aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base/plugins.cpp3
-rwxr-xr-xconfigure1
-rw-r--r--engines/cge/bitmap.cpp504
-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/btfile.cpp150
-rw-r--r--engines/cge/btfile.h95
-rw-r--r--engines/cge/cfile.cpp260
-rw-r--r--engines/cge/cfile.h80
-rw-r--r--engines/cge/cge.cpp257
-rw-r--r--engines/cge/cge.h212
-rw-r--r--engines/cge/cge_main.cpp1844
-rw-r--r--engines/cge/cge_main.h194
-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/events.cpp321
-rw-r--r--engines/cge/events.h131
-rw-r--r--engines/cge/game.cpp91
-rw-r--r--engines/cge/game.h62
-rw-r--r--engines/cge/general.cpp393
-rw-r--r--engines/cge/general.h241
-rw-r--r--engines/cge/gettext.cpp119
-rw-r--r--engines/cge/gettext.h61
-rw-r--r--engines/cge/jbw.h132
-rw-r--r--engines/cge/mixer.cpp144
-rw-r--r--engines/cge/mixer.h61
-rw-r--r--engines/cge/module.mk38
-rw-r--r--engines/cge/snail.cpp1091
-rw-r--r--engines/cge/snail.h110
-rw-r--r--engines/cge/snddrv.h130
-rw-r--r--engines/cge/sound.cpp227
-rw-r--r--engines/cge/sound.h80
-rw-r--r--engines/cge/startup.cpp199
-rw-r--r--engines/cge/startup.h79
-rw-r--r--engines/cge/talk.cpp336
-rw-r--r--engines/cge/talk.h104
-rw-r--r--engines/cge/text.cpp256
-rw-r--r--engines/cge/text.h84
-rw-r--r--engines/cge/vga13h.cpp1363
-rw-r--r--engines/cge/vga13h.h352
-rw-r--r--engines/cge/vmenu.cpp155
-rw-r--r--engines/cge/vmenu.h69
-rw-r--r--engines/cge/vol.cpp122
-rw-r--r--engines/cge/vol.h92
-rw-r--r--engines/cge/wav.h148
-rw-r--r--engines/engines.mk5
51 files changed, 11625 insertions, 0 deletions
diff --git a/base/plugins.cpp b/base/plugins.cpp
index 4413995b88..7dbbf9843d 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 78998f8100..fbcd2147c6 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..4630f87456
--- /dev/null
+++ b/engines/cge/bitmap.cpp
@@ -0,0 +1,504 @@
+/* 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) && (!loadVBM(&file)))
+ error("Bad VBM [%s]", fname);
+ } else
+#endif
+ {
+#if (BMP_MODE)
+ ForceExt(pat, fname, ".BMP");
+ PIC_FILE file(pat);
+ if (file._error == 0) {
+ if (loadBMP(&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
+
+ // Replicate lines
+ byte *destP;
+ for (destP = v + lsiz; destP < (v + psiz); destP += lsiz)
+ Common::copy(v, v + lsiz, destP);
+
+ *(uint16 *)(v + psiz - 2) = EOI; // plane trailer uint16
+
+ // Repliccate planes
+ for (destP = v + psiz; destP < (v + 4 * psiz); destP += psiz)
+ Common::copy(v, v + psiz, destP);
+
+ HideDesc *b = (HideDesc *)(v + 4 * psiz);
+ b->skip = (SCR_WID - _w) >> 2;
+ b->hide = _w >> 2;
+
+ // Replicate across the entire table
+ for (HideDesc *hdP = b + 1; hdP < (b + _h); ++hdP)
+ *hdP = *b;
+
+ 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() {
+ 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() {
+ 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 = static_cast<uint16>(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::saveVBM(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::loadVBM(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) {
+ // Read in the palette
+ byte palData[PAL_SIZ];
+ f->read(palData, PAL_SIZ);
+
+ const byte *srcP = palData;
+ for (int idx = 0; idx < PAL_CNT; ++idx, srcP += 3) {
+ _pal[idx]._r = *srcP;
+ _pal[idx]._g = *(srcP + 1);
+ _pal[idx]._b = *(srcP + 2);
+ }
+ } 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::loadBMP(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];
+ 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..4c2b67b8df
--- /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 __CGE_BITMAP__
+#define __CGE_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 loadBMP(XFile *f);
+ bool loadVBM(XFile *f);
+public:
+ static Dac *_pal;
+ uint16 _w;
+ uint16 _h;
+ uint8 *_m;
+ uint8 *_v;
+ HideDesc *_b;
+
+ Bitmap(const char *fname, bool rem);
+ Bitmap(uint16 w, uint16 h, uint8 *map);
+ Bitmap(uint16 w, uint16 h, uint8 fill);
+ Bitmap(const Bitmap &bmp);
+ ~Bitmap();
+
+ static void init();
+ static void deinit();
+ Bitmap *flipH();
+ 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 saveVBM(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..8569932134
--- /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 __CGE_BITMAPS__
+#define __CGE_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/btfile.cpp b/engines/cge/btfile.cpp
new file mode 100644
index 0000000000..eda18ebaaf
--- /dev/null
+++ b/engines/cge/btfile.cpp
@@ -0,0 +1,150 @@
+/* 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"
+
+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 BtPage;
+ _buff[i]._pgNo = BT_NONE;
+ _buff[i]._indx = -1;
+ _buff[i]._updt = false;
+ if (_buff[i]._page == NULL)
+ error("No core");
+ }
+}
+
+
+BtFile::~BtFile() {
+ for (int i = 0; i < BT_LEVELS; i++) {
+ putPage(i, false);
+ delete _buff[i]._page;
+ }
+}
+
+
+void BtFile::putPage(int lev, bool hard) {
+ if (hard || _buff[lev]._updt) {
+ seek(_buff[lev]._pgNo * sizeof(BtPage));
+ write((uint8 *) _buff[lev]._page, sizeof(BtPage));
+ _buff[lev]._updt = false;
+ }
+}
+
+
+BtPage *BtFile::getPage(int lev, uint16 pgn) {
+ if (_buff[lev]._pgNo != pgn) {
+ int32 pos = pgn * sizeof(BtPage);
+ putPage(lev, false);
+ _buff[lev]._pgNo = pgn;
+ if (size() > pos) {
+ seek((uint32) pgn * sizeof(BtPage));
+ read((uint8 *) _buff[lev]._page, sizeof(BtPage));
+ _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;
+}
+
+BtKeypack *BtFile::find(const char *key) {
+ int lev = 0;
+ uint16 nxt = BT_ROOT;
+ while (!_error) {
+ BtPage *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(BtKeypack *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;
+ BtPage *Root = getPage(0, n++);
+ BtPage *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..1ac093d897
--- /dev/null
+++ b/engines/cge/btfile.h
@@ -0,0 +1,95 @@
+/* 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_BTFILE__
+#define __CGE_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 BtKeypack {
+ char _key[BT_KEYLEN];
+ uint32 _mark;
+ uint16 _size;
+};
+
+struct Inner {
+ uint8 _key[BT_KEYLEN];
+ uint16 _down;
+};
+
+struct Hea {
+ uint16 _count;
+ uint16 _down;
+};
+
+struct BtPage {
+ Hea _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
+ BtKeypack _lea[(BT_SIZE - sizeof(Hea)) / sizeof(BtKeypack)];
+ };
+};
+
+#include "common/pack-end.h" // END STRUCT PACKING
+
+
+class BtFile : public IoHand {
+ struct {
+ BtPage *_page;
+ uint16 _pgNo;
+ int _indx;
+ bool _updt;
+ } _buff[BT_LEVELS];
+
+ void putPage(int lev, bool hard);
+ BtPage *getPage(int lev, uint16 pgn);
+public:
+ BtFile(const char *name, IOMODE mode, CRYPT *crpt);
+ virtual ~BtFile();
+ BtKeypack *find(const char *key);
+ BtKeypack *next();
+ void make(BtKeypack *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..b235d552b2
--- /dev/null
+++ b/engines/cge/cfile.cpp
@@ -0,0 +1,260 @@
+/* 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 "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() {
+ if (_mode > REA)
+ writeBuff();
+ if (_buff)
+ free(_buff);
+}
+
+
+void IoBuf::readBuff() {
+ _bufMark = IoHand::mark();
+ _lim = IoHand::read(_buff, IOBUF_SIZE);
+ _ptr = 0;
+}
+
+
+void IoBuf::writeBuff() {
+ 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() {
+ 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 CFile::flush() {
+ if (_mode > REA)
+ writeBuff();
+ else
+ _lim = 0;
+
+ /*
+ _BX = Handle;
+ _AH = 0x68; // Flush buffer
+ asm int 0x21
+ */
+ warning("FIXME: CFILE::Flush");
+}
+
+
+long CFile::mark() {
+ 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..bf90633dd0
--- /dev/null
+++ b/engines/cge/cfile.h
@@ -0,0 +1,80 @@
+/* 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_CFILE__
+#define __CGE_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;
+ uint16 _lim;
+ long _bufMark;
+ uint16 _seed;
+ CRYPT *_crypt;
+ virtual void readBuff();
+ virtual void writeBuff();
+public:
+ IoBuf(IOMODE mode, CRYPT *crpt = NULL);
+ IoBuf(const char *name, IOMODE mode, CRYPT *crpt = NULL);
+ virtual ~IoBuf();
+ uint16 read(void *buf, uint16 len);
+ uint16 read(uint8 *buf);
+ int read();
+ 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 flush();
+ long mark();
+ 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..b953f2f5b0
--- /dev/null
+++ b/engines/cge/cge.cpp
@@ -0,0 +1,257 @@
+/* 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), _randomSource("cge") {
+
+ // Debug/console setup
+ DebugMan.addDebugChannel(kCGEDebug, "general", "CGE general debug channel");
+
+ _isDemo = _gameDescription->flags & ADGF_DEMO;
+ _startupMode = 1;
+ _demoText = DEMO_TEXT;
+ _oldLev = 0;
+ _jbw = false;
+ _pocPtr = 0;
+
+}
+
+void CGEEngine::setup() {
+ // Initialise fields
+ _lastFrame = 0;
+ _hero = NULL;
+
+ // Create debugger console
+ _console = new CGEConsole(this);
+
+ // Initialise classes that have static members
+ Vga::init();
+ VFile::init();
+ Bitmap::init();
+ Talk::init();
+
+ // Initialise sprite arrays used by game objects
+ MB[0] = new Bitmap("BRICK", true);
+ MB[1] = NULL;
+ HL[0] = new Bitmap("HLINE", true);
+ HL[1] = NULL;
+ MC[0] = new Bitmap("MOUSE", true);
+ MC[1] = new Bitmap("DUMMY", true);
+ MC[2] = NULL;
+ PR[0] = new Bitmap("PRESS", true);
+ PR[1] = NULL;
+ SP[0] = new Bitmap("SPK_L", true);
+ SP[1] = new Bitmap("SPK_R", true);
+ SP[2] = NULL;
+ LI[0] = new Bitmap("LITE0", true);
+ LI[1] = new Bitmap("LITE1", true);
+ LI[2] = new Bitmap("LITE2", true);
+ LI[3] = new Bitmap("LITE3", true);
+ LI[4] = NULL;
+
+ // Initialise engine objects
+ _text = new Text(this, progName(), 128);
+ _vga = new Vga(M13H);
+ _heart = new Heart;
+ _sys = new System(this);
+ _pocLight = new Sprite(this, LI);
+ 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 InfoLine(this, INFO_W);
+ _cavLight = new Sprite(this, PR);
+ _debugLine = new InfoLine(this, SCR_WID);
+ _snail = new Snail(this, false);
+ _snail_ = new Snail(this, true);
+
+ _mouse = new MOUSE(this);
+ _keyboard = new Keyboard();
+ _eventManager = new EventManager();
+ _offUseCount = atoi(_text->getText(OFF_USE_COUNT));
+ _music = true;
+
+ for (int i = 0; i < POCKET_NX; i++)
+ _pocref[i] = -1;
+ _volume[0] = 0;
+ _volume[1] = 0;
+
+ _savTab[0]._ptr = &_now;
+ _savTab[0]._len = sizeof(_now);
+ _savTab[0]._flag = true;
+ _savTab[1]._ptr = &_oldLev;
+ _savTab[1]._len = sizeof(_oldLev);
+ _savTab[1]._flag = true;
+ _savTab[2]._ptr = &_demoText;
+ _savTab[2]._len = sizeof(_demoText);
+ _savTab[2]._flag = true;
+ _savTab[3]._ptr = &_game;
+ _savTab[3]._len = sizeof(_game);
+ _savTab[3]._flag = true;
+ _savTab[4]._ptr = &_game;
+ _savTab[4]._len = sizeof(_game);
+ _savTab[4]._flag = true;
+ _savTab[5]._ptr = &_game;
+ _savTab[5]._len = sizeof(_game);
+ _savTab[5]._flag = true;
+ _savTab[6]._ptr = &_game;
+ _savTab[6]._len = sizeof(_game);
+ _savTab[6]._flag = true;
+ _savTab[7]._ptr = &_game;
+ _savTab[7]._len = sizeof(_game);
+ _savTab[7]._flag = true;
+ _savTab[8]._ptr = &_vga->_mono;
+ _savTab[8]._len = sizeof(_vga->_mono);
+ _savTab[8]._flag = false;
+ _savTab[9]._ptr = &_music;
+ _savTab[9]._len = sizeof(_music);
+ _savTab[9]._flag = true;
+ _savTab[10]._ptr = _volume;
+ _savTab[10]._len = sizeof(_volume);
+ _savTab[10]._flag = true;
+ _savTab[11]._ptr = _flag;
+ _savTab[11]._len = sizeof(_flag);
+ _savTab[11]._flag = true;
+ _savTab[12]._ptr = _heroXY;
+// _savTab[12]._len = sizeof(_heroXY); FIXME: illegal sizeof
+ _savTab[12]._len = 0;
+ _savTab[12]._flag = true;
+ _savTab[13]._ptr = _barriers;
+// _savTab[13]._len = sizeof(_barriers); FIXME: illegal sizeof
+ _savTab[13]._len = 0;
+ _savTab[13]._flag = true;
+ _savTab[14]._ptr = _pocref;
+ _savTab[14]._len = sizeof(_pocref);
+ _savTab[14]._flag = true;
+ _savTab[15]._ptr = NULL;
+ _savTab[15]._len = 0;
+ _savTab[15]._flag = false;
+
+ if (_isDemo) {
+ _maxCaveArr[0] = CAVE_MAX;
+ _maxCaveArr[1] = -1;
+ _maxCaveArr[2] = -1;
+ _maxCaveArr[3] = -1;
+ _maxCaveArr[4] = -1;
+ } else {
+ _maxCaveArr[0] = 1;
+ _maxCaveArr[1] = 8;
+ _maxCaveArr[2] = 16;
+ _maxCaveArr[3] = 23;
+ _maxCaveArr[4] = 24;
+ };
+ _maxCave = 0;
+ _dark = false;
+ _game = false;
+ _now = 1;
+ _lev = -1;
+
+ for (int i = 0; i < 4; i++)
+ _flag[i] = false;
+
+}
+
+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();
+
+ delete _console;
+
+ // Delete engine objects
+ 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 _text;
+ delete _heart;
+ delete _pocLight;
+ delete _keyboard;
+ delete _mouse;
+ for (int i = 0; i < POCKET_NX; i++)
+ delete _pocket[i];
+ delete _snail;
+ delete _snail_;
+ delete _hero;
+ delete _vga;
+ delete _sys;
+}
+
+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..4f6b452850
--- /dev/null
+++ b/engines/cge/cge.h
@@ -0,0 +1,212 @@
+/* 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"
+#include "cge/bitmap.h"
+
+#define CGE_SAVEGAME_VERSION 1
+
+namespace CGE {
+
+class Console;
+class Sprite;
+
+// our engine debug channels
+enum {
+ kCGEDebug = 1 << 0
+};
+
+enum SNLIST { NEAR, TAKE };
+
+#define POCKET_NX 8
+
+struct SavTab {
+ void *_ptr;
+ int32 _len;
+ bool _flag;
+};
+
+class CGEEngine : public Engine {
+private:
+ uint32 _lastFrame;
+ void tick();
+public:
+ CGEEngine(OSystem *syst, const ADGameDescription *gameDescription);
+ ~CGEEngine();
+
+ const ADGameDescription *_gameDescription;
+ bool _isDemo;
+ int _startupMode;
+ int _demoText;
+ int _oldLev;
+ bool _jbw;
+ int _pocPtr;
+ SavTab _savTab[16];
+ bool _music;
+ int _pocref[POCKET_NX];
+ uint8 _volume[2];
+ int _maxCaveArr[5];
+
+ int _maxCave;
+ bool _flag[4];
+ bool _dark;
+ bool _game;
+ int _now;
+ int _lev;
+
+ Common::RandomSource _randomSource;
+
+ 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 dummy() {}
+ void NONE();
+ void SB();
+ void caveDown();
+ void caveUp();
+ void xCave();
+ void qGame();
+ void SBM();
+ void GUS();
+ void GUSM();
+ void MIDI();
+ void AUTO();
+ void setPortD();
+ void setPortM();
+ void setIRQ();
+ void setDMA();
+ void mainLoop();
+ void saveGame(XFile &file);
+ void switchMusic();
+ void selectPocket(int n);
+ void expandSprite(Sprite *spr);
+ void contractSprite(Sprite *spr);
+ int findPocket(Sprite *spr);
+ void feedSnail(Sprite *spr, SNLIST snq);
+ void pocFul();
+ void hide1(Sprite *spr);
+ void loadMapping();
+ void saveMapping();
+ void saveSound();
+ void heroCover(int cvr);
+ void trouble(int seq, int txt);
+ void offUse();
+ void tooFar();
+ void noWay();
+ void loadHeroXY();
+ void keyClick();
+ void switchColorMode();
+ void killSprite();
+ void pushSprite();
+ void pullSprite();
+ void sayDebug();
+ void nextStep();
+ void switchDebug();
+
+ void snBackPt(Sprite *spr, int stp);
+ void snBarrier(int cav, int bar, bool horz);
+ void snCover(Sprite *spr, int xref);
+ void snFlag(int fn, bool v);
+ void snFlash(bool on);
+ void snGame(Sprite *spr, int num);
+ void snGhost(Bitmap *bmp);
+ void snGive(Sprite *spr, int stp);
+ void snHide(Sprite *spr, int val);
+ void snKeep(Sprite *spr, int stp);
+ void snKill(Sprite *spr);
+ void snLevel(Sprite *spr, int lev);
+ void snLight(bool in);
+ void snMouse(bool on);
+ void snNNext(Sprite *sprel, int p);
+ void snPort(Sprite *spr, int port);
+ void snReach(Sprite *spr, int mode);
+ void snRelZ(Sprite *spr, int z);
+ void snRNNext(Sprite *sprel, int p);
+ void snRTNext(Sprite *sprel, int p);
+ void snSelect();
+ void snSend(Sprite *spr, int val);
+ void snRelX(Sprite *spr, int x);
+ void snRelY(Sprite *spr, int y);
+ void snRmNear(Sprite *spr);
+ void snRmTake(Sprite *spr);
+ void snRSeq(Sprite *spr, int val);
+ void snSeq(Sprite *spr, int val);
+ void snSetRef(Sprite *spr, int nr);
+ void snSetX(Sprite *spr, int x);
+ void snSetX0(int cav, int x0);
+ void snSetXY(Sprite *spr, uint16 xy);
+ void snSetY(Sprite *spr, int y);
+ void snSetY0(int cav, int y0);
+ void snSetZ(Sprite *spr, int z);
+ void snSlave(Sprite *spr, int ref);
+ void snSound(Sprite *spr, int wav, int cnt);
+ void snSwap(Sprite *spr, int xref);
+ void snTNext(Sprite *sprel, int p);
+ void snTrans(Sprite *spr, int trans);
+ void snUncover(Sprite *spr, Sprite *xspr);
+ void snWalk(Sprite *spr, int x, int y);
+ void snZTrim(Sprite *spr);
+
+private:
+ CGEConsole *_console;
+ void setup();
+};
+
+// Example console class
+class Console : public GUI::Debugger {
+public:
+ Console(CGEEngine *vm) {}
+ virtual ~Console() {}
+};
+
+} // 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..e7ca76a98f
--- /dev/null
+++ b/engines/cge/cge_main.cpp
@@ -0,0 +1,1844 @@
+/* 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 "common/memstream.h"
+#include "common/serializer.h"
+#include "cge/general.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/events.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 "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
+
+uint16 _stklen = (STACK_SIZ * 2);
+
+Vga *_vga;
+Heart *_heart;
+WALK *_hero;
+System *_sys;
+Sprite *_pocLight;
+EventManager *_eventManager;
+Keyboard *_keyboard;
+MOUSE *_mouse;
+Sprite *_pocket[POCKET_NX];
+Sprite *_sprite;
+Sprite *_miniCave;
+Sprite *_shadow;
+Sprite *_horzLine;
+InfoLine *_infoLine;
+Sprite *_cavLight;
+InfoLine *_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
+
+static char _usrFnam[15] = "\0ɱ%^þúȼ´ ÇÉ";
+
+//--------------------------------------------------------------------------
+
+static Ems *_mini = _miniEmm.alloc((uint16)MINI_EMM_SIZE);
+static BMP_PTR *_miniShpList = NULL;
+static BMP_PTR _miniShp[] = { NULL, NULL };
+static bool _finis = false;
+int _offUseCount;
+uint16 *_intStackPtr = false;
+
+Hxy _heroXY[CAVE_MAX] = {{0, 0}};
+Bar _barriers[1 + CAVE_MAX] = { { 0xFF, 0xFF } };
+
+extern Dac _stdPal[58];
+
+uint8 Cluster::_map[MAP_ZCNT][MAP_XCNT];
+
+
+uint8 &Cluster::cell() {
+ return _map[_b][_a];
+}
+
+
+bool Cluster::Protected() {
+/*
+ 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);
+}
+
+void CGEEngine::loadGame(XFile &file, bool tiny = false) {
+ SavTab *st;
+ Sprite *spr;
+ int i;
+
+ // Read the data into a data buffer
+ int size = file.size() - file.mark();
+ byte *dataBuffer = new byte[size];
+ file.read(dataBuffer, size);
+ Common::MemoryReadStream readStream(dataBuffer, size, DisposeAfterUse::YES);
+ Common::Serializer s(&readStream, NULL);
+
+ // Synchronise header data
+ s.syncAsUint16LE(_now);
+ s.syncAsUint16LE(_oldLev);
+ s.syncAsUint16LE(_demoText);
+ for (i = 0; i < 5; ++i)
+ s.syncAsUint16LE(_game);
+ s.syncAsSint16LE(i); // unused VGA::Mono variable
+ s.syncAsUint16LE(_music);
+ s.syncBytes(_volume, 2);
+ for (i = 0; i < 4; ++i)
+ s.syncAsUint16LE(_flag[i]);
+
+ for (i = 0; i < CAVE_MAX; ++i) {
+ s.syncAsSint16LE(_heroXY[i]._x);
+ s.syncAsUint16LE(_heroXY[i]._y);
+ }
+ for (i = 0; i < 1 + CAVE_MAX; ++i) {
+ s.syncAsByte(_barriers[i]._horz);
+ s.syncAsByte(_barriers[i]._vert);
+ }
+ for (i = 0; i < POCKET_NX; ++i)
+ s.syncAsUint16LE(_pocref[i]);
+
+ uint16 checksum;
+ s.syncAsUint16LE(checksum);
+ if (checksum != 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 (readStream.pos() < readStream.size()) {
+ Sprite S(this, NULL);
+ S.sync(s);
+
+ 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);
+ }
+ }
+}
+
+
+void CGEEngine::saveSound() {
+ CFile cfg(usrPath(progName(CFG_EXT)), WRI);
+ if (!cfg._error)
+ cfg.write(&_sndDrvInfo, sizeof(_sndDrvInfo) - sizeof(_sndDrvInfo.Vol2));
+}
+
+
+void CGEEngine::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));
+}
+
+void CGEEngine::heroCover(int cvr) {
+ SNPOST(SNCOVER, 1, cvr, NULL);
+}
+
+void CGEEngine::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);
+}
+
+void CGEEngine::offUse() {
+ trouble(OFF_USE, OFF_USE_TEXT + new_random(_offUseCount));
+}
+
+void CGEEngine::tooFar() {
+ trouble(TOO_FAR, TOO_FAR_TEXT);
+}
+
+// Used in stubbed function, do not remove!
+void CGEEngine::noWay() {
+ trouble(NO_WAY, NO_WAY_TEXT);
+}
+
+
+void CGEEngine::loadHeroXY() {
+ INI_FILE cf(progName(".HXY"));
+ memset(_heroXY, 0, sizeof(_heroXY));
+ if (!cf._error)
+ cf.CFREAD(&_heroXY);
+}
+
+void CGEEngine::loadMapping() {
+ 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() {
+ 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) {
+ _vm->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() {
+ 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: WALK::findWay");
+ /*
+ bool Find1Way();
+ 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);
+ virtual 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->gotoxy(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();
+//static void switchDebug();
+//static void pullSprite();
+//static void NextStep();
+
+void CGEEngine::keyClick() {
+ 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() {
+ 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() {
+ 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() {
+ 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();
+ }
+}
+
+
+void CGEEngine::caveUp() {
+ 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->gotoxy(_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 (!_startupMode)
+ _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->gotoxy(CAVE_X + ((_now - 1) % CAVE_NX) * CAVE_DX + CAVE_SX,
+ CAVE_Y + ((_now - 1) / CAVE_NX) * CAVE_DY + CAVE_SY);
+ killText();
+ if (!_startupMode)
+ 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;
+ _vm->keyClick();
+ killText();
+ if (_vm->_startupMode == 1) {
+ SNPOST(SNCLEAR, -1, 0, NULL);
+ return;
+ }
+ pp0 = pp;
+ switch (x) {
+ case Del:
+ if (_keyboard->_key[ALT] && _keyboard->_key[CTRL])
+ AltCtrlDel();
+ else
+ _vm->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:
+ _vm->pushSprite();
+ break;
+ case PgDn:
+ _vm->pullSprite();
+ break;
+ case '+':
+ _vm->nextStep();
+ break;
+ case '`':
+ if (_keyboard->_key[ALT])
+ _vm->saveMapping();
+ else
+ _vm->switchMapping();
+ break;
+ case F1:
+ _vm->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)
+ _vm->_jbw = !_vm->_jbw;
+ break;
+ }
+ if (pp == pp0)
+ pp = 0;
+ } else {
+ if (_vm->_startupMode)
+ 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 && !_vm->_game) {
+ cav = ((y - CAVE_Y) / CAVE_DY) * CAVE_NX + (x - CAVE_X) / CAVE_DX + 1;
+ if (cav > _vm->_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;
+ _vm->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 && !_vm->_game) {
+ _hero->findWay(XZ(x, y));
+ }
+ }
+ }
+ }
+}
+
+
+void System::tick() {
+ if (!_vm->_startupMode)
+ if (--_funDel == 0) {
+ killText();
+ if (_snail->idle()) {
+ if (PAIN)
+ _vm->heroCover(9);
+ else if (Startup::_core >= CORE_MID) {
+ int n = new_random(100);
+ if (n > 96)
+ _vm->heroCover(6 + (_hero->_x + _hero->_w / 2 < SCR_WID / 2));
+ else {
+ if (n > 90)
+ _vm->heroCover(5);
+ else {
+ if (n > 60)
+ _vm->heroCover(4);
+ else
+ _vm->heroCover(3);
+ }
+ }
+ }
+ }
+ funTouch();
+ }
+ _time = SYSTIMERATE;
+}
+
+
+/*
+static void SpkOpen() {
+ asm in al,0x61
+ asm or al,0x03
+ asm out 0x61,al
+ asm mov al,0x90
+ asm out 0x43,al
+}
+
+
+static void SpkClose() {
+ asm in al,0x61
+ asm and al,0xFC
+ asm out 0x61,al
+}
+
+*/
+
+
+void CGEEngine::switchColorMode() {
+ SNPOST_(SNSEQ, 121, _vga->_mono = !_vga->_mono, NULL);
+ keyClick();
+ _vga->setColors(Vga::_sysPal, 64);
+}
+
+
+
+void CGEEngine::switchMusic() {
+ 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 (GetText::_ptr)
+ SNPOST_(SNKILL, -1, 0, GetText::_ptr);
+ else {
+ GetText *tn = new GetText(this, _text->getText(GETNAME_PROMPT), _usrFnam, 8);
+ if (tn) {
+ tn->setName(_text->getText(GETNAME_TITLE));
+ tn->center();
+ tn->gotoxy(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;
+}
+
+void CGEEngine::killSprite() {
+ _sprite->_flags._kill = true;
+ _sprite->_flags._bDel = true;
+ SNPOST_(SNKILL, -1, 0, _sprite);
+ _sprite = NULL;
+}
+
+void CGEEngine::pushSprite() {
+ 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);
+}
+
+void CGEEngine::pullSprite() {
+ 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);
+}
+
+void CGEEngine::nextStep() {
+ SNPOST_(SNSTEP, 0, 0, _sprite);
+}
+
+void CGEEngine::saveMapping() {
+ {
+ 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)
+
+void CGEEngine::sayDebug() {
+ 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);
+ }
+}
+
+
+void CGEEngine::switchDebug() {
+ _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 (_vm->_game) if (mask & L_UP) {
+ mask &= ~L_UP;
+ mask |= R_UP;
+ }
+ if ((mask & R_UP) && _snail->idle()) {
+ Sprite *ps = (_pocLight->_seqPtr) ? _pocket[_vm->_pocPtr] : NULL;
+ if (ps) {
+ if (_flags._kept || _hero->distance(this) < MAX_DISTANCE) {
+ if (works(ps)) {
+ _vm->feedSnail(ps, TAKE);
+ } else
+ _vm->offUse();
+ _vm->selectPocket(-1);
+ } else
+ _vm->tooFar();
+ } else {
+ if (_flags._kept)
+ mask |= L_UP;
+ else {
+ if (_hero->distance(this) < MAX_DISTANCE) {
+ ///
+ if (_flags._port) {
+ if (_vm->findPocket(NULL) < 0)
+ _vm->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)
+ _vm->offUse();
+ else
+ _vm->feedSnail(this, TAKE);
+ } else
+ _vm->offUse();
+ }
+ }///
+ else
+ _vm->tooFar();
+ }
+ }
+ }
+ if ((mask & L_UP) && _snail->idle()) {
+ if (_flags._kept) {
+ int n;
+ for (n = 0; n < POCKET_NX; n++) {
+ if (_pocket[n] == this) {
+ _vm->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("Bad line %d [%s]", lcnt, fname);
+
+
+ switch (i) {
+ case 0 : // Name - will be taken in Expand routine
+ break;
+ case 1 : // Type
+ if ((type = takeEnum(Type, strtok(NULL, " \t,;/"))) < 0)
+ error("Bad line %d [%s]", lcnt, fname);
+ break;
+ case 2 : // Phase
+ ++ shpcnt;
+ break;
+ case 3 : // East
+ east = (atoi(strtok(NULL, " \t,;/")) != 0);
+ break;
+ case 11 : // Portable
+ port = (atoi(strtok(NULL, " \t,;/")) != 0);
+ break;
+ case 12 : // Transparent
+ tran = (atoi(strtok(NULL, " \t,;/")) != 0);
+ break;
+ }
+ }
+ if (! shpcnt)
+ 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->gotoxy(col, row);
+ //Sprite->Time = 1;//-----------$$$$$$$$$$$$$$$$
+ }
+ break;
+ }
+ case 2 : { // WALK
+ WALK *w = new WALK(this, NULL);
+ if (w && ref == 1) {
+ w->gotoxy(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->gotoxy(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("Bad INI line %d [%s]", lcnt, fname);
+}
+
+#define GAME_FRAME_DELAY (1000 / 50)
+
+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();
+
+ // Game frame delay
+ uint32 millis = g_system->getMillis();
+ while (!_eventManager->_quitFlag && (millis < (_lastFrame + GAME_FRAME_DELAY))) {
+ // Handle any pending events
+ _eventManager->poll();
+
+ // Slight delay
+ g_system->delayMillis(10);
+ millis = g_system->getMillis();
+ }
+ _lastFrame = millis;
+
+ // Dispatch the tick to any active objects
+ tick();
+}
+
+void CGEEngine::tick() {
+ for (Sprite *spr = _vga->_showQ->first(); spr; spr = spr->_next) {
+ if (spr->_time) {
+ if (!spr->_flags._hide) {
+ if (--spr->_time == 0)
+ spr->tick();
+ }
+ }
+ }
+}
+
+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() {
+ if (_eventManager->_quitFlag)
+ return;
+
+ _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->gotoxy(_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->gotoxy(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);
+
+ _startupMode = 0;
+
+ SNPOST(SNLEVEL, -1, _oldLev, &_cavLight);
+ _cavLight->gotoxy(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 && !_eventManager->_quitFlag) {
+ //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) {
+ if (_eventManager->_quitFlag)
+ return;
+
+ 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() && !_eventManager->_quitFlag)
+ 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) {
+ if (_eventManager->_quitFlag)
+ return false;
+
+ Bitmap::_pal = Vga::_sysPal;
+ BMP_PTR LB[] = { new Bitmap(name, true), 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();
+ if (_eventManager->_quitFlag)
+ return false;
+ }
+
+ _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
+ // At this point the game originally read the boot sector to get
+ // the serial number for it's copy protection check
+#endif
+ //-----------------------------------------
+ movie("X00"); // paylist
+ _vga->copyPage(1, 2);
+ _vga->copyPage(0, 1);
+ _vga->_showQ->append(_mouse);
+ //Mouse.On();
+ _heart->_enable = true;
+ for (takeName(); GetText::_ptr;) {
+ mainLoop();
+ if (_eventManager->_quitFlag)
+ return false;
+ }
+ _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 (_flag[3]) { //flag FINIS
+ Startup::_mode++;
+ _flag[3] = 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 () {
+ CFILE f("!STACK.DMP", BFW);
+ f.Write((uint8 *) (intStackPtr-STACK_SIZ/2), STACK_SIZ*2);
+}
+*/
+
+
+void CGEEngine::cge_main() {
+ 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();
+ _startupMode = 2;
+ if (_flag[3]) // Flag FINIS
+ movie("X03");
+ } else
+ _vga->sunset();
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/cge_main.h b/engines/cge/cge_main.h
new file mode 100644
index 0000000000..3ef3679e8e
--- /dev/null
+++ b/engines/cge/cge_main.h
@@ -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
+ */
+
+#ifndef __CGE_CGE__
+#define __CGE_CGE__
+
+#include "cge/wav.h"
+#include "cge/vga13h.h"
+#include "cge/events.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 (_vm->_flag[0])
+//#define FINIS (_vm->_flag[3])
+
+
+class System : public Sprite {
+ int _lum;
+public:
+ int _funDel;
+
+ System(CGEEngine *vm);
+
+ void setPal();
+ void funTouch();
+ virtual 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();
+ Cluster() : Couple() { }
+ Cluster(int a, int b) : Couple(a, b) { }
+ bool Protected();
+};
+
+
+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 findWay(Cluster c);
+ void findWay(Sprite *spr);
+ int distance(Sprite *spr);
+ void turn(DIR d);
+ void park();
+ bool lower(Sprite *spr);
+ void reach(Sprite *spr, int mode = -1);
+private:
+ CGEEngine *_vm;
+
+};
+
+Cluster XZ(int x, int y);
+Cluster XZ(Couple xy);
+
+extern WALK *_hero;
+extern Vga *_vga;
+extern Heart *_heart;
+extern System *_sys;
+extern int _offUseCount;
+extern Sprite *_pocLight;
+extern Keyboard *_keyboard;
+extern MOUSE *_mouse;
+extern EventManager *_eventManager;
+extern Sprite *_pocket[];
+extern Sprite *_sprite;
+extern Sprite *_miniCave;
+extern Sprite *_shadow;
+extern Sprite *_horzLine;
+extern InfoLine *_infoLine;
+extern Sprite *_cavLight;
+extern InfoLine *_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..808d74ff9b
--- /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->gotoxy(_talk->_x, FONT_HIG / 2);
+ for (i = 0; i < (int)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() {
+ _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->gotoxy(_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..4a1e5927e5
--- /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 __CGE_CONFIG__
+#define __CGE_CONFIG__
+
+namespace CGE {
+
+void selectSound();
+
+} // 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..25a1a4fae3
--- /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();
+
+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..93342f77da
--- /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() {
+ /* 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() {
+ /*
+ 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() {
+ while (_list) {
+ Ems *e = _list;
+ _list = e->_next;
+ delete e;
+ }
+ _top = 0;
+}
+
+
+Ems::Ems() : _ptr(0), _size(0), _next(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() {
+ return _size;
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/events.cpp b/engines/cge/events.cpp
new file mode 100644
index 0000000000..e904b710ba
--- /dev/null
+++ b/engines/cge/events.cpp
@@ -0,0 +1,321 @@
+/* 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/events.h"
+#include "cge/events.h"
+#include "cge/events.h"
+#include "cge/text.h"
+#include "cge/cge_main.h"
+
+namespace CGE {
+
+CGEEvent Evt[EVT_MAX];
+
+uint16 EvtHead = 0, EvtTail = 0;
+
+/*----------------- KEYBOARD interface -----------------*/
+
+const 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
+};
+
+const uint16 Keyboard::_scummVmCodes[0x60] = {
+ 0, Common::KEYCODE_ESCAPE, Common::KEYCODE_1, Common::KEYCODE_2, Common::KEYCODE_3,
+ Common::KEYCODE_4, Common::KEYCODE_5, Common::KEYCODE_6, Common::KEYCODE_7, Common::KEYCODE_8,
+ Common::KEYCODE_9, Common::KEYCODE_0, Common::KEYCODE_MINUS, Common::KEYCODE_PLUS, Common::KEYCODE_BACKSPACE,
+ Common::KEYCODE_TAB, Common::KEYCODE_q, Common::KEYCODE_w, Common::KEYCODE_e, Common::KEYCODE_r,
+ Common::KEYCODE_t, Common::KEYCODE_y, Common::KEYCODE_u, Common::KEYCODE_i, Common::KEYCODE_o,
+ Common::KEYCODE_p, Common::KEYCODE_LEFTBRACKET, Common::KEYCODE_RIGHTBRACKET, Common::KEYCODE_RETURN, 0/*Ctrl*/,
+ Common::KEYCODE_a, Common::KEYCODE_s, Common::KEYCODE_d, Common::KEYCODE_f, Common::KEYCODE_g,
+ Common::KEYCODE_h, Common::KEYCODE_j, Common::KEYCODE_k, Common::KEYCODE_l, Common::KEYCODE_SEMICOLON,
+ Common::KEYCODE_BACKSLASH, Common::KEYCODE_TILDE, Common::KEYCODE_LSHIFT, Common::KEYCODE_BACKSLASH, Common::KEYCODE_z,
+ Common::KEYCODE_x, Common::KEYCODE_c, Common::KEYCODE_v, Common::KEYCODE_b, Common::KEYCODE_n,
+ Common::KEYCODE_m, Common::KEYCODE_COMMA, Common::KEYCODE_PERIOD, Common::KEYCODE_SLASH, Common::KEYCODE_RSHIFT,
+ Common::KEYCODE_KP_MULTIPLY, 0 /*Alt*/, Common::KEYCODE_SPACE, Common::KEYCODE_CAPSLOCK, Common::KEYCODE_F1,
+ Common::KEYCODE_F2, Common::KEYCODE_F3, Common::KEYCODE_F4, Common::KEYCODE_F5, Common::KEYCODE_F6,
+ Common::KEYCODE_F7, Common::KEYCODE_F8, Common::KEYCODE_F9, Common::KEYCODE_F10, Common::KEYCODE_NUMLOCK,
+ Common::KEYCODE_SCROLLOCK, Common::KEYCODE_KP7, Common::KEYCODE_KP8, Common::KEYCODE_KP9, Common::KEYCODE_KP_MINUS,
+ Common::KEYCODE_KP4, Common::KEYCODE_KP5, Common::KEYCODE_KP6, Common::KEYCODE_KP_PLUS, Common::KEYCODE_KP1,
+ Common::KEYCODE_KP2, Common::KEYCODE_KP3, Common::KEYCODE_KP0, Common::KEYCODE_KP_PERIOD, 0,
+ 0, 0, Common::KEYCODE_F11, Common::KEYCODE_F12, 0,
+ 0, 0, 0, 0, 0,
+ 0
+};
+
+Keyboard::Keyboard() {
+ _client = NULL;
+ Common::set_to(&_key[0], &_key[0x60], false);
+ _current = 0;
+}
+
+Keyboard::~Keyboard() {
+}
+
+Sprite *Keyboard::setClient(Sprite *spr) {
+ swap(_client, spr);
+ return spr;
+}
+
+bool Keyboard::getKey(uint16 keycode, int &cgeCode) {
+ if ((keycode == Common::KEYCODE_LCTRL) || (keycode == Common::KEYCODE_RCTRL)) {
+ cgeCode = 29;
+ return true;
+ }
+
+ // Scan through the ScummVM mapping list
+ for (int idx = 0; idx < 0x60; ++idx) {
+ if (_scummVmCodes[idx] == keycode) {
+ cgeCode = idx;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Keyboard::NewKeyboard(Common::Event &event) {
+ int keycode;
+ if (!getKey(event.kbd.keycode, keycode))
+ return;
+
+ if (event.type == Common::EVENT_KEYUP) {
+ // Key release
+ _key[event.kbd.keycode] = false;
+ } else if (event.type == Common::EVENT_KEYDOWN) {
+ // Key press
+ _key[keycode] = true;
+ _current = Keyboard::_code[keycode];
+
+ if (_client) {
+ CGEEvent &evt = Evt[EvtHead];
+ EvtHead = (EvtHead + 1) % EVT_MAX;
+ evt._x = _current; // Keycode
+ evt._msk = KEYB; // Event mask
+ evt._ptr = _client; // Sprite pointer
+ }
+ }
+}
+
+/*----------------- MOUSE interface -----------------*/
+
+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 }
+ };
+
+ Hold = NULL;
+ hx = 0; hy = 0;
+ Exist = true;
+ Buttons = 0;
+ Busy = NULL;
+ _active = false;
+
+ setSeq(ms);
+
+ gotoxy(SCR_WID/2, SCR_HIG/2);
+ _z = 127;
+ step(1);
+}
+
+
+MOUSE::~MOUSE() {
+ Off();
+}
+
+
+//void MOUSE::SetFun()
+//{
+//}
+
+
+void MOUSE::On() {
+ if (_seqPtr && Exist) {
+ _active = true;
+ step(0);
+ if (Busy) Busy->step(0);
+ }
+}
+
+
+void MOUSE::Off() {
+ if (_seqPtr == 0) {
+ if (Exist) {
+ _active = false;
+ }
+
+ step(1);
+ if (Busy) Busy->step(1);
+ }
+}
+
+void MOUSE::NewMouse(Common::Event &event) {
+ if (!_active)
+ return;
+
+ CGEEvent &evt = Evt[EvtHead];
+ EvtHead = (EvtHead + 1) % EVT_MAX;
+ evt._x = event.mouse.x;
+ evt._y = event.mouse.y;
+ evt._ptr = spriteAt(evt._x, evt._y);
+
+ switch (event.type) {
+ case Common::EVENT_MOUSEMOVE:
+ evt._msk = ROLL;
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ evt._msk = L_DN;
+ Buttons |= 1;
+ break;
+ case Common::EVENT_LBUTTONUP:
+ evt._msk = L_UP;
+ Buttons &= ~1;
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ evt._msk = R_DN;
+ Buttons |= 2;
+ break;
+ case Common::EVENT_RBUTTONUP:
+ evt._msk = R_UP;
+ Buttons &= ~2;
+ break;
+ default:
+ break;
+ }
+}
+
+/*----------------- EventManager interface -----------------*/
+
+EventManager::EventManager() {
+ _quitFlag = false;
+}
+
+void EventManager::poll() {
+ while (g_system->getEventManager()->pollEvent(_event)) {
+ switch (_event.type) {
+ case Common::EVENT_QUIT:
+ // Signal to quit
+ _quitFlag = true;
+ return;
+ case Common::EVENT_KEYDOWN:
+ case Common::EVENT_KEYUP:
+ // Handle keyboard events
+ _keyboard->NewKeyboard(_event);
+ handleEvents();
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONDOWN:
+ case Common::EVENT_RBUTTONUP:
+ // Handle mouse events
+ _mouse->NewMouse(_event);
+ handleEvents();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void EventManager::handleEvents() {
+ while (EvtTail != EvtHead) {
+ CGEEvent e = Evt[EvtTail];
+ if (e._msk) {
+ if (_mouse->Hold && e._ptr != _mouse->Hold)
+ _mouse->Hold->touch(e._msk | ATTN, e._x - _mouse->Hold->_x, e._y - _mouse->Hold->_y);
+
+ // update mouse cursor position
+ if (e._msk & ROLL)
+ _mouse->gotoxy(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) {
+ _mouse->Hold = e._ptr;
+ if (_mouse->Hold) {
+ _mouse->Hold->_flags._hold = true;
+ _mouse->hx = e._x - _mouse->Hold->_x;
+ _mouse->hy = e._y - _mouse->Hold->_y;
+ }
+ }
+
+ if (e._msk & L_UP) {
+ if (_mouse->Hold) {
+ _mouse->Hold->_flags._hold = false;
+ _mouse->Hold = NULL;
+ }
+ }
+ ///Touched = e.Ptr;
+
+ // discard Text if button released
+ if (e._msk & (L_UP | R_UP))
+ killText();
+ }
+ EvtTail = (EvtTail + 1) % EVT_MAX;
+ }
+ if (_mouse->Hold)
+ _mouse->Hold->gotoxy(_mouse->_x - _mouse->hx, _mouse->_y - _mouse->hy);
+}
+
+void EventManager::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;
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/events.h b/engines/cge/events.h
new file mode 100644
index 0000000000..cfb1023d6b
--- /dev/null
+++ b/engines/cge/events.h
@@ -0,0 +1,131 @@
+/* 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_CGE_EVENTS__
+#define __CGE_CGE_EVENTS__
+
+#include "common/events.h"
+#include "cge/game.h"
+#include "cge/talk.h"
+#include "cge/jbw.h"
+#include "cge/vga13h.h"
+
+namespace CGE {
+
+/*----------------- KEYBOARD interface -----------------*/
+
+#define KEYBD_INT 9
+#define LSHIFT 42
+#define RSHIFT 54
+#define CTRL 29
+#define ALT 56
+
+
+class Keyboard {
+private:
+ bool getKey(uint16 keycode, int &cgeCode);
+public:
+ static const uint16 _code[0x60];
+ static const uint16 _scummVmCodes[0x60];
+
+ uint16 _current;
+ Sprite *_client;
+ bool _key[0x60];
+
+ void NewKeyboard(Common::Event &event);
+ uint16 last() {
+ uint16 cur = _current;
+ _current = 0;
+ return cur;
+ }
+ Sprite *setClient(Sprite *spr);
+
+ Keyboard();
+ ~Keyboard();
+};
+
+/*----------------- MOUSE interface -----------------*/
+
+#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 CGEEvent {
+ uint16 _msk;
+ uint16 _x;
+ uint16 _y;
+ Sprite *_ptr;
+};
+
+extern CGEEvent Evt[EVT_MAX];
+extern uint16 EvtHead, EvtTail;
+
+
+class MOUSE : public Sprite {
+public:
+ Sprite *Hold;
+ bool _active;
+ int hx, hy;
+ bool Exist;
+ int Buttons;
+ Sprite *Busy;
+ //Sprite *Touched;
+ MOUSE(CGEEngine *vm, Bitmap **shpl = MC);
+ ~MOUSE();
+ void On();
+ void Off();
+ void Tick();
+ void NewMouse(Common::Event &event);
+private:
+ CGEEngine *_vm;
+};
+
+/*----------------- EventManager interface -----------------*/
+
+class EventManager {
+private:
+ Common::Event _event;
+ void handleEvents();
+public:
+ bool _quitFlag;
+
+ EventManager();
+ void poll();
+ static void ClrEvt(Sprite *spr = NULL);
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/game.cpp b/engines/cge/game.cpp
new file mode 100644
index 0000000000..f2ebc0b4f8
--- /dev/null
+++ b/engines/cge/game.cpp
@@ -0,0 +1,91 @@
+/* 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/events.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;
+}
+
+/* Useless?
+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, mkDax(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));
+ gotoxy(_l + new_random(_r - _l - _w), _t + new_random(_b - _t - _h));
+}
+
+
+void Fly::tick() {
+ 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;
+ gotoxy(_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..b26fc0d165
--- /dev/null
+++ b/engines/cge/game.h
@@ -0,0 +1,62 @@
+/* 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_GAME__
+#define __CGE_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;
+ static int _t;
+ static int _r;
+ static int _b;
+public:
+ int _tx, _ty;
+ Fly(CGEEngine *vm, Bitmap **shpl);
+ void tick();
+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..6ed6884aba
--- /dev/null
+++ b/engines/cge/general.cpp
@@ -0,0 +1,393 @@
+/* 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/cge.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;
+
+void _fqsort(void *base, uint16 nelem, uint16 width, int (*fcmp)(const void *, const void *)) {
+ warning("STUB: _fqsort");
+}
+
+const char *progName(const char *ext) {
+ static char buf[MAXFILE];
+ strcpy(buf, "CGE");
+ if (ext)
+ strcat(buf, ext);
+
+ return buf;
+}
+
+char *mergeExt(char *buf, const char *nam, const char *ext) {
+ strcpy(buf, nam);
+ char *dot = strrchr(buf, '.');
+ if (!dot)
+ strcat(buf, ext);
+
+ return buf;
+}
+
+char *forceExt(char *buf, const char *nam, const char *ext) {
+ strcpy(buf, nam);
+ char *dot = strrchr(buf, '.');
+ if (dot)
+ *dot = '\0';
+ strcat(buf, ext);
+
+ return buf;
+}
+
+static unsigned Seed = 0xA5;
+
+unsigned fastRand() {
+ 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() {
+ _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() {
+ return _file->pos();
+}
+
+long IoHand::seek(long pos) {
+ _file->seek(pos, SEEK_SET);
+ return _file->pos();
+}
+
+long IoHand::size() {
+ 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;
+}
+
+void sndInit() {
+ warning("STUB: SNDInit");
+}
+
+void sndDone() {
+ // FIXME: STUB: SNDDone
+}
+
+void sndSetVolume() {
+ warning("STUB: SNDSetVolume");
+}
+
+void sndDigiStart(SmpInfo *PSmpInfo) {
+ warning("STUB: SNDDigitStart");
+}
+
+void sndDigiStop(SmpInfo *PSmpInfo) {
+ warning("STUB: SNDDigiStop");
+}
+
+void sndMidiStart(uint8 *MIDFile) {
+ warning("STUB: SNDMIDIStart");
+}
+
+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;
+}
+
+long timer() {
+/*
+ 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) {
+ return ((CGEEngine *)g_engine)->_randomSource.getRandomNumber(range - 1);
+}
+
+#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_() {
+/*
+ // 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() {
+ 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..7cf3ec3e41
--- /dev/null
+++ b/engines/cge/general.h
@@ -0,0 +1,241 @@
+/* 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_GENERAL__
+#define __CGE_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"
+
+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 };
+
+struct Dac {
+ uint8 _r, _g, _b;
+};
+
+typedef uint16 CRYPT(void *buf, uint16 siz, uint16 seed);
+
+class Couple {
+protected:
+ signed char _a;
+ signed char _b;
+public:
+ Couple() { }
+ 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_();
+};
+
+
+class Ems;
+
+
+class Emm {
+ friend class Ems;
+ bool test();
+
+ long _top;
+ long _lim;
+ Ems *_list;
+ int _han;
+ static void *_frame;
+public:
+ Emm(long size = 0);
+ ~Emm();
+ Ems *alloc(uint16 siz);
+ void release();
+};
+
+
+class Ems {
+ friend class Emm;
+ Emm *_emm;
+ long _ptr;
+ uint16 _size;
+ Ems *_next;
+public:
+ Ems();
+ void *operator & () const;
+ uint16 size();
+};
+
+
+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() : _mode(REA), _error(0) { }
+ XFile(IOMODE mode) : _mode(mode), _error(0) { }
+ virtual ~XFile() { }
+ virtual uint16 read(void *buf, uint16 len) = 0;
+ virtual uint16 write(void *buf, uint16 len) = 0;
+ virtual long mark() = 0;
+ virtual long size() = 0;
+ virtual long seek(long pos) = 0;
+};
+
+
+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();
+ static bool exist(const char *name);
+ uint16 read(void *buf, uint16 len);
+ uint16 write(void *buf, uint16 len);
+ long mark();
+ long size();
+ long seek(long pos);
+ //timeb Time ();
+// 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();
+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();
+
+
+// MISSING FUNCTIONS
+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();
+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);
+long timer();
+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..2ee6dc42eb
--- /dev/null
+++ b/engines/cge/gettext.cpp
@@ -0,0 +1,119 @@
+/* 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/events.h"
+#include "cge/cge_main.h"
+
+namespace CGE {
+
+GetText *GetText::_ptr = NULL;
+
+
+GetText::GetText(CGEEngine *vm, const char *info, char *text, int size)
+ : Talk(vm), _text(text), _size(min<int>(size, GTMAX)), _len(min<int>(_size, strlen(text))),
+ _cntr(GTBLINK), _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();
+}
+
+
+GetText::~GetText() {
+ _keyboard->setClient(_oldKeybClient);
+ _ptr = NULL;
+}
+
+
+void GetText::tick() {
+ if (++_cntr >= GTBLINK) {
+ _buff[_len] ^= (' ' ^ '_');
+ _cntr = 0;
+ }
+ putLine(1, _buff);
+ _time = GTTIME;
+}
+
+
+void GetText::touch(uint16 mask, int x, int y) {
+ static char ogon[] = "•œ¥£˜ ¡";
+ static char bezo[] = "ACELNOSXZ";
+ char *p;
+
+ if (mask & KEYB) {
+ _vm->keyClick();
+ 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..188e90c776
--- /dev/null
+++ b/engines/cge/gettext.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 __CGE_GETTEXT__
+#define __CGE_GETTEXT__
+
+#include "cge/general.h"
+#include "cge/talk.h"
+
+namespace CGE {
+
+#define GTMAX 24
+#define GTBLINK 6
+#define GTTIME 6
+
+class GetText : public Talk {
+ char _buff[GTMAX + 2];
+ char *_text;
+ uint16 _size;
+ uint16 _len;
+ uint16 _cntr;
+ Sprite *_oldKeybClient;
+
+public:
+ static GetText *_ptr;
+ GetText(CGEEngine *vm, const char *info, char *text, int size);
+ ~GetText();
+ void touch(uint16 mask, int x, int y);
+ void tick();
+
+private:
+ CGEEngine *_vm;
+};
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/jbw.h b/engines/cge/jbw.h
new file mode 100644
index 0000000000..74084fb905
--- /dev/null
+++ b/engines/cge/jbw.h
@@ -0,0 +1,132 @@
+/* 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_JBW__
+#define __CGE_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)();
+
+#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)
+
+enum Keys {
+ 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
+};
+
+#define HGC_Cursor 0x0B0C
+#define CGA_Cursor 0x0607
+#define OFF_Cursor 0x2000
+
+//#define TimerCount (*((volatile long *) ((void _seg *) 0x40 + (void *) 0x6C)))
+//#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))
+
+
+extern uint16 _stklen;
+extern uint16 _heaplen;
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/mixer.cpp b/engines/cge/mixer.cpp
new file mode 100644
index 0000000000..d4a5212552
--- /dev/null
+++ b/engines/cge/mixer.cpp
@@ -0,0 +1,144 @@
+/* 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/events.h"
+#include "cge/snddrv.h"
+#include "cge/cge_main.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", true);
+ _mb[1] = NULL;
+ setShapeList(_mb);
+ setName(_text->getText(MIX_NAME));
+ _flags._syst = true;
+ _flags._kill = true;
+ _flags._bDel = true;
+ gotoxy(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, true);
+ _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->gotoxy(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() {
+ _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() {
+ 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() {
+ _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..8ded075514
--- /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 __CGE_MIXER__
+#define __CGE_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();
+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..d9dea6534d
--- /dev/null
+++ b/engines/cge/module.mk
@@ -0,0 +1,38 @@
+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 \
+ events.o \
+ game.o \
+ general.o \
+ gettext.o \
+ mixer.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/snail.cpp b/engines/cge/snail.cpp
new file mode 100644
index 0000000000..683568e1a8
--- /dev/null
+++ b/engines/cge/snail.cpp
@@ -0,0 +1,1091 @@
+/* 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/cge_main.h"
+#include "cge/events.h"
+
+namespace CGE {
+
+static void _enable() {
+ warning("STUB: _enable");
+}
+
+static void _disable() {
+ warning("STUB: _disable");
+}
+
+extern Sprite *_pocLight;
+
+//-------------------------------------------------------------------------
+// SPRITE * Pocket[POCKET_NX]={ NULL, NULL, NULL, NULL,
+// NULL, NULL, NULL, NULL, };
+// int _pocPtr = 0;
+//-------------------------------------------------------------------------
+extern Sprite *_pocket[];
+
+void CGEEngine::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 CGEEngine::expandSprite(Sprite *spr) {
+ if (spr)
+ _vga->_showQ->insert(_vga->_spareQ->remove(spr));
+}
+
+
+void CGEEngine::contractSprite(Sprite *spr) {
+ if (spr)
+ _vga->_spareQ->append(_vga->_showQ->remove(spr));
+}
+
+int CGEEngine::findPocket(Sprite *spr) {
+ for (int i = 0; i < POCKET_NX; i++)
+ if (_pocket[i] == spr)
+ return i;
+ return -1;
+}
+
+
+void CGEEngine::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->gotoxy(POCKET_X + _pocPtr * POCKET_DX + POCKET_SX, POCKET_Y + POCKET_SY);
+}
+
+void CGEEngine::pocFul() {
+ _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 CGEEngine::hide1(Sprite *spr) {
+ SNPOST_(SNGHOST, -1, 0, spr->ghost());
+}
+
+void CGEEngine::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 CGEEngine::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),
+ _timerExpiry(0), _talkEnable(true),
+ _head(0), _tail(0), _snList(farnew(Com, 256)), _vm(vm) {
+}
+
+Snail::~Snail() {
+ 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();
+ _timerExpiry = 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();
+ _timerExpiry = 0;
+ }
+ _enable();
+}
+
+void CGEEngine::snNNext(Sprite *sprel, int p) {
+ if (sprel)
+ if (sprel->_nearPtr != NO_PTR)
+ sprel->_nearPtr = p;
+}
+
+void CGEEngine::snTNext(Sprite *sprel, int p) {
+ if (sprel)
+ if (sprel->_takePtr != NO_PTR)
+ sprel->_takePtr = p;
+}
+
+void CGEEngine::snRNNext(Sprite *sprel, int p) {
+ if (sprel)
+ if (sprel->_nearPtr != NO_PTR)
+ sprel->_nearPtr += p;
+}
+
+
+void CGEEngine::snRTNext(Sprite *sprel, int p) {
+ if (sprel)
+ if (sprel->_takePtr != NO_PTR)
+ sprel->_takePtr += p;
+}
+
+void CGEEngine::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;
+ }
+}
+
+void CGEEngine::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;
+ }
+}
+
+void CGEEngine::snRmNear(Sprite *spr) {
+ if (spr)
+ spr->_nearPtr = NO_PTR;
+}
+
+void CGEEngine::snRmTake(Sprite *spr) {
+ if (spr)
+ spr->_takePtr = NO_PTR;
+}
+
+void CGEEngine::snSeq(Sprite *spr, int val) {
+ if (spr) {
+ if (spr == _hero && val == 0)
+ _hero->park();
+ else
+ spr->step(val);
+ }
+}
+
+void CGEEngine::snRSeq(Sprite *spr, int val) {
+ if (spr)
+ snSeq(spr, spr->_seqPtr + val);
+}
+
+void CGEEngine::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 CGEEngine::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 CGEEngine::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->gotoxy(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 CGEEngine::snUncover(Sprite *spr, Sprite *xspr) {
+ if (spr && xspr) {
+ spr->_flags._hide = false;
+ spr->_cave = xspr->_cave;
+ spr->gotoxy(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 CGEEngine::snSetX0(int cav, int x0) {
+ _heroXY[cav - 1]._x = x0;
+}
+
+void CGEEngine::snSetY0(int cav, int y0) {
+ _heroXY[cav - 1]._y = y0;
+}
+
+void CGEEngine::snSetXY(Sprite *spr, uint16 xy) {
+ if (spr)
+ spr->gotoxy(xy % SCR_WID, xy / SCR_WID);
+}
+
+void CGEEngine::snRelX(Sprite *spr, int x) {
+ if (spr && _hero)
+ spr->gotoxy(_hero->_x + x, spr->_y);
+}
+
+void CGEEngine::snRelY(Sprite *spr, int y) {
+ if (spr && _hero)
+ spr->gotoxy(spr->_x, _hero->_y + y);
+}
+
+
+void CGEEngine::snRelZ(Sprite *spr, int z) {
+ if (spr && _hero) {
+ spr->_z = _hero->_z + z;
+ snZTrim(spr);
+ }
+}
+
+
+void CGEEngine::snSetX(Sprite *spr, int x) {
+ if (spr)
+ spr->gotoxy(x, spr->_y);
+}
+
+
+void CGEEngine::snSetY(Sprite *spr, int y) {
+ if (spr)
+ spr->gotoxy(spr->_x, y);
+}
+
+
+void CGEEngine::snSetZ(Sprite *spr, int z) {
+ if (spr) {
+ spr->_z = z;
+ //SNPOST_(SNZTRIM, -1, 0, spr);
+ snZTrim(spr);
+ }
+}
+
+
+void CGEEngine::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 CGEEngine::snTrans(Sprite *spr, int trans) {
+ if (spr)
+ spr->_flags._tran = (trans < 0) ? !spr->_flags._tran : (trans != 0);
+}
+
+void CGEEngine::snPort(Sprite *spr, int port) {
+ if (spr)
+ spr->_flags._port = (port < 0) ? !spr->_flags._port : (port != 0);
+}
+
+void CGEEngine::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);
+ EventManager::ClrEvt(spr);
+ if (spr->_flags._kill)
+ delete spr;
+ else {
+ spr->_cave = -1;
+ _vga->_spareQ->append(spr);
+ }
+ if (nx) {
+ if (nx->_flags._slav)
+ snKill(nx);
+ }
+ }
+}
+
+
+void CGEEngine::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 CGEEngine::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->gotoxy(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 CGEEngine::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);
+}
+
+
+void CGEEngine::snBackPt(Sprite *spr, int stp) {
+ if (spr) {
+ if (stp >= 0)
+ spr->step(stp);
+ spr->backShow(true);
+ }
+}
+
+void CGEEngine::snLevel(Sprite *spr, int lev) {
+ while (_lev < lev) {
+ _lev++;
+ spr = _vga->_spareQ->locate(100 + _lev);
+ if (spr) {
+ spr->backShow(true);
+ spr->_cave = 0;
+ }
+ }
+ _maxCave = _maxCaveArr[_lev];
+ if (spr)
+ spr->_flags._hide = false;
+}
+
+
+void CGEEngine::snFlag(int fn, bool v) {
+ _flag[fn] = v;
+}
+
+void CGEEngine::snSetRef(Sprite *spr, int nr) {
+ if (spr)
+ spr->_ref = nr;
+}
+
+void CGEEngine::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;
+}
+
+
+void CGEEngine::snLight(bool in) {
+ if (in)
+ _vga->sunrise(Vga::_sysPal);
+ else
+ _vga->sunset();
+ _dark = ! in;
+}
+
+void CGEEngine::snBarrier(int cav, int bar, bool horz) {
+ ((uint8 *)(_barriers + ((cav > 0) ? cav : _now)))[horz] = bar;
+}
+
+void CGEEngine::snWalk(Sprite *spr, int x, int y) {
+ if (_hero) {
+ if (spr && y < 0)
+ _hero->findWay(spr);
+ else
+ _hero->findWay(XZ(x, y));
+ }
+}
+
+void CGEEngine::snReach(Sprite *spr, int mode) {
+ if (_hero)
+ _hero->reach(spr, mode);
+}
+
+void CGEEngine::snMouse(bool on) {
+ if (on)
+ _mouse->On();
+ else
+ _mouse->Off();
+}
+
+
+void Snail::runCom() {
+ 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 (_timerExpiry) {
+ // Delay in progress
+ if (_timerExpiry > g_system->getMillis())
+ // Delay not yet ended
+ break;
+
+ // Delay is finished
+ _timerExpiry = 0;
+ } 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 :
+ _timerExpiry = g_system->getMillis() + snc->_val * SNAIL_FRAME_DELAY;
+ if (_talk)
+ _textDelay = true;
+ break;
+ case SNWAIT :
+ if (sprel) {
+ if (sprel->seqTest(snc->_val) &&
+ (snc->_val >= 0 || sprel != _hero || _hero->_tracePtr < 0)) {
+ _timerExpiry = g_system->getMillis() + sprel->_time * SNAIL_FRAME_DELAY;
+ } else
+ goto xit;
+ }
+ break;
+ case SNLEVEL :
+ _vm->snLevel(sprel, snc->_val);
+ break;
+ case SNHIDE :
+ _vm->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 :
+ _vm->snKill(sprel);
+ break;
+ case SNSEQ :
+ _vm->snSeq(sprel, snc->_val);
+ break;
+ case SNRSEQ :
+ _vm->snRSeq(sprel, snc->_val);
+ break;
+ case SNSEND :
+ _vm->snSend(sprel, snc->_val);
+ break;
+ case SNSWAP :
+ _vm->snSwap(sprel, snc->_val);
+ break;
+ case SNCOVER :
+ _vm->snCover(sprel, snc->_val);
+ break;
+ case SNUNCOVER :
+ _vm->snUncover(sprel, (snc->_val >= 0) ? locate(snc->_val) : ((Sprite *) snc->_ptr));
+ break;
+ case SNKEEP :
+ _vm->snKeep(sprel, snc->_val);
+ break;
+ case SNGIVE :
+ _vm->snGive(sprel, snc->_val);
+ break;
+ case SNGAME :
+ _vm->snGame(sprel, snc->_val);
+ break;
+ case SNSETX0 :
+ _vm->snSetX0(snc->_ref, snc->_val);
+ break;
+ case SNSETY0 :
+ _vm->snSetY0(snc->_ref, snc->_val);
+ break;
+ case SNSETXY :
+ _vm->snSetXY(sprel, snc->_val);
+ break;
+ case SNRELX :
+ _vm->snRelX(sprel, snc->_val);
+ break;
+ case SNRELY :
+ _vm->snRelY(sprel, snc->_val);
+ break;
+ case SNRELZ :
+ _vm->snRelZ(sprel, snc->_val);
+ break;
+ case SNSETX :
+ _vm->snSetX(sprel, snc->_val);
+ break;
+ case SNSETY :
+ _vm->snSetY(sprel, snc->_val);
+ break;
+ case SNSETZ :
+ _vm->snSetZ(sprel, snc->_val);
+ break;
+ case SNSLAVE :
+ _vm->snSlave(sprel, snc->_val);
+ break;
+ case SNTRANS :
+ _vm->snTrans(sprel, snc->_val);
+ break;
+ case SNPORT :
+ _vm->snPort(sprel, snc->_val);
+ break;
+ case SNNEXT :
+ case SNIF :
+ case SNTALK :
+ break;
+ case SNMOUSE :
+ _vm->snMouse(snc->_val != 0);
+ break;
+ case SNNNEXT :
+ _vm->snNNext(sprel, snc->_val);
+ break;
+ case SNTNEXT :
+ _vm->snTNext(sprel, snc->_val);
+ break;
+ case SNRNNEXT :
+ _vm->snRNNext(sprel, snc->_val);
+ break;
+ case SNRTNEXT :
+ _vm->snRTNext(sprel, snc->_val);
+ break;
+ case SNRMNEAR :
+ _vm->snRmNear(sprel);
+ break;
+ case SNRMTAKE :
+ _vm->snRmTake(sprel);
+ break;
+ case SNFLAG :
+ _vm->snFlag(snc->_ref & 3, snc->_val != 0);
+ break;
+ case SNSETREF :
+ _vm->snSetRef(sprel, snc->_val);
+ break;
+ case SNBACKPT :
+ _vm->snBackPt(sprel, snc->_val);
+ break;
+ case SNFLASH :
+ _vm->snFlash(snc->_val != 0);
+ break;
+ case SNLIGHT :
+ _vm->snLight(snc->_val != 0);
+ break;
+ case SNSETHB :
+ _vm->snBarrier(snc->_ref, snc->_val, true);
+ break;
+ case SNSETVB :
+ _vm->snBarrier(snc->_ref, snc->_val, false);
+ break;
+ case SNWALK :
+ _vm->snWalk(sprel, snc->_ref, snc->_val);
+ break;
+ case SNREACH :
+ _vm->snReach(sprel, snc->_val);
+ break;
+ case SNSOUND :
+ _vm->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);
+ warning("STUB: SNEXEC code");
+ break;
+ case SNSTEP :
+ sprel->step();
+ break;
+ case SNZTRIM :
+ _vm->snZTrim(sprel);
+ break;
+ case SNGHOST :
+ _vm->snGhost((Bitmap *) snc->_ptr);
+ break;
+ default :
+ warning("Unhandled snc->_com in SNMouse(bool)");
+ break;
+ }
+ _tail++;
+ if (!_turbo)
+ break;
+ }
+xit:
+ _busy = false;
+ }
+}
+
+
+bool Snail::idle() {
+ 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..888fae6ce9
--- /dev/null
+++ b/engines/cge/snail.h
@@ -0,0 +1,110 @@
+/* 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_SNAIL__
+#define __CGE_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_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)
+
+#define SNAIL_FRAME_RATE 62
+#define SNAIL_FRAME_DELAY (1000 / SNAIL_FRAME_RATE)
+
+struct Bar {
+ uint8 _horz;
+ uint8 _vert;
+};
+
+
+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
+};
+
+class Snail {
+public:
+ struct Com {
+ SNCOM _com;
+ int _ref;
+ int _val;
+ void *_ptr;
+ } *_snList;
+ uint8 _head;
+ uint8 _tail;
+ bool _turbo;
+ bool _busy;
+ bool _textDelay;
+ uint32 _timerExpiry;
+ static const char *_comTxt[];
+ bool _talkEnable;
+ Snail(CGEEngine *vm, bool turbo);
+ ~Snail();
+ void runCom();
+ void addCom(SNCOM com, int ref, int val, void *ptr);
+ void insCom(SNCOM com, int ref, int val, void *ptr);
+ bool idle();
+private:
+ CGEEngine *_vm;
+};
+
+
+extern bool _dark;
+extern int _lev;
+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..0ea776b784
--- /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 __CGE_SNDDRV__
+#define __CGE_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
+void sndInit();
+
+// Close Digi Device
+void sndDone();
+
+// Set Volume
+void sndSetVolume();
+
+// Start Digi
+void sndDigiStart(SmpInfo *PSmpInfo);
+
+// Stop Digi
+void sndDigiStop(SmpInfo *PSmpInfo);
+
+// Start MIDI File
+void sndMidiStart(uint8 *MIDFile);
+
+// Stop MIDI File
+void sndMidiStop();
+
+// Play MIDI File (to be called while interrupting)
+// WARNING: Uses ALL registers!
+void sndMidiPlay();
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/sound.cpp b/engines/cge/sound.cpp
new file mode 100644
index 0000000000..a163949ddd
--- /dev/null
+++ b/engines/cge/sound.cpp
@@ -0,0 +1,227 @@
+/* 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 {
+
+Fx _fx = 16; // must precede SOUND!!
+Sound _sound;
+
+
+Sound::Sound() {
+ if (Startup::_soundOk)
+ open();
+}
+
+
+Sound::~Sound() {
+ close();
+}
+
+
+void Sound::close() {
+ killMidi();
+ sndDone();
+}
+
+
+void Sound::open() {
+ 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() {
+ 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() {
+ clear();
+ delete[] _cache;
+}
+
+
+void Fx::clear() {
+ 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() {
+ 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);
+ }
+ }
+ }
+}
+
+
+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..fda8d4f128
--- /dev/null
+++ b/engines/cge/sound.h
@@ -0,0 +1,80 @@
+/* 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_SOUND__
+#define __CGE_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();
+ ~Sound();
+ void open();
+ void close();
+ void play(DataCk *wav, int pan, int cnt = 1);
+ void stop();
+};
+
+
+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 clear();
+ void preload(int ref0);
+ DataCk *operator[](int ref);
+};
+
+extern Sound _sound;
+extern Fx _fx;
+
+
+void loadMidi(int ref);
+void killMidi();
+
+} // End of namespace CGE
+
+#endif
+
diff --git a/engines/cge/startup.cpp b/engines/cge/startup.cpp
new file mode 100644
index 0000000000..9210b40c77
--- /dev/null
+++ b/engines/cge/startup.cpp
@@ -0,0 +1,199 @@
+/* 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/cfile.h"
+#include "cge/snddrv.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 quitNow(int ref) {
+ error("%s", _text->getText(ref));
+}
+
+
+bool Startup::getParms() {
+ _summa = 0;
+
+ /*
+ 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;
+ }
+ if (_vm->_isDemo)
+ // 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
+ }
+
+ if (SNDDrvInfo.MDEV != DEV_GM)
+ SNDDrvInfo.MDEV = SNDDrvInfo.DDEV;
+ return true;
+ */
+ warning("STUB: Startup::get_parms");
+ return true;
+}
+
+
+Startup::Startup() {
+ /*
+ 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..cc16f2a123
--- /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 __CGE_STARTUP__
+#define __CGE_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 getParms();
+public:
+ static int _mode;
+ static int _core;
+ static int _soundOk;
+ static uint16 _summa;
+ Startup();
+};
+
+
+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..7c0f9563a6
--- /dev/null
+++ b/engines/cge/talk.cpp
@@ -0,0 +1,336 @@
+/* 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/events.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() {
+ free(_map);
+ free(_pos);
+ free(_wid);
+}
+
+
+void Font::load() {
+ 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[(unsigned char)*(text++)];
+ return w;
+}
+
+
+/*
+void Font::save() {
+ 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() {
+ 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[(unsigned char)*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[(unsigned char)*tx], i;
+ uint8 *f = _font->_map + _font->_pos[(unsigned char)*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;
+ uint16 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[(unsigned char)*text], i;
+ uint8 *fp = _font->_map + _font->_pos[(unsigned char)*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++;
+ }
+ }
+}
+
+
+InfoLine::InfoLine(CGEEngine *vm, uint16 w) : Talk(vm), _oldTxt(NULL), _vm(vm) {
+ _ts[0] = new Bitmap(w, FONT_HIG, TEXT_BG);
+ setShapeList(_ts);
+}
+
+
+void InfoLine::update(const char *tx) {
+ if (tx != _oldTxt) {
+ uint16 w = _ts[0]->_w;
+ uint16 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
+
+ // clear 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[(unsigned char)*tx];
+ uint8 *fp = _font->_map + _font->_pos[(unsigned char)*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..2f70471359
--- /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 __CGE_TALK__
+#define __CGE_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();
+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();
+ uint16 width(const char *text);
+ void save();
+};
+
+
+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);
+ Talk(CGEEngine *vm);
+ //~TALK();
+
+ static Font *_font;
+ static void init();
+ static void deinit();
+
+ virtual void update(const char *tx);
+ virtual void update() {}
+ void putLine(int line, const char *text);
+private:
+ CGEEngine *_vm;
+};
+
+
+class InfoLine : public Talk {
+ const char *_oldTxt;
+public:
+ InfoLine(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..5f370150ca
--- /dev/null
+++ b/engines/cge/text.cpp
@@ -0,0 +1,256 @@
+/* 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"
+
+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->gotoxy(x - (_talk->_w - sw) / 2 - 3 + 6 * east, y - spike->_h - _talk->_h + 1);
+ _talk->_z = 125;
+ _talk->_ref = SAY_REF;
+
+ spike->gotoxy(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->gotoxy(_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() {
+ 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..cf917ece61
--- /dev/null
+++ b/engines/cge/text.h
@@ -0,0 +1,84 @@
+/* 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_TEXT__
+#define __CGE_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 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();
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp
new file mode 100644
index 0000000000..36ac060111
--- /dev/null
+++ b/engines/cge/vga13h.cpp
@@ -0,0 +1,1363 @@
+/* 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 "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();
+
+/*
+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() {
+ /*
+ 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()
+ : 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 *shpP)
+ : _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;
+ _ref = 0;
+ _x = _y = 0;
+ _w = _h = 0;
+ _time = 0;
+ _seqPtr = 0;
+ _shpCnt = 0;
+ _prev = _next = NULL;
+
+ setShapeList(shpP);
+}
+
+
+Sprite::~Sprite() {
+ if (_sprite == this)
+ _sprite = NULL;
+ 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 *shpP) {
+ BMP_PTR *r = (_ext) ? _ext->_shpList : NULL;
+
+ _shpCnt = 0;
+ _w = 0;
+ _h = 0;
+
+ if (shpP) {
+ BMP_PTR *p;
+ for (p = shpP; *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 = shpP;
+ 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 == _vm->_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() {
+ 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,;/"), true);
+ 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("Bad NEAR in %d [%s]", lcnt, fname);
+ c->_ref = atoi(strtok(NULL, " \t,;/"));
+ c->_val = atoi(strtok(NULL, " \t,;/"));
+ c->_ptr = NULL;
+ }
+ }
+ }
+ break;
+ case 4 : { // Take
+ if (_takePtr != NO_PTR) {
+ tak = (Snail::Com *) realloc(tak, (takcnt + 1) * sizeof(*tak));
+ if (tak == NULL)
+ error("No core [%s]", fname);
+ else {
+ Snail::Com *c = &tak[takcnt++];
+ if ((c->_com = (SNCOM)takeEnum(Snail::_comTxt, strtok(NULL, " \t,;/"))) < 0)
+ error("Bad NEAR in %d [%s]", lcnt, fname);
+ c->_ref = atoi(strtok(NULL, " \t,;/"));
+ c->_val = atoi(strtok(NULL, " \t,;/"));
+ c->_ptr = NULL;
+ }
+ }
+ break;
+ }
+ }
+ }
+ } else { // no sprite description: try to read immediately from .BMP
+ shplist[shpcnt++] = new Bitmap(_file, true);
+ }
+ 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() {
+ 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) {
+ gotoxy(_x + (seq->_dx), _y + (seq->_dy));
+ _time = seq->_dly;
+ }
+ }
+}
+
+
+void Sprite::tick() {
+ 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() {
+ 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::gotoxy(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->gotoxy(_next->_x - xo + _x, _next->_y - yo + _y);
+ if (_flags._shad)
+ _prev->gotoxy(_prev->_x - xo + _x, _prev->_y - yo + _y);
+}
+
+
+void Sprite::center() {
+ gotoxy((SCR_WID - _w) / 2, (SCR_HIG - _h) / 2);
+}
+
+
+void Sprite::show() {
+ 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() {
+ register SprExt *e = _ext;
+ if (e->_b0)
+ e->_b0->hide(e->_x0, e->_y0);
+}
+
+
+BMP_PTR Sprite::ghost() {
+ 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;
+}
+
+void Sprite::sync(Common::Serializer &s) {
+ uint16 unused;
+
+ s.syncAsUint16LE(unused);
+ s.syncAsUint16LE(unused); // _ext
+ s.syncAsUint16LE(_ref);
+ s.syncAsByte(_cave);
+ s.syncBytes((byte *)&_flags, 2);
+ s.syncAsUint16LE(_x);
+ s.syncAsUint16LE(_y);
+ s.syncAsByte(_z);
+ s.syncAsUint16LE(_w);
+ s.syncAsUint16LE(_h);
+ s.syncAsUint16LE(_time);
+ s.syncAsByte(_nearPtr);
+ s.syncAsByte(_takePtr);
+ s.syncAsSint16LE(_seqPtr);
+ s.syncAsUint16LE(_shpCnt);
+ s.syncBytes((byte *)&_file[0], 9);
+ _file[8] = '\0';
+
+ s.syncAsUint16LE(unused); // _prev
+ s.syncAsUint16LE(unused); // _next
+}
+
+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() {
+ clear();
+}
+
+
+void Queue::clear() {
+ 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) {
+ _page[idx]->free();
+ 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) {
+ debugN("%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() {
+ _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 + "]";
+
+ debugN("%s", buffer.c_str());
+ }
+
+ delete _showQ;
+ delete _spareQ;
+}
+
+
+void Vga::setStatAdr() {
+ /*
+ 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);
+ palToDac(palData, tab);
+}
+
+void Vga::palToDac(const byte *palData, Dac *tab) {
+ const byte *colP = palData;
+ for (int idx = 0; idx < PAL_CNT; ++idx, colP += 3) {
+ tab[idx]._r = *colP >> 2;
+ tab[idx]._g = *(colP + 1) >> 2;
+ tab[idx]._b = *(colP + 2) >> 2;
+ }
+}
+
+void Vga::dacToPal(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, *destP = _newColors;
+ for (int idx = 0; idx < PAL_CNT; ++idx, ++palP, ++destP) {
+ destP->_r = (palP->_r * lum) >> 6;
+ destP->_g = (palP->_g * lum) >> 6;
+ destP->_b = (palP->_b * lum) >> 6;
+ }
+
+ if (_mono) {
+ destP = _newColors;
+ for (int idx = 0; idx < PAL_CNT; ++idx, ++palP) {
+ // Form a greyscalce colour from 30% R, 59% G, 11% B
+ uint8 intensity = (destP->_r * 77) + (destP->_g * 151) + (destP->_b * 28);
+ destP->_r = intensity;
+ destP->_g = intensity;
+ destP->_b = intensity;
+ }
+ }
+
+ _setPal = true;
+}
+
+
+void Vga::setColors() {
+ 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() {
+ Dac tab[256];
+ getColors(tab);
+ for (int i = 64; i >= 0; i -= FADE_STEP) {
+ setColors(tab, i);
+ waitVR(true);
+ updateColors();
+ }
+}
+
+
+void Vga::show() {
+ 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() {
+ byte palData[PAL_SIZ];
+ dacToPal(_newColors, palData);
+ g_system->getPaletteManager()->setPalette(palData, 0, 256);
+}
+
+
+void Vga::update() {
+ 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) {
+ for (int yp = y; yp < y + _h; ++yp) {
+ const byte *srcP = (const byte *)Vga::_page[2]->getBasePtr(x, yp);
+ byte *destP = (byte *)Vga::_page[1]->getBasePtr(x, yp);
+
+ Common::copy(srcP, srcP + _w, destP);
+ }
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/vga13h.h b/engines/cge/vga13h.h
new file mode 100644
index 0000000000..b0cba4dcc0
--- /dev/null
+++ b/engines/cge/vga13h.h
@@ -0,0 +1,352 @@
+/* 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_VGA13H__
+#define __CGE_VGA13H__
+
+#include "common/serializer.h"
+#include "graphics/surface.h"
+#include "cge/general.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;
+ uint8 _takePtr;
+ int _seqPtr;
+ int _shpCnt;
+ char _file[MAXFILE];
+ Sprite *_prev;
+ Sprite *_next;
+
+ bool works(Sprite *spr);
+ bool seqTest(int n);
+ inline bool active() {
+ return _ext != NULL;
+ }
+ Sprite(CGEEngine *vm, BMP_PTR *shp);
+ virtual ~Sprite();
+ BMP_PTR shp();
+ BMP_PTR *setShapeList(BMP_PTR *shp);
+ void moveShapes(uint8 *buf);
+ Sprite *expand();
+ Sprite *contract();
+ Sprite *backShow(bool fast = false);
+ void setName(char *n);
+ inline char *name() {
+ return (_ext) ? _ext->_name : NULL;
+ }
+ void gotoxy(int x, int y);
+ void center();
+ void show();
+ void hide();
+ BMP_PTR ghost();
+ void show(uint16 pg);
+ void makeXlat(uint8 *x);
+ void killXlat();
+ 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 sync(Common::Serializer &s);
+private:
+ CGEEngine *_vm;
+};
+
+
+class Queue {
+ Sprite *_head;
+ Sprite *_tail;
+public:
+ Queue(bool show);
+ ~Queue();
+
+ bool _show;
+
+ 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() {
+ return _head;
+ }
+ Sprite *last() {
+ return _tail;
+ }
+ Sprite *locate(int ref);
+ void clear();
+};
+
+
+class Vga {
+ uint16 _oldMode;
+ uint16 *_oldScreen;
+ uint16 _statAdr;
+ bool _setPal;
+ Dac *_oldColors;
+ Dac *_newColors;
+ const char *_msg;
+ const char *_nam;
+
+ int setMode(int mode);
+ void updateColors();
+ void setColors();
+ void setStatAdr();
+ void waitVR(bool on);
+public:
+ uint32 _frmCnt;
+ Queue *_showQ;
+ Queue *_spareQ;
+ int _mono;
+ static Graphics::Surface *_page[4];
+ static Dac *_sysPal;
+
+ Vga(int mode);
+ ~Vga();
+ 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 show();
+ void update();
+
+ static void palToDac(const byte *palData, Dac *tab);
+ static void dacToPal(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
+}
+
+uint16 *saveScreen();
+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..8fef6307b1
--- /dev/null
+++ b/engines/cge/vmenu.cpp
@@ -0,0 +1,155 @@
+/* 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/events.h"
+#include "cge/cge_main.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
+
+
+
+
+MenuBar::MenuBar(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
+ gotoxy(x - _w / 2, y - (TEXT_VM + FONT_HIG / 2));
+ _vga->_showQ->insert(this, _vga->_showQ->last());
+ _bar = new MenuBar(_vm, _w - 2 * TEXT_HM);
+ _bar->gotoxy(_x + TEXT_HM - MB_HM, _y + TEXT_VM - MB_VM);
+ _vga->_showQ->insert(_bar, _vga->_showQ->last());
+}
+
+
+Vmenu::~Vmenu() {
+ _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->gotoxy(_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..6b4eb85a53
--- /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 __CGE_VMENU__
+#define __CGE_VMENU__
+
+#include "cge/talk.h"
+
+namespace CGE {
+
+#define MB_VM 1
+#define MB_HM 3
+
+
+struct Choice {
+ const char *_text;
+ void (CGEEngine::*Proc)();
+};
+
+
+class MenuBar : public Talk {
+public:
+ MenuBar(CGEEngine *vm, uint16 w);
+private:
+ CGEEngine *_vm;
+};
+
+
+class Vmenu : public Talk {
+ uint16 _items;
+ Choice *_menu;
+public:
+ static Vmenu *_addr;
+ static int _recent;
+ MenuBar *_bar;
+ Vmenu(CGEEngine *vm, Choice *list, int x, int y);
+ ~Vmenu();
+ virtual 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..04a9189682
--- /dev/null
+++ b/engines/cge/vol.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/vol.h"
+#include "common/system.h"
+#include "common/str.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");
+ BtKeypack *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() {
+ if (_recent == this)
+ _recent = NULL;
+}
+
+
+bool VFile::exist(const char *name) {
+ return scumm_stricmp(_cat->find(name)->_key, name) == 0;
+}
+
+
+void VFile::readBuff() {
+ 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;
+}
+
+long VFile::mark() {
+ return (_bufMark + _ptr) - _begMark;
+}
+
+long VFile::size() {
+ return _endMark - _begMark;
+}
+
+long VFile::seek(long pos) {
+ _recent = NULL;
+ _lim = 0;
+ return (_bufMark = _begMark + pos);
+}
+
+} // End of namespace CGE
diff --git a/engines/cge/vol.h b/engines/cge/vol.h
new file mode 100644
index 0000000000..8ed33d0ab4
--- /dev/null
+++ b/engines/cge/vol.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 __CGE_VOL__
+#define __CGE_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;
+ long _endMark;
+
+ void readBuff();
+ void writeBuff() { }
+ void make(const char *fspec);
+public:
+ VFile(const char *name, IOMODE mode = REA);
+ ~VFile();
+
+ static void init();
+ static void deinit();
+ static bool exist(const char *name);
+ static const char *next();
+ long mark();
+ long size();
+ long seek(long pos);
+};
+
+
+} // End of namespace CGE
+
+#endif
diff --git a/engines/cge/wav.h b/engines/cge/wav.h
new file mode 100644
index 0000000000..c3e67f5f95
--- /dev/null
+++ b/engines/cge/wav.h
@@ -0,0 +1,148 @@
+/* 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_WAV__
+#define __CGE_WAV__
+
+#include "cge/general.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
+
+class ChunkId { // Chunk type identifier
+ union {
+ FourCC _tx;
+ uint32 _id;
+ };
+protected:
+ static XFile *ckFile;
+public:
+ ChunkId(FourCC t) {
+ memcpy(_tx, t, sizeof(_tx));
+ }
+ ChunkId(uint32 d) {
+ _id = d;
+ }
+ ChunkId(XFile *xf) {
+ (ckFile = xf)->read(_tx, sizeof(_tx));
+ }
+ bool operator !=(ChunkId &X) {
+ return _id != X._id;
+ }
+ bool operator ==(ChunkId &X) {
+ return _id == X._id;
+ }
+ const char *name();
+};
+
+
+class CkHea : public ChunkId {
+protected:
+ uint32 _ckSize; // Chunk size field (size of ckData)
+public:
+ CkHea(XFile *xf) : ChunkId(xf) {
+ XRead(xf, &_ckSize);
+ }
+ CkHea(char id[]) : ChunkId(id), _ckSize(0) { }
+ void skip();
+ uint32 size() {
+ 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() {
+ return _wav._wChannels;
+ }
+ inline uint32 smplRate() {
+ return _wav._dwSamplesPerSec;
+ }
+ inline uint32 byteRate() {
+ return _wav._dwAvgBytesPerSec;
+ }
+ inline uint16 blckSize() {
+ return _wav._wBlockAlign;
+ }
+ inline uint16 smplSize() {
+ 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();
+ inline uint8 *addr() {
+ return _buf;
+ }
+ inline Ems *eAddr() {
+ return _eBuf;
+ }
+};
+
+
+extern ChunkId _riff;
+extern ChunkId _wave;
+extern ChunkId _fmt;
+extern ChunkId _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