aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base/plugins.cpp3
-rwxr-xr-xconfigure1
-rw-r--r--engines/cge/bitmap.cpp483
-rw-r--r--engines/cge/bitmap.h97
-rw-r--r--engines/cge/bitmaps.cpp229
-rw-r--r--engines/cge/bitmaps.h44
-rw-r--r--engines/cge/boot.h79
-rw-r--r--engines/cge/btfile.cpp151
-rw-r--r--engines/cge/btfile.h92
-rw-r--r--engines/cge/cfile.cpp262
-rw-r--r--engines/cge/cfile.h79
-rw-r--r--engines/cge/cge.cpp164
-rw-r--r--engines/cge/cge.h108
-rw-r--r--engines/cge/cge_main.cpp1874
-rw-r--r--engines/cge/cge_main.h196
-rw-r--r--engines/cge/config.cpp282
-rw-r--r--engines/cge/config.h37
-rw-r--r--engines/cge/console.cpp34
-rw-r--r--engines/cge/console.h43
-rw-r--r--engines/cge/detection.cpp238
-rw-r--r--engines/cge/ems.cpp225
-rw-r--r--engines/cge/game.cpp92
-rw-r--r--engines/cge/game.h59
-rw-r--r--engines/cge/general.cpp420
-rw-r--r--engines/cge/general.h240
-rw-r--r--engines/cge/gettext.cpp122
-rw-r--r--engines/cge/gettext.h59
-rw-r--r--engines/cge/ident.h42
-rw-r--r--engines/cge/jbw.h156
-rw-r--r--engines/cge/keybd.cpp151
-rw-r--r--engines/cge/keybd.h63
-rw-r--r--engines/cge/mixer.cpp145
-rw-r--r--engines/cge/mixer.h61
-rw-r--r--engines/cge/module.mk39
-rw-r--r--engines/cge/mouse.cpp194
-rw-r--r--engines/cge/mouse.h85
-rw-r--r--engines/cge/snail.cpp1135
-rw-r--r--engines/cge/snail.h126
-rw-r--r--engines/cge/snddrv.h130
-rw-r--r--engines/cge/sound.cpp228
-rw-r--r--engines/cge/sound.h82
-rw-r--r--engines/cge/startup.cpp176
-rw-r--r--engines/cge/startup.h79
-rw-r--r--engines/cge/talk.cpp334
-rw-r--r--engines/cge/talk.h104
-rw-r--r--engines/cge/text.cpp259
-rw-r--r--engines/cge/text.h86
-rw-r--r--engines/cge/vga13h.cpp1391
-rw-r--r--engines/cge/vga13h.h346
-rw-r--r--engines/cge/vmenu.cpp156
-rw-r--r--engines/cge/vmenu.h69
-rw-r--r--engines/cge/vol.cpp111
-rw-r--r--engines/cge/vol.h98
-rw-r--r--engines/cge/wav.h152
-rw-r--r--engines/engines.mk5
55 files changed, 11716 insertions, 0 deletions
diff --git a/base/plugins.cpp b/base/plugins.cpp
index 4c2fd2cffc..46fd646563 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -94,6 +94,9 @@ public:
#if PLUGIN_ENABLED_STATIC(AGOS)
LINK_PLUGIN(AGOS)
#endif
+ #if PLUGIN_ENABLED_STATIC(CGE)
+ LINK_PLUGIN(CGE)
+ #endif
#if PLUGIN_ENABLED_STATIC(CINE)
LINK_PLUGIN(CINE)
#endif
diff --git a/configure b/configure
index 0443a2fb94..537b62d456 100755
--- a/configure
+++ b/configure
@@ -83,6 +83,7 @@ add_engine he "HE71+ games" yes
add_engine agi "AGI" yes
add_engine agos "AGOS" yes "agos2"
add_engine agos2 "AGOS 2 games" yes
+add_engine cge "CGE" no
add_engine cine "Cinematique evo 1" yes
add_engine cruise "Cinematique evo 2" yes
add_engine draci "Dragon History" yes
diff --git a/engines/cge/bitmap.cpp b/engines/cge/bitmap.cpp
new file mode 100644
index 0000000000..ab5c1ff3c7
--- /dev/null
+++ b/engines/cge/bitmap.cpp
@@ -0,0 +1,483 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/bitmap.h"
+#include "cge/cfile.h"
+#include "cge/jbw.h"
+#include "cge/vol.h"
+#include "cge/cfile.h"
+#include "cge/vga13h.h"
+#include "common/system.h"
+
+namespace CGE {
+
+DAC *Bitmap::Pal = NULL;
+#define MAXPATH 128
+
+void Bitmap::init() {
+ Pal = NULL;
+}
+
+void Bitmap::deinit() {
+}
+
+#pragma argsused
+Bitmap::Bitmap(const char *fname, bool 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) && (!VBMLoad(&file)))
+ error("Bad VBM [%s]", fname);
+ } else
+#endif
+ {
+#if (BMP_MODE)
+ ForceExt(pat, fname, ".BMP");
+ PIC_FILE file(pat);
+ if (file.Error == 0) {
+ if (BMPLoad(&file)) {
+ Code();
+ if (rem) {
+ free(_m);
+ _m = NULL;
+ }
+ } else
+ error("Bad BMP [%s]", fname);
+ }
+#else
+ error("Bad VBM [%s]", fname);
+#endif
+ }
+}
+
+
+Bitmap::Bitmap(uint16 w, uint16 h, uint8 *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(uint16 w, uint16 h, uint8 fill)
+ : _w((w + 3) & ~3), // only full uint32 allowed!
+ _h(h),
+ _m(NULL) {
+ uint16 dsiz = _w >> 2; // data size (1 plane line size)
+ uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap
+ uint16 psiz = _h * lsiz; // - last gape, but + plane trailer
+ uint8 *v = new uint8[4 * psiz + _h * sizeof(*_b)];// the same for 4 planes
+ // + room for wash table
+ if (v == NULL)
+ error("No core");
+
+ *(uint16 *) v = CPY | dsiz; // data chunk hader
+ memset(v + 2, fill, dsiz); // data bytes
+ *(uint16 *)(v + lsiz - 2) = SKP | ((SCR_WID / 4) - dsiz); // gap
+ memcpy(v + lsiz, v, psiz - lsiz); // tricky replicate lines
+ *(uint16 *)(v + psiz - 2) = EOI; // plane trailer uint16
+ 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) {
+ uint8 *v0 = bmp._v;
+ if (v0) {
+ uint16 vsiz = (uint8 *)(bmp._b) - (uint8 *)(v0);
+ uint16 siz = vsiz + _h * sizeof(HideDesc);
+ uint8 *v1 = farnew(uint8, siz);
+ if (v1 == NULL)
+ error("No core");
+ memcpy(v1, v0, siz);
+ _b = (HideDesc *)((_v = v1) + vsiz);
+ }
+}
+
+
+Bitmap::~Bitmap(void) {
+ if (MemType(_m) == FAR_MEM)
+ free(_m);
+
+ switch (MemType(_v)) {
+ case NEAR_MEM :
+ delete[](uint8 *) _v;
+ break;
+ case FAR_MEM :
+ free(_v);
+ default:
+ warning("Unhandled MemType in Bitmap destructor");
+ break;
+ break;
+ }
+}
+
+
+Bitmap &Bitmap::operator = (const Bitmap &bmp) {
+ uint8 *v0 = bmp._v;
+ _w = bmp._w;
+ _h = bmp._h;
+ _m = NULL;
+ if (MemType(_v) == FAR_MEM)
+ free(_v);
+ if (v0 == NULL)
+ _v = NULL;
+ else {
+ uint16 vsiz = (uint8 *)bmp._b - (uint8 *)v0;
+ uint16 siz = vsiz + _h * sizeof(HideDesc);
+ uint8 *v1 = farnew(uint8, siz);
+ if (v1 == NULL)
+ error("No core");
+ memcpy(v1, v0, siz);
+ _b = (HideDesc *)((_v = v1) + vsiz);
+ }
+ return *this;
+}
+
+
+uint16 Bitmap::MoveVmap(uint8 *buf) {
+ if (_v) {
+ uint16 vsiz = (uint8 *)_b - (uint8 *)_v;
+ uint16 siz = vsiz + _h * sizeof(HideDesc);
+ memcpy(buf, _v, siz);
+ if (MemType(_v) == FAR_MEM)
+ free(_v);
+ _b = (HideDesc *)((_v = buf) + vsiz);
+ return siz;
+ }
+ return 0;
+}
+
+
+BMP_PTR Bitmap::Code(void) {
+ if (_m) {
+ uint16 i, cnt;
+
+ if (_v) { // old X-map exists, so remove it
+ switch (MemType(_v)) {
+ case NEAR_MEM :
+ delete[](uint8 *) _v;
+ break;
+ case FAR_MEM :
+ free(_v);
+ break;
+ default:
+ warning("Unhandled MemType in Bitmap::Code()");
+ break;
+ }
+ _v = NULL;
+ }
+
+ while (true) { // at most 2 times: for (V == NULL) & for allocated block;
+ uint8 *im = _v + 2;
+ uint16 *cp = (uint16 *) _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
+ uint8 *bm = _m;
+ bool skip = (bm[bpl] == TRANS);
+ uint16 j;
+
+ cnt = 0;
+ for (i = 0; i < _h; i++) { // once per each line
+ uint8 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 uint16
+
+ cp = (uint16 *) 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 = (uint16 *) im;
+ im += 2;
+ skip = true;
+ cnt = (SCR_WID - j + 3) / 4;
+ }
+ }
+ }
+ if (cnt && ! skip) {
+ cnt |= CPY;
+ if (_v)
+ *cp = cnt;
+
+ cp = (uint16 *) im;
+ im += 2;
+ }
+ if (_v)
+ *cp = EOI;
+ cp = (uint16 *) im;
+ im += 2;
+ }
+ if (_v)
+ break;
+
+ uint16 sizV = (uint16)(im - 2 - _v);
+ _v = farnew(uint8, sizV + _h * sizeof(*_b));
+ if (!_v)
+ error("No core");
+
+ _b = (HideDesc *)(_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 {
+ uint16 s = _b[i].skip & ~3;
+ uint16 h = (_b[i].hide + 3) & ~3;
+ _b[i].skip = (cnt + s) >> 2;
+ _b[i].hide = (h - s) >> 2;
+ cnt = SCR_WID - h;
+ }
+ }
+ }
+ return this;
+}
+
+
+bool Bitmap::SolidAt(int x, int y) {
+ uint8 *m;
+ uint16 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) {
+ uint16 w, t;
+
+ w = *(uint16 *) 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) {
+ uint16 w, t;
+
+ w = *(uint16 *) 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);
+ }
+}
+
+
+bool Bitmap::VBMSave(XFILE *f) {
+ uint16 p = (Pal != NULL),
+ n = ((uint16)(((uint8 *)_b) - _v)) + _h * sizeof(HideDesc);
+ if (f->Error == 0)
+ f->Write((uint8 *)&p, sizeof(p));
+
+ if (f->Error == 0)
+ f->Write((uint8 *)&n, sizeof(n));
+
+ if (f->Error == 0)
+ f->Write((uint8 *)&_w, sizeof(_w));
+
+ if (f->Error == 0)
+ f->Write((uint8 *)&_h, sizeof(_h));
+
+ if (f->Error == 0)
+ if (p)
+ f->Write((uint8 *)Pal, 256 * 3);
+
+ if (f->Error == 0)
+ f->Write(_v, n);
+
+ return (f->Error == 0);
+}
+
+
+bool Bitmap::VBMLoad(XFILE *f) {
+ uint16 p = 0, n = 0;
+ if (f->Error == 0)
+ f->Read((uint8 *)&p, sizeof(p));
+
+ if (f->Error == 0)
+ f->Read((uint8 *)&n, sizeof(n));
+
+ if (f->Error == 0)
+ f->Read((uint8 *)&_w, sizeof(_w));
+
+ if (f->Error == 0)
+ f->Read((uint8 *)&_h, sizeof(_h));
+
+ if (f->Error == 0) {
+ if (p) {
+ if (Pal) {
+ byte palData[PAL_SIZ];
+ f->Read(palData, PAL_SIZ);
+ VGA::pal2DAC(palData, Pal);
+ } else
+ f->Seek(f->Mark() + PAL_SIZ);
+ }
+ }
+ if ((_v = farnew(uint8, n)) == NULL)
+ return false;
+
+ if (f->Error == 0)
+ f->Read(_v, n);
+
+ _b = (HideDesc *)(_v + n - _h * sizeof(HideDesc));
+ return (f->Error == 0);
+}
+
+bool Bitmap::BMPLoad (XFILE * f) {
+ struct {
+ char BM[2];
+ union { int16 len; int32 len_; };
+ union { int16 _06; int32 _06_; };
+ union { int16 hdr; int32 hdr_; };
+ union { int16 _0E; int32 _0E_; };
+ union { int16 wid; int32 wid_; };
+ union { int16 hig; int32 hig_; };
+ union { int16 _1A; int32 _1A_; };
+ union { int16 _1E; int32 _1E_; };
+ union { int16 _22; int32 _22_; };
+ union { int16 _26; int32 _26_; };
+ union { int16 _2A; int32 _2A_; };
+ union { int16 _2E; int32 _2E_; };
+ union { int16 _32; int32 _32_; };
+ } hea;
+ BGR4 bpal[256];
+
+ f->Read((byte *)&hea, sizeof(hea));
+ if (f->Error == 0) {
+ if (hea.hdr == 0x436L) {
+ int16 i = (hea.hdr - sizeof(hea)) / sizeof(BGR4);
+ f->Read((byte *)&bpal, sizeof(bpal));
+ if (f->Error == 0) {
+ if (Pal) {
+ for (i = 0; i < 256; i ++) {
+ Pal[i].R = bpal[i].R;
+ Pal[i].G = bpal[i].G;
+ Pal[i].B = bpal[i].B;
+ }
+ Pal = NULL;
+ }
+ _h = hea.hig;
+ _w = hea.wid;
+ if ((_m = farnew(byte, _h * _w)) != NULL) {
+ int16 r = (4 - (hea.wid & 3)) % 4;
+ byte buf[3]; int i;
+ for (i = _h - 1; i >= 0; i--) {
+ f->Read(_m + (_w * i), _w);
+ if (r && f->Error == 0)
+ f->Read(buf, r);
+ if (f->Error)
+ break;
+ }
+ if (i < 0)
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/bitmap.h b/engines/cge/bitmap.h
new file mode 100644
index 0000000000..cfa7830f39
--- /dev/null
+++ b/engines/cge/bitmap.h
@@ -0,0 +1,97 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __BITMAP__
+#define __BITMAP__
+
+#include "cge/general.h"
+
+namespace CGE {
+
+#define EOI 0x0000
+#define SKP 0x4000
+#define REP 0x8000
+#define CPY 0xC000
+
+#define TRANS 0xFE
+
+#include "common/pack-start.h"
+
+struct BGR4 {
+ uint16 b : 2;
+ uint16 B : 6;
+ uint16 g : 2;
+ uint16 G : 6;
+ uint16 r : 2;
+ uint16 R : 6;
+ uint16 Z : 8;
+};
+
+
+struct HideDesc {
+ uint16 skip;
+ uint16 hide;
+};
+
+#include "common/pack-end.h"
+
+class Bitmap {
+ bool BMPLoad(XFILE *f);
+ bool VBMLoad(XFILE *f);
+public:
+ static DAC *Pal;
+ uint16 _w;
+ uint16 _h;
+ uint8 *_m;
+ uint8 *_v;
+ HideDesc *_b;
+
+ Bitmap(const char *fname, bool rem = true);
+ Bitmap(uint16 w, uint16 h, uint8 *map);
+ Bitmap(uint16 w, uint16 h, uint8 fill);
+ Bitmap(const Bitmap &bmp);
+ ~Bitmap(void);
+ static void init();
+ static void deinit();
+
+ 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);
+ bool SolidAt(int x, int y);
+ bool VBMSave(XFILE *f);
+ uint16 MoveVmap(uint8 *buf);
+};
+
+
+typedef Bitmap *BMP_PTR;
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/bitmaps.cpp b/engines/cge/bitmaps.cpp
new file mode 100644
index 0000000000..5e8757ae73
--- /dev/null
+++ b/engines/cge/bitmaps.cpp
@@ -0,0 +1,229 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/bitmaps.h"
+/*
+
+#define W 255,
+#define x 252,
+#define _ TRANS,
+#define o 0,
+#define L LGRAY,
+#define G GRAY,
+#define D DGRAY,
+
+static uint8 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 uint8 MCDesign1[]= { _ };
+
+
+
+static uint8 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 uint8 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 uint8 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 uint8 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 uint8 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 uint8 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 uint8 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 uint8 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
+*/
+
+namespace CGE {
+
+
+
+} // End of namespace CGE
diff --git a/engines/cge/bitmaps.h b/engines/cge/bitmaps.h
new file mode 100644
index 0000000000..40b1158b21
--- /dev/null
+++ b/engines/cge/bitmaps.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __BITMAPS__
+#define __BITMAPS__
+
+#include "cge/vga13h.h"
+
+namespace CGE {
+
+extern Bitmap *MB[];
+extern Bitmap *HL[];
+extern Bitmap *MC[];
+extern Bitmap *PR[];
+extern Bitmap *SP[];
+extern Bitmap *LI[];
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/boot.h b/engines/cge/boot.h
new file mode 100644
index 0000000000..ab4dcde0e2
--- /dev/null
+++ b/engines/cge/boot.h
@@ -0,0 +1,79 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __BOOT__
+#define __BOOT__
+
+#include "cge/jbw.h"
+
+namespace CGE {
+
+#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 {
+ uint8 Jmp[3]; // NEAR jump machine code
+ char OEM_ID[8]; // OEM name and version
+ uint16 SectSize; // bytes per sector
+ uint8 ClustSize; // sectors per cluster
+ uint16 ResSecs; // sectors before 1st FAT
+ uint8 FatCnt; // number of FATs
+ uint16 RootSize; // root directory entries
+ uint16 TotSecs; // total sectors on disk
+ uint8 Media; // media descriptor byte
+ uint16 FatSize; // sectors per FAT
+ uint16 TrkSecs; // sectors per track
+ uint16 HeadCnt; // number of sufraces
+ uint16 HidnSecs; // special hidden sectors
+ uint16 _; // (unknown: reserved?)
+ uint32 lTotSecs; // total number of sectors
+ uint16 DriveNum; // physical drive number
+ uint8 XSign; // extended boot signature
+ uint32 Serial; // volume serial number
+ char Label[11]; // volume label
+ char FileSysID[8]; // file system ID
+ char Code[BOOTCODE_SIZ - 8]; // 8 = length of following
+ uint32 Secret; // long secret number
+ uint8 BootCheck; // boot sector checksum
+ uint8 BootFlags; // secret flags
+ uint16 BootSig; // boot signature 0xAA55
+} Boot;
+
+
+EC Boot *ReadBoot(int drive);
+EC uint8 CheckBoot(Boot *boot);
+EC bool WriteBoot(int drive, Boot *boot);
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/btfile.cpp b/engines/cge/btfile.cpp
new file mode 100644
index 0000000000..db0ebc2d5f
--- /dev/null
+++ b/engines/cge/btfile.cpp
@@ -0,0 +1,151 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/btfile.h"
+#include "common/system.h"
+#include "common/str.h"
+#include <string.h>
+
+namespace CGE {
+
+#ifndef BT_SIZE
+#define BT_SIZE K(1)
+#endif
+
+#ifndef BT_KEYLEN
+#define BT_KEYLEN 13
+#endif
+
+BTFILE::BTFILE(const char *name, IOMODE mode, CRYPT *crpt)
+ : IOHAND(name, mode, crpt) {
+ for (int i = 0; i < BT_LEVELS; i++) {
+ Buff[i].Page = new BT_PAGE;
+ Buff[i].PgNo = BT_NONE;
+ Buff[i].Indx = -1;
+ Buff[i].Updt = false;
+ if (Buff[i].Page == NULL)
+ error("No core");
+ }
+}
+
+
+BTFILE::~BTFILE(void) {
+ for (int i = 0; i < BT_LEVELS; i++) {
+ PutPage(i);
+ delete Buff[i].Page;
+ }
+}
+
+
+void BTFILE::PutPage(int lev, bool hard) {
+ if (hard || Buff[lev].Updt) {
+ Seek(Buff[lev].PgNo * sizeof(BT_PAGE));
+ Write((uint8 *) Buff[lev].Page, sizeof(BT_PAGE));
+ Buff[lev].Updt = false;
+ }
+}
+
+
+BT_PAGE *BTFILE::GetPage(int lev, uint16 pgn) {
+ if (Buff[lev].PgNo != pgn) {
+ int32 pos = pgn * sizeof(BT_PAGE);
+ PutPage(lev);
+ Buff[lev].PgNo = pgn;
+ if (Size() > pos) {
+ Seek((uint32) pgn * sizeof(BT_PAGE));
+ Read((uint8 *) Buff[lev].Page, sizeof(BT_PAGE));
+ Buff[lev].Updt = false;
+ } else {
+ Buff[lev].Page->Hea.Count = 0;
+ Buff[lev].Page->Hea.Down = BT_NONE;
+ memset(Buff[lev].Page->Data, '\0', sizeof(Buff[lev].Page->Data));
+ Buff[lev].Updt = true;
+ }
+ Buff[lev].Indx = -1;
+ }
+ return Buff[lev].Page;
+}
+
+BT_KEYPACK *BTFILE::Find(const char *key) {
+ int lev = 0;
+ uint16 nxt = BT_ROOT;
+ while (! Error) {
+ BT_PAGE *pg = GetPage(lev, nxt);
+ // search
+ if (pg->Hea.Down != BT_NONE) {
+ int i;
+ for (i = 0; i < pg->Hea.Count; i++) {
+ // Does this work, or does it have to compare the entire buffer?
+ if (scumm_strnicmp((const char *) key, (const char*)pg->Inn[i].Key, BT_KEYLEN) < 0)
+ break;
+ }
+ nxt = (i) ? pg->Inn[i - 1].Down : pg->Hea.Down;
+ Buff[lev].Indx = i - 1;
+ ++ lev;
+ } else {
+ int i;
+ for (i = 0; i < pg->Hea.Count - 1; i++) {
+ if (scumm_stricmp((const char *)key, (const char *)pg->Lea[i].Key) <= 0)
+ break;
+ }
+ Buff[lev].Indx = i;
+ return &pg->Lea[i];
+ }
+ }
+ return NULL;
+}
+
+
+int keycomp(const void *k1, const void *k2) {
+ return scumm_strnicmp((const char *) k1, (const char*) k2, BT_KEYLEN);
+}
+
+
+void BTFILE::Make(BT_KEYPACK *keypack, uint16 count) {
+#if BT_LEVELS != 2
+#error This tiny BTREE implementation works with exactly 2 levels!
+#endif
+ _fqsort(keypack, count, sizeof(*keypack), keycomp);
+ uint16 n = 0;
+ BT_PAGE *Root = GetPage(0, n++),
+ *Leaf = GetPage(1, n);
+ Root->Hea.Down = n;
+ PutPage(0, true);
+ while (count--) {
+ if (Leaf->Hea.Count >= ArrayCount(Leaf->Lea)) {
+ PutPage(1, true); // save filled page
+ Leaf = GetPage(1, ++n); // take empty page
+ memcpy(Root->Inn[Root->Hea.Count].Key, keypack->Key, BT_KEYLEN);
+ Root->Inn[Root->Hea.Count++].Down = n;
+ Buff[0].Updt = true;
+ }
+ Leaf->Lea[Leaf->Hea.Count++] = *(keypack++);
+ Buff[1].Updt = true;
+ }
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/btfile.h b/engines/cge/btfile.h
new file mode 100644
index 0000000000..449f200140
--- /dev/null
+++ b/engines/cge/btfile.h
@@ -0,0 +1,92 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __BTFILE__
+#define __BTFILE__
+
+#include "cge/general.h"
+
+namespace CGE {
+
+#define BT_SIZE K(1)
+#define BT_KEYLEN 13
+#define BT_LEVELS 2
+
+#define BT_NONE 0xFFFF
+#define BT_ROOT 0
+
+#include "common/pack-start.h" // START STRUCT PACKING
+
+struct BT_KEYPACK {
+ char Key[BT_KEYLEN];
+ uint32 Mark;
+ uint16 Size;
+};
+
+typedef struct {
+ uint8 Key[BT_KEYLEN];
+ uint16 Down;
+} INNER;
+
+struct BT_PAGE {
+ struct HEA {
+ uint16 Count;
+ uint16 Down;
+ } Hea;
+ union {
+ // dummy filler to make proper size of union
+ uint8 Data[BT_SIZE - sizeof(HEA)];
+ // inner version of data: key + word-sized page link
+ INNER Inn[(BT_SIZE - sizeof(HEA)) / sizeof(INNER)];
+ // leaf version of data: key + all user data
+ BT_KEYPACK Lea[(BT_SIZE - sizeof(HEA)) / sizeof(BT_KEYPACK)];
+ };
+};
+
+#include "common/pack-end.h" // END STRUCT PACKING
+
+
+class BTFILE : public IOHAND {
+ struct {
+ BT_PAGE *Page;
+ uint16 PgNo;
+ int Indx;
+ bool Updt;
+ } Buff[BT_LEVELS];
+ void PutPage(int lev, bool hard = false);
+ BT_PAGE *GetPage(int lev, uint16 pgn);
+public:
+ BTFILE(const char *name, IOMODE mode = REA, CRYPT *crpt = NULL);
+ virtual ~BTFILE(void);
+ BT_KEYPACK *Find(const char *key);
+ BT_KEYPACK *Next(void);
+ void Make(BT_KEYPACK *keypack, uint16 count);
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/cfile.cpp b/engines/cge/cfile.cpp
new file mode 100644
index 0000000000..85e51a94c1
--- /dev/null
+++ b/engines/cge/cfile.cpp
@@ -0,0 +1,262 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/cfile.h"
+#include <fcntl.h>
+#include <string.h>
+#include "common/system.h"
+
+namespace CGE {
+
+IOBUF::IOBUF(IOMODE mode, CRYPT *crpt)
+ : IOHAND(mode, crpt),
+ BufMark(0),
+ Ptr(0),
+ Lim(0) {
+ Buff = farnew(uint8, IOBUF_SIZE);
+ if (Buff == NULL)
+ error("No core for I/O");
+}
+
+
+IOBUF::IOBUF(const char *name, IOMODE mode, CRYPT *crpt)
+ : IOHAND(name, mode, crpt),
+ BufMark(0),
+ Ptr(0),
+ Lim(0) {
+ Buff = farnew(uint8, IOBUF_SIZE);
+ if (Buff == NULL)
+ error("No core for I/O [%s]", name);
+}
+
+IOBUF::~IOBUF(void) {
+ if (Mode > REA)
+ WriteBuff();
+ if (Buff)
+ free(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;
+ }
+}
+
+
+uint16 IOBUF::Read(void *buf, uint16 len) {
+ uint16 total = 0;
+ while (len) {
+ if (Ptr >= Lim)
+ ReadBuff();
+ uint16 n = Lim - Ptr;
+ if (n) {
+ if (len < n)
+ n = len;
+ memcpy(buf, Buff + Ptr, n);
+ buf = (uint8 *)buf + n;
+ len -= n;
+ total += n;
+ Ptr += n;
+ } else
+ break;
+ }
+ return total;
+}
+
+
+uint16 IOBUF::Read(uint8 *buf) {
+ uint16 total = 0;
+
+ while (total < LINE_MAX - 2) {
+ if (Ptr >= Lim)
+ ReadBuff();
+ uint8 *p = Buff + Ptr;
+ uint16 n = Lim - Ptr;
+ if (n) {
+ if (total + n >= LINE_MAX - 2)
+ n = LINE_MAX - 2 - total;
+ uint8 *eol = (uint8 *) memchr(p, '\r', n);
+ if (eol)
+ n = (uint16)(eol - p);
+ uint8 *eof = (uint8 *) memchr(p, '\32', n);
+ if (eof) { // end-of-file
+ n = (uint16)(eof - p);
+ Ptr = (uint16)(eof - Buff);
+ }
+ if (n)
+ memcpy(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;
+}
+
+
+uint16 IOBUF::Write(void *buf, uint16 len) {
+ uint16 tot = 0;
+ while (len) {
+ uint16 n = IOBUF_SIZE - Lim;
+ if (n > len)
+ n = len;
+ if (n) {
+ memcpy(Buff + Lim, buf, n);
+ Lim += n;
+ len -= n;
+ buf = (uint8 *)buf + n;
+ tot += n;
+ } else
+ WriteBuff();
+ }
+ return tot;
+}
+
+
+uint16 IOBUF::Write(uint8 *buf) {
+ uint16 len = 0;
+ if (buf) {
+ len = strlen((const char *) buf);
+ if (len)
+ if (buf[len - 1] == '\n')
+ --len;
+ len = Write(buf, len);
+ if (len) {
+ static char EOL[] = "\r\n";
+ uint16 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(uint8 b) {
+ if (Lim >= IOBUF_SIZE)
+ WriteBuff();
+ Buff[Lim++] = b;
+}
+
+
+uint16 CFILE::MaxLineLen = LINE_MAX;
+
+
+CFILE::CFILE(const char *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
+ */
+ warning("FIXME: CFILE::Flush");
+}
+
+
+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) = (uint16)(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;
+ }
+ }
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/cfile.h b/engines/cge/cfile.h
new file mode 100644
index 0000000000..f045c48c0f
--- /dev/null
+++ b/engines/cge/cfile.h
@@ -0,0 +1,79 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __CFILE__
+#define __CFILE__
+
+#include "cge/general.h"
+
+namespace CGE {
+
+#define LINE_MAX 512
+
+#ifndef IOBUF_SIZE
+#define IOBUF_SIZE K(2)
+#endif
+
+#define CFREAD(x) Read((uint8 *)(x),sizeof(*(x)))
+
+
+class IOBUF : public IOHAND {
+protected:
+ uint8 *Buff;
+ uint16 Ptr, Lim;
+ long BufMark;
+ uint16 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);
+ uint16 Read(void *buf, uint16 len);
+ uint16 Read(uint8 *buf);
+ int Read(void);
+ uint16 Write(void *buf, uint16 len);
+ uint16 Write(uint8 *buf);
+ void Write(uint8 b);
+};
+
+
+class CFILE : public IOBUF {
+public:
+ static uint16 MaxLineLen;
+ CFILE(const char *name, IOMODE mode = REA, CRYPT *crpt = NULL);
+ virtual ~CFILE(void);
+ void Flush(void);
+ long Mark(void);
+ long Seek(long pos);
+ void Append(CFILE &f);
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/cge.cpp b/engines/cge/cge.cpp
new file mode 100644
index 0000000000..885aa4d492
--- /dev/null
+++ b/engines/cge/cge.cpp
@@ -0,0 +1,164 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/error.h"
+#include "common/EventRecorder.h"
+#include "common/file.h"
+#include "common/fs.h"
+#include "engines/util.h"
+#include "cge/cge.h"
+#include "cge/vga13h.h"
+#include "cge/cge_main.h"
+#include "cge/talk.h"
+#include "cge/text.h"
+#include "cge/bitmaps.h"
+#include "cge/vol.h"
+
+
+namespace CGE {
+
+CGEEngine::CGEEngine(OSystem *syst, const ADGameDescription *gameDescription)
+ : Engine(syst), _gameDescription(gameDescription) {
+
+ // Debug/console setup
+ DebugMan.addDebugChannel(kCGEDebug, "general", "CGE general debug channel");
+
+ _isDemo = _gameDescription->flags & ADGF_DEMO;
+
+}
+
+void CGEEngine::setup() {
+ // Create debugger console
+ _console = new CGEConsole(this);
+
+ // Initialise classes that have static members
+ VGA::init();
+ VFILE::init();
+ Bitmap::init();
+ TALK::init();
+
+ // Initialise engine objects
+ Text = new TEXT(this, ProgName(), 128);
+ Vga = new VGA(M13H);
+ _heart = new Heart;
+ Hero = new WALK(this, NULL);
+ Sys = new SYSTEM(this);
+ _pocLight = new Sprite(this, LI);
+ Mouse = new MOUSE(this);
+ for (int i = 0; i < POCKET_NX; i++)
+ _pocket[i] = new Sprite(this, NULL);
+ _sprite = new Sprite(this, NULL);
+ _miniCave = new Sprite(this, NULL);
+ _shadow = new Sprite(this, NULL);
+ _horzLine = new Sprite(this, HL);
+ InfoLine = new INFO_LINE(this, INFO_W);
+ _cavLight = new Sprite(this, PR);
+ DebugLine = new INFO_LINE(this, SCR_WID);
+ MB[0] = new Bitmap("BRICK");
+ MB[1] = NULL;
+ HL[0] = new Bitmap("HLINE");
+ HL[1] = NULL;
+ MC[0] = new Bitmap("MOUSE");
+ MC[1] = new Bitmap("DUMMY");
+ MC[2] = NULL;
+ PR[0] = new Bitmap("PRESS");
+ PR[1] = NULL;
+ SP[0] = new Bitmap("SPK_L");
+ SP[1] = new Bitmap("SPK_R");
+ SP[2] = NULL;
+ LI[0] = new Bitmap("LITE0");
+ LI[1] = new Bitmap("LITE1");
+ LI[2] = new Bitmap("LITE2");
+ LI[3] = new Bitmap("LITE3");
+ LI[4] = NULL;
+ Snail = new SNAIL(this, false);
+ Snail_ = new SNAIL(this, true);
+
+ OffUseCount = atoi(Text->getText(OFF_USE_COUNT));
+}
+
+CGEEngine::~CGEEngine() {
+ debug("CGEEngine::~CGEEngine");
+
+ // Call classes with static members to clear them up
+ TALK::deinit();
+ Bitmap::deinit();
+ VFILE::deinit();
+ VGA::deinit();
+
+ // Remove all of our debug levels here
+ DebugMan.clearAllDebugChannels();
+
+ _console = new CGEConsole(this);
+
+ // Delete engine objects
+ delete Text;
+ delete Vga;
+ delete _heart;
+ delete Hero;
+ delete Sys;
+ delete _pocLight;
+ delete Mouse;
+ for (int i = 0; i < POCKET_NX; i++)
+ delete _pocket[i];
+ delete _sprite;
+ delete _miniCave;
+ delete _shadow;
+ delete _horzLine;
+ delete InfoLine;
+ delete _cavLight;
+ delete DebugLine;
+ delete MB[0];
+ delete HL[0];
+ delete MC[0];
+ delete MC[1];
+ delete PR[0];
+ delete SP[0];
+ delete SP[1];
+ delete LI[0];
+ delete LI[1];
+ delete LI[2];
+ delete LI[3];
+ delete Snail;
+ delete Snail_;
+}
+
+Common::Error CGEEngine::run() {
+ // Initialize graphics using following:
+ initGraphics(320, 200, false);
+
+ // Setup necessary game objects
+ setup();
+
+ // Additional setup.
+ debug("CGEEngine::init");
+
+ cge_main();
+
+ return Common::kNoError;
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/cge.h b/engines/cge/cge.h
new file mode 100644
index 0000000000..c3f241b2fe
--- /dev/null
+++ b/engines/cge/cge.h
@@ -0,0 +1,108 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+#ifndef CGE_H
+#define CGE_H
+
+#include "cge/general.h"
+#include "common/random.h"
+#include "engines/engine.h"
+#include "gui/debugger.h"
+#include "graphics/surface.h"
+#include "engines/advancedDetector.h"
+#include "cge/console.h"
+
+#define CGE_SAVEGAME_VERSION 1
+
+namespace CGE {
+
+class Console;
+
+// our engine debug channels
+enum {
+ kCGEDebug = 1 << 0
+};
+
+class CGEEngine : public Engine {
+public:
+ CGEEngine(OSystem *syst, const ADGameDescription *gameDescription);
+ ~CGEEngine();
+
+ const ADGameDescription *_gameDescription;
+ bool _isDemo;
+
+ virtual Common::Error run();
+ GUI::Debugger *getDebugger() {
+ return _console;
+ }
+
+ void cge_main();
+ void SwitchCave(int cav);
+ void StartCountDown();
+ void Quit();
+ void ResetQSwitch();
+ void OptionTouch(int opt, uint16 mask);
+ void LoadGame(XFILE &file, bool tiny);
+ void SetMapBrick(int x, int z);
+ void SwitchMapping();
+ void LoadSprite(const char *fname, int ref, int cav, int col, int row, int pos);
+ void LoadScript(const char *fname);
+ void LoadUser();
+ void RunGame();
+ bool ShowTitle(const char *name);
+ void Movie(const char *ext);
+ void TakeName();
+ void Inf(const char *txt);
+ void SelectSound();
+ void SNSelect();
+ void dummy() {}
+ void NONE();
+ void SB();
+ void CaveDown();
+ void XCave();
+ void QGame();
+ void SBM();
+ void GUS();
+ void GUSM();
+ void MIDI();
+ void AUTO();
+ void SetPortD();
+ void SetPortM();
+ void SetIRQ();
+ void SetDMA();
+ void MainLoop();
+
+private:
+ CGEConsole *_console;
+ void setup();
+};
+
+// Example console class
+class Console : public GUI::Debugger {
+public:
+ Console(CGEEngine *vm) {}
+ virtual ~Console(void) {}
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp
new file mode 100644
index 0000000000..1e1b952f77
--- /dev/null
+++ b/engines/cge/cge_main.cpp
@@ -0,0 +1,1874 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "common/scummsys.h"
+#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 "cge/cge.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include "common/str.h"
+
+namespace CGE {
+
+#define STACK_SIZ (K(2))
+#define SVGCHKSUM (1956 + Now + OldLev + Game + Music + DemoText)
+
+#define SVG0NAME ("{{INIT}}" SVG_EXT)
+#define SVG0FILE INI_FILE
+
+extern uint16 _stklen = (STACK_SIZ * 2);
+
+VGA *Vga;
+Heart *_heart;
+WALK *Hero;
+SYSTEM *Sys;
+Sprite *_pocLight;
+MOUSE *Mouse;
+Sprite *_pocket[POCKET_NX];
+Sprite *_sprite;
+Sprite *_miniCave;
+Sprite *_shadow;
+Sprite *_horzLine;
+INFO_LINE *InfoLine;
+Sprite *_cavLight;
+INFO_LINE *DebugLine;
+
+BMP_PTR MB[2];
+BMP_PTR HL[2];
+BMP_PTR MC[3];
+BMP_PTR PR[2];
+BMP_PTR SP[3];
+BMP_PTR LI[5];
+
+SNAIL *Snail;
+SNAIL *Snail_;
+
+// 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;
+
+//--------------------------------------------------------------------------
+
+bool JBW = false;
+
+//-------------------------------------------------------------------------
+int PocPtr = 0;
+
+static EMS *Mini = MiniEmm.Alloc((uint16)MINI_EMM_SIZE);
+static BMP_PTR *MiniShpList = NULL;
+static BMP_PTR MiniShp[] = { NULL, NULL };
+static KEYBOARD Keyboard;
+static bool Finis = false;
+static int Startup = 1;
+int OffUseCount;
+uint16 *intStackPtr = false;
+
+HXY HeroXY[CAVE_MAX] = {{0, 0}};
+BAR Barriers[1 + CAVE_MAX] = { { 0xFF, 0xFF } };
+
+
+extern int FindPocket(Sprite *);
+
+extern DAC StdPal[58];
+
+void FeedSnail(Sprite *spr, SNLIST snq); // defined in SNAIL
+uint8 CLUSTER::Map[MAP_ZCNT][MAP_XCNT];
+
+
+uint8 &CLUSTER::Cell(void) {
+ return Map[B][A];
+}
+
+
+bool CLUSTER::Protected(void) {
+/*
+ if (A == Barriers[Now].Vert || B == Barriers[Now].Horz)
+ return true;
+
+ _DX = (MAP_ZCNT << 8) + MAP_XCNT;
+ _BX = (uint16) 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 += (uint16) 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;
+ */
+
+ warning("STUB: CLUSTER::Protected()");
+ return true;
+}
+
+
+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];
+uint8 volume[2];
+
+struct SavTab {
+ void *Ptr;
+ int Len;
+ uint8 Flg;
+};
+
+SavTab _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 }
+};
+
+
+void CGEEngine::LoadGame(XFILE &file, bool tiny = false) {
+ SavTab *st;
+ Sprite *spr;
+ int i;
+
+ for (st = _savTab; st->Ptr; st++) {
+ if (file.Error)
+ error("Bad SVG");
+ file.Read((uint8 *)((tiny || st->Flg) ? st->Ptr : &i), st->Len);
+ }
+
+ file.Read((uint8 *) &i, sizeof(i));
+ if (i != SVGCHKSUM)
+ error("%s", Text->getText(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(this, NULL);
+ uint16 n = file.Read((uint8 *) &S, sizeof(S));
+
+ if (n != sizeof(S))
+ break;
+
+ S._prev = S._next = NULL;
+ spr = (scumm_stricmp(S.File + 2, "MUCHA") == 0) ? new FLY(this, NULL)
+ : new Sprite(this, NULL);
+ if (spr == NULL)
+ error("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)
+ error("Bad SVG");
+ file.Write((uint8 *) st->Ptr, st->Len);
+ }
+
+ file.Write((uint8 *) & (i = SVGCHKSUM), sizeof(i));
+
+ for (spr = Vga->SpareQ->First(); spr; spr = spr->_next)
+ if (spr->_ref >= 1000)
+ if (!file.Error)
+ file.Write((uint8 *)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 + new_random(OffUseCount));
+}
+
+
+static void TooFar(void) {
+ Trouble(TOO_FAR, TOO_FAR_TEXT);
+}
+
+
+// Used in stubbed function, do not remove!
+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((uint8 *) CLUSTER::Map, sizeof(CLUSTER::Map));
+ }
+ }
+}
+
+
+CLUSTER Trace[MAX_FIND_LEVEL];
+int FindLevel;
+
+
+WALK::WALK(CGEEngine *vm, BMP_PTR *shpl)
+ : Sprite(vm, shpl), Dir(NO_DIR), TracePtr(-1), _vm(vm) {
+}
+
+
+void WALK::Tick(void) {
+ if (_flags._hide)
+ return;
+
+ Here = XZ(_x + _w / 2, _y + _h);
+
+ if (Dir != NO_DIR) {
+ Sprite *spr;
+ Sys->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) {
+ warning("STUB: Find1Way");
+ /*
+ bool Find1Way(void);
+ extern uint16 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;
+ int 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))));
+ }
+}
+
+
+bool 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
+}
+
+
+class SQUARE : public Sprite {
+public:
+ SQUARE(CGEEngine *vm);
+ void Touch(uint16 mask, int x, int y);
+private:
+ CGEEngine *_vm;
+};
+
+
+SQUARE::SQUARE(CGEEngine *vm)
+ : Sprite(vm, MB), _vm(vm) {
+ _flags._kill = true;
+ _flags._bDel = false;
+}
+
+
+void SQUARE::Touch(uint16 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);
+ }
+}
+
+
+void CGEEngine::SetMapBrick(int x, int z) {
+ SQUARE *s = new SQUARE(this);
+ 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());
+ }
+}
+
+static void SwitchColorMode(void);
+static void SwitchDebug(void);
+static void SwitchMusic(void);
+static void KillSprite(void);
+static void PushSprite(void);
+static void PullSprite(void);
+static void NextStep(void);
+static void SaveMapping(void);
+
+static void KeyClick(void) {
+ SNPOST_(SNSOUND, -1, 5, NULL);
+}
+
+
+void CGEEngine::ResetQSwitch() {
+ SNPOST_(SNSEQ, 123, 0, NULL);
+ KeyClick();
+}
+
+
+void CGEEngine::Quit() {
+ static CHOICE QuitMenu[] = {
+ { NULL, &CGEEngine::StartCountDown },
+ { NULL, &CGEEngine::ResetQSwitch },
+ { NULL, &CGEEngine::dummy }
+ };
+
+ if (Snail->Idle() && ! Hero->_flags._hide) {
+ if (VMENU::Addr) {
+ SNPOST_(SNKILL, -1, 0, VMENU::Addr);
+ ResetQSwitch();
+ } else {
+ QuitMenu[0].Text = Text->getText(QUIT_TEXT);
+ QuitMenu[1].Text = Text->getText(NOQUIT_TEXT);
+ (new VMENU(this, QuitMenu, -1, -1))->SetName(Text->getText(QUIT_TITLE));
+ SNPOST_(SNSEQ, 123, 1, NULL);
+ KeyClick();
+ }
+ }
+}
+
+
+static void AltCtrlDel(void) {
+ SNPOST_(SNSAY, -1, A_C_D_TEXT, Hero);
+}
+
+// Used in stubbed function, do not remove!
+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;
+ //TODO Change the SNPOST message send to a special way to send function pointer
+ //if (MiniCave && stp != recent) SNPOST_(SNEXEC, -1, recent = stp, (void *)&MiniStep);
+ warning("STUB: PostMiniStep()");
+}
+
+void SYSTEM::SetPal(void) {
+ uint i;
+ DAC *p = VGA::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) {
+ uint16 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 = VGA::SysPal;
+ spr->Expand();
+ Bitmap::Pal = NULL;
+ spr->Show(2);
+ Vga->CopyPage(1, 2);
+ Sys->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(VGA::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(VGA::SysPal);
+ Dark = false;
+ if (! Startup)
+ Mouse->On();
+
+ _heart->_enable = true;
+}
+
+
+void CGEEngine::CaveDown() {
+ Sprite *spr;
+ 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);
+}
+
+
+void CGEEngine::XCave() {
+ CaveDown();
+ CaveUp();
+}
+
+
+void CGEEngine::QGame() {
+ CaveDown();
+ OldLev = Lev;
+ SaveSound();
+ CFILE file = CFILE(UsrPath(UsrFnam), WRI, RCrypt);
+ SaveGame(file);
+ Vga->Sunset();
+ Finis = true;
+}
+
+
+void CGEEngine::SwitchCave(int cav) {
+ if (cav != Now) {
+ _heart->_enable = false;
+ if (cav < 0) {
+ SNPOST(SNLABEL, -1, 0, NULL); // wait for repaint
+ //TODO Change the SNPOST message send to a special way to send function pointer
+ //SNPOST(SNEXEC, -1, 0, (void *)&QGame); // switch cave
+ warning("SwitchCave() - SNPOST");
+ } else {
+ Now = cav;
+ Mouse->Off();
+ if (Hero) {
+ Hero->Park();
+ Hero->Step(0);
+ if (!_isDemo)
+ ///// protection: auto-destruction on! ----------------------
+ Vga->SpareQ->Show = STARTUP::Summa * (cav <= CAVE_MAX);
+ /////--------------------------------------------------------
+ }
+ _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
+ //TODO Change the SNPOST message send to a special way to send function pointer
+ //SNPOST(SNEXEC, 0, 0, (void *)&XCave); // switch cave
+ warning("SwitchCave() - SNPOST");
+ }
+ }
+}
+
+SYSTEM::SYSTEM(CGEEngine *vm) : Sprite(vm, NULL), _vm(vm) {
+ FunDel = HEROFUN0;
+ SetPal();
+ Tick();
+}
+
+void SYSTEM::Touch(uint16 mask, int x, int y) {
+ static int pp = 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();
+ 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;
+ case PgUp:
+ PushSprite();
+ break;
+ case PgDn:
+ PullSprite();
+ break;
+ case '+':
+ NextStep();
+ break;
+ case '`':
+ if (KEYBOARD::Key[ALT])
+ SaveMapping();
+ else
+ _vm->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:
+ Sys->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;
+ case F10 :
+ if (Snail->Idle() && ! Hero->_flags._hide)
+ _vm->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;
+ int cav = 0;
+ 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)
+ _vm->SwitchCave(cav);
+
+ if (!_horzLine->_flags._hide) {
+ if (y >= MAP_TOP && y < MAP_TOP + MAP_HIG) {
+ int8 x1, z1;
+ XZ(x, y).Split(x1, z1);
+ CLUSTER::Map[z1][x1] = 1;
+ _vm->SetMapBrick(x1, z1);
+ }
+ } else
+ {
+ 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 = new_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(VGA::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);
+ //TODO Change the SNPOST message send to a special way to send function pointer
+ // SNPOST(SNEXEC, -1, 0, (void *)&SelectSound);
+ warning("SwitchMusic() - SNPOST");
+ }
+ } 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();
+}
+
+
+void CGEEngine::StartCountDown() {
+ //SNPOST(SNSEQ, 123, 0, NULL);
+ SwitchCave(-1);
+}
+
+
+void CGEEngine::TakeName() {
+ if (GET_TEXT::Ptr)
+ SNPOST_(SNKILL, -1, 0, GET_TEXT::Ptr);
+ else {
+ GET_TEXT *tn = new GET_TEXT(this, Text->getText(GETNAME_PROMPT), UsrFnam, 8, KeyClick);
+ if (tn) {
+ tn->SetName(Text->getText(GETNAME_TITLE));
+ tn->Center();
+ tn->Goto(tn->_x, tn->_y - 10);
+ tn->_z = 126;
+ Vga->ShowQ->Insert(tn);
+ }
+ }
+}
+
+
+void CGEEngine::SwitchMapping() {
+ 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) {
+ bool 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((uint8 *) 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((uint8 *) HeroXY, sizeof(HeroXY));
+ }
+ }
+}
+
+// 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)
+
+static void SayDebug(void) {
+ if (!DebugLine->_flags._hide) {
+ static long t = -1L;
+ long t1 = Timer();
+
+ if (t1 - t >= 18) {
+ static uint32 old = 0L;
+ uint32 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
+ uint16 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(*(uint16 *)(&_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;
+}
+
+
+void CGEEngine::OptionTouch(int opt, uint16 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(this, BUTTON_X, BUTTON_Y);
+ }
+ break;
+ case 3 :
+ if (mask & L_UP)
+ Quit();
+ break;
+ }
+}
+
+
+#pragma argsused
+void Sprite::Touch(uint16 mask, int x, int y) {
+ Sys->FunTouch();
+ if ((mask & ATTN) == 0) {
+ InfoLine->Update(Name());
+ if (mask & (R_DN | L_DN))
+ _sprite = this;
+ if (_ref / 10 == 12) {
+ _vm->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);
+ }
+ }
+}
+
+
+void CGEEngine::LoadSprite(const char *fname, int ref, int cav, int col = 0, int row = 0, int pos = 0) {
+ static const char *Comd[] = { "Name", "Type", "Phase", "East",
+ "Left", "Right", "Top", "Bottom",
+ "Seq", "Near", "Take",
+ "Portable", "Transparent",
+ NULL
+ };
+ static const char *Type[] = { "DEAD", "AUTO", "WALK", "NEWTON", "LISSAJOUS",
+ "FLY", NULL
+ };
+ char line[LINE_MAX];
+
+ int shpcnt = 0;
+ int type = 0; // DEAD
+ bool east = false;
+ bool port = false;
+ bool tran = false;
+ int i, lcnt = 0;
+ uint16 len;
+
+ MergeExt(line, fname, SPR_EXT);
+ if (INI_FILE::Exist(line)) { // sprite description file exist
+ INI_FILE sprf(line);
+ if (sprf.Error)
+ error("Bad SPR [%s]", line);
+
+ while ((len = sprf.Read((uint8 *)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)
+ error("%s [%s]", NumStr("Bad line ######", lcnt), (const char *)fname);
+
+
+ switch (i) {
+ case 0 : // Name - will be taken in Expand routine
+ break;
+ case 1 : // Type
+ if ((type = TakeEnum(Type, strtok(NULL, " \t,;/"))) < 0)
+ error("%s [%s]", NumStr("Bad line ######", lcnt), (const char *)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)
+ error("No shapes [%s]", 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(this, NULL);
+ if (_sprite) {
+ _sprite->Goto(col, row);
+ //Sprite->Time = 1;//-----------$$$$$$$$$$$$$$$$
+ }
+ break;
+ }
+ case 2 : { // WALK
+ WALK *w = new WALK(this, NULL);
+ if (w && ref == 1) {
+ w->Goto(col, row);
+ if (Hero)
+ error("2nd HERO [%s]", 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
+ error("Bad type [%s]", 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(this, NULL);
+ _sprite = f;
+ //////Sprite->Time = 1;//-----------$$$$$$$$$$$$$$
+ break;
+ }
+ default: { // DEAD
+ _sprite = new Sprite(this, 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;
+
+ // Extract the filename, without the extension
+ strcpy(_sprite->File, fname);
+ char *p = strchr(_sprite->File, '.');
+ if (p)
+ *p = '\0';
+
+ _sprite->_shpCnt = shpcnt;
+ Vga->SpareQ->Append(_sprite);
+ }
+}
+
+
+void CGEEngine::LoadScript(const char *fname) {
+ char line[LINE_MAX];
+ char *SpN;
+ int SpI, SpA, SpX, SpY, SpZ;
+ bool BkG = false;
+ INI_FILE scrf(fname);
+ int lcnt = 0;
+ bool ok = true;
+
+ if (scrf.Error)
+ return;
+
+ while (scrf.Read((uint8 *)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)
+ error("%s [%s]", NumStr("Bad INI line ######", lcnt), fname);
+}
+
+
+void CGEEngine::MainLoop() {
+ SayDebug();
+
+ if (_isDemo) {
+// static uint32 tc = 0;
+ if (/* FIXME: TimerCount - tc >= ((182L * 6L) * 5L) && */ Talk == NULL && Snail->Idle()) {
+ if (Text->getText(DemoText)) {
+ SNPOST(SNSOUND, -1, 4, NULL); // drumla
+ SNPOST(SNINF, -1, DemoText, NULL);
+ SNPOST(SNLABEL, -1, -1, NULL);
+ if (Text->getText(++ DemoText) == NULL)
+ DemoText = DEMO_TEXT + 1;
+ }
+ //FIXME: tc = TimerCount;
+ }
+ }
+ Vga->Show();
+ Snail_->RunCom();
+ Snail->RunCom();
+
+ // Delay to slow things down
+ g_system->delayMillis(10);
+}
+
+
+void CGEEngine::LoadUser() {
+ // set scene
+ if (STARTUP::Mode == 0) { // user .SVG file found
+ CFILE cfile = CFILE(UsrPath(UsrFnam), REA, RCrypt);
+ LoadGame(cfile);
+ } else {
+ if (STARTUP::Mode == 1) {
+ SVG0FILE file = SVG0FILE(SVG0NAME);
+ LoadGame(file);
+ } else {
+ LoadScript(ProgName(INI_EXT));
+ Music = true;
+ CFILE file = CFILE(SVG0NAME, WRI);
+ SaveGame(file);
+ error("Ok [%s]", SVG0NAME);
+ }
+ }
+ LoadScript(ProgName(IN0_EXT));
+}
+
+
+void CGEEngine::RunGame() {
+ 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);
+
+ // FIXME: Allow ScummVM to handle mouse display
+// 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")) {
+ uint8 *ptr = (uint8 *) &*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);
+
+ DebugLine->_z = 126;
+ Vga->ShowQ->Insert(DebugLine);
+
+ _horzLine->_y = MAP_TOP - (MAP_TOP > 0);
+ _horzLine->_z = 126;
+ Vga->ShowQ->Insert(_horzLine);
+
+ 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) {
+ //TODO Change the SNPOST message send to a special way to send function pointer
+ // if (FINIS) SNPOST(SNEXEC, -1, 0, (void *)&QGame);
+ warning("RunGame: problematic use of SNPOST");
+ 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 CGEEngine::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);
+
+ // FIXME: Allow ScummVM to handle mouse display
+ //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();
+ }
+}
+
+
+bool CGEEngine::ShowTitle(const char *name) {
+ Bitmap::Pal = VGA::SysPal;
+ BMP_PTR LB[] = { new Bitmap(name), NULL };
+ Bitmap::Pal = NULL;
+ bool usr_ok = false;
+
+ Sprite D(this, 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(VGA::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) {
+ if (_isDemo) {
+ 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());
+ warning("ShowTitle: FIXME ReadBoot");
+ Boot *b = ReadBoot(0);
+ uint32 sn = (b->XSign == 0x29) ? b->Serial : b->lTotSecs;
+ free(b);
+ sn -= ((IDENT *)Copr)->disk;
+ STARTUP::Summa |= Lo(sn) | Hi(sn);
+#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)) {
+ CFILE file = CFILE(n, REA, RCrypt);
+ LoadGame(file, true); // only system vars
+ Vga->SetColors(VGA::SysPal, 64);
+ Vga->Update();
+ if (FINIS) {
+ ++ STARTUP::Mode;
+ FINIS = false;
+ }
+ } else
+ ++STARTUP::Mode;
+ }
+ }
+
+ if (STARTUP::Mode < 2)
+ Movie("X01"); // wink
+
+ Vga->CopyPage(0, 2);
+
+ if (_isDemo)
+ return true;
+ else
+ return (STARTUP::Mode == 2 || usr_ok);
+}
+
+
+/*
+void StkDump (void) {
+ CFILE f("!STACK.DMP", BFW);
+ f.Write((uint8 *) (intStackPtr-STACK_SIZ/2), STACK_SIZ*2);
+}
+*/
+
+
+void CGEEngine::cge_main(void) {
+ uint16 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)
+ error("%s", Text->getText(NO_MOUSE_TEXT));
+
+ if (!SVG0FILE::Exist(SVG0NAME))
+ STARTUP::Mode = 2;
+
+ DebugLine->_flags._hide = true;
+ _horzLine->_flags._hide = true;
+
+ //srand((uint16) Timer());
+ Sys = new SYSTEM(this);
+
+ if (Music && STARTUP::SoundOk)
+ LoadMIDI(0);
+ if (STARTUP::Mode < 2)
+ Movie(LGO_EXT);
+ if (ShowTitle("WELCOME")) {
+ if ((!_isDemo) && (STARTUP::Mode == 1))
+ Movie("X02"); // intro
+ RunGame();
+ Startup = 2;
+ if (FINIS)
+ Movie("X03");
+ } else
+ Vga->Sunset();
+ error("%s", Text->getText(EXIT_OK_TEXT + FINIS));
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/cge_main.h b/engines/cge/cge_main.h
new file mode 100644
index 0000000000..8b2f87aad9
--- /dev/null
+++ b/engines/cge/cge_main.h
@@ -0,0 +1,196 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __CGE__
+#define __CGE__
+
+#include "cge/wav.h"
+#include "cge/vga13h.h"
+#include "cge/mouse.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
+#define CAVE_X 4
+#define CAVE_Y 166
+#define CAVE_SX 0
+#define CAVE_SY 0
+
+#ifdef DEMO
+#define CAVE_DX 23
+#define CAVE_DY 29
+#define CAVE_NX 3
+#define CAVE_NY 1
+#else
+#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 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)
+#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:
+ int FunDel;
+
+ SYSTEM(CGEEngine *vm);
+
+ void SetPal();
+ void FunTouch();
+ void Touch(uint16 mask, int x, int y);
+ void Tick();
+private:
+ CGEEngine *_vm;
+};
+
+
+class CLUSTER : public COUPLE {
+public:
+ static uint8 Map[MAP_ZCNT][MAP_XCNT];
+ uint8 &Cell(void);
+ CLUSTER(void) : COUPLE() { }
+ CLUSTER(int a, int b) : COUPLE(a, b) { }
+ bool Protected(void);
+};
+
+
+class WALK : public Sprite {
+public:
+ CLUSTER Here;
+ int TracePtr;
+
+ enum DIR { NO_DIR = -1, NN, EE, SS, WW } Dir;
+ WALK(CGEEngine *vm, 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);
+ bool Lower(Sprite *spr);
+ void Reach(Sprite *spr, int mode = -1);
+private:
+ CGEEngine *_vm;
+
+};
+
+
+CLUSTER XZ(int x, int y);
+CLUSTER XZ(COUPLE xy);
+
+void ExpandSprite(Sprite *spr);
+void ContractSprite(Sprite *spr);
+
+extern WALK *Hero;
+extern VGA *Vga;
+extern Heart *_heart;
+extern SYSTEM *Sys;
+extern int OffUseCount;
+extern Sprite *_pocLight;
+extern MOUSE *Mouse;
+extern Sprite *_pocket[];
+extern Sprite *_sprite;
+extern Sprite *_miniCave;
+extern Sprite *_shadow;
+extern Sprite *_horzLine;
+extern INFO_LINE *InfoLine;
+extern Sprite *_cavLight;
+extern INFO_LINE *DebugLine;
+extern BMP_PTR MB[2];
+extern BMP_PTR MB[2];
+extern BMP_PTR HL[2];
+extern BMP_PTR MC[3];
+extern BMP_PTR PR[2];
+extern BMP_PTR SP[3];
+extern BMP_PTR LI[5];
+extern SNAIL *Snail;
+extern SNAIL *Snail_;
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/config.cpp b/engines/cge/config.cpp
new file mode 100644
index 0000000000..2673143285
--- /dev/null
+++ b/engines/cge/config.cpp
@@ -0,0 +1,282 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/config.h"
+#include "cge/sound.h"
+#include "cge/vmenu.h"
+#include "cge/text.h"
+#include "cge/cge_main.h"
+
+namespace CGE {
+
+/*
+ 51=wska§ typ posiadanej karty d¦wi‘kowej
+ 52=wybierz numer portu dla karty d¦wi‘kowej
+ 53=wybierz numer przerwania dla karty d¦wi‘kowej
+ 54=wybierz numer kana’u DMA dla karty d¦wi‘kowej
+ 55=wybierz numer portu dla General MIDI
+ 55=konfiguracja karty d¦wi‘kowej
+*/
+#define STYPE_TEXT 51
+#define SPORT_TEXT 52
+#define SIRQ_TEXT 53
+#define SDMA_TEXT 54
+#define MPORT_TEXT 55
+#define MENU_TEXT 56
+
+#define NONE_TEXT 60
+#define SB_TEXT 61
+#define SBM_TEXT 62
+#define GUS_TEXT 63
+#define GUSM_TEXT 64
+#define MIDI_TEXT 65
+#define AUTO_TEXT 66
+
+#define DETECT 0xFFFF
+
+
+static int DevName[] = {
+ NONE_TEXT, SB_TEXT, SBM_TEXT, GUS_TEXT, GUSM_TEXT,
+ MIDI_TEXT, AUTO_TEXT
+};
+
+static CHOICE DevMenu[] = {
+ { NULL, &CGEEngine::NONE },
+ { NULL, &CGEEngine::SB },
+ { NULL, &CGEEngine::SBM },
+ { NULL, &CGEEngine::GUS },
+ { NULL, &CGEEngine::GUSM },
+ { NULL, &CGEEngine::MIDI },
+ { NULL, &CGEEngine::AUTO },
+ { NULL, NULL }
+};
+
+
+static CHOICE DigiPorts[] = {
+ { " 210h", &CGEEngine::SetPortD },
+ { " 220h", &CGEEngine::SetPortD },
+ { " 230h", &CGEEngine::SetPortD },
+ { " 240h", &CGEEngine::SetPortD },
+ { " 250h", &CGEEngine::SetPortD },
+ { " 260h", &CGEEngine::SetPortD },
+ { "AUTO ", &CGEEngine::SetPortD },
+ { NULL, NULL }
+};
+
+static CHOICE MIDIPorts[] = {
+ { " 220h", &CGEEngine::SetPortM },
+ { " 230h", &CGEEngine::SetPortM },
+ { " 240h", &CGEEngine::SetPortM },
+ { " 250h", &CGEEngine::SetPortM },
+ { " 300h", &CGEEngine::SetPortM },
+ { " 320h", &CGEEngine::SetPortM },
+ { " 330h", &CGEEngine::SetPortM },
+ { " 340h", &CGEEngine::SetPortM },
+ { " 350h", &CGEEngine::SetPortM },
+ { " 360h", &CGEEngine::SetPortM },
+ { "AUTO ", &CGEEngine::SetPortM },
+ { NULL, NULL }
+};
+
+static CHOICE BlsterIRQ[] = {
+ { "IRQ 2", &CGEEngine::SetIRQ },
+ { "IRQ 5", &CGEEngine::SetIRQ },
+ { "IRQ 7", &CGEEngine::SetIRQ },
+ { "IRQ 10", &CGEEngine::SetIRQ },
+ { "AUTO ", &CGEEngine::SetIRQ },
+ { NULL, NULL }
+};
+
+static CHOICE GravisIRQ[] = {
+ { "IRQ 2", &CGEEngine::SetIRQ },
+ { "IRQ 5", &CGEEngine::SetIRQ },
+ { "IRQ 7", &CGEEngine::SetIRQ },
+ { "IRQ 11", &CGEEngine::SetIRQ },
+ { "IRQ 12", &CGEEngine::SetIRQ },
+ { "IRQ 15", &CGEEngine::SetIRQ },
+ { "AUTO ", &CGEEngine::SetIRQ },
+ { NULL, NULL }
+};
+
+static CHOICE GravisDMA[] = {
+ { "DMA 1", &CGEEngine::SetDMA },
+ { "DMA 3", &CGEEngine::SetDMA },
+ { "DMA 5", &CGEEngine::SetDMA },
+ { "DMA 6", &CGEEngine::SetDMA },
+ { "DMA 7", &CGEEngine::SetDMA },
+ { "AUTO ", &CGEEngine::SetDMA },
+ { NULL, NULL }
+};
+
+static CHOICE BlsterDMA[] = {
+ { "DMA 0", &CGEEngine::SetDMA },
+ { "DMA 1", &CGEEngine::SetDMA },
+ { "DMA 3", &CGEEngine::SetDMA },
+ { "AUTO ", &CGEEngine::SetDMA },
+ { NULL, NULL }
+};
+
+
+void CGEEngine::SelectSound() {
+ int i;
+ Sound.Close();
+ if (VMENU::Addr)
+ SNPOST_(SNKILL, -1, 0, VMENU::Addr);
+ Inf(Text->getText(STYPE_TEXT));
+ Talk->Goto(Talk->_x, FONT_HIG / 2);
+ for (i = 0; i < ArrayCount(DevName); i++)
+ DevMenu[i].Text = Text->getText(DevName[i]);
+ (new VMENU(this, DevMenu, SCR_WID / 2, Talk->_y + Talk->_h + TEXT_VM + FONT_HIG))->SetName(Text->getText(MENU_TEXT));
+}
+
+
+static void Reset(void) {
+ SNDDrvInfo.DBASE = SNDDrvInfo.DIRQ = SNDDrvInfo.DDMA = SNDDrvInfo.MBASE = DETECT;
+}
+
+
+static uint16 deco(const char *str, uint16(*dco)(const char *)) {
+ while (*str && ! IsDigit(*str))
+ ++str;
+ if (*str)
+ return dco(str);
+ else
+ return DETECT;
+}
+
+
+static uint16 ddeco(const char *str) {
+ return deco(str, atow);
+}
+
+
+static uint16 xdeco(const char *str) {
+ return deco(str, xtow);
+}
+
+
+static CHOICE *Cho;
+static int Hlp;
+
+void CGEEngine::SNSelect() {
+ Inf(Text->getText(Hlp));
+ Talk->Goto(Talk->_x, FONT_HIG / 2);
+ (new VMENU(this, Cho, SCR_WID / 2, Talk->_y + Talk->_h + TEXT_VM + FONT_HIG))->SetName(Text->getText(MENU_TEXT));
+}
+
+
+static void Select(CHOICE *cho, int hlp) {
+ Cho = cho;
+ Hlp = hlp;
+ //TODO Change the SNPOST message send to a special way to send function pointer
+ //SNPOST(SNEXEC, -1, 0, (void *)&SNSelect);
+ warning("STUB: Select");
+}
+
+
+void CGEEngine::NONE() {
+ SNDDrvInfo.DDEV = DEV_QUIET;
+ SNDDrvInfo.MDEV = DEV_QUIET;
+ Sound.Open();
+}
+
+
+void CGEEngine::SB() {
+ SNDDrvInfo.DDEV = DEV_SB;
+ SNDDrvInfo.MDEV = DEV_SB;
+ Reset();
+ Select(DigiPorts, SPORT_TEXT);
+}
+
+
+void CGEEngine::SBM() {
+ SNDDrvInfo.DDEV = DEV_SB;
+ SNDDrvInfo.MDEV = DEV_GM;
+ Reset();
+ Select(DigiPorts, SPORT_TEXT);
+}
+
+
+void CGEEngine::GUS() {
+ SNDDrvInfo.DDEV = DEV_GUS;
+ SNDDrvInfo.MDEV = DEV_GUS;
+ Reset();
+ Select(DigiPorts, SPORT_TEXT);
+}
+
+
+void CGEEngine::GUSM() {
+ SNDDrvInfo.DDEV = DEV_GUS;
+ SNDDrvInfo.MDEV = DEV_GM;
+ Reset();
+ Select(DigiPorts, SPORT_TEXT);
+}
+
+
+void CGEEngine::MIDI() {
+ SNDDrvInfo.DDEV = DEV_QUIET;
+ SNDDrvInfo.MDEV = DEV_GM;
+ SNDDrvInfo.MBASE = DETECT;
+ Select(MIDIPorts, MPORT_TEXT);
+}
+
+
+void CGEEngine::AUTO() {
+ SNDDrvInfo.DDEV = DEV_AUTO;
+ SNDDrvInfo.MDEV = DEV_AUTO;
+ Reset();
+ Sound.Open();
+}
+
+
+void CGEEngine::SetPortD() {
+ SNDDrvInfo.DBASE = xdeco(DigiPorts[VMENU::Recent].Text);
+ Select((SNDDrvInfo.DDEV == DEV_SB) ? BlsterIRQ : GravisIRQ, SIRQ_TEXT);
+}
+
+
+void CGEEngine::SetPortM() {
+ SNDDrvInfo.MBASE = xdeco(MIDIPorts[VMENU::Recent].Text);
+ Sound.Open();
+}
+
+
+void CGEEngine::SetIRQ() {
+ SNDDrvInfo.DIRQ = ddeco(((SNDDrvInfo.DDEV == DEV_SB) ? BlsterIRQ : GravisIRQ)[VMENU::Recent].Text);
+ Select((SNDDrvInfo.DDEV == DEV_SB) ? BlsterDMA : GravisDMA, SDMA_TEXT);
+}
+
+
+void CGEEngine::SetDMA() {
+ SNDDrvInfo.DDMA = ddeco(((SNDDrvInfo.DDEV == DEV_SB) ? BlsterDMA : GravisDMA)[VMENU::Recent].Text);
+ if (SNDDrvInfo.MDEV != SNDDrvInfo.DDEV)
+ Select(MIDIPorts, MPORT_TEXT);
+ else
+ Sound.Open();
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/config.h b/engines/cge/config.h
new file mode 100644
index 0000000000..e3fe094681
--- /dev/null
+++ b/engines/cge/config.h
@@ -0,0 +1,37 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __CONFIG__
+#define __CONFIG__
+
+namespace CGE {
+
+void SelectSound(void);
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/console.cpp b/engines/cge/console.cpp
new file mode 100644
index 0000000000..71eedf34ea
--- /dev/null
+++ b/engines/cge/console.cpp
@@ -0,0 +1,34 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "cge/console.h"
+#include "cge/cge.h"
+
+namespace CGE {
+
+CGEConsole::CGEConsole(CGEEngine *vm) : GUI::Debugger(), _vm(vm) {
+}
+
+CGEConsole::~CGEConsole() {
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/console.h b/engines/cge/console.h
new file mode 100644
index 0000000000..7f265202ea
--- /dev/null
+++ b/engines/cge/console.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CGE_CONSOLE_H
+#define CGE_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace CGE {
+
+class CGEEngine;
+
+class CGEConsole : public GUI::Debugger {
+public:
+ CGEConsole(CGEEngine *vm);
+ virtual ~CGEConsole(void);
+
+private:
+ CGEEngine *_vm;
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp
new file mode 100644
index 0000000000..31bf629fcf
--- /dev/null
+++ b/engines/cge/detection.cpp
@@ -0,0 +1,238 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/config-manager.h"
+#include "engines/advancedDetector.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "base/plugins.h"
+#include "graphics/thumbnail.h"
+#include "cge/cge.h"
+
+static const PlainGameDescriptor CGEGames[] = {
+ { "soltys", "Soltys" },
+ { 0, 0 }
+};
+
+namespace CGE {
+
+using Common::GUIO_NONE;
+
+static const ADGameDescription gameDescriptions[] = {
+
+ {
+ "soltys", "",
+ {
+ {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
+ {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437572},
+ AD_LISTEND
+ },
+ Common::PL_POL, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE
+ },
+ {
+ "soltys", "Soltys Freeware",
+ {
+ {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
+ {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676},
+ AD_LISTEND
+ },
+ Common::PL_POL, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE
+ },
+ {
+ "soltys", "Soltys Demo",
+ {
+ {"vol.cat", 0, "1e077c8ff58109a187f07ac54b0c873a", 18788},
+ {"vol.dat", 0, "75d385a6074c58b69f7730481f256051", 1796710},
+ AD_LISTEND
+ },
+ Common::PL_POL, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE
+ },
+ {
+ "soltys", "Soltys Demo",
+ {
+ {"vol.cat", 0, "f17987487fab1ebddd781d8d02fedecc", 7168},
+ {"vol.dat", 0, "c5d9b15863cab61dc125551576dece04", 1075272},
+ AD_LISTEND
+ },
+ Common::PL_POL, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE
+ },
+ AD_TABLE_END_MARKER
+};
+
+static const ADFileBasedFallback fileBasedFallback[] = {
+ { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } },
+ { 0, { 0 } }
+};
+
+} // End of namespace CGE
+
+class CGEMetaEngine : public AdvancedMetaEngine {
+public:
+ CGEMetaEngine() : AdvancedMetaEngine(CGE::gameDescriptions, sizeof(ADGameDescription), CGEGames) {
+ _singleid = "Soltys";
+ }
+
+ virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
+ return detectGameFilebased(allFiles, CGE::fileBasedFallback);
+ }
+
+ virtual const char *getName() const {
+ return "CGE";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Soltys (c) 1994-1996 L.K. Avalon";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual SaveStateList listSaves(const char *target) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+};
+
+bool CGEMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate);
+}
+
+void CGEMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+int CGEMetaEngine::getMaximumSaveSlot() const {
+ return 99;
+}
+
+SaveStateList CGEMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String pattern = target;
+ pattern += ".???";
+
+ filenames = saveFileMan->listSavefiles(pattern);
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ int slotNum = 0;
+ for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); filename++) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ slotNum = atoi(filename->c_str() + filename->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 99) {
+ Common::InSaveFile *file = saveFileMan->openForLoading(*filename);
+ if (file) {
+ int32 version = file->readSint32BE();
+ if (version != CGE_SAVEGAME_VERSION) {
+ delete file;
+ continue;
+ }
+
+ // read name
+ uint16 nameSize = file->readUint16BE();
+ if (nameSize >= 255) {
+ delete file;
+ continue;
+ }
+ char name[256];
+ file->read(name, nameSize);
+ name[nameSize] = 0;
+
+ saveList.push_back(SaveStateDescriptor(slotNum, name));
+ delete file;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
+
+ if (file) {
+
+ int32 version = file->readSint32BE();
+ if (version != CGE_SAVEGAME_VERSION) {
+ delete file;
+ return SaveStateDescriptor();
+ }
+
+ uint32 saveNameLength = file->readUint16BE();
+ char saveName[256];
+ file->read(saveName, saveNameLength);
+ saveName[saveNameLength] = 0;
+
+ SaveStateDescriptor desc(slot, saveName);
+
+ Graphics::Surface *thumbnail = new Graphics::Surface();
+ assert(thumbnail);
+ if (!Graphics::loadThumbnail(*file, *thumbnail)) {
+ delete thumbnail;
+ thumbnail = 0;
+ }
+ desc.setThumbnail(thumbnail);
+
+ desc.setDeletableFlag(true);
+ desc.setWriteProtectedFlag(false);
+
+ uint32 saveDate = file->readUint32BE();
+ uint16 saveTime = file->readUint16BE();
+
+ int day = (saveDate >> 24) & 0xFF;
+ int month = (saveDate >> 16) & 0xFF;
+ int year = saveDate & 0xFFFF;
+
+ desc.setSaveDate(year, month, day);
+
+ int hour = (saveTime >> 8) & 0xFF;
+ int minutes = saveTime & 0xFF;
+
+ desc.setSaveTime(hour, minutes);
+
+ delete file;
+ return desc;
+ }
+
+ return SaveStateDescriptor();
+}
+
+bool CGEMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc) {
+ *engine = new CGE::CGEEngine(syst, desc);
+ }
+ return desc != 0;
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(CGE)
+REGISTER_PLUGIN_DYNAMIC(CGE, PLUGIN_TYPE_ENGINE, CGEMetaEngine);
+#else
+REGISTER_PLUGIN_STATIC(CGE, PLUGIN_TYPE_ENGINE, CGEMetaEngine);
+#endif
diff --git a/engines/cge/ems.cpp b/engines/cge/ems.cpp
new file mode 100644
index 0000000000..56d853f4e8
--- /dev/null
+++ b/engines/cge/ems.cpp
@@ -0,0 +1,225 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/general.h"
+
+namespace CGE {
+
+#define EMS_INT 0x67
+#define PAGE_MASK 0x3FFF
+#define SIZ(n) ((n) ? ((long)n) : (0x10000L))
+
+
+enum EMM_FUN {
+ GET_STATUS = 0x40, GET_FRAME, GET_SIZE, OPEN_HANDLE, MAP_PAGE,
+ CLOSE_HANDLE, GET_VER, SAVE_CONTEXT, REST_CONTEXT, GET_PAGES = 0x4B,
+ GET_HANDLES, GET_INFO, CONTROL
+};
+
+
+void *EMM::Frame = NULL;
+
+
+EMM::EMM(long size): Han(-1), Top(0), Lim(0), List(NULL) {
+ /*
+ if (Test())
+ {
+ asm mov ah,GET_FRAME // get EMS frame segment
+ asm int EMS_INT // do it!
+ asm or ah,ah // see status
+ asm jnz xit // abort on error
+ Frame = (void _seg *) _BX; // save frame segment
+
+ if (size == 0)
+ {
+ asm mov ah,GET_SIZE // get EMS memory size
+ asm int EMS_INT // do it!
+ asm or ah,ah // see status
+ asm jnz xit // abort on error
+ asm or bx,bx // test page count
+ asm jz xit // abort if no free pages
+ // number of available pages in BX is ready to use by OPEN
+ }
+ else _BX = (uint16) ((size + PAGE_MASK) >> 14);
+ asm mov ah,OPEN_HANDLE // open EMM handle
+ asm int EMS_INT // do it!
+ asm or ah,ah // see status
+ asm jnz xit // abort on error
+ Han = _DX;
+ Lim = _BX;
+ Lim <<= 14;
+ _DX = Han;
+ asm mov ah,SAVE_CONTEXT // save mapping context
+ asm int EMS_INT // do it!
+ }
+ xit:
+ */
+ warning("STUB: EMM:EMM");
+}
+
+
+EMM::~EMM(void) {
+ /* FIXME
+ Release();
+ if (Han >= 0)
+ {
+ _DX = Han;
+ asm mov ah,REST_CONTEXT
+ asm int EMS_INT
+ asm mov ah,CLOSE_HANDLE
+ asm int EMS_INT
+ }
+ */
+}
+
+
+bool EMM::Test(void) {
+ /*
+ static char e[] = "EMMXXXX0";
+
+ asm mov ax,0x3D40
+ asm mov dx,offset e
+ asm int 0x21
+ asm jc fail
+
+ asm push ax
+ asm mov bx,ax
+ asm mov ax,0x4407
+ asm int 0x21
+
+ asm pop bx
+ asm push ax
+ asm mov ax,0x3E00
+ asm int 0x21
+ asm pop ax
+
+ asm cmp al,0x00
+ asm je fail
+
+ success:
+ return TRUE;
+ fail:
+ return FALSE;
+ */
+ warning("EMM::Test");
+ return false;
+}
+
+
+EMS *EMM::Alloc(uint16 siz) {
+ /*
+ long size = SIZ(siz),
+ top = Top;
+
+ uint16 pgn = (uint16) (top >> 14),
+ cnt = (uint16) ((top + size + PAGE_MASK) >> 14) - pgn;
+
+ if (cnt > 4)
+ {
+ top = (top + PAGE_MASK) & 0xFFFFC000L;
+ pgn++;
+ cnt--;
+ }
+
+ if (size <= Lim - top)
+ {
+ EMS * e = new EMS, * f;
+
+ if (e)
+ {
+ Top = (e->Ptr = top) + (e->Siz = siz);
+ e->Emm = this;
+
+ if (List)
+ {
+ for (f = List; f->Nxt; f = f->Nxt);
+ return (f->Nxt = e); // existing list: link to the end
+ }
+ else
+ {
+ return (List = e); // empty list: link to the head
+ }
+ }
+ }
+ fail: return NULL;
+ */
+ warning("STUB: EMM::Alloc");
+ return NULL;
+}
+
+
+void EMM::Release(void) {
+ while (List) {
+ EMS *e = List;
+ List = e->Nxt;
+ delete e;
+ }
+ Top = 0;
+}
+
+
+EMS::EMS(void) : Ptr(0), Siz(0), Nxt(NULL) {
+}
+
+
+void *EMS::operator & () const {
+ /*
+ uint16 pgn = (uint16) (Ptr >> 14),
+ off = (uint16) Ptr & PAGE_MASK,
+ cnt = (uint16) ((Ptr + SIZ(Siz) + PAGE_MASK) >> 14) - pgn,
+ cmd = MAP_PAGE << 8;
+
+ _DX = Emm->Han; // take EMM handle
+ asm dec cnt // prapare for deferred checking
+ asm or dx,dx // see if valid
+ asm jns more // negative handle = unavailable
+
+ fail: return NULL;
+
+ more:
+ asm mov ax,cmd // command + page frame index
+ asm mov bx,pgn // logical page number
+ asm int EMS_INT // do it!
+ asm or ah,ah // check error code
+ asm jnz fail // exit on error
+ asm inc cmd // advance page frame index
+ asm inc pgn // advance logical page number
+ asm cmp al,byte ptr cnt // all pages?
+ asm jb more
+
+ return (void *) (EMM::Frame + (void *) off);
+ */
+ warning("STUB: EMS::operator &");
+ return NULL;
+}
+
+
+uint16 EMS::Size(void) {
+ return Siz;
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/game.cpp b/engines/cge/game.cpp
new file mode 100644
index 0000000000..87daced31e
--- /dev/null
+++ b/engines/cge/game.cpp
@@ -0,0 +1,92 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/game.h"
+#include "cge/mouse.h"
+#include <stdlib.h>
+
+namespace CGE {
+
+uint8 *Glass(DAC *pal, uint8 r, uint8 g, uint8 b) {
+ uint8 *x = new uint8[256];
+ if (x) {
+ uint16 i;
+ for (i = 0; i < 256; i++) {
+ x[i] = Closest(pal, MkDAC(((uint16)(pal[i].R) * r) / 255,
+ ((uint16)(pal[i].G) * g) / 255,
+ ((uint16)(pal[i].B) * b) / 255));
+ }
+ }
+ return x;
+}
+
+
+uint8 *Mark(DAC *pal) {
+#define f(c) (c ^ 63)
+ uint8 *x = new uint8[256];
+ if (x) {
+ uint16 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(CGEEngine *vm, Bitmap **shpl)
+ : Sprite(vm, shpl), Tx(0), Ty(0), _vm(vm) {
+ Step(new_random(2));
+ Goto(L + new_random(R - L - _w), T + new_random(B - T - _h));
+}
+
+
+void FLY::Tick(void) {
+ Step();
+ if (!_flags._kept) {
+ if (new_random(10) < 1) {
+ Tx = new_random(3) - 1;
+ Ty = new_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);
+ }
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/game.h b/engines/cge/game.h
new file mode 100644
index 0000000000..a64018aa58
--- /dev/null
+++ b/engines/cge/game.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __GAME__
+#define __GAME__
+
+#include "cge/vga13h.h"
+#include "cge/bitmaps.h"
+
+namespace CGE {
+
+
+#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)
+
+int Sinus(long x);
+uint8 *Glass(DAC *pal, uint8 r, uint8 g, uint8 b);
+uint8 *Mark(DAC *pal);
+
+class FLY : public Sprite {
+ static int L, T, R, B;
+public:
+ int Tx, Ty;
+ FLY(CGEEngine *vm, Bitmap **shpl);
+ void Tick(void);
+private:
+ CGEEngine *_vm;
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/general.cpp b/engines/cge/general.cpp
new file mode 100644
index 0000000000..7bf753ff9f
--- /dev/null
+++ b/engines/cge/general.cpp
@@ -0,0 +1,420 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/boot.h"
+#include "cge/general.h"
+#include "cge/snddrv.h"
+#include "cge/wav.h"
+
+namespace CGE {
+
+DAC StdPal[] = {// R G B
+ { 0, 60, 0}, // 198
+ { 0, 104, 0}, // 199
+ { 20, 172, 0}, // 200
+ { 82, 82, 0}, // 201
+ { 0, 132, 82}, // 202
+ { 132, 173, 82}, // 203
+ { 82, 0, 0}, // 204
+ { 206, 0, 24}, // 205
+ { 255, 33, 33}, // 206
+ { 123, 41, 0}, // 207
+ { 0, 41, 0}, // 208
+ { 0, 0, 82}, // 209
+ { 132, 0, 0}, // 210
+ { 255, 0, 0}, // 211
+ { 255, 66, 66}, // 212
+ { 148, 66, 16}, // 213
+ { 0, 82, 0}, // 214
+ { 0, 0, 132}, // 215
+ { 173, 0, 0}, // 216
+ { 255, 49, 0}, // 217
+ { 255, 99, 99}, // 218
+ { 181, 107, 49}, // 219
+ { 0, 132, 0}, // 220
+ { 0, 0, 255}, // 221
+ { 173, 41, 0}, // 222
+ { 255, 82, 0}, // 223
+ { 255, 132, 132}, // 224
+ { 214, 148, 74}, // 225
+ { 41, 214, 0}, // 226
+ { 0, 82, 173}, // 227
+ { 255, 214, 0}, // 228
+ { 247, 132, 49}, // 229
+ { 255, 165, 165}, // 230
+ { 239, 198, 123}, // 231
+ { 173, 214, 0}, // 232
+ { 0, 132, 214}, // 233
+ { 57, 57, 57}, // 234
+ { 247, 189, 74}, // 235
+ { 255, 198, 198}, // 236
+ { 255, 239, 173}, // 237
+ { 214, 255, 173}, // 238
+ { 82, 173, 255}, // 239
+ { 107, 107, 107}, // 240
+ { 247, 222, 99}, // 241
+ { 255, 0, 255}, // 242
+ { 255, 132, 255}, // 243
+ { 132, 132, 173}, // 244
+ { 148, 247, 255}, // 245
+ { 148, 148, 148}, // 246
+ { 82, 0, 82}, // 247
+ { 112, 68, 112}, // 248
+ { 176, 88, 144}, // 249
+ { 214, 132, 173}, // 250
+ { 206, 247, 255}, // 251
+ { 198, 198, 198}, // 252
+ { 0, 214, 255}, // 253
+ { 96, 224, 96 }, // 254
+ { 255, 255, 255}, // 255
+};
+
+DRVINFO SNDDrvInfo;
+
+EC void _fqsort(void *base, uint16 nelem, uint16 width, int (*fcmp)(const void *, const void *)) {
+ warning("STUB: _fqsort");
+}
+
+const char *ProgName(const char *ext) {
+ warning("ProgName");
+
+ static Common::String buf = "CGE";
+ if (ext)
+ buf += ext;
+ return buf.c_str();
+}
+
+char *MergeExt(char *buf, const char *nam, const char *ext) {
+// char dr[MAXDRIVE], di[MAXDIR], na[MAXFILE], ex[MAXEXT];
+// fnmerge(buf, dr, di, na, (fnsplit(nam, dr, di, na, ex) & EXTENSION) ? ex : ext);
+// return buf;
+ warning("MergeExt");
+
+ strcpy(buf, nam);
+ char *dot = strrchr(buf, '.');
+ if (!dot)
+ strcat(buf, ext);
+
+ return buf;
+}
+
+char *ForceExt(char *buf, const char *nam, const char *ext) {
+// char dr[MAXDRIVE], di[MAXDIR], na[MAXFILE], ex[MAXEXT];
+// fnsplit(nam, dr, di, na, ex);
+// fnmerge(buf, dr, di, na, ext);
+// return buf;
+ strcpy(buf, nam);
+ char *dot = strrchr(buf, '.');
+ if (dot)
+ *dot = '\0';
+ strcat(buf, ext);
+
+ return buf;
+}
+
+static unsigned Seed = 1;
+
+unsigned FastRand(void) {
+ return Seed = 257 * Seed + 817;
+}
+unsigned FastRand(unsigned s) {
+ return Seed = 257 * s + 817;
+}
+
+uint16 RCrypt(void *buf, uint16 siz, uint16 seed) {
+ if (buf && siz) {
+ byte *b = static_cast<byte *>(buf);
+ byte *q = b + (siz - 1);
+ seed = FastRand(seed);
+ *b++ ^= seed;
+ while (buf < q)
+ *b++ ^= FastRand();
+ if (buf == q)
+ *b ^= (seed = FastRand());
+ }
+ return seed;
+}
+
+uint16 XCrypt(void *buf, uint16 siz, uint16 seed) {
+ byte *b = static_cast<byte *>(buf);
+
+ for (uint16 i = 0; i < siz; i++)
+ *b++ ^= seed;
+
+ return seed;
+}
+
+uint16 atow(const char *a) {
+ uint16 w = 0;
+ if (a)
+ while (IsDigit(*a))
+ w = (10 * w) + (*(a++) & 0xF);
+ return w;
+}
+
+uint16 xtow(const char *x) {
+ uint16 w = 0;
+ if (x) {
+ while (IsHxDig(*x)) {
+ register uint16 d = *(x++);
+ if (d > '9')
+ d -= 'A' - ('9' + 1);
+ w = (w << 4) | (d & 0xF);
+ }
+ }
+ return w;
+}
+
+char *wtom(uint16 val, char *str, int radix, int len) {
+ while (--len >= 0) {
+ uint16 w = val % radix;
+ if (w > 9)
+ w += ('A' - ('9' + 1));
+ str[len] = '0' + w;
+ val /= radix;
+ }
+ return str;
+}
+
+char *dwtom(uint32 val, char *str, int radix, int len) {
+ while (--len >= 0) {
+ uint16 w = (uint16) (val % radix);
+ if (w > 9)
+ w += ('A' - ('9' + 1));
+ str[len] = '0' + w;
+ val /= radix;
+ }
+ return str;
+}
+
+IOHAND::IOHAND(IOMODE mode, CRYPT *crpt)
+ : XFILE(mode), Crypt(crpt), Seed(SEED) {
+ _file = new Common::File();
+}
+
+IOHAND::IOHAND(const char *name, IOMODE mode, CRYPT *crpt)
+ : XFILE(mode), Crypt(crpt), Seed(SEED) {
+ // TODO: Check if WRI and/or UPD modes are needed, and map to a save file
+ assert(mode == REA);
+
+ _file = new Common::File();
+ _file->open(name);
+}
+
+IOHAND::~IOHAND(void) {
+ _file->close();
+ delete _file;
+}
+
+uint16 IOHAND::Read(void *buf, uint16 len) {
+ if (Mode == WRI || !_file->isOpen())
+ return 0;
+
+ uint16 bytesRead = _file->read(buf, len);
+ if (!bytesRead)
+ error("Read %s - %d bytes", _file->getName(), len);
+ if (Crypt)
+ Seed = Crypt(buf, len, Seed);
+ return bytesRead;
+}
+
+uint16 IOHAND::Write(void *buf, uint16 len) {
+ error("IOHAND::Write not supported");
+/*
+ if (len) {
+ if (Mode == REA || Handle < 0)
+ return 0;
+ if (Crypt)
+ Seed = Crypt(buf, len, Seed);
+ Error = _dos_write(Handle, buf, len, &len);
+ if (Crypt)
+ Seed = Crypt(buf, len, Seed); //------$$$$$$$
+ }
+ return len;
+*/
+}
+
+long IOHAND::Mark(void) {
+ return _file->pos();
+}
+
+long IOHAND::Seek(long pos) {
+ _file->seek(pos, SEEK_SET);
+ return _file->pos();
+}
+
+long IOHAND::Size(void) {
+ return _file->size();
+}
+
+bool IOHAND::Exist(const char *name) {
+ Common::File f;
+ return f.exists(name);
+}
+
+//#define EMS_ADR(a) (FP_SEG(a) > 0xA000)
+//#define HNODE_OK(p) (heapchecknode(p)==4)
+
+MEM_TYPE MemType(void *mem) {
+ /* if (FP_SEG(mem) == _DS) {
+ if (heapchecknode((void *)mem)==4)
+ return NEAR_MEM;
+ } else {
+ if (FP_SEG(mem) > 0xA000)
+ return EMS_MEM;
+ else if (farheapchecknode(mem)==4)
+ return FAR_MEM;
+ }
+ return BAD_MEM;
+ */
+ warning("STUB: MemType");
+ return FAR_MEM;
+}
+
+bool IsVga() {
+ return true;
+}
+
+EC void SNDInit() {
+ warning("STUB: SNDInit");
+}
+
+EC void SNDDone() {
+ // FIXME: STUB: SNDDone
+}
+
+EC void SNDSetVolume() {
+ warning("STUB: SNDSetVolume");
+}
+
+EC void SNDDigiStart(SMPINFO *PSmpInfo) {
+ warning("STUB: SNDDigitStart");
+}
+
+EC void SNDDigiStop(SMPINFO *PSmpInfo) {
+ warning("STUB: SNDDigiStop");
+}
+
+EC void SNDMIDIStart(uint8 *MIDFile) {
+ warning("STUB: SNDMIDIStart");
+}
+
+EC void SNDMIDIStop() {
+ // FIXME: STUB: SNDMIDIStop
+}
+
+DATACK *LoadWave(XFILE *file, EMM *emm) {
+ warning("STUB: LoadWave");
+ return NULL;
+}
+
+int TakeEnum(const char **tab, const char *txt) {
+ const char **e;
+ if (txt) {
+ for (e = tab; *e; e++) {
+ if (scumm_stricmp(txt, *e) == 0) {
+ return e - tab;
+ }
+ }
+ }
+ return -1;
+}
+
+Boot *ReadBoot(int drive) {
+ /*
+ struct fatinfo fi; Boot *b;
+ getfat(drive+1, &fi);
+ if (fi.fi_sclus & 0x80) return NULL;
+ if ((b = malloc(fi.fi_bysec)) == NULL) return NULL;
+ // read boot sector
+ if (absread(drive, 1, 0L, b) == 0) return b;
+ free(b);
+ return NULL;
+ */
+ warning("STUB: ReadBoot");
+ return NULL;
+}
+
+long Timer(void) {
+/*
+ asm mov ax,0x40
+ asm mov es,ax
+ asm mov cx,es:[0x6C]
+ asm mov dx,es:[0x6E]
+ return ((long) _DX << 16) | _CX;
+*/
+ warning("STUB: Timer");
+ return 0;
+}
+
+int new_random(int range) {
+ warning("STUB: new_random(a)");
+ return 0;
+}
+
+#define TIMER_INT 0x08
+//void interrupt (* ENGINE::OldTimer) (...) = NULL;
+
+ENGINE::ENGINE (uint16 tdiv)
+{
+/*
+ // steal timer interrupt
+ OldTimer = getvect(TIMER_INT);
+ setvect(TIMER_INT, NewTimer);
+
+ // set turbo-timer mode
+ asm mov al,0x36
+ asm out 0x43,al
+ asm mov ax,TMR_DIV
+ asm out 0x40,al
+ asm mov al,ah
+ asm out 0x40,al
+*/
+ warning("STUB: ENGINE::ENGINE");
+}
+
+ENGINE::~ENGINE (void)
+{
+/*
+ // reset timer
+ asm mov al,0x36
+ asm out 0x43,al
+ asm xor al,al
+ asm out 0x40,al
+ asm out 0x40,al
+ // bring back timer interrupt
+ setvect(TIMER_INT, OldTimer);
+*/
+ warning("STUB: ENGINE::~ENGINE");
+}
+
+DATACK::~DATACK (void)
+{
+ if (!e && Buf) free(Buf);
+}
+} // End of namespace CGE
+
diff --git a/engines/cge/general.h b/engines/cge/general.h
new file mode 100644
index 0000000000..4946e40c7b
--- /dev/null
+++ b/engines/cge/general.h
@@ -0,0 +1,240 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __GENERAL__
+#define __GENERAL__
+
+#include "common/system.h"
+#include "common/file.h"
+#include "common/random.h"
+#include "common/textconsole.h"
+#include "common/str.h"
+#include "cge/jbw.h"
+#include "cge/boot.h"
+
+namespace CGE {
+
+#define SEED 0xA5
+
+#define SCR_WID_ 320
+#define SCR_HIG_ 200
+#define SCR_WID ((uint16)SCR_WID_)
+#define SCR_HIG ((uint16)SCR_HIG_)
+#define SCR_SEG 0xA000
+#define SCR_ADR ((uint8 *) 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 {
+ uint8 R, G, B;
+} DAC;
+
+typedef uint16 CRYPT(void *buf, uint16 siz, uint16 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;
+ }
+
+ bool operator == (COUPLE c) {
+ return ((A - c.A) | (B - c.B)) == 0;
+ }
+
+ bool operator != (COUPLE c) {
+ return !(operator == (c));
+ }
+
+ void Split(signed char &a, signed char &b) {
+ a = A;
+ b = B;
+ }
+};
+
+
+class ENGINE {
+protected:
+ static void (* OldTimer)(...);
+ static void NewTimer(...);
+public:
+ ENGINE(uint16 tdiv);
+ ~ENGINE(void);
+};
+
+
+class EMS;
+
+
+class EMM {
+ friend class EMS;
+ bool Test(void);
+ long Top, Lim;
+ EMS *List;
+ int Han;
+ static void *Frame;
+public:
+ EMM(long size = 0);
+ ~EMM(void);
+ EMS *Alloc(uint16 siz);
+ void Release(void);
+};
+
+
+class EMS {
+ friend class EMM;
+ EMM *Emm;
+ long Ptr;
+ uint16 Siz;
+ EMS *Nxt;
+public:
+ EMS(void);
+ void *operator & () const;
+ uint16 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;
+ uint16 Error;
+ XFILE(void) : Mode(REA), Error(0) { }
+ XFILE(IOMODE mode) : Mode(mode), Error(0) { }
+ virtual uint16 Read(void *buf, uint16 len) = 0;
+ virtual uint16 Write(void *buf, uint16 len) = 0;
+ virtual long Mark(void) = 0;
+ virtual long Size(void) = 0;
+ virtual long Seek(long pos) = 0;
+ virtual ~XFILE() { }
+};
+
+
+template <class T>
+inline uint16 XRead(XFILE *xf, T *t) {
+ return xf->Read((uint8 *) t, sizeof(*t));
+}
+
+
+class IOHAND : public XFILE {
+protected:
+ Common::File *_file;
+ uint16 Seed;
+ CRYPT *Crypt;
+public:
+ IOHAND(const char *name, IOMODE mode = REA, CRYPT crypt = NULL);
+ IOHAND(IOMODE mode = REA, CRYPT *crpt = NULL);
+ virtual ~IOHAND(void);
+ static bool Exist(const char *name);
+ uint16 Read(void *buf, uint16 len);
+ uint16 Write(void *buf, uint16 len);
+ long Mark(void);
+ long Size(void);
+ long Seek(long pos);
+ //timeb Time (void);
+// void SetTime (timeb t);
+};
+
+
+CRYPT XCrypt;
+CRYPT RCrypt;
+MEM_TYPE MemType(void *mem);
+uint16 atow(const char *a);
+uint16 xtow(const char *x);
+char *wtom(uint16 val, char *str, int radix, int len);
+char *dwtom(uint32 val, char *str, int radix, int len);
+int TakeEnum(const char **tab, const char *txt);
+uint16 ChkSum(void *m, uint16 n);
+long Timer(void);
+char *MergeExt(char *buf, const char *nam, const char *ext);
+char *ForceExt(char *buf, const char *nam, const char *ext);
+int DriveCD(unsigned drv);
+bool IsVga(void);
+
+
+// MISSING FUNCTIONS
+EC void _fqsort(void *base, uint16 nelem, uint16 width, int (*fcmp)(const void *, const void *));
+const char *ProgName(const char *ext = NULL);
+char *MergeExt(char *buf, const char *nam, const char *ext);
+char *ForceExt(char *buf, const char *nam, const char *ext);
+unsigned FastRand(void);
+unsigned FastRand(unsigned s);
+uint16 RCrypt(void *buf, uint16 siz, uint16 seed);
+uint16 atow(const char *a);
+uint16 xtow(const char *x);
+char *wtom(uint16 val, char *str, int radix, int len);
+char *dwtom(uint32 val, char * str, int radix, int len);
+int TakeEnum(const char **tab, const char *txt);
+Boot *ReadBoot(int drive);
+long Timer(void);
+int new_random(int range);
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/gettext.cpp b/engines/cge/gettext.cpp
new file mode 100644
index 0000000000..e3c60b6e21
--- /dev/null
+++ b/engines/cge/gettext.cpp
@@ -0,0 +1,122 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/gettext.h"
+#include "cge/keybd.h"
+#include "cge/mouse.h"
+#include "cge/cge_main.h"
+#include <string.h>
+
+namespace CGE {
+
+GET_TEXT *GET_TEXT::Ptr = NULL;
+
+
+GET_TEXT::GET_TEXT(CGEEngine *vm, const char *info, char *text, int size, void (*click)(void))
+ : TALK(vm), Text(text), Size(min<int>(size, GTMAX)), Len(min<int>(Size, strlen(text))),
+ Cntr(GTBLINK), Click(click), OldKeybClient(KEYBOARD::SetClient(this)), _vm(vm) {
+ 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(uint16 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);
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/gettext.h b/engines/cge/gettext.h
new file mode 100644
index 0000000000..33210758af
--- /dev/null
+++ b/engines/cge/gettext.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __GETTEXT__
+#define __GETTEXT__
+
+#include "cge/general.h"
+#include "cge/talk.h"
+
+namespace CGE {
+
+#define GTMAX 24
+#define GTBLINK 6
+#define GTTIME 6
+
+class GET_TEXT : public TALK {
+ char Buff[GTMAX + 2], * Text;
+ uint16 Size, Len;
+ uint16 Cntr;
+ Sprite *OldKeybClient;
+ void (*Click)();
+public:
+ static GET_TEXT *Ptr;
+ GET_TEXT(CGEEngine *vm, const char *info, char *text, int size, void (*click)(void) = NULL);
+ ~GET_TEXT();
+ void Touch(uint16 mask, int x, int y);
+ void Tick();
+
+private:
+ CGEEngine *_vm;
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/ident.h b/engines/cge/ident.h
new file mode 100644
index 0000000000..da36bfa682
--- /dev/null
+++ b/engines/cge/ident.h
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __IDENT__
+#define __IDENT__
+
+namespace CGE {
+
+struct IDENT {
+ char copr[83];
+ char fill[8];
+ unsigned long disk;
+ unsigned char cork;
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/jbw.h b/engines/cge/jbw.h
new file mode 100644
index 0000000000..12c6609f4e
--- /dev/null
+++ b/engines/cge/jbw.h
@@ -0,0 +1,156 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __JBW__
+#define __JBW__
+
+#include "common/scummsys.h"
+
+namespace CGE {
+
+// Defines found in cge.mak
+#define VOL
+#define INI_FILE VFILE // Or is it CFILE?
+#define PIC_FILE VFILE
+#define BMP_MODE 0
+//
+
+#define BEL 7
+#define BS 8
+#define HT 9
+#define LF 10
+#define FF 12
+#define CR 13
+#define MAXFILE 128
+
+#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 *) malloc(sizeof(t) * (n)))
+#define ArrayCount(a) (sizeof(a) / sizeof((a)[0]))
+#define MAX_TIMER 0x1800B0L
+
+typedef void (MouseFunType)(void);
+
+#define Lo(d) (((int *) &d)[0])
+#define Hi(d) (((int *) &d)[1])
+#define LoWord(d) ((uint16) Lo(d))
+#define HiWord(d) ((uint16) 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 *) ((void _seg *) 0x40 + (void *) 0x6C)))
+#define KeyStat (*((volatile struct KeyStatStruct *) ((void _seg *) 0x40 + (void *) 0x17)))
+#define BreakFlag (*((volatile uint8 *) ((void _seg *) 0x40 + (void *) 0x71)))
+#define PostFlag (*((volatile uint16 *) ((void _seg *) 0x40 + (void *) 0x72)))
+#define POST ((void (*)(void)) ((void _seg *) 0xF000 + (void *) 0xFFF0))
+
+
+#ifdef __cplusplus
+#define EC extern "C"
+#else
+#define EC
+#endif
+
+
+extern uint16 _stklen;
+extern uint16 _heaplen;
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/keybd.cpp b/engines/cge/keybd.cpp
new file mode 100644
index 0000000000..8530815b16
--- /dev/null
+++ b/engines/cge/keybd.cpp
@@ -0,0 +1,151 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/keybd.h"
+#include "cge/mouse.h"
+
+namespace CGE {
+
+Sprite *KEYBOARD::Client = NULL;
+uint8 KEYBOARD::Key[0x60] = { 0 };
+uint16 KEYBOARD::Current = 0;
+uint16 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 (* KEYBOARD::OldKeyboard)(...);
+
+
+KEYBOARD::KEYBOARD(void) {
+ // steal keyboard interrupt
+ /* TODO replace totally by scummvm handling
+ OldKeyboard = getvect(KEYBD_INT);
+ setvect(KEYBD_INT, NewKeyboard);
+ */
+ warning("STUB: KEYBOARD::KEYBOARD");
+}
+
+
+KEYBOARD::~KEYBOARD(void) {
+ // bring back keyboard interrupt
+ /* TODO replace totally by scummvm handling
+ setvect(KEYBD_INT, OldKeyboard);
+ */
+ // FIXME: STUB: KEYBOARD::~KEYBOARD
+}
+
+
+Sprite *KEYBOARD::SetClient(Sprite *spr) {
+ Swap(Client, spr);
+ return spr;
+}
+
+
+void KEYBOARD::NewKeyboard(...) {
+ // table address
+ /*
+ _SI = (uint16) 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 = (uint16) Code;
+ asm add bx,bx // uint16 size
+ asm mov ax,[si+bx]
+ asm or ax,ax
+ asm jz xit // zero means NO KEY
+ Current = _AX;
+
+ _SI = (uint16) 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
+ */
+ warning("STUB: KEYBOARD::NewKeyboard");
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/keybd.h b/engines/cge/keybd.h
new file mode 100644
index 0000000000..2cdbd558d8
--- /dev/null
+++ b/engines/cge/keybd.h
@@ -0,0 +1,63 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __KEYBD__
+#define __KEYBD__
+
+#include "cge/jbw.h"
+#include "cge/vga13h.h"
+
+namespace CGE {
+
+#define KEYBD_INT 9
+#define LSHIFT 42
+#define RSHIFT 54
+#define CTRL 29
+#define ALT 56
+
+
+class KEYBOARD {
+public:
+ static void (* OldKeyboard)(...);
+ static void NewKeyboard(...);
+ static uint16 Code[0x60];
+ static uint16 Current;
+ static Sprite *Client;
+ static uint8 Key[0x60];
+ static uint16 Last(void) {
+ uint16 cur = Current;
+ Current = 0;
+ return cur;
+ }
+ static Sprite *SetClient(Sprite *spr);
+ KEYBOARD(void);
+ ~KEYBOARD(void);
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/mixer.cpp b/engines/cge/mixer.cpp
new file mode 100644
index 0000000000..7b9ce59f5e
--- /dev/null
+++ b/engines/cge/mixer.cpp
@@ -0,0 +1,145 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/mixer.h"
+#include "cge/text.h"
+#include "cge/snail.h"
+#include "cge/mouse.h"
+#include "cge/snddrv.h"
+#include "cge/cge_main.h"
+#include <string.h>
+
+namespace CGE {
+
+extern MOUSE *Mouse;
+
+bool MIXER::Appear = false;
+
+
+MIXER::MIXER(CGEEngine *vm, int x, int y) : Sprite(vm, NULL), Fall(MIX_FALL), _vm(vm) {
+ Appear = true;
+ mb[0] = new Bitmap("VOLUME");
+ mb[1] = NULL;
+ SetShapeList(mb);
+ SetName(Text->getText(MIX_NAME));
+ _flags._syst = true;
+ _flags._kill = true;
+ _flags._bDel = true;
+ Goto(x, y);
+ _z = MIX_Z;
+
+ // slaves
+
+ uint i;
+ 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(_vm, 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(uint16 mask, int x, int y) {
+ Sprite::Touch(mask, x, y);
+ if (mask & L_UP) {
+ uint8 *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;
+ int 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 {
+ for (uint 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);
+
+ //TODO Change the SNPOST message send to a special way to send function pointer
+ //SNPOST_(SNEXEC, -1, 0, (void*)&SNDSetVolume);
+ warning("STUB: MIXER::Update");
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/mixer.h b/engines/cge/mixer.h
new file mode 100644
index 0000000000..d42d25ca24
--- /dev/null
+++ b/engines/cge/mixer.h
@@ -0,0 +1,61 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __MIXER__
+#define __MIXER__
+
+#include "cge/vga13h.h"
+
+namespace CGE {
+
+#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 bool Appear;
+ MIXER(CGEEngine *vm, int x, int y);
+ ~MIXER();
+ void Touch(uint16 mask, int x, int y);
+ void Tick();
+private:
+ CGEEngine *_vm;
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/module.mk b/engines/cge/module.mk
new file mode 100644
index 0000000000..70967667a5
--- /dev/null
+++ b/engines/cge/module.mk
@@ -0,0 +1,39 @@
+MODULE := engines/cge
+
+MODULE_OBJS := \
+ bitmap.o \
+ bitmaps.o \
+ btfile.o \
+ cfile.o \
+ cge.o \
+ cge_main.o \
+ config.o \
+ console.o \
+ detection.o \
+ ems.o \
+ game.o \
+ general.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
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_CGE), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
+
diff --git a/engines/cge/mouse.cpp b/engines/cge/mouse.cpp
new file mode 100644
index 0000000000..5bdf7449fc
--- /dev/null
+++ b/engines/cge/mouse.cpp
@@ -0,0 +1,194 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/mouse.h"
+#include "cge/text.h"
+#include "cge/cge_main.h"
+
+namespace CGE {
+
+Event Evt[EVT_MAX];
+
+uint16 EvtHead = 0, EvtTail = 0;
+
+MOUSE_FUN *MOUSE::OldMouseFun = NULL;
+uint16 MOUSE::OldMouseMask = 0;
+
+
+MOUSE::MOUSE(CGEEngine *vm, Bitmap **shpl) : Sprite(vm, shpl), Busy(NULL), Hold(NULL), hx(0), _vm(vm) {
+ static Seq ms[] = {
+ { 0, 0, 0, 0, 1 },
+ { 1, 1, 0, 0, 1 }
+ };
+
+ SetSeq(ms);
+
+ /* TODO Mouse handling
+ // 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);
+ */
+ Exist = true;
+ warning("STUB: MOUSE::MOUSE");
+}
+
+
+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);
+ }
+ */
+ warning("STUB: MOUSE::On");
+}
+
+
+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);
+ }
+ */
+ warning("STUB: MOUSE::Off");
+}
+
+
+void MOUSE::ClrEvt(Sprite *spr) {
+ if (spr) {
+ uint16 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;
+ 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)
+ Hold->Goto(_x - hx, _y - hy);
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/mouse.h b/engines/cge/mouse.h
new file mode 100644
index 0000000000..4d95f10423
--- /dev/null
+++ b/engines/cge/mouse.h
@@ -0,0 +1,85 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __MOUSE__
+#define __MOUSE__
+
+#include "cge/game.h"
+#include "cge/talk.h"
+
+namespace CGE {
+
+#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 {
+ uint16 _msk;
+ uint16 _x;
+ uint16 _y;
+ Sprite *_ptr;
+};
+
+extern Event Evt[EVT_MAX];
+extern uint16 EvtHead, EvtTail;
+typedef void (MOUSE_FUN)(void);
+
+
+class MOUSE : public Sprite {
+ static MOUSE_FUN *OldMouseFun;
+ static MOUSE_FUN NewMouseFun;
+ static uint16 OldMouseMask;
+ Sprite *Hold;
+ int hx, hy;
+ //void SetFun (void);
+ //void ResetFun (void);
+public:
+ bool Exist;
+ int Buttons;
+ Sprite *Busy;
+ //Sprite *Touched;
+ MOUSE(CGEEngine *vm, Bitmap **shpl = MC);
+ ~MOUSE();
+ void On();
+ void Off();
+ static void ClrEvt(Sprite *spr = NULL);
+ void Tick();
+private:
+ CGEEngine *_vm;
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/snail.cpp b/engines/cge/snail.cpp
new file mode 100644
index 0000000000..565c7d33f0
--- /dev/null
+++ b/engines/cge/snail.cpp
@@ -0,0 +1,1135 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/general.h"
+#include "cge/sound.h"
+#include "cge/snail.h"
+#include "cge/vga13h.h"
+#include "cge/bitmaps.h"
+#include "cge/text.h"
+#include "cge/mouse.h"
+#include "cge/cge_main.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "cge/keybd.h"
+
+namespace CGE {
+
+static void _enable() {
+ warning("STUB: _enable");
+}
+
+static void _disable() {
+ warning("STUB: _disable");
+}
+
+int MaxCave = 0;
+
+SCB Scb = { NULL, 0, NULL };
+bool Flag[4];
+bool Dark = false;
+bool Game = false;
+int Now = 1;
+int Lev = -1;
+
+extern Sprite *_pocLight;
+
+//-------------------------------------------------------------------------
+// SPRITE * Pocket[POCKET_NX]={ NULL, NULL, NULL, NULL,
+// NULL, NULL, NULL, NULL, };
+// int PocPtr = 0;
+//-------------------------------------------------------------------------
+extern Sprite *_pocket[];
+extern int PocPtr;
+
+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 = 0;
+ int Stage = 0;
+
+ 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 = new_random(3), hand = (dup[0]->_shpCnt == 6);
+ Stage++;
+ if (hand && Stage > DRESSED)
+ ++hand;
+ if (i >= 0 || (dup[i] == spr && new_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;
+
+ 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(new_random(6));
+ k2->Step(new_random(6));
+ k3->Step(new_random(6));
+ ///--------------------
+ if (spr->_ref == 1 && KEYBOARD::Key[ALT]) {
+ k1->Step(5);
+ k2->Step(5);
+ k3->Step(5);
+ }
+ ///--------------------
+ SNPOST(SNSETZ, 20700, 0, NULL);
+ bool 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(new_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) {
+ for (int 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) {
+ // TODO : Get x and y from M but not using segment / offset
+ //bmp->Hide(FP_OFF(bmp->_m), FP_SEG(bmp->_m));
+ bmp->_m = NULL;
+ delete bmp;
+ warning("STUB: SNGhost");
+}
+
+
+void FeedSnail(Sprite *spr, SNLIST snq) {
+ if (spr)
+ if (spr->Active()) {
+ uint8 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) {
+ uint8 *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;
+ }
+ }
+ }
+ }
+}
+
+
+const 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(CGEEngine *vm, bool turbo)
+ : Turbo(turbo), Busy(false), TextDelay(false),
+ Pause(0), TalkEnable(true),
+ Head(0), Tail(0), SNList(farnew(COM, 256)), _vm(vm) {
+}
+
+
+SNAIL::~SNAIL(void) {
+ if (SNList)
+ free(SNList);
+}
+
+
+void SNAIL::AddCom(SNCOM com, int ref, int val, void *ptr) {
+ _disable();
+ COM *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 *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()) {
+ bool 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;
+ bool was1 = (was == 0 || was == Now);
+ bool 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 = VGA::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;
+ bool was1 = (was == 0 || was == Now);
+ bool 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) == 1) {
+ 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) == 1) {
+ 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, uint16 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) {
+ ++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, bool v) {
+ Flag[fn] = v;
+}
+
+
+static void SNSetRef(Sprite *spr, int nr) {
+ if (spr)
+ spr->_ref = nr;
+}
+
+
+void SNFlash(bool on) {
+ if (on) {
+ DAC *pal = farnew(DAC, PAL_CNT);
+ if (pal) {
+ memcpy(pal, VGA::SysPal, PAL_SIZ);
+ for (int 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(VGA::SysPal, 64);
+ Dark = false;
+}
+
+
+static void SNLight(bool in) {
+ if (in)
+ Vga->Sunrise(VGA::SysPal);
+ else
+ Vga->Sunset();
+ Dark = ! in;
+}
+
+
+static void SNBarrier(int cav, int bar, bool horz) {
+ ((uint8 *)(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(bool on) {
+ if (on)
+ Mouse->On();
+ else
+ Mouse->Off();
+}
+
+
+void SNAIL::RunCom(void) {
+ static int count = 1;
+ if (! Busy) {
+ Busy = true;
+ uint8 tmphea = Head;
+ while (Tail != tmphea) {
+ COM *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);
+ Text->Say(Text->getText(snc->Val), sprel);
+ Sys->FunDel = HEROFUN0;
+ }
+ break;
+ case SNINF :
+ if (TalkEnable) {
+ _vm->Inf(Text->getText(snc->Val));
+ Sys->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);
+ warning("Problematic call of SwitchCave in SNAIL::RunCom");
+ 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 :
+ // TODO: Handle correctly the execution of function pointer coming from Message send SNPOST
+ // ((void(*)(int)) (snc->Ptr))(snc->Val); break;
+ warning("STUB: SNEXEC code");
+ case SNSTEP :
+ sprel->Step();
+ break;
+ case SNZTRIM :
+ SNZTrim(sprel);
+ break;
+ case SNGHOST :
+ SNGhost((Bitmap *) snc->Ptr);
+ break;
+ default :
+ warning("Unhandled snc->Com in SNMouse(bool)");
+ break;
+ }
+ Tail++;
+ if (!Turbo)
+ break;
+ }
+xit:
+ Busy = false;
+ }
+}
+
+
+bool SNAIL::Idle(void) {
+ return (Head == Tail);
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/snail.h b/engines/cge/snail.h
new file mode 100644
index 0000000000..e1df628d3b
--- /dev/null
+++ b/engines/cge/snail.h
@@ -0,0 +1,126 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __SNAIL__
+#define __SNAIL__
+
+#include "cge/jbw.h"
+#include "cge/cge.h"
+
+namespace CGE {
+
+#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 {
+ uint8 Horz, Vert;
+} BAR;
+
+
+struct SCB {
+ uint8 *Ptr;
+ uint16 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 {
+public:
+ struct COM {
+ SNCOM Com;
+ int Ref;
+ int Val;
+ void *Ptr;
+ } *SNList;
+ uint8 Head, Tail;
+ bool Turbo, Busy, TextDelay;
+ uint16 Pause;
+ static const char *ComTxt[];
+ bool TalkEnable;
+ SNAIL(CGEEngine *vm, bool turbo = false);
+ ~SNAIL();
+ 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);
+ bool Idle(void);
+private:
+ CGEEngine *_vm;
+};
+
+
+void SelectPocket(int n);
+void PocFul(void);
+
+
+extern SCB Scb;
+extern bool Flag[4];
+extern bool Game;
+extern bool 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[];
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/snddrv.h b/engines/cge/snddrv.h
new file mode 100644
index 0000000000..3d1658e1e0
--- /dev/null
+++ b/engines/cge/snddrv.h
@@ -0,0 +1,130 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+// ******************************************************
+// * 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__
+
+namespace CGE {
+
+// ******************************************************
+// * 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
+ uint16 DBASE; // digi base port
+ uint16 DDMA; // digi dma no
+ uint16 DIRQ; // digi irq no
+ uint16 MBASE; // midi base port
+ union {
+ struct {
+ uint16 DR : 4;
+ uint16 DL : 4;
+ uint16 MR : 4;
+ uint16 ML : 4;
+ } VOL4;
+ struct {
+ uint8 D; // digi volume
+ uint8 M; // midi volume
+ } VOL2;
+ };
+};
+
+// sample info
+struct SMPINFO {
+ uint8 *saddr; // address
+ uint16 slen; // length
+ uint16 span; // left/right pan (0-15)
+ int sflag; // flag
+};
+
+// ******************************************************
+// * Data *
+// ******************************************************
+// driver info
+extern DRVINFO SNDDrvInfo;
+
+// midi player flag (1 means we are playing)
+extern uint16 MIDIPlayFlag;
+
+// midi song end flag (1 means we have crossed end mark)
+extern uint16 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(uint8 *MIDFile);
+
+// Stop MIDI File
+EC void SNDMIDIStop(void);
+
+// Play MIDI File (to be called while interrupting)
+// WARNING: Uses ALL registers!
+EC void SNDMIDIPlay(void);
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/sound.cpp b/engines/cge/sound.cpp
new file mode 100644
index 0000000000..4a7b63fb08
--- /dev/null
+++ b/engines/cge/sound.cpp
@@ -0,0 +1,228 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/general.h"
+#include "cge/startup.h"
+#include "cge/sound.h"
+#include "cge/text.h"
+#include "cge/cfile.h"
+#include "cge/vol.h"
+
+
+namespace CGE {
+
+bool 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 = (uint8 *) &*(wav->EAddr());
+ smpinf.slen = (uint16)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);
+ INI_FILE file = INI_FILE(fname);
+ DATACK *wav = LoadWave(&file, &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);
+
+ INI_FILE file = INI_FILE(fname);
+ DATACK *wav = LoadWave(&file, &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 uint8 *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) {
+ uint16 siz = (uint16) mid.Size();
+ midi = new uint8[siz];
+ if (midi) {
+ mid.Read(midi, siz);
+ if (mid.Error)
+ KillMIDI();
+ else
+ SNDMIDIStart(midi);
+ }
+ }
+ }
+}
+
+
+EC void *Patch(int pat) {
+ void *p = NULL;
+ static char fn[] = "PATCH000.SND";
+
+ wtom(pat, fn + 5, 10, 3);
+ INI_FILE snd = fn;
+ if (! snd.Error) {
+ uint16 siz = (uint16) snd.Size();
+ p = (uint8 *) malloc(siz);
+ if (p) {
+ snd.Read(p, siz);
+ if (snd.Error) {
+ free(p);
+ p = NULL;
+ }
+ }
+ }
+ return p;
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/sound.h b/engines/cge/sound.h
new file mode 100644
index 0000000000..b617891268
--- /dev/null
+++ b/engines/cge/sound.h
@@ -0,0 +1,82 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __SOUND__
+#define __SOUND__
+
+#include "cge/wav.h"
+#include "cge/snddrv.h"
+
+namespace CGE {
+
+#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 bool Music;
+extern SOUND Sound;
+extern FX Fx;
+
+
+void LoadMIDI(int ref);
+void KillMIDI(void);
+
+} // End of namespace CGE
+
+#endif
+
diff --git a/engines/cge/startup.cpp b/engines/cge/startup.cpp
new file mode 100644
index 0000000000..4895ce9861
--- /dev/null
+++ b/engines/cge/startup.cpp
@@ -0,0 +1,176 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/startup.h"
+#include "cge/text.h"
+#include "cge/sound.h"
+#include "cge/ident.h"
+#include "cge/cfile.h"
+#include "cge/snddrv.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+namespace CGE {
+
+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;
+uint16 STARTUP::Summa;
+
+
+void quit_now(int ref) {
+ error("%s", Text->getText(ref));
+}
+
+
+bool 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], " =:("));
+ uint16 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; uint32 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;
+ */
+ warning("STUB: STARTUP::get_parms");
+ return true;
+}
+
+
+STARTUP::STARTUP(void) {
+ /*
+ uint32 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);
+
+ 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;
+ }
+ }
+ */
+ warning("STUB: STARTUP::STARTUP");
+}
+
+
+const char *UsrPath(const char *nam) {
+ static char buf[MAXPATH] = ".\\", *p = buf + 2;
+#if defined(CD)
+ if (DriveCD(0)) {
+ bool 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 (scumm_strnicmp((const char *) buf, (const char*) 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;
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/startup.h b/engines/cge/startup.h
new file mode 100644
index 0000000000..5bfa9876d6
--- /dev/null
+++ b/engines/cge/startup.h
@@ -0,0 +1,79 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __STARTUP__
+#define __STARTUP__
+
+
+#include "cge/general.h"
+
+namespace CGE {
+
+#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 bool get_parms(void);
+public:
+ static int Mode;
+ static int Core;
+ static int SoundOk;
+ static uint16 Summa;
+ STARTUP(void);
+};
+
+
+extern EMM MiniEmm;
+
+const char *UsrPath(const char *nam);
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/talk.cpp b/engines/cge/talk.cpp
new file mode 100644
index 0000000000..5aa5e44b8d
--- /dev/null
+++ b/engines/cge/talk.cpp
@@ -0,0 +1,334 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/general.h"
+#include "cge/talk.h"
+#include "cge/vol.h"
+#include "cge/game.h"
+#include "cge/mouse.h"
+
+namespace CGE {
+
+#define WID_SIZ 256
+#define POS_SIZ 256
+#define MAP_SIZ (256*8)
+
+//uint8 FONT::Wid[WID_SIZ];
+//uint16 FONT::Pos[POS_SIZ];
+//uint8 FONT::Map[MAP_SIZ];
+
+
+FONT::FONT(const char *name) {
+ Map = farnew(uint8, MAP_SIZ);
+ Pos = farnew(uint16, POS_SIZ);
+ Wid = farnew(uint8, WID_SIZ);
+ if ((Map == NULL) || (Pos == NULL) || (Wid == NULL))
+ error("No core");
+ MergeExt(Path, name, FONT_EXT);
+ Load();
+}
+
+
+FONT::~FONT(void) {
+ free(Map);
+ free(Pos);
+ free(Wid);
+}
+
+
+void FONT::Load(void) {
+ INI_FILE f(Path);
+ if (! f.Error) {
+ f.Read(Wid, WID_SIZ);
+ if (! f.Error) {
+ uint16 i, p = 0;
+ for (i = 0; i < POS_SIZ; i++) {
+ Pos[i] = p;
+ p += Wid[i];
+ }
+ f.Read(Map, p);
+ }
+ }
+}
+
+
+uint16 FONT::Width(const char *text) {
+ uint16 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]);
+ }
+}
+*/
+
+
+TALK::TALK(CGEEngine *vm, const char *tx, TBOX_STYLE mode)
+ : Sprite(vm, NULL), Mode(mode), _vm(vm) {
+ TS[0] = TS[1] = NULL;
+ _flags._syst = true;
+ Update(tx);
+}
+
+
+TALK::TALK(CGEEngine *vm)
+ : Sprite(vm, NULL), Mode(PURE), _vm(vm) {
+ TS[0] = TS[1] = NULL;
+ _flags._syst = true;
+}
+
+
+/*
+TALK::~TALK (void) {
+ for (uint16 i = 0; i < ShpCnt; i++) {
+ if (FP_SEG(ShpList[i]) != _DS) { // small model: always false
+ delete ShpList[i];
+ ShpList[i] = NULL;
+ }
+ }
+}
+*/
+
+FONT *TALK::_Font;
+
+void TALK::init() {
+ _Font = new FONT(ProgName());
+}
+
+void TALK::deinit() {
+ delete _Font;
+}
+
+
+void TALK::Update(const char *tx) {
+ uint16 vmarg = (Mode) ? TEXT_VM : 0;
+ uint16 hmarg = (Mode) ? TEXT_HM : 0;
+ uint16 mw = 0, mh, ln = vmarg;
+ const char *p;
+ uint8 *m;
+
+ if (!TS[0]) {
+ uint16 k = 2 * hmarg;
+ mh = 2 * vmarg + FONT_HIG;
+ 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;
+ uint8 *f = _Font->Map + _Font->Pos[*tx];
+ for (i = 0; i < cw; i++) {
+ uint8 *pp = m;
+ uint16 n;
+ register uint16 b = *(f++);
+ for (n = 0; n < FONT_HIG; n++) {
+ if (b & 1)
+ *pp = TEXT_FG;
+ b >>= 1;
+ pp += mw;
+ }
+ m++;
+ }
+ }
+ tx++;
+ }
+ TS[0]->Code();
+ SetShapeList(TS);
+}
+
+
+
+
+Bitmap *TALK::Box(uint16 w, uint16 h) {
+ uint8 *b, * p, * q;
+ uint16 n, r = (Mode == ROUND) ? TEXT_RD : 0;
+
+ if (w < 8)
+ w = 8;
+ if (h < 8)
+ h = 8;
+ b = farnew(uint8, n = w * h);
+ if (! b)
+ error("No core");
+ memset(b, TEXT_BG, n);
+
+ if (Mode) {
+ p = b;
+ q = b + n - w;
+ memset(p, LGRAY, w);
+ memset(q, DGRAY, w);
+ while (p < q) {
+ p += w;
+ *(p - 1) = DGRAY;
+ *p = LGRAY;
+ }
+ p = b;
+ for (int 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
+ uint16 w = TS[0]->_w, h = TS[0]->_h;
+ uint8 *v = TS[0]->_v, * p;
+ uint16 dsiz = w >> 2; // data size (1 plane line size)
+ uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap
+ uint16 psiz = h * lsiz; // - last gap, but + plane trailer
+ uint16 size = 4 * psiz; // whole map size
+ uint16 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
+ memcpy(p, p - lsiz, rsiz);
+ p += psiz; // tricky replicate lines for plane 0
+ memcpy(p, p - lsiz, rsiz);
+ p += psiz; // same for plane 1
+ memcpy(p, p - lsiz, rsiz);
+ p += psiz; // same for plane 2
+ memcpy(p, p - lsiz, rsiz); // same for plane 3
+
+ // paint text line
+ if (text) {
+ uint8 *q;
+ p = v + 2 + TEXT_HM / 4 + (TEXT_HM % 4) * psiz;
+ q = v + size;
+
+ while (* text) {
+ uint16 cw = _Font->Wid[*text], i;
+ uint8 *fp = _Font->Map + _Font->Pos[*text];
+
+ for (i = 0; i < cw; i++) {
+ register uint16 b = fp[i];
+ uint16 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(CGEEngine *vm, uint16 w) : TALK(vm), OldTxt(NULL), _vm(vm) {
+ TS[0] = new Bitmap(w, FONT_HIG, TEXT_BG);
+ SetShapeList(TS);
+}
+
+
+void INFO_LINE::Update(const char *tx) {
+ if (tx != OldTxt) {
+ uint16 w = TS[0]->_w, h = TS[0]->_h;
+ uint8 *v = (uint8 *) TS[0]->_v;
+ uint16 dsiz = w >> 2; // data size (1 plane line size)
+ uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap
+ uint16 psiz = h * lsiz; // - last gape, but + plane trailer
+ uint16 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
+ *(uint16 *)(v + psiz - 2) = EOI; // plane trailer uint16
+ memcpy(v + psiz, v, 3 * psiz); // tricky replicate planes
+
+ // paint text line
+ if (tx) {
+ uint8 *p = v + 2, * q = p + size;
+
+ while (*tx) {
+ uint16 cw = _Font->Wid[*tx];
+ uint8 *fp = _Font->Map + _Font->Pos[*tx];
+
+ for (uint16 i = 0; i < cw; i++) {
+ register uint16 b = fp[i];
+ for (uint16 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;
+ }
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/talk.h b/engines/cge/talk.h
new file mode 100644
index 0000000000..60f7f213d4
--- /dev/null
+++ b/engines/cge/talk.h
@@ -0,0 +1,104 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __TALK__
+#define __TALK__
+
+#include "cge/vga13h.h"
+#include "cge/general.h"
+#include "cge/jbw.h"
+
+namespace CGE {
+
+#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"
+
+
+
+#define MAXPATH 128
+
+class FONT {
+ char Path[MAXPATH];
+ void Load(void);
+public:
+// static uint8 Wid[256];
+// static uint16 Pos[256];
+// static uint8 Map[256*8];
+ uint8 *Wid;
+ uint16 *Pos;
+ uint8 *Map;
+ FONT(const char *name);
+ ~FONT(void);
+ uint16 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(uint16 w, uint16 h);
+public:
+ TALK(CGEEngine *vm, const char *tx, TBOX_STYLE mode = PURE);
+ TALK(CGEEngine *vm);
+ //~TALK (void);
+
+ static FONT *_Font;
+ static void init();
+ static void deinit();
+
+ virtual void Update(const char *tx);
+ virtual void Update(void) {}
+ void PutLine(int line, const char *text);
+private:
+ CGEEngine *_vm;
+};
+
+
+class INFO_LINE : public TALK {
+ const char *OldTxt;
+public:
+ INFO_LINE(CGEEngine *vm, uint16 wid);
+ void Update(const char *tx);
+private:
+ CGEEngine *_vm;
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/text.cpp b/engines/cge/text.cpp
new file mode 100644
index 0000000000..7b191b492b
--- /dev/null
+++ b/engines/cge/text.cpp
@@ -0,0 +1,259 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/general.h"
+#include "cge/text.h"
+#include "cge/talk.h"
+#include "cge/vol.h"
+#include "cge/bitmaps.h"
+#include "cge/game.h"
+#include "cge/snail.h"
+#include "cge/cge_main.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+namespace CGE {
+
+TEXT *Text;
+TALK *Talk = NULL;
+
+TEXT::TEXT(CGEEngine *vm, const char *fname, int size) : _vm(vm) {
+ Cache = new HAN[size];
+ MergeExt(FileName, fname, SAY_EXT);
+ if (!INI_FILE::Exist(FileName))
+ error("No talk (%s)\n", FileName);
+
+ for (Size = 0; Size < size; Size++) {
+ Cache[Size].Ref = 0;
+ Cache[Size].Txt = NULL;
+ }
+}
+
+
+TEXT::~TEXT() {
+ 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((uint8 *)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((uint8 *)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::getText(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 TEXT::Say(const char *txt, Sprite *spr) {
+ KillText();
+ Talk = new TALK(_vm, txt, ROUND);
+ if (Talk) {
+ bool east = spr->_flags._east;
+ int x = (east) ? (spr->_x + spr->_w - 2) : (spr->_x + 2);
+ int y = spr->_y + 2;
+ Sprite *spike = new Sprite(_vm, SP);
+ uint16 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->getText(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->getText(SAY_NAME));
+ spike->Step(east);
+ spike->_ref = SAY_REF;
+
+ Vga->ShowQ->Insert(Talk, Vga->ShowQ->Last());
+ Vga->ShowQ->Insert(spike, Vga->ShowQ->Last());
+ }
+}
+
+void CGEEngine::Inf(const char *txt) {
+ KillText();
+ Talk = new TALK(this, txt, RECT);
+ if (Talk) {
+ Talk->_flags._kill = true;
+ Talk->_flags._bDel = true;
+ Talk->SetName(Text->getText(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);
+ */
+ warning("STUB: SayTime");
+}
+
+void KillText(void) {
+ if (Talk) {
+ SNPOST_(SNKILL, -1, 0, Talk);
+ Talk = NULL;
+ }
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/text.h b/engines/cge/text.h
new file mode 100644
index 0000000000..874a640ad0
--- /dev/null
+++ b/engines/cge/text.h
@@ -0,0 +1,86 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __TEXT__
+#define __TEXT__
+
+#include "cge/talk.h"
+#include "cge/jbw.h"
+
+namespace CGE {
+
+#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(CGEEngine *vm, const char *fname, int size);
+ ~TEXT(void);
+ void Clear(int from = 1, int upto = 0x7FFF);
+ void Preload(int from = 1, int upto = 0x7FFF);
+ char *getText(int ref);
+ void Say(const char *txt, Sprite *spr);
+private:
+ CGEEngine *_vm;
+};
+
+
+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);
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp
new file mode 100644
index 0000000000..673d6036d8
--- /dev/null
+++ b/engines/cge/vga13h.cpp
@@ -0,0 +1,1391 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "common/rect.h"
+#include "graphics/palette.h"
+#include "cge/general.h"
+#include "cge/vga13h.h"
+#include "cge/bitmap.h"
+#include "cge/vol.h"
+#include "cge/text.h"
+#include "cge/cge_main.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include "cge/cge.h"
+
+namespace CGE {
+
+#define FADE_STEP 2
+#define TMR_DIV ((0x8000/TMR_RATE)*2)
+#define NREP 9
+#define FREP 24
+
+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, 0x00, 0x00, 0x00 }
+};
+
+bool SpeedTest = false;
+Seq _seq1[] = { { 0, 0, 0, 0, 0 } };
+Seq _seq2[] = { { 0, 1, 0, 0, 0 }, { 1, 0, 0, 0, 0 } };
+
+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() {
+ static uint16 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
+}
+*/
+
+
+uint16 *SaveScreen(void) {
+ /*
+ uint16 cxy, cur, siz, * scr = NULL, * 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(uint16, siz+3); // +3 extra uint16s for size and cursor
+ if (sav)
+ {
+ sav[0] = siz;
+ sav[1] = cur;
+ sav[2] = cxy;
+ memcpy(sav+3, scr, siz * 2);
+ }
+ return sav;
+ */
+ warning("STUB: SaveScreen");
+ return 0;
+}
+
+
+void RestoreScreen(uint16 * &sav) {
+ /*
+ uint16 * 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
+
+ memcpy(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
+
+ free(sav);
+ sav = NULL;
+ */
+ warning("STUB: RestoreScreen");
+}
+
+
+DAC MkDAC(uint8 r, uint8 g, uint8 b) {
+ static DAC x;
+ x.R = r;
+ x.G = g;
+ x.B = b;
+ return x;
+}
+
+
+Rgb MkRGB(uint8 r, uint8 g, uint8 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);
+}
+
+
+Heart::Heart(void)
+ : ENGINE(TMR_DIV) {
+ _enable = false;
+ _xTimer = NULL;
+}
+
+
+/*
+extern "C" void TimerProc() {
+ static SPRITE * spr;
+ static uint8 run = 0;
+
+ // decrement external timer uint16
+ if (_heart->_xTimer) {
+ if (*_heart->_xTimer)
+ *_heart->_xTimer--;
+ else
+ _heart->_xTimer = NULL;
+ }
+
+ if (!run && _heart->_enable) { // check overrun flag
+ static uint16 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 ENGINE::NewTimer(...) {
+ /*
+ static SPRITE *spr;
+ static uint8 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 uint16
+ if (_heart->XTimer) {
+ if (*_heart->XTimer)
+ *_heart->XTimer--;
+ else
+ _heart->XTimer = NULL;
+ }
+
+ if (! run && _heart->Enable) { // check overrun flag
+ static uint16 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--;
+ }
+
+ */
+ warning("STUB: ENGINE::NewTimer");
+}
+
+
+void Heart::setXTimer(uint16 *ptr) {
+ if (_xTimer && ptr != _xTimer)
+ *_xTimer = 0;
+ _xTimer = ptr;
+}
+
+
+void Heart::setXTimer(uint16 *ptr, uint16 time) {
+ setXTimer(ptr);
+ *ptr = time;
+}
+
+
+Sprite::Sprite(CGEEngine *vm, 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), _vm(vm) {
+ memset(File, 0, sizeof(File));
+ *((uint16 *)&_flags) = 0;
+ SetShapeList(shp);
+}
+
+
+Sprite::~Sprite() {
+ Contract();
+}
+
+
+BMP_PTR Sprite::Shp() {
+ register SprExt *e = _ext;
+ if (e)
+ if (e->_seq) {
+ int i = e->_seq[_seqPtr].Now;
+ 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);
+ error("Invalid PHASE in SPRITE::Shp() %s", File);
+ }
+ 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(uint8 *buf) {
+ BMP_PTR *p;
+ for (p = _ext->_shpList; *p; p++) {
+ buf += (*p)->MoveVmap(buf);
+ }
+}
+
+
+bool 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;
+}
+
+
+bool 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
+ error("No core [%s]", n);
+ }
+ }
+}
+
+
+Sprite *Sprite::Expand(void) {
+ if (!_ext) {
+ bool enbl = _heart->_enable;
+ _heart->_enable = false;
+ if ((_ext = new SprExt) == NULL)
+ error("No core");
+ if (*File) {
+ static const 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;
+
+ 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 (! (sprf.Error==0))
+ error("Bad SPR [%s]", fname);
+ int len = 0, lcnt = 0;
+ while ((len = sprf.Read((uint8 *)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)
+ error("No core [%s]", 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)
+ error("No core [%s]", fname);
+ else {
+ SNAIL::COM *c = &nea[neacnt++];
+ if ((c->Com = (SNCOM) TakeEnum(SNAIL::ComTxt, strtok(NULL, " \t,;/"))) < 0)
+ error("%s [%s]", (const char*)NumStr("Bad NEAR in ######", lcnt), (const char*)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)
+ error("No core [%s]", fname);
+ else {
+ SNAIL::COM *c = &tak[takcnt++];
+ if ((c->Com = (SNCOM) TakeEnum(SNAIL::ComTxt, strtok(NULL, " \t,;/"))) < 0)
+ error("%s [%s]", NumStr("Bad NEAR in ######", lcnt), (const char *)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)
+ error("Bad PHASE in SEQ [%s]", fname);
+ if (maxnxt >= seqcnt)
+ error("Bad JUMP in SEQ [%s]", fname);
+ SetSeq(seq);
+ } else
+ SetSeq((_shpCnt == 1) ? _seq1 : _seq2);
+ //disable(); // disable interupt
+
+ SetShapeList(shplist);
+ //enable(); // enable interupt
+ 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(bool 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(uint8 *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;
+ uint8 *m = (*_ext->_shpList)->_m;
+
+ switch (MemType(m)) {
+ case NEAR_MEM :
+ delete[](uint8 *) m;
+ break;
+ case FAR_MEM :
+ free(m);
+ break;
+ default:
+ warning("Unhandled MemType in Sprite::KillXlat()");
+ 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 (_x < 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(uint16 pg) {
+ Graphics::Surface *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, (uint8 *)NULL);
+ if (bmp == NULL)
+ error("No core");
+ bmp->_w = e->_b1->_w;
+ bmp->_h = e->_b1->_h;
+ if ((bmp->_b = farnew(HideDesc, bmp->_h)) == NULL)
+ error("No Core");
+ bmp->_v = (uint8 *) memcpy(bmp->_b, e->_b1->_b, sizeof(HideDesc) * bmp->_h);
+ // TODO offset correctly in the surface using y1 pitch and x1 and not via offset segment
+ //bmp->_m = (uint8 *) MK_FP(e->y1, e->x1);
+ warning("FIXME: SPRITE::Ghost");
+ 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(bool 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;
+}
+
+
+//extern const char Copr[];
+Graphics::Surface *VGA::Page[4];
+DAC *VGA::SysPal;
+
+void VGA::init() {
+ for (int idx = 0; idx < 4; ++idx) {
+ Page[idx] = new Graphics::Surface();
+ Page[idx]->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
+ }
+
+ SysPal = new DAC[PAL_CNT];
+}
+
+void VGA::deinit() {
+ for (int idx = 0; idx < 4; ++idx)
+ delete Page[idx];
+
+ delete[] SysPal;
+}
+
+VGA::VGA(int mode)
+ : FrmCnt(0), OldMode(0), OldScreen(NULL), StatAdr(VGAST1_),
+ Msg(NULL), Nam(NULL), SetPal(false), Mono(0) {
+ OldColors = NULL;
+ NewColors = NULL;
+ ShowQ = new QUEUE(true);
+ SpareQ = new QUEUE(false);
+
+ bool std = true;
+ int i;
+ for (i = 10; i < 20; i++) {
+ char *txt = Text->getText(i);
+ if (txt) {
+ warning("%s", txt);
+ std = false;
+ }
+ }
+ if (std)
+// warning(Copr);
+ warning("TODO: Fix 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(0);
+ }
+}
+
+
+VGA::~VGA(void) {
+ Mono = 0;
+ if (IsVga()) {
+ Common::String buffer = "";
+ Clear(0);
+ SetMode(OldMode);
+ SetColors();
+ RestoreScreen(OldScreen);
+ Sunrise(OldColors);
+ if (OldColors)
+ free(OldColors);
+ if (NewColors)
+ free(NewColors);
+ if (Msg)
+ buffer = Common::String(Msg);
+ if (Nam)
+ buffer = buffer + " [" + Nam + "]";
+
+ warning("%s", buffer.c_str());
+ }
+}
+
+
+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;
+ */
+ warning("STUB: VGA::SetStatADR");
+}
+
+
+#pragma argsused
+void VGA::WaitVR(bool on) {
+ // Since some of the game parts rely on using vertical sync as a delay mechanism,
+ // we're introducing a short delay to simulate it
+ g_system->delayMillis(10);
+}
+
+
+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:
+ */
+ warning("STUB: VGA::Setup");
+}
+
+
+int VGA::SetMode(int mode) {
+ // ScummVM provides it's own vieo services
+ return 0;
+}
+
+
+void VGA::GetColors(DAC *tab) {
+ byte palData[PAL_SIZ];
+ g_system->getPaletteManager()->grabPalette(palData, 0, PAL_CNT);
+ pal2DAC(palData, tab);
+}
+
+void VGA::pal2DAC(const byte *palData, DAC *tab) {
+ const byte *colP = palData;
+ for (int idx = 0; idx < PAL_CNT; ++idx, colP += 3) {
+ tab[idx].R = *colP;
+ tab[idx].G = *(colP + 1);
+ tab[idx].B = *(colP + 2);
+ }
+}
+
+void VGA::DAC2pal(const DAC *tab, byte *palData) {
+ for (int idx = 0; idx < PAL_CNT; ++idx, palData += 3) {
+ *palData = tab[idx].R << 2;
+ *(palData + 1) = tab[idx].G << 2;
+ *(palData + 2) = tab[idx].B << 2;
+ }
+}
+
+void VGA::SetColors(DAC *tab, int lum) {
+ DAC *palP = tab;
+ for (int idx = 0; idx < PAL_CNT; ++idx, ++palP) {
+ palP->R = (palP->R * lum) >> 6;
+ palP->G = (palP->G * lum) >> 6;
+ palP->B = (palP->B * lum) >> 6;
+ }
+
+ if (Mono) {
+ palP = tab;
+ for (int idx = 0; idx < PAL_CNT; ++idx, ++palP) {
+ // Form a greyscalce colour from 30% R, 59% G, 11% B
+ uint8 intensity = (palP->R * 77) + (palP->G * 151) + (palP->B * 28);
+ palP->R = intensity;
+ palP->G = intensity;
+ palP->B = intensity;
+ }
+ }
+
+ SetPal = true;
+}
+
+
+void VGA::SetColors(void) {
+ memset(NewColors, 0, PAL_SIZ);
+ UpdateColors();
+}
+
+
+void VGA::Sunrise(DAC *tab) {
+ for (int i = 0; i <= 64; i += FADE_STEP) {
+ SetColors(tab, i);
+ WaitVR(true);
+ UpdateColors();
+ }
+}
+
+
+void VGA::Sunset(void) {
+ DAC tab[256];
+ GetColors(tab);
+ for (int i = 64; i >= 0; i -= FADE_STEP) {
+ SetColors(tab, i);
+ WaitVR(true);
+ 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) {
+ byte palData[PAL_SIZ];
+ DAC2pal(NewColors, palData);
+ g_system->getPaletteManager()->setPalette(palData, 0, 256);
+}
+
+
+void VGA::Update(void) {
+ SWAP(VGA::Page[0], VGA::Page[1]);
+
+ if (SetPal) {
+ UpdateColors();
+ SetPal = false;
+ }
+
+ g_system->copyRectToScreen((const byte *)VGA::Page[0]->getBasePtr(0, 0), SCR_WID, 0, 0, SCR_WID, SCR_HIG);
+ g_system->updateScreen();
+}
+
+
+void VGA::Clear(uint8 color) {
+ for (int paneNum = 0; paneNum < 4; ++paneNum)
+ Page[paneNum]->fillRect(Common::Rect(0, 0, SCR_WID, SCR_HIG), color);
+}
+
+
+void VGA::CopyPage(uint16 d, uint16 s) {
+ Page[d]->copyFrom(*Page[s]);
+}
+
+//--------------------------------------------------------------------------
+
+void Bitmap::XShow(int x, int y) {
+ /*
+ uint8 rmsk = x % 4,
+ mask = 1 << rmsk,
+ *scr = VGA::Page[1] + y * (SCR_WID / 4) + x / 4;
+ uint8 *m = (char *) M;
+ uint8 *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
+ */
+ warning("STUB: BITMAP::XShow");
+}
+
+
+void Bitmap::Show(int x, int y) {
+ const byte *srcP = (const byte *)_v;
+ byte *destEndP = (byte *)VGA::Page[1]->pixels + (SCR_WID * SCR_HIG);
+
+ // Loop through processing data for each plane. The game originally ran in plane mapped mode, where a
+ // given plane holds each fourth pixel sequentially. So to handle an entire picture, each plane's data
+ // must be decompressed and inserted into the surface
+ for (int planeCtr = 0; planeCtr < 4; ++planeCtr) {
+ byte *destP = (byte *)VGA::Page[1]->getBasePtr(x + planeCtr, y);
+
+ for (;;) {
+ uint16 v = READ_LE_UINT16(srcP);
+ srcP += 2;
+ int cmd = v >> 14;
+ int count = v & 0x3FFF;
+
+ if (cmd == 0) {
+ // End of image
+ break;
+ }
+
+ assert(destP < destEndP);
+
+ // Handle a set of pixels
+ while (count-- > 0) {
+ // Transfer operation
+ switch (cmd) {
+ case 1:
+ // SKIP
+ break;
+ case 2:
+ // REPEAT
+ *destP = *srcP;
+ break;
+ case 3:
+ // COPY
+ *destP = *srcP++;
+ break;
+ }
+
+ // Move to next dest position
+ destP += 4;
+ }
+
+ if (cmd == 2)
+ ++srcP;
+ }
+ }
+/*
+ DEBUG code to display image immediately
+ // Temporary
+ g_system->copyRectToScreen((const byte *)VGA::Page[1]->getBasePtr(0, 0), SCR_WID, 0, 0, SCR_WID, SCR_HIG);
+ byte palData[PAL_SIZ];
+ VGA::DAC2pal(VGA::SysPal, palData);
+ g_system->getPaletteManager()->setPalette(palData, 0, PAL_CNT);
+
+ g_system->updateScreen();
+ g_system->delayMillis(5000);
+*/
+}
+
+
+void Bitmap::Hide(int x, int y) {
+ /*
+ uint8 *scr = VGA::Page[1] + y * (SCR_WID / 4) + x / 4;
+ uint16 d = FP_OFF(VGA::Page[2]) - FP_OFF(VGA::Page[1]);
+ HideDesc *b = B;
+ uint16 extra = ((x & 3) != 0);
+ uint16 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
+ */
+ warning("STUB: Bitmap::Hide");
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/vga13h.h b/engines/cge/vga13h.h
new file mode 100644
index 0000000000..0c75dd6ba9
--- /dev/null
+++ b/engines/cge/vga13h.h
@@ -0,0 +1,346 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __VGA13H__
+#define __VGA13H__
+
+#include "graphics/surface.h"
+#include "cge/general.h"
+#include <stddef.h>
+#include "cge/bitmap.h"
+#include "cge/snail.h"
+#include "cge/cge.h"
+
+namespace CGE {
+
+#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 ((uint8)-1)
+
+#define SPR_EXT ".SPR"
+
+#define IsFile(s) (access(s, 0) == 0)
+#define IsWrit(s) (access(s, 2) == 0)
+
+
+
+struct Rgb {
+ uint16 r : 2;
+ uint16 R : 6;
+ uint16 g : 2;
+ uint16 G : 6;
+ uint16 b : 2;
+ uint16 B : 6;
+};
+
+typedef union {
+ DAC dac;
+ Rgb rgb;
+} TRGB;
+
+struct VgaRegBlk {
+ uint8 idx;
+ uint8 adr;
+ uint8 clr;
+ uint8 set;
+};
+
+struct Seq {
+ uint8 Now;
+ uint8 Next;
+ int8 Dx;
+ int8 Dy;
+ int Dly;
+};
+
+extern Seq _seq1[];
+extern Seq _seq2[];
+//extern SEQ * Compass[];
+//extern SEQ TurnToS[];
+
+#define PAL_CNT 256
+#define PAL_SIZ (PAL_CNT * 3)
+#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 class ENGINE;
+public:
+ Heart();
+
+ bool _enable;
+ uint16 *_xTimer;
+
+ void setXTimer(uint16 *ptr);
+ void setXTimer(uint16 *ptr, uint16 time);
+};
+
+
+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() :
+ _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 {
+ uint16 _hide : 1; // general visibility switch
+ uint16 _near : 1; // Near action lock
+ uint16 _drag : 1; // sprite is moveable
+ uint16 _hold : 1; // sprite is held with mouse
+ uint16 _____ : 1; // intrrupt driven animation
+ uint16 _slav : 1; // slave object
+ uint16 _syst : 1; // system object
+ uint16 _kill : 1; // dispose memory after remove
+ uint16 _xlat : 1; // 2nd way display: xlat table
+ uint16 _port : 1; // portable
+ uint16 _kept : 1; // kept in pocket
+ uint16 _east : 1; // talk to east (in opposite to west)
+ uint16 _shad : 1; // shadow
+ uint16 _back : 1; // 'send to background' request
+ uint16 _bDel : 1; // delete bitmaps in ~SPRITE
+ uint16 _tran : 1; // transparent (untouchable)
+ } _flags;
+ int _x;
+ int _y;
+ signed char _z;
+ uint16 _w;
+ uint16 _h;
+ uint16 _time;
+ uint8 NearPtr, TakePtr;
+ int _seqPtr;
+ int _shpCnt;
+ char File[MAXFILE];
+ Sprite *_prev;
+ Sprite *_next;
+ bool Works(Sprite *spr);
+ bool SeqTest(int n);
+ inline bool Active(void) {
+ return _ext != NULL;
+ }
+ Sprite(CGEEngine *vm, BMP_PTR *shp);
+ virtual ~Sprite(void);
+ BMP_PTR Shp(void);
+ BMP_PTR *SetShapeList(BMP_PTR *shp);
+ void MoveShapes(uint8 *buf);
+ Sprite *Expand(void);
+ Sprite *Contract(void);
+ Sprite *BackShow(bool 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(uint16 pg);
+ void MakeXlat(uint8 *x);
+ void KillXlat(void);
+ void Step(int nr = -1);
+ Seq *SetSeq(Seq *seq);
+ SNAIL::COM *SnList(SNLIST type);
+ virtual void Touch(uint16 mask, int x, int y);
+ virtual void Tick(void);
+private:
+ CGEEngine *_vm;
+};
+
+
+class QUEUE {
+ Sprite *Head, * Tail;
+public:
+ bool Show;
+ QUEUE(bool show);
+ ~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 {
+ uint16 OldMode;
+ uint16 *OldScreen;
+ uint16 StatAdr;
+ bool SetPal;
+ DAC *OldColors, *NewColors;
+ const char *Msg;
+ const char *Nam;
+
+ int SetMode(int mode);
+ void UpdateColors(void);
+ void SetColors(void);
+ void SetStatAdr(void);
+ void WaitVR(bool on);
+public:
+ uint32 FrmCnt;
+ QUEUE *ShowQ, *SpareQ;
+ int Mono;
+ static Graphics::Surface *Page[4];
+ static DAC *SysPal;
+
+ VGA(int mode);
+ ~VGA(void);
+ static void init();
+ static void deinit();
+
+ void Setup(VgaRegBlk *vrb);
+ void GetColors(DAC *tab);
+ void SetColors(DAC *tab, int lum);
+ void Clear(uint8 color);
+ void CopyPage(uint16 d, uint16 s);
+ void Sunrise(DAC *tab);
+ void Sunset(void);
+ void Show(void);
+ void Update(void);
+
+ static void pal2DAC(const byte *palData, DAC *tab);
+ static void DAC2pal(const DAC *tab, byte *palData);
+};
+
+
+DAC MkDAC(uint8 r, uint8 g, uint8 b);
+Rgb MkRGB(uint8 r, uint8 g, uint8 b);
+
+
+template <class CBLK>
+uint8 Closest(CBLK *pal, CBLK x) {
+#define f(col, lum) ((((uint16)(col)) << 8) / lum)
+ uint16 i, dif = 0xFFFF, found = 0;
+ uint16 L = x.R + x.G + x.B;
+ if (!L)
+ ++L;
+ uint16 R = f(x.R, L), G = f(x.G, L), B = f(x.B, L);
+ for (i = 0; i < 256; i++) {
+ uint16 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);
+ uint16 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);
+//static void Video (void);
+uint16 *SaveScreen(void);
+void RestoreScreen(uint16 * &sav);
+Sprite *SpriteAt(int x, int y);
+Sprite *Locate(int ref);
+
+extern bool SpeedTest;
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/vmenu.cpp b/engines/cge/vmenu.cpp
new file mode 100644
index 0000000000..ed07a1269f
--- /dev/null
+++ b/engines/cge/vmenu.cpp
@@ -0,0 +1,156 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/vmenu.h"
+#include "cge/mouse.h"
+#include "cge/cge_main.h"
+#include <string.h>
+
+namespace CGE {
+
+
+#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(CGEEngine *vm, uint16 w) : TALK(vm), _vm(vm) {
+ int h = FONT_HIG + 2 * MB_VM, i = (w += 2 * MB_HM) * h;
+ uint8 *p = farnew(uint8, i), * p1, * p2;
+
+ memset(p + w, TRANS, i - 2 * w);
+ memset(p, MB_LT, w);
+ memset(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 char[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(CGEEngine *vm, CHOICE *list, int x, int y)
+ : TALK(vm, VMGather(list), RECT), Menu(list), Bar(NULL), _vm(vm) {
+ 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(_vm, _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(uint16 mask, int x, int y) {
+ uint16 h = FONT_HIG + TEXT_LS;
+ bool ok = false;
+
+ if (Items) {
+ Sprite::Touch(mask, x, y);
+
+ y -= TEXT_VM - 1;
+ int n = 0;
+ 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();
+ warning("Missing call to proc()");
+ }
+ }
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/vmenu.h b/engines/cge/vmenu.h
new file mode 100644
index 0000000000..3c38576a40
--- /dev/null
+++ b/engines/cge/vmenu.h
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __VMENU__
+#define __VMENU__
+
+#include "cge/talk.h"
+
+namespace CGE {
+
+#define MB_VM 1
+#define MB_HM 3
+
+
+typedef struct {
+ const char *Text;
+ void (CGEEngine::*Proc)();
+} CHOICE;
+
+
+class MENU_BAR : public TALK {
+public:
+ MENU_BAR(CGEEngine *vm, uint16 w);
+private:
+ CGEEngine *_vm;
+};
+
+
+class VMENU : public TALK {
+ uint16 Items;
+ CHOICE *Menu;
+public:
+ static VMENU *Addr;
+ static int Recent;
+ MENU_BAR *Bar;
+ VMENU(CGEEngine *vm, CHOICE *list, int x, int y);
+ ~VMENU();
+ void Touch(uint16 mask, int x, int y);
+private:
+ CGEEngine *_vm;
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/vol.cpp b/engines/cge/vol.cpp
new file mode 100644
index 0000000000..c76914c003
--- /dev/null
+++ b/engines/cge/vol.cpp
@@ -0,0 +1,111 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge/vol.h"
+#include "common/system.h"
+#include "common/str.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+namespace CGE {
+
+DAT *VFILE::_Dat = NULL;
+BTFILE *VFILE::_Cat = NULL;
+VFILE *VFILE::_Recent = NULL;
+
+/*-----------------------------------------------------------------------*/
+
+DAT::DAT():
+#ifdef VOL_UPD
+ _File(DAT_NAME, UPD, CRP)
+#else
+ _File(DAT_NAME, REA, CRP)
+#endif
+{
+}
+
+/*-----------------------------------------------------------------------*/
+
+void VFILE::init() {
+ _Dat = new DAT();
+#ifdef VOL_UPD
+ _Cat = new BTFILE(CAT_NAME, UPD, CRP);
+#else
+ _Cat = new BTFILE(CAT_NAME, REA, CRP);
+#endif
+
+ _Recent = NULL;
+}
+
+void VFILE::deinit() {
+ delete _Dat;
+ delete _Cat;
+}
+
+VFILE::VFILE(const char *name, IOMODE mode)
+ : IOBUF(mode) {
+ if (mode == REA) {
+ if (_Dat->_File.Error || _Cat->Error)
+ error("Bad volume data");
+ BT_KEYPACK *kp = _Cat->Find(name);
+ if (scumm_stricmp(kp->Key, name) != 0)
+ Error = 1;
+ EndMark = (BufMark = BegMark = kp->Mark) + kp->Size;
+ }
+#ifdef VOL_UPD
+ else
+ Make(name);
+#endif
+}
+
+
+VFILE::~VFILE(void) {
+ if (_Recent == this)
+ _Recent = NULL;
+}
+
+
+bool VFILE::Exist(const char *name) {
+ return scumm_stricmp(_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, (uint16) n);
+ Ptr = 0;
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/vol.h b/engines/cge/vol.h
new file mode 100644
index 0000000000..a910aa7209
--- /dev/null
+++ b/engines/cge/vol.h
@@ -0,0 +1,98 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __VOL__
+#define __VOL__
+
+#include "cge/btfile.h"
+#include "cge/cfile.h"
+
+namespace CGE {
+
+#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 class VFILE;
+ VOLBASE _File;
+public:
+ DAT();
+
+ bool Append(uint8 *buf, uint16 len);
+ bool Write(CFILE &f);
+ bool Read(long org, uint16 len, uint8 *buf);
+};
+
+
+class VFILE : public IOBUF {
+private:
+ 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 void init();
+ static void deinit();
+
+ static bool 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);
+ }
+};
+
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/wav.h b/engines/cge/wav.h
new file mode 100644
index 0000000000..304c2827d8
--- /dev/null
+++ b/engines/cge/wav.h
@@ -0,0 +1,152 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Soltys source code
+ * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef __WAV__
+#define __WAV__
+
+#include "cge/general.h"
+#include <string.h>
+
+namespace CGE {
+
+#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 uint32 CKSIZE; // 32-bit unsigned size
+
+
+class CKID { // Chunk type identifier
+ union {
+ FOURCC Tx;
+ uint32 Id;
+ };
+protected:
+ static XFILE *ckFile;
+public:
+ CKID(FOURCC t) {
+ memcpy(Tx, t, sizeof(Tx));
+ }
+ CKID(uint32 d) {
+ Id = d;
+ }
+ CKID(XFILE *xf) {
+ (ckFile = xf)->Read(Tx, sizeof(Tx));
+ }
+ bool operator !=(CKID &X) {
+ return Id != X.Id;
+ }
+ bool 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 {
+ uint16 wFormatTag; // Format category
+ uint16 wChannels; // Number of channels
+ uint32 dwSamplesPerSec; // Sampling rate
+ uint32 dwAvgBytesPerSec; // For buffer estimation
+ uint16 wBlockAlign; // Data block size
+ } Wav;
+
+ union {
+ struct {
+ uint16 wBitsPerSample; // Sample size
+ } Pcm;
+ };
+public:
+ FMTCK(CKHEA &hea);
+ inline uint16 Channels(void) {
+ return Wav.wChannels;
+ }
+ inline uint32 SmplRate(void) {
+ return Wav.dwSamplesPerSec;
+ }
+ inline uint32 ByteRate(void) {
+ return Wav.dwAvgBytesPerSec;
+ }
+ inline uint16 BlckSize(void) {
+ return Wav.wBlockAlign;
+ }
+ inline uint16 SmplSize(void) {
+ return Pcm.wBitsPerSample;
+ }
+};
+
+
+class DATACK : public CKHEA {
+ bool e;
+ union {
+ uint8 *Buf;
+ EMS *EBuf;
+ };
+public:
+ DATACK(CKHEA &hea);
+ DATACK(CKHEA &hea, EMM *emm);
+ DATACK(int first, int last);
+ ~DATACK(void);
+ inline uint8 *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);
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/engines.mk b/engines/engines.mk
index dc09fbd54e..07364a5bd3 100644
--- a/engines/engines.mk
+++ b/engines/engines.mk
@@ -26,6 +26,11 @@ DEFINES += -DENABLE_AGOS2
endif
endif
+ifdef ENABLE_CGE
+DEFINES += -DENABLE_CGE=$(ENABLE_CGE)
+MODULES += engines/cge
+endif
+
ifdef ENABLE_CINE
DEFINES += -DENABLE_CINE=$(ENABLE_CINE)
MODULES += engines/cine