--- /dev/null
+copy *.c backup
+copy *.h backup
+copy *.asm backup
+copy *.prj backup
+copy *.dsk backup
+copy _*.obj backup
--- /dev/null
+fgrab /ega ted.nsc
+copy egalatch.ted _tedchar.ega
--- /dev/null
+//////////////////////////////////////
+//
+// Graphics DEFINE file for .TED
+// FGRAB-ed on Thu Aug 08 17:33:46 1991
+//
+//////////////////////////////////////
+
+
+
+//
+// Thank you for using FGRAB!
+//
--- /dev/null
+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
--- /dev/null
+#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
+
+
--- /dev/null
+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);
--- /dev/null
+#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,®s,®s);
+ return(regs.x.bx);
+}
+
+
+
+void MouseCoords(int *x,int *y)
+{
+ union REGS regs;
+
+ if (!MouseStatus)
+ return;
+
+ regs.x.ax=3;
+ int86(0x33,®s,®s);
+ *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);
+}
+
+
--- /dev/null
+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
--- /dev/null
+;====================================================
+;
+; 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
--- /dev/null
+#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;
+}
+
+//==========================================================================
--- /dev/null
+
+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
--- /dev/null
+/////////////////////////////////////////////////////////////////
+//
+// 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;
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////
+//
+// 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);
--- /dev/null
+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.
--- /dev/null
+TED5
+====
--- /dev/null
+cd test
+td386 ..\ted5
+cd ..
+bcx
--- /dev/null
+start chars
+
+load chars
+grab 128
+
+save ted
+.\1a
\ No newline at end of file
--- /dev/null
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// 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();
+}
--- /dev/null
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// 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();
+}
--- /dev/null
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// 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);
+}
--- /dev/null
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+//
+// 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();
+ }
+}
--- /dev/null
+////////////////////////////////////////////////////
+//
+// 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,""}};
--- /dev/null
+#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);
--- /dev/null
+
+ 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
+
--- /dev/null
+;====================================================
+;
+; 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
--- /dev/null
+copy ted5.exe ..
+lcd keen4
+ted5
+lcd ted5
+bcx
+
--- /dev/null
+////////////////////////////////////////////////////
+//
+// 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
--- /dev/null
+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