]> 4ch.mooo.com Git - 16.git/commitdiff
ted5 added
authorsparky4 <sparky4@cock.li>
Fri, 27 Oct 2023 00:37:56 +0000 (19:37 -0500)
committersparky4 <sparky4@cock.li>
Fri, 27 Oct 2023 00:37:56 +0000 (19:37 -0500)
41 files changed:
16/ted5/BACKUP.BAT [new file with mode: 0755]
16/ted5/CHARSE.LBM [new file with mode: 0755]
16/ted5/EGAHEAD.TED [new file with mode: 0755]
16/ted5/EGALATCH.TED [new file with mode: 0755]
16/ted5/GRAB.BAT [new file with mode: 0755]
16/ted5/GRAPHTED.H [new file with mode: 0755]
16/ted5/INFO.TXT [new file with mode: 0755]
16/ted5/JHUFF.C [new file with mode: 0755]
16/ted5/JHUFF.H [new file with mode: 0755]
16/ted5/LIB.C [new file with mode: 0755]
16/ted5/LIB.H [new file with mode: 0755]
16/ted5/LIB_A.ASM [new file with mode: 0755]
16/ted5/MAPTEMP [new file with mode: 0755]
16/ted5/MAPTHEAD [new file with mode: 0755]
16/ted5/MEMMGR.C [new file with mode: 0755]
16/ted5/MEMMGR.H [new file with mode: 0755]
16/ted5/MENU.C [new file with mode: 0755]
16/ted5/MENU.H [new file with mode: 0755]
16/ted5/README.TXT [new file with mode: 0755]
16/ted5/README.md [new file with mode: 0755]
16/ted5/T.BAT [new file with mode: 0755]
16/ted5/TDCONFIG.TD [new file with mode: 0755]
16/ted5/TED.NSC [new file with mode: 0755]
16/ted5/TED5-1.C [new file with mode: 0755]
16/ted5/TED5-2.C [new file with mode: 0755]
16/ted5/TED5-3.C [new file with mode: 0755]
16/ted5/TED5-4.C [new file with mode: 0755]
16/ted5/TED5.C [new file with mode: 0755]
16/ted5/TED5.DSK [new file with mode: 0755]
16/ted5/TED5.EXE [new file with mode: 0755]
16/ted5/TED5.H [new file with mode: 0755]
16/ted5/TED5.MAP [new file with mode: 0755]
16/ted5/TED5.PRJ [new file with mode: 0755]
16/ted5/TED5.SYM [new file with mode: 0755]
16/ted5/TED5.TDK [new file with mode: 0755]
16/ted5/TED5_A.ASM [new file with mode: 0755]
16/ted5/TEST.BAT [new file with mode: 0755]
16/ted5/XMS.C [new file with mode: 0755]
16/ted5/XMS.H [new file with mode: 0755]
16/ted5/_TEDCHAR.EGA [new file with mode: 0755]
16/ted5/_TOM.PIC [new file with mode: 0755]

diff --git a/16/ted5/BACKUP.BAT b/16/ted5/BACKUP.BAT
new file mode 100755 (executable)
index 0000000..1651dea
--- /dev/null
@@ -0,0 +1,6 @@
+copy *.c backup
+copy *.h backup
+copy *.asm backup
+copy *.prj backup
+copy *.dsk backup
+copy _*.obj backup
diff --git a/16/ted5/CHARSE.LBM b/16/ted5/CHARSE.LBM
new file mode 100755 (executable)
index 0000000..25e4f26
Binary files /dev/null and b/16/ted5/CHARSE.LBM differ
diff --git a/16/ted5/EGAHEAD.TED b/16/ted5/EGAHEAD.TED
new file mode 100755 (executable)
index 0000000..053a72c
Binary files /dev/null and b/16/ted5/EGAHEAD.TED differ
diff --git a/16/ted5/EGALATCH.TED b/16/ted5/EGALATCH.TED
new file mode 100755 (executable)
index 0000000..a01c32f
Binary files /dev/null and b/16/ted5/EGALATCH.TED differ
diff --git a/16/ted5/GRAB.BAT b/16/ted5/GRAB.BAT
new file mode 100755 (executable)
index 0000000..47dc78e
--- /dev/null
@@ -0,0 +1,2 @@
+fgrab /ega ted.nsc
+copy egalatch.ted _tedchar.ega
diff --git a/16/ted5/GRAPHTED.H b/16/ted5/GRAPHTED.H
new file mode 100755 (executable)
index 0000000..4ea25ac
--- /dev/null
@@ -0,0 +1,12 @@
+//////////////////////////////////////
+//
+// Graphics DEFINE file for .TED
+// FGRAB-ed on Thu Aug 08 17:33:46 1991
+//
+//////////////////////////////////////
+
+
+
+//
+// Thank you for using FGRAB!
+//
diff --git a/16/ted5/INFO.TXT b/16/ted5/INFO.TXT
new file mode 100755 (executable)
index 0000000..d7d9e4b
--- /dev/null
@@ -0,0 +1,97 @@
+TED 5.0 Features
+---------------------------------------------------------------------------
+
+__ Handles all current tile types with ease of expansion for future sizes.
+   Current sizes are: 8x8,16x16,32x32. Only one tile size is permitted per
+   map set.
+
+__ Handles any amount of tiles that will fit in EMS memory. If EMS is not
+   present, you can't use TED 5.0!
+
+__ Handles masked and non-masked tiles.
+
+__ Each map has 3 planes: background tiles, foreground tiles, and extra
+   info. The extra info plane will blit icons for values 0-63 (?), higher
+   values will be printed as hex. Planes will be selected upon project
+   creation.
+
+__ Must have ability to turn on/off each individual plane so all planes
+   can be on or off at once.
+
+__ Video modes supported will be CGA 320x200, EGA 320x200/640x480/800x600,
+   VGA 320x200 256-color.
+
+__ Map Morph feature will allow user to select a block area and make snap-
+   shots of it, modify the area, make another snapshot, etc. until the
+   morph process is completed. Full editing capabilities will include:
+   DELETE FRAME, INSERT FRAME, MAKE SNAPSHOT.
+
+__ TileInfo feature will allow user to edit tile attributes. Editing capa-
+   bilities will include: ADD, DELETE, CHANGE NAME.
+
+__ TED editing feature will include:
+
+       __ Flood Fill
+       __ Block Fill
+       __ Copy Block (from tile maps as well) with SparseTile handling
+       __ Paste (with floating corners)
+       __ Draw
+       __ Line
+
+__ Other features:
+
+       __ Info Bar (on/off)
+       __ Tile Search
+       __ Map Info
+       __ ScrollKeys (SHIFT for full screen moves)
+       __ Right-Button tile-pickup
+       __ Map Resizing (with Edge Selection)
+       __ X,Y coords in Hex & Dec
+       __ All numeric input will support HEX,DEC,BIN
+
+__ Map files will be saved as either MAPTEMP.ext for the RLEW-only
+   (development) version, or GAMEMAPS.ext for the HUFF/RLEW version.
+
+__ Dialogs will be implemented.
+
+__ Project selection.
+
+__ Map selection by name!
+
+__ Create ApplePreferred or ILBM Map dumps
+
+
+
+
+
+Map Header Struct
+-------------------------------------------------------------------
+size           what            description
+-------------------------------------------------------------------
+unsigned       HeaderSize      size of the entire map header
+unsigned       MapType         how many planes the map has. If there
+                               are 3, you have back/foreground & info.
+                               If there are 2, you have back & info, If
+                               there is 1, you have background.
+unsigned       TileSize        size of tiles map is made for
+                               (1=8,2=16,3=32)
+long           TileInfoOff     offset to TILEINFO data
+long           TileInfoMOff    offset to MASKED TILEINFO data
+unsigned       RLEWtag         RLEW tag byte
+unsigned       Dictionary      offset to Huff dictionary. 0 if RLEW only.
+unsigned       DataOffsets     offset to MapOffset list
+...
+long           MapOffsets      offsets to Maps in map file
+
+
+
+Map Structure
+-------------------------------------------------------------------
+size           what            description
+-------------------------------------------------------------------
+long           Plane 0         offset to plane 0
+long           Plane 1         offset to plane 1 (0 if none)
+long           Plane 2         offset to plane 2 (0 if none)
+char           Name            Map name (16 chars)
+...
+unsigned       MapData         all map data is in WORDs
\ No newline at end of file
diff --git a/16/ted5/JHUFF.C b/16/ted5/JHUFF.C
new file mode 100755 (executable)
index 0000000..3741465
--- /dev/null
@@ -0,0 +1,1287 @@
+#include "ted5.h"
+#pragma hdrstop
+
+long inlength,outlength;
+
+long counts[256];
+
+unsigned huffbits[256];
+unsigned long huffstring[256];
+
+huffnode nodearray[256];       // 256 nodes is worst case
+
+void CountBytes (unsigned char huge *start, long length);
+void Huffmanize (void);
+void OptimizeNodes (huffnode *table);
+long HuffCompress (unsigned char huge *source, long length,
+  unsigned char huge *dest);
+void HuffExpand (unsigned char huge *source, unsigned char huge *dest,
+  long length,huffnode *hufftable);
+void RLEWExpand (unsigned huge *source, unsigned huge *dest,long length,
+  unsigned rlewtag);
+long RLEWCompress (unsigned huge *source, long length, unsigned huge *dest,
+  unsigned rlewtag);
+
+/*
+=============================================================================
+
+                          COMPRESSION SUBS
+
+=============================================================================
+*/
+
+
+/*
+======================
+=
+= CountBytes
+=
+= Adds the bytes in the pointed to area to the counts array
+= If this is the first segment, make sure counts is zerod
+=
+======================
+*/
+
+void CountBytes (unsigned char huge *start, long length)
+{
+  long i;
+
+  while (length--)
+    counts[*start++]++;
+}
+
+/*
+=======================
+=
+= FindLeast
+=
+= Returns the byte with the lowest counts value
+=
+=======================
+*/
+
+int FindLeast (void)
+{
+  int i,least;
+  long low = 0x7fffffff;
+
+  for (i=0;i<256;i++)
+    if (counts[i]<low)
+    {
+      low = counts[i];
+      least = i;
+    }
+
+  return least;
+}
+
+/*========================================================================*/
+
+/*
+==================
+=
+= TraceNode
+=
+= A recursive function that follows all leaves of nodearray and fills in
+= coding tables huffbits and huffstring.
+=
+==================
+*/
+
+void TraceNode (int nodenum,int numbits,unsigned long bitstring)
+{
+  unsigned bit0,bit1;
+
+  bit0 = nodearray[nodenum].bit0;
+  bit1 = nodearray[nodenum].bit1;
+
+  numbits++;
+
+  if (bit0 <256)
+  {
+    huffbits[bit0]=numbits;
+    huffstring[bit0]=bitstring;                // just added a zero in front
+    if (huffbits[bit0]>24 && counts[bit0])
+    {
+      puts("Error: Huffman bit string went over 32 bits!");
+      exit(1);
+    }
+  }
+  else
+    TraceNode (bit0-256,numbits,bitstring);
+
+  if (bit1 <256)
+  {
+    huffbits[bit1]=numbits;
+    huffstring[bit1]=bitstring+ (1ul<<(numbits-1));    // add a one in front
+    if (huffbits[bit1]>24 && counts[bit1])
+    {
+      puts("Error: Huffman bit string went over 32 bits!");
+      exit(1);
+    }
+  }
+  else
+    TraceNode (bit1-256,numbits,bitstring+(1ul<<(numbits-1)));
+}
+
+/*
+=======================
+=
+= Huffmanize
+=
+= Takes the counts array and builds a huffman tree at
+= nodearray, then builds a codeing table.
+=
+=======================
+*/
+
+void Huffmanize (void)
+{
+
+//
+// codes are either bytes if <256 or nodearray numbers+256 if >=256
+//
+  unsigned value[256],code0,code1;
+//
+// probablilities are the number of times the code is hit or $ffffffff if
+// it is allready part of a higher node
+//
+  unsigned long prob[256],low,workprob;
+
+  int i,worknode,bitlength;
+  unsigned long bitstring;
+
+
+//
+// all possible leaves start out as bytes
+//
+  for (i=0;i<256;i++)
+  {
+    value[i]=i;
+    prob[i]=counts[i];
+  }
+
+//
+// start selecting the lowest probable leaves for the ends of the tree
+//
+
+  worknode = 0;
+  while (1)    // break out of when all codes have been used
+  {
+    //
+    // find the two lowest probability codes
+    //
+
+    code0=0xffff;
+    low = 0x7ffffffff;
+    for (i=0;i<256;i++)
+      if (prob[i]<low)
+      {
+       code0 = i;
+       low = prob[i];
+      }
+
+    code1=0xffff;
+    low = 0x7fffffff;
+    for (i=0;i<256;i++)
+      if (prob[i]<low && i != code0)
+      {
+       code1 = i;
+       low = prob[i];
+      }
+
+    if (code1 == 0xffff)
+    {
+      if (value[code0]<256)
+       Quit("Wierdo huffman error: last code wasn't a node!");
+      if (value[code0]-256 != 254)
+       Quit("Wierdo huffman error: headnode wasn't 254!");
+      break;
+    }
+
+    //
+    // make code0 into a pointer to work
+    // remove code1 (make 0xffffffff prob)
+    //
+    nodearray[worknode].bit0 = value[code0];
+    nodearray[worknode].bit1 = value[code1];
+
+    value[code0] = 256 + worknode;
+    prob[code0] += prob[code1];
+    prob[code1] = 0xffffffff;
+    worknode++;
+  }
+
+//
+// done with tree, now build table recursively
+//
+
+  TraceNode (254,0,0);
+
+}
+
+/*========================================================================*/
+
+
+/*
+===============
+=
+= OptimizeNodes
+=
+= Goes through a huffman table and changes the 256-511 node numbers to the
+= actular address of the node.  Must be called before HuffExpand
+=
+===============
+*/
+
+void OptimizeNodes (huffnode *table)
+{
+  huffnode *node;
+  int i;
+
+  node = table;
+
+  for (i=0;i<255;i++)
+  {
+    if (node->bit0 >= 256)
+      node->bit0 = (unsigned)(table+(node->bit0-256));
+    if (node->bit1 >= 256)
+      node->bit1 = (unsigned)(table+(node->bit1-256));
+    node++;
+  }
+}
+
+/*========================================================================*/
+
+#if 0
+/*
+======================
+=
+= HuffCompress
+=
+= The file must be counted with CountBytes and then Huffmanized first
+=
+======================
+*/
+
+long HuffCompress (unsigned char huge *source, long length,
+  unsigned char huge *dest)
+{
+  long outlength;
+  unsigned long string;
+  unsigned biton,bits;
+  unsigned char byte;
+
+  outlength = biton = 0;
+
+  *(long huge *)dest=0;                // so bits can be or'd on
+
+  while (length--)
+  {
+    byte = *source++;
+    bits = huffbits[byte];
+    string = huffstring[byte] << biton;
+    *(long huge *)(dest+1)=0;  // so bits can be or'd on
+    *(long huge *)dest |= string;
+    biton += bits;             // advance this many bits
+    dest+= biton/8;
+    biton&=7;                  // stay under 8 shifts
+    outlength+=bits;
+  }
+
+  return (outlength+7)/8;
+}
+#endif
+
+
+/*========================================================================*/
+
+/*
+======================
+=
+= HuffExpand
+=
+======================
+*/
+
+void HuffExpand (unsigned char huge *source, unsigned char huge *dest,
+  long length,huffnode *hufftable)
+
+{
+  unsigned bit,byte,node,code;
+  unsigned sourceseg,sourceoff,destseg,destoff,endoff;
+  huffnode *nodeon,*headptr;
+
+  headptr = hufftable+254;     // head node is allways node 254
+
+  source++;    // normalize
+  source--;
+  dest++;
+  dest--;
+
+  sourceseg = FP_SEG(source);
+  sourceoff = FP_OFF(source);
+  destseg = FP_SEG(dest);
+  destoff = FP_OFF(dest);
+  endoff = destoff+length;
+
+//
+// ds:si source
+// es:di dest
+// ss:bx node pointer
+//
+
+       if (length <0xfff0)
+       {
+
+//--------------------------
+// expand less than 64k of data
+//--------------------------
+
+asm mov        bx,[headptr]
+
+asm    mov     si,[sourceoff]
+asm    mov     di,[destoff]
+asm    mov     es,[destseg]
+asm    mov     ds,[sourceseg]
+asm    mov     ax,[endoff]
+
+asm    mov     ch,[si]                         // load first byte
+asm    inc     si
+asm    mov     cl,1
+
+expandshort:
+asm    test    ch,cl                   // bit set?
+asm    jnz     bit1short
+asm    mov     dx,[ss:bx]                      // take bit0 path from node
+asm    shl     cl,1                            // advance to next bit position
+asm    jc      newbyteshort
+asm    jnc     sourceupshort
+
+bit1short:
+asm    mov     dx,[ss:bx+2]            // take bit1 path
+asm    shl     cl,1                            // advance to next bit position
+asm    jnc     sourceupshort
+
+newbyteshort:
+asm    mov     ch,[si]                         // load next byte
+asm    inc     si
+asm    mov     cl,1                            // back to first bit
+
+sourceupshort:
+asm    or      dh,dh                           // if dx<256 its a byte, else move node
+asm    jz      storebyteshort
+asm    mov     bx,dx                           // next node = (huffnode *)code
+asm    jmp     expandshort
+
+storebyteshort:
+asm    mov     [es:di],dl
+asm    inc     di                                      // write a decopmpressed byte out
+asm    mov     bx,[headptr]            // back to the head node for next bit
+
+asm    cmp     di,ax                           // done?
+asm    jne     expandshort
+       }
+       else
+       {
+
+//--------------------------
+// expand more than 64k of data
+//--------------------------
+
+  length--;
+
+asm mov        bx,[headptr]
+asm    mov     cl,1
+
+asm    mov     si,[sourceoff]
+asm    mov     di,[destoff]
+asm    mov     es,[destseg]
+asm    mov     ds,[sourceseg]
+
+asm    lodsb                   // load first byte
+
+expand:
+asm    test    al,cl           // bit set?
+asm    jnz     bit1
+asm    mov     dx,[ss:bx]      // take bit0 path from node
+asm    jmp     gotcode
+bit1:
+asm    mov     dx,[ss:bx+2]    // take bit1 path
+
+gotcode:
+asm    shl     cl,1            // advance to next bit position
+asm    jnc     sourceup
+asm    lodsb
+asm    cmp     si,0x10         // normalize ds:si
+asm    jb      sinorm
+asm    mov     cx,ds
+asm    inc     cx
+asm    mov     ds,cx
+asm    xor     si,si
+sinorm:
+asm    mov     cl,1            // back to first bit
+
+sourceup:
+asm    or      dh,dh           // if dx<256 its a byte, else move node
+asm    jz      storebyte
+asm    mov     bx,dx           // next node = (huffnode *)code
+asm    jmp     expand
+
+storebyte:
+asm    mov     [es:di],dl
+asm    inc     di              // write a decopmpressed byte out
+asm    mov     bx,[headptr]    // back to the head node for next bit
+
+asm    cmp     di,0x10         // normalize es:di
+asm    jb      dinorm
+asm    mov     dx,es
+asm    inc     dx
+asm    mov     es,dx
+asm    xor     di,di
+dinorm:
+
+asm    sub     [WORD PTR ss:length],1
+asm    jnc     expand
+asm    dec     [WORD PTR ss:length+2]
+asm    jns     expand          // when length = ffff ffff, done
+
+       }
+
+asm    mov     ax,ss
+asm    mov     ds,ax
+
+}
+
+
+//----------------- replaced by John C. ------------------------------------
+#if 0
+{
+  unsigned bit,byte,node,code;
+  unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;
+  huffnode *nodeon,*headptr;
+
+  nodeon = headptr = hufftable+254;    // head node is allways node 254
+
+  bit = 1;
+  byte = *source++;
+
+  while (length)
+  {
+    if (byte&bit)
+      code = nodeon->bit1;
+    else
+      code = nodeon->bit0;
+
+    bit<<=1;
+    if (bit==256)
+    {
+      bit=1;
+      byte = *source++;
+    }
+
+    if (code<256)
+    {
+      *dest++=code;
+      nodeon=headptr;
+      length--;
+    }
+    else
+      nodeon = (huffnode *)code;
+  }
+
+
+#if 0
+
+  source++;    // normalize
+  source--;
+  dest++;
+  dest--;
+
+  sourceseg = FP_SEG(source);
+  sourceoff = FP_OFF(source);
+  destseg = FP_SEG(dest);
+  destoff = FP_OFF(dest);
+
+  length--;
+//
+// al = source byte
+// cl = bit in source (1,2,4,8,...)
+// dx = code
+//
+// ds:si source
+// es:di dest
+// ss:bx node pointer
+//
+
+asm     mov    bx,headptr
+asm    mov     cl,1
+
+asm    mov     si,sourceoff
+asm    mov     di,destoff
+asm    mov     es,destseg
+asm    mov     ds,sourceseg
+
+asm    lodsb                   // load first byte
+
+expand:
+asm    test    al,cl           // bit set?
+asm    jnz     bit1
+asm    mov     dx,ss:bx        // take bit0 path from node
+asm    jmp     gotcode
+bit1:
+asm    mov     dx,ss:bx+2      // take bit1 path
+
+gotcode:
+asm    shl     cl,1            // advance to next bit position
+asm    jnc     sourceup
+asm    lodsb
+asm    cmp     si,0x10         // normalize ds:si
+asm    jb      sinorm
+asm    mov     cx,ds
+asm    inc     cx
+asm    mov     ds,cx
+asm    xor     si,si
+sinorm:
+asm    mov     cl,1            // back to first bit
+
+sourceup:
+asm    or      dh,dh           // if dx<256 its a byte, else move node
+asm    jz      storebyte
+asm    mov     bx,dx           // next node = (huffnode *)code
+asm    jmp     expand
+
+storebyte:
+asm    mov     [es:di],dl
+asm    inc     di              // write a decopmpressed byte out
+asm    mov     bx,headptr      // back to the head node for next bit
+
+asm    cmp     di,0x10         // normalize es:di
+asm    jb      dinorm
+asm    mov     dx,es
+asm    inc     dx
+asm    mov     es,dx
+asm    xor     di,di
+dinorm:
+
+asm    sub     WORD PTR ss:length,1
+asm    jnc     expand
+asm    dec     WORD PTR ss:length+2
+asm    jns     expand          // when length = ffff ffff, done
+
+asm    mov     ax,ss
+asm    mov     ds,ax
+
+#endif
+
+}
+#endif
+//---------------------------------------------------------------------------
+
+/*========================================================================*/
+
+/*
+======================
+=
+= RLEWcompress
+=
+======================
+*/
+
+long RLEWCompress (unsigned huge *source, long length, unsigned huge *dest,
+  unsigned rlewtag)
+{
+  long complength;
+  unsigned value,count,i;
+  unsigned huge *start,huge *end;
+
+  start = dest;
+
+  end = source + (length+1)/2;
+
+//
+// compress it
+//
+  do
+  {
+    count = 1;
+    value = *source++;
+    while (*source == value && source<end)
+    {
+      count++;
+      source++;
+    }
+    if (count>3 || value == rlewtag)
+    {
+    //
+    // send a tag / count / value string
+    //
+      *dest++ = rlewtag;
+      *dest++ = count;
+      *dest++ = value;
+    }
+    else
+    {
+    //
+    // send word without compressing
+    //
+      for (i=1;i<=count;i++)
+       *dest++ = value;
+    }
+
+  } while (source<end);
+
+  complength = 2*(dest-start);
+  return complength;
+}
+
+
+
+/*
+======================
+=
+= RLEWexpand
+=
+======================
+*/
+
+void RLEWExpand (unsigned huge *source, unsigned huge *dest,long length,
+  unsigned rlewtag)
+{
+  unsigned value,count,i;
+  unsigned huge *end;
+  unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;
+
+
+//
+// expand it
+//
+#if 0
+  do
+  {
+    value = *source++;
+    if (value != rlewtag)
+    //
+    // uncompressed
+    //
+      *dest++=value;
+    else
+    {
+    //
+    // compressed string
+    //
+      count = *source++;
+      value = *source++;
+      for (i=1;i<=count;i++)
+       *dest++ = value;
+    }
+  } while (dest<end);
+#endif
+
+  end = dest + (length)/2;
+  sourceseg = FP_SEG(source);
+  sourceoff = FP_OFF(source);
+  destseg = FP_SEG(dest);
+  destoff = FP_OFF(dest);
+  endseg = FP_SEG(end);
+  endoff = FP_OFF(end);
+
+
+//
+// ax = source value
+// bx = tag value
+// cx = repeat counts
+// dx = scratch
+//
+// NOTE: A repeat count that produces 0xfff0 bytes can blow this!
+//
+
+asm    mov     bx,rlewtag
+asm    mov     si,sourceoff
+asm    mov     di,destoff
+asm    mov     es,destseg
+asm    mov     ds,sourceseg
+
+expand:
+asm    lodsw
+asm    cmp     ax,bx
+asm    je      repeat
+asm    stosw
+asm    jmp     next
+
+repeat:
+asm    lodsw
+asm    mov     cx,ax           // repeat count
+asm    lodsw                   // repeat value
+asm    rep stosw
+
+next:
+
+asm    cmp     si,0x10         // normalize ds:si
+asm    jb      sinorm
+asm    mov     ax,si
+asm    shr     ax,1
+asm    shr     ax,1
+asm    shr     ax,1
+asm    shr     ax,1
+asm    mov     dx,ds
+asm    add     dx,ax
+asm    mov     ds,dx
+asm    and     si,0xf
+sinorm:
+asm    cmp     di,0x10         // normalize es:di
+asm    jb      dinorm
+asm    mov     ax,di
+asm    shr     ax,1
+asm    shr     ax,1
+asm    shr     ax,1
+asm    shr     ax,1
+asm    mov     dx,es
+asm    add     dx,ax
+asm    mov     es,dx
+asm    and     di,0xf
+dinorm:
+
+asm    cmp     di,ss:endoff
+asm    jne     expand
+asm    mov     ax,es
+asm    cmp     ax,ss:endseg
+asm    jb      expand
+
+asm    mov     ax,ss
+asm    mov     ds,ax
+
+}
+
+
+/*
+======================
+=
+= RLEBcompress
+=
+======================
+*/
+
+long RLEBCompress (unsigned char huge *source, long length,
+  unsigned char huge *dest, unsigned char rlebtag)
+{
+  long complength;
+  unsigned char value,count;
+  unsigned i;
+  unsigned char huge *start,huge *end;
+
+  start = dest;
+
+  end = source+length;
+
+//
+// compress it
+//
+  do
+  {
+    count = 1;
+    value = *source++;
+    while (*source == value && source<end && count<255)
+    {
+      count++;
+      source++;
+    }
+    if (count>3 || value == rlebtag)
+    {
+    //
+    // send a tag / count / value string
+    //
+      *dest++ = rlebtag;
+      *dest++ = count;
+      *dest++ = value;
+    }
+    else
+    {
+    //
+    // send byte without compressing
+    //
+      for (i=1;i<=count;i++)
+       *dest++ = value;
+    }
+
+  } while (source<end);
+
+  complength = dest-start;
+  return complength;
+}
+
+
+
+/*
+======================
+=
+= RLEBExpand
+=
+======================
+*/
+
+void RLEBExpand (unsigned char huge *source, unsigned char huge *dest,
+  long length, unsigned char rlebtag)
+{
+  unsigned char value,count;
+  unsigned i;
+  unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;
+  unsigned char huge *end;
+
+
+//
+// expand it
+//
+#if 0
+  do
+  {
+    value = *source++;
+    if (value != rlebtag)
+    //
+    // uncompressed
+    //
+      *dest++=value;
+    else
+    {
+    //
+    // compressed string
+    //
+      count = *source++;
+      value = *source++;
+      for (i=1;i<=count;i++)
+       *dest++ = value;
+    }
+  } while (dest<end);
+#endif
+
+
+  end = dest + (length);
+  sourceseg = FP_SEG(source);
+  sourceoff = FP_OFF(source);
+  destseg = FP_SEG(dest);
+  destoff = FP_OFF(dest);
+  endseg = FP_SEG(end);
+  endoff = FP_OFF(end);
+
+
+//
+// al = source value
+// bl = tag value
+// cl = repeat counts
+// dx = scratch
+//
+// NOTE: A repeat count that produces 0xfff0 bytes can blow this!
+//
+
+asm    mov     bx,WORD PTR rlebtag
+asm    mov     si,sourceoff
+asm    mov     di,destoff
+asm    mov     es,destseg
+asm    mov     ds,sourceseg
+asm    xor     ch,ch
+
+expand:
+asm    lodsb
+asm    cmp     al,bl
+asm    je      repeat
+asm    stosb
+asm    jmp     next
+
+repeat:
+asm    lodsb
+asm    mov     cl,al           // repeat count
+asm    lodsb                   // repeat value
+asm    rep stosb
+
+next:
+
+asm    cmp     si,0x10         // normalize ds:si
+asm    jb      sinorm
+asm    mov     ax,si
+asm    shr     ax,1
+asm    shr     ax,1
+asm    shr     ax,1
+asm    shr     ax,1
+asm    mov     dx,ds
+asm    add     dx,ax
+asm    mov     ds,dx
+asm    and     si,0xf
+sinorm:
+asm    cmp     di,0x10         // normalize es:di
+asm    jb      dinorm
+asm    mov     ax,di
+asm    shr     ax,1
+asm    shr     ax,1
+asm    shr     ax,1
+asm    shr     ax,1
+asm    mov     dx,es
+asm    add     dx,ax
+asm    mov     es,dx
+asm    and     di,0xf
+dinorm:
+
+asm    cmp     di,ss:endoff
+asm    jne     expand
+asm    mov     ax,es
+asm    cmp     ax,ss:endseg
+asm    jb      expand
+
+asm    mov     ax,ss
+asm    mov     ds,ax
+
+
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+
+#if 1
+/*
+==================
+=
+= CarmackCompress
+=
+= Compress a string of words
+=
+==================
+*/
+
+#define NEARTAG        0xa7
+#define FARTAG 0xa8
+
+long CarmackCompress (unsigned far *source,long length,
+       unsigned far *dest)
+{
+       unsigned        ch,chhigh;
+       unsigned        far *instart, far *inptr, far *inscan,
+                               far *stopscan, far *outptr;
+       unsigned        far *bestscan, beststring;
+       unsigned        dist,maxstring,string,outlength;
+       unsigned        nearrepeats,farrepeats;
+       unsigned        dups,count;
+       unsigned        newwords;
+
+//
+// this compression method produces a stream of words
+// If the words high byte is NEARTAG or FARTAG, the low byte is a word
+// copy count from the a position specified by either the next byte
+// or the next word, respectively.  A copy count of 0 means to insert the
+// next byte as the low byte of the tag into the output
+//
+
+
+//
+// set up
+//
+       instart = inptr = source;
+       outptr = dest;
+
+       outlength = 0;
+       length = (length+1)/2;
+
+       nearrepeats = farrepeats = dups = 0;
+       count = 10;
+       newwords = 0;
+//
+// compress
+//
+       do
+       {
+               ch = *inptr;
+
+//
+// scan from start for patterns that match current data
+//
+               beststring = 0;
+               for (inscan = instart; inscan<inptr; inscan++)
+               {
+                       if (*inscan != ch)
+                               continue;
+
+                       maxstring = inptr-inscan;
+                       if (maxstring > length)
+                               maxstring = length;
+                       if (maxstring > 255)
+                               maxstring = 255;
+
+                       string = 1;
+                       while (*(inscan+string) == *(inptr+string) && string<maxstring)
+                               string++;
+
+                       if (string >= beststring)
+                       {
+                               beststring = string;
+                               bestscan = inscan;
+                       }
+               }
+
+               if (beststring > 1 && inptr-bestscan <= 255)
+               {
+               // near string
+                       *outptr++ = beststring + (NEARTAG*256);
+                       *((unsigned char far *)outptr)++ = inptr-bestscan;
+                       outlength += 3;
+                       nearrepeats++;
+                       inptr += beststring;
+                       length -= beststring;
+               }
+               else if (beststring > 2)
+               {
+               // far string
+                       *outptr++ = beststring + (FARTAG*256);
+                       *outptr++ = bestscan-instart;
+                       outlength += 4;
+                       farrepeats++;
+                       inptr += beststring;
+                       length -= beststring;
+               }
+               else                                                    // no compression
+               {
+                       chhigh = ch>>8;
+                       if (chhigh == NEARTAG || chhigh == FARTAG)
+                       {
+                       // special case of encountering a
+                       // tag word in the data stream
+                       // send a length of 0, and follow it with the real low byte
+                               *outptr++ = ch & 0xff00;
+                               *((unsigned char far *)outptr)++ = ch&0xff;
+                               outlength += 3;
+                               dups++;
+                       }
+                       else
+                       {
+                               *outptr++ = ch;
+                               outlength += 2;
+                       }
+                       inptr++;
+                       length--;
+                       newwords++;
+               }
+
+               if (!--count)
+               {
+                       static char cc[2]="-";
+                       cc[0]^='+'^'-';
+                       print(cc);
+                       sx--;
+
+                       count = 10;
+
+                if (keydown[1])
+                {
+                 while(keydown[1]);
+                 return 0;
+                }
+               }
+               if (length<0)
+                       Quit ("Length < 0!");
+       } while (length);
+       #if 0
+       printf ("%u near patterns\n",nearrepeats);
+       printf ("%u far patterns\n",farrepeats);
+       printf ("%u new words\n",newwords);
+       printf ("%u dups\n\n",dups);
+       #endif
+       return outlength;
+}
+#else
+
+
+
+/*
+==================
+=
+= CarmackCompress
+=
+= Compress a string of words
+=
+==================
+*/
+
+#define NEARTAG        0xa7
+#define FARTAG 0xa8
+
+long CarmackCompress (unsigned far *source,long length,
+       unsigned far *dest)
+{
+       unsigned        wch,chhigh;
+       unsigned        inptrx;
+       unsigned        far *instart, far *inptr, far *inscan,
+                               far *stopscan, far *outptr;
+       unsigned        far *bestscan, beststring;
+       unsigned        dist,maxstring,string,outlength;
+       unsigned        nearrepeats,farrepeats;
+       unsigned        dups,count;
+       unsigned        newwords;
+
+//
+// this compression method produces a stream of words
+// If the words high byte is NEARTAG or FARTAG, the low byte is a word
+// copy count from the a position specified by either the next byte
+// or the next word, respectively.  A copy count of 0 means to insert the
+// next byte as the low byte of the tag into the output
+//
+
+
+//
+// set up
+//
+       instart = inptr = bestscan = source;
+       outptr = dest;
+
+       outlength = 0;
+       length = (length+1)/2;
+
+       nearrepeats = farrepeats = dups = 0;
+       count = 10;
+       newwords = 0;
+//
+// compress
+//
+       do
+       {
+               wch = *inptr;
+               inptrx = FP_OFF(inptr)+2;       // convienient for cmpsw
+
+//
+// scan from start for patterns that match current data
+//
+//================
+
+//
+// ax:
+// bx: beststring
+// cx: repeat counts
+// dx: holding spot for inscan repeat count
+// si: inptr
+// di: inscan
+//
+asm    xor     bx,bx                                   // beststring = 0
+
+asm    les     di,[instart]                    // start looking for an identical string
+                                                               // at the start of uncompressed text
+asm    mov     ax,es
+asm    mov     ds,ax                                   // both DS and ES point to uncompressed data
+
+asm    mov     cx,WORD PTR [inptr]
+asm    sub     cx,di
+asm    shr     cx,1                                    // cx = words between inscan and inptr
+
+search:
+asm    mov     ax,[wch]                                // current uncompressed word
+asm    repne   scasw                           // search from DI for up to CX words for a
+                                                               // first char match
+asm    jcxz    done                            // no more to search
+
+asm    mov     dx,cx                                   // save off remaining repeat count
+                                                               // the number in CX is the remaining words
+                                                               // to search for a long pattern
+asm    mov     si,[inptrx]                             // SI is the current source data
+                                                               // DI is the match in previously compressed
+                                                               // data
+asm    mov     ax,di                                   // save off DI so we can back up after scan
+asm    repe    cmpsw                           // decrement CX for each additional match
+asm    jne     ended
+asm    dec     cx                                              // the search ended because of CX, not bad match
+ended:
+asm    mov     di,ax                                   // back to original spot
+asm    mov     ax,dx
+asm    sub     ax,cx                                   // AX is the total number of matching words
+asm    cmp     ax,bx                                   // more chars than beststring?
+asm    jb      next
+asm    mov     bx,ax
+asm    mov     WORD PTR [bestscan],di  // bestscan is start of the best match+2
+
+next:
+asm    mov     cx,dx                                   // restore the remaining count
+asm    jmp     search
+
+done:
+asm    mov     ax,ss
+asm    mov     ds,ax
+asm    mov     [beststring],bx                 // save out the register variable
+asm    dec     bx
+asm    sub     WORD PTR [bestscan],2   // scasw incremented past start
+//================
+
+               if (beststring>length)
+                       beststring = length;
+
+               if (beststring > 1 && inptr-bestscan <= 255)
+               {
+               // near string
+                       *outptr++ = beststring + (NEARTAG*256);
+                       *((unsigned char far *)outptr)++ = inptr-bestscan;
+                       outlength += 3;
+                       nearrepeats++;
+                       inptr += beststring;
+                       length -= beststring;
+               }
+               else if (beststring > 2)
+               {
+               // far string
+                       *outptr++ = beststring + (FARTAG*256);
+                       *outptr++ = bestscan-instart;
+                       outlength += 4;
+                       farrepeats++;
+                       inptr += beststring;
+                       length -= beststring;
+               }
+               else                                                    // no compression
+               {
+                       chhigh = wch>>8;
+                       if (chhigh == NEARTAG || chhigh == FARTAG)
+                       {
+                       // special case of encountering a
+                       // tag word in the data stream
+                       // send a length of 0, and follow it with the real low byte
+                               *outptr++ = wch & 0xff00;
+                               *((unsigned char far *)outptr)++ = wch&0xff;
+                               outlength += 3;
+                               dups++;
+                       }
+                       else
+                       {
+                               *outptr++ = wch;
+                               outlength += 2;
+                       }
+                       inptr++;
+                       length--;
+                       newwords++;
+               }
+
+               if (!--count)
+               {
+                static char cc[2]="-";
+                cc[0]^='+'^'-';
+                print(cc);
+                sx--;
+
+                count = 10;
+
+                if (keydown[1])
+                {
+                 while(keydown[1]);
+                 return 0;
+                }
+               }
+       } while (length);
+#if 0
+       printf ("\r%u near patterns\n",nearrepeats);
+       printf ("%u far patterns\n",farrepeats);
+       printf ("%u new words\n",newwords);
+       printf ("%u dups\n\n",dups);
+#endif
+       return outlength;
+}
+#endif
+
+
diff --git a/16/ted5/JHUFF.H b/16/ted5/JHUFF.H
new file mode 100755 (executable)
index 0000000..0d4536c
--- /dev/null
@@ -0,0 +1,26 @@
+typedef struct
+{
+  unsigned bit0,bit1;  // 0-255 is a character, > is a pointer to a node
+} huffnode;
+
+extern long counts[256];
+extern huffnode nodearray[256];
+
+
+void CountBytes (unsigned char huge *start, long length);
+void Huffmanize (void);
+void OptimizeNodes (huffnode *table);
+long HuffCompress (unsigned char huge *source, long length,
+  unsigned char huge *dest);
+void HuffExpand (unsigned char huge *source, unsigned char huge *dest,
+  long length,huffnode *hufftable);
+void RLEWExpand (unsigned huge *source, unsigned huge *dest,long length,
+  unsigned rlewtag);
+long RLEWCompress (unsigned huge *source, long length, unsigned huge *dest,
+  unsigned rlewtag);
+void RLEBExpand (unsigned char huge *source, unsigned char huge *dest,
+  long length, unsigned char rlebtag);
+long RLEBCompress (unsigned char huge *source, long length,
+  unsigned char huge *dest, unsigned char rlebtag);
+long CarmackCompress (unsigned far *source,long length,
+       unsigned far *dest);
diff --git a/16/ted5/LIB.C b/16/ted5/LIB.C
new file mode 100755 (executable)
index 0000000..e5a06fd
--- /dev/null
@@ -0,0 +1,1011 @@
+#include "ted5.h"
+#pragma hdrstop
+
+extern char far TEDCHAR,far VGAPAL;
+
+void Quit(char *string);
+void drawchar(int x,int y,int chr);
+void centerwindow (int width, int height);
+
+int win_xl,win_yl,win_xh,win_yh;
+int screencenterx = 19,screencentery = 11;
+unsigned char keydown[256];
+unsigned leftedge,yshift,xormask,MouseStatus,sx,sy;
+void interrupt (*oldint9) ()=NULL;
+enum {false,true} boolean;
+memptr CGAfont,VGAfont;
+unsigned doubled[256];
+//
+// Special vars to handle EGA3 mouse mode
+//
+int EGA3mx,EGA3my;
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Return a file's length
+//
+////////////////////////////////////////////////////////////////////
+long filelen(char *filename)
+{
+ long size;
+ int handle;
+
+ if ((handle=open(filename,O_BINARY))==-1)
+   return 0;
+
+ size=filelength(handle);
+ close(handle);
+ return size;
+}
+
+////////////////////////////////////////////////////////////////////
+//
+// WaitVBL
+//
+////////////////////////////////////////////////////////////////////
+void WaitVBL(int times)
+{
+asm    mov     cx,times
+asm    mov     dx,crtcaddr
+asm    add     dx,6
+
+waitvbl1:
+asm    in      al,dx
+asm    test    al,00001000b    //;look for vbl
+asm    jnz     waitvbl1
+
+waitvbl2:
+asm    in      al,dx
+asm    test    al,00001000b    //;look for vbl
+asm    jz      waitvbl2
+
+asm    loop    waitvbl1
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Int9ISR
+// Called for every keypress.  Keeps track of which keys are down, and passes
+// the key on to DOS after clearing the dos buffer (max 1 char in buffer).
+//
+////////////////////////////////////////////////////////////////////
+void interrupt Int9ISR ()
+{
+ int key = inportb (0x60);             /* get the key pressed */
+
+ if (key>127)
+   keydown [key-128] = false;          /* break scan code */
+ else
+ {
+   keydown [key] = true;               /* make scan code */
+   poke (0x40,0x1c,peek(0x40,0x1a));   /* clear the bios key buffer */
+ }
+asm {
+   push ax
+   push        bx
+   push        cx
+   push        dx
+   push        si
+   push        di
+   push        bp
+ }
+ oldint9 ();                           /* give it to DOS */
+asm {
+   pop bp
+   pop  di
+   pop si
+   pop dx
+   pop cx
+   pop bx
+   pop ax
+ }
+ outport (0x20,0x20);                  /* tell the int manager we got it */
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// SetupKBD
+// Clears the keydown array and installs the INT 9 ISR if it isn't already
+// hooked up.
+//
+////////////////////////////////////////////////////////////////////
+void SetupKBD ()
+{
+ void far *vect = getvect (9);
+ int i;
+
+ for (i=0;i<128;i++)                   /* clear our key down table */
+   keydown[i]= false;
+
+ poke (0x40,0x1c,peek(0x40,0x1a));     /* clear the bios key buffer */
+
+ if ( &Int9ISR != vect )               /* is our handler allready set up? */
+ {
+   oldint9 = vect;
+   setvect (9,Int9ISR);
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// ShutdownKBD
+// Sets the int 9 vector back to oldint 9
+//
+////////////////////////////////////////////////////////////////////
+void ShutdownKBD ()
+{
+ if (oldint9 != NULL)
+   setvect (9,oldint9);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// clearkeys
+// Clears out the bios buffer and zeros out the keydown array
+//
+////////////////////////////////////////////////////////////////////
+void clearkeys (void)
+{
+  int i;
+  while (bioskey (1))
+    bioskey(0);
+
+  for (i=0;i<128;i++)
+    keydown [i]=0;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Mouse Routines
+//
+////////////////////////////////////////////////////////////////////
+int MouseInit(void)
+{
+ union REGS regs;
+ unsigned char far *vector;
+
+ if ((vector=MK_FP(peek(0,0x33*4+2),peek(0,0x33*4)))==NULL) return 0;
+
+ if (*vector == 207)
+   return MouseStatus = 0;
+
+ _AX=0;
+ geninterrupt(0x33);
+ EGA3mx=800/2;
+ EGA3my=600/2;
+
+ //
+ // Set CGA mouse cursor (normal one sucks)
+ //
+ if (videomode==CGA)
+   {
+    static unsigned CGAcursor[]=
+      {
+       0x0fff,0x03ff,0x00ff,0x003f,0x000f,0x0003,0x0000,0x000f,0x0c03,0x3c03,
+       0xff03,0xffff,0xffff,0xffff,0xffff,0xffff,
+
+       0xf000,0xcc00,0xc300,0xc0c0,0xc030,0xc00c,0xc03f,0xcc30,0xf30c,0xc30c,
+       0x00fc,0x0000,0x0000,0x0000,0x0000,0x0000
+      };
+
+    _BX=0;
+    _CX=0;
+    _DX=FP_OFF(CGAcursor);
+    _ES=_DS;
+    _AX=9;
+    geninterrupt(0x33);
+   }
+
+ return MouseStatus = 1;
+}
+
+
+void MouseOrigin(int x,int y)
+{
+ if (!MouseStatus) return;
+
+ _CX=x;
+ _DX=y;
+ _AX=4;
+ geninterrupt(0x33);
+}
+
+
+void MouseLimits(int xmin,int xmax,int ymin,int ymax)
+{
+ if (!MouseStatus) return;
+
+ _CX=xmin;
+ _DX=xmax;
+ _AX=7;
+ geninterrupt(0x33);
+ _CX=ymin;
+ _DX=ymax;
+ _AX=8;
+ geninterrupt(0x33);
+}
+
+
+void MouseHide(void)
+{
+ if (!MouseStatus) return;
+
+ _AX=2;
+ geninterrupt(0x33);
+}
+
+
+
+void MouseShow(void)
+{
+ if (!MouseStatus) return;
+
+ _AX=1;
+ geninterrupt(0x33);
+}
+
+
+
+int MouseButton(void)
+{
+ union REGS regs;
+
+ if (!MouseStatus) return 0;
+
+ regs.x.ax=3;
+ int86(0x33,&regs,&regs);
+ return(regs.x.bx);
+}
+
+
+
+void MouseCoords(int *x,int *y)
+{
+ union REGS regs;
+
+ if (!MouseStatus)
+   return;
+
+ regs.x.ax=3;
+ int86(0x33,&regs,&regs);
+ *x=regs.x.cx;
+ *y=regs.x.dx;
+
+ *x/=2;
+ if (videomode==EGA2)
+   *x*=2;
+}
+
+/////////////////////////
+//
+// print
+// Prints a string at sx,sy.  No clipping!!!
+//
+/////////////////////////
+
+void print (const char *str)
+{
+  char ch;
+
+  while ((ch=*str++) != 0)
+    if (ch == '\n')
+    {
+      sy++;
+      sx=leftedge;
+    }
+    else if (ch == '\r')
+      sx=leftedge;
+    else
+      drawchar (sx++,sy,ch);
+}
+void fprint (const char huge *str)
+{
+  char ch;
+
+  while ((ch=*str++) != 0)
+    if (ch == '\n')
+    {
+      sy++;
+      sx=leftedge;
+    }
+    else if (ch == '\r')
+      sx=leftedge;
+    else
+      drawchar (sx++,sy,ch);
+}
+
+////////////////////////////////////////////////////////////////////
+//
+// print hex byte
+//
+////////////////////////////////////////////////////////////////////
+void printhexb(unsigned char value)
+{
+ int loop;
+ char hexstr[16]="0123456789ABCDEF",str[2]="";
+
+ for (loop=0;loop<2;loop++)
+   {
+    str[0]=hexstr[(value>>(1-loop)*4)&15];
+    print(str);
+   }
+}
+
+////////////////////////////////////////////////////////////////////
+//
+// print hex
+//
+////////////////////////////////////////////////////////////////////
+void printhex(unsigned value)
+{
+ print("$");
+ printhexb(value>>8);
+ printhexb(value&0xff);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// print int
+//
+////////////////////////////////////////////////////////////////////
+void printint(unsigned value)
+{
+ char temp[10];
+
+ ultoa((unsigned long)value,temp,10);
+ print(temp);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// print bin
+//
+////////////////////////////////////////////////////////////////////
+void printbin(unsigned value)
+{
+ int loop;
+
+ print("%");
+ for (loop=0;loop<16;loop++)
+    if ((value>>15-loop)&1) print("1"); else print("0");
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// input unsigned
+//
+////////////////////////////////////////////////////////////////////
+unsigned inputint(int numchars)
+{
+ char string[18]="",digit,hexstr[16]="0123456789ABCDEF";
+ unsigned value,loop,loop1;
+
+ if (!input(string,numchars))
+   return ESCOUT;
+
+ if (string[0]=='$')
+   {
+    int digits;
+
+    digits=strlen(string)-2;
+    if (digits<0) return 0;
+
+    for (value=0,loop1=0;loop1<=digits;loop1++)
+      {
+       digit=toupper(string[loop1+1]);
+       for (loop=0;loop<16;loop++)
+         if (digit==hexstr[loop])
+           {
+            value|=(loop<<(digits-loop1)*4);
+            break;
+           }
+      }
+   }
+ else if (string[0]=='%')
+   {
+    int digits;
+
+    digits=strlen(string)-2;
+    if (digits<0) return 0;
+
+    for (value=0,loop1=0;loop1<=digits;loop1++)
+      {
+       if (string[loop1+1]<'0' || string[loop1+1]>'1') return 0;
+       value|=(string[loop1+1]-'0')<<(digits-loop1);
+      }
+   }
+ else value=atoi(string);
+ return value;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// line input routine
+//
+////////////////////////////////////////////////////////////////////
+int input(char *string,int max)
+{
+ char key;
+ int count=0,loop;
+
+ do {
+     key=get()&0xff;
+     if ((key==127 || key==8)&&count>0)
+       {
+       count--;
+       drawchar(sx,sy,' ');
+       sx--;
+       }
+
+     if (key>=' ' && key<='z' && count<max)
+       {
+       *(string+count++)=key;
+       drawchar(sx++,sy,key);
+       }
+
+    } while (key!=27 && key!=13);
+
+ for (loop=count;loop<max;loop++) *(string+loop)=0;
+
+ while(keydown[1]);    // don't let ESC repeat
+
+ if (key==13)
+   {
+    while(keydown[0x1c]);
+    return 1;
+   }
+ return 0;
+}
+
+void bar (int xl, int yl, int xh, int yh, int ch)
+{
+  int x,y;
+
+  for (y=yl;y<=yh;y++)
+    for (x=xl;x<=xh;x++)
+      drawchar (x,y,ch);
+}
+
+/////////////////////////
+//
+// get
+// Flash a cursor at sx,sy and waits for a user bioskey
+//
+/////////////////////////
+
+int get (void)
+{
+ int cycle,key;
+
+ do
+ {
+   cycle = 9;
+   while (!(key = bioskey(1)) && cycle<11)
+   {
+     drawchar (sx,sy,cycle++);
+     WaitVBL (5);
+   }
+ } while (key == 0);
+ drawchar (sx,sy,' ');
+ return bioskey(0);            // take it out of the buffer
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// drawchar
+//
+////////////////////////////////////////////////////////////////////
+void drawchar(int x,int y,int chr)
+{
+ switch(videomode)
+ {
+  case CGA: CGAcharout(x,y,chr); break;
+  case EGA1:
+  case EGA2: EGAcharout(x,y,chr,videomode); break;
+  case VGA: VGAcharout(x,y,chr);
+ }
+}
+
+////////////////////////////////////////////////////////////////////
+//
+// Set a video mode
+//
+////////////////////////////////////////////////////////////////////
+void setvideo(video vid)
+{
+ //
+ // create CGA font (if not already created)
+ //
+ if (vid==CGA && !CGAfont)
+   {
+    unsigned char huge *oldfont=MK_FP(FP_SEG(&TEDCHAR),FP_OFF(&TEDCHAR));
+    unsigned i,j,huge *newfont;
+
+    centerwindow(20,1);
+    print("Creating CGA font...");
+
+    MMAllocate(&CGAfont,2048);
+    newfont=MK_FP(CGAfont,0);
+
+    for(i=0;i<127;i++)
+      for(j=0;j<8;j++)
+       (unsigned)*(newfont+i*8+j)=doubled[*(oldfont+i*8+j)]; //color=|0xaaaa;
+   }
+ else
+ //
+ // OR create VGA font (if not already created)
+ //
+ if (vid==VGA && !VGAfont)
+   {
+    unsigned char huge *oldfont=MK_FP(FP_SEG(&TEDCHAR),FP_OFF(&TEDCHAR)),
+       huge *newfont;
+    unsigned i,j,k;
+    unsigned char bitbyte[2]={0,0xff}; // colors={0x7e,0x78};
+
+    centerwindow(20,1);
+    print("Creating VGA font...");
+
+    MMAllocate(&VGAfont,0x2000);
+    newfont=MK_FP(VGAfont,0);
+
+    for(i=0;i<128;i++)
+      for(j=0;j<8;j++)
+       for(k=0;k<8;k++)
+         *(newfont+i*64+j*8+k)=bitbyte[(*(oldfont+i*8+j)>>(7-k))&1];
+   }
+ //
+ // Now, change video modes!
+ //
+ switch(vid)
+ {
+  case TEXT: _AX=3; break;
+  case CGA:
+    screencenterx=19;
+    screencentery=11;
+    scrnbot=199;
+    scrnrgt=319;
+    _AX=4;
+    break;
+  case EGA1:
+    screencenterx=19;
+    screencentery=11;
+    scrnbot=199;
+    scrnrgt=319;
+    _AX=0x0d;
+    break;
+  case EGA2:
+    screencenterx=39;
+    screencentery=29;
+    scrnbot=479;
+    scrnrgt=638;
+    _AX=0x12;
+    break;
+  case VGA:
+    _AX=0x13;
+    screencenterx=19;
+    screencentery=11;
+    scrnbot=199;
+    scrnrgt=319;
+ }
+ geninterrupt(0x10);
+ videomode=vid;
+
+ //
+ // Set CGA mouse cursor (normal one sucks)
+ //
+ if (vid==CGA)
+   {
+    static unsigned CGAcursor[]=
+      {
+       0x0fff,0x03ff,0x00ff,0x003f,0x000f,0x0003,0x0000,0x000f,0x0c03,0x3c03,
+       0xff03,0xffff,0xffff,0xffff,0xffff,0xffff,
+
+       0xf000,0xcc00,0xc300,0xc0c0,0xc030,0xc00c,0xc03f,0xcc30,0xf30c,0xc30c,
+       0x00fc,0x0000,0x0000,0x0000,0x0000,0x0000
+      };
+
+    _BX=0;
+    _CX=0;
+    _DX=FP_OFF(CGAcursor);
+    _ES=_DS;
+    _AX=9;
+    geninterrupt(0x33);
+   }
+ else
+ //
+ // Move EGA font into LATCH memory!
+ //
+ if (vid==EGA1 || vid==EGA2)
+   {
+    unsigned i,s=FP_SEG(&TEDCHAR),o=FP_OFF(&TEDCHAR);
+
+    outport(GCindex,GCmode);
+    for (i=0;i<4;i++)
+      {
+       outport(SCindex,SCmapmask | (1<<i)*256);
+       movedata(s,o+i*0x400,0xaf00,0,0x400);
+      }
+   }
+ else
+ //
+ // OR set the VGA palette
+ //
+ if (vid==VGA) // set VGA palette
+   {
+    _BX=0;
+    _CX=0x100;
+    _DX=FP_OFF(&VGAPAL);
+    _ES=FP_SEG(&VGAPAL);
+    _AX=0x1012;
+    geninterrupt(0x10);
+   }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Quit the fuck outta here!
+//
+////////////////////////////////////////////////////////////////////
+void Quit(char *string)
+{
+ Unhook();
+ setvideo(TEXT);
+ poke(0,0x41a,peek(0,0x41c));  // clear keyboard
+ if (string[0])
+   {
+    printf("TED5 ERROR: %s",string);
+    exit(1);
+   }
+ printf("Thanks for using TED5!");
+ nosound();
+ exit(0);
+}
+
+
+//////////////////////////
+//
+// drawwindow
+// draws a bordered window and homes the cursor
+//
+//////////////////////////
+
+void drawwindow (int xl, int yl, int xh, int yh)
+{
+ int x,y;
+ win_xl=xl;
+ win_yl=yl;
+ win_xh=xh;
+ win_yh=yh;            // so the window can be erased
+
+ drawchar (xl,yl,1);
+ for (x=xl+1;x<xh;x++)
+   drawchar (x,yl,2);
+ drawchar (xh,yl,3);
+ for (y=yl+1;y<yh;y++)
+ {
+   drawchar (xl,y,4);
+   for (x=xl+1;x<xh;x++)
+     drawchar (x,y,' ');
+   drawchar (xh,y,5);
+ }
+ drawchar (xl,yh,6);
+ for (x=xl+1;x<xh;x++)
+   drawchar (x,yh,7);
+ drawchar (xh,yh,8);
+
+ sx = leftedge = xl+1;
+ sy = yl+1;
+}
+
+////////////////////////////
+//
+// erasewindow
+// clears out the last window and it's border to spaces
+//
+///////////////////////////
+
+void erasewindow (void)
+{
+  bar (win_xl,win_yl,win_xh,win_yh,' ');
+}
+
+/////////////////////////////
+//
+// centerwindow
+// Centers a drawwindow of the given size
+//
+/////////////////////////////
+
+void centerwindow (int width, int height)
+{
+  int xl = screencenterx-width/2;
+  int yl = screencentery-height/2;
+
+  drawwindow (xl,yl,xl+width+1,yl+height+1);
+}
+
+///////////////////////////////
+//
+// expwin {h / v}
+// Grows the window outward
+//
+///////////////////////////////
+void expwinh (int width, int height)
+{
+  if (width > 2)
+    expwinh (width-2,height);
+
+  WaitVBL (1);
+  centerwindow (width,height);
+}
+
+void expwinv (int width, int height)
+{
+  if (height >2)
+    expwinv (width,height-2);
+
+  WaitVBL (1);
+  centerwindow (width,height);
+}
+void expwin (int width, int height)
+{
+  if (width > 2)
+  {
+    if (height >2)
+      expwin (width-2,height-2);
+    else
+      expwinh (width-2,height);
+  }
+  else
+    if (height >2)
+      expwinv (width,height-2);
+
+  WaitVBL (1);
+  centerwindow (width,height);
+}
+
+
+////////////////////////////////////////////////////////////
+//
+// Save a *LARGE* file from a FAR buffer!
+// by John Romero (C) 1990 Gamer's Edge
+//
+////////////////////////////////////////////////////////////
+void SaveFile(char *filename,char huge *buffer,long offset,long size)
+{
+ unsigned int handle,buf1,buf2,offlo,offhi,sizelo,sizehi;
+
+ buf1=FP_OFF(buffer);
+ buf2=FP_SEG(buffer);
+ offlo=offset&0xffff;
+ offhi=offset>>16;
+ sizelo=size&0xffff;
+ sizehi=size>>16;
+
+asm            mov     ax,offlo
+asm            or      ax,offhi
+asm            jz      CREATEIT
+
+asm            mov     dx,filename
+asm            mov     ax,3d02h                // OPEN w/handle (read only)
+asm            int     21h
+asm            jnc     L0
+
+ return;
+
+L0:
+
+asm            mov     handle,ax
+
+asm            mov     bx,handle
+asm            mov     dx,offlo
+asm            mov     cx,offhi
+asm            mov     ax,4200h
+asm            int     21h                     // SEEK (to file offset)
+asm            jc      out
+
+asm            jmp     DOSAVE
+
+CREATEIT:
+
+asm            mov     dx,filename
+asm            mov     ax,3c00h                // CREATE w/handle (read only)
+asm            xor     cx,cx
+asm            int     21h
+asm            jc      out
+
+asm            mov     handle,ax
+
+DOSAVE:
+
+asm            cmp     WORD PTR sizehi,0               // larger than 1 segment?
+asm            je      L2
+
+L1:
+
+asm            push    ds
+asm            mov     bx,handle
+asm            mov     cx,8000h
+asm            mov     dx,buf1
+asm            mov     ax,buf2
+asm            mov     ds,ax
+asm            mov     ah,40h                  // WRITE w/handle
+asm            int     21h
+asm            pop     ds
+
+asm            add     WORD PTR buf2,800h              // bump ptr up 1/2 segment
+asm            sub     WORD PTR sizelo,8000h           // done yet?
+asm            sbb     WORD PTR sizehi,0
+asm            cmp     WORD PTR sizehi,0
+asm            ja      L1
+asm            cmp     WORD PTR sizelo,8000h
+asm            jae     L1
+
+L2:
+
+asm            push    ds
+asm            mov     bx,handle
+asm            mov     cx,sizelo
+asm            mov     dx,buf1
+asm            mov     ax,buf2
+asm            mov     ds,ax
+asm            mov     ah,40h                  // WRITE w/handle
+asm            int     21h
+asm            pop     ds
+
+out:
+
+asm            mov     bx,handle               // CLOSE w/handle
+asm            mov     ah,3eh
+asm            int     21h
+
+}
+
+////////////////////////////////////////////////////////////
+//
+// Load a *LARGE* file into a FAR buffer!
+// by John Romero (C) 1990 Gamer's Edge
+//
+////////////////////////////////////////////////////////////
+unsigned long LoadFile(char *filename,char huge *buffer,long offset,long size)
+{
+ unsigned handle,flength1=0,flength2=0,buf1,buf2,len1,len2,
+         rsize1,rsize2,roffset1,roffset2;
+
+ rsize1=size&0xffff;
+ rsize2=size>>16;
+ roffset1=offset&0xffff;
+ roffset2=offset>>16;
+ buf1=FP_OFF(buffer);
+ buf2=FP_SEG(buffer);
+
+asm            mov     dx,filename
+asm            mov     ax,3d00h                // OPEN w/handle (read only)
+asm            int     21h
+asm            jnc     L_0
+
+ return 0;
+
+L_0:
+
+asm            mov     handle,ax
+asm            mov     bx,ax
+asm            xor     cx,cx
+asm            xor     dx,dx
+asm            mov     ax,4202h
+asm            int     21h                     // SEEK (find file length)
+asm            jc      out
+
+asm            mov     flength1,ax
+asm            mov     len1,ax
+asm            mov     flength2,dx
+asm            mov     len2,dx
+
+asm            mov     ax,rsize1               // was a size specified?
+asm            or      ax,rsize1
+asm            jz      LOADALL
+
+asm            mov     ax,rsize1               // only load size requested
+asm            mov     len1,ax
+asm            mov     ax,rsize2
+asm            mov     len2,ax
+
+LOADALL:
+
+asm            mov     bx,handle
+asm            mov     dx,roffset1
+asm            mov     cx,roffset2
+asm            mov     ax,4200h
+asm            int     21h                     // SEEK (to file offset)
+asm            jc      out
+
+asm            cmp     WORD PTR len2,0                 // MULTI-SEGMENTAL?
+asm            je      L_2
+
+L_1:
+
+asm            push    ds
+asm            mov     bx,handle
+asm            mov     cx,8000h                // read 32K chunks
+asm            mov     dx,buf1
+asm            mov     ax,buf2
+asm            mov     ds,ax
+asm            mov     ah,3fh                  // READ w/handle
+asm            int     21h
+asm            pop     ds
+asm            jc      out
+
+asm            add     WORD PTR buf2,800h
+asm            sub     WORD PTR len1,8000h
+asm            sbb     WORD PTR len2,0
+asm            cmp     WORD PTR len2,0
+asm            ja      L_1
+asm            cmp     WORD PTR len1,8000h
+asm            jae     L_1
+
+L_2:
+
+asm            push    ds
+asm            mov     bx,handle
+asm            mov     cx,len1
+asm            mov     dx,buf1
+asm            mov     ax,buf2
+asm            mov     ds,ax
+asm            mov     ah,3fh                  // READ w/handle
+asm            int     21h
+asm            pop     ds
+asm            jmp     exit
+
+out:
+
+asm            mov     WORD PTR flength2,0
+asm            mov     WORD PTR flength1,0
+
+exit:
+
+asm            mov     bx,handle               // CLOSE w/handle
+asm            mov     ah,3eh
+asm            int     21h
+
+ return (flength2*0x10000+flength1);
+
+}
+
+
+////////////////////////////////////////////////////////////
+//
+// Allocate memory and load file in
+//
+////////////////////////////////////////////////////////////
+void LoadIn(char *filename,void _seg **baseptr)
+{
+ char errstr[80];
+ int handle;
+ long len;
+
+ if ((handle=open(filename,O_BINARY))==-1)
+   {
+    strcpy(errstr,"Error loading file ");
+    strcat(errstr,filename);
+    Quit(errstr);
+   }
+
+ len=filelength(handle);
+ close(handle);
+ MMAllocate((memptr *)baseptr,len);
+ LoadFile(filename,MK_FP(*baseptr,0),0,0);
+}
+
+
diff --git a/16/ted5/LIB.H b/16/ted5/LIB.H
new file mode 100755 (executable)
index 0000000..4075871
--- /dev/null
@@ -0,0 +1,42 @@
+typedef enum {CGA,EGA1,EGA2,VGA,TEXT} video;
+#define ESCOUT 0xdeaf
+
+void Quit(char *string);
+void WaitVBL(int times);
+int  input(char *string,int max);
+void SetupKBD ();
+void ShutdownKBD ();
+void clearkeys (void);
+int  MouseInit(void);
+void MouseHide(void);
+void MouseShow(void);
+int  MouseButton(void);
+void MouseCoords(int *x,int *y);
+void printhex(unsigned value);
+void printbin(unsigned value);
+unsigned inputint(int numchars);
+int  input(char *string,int max);
+void print (const char *str);
+void fprint (const char huge *str);
+void printhexb(unsigned char value);
+void printint(unsigned value);
+void bar (int xl, int yl, int xh, int yh, int ch);
+int  get(void);
+void drawwindow (int xl, int yl, int xh, int yh);
+void erasewindow (void);
+void centerwindow (int width, int height);
+void expwin (int width, int height);
+void expwinh (int width, int height);
+void expwinv (int width, int height);
+void SaveFile(char *filename,char huge *buffer, long size,long offset);
+unsigned long LoadFile(char *filename,char huge *buffer,long offset,long size);
+void LoadIn(char *filename,void _seg **baseptr);
+
+void MouseOrigin(int x,int y);
+void MouseLimits(int xmin,int xmax,int ymin,int ymax);
+
+extern int win_xl,win_yl,win_xh,win_yh,screencenterx,screencentery;
+extern unsigned char keydown[256];
+extern unsigned sx,sy,xormask,MouseStatus,leftedge;
+
+long filelen(char *filename);
\ No newline at end of file
diff --git a/16/ted5/LIB_A.ASM b/16/ted5/LIB_A.ASM
new file mode 100755 (executable)
index 0000000..1ce1de9
--- /dev/null
@@ -0,0 +1,259 @@
+;====================================================
+;
+; Library ASM code
+;
+;====================================================
+       IDEAL
+       P386N
+       MODEL   medium,C
+
+extrn  xormask:WORD,yshift:WORD,CGAfont:WORD,VGAfont:WORD
+
+       DATASEG
+
+SCindex        =       3c4h
+SCmapmask =    2
+GCindex =              3CEh
+GCreadmap =    4
+GCmode         =       5
+
+a      =       0
+LABEL  CGAlookup WORD
+PUBLIC CGAlookup
+       REPT    100
+       dw      a,a XOR 2000h
+a      =       a+80
+       ENDM
+
+a      =       0
+LABEL  EGA1lookup WORD
+PUBLIC EGA1lookup
+       REPT    200
+       dw      a
+a      =       a+40
+       ENDM
+
+a      =       0
+LABEL  EGA2lookup WORD
+PUBLIC EGA2lookup
+       REPT    480
+       dw      a
+a      =       a+80
+       ENDM
+
+a      =       0
+LABEL  VGAlookup WORD
+PUBLIC VGAlookup
+       REPT    200
+       dw      a
+a      =       a+320
+       ENDM
+
+
+       CODESEG
+
+;====================================================
+;
+; Draw CGA chars
+;
+;====================================================
+PROC CGAcharout
+PUBLIC CGAcharout
+ARG    x:WORD,y:WORD,chr:BYTE
+USES si,di,ds
+       mov     bx,[y]
+       shl     bx,1
+       shl     bx,1
+       shl     bx,1
+       shl     bx,1
+       mov     di,[CGAlookup+bx]
+       mov     ax,[x]
+       shl     ax,1
+       add     di,ax
+
+       mov     al,[chr]
+       xor     ah,ah
+       shl     ax,1
+       shl     ax,1
+       shl     ax,1
+       shl     ax,1
+       mov     si,ax
+
+       mov     ax,0b800h
+       mov     es,ax
+       mov     ds,[CGAfont]
+       cld
+       cmp     [ss:xormask],0
+       ja      @@1
+
+       REPT    4
+       movsw
+       add     di,2000h-2
+       movsw
+       sub     di,2000h-78
+       ENDM
+       jmp     @@exit
+@@1:
+       REPT    4
+       lodsw
+       xor     ax,0ffffh
+       stosw
+       add     di,2000h-2
+       lodsw
+       xor     ax,0ffffh
+       stosw
+       sub     di,2000h-78
+       ENDM
+@@exit:
+       ret
+ENDP
+
+;====================================================
+;
+; Draw EGA chars
+;
+;====================================================
+PROC EGAcharout
+PUBLIC EGAcharout
+ARG    x:WORD,y:WORD,chr:BYTE,video:WORD
+USES si,di,ds,bp
+
+       mov     dx,GCindex
+       mov     ax,GCmode
+       out     dx,ax
+
+       mov     bx,[y]
+       shl     bx,1
+       shl     bx,1
+       shl     bx,1
+       add     bx,[yshift]
+       shl     bx,1
+
+       cmp     [video],1
+       jne     @@0
+       mov     cx,39
+       mov     di,[EGA1lookup+bx]
+       jmp     @@1
+@@0:
+       mov     cx,79
+       mov     di,[EGA2lookup+bx]
+@@1:
+       add     di,[x]
+
+       mov     ax,0a000h
+       mov     es,ax
+       mov     ds,ax
+
+       mov     si,0f000h
+       mov     al,[chr]
+       xor     ah,ah
+       shl     ax,1
+       shl     ax,1
+       shl     ax,1
+       add     si,ax
+
+       cld
+       cmp     [ss:xormask],0
+       ja      @@2
+
+       mov     dx,GCindex
+       mov     ax,GCmode OR 100h
+       out     dx,ax
+       mov     dx,SCindex
+       mov     ax,SCmapmask OR 0f00h
+       out     dx,ax
+
+       REPT    8
+       movsb
+       add     di,cx
+       ENDM
+       jmp     @@exit
+
+@@2:
+ga     =       100h
+gb     =       0
+       mov     bp,si
+       mov     bx,di
+       REPT    4
+       mov     dx,SCindex
+       mov     ax,SCmapmask OR ga
+       out     dx,ax
+       mov     dx,GCindex
+       mov     ax,GCreadmap OR gb
+       out     dx,ax
+       REPT    8
+       lodsb
+       xor     al,0ffh
+       stosb
+       add     di,cx
+       ENDM
+       mov     di,bx
+       mov     si,bp
+ga     =       ga*2
+gb     =       gb+100h
+       ENDM
+@@exit:
+       mov     dx,GCindex
+       mov     ax,GCmode
+       out     dx,ax
+       ret
+ENDP
+
+;====================================================
+;
+; Draw VGA chars
+;
+;====================================================
+PROC VGAcharout
+PUBLIC VGAcharout
+ARG    x:WORD,y:WORD,chr:BYTE
+USES si,di,ds
+
+       mov     bx,[y]
+       shl     bx,1
+       shl     bx,1
+       shl     bx,1
+       add     bx,[yshift]
+       shl     bx,1
+       mov     di,[VGAlookup+bx]
+
+       mov     ax,[x]
+       shl     ax,1
+       shl     ax,1
+       shl     ax,1
+       add     di,ax
+
+       mov     ah,[chr]
+       xor     al,al
+       shr     ax,1
+       shr     ax,1    ;[chr]*64!
+       mov     si,ax
+
+       mov     ax,0a000h
+       mov     es,ax
+       mov     ds,[VGAfont]
+
+       cmp     [ss:xormask],0
+       ja      @@1
+
+       REPT    8
+       REPT    4
+       movsw
+       ENDM
+       add     di,320-8
+       ENDM
+       jmp     @@exit
+@@1:
+       REPT    8
+       REPT    4
+       lodsw
+       xor     ax,0ffffh
+       stosw
+       ENDM
+       add     di,320-8
+       ENDM
+@@exit:
+       ret
+ENDP
+
+END
diff --git a/16/ted5/MAPTEMP b/16/ted5/MAPTEMP
new file mode 100755 (executable)
index 0000000..48f87cc
Binary files /dev/null and b/16/ted5/MAPTEMP differ
diff --git a/16/ted5/MAPTHEAD b/16/ted5/MAPTHEAD
new file mode 100755 (executable)
index 0000000..dee1d89
Binary files /dev/null and b/16/ted5/MAPTHEAD differ
diff --git a/16/ted5/MEMMGR.C b/16/ted5/MEMMGR.C
new file mode 100755 (executable)
index 0000000..d13240f
--- /dev/null
@@ -0,0 +1,781 @@
+#include "ted5.h"
+#pragma hdrstop
+
+#define EMSINT         0x67
+
+#define SPACEFREE      0x2000  // how much mem to leave alone in farheap
+#define EXTRASTACKSIZE 0x2000
+#define MAXBLOCKS      1000
+#define LOCKBIT                0x8000  // if set in attributes, block cannot be moved
+#define PURGEBITS      3       // 0-3 level, 0= unpurgable, 3= purge first
+
+#define BASEATTRIBUTES 0       // unlocked, non purgable
+
+unsigned totalmem;             // total paragraphs available with 64k EMS
+int    EMSpresent,XMSpresent;
+
+
+long TTLMainMem;
+
+void far *farheap;
+void *nearheap;
+
+int    numblocks;
+struct {
+        unsigned start;        // in paragraphs
+        unsigned length;
+        unsigned attributes;
+        memptr *useptr;
+       } blocks[MAXBLOCKS],tempblock;
+
+//==========================================================================
+
+//
+// local prototypes
+//
+void CheckForEMS (void);
+int FindBlock (memptr *ptr);
+void RemoveBlock (int block);
+void InsertBlock (int block);
+
+
+//
+// public prototypes
+//
+
+void MMStartup (void);
+void MMShutdown (void);
+void MMMapEMS (void);
+void MMGetPtr (memptr *baseptr,unsigned size);
+void MMFreePtr (memptr *baseptr);
+void MMSetPurge (memptr *baseptr, int purge);
+void MMSortMem (void);
+void MMBlockDump (void);
+unsigned MMUnusedMemory (void);
+unsigned MMTotalFree (void);
+
+//==========================================================================
+
+
+//
+// CheckForEMS
+//
+// Routine from p36 of Extending DOS
+//
+void CheckForEMS (void)
+{
+  char emmname[9] = "EMMXXXX0";
+
+asm    mov     dx,OFFSET emmname
+asm    mov     ax,0x3d00
+asm    int     0x21            // try to open EMMXXXX0 device
+asm    jc      error
+
+asm    mov     bx,ax
+asm    mov     ax,0x4400
+
+asm    int     0x21            // get device info
+asm    jc      error
+
+asm    and     dx,0x80
+asm    jz      error
+
+asm    mov     ax,0x4407
+
+asm    int     0x21            // get status
+asm    jc      error
+asm    or      al,al
+asm    jz      error
+
+asm    mov     ah,0x3e
+asm    int     0x21            // close handle
+asm    jc      error
+
+//
+// EMS is good
+//
+
+
+  return;
+
+error:
+//
+// EMS is bad
+//
+  EMSpresent = 0;
+
+}
+
+//==========================================================================
+
+
+//
+// FindBlock
+//
+int FindBlock (memptr *ptr)
+{
+  int i;
+  for (i=1;i<numblocks;i++)
+    if (blocks[i].useptr == ptr)
+      return i;
+
+  Quit ("Memory manager error: Block not found!");
+  return -1;
+}
+
+//
+// RemoveBlock
+// 0 the pointer, close the block array down, and decrement numblocks
+//
+void RemoveBlock (int block)
+{
+  void far *source, far *dest;
+  unsigned length;
+
+  *blocks[block].useptr = NULL;
+  if (block!=numblocks-1)
+  {
+    source = &blocks[block+1];
+    dest = &blocks[block];
+    length = (numblocks-1-block)*sizeof(blocks[0]);
+    movedata (FP_SEG(source),FP_OFF(source),FP_SEG(dest),FP_OFF(dest),length);
+  }
+  numblocks--;
+}
+
+//
+// InsertBlock
+// Inserts space in the block array AFTER parameter and increments numblocks
+//
+void InsertBlock (int block)
+{
+  unsigned source,dest,length;
+
+  if (block!=numblocks-1)
+  {
+    source = ((unsigned)&blocks[numblocks])-2;
+    dest = ((unsigned)&blocks[numblocks+1])-2;
+    length = (numblocks-1-block)*sizeof(blocks[0])/2;
+asm    mov     cx,length
+asm    mov     si,source
+asm    mov     di,dest
+asm    mov     ax,ds
+asm    mov     es,ax
+asm    std
+asm    rep     movsw
+asm    cld
+  }
+  if (++numblocks>=MAXBLOCKS)
+    Quit ("Memory manager error: Too many blocks!");
+}
+
+
+
+// check numblocks<MAXBLOCKS
+
+//==========================================================================
+
+/*
+===================
+=
+= MMStartup
+=
+= Initializes the memory manager and returns the total
+= allocatable free space.
+=
+= Grabs all space from turbo with farmalloc
+=
+===================
+*/
+
+void MMStartup (void)
+{
+  unsigned long length;
+  void far *start;
+  unsigned nearstart,farstart,EMSstart,seg,i;
+  unsigned nearlength,farlength,emslength,xmslength;
+
+//
+// get all available near conventional memory
+//
+  length=coreleft();
+  start = (void far *)(nearheap = malloc(length-SPACEFREE));
+
+//
+// paragraph align it and figure size
+//
+  length -= 16-(FP_OFF(start)&15);
+  length -= EXTRASTACKSIZE;
+  nearlength = length / 16;                    // now in paragraphs
+  nearstart = FP_SEG(start)+(FP_OFF(start)+15)/16;
+
+//
+// get all available far conventional memory
+//
+  length=farcoreleft();
+  start = farheap = farmalloc(length);
+
+//
+// paragraph align it and figure size
+//
+  if (FP_OFF(start))
+  {
+    length -= 16-FP_OFF(start);
+    start = (void far *)MK_FP(FP_SEG(start)+1,0);
+  }
+  farlength = length / 16;                     // now in paragraphs
+  farstart = FP_SEG(start);
+
+  totalmem = nearlength + farlength;
+
+//
+// detect EMS and allocate 64K at page frame
+//
+  CheckForEMS();
+  if (EMSpresent)
+  {
+    EMSstart = 0xffff;
+    totalmem += 0x1000;                                // 64k of EMS
+    MMMapEMS();                                        // map in used pages
+  }
+  else
+  {
+    EMSstart = 0xffff;
+  }
+
+//
+// set up locked blocks
+//
+  numblocks = 0;
+
+  blocks[numblocks].start = 0;
+  blocks[numblocks].length = nearstart;
+  blocks[numblocks].attributes = LOCKBIT;
+
+  numblocks++;
+
+  blocks[numblocks].start = nearstart+nearlength;
+  blocks[numblocks].length = farstart-(nearstart+nearlength);
+  blocks[numblocks].attributes = LOCKBIT;
+
+  numblocks++;
+
+  blocks[numblocks].start = farstart+farlength;
+  blocks[numblocks].length = EMSstart-(farstart+farlength);
+  blocks[numblocks].attributes = LOCKBIT;
+
+  numblocks++;
+
+  TTLMainMem=16L*MMTotalFree();
+}
+
+//==========================================================================
+
+/*
+====================
+=
+= MMShutdown
+=
+= Frees all conventional, EMS, and XMS allocated
+=
+====================
+*/
+
+void MMShutdown (void)
+{
+ int i;
+
+ //
+ // 0 the pointers (if any)
+ //
+  for (i=0;i<numblocks-1;i++)
+    *blocks[i].useptr=NULL;
+
+  farfree (farheap);
+  free (nearheap);
+
+}
+
+//==========================================================================
+
+/*
+====================
+=
+= MMMapEMS
+=
+= Maps the 64k of EMS used by memory manager into the page frame
+= for general use.
+=
+====================
+*/
+
+void MMMapEMS (void)
+{
+
+}
+
+//==========================================================================
+
+/*
+====================
+=
+= MMGetPtr
+=
+= Allocates an unlocked, unpurgable block
+= Start looking at the top of memory
+=
+====================
+*/
+void MMAllocate(memptr *baseptr,long size)
+{
+ MMGetPtr(baseptr,(unsigned)((size+15)/16));
+ TTLMainMem=16L*MMTotalFree();
+}
+
+void MMGetPtr (memptr *baseptr,unsigned size)
+{
+  int i,j,k,try;
+  unsigned start,end;
+
+  //
+  // try a normal scan, then compress if not found
+  //
+  for (try=0;try<2;try++)
+  {
+    for (i=0;i<numblocks-1;i++)
+    {
+      if (blocks[i].attributes & PURGEBITS )
+       continue;
+      //
+      // blocks[i] cannot be written over, so try to allocate the
+      // new block right after it
+      //
+      start = blocks[i].start + blocks[i].length;
+      end = start + size;
+      j=i+1;
+      while (blocks[j].start < end)
+      {
+       if (!(blocks[j].attributes & PURGEBITS))
+       {
+         i = j-1;
+         goto lookmore;                // a non purgable block is in the way
+       }
+       j++;
+      }
+      //
+      // purge the blocks in the way
+      //
+      for (k=i+1;k<j;j--)
+       RemoveBlock(k);
+      //
+      // allocate the new block
+      //
+      InsertBlock(i);
+      *(unsigned *)baseptr = start;
+      blocks[i+1].start = start;
+      blocks[i+1].length = size;
+      blocks[i+1].useptr = baseptr;
+      blocks[i+1].attributes = BASEATTRIBUTES;
+      return;
+lookmore:;
+    }
+    //
+    // didn't find any space, so compress and try again
+    //
+    if (try==0)
+      MMSortMem();
+  }
+
+//puts("");
+//MMBlockDump();       // DEBUG
+  Quit ("Memory manager error: Out of memory!");
+}
+
+//==========================================================================
+
+/*
+=====================
+=
+= MMFreePtr
+=
+= Frees up a block and NULL's the pointer
+=
+=====================
+*/
+
+void MMFreePtr (memptr *baseptr)
+{
+ RemoveBlock(FindBlock (baseptr));
+ TTLMainMem=16L*MMTotalFree();
+}
+
+
+//==========================================================================
+
+/*
+=====================
+=
+= MMSetPurge
+=
+= Sets the purge level for a block
+=
+=====================
+*/
+
+void MMSetPurge (memptr *baseptr, int purge)
+{
+  int block;
+  unsigned attr;
+
+  block = FindBlock (baseptr);
+
+  attr = blocks[block].attributes;
+  attr &= 0xffff - PURGEBITS;
+  attr |= purge;               // set bits in attributes
+  blocks[block].attributes = attr;
+}
+
+
+/*
+=============================================================================
+
+                           MMSortMem
+
+=============================================================================
+*/
+
+//
+// MoveParas
+//
+void MoveParaBase (unsigned source, unsigned dest, unsigned words)
+{
+asm    mov     cx,words
+asm    xor     si,si
+asm    xor     di,di
+asm    mov     ax,source
+asm    mov     bx,dest
+asm    mov     ds,source
+asm    mov     es,dest
+asm    rep     movsw
+asm    mov     ax,ss
+asm    mov     ds,ax
+}
+
+void MoveParaBaseUp (unsigned source, unsigned dest, unsigned words)
+{
+asm    mov     cx,words
+asm    mov     si,cx
+asm    dec     si
+asm    shl     si,1
+asm    mov     di,si
+asm    mov     ax,source
+asm    mov     bx,dest
+asm    mov     ds,source
+asm    mov     es,dest
+asm    rep     movsw
+asm    mov     ax,ss
+asm    mov     ds,ax
+}
+
+
+void MoveParas (unsigned source, unsigned dest, unsigned paragraphs)
+{
+  if (source>dest)
+  {
+asm    cld
+    while (paragraphs>0xfff)
+    {
+      MoveParaBase (source,dest,0xfff*8);
+      source += 0xfff*8;
+      dest += 0xfff*8;
+      paragraphs -= 0xfff;
+    }
+    MoveParaBase (source,dest,paragraphs*8);
+  }
+  else
+  {
+asm    std
+    source+=paragraphs;
+    dest+=paragraphs;
+    while (paragraphs>0xfff)
+    {
+      source-=0xfff;
+      dest-=0xfff;
+      MoveParaBaseUp (source,dest,0xfff*8);
+      paragraphs -= 0xfff;
+    }
+    source-=paragraphs;
+    dest-=paragraphs;
+    MoveParaBaseUp (source,dest,paragraphs*8);
+asm    cld
+  }
+}
+
+
+/*
+======================
+=
+= MMSortMem
+=
+= Sorts all non locked blocks so lower purge levels are lower in memory
+= and all free space is at the top
+=
+======================
+*/
+
+int keyblock;
+
+//
+// PushUp
+//
+// Pushes the block (purgeable) as high in memory as possible
+// must be BELOW keyblock
+// If it can't fit above keyblock it will be freed
+//
+void PushUp (int move)
+{
+  unsigned source,dest,size;
+  int i;
+
+  size = blocks[move].length;
+  source = blocks[move].start;
+
+  for (i=numblocks-1;i>keyblock;i--)
+  {
+  //
+  // if the block can fit under this block, move it
+  //
+    dest = blocks[i].start - size;
+    if (blocks[i-1].start+blocks[i-1].length <= dest)
+    {
+    //
+    // make a copy of block 'move' under block 'i'
+    //
+      InsertBlock (i-1);
+      blocks[i] = blocks[move];
+      blocks[i].start = dest;
+      *(blocks[i].useptr) = (void _seg *)dest; // modify the pointer to the new spot
+      MoveParas (source,dest,size);
+      break;
+    }
+  }
+
+  //
+  // erase original position
+  //
+  RemoveBlock (move);
+  keyblock--;          // because a block below it was removed
+}
+
+
+//
+// PushDown
+//
+// Push keyblock (unpurgable) as low in memory as possible
+//
+void PushDown (void)
+{
+  unsigned source,dest,size,end,lowblock,checkblock,i;
+
+  size = blocks[keyblock].length;
+  source = blocks[keyblock].start;
+
+//
+// find the lowest space it can be moved into
+//
+  for (lowblock = 0;lowblock<keyblock;lowblock++)
+    if (!(blocks[lowblock].attributes & PURGEBITS) ||
+       blocks[lowblock].attributes & LOCKBIT)
+    {
+    //
+    // found a locked or nonpurgable block below keyblock
+    //
+    // see if there is enough space to move block
+    //
+      dest = blocks[lowblock].start + blocks[lowblock].length;
+      end = dest+size;
+
+    //
+    // see if any of the blocks in the middle can be moved away
+    //
+      checkblock = lowblock+1;
+      while (checkblock < keyblock && blocks[checkblock].start<end)
+      {
+       if (!(blocks[checkblock].attributes & PURGEBITS) )
+         goto nofit;   // can't fit between two locked blocks
+       //
+       // push the block up or remove it, in either case dropping
+       // keyblock and changing blocks[checkblock]
+       //
+       PushUp (checkblock);
+      }
+//
+// move it!
+//
+      if (dest != source)
+      {
+       MoveParas (source,dest,size);
+       blocks[keyblock].start = dest;
+       *(blocks[keyblock].useptr) = (void _seg *)dest; // modify the pointer to the new spot
+       if (lowblock<keyblock-1)
+       {
+       //
+       // reorder the block records
+       //
+         tempblock = blocks[keyblock];
+         for (i=keyblock;i>lowblock+1;i--)
+           blocks[i]=blocks[i-1];
+         blocks[lowblock+1] = tempblock;
+       }
+
+//MMBlockDump();       // DEBUG
+      }
+      return;
+
+ nofit:;               // keep looking...
+
+    }
+}
+
+
+//
+// MMSortMem
+//
+
+void MMSortMem (void)
+{
+  unsigned i,source,dest;
+
+  keyblock = 0;
+
+  do
+  {
+    keyblock++;
+
+    //
+    // non-purgable, unlocked blocks will be pushed low in memory
+    //
+    if ( !(blocks[keyblock].attributes & PURGEBITS) &&
+        !(blocks[keyblock].attributes & LOCKBIT) )
+      PushDown ();
+
+  } while (keyblock<numblocks-1);
+
+
+  for (i=numblocks-2;i>0;i--)
+  {
+    //
+    // push all purgable blocks as high as possible
+    // Currently they are NOT moved around locked blocks!
+    //
+    if ( blocks[i].attributes & PURGEBITS )
+    {
+      source= blocks[i].start;
+      dest= blocks[i+1].start-blocks[i].length;
+      if (source!=dest)
+      {
+       MoveParas (source,dest,blocks[i].length);
+       blocks[i].start = dest;
+       *(blocks[i].useptr) = (void _seg *)dest;        // modify the pointer to the new spot
+      }
+    }
+  }
+
+  PatchPointers();             // let the main program fix up any
+                               // internal references
+}
+
+
+//==========================================================================
+
+/*
+=======================
+=
+= MMBlockDump
+=
+= Dewbug tool
+=
+=======================
+*/
+
+void MMBlockDump (void)
+{
+  int i;
+  unsigned free;
+
+  fprintf (stdprn,"-------------\n");
+  for (i=0;i<numblocks;i++)
+  {
+    fprintf (stdprn,"Start:%4X\tLength:%4X\tAttr:%4X\tPtr:%p\n"
+    ,blocks[i].start,blocks[i].length,blocks[i].attributes,blocks[i].useptr);
+    if (i<numblocks-1)
+    {
+      free = blocks[i+1].start - (blocks[i].start+blocks[i].length);
+      if (free)
+       fprintf (stdprn,"### Free:%X\n",free);
+    }
+  }
+  puts("");
+}
+
+
+//==========================================================================
+
+/*
+======================
+=
+= MMUnusedMemory
+=
+= Returns the total free space without purging
+=
+======================
+*/
+
+unsigned MMUnusedMemory (void)
+{
+  int i;
+  unsigned free;
+
+  free = 0;
+
+  for (i=0;i<numblocks;i++)
+  {
+    if (i<numblocks-1)
+      free += blocks[i+1].start - (blocks[i].start+blocks[i].length);
+  }
+
+  return free;
+}
+
+//==========================================================================
+
+
+/*
+======================
+=
+= MMTotalFree
+=
+= Returns the total free space with purging
+=
+======================
+*/
+
+unsigned MMTotalFree (void)
+{
+  int i;
+  unsigned free;
+
+  free = 0;
+
+  for (i=0;i<numblocks;i++)
+  {
+    if (blocks[i].attributes & PURGEBITS)
+      free += blocks[i].length;
+    if (i<numblocks-1)
+      free += blocks[i+1].start - (blocks[i].start+blocks[i].length);
+  }
+
+  return free;
+}
+
+//==========================================================================
diff --git a/16/ted5/MEMMGR.H b/16/ted5/MEMMGR.H
new file mode 100755 (executable)
index 0000000..dab1357
--- /dev/null
@@ -0,0 +1,28 @@
+
+typedef void _seg * memptr;
+
+extern long TTLMainMem;
+extern unsigned totalmem;              // total paragraphs available with 64k EMS
+extern int     EMSpresent,XMSpresent;
+
+
+//==========================================================================
+
+//
+// public prototypes
+//
+
+void MMStartup (void);
+void MMShutdown (void);
+void MMMapEMS (void);
+void MMAllocate(memptr *baseptr,long size);
+void MMGetPtr (memptr *baseptr,unsigned size);
+void MMFreePtr (memptr *baseptr);
+void MMSetPurge (memptr *baseptr, int purge);
+void MMSortMem (void);
+void MMBlockDump (void);
+unsigned MMUnusedMemory (void);
+unsigned MMTotalFree (void);
+
+
+void PatchPointers (void);     // must be present in the main program
\ No newline at end of file
diff --git a/16/ted5/MENU.C b/16/ted5/MENU.C
new file mode 100755 (executable)
index 0000000..63f47a6
--- /dev/null
@@ -0,0 +1,1877 @@
+/////////////////////////////////////////////////////////////////
+//
+// Pull-Down Menu Interface
+// by John Romero (C) 1991 Id Software
+//
+/////////////////////////////////////////////////////////////////
+#include "ted5.h"
+#pragma hdrstop
+
+#define NUMFLASHES     10
+#define ALT            0x38
+#define CTRL           0x1d
+
+#define CGASIZE                0x4000
+#define EGA1SIZE       0x2000
+#define EGA2SIZE       0x9600
+#define EGA3SIZE       60000
+#define VGASIZE                64000
+
+void (*HookRoutine)(int x,int y);
+void (*ItemRoutine)(void);
+char MenuStr[20][80],tempstr[80];
+memptr Background[10];
+int WhichBack;
+struct { int savex,savey,savew,saveh;  } Back[10];
+MBarDef *MBarPtr;
+MInfoType MenuInfo[10];
+int ScreenWidth,OpenMenu,NumMenus,ItemOn,KeybdOn;
+
+void HandleOpenMenu(void (*UserRoutine)(void),int which);
+void HandleCloseMenu(void (*UserRoutine)(void));
+void HandleHighlight(void (*UserRoutine)(void));
+int  DetectMenu(int x,int y);
+void ChangeItem(int newitem);
+void ClearScreen(void);
+void RedrawDesktop(void);
+char *PassScancode(int sc);
+
+/////////////////////////////////////////////////////////////////
+//
+// Desktop Event Loop
+//
+/////////////////////////////////////////////////////////////////
+void DeskEventLoop(void (*UserRoutine)(void),void (*ConstantRoutine)(void))
+{
+ int buttonstatus=0,oldmenu,olditem;
+ enum clicks {upup,updown,downup,downdown};
+
+ if (KeybdOn)
+   {
+    HandleOpenMenu(UserRoutine,2);
+    ChangeItem(1);
+   }
+
+ MouseShow();
+ while(1)
+   {
+    int temp=MouseButton()&1,temp1=(MouseButton()>>1)&1;
+
+    sx=0;
+    sy=3;
+
+    if (!OpenMenu)
+      ConstantRoutine();
+    switch(buttonstatus=((buttonstatus<<1)|temp|temp1)&3)
+      {
+       case upup: break;
+       case updown: HandleOpenMenu(UserRoutine,0);
+                   break;
+       case downdown: HandleHighlight(UserRoutine);
+                     break;
+       case downup: HandleCloseMenu(UserRoutine);
+                   if (ItemOn && ItemRoutine)
+                     ItemRoutine();
+                   ItemOn=0;
+                   break;
+      }
+
+    if (bioskey(1))
+      {
+       char key=bioskey(1)>>8;
+       int nitems;
+
+       if (OpenMenu)
+        {
+         bioskey(0);
+
+         nitems=(MBarPtr+OpenMenu-1)->num_items;
+
+         switch(key)
+           {
+            case 0x48: if (OpenMenu)
+                         if (ItemOn)
+                           if (ItemOn==1)
+                             ChangeItem(nitems);
+                           else
+                             ChangeItem(ItemOn-1);
+                       break;
+            case 0x50: if (OpenMenu)
+                         if (ItemOn)
+                           if (ItemOn==nitems)
+                             ChangeItem(1);
+                           else
+                             ChangeItem(ItemOn+1);
+                       break;
+            case 0x1c: oldmenu=OpenMenu;
+                       olditem=ItemOn;
+                       HandleCloseMenu(UserRoutine);
+                       if (ItemOn)
+                         ItemRoutine();
+
+                       break;
+            case 0x4b: if (OpenMenu)
+                         {
+                          int newmenu;
+
+                          ItemOn=0;
+                          if (OpenMenu==1)
+                            newmenu=NumMenus;
+                          else
+                            newmenu=OpenMenu-1;
+
+                          HandleCloseMenu(UserRoutine);
+                          HandleOpenMenu(UserRoutine,newmenu);
+
+                          ChangeItem(1);
+                         }
+                       break;
+            case 0x4d: if (OpenMenu)
+                         {
+                          int newmenu;
+
+                          ItemOn=0;
+                          if (OpenMenu==NumMenus)
+                            newmenu=1;
+                          else
+                            newmenu=OpenMenu+1;
+
+                          HandleCloseMenu(UserRoutine);
+                          HandleOpenMenu(UserRoutine,newmenu);
+
+                          ChangeItem(1);
+                         }
+                       break;
+            case 0x01: if (!OpenMenu)
+                         {
+                          HandleOpenMenu(UserRoutine,oldmenu);
+                          ChangeItem(olditem);
+                         }
+                       break;
+           }
+        }
+       else
+        {
+         int i,j,numitems,run=0;
+         MenuDef *items;
+
+         for (i=0;i<NumMenus;i++)
+           {
+            numitems=(MBarPtr+i)->num_items;
+            items=(MBarPtr+i)->menu_def;
+
+            for (j=0;j<numitems;j++)
+              if ((items+j)->hotkey==key && (items+j)->hotkey)
+                {
+                 if (((items+j)->shiftflag) &&
+                     (!keydown[(items+j)->shiftflag]))
+                   continue;
+
+                 ItemRoutine=(items+j)->routine;
+                 ItemRoutine();
+                 run=1;
+                 break;
+                }
+            if (run)
+              {
+               if (bioskey(1))
+                 bioskey(0);
+               break;
+              }
+           }
+         if (!run)
+           UserRoutine();
+        }
+      }
+   }
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// See if a menu was opened
+//
+/////////////////////////////////////////////////////////////////
+void HandleOpenMenu(void (*UserRoutine)(void),int which)
+{
+ int x,y,loop,flag,tempx,tempw,maxw,loopsize;
+ MenuDef *items;
+
+ if (!which)
+   {
+    MouseCoords(&x,&y);
+    if (y>8 && !OpenMenu)
+      {
+       UserRoutine();
+       return;
+      }
+
+    flag=DetectMenu(x,y);
+    if (!flag) return;
+   }
+ else
+   flag=which;
+
+
+ tempx=MenuInfo[flag-1].menux;
+ tempw=MenuInfo[flag-1].menuwidth;
+ items=(MBarPtr+flag-1)->menu_def;
+
+ sx=tempx+1;
+ sy=0;
+ maxw=0;
+
+ MouseHide();
+
+
+ //
+ // BUILD MENU STRINGS
+ //
+ loopsize=(MBarPtr+flag-1)->num_items;
+
+ for (loop=0;loop<loopsize;loop++)
+   {
+    int len;
+
+    memset(MenuStr[loop],0,80);
+
+    MenuStr[loop][0]=4;        // leftedge
+    strcat(MenuStr[loop],(items+loop)->item_name);
+
+    len=strlen(MenuStr[loop]);
+    memset(&MenuStr[loop][len],' ',tempw-len+1);
+
+    switch((items+loop)->shiftflag)
+      {
+       case ALT: strcat(MenuStr[loop]," ALT-"); break;
+       case CTRL:strcat(MenuStr[loop],"CTRL-");
+      }
+
+    strcat(MenuStr[loop],PassScancode((items+loop)->hotkey));
+
+    len=strlen(MenuStr[loop]);
+    if (len>maxw)
+      maxw=len;
+   }
+
+ if (tempx+maxw>ScreenWidth)
+   tempx=ScreenWidth-1-maxw;
+ SaveBackground(tempx*8,0,(maxw+1)*8,(MBarPtr+flag-1)->num_items*8+16);
+
+ //
+ // PRINT MENU STRINGS
+ //
+ xormask=0xffff;
+ print((MBarPtr+flag-1)->menu_name);
+ xormask=0;
+
+ for (loop=0;loop<loopsize;loop++)
+   {
+    int len;
+
+    len=strlen(MenuStr[loop]);
+    if (len<maxw)
+      memset(&MenuStr[loop][len],' ',maxw-len);
+    strcat(MenuStr[loop],"\x5");
+
+    sx=tempx;
+    sy=loop+1;
+    print(MenuStr[loop]);
+   }
+
+  sx=tempx;
+  sy=loopsize+1;
+  print("\x6");
+  bar(sx,sy,sx+maxw-2,sy,7);
+  sx=tempx+maxw;
+  print("\x8");
+
+ MouseShow();
+ OpenMenu=flag;
+ ItemOn=0;
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Detect whether a menu is clicked on or not
+//
+/////////////////////////////////////////////////////////////////
+int DetectMenu(int x,int y)
+{
+ int flag,loop;
+
+ if (y>10)
+   return 0;
+
+ flag=0;
+ for (loop=0;loop<NumMenus;loop++)
+   if (x/8>=MenuInfo[loop].menux && x/8<MenuInfo[loop].menux+MenuInfo[loop].menunamelen)
+     {
+      flag=loop+1;
+      break;
+     }
+ return flag;
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Highlight & De-highlight items
+//
+/////////////////////////////////////////////////////////////////
+void HandleHighlight(void (*UserRoutine)(void))
+{
+ int x,y,nitems,tempx,tempw,tempy,opmen;
+
+ if (!OpenMenu)
+   {
+    UserRoutine();
+    return;
+   }
+
+ MouseCoords(&x,&y);
+ nitems=(MBarPtr+OpenMenu-1)->num_items;
+ tempx=MenuInfo[OpenMenu-1].menux;
+ tempw=strlen(MenuStr[0])-5;
+ if (tempx+tempw+5>ScreenWidth)
+   tempx=ScreenWidth-tempw-5;
+
+ opmen=DetectMenu(x,y);
+ if (opmen && opmen!=OpenMenu)
+   {
+    OpenMenu=0;
+    RestoreBackground();
+    HandleOpenMenu(UserRoutine,0);
+    return;
+   }
+
+ //
+ // IS USER IN A MENU?
+ //
+
+ if (x/8>tempx && x/8<tempx+tempw+4 && y>8 && y<(nitems+1)*8)
+   {
+    if (y/8==ItemOn)
+      return;  // EXIT IF ON SAME ITEM
+
+    //
+    // IF AN ITEM IS CURRENTLY SELECTED, DEHIGHLIGHT IT
+    // AND HIGHLIGHT A NEW ITEM
+    //
+
+    ChangeItem(y/8);
+   }
+ else
+   //
+   // USER MOVED POINTER OUTSIDE OF MENU; DEHIGHLIGHT ITEM
+   //
+
+   if (ItemOn)
+     {
+      MouseHide();
+
+      sx=tempx;
+      sy=ItemOn;
+      print(MenuStr[ItemOn-1]);
+
+      ItemOn=0;
+      MouseShow();
+     }
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Set new item highlighted
+//
+/////////////////////////////////////////////////////////////////
+void ChangeItem(int newitem)
+{
+ int tempx,tempw;
+ MenuDef *items;
+ char tempstr[80]="";
+
+ tempx=MenuInfo[OpenMenu-1].menux;
+ if (tempx+strlen(MenuStr[0])>ScreenWidth)
+   tempx=ScreenWidth-strlen(MenuStr[0]);
+
+ MouseHide();
+ if (ItemOn)
+   {
+    sx=tempx;
+    sy=ItemOn;
+    print(MenuStr[ItemOn-1]);
+   }
+
+ xormask=0xffff;
+ ItemOn=newitem;
+ strncpy(tempstr,&MenuStr[ItemOn-1][1],strlen(MenuStr[ItemOn-1])-2);
+ sx=tempx+1;
+ sy=ItemOn;
+ print(tempstr);
+ xormask=0;
+
+ MouseShow();
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// See if a menu was closed
+//
+/////////////////////////////////////////////////////////////////
+void HandleCloseMenu(void (*UserRoutine)(void))
+{
+ MenuDef *items;
+ int loop,tempx;
+ char tempstr[80]="";
+
+ if (!OpenMenu)
+   {
+    UserRoutine();
+    return;
+   }
+
+ if (ItemOn)
+   {
+    items=(MBarPtr+OpenMenu-1)->menu_def;
+    tempx=MenuInfo[OpenMenu-1].menux;
+    if (tempx+strlen(MenuStr[0])>ScreenWidth)
+      tempx=ScreenWidth-strlen(MenuStr[0]);
+
+    for (loop=0;loop<NUMFLASHES;loop++)
+      {
+       xormask^=0xffff;
+       MouseHide();
+
+       strncpy(tempstr,&MenuStr[ItemOn-1][1],strlen(MenuStr[ItemOn-1])-2);
+       sx=tempx+1;
+       sy=ItemOn;
+       print(tempstr);
+
+       MouseShow();
+       WaitVBL(3);
+      }
+    xormask=0;
+    ItemRoutine=(items+ItemOn-1)->routine;
+   }
+
+ OpenMenu=0;
+ RestoreBackground();
+}
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Save the background
+//
+/////////////////////////////////////////////////////////////////
+void SaveBackground(int x,int y,int w,int h)
+{
+ long size;
+ unsigned loc,loop,loop1,seg,planelen;
+
+ Back[WhichBack].savex=x;
+ Back[WhichBack].savey=y;
+ Back[WhichBack].savew=w;
+ Back[WhichBack].saveh=h;
+
+ MouseHide();
+ switch (videomode)
+   {
+    case CGA:
+      MMAllocate(&Background[WhichBack],(w/4)*h);
+
+      for(loop=y;loop<y+h;loop++)
+       {
+        loc=(loop/2)*80+0x2000*(loop&1)+x/4;
+        movedata(0xb800,loc,(unsigned)Background[WhichBack],(loop-y)*(w/4),w/4);
+       }
+      break;
+
+    case EGA2:
+    case EGA1:
+      {
+       unsigned tempw=w/8,tempx=x/8,psize;
+
+       planelen=tempw*h;
+       MMAllocate(&Background[WhichBack],5L*planelen);
+       outport(GCindex,GCmode);
+       for (loop=0;loop<4;loop++)
+        {
+         psize=loop*planelen;
+
+         outport(GCindex,GCreadmap | loop*256);
+         for (loop1=y;loop1<y+h;loop1++)
+           movedata(0xa000,((unsigned)loop1*ScreenWidth)+tempx,
+             ((unsigned)Background[WhichBack])+(psize/16),
+             (psize&15)+((loop1-y)*tempw),tempw);
+        }
+      }
+      break;
+
+    case VGA:
+      MMAllocate(&Background[WhichBack],(long)w*h);
+      for(loop=y;loop<y+h;loop++)
+       movedata(0xa000,loop*320+x,(unsigned)Background[WhichBack],(loop-y)*w,w);
+   }
+ MouseShow();
+ if (WhichBack<10)
+   WhichBack++;
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Restore the background
+//
+/////////////////////////////////////////////////////////////////
+void setfarmem(char huge *mem,unsigned char val,unsigned len)
+{
+ int i;
+ for (i=0;i<len;i++)
+   *(mem+i)=val;
+}
+
+void RestoreBackground(void)
+{
+ long size;
+ unsigned loc,loop1,x,y,w,h,loop,planelen;
+
+ if (!Back[WhichBack-1].savex &&
+     !Back[WhichBack-1].savey &&
+     !Back[WhichBack-1].savew &&
+     !Back[WhichBack-1].saveh)
+   Quit("Can't RestoreBackground with no information!");
+
+ x=Back[WhichBack-1].savex;
+ y=Back[WhichBack-1].savey;
+ w=Back[WhichBack-1].savew;
+ h=Back[WhichBack-1].saveh;
+
+ MouseHide();
+ switch (videomode)
+   {
+    case CGA:
+      for(loop=y;loop<y+h;loop++)
+       {
+        loc=(loop/2)*80+0x2000*(loop&1)+x/4;
+        movedata((unsigned)Background[WhichBack-1],(loop-y)*(w/4),0xb800,loc,w/4);
+       }
+      break;
+
+    case EGA2:
+    case EGA1:
+      planelen=(w/8)*h;
+      outport(GCindex,GCmode);
+      for (loop=0;loop<4;loop++)
+       {
+        outport(SCindex,SCmapmask | (1<<loop)*256);
+        for (loop1=y;loop1<y+h;loop1++)
+          movedata(((unsigned)Background[WhichBack-1])+((loop*planelen)/16),
+            ((loop*planelen)&15)+(loop1-y)*(w/8),
+            0xa000,loop1*ScreenWidth+x/8,w/8);
+       }
+      break;
+
+    case VGA:
+      for(loop=y;loop<y+h;loop++)
+       movedata((unsigned)Background[WhichBack-1],(loop-y)*w,0xa000,loop*320+x,w);
+   }
+
+ MMFreePtr(&Background[WhichBack-1]);
+
+ MouseShow();
+
+ WhichBack--;
+ Back[WhichBack].savex=0;
+ Back[WhichBack].savey=0;
+ Back[WhichBack].savew=0;
+ Back[WhichBack].saveh=0;
+}
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Draw the Desktop
+//
+/////////////////////////////////////////////////////////////////
+void RedrawDesktop(void)
+{
+ int flag,count,i;
+
+ ClearScreen();
+
+ sx=sy=0;
+ bar(0,0,ScreenWidth-1,0,' ');
+
+ flag=0;
+ count=0;
+ NumMenus=0;
+ while((MBarPtr+count)->num_items && !flag)
+   {
+    int len,max_width,loop;
+    MenuDef *the_item;
+    char string[80];
+
+    //
+    // First, determine xcoord & namewidth & print
+    //
+
+    strcpy(string,(MBarPtr+count)->menu_name);
+    len=strlen(string);
+    MenuInfo[NumMenus].menux=sx;
+    MenuInfo[NumMenus].menunamelen=len+2;
+    if (len+sx>ScreenWidth-1)
+      {
+       string[ScreenWidth-1-sx]=0;
+       MenuInfo[NumMenus].menunamelen=ScreenWidth-1-sx;
+       MenuInfo[NumMenus].menux=ScreenWidth-MenuInfo[NumMenus].menunamelen;
+       flag++;
+      }
+
+    drawchar(sx++,sy,' ');
+    print(string);
+    drawchar(sx++,sy,' ');
+
+    //
+    // Now, figure out length of widest item
+    //
+
+    max_width=0;
+    the_item=(MBarPtr+count)->menu_def;
+
+    for (loop=0;loop<(MBarPtr+count)->num_items;loop++)
+      {
+       int len;
+
+       len=strlen((the_item+loop)->item_name);
+       if (len>max_width)
+        max_width=len;
+      }
+
+    MenuInfo[NumMenus].menuwidth=max_width+1;
+
+    count++;
+    NumMenus++;
+   }
+
+ //
+ // clear bottom line of menubar
+ //
+ switch(videomode)
+ {
+  case CGA:
+    {
+     unsigned huge *CGAmem=MK_FP(0xb800,240+0x2000);
+     for(i=0;i<40;i++)
+       *(CGAmem+i)=0;
+    }
+    break;
+  case EGA1:
+  case EGA2:
+    {
+    char huge *EGAmem=MK_FP(0xa000,0);
+    outport(GCindex,GCmode);
+    outport(SCindex,0x0f00 | SCmapmask);
+    for (i=0;i<ScreenWidth;i++)
+      *(EGAmem+7*ScreenWidth+i)=0;
+    }
+    break;
+  case VGA:
+    {
+    unsigned huge *VGAmem=MK_FP(0xa000,320*7);
+    for (i=0;i<160;i++)
+      *(VGAmem+i)=0;
+    }
+ }
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Init Desktop
+//
+/////////////////////////////////////////////////////////////////
+void InitDesktop(MBarDef *menubar,int initmouse)
+{
+ switch(videomode)
+   {
+    case CGA: ScreenWidth=40; break;
+    case EGA1: ScreenWidth=40; break;
+    case EGA2: ScreenWidth=80; break;
+    case VGA: ScreenWidth=40;
+   }
+
+ MBarPtr=menubar;
+ RedrawDesktop();
+ if (initmouse)
+   MouseInit();
+ OpenMenu=KeybdOn=0;
+ if (!MouseStatus)
+   KeybdOn=1;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Clear the current screen
+//
+////////////////////////////////////////////////////////////////////
+void ClearScreen(void)
+{
+ unsigned size,segment;
+
+ segment=0xa000;
+ switch(videomode)
+   {
+    case CGA: segment=0xb800; size=CGASIZE/2; break;
+    case EGA1: size=EGA1SIZE/2; break;
+    case EGA2: size=EGA2SIZE/2; break;
+    case VGA: size=VGASIZE/2;
+   }
+
+ MouseHide();
+
+ asm   push    di
+ asm   push    es
+ asm   xor     di,di
+ asm   mov     ax,segment
+ asm   mov     es,ax
+ asm   mov     cx,size
+ asm   cld
+ asm   xor     ax,ax
+ asm   rep stosw
+ asm   pop     es
+ asm   pop     di
+
+ MouseShow();
+}
+
+
+
+/////////////////////////////////////////////////////////
+//
+// print a representation of the scan code key
+//
+/////////////////////////////////////////////////////////
+char *PassScancode(int sc)
+{
+ char smallstr[2];
+ char static chartable[128] =
+ {' ',' ','1','2','3','4','5','6','7','8','9','0','-','+','?','?',
+  'Q','W','E','R','T','Y','U','I','O','P','[',']','|','?','A','S',
+  'D','F','G','H','J','K','L',';','"',' ',' ',' ','Z','X','C','V',
+  'B','N','M',',','.','/','?',' ',' ',' ',' ',' ',' ',' ',' ',' ',
+  ' ',' ',' ',' ',' ',' ',' ',' ', 15,' ','-', 14,'5', 31,'+',' ',
+   19,' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
+  ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
+  ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+
+ sc = sc & 0x7f;
+
+ if (sc==1)
+   strcpy(tempstr,"ESC");
+ else if (sc==0x48)
+   strcpy(tempstr,"\xb");
+ else if (sc==0x50)
+   strcpy(tempstr,"\xc");
+ else if (sc==0xe)
+   strcpy(tempstr,"BKSP");
+ else if (sc==0xf)
+   strcpy(tempstr,"TAB");
+ else if (sc==0x1d)
+   strcpy(tempstr,"CTRL");
+ else if (sc==0x2A)
+   strcpy(tempstr,"LSHIFT");
+ else if (sc==0x39)
+   strcpy(tempstr,"SPACE");
+ else if (sc==0x3A)
+   strcpy(tempstr,"CAPSLK");
+ else if (sc>=0x3b && sc<=0x44)
+ {
+   char str[3];
+   strcpy(tempstr,"F");
+   itoa (sc-0x3a,str,10);
+   strcat(tempstr,str);
+ }
+ else if (sc==0x57)
+   strcpy(tempstr,"F11");
+ else if (sc==0x59)
+   strcpy(tempstr,"F12");
+ else if (sc==0x46)
+   strcpy(tempstr,"SCRLLK");
+ else if (sc==0x1c)
+   strcpy(tempstr,"ENTER");
+ else if (sc==0x36)
+   strcpy(tempstr,"RSHIFT");
+ else if (sc==0x37)
+   strcpy(tempstr,"PRTSC");
+ else if (sc==0x38)
+   strcpy(tempstr,"ALT");
+ else if (sc==0x47)
+   strcpy(tempstr,"HOME");
+ else if (sc==0x49)
+   strcpy(tempstr,"PGUP");
+ else if (sc==0x4f)
+   strcpy(tempstr,"END");
+ else if (sc==0x51)
+   strcpy(tempstr,"PGDN");
+ else if (sc==0x52)
+   strcpy(tempstr,"INS");
+ else if (sc==0x53)
+   strcpy(tempstr,"DEL");
+ else if (sc==0x45)
+   strcpy(tempstr,"NUMLK");
+ else
+   {
+    smallstr[0]=chartable[sc];
+    smallstr[1]=0;
+    strcpy(tempstr,smallstr);
+   }
+
+ return tempstr;
+}
+
+/////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////
+//
+//
+// DIALOG MANAGER CODE
+//
+//
+/////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////
+//
+// Dialog Boxes!
+//
+/////////////////////////////////////////////////////////
+int DoDialog(DialogDef *TheDialog)
+{
+ btype *TheButton;
+ int i,ox,oy,Float=0,Released=0,Clicked=0,xc[30],yc[30],wid[30];
+
+ for (i=0;i<30;i++)
+   xc[i]=yc[i]=wid[i]=0;
+
+ MouseHide();
+ SaveBackground((screencenterx-TheDialog->width/2)*8,
+   (screencentery-TheDialog->height/2)*8,(TheDialog->width+2)*8,
+   (TheDialog->height+2)*8);
+
+ xormask=0;
+ centerwindow(TheDialog->width,TheDialog->height);
+ ox=sx;
+ oy=sy;
+ print(TheDialog->text);
+ for (i=0;i<TheDialog->numbuttons;i++)
+   {
+    int xx,yy,j;
+
+    TheButton=TheDialog->buttons;
+
+    xc[i]=sx=ox+(TheButton+i)->xoff;
+    yc[i]=sy=oy+(TheButton+i)->yoff;
+    xx=sx-1;
+    yy=sy-1;
+    print((TheButton+i)->text);
+    wid[i]=strlen((TheButton+i)->text);
+
+    if ((TheButton+i)->border)
+      DrawBorder(xx,yy,wid[i]+1,2,(TheButton+i)->border);
+   }
+
+ if (TheDialog->hook)
+   {
+    HookRoutine=(void (*)(int x,int y))TheDialog->hook;
+    HookRoutine(ox,oy);
+   }
+ MouseShow();
+
+ clearkeys();
+ do
+ {
+  char temp;
+  int mx,my;
+
+  temp=((temp<<1)|(MouseButton()&1))&3;
+  MouseCoords(&mx,&my);
+  mx/=8;
+  my/=8;
+
+  //
+  // ENTER press
+  //
+  if (keydown[0x1c])
+    for(i=0;i<TheDialog->numbuttons;i++)
+      {
+       TheButton=TheDialog->buttons;
+       if ((TheButton+i)->border==2)
+        {
+         Clicked=i+1;
+         Released=1;
+         temp=Float=0;
+         while(keydown[0x1c]);
+         clearkeys();
+        }
+      }
+
+  //
+  // ESC press
+  //
+  if (keydown[1])
+    {
+     temp=Float=Clicked=0;
+     Released=1;
+     while(keydown[1]);
+    }
+
+  switch(temp)
+  {
+   case 0: // upup (no press)
+     break;
+   case 3: // downdown (held down)
+     if (!Float && Clicked && (mx<xc[Clicked-1] ||
+        mx>xc[Clicked-1]+wid[Clicked-1]-1 || my!=yc[Clicked-1]))
+       {
+       xormask=0;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=1;
+       Float=1;
+       }
+     else
+     if (Float && mx>=xc[Clicked-1] &&
+        mx<xc[Clicked-1]+wid[Clicked-1] && my==yc[Clicked-1])
+       {
+       xormask=1;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=0;
+       Float=0;
+       }
+     break;
+   case 1: // updown (press)
+     for (i=0;i<TheDialog->numbuttons;i++)
+       {
+       if (mx>=xc[i] && mx<xc[i]+wid[i] && my==yc[i])
+         {
+          Clicked=i+1;
+          xormask=1;
+          sx=xc[i];
+          sy=yc[i];
+          MouseHide();
+          print((TheButton+i)->text);
+          MouseShow();
+          xormask=0;
+          break;
+         }
+       }
+     break;
+   case 2: // downup (release)
+     if (Clicked && !Float)
+       Released++;
+  }
+ } while (!Released);
+
+ RestoreBackground();
+ return Clicked;
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Just CHECK a Dialog Box's BUTTONS
+//
+/////////////////////////////////////////////////////////
+int CheckButtons(DialogDef *TheDialog)
+{
+ btype *TheButton;
+ int i,ox,oy,Float=0,Released=0,Clicked=0,xc[30],yc[30],wid[30];
+
+ for (i=0;i<30;i++)
+   xc[i]=yc[i]=wid[i]=0;
+
+ ox=screencenterx-TheDialog->width/2+1;
+ oy=screencentery-TheDialog->height/2+1;
+ for (i=0;i<TheDialog->numbuttons;i++)
+   {
+    int xx,yy,j;
+
+    TheButton=TheDialog->buttons;
+
+    xc[i]=ox+(TheButton+i)->xoff;
+    yc[i]=oy+(TheButton+i)->yoff;
+    wid[i]=strlen((TheButton+i)->text);
+   }
+
+
+ clearkeys();
+ do
+ {
+  char temp;
+  int mx,my;
+
+  temp=((temp<<1)|(MouseButton()&1))&3;
+  MouseCoords(&mx,&my);
+  mx/=8;
+  my/=8;
+
+  //
+  // ENTER press
+  //
+  if (keydown[0x1c])
+    for(i=0;i<TheDialog->numbuttons;i++)
+      {
+       TheButton=TheDialog->buttons;
+       if ((TheButton+i)->border==2)
+        {
+         Clicked=i+1;
+         Released=1;
+         temp=Float=0;
+         while(keydown[0x1c]);
+         clearkeys();
+        }
+      }
+
+  //
+  // ESC press
+  //
+  if (keydown[1])
+    {
+     temp=Float=Clicked=0;
+     Released=1;
+     while(keydown[1]);
+    }
+
+  switch(temp)
+  {
+   case 0: // upup (no press)
+     break;
+   case 3: // downdown (held down)
+     if (!Float && Clicked && (mx<xc[Clicked-1] ||
+        mx>xc[Clicked-1]+wid[Clicked-1]-1 || my!=yc[Clicked-1]))
+       {
+       xormask=0;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=1;
+       Float=1;
+       }
+     else
+     if (Float && mx>=xc[Clicked-1] &&
+        mx<xc[Clicked-1]+wid[Clicked-1] && my==yc[Clicked-1])
+       {
+       xormask=1;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=0;
+       Float=0;
+       }
+     break;
+   case 1: // updown (press)
+     for (i=0;i<TheDialog->numbuttons;i++)
+       {
+       if (mx>=xc[i] && mx<xc[i]+wid[i] && my==yc[i])
+         {
+          Clicked=i+1;
+          xormask=1;
+          sx=xc[i];
+          sy=yc[i];
+          MouseHide();
+          print((TheButton+i)->text);
+          MouseShow();
+          xormask=0;
+          break;
+         }
+       }
+     break;
+   case 2: // downup (release)
+     if (Clicked && !Float)
+       Released++;
+  }
+ } while (!Released);
+ clearkeys();
+
+ if (Clicked)
+ {
+  sx=xc[Clicked-1];
+  sy=yc[Clicked-1];
+  MouseHide();
+  print((TheButton+Clicked-1)->text);
+  MouseShow();
+ }
+
+ return Clicked;
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Just CHECK a Dialog Box's BUTTONS
+// BUT!...RETURN IF MOUSE BUTTON IS PRESSED OUTSIDE DIALOG BUTTON!
+//
+/////////////////////////////////////////////////////////
+int CheckButtonsRet(DialogDef *TheDialog)
+{
+ btype *TheButton;
+ int i,ox,oy,Float=0,Released=0,Clicked=0,xc[30],yc[30],wid[30];
+
+ for (i=0;i<30;i++)
+   xc[i]=yc[i]=wid[i]=0;
+
+ ox=screencenterx-TheDialog->width/2+1;
+ oy=screencentery-TheDialog->height/2+1;
+ for (i=0;i<TheDialog->numbuttons;i++)
+   {
+    int xx,yy,j;
+
+    TheButton=TheDialog->buttons;
+
+    xc[i]=ox+(TheButton+i)->xoff;
+    yc[i]=oy+(TheButton+i)->yoff;
+    wid[i]=strlen((TheButton+i)->text);
+   }
+
+ do
+ {
+  char temp;
+  int mx,my;
+
+  temp=((temp<<1)|(MouseButton()&1))&3;
+  if (MouseButton()&2)
+    return -1;
+
+  MouseCoords(&mx,&my);
+  mx/=8;
+  my/=8;
+
+  //
+  // ENTER press
+  //
+  if (keydown[0x1c])
+    for(i=0;i<TheDialog->numbuttons;i++)
+      {
+       TheButton=TheDialog->buttons;
+       if ((TheButton+i)->border==2)
+        {
+         Clicked=i+1;
+         Released=1;
+         temp=Float=0;
+         while(keydown[0x1c]);
+         clearkeys();
+        }
+      }
+
+  //
+  // ESC press
+  //
+  if (keydown[1])
+    {
+     temp=Float=Clicked=0;
+     Released=1;
+     while(keydown[1]);
+    }
+
+  //
+  // arrows or PgUp/PgDn/Home/End
+  //
+  if (keydown[0x48] || keydown[0x50] || keydown[0x4b] || keydown[0x4d] ||
+      keydown[0x49] || keydown[0x51] || keydown[0x47] || keydown[0x4f] ||
+      keydown[0x39] || keydown[0x2e])
+    return -1;
+
+  switch(temp)
+  {
+   case 0: // upup (no press)
+     break;
+   case 3: // downdown (held down)
+     if (!Float && Clicked && (mx<xc[Clicked-1] ||
+        mx>xc[Clicked-1]+wid[Clicked-1]-1 || my!=yc[Clicked-1]))
+       {
+       xormask=0;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=1;
+       Float=1;
+       }
+     else
+     if (Float && mx>=xc[Clicked-1] &&
+        mx<xc[Clicked-1]+wid[Clicked-1] && my==yc[Clicked-1])
+       {
+       xormask=1;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=0;
+       Float=0;
+       }
+     break;
+   case 1: // updown (press)
+     for (i=0;i<TheDialog->numbuttons;i++)
+       {
+       if (mx>=xc[i] && mx<xc[i]+wid[i] && my==yc[i])
+         {
+          Clicked=i+1;
+          xormask=1;
+          sx=xc[i];
+          sy=yc[i];
+          MouseHide();
+          print((TheButton+i)->text);
+          MouseShow();
+          xormask=0;
+          break;
+         }
+       }
+
+     if (!Clicked)     // MOD TO ORIGINAL CHECKBUTTONS
+       return -1;
+
+     break;
+   case 2: // downup (release)
+     if (Clicked && !Float)
+       Released++;
+  }
+ } while (!Released);
+ clearkeys();
+ return Clicked;
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Just DRAW a Dialog Box
+//
+/////////////////////////////////////////////////////////
+void DrawDialog(DialogDef *TheDialog,int saveback)
+{
+ btype *TheButton;
+ int i,ox,oy,xc[30],yc[30],wid[30];
+
+ for (i=0;i<30;i++)
+   xc[i]=yc[i]=wid[i]=0;
+
+ MouseHide();
+ if (saveback)
+   SaveBackground((screencenterx-TheDialog->width/2)*8,
+     (screencentery-TheDialog->height/2)*8,(TheDialog->width+2)*8,
+     (TheDialog->height+2)*8);
+
+ xormask=0;
+ centerwindow(TheDialog->width,TheDialog->height);
+ ox=sx;
+ oy=sy;
+ print(TheDialog->text);
+ for (i=0;i<TheDialog->numbuttons;i++)
+   {
+    int xx,yy,j;
+
+    TheButton=TheDialog->buttons;
+
+    xc[i]=sx=ox+(TheButton+i)->xoff;
+    yc[i]=sy=oy+(TheButton+i)->yoff;
+    xx=sx-1;
+    yy=sy-1;
+    print((TheButton+i)->text);
+    wid[i]=strlen((TheButton+i)->text);
+
+    if ((TheButton+i)->border)
+      DrawBorder(xx,yy,wid[i]+1,2,(TheButton+i)->border);
+   }
+
+ if (TheDialog->hook)
+   {
+    HookRoutine=(void (*)(int x,int y))TheDialog->hook;
+    HookRoutine(ox,oy);
+   }
+
+ MouseShow();
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Error Dialog Box
+//
+/////////////////////////////////////////////////////////
+char errstring[200],bstring[20];
+btype ERROKb={bstring,0,0,2};
+DialogDef ERRR={errstring,0,0,1,&ERROKb,NULL};
+
+void ErrDialog(char *string,char *bstr)
+{
+ int maxw=0,width=0,height=1,i;
+
+ if (strlen(string)>200)
+   Quit("Programmer Error: ErrDialog string is too long!");
+
+ for (i=0;i<strlen(string);i++)
+   {
+    width++;
+    if (width>maxw)
+      maxw=width;
+
+    if (string[i]=='\n')
+      {
+       height++;
+       width=0;
+      }
+   }
+ height+=3;    // add for button!
+
+ if (strlen(bstr)>maxw)
+   Quit("Programmer Error: ErrDialog BUTTONstring is longer than dialog!");
+
+ strcpy(bstring,bstr);
+ strcpy(errstring,string);
+ ERRR.width=maxw;
+ ERRR.height=height;
+ ERRR.numbuttons=1;
+ if (!bstr[0])
+   {
+    ERRR.numbuttons=0;
+    ERRR.height-=3;
+   }
+
+ ERROKb.xoff=(maxw/2)-(strlen(bstr)/2);
+ ERROKb.yoff=height-2;
+
+ if (bstr[0])
+   DoDialog(&ERRR);
+ else
+   DrawDialog(&ERRR,1);
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Draw a border
+//
+/////////////////////////////////////////////////////////
+void DrawBorder(int x,int y,int w,int h,int b)
+{
+ int xx=x,yy=y,j;
+
+ if (b==2)
+   {
+    drawchar(xx,yy,15);
+    drawchar(xx+w,yy,17);
+    drawchar(xx,yy+h,20);
+    drawchar(xx+w,yy+h,22);
+
+    for (j=yy+1;j<yy+h;j++)
+      {
+       drawchar(xx,j,18);
+       drawchar(xx+w,j,19);
+      }
+    for (j=xx+1;j<xx+w;j++)
+      {
+       drawchar(j,yy,16);
+       drawchar(j,yy+h,21);
+      }
+   }
+
+ if (b==1)
+   {
+    drawchar(xx,yy,23);
+    drawchar(xx+w,yy,25);
+    drawchar(xx,yy+h,28);
+    drawchar(xx+w,yy+h,30);
+
+    for (j=yy+1;j<yy+h;j++)
+      {
+       drawchar(xx,j,26);
+       drawchar(xx+w,j,27);
+      }
+    for (j=xx+1;j<xx+w;j++)
+      {
+       drawchar(j,yy,24);
+       drawchar(j,yy+h,29);
+      }
+   }
+
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Get the XY coords of a dialog's button
+//
+/////////////////////////////////////////////////////////
+void GetButtonXY(DialogDef *TheDialog,int button,unsigned *x,unsigned *y)
+{
+ btype *TheButton;
+
+ TheButton=TheDialog->buttons;
+
+ *x=(TheButton+button)->xoff+screencenterx-TheDialog->width/2+1;
+ *y=(TheButton+button)->yoff+screencentery-TheDialog->height/2+1;
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Get the XY coords of a dialog
+//
+/////////////////////////////////////////////////////////
+void GetDialogXY(DialogDef *TheDialog,unsigned *x,unsigned *y)
+{
+ *x=screencenterx-TheDialog->width/2+1;
+ *y=screencentery-TheDialog->height/2+1;
+}
+
+
+////////////////////////////////////////////////////
+//
+// Allow user to select a list item (like the menus)
+//
+////////////////////////////////////////////////////
+int CheckList(int x,int y,int w,int h,void (*oncode)(),void (*offcode)(),int blink)
+{
+ enum {upup,updown,downup,downdown} clicks;
+ static char bpress=0;
+ unsigned mx,my,i;
+ int high=-1;
+
+
+ while(1)
+ {
+  MouseCoords(&(int)mx,&(int)my);
+  mx/=8;
+  my/=8;
+  bpress=((bpress<<1)|(MouseButton()&1))&3;
+  switch(bpress)
+  {
+   case upup:
+     return -1;
+   case updown:
+     if (mx>=x && mx<x+w && my>=y && my<y+h)
+       {
+       high=my-y;
+       MouseHide();
+       oncode(x,my,high);
+       MouseShow();
+       }
+     else
+       return -1;
+
+     break;
+   case downup:
+     if (high!=-1)
+       {
+       if (blink)
+         for(i=0;i<5;i++)
+         {
+          MouseHide();
+          oncode(x,my,high);
+          MouseShow();
+          WaitVBL(3);
+
+          MouseHide();
+          offcode(x,my,high);
+          WaitVBL(3);
+          MouseShow();
+         }
+       }
+     return high;
+
+   case downdown:
+     if (mx>=x && mx<x+w && my>=y && my<y+h)
+       {
+       if (my-y != high && high!=-1)
+         {
+          MouseHide();
+          offcode(x,high+y,high);
+          MouseShow();
+
+         }
+
+       if (my-y != high)
+         {
+          high=my-y;
+          MouseHide();
+          oncode(x,y+high,high);
+          MouseShow();
+         }
+       }
+     else
+       {
+       if (high!=-1)
+         {
+          MouseHide();
+          offcode(x,high+y,high);
+          MouseShow();
+         }
+       high=-1;
+       return -1;
+       }
+  }
+ }
+}
+
+
+/////////////////////////////////////////////////
+//
+// Message dialog
+// Returns: -1=ESC, 0=No, 1=Yes
+//
+/////////////////////////////////////////////////
+char MessStr[200];
+btype MessOKb[]={{" No ",0,0,1},{" Yes ",0,0,2}};
+DialogDef Mess={MessStr,0,0,2,&MessOKb[0],NULL};
+
+int Message(char *string)
+{
+ int maxw=0,width=0,height=1,i;
+
+ if (strlen(string)>200)
+   Quit("Programmer Error: Message string is too long!");
+
+ for (i=0;i<strlen(string);i++)
+   {
+    width++;
+    if (width>maxw)
+      maxw=width;
+
+    if (string[i]=='\n')
+      {
+       height++;
+       width=0;
+      }
+   }
+ height+=3;    // add for buttons!
+
+ strcpy(MessStr,string);
+ Mess.width=maxw;
+ Mess.height=height;
+
+ MessOKb[1].xoff=(maxw/4)-(strlen(MessOKb[0].text)/2);
+ MessOKb[1].yoff=height-2;
+ MessOKb[0].xoff=(maxw/4)*3-(strlen(MessOKb[1].text)/2);
+ MessOKb[0].yoff=height-2;
+
+ return DoDialog(&Mess);
+}
+
+
+/////////////////////////////////////////////////
+//
+// GetPath dialog
+// *path is returned
+// (exit:0 if OK,-1 if Not Successful,-2 if Canceled)
+//
+/////////////////////////////////////////////////
+#define LISTX  1
+#define LISTY  3
+
+char dstr[80];
+btype GPb={"Cancel",15,3,1};
+DialogDef GPd={dstr,22,14,1,&GPb,NULL};
+char NameList[MAXFDNAMES][13];
+int base;
+struct ffblk f;
+
+int GetPath(char *string,char *filter,char *path)
+{
+ char pname[64];
+ unsigned int numnames=0,max,dx,dy,redraw,exit;
+ int select,zset,i;
+
+
+ strcpy(pname,filter);
+ for (zset=0,i=strlen(pname);i>=0;i--)
+   if (pname[i]=='\\')
+     {
+      pname[i+1]=0;
+      zset++;
+      break;
+     }
+ if (!zset)
+   pname[0]=0;
+
+ strcpy(dstr,string);
+ //
+ // FIRST, GET THE NAMES FROM THE DIRECTORY
+ //
+ if (findfirst(filter,&f,FA_ARCH))
+   return -1;
+ strcpy(NameList[numnames++],f.ff_name);
+
+ while(!findnext(&f) && numnames<MAXFDNAMES)
+   strcpy(NameList[numnames++],f.ff_name);
+
+ DrawDialog(&GPd,1);
+ MouseHide();
+ GetDialogXY(&GPd,&dx,&dy);
+ DrawBorder(dx+LISTX-1,dy+LISTY-1,13,11,1);
+ MouseShow();
+
+ base=exit=0;
+
+ //
+ // THIS LOOP DRAWS THE DIALOG
+ //
+ do
+ {
+  redraw=0;
+  MouseHide();
+  max=10;
+  if (numnames<10)
+    max=numnames;
+  for (i=0;i<max;i++)
+    {
+     bar(dx+LISTX,dy+LISTY+i,dx+LISTX+11,dy+LISTY+i,' ');
+     FDoff(dx+LISTX,dy+LISTY+i,i);
+    }
+  MouseShow();
+
+  //
+  // THIS LOOP CHECKS INPUT
+  //
+  do
+  {
+   select=CheckList(dx+LISTX,dy+LISTY,12,max,FDon,FDoff,0);
+   if (select>=0)
+     {
+      redraw=exit=1;
+      continue;
+     }
+
+   GetButtonXY(&GPd,0,&sx,&sy);
+   select=CheckList(sx,sy,strlen(GPb.text),1,CancelOn,CancelOff,0);
+   if (!select || keydown[1])
+     {
+      RestoreBackground();
+      while(keydown[1]);
+      clearkeys();
+      return -2;
+     }
+
+   //
+   // CHECK ARROWS & PGUP/DN
+   //
+   if (keydown[0x48] && base)
+     {
+      base--;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x48]);
+     }
+   else
+   if (keydown[0x50] && base+10<numnames)
+     {
+      base++;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x50]);
+     }
+   else
+   if (keydown[0x49])
+     {
+      base-=10;
+      if (base<0)
+       base=0;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x49]);
+     }
+   else
+   if (keydown[0x51])
+     {
+      base+=10;
+      if (base+10>numnames)
+       base=numnames-10;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x51]);
+     }
+
+  } while(!redraw);
+ } while(!exit);
+
+ //
+ // RETURN PATHNAME
+ //
+ RestoreBackground();
+ strcpy(path,pname);
+ strcat(path,NameList[select+base]);
+ findfirst(path,&f,FA_ARCH);
+ return 0;
+}
+
+
+static void FDon(int x,int y,int w)
+{
+ xormask=1;
+ FDoff(x,y,w);
+ xormask=0;
+}
+
+static void FDoff(int x,int y,int w)
+{
+ MouseHide();
+ sx=x;
+ sy=y;
+ print(NameList[w+base]);
+ MouseShow();
+}
+
+
+static void CancelOn(int x,int y)
+{
+ xormask=1;
+ CancelOff(x,y);
+ xormask=0;
+}
+
+static void CancelOff(int x,int y)
+{
+ MouseHide();
+ sx=x;
+ sy=y;
+ print("Cancel");
+ MouseShow();
+}
+
+
+/////////////////////////////////////////////////
+//
+// GetList dialog
+// Fill "NameList[?][13]" with your strings
+// (exit:>=0 is selection,-1 if Not Successful,-2 if Canceled)
+//
+/////////////////////////////////////////////////
+int GetList(char *string,int numnames)
+{
+ unsigned int max,dx,dy,redraw,exit,i;
+ int select;
+
+
+ strcpy(dstr,string);
+
+ DrawDialog(&GPd,1);
+ MouseHide();
+ GetDialogXY(&GPd,&dx,&dy);
+ DrawBorder(dx+LISTX-1,dy+LISTY-1,13,11,1);
+ MouseShow();
+
+ base=exit=0;
+
+ //
+ // THIS LOOP DRAWS THE DIALOG
+ //
+ do
+ {
+  redraw=0;
+  MouseHide();
+  max=10;
+  if (numnames<10)
+    max=numnames;
+  for (i=0;i<max;i++)
+    {
+     bar(dx+LISTX,dy+LISTY+i,dx+LISTX+11,dy+LISTY+i,' ');
+     FDoff(dx+LISTX,dy+LISTY+i,i);
+    }
+  MouseShow();
+
+  //
+  // THIS LOOP CHECKS INPUT
+  //
+  do
+  {
+   select=CheckList(dx+LISTX,dy+LISTY,12,max,FDon,FDoff,0);
+   if (select>=0)
+     {
+      redraw=exit=1;
+      continue;
+     }
+
+   GetButtonXY(&GPd,0,&sx,&sy);
+   select=CheckList(sx,sy,strlen(GPb.text),1,CancelOn,CancelOff,0);
+   if (!select || keydown[1])
+     {
+      RestoreBackground();
+      while(keydown[1]);
+      clearkeys();
+      return -2;
+     }
+
+   //
+   // CHECK ARROWS & PGUP/DN
+   //
+   if (keydown[0x48] && base)
+     {
+      base--;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x48]);
+     }
+   else
+   if (keydown[0x50] && base+10<numnames)
+     {
+      base++;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x50]);
+     }
+   else
+   if (keydown[0x49])
+     {
+      base-=10;
+      if (base<0)
+       base=0;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x49]);
+     }
+   else
+   if (keydown[0x51])
+     {
+      base+=10;
+      if (base+10>numnames)
+       base=numnames-10;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x51]);
+     }
+
+  } while(!redraw);
+ } while(!exit);
+
+ //
+ // RETURN SELECTION
+ //
+ RestoreBackground();
+ return select+base;
+}
diff --git a/16/ted5/MENU.H b/16/ted5/MENU.H
new file mode 100755 (executable)
index 0000000..4b624de
--- /dev/null
@@ -0,0 +1,78 @@
+/////////////////////////////////////////////////////////////////
+//
+// Pull-Down menu interface .H file
+//
+/////////////////////////////////////////////////////////////////
+typedef struct { char *item_name;
+                void (*routine)(void);
+                char shiftflag;
+                char hotkey;
+              } MenuDef;
+
+typedef struct { int num_items;
+                MenuDef *menu_def;
+                char *menu_name;
+              } MBarDef;
+
+typedef struct { int menux;
+                int menunamelen;
+                int menuwidth;
+              } MInfoType;
+
+typedef struct { char *text;
+                int xoff,yoff,border;
+              } btype;
+
+typedef struct { char *text;
+                int width,height,numbuttons;
+                btype *buttons;
+                void (*hook)(int x,int y);
+              } DialogDef;
+
+typedef struct { int x,y,w,h;
+                void _seg *buffer;
+              } BackSaveStr;
+
+#define SCindex 0x3C4
+#define SCmapmask 2
+#define GCindex 0x3CE
+#define GCreadmap 4
+#define GCmode 5
+#define crtcaddr 0x3d4
+
+#define NUMFLASHES     10
+#define ALT            0x38
+#define CTRL           0x1d
+
+#define MAXFDNAMES     40
+extern struct ffblk f;         // more info from GetPath
+
+
+void extern InitDesktop(MBarDef *menubar,int initmouse);
+void extern DeskEventLoop(void (*UserRoutine)(void),void (*ConstantRoutine)(void));
+void extern ClearScreen(void);
+void extern RedrawDesktop(void);
+void extern SaveBackground(int x,int y,int w,int h);
+void extern RestoreBackground(void);
+int extern DoDialog(DialogDef *TheDialog);
+void extern ErrDialog(char *string,char *bstring);
+void extern DrawBorder(int x,int y,int w,int h,int b);
+int extern CheckButtons(DialogDef *TheDialog);
+int extern CheckButtonsRet(DialogDef *TheDialog);
+void extern DrawDialog(DialogDef *TheDialog,int saveback);
+void extern GetButtonXY(DialogDef *TheDialog,int button,unsigned *x,unsigned *y);
+void extern GetDialogXY(DialogDef *TheDialog,unsigned *x,unsigned *y);
+int extern CheckList(int x,int y,int w,int h,void (*oncode)(),void (*offcode)(),int blink);
+int extern Message(char *mstring);
+
+//
+// RETURNS 0=OK,-1=NO FILES MATCH FILTER,-2=CANCELED
+//
+extern char NameList[MAXFDNAMES][13];
+int GetPath(char *string,char *filter,char *path);
+int GetList(char *string,int numnames);
+
+static void FDon(int x,int y,int w);
+static void FDoff(int x,int y,int w);
+static void CancelOn(int x,int y);
+static void CancelOff(int x,int y);
diff --git a/16/ted5/README.TXT b/16/ted5/README.TXT
new file mode 100755 (executable)
index 0000000..72a7103
--- /dev/null
@@ -0,0 +1,13 @@
+Ted 5.0
+=======
+
+The Ted source code needs to be compiled with Borland C/C++ 3.1.  It will
+probably compile with 4.0 but there are a few OBJ's that are linked in and
+not built (the vgapalette, the tedfont etc.).
+
+This code was written by John Romero of Id Software Inc.  A screen blanker
+was added and a scrolling bug was fixed by Mark Dochtermann of Apogee
+Software Ltd.
+
+Do not contact Apogee or id regarding any questions on this software.  It
+is provided "AS IS" with no warranty.
diff --git a/16/ted5/README.md b/16/ted5/README.md
new file mode 100755 (executable)
index 0000000..1973000
--- /dev/null
@@ -0,0 +1,2 @@
+TED5
+====
diff --git a/16/ted5/T.BAT b/16/ted5/T.BAT
new file mode 100755 (executable)
index 0000000..dfa9dc8
--- /dev/null
@@ -0,0 +1,4 @@
+cd test
+td386 ..\ted5
+cd ..
+bcx
diff --git a/16/ted5/TDCONFIG.TD b/16/ted5/TDCONFIG.TD
new file mode 100755 (executable)
index 0000000..c2d4161
Binary files /dev/null and b/16/ted5/TDCONFIG.TD differ
diff --git a/16/ted5/TED.NSC b/16/ted5/TED.NSC
new file mode 100755 (executable)
index 0000000..117c3c2
--- /dev/null
@@ -0,0 +1,7 @@
+start chars
+
+load chars
+grab 128
+
+save ted
+.\1a
\ No newline at end of file
diff --git a/16/ted5/TED5-1.C b/16/ted5/TED5-1.C
new file mode 100755 (executable)
index 0000000..2eb3171
--- /dev/null
@@ -0,0 +1,2089 @@
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// TED5-1
+//
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+#include "ted5.h"
+#pragma hdrstop
+
+void InputMap(char *lvlname,unsigned *levelw,unsigned *levelh,int exitok);
+void MNameOn(int x,int y,int i);
+void MNameOff(int x,int y,int i);
+void DnarOn(int x,int y);
+void DnarOff(int x,int y);
+void UparOn(int x,int y);
+void UparOff(int x,int y);
+void ExitOn(int x,int y);
+void ExitOff(int x,int y);
+void TInfoNon(int x,int y,int b);
+void TInfoNoff(int x,int y,int b);
+void TInfoMNon(int x,int y,int b);
+void TInfoMNoff(int x,int y,int b);
+void TIDoneOn(int x,int y);
+void TIDoneOff(int x,int y);
+
+
+////////////////////////////////////////////////////
+//
+// SAVE the current map
+//
+////////////////////////////////////////////////////
+void SaveMap(int delmap)
+{
+ memptr block;
+ long fsize,size,nsize,change;
+ MapHeaderStr TempHeader;
+ int i,XMStemp;
+ char string[100],TEDid[]=IDSTRING;
+
+
+
+ RemoveUndoBuffers();
+ if (delmap)
+   {
+       LoadFile(mapname,(char huge *)&TempHeader,
+       MapFileHeader->dataoffsets[whichmap],sizeof(MapHeaderStr));
+       strcpy(string,"Deleting Map, '");
+       strcat(string,TempHeader.name);
+   }
+ else
+   {
+       strcpy(string,"Saving Map, '");
+       strcat(string,MapHeader.name);
+   }
+
+ strcat(string,"'.");
+ ErrDialog(string,"");
+
+
+ BackupFile(mapheadname);
+ BackupFile(SM_loadname);
+
+
+ if (delmap || DirtyFlag)
+   {
+       //
+       // SAVE MAP FILE HEADER
+       //
+       if (delmap)
+         MapFileHeader->dataoffsets[whichmap]=-1;
+
+       SaveFile(mapheadname,MK_FP(MapFileHeader,0),0,sizeof(MapFileHeaderStr));
+       fsize=sizeof(MapFileHeaderStr);
+
+       //
+       // COMPRESS & SAVE TILEINFOS
+       //
+       MMAllocate(&block,tilenum);
+       for (i=0;i<numtplanes;i++)
+         {
+          MapFileHeader->tileinfooff[i]=fsize;
+          nsize=RLEBCompress(MK_FP(Tinfo[i],0),tilenum,MK_FP(block,0),MapFileHeader->RLEWtag);
+          MapFileHeader->tileinfolen[i]=nsize;
+          SaveFile(mapheadname,MK_FP(block,0),fsize,nsize);
+          fsize+=nsize;
+         }
+       MMFreePtr(&block);
+
+       MMAllocate(&block,tilemnum);
+       for (i=0;i<numtmplanes;i++)
+         {
+          MapFileHeader->tileinfomoff[i]=fsize;
+          nsize=RLEBCompress(MK_FP(TMinfo[i],0),tilemnum,MK_FP(block,0),MapFileHeader->RLEWtag);
+          MapFileHeader->tileinfomlen[i]=nsize;
+          SaveFile(mapheadname,MK_FP(block,0),fsize,nsize);
+          fsize+=nsize;
+         }
+       MMFreePtr(&block);
+
+       MapFileHeader->oldtilenum=tilenum;
+       MapFileHeader->oldtilemnum=tilemnum;
+
+       SaveFile(mapheadname,MK_FP(MapFileHeader,2),2,sizeof(MapFileHeaderStr)-2);
+       //
+       // SAVE ALREADY COMPRESSED MAPS
+       //
+
+       //
+       // IF MAPS ARE IN XMS ALREADY, ALLOCATE A NEW BUFFER
+       // TO SHUFFLE ALREADY-COMPRESSED MAPS INTO
+       //
+       if (XMSmaps)
+         {
+          int planes;
+          long len=filelen(SM_loadname);
+
+
+          planes=(MapFileHeader->maptype&BPLANE>0)+
+                 (MapFileHeader->maptype&FPLANE>0)+
+                 (MapFileHeader->maptype&IPLANE>0);
+          len+=2L*mapwidth*mapheight*planes;
+
+          if (1024L*XMSTotalFree()<len)
+        {
+         XMSFreeMem(XMSmaps);
+         XMSmaps=0;
+        }
+          else
+        XMStemp=XMSAllocate(len);
+         }
+
+       //
+       // NOTE: I AM STORING "TED5" AT THE START OF THE FILE BECAUSE
+       // SAVING THE FILE AT OFFSET 0 WILL TRASH IT (I HAVE TO RE-SAVE THE HEADER!)
+       //
+       if (XMSmaps)
+         XMSmove(0,(long)&TEDid,XMStemp,0,strlen(TEDid));
+       else
+         SaveFile(SM_name,(char huge *)TEDid,0,strlen(TEDid));
+       fsize=strlen(TEDid);
+
+       for (i=0;i<100;i++)
+    {
+     long oldoff;
+
+     if (MapFileHeader->dataoffsets[i]==-1 || i==whichmap)
+       continue;
+
+     oldoff=MapFileHeader->dataoffsets[i];
+
+     if (XMSmaps)
+          XMSmove(XMSmaps,oldoff,0,(long)&TempHeader,sizeof(MapHeaderStr));
+     else
+       LoadFile(SM_loadname,(char huge *)&TempHeader,oldoff,sizeof(MapHeaderStr));
+
+     strcpy(TempHeader.name,MapNames[i]);
+     MapFileHeader->dataoffsets[i]=fsize;
+     size=TempHeader.mapbkgndlen+TempHeader.mapfrgndlen+TempHeader.mapinfolen;
+     change=TempHeader.mapbkgndpl-fsize-sizeof(MapHeaderStr);
+     TempHeader.mapbkgndpl-=change;
+     TempHeader.mapfrgndpl-=change;
+     TempHeader.mapinfopl-=change;
+
+     if (XMSmaps)
+       XMSmove(0,(long)&TempHeader,XMStemp,fsize,sizeof(MapHeaderStr));
+     else
+       SaveFile(SM_name,(char huge *)&TempHeader,fsize,sizeof(MapHeaderStr));
+     fsize+=sizeof(MapHeaderStr);
+
+     if (XMSmaps)
+       {
+       XMSmove(XMSmaps,oldoff+sizeof(MapHeaderStr),XMStemp,fsize,size);
+       fsize+=size;
+       XMSmove(0,(long)"!ID!",XMStemp,fsize,4);
+       fsize+=4;
+       }
+     else
+       {
+       MMAllocate(&block,size);
+       LoadFile(SM_loadname,MK_FP(block,0),oldoff+sizeof(MapHeaderStr),size);
+       SaveFile(SM_name,MK_FP(block,0),fsize,size);
+       fsize+=size;
+       SaveFile(SM_name,"!ID!",fsize,4);
+       fsize+=4;
+       MMFreePtr(&block);
+       }
+    }
+
+    //
+    // SAVE CURRENT MAP AT END OF FILE
+    //
+    if (!delmap)
+      {
+       MapFileHeader->dataoffsets[whichmap]=fsize;
+       MapFileHeader->datalengths[whichmap]=sizeof(MapHeaderStr);
+       if (XMSmaps)
+        XMSmove(0,(long)&MapHeader,XMStemp,fsize,sizeof(MapHeaderStr));
+       else
+        SaveFile(SM_name,(char huge *)&MapHeader,fsize,sizeof(MapHeaderStr));
+       fsize+=sizeof(MapHeaderStr);
+
+       size=MapHeader.width*MapHeader.height*sizeof(int);
+       MMAllocate(&block,size);
+       if (MapFileHeader->maptype & BPLANE)
+        {
+         MapHeader.mapbkgndpl=fsize;
+         nsize=RLEWCompress(MK_FP(MapBkgnd,0),size,MK_FP(block,0),MapFileHeader->RLEWtag);
+
+         MapHeader.mapbkgndlen=nsize+2;
+
+         if (XMSmaps)
+           XMSmove(0,(long)&size,XMStemp,fsize,2);
+         else
+           SaveFile(SM_name,(char huge *)&size,fsize,2);
+
+         fsize+=2;
+
+         if (XMSmaps)
+           XMSmove(0,(long)MK_FP(block,0),XMStemp,fsize,nsize);
+         else
+           SaveFile(SM_name,MK_FP(block,0),fsize,nsize);
+
+         fsize+=nsize;
+        }
+       else
+        MapHeader.mapbkgndlen=0;
+
+       if (MapFileHeader->maptype & FPLANE)
+        {
+         MapHeader.mapfrgndpl=fsize;
+         nsize=RLEWCompress(MK_FP(MapFrgnd,0),size,MK_FP(block,0),MapFileHeader->RLEWtag);
+
+         MapHeader.mapfrgndlen=nsize+2;
+
+         if (XMSmaps)
+           XMSmove(0,(long)&size,XMStemp,fsize,2);
+         else
+           SaveFile(SM_name,(char huge *)&size,fsize,2);
+
+         fsize+=2;
+
+         if (XMSmaps)
+           XMSmove(0,(long)MK_FP(block,0),XMStemp,fsize,nsize);
+         else
+           SaveFile(SM_name,MK_FP(block,0),fsize,nsize);
+
+         fsize+=nsize;
+        }
+       else
+        MapHeader.mapfrgndlen=0;
+
+       if (MapFileHeader->maptype & IPLANE)
+        {
+         MapHeader.mapinfopl=fsize;
+         nsize=RLEWCompress(MK_FP(MapInfoPl,0),size,MK_FP(block,0),MapFileHeader->RLEWtag);
+
+         MapHeader.mapinfolen=nsize+2;
+
+         if (XMSmaps)
+           XMSmove(0,(long)&size,XMStemp,fsize,2);
+         else
+           SaveFile(SM_name,(char huge *)&size,fsize,2);
+
+         fsize+=2;
+
+         if (XMSmaps)
+           XMSmove(0,(long)MK_FP(block,0),XMStemp,fsize,nsize);
+         else
+           SaveFile(SM_name,MK_FP(block,0),fsize,nsize);
+
+         fsize+=nsize;
+        }
+       else
+        MapHeader.mapinfolen=0;
+
+       if (XMSmaps)
+        XMSmove(0,(long)"!ID!",XMStemp,fsize,4);
+       else
+        SaveFile(SM_name,"!ID!",fsize,4);
+
+       fsize+=4;
+
+       MMFreePtr(&block);
+
+       // RE-SAVE HEADER
+       if (XMSmaps)
+                       XMSmove(0,(long)&MapHeader,XMStemp,
+                               MapFileHeader->dataoffsets[whichmap],sizeof(MapHeaderStr));
+          else
+                       SaveFile(SM_name,(char huge *)&MapHeader,
+                               MapFileHeader->dataoffsets[whichmap],sizeof(MapHeaderStr));
+
+       //
+       // RE-SAVE FILE HEADER
+          // NOTE: The "2" is so SaveFile doesn't truncate the fucking file!
+       //
+       SaveFile(mapheadname,MK_FP(MapFileHeader,2),2,sizeof(MapFileHeaderStr)-2);
+         }
+
+    if (XMSmaps)
+      {
+       #define BCSIZE  0x4000
+       long size=fsize,clen,coff;
+
+       //
+       // SAVE ENTIRE MAPFILE IN XMS TO DISK!
+       //
+       XMSFreeMem(XMSmaps);
+       XMSmaps=XMStemp;
+
+       MMAllocate(&block,BCSIZE);
+       coff=0;
+       do
+       {
+               clen=BCSIZE;
+               if (size<BCSIZE)
+                       clen=size;
+
+               XMSmove(XMSmaps,coff,0,(long)MK_FP(block,0),clen);
+               SaveFile(SM_loadname,MK_FP(block,0),coff,clen);
+               size-=BCSIZE;
+               coff+=clen;
+
+          } while(size>0);
+
+       MMFreePtr(&block);
+      }
+    else
+      {
+       unlink(SM_loadname);
+       rename(SM_name,SM_loadname);
+      }
+   }
+
+ AllocateUndoBuffers();
+ UndoRegion.x=-1;
+ SaveUndo(0,0,mapwidth,mapheight);
+ RestoreBackground();
+}
+
+
+
+
+
+
+////////////////////////////////////////////////////
+//
+// BACKUP FILES!
+//
+////////////////////////////////////////////////////
+void BackupFile(char *filename)
+{
+ #define BUFSIZE       0x8000
+ memptr block;
+ long size,clen,coff;
+ int i;
+ char backupname[14];
+
+
+ size = filelen(filename);
+ if (!size)
+   return;
+
+ strcpy(backupname,filename);
+ for (i=strlen(backupname);i;i--)
+   if (backupname[i] == '.')
+        backupname[i+1] = 0;
+ strcat(backupname,"BAK");
+
+ MMAllocate(&block,BUFSIZE);
+ coff=0;
+ do
+ {
+  clen=BUFSIZE;
+  if (size<BUFSIZE)
+         clen=size;
+
+  LoadFile(filename,(char far *)block,coff,clen);
+  SaveFile(backupname,MK_FP(block,0),coff,clen);
+  size-=BUFSIZE;
+  coff+=clen;
+
+ } while(size>0);
+
+ MMFreePtr(&block);
+}
+
+
+////////////////////////////////////////////////////
+//
+// SAVE OUT TEDINFO FILE
+//
+////////////////////////////////////////////////////
+void SaveTEDInfo(void)
+{
+ BackupFile(infoname);
+
+ TEDInfo->oscrx=xbase;
+ TEDInfo->oscry=ybase;
+ _fstrcpy(TEDInfo->launchname,(char far *)launchname);
+ SaveFile(infoname,MK_FP(TEDInfo,0),0,sizeof(InfoStruct));
+}
+
+
+////////////////////////////////////////////////////
+//
+// WRITE OUT THE OUTPUT HEADER FILE
+//
+////////////////////////////////////////////////////
+char * _nfstrcpy(char *dest,char far *source)
+{
+ int i;
+
+ for (i=0;i<_fstrlen(source);i++)
+   *(dest+i)=*(source+i);
+
+ return dest;
+}
+
+
+void SaveOutputHeader(void)
+{
+ char outhead[14]="MAPHEAD.",dot_h[14]="MAPS",t[15],tm[15],temp[40],temp1[40];
+ FILE *fp;
+ OutputHeadStr OutHead;
+ int i,Thelast;
+ long fsize;
+
+
+ ErrDialog("Saving header...","");
+
+ strcat(outhead,ext);
+
+ BackupFile(outhead);
+
+ memset(&OutHead,0,sizeof(OutputHeadStr));
+
+ OutHead.RLEWtag=MapFileHeader->RLEWtag;
+
+ for (i=0;i<100;i++)
+   OutHead.dataoffsets[i]=MapFileHeader->dataoffsets[i];
+
+ fsize=sizeof(OutputHeadStr);
+ SaveFile(outhead,(char huge *)&OutHead,0,fsize);
+ for (i=0;i<numtplanes;i++)
+   {
+    SaveFile(outhead,MK_FP(Tinfo[i],0),fsize,tilenum);
+    fsize+=tilenum;
+   }
+ for (i=0;i<numtmplanes;i++)
+   {
+    SaveFile(outhead,MK_FP(TMinfo[i],0),fsize,tilemnum);
+    fsize+=tilemnum;
+   }
+
+ RestoreBackground();
+
+ //
+ // DUMP OUT A MAPSext.H HEADER FILE
+ //
+ if (writeH)
+   {
+    ErrDialog("Saving .h file...","");
+
+    strcat(dot_h,ext);
+    strcat(dot_h,".H");
+    unlink(dot_h);
+
+    if ((fp=fopen(dot_h,"wt"))==NULL)
+      return;
+
+    fprintf(fp,"///////////////////////////////////////\n");
+    fprintf(fp,"//\n");
+    fprintf(fp,"// TED5 Map Header for %s\n",ext);
+    fprintf(fp,"//\n");
+    fprintf(fp,"///////////////////////////////////////\n");
+
+    Thelast=99;
+       for (i=99;i>=0;i--)
+      if (MapFileHeader->dataoffsets[i]>=0)
+      {
+       Thelast=i;
+       break;
+      }
+
+
+    fprintf(fp,"\n");
+    fprintf(fp,"//\n");
+    fprintf(fp,"// Map Names\n");
+    fprintf(fp,"//\n");
+
+    fprintf(fp,"typedef enum {\n");
+    for (i=0;i<100;i++)
+      if (MapFileHeader->dataoffsets[i]>=0)
+       {
+        char temp[28];
+        int j;
+
+
+        strcpy(temp,&MapNames[i][0]);
+        strcat(temp,"_MAP");
+
+        for (j=0;j<strlen(temp);j++)
+          if (temp[j]==' ')
+            temp[j]='_';
+
+        strcat(temp,",");
+        while(strlen(temp)<25)
+          strcat(temp," ");
+
+        fprintf(fp,"\t\t%s// %d\n",strupr(temp),i);
+       }
+      else
+       if (i<Thelast)
+         fprintf(fp,"\t\tEMPTYMAP%d,\n",i);
+
+    fprintf(fp,"\t\tLASTMAP\n\t     } mapnames;\n");
+
+    switch(tsize)
+    {
+     case 1:
+       strcpy(t,"NUMTILE8");
+       strcpy(tm,"NUMTILE8M");
+          break;
+     case 2:
+       strcpy(t,"NUMTILE16");
+       strcpy(tm,"NUMTILE16M");
+       break;
+     case 3:
+       strcpy(t,"NUMTILE32");
+       strcpy(tm,"NUMTILE32M");
+    }
+
+
+    if (numtplanes)
+    {
+     fprintf(fp,"\n");
+     fprintf(fp,"//\n");
+     fprintf(fp,"// TILEINFO offsets\n");
+     fprintf(fp,"//\n");
+
+     memset(temp,0,sizeof(temp));
+     memset(temp1,0,sizeof(temp1));
+     fprintf(fp,"#define %s\x9\x9%d\n",
+       strupr(_nfstrcpy(temp,MapFileHeader->tnames[0])),
+       sizeof(OutputHeadStr));
+     for (i=1;i<numtplanes;i++)
+       {
+       memset(temp,0,sizeof(temp));
+       memset(temp1,0,sizeof(temp1));
+
+       fprintf(fp,"#define %s\x9\x9(%s+%s)\n",
+         strupr(_nfstrcpy(temp,MapFileHeader->tnames[i])),
+         strupr(_nfstrcpy(temp1,MapFileHeader->tnames[i-1])),
+         t);
+       }
+    }
+
+    if (numtmplanes)
+    {
+     fprintf(fp,"\n");
+     fprintf(fp,"//\n");
+     fprintf(fp,"// TILEINFOM offsets\n");
+     fprintf(fp,"//\n");
+
+     memset(temp,0,sizeof(temp));
+     memset(temp1,0,sizeof(temp1));
+     fprintf(fp,"#define %s\x9\x9(%s+%s)\n",
+       strupr(_nfstrcpy(temp,MapFileHeader->tmnames[0])),
+       strupr(_nfstrcpy(temp1,MapFileHeader->tnames[numtplanes-1])),
+       t);
+     for (i=1;i<numtmplanes;i++)
+       {
+       memset(temp,0,sizeof(temp));
+       memset(temp1,0,sizeof(temp1));
+
+       fprintf(fp,"#define %s\x9\x9(%s+%s)\n",
+         strupr(_nfstrcpy(temp,MapFileHeader->tmnames[i])),
+         strupr(_nfstrcpy(temp1,MapFileHeader->tmnames[i-1])),
+         tm);
+       }
+    }
+
+    fclose(fp);
+    writeH=0;
+    RestoreBackground();
+   }
+
+}
+
+
+////////////////////////////////////////////////////
+//
+// Initialize the TILEINFO/M arrays
+//
+////////////////////////////////////////////////////
+btype TIb[]={{"                  ",1,2,1},
+            {"                  ",1,6,1},
+            {" Done ",12,9,2}};
+DialogDef TId={" How many TILEINFO planes?\n\n\n\n"
+              " How many TILEINFOM planes?",
+              27,11,3,&TIb[0],NULL};
+
+void InitTileinfo(void)
+{
+ unsigned temp,which,oktoexit=0,ox,oy,i,j;
+ long fsize;
+
+ numtplanes=numtmplanes=0;
+ DrawDialog(&TId,1);
+ GetButtonXY(&TId,0,&sx,&sy);
+ printint(numtplanes);
+ if (MapFileHeader->maptype&FPLANE)
+   {
+    GetButtonXY(&TId,1,&sx,&sy);
+    printint(numtmplanes);
+   }
+ do
+ {
+  which=CheckButtons(&TId);
+  switch(which)
+  {
+   case 1:
+     MouseHide();
+     GetButtonXY(&TId,0,&sx,&sy);
+     ox=sx;
+     oy=sy;
+     print(TIb[0].text);
+     sx=ox;
+     sy=oy;
+     if ((temp=inputint(9))!=ESCOUT && temp<11 && temp)
+       numtplanes=temp;
+     sx=ox;
+     sy=oy;
+     print(TIb[0].text);
+     sx=ox;
+     sy=oy;
+     printint(numtplanes);
+     MouseShow();
+
+   case 2:
+     MouseHide();
+     GetButtonXY(&TId,1,&sx,&sy);
+     ox=sx;
+     oy=sy;
+     print(TIb[1].text);
+     sx=ox;
+     sy=oy;
+     if (MapFileHeader->maptype&FPLANE)
+       {
+       if ((temp=inputint(9))!=ESCOUT && temp<11 && temp)
+         numtmplanes=temp;
+       sx=ox;
+       sy=oy;
+       print(TIb[1].text);
+       sx=ox;
+       sy=oy;
+       printint(numtmplanes);
+       }
+     MouseShow();
+     break;
+
+   case 3:
+     MouseHide();
+     oktoexit=1;
+     GetButtonXY(&TId,2,&sx,&sy);
+     print(TIb[2].text);
+     MouseShow();
+  }
+
+ } while(!oktoexit);
+
+ RestoreBackground();
+
+ //
+ // allocate arrays
+ //
+ fsize=sizeof(MapFileHeaderStr);
+
+ for (i=0;i<numtplanes;i++)
+   {
+    MMAllocate((memptr *)&Tinfo[i],tilenum);
+    MapFileHeader->tileinfooff[i]=fsize;       // THIS DOESN'T REALLY MATTER
+    fsize+=tilenum;                            // ....YET!
+    for(j=0;j<tilenum;j++)
+      *(Tinfo[i]+j)=0;
+   }
+
+ for (i=0;i<numtmplanes;i++)
+   {
+    MMAllocate((memptr *)&TMinfo[i],tilemnum);
+    MapFileHeader->tileinfomoff[i]=fsize;
+    fsize+=tilemnum;
+    for(j=0;j<tilemnum;j++)
+      *(TMinfo[i]+j)=0;
+   }
+
+ MapFileHeader->numtplanes=numtplanes;
+ MapFileHeader->numtmplanes=numtmplanes;
+
+ MapFileHeader->oldtilenum=tilenum;
+ MapFileHeader->oldtilemnum=tilemnum;
+ writeH=1;
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Edit the TILEINFO names
+//
+////////////////////////////////////////////////////
+btype TINb={" Done ",8,15,1};
+DialogDef TINd={"  Enter plane names:\n"
+               " TILEINFO   TILEINFOM",
+               22,17,1,&TINb,NULL};
+
+void Item_EditTinfoNames(void)
+{
+ unsigned ox,oy,i,oktoexit=0;
+ int which;
+
+ MouseHide();
+ DrawDialog(&TINd,1);
+ GetDialogXY(&TINd,&sx,&sy);
+ ox=sx;
+ oy=sy;
+ DrawBorder(sx,sy+2,10,11,1);
+ sx=ox;
+ sy=oy;
+ DrawBorder(sx+11,sy+2,10,11,1);
+
+ for (i=0;i<10;i++)
+ {
+  sx=ox+1;
+  sy=oy+i+3;
+  fprint(MapFileHeader->tnames[i]);
+  sx=ox+12;
+  sy=oy+i+3;
+  fprint(MapFileHeader->tmnames[i]);
+ }
+ MouseShow();
+
+ do
+ {
+  if ((which=CheckList(ox+1,oy+3,8,numtplanes,TInfoNon,TInfoNoff,0))>=0)
+    {
+     char temp[8];
+
+     MouseHide();
+redo:
+     sx=ox+1;
+     sy=oy+which+3;
+     print("         ");
+     sx=ox+1;
+     sy=oy+which+3;
+     if (input(temp,7))
+       {
+       for(i=0;i<8;i++)
+         MapFileHeader->tnames[which][i]=temp[i];
+       which++;
+       writeH=DirtyFlag=1;
+       if (which<numtplanes)
+         goto redo;
+       }
+     else
+       TInfoNoff(ox+1,oy+3+which,which);
+    MouseShow();
+    }
+
+  if ((which=CheckList(ox+12,oy+3,8,numtmplanes,TInfoMNon,TInfoMNoff,0))>=0)
+    {
+     char temp[8];
+
+     MouseHide();
+redo1:
+     sx=ox+12;
+     sy=oy+which+3;
+     print("         ");
+     sx=ox+12;
+     sy=oy+which+3;
+     if (input(temp,7))
+       {
+       for(i=0;i<8;i++)
+         MapFileHeader->tmnames[which][i]=temp[i];
+       which++;
+       writeH=DirtyFlag=1;
+       if (which<numtmplanes)
+         goto redo1;
+       }
+     else
+       TInfoMNoff(ox+12,oy+3+which,which);
+    MouseShow();
+    }
+
+  GetButtonXY(&TINd,0,&sx,&sy);
+  if (!CheckList(sx,sy,6,1,TIDoneOn,TIDoneOff,1))
+    oktoexit++;
+
+  if (keydown[1])
+    {
+     while(keydown[1]);
+     oktoexit++;
+    }
+ }while(!oktoexit);
+
+ RestoreBackground();
+}
+
+void TInfoNon(int x,int y,int b)
+{
+ xormask=1;
+ sx=x;
+ sy=y;
+ if (!MapFileHeader->tnames[b][0])
+   print("         ");
+ else
+   fprint(MapFileHeader->tnames[b]);
+ xormask=0;
+}
+void TInfoNoff(int x,int y,int b)
+{
+ sx=x;
+ sy=y;
+ if (!MapFileHeader->tnames[b][0])
+   print("         ");
+ else
+   fprint(MapFileHeader->tnames[b]);
+}
+void TInfoMNon(int x,int y,int b)
+{
+ xormask=1;
+ sx=x;
+ sy=y;
+ if (!MapFileHeader->tmnames[b][0])
+   print("         ");
+ else
+   fprint(MapFileHeader->tmnames[b]);
+ xormask=0;
+}
+void TInfoMNoff(int x,int y,int b)
+{
+ sx=x;
+ sy=y;
+ if (!MapFileHeader->tmnames[b][0])
+   print("         ");
+ else
+   fprint(MapFileHeader->tmnames[b]);
+}
+void TIDoneOn(int x,int y)
+{
+ xormask=1;
+ sx=x;
+ sy=y;
+ print(" Done ");
+ xormask=0;
+}
+void TIDoneOff(int x,int y)
+{
+ sx=x;
+ sy=y;
+ print(" Done ");
+}
+
+////////////////////////////////////////////////////
+//
+// Create a new map!
+//
+////////////////////////////////////////////////////
+void CreateMap(int exitok)
+{
+ unsigned lwidth,lheight,i;
+ int mapnum;
+ long size;
+ char lname[16];
+
+ if ((mapnum=SelectMap(exitok,NOTCREATED,"TO CREATE"))==-1)
+   return;
+
+ InputMap(lname,&lwidth,&lheight,exitok);
+ if (!lname[0])
+   return;
+
+ RemoveUndoBuffers();
+ SaveCutBuffers();
+
+ if (MapBkgnd)
+   {
+    MMFreePtr((memptr *)&MapBkgnd);
+    MMFreePtr((memptr *)&CutBkgnd);
+   }
+ if (MapFrgnd)
+   {
+    MMFreePtr((memptr *)&MapFrgnd);
+    MMFreePtr((memptr *)&CutFrgnd);
+   }
+ if (MapInfoPl)
+   {
+    MMFreePtr((memptr *)&MapInfoPl);
+    MMFreePtr((memptr *)&CutInfoPl);
+   }
+
+ size=2L*(lwidth*lheight);
+
+ if (MapFileHeader->maptype&BPLANE)
+   {
+    MMAllocate((memptr *)&MapBkgnd,size);
+    MMAllocate((memptr *)&CutBkgnd,size);
+    for(i=0;i<lwidth*lheight;i++)
+      *(MapBkgnd+i)=*(CutBkgnd+i)=0;
+   }
+ if (MapFileHeader->maptype&FPLANE)
+   {
+    MMAllocate((memptr *)&MapFrgnd,size);
+    MMAllocate((memptr *)&CutFrgnd,size);
+    for(i=0;i<lwidth*lheight;i++)
+      *(MapFrgnd+i)=*(CutFrgnd+i)=0;
+   }
+ if (MapFileHeader->maptype&IPLANE)
+   {
+    MMAllocate((memptr *)&MapInfoPl,size);
+    MMAllocate((memptr *)&CutInfoPl,size);
+    for(i=0;i<lwidth*lheight;i++)
+      *(MapInfoPl+i)=*(CutInfoPl+i)=0;
+   }
+
+ whichmap=mapnum;
+ strcpy(MapHeader.name,lname);
+ MapHeader.width=mapwidth=lwidth;
+ MapHeader.height=mapheight=lheight;
+ strcpy(MapNames[mapnum],MapHeader.name);
+ AllocateUndoBuffers();
+ DirtyFlag=1;
+ SaveMap(0);
+ DirtyFlag=0;
+ RestoreCutBuffers();
+ SelectMode=PasteMode=xbase=ybase=0;
+ SelX1=SelX2=SelY1=SelY2=-1;
+ writeH=1;
+}
+
+
+////////////////////////////////////////////////////
+//
+// Load a map
+//
+////////////////////////////////////////////////////
+void LoadMap(int mapnum)
+{
+ unsigned long csize,size=0;
+ memptr block;
+
+ SaveCutBuffers();
+ //
+ // DEALLOCATE ALL CURRENT MAP MEMORY
+ //
+ RemoveUndoBuffers();
+
+ if (MapBkgnd)
+   {
+    MMFreePtr((memptr *)&MapBkgnd);
+    MMFreePtr((memptr *)&CutBkgnd);
+   }
+ if (MapFrgnd)
+   {
+    MMFreePtr((memptr *)&MapFrgnd);
+    MMFreePtr((memptr *)&CutFrgnd);
+   }
+ if (MapInfoPl)
+   {
+    MMFreePtr((memptr *)&MapInfoPl);
+    MMFreePtr((memptr *)&CutInfoPl);
+   }
+
+ //
+ // LOAD MAP HEADER
+ //
+ if (XMSmaps)
+   XMSmove(XMSmaps,MapFileHeader->dataoffsets[mapnum],0,(long)&MapHeader,sizeof(MapHeaderStr));
+ else
+   LoadFile(mapname,(char huge *)&MapHeader,MapFileHeader->dataoffsets[mapnum],sizeof(MapHeaderStr));
+
+ //
+ // LOAD & DECOMPRESS MAP PLANES
+ //
+ if (MapFileHeader->maptype & BPLANE)
+   {
+    if (XMSmaps)
+      XMSmove(XMSmaps,MapHeader.mapbkgndpl,0,(long)&size,2);
+    else
+      LoadFile(mapname,(char huge *)&size,MapHeader.mapbkgndpl,2);
+
+    MMAllocate((memptr *)&MapBkgnd,size);
+    MMAllocate((memptr *)&CutBkgnd,size);
+    csize=MapHeader.mapbkgndlen-2;
+    MMAllocate(&block,csize);
+
+    if (XMSmaps)
+      XMSmove(XMSmaps,MapHeader.mapbkgndpl+2,0,(long)MK_FP(block,0),csize);
+    else
+      LoadFile(mapname,MK_FP(block,0),MapHeader.mapbkgndpl+2,csize);
+
+    RLEWExpand(MK_FP(block,0),MK_FP(MapBkgnd,0),size,MapFileHeader->RLEWtag);
+    MMFreePtr(&block);
+   }
+ if (MapFileHeader->maptype & FPLANE)
+   {
+    if (XMSmaps)
+      XMSmove(XMSmaps,MapHeader.mapfrgndpl,0,(long)&size,2);
+    else
+      LoadFile(mapname,(char huge *)&size,MapHeader.mapfrgndpl,2);
+
+    MMAllocate((memptr *)&MapFrgnd,size);
+    MMAllocate((memptr *)&CutFrgnd,size);
+    csize=MapHeader.mapfrgndlen-2;
+    MMAllocate(&block,csize);
+
+    if (XMSmaps)
+      XMSmove(XMSmaps,MapHeader.mapfrgndpl+2,0,(long)MK_FP(block,0),csize);
+    else
+      LoadFile(mapname,MK_FP(block,0),MapHeader.mapfrgndpl+2,csize);
+
+    RLEWExpand(MK_FP(block,0),MK_FP(MapFrgnd,0),size,MapFileHeader->RLEWtag);
+    MMFreePtr(&block);
+   }
+ if (MapFileHeader->maptype & IPLANE)
+   {
+    if (XMSmaps)
+      XMSmove(XMSmaps,MapHeader.mapinfopl,0,(long)&size,2);
+    else
+      LoadFile(mapname,(char huge *)&size,MapHeader.mapinfopl,2);
+
+    MMAllocate((memptr *)&MapInfoPl,size);
+    MMAllocate((memptr *)&CutInfoPl,size);
+    csize=MapHeader.mapinfolen-2;
+    MMAllocate(&block,csize);
+
+    if (XMSmaps)
+      XMSmove(XMSmaps,MapHeader.mapinfopl+2,0,(long)MK_FP(block,0),csize);
+    else
+      LoadFile(mapname,MK_FP(block,0),MapHeader.mapinfopl+2,csize);
+
+    RLEWExpand(MK_FP(block,0),MK_FP(MapInfoPl,0),size,MapFileHeader->RLEWtag);
+    MMFreePtr(&block);
+   }
+
+ mapwidth=MapHeader.width;
+ mapheight=MapHeader.height;
+ strcpy(MapNames[mapnum],MapHeader.name);
+
+ AllocateUndoBuffers();
+ UndoRegion.x=-1;
+ SaveUndo(0,0,mapwidth,mapheight);
+ RestoreCutBuffers();
+
+ SelectMode=PasteMode=xbase=ybase=0;
+ SelX1=SelX2=SelY1=SelY2=-1;
+}
+
+
+////////////////////////////////////////////////////
+//
+// Select a new map!
+//
+////////////////////////////////////////////////////
+btype ClvlB[]={{"\xb",28,5,1},
+              {"\xc",28,14,1},
+              {" Exit ",12,17,1}};
+DialogDef ClvlD={"          SELECT MAP",
+                30,19,2,&ClvlB[0],NULL};
+int smbase=0;
+
+int SelectMap(int exitok,int createflg,char *title)
+{
+ MapHeaderStr TempMapHeader;
+ unsigned ox,oy,i,dx,dy;
+ int select=-1,redraw;
+
+ if (exitok)
+   {
+    ClvlD.numbuttons=3;
+    ClvlD.height=19;
+   }
+ else
+   {
+    ClvlD.numbuttons=2;
+    ClvlD.height=16;
+   }
+
+ DrawDialog(&ClvlD,1);
+ GetDialogXY(&ClvlD,&dx,&dy);
+ sy=dy+1;
+ sx=screencenterx-strlen(title)/2;
+ print(title);
+
+ dx+=3;
+ dy+=5;
+
+ MouseHide();
+ GetButtonXY(&ClvlD,0,&sx,&sy);
+ sx-=27;
+ sy-=2;
+ print("Map   Name\n");
+ ox=sx+1;
+ oy=sy+1;
+ DrawBorder(sx,sy,26,11,2);
+ MouseShow();
+
+
+ do
+ {
+  int mx,my;
+
+  //
+  // DRAW MAP NAMES
+  //
+  MouseHide();
+  for (i=0;i<10;i++)
+  {
+   sy=oy+i;
+   sx=ox;
+   if (i+smbase==whichmap)
+     print("*");
+   else
+     print(" ");
+
+   printint(i+smbase);
+   print(" ");
+   sx=ox+5;
+   MNameOff(sx,sy,i);
+  }
+  MouseShow();
+  redraw=0;
+
+  do
+  {
+   GetButtonXY(&ClvlD,0,&(unsigned)mx,&(unsigned)my);
+   if (!CheckList(mx,my,1,1,UparOn,UparOff,0) || keydown[0x48])
+     {
+      MouseHide();
+      GetButtonXY(&ClvlD,0,&sx,&sy);
+      print(ClvlB[0].text);
+
+      smbase-=10;
+      if (smbase<0)
+       smbase=0;
+      redraw=1;
+      MouseShow();
+      while(keydown[0x48]);
+      continue;
+     }
+
+   GetButtonXY(&ClvlD,1,&(unsigned)mx,&(unsigned)my);
+   if (!CheckList(mx,my,1,1,DnarOn,DnarOff,0) || keydown[0x50])
+     {
+      MouseHide();
+      GetButtonXY(&ClvlD,1,&sx,&sy);
+      print(ClvlB[1].text);
+
+      smbase+=10;
+      if (smbase>90)
+       smbase=90;
+      redraw=1;
+      MouseShow();
+      while(keydown[0x50]);
+      continue;
+     }
+
+   if (exitok)
+     {
+      GetButtonXY(&ClvlD,2,&(unsigned)mx,&(unsigned)my);
+      if (!CheckList(mx,my,6,1,ExitOn,ExitOff,0))
+       {
+        RestoreBackground();
+        return -1;
+       }
+     }
+
+   if (exitok && keydown[1])
+     {
+      RestoreBackground();
+      return -1;
+     }
+
+   select=CheckList(ox+5,oy,20,10,MNameOn,MNameOff,0);
+   if (select>=0)
+     {
+      MouseHide();
+      sy=select+oy;
+      sx=ox+5;
+      MNameOff(sx,sy,select);
+      MouseShow();
+      if ((MapFileHeader->dataoffsets[select+smbase]!=-1 && createflg==NOTCREATED)||
+         (MapFileHeader->dataoffsets[select+smbase]==-1 && createflg==CREATED))
+       select=-1;
+     }
+
+  } while(!redraw && select<0);
+ } while(select<0);
+
+ RestoreBackground();
+ return select+smbase;
+}
+
+//
+// Print arrows
+//
+void DnarOn(int x,int y)
+{
+ sx=x;
+ sy=y;
+ xormask=1;
+ drawchar(sx,sy,0xc);
+ xormask=0;
+}
+void DnarOff(int x,int y)
+{
+ sx=x;
+ sy=y;
+ drawchar(sx,sy,0xc);
+}
+void UparOn(int x,int y)
+{
+ sx=x;
+ sy=y;
+ xormask=1;
+ drawchar(sx,sy,0xb);
+ xormask=0;
+}
+void UparOff(int x,int y)
+{
+ sx=x;
+ sy=y;
+ drawchar(sx,sy,0xb);
+}
+void ExitOn(int x,int y)
+{
+ sx=x;
+ sy=y;
+ xormask=1;
+ print(" Exit ");
+ xormask=0;
+}
+void ExitOff(int x,int y)
+{
+ sx=x;
+ sy=y;
+ print(" Exit ");
+}
+
+//
+// Highlight Map Name
+//
+void MNameOn(int x,int y,int i)
+{
+ xormask=1;
+ MNameOff(x,y,i);
+ xormask=0;
+}
+
+//
+// De-Highlight Map Name
+//
+void MNameOff(int x,int y,int i)
+{
+ MapHeaderStr TempMapHeader;
+
+ sx=x;
+ sy=y;
+ if (MapFileHeader->dataoffsets[i+smbase]!=-1)
+   {
+    print("                   ");
+    sx=x;
+    print(MapNames[i+smbase]);
+   }
+ else
+   print("--not created yet--");
+}
+
+
+
+////////////////////////////////////////////////////
+//
+// Pick more planes for the map set
+//
+////////////////////////////////////////////////////
+btype PickPlaneb[]={{"X",1,3,1},
+                   {"X",1,6,1},
+                   {" Done ",1,9,2}};
+DialogDef PickPlaneD={"Which other planes\n"
+                    "to enable?\n\n"
+                    "    Foreground\n\n\n"
+                    "    Information"
+                    ,18,11,3,&PickPlaneb[0],NULL};
+
+int PickMorePlanes(void)
+{
+ int which;
+ char planes=7;        // 1=bkgnd/2=frgnd/4=info
+
+ DrawDialog(&PickPlaneD,1);
+ do
+ {
+  which=CheckButtons(&PickPlaneD);
+  switch(which)
+  {
+   case 0:
+     RestoreBackground();
+     return 1;
+   case 1:
+     GetButtonXY(&PickPlaneD,0,&sx,&sy);
+     planes^=2;
+     MouseHide();
+     if (planes&2)
+       print("X");
+     else
+       print(" ");
+     MouseShow();
+     break;
+   case 2:
+     GetButtonXY(&PickPlaneD,1,&sx,&sy);
+     planes^=4;
+     MouseHide();
+     if (planes&4)
+       print("X");
+     else
+       print(" ");
+     MouseShow();
+  }
+ } while(which!=3);
+
+ RestoreBackground();
+ MapFileHeader->maptype=planes;
+ return 0;
+}
+
+////////////////////////////////////////////////////
+//
+// Get map dimensions
+//
+////////////////////////////////////////////////////
+btype LvlSpecb[]={{"                  ",1,3,1},
+                 {"                  ",1,7,1},
+                 {"                  ",1,11,1},
+                 {" Done ",7,14,2}};
+DialogDef LvlSpec={"   MAP DIMENSIONS\n"
+                  " Map Name:\n\n\n\n"
+                  " Map Width:\n\n\n\n"
+                  " Map Height:\n",
+                  20,16,4,&LvlSpecb[0],NULL};
+
+void InputMap(char *lvlname,unsigned *levelw,unsigned *levelh,int exitok)
+{
+ unsigned butn,ok=0,nameok=0,widok=0,heightok=0,
+     ox,oy,width=0,height=0,oldwidth=0,oldheight=0;
+ char oldname[16]="",name[16]="";
+
+ MouseHide();
+ DrawDialog(&LvlSpec,1);
+ GetButtonXY(&LvlSpec,1,&sx,&sy);
+ printint(width);
+ GetButtonXY(&LvlSpec,2,&sx,&sy);
+ printint(height);
+ MouseShow();
+
+ //
+ // START INPUT IMMEDIATELY
+ //
+ butn=1;
+ goto firsttime;
+
+#pragma warn -rch
+ while (!ok)
+#pragma warn +rch
+ {
+  butn=CheckButtons(&LvlSpec);
+  if (!butn)
+     if (exitok)
+      {
+       RestoreBackground();
+       lvlname[0]=0;
+       return;
+      }
+     else
+      continue;
+
+firsttime:
+
+  xormask=0;
+  GetButtonXY(&LvlSpec,butn-1,&sx,&sy);
+  MouseHide();
+  ox=sx;
+  oy=sy;
+  print(LvlSpecb[butn-1].text);
+  sx=ox;
+  sy=oy;
+  switch(butn)
+  {
+   case 1:
+     name[0]=0;
+     if (!input(name,15))
+       {
+       strcpy(name,oldname);
+       sx=ox;
+       sy=oy;
+       print(LvlSpecb[butn-1].text);
+       }
+     strcpy(oldname,name);
+     sx=ox;
+     sy=oy;
+     if (name[0])
+                {
+       print(name);
+       nameok=1;
+       }
+     else
+       nameok=0;
+
+     if (nameok)
+       {
+       butn=2;
+       GetButtonXY(&LvlSpec,butn-1,&sx,&sy);
+       ox=sx;
+       oy=sy;
+       print(LvlSpecb[butn-1].text);
+       sx=ox;
+       sy=oy;
+       }
+     else
+     break;
+
+   case 2:
+     width=0;
+     if ((width=inputint(9))==ESCOUT)
+       {
+       widok=0;
+       width=oldwidth;
+       }
+     if (width)
+       widok=1;
+
+     oldwidth=width;
+     sx=ox;
+     sy=oy;
+     print(LvlSpecb[butn-1].text);
+         sx=ox;
+     sy=oy;
+     printint(width);
+     if (widok)
+       {
+       butn=3;
+       GetButtonXY(&LvlSpec,butn-1,&sx,&sy);
+       ox=sx;
+       oy=sy;
+       print(LvlSpecb[butn-1].text);
+       sx=ox;
+       sy=oy;
+       }
+     else
+     break;
+
+   case 3:
+     height=0;
+     if ((height=inputint(9))==ESCOUT)
+       {
+       heightok=0;
+       height=oldheight;
+       }
+     if (height)
+       heightok=1;
+
+     oldheight=height;
+     sx=ox;
+     sy=oy;
+     print(LvlSpecb[butn-1].text);
+     sx=ox;
+     sy=oy;
+     printint(height);
+     break;
+
+   case 4:
+     if (2L*height*width>0x10000)      // TOO BIG! TRIM IT!
+       {
+       errsound();
+       errsound();
+       widok=heightok=0;
+       break;
+       }
+     if (nameok && widok && heightok)
+       ok=1;
+  }
+
+  MouseShow();
+ }
+
+ RestoreBackground();
+
+ *levelw=width;
+ *levelh=height;
+ strcpy(lvlname,name);
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Input INFOPLANE value
+//
+////////////////////////////////////////////////////
+btype EnterIVb={"          ",1,3,1};
+DialogDef EnterIV={"Enter a value for\nthe INFO plane:\n\n\n",18,5,1,&EnterIVb,NULL};
+
+void Item_InputInfoplane(void)
+{
+ unsigned val;
+
+
+ if (TsearchMode || BfillMode || FillMode || PasteMode || SelectMode)
+   return;
+
+ clearkeys();
+ DrawDialog(&EnterIV,1);
+ MouseHide();
+ GetButtonXY(&EnterIV,0,&sx,&sy);
+ if ((val=inputint(9))!=ESCOUT)
+   whichi=val+tilenum;
+ RestoreBackground();
+ DrawInfoBar();
+ MouseShow();
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Select Tile
+//
+////////////////////////////////////////////////////
+void Item_SelectTile(void)
+{
+ SelectTiles(0);
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Block Fill
+//
+////////////////////////////////////////////////////
+void Item_BlockFill(void)
+{
+ ZeroModes();
+ BfillMode=1;
+ DrawInfoBar();
+}
+
+//
+// DO THE ACTUAL BLOCK FILL
+//
+void DoBlockFill(void)
+{
+ unsigned loc,i,j,ctrl=0,newt,newm,newi,tton,tmon,tion,from;
+
+ if (keydown[0x1d])
+   ctrl++;
+
+ MouseHide();
+
+ CopyUndoRegion();
+ UndoRegion.x=SelX1;
+ UndoRegion.y=SelY1;
+ UndoRegion.w=SelX2-SelX1+1;
+ UndoRegion.h=SelY2-SelY1+1;
+
+ if (ctrl)
+   {
+    for (j=SelY1;j<=SelY2;j++)
+      for (i=SelX1;i<=SelX2;i++)
+       {
+        loc=j*mapwidth+i;
+        from=(TileCopy.y+((j-SelY1)%TileCopy.h))*mapwidth+
+             TileCopy.x+((i-SelX1)%TileCopy.w);
+
+        switch(TileCopy.MapOrTileSelect)
+        {
+         case 0: // COPY BUFFER
+                tton=TileCopy.PlanesCopied&BPLANE;
+           tmon=TileCopy.PlanesCopied&FPLANE;
+           tion=TileCopy.PlanesCopied&IPLANE;
+
+           newt=CutBkgnd[from];
+           newm=CutFrgnd[from];
+           newi=CutInfoPl[from];
+
+           break;
+         case 1: // TILES
+           tton=1;
+           tmon=tion=0;
+
+           newt=((j%TileCopy.h)+TileCopy.y)*selectcols+
+                TileCopy.x+(i%TileCopy.w);
+           if (XMSlookup[newt]<0)
+             tton=0;
+           break;
+         case 2: // MASKED
+           tton=tion=0;
+           tmon=1;
+
+           newm=((j%TileCopy.h)+TileCopy.y)*selectcols+
+                TileCopy.x+(i%TileCopy.w)+tilenum+maxiconrows*selectcols;
+           if (XMSlookup[newm]<0)
+             tmon=0;
+           else
+             newm-=tilenum;
+        }
+
+        if (tton)
+          *(MapBkgnd+loc)=newt;
+        if (tmon)
+          *(MapFrgnd+loc)=newm;
+        if (tion)
+          *(MapInfoPl+loc)=newi;
+
+        if (j>=ybase && j<ybase+screenh &&
+            i>=xbase && i<xbase+screenw)
+          {
+           int tempt,tempm,tempi;
+
+           tempt=*(MapBkgnd+loc);
+           tempm=*(MapFrgnd+loc)+tilenum;
+           tempi=*(MapInfoPl+loc)+tilenum;
+
+           CombineTiles(viewton?tempt:-BkgndColor,viewmon*tempm,viewion*tempi,tsize);
+           if (GridMode)
+             Overlay(tsize);
+           DrawTile((i-xbase)<<(tsize-1),((j-ybase)<<(tsize+2))+8,tsize);
+          }
+       }
+   }
+ else
+   for (j=SelY1;j<=SelY2;j++)
+     for (i=SelX1;i<=SelX2;i++)
+       {
+       loc=j*mapwidth+i;
+
+       if (planeton)
+         *(MapBkgnd+loc)=whicht;
+       if (planemon)
+         *(MapFrgnd+loc)=whichtm-tilenum;
+       if (planeion)
+         *(MapInfoPl+loc)=whichi-tilenum;
+
+       if (j>=ybase && j<ybase+screenh &&
+           i>=xbase && i<xbase+screenw)
+         {
+          int tempt,tempm,tempi;
+
+          tempt=*(MapBkgnd+loc);
+          tempm=*(MapFrgnd+loc)+tilenum;
+          tempi=*(MapInfoPl+loc)+tilenum;
+
+          CombineTiles(viewton?tempt:-BkgndColor,viewmon*tempm,viewion*tempi,tsize);
+          if (GridMode)
+            Overlay(tsize);
+          DrawTile((i-xbase)<<(tsize-1),((j-ybase)<<(tsize+2))+8,tsize);
+         }
+       }
+
+ DirtyFlag=1;
+ MouseShow();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Remove the XMS undo buffers
+//
+////////////////////////////////////////////////////
+void RemoveUndoBuffers(void)
+{
+ if (XMSundoB)
+   XMSFreeMem(XMSundoB);
+ if (XMSundoF)
+   XMSFreeMem(XMSundoF);
+ if (XMSundoI)
+   XMSFreeMem(XMSundoI);
+
+ XMSundoB=XMSundoF=XMSundoI=0;
+}
+
+
+////////////////////////////////////////////////////
+//
+// Allocate XMS undo buffers
+// NOTE: uses "mapwidth" & "mapheight"
+//
+////////////////////////////////////////////////////
+void AllocateUndoBuffers(void)
+{
+ long size=2L*mapwidth*mapheight;
+
+ if (MapFileHeader->maptype&BPLANE)
+   XMSundoB=XMSAllocate(size);
+ if (MapFileHeader->maptype&FPLANE)
+   XMSundoF=XMSAllocate(size);
+ if (MapFileHeader->maptype&IPLANE)
+   XMSundoI=XMSAllocate(size);
+}
+
+
+////////////////////////////////////////////////////
+//
+// Save Undo buffers
+//
+////////////////////////////////////////////////////
+void SaveUndo(int x,int y,int w,int h)
+{
+ unsigned hsize=w*2,j;
+
+ for (j=y;j<y+h;j++)
+   {
+    unsigned off=2*(j*mapwidth+x);
+
+    if (MapFileHeader->maptype&BPLANE)
+      XMSmove(0,(long)MK_FP(MapBkgnd,off),XMSundoB,off,hsize);
+    if (MapFileHeader->maptype&FPLANE)
+      XMSmove(0,(long)MK_FP(MapFrgnd,off),XMSundoF,off,hsize);
+    if (MapFileHeader->maptype&IPLANE)
+      XMSmove(0,(long)MK_FP(MapInfoPl,off),XMSundoI,off,hsize);
+   }
+}
+
+
+////////////////////////////////////////////////////
+//
+// Restore Undo buffers
+//
+////////////////////////////////////////////////////
+void RestoreUndo(void)
+{
+ long size=2L*UndoRegion.w;
+ unsigned j;
+
+ sound(2000);
+ for (j=UndoRegion.y;j<UndoRegion.y+UndoRegion.h;j++)
+   {
+    unsigned loc=2*(j*mapwidth+UndoRegion.x);
+
+    if (MapFileHeader->maptype&BPLANE)
+      XMSmove(XMSundoB,loc,0,(long)MK_FP(MapBkgnd,loc),size);
+    if (MapFileHeader->maptype&FPLANE)
+      XMSmove(XMSundoF,loc,0,(long)MK_FP(MapFrgnd,loc),size);
+    if (MapFileHeader->maptype&IPLANE)
+      XMSmove(XMSundoI,loc,0,(long)MK_FP(MapInfoPl,loc),size);
+   }
+
+ nosound();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Copy the current UNDO region to the undo buffers
+//
+////////////////////////////////////////////////////
+void CopyUndoRegion(void)
+{
+ if (UndoRegion.x==-1)
+       return;
+
+ SaveUndo(UndoRegion.x,UndoRegion.y,UndoRegion.w,UndoRegion.h);
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Undo
+//
+////////////////////////////////////////////////////
+void Item_Undo(void)
+{
+ if (UndoRegion.x==-1)
+       {
+        ErrDialog("You don't have anything to UNDO!"," Oh, yeah. ");
+        return;
+       }
+
+ RestoreUndo();
+ DrawMap();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Tile Search!
+//
+////////////////////////////////////////////////////
+void Item_TileSearch(void)
+{
+ int num=planeton+planemon+planeion;
+
+ ZeroModes();
+ if (num>1)
+       {
+        ErrDialog("TILE SEARCH will only work\n"
+                       "with ONE active plane! Make\n"
+                       "sure that the tile you're\n"
+                       "searching for is selected!"," OK ");
+        return;
+       }
+
+ TsearchMode=1;
+ DrawInfoBar();
+ DrawMap();
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Launch
+//
+////////////////////////////////////////////////////
+char tempparm[40];
+
+void Item_Launch(void)
+{
+ TempStruct LaunchInfo;
+ char ename[64],*envstr[15],temp[40],temp1[40],temp2[40],tiname[14]="TEDINFO.TMP",i,j;
+ long size;
+ int  rottlaunch;
+ int  startp;
+ unsigned mx,my;
+
+
+ rottlaunch=0;
+ if (!TEDInfo->launchname[0])
+       {
+        ErrDialog("You didn't specify a launching\n"
+                       "name on the command line? What\n"
+                       "do I launch, Einstein? Geez!"," What a goober. ");
+        return;
+       }
+
+ //
+ // Save the handles for all XMS memory so we don't
+ // have to re-install this shit!
+ //
+ TEDInfo->OldCgaXMS=CgaXMS;
+ TEDInfo->OldEgaXMS=EgaXMS;
+ TEDInfo->OldVgaXMS=VgaXMS;
+
+ TEDInfo->OldCgaXMSsize=CgaXMSsize;
+ TEDInfo->OldEgaXMSsize=EgaXMSsize;
+ TEDInfo->OldVgaXMSsize=VgaXMSsize;
+
+ size=4L*(tilenum+tilemnum);
+ if (CgaXMS)
+       {
+        if (1024L*XMSTotalFree()<size)
+               {
+                XMSFreeMem(CgaXMS);
+                TEDInfo->OldCgaXMS=TEDInfo->OldCgaXMSsize=0;
+               }
+        else
+               {
+                TEDInfo->CgaXMSlook=XMSAllocate(size);
+                XMSmove(0,(long)MK_FP(CgaXMSlookup,0),TEDInfo->CgaXMSlook,0,size);
+               }
+       }
+
+ if (EgaXMS)
+       {
+        if (1024L*XMSTotalFree()<size)
+               {
+                XMSFreeMem(EgaXMS);
+                TEDInfo->OldEgaXMS=TEDInfo->OldEgaXMSsize=0;
+               }
+        else
+               {
+                TEDInfo->EgaXMSlook=XMSAllocate(size);
+                XMSmove(0,(long)MK_FP(EgaXMSlookup,0),TEDInfo->EgaXMSlook,0,size);
+               }
+       }
+
+ if (VgaXMS)
+       {
+        if (1024L*XMSTotalFree()<size)
+               {
+                XMSFreeMem(VgaXMS);
+                TEDInfo->OldVgaXMS=TEDInfo->OldVgaXMSsize=0;
+               }
+        else
+               {
+                TEDInfo->VgaXMSlook=XMSAllocate(size);
+                XMSmove(0,(long)MK_FP(VgaXMSlookup,0),TEDInfo->VgaXMSlook,0,size);
+               }
+       }
+
+ //
+ // SAVE CURRENT VIDEOMODE FOR LAUNCH RETURN
+ //
+ LaunchInfo.lastmode=videomode;
+ strcpy(LaunchInfo.ext,ext);
+ SaveFile(tiname,(char huge *)&LaunchInfo,0,sizeof(TempStruct));
+
+ //
+ // ICON CHANGE ON LAUNCH?
+ //
+ if (keydown[0x2A])
+        {
+        rottlaunch=1;
+        startp=5;
+        mx=xbase+(pixelx>>(tsize+2));
+        my=ybase+((pixely-8)>>(tsize+2));
+        }
+ else
+        startp=3;
+ if (pixely>=8 && pixely<infoy*8 && TEDInfo->permicon
+         && MapFileHeader->maptype&IPLANE && !usingbat && keydown[0x1d])
+       {
+        unsigned i,j;
+
+        mx=xbase+(pixelx>>(tsize+2));
+        my=ybase+((pixely-8)>>(tsize+2));
+
+        for (j=0;j<mapheight;j++)
+               for (i=0;i<mapwidth;i++)
+       if (MapInfoPl[j*mapwidth+i]==TEDInfo->permicon)
+         {
+               MapInfoPl[j*mapwidth+i]=0;
+               TEDInfo->lastx=i;
+               TEDInfo->lasty=j;
+               break;
+         }
+
+        MapInfoPl[my*mapwidth+mx]=TEDInfo->permicon;
+        DrawMap();
+        DirtyFlag=1;
+       }
+
+ TEDInfo->oscrx=xbase;
+ TEDInfo->oscry=ybase;
+ TEDInfo->pflags=((planeton&1)<<6)|
+                ((planemon&1)<<5)|
+                ((planeion&1)<<4)|
+                ((viewton&1)<<2)|
+                ((viewmon&1)<<1)|
+                (viewion&1);
+
+ _fmemcpy((void far *)TEDInfo->parmstring,(void far *)parmstring,64);
+
+ Item_SaveMap();
+ SaveTEDInfo();
+ SaveOutputHeader();
+
+ if (XMSmaps)
+       XMSFreeMem(XMSmaps);
+
+ strcpy(temp,"Launching ");
+ _fstrcat((char far *)temp,(char far *)TEDInfo->launchname);
+ strcat(temp,"...");
+ ErrDialog(temp,"");
+ clearkeys();
+ nosound();
+ MouseHide();
+
+ _fmemcpy((char far *)ename,(char far *)TEDInfo->launchname,14);
+
+ envstr[0] = ename;
+ envstr[1] = "/TEDLEVEL";
+ itoa(whichmap,temp,10);
+ envstr[2] = temp;
+ if (rottlaunch)
+        {
+        itoa(mx,temp1,10);
+        envstr[3] = temp1;
+        itoa(my,temp2,10);
+        envstr[4] = temp2;
+        }
+ //
+ // CHOP UP THE PARMSTRING FOR 'EXECV'
+ //
+ strcpy(tempparm,parmstring);
+ envstr[startp]=&tempparm[0];
+ for(j=startp+1,i=0;i<strlen(tempparm);i++)
+       if (tempparm[i]==' ')
+       {
+        envstr[j]=&tempparm[i+1];
+        tempparm[i]=0;
+        j++;
+       }
+ envstr[j]=0;
+
+ RemoveUndoBuffers();
+ ShutdownKBD();
+
+ //
+ // ARE WE EXITING WITH A BATCH FILE?
+ //
+
+ if (usingbat)
+       {
+        setvideo(TEXT);
+        exit(whichmap+2);
+   }
+
+ fcloseall();
+ MMShutdown();
+ execv(ename,envstr);
+
+ SetupKBD();
+ RestoreBackground();
+ MouseShow();
+ ErrDialog("LAUNCHing failed. TED5 will\n"
+          "now restart."," I have gubs ");
+ ShutdownKBD();
+ execlp("TED5.EXE","TED5.EXE","/LAUNCH",NULL);
+
+ printf("Couldn't find TED5 for some reason!");
+ exit(1);
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - TILEINFO Copy
+//
+////////////////////////////////////////////////////
+DialogDef TICd=
+{"TILEINFOM Copy Kludge\n\n"
+ "From:\n"
+ "  To:\n"
+ "Rows:",22,6};
+
+
+void Item_TINFOCopy(void)
+{
+ unsigned dx,dy,i,from,to,amt;
+ memptr block;
+
+
+ MouseHide();
+ DrawDialog(&TICd,1);
+ GetDialogXY(&TICd,&dx,&dy);
+
+
+ sx=dx+5;
+ sy=dy+2;
+ from=inputint(9);
+ if (from==ESCOUT)
+ {
+  RestoreBackground();
+  MouseShow();
+  return;
+ }
+
+
+ sx=dx+5;
+ sy=dy+3;
+ to=inputint(9);
+ if (to==ESCOUT)
+ {
+  RestoreBackground();
+  MouseShow();
+  return;
+ }
+
+
+ sx=dx+5;
+ sy=dy+4;
+ amt=inputint(9);
+ if (amt==ESCOUT)
+ {
+  RestoreBackground();
+  MouseShow();
+  return;
+ }
+ amt*=18;
+
+
+ MMAllocate(&block,amt);
+
+ for (i=0;i<numtmplanes;i++)
+ {
+  movedata((unsigned)TMinfo[i],from,(unsigned)block,0,amt);
+  movedata((unsigned)block,0,(unsigned)TMinfo[i],to,amt);
+ }
+
+ MMFreePtr(&block);
+ RestoreBackground();
+ DirtyFlag=writeH=1;
+
+
+ MouseShow();
+}
diff --git a/16/ted5/TED5-2.C b/16/ted5/TED5-2.C
new file mode 100755 (executable)
index 0000000..d778d69
--- /dev/null
@@ -0,0 +1,2184 @@
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// TED5-2 : Menu Item Routines
+//
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+#include "ted5.h"
+#pragma hdrstop
+
+////////////////////////////////////////////////////
+//
+// Toggle the INFOBAR on and off
+//
+////////////////////////////////////////////////////
+void Item_ToggleInfo(void)
+{
+ infobaron^=1;
+ MouseHide();
+ InitDesktop(TED5MenuBar,0);
+ FigureScreenEdges();
+ if (ybase+screenh>mapheight && mapheight>screenh)
+   ybase--;
+ DrawMap();
+ DrawInfoBar();
+ MouseShow();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Tile Select
+//
+////////////////////////////////////////////////////
+btype SelTb[]={{" Tiles ",2,21,1},
+              {" Masked ",11,21,1},
+              {" Icons ",21,21,1},
+              {" Exit ",30,21,2}};
+DialogDef SelTd={"",38,23,4,&SelTb[0],NULL};
+
+void SelectTiles(int screen)
+{
+ int exitok=0,which,i,numrows,numcols,b0,b1,redraw=0;
+
+ //
+ // if parameter passed, change the screen
+ //
+ if (screen)
+   whichscreen=screen-1;
+
+ if (PasteMode || SelectMode)   // RE-BLIT MAP IF WE ARE ENTERING WHILE
+   redraw=1;                    // FLOATING AN IMAGE
+
+ PasteMode=SelectMode=0;
+ SelX1=SelX2=SelY1=SelY2=-1;
+
+ switch(videomode)
+ {
+  case CGA:
+  case EGA1:
+  case VGA:
+        SelTd.height=23;
+    for(i=0;i<4;i++)
+      SelTb[i].yoff=21;
+    break;
+  case EGA2:
+    SelTd.height=58;
+    for(i=0;i<4;i++)
+      SelTb[i].yoff=56;
+ }
+
+ DrawDialog(&SelTd,1);
+ DrawTileSelect(0,&numrows,&numcols);
+ selectcols=numcols;    // VERY IMPORTANT TO PASTE-FROM-TILESELECT MODE
+ DrawCurrentTiles();
+ while(keydown[0x39]);  // WAIT FOR SPACE-UP
+
+ do
+ {
+  which=CheckButtonsRet(&SelTd);
+  b0=MouseButton()&1;
+  b1=(MouseButton()>>1)&1;
+
+  if (which<0)
+    {
+     //
+     // GRAB CURRENT TILE FROM MATRIX
+     //
+     if (b0 || b1)
+       {
+       int mx,my;
+
+       MouseCoords(&mx,&my);
+       mx/=8;
+       if (mx>=left && mx<left+(numcols<<(tsize-1)) &&
+           my>=16 && my<=16+(numrows<<(2+tsize)))
+         {
+          int tile;
+
+          tile=((my-16)>>(tsize+2))*numcols+
+               ((mx-left)>>(tsize-1));
+
+          if (SelectMode)
+            {
+             int thebase;
+             switch(whichscreen)
+                       {
+              case TILES: thebase=tilebase/numcols; break;
+              case MASKED: thebase=tilembase/numcols;
+             }
+
+             if (b0)
+               {
+                sound(1000);
+                SelY1=((my-16)>>(tsize+2))+thebase;
+                SelX1=((mx-left)>>(tsize-1));
+                if (SelX2==-1 && SelY2==-1)
+                  {
+                   SelX2=SelX1;
+                   SelY2=SelY1;
+                  }
+                DrawTileSelect(0,&numrows,&numcols);
+                nosound();
+               }
+             else
+             if (b1)
+               {
+                sound(1000);
+                SelY2=((my-16)>>(tsize+2))+thebase;
+                SelX2=((mx-left)>>(tsize-1));
+                if (SelX1==-1 && SelY1==-1)
+                  {
+                   SelX1=SelX2;
+                   SelY1=SelY2;
+                  }
+                DrawTileSelect(0,&numrows,&numcols);
+                nosound();
+               }
+            }
+          else
+            {
+             switch(whichscreen)
+             {
+              case TILES:
+                if (XMSlookup[tile+tilebase]>=0)
+                  whicht=tile+tilebase;
+                else
+                  errsound();
+                break;
+              case MASKED:
+                whichtm=tile+tilembase+numcols*maxiconrows+tilenum;
+                if (XMSlookup[whichtm]==-1)
+                  whichtm=tilenum;
+                break;
+              case ICONS:
+                if (XMSlookup[tile+tilenum]>=0 || !tile)
+                  whichi=tile+tilenum;
+                else
+                  errsound();
+                break;
+             }
+             DrawCurrentTiles();
+            }
+         }
+       }
+
+     if (keydown[0x48])                 // UP
+       DrawTileSelect(-1,&numrows,&numcols);
+     else
+     if (keydown[0x50])                 // DOWN
+       DrawTileSelect(1,&numrows,&numcols);
+     else
+     if (keydown[0x47])                 // HOME
+       {
+       if (whichscreen==TILES)
+         DrawTileSelect(-tilebase/numcols,&numrows,&numcols);
+       else
+       if (whichscreen==MASKED)
+         DrawTileSelect(-tilembase/numcols,&numrows,&numcols);
+       }
+     else
+     if (keydown[0x4f])                 // END
+       {
+       if (whichscreen==TILES)
+         DrawTileSelect(tilenum,&numrows,&numcols);
+       else
+       if (whichscreen==MASKED)
+         DrawTileSelect(tilemnum,&numrows,&numcols);
+       }
+     else
+     if (keydown[0x49])                 // PgUP
+       {
+       DrawTileSelect(-numrows,&numrows,&numcols);
+       if (!keydown[0x1d])     // if not CTRL down, wait for keyup
+         while(keydown[0x49]);
+       }
+         else
+     if (keydown[0x51])                 // PgDN
+       {
+       DrawTileSelect(numrows,&numrows,&numcols);
+       if (!keydown[0x1d])     // if not CTRL down, wait for keyup
+         while(keydown[0x51]);
+       }
+     else
+     if (keydown[0x39])                 // SPACEBAR
+       {
+       RestoreBackground();
+       while(keydown[0x39]);
+       SelectMode=0;
+       if (redraw)
+         DrawMap();
+       DrawInfoBar();
+       return;
+       }
+     else                               // 'C' TO COPY
+     if (keydown[0x2e] && (whichscreen==TILES || whichscreen==MASKED))
+       {
+       char temp[]="COPY MODE";
+
+       sx=screencenterx-strlen(temp)/2;
+       SelectMode=sy=1;
+       print(temp);
+
+       while(keydown[0x2e]);
+       }
+    }
+  else
+    switch(which)
+    {
+     case 0:
+       if (!SelectMode)
+        exitok=1;
+       else
+        {
+         char temp[]="         ";
+
+         sx=screencenterx-strlen(temp)/2;
+         SelectMode=0;
+         SelX1=SelX2=SelY1=SelY2=-1;
+         sy=1;
+         print(temp);
+         DrawTileSelect(0,&numrows,&numcols);
+        }
+       break;
+
+     case 4:
+       if (!SelectMode)
+        exitok=1;
+       //
+       // 'ENTER' TO FINALIZE COPY
+       //
+       else
+        {
+         char temp[]="         ";
+
+         if (MouseButton())    // IF CLICKED ON 'EXIT' WITH MOUSE
+           break;
+
+         sound(500);
+         sx=screencenterx-strlen(temp)/2;
+         PasteOK=sy=1;
+         print(temp);
+
+         TileCopy.x=SelX1;
+         TileCopy.y=SelY1;
+         TileCopy.w=SelX2-SelX1+1;
+         TileCopy.h=SelY2-SelY1+1;
+         TileCopy.MapOrTileSelect=(whichscreen==TILES)+2*(whichscreen==MASKED);
+
+         while(keydown[0x1c]);
+         nosound();
+         SelectMode=0;
+         SelX1=SelX2=SelY1=SelY2=-1;
+         DrawTileSelect(0,&numrows,&numcols);
+        }
+       break;
+     //
+     // NORMAL TILE SELECT
+     //
+     case 1:
+       if (whichscreen!=TILES)
+        {
+         SelX1=SelX2=SelY1=SelY2=-1;
+         SelectMode=0;
+         whichscreen=TILES;
+         DrawDialog(&SelTd,0);
+         DrawCurrentTiles();
+         DrawTileSelect(0,&numrows,&numcols);
+        }
+       else
+        errsound();
+       GetButtonXY(&SelTd,0,&sx,&sy);
+       MouseHide();
+       print(SelTb[0].text);
+       MouseShow();
+       break;
+     //
+     // MASKED TILE SELECT
+     //
+     case 2:
+       if (tilemnum && whichscreen!=MASKED)
+        {
+         SelX1=SelX2=SelY1=SelY2=-1;
+         SelectMode=0;
+         whichscreen=MASKED;
+         DrawDialog(&SelTd,0);
+         DrawCurrentTiles();
+         DrawTileSelect(0,&numrows,&numcols);
+        }
+       else
+        errsound();
+       GetButtonXY(&SelTd,1,&sx,&sy);
+       MouseHide();
+       print(SelTb[1].text);
+       MouseShow();
+       break;
+     //
+     // ICON SELECT
+     //
+     case 3:
+       if (tilemnum && whichscreen!=ICONS)
+        {
+         whichscreen=ICONS;
+         DrawDialog(&SelTd,0);
+         DrawCurrentTiles();
+         DrawTileSelect(0,&numrows,&numcols);
+        }
+       else
+        errsound();
+       GetButtonXY(&SelTd,2,&sx,&sy);
+       MouseHide();
+                print(SelTb[2].text);
+       MouseShow();
+    }
+
+ } while(!exitok);
+ RestoreBackground();
+ SelectMode=0;
+ SelX1=SelX2=SelY1=SelY2=-1;
+ DrawInfoBar();
+ if (redraw)
+   DrawMap();
+}
+
+
+//
+// DRAW THE CURRENT TILES IN THE TILE-SELECT WINDOW
+//
+void DrawCurrentTiles(void)
+{
+ MouseHide();
+ GetButtonXY(&SelTd,0,&sx,&sy);
+ sy-=1+tsize;
+ CombineTiles(whicht,0,0,tsize);
+ DrawTile(sx,sy*8,tsize);
+ sx+=2;
+ printhex(whicht);
+ sy++;
+ sx-=5;
+ printint(whicht);
+ print("   ");
+
+ if (tilemnum)
+   {
+    GetButtonXY(&SelTd,1,&sx,&sy);
+    sy-=1+tsize;
+    CombineTiles(-BkgndColor,whichtm,0,tsize);
+    DrawTile(sx,sy*8,tsize);
+    sx+=2;
+    (whichtm==tilenum)?print(" No  "):printhex(whichtm-tilenum);
+
+    sy++;
+    sx-=5;
+    (whichtm==tilenum)?print(" Tile "):printint(whichtm-tilenum);
+    print("    ");
+
+        GetButtonXY(&SelTd,2,&sx,&sy);
+    sy-=1+tsize;
+    CombineTiles(-ICONBACK,whichi,0,tsize);
+    DrawTile(sx,sy*8,tsize);
+    sx+=2;
+    (whichi==tilenum)?print(" No  "):printhex(whichi-tilenum);
+    sy++;
+    sx-=5;
+    (whichi==tilenum)?print(" Icon "):printint(whichi-tilenum);
+    print("    ");
+   }
+ MouseShow();
+}
+
+
+//
+// CHECK TILESELECT EDGES
+//
+void CheckTSelectEdges(int x,int y,int basey)
+{
+ int xx,yy,temp;
+
+ xx=left+(x<<(tsize-1));
+ yy=(y<<(tsize-1))+2;
+
+ if (SelX2<SelX1)
+   {
+    temp=SelX1;
+    SelX1=SelX2;
+    SelX2=temp;
+   }
+
+ if (SelY2<SelY1)
+   {
+    temp=SelY1;
+    SelY1=SelY2;
+    SelY2=temp;
+   }
+
+ if (x==SelX1 && y==SelY1-basey)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(xx,yy,1); return;
+     case 2: drawchar(xx  ,yy,1);
+                 drawchar(xx+1,yy,2);
+            drawchar(xx  ,yy+1,4);
+            break;
+     case 3: drawchar(xx,yy,1);
+
+            drawchar(xx,yy+1,4);
+            drawchar(xx,yy+2,4);
+            drawchar(xx,yy+3,4);
+
+            drawchar(xx+1,yy,2);
+            drawchar(xx+2,yy,2);
+            drawchar(xx+3,yy,2);
+
+            break;
+    }
+   }
+ if (x==SelX2 && y==SelY2-basey)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(xx,yy,8); return;
+     case 2: drawchar(xx+1,yy+1,8);
+            drawchar(xx+1,yy,5);
+            drawchar(xx,yy+1,7);
+            break;
+     case 3: drawchar(xx+3,yy+3,8);
+
+            drawchar(xx+3,yy  ,5);
+            drawchar(xx+3,yy+1,5);
+            drawchar(xx+3,yy+2,5);
+
+            drawchar(xx  ,yy+3,7);
+            drawchar(xx+1,yy+3,7);
+            drawchar(xx+2,yy+3,7);
+            break;
+    }
+   }
+ if (x==SelX2 && y==SelY1-basey)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(xx,yy,3); return;
+     case 2: drawchar(xx+1,yy,3);
+            drawchar(xx,yy,2);
+            drawchar(xx+1,yy+1,5);
+                 break;
+     case 3: drawchar(xx+3,yy,3);
+
+            drawchar(xx+2,yy,2);
+            drawchar(xx+1,yy,2);
+            drawchar(xx  ,yy,2);
+
+            drawchar(xx+3,yy+1,5);
+            drawchar(xx+3,yy+2,5);
+            drawchar(xx+3,yy+3,5);
+            break;
+    }
+   }
+ if (x==SelX1 && y==SelY2-basey)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(xx,yy,6); return;
+     case 2: drawchar(xx,yy+1,6);
+            drawchar(xx+1,yy+1,7);
+            drawchar(xx,yy,4);
+            break;
+     case 3: drawchar(xx,yy+3,6);
+
+            drawchar(xx  ,yy+2,4);
+            drawchar(xx  ,yy+1,4);
+            drawchar(xx  ,yy,4);
+
+            drawchar(xx+1,yy+3,7);
+            drawchar(xx+2,yy+3,7);
+            drawchar(xx+3,yy+3,7);
+            break;
+    }
+   }
+
+ if (x==SelX1 && y>SelY1-basey && y<SelY2-basey)
+   {
+    switch(tsize)
+    {
+     case 3: drawchar(xx,yy+3,4);
+            drawchar(xx,yy+2,4);
+     case 2: drawchar(xx,yy+1,4);
+     case 1: drawchar(xx,yy,4);
+            break;
+    }
+       }
+ else
+ if (y==SelY1-basey && x>SelX1 && x<SelX2)
+   {
+    switch(tsize)
+    {
+     case 3: drawchar(xx+3,yy,2);
+            drawchar(xx+2,yy,2);
+     case 2: drawchar(xx+1,yy,2);
+     case 1: drawchar(xx  ,yy,2);
+            break;
+    }
+   }
+ else
+ if (x==SelX2 && y>SelY1-basey && y<SelY2-basey)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(xx,yy,5); return;
+     case 2: drawchar(xx+1,yy,5);
+            drawchar(xx+1,yy+1,5);
+            break;
+     case 3: drawchar(xx+3,yy,5);
+            drawchar(xx+3,yy+1,5);
+            drawchar(xx+3,yy+2,5);
+            drawchar(xx+3,yy+3,5);
+            break;
+    }
+   }
+ else
+ if (y==SelY2-basey && x>SelX1 && x<SelX2)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(xx,yy,7); return;
+     case 2: drawchar(xx  ,yy+1,7);
+            drawchar(xx+1,yy+1,7);
+            break;
+     case 3: drawchar(xx  ,yy+3,7);
+            drawchar(xx+1,yy+3,7);
+            drawchar(xx+2,yy+3,7);
+            drawchar(xx+3,yy+3,7);
+            break;
+    }
+   }
+}
+
+
+
+//
+// FILL THE TILE SELECT SCREEN WITH TILES
+//
+void DrawTileSelect(int deltarow,int *retrows,int *retcols)
+{
+ char tile[32*32];
+ int numcols,numrows,i,j;
+
+ MouseHide();
+ switch(videomode)
+ {
+  case CGA:
+  case EGA1:
+  case VGA:
+    numrows=18-10*(tsize==2)-15*(tsize==3);
+    left=2;
+    break;
+  case EGA2:
+    numrows=49-23*(tsize==2)-34*(tsize==3);
+    left=22;
+ }
+
+ switch(tsize)
+ {
+  case 1: numcols=36; break;
+  case 2: numcols=18; break;
+  case 3: numcols=9;
+ }
+
+ if (whichscreen==TILES && tilebase+numrows*numcols>tilenum)
+   {
+    tilebase=0;
+    numrows=tilenum/numcols;
+   }
+
+ if (whichscreen==MASKED && tilembase+numrows*numcols>tilemnum-maxiconrows*numcols)
+   {
+    tilembase=0;
+    numrows=tilemnum/numcols-maxiconrows;
+   }
+
+ if (whichscreen==ICONS && numrows*numcols>maxiconrows*numcols)
+   {
+    tilembase=0;
+    numrows=maxiconrows;
+   }
+
+ switch((deltarow<0?-1:deltarow>0?1:0))
+ {
+  case -1:
+   switch(whichscreen)
+   {
+    case TILES:
+      tilebase+=deltarow*numcols;
+      if (tilebase<0)
+       tilebase=0;
+      break;
+    case MASKED:
+      tilembase+=deltarow*numcols;
+      if (tilembase<0)
+       tilembase=0;
+   }
+   break;
+  case 1:
+   switch(whichscreen)
+   {
+    case TILES:
+      tilebase+=deltarow*numcols;
+      if (tilebase+numrows*numcols>tilenum)
+       tilebase=tilenum-numcols*numrows;
+      break;
+    case MASKED:
+      tilembase+=deltarow*numcols;
+      if (tilembase+numrows*numcols>tilemnum-maxiconrows*numcols)
+       tilembase=(tilemnum-maxiconrows*numcols)-numcols*numrows;
+   }
+ }
+
+ switch(whichscreen)
+ {
+  case TILES:
+    for(j=0;j<numrows;j++)
+      for(i=0;i<numcols;i++)
+      {
+       CombineTiles(tilebase+j*numcols+i,0,0,tsize);
+       if (GridMode)
+        Overlay(tsize);
+       DrawTile(i*2+left,j*16+16,tsize);
+       CheckTSelectEdges(i,j,tilebase/numcols);
+      }
+    break;
+
+  case MASKED:
+    for(j=0;j<numrows;j++)
+      for(i=0;i<numcols;i++)
+      {
+       CombineTiles(-BkgndColor,tilenum+numcols*maxiconrows+tilembase+j*numcols+i,0,tsize);
+       if (GridMode)
+        Overlay(tsize);
+       DrawTile(i*2+left,j*16+16,tsize);
+       CheckTSelectEdges(i,j,tilembase/numcols);
+      }
+    break;
+
+  default:
+    for(j=0;j<numrows;j++)
+      for(i=0;i<numcols;i++)
+      {
+       CombineTiles(-ICONBACK,tilenum+j*numcols+i,0,tsize);
+       if (GridMode)
+        Overlay(tsize);
+       DrawTile(i*2+left,j*16+16,tsize);
+      }
+ }
+ MouseShow();
+
+ *retrows=numrows;
+ *retcols=numcols;
+}
+
+
+
+void errsound(void)
+{
+ sound(1000);
+ delay(50);
+ nosound();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - About
+//
+////////////////////////////////////////////////////
+void Item_About(void)
+{
+ char dstr[200]=IDSTSTR;
+
+ strcat(dstr,"\n\n   IdWare by John Romero\n");
+ strcat(dstr,"        ");
+ strcat(dstr,__DATE__);
+ strcat(dstr,"\n    (C)1991 Id Software\n\n"
+            " DeluxePaint for Tile Maps! ");
+
+ ErrDialog(dstr," OK ");
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Video Mode Switch
+//
+////////////////////////////////////////////////////
+btype VMS1b[]={{" CGA 320x200 ",5,2,1},
+              {" EGA 320x200 ",5,5,1},
+                        {" EGA 640x350 ",5,8,1},
+              {" VGA 320x200 ",5,11,1}};
+DialogDef VMS1d={"Select the resolution:",22,14,4,&VMS1b[0],NULL};
+
+void Item_ModeSwitch(void)
+{
+ int i,which,rtn;
+
+ for(i=0;i<VMS1d.numbuttons;i++)
+   {
+    VMS1b[i].border=1;
+    if (i==lastvideo)
+      VMS1b[i].border=2;
+   }
+
+// which=DoDialog(&VMS1d);
+ //
+ // Keep track of last video mode!
+ //
+ if (videomode==EGA1)
+        {
+        which=3;
+        lastvideo=videomode;
+        }
+ else
+        {
+        which=2;
+        lastvideo=videomode;
+        }
+
+ MouseHide();
+ switch(which)
+ {
+  case 0:
+        MouseShow();
+        return;
+  case 1:
+        if (!CgaXMS)
+               {
+                rtn=LoadGraphStuff(1,CGA);
+                if (!rtn)
+        {
+         MouseShow();
+         ErrDialog("There aren't any CGA\n"
+                        "graphics files available!"," OK ");
+         return;
+        }
+                if (rtn<0)
+        return;
+                MouseShow();
+               }
+        else
+               {
+                xmshandle=CgaXMS;
+                XMSlookup=CgaXMSlookup;
+               }
+        setvideo(CGA);
+        break;
+  case 2:
+        if (!EgaXMS)
+               {
+                rtn=LoadGraphStuff(1,EGA1);
+                if (!rtn)
+        {
+         MouseShow();
+         ErrDialog("There aren't any EGA\n"
+                        "graphics files available!"," OK ");
+         return;
+        }
+                if (rtn<0)
+        return;
+                MouseShow();
+               }
+        else
+      {
+       xmshandle=EgaXMS;
+       XMSlookup=EgaXMSlookup;
+      }
+    setvideo(EGA1);
+    break;
+  case 3:
+    if (!EgaXMS)
+      {
+       rtn=LoadGraphStuff(1,EGA1);
+       if (!rtn)
+        {
+         MouseShow();
+         ErrDialog("There aren't any EGA\n"
+                   "graphics files available!"," OK ");
+         return;
+        }
+       if (rtn<0)
+        return;
+       MouseShow();
+      }
+    else
+      {
+       xmshandle=EgaXMS;
+       XMSlookup=EgaXMSlookup;
+      }
+    setvideo(EGA2);
+    break;
+  case 4:
+    if (!VgaXMS)
+      {
+       rtn=LoadGraphStuff(1,VGA);
+       if (!rtn)
+        {
+         MouseShow();
+         ErrDialog("There aren't any VGA\n"
+                   "graphics files available!"," OK ");
+         return;
+        }
+       if (rtn<0)
+        return;
+       MouseShow();
+               }
+        else
+      {
+       xmshandle=VgaXMS;
+       XMSlookup=VgaXMSlookup;
+      }
+    setvideo(VGA);
+ }
+
+ InitDesktop(TED5MenuBar,0);
+ DrawInfoBar();
+ FigureScreenEdges();
+
+ if (xbase+screenw>mapwidth)
+   xbase=mapwidth-screenw;
+ if (mapwidth<screenw)
+   xbase=0;
+ if (ybase+screenh>mapheight)
+   ybase=mapheight-screenh;
+ if (mapheight<screenh)
+   ybase=0;
+
+ DrawMap();
+ MouseShow();
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Map Stats
+//
+////////////////////////////////////////////////////
+btype MapStatsb={" OK ",11,11,2};
+DialogDef MapStatsd={"        MAP STATS\n\n"
+                    "Width   :\n"
+                    "Height  :\n"
+                    "Name    :\n"
+                    "Planes  :",
+                    24,13,1,&MapStatsb,NULL};
+
+void Item_MapStats(void)
+{
+ int ox,oy;
+ unsigned i,_seg *unique;
+
+ DrawDialog(&MapStatsd,1);
+ MouseHide();
+ GetDialogXY(&MapStatsd,&sx,&sy);
+ ox=sx+9;
+ oy=sy+2;
+ sx=ox;
+ sy=oy;
+ printint(mapwidth);
+ sx=ox;
+ sy=oy+1;
+ printint(mapheight);
+ sx=ox;
+ sy=oy+2;
+ print(MapHeader.name);
+ sx=ox;
+ sy=oy+3;
+
+ if (MapFileHeader->maptype&BPLANE)
+   print("BACK");
+ if (MapFileHeader->maptype&FPLANE)
+   print(",FORE");
+ if (MapFileHeader->maptype&IPLANE)
+   print(",INFO");
+
+ //
+ // Count amount of unique background tiles
+ //
+ sx=ox-9;
+ sy=oy+4;
+ if (MapFileHeader->maptype&BPLANE)
+   {
+    int amount=0;
+
+    print("Unique Bkgnd Tiles:");
+    MMAllocate((memptr *)&unique,tilenum*2);
+    _fmemset(unique,0,tilenum*2);
+    for (i=0;i<mapwidth*mapheight;i++)
+      unique[MapBkgnd[i]]=1;
+    for (i=0;i<tilenum;i++)
+      amount+=unique[i];
+    MMFreePtr((memptr *)&unique);
+        printint(amount);
+   }
+
+ //
+ // Count amount of unique foreground tiles
+ //
+ sx=ox-9;
+ sy=oy+5;
+ if (MapFileHeader->maptype&FPLANE)
+   {
+    int amount=0;
+
+    print("Unique Frgnd Tiles:");
+    MMAllocate((memptr *)&unique,tilemnum*2);
+    _fmemset(unique,0,tilemnum*2);
+    for (i=0;i<mapwidth*mapheight;i++)
+      if (MapFrgnd[i])
+       unique[MapFrgnd[i]]=1;
+    for (i=0;i<tilemnum;i++)
+      amount+=unique[i];
+    MMFreePtr((memptr *)&unique);
+    printint(amount);
+   }
+
+ //
+ // Count amount of icons
+ //
+ sx=ox-9;
+ sy=oy+6;
+ if (MapFileHeader->maptype&IPLANE)
+   {
+    int amount=0;
+
+    print("Amount of Icons:");
+    for (i=0;i<mapwidth*mapheight;i++)
+      if (MapInfoPl[i])
+       amount++;
+    printint(amount);
+   }
+
+ //
+ // Display amount of memory the map needs
+ //
+ sx=ox-9;
+ sy=oy+7;
+ {
+  long length=0;
+
+  if (MapFileHeader->maptype&BPLANE)
+    length+=2L*mapwidth*mapheight;
+  if (MapFileHeader->maptype&FPLANE)
+        length+=2L*mapwidth*mapheight;
+  if (MapFileHeader->maptype&IPLANE)
+    length+=2L*mapwidth*mapheight;
+  length+=sizeof(MapHeaderStr);
+
+  print("Size of map:");
+  length=(length+1023)/1024;
+  printint(length);
+  print("K");
+ }
+
+ MouseShow();
+ CheckButtons(&MapStatsd);
+ RestoreBackground();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Edit New Map
+//
+////////////////////////////////////////////////////
+btype DOSAVEb[]={{" Yes ",3,3,2},
+                {" No! ",15,3,1}};
+DialogDef DOSAVEd={"Your map has changed!\n"
+                  "       Save it?",
+                  21,5,2,&DOSAVEb[0],NULL};
+
+void Item_EditMap(void)
+{
+ int which,olddirt;
+
+ olddirt=DirtyFlag;
+ if (DirtyFlag)
+   {
+    which=DoDialog(&DOSAVEd);
+    if (!which)
+      return;
+    if (which==1)
+               Item_SaveMap();
+    DirtyFlag=0;
+   }
+
+ if ((which=SelectMap(1,CREATED,"TO EDIT"))==-1)
+   {
+        DirtyFlag=olddirt;
+    return;
+   }
+
+ TEDInfo->level=whichmap=which;
+ LoadMap(whichmap);
+ MouseHide();
+ InitDesktop(TED5MenuBar,0);
+ DrawInfoBar();
+ FigureScreenEdges();
+ DrawMap();
+ MouseShow();
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Save Map
+//
+////////////////////////////////////////////////////
+void Item_SaveMap(void)
+{
+ SaveMap(0);
+ DirtyFlag=0;
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Create Map
+//
+////////////////////////////////////////////////////
+void Item_CreateMap(void)
+{
+ if (DirtyFlag)
+   {
+    int button;
+
+    button=DoDialog(&DoCreated);
+    if (!button)
+      return;
+        if (button==1)
+      Item_SaveMap();
+    DirtyFlag=0;
+   }
+
+ CreateMap(1);
+ MouseHide();
+ InitDesktop(TED5MenuBar,0);
+ DrawInfoBar();
+ FigureScreenEdges();
+ DrawMap();
+ MouseShow();
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Delete Map
+//
+////////////////////////////////////////////////////
+btype AreSureB[]={{" Yes ",1,4,1},
+                 {" No ",11,4,2}};
+DialogDef AreSureD={"Are you sure you\n"
+                       "you want to delete",
+                       18,6,2,&AreSureB[0],NULL};
+
+void Item_DeleteMap(void)
+{
+ MapHeaderStr TempHead;
+ int whichdel,which,temp;
+
+ if ((whichdel=SelectMap(1,CREATED,"TO DELETE"))==-1)
+   return;
+
+ if (whichmap==whichdel)
+   {
+       ErrDialog("I'm just not gonna stand for\n"
+                "you deleting the map you're\n"
+                "currently editing. I'm not\n"
+                "gonna doit. Nope."," Gee... ");
+       return;
+   }
+
+ LoadFile(mapname,(char huge *)&TempHead,
+       MapFileHeader->dataoffsets[whichdel],sizeof(MapHeaderStr));
+ MouseHide();
+ DrawDialog(&AreSureD,1);
+ GetDialogXY(&AreSureD,&sx,&sy);
+ sy+=2;
+ sx=screencenterx-(strlen(TempHead.name)+1)/2;
+ print(TempHead.name);
+ print("?");
+ MouseShow();
+
+ which=CheckButtons(&AreSureD);
+ switch(which)
+ {
+  case 1:
+       temp=whichmap;
+       whichmap=whichdel;
+       RestoreBackground();
+       SaveMap(1);
+       whichmap=temp;
+       return;
+ }
+ RestoreBackground();
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Amputate Maps
+//
+////////////////////////////////////////////////////
+void Item_Amputate(void)
+{
+       char tstr[40];
+       MapHeaderStr TempHead;
+       int which1,which2,whichtemp,i,button;
+       long temp;
+
+
+       if ((which1 = SelectMap(1,CREATED,"TO START AMPUTATE"))==-1)
+               return;
+
+       LoadFile(mapname,(char huge *)&TempHead,
+               MapFileHeader->dataoffsets[which1],sizeof(MapHeaderStr));
+
+       if ((which2 = SelectMap(1,ANYLIST,"TO END AMPUTATE"))==-1)
+               return;
+
+       if (which2 < which1)
+       {
+               whichtemp = which1;
+               which1 = which2;
+               which2 = whichtemp;
+       }
+
+       if (whichmap >= which1 && whichmap <= which2)
+       {
+               ErrDialog (     "The currently loaded map\n"
+                                       "is within that range!\n"
+                                       "NON-AMPUTATENESS!!","Wah!");
+               return;
+       }
+
+       DrawDialog(&AreSureD,1);
+       button = CheckButtons(&AreSureD);
+       switch (button)
+       {
+               case 1:
+                       for (i = which1;i <= which2;i++)
+                       {
+                               MapFileHeader->dataoffsets[i] = -1;
+                               MapFileHeader->datalengths[i] = 0;
+                       }
+
+                       DirtyFlag = writeH = 1;
+                       SaveMap(0);
+       }
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Switch Maps
+//
+////////////////////////////////////////////////////
+void Item_SwitchMap(void)
+{
+ char tstr[40];
+ MapHeaderStr TempHead;
+ int which1,which2;
+ long temp;
+
+ while(1)
+ {
+  if ((which1=SelectMap(1,CREATED,"TO SWAP"))==-1)
+       return;
+  LoadFile(mapname,(char huge *)&TempHead,
+       MapFileHeader->dataoffsets[which1],sizeof(MapHeaderStr));
+  strcpy(tstr,"TO SWAP WITH '");
+  strcat(tstr,TempHead.name);
+  strcat(tstr,"'");
+  if ((which2=SelectMap(1,ANYLIST,tstr))==-1)
+       return;
+
+  if (which1==whichmap) // MAKE SURE THE CURRENTLY EDITED MAP GETS CHANGED!
+       whichmap=which2;
+  else
+  if (which2==whichmap)
+       whichmap=which1;
+
+  temp=MapFileHeader->dataoffsets[which1];
+
+  strcpy(tstr,MapNames[which1]);
+  strcpy(MapNames[which1],MapNames[which2]);
+  strcpy(MapNames[which2],tstr);
+
+  MapFileHeader->dataoffsets[which1]=MapFileHeader->dataoffsets[which2];
+  MapFileHeader->dataoffsets[which2]=temp;
+  writeH=DirtyFlag=1;
+ }
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Quit
+//
+////////////////////////////////////////////////////
+btype Qbuttons[]={{" Yes ",4,2,2},{" No ",12,2,1}},
+      DoSaveb[]={{" Yes ",7,4,2},{" No ",14,4,1}};
+DialogDef Qdialog={"Quit - Are you sure?",20,4,2,&Qbuttons[0],NULL},
+         DoSaved={"The map has been modified.\n"
+                  "Do you want to SAVE it\n"
+                  "before exiting TED5?",26,6,2,&DoSaveb[0],NULL},
+         DoCreated={"The map has been modified.\n"
+                    "Do you want to SAVE it\n"
+                    "before CREATING a new one?",26,6,2,&DoSaveb[0],NULL};
+
+void Item_Quit(void)
+{
+ int button;
+
+ button=DoDialog(&Qdialog);
+
+ if (button==1)
+   {
+        TEDInfo->lastvid=videomode;
+    TEDInfo->level=whichmap;
+    TEDInfo->OldCgaXMS=0;
+    TEDInfo->OldEgaXMS=0;
+    TEDInfo->OldVgaXMS=0;
+    TEDInfo->OldCgaXMSsize=0;
+    TEDInfo->OldEgaXMSsize=0;
+    TEDInfo->OldVgaXMSsize=0;
+
+    TEDInfo->pflags=((planeton&1)<<6)|
+                   ((planemon&1)<<5)|
+                   ((planeion&1)<<4)|
+                   ((viewton&1)<<2)|
+                   ((viewmon&1)<<1)|
+                   (viewion&1);
+
+    SaveTEDInfo();
+    if (DirtyFlag)
+      {
+       button=DoDialog(&DoSaved);
+       if (button==1)
+        Item_SaveMap();
+       if (!button)
+        return;        // ESC exits
+      }
+    SaveOutputHeader();
+    Quit("");
+   }
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Edit Map Names
+//
+////////////////////////////////////////////////////
+char EMNstring[16];
+btype EMNb[]={{EMNstring,1,4,1},
+             {"                ",1,8,1},
+             {" Exit ",7,11,1}};
+DialogDef EMNd={"     MAP RENAME\n\nChange...\n\n\n\nTo..."
+               ,20,13,3,&EMNb[0],NULL};
+
+void Item_EditMapNames(void)
+{
+ int which,mapnum,redraw=0,omapnum,oxb,oyb;
+ MapHeaderStr TempHeader;
+ char temp[16];
+
+
+ CheckForMapSave();
+ omapnum=whichmap;
+ oxb=xbase;
+ oyb=ybase;
+
+ if ((mapnum=SelectMap(1,CREATED,"TO RENAME"))<0)
+   return;
+
+ whichmap=mapnum;
+ LoadMap(whichmap);
+ strcpy(EMNstring,MapHeader.name);
+
+ MouseHide();
+ DrawDialog(&EMNd,1);
+ GetDialogXY(&EMNd,&sx,&sy);
+ MouseShow();
+ which=2;
+#pragma warn -rch
+ goto badboy;
+
+ do
+ {
+  which=CheckButtons(&EMNd);
+
+badboy:
+#pragma warn +rch
+  switch(which)
+  {
+   case 1:
+     RestoreBackground();
+     if ((mapnum=SelectMap(1,CREATED,"TO RENAME"))<0)
+       {
+       if (redraw)
+         DrawInfoBar();
+
+       whichmap=omapnum;
+       LoadMap(whichmap);
+       xbase=oxb;
+       ybase=oyb;
+       return;
+       }
+
+     whichmap=mapnum;
+     LoadMap(whichmap);
+     strcpy(EMNstring,MapHeader.name);
+     MouseHide();
+     DrawDialog(&EMNd,1);
+     MouseShow();
+
+   case 2:
+     MouseHide();
+     GetButtonXY(&EMNd,1,&sx,&sy);
+     print(EMNb[1].text);
+     GetButtonXY(&EMNd,1,&sx,&sy);
+     if (input(temp,15))
+       {
+       writeH=1;
+       strcpy(MapHeader.name,temp);
+       strcpy(MapNames[mapnum],temp);
+       DirtyFlag=1;
+       Item_SaveMap();
+       }
+     else
+       {
+       GetButtonXY(&EMNd,1,&sx,&sy);
+       print(EMNb[1].text);
+       }
+     MouseShow();
+     break;
+
+   case 3:
+     which=0;
+  }
+ } while(which);
+
+ RestoreBackground();
+ if (redraw)
+   DrawInfoBar();
+
+ whichmap=omapnum;
+ LoadMap(whichmap);
+ xbase=oxb;
+ ybase=oyb;
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Paste Mode
+//
+////////////////////////////////////////////////////
+void Item_Paste(void)
+{
+ if (!TileCopy.w)
+   return;
+
+ ZeroModes();
+ PasteMode=1;
+ DrawInfoBar();
+ px=(pixelx>>(tsize+2))+xbase;
+ py=((pixely-8)>>(tsize+2))+ybase;
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Copy Mode
+//
+////////////////////////////////////////////////////
+void Item_Copy(void)
+{
+ ZeroModes();
+ SelectMode=1;
+ SelX1=SelY1=SelX2=SelY2=-1;
+ DrawInfoBar();
+}
+
+////////////////////////////////////////////////////
+//
+// Item - LastVideo
+//
+////////////////////////////////////////////////////
+void Item_LastVideo(void)
+{
+ int temp=videomode;
+
+
+ videomode=lastvideo;
+ lastvideo=temp;
+ if (temp==EGA1)
+        videomode=EGA2;
+ else
+        videomode=EGA1;
+
+ switch(videomode)
+ {
+  case CGA:
+        xmshandle=CgaXMS;
+        XMSlookup=CgaXMSlookup;
+        break;
+  case EGA1:
+  case EGA2:
+        xmshandle=EgaXMS;
+        XMSlookup=EgaXMSlookup;
+        break;
+  case VGA:
+        xmshandle=VgaXMS;
+        XMSlookup=VgaXMSlookup;
+ }
+
+ MouseHide();
+ setvideo(videomode);
+ InitDesktop(TED5MenuBar,0);
+ DrawInfoBar();
+ FigureScreenEdges();
+
+ if (xbase+screenw>mapwidth)
+       xbase=mapwidth-screenw;
+ if (mapwidth<screenw)
+       xbase=0;
+ if (ybase+screenh>mapheight)
+       ybase=mapheight-screenh;
+ if (mapheight<screenh)
+       ybase=0;
+
+ DrawMap();
+ MouseShow();
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Switch to the Last Map
+//
+////////////////////////////////////////////////////
+void Item_LastMap(void)
+{
+ int temp;
+
+ if (!CheckForMapSave())
+       return;
+
+ if (lastmap==-1)
+       {
+        int which=SelectMap(1,CREATED,"TO EDIT");
+    if (which==-1)
+      return;
+    lastmap=which;
+   }
+
+ temp=whichmap;
+ whichmap=lastmap;
+ lastmap=temp;
+
+ LoadMap(whichmap);
+ InitDesktop(TED5MenuBar,0);
+ MouseShow();
+ DrawMap();
+ DrawInfoBar();
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Flood Fill!
+//
+////////////////////////////////////////////////////
+void Item_FloodFill(void)
+{
+ ZeroModes();
+ FillMode=1;
+ DrawInfoBar();
+}
+
+void DoFloodFill(int x,int y,int whichb)
+{
+#define NUMSPORES       500
+
+ int obx[NUMSPORES],oby[NUMSPORES],i,used,j,width,k,highest,height,
+     vectx[4]={0,1,0,-1},vecty[4]={-1,0,1,0},orgt,orgm,orgi,Ton,Mon,Ion;
+ unsigned ptr,newoff,whichplanes=0,ctrl=0;
+ int nx,ny,newt,newm,newi;
+
+
+ if (keydown[0x1d] || whichb)
+   ctrl++;
+
+ whichplanes=planeton+planemon+planeion;
+ if (whichplanes>1)
+   {
+        ErrDialog("I will only allow Flood Filling\n"
+             "one plane at a time; you have\n"
+             "more than one plane selected."," OK ");
+    return;
+   }
+
+ for (i=0;i<NUMSPORES;i++)
+   obx[i]=oby[i]=-1;
+
+ obx[0]=x;
+ oby[0]=y;
+ newoff=ptr=oby[0]*mapwidth+obx[0];
+ width=MapHeader.width;
+ height=MapHeader.height;
+ used=1;
+ highest=1;
+ if (obx[0]<0 || oby[0]<0 || obx[0]>width || oby[0]>height)
+   {
+    FillMode=0;
+    DrawInfoBar();
+    return;
+   }
+
+ Ton=planeton;
+ Mon=planemon;
+ Ion=planeion;
+
+ orgt=*(MapBkgnd+ptr);
+ orgm=*(MapFrgnd+ptr);
+ orgi=*(MapInfoPl+ptr);
+
+ if (((Ton?whicht==orgt:0) ||
+     (Mon?whichtm-tilenum==orgm:0) ||
+     (Ion?whichi-tilenum==orgi:0)) && !ctrl)
+   {
+    FillMode=0;
+    DrawInfoBar();
+    return;
+   }
+
+ MouseHide();
+ CopyUndoRegion();
+ UndoRegion.x=UndoRegion.y=0;
+ UndoRegion.w=mapwidth;
+ UndoRegion.h=mapheight;
+
+ if (ctrl)
+   {
+    unsigned from=(TileCopy.y+(y%TileCopy.h))*mapwidth+
+         TileCopy.x+(x%TileCopy.w);
+
+    switch(TileCopy.MapOrTileSelect)
+    {
+     case 0: // COPY BUFFER
+       Ton=TileCopy.PlanesCopied&BPLANE;
+       Mon=TileCopy.PlanesCopied&FPLANE;
+       Ion=TileCopy.PlanesCopied&IPLANE;
+
+       newt=CutBkgnd[from];
+       newm=CutFrgnd[from];
+       newi=CutInfoPl[from];
+
+       break;
+     case 1: // TILES
+       Ton=1;
+       Mon=Ion=0;
+
+       newt=((y%TileCopy.h)+TileCopy.y)*selectcols+
+           TileCopy.x+(x%TileCopy.w);
+       if (XMSlookup[newt]<0)
+        Ton=0;
+       break;
+     case 2: // MASKED
+       Ton=Ion=0;
+       Mon=1;
+
+       newm=((y%TileCopy.h)+TileCopy.y)*selectcols+
+           TileCopy.x+(x%TileCopy.w)+tilenum+maxiconrows*selectcols;
+       if (XMSlookup[newm]<0)
+        Mon=0;
+       else
+        newm-=tilenum;
+    }
+   }
+ else
+   {
+    newt=whicht;
+    newm=whichtm-tilenum;
+    newi=whichi-tilenum;
+   }
+
+ if (Ton)
+   *(MapBkgnd+newoff)=newt;
+ if (Mon)
+   *(MapFrgnd+newoff)=newm;
+ if (Ion)
+   *(MapInfoPl+newoff)=newi;
+
+ do
+   {
+    for (i=0;i<=highest;i++)
+      //
+      // SEE IF SPORE EXISTS
+      //
+      if (obx[i]!=-1)
+       {
+        //
+        // DRAW TILE AT SPORE IF IT'S ONSCREEN
+        //
+        if (oby[i]>=ybase && oby[i]<ybase+screenh &&
+            obx[i]>=xbase && obx[i]<xbase+screenw)
+            {
+             unsigned oldt,oldm,oldi,off;
+
+             off=oby[i]*width+obx[i];
+
+             oldt=*(MapBkgnd+off);
+             oldm=*(MapFrgnd+off)+tilenum;
+             oldi=*(MapInfoPl+off)+tilenum;
+
+             CombineTiles(viewton?oldt:-BkgndColor,
+                          viewmon?oldm:0,
+                          viewion?oldi:0,
+                          tsize);
+             DrawTile((obx[i]-xbase)<<(tsize-1),((oby[i]-ybase)<<(tsize+2))+8,tsize);
+            }
+
+        //
+        // FREE THIS SPORE
+        //
+        x=obx[i];
+        y=oby[i];
+        obx[i]=-1;
+        used--;
+
+        //
+        // SEARCH 4 QUADRANTS FOR A SPORE TO FILL
+        // (ONLY 4 QUADS SO WE DON'T FILL THRU DIAGONALS)
+        //
+        if (!ctrl)
+        for (j=0;j<4;j++)
+          {
+           newoff=(y+vecty[j])*mapwidth+x+vectx[j];
+
+           if ((Ton?*(MapBkgnd+newoff)==orgt:1) &&
+               (Mon?*(MapFrgnd+newoff)==orgm:1) &&
+               (Ion?*(MapInfoPl+newoff)==orgi:1))
+             {
+              for (k=0;k<NUMSPORES;k++)
+                if (obx[k]==-1)
+                  {
+                   obx[k]=x+vectx[j];
+                   oby[k]=y+vecty[j];
+                   if (obx[k]<0 || obx[k]>width || oby[k]<0 || oby[k]>height)
+                     {
+                      obx[k]=-1;
+                      break;
+                     }
+
+                   used++;
+                   if (Ton)
+                     *(MapBkgnd+newoff)=whicht;
+                   if (Mon)
+                     *(MapFrgnd+newoff)=whichtm-tilenum;
+                   if (Ion)
+                     *(MapInfoPl+newoff)=whichi-tilenum;
+                   DirtyFlag=1;
+                   if (k>highest)
+                     highest=k;
+                   break;
+                  }
+             }
+
+           if (keydown[1])     // ESC OUT
+             {
+              while(keydown[1]);
+              goto done;
+             }
+          }
+        else
+        for (j=0;j<4;j++)
+          {
+           unsigned from;
+
+           ny=y+vecty[j];
+           nx=x+vectx[j];
+
+           newoff=ny*mapwidth+nx;
+
+           if ((Ton?*(MapBkgnd+newoff)==orgt:1) &&
+               (Mon?*(MapFrgnd+newoff)==orgm:1) &&
+               (Ion?*(MapInfoPl+newoff)==orgi:1))
+             {
+              for (k=0;k<NUMSPORES;k++)
+                if (obx[k]==-1)
+                  {
+                   obx[k]=nx;
+                   oby[k]=ny;
+                   if (obx[k]<0 || obx[k]>width || oby[k]<0 || oby[k]>height)
+                     {
+                      obx[k]=-1;
+                      break;
+                     }
+
+                   from=(TileCopy.y+(ny%TileCopy.h))*mapwidth+
+                        TileCopy.x+(nx%TileCopy.w);
+
+                   switch(TileCopy.MapOrTileSelect)
+                   {
+                    case 0: // COPY BUFFER
+                      Ton=TileCopy.PlanesCopied&BPLANE;
+                      Mon=TileCopy.PlanesCopied&FPLANE;
+                      Ion=TileCopy.PlanesCopied&IPLANE;
+
+                      newt=CutBkgnd[from];
+                      newm=CutFrgnd[from];
+                      newi=CutInfoPl[from];
+
+                      break;
+                    case 1: // TILES
+                      Ton=1;
+                      Mon=Ion=0;
+
+                      newt=((ny%TileCopy.h)+TileCopy.y)*selectcols+
+                           TileCopy.x+(nx%TileCopy.w);
+                                if (XMSlookup[newt]<0)
+                        Ton=0;
+                      break;
+                    case 2: // MASKED
+                      Ton=Ion=0;
+                      Mon=1;
+
+                      newm=((ny%TileCopy.h)+TileCopy.y)*selectcols+
+                           TileCopy.x+(nx%TileCopy.w)+tilenum+maxiconrows*selectcols;
+                      if (XMSlookup[newm]<0)
+                        Mon=0;
+                      else
+                        newm-=tilenum;
+                   }
+
+                   if (Ton)
+                     *(MapBkgnd+newoff)=newt;
+                   if (Mon)
+                     *(MapFrgnd+newoff)=newm;
+                   if (Ion)
+                     *(MapInfoPl+newoff)=newi;
+                   used++;
+
+                   DirtyFlag=1;
+                   if (k>highest)
+                     highest=k;
+                   break;
+                  }
+             }
+
+           if (keydown[1])     // ESC OUT
+             {
+              while(keydown[1]);
+              goto done;
+             }
+          }
+       }
+   } while(used);
+
+done:
+ DrawMap();
+ MouseShow();
+ FillMode=0;
+ DrawInfoBar();
+}
+
+
+
+////////////////////////////////////////////////////
+//
+// If map has been changed, ask user if they want
+// to SAVE it before continuing.
+//
+////////////////////////////////////////////////////
+btype oktosaveB[]={{" Yes ",10,2,2},{" No ",20,2,1}};
+DialogDef oktosaveD={"The map has been modified!\n"
+                    "Save it?",26,4,2,&oktosaveB[0],NULL};
+
+int CheckForMapSave(void)
+{
+ if (DirtyFlag)
+   {
+    int which=DoDialog(&oktosaveD);
+    if (!which)
+      return 0;
+    if (which==1)
+      Item_SaveMap();
+   }
+ return 1;
+}
+
+
+////////////////////////////////////////////////////
+//
+// Zero all special mode flags
+//
+////////////////////////////////////////////////////
+void ZeroModes(void)
+{
+ SelX1=SelX2=SelY1=SelY2=-1;
+ if (BfillMode || SelectMode || PasteMode || FillMode)
+ {
+  DrawMap();
+  DrawInfoBar();
+ }
+
+ BfillMode=SelectMode=PasteMode=FillMode=0;
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Count Map Tiles
+//
+////////////////////////////////////////////////////
+btype CMTb[]={
+             {" Exit ",9,20,2},
+             {" TILE ",1,20,1},
+             {" MASKED ",17,20,1},
+             {" Rebuild ",27,20,1}
+            };
+DialogDef CMTd={"        Count Unused Map Tiles",38,22,4,&CMTb[0],0};
+unsigned char _seg *tarray,_seg *tmarray,thesparse;
+
+
+void Item_CountTiles(void)
+{
+ enum {TILE,TILEM};
+
+ unsigned i,j,dx,dy,max,exit=0,numt,numtm,oxbase,oybase,nsize,nmsize,redraw;
+ int which,dumrow,dumcol;
+ char pb,pf,pi;
+
+
+ CheckForMapSave();
+
+ oxbase=xbase;
+ oybase=ybase;
+
+ //
+ // COMPUTE SIZE OF EACH TILE
+ //
+ switch(videomode)
+ {
+  case CGA: nsize=16; nmsize=32; break;
+  case EGA1:
+  case EGA2: nsize=32; nmsize=40; break;
+  case VGA: nsize=64; nmsize=128;
+ }
+ nsize=nsize<<((tsize-1)<<1);
+ nmsize=nmsize<<((tsize-1)<<1);
+
+
+ MouseHide();
+ DrawDialog(&CMTd,1);
+ GetDialogXY(&CMTd,&dx,&dy);
+ sx=dx+4;
+ sy=dy+2;
+ print("Counting tiles in map:");
+ MouseShow();
+
+ MMAllocate((memptr *)&tarray,tilenum);
+ MMAllocate((memptr *)&tmarray,tilemnum);
+ _fmemset(tarray,0,tilenum);
+ _fmemset(tmarray,0,tilemnum);
+
+ //
+ // Now, load each map in & count the tiles
+ //
+ pb=MapFileHeader->maptype&BPLANE;
+ pf=MapFileHeader->maptype&FPLANE;
+ pi=MapFileHeader->maptype&IPLANE;
+
+ for (i=0;i<100;i++)
+   if (MapFileHeader->dataoffsets[i]>=0)
+     {
+      sx=dx+26;
+      sy=dy+2;
+      printint(i);
+
+      LoadMap(i);
+      max=mapwidth*mapheight;
+      for (j=0;j<max;j++)
+       {
+        if (pb)
+           tarray[MapBkgnd[j]]=1;
+        if (pf)
+           tmarray[MapFrgnd[j]]=1;
+        if (pi)
+           tmarray[MapInfoPl[j]]=1;
+       }
+     }
+
+ //
+ // Find a SPARSE tile
+ //
+ for (i=0;i<tilenum;i++)
+   if (XMSlookup[i]<0)
+     {
+      thesparse=i;
+      break;
+     }
+
+ //
+ // Count unused amount
+ //
+ numt=0;
+ for (i=0;i<tilenum;i++)
+   if (XMSlookup[i]>=0 && !tarray[i])
+     numt++;
+
+ numtm=0;
+ for (i=0;i<tilemnum;i++)
+   if (XMSlookup[i+tilenum]>=0 && !tmarray[i])
+     numtm++;
+
+
+ //
+ // INPUT FROM DIALOG
+ //
+ do
+ {
+  MouseHide();
+  xormask=0;
+  sx=dx+2;
+  sy=dy+17;
+  print("Unused TILES:");
+  printint(numt);
+  print(", unused MASKED:");
+  printint(numtm);
+  print(" ");
+  sx=dx+2;
+  sy=dy+18;
+  print("TILE Memory:");
+  printint((1023l+(long)numt*nsize)/1024);
+  print("K, MASKED Memory:");
+  printint((1023l+(long)numtm*nmsize)/1024);
+  print("K ");
+  MouseShow();
+  DrawUnused(0);
+  redraw=0;
+
+  do
+  {
+   if (!MouseButton())
+     which=CheckButtonsRet(&CMTd);
+   MouseCoords(&pixelx,&pixely);
+   pixelx/=8;
+   pixely/=8;
+   if (MouseButton() && pixelx>dx && pixelx<dx+37 && pixely>dy && pixely<dy+18)
+     {
+      int tile=((pixelx-dx-1)>>(tsize-1))+((pixely-dy-1)>>(tsize-1))*(9<<(3-tsize));
+
+      switch(whichscreen)
+      {
+       case TILES:
+        if (!tarray[tile+tilebase] && XMSlookup[tile+tilebase]>=0)
+          {
+           tarray[tile+tilebase]=1;
+           numt--;
+           redraw=1;
+          }
+        break;
+       case MASKED:
+        if (!tmarray[tile+tilembase] && XMSlookup[tilenum+tile+tilembase]>=0)
+          {
+           tmarray[tile+tilembase]=1;
+           numtm--;
+           redraw=1;
+          }
+      }
+      continue;
+     }
+
+   switch(which)
+   {
+    case 0:
+    case 1:
+      exit=1;
+      continue;
+
+    case 2:
+      MouseHide();
+      GetButtonXY(&CMTd,which-1,&sx,&sy);
+      print(CMTb[which-1].text);
+      whichscreen=TILES;
+      DrawUnused(0);
+      MouseShow();
+      continue;
+
+    case 3:
+      MouseHide();
+      GetButtonXY(&CMTd,which-1,&sx,&sy);
+      print(CMTb[which-1].text);
+      whichscreen=MASKED;
+      DrawUnused(0);
+      MouseShow();
+      continue;
+
+    //
+    // REBUILD GRAPHICS FILE & HEADER
+    //
+    case 4:
+      {
+       char newgfx[13]="NEW?GA.",
+           newhead[13]="NEW?HEAD.",
+           newhobj[13]="NEW?HEAD.",
+           oldhead[13]="?GAHEAD.";
+
+       char _seg *gfxhead;
+
+
+       newgfx[3]=format[0];
+       newhead[3]=format[0];
+       newhobj[3]=format[0];
+       oldhead[0]=format[0];
+
+
+       LoadIn(oldhead,(memptr *)&gfxhead);
+       for (i=0;i<tilenum;i++)
+       {
+       if (tarray[i])
+         *(gfxhead+i*3)=*(gfxhead+i*3);
+       }
+
+
+      }
+      continue;
+   }
+   //
+   // KEY CHECKS
+   //
+   if (keydown[1])
+     {
+      exit=1;
+      continue;
+     }
+   else
+   if (keydown[0x50])
+     DrawUnused(1);
+   else
+   if (keydown[0x48])
+     DrawUnused(-1);
+   else
+   if (keydown[0x49])
+     {
+      DrawUnused(-8);
+      while(keydown[0x49]);
+     }
+   else
+   if (keydown[0x51])
+     {
+      DrawUnused(8);
+      while(keydown[0x51]);
+     }
+
+  } while(!redraw && !exit);
+ } while(!exit);
+
+ RestoreBackground();
+ LoadMap(whichmap);
+ tilebase=tilembase=0;
+
+ xbase=oxbase;
+ ybase=oybase;
+}
+
+
+//
+// FILL THE "UNUSED TILES" SCREEN WITH TILES
+//
+void DrawUnused(int deltarow)
+{
+ char tile[32*32];
+ int numcols,numrows,i,j,top;
+
+ if (whichscreen==ICONS)
+   whichscreen=TILES;
+
+ MouseHide();
+
+ numrows=18-10*(tsize==2)-15*(tsize==3);
+ left=2;
+ top=2*8;
+ if (videomode==EGA2)
+   {
+    left=22;
+    top=20*8;
+   }
+
+ switch(tsize)
+ {
+  case 1: numcols=36; break;
+  case 2: numcols=18; break;
+  case 3: numcols=9;
+ }
+
+ if (whichscreen==TILES && tilebase+numrows*numcols>tilenum)
+   {
+    tilebase=0;
+    numrows=tilenum/numcols;
+   }
+
+ if (whichscreen==MASKED && tilembase+numrows*numcols>tilemnum)
+   {
+    tilembase=0;
+    numrows=tilemnum/numcols;
+   }
+
+ switch((deltarow<0?-1:deltarow>0?1:0))
+ {
+  case -1:
+   switch(whichscreen)
+   {
+    case TILES:
+      tilebase+=deltarow*numcols;
+      if (tilebase<0)
+       tilebase=0;
+      break;
+    case MASKED:
+      tilembase+=deltarow*numcols;
+      if (tilembase<0)
+       tilembase=0;
+   }
+   break;
+  case 1:
+   switch(whichscreen)
+   {
+    case TILES:
+      tilebase+=deltarow*numcols;
+      if (tilebase+numrows*numcols>tilenum)
+       tilebase=tilenum-numcols*numrows;
+      break;
+    case MASKED:
+      tilembase+=deltarow*numcols;
+      if (tilembase+numrows*numcols>tilemnum)
+       tilembase=tilemnum-numcols*numrows;
+   }
+ }
+
+ switch(whichscreen)
+ {
+  case TILES:
+    for(j=0;j<numrows;j++)
+      for(i=0;i<numcols;i++)
+      {
+       if (!tarray[tilebase+j*numcols+i] && XMSlookup[tilebase+j*numcols+i]>=0)
+        CombineTiles(tilebase+j*numcols+i,0,0,tsize);
+       else
+        CombineTiles(thesparse,0,0,tsize);
+       DrawTile(i*2+left,j*16+top,tsize);
+      }
+    break;
+
+  case MASKED:
+    for(j=0;j<numrows;j++)
+      for(i=0;i<numcols;i++)
+      {
+       if (!tmarray[tilembase+j*numcols+i] && XMSlookup[tilenum+tilembase+j*numcols+i]>=0)
+        CombineTiles(-BkgndColor,tilenum+tilembase+j*numcols+i,0,tsize);
+       else
+        CombineTiles(thesparse,0,0,tsize);
+       DrawTile(i*2+left,j*16+top,tsize);
+      }
+ }
+ MouseShow();
+}
diff --git a/16/ted5/TED5-3.C b/16/ted5/TED5-3.C
new file mode 100755 (executable)
index 0000000..f41aa23
--- /dev/null
@@ -0,0 +1,2033 @@
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// TED5-3
+//
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+#include "ted5.h"
+#pragma hdrstop
+
+int xms1;
+extern int tics;
+
+////////////////////////////////////////////////////
+//
+// MAP SCROLLING
+//
+////////////////////////////////////////////////////
+void CheckMapScroll(void)
+{
+ //
+ // LEFT
+ //
+ if (keydown[0x4b])    // left arrow
+   {
+    int i,j,imax,jmax,tilesmoved;
+
+    tics=biostime(0,0);
+
+    if (xbase)
+    {
+     EraseFloatPaste();
+
+     if (keydown[0x1d])        // CTRL-KEY
+     {
+      tilesmoved=screenw;
+      if (keydown[0x38]) // ALT-KEY
+      {
+       xbase=0;
+       DrawMap();
+       return;
+      }
+     }
+     else
+       switch(videomode)
+       {
+       case CGA:
+       case EGA1:
+       case VGA:
+         tilesmoved=1;
+         break;
+       case EGA2:
+         tilesmoved=2;
+       }
+
+     if (xbase<tilesmoved)
+       tilesmoved=xbase;
+     xbase-=tilesmoved;
+
+     MouseHide();
+     if (tilesmoved<screenw)
+       CopyScreen(0,8,infomaxw-(tilesmoved<<(tsize-1)),screenh<<(tsize+2),tilesmoved<<(tsize-1),8);
+
+     jmax=screenh;
+     if (jmax>mapheight)
+       jmax=mapheight;
+
+     for (i=0;i<tilesmoved;i++)
+       for (j=0;j<jmax;j++)
+       {
+       unsigned tilet,tilem,tilei,loc;
+
+       loc=(ybase+j)*mapwidth+xbase+i;
+
+       tilet=*(MapBkgnd+loc);
+       tilem=*(MapFrgnd+loc)+tilenum;
+       tilei=*(MapInfoPl+loc)+tilenum;
+
+       CombineTiles(tilet*viewton-BkgndColor*(!viewton),tilem*viewmon,tilei*viewion,tsize);
+       if (GridMode)
+         Overlay(tsize);
+       DrawTile(i<<(tsize-1),j*(4<<tsize)+8,tsize);
+       CheckInfoValues(i,j,tilei);
+       CheckSelectEdges(i+xbase,j+ybase,i,j);
+       }
+
+     px+=tilesmoved;
+     DrawFloatPaste();
+     MouseShow();
+     if (keydown[0x36] || keydown[0x1d])
+       while(keydown[0x4b]);
+    }
+   }
+ else
+ //
+ // RIGHT
+ //
+ if (keydown[0x4d])    // right arrow
+   {
+    int i,j,imax,jmax,tilesmoved;
+
+    tics=biostime(0,0);
+
+    if (xbase+screenw<mapwidth)
+    {
+     EraseFloatPaste();
+
+     if (keydown[0x1d])        // CTRL-KEY
+     {
+      tilesmoved=screenw;
+      if (keydown[0x38]) // ALT-KEY
+      {
+       xbase=mapwidth-screenw;
+       DrawMap();
+       return;
+      }
+     }
+     else
+       switch(videomode)
+       {
+       case CGA:
+       case EGA1:
+       case VGA:
+         tilesmoved=1;
+         break;
+       case EGA2:
+         tilesmoved=2;
+       }
+
+
+     if (xbase+screenw+tilesmoved>=mapwidth)
+       tilesmoved=mapwidth-screenw-xbase;
+     xbase+=tilesmoved;
+
+     MouseHide();
+     if (tilesmoved<screenw)
+       CopyScreen(tilesmoved<<(tsize-1),8,infomaxw-(tilesmoved<<(tsize-1)),screenh<<(tsize+2),0,8);
+
+     jmax=screenh;
+     if (jmax>mapheight)
+       jmax=mapheight;
+
+     for (i=0;i<tilesmoved;i++)
+       for (j=0;j<jmax;j++)
+       {
+       unsigned tilet,tilem,tilei,loc;
+
+       loc=(ybase+j)*mapwidth+xbase+screenw-tilesmoved+i;
+
+       tilet=*(MapBkgnd+loc);
+       tilem=*(MapFrgnd+loc)+tilenum;
+       tilei=*(MapInfoPl+loc)+tilenum;
+
+       CombineTiles(tilet*viewton-BkgndColor*(!viewton),tilem*viewmon,tilei*viewion,tsize);
+       if (GridMode)
+         Overlay(tsize);
+       DrawTile(infomaxw-((tilesmoved-i)<<(tsize-1)),j*(4<<tsize)+8,tsize);
+       CheckInfoValues(screenw-tilesmoved+i,j,tilei);
+       CheckSelectEdges(screenw-tilesmoved+i+xbase,j+ybase,i+screenw-tilesmoved,j);
+       }
+
+     px+=tilesmoved;
+     DrawFloatPaste();
+     MouseShow();
+     if (keydown[0x36] || keydown[0x1d])
+       while(keydown[0x4d]);
+    }
+   }
+
+ //
+ // UP
+ //
+ if (keydown[0x48])    // up arrow
+   {
+    int i,j,imax,jmax,tilesmoved;
+
+    tics=biostime(0,0);
+
+    if (ybase)
+    {
+     EraseFloatPaste();
+
+     if (keydown[0x1d])        // CTRL-KEY
+     {
+      tilesmoved=screenh;
+      if (keydown[0x38]) // ALT-KEY
+      {
+       ybase=0;
+       DrawMap();
+       return;
+      }
+     }
+     else
+       switch(videomode)
+       {
+       case CGA:
+       case EGA1:
+       case VGA:
+         tilesmoved=1;
+         break;
+       case EGA2:
+         tilesmoved=2;
+       }
+
+     if (ybase<tilesmoved)
+       tilesmoved=ybase;
+     ybase-=tilesmoved;
+
+     MouseHide();
+     if (tilesmoved<screenh)
+       CopyScreen(0,8,infomaxw,(screenh-tilesmoved)<<(tsize+2),0,8+(tilesmoved<<(tsize+2)));
+
+     imax=screenw;
+     if (imax>mapwidth)
+       imax=mapwidth;
+
+     for (j=0;j<tilesmoved;j++)
+       for (i=0;i<imax;i++)
+       {
+       unsigned tilet,tilem,tilei,loc;
+
+       loc=(ybase+j)*mapwidth+xbase+i;
+
+       tilet=*(MapBkgnd+loc);
+       tilem=*(MapFrgnd+loc)+tilenum;
+       tilei=*(MapInfoPl+loc)+tilenum;
+
+       CombineTiles(tilet*viewton-BkgndColor*(!viewton),tilem*viewmon,tilei*viewion,tsize);
+       if (GridMode)
+         Overlay(tsize);
+       DrawTile(i<<(tsize-1),8+(j<<(tsize+2)),tsize);
+       CheckInfoValues(i,j,tilei);
+       CheckSelectEdges(i+xbase,j+ybase,i,j);
+       }
+
+     py+=tilesmoved;
+     DrawFloatPaste();
+     MouseShow();
+     if (keydown[0x36] || keydown[0x1d])
+       while(keydown[0x48]);
+    }
+   }
+ else
+ //
+ // DOWN
+ //
+ if (keydown[0x50])    // down arrow
+   {
+    int i,j,imax,jmax,tilesmoved;
+
+    tics=biostime(0,0);
+
+    if (ybase+screenh<mapheight)
+    {
+     EraseFloatPaste();
+
+     if (keydown[0x1d])        // CTRL-KEY
+     {
+      tilesmoved=screenh;
+      if (keydown[0x38]) // ALT-KEY
+      {
+       ybase=mapheight-screenh;
+       DrawMap();
+       return;
+      }
+     }
+     else
+       switch(videomode)
+       {
+       case CGA:
+       case EGA1:
+       case VGA:
+         tilesmoved=1;
+         break;
+       case EGA2:
+         tilesmoved=2;
+       }
+
+     if (ybase+screenh+tilesmoved>=mapheight)
+       tilesmoved=mapheight-screenh-ybase;
+     ybase+=tilesmoved;
+
+     MouseHide();
+     if (tilesmoved<screenh)
+       CopyScreen(0,8+(tilesmoved<<(tsize+2)),infomaxw,(screenh-tilesmoved)<<(tsize+2),0,8);
+
+     imax=screenw;
+     if (imax>mapwidth)
+       imax=mapwidth;
+
+     for (j=0;j<tilesmoved;j++)
+       for (i=0;i<imax;i++)
+       {
+       unsigned tilet,tilem,tilei,loc;
+
+       loc=(ybase+j+screenh-tilesmoved)*mapwidth+xbase+i;
+
+       tilet=*(MapBkgnd+loc);
+       tilem=*(MapFrgnd+loc)+tilenum;
+       tilei=*(MapInfoPl+loc)+tilenum;
+
+       CombineTiles(tilet*viewton-BkgndColor*(!viewton),tilem*viewmon,tilei*viewion,tsize);
+       if (GridMode)
+         Overlay(tsize);
+       DrawTile(i<<(tsize-1),8+((screenh-tilesmoved+j)<<(tsize+2)),tsize);
+       CheckInfoValues(i,screenh-tilesmoved+j,tilei);
+       CheckSelectEdges(i+xbase,screenh-tilesmoved+j+ybase,i,j+screenh-tilesmoved);
+       }
+
+
+     py+=tilesmoved;
+     DrawFloatPaste();
+     MouseShow();
+     if (keydown[0x36] || keydown[0x1d])
+       while(keydown[0x50]);
+    }
+   }
+}
+
+
+////////////////////////////////////////////////////
+//
+// Copy a screen section to another, mode independent
+//
+////////////////////////////////////////////////////
+void CopyScreen(int srcx,int srcy,int width,int height,int destx,int desty)
+{
+ switch(videomode)
+ {
+  case CGA: CopyCGA(srcx,srcy,width,height,destx,desty); break;
+  case EGA1:
+  case EGA2:outport(SCindex,0x0f00 | SCmapmask);CopyEGA(srcx,srcy,width,height,destx,desty); break;
+  case VGA: CopyVGA(srcx,srcy,width,height,destx,desty);
+ }
+}
+
+
+////////////////////////////////////////////////////
+//
+// See if either of the Select edges are visible on the map
+// Draw them if so
+//
+////////////////////////////////////////////////////
+void CheckSelectEdges(int x,int y,int i,int j)
+{
+ int temp;
+
+ if (SelX2<SelX1)
+   {
+    temp=SelX1;
+    SelX1=SelX2;
+    SelX2=temp;
+   }
+ if (SelY2<SelY1)
+   {
+    temp=SelY1;
+    SelY1=SelY2;
+    SelY2=temp;
+   }
+
+ if (y==SelY2 && x==SelX2)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(i,j+1,8);
+            break;
+     case 2: drawchar(i*2+1,j*2+2,8);
+            drawchar(i*2+1,j*2+1,5);
+            drawchar(i*2,j*2+2,7);
+            break;
+     case 3: drawchar(i*4+3,j*4+4,8);
+
+            drawchar(i*4+3,j*4+3,5);
+            drawchar(i*4+3,j*4+2,5);
+            drawchar(i*4+3,j*4+1,5);
+
+            drawchar(i*4+2,j*4+4,7);
+            drawchar(i*4+1,j*4+4,7);
+            drawchar(i*4,j*4+4,7);
+            break;
+    }
+   }
+
+ if (y==SelY1 && x==SelX1)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(i,j+1,1);
+            break;
+     case 2: drawchar(i*2,j*2+1,1);
+            drawchar(i*2+1,j*2+1,2);
+            drawchar(i*2,j*2+2,4);
+            break;
+     case 3: drawchar(i*4,j*4+1,1);
+
+            drawchar(i*4+1,j*4+1,2);
+            drawchar(i*4+2,j*4+1,2);
+            drawchar(i*4+3,j*4+1,2);
+
+            drawchar(i*4,j*4+2,4);
+            drawchar(i*4,j*4+3,4);
+            drawchar(i*4,j*4+4,4);
+            break;
+    }
+   }
+
+ if (y==SelY2 && x==SelX1)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(i,j+1,6);
+            break;
+     case 2: drawchar(i*2  ,j*2+2,6);
+            drawchar(i*2+1,j*2+2,7);
+            drawchar(i*2  ,j*2+1,4);
+            break;
+     case 3: drawchar(i*4,j*4+4,6);
+
+            drawchar(i*4+1,j*4+4,7);
+            drawchar(i*4+2,j*4+4,7);
+            drawchar(i*4+3,j*4+4,7);
+
+            drawchar(i*4,j*4+1,4);
+            drawchar(i*4,j*4+2,4);
+            drawchar(i*4,j*4+3,4);
+            break;
+    }
+   }
+
+ if (y==SelY1 && x==SelX2)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(i,j+1,3);
+            break;
+     case 2: drawchar(i*2+1,j*2+1,3);
+            drawchar(i*2+1,j*2+2,5);
+            drawchar(i*2  ,j*2+1,2);
+            break;
+     case 3: drawchar(i*4+3,j*4+1,3);
+
+            drawchar(i*4+3,j*4+4,5);
+            drawchar(i*4+3,j*4+3,5);
+            drawchar(i*4+3,j*4+2,5);
+
+            drawchar(i*4+2,j*4+4,7);
+            drawchar(i*4+1,j*4+4,7);
+            drawchar(i*4,j*4+4,7);
+            break;
+    }
+   }
+
+ if (y==SelY1 && x>SelX1 && x<SelX2)
+   {
+    switch(tsize)
+    {
+     case 3: drawchar(i*4+2,j*4+1,2);
+            drawchar(i*4+3,j*4+1,2);
+            drawchar(i*4+1,j*4+1,2);
+            drawchar(i*4  ,j*4+1,2);
+            break;
+     case 2: drawchar(i*2+1,j*2+1,2);
+            drawchar(i*2  ,j*2+1,2);
+            break;
+     case 1: drawchar(i,j+1,2);
+            break;
+    }
+   }
+
+ if (y==SelY2 && x>SelX1 && x<SelX2)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(i,j+1,7);
+            break;
+     case 2: drawchar(i*2,j*2+2,7);
+            drawchar(i*2+1,j*2+2,7);
+            break;
+     case 3: drawchar(i*4  ,j*4+4,7);
+            drawchar(i*4+1,j*4+4,7);
+            drawchar(i*4+2,j*4+4,7);
+            drawchar(i*4+3,j*4+4,7);
+            break;
+    }
+   }
+
+ if (x==SelX1 && y>SelY1 && y<SelY2)
+   {
+    switch(tsize)
+    {
+     case 3: drawchar(i*4,j*4+3,4);
+            drawchar(i*4,j*4+4,4);
+            drawchar(i*4,j*4+2,4);
+            drawchar(i*4,j*4+1,4);
+            break;
+     case 2: drawchar(i*2,j*2+2,4);
+            drawchar(i*2,j*2+1,4);
+            break;
+     case 1: drawchar(i,j+1,4);
+            break;
+    }
+   }
+
+ if (x==SelX2 && y>SelY1 && y<SelY2)
+   {
+    switch(tsize)
+    {
+     case 1: drawchar(i,j+1,5);
+            break;
+     case 2: drawchar(i*2+1,j*2+1,5);
+            drawchar(i*2+1,j*2+2,5);
+            break;
+     case 3: drawchar(i*4+3,j*4+1,5);
+            drawchar(i*4+2,j*4+1,5);
+            drawchar(i*4+1,j*4+1,5);
+            drawchar(i*4  ,j*4+1,5);
+    }
+   }
+
+
+}
+
+////////////////////////////////////////////////////
+//
+// FLOATING PASTE REGION!
+//
+////////////////////////////////////////////////////
+void CheckFloatPaste(int mx,int my)
+{
+ int i,j,maxh,maxw;
+
+
+ if (SnapMode && PasteMode && (pixely>=8 || pixely<infoy*8))
+   {
+    mx=(mx/snapxsize)*snapxsize+snapx;
+    my=(my/snapysize)*snapysize+snapy;
+
+    if (mx<xbase)
+      mx+=snapxsize;
+    if (my<ybase)
+      my+=snapysize;
+    if (mx>=xbase+screenw)
+      mx-=snapxsize;
+    if (my>=ybase+screenh)
+      my-=snapysize;
+   }
+
+ if (!PasteMode || (px==mx && py==my) || (pixely<8 || pixely>infoy*8))
+   return;
+
+ if (mx>mapwidth || my>mapheight)
+   return;
+
+ MouseHide();
+ EraseFloatPaste();
+
+ //
+ // FLOAT IT...
+ //
+ px=mx;
+ py=my;
+
+ DrawFloatPaste();
+ MouseShow();
+}
+
+
+////////////////////////////////////////////////////
+//
+// DRAW FLOATING PASTE REGION
+//
+void DrawFloatPaste(void)
+{
+ int i,j,maxw,maxh;
+
+
+ if (px==-1 || py==-1 || !PasteMode)
+   return;
+ //
+ // NOW, DRAW IT IN A NEW LOCATION!
+ //
+ MouseHide();
+
+
+ maxh=TileCopy.h;
+ if (py+maxh>mapheight)
+   maxh=mapheight-py;
+ if (py+maxh-ybase>screenh)
+   maxh=screenh-(py-ybase);
+
+ maxw=TileCopy.w;
+ if (px+maxw>mapwidth)
+   maxw=mapwidth-px;
+ if (px+maxw-xbase>screenw)
+   maxw=screenw-(px-xbase);
+
+ switch(TileCopy.MapOrTileSelect)
+ {
+  case 0: // MAP PASTE DRAW
+    for (j=0;j<maxh;j++)
+      for (i=0;i<maxw;i++)
+       {
+        unsigned tilet,tilem,tilei,loc,loc1,oldt,oldm,oldi;
+        int theT,theM,theI;
+
+        loc=(TileCopy.y+j)*mapwidth+TileCopy.x+i;
+        loc1=(py+j)*mapwidth+px+i;
+
+        tilet=*(CutBkgnd+loc);
+        oldt=MapBkgnd[loc1];
+        tilem=*(CutFrgnd+loc)+tilenum;
+        if (tilem==tilenum)
+          tilem=0;
+        oldm=MapFrgnd[loc1]+tilenum;
+        tilei=*(CutInfoPl+loc)+tilenum;
+        if (tilei==tilenum)
+          tilei=0;
+        oldi=MapInfoPl[loc1]+tilenum;
+
+        theT=(TileCopy.PlanesCopied&BPLANE)?tilet:-BkgndColor;
+        if (theT==-BkgndColor && viewton)
+          theT=oldt;
+        theM=(TileCopy.PlanesCopied&FPLANE)?tilem:0;
+        if (!theM && viewmon && !(TileCopy.PlanesCopied&FPLANE && F3_flag))
+          theM=oldm;
+        theI=(TileCopy.PlanesCopied&IPLANE)?tilei:0;
+        if (!theI && viewion && !(TileCopy.PlanesCopied&IPLANE && F3_flag))
+          theI=oldi;
+
+        CombineTiles(theT,theM,theI,tsize);
+        if (GridMode)
+          Overlay(tsize);
+        DrawTile((px+i-xbase)<<(tsize-1),(py+j-ybase)*(4<<tsize)+8,tsize);
+       }
+    break;
+
+  case 1: // TILE PASTE DRAW
+    for (j=0;j<maxh;j++)
+      for (i=0;i<maxw;i++)
+       {
+        int val=(j+TileCopy.y)*selectcols+TileCopy.x+i;
+        unsigned tilem,tilei,loc;
+
+        loc=(py+j)*mapwidth+px+i;
+
+        tilem=MapFrgnd[loc]+tilenum;
+        tilei=MapInfoPl[loc]+tilenum;
+
+        if (XMSlookup[val]!=-1)
+          {
+           CombineTiles(viewton?val:-BkgndColor,
+                        viewmon?tilem:0,
+                        viewion?tilei:0,
+                        tsize);
+           if (GridMode)
+             Overlay(tsize);
+           DrawTile((px+i-xbase)<<(tsize-1),(py+j-ybase)*(4<<tsize)+8,tsize);
+          }
+       }
+    break;
+
+  case 2: // MASKED PASTE DRAW
+    for (j=0;j<maxh;j++)
+      for (i=0;i<maxw;i++)
+       {
+        int val=(j+TileCopy.y)*selectcols+TileCopy.x+i+tilenum+maxiconrows*selectcols;
+        unsigned tilet,tilei,loc;
+
+        loc=(py+j)*mapwidth+px+i;
+
+        tilet=MapBkgnd[loc];
+        tilei=MapInfoPl[loc]+tilenum;
+
+        if (XMSlookup[val]!=-1)
+          {
+           CombineTiles(viewton?tilet:-BkgndColor,
+                        viewmon?val:0,
+                        viewion?tilei:0,
+                        tsize);
+           if (GridMode)
+             Overlay(tsize);
+           DrawTile((px+i-xbase)<<(tsize-1),(py+j-ybase)*(4<<tsize)+8,tsize);
+          }
+       }
+ }
+
+ MouseShow();
+}
+
+////////////////////////////////////////////////////
+//
+// ERASE FLOATING PASTE REGION
+//
+void EraseFloatPaste(void)
+{
+ int maxh,maxw,i,j;
+
+
+ if (px==-1 || py==-1 || !PasteMode)
+   return;
+
+ //
+ // ERASE THE FLOATING REGION
+ // (PRECLIPPING REGION)
+ //
+ MouseHide();
+
+ maxh=TileCopy.h;
+ if (py+maxh>mapheight)
+   maxh=mapheight-py;
+ if (py+maxh-ybase>screenh)
+   maxh=screenh-(py-ybase);
+
+ maxw=TileCopy.w;
+ if (px+maxw>mapwidth)
+   maxw=mapwidth-px;
+ if (px+maxw-xbase>screenw)
+   maxw=screenw-(px-xbase);
+
+ for (j=0;j<maxh;j++)
+   for (i=0;i<maxw;i++)
+     {
+      unsigned tile_t,tile_m,tile_i,loc;
+
+      loc=(py+j)*mapwidth+px+i;
+
+      tile_t=*(MapBkgnd+loc);
+      tile_m=*(MapFrgnd+loc)+tilenum;
+      tile_i=*(MapInfoPl+loc)+tilenum;
+
+      CombineTiles(viewton?tile_t:-BkgndColor,viewmon?tile_m:0,viewion?tile_i:0,tsize);
+      if (GridMode)
+       Overlay(tsize);
+      DrawTile((px+i-xbase)<<(tsize-1),(py+j-ybase)*(4<<tsize)+8,tsize);
+     }
+
+ MouseShow();
+}
+
+
+////////////////////////////////////////////////////
+//
+// SAVE CUT BUFFERS TO XMS BEFORE MAP LOAD/CREATE
+//
+////////////////////////////////////////////////////
+void SaveCutBuffers(void)
+{
+ long size,off;
+ int j;
+
+ //
+ // IS SOMETHING IN THE COPY BUFFER?
+ // IF SO, PRESERVE AS MUCH AS POSSIBLE
+ //
+ if (!TileCopy.MapOrTileSelect)
+   {
+    size=(2L*TileCopy.w*TileCopy.h)*(((TileCopy.PlanesCopied&BPLANE)>0)+
+      ((TileCopy.PlanesCopied&FPLANE)>0)+((TileCopy.PlanesCopied&IPLANE)>0));
+
+    xms1=XMSAllocate(size);
+
+    off=0;
+    if (TileCopy.PlanesCopied&BPLANE)
+      for (j=0;j<TileCopy.h;j++)
+       {
+        XMSmove(0,(long)MK_FP(CutBkgnd,2L*((TileCopy.y+j)*mapwidth)+2L*TileCopy.x),
+          xms1,off,2L*TileCopy.w);
+        off+=2L*TileCopy.w;
+       }
+
+    if (TileCopy.PlanesCopied&FPLANE)
+      for (j=0;j<TileCopy.h;j++)
+       {
+        XMSmove(0,(long)MK_FP(CutFrgnd,2L*((TileCopy.y+j)*mapwidth)+2L*TileCopy.x),
+          xms1,off,2L*TileCopy.w);
+        off+=2L*TileCopy.w;
+       }
+
+    if (TileCopy.PlanesCopied&IPLANE)
+      for (j=0;j<TileCopy.h;j++)
+       {
+        XMSmove(0,(long)MK_FP(CutInfoPl,2L*((TileCopy.y+j)*mapwidth)+2L*TileCopy.x),
+          xms1,off,2L*TileCopy.w);
+        off+=2L*TileCopy.w;
+       }
+   }
+}
+
+
+////////////////////////////////////////////////////
+//
+// RESTORE CUT BUFFERS FROM XMS AFTER MAP LOAD/CREATE
+//
+////////////////////////////////////////////////////
+void RestoreCutBuffers(void)
+{
+ //
+ // COPY BACK STUFF IN XMS
+ //
+ if (!TileCopy.MapOrTileSelect)
+   {
+    long ToOff,off;
+    int newwidth,newheight,j;
+
+    newwidth=(TileCopy.w>mapwidth)?mapwidth:TileCopy.w;
+    newheight=(TileCopy.h>mapheight)?mapheight:TileCopy.h;
+
+    ToOff=off=0;
+
+    if (TileCopy.PlanesCopied&BPLANE)
+      for (j=0;j<newheight;j++)
+       {
+        XMSmove(xms1,off,0,(long)MK_FP(CutBkgnd,2L*(j*mapwidth)),2L*newwidth);
+        ToOff+=2L*newwidth;
+        off+=2L*TileCopy.w;
+       }
+
+    if (TileCopy.PlanesCopied&FPLANE)
+      for (j=0;j<newheight;j++)
+       {
+        XMSmove(xms1,off,0,(long)MK_FP(CutFrgnd,2L*(j*mapwidth)),2L*newwidth);
+        ToOff+=2L*newwidth;
+        off+=2L*TileCopy.w;
+       }
+
+    if (TileCopy.PlanesCopied&IPLANE)
+      for (j=0;j<newheight;j++)
+       {
+        XMSmove(xms1,off,0,(long)MK_FP(CutInfoPl,2L*(j*mapwidth)),2L*newwidth);
+        ToOff+=2L*newwidth;
+        off+=2L*TileCopy.w;
+       }
+
+    TileCopy.x=TileCopy.y=0;
+    TileCopy.w=newwidth;
+    TileCopy.h=newheight;
+
+    XMSFreeMem(xms1);  // RELEASE THE MEMORY
+   }
+}
+
+////////////////////////////////////////////////////
+//
+// SEE IF THERE'S AN INFO VALUES AT THE CURRENT POSITION
+// THAT NEEDS TO BE PRINTED
+//
+////////////////////////////////////////////////////
+void CheckInfoValues(int i,int j,int tilei)
+{
+ sx=i<<(tsize-1);
+ sy=(j<<(tsize-1))+1;
+
+ if (TsearchMode)
+   {
+    unsigned loc,temp,p=0;
+
+    loc=(j+ybase)*mapwidth+i+xbase;
+
+    if (planeton)
+      {
+       if (MapBkgnd[loc]==whicht)
+        {
+         temp=whicht;
+         p=1;
+        }
+      }
+    else
+    if (planemon)
+      {
+       if (MapFrgnd[loc]==whichtm-tilenum)
+        {
+         temp=whichtm-tilenum;
+         p=1;
+        }
+      }
+    else
+    if (planeion)
+      if ((unsigned)MapInfoPl[loc]==whichi-tilenum)
+       {
+        temp=whichi-tilenum;
+        p=1;
+       }
+
+    if (p)
+      switch(tsize)
+      {
+       case 1:
+        print("#");
+        break;
+       case 2:
+        printhexb(temp>>8);
+        sx-=2;
+        sy++;
+        printhexb(temp&0xff);
+        break;
+       case 3: printhex(temp);
+      }
+   }
+ else
+ if (viewion && tilei>lasticon)
+   {
+    switch(tsize)
+    {
+     case 1:
+       print("#");
+       break;
+     case 2:
+       printhexb(tilei-tilenum>>8);
+       sx-=2;
+       sy++;
+       printhexb(tilei-tilenum&0xff);
+       break;
+     case 3: printhex(tilei-tilenum);
+    }
+   }
+}
+
+////////////////////////////////////////////////////
+//
+// Item - Edit Map Edges
+//
+////////////////////////////////////////////////////
+btype MapEdgeB[]={{"\xb",7,3,1},
+                 {"\xc",7,7,1},
+                 {"\xe",4,5,1},
+                 {"\x1f",10,5,1},
+                 {" Exit ",5,16,2}};
+DialogDef MapEdgeD={"  PICK MAP EDGE\n"
+                   "    TO CHANGE",
+                   16,18,5,&MapEdgeB[0],NULL};
+
+void Item_EditMapEdges(void)
+{
+ int which,val,newwidth,newheight,b,f,i,
+       _seg *tempB,_seg *tempF,_seg *tempI;
+ unsigned dx,dy,obx,oby,k,j,modified=0;
+ long size;
+
+ b=MapFileHeader->maptype&BPLANE;
+ f=MapFileHeader->maptype&FPLANE;
+ i=MapFileHeader->maptype&IPLANE;
+
+ DrawDialog(&MapEdgeD,1);
+ GetDialogXY(&MapEdgeD,&dx,&dy);
+ do
+ {
+  MouseHide();
+  sx=dx+2;
+  sy=dy+14;
+  print("W:");
+  printint(MapHeader.width);
+  print(", H:");
+  printint(MapHeader.height);
+  print("   ");
+  MouseShow();
+
+
+  which=CheckButtons(&MapEdgeD);
+  GetButtonXY(&MapEdgeD,which-1,&obx,&oby);
+  MouseHide();
+  if (which>=1 && which<=4)
+    {
+     // DRAW INPUT BAR
+     sx=dx;
+     sy=dy+9;
+     print("+ or - value");
+     DrawBorder(dx,dy+10,15,2,1);
+
+     // INPUT VALUE
+     sx=dx+1;
+     sy=dy+11;
+     val=inputint(9);
+
+     // ERASE THE ARROW AND INPUT BAR
+     sx=obx;
+     sy=oby;
+     print(MapEdgeB[which-1].text);
+     bar(dx,dy+9,dx+15,dy+12,' ');
+
+     // CHECK FOR ESC
+     if (val==(int)ESCOUT)
+       which=6;
+    }
+
+  MouseShow();
+  switch(which)
+  {
+   //
+   // ADD OR DELETE FROM TOP
+   //
+   case 1:
+     newheight=mapheight+val;
+     size=2L*newheight*mapwidth;
+     if (size<=0 || size>0x10000L)
+       {
+       RestoreBackground();
+       ErrDialog("Invalid Map height!"," OK ");
+       return;
+       }
+
+     // FREE UP SOME MEMORY!
+     SaveCutBuffers();
+     RemoveUndoBuffers();
+
+     if (b)
+       {
+       MMFreePtr((memptr *)&CutBkgnd);
+       MMAllocate((memptr *)&tempB,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&CutFrgnd);
+       MMAllocate((memptr *)&tempF,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&CutInfoPl);
+       MMAllocate((memptr *)&tempI,size);
+       }
+
+     if (val<0)
+       {
+       // COPY MAP PLANES INTO TEMP MEMORY (CLIPPED, HERE)
+       for (j=abs(val);j<mapheight;j++)
+         for (k=0;k<mapwidth;k++)
+           {
+            if (b)
+              tempB[(j+val)*mapwidth+k]=MapBkgnd[j*mapwidth+k];
+            if (f)
+              tempF[(j+val)*mapwidth+k]=MapFrgnd[j*mapwidth+k];
+            if (i)
+              tempI[(j+val)*mapwidth+k]=MapInfoPl[j*mapwidth+k];
+           }
+       }
+     else
+       {
+       for (j=0;j<mapheight+val;j++)
+         for (k=0;k<mapwidth;k++)
+           {
+            if (j<abs(val))
+              {
+               if (b)
+                 tempB[j*mapwidth+k]=whicht;
+               if (f)
+                 tempF[j*mapwidth+k]=whichtm-tilenum;
+               if (i)
+                 tempI[j*mapwidth+k]=whichi-tilenum;
+              }
+            else
+              {
+               if (b)
+                 tempB[j*mapwidth+k]=MapBkgnd[(j-val)*mapwidth+k];
+               if (f)
+                 tempF[j*mapwidth+k]=MapFrgnd[(j-val)*mapwidth+k];
+               if (i)
+                 tempI[j*mapwidth+k]=MapInfoPl[(j-val)*mapwidth+k];
+              }
+           }
+       }
+
+     // DEALLOCATE & REALLOCATE THE MAP BUFFERS, RESIZED
+     if (b)
+       {
+       MMFreePtr((memptr *)&MapBkgnd);
+       MMAllocate((memptr *)&MapBkgnd,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&MapFrgnd);
+       MMAllocate((memptr *)&MapFrgnd,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&MapInfoPl);
+       MMAllocate((memptr *)&MapInfoPl,size);
+       }
+
+     // COPY THE REGION BACK IN...
+     for (j=0;j<newheight;j++)
+       for (k=0;k<mapwidth;k++)
+        {
+         if (b)
+           MapBkgnd[j*mapwidth+k]=tempB[j*mapwidth+k];
+         if (f)
+           MapFrgnd[j*mapwidth+k]=tempF[j*mapwidth+k];
+         if (i)
+           MapInfoPl[j*mapwidth+k]=tempI[j*mapwidth+k];
+        }
+
+     // TOAST THE 'TEMP' BUFFERS & REALLOCATE THE 'CUT' BUFFERS
+     if (b)
+       {
+       MMFreePtr((memptr *)&tempB);
+       MMAllocate((memptr *)&CutBkgnd,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&tempF);
+       MMAllocate((memptr *)&CutFrgnd,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&tempI);
+       MMAllocate((memptr *)&CutInfoPl,size);
+       }
+
+     mapheight=newheight;
+     MapHeader.height=newheight;
+     modified=DirtyFlag=1;
+     AllocateUndoBuffers();
+     UndoRegion.x=-1;
+     SaveUndo(0,0,mapwidth,mapheight);
+     RestoreCutBuffers();
+
+     break;
+
+   //
+   // ADD OR DELETE FROM BOTTOM
+   //
+   case 2:
+     newheight=mapheight+val;
+     size=2L*newheight*mapwidth;
+     if (size<=0 || size>0x10000L)
+       {
+       RestoreBackground();
+       ErrDialog("Invalid Map height!"," OK ");
+       return;
+       }
+
+     // FREE UP SOME MEMORY!
+     SaveCutBuffers();
+     RemoveUndoBuffers();
+     if (b)
+       {
+       MMFreePtr((memptr *)&CutBkgnd);
+       MMAllocate((memptr *)&tempB,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&CutFrgnd);
+       MMAllocate((memptr *)&tempF,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&CutInfoPl);
+       MMAllocate((memptr *)&tempI,size);
+       }
+
+     if (val<0)
+       {
+       // COPY MAP PLANES INTO TEMP MEMORY (CLIPPED, HERE)
+       for (j=0;j<mapheight+val;j++)
+         for (k=0;k<mapwidth;k++)
+           {
+            if (b)
+              tempB[j*mapwidth+k]=MapBkgnd[j*mapwidth+k];
+            if (f)
+              tempF[j*mapwidth+k]=MapFrgnd[j*mapwidth+k];
+            if (i)
+              tempI[j*mapwidth+k]=MapInfoPl[j*mapwidth+k];
+           }
+       }
+     else
+       {
+       for (j=0;j<mapheight+val;j++)
+         for (k=0;k<mapwidth;k++)
+           {
+            if (j>=mapheight)
+              {
+               if (b)
+                 tempB[j*mapwidth+k]=whicht;
+               if (f)
+                 tempF[j*mapwidth+k]=whichtm-tilenum;
+               if (i)
+                 tempI[j*mapwidth+k]=whichi-tilenum;
+              }
+            else
+              {
+               if (b)
+                 tempB[j*mapwidth+k]=MapBkgnd[j*mapwidth+k];
+               if (f)
+                 tempF[j*mapwidth+k]=MapFrgnd[j*mapwidth+k];
+               if (i)
+                 tempI[j*mapwidth+k]=MapInfoPl[j*mapwidth+k];
+              }
+           }
+       }
+
+     // DEALLOCATE & REALLOCATE THE MAP BUFFERS, RESIZED
+     if (b)
+       {
+       MMFreePtr((memptr *)&MapBkgnd);
+       MMAllocate((memptr *)&MapBkgnd,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&MapFrgnd);
+       MMAllocate((memptr *)&MapFrgnd,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&MapInfoPl);
+       MMAllocate((memptr *)&MapInfoPl,size);
+       }
+
+     // COPY THE REGION BACK IN...
+     for (j=0;j<newheight;j++)
+       for (k=0;k<mapwidth;k++)
+        {
+         if (b)
+           MapBkgnd[j*mapwidth+k]=tempB[j*mapwidth+k];
+         if (f)
+           MapFrgnd[j*mapwidth+k]=tempF[j*mapwidth+k];
+         if (i)
+           MapInfoPl[j*mapwidth+k]=tempI[j*mapwidth+k];
+        }
+
+     // TOAST THE 'TEMP' BUFFERS & REALLOCATE THE 'CUT' BUFFERS
+     if (b)
+       {
+       MMFreePtr((memptr *)&tempB);
+       MMAllocate((memptr *)&CutBkgnd,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&tempF);
+       MMAllocate((memptr *)&CutFrgnd,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&tempI);
+       MMAllocate((memptr *)&CutInfoPl,size);
+       }
+
+     mapheight=newheight;
+     MapHeader.height=newheight;
+     modified=DirtyFlag=1;
+     AllocateUndoBuffers();
+     UndoRegion.x=-1;
+     SaveUndo(0,0,mapwidth,mapheight);
+     RestoreCutBuffers();
+
+     break;
+
+   //
+   // ADD OR DELETE FROM LEFTEDGE
+   //
+   case 3:
+     newwidth=mapwidth+val;
+     size=2L*newwidth*mapheight;
+     if (size<=0 || size>0x10000L)
+       {
+       RestoreBackground();
+       ErrDialog("Invalid Map width!"," OK ");
+       return;
+       }
+
+     // FREE UP SOME MEMORY!
+     SaveCutBuffers();
+     RemoveUndoBuffers();
+     if (b)
+       {
+       MMFreePtr((memptr *)&CutBkgnd);
+       MMAllocate((memptr *)&tempB,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&CutFrgnd);
+       MMAllocate((memptr *)&tempF,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&CutInfoPl);
+       MMAllocate((memptr *)&tempI,size);
+       }
+
+     if (val<0)
+       {
+       // COPY MAP PLANES INTO TEMP MEMORY (CLIPPED, HERE)
+       for (j=0;j<mapheight;j++)
+         for (k=abs(val);k<mapwidth;k++)
+           {
+            if (b)
+              tempB[j*newwidth+k+val]=MapBkgnd[j*mapwidth+k];
+            if (f)
+              tempF[j*newwidth+k+val]=MapFrgnd[j*mapwidth+k];
+            if (i)
+              tempI[j*newwidth+k+val]=MapInfoPl[j*mapwidth+k];
+           }
+       }
+     else
+       {
+       for (j=0;j<mapheight;j++)
+         for (k=0;k<mapwidth+val;k++)
+           {
+            if (k<abs(val))
+              {
+               if (b)
+                 tempB[j*newwidth+k]=whicht;
+               if (f)
+                 tempF[j*newwidth+k]=whichtm-tilenum;
+               if (i)
+                 tempI[j*newwidth+k]=whichi-tilenum;
+              }
+            else
+              {
+               if (b)
+                 tempB[j*newwidth+k]=MapBkgnd[j*mapwidth+k-val];
+               if (f)
+                 tempF[j*newwidth+k]=MapFrgnd[j*mapwidth+k-val];
+               if (i)
+                 tempI[j*newwidth+k]=MapInfoPl[j*mapwidth+k-val];
+              }
+           }
+       }
+
+     // DEALLOCATE & REALLOCATE THE MAP BUFFERS, RESIZED
+     if (b)
+       {
+       MMFreePtr((memptr *)&MapBkgnd);
+       MMAllocate((memptr *)&MapBkgnd,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&MapFrgnd);
+       MMAllocate((memptr *)&MapFrgnd,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&MapInfoPl);
+       MMAllocate((memptr *)&MapInfoPl,size);
+       }
+
+     // COPY THE REGION BACK IN...
+     for (j=0;j<mapheight;j++)
+       for (k=0;k<newwidth;k++)
+        {
+         if (b)
+           MapBkgnd[j*newwidth+k]=tempB[j*newwidth+k];
+         if (f)
+           MapFrgnd[j*newwidth+k]=tempF[j*newwidth+k];
+         if (i)
+           MapInfoPl[j*newwidth+k]=tempI[j*newwidth+k];
+        }
+
+     // TOAST THE 'TEMP' BUFFERS & REALLOCATE THE 'CUT' BUFFERS
+     if (b)
+       {
+       MMFreePtr((memptr *)&tempB);
+       MMAllocate((memptr *)&CutBkgnd,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&tempF);
+       MMAllocate((memptr *)&CutFrgnd,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&tempI);
+       MMAllocate((memptr *)&CutInfoPl,size);
+       }
+
+     mapwidth=newwidth;
+     MapHeader.width=newwidth;
+     modified=DirtyFlag=1;
+     AllocateUndoBuffers();
+     UndoRegion.x=-1;
+     SaveUndo(0,0,mapwidth,mapheight);
+     RestoreCutBuffers();
+
+     break;
+
+   //
+   // ADD OR DELETE FROM RIGHTEDGE
+   //
+   case 4:
+     newwidth=mapwidth+val;
+     size=2L*newwidth*mapheight;
+     if (size<=0 || size>0x10000L)
+       {
+       RestoreBackground();
+       ErrDialog("Invalid Map width!"," OK ");
+       return;
+       }
+
+     // FREE UP SOME MEMORY!
+     SaveCutBuffers();
+     RemoveUndoBuffers();
+     if (b)
+       {
+       MMFreePtr((memptr *)&CutBkgnd);
+       MMAllocate((memptr *)&tempB,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&CutFrgnd);
+       MMAllocate((memptr *)&tempF,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&CutInfoPl);
+       MMAllocate((memptr *)&tempI,size);
+       }
+
+     if (val<0)
+       {
+       // COPY MAP PLANES INTO TEMP MEMORY (CLIPPED, HERE)
+       for (j=0;j<mapheight;j++)
+         for (k=0;k<mapwidth+val;k++)
+           {
+            if (b)
+              tempB[j*newwidth+k]=MapBkgnd[j*mapwidth+k];
+            if (f)
+              tempF[j*newwidth+k]=MapFrgnd[j*mapwidth+k];
+            if (i)
+              tempI[j*newwidth+k]=MapInfoPl[j*mapwidth+k];
+           }
+       }
+     else
+       {
+       for (j=0;j<mapheight;j++)
+         for (k=0;k<mapwidth+val;k++)
+           {
+            if (k>=mapwidth)
+              {
+               if (b)
+                 tempB[j*newwidth+k]=whicht;
+               if (f)
+                 tempF[j*newwidth+k]=whichtm-tilenum;
+               if (i)
+                 tempI[j*newwidth+k]=whichi-tilenum;
+              }
+            else
+              {
+               if (b)
+                 tempB[j*newwidth+k]=MapBkgnd[j*mapwidth+k];
+               if (f)
+                 tempF[j*newwidth+k]=MapFrgnd[j*mapwidth+k];
+               if (i)
+                 tempI[j*newwidth+k]=MapInfoPl[j*mapwidth+k];
+              }
+           }
+       }
+
+     // DEALLOCATE & REALLOCATE THE MAP BUFFERS, RESIZED
+     if (b)
+       {
+       MMFreePtr((memptr *)&MapBkgnd);
+       MMAllocate((memptr *)&MapBkgnd,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&MapFrgnd);
+       MMAllocate((memptr *)&MapFrgnd,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&MapInfoPl);
+       MMAllocate((memptr *)&MapInfoPl,size);
+       }
+
+     // COPY THE REGION BACK IN...
+     for (j=0;j<mapheight;j++)
+       for (k=0;k<newwidth;k++)
+        {
+         if (b)
+           MapBkgnd[j*newwidth+k]=tempB[j*newwidth+k];
+         if (f)
+           MapFrgnd[j*newwidth+k]=tempF[j*newwidth+k];
+         if (i)
+           MapInfoPl[j*newwidth+k]=tempI[j*newwidth+k];
+        }
+
+     // TOAST THE 'TEMP' BUFFERS & REALLOCATE THE 'CUT' BUFFERS
+     if (b)
+       {
+       MMFreePtr((memptr *)&tempB);
+       MMAllocate((memptr *)&CutBkgnd,size);
+       }
+     if (f)
+       {
+       MMFreePtr((memptr *)&tempF);
+       MMAllocate((memptr *)&CutFrgnd,size);
+       }
+     if (i)
+       {
+       MMFreePtr((memptr *)&tempI);
+       MMAllocate((memptr *)&CutInfoPl,size);
+       }
+
+     mapwidth=newwidth;
+     MapHeader.width=newwidth;
+     modified=DirtyFlag=1;
+     AllocateUndoBuffers();
+     UndoRegion.x=-1;
+     SaveUndo(0,0,mapwidth,mapheight);
+     RestoreCutBuffers();
+     break;
+  }
+ } while(which && which!=5);
+ RestoreBackground();
+ if (modified)
+   {
+    xbase=ybase=0;
+    MouseHide();
+    InitDesktop(TED5MenuBar,0);
+    DrawInfoBar();
+    DrawMap();
+    MouseShow();
+   }
+}
+
+
+////////////////////////////////////////////////////
+//
+// Display amount of memory available
+//
+////////////////////////////////////////////////////
+btype     ShowMemb={" OK ",6,11,2};
+DialogDef ShowMemd={"Extended Memory \n"
+                   "Available:\n\n"
+                   "Main Memory\n"
+                   "Available:\n\n"
+                   "In Extended Mem\n"
+                   "----------------\n"
+                   "CGA:     EGA:\n"
+                   "VGA:    Maps:"
+                   ,16,13,1,&ShowMemb,PrintMem};
+
+void Item_PrintMem(void)
+{
+ DoDialog(&ShowMemd);
+}
+
+void PrintMem(int x,int y)
+{
+ long total;
+ char memstring[10];
+
+ sx=x+10;
+ sy=y+1;
+ itoa(XMSTotalFree(),memstring,10);
+ strcat(memstring,"K");
+ print(memstring);
+
+ sx=x+10;
+ sy=y+4;
+ total=(MMTotalFree()*16L)/1024;
+ ltoa(total,memstring,10);
+ strcat(memstring,"K");
+ print(memstring);
+
+ sx=x+4;
+ sy=y+8;
+ if (!CgaXMS)
+   print("No");
+ else
+   print("Yes");
+
+ sx=x+13;
+ sy=y+8;
+ if (!EgaXMS)
+   print("No");
+ else
+   print("Yes");
+
+ sx=x+4;
+ sy=y+9;
+ if (!VgaXMS)
+   print("No");
+ else
+   print("Yes");
+
+
+ sx=x+13;
+ sy=y+9;
+ if (!XMSmaps)
+   print("No");
+ else
+   print("Yes");
+}
+
+
+////////////////////////////////////////////////////
+//
+// CARMACIZE THE MAP FILE!
+//
+////////////////////////////////////////////////////
+void Item_Huffman(void)
+{
+ OutputHeadStr NewFileHeader;
+ char huffname[14]="GAMEMAPS.",huffheadname[14]="MAPSHEAD.",tempstr[200],
+       mapidstr[8]=IDSTRING,objname[14],dictname[14],tempname[14];
+ int dx,dy,i,oxb,oyb,maplengths[100];
+ MapHeaderStr TempHeader;
+ memptr block,block1,block2;
+ long size,fsize,nsize;
+
+
+ Item_SaveMap();
+
+ strcat(huffname,ext);
+ strcat(huffheadname,ext);
+ strcpy(tempstr,"This will take a while.\n");
+ strcat(tempstr,huffname);
+ strcat(tempstr,". [               ]");
+ ErrDialog(tempstr,"");
+ dy=sy;
+ dx=sx-16;
+
+ oxb=xbase;
+ oyb=ybase;
+ //
+ // Free up memory
+ //
+ if (MapBkgnd)
+   {
+    MMFreePtr((memptr *)&MapBkgnd);
+    MMFreePtr((memptr *)&CutBkgnd);
+   }
+ if (MapFrgnd)
+   {
+    MMFreePtr((memptr *)&MapFrgnd);
+    MMFreePtr((memptr *)&CutFrgnd);
+   }
+ if (MapInfoPl)
+   {
+    MMFreePtr((memptr *)&MapInfoPl);
+    MMFreePtr((memptr *)&CutInfoPl);
+   }
+
+ //
+ // Now, time to Carmacize all the maps
+ //
+ sx=dx;
+ sy=dy;
+ print("Carmacizing");
+ dx=sx+1;
+
+ fsize=0;
+ SaveFile(huffname,(char huge *)&mapidstr,fsize,strlen(mapidstr));
+ fsize+=strlen(mapidstr);
+
+ memset(&maplengths,0,sizeof(long)*100);
+ memset(&NewFileHeader,0,sizeof(OutputHeadStr));
+ MMAllocate(&block1,sizeof(MapHeaderStr));
+ for (i=0;i<100;i++)
+   if (MapFileHeader->dataoffsets[i]!=-1)
+     {
+      //
+      // LOAD MAP HEADER
+      //
+      sx=dx;
+      printint(i);
+      LoadFile(mapname,(char huge *)&TempHeader,MapFileHeader->dataoffsets[i],sizeof(MapHeaderStr));
+
+      //
+      // COMPRESS EACH MAP PLANE
+      //
+      #pragma warn -sus
+      if (MapFileHeader->maptype&BPLANE)
+       {
+        size=TempHeader.mapbkgndlen;
+        MMAllocate(&block,size);
+        MMAllocate(&block2,size);
+        LoadFile(mapname,block,TempHeader.mapbkgndpl,size);
+        *(int _seg *)block2=TempHeader.mapbkgndlen;
+        nsize=CarmackCompress((unsigned  char huge *)block,size,(unsigned char huge *)block2+2)+2;
+        maplengths[i]+=nsize;
+        if (nsize==2)
+        {
+         RestoreBackground();
+         MMFreePtr(&block2);
+         MMFreePtr(&block);
+         MMFreePtr(&block1);
+         LoadMap(whichmap);
+         xbase=oxb;
+         ybase=oyb;
+         ErrDialog("ESC out of this infernal thing!"," YES! ");
+         return;
+        }
+
+        SaveFile(huffname,block2,fsize,nsize);
+        TempHeader.mapbkgndpl=fsize;
+        TempHeader.mapbkgndlen=nsize;
+        MMFreePtr(&block2);
+        MMFreePtr(&block);
+        fsize+=nsize;
+       }
+      if (MapFileHeader->maptype&FPLANE)
+       {
+        size=TempHeader.mapfrgndlen;
+        MMAllocate(&block,size);
+        MMAllocate(&block2,size);
+        LoadFile(mapname,block,TempHeader.mapfrgndpl,size);
+        *(int _seg *)block2=TempHeader.mapfrgndlen;
+        nsize=CarmackCompress((unsigned  char huge *)block,size,(unsigned  char huge *)block2+2)+2;
+        maplengths[i]+=nsize;
+        if (nsize==2)
+        {
+         RestoreBackground();
+         MMFreePtr(&block2);
+         MMFreePtr(&block);
+         MMFreePtr(&block1);
+         LoadMap(whichmap);
+         xbase=oxb;
+         ybase=oyb;
+         ErrDialog("ESC out of this infernal thing!"," YES! ");
+         return;
+        }
+
+        SaveFile(huffname,block2,fsize,nsize);
+        TempHeader.mapfrgndpl=fsize;
+        TempHeader.mapfrgndlen=nsize;
+        MMFreePtr(&block2);
+        MMFreePtr(&block);
+        fsize+=nsize;
+       }
+      if (MapFileHeader->maptype&IPLANE)
+       {
+        size=TempHeader.mapinfolen;
+        MMAllocate(&block,size);
+        MMAllocate(&block2,size);
+        LoadFile(mapname,block,TempHeader.mapinfopl,size);
+        *(int _seg *)block2=TempHeader.mapinfolen;
+        nsize=CarmackCompress((unsigned  char huge *)block,size,(unsigned  char huge *)block2+2)+2;
+        maplengths[i]+=nsize;
+        if (nsize==2)
+        {
+         RestoreBackground();
+         MMFreePtr(&block2);
+         MMFreePtr(&block);
+         MMFreePtr(&block1);
+         LoadMap(whichmap);
+         xbase=oxb;
+         ybase=oyb;
+         ErrDialog("ESC out of this infernal thing!"," YES! ");
+         return;
+        }
+
+        SaveFile(huffname,block2,fsize,nsize);
+        TempHeader.mapinfopl=fsize;
+        TempHeader.mapinfolen=nsize;
+        MMFreePtr(&block2);
+        MMFreePtr(&block);
+        fsize+=nsize;
+       }
+      #pragma warn +sus
+
+      //
+      // SAVE MAP HEADER
+      //
+      nsize=sizeof(TempHeader);
+      maplengths[i]+=nsize;
+      SaveFile(huffname,(char huge *)&TempHeader,fsize,nsize);
+      NewFileHeader.dataoffsets[i]=fsize;
+      fsize+=nsize;
+
+      SaveFile(huffname,"!ID!",fsize,4);
+      fsize+=4;
+     }
+ MMFreePtr(&block1);
+
+
+ //
+ // COPY PERTINENT MAPFILEHEADER DATA TO NEWFILEHEADER
+ //
+ {
+  char outname[14],tempname[14]="MTEMP.TMP",doutname[14];
+
+
+  strcpy(outname,ext);
+  strcat(outname,"MHEAD.OBJ");
+
+  NewFileHeader.RLEWtag=MapFileHeader->RLEWtag;
+  fsize=sizeof(OutputHeadStr);
+  SaveFile(tempname,(char huge *)&NewFileHeader,0,fsize);
+
+  for (i=0;i<numtplanes;i++)
+       {
+        SaveFile(tempname,MK_FP(Tinfo[i],0),fsize,tilenum);
+        fsize+=tilenum;
+       }
+  for (i=0;i<numtmplanes;i++)
+       {
+        SaveFile(tempname,MK_FP(TMinfo[i],0),fsize,tilemnum);
+        fsize+=tilemnum;
+       }
+
+  MakeOBJ(tempname,outname,"_maphead",FARDATA,"MapHeader");
+//  unlink(tempname);
+ }
+
+ RestoreBackground();
+ SignalSound();
+
+ //
+ // FINSIHED. PRINT REPORT?
+ //
+ if (Message("Finished with compression.\n"
+            "Print report on lengths?")==2)
+ {
+  fprintf(stdprn,"TED5 Carmacized Map Lengths for .%s\n\n",ext);
+  fprintf(stdprn,"#\tMap Name\t\tLength\n");
+  fprintf(stdprn,"_\t--------\t\t------\n");
+  for (i=0;i<100;i++)
+    if (MapFileHeader->dataoffsets[i]!=-1)
+    {
+     char tstr[16];
+     strcpy(tstr,MapNames[i]);
+     while(strlen(tstr)<16)
+       strcat(tstr," ");
+     fprintf(stdprn,"%d\t%s\t%d\n",i,tstr,maplengths[i]);
+    }
+  fprintf(stdprn,"%c",12);
+ }
+
+ LoadMap(whichmap);
+ xbase=oxb;
+ ybase=oyb;
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Change the LAUNCH name
+//
+////////////////////////////////////////////////////
+btype CLNb={"                                    ",1,5,1};
+DialogDef CLNd={"Current LAUNCH name:\n\n\nNew LAUNCH name:",38,7,1,&CLNb,NULL};
+
+void Item_LAUNCHname(void)
+{
+ char tempstr[40];
+
+
+ MouseHide();
+ DrawDialog(&CLNd,1);
+ GetDialogXY(&CLNd,&sx,&sy);
+ sy++;
+ sx++;
+ print(launchname);
+ GetButtonXY(&CLNd,0,&sx,&sy);
+ if (input(tempstr,36))
+ {
+  strcpy(launchname,tempstr);
+  SaveTEDInfo();
+ }
+ MouseShow();
+ RestoreBackground();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Change the PARM string
+//
+////////////////////////////////////////////////////
+btype CPSb={"                                    ",1,5,1};
+DialogDef CPSd={"Current PARM string:\n\n\nNew PARM string:",38,7,1,&CPSb,NULL};
+
+void Item_PARMstring(void)
+{
+ char tempstr[40];
+
+
+ MouseHide();
+ DrawDialog(&CPSd,1);
+ GetDialogXY(&CPSd,&sx,&sy);
+ sy++;
+ sx++;
+ print(parmstring);
+ GetButtonXY(&CPSd,0,&sx,&sy);
+ if (input(tempstr,36))
+ {
+  strcpy(parmstring,tempstr);
+  _fstrcpy(TEDInfo->parmstring,(char far *)parmstring);
+  SaveTEDInfo();
+ }
+ MouseShow();
+ RestoreBackground();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Change Icon Rows
+//
+////////////////////////////////////////////////////
+btype CIRb={"    ",8,4,1};
+DialogDef CIRd={"Enter amount of icons\n"
+               "to add/delete.\n"
+               "Use + or -.",22,6,1,&CIRb,NULL};
+
+void Item_ChangeIconRows(void)
+{
+ unsigned i,j,dx,dy,max,oxbase,oybase,base;
+ int value,owm;
+ memptr block;
+
+
+ if (!(MapFileHeader->maptype&IPLANE))
+ {
+  ErrDialog("You don't have an icon plane!"," OK ");
+  return;
+ }
+
+ CheckForMapSave();
+
+ oxbase=xbase;
+ oybase=ybase;
+
+ DrawDialog(&CIRd,1);
+ GetButtonXY(&CIRd,0,&dx,&dy);
+ sx=dx;
+ sy=dy;
+ MouseHide();
+ value=inputint(3);
+ MouseShow();
+ if (!value || value==(int)ESCOUT)
+ {
+  RestoreBackground();
+  return;
+ }
+
+ value=SGN(value)*(18*((abs(value)+17)/18));
+
+ base=18*maxiconrows;
+ maxiconrows+=value/18;
+ MapFileHeader->NumIconRows+=value/18;
+
+ owm=whichmap;
+ RestoreBackground();
+
+
+ //
+ // MAKE SURE WE ADJUST TILEINFOM!
+ //
+ MMAllocate(&block,tilemnum+value);
+ for (i=0;i<numtmplanes;i++)
+ {
+  _fmemset(block,0,tilemnum+value);
+  movedata((unsigned)TMinfo[i],0,(unsigned)block,0,base);
+  movedata((unsigned)TMinfo[i],base,
+          (unsigned)block,base+value,tilemnum-base);
+  MMFreePtr((memptr *)&TMinfo[i]);
+  MMAllocate((memptr *)&TMinfo[i],tilemnum+value);
+  movedata((unsigned)block,0,(unsigned)TMinfo[i],0,tilemnum+value);
+ }
+ MMFreePtr(&block);
+ MapFileHeader->oldtilemnum=tilemnum+value;
+
+
+ //
+ // RUN THROUGH EACH MAP AND ADJUST TILEM VALUES
+ //
+ for (i=0;i<100;i++)
+   if (MapFileHeader->dataoffsets[i]>=0)
+     {
+      whichmap=i;
+      LoadMap(i);
+      max=mapwidth*mapheight;
+      for (j=0;j<max;j++)
+       if (MapFrgnd[j]>0)
+         MapFrgnd[j]+=value;
+      DirtyFlag=1;
+      SaveMap(0);
+     }
+
+ DirtyFlag=0;
+ whichmap=owm;
+ LoadMap(whichmap);
+ xbase=oxbase;
+ ybase=oybase;
+ DrawMap();
+ ErrDialog("If your map looks messed up,\n"
+          "you need to change the amount\n"
+          "of icons in your IGRAB script\n"
+          "and re-grab your tiles!"," OK ");
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Change LAUNCH Icon
+//
+////////////////////////////////////////////////////
+void Item_ChangeLaunchIcon(void)
+{
+ sound(1700);
+ TEDInfo->permicon=whichi-tilenum;
+ delay(30);
+ nosound();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Change Background color
+//
+////////////////////////////////////////////////////
+btype CBCb[]={{"\xb",5,2,1},
+             {"\xc",16,2,1},
+             {"Exit",9,2,2}};
+DialogDef CBCd={"Change Backgrnd Color!",22,4,3,&CBCb[0],0};
+void Item_ChangeBkgndColor(void)
+{
+ int which;
+
+ do
+ {
+  which=DoDialog(&CBCd);
+  switch(which)
+  {
+   case 1:
+     sound(1700);
+     if (--BkgndColor<0)
+       BkgndColor=15;
+     TEDInfo->BackgndColor=BkgndColor;
+     DrawMap();
+     DrawInfoBar();
+     break;
+   case 2:
+     sound(1700);
+     if (++BkgndColor>15)
+       BkgndColor=0;
+     TEDInfo->BackgndColor=BkgndColor;
+     DrawMap();
+     DrawInfoBar();
+  }
+  nosound();
+ } while(which>0 && which<3);
+}
diff --git a/16/ted5/TED5-4.C b/16/ted5/TED5-4.C
new file mode 100755 (executable)
index 0000000..e235257
--- /dev/null
@@ -0,0 +1,2633 @@
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// TED5-4
+//
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+#include "ted5.h"
+#pragma hdrstop
+
+
+void SignalSound(void)
+{
+ int i;
+
+ for(i=0;i<10;i++)
+ {
+  sound(500+i*500);
+  delay(5);
+  nosound();
+ }
+}
+
+
+////////////////////////////////////////////////////
+//
+// Create an OBJ linkable file from any type of datafile
+//
+// Exit:
+//  0 = everything's a-ok!
+// -1 = file not found
+// -2 = file >64K
+//
+////////////////////////////////////////////////////
+int MakeOBJ(char *filename,char *destfilename,char *public,segtype whichseg,char *farname)
+{
+ char THEADR[17]={0x80,14,0,12,32,32,32,32,32,32,32,32,32,32,32,32,0},
+      COMENT[18]={0x88,0,0,0,0,'M','a','k','e','O','B','J',' ','v','1','.','1',0},
+      LNAMES[42]={0x96,0,0,
+                 6,'D','G','R','O','U','P',
+                 5,'_','D','A','T','A',
+                 4,'D','A','T','A',
+                 0,
+                 5,'_','T','E','X','T',
+                 4,'C','O','D','E',
+                 8,'F','A','R','_','D','A','T','A'},
+      SEGDEF[9]={0x98,7,0,0x48,0,0,2,3,4},     // for .DATA
+      SEGDEF1[9]={0x98,7,0,0x48,0,0,5,6,4},    // for .CODE
+      SEGDEF2[9]={0x98,7,0,0x60,0,0,8,7,4},    // for .FARDATA
+      GRPDEF[7]={0x9a,4,0,1,0xff,1,0x61},
+      MODEND[5]={0x8a,2,0,0,0x74};
+
+ unsigned i,j,flag,handle;
+ long fsize,offset,loffset,temp,amtleft,amount,offset1;
+ char _seg *dblock,*block;
+
+
+ //
+ // Need to compute the CHECKSUM in the COMENT field
+ // (so if the "MakeOBJ..." string is modified, the CHECKSUM
+ //  will be correct).
+ //
+ COMENT[1]=sizeof(COMENT)-3;
+ for (flag=i=0;i<sizeof(COMENT);i++)
+    flag+=COMENT[i];
+ COMENT[sizeof(COMENT)-1]=(flag^0xff)+1;
+
+ if ((handle=open(filename,O_BINARY))==NULL)
+   return -1;
+
+ fsize=filelength(handle);
+ close(handle);
+ if (fsize>0x10000L)           // BIGGER THAN 1 SEG = ERROR!
+   return -2;
+
+ LoadIn(filename,(memptr *)&block);    // LOAD FILE IN
+ offset=0;
+
+ MMAllocate((memptr *)&dblock,0x10000L);
+
+ ////////////////////////////////////////////////////
+ //
+ // INSERT HEADER RECORD
+ //
+ movedata(_DS,FP_OFF(&THEADR),(unsigned)dblock,offset,sizeof(THEADR));
+ movedata(FP_SEG(filename),FP_OFF(filename),
+         (unsigned)dblock,offset+4,strlen(filename));
+ offset+=sizeof(THEADR);
+
+
+ ////////////////////////////////////////////////////
+ //
+ // INSERT COMMENT RECORD
+ //
+ movedata(_DS,FP_OFF(COMENT),(unsigned)dblock,offset,sizeof(COMENT));
+ offset+=sizeof(COMENT);
+
+
+ ////////////////////////////////////////////////////
+ //
+ // INSERT START OF LIST-OF-NAMES RECORD
+ //
+ loffset=offset;
+ movedata(_DS,FP_OFF(LNAMES),(unsigned)dblock,offset,sizeof(LNAMES));
+ offset+=sizeof(LNAMES);
+
+ // If it's a .FARDATA segment, we need to insert the segment name!
+ if (whichseg==FARDATA)
+   {
+    *(dblock+offset)=strlen(farname);
+    movedata(FP_SEG(farname),FP_OFF(farname),
+       (unsigned)dblock,offset+1,strlen(farname));
+    offset+=strlen(farname)+1;
+   }
+
+ // Now, finish the List-Of-Names record by creating
+ // the CHECKSUM and LENGTH
+ temp=offset;
+ offset=offset-loffset-2;
+ *(int huge *)(dblock+loffset+1)=offset;
+ offset=temp;
+
+ // Now, figure out the CHECKSUM of the record
+ for (flag=i=0;i<(offset-loffset);i++)
+   flag+=*(dblock+i+loffset);
+ *(dblock+offset)=(flag^0xff)+1;
+ offset++;
+
+
+ ////////////////////////////////////////////////////
+ //
+ // CREATE SEGMENT DEFINITION RECORD
+ //
+ loffset=offset;
+ temp=fsize;
+ switch(whichseg)
+ {
+  case DATA:
+    movedata(FP_SEG(&SEGDEF),FP_OFF(&SEGDEF),
+            (unsigned)dblock,offset,sizeof(SEGDEF));
+    *(int huge *)(dblock+offset+4)=temp;
+    offset+=sizeof(SEGDEF);
+    break;
+  case CODE:
+    movedata(FP_SEG(&SEGDEF1),FP_OFF(&SEGDEF1),
+            (unsigned)dblock,offset,sizeof(SEGDEF1));
+    *(int huge *)(dblock+offset+4)=temp;
+    offset+=sizeof(SEGDEF1);
+    break;
+  case FARDATA:
+    movedata(FP_SEG(&SEGDEF2),FP_OFF(&SEGDEF2),
+            (unsigned)dblock,offset,sizeof(SEGDEF2));
+    *(int huge *)(dblock+offset+4)=temp;
+    offset+=sizeof(SEGDEF2);
+    break;
+ }
+
+ // CHECKSUM
+ for (flag=0,i=loffset;i<offset;i++)
+   flag+=*(dblock+i);
+ *(dblock+offset)=(flag^0xff)+1;
+ offset++;
+
+
+ ////////////////////////////////////////////////////
+ //
+ // CREATE GROUP DEFINITION RECORD
+ //
+ switch(whichseg)
+ {
+  case DATA:
+  case CODE:
+    movedata(FP_SEG(&GRPDEF),FP_OFF(&GRPDEF),
+            (unsigned)dblock,offset,sizeof(GRPDEF));
+    offset+=sizeof(GRPDEF);
+ }
+
+
+ ////////////////////////////////////////////////////
+ //
+ // CREATE PUBLIC DEFINITION RECORD
+ //
+ loffset=offset;
+ *(dblock+offset)=0x90;                // PUBDEF ID
+ offset+=3;                    // point to public base, skip length
+ *(dblock+offset)=1;           // group index=1
+ *(dblock+offset+1)=1;         // segment index=1
+ offset+=2;                    // point to public name
+
+ temp=0;
+ movedata(FP_SEG(public),FP_OFF(public),
+         (unsigned)dblock,offset+1,strlen(public));
+ *(dblock+offset)=strlen(public);
+ offset+=strlen(public)+1;
+ *(int huge *)(dblock+offset)=0;       // public offset within segment
+ offset+=2;
+ *(dblock+offset)=0;           // type index
+ offset++;
+
+ // LENGTH
+ temp=offset-loffset-2;
+ *(int huge *)(dblock+loffset+1)=temp;
+ offset++;
+
+ // CHECKSUM
+ for (flag=0,i=loffset;i<offset;i++)
+   flag+=*(dblock+i);
+ *(dblock+offset)=(flag^0xff)+1;
+
+
+ ////////////////////////////////////////////////////
+ //
+ // DATA RECORD(S). YUCK.
+ //
+
+ amtleft=fsize;
+ amount=1024;
+ for (i=0;i<(fsize+1023)/1024;i++)
+   {
+    offset1=offset;
+    if (amtleft<1024)
+      amount=amtleft;
+    //
+    // RECORD HEADER
+    //
+    *(dblock+offset)=0xa0;                     // LEDATA ID
+    *(int huge *)(dblock+offset+1)=amount+4;   // length of record
+    offset+=3;
+    *(dblock+offset)=1;                                // segment index
+    *(int huge *)(dblock+offset+1)=i*1024;     // index into segment
+    offset+=3;
+    //
+    // LOAD DATA IN
+    //
+    LoadFile(filename,(char huge *)dblock+offset,i*1024,amount);
+    offset+=amount;
+    //
+    // CHECKSUM!
+    //
+    for (flag=0,j=offset1;j<offset;j++)
+      flag+=*(dblock+j);
+    *(dblock+offset)=(flag^0xff)+1;
+    offset++;
+
+    amtleft-=1024;
+   }
+
+ ////////////////////////////////////////////////////
+ //
+ // MODULE END! YES!
+ //
+ movedata(FP_SEG(&MODEND),FP_OFF(&MODEND),(unsigned)dblock,offset,sizeof(MODEND));
+ offset+=sizeof(MODEND);
+
+ //
+ // Save the little puppy out!
+ //
+ SaveFile(destfilename,(char huge *)dblock,0,offset);
+ MMFreePtr((memptr *)&dblock);
+ MMFreePtr((memptr *)&block);
+ return 0;
+}
+
+
+////////////////////////////////////////////////////
+//
+// DUMP THE PASTE BUFFER OUT TO EITHER AN
+// "APPLE PREFERRED" OR "ILBM" GRAPHICS FORMAT FILE
+//
+// NOTE: THIS IS ONLY AVAILABLE IN EGA, BECAUSE I
+// DON'T FEEL LIKE WRITING A CGA ILBM PIXEL-SPLICER --
+// AND APPLE PREFERRED ONLY HANDLES 4-BIT COLOR ANYWAY!
+// (YES, I KNOW, I COULD ONLY USE 4 OUT OF 16 COLORS...SHUT UP!)
+//
+////////////////////////////////////////////////////
+btype dumpB[]={{" DeluxePaint II ILBM ",4,2,2},
+              {"   Apple Preferred   ",4,5,1}},
+      fnameB={"         ",4,3,1};
+DialogDef dumpD={" Which format do you require?",30,7,2,&dumpB[0],NULL},
+         fnameD={"Enter filename to\nsave (no suffix)",17,5,1,&fnameB,NULL};
+
+void Item_GraphicDump(void)
+{
+ char filename[14],ext[5],_seg *block,_seg *block1;
+ ApPrefStr PrefHeader;
+ int which,i,j,k,m,n,pwidth,lwidth,dx,dy;
+ long tilelen,fsize=0,bufsize;
+
+ if (!PasteOK)
+   {
+    ErrDialog("You need to use the Copy command\n"
+             "to copy part of the map or tiles\n"
+             "so I know what I need to dump!"," OK ");
+    return;
+   }
+
+ switch(videomode)
+ {
+  case CGA:
+  case VGA:
+    ErrDialog("Sorry, but this function is only\n"
+             "available for EGA mode.  If you\n"
+             "have a REAL NEED for this to work\n"
+             "in CGA or VGA, talk to Id Software!"," OK ");
+    return;
+ }
+
+ if (!(which=DoDialog(&dumpD)))
+   return;
+
+ //
+ // SET TILE LENGTH
+ //
+ switch(tsize)
+ {
+  case 1: tilelen=32L; break;
+  case 2: tilelen=128L; break;
+  case 3: tilelen=512L;
+ }
+
+ //
+ // GET FILENAME TO SAVE UNDER
+ //
+ DrawDialog(&fnameD,1);
+ MouseHide();
+ GetButtonXY(&fnameD,0,&sx,&sy);
+ if (!input(filename,8))
+   {
+    RestoreBackground();
+    MouseShow();
+    return;
+   }
+ for (i=0;i<strlen(filename);i++)
+   if (filename[i]=='.')
+     {
+      filename[i]=0;
+      break;
+     }
+ RestoreBackground();
+ MouseShow();
+
+ //
+ // SETUP FOR EACH TYPE
+ //
+ switch(which)
+ {
+  case 1:      // ILBM
+    {
+     long size;
+     char form[5]="FORM",ilbm[9]="ILBMBMHD",body[5]="BODY";
+
+
+     size=48L;
+     MMAllocate((memptr *)&block,size);
+
+     movedata(FP_SEG(form),FP_OFF(form),(unsigned)block,fsize,4);
+     fsize+=4;
+     size=40L+tilelen*TileCopy.w*TileCopy.h;
+     *(block+fsize)=(size>>24)&0xff;
+     *(block+fsize+1)=(size>>16)&0xff;
+     *(block+fsize+2)=(size>>8)&0xff;
+     *(block+fsize+3)=size&0xff;
+     fsize+=4;
+     movedata(FP_SEG(ilbm),FP_OFF(ilbm),(unsigned)block,fsize,8);
+     fsize+=8;
+     *(block+fsize)=0;
+     *(block+fsize+1)=0;
+     *(block+fsize+2)=0;
+     *(block+fsize+3)=20;
+     fsize+=4;
+     *(block+fsize)=(TileCopy.w<<(tsize+2))/256;   // pixel width
+     *(block+fsize+1)=(TileCopy.w<<(tsize+2))&0xff;
+     *(block+fsize+2)=(TileCopy.h<<(tsize+2))/256; // pixel height
+     *(block+fsize+3)=(TileCopy.h<<(tsize+2))&0xff;
+     *(int huge *)(block+fsize+4)=0;           // Xorg
+     *(int huge *)(block+fsize+6)=0;           // Yorg
+     *(block+fsize+8)=4;                       // planes
+     *(block+fsize+9)=0;                       // mask (stencil!)
+     *(block+fsize+10)=0;                      // compression (none)
+     *(block+fsize+11)=0;                      // pad (?)
+     *(int huge *)(block+fsize+12)=0;          // trans (?)
+     *(int huge *)(block+fsize+14)=0x101;      // aspt (aspect?)
+     *(int huge *)(block+fsize+16)=0x4001;     // page width
+     *(int huge *)(block+fsize+18)=0xc800;     // page height
+     fsize+=20;
+     movedata(FP_SEG(body),FP_OFF(body),(unsigned)block,fsize,4);
+     fsize+=4;
+     size=tilelen*TileCopy.w*TileCopy.h;
+     *(block+fsize)=(size>>24)&0xff;
+     *(block+fsize+1)=(size>>16)&0xff;
+     *(block+fsize+2)=(size>>8)&0xff;
+     *(block+fsize+3)=size&0xff;
+     fsize+=4;
+
+     strcpy(ext,".LBM");
+    }
+    break;
+
+  case 2:      // APPLE PREFERRED
+    {
+     int Ctable[16]={0x0000,0x000a,0x00a0,0x00aa,0x0a00,0x0a0a,0x0a50,0x0aaa,
+                    0x0555,0x055f,0x05f5,0x05ff,0x0f55,0x0f5f,0x0ff5,0x0fff};
+     long size,pixwid;
+
+
+     PrefHeader.length=sizeof(ApPrefStr)+4L*(TileCopy.h<<(tsize+2))+
+       TileCopy.w*TileCopy.h*tilelen+(((TileCopy.w*TileCopy.h*tilelen)+63)/64);
+     strncpy(PrefHeader.Kind,"\x4MAIN",5);
+     PrefHeader.MasterMode=0;
+     PrefHeader.PixelsPerLine=TileCopy.w<<(tsize+2);
+     PrefHeader.NumColorTables=1;
+     for (i=0;i<16;i++)
+       PrefHeader.ColorTable[i]=Ctable[i];
+     PrefHeader.NumScanLines=TileCopy.h<<(tsize+2);
+
+     size=sizeof(ApPrefStr)+4L*(TileCopy.h<<(tsize+2));
+     MMAllocate((memptr *)&block,size);
+     movedata(FP_SEG(&PrefHeader),FP_OFF(&PrefHeader),(unsigned)block,fsize,sizeof(ApPrefStr));
+     fsize+=sizeof(ApPrefStr);
+
+     pixwid=TileCopy.w*(2<<tsize);
+     for (i=0;i<(TileCopy.h<<(tsize+2));i++)
+       {
+       *(int huge *)(block+fsize)=pixwid+(pixwid+63)/64;
+       *(int huge *)(block+fsize+2)=0;
+       fsize+=4;
+       }
+
+     strcpy(ext,".APP");
+     MMAllocate((memptr *)&block1,tilelen*TileCopy.w);
+    }
+ }
+
+ //
+ // SAVE HEADER OUT
+ //
+ strcat(filename,ext);
+ SaveFile(filename,(char huge *)block,0,fsize);
+ MMFreePtr((memptr *)&block);
+
+ //
+ // NOW, WRITE THE DATA OUT! EEEE!
+ //
+ bufsize=tilelen*TileCopy.w;
+ MMAllocate((memptr *)&block,bufsize);
+
+ pwidth=(1<<(tsize-1))*TileCopy.w;
+ lwidth=pwidth*4;
+
+ ErrDialog("One moment. I am busy.\n     Countdown:","");
+ dx=sx;
+ dy=sy;
+
+ for (j=0;j<TileCopy.h;j++)
+   {
+    sx=dx;
+    sy=dy;
+    printint(TileCopy.h-j);
+    print(" ");
+
+    for (i=0;i<TileCopy.w;i++)
+      {
+       unsigned tilet,tilem,tilei,loc;
+
+       //
+       // ESC out?
+       //
+       if (keydown[1])
+        {
+         RestoreBackground();
+         while(keydown[1]);
+         ErrDialog("You aborted out of the\n"
+                   "graphic dump conversion!"," Yes, I know ");
+
+         if (which==2)
+           MMFreePtr((memptr *)&block1);
+         return;
+        }
+       //
+       // GET THE CORRECT TILE MOVED INTO "TDATA"
+       //
+       switch(TileCopy.MapOrTileSelect)
+       {
+       case 0: // MAP COPY
+         loc=(j+TileCopy.y)*mapwidth+TileCopy.x+i;
+         tilet=(TileCopy.PlanesCopied&BPLANE)?CutBkgnd[loc]:-BkgndColor;
+         tilem=(TileCopy.PlanesCopied&FPLANE)?CutFrgnd[loc]+tilenum:0;
+         tilei=(TileCopy.PlanesCopied&IPLANE)?CutInfoPl[loc]+tilenum:0;
+         CombineTiles(tilet,tilem,tilei,tsize);
+         break;
+       case 1: // BKGND TILE COPY
+         loc=(TileCopy.y+j)*selectcols+TileCopy.x+i;
+         CombineTiles(loc,0,0,tsize);
+         break;
+       case 2: // FRGND TILE COPY
+         loc=(TileCopy.y+j)*selectcols+TileCopy.x+i+tilenum;
+         CombineTiles(-BkgndColor,loc,0,tsize);
+       }
+
+       //
+       // NOW, MUNGE "TDATA" INTO BIT-PLANES!
+       //
+       // INTERNAL:            P0      P1      P2      P3
+       //      SCANLINE x      ......  ......  ......  ......
+       //
+       for (k=0;k<8<<(tsize-1);k++)
+        for (m=0;m<4;m++)
+          movedata(FP_SEG(&tdata),FP_OFF(&tdata)+(m*tsize*(8<<(tsize-1)))+k*(1<<(tsize-1)),
+               (unsigned)block,k*lwidth+m*pwidth+i*(1<<(tsize-1)),1<<(tsize-1));
+      }
+    //
+    // ALRIGHT. NOW SAVE THIS CHUNK OUT IN THE CORRECT FORMAT
+    //
+    switch(which)
+    {
+     case 1:   // ILBM
+       SaveFile(filename,MK_FP(block,0),fsize,bufsize);
+       fsize+=bufsize;
+       break;
+     case 2:   // APPLE PREFERRED
+       {
+       int len,clen;
+
+       //
+       // FIRST, I NEED TO CONVERT THE ILBM PLANAR FORMAT
+       // TO SUPER-RES NIBBLES
+       //
+       for (k=0;k<8<<(tsize-1);k++)
+         for (m=0;m<(1<<(tsize-1))*TileCopy.w;m++)
+           {
+            unsigned char src[4],dest[4]={0,0,0,0};
+
+            for (n=0;n<4;n++)
+              src[n]=block[k*lwidth+pwidth*n+m];
+
+            asm        mov     al,[BYTE PTR src+0]
+            asm        mov     ah,[BYTE PTR src+1]
+            asm        mov     bl,[BYTE PTR src+2]
+            asm        mov     bh,[BYTE PTR src+3]
+
+            // dest[0]
+            asm        shl     bh,1
+            asm        rcl     cl,1
+            asm        shl     bl,1
+            asm        rcl     cl,1
+            asm        shl     ah,1
+            asm        rcl     cl,1
+            asm        shl     al,1
+            asm        rcl     cl,1
+
+            asm        shl     bh,1
+            asm        rcl     cl,1
+            asm        shl     bl,1
+            asm        rcl     cl,1
+            asm        shl     ah,1
+            asm        rcl     cl,1
+            asm        shl     al,1
+            asm        rcl     cl,1
+
+            // dest[1]
+            asm        shl     bh,1
+            asm        rcl     ch,1
+            asm        shl     bl,1
+            asm        rcl     ch,1
+            asm        shl     ah,1
+            asm        rcl     ch,1
+            asm        shl     al,1
+            asm        rcl     ch,1
+
+            asm        shl     bh,1
+            asm        rcl     ch,1
+            asm        shl     bl,1
+            asm        rcl     ch,1
+            asm        shl     ah,1
+            asm        rcl     ch,1
+            asm        shl     al,1
+            asm        rcl     ch,1
+
+            // dest[2]
+            asm        shl     bh,1
+            asm        rcl     dl,1
+            asm        shl     bl,1
+            asm        rcl     dl,1
+            asm        shl     ah,1
+            asm        rcl     dl,1
+            asm        shl     al,1
+            asm        rcl     dl,1
+
+            asm        shl     bh,1
+            asm        rcl     dl,1
+            asm        shl     bl,1
+            asm        rcl     dl,1
+            asm        shl     ah,1
+            asm        rcl     dl,1
+            asm        shl     al,1
+            asm        rcl     dl,1
+
+            // dest[3]
+            asm        shl     bh,1
+            asm        rcl     dh,1
+            asm        shl     bl,1
+            asm        rcl     dh,1
+            asm        shl     ah,1
+            asm        rcl     dh,1
+            asm        shl     al,1
+            asm        rcl     dh,1
+
+            asm        shl     bh,1
+            asm        rcl     dh,1
+            asm        shl     bl,1
+            asm        rcl     dh,1
+            asm        shl     ah,1
+            asm        rcl     dh,1
+            asm        shl     al,1
+            asm        rcl     dh,1
+
+            asm        mov     [BYTE PTR dest+0],cl
+            asm        mov     [BYTE PTR dest+1],ch
+            asm        mov     [BYTE PTR dest+2],dl
+            asm        mov     [BYTE PTR dest+3],dh
+
+            movedata(FP_SEG(&dest),FP_OFF(&dest),
+               (unsigned)block1,k*lwidth+m*4,4);
+           }
+
+       //
+       // NOW, TIME TO WRITE THE DATA OUT IN 64-BYTE CHUNKS! YUCK!
+       //
+       for (k=0;k<8<<(tsize-1);k++)
+         {
+          char clen;
+          int off=k*lwidth;;
+
+          len=4*pwidth;
+          while(len>0)
+          {
+           if (len>64)
+             clen=64;
+           else
+             clen=len;
+
+           clen--;
+           SaveFile(filename,(char huge *)&clen,fsize++,1);
+           clen++;
+
+           SaveFile(filename,MK_FP(block1,off),fsize,clen);
+           fsize+=clen;
+           off+=clen;
+           len-=clen;
+          }
+         }
+       }
+    }
+   }
+
+ if (which==2)
+   MMFreePtr((memptr *)&block1);
+
+ MMFreePtr((memptr *)&block);
+ RestoreBackground();
+
+ ErrDialog("Graphic successfully dumped!"," Yeah! ");
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Edit TILEINFO/M values
+//
+////////////////////////////////////////////////////
+btype ETVb[]={{" Tileinfo ",2,21,1},
+             {" TileinfoM ",16,21,1},
+             {" Exit ",30,21,2}};
+DialogDef ETVd={"       Edit TILEINFO/M values",38,23,3,&ETVb[0],NULL};
+int CurTIvalue;
+
+void Item_EditTinfoValues(void)
+{
+ int max,i,which,exitok=0,mx,my,b0,b1,CTRLdown;
+ static int whichtinfo=0;
+
+ //
+ // IS THE "CTRL" KEY DOWN?
+ //
+ CTRLdown=keydown[0x1d];
+ if (CTRLdown)
+   {
+    if (planeton)
+      whichtinfo=0;
+    else
+      whichtinfo=1;
+   }
+
+ switch(whichtinfo)
+ {
+  case 0: max=tilenum; break;
+  case 1: max=tilemnum;
+ }
+
+ switch(videomode)
+ {
+  case CGA:
+  case EGA1:
+  case VGA:
+    ETVd.height=23;
+    for(i=0;i<3;i++)
+      ETVb[i].yoff=21;
+    break;
+  case EGA2:
+    ETVd.height=58;
+    for(i=0;i<3;i++)
+      ETVb[i].yoff=56;
+ }
+
+ //
+ // DRAW THE SCREEN
+ //
+ DrawDialog(&ETVd,1);
+ if (CTRLdown)
+   {
+    DrawTinfoScreen(whichtinfo,0,-max);        // ALIGN TO TOP
+    switch(whichtinfo)
+    {
+     case 0: DrawTinfoScreen(whichtinfo,0,whicht); break;
+     case 1: DrawTinfoScreen(whichtinfo,0,whichtm-tilenum);
+    }
+   }
+ else
+   DrawTinfoScreen(whichtinfo,0,0);
+
+
+ do
+ {
+  which=CheckButtonsRet(&ETVd);
+  if (which>=0)
+    switch(which)
+    {
+     case 0:
+       RestoreBackground();
+       return;
+     case 1:
+       if (whichtinfo)
+        {
+         max=tilenum;
+         whichtinfo=0;
+         DrawDialog(&ETVd,0);
+         DrawTinfoScreen(whichtinfo,0,0);
+        }
+       else
+        {
+         GetButtonXY(&ETVd,0,&sx,&sy);
+         MouseHide();
+         print(ETVb[0].text);
+         MouseShow();
+         errsound();
+        }
+       break;
+     case 2:
+       if (!tilemnum)
+        {
+         GetButtonXY(&ETVd,1,&sx,&sy);
+         MouseHide();
+         print(ETVb[1].text);
+         MouseShow();
+         errsound();
+         break;
+        }
+
+       if (!whichtinfo)
+        {
+         max=tilemnum;
+         whichtinfo=1;
+         DrawDialog(&ETVd,0);
+         DrawTinfoScreen(whichtinfo,0,0);
+        }
+       else
+        {
+         GetButtonXY(&ETVd,1,&sx,&sy);
+         MouseHide();
+         print(ETVb[1].text);
+         MouseShow();
+         errsound();
+        }
+       break;
+
+     case 3:
+       exitok=1;
+    }
+  else
+    {
+     MouseCoords(&mx,&my);
+     mx/=8;
+     my/=8;
+     b0=MouseButton()&1;
+     b1=MouseButton()&2;
+
+     //
+     // CHECK FOR BUTTON PRESSES
+     //
+     if (b0)
+       UseTinfoValue(whichtinfo,mx,my,1);
+     else
+     if (b1)
+       UseTinfoValue(whichtinfo,mx,my,0);
+
+     //
+     // SPACE = ENTER VALUES HORIZONTALLY
+     //
+     if (keydown[0x39])
+     {
+      while(keydown[0x39]);
+      clearkeys();
+      EnterTinfoValue(whichtinfo,mx,my,0);
+     }
+
+     //
+     // CHECK FOR SCROLLING
+     //
+     if (keydown[0x48])                // UP
+       {
+       DrawTinfoScreen(whichtinfo,0,-1);
+       if (keydown[0x1d])
+         while(keydown[0x48]);
+       }
+     else
+     if (keydown[0x50])                // DOWN
+       {
+       DrawTinfoScreen(whichtinfo,0,1);
+       if (keydown[0x1d])
+         while(keydown[0x50]);
+       }
+     else
+     if (keydown[0x49])                // PGUP
+       {
+       DrawTinfoScreen(whichtinfo,0,-8);
+       if (!keydown[0x1d])
+         while(keydown[0x49]);
+       }
+     else
+     if (keydown[0x51])                // PGDN
+       {
+       DrawTinfoScreen(whichtinfo,0,8);
+       if (!keydown[0x1d])
+         while(keydown[0x51]);
+       }
+     else
+     if (keydown[0x47])                // HOME
+       {
+       DrawTinfoScreen(whichtinfo,0,-max);
+       while(keydown[0x47]);
+       }
+     else
+     if (keydown[0x4f])                // END
+       {
+       DrawTinfoScreen(whichtinfo,0,max);
+       while(keydown[0x4f]);
+       }
+     else
+     if (keydown[0x4d])                // RIGHT
+       {
+       DrawTinfoScreen(whichtinfo,1,0);
+       if (!keydown[0x1d])
+         while(keydown[0x4d]);
+       }
+     else
+     if (keydown[0x4b])                // LEFT
+       {
+       DrawTinfoScreen(whichtinfo,-1,0);
+       if (!keydown[0x1d])
+         while(keydown[0x4b]);
+       }
+
+    }
+
+ } while(!exitok);
+
+ RestoreBackground();
+}
+
+
+//
+// PICKUP/DROP TILEINFO VALUE AT CURSOR
+//
+void UseTinfoValue(int whichtinfo,int mx,int my,int PickupOrDrop)
+{
+ int whichx=-1,whichy=-1;
+ unsigned dialogx,dialogy;
+
+
+ GetDialogXY(&ETVd,&dialogx,&dialogy);
+
+ if (mx>=dialogx+10 && mx<=dialogx+45)
+   whichx=(mx-(dialogx+10))/7;
+
+ if (my>=4 && my<=((videomode==EGA2)?55:19))
+   whichy=(my-4)>>(tsize-1);
+
+ switch(whichtinfo)
+ {
+  case 0:
+    if (whichx>=numtplanes)
+      whichx=-1;
+    if (whichy>=tilenum)
+      whichy=-1;
+    break;
+
+  case 1:
+    if (whichx>=numtmplanes)
+      whichx=-1;
+    if (whichy>=tilemnum)
+      whichy=-1;
+ }
+
+ if (whichx>=0 && whichy>=0)
+ {
+  if (!PickupOrDrop)
+    switch(whichtinfo)
+    {
+     case 0:   // TILE
+       CurTIvalue=*(Tinfo[whichx+TIxbase]+whichy+TIybase);
+       break;
+     case 1:   // MASKED
+       CurTIvalue=*(TMinfo[whichx+TIxmbase]+whichy+TIymbase);
+    }
+  else
+    switch(whichtinfo)
+    {
+     case 0:   // TILE
+       *(Tinfo[whichx+TIxbase]+whichy+TIybase)=CurTIvalue;
+       DirtyFlag=1;
+       break;
+     case 1:   // MASKED
+       *(TMinfo[whichx+TIxmbase]+whichy+TIymbase)=CurTIvalue;
+       DirtyFlag=1;
+    }
+
+  DrawTinfoScreen(whichtinfo,0,0);
+ }
+ while(MouseButton());
+}
+
+
+//
+// ENTER TILEINFO/M CELL VALUES
+//
+void EnterTinfoValue(int whichtinfo,int mx,int my,int H_or_V)
+{
+ int whichx=-1,whichy=-1,val,outok=0,tempx,tempy,maxx,maxy;
+ unsigned dialogx,dialogy;
+
+
+ GetDialogXY(&ETVd,&dialogx,&dialogy);
+
+ if (mx>=dialogx+10 && mx<=dialogx+45)
+   whichx=(mx-(dialogx+10))/7;
+
+ if (my>=4 && my<=((videomode==EGA2)?55:19))
+   whichy=(my-4)>>(tsize-1);
+
+ switch(whichtinfo)
+ {
+  case 0:
+    if (whichx>=numtplanes)
+      whichx=-1;
+    if (whichy>=tilenum)
+      whichy=-1;
+    break;
+
+  case 1:
+    if (whichx>=numtmplanes)
+      whichx=-1;
+    if (whichy>=tilemnum)
+      whichy=-1;
+ }
+
+ MouseHide();
+
+ if (whichx>=0 && whichy>=0)
+   do
+   {
+    //
+    // INPUT VALUE
+    //
+    sx=whichx*7+dialogx+10;
+    sy=(whichy<<(tsize-1))+4;
+    print("    ");
+    sx-=4;
+    if ((val=inputint(3))!=(int)ESCOUT)
+      switch(whichtinfo)
+      {
+       case 0: // TILE
+        *(Tinfo[whichx+TIxbase]+whichy+TIybase)=val&0xff;
+        DirtyFlag=1;
+        break;
+       case 1: // MASKED
+        *(TMinfo[whichx+TIxmbase]+whichy+TIymbase)=val&0xff;
+        DirtyFlag=1;
+      }
+    else
+      outok=1;
+
+    //
+    // INPUT INTO THE NEXT FIELD!
+    //
+    if (!outok)
+      {
+       tempx=(whichtinfo?TIxmbase:TIxbase);
+       tempy=(whichtinfo?TIymbase:TIybase);
+       maxx=(whichtinfo?numtmplanes:numtplanes);
+       maxy=(whichtinfo?tilemnum:tilenum);
+
+       switch(H_or_V)
+       {
+       case 0: // HORIZONTAL
+         whichx++;
+         if (tempx+whichx>=maxx)
+           outok=1;
+         else
+         if (whichx>TINFOWIDTH)
+           {
+            whichx=TINFOWIDTH;
+            tempx++;
+            if (tempx>=maxx)
+              outok=1;
+           }
+
+         switch(whichtinfo)
+         {
+          case 0: TIxbase=tempx; break;
+          case 1: TIxmbase=tempx;
+         }
+         break;
+
+       case 1: // VERTICAL
+         whichy++;
+         if (tempy+whichy>=maxy)
+           outok=1;
+         else
+         if (whichy>(videomode==EGA2?TINFOHEIGHTEGA2:TINFOHEIGHT))
+           {
+            whichy=(videomode==EGA2?TINFOHEIGHTEGA2:TINFOHEIGHT);
+            tempy++;
+            if (tempy>=maxy)
+              outok=1;
+           }
+
+         switch(whichtinfo)
+         {
+          case 0: TIybase=tempy; break;
+          case 1: TIymbase=tempy;
+         }
+       }
+      }
+
+    DrawTinfoScreen(whichtinfo,0,0);
+
+   } while (!outok);
+
+ MouseShow();
+}
+
+
+
+//
+// Draw the Tileinfo screen
+//
+void DrawTinfoScreen(int thescreen,int deltax,int deltay)
+{
+ int temp,temp1,i,j,width,height,dialogx;
+ char _seg *Values[10];
+
+
+ MouseHide();
+ switch(videomode)
+ {
+  case CGA:
+  case EGA1:
+  case VGA:
+    dialogx=1;
+    height=16>>(tsize-1); break;
+  case EGA2:
+    dialogx=21;
+    height=52>>(tsize-1);
+ }
+
+ switch(thescreen)
+ {
+  case 0:      // TILEINFO
+    if (height>tilenum)
+      height=tilenum;
+    else
+      {
+       TIybase+=deltay;
+       if (TIybase<0)
+        TIybase=0;
+       else
+       if (TIybase+height>tilenum)
+        TIybase=tilenum-height;
+      }
+    temp=TIybase;
+    break;
+
+  case 1:      // TILEINFOM
+    if (height>tilemnum)
+      height=tilemnum;
+    else
+      {
+       TIymbase+=deltay;
+       if (TIymbase<0)
+        TIymbase=0;
+       else
+       if (TIymbase+height>tilemnum)
+        TIymbase=tilemnum-height;
+      }
+    temp=TIymbase;
+ }
+
+ //
+ // DRAW TILES AND THEIR VALUES
+ //
+ for (i=0;i<height;i++)
+   {
+    sx=dialogx;
+    sy=(i<<(tsize-1))+4;
+    printhex(i+temp);
+    sx=dialogx;
+    sy++;
+    print("    ");
+    sx-=4;
+    printint(i+temp);
+
+    switch(thescreen)
+    {
+     case 0:
+       CombineTiles(temp+i,0,0,tsize);
+       break;
+     case 1:
+       CombineTiles(-BkgndColor,temp+i+tilenum,0,tsize);
+    }
+
+    DrawTile(dialogx+5,(i+2)<<(3+(tsize-1)),tsize);
+   }
+
+ //
+ // DRAW TILEINFO ARRAYS
+ //
+ width=4;
+
+ switch(thescreen)
+ {
+  case 0:
+    if (width>numtplanes)
+      width=numtplanes;
+    else
+      {
+       TIxbase+=deltax;
+       if (TIxbase<0)
+        TIxbase=0;
+       else
+       if (TIxbase+width>numtplanes)
+        TIxbase=numtplanes-width;
+      }
+    temp1=TIxbase;
+    for (i=0;i<10;i++)
+      Values[i]=Tinfo[i];
+
+    break;
+
+  case 1:
+    if (width>numtmplanes)
+      width=numtmplanes;
+    else
+      {
+       TIxmbase+=deltax;
+       if (TIxmbase<0)
+        TIxmbase=0;
+       else
+       if (TIxmbase+width>numtmplanes)
+        TIxmbase=numtmplanes-width;
+      }
+    temp1=TIxmbase;
+    for (i=0;i<10;i++)
+      Values[i]=TMinfo[i];
+ }
+
+ for (j=0;j<width;j++)
+   {
+    sx=(dialogx+10)+j*7;
+    sy=3;
+    switch(thescreen)
+    {
+     case 0:
+       print("       ");
+       sx-=7;
+       fprint(MapFileHeader->tnames[j+TIxbase]);
+       break;
+     case 1:
+       print("       ");
+       sx-=7;
+       fprint(MapFileHeader->tmnames[j+TIxmbase]);
+    }
+    for (i=0;i<height;i++)
+      {
+       sx=(dialogx+10)+j*7;
+       sy=(i<<(tsize-1))+4;
+       print("$");
+       printhexb(Values[j+temp1][i+temp]);
+       sx=(dialogx+10)+j*7;
+       sy++;
+       print("   ");
+       sx-=3;
+       printint(Values[j+temp1][i+temp]&0xff);
+      }
+   }
+ MouseShow();
+}
+
+
+
+////////////////////////////////////////////////////
+//
+// Item - Add or Delete TILEINFO/M planes
+//
+////////////////////////////////////////////////////
+btype AODb[]={{" Add ",1,3,1},
+             {" Delete ",8,3,1},
+             {" Exit ",18,3,2}},
+      TOMb[]={{" Tileinfo  ",1,2,1},
+             {" TileinfoM ",1,5,1}},
+      AreSureB2[]={{" Yes ",1,2,1},
+                  {" No ",8,2,2}},
+      TINb2={" Done ",8,15,1};;
+DialogDef AODd={"       TILEINFO/M\n     Pick a function",25,5,3,&AODb[0],NULL},
+         TOMd={"Add to what?",13,7,2,&TOMb[0],NULL},
+         NId={"Gimme a name!",13,4,0,NULL,NULL},
+         AreSureD2={"Are you sure?",13,4,2,&AreSureB2[0],NULL},
+         TINd2={"   Which to delete?\n"
+               " TILEINFO   TILEINFOM",
+               22,17,1,&TINb2,NULL};
+
+void Item_AddDelTinfo(void)
+{
+ char temp[16];
+ int which,i;
+ unsigned dx,dy;
+
+ while(1)
+ {
+  which=DoDialog(&AODd);
+  switch(which)
+  {
+   case 0:     // ESC or EXIT
+   case 3:
+     return;
+   //
+   // ADD
+   //
+   case 1:
+     which=DoDialog(&TOMd);
+     if (!which)
+       break;
+
+     switch(which)
+     {
+      case 1:
+       if (numtplanes==10)
+         {
+          ErrDialog("You already have 10 TILEINFO\n"
+                    "planes defined!"," OK ");
+          return;
+         }
+       break;
+
+      case 2:
+       if (!tilemnum)
+         {
+          ErrDialog("You crazy shit! You don't\n"
+                    "have any masked tiles!"," Duh! ");
+          return;
+         }
+
+       if (numtmplanes==10)
+         {
+          ErrDialog("You already have 10 TILEINFOM\n"
+                    "planes defined!"," OK ");
+          return;
+         }
+       break;
+     }
+
+     DrawDialog(&NId,1);
+     MouseHide();
+     GetDialogXY(&NId,&dx,&dy);
+     sx=dx+1;
+     sy=dy+1;
+     DrawBorder(sx,sy,9,2,1);
+     sx=dx+2;
+     sy=dy+2;
+     if (!input(temp,7))
+       {
+       RestoreBackground();
+       MouseShow();
+       break;
+       }
+
+     //
+     // MOVE THE NAME AND ALLOCATE THE MEMORY!
+     //
+     switch(which)
+     {
+      case 1:
+       movedata(FP_SEG(temp),FP_OFF(temp),
+                (unsigned)MapFileHeader,FP_OFF(MapFileHeader->tnames[numtplanes]),8);
+       MMAllocate((memptr *)&Tinfo[numtplanes],tilenum);
+       for (i=0;i<tilenum;i++)
+         *(Tinfo[numtplanes]+i)=0;
+       MapFileHeader->numtplanes=++numtplanes;
+       writeH=DirtyFlag=1;
+       break;
+
+      case 2:
+       movedata(FP_SEG(temp),FP_OFF(temp),
+                (unsigned)MapFileHeader,FP_OFF(MapFileHeader->tmnames[numtmplanes]),8);
+       MMAllocate((memptr *)&TMinfo[numtmplanes],tilemnum);
+       for (i=0;i<tilemnum;i++)
+         *(TMinfo[numtmplanes]+i)=0;
+       MapFileHeader->numtmplanes=++numtmplanes;
+       writeH=DirtyFlag=1;
+     }
+
+     RestoreBackground();
+     MouseShow();
+     break;
+
+   //
+   // DELETE
+   //
+   case 2:
+     {
+      unsigned ox,oy,i,oktoexit=0;
+      int which;
+
+      redo:
+
+      MouseHide();
+      DrawDialog(&TINd2,1);
+      GetDialogXY(&TINd2,&sx,&sy);
+      ox=sx;
+      oy=sy;
+      DrawBorder(sx,sy+2,10,11,1);
+      sx=ox;
+      sy=oy;
+      DrawBorder(sx+11,sy+2,10,11,1);
+
+      for (i=0;i<10;i++)
+      {
+       sx=ox+1;
+       sy=oy+i+3;
+       fprint(MapFileHeader->tnames[i]);
+       sx=ox+12;
+       sy=oy+i+3;
+       fprint(MapFileHeader->tmnames[i]);
+      }
+      MouseShow();
+
+      do
+      {
+       if ((which=CheckList(ox+1,oy+3,8,numtplanes,TInfoNon,TInfoNoff,0))>=0)
+        {
+         int reply;
+
+         RestoreBackground();
+         reply=DoDialog(&AreSureD2);
+         switch(reply)
+         {
+          case 0:
+          case 2:
+            goto redo;
+         }
+
+         if (which!=numtplanes-1)
+           {
+            for (i=0;i<8;i++)
+              {
+               MapFileHeader->tnames[which][i]=MapFileHeader->tnames[numtplanes-1][i];
+               MapFileHeader->tnames[numtplanes-1][i]=0;
+              }
+            for (i=0;i<tilenum;i++)
+              *(Tinfo[which]+i)=*(Tinfo[numtplanes-1]+i);
+            MMFreePtr((memptr *)&Tinfo[numtplanes-1]);
+           }
+         else
+           {
+            MMFreePtr((memptr *)&Tinfo[which]);
+            for (i=0;i<8;i++)
+              MapFileHeader->tnames[which][i]=0;
+           }
+         writeH=DirtyFlag=1;
+         MapFileHeader->numtplanes=--numtplanes;
+         goto redo;
+        }
+
+       if ((which=CheckList(ox+12,oy+3,8,numtmplanes,TInfoMNon,TInfoMNoff,0))>=0)
+        {
+         int reply;
+
+         RestoreBackground();
+         reply=DoDialog(&AreSureD2);
+         switch(reply)
+         {
+          case 0:
+          case 2:
+            goto redo;
+         }
+
+         if (which!=numtmplanes-1)
+           {
+            for (i=0;i<8;i++)
+              {
+               MapFileHeader->tmnames[which][i]=MapFileHeader->tmnames[numtplanes-1][i];
+               MapFileHeader->tmnames[numtmplanes-1][i]=0;
+              }
+            for (i=0;i<tilemnum;i++)
+              *(TMinfo[which]+i)=*(TMinfo[numtmplanes-1]+i);
+            MMFreePtr((memptr *)&TMinfo[numtmplanes-1]);
+           }
+         else
+           {
+            MMFreePtr((memptr *)&TMinfo[which]);
+            for (i=0;i<8;i++)
+              MapFileHeader->tmnames[which][i]=0;
+           }
+         writeH=DirtyFlag=1;
+         MapFileHeader->numtmplanes=--numtmplanes;
+         goto redo;
+        }
+
+       GetButtonXY(&TINd2,0,&sx,&sy);
+       if (!CheckList(sx,sy,6,1,TIDoneOn,TIDoneOff,1))
+        oktoexit++;
+
+       if (keydown[1])
+        {
+         while(keydown[1]);
+         oktoexit++;
+        }
+      }while(!oktoexit);
+
+      RestoreBackground();
+     }
+  }
+ }
+}
+
+
+
+////////////////////////////////////////////////////
+//
+// Item - Project Re-Select
+//
+////////////////////////////////////////////////////
+btype NGBb[]={{" Do It! ",1,4,2},
+             {" No! Help! ",16,4,1}};
+DialogDef NGBd={"Are you sure you want to\n"
+               "switch projects? Abort now\n"
+               "or forever hold your peace!",
+               28,6,2,&NGBb[0],NULL};
+
+void Item_ProjectReSelect(void)
+{
+ int i,which;
+
+ //
+ // ARE YOU SURE?!
+ //
+ which=DoDialog(&NGBd);
+ if (!which || which==2)
+   return;
+
+
+ TEDInfo->lastvid=videomode;
+ TEDInfo->level=whichmap;
+ SaveTEDInfo();
+ SaveOutputHeader();
+
+ if (!CheckForMapSave())
+   return;
+
+ //
+ // RELEASE ALL MEMORY
+ //         ---
+ if (MapBkgnd)
+   {
+    MMFreePtr((memptr *)&MapBkgnd);
+    MMFreePtr((memptr *)&CutBkgnd);
+   }
+ if (MapFrgnd)
+   {
+    MMFreePtr((memptr *)&MapFrgnd);
+    MMFreePtr((memptr *)&CutFrgnd);
+   }
+ if (MapInfoPl)
+   {
+    MMFreePtr((memptr *)&MapInfoPl);
+    MMFreePtr((memptr *)&CutInfoPl);
+   }
+
+ MMFreePtr((memptr *)&TEDInfo);
+ MMFreePtr((memptr *)&MapFileHeader);
+
+ if (CgaXMS)
+   {
+    MMFreePtr((memptr *)&CgaXMSlookup);
+    XMSFreeMem(CgaXMS);
+   }
+ if (EgaXMS)
+   {
+    MMFreePtr((memptr *)&EgaXMSlookup);
+    XMSFreeMem(EgaXMS);
+   }
+ if (VgaXMS)
+   {
+    MMFreePtr((memptr *)&VgaXMSlookup);
+    XMSFreeMem(VgaXMS);
+   }
+ if (XMSmaps)
+   XMSFreeMem(XMSmaps);
+
+ XMSmaps=CgaXMS=EgaXMS=VgaXMS=xmshandle=0;
+
+
+ for (i=0;i<numtplanes;i++)
+   if (Tinfo[i])
+     MMFreePtr((memptr *)&Tinfo[i]);
+ for (i=0;i<numtmplanes;i++)
+   if (TMinfo[i])
+     MMFreePtr((memptr *)&TMinfo[i]);
+
+ //
+ // FORCE RE-INIT
+ //
+ writeH=TIxbase=TIxmbase=TIybase=TIymbase=PasteOK=DirtyFlag=ext[0]=0;
+ lastmap=-1;
+
+ FindGraphFile();
+ LoadInfoFile();
+ LoadMapHeader();
+ LoadGraphStuff(0,videomode);
+ MouseHide();
+ RedrawDesktop();
+ MouseShow();
+ DrawInfoBar();
+ DrawMap();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Toggle GRIDMODE on/off
+//
+////////////////////////////////////////////////////
+void Item_GridMode(void)
+{
+ GridMode^=1;
+
+ if (PasteMode)
+   DrawFloatPaste();
+
+ DrawMap();
+ DrawInfoBar();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Toggle SNAP-PASTE on/off
+//
+////////////////////////////////////////////////////
+void Item_SnapTog(void)
+{
+ if (!PasteMode)
+   return;
+
+ EraseFloatPaste();
+ SnapMode^=1;
+
+ snapx=(pixelx>>(tsize+2))+xbase;
+ snapy=((pixely-8)>>(tsize+2))+ybase;
+ snapxsize=TileCopy.w;
+ snapysize=TileCopy.h;
+
+ snapx=snapx-(snapx/snapxsize)*snapxsize;
+ snapy=snapy-(snapy/snapysize)*snapysize;
+
+ DrawInfoBar();
+ DrawFloatPaste();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - View Map & Goto
+//
+////////////////////////////////////////////////////
+void Item_ViewMap(void)
+{
+ Do_ViewMap(0);
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Review Map & Goto
+//
+////////////////////////////////////////////////////
+void Item_ReviewMap(void)
+{
+ Do_ViewMap(1);
+}
+
+
+////////////////////////////////////////////////////
+//
+// Code to actually do the ViewMap (and save it in
+// EGA memory when finished).
+// Entry:
+// 0 = ViewMap, as normal & save when done (but only
+//     if a full map was viewed)
+// 1 = RestoreMap for GOTO
+//
+////////////////////////////////////////////////////
+void Do_ViewMap(int how)
+{
+ int _seg *a_bg,_seg *a_fg,_seg *a_in,CopyArea,bl_width,bl_height,bl_x,bl_y,p_info;
+
+ char huge *EGA=MK_FP(0xa000,0);
+ char _seg *block,_seg *gblock[4];
+ int i,j,k,m,n,pwidth,lwidth,maptype,step,pixnum[4]={0,8,16,32},curpix,
+         maxpack,curline,lybase,t8=8<<(tsize-1),t1=1<<(tsize-1),scrn_h,scrn_w;
+ long tilelen,bufsize;
+ int savevideo;
+
+
+
+ savevideo=videomode;
+ MouseHide();
+ setvideo(EGA1);
+ MouseShow();
+ if (videomode!=EGA1 && videomode!=EGA2)
+ {
+  ErrDialog("This function is currently\n"
+                "only usable in EGA mode!"," OK ");
+  return;
+ }
+
+ //
+ // SCREEN DIMENSIONS
+ //
+ scrn_w=320;
+ scrn_h=200;
+
+
+ bl_x=bl_y=0;
+ bl_width=mapwidth;
+ bl_height=mapheight;
+ a_bg=MapBkgnd;
+ a_fg=MapFrgnd;
+ a_in=MapInfoPl;
+ p_info=MapFileHeader->maptype;
+ CopyArea=0;
+
+ if ((TileCopy.w>screenw || TileCopy.h>screenh) && !how)
+       if (Message("\"Yes\" to display full map,\n"
+                        "\"No\" to display COPY buffer.")==1)
+       {
+        bl_x=TileCopy.x;
+        bl_y=TileCopy.y;
+        bl_width=TileCopy.w;
+        bl_height=TileCopy.h;
+        a_bg=CutBkgnd;
+        a_fg=CutFrgnd;
+        a_in=CutInfoPl;
+        p_info=TileCopy.PlanesCopied;
+        CopyArea=1;
+       }
+
+ //
+ // VALIDATE WIDTH & HEIGHT
+ //
+ if (bl_height<screenh && bl_width<screenw)
+ {
+  ErrDialog("The area fits within the\n"
+                "screen! Forget it!"," Wah! ");
+  return;
+ }
+
+
+ //
+ // FIGURE OUT THE BEST RATIO FOR CONVERSION
+ //
+ if (!how)
+       switch(bl_width>=bl_height)
+       {
+        case 1: // WIDTH > HEIGHT
+               step=(float)(pixnum[tsize]*bl_width)/scrn_w+.5;
+               if (pixnum[tsize]*bl_width/step>scrn_w)
+       step++;
+               if ((float)(pixnum[tsize]*bl_height)/step+.5<scrn_h)
+       break;
+
+        case 0: // HEIGHT > WIDTH
+               step=(float)(pixnum[tsize]*bl_height)/scrn_h+.5;
+               if (pixnum[tsize]*bl_height/step>scrn_h)
+       step++;
+       }
+ else
+       step=VMapData.step;
+
+
+ //
+ // POP LAST MAP ON SCREEN
+ //
+ if (how)
+ {
+  unsigned EGAseg=VMapData.EGAseg;
+
+  if (!VMapData.built_flag)
+  {
+       ErrDialog("You haven't previously\n"
+                 "VIEWed a map!"," OK ");
+       return;
+  }
+
+  //
+  // RESTORE MAP IN MEMORY!
+  //
+  MouseHide();
+  outport(GCindex,GCmode | 0x100);
+  outport(SCindex,SCmapmask | 0xf00);
+  asm  push    ds
+  asm  mov     ax,[EGAseg]
+  asm  mov     ds,ax
+  asm  mov     ax,0xa000
+  asm  mov     es,ax
+  asm  xor     si,si
+  asm  xor     di,di
+  asm  mov     cx,0x2000
+  asm  rep movsb
+  asm  pop     ds
+  step=VMapData.step;
+  maxpack=VMapData.maxpack;
+  MouseShow();
+ }
+ //
+ // BUILD MAP
+ //
+ else
+ {
+  //
+  // CLEAR EGA SCREEN
+  //
+  outport(GCindex,GCmode);
+  outport(SCindex,SCmapmask | 0xf00);
+  _fmemset(MK_FP(0xa000,0),0,0x2000);
+
+  //
+  // SET TILE LENGTH
+  //
+  switch(tsize)
+  {
+       case 1: tilelen=32L; break;
+       case 2: tilelen=128L; break;
+       case 3: tilelen=512L;
+  }
+
+  //
+  // ALLOCATE TEMP BUFFERS & BEGIN!
+  //
+  bufsize=tilelen*bl_width;
+  pwidth=t1*bl_width;
+  lwidth=pwidth*4;
+  MMAllocate((memptr *)&block,bufsize);
+  maxpack=pwidth/step+1;
+  for (i=0;i<4;i++)
+        MMAllocate((memptr *)&gblock[i],maxpack);
+
+  outport(GCindex,GCmode);
+  curline=0;
+  for (j=bl_y;j<bl_y+bl_height;j++)
+  {
+       lybase=j*t8;
+       for (i=bl_x;i<bl_x+bl_width;i++)
+       {
+        unsigned tilet,tilem,tilei,loc;
+
+        //
+        // ESC out?
+        //
+        if (keydown[1])
+        {
+         while(keydown[1]);
+         setvideo(savevideo);
+         RedrawDesktop();
+         DrawMap();
+         DrawInfoBar();
+         return;
+        }
+        //
+        // GET THE CORRECT TILE MOVED INTO "TDATA"
+        //
+        loc=j*mapwidth+i;
+        tilet=viewton?((p_info&BPLANE)?a_bg[loc]:-BkgndColor):-BkgndColor;
+        tilem=viewmon?((p_info&FPLANE)?a_fg[loc]+tilenum:0):0;
+        tilei=viewion?((p_info&IPLANE)?a_in[loc]+tilenum:0):0;
+        CombineTiles(tilet,tilem,tilei,tsize);
+
+        //
+        // NOW, MUNGE "TDATA" INTO BIT-PLANES!
+        //
+        // INTERNAL:           P0      P1      P2      P3
+        //     SCANLINE x      ......  ......  ......  ......
+        //
+        for (k=0;k<t8;k++)
+               if (!((lybase+k)%step))
+       for (m=0;m<4;m++)
+         movedata(FP_SEG(&tdata),FP_OFF(&tdata)+(m*tsize*t8)+k*t1,
+                        (unsigned)block,k*lwidth+m*pwidth+(i-bl_x)*t1,t1);
+       }
+
+       //
+       // CONVERT BIT-PLANE LINES TO COMPRESSED FORM...
+       //
+       for (k=0;k<8<<(tsize-1);k++)
+       {
+        if (!((lybase+k)%step))
+        {
+         int midx=k*lwidth;
+
+
+         curpix=0;
+         _fmemset(gblock[0],0,maxpack);
+         _fmemset(gblock[1],0,maxpack);
+         _fmemset(gblock[2],0,maxpack);
+         _fmemset(gblock[3],0,maxpack);
+         for (m=0;m<pwidth*8;m++)
+         {
+               if (!(m%step))
+               {
+                int temp=curpix/8,
+               temp1=7-(curpix%8),
+               temp2=7-(m%8),
+               idx;
+
+
+                idx=midx+m/8;
+
+                #if 1
+                asm    push    ds
+
+                asm    mov     ds,[block]
+                asm    mov     si,[idx]
+                asm    mov     cl,[BYTE PTR temp2]
+                asm    mov     ch,[BYTE PTR temp1]
+                asm    mov     di,[temp]
+                asm    mov     dx,[pwidth]
+                asm    dec     dx
+
+                asm    mov     es,[WORD PTR gblock]
+
+                asm    lodsb
+                asm    shr     al,cl
+                asm    and     al,1
+                asm    xchg    ch,cl
+                asm    shl     al,cl
+                asm    xchg    ch,cl
+                asm    or      [es:di],al
+
+                asm    add     si,dx
+
+                asm    mov     es,[WORD PTR gblock+2]
+
+                asm    lodsb
+                asm    shr     al,cl
+                asm    and     al,1
+                asm    xchg    ch,cl
+                asm    shl     al,cl
+                asm    xchg    ch,cl
+                asm    or      [es:di],al
+
+                asm    add     si,dx
+
+                asm    mov     es,[WORD PTR gblock+4]
+
+                asm    lodsb
+                asm    shr     al,cl
+                asm    and     al,1
+                asm    xchg    ch,cl
+                asm    shl     al,cl
+                asm    xchg    ch,cl
+                asm    or      [es:di],al
+
+                asm    add     si,dx
+
+                asm    mov     es,[WORD PTR gblock+6]
+
+                asm    lodsb
+                asm    shr     al,cl
+                asm    and     al,1
+                asm    xchg    ch,cl
+                asm    shl     al,cl
+                asm    xchg    ch,cl
+                asm    or      [es:di],al
+
+                asm    add     si,dx
+
+                asm    pop     ds
+
+                #else
+                *(gblock[0]+temp)|=((block[idx]>>temp2)&1)<<temp1;
+                *(gblock[1]+temp)|=((block[idx+pwidth]>>temp2)&1)<<temp1;
+                *(gblock[2]+temp)|=((block[idx+pwidth*2]>>temp2)&1)<<temp1;
+                *(gblock[3]+temp)|=((block[idx+pwidth*3]>>temp2)&1)<<temp1;
+                #endif
+
+                curpix++;
+               }
+         }
+
+         //
+         // BLAST ONTO THE SCREEN
+         //
+
+         MouseHide();
+         for (n=0;n<4;n++)
+         {
+               outport(SCindex,SCmapmask | (0x100<<n));
+               for (m=0;m<maxpack;m++)
+       *(EGA+EGA1lookup[curline]+m)=*(gblock[n]+m);
+     }
+     MouseShow();
+
+     curline++;
+    }
+   }
+  }
+
+  MMFreePtr((memptr *)&block);
+  for(m=0;m<4;m++)
+    MMFreePtr((memptr *)&gblock[m]);
+
+
+  //
+  // SAVE MAP IN MEMORY!
+  //
+  if (!CopyArea)
+  {
+   unsigned EGAseg=0xa800;
+
+
+   MouseHide();
+   outport(GCindex,GCmode | 0x100);
+   outport(SCindex,SCmapmask | 0xf00);
+   asm push    ds
+   asm mov     ax,[EGAseg]
+   asm mov     es,ax
+   asm mov     ax,0xa000
+   asm mov     ds,ax
+   asm xor     si,si
+   asm xor     di,di
+   asm mov     cx,0x2000
+   asm rep movsb
+   asm pop     ds
+   VMapData.step=step;
+   VMapData.built_flag=1;
+   VMapData.EGAseg=EGAseg;
+   VMapData.maxpack=maxpack;
+   MouseShow();
+  }
+ }
+
+
+ //
+ // DONE WITH MAP BUILD-N-DISPLAY
+ //
+ SignalSound();
+ clearkeys();
+
+ //
+ // IF MOUSE BUTTON PRESSED WITHIN REGION, GO THERE!
+ //
+ while(!bioskey(1))
+   if (MouseButton())
+   {
+    int x,y;
+
+    MouseCoords(&x,&y);
+    if (x<maxpack*8 && y<(mapheight*t8/step) && !CopyArea)
+    {
+     xbase=(x*step)/t8-screenw/2;
+     ybase=(y*step)/t8-screenh/2;
+     if (xbase+screenw>mapwidth)
+       xbase=mapwidth-screenw;
+     if (ybase+screenh>mapheight)
+       ybase=mapheight-screenh;
+     if (xbase<0)
+       xbase=0;
+     if (ybase<0)
+       ybase=0;
+    }
+    while(MouseButton());
+    break;
+   }
+
+ clearkeys();
+ MouseHide();
+ setvideo(savevideo);
+ RedrawDesktop();
+ DrawMap();
+ DrawInfoBar();
+ MouseShow();
+}
+
+
+////////////////////////////////////////////////////
+//
+// MAP IMPORTING FUNCTIONS FOLLOW:
+//
+////////////////////////////////////////////////////
+char _seg *oldnames,oldmapname[64],oldmapheadname[64],
+       oldSM_name[64],oldSM_loadname[64];
+
+int IM_swapin(void)
+{
+ int i;
+
+
+ _fstrcpy(mapheadname,TEDInfo->ImportPath);
+ strcat(mapheadname,oldmapheadname);
+ if (access(mapheadname,0))
+   {
+    strcpy(mapheadname,oldmapheadname);
+    return 0;
+   }
+
+ _fstrcpy(mapname,TEDInfo->ImportPath);
+ strcat(mapname,oldmapname);
+
+
+ _fstrcpy(SM_name,TEDInfo->ImportPath);
+ strcat(SM_name,oldSM_name);
+
+ _fstrcpy(SM_loadname,TEDInfo->ImportPath);
+ strcat(SM_loadname,oldSM_loadname);
+
+ MMAllocate((memptr *)&oldnames,100*16);
+ movedata(FP_SEG(MapNames),FP_OFF(MapNames),(unsigned)oldnames,0,100*16);
+
+ MMFreePtr((memptr *)&MapFileHeader);
+
+ LoadIn(mapheadname,(memptr *)&MapFileHeader);
+
+ for (i=0;i<100;i++)
+   if (MapFileHeader->dataoffsets[i]>=0)
+   {
+    MapHeaderStr TempHead;
+
+    LoadFile(mapname,(char huge *)&TempHead,MapFileHeader->dataoffsets[i],sizeof(MapHeaderStr));
+    strcpy(MapNames[i],TempHead.name);
+   }
+ return 1;
+}
+
+
+void IM_swapout(void)
+{
+ if (oldnames)         // GET RID OF MAPNAMES
+ {
+  strcpy(mapname,oldmapname);
+  strcpy(mapheadname,oldmapheadname);
+  strcpy(SM_name,oldSM_name);
+  strcpy(SM_loadname,oldSM_loadname);
+
+  movedata((unsigned)oldnames,0,FP_SEG(MapNames),FP_OFF(MapNames),100*16);
+  MMFreePtr((memptr *)&oldnames);
+  MMFreePtr((memptr *)&MapFileHeader);
+  LoadIn(mapheadname,(memptr *)&MapFileHeader);
+
+ }
+}
+
+void IM_LoadMap(void)
+{
+ unsigned long csize,size=0;
+ memptr block;
+
+ //
+ // DEALLOCATE ALL CURRENT MAP MEMORY
+ //
+ if (MapBkgnd)
+   {
+    MMFreePtr((memptr *)&MapBkgnd);
+    MMFreePtr((memptr *)&CutBkgnd);
+   }
+ if (MapFrgnd)
+   {
+    MMFreePtr((memptr *)&MapFrgnd);
+    MMFreePtr((memptr *)&CutFrgnd);
+   }
+ if (MapInfoPl)
+   {
+    MMFreePtr((memptr *)&MapInfoPl);
+    MMFreePtr((memptr *)&CutInfoPl);
+   }
+
+ //
+ // LOAD MAP HEADER
+ //
+ LoadFile(mapname,(char huge *)&MapHeader,MapFileHeader->dataoffsets[whichmap],sizeof(MapHeaderStr));
+
+ //
+ // LOAD & DECOMPRESS MAP PLANES
+ //
+ if (MapFileHeader->maptype & BPLANE)
+   {
+    LoadFile(mapname,(char huge *)&size,MapHeader.mapbkgndpl,2);
+
+    MMAllocate((memptr *)&MapBkgnd,size);
+    MMAllocate((memptr *)&CutBkgnd,size);
+    csize=MapHeader.mapbkgndlen-2;
+    MMAllocate(&block,csize);
+
+    LoadFile(mapname,MK_FP(block,0),MapHeader.mapbkgndpl+2,csize);
+
+    RLEWExpand(MK_FP(block,0),MK_FP(MapBkgnd,0),size,MapFileHeader->RLEWtag);
+    MMFreePtr(&block);
+   }
+ if (MapFileHeader->maptype & FPLANE)
+   {
+    LoadFile(mapname,(char huge *)&size,MapHeader.mapfrgndpl,2);
+
+    MMAllocate((memptr *)&MapFrgnd,size);
+    MMAllocate((memptr *)&CutFrgnd,size);
+    csize=MapHeader.mapfrgndlen-2;
+    MMAllocate(&block,csize);
+
+    LoadFile(mapname,MK_FP(block,0),MapHeader.mapfrgndpl+2,csize);
+
+    RLEWExpand(MK_FP(block,0),MK_FP(MapFrgnd,0),size,MapFileHeader->RLEWtag);
+    MMFreePtr(&block);
+   }
+ if (MapFileHeader->maptype & IPLANE)
+   {
+    LoadFile(mapname,(char huge *)&size,MapHeader.mapinfopl,2);
+
+    MMAllocate((memptr *)&MapInfoPl,size);
+    MMAllocate((memptr *)&CutInfoPl,size);
+    csize=MapHeader.mapinfolen-2;
+    MMAllocate(&block,csize);
+
+    LoadFile(mapname,MK_FP(block,0),MapHeader.mapinfopl+2,csize);
+
+    RLEWExpand(MK_FP(block,0),MK_FP(MapInfoPl,0),size,MapFileHeader->RLEWtag);
+    MMFreePtr(&block);
+   }
+}
+
+
+void IM_SaveMap(void)
+{
+ memptr block;
+ long fsize,size,nsize,change;
+ MapHeaderStr TempHeader;
+ int i,XMStemp;
+ char string[100],TEDid[]=IDSTRING;
+
+
+
+ strcpy(string,"Saving Map, '");
+ strcat(string,MapHeader.name);
+
+ strcat(string,"'.");
+ ErrDialog(string,"");
+
+ //
+ // SAVE MAP FILE HEADER
+ //
+ SaveFile(mapheadname,MK_FP(MapFileHeader,0),0,sizeof(MapFileHeaderStr));
+ fsize=sizeof(MapFileHeaderStr);
+
+ //
+ // COMPRESS & SAVE TILEINFOS
+ //
+ for (i=0;i<numtplanes;i++)
+   {
+    MMAllocate(&block,tilenum);
+    MapFileHeader->tileinfooff[i]=fsize;
+    nsize=RLEBCompress(MK_FP(Tinfo[i],0),tilenum,MK_FP(block,0),MapFileHeader->RLEWtag);
+    MapFileHeader->tileinfolen[i]=nsize;
+    SaveFile(mapheadname,MK_FP(block,0),fsize,nsize);
+    fsize+=nsize;
+    MMFreePtr(&block);
+   }
+
+ for (i=0;i<numtmplanes;i++)
+   {
+    MMAllocate(&block,tilemnum);
+    MapFileHeader->tileinfomoff[i]=fsize;
+    nsize=RLEBCompress(MK_FP(TMinfo[i],0),tilemnum,MK_FP(block,0),MapFileHeader->RLEWtag);
+    MapFileHeader->tileinfomlen[i]=nsize;
+    SaveFile(mapheadname,MK_FP(block,0),fsize,nsize);
+    fsize+=nsize;
+    MMFreePtr(&block);
+   }
+
+ MapFileHeader->oldtilenum=tilenum;
+ MapFileHeader->oldtilemnum=tilemnum;
+
+ SaveFile(mapheadname,MK_FP(MapFileHeader,2),2,sizeof(MapFileHeaderStr)-2);
+ //
+ // SAVE ALREADY COMPRESSED MAPS
+ //
+
+ //
+ // NOTE: I AM STORING "TED5" AT THE START OF THE FILE BECAUSE
+ // SAVING THE FILE AT OFFSET 0 WILL TRASH IT (I HAVE TO RE-SAVE THE HEADER!)
+ //
+ SaveFile(SM_name,(char huge *)TEDid,0,strlen(TEDid));
+ fsize=strlen(TEDid);
+
+ for (i=0;i<100;i++)
+ {
+  long oldoff;
+
+  if (MapFileHeader->dataoffsets[i]==-1 || i==whichmap)
+    continue;
+
+  oldoff=MapFileHeader->dataoffsets[i];
+
+  LoadFile(SM_loadname,(char huge *)&TempHeader,oldoff,sizeof(MapHeaderStr));
+
+  strcpy(TempHeader.name,MapNames[i]);
+  MapFileHeader->dataoffsets[i]=fsize;
+  size=TempHeader.mapbkgndlen+TempHeader.mapfrgndlen+TempHeader.mapinfolen;
+  change=TempHeader.mapbkgndpl-fsize-sizeof(MapHeaderStr);
+  TempHeader.mapbkgndpl-=change;
+  TempHeader.mapfrgndpl-=change;
+  TempHeader.mapinfopl-=change;
+
+  SaveFile(SM_name,(char huge *)&TempHeader,fsize,sizeof(MapHeaderStr));
+  fsize+=sizeof(MapHeaderStr);
+
+  MMAllocate(&block,size);
+  LoadFile(SM_loadname,MK_FP(block,0),oldoff+sizeof(MapHeaderStr),size);
+  SaveFile(SM_name,MK_FP(block,0),fsize,size);
+  fsize+=size;
+  SaveFile(SM_name,"!ID!",fsize,4);
+  fsize+=4;
+  MMFreePtr(&block);
+ }
+
+ //
+ // SAVE CURRENT MAP AT END OF FILE
+ //
+ MapFileHeader->dataoffsets[whichmap]=fsize;
+ MapFileHeader->datalengths[whichmap]=sizeof(MapHeaderStr);
+ SaveFile(SM_name,(char huge *)&MapHeader,fsize,sizeof(MapHeaderStr));
+ fsize+=sizeof(MapHeaderStr);
+
+ size=MapHeader.width*MapHeader.height*sizeof(int);
+ MMAllocate(&block,size);
+ if (MapFileHeader->maptype & BPLANE)
+   {
+    MapHeader.mapbkgndpl=fsize;
+    nsize=RLEWCompress(MK_FP(MapBkgnd,0),size,MK_FP(block,0),MapFileHeader->RLEWtag);
+    MapHeader.mapbkgndlen=nsize+2;
+
+    SaveFile(SM_name,(char huge *)&size,fsize,2);
+    fsize+=2;
+    SaveFile(SM_name,MK_FP(block,0),fsize,nsize);
+    fsize+=nsize;
+   }
+ else
+   MapHeader.mapbkgndlen=0;
+
+ if (MapFileHeader->maptype & FPLANE)
+   {
+    MapHeader.mapfrgndpl=fsize;
+    nsize=RLEWCompress(MK_FP(MapFrgnd,0),size,MK_FP(block,0),MapFileHeader->RLEWtag);
+    MapHeader.mapfrgndlen=nsize+2;
+
+    SaveFile(SM_name,(char huge *)&size,fsize,2);
+    fsize+=2;
+    SaveFile(SM_name,MK_FP(block,0),fsize,nsize);
+    fsize+=nsize;
+   }
+ else
+   MapHeader.mapfrgndlen=0;
+
+ if (MapFileHeader->maptype & IPLANE)
+   {
+    MapHeader.mapinfopl=fsize;
+    nsize=RLEWCompress(MK_FP(MapInfoPl,0),size,MK_FP(block,0),MapFileHeader->RLEWtag);
+    MapHeader.mapinfolen=nsize+2;
+
+    SaveFile(SM_name,(char huge *)&size,fsize,2);
+    fsize+=2;
+    SaveFile(SM_name,MK_FP(block,0),fsize,nsize);
+    fsize+=nsize;
+   }
+ else
+   MapHeader.mapinfolen=0;
+
+ SaveFile(SM_name,"!ID!",fsize,4);
+
+ fsize+=4;
+
+ MMFreePtr(&block);
+
+ // RE-SAVE HEADER
+ SaveFile(SM_name,(char huge *)&MapHeader,
+     MapFileHeader->dataoffsets[whichmap],sizeof(MapHeaderStr));
+
+ //
+ // RE-SAVE FILE HEADER
+ // NOTE: The "2" is so MSDOS doesn't truncate the fucking file!
+ //
+ SaveFile(mapheadname,MK_FP(MapFileHeader,2),2,sizeof(MapFileHeaderStr)-2);
+
+ unlink(SM_loadname);
+ rename(SM_name,SM_loadname);
+
+ RestoreBackground();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Import Maps
+//
+////////////////////////////////////////////////////
+btype IMPMb[]={{"New Path",3,2,1},
+              {" Import ",3,5,1},
+              {"  Exit  ",3,8,2}};
+DialogDef IMPMd={"Map Importing",13,11,3,&IMPMb[0],NULL};
+btype NPb={"                                    ",1,3,1};
+DialogDef NPd={"Current Path:",38,5,1,&NPb,NULL};
+
+
+void Item_ImportMaps(void)
+{
+ char imfile[64],tempstr[40],impath[64];
+ int oldwhichmap,which,mapnum,i;
+ int oldxb,oldyb;
+
+
+ CheckForMapSave();
+
+ //
+ // THE IMPORT FUNCTION WILL RID THE SYSTEM OF XMSMAPS
+ //
+ if (XMSmaps)
+ {
+  XMSFreeMem(XMSmaps);
+  XMSmaps=0;
+ }
+
+ //
+ // SAVE PATHS
+ //
+ _fstrcpy(impath,TEDInfo->ImportPath);
+
+ strcpy(oldmapname,mapname);
+ strcpy(oldmapheadname,mapheadname);
+ strcpy(oldSM_name,SM_name);
+ strcpy(oldSM_loadname,SM_loadname);
+
+ oldxb=xbase;
+ oldyb=ybase;
+ #pragma warn -sus
+ oldnames=0;
+ #pragma warn +sus
+ oldwhichmap=whichmap;
+
+ DrawDialog(&IMPMd,1);
+ while(1)
+ {
+  which=CheckButtons(&IMPMd);
+  switch(which)
+  {
+   //
+   // NEW PATH
+   //
+   case 1:
+     MouseHide();
+     DrawDialog(&NPd,1);
+     GetDialogXY(&NPd,&sx,&sy);
+     sy++;
+     sx++;
+     if (!impath[0])
+       print("- current dir -");
+     else
+       print(impath);
+     GetButtonXY(&NPd,0,&sx,&sy);
+     if (input(tempstr,36))
+       {
+       strcpy(impath,tempstr);
+       if (impath[strlen(impath)-1]!='\\')
+         strcat(impath,"\\");
+
+       MouseShow();
+       if (access(mapheadname,0))
+       {
+        ErrDialog("Can't find any TED5\n"
+                  "map files at that path."," OK ");
+       }
+       else
+       {
+        RestoreBackground();
+        ErrDialog("Verifying path...","");
+        _fstrcpy(TEDInfo->ImportPath,impath);
+        DirtyFlag=1;
+       }
+
+       MouseHide();
+       }
+     MouseShow();
+     RestoreBackground();
+     break;
+
+   //
+   // IMPORT
+   //
+   case 2:
+     if (!oldnames)
+     {
+      ErrDialog("Loading File Info...","");
+      if (!IM_swapin())
+      {
+       RestoreBackground();
+       ErrDialog("Having problems with your path!"," OK ");
+       break;
+      }
+      RestoreBackground();
+     }
+
+     mapnum=SelectMap(1,CREATED,"TO IMPORT");
+     if (mapnum>=0)
+     {
+      char check[100]="Are you SURE you want to\n"
+                     "Import ";
+
+      strcat(check,MapNames[mapnum]);
+      strcat(check,"?");
+      if (Message(check)<2)
+       break;
+
+      whichmap=mapnum;
+      ErrDialog("Importing. One moment.","");
+      IM_LoadMap();
+      IM_swapout();
+      IM_SaveMap();
+      IM_swapin();
+      RestoreBackground();
+     }
+     break;
+
+   //
+   // EXIT
+   //
+   case 0:
+   case 3:
+     RestoreBackground();
+     whichmap=oldwhichmap;
+     IM_swapout();
+
+     LoadMap(whichmap);
+     xbase=oldxb;
+     ybase=oldyb;
+     DrawMap();
+
+     return;
+  }
+ }
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Visit DOS
+//
+////////////////////////////////////////////////////
+int olddisk;
+char oldpath[64]="\\";
+
+void Item_VisitDOS(void)
+{
+ TempStruct LaunchInfo;
+ char ename[64],temp[40],tiname[14]="TEDINFO.TMP";
+
+ long size;
+
+
+ //
+ // Save the handles for all XMS memory so we don't
+ // have to re-install this shit!
+ //
+ TEDInfo->OldCgaXMS=CgaXMS;
+ TEDInfo->OldEgaXMS=EgaXMS;
+ TEDInfo->OldVgaXMS=VgaXMS;
+
+ TEDInfo->OldCgaXMSsize=CgaXMSsize;
+ TEDInfo->OldEgaXMSsize=EgaXMSsize;
+ TEDInfo->OldVgaXMSsize=VgaXMSsize;
+
+ size=4L*(tilenum+tilemnum);
+ if (CgaXMS)
+   {
+    if (1024L*XMSTotalFree()<size)
+      {
+       XMSFreeMem(CgaXMS);
+       TEDInfo->OldCgaXMS=TEDInfo->OldCgaXMSsize=0;
+      }
+    else
+      {
+       TEDInfo->CgaXMSlook=XMSAllocate(size);
+       XMSmove(0,(long)MK_FP(CgaXMSlookup,0),TEDInfo->CgaXMSlook,0,size);
+      }
+   }
+
+ if (EgaXMS)
+   {
+    if (1024L*XMSTotalFree()<size)
+      {
+       XMSFreeMem(EgaXMS);
+       TEDInfo->OldEgaXMS=TEDInfo->OldEgaXMSsize=0;
+      }
+    else
+      {
+       TEDInfo->EgaXMSlook=XMSAllocate(size);
+       XMSmove(0,(long)MK_FP(EgaXMSlookup,0),TEDInfo->EgaXMSlook,0,size);
+      }
+   }
+
+ if (VgaXMS)
+   {
+    if (1024L*XMSTotalFree()<size)
+      {
+       XMSFreeMem(VgaXMS);
+       TEDInfo->OldVgaXMS=TEDInfo->OldVgaXMSsize=0;
+      }
+    else
+      {
+       TEDInfo->VgaXMSlook=XMSAllocate(size);
+       XMSmove(0,(long)MK_FP(VgaXMSlookup,0),TEDInfo->VgaXMSlook,0,size);
+      }
+   }
+
+ //
+ // SAVE CURRENT VIDEOMODE FOR LAUNCH RETURN
+ //
+ LaunchInfo.lastmode=videomode;
+ strcpy(LaunchInfo.ext,ext);
+ SaveFile(tiname,(char huge *)&LaunchInfo,0,sizeof(TempStruct));
+
+ TEDInfo->oscrx=xbase;
+ TEDInfo->oscry=ybase;
+ _fmemcpy((void far *)TEDInfo->parmstring,(void far *)parmstring,64);
+
+ Item_SaveMap();
+ SaveTEDInfo();
+ SaveOutputHeader();
+
+ if (XMSmaps)
+   XMSFreeMem(XMSmaps);
+
+ strcpy(temp,"Launching ");
+ _fstrcat((char far *)temp,(char far *)TEDInfo->launchname);
+ strcat(temp,"...");
+ ErrDialog(temp,"");
+ clearkeys();
+ nosound();
+ MouseHide();
+
+ _fmemcpy((char far *)ename,(char far *)TEDInfo->launchname,14);
+
+ RemoveUndoBuffers();
+ ShutdownKBD();
+
+ //
+ // ARE WE EXITING WITH A BATCH FILE?
+ //
+
+ setvideo(TEXT);
+ printf("The TED5 DOS shell. Type 'EXIT' to return to TED5.");
+
+ //
+ // SAVE CURRENT DRIVE & PATH
+ //
+ olddisk=getdisk();
+ getcurdir(0,oldpath+1);
+
+ MMShutdown();
+ fcloseall();
+ spawnlp(P_WAIT,"COMMAND",NULL);
+
+ //
+ // RESET OLD PATH
+ //
+ setdisk(olddisk);
+ chdir(oldpath);
+
+ execlp("TED5.EXE","TED5.EXE","/LAUNCH",NULL);
+
+ printf("Can't find TED5 for some reason!");
+ exit(1);
+}
+
+
+////////////////////////////////////////////////////
+//
+// Item - Paste Overlay toggle
+//
+////////////////////////////////////////////////////
+void Item_POtog(void)
+{
+ F3_flag^=1;
+
+ if (PasteMode)
+ {
+  EraseFloatPaste();
+  DrawFloatPaste();
+ }
+}
diff --git a/16/ted5/TED5.C b/16/ted5/TED5.C
new file mode 100755 (executable)
index 0000000..8614ef9
--- /dev/null
@@ -0,0 +1,2779 @@
+////////////////////////////////////////////////////
+//
+// TED 5
+// MultiVideo mode, MultiTile size, MultiMap editor
+// by John Romero (C) 1991 Id Software
+//
+// Development Log:
+// -------------------------------------------------
+// Mar 19 91 - Starting this thing! Getting it to
+//      compile with the JHUFF and MEM stuff.
+//
+// Mar 20 91 - Got the whole deal compiling and wrote
+//      the EGA drawchar routine and got most of
+//      Dialogs written!
+//
+// Mar 25 91 - Forgot some days in there! Got the XMS
+//      stuff going and started the big initialization
+//      part. Past init will be lots easier!
+//
+// Mar 30 91 - Got map selection and dimensioning and
+//      allocation done. Added more MENU abilities to
+//      allow more flexible dialogs.
+//
+// Apr  7 91 - Got project initialization done. Got
+//      tiles into XMS. Wrote XMS routines for all
+//      memory functions needed.
+//
+// Apr 12 91 - FINALLY got the maps loading and saving
+//      correctly - NO THANKS TO MR.C OVER THERE! You
+//      see, he can't remember whether his expansion
+//      routines use the compressed or expanded length
+//      and that was causing me quite a problem. Got
+//      it solved and the map shuffling shit works
+//      PERFECTLY now!  Got tile select in, map stats,
+//      and other stuff...
+//
+// Apr 19 91 - Got all 3 planes working (drawing,etc.)
+//      TileSelect screens jam...lots of little options
+//      thrown in... !!! I got my '75 Cougar !!!
+//
+// Apr 25 91 - Got map dimension changing done! Fixed
+//      some small bugs...had a WHOPPER of a fucking
+//      bug today ... I was overwriting the stack
+//      when the first background save happened. I'm SURE
+//      I allocated enough memory -- I don't know...
+//
+// Apr 27 91 - Map Edge Select works (for Copy) & now I
+//      draw a frame around the entire region.
+//
+// May 01 91 - Added a nice feature - retaining the Copy
+//      buffer wherever it may get toasted. Used XMS so
+//      I didn't chew mainmem. Also made it so you can
+//      turn the plane READ/WRITEs ON/OFF (obvious advantage).
+//      Got Copy/Paste from everywhere with FloatingPaste!
+//
+// May 03 91 - Got entering values for infoplane stuff & all
+//      that shit encompasses. Trying to get a cursor drawn
+//      (with backgrnd save/restore) in CGA & EGA3 modes.
+//      Wish me luck! ... FUCK IT! I removed EGA3 mode -- it
+//      was too much shit & kludgery to get a cursor going.
+//
+// May 08 91 - Well! Let's see...I got Huffman map compression
+//      done; wrote a MakeOBJ function that can be used within
+//      the Memory Manager or Standard Borland C. Added .OBJ
+//      generation to IGRAB. Started the function to generate
+//      graphic map dumps. Modified the MapHeader stuff more
+//      when John needed "extras".
+//
+// May 09 91 - Finished ILBM & Apple Preferred map dumps!
+//      Fixed a couple hidden bugs, made some things nicer,
+//      started on Flood Fill...
+//
+// May 11 91 - Got the TILEINFO/M stuff structured and loading
+//      and saving (with compression). Putting all the "hidden"
+//      commands in the menus...
+//
+// May 13 91 - Stuck in a PROJECT SELECT option (for the Keen2
+//      trilogy, it'll be nice).
+//
+// May 16 91 - Got all of TILEINFO stuff finished. Tom and
+//      Jason's first day! Tom BETAed IGRAB & TED5 big time.
+//      Had to basically dump the GraphHeaderStr and just
+//      make the ?GAHEAD.ext file all dataoffsets! (The simpler,
+//      the better!)
+//
+// May 19 91 - Almost got the Flood Fill mode working...Tom
+//      started drawing maps a little early & now I need to add
+//      a little kludge-fix to reformat his old maps...
+//
+// May 22 91 - Got AWESOME UNDO working ... fixed the nagging little
+//      paste/scrolling bug fixed (separated the PasteErase
+//      & PasteDraw routines) ... finished Block Fill ... fixed
+//      the floating paste/tile showthru bug ...
+//
+// May 27 91 - Basically finished up. Tom is BETAing now. I need
+//      to make SelectMap accept the arrows & make an array for
+//      the map names instead of the sorry way I'm doing it now.
+//
+// Jun 2  91 - Got level launching working!  Been working on
+//      TED5 and IGRAB docs and MUSE most of the time.
+//
+// Jun 18 91 - v0.13 because John C.'s system didn't have
+//      the SCmapmask set to 15 in CopyEGA!
+//
+// Jun 20 91 - v0.14: It's annoying to LAUNCH the game and come
+//      back at the top-left corner!
+//
+// Jun 26 91 - v0.17: Made LAUNCH with ICON CHANGE ctrl-alt-L
+//      because Tomshit was having problems...adding Unused Tile
+//      Scan...fixing a couple minor Tom-irritants...
+//
+// Jul 12 91 - v0.23: Made VGA & CGA work! Fixed a small
+//      bug with plane-on starting...added a GridMode for the
+//      FloatingPaste...XMS Map-Cache...now saves the Launchname
+//      in TEDINFO? so user program doesn't need to send anything
+//      back but /LAUNCHED...finally fixed nagging FloatingPaste
+//      multi-plane viewing bug...
+//
+// Jul 19 91 - v0.24: Changed TEDINFO structure and added GFXINFO
+//      to IGRAB. Got most all bugs out...lowercase input now...
+//
+// Jul 23 91 - v0.26: Only write out .H if it needs to...got the
+//      SnapPaste feature in that Tom wanted...
+//
+// Aug 08 91 - v0.28: I can't believe this shit! Mr. Tom decided
+//      to enter the value "0xF00D" into the map, which was my secret
+//      value for passing an ESC press back from "inputint". I made
+//      it a #define now!
+//
+// Aug 09 91 - v0.29: I FUCKING FRIED THE LIB_A.ASM & LIB.C FILES!
+//      THESE USED TO HOLD TED5'S TILE-DRAWING AND CGA/VGA ROUTINES!
+//      AAAARRRRGGGG!!!! Trying to recontruct the program. It'll
+//      take a bit (I was trying to fix a bug in EditMapNames).
+//
+// Aug 14 91 - v0.30: Just got finished fixing the FRIED SOURCE HELL!
+//
+// Aug 16 91 - v0.31: Heh heh, I added the ViewMap function!
+//
+// Aug 19 91 - v0.32: Added the MapImport function and it works! YES!
+//
+// Aug 22-23 - v0.35: Fixed a WHOLE BUNCH of little things and added
+//      some cool features like easier TILEINFO entering, default
+//      Import drive, F3 to toggle Paste Overlay, etc. Very nice now.
+//
+// Aug 24 91 - v0.38: Fixed a bug in passing multiple command-line
+//      parameters to LAUNCHed program. Let user enter new parms and
+//      a new launch name while in TED5.  Added the CarmackCompression
+//      and trashed the Huffman shit.
+//
+// Sep 07 91 - v0.40: Only ViewMap planes viewable instead of all; flag
+//     currently loaded map in SelectMap dialog; check NumIconRows for
+//     a bogus value for old TED5 compatibility; show map dimensions in
+//     ChangeMapEdges dialog; CTRL-ALT-arrows will go to map edges.
+//
+// Sep 12 91 - v0.41: Let user PERMANENTLY change the Launch icon. Also,
+//     the plane flags are always saved!
+//
+// Sep 27 91 - v0.43: Added REVIEW_MAP function. Fixed a hard-to-find bug
+//     in the BlockFill-with-pattern function.
+//
+// Sep 29 91 - v0.44: Fixed small annoying bug w/Flood-fill w/pattern.
+//
+// Oct 12 91 - v0.45: Added the PrintReport feature after Carmacizing
+//     all the maps.
+//
+// Nov 24 91 - v0.48: Saving the Import Path, added TILEINFOM copying
+//     from one area to another, getting rid of the "turning the plane
+//     viewing ON automatically sets it for writing."
+//
+// May 22 92 - v0.49: Added graphics-select switch to get rid of a dialog.
+//
+// Oct 20 95 - v0.50: Fixed EGA scrolling bug, added screensaver which comes
+//                    on automatically after 2 minutes.  Timelimit adjustable
+//                    through TIMELIMIT command line MED
+//
+////////////////////////////////////////////////////
+#include "ted5.h"
+#pragma hdrstop
+
+extern unsigned _stklen=0x2000;
+
+////////////////////////////////////////////////////
+//
+// Variables
+//
+////////////////////////////////////////////////////
+extern char far TEDCHAR,far VGAPAL,tdata;
+extern unsigned doubled[256];
+
+UndoStr UndoRegion;
+CopyStr TileCopy;
+MapFileHeaderStr _seg *MapFileHeader;
+char _seg *Tinfo[10],_seg *TMinfo[10],_seg *GraphHeader;
+long _seg *XMSlookup,_seg *EgaXMSlookup,_seg *CgaXMSlookup,_seg *VgaXMSlookup;
+int _seg *MapBkgnd,_seg *MapFrgnd,_seg *MapInfoPl,
+    _seg *CutBkgnd,_seg *CutFrgnd,_seg *CutInfoPl;
+MapHeaderStr MapHeader;
+
+TempStruct LaunchInfo;
+InfoStruct _seg *TEDInfo;
+GfxStruct _seg *GFXInfo;
+video lastvideo,videomode;
+screentype whichscreen=TILES;
+VMapStr VMapData;
+
+char launchname[64],ext[4],format[2],projname[64],mapname[64],planes,
+       infoname[64],mapheadname[64],MapNames[100][16],parmstring[64];
+char SM_name[64],SM_loadname[64],BkgndColor,GfxToUse;
+
+unsigned temp,whichmap,numtplanes,tilenum,tilemnum,numtmplanes,left,
+       DirtyFlag,tilelen,tilemlen,whicht,whichtm,whichi,
+       tsize,infoy,infomaxw,mapwidth,mapheight,screenw,usingbat,
+       screenh,planeton,planemon,planeion,maxiconrows,lasticon,firsticon,
+       viewton,viewmon,viewion,XMSundoB,XMSundoF,XMSundoI,launched,
+       XMSmaps,EgaXMS,CgaXMS,VgaXMS,xmshandle,GridMode,SnapMode,snapx,
+       snapy,snapxsize,snapysize,writeH,NoAbout,F3_flag;
+int tilebase=0,tilembase=0,infobaron=1,xbase,ybase,scrnbot,scrnrgt,
+       FillMode=0,PasteMode=0,SelectMode=0,SelX1=-1,SelY1=-1,PasteOK=0,SelX2=-1,
+       SelY2=-1,pixelx,pixely,selectcols,px,py,lastmap=-1,TIybase,TIymbase,TIxbase,
+       TIxmbase,BfillMode,Plotting,TsearchMode,NoXMSFlag;
+long CgaXMSsize,EgaXMSsize,VgaXMSsize;
+long tics, tictime=1092L*2L;
+
+
+//
+// harderr-called routine
+//
+int ignore(void)
+{
+ hardresume(0);
+ return 0;
+}
+
+////////////////////////////////////////////////////
+//
+// Start of The Beast From Hell
+//
+////////////////////////////////////////////////////
+void main(void)
+{
+ ParseCmdline();
+ SetupKBD();
+ MMStartup();
+ setvideo(EGA1);
+ lastvideo=EGA1;
+ InitTed5();
+ harderr(ignore);
+ tics=biostime(0,0);
+ DeskEventLoop(HandleEvent,Continuous);
+}
+
+////////////////////////////////////////////////////
+//
+// Parse the commandline
+//
+////////////////////////////////////////////////////
+void ParseCmdline(void)
+{
+ int i;
+
+ for (i=1;i<_argc;i++)
+ {
+  _argv[i]=strupr(_argv[i]);
+
+  if (_argv[i][0]=='-' || _argv[i][0]=='/')
+       _argv[i]++;
+
+  if (!strcmp(_argv[i],"?"))
+       {
+        printf(TITLESTR" by John Romero (C) 1991 Id Software, Inc.\n\n");
+        printf("Command Line parameters:\n");
+        printf("/?              : gets this stuff\n");
+        printf("/EXT=???        : set the project extension\n");
+        printf("<filename>      : set the Launch filename\n");
+        printf("/PARMS=<string> : set parms to Launch with\n");
+        printf("/NOXMSMAPS      : don't cache maps in XMS\n");
+    printf("/GFX=???        : set gfx to use - E,C,V\n");
+        printf("/TIME=???       : half-minutes until screenblanker (default 2 minutes)\n");
+    exit(0);
+       }
+  else
+  if (!strncmp(_argv[i],"EXT=",4))
+       strcpy(ext,&_argv[i][4]);
+  else
+  if (!strncmp(_argv[i],"GFX=",4))
+       GfxToUse = _argv[i][4];
+  else
+  if (!strcmp(_argv[i],"LAUNCH"))
+       launched=1;
+  else
+  if (!strcmp(_argv[i],"BAT"))
+       usingbat=1;
+  else
+  if (!strncmp(_argv[i],"PARMS=",6))
+       strcpy(parmstring,&_argv[i][6]);
+  else
+  if (!strncmp(_argv[i],"TIME=",5))
+         tictime=(atol(&_argv[i][5]))*546L;
+  else
+  if (!strcmp(_argv[i],"NOXMSMAPS"))
+       NoXMSFlag=1;
+  else
+  if (!strcmp(_argv[i],"NOABOUT"))
+       NoAbout=1;
+  else
+       strcpy(launchname,_argv[i]);
+ }
+}
+
+
+////////////////////////////////////////////////////
+//
+// Event handler - called when button is pressed
+// outside menu bar
+//
+////////////////////////////////////////////////////
+void HandleEvent(void)
+{
+ int pixelx,pixely,mx,my,b0,b1;
+ unsigned loc;
+
+ b0=MouseButton()&1;
+ b1=(MouseButton()>>1)&1;
+
+ MouseCoords(&mx,&my);
+ pixely=my;
+ pixelx=mx;
+
+ //
+ // PLOT OR PICK-UP TILE
+ //
+ if (my>=8 && my<infoy*8 && (b0 || b1))
+   {
+       mx=xbase+(mx>>(tsize+2));
+    my=ybase+((my-8)>>(tsize+2));
+
+    loc=my*mapwidth+mx;
+
+    if (mx>=mapwidth || my>=mapheight)
+      errsound();
+    else
+      {
+       if (b1)
+        {
+         //
+         // SELECT BOTTOM-RIGHT EDGE
+         //
+         if (SelectMode || BfillMode)
+           {
+            SelX2=mx;
+            SelY2=my;
+            if ((SelX1==-1 && SelY1==-1) ||
+                (SelX2<SelX1 || SelY2<SelY1))
+              {
+               SelX1=mx;
+               SelY1=my;
+              }
+            DrawMap();
+            sound(2000);
+           }
+         //
+         // FLOOD FILL!
+         //
+         else
+         if (FillMode)
+           {
+            while(MouseButton());
+            DoFloodFill(mx,my,1);
+           }
+         //
+         // PICK UP TILE(S)
+         //
+         else
+           {
+            if (planeton)
+              whicht=*(MapBkgnd+loc);
+            if (planemon)
+              whichtm=*(MapFrgnd+loc)+tilenum;
+                if (planeion)
+              whichi=*(MapInfoPl+loc)+tilenum;
+            DrawInfoBar();
+
+            //
+            // IF WE'RE IN TILESEARCH MODE, SHOW IT!
+            //
+            if (TsearchMode)
+              DrawMap();
+           }
+         while(MouseButton()>>1);
+         nosound();
+        }
+       if (b0)
+        {
+         //
+         // SELECT TOP-LEFT EDGE
+         //
+         if (SelectMode || BfillMode)
+           {
+            SelX1=mx;
+            SelY1=my;
+            if ((SelX2==-1 && SelY2==-1) ||
+                (SelX1>SelX2 || SelY1>SelY2))
+              {
+               SelX2=mx;
+               SelY2=my;
+              }
+
+            DrawMap();
+            sound(2000);
+            while(MouseButton());
+           }
+         //
+         // FLOOD FILL!
+         //
+         else
+         if (FillMode)
+           {
+            while(MouseButton());
+            DoFloodFill(mx,my,0);
+           }
+         //
+         // PASTE A CHUNK O' TILES/MAP
+         //
+         else
+         if (PasteMode)
+           {
+            if (TileCopy.MapOrTileSelect)      // TILE-SELECT AREA?
+              {
+               int i,j;
+
+               if (SnapMode)
+                 {
+                  mx=(mx/snapxsize)*snapxsize+snapx;
+                  my=(my/snapysize)*snapysize+snapy;
+                 }
+
+               if (mx+TileCopy.w>mapwidth ||
+                   my+TileCopy.h>mapheight)
+               sound(500);
+               else
+                 {
+                  CopyUndoRegion();
+                  UndoRegion.x=mx;
+                  UndoRegion.y=my;
+                  UndoRegion.w=TileCopy.w;
+                  UndoRegion.h=TileCopy.h;
+
+                  sound(500);
+                  switch(TileCopy.MapOrTileSelect)
+                  {
+                   case 1: // TILES
+                     for (j=0;j<TileCopy.h;j++)
+                       for (i=0;i<TileCopy.w;i++)
+                         {
+                          int val=(j+TileCopy.y)*selectcols+TileCopy.x+i;
+                          if (XMSlookup[val]!=-1)
+                            MapBkgnd[(my+j)*mapwidth+mx+i]=val;
+                         }
+                     break;
+                   case 2: // MASKED
+                     for (j=0;j<TileCopy.h;j++)
+                       for (i=0;i<TileCopy.w;i++)
+                         {
+                          int val=(j+TileCopy.y)*selectcols+TileCopy.x+i+tilenum+maxiconrows*selectcols;
+                          if (XMSlookup[val]!=-1)
+                            MapFrgnd[(my+j)*mapwidth+mx+i]=val-tilenum;
+                         }
+                  }
+                  nosound();
+                  DrawMap();
+                  DirtyFlag=1;
+                 }
+               while(MouseButton());
+               nosound();
+              }
+            else
+              {
+               int i,j;
+
+               if (SnapMode)
+                 {
+                  mx=(mx/snapxsize)*snapxsize+snapx;
+                  my=(my/snapysize)*snapysize+snapy;
+                 }
+
+               if (mx+TileCopy.w-1<mapwidth && my+TileCopy.h-1<mapheight)
+                 {
+                  sound(500);
+                  CopyUndoRegion();
+                  UndoRegion.x=mx;
+                  UndoRegion.y=my;
+                  UndoRegion.w=TileCopy.w;
+                  UndoRegion.h=TileCopy.h;
+
+                  for (j=0;j<TileCopy.h;j++)
+                    for (i=0;i<TileCopy.w;i++)
+                      {
+                       int theM,theI;
+
+
+                       if (TileCopy.PlanesCopied&BPLANE)
+                         MapBkgnd[(j+my)*mapwidth+mx+i]=
+                           CutBkgnd[(j+TileCopy.y)*mapwidth+TileCopy.x+i];
+                       if (TileCopy.PlanesCopied&FPLANE)
+                         {
+                          theM=CutFrgnd[(j+TileCopy.y)*mapwidth+TileCopy.x+i];
+                          if (theM || F3_flag)
+                            MapFrgnd[(j+my)*mapwidth+mx+i]=theM;
+                         }
+                       if (TileCopy.PlanesCopied&IPLANE)
+                         {
+                          theI=CutInfoPl[(j+TileCopy.y)*mapwidth+TileCopy.x+i];
+                          if (theI || F3_flag)
+                                MapInfoPl[(j+my)*mapwidth+mx+i]=theI;
+                         }
+                      }
+                  nosound();
+                  DrawMap();
+                  DirtyFlag=1;
+                 }
+               else
+                 sound(500);
+
+               while(MouseButton());
+              }
+           }
+         //
+         // PLOT TILE(S)
+         //
+         else
+           {
+            unsigned oldt,oldm,oldi;
+
+            //
+            // ARE WE STARTING THE PLOTTING REGION?
+            //
+            if (!Plotting)
+              {
+               CopyUndoRegion();
+               UndoRegion.x=mx;
+               UndoRegion.y=my;
+               UndoRegion.w=UndoRegion.h=1;
+               Plotting=1;
+              }
+
+            //
+            // FLOAT THE PLOTTING REGION
+            //
+            if (mx<UndoRegion.x)
+              UndoRegion.x=mx;
+            if (my<UndoRegion.y)
+              UndoRegion.y=my;
+            if (mx+1>UndoRegion.x+UndoRegion.w)
+              UndoRegion.w=mx-UndoRegion.x+1;
+            if (my+1>UndoRegion.y+UndoRegion.h)
+              UndoRegion.h=my-UndoRegion.y+1;
+
+            if (planeton)
+                  *(MapBkgnd+loc)=whicht;
+            if (planemon)
+              *(MapFrgnd+loc)=whichtm-tilenum;
+            if (planeion)
+              *(MapInfoPl+loc)=whichi-tilenum;
+
+            oldt=MapBkgnd[loc];
+            oldm=MapFrgnd[loc]+tilenum;
+            oldi=MapInfoPl[loc]+tilenum;
+
+            CombineTiles(viewton?oldt:-BkgndColor,viewmon*oldm,oldi*viewion,tsize);
+            if (GridMode)
+              Overlay(tsize);
+            MouseHide();
+            DrawTile((mx-xbase)<<(tsize-1),(my-ybase)*(4<<tsize)+8,tsize);
+            CheckInfoValues(mx-xbase,my-ybase,oldi);
+            MouseShow();
+            DirtyFlag=1;
+           }
+        }
+       nosound();
+      }
+   }
+
+ //
+ // CLICK ON TILES
+ //
+ if (b0 && pixely>infoy*8)
+   {
+    if (pixelx<7*8)
+      SelectTiles(1);
+    else
+    if (pixelx<8*14 && tilemnum)
+      SelectTiles(2);
+    else
+    if (pixelx<8*20 && tilemnum)
+      SelectTiles(3);
+   }
+
+}
+
+#define PEL_WRITE_ADR   0x3c8
+#define PEL_READ_ADR    0x3c7
+#define PEL_DATA        0x3c9
+#define PEL_MASK        0x3c6
+
+void ScreenBlank ( void )
+{
+  int done;
+  int x;
+  int y;
+  int r;
+  int g;
+  int b;
+  int c;
+  int oldx,oldy;
+  int i, j;
+  int xdir,ydir;
+  int cury;
+  int size;
+  int type;
+  struct {
+         int x,y;
+         } snake[256];
+
+  unsigned char far * screen=(unsigned char far *)0xa0000000l;
+
+
+  randomize();
+  _AX=0x13;
+  asm int 10h
+  done=0;
+  size=random(10)+2;
+  clearkeys();
+
+  for (i=255;i>=0;i--)
+         {
+         snake[i].x=160;
+         snake[i].y=100;
+         }
+  type=random(11);
+  r=random(200)+56;
+  g=random(200)+56;
+  b=random(200)+56;
+  outp (PEL_WRITE_ADR,0);
+  for (i=0;i<=255;i++)
+               {
+               outp (PEL_DATA, (unsigned char)((i*r)>>10));
+               outp (PEL_DATA, (unsigned char)((i*g)>>10));
+               outp (PEL_DATA, (unsigned char)((i*b)>>10));
+               }
+  xdir=0;
+  while (!xdir)
+         xdir=random(size<<1)-size;
+  ydir=0;
+  while (!ydir)
+         ydir=random(size<<1)-size;
+  while (!done)
+         {
+         if ((random(100)-80)>0)
+                 {
+                 xdir+=random(3)-1;
+                 ydir+=random(3)-1;
+                 }
+         for (i=255;i>0;i--)
+                 snake[i]=snake[i-1];
+         snake[0].x+=xdir;
+         snake[0].y+=ydir;
+         if ((snake[0].x<size+1) || (snake[0].x>320-(size+1)))
+                 {
+                 xdir=-xdir;
+                 snake[0].x+=xdir<<1;
+                 }
+         else if (abs(xdir)>size-1)
+                 xdir=-(xdir>>1);
+         if ((snake[0].y<size+1) || (snake[0].y>200-(size+1)))
+                 {
+                 ydir=-ydir;
+                 snake[0].y+=ydir<<1;
+                 }
+         else if (abs(ydir)>size-1)
+                 ydir=-(ydir>>1);
+         for (x=255;x>=0;x--)
+                 {
+                 if (type<7)
+                         {
+                         for (j=snake[x].y,cury=320*snake[x].y;j<snake[x].y+size;j++,cury+=320)
+                                 _fmemset((screen+cury+snake[x].x),255-x,size);
+                         }
+                 else
+                         {
+                         _fmemset((screen+(320*snake[x].y)+snake[x].x),255-x,size);
+                         }
+                 }
+         oldx=pixelx;
+         oldy=pixely;
+         MouseCoords(&pixelx,&pixely);
+         if ((oldx!=pixelx) || (oldy!=pixely))
+                 done=1;
+         for (x=0;x<127;x++)
+                 if (keydown[x])
+                         done=1;
+         }
+}
+
+////////////////////////////////////////////////////
+//
+// Routine called continuously by DeskEventLoop
+//
+////////////////////////////////////////////////////
+void Continuous(void)
+{
+ static int oldx, oldy;
+ if (biostime(0,0)-tics>tictime)
+        {
+        MouseHide();
+        ScreenBlank();
+        clearkeys();
+        videomode=lastvideo;
+        Item_ModeSwitch();
+        RedrawDesktop();
+        DrawMap();
+        DrawInfoBar();
+        MouseShow();
+        tics=biostime(0,0);
+        }
+ oldx=pixelx;
+ oldy=pixely;
+ MouseCoords(&pixelx,&pixely);
+ if ((oldx!=pixelx) || (oldy!=pixely))
+        {
+        tics=biostime(0,0);
+        PrintCoords();
+        }
+
+ if (!MouseButton())
+   Plotting=0;
+
+ //
+ // PLANE "WRITE" SELECTION
+ //
+ if (keydown[2] && viewton)
+   {
+    planeton^=1;
+    DrawInfoBar();
+    DrawMap();
+    PrintCoords();
+    tics=biostime(0,0);
+    while(keydown[2]);
+   }
+ if (keydown[3] && tilemnum && (MapFileHeader->maptype&FPLANE) && viewmon)
+   {
+    planemon^=1;
+    DrawInfoBar();
+    DrawMap();
+    PrintCoords();
+    tics=biostime(0,0);
+    while(keydown[3]);
+   }
+ if (keydown[4] && (MapFileHeader->maptype&IPLANE) && viewion)
+   {
+    planeion^=1;
+    DrawInfoBar();
+    DrawMap();
+    PrintCoords();
+    tics=biostime(0,0);
+    while(keydown[4]);
+   }
+
+ //
+ // PLANE "VIEW" SELECTION
+ //
+ if (keydown[5])
+   {
+    viewton^=1;
+    if (!viewton)
+         planeton=0;
+    DrawInfoBar();
+    DrawMap();
+    PrintCoords();
+    tics=biostime(0,0);
+    while(keydown[5]);
+   }
+ if (keydown[6] && tilemnum && (MapFileHeader->maptype&FPLANE))
+   {
+    viewmon^=1;
+    if (!viewmon)
+      planemon=0;
+    DrawInfoBar();
+    DrawMap();
+    PrintCoords();
+    tics=biostime(0,0);
+    while(keydown[6]);
+   }
+ if (keydown[7] && (MapFileHeader->maptype&IPLANE))
+   {
+    viewion^=1;
+    if (!viewion)
+      planeion=0;
+    DrawInfoBar();
+    DrawMap();
+    PrintCoords();
+    tics=biostime(0,0);
+    while(keydown[7]);
+   }
+
+ //
+ // Cancel COPY or PASTE or FLOOD FILL or BLOCK FILL
+ //
+ if (keydown[1] && (PasteMode || SelectMode || FillMode ||
+        BfillMode || TsearchMode))
+   {
+    while(keydown[1]);
+
+    if (PasteMode)
+      {
+       EraseFloatPaste();
+       px=py=-1;
+      }
+
+    SnapMode=TsearchMode=BfillMode=FillMode=PasteMode=SelectMode=0;
+    SelX1=SelX2=SelY1=SelY2=-1;
+    DrawMap();
+    DrawInfoBar();
+    tics=biostime(0,0);
+   }
+
+ //
+ // END OF COPY || BLOCK FILL
+ //
+ if (keydown[0x1c] && (SelectMode || BfillMode))
+   {
+    int temp,j,i;
+
+    tics=biostime(0,0);
+    while(keydown[0x1c]);
+
+    if (SelX2<SelX1)
+      {
+       temp=SelX1;
+       SelX1=SelX2;
+       SelX2=temp;
+      }
+    if (SelY2<SelY1)
+      {
+       temp=SelY1;
+       SelY1=SelY2;
+       SelY2=temp;
+      }
+
+    //
+    // BLOCK FILL?
+    //
+    if (BfillMode)
+      {
+       BfillMode=0;
+       DrawInfoBar();
+       DoBlockFill();
+       SelX1=SelX2=SelY1=SelY2=-1;
+      }
+    else
+    //
+    // COPY MODE?
+    //
+    if (SelectMode)
+      {
+       SelectMode=0;
+
+       TileCopy.x=SelX1;
+       TileCopy.y=SelY1;
+       TileCopy.w=SelX2-SelX1+1;
+          TileCopy.h=SelY2-SelY1+1;
+       TileCopy.MapOrTileSelect=0;
+       TileCopy.PlanesCopied=planeton*BPLANE | planemon*FPLANE | planeion*IPLANE;
+
+       //
+       // DO THE COPY!
+       //
+       sound(600);
+       for (j=SelY1;j<=SelY2;j++)
+        for (i=SelX1;i<=SelX2;i++)
+          {
+           if (planeton)
+             CutBkgnd[j*mapwidth+i]=MapBkgnd[j*mapwidth+i];
+           if (planemon)
+             CutFrgnd[j*mapwidth+i]=MapFrgnd[j*mapwidth+i];
+           if (planeion)
+             CutInfoPl[j*mapwidth+i]=MapInfoPl[j*mapwidth+i];
+          }
+
+       DrawInfoBar();
+       SelX1=SelX2=SelY1=SelY2=-1;
+       PasteOK=1;
+       px=py=-1;
+       nosound();
+       DrawMap();
+      }
+    clearkeys();
+   }
+
+ //
+ // See if we want to scroll the map!
+ //
+ CheckMapScroll();
+ CheckFloatPaste((pixelx>>(tsize+2))+xbase,((pixely-8)>>(tsize+2))+ybase);
+}
+
+////////////////////////////////////////////////////
+//
+// Draw the current map on the screen at xbase,ybase
+//
+////////////////////////////////////////////////////
+void DrawMap(void)
+{
+ int i,j,imax,jmax;
+
+
+ EraseFloatPaste();
+ jmax=screenh;
+ if (jmax>mapheight)
+   jmax=mapheight;
+
+ imax=screenw;
+ if (imax>mapwidth)
+   imax=mapwidth;
+
+ MouseHide();
+ for(j=0;j<jmax;j++)
+   for(i=0;i<imax;i++)
+     {
+      unsigned tilet,tilem,tilei,loc;
+
+      loc=(ybase+j)*mapwidth+xbase+i;
+
+      tilet=*(MapBkgnd+loc);
+      tilem=*(MapFrgnd+loc)+tilenum;
+      tilei=*(MapInfoPl+loc)+tilenum;
+
+      CombineTiles(tilet*viewton-BkgndColor*(!viewton),tilem*viewmon,tilei*viewion,tsize);
+      if (GridMode)
+       Overlay(tsize);
+      DrawTile(i<<(tsize-1),j*(4<<tsize)+8,tsize);
+      CheckInfoValues(i,j,tilei);
+      CheckSelectEdges(i+xbase,j+ybase,i,j);
+     }
+ MouseShow();
+ DrawFloatPaste();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Figure out SCREENW,SCREENH from videomode & tsize
+//
+////////////////////////////////////////////////////
+void FigureScreenEdges(void)
+{
+ switch(videomode)
+ {
+  case CGA:
+  case EGA1:
+  case VGA:
+    screenw=40>>(tsize-1);
+    screenh=22>>(tsize-1);
+    break;
+  case EGA2:
+    screenw=80>>(tsize-1);
+    screenh=57>>(tsize-1);
+    break;
+ }
+ if (!infobaron)
+   {
+    infoy=100;  // WAY OFF THE BOTTOM!
+    screenh+=2*(tsize==1)+(tsize==2);
+   }
+}
+
+
+////////////////////////////////////////////////////
+//
+// Print the coords on the INFOBAR
+//
+////////////////////////////////////////////////////
+void PrintCoords(void)
+{
+ static zeroed=0;
+ int mx,my;
+
+ if (!infobaron)
+   return;
+
+ xormask=0;
+ MouseCoords(&mx,&my);
+ if (my<8 || my>=infoy*8)
+   {
+    if (zeroed)
+      return;
+    sx=infomaxw-9;
+    sy=infoy;
+    print("??? ?????");
+    sx=infomaxw-9;
+    sy=infoy+1;
+    print("??? ?????");
+    zeroed=1;
+    return;
+   }
+
+ zeroed=0;
+ mx=mx>>(tsize+2);
+ sx=infomaxw-9;
+ sy=infoy;
+ printint(mx+xbase);
+ print("  ");
+ sx=infomaxw-5;
+ printhex(mx+xbase);
+
+ my=(my-8)>>(tsize+2);
+ sx=infomaxw-9;
+ sy=infoy+1;
+ printint(my+ybase);
+ print("  ");
+ sx=infomaxw-5;
+ printhex(my+ybase);
+}
+
+
+////////////////////////////////////////////////////
+//
+// Draw the INFOBAR
+//
+////////////////////////////////////////////////////
+void DrawInfoBar(void)
+{
+ int ox,oy;
+
+
+ if (PasteMode)
+   {
+    px=py=-1;
+    CheckFloatPaste((pixelx>>(tsize+2))+xbase,((pixely-8)>>(tsize+2))+ybase);
+   }
+
+ if (!infobaron)
+   return;
+
+ EraseFloatPaste();
+
+ ox=sx=0;
+ switch(videomode)
+ {
+  case CGA:
+  case EGA1:
+  case VGA:
+    oy=sy=23-2*(tsize==3);
+    infomaxw=40;
+    break;
+  case EGA2:
+    oy=sy=58-2*(tsize==3)-1*(tsize==2);
+    infomaxw=80;
+ }
+
+ MouseHide();
+ infoy=oy;
+ bar(0,infoy,infomaxw-1,infoy+1,' ');
+
+ if (SelectMode)
+   {
+    sx=leftedge=1;
+    sy=infoy;
+    print("Copy Mode\nESC to exit");
+   }
+ else
+ if (TsearchMode)
+   {
+    sx=leftedge=1;
+    sy=infoy;
+    print("Tile Search Mode\nESC to exit");
+   }
+ else
+ if (BfillMode)
+   {
+    sx=leftedge=1;
+    sy=infoy;
+    print("Block Fill Mode\nESC to exit");
+   }
+ else
+ if (PasteMode)
+   {
+    sx=leftedge=1;
+    sy=infoy;
+    print("Paste Mode\nESC to exit");
+   }
+ else
+ if (FillMode)
+   {
+    sx=leftedge=1;
+       sy=infoy;
+    print("Flood Fill Mode\nESC to exit");
+   }
+ else
+   {
+    CombineTiles(whicht,0,0,tsize);
+    DrawTile(ox,oy*8+8*(tsize==1),tsize);
+    sx=ox+2+2*(tsize==3);
+    sy=oy;
+    printhex(whicht);
+    sx-=5;
+    sy++;
+    printint(whicht);
+    print("    ");
+
+    if (tilemnum)
+      {
+       ox+=7;
+       CombineTiles(-BkgndColor,whichtm,0,tsize);
+       DrawTile(ox,oy*8+8*(tsize==1),tsize);
+       sx=ox+2+2*(tsize==3);
+       sy=oy;
+       (whichtm==tilenum)?print(" No  "):printhex(whichtm-tilenum);
+       sx-=5;
+       sy++;
+       (whichtm==tilenum)?print("Tile"):printint(whichtm-tilenum);
+       print("    ");
+
+       ox+=7;
+       CombineTiles(-ICONBACK,(whichi>lasticon)?firsticon:whichi,0,tsize);
+       DrawTile(ox,oy*8+8*(tsize==1),tsize);
+       sx=ox+2+2*(tsize==3);
+       sy=oy;
+       (whichi==tilenum)?print(" No  "):printhex(whichi-tilenum);
+       sx-=5;
+       sy++;
+       (whichi==tilenum)?print("Icon"):printint(whichi-tilenum);
+       print("    ");
+      }
+   }
+
+
+ sx=infomaxw-11;
+ sy=infoy;
+ print("X=");
+ sy++;
+ sx-=2;
+ print("Y=");
+
+ sx=infomaxw-((videomode==EGA2)?19:18);
+ sy=infoy+1;
+ print("123");
+ if (SnapMode)
+   {
+    sx=infomaxw-((videomode==EGA2)?21:20);
+    sy=infoy+1;
+    print("S");
+   }
+ if (GridMode)
+   {
+    sx=infomaxw-((videomode==EGA2)?20:19);
+    sy=infoy+1;
+    print("G");
+   }
+ sx=infomaxw-((videomode==EGA2)?19:18);
+ sy=infoy;
+ (planeton)?print("B"):print(" ");
+ (planemon)?print("F"):print(" ");
+ (planeion)?print("I"):print(" ");
+
+ sx=infomaxw-15;
+ sy=infoy+1;
+ print("456");
+ sx=infomaxw-15;
+ sy=infoy;
+ (viewton)?print("b"):print(" ");
+ (viewmon)?print("f"):print(" ");
+ (viewion)?print("i"):print(" ");
+
+ if (videomode==EGA2)
+   {
+    sx=screencenterx-strlen(MapHeader.name)/2;
+    sy=infoy;
+    print(MapHeader.name);
+   }
+
+ DrawFloatPaste();
+ MouseShow();
+}
+
+
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// Initialize TED5:
+//
+// * Project Select if multiple projects
+// * If Project has NO LEVELS:
+//   * Init Level 1
+//   * Init TILEINFO
+//   * Init TEDINFO file
+// * Load TILES into XMS
+//
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+char bstrings[10][15];
+btype ProjButns[10];
+DialogDef ProjSelect={"Select the project to work on:",
+                     30,0,0,&ProjButns[0],DrawProjBord};
+
+void InitTed5(void)
+{
+ char pname[15];
+ unsigned i,loop,which;
+
+ MouseInit();
+ MouseShow();
+ if (!MouseStatus)
+   {
+       ErrDialog("Sorry, but TED5 will NOT\n"
+                 "operate without a mouse!\n"," Press ENTER ");
+       Quit("Only REAL developers have a mouse!");
+   }
+ MouseOrigin(0,0);
+
+ ErrDialog("Initializing. One moment.","");
+ //
+ // Create bit-doubling lookup table
+ // for CGA font creation
+ //
+ for (loop=0;loop<256;loop++)
+   {
+       unsigned result,temp=loop;
+
+       asm         mov     ax,temp
+       asm         mov     ah,al
+       asm         mov     cx,8
+       LOOP0:
+       asm         shl     al,1
+       asm         rcl     bx,1
+       asm         shl     ah,1
+       asm         rcl     bx,1
+       asm         loop    LOOP0
+
+       asm         xchg    bh,bl
+       asm         mov     result,bx
+
+       doubled[loop]=result;
+   }
+
+ //
+ // Init everything!
+ //
+ InitXMS();
+ FindGraphFile();
+ LoadInfoFile();
+ LoadMapHeader();
+
+ RestoreBackground();
+
+ LoadGraphStuff(0,TEDInfo->lastvid);
+ DrawInfoBar();
+ DrawMap();
+ if (!launched && !NoAbout)
+   Item_About();
+ launched=0;
+}
+
+
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// Load the MAPTEMP.ext header in...
+//
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+btype SelectTsizeb[]={{"  8x8  ",1,2,1},
+                     {" 16x16 ",1,5,1},
+                         {" 32x32 ",1,8,1}};
+DialogDef SelectTsize={" Which tile size to use?"
+                      ,26,10,3,&SelectTsizeb[0],STnot};
+
+void LoadMapHeader(void)
+{
+ unsigned size,i,j,pflag;
+ char types=0;
+
+
+ strcpy(mapheadname,"MAPTHEAD.");
+ strcat(mapheadname,ext);
+ strcpy(mapname,"MAPTEMP.");
+ strcat(mapname,ext);
+ strcpy(SM_name,"MAPTEMP1.");
+ strcat(SM_name,ext);
+ strcpy(SM_loadname,"MAPTEMP.");
+ strcat(SM_loadname,ext);
+
+ if (access(mapheadname,0))
+   {
+    int i;
+    //
+    // Gotta create a new map file!
+    //
+    MMAllocate((memptr *)&MapFileHeader,sizeof(MapFileHeaderStr));
+    for (i=0;i<sizeof(MapFileHeaderStr);i++)
+      *((char _seg *)MapFileHeader+i)=0;
+
+    MapFileHeader->RLEWtag=0xabcd;
+    for (i=0;i<100;i++)
+      {
+       MapFileHeader->dataoffsets[i]=-1;
+       MapFileHeader->datalengths[i]=0;
+       memset(MapNames[i],0,16);
+      }
+
+    if (!GFXInfo->num8 &&
+       !GFXInfo->num8m &&
+       !GFXInfo->num16 &&
+       !GFXInfo->num16m &&
+       !GFXInfo->num32 &&
+       !GFXInfo->num32m)
+      {
+       ErrDialog("Uhh...you 'neglected' to\n"
+                "grab tiles to use. Running\n"
+                "TED5 is quite useless at\n"
+                "this point, I'm afraid.","Duh!");
+       Quit("Get some tiles ... quick! Me hungry!");
+      }
+
+    if (!GFXInfo->num8 &&
+       !GFXInfo->num16 &&
+       !GFXInfo->num32)
+      {
+       ErrDialog("You may have grabbed some\n"
+                "MASKED tiles, but I require\n"
+                "NON-MASKED tiles as a\n"
+                "minimum requirement!","Geez...");
+       Quit("Please grab some normal tiles!");
+      }
+
+    types+=(GFXInfo->num8>0)+(GFXInfo->num16>0)+(GFXInfo->num32>0);
+
+    redo:
+
+    if (types>1)
+      {
+       int which;
+
+       which=DoDialog(&SelectTsize);
+       switch(which)
+       {
+       case 0:
+         Quit("");
+       case 1:
+         if (!GFXInfo->num8)
+           which=0;
+         break;
+       case 2:
+         if (!GFXInfo->num16)
+           which=0;
+         break;
+       case 3:
+         if (!GFXInfo->num32)
+           which=0;
+         break;
+       }
+
+       MapFileHeader->tsize=TEDInfo->tsize=tsize=which;
+         }
+    else
+      {
+       if (GFXInfo->num8)
+        TEDInfo->tsize=1;
+       else
+       if (GFXInfo->num16)
+        TEDInfo->tsize=2;
+       else
+       if (GFXInfo->num32)
+        TEDInfo->tsize=3;
+
+       MapFileHeader->tsize=tsize=TEDInfo->tsize;
+      }
+
+    //
+    // pick the planes that all maps will use
+    //
+    if (PickMorePlanes())
+      goto redo;
+
+    //
+    // initialize TILEINFO/TILEINFOM
+    //
+    switch(tsize)
+    {
+     case 1:
+       tilenum=GFXInfo->num8;
+       tilemnum=GFXInfo->num8m;
+       break;
+     case 2:
+       tilenum=GFXInfo->num16;
+       tilemnum=GFXInfo->num16m;
+       break;
+     case 3:
+       tilenum=GFXInfo->num32;
+       tilemnum=GFXInfo->num32m;
+    }
+    InitTileinfo();
+    if (numtplanes || numtmplanes)      // only input if applicable
+      Item_EditTinfoNames();            // void where prohibited
+    //
+    // now create a map!
+    //
+    CreateMap(0);
+       FigureScreenEdges();
+    MapFileHeader->NumIconRows=maxiconrows=InputIconAmount();
+   }
+ //
+ // MAP FILE ALREADY IN PLACE. LOAD STUFF IN...
+ //
+ else
+   {
+    memptr block,tempblock;
+
+    LoadIn(mapheadname,(memptr *)&MapFileHeader);
+
+    //
+    // See if the NumIconRows is toasty (old TED5 compatibility)
+    //
+    if (MapFileHeader->NumIconRows>50)
+      MapFileHeader->NumIconRows=4;
+
+    //
+    // has the TEDINFO?.ext file been changed?
+    // if so, reconstruct pertinent data...
+    //
+    if (!TEDInfo->tsize)
+      {
+       tsize=TEDInfo->tsize=MapFileHeader->tsize;
+       switch(tsize)
+       {
+       case 1:
+         tilenum=GFXInfo->num8;
+         tilemnum=GFXInfo->num8m;
+         break;
+       case 2:
+         tilenum=GFXInfo->num16;
+         tilemnum=GFXInfo->num16m;
+         break;
+       case 3:
+         tilenum=GFXInfo->num32;
+         tilemnum=GFXInfo->num32m;
+       }
+      }
+
+    maxiconrows=MapFileHeader->NumIconRows;
+
+    //
+    // Read-in all the Map Names
+       //
+    for (i=0;i<100;i++)
+      if (MapFileHeader->dataoffsets[i]!=-1)
+       {
+        MapHeaderStr TempHead;
+
+        LoadFile(mapname,(char huge *)&TempHead,
+          MapFileHeader->dataoffsets[i],sizeof(MapHeaderStr));
+        strcpy(MapNames[i],TempHead.name);
+       }
+
+    FigureScreenEdges();
+
+    if (!TEDInfo->level)
+      {
+       for(i=0;i<100;i++)
+        if (MapFileHeader->dataoffsets[i]!=-1)
+          {
+           whichmap=TEDInfo->level=i;
+           break;
+          }
+      }
+    else
+      whichmap=TEDInfo->level;
+
+    LoadMap(TEDInfo->level);
+
+    //
+    // IF WE WERE LAUNCHED AND CHARACTER POSITION WAS CHANGED,
+    // PUT IT BACK!
+    //
+    if (launched && (TEDInfo->lastx || TEDInfo->lasty))
+      {
+       int i;
+
+       for (i=0;i<mapwidth*mapheight;i++)
+        if (MapInfoPl[i]==TEDInfo->permicon)
+          {
+           MapInfoPl[i]=0;
+           MapInfoPl[TEDInfo->lasty*mapwidth+TEDInfo->lastx]=TEDInfo->permicon;
+           TEDInfo->lastx=TEDInfo->lasty=0;
+           DirtyFlag=1;
+           break;
+          }
+      }
+
+    //
+    // POSITION SCREEN
+    //
+    xbase=TEDInfo->oscrx;
+    ybase=TEDInfo->oscry;
+    if (xbase+screenw>mapwidth)
+      xbase=mapwidth-screenw;
+    if (ybase+screenh>mapheight)
+      ybase=mapheight-screenh;
+
+    if (launched)
+      _fmemcpy((void far *)parmstring,(void far *)TEDInfo->parmstring,64);
+
+    //
+    // LOAD TILEINFO/M AND ADJUST IF IT CHANGED
+    //
+    numtplanes=MapFileHeader->numtplanes;
+    numtmplanes=MapFileHeader->numtmplanes;
+
+    pflag=0;
+    for (i=0;i<numtplanes;i++)
+      {
+       //
+       // SPACE FOR OLD TILEINFO TO DECOMPRESS INTO
+       //
+       MMAllocate(&tempblock,MapFileHeader->oldtilenum);
+       //
+       // SPACE FOR OLD TILEINFO TO LOAD INTO
+       //
+       MMAllocate(&block,MapFileHeader->tileinfolen[i]);
+       LoadFile(mapheadname,MK_FP(block,0),MapFileHeader->tileinfooff[i],MapFileHeader->tileinfolen[i]);
+       //
+       // DECOMPRESS FROM "BLOCK" TO "TEMPBLOCK"
+       //
+       RLEBExpand(MK_FP(block,0),MK_FP(tempblock,0),
+          MapFileHeader->oldtilenum,MapFileHeader->RLEWtag);
+       MMFreePtr(&block);
+       //
+       // ALLOCATE TINFO ARRAY
+       //
+       MMAllocate((memptr *)&Tinfo[i],tilenum);
+       //
+       // MOVE FROM "TEMPBLOCK" TO "TINFO[I]" ARRAY
+       //
+          if (MapFileHeader->oldtilenum<tilenum)
+        {
+         movedata((unsigned)tempblock,0,(unsigned)Tinfo[i],0,MapFileHeader->oldtilenum);
+         //
+         // IF NEW TILEINFO IS MORE, FILL END WITH 0s
+         //
+         for (j=MapFileHeader->oldtilenum;j<tilenum;j++)
+           *(Tinfo[i]+j)=0;
+         DirtyFlag=pflag=1;
+        }
+       else
+        {
+         movedata((unsigned)tempblock,0,(unsigned)Tinfo[i],0,tilenum);
+         if (MapFileHeader->oldtilenum>tilenum)
+           DirtyFlag=pflag=2;
+        }
+
+       MMFreePtr(&tempblock);
+      }
+
+    switch(pflag)
+    {
+     case 1:
+       ErrDialog("The new TILEINFO data has\n"
+                "been expanded to accomodate\n"
+                "the newly grabbed tiles."," OK ");
+       break;
+     case 2:
+       ErrDialog("The new TILEINFO data has\n"
+                "been shrunk due to a reduced\n"
+                "amount of tiles."," OK ");
+    }
+
+    pflag=0;
+    if (tilemnum && (MapFileHeader->maptype&FPLANE))
+      for (i=0;i<numtmplanes;i++)
+       {
+        MMAllocate(&tempblock,MapFileHeader->oldtilemnum);
+        MMAllocate(&block,MapFileHeader->tileinfomlen[i]);
+        LoadFile(mapheadname,MK_FP(block,0),MapFileHeader->tileinfomoff[i],MapFileHeader->tileinfomlen[i]);
+        RLEBExpand(MK_FP(block,0),MK_FP(tempblock,0),
+            MapFileHeader->oldtilemnum,MapFileHeader->RLEWtag);
+        MMFreePtr(&block);
+        MMAllocate((memptr *)&TMinfo[i],tilemnum);
+        if (MapFileHeader->oldtilemnum<tilemnum)
+          {
+           movedata((unsigned)tempblock,0,(unsigned)TMinfo[i],0,MapFileHeader->oldtilemnum);
+           for (j=MapFileHeader->oldtilemnum;j<tilemnum;j++)
+             *(TMinfo[i]+j)=0;
+           DirtyFlag=pflag=1;
+          }
+        else
+          {
+           movedata((unsigned)tempblock,0,(unsigned)TMinfo[i],0,tilemnum);
+           if (MapFileHeader->oldtilemnum>tilemnum)
+             DirtyFlag=pflag=2;
+          }
+
+        MMFreePtr(&tempblock);
+       }
+
+    switch(pflag)
+    {
+     case 1:
+       ErrDialog("The new TILEINFOM data has\n"
+                "been expanded to accomodate\n"
+                "the newly grabbed masked tiles."," OK ");
+       break;
+     case 2:
+       ErrDialog("The new TILEINFOM data has\n"
+                "been shrunk due to a reduced\n"
+                "amount of tiles."," OK ");
+    }
+
+    #if 0
+    //
+    // TURN ON PLANES
+    //
+    viewton=planeton=1;
+    if (MapFileHeader->maptype&FPLANE)
+      viewmon=1;
+    if (MapFileHeader->maptype&IPLANE)
+      viewion=1;
+    planemon=planeion=0;
+    #endif
+
+   }
+
+ //
+ // LOAD THE MAPFILE INTO XMS IF ENOUGH ROOM
+ //
+ if (1024L*XMSTotalFree()>2L*filelen(mapname) && !NoXMSFlag)
+   {
+    #define LBCSIZE     0x4000
+    memptr block;
+    long size,clen,coff;
+
+
+    size=filelen(mapname);
+    MMAllocate(&block,LBCSIZE);
+    XMSmaps=XMSAllocate(size);
+
+    //
+    // LOAD ENTIRE MAPFILE FROM DISK TO XMS!
+    //
+    coff=0;
+    do
+    {
+     clen=LBCSIZE;
+     if (size<LBCSIZE)
+       clen=size;
+
+     LoadFile(mapname,MK_FP(block,0),coff,clen);
+     XMSmove(0,(long)MK_FP(block,0),XMSmaps,coff,clen);
+     size-=LBCSIZE;
+     coff+=clen;
+    } while(size>0);
+
+    MMFreePtr(&block);
+   }
+
+}
+
+void STnot(int x,int y)
+{
+ sx=x+10;
+ sy=y+2;
+ if (!GFXInfo->num8)
+   print("<-Not available");
+ else
+   {
+    printint(GFXInfo->num8);
+    print(" total tiles");
+   }
+ sx=x+10;
+ sy=y+5;
+ if (!GFXInfo->num16)
+   print("<-Not available");
+ else
+   {
+    printint(GFXInfo->num16);
+    print(" total tiles");
+   }
+ sx=x+10;
+ sy=y+8;
+ if (!GFXInfo->num32)
+   print("<-Not available");
+ else
+   {
+    printint(GFXInfo->num32);
+    print(" total tiles");
+   }
+}
+
+
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// Load the graphheader file & ?GAGRAPH.ext file and stick it in XMS!
+//
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+int LoadGraphStuff(int rtn,video newvid)
+{
+ #define NUMFASTDECOMP  100     // # of tiles in fast decompress buffer
+
+ char gname[14]="?GAHEAD.",gname1[14]="?GAGRAPH.",_seg *packed,_seg *unpack,
+      dictname[14]="?GADICT.",hufftable[1020],_seg *CacheBlock;
+ unsigned index,indexm,num,numm,i,realnum,realnumm,ox,oy,cacheon=0,_seg *tile_len,
+      _seg *tilem_len,cacheon_h;
+ long expsize,expmsize,xmsoff=0,unpackoff,unpackmax,unpacksize,
+      unpackxms;
+ video tempvid,pickedvid;
+
+ char huge *offsets;
+
+
+
+ strcat(gname,ext);
+ strcat(gname1,ext);
+ strcat(dictname,ext);
+ gname[0]=format[0];
+ gname1[0]=format[0];
+ dictname[0]=format[0];
+
+ if (!launched)
+   switch(format[0])
+   {
+       case 'C': pickedvid=CGA; break;
+       case 'E': pickedvid=EGA1; break;
+       case 'V': pickedvid=VGA;
+   }
+ else
+   pickedvid=TEDInfo->lastvid;
+
+ //
+ // VALIDATE GRAPHICS MODE
+ //
+ tempvid=rtn?newvid:pickedvid;
+ switch(tempvid)
+ {
+  case CGA:
+       gname[0]='C';
+       if (access(gname,0))
+         {
+          if (rtn)
+                return 0;
+         }
+       else
+         {
+          TEDInfo->lastvid=CGA;
+          dictname[0]=format[0]=gname1[0]='C';
+          setvideo(CGA);
+          InitDesktop(TED5MenuBar,1);
+          MouseShow();
+          break;
+         }
+  case EGA1:
+  case EGA2:
+       gname[0]='E';
+       if (access(gname,0))
+         {
+          if (rtn)
+        return 0;
+         }
+       else
+         {
+          TEDInfo->lastvid=tempvid;
+          dictname[0]=format[0]=gname1[0]='E';
+          setvideo(tempvid);
+          InitDesktop(TED5MenuBar,1);
+          MouseShow();
+          break;
+         }
+  case VGA:
+       gname[0]='V';
+       if (access(gname,0))
+         {
+          if (rtn)
+        return 0;
+
+       gname[0]=format[0];
+      }
+    else
+      {
+       TEDInfo->lastvid=VGA;
+       dictname[0]=format[0]=gname1[0]='V';
+       setvideo(VGA);
+       InitDesktop(TED5MenuBar,1);
+       MouseShow();
+       break;
+      }
+ }
+
+
+ //
+ // FIND HEADER & LOAD IT
+ //
+ if (access(gname,0))
+   {
+    char errstr[100]="Can't find the ";
+
+    strcat(errstr,format);
+    strcat(errstr,"GAHEAD.");
+    strcat(errstr,ext);
+    strcat(errstr,"\nfile! Maybe you didn't\n"
+                 "copy it from the graphics\n"
+                 "subdirectory?");
+
+    ErrDialog(errstr," OK ");
+    if (rtn)
+      return 0;
+    Quit("You're stupid! Copy the damn file!");
+   }
+
+ LoadIn(gname,(memptr *)&GraphHeader);
+
+ switch(MapFileHeader->tsize)
+ {
+  case 1:
+    index=GFXInfo->off8;
+    indexm=GFXInfo->off8m;
+    num=GFXInfo->num8;
+    numm=GFXInfo->num8m;
+    if (indexm==index+1)
+      {
+       ErrDialog("I'm sorry, but you need to\n"
+                "capture your 8x8 tiles\n"
+                "individually, and not in a\n"
+                "big chunk."," Alright ");
+       if (rtn)
+        return 0;
+       Quit("Regrab-time, bag o' shit!");
+      }
+
+    switch(tempvid)
+    {
+     case CGA: expsize=16; expmsize=32; break;
+     case EGA1:
+     case EGA2: expsize=32; expmsize=40; break;
+        case VGA: expsize=64; expmsize=128;
+    }
+    break;
+  case 2:
+    index=GFXInfo->off16;
+    indexm=GFXInfo->off16m;
+    num=GFXInfo->num16;
+    numm=GFXInfo->num16m;
+    switch(tempvid)
+    {
+     case CGA: expsize=64; expmsize=128; break;
+     case EGA1:
+     case EGA2: expsize=128; expmsize=128+32; break;
+     case VGA: expsize=256; expmsize=512;
+    }
+    break;
+  case 3:
+    index=GFXInfo->off32;
+    indexm=GFXInfo->off32m;
+    num=GFXInfo->num32;
+    numm=GFXInfo->num32m;
+    switch(tempvid)
+       {
+     case CGA: expsize=256; expmsize=512; break;
+     case EGA1:
+     case EGA2: expsize=512; expsize=512+4*32; break;
+     case VGA: expsize=1024; expmsize=2048;
+    }
+ }
+
+ //
+ // MOVE TILES INTO XMS MEMORY!
+ //
+
+ MMAllocate((memptr *)&packed,expmsize);
+ unpackmax=expmsize*NUMFASTDECOMP;
+ MMAllocate((memptr *)&unpack,unpackmax);
+
+
+ tilelen=expsize;
+ tilemlen=expmsize;
+ offsets=MK_FP(GraphHeader,0);
+
+ //
+ // LOAD DICTIONARY IN & INITIALIZE IT
+ //
+ if (!launched)
+   {
+    char _seg *block;
+
+    if (access(dictname,0))
+      {
+       char errst[200]="I can't find the \n";
+
+       strcat(errst,dictname);
+       strcat(errst," file!");
+
+       ErrDialog(errst," OK ");
+       if (rtn)
+        return 0;
+       Quit("Look in the graphics grab directory!");
+      }
+
+    LoadIn(dictname,(memptr *)&block);
+    movedata((unsigned)block,0,FP_SEG(hufftable),FP_OFF(hufftable),1020);
+    MMFreePtr((memptr *)&block);
+    OptimizeNodes((huffnode *)hufftable);
+   }
+
+ //
+ // Count up the REAL number of tiles there are!
+ // Build tables for tile lengths
+ //
+ MMAllocate((memptr *)&tile_len,num*2);
+ for (realnum=i=0;i<num;i++)
+ {
+  int j;
+
+
+
+  if (OFF3(offsets,i+index)!=0xffffff)
+  {
+   realnum++;
+   if (OFF3(offsets,i+index+1)!=0xffffff)
+     tile_len[i]=OFF3(offsets,i+index+1)-OFF3(offsets,i+index);
+   else
+     for (j=i+1;j<num+numm;j++)
+       if (OFF3(offsets,j+index)!=0xffffff)
+       {
+       tile_len[i]=OFF3(offsets,j+index)-OFF3(offsets,i+index);
+       break;
+       }
+  }
+  else
+    tile_len[i]=0;
+
+ }
+ MMAllocate((memptr *)&tilem_len,numm*2);
+ for (realnumm=i=0;i<numm;i++)
+ {
+  int j;
+
+
+  if (OFF3(offsets,i+indexm)!=0xffffff)
+  {
+   realnumm++;
+   if (OFF3(offsets,i+indexm+1)!=0xffffff)
+     tilem_len[i]=OFF3(offsets,i+indexm+1)-OFF3(offsets,i+indexm);
+   else
+     for (j=i+1;j<numm+1;j++)
+       if (OFF3(offsets,j+indexm)!=0xffffff)
+       {
+       tilem_len[i]=OFF3(offsets,j+indexm)-OFF3(offsets,i+indexm);
+       break;
+       }
+  }
+  else
+    tilem_len[i]=0;
+ }
+
+ //
+ // DON'T REALLOCATE THIS IF WE'RE COMING BACK FROM A LAUNCH!
+ //
+ if (!launched)
+   {
+    long size=expsize*realnum+expmsize*realnumm,savings=0;
+
+
+    if (1024L*XMSTotalFree()<size)
+      {
+       savings=CgaXMSsize+EgaXMSsize+VgaXMSsize;
+       if (1024L*XMSTotalFree()<size-savings)
+        {
+         MouseShow();
+         ErrDialog("Not enough memory to load\n"
+                   "requested graphics.\n"," OK ");
+
+         MMFreePtr((memptr *)&GraphHeader);
+         MMFreePtr((memptr *)&packed);
+         MMFreePtr((memptr *)&unpack);
+
+         if (rtn)
+           return -1;
+         else
+           Quit("Get more Extended memory!");
+        }
+
+       if (CgaXMS)
+        {
+         XMSFreeMem(CgaXMS);
+         MMFreePtr((memptr *)&CgaXMSlookup);
+        }
+       if (EgaXMS)
+        {
+         XMSFreeMem(EgaXMS);
+         MMFreePtr((memptr *)&EgaXMSlookup);
+        }
+          if (VgaXMS)
+        {
+         XMSFreeMem(VgaXMS);
+         MMFreePtr((memptr *)&VgaXMSlookup);
+        }
+       CgaXMSsize=EgaXMSsize=VgaXMSsize=CgaXMS=EgaXMS=VgaXMS=0;
+      }
+
+    switch(tempvid)
+    {
+     case CGA:
+       xmshandle=CgaXMS=XMSAllocate(size);
+       CgaXMSsize=size;
+       break;
+     case EGA1:
+     case EGA2:
+       xmshandle=EgaXMS=XMSAllocate(size);
+       EgaXMSsize=size;
+       break;
+     case VGA:
+       xmshandle=VgaXMS=XMSAllocate(size);
+       VgaXMSsize=size;
+    }
+
+    ErrDialog("GRAPHICS INSTALLATION\n"
+             "Decompressing and\n"
+             "moving tiles into\n"
+             "Extended memory:","");
+   }
+ else
+   {
+    long size;
+
+
+    CgaXMS=TEDInfo->OldCgaXMS;
+    EgaXMS=TEDInfo->OldEgaXMS;
+    VgaXMS=TEDInfo->OldVgaXMS;
+
+    CgaXMSsize=TEDInfo->OldCgaXMSsize;
+    EgaXMSsize=TEDInfo->OldEgaXMSsize;
+    VgaXMSsize=TEDInfo->OldVgaXMSsize;
+
+    size=(num+numm)*4;
+    if (CgaXMS)
+      {
+          MMAllocate((memptr *)&CgaXMSlookup,size);
+       XMSmove(TEDInfo->CgaXMSlook,0,0,(long)MK_FP(CgaXMSlookup,0),size);
+       XMSFreeMem(TEDInfo->CgaXMSlook);
+       TEDInfo->CgaXMSlook=0;
+      }
+    if (EgaXMS)
+      {
+       MMAllocate((memptr *)&EgaXMSlookup,size);
+       XMSmove(TEDInfo->EgaXMSlook,0,0,(long)MK_FP(EgaXMSlookup,0),size);
+       XMSFreeMem(TEDInfo->EgaXMSlook);
+       TEDInfo->EgaXMSlook=0;
+      }
+    if (VgaXMS)
+      {
+       MMAllocate((memptr *)&VgaXMSlookup,size);
+       XMSmove(TEDInfo->VgaXMSlook,0,0,(long)MK_FP(VgaXMSlookup,0),size);
+       XMSFreeMem(TEDInfo->VgaXMSlook);
+       TEDInfo->VgaXMSlook=0;
+      }
+
+    switch(tempvid)
+    {
+     case CGA:
+       xmshandle=CgaXMS;
+       XMSlookup=CgaXMSlookup;
+       break;
+     case EGA1:
+     case EGA2:
+       xmshandle=EgaXMS;
+       XMSlookup=EgaXMSlookup;
+       break;
+     case VGA:
+       xmshandle=VgaXMS;
+       XMSlookup=VgaXMSlookup;
+    }
+
+    ErrDialog("RE-INITIALIZING...","");
+   }
+
+ ox=sx;
+ oy=sy;
+
+ //
+ // INSTALL GRAPHICS IF NOT A LAUNCH...
+ //
+ if (!launched)
+ {
+  switch(tempvid)
+  {
+   case CGA:
+     MMAllocate((memptr *)&CgaXMSlookup,(num+numm)*4);
+     XMSlookup=CgaXMSlookup;
+     break;
+   case EGA1:
+   case EGA2:
+     MMAllocate((memptr *)&EgaXMSlookup,(num+numm)*4);
+     XMSlookup=EgaXMSlookup;
+     break;
+   case VGA:
+     MMAllocate((memptr *)&VgaXMSlookup,(num+numm)*4);
+     XMSlookup=VgaXMSlookup;
+  }
+
+
+  //
+  // SET UP MEMORY CACHE IF ENOUGH IS AVAILABLE...
+  //
+  cacheon_h=0;
+  if (filelen(gname1)<16L*MMTotalFree())
+  {
+   LoadIn(gname1,(memptr *)&CacheBlock);
+   cacheon=1;
+  }
+  else
+  //
+  // DAMN! TRY XMS AS A LAST RESORT...
+  //
+  if (filelen(gname1)<1024l*XMSTotalFree())
+  {
+   #define TMPBUFSIZE 32000l
+   long amtleft,tmpoff=0,tmpsize;
+   memptr tblock;
+
+
+   amtleft=filelen(gname1);
+   MMAllocate(&tblock,TMPBUFSIZE);
+   cacheon_h=XMSAllocate(amtleft);
+   tmpsize=TMPBUFSIZE;
+   while(amtleft>0)
+   {
+       LoadFile(gname1,MK_FP(tblock,0),tmpoff,tmpsize);
+    XMSmove(0,(long)MK_FP(tblock,0),cacheon_h,tmpoff,tmpsize);
+    amtleft-=TMPBUFSIZE;
+    tmpoff+=TMPBUFSIZE;
+    tmpsize=(amtleft>TMPBUFSIZE)?TMPBUFSIZE:amtleft;
+   }
+
+   MMFreePtr(&tblock);
+   cacheon=2;
+  }
+
+  clearkeys();
+
+  //
+  // MOVE NONMASKED TILES INTO XMS MEMORY!
+  //      ---------
+  unpacksize=unpackoff=0;
+  unpackxms=xmsoff;
+  for (i=0;i<num;i++)
+  {
+   long size,off;
+
+
+   off=OFF3(offsets,index+i);
+   if (off==0xffffff)   // SPARSE TILE?
+     {
+      *(XMSlookup+i)=-1;
+      continue;
+     }
+
+   size=tile_len[i];
+
+   //
+   // GET COMPRESSED TILE DATA FROM CACHE OR DISK
+   //
+   if (cacheon==1)
+   {
+    //
+    // HUFFMAN DECOMPRESS
+    //
+    HuffExpand((unsigned char huge *)CacheBlock+off,(unsigned char huge *)unpack+unpackoff,
+         expsize,(huffnode *)hufftable);
+   }
+   else
+   if (cacheon==2)
+   {
+    XMSmove(cacheon_h,off,0,(long)packed,size);
+    //
+    // HUFFMAN DECOMPRESS
+    //
+    HuffExpand((unsigned char huge *)packed,(unsigned char huge *)unpack+unpackoff,
+         expsize,(huffnode *)hufftable);
+   }
+   else
+   {
+    LoadFile(gname1,(char huge *)packed,off,size);
+    //
+    // HUFFMAN DECOMPRESS
+    //
+    HuffExpand((unsigned char huge *)packed,(unsigned char huge *)unpack+unpackoff,
+         expsize,(huffnode *)hufftable);
+   }
+
+   unpacksize+=expsize;
+   unpackoff+=expsize;
+
+   *(XMSlookup+i)=xmsoff;
+   xmsoff+=expsize;
+
+   if (unpacksize>unpackmax-expsize)
+   {
+    XMSmove(0,(long)MK_FP(unpack,0),xmshandle,unpackxms,unpacksize);
+    unpacksize=unpackoff=0;
+    unpackxms=xmsoff;
+
+    sx=ox;
+    sy=oy;
+    printint(num+numm-i);
+    print(" ");
+   }
+
+   //
+   // ESC will exit!
+   //
+   if (keydown[1])
+     if (rtn)
+     {
+      switch(tempvid)
+      {
+       case CGA:
+        XMSFreeMem(CgaXMS);
+        MMFreePtr((memptr *)&CgaXMSlookup);
+        CgaXMS=0;
+        break;
+       case EGA1:
+       case EGA2:
+        XMSFreeMem(EgaXMS);
+        MMFreePtr((memptr *)&EgaXMSlookup);
+        EgaXMS=0;
+        break;
+       case VGA:
+        XMSFreeMem(VgaXMS);
+        MMFreePtr((memptr *)&VgaXMSlookup);
+        VgaXMS=0;
+      }
+
+      switch(videomode)
+      {
+       case CGA:
+        xmshandle=CgaXMS;
+        XMSlookup=CgaXMSlookup;
+        break;
+       case EGA1:
+       case EGA2:
+        xmshandle=EgaXMS;
+        XMSlookup=EgaXMSlookup;
+        break;
+       case VGA:
+        xmshandle=VgaXMS;
+        XMSlookup=VgaXMSlookup;
+      }
+
+      MMFreePtr((memptr *)&GraphHeader);
+      MMFreePtr((memptr *)&packed);
+      MMFreePtr((memptr *)&unpack);
+
+      if (cacheon)
+       MMFreePtr((memptr *)&CacheBlock);
+
+      return 0;
+     }
+     else
+       Quit("XMS LOADING ABORTED!");
+  }
+
+  //
+  // FLUSH THE FAST(?)-CACHE
+  //
+  if (unpacksize)
+  {
+   XMSmove(0,(long)MK_FP(unpack,0),xmshandle,unpackxms,unpacksize);
+   unpacksize=unpackoff=0;
+   unpackxms=xmsoff;
+  }
+
+  //
+  // MOVE MASKED TILES INTO XMS MEMORY!
+  //      ------
+  for (i=0;i<numm;i++)
+  {
+   long size,off;
+
+   off=OFF3(offsets,indexm+i);
+   if (off==0xffffff)   // SPARSE TILE?
+        {
+         *(XMSlookup+i+num)=-1;
+         continue;
+     }
+
+   size=tilem_len[i];
+
+   //
+   // GET COMPRESSED TILE DATA FROM CACHE OR DISK
+   //
+   if (cacheon==1)
+   {
+    //
+    // HUFFMAN DECOMPRESS
+    //
+    HuffExpand((unsigned char huge *)CacheBlock+off,(unsigned char huge *)unpack+unpackoff,
+         expmsize,(huffnode *)hufftable);
+   }
+   else
+   if (cacheon==2)
+   {
+    XMSmove(cacheon_h,off,0,(long)packed,size);
+    //
+    // HUFFMAN DECOMPRESS
+    //
+    HuffExpand((unsigned char huge *)packed,(unsigned char huge *)unpack+unpackoff,
+         expmsize,(huffnode *)hufftable);
+   }
+   else
+   {
+    LoadFile(gname1,(char huge *)packed,off,size);
+    //
+    // HUFFMAN DECOMPRESS
+    //
+    HuffExpand((unsigned char huge *)packed,(unsigned char huge *)unpack+unpackoff,
+         expmsize,(huffnode *)hufftable);
+   }
+
+   unpacksize+=expmsize;
+   unpackoff+=expmsize;
+
+   *(XMSlookup+i+num)=xmsoff;
+   xmsoff+=expmsize;
+
+   if (unpacksize>unpackmax-expmsize)
+   {
+    XMSmove(0,(long)MK_FP(unpack,0),xmshandle,unpackxms,unpacksize);
+       unpacksize=unpackoff=0;
+    unpackxms=xmsoff;
+
+    sx=ox;
+    sy=oy;
+    printint(numm-i);
+    print(" ");
+   }
+
+
+   //
+   // ESC will exit!
+   //
+   if (keydown[1])
+     if (rtn)
+     {
+      switch(tempvid)
+      {
+       case CGA:
+        XMSFreeMem(CgaXMS);
+        MMFreePtr((memptr *)&CgaXMSlookup);
+        CgaXMS=0;
+        break;
+       case EGA1:
+       case EGA2:
+        XMSFreeMem(EgaXMS);
+        MMFreePtr((memptr *)&EgaXMSlookup);
+        EgaXMS=0;
+        break;
+       case VGA:
+        XMSFreeMem(VgaXMS);
+        MMFreePtr((memptr *)&VgaXMSlookup);
+        VgaXMS=0;
+      }
+
+      switch(videomode)
+      {
+       case CGA:
+        xmshandle=CgaXMS;
+        XMSlookup=CgaXMSlookup;
+        break;
+       case EGA1:
+       case EGA2:
+        xmshandle=EgaXMS;
+        XMSlookup=EgaXMSlookup;
+        break;
+       case VGA:
+        xmshandle=VgaXMS;
+        XMSlookup=VgaXMSlookup;
+      }
+
+      MMFreePtr((memptr *)&GraphHeader);
+      MMFreePtr((memptr *)&packed);
+      MMFreePtr((memptr *)&unpack);
+
+      if (cacheon)
+       MMFreePtr((memptr *)&CacheBlock);
+
+      return 0;
+     }
+     else
+       Quit("XMS LOADING ABORTED!");
+  }
+  //
+  // FLUSH THE FAST-CACHE
+  //
+  if (unpacksize)
+  {
+   XMSmove(0,(long)MK_FP(unpack,0),xmshandle,unpackxms,unpacksize);
+   unpacksize=unpackoff=0;
+   unpackxms=xmsoff;
+  }
+
+  if (cacheon==1)
+    MMFreePtr((memptr *)&CacheBlock);
+  else
+  if (cacheon==2)
+    XMSFreeMem(cacheon_h);
+ }
+
+ //
+ // GET RID OF TILE-FILE CACHE MEMORY (OR WE'RE TOASTY)
+ //
+ MMFreePtr((memptr *)&GraphHeader);
+ MMFreePtr((memptr *)&packed);
+ MMFreePtr((memptr *)&unpack);
+
+ MMFreePtr((memptr *)&tile_len);
+ MMFreePtr((memptr *)&tilem_len);
+
+ whicht=0;
+ whichi=tilenum;
+ whichtm=tilenum;
+
+ switch(tsize)
+ {
+  case 1: lasticon=tilenum+36*maxiconrows;
+         break;
+  case 2: lasticon=tilenum+18*maxiconrows;
+         break;
+  case 3: lasticon=tilenum+7*maxiconrows;
+ }
+ firsticon=tilenum;
+
+ RestoreBackground();
+ return 1;
+}
+
+
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// Load TEDINFO.ext file
+//
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+void LoadInfoFile(void)
+{
+ char pname[14]="TEDINFO.",gfxname[14]="GFXINFO";
+
+
+ //
+ // Load the TEDINFO.ext file!
+ //
+ strcat(pname,ext);
+ strcpy(infoname,pname);
+
+ if (access(pname,0))
+   {
+    MMAllocate((memptr *)&TEDInfo,sizeof(InfoStruct));
+    _fmemset(TEDInfo,0,sizeof(InfoStruct));
+                               //  BFI  BFI
+    TEDInfo->pflags=0x27;      // 0010 0111
+   }
+ else
+   LoadIn(pname,(memptr *)&TEDInfo);
+
+ tsize=TEDInfo->tsize;
+ if (launchname[0])
+   _fmemcpy((char far *)TEDInfo->launchname,(char far *)launchname,14);
+
+ //
+ // LOAD THE "GFXINFO?.EXT" FILE
+ //
+ strcat(gfxname,format);
+ strcat(gfxname,".");
+ strcat(gfxname,ext);
+ LoadIn(gfxname,(memptr *)&GFXInfo);
+
+ switch(tsize)
+ {
+  case 1:
+    tilenum=GFXInfo->num8;
+    tilemnum=GFXInfo->num8m;
+    break;
+  case 2:
+    tilenum=GFXInfo->num16;
+    tilemnum=GFXInfo->num16m;
+    break;
+  case 3:
+    tilenum=GFXInfo->num32;
+    tilemnum=GFXInfo->num32m;
+ }
+
+ _fstrcpy((char far *)launchname,(char far *)TEDInfo->launchname);
+
+ if (launched)
+   TEDInfo->lastvid=LaunchInfo.lastmode;
+
+ //
+ // SET PLANE FLAGS BACK TO NORMAL
+ //
+ planeton=(TEDInfo->pflags>>6)&1;
+ planemon=(TEDInfo->pflags>>5)&1;
+ planeion=(TEDInfo->pflags>>4)&1;
+ viewton=(TEDInfo->pflags>>2)&1;
+ viewmon=(TEDInfo->pflags>>1)&1;
+ viewion=(TEDInfo->pflags)&1;
+
+ //
+ // SET BACKGROUND COLOR
+ //
+ BkgndColor=TEDInfo->BackgndColor;
+ if (BkgndColor>16)
+   TEDInfo->BackgndColor=BkgndColor=O_FGNDBACK;
+}
+
+
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// Find ?GAGRAPH.ext file
+//
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+void FindGraphFile(void)
+{
+ struct ffblk ffblk;
+ char pname[15]="?GAGRAPH.*",*tempstr,tiname[13]="TEDINFO.TMP";
+ int i,which;
+
+
+ //
+ // RETURNING FROM LAUNCH...GET INFO BACK
+ //
+ if (launched)
+   {
+       LoadFile(tiname,(char huge *)&LaunchInfo,0,0);
+       unlink(tiname);
+       videomode=LaunchInfo.lastmode;
+       switch(videomode)
+       {
+        case CGA:
+          format[0]='C';
+          break;
+        case EGA1:
+        case EGA2:
+          format[0]='E';
+          break;
+        case VGA:
+          format[0]='V';
+       }
+
+       strcpy(ext,LaunchInfo.ext);
+       projname[0]=format[0];
+       strcat(projname,"GAGRAPH.");
+       strcat(projname,ext);
+       return;
+   }
+
+ //
+ // Find ?GAGRAPH.ext
+ //
+ if (ext[0])
+   {
+       strcpy(pname,"?GAGRAPH.");
+       strcat(pname,ext);
+   }
+
+ if (findfirst(pname,&ffblk,FA_ARCH))
+   {
+       ErrDialog("I can't find a graphics\nfile! (ex:?GAGRAPH.ext)"," Alright ");
+       Quit("Can't work without graphics ya know!");
+   }
+
+
+ if (GfxToUse)
+   format[0] = GfxToUse;
+ else
+ {
+  // setup the dialog
+
+  strcpy(bstrings[0],ffblk.ff_name);
+  ProjButns[0].xoff=9;
+  ProjButns[0].yoff=2;
+  ProjButns[0].border=0;
+  ProjButns[0].text=bstrings[0];
+  for (i=1;i<10;i++)
+       {
+        if (findnext(&ffblk))
+          break;
+        strcpy(bstrings[i],ffblk.ff_name);
+        ProjButns[i].xoff=9;
+        ProjButns[i].yoff=2+i;
+        ProjButns[i].border=0;
+        ProjButns[i].text=bstrings[i];
+       }
+  ProjSelect.numbuttons=i;
+  ProjSelect.height=i+3;
+
+  which=1;
+  if (i>1)
+       do
+       {
+        which=DoDialog(&ProjSelect);
+       } while(!which);
+  which--;
+
+  tempstr=strpbrk(bstrings[which],".")+1;
+  strcpy(ext,tempstr);
+  format[0]=bstrings[which][0];
+ }
+
+ strcpy(projname,bstrings[which]);
+}
+
+//
+// draw border for project window
+//
+void DrawProjBord(int x,int y)
+{
+ DrawBorder(x+8,y+1,13,ProjSelect.height-2,1);
+}
+
+
+////////////////////////////////////////////////////
+//
+// Input amount of icons to reserve
+// Returns maximum # of icon rows to reserve
+//
+////////////////////////////////////////////////////
+btype ICb={"    ",8,3,1};
+DialogDef ICd={"Enter maximum amount\nof icons to reserve:",20,5,1,&ICb,NULL};
+
+int InputIconAmount(void)
+{
+ char tempstr[4];
+ int value;
+
+
+ if (!(MapFileHeader->maptype&IPLANE))
+   return 4;
+
+ MouseHide();
+ DrawDialog(&ICd,1);
+ while(1)
+ {
+  GetDialogXY(&ICd,&sx,&sy);
+  GetButtonXY(&ICd,0,&sx,&sy);
+  if (input(tempstr,3))
+  {
+   value=atoi(tempstr);
+   if (value>0)
+   {
+    MouseShow();
+    RestoreBackground();
+    return (value+17)/18;
+   }
+  }
+ }
+}
+
+
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// Unhook everything
+//
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+void Unhook(void)
+{
+ ShutdownKBD();
+ if (CgaXMS)
+   XMSFreeMem(CgaXMS);
+ if (EgaXMS)
+   XMSFreeMem(EgaXMS);
+ if (VgaXMS)
+   XMSFreeMem(VgaXMS);
+ if (XMSundoB)
+   XMSFreeMem(XMSundoB);
+ if (XMSundoF)
+   XMSFreeMem(XMSundoF);
+ if (XMSundoI)
+   XMSFreeMem(XMSundoI);
+ if (XMSmaps)
+   XMSFreeMem(XMSmaps);
+}
+
+void PatchPointers(void)
+{
+}
+
+
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// Menu Definitions
+//
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+MenuDef AboutMenu[]=
+  {{"About...",Item_About,0,0},
+   {"Video Mode Switch",Item_ModeSwitch,0,0x43},
+   {"Last Video Mode",Item_LastVideo,ALT,0x2c},
+   {"Memory Available",Item_PrintMem,0,0x44},
+   {"Launch Project",Item_Launch,ALT,0x26},
+   {"--------------------",NULL,0,0},
+//   {"Display Unused Tiles",Item_CountTiles,0,0},
+   {"Project Re-Select",Item_ProjectReSelect,0,0},
+   {"Visit DOS",Item_VisitDOS,0,0}
+  };
+
+MenuDef FileMenu[]=
+  {{"Edit New Map",Item_EditMap,ALT,0x18},
+   {"Save Map",Item_SaveMap,ALT,0x1f},
+   {"Create Map",Item_CreateMap,ALT,0x2e},
+   {"Delete Map",Item_DeleteMap,ALT,0x20},
+   {"Switch Map",Item_SwitchMap,ALT,0x11},
+   {"Amputate Maps",Item_Amputate},
+   {"---------------",NULL,0,0},
+   {"Import Maps",Item_ImportMaps,0,0},
+   {"Change ICON Rows",Item_ChangeIconRows,0,0},
+   {"Carmacize Maps",Item_Huffman,0,0},
+   {"Quit TED5",Item_Quit,ALT,0x2d}};
+
+MenuDef EditMenu[]=
+  {{"Switch to Last Map",Item_LastMap,ALT,0x32},
+   {"Edit TILEINFO/M Values",Item_EditTinfoValues,ALT,0x14},
+   {"Change LAUNCH name",Item_LAUNCHname,0,0},
+   {"Change PARM string",Item_PARMstring,0,0},
+   {"Edit TILEINFO/M Names",Item_EditTinfoNames,0,0},
+   {"Add/Del TILEINFO/M Planes",Item_AddDelTinfo,0,0},
+   {"Edit MAP Names",Item_EditMapNames,0,0},
+   {"Change MAP Edges",Item_EditMapEdges,0,0}};
+
+MenuDef ModeMenu[]=
+{
+ {"Copy Mode",Item_Copy,0,0x2e},
+ {"Paste Mode",Item_Paste,0,0x19},
+ {"Block Fill",Item_BlockFill,0,0x30},
+ {"Flood Fill",Item_FloodFill,0,0x21},
+ {"Undo last action",Item_Undo,0,0x16},
+ {"Tile Search",Item_TileSearch,0,0x14},
+ {"GridMode toggle",Item_GridMode,0,0x22},
+ {"Snap-Paste toggle",Item_SnapTog,0,0x1f},
+ {"Paste Overlay toggle",Item_POtog,0,0x3d}
+};
+
+
+MenuDef MiscMenu[]=
+{
+ {"Select Tile",Item_SelectTile,0,0x39},
+ {"Map Stats",Item_MapStats,0,0x17},
+ {"Toggle INFOBAR",Item_ToggleInfo,0,0x42},
+ {"New INFOPLANE value",Item_InputInfoplane,0,0x1c},
+ {"View Map & Goto",Item_ViewMap,ALT,0x2f},
+ {"ReView Map & Goto",Item_ReviewMap,0,0xe},
+ {"Change LAUNCH icon",Item_ChangeLaunchIcon,0,0},
+ {"Change bkgnd color",Item_ChangeBkgndColor,0,0},
+ {"TILEINFOM Copy",Item_TINFOCopy,0,0},
+ {"Graphic Map Dump",Item_GraphicDump,0,0}
+};
+
+
+MBarDef TED5MenuBar[]=
+  {{9,AboutMenu," ? "},
+   {11,FileMenu,"File"},
+   {8,EditMenu,"Edit"},
+   {9,ModeMenu,"Modes"},
+   {10,MiscMenu,"Misc"},
+   {0,0,""}};
diff --git a/16/ted5/TED5.DSK b/16/ted5/TED5.DSK
new file mode 100755 (executable)
index 0000000..2e17920
Binary files /dev/null and b/16/ted5/TED5.DSK differ
diff --git a/16/ted5/TED5.EXE b/16/ted5/TED5.EXE
new file mode 100755 (executable)
index 0000000..02076f9
Binary files /dev/null and b/16/ted5/TED5.EXE differ
diff --git a/16/ted5/TED5.H b/16/ted5/TED5.H
new file mode 100755 (executable)
index 0000000..e44ff89
--- /dev/null
@@ -0,0 +1,356 @@
+#define IDSTRING       "TED5v1.0"
+#define TITLESTR       "TED5 vD.IP"
+#define IDSTSTR                "         "TITLESTR
+
+#include <stdio.h>
+#include <process.h>
+#include <io.h>
+#include <dos.h>
+#include <alloc.h>
+#include <dir.h>
+#include <mem.h>
+#include <string.h>
+#include <stdlib.h>
+#include <conio.h>
+#include <fcntl.h>
+#include "lib.h"
+#include "memmgr.h"
+#include "menu.h"
+#include "jhuff.h"
+#include "xms.h"
+
+#define        SGN(x)          (x>0?1:x<0?-1:0)
+#define        OFF3(m,i)       (*(long huge *)((char huge *)m+(i)*3)&0xffffff)
+
+
+//
+// Defs for TED5
+//
+
+typedef enum {TILES,MASKED,ICONS} screentype;
+typedef enum {DATA,CODE,FARDATA} segtype;      // FOR MAKEOBJ ONLY
+
+#define SCindex                0x3C4
+#define SCmapmask      2
+#define GCindex                0x3CE
+#define GCreadmap      4
+#define GCmode         5
+#define crtcaddr       0x3d4
+
+//
+// STRUCTURE OF TED5 TEMPFILE WHILE LAUNCHING
+//
+typedef struct {
+               video lastmode;
+               char ext[4];
+              } TempStruct;
+
+//
+// STRUCTURE OF THE "TEDINFO.EXT" FILE THAT TED5 CREATES
+//
+typedef struct {
+               int level,lastvid,lastx,lasty,tsize;
+               int OldCgaXMS,OldEgaXMS,OldVgaXMS;
+               long OldCgaXMSsize,OldEgaXMSsize,OldVgaXMSsize;
+               int CgaXMSlook,EgaXMSlook,VgaXMSlook;
+               char permicon,pflags;
+               int oscrx,oscry;
+               char parmstring[64],launchname[14];
+               char BackgndColor;
+               char ImportPath[64];
+              } InfoStruct;
+
+//
+// STRUCTURE OF THE "GFXINFO?.EXT" FILE THAT IGRAB CREATES
+//
+typedef struct {
+                int num8,num8m,num16,num16m,num32,num32m;
+                int off8,off8m,off16,off16m,off32,off32m;
+                int numpics,numpicm,numsprites;
+                int offpic,offpicm,offsprites;
+                int offpicstr,offpicmstr,offsprstr;
+                int numexterns,offexterns;
+              } GfxStruct;
+
+//
+// TED5 LOADS & SAVES THIS HEADER FOR INTERNAL MAPFILE USAGE
+//
+typedef struct { unsigned maptype;     //bit 0=bkgnd/1=frgnd/2=info
+                unsigned tsize;        //1=8/2=16/3=32
+
+                unsigned numtplanes,oldtilenum;
+                long tileinfooff[10];
+                unsigned tileinfolen[10];
+                char tnames[10][8];
+
+                unsigned numtmplanes,oldtilemnum;
+                long tileinfomoff[10];
+                unsigned tileinfomlen[10];
+                char tmnames[10][8];
+
+                unsigned RLEWtag;
+                long dataoffsets[100];
+                long datalengths[100];
+
+                int NumIconRows;
+              } MapFileHeaderStr;
+
+//
+// TED5 SAVES THIS MAPFILE HEADER FOR THE GAME
+//
+typedef struct {
+                unsigned RLEWtag;
+                long dataoffsets[100];
+
+              } OutputHeadStr;
+
+//
+// EACH AND EVERY MAP HAS THIS HEADER (IF THE MAP EXISTS)
+//
+typedef struct { long mapbkgndpl;
+                long mapfrgndpl;
+                long mapinfopl;
+                unsigned mapbkgndlen;
+                unsigned mapfrgndlen;
+                unsigned mapinfolen;
+                unsigned width,height;
+                char name[16];
+              } MapHeaderStr;
+
+//
+// SPECIFY WHAT, WHEREFROM, AND HOW TO COPY A REGION
+//
+typedef struct {
+                char PlanesCopied;     // use BPLANE,FPLANE,IPLANE to mask
+                int MapOrTileSelect;   // 0:map,1:tileselect
+                int x,y,w,h;           // from map or tileselect
+              } CopyStr;
+
+//
+// UNDO REGION
+//
+typedef struct {
+               int x,y,w,h;
+              } UndoStr;
+
+//
+// LAST-BUILT "VIEWMAP"
+//
+typedef struct {
+               unsigned step,built_flag,EGAseg,maxpack;
+              } VMapStr;
+
+
+//
+// HEADER FOR APPLE-PREFERRED FILES
+//
+typedef struct { long length;
+                char Kind[5];
+                int MasterMode;
+                int PixelsPerLine;
+                int NumColorTables;
+                int ColorTable[16];
+                int NumScanLines;
+              } ApPrefStr;
+
+#define CREATED                1
+#define NOTCREATED     2
+#define ANYLIST                3
+
+#define BPLANE         1
+#define FPLANE         2
+#define IPLANE         4
+
+#define O_FGNDBACK     4
+#define ICONBACK       3
+
+#define TINFOWIDTH     3
+#define TINFOHEIGHT    7
+#define TINFOHEIGHTEGA2        25
+
+extern MBarDef TED5MenuBar[];
+extern DialogDef DoCreated;
+
+extern UndoStr UndoRegion;
+extern CopyStr TileCopy;
+extern MapFileHeaderStr _seg *MapFileHeader;
+extern char _seg *Tinfo[10],_seg *TMinfo[10],_seg *GraphHeader;
+extern long _seg *XMSlookup,_seg *CgaXMSlookup,_seg *EgaXMSlookup,_seg *VgaXMSlookup;
+extern int _seg *MapBkgnd,_seg *MapFrgnd,_seg *MapInfoPl,
+    _seg *CutBkgnd,_seg *CutFrgnd,_seg *CutInfoPl;
+extern MapHeaderStr MapHeader;
+
+#if 0
+extern char far TOM;   // JOKE SHIT!
+#endif
+
+extern TempStruct LaunchInfo;
+extern InfoStruct _seg *TEDInfo;
+extern GfxStruct _seg *GfxInfo;
+extern video lastvideo,videomode;
+extern screentype whichscreen;
+extern VMapStr VMapData;
+
+extern char launchname[64],ext[4],format[2],projname[64],mapname[64],planes,
+       infoname[64],mapheadname[64],tdata,MapNames[100][16],parmstring[64];
+extern char SM_name[64],SM_loadname[64],BkgndColor;
+
+extern unsigned temp,whichmap,numtplanes,tilenum,tilemnum,numtmplanes,left,
+       DirtyFlag,tilelen,tilemlen,whicht,whichtm,whichi,
+       tsize,infoy,infomaxw,mapwidth,mapheight,screenw,usingbat,
+       screenh,planeton,planemon,planeion,maxiconrows,lasticon,firsticon,
+       viewton,viewmon,viewion,XMSundoB,XMSundoF,XMSundoI,XMSmaps,
+       EgaXMS,CgaXMS,VgaXMS,xmshandle,GridMode,SnapMode,snapx,snapy,
+       snapxsize,snapysize,writeH,F3_flag,NoAbout;
+extern int tilebase,tilembase,infobaron,xbase,ybase,scrnbot,scrnrgt,
+       FillMode,PasteMode,SelectMode,SelX1,SelY1,PasteOK,SelX2,SelY2,pixelx,pixely,
+       selectcols,px,py,lastmap,TIybase,TIymbase,TIxbase,TIxmbase,BfillMode,
+       Plotting,TsearchMode;
+extern long CgaXMSsize,EgaXMSsize,VgaXMSsize;
+
+extern void far *XMSdriver;
+
+//
+// FUNCTION PROTOTYPES
+//
+
+//
+// LIB_A.ASM
+//
+extern void CGAcharout(int x,int y,char ch);
+extern void EGAcharout(int x,int y,char ch,video vid);
+extern void VGAcharout(int x,int y,char ch);
+
+//
+// TED5_A.ASM
+//
+extern unsigned EGA1lookup[200];
+extern unsigned EGA2lookup[200];
+extern void DrawTile(int x,int y,int tile);
+extern void CopyCGA(int srcx,int srcy,int width,int height,int destx,int desty);
+extern void CopyEGA(int srcx,int srcy,int width,int height,int destx,int desty);
+extern void CopyVGA(int srcx,int srcy,int width,int height,int destx,int desty);
+extern void Overlay(int tsize);
+
+//
+// TED5
+//
+void FindGraphFile(void);
+void HandleEvent(void);
+void Continuous(void);
+void LoadInfoFile(void);
+int  LoadGraphStuff(int rtn,video newvid);
+void LoadMapHeader(void);
+void ParseCmdline(void);
+void InitTed5(void);
+void CallDesktop(void);
+void SelectTiles(int screen);
+void STnot(int x,int y);
+void DrawProjBord(int x,int y);
+void DrawInfoBar(void);
+void PrintCoords(void);
+void FigureScreenEdges(void);
+void errsound(void);
+void DrawMap(void);
+void CheckSelectEdges(int x,int y,int i,int j);
+int  InputIconAmount(void);
+
+//
+// TED5-1
+//
+void Item_InputInfoplane(void);
+void Item_SelectTile(void);
+void Item_EditTinfoNames(void);
+void Item_BlockFill(void);
+void Item_TileSearch(void);
+void Item_Launch(void);
+void Item_Undo(void);
+void Item_TINFOCopy(void);
+
+void CreateMap(int exitok);
+int  SelectMap(int exitok,int createflg,char *title);
+int  PickMorePlanes(void);
+void DoBlockFill(void);
+void RemoveUndoBuffers(void);
+void AllocateUndoBuffers(void);
+void RestoreUndo(void);
+void SaveUndo(int x,int y,int w,int h);
+void CopyUndoRegion(void);
+void SaveOutputHeader(void);
+void SaveTEDInfo(void);
+void BackupFile(char *filename);
+
+void TInfoNon(int x,int y,int b);
+void TInfoNoff(int x,int y,int b);
+void TInfoMNon(int x,int y,int b);
+void TInfoMNoff(int x,int y,int b);
+void TIDoneOn(int x,int y);
+void TIDoneOff(int x,int y);
+
+
+//
+// TED5-2
+//
+void Item_About(void);
+void Item_ModeSwitch(void);
+void Item_DeleteMap(void);
+void Item_EditMap(void);
+void Item_SaveMap(void);
+void Item_CreateMap(void);
+void Item_Quit(void);
+void Item_MapStats(void);
+void Item_ToggleInfo(void);
+void Item_Amputate(void);
+void Item_SwitchMap(void);
+void Item_EditMapNames(void);
+void Item_Copy(void);
+void Item_Paste(void);
+void Item_LastVideo(void);
+void Item_FloodFill(void);
+void Item_LastMap(void);
+void Item_CountTiles(void);
+int  CheckForMapSave(void);
+void DoFloodFill(int x,int y,int whichb);
+
+void DrawTileSelect(int deltarows,int *numrows,int *numcols);
+void DrawUnused(int deltarow);
+void DrawCurrentTiles(void);
+void ZeroModes(void);
+
+//
+// TED5-3
+//
+void Item_EditMapEdges(void);
+void Item_PrintMem(void);
+void Item_Huffman(void);
+void CheckInfoValues(int i,int j,int tilei);
+void PrintMem(int x,int y);
+void EraseFloatPaste(void);
+void DrawFloatPaste(void);
+void CopyScreen(int srcx,int srcy,int width,int height,int destx,int desty);
+void Item_LAUNCHname(void);
+void Item_PARMstring(void);
+void Item_ChangeIconRows(void);
+void Item_ChangeLaunchIcon(void);
+void Item_ChangeBkgndColor(void);
+
+//
+// TED5-4
+//
+void SignalSound(void);
+void Item_GraphicDump(void);
+void Item_EditTinfoValues(void);
+void Item_ProjectReSelect(void);
+void Item_AddDelTinfo(void);
+void Item_GridMode(void);
+void Item_SnapTog(void);
+void Item_ViewMap(void);
+void Item_ReviewMap(void);
+void Item_ImportMaps(void);
+void Item_VisitDOS(void);
+void Item_POtog(void);
+void Do_ViewMap(int how);
+int  MakeOBJ(char *filename,char *destfilename,char *public,segtype whichseg,char *farname);
+void DrawTinfoScreen(int thescreen,int deltax,int deltay);
+void EnterTinfoValue(int whichtinfo,int mx,int my,int H_or_V);
+void UseTinfoValue(int whichtinfo,int mx,int my,int PickupOrDrop);
diff --git a/16/ted5/TED5.MAP b/16/ted5/TED5.MAP
new file mode 100755 (executable)
index 0000000..1d9315e
--- /dev/null
@@ -0,0 +1,37 @@
+
+ Start  Stop   Length Name               Class
+
+ 00000H 03D85H 03D86H _TEXT              CODE
+ 03D86H 075F3H 0386EH TED5_TEXT          CODE
+ 075F4H 0AAB4H 034C1H TED5-1_TEXT        CODE
+ 0AAB5H 0DF0EH 0345AH TED5-2_TEXT        CODE
+ 0DF0FH 11A7EH 03B70H TED5-3_TEXT        CODE
+ 11A7FH 155C6H 03B48H TED5-4_TEXT        CODE
+ 155C8H 15F88H 009C1H TED5_A_TEXT        CODE
+ 15F89H 18B31H 02BA9H MENU_TEXT          CODE
+ 18B32H 1998FH 00E5EH LIB_TEXT           CODE
+ 19990H 1A2B3H 00924H MEMMGR_TEXT        CODE
+ 1A2B4H 1A55FH 002ACH XMS_TEXT           CODE
+ 1A560H 1B034H 00AD5H JHUFF_TEXT         CODE
+ 1B038H 1B3D8H 003A1H LIB_A_TEXT         CODE
+ 1B3E0H 1DB46H 02767H EMU_PROG           CODE
+ 1DB50H 1E117H 005C8H E87_PROG           CODE
+ 1E120H 1E120H 00000H _FARDATA           FAR_DATA
+ 1E120H 1F11FH 01000H TEDcharset         FAR_DATA
+ 1F120H 1F120H 00000H _FARBSS            FAR_BSS
+ 1F120H 1F120H 00000H _OVERLAY_          OVRINFO
+ 1F120H 1F120H 00000H _1STUB_            STUBSEG
+ 1F120H 25277H 06158H _DATA              DATA
+ 25278H 25279H 00002H _CVTSEG            DATA
+ 2527AH 2527AH 00000H _SCNSEG            DATA
+ 2527AH 2527AH 00000H _CONST             CONST
+ 2527AH 25291H 00018H _INIT_             INITDATA
+ 25292H 25292H 00000H _INITEND_          INITDATA
+ 25292H 25297H 00006H _EXIT_             EXITDATA
+ 25298H 25298H 00000H _EXITEND_          EXITDATA
+ 25298H 29B6BH 048D4H _BSS               BSS
+ 29B6CH 29B6CH 00000H _BSSEND            BSSEND
+ 29B70H 29BEFH 00080H _STACK             STACK
+
+Program entry point at 0000:0000
+
diff --git a/16/ted5/TED5.PRJ b/16/ted5/TED5.PRJ
new file mode 100755 (executable)
index 0000000..f05bc86
Binary files /dev/null and b/16/ted5/TED5.PRJ differ
diff --git a/16/ted5/TED5.SYM b/16/ted5/TED5.SYM
new file mode 100755 (executable)
index 0000000..6e4d3db
Binary files /dev/null and b/16/ted5/TED5.SYM differ
diff --git a/16/ted5/TED5.TDK b/16/ted5/TED5.TDK
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/16/ted5/TED5_A.ASM b/16/ted5/TED5_A.ASM
new file mode 100755 (executable)
index 0000000..d8150ea
--- /dev/null
@@ -0,0 +1,1385 @@
+;====================================================
+;
+; TED5 ASM Routines
+;
+;====================================================
+       IDEAL
+       P386N
+       MODEL   medium,C
+
+extrn  XMSdriver:DWORD
+extrn  videomode:WORD,xmshandle:WORD,XMSlookup:WORD
+extrn  tilenum:WORD,lasticon:WORD,firsticon:WORD
+extrn  CGAlookup:WORD,EGA1lookup:WORD,EGA2lookup:WORD,VGAlookup:WORD
+
+       DATASEG
+
+SCindex        =       3c4h
+SCmapmask =    2
+GCindex =              3CEh
+GCreadmap =    4
+GCmode         =       5
+
+CombTable dw   CombineCGA,CombineEGA,CombineEGA,CombineVGA
+DrawTable dw   DrawTCGA,DrawTEGA1,DrawTEGA2,DrawTVGA
+OverTable dw   OverlayCGA,OverlayEGA,OverlayEGA,OverlayVGA
+
+cgacolors db   55h,0aah
+egacolors dw   0,0ffffh
+
+oldh   db      0
+oldy   dw      0
+horzadd dw     0
+wsize  dw      1,2,4
+hsize  dw      8,16,32
+twidth dw      0
+theight        dw      0
+bmlen  dw      0
+masklen        dw      0
+
+csize  dw      32,64,256
+esize  dw      32,128,512
+vsize  dw      64,256,1024
+
+cmsize dw      64,128,512
+emsize dw      40,160,640
+vmsize dw      128,512,2048
+
+       PUBLIC  tdata
+tdata  db      2048 dup(?)
+tdata1 db      2048 dup(?)
+
+;
+; XMS move structure
+;
+blen   dw      0,0
+shandle        dw      0
+soff   dd      0
+dhandle dw     0
+doff   dd      tdata1
+
+
+Csparse        dw      csp8,csp16,csp32
+Esparse        dw      esp8,esp16,esp32
+Vsparse        dw      vsp8,vsp16,vsp32
+
+csp8   db      0ffh,0ffh
+       REPT    7
+       db      0c0h,0
+       ENDM
+csp16  db      4 dup (0ffh)
+       REPT    15
+       db      0c0h
+       db      3 dup (0)
+       ENDM
+csp32  db      8 dup (0ffh)
+       REPT    31
+       db      0c0h
+       db      7 dup(0)
+       ENDM
+
+LABEL  esp8    BYTE
+       REPT    4
+       db      0ffh
+       db      7 dup (80h)
+       ENDM
+LABEL  esp16   BYTE
+       REPT    4
+       db      0ffh,0ffh
+       REPT    15
+       db      80h,0
+       ENDM
+       ENDM
+LABEL  esp32   BYTE
+       REPT    4
+       db      4 dup (0ffh)
+       REPT    31
+       db      80h,0,0,0
+       ENDM
+       ENDM
+
+vsp8   db      8 dup(0ffh)
+       REPT    7
+       db      0ffh,7 dup(0)
+       ENDM
+vsp16  db      16 dup(0ffh)
+       REPT    15
+       db      0ffh,15 dup(0)
+       ENDM
+vsp32  db      32 dup(0ffh)
+       REPT    31
+       db      0ffh,31 dup(0)
+       ENDM
+
+
+       CODESEG
+;====================================================
+;
+; Combine tiles together (background,foreground,icons)
+;
+;====================================================
+PUBLIC CombineTiles
+PROC   CombineTiles
+       ARG     tileb:WORD,tilef:WORD,tilei:WORD,tsize:WORD
+
+       push    si
+       push    di
+
+       cld
+       mov     bx,[tsize]
+       shl     bx,1
+       mov     dx,[hsize+bx-2]
+       mov     [theight],dx
+       mov     cx,[wsize+bx-2]
+       mov     [twidth],cx
+       mov     ax,[xmshandle]
+       mov     [shandle],ax            ;set XMS handle
+
+       mov     si,[videomode]
+       shl     si,1
+       mov     ax,[CombTable+si]
+       jmp     ax
+;
+; Combine CGA tiles
+;
+LABEL  CombineCGA      PROC
+
+       shl     [twidth],1
+       mov     cx,[cmsize+bx-2]
+       mov     [bmlen],cx
+       mov     ax,[csize+bx-2]         ;get length of block to move
+       mov     [blen],ax
+       sub     cx,ax
+       mov     [masklen],cx
+
+;
+; Handle the background tiles first!
+;
+       mov     ax,[tileb]
+       cmp     ax,8000h                ;solid color?
+       jb      @@c1
+       neg     ax
+
+       mov     di,ds
+       mov     es,di
+       mov     di,OFFSET tdata
+       mov     bx,ax
+       and     bx,1
+       mov     al,[cgacolors+bx]
+
+       mov     cx,[blen]
+       rep stosb
+       jmp     SHORT @@c2
+
+@@c1:
+       shl     ax,2
+       mov     bx,ax
+       mov     es,[XMSlookup]          ;(LONG SEG *)
+       mov     ax,[es:bx]
+       mov     [WORD PTR soff],ax
+       mov     ax,[es:bx+2]
+       mov     [WORD PTR soff+2],ax
+       cmp     ax,-1                   ;SPARSE TILE?
+       je      @@c1a
+
+       mov     ax,OFFSET tdata         ;(quickie modification since "doff"
+       mov     [WORD doff],ax          ; should always point to "tdata1")
+       mov     si,OFFSET blen
+       mov     ah,11
+       call    [DWORD XMSdriver]       ;move tile into tdata1
+       mov     ax,OFFSET tdata1
+       mov     [WORD doff],ax          ;ahhh....back to normal
+
+       jmp     @@c2
+;
+; Copy sparse tile to tdata
+;
+@@c1a:
+       mov     bx,[tsize]
+       shl     bx,1
+       mov     si,[Csparse+bx-2]
+       mov     di,OFFSET tdata
+       mov     cx,[blen]
+       shr     cx,1                    ;for WORD copy
+       mov     ax,ds
+       mov     es,ax
+       rep movsw
+
+;
+; Handle foreground tiles
+;
+@@c2:
+       mov     bx,[tilef]
+       cmp     bx,0
+       je      @@c3                    ;any masked tile?
+
+       shl     bx,2
+       mov     es,[XMSlookup]
+       mov     ax,[es:bx]
+       mov     [WORD PTR soff],ax
+       mov     ax,[es:bx+2]
+       mov     [WORD PTR soff+2],ax
+       cmp     ax,-1                   ;SPARSE MASKED TILE?
+       je      @@c3
+
+       mov     ax,[bmlen]
+       mov     [blen],ax               ;set masked tile length for XMS copy
+       mov     si,OFFSET blen
+       mov     ah,11
+       call    [DWORD XMSdriver]       ;move tile into tdata1
+;
+; now we have the masked tile in "tdata1".
+; time to mask it onto "tdata"
+;
+       mov     si,OFFSET tdata1
+       add     si,[masklen]            ;SI = masked tile's tiledata
+       mov     di,OFFSET tdata         ;DI = tile in "tdata"
+
+       mov     dx,[theight]
+       mov     bx,OFFSET tdata1        ;BX = mask
+@@c2a:
+       mov     cx,[twidth]
+@@c2b:
+       mov     al,[bx]                 ;get mask byte
+       and     [di],al                 ;and tdata with it
+       lodsb                           ;get tilem byte
+       or      [di],al                 ;OR it onto tdata
+       inc     di
+       inc     bx
+       loop    @@c2b
+       dec     dx
+       jnz     @@c2a
+;
+; Handle icons (foreground tiles)
+;
+@@c3:
+       mov     bx,[tilei]
+       cmp     bx,[lasticon]
+       ja      @@cexit                 ;any icons?
+       cmp     bx,[firsticon]
+       jbe     @@cexit
+
+       shl     bx,2
+       mov     es,[XMSlookup]
+       mov     ax,[es:bx]
+       mov     [WORD PTR soff],ax
+       mov     ax,[es:bx+2]
+       mov     [WORD PTR soff+2],ax
+
+       mov     ax,[bmlen]
+       mov     [blen],ax               ;set masked tile length for XMS copy
+       mov     si,OFFSET blen
+       mov     ah,11
+       call    [DWORD XMSdriver]       ;move tile into tdata1
+;
+; now we have the masked tile in "tdata1".
+; time to mask it onto "tdata"
+;
+       mov     si,OFFSET tdata1
+       add     si,[masklen]            ;SI = masked tile's tiledata
+       mov     di,OFFSET tdata         ;DI = tile in "tdata"
+
+       mov     dx,[theight]
+       mov     bx,OFFSET tdata1        ;BX = mask
+@@c3a:
+       mov     cx,[twidth]
+@@c3b:
+       mov     al,[bx]                 ;get mask byte
+       and     [di],al                 ;and tdata with it
+       lodsb                           ;get tilem byte
+       or      [di],al                 ;OR it onto tdata
+       inc     di
+       inc     bx
+       loop    @@c3b
+       dec     dx
+       jnz     @@c3a
+@@cexit:
+       pop     di
+       pop     si
+       ret
+
+;
+; Combine EGA tiles
+;
+LABEL  CombineEGA      PROC
+
+       mov     cx,[emsize+bx-2]
+       mov     [bmlen],cx
+       mov     ax,[esize+bx-2]         ;get length of block to move
+       mov     [blen],ax
+       sub     cx,ax
+       mov     [masklen],cx
+
+;
+; Handle the background tiles first!
+;
+       mov     ax,[tileb]
+       cmp     ax,8000h                ;solid color?
+       jb      @@e1
+       neg     ax
+
+       mov     di,ds
+       mov     es,di
+       mov     di,OFFSET tdata
+       mov     dx,ax
+
+       mov     cx,[blen]               ;plane 0
+       shr     cx,3
+       mov     bx,dx
+       shr     dx,1
+       and     bx,1
+       shl     bx,1
+       mov     ax,[egacolors+bx]
+       rep stosw
+
+       mov     cx,[blen]               ;plane 1
+       shr     cx,3
+       mov     bx,dx
+       shr     dx,1
+       and     bx,1
+       shl     bx,1
+       mov     ax,[egacolors+bx]
+       rep stosw
+
+       mov     cx,[blen]               ;plane 2
+       shr     cx,3
+       mov     bx,dx
+       shr     dx,1
+       and     bx,1
+       shl     bx,1
+       mov     ax,[egacolors+bx]
+       rep stosw
+
+       mov     cx,[blen]               ;plane 3
+       shr     cx,3
+       mov     bx,dx
+       shr     dx,1
+       and     bx,1
+       shl     bx,1
+       mov     ax,[egacolors+bx]
+       rep stosw
+       jmp     SHORT @@e2
+
+@@e1:
+       shl     ax,2
+       mov     bx,ax
+       mov     es,[XMSlookup]          ;(LONG SEG *)
+       mov     ax,[es:bx]
+       mov     [WORD PTR soff],ax
+       mov     ax,[es:bx+2]
+       mov     [WORD PTR soff+2],ax
+       cmp     ax,-1                   ;SPARSE TILE?
+       je      @@e1a
+
+       mov     ax,OFFSET tdata         ;(quickie modification since "doff"
+       mov     [WORD doff],ax          ; should always point to "tdata1")
+       mov     si,OFFSET blen
+       mov     ah,11
+       call    [DWORD XMSdriver]       ;move tile into tdata1
+       mov     ax,OFFSET tdata1
+       mov     [WORD doff],ax          ;ahhh....back to normal
+
+       jmp     @@e2
+;
+; Copy sparse tile to tdata
+;
+@@e1a:
+       mov     bx,[tsize]
+       shl     bx,1
+       mov     si,[Esparse+bx-2]
+       mov     di,OFFSET tdata
+       mov     cx,[blen]
+       shr     cx,1                    ;for WORD copy
+       mov     ax,ds
+       mov     es,ax
+       rep movsw
+
+;
+; Handle foreground tiles
+;
+@@e2:
+       mov     bx,[tilef]
+       cmp     bx,0
+       je      @@e3                    ;any masked tile?
+
+       shl     bx,2
+       mov     es,[XMSlookup]
+       mov     ax,[es:bx]
+       mov     [WORD PTR soff],ax
+       mov     ax,[es:bx+2]
+       mov     [WORD PTR soff+2],ax
+       cmp     ax,-1                   ;SPARSE MASKED TILE?
+       je      @@e3
+
+       mov     ax,[bmlen]
+       mov     [blen],ax               ;set masked tile length for XMS copy
+       mov     si,OFFSET blen
+       mov     ah,11
+       call    [DWORD XMSdriver]       ;move tile into tdata1
+;
+; now we have the masked tile in "tdata1".
+; time to mask it onto "tdata"
+;
+       mov     si,OFFSET tdata1
+       add     si,[masklen]            ;SI = masked tile's tiledata
+       mov     di,OFFSET tdata         ;DI = tile in "tdata"
+       mov     ah,4
+@@e2a0:
+       mov     dx,[theight]
+       mov     bx,OFFSET tdata1        ;BX = mask
+@@e2a:
+       mov     cx,[twidth]
+@@e2b:
+       mov     al,[bx]                 ;get mask byte
+       and     [di],al                 ;and tdata with it
+       lodsb                           ;get tilem byte
+       or      [di],al                 ;OR it onto tdata
+       inc     di
+       inc     bx
+       loop    @@e2b
+       dec     dx
+       jnz     @@e2a
+       dec     ah
+       jnz     @@e2a0                  ;do all 4 planes!
+;
+; Handle icons (foreground tiles)
+;
+@@e3:
+       mov     bx,[tilei]
+       cmp     bx,[lasticon]
+       ja      @@eexit                 ;any icons?
+       cmp     bx,[firsticon]
+       jbe     @@eexit
+
+       shl     bx,2
+       mov     es,[XMSlookup]
+       mov     ax,[es:bx]
+       mov     [WORD PTR soff],ax
+       mov     ax,[es:bx+2]
+       mov     [WORD PTR soff+2],ax
+
+       mov     ax,[bmlen]
+       mov     [blen],ax               ;set masked tile length for XMS copy
+       mov     si,OFFSET blen
+       mov     ah,11
+       call    [DWORD XMSdriver]       ;move tile into tdata1
+;
+; now we have the masked tile in "tdata1".
+; time to mask it onto "tdata"
+;
+       mov     si,OFFSET tdata1
+       add     si,[masklen]            ;SI = masked tile's tiledata
+       mov     di,OFFSET tdata         ;DI = tile in "tdata"
+       mov     ah,4
+@@e3a0:
+       mov     dx,[theight]
+       mov     bx,OFFSET tdata1        ;BX = mask
+@@e3a:
+       mov     cx,[twidth]
+@@e3b:
+       mov     al,[bx]                 ;get mask byte
+       and     [di],al                 ;and tdata with it
+       lodsb                           ;get tilem byte
+       or      [di],al                 ;OR it onto tdata
+       inc     di
+       inc     bx
+       loop    @@e3b
+       dec     dx
+       jnz     @@e3a
+       dec     ah
+       jnz     @@e3a0                  ;do all 4 planes!
+@@eexit:
+       pop     di
+       pop     si
+       ret
+
+;
+; Combine VGA tiles
+;
+LABEL  CombineVGA      PROC
+
+       shl     [twidth],3
+       mov     cx,[vmsize+bx-2]
+       mov     [bmlen],cx
+       mov     ax,[vsize+bx-2]         ;get length of block to move
+       mov     [blen],ax
+       sub     cx,ax
+       mov     [masklen],cx
+
+;
+; Handle the background tiles first!
+;
+       mov     ax,[tileb]
+       cmp     ax,8000h                ;solid color?
+       jb      @@v1
+       neg     ax
+
+       mov     di,ds
+       mov     es,di
+       mov     di,OFFSET tdata
+       shl     ax,4
+       mov     bx,[blen]
+       shr     bx,3
+
+       mov     cx,bx
+       rep stosb
+       inc     al
+       mov     cx,bx
+       rep stosb
+       inc     al
+       mov     cx,bx
+       rep stosb
+       inc     al
+       mov     cx,bx
+       rep stosb
+       inc     al
+       mov     cx,bx
+       rep stosb
+       inc     al
+       mov     cx,bx
+       rep stosb
+       inc     al
+       mov     cx,bx
+       rep stosb
+       inc     al
+       mov     cx,bx
+       rep stosb
+
+       jmp     SHORT @@v2
+
+@@v1:
+       shl     ax,2
+       mov     bx,ax
+       mov     es,[XMSlookup]          ;(LONG SEG *)
+       mov     ax,[es:bx]
+       mov     [WORD PTR soff],ax
+       mov     ax,[es:bx+2]
+       mov     [WORD PTR soff+2],ax
+       cmp     ax,-1                   ;SPARSE TILE?
+       je      @@v1a
+
+       mov     ax,OFFSET tdata         ;(quickie modification since "doff"
+       mov     [WORD doff],ax          ; should always point to "tdata1")
+       mov     si,OFFSET blen
+       mov     ah,11
+       call    [DWORD XMSdriver]       ;move tile into tdata1
+       mov     ax,OFFSET tdata1
+       mov     [WORD doff],ax          ;ahhh....back to normal
+
+       jmp     @@v2
+;
+; Copy sparse tile to tdata
+;
+@@v1a:
+       mov     bx,[tsize]
+       shl     bx,1
+       mov     si,[Vsparse+bx-2]
+       mov     di,OFFSET tdata
+       mov     cx,[blen]
+       shr     cx,1                    ;for WORD copy
+       mov     ax,ds
+       mov     es,ax
+       rep movsw
+
+;
+; Handle foreground tiles
+;
+@@v2:
+       mov     bx,[tilef]
+       cmp     bx,0
+       je      @@v3                    ;any masked tile?
+
+       shl     bx,2
+       mov     es,[XMSlookup]
+       mov     ax,[es:bx]
+       mov     [WORD PTR soff],ax
+       mov     ax,[es:bx+2]
+       mov     [WORD PTR soff+2],ax
+       cmp     ax,-1                   ;SPARSE MASKED TILE?
+       je      @@v3
+
+       mov     ax,[bmlen]
+       mov     [blen],ax               ;set masked tile length for XMS copy
+       mov     si,OFFSET blen
+       mov     ah,11
+       call    [DWORD XMSdriver]       ;move tile into tdata1
+;
+; now we have the masked tile in "tdata1".
+; time to mask it onto "tdata"
+;
+       mov     si,OFFSET tdata1
+       add     si,[masklen]            ;SI = masked tile's tiledata
+       mov     di,OFFSET tdata         ;DI = tile in "tdata"
+
+       mov     dx,[theight]
+       mov     bx,OFFSET tdata1        ;BX = mask
+@@v2a:
+       mov     cx,[twidth]
+@@v2b:
+       mov     al,[bx]                 ;get mask byte
+       and     [di],al                 ;and tdata with it
+       lodsb                           ;get tilem byte
+       or      [di],al                 ;OR it onto tdata
+       inc     di
+       inc     bx
+       loop    @@v2b
+       dec     dx
+       jnz     @@v2a
+;
+; Handle icons (foreground tiles)
+;
+@@v3:
+       mov     bx,[tilei]
+       cmp     bx,[lasticon]
+       ja      @@vexit                 ;any icons?
+       cmp     bx,[firsticon]
+       jbe     @@vexit
+
+       shl     bx,2
+       mov     es,[XMSlookup]
+       mov     ax,[es:bx]
+       mov     [WORD PTR soff],ax
+       mov     ax,[es:bx+2]
+       mov     [WORD PTR soff+2],ax
+
+       mov     ax,[bmlen]
+       mov     [blen],ax               ;set masked tile length for XMS copy
+       mov     si,OFFSET blen
+       mov     ah,11
+       call    [DWORD XMSdriver]       ;move tile into tdata1
+;
+; now we have the masked tile in "tdata1".
+; time to mask it onto "tdata"
+;
+       mov     si,OFFSET tdata1
+       add     si,[masklen]            ;SI = masked tile's tiledata
+       mov     di,OFFSET tdata         ;DI = tile in "tdata"
+
+       mov     dx,[theight]
+       mov     bx,OFFSET tdata1        ;BX = mask
+@@v3a:
+       mov     cx,[twidth]
+@@v3b:
+       mov     al,[bx]                 ;get mask byte
+       and     [di],al                 ;and tdata with it
+       lodsb                           ;get tilem byte
+       or      [di],al                 ;OR it onto tdata
+       inc     di
+       inc     bx
+       loop    @@v3b
+       dec     dx
+       jnz     @@v3a
+@@vexit:
+       pop     di
+       pop     si
+       ret
+ENDP
+
+
+;====================================================
+;
+; Draw a tile in any of the video modes
+; NOTE: ONLY WORKS WITH TSIZE=2!
+;
+;====================================================
+PUBLIC DrawTile
+PROC   DrawTile
+       ARG     x:WORD,y:WORD,tsize:WORD
+
+       push    si
+       push    di
+
+       mov     bx,[tsize]
+       shl     bx,1
+       mov     ah,[BYTE PTR hsize+bx-2]
+       mov     [oldh],ah
+       mov     cx,[wsize+bx-2]
+
+       mov     bx,[videomode]
+       shl     bx,1
+       mov     dx,[DrawTable+bx]
+
+       mov     bx,[y]
+       shl     bx,1
+       jmp     dx
+
+label  DrawTCGA proc
+
+       mov     ax,0b800h
+       mov     es,ax
+       mov     si,OFFSET tdata
+       mov     di,[x]
+       shl     di,1
+       add     di,[CGAlookup+bx]
+       mov     bx,cx
+       shl     bx,1
+       mov     ah,[oldh]
+@@c1:
+       mov     cx,bx
+       rep movsb
+       sub     di,bx
+       xor     di,2000h
+       mov     cx,bx
+       rep movsb
+       sub     di,bx
+       xor     di,2000h
+       add     di,80
+
+       sub     ah,2
+       jnz     @@c1
+
+       pop     di
+       pop     si
+       ret
+;
+; EGA1/2/3 TILE DRAW ROUTINES
+;
+label  DrawTEGA1 proc
+       mov     [horzadd],38
+       mov     di,[EGA1lookup+bx]
+       jmp     SHORT DoDrawEGAT
+label  DrawTEGA2 proc
+       mov     [horzadd],78
+       mov     di,[EGA2lookup+bx]
+       jmp     SHORT DoDrawEGAT
+label  DoDrawEGAT proc
+       add     di,[x]
+       mov     [oldy],di
+       mov     si,OFFSET tdata
+       mov     bx,0a000h
+       mov     es,bx
+       mov     bx,cx
+;
+; AH : height
+; BX : width
+; ES:DI : dest
+; DS:SI : source
+;
+       cld
+       mov     dx,GCindex
+       mov     al,GCmode
+       out     dx,al
+       inc     dx
+       mov     al,0
+       out     dx,al
+;
+; Plane 0
+;
+       mov     dx,SCindex
+       mov     al,SCmapmask
+       out     dx,al
+       inc     dx
+       mov     al,1
+       out     dx,al
+
+       mov     dx,[horzadd]
+@@1:
+       mov     cx,bx
+       rep movsb
+       add     di,dx
+       dec     ah
+       jne     @@1
+;
+; Plane 1
+;
+       mov     dx,SCindex
+       mov     al,SCmapmask
+       out     dx,al
+       inc     dx
+       mov     al,2
+       out     dx,al
+
+       mov     dx,[horzadd]
+       mov     di,[oldy]
+       mov     ah,[oldh]
+@@2:
+       mov     cx,bx
+       rep movsb
+       add     di,dx
+       dec     ah
+       jne     @@2
+;
+; Plane 2
+;
+       mov     dx,SCindex
+       mov     al,SCmapmask
+       out     dx,al
+       inc     dx
+       mov     al,4
+       out     dx,al
+
+       mov     dx,[horzadd]
+       mov     di,[oldy]
+       mov     ah,[oldh]
+@@3:
+       mov     cx,bx
+       rep movsb
+       add     di,dx
+       dec     ah
+       jne     @@3
+;
+; Plane 3
+;
+       mov     dx,SCindex
+       mov     al,SCmapmask
+       out     dx,al
+       inc     dx
+       mov     al,8
+       out     dx,al
+
+       mov     dx,[horzadd]
+       mov     di,[oldy]
+       mov     ah,[oldh]
+@@4:
+       mov     cx,bx
+       rep movsb
+       add     di,dx
+       dec     ah
+       jne     @@4
+
+       pop     di
+       pop     si
+       ret
+
+label  DrawTVGA proc
+
+       mov     ax,0a000h
+       mov     es,ax
+       mov     si,OFFSET tdata
+       mov     di,[x]
+       shl     di,3
+       add     di,[VGAlookup+bx]
+       mov     bx,cx
+       shl     bx,2
+       mov     ah,[oldh]
+@@v1:
+       mov     cx,bx
+       rep movsw
+       add     di,304
+
+       dec     ah
+       jnz     @@v1
+
+       pop     di
+       pop     si
+       ret
+ENDP
+
+;////////////////////////////////////////////////////////////////////
+;
+; TED5 screen scroll routines!
+;
+;////////////////////////////////////////////////////////////////////
+PROC   CopyCGA
+PUBLIC CopyCGA
+       ARG     srcx:WORD,srcy:WORD,width:WORD,height:WORD,destx:WORD,desty:WORD
+       USES    si,di
+       push    ds
+
+       mov     ax,0b800h
+       mov     es,ax
+       mov     ds,ax
+       shl     [width],1
+       shl     [destx],1
+       shl     [srcx],1
+
+       mov     ax,[srcy]
+       cmp     ax,[desty]
+       jb      @@1
+       ja      @@2
+       mov     ax,[srcx]
+       cmp     ax,[destx]
+       jb      @@0
+;
+; Copy from sourcex to destx, right
+;
+       mov     dx,[height]
+       mov     bx,[srcy]       ;source & dest are the same!
+       shl     bx,1
+       cld
+
+@@aa:
+       mov     si,[ss:CGAlookup+bx]
+       mov     di,si
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       add     bx,2
+       dec     dx
+       jnz     @@aa
+       jz      @@exit
+;
+; Copy from end of sourcex to end of destx, left
+;
+@@0:
+       mov     dx,[height]
+       mov     bx,[srcy]       ;source & dest are the same!
+       shl     bx,1
+
+@@0a0:
+       mov     si,[ss:CGAlookup+bx]
+       mov     di,si
+       add     si,[srcx]
+       add     si,[width]
+       dec     si
+       add     di,[destx]
+       add     di,[width]
+       dec     di
+       mov     cx,[width]
+       std
+       rep movsb
+       cld
+       add     bx,2
+       dec     dx
+       jnz     @@0a0
+       jz      @@exit
+;
+; Copy from end of sourcey to end of desty, up
+;
+@@1:
+       mov     ah,[BYTE height]
+       mov     dl,[BYTE srcy]
+       add     dl,ah
+       dec     dl
+       mov     dh,[BYTE desty]
+       add     dh,ah
+       dec     dh
+       cld
+
+@@1a0:
+       mov     bx,[srcy]
+       add     bx,[height]
+       dec     bx
+       shl     bx,1
+       mov     si,[ss:CGAlookup+bx]
+       mov     bx,[desty]
+       add     bx,[height]
+       dec     bx
+       shl     bx,1
+       mov     di,[ss:CGAlookup+bx]
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       dec     [height]
+       jnz     @@1a0
+       jz      @@exit
+;
+; Copy from sourcey to desty, down
+;
+@@2:
+       mov     ah,[BYTE height]
+       mov     dl,[BYTE srcy]
+       mov     dh,[BYTE desty]
+       cld
+
+@@2a0:
+       mov     bx,[srcy]
+       shl     bx,1
+       mov     si,[ss:CGAlookup+bx]
+       mov     bx,[desty]
+       shl     bx,1
+       mov     di,[ss:CGAlookup+bx]
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       inc     [srcy]
+       inc     [desty]
+       dec     [height]
+       jnz     @@2a0
+       jz      @@exit
+@@exit:
+       pop     ds
+       ret
+ENDP
+
+
+PROC   CopyEGA
+PUBLIC CopyEGA
+       ARG     srcx:WORD,srcy:WORD,width:WORD,height:WORD,destx:WORD,desty:WORD
+       USES    si,di
+       push    ds
+
+       mov     dx,GCindex
+       mov     ax,GCmode OR 100h
+       out     dx,ax
+
+       mov     ax,0a000h
+       mov     es,ax
+       mov     ds,ax
+
+       mov     ax,[srcy]
+       cmp     ax,[desty]
+       jb      @@1
+       ja      @@2
+       mov     ax,[srcx]
+       cmp     ax,[destx]
+       jb      @@0
+;
+; Copy from sourcex to destx, right
+;
+       mov     dx,[height]
+       mov     bx,[srcy]       ;source & dest are the same!
+       shl     bx,1
+       cld
+
+       cmp     [ss:videomode],2
+       jb      @@a
+@@aa:
+       mov     si,[ss:EGA2lookup+bx]
+       mov     di,si
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       add     bx,2
+       dec     dx
+       jnz     @@aa
+       jz      @@exit
+@@a:
+       mov     si,[ss:EGA1lookup+bx]
+       mov     di,si
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       add     bx,2
+       dec     dx
+       jnz     @@a
+       jz      @@exit
+;
+; Copy from end of sourcex to end of destx, left
+;
+@@0:
+       mov     dx,[height]
+       mov     bx,[srcy]       ;source & dest are the same!
+       shl     bx,1
+
+       cmp     [ss:videomode],2
+       jb      @@0a
+@@0a0:
+       mov     si,[ss:EGA2lookup+bx]
+       mov     di,si
+       add     si,[srcx]
+       add     si,[width]
+       dec     si
+       add     di,[destx]
+       add     di,[width]
+       dec     di
+       mov     cx,[width]
+       std
+       rep movsb
+       cld
+       add     bx,2
+       dec     dx
+       jnz     @@0a0
+       jz      @@exit
+@@0a:
+       mov     si,[ss:EGA1lookup+bx]
+       mov     di,si
+       add     si,[srcx]
+       add     si,[width]
+       dec     si
+       add     di,[destx]
+       add     di,[width]
+       dec     di
+       mov     cx,[width]
+       std
+       rep movsb
+       cld
+       add     bx,2
+       dec     dx
+       jnz     @@0a
+       jz      @@exit
+;
+; Copy from end of sourcey to end of desty, up
+;
+@@1:
+       mov     ah,[BYTE height]
+       mov     dl,[BYTE srcy]
+       add     dl,ah
+       dec     dl
+       mov     dh,[BYTE desty]
+       add     dh,ah
+       dec     dh
+       cld
+
+       cmp     [ss:videomode],2
+       jb      @@1a
+@@1a0:
+       mov     bx,[srcy]
+       add     bx,[height]
+       dec     bx
+       shl     bx,1
+       mov     si,[ss:EGA2lookup+bx]
+       mov     bx,[desty]
+       add     bx,[height]
+       dec     bx
+       shl     bx,1
+       mov     di,[ss:EGA2lookup+bx]
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       dec     [height]
+       jnz     @@1a0
+       jz      @@exit
+@@1a:
+       mov     bl,dl
+       xor     bh,bh
+       shl     bx,1
+       mov     si,[ss:EGA1lookup+bx]
+       mov     bl,dh
+       xor     bh,bh
+       shl     bx,1
+       mov     di,[ss:EGA1lookup+bx]
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       dec     dl
+       dec     dh
+       dec     ah
+       jnz     @@1a
+       jz      @@exit
+;
+; Copy from sourcey to desty, down
+;
+@@2:
+       mov     ah,[BYTE height]
+       mov     dl,[BYTE srcy]
+       mov     dh,[BYTE desty]
+       cld
+
+       cmp     [ss:videomode],2
+       jb      @@2a
+@@2a0:
+       mov     bx,[srcy]
+       shl     bx,1
+       mov     si,[ss:EGA2lookup+bx]
+       mov     bx,[desty]
+       shl     bx,1
+       mov     di,[ss:EGA2lookup+bx]
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       inc     [srcy]
+       inc     [desty]
+       dec     [height]
+       jnz     @@2a0
+       jz      @@exit
+@@2a:
+       mov     bl,dl
+       xor     bh,bh
+       shl     bx,1
+       mov     si,[ss:EGA1lookup+bx]
+       mov     bl,dh
+       xor     bh,bh
+       shl     bx,1
+       mov     di,[ss:EGA1lookup+bx]
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       inc     dl
+       inc     dh
+       dec     ah
+       jnz     @@2a
+@@exit:
+       pop     ds
+       ret
+ENDP
+
+PROC   CopyVGA
+PUBLIC CopyVGA
+       ARG     srcx:WORD,srcy:WORD,width:WORD,height:WORD,destx:WORD,desty:WORD
+       USES    si,di
+       push    ds
+
+       mov     ax,0a000h
+       mov     es,ax
+       mov     ds,ax
+       shl     [width],3
+       shl     [destx],3
+       shl     [srcx],3
+
+       mov     ax,[srcy]
+       cmp     ax,[desty]
+       jb      @@1
+       ja      @@2
+       mov     ax,[srcx]
+       cmp     ax,[destx]
+       jb      @@0
+;
+; Copy from sourcex to destx, right
+;
+       mov     dx,[height]
+       mov     bx,[srcy]       ;source & dest are the same!
+       shl     bx,1
+       cld
+
+@@aa:
+       mov     si,[ss:VGAlookup+bx]
+       mov     di,si
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       add     bx,2
+       dec     dx
+       jnz     @@aa
+       jz      @@exit
+;
+; Copy from end of sourcex to end of destx, left
+;
+@@0:
+       mov     dx,[height]
+       mov     bx,[srcy]       ;source & dest are the same!
+       shl     bx,1
+
+@@0a0:
+       mov     si,[ss:VGAlookup+bx]
+       mov     di,si
+       add     si,[srcx]
+       add     si,[width]
+       dec     si
+       add     di,[destx]
+       add     di,[width]
+       dec     di
+       mov     cx,[width]
+       std
+       rep movsb
+       cld
+       add     bx,2
+       dec     dx
+       jnz     @@0a0
+       jz      @@exit
+;
+; Copy from end of sourcey to end of desty, up
+;
+@@1:
+       mov     ah,[BYTE height]
+       mov     dl,[BYTE srcy]
+       add     dl,ah
+       dec     dl
+       mov     dh,[BYTE desty]
+       add     dh,ah
+       dec     dh
+       cld
+
+@@1a0:
+       mov     bx,[srcy]
+       add     bx,[height]
+       dec     bx
+       shl     bx,1
+       mov     si,[ss:VGAlookup+bx]
+       mov     bx,[desty]
+       add     bx,[height]
+       dec     bx
+       shl     bx,1
+       mov     di,[ss:VGAlookup+bx]
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       dec     [height]
+       jnz     @@1a0
+       jz      @@exit
+;
+; Copy from sourcey to desty, down
+;
+@@2:
+       mov     ah,[BYTE height]
+       mov     dl,[BYTE srcy]
+       mov     dh,[BYTE desty]
+       cld
+
+@@2a0:
+       mov     bx,[srcy]
+       shl     bx,1
+       mov     si,[ss:VGAlookup+bx]
+       mov     bx,[desty]
+       shl     bx,1
+       mov     di,[ss:VGAlookup+bx]
+       add     si,[srcx]
+       add     di,[destx]
+       mov     cx,[width]
+       rep movsb
+       inc     [srcy]
+       inc     [desty]
+       dec     [height]
+       jnz     @@2a0
+       jz      @@exit
+@@exit:
+       pop     ds
+       ret
+ENDP
+
+;////////////////////////////////////////////////////////////////////
+;
+; OVERLAY routine
+;
+;////////////////////////////////////////////////////////////////////
+PROC   Overlay
+PUBLIC Overlay
+       ARG     tsize:WORD
+
+       push    di
+       push    si
+
+       mov     di,OFFSET tdata
+       mov     bx,[tsize]
+       shl     bx,1
+       mov     si,[videomode]
+       shl     si,1
+       mov     ax,[OverTable+si]
+       jmp     ax
+
+LABEL  OverlayCGA      PROC
+
+       mov     cx,[csize+bx-2]
+       shr     cx,1
+       mov     si,[Csparse+bx-2]
+@@c1:  lodsw
+       or      [di],ax
+       add     di,2
+       loop    @@c1
+
+       pop     si
+       pop     di
+       ret
+
+LABEL  OverlayEGA      PROC
+
+       mov     cx,[esize+bx-2]
+       shr     cx,1
+       mov     si,[Esparse+bx-2]
+@@e1:  lodsw
+       or      [di],ax
+       add     di,2
+       loop    @@e1
+
+       pop     si
+       pop     di
+       ret
+
+LABEL  OverlayVGA      PROC
+
+       mov     cx,[vsize+bx-2]
+       shr     cx,1
+       mov     si,[Vsparse+bx-2]
+@@v1:  lodsw
+       or      [di],ax
+       add     di,2
+       loop    @@v1
+
+       pop     si
+       pop     di
+       ret
+
+ENDP
+
+END
\ No newline at end of file
diff --git a/16/ted5/TEST.BAT b/16/ted5/TEST.BAT
new file mode 100755 (executable)
index 0000000..c9cf28a
--- /dev/null
@@ -0,0 +1,6 @@
+copy ted5.exe ..
+lcd keen4
+ted5
+lcd ted5
+bcx
+
diff --git a/16/ted5/XMS.C b/16/ted5/XMS.C
new file mode 100755 (executable)
index 0000000..a3b32f8
--- /dev/null
@@ -0,0 +1,200 @@
+////////////////////////////////////////////////////
+//
+// XMS routines - uses the MENU.C & LIB.C routines for output
+//
+////////////////////////////////////////////////////
+#include "ted5.h"
+#pragma hdrstop
+
+
+long TTLxms;
+unsigned XMSavail;
+void far *XMSdriver;
+
+////////////////////////////////////////////////////
+//
+// CALL the XMSdriver with a function #
+//
+////////////////////////////////////////////////////
+void CallXMS(char func)
+{
+ asm   mov     ah,[func]
+ asm   call    [DWORD PTR XMSdriver]
+}
+
+////////////////////////////////////////////////////
+//
+// Initialize the XMS memory
+//
+////////////////////////////////////////////////////
+void InitXMS(void)
+{
+ //
+ // See if XMS driver is present...
+ //
+ asm   mov     ax,0x4300
+ asm   int     0x2f
+ asm   cmp     al,0x80         // installed?
+ asm   je      Present
+
+ ErrDialog("You poor bastard! I refuse\n"
+          "to work without Extended\n"
+          "Memory! Goodbye!"," I Suck ");
+ Quit("No Extended Memory Driver found!");
+
+ //
+ // YES! We found an XMS driver! Now we
+ // need to get the XMS driver's entry address...
+ //
+ Present:
+ asm   mov     ax,0x4310
+ asm   int     0x2f
+ asm   mov     WORD PTR XMSdriver,bx
+ asm   mov     WORD PTR XMSdriver+2,es
+
+ XMSTotalFree();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Report an XMS error, if any
+//
+////////////////////////////////////////////////////
+void XMSerror(void)
+{
+ if (_AX==0)
+   switch(_BL)
+   {
+    case 0x80: Quit("Function not implemented!");
+    case 0x81: Quit("VDISK device driver was detected!");
+    case 0x82: Quit("A20 error occurred!");
+    case 0x8e: Quit("General driver error!");
+    case 0x8f: Quit("Unrecoverable driver error!");
+
+    case 0x90: Quit("High memory area does not exist!");
+    case 0x91: Quit("High memory area already in use!");
+    case 0x92: Quit("DX is less than /HMAMIN= parameter!");
+    case 0x93: Quit("High memory area not allocated!");
+    case 0x94: Quit("A20 line still enabled!");
+
+    case 0xa0: Quit("Not enough Extended Memory available!");
+    case 0xa1: Quit("Extended memory handles exhausted!");
+    case 0xa2: Quit("Invalid handle!");
+    case 0xa3: Quit("Invalid source handle!");
+    case 0xa4: Quit("Invalid source offset!");
+    case 0xa5: Quit("Invalid destination handle!");
+    case 0xa6: Quit("Invalid destination offset!");
+    case 0xa7: Quit("Invalid length!");
+    case 0xa8: Quit("Invalid overlap in move request!");
+    case 0xa9: Quit("Parity error detected!");
+    case 0xaa: Quit("Block is not locked!");
+    case 0xab: Quit("Block is locked!");
+    case 0xac: Quit("Lock count overflowed!");
+    case 0xad: Quit("Lock failed!");
+
+    case 0xb0: Quit("Smaller UMB is available!");
+    case 0xb1: Quit("No UMBs are available!");
+    case 0xb2: Quit("Invalid UMB segment number!");
+
+    default: Quit("Unknown XMS Memory Error! I'm totally stumped!");
+   }
+}
+
+////////////////////////////////////////////////////
+//
+// Allocate XMS memory
+//
+////////////////////////////////////////////////////
+int XMSAllocate(long size)
+{
+ #if 0
+ static int allocnum=0;
+
+ _MouseHide();
+ sx=0;
+ sy=1;
+ print("XMS allocation #");
+ printint(allocnum++);
+ print(":");
+ printint((1023L+size)/1024L);
+ print("K");
+ while(!keydown[0x1c]);
+ clearkeys();
+ _MouseShow();
+ #endif
+
+
+ _DX=(size+1023)/1024;
+ CallXMS(9);
+ XMSerror();
+ asm push dx
+ TTLxms=1024L*XMSTotalFree();
+ asm pop dx
+ return _DX;
+}
+
+////////////////////////////////////////////////////
+//
+// Free XMS memory
+//
+////////////////////////////////////////////////////
+void XMSFreeMem(int handle)
+{
+ _DX=handle;
+ CallXMS(10);
+ XMSerror();
+ TTLxms=1024L*XMSTotalFree();
+}
+
+
+////////////////////////////////////////////////////
+//
+// Return XMS memory available
+//
+////////////////////////////////////////////////////
+unsigned XMSTotalFree(void)
+{
+ CallXMS(8);
+ XMSerror();
+ XMSavail=_DX;
+ return XMSavail;
+}
+
+////////////////////////////////////////////////////
+//
+// Move XMS memory
+//
+////////////////////////////////////////////////////
+void XMSmove(int srchandle,long srcoff,int desthandle,long destoff,long size)
+{
+ struct { long bsize;
+         int shandle;
+         long soff;
+         int dhandle;
+         long doff;
+       } XMSparms;
+
+ unsigned DSreg,SIreg;
+
+ XMSparms.bsize=size+(size&1);
+ XMSparms.shandle=srchandle;
+ XMSparms.dhandle=desthandle;
+ XMSparms.soff=srcoff;
+ XMSparms.doff=destoff;
+
+ DSreg=FP_SEG(&XMSparms);
+ SIreg=FP_OFF(&XMSparms);
+
+ asm   push    ds
+ asm   push    si
+ asm   mov     si,SIreg
+ asm   mov     ds,DSreg
+
+ CallXMS(11);
+
+ asm   pop     si
+ asm   pop     ds
+
+ XMSerror();
+}
\ No newline at end of file
diff --git a/16/ted5/XMS.H b/16/ted5/XMS.H
new file mode 100755 (executable)
index 0000000..d51a2c0
--- /dev/null
@@ -0,0 +1,8 @@
+void InitXMS(void);
+int XMSAllocate(long size);
+unsigned XMSTotalFree(void);   // returns KB free
+void XMSFreeMem(int handle);
+void XMSmove(int srchandle,long srcoff,int desthandle,long destoff,long size);
+
+extern unsigned XMSavail;
+extern long TTLxms;
\ No newline at end of file
diff --git a/16/ted5/_TEDCHAR.EGA b/16/ted5/_TEDCHAR.EGA
new file mode 100755 (executable)
index 0000000..a01c32f
Binary files /dev/null and b/16/ted5/_TEDCHAR.EGA differ
diff --git a/16/ted5/_TOM.PIC b/16/ted5/_TOM.PIC
new file mode 100755 (executable)
index 0000000..ad3b7a4
Binary files /dev/null and b/16/ted5/_TOM.PIC differ