diff options
44 files changed, 10244 insertions, 3 deletions
diff --git a/engines/cge/bitmap.cpp b/engines/cge/bitmap.cpp new file mode 100644 index 0000000000..f3a7f85331 --- /dev/null +++ b/engines/cge/bitmap.cpp @@ -0,0 +1,433 @@ +#include "bitmap.h" +#include <cfile.h> + +#ifdef VOL + #include "vol.h" +#endif + +#ifdef DROP_H + #include "drop.h" +#endif + + +#include <alloc.h> +#include <dos.h> +#include <dir.h> +#include <mem.h> + + +//-------------------------------------------------------------------------- + + + + +DAC far * BITMAP::Pal = NULL; + + + +#pragma argsused +BITMAP::BITMAP (const char * fname, Boolean rem) +: M(NULL), V(NULL) +{ + char pat[MAXPATH]; + + ForceExt(pat, fname, ".VBM"); + + #if (BMP_MODE < 2) + if (rem && PIC_FILE::Exist(pat)) + { + PIC_FILE file(pat); + if (file.Error == 0) + if (! VBMLoad(&file)) + DROP("Bad VBM", fname); + } + else + #endif + { + #if (BMP_MODE) + ForceExt(pat, fname, ".BMP"); + PIC_FILE file(pat); + if (file.Error == 0) + { + if (BMPLoad(&file)) + { + Code(); + if (rem) + { + farfree(M); + M = NULL; + } + } + else DROP("Bad BMP", fname); + } + #else + DROP("Bad VBM", fname); + #endif + } +} + + + + + +BITMAP::BITMAP (word w, word h, byte far * map) +: W(w), H(h), M(map), V(NULL) +{ + if (map) Code(); +} + + + + +// following routine creates filled rectangle +// immediately as VGA video chunks, in near memory as fast as possible, +// especially for text line real time display + +BITMAP::BITMAP (word w, word h, byte fill) +: W((w + 3) & ~3), // only full dwords allowed! + H(h), + M(NULL) +{ + word dsiz = W >> 2; // data size (1 plane line size) + word lsiz = 2 + dsiz + 2; // word for line header, word for gap + word psiz = H * lsiz; // - last gape, but + plane trailer + byte * v = new byte[4 * psiz // the same for 4 planes + + H * sizeof(*B)]; // + room for wash table + if (v == NULL) DROP("No core", NULL); + + * (word *) v = CPY | dsiz; // data chunk hader + memset(v+2, fill, dsiz); // data bytes + * (word *) (v + lsiz - 2) = SKP | ((SCR_WID / 4) - dsiz); // gap + memcpy(v + lsiz, v, psiz - lsiz); // tricky replicate lines + * (word *) (v + psiz - 2) = EOI; // plane trailer word + memcpy(v + psiz, v, 3 * psiz); // tricky replicate planes + HideDesc * b = (HideDesc *) (v + 4 * psiz); + b->skip = (SCR_WID - W) >> 2; + b->hide = W >> 2; + memcpy(b+1, b, (H-1) * sizeof(*b)); // tricky fill entire table + b->skip = 0; // fix the first entry + V = v; + B = b; +} + + + + + + + +BITMAP::BITMAP (const BITMAP& bmp) +: W(bmp.W), H(bmp.H), + M(NULL), V(NULL) +{ + byte far * v0 = bmp.V; + if (v0) + { + word vsiz = FP_OFF(bmp.B) - FP_OFF(v0); + word siz = vsiz + H * sizeof(HideDesc); + byte far * v1 = farnew(byte, siz); + if (v1 == NULL) DROP("No core", NULL); + _fmemcpy(v1, v0, siz); + B = (HideDesc far *) ((V = v1) + vsiz); + } +} + + + + + +BITMAP::~BITMAP (void) +{ + switch (MemType(M)) + { + case FAR_MEM : farfree(M); break; + } + switch (MemType(V)) + { + case NEAR_MEM : delete[] (byte *) V; break; + case FAR_MEM : farfree(V); break; + } +} + + + +BITMAP& BITMAP::operator = (const BITMAP& bmp) +{ + byte far * v0 = bmp.V; + W = bmp.W; + H = bmp.H; + M = NULL; + if (MemType(V) == FAR_MEM) farfree(V); + if (v0 == NULL) V = NULL; + else + { + word vsiz = FP_OFF(bmp.B) - FP_OFF(v0); + word siz = vsiz + H * sizeof(HideDesc); + byte far * v1 = farnew(byte, siz); + if (v1 == NULL) DROP("No core", NULL); + _fmemcpy(v1, v0, siz); + B = (HideDesc far *) ((V = v1) + vsiz); + } + return *this; +} + + + + + +word BITMAP::MoveVmap (byte far * buf) +{ + if (V) + { + word vsiz = FP_OFF(B) - FP_OFF(V); + word siz = vsiz + H * sizeof(HideDesc); + _fmemcpy(buf, V, siz); + if (MemType(V) == FAR_MEM) farfree(V); + B = (HideDesc far *) ((V = buf) + vsiz); + return siz; + } + return 0; +} + + + + + + + +BMP_PTR BITMAP::Code (void) +{ + if (M) + { + word i, cnt; + + if (V) // old X-map exists, so remove it + { + switch (MemType(V)) + { + case NEAR_MEM : delete[] (byte *) V; break; + case FAR_MEM : farfree(V); break; + } + V = NULL; + } + + while (TRUE) // at most 2 times: for (V == NULL) & for allocated block; + { + byte far * im = V+2; + word far * cp = (word far *) V; + int bpl; + + if (V) // 2nd pass - fill the hide table + { + for (i = 0; i < H; i ++) + { + B[i].skip = 0xFFFF; + B[i].hide = 0x0000; + } + } + for (bpl = 0; bpl < 4; bpl ++) // once per each bitplane + { + byte far * bm = M; + Boolean skip = (bm[bpl] == TRANS); + word j; + + cnt = 0; + for (i = 0; i < H; i ++) // once per each line + { + byte pix; + for (j = bpl; j < W; j += 4) + { + pix = bm[j]; + if (V && pix != TRANS) + { + if (j < B[i].skip) B[i].skip = j; + if (j >= B[i].hide) B[i].hide = j+1; + } + if ((pix == TRANS) != skip || cnt >= 0x3FF0) // end of block + { + cnt |= (skip) ? SKP : CPY; + if (V) + { + *cp = cnt; // store block description word + } + cp = (word far *) im; + im += 2; + skip = (pix == TRANS); + cnt = 0; + } + if (! skip) + { + if (V) * im = pix; + ++ im; + } + ++ cnt; + } + + bm += W; + if (W < SCR_WID) + { + if (skip) + { + cnt += (SCR_WID - j + 3) / 4; + } + else + { + cnt |= CPY; + if (V) + { + *cp = cnt; + } + cp = (word far *) im; + im += 2; + skip = TRUE; + cnt = (SCR_WID - j + 3) / 4; + } + } + } + if (cnt && ! skip) + { + cnt |= CPY; + if (V) + { + *cp = cnt; + } + cp = (word far *) im; + im += 2; + } + if (V) *cp = EOI; + cp = (word far *) im; + im += 2; + } + if (V) break; + word sizV = (word) (im - 2 - V); + V = farnew(byte, sizV + H * sizeof(*B)); + if (! V) + { + DROP("No core", NULL); + } + B = (HideDesc far *) (V + sizV); + } + cnt = 0; + for (i = 0; i < H; i ++) + { + if (B[i].skip == 0xFFFF) // whole line is skipped + { + B[i].skip = (cnt + SCR_WID) >> 2; + cnt = 0; + } + else + { + word s = B[i].skip & ~3; + word h = (B[i].hide + 3) & ~3; + B[i].skip = (cnt + s) >> 2; + B[i].hide = (h - s) >> 2; + cnt = SCR_WID - h; + } + } + } + return this; +} + + + + + + +Boolean BITMAP::SolidAt (int x, int y) +{ + byte far * m; + word r, n, n0; + + if (x >= W || y >= H) return FALSE; + + m = V; + r = x % 4; + n0 = (SCR_WID * y + x) / 4, n = 0; + + while (r) + { + word w, t; + + w = * (word far *) m; + m += 2; + t = w & 0xC000; + w &= 0x3FFF; + + switch (t) + { + case EOI : -- r; + case SKP : w = 0; break; + case REP : w = 1; break; + } + m += w; + } + + while (TRUE) + { + word w, t; + + w = * (word far *) m; + m += 2; + t = w & 0xC000; + w &= 0x3FFF; + + if (n > n0) return FALSE; + n += w; + switch (t) + { + case EOI : return FALSE; + case SKP : w = 0; break; + case REP : + case CPY : if (n-w <= n0 && n > n0) return TRUE; break; + } + m += (t == REP) ? 1 : w; + } +} + + + + + + +Boolean BITMAP::VBMSave (XFILE * f) +{ + word p = (Pal != NULL), + n = ((word) (((byte far *)B) - V)) + H * sizeof(HideDesc); + if (f->Error == 0) f->Write((byte far *)&p, sizeof(p)); + if (f->Error == 0) f->Write((byte far *)&n, sizeof(n)); + if (f->Error == 0) f->Write((byte far *)&W, sizeof(W)); + if (f->Error == 0) f->Write((byte far *)&H, sizeof(H)); + if (f->Error == 0) if (p) f->Write((byte far *)Pal, 256 * sizeof(DAC)); + if (f->Error == 0) f->Write(V, n); + return (f->Error == 0); +} + + + + + +Boolean BITMAP::VBMLoad (XFILE * f) +{ + word p, n; + if (f->Error == 0) f->Read((byte far *)&p, sizeof(p)); + if (f->Error == 0) f->Read((byte far *)&n, sizeof(n)); + if (f->Error == 0) f->Read((byte far *)&W, sizeof(W)); + if (f->Error == 0) f->Read((byte far *)&H, sizeof(H)); + if (f->Error == 0) + { + if (p) + { + if (Pal) f->Read((byte far *)Pal, 256 * sizeof(DAC)); + else f->Seek(f->Mark() + 256 * sizeof(DAC)); + } + } + if ((V = farnew(byte, n)) == NULL) return FALSE; + if (f->Error == 0) f->Read(V, n); + B = (HideDesc far *) (V + n - H * sizeof(HideDesc)); + return (f->Error == 0); +} + + + + + diff --git a/engines/cge/bitmap.h b/engines/cge/bitmap.h new file mode 100644 index 0000000000..10d85430dc --- /dev/null +++ b/engines/cge/bitmap.h @@ -0,0 +1,60 @@ +#ifndef __BITMAP__ +#define __BITMAP__ + +#include <general.h> + +#define EOI 0x0000 +#define SKP 0x4000 +#define REP 0x8000 +#define CPY 0xC000 + +#define TRANS 0xFE + + +typedef struct { word b : 2; + word B : 6; + word g : 2; + word G : 6; + word r : 2; + word R : 6; + word Z : 8; + } BGR4; + + +typedef struct { word skip; word hide; } HideDesc; + + + + +class BITMAP +{ + Boolean BMPLoad (XFILE * f); + Boolean VBMLoad (XFILE * f); +public: + static DAC far * Pal; + word W, H; + byte far * M, far * V; HideDesc far * B; + BITMAP (const char * fname, Boolean rem = TRUE); + BITMAP (word w, word h, byte far * map); + BITMAP (word w, word h, byte fill); + BITMAP (const BITMAP& bmp); + ~BITMAP (void); + BITMAP * FlipH (void); + BITMAP * Code (); + BITMAP& operator = (const BITMAP& bmp); + void Hide (int x, int y); + void Show (int x, int y); + void XShow (int x, int y); + Boolean SolidAt (int x, int y); + Boolean VBMSave (XFILE * f); + word MoveVmap (byte far * buf); +}; + + + +typedef BITMAP * BMP_PTR; + + + + +#endif
\ No newline at end of file diff --git a/engines/cge/bitmaps.cpp b/engines/cge/bitmaps.cpp new file mode 100644 index 0000000000..2f79599c87 --- /dev/null +++ b/engines/cge/bitmaps.cpp @@ -0,0 +1,214 @@ +#include "bitmaps.h" +/* + +#define W 255, +#define x 252, +#define _ TRANS, +#define o 0, +#define L LGRAY, +#define G GRAY, +#define D DGRAY, + +static byte MCDesign0[]= { W W W W W W _ + W W W W W o _ + W W W W o _ _ + W W W W W _ _ + W W o W W W _ + W o _ o W W W + o _ _ _ o W W + _ _ _ _ _ o o }; + + +static byte MCDesign1[]= { _ }; + + + +static byte SLDesign[] = { G G G G G G G G G _ _ _ _ _ _ + L G G G G G G G G D _ _ _ _ _ + _ L G G G G G G G D _ _ _ _ _ + _ _ L G G G G G G G D _ _ _ _ + _ _ _ L G G G G G G D _ _ _ _ + _ _ _ _ L G G G G G D _ _ _ _ + _ _ _ _ _ L G G G G G D _ _ _ + _ _ _ _ _ _ L G G G G D _ _ _ + _ _ _ _ _ _ _ L G G G D _ _ _ + _ _ _ _ _ _ _ _ L G G G D _ _ + _ _ _ _ _ _ _ _ _ L G G D _ _ + _ _ _ _ _ _ _ _ _ _ L G D _ _ + _ _ _ _ _ _ _ _ _ _ _ L G D _ + _ _ _ _ _ _ _ _ _ _ _ _ L D _ + _ _ _ _ _ _ _ _ _ _ _ _ _ L D + _ _ _ _ _ _ _ _ _ _ _ _ _ _ D + }; + +static byte SRDesign[] = { _ _ _ _ _ _ G G G G G G G G G + _ _ _ _ _ L G G G G G G G G D + _ _ _ _ _ L G G G G G G G D _ + _ _ _ _ L G G G G G G G D _ _ + _ _ _ _ L G G G G G G D _ _ _ + _ _ _ _ L G G G G G D _ _ _ _ + _ _ _ L G G G G G D _ _ _ _ _ + _ _ _ L G G G G D _ _ _ _ _ _ + _ _ _ L G G G D _ _ _ _ _ _ _ + _ _ L G G G D _ _ _ _ _ _ _ _ + _ _ L G G D _ _ _ _ _ _ _ _ _ + _ _ L G D _ _ _ _ _ _ _ _ _ _ + _ L G D _ _ _ _ _ _ _ _ _ _ _ + _ L D _ _ _ _ _ _ _ _ _ _ _ _ + L D _ _ _ _ _ _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ _ _ _ _ _ _ + }; + +static byte MapBrick[] = { L L L L L L L G + L G G G G G G D + L G G G G G G D + G D D D D D D D + }; + +#undef W +#undef _ +#undef x +#undef o +#undef L +#undef G +#undef D + + +#if 0 + +#define _ TRANS, +#define A 213, +#define B 207, +#define C 225, +#define D 219, +#define E 231, + +static byte PRDesign[] = { A E E E C C D A B + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + B A A A A A A A B + B B B B B B B B B + }; + +#else + +#define _ TRANS, +#define A 213, +#define B 207, +#define C 225, // DGRAY +#define D 219, +#define E 231, +#define F 237, + +static byte PRDesign[] = { D D D D D D D D _ + D D D D D D D D _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ C _ + D C C C C C C C _ + _ _ _ _ _ _ _ _ _ + }; +#endif + + +#undef _ +#undef A +#undef B +#undef C +#undef D +#undef E + + + +#define _ 0x00, +#define x 0xFF, +#define A _ x _ x _ x _ x +#define B A A A A A A A A + +static byte HLDesign[] = { B B B B B }; + +#undef _ +#undef x +#undef A +#undef B + + +// 228 yellow +// 211 red +// 226 light green +// 221 blue + +#define A 208, +#define B 214, +#define C 220, +#define D 226, +#define E 255, + +static byte LIDesign[][9] = { { A A A + A B A + A A A }, + + { A B A + B C B + A B A }, + + { B C B + C D C + B C B }, + + { C D C + D E D + C D C }, + }; + +#undef A +#undef B +#undef C +#undef D +#undef E + + +#define R 211, +#define G 0, +//226, + +static byte MEDesign[][9] = { { R R R R R R R R R }, // 0 + { R R R R R R R R G }, // 1 + { R R R R R R R G G }, // 2 + { R R R R R R G G G }, // 3 + { R R R R R G G G G }, // 4 + { R R R R G G G G G }, // 5 + { R R R G G G G G G }, // 6 + { R R G G G G G G G }, // 7 + { R G G G G G G G G }, // 8 + { G G G G G G G G G }, // 9 + }; + +#undef R +#undef G +*/ + +#ifdef DEBUG + BMP_PTR MB[] = { new BITMAP("BRICK"), NULL }; + BMP_PTR HL[] = { new BITMAP("HLINE"), NULL }; +#endif + + BMP_PTR MC[] = { new BITMAP("MOUSE"), + new BITMAP("DUMMY"), + NULL }; + BMP_PTR PR[] = { new BITMAP("PRESS"), NULL }; + BMP_PTR SP[] = { new BITMAP("SPK_L"), + new BITMAP("SPK_R"), + NULL }; + BMP_PTR LI[] = { new BITMAP("LITE0"), + new BITMAP("LITE1"), + new BITMAP("LITE2"), + new BITMAP("LITE3"), + NULL }; diff --git a/engines/cge/bitmaps.h b/engines/cge/bitmaps.h new file mode 100644 index 0000000000..ef02c034e1 --- /dev/null +++ b/engines/cge/bitmaps.h @@ -0,0 +1,18 @@ +#ifndef __BITMAPS__ +#define __BITMAPS__ + +#include "vga13h.h" + +#ifdef DEBUG + extern BITMAP * MB[]; + extern BITMAP * HL[]; +#endif + +extern BITMAP * MC[]; +extern BITMAP * PR[]; +extern BITMAP * SP[]; +extern BITMAP * LI[]; + + +#endif +
\ No newline at end of file diff --git a/engines/cge/boot.h b/engines/cge/boot.h new file mode 100644 index 0000000000..18c7cd2499 --- /dev/null +++ b/engines/cge/boot.h @@ -0,0 +1,49 @@ +#ifndef __BOOT__ +#define __BOOT__ + +#include <jbw.h> + +#define BOOTSECT_SIZ 512 +#define BOOTHEAD_SIZ 62 +#define BOOTCODE_SIZ BOOTSECT_SIZ-BOOTHEAD_SIZ +#define FreeBoot(b) free(b) + +#ifndef EC + #define EC +#endif + +typedef struct { + byte Jmp[3]; // NEAR jump machine code + char OEM_ID[8]; // OEM name and version + word SectSize; // bytes per sector + byte ClustSize; // sectors per cluster + word ResSecs; // sectors before 1st FAT + byte FatCnt; // number of FATs + word RootSize; // root directory entries + word TotSecs; // total sectors on disk + byte Media; // media descriptor byte + word FatSize; // sectors per FAT + word TrkSecs; // sectors per track + word HeadCnt; // number of sufraces + word HidnSecs; // special hidden sectors + word _; // (unknown: reserved?) + dword lTotSecs; // total number of sectors + word DriveNum; // physical drive number + byte XSign; // extended boot signature + dword Serial; // volume serial number + char Label[11]; // volume label + char FileSysID[8]; // file system ID + char Code[BOOTCODE_SIZ-8]; // 8 = length of following + dword Secret; // long secret number + byte BootCheck; // boot sector checksum + byte BootFlags; // secret flags + word BootSig; // boot signature 0xAA55 + } Boot; + + +EC Boot * ReadBoot (int drive); +EC byte CheckBoot (Boot * boot); +EC Boolean WriteBoot (int drive, Boot * boot); + + +#endif
\ No newline at end of file diff --git a/engines/cge/cfile.cpp b/engines/cge/cfile.cpp new file mode 100644 index 0000000000..53b845b89f --- /dev/null +++ b/engines/cge/cfile.cpp @@ -0,0 +1,332 @@ +#include <cfile.h> +#include <dos.h> +#include <fcntl.h> +#include <string.h> +#include <alloc.h> + +#ifdef DROP_H + #include "drop.h" +#else + #include <stdio.h> + #include <stdlib.h> + #define DROP(m,n) { printf("%s [%s]\n", m, n); _exit(1); } +#endif + + + + +IOBUF::IOBUF (IOMODE mode, CRYPT * crpt) +: IOHAND(mode, crpt), + BufMark(0), + Ptr(0), + Lim(0) +{ + Buff = farnew(byte, IOBUF_SIZE); + if (Buff == NULL) DROP("No core for I/O", NULL); +} + + + + + + + + + +IOBUF::IOBUF (const char * name, IOMODE mode, CRYPT * crpt) +: IOHAND(name, mode, crpt), + BufMark(0), + Ptr(0), + Lim(0) +{ + Buff = farnew(byte, IOBUF_SIZE); + if (Buff == NULL) DROP("No core for I/O", name); +} + + + + + + + + + +IOBUF::~IOBUF (void) +{ + if (Mode > REA) WriteBuff(); + if (Buff) farfree(Buff); +} + + + + + + +void IOBUF::ReadBuff (void) +{ + BufMark = IOHAND::Mark(); + Lim = IOHAND::Read(Buff, IOBUF_SIZE); + Ptr = 0; +} + + + + + +void IOBUF::WriteBuff (void) +{ + if (Lim) + { + IOHAND::Write(Buff, Lim); + BufMark = IOHAND::Mark(); + Lim = 0; + } +} + + + + + +word IOBUF::Read (void far * buf, word len) +{ + word total = 0; + while (len) + { + if (Ptr >= Lim) ReadBuff(); + word n = Lim - Ptr; + if (n) + { + if (len < n) n = len; + _fmemcpy(buf, Buff+Ptr, n); + (byte far *) buf += n; + len -= n; + total += n; + Ptr += n; + } + else break; + } + return total; +} + + + + + + +word IOBUF::Read (byte far * buf) +{ + word total = 0; + + while (total < LINE_MAX-2) + { + if (Ptr >= Lim) ReadBuff(); + byte far * p = Buff + Ptr; + word n = Lim - Ptr; + if (n) + { + if (total + n >= LINE_MAX-2) n = LINE_MAX-2 - total; + byte far * eol = (byte far *) _fmemchr(p, '\r', n); + if (eol) n = (word) (eol - p); + byte far * eof = (byte far *) _fmemchr(p, '\32', n); + if (eof) // end-of-file + { + n = (word) (eof - p); + Ptr = (word) (eof - Buff); + } + if (n) _fmemcpy(buf, p, n); + buf += n; + total += n; + if (eof) break; + Ptr += n; + if (eol) + { + ++ Ptr; + * (buf ++) = '\n'; + ++ total; + if (Ptr >= Lim) ReadBuff(); + if (Ptr < Lim) if (Buff[Ptr] == '\n') ++ Ptr; + break; + } + } + else break; + } + *buf = '\0'; + return total; +} + + + + + + + +word IOBUF::Write (void far * buf, word len) +{ + word tot = 0; + while (len) + { + word n = IOBUF_SIZE - Lim; + if (n > len) n = len; + if (n) + { + _fmemcpy(Buff+Lim, buf, n); + Lim += n; + len -= n; + (byte far *) buf += n; + tot += n; + } + else WriteBuff(); + } + return tot; +} + + + + + + +word IOBUF::Write (byte far * buf) +{ + word len = 0; + if (buf) + { + len = _fstrlen((const char far *) buf); + if (len) if (buf[len-1] == '\n') -- len; + len = Write(buf, len); + if (len) + { + static char EOL[] = "\r\n"; + word n = Write(EOL, sizeof(EOL)-1); + len += n; + } + } + return len; +} + + + + + + +int IOBUF::Read (void) +{ + if (Ptr >= Lim) + { + ReadBuff(); + if (Lim == 0) return -1; + } + return Buff[Ptr ++]; +} + + + + + + +void IOBUF::Write (byte b) +{ + if (Lim >= IOBUF_SIZE) + { + WriteBuff(); + } + Buff[Lim ++] = b; +} + + + + + + + word CFILE::MaxLineLen = LINE_MAX; + + + + + + + + +CFILE::CFILE (const char near * name, IOMODE mode, CRYPT * crpt) +: IOBUF(name, mode, crpt) +{ +} + + + + + + + + + +CFILE::~CFILE (void) +{ +} + + + + + + +void CFILE::Flush (void) +{ + if (Mode > REA) WriteBuff(); + else Lim = 0; + _BX = Handle; + _AH = 0x68; // Flush buffer + asm int 0x21 +} + + + + + +long CFILE::Mark (void) +{ + return BufMark + ((Mode > REA) ? Lim : Ptr); +} + + + + + +long CFILE::Seek (long pos) +{ + if (pos >= BufMark && pos < BufMark + Lim) + { + ((Mode == REA) ? Ptr : Lim) = (word) (pos - BufMark); + return pos; + } + else + { + if (Mode > REA) + { + WriteBuff(); + } + else + { + Lim = 0; + } + Ptr = 0; + return BufMark = IOHAND::Seek(pos); + } +} + + + + + + +void CFILE::Append (CFILE& f) +{ + Seek(Size()); + if (f.Error == 0) + { + while (TRUE) + { + if ((Lim = f.IOHAND::Read(Buff, IOBUF_SIZE)) == IOBUF_SIZE) WriteBuff(); + else break; + if ((Error = f.Error) != 0) break; + } + } +} diff --git a/engines/cge/cfile.h b/engines/cge/cfile.h new file mode 100644 index 0000000000..57ff38831c --- /dev/null +++ b/engines/cge/cfile.h @@ -0,0 +1,56 @@ +#ifndef __CFILE__ +#define __CFILE__ + +#include <general.h> +#include <io.h> + + +#define LINE_MAX 512 + +#ifndef IOBUF_SIZE + #define IOBUF_SIZE K(2) +#endif + +#define CFREAD(x) Read((byte far *)(x),sizeof(*(x))) + + + + +class IOBUF : public IOHAND +{ +protected: + byte far * Buff; + word Ptr, Lim; + long BufMark; + word Seed; + CRYPT * Crypt; + virtual void ReadBuff (void); + virtual void WriteBuff (void); +public: + IOBUF (IOMODE mode, CRYPT * crpt = NULL); + IOBUF (const char * name, IOMODE mode, CRYPT * crpt = NULL); + virtual ~IOBUF (void); + word Read (void far * buf, word len); + word Read (char far * buf); + int Read (void); + word Write (void far * buf, word len); + word Write (byte far * buf); + void Write (byte b); +}; + + + +class CFILE : public IOBUF +{ +public: + static word MaxLineLen; + CFILE (const char near * name, IOMODE mode = REA, CRYPT * crpt = NULL); + virtual ~CFILE (void); + void Flush (void); + long Mark (void); + long Seek (long pos); + void Append (CFILE& f); +}; + + +#endif diff --git a/engines/cge/cge.cpp b/engines/cge/cge.cpp index e7c462e772..5613c3bb68 100644 --- a/engines/cge/cge.cpp +++ b/engines/cge/cge.cpp @@ -33,6 +33,7 @@ #include "engines/util.h" #include "cge/cge.h" +#include "cge/cge_main.h" namespace CGE { @@ -61,7 +62,9 @@ Common::Error CGEEngine::run() { // Additional setup. debug("CGEEngine::init"); - + + cge_main(); + return Common::kNoError; } diff --git a/engines/cge/cge.h b/engines/cge/cge.h index fac4f2c6cc..cb2c507ffa 100644 --- a/engines/cge/cge.h +++ b/engines/cge/cge.h @@ -40,7 +40,7 @@ class Console; enum { kCGEDebug = 1 << 0 }; - + class CGEEngine : public Engine { public: CGEEngine(OSystem *syst, const ADGameDescription *gameDescription); diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp new file mode 100644 index 0000000000..23865ec386 --- /dev/null +++ b/engines/cge/cge_main.cpp @@ -0,0 +1,2232 @@ +#include "cge\general.h" +#include "cge\boot.h" +#include "cge\ident.h" +#include "cge\sound.h" +#include "cge\startup.h" +#include "cge\config.h" +#include "cge\vga13h.h" +#include "cge\snail.h" +#include "cge\text.h" +#include "cge\game.h" +#include "cge\mouse.h" +#include "cge\keybd.h" +#include "cge\cfile.h" +#include "cge\vol.h" +#include "cge\talk.h" +#include "cge\vmenu.h" +#include "cge\gettext.h" +#include "cge\mixer.h" +#include "cge\cge_main.h" +#include <alloc.h> +#include <conio.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dos.h> +#include <dir.h> +#include <fcntl.h> +#include <bios.h> +#include <io.h> + +#define STACK_SIZ (K(2)) +#define SVGCHKSUM (1956+Now+OldLev+Game+Music+DemoText) + +#ifdef DEMO + #ifdef DEBUG + #define SVG0NAME ("{{INIT}}" SVG_EXT) + #else + #define SVG0NAME (ProgName(SVG_EXT)) + #endif +#else + #define SVG0NAME ("{{INIT}}" SVG_EXT) +#endif + +#ifdef DEBUG + #define SVG0FILE CFILE +#else + #define SVG0FILE INI_FILE +#endif + +extern word _stklen = (STACK_SIZ * 2); + +// 0.75 - 17II95 - full sound support +// 0.76 - 18II95 - small MiniEMS in DEMO, +// unhide CavLight in SNLEVEL +// keyclick suppress in startup +// keyclick on key service in: SYSTEM, GET_TEXT +// 1.01 - 17VII95 - default savegame with sound ON +// coditionals EVA for 2-month evaluation version + +/* + char Copr[] = "Common Game Engine " + #ifdef EVA + "ú" + #else + #ifdef CD + "ù" + #else + " " + #endif + #endif + " version 1.05 [" + #if sizeof(INI_FILE) == sizeof(VFILE) + "I" + #else + "i" + #endif + #if sizeof(PIC_FILE) == sizeof(VFILE) + "B" + #else + "b" + #endif + "]\n" + "Copyright (c) 1994 by Janusz B. Wi$niewski"; +*/ + char Copr[] = "To be fixed - Copr[]"; + +static char UsrFnam[15] = "\0ɱ%^þúȼ´ ÇÉ"; +static int OldLev = 0; +static int DemoText = DEMO_TEXT; + +//-------------------------------------------------------------------------- + + Boolean JBW = FALSE; + DAC *SysPal = farnew(DAC, PAL_CNT); + +//------------------------------------------------------------------------- + SPRITE PocLight = LI; + SPRITE * Pocket[POCKET_NX]={ NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, }; + int PocPtr = 0; +//------------------------------------------------------------------------- +//extern SPRITE * PocLight; +//extern SPRITE * Pocket[]; +//extern int PocPtr; +//------------------------------------------------------------------------- + + MOUSE Mouse; +static SPRITE * Sprite = NULL; +static SPRITE * MiniCave = NULL; +static SPRITE * Shadow = NULL; + +static VGA Vga = M13H; +static EMS * Mini = MiniEmm.Alloc((word)MINI_EMM_SIZE); +static BMP_PTR * MiniShpList = NULL; +static BMP_PTR MiniShp[] = { NULL, NULL }; +static KEYBOARD Keyboard; +static Boolean Finis = FALSE; +static int Startup = 1; +static int OffUseCount = atoi(Text[OFF_USE_COUNT]); + word * intStackPtr = FALSE; + + + HXY HeroXY[CAVE_MAX] = {{0,0}}; + BAR Barriers[1+CAVE_MAX] = { { 0xFF, 0xFF } }; + + +extern int FindPocket (SPRITE *); + +extern DAC StdPal[58]; + +#ifdef DEBUG +static SPRITE HorzLine = HL; +#endif + + + +void FeedSnail (SPRITE * spr, SNLIST snq); // defined in SNAIL + +//-------------------------------------------------------------------------- + + + + +byte CLUSTER::Map[MAP_ZCNT][MAP_XCNT]; + + + +byte & CLUSTER::Cell (void) +{ + return Map[B][A]; +} + + + + + + + + +Boolean CLUSTER::Protected (void) +{ + if (A == Barriers[Now].Vert || B == Barriers[Now].Horz) return TRUE; + + _DX = (MAP_ZCNT << 8) + MAP_XCNT; + _BX = (word) this; + + asm mov ax,1 + asm mov cl,[bx].(COUPLE)A + asm mov ch,[bx].(COUPLE)B + asm test cx,0x8080 // (A < 0) || (B < 0) + asm jnz xit + + asm cmp cl,dl + asm jge xit + asm cmp ch,dh + asm jge xit + +// if (A < 0 || A >= MAP_XCNT || B < 0 || B >= MAP_ZCNT) return TRUE; + + asm mov al,dl + asm mul ch + asm xor ch,ch + asm add ax,cx + asm mov bx,ax + _BX += (word) Map; + //asm add bx,offset CLUSTER::Map + asm mov al,[bx] + asm and ax,0xFF + asm jz xit + asm mov ax,1 + +// return Map[B][A] != 0; + + xit: return _AX; +} + + + + + +CLUSTER XZ (int x, int y) +{ + if (y < MAP_TOP) y = MAP_TOP; + if (y > MAP_TOP + MAP_HIG - MAP_ZGRID) y = MAP_TOP + MAP_HIG - MAP_ZGRID; + return CLUSTER(x / MAP_XGRID, (y-MAP_TOP) / MAP_ZGRID); +} + + + + +CLUSTER XZ (COUPLE xy) +{ + signed char x, y; + xy.Split(x, y); + return XZ(x, y); +} + + + + + + + +//-------------------------------------------------------------------------- + + + int pocref[POCKET_NX]; + byte volume[2]; + struct SAVTAB { void * Ptr; int Len; byte Flg; } SavTab[] = + {{ &Now, sizeof(Now), 1 }, + { &OldLev, sizeof(OldLev), 1 }, + { &DemoText, sizeof(DemoText), 1 }, + { &Game, sizeof(Game), 1 }, + { &Game, sizeof(Game), 1 }, // spare 1 + { &Game, sizeof(Game), 1 }, // spare 2 + { &Game, sizeof(Game), 1 }, // spare 3 + { &Game, sizeof(Game), 1 }, // spare 4 + { &VGA::Mono, sizeof(VGA::Mono), 0 }, + { &Music, sizeof(Music), 1 }, + { volume, sizeof(volume), 1 }, + + { Flag, sizeof(Flag), 1 }, + { HeroXY, sizeof(HeroXY), 1 }, + { Barriers, sizeof(Barriers), 1 }, + { pocref, sizeof(pocref), 1 }, + { NULL, 0, 0 } }; + + + + + +static void LoadGame (XFILE& file, Boolean tiny = FALSE) +{ + SAVTAB * st; + SPRITE * spr; + int i; + + for (st = SavTab; st->Ptr; st ++) + { + if (file.Error) VGA::Exit("Bad SVG"); + file.Read((byte far *) ((tiny || st->Flg) ? st->Ptr : &i), st->Len); + } + + file.Read((byte far *) &i, sizeof(i)); + if (i != SVGCHKSUM) VGA::Exit(BADSVG_TEXT); + if (STARTUP::Core < CORE_HIG) Music = FALSE; + if (STARTUP::SoundOk == 1 && STARTUP::Mode == 0) + { + SNDDrvInfo.VOL2.D = volume[0]; + SNDDrvInfo.VOL2.M = volume[1]; + SNDSetVolume(); + } + + if (! tiny) // load sprites & pocket + { + while (! file.Error) + { + SPRITE S(NULL); + word n = file.Read((byte far *) &S, sizeof(S)); + + if (n != sizeof(S)) break; + S.Prev = S.Next = NULL; + spr = (stricmp(S.File+2, "MUCHA") == 0) ? new FLY(NULL) + : new SPRITE(NULL); + if (spr == NULL) VGA::Exit("No core"); + *spr = S; + VGA::SpareQ.Append(spr); + } + + for (i = 0; i < POCKET_NX; i ++) + { + register int r = pocref[i]; + Pocket[i] = (r < 0) ? NULL : VGA::SpareQ.Locate(r); + } + } +} + + + + +static void SaveSound (void) +{ + CFILE cfg(UsrPath(ProgName(CFG_EXT)), WRI); + if (! cfg.Error) cfg.Write(&SNDDrvInfo,sizeof(SNDDrvInfo)-sizeof(SNDDrvInfo.VOL2)); +} + + + + + + +static void SaveGame (XFILE& file) +{ + SAVTAB * st; + SPRITE * spr; + int i; + + for (i = 0; i < POCKET_NX; i ++) + { + register SPRITE * s = Pocket[i]; + pocref[i] = (s) ? s->Ref : -1; + } + + volume[0] = SNDDrvInfo.VOL2.D; + volume[1] = SNDDrvInfo.VOL2.M; + + for (st = SavTab; st->Ptr; st ++) + { + if (file.Error) VGA::Exit("Bad SVG"); + file.Write((byte far *) st->Ptr, st->Len); + } + + file.Write((byte far *) &(i = SVGCHKSUM), sizeof(i)); + + for (spr = VGA::SpareQ.First(); spr; spr = spr->Next) + if (spr->Ref >= 1000) + if (!file.Error) file.Write((byte far *)spr, sizeof(*spr)); +} + + + + + + + +static void HeroCover (int cvr) +{ + SNPOST(SNCOVER, 1, cvr, NULL); +} + + + + +static void Trouble (int seq, int txt) +{ + Hero->Park(); + SNPOST(SNWAIT, -1, -1, Hero); + SNPOST(SNSEQ, -1, seq, Hero); + SNPOST(SNSOUND, -1, 2, Hero); + SNPOST(SNWAIT, -1, -1, Hero); + SNPOST(SNSAY, 1, txt, Hero); +} + + + +static void OffUse (void) +{ + Trouble(OFF_USE, OFF_USE_TEXT+random(OffUseCount)); +} + + + + +static void TooFar (void) +{ + Trouble(TOO_FAR, TOO_FAR_TEXT); +} + + + + +static void NoWay (void) +{ + Trouble(NO_WAY, NO_WAY_TEXT); +} + + + + + +static void LoadHeroXY (void) +{ + INI_FILE cf(ProgName(".HXY")); + memset(HeroXY, 0, sizeof(HeroXY)); + if (! cf.Error) cf.CFREAD(&HeroXY); +} + + + + + +static void LoadMapping (void) +{ + if (Now <= CAVE_MAX) + { + INI_FILE cf(ProgName(".TAB")); + if (! cf.Error) + { + memset(CLUSTER::Map, 0, sizeof(CLUSTER::Map)); + cf.Seek((Now - 1) * sizeof(CLUSTER::Map)); + cf.Read((byte far *) CLUSTER::Map, sizeof(CLUSTER::Map)); + } + } +} + + + + + + +//-------------------------------------------------------------------------- + +CLUSTER Trace[MAX_FIND_LEVEL]; +int FindLevel; + + + + + + + + +WALK::WALK (BMP_PTR * shpl) +: SPRITE(shpl), Dir(NO_DIR), TracePtr(-1) +{ +} + + + + + +void WALK::Tick (void) +{ + if (Flags.Hide) return; + + Here = XZ(X+W/2, Y+H); + + if (Dir != NO_DIR) + { + SPRITE * spr; + SYSTEM::FunTouch(); + for (spr = VGA::ShowQ.First(); spr; spr = spr->Next) + { + if (Distance(spr) < 2) + { + if (! spr->Flags.Near) + { + FeedSnail(spr, NEAR); + spr->Flags.Near = TRUE; + } + } + else spr->Flags.Near = FALSE; + } + } + + if (Flags.Hold || TracePtr < 0) Park(); + else + { + if (Here == Trace[TracePtr]) + { + if (-- TracePtr < 0) Park(); + } + else + { + signed char dx, dz; + (Trace[TracePtr] - Here).Split(dx, dz); + DIR d = (dx) ? ((dx > 0) ? EE : WW) : ((dz > 0) ? SS : NN); + Turn(d); + } + } + Step(); + if ((Dir == WW && X <= 0) || + (Dir == EE && X + W >= SCR_WID) || + (Dir == SS && Y + W >= WORLD_HIG-2)) Park(); + else + { + signed char x; // dummy var + Here.Split(x, Z); // take current Z position + SNPOST_(SNZTRIM, -1, 0, this); // update Hero's pos in show queue + } +} + + + + + + +int WALK::Distance (SPRITE * spr) +{ + int dx, dz; + dx = spr->X - (X+W-WALKSIDE); + if (dx < 0) dx = (X+WALKSIDE) - (spr->X+spr->W); + if (dx < 0) dx = 0; + dx /= MAP_XGRID; + dz = spr->Z - Z; + if (dz < 0) dz = - dz; + dx = dx * dx + dz * dz; + for (dz = 1; dz * dz < dx; dz ++) ; + return dz-1; +} + + + + + + + + + + +void WALK::Turn (DIR d) +{ + DIR dir = (Dir == NO_DIR) ? SS : Dir; + if (d != Dir) + { + Step((d == dir) ? (1 + dir + dir) : (9 + 4 * dir + d)); + Dir = d; + } +} + + + + + +void WALK::Park (void) +{ + if (Time == 0) ++ Time; + if (Dir != NO_DIR) + { + Step(9 + 4 * Dir + Dir); + Dir = NO_DIR; + TracePtr = -1; + } +} + + + + + + + +void WALK::FindWay (CLUSTER c) +{ + Boolean Find1Way(void); + extern word Target; + + if (c != Here) + { + for (FindLevel = 1; FindLevel <= MAX_FIND_LEVEL; FindLevel ++) + { + signed char x, z; + Here.Split(x, z); + Target = (z << 8) | x; + c.Split(x, z); + _CX = (z << 8) | x; + if (Find1Way()) break; + } + TracePtr = (FindLevel > MAX_FIND_LEVEL) ? -1 : (FindLevel - 1); + if (TracePtr < 0) NoWay(); + Time = 1; + } +} + + + + + + +void WALK::FindWay (SPRITE * spr) +{ + if (spr && spr != this) + { + int x = spr->X, z = spr->Z; + if (spr->Flags.East) x += spr->W + W/2 - WALKSIDE; + else x -= W/2 - WALKSIDE; + FindWay(CLUSTER((x/MAP_XGRID), + ((z < MAP_ZCNT-MAX_DISTANCE) ? (z+1) + : (z-1)))); + } +} + + + + + + +Boolean WALK::Lower (SPRITE * spr) +{ + return (spr->Y > Y + (H * 3) / 5); +} + + + + + + +void WALK::Reach (SPRITE * spr, int mode) +{ + if (spr) + { + Hero->FindWay(spr); + if (mode < 0) + { + mode = spr->Flags.East; + if (Lower(spr)) mode += 2; + } + } + // note: insert SNAIL commands in reverse order + SNINSERT(SNPAUSE, -1, 64, NULL); + SNINSERT(SNSEQ, -1, TSEQ + mode, this); + if (spr) + { + SNINSERT(SNWAIT, -1, -1, Hero); /////--------$$$$$$$ + //SNINSERT(SNWALK, -1, -1, spr); + } + // sequence is not finished, + // now it is just at sprite appear (disappear) point +} + + + + + + +//-------------------------------------------------------------------------- + + + +#ifdef DEBUG + + +class SQUARE : public SPRITE +{ +public: + SQUARE (void); + void Touch (word mask, int x, int y); +}; + + + + + + +SQUARE::SQUARE (void) +: SPRITE(MB) +{ + Flags.Kill = TRUE; + Flags.BDel = FALSE; +} + + + + + + + + +void SQUARE::Touch (word mask, int x, int y) +{ + SPRITE::Touch(mask, x, y); + if (mask & L_UP) + { + XZ(X+x, Y+y).Cell() = 0; + SNPOST_(SNKILL, -1, 0, this); + } +} + + + + + + +static void SetMapBrick (int x, int z) +{ + SQUARE * s = new SQUARE; + if (s) + { + static char n[] = "00:00"; + s->Goto(x * MAP_XGRID, MAP_TOP + z * MAP_ZGRID); + wtom(x, n+0, 10, 2); + wtom(z, n+3, 10, 2); + CLUSTER::Map[z][x] = 1; + s->SetName(n); + VGA::ShowQ.Insert(s, VGA::ShowQ.First()); + } +} + + +#endif + + + +//-------------------------------------------------------------------------- + +void dummy (void) { } +void SwitchMapping (void); +void SwitchColorMode (void); +void StartCountDown (void); +Debug( void SwitchDebug (void); ) +void SwitchMusic (void); +void KillSprite (void); +void PushSprite (void); +void PullSprite (void); +void BackPaint (void); +void NextStep (void); +void SaveMapping (void); + + + WALK * Hero = NULL; +static INFO_LINE InfoLine = INFO_W; + +static HEART Heart; + +static SPRITE CavLight = PR; + + + + + +static void KeyClick (void) +{ + SNPOST_(SNSOUND, -1, 5, NULL); +} + + + +static void ResetQSwitch (void) +{ + SNPOST_(SNSEQ, 123, 0, NULL); + KeyClick(); +} + + + + +static void Quit (void) +{ + static CHOICE QuitMenu[]={ { NULL, StartCountDown }, + { NULL, ResetQSwitch }, + { NULL, dummy } }; + + if (Snail.Idle() && ! Hero->Flags.Hide) + { + if (VMENU::Addr) + { + SNPOST_(SNKILL, -1, 0, VMENU::Addr); + ResetQSwitch(); + } + else + { + QuitMenu[0].Text = Text[QUIT_TEXT]; + QuitMenu[1].Text = Text[NOQUIT_TEXT]; + (new VMENU(QuitMenu, -1, -1))->SetName(Text[QUIT_TITLE]); + SNPOST_(SNSEQ, 123, 1, NULL); + KeyClick(); + } + } +} + + + + +static void AltCtrlDel (void) +{ + #if 0 + //def DEBUG + if (KEYBOARD::Key[LSHIFT] || KEYBOARD::Key[RSHIFT]) + { + PostFlag = 0x1234; + POST(); + } + else + #endif + SNPOST_(SNSAY, -1, A_C_D_TEXT, Hero); +} + + + + +static void MiniStep (int stp) +{ + if (stp < 0) MiniCave->Flags.Hide = TRUE; + else + { + &*Mini; + *MiniShp[0] = *MiniShpList[stp]; + if (Fx.Current) &*(Fx.Current->EAddr()); + MiniCave->Flags.Hide = FALSE; + } +} + + + + + +static void PostMiniStep (int stp) +{ + static int recent = -2; + if (MiniCave && stp != recent) SNPOST_(SNEXEC, -1, recent = stp, (void *) MiniStep); +} + + + +//-------------------------------------------------------------------------- + + + +int SYSTEM::FunDel = HEROFUN0; + + + + +void SYSTEM::SetPal (void) +{ + int i; + DAC far * p = SysPal + 256-ArrayCount(StdPal); + for (i = 0; i < ArrayCount(StdPal); i ++) + { + p[i].R = StdPal[i].R >> 2; + p[i].G = StdPal[i].G >> 2; + p[i].B = StdPal[i].B >> 2; + } +} + + + + + +void SYSTEM::FunTouch (void) +{ + word n = (PAIN) ? HEROFUN1 : HEROFUN0; + if (Talk == NULL || n > FunDel) FunDel = n; +} + + + + + + +static void ShowBak (int ref) +{ + SPRITE * spr = VGA::SpareQ.Locate(ref); + if (spr) + { + BITMAP::Pal = SysPal; + spr->Expand(); + BITMAP::Pal = NULL; + spr->Show(2); + VGA::CopyPage(1, 2); + SYSTEM::SetPal(); + spr->Contract(); + } +} + + + + + + +static void CaveUp (void) +{ + int BakRef = 1000 * Now; + if (Music) LoadMIDI(Now); + ShowBak(BakRef); + LoadMapping(); + Text.Preload(BakRef, BakRef+1000); + SPRITE * spr = VGA::SpareQ.First(); + while (spr) + { + SPRITE * n = spr->Next; + if (spr->Cave == Now || spr->Cave == 0) + if (spr->Ref != BakRef) + { + if (spr->Flags.Back) spr->BackShow(); + else ExpandSprite(spr); + } + spr = n; + } + if (SNDDrvInfo.DDEV) + { + Sound.Stop(); + Fx.Clear(); + Fx.Preload(0); + Fx.Preload(BakRef); + } + + if (Hero) + { + Hero->Goto(HeroXY[Now-1].X, HeroXY[Now-1].Y); + // following 2 lines trims Hero's Z position! + Hero->Tick(); + Hero->Time = 1; + Hero->Flags.Hide = FALSE; + } + + if (! Dark) Vga.Sunset(); + VGA::CopyPage(0, 1); + SelectPocket(-1); + if (Hero) VGA::ShowQ.Insert(VGA::ShowQ.Remove(Hero)); + if (Shadow) + { + VGA::ShowQ.Remove(Shadow); + Shadow->MakeXlat(Glass(SysPal, 204, 204, 204)); + VGA::ShowQ.Insert(Shadow, Hero); + Shadow->Z = Hero->Z; + } + FeedSnail(VGA::ShowQ.Locate(BakRef+999), TAKE); + Vga.Show(); + Vga.CopyPage(1, 0); + Vga.Show(); + Vga.Sunrise(SysPal); + Dark = FALSE; + if (! Startup) Mouse.On(); + HEART::Enable = TRUE; +} + + + + + +static void CaveDown (void) +{ + SPRITE * spr; + Debug( if (! HorzLine.Flags.Hide) SwitchMapping(); ) + + for (spr = VGA::ShowQ.First(); spr; ) + { + SPRITE * n = spr->Next; + if (spr->Ref >= 1000 /*&& spr->Cave*/) + { + if (spr->Ref % 1000 == 999) FeedSnail(spr, TAKE); + VGA::SpareQ.Append(VGA::ShowQ.Remove(spr)); + } + spr = n; + } + Text.Clear(1000); +} + + + + + +static void XCave (void) +{ + CaveDown(); + CaveUp(); +} + + + + +static void QGame (void) +{ + CaveDown(); + OldLev = Lev; + SaveSound(); + SaveGame(CFILE(UsrPath(UsrFnam), WRI, RCrypt)); + Vga.Sunset(); + Finis = TRUE; +} + + + + +void SwitchCave (int cav) +{ + if (cav != Now) + { + HEART::Enable = FALSE; + if (cav < 0) + { + SNPOST(SNLABEL, -1, 0, NULL); // wait for repaint + SNPOST(SNEXEC, -1, 0, (void *) QGame); // switch cave + } + else + { + Now = cav; + Mouse.Off(); + if (Hero) + { + Hero->Park(); + Hero->Step(0); + #ifndef DEMO + ///// protection: auto-destruction on! ---------------------- + VGA::SpareQ.Show = STARTUP::Summa * (cav <= CAVE_MAX); + /////-------------------------------------------------------- + #endif + } + CavLight.Goto(CAVE_X + ((Now-1) % CAVE_NX) * CAVE_DX + CAVE_SX, + CAVE_Y + ((Now-1) / CAVE_NX) * CAVE_DY + CAVE_SY); + KillText(); + if (! Startup) KeyClick(); + SNPOST(SNLABEL, -1, 0, NULL); // wait for repaint + SNPOST(SNEXEC, 0, 0, (void *) XCave); // switch cave + } + } +} + + + + + + +void SYSTEM::Touch (word mask, int x, int y) +{ + static int pp = 0; + void SwitchCave (int cav); + int cav = 0; + + FunTouch(); + + if (mask & KEYB) + { + int pp0; + KeyClick(); + KillText(); + if (Startup == 1) + { + SNPOST(SNCLEAR, -1, 0, NULL); + return; + } + pp0 = pp; + switch (x) + { + case Del : if (KEYBOARD::Key[ALT] && + KEYBOARD::Key[CTRL]) AltCtrlDel(); + Debug ( else KillSprite(); ) + break; + case 'F' : if (KEYBOARD::Key[ALT]) + { + SPRITE * m = VGA::ShowQ.Locate(17001); + if (m) + { + m->Step(1); + m->Time = 216; // 3s + } + } + break; + + #ifdef DEBUG + case PgUp : PushSprite(); break; + case PgDn : PullSprite(); break; + case '+' : NextStep(); break; + case '`' : if (KEYBOARD::Key[ALT]) SaveMapping(); else SwitchMapping(); break; + case F1 : SwitchDebug(); break; + case F3 : Hero->Step(TSEQ + 4); break; + case F4 : Hero->Step(TSEQ + 5); break; + case F5 : Hero->Step(TSEQ + 0); break; + case F6 : Hero->Step(TSEQ + 1); break; + case F7 : Hero->Step(TSEQ + 2); break; + case F8 : Hero->Step(TSEQ + 3); break; + case F9 : SYSTEM::FunDel = 1; break; + case 'X' : if (KEYBOARD::Key[ALT]) Finis = TRUE; break; + case '0' : + case '1' : + case '2' : + case '3' : + case '4' : if (KEYBOARD::Key[ALT]) { SNPOST(SNLEVEL, -1, x - '0', NULL); break; } + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : if (Sprite) Sprite->Step(x - '0'); break; + #else + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : SelectPocket(x - '1'); break; + #endif + + case F10 : if (Snail.Idle() && ! Hero->Flags.Hide) + StartCountDown(); + break; + case 'J' : if (pp == 0) ++ pp; break; + case 'B' : if (pp == 1) ++ pp; break; + case 'W' : if (pp == 2) JBW = !JBW; break; + } + if (pp == pp0) pp = 0; + } + else + { + if (Startup) return; + InfoLine.Update(NULL); + if (y >= WORLD_HIG) + { + if (x < BUTTON_X) // select cave? + { + if (y >= CAVE_Y && y < CAVE_Y + CAVE_NY * CAVE_DY && + x >= CAVE_X && x < CAVE_X + CAVE_NX * CAVE_DX && ! Game) + { + cav = ((y-CAVE_Y) / CAVE_DY) * CAVE_NX + (x-CAVE_X) / CAVE_DX + 1; + if (cav > MaxCave) cav = 0; + } + else + { + cav = 0; + } + } + else if (mask & L_UP) + { + if (y >= POCKET_Y && y < POCKET_Y + POCKET_NY * POCKET_DY && + x >= POCKET_X && x < POCKET_X + POCKET_NX * POCKET_DX) + { + int n = ((y-POCKET_Y) / POCKET_DY) * POCKET_NX + (x-POCKET_X) / POCKET_DX; + SelectPocket(n); + } + } + } + + PostMiniStep(cav-1); + + if (mask & L_UP) + { + if (cav && Snail.Idle() && Hero->TracePtr < 0) + { + SwitchCave(cav); + } + #ifdef DEBUG + if (! HorzLine.Flags.Hide) + { + if (y >= MAP_TOP && y < MAP_TOP+MAP_HIG) + { + signed char x1, z1; + XZ(x, y).Split(x1, z1); + CLUSTER::Map[z1][x1] = 1; + SetMapBrick(x1, z1); + } + } + else + #endif + { + if (! Talk && Snail.Idle() && Hero + && y >= MAP_TOP && y < MAP_TOP+MAP_HIG && ! Game) + { + Hero->FindWay(XZ(x, y)); + } + } + } + } +} + + + + + + + +void SYSTEM::Tick (void) +{ + if (! Startup) if (-- FunDel == 0) + { + KillText(); + if (Snail.Idle()) + { + if (PAIN) HeroCover(9); + else if (STARTUP::Core >= CORE_MID) + { + int n = random(100); + if (n > 96) HeroCover(6+(Hero->X+Hero->W/2 < SCR_WID/2)); + else + { + if (n > 90) HeroCover(5); + else + { + if (n > 60) HeroCover(4); + else HeroCover(3); + } + } + } + } + FunTouch(); + } + Time = SYSTIMERATE; +} + + + + + + + + + + +//-------------------------------------------------------------------------- + + + +/* +static void SpkOpen (void) +{ + asm in al,0x61 + asm or al,0x03 + asm out 0x61,al + asm mov al,0x90 + asm out 0x43,al +} + + + + + +static void SpkClose (void) +{ + asm in al,0x61 + asm and al,0xFC + asm out 0x61,al +} + +*/ + + + +static void SwitchColorMode (void) +{ + SNPOST_(SNSEQ, 121, VGA::Mono = ! VGA::Mono, NULL); + KeyClick(); + VGA::SetColors(SysPal, 64); +} + + + +static void SwitchMusic (void) +{ + if (KEYBOARD::Key[ALT]) + { + if (VMENU::Addr) SNPOST_(SNKILL, -1, 0, VMENU::Addr); + else + { + SNPOST_(SNSEQ, 122, (Music = FALSE), NULL); + SNPOST(SNEXEC, -1, 0, (void *) SelectSound); + } + } + else + { + if (STARTUP::Core < CORE_HIG) SNPOST(SNINF, -1, NOMUSIC_TEXT, NULL); + else + { + SNPOST_(SNSEQ, 122, (Music = ! Music), NULL); + KeyClick(); + } + } + if (Music) LoadMIDI(Now); + else KillMIDI(); +} + + + + + +static void StartCountDown (void) +{ + //SNPOST(SNSEQ, 123, 0, NULL); + SwitchCave(-1); +} + + + + +#ifndef DEMO +static void TakeName (void) +{ + if (GET_TEXT::Ptr) SNPOST_(SNKILL, -1, 0, GET_TEXT::Ptr); + else + { + GET_TEXT * tn = new GET_TEXT(Text[GETNAME_PROMPT], UsrFnam, 8, KeyClick); + if (tn) + { + tn->SetName(Text[GETNAME_TITLE]); + tn->Center(); + tn->Goto(tn->X, tn->Y - 10); + tn->Z = 126; + VGA::ShowQ.Insert(tn); + } + } +} +#endif + + + + + +#ifdef DEBUG + + +static void SwitchMapping (void) +{ + if (HorzLine.Flags.Hide) + { + int i; + for (i = 0; i < MAP_ZCNT; i ++) + { + int j; + for (j = 0; j < MAP_XCNT; j ++) + { + if (CLUSTER::Map[i][j]) + SetMapBrick(j, i); + } + } + } + else + { + SPRITE * s; + for (s = VGA::ShowQ.First(); s; s = s->Next) + if (s->W == MAP_XGRID && s->H == MAP_ZGRID) + SNPOST_(SNKILL, -1, 0, s); + } + HorzLine.Flags.Hide = ! HorzLine.Flags.Hide; +} + + + + + +static void KillSprite (void) +{ + Sprite->Flags.Kill = TRUE; + Sprite->Flags.BDel = TRUE; + SNPOST_(SNKILL, -1, 0, Sprite); + Sprite = NULL; +} + + + + + +static void PushSprite (void) +{ + SPRITE * spr = Sprite->Prev; + if (spr) + { + VGA::ShowQ.Insert(VGA::ShowQ.Remove(Sprite), spr); + while (Sprite->Z > Sprite->Next->Z) -- Sprite->Z; + } + else SNPOST_(SNSOUND, -1, 2, NULL); +} + + + + + +static void PullSprite (void) +{ + Boolean ok = FALSE; + SPRITE * spr = Sprite->Next; + if (spr) + { + spr = spr->Next; + if (spr) + { + ok = (! spr->Flags.Slav); + } + } + if (ok) + { + VGA::ShowQ.Insert(VGA::ShowQ.Remove(Sprite), spr); + if (Sprite->Prev) + while (Sprite->Z < Sprite->Prev->Z) ++ Sprite->Z; + } + else SNPOST_(SNSOUND, -1, 2, NULL); +} + + + + + + +static void NextStep (void) +{ + SNPOST_(SNSTEP, 0, 0, Sprite); +} + + + + + + + + + +static void SaveMapping (void) +{ + { + IOHAND cf(ProgName(".TAB"), UPD); + if (! cf.Error) + { + cf.Seek((Now-1) * sizeof(CLUSTER::Map)); + cf.Write((byte far *) CLUSTER::Map, sizeof(CLUSTER::Map)); + } + } + { + IOHAND cf(ProgName(".HXY"), WRI); + if (! cf.Error) + { + HeroXY[Now-1].X = Hero->X; + HeroXY[Now-1].Y = Hero->Y; + cf.Write((byte far *) HeroXY, sizeof(HeroXY)); + } + } +} + +#endif + + + +//-------------------------------------------------------------------------- + + + + + + + + + +#ifdef DEBUG + + + + // 1111111111222222222233333333 334444444444555555555566666666667777777777 + // 01234567890123456789012345678901234567 890123456789012345678901234567890123456789 +static char DebugText[] = " N=00000 F=000000 X=000 Y=000 FPS=0000\0S=00:00 000:000:000 000:000 00 "; + +#define NFRE (DebugText + 3) +#define FFRE (DebugText + 11) +#define ABSX (DebugText + 20) +#define ABSY (DebugText + 26) +#define FRPS (DebugText + 34) +#define XSPR (DebugText + 38) +#define SP_N (DebugText + 41) +#define SP_S (DebugText + 44) + +#define SP_X (DebugText + 47) +#define SP_Y (DebugText + 51) +#define SP_Z (DebugText + 55) +#define SP_W (DebugText + 59) +#define SP_H (DebugText + 63) +#define SP_F (DebugText + 67) +#define SP__ (DebugText + 70) + +INFO_LINE DebugLine(SCR_WID); + +static void SayDebug (void) +{ + if (! DebugLine.Flags.Hide) + { + static long t = -1L; + long t1 = Timer(); + + if (t1 - t >= 18) + { + static dword old = 0L; + dword now = Vga.FrmCnt; + dwtom(now - old, FRPS, 10, 4); + old = now; + t = t1; + } + + dwtom(Mouse.X, ABSX, 10, 3); + dwtom(Mouse.Y, ABSY, 10, 3); + dwtom(coreleft(), NFRE, 10, 5); + dwtom(farcoreleft(), FFRE, 10, 6); + + // sprite queue size + word n = 0; + SPRITE * spr; + for (spr = VGA::ShowQ.First(); spr; spr = spr->Next) + { + ++ n; + if (spr == Sprite) + { + *XSPR = ' '; + dwtom(n, SP_N, 10, 2); + dwtom(Sprite->X, SP_X, 10, 3); + dwtom(Sprite->Y, SP_Y, 10, 3); + dwtom(Sprite->Z, SP_Z, 10, 3); + dwtom(Sprite->W, SP_W, 10, 3); + dwtom(Sprite->H, SP_H, 10, 3); + dwtom(*(word *) (&Sprite->Flags), SP_F, 16, 2); + } + } + dwtom(n, SP_S, 10, 2); + *SP__ = (heapcheck() < 0) ? '!' : ' '; + DebugLine.Update(DebugText); + } +} + + + + + +static void SwitchDebug (void) +{ + DebugLine.Flags.Hide = ! DebugLine.Flags.Hide; +} + + + +#endif + + + + + + +static void OptionTouch (int opt, word mask) +{ + switch (opt) + { + case 1 : if (mask & L_UP) SwitchColorMode(); break; + case 2 : if (mask & L_UP) SwitchMusic(); + else + if (mask & R_UP) + if (! MIXER::Appear) + { + MIXER::Appear = TRUE; + new MIXER(BUTTON_X, BUTTON_Y); + } + break; + case 3 : if (mask & L_UP) Quit(); break; + } +} + + + + + +#pragma argsused +void SPRITE::Touch (word mask, int x, int y) +{ + SYSTEM::FunTouch(); + if ((mask & ATTN) == 0) + { + InfoLine.Update(Name()); + if (mask & (R_DN | L_DN)) Sprite = this; // DEBUG mode only? + if (Ref/10 == 12) + { + OptionTouch(Ref % 10, mask); + return; + } + if (Flags.Syst) return; // cannot access system sprites + if (Game) if (mask & L_UP) { mask &= ~L_UP; mask |= R_UP; } + if ((mask & R_UP) && Snail.Idle()) + { + SPRITE * ps = (PocLight.SeqPtr) ? Pocket[PocPtr] : NULL; + if (ps) + { + if (Flags.Kept || Hero->Distance(this) < MAX_DISTANCE) + { + if (Works(ps)) + { + FeedSnail(ps, TAKE); + } + else OffUse(); + SelectPocket(-1); + } + else TooFar(); + } + else + { + if (Flags.Kept) mask |= L_UP; + else + { + if (Hero->Distance(this) < MAX_DISTANCE) + {/// + if (Flags.Port) + { + if (FindPocket(NULL) < 0) PocFul(); + else + { + SNPOST(SNREACH, -1, -1, this); + SNPOST(SNKEEP, -1, -1, this); + Flags.Port = FALSE; + } + } + else + { + if (TakePtr != NO_PTR) + { + if (SnList(TAKE)[TakePtr].Com == SNNEXT) OffUse(); + else FeedSnail(this, TAKE); + } + else OffUse(); + } + }/// + else TooFar(); + } + } + } + if ((mask & L_UP) && Snail.Idle()) + { + if (Flags.Kept) + { + int n; + for (n = 0; n < POCKET_NX; n ++) + { + if (Pocket[n] == this) + { + SelectPocket(n); + break; + } + } + } + else SNPOST(SNWALK, -1, -1, this); // Hero->FindWay(this); + } + } +} + + + + + + + +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- + + + + + + +static void LoadSprite (const char *fname, int ref, int cav, int col = 0, int row = 0, int pos = 0) +{ + static char * Comd[] = { "Name", "Type", "Phase", "East", + "Left", "Right", "Top", "Bottom", + "Seq", "Near", "Take", + "Portable", "Transparent", + NULL }; + static char * Type[] = { "DEAD", "AUTO", "WALK", "NEWTON", "LISSAJOUS", + "FLY", NULL }; + char line[LINE_MAX]; + + int shpcnt = 0; + int type = 0; // DEAD + Boolean east = FALSE; + Boolean port = FALSE; + Boolean tran = FALSE; + int i, lcnt = 0; + word len; + + MergeExt(line, fname, SPR_EXT); + if (INI_FILE::Exist(line)) // sprite description file exist + { + INI_FILE sprf(line); + if (sprf.Error) + { + VGA::Exit("Bad SPR", line); + } + + while ((len = sprf.Read(line)) != 0) + { + ++ lcnt; + if (len && line[len-1] == '\n') line[-- len] = '\0'; + if (len == 0 || *line == '.') continue; + + if ((i = TakeEnum(Comd, strtok(line, " =\t"))) < 0) + { + VGA::Exit(NumStr("Bad line ######", lcnt), fname); + } + + switch (i) + { + case 0 : // Name - will be taken in Expand routine + break; + case 1 : // Type + if ((type = TakeEnum(Type, strtok(NULL, " \t,;/"))) < 0) + VGA::Exit(NumStr("Bad line ######", lcnt), fname); + break; + case 2 : // Phase + ++ shpcnt; + break; + case 3 : // East + east = (atoi(strtok(NULL, " \t,;/")) != 0); + break; + case 11 : // Portable + port = (atoi(strtok(NULL, " \t,;/")) != 0); + break; + case 12 : // Transparent + tran = (atoi(strtok(NULL, " \t,;/")) != 0); + break; + } + } + if (! shpcnt) + { + VGA::Exit("No shapes", fname); + } + } + else // no sprite description: mono-shaped sprite with only .BMP file + { + ++ shpcnt; + } + + // make sprite of choosen type + switch (type) + { + case 1 : // AUTO + Sprite = new SPRITE(NULL); + if (Sprite) + { + Sprite->Goto(col, row); + //Sprite->Time = 1;//-----------$$$$$$$$$$$$$$$$ + } + break; + case 2 : // WALK + WALK * w = new WALK(NULL); + if (w && ref == 1) + { + w->Goto(col, row); + if (Hero) + { + VGA::Exit("2nd HERO", fname); + } + Hero = w; + } + Sprite = w; + break; + /* + case 3 : // NEWTON + NEWTON * n = new NEWTON(NULL); + if (n) + { + n->Ay = (bottom-n->H); + n->By = 90; + n->Cy = 3; + n->Bx = 99; + n->Cx = 3; + n->Goto(col, row); + } + Sprite = n; + break; + */ + case 4 : // LISSAJOUS + VGA::Exit("Bad type", fname); + /* + LISSAJOUS * l = new LISSAJOUS(NULL); + if (l) + { + l->Ax = SCR_WID/2; + l->Ay = SCR_HIG/2; + l->Bx = 7; + l->By = 13; + l->Cx = 300; + l->Cy = 500; + * (long *) &l->Dx = 0; // movex * cnt + l->Goto(col, row); + } + Sprite = l; + */ + break; + case 5 : // FLY + FLY * f = new FLY(NULL); + Sprite = f; + //////Sprite->Time = 1;//-----------$$$$$$$$$$$$$$ + break; + default: // DEAD + Sprite = new SPRITE(NULL); + if (Sprite) Sprite->Goto(col, row); + break; + } + if (Sprite) + { + Sprite->Ref = ref; + Sprite->Cave = cav; + Sprite->Z = pos; + Sprite->Flags.East = east; + Sprite->Flags.Port = port; + Sprite->Flags.Tran = tran; + Sprite->Flags.Kill = TRUE; + Sprite->Flags.BDel = TRUE; + fnsplit(fname, NULL, NULL, Sprite->File, NULL); + Sprite->ShpCnt = shpcnt; + VGA::SpareQ.Append(Sprite); + } +} + + + + + + +static void LoadScript (const char *fname) +{ + char line[LINE_MAX]; + char * SpN; + int SpI, SpA, SpX, SpY, SpZ; + Boolean BkG = FALSE; + INI_FILE scrf(fname); + int lcnt = 0; + Boolean ok = TRUE; + + if (scrf.Error) return; + + while (scrf.Read(line) != 0) + { + char *p; + + ++ lcnt; + if (*line == 0 || *line == '\n' || *line == '.') continue; + + ok = FALSE; // not OK if break + // sprite ident number + if ((p = strtok(line, " \t\n")) == NULL) break; + SpI = atoi(p); + // sprite file name + if ((SpN = strtok(NULL, " ,;/\t\n")) == NULL) break; + // sprite cave + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) break; + SpA = atoi(p); + // sprite column + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) break; + SpX = atoi(p); + // sprite row + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) break; + SpY = atoi(p); + // sprite Z pos + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) break; + SpZ = atoi(p); + // sprite life + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) break; + BkG = atoi(p) == 0; + + ok = TRUE; // no break: OK + + Sprite = NULL; + LoadSprite(SpN, SpI, SpA, SpX, SpY, SpZ); + if (Sprite && BkG) Sprite->Flags.Back = TRUE; + } + if (! ok) + { + VGA::Exit(NumStr("Bad INI line ######", lcnt), fname); + } +} + + + + +static void MainLoop (void) +{ +#if 0 +//def DEBUG + static VgaRegBlk Mode[] = { + + { 0x04, VGASEQ, 0x08, 0x04 }, // memory mode + + { 0x03, VGAGRA, 0xFF, 0x00 }, // data rotate = 0 + { 0x05, VGAGRA, 0x03, 0x00 }, // R/W mode = 0 + { 0x06, VGAGRA, 0x02, 0x00 }, // misc + + { 0x14, VGACRT, 0x40, 0x00 }, // underline + { 0x13, VGACRT, 0xFF, 0x28 }, // screen width + { 0x17, VGACRT, 0xFF, 0xC3 }, // mode control + + { 0x11, VGACRT, 0x80, 0x00 }, // vert retrace end + { 0x09, VGACRT, 0xEF, 0x01 }, // max scan line + + { 0x30, VGAATR, 0x00, 0x20 }, // 256 color mode + +// { 0x12, VGACRT, 0xFF, 0x6E }, // vert display end +// { 0x15, VGACRT, 0xFF, 0x7F }, // start vb +// { 0x10, VGACRT, 0xFF, 0x94 }, // start vr + + { 0x00 } }; + + Vga.Setup(Mode); +#endif + + Debug( SayDebug(); ) + + #ifdef DEMO + #define TIM ((182L*6L) * 5L) + static dword tc = 0; + if (TimerCount - tc >= TIM && Talk == NULL && Snail.Idle()) + { + if (Text[DemoText]) + { + SNPOST(SNSOUND, -1, 4, NULL); // drumla + SNPOST(SNINF, -1, DemoText, NULL); + SNPOST(SNLABEL, -1, -1, NULL); + if (Text[++ DemoText] == NULL) DemoText = DEMO_TEXT + 1; + } + tc = TimerCount; + } + #undef TIM + #endif + + Vga.Show(); + Snail_.RunCom(); + Snail.RunCom(); +} + + + + + +void LoadUser (void) +{ + // set scene + if (STARTUP::Mode == 0) // user .SVG file found + { + LoadGame(CFILE(UsrPath(UsrFnam), REA, RCrypt)); + } + else + { + if (STARTUP::Mode == 1) LoadGame(SVG0FILE(SVG0NAME)); + else + { + LoadScript(ProgName(INI_EXT)); + Music = TRUE; + SaveGame(CFILE(SVG0NAME, WRI)); + VGA::Exit("Ok", SVG0NAME); + } + } + LoadScript(ProgName(IN0_EXT)); +} + + + + + +static void RunGame (void) +{ + Text.Clear(); + Text.Preload(100, 1000); + LoadHeroXY(); + + CavLight.Flags.Tran = TRUE; + VGA::ShowQ.Append(&CavLight); + CavLight.Flags.Hide = TRUE; + + static SEQ PocSeq[] = { { 0, 0, 0, 0, 20 }, + { 1, 2, 0, 0, 4 }, + { 2, 3, 0, 0, 4 }, + { 3, 4, 0, 0, 16 }, + { 2, 5, 0, 0, 4 }, + { 1, 6, 0, 0, 4 }, + { 0, 1, 0, 0, 16 }, + }; + PocLight.SetSeq(PocSeq); + PocLight.Flags.Tran = TRUE; + PocLight.Time = 1; + PocLight.Z = 120; + VGA::ShowQ.Append(&PocLight); + SelectPocket(-1); + + VGA::ShowQ.Append(&Mouse); + +// ___________ + LoadUser(); +// ~~~~~~~~~~~ + + if ((Sprite = VGA::SpareQ.Locate(121)) != NULL) + SNPOST_(SNSEQ, -1, VGA::Mono, Sprite); + if ((Sprite = VGA::SpareQ.Locate(122)) != NULL) Sprite->Step(Music); + SNPOST_(SNSEQ, -1, Music, Sprite); + if (! Music) KillMIDI(); + + if (Mini && INI_FILE::Exist("MINI.SPR")) + { + byte far * ptr = (byte far *) &*Mini; + if (ptr != NULL) + { + LoadSprite("MINI", -1, 0, MINI_X, MINI_Y); + ExpandSprite(MiniCave = Sprite); // NULL is ok + if (MiniCave) + { + MiniCave->Flags.Hide = TRUE; + MiniCave->MoveShapes(ptr); + MiniShp[0] = new BITMAP(*MiniCave->Shp()); + MiniShpList = MiniCave->SetShapeList(MiniShp); + PostMiniStep(-1); + } + } + } + + if (Hero) + { + ExpandSprite(Hero); + Hero->Goto(HeroXY[Now-1].X, HeroXY[Now-1].Y); + if (INI_FILE::Exist("00SHADOW.SPR")) + { + LoadSprite("00SHADOW", -1, 0, Hero->X + 14, Hero->Y + 51); + if ((Shadow = Sprite) != NULL) + { + Shadow->Ref = 2; + Shadow->Flags.Tran = TRUE; + Hero->Flags.Shad = TRUE; + VGA::ShowQ.Insert(VGA::SpareQ.Remove(Shadow), Hero); + } + } + } + + InfoLine.Goto(INFO_X, INFO_Y); + InfoLine.Flags.Tran = TRUE; + InfoLine.Update(NULL); + VGA::ShowQ.Insert(&InfoLine); + + #ifdef DEBUG + DebugLine.Z = 126; + VGA::ShowQ.Insert(&DebugLine); + + HorzLine.Y = MAP_TOP - (MAP_TOP > 0); + HorzLine.Z = 126; + VGA::ShowQ.Insert(&HorzLine); + #endif + + Mouse.Busy = VGA::SpareQ.Locate(BUSY_REF); + if (Mouse.Busy) ExpandSprite(Mouse.Busy); + + Startup = 0; + + SNPOST(SNLEVEL, -1, OldLev, &CavLight); + CavLight.Goto(CAVE_X + ((Now-1) % CAVE_NX) * CAVE_DX + CAVE_SX, + CAVE_Y + ((Now-1) / CAVE_NX) * CAVE_DY + CAVE_SY); + CaveUp(); + + KEYBOARD::SetClient(Sys); + // main loop + while (! Finis) + { + if (FINIS) SNPOST(SNEXEC, -1, 0, (void *) QGame); + MainLoop(); + } + + KEYBOARD::SetClient(NULL); + HEART::Enable = FALSE; + SNPOST(SNCLEAR, -1, 0, NULL); + SNPOST_(SNCLEAR, -1, 0, NULL); + Mouse.Off(); + VGA::ShowQ.Clear(); + VGA::SpareQ.Clear(); + Hero = NULL; + Shadow = NULL; +} + + + + +void Movie (const char * ext) +{ + const char * fn = ProgName(ext); + if (INI_FILE::Exist(fn)) + { + LoadScript(fn); + ExpandSprite(VGA::SpareQ.Locate(999)); + FeedSnail(VGA::ShowQ.Locate(999), TAKE); + VGA::ShowQ.Append(&Mouse); + HEART::Enable = TRUE; + KEYBOARD::SetClient(Sys); + while (! Snail.Idle()) + { + MainLoop(); + } + KEYBOARD::SetClient(NULL); + HEART::Enable = FALSE; + SNPOST(SNCLEAR, -1, 0, NULL); + SNPOST_(SNCLEAR, -1, 0, NULL); + VGA::ShowQ.Clear(); + VGA::SpareQ.Clear(); + } +} + + + + + + +Boolean ShowTitle (const char * name) +{ + BITMAP::Pal = SysPal; + BMP_PTR LB[] = { new BITMAP(name), NULL }; + BITMAP::Pal = NULL; + Boolean usr_ok = FALSE; + + SPRITE D(LB); + D.Flags.Kill = TRUE; + D.Flags.BDel = TRUE; + D.Center(); + D.Show(2); + + if (STARTUP::Mode == 2) + { + Inf(SVG0NAME); + Talk->Show(2); + } + + Vga.Sunset(); + VGA::CopyPage(1, 2); + VGA::CopyPage(0, 1); + SelectPocket(-1); + Vga.Sunrise(SysPal); + + if (STARTUP::Mode < 2 && ! STARTUP::SoundOk) + { + VGA::CopyPage(1, 2); + VGA::CopyPage(0, 1); + VGA::ShowQ.Append(&Mouse); + HEART::Enable = TRUE; + Mouse.On(); + for (SelectSound(); ! Snail.Idle() || VMENU::Addr; ) MainLoop(); + Mouse.Off(); + HEART::Enable = FALSE; + VGA::ShowQ.Clear(); + VGA::CopyPage(0, 2); + STARTUP::SoundOk = 2; + if (Music) LoadMIDI(0); + } + + if (STARTUP::Mode < 2) + { + #ifdef DEMO + strcpy(UsrFnam, ProgName(SVG_EXT)); + usr_ok = TRUE; + #else + //----------------------------------------- + #ifndef EVA + #ifdef CD + STARTUP::Summa |= (0xC0 + (DriveCD(0) << 6)) & 0xFF; + #else + Boot * b = ReadBoot(getdisk()); + dword sn = (b->XSign == 0x29) ? b->Serial : b->lTotSecs; + free(b); + sn -= ((IDENT *)Copr)->disk; + STARTUP::Summa |= Lo(sn) | Hi(sn); + #endif + #endif + //----------------------------------------- + Movie("X00"); // paylist + VGA::CopyPage(1, 2); + VGA::CopyPage(0, 1); + VGA::ShowQ.Append(&Mouse); + //Mouse.On(); + HEART::Enable = TRUE; + for (TakeName(); GET_TEXT::Ptr; ) MainLoop(); + HEART::Enable = FALSE; + if (KEYBOARD::Last() == Enter && *UsrFnam) usr_ok = TRUE; + if (usr_ok) strcat(UsrFnam, SVG_EXT); + //Mouse.Off(); + VGA::ShowQ.Clear(); + VGA::CopyPage(0, 2); + #endif + if (usr_ok && STARTUP::Mode == 0) + { + const char *n = UsrPath(UsrFnam); + if (CFILE::Exist(n)) + { + LoadGame(CFILE(n, REA, RCrypt), TRUE); // only system vars + VGA::SetColors(SysPal, 64); + Vga.Update(); + if (FINIS) + { + ++ STARTUP::Mode; + FINIS = FALSE; + } + } + else ++ STARTUP::Mode; + } + } + + if (STARTUP::Mode < 2) Movie("X01"); // wink + + VGA::CopyPage(0, 2); + + #ifdef DEMO + return TRUE; + #else + return (STARTUP::Mode == 2 || usr_ok); + #endif +} + + + + +/* +#ifdef DEBUG +void StkDump (void) +{ + CFILE f("!STACK.DMP", BFW); + f.Write((byte far *) (intStackPtr-STACK_SIZ/2), STACK_SIZ*2); +} +#endif +*/ + + + + +void cge_main (void) +{ + word intStack[STACK_SIZ/2]; + intStackPtr = intStack; + + //Debug( memset((void *) (-K(2)), 0, K(1)); ) + //Debug( memset((void *) (-K(4)), 0, K(1)); ) + memset(Barriers, 0xFF, sizeof(Barriers)); + + if (! Mouse.Exist) VGA::Exit(NO_MOUSE_TEXT); + if (! SVG0FILE::Exist(SVG0NAME)) STARTUP::Mode = 2; + + Debug( DebugLine.Flags.Hide = TRUE; ) + Debug( HorzLine.Flags.Hide = TRUE; ) + + srand((word) Timer()); + Sys = new SYSTEM; + + if (Music && STARTUP::SoundOk) LoadMIDI(0); + if (STARTUP::Mode < 2) Movie(LGO_EXT); + if (ShowTitle("WELCOME")) + { + #ifndef DEMO + if (STARTUP::Mode == 1) Movie("X02"); // intro + #endif + RunGame(); + Startup = 2; + if (FINIS) Movie("X03"); + } + else Vga.Sunset(); + VGA::Exit(EXIT_OK_TEXT+FINIS); +} diff --git a/engines/cge/cge_main.h b/engines/cge/cge_main.h new file mode 100644 index 0000000000..f5c104600a --- /dev/null +++ b/engines/cge/cge_main.h @@ -0,0 +1,181 @@ +#ifndef __CGE__ +#define __CGE__ + +#include "cge\wav.h" + +namespace CGE { + +#define TSEQ 96 +#define HTALK (TSEQ+4) +#define TOO_FAR (TSEQ+5) +#define NO_WAY (TSEQ+5) +#define POC_FUL (TSEQ+5) +#define OFF_USE (TSEQ+6) + +#define EXIT_OK_TEXT 40 +#define NOMUSIC_TEXT 98 +#define BADSVG_TEXT 99 +#define OFF_USE_COUNT 600 +#define OFF_USE_TEXT 601 +#define NO_WAY_TEXT 671 +#define TOO_FAR_TEXT 681 +#define POC_FUL_TEXT 691 +#define A_C_D_TEXT 777 + +#define GETNAME_PROMPT 50 +#define GETNAME_TITLE 51 + +#define QUIT_TITLE 200 +#define QUIT_TEXT 201 +#define NOQUIT_TEXT 202 +#define DEMO_TEXT 300 +#define NOSOUND_TEXT 310 + +#define PAN_HIG 40 +#define WORLD_HIG (SCR_HIG-PAN_HIG) + +#define INFO_X 177 +#define INFO_Y 164 +#define INFO_W 140 + +#if defined(DEMO) + #define CAVE_X 4 + #define CAVE_Y 166 + #define CAVE_SX 0 + #define CAVE_SY 0 + #define CAVE_DX 23 + #define CAVE_DY 29 + #define CAVE_NX 3 + #define CAVE_NY 1 +#else + #define CAVE_X 4 + #define CAVE_Y 166 + #define CAVE_SX 0 + #define CAVE_SY 0 + #define CAVE_DX 9 + #define CAVE_DY 10 + #define CAVE_NX 8 + #define CAVE_NY 3 +#endif + +#define BUTTON_X 151 +#define BUTTON_Y 164 +#define BUTTON_DX 19 +#define BUTTON_DY 11 +#define BUTTON_NX 1 +#define BUTTON_NY 3 + +#define MINI_X 86 +#define MINI_Y 162 + +//#define MAP_XCNT 16 +//#define MAP_ZCNT 4 +#define MAP_XCNT 40 +#define MAP_ZCNT 20 +#define MAP_TOP 80 +#define MAP_HIG 80 +#define MAP_XGRID (SCR_WID / MAP_XCNT) +#define MAP_ZGRID (MAP_HIG / MAP_ZCNT) + +//#if SCR_WID % MAP_XGRID +// #error Illegal horizontal grid size or count +//#endif + +//#if MAP_HIG % MAP_ZGRID +// #error Illegal vertical grid size or count +//#endif + +#define LINE_MAX 512 +#define USER_MAX 100 +#define SHP_MAX 1024 +#define STD_DELAY 3 +#define LEV_MAX 5 +#define CAVE_MAX (CAVE_NX*CAVE_NY) +#define MAX_FIND_LEVEL 3 +#define MAX_DISTANCE 3 + +#define INI_EXT ".INI" +#define IN0_EXT ".IN0" +#define LGO_EXT ".LGO" +#define SVG_EXT ".SVG" + +#define WALKSIDE 10 + +#define BUSY_REF 500 + +#define SYSTIMERATE 6 // 12 Hz +#define HEROFUN0 (40*12) +#define HEROFUN1 ( 2*12) +#define PAIN (Flag[0]) +#define FINIS (Flag[3]) + + +//-------------------------------------------------------------------------- + + +class SYSTEM : public SPRITE +{ + int lum; +public: + static int FunDel; + static void SetPal (void); + static void FunTouch (void); + SYSTEM (void) : SPRITE(NULL) { SetPal(); Tick(); } + void Touch (word mask, int x, int y); + void Tick (void); +}; + + + + +//-------------------------------------------------------------------------- + + + + +class CLUSTER : public COUPLE +{ +public: + static byte Map[MAP_ZCNT][MAP_XCNT]; + byte &Cell (void); + CLUSTER (void) : COUPLE () { } + CLUSTER (int a, int b) : COUPLE (a, b) { } + Boolean Protected (void); +}; + + + + +class WALK : public SPRITE +{ +public: + CLUSTER Here; + enum DIR { NO_DIR = -1, NN, EE, SS, WW } Dir; + int TracePtr; + WALK (BMP_PTR * shpl); + void Tick (void); + void FindWay(CLUSTER c); + void FindWay(SPRITE * spr); + int Distance (SPRITE * spr); + void Turn (DIR d); + void Park (void); + Boolean Lower (SPRITE * spr); + void Reach (SPRITE * spr, int mode = -1); +}; + + + + + CLUSTER XZ (int x, int y); + CLUSTER XZ (COUPLE xy); + + +extern WALK * Hero; + + + void ExpandSprite (SPRITE * spr); + void ContractSprite (SPRITE * spr); + void cge_main(void); + +} // End of CGE +#endif diff --git a/engines/cge/drop.h b/engines/cge/drop.h new file mode 100644 index 0000000000..e79b2eb899 --- /dev/null +++ b/engines/cge/drop.h @@ -0,0 +1 @@ +#include "vga13h.h" diff --git a/engines/cge/game.cpp b/engines/cge/game.cpp new file mode 100644 index 0000000000..4ac27651b7 --- /dev/null +++ b/engines/cge/game.cpp @@ -0,0 +1,91 @@ +#include "game.h" +#include "mouse.h" +#include <stdlib.h> +#include <dos.h> + + + + + +byte * Glass (DAC far * pal, byte r, byte g, byte b) +{ + byte * x = new byte[256]; + if (x) + { + word i; + for (i = 0; i < 256; i ++) + { + x[i] = Closest(pal, MkDAC(((word)(pal[i].R) * r) / 255, + ((word)(pal[i].G) * g) / 255, + ((word)(pal[i].B) * b) / 255)); + } + } + return x; +} + + + + + +byte * Mark (DAC far * pal) +{ + #define f(c) (c ^ 63) + byte * x = new byte[256]; + if (x) + { + word i; + for (i = 0; i < 256; i ++) + { + x[i] = Closest(pal, MkDAC(f(pal[i].R), + f(pal[i].G), + f(pal[i].B)) ); + } + } + return x; + #undef f +} + + + + + +//-------------------------------------------------------------------------- + + + +int FLY::L = 20, + FLY::T = 40, + FLY::R = 110, + FLY::B = 100; + + + +FLY::FLY (BITMAP ** shpl) +: SPRITE(shpl), Tx(0), Ty(0) +{ + Step(random(2)); + Goto(L+random(R-L-W), T+random(B-T-H)); +} + + + + +void FLY::Tick (void) +{ + Step(); + if (! Flags.Kept) + { + if (random(10) < 1) + { + Tx = random(3) - 1; + Ty = random(3) - 1; + } + if (X + Tx < L || X + Tx + W > R) Tx = -Tx; + if (Y + Ty < T || Y + Ty + H > B) Ty = -Ty; + Goto(X + Tx, Y + Ty); + } +} + + +//-------------------------------------------------------------------------- + diff --git a/engines/cge/game.h b/engines/cge/game.h new file mode 100644 index 0000000000..92ad49b2a4 --- /dev/null +++ b/engines/cge/game.h @@ -0,0 +1,40 @@ +#ifndef __GAME__ +#define __GAME__ + +#include "vga13h.h" +#include "bitmaps.h" + + + +#define PAN_HIG 40 +#define LBound(s) (s->X <= 0) +#define RBound(s) (s->X+s->W >= SCR_WID) +#define TBound(s) (s->Y <= 0) +#define BBound(s) (s->Y+s->H >= SCR_HIG - PAN_HIG) + + + +extern SPRITE * Sys; + +int Sinus (long x); +byte * Glass (DAC far * pal, byte r, byte g, byte b); +byte * Mark (DAC far * pal); + + + + + +class FLY : public SPRITE +{ + static int L, T, R, B; +public: + int Tx, Ty; + FLY (BITMAP ** shpl); + void Tick (void); +}; + + + + + +#endif
\ No newline at end of file diff --git a/engines/cge/general.h b/engines/cge/general.h new file mode 100644 index 0000000000..7e9551e076 --- /dev/null +++ b/engines/cge/general.h @@ -0,0 +1,241 @@ +#ifndef __GENERAL__ +#define __GENERAL__ + +#include "cge\jbw.h" +#include <io.h> + +#define SEED 0xA5 + +#define SCR_WID_ 320 +#define SCR_HIG_ 200 +#define SCR_WID ((word)SCR_WID_) +#define SCR_HIG ((word)SCR_HIG_) +#define SCR_SEG 0xA000 +#define SCR_ADR ((byte far *) MK_FP(SCR_SEG, 0)) + + + +enum CPU { _8086, _80186, _80286, _80386, _80486 }; +enum MEM_TYPE { BAD_MEM, EMS_MEM, NEAR_MEM, FAR_MEM }; +enum ALLOC_MODE { FIRST_FIT, BEST_FIT, LAST_FIT }; +enum IOMODE { REA, WRI, UPD }; + +typedef struct { + byte R, G, B; + } DAC; + +typedef word CRYPT (void far * buf, word siz, word seed); + + + + + + +class COUPLE +{ +protected: + signed char A; + signed char B; +public: + COUPLE (void) { } + COUPLE (const signed char a, const signed char b) : A(a), B(b) { } + COUPLE operator + (COUPLE c) { return COUPLE(A+c.A, B+c.B); } + void operator += (COUPLE c) { A += c.A; B += c.B; } + COUPLE operator - (COUPLE c) { return COUPLE(A-c.A, B-c.B); } + void operator -= (COUPLE c) { A -= c.A; B -= c.B; } + Boolean operator == (COUPLE c) { return ((A - c.A) | (B - c.B)) == 0; } + Boolean operator != (COUPLE c) { return ! (operator == (c)); } + void Split (signed char& a, signed char& b) { a = A; b = B; } +}; + + +//------------------------------------------------------------------------- + + + +class ENGINE +{ +protected: + static void interrupt (far * OldTimer) (...); + static void interrupt NewTimer (...); +public: + ENGINE (word tdiv); + ~ENGINE (void); +}; + + + + +//------------------------------------------------------------------------- + + +class EMS; + + + +class EMM +{ + friend EMS; + Boolean Test (void); + long Top, Lim; + EMS * List; + int Han; + static void _seg * Frame; +public: + EMM::EMM (long size = 0); + EMM::~EMM (void); + EMS * Alloc (word siz); + void Release (void); +}; + + + + + +class EMS +{ + friend EMM; + EMM * Emm; + long Ptr; + word Siz; + EMS * Nxt; +public: + EMS (void); + void far * operator & () const; + word Size (void); +}; + + + +//------------------------------------------------------------------------- + + + + +template <class T> +void Swap (T& A, T& B) +{ + T a = A; + A = B; + B = a; +}; + + + + + +#ifdef __cplusplus + + +template <class T> +T max (T A, T B) +{ + return (A > B) ? A : B; +}; + + + +template <class T> +T min (T A, T B) +{ + return (A < B) ? A : B; +}; + + +#endif + + + + + + + +class XFILE +{ +public: + IOMODE Mode; + word Error; + XFILE (void) : Mode(REA), Error(0) { } + XFILE (IOMODE mode) : Mode(mode), Error(0) { } + virtual word Read (void far * buf, word len) = 0; + virtual word Write (void far * buf, word len) = 0; + virtual long Mark (void) = 0; + virtual long Size (void) = 0; + virtual long Seek (long pos) = 0; +}; + + + + + +template <class T> +inline word XRead (XFILE * xf, T * t) +{ + return xf->Read((byte far *) t, sizeof(*t)); +}; + + + + + +class IOHAND : public XFILE +{ +protected: + int Handle; + word Seed; + CRYPT * Crypt; +public: + IOHAND (const char near * name, IOMODE mode = REA, CRYPT crypt = NULL); + IOHAND (IOMODE mode = REA, CRYPT * crpt = NULL); + virtual ~IOHAND (void); + static Boolean Exist (const char * name); + word Read (void far * buf, word len); + word Write (void far * buf, word len); + long Mark (void); + long Size (void); + long Seek (long pos); + ftime Time (void); + void SetTime (ftime t); +}; + + + + + +CRYPT XCrypt; +CRYPT RXCrypt; +CRYPT RCrypt; + +MEM_TYPE MemType (void far * mem); +unsigned FastRand (void); +unsigned FastRand (unsigned s); +CPU Cpu (void); +ALLOC_MODE SetAllocMode (ALLOC_MODE am); +word atow (const char * a); +word xtow (const char * x); +char * wtom (word val, char * str, int radix, int len); +char * dwtom (dword val, char * str, int radix, int len); +char * DateTimeString (void); +void StdLog (const char *msg, const char *nam = NULL); +void StdLog (const char *msg, word w); +void StdLog (const char *msg, dword d); +int TakeEnum (const char ** tab, const char * txt); +word ChkSum (void far * m, word n); +long Timer (void); +long TimerLimit (word t); +Boolean TimerLimitGone (long t); +char * MergeExt (char * buf, const char * nam, const char * ext); +char * ForceExt (char * buf, const char * nam, const char * ext); +inline const char * ProgPath (void); +const char * ProgName (const char * ext = NULL); +int DriveFixed (unsigned drv); +int DriveRemote (unsigned drv); +int DriveCD (unsigned drv); +Boolean IsVga (void); + +EC void _fqsort (void far *base, word nelem, word width, + int (*fcmp)(const void far *, const void far *)); + + + +#endif diff --git a/engines/cge/gettext.cpp b/engines/cge/gettext.cpp new file mode 100644 index 0000000000..69350b5fc8 --- /dev/null +++ b/engines/cge/gettext.cpp @@ -0,0 +1,110 @@ +#include "gettext.h" +#include "keybd.h" +#include "mouse.h" +#include <string.h> + + + + + +GET_TEXT * GET_TEXT::Ptr = NULL; + + + +GET_TEXT::GET_TEXT (const char * info, char * text, int size, void (*click)(void)) +: Text(text), Size(min(size, GTMAX)), Len(min(Size, strlen(text))), + Cntr(GTBLINK), Click(click), OldKeybClient(KEYBOARD::SetClient(this)) +{ + int i = 2 * TEXT_HM + Font.Width(info); + Ptr = this; + Mode = RECT; + TS[0] = Box((i + 3) & ~3, 2 * TEXT_VM + 2 * FONT_HIG + TEXT_LS); + SetShapeList(TS); + Flags.BDel = TRUE; + Flags.Kill = TRUE; + memcpy(Buff, text, Len); + Buff[Len] = ' '; + Buff[Len+1] = '\0'; + PutLine(0, info); + Tick(); +} + + + + + + +GET_TEXT::~GET_TEXT (void) +{ + KEYBOARD::SetClient(OldKeybClient); + Ptr = NULL; +} + + + + + + +void GET_TEXT::Tick (void) +{ + if (++ Cntr >= GTBLINK) + { + Buff[Len] ^= (' ' ^ '_'); + Cntr = 0; + } + PutLine(1, Buff); + Time = GTTIME; +} + + + + +void GET_TEXT::Touch (word mask, int x, int y) +{ + static char ogon[] = "•œ¥£˜ ¡"; + static char bezo[] = "ACELNOSXZ"; + char * p; + + if (mask & KEYB) + { + if (Click) Click(); + switch (x) + { + case Enter : Buff[Len] = '\0'; strcpy(Text, Buff); + for (p = Text; *p; p ++) + { + char * q = strchr(ogon, *p); + if (q) *p = bezo[q-ogon]; + } + case Esc : SNPOST_(SNKILL, -1, 0, this); break; + case BSp : if (Len) + { + -- Len; + Buff[Len] = Buff[Len+1]; + Buff[Len+1] = Buff[Len+2]; + } + break; + default : if (x < 'A' || x > 'Z') + { + if (OldKeybClient) + OldKeybClient->Touch(mask, x, y); + } + else + { + if (KEYBOARD::Key[ALT]) + { + p = strchr(bezo, x); + if (p) x = ogon[p-bezo]; + } + if (Len < Size && 2 * TEXT_HM + Font.Width(Buff) + Font.Wid[x] <= W) + { + Buff[Len+2] = Buff[Len+1]; + Buff[Len+1] = Buff[Len]; + Buff[Len ++] = x; + } + } + break; + } + } + else SPRITE::Touch(mask, x, y); +} diff --git a/engines/cge/gettext.h b/engines/cge/gettext.h new file mode 100644 index 0000000000..8d4e15c6cb --- /dev/null +++ b/engines/cge/gettext.h @@ -0,0 +1,35 @@ +#ifndef __GETTEXT__ +#define __GETTEXT__ + +#include <general.h> +#include "talk.h" + + +#define GTMAX 24 +#define GTBLINK 6 +#define GTTIME 6 + + + + + + + +class GET_TEXT : public TALK +{ + char Buff[GTMAX+2], * Text; + word Size, Len; + word Cntr; + SPRITE * OldKeybClient; + void (*Click)(void); +public: + static GET_TEXT * Ptr; + GET_TEXT (const char * info, char * text, int size, void (*click)(void) = NULL); + ~GET_TEXT (void); + void Touch (word mask, int x, int y); + void Tick (void); +}; + + + +#endif diff --git a/engines/cge/ident.h b/engines/cge/ident.h new file mode 100644 index 0000000000..5370b9638c --- /dev/null +++ b/engines/cge/ident.h @@ -0,0 +1,14 @@ +#ifndef __IDENT__ +#define __IDENT__ + + +struct IDENT + { + char copr[83]; + char fill[8]; + unsigned long disk; + unsigned char cork; + }; + + +#endif diff --git a/engines/cge/jbw.h b/engines/cge/jbw.h new file mode 100644 index 0000000000..98ce9e27b5 --- /dev/null +++ b/engines/cge/jbw.h @@ -0,0 +1,149 @@ +#ifndef __JBW__ +#define __JBW__ + +#define BEL 7 +#define BS 8 +#define HT 9 +#define LF 10 +#define FF 12 +#define CR 13 + +#define NULL 0 +#define TRUE (1==1) +#define FALSE (!TRUE) +#define OFF FALSE +#define ON TRUE + +#define IsWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') +#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') +#define IsLower(c) ((c) >= 'a' && (c) <= 'z') +#define IsDigit(c) ((c) >= '0' && (c) <= '9') +#define IsAlpha(c) (IsLower(c) || IsUpper(c) || (c) == '_') +#define IsAlNum(c) (IsAlpha(c) || IsDigit(c)) +#define IsHxDig(c) (IsDigit(c) || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) + +#define farnew(t,n) ((t far *) farmalloc(sizeof(t) * (n))) +#define ArrayCount(a) (sizeof(a)/sizeof((a)[0])) +#define MAX_TIMER 0x1800B0L + +typedef unsigned char BYTE; +typedef unsigned int WORD; +typedef unsigned long DWORD; + +typedef int Boolean; +typedef unsigned char byte; +typedef unsigned int word; +typedef unsigned long dword; +typedef void (far _loadds MouseFunType)(void); + +#define Lo(d) (((int *) &d)[0]) +#define Hi(d) (((int *) &d)[1]) +#define LoWord(d) ((word) Lo(d)) +#define HiWord(d) ((word) Hi(d)) +#define K(n) (1024*(n)) +#define MASK(n) ((1<<n)-1) + +typedef enum + { + NoKey = 0, CtrlA, CtrlB, CtrlC, CtrlD, CtrlE, CtrlF, CtrlG, CtrlH, + CtrlI, CtrlJ, CtrlK, CtrlL, CtrlM, CtrlN, CtrlO, CtrlP, + CtrlQ, CtrlR, CtrlS, CtrlT, CtrlU, CtrlV, CtrlW, CtrlX, + CtrlY, CtrlZ, + BSp = 8, + Tab = 9, + Enter = 13, + Eof = 26, + Esc = 27, + AltQ = 256+16, AltW, AltE, AltR, AltT, AltY, AltU, AltI, AltO, AltP, + AltA = 256+30, AltS, AltD, AltF, AltG, AltH, AltJ, AltK, AltL, + AltZ = 256+44, AltX, AltC, AltV, AltB, AltN, AltM, + F11 = 256+87, F12, + F1 = 256+59, F2, F3, F4, F5, F6, F7, F8, F9, F10, + ShiftTab = 256+15, + ShiftF1 = 256+84, ShiftF2, ShiftF3, ShiftF4, ShiftF5, + ShiftF6, ShiftF7, ShiftF8, ShiftF9, ShiftF10, + CtrlF1 = 256+94, CtrlF2, CtrlF3, CtrlF4, CtrlF5, + CtrlF6, CtrlF7, CtrlF8, CtrlF9, CtrlF10, + AltF1 = 256+104, AltF2, AltF3, AltF4, AltF5, + AltF6, AltF7, AltF8, AltF9, AltF10, + Home = 256+71, + Up, + PgUp, + Left = 256+75, + Ctr, + Right, + End = 256+79, + Down, + PgDn, + Ins, + Del, + CtrlLeft = 256+115, + CtrlRight, + CtrlEnd, + CtrlPgDn, + CtrlHome, + CtrlPgUp = 256+132, + + MouseLeft = 512+1, + MouseRight, + TwiceLeft = 512+256+1, + TwiceRight + } Keys; + +struct KeyStatStruct + { + int RShift : 1; + int LShift : 1; + int Ctrl : 1; + int Alt : 1; + + int ScrollLock : 1; + int NumLock : 1; + int CapsLock : 1; + int Ins : 1; + + int LeftCtrl : 1; + int LeftAlt : 1; + int Unused : 6; + }; + +#define HGC_Cursor 0x0B0C +#define CGA_Cursor 0x0607 +#define OFF_Cursor 0x2000 + +#define TimerCount (* ((volatile long far *) ((void _seg *) 0x40 + (void near *) 0x6C))) +#define KeyStat (* ((volatile struct KeyStatStruct far *) ((void _seg *) 0x40 + (void near *) 0x17))) +#define BreakFlag (* ((volatile byte far *) ((void _seg *) 0x40 + (void near *) 0x71))) +#define PostFlag (* ((volatile word far *) ((void _seg *) 0x40 + (void near *) 0x72))) +#define POST ((void far (*)(void)) ((void _seg *) 0xF000 + (void near *) 0xFFF0)) +#define SLIF if (KeyStat.ScrollLock) + +#define FOR(i,n) for(i=0;i<(n);i++) + +#define TRAP(x) { if (x) asm { int 3 } } + +#ifdef DEBUG + #define Debug(x) x +#else + #define Debug(x) +#endif + +#ifdef DEMO + #define Demo(x) x +#else + #define Demo(x) +#endif + + +#ifdef __cplusplus + #define EC extern "C" +#else + #define EC +#endif + + +extern word _stklen; +extern word _heaplen; + + +#endif diff --git a/engines/cge/keybd.cpp b/engines/cge/keybd.cpp new file mode 100644 index 0000000000..9986ad0b5d --- /dev/null +++ b/engines/cge/keybd.cpp @@ -0,0 +1,114 @@ +#include "keybd.h" +#include "mouse.h" +#include <dos.h> + + +SPRITE * KEYBOARD::Client = NULL; +byte KEYBOARD::Key[0x60] = { 0 }; +word KEYBOARD::Current = 0; +word KEYBOARD::Code[0x60] = { 0,Esc,'1','2','3','4','5','6','7','8','9','0', + '-','+',BSp,Tab,'Q','W','E','R','T','Y','U', + 'I','O','P','[',']',Enter,0/*Ctrl*/,'A','S', + 'D','F','G','H','J','K','L',';','\'','`', + 0/*LShift*/,'\\','Z','X','C','V','B','N','M', + ',','.','/',0/*RShift*/,'*',0/*Alt*/,' ', + 0/*Caps*/,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10, + 0/*NumLock*/,0/*ScrollLock*/,Home,Up,PgUp, + '-',Left,Ctr,Right,'+',End,Down,PgDn,Ins,Del, + 0*0x54,0*0x55,0*0x56,F11,F12,0*0x59,0*0x5A, + 0*0x5B,0*0x5C,0*0x5D,0*0x5E,0*0x5F + }; +void interrupt (far * KEYBOARD::OldKeyboard) (...); + + + +KEYBOARD::KEYBOARD (void) +{ + // steal keyboard interrupt + OldKeyboard = getvect(KEYBD_INT); + setvect(KEYBD_INT, NewKeyboard); +} + + + + +KEYBOARD::~KEYBOARD (void) +{ + // bring back keyboard interrupt + setvect(KEYBD_INT, OldKeyboard); +} + + + + +SPRITE * KEYBOARD::SetClient (SPRITE * spr) +{ + Swap(Client, spr); + return spr; +} + + + + + +void interrupt KEYBOARD::NewKeyboard (...) +{ + // table address + _SI = (word) Key; + + // take keyboard code + asm in al,60h + asm mov bl,al + asm and bx,007Fh + asm cmp bl,60h + asm jae xit + asm cmp al,bl + asm je ok // key pressed + + // key released... + asm cmp [si+bx],bh // BH == 0 + asm jne ok + // ...but not pressed: call the original service + OldKeyboard(); + return; + + ok: + asm shl ax,1 + asm and ah,1 + asm xor ah,1 + asm mov [si+bx],ah + asm jz xit // released: exit + + // pressed: lock ASCII code + _SI = (word) Code; + asm add bx,bx // word size + asm mov ax,[si+bx] + asm or ax,ax + asm jz xit // zero means NO KEY + Current = _AX; + + _SI = (word) Client; + asm or si,si + asm jz xit // if (Client) ... +//--- fill current event entry with mask, key code and sprite + asm mov bx,EvtHead // take queue head pointer + asm inc byte ptr EvtHead // update queue head pointer + asm shl bx,3 // * 8 + _AX = Current; + asm mov Evt[bx].(struct EVENT)X,ax // key code + asm mov ax,KEYB // event mask + asm mov Evt[bx].(struct EVENT)Msk,ax // event mask + //asm mov Evt[bx].(struct EVENT)Y,dx // row + asm mov Evt[bx].(struct EVENT)Ptr,si // SPRITE pointer + + xit: + + asm in al,61h // kbd control lines + asm push ax // save it + asm or al,80h // set the "enable kbd" bit + asm out 61h,al // and write it out + asm pop ax // original control port value + asm out 61h,al // write it back + asm mov al,20h // send End-Of-Interrupt + asm out 20h,al // to the 8259 IC +} diff --git a/engines/cge/keybd.h b/engines/cge/keybd.h new file mode 100644 index 0000000000..744dc8c8ac --- /dev/null +++ b/engines/cge/keybd.h @@ -0,0 +1,31 @@ +#ifndef __KEYBD__ +#define __KEYBD__ + +#include <jbw.h> +#include "vga13h.h" + + +#define KEYBD_INT 9 +#define LSHIFT 42 +#define RSHIFT 54 +#define CTRL 29 +#define ALT 56 + + +class KEYBOARD +{ + static void interrupt (far * OldKeyboard) (...); + static void interrupt NewKeyboard (...); + static word Code[0x60]; + static word Current; + static SPRITE * Client; +public: + static byte Key[0x60]; + static word Last (void) { _AX = Current; Current = 0; return _AX; } + static SPRITE * SetClient (SPRITE * spr); + KEYBOARD (void); + ~KEYBOARD (void); +}; + + +#endif diff --git a/engines/cge/mixer.cpp b/engines/cge/mixer.cpp new file mode 100644 index 0000000000..7a494d0b90 --- /dev/null +++ b/engines/cge/mixer.cpp @@ -0,0 +1,129 @@ +#include "mixer.h" +#include "text.h" +#include "snail.h" +#include "mouse.h" +#include <snddrv.h> +#include <string.h> +#include <alloc.h> + +//-------------------------------------------------------------------------- + + +extern MOUSE Mouse; + + Boolean MIXER::Appear = FALSE; + + + +MIXER::MIXER (int x, int y) +: SPRITE(NULL), Fall(MIX_FALL) +{ + int i; + Appear = TRUE; + mb[0] = new BITMAP("VOLUME"); + mb[1] = NULL; + SetShapeList(mb); + SetName(Text[MIX_NAME]); + Flags.Syst = TRUE; + Flags.Kill = TRUE; + Flags.BDel = TRUE; + Goto(x, y); + Z = MIX_Z; + + // slaves + + for (i = 0; i < MIX_MAX; i ++) + { + static char fn[] = "V00"; + wtom(i, fn+1, 10, 2); + lb[i] = new BITMAP(fn); + ls[i].Now = ls[i].Next = i; + ls[i].Dx = ls[i].Dy = ls[i].Dly = 0; + } + lb[i] = NULL; + + for (i = 0; i < ArrayCount(Led); i ++) + { + register SPRITE * spr = new SPRITE(lb); + spr->SetSeq(ls); + spr->Goto(x+2+12*i, y+8); + spr->Flags.Tran = TRUE; + spr->Flags.Kill = TRUE; + spr->Flags.BDel = FALSE; + spr->Z = MIX_Z; + Led[i] = spr; + } + Led[ArrayCount(Led)-1]->Flags.BDel = TRUE; + + VGA::ShowQ.Insert(this); + for (i = 0; i < ArrayCount(Led); i ++) VGA::ShowQ.Insert(Led[i]); + + //--- reset balance + i = (SNDDrvInfo.VOL4.ML + SNDDrvInfo.VOL4.MR) / 2; + SNDDrvInfo.VOL4.ML = i; + SNDDrvInfo.VOL4.MR = i; + i = (SNDDrvInfo.VOL4.DL + SNDDrvInfo.VOL4.DR) / 2; + SNDDrvInfo.VOL4.DL = i; + SNDDrvInfo.VOL4.DR = i; + Update(); + Time = MIX_DELAY; +} + + + + +MIXER::~MIXER (void) +{ + Appear = FALSE; +} + + + +#pragma argsused +void MIXER::Touch (word mask, int x, int y) +{ + SPRITE::Touch(mask, x, y); + if (mask & L_UP) + { + byte * vol = (&SNDDrvInfo.VOL2.D) + (x < W/2); + if (y < MIX_BHIG) { if (*vol < 0xFF) *vol += 0x11; } + else if (y >= H-MIX_BHIG) { if (*vol > 0x00) *vol -= 0x11; } + Update(); + } +} + + + +void MIXER::Tick (void) +{ + int x = Mouse.X, y = Mouse.Y; + if (SpriteAt(x, y) == this) + { + Fall = MIX_FALL; + if (Flags.Hold) Touch(L_UP, x-X, y-Y); + } + else + { + if (Fall) -- Fall; + else + { + int i; + for (i = 0; i < ArrayCount(Led); i ++) + { + SNPOST_(SNKILL, -1, 0, Led[i]); + } + SNPOST_(SNKILL, -1, 0, this); + } + } + Time = MIX_DELAY; +} + + + + +void MIXER::Update (void) +{ + Led[0]->Step(SNDDrvInfo.VOL4.ML); + Led[1]->Step(SNDDrvInfo.VOL4.DL); + SNPOST_(SNEXEC, -1, 0, SNDSetVolume); +} diff --git a/engines/cge/mixer.h b/engines/cge/mixer.h new file mode 100644 index 0000000000..8ee2bb6f80 --- /dev/null +++ b/engines/cge/mixer.h @@ -0,0 +1,31 @@ +#ifndef __MIXER__ +#define __MIXER__ + +#include "vga13h.h" + +#define MIX_MAX 16 // count of Leds +#define MIX_Z 64 // mixer Z position +#define MIX_DELAY 12 // 6/s +#define MIX_FALL 6 // in MIX_DELAY units +#define MIX_BHIG 6 // mixer button high +#define MIX_NAME 105 // sprite name + +class MIXER : public SPRITE +{ + BMP_PTR mb[2]; + BMP_PTR lb[MIX_MAX+1]; + SEQ ls[MIX_MAX]; + SPRITE * Led[2]; + int Fall; + void Update (void); +public: + static Boolean Appear; + MIXER (int x, int y); + ~MIXER (void); + void Touch (word mask, int x, int y); + void Tick (void); +}; + + + +#endif diff --git a/engines/cge/module.mk b/engines/cge/module.mk index 62ddd9d362..7424c8bc38 100644 --- a/engines/cge/module.mk +++ b/engines/cge/module.mk @@ -1,9 +1,26 @@ MODULE := engines/cge MODULE_OBJS := \ + bitmap.o \ + bitmaps.o \ + cfile.o \ cge.o \ + cge_main.o \ console.o \ - detection.o + detection.o \ + game.o \ + gettext.o \ + keybd.o \ + mixer.o \ + mouse.o \ + snail.o \ + sound.o \ + startup.o \ + talk.o \ + text.o \ + vga13h.o \ + vmenu.o \ + vol.o MODULE_DIRS += \ engines/cge diff --git a/engines/cge/mouse.cpp b/engines/cge/mouse.cpp new file mode 100644 index 0000000000..703fd80f65 --- /dev/null +++ b/engines/cge/mouse.cpp @@ -0,0 +1,207 @@ +#include "mouse.h" +#include "text.h" +#include <dos.h> + + + + EVENT Evt[EVT_MAX]; + + word EvtHead = 0, EvtTail = 0; +//-------------------------------------------------------------------------- + +MOUSE_FUN * MOUSE::OldMouseFun = NULL; +word MOUSE::OldMouseMask = 0; + + + +//-------------------------------------------------------------------------- + + + + + +MOUSE::MOUSE (BITMAP ** shpl) + : SPRITE(shpl), Busy(NULL), Hold(NULL), hx(0) +{ + static SEQ ms[] = { { 0,0,0,0,1 }, { 1,1,0,0,1 } }; + SetSeq(ms); + + // Mouse reset + _AX = 0x0000; // soft & hard reset (0x0021 soft reset does not work) + __int__(0x33); + Exist = (_AX != 0); + Buttons = _BX; + + Goto(SCR_WID/2, SCR_HIG/2); + Z = 127; + Step(1); +} + + + + +MOUSE::~MOUSE (void) +{ + Off(); +} + + + + + +//void MOUSE::SetFun (void) +//{ +//} + + + + + +void MOUSE::On (void) +{ + if (SeqPtr && Exist) + { + _CX = X + X; // horizontal position + _DX = Y; // vertical position + _AX = 0x0004; // Set Mouse Position + __int__(0x33); + // set new mouse fun + _ES = FP_SEG(NewMouseFun); + _DX = FP_OFF(NewMouseFun); + _CX = 0x001F; // 11111b = all events + _AX = 0x0014; // Swap User-Interrupt Vector + __int__(0x33); + // save old mouse fun + OldMouseMask = _CX; + OldMouseFun = (MOUSE_FUN *) MK_FP(_ES, _DX); + + // set X bounds + _DX = (SCR_WID - W) * 2; // right limit + _CX = 0; // left limit + _AX = 0x0007; // note: each pixel = 2 + __int__(0x33); + + // set Y bounds + _DX = SCR_HIG - H; // bottom limit + _CX = 0; // top limit + _AX = 0x0008; + __int__(0x33); + + Step(0); + if (Busy) Busy->Step(0); + } +} + + + + + + +void MOUSE::Off (void) +{ + if (SeqPtr == 0) + { + if (Exist) + { + // bring back old mouse fun + _ES = FP_SEG(OldMouseFun); + _DX = FP_OFF(OldMouseFun); + _CX = OldMouseMask; + _AX = 0x0014; // Swap User-Interrupt Vector + __int__(0x33); + } + Step(1); + if (Busy) Busy->Step(1); + } +} + + + + + + +void MOUSE::ClrEvt (SPRITE * spr) +{ + if (spr) + { + word e; + for (e = EvtTail; e != EvtHead; e = (e + 1) % EVT_MAX) + if (Evt[e].Ptr == spr) Evt[e].Msk = 0; + } + else EvtTail = EvtHead; +} + + + + + + +void MOUSE::Tick (void) +{ + Step(); + while (EvtTail != EvtHead) + { + EVENT e = Evt[EvtTail]; + if (e.Msk) + { + if (Hold && e.Ptr != Hold) + { + Hold->Touch(e.Msk | ATTN, e.X - Hold->X, e.Y - Hold->Y); + } + + // update mouse cursor position + if (e.Msk & ROLL) + { + Goto(e.X, e.Y); + } + + // activate current touched SPRITE + if (e.Ptr) + { + if (e.Msk & KEYB) e.Ptr->Touch(e.Msk, e.X, e.Y); + else e.Ptr->Touch(e.Msk, e.X - e.Ptr->X, e.Y - e.Ptr->Y); + } + else if (Sys) Sys->Touch(e.Msk, e.X, e.Y); + + if (e.Msk & L_DN) + { + Hold = e.Ptr; + if (Hold) + { + Hold->Flags.Hold = TRUE; + #ifndef DEBUG + if (Hold->Flags.Drag) + #endif + { + hx = e.X - Hold->X; + hy = e.Y - Hold->Y; + } + } + } + + if (e.Msk & L_UP) + { + if (Hold) + { + Hold->Flags.Hold = FALSE; + Hold = NULL; + } + } + ///Touched = e.Ptr; + + // discard Text if button released + if (e.Msk & (L_UP | R_UP)) KillText(); + } + EvtTail = (EvtTail + 1) % EVT_MAX; + } + if (Hold) + #ifndef DEBUG + if (Hold->Flags.Drag) + #endif + Hold->Goto(X-hx, Y-hy); +} + + + +//-------------------------------------------------------------------------- + diff --git a/engines/cge/mouse.h b/engines/cge/mouse.h new file mode 100644 index 0000000000..9f51456baf --- /dev/null +++ b/engines/cge/mouse.h @@ -0,0 +1,58 @@ +#ifndef __MOUSE__ +#define __MOUSE__ + +#include "game.h" +#include "talk.h" + +#define EVT_MAX 256 + +#define ROLL 0x01 +#define L_DN 0x02 +#define L_UP 0x04 +#define R_DN 0x08 +#define R_UP 0x10 +#define ATTN 0x20 +// 0x40 +#define KEYB 0x80 + + +extern TALK * Talk; + +struct EVENT { word Msk; + word X, Y; + SPRITE * Ptr; + }; +extern EVENT Evt[EVT_MAX]; +extern word EvtHead, EvtTail; +typedef void (far MOUSE_FUN) (void); + + + + + +class MOUSE : public SPRITE +{ + static MOUSE_FUN * OldMouseFun; + static MOUSE_FUN NewMouseFun; + static word OldMouseMask; + SPRITE * Hold; + int hx, hy; + //void SetFun (void); + //void ResetFun (void); +public: + Boolean Exist; + int Buttons; + SPRITE * Busy; + //SPRITE * Touched; + MOUSE (BITMAP ** shpl = MC); + ~MOUSE (void); + void On (void); + void Off (void); + static void ClrEvt (SPRITE * spr = NULL); + void Tick (void); +}; + + + + +#endif diff --git a/engines/cge/snail.cpp b/engines/cge/snail.cpp new file mode 100644 index 0000000000..d6b2528310 --- /dev/null +++ b/engines/cge/snail.cpp @@ -0,0 +1,1280 @@ +#include <general.h> +#include "sound.h" +#include "snail.h" +#include "vga13h.h" +#include "bitmaps.h" +#include "text.h" +#include "mouse.h" +#include "cge.h" +#include <dos.h> +#include <alloc.h> +#include <mem.h> +#include <stdio.h> +#include <stdlib.h> + +#include "keybd.h" + + int MaxCave = 0; + + SCB Scb = { NULL, 0, NULL }; + Boolean Flag[4]; + Boolean Dark = FALSE; + Boolean Game = FALSE; + int Now = 1; + int Lev = -1; + SNAIL Snail = FALSE; + SNAIL Snail_ = TRUE; + +extern SPRITE PocLight; + +//------------------------------------------------------------------------- +// SPRITE * Pocket[POCKET_NX]={ NULL, NULL, NULL, NULL, +// NULL, NULL, NULL, NULL, }; +// int PocPtr = 0; +//------------------------------------------------------------------------- +extern SPRITE * Pocket[]; +extern int PocPtr; +//------------------------------------------------------------------------- + +extern DAC far * SysPal; +extern MOUSE Mouse; + + + +//------------------------------------------------------------------------- + + +static void SNGame (SPRITE * spr, int num) +{ + switch (num) + { + //-------------------------------------------------------------------- + case 1 : + { + #define STAGES 8 + #define DRESSED 3 + static SPRITE * dup[3] = { NULL, NULL, NULL }; + int buref; + int Stage; + + for (dup[0] = VGA::ShowQ.First(); dup[0]; dup[0] = dup[0]->Next) + { + buref = dup[0]->Ref; + if (buref / 1000 == 16 && buref % 100 == 6) + { + Stage = (buref / 100) % 10; + break; + } + } + if (dup[1] == NULL) + { + dup[1] = VGA::ShowQ.Locate(16003); // pan + dup[2] = VGA::ShowQ.Locate(16004); // pani + } + + if (Game) // continue game + { + int i = random(3), hand = (dup[0]->ShpCnt == 6); + ++ Stage; + if (hand && Stage > DRESSED) ++ hand; + if ( + Debug( i >= 0 || ) + dup[i] == spr && random(3) == 0) + { + SNPOST(SNSEQ, -1, 3, dup[0]); // yes + SNPOST(SNSEQ, -1, 3, dup[1]); // yes + SNPOST(SNSEQ, -1, 3, dup[2]); // yes + SNPOST(SNTNEXT, -1, 0, dup[0]); // reset Take + SNPOST(SNTNEXT, -1, 0, dup[1]); // reset Take + SNPOST(SNTNEXT, -1, 0, dup[2]); // reset Take + SNPOST(SNNNEXT, -1, 0, dup[0]); // reset Near + SNPOST(SNPAUSE, -1, 72, NULL); // little rest + SNPOST(SNSAY, 1, 16009, NULL); // hura + SNPOST(SNSAY, buref, 16010, NULL); // siadaj + SNPOST(SNSAY, 1, 16011, NULL); // postoj‘ + + if (hand) + { + SNPOST(SNSEND, 16060+hand, 16, NULL); // dawaj r‘k‘ + SNPOST(SNSEQ, buref, 4, NULL); // zdejmowanie + SNPOST(SNSEQ, 16060+hand, 1, NULL); // ruch + SNPOST(SNSOUND, 16060+hand, 16002, NULL); // szelest + SNPOST(SNWAIT, 16060+hand, 3, NULL); // podniesie + SNPOST(SNSWAP, buref, buref+100, NULL); // rozdziana + SNPOST(SNSEQ, 16016, Stage, NULL); // rožnie kupa + SNPOST(SNSEND, 16060+hand, -1, NULL); // chowaj r‘k‘ + SNPOST(SNWAIT, 16060+hand, -1, NULL); // r‘ka zamar’a + } + else + { + SNPOST(SNSEQ, buref, 4, NULL); // zdejmowanie + SNPOST(SNSOUND, 16060+hand, 16002, NULL); // szelest + SNPOST(SNWAIT, buref, -1, NULL); // zdejmie + SNPOST(SNSWAP, buref, buref+100, NULL); // rozdziana + SNPOST(SNSEQ, 16016, Stage, NULL); // rožnie kupa + } + //SNPOST(SNSEQ, buref+100, 0, NULL); // reset + SNPOST(SNPAUSE, -1, 72, NULL); // chwilk‘... + + SNPOST(SNSEQ, -1, 0, dup[1]); // odstaw Go + SNPOST(SNSETXY, -1, 203 + SCR_WID * 49, dup[1]); + SNPOST(SNSETZ, -1, 7, dup[1]); + + SNPOST(SNSEQ, -1, 0, dup[2]); // odstaw J† + SNPOST(SNSETXY, -1, 182 + SCR_WID * 62, dup[2]); + SNPOST(SNSETZ, -1, 9, dup[2]); + Game = 0; + return; + } + else + { + SNPOST(SNSEQ, -1, 2, dup[0]); // no + SNPOST(SNSEQ, -1, 2, dup[1]); // no + SNPOST(SNSEQ, -1, 2, dup[2]); // no + SNPOST(SNPAUSE, -1, 72, NULL); // 1 sec + } + } + SNPOST(SNWALK, 198, 134, NULL); // na miejsce + SNPOST(SNWAIT, 1, -1, NULL); // stoi + SNPOST(SNCOVER, 1, 16101, NULL); // ch’op do bicia + SNPOST(SNSEQ, 16101, 1, NULL); // wystaw + SNPOST(SNWAIT, 16101, 5, NULL); // czekaj + SNPOST(SNPAUSE, 16101, 24, NULL); // czekaj chwil‘ + SNPOST(SNSEQ, 16040, 1, NULL); // plask + SNPOST(SNSOUND, 16101, 16001, NULL); // plask! + SNPOST(SNPAUSE, 16101, 24, NULL); // czekaj chwil‘ + SNPOST(SNSEQ, 16040, 0, NULL); // schowaj plask + SNPOST(SNWAIT, 16101, -1, NULL); // stoi + SNPOST(SNUNCOVER, 1, 16101, NULL); // SDS + if (! Game) + { + SNPOST(SNSAY, buref, 16008, NULL); // zgadnij! + Game = TRUE; + } + #undef STEPS + #undef DRESSED + } break; + //-------------------------------------------------------------------- + case 2 : + { + static SPRITE * k = NULL, * k1, * k2, * k3; + static int count = 0; + Boolean hit; + + if (k == NULL) + { + k = VGA::ShowQ.Locate(20700); + k1 = VGA::ShowQ.Locate(20701); + k2 = VGA::ShowQ.Locate(20702); + k3 = VGA::ShowQ.Locate(20703); + } + + if (! Game) // init + { + SNPOST(SNGAME, 20002, 2, NULL); + Game = TRUE; + } + else // cont + { + k1->Step(random(6)); + k2->Step(random(6)); + k3->Step(random(6)); + ///-------------------- + if (spr->Ref == 1 && KEYBOARD::Key[ALT]) + { + k1->Step(5); + k2->Step(5); + k3->Step(5); + } + ///-------------------- + SNPOST(SNSETZ, 20700, 0, NULL); + hit = (k1->SeqPtr + k2->SeqPtr + k3->SeqPtr == 15); + if (hit) + { + if (spr->Ref == 1) + { + SNPOST(SNSAY, 1, 20003, NULL); // hura! + SNPOST(SNSEQ, 20011, 2, NULL); // kamera won + SNPOST(SNSEND, 20701, -1, NULL); // k1 won + SNPOST(SNSEND, 20702, -1, NULL); // k2 won + SNPOST(SNSEND, 20703, -1, NULL); // k3 won + SNPOST(SNSEND, 20700, -1, NULL); // tv won + SNPOST(SNKEEP, 20007, 0, NULL); // do kieszeni + SNPOST(SNSEND, 20006, 20, NULL); // bilon + SNPOST(SNSOUND,20006, 20002, NULL); // bilon! + SNPOST(SNSAY, 20002, 20004, NULL); + SNPOST(SNSEND, 20010, 20, NULL); // papier + SNPOST(SNSOUND,20010, 20003, NULL); // papier! + SNPOST(SNSAY, 20001, 20005, NULL); + Game = FALSE; + return; + } + else k3->Step(random(5)); + } + if (count < 100) + { + switch (count) + { + case 15 : SNPOST(SNSAY, 20003, 20021, NULL); break; + case 30 : + case 45 : + case 60 : + case 75 : SNPOST(SNSAY, 20003, 20022, NULL); break; + } + ++ count; + } + switch (spr->Ref) + { + case 1 : SNPOST(SNSAY, 20001, 20011, NULL); // zapro + SNPOST(SNSEQ, 20001, 1, NULL); // rzu + SNPOST(SNWAIT, 20001, 1, NULL); // czekaj + SNPOST(SNSETZ, 20700, 2, NULL); // skryj k + SNPOST(SNHIDE, 20007, 1, NULL); // skryj k + SNPOST(SNWAIT, 20001, 16, NULL); // czekaj + SNPOST(SNSEQ, 20007, 1, NULL); // lec† + SNPOST(SNHIDE, 20007, 0, NULL); // poka§ + SNPOST(SNSOUND,20007, 20001, NULL); // grzech + SNPOST(SNWAIT, 20007, -1, NULL); // koniec + SNPOST(SNGAME, 20001, 2, NULL); // again! + break; + case 20001 : SNPOST(SNSAY, 20002, 20012, NULL); // zapro + SNPOST(SNSEQ, 20002, 1, NULL); // rzu + SNPOST(SNWAIT, 20002, 3, NULL); // czekaj + SNPOST(SNSETZ, 20700, 2, NULL); // skryj k + SNPOST(SNHIDE, 20007, 1, NULL); // skryj k + SNPOST(SNWAIT, 20002, 10, NULL); // czekaj + SNPOST(SNSEQ, 20007, 2, NULL); // lec† + SNPOST(SNHIDE, 20007, 0, NULL); // poka§ + SNPOST(SNSOUND,20007, 20001, NULL); // grzech + SNPOST(SNWAIT, 20007, -1, NULL); // koniec + SNPOST(SNGAME, 20002, 2, NULL); // again! + break; + case 20002 : SNPOST(SNSAY, 20002, 20010, NULL); // zapro + SNPOST(SNWALK, 20005, -1, NULL); // do stol + SNPOST(SNWAIT, 1, -1, NULL); // stoi + SNPOST(SNCOVER, 1, 20101, NULL); // grasol + SNPOST(SNSEQ, 20101, 1, NULL); // rzu + SNPOST(SNWAIT, 20101, 5, NULL); // czekaj + SNPOST(SNSETZ, 20700, 2, NULL); // skryj k + SNPOST(SNHIDE, 20007, 1, NULL); // skryj k + SNPOST(SNWAIT, 20101, 15, NULL); // czekaj + SNPOST(SNSEQ, 20007, 1, NULL); // lec† + SNPOST(SNHIDE, 20007, 0, NULL); // poka§ + SNPOST(SNSOUND,20007, 20001, NULL); // grzech + SNPOST(SNWAIT, 20101, -1, NULL); // koniec + SNPOST(SNUNCOVER, 1, 20101, NULL); // SDS + SNPOST(SNGAME, 1, 2, NULL); // again! + break; + } + } + } break; + //-------------------------------------------------------------------- + } +} + + +//------------------------------------------------------------------------- + + + + +void ExpandSprite (SPRITE * spr) +{ + if (spr) VGA::ShowQ.Insert(VGA::SpareQ.Remove(spr)); +} + + + + + +void ContractSprite (SPRITE * spr) +{ + if (spr) VGA::SpareQ.Append(VGA::ShowQ.Remove(spr)); +} + + + + + + + +int FindPocket (SPRITE * spr) +{ + int i; + for (i = 0; i < POCKET_NX; i ++) if (Pocket[i] == spr) return i; + return -1; +} + + + + + +void SelectPocket (int n) +{ + if (n < 0 || (PocLight.SeqPtr && PocPtr == n)) + { + PocLight.Step(0); + n = FindPocket(NULL); + if (n >= 0) PocPtr = n; + } + else + { + if (Pocket[n] != NULL) + { + PocPtr = n; + PocLight.Step(1); + } + } + PocLight.Goto(POCKET_X+PocPtr*POCKET_DX+POCKET_SX, POCKET_Y+POCKET_SY); +} + + + + + +void PocFul (void) +{ + Hero->Park(); + SNPOST(SNWAIT, -1, -1, Hero); + SNPOST(SNSEQ, -1, POC_FUL, Hero); + SNPOST(SNSOUND, -1, 2, Hero); + SNPOST(SNWAIT, -1, -1, Hero); + SNPOST(SNSAY, 1, POC_FUL_TEXT, Hero); +} + + + + +void Hide1 (SPRITE * spr) +{ + SNPOST_(SNGHOST, -1, 0, spr->Ghost()); +} + + + + +void SNGhost (BITMAP * bmp) +{ + bmp->Hide(FP_OFF(bmp->M), FP_SEG(bmp->M)); + bmp->M = NULL; + delete bmp; +} + + + + +void FeedSnail (SPRITE * spr, SNLIST snq) +{ + if (spr) if (spr->Active()) + { + byte ptr = (snq == TAKE) ? spr->TakePtr : spr->NearPtr; + + if (ptr != NO_PTR) + { + SNAIL::COM * comtab = spr->SnList(snq); + SNAIL::COM * c = comtab + ptr; + + if (FindPocket(NULL) < 0) // no empty pockets? + { + SNAIL::COM * p; + for (p = c; p->Com != SNNEXT; p ++) // find KEEP command + { + if (p->Com == SNKEEP) + { + PocFul(); + return; + } + if (p->Ptr) break; + } + } + while (TRUE) + { + if (c->Com == SNTALK) + { + if ((Snail.TalkEnable = (c->Val != 0)) == FALSE) KillText(); + } + if (c->Com == SNNEXT) + { + SPRITE * s = (c->Ref < 0) ? spr : Locate(c->Ref); + if (s) + { + byte * idx = (snq == TAKE) ? &s->TakePtr : &s->NearPtr; + if (*idx != NO_PTR) + { + int v; + switch (c->Val) + { + case -1 : v = c - comtab + 1; break; + case -2 : v = c - comtab; break; + case -3 : v = -1; break; + default : v = c->Val; break; + } + if (v >= 0) *idx = v; + } + } + if (s == spr) break; + } + if (c->Com == SNIF) + { + SPRITE * s = (c->Ref < 0) ? spr : Locate(c->Ref); + if (s) // sprite extsts + { + if (! s->SeqTest(-1)) c = comtab + c->Val; // not parked + else ++ c; + } + else ++ c; + } + else + { + SNPOST(c->Com, c->Ref, c->Val, spr); + if (c->Ptr) break; + else ++ c; + } + } + } + } +} + + + + + + +//-------------------------------------------------------------------------- + +char * SNAIL::ComTxt[] = { "LABEL", "PAUSE", "WAIT", "LEVEL", + "HIDE", "SAY", "INF", "TIME", + "CAVE", "KILL", "RSEQ", + "SEQ", "SEND", "SWAP", "KEEP", "GIVE", + "IF", "GAME", "SETX0", "SETY0", "SLAVE", + "SETXY", "RELX", "RELY", "RELZ", + "SETX", "SETY", "SETZ", "TRANS", "PORT", + "NEXT","NNEXT", "TNEXT", "RNNEXT", "RTNEXT", + "RMNEAR", "RMTAKE", "FLAG", "SETREF", + "BACKPT", "FLASH", "LIGHT", + "SETHB", "SETVB", + "WALK", "REACH", "COVER", "UNCOVER", + "CLEAR", "TALK", "MOUSE", + "SOUND", "COUNT", + NULL }; + + + +SNAIL::SNAIL (Boolean turbo) +: Turbo(turbo), Busy(FALSE), TextDelay(FALSE), + Pause(0), TalkEnable(TRUE), + Head(0), Tail(0), SNList(farnew(COM, 256)) +{ +} + + + + + + +SNAIL::~SNAIL (void) +{ + if (SNList) farfree(SNList); +} + + + + + + +void SNAIL::AddCom (SNCOM com, int ref, int val, void * ptr) +{ + _disable(); + COM far * snc = &SNList[Head ++]; + snc->Com = com; + snc->Ref = ref; + snc->Val = val; + snc->Ptr = ptr; + if (com == SNCLEAR) + { + Tail = Head; + KillText(); + Pause = 0; + } + _enable(); +} + + + + +void SNAIL::InsCom (SNCOM com, int ref, int val, void * ptr) +{ + COM far * snc; + + _disable(); + if (Busy) + { + SNList[(Tail-1)&0xFF] = SNList[Tail]; + snc = &SNList[Tail]; + } + else snc = &SNList[(Tail-1)&0xFF]; + -- Tail; + snc->Com = com; + snc->Ref = ref; + snc->Val = val; + snc->Ptr = ptr; + if (com == SNCLEAR) + { + Tail = Head; + KillText(); + Pause = 0; + } + _enable(); +} + + + + + + + +static void SNNNext(SPRITE * sprel, int p) +{ + if (sprel) if (sprel->NearPtr != NO_PTR) sprel->NearPtr = p; +} + + + + + + +static void SNTNext(SPRITE * sprel, int p) +{ + if (sprel) if (sprel->TakePtr != NO_PTR) sprel->TakePtr = p; +} + + + + + + +static void SNRNNext(SPRITE * sprel, int p) +{ + if (sprel) if (sprel->NearPtr != NO_PTR) sprel->NearPtr += p; +} + + + + + + +static void SNRTNext(SPRITE * sprel, int p) +{ + if (sprel) if (sprel->TakePtr != NO_PTR) sprel->TakePtr += p; +} + + + + + + +static void SNZTrim (SPRITE * spr) +{ + if (spr) if (spr->Active()) + { + Boolean en = HEART::Enable; + SPRITE * s; + HEART::Enable = FALSE; + s = (spr->Flags.Shad) ? spr->Prev : NULL; + VGA::ShowQ.Insert(VGA::ShowQ.Remove(spr)); + if (s) + { + s->Z = spr->Z; + VGA::ShowQ.Insert(VGA::ShowQ.Remove(s), spr); + } + HEART::Enable = en; + } +} + + + + + + +static void SNHide (SPRITE * spr, int val) +{ + if (spr) + { + spr->Flags.Hide = (val >= 0) ? (val != 0) : (! spr->Flags.Hide); + if (spr->Flags.Shad) spr->Prev->Flags.Hide = spr->Flags.Hide; + } +} + + + + + +static void SNRmNear (SPRITE * spr) +{ + if (spr) spr->NearPtr = NO_PTR; +} + + + + + +static void SNRmTake (SPRITE * spr) +{ + if (spr) spr->TakePtr = NO_PTR; +} + + + + + +void SNSeq (SPRITE * spr, int val) +{ + if (spr) + { + if (spr == Hero && val == 0) Hero->Park(); + else spr->Step(val); + } +} + + + + + +void SNRSeq (SPRITE * spr, int val) +{ + if (spr) SNSeq(spr, spr->SeqPtr + val); +} + + + + + +void SNSend (SPRITE * spr, int val) +{ + if (spr) + { + int was = spr->Cave; + Boolean was1 = (was == 0 || was == Now); + Boolean val1 = (val == 0 || val == Now); + spr->Cave = val; + if (val1 != was1) + { + if (was1) + { + if (spr->Flags.Kept) + { + int n = FindPocket(spr); + if (n >= 0) Pocket[n] = NULL; + } + Hide1(spr); + ContractSprite(spr); + spr->Flags.Slav = FALSE; + } + else + { + if (spr->Ref % 1000 == 0) BITMAP::Pal = SysPal; + if (spr->Flags.Back) spr->BackShow(TRUE); + else ExpandSprite(spr); + BITMAP::Pal = NULL; + } + } + } +} + + + + + +void SNSwap (SPRITE * spr, int xref) +{ + SPRITE * xspr = Locate(xref); + if (spr && xspr) + { + int was = spr->Cave; + int xwas = xspr->Cave; + Boolean was1 = (was == 0 || was == Now); + Boolean xwas1 = (xwas == 0 || xwas == Now); + + Swap(spr->Cave, xspr->Cave); + Swap(spr->X, xspr->X); + Swap(spr->Y, xspr->Y); + Swap(spr->Z, xspr->Z); + if (spr->Flags.Kept) + { + int n = FindPocket(spr); + if (n >= 0) Pocket[n] = xspr; + xspr->Flags.Kept = TRUE; + xspr->Flags.Port = FALSE; + } + if (xwas1 != was1) + { + if (was1) + { + Hide1(spr); + ContractSprite(spr); + } + else ExpandSprite(spr); + if (xwas1) + { + Hide1(xspr); + ContractSprite(xspr); + } + else ExpandSprite(xspr); + } + } +} + + + + + +void SNCover (SPRITE * spr, int xref) +{ + SPRITE * xspr = Locate(xref); + if (spr && xspr) + { + spr->Flags.Hide = TRUE; + xspr->Z = spr->Z; + xspr->Cave = spr->Cave; + xspr->Goto(spr->X, spr->Y); + ExpandSprite(xspr); + if ((xspr->Flags.Shad = spr->Flags.Shad) == TRUE) + { + VGA::ShowQ.Insert(VGA::ShowQ.Remove(spr->Prev), xspr); + spr->Flags.Shad = FALSE; + } + FeedSnail(xspr, NEAR); + } +} + + + + + +void SNUncover (SPRITE * spr, SPRITE * xspr) +{ + if (spr && xspr) + { + spr->Flags.Hide = FALSE; + spr->Cave = xspr->Cave; + spr->Goto(xspr->X, xspr->Y); + if ((spr->Flags.Shad = xspr->Flags.Shad) == TRUE) + { + VGA::ShowQ.Insert(VGA::ShowQ.Remove(xspr->Prev), spr); + xspr->Flags.Shad = FALSE; + } + spr->Z = xspr->Z; + SNSend(xspr, -1); + if (spr->Time == 0) ++ spr->Time; + } +} + + + + + +void SNSetX0 (int cav, int x0) +{ + HeroXY[cav-1].X = x0; +} + + + + + +void SNSetY0 (int cav, int y0) +{ + HeroXY[cav-1].Y = y0; +} + + + + + +void SNSetXY (SPRITE * spr, word xy) +{ + if (spr) + { + spr->Goto(xy % SCR_WID, xy / SCR_WID); + } +} + + + + + +void SNRelX (SPRITE * spr, int x) +{ + if (spr && Hero) + { + spr->Goto(Hero->X + x, spr->Y); + } +} + + + + + +void SNRelY (SPRITE * spr, int y) +{ + if (spr && Hero) + { + spr->Goto(spr->X, Hero->Y + y); + } +} + + + + + +void SNRelZ (SPRITE * spr, int z) +{ + if (spr && Hero) + { + spr->Z = Hero->Z + z; + SNZTrim(spr); + } +} + + + + + +void SNSetX (SPRITE * spr, int x) +{ + if (spr) + { + spr->Goto(x, spr->Y); + } +} + + + + + +void SNSetY (SPRITE * spr, int y) +{ + if (spr) + { + spr->Goto(spr->X, y); + } +} + + + + + +void SNSetZ (SPRITE * spr, int z) +{ + if (spr) + { + spr->Z = z; + //SNPOST_(SNZTRIM, -1, 0, spr); + SNZTrim(spr); + } +} + + + + + +void SNSlave (SPRITE * spr, int ref) +{ + SPRITE * slv = Locate(ref); + if (spr && slv) + { + if (spr->Active()) + { + SNSend(slv, spr->Cave); + slv->Flags.Slav = TRUE; + slv->Z = spr->Z; + VGA::ShowQ.Insert(VGA::ShowQ.Remove(slv), spr->Next); + } + } +} + + + + + +void SNTrans (SPRITE * spr, int trans) +{ + if (spr) + { + spr->Flags.Tran = (trans < 0) ? !spr->Flags.Tran : (trans != 0); + } +} + + + + + +void SNPort (SPRITE * spr, int port) +{ + if (spr) + { + spr->Flags.Port = (port < 0) ? !spr->Flags.Port : (port != 0); + } +} + + + + + +void SNKill (SPRITE * spr) +{ + if (spr) + { + if (spr->Flags.Kept) + { + int n = FindPocket(spr); + if (n >= 0) Pocket[n] = NULL; + } + SPRITE * nx = spr->Next; + Hide1(spr); + VGA::ShowQ.Remove(spr); + MOUSE::ClrEvt(spr); + if (spr->Flags.Kill) delete spr; + else + { + spr->Cave = -1; + VGA::SpareQ.Append(spr); + } + if (nx) if (nx->Flags.Slav) SNKill(nx); + } +} + + + + + +static void SNSound (SPRITE * spr, int wav, int cnt) +{ + if (SNDDrvInfo.DDEV) + { + if (wav == -1) Sound.Stop(); + else + Sound.Play(Fx[wav], (spr) ? ((spr->X+spr->W/2)/(SCR_WID/16)) : 8, cnt); + } +} + + + + + +void SNKeep (SPRITE * spr, int stp) +{ + SelectPocket(-1); + if (spr && ! spr->Flags.Kept && Pocket[PocPtr] == NULL) + { + SNSound(spr, 3, 1); + Pocket[PocPtr] = spr; + spr->Cave = 0; + spr->Flags.Kept = TRUE; + spr->Goto(POCKET_X + POCKET_DX*PocPtr + POCKET_DX/2 - spr->W/2, + POCKET_Y + POCKET_DY/2 - spr->H/2); + if (stp >= 0) spr->Step(stp); + } + SelectPocket(-1); +} + + + + + + +void SNGive (SPRITE * spr, int stp) +{ + if (spr) + { + int p = FindPocket(spr); + if (p >= 0) + { + Pocket[p] = NULL; + spr->Cave = Now; + spr->Flags.Kept = FALSE; + if (stp >= 0) spr->Step(stp); + } + } + SelectPocket(-1); +} + + + + +static void SNBackPt (SPRITE * spr, int stp) +{ + if (spr) + { + if (stp >= 0) spr->Step(stp); + spr->BackShow(TRUE); + } +} + + + + + +static void SNLevel (SPRITE * spr, int lev) +{ + #ifdef DEMO + static int maxcav[] = { CAVE_MAX }; + #else + static int maxcav[] = { 1, 8, 16, 23, 24 }; + #endif + while (Lev < lev) + { + SPRITE * spr; + ++ Lev; + spr = VGA::SpareQ.Locate(100+Lev); + if (spr) + { + spr->BackShow(TRUE); + spr->Cave = 0; + } + } + MaxCave = maxcav[Lev]; + if (spr) spr->Flags.Hide = FALSE; +} + + + + + + +static void SNFlag (int fn, Boolean v) +{ + Flag[fn] = v; +} + + + + + + +static void SNSetRef (SPRITE * spr, int nr) +{ + if (spr) + { + spr->Ref = nr; + } +} + + + + +void SNFlash (Boolean on) +{ + if (on) + { + DAC far * pal = farnew(DAC, PAL_CNT); + if (pal) + { + int i; + _fmemcpy(pal, SysPal, PAL_SIZ); + for (i = 0; i < PAL_CNT; i ++) + { + register int c; + c = pal[i].R << 1; pal[i].R = (c < 64) ? c : 63; + c = pal[i].G << 1; pal[i].G = (c < 64) ? c : 63; + c = pal[i].B << 1; pal[i].B = (c < 64) ? c : 63; + } + VGA::SetColors(pal, 64); + } + } + else VGA::SetColors(SysPal, 64); + Dark = FALSE; +} + + + + + +static void SNLight (Boolean in) +{ + if (in) VGA::Sunrise(SysPal); + else VGA::Sunset(); + Dark = ! in; +} + + + + + +static void SNBarrier (int cav, int bar, Boolean horz) +{ + ((byte *) (Barriers + ((cav > 0) ? cav : Now)))[horz] = bar; +} + + + + + +static void SNWalk (SPRITE * spr, int x, int y) +{ + if (Hero) + { + if (spr && y < 0) Hero->FindWay(spr); + else Hero->FindWay(XZ(x, y)); + } +} + + + + + +static void SNReach (SPRITE * spr, int mode) +{ + if (Hero) Hero->Reach(spr, mode); +} + + + + + + +static void SNMouse (Boolean on) +{ + if (on) Mouse.On(); + else Mouse.Off(); +} + + + + + + +void SNAIL::RunCom (void) +{ + static int count = 1; + extern void SwitchCave(int); + if (! Busy) + { + Busy = TRUE; + byte tmphea = Head; + while (Tail != tmphea) + { + COM far * snc = &SNList[Tail]; + + if (! Turbo) // only for the slower one + { + if (Pause) break; + else + { + if (TextDelay) + { + KillText(); + TextDelay = FALSE; + } + } + if (Talk && snc->Com != SNPAUSE) break; + } + + SPRITE * sprel = ((snc->Ref >= 0) ? Locate(snc->Ref) + : ((SPRITE *) snc->Ptr)); + switch (snc->Com) + { + case SNLABEL : break; + case SNPAUSE : HEART::SetXTimer(&Pause, snc->Val); + if (Talk) TextDelay = TRUE; break; + case SNWAIT : if (sprel) + { + if (sprel->SeqTest(snc->Val) && + (snc->Val >= 0 || sprel != Hero || Hero->TracePtr < 0)) + { + HEART::SetXTimer(&Pause, sprel->Time); + } + else goto xit; + } + break; + case SNLEVEL : SNLevel(sprel, snc->Val); break; + case SNHIDE : SNHide(sprel, snc->Val); break; + case SNSAY : if (sprel && TalkEnable) + { + if (sprel == Hero && sprel->SeqTest(-1)) + sprel->Step(HTALK); + Say(Text[snc->Val], sprel); + SYSTEM::FunDel = HEROFUN0; + } + break; + case SNINF : if (TalkEnable) + { + Inf(Text[snc->Val]); + SYSTEM::FunDel = HEROFUN0; + } + break; + case SNTIME : if (sprel && TalkEnable) + { + if (sprel == Hero && sprel->SeqTest(-1)) + sprel->Step(HTALK); + SayTime(sprel); + } + break; + case SNCAVE : SwitchCave(snc->Val); break; + case SNKILL : SNKill(sprel); break; + case SNSEQ : SNSeq(sprel, snc->Val); break; + case SNRSEQ : SNRSeq(sprel, snc->Val); break; + case SNSEND : SNSend(sprel, snc->Val); break; + case SNSWAP : SNSwap(sprel, snc->Val); break; + case SNCOVER : SNCover(sprel, snc->Val); break; + case SNUNCOVER : SNUncover(sprel, (snc->Val >= 0) ? Locate(snc->Val) + : ((SPRITE *) snc->Ptr)); + break; + case SNKEEP : SNKeep(sprel, snc->Val); break; + case SNGIVE : SNGive(sprel, snc->Val); break; + case SNGAME : SNGame(sprel, snc->Val); break; + case SNSETX0 : SNSetX0(snc->Ref, snc->Val); break; + case SNSETY0 : SNSetY0(snc->Ref, snc->Val); break; + case SNSETXY : SNSetXY(sprel, snc->Val); break; + case SNRELX : SNRelX(sprel, snc->Val); break; + case SNRELY : SNRelY(sprel, snc->Val); break; + case SNRELZ : SNRelZ(sprel, snc->Val); break; + case SNSETX : SNSetX(sprel, snc->Val); break; + case SNSETY : SNSetY(sprel, snc->Val); break; + case SNSETZ : SNSetZ(sprel, snc->Val); break; + case SNSLAVE : SNSlave(sprel, snc->Val); break; + case SNTRANS : SNTrans(sprel, snc->Val); break; + case SNPORT : SNPort(sprel, snc->Val); break; + case SNNEXT : break; + case SNIF : break; + case SNTALK : break; + case SNMOUSE : SNMouse(snc->Val != 0); break; + case SNNNEXT : SNNNext(sprel, snc->Val); break; + case SNTNEXT : SNTNext(sprel, snc->Val); break; + case SNRNNEXT : SNRNNext(sprel, snc->Val); break; + case SNRTNEXT : SNRTNext(sprel, snc->Val); break; + case SNRMNEAR : SNRmNear(sprel); break; + case SNRMTAKE : SNRmTake(sprel); break; + case SNFLAG : SNFlag(snc->Ref & 3, snc->Val != 0); break; + case SNSETREF : SNSetRef(sprel, snc->Val); break; + case SNBACKPT : SNBackPt(sprel, snc->Val); break; + case SNFLASH : SNFlash(snc->Val != 0); break; + case SNLIGHT : SNLight(snc->Val != 0); break; + case SNSETHB : SNBarrier(snc->Ref, snc->Val, TRUE); break; + case SNSETVB : SNBarrier(snc->Ref, snc->Val, FALSE); break; + case SNWALK : SNWalk(sprel, snc->Ref, snc->Val); break; + case SNREACH : SNReach(sprel, snc->Val); break; + case SNSOUND : SNSound(sprel, snc->Val, count); count = 1; break; + case SNCOUNT : count = snc->Val; break; + + case SNEXEC : ((void(*)(int)) (snc->Ptr))(snc->Val); break; + case SNSTEP : sprel->Step(); break; + case SNZTRIM : SNZTrim(sprel); break; + case SNGHOST : SNGhost((BITMAP *) snc->Ptr); break; + } + ++ Tail; + if (! Turbo) break; + } + xit: + Busy = FALSE; + } +} + + + + + +Boolean SNAIL::Idle (void) +{ + return (Head == Tail); +} diff --git a/engines/cge/snail.h b/engines/cge/snail.h new file mode 100644 index 0000000000..f1b0ab762f --- /dev/null +++ b/engines/cge/snail.h @@ -0,0 +1,98 @@ +#ifndef __SNAIL__ +#define __SNAIL__ + +#include <jbw.h> + +#define POCKET_X 174 +#define POCKET_Y 176 +#define POCKET_DX 18 +#define POCKET_DY 22 +#define POCKET_NX 8 +#define POCKET_NY 1 + +#define POCKET_SX 8 +#define POCKET_SY 3 + +#define SNINSERT(c,r,v,p) Snail.InsCom(c,r,v,p) +#define SNPOST(c,r,v,p) Snail.AddCom(c,r,v,p) +#define SNPOST_(c,r,v,p) Snail_.AddCom(c,r,v,p) + + + +typedef struct { byte Horz, Vert; } BAR; + + + +struct SCB +{ + byte far * Ptr; + word Siz; + SCB * Nxt; +}; + + + +enum SNCOM { SNLABEL, SNPAUSE, SNWAIT, SNLEVEL, + SNHIDE, SNSAY, SNINF, SNTIME, + SNCAVE, SNKILL, SNRSEQ, + SNSEQ, SNSEND, SNSWAP, SNKEEP, SNGIVE, + SNIF, SNGAME, SNSETX0, SNSETY0, SNSLAVE, + SNSETXY, SNRELX, SNRELY, SNRELZ, + SNSETX, SNSETY, SNSETZ, SNTRANS, SNPORT, + SNNEXT, SNNNEXT, SNTNEXT, SNRNNEXT, SNRTNEXT, + SNRMNEAR, SNRMTAKE, SNFLAG, SNSETREF, + SNBACKPT, SNFLASH, SNLIGHT, + SNSETHB, SNSETVB, + SNWALK, SNREACH, SNCOVER, SNUNCOVER, + SNCLEAR, SNTALK, SNMOUSE, + SNSOUND, SNCOUNT, + SNEXEC, SNSTEP, SNZTRIM, + SNGHOST + }; + +enum SNLIST { NEAR, TAKE }; + +class SNAIL +{ + struct COM { SNCOM Com; int Ref; int Val; void * Ptr; } far * SNList; + byte Head, Tail; + Boolean Turbo, Busy, TextDelay; + word Pause; +public: + static char * ComTxt[]; + Boolean TalkEnable; + SNAIL (Boolean turbo = FALSE); + ~SNAIL (void); + void RunCom (void); + void AddCom (SNCOM com, int ref = 0, int val = 0, void * ptr = NULL); + void InsCom (SNCOM com, int ref = 0, int val = 0, void * ptr = NULL); + Boolean Idle (void); +}; + + + + + +void SelectPocket (int n); +void PocFul (void); + + + + + + + +extern SCB Scb; +extern Boolean Flag[4]; +extern Boolean Game; +extern Boolean Dark; +extern SNAIL Snail; +extern SNAIL Snail_; +extern int Now; +extern int Lev; +extern int MaxCave; +extern int PocPtr; +extern BAR Barriers[]; +extern struct HXY { int X; int Y; } HeroXY[]; + +#endif diff --git a/engines/cge/snddrv.h b/engines/cge/snddrv.h new file mode 100644 index 0000000000..69ea3c2b15 --- /dev/null +++ b/engines/cge/snddrv.h @@ -0,0 +1,104 @@ +// ****************************************************** +// * Sound Driver by Hedges (c) 1995 LK AVALON * +// * Ver 1.00: 01-Mar-95 * +// * Ver 1.10: 03-Mar-95 * +// * Ver 1.20: 07-Mar-95 * +// * Ver 1.30: 09-Mar-95 * +// * Ver 1.40: 11-Mar-95 * +// ****************************************************** + +#ifndef __SNDDRV__ +#define __SNDDRV__ + +// ****************************************************** +// * Constants * +// ****************************************************** +// available devices + +enum DEV_TYPE { DEV_AUTO = -1, // auto-detect mode + DEV_QUIET, // disable sound + DEV_SB, // sb/pro/16/awe32 + DEV_GUS, // gus/max + DEV_GM // general midi + }; + +#define SERR_OK 0 // no error +#define SERR_INITFAIL 1 // couldn't initialize +#define SERR_BADDDEV 128 // bad device + +// driver info +struct DRVINFO +{ + DEV_TYPE DDEV; // digi device + DEV_TYPE MDEV; // midi device + WORD DBASE; // digi base port + WORD DDMA; // digi dma no + WORD DIRQ; // digi irq no + WORD MBASE; // midi base port + union + { + struct + { + WORD DR : 4; + WORD DL : 4; + WORD MR : 4; + WORD ML : 4; + } VOL4; + struct + { + BYTE D; // digi volume + BYTE M; // midi volume + } VOL2; + }; +}; + +// sample info +struct SMPINFO +{ + BYTE far * saddr; // address + WORD slen; // length + WORD span; // left/right pan (0-15) + int sflag; // flag +}; + +// ****************************************************** +// * Data * +// ****************************************************** +// driver info +extern DRVINFO SNDDrvInfo; + +// midi player flag (1 means we are playing) +extern WORD MIDIPlayFlag; + +// midi song end flag (1 means we have crossed end mark) +extern WORD MIDIEndFlag; + +// ****************************************************** +// * Driver Code * +// ****************************************************** +// Init Digi Device +EC void SNDInit (void); + +// Close Digi Device +EC void SNDDone (void); + +// Set Volume +EC void SNDSetVolume (void); + +// Start Digi +EC void SNDDigiStart (SMPINFO *PSmpInfo); + +// Stop Digi +EC void SNDDigiStop (SMPINFO *PSmpInfo); + +// Start MIDI File +EC void SNDMIDIStart (BYTE far *MIDFile); + +// Stop MIDI File +EC void SNDMIDIStop (void); + +// Play MIDI File (to be called while interrupting) +// WARNING: Uses ALL registers! +EC void SNDMIDIPlay (void); + +#endif diff --git a/engines/cge/sound.cpp b/engines/cge/sound.cpp new file mode 100644 index 0000000000..f4fc27ddd7 --- /dev/null +++ b/engines/cge/sound.cpp @@ -0,0 +1,293 @@ +#include <general.h> +#include "startup.h" +#include "sound.h" + +#ifdef DROP_H + #include "drop.h" +#else + #include <stdio.h> + #include <stdlib.h> + #define DROP(m,n) { printf("%s [%s]\n", m, n); _exit(1); } +#endif + +#include "text.h" +#include <cfile.h> +#include "vol.h" +#include <alloc.h> + + + Boolean Music = TRUE; + FX Fx = 16; // must precede SOUND!! + SOUND Sound; + + + +SOUND::SOUND (void) +{ + if (STARTUP::SoundOk) Open(); +} + + + + +SOUND::~SOUND (void) +{ + Close(); +} + + + + + +void SOUND::Close (void) +{ + KillMIDI(); + SNDDone(); +} + + + + + +void SOUND::Open (void) +{ + SNDInit(); + Play(Fx[30000], 8); +} + + + + +void SOUND::Play (DATACK * wav, int pan, int cnt) +{ + if (wav) + { + Stop(); + smpinf.saddr = (char far *) &*(wav->EAddr()); + smpinf.slen = (word)wav->Size(); + smpinf.span = pan; + smpinf.sflag = cnt; + SNDDigiStart(&smpinf); + } +} + + + + +void SOUND::Stop (void) +{ + SNDDigiStop(&smpinf); +} + + +//------------------------------------------------------------------------ + + + + + + + + +FX::FX (int size) +: Emm(0L), Current(NULL) +{ + Cache = new HAN[size]; + for (Size = 0; Size < size; Size ++) + { + Cache[Size].Ref = 0; + Cache[Size].Wav = NULL; + } +} + + + + +FX::~FX (void) +{ + Clear(); + delete[] Cache; +} + + + + + +void FX::Clear (void) +{ + HAN * p, * q; + for (p = Cache, q = p+Size; p < q; p ++) + { + if (p->Ref) + { + p->Ref = 0; + delete p->Wav; + p->Wav = NULL; + } + } + Emm.Release(); + Current = NULL; +} + + + + + +int FX::Find (int ref) +{ + HAN * p, * q; + int i = 0; + for (p = Cache, q = p+Size; p < q; p ++) + { + if (p->Ref == ref) break; + else ++ i; + } + return i; +} + + + + + + + + + + + +void FX::Preload (int ref0) +{ + HAN * CacheLim = Cache + Size; + int ref; + + for (ref = ref0; ref < ref0+10; ref ++) + { + static char fname[] = "FX00000.WAV"; + wtom(ref, fname+2, 10, 5); + DATACK * wav = LoadWave(&INI_FILE(fname), &Emm); + if (wav) + { + HAN * p = &Cache[Find(0)]; + if (p >= CacheLim) break; + p->Wav = wav; + p->Ref = ref; + } + } +} + + + + + +DATACK * FX::Load (int idx, int ref) +{ + static char fname[] = "FX00000.WAV"; + wtom(ref, fname+2, 10, 5); + + DATACK * wav = LoadWave(&INI_FILE(fname), &Emm); + if (wav) + { + HAN * p = &Cache[idx]; + p->Wav = wav; + p->Ref = ref; + } + return wav; +} + + + + +DATACK * FX::operator [] (int ref) +{ + int i; + if ((i = Find(ref)) < Size) Current = Cache[i].Wav; + else + { + if ((i = Find(0)) >= Size) + { + Clear(); + i = 0; + } + Current = Load(i, ref); + } + return Current; +} + + + + +//------------------------------------------------------------------------- + + +static byte far * midi = NULL; + + + +void KillMIDI (void) +{ + SNDMIDIStop(); + if (midi) + { + delete[] midi; + midi = NULL; + } +} + + + + + +void LoadMIDI (int ref) +{ + static char fn[] = "00.MID"; + wtom(ref, fn, 10, 2); + if (INI_FILE::Exist(fn)) + { + KillMIDI(); + INI_FILE mid = fn; + if (mid.Error == 0) + { + word siz = (word) mid.Size(); + midi = new far byte[siz]; + if (midi) + { + mid.Read(midi, siz); + if (mid.Error) KillMIDI(); + else + { + SNDMIDIStart(midi); + } + } + } + } +} + + + + + + +EC void far * Patch (int pat) +{ + void far * p = NULL; + static char fn[] = "PATCH000.SND"; + + wtom(pat, fn+5, 10, 3); + INI_FILE snd = fn; + if (! snd.Error) + { + word siz = (word) snd.Size(); + p = (byte far *) farmalloc(siz); + if (p) + { + snd.Read(p, siz); + if (snd.Error) + { + farfree(p); + p = NULL; + } + } + } + return p; +} + diff --git a/engines/cge/sound.h b/engines/cge/sound.h new file mode 100644 index 0000000000..b4efd99808 --- /dev/null +++ b/engines/cge/sound.h @@ -0,0 +1,61 @@ +#ifndef __SOUND__ +#define __SOUND__ + +#include <wav.h> +#include <snddrv.h> + + +#define BAD_SND_TEXT 97 +#define BAD_MIDI_TEXT 98 + + + + +class SOUND +{ +public: + SMPINFO smpinf; + SOUND (void); + ~SOUND (void); + void Open (void); + void Close (void); + void Play (DATACK * wav, int pan, int cnt = 1); + void Stop (void); +}; + + + + + +class FX +{ + EMM Emm; + struct HAN { int Ref; DATACK * Wav; } * Cache; + int Size; + DATACK * Load (int idx, int ref); + int Find (int ref); +public: + DATACK * Current; + FX (int size = 16); + ~FX (void); + void Clear (void); + void Preload (int ref0); + DATACK * operator[] (int ref); +}; + + + + + + +extern Boolean Music; +extern SOUND Sound; +extern FX Fx; + + +void LoadMIDI (int ref); +void KillMIDI (void); + + +#endif + diff --git a/engines/cge/startup.cpp b/engines/cge/startup.cpp new file mode 100644 index 0000000000..3557891a03 --- /dev/null +++ b/engines/cge/startup.cpp @@ -0,0 +1,168 @@ +#include "startup.h" +#include "text.h" +#include "sound.h" +#include "ident.h" +#include <cfile.h> +#include <snddrv.h> +#include <stdio.h> +#include <process.h> +#include <dos.h> +#include <alloc.h> +#include <string.h> + +#ifdef DEBUG + #include <stdlib.h> +#endif + +extern char Copr[]; + +#define id (*(IDENT*)Copr) + + + EMM MiniEmm = MINI_EMM_SIZE; + +static STARTUP StartUp; + + + int STARTUP::Mode = 0; + int STARTUP::Core; + int STARTUP::SoundOk = 0; + word STARTUP::Summa; + + + +void quit_now (int ref) +{ + fputs(Text[ref], stderr); + fputc('\n', stderr); + _exit(1); +} + + + +Boolean STARTUP::get_parms (void) +{ + int i = _argc; + while (i > 1) + { + static char *PrmTab[] = { "NEW", "MK0SVG", "QUIET", "SB", "GUS", "MIDI", + "P", "D", "I", "M" }; + int n = TakeEnum(PrmTab, strtok(_argv[--i], " =:(")); + word p = xtow(strtok(NULL, " h,)")); + switch (n) + { + case 0 : if (Mode != 2) Mode = 1; break; + case 1 : Mode = 2; break; + case 2 : SNDDrvInfo.DDEV = DEV_QUIET; break; + case 3 : SNDDrvInfo.DDEV = DEV_SB; break; + case 4 : SNDDrvInfo.DDEV = DEV_GUS; break; + case 5 : SNDDrvInfo.MDEV = DEV_GM; break; + case 6 : SNDDrvInfo.DBASE = p; break; + case 7 : SNDDrvInfo.DDMA = p; break; + case 8 : SNDDrvInfo.DIRQ = p; break; + case 9 : SNDDrvInfo.MBASE = p; + SNDDrvInfo.MDEV = DEV_GM; break; + default: return FALSE; + } + if (n >= 2) SoundOk = 2; + } + #ifdef DEMO + // protection disabled + Summa = 0; + #else + #ifdef EVA + { + union { dosdate_t d; dword n; } today; + _dos_getdate(&today.d); + id.disk += (id.disk < today.n); + } + #endif + #ifdef CD + Summa = 0; + #else + // disk signature checksum + Summa = ChkSum(Copr, sizeof(IDENT)); + #endif + #endif + if (SNDDrvInfo.MDEV != DEV_GM) SNDDrvInfo.MDEV = SNDDrvInfo.DDEV; + return TRUE; +} + + + + +STARTUP::STARTUP (void) +{ + dword m = farcoreleft() >> 10; + if (m < 0x7FFF) Core = (int) m; else Core = 0x7FFF; + + if (! IsVga()) quit_now(NOT_VGA_TEXT); + if (Cpu() < _80286) quit_now(BAD_CHIP_TEXT); + if (100 * _osmajor + _osminor < 330) quit_now(BAD_DOS_TEXT); + + #ifndef DEBUG + if (Core < CORE_LOW) quit_now(NO_CORE_TEXT); + if (Core < CORE_HIG) + { + SNDDrvInfo.MDEV = DEV_QUIET; + Music = FALSE; + } + #endif + if (! get_parms()) quit_now(BAD_ARG_TEXT); + //--- load sound configuration + const char * fn = UsrPath(ProgName(CFG_EXT)); + if (! STARTUP::SoundOk && CFILE::Exist(fn)) + { + CFILE cfg(fn, REA); + if (! cfg.Error) + { + cfg.Read(&SNDDrvInfo, sizeof(SNDDrvInfo)-sizeof(SNDDrvInfo.VOL2)); + if (! cfg.Error) STARTUP::SoundOk = 1; + } + } +} + + + + + + +const char *UsrPath (const char *nam) +{ + static char buf[MAXPATH] = ".\\", *p = buf+2; + #if defined(CD) + if (DriveCD(0)) + { + Boolean ok = FALSE; + CFILE ini = Text[CDINI_FNAME]; + if (!ini.Error) + { + char *key = Text[GAME_ID]; + int i = strlen(key); + while (ini.Read(buf) && !ok) + { + int j = strlen(buf); + if (j) if (buf[--j] == '\n') buf[j] = '\0'; + if (memicmp(buf, key, i) == 0) ok = TRUE; + } + if (ok) + { + strcpy(buf, buf+i); + p = buf + strlen(buf); + if (*(p-1) != '\\') *(p++) = '\\'; + strcpy(p, "NUL"); + if (_dos_open(buf, 0, &i) == 0) _dos_close(i); + else ok = FALSE; + } + } + if (!ok) quit_now(BADCD_TEXT); + } + #endif + strcpy(p, nam); + return buf; +} + + + + + diff --git a/engines/cge/startup.h b/engines/cge/startup.h new file mode 100644 index 0000000000..6db566a781 --- /dev/null +++ b/engines/cge/startup.h @@ -0,0 +1,52 @@ +#ifndef __STARTUP__ +#define __STARTUP__ + + +#include <general.h> + +#define GAME_ID 45 +#define CDINI_FNAME 46 + +#define NOT_VGA_TEXT 90 +#define BAD_CHIP_TEXT 91 +#define BAD_DOS_TEXT 92 +#define NO_CORE_TEXT 93 +#define BAD_MIPS_TEXT 94 +#define NO_MOUSE_TEXT 95 +#define BAD_ARG_TEXT 96 +#define BADCD_TEXT 97 + +#define CFG_EXT ".CFG" + +#if defined(DEMO) + #define MINI_EMM_SIZE 0x00004000L + #define CORE_HIG 400 +#else + #define MINI_EMM_SIZE 0x00010000L + #define CORE_HIG 450 +#endif + +#define CORE_MID (CORE_HIG-20) +#define CORE_LOW (CORE_MID-20) + + +class STARTUP +{ + static Boolean get_parms (void); +public: + static int Mode; + static int Core; + static int SoundOk; + static word Summa; + STARTUP (void); +}; + + + + +extern EMM MiniEmm; + +const char *UsrPath (const char *nam); + + +#endif diff --git a/engines/cge/talk.cpp b/engines/cge/talk.cpp new file mode 100644 index 0000000000..a018761000 --- /dev/null +++ b/engines/cge/talk.cpp @@ -0,0 +1,376 @@ +#include <general.h> +#include "talk.h" +#include "vol.h" +#include "game.h" +#include "mouse.h" +#include <dos.h> +#include <alloc.h> +#include <mem.h> + +#define WID_SIZ 256 +#define POS_SIZ 256 +#define MAP_SIZ (256*8) + + +//-------------------------------------------------------------------------- + + + +//byte FONT::Wid[WID_SIZ]; +//word FONT::Pos[POS_SIZ]; +//byte FONT::Map[MAP_SIZ]; + + + + + + + +FONT::FONT (const char * name) +{ + Map = farnew(byte, MAP_SIZ); + Pos = farnew(word, POS_SIZ); + Wid = farnew(byte, WID_SIZ); + if (Map == NULL || Pos == NULL || Wid == NULL) DROP("No core", NULL); + MergeExt(Path, name, FONT_EXT); + Load(); +} + + + + +FONT::~FONT (void) +{ + farfree(Map); + farfree(Pos); + farfree(Wid); +} + + + + +void FONT::Load (void) +{ + INI_FILE f(Path); + if (! f.Error) + { + f.Read(Wid, WID_SIZ); + if (! f.Error) + { + word i, p = 0; + for (i = 0; i < POS_SIZ; i ++) + { + Pos[i] = p; + p += Wid[i]; + } + f.Read(Map, p); + } + } +} + + + + + +word FONT::Width (const char * text) +{ + word w = 0; + if (text) while (* text) w += Wid[*(text ++)]; + return w; +} + + + +/* +void FONT::Save (void) +{ + CFILE f((const char *) Path, WRI); + if (! f.Error) + { + f.Write(Wid, WID_SIZ); + if (! f.Error) + { + f.Write(Map, Pos[POS_SIZ-1] + Wid[WID_SIZ-1]); + } + } +} +*/ + + + + +//-------------------------------------------------------------------------- + + + +FONT TALK::Font(ProgName()); + + + +TALK::TALK (const char * tx, TBOX_STYLE mode) +: SPRITE(NULL), Mode(mode) +{ + TS[0] = TS[1] = NULL; + Flags.Syst = TRUE; + Update(tx); +} + + + + + +TALK::TALK (void) +: SPRITE(NULL), Mode(PURE) +{ + TS[0] = TS[1] = NULL; + Flags.Syst = TRUE; +} + + + + + +/* +TALK::~TALK (void) +{ + word i; + for (i = 0; i < ShpCnt; i ++) + { + if (FP_SEG(ShpList[i]) != _DS) // small model: always FALSE + { + delete ShpList[i]; + ShpList[i] = NULL; + } + } +} +*/ + + + +void TALK::Update (const char * tx) +{ + word vmarg = (Mode) ? TEXT_VM : 0; + word hmarg = (Mode) ? TEXT_HM : 0; + word mw, mh, ln = vmarg; + const char * p; + byte far * m; + + if (! TS[0]) + { + word k = 2 * hmarg; + mh = 2 * vmarg + FONT_HIG; + mw = 0; + for (p = tx; *p; p ++) + { + if (*p == '|' || *p == '\n') + { + mh += FONT_HIG + TEXT_LS; + if (k > mw) mw = k; + k = 2 * hmarg; + } + else k += Font.Wid[*p]; + } + if (k > mw) mw = k; + TS[0] = Box(mw, mh); + } + + m = TS[0]->M + ln * mw + hmarg; + + while (* tx) + { + if (*tx == '|' || *tx == '\n') + m = TS[0]->M + (ln += FONT_HIG + TEXT_LS) * mw + hmarg; + else + { + int cw = Font.Wid[*tx], i; + char far * f = Font.Map + Font.Pos[*tx]; + for (i = 0; i < cw; i ++) + { + char far * p = m; + word n; + register word b = * (f ++); + for (n = 0; n < FONT_HIG; n ++) + { + if (b & 1) * p = TEXT_FG; + b >>= 1; + p += mw; + } + ++ m; + } + } + ++ tx; + } + TS[0]->Code(); + SetShapeList(TS); +} + + + + +BITMAP * TALK::Box (word w, word h) +{ + byte far * b, far * p, far * q; + word n, r = (Mode == ROUND) ? TEXT_RD : 0; + int i; + + if (w < 8) w = 8; + if (h < 8) h = 8; + b = farnew(byte, n = w * h); + if (! b) VGA::Exit("No core"); + _fmemset(b, TEXT_BG, n); + + if (Mode) + { + p = b; q = b + n - w; + _fmemset(p, LGRAY, w); + _fmemset(q, DGRAY, w); + while (p < q) + { + p += w; + * (p-1) = DGRAY; + * p = LGRAY; + } + p = b; + for (i = 0; i < r; i ++) + { + int j; + for (j = 0; j < r-i; j ++) + { + p[ j ] = TRANS; + p[w-j-1] = TRANS; + q[ j ] = TRANS; + q[w-j-1] = TRANS; + } + p[ j ] = LGRAY; + p[w-j-1] = DGRAY; + q[ j ] = LGRAY; + q[w-j-1] = DGRAY; + p += w; + q -= w; + } + } + return new BITMAP(w, h, b); +} + + + + + +void TALK::PutLine (int line, const char * text) +// Note: (TS[0].W % 4) have to be 0 +{ + word w = TS[0]->W, h = TS[0]->H; + byte far * v = TS[0]->V, far * p; + word dsiz = w >> 2; // data size (1 plane line size) + word lsiz = 2 + dsiz + 2; // word for line header, word for gap + word psiz = h * lsiz; // - last gap, but + plane trailer + word size = 4 * psiz; // whole map size + word rsiz = FONT_HIG * lsiz; // length of whole text row map + + // set desired line pointer + v += (TEXT_VM + (FONT_HIG + TEXT_LS) * line) * lsiz; + + // clear whole rectangle + p = v; // assume blanked line above text + _fmemcpy(p, p-lsiz, rsiz); p += psiz; // tricky replicate lines for plane 0 + _fmemcpy(p, p-lsiz, rsiz); p += psiz; // same for plane 1 + _fmemcpy(p, p-lsiz, rsiz); p += psiz; // same for plane 2 + _fmemcpy(p, p-lsiz, rsiz); // same for plane 3 + + // paint text line + if (text) + { + byte far * q; + p = v + 2 + TEXT_HM/4 + (TEXT_HM%4)*psiz; + q = v + size; + + while (* text) + { + word cw = Font.Wid[*text], i; + byte far * fp = Font.Map + Font.Pos[*text]; + + for (i = 0; i < cw; i ++) + { + register word b = fp[i]; + word n; + for (n = 0; n < FONT_HIG; n ++) + { + if (b & 1) *p = TEXT_FG; + b >>= 1; + p += lsiz; + } + p = p - rsiz + psiz; + if (p >= q) p = p - size + 1; + } + ++ text; + } + } +} + + + + + + +//-------------------------------------------------------------------------- + + + + +INFO_LINE::INFO_LINE (word w) +: OldTxt(NULL) +{ + TS[0] = new BITMAP(w, FONT_HIG, TEXT_BG); + SetShapeList(TS); +} + + + + + + +void INFO_LINE::Update (const char * tx) +{ + if (tx != OldTxt) + { + word w = TS[0]->W, h = TS[0]->H; + byte * v = (byte near *) TS[0]->V; + word dsiz = w >> 2; // data size (1 plane line size) + word lsiz = 2 + dsiz + 2; // word for line header, word for gap + word psiz = h * lsiz; // - last gape, but + plane trailer + word size = 4 * psiz; // whole map size + + // claer whole rectangle + memset(v+2, TEXT_BG, dsiz); // data bytes + memcpy(v + lsiz, v, psiz - lsiz); // tricky replicate lines + * (word *) (v + psiz - 2) = EOI; // plane trailer word + memcpy(v + psiz, v, 3 * psiz); // tricky replicate planes + + // paint text line + if (tx) + { + byte * p = v + 2, * q = p + size; + + while (* tx) + { + word cw = Font.Wid[*tx], i; + byte far * fp = Font.Map + Font.Pos[*tx]; + + for (i = 0; i < cw; i ++) + { + register word b = fp[i]; + word n; + for (n = 0; n < FONT_HIG; n ++) + { + if (b & 1) *p = TEXT_FG; + b >>= 1; + p += lsiz; + } + if (p >= q) p = p - size + 1; + } + ++ tx; + } + } + OldTxt = tx; + } +} diff --git a/engines/cge/talk.h b/engines/cge/talk.h new file mode 100644 index 0000000000..12b0b94dde --- /dev/null +++ b/engines/cge/talk.h @@ -0,0 +1,81 @@ +#ifndef __TALK__ +#define __TALK__ + +#include "vga13h.h" +#include <dir.h> + + + +#define TEXT_FG DARK // foreground color +#define TEXT_BG GRAY // background color +#define TEXT_HM (6&~1) // EVEN horizontal margins! +#define TEXT_VM 5 // vertical margins +#define TEXT_LS 2 // line spacing +#define TEXT_RD 3 // rounded corners + +#define FONT_HIG 8 +#define FONT_EXT ".CFT" + + + + + +class FONT +{ + char Path[MAXPATH]; + void Load (void); +public: +// static byte Wid[256]; +// static word Pos[256]; +// static byte Map[256*8]; + byte far * Wid; + word far * Pos; + byte far * Map; + FONT (const char * name); + ~FONT (void); + word Width (const char * text); + void Save (void); +}; + + + + + +enum TBOX_STYLE { PURE, RECT, ROUND }; + + + +class TALK : public SPRITE +{ +protected: + TBOX_STYLE Mode; + BITMAP * TS[2]; + BITMAP * Box(word w, word h); +public: + static FONT Font; + TALK (const char * tx, TBOX_STYLE mode = PURE); + TALK (void); + //~TALK (void); + virtual void Update (const char * tx); + virtual void Update (void) {} + void PutLine (int line, const char * text); +}; + + + + + + + +class INFO_LINE : public TALK +{ + const char * OldTxt; +public: + INFO_LINE (word wid); + void Update (const char * tx); +}; + + + + +#endif
\ No newline at end of file diff --git a/engines/cge/text.cpp b/engines/cge/text.cpp new file mode 100644 index 0000000000..a18eec5baf --- /dev/null +++ b/engines/cge/text.cpp @@ -0,0 +1,291 @@ +#include <general.h> +#include "text.h" +#include "talk.h" +#include "vol.h" +#include "bitmaps.h" +#include "game.h" +#include "snail.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <dos.h> + + + + TEXT Text = ProgName(); + TALK * Talk = NULL; + + + + + +TEXT::TEXT (const char * fname, int size) +{ + Cache = new HAN[size]; + MergeExt(FileName, fname, SAY_EXT); + if (! INI_FILE::Exist(FileName)) + { + fputs("No talk\n", stderr); + _exit(1); + } + for (Size = 0; Size < size; Size ++) + { + Cache[Size].Ref = 0; + Cache[Size].Txt = NULL; + } +} + + + + +TEXT::~TEXT (void) +{ + Clear(); + delete[] Cache; +} + + + + + +void TEXT::Clear (int from, int upto) +{ + HAN * p, * q; + for (p = Cache, q = p+Size; p < q; p ++) + { + if (p->Ref && p->Ref >= from && p->Ref < upto) + { + p->Ref = 0; + delete p->Txt; + p->Txt = NULL; + } + } +} + + + + + +int TEXT::Find (int ref) +{ + HAN * p, * q; + int i = 0; + for (p = Cache, q = p+Size; p < q; p ++) + { + if (p->Ref == ref) break; + else ++ i; + } + return i; +} + + + + + + + + + + + +void TEXT::Preload (int from, int upto) +{ + INI_FILE tf = FileName; + if (! tf.Error) + { + HAN * CacheLim = Cache + Size; + char line[LINE_MAX+1]; + int n; + + while ((n = tf.Read(line)) != 0) + { + char * s; + int ref; + + if (line[n-1] == '\n') line[-- n] = '\0'; + if ((s = strtok(line, " =,;/\t\n")) == NULL) continue; + if (! IsDigit(*s)) continue; + ref = atoi(s); + if (ref && ref >= from && ref < upto) + { + HAN * p; + + p = &Cache[Find(ref)]; + if (p < CacheLim) + { + delete[] p->Txt; + p->Txt = NULL; + } + else p = &Cache[Find(0)]; + if (p >= CacheLim) break; + s += strlen(s); + if (s < line + n) ++ s; + if ((p->Txt = new char[strlen(s) + 1]) == NULL) break; + p->Ref = ref; + strcpy(p->Txt, s); + } + } + } +} + + + + + +char * TEXT::Load (int idx, int ref) +{ + INI_FILE tf = FileName; + if (! tf.Error) + { + HAN * p = &Cache[idx]; + char line[LINE_MAX+1]; + int n; + + while ((n = tf.Read(line)) != 0) + { + char * s; + + if (line[n-1] == '\n') line[-- n] = '\0'; + if ((s = strtok(line, " =,;/\t\n")) == NULL) continue; + if (! IsDigit(*s)) continue; + + int r = atoi(s); + if (r < ref) continue; + if (r > ref) break; + // (r == ref) + s += strlen(s); + if (s < line + n) ++ s; + p->Ref = ref; + if ((p->Txt = new char[strlen(s) + 1]) == NULL) return NULL; + return strcpy(p->Txt, s); + } + } + return NULL; +} + + + + +char * TEXT::operator [] (int ref) +{ + int i; + if ((i = Find(ref)) < Size) return Cache[i].Txt; + + if ((i = Find(0)) >= Size) + { + Clear(SYSTXT_MAX); // clear non-system + if ((i = Find(0)) >= Size) + { + Clear(); // clear all + i = 0; + } + } + return Load(i, ref); +} + + + + + + +void Say (const char * txt, SPRITE * spr) +{ + KillText(); + Talk = new TALK(txt, ROUND); + if (Talk) + { + Boolean east = spr->Flags.East; + int x = (east) ? (spr->X+spr->W-2) : (spr->X+2); + int y = spr->Y+2; + SPRITE * spike = new SPRITE(SP); + word sw = spike->W; + + if (east) + { + if (x + sw + TEXT_RD + 5 >= SCR_WID) east = FALSE; + } + else + { + if (x <= 5 + TEXT_RD + sw) east = TRUE; + } + x = (east) ? (spr->X+spr->W-2) : (spr->X+2-sw); + if (spr->Ref == 1) x += (east) ? -10 : 10; // Hero + + Talk->Flags.Kill = TRUE; + Talk->Flags.BDel = TRUE; + Talk->SetName(Text[SAY_NAME]); + Talk->Goto(x - (Talk->W - sw) / 2 - 3 + 6 * east, y - spike->H - Talk->H+1); + Talk->Z = 125; + Talk->Ref = SAY_REF; + + spike->Goto(x, Talk->Y + Talk->H - 1); + spike->Z = 126; + spike->Flags.Slav = TRUE; + spike->Flags.Kill = TRUE; + spike->SetName(Text[SAY_NAME]); + spike->Step(east); + spike->Ref = SAY_REF; + + VGA::ShowQ.Insert(Talk, VGA::ShowQ.Last()); + VGA::ShowQ.Insert(spike, VGA::ShowQ.Last()); + } +} + + + + + + + +void Inf (const char * txt) +{ + KillText(); + Talk = new TALK(txt, RECT); + if (Talk) + { + Talk->Flags.Kill = TRUE; + Talk->Flags.BDel = TRUE; + Talk->SetName(Text[INF_NAME]); + Talk->Center(); + Talk->Goto(Talk->X, Talk->Y - 20); + Talk->Z = 126; + Talk->Ref = INF_REF; + VGA::ShowQ.Insert(Talk, VGA::ShowQ.Last()); + } +} + + + + + + + +void SayTime (SPRITE * spr) +{ + static char t[] = "00:00"; + struct time ti; + gettime(&ti); + wtom(ti.ti_hour, t+0, 10, 2); + wtom(ti.ti_min, t+3, 10, 2); + Say((*t == '0') ? (t+1) : t, spr); +} + + + + + + +void KillText (void) +{ + if (Talk) + { + SNPOST_(SNKILL, -1, 0, Talk); + Talk = NULL; + } +} + + + + + +//------------------------------------------------------------------------- diff --git a/engines/cge/text.h b/engines/cge/text.h new file mode 100644 index 0000000000..d960fbef91 --- /dev/null +++ b/engines/cge/text.h @@ -0,0 +1,60 @@ +#ifndef __TEXT__ +#define __TEXT__ + +#include "talk.h" +#include <jbw.h> +#include <dir.h> + + + + +#ifndef SYSTXT_MAX + #define SYSTXT_MAX 1000 +#endif + +#define SAY_EXT ".SAY" + +#define NOT_VGA_TEXT 90 +#define BAD_CHIP_TEXT 91 +#define BAD_DOS_TEXT 92 +#define NO_CORE_TEXT 93 +#define BAD_MIPS_TEXT 94 +#define NO_MOUSE_TEXT 95 + + +#define INF_NAME 101 +#define SAY_NAME 102 + +#define INF_REF 301 +#define SAY_REF 302 + + +class TEXT +{ + struct HAN { int Ref; char * Txt; } * Cache; + int Size; + char FileName[MAXPATH]; + char * Load (int idx, int ref); + int Find (int ref); +public: + TEXT (const char * fname, int size = 128); + ~TEXT (void); + void Clear (int from = 1, int upto = 0x7FFF); + void Preload (int from = 1, int upto = 0x7FFF); + char * operator[] (int ref); +}; + + + +extern TALK * Talk; +extern TEXT Text; + + +void Say (const char * txt, SPRITE * spr); +void SayTime (SPRITE * spr); +void Inf (const char * txt); +void KillText (void); + + + +#endif
\ No newline at end of file diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp new file mode 100644 index 0000000000..227304668b --- /dev/null +++ b/engines/cge/vga13h.cpp @@ -0,0 +1,1775 @@ +#include <general.h> +#include "vga13h.h" +#include "bitmap.h" +#include "vol.h" +#include "text.h" +#include <alloc.h> +#include <conio.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dos.h> +#include <dir.h> +#include <fcntl.h> +#include <bios.h> +#include <io.h> + +#ifdef DEBUG +#define REPORT +#endif + +#define OK(f) ((f).Error==0) +#define FADE_STEP 2 + +#define TMR_DIV ((0x8000/TMR_RATE)*2) + + +//-------------------------------------------------------------------------- + +#ifdef REPORT +static char Report[] = "NearHeap=..... FarHeap=......\n"; +#define NREP 9 +#define FREP 24 +#endif + + + +static VgaRegBlk VideoMode[] = { + + { 0x04, VGASEQ, 0x08, 0x04 }, // memory mode + + { 0x03, VGAGRA, 0xFF, 0x00 }, // data rotate = 0 + { 0x05, VGAGRA, 0x03, 0x00 }, // R/W mode = 0 + { 0x06, VGAGRA, 0x02, 0x00 }, // misc + + { 0x14, VGACRT, 0x40, 0x00 }, // underline + { 0x13, VGACRT, 0xFF, 0x28 }, // screen width + { 0x17, VGACRT, 0xFF, 0xC3 }, // mode control + + { 0x11, VGACRT, 0x80, 0x00 }, // vert retrace end + { 0x09, VGACRT, 0xEF, 0x01 }, // max scan line + + { 0x30, VGAATR, 0x00, 0x20 }, // 256 color mode + +// { 0x12, VGACRT, 0xFF, 0x6E }, // vert display end +// { 0x15, VGACRT, 0xFF, 0x7F }, // start vb +// { 0x10, VGACRT, 0xFF, 0x94 }, // start vr + + { 0x00 } }; + + + Boolean SpeedTest = FALSE; + SEQ Seq1[] = { { 0, 0, 0, 0, 0 } }; + SEQ Seq2[] = { { 0, 1, 0, 0, 0 }, { 1, 0, 0, 0, 0 } }; + SPRITE * Sys = NULL; + +extern "C" void SNDMIDIPlay (void); + + + + + + +char * NumStr (char * str, int num) +{ + char * p = strchr(str, '#'); + if (p) wtom(num, p, 10, 5); + return str; +} + + + + + + + + +static void Video (void) +{ + static word SP_S; + + asm push bx + asm push bp + asm push si + asm push di + asm push es + asm xor bx,bx // video page #0 + SP_S = _SP; + asm int VIDEO + _SP = SP_S; + asm pop es + asm pop di + asm pop si + asm pop bp + asm pop bx +} + + + + + + +word far * SaveScreen (void) +{ + word cxy, cur, siz, far * scr = NULL, far * sav; + + // horizontal size of text mode screen + asm mov ah,0x0F // get current video mode + Video(); // BIOS video service + asm xchg ah,al // answer in ah + asm push ax // preserve width + + // vertical size of text mode screen + asm mov dl,24 // last row on std screen + asm xor bx,bx // valid request in BH + asm mov ax,0x1130 // get EGA's last row # + Video(); // BIOS video service + asm inc dl // # of rows = last+1 + + // compute screen size in words + asm pop ax // restore width + asm mul dl // width * height + + siz = _AX; + + asm mov ax,0x40 // system data segment + asm mov es,ax + asm mov ax,0B000H // Mono + asm cmp byte ptr es:[0x49],0x07 + asm je sto + asm mov ax,0B800H // Color + sto: // store screen address + asm mov word ptr scr+2,ax + + _AH = 0x0F; Video(); // active page + + // take cursor shape + _AH = 0x03; Video(); // get cursor size + cur = _CX; + + // take cursor position + _DH = 0; + _AH = 0x03; Video(); // get cursor + cxy = _DX; + + sav = farnew(word, siz+3); // +3 extra words for size and cursor + if (sav) + { + sav[0] = siz; + sav[1] = cur; + sav[2] = cxy; + _fmemcpy(sav+3, scr, siz * 2); + } + return sav; +} + + + + + +void RestoreScreen (word far * &sav) +{ + word far * scr = NULL; + + asm mov ax,0x40 // system data segment + asm mov es,ax + asm mov ax,0B000H // Mono + asm cmp byte ptr es:[0x49],0x07 + asm je sto + asm mov ax,0B800H // Color + sto: // store screen address + asm mov word ptr scr+2,ax + + _fmemcpy(scr, sav+3, sav[0] * 2); + + _AH = 0x0F; Video(); // active page + + // set cursor shape + _CX = sav[1]; + _AH = 0x01; Video(); // set cursor size + + // set cursor position + _DX = sav[2]; + _AH = 0x02; Video(); // set cursor + + farfree(sav); + sav = NULL; +} + + + + + + +DAC MkDAC (byte r, byte g, byte b) +{ + static DAC x; + x.R = r; + x.G = g; + x.B = b; + return x; +} + + + + +RGB MkRGB (byte r, byte g, byte b) +{ + static TRGB x; + x.dac.R = r; + x.dac.G = g; + x.dac.B = b; + return x.rgb; +} + + + + + + +SPRITE * Locate (int ref) +{ + SPRITE * spr = VGA::ShowQ.Locate(ref); + return (spr) ? spr : VGA::SpareQ.Locate(ref); +} + + + + + +//-------------------------------------------------------------------------- + + +Boolean HEART::Enable = FALSE; +word * HEART::XTimer = NULL; + + + + +HEART::HEART (void) +: ENGINE(TMR_DIV) +{ +} + + +/* +extern "C" void TimerProc (void) +{ + static SPRITE * spr; + static byte run = 0; + + // decrement external timer word + if (HEART::XTimer) + if (*HEART::XTimer) -- *HEART::XTimer; + else HEART::XTimer = NULL; + + if (! run && HEART::Enable) // check overrun flag + { + static word oldSP, oldSS; + + ++ run; // disable 2nd call until current lasts + asm mov ax,ds + asm mov oldSS,ss + asm mov oldSP,sp + asm mov ss,ax + asm mov sp,0xFF80 + + // system pseudo-sprite + if (Sys) if (Sys->Time) if (-- Sys->Time == 0) Sys->Tick(); + + for (spr = VGA::ShowQ.First(); spr; spr = spr->Next) + { + if (spr->Time) if (!spr->Flags.Hide) if (-- spr->Time == 0) spr->Tick(); + } + asm mov ss,oldSS + asm mov sp,oldSP + -- run; + } +} +*/ + + +void interrupt ENGINE::NewTimer (...) +{ + static SPRITE * spr; + static byte run = 0, cntr1 = TMR_RATE1, cntr2 = TMR_RATE2; + + ___1152_Hz___: + + SNDMIDIPlay(); + asm dec cntr1 + asm jz ___72_Hz___ + asm mov al,0x20 // send... + asm out 0x020,al // ...e-o-i + return; + + ___72_Hz___: + + asm mov cntr1,TMR_RATE1 + asm dec cntr2 + asm jnz my_eoi + + ___18_Hz___: + + OldTimer(); + asm mov cntr2,TMR_RATE2 + asm jmp short my_int + + // send E-O-I + my_eoi: + asm mov al,0x20 + asm out 0x020,al + asm sti // enable interrupts + + my_int: //------72Hz-------// + + // decrement external timer word + if (HEART::XTimer) + if (*HEART::XTimer) -- *HEART::XTimer; + else HEART::XTimer = NULL; + + if (! run && HEART::Enable) // check overrun flag + { + static word oldSP, oldSS; + + ++ run; // disable 2nd call until current lasts + asm mov ax,ds + asm mov oldSS,ss + asm mov oldSP,sp + asm mov ss,ax + asm mov sp,0xFF80 + + // system pseudo-sprite + if (Sys) if (Sys->Time) if (-- Sys->Time == 0) Sys->Tick(); + + for (spr = VGA::ShowQ.First(); spr; spr = spr->Next) + { + if (spr->Time) if (!spr->Flags.Hide) if (-- spr->Time == 0) spr->Tick(); + } + asm mov ss,oldSS + asm mov sp,oldSP + -- run; + } +} + + + + + +void HEART::SetXTimer (word * ptr) +{ + if (XTimer && ptr != XTimer) *XTimer = 0; + XTimer = ptr; +} + + + + +void HEART::SetXTimer (word * ptr, word time) +{ + SetXTimer(ptr); + *ptr = time; +} + + + + +//-------------------------------------------------------------------------- + + + + + + + +SPRITE::SPRITE (BMP_PTR * shp) +: X(0), Y(0), Z(0), NearPtr(0), TakePtr(0), + Next(NULL), Prev(NULL), SeqPtr(NO_SEQ), Time(0), //Delay(0), + Ext(NULL), Ref(-1), Cave(0) +{ + memset(File, 0, sizeof(File)); + *((word *)&Flags) = 0; + SetShapeList(shp); +} + + + + + + +SPRITE::~SPRITE (void) +{ + Contract(); +} + + + + +BMP_PTR SPRITE::Shp (void) +{ + register SPREXT * e = Ext; + if (e) if (e->Seq) + { + int i = e->Seq[SeqPtr].Now; + #ifdef DEBUG + if (i >= ShpCnt) + { + //char s[256]; + //sprintf(s, "Seq=%p ShpCnt=%d SeqPtr=%d Now=%d Next=%d", + // Seq, ShpCnt, SeqPtr, Seq[SeqPtr].Now, Seq[SeqPtr].Next); + //VGA::Exit(s, File); + VGA::Exit("Invalid PHASE in SPRITE::Shp()", File); + } + #endif + return e->ShpList[i]; + } + return NULL; +} + + + + + +BMP_PTR * SPRITE::SetShapeList (BMP_PTR * shp) +{ + BMP_PTR * r = (Ext) ? Ext->ShpList : NULL; + + ShpCnt = 0; + W = 0; + H = 0; + + if (shp) + { + BMP_PTR * p; + for (p = shp; *p; p ++) + { + BMP_PTR b = (*p); // ->Code(); + if (b->W > W) W = b->W; + if (b->H > H) H = b->H; + ++ ShpCnt; + } + Expand(); + Ext->ShpList = shp; + if (! Ext->Seq) SetSeq((ShpCnt < 2) ? Seq1 : Seq2); + } + return r; +} + + + + + +void SPRITE::MoveShapes (byte far * buf) +{ + BMP_PTR * p; + for (p = Ext->ShpList; *p; p ++) + { + buf += (*p)->MoveVmap(buf); + } +} + + + + + +Boolean SPRITE::Works (SPRITE * spr) +{ + if (spr) if (spr->Ext) + { + SNAIL::COM * c = spr->Ext->Take; + if (c != NULL) + { + c += spr->TakePtr; + if (c->Ref == Ref) + if (c->Com != SNLABEL || (c->Val == 0 || c->Val == Now)) + return TRUE; + } + } + return FALSE; +} + + + + + +SEQ * SPRITE::SetSeq (SEQ * seq) +{ + Expand(); + register SEQ * s = Ext->Seq; + Ext->Seq = seq; + if (SeqPtr == NO_SEQ) Step(0); + else + if (Time == 0) Step(SeqPtr); + return s; +} + + + + + + +Boolean SPRITE::SeqTest (int n) +{ + if (n >= 0) return (SeqPtr == n); + if (Ext) return (Ext->Seq[SeqPtr].Next == SeqPtr); + return TRUE; +} + + + + + + +SNAIL::COM * SPRITE::SnList (SNLIST type) +{ + register SPREXT * e = Ext; + if (e) return (type == NEAR) ? e->Near : e->Take; + return NULL; +} + + + + + + +void SPRITE::SetName (char * n) +{ + if (Ext) + { + if (Ext->Name) + { + delete[] Ext->Name; + Ext->Name = NULL; + } + if (n) + { + if ((Ext->Name = new char[strlen(n)+1]) != NULL) strcpy(Ext->Name, n); + else VGA::Exit("No core", n); + } + } +} + + + + + +SPRITE * SPRITE::Expand (void) +{ + if (! Ext) + { + Boolean enbl = HEART::Enable; + HEART::Enable = FALSE; + if ((Ext = new SPREXT) == NULL) DROP("No core", NULL); + if (*File) + { + static char * Comd[] = { "Name", "Phase", "Seq", "Near", "Take", NULL }; + char line[LINE_MAX], fname[MAXPATH]; + BMP_PTR * shplist = new BMP_PTR [ShpCnt+1]; + SEQ * seq = NULL; + int shpcnt = 0, + seqcnt = 0, + neacnt = 0, + takcnt = 0, + maxnow = 0, + maxnxt = 0, + lcnt = 0, + len; + + SNAIL::COM * nea = NULL; + SNAIL::COM * tak = NULL; + MergeExt(fname, File, SPR_EXT); + if (INI_FILE::Exist(fname)) // sprite description file exist + { + INI_FILE sprf(fname); + if (! OK(sprf)) + { + VGA::Exit("Bad SPR", fname); + } + + while ((len = sprf.Read(line)) != 0) + { + ++ lcnt; + if (len && line[len-1] == '\n') line[-- len] = '\0'; + if (len == 0 || *line == '.') continue; + + switch (TakeEnum(Comd, strtok(line, " =\t"))) + { + case 0 : // Name + SetName(strtok(NULL, "")); break; + case 1 : // Phase + shplist[shpcnt ++] = new BITMAP(strtok(NULL, " \t,;/")); + break; + case 2 : // Seq + seq = (SEQ *) realloc(seq, (seqcnt + 1) * sizeof(*seq)); + if (seq == NULL) + VGA::Exit("No core", fname); + SEQ * s = &seq[seqcnt ++]; + s->Now = atoi(strtok(NULL, " \t,;/")); + if (s->Now > maxnow) maxnow = s->Now; + s->Next = atoi(strtok(NULL, " \t,;/")); + switch (s->Next) + { + case 0xFF : s->Next = seqcnt; break; + case 0xFE : s->Next = seqcnt-1; break; + } + if (s->Next > maxnxt) maxnxt = s->Next; + s->Dx = atoi(strtok(NULL, " \t,;/")); + s->Dy = atoi(strtok(NULL, " \t,;/")); + s->Dly = atoi(strtok(NULL, " \t,;/")); + break; + case 3 : // Near + if (NearPtr != NO_PTR) + { + nea = (SNAIL::COM *) realloc(nea, (neacnt + 1) * sizeof(*nea)); + if (nea == NULL) VGA::Exit("No core", fname); + else + { + SNAIL::COM * c = &nea[neacnt ++]; + if ((c->Com = (SNCOM) TakeEnum(SNAIL::ComTxt, strtok(NULL, " \t,;/"))) < 0) + VGA::Exit(NumStr("Bad NEAR in ######", lcnt), fname); + c->Ref = atoi(strtok(NULL, " \t,;/")); + c->Val = atoi(strtok(NULL, " \t,;/")); + c->Ptr = NULL; + } + } + break; + case 4 : // Take + if (TakePtr != NO_PTR) + { + tak = (SNAIL::COM *) realloc(tak, (takcnt + 1) * sizeof(*tak)); + if (tak == NULL) VGA::Exit("No core", fname); + else + { + SNAIL::COM * c = &tak[takcnt ++]; + if ((c->Com = (SNCOM) TakeEnum(SNAIL::ComTxt, strtok(NULL, " \t,;/"))) < 0) + VGA::Exit(NumStr("Bad NEAR in ######", lcnt), fname); + c->Ref = atoi(strtok(NULL, " \t,;/")); + c->Val = atoi(strtok(NULL, " \t,;/")); + c->Ptr = NULL; + } + } + break; + } + } + } + else // no sprite description: try to read immediately from .BMP + { + shplist[shpcnt ++] = new BITMAP(File); + } + shplist[shpcnt] = NULL; + if (seq) + { + if (maxnow >= shpcnt) VGA::Exit("Bad PHASE in SEQ", fname); + if (maxnxt >= seqcnt) VGA::Exit("Bad JUMP in SEQ", fname); + SetSeq(seq); + } + else SetSeq((ShpCnt == 1) ? Seq1 : Seq2); + disable(); + + SetShapeList(shplist); + enable(); + if (nea) nea[neacnt-1].Ptr = Ext->Near = nea; else NearPtr = NO_PTR; + if (tak) tak[takcnt-1].Ptr = Ext->Take = tak; else TakePtr = NO_PTR; + } + HEART::Enable = enbl; + } + return this; +} + + + + +SPRITE * SPRITE::Contract (void) +{ + register SPREXT * e = Ext; + if (e) + { + if (e->Name) delete[] e->Name; + if (Flags.BDel && e->ShpList) + { + int i; + for (i = 0; e->ShpList[i]; i ++) delete e->ShpList[i]; + if (MemType(e->ShpList) == NEAR_MEM) delete[] e->ShpList; + } + if (MemType(e->Seq) == NEAR_MEM) free(e->Seq); + if (e->Near) free(e->Near); + if (e->Take) free(e->Take); + delete e; + Ext = NULL; + } + return this; +} + + + + + + +SPRITE * SPRITE::BackShow (Boolean fast) +{ + Expand(); + Show(2); + Show(1); + if (fast) Show(0); + Contract(); + return this; +} + + + + + + + + +void SPRITE::Step (int nr) +{ + if (nr >= 0) SeqPtr = nr; + if (Ext) + { + SEQ * seq; + if (nr < 0) SeqPtr = Ext->Seq[SeqPtr].Next; + seq = Ext->Seq + SeqPtr; + if (seq->Dly >= 0) + { + Goto(X + (seq->Dx), Y + (seq->Dy)); + Time = seq->Dly; + } + } +} + + + + + + +void SPRITE::Tick (void) +{ + Step(); +} + + + + + +void SPRITE::MakeXlat (byte far * x) +{ + if (Ext) + { + BMP_PTR * b; + + if (Flags.Xlat) KillXlat(); + for (b = Ext->ShpList; *b; b ++) (*b)->M = x; + Flags.Xlat = TRUE; + } +} + + + + + +void SPRITE::KillXlat (void) +{ + if (Flags.Xlat && Ext) + { + BMP_PTR * b; + byte far * m = (*Ext->ShpList)->M; + + switch (MemType(m)) + { + case NEAR_MEM : delete[] (byte *) m; break; + case FAR_MEM : farfree(m); break; + } + for (b = Ext->ShpList; *b; b ++) (*b)->M = NULL; + Flags.Xlat = FALSE; + } +} + + + + + +void SPRITE::Goto (int x, int y) +{ + int xo = X, yo = Y; + if (W < SCR_WID) + { + if (x < 0) x = 0; + if (x + W > SCR_WID) x = (SCR_WID - W); + X = x; + } + if (H < SCR_HIG) + { + if (y < 0) y = 0; + if (y + H > SCR_HIG) y = (SCR_HIG - H); + Y = y; + } + if (Next) if (Next->Flags.Slav) Next->Goto(Next->X-xo+X, Next->Y-yo+Y); + if (Flags.Shad) Prev->Goto(Prev->X-xo+X, Prev->Y-yo+Y); +} + + + + + + + + + + + + +void SPRITE::Center (void) +{ + Goto((SCR_WID - W) / 2, (SCR_HIG - H) / 2); +} + + + + + + + + +void SPRITE::Show (void) +{ + register SPREXT * e; + asm cli // critic section... + e = Ext; + e->x0 = e->x1; + e->y0 = e->y1; + e->b0 = e->b1; + e->x1 = X; + e->y1 = Y; + e->b1 = Shp(); + asm sti // ...done! + if (! Flags.Hide) + { + if (Flags.Xlat) e->b1->XShow(e->x1, e->y1); + else e->b1->Show(e->x1, e->y1); + } +} + + + + + + + +void SPRITE::Show (word pg) +{ + byte far * a = VGA::Page[1]; + VGA::Page[1] = VGA::Page[pg & 3]; + Shp()->Show(X, Y); + VGA::Page[1] = a; +} + + + + + + + + +void SPRITE::Hide (void) +{ + register SPREXT * e = Ext; + if (e->b0) e->b0->Hide(e->x0, e->y0); +} + + + + +BMP_PTR SPRITE::Ghost (void) +{ + register SPREXT * e = Ext; + if (e->b1) + { + BMP_PTR bmp = new BITMAP(0, 0, (byte far *)NULL); + if (bmp == NULL) VGA::Exit("No core"); + bmp->W = e->b1->W; + bmp->H = e->b1->H; + if ((bmp->B = farnew(HideDesc, bmp->H)) == NULL) VGA::Exit("No Core"); + bmp->V = (byte far *) _fmemcpy(bmp->B, e->b1->B, sizeof(HideDesc) * bmp->H); + bmp->M = (byte far *) MK_FP(e->y1, e->x1); + return bmp; + } + return NULL; +} + + + + + + +SPRITE * SpriteAt (int x, int y) +{ + SPRITE * spr = NULL, * tail = VGA::ShowQ.Last(); + if (tail) + { + for (spr = tail->Prev; spr; spr = spr->Prev) + if (! spr->Flags.Hide && ! spr->Flags.Tran) + if (spr->Shp()->SolidAt(x-spr->X, y-spr->Y)) + break; + } + return spr; +} + + + + + +//-------------------------------------------------------------------------- + + + + + + +QUEUE::QUEUE (Boolean show) +: Head(NULL), Tail(NULL), Show(show) +{ +} + + + + +QUEUE::~QUEUE (void) +{ + Clear(); +} + + + + +void QUEUE::Clear (void) +{ + while (Head) + { + SPRITE * s = Remove(Head); + if (s->Flags.Kill) delete s; + } +} + + + + +void QUEUE::ForAll (void (*fun)(SPRITE *)) +{ + SPRITE * s = Head; + while (s) + { + SPRITE * n = s->Next; + fun(s); + s = n; + } +} + + + + + +void QUEUE::Append (SPRITE * spr) +{ + if (Tail) + { + spr->Prev = Tail; + Tail->Next = spr; + } + else Head = spr; + Tail = spr; + if (Show) spr->Expand(); + else spr->Contract(); +} + + + + + +void QUEUE::Insert (SPRITE * spr, SPRITE * nxt) +{ + if (nxt == Head) + { + spr->Next = Head; + Head = spr; + if (! Tail) Tail = spr; + } + else + { + spr->Next = nxt; + spr->Prev = nxt->Prev; + if (spr->Prev) spr->Prev->Next = spr; + } + if (spr->Next) spr->Next->Prev = spr; + if (Show) spr->Expand(); + else spr->Contract(); +} + + + + + +void QUEUE::Insert (SPRITE * spr) +{ + SPRITE * s; + for (s = Head; s; s = s->Next) + if (s->Z > spr->Z) + break; + if (s) Insert(spr, s); + else Append(spr); + if (Show) spr->Expand(); + else spr->Contract(); +} + + + + + +SPRITE * QUEUE::Remove (SPRITE * spr) +{ + if (spr == Head) Head = spr->Next; + if (spr == Tail) Tail = spr->Prev; + if (spr->Next) spr->Next->Prev = spr->Prev; + if (spr->Prev) spr->Prev->Next = spr->Next; + spr->Prev = NULL; + spr->Next = NULL; + return spr; +} + + + + + +SPRITE * QUEUE::Locate (int ref) +{ + SPRITE * spr; + for (spr = Head; spr; spr = spr->Next) if (spr->Ref == ref) return spr; + return NULL; +} + + + + + +//-------------------------------------------------------------------------- + + + + +word VGA::StatAdr = VGAST1_; +word VGA::OldMode = 0; +word far * VGA::OldScreen = NULL; +const char * VGA::Msg = NULL; +const char * VGA::Nam = NULL; +DAC far * VGA::OldColors = NULL; +DAC far * VGA::NewColors = NULL; +Boolean VGA::SetPal = FALSE; +int VGA::Mono = 0; +QUEUE VGA::ShowQ = TRUE, VGA::SpareQ = FALSE; +byte far * VGA::Page[4] = { (byte far *) MK_FP(SCR_SEG, 0x0000), + (byte far *) MK_FP(SCR_SEG, 0x4000), + (byte far *) MK_FP(SCR_SEG, 0x8000), + (byte far *) MK_FP(SCR_SEG, 0xC000) }; + + + + +VGA::VGA (int mode) +: FrmCnt(0) +{ + extern const char Copr[]; + Boolean std = TRUE; + int i; + for (i = 10; i < 20; i ++) + { + char * txt = Text[i]; + if (txt) + { + puts(txt); + #ifndef DEBUG + std = FALSE; + #endif + } + } + if (std) puts(Copr); + SetStatAdr(); + if (StatAdr != VGAST1_) ++ Mono; + if (IsVga()) + { + OldColors = farnew(DAC, 256); + NewColors = farnew(DAC, 256); + OldScreen = SaveScreen(); + GetColors(OldColors); + Sunset(); + OldMode = SetMode(mode); + SetColors(); + Setup(VideoMode); + Clear(); + } +} + + + + + +VGA::~VGA (void) +{ + Mono = 0; + if (IsVga()) + { + Clear(); + SetMode(OldMode); + SetColors(); + RestoreScreen(OldScreen); + Sunrise(OldColors); + if (OldColors) farfree(OldColors); + if (NewColors) farfree(NewColors); + if (Msg) fputs(Msg, stderr); + if (Nam) + { + fputs(" [", stderr); + fputs(Nam, stderr); + fputc(']', stderr); + } + if (Msg || Nam) fputc('\n', stderr); + #ifdef REPORT + fputs(Report, stderr); + #endif + } +} + + + + + +void VGA::SetStatAdr (void) +{ + asm mov dx,VGAMIr_ + asm in al,dx + asm test al,1 // CGA addressing mode flag + asm mov ax,VGAST1_ // CGA addressing + asm jnz set_mode_adr + asm xor al,0x60 // MDA addressing + set_mode_adr: + StatAdr = _AX; +} + + + + + + +#pragma argsused +void VGA::WaitVR (Boolean on) +{ + _DX = StatAdr; + _AH = (on) ? 0x00 : 0x08; + + asm mov cx,2 + // wait for vertical retrace on (off) + wait: + asm in al,dx + asm xor al,ah + asm test al,0x08 + asm jnz wait + asm xor ah,0x08 + asm loop wait +} + + + + + + +void VGA::Setup (VgaRegBlk * vrb) +{ + WaitVR(); // *--LOOK!--* resets VGAATR logic + asm cld + asm mov si, vrb // take address of parameter table + asm mov dh,0x03 // higher byte of I/O address is always 3 + + s: + asm lodsw // take lower byte of I/O address and index + asm or ah,ah // 0 = end of table + asm jz xit // no more: exit + asm or al,al // indexed register? + asm js single // 7th bit set means single register + asm mov dl,ah // complete I/O address + asm out dx,al // put index into control register + asm inc dx // data register is next to control + asm in al,dx // take old data + + write: + asm mov cl,al // preserve old data + asm lodsw // take 2 masks from table + asm xor al,0xFF // invert mask bits + asm and al,cl // clear bits with "clr" mask + asm or al,ah // set bits with "set" mask + asm cmp dl,0xC1 // special case? + asm jne std2 // no: standard job, otherwise... + asm dec dx // data out reg shares address with index + std2: + asm out dx,al // write new value to register + asm jmp s + + single: // read address in al, write address in ah + asm mov dl,al // complete I/O read address + asm in al,dx // take old data + asm mov dl,ah // complete I/O write address + asm jmp write // continue standard routine + + xit: +} + + + + + + +int VGA::SetMode (int mode) +{ + Clear(); + // get current mode + asm mov ah,0x0F + Video(); // BIOS video service + asm xor ah,ah + asm push ax + + // wait for v-retrace + WaitVR(); + + // set mode + asm xor ah,ah + asm mov al,byte ptr mode + Video(); // BIOS video service + SetStatAdr(); + // return previous mode + asm pop ax + return _AX; +} + + + + + + +void VGA::GetColors (DAC far * tab) +{ + asm cld + asm les di,tab // color table + asm mov dx,0x3C7 // PEL address read mode register + asm xor al,al // start from address 0 + asm out dx,al // put address + asm mov cx,256*3 // # of colors + asm mov dl,0xC9 // PEL data register + +// asm rep insb // very fast! + + gc: // much slower: + asm in al,dx // take 1 color + asm jmp sto // little delay + sto: + asm stosb // store 1 color + asm loop gc // next one? +} + + + + +void VGA::SetColors (DAC far * tab, int lum) +{ + DAC far * des = NewColors; + asm push ds + + asm les di,des + asm lds si,tab + asm mov cx,256*3 + asm xor bx,bx + asm mov dx,lum + + copcol: + asm mov al,[si+bx] + asm mul dl + asm shr ax,6 + asm mov es:[di+bx],al + asm inc bx + asm cmp bx,cx + asm jb copcol + + asm pop ds + + if (Mono) + { + asm add cx,di + mono: + asm xor dx,dx + asm mov al,77 // 30% R + asm mul byte ptr es:[di].0 + asm add dx,ax + asm mov al,151 // 59% G + asm mul byte ptr es:[di].1 + asm add dx,ax + asm mov al,28 // 11% B + asm mul byte ptr es:[di].2 + asm add dx,ax + + asm mov es:[di].0,dh + asm mov es:[di].1,dh + asm mov es:[di].2,dh + + asm add di,3 + asm cmp di,cx + asm jb mono + } + SetPal = TRUE; +} + + + + + + +void VGA::SetColors (void) +{ + _fmemset(NewColors, 0, PAL_SIZ); + UpdateColors(); +} + + + + + + +void VGA::Sunrise (DAC far * tab) +{ + int i; + for (i = 0; i <= 64; i += FADE_STEP) + { + SetColors(tab, i); + WaitVR(); + UpdateColors(); + } +} + + + + + + +void VGA::Sunset (void) +{ + DAC tab[256]; + int i; + GetColors(tab); + for (i = 64; i >= 0; i -= FADE_STEP) + { + SetColors(tab, i); + WaitVR(); + UpdateColors(); + } +} + + + + + + + + + +void VGA::Show (void) +{ + SPRITE * spr = ShowQ.First(); + + for (spr = ShowQ.First(); spr; spr = spr->Next) spr->Show(); + Update(); + for (spr = ShowQ.First(); spr; spr = spr->Next) spr->Hide(); + + ++ FrmCnt; +} + + + + +void VGA::UpdateColors (void) +{ + DAC far * tab = NewColors; + + asm push ds + asm cld + asm lds si,tab // color table + asm mov dx,0x3C8 // PEL address write mode register + asm xor al,al // start from address 0 + asm out dx,al // put address + asm mov cx,256*3 // # of colors + asm mov dl,0xC9 // PEL data register + +// asm rep outsb // very fast! + + // the slower version of above: + sc: + asm lodsb // take 1/3 color + asm out dx,al // put 1/3 color + asm jmp loop // little delay + loop: + asm loop sc // next one? + + + asm pop ds +} + + + + + + + +void VGA::Update (void) +{ + byte far * p = Page[1]; + Page[1] = Page[0]; + Page[0] = p; + + asm mov dx,VGACRT_ + asm mov al,0x0D + asm mov ah,byte ptr p + asm out dx,ax + asm dec al + asm mov ah,byte ptr p+1 + asm out dx,ax + + if (! SpeedTest) WaitVR(); + + if (SetPal) + { + UpdateColors(); + SetPal = FALSE; + } +} + + + + + + + + +void VGA::Clear (byte color) +{ + byte far * a = (byte far *) MK_FP(SCR_SEG, 0); + + asm mov dx,VGASEQ_ + asm mov ax,0x0F02 // map mask register - enable all planes + asm out dx,ax + asm les di,a + asm cld + + asm mov cx,0xFFFF + asm mov al,color + asm rep stosb + asm stosb +} + + + + + + +void VGA::CopyPage (word d, word s) +{ + byte far * S = Page[s & 3], far * D = Page[d & 3]; + + asm mov dx,VGAGRA_ + asm mov al,0x05 // R/W mode + asm out dx,al + asm inc dx + asm in al,dx + asm and al,0xF4 + asm push ax + asm push dx + asm or al,0x01 + asm out dx,al + + asm mov dx,VGASEQ_ + asm mov ax,0x0F02 // map mask register - enable all planes + asm out dx,ax + + asm push ds + + asm les di,D + asm lds si,S + asm cld + asm mov cx,0x4000 + asm rep movsb + + asm pop ds + + asm pop dx + asm pop ax + asm out dx,al // end of copy mode +} + + + + + + + +void VGA::Exit (const char * txt, const char * name) +{ + Msg = txt; + Nam = name; + #ifdef REPORT + wtom(coreleft(), Report + NREP, 10, 5); + dwtom(farcoreleft(), Report + FREP, 10, 6); + #endif + exit(0); +} + + + + +void VGA::Exit (int tref, const char * name) +{ + Exit(Text[tref], name); +} + + + + +//-------------------------------------------------------------------------- + + + + +void BITMAP::XShow (int x, int y) +{ + byte rmsk = x % 4, + mask = 1 << rmsk, + far * scr = VGA::Page[1] + y * (SCR_WID / 4) + x / 4; + byte near * m = (char *) M; + byte far * v = V; + + asm push bx + asm push si + asm push ds + + asm cld + asm les di,scr + asm lds si,v + asm mov bx,m + + + + asm mov al,0x02 // map mask register + asm mov ah,mask + + plane: + // enable output plane + asm mov dx,VGASEQ_ + asm out dx,ax + asm push ax + + // select input plane + asm mov dx,VGAGRA_ + asm mov al,0x04 // read map select register + asm mov ah,rmsk + asm out dx,ax + + asm push di + + block: + asm lodsw + asm mov cx,ax + asm and ch,0x3F + asm test ah,0xC0 + asm jz endpl + asm jns skip + asm jnp incsi // replicate? + asm add si,cx // skip over data block + asm dec si // fix it before following inc + + incsi: + asm inc si + tint: + asm mov al,es:[di] + //----------------------------------------------- + // asm xlat ss:0 // unsupported with BASM! + __emit__(0x36, 0xD7); // this stands for above! + //----------------------------------------------- + asm stosb + asm loop tint + asm jmp block + + skip: + asm add di,cx + asm jmp block + + endpl: + asm pop di + asm pop ax + asm inc rmsk + asm shl ah,1 + asm test ah,0x10 + asm jz x_chk + asm mov ah,0x01 + asm mov rmsk,0 + asm inc di + x_chk: + asm cmp ah,mask + asm jne plane + asm pop ds + asm pop si + asm pop bx +} + + + + + + +void BITMAP::Show (int x, int y) +{ + byte mask = 1 << (x & 3), + far * scr = VGA::Page[1] + y * (SCR_WID >> 2) + (x >> 2); + byte far * v = V; + + asm push ds // preserve DS + + asm cld // normal direction + asm les di,scr // screen address + asm lds si,v // picture address + asm mov dx,VGASEQ_ // VGA reg + asm mov al,0x02 + asm mov ah,mask + + plane: + asm out dx,ax + asm push ax + asm push di + + block: + asm mov cx,[si] // with ADD faster then LODSW + asm add si,2 + asm test ch,0xC0 + asm jns skip // 1 (SKP) or 0 (EOI) + asm jpo repeat // 2 (REP) + + copy: // 3 (CPY) + asm and ch,0x3F + asm shr cx,1 + asm rep movsw + asm jnc block + asm movsb + asm jmp block + + repeat: + asm and ch,0x3F + asm mov al,[si] + asm inc si + asm mov ah,al + asm shr cx,1 + asm rep stosw + asm jnc block + asm mov es:[di],al + asm inc di + asm jmp block + + skip: + asm jz endpl + asm and ch,0x3F + asm add di,cx + asm jmp block + + endpl: + asm pop di + asm pop ax + asm shl ah,1 + asm test ah,0x10 + asm jz x_chk + asm mov ah,0x01 + asm inc di + x_chk: + asm cmp ah,mask + asm jne plane + asm pop ds +} + + + + + +void BITMAP::Hide (int x, int y) +{ + byte far * scr = VGA::Page[1] + y * (SCR_WID / 4) + x / 4; + word d = FP_OFF(VGA::Page[2]) - FP_OFF(VGA::Page[1]); + HideDesc far * b = B; + word extra = ((x & 3) != 0); + word h = H; + +// asm push bx + asm push si + asm push ds + + asm cld + asm les di,scr + asm mov si,di + asm add si,d // take bytes from background page + asm lds bx,b + + asm mov dx,VGAGRA_ + asm mov al,0x05 // R/W mode + asm out dx,al + asm inc dx + asm in al,dx + asm and al,0xF4 + asm push ax + asm push dx + asm or al,0x01 + asm out dx,al + + asm mov dx,VGASEQ_ + asm mov ax,0x0F02 // enable all planes + asm out dx,ax + + asm mov dx,ds // save DS + + row: +// skip block + asm mov cx,[bx] + asm add si,cx + asm add di,cx + asm mov cx,[bx+2] + asm add bx,4 + asm add cx,extra + + asm push es + asm pop ds // set DS to video seg + asm rep movsb // move bytes fast + asm sub si,extra + asm sub di,extra + asm mov ds,dx // restore DS + + asm dec h + asm jnz row + + asm pop dx + asm pop ax + asm out dx,al // end of copy mode + + + asm pop ds + asm pop si +// asm pop bx +} + + + + + + + +//-------------------------------------------------------------------------- + + + diff --git a/engines/cge/vga13h.h b/engines/cge/vga13h.h new file mode 100644 index 0000000000..f3c17fa73e --- /dev/null +++ b/engines/cge/vga13h.h @@ -0,0 +1,310 @@ +#ifndef __VGA13H__ +#define __VGA13H__ + +#include <general.h> +#include <stddef.h> +#include <dir.h> +#include "bitmap.h" +#include "snail.h" + + +#define TMR_RATE1 16 +#define TMR_RATE2 4 +#define TMR_RATE (TMR_RATE1*TMR_RATE2) + +#define MAX_NAME 20 +#define VIDEO 0x10 + +#define NO_CLEAR 0x80 +#define TEXT_MODE 0x03 +#define M13H 0x13 + +#ifndef SCR_WID + #define SCR_WID 320 +#endif + +#ifndef SCR_HIG + #define SCR_HIG 200 +#endif + + +#if 0 + #define LIGHT 0xFF + #define DARK 0x00 + #define DGRAY 0xF6 + #define GRAY 0xFC + #define LGRAY 0xFF +#else + #define LIGHT 0xFF + #define DARK 207 + #define DGRAY 225 /*219*/ + #define GRAY 231 + #define LGRAY 237 +#endif + +#define NO_SEQ (-1) +#define NO_PTR ((byte)-1) + +#define SPR_EXT ".SPR" + +#define IsFile(s) (access(s,0)==0) +#define IsWrit(s) (access(s,2)==0) + + + +typedef struct { word r : 2; word R : 6; + word g : 2; word G : 6; + word b : 2; word B : 6; + } RGB; + +typedef union { + DAC dac; + RGB rgb; + } TRGB; + +typedef struct { byte idx, adr; byte clr, set; } VgaRegBlk; + +typedef struct { byte Now, Next; signed char Dx, Dy; int Dly; } SEQ; + +extern SEQ Seq1[]; +extern SEQ Seq2[]; +//extern SEQ * Compass[]; +//extern SEQ TurnToS[]; + + +#define PAL_CNT 256 +#define PAL_SIZ (PAL_CNT*sizeof(DAC)) + +#define VGAATR_ 0x3C0 +#define VGAMIw_ 0x3C0 +#define VGASEQ_ 0x3C4 +#define VGAMIr_ 0x3CC +#define VGAGRA_ 0x3CE +#define VGACRT_ 0x3D4 +#define VGAST1_ 0x3DA +#define VGAATR (VGAATR_ & 0xFF) +#define VGAMIw (VGAMIw_ & 0xFF) +#define VGASEQ (VGASEQ_ & 0xFF) +#define VGAMIr (VGAMIr_ & 0xFF) +#define VGAGRA (VGAGRA_ & 0xFF) +#define VGACRT (VGACRT_ & 0xFF) +#define VGAST1 (VGAST1_ & 0xFF) + + + + + + +class HEART : public ENGINE +{ + friend ENGINE; +public: + static Boolean Enable; + static word * XTimer; + static void SetXTimer (word * ptr); + static void SetXTimer (word * ptr, word time); + HEART (void); +}; + + + + + +class SPREXT +{ +public: + int x0, y0; + int x1, y1; + BMP_PTR b0, b1; + BMP_PTR * ShpList; + SEQ * Seq; + char * Name; + SNAIL::COM * Near, * Take; + SPREXT (void) : + x0(0), y0(0), + x1(0), y1(0), + b0(NULL), b1(NULL), + ShpList(NULL), Seq(NULL), + Name(NULL), Near(NULL), Take(NULL) + {} +}; + + + + +class SPRITE +{ +protected: + SPREXT * Ext; +public: + int Ref; + signed char Cave; + struct FLAGS { word Hide : 1; // general visibility switch + word Near : 1; // Near action lock + word Drag : 1; // sprite is moveable + word Hold : 1; // sprite is held with mouse + word ____ : 1; // intrrupt driven animation + word Slav : 1; // slave object + word Syst : 1; // system object + word Kill : 1; // dispose memory after remove + word Xlat : 1; // 2nd way display: xlat table + word Port : 1; // portable + word Kept : 1; // kept in pocket + word East : 1; // talk to east (in opposite to west) + word Shad : 1; // shadow + word Back : 1; // 'send to background' request + word BDel : 1; // delete bitmaps in ~SPRITE + word Tran : 1; // transparent (untouchable) + } Flags; + int X, Y; + signed char Z; + word W, H; + word Time; + byte NearPtr, TakePtr; + int SeqPtr; + int ShpCnt; + char File[MAXFILE]; + SPRITE * Prev, * Next; + Boolean Works (SPRITE * spr); + Boolean SeqTest (int n); + inline Boolean Active (void) { return Ext != NULL; } + SPRITE (BMP_PTR * shp); + virtual ~SPRITE (void); + BMP_PTR Shp (void); + BMP_PTR * SetShapeList (BMP_PTR * shp); + void MoveShapes (byte far * buf); + SPRITE * Expand (void); + SPRITE * Contract (void); + SPRITE * BackShow (Boolean fast = FALSE); + void SetName(char * n); + inline char * Name(void) { return (Ext) ? Ext->Name : NULL; } + void Goto (int x, int y); + void Center (void); + void Show (void); + void Hide (void); + BMP_PTR Ghost (void); + void Show (word pg); + void MakeXlat (byte far * x); + void KillXlat (void); + void Step (int nr = -1); + SEQ * SetSeq (SEQ * seq); + SNAIL::COM * SnList(SNLIST type); + virtual void Touch (word mask, int x, int y); + virtual void Tick (void); +}; + + + + + + +class QUEUE +{ + SPRITE * Head, * Tail; +public: + Boolean Show; + QUEUE (Boolean show = FALSE); + ~QUEUE (void); + void Append (SPRITE * spr); + void Insert (SPRITE * spr, SPRITE * nxt); + void Insert (SPRITE * spr); + SPRITE * Remove (SPRITE * spr); + void ForAll (void (*fun)(SPRITE *)); + SPRITE * First (void) { return Head; } + SPRITE * Last (void) { return Tail; } + SPRITE * Locate (int ref); + void Clear (void); +}; + + + + + + +class VGA +{ + static word OldMode; + static word far * OldScreen; + static word StatAdr; + static Boolean SetPal; + static DAC far * OldColors, far * NewColors; + static int SetMode (int mode); + static void UpdateColors (void); + static void SetColors (void); + static const char * Msg; + static const char * Nam; + static void SetStatAdr (void); + static void WaitVR (Boolean on = TRUE); +public: + dword FrmCnt; + static QUEUE ShowQ, SpareQ; + static int Mono; + static byte far * Page[4]; + VGA (int mode = M13H); + ~VGA (void); + void Setup (VgaRegBlk * vrb); + static void GetColors (DAC far * tab); + static void SetColors (DAC far * tab, int lum); + static void Clear (byte color = 0); + static void Exit (const char * txt = NULL, const char * name = NULL); + static void Exit (int tref, const char * name = NULL); + static void CopyPage (word d, word s = 3); + static void Sunrise (DAC far * tab); + static void Sunset (void); + void Show (void); + void Update (void); +}; + + + +DAC MkDAC (byte r, byte g, byte b); +RGB MkRGB (byte r, byte g, byte b); + + + + +template <class CBLK> +byte Closest (CBLK far * pal, CBLK x) +{ + #define f(col,lum) ((((word)(col))<<8)/lum) + word i, dif = 0xFFFF, found; + word L = x.R + x.G + x.B; if (! L) ++ L; + word R = f(x.R, L), G = f(x.G, L), B = f(x.B, L); + for (i = 0; i < 256; i ++) + { + word l = pal[i].R + pal[i].G + pal[i].B; if (! l) ++ l; + int r = f(pal[i].R, l), g = f(pal[i].G, l), b = f(pal[i].B, l); + word D = ((r > R) ? (r - R) : (R - r)) + + ((g > G) ? (g - G) : (G - g)) + + ((b > B) ? (b - B) : (B - b)) + + ((l > L) ? (l - L) : (L - l)) * 10 ; + + if (D < dif) + { + found = i; + dif = D; + if (D == 0) break; // exact! + } + } + return found; + #undef f +}; + + + + + + + + char * NumStr (char * str, int num); + void Video (void); + word far * SaveScreen (void); + void RestoreScreen (word far * &sav); + SPRITE * SpriteAt (int x, int y); + SPRITE * Locate (int ref); + +extern Boolean SpeedTest; + + +#endif +
\ No newline at end of file diff --git a/engines/cge/vmenu.cpp b/engines/cge/vmenu.cpp new file mode 100644 index 0000000000..5dd3efb191 --- /dev/null +++ b/engines/cge/vmenu.cpp @@ -0,0 +1,149 @@ +#include "vmenu.h" +#include "mouse.h" +#include <string.h> +#include <alloc.h> + +//-------------------------------------------------------------------------- + + +#define RELIEF 1 +#if RELIEF + #define MB_LT LGRAY + #define MB_RB DGRAY +#else + #define MB_LT DGRAY + #define MB_RB LGRAY +#endif + + + + +MENU_BAR::MENU_BAR (word w) +{ + int h = FONT_HIG + 2 * MB_VM, i = (w += 2 * MB_HM) * h; + byte far * p = farnew(byte, i), far * p1, far * p2; + + _fmemset(p+w, TRANS, i-2*w); + _fmemset(p, MB_LT, w); + _fmemset(p+i-w, MB_RB, w); + p1 = p; + p2 = p+i-1; + for (i = 0; i < h; i ++) + { + * p1 = MB_LT; + * p2 = MB_RB; + p1 += w; + p2 -= w; + } + TS[0] = new BITMAP(w, h, p); + SetShapeList(TS); + Flags.Slav = TRUE; + Flags.Tran = TRUE; + Flags.Kill = TRUE; + Flags.BDel = TRUE; +} + + + +//-------------------------------------------------------------------------- + +static char * vmgt; + + + +char * VMGather (CHOICE * list) +{ + CHOICE * cp; + int len = 0, h = 0; + + for (cp = list; cp->Text; cp ++) + { + len += strlen(cp->Text); + ++ h; + } + vmgt = new byte[len+h]; + if (vmgt) + { + *vmgt = '\0'; + for (cp = list; cp->Text; cp ++) + { + if (*vmgt) strcat(vmgt, "|"); + strcat(vmgt, cp->Text); + ++ h; + } + } + return vmgt; +} + + + + +VMENU * VMENU::Addr = NULL; +int VMENU::Recent = -1; + + + + +VMENU::VMENU (CHOICE * list, int x, int y) +: TALK(VMGather(list), RECT), Menu(list), Bar(NULL) +{ + CHOICE * cp; + + Addr = this; + delete[] vmgt; + Items = 0; + for (cp = list; cp->Text; cp ++) ++ Items; + Flags.BDel = TRUE; + Flags.Kill = TRUE; + if (x < 0 || y < 0) Center(); + else Goto(x - W / 2, y - (TEXT_VM + FONT_HIG / 2)); + VGA::ShowQ.Insert(this, VGA::ShowQ.Last()); + Bar = new MENU_BAR(W - 2 * TEXT_HM); + Bar->Goto(X + TEXT_HM - MB_HM, Y + TEXT_VM - MB_VM); + VGA::ShowQ.Insert(Bar, VGA::ShowQ.Last()); +} + + + + +VMENU::~VMENU (void) +{ + Addr = NULL; +} + + + + +void VMENU::Touch (word mask, int x, int y) +{ +#define h (FONT_HIG+TEXT_LS) + int n = 0; + Boolean ok = FALSE; + + if (Items) + { + SPRITE::Touch(mask, x, y); + + y -= TEXT_VM-1; + //if + if (y >= 0) + { + n = y / h; + if (n < Items) ok = (x >= TEXT_HM && x < W - TEXT_HM/* && y % h < FONT_HIG*/); + else n = Items-1; + } + + Bar->Goto(X + TEXT_HM - MB_HM, Y + TEXT_VM + n * h - MB_VM); + + if (ok && (mask & L_UP)) + { + Items = 0; + SNPOST_(SNKILL, -1, 0, this); + Menu[Recent = n].Proc(); + } + } +#undef h +} + + + diff --git a/engines/cge/vmenu.h b/engines/cge/vmenu.h new file mode 100644 index 0000000000..c4d3a8df18 --- /dev/null +++ b/engines/cge/vmenu.h @@ -0,0 +1,45 @@ +#ifndef __VMENU__ +#define __VMENU__ + +#include "talk.h" + +#define MB_VM 1 +#define MB_HM 3 + + + +typedef struct { char * Text; void (* Proc)(void); } CHOICE; + + + + + + +class MENU_BAR : public TALK +{ +public: + MENU_BAR (word w); +}; + + + + + + + +class VMENU : public TALK +{ + word Items; + CHOICE * Menu; +public: + static VMENU * Addr; + static int Recent; + MENU_BAR * Bar; + VMENU (CHOICE * list, int x, int y); + ~VMENU (void); + void Touch (word mask, int x, int y); +}; + + + +#endif diff --git a/engines/cge/vol.cpp b/engines/cge/vol.cpp new file mode 100644 index 0000000000..d0d8dce35c --- /dev/null +++ b/engines/cge/vol.cpp @@ -0,0 +1,79 @@ +#include "vol.h" +#include <alloc.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#ifdef DROP_H + #include "drop.h" +#else + #include <stdio.h> + #define DROP(m,n) { printf("%s [%s]\n", (m), (n)); _exit(1); } +#endif + + + + +#ifdef VOL_UPD +BTFILE VFILE::Cat(CAT_NAME, UPD, CRP); +VOLBASE DAT::File(DAT_NAME, UPD, CRP); +#else +BTFILE VFILE::Cat(CAT_NAME, REA, CRP); +VOLBASE DAT::File(DAT_NAME, REA, CRP); +#endif +DAT VFILE::Dat; +VFILE * VFILE::Recent = NULL; + + + + + +VFILE::VFILE (const char * name, IOMODE mode) +: IOBUF(mode) +{ + if (mode == REA) + { + if (Dat.File.Error || Cat.Error) DROP("Bad volume data", NULL); + BT_KEYPACK far * kp = Cat.Find(name); + if (_fstricmp(kp->Key, name) != 0) Error = ENOFILE; + EndMark = (BufMark = BegMark = kp->Mark) + kp->Size; + } + #ifdef VOL_UPD + else Make(name); + #endif +} + + + + + +VFILE::~VFILE (void) +{ + if (Recent == this) Recent = NULL; +} + + + + + +Boolean VFILE::Exist (const char * name) +{ + return _fstricmp(Cat.Find(name)->Key, name) == 0; +} + + + + +void VFILE::ReadBuff (void) +{ + if (Recent != this) + { + Dat.File.Seek(BufMark + Lim); + Recent = this; + } + BufMark = Dat.File.Mark(); + long n = EndMark - BufMark; + if (n > IOBUF_SIZE) n = IOBUF_SIZE; + Lim = Dat.File.Read(Buff, (word) n); + Ptr = 0; +} diff --git a/engines/cge/vol.h b/engines/cge/vol.h new file mode 100644 index 0000000000..347b0b48fe --- /dev/null +++ b/engines/cge/vol.h @@ -0,0 +1,64 @@ +#ifndef __VOL__ +#define __VOL__ + + +#include <dir.h> +#include "btfile.h" +#include "cfile.h" + +#define CAT_NAME "VOL.CAT" +#define DAT_NAME "VOL.DAT" + +#ifndef CRP + #define CRP XCrypt +#endif + +#define XMASK 0xA5 + +#ifdef VOL_UPD +#define VOLBASE IOHAND +#else +#define VOLBASE CFILE +#endif + + + +class DAT +{ + friend VFILE; + static VOLBASE File; +public: + static Boolean Append (byte far * buf, word len); + static Boolean Write (CFILE& f); + static Boolean Read (long org, word len, byte far * buf); +}; + + + + + + + +class VFILE : public IOBUF +{ + static DAT Dat; + static BTFILE Cat; + static VFILE * Recent; + long BegMark, EndMark; + void ReadBuff (void); + void WriteBuff (void) { } + void Make(const char * fspec); +public: + VFILE (const char * name, IOMODE mode = REA); + ~VFILE (void); + static Boolean Exist (const char * name); + static const char * Next (void); + long Mark (void) { return (BufMark+Ptr) - BegMark; } + long Size (void) { return EndMark - BegMark; } + long Seek (long pos) { Recent = NULL; Lim = 0; return (BufMark = BegMark+pos); } +}; + + + + +#endif diff --git a/engines/cge/wav.h b/engines/cge/wav.h new file mode 100644 index 0000000000..c32178420c --- /dev/null +++ b/engines/cge/wav.h @@ -0,0 +1,109 @@ +#ifndef __WAV__ +#define __WAV__ + +#include <general.h> +#include <string.h> + +#define WAVE_FORMAT_PCM 0x0001 +#define IBM_FORMAT_MULAW 0x0101 +#define IBM_FORMAT_ALAW 0x0102 +#define IBM_FORMAT_ADPCM 0x0103 + + + +typedef char FOURCC[4]; // Four-character code +typedef dword CKSIZE; // 32-bit unsigned size + + +class CKID // Chunk type identifier +{ + union { FOURCC Tx; dword Id; }; +protected: + static XFILE * ckFile; +public: + CKID (FOURCC t) { memcpy(Tx, t, sizeof(Tx)); } + CKID (dword d) { Id = d; } + CKID (XFILE * xf) { (ckFile = xf)->Read(Tx, sizeof(Tx)); } + Boolean operator !=(CKID& X) { return Id != X.Id; } + Boolean operator ==(CKID& X) { return Id == X.Id; } + const char * Name (void); +}; + + + + +class CKHEA : public CKID +{ +protected: + CKSIZE ckSize; // Chunk size field (size of ckData) +public: + CKHEA (XFILE * xf) : CKID(xf) { XRead(xf, &ckSize); } + CKHEA (char id[]) : CKID(id), ckSize(0) { } + void Skip (void); + CKSIZE Size (void) { return ckSize; } +}; + + + + + +class FMTCK : public CKHEA +{ + struct WAV + { + word wFormatTag; // Format category + word wChannels; // Number of channels + dword dwSamplesPerSec; // Sampling rate + dword dwAvgBytesPerSec; // For buffer estimation + word wBlockAlign; // Data block size + } Wav; + + union + { + struct PCM + { + word wBitsPerSample; // Sample size + } Pcm; + }; +public: + FMTCK (CKHEA& hea); + inline word Channels (void) { return Wav.wChannels; } + inline dword SmplRate (void) { return Wav.dwSamplesPerSec; } + inline dword ByteRate (void) { return Wav.dwAvgBytesPerSec; } + inline word BlckSize (void) { return Wav.wBlockAlign; } + inline word SmplSize (void) { return Pcm.wBitsPerSample; } +}; + + + + + +class DATACK : public CKHEA +{ + Boolean e; + union + { + byte far * Buf; + EMS * EBuf; + }; +public: + DATACK (CKHEA& hea); + DATACK (CKHEA& hea, EMM * emm); + DATACK (int first, int last); + ~DATACK (void); + inline byte far * Addr (void) { return Buf; } + inline EMS * EAddr (void) { return EBuf; } +}; + + + +extern CKID RIFF; +extern CKID WAVE; +extern CKID FMT; +extern CKID DATA; + + +DATACK * LoadWave (XFILE * file, EMM * emm = NULL); + + +#endif |