aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/cge/cge.h6
-rw-r--r--engines/cge/detection.cpp113
-rw-r--r--engines/cge2/bitmap.cpp388
-rw-r--r--engines/cge2/bitmap.h92
-rw-r--r--engines/cge2/cge2.cpp182
-rw-r--r--engines/cge2/cge2.h244
-rw-r--r--engines/cge2/cge2_main.cpp759
-rw-r--r--engines/cge2/cge2_main.h67
-rw-r--r--engines/cge2/configure.engine3
-rw-r--r--engines/cge2/detection.cpp87
-rw-r--r--engines/cge2/events.cpp85
-rw-r--r--engines/cge2/events.h88
-rw-r--r--engines/cge2/fileio.cpp270
-rw-r--r--engines/cge2/fileio.h136
-rw-r--r--engines/cge2/general.h47
-rw-r--r--engines/cge2/hero.cpp146
-rw-r--r--engines/cge2/hero.h105
-rw-r--r--engines/cge2/module.mk24
-rw-r--r--engines/cge2/snail.cpp689
-rw-r--r--engines/cge2/snail.h153
-rw-r--r--engines/cge2/sound.cpp254
-rw-r--r--engines/cge2/sound.h130
-rw-r--r--engines/cge2/spare.cpp97
-rw-r--r--engines/cge2/spare.h55
-rw-r--r--engines/cge2/talk.cpp88
-rw-r--r--engines/cge2/talk.h78
-rw-r--r--engines/cge2/text.cpp152
-rw-r--r--engines/cge2/text.h67
-rw-r--r--engines/cge2/vga13h.cpp1182
-rw-r--r--engines/cge2/vga13h.h295
30 files changed, 6001 insertions, 81 deletions
diff --git a/engines/cge/cge.h b/engines/cge/cge.h
index a65069ff46..c43358f252 100644
--- a/engines/cge/cge.h
+++ b/engines/cge/cge.h
@@ -80,12 +80,6 @@ class Talk;
#define kSayTheEnd 41
-enum GameType {
- kGameTypeNone = 0,
- kGameTypeSoltys,
- kGameTypeSfinx
-};
-
// our engine debug channels
enum {
kCGEDebugBitmap = 1 << 0,
diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp
index 4c2f81c1ae..60558f147e 100644
--- a/engines/cge/detection.cpp
+++ b/engines/cge/detection.cpp
@@ -33,7 +33,6 @@ namespace CGE {
struct CgeGameDescription {
ADGameDescription desc;
- GameType gameType;
};
#define GAMEOPTION_COLOR_BLIND_DEFAULT_OFF GUIO_GAMEOPTIONS1
@@ -42,117 +41,81 @@ struct CgeGameDescription {
static const PlainGameDescriptor CGEGames[] = {
{ "soltys", "Soltys" },
- { "sfinx", "Sfinx" },
{ 0, 0 }
};
namespace CGE {
-static const CgeGameDescription gameDescriptions[] = {
-
- {
- {
- "soltys", "",
- {
- {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
- {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437572},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0()
- },
- kGameTypeSoltys
- },
+static const ADGameDescription gameDescriptions[] = {
{
+ "soltys", "",
{
- "soltys", "Soltys Freeware",
- {
- {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
- {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
+ {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437572},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0()
},
{
+ "soltys", "Soltys Freeware",
{
- "soltys", "Soltys Demo (not supported)",
- {
- {"vol.cat", 0, "1e077c8ff58109a187f07ac54b0c873a", 18788},
- {"vol.dat", 0, "75d385a6074c58b69f7730481f256051", 1796710},
- AD_LISTEND
- },
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176},
+ {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Soltys Demo (not supported)",
{
- "soltys", "Soltys Demo (not supported)",
- {
- {"vol.cat", 0, "f17987487fab1ebddd781d8d02fedecc", 7168},
- {"vol.dat", 0, "c5d9b15863cab61dc125551576dece04", 1075272},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "1e077c8ff58109a187f07ac54b0c873a", 18788},
+ {"vol.dat", 0, "75d385a6074c58b69f7730481f256051", 1796710},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Soltys Demo (not supported)",
{
- "soltys", "Soltys Freeware v1.0",
- {
- {"vol.cat", 0, "f1675684c68ab90272f5776f8f2c3974", 50176},
- {"vol.dat", 0, "4ffeff4abc99ac5999b55ccfc56ab1df", 8430868},
- AD_LISTEND
- },
- Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "f17987487fab1ebddd781d8d02fedecc", 7168},
+ {"vol.dat", 0, "c5d9b15863cab61dc125551576dece04", 1075272},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::PL_POL, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Soltys Freeware v1.0",
{
- "soltys", "Soltys Freeware v1.0",
- {
- {"vol.cat", 0, "20fdce799adb618100ef9ee2362be875", 50176},
- {"vol.dat", 0, "0e43331c846094d77f5dd201827e0a3b", 8439339},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "f1675684c68ab90272f5776f8f2c3974", 50176},
+ {"vol.dat", 0, "4ffeff4abc99ac5999b55ccfc56ab1df", 8430868},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Soltys Freeware v1.0",
{
- "soltys", "Soltys Freeware v1.0",
- {
- {"vol.cat", 0, "fcae86b20eaa5cedec17b24fa5e85eb4", 50176},
- {"vol.dat", 0, "ff10d54acc2c95696c57e05819b6906f", 8450151},
- AD_LISTEND
- },
- Common::ES_ESP, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "20fdce799adb618100ef9ee2362be875", 50176},
+ {"vol.dat", 0, "0e43331c846094d77f5dd201827e0a3b", 8439339},
+ AD_LISTEND
},
- kGameTypeSoltys
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
{
+ "soltys", "Soltys Freeware v1.0",
{
- // Polish version, provided by Strangerke
- "sfinx", "Sfinx Freeware",
- {
- {"vol.cat", 0, "21197b287d397c53261b6616bf0dd880", 129024},
- {"vol.dat", 0, "de14291869a8eb7c2732ab783c7542ef", 34180844},
- AD_LISTEND
- },
- Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
+ {"vol.cat", 0, "fcae86b20eaa5cedec17b24fa5e85eb4", 50176},
+ {"vol.dat", 0, "ff10d54acc2c95696c57e05819b6906f", 8450151},
+ AD_LISTEND
},
- kGameTypeSfinx
+ Common::ES_ESP, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF)
},
- {AD_TABLE_END_MARKER, kGameTypeNone}
+ AD_TABLE_END_MARKER
};
static const ADFileBasedFallback fileBasedFallback[] = {
- { &gameDescriptions[0].desc, { "vol.cat", "vol.dat", 0 } },
+ { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } },
{ 0, { 0 } }
};
} // End of namespace CGE
diff --git a/engines/cge2/bitmap.cpp b/engines/cge2/bitmap.cpp
new file mode 100644
index 0000000000..10fd6f1163
--- /dev/null
+++ b/engines/cge2/bitmap.cpp
@@ -0,0 +1,388 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/bitmap.h"
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+//#include "cge/cge_main.h"
+#include "common/system.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+
+namespace CGE2 {
+
+Bitmap::Bitmap(CGE2Engine *vm, const char *fname) : _m(NULL), _v(NULL), _map(0), _vm(vm) {
+ char pat[kMaxPath];
+ forceExt(pat, fname, ".VBM");
+
+ if (_vm->_resman->exist(pat)) {
+ EncryptedStream file(_vm, pat);
+ if (file.err())
+ error("Unable to find VBM [%s]", fname);
+ if (!loadVBM(&file))
+ error("Bad VBM [%s]", fname);
+ } else {
+ error("Bad VBM [%s]", fname);
+ }
+}
+
+Bitmap::Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 *map) : _w(w), _h(h), _m(map), _v(NULL), _map(0), _b(NULL), _vm(vm) {
+ 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(CGE2Engine *vm, uint16 w, uint16 h, uint8 fill)
+ : _w((w + 3) & ~3), // only full uint32 allowed!
+ _h(h), _m(NULL), _map(0), _b(NULL), _vm(vm) {
+
+ 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
+ assert(v != NULL);
+
+ WRITE_LE_UINT16(v, (kBmpCPY | dsiz)); // data chunk hader
+ memset(v + 2, fill, dsiz); // data bytes
+ WRITE_LE_UINT16(v + lsiz - 2, (kBmpSKP | ((kScrWidth / 4) - dsiz))); // gap
+
+ // Replicate lines
+ byte *destP;
+ for (destP = v + lsiz; destP < (v + psiz); destP += lsiz)
+ Common::copy(v, v + lsiz, destP);
+
+ WRITE_LE_UINT16(v + psiz - 2, kBmpEOI); // plane trailer uint16
+
+ // Replicate 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 = (kScrWidth - _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(CGE2Engine *vm, const Bitmap &bmp) : _w(bmp._w), _h(bmp._h), _m(NULL), _v(NULL), _map(0), _b(NULL), _vm(vm) {
+ uint8 *v0 = bmp._v;
+ if (!v0)
+ return;
+
+ uint16 vsiz = (uint8 *)(bmp._b) - (uint8 *)(v0);
+ uint16 siz = vsiz + _h * sizeof(HideDesc);
+ uint8 *v1 = new uint8[siz];
+ assert(v1 != NULL);
+ memcpy(v1, v0, siz);
+ _b = (HideDesc *)((_v = v1) + vsiz);
+}
+
+Bitmap::~Bitmap() {
+ release();
+}
+
+void Bitmap::release() {
+ free(_m);
+ delete[] _v;
+}
+
+Bitmap &Bitmap::operator=(const Bitmap &bmp) {
+ if (this == &bmp)
+ return *this;
+
+ uint8 *v0 = bmp._v;
+ _w = bmp._w;
+ _h = bmp._h;
+ _m = NULL;
+ _map = 0;
+ _vm = bmp._vm;
+ delete[] _v;
+
+ if (v0 == NULL) {
+ _v = NULL;
+ } else {
+ uint16 vsiz = (uint8 *)bmp._b - (uint8 *)v0;
+ uint16 siz = vsiz + _h * sizeof(HideDesc);
+ uint8 *v1 = new uint8[siz];
+ assert(v1 != NULL);
+ memcpy(v1, v0, siz);
+ _b = (HideDesc *)((_v = v1) + vsiz);
+ }
+ return *this;
+}
+
+char *Bitmap::forceExt(char *buf, const char *name, const char *ext) {
+ strcpy(buf, name);
+ char *dot = strrchr(buf, '.');
+ if (dot)
+ *dot = '\0';
+ strcat(buf, ext);
+
+ return buf;
+}
+
+BitmapPtr Bitmap::code() {
+ if (!_m)
+ return NULL;
+
+ uint16 cnt;
+
+ if (_v) { // old X-map exists, so remove it
+ delete[] _v;
+ _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 (uint16 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] == kPixelTransp);
+ uint16 j;
+
+ cnt = 0;
+ for (uint16 i = 0; i < _h; i++) { // once per each line
+ uint8 pix;
+ for (j = bpl; j < _w; j += 4) {
+ pix = bm[j];
+ if (_v && pix != kPixelTransp) {
+ if (j < _b[i]._skip)
+ _b[i]._skip = j;
+
+ if (j >= _b[i]._hide)
+ _b[i]._hide = j + 1;
+ }
+ if ((pix == kPixelTransp) != skip || cnt >= 0x3FF0) { // end of block
+ cnt |= (skip) ? kBmpSKP : kBmpCPY;
+ if (_v)
+ WRITE_LE_UINT16(cp, cnt); // store block description uint16
+
+ cp = (uint16 *) im;
+ im += 2;
+ skip = (pix == kPixelTransp);
+ cnt = 0;
+ }
+ if (!skip) {
+ if (_v)
+ *im = pix;
+ im++;
+ }
+ cnt++;
+ }
+
+ bm += _w;
+ if (_w < kScrWidth) {
+ if (skip) {
+ cnt += (kScrWidth - j + 3) / 4;
+ } else {
+ cnt |= kBmpCPY;
+ if (_v)
+ WRITE_LE_UINT16(cp, cnt);
+
+ cp = (uint16 *) im;
+ im += 2;
+ skip = true;
+ cnt = (kScrWidth - j + 3) / 4;
+ }
+ }
+ }
+ if (cnt && ! skip) {
+ cnt |= kBmpCPY;
+ if (_v)
+ WRITE_LE_UINT16(cp, cnt);
+
+ cp = (uint16 *) im;
+ im += 2;
+ }
+ if (_v)
+ WRITE_LE_UINT16(cp, kBmpEOI);
+ cp = (uint16 *) im;
+ im += 2;
+ }
+ if (_v)
+ break;
+
+ uint16 sizV = (uint16)(im - 2 - _v);
+ _v = new uint8[sizV + _h * sizeof(*_b)];
+ assert(_v != NULL);
+
+ _b = (HideDesc *)(_v + sizV);
+ }
+ cnt = 0;
+ for (uint16 i = 0; i < _h; i++) {
+ if (_b[i]._skip == 0xFFFF) { // whole line is skipped
+ _b[i]._skip = (cnt + kScrWidth) >> 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 = kScrWidth - h;
+ }
+ }
+
+ return this;
+}
+
+bool Bitmap::solidAt(int16 x, int16 y) {
+ if ((x >= _w) || (y >= _h))
+ return false;
+
+ uint8 *m = _v;
+ uint16 r = static_cast<uint16>(x) % 4;
+ uint16 n0 = (kScrWidth * y + x) / 4;
+ uint16 n = 0;
+
+ while (r) {
+ uint16 w, t;
+
+ w = READ_LE_UINT16(m);
+ m += 2;
+ t = w & 0xC000;
+ w &= 0x3FFF;
+
+ switch (t) {
+ case kBmpEOI:
+ r--;
+ // No break on purpose
+ case kBmpSKP:
+ w = 0;
+ break;
+ case kBmpREP:
+ w = 1;
+ break;
+ }
+ m += w;
+ }
+
+ while (true) {
+ uint16 w, t;
+
+ w = READ_LE_UINT16(m);
+ m += 2;
+ t = w & 0xC000;
+ w &= 0x3FFF;
+
+ if (n > n0)
+ return false;
+
+ n += w;
+ switch (t) {
+ case kBmpEOI:
+ return false;
+ case kBmpSKP:
+ w = 0;
+ break;
+ case kBmpREP:
+ case kBmpCPY:
+ if (n - w <= n0 && n > n0)
+ return true;
+ break;
+ }
+ m += ((t == kBmpREP) ? 1 : w);
+ }
+}
+
+bool Bitmap::loadVBM(EncryptedStream *f) {
+ uint16 p = 0, n = 0;
+ if (!f->err())
+ f->read((uint8 *)&p, sizeof(p));
+ p = FROM_LE_16(p);
+
+ if (!f->err())
+ f->read((uint8 *)&n, sizeof(n));
+ n = FROM_LE_16(n);
+
+ if (!f->err())
+ f->read((uint8 *)&_w, sizeof(_w));
+ _w = FROM_LE_16(_w);
+
+ if (!f->err())
+ f->read((uint8 *)&_h, sizeof(_h));
+ _h = FROM_LE_16(_h);
+
+ if (!f->err()) {
+ if (p) {
+ if (_vm->_bitmapPalette) {
+ // Read in the palette
+ byte palData[kPalSize];
+ f->read(palData, kPalSize);
+
+ const byte *srcP = palData;
+ for (int idx = 0; idx < kPalCount; idx++, srcP += 3) {
+ _vm->_bitmapPalette[idx]._r = *srcP;
+ _vm->_bitmapPalette[idx]._g = *(srcP + 1);
+ _vm->_bitmapPalette[idx]._b = *(srcP + 2);
+ }
+ } else
+ f->seek(f->pos() + kPalSize);
+ }
+ }
+ if ((_v = new uint8[n]) == NULL)
+ return false;
+
+ if (!f->err())
+ f->read(_v, n);
+
+ _b = (HideDesc *)(_v + n - _h * sizeof(HideDesc));
+ return (!f->err());
+}
+
+void Bitmap::xLatPos(V2D& p) {
+ p.x -= (_w >> 1);
+ p.y = kWorldHeight - p.y - _h;
+}
+
+bool Bitmap::moveHi(void) {
+ warning("STUB: Bitmap::moveHi()");
+ return true;
+}
+
+bool Bitmap::moveLo(void) {
+ warning("STUB: Bitmap::moveLo()");
+ return true;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/bitmap.h b/engines/cge2/bitmap.h
new file mode 100644
index 0000000000..82c3b07e31
--- /dev/null
+++ b/engines/cge2/bitmap.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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_BITMAP_H
+#define CGE2_BITMAP_H
+
+#include "cge2/general.h"
+#include "common/file.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+class EncryptedStream;
+class V2D;
+
+#define kMaxPath 128
+enum {
+ kBmpEOI = 0x0000,
+ kBmpSKP = 0x4000,
+ kBmpREP = 0x8000,
+ kBmpCPY = 0xC000
+};
+
+#include "common/pack-start.h"
+
+struct HideDesc {
+ uint16 _skip;
+ uint16 _hide;
+};
+
+#include "common/pack-end.h"
+
+class Bitmap {
+ CGE2Engine *_vm;
+ char *forceExt(char *buf, const char *name, const char *ext);
+ bool loadVBM(EncryptedStream *f);
+public:
+ uint16 _w;
+ uint16 _h;
+ uint8 *_m;
+ uint8 *_v;
+ int32 _map;
+ HideDesc *_b;
+
+ Bitmap(CGE2Engine *vm, const char *fname);
+ Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 *map);
+ Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 fill);
+ Bitmap(CGE2Engine *vm, const Bitmap &bmp);
+ ~Bitmap();
+
+ Bitmap *code();
+ Bitmap &operator=(const Bitmap &bmp);
+ void release();
+ void hide(int16 x, int16 y);
+ void show(int16 x, int16 y);
+ void xShow(int16 x, int16 y);
+ bool solidAt(int16 x, int16 y);
+ void xLatPos(V2D& p);
+ bool moveHi(void);
+ bool moveLo(void);
+};
+
+
+typedef Bitmap *BitmapPtr;
+
+} // End of namespace CGE2
+
+#endif // CGE2_BITMAP_H
diff --git a/engines/cge2/cge2.cpp b/engines/cge2/cge2.cpp
new file mode 100644
index 0000000000..273c9dac0d
--- /dev/null
+++ b/engines/cge2/cge2.cpp
@@ -0,0 +1,182 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "engines/util.h"
+
+#include "cge2/cge2.h"
+#include "cge2/bitmap.h"
+#include "cge2/vga13h.h"
+#include "cge2/sound.h"
+#include "cge2/text.h"
+#include "cge2/hero.h"
+#include "cge2/general.h"
+#include "cge2/spare.h"
+#include "cge2/events.h"
+#include "cge2/talk.h"
+#include "cge2/cge2_main.h"
+
+namespace CGE2 {
+
+CGE2Engine::CGE2Engine(OSystem *syst, const ADGameDescription *gameDescription)
+ : Engine(syst), _gameDescription(gameDescription), _randomSource("cge") {
+ _resman = nullptr;
+ _vga = nullptr;
+ _sprite = nullptr;
+ _midiPlayer = nullptr;
+ _fx = nullptr;
+ _sound = nullptr;
+ _text = nullptr;
+ for (int i = 0; i < 2; i++)
+ _heroTab[i] = nullptr;
+ _eye = nullptr;
+ for (int i = 0; i < kCaveMax; i++)
+ _eyeTab[i] = nullptr;
+ _spare = nullptr;
+ _commandHandler = nullptr;
+ _commandHandlerTurbo = nullptr;
+ _infoLine = nullptr;
+ _mouse = nullptr;
+ _keyboard = nullptr;
+ _talk = nullptr;
+ for (int i = 0; i < kMaxPoint; i++)
+ _point[i] = nullptr;
+ _sys = nullptr;
+ _busyPtr = nullptr;
+ for (int i = 0; i < 2; i++)
+ _vol[i] = nullptr;
+
+ _quitFlag = false;
+ _bitmapPalette = nullptr;
+ _mode = 0;
+ _music = true;
+ _startupMode = 1;
+ _now = 1;
+ _sex = true;
+ _mouseTop = kWorldHeight / 3;
+ _dark = false;
+ _lastFrame = 0;
+ _lastTick = 0;
+ _waitSeq = 0;
+ _waitRef = 0;
+ _commandStat._wait = nullptr;
+ _commandStat._ref[0] = 0;
+ _commandStat._ref[1] = 0;
+ _taken = false;
+ _endGame = false;
+ for (int i = 0; i < 4; i++)
+ _flag[i] = false;
+}
+
+void CGE2Engine::init() {
+ _resman = new ResourceManager();
+ _vga = new Vga(this);
+ _fx = new Fx(this, 16);
+ _sound = new Sound(this);
+ _midiPlayer = new MusicPlayer(this);
+ _text = new Text(this, "CGE");
+ for (int i = 0; i < 2; i++)
+ _heroTab[i] = new HeroTab(this);
+ _eye = new V3D();
+ for (int i = 0; i < kCaveMax; i++)
+ _eyeTab[i] = new V3D();
+ _spare = new Spare(this);
+ _commandHandler = new CommandHandler(this, false);
+ _commandHandlerTurbo = new CommandHandler(this, true);
+ _infoLine = new InfoLine(this, kInfoW);
+ _mouse = new Mouse(this);
+ _keyboard = new Keyboard(this);
+ for (int i = 0; i < kMaxPoint; i++)
+ _point[i] = new V3D();
+ _sys = new System(this);
+}
+
+void CGE2Engine::deinit() {
+ delete _resman;
+ delete _vga;
+ delete _fx;
+ delete _sound;
+ delete _midiPlayer;
+ delete _text;
+ for (int i = 0; i < 2; i++)
+ delete _heroTab[i];
+ for (int i = 0; i < kCaveMax; i++) {
+ if (_eye == _eyeTab[i])
+ _eye = nullptr;
+ delete _eyeTab[i];
+ }
+ if (_eye != nullptr)
+ delete _eye;
+ delete _spare;
+ delete _sprite;
+ delete _commandHandler;
+ delete _commandHandlerTurbo;
+ delete _infoLine;
+ delete _mouse;
+ delete _keyboard;
+ if (_talk != nullptr)
+ delete _talk;
+ for (int i = 0; i < kMaxPoint; i++) {
+ delete _point[i];
+ }
+ delete _sys;
+}
+
+bool CGE2Engine::hasFeature(EngineFeature f) const {
+ return false;
+}
+
+bool CGE2Engine::canLoadGameStateCurrently() {
+ return false;
+}
+bool CGE2Engine::canSaveGameStateCurrently() {
+ return false;
+}
+
+Common::Error CGE2Engine::loadGameState(int slot) {
+ warning("STUB: CGE2Engine::loadGameState()");
+ return Common::kNoError;
+}
+
+Common::Error CGE2Engine::saveGameState(int slot, const Common::String &desc) {
+ warning("STUB: CGE2Engine::saveGameState()");
+ return Common::kNoError;
+}
+
+Common::Error CGE2Engine::run() {
+ warning("STUB: CGE2Engine::run()");
+
+ initGraphics(kScrWidth, kScrHeight, false);
+
+ init();
+
+ cge2_main();
+
+ deinit();
+ return Common::kNoError;
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/cge2.h b/engines/cge2/cge2.h
new file mode 100644
index 0000000000..66bcd911e9
--- /dev/null
+++ b/engines/cge2/cge2.h
@@ -0,0 +1,244 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_H
+#define CGE2_H
+
+#include "common/random.h"
+#include "engines/engine.h"
+#include "engines/advancedDetector.h"
+#include "common/system.h"
+#include "cge2/fileio.h"
+
+namespace CGE2 {
+
+class Vga;
+class Sprite;
+class MusicPlayer;
+class Fx;
+class Sound;
+class Text;
+struct HeroTab;
+class V3D;
+class V2D;
+struct Dac;
+class Spare;
+class CommandHandler;
+class InfoLine;
+class Mouse;
+class Keyboard;
+class Talk;
+class Hero;
+class Bitmap;
+class System;
+
+#define kScrWidth 320
+#define kScrHeight 240
+#define kScrDepth 480
+#define kPanHeight 40
+#define kWorldHeight (kScrHeight - kPanHeight)
+#define kMaxFile 128
+#define kPathMax 128
+#define kDimMax 8
+#define kWayMax 10
+#define kPocketMax 4
+#define kCaveMax 100
+#define kMaxPoint 4
+#define kInfoX 160
+#define kInfoY -11
+#define kInfoW 180
+
+enum CallbackType {
+ kNullCB = 0, kQGame, kMiniStep, kXScene, kSoundSetVolume
+};
+
+enum Action { kNear, kMTake, kFTake, kActions };
+
+class Font {
+ char _path[kPathMax];
+ void load();
+ CGE2Engine *_vm;
+public:
+ uint8 *_widthArr;
+ uint16 *_pos;
+ uint8 *_map;
+ Font(CGE2Engine *vm, const char *name);
+ ~Font();
+ uint16 width(const char *text);
+ void save();
+};
+
+class CGE2Engine : public Engine {
+private:
+ uint32 _lastFrame, _lastTick;
+ void tick();
+public:
+ CGE2Engine(OSystem *syst, const ADGameDescription *gameDescription);
+ virtual bool hasFeature(EngineFeature f) const;
+ virtual bool canLoadGameStateCurrently();
+ virtual bool canSaveGameStateCurrently();
+ virtual Common::Error loadGameState(int slot);
+ virtual Common::Error saveGameState(int slot, const Common::String &desc);
+ virtual Common::Error run();
+
+ bool showTitle(const char *name);
+ void cge2_main();
+ char *mergeExt(char *buf, const char *name, const char *ext);
+ void inf(const char *text, bool wideSpace = false);
+ void movie(const char *ext);
+ void runGame();
+ void loadScript(const char *fname);
+ void loadSprite(const char *fname, int ref, int scene, V3D &pos);
+ void badLab(const char *fn);
+ void caveUp(int cav);
+ void switchCave(int cav);
+ void showBak(int ref);
+ void loadTab();
+ int newRandom(int range);
+ void loadMap(int cav);
+ void openPocket();
+ void selectPocket(int n);
+ void busy(bool on);
+ void feedSnail(Sprite *spr, Action snq, Hero *hero);
+ int freePockets(int sx);
+ int findActivePocket(int ref);
+ void pocFul();
+ void killText();
+ void mainLoop();
+ void handleFrame();
+ Sprite *locate(int ref);
+ bool isHero(Sprite *spr);
+ void loadUser();
+ void checkSaySwitch();
+ void qGame();
+ void loadPos();
+ void releasePocket(Sprite *spr);
+ void switchHero(bool sex);
+
+ void setEye(V3D &e);
+ void setEye(const V2D& e2, int z = -kScrWidth);
+ void setEye(const char *s);
+
+ int number(char *s);
+ char *token(char *s);
+ char *tail(char *s);
+ int takeEnum(const char **tab, const char *text);
+ ID ident(const char *s);
+ bool testBool(char *s);
+
+ void snKill(Sprite *spr);
+ void snHide(Sprite *spr, int val);
+ void snMidi(int val);
+ void snSetDlg(int clr, int set);
+ void snMskDlg(int clr, int set);
+ void snSeq(Sprite *spr, int val);
+ void snRSeq(Sprite *spr, int val);
+ void snSend(Sprite *spr, int val);
+ void snSwap(Sprite *spr, int val);
+ void snCover(Sprite *spr, int val);
+ void snUncover(Sprite *spr, Sprite *spr2);
+ void snFocus(int val);
+ void snKeep(Sprite *spr, int val);
+ void snGive(Sprite *spr, int val);
+ void snGoto(Sprite *spr, int val);
+ void snMove(Sprite *spr, V3D pos);
+ void snSlave(Sprite *spr, int val);
+ void snTrans(Sprite *spr, int val);
+ void snPort(Sprite *spr, int val);
+ void snMouse(int val);
+ void snNNext(Sprite *spr, Action act, int val);
+ void snRNNext(Sprite *spr, int val);
+ void snRMTNext(Sprite *spr, int val);
+ void snRFTNext(Sprite *spr, int val);
+ void snRmNear(Sprite *spr);
+ void snRmMTake(Sprite *spr);
+ void snRmFTake(Sprite *spr);
+ void snFlag(int ref, int val);
+ void snSetRef(Sprite *spr, int val);
+ void snBackPt(Sprite *spr, int val);
+ void snFlash(int val);
+ void snLight(int val);
+ void snWalk(Sprite *spr, int val);
+ void snReach(Sprite *spr, int val);
+ void snSound(Sprite *spr, int wav);
+ void snRoom(Sprite *spr, int val);
+ void snGhost(Bitmap *bmp);
+
+ void hide1(Sprite *spr);
+
+ const ADGameDescription *_gameDescription;
+
+ Common::RandomSource _randomSource;
+
+ bool _quitFlag;
+ Dac *_bitmapPalette;
+ int _mode;
+ bool _music;
+ int _startupMode;
+ int _now;
+ bool _sex;
+ int _mouseTop;
+ bool _dark;
+ int _waitSeq;
+ int _waitRef;
+ struct CommandStat {
+ int *_wait;
+ int _ref[2];
+ } _commandStat;
+ bool _taken;
+ bool _endGame;
+ bool _flag[4];
+
+ ResourceManager *_resman;
+ Vga *_vga;
+ Sprite *_sprite;
+ MusicPlayer *_midiPlayer;
+ Fx *_fx;
+ Sound *_sound;
+ Text *_text;
+ HeroTab *_heroTab[2];
+ V3D *_eye;
+ V3D *_eyeTab[kCaveMax];
+ Spare *_spare;
+ CommandHandler *_commandHandler;
+ CommandHandler *_commandHandlerTurbo;
+ InfoLine *_infoLine;
+ Mouse *_mouse;
+ Keyboard *_keyboard;
+ Talk *_talk;
+ V3D *_point[kMaxPoint];
+ System *_sys;
+ Sprite *_busyPtr;
+ Sprite *_vol[2];
+private:
+ void init();
+ void deinit();
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_H
diff --git a/engines/cge2/cge2_main.cpp b/engines/cge2/cge2_main.cpp
new file mode 100644
index 0000000000..9e9d6da76a
--- /dev/null
+++ b/engines/cge2/cge2_main.cpp
@@ -0,0 +1,759 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "sound.h"
+#include "cge2/cge2_main.h"
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+#include "cge2/text.h"
+#include "cge2/snail.h"
+#include "cge2/hero.h"
+#include "cge2/spare.h"
+#include "cge2/events.h"
+
+namespace CGE2 {
+
+System::System(CGE2Engine *vm) : Sprite(vm), _vm(vm) {
+ warning("STUB: System::System()");
+}
+
+void System::touch(uint16 mask, int x, int y, Common::KeyCode keyCode) {
+ warning("STUB: System::touch()");
+}
+
+void System::tick() {
+ warning("STUB: System::tick()");
+}
+
+int CGE2Engine::number(char *s) { // TODO: Rework it later to include the preceding token() call!
+ int r = atoi(s);
+ char *pp = strchr(s, ':');
+ if (pp)
+ r = (r << 8) + atoi(pp + 1);
+ return r;
+}
+
+char *CGE2Engine::token(char *s) {
+ return strtok(s, " =\t,;/()");
+}
+
+char *CGE2Engine::tail(char *s) {
+ if (s && (*s == '='))
+ s++;
+ return s;
+}
+
+int CGE2Engine::takeEnum(const char **tab, const char *text) {
+ if (text) {
+ for (const char **e = tab; *e; e++) {
+ if (scumm_stricmp(text, *e) == 0) {
+ return e - tab;
+ }
+ }
+ }
+ return -1;
+}
+
+ID CGE2Engine::ident(const char *s) {
+ return ID(takeEnum(EncryptedStream::kIdTab, s));
+}
+
+bool CGE2Engine::testBool(char *s) {
+ return number(s) != 0;
+}
+
+void CGE2Engine::badLab(const char *fn) {
+ error("Misplaced label in %s!", fn);
+}
+
+void CGE2Engine::loadSprite(const char *fname, int ref, int scene, V3D &pos) {
+ int shpcnt = 0;
+ int seqcnt = 0;
+ int cnt[kActions];
+ for (int i = 0; i < kActions; i++)
+ cnt[i] = 0;
+ ID section = kIdPhase;
+ bool frnt = true;
+ bool east = false;
+ bool port = false;
+ bool tran = false;
+ Hero *h;
+ ID id;
+
+ char tmpStr[kLineMax + 1];
+ mergeExt(tmpStr, fname, kSprExt);
+
+ if (_resman->exist(tmpStr)) { // sprite description file exist
+ EncryptedStream sprf(this, tmpStr);
+ if (sprf.err())
+ error("Bad SPR [%s]", tmpStr);
+
+ int label = kNoByte;
+ Common::String line;
+
+ for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()){
+ if (line.size() == 0)
+ continue;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *p;
+ p = token(tmpStr);
+ if (*p == '@') {
+ if (label != kNoByte)
+ badLab(fname);
+ label = atoi(p + 1);
+ continue;
+ }
+
+ id = ident(p);
+ switch (id) {
+ case kIdName: // will be taken in Expand routine
+ if (label != kNoByte)
+ badLab(fname);
+ break;
+ case kIdType:
+ if (label != kNoByte)
+ badLab(fname);
+ break;
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ case kIdPhase:
+ case kIdSeq:
+ if (label != kNoByte)
+ badLab(fname);
+ section = id;
+ break;
+ case kIdFront:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ frnt = testBool(p);
+ break;
+ case kIdEast:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ east = testBool(p);
+ break;
+ case kIdPortable:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ port = testBool(p);
+ break;
+ case kIdTransparent:
+ if (label != kNoByte)
+ badLab(fname);
+ p = token(nullptr);
+ tran = testBool(p);
+ break;
+ default:
+ if (id >= kIdNear)
+ break;
+ switch (section) {
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ if (_commandHandler->com(p) >= 0)
+ ++cnt[section];
+ else
+ error("Bad line %d [%s]", sprf.getLineCount(), tmpStr);
+ break;
+ case kIdPhase:
+ if (label != kNoByte)
+ badLab(fname);
+ ++shpcnt;
+ break;
+ case kIdSeq:
+ if (label != kNoByte)
+ badLab(fname);
+ ++seqcnt;
+ break;
+ }
+ break;
+ }
+ label = kNoByte;
+ }
+
+ if (!shpcnt) {
+ error("No shapes - %s", fname);
+ }
+ } else // No sprite description: mono-shaped sprite with only .BMP file.
+ ++shpcnt;
+
+ // Make sprite of choosen type:
+ char c = *fname | 0x20;
+ if (c >= 'a' && c <= 'z' && fname[1] == '0' && fname[2] == '\0') {
+ h = new Hero(this);
+ if (h) {
+ h->gotoxyz(pos);
+ _sprite = h;
+ }
+ } else {
+ if (_sprite)
+ delete _sprite;
+ _sprite = new Sprite(this);
+ if (_sprite)
+ _sprite->gotoxyz(pos);
+ }
+
+ if (_sprite) {
+ _sprite->_ref = ref;
+ _sprite->_scene = scene;
+
+ _sprite->_flags._frnt = frnt;
+ _sprite->_flags._east = east;
+ _sprite->_flags._port = port;
+ _sprite->_flags._tran = tran;
+ _sprite->_flags._kill = true;
+
+ // Extract the filename, without the extension
+ Common::strlcpy(_sprite->_file, fname, sizeof(_sprite->_file));
+ char *p = strchr(_sprite->_file, '.');
+ if (p)
+ *p = '\0';
+
+ _sprite->_shpCnt = shpcnt;
+ _sprite->_seqCnt = seqcnt;
+
+ for (int i = 0; i < kActions; i++)
+ _sprite->_actionCtrl[i]._cnt = cnt[i];
+ }
+}
+
+void CGE2Engine::loadScript(const char *fname) {
+ EncryptedStream scrf(this, fname);
+
+ if (scrf.err())
+ return;
+
+ bool ok = true;
+ int lcnt = 0;
+
+ char tmpStr[kLineMax + 1];
+ Common::String line;
+
+ for (line = scrf.readLine(); !scrf.eos(); line = scrf.readLine()) {
+ if (line.size() == 0)
+ continue;
+
+ char *p;
+
+ lcnt++;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ ok = false; // not OK if break
+
+ V3D P;
+
+ // sprite ident number
+ if ((p = token(tmpStr)) == NULL)
+ break;
+ int SpI = number(p);
+
+ // sprite file name
+ char *SpN;
+ if ((SpN = token(nullptr)) == NULL)
+ break;
+
+ // sprite scene
+ if ((p = token(nullptr)) == NULL)
+ break;
+ int SpA = number(p);
+
+ // sprite column
+ if ((p = token(nullptr)) == NULL)
+ break;
+ P._x = number(p);
+
+ // sprite row
+ if ((p = token(nullptr)) == NULL)
+ break;
+ P._y = number(p);
+
+ // sprite Z pos
+ if ((p = token(nullptr)) == NULL)
+ break;
+ P._z = number(p);
+
+ // sprite life
+ if ((p = token(nullptr)) == NULL)
+ break;
+ bool BkG = number(p) == 0;
+
+ ok = true; // no break: OK
+
+ _sprite = NULL;
+ loadSprite(SpN, SpI, SpA, P);
+ if (_sprite) {
+ if (BkG)
+ _sprite->_flags._back = true;
+
+ int n = _spare->count();
+ if (_spare->locate(_sprite->_ref) == nullptr)
+ _spare->store(_sprite);
+ _sprite = nullptr;
+ if (_spare->count() == n)
+ error("Durplicated reference! %s", SpN);
+ }
+ }
+
+ if (!ok)
+ error("Bad INI line %d [%s]", scrf.getLineCount(), fname);
+}
+
+void CGE2Engine::movie(const char *ext) {
+ assert(ext);
+
+ if (_quitFlag)
+ return;
+
+ char fn[12];
+ sprintf(fn, "CGE.%s", (*ext == '.') ? ext + 1 : ext);
+
+ if (_resman->exist(fn)) {
+ int now = _now;
+ _now = atoi(ext + 2);
+ loadScript(fn);
+ caveUp(_now);
+
+ while (!_commandHandler->idle() && !_quitFlag)
+ mainLoop();
+
+ warning("STUB: CGE2Engine::movie()");
+
+ _commandHandler->addCommand(kCmdClear, -1, 0, nullptr);
+ _commandHandlerTurbo->addCommand(kCmdClear, -1, 0, nullptr);
+ _vga->_showQ->clear();
+ _spare->clear();
+ _now = now;
+ }
+}
+
+void CGE2Engine::caveUp(int cav) {
+ _now = cav;
+ int bakRef = _now << 8;
+ if (_music)
+ _midiPlayer->loadMidi(bakRef);
+ showBak(bakRef);
+ _eye = _eyeTab[_now];
+ _mouseTop = V2D(this, V3D(0, 1, kScrDepth)).y;
+ _spare->takeCave(_now);
+ openPocket();
+
+ warning("STUB: CGE2Engine::caveUp()");
+ // TODO: Implement "Hero" things here!
+
+ _sound->stop();
+ _fx->clear();
+
+ selectPocket(-1);
+ _infoLine->setText(nullptr);
+ busy(false);
+
+ if (!_dark)
+ _vga->sunset();
+ _vga->show();
+ _vga->copyPage(1, 0);
+ _vga->show();
+
+ _sprite = _vga->_showQ->first();
+ _vga->sunrise(_vga->_sysPal);
+
+ feedSnail(_vga->_showQ->locate(bakRef + 255), kNear, _heroTab[_sex]->_ptr);
+ //setDrawColors(); - It's only for debugging purposes. Can be left out for now.
+}
+
+void CGE2Engine::switchCave(int cav) {
+ warning("STUB: CGE2Engine::switchCave()");
+}
+
+void CGE2Engine::showBak(int ref) {
+ Sprite *spr = _spare->locate(ref);
+ if (spr != nullptr) {
+ _bitmapPalette = _vga->_sysPal;
+ spr->expand();
+ _bitmapPalette = NULL;
+ spr->show(2);
+ _vga->copyPage(1, 2);
+ _spare->dispose(spr);
+ }
+}
+
+void CGE2Engine::mainLoop() {
+ _vga->show();
+ _commandHandlerTurbo->runCommand();
+ _commandHandler->runCommand();
+
+ // Handle a delay between game frames
+ handleFrame();
+
+ // Handle any pending events
+ //_eventManager->poll();
+ warning("STUB: CGE2Engine::mainLoop() - Event handling is missing!");
+
+ // Check shouldQuit()
+ _quitFlag = shouldQuit();
+}
+
+void CGE2Engine::handleFrame() {
+ // Game frame delay
+ uint32 millis = g_system->getMillis();
+ while (!_quitFlag && (millis < (_lastFrame + kGameFrameDelay))) {
+ // Handle any pending events
+ //_eventManager->poll();
+ warning("STUB: CGE2Engine::handleFrame() - Event handling is missing!");
+
+ if (millis >= (_lastTick + kGameTickDelay)) {
+ // Dispatch the tick to any active objects
+ tick();
+ _lastTick = millis;
+ }
+
+ // Slight delay
+ g_system->delayMillis(5);
+ millis = g_system->getMillis();
+ }
+ _lastFrame = millis;
+
+ if (millis >= (_lastTick + kGameTickDelay)) {
+ // Dispatch the tick to any active objects
+ tick();
+ _lastTick = millis;
+ }
+}
+
+Sprite *CGE2Engine::locate(int ref) {
+ _taken = false;
+ Sprite *spr = _vga->_showQ->locate(ref);
+ if (!spr) {
+ spr = _spare->locate(ref);
+ if (spr)
+ _taken = true;
+ }
+ return spr;
+}
+
+bool CGE2Engine::isHero(Sprite *spr) {
+ return spr && spr->_ref / 10 == 14;
+}
+
+void CGE2Engine::tick() {
+ for (Sprite *spr = _vga->_showQ->first(); spr; spr = spr->_next) {
+ if (spr->_time) {
+ if (--spr->_time == 0)
+ spr->tick();
+ }
+ if (_waitRef) {
+ if (_waitRef == _sprite->_ref)
+ if (spr->seqTest(_waitSeq))
+ _waitRef = 0;
+ }
+ }
+
+ //Mouse->Tick();
+ warning("STUB: CGE2Engine::tick() - Mouse");
+}
+
+void CGE2Engine::loadMap(int cav) {
+ warning("STUB: CGE2Engine::loadMap()");
+}
+
+void CGE2Engine::openPocket() {
+ warning("STUB: CGE2Engine::openPocket()");
+}
+
+void CGE2Engine::selectPocket(int n) {
+ warning("STUB: CGE2Engine::selectPocket()");
+}
+
+void CGE2Engine::busy(bool on) {
+ warning("STUB: CGE2Engine::selectPocket()");
+}
+
+void CGE2Engine::runGame() {
+ if (_quitFlag)
+ return;
+
+ selectPocket(-1);
+
+ loadUser();
+
+ _commandHandlerTurbo->addCommand(kCmdSeq, kMusicRef, _music, nullptr);
+ if (!_music)
+ _midiPlayer->killMidi();
+
+ checkSaySwitch();
+
+ _infoLine->gotoxyz(V3D(kInfoX, kInfoY, 0));
+ _infoLine->setText(nullptr);
+ //_vga->_showQ->insert(_infoLine);
+ warning("STUB: CGE2Engine::runGame() - Info Line is missing!");
+
+ caveUp(_now);
+ _startupMode = 0;
+ _mouse->center();
+ _mouse->off();
+ _mouse->on();
+
+ _keyboard->setClient(_sys);
+ _commandHandler->addCommand(kCmdSeq, kPowerRef, 1, nullptr);
+
+ _busyPtr = _vga->_showQ->locate(kBusyRef);
+
+ _vol[0] = _vga->_showQ->locate(kDvolRef);
+ _vol[1] = _vga->_showQ->locate(kMvolRef);
+
+ // these sprites are loaded with SeqPtr==0 (why?!)
+ if (_vol[0])
+ _vol[0]->step((/*(int)SNDDrvInfo.VOL4.DL * */ _vol[0]->_seqCnt + _vol[0]->_seqCnt / 2) >> 4);
+ if (_vol[1])
+ _vol[1]->step((/*(int)SNDDrvInfo.VOL4.ML * */ _vol[1]->_seqCnt + _vol[1]->_seqCnt / 2) >> 4);
+ // TODO: Recheck these! ^
+
+ // main loop
+ while (!_endGame && !_quitFlag) {
+ if (_flag[3]) // Flag FINIS
+ _commandHandler->addCallback(kCmdExec, -1, 0, kQGame);
+ mainLoop();
+ }
+
+ // If finishing game due to closing ScummVM window, explicitly save the game
+ if (!_endGame && canSaveGameStateCurrently())
+ qGame();
+
+ _keyboard->setClient(nullptr);
+ _commandHandler->addCommand(kCmdClear, -1, 0, nullptr);
+ _commandHandlerTurbo->addCommand(kCmdClear, -1, 0, nullptr);
+ _mouse->off();
+ _vga->_showQ->clear();
+ _vga->_spareQ->clear();
+}
+
+void CGE2Engine::loadUser() {
+ warning("STUB: CGE2Engine::loadUser()");
+ // Missing loading from file. TODO: Implement it with the saving/loading!
+ loadScript("CGE.INI");
+ loadPos();
+}
+
+void CGE2Engine::loadPos() {
+ if (_resman->exist("CGE.HXY")) {
+ for (int cav = 0; cav < kCaveMax; cav++)
+ _heroTab[1]->_posTab[cav] = new V2D(this, 180, 10);
+
+ EncryptedStream file(this, "CGE.HXY");
+
+ for (int cav = 0; cav < kCaveMax; cav++) {
+ _heroTab[0]->_posTab[cav]->x = file.readSint16LE();
+ _heroTab[0]->_posTab[cav]->y = file.readSint16LE();
+ }
+
+ for (int cav = 0; cav < 41; cav++) { // (564 - 400) / 4 = 41
+ _heroTab[1]->_posTab[cav]->x = file.readSint16LE();
+ _heroTab[1]->_posTab[cav]->y = file.readSint16LE();
+ }
+ } else
+ error("Missing file: CGE.HXY");
+}
+
+void CGE2Engine::releasePocket(Sprite *spr) {
+ warning("STUB: CGE2Engine::releasePocket()");
+}
+
+void CGE2Engine::checkSaySwitch() {
+ warning("STUB: CGE2Engine::checkSaySwitch()");
+}
+
+void CGE2Engine::qGame() {
+ warning("STUB: CGE2Engine::qGame()");
+ _endGame = true;
+}
+
+void CGE2Engine::loadTab() {
+ setEye(_text->getText(240));
+ for (int i = 0; i < kCaveMax; i++)
+ _eyeTab[i] = _eye;
+
+ if (_resman->exist(kTabName)) {
+ EncryptedStream f(this, kTabName);
+ for (int i = 0; i < kCaveMax; i++) {
+ for (int j = 0; j < 3; j++) {
+ signed b = f.readSint16BE();
+ unsigned a = f.readUint16BE();
+ uint16 round = uint16((long(a) << 16) / 100);
+
+ if (round > 0x7FFF)
+ b++;
+
+ switch (j) {
+ case 0:
+ _eyeTab[i]->_x = b;
+ break;
+ case 1:
+ _eyeTab[i]->_y = b;
+ break;
+ case 2:
+ _eyeTab[i]->_z = b;
+ break;
+ }
+
+ }
+ }
+ }
+
+ warning("STUB: CGE2Engine::loadTab() - Recheck this");
+}
+
+void CGE2Engine::cge2_main() {
+ warning("STUB: CGE2Engine::cge2_main()");
+
+ loadTab();
+
+ _mode++;
+
+ if (showTitle("WELCOME")) {
+#if 0
+ if (_mode == 1)
+ movie(kIntroExt);
+#endif
+ if (_text->getText(255) != NULL) {
+ runGame();
+ _startupMode = 2;
+ } else
+ _vga->sunset();
+ } else
+ _vga->sunset();
+}
+
+char *CGE2Engine::mergeExt(char *buf, const char *name, const char *ext) {
+ strcpy(buf, name);
+ char *dot = strrchr(buf, '.');
+ if (!dot)
+ strcat(buf, ext);
+
+ return buf;
+}
+
+void CGE2Engine::setEye(V3D &e) {
+ _eye = &e;
+}
+
+void CGE2Engine::setEye(const V2D& e2, int z) {
+ _eye->_x = e2.x;
+ _eye->_y = e2.y;
+ _eye->_z = z;
+}
+
+void CGE2Engine::setEye(const char *s) {
+ char tempStr[kLineMax];
+ strcpy(tempStr, s);
+ _eye->_x = atoi(token(tempStr));
+ _eye->_y = atoi(token(NULL));
+ _eye->_z = atoi(token(NULL));
+}
+
+int CGE2Engine::newRandom(int range) {
+ if (!range)
+ return 0;
+
+ return _randomSource.getRandomNumber(range - 1);
+}
+
+bool CGE2Engine::showTitle(const char *name) {
+ if (_quitFlag)
+ return false;
+
+ _bitmapPalette = _vga->_sysPal;
+ BitmapPtr *LB = new BitmapPtr[2];
+ LB[0] = new Bitmap(this, name);
+ LB[1] = NULL;
+ _bitmapPalette = NULL;
+
+ Sprite D(this, LB, 1);
+ D._flags._kill = true;
+ warning("STUB: Sprite::showTitle() - Flags changed compared to CGE1's Sprite type.");
+ D.gotoxyz(kScrWidth >> 1, -(kPanHeight >> 1));
+ _vga->sunset();
+
+ D.show(2);
+
+ _vga->copyPage(1, 2);
+ _vga->copyPage(0, 1);
+
+ _vga->sunrise(_vga->_sysPal);
+
+ _vga->update();
+
+ warning("STUB: CGE2Engine::showTitle()");
+
+ return true;
+}
+
+int CGE2Engine::freePockets(int sx) {
+ int n = 0;
+ for (int i = 0; i < kPocketMax; i++){
+ if (_heroTab[sx]->_pocket[i] == nullptr)
+ ++n;
+ }
+ return n;
+}
+
+int CGE2Engine::findActivePocket(int ref) {
+ for (int i = 0; i < kPocketMax; i++) {
+ Sprite *spr = _heroTab[_sex]->_pocket[i];
+ if (ref >= 0) {
+ if (spr && spr->_ref == ref)
+ return i;
+ } else if (!spr)
+ return i;
+ }
+ return -1;
+}
+
+void CGE2Engine::pocFul() {
+ Hero *h = _heroTab[_sex]->_ptr;
+ h->park();
+ _commandHandler->addCommand(kCmdWait, -1, -1, h);
+ _commandHandler->addCommand(kCmdSound, -1, 2, h);
+ _commandHandler->addCommand(kCmdSay, -1, kPocketFull + _sex, h);
+}
+
+void CGE2Engine::killText() {
+ if (!_talk)
+ return;
+
+ _commandHandlerTurbo->addCommand(kCmdKill, -1, 0, _talk);
+ _talk = NULL;
+}
+
+void CGE2Engine::switchHero(bool sex) {
+ warning("STUB: CGE2Engine::switchHero()");
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/cge2_main.h b/engines/cge2/cge2_main.h
new file mode 100644
index 0000000000..272cdf79d5
--- /dev/null
+++ b/engines/cge2/cge2_main.h
@@ -0,0 +1,67 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_MAIN_H
+#define CGE2_MAIN_H
+
+#include "cge2/events.h"
+
+namespace CGE2 {
+
+#define kLineMax 512
+#define kIntroExt ".I80"
+#define kTabName "CGE.TAB"
+#define kPocketFull 170
+#define kGameFrameDelay (750 / 50)
+#define kGameTickDelay (750 / 62)
+
+#define kMusicRef 122
+#define kPowerRef 123
+#define kDvolRef 124
+#define kMvolRef 125
+#define kRef 126
+#define kBusyRef 127
+#define kCapRef 128
+#define kVoxRef 129
+
+class System : public Sprite {
+public:
+ int _funDel;
+ int _blinkCounter;
+ Sprite *_blinkSprite;
+
+ System(CGE2Engine *vm);
+
+ virtual void touch(uint16 mask, int x, int y, Common::KeyCode keyCode);
+ void tick();
+private:
+ CGE2Engine *_vm;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_MAIN_H
diff --git a/engines/cge2/configure.engine b/engines/cge2/configure.engine
new file mode 100644
index 0000000000..6ccbfee088
--- /dev/null
+++ b/engines/cge2/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine cge2 "CGE2" no
diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp
new file mode 100644
index 0000000000..9c63af1ec6
--- /dev/null
+++ b/engines/cge2/detection.cpp
@@ -0,0 +1,87 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/cge2.h"
+#include "engines/advancedDetector.h"
+
+namespace CGE2 {
+
+static const PlainGameDescriptor CGE2Games[] = {
+ { "sfinx", "Sfinx" },
+ { 0, 0 }
+};
+
+static const ADGameDescription gameDescriptions[] = { // TODO: Add ENG version too.
+ {
+ "sfinx", "Sfinx Freeware",
+ {
+ { "vol.cat", 0, "21197b287d397c53261b6616bf0dd880", 129024 },
+ { "vol.dat", 0, "de14291869a8eb7c2732ab783c7542ef", 34180844 },
+ AD_LISTEND
+ },
+ Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0()
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+class CGE2MetaEngine : public AdvancedMetaEngine {
+public:
+ CGE2MetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), CGE2Games) {
+ _singleid = "sfinx";
+ }
+
+ virtual const char *getName() const {
+ return "CGE2";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Sfinx (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon";
+ }
+
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
+};
+
+bool CGE2MetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc) {
+ *engine = new CGE2::CGE2Engine(syst, desc);
+ }
+ return desc != 0;
+}
+
+bool CGE2MetaEngine::hasFeature(MetaEngineFeature f) const {
+ return false;
+}
+
+} // End of namespace CGE2
+
+#if PLUGIN_ENABLED_DYNAMIC(CGE2)
+ REGISTER_PLUGIN_DYNAMIC(CGE2, PLUGIN_TYPE_ENGINE, CGE2::CGE2MetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(CGE2, PLUGIN_TYPE_ENGINE, CGE2::CGE2MetaEngine);
+#endif
diff --git a/engines/cge2/events.cpp b/engines/cge2/events.cpp
new file mode 100644
index 0000000000..670ea61c93
--- /dev/null
+++ b/engines/cge2/events.cpp
@@ -0,0 +1,85 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "gui/saveload.h"
+#include "gui/about.h"
+#include "gui/message.h"
+#include "common/config-manager.h"
+#include "common/events.h"
+#include "engines/advancedDetector.h"
+#include "cge2/events.h"
+#include "cge2/text.h"
+#include "cge2/cge2_main.h"
+
+namespace CGE2 {
+
+/*----------------- KEYBOARD interface -----------------*/
+
+Keyboard::Keyboard(CGE2Engine *vm) : _client(NULL), _vm(vm) {
+ warning("STUB: Keyboard::Keyboard() - Recheck the whole implementation!!!");
+}
+
+Keyboard::~Keyboard() {
+}
+
+Sprite *Keyboard::setClient(Sprite *spr) {
+ warning("STUB: Keyboard::setClient()");
+ return spr;
+}
+
+bool Keyboard::getKey(Common::Event &event) {
+ warning("STUB: Keyboard::getKey()");
+ return false;
+}
+
+void Keyboard::newKeyboard(Common::Event &event) {
+ warning("STUB: Keyboard::newKeyboard()");
+}
+
+/*----------------- MOUSE interface -----------------*/
+
+Mouse::Mouse(CGE2Engine *vm) : Sprite(vm), _busy(NULL), _hold(NULL), _hx(0), _vm(vm) {
+ warning("STUB: Mouse::Mouse() - Recheck the whole implementation!!!");
+}
+
+Mouse::~Mouse() {
+ warning("STUB: Mouse::~Mouse()");
+}
+
+void Mouse::on() {
+ warning("STUB: Mouse::on()");
+}
+
+void Mouse::off() {
+ warning("STUB: Mouse::off()");
+}
+
+void Mouse::newMouse(Common::Event &event) {
+ warning("STUB: Mouse::newMouse()");
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/events.h b/engines/cge2/events.h
new file mode 100644
index 0000000000..99f017bae3
--- /dev/null
+++ b/engines/cge2/events.h
@@ -0,0 +1,88 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_EVENTS_H
+#define CGE2_EVENTS_H
+
+#include "common/events.h"
+#include "cge2/talk.h"
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+/*----------------- KEYBOARD interface -----------------*/
+
+#define kEventMax 256
+
+enum EventMask {
+ kMouseRoll = 1 << 0,
+ kMouseLeftDown = 1 << 1,
+ kMouseLeftUp = 1 << 2,
+ kMouseRightDown = 1 << 3,
+ kMouseRightUp = 1 << 4,
+ kEventAttn = 1 << 5,
+ kEventKeyb = 1 << 7
+};
+
+class Keyboard {
+private:
+ bool getKey(Common::Event &event);
+ CGE2Engine *_vm;
+public:
+ Sprite *_client;
+ bool _keyAlt;
+
+ void newKeyboard(Common::Event &event);
+ Sprite *setClient(Sprite *spr);
+
+ Keyboard(CGE2Engine *vm);
+ ~Keyboard();
+};
+
+/*----------------- MOUSE interface -----------------*/
+
+class Mouse : public Sprite {
+public:
+ Sprite *_hold;
+ bool _active;
+ int _hx;
+ int _hy;
+ bool _exist;
+ int _buttons;
+ Sprite *_busy;
+ Mouse(CGE2Engine *vm);
+ ~Mouse();
+ void on();
+ void off();
+ void newMouse(Common::Event &event);
+private:
+ CGE2Engine *_vm;
+};
+
+} // End of namespace CGE
+
+#endif // #define CGE2_EVENTS_H
diff --git a/engines/cge2/fileio.cpp b/engines/cge2/fileio.cpp
new file mode 100644
index 0000000000..4fec4a67ca
--- /dev/null
+++ b/engines/cge2/fileio.cpp
@@ -0,0 +1,270 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "common/system.h"
+#include "common/str.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/memstream.h"
+#include "cge2/cge2.h"
+#include "cge2/fileio.h"
+
+namespace CGE2 {
+
+/*-----------------------------------------------------------------------
+ * BtPage
+ *-----------------------------------------------------------------------*/
+void BtPage::readBTree(Common::ReadStream &s) {
+ _header._count = s.readUint16LE();
+ _header._down = s.readUint16LE();
+
+ if (_header._down == kBtValNone) {
+ // Leaf list
+ for (int i = 0; i < kBtLeafCount; ++i) {
+ s.read(_leaf[i]._key, kBtKeySize);
+ _leaf[i]._pos = s.readUint32LE();
+ _leaf[i]._size = s.readUint32LE();
+ }
+ } else {
+ // Root index
+ for (int i = 0; i < kBtInnerCount; ++i) {
+ s.read(_inner[i]._key, kBtKeySize);
+ _inner[i]._down = s.readUint16LE();
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ * ResourceManager
+ *-----------------------------------------------------------------------*/
+ResourceManager::ResourceManager() {
+ _datFile = new Common::File();
+ _datFile->open(kDatName);
+
+ _catFile = new Common::File();
+ _catFile->open(kCatName);
+
+ if (!_datFile->isOpen() || !_catFile->isOpen())
+ error("Unable to open data files");
+
+ for (int i = 0; i < kBtLevel; i++) {
+ _buff[i]._page = new BtPage;
+ _buff[i]._pageNo = kBtValNone;
+ _buff[i]._index = -1;
+ assert(_buff[i]._page != NULL);
+ }
+}
+
+ResourceManager::~ResourceManager() {
+ _datFile->close();
+ delete _datFile;
+
+ _catFile->close();
+ delete _catFile;
+
+ for (int i = 0; i < kBtLevel; i++)
+ delete _buff[i]._page;
+}
+
+void ResourceManager::XCrypt(byte *buf, uint16 length) {
+ byte *b = buf;
+
+ for (uint16 i = 0; i < length; i++)
+ *b++ ^= kCryptSeed;
+}
+
+bool ResourceManager::seek(int32 offs, int whence) {
+ return _datFile->seek(offs, whence);
+}
+
+uint16 ResourceManager::read(byte *buf, uint16 length) {
+ if (!_datFile->isOpen())
+ return 0;
+
+ uint16 bytesRead = _datFile->read(buf, length);
+ if (!bytesRead)
+ error("Read %s - %d bytes", _datFile->getName(), length);
+ XCrypt(buf, length);
+ return bytesRead;
+}
+
+BtPage *ResourceManager::getPage(int level, uint16 pageId) {
+ if (_buff[level]._pageNo != pageId) {
+ int32 pos = pageId * kBtSize;
+ _buff[level]._pageNo = pageId;
+ assert(_catFile->size() > pos);
+ // In the original, there was a check verifying if the
+ // purpose was to write a new file. This should only be
+ // to create a new file, thus it was removed.
+ _catFile->seek(pageId * kBtSize, SEEK_SET);
+
+ // Read in the page
+ byte buffer[kBtSize];
+ int bytesRead = catRead(buffer, kBtSize);
+
+ // Unpack it into the page structure
+ Common::MemoryReadStream stream(buffer, bytesRead, DisposeAfterUse::NO);
+ _buff[level]._page->readBTree(stream);
+ _buff[level]._index = -1;
+ }
+ return _buff[level]._page;
+}
+
+BtKeypack *ResourceManager::find(const char *key) {
+ int lev = 0;
+ uint16 nxt = kBtValRoot;
+ while (!_catFile->eos()) {
+ BtPage *pg = getPage(lev, nxt);
+ // search
+ if (pg->_header._down != kBtValNone) {
+ int i;
+ for (i = 0; i < pg->_header._count; i++) {
+ // Does this work, or does it have to compare the entire buffer?
+ if (scumm_strnicmp((const char *)key, (const char*)pg->_inner[i]._key, kBtKeySize) < 0)
+ break;
+ }
+ nxt = (i) ? pg->_inner[i - 1]._down : pg->_header._down;
+ _buff[lev]._index = i - 1;
+ lev++;
+ } else {
+ int i;
+ for (i = 0; i < pg->_header._count - 1; i++) {
+ if (scumm_stricmp((const char *)key, (const char *)pg->_leaf[i]._key) <= 0)
+ break;
+ }
+ _buff[lev]._index = i;
+ return &pg->_leaf[i];
+ }
+ }
+ return NULL;
+}
+
+bool ResourceManager::exist(const char *name) {
+ return scumm_stricmp(find(name)->_key, name) == 0;
+}
+
+uint16 ResourceManager::catRead(byte *buf, uint16 length) {
+ if (!_catFile->isOpen())
+ return 0;
+
+ uint16 bytesRead = _catFile->read(buf, length);
+ if (!bytesRead)
+ error("Read %s - %d bytes", _catFile->getName(), length);
+ XCrypt(buf, length);
+ return bytesRead;
+}
+
+/*-----------------------------------------------------------------------
+ * EncryptedStream
+ *-----------------------------------------------------------------------*/
+EncryptedStream::EncryptedStream(CGE2Engine *vm, const char *name) : _vm(vm), _lineCount(0) {
+ _error = false;
+ BtKeypack *kp = _vm->_resman->find(name);
+ if (scumm_stricmp(kp->_key, name) != 0)
+ _error = true;
+
+ _vm->_resman->seek(kp->_pos);
+ byte *dataBuffer;
+ int bufSize;
+
+ if ((strlen(name) > 4) && (scumm_stricmp(name + strlen(name) - 4, ".SPR") == 0)) {
+ // SPR files have some inconsistencies. Some have extra 0x1A at the end, some others
+ // do not have a carriage return at the end of the last line
+ // Therefore, we remove this ending 0x1A and add extra new lines.
+ // This fixes bug #3537527
+ dataBuffer = (byte *)malloc(kp->_size + 2);
+ _vm->_resman->read(dataBuffer, kp->_size);
+ if (dataBuffer[kp->_size - 1] == 0x1A)
+ dataBuffer[kp->_size - 1] = '\n';
+ dataBuffer[kp->_size] = '\n';
+ dataBuffer[kp->_size + 1] = '\n';
+ bufSize = kp->_size + 2;
+ } else {
+ dataBuffer = (byte *)malloc(kp->_size);
+ _vm->_resman->read(dataBuffer, kp->_size);
+ bufSize = kp->_size;
+ }
+
+ _readStream = new Common::MemoryReadStream(dataBuffer, bufSize, DisposeAfterUse::YES);
+}
+
+uint32 EncryptedStream::read(byte *dataPtr, uint32 dataSize) {
+ return _readStream->read(dataPtr, dataSize);
+}
+
+unsigned EncryptedStream::readUint16BE() {
+ return _readStream->readUint16BE();
+}
+
+signed EncryptedStream::readSint16BE() {
+ return _readStream->readSint16BE();
+}
+
+signed EncryptedStream::readSint16LE() {
+ return _readStream->readSint16LE();
+}
+
+bool EncryptedStream::err() {
+ return (_error & _readStream->err());
+}
+
+bool EncryptedStream::eos() {
+ return _readStream->eos();
+}
+
+bool EncryptedStream::seek(int32 offset) {
+ return _readStream->seek(offset);
+}
+
+Common::String EncryptedStream::readLine() {
+ _lineCount++;
+ Common::String line = _readStream->readLine();
+ if (!line.empty() && (line[0] == ';' || line[0] == '.' || line[0] == '*'))
+ line.clear(); // Returns an empty string, if the line is invalid.
+ return line;
+}
+
+int32 EncryptedStream::size() {
+ return _readStream->size();
+}
+
+int32 EncryptedStream::pos() {
+ return _readStream->pos();
+}
+
+EncryptedStream::~EncryptedStream() {
+ delete _readStream;
+}
+
+const char *EncryptedStream::kIdTab[] = {
+ "[near]", "[mtake]", "[ftake]", "[phase]", "[seq]",
+ "Name", "Type", "Front", "East",
+ "Portable", "Transparent",
+ NULL
+};
+
+} // End of namespace CGE2
diff --git a/engines/cge2/fileio.h b/engines/cge2/fileio.h
new file mode 100644
index 0000000000..83a14560ad
--- /dev/null
+++ b/engines/cge2/fileio.h
@@ -0,0 +1,136 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_FILEIO_H
+#define CGE2_FILEIO_H
+
+#include "common/file.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+
+#define kBtSize 2048
+#define kBtKeySize 13
+#define kBtLevel 2
+#define kBtInnerCount ((kBtSize - 4 /*sizeof(Header) */) / (kBtKeySize + 2 /*sizeof(Inner) */))
+#define kBtLeafCount ((kBtSize - 4 /*sizeof(Header) */) / (kBtKeySize + 4 + 4 /*sizeof(BtKeypack) */))
+#define kBtValNone 0xFFFF
+#define kBtValRoot 0
+#define kCatName "VOL.CAT"
+#define kDatName "VOL.DAT"
+#define kCryptSeed 0xA5
+
+enum ID {
+ kIdNear, kIdMTake, kIdFTake, kIdPhase, kIdSeq,
+ kIdName, kIdType, kIdFront, kIdEast,
+ kIdPortable, kIdTransparent,
+ kIdNone = -1
+};
+
+struct BtKeypack {
+ char _key[kBtKeySize];
+ uint32 _pos;
+ uint32 _size;
+};
+
+struct Inner {
+ uint8 _key[kBtKeySize];
+ uint16 _down;
+};
+
+struct Header {
+ uint16 _count;
+ uint16 _down;
+};
+
+struct BtPage {
+ Header _header;
+ union {
+ // dummy filler to make proper size of union
+ uint8 _data[kBtSize - 4]; /* 4 is the size of struct Header */
+ // inner version of data: key + word-sized page link
+ Inner _inner[kBtInnerCount];
+ // leaf version of data: key + all user data
+ BtKeypack _leaf[kBtLeafCount];
+ };
+
+ void readBTree(Common::ReadStream &s);
+};
+
+class ResourceManager {
+private:
+ struct {
+ BtPage *_page;
+ uint16 _pageNo;
+ int _index;
+ } _buff[kBtLevel];
+
+ BtPage *getPage(int level, uint16 pageId);
+ uint16 catRead(byte *buf, uint16 length);
+ Common::File *_catFile;
+ Common::File *_datFile;
+ void XCrypt(byte *buf, uint16 length);
+public:
+ ResourceManager();
+ ~ResourceManager();
+ uint16 read(byte *buf, uint16 length);
+ bool seek(int32 offs, int whence = SEEK_SET);
+
+ BtKeypack *find(const char *key);
+ bool exist(const char *name);
+};
+
+// TODO: Revise the whole class!
+class EncryptedStream {
+private:
+ CGE2Engine *_vm;
+ Common::SeekableReadStream *_readStream;
+ const char **_tab;
+ int _lineCount;
+ bool _error;
+public:
+ EncryptedStream(CGE2Engine *vm, const char *name);
+ ~EncryptedStream();
+ bool err();
+ bool eos();
+ bool seek(int32 offset);
+ int32 pos();
+ int32 size();
+ uint32 read(byte *dataPtr, uint32 dataSize);
+ unsigned readUint16BE();
+ signed readSint16BE();
+ signed readSint16LE();
+ Common::String readLine();
+ int getLineCount() { return _lineCount; }
+
+ static const char *kIdTab[];
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_FILEIO_H
diff --git a/engines/cge2/general.h b/engines/cge2/general.h
new file mode 100644
index 0000000000..0239402ea3
--- /dev/null
+++ b/engines/cge2/general.h
@@ -0,0 +1,47 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_GENERAL_H
+#define CGE2_GENERAL_H
+
+#include "common/file.h"
+
+namespace CGE2 {
+
+#define SCR_WID_ 320
+
+class CGE2Engine;
+
+struct Dac {
+ uint8 _r;
+ uint8 _g;
+ uint8 _b;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_GENERAL_H
diff --git a/engines/cge2/hero.cpp b/engines/cge2/hero.cpp
new file mode 100644
index 0000000000..3a6d1d2920
--- /dev/null
+++ b/engines/cge2/hero.cpp
@@ -0,0 +1,146 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/hero.h"
+
+namespace CGE2 {
+
+Hero::Hero(CGE2Engine *vm) : Sprite(vm) {
+ warning("STUB: Hero::Hero()");
+}
+
+Sprite *Hero::expand(void) {
+ warning("STUB: Hero::expand()");
+ return this;
+}
+
+void Hero::setCurrent(void) {
+ warning("STUB: Hero::setCurrent()");
+}
+
+void Hero::hStep(void) {
+ warning("STUB: Hero::hStep()");
+}
+
+Sprite *Hero::setContact(void) {
+ warning("STUB: Hero::setContact()");
+ return this;
+}
+
+void Hero::tick(void) {
+ warning("STUB: Hero::tick()");
+}
+
+int Hero::distance(V3D pos) {
+ warning("STUB: Hero::distance()");
+ return 0;
+}
+
+int Hero::distance(Sprite *spr) {
+ warning("STUB: Hero::distance()");
+ return 0;
+}
+
+void Hero::turn(Dir d) {
+ warning("STUB: Hero::turn()");
+}
+
+void Hero::park(void) {
+ warning("STUB: Hero::park()");
+}
+
+bool Hero::lower(Sprite * spr) {
+ warning("STUB: Hero::lower()");
+ return false;
+}
+
+void Hero::reach(int mode) {
+ warning("STUB: Hero::reach()");
+}
+
+void Hero::fun(void) {
+ warning("STUB: Hero::fun()");
+}
+
+void Hero::operator ++ (void) {
+ warning("STUB: Hero::operator ++()");
+}
+
+void Hero::operator -- (void) {
+ warning("STUB: Hero::operator --()");
+}
+
+uint32 Hero::len(V2D v) {
+ warning("STUB: Hero::works()");
+ return 0;
+}
+
+bool Hero::findWay(void){
+ warning("STUB: Hero::findWay()");
+ return false;
+}
+
+int Hero::snap(int p, int q, int grid) {
+ warning("STUB: Hero::findWay()");
+ return 0;
+}
+
+void Hero::walkTo(V3D pos) {
+ warning("STUB: Hero::walkTo()");
+}
+
+void Hero::walkTo(Sprite *spr) {
+ warning("STUB: Hero::walkTo()");
+}
+
+V3D Hero::screenToGround(V2D pos) {
+ double z = _vm->_eye->_z + (_vm->_eye->_y * _vm->_eye->_z) / (double(pos.y) - _vm->_eye->_y);
+ double x = _vm->_eye->_x - ((double(pos.x) - _vm->_eye->_x) * (z - _vm->_eye->_z)) / _vm->_eye->_z;
+ return V3D(V2D::round(x), 0, V2D::round(z));
+}
+
+
+int Hero::cross(const V2D &a, const V2D &b) {
+ warning("STUB: Hero::cross()");
+ return 0;
+}
+
+int Hero::mapCross(const V2D &a, const V2D &b) {
+ warning("STUB: Hero::mapCross()");
+ return 0;
+}
+
+int Hero::mapCross(const V3D &a, const V3D &b) {
+ warning("STUB: Hero::mapCross()");
+ return 0;
+}
+
+void Hero::setCave(int c) {
+ warning("STUB: Hero::mapCross()");
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/hero.h b/engines/cge2/hero.h
new file mode 100644
index 0000000000..032a46d1b3
--- /dev/null
+++ b/engines/cge2/hero.h
@@ -0,0 +1,105 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_HERO_H
+#define CGE2_HERO_H
+
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+#include "cge2/snail.h"
+
+namespace CGE2 {
+
+#define kMaxTry 400
+
+class Hero;
+
+struct HeroTab {
+ Hero *_ptr;
+ Sprite *_face;
+ Sprite *_pocket[kPocketMax + 1];
+ int _pocPtr;
+ V2D *_posTab[kCaveMax];
+ HeroTab(CGE2Engine *vm) {
+ for (int i = 0; i < kCaveMax; i++)
+ _posTab[i] = new V2D(vm);
+ }
+ ~HeroTab() {
+ for (int i = 0; i < kCaveMax; i++)
+ delete _posTab[i];
+ }
+};
+
+class Hero : public Sprite {
+ int _hig[kDimMax];
+ Sprite *_contact;
+public:
+ BitmapPtr _dim[kDimMax];
+ V3D _trace[kWayMax];
+ enum Dir { kNoDir = -1, kSS, kWW, kNN, kEE } _dir;
+ int _curDim;
+ int _tracePtr;
+ int _reachStart, _reachCycle, _sayStart, _funStart;
+ int _funDel0, _funDel;
+ int _maxDist;
+ bool _ignoreMap;
+ Hero(CGE2Engine *vm);
+ void tick(void);
+ Sprite *expand(void);
+ Sprite *contract(void) { return this; }
+ Sprite *setContact(void);
+ int stepSize(void) { return _ext->_seq[7]._dx; }
+ int distance(V3D pos);
+ int distance(Sprite * spr);
+ void turn(Dir d);
+ void park(void);
+ static uint32 len(V2D v);
+ bool findWay(void);
+ static int snap(int p, int q, int grid);
+ void walkTo(V3D pos);
+ void walkTo(V2D pos) { walkTo(screenToGround(pos)); }
+ V3D screenToGround(V2D pos);
+ void walkTo(Sprite *spr);
+ void say(void) { step(_sayStart); }
+ void fun(void);
+ void resetFun(void) { _funDel = _funDel0; }
+ void hStep(void);
+ bool lower(Sprite * spr);
+ int cross(const V2D &a, const V2D &b);
+ int mapCross(const V2D &a, const V2D &b);
+ int mapCross(const V3D &a, const V3D &b);
+ Hero *other(void) { return _vm->_heroTab[!(_ref & 1)]->_ptr;}
+ Action action(void) { return (Action)(_ref % 10); }
+ void reach(int mode);
+ void setCurrent(void);
+ void setCave(int c);
+ void operator ++ (void);
+ void operator -- (void);
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_HERO_H
diff --git a/engines/cge2/module.mk b/engines/cge2/module.mk
new file mode 100644
index 0000000000..7272ed3829
--- /dev/null
+++ b/engines/cge2/module.mk
@@ -0,0 +1,24 @@
+MODULE := engines/cge2
+
+MODULE_OBJS = \
+ cge2.o \
+ detection.o \
+ fileio.o \
+ vga13h.o \
+ bitmap.o \
+ sound.o \
+ cge2_main.o \
+ text.o \
+ hero.o \
+ snail.o \
+ spare.o \
+ talk.o \
+ events.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_CGE2), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/cge2/snail.cpp b/engines/cge2/snail.cpp
new file mode 100644
index 0000000000..f00b02c7bd
--- /dev/null
+++ b/engines/cge2/snail.cpp
@@ -0,0 +1,689 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/snail.h"
+#include "cge2/fileio.h"
+#include "cge2/hero.h"
+#include "cge2/text.h"
+#include "cge2/sound.h"
+
+namespace CGE2 {
+
+const char *CommandHandler::_commandText[] = {
+ "NOP", "USE", "PAUSE", "INF", "CAVE",
+ "SLAVE", "FOCUS", "SETX", "SETY", "SETZ",
+ "ADD", "SUB", "MUL", "DIV", "IF", "FLAG",
+ "FLASH", "LIGHT", "CYCLE",
+ "CLEAR", "TALK", "MOUSE",
+ "MAP", "COUNT", "MIDI",
+ "SETDLG", "MSKDLG",
+ ".DUMMY.",
+ "WAIT", "HIDE", "ROOM",
+ "SAY", "SOUND", "TIME", "KILL",
+ "RSEQ", "SEQ", "SEND", "SWAP",
+ "KEEP", "GIVE",
+ "GETPOS", "GOTO", "MOVEX", "MOVEY",
+ "MOVEZ", "TRANS", "PORT",
+ "NEXT", "NNEXT", "MTNEXT", "FTNEXT",
+ "RNNEXT", "RMTNEXT", "RFTNEXT",
+ "RMNEAR", "RMMTAKE", "RMFTAKE",
+ "SETREF", "BACKPT",
+ "WALKTO", "REACH", "COVER", "UNCOVER",
+ NULL };
+
+CommandHandler::CommandHandler(CGE2Engine *vm, bool turbo)
+ : _turbo(turbo), _textDelay(false), _timerExpiry(0), _talkEnable(true),
+ _head(0), _tail(0), _commandList((Command *)malloc(sizeof(Command)* 256)),
+ _count(1), _vm(vm) {
+}
+
+CommandHandler::~CommandHandler() {
+ free(_commandList);
+}
+
+void CommandHandler::runCommand() {
+ if (!_turbo && _vm->_commandStat._wait) {
+ if (*(_vm->_commandStat._wait))
+ return;
+ else {
+ ++_vm->_commandStat._ref[0];
+ warning("STUB: CommandHandler::runCommand() - Sound code missing!");
+ _vm->_commandStat._wait = nullptr;
+ }
+ }
+
+ uint8 tmpHead = _head;
+ while (_tail != tmpHead) {
+ Command tailCmd = _commandList[_tail];
+
+ if (!_turbo) { // only for the slower one
+ if (_vm->_waitRef)
+ break;
+ if (_timerExpiry) {
+ // Delay in progress
+ if (_timerExpiry > g_system->getMillis())
+ // Delay not yet ended
+ break;
+
+ // Delay is finished
+ _timerExpiry = 0;
+ } else if (_textDelay) {
+ if (_vm->_talk) {
+ _vm->snKill((Sprite *)_vm->_talk);
+ _vm->_talk = nullptr;
+ }
+ _textDelay = false;
+ }
+
+ if (_vm->_talk && tailCmd._commandType != kCmdPause)
+ break;
+ }
+ ++_tail;
+ _vm->_taken = false;
+ Sprite *spr = nullptr;
+ if (tailCmd._commandType > kCmdSpr)
+ spr = (tailCmd._ref < 0) ? ((Sprite *)tailCmd._spritePtr) : _vm->locate(tailCmd._ref);
+
+ switch (tailCmd._commandType) {
+ case kCmdUse:
+ break;
+ case kCmdPause:
+ _timerExpiry = g_system->getMillis() + tailCmd._val * kCommandFrameDelay;
+ if (_vm->_talk)
+ _textDelay = true;
+ break;
+ case kCmdWait:
+ if (spr && spr->active() && (spr->_scene == _vm->_now || spr->_scene == 0)) {
+ _vm->_waitSeq = tailCmd._val;
+ _vm->_waitRef = spr->_ref;
+ }
+ break;
+ case kCmdHide:
+ _vm->snHide(spr, tailCmd._val);
+ break;
+ case kCmdSay:
+ if (spr && spr->active() && _talkEnable) //-- mouth animation
+ warning("STUB: CommandHandler::runCommand() - Mouth animation missing!");
+ break;
+ case kCmdInf:
+ if (_talkEnable)
+ _vm->inf(((tailCmd._val) >= 0) ? _vm->_text->getText(tailCmd._val) : (const char *)tailCmd._spritePtr);
+ break;
+ case kCmdTime:
+ warning("STUB: CommandHandler::runCommand() - Something missing connected to kCmdTime!");
+ break;
+ case kCmdCave:
+ _vm->switchCave(tailCmd._val);
+ break;
+ case kCmdMidi:
+ _vm->snMidi(tailCmd._val);
+ break;
+ case kCmdSetDlg:
+ _vm->snSetDlg(tailCmd._ref, tailCmd._val);
+ break;
+ case kCmdMskDlg:
+ _vm->snMskDlg(tailCmd._ref, tailCmd._val);
+ break;
+ case kCmdKill:
+ _vm->snKill(spr);
+ break;
+ case kCmdSeq:
+ _vm->snSeq(spr, tailCmd._val);
+ break;
+ case kCmdRSeq:
+ _vm->snRSeq(spr, tailCmd._val);
+ break;
+ case kCmdSend:
+ _vm->snSend(spr, tailCmd._val);
+ break;
+ case kCmdSwap:
+ _vm->snSwap(spr, tailCmd._val);
+ break;
+ case kCmdCover:
+ _vm->snCover(spr, tailCmd._val);
+ break;
+ case kCmdUncover:
+ _vm->snUncover(spr, (tailCmd._val >= 0) ? _vm->locate(tailCmd._val) : ((Sprite *)tailCmd._spritePtr));
+ break;
+ case kCmdFocus:
+ _vm->snFocus(tailCmd._val);
+ break;
+ case kCmdKeep:
+ _vm->snKeep(spr, tailCmd._val);
+ break;
+ case kCmdGive:
+ _vm->snGive(spr, tailCmd._val);
+ break;
+ case kCmdSetX:
+ _vm->_point[tailCmd._val]->_x = tailCmd._ref;
+ break;
+ case kCmdSetY:
+ _vm->_point[tailCmd._val]->_y = tailCmd._ref;
+ break;
+ case kCmdSetZ:
+ _vm->_point[tailCmd._val]->_z = tailCmd._ref;
+ break;
+ case kCmdAdd:
+ *(_vm->_point[tailCmd._ref]) = *(_vm->_point[tailCmd._ref]) + *(_vm->_point[tailCmd._val]);
+ break;
+ case kCmdSub:
+ *(_vm->_point[tailCmd._ref]) = *(_vm->_point[tailCmd._ref]) - *(_vm->_point[tailCmd._val]);
+ break;
+ case kCmdMul:
+ *(_vm->_point[tailCmd._ref]) = *(_vm->_point[tailCmd._ref]) * tailCmd._val;
+ break;
+ case kCmdDiv:
+ *(_vm->_point[tailCmd._ref]) = *(_vm->_point[tailCmd._ref]) / tailCmd._val;
+ break;
+ case kCmdGetPos:
+ if (spr)
+ *(_vm->_point[tailCmd._val]) = spr->_pos3D;
+ break;
+ case kCmdGoto:
+ _vm->snGoto(spr, tailCmd._val);
+ break;
+ case kCmdMoveX:
+ _vm->snMove(spr, V3D(tailCmd._val, 0, 0));
+ break;
+ case kCmdMoveY:
+ _vm->snMove(spr, V3D(0, tailCmd._val, 0));
+ break;
+ case kCmdMoveZ:
+ _vm->snMove(spr, V3D(0, 0, tailCmd._val));
+ break;
+ case kCmdSlave:
+ _vm->snSlave(spr, tailCmd._val);
+ break;
+ case kCmdTrans:
+ _vm->snTrans(spr, tailCmd._val);
+ break;
+ case kCmdPort:
+ _vm->snPort(spr, tailCmd._val);
+ break;
+ case kCmdNext:
+ break;
+ case kCmdIf:
+ break;
+ case kCmdTalk:
+ break;
+ case kCmdMouse:
+ _vm->snMouse(tailCmd._val != 0);
+ break;
+ case kCmdNNext:
+ _vm->snNNext(spr, kNear, tailCmd._val);
+ break;
+ case kCmdMTNext:
+ _vm->snNNext(spr, kMTake, tailCmd._val);
+ break;
+ case kCmdFTNext:
+ _vm->snNNext(spr, kFTake, tailCmd._val);
+ break;
+ case kCmdRNNext:
+ _vm->snRNNext(spr, tailCmd._val);
+ break;
+ case kCmdRMTNext:
+ _vm->snRMTNext(spr, tailCmd._val);
+ break;
+ case kCmdRFTNext:
+ _vm->snRFTNext(spr, tailCmd._val);
+ break;
+ case kCmdRMNear:
+ _vm->snRmNear(spr);
+ break;
+ case kCmdRMMTake:
+ _vm->snRmMTake(spr);
+ break;
+ case kCmdRMFTake:
+ _vm->snRmFTake(spr);
+ break;
+ case kCmdFlag:
+ _vm->snFlag(tailCmd._ref & 3, tailCmd._val);
+ break;
+ case kCmdSetRef:
+ _vm->snSetRef(spr, tailCmd._val);
+ break;
+ case kCmdBackPt:
+ _vm->snBackPt(spr, tailCmd._val);
+ break;
+ case kCmdFlash:
+ _vm->snFlash(tailCmd._val != 0);
+ break;
+ case kCmdLight:
+ _vm->snLight(tailCmd._val != 0);
+ break;
+ case kCmdCycle:
+ warning("Unhandled command - kCmdCycle");
+ break;
+ case kCmdWalk:
+ _vm->snWalk(spr, tailCmd._val);
+ break;
+ case kCmdReach:
+ _vm->snReach(spr, tailCmd._val);
+ break;
+ case kCmdSound:
+ _vm->snSound(spr, tailCmd._val);
+ _count = 1;
+ break;
+ case kCmdMap:
+ _vm->_heroTab[tailCmd._ref & 1]->_ptr->_ignoreMap = tailCmd._val == 0;
+ break;
+ case kCmdCount:
+ _count = tailCmd._val;
+ break;
+ case kCmdRoom:
+ _vm->snRoom(spr, tailCmd._val);
+ break;
+ case kCmdDim:
+ warning("Unhandled command - kCmdDim");
+ break;
+ case kCmdExec:
+ warning("Unhandled command - kCmdExec");
+ break;
+ case kCmdStep:
+ spr->step();
+ break;
+ case kCmdGhost:
+ _vm->snGhost((Bitmap *)tailCmd._spritePtr);
+ break;
+ default:
+ warning("Unhandled command");
+ break;
+ }
+
+ if (_vm->_taken && spr)
+ _vm->_spare->dispose(spr);
+
+ if (!_turbo)
+ break;
+ }
+}
+
+void CGE2Engine::snKill(Sprite *spr) {
+ warning("STUB: CGE2Engine::snKill()");
+}
+
+void CGE2Engine::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 CGE2Engine::snMidi(int val) {
+ warning("STUB: CGE2Engine::snMidi()");
+}
+
+void CGE2Engine::snSetDlg(int clr, int set) {
+ warning("STUB: CGE2Engine::snSetDlg()");
+}
+
+void CGE2Engine::snMskDlg(int clr, int set) {
+ warning("STUB: CGE2Engine::snMskDlg()");
+}
+
+void CGE2Engine::snSeq(Sprite *spr, int val) {
+ if (spr) {
+ if (isHero(spr) && val == 0)
+ ((Hero*)spr)->park();
+ else
+ spr->step(val);
+ }
+}
+
+void CGE2Engine::snRSeq(Sprite *spr, int val) {
+ if (spr)
+ snSeq(spr, spr->_seqPtr + val);
+}
+
+void CGE2Engine::snSend(Sprite *spr, int val) {
+ if (!spr)
+ return;
+
+ // Sending", spr->File
+ // from cave", spr->Cave
+ // to cave", val
+ bool was1 = (_vga->_showQ->locate(spr->_ref) != nullptr);
+ bool val1 = (val == 0 || val == _now);
+ spr->_scene = val;
+ releasePocket(spr);
+ if (val1 != was1) {
+ if (was1) {
+ // deactivating
+ hide1(spr);
+ spr->_flags._slav = false;
+ if (spr == _heroTab[_sex]->_ptr)
+ if (_heroTab[!_sex]->_ptr->_scene == _now)
+ switchHero(!_sex);
+ _spare->dispose(spr);
+ } else {
+ // activating
+ if (byte(spr->_ref) == 0)
+ _bitmapPalette = _vga->_sysPal;
+ _vga->_showQ->insert(spr);
+ if (isHero(spr)) {
+ V2D p = *_heroTab[spr->_ref & 1]->_posTab[val];
+ spr->gotoxyz(V3D(p.x, 0, p.y));
+ ((Hero*)spr)->setCurrent();
+ }
+ _taken = false;
+ _bitmapPalette = NULL;
+ }
+ }
+}
+
+void CGE2Engine::snSwap(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snSwap()");
+}
+void CGE2Engine::snCover(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snCover()");
+}
+
+void CGE2Engine::snUncover(Sprite *spr, Sprite *spr2) {
+ warning("STUB: CGE2Engine::snUncover()");
+}
+
+void CGE2Engine::snFocus(int val) {
+ warning("STUB: CGE2Engine::snFocus()");
+}
+
+void CGE2Engine::snKeep(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snKeep()");
+}
+
+void CGE2Engine::snGive(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snGive()");
+}
+
+void CGE2Engine::snGoto(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snGoto()");
+}
+
+void CGE2Engine::snMove(Sprite *spr, V3D pos) {
+ warning("STUB: CGE2Engine::snMove()");
+}
+
+void CGE2Engine::snSlave(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snSlave()");
+}
+
+void CGE2Engine::snTrans(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snTrans()");
+}
+
+void CGE2Engine::snPort(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snPort()");
+}
+
+void CGE2Engine::snMouse(int val) {
+ warning("STUB: CGE2Engine::snMouse()");
+}
+
+void CGE2Engine::snNNext(Sprite *spr, Action act, int val) {
+ warning("STUB: CGE2Engine::snNNext()");
+}
+
+void CGE2Engine::snRNNext(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snRNNext()");
+}
+
+void CGE2Engine::snRMTNext(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snRMTNext()");
+}
+
+void CGE2Engine::snRFTNext(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snRFTNext()");
+}
+
+void CGE2Engine::snRmNear(Sprite *spr) {
+ warning("STUB: CGE2Engine::snRmNear()");
+}
+
+void CGE2Engine::snRmMTake(Sprite *spr) {
+ warning("STUB: CGE2Engine::snRmMTake()");
+}
+
+void CGE2Engine::snRmFTake(Sprite *spr) {
+ warning("STUB: CGE2Engine::snRmFTake()");
+}
+
+void CGE2Engine::snFlag(int ref, int val) {
+ warning("STUB: CGE2Engine::snFlag()");
+}
+
+void CGE2Engine::snSetRef(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snSetRef()");
+}
+
+void CGE2Engine::snBackPt(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snBackPt()");
+}
+
+void CGE2Engine::snFlash(int val) {
+ warning("STUB: CGE2Engine::snFlash()");
+}
+
+void CGE2Engine::snLight(int val) {
+ warning("STUB: CGE2Engine::snLight()");
+}
+
+void CGE2Engine::snWalk(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snWalk()");
+}
+
+void CGE2Engine::snReach(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snReach()");
+}
+
+void CGE2Engine::snSound(Sprite *spr, int wav) {
+ if (wav == -1)
+ _sound->stop();
+ else {
+ if (_sound->_smpinf._counter && wav < 20)
+ return;
+ if (_commandStat._wait && ((wav & 255) > 80))
+ return;
+
+ _commandStat._ref[1] = wav;
+ _commandStat._ref[0] = !_fx->exist(_commandStat._ref[1]);
+ _sound->play(_fx->load(_commandStat._ref[1], _commandStat._ref[0]),
+ (spr) ? (spr->_pos2D.x / (kScrWidth / 16)) : 8);
+ }
+
+}
+
+void CGE2Engine::snRoom(Sprite *spr, int val) {
+ warning("STUB: CGE2Engine::snRoom()");
+}
+
+void CGE2Engine::snGhost(Bitmap *bmp) {
+ V2D p(this, *bmp->_v & 0xFFFF, *bmp->_v >> 16);
+ bmp->hide(p.x, p.y);
+ delete bmp->_b;
+ bmp->_v = nullptr;
+ bmp->_b = nullptr;
+ delete bmp;
+}
+
+void CGE2Engine::hide1(Sprite *spr) {
+ _commandHandlerTurbo->addCommand(kCmdGhost, -1, 0, spr->ghost());
+}
+
+void CommandHandler::addCommand(CommandType com, int ref, int val, void *ptr) {
+ if (ref == 2)
+ ref = 142 - _vm->_sex;
+ Command *headCmd = &_commandList[_head++];
+ headCmd->_commandType = com;
+ headCmd->_ref = ref;
+ headCmd->_val = val;
+ headCmd->_spritePtr = ptr;
+ headCmd->_cbType = kNullCB;
+ if (headCmd->_commandType == kCmdClear) {
+ clear();
+ }
+}
+
+void CommandHandler::addCallback(CommandType com, int ref, int val, CallbackType cbType) {
+ warning("STUB: CommandHandler::addCallback()");
+}
+
+void CommandHandler::insertCommand(CommandType com, int ref, int val, void *ptr) {
+ warning("STUB: CommandHandler::insertCommand()");
+}
+
+bool CommandHandler::idle() {
+ return (!_vm->_waitRef && _head == _tail);
+}
+
+void CommandHandler::reset() {
+ warning("STUB: CommandHandler::reset()");
+}
+
+void CommandHandler::clear() {
+ _tail = _head;
+ _vm->killText();
+ _timerExpiry = 0;
+}
+
+int CommandHandler::com(const char *com) {
+ int i = _vm->takeEnum(_commandText, com);
+ return (i < 0) ? i : i + kCmdCom0 + 1;
+}
+
+void CGE2Engine::feedSnail(Sprite *spr, Action snq, Hero *hero) {
+ if (!spr || !spr->active())
+ return;
+
+ int cnt = spr->_actionCtrl[snq]._cnt;
+ if (cnt) {
+ byte ptr = spr->_actionCtrl[snq]._ptr;
+ CommandHandler::Command *comtab = spr->snList(snq);
+ CommandHandler::Command *c = &comtab[ptr];
+ CommandHandler::Command *q = &comtab[cnt];
+
+ warning("STUB: CGE2Engine::feedSnail()");
+ // Dont bother with pockets (inventory system) for now... TODO: Implement it later!!!
+ /*
+ int pocFre = freePockets(hero->_ref & 1);
+ int pocReq = 0;
+ CommandHandler::Command *p = c;
+ for (; p < q && p->_commandType != kCmdNext; p++) { // scan commands
+ // drop from pocket?
+ if ((p->_commandType == kCmdSend && p->_val != _now)
+ || p->_commandType == kCmdGive) {
+ int ref = p->_ref;
+ if (ref < 0)
+ ref = spr->_ref;
+ if (findActivePocket(ref) >= 0)
+ --pocReq;
+ }
+ // make/dispose additional room?
+ if (p->_commandType == kCmdRoom) {
+ if (p->_val == 0)
+ ++pocReq;
+ else
+ --pocReq;
+ }
+ // put into pocket?
+ if (p->_commandType == kCmdKeep)
+ ++pocReq;
+ // overloaded?
+ if (pocReq > pocFre) {
+ pocFul();
+ return;
+ }
+ }*/
+
+ while (c < q) {
+ if (c->_commandType == kCmdTalk) {
+ if ((_commandHandler->_talkEnable = (c->_val != 0)) == false)
+ killText();
+ }
+ if (c->_commandType == kCmdWalk || c->_commandType == kCmdReach) {
+ if (c->_val == -1)
+ c->_val = spr->_ref;
+ }
+ if (c->_commandType == kCmdNext) {
+ Sprite *s;
+
+ switch (c->_ref) {
+ case -2:
+ s = hero;
+ break;
+ case -1:
+ s = spr;
+ break;
+ default:
+ s = _vga->_showQ->locate(c->_ref);
+ break;
+ }
+
+ if (s) {
+ if (s->_actionCtrl[snq]._cnt) {
+ int v;
+ switch (c->_val) {
+ case -1:
+ v = int(c - comtab + 1);
+ break;
+ case -2:
+ v = int(c - comtab);
+ break;
+ case -3:
+ v = -1;
+ break;
+ default:
+ v = c->_val;
+ if ((v > 255) && s)
+ v = s->labVal(snq, v >> 8);
+ break;
+ }
+ if (v >= 0)
+ s->_actionCtrl[snq]._ptr = v;
+ }
+ }
+ if (s == spr)
+ break;
+ }
+ if (c->_commandType == kCmdIf) {
+ Sprite *s = (c->_ref < 0) ? spr : _vga->_showQ->locate(c->_ref);
+ if (s) { // sprite extsts
+ if (!s->seqTest(-1)) { // not parked
+ int v = c->_val;
+ if (v > 255) if (s) v = s->labVal(snq, v >> 8);
+ c = comtab + (v - 1);
+ }
+ }
+ } else
+ _commandHandler->addCommand(c->_commandType, c->_ref, c->_val, spr);
+
+ ++c;
+ }
+ }
+
+}
+
+} // End of namespace CGE2.
diff --git a/engines/cge2/snail.h b/engines/cge2/snail.h
new file mode 100644
index 0000000000..afd52dfd45
--- /dev/null
+++ b/engines/cge2/snail.h
@@ -0,0 +1,153 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_SNAIL_H
+#define CGE2_SNAIL_H
+
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+#define kCommandFrameRate 80
+#define kCommandFrameDelay (1000 / kCommandFrameRate)
+#define kNoByte -1 // Recheck this! We have no proof for it's original value.
+
+
+enum CommandType {
+ kCmdCom0 = 128,
+ kCmdNop, // NOP :: do nothing
+ kCmdUse, // USE <spr> <cav>|<lab> :: hint for using
+ kCmdPause, // PAUSE -1 <dly> :: delay <dly>/72 seconds
+ kCmdInf, // INF -1 <ref> :: show text referrenced by <ref>
+ kCmdCave, // CAVE -1 <cav> :: go to board <cav>
+ kCmdSlave, // SLAVE
+ kCmdFocus, // FOCUS :: change active hero
+ kCmdSetX, // SETX <x> <idx> :: set sprite shift in x axis
+ kCmdSetY, // SETX <y> <idx> :: set sprite shift in y axis
+ kCmdSetZ, // SETX <z> <idx> :: set sprite shift in z axis
+ kCmdAdd, // ADD <idx1> <idx2> :: sum vectors
+ kCmdSub, // SUB <idx1> <idx2> :: subtract vectors
+ kCmdMul, // MUL <idx> <nr> :: multiply vector by number
+ kCmdDiv, // DIV <idx> <nr> :: divide vector by number
+ kCmdIf, // IF
+ kCmdFlag, // FLAG <nr> <val> :: set flag <nr> to <val>
+ kCmdFlash, // FLASH -1 0|1 :: lighten whole image (on/off)
+ kCmdLight, // LIGHT
+ kCmdCycle, // CYCLE <cnt> :: rotate <cnt> colors from 1
+ kCmdClear, // CLEAR -1 0 :: clear kCmdAIL queue
+ kCmdTalk, // TALK -1 0|1 :: enable speach (on/off)
+ kCmdMouse, // MOUSE -1 0|1 :: enable mouse (on/off)
+ kCmdMap, // MAP 0|1 0 :: temporarily turn off map for hero
+ kCmdCount, // COUNT
+ kCmdMidi, // MIDI -1 <midi> :: play MIDI referenced by <midi> (-1 = off)
+ kCmdSetDlg, // SETDLG 0..3 0..3 :: switch of speach mode
+ kCmdMskDlg, // MSKDLG 0..3 0..3 :: switch of speach mode mask
+
+ kCmdSpr,
+
+ kCmdWait, // WAIT <spr> <seq>|-1 :: wait for SEQ <seq> (-1 = freeze)
+ kCmdHide, // HIDE <spr> 0|1 :: visibility of sprite
+ kCmdRoom, // ROOM <hero> 0|1 :: additional room in pocket (no/yes)
+ kCmdSay, // SAY <spr> <ref> :: say text referenced by <ref>
+ kCmdSound, // SOUND <spr> <ref> :: play sound effect referenced by <ref>
+ kCmdTime, // TIME <spr> 0 :: say current time
+ kCmdKill, // KILL <spr> 0 :: remove sprite
+ kCmdRSeq, // RSEQ <spr> <nr> :: relative jump SEQ <nr> lines
+ kCmdSeq, // SEQ <spr> <seq> :: jump to certain SEQ
+ kCmdSend, // SEND <spr> <cav> :: move sprite to board <cav>
+ kCmdSwap, // SWAP <spr1> spr2> :: sprite exchange
+ kCmdKeep, // KEEP <spr> <seq> :: take sprite into pocket and jump to <seq>
+ kCmdGive, // GIVE <spr> <seq> :: remove sprite from pocket and jump to <seq>
+ kCmdGetPos, // GETPOS <spr> <idx> :: take sprite's position
+ kCmdGoto, // GOTO <spr> <idx> :: move sprite to position
+ kCmdMoveX, // MOVEX <spr> <dx> :: relative move along X axis
+ kCmdMoveY, // MOVEY <spr> <dy> :: relative move along Y axis
+ kCmdMoveZ, // MOVEZ <spr> <dz> :: relative move along Z axis
+ kCmdTrans, // TRANS <spr> 0|1 :: clear/set logical transparency
+ kCmdPort, // PORT <spr> 0|1 :: clear/set "takeability" of sprite
+ kCmdNext, // NEXT <spr> <nr> :: jump to <nr> - NEAR or TAKE
+ kCmdNNext, // NNEXT <spr> <nr> :: jump to <nr> - NEAR
+ kCmdMTNext, // MTNEXT <spr> <nr> :: jump to <nr> - TAKE
+ kCmdFTNext, // FTNEXT <spr> <nr> :: jump to <nr> - TAKE
+ kCmdRNNext, // RNNEXT <spr> <nr> :: relative jump to <nr> - NEAR
+ kCmdRMTNext, // RMTNEXT <spr> <nr> :: relative jump to <nr> - TAKE
+ kCmdRFTNext, // RFTNEXT <spr> <nr> :: relative jump to <nr> - TAKE
+ kCmdRMNear, // RMNEAR <spr> 0 :: remove NEAR list
+ kCmdRMMTake, // RMMTAKE <spr> 0 :: remove TAKE list
+ kCmdRMFTake, // RMFTAKE <spr> 0 :: remove TAKE list
+ kCmdSetRef, // RETREF <spr> <ref> :: change reference of sprite <spr> to <ref>
+ kCmdBackPt, // BACKPT <spr> 0 :: paint sprite onto the background
+ kCmdWalk, // WALK <hero> <ref>|<point> :: go close to the sprite or point
+ kCmdReach, // REACH <hero> <ref>|<m> :: reach the sprite or point with <m> method
+ kCmdCover, // COVER <sp1> <sp2> :: cover sprite <sp1> with sprite <sp2>
+ kCmdUncover, // UNCOVER <sp1> <sp2> :: restore the state before COVER
+
+ kCmdDim,
+ kCmdExec,
+ kCmdStep,
+ kCmdGhost,
+
+ kCmdNOne = kNoByte
+};
+
+class CommandHandler {
+public:
+ struct Command {
+ CommandType _commandType;
+ byte _lab;
+ int _ref;
+ int _val;
+ void *_spritePtr;
+ CallbackType _cbType;
+ } *_commandList;
+ static const char *_commandText[];
+ bool _talkEnable;
+
+ CommandHandler(CGE2Engine *vm, bool turbo);
+ ~CommandHandler();
+ void runCommand();
+ void addCommand(CommandType com, int ref, int val, void *ptr);
+ void addCallback(CommandType com, int ref, int val, CallbackType cbType);
+ void insertCommand(CommandType com, int ref, int val, void *ptr);
+ bool idle();
+ void reset();
+ void clear();
+ int com(const char *com);
+private:
+ CGE2Engine *_vm;
+ bool _turbo;
+ uint8 _head;
+ uint8 _tail;
+ bool _busy;
+ bool _textDelay;
+ uint32 _timerExpiry; // "pause" in the original.
+ int _count;
+};
+
+} // End of namespace CGE2
+
+#endif
diff --git a/engines/cge2/sound.cpp b/engines/cge2/sound.cpp
new file mode 100644
index 0000000000..9f5ec2bb6c
--- /dev/null
+++ b/engines/cge2/sound.cpp
@@ -0,0 +1,254 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/sound.h"
+//#include "cge/text.h"
+//#include "cge/cge_main.h"
+#include "common/config-manager.h"
+#include "common/memstream.h"
+#include "audio/decoders/raw.h"
+#include "audio/audiostream.h"
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+DataCk::DataCk(byte *buf, int bufSize) {
+ _buf = buf;
+ _ckSize = bufSize;
+}
+
+DataCk::~DataCk() {
+ free(_buf);
+}
+
+Sound::Sound(CGE2Engine *vm) : _vm(vm) {
+ _audioStream = NULL;
+ _soundRepeatCount = 1;
+ open();
+}
+
+Sound::~Sound() {
+ close();
+}
+
+void Sound::close() {
+ _vm->_midiPlayer->killMidi();
+}
+
+void Sound::open() {
+ setRepeat(1);
+ warning("STUB: Sound::open()");
+ play(_vm->_fx->load(99, 99));
+}
+
+void Sound::setRepeat(int16 count) {
+ _soundRepeatCount = count;
+}
+
+int16 Sound::getRepeat() {
+ return _soundRepeatCount;
+}
+
+void Sound::play(DataCk *wav, int pan) {
+ if (wav) {
+ stop();
+ _smpinf._saddr = &*(wav->addr());
+ _smpinf._slen = (uint16)wav->size();
+ _smpinf._span = pan;
+ _smpinf._counter = getRepeat();
+ sndDigiStart(&_smpinf);
+ }
+}
+
+void Sound::sndDigiStart(SmpInfo *PSmpInfo) {
+ // Create an audio stream wrapper for sound
+ Common::MemoryReadStream *stream = new Common::MemoryReadStream(PSmpInfo->_saddr,
+ PSmpInfo->_slen, DisposeAfterUse::NO);
+ _audioStream = Audio::makeWAVStream(stream, DisposeAfterUse::YES);
+
+ // Start the new sound
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle,
+ Audio::makeLoopingAudioStream(_audioStream, (uint)PSmpInfo->_counter));
+
+ // CGE pan:
+ // 8 = Center
+ // Less = Left
+ // More = Right
+ _vm->_mixer->setChannelBalance(_soundHandle, (int8)CLIP(((PSmpInfo->_span - 8) * 16), -127, 127));
+}
+
+void Sound::stop() {
+ sndDigiStop(&_smpinf);
+}
+
+void Sound::sndDigiStop(SmpInfo *PSmpInfo) {
+ if (_vm->_mixer->isSoundHandleActive(_soundHandle))
+ _vm->_mixer->stopHandle(_soundHandle);
+ _audioStream = NULL;
+}
+
+Fx::Fx(CGE2Engine *vm, int size) : _current(NULL), _vm(vm) {
+}
+
+Fx::~Fx() {
+ clear();
+}
+
+void Fx::clear() {
+ if (_current)
+ delete _current;
+ _current = NULL;
+}
+
+Common::String Fx::name(int ref, int sub) {
+ char name[] = "%.2dfx%.2d.WAV\0";
+ char subn[] = "%.2dfx%.2d?.WAV\0";
+ char *p = (sub) ? subn : name;
+ Common::String filename = Common::String::format(p, ref >> 8, ref & 0xFF);
+ if (sub)
+ filename.setChar('@' + sub, 6);
+ return filename;
+}
+
+bool Fx::exist(int ref, int sub) {
+ return _vm->_resman->exist(name(ref, sub).c_str());
+}
+
+DataCk *Fx::load(int ref, int sub) {
+ Common::String filename = name(ref, sub);
+ EncryptedStream file(_vm, filename.c_str());
+ clear();
+ return (_current = loadWave(&file));
+}
+
+DataCk *Fx::loadWave(EncryptedStream *file) {
+ byte *data = (byte *)malloc(file->size());
+
+ if (!data)
+ return 0;
+
+ file->read(data, file->size());
+
+ return new DataCk(data, file->size());
+}
+
+MusicPlayer::MusicPlayer(CGE2Engine *vm) : _vm(vm) {
+ _data = NULL;
+ _isGM = false;
+
+ MidiPlayer::createDriver();
+
+ int ret = _driver->open();
+ if (ret == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ // TODO: Load cmf.ins with the instrument table. It seems that an
+ // interface for such an operation is supported for AdLib. Maybe for
+ // this card, setting instruments is necessary.
+
+ _driver->setTimerCallback(this, &timerCallback);
+ }
+ _dataSize = -1;
+}
+
+MusicPlayer::~MusicPlayer() {
+ killMidi();
+}
+
+void MusicPlayer::killMidi() {
+ Audio::MidiPlayer::stop();
+
+ free(_data);
+ _data = NULL;
+}
+
+void MusicPlayer::loadMidi(int ref) {
+ warning("STUB: MusicPlayer::loadMidi()"); // if (MidiNotify) MidiNotify();
+
+ // Work out the filename and check the given MIDI file exists
+ Common::String filename = Common::String::format("%.2dSG%.2d.MID", ref >> 8, ref & 0xFF);
+ if (!_vm->_resman->exist(filename.c_str()))
+ return;
+
+ // Stop any currently playing MIDI file
+ killMidi();
+
+ // Read in the data for the file
+ EncryptedStream mid(_vm, filename.c_str());
+ _dataSize = mid.size();
+ _data = (byte *)malloc(_dataSize);
+ mid.read(_data, _dataSize);
+
+ // Start playing the music
+ sndMidiStart();
+}
+
+void MusicPlayer::sndMidiStart() {
+ _isGM = true;
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(_data, _dataSize)) {
+ parser->setTrack(0);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+ _parser = parser;
+
+ syncVolume();
+
+ // Al the tracks are supposed to loop
+ _isLooping = true;
+ _isPlaying = true;
+ }
+}
+
+void MusicPlayer::send(uint32 b) {
+ if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
+ b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
+ }
+
+ Audio::MidiPlayer::send(b);
+}
+
+void MusicPlayer::sendToChannel(byte channel, uint32 b) {
+ if (!_channelsTable[channel]) {
+ _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+ // If a new channel is allocated during the playback, make sure
+ // its volume is correctly initialized.
+ if (_channelsTable[channel])
+ _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
+ }
+
+ if (_channelsTable[channel])
+ _channelsTable[channel]->send(b);
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/sound.h b/engines/cge2/sound.h
new file mode 100644
index 0000000000..6fa2b2a553
--- /dev/null
+++ b/engines/cge2/sound.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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_SOUND_H
+#define CGE2_SOUND_H
+
+#include "cge2/fileio.h"
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+#include "audio/fmopl.h"
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
+#include "audio/midiplayer.h"
+#include "audio/mixer.h"
+#include "common/memstream.h"
+
+namespace CGE2 {
+
+class CGE2Engine;
+
+// sample info
+struct SmpInfo {
+ const uint8 *_saddr; // address
+ uint16 _slen; // length
+ uint16 _span; // left/right pan (0-15)
+ int _counter; // number of time the sample should be played
+};
+
+class DataCk {
+ byte *_buf;
+ int _ckSize;
+public:
+ DataCk(byte *buf, int bufSize);
+ ~DataCk();
+ inline const byte *addr() {
+ return _buf;
+ }
+ inline int size() {
+ return _ckSize;
+ }
+};
+
+class Sound {
+public:
+ SmpInfo _smpinf;
+
+ Sound(CGE2Engine *vm);
+ ~Sound();
+ void open();
+ void close();
+ void play(DataCk *wav, int pan = 8);
+ int16 getRepeat();
+ void setRepeat(int16 count);
+ void stop();
+private:
+ int _soundRepeatCount;
+ CGE2Engine *_vm;
+ Audio::SoundHandle _soundHandle;
+ Audio::RewindableAudioStream *_audioStream;
+
+ void sndDigiStart(SmpInfo *PSmpInfo);
+ void sndDigiStop(SmpInfo *PSmpInfo);
+};
+
+class Fx {
+ CGE2Engine *_vm;
+ int _size;
+
+ DataCk *loadWave(EncryptedStream *file);
+ Common::String name(int ref, int sub);
+public:
+ DataCk *_current;
+
+ Fx(CGE2Engine *vm, int size);
+ ~Fx();
+ void clear();
+ bool exist(int ref, int sub = 0);
+ DataCk *load(int ref, int sub = 0);
+};
+
+class MusicPlayer: public Audio::MidiPlayer {
+private:
+ CGE2Engine *_vm;
+ byte *_data;
+ int _dataSize;
+ bool _isGM;
+
+ // Start MIDI File
+ void sndMidiStart();
+
+ // Stop MIDI File
+ void sndMidiStop();
+public:
+ MusicPlayer(CGE2Engine *vm);
+ ~MusicPlayer();
+
+ void loadMidi(int ref);
+ void killMidi();
+
+ virtual void send(uint32 b);
+ virtual void sendToChannel(byte channel, uint32 b);
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_SOUND_H
diff --git a/engines/cge2/spare.cpp b/engines/cge2/spare.cpp
new file mode 100644
index 0000000000..be2fc64d23
--- /dev/null
+++ b/engines/cge2/spare.cpp
@@ -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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/spare.h"
+
+namespace CGE2 {
+
+void Spare::synchronize() {
+ warning("STUB: Spare::Load");
+}
+
+void Spare::clear() {
+ _container.clear();
+}
+
+Sprite *Spare::locate(int ref) {
+ for (uint i = 0; i < _container.size(); ++i) {
+ if (_container[i]->_ref == ref)
+ return _container[i];
+ }
+ return nullptr;
+}
+
+void Spare::takeCave(int cav) {
+ int bakRef = cav << 8;
+ Common::Array<Sprite*> tempCont = _container;
+ for (uint i = 0; i < tempCont.size(); ++i) {
+ Sprite *spr = tempCont[i];
+ int c = spr->_scene;
+ if ((c == _vm->_now || c == 0) && spr->_ref != bakRef) {
+ _vm->_vga->_showQ->insert(spr);
+ }
+ }
+}
+
+void Spare::store(Sprite *spr) {
+ _container.insert_at(_container.size(), spr);
+}
+
+void Spare::update(Sprite *spr) {
+ Sprite *sp = locate(spr->_ref);
+ if (sp == nullptr)
+ store(spr);
+}
+
+void Spare::dispose(Sprite *spr) {
+ if (spr) {
+ _vm->_vga->_showQ->remove(spr);
+ update(spr->contract());
+ if (!_vm->isHero(spr)) {
+ for (uint i = 0; i < _container.size(); ++i) {
+ if (spr == _container[i]) {
+ _container.remove_at(i);
+ delete spr;
+ break;
+ }
+ }
+ }
+ }
+}
+
+void Spare::dispose(int ref) {
+ dispose(_vm->_vga->_showQ->locate(ref));
+}
+
+void Spare::dispose() {
+ for (uint i = 0; i < _container.size(); ++i) {
+ if (_container[i]->_ref > 255)
+ dispose(_container[i]);
+ }
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/spare.h b/engines/cge2/spare.h
new file mode 100644
index 0000000000..7bd520d9d0
--- /dev/null
+++ b/engines/cge2/spare.h
@@ -0,0 +1,55 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_SPARE_H
+#define CGE2_SPARE_H
+
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+class Spare {
+ CGE2Engine *_vm;
+ Common::Array<Sprite*> _container;
+public:
+ Spare(CGE2Engine *vm) : _vm(vm) {}
+ ~Spare() { clear(); }
+ void store(Sprite *spr);
+ Sprite *locate(int ref);
+ void takeCave(int cav);
+ void update(Sprite *spr);
+ void dispose(Sprite *spr);
+ void dispose(int ref);
+ void dispose();
+ void synchronize();
+ uint16 count() { return _container.size(); }
+ void clear();
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_SPARE_H
diff --git a/engines/cge2/talk.cpp b/engines/cge2/talk.cpp
new file mode 100644
index 0000000000..2913327320
--- /dev/null
+++ b/engines/cge2/talk.cpp
@@ -0,0 +1,88 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "cge2/general.h"
+#include "cge2/talk.h"
+//#include "cge2/game.h"
+//#include "cge2/events.h"
+#include "cge2/cge2_main.h"
+
+namespace CGE2 {
+
+Font::Font(CGE2Engine *vm, const char *name) : _vm(vm) {
+ warning("STUB: Font::Font()");
+}
+
+Font::~Font() {
+ warning("STUB: Font::~Font()");
+}
+
+void Font::load() {
+ warning("STUB: Font::load()");
+}
+
+uint16 Font::width(const char *text) {
+ warning("STUB: Font::width()");
+ return 0;
+}
+
+Talk::Talk(CGE2Engine *vm, const char *text, TextBoxStyle mode, bool wideSpace)
+ : Sprite(vm), _mode(mode), _wideSpace(wideSpace), _vm(vm) {
+ warning("STUB: Talk::Talk()");
+}
+
+Talk::Talk(CGE2Engine *vm)
+ : Sprite(vm), _mode(kTBPure), _vm(vm) {
+ warning("STUB: Talk::Talk()");
+}
+
+void Talk::update(const char *text) {
+ warning("STUB: Talk::update()");
+}
+
+Bitmap *Talk::box(uint16 w, uint16 h) {
+ warning("STUB: Talk::box()");
+ return *_ts;
+}
+
+InfoLine::InfoLine(CGE2Engine *vm, uint16 w) : Talk(vm), _oldText(NULL), _vm(vm) {
+ warning("STUB: InfoLine::InfoLine()");
+}
+
+void InfoLine::update(const char *text) {
+ warning("STUB: InfoLine::update()");
+}
+
+void InfoLine::update() {
+ warning("STUB: InfoLine::update()");
+}
+
+void InfoLine::setText(const char *txt) {
+ warning("STUB: InfoLine::setText()");
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/talk.h b/engines/cge2/talk.h
new file mode 100644
index 0000000000..2d4c235d9d
--- /dev/null
+++ b/engines/cge2/talk.h
@@ -0,0 +1,78 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_TALK_H
+#define CGE2_TALK_H
+
+#include "cge2/general.h"
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+#define kTextColFG kVgaColDark // foreground color
+#define kTextColBG kVgaColGray // background color
+#define kTextHMargin (6&~1) // EVEN horizontal margins!
+#define kTextVMargin 5 // vertical margins
+#define kTextLineSpace 2 // line spacing
+#define kTextRoundCorner 3 // rounded corners
+#define kWidSize 256
+#define kPosSize 256
+#define kMapSize (256*8)
+#define kFontHigh 8
+#define kFontExt ".CFT"
+
+enum TextBoxStyle { kTBPure, kTBRect, kTBRound };
+
+class Talk : public Sprite {
+protected:
+ TextBoxStyle _mode;
+ BitmapPtr *_ts;
+ Bitmap *box(uint16 w, uint16 h);
+ bool _wideSpace;
+public:
+ Talk(CGE2Engine *vm, const char *text, TextBoxStyle mode, bool wideSpace = false);
+ Talk(CGE2Engine *vm);
+
+ virtual void update(const char *text);
+private:
+ CGE2Engine *_vm;
+};
+
+class InfoLine : public Talk {
+ const char *_oldText;
+public:
+ InfoLine(CGE2Engine *vm, uint16 wid);
+ void update(const char *text);
+ void update();
+ void setText(const char *txt);
+private:
+ CGE2Engine *_vm;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_TALK_H
diff --git a/engines/cge2/text.cpp b/engines/cge2/text.cpp
new file mode 100644
index 0000000000..2f8e9b4011
--- /dev/null
+++ b/engines/cge2/text.cpp
@@ -0,0 +1,152 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+//#include "cge/general.h"
+#include "cge2/text.h"
+//#include "cge/talk.h"
+//#include "cge/game.h"
+//#include "cge/snail.h"
+#include "cge2/cge2_main.h"
+#include "common/str.h"
+
+namespace CGE2 {
+
+Text::Text(CGE2Engine *vm, const char *fname) : _vm(vm) {
+ _vm->mergeExt(_fileName, fname, kSayExt);
+ if (!_vm->_resman->exist(_fileName))
+ error("No talk (%s)", _fileName);
+ int16 txtCount = count() + 1;
+ if (!txtCount)
+ error("Unable to read dialog file %s", _fileName);
+
+ _cache = new Handler[txtCount];
+ for (_size = 0; _size < txtCount; _size++) {
+ _cache[_size]._ref = 0;
+ _cache[_size]._text = NULL;
+ }
+ load();
+}
+
+Text::~Text() {
+ clear();
+ delete[] _cache;
+}
+
+int16 Text::count() {
+ EncryptedStream tf(_vm, _fileName);
+ if (tf.err())
+ return -1;
+
+ Common::String line;
+ char tmpStr[kLineMax + 1];
+
+ int counter = 0;
+
+ for (line = tf.readLine(); !tf.eos(); line = tf.readLine()) {
+ char *s;
+ assert(line.size() <= 513);
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ if ((s = strtok(tmpStr, " =,;/\t\n")) == NULL)
+ continue;
+ if (!Common::isDigit(*s))
+ continue;
+
+ counter++;
+ }
+ return counter;
+}
+
+void Text::clear() {
+ for (Handler *p = _cache, *q = p + _size; p < q; p++) {
+ if (p->_ref) {
+ p->_ref = 0;
+ delete[] p->_text;
+ p->_text = NULL;
+ }
+ }
+}
+
+void Text::load() {
+ EncryptedStream tf(_vm, _fileName);
+ assert(!tf.err());
+
+ Common::String line;
+ char tmpStr[kLineMax + 1];
+ int idx;
+
+ for (idx = 0, line = tf.readLine(); !tf.eos(); line = tf.readLine()) {
+ int n = line.size();
+ char *s;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ if ((s = strtok(tmpStr, " =,;/\t\n")) == NULL)
+ continue;
+ if (!Common::isDigit(*s))
+ continue;
+
+ int r = _vm->number(s);
+
+ s += strlen(s);
+ if (s < tmpStr + n)
+ ++s;
+
+ _cache[idx]._ref = r;
+ _cache[idx]._text = new char[strlen(s) + 1];
+ strcpy(_cache[idx]._text, s);
+ idx++;
+ }
+}
+
+char *Text::getText(int ref) {
+ int i;
+ for (i = 0; (i < _size) && (_cache[i]._ref != ref); i++)
+ ;
+
+ if (i < _size)
+ return _cache[i]._text;
+
+ warning("getText: Unable to find ref %d", ref);
+ return NULL;
+}
+
+void Text::say(const char *text, Sprite *spr) {
+ warning("STUB: Text::say()");
+}
+
+void CGE2Engine::inf(const char *text, bool wideSpace) {
+ warning("STUB: CGE2Engine::inf()");
+}
+
+void Text::sayTime(Sprite *spr) {
+ TimeDate curTime;
+ _vm->_system->getTimeAndDate(curTime);
+
+ char t[6];
+ sprintf(t, "%d:%02d", curTime.tm_hour, curTime.tm_min);
+ say(t, spr);
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/text.h b/engines/cge2/text.h
new file mode 100644
index 0000000000..bca774357a
--- /dev/null
+++ b/engines/cge2/text.h
@@ -0,0 +1,67 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_TEXT_H
+#define CGE2_TEXT_H
+
+#include "cge2/talk.h"
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+#define kSayExt ".SAY"
+#define kSysTextMax 1000
+#define kTextNoMouse 95
+#define kInfName 101
+#define kSayName 102
+#define kInfRef 301
+#define kSayRef 302
+
+
+class Text {
+ struct Handler {
+ int _ref;
+ char *_text;
+ } *_cache;
+ int _size;
+ char _fileName[kPathMax];
+ void load();
+ int16 count();
+public:
+ Text(CGE2Engine *vm, const char *fname);
+ ~Text();
+ void clear();
+ char *getText(int ref);
+ void say(const char *text, Sprite *spr);
+ void sayTime(Sprite *spr);
+private:
+ CGE2Engine *_vm;
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_TEXT_H
diff --git a/engines/cge2/vga13h.cpp b/engines/cge2/vga13h.cpp
new file mode 100644
index 0000000000..618fb8a987
--- /dev/null
+++ b/engines/cge2/vga13h.cpp
@@ -0,0 +1,1182 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#include "common/array.h"
+#include "common/config-manager.h"
+#include "common/rect.h"
+#include "graphics/palette.h"
+#include "cge2/general.h"
+#include "cge2/vga13h.h"
+#include "cge2/bitmap.h"
+#include "cge2/text.h"
+#include "cge2/cge2_main.h"
+#include "cge2/cge2.h"
+#include "cge2/vga13h.h"
+
+namespace CGE2 {
+
+Seq *getConstantSeq(bool seqFlag) {
+ const Seq seq1[] = { { 0, 0, 0, 0, 0 } };
+ const Seq seq2[] = { { 0, 1, 0, 0, 0 }, { 1, 0, 0, 0, 0 } };
+
+ Seq *seq;
+ if (seqFlag) {
+ seq = (Seq *)malloc(1 * sizeof(Seq));
+ *seq = seq1[0];
+ } else {
+ seq = (Seq *)malloc(2 * sizeof(Seq));
+ seq[0] = seq2[0];
+ seq[1] = seq2[1];
+ }
+
+ return seq;
+}
+
+void(*Sprite::notify) (void) = nullptr;
+
+byte Sprite::_constY = 0;
+byte Sprite::_follow = 0;
+
+Seq Sprite::_stdSeq8[] =
+{ { 0, 0, 0, 0, 0, 0 },
+ { 1, 1, 0, 0, 0, 0 },
+ { 2, 2, 0, 0, 0, 0 },
+ { 3, 3, 0, 0, 0, 0 },
+ { 4, 4, 0, 0, 0, 0 },
+ { 5, 5, 0, 0, 0, 0 },
+ { 6, 6, 0, 0, 0, 0 },
+ { 7, 7, 0, 0, 0, 0 },
+};
+
+SprExt::SprExt(CGE2Engine *vm)
+ : _p0(vm, 0, 0), _p1(vm, 0, 0),
+ _b0(NULL), _b1(NULL), _shpList(NULL),
+ _location(0), _seq(NULL), _name(NULL) {
+ for (int i = 0; i < kActions; i++)
+ _actions[i] = nullptr;
+}
+
+Sprite::Sprite(CGE2Engine *vm)
+ : _siz(_vm, 0, 0), _seqPtr(kNoSeq), _seqCnt(0), _shpCnt(0),
+ _next(NULL), _prev(NULL), _time(0),
+ _ext(NULL), _ref(-1), _scene(0), _vm(vm),
+ _pos2D(_vm, kScrWidth >> 1, 0), _pos3D(kScrWidth >> 1, 0, 0) {
+ memset(_actionCtrl, 0, sizeof(_actionCtrl));
+ memset(_file, 0, sizeof(_file));
+ memset(&_flags, 0, sizeof(_flags));
+ _flags._frnt = 1;
+}
+
+Sprite::Sprite(CGE2Engine *vm, BitmapPtr *shpP, int cnt)
+ : _siz(_vm, 0, 0), _seqPtr(kNoSeq), _seqCnt(0), _shpCnt(0),
+ _next(NULL), _prev(NULL), _time(0),
+ _ext(NULL), _ref(-1), _scene(0), _vm(vm),
+ _pos2D(_vm, kScrWidth >> 1, 0), _pos3D(kScrWidth >> 1, 0, 0) {
+ memset(_actionCtrl, 0, sizeof(_actionCtrl));
+ memset(_file, 0, sizeof(_file));
+ memset(&_flags, 0, sizeof(_flags));
+ _flags._frnt = 1;
+
+ setShapeList(shpP, cnt);
+}
+
+Sprite::~Sprite() {
+ if (_vm->_sprite == this)
+ _vm->_sprite = NULL;
+
+ contract();
+}
+
+BitmapPtr Sprite::shp() {
+ SprExt *e = _ext;
+ if (!e || !e->_seq)
+ return NULL;
+
+ int i = e->_seq[_seqPtr]._now;
+ if (i >= _shpCnt)
+ error("Invalid PHASE in SPRITE::Shp() %s", _file);
+ return e->_shpList[i];
+}
+
+void Sprite::setShapeList(BitmapPtr *shp, int cnt) {
+ _shpCnt = cnt;
+ _siz.x = 0;
+ _siz.y = 0;
+
+ if (shp) {
+ for (int i = 0; i < cnt; i++) {
+ BitmapPtr p = *shp + i;
+ if (p->_w > _siz.x)
+ _siz.x = p->_w;
+ if (p->_h > _siz.y)
+ _siz.y = p->_h;
+ }
+ expand();
+ _ext->_shpList = shp;
+ if (!_ext->_seq) {
+ setSeq(_stdSeq8);
+ _seqCnt = (cnt < ARRAYSIZE(_stdSeq8)) ? cnt : ARRAYSIZE(_stdSeq8);
+ }
+ }
+}
+
+bool Sprite::works(Sprite *spr) {
+ //if (!spr || !spr->_ext)
+ // return false;
+
+ //CommandHandler::Command *c = spr->_ext->_take;
+ //if (c != NULL) {
+ // c += spr->_takePtr;
+ // if (c->_ref == _ref)
+ // if (c->_commandType != kCmdLabel || (c->_val == 0 || c->_val == _vm->_now))
+ // return true;
+ //}
+
+ warning("STUB: Sprite::works()");
+
+ return false;
+}
+
+Seq *Sprite::setSeq(Seq *seq) {
+ expand();
+
+ Seq *s = _ext->_seq;
+ _ext->_seq = seq;
+ if (_seqPtr == kNoSeq)
+ 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;
+}
+
+void Sprite::setName(char *newName) {
+ if (!_ext)
+ return;
+
+ if (_ext->_name) {
+ delete[] _ext->_name;
+ _ext->_name = NULL;
+ }
+ if (newName) {
+ _ext->_name = new char[strlen(newName) + 1];
+ assert(_ext->_name != NULL);
+ strcpy(_ext->_name, newName);
+ }
+}
+
+int Sprite::labVal(Action snq, int lab) {
+ warning("STUB: Sprite::labVal()");
+ return 0;
+}
+
+CommandHandler::Command *Sprite::snList(Action type) {
+ SprExt *e = _ext;
+ return (e) ? e->_actions[type] : NULL;
+}
+
+Sprite *Sprite::expand() {
+ if (_ext)
+ return this;
+
+ if (notify != nullptr)
+ notify();
+
+ _ext = new SprExt(_vm);
+ assert(_ext != NULL);
+
+ if (!*_file)
+ return this;
+
+ Common::Array<BitmapPtr> shplist;
+ for (int i = 0; i < _shpCnt; ++i)
+ shplist.push_back(NULL);
+
+ int cnt[kActions],
+ shpcnt = 0,
+ seqcnt = 0,
+ maxnow = 0,
+ maxnxt = 0;
+
+ char fname[kPathMax];
+ _vm->mergeExt(fname, _file, kSprExt);
+
+ Seq *seq;
+ if (_seqCnt) {
+ seq = new Seq[_seqCnt];
+ if (seq == NULL)
+ error("No core %s", fname);
+ } else
+ seq = nullptr;
+
+ for (int i = 0; i < kActions; i++)
+ cnt[i] = 0;
+
+ for (int i = 0; i < kActions; i++){
+ byte n = _actionCtrl[i]._cnt;
+ if (n) {
+ _ext->_actions[i] = new CommandHandler::Command[n];
+ if (_ext->_actions[i] == nullptr)
+ error("No core %s", fname);
+ } else
+ _ext->_actions[i] = nullptr;
+ }
+
+ if (_vm->_resman->exist(fname)) { // sprite description file exist
+ EncryptedStream sprf(_vm, fname);
+ if (sprf.err())
+ error("Bad SPR [%s]", fname);
+
+ int label = kNoByte;
+ ID section = kIdPhase;
+ ID id;
+ Common::String line;
+ char tmpStr[kLineMax + 1];
+
+ for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()){
+ if (line.size() == 0)
+ continue;
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+
+ char *p = _vm->token(tmpStr);
+ if (*p == '@') {
+ label = atoi(p + 1);
+ continue;
+ }
+
+ id = _vm->ident(p);
+ switch (id) {
+ case kIdType:
+ break;
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ case kIdPhase:
+ case kIdSeq:
+ section = id;
+ break;
+ case kIdName:
+ Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr));
+ for (p = tmpStr; *p != '='; p++); // We search for the =
+ setName(_vm->tail(p));
+ break;
+ default:
+ if (id >= kIdNear)
+ break;
+ Seq *s;
+ switch (section) {
+ case kIdNear:
+ case kIdMTake:
+ case kIdFTake:
+ id = (ID)_vm->_commandHandler->com(p);
+ if (_actionCtrl[section]._cnt) {
+ CommandHandler::Command *c = &_ext->_actions[section][cnt[section]++];
+ c->_commandType = CommandType(id);
+ c->_lab = label;
+ if ((p = _vm->token(nullptr)) == NULL)
+ error("Unexpected end of file! %s", fname);
+ c->_ref = _vm->number(p);
+ if ((p = _vm->token(nullptr)) == NULL)
+ error("Unexpected end of file! %s", fname);
+ c->_val = _vm->number(p);
+ c->_spritePtr = nullptr;
+ }
+ break;
+ case kIdSeq:
+ s = &seq[seqcnt++];
+ s->_now = atoi(p);
+ if (s->_now > maxnow)
+ maxnow = s->_now;
+ if ((p = _vm->token(nullptr)) == NULL)
+ break;
+ s->_next = _vm->number(p);
+ switch (s->_next) {
+ case 0xFF:
+ s->_next = seqcnt;
+ break;
+ case 0xFE:
+ s->_next = seqcnt - 1;
+ break;
+ }
+ if (s->_next > maxnxt)
+ maxnxt = s->_next;
+ if ((p = _vm->token(nullptr)) == NULL)
+ error("Unexpected end of file! %s", fname);
+ s->_dx = _vm->number(p);
+ if ((p = _vm->token(nullptr)) == NULL)
+ error("Unexpected end of file! %s", fname);
+ s->_dy = _vm->number(p);
+ if ((p = _vm->token(nullptr)) == NULL)
+ error("Unexpected end of file! %s", fname);
+ s->_dz = _vm->number(p);
+ if ((p = _vm->token(nullptr)) == NULL)
+ error("Unexpected end of file! %s", fname);
+ s->_dly = _vm->number(p);
+ break;
+ case kIdPhase:
+ BitmapPtr bmp = new Bitmap(_vm, p);
+ shplist[shpcnt] = bmp;
+ if (!shplist[shpcnt]->moveHi())
+ error("No EMS");
+ shpcnt++;
+ break;
+ }
+ break;
+ }
+ label = kNoByte;
+ }
+
+ if (!shpcnt)
+ error("No shapes - %s", fname);
+ } else // no sprite description: try to read immediately from .BMP
+ shplist[shpcnt++] = new Bitmap (_vm, _file);
+
+ if (seq) {
+ if (maxnow >= shpcnt)
+ error("Bad PHASE in SEQ %s", fname);
+ if (maxnxt && maxnxt >= seqcnt)
+ error("Bad JUMP in SEQ %s", fname);
+ setSeq(seq);
+ } else {
+ setSeq(_stdSeq8);
+ _seqCnt = (shpcnt < ARRAYSIZE(_stdSeq8)) ? shpcnt : ARRAYSIZE(_stdSeq8);
+ }
+
+ // Set the shape list
+ BitmapPtr *shapeList = new BitmapPtr[shplist.size()];
+ for (uint i = 0; i < shplist.size(); ++i)
+ shapeList[i] = shplist[i];
+
+ setShapeList(shapeList, shpcnt);
+
+ if (_file[2] == '~') { // FLY-type sprite
+ Seq *seq = _ext->_seq;
+ int x = (seq + 1)->_dx, y = (seq + 1)->_dy, z = (seq + 1)->_dz;
+ // random position
+ seq->_dx = _vm->newRandom(x + x) - x;
+ seq->_dy = _vm->newRandom(y + y) - y;
+ seq->_dz = _vm->newRandom(z + z) - z;
+ gotoxyz(_pos3D + V3D(seq->_dx, seq->_dy, seq->_dz));
+ }
+
+ return this;
+}
+
+Sprite *Sprite::contract() {
+ SprExt *e = _ext;
+ if (!e)
+ return this;
+
+ if (_file[2] == '~') { // FLY-type sprite
+ Seq *seq = _ext->_seq;
+ // return to middle
+ gotoxyz(_pos3D - V3D(seq->_dx, seq->_dy, seq->_dz));
+ seq->_dx = seq->_dy = seq->_dz = 0;
+ }
+
+ if (notify)
+ notify();
+
+ if (e->_name)
+ delete[] e->_name;
+
+ if (e->_shpList) {
+ for (int i = 0; i < _shpCnt; i++)
+ e->_shpList[i]->release();
+ delete[] e->_shpList;
+ }
+
+ if (e->_seq) {
+ if (e->_seq == _stdSeq8)
+ _seqCnt = 0;
+ else
+ delete[] e->_seq;
+ }
+
+ for (int i = 0; i < kActions; i++)
+ if (e->_actions[i])
+ delete[] e->_actions[i];
+
+ _ext = nullptr;
+
+ return this;
+}
+
+void Sprite::backShow(void) {
+ expand();
+ show(2);
+ show(1);
+ _vm->_spare->dispose(this);
+}
+
+void Sprite::step(int nr) {
+ if (nr >= 0)
+ _seqPtr = nr;
+
+ if (_ext) {
+ V3D p = _pos3D;
+ Seq *seq = nullptr;
+
+ if (nr < 0)
+ _seqPtr = _ext->_seq[_seqPtr]._next;
+
+ if (_file[2] == '~') { // FLY-type sprite
+ warning("STUB: Sprite::step() - FLY-type sprite");
+ } else {
+ seq = _ext->_seq + _seqPtr;
+ if (seq->_dz == 127 && seq->_dx != 0) {
+ _vm->_commandHandlerTurbo->addCommand(kCmdSound, -1, 256 * seq->_dy + seq->_dx, this);
+ } else {
+ p._x += seq->_dx;
+ p._y += seq->_dy;
+ p._z += seq->_dz;
+ //if (!_flags._kept)
+ // gotoxyz(p);
+ warning("STUB: Sprite::step()");
+ }
+ }
+ if (seq && (seq->_dly >= 0))
+ _time = seq->_dly;
+ } else if (_vm->_waitRef && _vm->_waitRef == _ref)
+ _vm->_waitRef = 0;
+}
+
+void Sprite::tick() {
+ step();
+}
+
+void Sprite::makeXlat(uint8 *x) {
+ if (!_ext)
+ return;
+
+ if (_flags._xlat)
+ killXlat();
+ for (BitmapPtr *b = _ext->_shpList; *b; b++)
+ (*b)->_m = x;
+ _flags._xlat = true;
+}
+
+void Sprite::killXlat() {
+ if (!_flags._xlat || !_ext)
+ return;
+
+ uint8 *m = (*_ext->_shpList)->_m;
+ free(m);
+
+ for (BitmapPtr *b = _ext->_shpList; *b; b++)
+ (*b)->_m = NULL;
+ _flags._xlat = false;
+}
+
+void Sprite::gotoxyz(int x, int y, int z) {
+ gotoxyz(V3D(x, y, z));
+}
+
+void Sprite::gotoxyz(void) {
+ gotoxyz(_pos3D);
+}
+
+void Sprite::gotoxyz(V2D pos) {
+ V2D o = _pos2D;
+ int ctr = _siz.x >> 1;
+ int rem = _siz.x - ctr;
+ byte trim = 0;
+
+ if (_ref / 10 == 14) { // HERO
+ int z = V2D::trunc(_pos3D._z);
+ ctr = (ctr * V2D::trunc(_vm->_eye->_z) / (V2D::trunc(_vm->_eye->_z) - z));
+ rem = (rem * V2D::trunc(_vm->_eye->_z) / (V2D::trunc(_vm->_eye->_z) - z));
+ ctr = (ctr * 3) / 4;
+ rem = (rem * 3) / 4;
+ }
+
+ if (pos.x - ctr < 0) {
+ pos.x = ctr;
+ ++trim;
+ }
+ if (pos.x + rem > kScrWidth) {
+ pos.x = kScrWidth - rem;
+ ++trim;
+ }
+ _pos2D.x = pos.x;
+
+ if (pos.y < -kPanHeight) {
+ pos.y = -kPanHeight;
+ ++trim;
+ }
+ if (pos.y + _siz.y > kWorldHeight) {
+ pos.y = kWorldHeight - _siz.y;
+ ++trim;
+ }
+ _pos2D.y = pos.y;
+
+ _flags._trim = (trim != 0);
+
+ if (!_follow) {
+ double m = _vm->_eye->_z / (_pos3D._z - _vm->_eye->_z);
+ _pos3D._x = (_vm->_eye->_x + V2D::round(_vm->_eye->_x - _pos2D.x) / m);
+ if (!_constY)
+ _pos3D._y = (_vm->_eye->_y + V2D::round(_vm->_eye->_y - _pos2D.y) / m);
+ }
+
+ if (_next && _next->_flags._slav)
+ _next->gotoxyz(_next->_pos2D - o + _pos2D);
+
+ if (_flags._shad)
+ _prev->gotoxyz(_prev->_pos2D - o + _pos2D);
+
+ if (_ref == 141 && _pos3D._y >= 5)
+ warning("Sprite::gotoxyz - asm nop");
+}
+
+void Sprite::gotoxyz_(V2D pos) {
+ _constY++;
+ gotoxyz(pos);
+ --_constY;
+}
+
+void Sprite::gotoxyz(V3D pos) {
+ _follow++;
+ if (pos._z != _pos3D._z)
+ _flags._zmov = true;
+ gotoxyz(V2D(_vm, _pos3D = pos));
+ --_follow;
+}
+
+void Sprite::center() {
+ gotoxyz(kScrWidth >> 1, (kWorldHeight - _siz.y) >> 1, 0);
+}
+
+void Sprite::show() {
+ SprExt *e = _ext;
+ if (e) {
+ e->_p0 = e->_p1;
+ e->_b0 = e->_b1;
+ e->_p1 = _pos2D;
+ e->_b1 = shp();
+ }
+ if (!_flags._hide)
+ e->_b1->show(e->_p1.x, e->_p1.y);
+}
+
+void Sprite::show(uint16 pg) {
+ Graphics::Surface *a = _vm->_vga->_page[1];
+ _vm->_vga->_page[1] = _vm->_vga->_page[pg];
+ shp()->show(_pos2D.x, _pos2D.y);
+ _vm->_vga->_page[1] = a;
+}
+
+void Sprite::hide() {
+ SprExt *e = _ext;
+ if (e->_b0)
+ e->_b0->hide(e->_p0.x, e->_p0.y);
+}
+
+BitmapPtr Sprite::ghost() {
+ SprExt *e = _ext;
+ if (!e->_b1)
+ return nullptr;
+
+ BitmapPtr bmp = new Bitmap(_vm, 0, 0, (uint8 *)nullptr);
+ assert(bmp != nullptr);
+ bmp->_w = e->_b1->_w;
+ bmp->_h = e->_b1->_h;
+ bmp->_b = new HideDesc[bmp->_h];
+ assert(bmp->_b != nullptr);
+ memcpy(bmp->_b, e->_b1->_b, sizeof(HideDesc)* bmp->_h);
+ uint8 *v = new uint8;
+ *v = (e->_p1.y << 16) + e->_p1.x;
+ bmp->_v = v;
+
+ return bmp;
+}
+
+void Sprite::sync(Common::Serializer &s) {
+ uint16 unused = 0;
+
+ s.syncAsUint16LE(unused);
+ s.syncAsUint16LE(unused); // _ext
+ s.syncAsUint16LE(_ref);
+ s.syncAsByte(_scene);
+
+ // bitfield in-memory storage is unpredictable, so to avoid
+ // any issues, pack/unpack everything manually
+ uint16 flags = 0;
+ if (s.isLoading()) {
+ s.syncAsUint16LE(flags);
+ _flags._hide = flags & 0x0001 ? true : false;
+ _flags._near = flags & 0x0002 ? true : false;
+ _flags._drag = flags & 0x0004 ? true : false;
+ _flags._hold = flags & 0x0008 ? true : false;
+ //_flags._dummy = flags & 0x0010 ? true : false;
+ _flags._slav = flags & 0x0020 ? true : false;
+ //_flags._syst = flags & 0x0040 ? true : false;
+ _flags._kill = flags & 0x0080 ? true : false;
+ _flags._xlat = flags & 0x0100 ? true : false;
+ _flags._port = flags & 0x0200 ? true : false;
+ _flags._kept = flags & 0x0400 ? true : false;
+ _flags._east = flags & 0x0800 ? true : false;
+ _flags._shad = flags & 0x1000 ? true : false;
+ _flags._back = flags & 0x2000 ? true : false;
+ //_flags._bDel = flags & 0x4000 ? true : false;
+ _flags._tran = flags & 0x8000 ? true : false;
+ } else {
+ flags = (flags << 1) | _flags._tran;
+ //flags = (flags << 1) | _flags._bDel;
+ flags = (flags << 1) | _flags._back;
+ flags = (flags << 1) | _flags._shad;
+ flags = (flags << 1) | _flags._east;
+ flags = (flags << 1) | _flags._kept;
+ flags = (flags << 1) | _flags._port;
+ flags = (flags << 1) | _flags._xlat;
+ flags = (flags << 1) | _flags._kill;
+ //flags = (flags << 1) | _flags._syst;
+ flags = (flags << 1) | _flags._slav;
+ //flags = (flags << 1) | _flags._dummy;
+ flags = (flags << 1) | _flags._hold;
+ flags = (flags << 1) | _flags._drag;
+ flags = (flags << 1) | _flags._near;
+ flags = (flags << 1) | _flags._hide;
+ s.syncAsUint16LE(flags);
+ }
+
+ warning("STUB: Sprite::sync() - Flags changed compared to CGE1's Sprite type.");
+
+ s.syncAsUint16LE(_pos3D._x);
+ s.syncAsUint16LE(_pos3D._y);
+ s.syncAsByte(_pos3D._z);
+ s.syncAsUint16LE(_time);
+ s.syncAsSint16LE(_seqPtr);
+ s.syncAsUint16LE(_shpCnt);
+ s.syncBytes((byte *)&_file[0], 9);
+ _file[8] = '\0';
+
+ s.syncAsUint16LE(unused); // _prev
+ s.syncAsUint16LE(unused); // _next
+}
+
+Queue::Queue(bool show) : _head(NULL), _tail(NULL) {
+}
+
+Queue::~Queue() {
+ clear();
+}
+
+void Queue::clear() {
+ while (_head) {
+ Sprite *s = remove(_head);
+ if (s->_flags._kill)
+ delete s;
+ }
+}
+
+void Queue::append(Sprite *spr) {
+ if (spr->_flags._back)
+ spr->backShow();
+ else {
+ spr->expand();
+ if (_tail) {
+ spr->_prev = _tail;
+ _tail->_next = spr;
+ } else
+ _head = spr;
+
+ _tail = spr;
+ }
+}
+
+void Queue::insert(Sprite *spr, Sprite *nxt) {
+ if (spr->_flags._back)
+ spr->backShow();
+ else {
+ spr->expand();
+ 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;
+ }
+}
+
+void Queue::insert(Sprite *spr) {
+ Sprite *s;
+ for (s = _head; s; s = s->_next)
+ if (s->_pos3D._z < spr->_pos3D._z)
+ break;
+
+ if (s)
+ insert(spr, s);
+ else
+ append(spr);
+}
+
+template<typename T>
+inline bool contains(const Common::List<T> &l, const T &v) {
+ return (Common::find(l.begin(), l.end(), v) != l.end());
+}
+
+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) {
+ for (Sprite *spr = _head; spr; spr = spr->_next) {
+ if (spr->_ref == ref)
+ return spr;
+ }
+ return NULL;
+}
+
+bool Queue::locate(Sprite *spr) {
+ Sprite *s;
+ for (s = _head; s; s = s->_next)
+ if (s == spr)
+ return true;
+ return false;
+}
+
+Vga::Vga(CGE2Engine *vm) : _frmCnt(0), _msg(NULL), _name(NULL), _setPal(false), _mono(0), _vm(vm) {
+ _oldColors = NULL;
+ _newColors = NULL;
+ _showQ = new Queue(true);
+ _spareQ = new Queue(false);
+ _sysPal = new Dac[kPalCount];
+
+ for (int idx = 0; idx < 4; idx++) {
+ _page[idx] = new Graphics::Surface();
+ _page[idx]->create(kScrWidth, kScrHeight, Graphics::PixelFormat::createFormatCLUT8());
+ }
+
+ /*if (ConfMan.getBool("enable_color_blind"))
+ _mono = 1;*/
+
+ warning("STUB: Vga::Vga()");
+
+ _oldColors = (Dac *)malloc(sizeof(Dac) * kPalCount);
+ _newColors = (Dac *)malloc(sizeof(Dac) * kPalCount);
+ getColors(_oldColors);
+ sunset();
+ setColors();
+ clear(0);
+}
+
+Vga::~Vga() {
+ _mono = 0;
+
+ Common::String buffer = "";
+/*
+ clear(0);
+ setMode(_oldMode);
+ setColors();
+ restoreScreen(_oldScreen);
+ sunrise(_oldColors);
+*/
+ warning("STUB: Vga::~Vga()");
+
+ free(_oldColors);
+ free(_newColors);
+ if (_msg)
+ buffer = Common::String(_msg);
+ if (_name)
+ buffer = buffer + " [" + _name + "]";
+
+ debugN("%s", buffer.c_str());
+
+ delete _showQ;
+ delete _spareQ;
+ delete[] _sysPal;
+
+ for (int idx = 0; idx < 4; idx++) {
+ _page[idx]->free();
+ delete _page[idx];
+ }
+}
+
+void Vga::waitVR() {
+ // 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(5);
+}
+
+void Vga::getColors(Dac *tab) {
+ byte palData[kPalSize];
+ g_system->getPaletteManager()->grabPalette(palData, 0, kPalCount);
+ palToDac(palData, tab);
+}
+
+uint8 Vga::closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB) {
+#define f(col, lum) ((((uint16)(col)) << 8) / lum)
+ uint16 i, dif = 0xFFFF, found = 0;
+ uint16 L = colR + colG + colB;
+ if (!L)
+ L++;
+ uint16 R = f(colR, L), G = f(colG, L), B = f(colB, 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
+}
+
+uint8 *Vga::glass(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB) {
+ uint8 *x = (uint8 *)malloc(256);
+ if (x) {
+ uint16 i;
+ for (i = 0; i < 256; i++) {
+ x[i] = closest(pal, ((uint16)(pal[i]._r) * colR) / 255,
+ ((uint16)(pal[i]._g) * colG) / 255,
+ ((uint16)(pal[i]._b) * colB) / 255);
+ }
+ }
+ return x;
+}
+
+void Vga::palToDac(const byte *palData, Dac *tab) {
+ const byte *colP = palData;
+ for (int idx = 0; idx < kPalCount; 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 < kPalCount; 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 < kPalCount; 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 < kPalCount; idx++, destP++) {
+ // Form a greyscalce color from 30% R, 59% G, 11% B
+ uint8 intensity = (((int)destP->_r * 77) + ((int)destP->_g * 151) + ((int)destP->_b * 28)) >> 8;
+ destP->_r = intensity;
+ destP->_g = intensity;
+ destP->_b = intensity;
+ }
+ }
+
+ _setPal = true;
+}
+
+void Vga::setColors() {
+ memset(_newColors, 0, kPalSize);
+ updateColors();
+}
+
+void Vga::sunrise(Dac *tab) {
+ for (int i = 0; i <= 64; i += kFadeStep) {
+ setColors(tab, i);
+ waitVR();
+ updateColors();
+ }
+}
+
+void Vga::sunset() {
+ Dac tab[256];
+ getColors(tab);
+ for (int i = 64; i >= 0; i -= kFadeStep) {
+ setColors(tab, i);
+ waitVR();
+ updateColors();
+ }
+}
+
+void Vga::show() {
+ for (Sprite *spr = _showQ->first(); spr; spr = spr->_next)
+ spr->show();
+ update();
+ for (Sprite *spr = _showQ->first(); spr; spr = spr->_next)
+ spr->hide();
+
+ _frmCnt++;
+}
+
+void Vga::updateColors() {
+ byte palData[kPalSize];
+ 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;
+ }
+ /*if (_vm->_showBoundariesFl) {
+ Vga::_page[0]->hLine(0, 200 - kPanHeight, 320, 0xee);
+ if (_vm->_barriers[_vm->_now]._horz != 255) {
+ for (int i = 0; i < 8; i++)
+ Vga::_page[0]->vLine((_vm->_barriers[_vm->_now]._horz * 8) + i, 0, 200, 0xff);
+ }
+ if (_vm->_barriers[_vm->_now]._vert != 255) {
+ for (int i = 0; i < 4; i++)
+ Vga::_page[0]->hLine(0, 80 + (_vm->_barriers[_vm->_now]._vert * 4) + i, 320, 0xff);
+ }
+ }*/
+
+ warning("STUB: Vga::update()");
+
+ g_system->copyRectToScreen(Vga::_page[0]->getPixels(), kScrWidth, 0, 0, kScrWidth, kScrHeight);
+ g_system->updateScreen();
+}
+
+void Vga::clear(uint8 color) {
+ for (int paneNum = 0; paneNum < 4; paneNum++)
+ _page[paneNum]->fillRect(Common::Rect(0, 0, kScrWidth, kScrHeight), color);
+}
+
+void Vga::copyPage(uint16 d, uint16 s) {
+ _page[d]->copyFrom(*_page[s]);
+}
+
+//--------------------------------------------------------------------------
+
+void Bitmap::xShow(int16 x, int16 y) {
+ const byte *srcP = (const byte *)_v;
+ byte *destEndP = (byte *)_vm->_vga->_page[1]->getBasePtr(0, kScrHeight);
+ byte *lookupTable = _m;
+
+ // 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 *)_vm->_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);
+
+ if (cmd == 2)
+ srcP++;
+ else if (cmd == 3)
+ srcP += count;
+
+ // Handle a set of pixels
+ while (count-- > 0) {
+ // Transfer operation
+ switch (cmd) {
+ case 1:
+ // SKIP
+ break;
+ case 2:
+ case 3:
+ // TINT
+ *destP = lookupTable[*destP];
+ break;
+ }
+
+ // Move to next dest position
+ destP += 4;
+ }
+ }
+ }
+}
+
+
+void Bitmap::show(int16 x, int16 y) {
+ V2D pos(_vm, x, y);
+ xLatPos(pos);
+ x = pos.x;
+ y = pos.y;
+ const byte *srcP = (const byte *)_v;
+ byte *destEndP = (byte *)_vm->_vga->_page[1]->getBasePtr(0, kScrHeight);
+
+ // 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 *)_vm->_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++;
+ }
+ }
+}
+
+
+void Bitmap::hide(int16 x, int16 y) {
+ V2D pos(_vm, x, y);
+ xLatPos(pos);
+ x = pos.x;
+ y = pos.y;
+ for (int yp = y; yp < y + _h; yp++) {
+ const byte *srcP = (const byte *)_vm->_vga->_page[2]->getBasePtr(x, yp);
+ byte *destP = (byte *)_vm->_vga->_page[1]->getBasePtr(x, yp);
+
+ Common::copy(srcP, srcP + _w, destP);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+HorizLine::HorizLine(CGE2Engine *vm) : Sprite(vm), _vm(vm) {
+ // Set the sprite list
+ BitmapPtr *HL = new BitmapPtr[2];
+ HL[0] = new Bitmap(_vm, "HLINE");
+ HL[1] = NULL;
+
+ setShapeList(HL, 1);
+
+ warning("HorizLine::HorizLine() - Recheck this!");
+}
+
+SceneLight::SceneLight(CGE2Engine *vm) : Sprite(vm), _vm(vm) {
+ // Set the sprite list
+ BitmapPtr *PR = new BitmapPtr[2];
+ PR[0] = new Bitmap(_vm, "PRESS");
+ PR[1] = NULL;
+
+ setShapeList(PR, 1);
+
+ warning("SceneLight::SceneLight() - Recheck this!");
+}
+
+Speaker::Speaker(CGE2Engine *vm): Sprite(vm), _vm(vm) {
+ // Set the sprite list
+ BitmapPtr *SP = new BitmapPtr[3];
+ SP[0] = new Bitmap(_vm, "SPK_L");
+ SP[1] = new Bitmap(_vm, "SPK_R");
+ SP[2] = NULL;
+
+ setShapeList(SP, 2);
+
+ warning("Speaker::Speaker() - Recheck this!");
+}
+
+PocLight::PocLight(CGE2Engine *vm): Sprite(vm), _vm(vm) {
+ // Set the sprite list
+ BitmapPtr *LI = new BitmapPtr[5];
+ LI[0] = new Bitmap(_vm, "LITE0");
+ LI[1] = new Bitmap(_vm, "LITE1");
+ LI[2] = new Bitmap(_vm, "LITE2");
+ LI[3] = new Bitmap(_vm, "LITE3");
+ LI[4] = NULL;
+
+ setShapeList(LI, 4);
+
+ _flags._kill = false;
+
+ warning("PocLight::PocLight() - Recheck this!");
+}
+
+} // End of namespace CGE2
diff --git a/engines/cge2/vga13h.h b/engines/cge2/vga13h.h
new file mode 100644
index 0000000000..20d97ee4eb
--- /dev/null
+++ b/engines/cge2/vga13h.h
@@ -0,0 +1,295 @@
+/* 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 Sfinx source code
+ * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
+ */
+
+#ifndef CGE2_VGA13H_H
+#define CGE2_VGA13H_H
+
+#include "common/serializer.h"
+#include "common/events.h"
+#include "graphics/surface.h"
+#include "cge2/general.h"
+#include "cge2/bitmap.h"
+#include "cge2/snail.h"
+#include "cge2/spare.h"
+#include "cge2/cge2.h"
+
+namespace CGE2 {
+
+#define kFadeStep 2
+#define kVgaColDark 207
+#define kVgaColDarkGray 225 /*219*/
+#define kVgaColGray 231
+#define kVgaColLightGray 237
+#define kPixelTransp 0xFE
+#define kNoSeq (-1)
+#define kNoPtr ((uint8)-1)
+#define kSprExt ".SPR"
+#define kPalCount 256
+#define kPalSize (kPalCount * 3)
+
+// From CGETYPE.H:
+class V3D {
+public:
+ double _x, _y, _z;
+ V3D(void) { }
+ V3D(double x, double y, double z = 0) : _x(x), _y(y), _z(z) { }
+ V3D(const V3D &p) : _x(p._x), _y(p._y), _z(p._z) { }
+ V3D operator+(const V3D &p) const { return V3D(_x + p._x, _y + p._y, _z + p._z); }
+ V3D operator-(const V3D &p) const { return V3D(_x - p._x, _y - p._y, _z - p._z); }
+ V3D operator*(long n) const { return V3D(_x * n, _y * n, _z * n); }
+ V3D operator/ (long n) const { return V3D(_x / n, _y / n, _z / n); }
+ bool operator==(V3D &p) const { return _x == p._x && _y == p._y && _z == p._z; }
+ bool operator!=(V3D &p) const { return _x != p._x || _y != p._y || _z != p._z; }
+ V3D& operator+=(const V3D &x) { return *this = *this + x; }
+ V3D& operator-=(const V3D &x) { return *this = *this - x; }
+};
+
+class V2D : public Common::Point {
+ CGE2Engine *_vm;
+public:
+ V2D& operator=(const V3D &p3) {
+ double m = _vm->_eye->_z / (p3._z - _vm->_eye->_z);
+ x = round((_vm->_eye->_x + (_vm->_eye->_x - p3._x) * m));
+ y = round((_vm->_eye->_y + (_vm->_eye->_y - p3._y) * m));
+ return *this;
+ }
+ V2D(CGE2Engine *vm) : _vm(vm) { }
+ V2D(CGE2Engine *vm, const V3D &p3) : _vm(vm) { *this = p3; }
+ V2D(CGE2Engine *vm, int x, int y) : _vm(vm), Common::Point(x, y) { }
+ bool operator<(const V2D &p) const { return (x < p.x) && (y < p.y); }
+ bool operator<=(const V2D &p) const { return (x <= p.x) && (y <= p.y); }
+ bool operator>(const V2D &p) const { return (x > p.x) && (y > p.y); }
+ bool operator>=(const V2D &p) const { return (x >= p.x) && (y >= p.y); }
+ V2D operator+(const V2D &p) const { return V2D(_vm, x + p.x, y + p.y); }
+ V2D operator-(const V2D &p) const { return V2D(_vm, x - p.x, y - p.y); }
+ uint16 area(void) { return x * y; }
+ bool limited(const V2D &p) {
+ return (uint16(x) < uint16(p.x)) && (uint16(y) < uint16(p.y));
+ }
+ V2D scale(int z) {
+ double m = _vm->_eye->_z / (_vm->_eye->_z - z);
+ return V2D(_vm, trunc(m * x), trunc(m * y));
+ }
+ static double trunc(double d) { return (d > 0) ? floor(d) : ceil(d); }
+ static double round(double number) { return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5); }
+};
+
+struct Seq {
+ uint8 _now;
+ uint8 _next;
+ int8 _dx;
+ int8 _dy;
+ int8 _dz;
+ int _dly;
+};
+
+class SprExt {
+public:
+ V2D _p0;
+ V2D _p1;
+ BitmapPtr _b0;
+ BitmapPtr _b1;
+ BitmapPtr *_shpList;
+ int _location;
+ Seq *_seq;
+ char *_name;
+ CommandHandler::Command *_actions[kActions];
+ SprExt(CGE2Engine *vm);
+};
+
+class Sprite {
+protected:
+ SprExt *_ext;
+ CGE2Engine *_vm;
+public:
+ int _ref;
+ signed char _scene;
+ struct Flags {
+ uint16 _hide : 1; // general visibility switch
+ uint16 _drag : 1; // sprite is moveable
+ uint16 _hold : 1; // sprite is held with mouse
+ uint16 _trim : 1; // Trim flag
+ uint16 _slav : 1; // slave 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 _frnt : 1; // stay in front of sprite
+ uint16 _east : 1; // talk to east (in opposite to west)
+ uint16 _near : 1; // Near action lock
+ uint16 _shad : 1; // shadow
+ uint16 _back : 1; // 'send to background' request
+ uint16 _zmov : 1; // sprite needs Z-update in queue
+ uint16 _tran : 1; // transparent (untouchable)
+ } _flags;
+ V2D _pos2D;
+ V3D _pos3D;
+ V2D _siz;
+ uint16 _time;
+ struct { byte _ptr, _cnt; } _actionCtrl[kActions];
+ int _seqPtr;
+ int _seqCnt;
+ int _shpCnt;
+ char _file[kMaxFile];
+ // Following trailer is not saved with the game:
+ Sprite *_prev;
+ Sprite *_next;
+ static byte _constY;
+ static byte _follow;
+ static Seq _stdSeq8[];
+
+ bool works(Sprite *spr);
+ bool seqTest(int n);
+ inline bool active() {
+ return _ext != NULL;
+ }
+ Sprite(CGE2Engine *vm);
+ Sprite(CGE2Engine *vm, BitmapPtr *shp, int cnt);
+ virtual ~Sprite();
+ BitmapPtr shp();
+ void setShapeList(BitmapPtr *shp, int cnt);
+ void moveShapesHi(void);
+ void moveShapesLo(void);
+ int labVal(Action snq, int lab);
+ Sprite *expand();
+ Sprite *contract();
+ void backShow(void);
+ void setName(char *newName);
+ inline char *name() {
+ return (_ext) ? _ext->_name : NULL;
+ }
+ void gotoxyz(int x, int y, int z = 0);
+ void gotoxyz(void);
+ void gotoxyz(V2D pos);
+ void gotoxyz_(V2D pos);
+ void gotoxyz(V3D pos);
+ void center();
+ void show(uint16 pg);
+ void hide(uint16 pg);
+ void show();
+ void hide();
+ BitmapPtr ghost();
+ void makeXlat(uint8 *x);
+ void killXlat();
+ void step(int nr = -1);
+ Seq *setSeq(Seq *seq);
+ CommandHandler::Command *snList(Action type);
+ //virtual void touch(uint16 mask, int x, int y, Common::KeyCode keyCode);
+ virtual void tick();
+ void clrHide(void) { if (_ext) _ext->_b0 = NULL; }
+ void sync(Common::Serializer &s);
+
+ static void (*notify) (void);
+};
+
+class Queue {
+ Sprite *_head;
+ Sprite *_tail;
+public:
+ Queue(bool show);
+ ~Queue();
+
+ void append(Sprite *spr);
+ void insert(Sprite *spr, Sprite *nxt);
+ void insert(Sprite *spr);
+ Sprite *remove(Sprite *spr);
+ Sprite *first() {
+ return _head;
+ }
+ Sprite *last() {
+ return _tail;
+ }
+ Sprite *locate(int ref);
+ bool locate(Sprite *spr);
+ void clear();
+};
+
+class Vga {
+ CGE2Engine *_vm;
+ bool _setPal;
+ Dac *_oldColors;
+ Dac *_newColors;
+ const char *_msg;
+ const char *_name;
+
+ void updateColors();
+ void setColors();
+ void waitVR();
+ uint8 closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB);
+
+public:
+ uint32 _frmCnt;
+ Queue *_showQ;
+ Queue *_spareQ;
+ int _mono;
+ Graphics::Surface *_page[4];
+ Dac *_sysPal;
+
+ Vga(CGE2Engine *vm);
+ ~Vga();
+
+ uint8 *glass(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB);
+ 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();
+
+ void palToDac(const byte *palData, Dac *tab);
+ void dacToPal(const Dac *tab, byte *palData);
+};
+
+class HorizLine: public Sprite {
+ CGE2Engine *_vm;
+public:
+ HorizLine(CGE2Engine *vm);
+};
+
+class SceneLight: public Sprite {
+ CGE2Engine *_vm;
+public:
+ SceneLight(CGE2Engine *vm);
+};
+
+class Speaker: public Sprite {
+ CGE2Engine *_vm;
+public:
+ Speaker(CGE2Engine *vm);
+};
+
+class PocLight: public Sprite {
+ CGE2Engine *_vm;
+public:
+ PocLight(CGE2Engine *vm);
+};
+
+} // End of namespace CGE2
+
+#endif // CGE2_VGA13H_H