aboutsummaryrefslogtreecommitdiff
path: root/engines/cge
diff options
context:
space:
mode:
authorStrangerke2011-06-09 08:20:53 +0200
committerStrangerke2011-06-09 08:20:53 +0200
commit01a7e7ad60819d247bfe815a8e2183a46c1c6437 (patch)
treea6804eb46237c112e25d234eaa120abace293556 /engines/cge
parentc545ebd0d5d1b0690e16f7472048e7ffde40d934 (diff)
downloadscummvm-rg350-01a7e7ad60819d247bfe815a8e2183a46c1c6437.tar.gz
scummvm-rg350-01a7e7ad60819d247bfe815a8e2183a46c1c6437.tar.bz2
scummvm-rg350-01a7e7ad60819d247bfe815a8e2183a46c1c6437.zip
CGE: Add several sources based on headers
Diffstat (limited to 'engines/cge')
-rw-r--r--engines/cge/bitmap.cpp433
-rw-r--r--engines/cge/bitmap.h60
-rw-r--r--engines/cge/bitmaps.cpp214
-rw-r--r--engines/cge/bitmaps.h18
-rw-r--r--engines/cge/boot.h49
-rw-r--r--engines/cge/cfile.cpp332
-rw-r--r--engines/cge/cfile.h56
-rw-r--r--engines/cge/cge.cpp5
-rw-r--r--engines/cge/cge.h2
-rw-r--r--engines/cge/cge_main.cpp2232
-rw-r--r--engines/cge/cge_main.h181
-rw-r--r--engines/cge/drop.h1
-rw-r--r--engines/cge/game.cpp91
-rw-r--r--engines/cge/game.h40
-rw-r--r--engines/cge/general.h241
-rw-r--r--engines/cge/gettext.cpp110
-rw-r--r--engines/cge/gettext.h35
-rw-r--r--engines/cge/ident.h14
-rw-r--r--engines/cge/jbw.h149
-rw-r--r--engines/cge/keybd.cpp114
-rw-r--r--engines/cge/keybd.h31
-rw-r--r--engines/cge/mixer.cpp129
-rw-r--r--engines/cge/mixer.h31
-rw-r--r--engines/cge/module.mk19
-rw-r--r--engines/cge/mouse.cpp207
-rw-r--r--engines/cge/mouse.h58
-rw-r--r--engines/cge/snail.cpp1280
-rw-r--r--engines/cge/snail.h98
-rw-r--r--engines/cge/snddrv.h104
-rw-r--r--engines/cge/sound.cpp293
-rw-r--r--engines/cge/sound.h61
-rw-r--r--engines/cge/startup.cpp168
-rw-r--r--engines/cge/startup.h52
-rw-r--r--engines/cge/talk.cpp376
-rw-r--r--engines/cge/talk.h81
-rw-r--r--engines/cge/text.cpp291
-rw-r--r--engines/cge/text.h60
-rw-r--r--engines/cge/vga13h.cpp1775
-rw-r--r--engines/cge/vga13h.h310
-rw-r--r--engines/cge/vmenu.cpp149
-rw-r--r--engines/cge/vmenu.h45
-rw-r--r--engines/cge/vol.cpp79
-rw-r--r--engines/cge/vol.h64
-rw-r--r--engines/cge/wav.h109
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