diff options
51 files changed, 11625 insertions, 0 deletions
diff --git a/base/plugins.cpp b/base/plugins.cpp index 4413995b88..7dbbf9843d 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -94,6 +94,9 @@ public: #if PLUGIN_ENABLED_STATIC(AGOS) LINK_PLUGIN(AGOS) #endif + #if PLUGIN_ENABLED_STATIC(CGE) + LINK_PLUGIN(CGE) + #endif #if PLUGIN_ENABLED_STATIC(CINE) LINK_PLUGIN(CINE) #endif @@ -83,6 +83,7 @@ add_engine he "HE71+ games" yes add_engine agi "AGI" yes add_engine agos "AGOS" yes "agos2" add_engine agos2 "AGOS 2 games" yes +add_engine cge "CGE" no add_engine cine "Cinematique evo 1" yes add_engine cruise "Cinematique evo 2" yes add_engine draci "Dragon History" yes diff --git a/engines/cge/bitmap.cpp b/engines/cge/bitmap.cpp new file mode 100644 index 0000000000..4630f87456 --- /dev/null +++ b/engines/cge/bitmap.cpp @@ -0,0 +1,504 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/bitmap.h" +#include "cge/cfile.h" +#include "cge/jbw.h" +#include "cge/vol.h" +#include "cge/cfile.h" +#include "cge/vga13h.h" +#include "common/system.h" + +namespace CGE { + +Dac *Bitmap::_pal = NULL; +#define MAXPATH 128 + +void Bitmap::init() { + _pal = NULL; +} + +void Bitmap::deinit() { +} + +#pragma argsused +Bitmap::Bitmap(const char *fname, bool rem) : _m(NULL), _v(NULL) { + char pat[MAXPATH]; + forceExt(pat, fname, ".VBM"); + +#if (BMP_MODE < 2) + if (rem && PIC_FILE::exist(pat)) { + PIC_FILE file(pat); + if ((file._error == 0) && (!loadVBM(&file))) + error("Bad VBM [%s]", fname); + } else +#endif + { +#if (BMP_MODE) + ForceExt(pat, fname, ".BMP"); + PIC_FILE file(pat); + if (file._error == 0) { + if (loadBMP(&file)) { + Code(); + if (rem) { + free(_m); + _m = NULL; + } + } else + error("Bad BMP [%s]", fname); + } +#else + error("Bad VBM [%s]", fname); +#endif + } +} + + +Bitmap::Bitmap(uint16 w, uint16 h, uint8 *map) : _w(w), _h(h), _m(map), _v(NULL) { + if (map) + code(); +} + + +// following routine creates filled rectangle +// immediately as VGA video chunks, in near memory as fast as possible, +// especially for text line real time display +Bitmap::Bitmap(uint16 w, uint16 h, uint8 fill) + : _w((w + 3) & ~3), // only full uint32 allowed! + _h(h), + _m(NULL) { + uint16 dsiz = _w >> 2; // data size (1 plane line size) + uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap + uint16 psiz = _h * lsiz; // - last gape, but + plane trailer + uint8 *v = new uint8[4 * psiz + _h * sizeof(*_b)];// the same for 4 planes + // + room for wash table + if (v == NULL) + error("No core"); + + *(uint16 *) v = CPY | dsiz; // data chunk hader + memset(v + 2, fill, dsiz); // data bytes + *(uint16 *)(v + lsiz - 2) = SKP | ((SCR_WID / 4) - dsiz); // gap + + // Replicate lines + byte *destP; + for (destP = v + lsiz; destP < (v + psiz); destP += lsiz) + Common::copy(v, v + lsiz, destP); + + *(uint16 *)(v + psiz - 2) = EOI; // plane trailer uint16 + + // Repliccate planes + for (destP = v + psiz; destP < (v + 4 * psiz); destP += psiz) + Common::copy(v, v + psiz, destP); + + HideDesc *b = (HideDesc *)(v + 4 * psiz); + b->skip = (SCR_WID - _w) >> 2; + b->hide = _w >> 2; + + // Replicate across the entire table + for (HideDesc *hdP = b + 1; hdP < (b + _h); ++hdP) + *hdP = *b; + + b->skip = 0; // fix the first entry + _v = v; + _b = b; +} + + +Bitmap::Bitmap(const Bitmap &bmp) : _w(bmp._w), _h(bmp._h), _m(NULL), _v(NULL) { + uint8 *v0 = bmp._v; + if (v0) { + uint16 vsiz = (uint8 *)(bmp._b) - (uint8 *)(v0); + uint16 siz = vsiz + _h * sizeof(HideDesc); + uint8 *v1 = farnew(uint8, siz); + if (v1 == NULL) + error("No core"); + memcpy(v1, v0, siz); + _b = (HideDesc *)((_v = v1) + vsiz); + } +} + + +Bitmap::~Bitmap() { + if (memType(_m) == FAR_MEM) + free(_m); + + switch (memType(_v)) { + case NEAR_MEM : + delete[](uint8 *) _v; + break; + case FAR_MEM : + free(_v); + default: + warning("Unhandled MemType in Bitmap destructor"); + break; + break; + } +} + + +Bitmap &Bitmap::operator = (const Bitmap &bmp) { + uint8 *v0 = bmp._v; + _w = bmp._w; + _h = bmp._h; + _m = NULL; + if (memType(_v) == FAR_MEM) + free(_v); + if (v0 == NULL) + _v = NULL; + else { + uint16 vsiz = (uint8 *)bmp._b - (uint8 *)v0; + uint16 siz = vsiz + _h * sizeof(HideDesc); + uint8 *v1 = farnew(uint8, siz); + if (v1 == NULL) + error("No core"); + memcpy(v1, v0, siz); + _b = (HideDesc *)((_v = v1) + vsiz); + } + return *this; +} + + +uint16 Bitmap::moveVmap(uint8 *buf) { + if (_v) { + uint16 vsiz = (uint8 *)_b - (uint8 *)_v; + uint16 siz = vsiz + _h * sizeof(HideDesc); + memcpy(buf, _v, siz); + if (memType(_v) == FAR_MEM) + free(_v); + _b = (HideDesc *)((_v = buf) + vsiz); + return siz; + } + return 0; +} + + +BMP_PTR Bitmap::code() { + if (_m) { + uint16 i, cnt; + + if (_v) { // old X-map exists, so remove it + switch (memType(_v)) { + case NEAR_MEM : + delete[](uint8 *) _v; + break; + case FAR_MEM : + free(_v); + break; + default: + warning("Unhandled MemType in Bitmap::Code()"); + break; + } + _v = NULL; + } + + while (true) { // at most 2 times: for (V == NULL) & for allocated block; + uint8 *im = _v + 2; + uint16 *cp = (uint16 *) _v; + int bpl; + + if (_v) { // 2nd pass - fill the hide table + for (i = 0; i < _h; i++) { + _b[i].skip = 0xFFFF; + _b[i].hide = 0x0000; + } + } + for (bpl = 0; bpl < 4; bpl++) { // once per each bitplane + uint8 *bm = _m; + bool skip = (bm[bpl] == TRANS); + uint16 j; + + cnt = 0; + for (i = 0; i < _h; i++) { // once per each line + uint8 pix; + for (j = bpl; j < _w; j += 4) { + pix = bm[j]; + if (_v && pix != TRANS) { + if (j < _b[i].skip) + _b[i].skip = j; + + if (j >= _b[i].hide) + _b[i].hide = j + 1; + } + if ((pix == TRANS) != skip || cnt >= 0x3FF0) { // end of block + cnt |= (skip) ? SKP : CPY; + if (_v) + *cp = cnt; // store block description uint16 + + cp = (uint16 *) im; + im += 2; + skip = (pix == TRANS); + cnt = 0; + } + if (! skip) { + if (_v) + *im = pix; + ++ im; + } + ++ cnt; + } + + bm += _w; + if (_w < SCR_WID) { + if (skip) { + cnt += (SCR_WID - j + 3) / 4; + } else { + cnt |= CPY; + if (_v) + *cp = cnt; + + cp = (uint16 *) im; + im += 2; + skip = true; + cnt = (SCR_WID - j + 3) / 4; + } + } + } + if (cnt && ! skip) { + cnt |= CPY; + if (_v) + *cp = cnt; + + cp = (uint16 *) im; + im += 2; + } + if (_v) + *cp = EOI; + cp = (uint16 *) im; + im += 2; + } + if (_v) + break; + + uint16 sizV = (uint16)(im - 2 - _v); + _v = farnew(uint8, sizV + _h * sizeof(*_b)); + if (!_v) + error("No core"); + + _b = (HideDesc *)(_v + sizV); + } + cnt = 0; + for (i = 0; i < _h; i++) { + if (_b[i].skip == 0xFFFF) { // whole line is skipped + _b[i].skip = (cnt + SCR_WID) >> 2; + cnt = 0; + } else { + uint16 s = _b[i].skip & ~3; + uint16 h = (_b[i].hide + 3) & ~3; + _b[i].skip = (cnt + s) >> 2; + _b[i].hide = (h - s) >> 2; + cnt = SCR_WID - h; + } + } + } + return this; +} + + +bool Bitmap::solidAt(int x, int y) { + uint8 *m; + uint16 r, n, n0; + + if ((x >= _w) || (y >= _h)) + return false; + + m = _v; + r = static_cast<uint16>(x) % 4; + n0 = (SCR_WID * y + x) / 4, n = 0; + + while (r) { + uint16 w, t; + + w = *(uint16 *) m; + m += 2; + t = w & 0xC000; + w &= 0x3FFF; + + switch (t) { + case EOI : + r--; + case SKP : + w = 0; + break; + case REP : + w = 1; + break; + } + m += w; + } + + while (true) { + uint16 w, t; + + w = *(uint16 *) m; + m += 2; + t = w & 0xC000; + w &= 0x3FFF; + + if (n > n0) + return false; + + n += w; + switch (t) { + case EOI : + return false; + case SKP : + w = 0; + break; + case REP : + case CPY : + if (n - w <= n0 && n > n0) + return true; + break; + } + m += ((t == REP) ? 1 : w); + } +} + + +bool Bitmap::saveVBM(XFile *f) { + uint16 p = (_pal != NULL), + n = ((uint16)(((uint8 *)_b) - _v)) + _h * sizeof(HideDesc); + if (f->_error == 0) + f->write((uint8 *)&p, sizeof(p)); + + if (f->_error == 0) + f->write((uint8 *)&n, sizeof(n)); + + if (f->_error == 0) + f->write((uint8 *)&_w, sizeof(_w)); + + if (f->_error == 0) + f->write((uint8 *)&_h, sizeof(_h)); + + if (f->_error == 0) + if (p) + f->write((uint8 *)_pal, 256 * 3); + + if (f->_error == 0) + f->write(_v, n); + + return (f->_error == 0); +} + + +bool Bitmap::loadVBM(XFile *f) { + uint16 p = 0, n = 0; + if (f->_error == 0) + f->read((uint8 *)&p, sizeof(p)); + + if (f->_error == 0) + f->read((uint8 *)&n, sizeof(n)); + + if (f->_error == 0) + f->read((uint8 *)&_w, sizeof(_w)); + + if (f->_error == 0) + f->read((uint8 *)&_h, sizeof(_h)); + + if (f->_error == 0) { + if (p) { + if (_pal) { + // Read in the palette + byte palData[PAL_SIZ]; + f->read(palData, PAL_SIZ); + + const byte *srcP = palData; + for (int idx = 0; idx < PAL_CNT; ++idx, srcP += 3) { + _pal[idx]._r = *srcP; + _pal[idx]._g = *(srcP + 1); + _pal[idx]._b = *(srcP + 2); + } + } else + f->seek(f->mark() + PAL_SIZ); + } + } + if ((_v = farnew(uint8, n)) == NULL) + return false; + + if (f->_error == 0) + f->read(_v, n); + + _b = (HideDesc *)(_v + n - _h * sizeof(HideDesc)); + return (f->_error == 0); +} + +bool Bitmap::loadBMP(XFile *f) { + struct { + char BM[2]; + union { int16 len; int32 len_; }; + union { int16 _06; int32 _06_; }; + union { int16 hdr; int32 hdr_; }; + union { int16 _0E; int32 _0E_; }; + union { int16 wid; int32 wid_; }; + union { int16 hig; int32 hig_; }; + union { int16 _1A; int32 _1A_; }; + union { int16 _1E; int32 _1E_; }; + union { int16 _22; int32 _22_; }; + union { int16 _26; int32 _26_; }; + union { int16 _2A; int32 _2A_; }; + union { int16 _2E; int32 _2E_; }; + union { int16 _32; int32 _32_; }; + } hea; + + Bgr4 bpal[256]; + + f->read((byte *)&hea, sizeof(hea)); + if (f->_error == 0) { + if (hea.hdr == 0x436L) { + int16 i = (hea.hdr - sizeof(hea)) / sizeof(Bgr4); + f->read((byte *)&bpal, sizeof(bpal)); + if (f->_error == 0) { + if (_pal) { + for (i = 0; i < 256; i ++) { + _pal[i]._r = bpal[i]._R; + _pal[i]._g = bpal[i]._G; + _pal[i]._b = bpal[i]._B; + } + _pal = NULL; + } + _h = hea.hig; + _w = hea.wid; + if ((_m = farnew(byte, _h * _w)) != NULL) { + int16 r = (4 - (hea.wid & 3)) % 4; + byte buf[3]; + for (i = _h - 1; i >= 0; i--) { + f->read(_m + (_w * i), _w); + if (r && f->_error == 0) + f->read(buf, r); + if (f->_error) + break; + } + if (i < 0) + return true; + } + } + } + } + return false; +} + +} // End of namespace CGE diff --git a/engines/cge/bitmap.h b/engines/cge/bitmap.h new file mode 100644 index 0000000000..4c2b67b8df --- /dev/null +++ b/engines/cge/bitmap.h @@ -0,0 +1,97 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_BITMAP__ +#define __CGE_BITMAP__ + +#include "cge/general.h" + +namespace CGE { + +#define EOI 0x0000 +#define SKP 0x4000 +#define REP 0x8000 +#define CPY 0xC000 + +#define TRANS 0xFE + +#include "common/pack-start.h" + +struct Bgr4 { + uint16 _b : 2; + uint16 _B : 6; + uint16 _g : 2; + uint16 _G : 6; + uint16 _r : 2; + uint16 _R : 6; + uint16 _Z : 8; +}; + + +struct HideDesc { + uint16 skip; + uint16 hide; +}; + +#include "common/pack-end.h" + +class Bitmap { + bool loadBMP(XFile *f); + bool loadVBM(XFile *f); +public: + static Dac *_pal; + uint16 _w; + uint16 _h; + uint8 *_m; + uint8 *_v; + HideDesc *_b; + + Bitmap(const char *fname, bool rem); + Bitmap(uint16 w, uint16 h, uint8 *map); + Bitmap(uint16 w, uint16 h, uint8 fill); + Bitmap(const Bitmap &bmp); + ~Bitmap(); + + static void init(); + static void deinit(); + Bitmap *flipH(); + Bitmap *code(); + Bitmap &operator = (const Bitmap &bmp); + void hide(int x, int y); + void show(int x, int y); + void xShow(int x, int y); + bool solidAt(int x, int y); + bool saveVBM(XFile *f); + uint16 moveVmap(uint8 *buf); +}; + + +typedef Bitmap *BMP_PTR; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/bitmaps.cpp b/engines/cge/bitmaps.cpp new file mode 100644 index 0000000000..5e8757ae73 --- /dev/null +++ b/engines/cge/bitmaps.cpp @@ -0,0 +1,229 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/bitmaps.h" +/* + +#define W 255, +#define x 252, +#define _ TRANS, +#define o 0, +#define L LGRAY, +#define G GRAY, +#define D DGRAY, + +static uint8 MCDesign0[]= { W W W W W W _ + W W W W W o _ + W W W W o _ _ + W W W W W _ _ + W W o W W W _ + W o _ o W W W + o _ _ _ o W W + _ _ _ _ _ o o }; + + +static uint8 MCDesign1[]= { _ }; + + + +static uint8 SLDesign[] = { G G G G G G G G G _ _ _ _ _ _ + L G G G G G G G G D _ _ _ _ _ + _ L G G G G G G G D _ _ _ _ _ + _ _ L G G G G G G G D _ _ _ _ + _ _ _ L G G G G G G D _ _ _ _ + _ _ _ _ L G G G G G D _ _ _ _ + _ _ _ _ _ L G G G G G D _ _ _ + _ _ _ _ _ _ L G G G G D _ _ _ + _ _ _ _ _ _ _ L G G G D _ _ _ + _ _ _ _ _ _ _ _ L G G G D _ _ + _ _ _ _ _ _ _ _ _ L G G D _ _ + _ _ _ _ _ _ _ _ _ _ L G D _ _ + _ _ _ _ _ _ _ _ _ _ _ L G D _ + _ _ _ _ _ _ _ _ _ _ _ _ L D _ + _ _ _ _ _ _ _ _ _ _ _ _ _ L D + _ _ _ _ _ _ _ _ _ _ _ _ _ _ D + }; + +static uint8 SRDesign[] = { _ _ _ _ _ _ G G G G G G G G G + _ _ _ _ _ L G G G G G G G G D + _ _ _ _ _ L G G G G G G G D _ + _ _ _ _ L G G G G G G G D _ _ + _ _ _ _ L G G G G G G D _ _ _ + _ _ _ _ L G G G G G D _ _ _ _ + _ _ _ L G G G G G D _ _ _ _ _ + _ _ _ L G G G G D _ _ _ _ _ _ + _ _ _ L G G G D _ _ _ _ _ _ _ + _ _ L G G G D _ _ _ _ _ _ _ _ + _ _ L G G D _ _ _ _ _ _ _ _ _ + _ _ L G D _ _ _ _ _ _ _ _ _ _ + _ L G D _ _ _ _ _ _ _ _ _ _ _ + _ L D _ _ _ _ _ _ _ _ _ _ _ _ + L D _ _ _ _ _ _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ _ _ _ _ _ _ + }; + +static uint8 MapBrick[] = { L L L L L L L G + L G G G G G G D + L G G G G G G D + G D D D D D D D + }; + +#undef W +#undef _ +#undef x +#undef o +#undef L +#undef G +#undef D + + +#if 0 + +#define _ TRANS, +#define A 213, +#define B 207, +#define C 225, +#define D 219, +#define E 231, + +static uint8 PRDesign[] = { A E E E C C D A B + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + B A A A A A A A B + B B B B B B B B B + }; + +#else + +#define _ TRANS, +#define A 213, +#define B 207, +#define C 225, // DGRAY +#define D 219, +#define E 231, +#define F 237, + +static uint8 PRDesign[] = { D D D D D D D D _ + D D D D D D D D _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ C _ + D C C C C C C C _ + _ _ _ _ _ _ _ _ _ + }; +#endif + + +#undef _ +#undef A +#undef B +#undef C +#undef D +#undef E + + + +#define _ 0x00, +#define x 0xFF, +#define A _ x _ x _ x _ x +#define B A A A A A A A A + +static uint8 HLDesign[] = { B B B B B }; + +#undef _ +#undef x +#undef A +#undef B + + +// 228 yellow +// 211 red +// 226 light green +// 221 blue + +#define A 208, +#define B 214, +#define C 220, +#define D 226, +#define E 255, + +static uint8 LIDesign[][9] = { { A A A + A B A + A A A }, + + { A B A + B C B + A B A }, + + { B C B + C D C + B C B }, + + { C D C + D E D + C D C }, + }; + +#undef A +#undef B +#undef C +#undef D +#undef E + + +#define R 211, +#define G 0, +//226, + +static uint8 MEDesign[][9] = { { R R R R R R R R R }, // 0 + { R R R R R R R R G }, // 1 + { R R R R R R R G G }, // 2 + { R R R R R R G G G }, // 3 + { R R R R R G G G G }, // 4 + { R R R R G G G G G }, // 5 + { R R R G G G G G G }, // 6 + { R R G G G G G G G }, // 7 + { R G G G G G G G G }, // 8 + { G G G G G G G G G }, // 9 + }; + +#undef R +#undef G +*/ + +namespace CGE { + + + +} // End of namespace CGE diff --git a/engines/cge/bitmaps.h b/engines/cge/bitmaps.h new file mode 100644 index 0000000000..8569932134 --- /dev/null +++ b/engines/cge/bitmaps.h @@ -0,0 +1,44 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_BITMAPS__ +#define __CGE_BITMAPS__ + +#include "cge/vga13h.h" + +namespace CGE { + +extern Bitmap *MB[]; +extern Bitmap *HL[]; +extern Bitmap *MC[]; +extern Bitmap *PR[]; +extern Bitmap *SP[]; +extern Bitmap *LI[]; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/btfile.cpp b/engines/cge/btfile.cpp new file mode 100644 index 0000000000..eda18ebaaf --- /dev/null +++ b/engines/cge/btfile.cpp @@ -0,0 +1,150 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/btfile.h" +#include "common/system.h" +#include "common/str.h" + +namespace CGE { + +#ifndef BT_SIZE +#define BT_SIZE K(1) +#endif + +#ifndef BT_KEYLEN +#define BT_KEYLEN 13 +#endif + +BtFile::BtFile(const char *name, IOMODE mode, CRYPT *crpt) + : IoHand(name, mode, crpt) { + for (int i = 0; i < BT_LEVELS; i++) { + _buff[i]._page = new BtPage; + _buff[i]._pgNo = BT_NONE; + _buff[i]._indx = -1; + _buff[i]._updt = false; + if (_buff[i]._page == NULL) + error("No core"); + } +} + + +BtFile::~BtFile() { + for (int i = 0; i < BT_LEVELS; i++) { + putPage(i, false); + delete _buff[i]._page; + } +} + + +void BtFile::putPage(int lev, bool hard) { + if (hard || _buff[lev]._updt) { + seek(_buff[lev]._pgNo * sizeof(BtPage)); + write((uint8 *) _buff[lev]._page, sizeof(BtPage)); + _buff[lev]._updt = false; + } +} + + +BtPage *BtFile::getPage(int lev, uint16 pgn) { + if (_buff[lev]._pgNo != pgn) { + int32 pos = pgn * sizeof(BtPage); + putPage(lev, false); + _buff[lev]._pgNo = pgn; + if (size() > pos) { + seek((uint32) pgn * sizeof(BtPage)); + read((uint8 *) _buff[lev]._page, sizeof(BtPage)); + _buff[lev]._updt = false; + } else { + _buff[lev]._page->_hea._count = 0; + _buff[lev]._page->_hea._down = BT_NONE; + memset(_buff[lev]._page->_data, '\0', sizeof(_buff[lev]._page->_data)); + _buff[lev]._updt = true; + } + _buff[lev]._indx = -1; + } + return _buff[lev]._page; +} + +BtKeypack *BtFile::find(const char *key) { + int lev = 0; + uint16 nxt = BT_ROOT; + while (!_error) { + BtPage *pg = getPage(lev, nxt); + // search + if (pg->_hea._down != BT_NONE) { + int i; + for (i = 0; i < pg->_hea._count; i++) { + // Does this work, or does it have to compare the entire buffer? + if (scumm_strnicmp((const char *)key, (const char*)pg->_inn[i]._key, BT_KEYLEN) < 0) + break; + } + nxt = (i) ? pg->_inn[i - 1]._down : pg->_hea._down; + _buff[lev]._indx = i - 1; + lev++; + } else { + int i; + for (i = 0; i < pg->_hea._count - 1; i++) { + if (scumm_stricmp((const char *)key, (const char *)pg->_lea[i]._key) <= 0) + break; + } + _buff[lev]._indx = i; + return &pg->_lea[i]; + } + } + return NULL; +} + + +int keycomp(const void *k1, const void *k2) { + return scumm_strnicmp((const char *) k1, (const char*) k2, BT_KEYLEN); +} + + +void BtFile::make(BtKeypack *keypack, uint16 count) { +#if BT_LEVELS != 2 +#error This tiny BTREE implementation works with exactly 2 levels! +#endif + _fqsort(keypack, count, sizeof(*keypack), keycomp); + uint16 n = 0; + BtPage *Root = getPage(0, n++); + BtPage *Leaf = getPage(1, n); + Root->_hea._down = n; + putPage(0, true); + while (count--) { + if (Leaf->_hea._count >= ArrayCount(Leaf->_lea)) { + putPage(1, true); // save filled page + Leaf = getPage(1, ++n); // take empty page + memcpy(Root->_inn[Root->_hea._count]._key, keypack->_key, BT_KEYLEN); + Root->_inn[Root->_hea._count++]._down = n; + _buff[0]._updt = true; + } + Leaf->_lea[Leaf->_hea._count++] = *(keypack++); + _buff[1]._updt = true; + } +} + +} // End of namespace CGE diff --git a/engines/cge/btfile.h b/engines/cge/btfile.h new file mode 100644 index 0000000000..1ac093d897 --- /dev/null +++ b/engines/cge/btfile.h @@ -0,0 +1,95 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_BTFILE__ +#define __CGE_BTFILE__ + +#include "cge/general.h" + +namespace CGE { + +#define BT_SIZE K(1) +#define BT_KEYLEN 13 +#define BT_LEVELS 2 + +#define BT_NONE 0xFFFF +#define BT_ROOT 0 + +#include "common/pack-start.h" // START STRUCT PACKING + +struct BtKeypack { + char _key[BT_KEYLEN]; + uint32 _mark; + uint16 _size; +}; + +struct Inner { + uint8 _key[BT_KEYLEN]; + uint16 _down; +}; + +struct Hea { + uint16 _count; + uint16 _down; +}; + +struct BtPage { + Hea _hea; + union { + // dummy filler to make proper size of union + uint8 _data[BT_SIZE - sizeof(Hea)]; + // inner version of data: key + word-sized page link + Inner _inn[(BT_SIZE - sizeof(Hea)) / sizeof(Inner)]; + // leaf version of data: key + all user data + BtKeypack _lea[(BT_SIZE - sizeof(Hea)) / sizeof(BtKeypack)]; + }; +}; + +#include "common/pack-end.h" // END STRUCT PACKING + + +class BtFile : public IoHand { + struct { + BtPage *_page; + uint16 _pgNo; + int _indx; + bool _updt; + } _buff[BT_LEVELS]; + + void putPage(int lev, bool hard); + BtPage *getPage(int lev, uint16 pgn); +public: + BtFile(const char *name, IOMODE mode, CRYPT *crpt); + virtual ~BtFile(); + BtKeypack *find(const char *key); + BtKeypack *next(); + void make(BtKeypack *keypack, uint16 count); +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/cfile.cpp b/engines/cge/cfile.cpp new file mode 100644 index 0000000000..b235d552b2 --- /dev/null +++ b/engines/cge/cfile.cpp @@ -0,0 +1,260 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/cfile.h" +#include "common/system.h" + +namespace CGE { + +IoBuf::IoBuf(IOMODE mode, CRYPT *crpt) + : IoHand(mode, crpt), + _bufMark(0), + _ptr(0), + _lim(0) { + _buff = farnew(uint8, IOBUF_SIZE); + if (_buff == NULL) + error("No core for I/O"); +} + + +IoBuf::IoBuf(const char *name, IOMODE mode, CRYPT *crpt) + : IoHand(name, mode, crpt), + _bufMark(0), + _ptr(0), + _lim(0) { + _buff = farnew(uint8, IOBUF_SIZE); + if (_buff == NULL) + error("No core for I/O [%s]", name); +} + +IoBuf::~IoBuf() { + if (_mode > REA) + writeBuff(); + if (_buff) + free(_buff); +} + + +void IoBuf::readBuff() { + _bufMark = IoHand::mark(); + _lim = IoHand::read(_buff, IOBUF_SIZE); + _ptr = 0; +} + + +void IoBuf::writeBuff() { + if (_lim) { + IoHand::write(_buff, _lim); + _bufMark = IoHand::mark(); + _lim = 0; + } +} + + +uint16 IoBuf::read(void *buf, uint16 len) { + uint16 total = 0; + while (len) { + if (_ptr >= _lim) + readBuff(); + uint16 n = _lim - _ptr; + if (n) { + if (len < n) + n = len; + memcpy(buf, _buff + _ptr, n); + buf = (uint8 *)buf + n; + len -= n; + total += n; + _ptr += n; + } else + break; + } + return total; +} + + +uint16 IoBuf::read(uint8 *buf) { + uint16 total = 0; + + while (total < LINE_MAX - 2) { + if (_ptr >= _lim) + readBuff(); + uint8 *p = _buff + _ptr; + uint16 n = _lim - _ptr; + if (n) { + if (total + n >= LINE_MAX - 2) + n = LINE_MAX - 2 - total; + uint8 *eol = (uint8 *) memchr(p, '\r', n); + if (eol) + n = (uint16)(eol - p); + uint8 *eof = (uint8 *) memchr(p, '\32', n); + if (eof) { // end-of-file + n = (uint16)(eof - p); + _ptr = (uint16)(eof - _buff); + } + if (n) + memcpy(buf, p, n); + buf += n; + total += n; + if (eof) + break; + _ptr += n; + if (eol) { + _ptr++; + *(buf++) = '\n'; + total++; + if (_ptr >= _lim) + readBuff(); + if (_ptr < _lim) + if (_buff[_ptr] == '\n') + ++_ptr; + break; + } + } else + break; + } + *buf = '\0'; + return total; +} + + +uint16 IoBuf::write(void *buf, uint16 len) { + uint16 tot = 0; + while (len) { + uint16 n = IOBUF_SIZE - _lim; + if (n > len) + n = len; + if (n) { + memcpy(_buff + _lim, buf, n); + _lim += n; + len -= n; + buf = (uint8 *)buf + n; + tot += n; + } else + writeBuff(); + } + return tot; +} + + +uint16 IoBuf::write(uint8 *buf) { + uint16 len = 0; + if (buf) { + len = strlen((const char *) buf); + if (len) + if (buf[len - 1] == '\n') + --len; + len = write(buf, len); + if (len) { + static char EOL[] = "\r\n"; + uint16 n = write(EOL, sizeof(EOL) - 1); + len += n; + } + } + return len; +} + + +int IoBuf::read() { + if (_ptr >= _lim) { + readBuff(); + if (_lim == 0) + return -1; + } + return _buff[_ptr++]; +} + + +void IoBuf::write(uint8 b) { + if (_lim >= IOBUF_SIZE) + writeBuff(); + _buff[_lim++] = b; +} + + +uint16 CFile::_maxLineLen = LINE_MAX; + + +CFile::CFile(const char *name, IOMODE mode, CRYPT *crpt) + : IoBuf(name, mode, crpt) { +} + + +CFile::~CFile() { +} + + +void CFile::flush() { + if (_mode > REA) + writeBuff(); + else + _lim = 0; + + /* + _BX = Handle; + _AH = 0x68; // Flush buffer + asm int 0x21 + */ + warning("FIXME: CFILE::Flush"); +} + + +long CFile::mark() { + return _bufMark + ((_mode > REA) ? _lim : _ptr); +} + + +long CFile::seek(long pos) { + if (pos >= _bufMark && pos < _bufMark + _lim) { + ((_mode == REA) ? _ptr : _lim) = (uint16)(pos - _bufMark); + return pos; + } else { + if (_mode > REA) + writeBuff(); + else + _lim = 0; + + _ptr = 0; + return _bufMark = IoHand::seek(pos); + } +} + + +void CFile::append(CFile &f) { + seek(size()); + if (f._error == 0) { + while (true) { + if ((_lim = f.IoHand::read(_buff, IOBUF_SIZE)) == IOBUF_SIZE) + writeBuff(); + else + break; + if ((_error = f._error) != 0) + break; + } + } +} + +} // End of namespace CGE diff --git a/engines/cge/cfile.h b/engines/cge/cfile.h new file mode 100644 index 0000000000..bf90633dd0 --- /dev/null +++ b/engines/cge/cfile.h @@ -0,0 +1,80 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_CFILE__ +#define __CGE_CFILE__ + +#include "cge/general.h" + +namespace CGE { + +#define LINE_MAX 512 + +#ifndef IOBUF_SIZE +#define IOBUF_SIZE K(2) +#endif + +#define CFREAD(x) read((uint8 *)(x),sizeof(*(x))) + + +class IoBuf : public IoHand { +protected: + uint8 *_buff; + uint16 _ptr; + uint16 _lim; + long _bufMark; + uint16 _seed; + CRYPT *_crypt; + virtual void readBuff(); + virtual void writeBuff(); +public: + IoBuf(IOMODE mode, CRYPT *crpt = NULL); + IoBuf(const char *name, IOMODE mode, CRYPT *crpt = NULL); + virtual ~IoBuf(); + uint16 read(void *buf, uint16 len); + uint16 read(uint8 *buf); + int read(); + uint16 write(void *buf, uint16 len); + uint16 write(uint8 *buf); + void write(uint8 b); +}; + + +class CFile : public IoBuf { +public: + static uint16 _maxLineLen; + CFile(const char *name, IOMODE mode = REA, CRYPT *crpt = NULL); + virtual ~CFile(); + void flush(); + long mark(); + long seek(long pos); + void append(CFile &f); +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/cge.cpp b/engines/cge/cge.cpp new file mode 100644 index 0000000000..b953f2f5b0 --- /dev/null +++ b/engines/cge/cge.cpp @@ -0,0 +1,257 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" +#include "common/config-manager.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/error.h" +#include "common/EventRecorder.h" +#include "common/file.h" +#include "common/fs.h" +#include "engines/util.h" +#include "cge/cge.h" +#include "cge/vga13h.h" +#include "cge/cge_main.h" +#include "cge/talk.h" +#include "cge/text.h" +#include "cge/bitmaps.h" +#include "cge/vol.h" + + +namespace CGE { + +CGEEngine::CGEEngine(OSystem *syst, const ADGameDescription *gameDescription) + : Engine(syst), _gameDescription(gameDescription), _randomSource("cge") { + + // Debug/console setup + DebugMan.addDebugChannel(kCGEDebug, "general", "CGE general debug channel"); + + _isDemo = _gameDescription->flags & ADGF_DEMO; + _startupMode = 1; + _demoText = DEMO_TEXT; + _oldLev = 0; + _jbw = false; + _pocPtr = 0; + +} + +void CGEEngine::setup() { + // Initialise fields + _lastFrame = 0; + _hero = NULL; + + // Create debugger console + _console = new CGEConsole(this); + + // Initialise classes that have static members + Vga::init(); + VFile::init(); + Bitmap::init(); + Talk::init(); + + // Initialise sprite arrays used by game objects + MB[0] = new Bitmap("BRICK", true); + MB[1] = NULL; + HL[0] = new Bitmap("HLINE", true); + HL[1] = NULL; + MC[0] = new Bitmap("MOUSE", true); + MC[1] = new Bitmap("DUMMY", true); + MC[2] = NULL; + PR[0] = new Bitmap("PRESS", true); + PR[1] = NULL; + SP[0] = new Bitmap("SPK_L", true); + SP[1] = new Bitmap("SPK_R", true); + SP[2] = NULL; + LI[0] = new Bitmap("LITE0", true); + LI[1] = new Bitmap("LITE1", true); + LI[2] = new Bitmap("LITE2", true); + LI[3] = new Bitmap("LITE3", true); + LI[4] = NULL; + + // Initialise engine objects + _text = new Text(this, progName(), 128); + _vga = new Vga(M13H); + _heart = new Heart; + _sys = new System(this); + _pocLight = new Sprite(this, LI); + for (int i = 0; i < POCKET_NX; i++) + _pocket[i] = new Sprite(this, NULL); + _sprite = new Sprite(this, NULL); + _miniCave = new Sprite(this, NULL); + _shadow = new Sprite(this, NULL); + _horzLine = new Sprite(this, HL); + _infoLine = new InfoLine(this, INFO_W); + _cavLight = new Sprite(this, PR); + _debugLine = new InfoLine(this, SCR_WID); + _snail = new Snail(this, false); + _snail_ = new Snail(this, true); + + _mouse = new MOUSE(this); + _keyboard = new Keyboard(); + _eventManager = new EventManager(); + _offUseCount = atoi(_text->getText(OFF_USE_COUNT)); + _music = true; + + for (int i = 0; i < POCKET_NX; i++) + _pocref[i] = -1; + _volume[0] = 0; + _volume[1] = 0; + + _savTab[0]._ptr = &_now; + _savTab[0]._len = sizeof(_now); + _savTab[0]._flag = true; + _savTab[1]._ptr = &_oldLev; + _savTab[1]._len = sizeof(_oldLev); + _savTab[1]._flag = true; + _savTab[2]._ptr = &_demoText; + _savTab[2]._len = sizeof(_demoText); + _savTab[2]._flag = true; + _savTab[3]._ptr = &_game; + _savTab[3]._len = sizeof(_game); + _savTab[3]._flag = true; + _savTab[4]._ptr = &_game; + _savTab[4]._len = sizeof(_game); + _savTab[4]._flag = true; + _savTab[5]._ptr = &_game; + _savTab[5]._len = sizeof(_game); + _savTab[5]._flag = true; + _savTab[6]._ptr = &_game; + _savTab[6]._len = sizeof(_game); + _savTab[6]._flag = true; + _savTab[7]._ptr = &_game; + _savTab[7]._len = sizeof(_game); + _savTab[7]._flag = true; + _savTab[8]._ptr = &_vga->_mono; + _savTab[8]._len = sizeof(_vga->_mono); + _savTab[8]._flag = false; + _savTab[9]._ptr = &_music; + _savTab[9]._len = sizeof(_music); + _savTab[9]._flag = true; + _savTab[10]._ptr = _volume; + _savTab[10]._len = sizeof(_volume); + _savTab[10]._flag = true; + _savTab[11]._ptr = _flag; + _savTab[11]._len = sizeof(_flag); + _savTab[11]._flag = true; + _savTab[12]._ptr = _heroXY; +// _savTab[12]._len = sizeof(_heroXY); FIXME: illegal sizeof + _savTab[12]._len = 0; + _savTab[12]._flag = true; + _savTab[13]._ptr = _barriers; +// _savTab[13]._len = sizeof(_barriers); FIXME: illegal sizeof + _savTab[13]._len = 0; + _savTab[13]._flag = true; + _savTab[14]._ptr = _pocref; + _savTab[14]._len = sizeof(_pocref); + _savTab[14]._flag = true; + _savTab[15]._ptr = NULL; + _savTab[15]._len = 0; + _savTab[15]._flag = false; + + if (_isDemo) { + _maxCaveArr[0] = CAVE_MAX; + _maxCaveArr[1] = -1; + _maxCaveArr[2] = -1; + _maxCaveArr[3] = -1; + _maxCaveArr[4] = -1; + } else { + _maxCaveArr[0] = 1; + _maxCaveArr[1] = 8; + _maxCaveArr[2] = 16; + _maxCaveArr[3] = 23; + _maxCaveArr[4] = 24; + }; + _maxCave = 0; + _dark = false; + _game = false; + _now = 1; + _lev = -1; + + for (int i = 0; i < 4; i++) + _flag[i] = false; + +} + +CGEEngine::~CGEEngine() { + debug("CGEEngine::~CGEEngine"); + + // Call classes with static members to clear them up + Talk::deinit(); + Bitmap::deinit(); + VFile::deinit(); + Vga::deinit(); + + // Remove all of our debug levels here + DebugMan.clearAllDebugChannels(); + + delete _console; + + // Delete engine objects + delete _sprite; + delete _miniCave; + delete _shadow; + delete _horzLine; + delete _infoLine; + delete _cavLight; + delete _debugLine; + delete MB[0]; + delete HL[0]; + delete MC[0]; + delete MC[1]; + delete PR[0]; + delete SP[0]; + delete SP[1]; + delete LI[0]; + delete LI[1]; + delete LI[2]; + delete LI[3]; + delete _text; + delete _heart; + delete _pocLight; + delete _keyboard; + delete _mouse; + for (int i = 0; i < POCKET_NX; i++) + delete _pocket[i]; + delete _snail; + delete _snail_; + delete _hero; + delete _vga; + delete _sys; +} + +Common::Error CGEEngine::run() { + // Initialize graphics using following: + initGraphics(320, 200, false); + + // Setup necessary game objects + setup(); + + // Additional setup. + debug("CGEEngine::init"); + + cge_main(); + + return Common::kNoError; +} + +} // End of namespace CGE diff --git a/engines/cge/cge.h b/engines/cge/cge.h new file mode 100644 index 0000000000..4f6b452850 --- /dev/null +++ b/engines/cge/cge.h @@ -0,0 +1,212 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef CGE_H +#define CGE_H + +#include "cge/general.h" +#include "common/random.h" +#include "engines/engine.h" +#include "gui/debugger.h" +#include "graphics/surface.h" +#include "engines/advancedDetector.h" +#include "cge/console.h" +#include "cge/bitmap.h" + +#define CGE_SAVEGAME_VERSION 1 + +namespace CGE { + +class Console; +class Sprite; + +// our engine debug channels +enum { + kCGEDebug = 1 << 0 +}; + +enum SNLIST { NEAR, TAKE }; + +#define POCKET_NX 8 + +struct SavTab { + void *_ptr; + int32 _len; + bool _flag; +}; + +class CGEEngine : public Engine { +private: + uint32 _lastFrame; + void tick(); +public: + CGEEngine(OSystem *syst, const ADGameDescription *gameDescription); + ~CGEEngine(); + + const ADGameDescription *_gameDescription; + bool _isDemo; + int _startupMode; + int _demoText; + int _oldLev; + bool _jbw; + int _pocPtr; + SavTab _savTab[16]; + bool _music; + int _pocref[POCKET_NX]; + uint8 _volume[2]; + int _maxCaveArr[5]; + + int _maxCave; + bool _flag[4]; + bool _dark; + bool _game; + int _now; + int _lev; + + Common::RandomSource _randomSource; + + virtual Common::Error run(); + GUI::Debugger *getDebugger() { + return _console; + } + + void cge_main(); + void switchCave(int cav); + void startCountDown(); + void quit(); + void resetQSwitch(); + void optionTouch(int opt, uint16 mask); + void loadGame(XFile &file, bool tiny); + void setMapBrick(int x, int z); + void switchMapping(); + void loadSprite(const char *fname, int ref, int cav, int col, int row, int pos); + void loadScript(const char *fname); + void loadUser(); + void runGame(); + bool showTitle(const char *name); + void movie(const char *ext); + void takeName(); + void inf(const char *txt); + void selectSound(); + void dummy() {} + void NONE(); + void SB(); + void caveDown(); + void caveUp(); + void xCave(); + void qGame(); + void SBM(); + void GUS(); + void GUSM(); + void MIDI(); + void AUTO(); + void setPortD(); + void setPortM(); + void setIRQ(); + void setDMA(); + void mainLoop(); + void saveGame(XFile &file); + void switchMusic(); + void selectPocket(int n); + void expandSprite(Sprite *spr); + void contractSprite(Sprite *spr); + int findPocket(Sprite *spr); + void feedSnail(Sprite *spr, SNLIST snq); + void pocFul(); + void hide1(Sprite *spr); + void loadMapping(); + void saveMapping(); + void saveSound(); + void heroCover(int cvr); + void trouble(int seq, int txt); + void offUse(); + void tooFar(); + void noWay(); + void loadHeroXY(); + void keyClick(); + void switchColorMode(); + void killSprite(); + void pushSprite(); + void pullSprite(); + void sayDebug(); + void nextStep(); + void switchDebug(); + + void snBackPt(Sprite *spr, int stp); + void snBarrier(int cav, int bar, bool horz); + void snCover(Sprite *spr, int xref); + void snFlag(int fn, bool v); + void snFlash(bool on); + void snGame(Sprite *spr, int num); + void snGhost(Bitmap *bmp); + void snGive(Sprite *spr, int stp); + void snHide(Sprite *spr, int val); + void snKeep(Sprite *spr, int stp); + void snKill(Sprite *spr); + void snLevel(Sprite *spr, int lev); + void snLight(bool in); + void snMouse(bool on); + void snNNext(Sprite *sprel, int p); + void snPort(Sprite *spr, int port); + void snReach(Sprite *spr, int mode); + void snRelZ(Sprite *spr, int z); + void snRNNext(Sprite *sprel, int p); + void snRTNext(Sprite *sprel, int p); + void snSelect(); + void snSend(Sprite *spr, int val); + void snRelX(Sprite *spr, int x); + void snRelY(Sprite *spr, int y); + void snRmNear(Sprite *spr); + void snRmTake(Sprite *spr); + void snRSeq(Sprite *spr, int val); + void snSeq(Sprite *spr, int val); + void snSetRef(Sprite *spr, int nr); + void snSetX(Sprite *spr, int x); + void snSetX0(int cav, int x0); + void snSetXY(Sprite *spr, uint16 xy); + void snSetY(Sprite *spr, int y); + void snSetY0(int cav, int y0); + void snSetZ(Sprite *spr, int z); + void snSlave(Sprite *spr, int ref); + void snSound(Sprite *spr, int wav, int cnt); + void snSwap(Sprite *spr, int xref); + void snTNext(Sprite *sprel, int p); + void snTrans(Sprite *spr, int trans); + void snUncover(Sprite *spr, Sprite *xspr); + void snWalk(Sprite *spr, int x, int y); + void snZTrim(Sprite *spr); + +private: + CGEConsole *_console; + void setup(); +}; + +// Example console class +class Console : public GUI::Debugger { +public: + Console(CGEEngine *vm) {} + virtual ~Console() {} +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp new file mode 100644 index 0000000000..e7ca76a98f --- /dev/null +++ b/engines/cge/cge_main.cpp @@ -0,0 +1,1844 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "common/scummsys.h" +#include "common/memstream.h" +#include "common/serializer.h" +#include "cge/general.h" +#include "cge/sound.h" +#include "cge/startup.h" +#include "cge/config.h" +#include "cge/vga13h.h" +#include "cge/snail.h" +#include "cge/text.h" +#include "cge/game.h" +#include "cge/events.h" +#include "cge/cfile.h" +#include "cge/vol.h" +#include "cge/talk.h" +#include "cge/vmenu.h" +#include "cge/gettext.h" +#include "cge/mixer.h" +#include "cge/cge_main.h" +#include "cge/cge.h" +#include "common/str.h" + +namespace CGE { + +#define STACK_SIZ (K(2)) +#define SVGCHKSUM (1956 + _now + _oldLev + _game + _music + _demoText) + +#define SVG0NAME ("{{INIT}}" SVG_EXT) +#define SVG0FILE INI_FILE + +uint16 _stklen = (STACK_SIZ * 2); + +Vga *_vga; +Heart *_heart; +WALK *_hero; +System *_sys; +Sprite *_pocLight; +EventManager *_eventManager; +Keyboard *_keyboard; +MOUSE *_mouse; +Sprite *_pocket[POCKET_NX]; +Sprite *_sprite; +Sprite *_miniCave; +Sprite *_shadow; +Sprite *_horzLine; +InfoLine *_infoLine; +Sprite *_cavLight; +InfoLine *_debugLine; + +BMP_PTR MB[2]; +BMP_PTR HL[2]; +BMP_PTR MC[3]; +BMP_PTR PR[2]; +BMP_PTR SP[3]; +BMP_PTR LI[5]; + +Snail *_snail; +Snail *_snail_; + +// 0.75 - 17II95 - full sound support +// 0.76 - 18II95 - small MiniEMS in DEMO, +// unhide CavLight in SNLEVEL +// keyclick suppress in startup +// keyclick on key service in: SYSTEM, GET_TEXT +// 1.01 - 17VII95 - default savegame with sound ON +// coditionals EVA for 2-month evaluation version + +static char _usrFnam[15] = "\0ɱ%^þúȼ´ ÇÉ"; + +//-------------------------------------------------------------------------- + +static Ems *_mini = _miniEmm.alloc((uint16)MINI_EMM_SIZE); +static BMP_PTR *_miniShpList = NULL; +static BMP_PTR _miniShp[] = { NULL, NULL }; +static bool _finis = false; +int _offUseCount; +uint16 *_intStackPtr = false; + +Hxy _heroXY[CAVE_MAX] = {{0, 0}}; +Bar _barriers[1 + CAVE_MAX] = { { 0xFF, 0xFF } }; + +extern Dac _stdPal[58]; + +uint8 Cluster::_map[MAP_ZCNT][MAP_XCNT]; + + +uint8 &Cluster::cell() { + return _map[_b][_a]; +} + + +bool Cluster::Protected() { +/* + if (A == Barriers[Now]._vert || B == Barriers[Now]._horz) + return true; + + _DX = (MAP_ZCNT << 8) + MAP_XCNT; + _BX = (uint16) this; + + asm mov ax,1 + asm mov cl,[bx].(COUPLE)A + asm mov ch,[bx].(COUPLE)B + asm test cx,0x8080 // (A < 0) || (B < 0) + asm jnz xit + + asm cmp cl,dl + asm jge xit + asm cmp ch,dh + asm jge xit + + // if (A < 0 || A >= MAP_XCNT || B < 0 || B >= MAP_ZCNT) return true; + + asm mov al,dl + asm mul ch + asm xor ch,ch + asm add ax,cx + asm mov bx,ax + _BX += (uint16) Map; + //asm add bx,offset CLUSTER::Map + asm mov al,[bx] + asm and ax,0xFF + asm jz xit + asm mov ax,1 + + // return Map[B][A] != 0; + + xit: return _AX; + */ + + warning("STUB: CLUSTER::Protected()"); + return true; +} + + +Cluster XZ(int x, int y) { + if (y < MAP_TOP) + y = MAP_TOP; + + if (y > MAP_TOP + MAP_HIG - MAP_ZGRID) + y = MAP_TOP + MAP_HIG - MAP_ZGRID; + + return Cluster(x / MAP_XGRID, (y - MAP_TOP) / MAP_ZGRID); +} + + +Cluster XZ(Couple xy) { + signed char x, y; + xy.split(x, y); + return XZ(x, y); +} + +void CGEEngine::loadGame(XFile &file, bool tiny = false) { + SavTab *st; + Sprite *spr; + int i; + + // Read the data into a data buffer + int size = file.size() - file.mark(); + byte *dataBuffer = new byte[size]; + file.read(dataBuffer, size); + Common::MemoryReadStream readStream(dataBuffer, size, DisposeAfterUse::YES); + Common::Serializer s(&readStream, NULL); + + // Synchronise header data + s.syncAsUint16LE(_now); + s.syncAsUint16LE(_oldLev); + s.syncAsUint16LE(_demoText); + for (i = 0; i < 5; ++i) + s.syncAsUint16LE(_game); + s.syncAsSint16LE(i); // unused VGA::Mono variable + s.syncAsUint16LE(_music); + s.syncBytes(_volume, 2); + for (i = 0; i < 4; ++i) + s.syncAsUint16LE(_flag[i]); + + for (i = 0; i < CAVE_MAX; ++i) { + s.syncAsSint16LE(_heroXY[i]._x); + s.syncAsUint16LE(_heroXY[i]._y); + } + for (i = 0; i < 1 + CAVE_MAX; ++i) { + s.syncAsByte(_barriers[i]._horz); + s.syncAsByte(_barriers[i]._vert); + } + for (i = 0; i < POCKET_NX; ++i) + s.syncAsUint16LE(_pocref[i]); + + uint16 checksum; + s.syncAsUint16LE(checksum); + if (checksum != SVGCHKSUM) + error("%s", _text->getText(BADSVG_TEXT)); + + if (Startup::_core < CORE_HIG) + _music = false; + + if (Startup::_soundOk == 1 && Startup::_mode == 0) { + _sndDrvInfo.Vol2._d = _volume[0]; + _sndDrvInfo.Vol2._m = _volume[1]; + sndSetVolume(); + } + + if (! tiny) { // load sprites & pocket + while (readStream.pos() < readStream.size()) { + Sprite S(this, NULL); + S.sync(s); + + S._prev = S._next = NULL; + spr = (scumm_stricmp(S._file + 2, "MUCHA") == 0) ? new Fly(this, NULL) + : new Sprite(this, NULL); + if (spr == NULL) + error("No core"); + *spr = S; + _vga->_spareQ->append(spr); + } + + for (i = 0; i < POCKET_NX; i++) { + register int r = _pocref[i]; + _pocket[i] = (r < 0) ? NULL : _vga->_spareQ->locate(r); + } + } +} + + +void CGEEngine::saveSound() { + CFile cfg(usrPath(progName(CFG_EXT)), WRI); + if (!cfg._error) + cfg.write(&_sndDrvInfo, sizeof(_sndDrvInfo) - sizeof(_sndDrvInfo.Vol2)); +} + + +void CGEEngine::saveGame(XFile &file) { + SavTab *st; + Sprite *spr; + int i; + + for (i = 0; i < POCKET_NX; i++) { + register Sprite *s = _pocket[i]; + _pocref[i] = (s) ? s->_ref : -1; + } + + _volume[0] = _sndDrvInfo.Vol2._d; + _volume[1] = _sndDrvInfo.Vol2._m; + + for (st = _savTab; st->_ptr; st++) { + if (file._error) + error("Bad SVG"); + file.write((uint8 *) st->_ptr, st->_len); + } + + file.write((uint8 *) & (i = SVGCHKSUM), sizeof(i)); + + for (spr = _vga->_spareQ->first(); spr; spr = spr->_next) + if (spr->_ref >= 1000) + if (!file._error) + file.write((uint8 *)spr, sizeof(*spr)); +} + +void CGEEngine::heroCover(int cvr) { + SNPOST(SNCOVER, 1, cvr, NULL); +} + +void CGEEngine::trouble(int seq, int txt) { + _hero->park(); + SNPOST(SNWAIT, -1, -1, _hero); + SNPOST(SNSEQ, -1, seq, _hero); + SNPOST(SNSOUND, -1, 2, _hero); + SNPOST(SNWAIT, -1, -1, _hero); + SNPOST(SNSAY, 1, txt, _hero); +} + +void CGEEngine::offUse() { + trouble(OFF_USE, OFF_USE_TEXT + new_random(_offUseCount)); +} + +void CGEEngine::tooFar() { + trouble(TOO_FAR, TOO_FAR_TEXT); +} + +// Used in stubbed function, do not remove! +void CGEEngine::noWay() { + trouble(NO_WAY, NO_WAY_TEXT); +} + + +void CGEEngine::loadHeroXY() { + INI_FILE cf(progName(".HXY")); + memset(_heroXY, 0, sizeof(_heroXY)); + if (!cf._error) + cf.CFREAD(&_heroXY); +} + +void CGEEngine::loadMapping() { + if (_now <= CAVE_MAX) { + INI_FILE cf(progName(".TAB")); + if (!cf._error) { + memset(Cluster::_map, 0, sizeof(Cluster::_map)); + cf.seek((_now - 1) * sizeof(Cluster::_map)); + cf.read((uint8 *) Cluster::_map, sizeof(Cluster::_map)); + } + } +} + + +Cluster Trace[MAX_FIND_LEVEL]; +int FindLevel; + + +WALK::WALK(CGEEngine *vm, BMP_PTR *shpl) + : Sprite(vm, shpl), Dir(NO_DIR), _tracePtr(-1), _vm(vm) { +} + + +void WALK::tick() { + if (_flags._hide) + return; + + _here = XZ(_x + _w / 2, _y + _h); + + if (Dir != NO_DIR) { + Sprite *spr; + _sys->funTouch(); + for (spr = _vga->_showQ->first(); spr; spr = spr->_next) { + if (distance(spr) < 2) { + if (!spr->_flags._near) { + _vm->feedSnail(spr, NEAR); + spr->_flags._near = true; + } + } else { + spr->_flags._near = false; + } + } + } + + if (_flags._hold || _tracePtr < 0) + park(); + else { + if (_here == Trace[_tracePtr]) { + if (--_tracePtr < 0) + park(); + } else { + signed char dx, dz; + (Trace[_tracePtr] - _here).split(dx, dz); + DIR d = (dx) ? ((dx > 0) ? EE : WW) : ((dz > 0) ? SS : NN); + turn(d); + } + } + step(); + if ((Dir == WW && _x <= 0) || + (Dir == EE && _x + _w >= SCR_WID) || + (Dir == SS && _y + _w >= WORLD_HIG - 2)) + park(); + else { + signed char x; // dummy var + _here.split(x, _z); // take current Z position + SNPOST_(SNZTRIM, -1, 0, this); // update Hero's pos in show queue + } +} + + +int WALK::distance(Sprite *spr) { + int dx, dz; + dx = spr->_x - (_x + _w - WALKSIDE); + if (dx < 0) + dx = (_x + WALKSIDE) - (spr->_x + spr->_w); + + if (dx < 0) + dx = 0; + + dx /= MAP_XGRID; + dz = spr->_z - _z; + if (dz < 0) + dz = - dz; + + dx = dx * dx + dz * dz; + for (dz = 1; dz * dz < dx; dz++) + ; + + return dz - 1; +} + + +void WALK::turn(DIR d) { + DIR dir = (Dir == NO_DIR) ? SS : Dir; + if (d != Dir) { + step((d == dir) ? (1 + dir + dir) : (9 + 4 * dir + d)); + Dir = d; + } +} + + +void WALK::park() { + if (_time == 0) + ++_time; + + if (Dir != NO_DIR) { + step(9 + 4 * Dir + Dir); + Dir = NO_DIR; + _tracePtr = -1; + } +} + + +void WALK::findWay(Cluster c) { + warning("STUB: WALK::findWay"); + /* + bool Find1Way(); + extern uint16 Target; + + if (c != Here) { + for (FindLevel = 1; FindLevel <= MAX_FIND_LEVEL; FindLevel++) { + signed char x, z; + Here.Split(x, z); + Target = (z << 8) | x; + c.Split(x, z); + _CX = (z << 8) | x; + if (Find1Way()) + break; + } + TracePtr = (FindLevel > MAX_FIND_LEVEL) ? -1 : (FindLevel - 1); + if (TracePtr < 0) + NoWay(); + Time = 1; + } +*/ +} + + +void WALK::findWay(Sprite *spr) { + if (spr && spr != this) { + int x = spr->_x; + int z = spr->_z; + if (spr->_flags._east) + x += spr->_w + _w / 2 - WALKSIDE; + else + x -= _w / 2 - WALKSIDE; + findWay(Cluster((x / MAP_XGRID), + ((z < MAP_ZCNT - MAX_DISTANCE) ? (z + 1) + : (z - 1)))); + } +} + + +bool WALK::lower(Sprite *spr) { + return (spr->_y > _y + (_h * 3) / 5); +} + + +void WALK::reach(Sprite *spr, int mode) { + if (spr) { + _hero->findWay(spr); + if (mode < 0) { + mode = spr->_flags._east; + if (lower(spr)) + mode += 2; + } + } + // note: insert SNAIL commands in reverse order + SNINSERT(SNPAUSE, -1, 64, NULL); + SNINSERT(SNSEQ, -1, TSEQ + mode, this); + if (spr) { + SNINSERT(SNWAIT, -1, -1, _hero); /////--------$$$$$$$ + //SNINSERT(SNWALK, -1, -1, spr); + } + // sequence is not finished, + // now it is just at sprite appear (disappear) point +} + + +class SQUARE : public Sprite { +public: + SQUARE(CGEEngine *vm); + virtual void touch(uint16 mask, int x, int y); +private: + CGEEngine *_vm; +}; + + +SQUARE::SQUARE(CGEEngine *vm) + : Sprite(vm, MB), _vm(vm) { + _flags._kill = true; + _flags._bDel = false; +} + + +void SQUARE::touch(uint16 mask, int x, int y) { + Sprite::touch(mask, x, y); + if (mask & L_UP) { + XZ(_x + x, _y + y).cell() = 0; + SNPOST_(SNKILL, -1, 0, this); + } +} + + +void CGEEngine::setMapBrick(int x, int z) { + SQUARE *s = new SQUARE(this); + if (s) { + static char n[] = "00:00"; + s->gotoxy(x * MAP_XGRID, MAP_TOP + z * MAP_ZGRID); + wtom(x, n + 0, 10, 2); + wtom(z, n + 3, 10, 2); + Cluster::_map[z][x] = 1; + s->setName(n); + _vga->_showQ->insert(s, _vga->_showQ->first()); + } +} + +//static void switchColorMode(); +//static void switchDebug(); +//static void pullSprite(); +//static void NextStep(); + +void CGEEngine::keyClick() { + SNPOST_(SNSOUND, -1, 5, NULL); +} + + +void CGEEngine::resetQSwitch() { + SNPOST_(SNSEQ, 123, 0, NULL); + keyClick(); +} + + +void CGEEngine::quit() { + static Choice QuitMenu[] = { + { NULL, &CGEEngine::startCountDown }, + { NULL, &CGEEngine::resetQSwitch }, + { NULL, &CGEEngine::dummy } + }; + + if (_snail->idle() && !_hero->_flags._hide) { + if (Vmenu::_addr) { + SNPOST_(SNKILL, -1, 0, Vmenu::_addr); + resetQSwitch(); + } else { + QuitMenu[0]._text = _text->getText(QUIT_TEXT); + QuitMenu[1]._text = _text->getText(NOQUIT_TEXT); + (new Vmenu(this, QuitMenu, -1, -1))->setName(_text->getText(QUIT_TITLE)); + SNPOST_(SNSEQ, 123, 1, NULL); + keyClick(); + } + } +} + + +static void AltCtrlDel() { + SNPOST_(SNSAY, -1, A_C_D_TEXT, _hero); +} + +// Used in stubbed function, do not remove! +static void miniStep(int stp) { + if (stp < 0) + _miniCave->_flags._hide = true; + else { + &*_mini; + *_miniShp[0] = *_miniShpList[stp]; + if (_fx._current) + &*(_fx._current->eAddr()); + + _miniCave->_flags._hide = false; + } +} + + +static void postMiniStep(int stp) { + //static int recent = -2; + //TODO Change the SNPOST message send to a special way to send function pointer + //if (MiniCave && stp != recent) SNPOST_(SNEXEC, -1, recent = stp, (void *)&MiniStep); + warning("STUB: PostMiniStep()"); +} + +void System::setPal() { + uint i; + Dac *p = Vga::_sysPal + 256 - ArrayCount(_stdPal); + for (i = 0; i < ArrayCount(_stdPal); i++) { + p[i]._r = _stdPal[i]._r >> 2; + p[i]._g = _stdPal[i]._g >> 2; + p[i]._b = _stdPal[i]._b >> 2; + } +} + + +void System::funTouch() { + uint16 n = (PAIN) ? HEROFUN1 : HEROFUN0; + if (_talk == NULL || n > _funDel) + _funDel = n; +} + + +static void ShowBak(int ref) { + Sprite *spr = _vga->_spareQ->locate(ref); + if (spr) { + Bitmap::_pal = Vga::_sysPal; + spr->expand(); + Bitmap::_pal = NULL; + spr->show(2); + _vga->copyPage(1, 2); + _sys->setPal(); + spr->contract(); + } +} + + +void CGEEngine::caveUp() { + int BakRef = 1000 * _now; + if (_music) + loadMidi(_now); + + ShowBak(BakRef); + loadMapping(); + _text->preload(BakRef, BakRef + 1000); + Sprite *spr = _vga->_spareQ->first(); + while (spr) { + Sprite *n = spr->_next; + if (spr->_cave == _now || spr->_cave == 0) + if (spr->_ref != BakRef) { + if (spr->_flags._back) + spr->backShow(); + else + expandSprite(spr); + } + spr = n; + } + if (_sndDrvInfo._dDev) { + _sound.stop(); + _fx.clear(); + _fx.preload(0); + _fx.preload(BakRef); + } + + if (_hero) { + _hero->gotoxy(_heroXY[_now - 1]._x, _heroXY[_now - 1]._y); + // following 2 lines trims Hero's Z position! + _hero->tick(); + _hero->_time = 1; + _hero->_flags._hide = false; + } + + if (!_dark) + _vga->sunset(); + + _vga->copyPage(0, 1); + selectPocket(-1); + if (_hero) + _vga->_showQ->insert(_vga->_showQ->remove(_hero)); + + if (_shadow) { + _vga->_showQ->remove(_shadow); + _shadow->makeXlat(glass(Vga::_sysPal, 204, 204, 204)); + _vga->_showQ->insert(_shadow, _hero); + _shadow->_z = _hero->_z; + } + feedSnail(_vga->_showQ->locate(BakRef + 999), TAKE); + _vga->show(); + _vga->copyPage(1, 0); + _vga->show(); + _vga->sunrise(Vga::_sysPal); + _dark = false; + if (!_startupMode) + _mouse->On(); + + _heart->_enable = true; +} + + +void CGEEngine::caveDown() { + Sprite *spr; + if (!_horzLine->_flags._hide) + switchMapping(); + + for (spr = _vga->_showQ->first(); spr;) { + Sprite *n = spr->_next; + if (spr->_ref >= 1000 /*&& spr->_cave*/) { + if (spr->_ref % 1000 == 999) + feedSnail(spr, TAKE); + _vga->_spareQ->append(_vga->_showQ->remove(spr)); + } + spr = n; + } + _text->clear(1000); +} + + +void CGEEngine::xCave() { + caveDown(); + caveUp(); +} + + +void CGEEngine::qGame() { + caveDown(); + _oldLev = _lev; + saveSound(); + CFile file = CFile(usrPath(_usrFnam), WRI, RCrypt); + saveGame(file); + _vga->sunset(); + _finis = true; +} + + +void CGEEngine::switchCave(int cav) { + if (cav != _now) { + _heart->_enable = false; + if (cav < 0) { + SNPOST(SNLABEL, -1, 0, NULL); // wait for repaint + //TODO Change the SNPOST message send to a special way to send function pointer + //SNPOST(SNEXEC, -1, 0, (void *)&QGame); // switch cave + warning("SwitchCave() - SNPOST"); + } else { + _now = cav; + _mouse->Off(); + if (_hero) { + _hero->park(); + _hero->step(0); + if (!_isDemo) + ///// protection: auto-destruction on! ---------------------- + _vga->_spareQ->_show = Startup::_summa * (cav <= CAVE_MAX); + /////-------------------------------------------------------- + } + _cavLight->gotoxy(CAVE_X + ((_now - 1) % CAVE_NX) * CAVE_DX + CAVE_SX, + CAVE_Y + ((_now - 1) / CAVE_NX) * CAVE_DY + CAVE_SY); + killText(); + if (!_startupMode) + keyClick(); + SNPOST(SNLABEL, -1, 0, NULL); // wait for repaint + //TODO Change the SNPOST message send to a special way to send function pointer + //SNPOST(SNEXEC, 0, 0, (void *)&XCave); // switch cave + warning("SwitchCave() - SNPOST"); + } + } +} + +System::System(CGEEngine *vm) : Sprite(vm, NULL), _vm(vm) { + _funDel = HEROFUN0; + setPal(); + tick(); +} + +void System::touch(uint16 mask, int x, int y) { + static int pp = 0; + + funTouch(); + + if (mask & KEYB) { + int pp0; + _vm->keyClick(); + killText(); + if (_vm->_startupMode == 1) { + SNPOST(SNCLEAR, -1, 0, NULL); + return; + } + pp0 = pp; + switch (x) { + case Del: + if (_keyboard->_key[ALT] && _keyboard->_key[CTRL]) + AltCtrlDel(); + else + _vm->killSprite(); + break; + case 'F': + if (_keyboard->_key[ALT]) { + Sprite *m = _vga->_showQ->locate(17001); + if (m) { + m->step(1); + m->_time = 216; // 3s + } + } + break; + case PgUp: + _vm->pushSprite(); + break; + case PgDn: + _vm->pullSprite(); + break; + case '+': + _vm->nextStep(); + break; + case '`': + if (_keyboard->_key[ALT]) + _vm->saveMapping(); + else + _vm->switchMapping(); + break; + case F1: + _vm->switchDebug(); + break; + case F3: + _hero->step(TSEQ + 4); + break; + case F4: + _hero->step(TSEQ + 5); + break; + case F5: + _hero->step(TSEQ + 0); + break; + case F6: + _hero->step(TSEQ + 1); + break; + case F7: + _hero->step(TSEQ + 2); + break; + case F8: + _hero->step(TSEQ + 3); + break; + case F9: + _sys->_funDel = 1; + break; + case 'X': + if (_keyboard->_key[ALT]) + _finis = true; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + if (_keyboard->_key[ALT]) { + SNPOST(SNLEVEL, -1, x - '0', NULL); + break; + } + case '5': + case '6': + case '7': + case '8': + case '9': + if (_sprite) + _sprite->step(x - '0'); + break; + case F10 : + if (_snail->idle() && !_hero->_flags._hide) + _vm->startCountDown(); + break; + case 'J': + if (pp == 0) + pp++; + break; + case 'B': + if (pp == 1) + pp++; + break; + case 'W': + if (pp == 2) + _vm->_jbw = !_vm->_jbw; + break; + } + if (pp == pp0) + pp = 0; + } else { + if (_vm->_startupMode) + return; + int cav = 0; + _infoLine->update(NULL); + if (y >= WORLD_HIG) { + if (x < BUTTON_X) { // select cave? + if (y >= CAVE_Y && y < CAVE_Y + CAVE_NY * CAVE_DY && + x >= CAVE_X && x < CAVE_X + CAVE_NX * CAVE_DX && !_vm->_game) { + cav = ((y - CAVE_Y) / CAVE_DY) * CAVE_NX + (x - CAVE_X) / CAVE_DX + 1; + if (cav > _vm->_maxCave) + cav = 0; + } else { + cav = 0; + } + } else if (mask & L_UP) { + if (y >= POCKET_Y && y < POCKET_Y + POCKET_NY * POCKET_DY && + x >= POCKET_X && x < POCKET_X + POCKET_NX * POCKET_DX) { + int n = ((y - POCKET_Y) / POCKET_DY) * POCKET_NX + (x - POCKET_X) / POCKET_DX; + _vm->selectPocket(n); + } + } + } + + postMiniStep(cav - 1); + + if (mask & L_UP) { + if (cav && _snail->idle() && _hero->_tracePtr < 0) + _vm->switchCave(cav); + + if (!_horzLine->_flags._hide) { + if (y >= MAP_TOP && y < MAP_TOP + MAP_HIG) { + int8 x1, z1; + XZ(x, y).split(x1, z1); + Cluster::_map[z1][x1] = 1; + _vm->setMapBrick(x1, z1); + } + } else + { + if (!_talk && _snail->idle() && _hero + && y >= MAP_TOP && y < MAP_TOP + MAP_HIG && !_vm->_game) { + _hero->findWay(XZ(x, y)); + } + } + } + } +} + + +void System::tick() { + if (!_vm->_startupMode) + if (--_funDel == 0) { + killText(); + if (_snail->idle()) { + if (PAIN) + _vm->heroCover(9); + else if (Startup::_core >= CORE_MID) { + int n = new_random(100); + if (n > 96) + _vm->heroCover(6 + (_hero->_x + _hero->_w / 2 < SCR_WID / 2)); + else { + if (n > 90) + _vm->heroCover(5); + else { + if (n > 60) + _vm->heroCover(4); + else + _vm->heroCover(3); + } + } + } + } + funTouch(); + } + _time = SYSTIMERATE; +} + + +/* +static void SpkOpen() { + asm in al,0x61 + asm or al,0x03 + asm out 0x61,al + asm mov al,0x90 + asm out 0x43,al +} + + +static void SpkClose() { + asm in al,0x61 + asm and al,0xFC + asm out 0x61,al +} + +*/ + + +void CGEEngine::switchColorMode() { + SNPOST_(SNSEQ, 121, _vga->_mono = !_vga->_mono, NULL); + keyClick(); + _vga->setColors(Vga::_sysPal, 64); +} + + + +void CGEEngine::switchMusic() { + if (_keyboard->_key[ALT]) { + if (Vmenu::_addr) + SNPOST_(SNKILL, -1, 0, Vmenu::_addr); + else { + SNPOST_(SNSEQ, 122, (_music = false), NULL); + //TODO Change the SNPOST message send to a special way to send function pointer + // SNPOST(SNEXEC, -1, 0, (void *)&selectSound); + warning("SwitchMusic() - SNPOST"); + } + } else { + if (Startup::_core < CORE_HIG) + SNPOST(SNINF, -1, NOMUSIC_TEXT, NULL); + else { + SNPOST_(SNSEQ, 122, (_music = !_music), NULL); + keyClick(); + } + } + if (_music) + loadMidi(_now); + else + killMidi(); +} + + +void CGEEngine::startCountDown() { + //SNPOST(SNSEQ, 123, 0, NULL); + switchCave(-1); +} + + +void CGEEngine::takeName() { + if (GetText::_ptr) + SNPOST_(SNKILL, -1, 0, GetText::_ptr); + else { + GetText *tn = new GetText(this, _text->getText(GETNAME_PROMPT), _usrFnam, 8); + if (tn) { + tn->setName(_text->getText(GETNAME_TITLE)); + tn->center(); + tn->gotoxy(tn->_x, tn->_y - 10); + tn->_z = 126; + _vga->_showQ->insert(tn); + } + } +} + + +void CGEEngine::switchMapping() { + if (_horzLine->_flags._hide) { + int i; + for (i = 0; i < MAP_ZCNT; i++) { + int j; + for (j = 0; j < MAP_XCNT; j++) { + if (Cluster::_map[i][j]) + setMapBrick(j, i); + } + } + } else { + Sprite *s; + for (s = _vga->_showQ->first(); s; s = s->_next) + if (s->_w == MAP_XGRID && s->_h == MAP_ZGRID) + SNPOST_(SNKILL, -1, 0, s); + } + _horzLine->_flags._hide = !_horzLine->_flags._hide; +} + +void CGEEngine::killSprite() { + _sprite->_flags._kill = true; + _sprite->_flags._bDel = true; + SNPOST_(SNKILL, -1, 0, _sprite); + _sprite = NULL; +} + +void CGEEngine::pushSprite() { + Sprite *spr = _sprite->_prev; + if (spr) { + _vga->_showQ->insert(_vga->_showQ->remove(_sprite), spr); + while (_sprite->_z > _sprite->_next->_z) + _sprite->_z--; + } else + SNPOST_(SNSOUND, -1, 2, NULL); +} + +void CGEEngine::pullSprite() { + bool ok = false; + Sprite *spr = _sprite->_next; + if (spr) { + spr = spr->_next; + if (spr) + ok = (!spr->_flags._slav); + } + if (ok) { + _vga->_showQ->insert(_vga->_showQ->remove(_sprite), spr); + if (_sprite->_prev) + while (_sprite->_z < _sprite->_prev->_z) + _sprite->_z++; + } else + SNPOST_(SNSOUND, -1, 2, NULL); +} + +void CGEEngine::nextStep() { + SNPOST_(SNSTEP, 0, 0, _sprite); +} + +void CGEEngine::saveMapping() { + { + IoHand cf(progName(".TAB"), UPD); + if (!cf._error) { + cf.seek((_now - 1) * sizeof(Cluster::_map)); + cf.write((uint8 *) Cluster::_map, sizeof(Cluster::_map)); + } + } + { + IoHand cf(progName(".HXY"), WRI); + if (!cf._error) { + _heroXY[_now - 1]._x = _hero->_x; + _heroXY[_now - 1]._y = _hero->_y; + cf.write((uint8 *) _heroXY, sizeof(_heroXY)); + } + } +} + +// 1111111111222222222233333333 334444444444555555555566666666667777777777 +// 01234567890123456789012345678901234567 890123456789012345678901234567890123456789 +static char DebugText[] = " N=00000 F=000000 X=000 Y=000 FPS=0000\0S=00:00 000:000:000 000:000 00 "; + +#define NFRE (DebugText + 3) +#define FFRE (DebugText + 11) +#define ABSX (DebugText + 20) +#define ABSY (DebugText + 26) +#define FRPS (DebugText + 34) +#define XSPR (DebugText + 38) +#define SP_N (DebugText + 41) +#define SP_S (DebugText + 44) + +#define SP_X (DebugText + 47) +#define SP_Y (DebugText + 51) +#define SP_Z (DebugText + 55) +#define SP_W (DebugText + 59) +#define SP_H (DebugText + 63) +#define SP_F (DebugText + 67) +#define SP__ (DebugText + 70) + +void CGEEngine::sayDebug() { + if (!_debugLine->_flags._hide) { + static long t = -1L; + long t1 = timer(); + + if (t1 - t >= 18) { + static uint32 old = 0L; + uint32 now = _vga->_frmCnt; + dwtom(now - old, FRPS, 10, 4); + old = now; + t = t1; + } + + dwtom(_mouse->_x, ABSX, 10, 3); + dwtom(_mouse->_y, ABSY, 10, 3); +// dwtom(coreleft(), NFRE, 10, 5); +// dwtom(farcoreleft(), FFRE, 10, 6); + + // sprite queue size + uint16 n = 0; + Sprite *spr; + for (spr = _vga->_showQ->first(); spr; spr = spr->_next) { + ++ n; + if (spr == _sprite) { + *XSPR = ' '; + dwtom(n, SP_N, 10, 2); + dwtom(_sprite->_x, SP_X, 10, 3); + dwtom(_sprite->_y, SP_Y, 10, 3); + dwtom(_sprite->_z, SP_Z, 10, 3); + dwtom(_sprite->_w, SP_W, 10, 3); + dwtom(_sprite->_h, SP_H, 10, 3); + dwtom(*(uint16 *)(&_sprite->_flags), SP_F, 16, 2); + } + } + dwtom(n, SP_S, 10, 2); +// *SP__ = (heapcheck() < 0) ? '!' : ' '; + _debugLine->update(DebugText); + } +} + + +void CGEEngine::switchDebug() { + _debugLine->_flags._hide = !_debugLine->_flags._hide; +} + + +void CGEEngine::optionTouch(int opt, uint16 mask) { + switch (opt) { + case 1 : + if (mask & L_UP) + switchColorMode(); + break; + case 2 : + if (mask & L_UP) + switchMusic(); + else if (mask & R_UP) + if (!Mixer::_appear) { + Mixer::_appear = true; + new Mixer(this, BUTTON_X, BUTTON_Y); + } + break; + case 3 : + if (mask & L_UP) + quit(); + break; + } +} + + +#pragma argsused +void Sprite::touch(uint16 mask, int x, int y) { + _sys->funTouch(); + if ((mask & ATTN) == 0) { + _infoLine->update(name()); + if (mask & (R_DN | L_DN)) + _sprite = this; + if (_ref / 10 == 12) { + _vm->optionTouch(_ref % 10, mask); + return; + } + if (_flags._syst) + return; // cannot access system sprites + if (_vm->_game) if (mask & L_UP) { + mask &= ~L_UP; + mask |= R_UP; + } + if ((mask & R_UP) && _snail->idle()) { + Sprite *ps = (_pocLight->_seqPtr) ? _pocket[_vm->_pocPtr] : NULL; + if (ps) { + if (_flags._kept || _hero->distance(this) < MAX_DISTANCE) { + if (works(ps)) { + _vm->feedSnail(ps, TAKE); + } else + _vm->offUse(); + _vm->selectPocket(-1); + } else + _vm->tooFar(); + } else { + if (_flags._kept) + mask |= L_UP; + else { + if (_hero->distance(this) < MAX_DISTANCE) { + /// + if (_flags._port) { + if (_vm->findPocket(NULL) < 0) + _vm->pocFul(); + else { + SNPOST(SNREACH, -1, -1, this); + SNPOST(SNKEEP, -1, -1, this); + _flags._port = false; + } + } else { + if (_takePtr != NO_PTR) { + if (snList(TAKE)[_takePtr]._com == SNNEXT) + _vm->offUse(); + else + _vm->feedSnail(this, TAKE); + } else + _vm->offUse(); + } + }/// + else + _vm->tooFar(); + } + } + } + if ((mask & L_UP) && _snail->idle()) { + if (_flags._kept) { + int n; + for (n = 0; n < POCKET_NX; n++) { + if (_pocket[n] == this) { + _vm->selectPocket(n); + break; + } + } + } else + SNPOST(SNWALK, -1, -1, this); // Hero->FindWay(this); + } + } +} + + +void CGEEngine::loadSprite(const char *fname, int ref, int cav, int col = 0, int row = 0, int pos = 0) { + static const char *Comd[] = { "Name", "Type", "Phase", "East", + "Left", "Right", "Top", "Bottom", + "Seq", "Near", "Take", + "Portable", "Transparent", + NULL + }; + static const char *Type[] = { "DEAD", "AUTO", "WALK", "NEWTON", "LISSAJOUS", + "FLY", NULL + }; + char line[LINE_MAX]; + + int shpcnt = 0; + int type = 0; // DEAD + bool east = false; + bool port = false; + bool tran = false; + int i, lcnt = 0; + uint16 len; + + mergeExt(line, fname, SPR_EXT); + if (INI_FILE::exist(line)) { // sprite description file exist + INI_FILE sprf(line); + if (sprf._error) + error("Bad SPR [%s]", line); + + while ((len = sprf.read((uint8 *)line)) != 0) { + ++ lcnt; + if (len && line[len - 1] == '\n') + line[-- len] = '\0'; + if (len == 0 || *line == '.') + continue; + + if ((i = takeEnum(Comd, strtok(line, " =\t"))) < 0) + error("Bad line %d [%s]", lcnt, fname); + + + switch (i) { + case 0 : // Name - will be taken in Expand routine + break; + case 1 : // Type + if ((type = takeEnum(Type, strtok(NULL, " \t,;/"))) < 0) + error("Bad line %d [%s]", lcnt, fname); + break; + case 2 : // Phase + ++ shpcnt; + break; + case 3 : // East + east = (atoi(strtok(NULL, " \t,;/")) != 0); + break; + case 11 : // Portable + port = (atoi(strtok(NULL, " \t,;/")) != 0); + break; + case 12 : // Transparent + tran = (atoi(strtok(NULL, " \t,;/")) != 0); + break; + } + } + if (! shpcnt) + error("No shapes [%s]", fname); + } else { // no sprite description: mono-shaped sprite with only .BMP file + ++shpcnt; + } + + // make sprite of choosen type + switch (type) { + case 1 : { // AUTO + _sprite = new Sprite(this, NULL); + if (_sprite) { + _sprite->gotoxy(col, row); + //Sprite->Time = 1;//-----------$$$$$$$$$$$$$$$$ + } + break; + } + case 2 : { // WALK + WALK *w = new WALK(this, NULL); + if (w && ref == 1) { + w->gotoxy(col, row); + if (_hero) + error("2nd HERO [%s]", fname); + _hero = w; + } + _sprite = w; + break; + } + /* + case 3 : // NEWTON + NEWTON * n = new NEWTON(NULL); + if (n) + { + n->Ay = (bottom-n->H); + n->By = 90; + n->Cy = 3; + n->Bx = 99; + n->Cx = 3; + n->Goto(col, row); + } + _sprite = n; + break; + */ + case 4 : { // LISSAJOUS + error("Bad type [%s]", fname); + /* + LISSAJOUS * l = new LISSAJOUS(NULL); + if (l) + { + l->Ax = SCR_WID/2; + l->Ay = SCR_HIG/2; + l->Bx = 7; + l->By = 13; + l->Cx = 300; + l->Cy = 500; + *(long *) &l->Dx = 0; // movex * cnt + l->Goto(col, row); + } + _sprite = l; + */ + break; + } + case 5 : { // FLY + Fly *f = new Fly(this, NULL); + _sprite = f; + //////Sprite->Time = 1;//-----------$$$$$$$$$$$$$$ + break; + } + default: { // DEAD + _sprite = new Sprite(this, NULL); + if (_sprite) + _sprite->gotoxy(col, row); + break; + } + } + if (_sprite) { + _sprite->_ref = ref; + _sprite->_cave = cav; + _sprite->_z = pos; + _sprite->_flags._east = east; + _sprite->_flags._port = port; + _sprite->_flags._tran = tran; + _sprite->_flags._kill = true; + _sprite->_flags._bDel = true; + + // Extract the filename, without the extension + strcpy(_sprite->_file, fname); + char *p = strchr(_sprite->_file, '.'); + if (p) + *p = '\0'; + + _sprite->_shpCnt = shpcnt; + _vga->_spareQ->append(_sprite); + } +} + + +void CGEEngine::loadScript(const char *fname) { + char line[LINE_MAX]; + char *SpN; + int SpI, SpA, SpX, SpY, SpZ; + bool BkG = false; + INI_FILE scrf(fname); + int lcnt = 0; + bool ok = true; + + if (scrf._error) + return; + + while (scrf.read((uint8 *)line) != 0) { + char *p; + + lcnt++; + if (*line == 0 || *line == '\n' || *line == '.') + continue; + + ok = false; // not OK if break + // sprite ident number + if ((p = strtok(line, " \t\n")) == NULL) + break; + SpI = atoi(p); + // sprite file name + if ((SpN = strtok(NULL, " ,;/\t\n")) == NULL) + break; + // sprite cave + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) + break; + SpA = atoi(p); + // sprite column + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) + break; + SpX = atoi(p); + // sprite row + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) + break; + SpY = atoi(p); + // sprite Z pos + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) + break; + SpZ = atoi(p); + // sprite life + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) + break; + BkG = atoi(p) == 0; + + ok = true; // no break: OK + + _sprite = NULL; + loadSprite(SpN, SpI, SpA, SpX, SpY, SpZ); + if (_sprite && BkG) + _sprite->_flags._back = true; + } + if (! ok) + error("Bad INI line %d [%s]", lcnt, fname); +} + +#define GAME_FRAME_DELAY (1000 / 50) + +void CGEEngine::mainLoop() { + sayDebug(); + + if (_isDemo) { +// static uint32 tc = 0; + if (/* FIXME: TimerCount - tc >= ((182L * 6L) * 5L) && */ _talk == NULL && _snail->idle()) { + if (_text->getText(_demoText)) { + SNPOST(SNSOUND, -1, 4, NULL); // drumla + SNPOST(SNINF, -1, _demoText, NULL); + SNPOST(SNLABEL, -1, -1, NULL); + if (_text->getText(++_demoText) == NULL) + _demoText = DEMO_TEXT + 1; + } + //FIXME: tc = TimerCount; + } + } + _vga->show(); + _snail_->runCom(); + _snail->runCom(); + + // Game frame delay + uint32 millis = g_system->getMillis(); + while (!_eventManager->_quitFlag && (millis < (_lastFrame + GAME_FRAME_DELAY))) { + // Handle any pending events + _eventManager->poll(); + + // Slight delay + g_system->delayMillis(10); + millis = g_system->getMillis(); + } + _lastFrame = millis; + + // Dispatch the tick to any active objects + tick(); +} + +void CGEEngine::tick() { + for (Sprite *spr = _vga->_showQ->first(); spr; spr = spr->_next) { + if (spr->_time) { + if (!spr->_flags._hide) { + if (--spr->_time == 0) + spr->tick(); + } + } + } +} + +void CGEEngine::loadUser() { + // set scene + if (Startup::_mode == 0) { // user .SVG file found + CFile cfile = CFile(usrPath(_usrFnam), REA, RCrypt); + loadGame(cfile); + } else { + if (Startup::_mode == 1) { + SVG0FILE file = SVG0FILE(SVG0NAME); + loadGame(file); + } else { + loadScript(progName(INI_EXT)); + _music = true; + CFile file = CFile(SVG0NAME, WRI); + saveGame(file); + error("Ok [%s]", SVG0NAME); + } + } + loadScript(progName(IN0_EXT)); +} + + +void CGEEngine::runGame() { + if (_eventManager->_quitFlag) + return; + + _text->clear(); + _text->preload(100, 1000); + loadHeroXY(); + + _cavLight->_flags._tran = true; + _vga->_showQ->append(_cavLight); + _cavLight->_flags._hide = true; + + static Seq pocSeq[] = { { 0, 0, 0, 0, 20 }, + { 1, 2, 0, 0, 4 }, + { 2, 3, 0, 0, 4 }, + { 3, 4, 0, 0, 16 }, + { 2, 5, 0, 0, 4 }, + { 1, 6, 0, 0, 4 }, + { 0, 1, 0, 0, 16 }, + }; + _pocLight->setSeq(pocSeq); + _pocLight->_flags._tran = true; + _pocLight->_time = 1; + _pocLight->_z = 120; + _vga->_showQ->append(_pocLight); + selectPocket(-1); + + // FIXME: Allow ScummVM to handle mouse display +// Vga->ShowQ->Append(Mouse); + +// ___________ + loadUser(); +// ~~~~~~~~~~~ + + if ((_sprite = _vga->_spareQ->locate(121)) != NULL) + SNPOST_(SNSEQ, -1, _vga->_mono, _sprite); + if ((_sprite = _vga->_spareQ->locate(122)) != NULL) + _sprite->step(_music); + SNPOST_(SNSEQ, -1, _music, _sprite); + if (!_music) + killMidi(); + + if (_mini && INI_FILE::exist("MINI.SPR")) { + uint8 *ptr = (uint8 *) &*_mini; + if (ptr != NULL) { + loadSprite("MINI", -1, 0, MINI_X, MINI_Y); + expandSprite(_miniCave = _sprite); // NULL is ok + if (_miniCave) { + _miniCave->_flags._hide = true; + _miniCave->moveShapes(ptr); + _miniShp[0] = new Bitmap(*_miniCave->shp()); + _miniShpList = _miniCave->setShapeList(_miniShp); + postMiniStep(-1); + } + } + } + + if (_hero) { + expandSprite(_hero); + _hero->gotoxy(_heroXY[_now - 1]._x, _heroXY[_now - 1]._y); + if (INI_FILE::exist("00SHADOW.SPR")) { + loadSprite("00SHADOW", -1, 0, _hero->_x + 14, _hero->_y + 51); + if ((_shadow = _sprite) != NULL) { + _shadow->_ref = 2; + _shadow->_flags._tran = true; + _hero->_flags._shad = true; + _vga->_showQ->insert(_vga->_spareQ->remove(_shadow), _hero); + } + } + } + + _infoLine->gotoxy(INFO_X, INFO_Y); + _infoLine->_flags._tran = true; + _infoLine->update(NULL); + _vga->_showQ->insert(_infoLine); + + _debugLine->_z = 126; + _vga->_showQ->insert(_debugLine); + + _horzLine->_y = MAP_TOP - (MAP_TOP > 0); + _horzLine->_z = 126; + _vga->_showQ->insert(_horzLine); + + _mouse->Busy = _vga->_spareQ->locate(BUSY_REF); + if (_mouse->Busy) + expandSprite(_mouse->Busy); + + _startupMode = 0; + + SNPOST(SNLEVEL, -1, _oldLev, &_cavLight); + _cavLight->gotoxy(CAVE_X + ((_now - 1) % CAVE_NX) * CAVE_DX + CAVE_SX, + CAVE_Y + ((_now - 1) / CAVE_NX) * CAVE_DY + CAVE_SY); + caveUp(); + + _keyboard->setClient(_sys); + // main loop + while (!_finis && !_eventManager->_quitFlag) { + //TODO Change the SNPOST message send to a special way to send function pointer + // if (FINIS) SNPOST(SNEXEC, -1, 0, (void *)&QGame); + warning("RunGame: problematic use of SNPOST"); + mainLoop(); + } + + _keyboard->setClient(NULL); + _heart->_enable = false; + SNPOST(SNCLEAR, -1, 0, NULL); + SNPOST_(SNCLEAR, -1, 0, NULL); + _mouse->Off(); + _vga->_showQ->clear(); + _vga->_spareQ->clear(); + _hero = NULL; + _shadow = NULL; +} + + +void CGEEngine::movie(const char *ext) { + if (_eventManager->_quitFlag) + return; + + const char *fn = progName(ext); + if (INI_FILE::exist(fn)) { + loadScript(fn); + expandSprite(_vga->_spareQ->locate(999)); + feedSnail(_vga->_showQ->locate(999), TAKE); + + // FIXME: Allow ScummVM to handle mouse display + //Vga->ShowQ->Append(Mouse); + + _heart->_enable = true; + _keyboard->setClient(_sys); + while (!_snail->idle() && !_eventManager->_quitFlag) + mainLoop(); + + _keyboard->setClient(NULL); + _heart->_enable = false; + SNPOST(SNCLEAR, -1, 0, NULL); + SNPOST_(SNCLEAR, -1, 0, NULL); + _vga->_showQ->clear(); + _vga->_spareQ->clear(); + } +} + + +bool CGEEngine::showTitle(const char *name) { + if (_eventManager->_quitFlag) + return false; + + Bitmap::_pal = Vga::_sysPal; + BMP_PTR LB[] = { new Bitmap(name, true), NULL }; + Bitmap::_pal = NULL; + bool usr_ok = false; + + Sprite D(this, LB); + D._flags._kill = true; + D._flags._bDel = true; + D.center(); + D.show(2); + + if (Startup::_mode == 2) { + inf(SVG0NAME); + _talk->show(2); + } + + _vga->sunset(); + _vga->copyPage(1, 2); + _vga->copyPage(0, 1); + selectPocket(-1); + _vga->sunrise(Vga::_sysPal); + + if (Startup::_mode < 2 && !Startup::_soundOk) { + _vga->copyPage(1, 2); + _vga->copyPage(0, 1); + _vga->_showQ->append(_mouse); + _heart->_enable = true; + _mouse->On(); + for (selectSound(); !_snail->idle() || Vmenu::_addr;) { + mainLoop(); + if (_eventManager->_quitFlag) + return false; + } + + _mouse->Off(); + _heart->_enable = false; + _vga->_showQ->clear(); + _vga->copyPage(0, 2); + Startup::_soundOk = 2; + if (_music) + loadMidi(0); + } + + if (Startup::_mode < 2) { + if (_isDemo) { + strcpy(_usrFnam, progName(SVG_EXT)); + usr_ok = true; + } else { + //----------------------------------------- +#ifndef EVA +#ifdef CD + Startup::_summa |= (0xC0 + (DriveCD(0) << 6)) & 0xFF; +#else + // At this point the game originally read the boot sector to get + // the serial number for it's copy protection check +#endif + //----------------------------------------- + movie("X00"); // paylist + _vga->copyPage(1, 2); + _vga->copyPage(0, 1); + _vga->_showQ->append(_mouse); + //Mouse.On(); + _heart->_enable = true; + for (takeName(); GetText::_ptr;) { + mainLoop(); + if (_eventManager->_quitFlag) + return false; + } + _heart->_enable = false; + if (_keyboard->last() == Enter && *_usrFnam) + usr_ok = true; + if (usr_ok) + strcat(_usrFnam, SVG_EXT); + //Mouse.Off(); + _vga->_showQ->clear(); + _vga->copyPage(0, 2); +#endif + } + + if (usr_ok && Startup::_mode == 0) { + const char *n = usrPath(_usrFnam); + if (CFile::exist(n)) { + CFile file = CFile(n, REA, RCrypt); + loadGame(file, true); // only system vars + _vga->setColors(Vga::_sysPal, 64); + _vga->update(); + if (_flag[3]) { //flag FINIS + Startup::_mode++; + _flag[3] = false; + } + } else + Startup::_mode++; + } + } + + if (Startup::_mode < 2) + movie("X01"); // wink + + _vga->copyPage(0, 2); + + if (_isDemo) + return true; + else + return (Startup::_mode == 2 || usr_ok); +} + + +/* +void StkDump () { + CFILE f("!STACK.DMP", BFW); + f.Write((uint8 *) (intStackPtr-STACK_SIZ/2), STACK_SIZ*2); +} +*/ + + +void CGEEngine::cge_main() { + uint16 intStack[STACK_SIZ / 2]; + _intStackPtr = intStack; + + //Debug( memset((void *) (-K(2)), 0, K(1)); ) + //Debug( memset((void *) (-K(4)), 0, K(1)); ) + memset(_barriers, 0xFF, sizeof(_barriers)); + + if (!_mouse->Exist) + error("%s", _text->getText(NO_MOUSE_TEXT)); + + if (!SVG0FILE::exist(SVG0NAME)) + Startup::_mode = 2; + + _debugLine->_flags._hide = true; + _horzLine->_flags._hide = true; + + //srand((uint16) Timer()); + _sys = new System(this); + + if (_music && Startup::_soundOk) + loadMidi(0); + if (Startup::_mode < 2) + movie(LGO_EXT); + + if (showTitle("WELCOME")) { + if ((!_isDemo) && (Startup::_mode == 1)) + movie("X02"); // intro + runGame(); + _startupMode = 2; + if (_flag[3]) // Flag FINIS + movie("X03"); + } else + _vga->sunset(); +} + +} // End of namespace CGE diff --git a/engines/cge/cge_main.h b/engines/cge/cge_main.h new file mode 100644 index 0000000000..3ef3679e8e --- /dev/null +++ b/engines/cge/cge_main.h @@ -0,0 +1,194 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_CGE__ +#define __CGE_CGE__ + +#include "cge/wav.h" +#include "cge/vga13h.h" +#include "cge/events.h" + +namespace CGE { + +#define TSEQ 96 +#define HTALK (TSEQ + 4) +#define TOO_FAR (TSEQ + 5) +#define NO_WAY (TSEQ + 5) +#define POC_FUL (TSEQ + 5) +#define OFF_USE (TSEQ + 6) +#define EXIT_OK_TEXT 40 +#define NOMUSIC_TEXT 98 +#define BADSVG_TEXT 99 +#define OFF_USE_COUNT 600 +#define OFF_USE_TEXT 601 +#define NO_WAY_TEXT 671 +#define TOO_FAR_TEXT 681 +#define POC_FUL_TEXT 691 +#define A_C_D_TEXT 777 +#define GETNAME_PROMPT 50 +#define GETNAME_TITLE 51 +#define QUIT_TITLE 200 +#define QUIT_TEXT 201 +#define NOQUIT_TEXT 202 +#define DEMO_TEXT 300 +#define NOSOUND_TEXT 310 +#define PAN_HIG 40 +#define WORLD_HIG (SCR_HIG - PAN_HIG) +#define INFO_X 177 +#define INFO_Y 164 +#define INFO_W 140 +#define CAVE_X 4 +#define CAVE_Y 166 +#define CAVE_SX 0 +#define CAVE_SY 0 + +#ifdef DEMO +#define CAVE_DX 23 +#define CAVE_DY 29 +#define CAVE_NX 3 +#define CAVE_NY 1 +#else +#define CAVE_DX 9 +#define CAVE_DY 10 +#define CAVE_NX 8 +#define CAVE_NY 3 +#endif + +#define BUTTON_X 151 +#define BUTTON_Y 164 +#define BUTTON_DX 19 +#define BUTTON_DY 11 +#define BUTTON_NX 1 +#define BUTTON_NY 3 +#define MINI_X 86 +#define MINI_Y 162 +#define MAP_XCNT 40 +#define MAP_ZCNT 20 +#define MAP_TOP 80 +#define MAP_HIG 80 +#define MAP_XGRID (SCR_WID / MAP_XCNT) +#define MAP_ZGRID (MAP_HIG / MAP_ZCNT) +#define LINE_MAX 512 +#define USER_MAX 100 +#define SHP_MAX 1024 +#define STD_DELAY 3 +#define LEV_MAX 5 +#define CAVE_MAX (CAVE_NX * CAVE_NY) +#define MAX_FIND_LEVEL 3 +#define MAX_DISTANCE 3 +#define INI_EXT ".INI" +#define IN0_EXT ".IN0" +#define LGO_EXT ".LGO" +#define SVG_EXT ".SVG" +#define WALKSIDE 10 +#define BUSY_REF 500 +#define SYSTIMERATE 6 // 12 Hz +#define HEROFUN0 (40 * 12) +#define HEROFUN1 ( 2 * 12) +#define PAIN (_vm->_flag[0]) +//#define FINIS (_vm->_flag[3]) + + +class System : public Sprite { + int _lum; +public: + int _funDel; + + System(CGEEngine *vm); + + void setPal(); + void funTouch(); + virtual void touch(uint16 mask, int x, int y); + void tick(); +private: + CGEEngine *_vm; +}; + + +class Cluster : public Couple { +public: + static uint8 _map[MAP_ZCNT][MAP_XCNT]; + uint8 &cell(); + Cluster() : Couple() { } + Cluster(int a, int b) : Couple(a, b) { } + bool Protected(); +}; + + +class WALK : public Sprite { +public: + Cluster _here; + int _tracePtr; + + enum DIR { NO_DIR = -1, NN, EE, SS, WW } Dir; + WALK(CGEEngine *vm, BMP_PTR *shpl); + void tick(); + void findWay(Cluster c); + void findWay(Sprite *spr); + int distance(Sprite *spr); + void turn(DIR d); + void park(); + bool lower(Sprite *spr); + void reach(Sprite *spr, int mode = -1); +private: + CGEEngine *_vm; + +}; + +Cluster XZ(int x, int y); +Cluster XZ(Couple xy); + +extern WALK *_hero; +extern Vga *_vga; +extern Heart *_heart; +extern System *_sys; +extern int _offUseCount; +extern Sprite *_pocLight; +extern Keyboard *_keyboard; +extern MOUSE *_mouse; +extern EventManager *_eventManager; +extern Sprite *_pocket[]; +extern Sprite *_sprite; +extern Sprite *_miniCave; +extern Sprite *_shadow; +extern Sprite *_horzLine; +extern InfoLine *_infoLine; +extern Sprite *_cavLight; +extern InfoLine *_debugLine; +extern BMP_PTR MB[2]; +extern BMP_PTR MB[2]; +extern BMP_PTR HL[2]; +extern BMP_PTR MC[3]; +extern BMP_PTR PR[2]; +extern BMP_PTR SP[3]; +extern BMP_PTR LI[5]; +extern Snail *_snail; +extern Snail *_snail_; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/config.cpp b/engines/cge/config.cpp new file mode 100644 index 0000000000..808d74ff9b --- /dev/null +++ b/engines/cge/config.cpp @@ -0,0 +1,282 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/config.h" +#include "cge/sound.h" +#include "cge/vmenu.h" +#include "cge/text.h" +#include "cge/cge_main.h" + +namespace CGE { + +/* + 51=wska§ typ posiadanej karty d¦wi‘kowej + 52=wybierz numer portu dla karty d¦wi‘kowej + 53=wybierz numer przerwania dla karty d¦wi‘kowej + 54=wybierz numer kana’u DMA dla karty d¦wi‘kowej + 55=wybierz numer portu dla General MIDI + 55=konfiguracja karty d¦wi‘kowej +*/ +#define STYPE_TEXT 51 +#define SPORT_TEXT 52 +#define SIRQ_TEXT 53 +#define SDMA_TEXT 54 +#define MPORT_TEXT 55 +#define MENU_TEXT 56 + +#define NONE_TEXT 60 +#define SB_TEXT 61 +#define SBM_TEXT 62 +#define GUS_TEXT 63 +#define GUSM_TEXT 64 +#define MIDI_TEXT 65 +#define AUTO_TEXT 66 + +#define DETECT 0xFFFF + + +static int DevName[] = { + NONE_TEXT, SB_TEXT, SBM_TEXT, GUS_TEXT, GUSM_TEXT, + MIDI_TEXT, AUTO_TEXT +}; + +static Choice DevMenu[] = { + { NULL, &CGEEngine::NONE }, + { NULL, &CGEEngine::SB }, + { NULL, &CGEEngine::SBM }, + { NULL, &CGEEngine::GUS }, + { NULL, &CGEEngine::GUSM }, + { NULL, &CGEEngine::MIDI }, + { NULL, &CGEEngine::AUTO }, + { NULL, NULL } +}; + + +static Choice DigiPorts[] = { + { " 210h", &CGEEngine::setPortD }, + { " 220h", &CGEEngine::setPortD }, + { " 230h", &CGEEngine::setPortD }, + { " 240h", &CGEEngine::setPortD }, + { " 250h", &CGEEngine::setPortD }, + { " 260h", &CGEEngine::setPortD }, + { "AUTO ", &CGEEngine::setPortD }, + { NULL, NULL } +}; + +static Choice MIDIPorts[] = { + { " 220h", &CGEEngine::setPortM }, + { " 230h", &CGEEngine::setPortM }, + { " 240h", &CGEEngine::setPortM }, + { " 250h", &CGEEngine::setPortM }, + { " 300h", &CGEEngine::setPortM }, + { " 320h", &CGEEngine::setPortM }, + { " 330h", &CGEEngine::setPortM }, + { " 340h", &CGEEngine::setPortM }, + { " 350h", &CGEEngine::setPortM }, + { " 360h", &CGEEngine::setPortM }, + { "AUTO ", &CGEEngine::setPortM }, + { NULL, NULL } +}; + +static Choice BlsterIRQ[] = { + { "IRQ 2", &CGEEngine::setIRQ }, + { "IRQ 5", &CGEEngine::setIRQ }, + { "IRQ 7", &CGEEngine::setIRQ }, + { "IRQ 10", &CGEEngine::setIRQ }, + { "AUTO ", &CGEEngine::setIRQ }, + { NULL, NULL } +}; + +static Choice GravisIRQ[] = { + { "IRQ 2", &CGEEngine::setIRQ }, + { "IRQ 5", &CGEEngine::setIRQ }, + { "IRQ 7", &CGEEngine::setIRQ }, + { "IRQ 11", &CGEEngine::setIRQ }, + { "IRQ 12", &CGEEngine::setIRQ }, + { "IRQ 15", &CGEEngine::setIRQ }, + { "AUTO ", &CGEEngine::setIRQ }, + { NULL, NULL } +}; + +static Choice GravisDMA[] = { + { "DMA 1", &CGEEngine::setDMA }, + { "DMA 3", &CGEEngine::setDMA }, + { "DMA 5", &CGEEngine::setDMA }, + { "DMA 6", &CGEEngine::setDMA }, + { "DMA 7", &CGEEngine::setDMA }, + { "AUTO ", &CGEEngine::setDMA }, + { NULL, NULL } +}; + +static Choice BlsterDMA[] = { + { "DMA 0", &CGEEngine::setDMA }, + { "DMA 1", &CGEEngine::setDMA }, + { "DMA 3", &CGEEngine::setDMA }, + { "AUTO ", &CGEEngine::setDMA }, + { NULL, NULL } +}; + + +void CGEEngine::selectSound() { + int i; + _sound.close(); + if (Vmenu::_addr) + SNPOST_(SNKILL, -1, 0, Vmenu::_addr); + inf(_text->getText(STYPE_TEXT)); + _talk->gotoxy(_talk->_x, FONT_HIG / 2); + for (i = 0; i < (int)ArrayCount(DevName); i++) + DevMenu[i]._text = _text->getText(DevName[i]); + (new Vmenu(this, DevMenu, SCR_WID / 2, _talk->_y + _talk->_h + TEXT_VM + FONT_HIG))->setName(_text->getText(MENU_TEXT)); +} + + +static void reset() { + _sndDrvInfo._dBase = _sndDrvInfo._dIrq = _sndDrvInfo._dDma = _sndDrvInfo._mBase = DETECT; +} + + +static uint16 deco(const char *str, uint16(*dco)(const char *)) { + while (*str && ! IsDigit(*str)) + ++str; + if (*str) + return dco(str); + else + return DETECT; +} + + +static uint16 ddeco(const char *str) { + return deco(str, atow); +} + + +static uint16 xdeco(const char *str) { + return deco(str, xtow); +} + + +static Choice *_cho; +static int _hlp; + +void CGEEngine::snSelect() { + inf(_text->getText(_hlp)); + _talk->gotoxy(_talk->_x, FONT_HIG / 2); + (new Vmenu(this, _cho, SCR_WID / 2, _talk->_y + _talk->_h + TEXT_VM + FONT_HIG))->setName(_text->getText(MENU_TEXT)); +} + + +static void select(Choice *cho, int hlp) { + _cho = cho; + _hlp = hlp; + //TODO Change the SNPOST message send to a special way to send function pointer + //SNPOST(SNEXEC, -1, 0, (void *)&SNSelect); + warning("STUB: select"); +} + + +void CGEEngine::NONE() { + _sndDrvInfo._dDev = DEV_QUIET; + _sndDrvInfo._mDev = DEV_QUIET; + _sound.open(); +} + + +void CGEEngine::SB() { + _sndDrvInfo._dDev = DEV_SB; + _sndDrvInfo._mDev = DEV_SB; + reset(); + select(DigiPorts, SPORT_TEXT); +} + + +void CGEEngine::SBM() { + _sndDrvInfo._dDev = DEV_SB; + _sndDrvInfo._mDev = DEV_GM; + reset(); + select(DigiPorts, SPORT_TEXT); +} + + +void CGEEngine::GUS() { + _sndDrvInfo._dDev = DEV_GUS; + _sndDrvInfo._mDev = DEV_GUS; + reset(); + select(DigiPorts, SPORT_TEXT); +} + + +void CGEEngine::GUSM() { + _sndDrvInfo._dDev = DEV_GUS; + _sndDrvInfo._mDev = DEV_GM; + reset(); + select(DigiPorts, SPORT_TEXT); +} + + +void CGEEngine::MIDI() { + _sndDrvInfo._dDev = DEV_QUIET; + _sndDrvInfo._mDev = DEV_GM; + _sndDrvInfo._mBase = DETECT; + select(MIDIPorts, MPORT_TEXT); +} + + +void CGEEngine::AUTO() { + _sndDrvInfo._dDev = DEV_AUTO; + _sndDrvInfo._mDev = DEV_AUTO; + reset(); + _sound.open(); +} + + +void CGEEngine::setPortD() { + _sndDrvInfo._dBase = xdeco(DigiPorts[Vmenu::_recent]._text); + select((_sndDrvInfo._dDev == DEV_SB) ? BlsterIRQ : GravisIRQ, SIRQ_TEXT); +} + + +void CGEEngine::setPortM() { + _sndDrvInfo._mBase = xdeco(MIDIPorts[Vmenu::_recent]._text); + _sound.open(); +} + + +void CGEEngine::setIRQ() { + _sndDrvInfo._dIrq = ddeco(((_sndDrvInfo._dDev == DEV_SB) ? BlsterIRQ : GravisIRQ)[Vmenu::_recent]._text); + select((_sndDrvInfo._dDev == DEV_SB) ? BlsterDMA : GravisDMA, SDMA_TEXT); +} + + +void CGEEngine::setDMA() { + _sndDrvInfo._dDma = ddeco(((_sndDrvInfo._dDev == DEV_SB) ? BlsterDMA : GravisDMA)[Vmenu::_recent]._text); + if (_sndDrvInfo._mDev != _sndDrvInfo._dDev) + select(MIDIPorts, MPORT_TEXT); + else + _sound.open(); +} + +} // End of namespace CGE diff --git a/engines/cge/config.h b/engines/cge/config.h new file mode 100644 index 0000000000..4a1e5927e5 --- /dev/null +++ b/engines/cge/config.h @@ -0,0 +1,37 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_CONFIG__ +#define __CGE_CONFIG__ + +namespace CGE { + +void selectSound(); + +} // End of namespace CGE + +#endif diff --git a/engines/cge/console.cpp b/engines/cge/console.cpp new file mode 100644 index 0000000000..71eedf34ea --- /dev/null +++ b/engines/cge/console.cpp @@ -0,0 +1,34 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "cge/console.h" +#include "cge/cge.h" + +namespace CGE { + +CGEConsole::CGEConsole(CGEEngine *vm) : GUI::Debugger(), _vm(vm) { +} + +CGEConsole::~CGEConsole() { +} + +} // End of namespace CGE diff --git a/engines/cge/console.h b/engines/cge/console.h new file mode 100644 index 0000000000..25a1a4fae3 --- /dev/null +++ b/engines/cge/console.h @@ -0,0 +1,43 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef CGE_CONSOLE_H +#define CGE_CONSOLE_H + +#include "gui/debugger.h" + +namespace CGE { + +class CGEEngine; + +class CGEConsole : public GUI::Debugger { +public: + CGEConsole(CGEEngine *vm); + virtual ~CGEConsole(); + +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp new file mode 100644 index 0000000000..31bf629fcf --- /dev/null +++ b/engines/cge/detection.cpp @@ -0,0 +1,238 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/config-manager.h" +#include "engines/advancedDetector.h" +#include "common/savefile.h" +#include "common/system.h" +#include "base/plugins.h" +#include "graphics/thumbnail.h" +#include "cge/cge.h" + +static const PlainGameDescriptor CGEGames[] = { + { "soltys", "Soltys" }, + { 0, 0 } +}; + +namespace CGE { + +using Common::GUIO_NONE; + +static const ADGameDescription gameDescriptions[] = { + + { + "soltys", "", + { + {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176}, + {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437572}, + AD_LISTEND + }, + Common::PL_POL, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + }, + { + "soltys", "Soltys Freeware", + { + {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176}, + {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676}, + AD_LISTEND + }, + Common::PL_POL, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + }, + { + "soltys", "Soltys Demo", + { + {"vol.cat", 0, "1e077c8ff58109a187f07ac54b0c873a", 18788}, + {"vol.dat", 0, "75d385a6074c58b69f7730481f256051", 1796710}, + AD_LISTEND + }, + Common::PL_POL, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE + }, + { + "soltys", "Soltys Demo", + { + {"vol.cat", 0, "f17987487fab1ebddd781d8d02fedecc", 7168}, + {"vol.dat", 0, "c5d9b15863cab61dc125551576dece04", 1075272}, + AD_LISTEND + }, + Common::PL_POL, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE + }, + AD_TABLE_END_MARKER +}; + +static const ADFileBasedFallback fileBasedFallback[] = { + { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } }, + { 0, { 0 } } +}; + +} // End of namespace CGE + +class CGEMetaEngine : public AdvancedMetaEngine { +public: + CGEMetaEngine() : AdvancedMetaEngine(CGE::gameDescriptions, sizeof(ADGameDescription), CGEGames) { + _singleid = "Soltys"; + } + + virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { + return detectGameFilebased(allFiles, CGE::fileBasedFallback); + } + + virtual const char *getName() const { + return "CGE"; + } + + virtual const char *getOriginalCopyright() const { + return "Soltys (c) 1994-1996 L.K. Avalon"; + } + + virtual bool hasFeature(MetaEngineFeature f) const; + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + virtual int getMaximumSaveSlot() const; + virtual SaveStateList listSaves(const char *target) const; + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; + virtual void removeSaveState(const char *target, int slot) const; +}; + +bool CGEMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsListSaves) || + (f == kSupportsLoadingDuringStartup) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSavesSupportCreationDate); +} + +void CGEMetaEngine::removeSaveState(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.%03d", target, slot); + g_system->getSavefileManager()->removeSavefile(fileName); +} + +int CGEMetaEngine::getMaximumSaveSlot() const { + return 99; +} + +SaveStateList CGEMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray filenames; + Common::String pattern = target; + pattern += ".???"; + + filenames = saveFileMan->listSavefiles(pattern); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + int slotNum = 0; + for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); filename++) { + // Obtain the last 3 digits of the filename, since they correspond to the save slot + slotNum = atoi(filename->c_str() + filename->size() - 3); + + if (slotNum >= 0 && slotNum <= 99) { + Common::InSaveFile *file = saveFileMan->openForLoading(*filename); + if (file) { + int32 version = file->readSint32BE(); + if (version != CGE_SAVEGAME_VERSION) { + delete file; + continue; + } + + // read name + uint16 nameSize = file->readUint16BE(); + if (nameSize >= 255) { + delete file; + continue; + } + char name[256]; + file->read(name, nameSize); + name[nameSize] = 0; + + saveList.push_back(SaveStateDescriptor(slotNum, name)); + delete file; + } + } + } + + return saveList; +} + +SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.%03d", target, slot); + Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName); + + if (file) { + + int32 version = file->readSint32BE(); + if (version != CGE_SAVEGAME_VERSION) { + delete file; + return SaveStateDescriptor(); + } + + uint32 saveNameLength = file->readUint16BE(); + char saveName[256]; + file->read(saveName, saveNameLength); + saveName[saveNameLength] = 0; + + SaveStateDescriptor desc(slot, saveName); + + Graphics::Surface *thumbnail = new Graphics::Surface(); + assert(thumbnail); + if (!Graphics::loadThumbnail(*file, *thumbnail)) { + delete thumbnail; + thumbnail = 0; + } + desc.setThumbnail(thumbnail); + + desc.setDeletableFlag(true); + desc.setWriteProtectedFlag(false); + + uint32 saveDate = file->readUint32BE(); + uint16 saveTime = file->readUint16BE(); + + int day = (saveDate >> 24) & 0xFF; + int month = (saveDate >> 16) & 0xFF; + int year = saveDate & 0xFFFF; + + desc.setSaveDate(year, month, day); + + int hour = (saveTime >> 8) & 0xFF; + int minutes = saveTime & 0xFF; + + desc.setSaveTime(hour, minutes); + + delete file; + return desc; + } + + return SaveStateDescriptor(); +} + +bool CGEMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + if (desc) { + *engine = new CGE::CGEEngine(syst, desc); + } + return desc != 0; +} + +#if PLUGIN_ENABLED_DYNAMIC(CGE) +REGISTER_PLUGIN_DYNAMIC(CGE, PLUGIN_TYPE_ENGINE, CGEMetaEngine); +#else +REGISTER_PLUGIN_STATIC(CGE, PLUGIN_TYPE_ENGINE, CGEMetaEngine); +#endif diff --git a/engines/cge/ems.cpp b/engines/cge/ems.cpp new file mode 100644 index 0000000000..93342f77da --- /dev/null +++ b/engines/cge/ems.cpp @@ -0,0 +1,225 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/general.h" + +namespace CGE { + +#define EMS_INT 0x67 +#define PAGE_MASK 0x3FFF +#define SIZ(n) ((n) ? ((long)n) : (0x10000L)) + + +enum EMM_FUN { + GET_STATUS = 0x40, GET_FRAME, GET_SIZE, OPEN_HANDLE, MAP_PAGE, + CLOSE_HANDLE, GET_VER, SAVE_CONTEXT, REST_CONTEXT, GET_PAGES = 0x4B, + GET_HANDLES, GET_INFO, CONTROL +}; + + +void *Emm::_frame = NULL; + + +Emm::Emm(long size): _han(-1), _top(0), _lim(0), _list(NULL) { + /* + if (Test()) + { + asm mov ah,GET_FRAME // get EMS frame segment + asm int EMS_INT // do it! + asm or ah,ah // see status + asm jnz xit // abort on error + Frame = (void _seg *) _BX; // save frame segment + + if (size == 0) + { + asm mov ah,GET_SIZE // get EMS memory size + asm int EMS_INT // do it! + asm or ah,ah // see status + asm jnz xit // abort on error + asm or bx,bx // test page count + asm jz xit // abort if no free pages + // number of available pages in BX is ready to use by OPEN + } + else _BX = (uint16) ((size + PAGE_MASK) >> 14); + asm mov ah,OPEN_HANDLE // open EMM handle + asm int EMS_INT // do it! + asm or ah,ah // see status + asm jnz xit // abort on error + Han = _DX; + Lim = _BX; + Lim <<= 14; + _DX = Han; + asm mov ah,SAVE_CONTEXT // save mapping context + asm int EMS_INT // do it! + } + xit: + */ + warning("STUB: EMM:EMM"); +} + + +Emm::~Emm() { + /* FIXME + Release(); + if (Han >= 0) + { + _DX = Han; + asm mov ah,REST_CONTEXT + asm int EMS_INT + asm mov ah,CLOSE_HANDLE + asm int EMS_INT + } + */ +} + + +bool Emm::test() { + /* + static char e[] = "EMMXXXX0"; + + asm mov ax,0x3D40 + asm mov dx,offset e + asm int 0x21 + asm jc fail + + asm push ax + asm mov bx,ax + asm mov ax,0x4407 + asm int 0x21 + + asm pop bx + asm push ax + asm mov ax,0x3E00 + asm int 0x21 + asm pop ax + + asm cmp al,0x00 + asm je fail + + success: + return TRUE; + fail: + return FALSE; + */ + warning("EMM::Test"); + return false; +} + + +Ems *Emm::alloc(uint16 siz) { + /* + long size = SIZ(siz), + top = Top; + + uint16 pgn = (uint16) (top >> 14), + cnt = (uint16) ((top + size + PAGE_MASK) >> 14) - pgn; + + if (cnt > 4) + { + top = (top + PAGE_MASK) & 0xFFFFC000L; + pgn++; + cnt--; + } + + if (size <= Lim - top) + { + EMS * e = new EMS, * f; + + if (e) + { + Top = (e->Ptr = top) + (e->Siz = siz); + e->Emm = this; + + if (List) + { + for (f = List; f->Nxt; f = f->Nxt); + return (f->Nxt = e); // existing list: link to the end + } + else + { + return (List = e); // empty list: link to the head + } + } + } + fail: return NULL; + */ + warning("STUB: Emm::alloc"); + return NULL; +} + + +void Emm::release() { + while (_list) { + Ems *e = _list; + _list = e->_next; + delete e; + } + _top = 0; +} + + +Ems::Ems() : _ptr(0), _size(0), _next(NULL) { +} + + +void *Ems::operator & () const { + /* + uint16 pgn = (uint16) (Ptr >> 14), + off = (uint16) Ptr & PAGE_MASK, + cnt = (uint16) ((Ptr + SIZ(Siz) + PAGE_MASK) >> 14) - pgn, + cmd = MAP_PAGE << 8; + + _DX = Emm->_han; // take EMM handle + asm dec cnt // prapare for deferred checking + asm or dx,dx // see if valid + asm jns more // negative handle = unavailable + + fail: return NULL; + + more: + asm mov ax,cmd // command + page frame index + asm mov bx,pgn // logical page number + asm int EMS_INT // do it! + asm or ah,ah // check error code + asm jnz fail // exit on error + asm inc cmd // advance page frame index + asm inc pgn // advance logical page number + asm cmp al,byte ptr cnt // all pages? + asm jb more + + return (void *) (EMM::Frame + (void *) off); + */ + warning("STUB: Ems::operator &"); + return NULL; +} + + +uint16 Ems::size() { + return _size; +} + +} // End of namespace CGE diff --git a/engines/cge/events.cpp b/engines/cge/events.cpp new file mode 100644 index 0000000000..e904b710ba --- /dev/null +++ b/engines/cge/events.cpp @@ -0,0 +1,321 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "common/events.h" +#include "cge/events.h" +#include "cge/events.h" +#include "cge/text.h" +#include "cge/cge_main.h" + +namespace CGE { + +CGEEvent Evt[EVT_MAX]; + +uint16 EvtHead = 0, EvtTail = 0; + +/*----------------- KEYBOARD interface -----------------*/ + +const uint16 Keyboard::_code[0x60] = { + 0, Esc, '1', '2', '3', + '4', '5', '6', '7', '8', + '9', '0', '-', '+', BSp, + Tab, 'Q', 'W', 'E', 'R', + 'T', 'Y', 'U', 'I', 'O', + 'P', '[', ']', Enter, 0/*Ctrl*/, + 'A', 'S', 'D', 'F', 'G', + 'H', 'J', 'K', 'L', ';', + '\'', '`', 0/*LShift*/, '\\', 'Z', + 'X', 'C', 'V', 'B', 'N', + 'M', ',', '.', '/', 0/*RShift*/, + '*', 0/*Alt*/, ' ', 0/*Caps*/, F1, + F2, F3, F4, F5, F6, + F7, F8, F9, F10, 0/*NumLock*/, + 0/*ScrollLock*/, Home, Up, PgUp, '-', + Left, Ctr, Right, '+', End, + Down, PgDn, Ins, Del, 0 * 0x54, + 0 * 0x55, 0 * 0x56, F11, F12, 0 * 0x59, + 0 * 0x5A, 0 * 0x5B, 0 * 0x5C, 0 * 0x5D, 0 * 0x5E, + 0 * 0x5F +}; + +const uint16 Keyboard::_scummVmCodes[0x60] = { + 0, Common::KEYCODE_ESCAPE, Common::KEYCODE_1, Common::KEYCODE_2, Common::KEYCODE_3, + Common::KEYCODE_4, Common::KEYCODE_5, Common::KEYCODE_6, Common::KEYCODE_7, Common::KEYCODE_8, + Common::KEYCODE_9, Common::KEYCODE_0, Common::KEYCODE_MINUS, Common::KEYCODE_PLUS, Common::KEYCODE_BACKSPACE, + Common::KEYCODE_TAB, Common::KEYCODE_q, Common::KEYCODE_w, Common::KEYCODE_e, Common::KEYCODE_r, + Common::KEYCODE_t, Common::KEYCODE_y, Common::KEYCODE_u, Common::KEYCODE_i, Common::KEYCODE_o, + Common::KEYCODE_p, Common::KEYCODE_LEFTBRACKET, Common::KEYCODE_RIGHTBRACKET, Common::KEYCODE_RETURN, 0/*Ctrl*/, + Common::KEYCODE_a, Common::KEYCODE_s, Common::KEYCODE_d, Common::KEYCODE_f, Common::KEYCODE_g, + Common::KEYCODE_h, Common::KEYCODE_j, Common::KEYCODE_k, Common::KEYCODE_l, Common::KEYCODE_SEMICOLON, + Common::KEYCODE_BACKSLASH, Common::KEYCODE_TILDE, Common::KEYCODE_LSHIFT, Common::KEYCODE_BACKSLASH, Common::KEYCODE_z, + Common::KEYCODE_x, Common::KEYCODE_c, Common::KEYCODE_v, Common::KEYCODE_b, Common::KEYCODE_n, + Common::KEYCODE_m, Common::KEYCODE_COMMA, Common::KEYCODE_PERIOD, Common::KEYCODE_SLASH, Common::KEYCODE_RSHIFT, + Common::KEYCODE_KP_MULTIPLY, 0 /*Alt*/, Common::KEYCODE_SPACE, Common::KEYCODE_CAPSLOCK, Common::KEYCODE_F1, + Common::KEYCODE_F2, Common::KEYCODE_F3, Common::KEYCODE_F4, Common::KEYCODE_F5, Common::KEYCODE_F6, + Common::KEYCODE_F7, Common::KEYCODE_F8, Common::KEYCODE_F9, Common::KEYCODE_F10, Common::KEYCODE_NUMLOCK, + Common::KEYCODE_SCROLLOCK, Common::KEYCODE_KP7, Common::KEYCODE_KP8, Common::KEYCODE_KP9, Common::KEYCODE_KP_MINUS, + Common::KEYCODE_KP4, Common::KEYCODE_KP5, Common::KEYCODE_KP6, Common::KEYCODE_KP_PLUS, Common::KEYCODE_KP1, + Common::KEYCODE_KP2, Common::KEYCODE_KP3, Common::KEYCODE_KP0, Common::KEYCODE_KP_PERIOD, 0, + 0, 0, Common::KEYCODE_F11, Common::KEYCODE_F12, 0, + 0, 0, 0, 0, 0, + 0 +}; + +Keyboard::Keyboard() { + _client = NULL; + Common::set_to(&_key[0], &_key[0x60], false); + _current = 0; +} + +Keyboard::~Keyboard() { +} + +Sprite *Keyboard::setClient(Sprite *spr) { + swap(_client, spr); + return spr; +} + +bool Keyboard::getKey(uint16 keycode, int &cgeCode) { + if ((keycode == Common::KEYCODE_LCTRL) || (keycode == Common::KEYCODE_RCTRL)) { + cgeCode = 29; + return true; + } + + // Scan through the ScummVM mapping list + for (int idx = 0; idx < 0x60; ++idx) { + if (_scummVmCodes[idx] == keycode) { + cgeCode = idx; + return true; + } + } + + return false; +} + +void Keyboard::NewKeyboard(Common::Event &event) { + int keycode; + if (!getKey(event.kbd.keycode, keycode)) + return; + + if (event.type == Common::EVENT_KEYUP) { + // Key release + _key[event.kbd.keycode] = false; + } else if (event.type == Common::EVENT_KEYDOWN) { + // Key press + _key[keycode] = true; + _current = Keyboard::_code[keycode]; + + if (_client) { + CGEEvent &evt = Evt[EvtHead]; + EvtHead = (EvtHead + 1) % EVT_MAX; + evt._x = _current; // Keycode + evt._msk = KEYB; // Event mask + evt._ptr = _client; // Sprite pointer + } + } +} + +/*----------------- MOUSE interface -----------------*/ + +MOUSE::MOUSE(CGEEngine *vm, Bitmap **shpl) : Sprite(vm, shpl), Busy(NULL), Hold(NULL), hx(0), _vm(vm) { + static Seq ms[] = { + { 0, 0, 0, 0, 1 }, + { 1, 1, 0, 0, 1 } + }; + + Hold = NULL; + hx = 0; hy = 0; + Exist = true; + Buttons = 0; + Busy = NULL; + _active = false; + + setSeq(ms); + + gotoxy(SCR_WID/2, SCR_HIG/2); + _z = 127; + step(1); +} + + +MOUSE::~MOUSE() { + Off(); +} + + +//void MOUSE::SetFun() +//{ +//} + + +void MOUSE::On() { + if (_seqPtr && Exist) { + _active = true; + step(0); + if (Busy) Busy->step(0); + } +} + + +void MOUSE::Off() { + if (_seqPtr == 0) { + if (Exist) { + _active = false; + } + + step(1); + if (Busy) Busy->step(1); + } +} + +void MOUSE::NewMouse(Common::Event &event) { + if (!_active) + return; + + CGEEvent &evt = Evt[EvtHead]; + EvtHead = (EvtHead + 1) % EVT_MAX; + evt._x = event.mouse.x; + evt._y = event.mouse.y; + evt._ptr = spriteAt(evt._x, evt._y); + + switch (event.type) { + case Common::EVENT_MOUSEMOVE: + evt._msk = ROLL; + break; + case Common::EVENT_LBUTTONDOWN: + evt._msk = L_DN; + Buttons |= 1; + break; + case Common::EVENT_LBUTTONUP: + evt._msk = L_UP; + Buttons &= ~1; + break; + case Common::EVENT_RBUTTONDOWN: + evt._msk = R_DN; + Buttons |= 2; + break; + case Common::EVENT_RBUTTONUP: + evt._msk = R_UP; + Buttons &= ~2; + break; + default: + break; + } +} + +/*----------------- EventManager interface -----------------*/ + +EventManager::EventManager() { + _quitFlag = false; +} + +void EventManager::poll() { + while (g_system->getEventManager()->pollEvent(_event)) { + switch (_event.type) { + case Common::EVENT_QUIT: + // Signal to quit + _quitFlag = true; + return; + case Common::EVENT_KEYDOWN: + case Common::EVENT_KEYUP: + // Handle keyboard events + _keyboard->NewKeyboard(_event); + handleEvents(); + break; + case Common::EVENT_MOUSEMOVE: + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + // Handle mouse events + _mouse->NewMouse(_event); + handleEvents(); + break; + default: + break; + } + } +} + +void EventManager::handleEvents() { + while (EvtTail != EvtHead) { + CGEEvent e = Evt[EvtTail]; + if (e._msk) { + if (_mouse->Hold && e._ptr != _mouse->Hold) + _mouse->Hold->touch(e._msk | ATTN, e._x - _mouse->Hold->_x, e._y - _mouse->Hold->_y); + + // update mouse cursor position + if (e._msk & ROLL) + _mouse->gotoxy(e._x, e._y); + + // activate current touched SPRITE + if (e._ptr) { + if (e._msk & KEYB) + e._ptr->touch(e._msk, e._x, e._y); + else + e._ptr->touch(e._msk, e._x - e._ptr->_x, e._y - e._ptr->_y); + } else if (_sys) + _sys->touch(e._msk, e._x, e._y); + + if (e._msk & L_DN) { + _mouse->Hold = e._ptr; + if (_mouse->Hold) { + _mouse->Hold->_flags._hold = true; + _mouse->hx = e._x - _mouse->Hold->_x; + _mouse->hy = e._y - _mouse->Hold->_y; + } + } + + if (e._msk & L_UP) { + if (_mouse->Hold) { + _mouse->Hold->_flags._hold = false; + _mouse->Hold = NULL; + } + } + ///Touched = e.Ptr; + + // discard Text if button released + if (e._msk & (L_UP | R_UP)) + killText(); + } + EvtTail = (EvtTail + 1) % EVT_MAX; + } + if (_mouse->Hold) + _mouse->Hold->gotoxy(_mouse->_x - _mouse->hx, _mouse->_y - _mouse->hy); +} + +void EventManager::ClrEvt(Sprite *spr) { + if (spr) { + uint16 e; + for (e = EvtTail; e != EvtHead; e = (e + 1) % EVT_MAX) + if (Evt[e]._ptr == spr) + Evt[e]._msk = 0; + } else + EvtTail = EvtHead; +} + +} // End of namespace CGE diff --git a/engines/cge/events.h b/engines/cge/events.h new file mode 100644 index 0000000000..cfb1023d6b --- /dev/null +++ b/engines/cge/events.h @@ -0,0 +1,131 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_CGE_EVENTS__ +#define __CGE_CGE_EVENTS__ + +#include "common/events.h" +#include "cge/game.h" +#include "cge/talk.h" +#include "cge/jbw.h" +#include "cge/vga13h.h" + +namespace CGE { + +/*----------------- KEYBOARD interface -----------------*/ + +#define KEYBD_INT 9 +#define LSHIFT 42 +#define RSHIFT 54 +#define CTRL 29 +#define ALT 56 + + +class Keyboard { +private: + bool getKey(uint16 keycode, int &cgeCode); +public: + static const uint16 _code[0x60]; + static const uint16 _scummVmCodes[0x60]; + + uint16 _current; + Sprite *_client; + bool _key[0x60]; + + void NewKeyboard(Common::Event &event); + uint16 last() { + uint16 cur = _current; + _current = 0; + return cur; + } + Sprite *setClient(Sprite *spr); + + Keyboard(); + ~Keyboard(); +}; + +/*----------------- MOUSE interface -----------------*/ + +#define EVT_MAX 256 +#define ROLL 0x01 +#define L_DN 0x02 +#define L_UP 0x04 +#define R_DN 0x08 +#define R_UP 0x10 +#define ATTN 0x20 // 0x40 +#define KEYB 0x80 + + +extern Talk *_talk; + +struct CGEEvent { + uint16 _msk; + uint16 _x; + uint16 _y; + Sprite *_ptr; +}; + +extern CGEEvent Evt[EVT_MAX]; +extern uint16 EvtHead, EvtTail; + + +class MOUSE : public Sprite { +public: + Sprite *Hold; + bool _active; + int hx, hy; + bool Exist; + int Buttons; + Sprite *Busy; + //Sprite *Touched; + MOUSE(CGEEngine *vm, Bitmap **shpl = MC); + ~MOUSE(); + void On(); + void Off(); + void Tick(); + void NewMouse(Common::Event &event); +private: + CGEEngine *_vm; +}; + +/*----------------- EventManager interface -----------------*/ + +class EventManager { +private: + Common::Event _event; + void handleEvents(); +public: + bool _quitFlag; + + EventManager(); + void poll(); + static void ClrEvt(Sprite *spr = NULL); +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/game.cpp b/engines/cge/game.cpp new file mode 100644 index 0000000000..f2ebc0b4f8 --- /dev/null +++ b/engines/cge/game.cpp @@ -0,0 +1,91 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/game.h" +#include "cge/events.h" + +namespace CGE { + +uint8 *glass(Dac *pal, uint8 r, uint8 g, uint8 b) { + uint8 *x = new uint8[256]; + if (x) { + uint16 i; + for (i = 0; i < 256; i++) { + x[i] = closest(pal, mkDac(((uint16)(pal[i]._r) * r) / 255, + ((uint16)(pal[i]._g) * g) / 255, + ((uint16)(pal[i]._b) * b) / 255)); + } + } + return x; +} + +/* Useless? +uint8 *Mark(DAC *pal) { +#define f(c) (c ^ 63) + uint8 *x = new uint8[256]; + if (x) { + uint16 i; + for (i = 0; i < 256; i++) { + x[i] = closest(pal, mkDax(f(pal[i]._R), + f(pal[i]._G), + f(pal[i]._B))); + } + } + return x; +#undef f +} +*/ + +int Fly::_l = 20, + Fly::_t = 40, + Fly::_r = 110, + Fly::_b = 100; + + +Fly::Fly(CGEEngine *vm, Bitmap **shpl) + : Sprite(vm, shpl), _tx(0), _ty(0), _vm(vm) { + step(new_random(2)); + gotoxy(_l + new_random(_r - _l - _w), _t + new_random(_b - _t - _h)); +} + + +void Fly::tick() { + step(); + if (!_flags._kept) { + if (new_random(10) < 1) { + _tx = new_random(3) - 1; + _ty = new_random(3) - 1; + } + if (_x + _tx < _l || _x + _tx + _w > _r) + _tx = -_tx; + if (_y + _ty < _t || _y + _ty + _h > _b) + _ty = -_ty; + gotoxy(_x + _tx, _y + _ty); + } +} + +} // End of namespace CGE diff --git a/engines/cge/game.h b/engines/cge/game.h new file mode 100644 index 0000000000..b26fc0d165 --- /dev/null +++ b/engines/cge/game.h @@ -0,0 +1,62 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_GAME__ +#define __CGE_GAME__ + +#include "cge/vga13h.h" +#include "cge/bitmaps.h" + +namespace CGE { + + +//#define PAN_HIG 40 +//#define LBound(s) (s->X <= 0) +//#define RBound(s) (s->X+s->W >= SCR_WID) +//#define TBound(s) (s->Y <= 0) +//#define BBound(s) (s->Y+s->H >= SCR_HIG - PAN_HIG) + +//int sinus(long x); +uint8 *glass(Dac *pal, uint8 r, uint8 g, uint8 b); +//uint8 *mark(DAC *pal); + +class Fly : public Sprite { + static int _l; + static int _t; + static int _r; + static int _b; +public: + int _tx, _ty; + Fly(CGEEngine *vm, Bitmap **shpl); + void tick(); +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/general.cpp b/engines/cge/general.cpp new file mode 100644 index 0000000000..6ed6884aba --- /dev/null +++ b/engines/cge/general.cpp @@ -0,0 +1,393 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/cge.h" +#include "cge/general.h" +#include "cge/snddrv.h" +#include "cge/wav.h" + +namespace CGE { + +Dac _stdPal[] = {// R G B + { 0, 60, 0}, // 198 + { 0, 104, 0}, // 199 + { 20, 172, 0}, // 200 + { 82, 82, 0}, // 201 + { 0, 132, 82}, // 202 + { 132, 173, 82}, // 203 + { 82, 0, 0}, // 204 + { 206, 0, 24}, // 205 + { 255, 33, 33}, // 206 + { 123, 41, 0}, // 207 + { 0, 41, 0}, // 208 + { 0, 0, 82}, // 209 + { 132, 0, 0}, // 210 + { 255, 0, 0}, // 211 + { 255, 66, 66}, // 212 + { 148, 66, 16}, // 213 + { 0, 82, 0}, // 214 + { 0, 0, 132}, // 215 + { 173, 0, 0}, // 216 + { 255, 49, 0}, // 217 + { 255, 99, 99}, // 218 + { 181, 107, 49}, // 219 + { 0, 132, 0}, // 220 + { 0, 0, 255}, // 221 + { 173, 41, 0}, // 222 + { 255, 82, 0}, // 223 + { 255, 132, 132}, // 224 + { 214, 148, 74}, // 225 + { 41, 214, 0}, // 226 + { 0, 82, 173}, // 227 + { 255, 214, 0}, // 228 + { 247, 132, 49}, // 229 + { 255, 165, 165}, // 230 + { 239, 198, 123}, // 231 + { 173, 214, 0}, // 232 + { 0, 132, 214}, // 233 + { 57, 57, 57}, // 234 + { 247, 189, 74}, // 235 + { 255, 198, 198}, // 236 + { 255, 239, 173}, // 237 + { 214, 255, 173}, // 238 + { 82, 173, 255}, // 239 + { 107, 107, 107}, // 240 + { 247, 222, 99}, // 241 + { 255, 0, 255}, // 242 + { 255, 132, 255}, // 243 + { 132, 132, 173}, // 244 + { 148, 247, 255}, // 245 + { 148, 148, 148}, // 246 + { 82, 0, 82}, // 247 + { 112, 68, 112}, // 248 + { 176, 88, 144}, // 249 + { 214, 132, 173}, // 250 + { 206, 247, 255}, // 251 + { 198, 198, 198}, // 252 + { 0, 214, 255}, // 253 + { 96, 224, 96 }, // 254 + { 255, 255, 255}, // 255 +}; + +DrvInfo _sndDrvInfo; + +void _fqsort(void *base, uint16 nelem, uint16 width, int (*fcmp)(const void *, const void *)) { + warning("STUB: _fqsort"); +} + +const char *progName(const char *ext) { + static char buf[MAXFILE]; + strcpy(buf, "CGE"); + if (ext) + strcat(buf, ext); + + return buf; +} + +char *mergeExt(char *buf, const char *nam, const char *ext) { + strcpy(buf, nam); + char *dot = strrchr(buf, '.'); + if (!dot) + strcat(buf, ext); + + return buf; +} + +char *forceExt(char *buf, const char *nam, const char *ext) { + strcpy(buf, nam); + char *dot = strrchr(buf, '.'); + if (dot) + *dot = '\0'; + strcat(buf, ext); + + return buf; +} + +static unsigned Seed = 0xA5; + +unsigned fastRand() { + return Seed = 257 * Seed + 817; +} +unsigned fastRand(unsigned s) { + return Seed = 257 * s + 817; +} + +uint16 RCrypt(void *buf, uint16 siz, uint16 seed) { + if (buf && siz) { + byte *b = static_cast<byte *>(buf); + byte *q = b + (siz - 1); + seed = fastRand(seed); + *b++ ^= seed; + while (buf < q) + *b++ ^= fastRand(); + if (buf == q) + *b ^= (seed = fastRand()); + } + return seed; +} + +uint16 XCrypt(void *buf, uint16 siz, uint16 seed) { + byte *b = static_cast<byte *>(buf); + + for (uint16 i = 0; i < siz; i++) + *b++ ^= seed; + + return seed; +} + +uint16 atow(const char *a) { + uint16 w = 0; + if (a) + while (IsDigit(*a)) + w = (10 * w) + (*(a++) & 0xF); + return w; +} + +uint16 xtow(const char *x) { + uint16 w = 0; + if (x) { + while (IsHxDig(*x)) { + register uint16 d = *(x++); + if (d > '9') + d -= 'A' - ('9' + 1); + w = (w << 4) | (d & 0xF); + } + } + return w; +} + +char *wtom(uint16 val, char *str, int radix, int len) { + while (--len >= 0) { + uint16 w = val % radix; + if (w > 9) + w += ('A' - ('9' + 1)); + str[len] = '0' + w; + val /= radix; + } + return str; +} + +char *dwtom(uint32 val, char *str, int radix, int len) { + while (--len >= 0) { + uint16 w = (uint16) (val % radix); + if (w > 9) + w += ('A' - ('9' + 1)); + str[len] = '0' + w; + val /= radix; + } + return str; +} + +IoHand::IoHand(IOMODE mode, CRYPT *crpt) + : XFile(mode), _crypt(crpt), _seed(SEED) { + _file = new Common::File(); +} + +IoHand::IoHand(const char *name, IOMODE mode, CRYPT *crpt) + : XFile(mode), _crypt(crpt), _seed(SEED) { + // TODO: Check if WRI and/or UPD modes are needed, and map to a save file + assert(mode == REA); + + _file = new Common::File(); + _file->open(name); +} + +IoHand::~IoHand() { + _file->close(); + delete _file; +} + +uint16 IoHand::read(void *buf, uint16 len) { + if (_mode == WRI || !_file->isOpen()) + return 0; + + uint16 bytesRead = _file->read(buf, len); + if (!bytesRead) + error("Read %s - %d bytes", _file->getName(), len); + if (_crypt) + _seed = _crypt(buf, len, Seed); + return bytesRead; +} + +uint16 IoHand::write(void *buf, uint16 len) { + error("IOHAND::Write not supported"); +/* + if (len) { + if (Mode == REA || Handle < 0) + return 0; + if (Crypt) + Seed = Crypt(buf, len, Seed); + Error = _dos_write(Handle, buf, len, &len); + if (Crypt) + Seed = Crypt(buf, len, Seed); //------$$$$$$$ + } + return len; +*/ +} + +long IoHand::mark() { + return _file->pos(); +} + +long IoHand::seek(long pos) { + _file->seek(pos, SEEK_SET); + return _file->pos(); +} + +long IoHand::size() { + return _file->size(); +} + +bool IoHand::exist(const char *name) { + Common::File f; + return f.exists(name); +} + +//#define EMS_ADR(a) (FP_SEG(a) > 0xA000) +//#define HNODE_OK(p) (heapchecknode(p)==4) + +MEM_TYPE memType(void *mem) { + /* if (FP_SEG(mem) == _DS) { + if (heapchecknode((void *)mem)==4) + return NEAR_MEM; + } else { + if (FP_SEG(mem) > 0xA000) + return EMS_MEM; + else if (farheapchecknode(mem)==4) + return FAR_MEM; + } + return BAD_MEM; + */ + warning("STUB: memType"); + return FAR_MEM; +} + +bool isVga() { + return true; +} + +void sndInit() { + warning("STUB: SNDInit"); +} + +void sndDone() { + // FIXME: STUB: SNDDone +} + +void sndSetVolume() { + warning("STUB: SNDSetVolume"); +} + +void sndDigiStart(SmpInfo *PSmpInfo) { + warning("STUB: SNDDigitStart"); +} + +void sndDigiStop(SmpInfo *PSmpInfo) { + warning("STUB: SNDDigiStop"); +} + +void sndMidiStart(uint8 *MIDFile) { + warning("STUB: SNDMIDIStart"); +} + +void sndMidiStop() { + // FIXME: STUB: sndMIDIStop +} + +DataCk *loadWave(XFile *file, Emm *emm) { + warning("STUB: LoadWave"); + return NULL; +} + +int takeEnum(const char **tab, const char *txt) { + const char **e; + if (txt) { + for (e = tab; *e; e++) { + if (scumm_stricmp(txt, *e) == 0) { + return e - tab; + } + } + } + return -1; +} + +long timer() { +/* + asm mov ax,0x40 + asm mov es,ax + asm mov cx,es:[0x6C] + asm mov dx,es:[0x6E] + return ((long) _DX << 16) | _CX; +*/ + warning("STUB: timer"); + return 0; +} + +int new_random(int range) { + return ((CGEEngine *)g_engine)->_randomSource.getRandomNumber(range - 1); +} + +#define TIMER_INT 0x08 +//void interrupt (* Engine_::oldTimer) (...) = NULL; + +Engine_::Engine_(uint16 tdiv) { +/* + // steal timer interrupt + OldTimer = getvect(TIMER_INT); + setvect(TIMER_INT, NewTimer); + + // set turbo-timer mode + asm mov al,0x36 + asm out 0x43,al + asm mov ax,TMR_DIV + asm out 0x40,al + asm mov al,ah + asm out 0x40,al +*/ + warning("STUB: Engine_::Engine_"); +} + +Engine_::~Engine_() { +/* + // reset timer + asm mov al,0x36 + asm out 0x43,al + asm xor al,al + asm out 0x40,al + asm out 0x40,al + // bring back timer interrupt + setvect(TIMER_INT, OldTimer); +*/ + warning("STUB: Engine_::~Engine_"); +} + +DataCk::~DataCk() { + if (!_e && _buf) + free(_buf); +} +} // End of namespace CGE + diff --git a/engines/cge/general.h b/engines/cge/general.h new file mode 100644 index 0000000000..7cf3ec3e41 --- /dev/null +++ b/engines/cge/general.h @@ -0,0 +1,241 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_GENERAL__ +#define __CGE_GENERAL__ + +#include "common/system.h" +#include "common/file.h" +#include "common/random.h" +#include "common/textconsole.h" +#include "common/str.h" +#include "cge/jbw.h" + +namespace CGE { + +#define SEED 0xA5 + +#define SCR_WID_ 320 +#define SCR_HIG_ 200 +#define SCR_WID ((uint16)SCR_WID_) +#define SCR_HIG ((uint16)SCR_HIG_) +#define SCR_SEG 0xA000 +#define SCR_ADR ((uint8 *) MK_FP(SCR_SEG, 0)) + + + +//enum CPU { _8086, _80186, _80286, _80386, _80486 }; +enum MEM_TYPE { BAD_MEM, EMS_MEM, NEAR_MEM, FAR_MEM }; +enum ALLOC_MODE { FIRST_FIT, BEST_FIT, LAST_FIT }; +enum IOMODE { REA, WRI, UPD }; + +struct Dac { + uint8 _r, _g, _b; +}; + +typedef uint16 CRYPT(void *buf, uint16 siz, uint16 seed); + +class Couple { +protected: + signed char _a; + signed char _b; +public: + Couple() { } + Couple(const signed char a, const signed char b) : _a(a), _b(b) { } + Couple operator + (Couple c) { + return Couple(_a + c._a, _b + c._b); + } + + void operator += (Couple c) { + _a += c._a; + _b += c._b; + } + + Couple operator - (Couple c) { + return Couple(_a - c._a, _b - c._b); + } + + void operator -= (Couple c) { + _a -= c._a; + _b -= c._b; + } + + bool operator == (Couple c) { + return ((_a - c._a) | (_b - c._b)) == 0; + } + + bool operator != (Couple c) { + return !(operator == (c)); + } + + void split(signed char &a, signed char &b) { + a = _a; + b = _b; + } +}; + + +class Engine_ { +protected: + static void (* oldTimer)(...); + static void newTimer(...); +public: + Engine_(uint16 tdiv); + ~Engine_(); +}; + + +class Ems; + + +class Emm { + friend class Ems; + bool test(); + + long _top; + long _lim; + Ems *_list; + int _han; + static void *_frame; +public: + Emm(long size = 0); + ~Emm(); + Ems *alloc(uint16 siz); + void release(); +}; + + +class Ems { + friend class Emm; + Emm *_emm; + long _ptr; + uint16 _size; + Ems *_next; +public: + Ems(); + void *operator & () const; + uint16 size(); +}; + + +template <class T> +void swap(T &A, T &B) { + T a = A; + A = B; + B = a; +} + + +#ifdef __cplusplus +template <class T> +T max(T A, T B) { + return (A > B) ? A : B; +} + +template <class T> +T min(T A, T B) { + return (A < B) ? A : B; +} +#endif + + +class XFile { +public: + IOMODE _mode; + uint16 _error; + + XFile() : _mode(REA), _error(0) { } + XFile(IOMODE mode) : _mode(mode), _error(0) { } + virtual ~XFile() { } + virtual uint16 read(void *buf, uint16 len) = 0; + virtual uint16 write(void *buf, uint16 len) = 0; + virtual long mark() = 0; + virtual long size() = 0; + virtual long seek(long pos) = 0; +}; + + +template <class T> +inline uint16 XRead(XFile *xf, T *t) { + return xf->read((uint8 *) t, sizeof(*t)); +} + + +class IoHand : public XFile { +protected: + Common::File *_file; + uint16 _seed; + CRYPT *_crypt; +public: + IoHand(const char *name, IOMODE mode = REA, CRYPT crypt = NULL); + IoHand(IOMODE mode = REA, CRYPT *crpt = NULL); + virtual ~IoHand(); + static bool exist(const char *name); + uint16 read(void *buf, uint16 len); + uint16 write(void *buf, uint16 len); + long mark(); + long size(); + long seek(long pos); + //timeb Time (); +// void SetTime (timeb t); +}; + + +CRYPT XCrypt; +CRYPT RCrypt; +MEM_TYPE memType(void *mem); +uint16 atow(const char *a); +uint16 xtow(const char *x); +char *wtom(uint16 val, char *str, int radix, int len); +char *dwtom(uint32 val, char *str, int radix, int len); +int takeEnum(const char **tab, const char *txt); +uint16 chkSum(void *m, uint16 n); +long timer(); +char *mergeExt(char *buf, const char *nam, const char *ext); +char *forceExt(char *buf, const char *nam, const char *ext); +int driveCD(unsigned drv); +bool isVga(); + + +// MISSING FUNCTIONS +void _fqsort(void *base, uint16 nelem, uint16 width, int (*fcmp)(const void *, const void *)); +const char *progName(const char *ext = NULL); +char *mergeExt(char *buf, const char *nam, const char *ext); +char *forceExt(char *buf, const char *nam, const char *ext); +unsigned fastRand(); +unsigned fastRand(unsigned s); +uint16 rCrypt(void *buf, uint16 siz, uint16 seed); +uint16 atow(const char *a); +uint16 xtow(const char *x); +char *wtom(uint16 val, char *str, int radix, int len); +char *dwtom(uint32 val, char * str, int radix, int len); +int takeEnum(const char **tab, const char *txt); +long timer(); +int new_random(int range); +} // End of namespace CGE + +#endif diff --git a/engines/cge/gettext.cpp b/engines/cge/gettext.cpp new file mode 100644 index 0000000000..2ee6dc42eb --- /dev/null +++ b/engines/cge/gettext.cpp @@ -0,0 +1,119 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/gettext.h" +#include "cge/events.h" +#include "cge/cge_main.h" + +namespace CGE { + +GetText *GetText::_ptr = NULL; + + +GetText::GetText(CGEEngine *vm, const char *info, char *text, int size) + : Talk(vm), _text(text), _size(min<int>(size, GTMAX)), _len(min<int>(_size, strlen(text))), + _cntr(GTBLINK), _oldKeybClient(_keyboard->setClient(this)), _vm(vm) { + int i = 2 * TEXT_HM + _font->width(info); + _ptr = this; + _mode = RECT; + _ts[0] = box((i + 3) & ~3, 2 * TEXT_VM + 2 * FONT_HIG + TEXT_LS); + setShapeList(_ts); + _flags._bDel = true; + _flags._kill = true; + memcpy(_buff, text, _len); + _buff[_len] = ' '; + _buff[_len + 1] = '\0'; + putLine(0, info); + tick(); +} + + +GetText::~GetText() { + _keyboard->setClient(_oldKeybClient); + _ptr = NULL; +} + + +void GetText::tick() { + if (++_cntr >= GTBLINK) { + _buff[_len] ^= (' ' ^ '_'); + _cntr = 0; + } + putLine(1, _buff); + _time = GTTIME; +} + + +void GetText::touch(uint16 mask, int x, int y) { + static char ogon[] = "•œ¥£˜ ¡"; + static char bezo[] = "ACELNOSXZ"; + char *p; + + if (mask & KEYB) { + _vm->keyClick(); + switch (x) { + case Enter : + _buff[_len] = '\0'; + strcpy(_text, _buff); + for (p = _text; *p; p++) { + char *q = strchr(ogon, *p); + if (q) + *p = bezo[q - ogon]; + } + case Esc : + SNPOST_(SNKILL, -1, 0, this); + break; + case BSp : + if (_len) { + _len--; + _buff[_len] = _buff[_len + 1]; + _buff[_len + 1] = _buff[_len + 2]; + } + break; + default : + if (x < 'A' || x > 'Z') { + if (_oldKeybClient) + _oldKeybClient->touch(mask, x, y); + } else { + if (_keyboard->_key[ALT]) { + p = strchr(bezo, x); + if (p) + x = ogon[p - bezo]; + } + if (_len < _size && 2 * TEXT_HM + _font->width(_buff) + _font->_wid[x] <= _w) { + _buff[_len + 2] = _buff[_len + 1]; + _buff[_len + 1] = _buff[_len]; + _buff[_len++] = x; + } + } + break; + } + } else + Sprite::touch(mask, x, y); +} + +} // End of namespace CGE diff --git a/engines/cge/gettext.h b/engines/cge/gettext.h new file mode 100644 index 0000000000..188e90c776 --- /dev/null +++ b/engines/cge/gettext.h @@ -0,0 +1,61 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_GETTEXT__ +#define __CGE_GETTEXT__ + +#include "cge/general.h" +#include "cge/talk.h" + +namespace CGE { + +#define GTMAX 24 +#define GTBLINK 6 +#define GTTIME 6 + +class GetText : public Talk { + char _buff[GTMAX + 2]; + char *_text; + uint16 _size; + uint16 _len; + uint16 _cntr; + Sprite *_oldKeybClient; + +public: + static GetText *_ptr; + GetText(CGEEngine *vm, const char *info, char *text, int size); + ~GetText(); + void touch(uint16 mask, int x, int y); + void tick(); + +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/jbw.h b/engines/cge/jbw.h new file mode 100644 index 0000000000..74084fb905 --- /dev/null +++ b/engines/cge/jbw.h @@ -0,0 +1,132 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_JBW__ +#define __CGE_JBW__ + +#include "common/scummsys.h" + +namespace CGE { + +// Defines found in cge.mak +#define VOL +#define INI_FILE VFile // Or is it CFile? +#define PIC_FILE VFile +#define BMP_MODE 0 +// + +#define BEL 7 +#define BS 8 +#define HT 9 +#define LF 10 +#define FF 12 +#define CR 13 +#define MAXFILE 128 + +#define IsWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') +#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') +#define IsLower(c) ((c) >= 'a' && (c) <= 'z') +#define IsDigit(c) ((c) >= '0' && (c) <= '9') +#define IsAlpha(c) (IsLower(c) || IsUpper(c) || (c) == '_') +#define IsAlNum(c) (IsAlpha(c) || IsDigit(c)) +#define IsHxDig(c) (IsDigit(c) || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) + +#define farnew(t, n) ((t *) malloc(sizeof(t) * (n))) +#define ArrayCount(a) (sizeof(a) / sizeof((a)[0])) +#define MAX_TIMER 0x1800B0L + +typedef void (MouseFunType)(); + +#define Lo(d) (((int *) &d)[0]) +#define Hi(d) (((int *) &d)[1]) +#define LoWord(d) ((uint16) Lo(d)) +#define HiWord(d) ((uint16) Hi(d)) +#define K(n) (1024 * (n)) +#define MASK(n) ((1 << n) - 1) + +enum Keys { + NoKey = 0, CtrlA, CtrlB, CtrlC, CtrlD, CtrlE, CtrlF, CtrlG, CtrlH, + CtrlI, CtrlJ, CtrlK, CtrlL, CtrlM, CtrlN, CtrlO, CtrlP, + CtrlQ, CtrlR, CtrlS, CtrlT, CtrlU, CtrlV, CtrlW, CtrlX, + CtrlY, CtrlZ, + BSp = 8, + Tab = 9, + Enter = 13, + Eof = 26, + Esc = 27, + AltQ = 256 + 16, AltW, AltE, AltR, AltT, AltY, AltU, AltI, AltO, AltP, + AltA = 256 + 30, AltS, AltD, AltF, AltG, AltH, AltJ, AltK, AltL, + AltZ = 256 + 44, AltX, AltC, AltV, AltB, AltN, AltM, + F11 = 256 + 87, F12, + F1 = 256 + 59, F2, F3, F4, F5, F6, F7, F8, F9, F10, + ShiftTab = 256 + 15, + ShiftF1 = 256 + 84, ShiftF2, ShiftF3, ShiftF4, ShiftF5, + ShiftF6, ShiftF7, ShiftF8, ShiftF9, ShiftF10, + CtrlF1 = 256 + 94, CtrlF2, CtrlF3, CtrlF4, CtrlF5, + CtrlF6, CtrlF7, CtrlF8, CtrlF9, CtrlF10, + AltF1 = 256 + 104, AltF2, AltF3, AltF4, AltF5, + AltF6, AltF7, AltF8, AltF9, AltF10, + Home = 256 + 71, + Up, + PgUp, + Left = 256 + 75, + Ctr, + Right, + End = 256 + 79, + Down, + PgDn, + Ins, + Del, + CtrlLeft = 256 + 115, + CtrlRight, + CtrlEnd, + CtrlPgDn, + CtrlHome, + CtrlPgUp = 256 + 132, + + MouseLeft = 512 + 1, + MouseRight, + TwiceLeft = 512 + 256 + 1, + TwiceRight +}; + +#define HGC_Cursor 0x0B0C +#define CGA_Cursor 0x0607 +#define OFF_Cursor 0x2000 + +//#define TimerCount (*((volatile long *) ((void _seg *) 0x40 + (void *) 0x6C))) +//#define BreakFlag (*((volatile uint8 *) ((void _seg *) 0x40 + (void *) 0x71))) +//#define PostFlag (*((volatile uint16 *) ((void _seg *) 0x40 + (void *) 0x72))) +//#define POST ((void (*)(void)) ((void _seg *) 0xF000 + (void *) 0xFFF0)) + + +extern uint16 _stklen; +extern uint16 _heaplen; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/mixer.cpp b/engines/cge/mixer.cpp new file mode 100644 index 0000000000..d4a5212552 --- /dev/null +++ b/engines/cge/mixer.cpp @@ -0,0 +1,144 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/mixer.h" +#include "cge/text.h" +#include "cge/snail.h" +#include "cge/events.h" +#include "cge/snddrv.h" +#include "cge/cge_main.h" + +namespace CGE { + +extern MOUSE *Mouse; + +bool Mixer::_appear = false; + + +Mixer::Mixer(CGEEngine *vm, int x, int y) : Sprite(vm, NULL), _fall(MIX_FALL), _vm(vm) { + _appear = true; + _mb[0] = new Bitmap("VOLUME", true); + _mb[1] = NULL; + setShapeList(_mb); + setName(_text->getText(MIX_NAME)); + _flags._syst = true; + _flags._kill = true; + _flags._bDel = true; + gotoxy(x, y); + _z = MIX_Z; + + // slaves + + uint i; + for (i = 0; i < MIX_MAX; i++) { + static char fn[] = "V00"; + wtom(i, fn + 1, 10, 2); + _lb[i] = new Bitmap(fn, true); + _ls[i]._now = _ls[i]._next = i; + _ls[i]._dx = _ls[i]._dy = _ls[i]._dly = 0; + } + _lb[i] = NULL; + + for (i = 0; i < ArrayCount(_led); i++) { + register Sprite *spr = new Sprite(_vm, _lb); + spr->setSeq(_ls); + spr->gotoxy(x + 2 + 12 * i, y + 8); + spr->_flags._tran = true; + spr->_flags._kill = true; + spr->_flags._bDel = false; + spr->_z = MIX_Z; + _led[i] = spr; + } + _led[ArrayCount(_led) - 1]->_flags._bDel = true; + + _vga->_showQ->insert(this); + for (i = 0; i < ArrayCount(_led); i++) + _vga->_showQ->insert(_led[i]); + + //--- reset balance + i = (_sndDrvInfo.Vol4._ml + _sndDrvInfo.Vol4._mr) / 2; + _sndDrvInfo.Vol4._ml = i; + _sndDrvInfo.Vol4._mr = i; + i = (_sndDrvInfo.Vol4._dl + _sndDrvInfo.Vol4._dr) / 2; + _sndDrvInfo.Vol4._dl = i; + _sndDrvInfo.Vol4._dr = i; + update(); + _time = MIX_DELAY; +} + +Mixer::~Mixer() { + _appear = false; +} + + +#pragma argsused +void Mixer::touch(uint16 mask, int x, int y) { + Sprite::touch(mask, x, y); + if (mask & L_UP) { + uint8 *vol = (&_sndDrvInfo.Vol2._d) + (x < _w / 2); + if (y < MIX_BHIG) { + if (*vol < 0xFF) + *vol += 0x11; + } else if (y >= _h - MIX_BHIG) { + if (*vol > 0x00) + *vol -= 0x11; + } + update(); + } +} + + +void Mixer::tick() { + int x = _mouse->_x; + int y = _mouse->_y; + if (spriteAt(x, y) == this) { + _fall = MIX_FALL; + if (_flags._hold) + touch(L_UP, x - _x, y - _y); + } else { + if (_fall) + _fall--; + else { + for (uint i = 0; i < ArrayCount(_led); i++) + SNPOST_(SNKILL, -1, 0, _led[i]); + SNPOST_(SNKILL, -1, 0, this); + } + } + _time = MIX_DELAY; +} + + +void Mixer::update() { + _led[0]->step(_sndDrvInfo.Vol4._ml); + _led[1]->step(_sndDrvInfo.Vol4._dl); + + //TODO Change the SNPOST message send to a special way to send function pointer + //SNPOST_(SNEXEC, -1, 0, (void*)&sndSetVolume); + warning("STUB: Mixer::Update"); +} + +} // End of namespace CGE diff --git a/engines/cge/mixer.h b/engines/cge/mixer.h new file mode 100644 index 0000000000..8ded075514 --- /dev/null +++ b/engines/cge/mixer.h @@ -0,0 +1,61 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_MIXER__ +#define __CGE_MIXER__ + +#include "cge/vga13h.h" + +namespace CGE { + +#define MIX_MAX 16 // count of Leds +#define MIX_Z 64 // mixer Z position +#define MIX_DELAY 12 // 6/s +#define MIX_FALL 6 // in MIX_DELAY units +#define MIX_BHIG 6 // mixer button high +#define MIX_NAME 105 // sprite name + +class Mixer : public Sprite { + BMP_PTR _mb[2]; + BMP_PTR _lb[MIX_MAX + 1]; + Seq _ls[MIX_MAX]; + Sprite *_led[2]; + int _fall; + void update(); +public: + static bool _appear; + Mixer(CGEEngine *vm, int x, int y); + ~Mixer(); + void touch(uint16 mask, int x, int y); + void tick(); +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/module.mk b/engines/cge/module.mk new file mode 100644 index 0000000000..d9dea6534d --- /dev/null +++ b/engines/cge/module.mk @@ -0,0 +1,38 @@ +MODULE := engines/cge + +MODULE_OBJS := \ + bitmap.o \ + bitmaps.o \ + btfile.o \ + cfile.o \ + cge.o \ + cge_main.o \ + config.o \ + console.o \ + detection.o \ + ems.o \ + events.o \ + game.o \ + general.o \ + gettext.o \ + mixer.o \ + snail.o \ + sound.o \ + startup.o \ + talk.o \ + text.o \ + vga13h.o \ + vmenu.o \ + vol.o + +MODULE_DIRS += \ + engines/cge + +# This module can be built as a plugin +ifeq ($(ENABLE_CGE), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk + diff --git a/engines/cge/snail.cpp b/engines/cge/snail.cpp new file mode 100644 index 0000000000..683568e1a8 --- /dev/null +++ b/engines/cge/snail.cpp @@ -0,0 +1,1091 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/general.h" +#include "cge/sound.h" +#include "cge/snail.h" +#include "cge/vga13h.h" +#include "cge/bitmaps.h" +#include "cge/text.h" +#include "cge/cge_main.h" +#include "cge/events.h" + +namespace CGE { + +static void _enable() { + warning("STUB: _enable"); +} + +static void _disable() { + warning("STUB: _disable"); +} + +extern Sprite *_pocLight; + +//------------------------------------------------------------------------- +// SPRITE * Pocket[POCKET_NX]={ NULL, NULL, NULL, NULL, +// NULL, NULL, NULL, NULL, }; +// int _pocPtr = 0; +//------------------------------------------------------------------------- +extern Sprite *_pocket[]; + +void CGEEngine::snGame(Sprite *spr, int num) { + switch (num) { + case 1 : { +#define STAGES 8 +#define DRESSED 3 + static Sprite *dup[3] = { NULL, NULL, NULL }; + int buref = 0; + int Stage = 0; + + for (dup[0] = _vga->_showQ->first(); dup[0]; dup[0] = dup[0]->_next) { + buref = dup[0]->_ref; + if (buref / 1000 == 16 && buref % 100 == 6) { + Stage = (buref / 100) % 10; + break; + } + } + if (dup[1] == NULL) { + dup[1] = _vga->_showQ->locate(16003); // pan + dup[2] = _vga->_showQ->locate(16004); // pani + } + + if (_game) { // continue game + int i = new_random(3), hand = (dup[0]->_shpCnt == 6); + Stage++; + if (hand && Stage > DRESSED) + ++hand; + if (i >= 0 || (dup[i] == spr && new_random(3) == 0)) { + SNPOST(SNSEQ, -1, 3, dup[0]); // yes + SNPOST(SNSEQ, -1, 3, dup[1]); // yes + SNPOST(SNSEQ, -1, 3, dup[2]); // yes + SNPOST(SNTNEXT, -1, 0, dup[0]); // reset Take + SNPOST(SNTNEXT, -1, 0, dup[1]); // reset Take + SNPOST(SNTNEXT, -1, 0, dup[2]); // reset Take + SNPOST(SNNNEXT, -1, 0, dup[0]); // reset Near + SNPOST(SNPAUSE, -1, 72, NULL); // little rest + SNPOST(SNSAY, 1, 16009, NULL); // hura + SNPOST(SNSAY, buref, 16010, NULL); // siadaj + SNPOST(SNSAY, 1, 16011, NULL); // postoj‘ + + if (hand) { + SNPOST(SNSEND, 16060 + hand, 16, NULL); // dawaj r‘k‘ + SNPOST(SNSEQ, buref, 4, NULL); // zdejmowanie + SNPOST(SNSEQ, 16060 + hand, 1, NULL); // ruch + SNPOST(SNSOUND, 16060 + hand, 16002, NULL); // szelest + SNPOST(SNWAIT, 16060 + hand, 3, NULL); // podniesie + SNPOST(SNSWAP, buref, buref + 100, NULL); // rozdziana + SNPOST(SNSEQ, 16016, Stage, NULL); // rožnie kupa + SNPOST(SNSEND, 16060 + hand, -1, NULL); // chowaj r‘k‘ + SNPOST(SNWAIT, 16060 + hand, -1, NULL); // r‘ka zamar’a + } else { + SNPOST(SNSEQ, buref, 4, NULL); // zdejmowanie + SNPOST(SNSOUND, 16060 + hand, 16002, NULL); // szelest + SNPOST(SNWAIT, buref, -1, NULL); // zdejmie + SNPOST(SNSWAP, buref, buref + 100, NULL); // rozdziana + SNPOST(SNSEQ, 16016, Stage, NULL); // rožnie kupa + } + //SNPOST(SNSEQ, buref+100, 0, NULL); // reset + SNPOST(SNPAUSE, -1, 72, NULL); // chwilk‘... + + SNPOST(SNSEQ, -1, 0, dup[1]); // odstaw Go + SNPOST(SNSETXY, -1, 203 + SCR_WID * 49, dup[1]); + SNPOST(SNSETZ, -1, 7, dup[1]); + + SNPOST(SNSEQ, -1, 0, dup[2]); // odstaw J† + SNPOST(SNSETXY, -1, 182 + SCR_WID * 62, dup[2]); + SNPOST(SNSETZ, -1, 9, dup[2]); + _game = 0; + return; + } else { + SNPOST(SNSEQ, -1, 2, dup[0]); // no + SNPOST(SNSEQ, -1, 2, dup[1]); // no + SNPOST(SNSEQ, -1, 2, dup[2]); // no + SNPOST(SNPAUSE, -1, 72, NULL); // 1 sec + } + } + SNPOST(SNWALK, 198, 134, NULL); // na miejsce + SNPOST(SNWAIT, 1, -1, NULL); // stoi + SNPOST(SNCOVER, 1, 16101, NULL); // ch’op do bicia + SNPOST(SNSEQ, 16101, 1, NULL); // wystaw + SNPOST(SNWAIT, 16101, 5, NULL); // czekaj + SNPOST(SNPAUSE, 16101, 24, NULL); // czekaj chwil‘ + SNPOST(SNSEQ, 16040, 1, NULL); // plask + SNPOST(SNSOUND, 16101, 16001, NULL); // plask! + SNPOST(SNPAUSE, 16101, 24, NULL); // czekaj chwil‘ + SNPOST(SNSEQ, 16040, 0, NULL); // schowaj plask + SNPOST(SNWAIT, 16101, -1, NULL); // stoi + SNPOST(SNUNCOVER, 1, 16101, NULL); // SDS + if (!_game) { + SNPOST(SNSAY, buref, 16008, NULL); // zgadnij! + _game = true; + } +#undef STEPS +#undef DRESSED + } + break; + //-------------------------------------------------------------------- + case 2 : { + static Sprite *k = NULL, * k1, * k2, * k3; + static int count = 0; + + if (k == NULL) { + k = _vga->_showQ->locate(20700); + k1 = _vga->_showQ->locate(20701); + k2 = _vga->_showQ->locate(20702); + k3 = _vga->_showQ->locate(20703); + } + + if (!_game) { // init + SNPOST(SNGAME, 20002, 2, NULL); + _game = true; + } else { // cont + k1->step(new_random(6)); + k2->step(new_random(6)); + k3->step(new_random(6)); + ///-------------------- + if (spr->_ref == 1 && _keyboard->_key[ALT]) { + k1->step(5); + k2->step(5); + k3->step(5); + } + ///-------------------- + SNPOST(SNSETZ, 20700, 0, NULL); + bool hit = (k1->_seqPtr + k2->_seqPtr + k3->_seqPtr == 15); + if (hit) { + if (spr->_ref == 1) { + SNPOST(SNSAY, 1, 20003, NULL); // hura! + SNPOST(SNSEQ, 20011, 2, NULL); // kamera won + SNPOST(SNSEND, 20701, -1, NULL); // k1 won + SNPOST(SNSEND, 20702, -1, NULL); // k2 won + SNPOST(SNSEND, 20703, -1, NULL); // k3 won + SNPOST(SNSEND, 20700, -1, NULL); // tv won + SNPOST(SNKEEP, 20007, 0, NULL); // do kieszeni + SNPOST(SNSEND, 20006, 20, NULL); // bilon + SNPOST(SNSOUND, 20006, 20002, NULL); // bilon! + SNPOST(SNSAY, 20002, 20004, NULL); + SNPOST(SNSEND, 20010, 20, NULL); // papier + SNPOST(SNSOUND, 20010, 20003, NULL); // papier! + SNPOST(SNSAY, 20001, 20005, NULL); + _game = false; + return; + } else + k3->step(new_random(5)); + } + if (count < 100) { + switch (count) { + case 15 : + SNPOST(SNSAY, 20003, 20021, NULL); + break; + case 30 : + case 45 : + case 60 : + case 75 : + SNPOST(SNSAY, 20003, 20022, NULL); + break; + } + count++; + } + switch (spr->_ref) { + case 1 : + SNPOST(SNSAY, 20001, 20011, NULL); // zapro + SNPOST(SNSEQ, 20001, 1, NULL); // rzu + SNPOST(SNWAIT, 20001, 1, NULL); // czekaj + SNPOST(SNSETZ, 20700, 2, NULL); // skryj k + SNPOST(SNHIDE, 20007, 1, NULL); // skryj k + SNPOST(SNWAIT, 20001, 16, NULL); // czekaj + SNPOST(SNSEQ, 20007, 1, NULL); // lec† + SNPOST(SNHIDE, 20007, 0, NULL); // poka§ + SNPOST(SNSOUND, 20007, 20001, NULL); // grzech + SNPOST(SNWAIT, 20007, -1, NULL); // koniec + SNPOST(SNGAME, 20001, 2, NULL); // again! + break; + case 20001: + SNPOST(SNSAY, 20002, 20012, NULL); // zapro + SNPOST(SNSEQ, 20002, 1, NULL); // rzu + SNPOST(SNWAIT, 20002, 3, NULL); // czekaj + SNPOST(SNSETZ, 20700, 2, NULL); // skryj k + SNPOST(SNHIDE, 20007, 1, NULL); // skryj k + SNPOST(SNWAIT, 20002, 10, NULL); // czekaj + SNPOST(SNSEQ, 20007, 2, NULL); // lec† + SNPOST(SNHIDE, 20007, 0, NULL); // poka§ + SNPOST(SNSOUND, 20007, 20001, NULL); // grzech + SNPOST(SNWAIT, 20007, -1, NULL); // koniec + SNPOST(SNGAME, 20002, 2, NULL); // again! + break; + case 20002: + SNPOST(SNSAY, 20002, 20010, NULL); // zapro + SNPOST(SNWALK, 20005, -1, NULL); // do stol + SNPOST(SNWAIT, 1, -1, NULL); // stoi + SNPOST(SNCOVER, 1, 20101, NULL); // grasol + SNPOST(SNSEQ, 20101, 1, NULL); // rzu + SNPOST(SNWAIT, 20101, 5, NULL); // czekaj + SNPOST(SNSETZ, 20700, 2, NULL); // skryj k + SNPOST(SNHIDE, 20007, 1, NULL); // skryj k + SNPOST(SNWAIT, 20101, 15, NULL); // czekaj + SNPOST(SNSEQ, 20007, 1, NULL); // lec† + SNPOST(SNHIDE, 20007, 0, NULL); // poka§ + SNPOST(SNSOUND, 20007, 20001, NULL); // grzech + SNPOST(SNWAIT, 20101, -1, NULL); // koniec + SNPOST(SNUNCOVER, 1, 20101, NULL); // SDS + SNPOST(SNGAME, 1, 2, NULL); // again! + break; + } + } + } + break; + } +} + + +void CGEEngine::expandSprite(Sprite *spr) { + if (spr) + _vga->_showQ->insert(_vga->_spareQ->remove(spr)); +} + + +void CGEEngine::contractSprite(Sprite *spr) { + if (spr) + _vga->_spareQ->append(_vga->_showQ->remove(spr)); +} + +int CGEEngine::findPocket(Sprite *spr) { + for (int i = 0; i < POCKET_NX; i++) + if (_pocket[i] == spr) + return i; + return -1; +} + + +void CGEEngine::selectPocket(int n) { + if (n < 0 || (_pocLight->_seqPtr && _pocPtr == n)) { + _pocLight->step(0); + n = findPocket(NULL); + if (n >= 0) + _pocPtr = n; + } else { + if (_pocket[n] != NULL) { + _pocPtr = n; + _pocLight->step(1); + } + } + _pocLight->gotoxy(POCKET_X + _pocPtr * POCKET_DX + POCKET_SX, POCKET_Y + POCKET_SY); +} + +void CGEEngine::pocFul() { + _hero->park(); + SNPOST(SNWAIT, -1, -1, _hero); + SNPOST(SNSEQ, -1, POC_FUL, _hero); + SNPOST(SNSOUND, -1, 2, _hero); + SNPOST(SNWAIT, -1, -1, _hero); + SNPOST(SNSAY, 1, POC_FUL_TEXT, _hero); +} + +void CGEEngine::hide1(Sprite *spr) { + SNPOST_(SNGHOST, -1, 0, spr->ghost()); +} + +void CGEEngine::snGhost(Bitmap *bmp) { + // TODO : Get x and y from M but not using segment / offset + //bmp->Hide(FP_OFF(bmp->_m), FP_SEG(bmp->_m)); + bmp->_m = NULL; + delete bmp; + warning("STUB: SNGhost"); +} + +void CGEEngine::feedSnail(Sprite *spr, SNLIST snq) { + if (spr) + if (spr->active()) { + uint8 ptr = (snq == TAKE) ? spr->_takePtr : spr->_nearPtr; + + if (ptr != NO_PTR) { + Snail::Com *comtab = spr->snList(snq); + Snail::Com *c = comtab + ptr; + + if (findPocket(NULL) < 0) { // no empty pockets? + Snail::Com *p; + for (p = c; p->_com != SNNEXT; p++) { // find KEEP command + if (p->_com == SNKEEP) { + pocFul(); + return; + } + if (p->_ptr) + break; + } + } + while (true) { + if (c->_com == SNTALK) { + if ((_snail->_talkEnable = (c->_val != 0)) == false) + killText(); + } + if (c->_com == SNNEXT) { + Sprite *s = (c->_ref < 0) ? spr : locate(c->_ref); + if (s) { + uint8 *idx = (snq == TAKE) ? &s->_takePtr : &s->_nearPtr; + if (*idx != NO_PTR) { + int v; + switch (c->_val) { + case -1 : + v = c - comtab + 1; + break; + case -2 : + v = c - comtab; + break; + case -3 : + v = -1; + break; + default : + v = c->_val; + break; + } + if (v >= 0) + *idx = v; + } + } + if (s == spr) + break; + } + if (c->_com == SNIF) { + Sprite *s = (c->_ref < 0) ? spr : locate(c->_ref); + if (s) { // sprite extsts + if (! s->seqTest(-1)) + c = comtab + c->_val; // not parked + else + ++c; + } else + ++c; + } else { + SNPOST(c->_com, c->_ref, c->_val, spr); + if (c->_ptr) + break; + else + ++c; + } + } + } + } +} + +const char *Snail::_comTxt[] = { + "LABEL", "PAUSE", "WAIT", "LEVEL", "HIDE", + "SAY", "INF", "TIME", "CAVE", "KILL", + "RSEQ", "SEQ", "SEND", "SWAP", "KEEP", + "GIVE", "IF", "GAME", "SETX0", "SETY0", + "SLAVE", "SETXY", "RELX", "RELY", "RELZ", + "SETX", "SETY", "SETZ", "TRANS", "PORT", + "NEXT", "NNEXT", "TNEXT", "RNNEXT", "RTNEXT", + "RMNEAR", "RMTAKE", "FLAG", "SETREF", "BACKPT", + "FLASH", "LIGHT", "SETHB", "SETVB", "WALK", + "REACH", "COVER", "UNCOVER", "CLEAR", "TALK", + "MOUSE", "SOUND", "COUNT", NULL +}; + + +Snail::Snail(CGEEngine *vm, bool turbo) + : _turbo(turbo), _busy(false), _textDelay(false), + _timerExpiry(0), _talkEnable(true), + _head(0), _tail(0), _snList(farnew(Com, 256)), _vm(vm) { +} + +Snail::~Snail() { + if (_snList) + free(_snList); +} + +void Snail::addCom(SNCOM com, int ref, int val, void *ptr) { + _disable(); + Com *snc = &_snList[_head++]; + snc->_com = com; + snc->_ref = ref; + snc->_val = val; + snc->_ptr = ptr; + if (com == SNCLEAR) { + _tail = _head; + killText(); + _timerExpiry = 0; + } + _enable(); +} + +void Snail::insCom(SNCOM com, int ref, int val, void *ptr) { + Com *snc; + + _disable(); + if (_busy) { + _snList[(_tail - 1) & 0xFF] = _snList[_tail]; + snc = &_snList[_tail]; + } else + snc = &_snList[(_tail - 1) & 0xFF]; + _tail--; + snc->_com = com; + snc->_ref = ref; + snc->_val = val; + snc->_ptr = ptr; + if (com == SNCLEAR) { + _tail = _head; + killText(); + _timerExpiry = 0; + } + _enable(); +} + +void CGEEngine::snNNext(Sprite *sprel, int p) { + if (sprel) + if (sprel->_nearPtr != NO_PTR) + sprel->_nearPtr = p; +} + +void CGEEngine::snTNext(Sprite *sprel, int p) { + if (sprel) + if (sprel->_takePtr != NO_PTR) + sprel->_takePtr = p; +} + +void CGEEngine::snRNNext(Sprite *sprel, int p) { + if (sprel) + if (sprel->_nearPtr != NO_PTR) + sprel->_nearPtr += p; +} + + +void CGEEngine::snRTNext(Sprite *sprel, int p) { + if (sprel) + if (sprel->_takePtr != NO_PTR) + sprel->_takePtr += p; +} + +void CGEEngine::snZTrim(Sprite *spr) { + if (spr) + if (spr->active()) { + bool en = _heart->_enable; + Sprite *s; + _heart->_enable = false; + s = (spr->_flags._shad) ? spr->_prev : NULL; + _vga->_showQ->insert(_vga->_showQ->remove(spr)); + if (s) { + s->_z = spr->_z; + _vga->_showQ->insert(_vga->_showQ->remove(s), spr); + } + _heart->_enable = en; + } +} + +void CGEEngine::snHide(Sprite *spr, int val) { + if (spr) { + spr->_flags._hide = (val >= 0) ? (val != 0) : (!spr->_flags._hide); + if (spr->_flags._shad) + spr->_prev->_flags._hide = spr->_flags._hide; + } +} + +void CGEEngine::snRmNear(Sprite *spr) { + if (spr) + spr->_nearPtr = NO_PTR; +} + +void CGEEngine::snRmTake(Sprite *spr) { + if (spr) + spr->_takePtr = NO_PTR; +} + +void CGEEngine::snSeq(Sprite *spr, int val) { + if (spr) { + if (spr == _hero && val == 0) + _hero->park(); + else + spr->step(val); + } +} + +void CGEEngine::snRSeq(Sprite *spr, int val) { + if (spr) + snSeq(spr, spr->_seqPtr + val); +} + +void CGEEngine::snSend(Sprite *spr, int val) { + if (spr) { + int was = spr->_cave; + bool was1 = (was == 0 || was == _now); + bool val1 = (val == 0 || val == _now); + spr->_cave = val; + if (val1 != was1) { + if (was1) { + if (spr->_flags._kept) { + int n = findPocket(spr); + if (n >= 0) + _pocket[n] = NULL; + } + hide1(spr); + contractSprite(spr); + spr->_flags._slav = false; + } else { + if (spr->_ref % 1000 == 0) + Bitmap::_pal = Vga::_sysPal; + if (spr->_flags._back) + spr->backShow(true); + else + expandSprite(spr); + Bitmap::_pal = NULL; + } + } + } +} + + +void CGEEngine::snSwap(Sprite *spr, int xref) { + Sprite *xspr = locate(xref); + if (spr && xspr) { + int was = spr->_cave; + int xwas = xspr->_cave; + bool was1 = (was == 0 || was == _now); + bool xwas1 = (xwas == 0 || xwas == _now); + + swap(spr->_cave, xspr->_cave); + swap(spr->_x, xspr->_x); + swap(spr->_y, xspr->_y); + swap(spr->_z, xspr->_z); + if (spr->_flags._kept) { + int n = findPocket(spr); + if (n >= 0) + _pocket[n] = xspr; + xspr->_flags._kept = true; + xspr->_flags._port = false; + } + if (xwas1 != was1) { + if (was1) { + hide1(spr); + contractSprite(spr); + } else + expandSprite(spr); + if (xwas1) { + hide1(xspr); + contractSprite(xspr); + } else + expandSprite(xspr); + } + } +} + + +void CGEEngine::snCover(Sprite *spr, int xref) { + Sprite *xspr = locate(xref); + if (spr && xspr) { + spr->_flags._hide = true; + xspr->_z = spr->_z; + xspr->_cave = spr->_cave; + xspr->gotoxy(spr->_x, spr->_y); + expandSprite(xspr); + if ((xspr->_flags._shad = spr->_flags._shad) == 1) { + _vga->_showQ->insert(_vga->_showQ->remove(spr->_prev), xspr); + spr->_flags._shad = false; + } + feedSnail(xspr, NEAR); + } +} + + +void CGEEngine::snUncover(Sprite *spr, Sprite *xspr) { + if (spr && xspr) { + spr->_flags._hide = false; + spr->_cave = xspr->_cave; + spr->gotoxy(xspr->_x, xspr->_y); + if ((spr->_flags._shad = xspr->_flags._shad) == 1) { + _vga->_showQ->insert(_vga->_showQ->remove(xspr->_prev), spr); + xspr->_flags._shad = false; + } + spr->_z = xspr->_z; + snSend(xspr, -1); + if (spr->_time == 0) + spr->_time++; + } +} + + +void CGEEngine::snSetX0(int cav, int x0) { + _heroXY[cav - 1]._x = x0; +} + +void CGEEngine::snSetY0(int cav, int y0) { + _heroXY[cav - 1]._y = y0; +} + +void CGEEngine::snSetXY(Sprite *spr, uint16 xy) { + if (spr) + spr->gotoxy(xy % SCR_WID, xy / SCR_WID); +} + +void CGEEngine::snRelX(Sprite *spr, int x) { + if (spr && _hero) + spr->gotoxy(_hero->_x + x, spr->_y); +} + +void CGEEngine::snRelY(Sprite *spr, int y) { + if (spr && _hero) + spr->gotoxy(spr->_x, _hero->_y + y); +} + + +void CGEEngine::snRelZ(Sprite *spr, int z) { + if (spr && _hero) { + spr->_z = _hero->_z + z; + snZTrim(spr); + } +} + + +void CGEEngine::snSetX(Sprite *spr, int x) { + if (spr) + spr->gotoxy(x, spr->_y); +} + + +void CGEEngine::snSetY(Sprite *spr, int y) { + if (spr) + spr->gotoxy(spr->_x, y); +} + + +void CGEEngine::snSetZ(Sprite *spr, int z) { + if (spr) { + spr->_z = z; + //SNPOST_(SNZTRIM, -1, 0, spr); + snZTrim(spr); + } +} + + +void CGEEngine::snSlave(Sprite *spr, int ref) { + Sprite *slv = locate(ref); + if (spr && slv) { + if (spr->active()) { + snSend(slv, spr->_cave); + slv->_flags._slav = true; + slv->_z = spr->_z; + _vga->_showQ->insert(_vga->_showQ->remove(slv), spr->_next); + } + } +} + + +void CGEEngine::snTrans(Sprite *spr, int trans) { + if (spr) + spr->_flags._tran = (trans < 0) ? !spr->_flags._tran : (trans != 0); +} + +void CGEEngine::snPort(Sprite *spr, int port) { + if (spr) + spr->_flags._port = (port < 0) ? !spr->_flags._port : (port != 0); +} + +void CGEEngine::snKill(Sprite *spr) { + if (spr) { + if (spr->_flags._kept) { + int n = findPocket(spr); + if (n >= 0) + _pocket[n] = NULL; + } + Sprite *nx = spr->_next; + hide1(spr); + _vga->_showQ->remove(spr); + EventManager::ClrEvt(spr); + if (spr->_flags._kill) + delete spr; + else { + spr->_cave = -1; + _vga->_spareQ->append(spr); + } + if (nx) { + if (nx->_flags._slav) + snKill(nx); + } + } +} + + +void CGEEngine::snSound(Sprite *spr, int wav, int cnt) { + if (_sndDrvInfo._dDev) { + if (wav == -1) + _sound.stop(); + else + _sound.play(_fx[wav], (spr) ? ((spr->_x + spr->_w / 2) / (SCR_WID / 16)) : 8, cnt); + } +} + + +void CGEEngine::snKeep(Sprite *spr, int stp) { + selectPocket(-1); + if (spr && ! spr->_flags._kept && _pocket[_pocPtr] == NULL) { + snSound(spr, 3, 1); + _pocket[_pocPtr] = spr; + spr->_cave = 0; + spr->_flags._kept = true; + spr->gotoxy(POCKET_X + POCKET_DX * _pocPtr + POCKET_DX / 2 - spr->_w / 2, + POCKET_Y + POCKET_DY / 2 - spr->_h / 2); + if (stp >= 0) + spr->step(stp); + } + selectPocket(-1); +} + + +void CGEEngine::snGive(Sprite *spr, int stp) { + if (spr) { + int p = findPocket(spr); + if (p >= 0) { + _pocket[p] = NULL; + spr->_cave = _now; + spr->_flags._kept = false; + if (stp >= 0) + spr->step(stp); + } + } + selectPocket(-1); +} + + +void CGEEngine::snBackPt(Sprite *spr, int stp) { + if (spr) { + if (stp >= 0) + spr->step(stp); + spr->backShow(true); + } +} + +void CGEEngine::snLevel(Sprite *spr, int lev) { + while (_lev < lev) { + _lev++; + spr = _vga->_spareQ->locate(100 + _lev); + if (spr) { + spr->backShow(true); + spr->_cave = 0; + } + } + _maxCave = _maxCaveArr[_lev]; + if (spr) + spr->_flags._hide = false; +} + + +void CGEEngine::snFlag(int fn, bool v) { + _flag[fn] = v; +} + +void CGEEngine::snSetRef(Sprite *spr, int nr) { + if (spr) + spr->_ref = nr; +} + +void CGEEngine::snFlash(bool on) { + if (on) { + Dac *pal = farnew(Dac, PAL_CNT); + if (pal) { + memcpy(pal, Vga::_sysPal, PAL_SIZ); + for (int i = 0; i < PAL_CNT; i++) { + register int c; + c = pal[i]._r << 1; + pal[i]._r = (c < 64) ? c : 63; + c = pal[i]._g << 1; + pal[i]._g = (c < 64) ? c : 63; + c = pal[i]._b << 1; + pal[i]._b = (c < 64) ? c : 63; + } + _vga->setColors(pal, 64); + } + } else + _vga->setColors(Vga::_sysPal, 64); + _dark = false; +} + + +void CGEEngine::snLight(bool in) { + if (in) + _vga->sunrise(Vga::_sysPal); + else + _vga->sunset(); + _dark = ! in; +} + +void CGEEngine::snBarrier(int cav, int bar, bool horz) { + ((uint8 *)(_barriers + ((cav > 0) ? cav : _now)))[horz] = bar; +} + +void CGEEngine::snWalk(Sprite *spr, int x, int y) { + if (_hero) { + if (spr && y < 0) + _hero->findWay(spr); + else + _hero->findWay(XZ(x, y)); + } +} + +void CGEEngine::snReach(Sprite *spr, int mode) { + if (_hero) + _hero->reach(spr, mode); +} + +void CGEEngine::snMouse(bool on) { + if (on) + _mouse->On(); + else + _mouse->Off(); +} + + +void Snail::runCom() { + static int count = 1; + if (!_busy) { + _busy = true; + uint8 tmphea = _head; + while (_tail != tmphea) { + Com *snc = &_snList[_tail]; + + if (!_turbo) { // only for the slower one + if (_timerExpiry) { + // Delay in progress + if (_timerExpiry > g_system->getMillis()) + // Delay not yet ended + break; + + // Delay is finished + _timerExpiry = 0; + } else { + if (_textDelay) { + killText(); + _textDelay = false; + } + } + if (_talk && snc->_com != SNPAUSE) + break; + } + + Sprite *sprel = ((snc->_ref >= 0) ? locate(snc->_ref) : ((Sprite *) snc->_ptr)); + switch (snc->_com) { + case SNLABEL : + break; + case SNPAUSE : + _timerExpiry = g_system->getMillis() + snc->_val * SNAIL_FRAME_DELAY; + if (_talk) + _textDelay = true; + break; + case SNWAIT : + if (sprel) { + if (sprel->seqTest(snc->_val) && + (snc->_val >= 0 || sprel != _hero || _hero->_tracePtr < 0)) { + _timerExpiry = g_system->getMillis() + sprel->_time * SNAIL_FRAME_DELAY; + } else + goto xit; + } + break; + case SNLEVEL : + _vm->snLevel(sprel, snc->_val); + break; + case SNHIDE : + _vm->snHide(sprel, snc->_val); + break; + case SNSAY : + if (sprel && _talkEnable) { + if (sprel == _hero && sprel->seqTest(-1)) + sprel->step(HTALK); + _text->say(_text->getText(snc->_val), sprel); + _sys->_funDel = HEROFUN0; + } + break; + case SNINF : + if (_talkEnable) { + _vm->inf(_text->getText(snc->_val)); + _sys->_funDel = HEROFUN0; + } + break; + case SNTIME : + if (sprel && _talkEnable) { + if (sprel == _hero && sprel->seqTest(-1)) + sprel->step(HTALK); + sayTime(sprel); + } + break; + case SNCAVE : + // SwitchCave(snc->_val); + warning("Problematic call of SwitchCave in SNAIL::runCom"); + break; + case SNKILL : + _vm->snKill(sprel); + break; + case SNSEQ : + _vm->snSeq(sprel, snc->_val); + break; + case SNRSEQ : + _vm->snRSeq(sprel, snc->_val); + break; + case SNSEND : + _vm->snSend(sprel, snc->_val); + break; + case SNSWAP : + _vm->snSwap(sprel, snc->_val); + break; + case SNCOVER : + _vm->snCover(sprel, snc->_val); + break; + case SNUNCOVER : + _vm->snUncover(sprel, (snc->_val >= 0) ? locate(snc->_val) : ((Sprite *) snc->_ptr)); + break; + case SNKEEP : + _vm->snKeep(sprel, snc->_val); + break; + case SNGIVE : + _vm->snGive(sprel, snc->_val); + break; + case SNGAME : + _vm->snGame(sprel, snc->_val); + break; + case SNSETX0 : + _vm->snSetX0(snc->_ref, snc->_val); + break; + case SNSETY0 : + _vm->snSetY0(snc->_ref, snc->_val); + break; + case SNSETXY : + _vm->snSetXY(sprel, snc->_val); + break; + case SNRELX : + _vm->snRelX(sprel, snc->_val); + break; + case SNRELY : + _vm->snRelY(sprel, snc->_val); + break; + case SNRELZ : + _vm->snRelZ(sprel, snc->_val); + break; + case SNSETX : + _vm->snSetX(sprel, snc->_val); + break; + case SNSETY : + _vm->snSetY(sprel, snc->_val); + break; + case SNSETZ : + _vm->snSetZ(sprel, snc->_val); + break; + case SNSLAVE : + _vm->snSlave(sprel, snc->_val); + break; + case SNTRANS : + _vm->snTrans(sprel, snc->_val); + break; + case SNPORT : + _vm->snPort(sprel, snc->_val); + break; + case SNNEXT : + case SNIF : + case SNTALK : + break; + case SNMOUSE : + _vm->snMouse(snc->_val != 0); + break; + case SNNNEXT : + _vm->snNNext(sprel, snc->_val); + break; + case SNTNEXT : + _vm->snTNext(sprel, snc->_val); + break; + case SNRNNEXT : + _vm->snRNNext(sprel, snc->_val); + break; + case SNRTNEXT : + _vm->snRTNext(sprel, snc->_val); + break; + case SNRMNEAR : + _vm->snRmNear(sprel); + break; + case SNRMTAKE : + _vm->snRmTake(sprel); + break; + case SNFLAG : + _vm->snFlag(snc->_ref & 3, snc->_val != 0); + break; + case SNSETREF : + _vm->snSetRef(sprel, snc->_val); + break; + case SNBACKPT : + _vm->snBackPt(sprel, snc->_val); + break; + case SNFLASH : + _vm->snFlash(snc->_val != 0); + break; + case SNLIGHT : + _vm->snLight(snc->_val != 0); + break; + case SNSETHB : + _vm->snBarrier(snc->_ref, snc->_val, true); + break; + case SNSETVB : + _vm->snBarrier(snc->_ref, snc->_val, false); + break; + case SNWALK : + _vm->snWalk(sprel, snc->_ref, snc->_val); + break; + case SNREACH : + _vm->snReach(sprel, snc->_val); + break; + case SNSOUND : + _vm->snSound(sprel, snc->_val, count); + count = 1; + break; + case SNCOUNT : + count = snc->_val; + break; + case SNEXEC : + // TODO: Handle correctly the execution of function pointer coming from Message send SNPOST + // ((void(*)(int)) (snc->_ptr))(snc->_val); + warning("STUB: SNEXEC code"); + break; + case SNSTEP : + sprel->step(); + break; + case SNZTRIM : + _vm->snZTrim(sprel); + break; + case SNGHOST : + _vm->snGhost((Bitmap *) snc->_ptr); + break; + default : + warning("Unhandled snc->_com in SNMouse(bool)"); + break; + } + _tail++; + if (!_turbo) + break; + } +xit: + _busy = false; + } +} + + +bool Snail::idle() { + return (_head == _tail); +} + +} // End of namespace CGE diff --git a/engines/cge/snail.h b/engines/cge/snail.h new file mode 100644 index 0000000000..888fae6ce9 --- /dev/null +++ b/engines/cge/snail.h @@ -0,0 +1,110 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_SNAIL__ +#define __CGE_SNAIL__ + +#include "cge/jbw.h" +#include "cge/cge.h" + +namespace CGE { + +#define POCKET_X 174 +#define POCKET_Y 176 +#define POCKET_DX 18 +#define POCKET_DY 22 +#define POCKET_NY 1 + +#define POCKET_SX 8 +#define POCKET_SY 3 + +#define SNINSERT(c, r, v, p) _snail->insCom(c, r, v, p) +#define SNPOST(c, r, v, p) _snail->addCom(c, r, v, p) +#define SNPOST_(c, r, v, p) _snail_->addCom(c, r, v, p) + +#define SNAIL_FRAME_RATE 62 +#define SNAIL_FRAME_DELAY (1000 / SNAIL_FRAME_RATE) + +struct Bar { + uint8 _horz; + uint8 _vert; +}; + + +enum SNCOM { + SNLABEL, SNPAUSE, SNWAIT, SNLEVEL, SNHIDE, + SNSAY, SNINF, SNTIME, SNCAVE, SNKILL, + SNRSEQ, SNSEQ, SNSEND, SNSWAP, SNKEEP, + SNGIVE, SNIF, SNGAME, SNSETX0, SNSETY0, + SNSLAVE, SNSETXY, SNRELX, SNRELY, SNRELZ, + SNSETX, SNSETY, SNSETZ, SNTRANS, SNPORT, + SNNEXT, SNNNEXT, SNTNEXT, SNRNNEXT, SNRTNEXT, + SNRMNEAR, SNRMTAKE, SNFLAG, SNSETREF, SNBACKPT, + SNFLASH, SNLIGHT, SNSETHB, SNSETVB, SNWALK, + SNREACH, SNCOVER, SNUNCOVER, SNCLEAR, SNTALK, + SNMOUSE, SNSOUND, SNCOUNT, SNEXEC, SNSTEP, + SNZTRIM, SNGHOST +}; + +class Snail { +public: + struct Com { + SNCOM _com; + int _ref; + int _val; + void *_ptr; + } *_snList; + uint8 _head; + uint8 _tail; + bool _turbo; + bool _busy; + bool _textDelay; + uint32 _timerExpiry; + static const char *_comTxt[]; + bool _talkEnable; + Snail(CGEEngine *vm, bool turbo); + ~Snail(); + void runCom(); + void addCom(SNCOM com, int ref, int val, void *ptr); + void insCom(SNCOM com, int ref, int val, void *ptr); + bool idle(); +private: + CGEEngine *_vm; +}; + + +extern bool _dark; +extern int _lev; +extern Bar _barriers[]; +extern struct Hxy { + int _x; + int _y; +} _heroXY[]; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/snddrv.h b/engines/cge/snddrv.h new file mode 100644 index 0000000000..0ea776b784 --- /dev/null +++ b/engines/cge/snddrv.h @@ -0,0 +1,130 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +// ****************************************************** +// * Sound Driver by Hedges (c) 1995 LK AVALON * +// * Ver 1.00: 01-Mar-95 * +// * Ver 1.10: 03-Mar-95 * +// * Ver 1.20: 07-Mar-95 * +// * Ver 1.30: 09-Mar-95 * +// * Ver 1.40: 11-Mar-95 * +// ****************************************************** + +#ifndef __CGE_SNDDRV__ +#define __CGE_SNDDRV__ + +namespace CGE { + +// ****************************************************** +// * Constants * +// ****************************************************** +// available devices + +enum DEV_TYPE { DEV_AUTO = -1, // auto-detect mode + DEV_QUIET, // disable sound + DEV_SB, // sb/pro/16/awe32 + DEV_GUS, // gus/max + DEV_GM // general midi + }; + +#define SERR_OK 0 // no error +#define SERR_INITFAIL 1 // couldn't initialize +#define SERR_BADDDEV 128 // bad device + +// driver info +struct DrvInfo { + DEV_TYPE _dDev; // digi device + DEV_TYPE _mDev; // midi device + uint16 _dBase; // digi base port + uint16 _dDma; // digi dma no + uint16 _dIrq; // digi irq no + uint16 _mBase; // midi base port + union { + struct { + uint16 _dr : 4; + uint16 _dl : 4; + uint16 _mr : 4; + uint16 _ml : 4; + } Vol4; + struct { + uint8 _d; // digi volume + uint8 _m; // midi volume + } Vol2; + }; +}; + +// sample info +struct SmpInfo { + uint8 *_saddr; // address + uint16 _slen; // length + uint16 _span; // left/right pan (0-15) + int _sflag; // flag +}; + +// ****************************************************** +// * Data * +// ****************************************************** +// driver info +extern DrvInfo _sndDrvInfo; + +// midi player flag (1 means we are playing) +extern uint16 _midiPlayFlag; + +// midi song end flag (1 means we have crossed end mark) +extern uint16 _midiEndFlag; + +// ****************************************************** +// * Driver Code * +// ****************************************************** +// Init Digi Device +void sndInit(); + +// Close Digi Device +void sndDone(); + +// Set Volume +void sndSetVolume(); + +// Start Digi +void sndDigiStart(SmpInfo *PSmpInfo); + +// Stop Digi +void sndDigiStop(SmpInfo *PSmpInfo); + +// Start MIDI File +void sndMidiStart(uint8 *MIDFile); + +// Stop MIDI File +void sndMidiStop(); + +// Play MIDI File (to be called while interrupting) +// WARNING: Uses ALL registers! +void sndMidiPlay(); + +} // End of namespace CGE + +#endif diff --git a/engines/cge/sound.cpp b/engines/cge/sound.cpp new file mode 100644 index 0000000000..a163949ddd --- /dev/null +++ b/engines/cge/sound.cpp @@ -0,0 +1,227 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/general.h" +#include "cge/startup.h" +#include "cge/sound.h" +#include "cge/text.h" +#include "cge/cfile.h" +#include "cge/vol.h" + + +namespace CGE { + +Fx _fx = 16; // must precede SOUND!! +Sound _sound; + + +Sound::Sound() { + if (Startup::_soundOk) + open(); +} + + +Sound::~Sound() { + close(); +} + + +void Sound::close() { + killMidi(); + sndDone(); +} + + +void Sound::open() { + sndInit(); + play(_fx[30000], 8); +} + + +void Sound::play(DataCk *wav, int pan, int cnt) { + if (wav) { + stop(); + _smpinf._saddr = (uint8 *) &*(wav->eAddr()); + _smpinf._slen = (uint16)wav->size(); + _smpinf._span = pan; + _smpinf._sflag = cnt; + sndDigiStart(&_smpinf); + } +} + + +void Sound::stop() { + sndDigiStop(&_smpinf); +} + + +Fx::Fx(int size) : _emm(0L), _current(NULL) { + _cache = new Han[size]; + for (_size = 0; _size < size; _size++) { + _cache[_size]._ref = 0; + _cache[_size]._wav = NULL; + } +} + + +Fx::~Fx() { + clear(); + delete[] _cache; +} + + +void Fx::clear() { + Han *p, * q; + for (p = _cache, q = p + _size; p < q; p++) { + if (p->_ref) { + p->_ref = 0; + delete p->_wav; + p->_wav = NULL; + } + } + _emm.release(); + _current = NULL; +} + + +int Fx::find(int ref) { + Han *p, * q; + int i = 0; + for (p = _cache, q = p + _size; p < q; p++) { + if (p->_ref == ref) + break; + else + ++i; + } + return i; +} + + +void Fx::preload(int ref0) { + Han *cacheLim = _cache + _size; + int ref; + + for (ref = ref0; ref < ref0 + 10; ref++) { + static char fname[] = "FX00000.WAV"; + wtom(ref, fname + 2, 10, 5); + INI_FILE file = INI_FILE(fname); + DataCk *wav = loadWave(&file, &_emm); + if (wav) { + Han *p = &_cache[find(0)]; + if (p >= cacheLim) + break; + p->_wav = wav; + p->_ref = ref; + } + } +} + + +DataCk *Fx::load(int idx, int ref) { + static char fname[] = "FX00000.WAV"; + wtom(ref, fname + 2, 10, 5); + + INI_FILE file = INI_FILE(fname); + DataCk *wav = loadWave(&file, &_emm); + if (wav) { + Han *p = &_cache[idx]; + p->_wav = wav; + p->_ref = ref; + } + return wav; +} + + +DataCk *Fx::operator [](int ref) { + int i; + if ((i = find(ref)) < _size) + _current = _cache[i]._wav; + else { + if ((i = find(0)) >= _size) { + clear(); + i = 0; + } + _current = load(i, ref); + } + return _current; +} + + +static uint8 *midi = NULL; + + +void killMidi() { + sndMidiStop(); + if (midi) { + delete[] midi; + midi = NULL; + } +} + + +void loadMidi(int ref) { + static char fn[] = "00.MID"; + wtom(ref, fn, 10, 2); + if (INI_FILE::exist(fn)) { + killMidi(); + INI_FILE mid = fn; + if (mid._error == 0) { + uint16 siz = (uint16) mid.size(); + midi = new uint8[siz]; + if (midi) { + mid.read(midi, siz); + if (mid._error) + killMidi(); + else + sndMidiStart(midi); + } + } + } +} + + +void *Patch(int pat) { + void *p = NULL; + static char fn[] = "PATCH000.SND"; + + wtom(pat, fn + 5, 10, 3); + INI_FILE snd = fn; + if (!snd._error) { + uint16 siz = (uint16) snd.size(); + p = (uint8 *) malloc(siz); + if (p) { + snd.read(p, siz); + if (snd._error) { + free(p); + p = NULL; + } + } + } + return p; +} + +} // End of namespace CGE diff --git a/engines/cge/sound.h b/engines/cge/sound.h new file mode 100644 index 0000000000..fda8d4f128 --- /dev/null +++ b/engines/cge/sound.h @@ -0,0 +1,80 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_SOUND__ +#define __CGE_SOUND__ + +#include "cge/wav.h" +#include "cge/snddrv.h" + +namespace CGE { + +#define BAD_SND_TEXT 97 +#define BAD_MIDI_TEXT 98 + + +class Sound { +public: + SmpInfo _smpinf; + Sound(); + ~Sound(); + void open(); + void close(); + void play(DataCk *wav, int pan, int cnt = 1); + void stop(); +}; + + +class Fx { + Emm _emm; + struct Han { + int _ref; + DataCk *_wav; + } *_cache; + int _size; + DataCk *load(int idx, int ref); + int find(int ref); +public: + DataCk *_current; + Fx(int size = 16); + ~Fx(); + void clear(); + void preload(int ref0); + DataCk *operator[](int ref); +}; + +extern Sound _sound; +extern Fx _fx; + + +void loadMidi(int ref); +void killMidi(); + +} // End of namespace CGE + +#endif + diff --git a/engines/cge/startup.cpp b/engines/cge/startup.cpp new file mode 100644 index 0000000000..9210b40c77 --- /dev/null +++ b/engines/cge/startup.cpp @@ -0,0 +1,199 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/startup.h" +#include "cge/text.h" +#include "cge/sound.h" +#include "cge/cfile.h" +#include "cge/snddrv.h" + +namespace CGE { + +extern char _copr[]; + +#define id (*(Ident*)_copr) + + +Emm _miniEmm = MINI_EMM_SIZE; + +// static Startup _startUp; + +int Startup::_mode = 0; +int Startup::_core; +int Startup::_soundOk = 0; +uint16 Startup::_summa; + + +void quitNow(int ref) { + error("%s", _text->getText(ref)); +} + + +bool Startup::getParms() { + _summa = 0; + + /* + int i = _argc; + while (i > 1) { + static char *PrmTab[] = { "NEW", "MK0SVG", "QUIET", "SB", "GUS", "MIDI", "P", "D", "I", "M" }; + int n = takeEnum(PrmTab, strtok(_argv[--i], " =:(")); + uint16 p = xtow(strtok(NULL, " h,)")); + switch (n) { + case 0 : + if (Mode != 2) + Mode = 1; + break; + case 1 : + Mode = 2; + break; + case 2 : + SNDDrvInfo.DDEV = DEV_QUIET; + break; + case 3 : + SNDDrvInfo.DDEV = DEV_SB; + break; + case 4 : + SNDDrvInfo.DDEV = DEV_GUS; + break; + case 5 : + SNDDrvInfo.MDEV = DEV_GM; + break; + case 6 : + SNDDrvInfo.DBASE = p; + break; + case 7 : + SNDDrvInfo.DDMA = p; + break; + case 8 : + SNDDrvInfo.DIRQ = p; + break; + case 9 : + SNDDrvInfo.MBASE = p; + SNDDrvInfo.MDEV = DEV_GM; + break; + default: + return false; + } + + if (n >= 2) + SoundOk = 2; + } + if (_vm->_isDemo) + // protection disabled + Summa = 0; + else { +#ifdef EVA + union { dosdate_t d; uint32 n; } today; + _dos_getdate(&today.d); + id.disk += (id.disk < today.n); +#endif +#ifdef CD + Summa = 0; +#else + // disk signature checksum + Summa = ChkSum(Copr, sizeof(Ident)); +#endif + } + + if (SNDDrvInfo.MDEV != DEV_GM) + SNDDrvInfo.MDEV = SNDDrvInfo.DDEV; + return true; + */ + warning("STUB: Startup::get_parms"); + return true; +} + + +Startup::Startup() { + /* + uint32 m = farcoreleft() >> 10; + if (m < 0x7FFF) + Core = (int) m; + else + Core = 0x7FFF; + + if (! IsVga()) + quit_now(NOT_VGA_TEXT); + if (Cpu() < _80286) + quit_now(BAD_CHIP_TEXT); + if (100 * _osmajor + _osminor < 330) + quit_now(BAD_DOS_TEXT); + if (! get_parms()) + quit_now(BAD_ARG_TEXT); + //--- load sound configuration + const char * fn = usrPath(ProgName(CFG_EXT)); + if (!Startup::_soundOk && CFILE::Exist(fn)) { + CFILE cfg(fn, REA); + if (! cfg.Error) { + cfg.Read(&SNDDrvInfo, sizeof(SNDDrvInfo)-sizeof(SNDDrvInfo.VOL2)); + if (! cfg.Error) + Startup::_soundOk = 1; + } + } + */ + warning("STUB: Startup::Startup"); +} + + +const char *usrPath(const char *nam) { + static char buf[MAXPATH] = ".\\", *p = buf + 2; +#if defined(CD) + if (DriveCD(0)) { + bool ok = false; + CFILE ini = Text[CDINI_FNAME]; + if (!ini.Error) { + char *key = Text[GAME_ID]; + int i = strlen(key); + while (ini.Read(buf) && !ok) { + int j = strlen(buf); + if (j) + if (buf[--j] == '\n') + buf[j] = '\0'; + if (scumm_strnicmp((const char *) buf, (const char*) key, i) == 0) + ok = true; + } + if (ok) { + strcpy(buf, buf + i); + p = buf + strlen(buf); + if (*(p - 1) != '\\') + *(p++) = '\\'; + strcpy(p, "NUL"); + if (_dos_open(buf, 0, &i) == 0) + _dos_close(i); + else + ok = false; + } + } + if (!ok) + quit_now(BADCD_TEXT); + } +#endif + strcpy(p, nam); + return buf; +} + +} // End of namespace CGE diff --git a/engines/cge/startup.h b/engines/cge/startup.h new file mode 100644 index 0000000000..cc16f2a123 --- /dev/null +++ b/engines/cge/startup.h @@ -0,0 +1,79 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_STARTUP__ +#define __CGE_STARTUP__ + + +#include "cge/general.h" + +namespace CGE { + +#define GAME_ID 45 +#define CDINI_FNAME 46 + +#define NOT_VGA_TEXT 90 +#define BAD_CHIP_TEXT 91 +#define BAD_DOS_TEXT 92 +#define NO_CORE_TEXT 93 +#define BAD_MIPS_TEXT 94 +#define NO_MOUSE_TEXT 95 +#define BAD_ARG_TEXT 96 +#define BADCD_TEXT 97 + +#define CFG_EXT ".CFG" + +#if defined(DEMO) +#define MINI_EMM_SIZE 0x00004000L +#define CORE_HIG 400 +#else +#define MINI_EMM_SIZE 0x00010000L +#define CORE_HIG 450 +#endif + +#define CORE_MID (CORE_HIG - 20) +#define CORE_LOW (CORE_MID - 20) + + +class Startup { + static bool getParms(); +public: + static int _mode; + static int _core; + static int _soundOk; + static uint16 _summa; + Startup(); +}; + + +extern Emm _miniEmm; + +const char *usrPath(const char *nam); + +} // End of namespace CGE + +#endif diff --git a/engines/cge/talk.cpp b/engines/cge/talk.cpp new file mode 100644 index 0000000000..7c0f9563a6 --- /dev/null +++ b/engines/cge/talk.cpp @@ -0,0 +1,336 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/general.h" +#include "cge/talk.h" +#include "cge/vol.h" +#include "cge/game.h" +#include "cge/events.h" + +namespace CGE { + +#define WID_SIZ 256 +#define POS_SIZ 256 +#define MAP_SIZ (256*8) + +//uint8 FONT::Wid[WID_SIZ]; +//uint16 FONT::Pos[POS_SIZ]; +//uint8 FONT::Map[MAP_SIZ]; + + +Font::Font(const char *name) { + _map = farnew(uint8, MAP_SIZ); + _pos = farnew(uint16, POS_SIZ); + _wid = farnew(uint8, WID_SIZ); + if ((_map == NULL) || (_pos == NULL) || (_wid == NULL)) + error("No core"); + mergeExt(_path, name, FONT_EXT); + load(); +} + + +Font::~Font() { + free(_map); + free(_pos); + free(_wid); +} + + +void Font::load() { + INI_FILE f(_path); + if (!f._error) { + f.read(_wid, WID_SIZ); + if (!f._error) { + uint16 i, p = 0; + for (i = 0; i < POS_SIZ; i++) { + _pos[i] = p; + p += _wid[i]; + } + f.read(_map, p); + } + } +} + + +uint16 Font::width(const char *text) { + uint16 w = 0; + if (text) + while (* text) + w += _wid[(unsigned char)*(text++)]; + return w; +} + + +/* +void Font::save() { + CFILE f((const char *) _path, WRI); + if (!f._error) { + f.Write(_wid, WID_SIZ); + if (!f._error) + f.Write(_map, _pos[POS_SIZ - 1] + _wid[WID_SIZ - 1]); + } +} +*/ + + +Talk::Talk(CGEEngine *vm, const char *tx, TBOX_STYLE mode) + : Sprite(vm, NULL), _mode(mode), _vm(vm) { + _ts[0] = _ts[1] = NULL; + _flags._syst = true; + update(tx); +} + + +Talk::Talk(CGEEngine *vm) + : Sprite(vm, NULL), _mode(PURE), _vm(vm) { + _ts[0] = _ts[1] = NULL; + _flags._syst = true; +} + + +/* +Talk::~Talk() { + for (uint16 i = 0; i < ShpCnt; i++) { + if (FP_SEG(_shpList[i]) != _DS) { // small model: always false + delete _shpList[i]; + ShpList[i] = NULL; + } + } +} +*/ + +Font *Talk::_font; + +void Talk::init() { + _font = new Font(progName()); +} + +void Talk::deinit() { + delete _font; +} + + +void Talk::update(const char *tx) { + uint16 vmarg = (_mode) ? TEXT_VM : 0; + uint16 hmarg = (_mode) ? TEXT_HM : 0; + uint16 mw = 0, mh, ln = vmarg; + const char *p; + uint8 *m; + + if (!_ts[0]) { + uint16 k = 2 * hmarg; + mh = 2 * vmarg + FONT_HIG; + for (p = tx; *p; p++) { + if (*p == '|' || *p == '\n') { + mh += FONT_HIG + TEXT_LS; + if (k > mw) + mw = k; + k = 2 * hmarg; + } else + k += _font->_wid[(unsigned char)*p]; + } + if (k > mw) + mw = k; + _ts[0] = box(mw, mh); + } + + m = _ts[0]->_m + ln * mw + hmarg; + + while (* tx) { + if (*tx == '|' || *tx == '\n') + m = _ts[0]->_m + (ln += FONT_HIG + TEXT_LS) * mw + hmarg; + else { + int cw = _font->_wid[(unsigned char)*tx], i; + uint8 *f = _font->_map + _font->_pos[(unsigned char)*tx]; + for (i = 0; i < cw; i++) { + uint8 *pp = m; + uint16 n; + register uint16 b = *(f++); + for (n = 0; n < FONT_HIG; n++) { + if (b & 1) + *pp = TEXT_FG; + b >>= 1; + pp += mw; + } + m++; + } + } + tx++; + } + _ts[0]->code(); + setShapeList(_ts); +} + + + + +Bitmap *Talk::box(uint16 w, uint16 h) { + uint8 *b, * p, * q; + uint16 n, r = (_mode == ROUND) ? TEXT_RD : 0; + + if (w < 8) + w = 8; + if (h < 8) + h = 8; + b = farnew(uint8, n = w * h); + if (! b) + error("No core"); + memset(b, TEXT_BG, n); + + if (_mode) { + p = b; + q = b + n - w; + memset(p, LGRAY, w); + memset(q, DGRAY, w); + while (p < q) { + p += w; + *(p - 1) = DGRAY; + *p = LGRAY; + } + p = b; + for (int i = 0; i < r; i++) { + int j; + for (j = 0; j < r - i; j++) { + p[j] = TRANS; + p[w - j - 1] = TRANS; + q[j] = TRANS; + q[w - j - 1] = TRANS; + } + p[j] = LGRAY; + p[w - j - 1] = DGRAY; + q[j] = LGRAY; + q[w - j - 1] = DGRAY; + p += w; + q -= w; + } + } + return new Bitmap(w, h, b); +} + + +void Talk::putLine(int line, const char *text) { +// Note: (TS[0].W % 4) have to be 0 + uint16 w = _ts[0]->_w; + uint16 h = _ts[0]->_h; + uint8 *v = _ts[0]->_v, * p; + uint16 dsiz = w >> 2; // data size (1 plane line size) + uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap + uint16 psiz = h * lsiz; // - last gap, but + plane trailer + uint16 size = 4 * psiz; // whole map size + uint16 rsiz = FONT_HIG * lsiz; // length of whole text row map + + // set desired line pointer + v += (TEXT_VM + (FONT_HIG + TEXT_LS) * line) * lsiz; + + // clear whole rectangle + p = v; // assume blanked line above text + memcpy(p, p - lsiz, rsiz); + p += psiz; // tricky replicate lines for plane 0 + memcpy(p, p - lsiz, rsiz); + p += psiz; // same for plane 1 + memcpy(p, p - lsiz, rsiz); + p += psiz; // same for plane 2 + memcpy(p, p - lsiz, rsiz); // same for plane 3 + + // paint text line + if (text) { + uint8 *q; + p = v + 2 + TEXT_HM / 4 + (TEXT_HM % 4) * psiz; + q = v + size; + + while (* text) { + uint16 cw = _font->_wid[(unsigned char)*text], i; + uint8 *fp = _font->_map + _font->_pos[(unsigned char)*text]; + + for (i = 0; i < cw; i++) { + register uint16 b = fp[i]; + uint16 n; + for (n = 0; n < FONT_HIG; n++) { + if (b & 1) + *p = TEXT_FG; + b >>= 1; + p += lsiz; + } + p = p - rsiz + psiz; + if (p >= q) + p = p - size + 1; + } + text++; + } + } +} + + +InfoLine::InfoLine(CGEEngine *vm, uint16 w) : Talk(vm), _oldTxt(NULL), _vm(vm) { + _ts[0] = new Bitmap(w, FONT_HIG, TEXT_BG); + setShapeList(_ts); +} + + +void InfoLine::update(const char *tx) { + if (tx != _oldTxt) { + uint16 w = _ts[0]->_w; + uint16 h = _ts[0]->_h; + uint8 *v = (uint8 *) _ts[0]->_v; + uint16 dsiz = w >> 2; // data size (1 plane line size) + uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap + uint16 psiz = h * lsiz; // - last gape, but + plane trailer + uint16 size = 4 * psiz; // whole map size + + // clear whole rectangle + memset(v + 2, TEXT_BG, dsiz); // data bytes + memcpy(v + lsiz, v, psiz - lsiz); // tricky replicate lines + *(uint16 *)(v + psiz - 2) = EOI; // plane trailer uint16 + memcpy(v + psiz, v, 3 * psiz); // tricky replicate planes + + // paint text line + if (tx) { + uint8 *p = v + 2, * q = p + size; + + while (*tx) { + uint16 cw = _font->_wid[(unsigned char)*tx]; + uint8 *fp = _font->_map + _font->_pos[(unsigned char)*tx]; + + for (uint16 i = 0; i < cw; i++) { + register uint16 b = fp[i]; + for (uint16 n = 0; n < FONT_HIG; n++) { + if (b & 1) + *p = TEXT_FG; + b >>= 1; + p += lsiz; + } + if (p >= q) + p = p - size + 1; + } + tx++; + } + } + _oldTxt = tx; + } +} + +} // End of namespace CGE diff --git a/engines/cge/talk.h b/engines/cge/talk.h new file mode 100644 index 0000000000..2f70471359 --- /dev/null +++ b/engines/cge/talk.h @@ -0,0 +1,104 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_TALK__ +#define __CGE_TALK__ + +#include "cge/vga13h.h" +#include "cge/general.h" +#include "cge/jbw.h" + +namespace CGE { + +#define TEXT_FG DARK // foreground color +#define TEXT_BG GRAY // background color +#define TEXT_HM (6&~1) // EVEN horizontal margins! +#define TEXT_VM 5 // vertical margins +#define TEXT_LS 2 // line spacing +#define TEXT_RD 3 // rounded corners + +#define FONT_HIG 8 +#define FONT_EXT ".CFT" + + + +#define MAXPATH 128 + +class Font { + char _path[MAXPATH]; + void load(); +public: +// static uint8 _wid[256]; +// static uint16 _pos[256]; +// static uint8 _map[256*8]; + uint8 *_wid; + uint16 *_pos; + uint8 *_map; + Font(const char *name); + ~Font(); + uint16 width(const char *text); + void save(); +}; + + +enum TBOX_STYLE { PURE, RECT, ROUND }; + + +class Talk : public Sprite { +protected: + TBOX_STYLE _mode; + Bitmap *_ts[2]; + Bitmap *box(uint16 w, uint16 h); +public: + Talk(CGEEngine *vm, const char *tx, TBOX_STYLE mode); + Talk(CGEEngine *vm); + //~TALK(); + + static Font *_font; + static void init(); + static void deinit(); + + virtual void update(const char *tx); + virtual void update() {} + void putLine(int line, const char *text); +private: + CGEEngine *_vm; +}; + + +class InfoLine : public Talk { + const char *_oldTxt; +public: + InfoLine(CGEEngine *vm, uint16 wid); + void update(const char *tx); +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/text.cpp b/engines/cge/text.cpp new file mode 100644 index 0000000000..5f370150ca --- /dev/null +++ b/engines/cge/text.cpp @@ -0,0 +1,256 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/general.h" +#include "cge/text.h" +#include "cge/talk.h" +#include "cge/vol.h" +#include "cge/bitmaps.h" +#include "cge/game.h" +#include "cge/snail.h" +#include "cge/cge_main.h" + +namespace CGE { + +Text *_text; +Talk *_talk = NULL; + +Text::Text(CGEEngine *vm, const char *fname, int size) : _vm(vm) { + _cache = new Han[size]; + mergeExt(_fileName, fname, SAY_EXT); + if (!INI_FILE::exist(_fileName)) + error("No talk (%s)\n", _fileName); + + for (_size = 0; _size < size; _size++) { + _cache[_size]._ref = 0; + _cache[_size]._txt = NULL; + } +} + + +Text::~Text() { + clear(); + delete[] _cache; +} + + +void Text::clear(int from, int upto) { + Han *p, * q; + for (p = _cache, q = p + _size; p < q; p++) { + if (p->_ref && p->_ref >= from && p->_ref < upto) { + p->_ref = 0; + delete[] p->_txt; + p->_txt = NULL; + } + } +} + + +int Text::find(int ref) { + Han *p, * q; + int i = 0; + for (p = _cache, q = p + _size; p < q; p++) { + if (p->_ref == ref) + break; + else + i++; + } + return i; +} + + +void Text::preload(int from, int upto) { + INI_FILE tf = _fileName; + if (!tf._error) { + Han *CacheLim = _cache + _size; + char line[LINE_MAX + 1]; + int n; + + while ((n = tf.read((uint8 *)line)) != 0) { + char *s; + int ref; + + if (line[n - 1] == '\n') + line[-- n] = '\0'; + if ((s = strtok(line, " =,;/\t\n")) == NULL) + continue; + if (! IsDigit(*s)) + continue; + ref = atoi(s); + if (ref && ref >= from && ref < upto) { + Han *p; + + p = &_cache[find(ref)]; + if (p < CacheLim) { + delete[] p->_txt; + p->_txt = NULL; + } else + p = &_cache[find(0)]; + if (p >= CacheLim) + break; + s += strlen(s); + if (s < line + n) + ++s; + if ((p->_txt = new char[strlen(s) + 1]) == NULL) + break; + p->_ref = ref; + strcpy(p->_txt, s); + } + } + } +} + + +char *Text::load(int idx, int ref) { + INI_FILE tf = _fileName; + if (!tf._error) { + Han *p = &_cache[idx]; + char line[LINE_MAX + 1]; + int n; + + while ((n = tf.read((uint8 *)line)) != 0) { + char *s; + + if (line[n - 1] == '\n') + line[-- n] = '\0'; + if ((s = strtok(line, " =,;/\t\n")) == NULL) + continue; + if (! IsDigit(*s)) + continue; + + int r = atoi(s); + if (r < ref) + continue; + if (r > ref) + break; + // (r == ref) + s += strlen(s); + if (s < line + n) + ++s; + p->_ref = ref; + if ((p->_txt = new char[strlen(s) + 1]) == NULL) + return NULL; + return strcpy(p->_txt, s); + } + } + return NULL; +} + + +char *Text::getText(int ref) { + int i; + if ((i = find(ref)) < _size) + return _cache[i]._txt; + + if ((i = find(0)) >= _size) { + clear(SYSTXT_MAX); // clear non-system + if ((i = find(0)) >= _size) { + clear(); // clear all + i = 0; + } + } + return load(i, ref); +} + + +void Text::say(const char *txt, Sprite *spr) { + killText(); + _talk = new Talk(_vm, txt, ROUND); + if (_talk) { + bool east = spr->_flags._east; + int x = (east) ? (spr->_x + spr->_w - 2) : (spr->_x + 2); + int y = spr->_y + 2; + Sprite *spike = new Sprite(_vm, SP); + uint16 sw = spike->_w; + + if (east) { + if (x + sw + TEXT_RD + 5 >= SCR_WID) + east = false; + } else { + if (x <= 5 + TEXT_RD + sw) + east = true; + } + x = (east) ? (spr->_x + spr->_w - 2) : (spr->_x + 2 - sw); + if (spr->_ref == 1) + x += ((east) ? -10 : 10); // Hero + + _talk->_flags._kill = true; + _talk->_flags._bDel = true; + _talk->setName(_text->getText(SAY_NAME)); + _talk->gotoxy(x - (_talk->_w - sw) / 2 - 3 + 6 * east, y - spike->_h - _talk->_h + 1); + _talk->_z = 125; + _talk->_ref = SAY_REF; + + spike->gotoxy(x, _talk->_y + _talk->_h - 1); + spike->_z = 126; + spike->_flags._slav = true; + spike->_flags._kill = true; + spike->setName(_text->getText(SAY_NAME)); + spike->step(east); + spike->_ref = SAY_REF; + + _vga->_showQ->insert(_talk, _vga->_showQ->last()); + _vga->_showQ->insert(spike, _vga->_showQ->last()); + } +} + +void CGEEngine::inf(const char *txt) { + killText(); + _talk = new Talk(this, txt, RECT); + if (_talk) { + _talk->_flags._kill = true; + _talk->_flags._bDel = true; + _talk->setName(_text->getText(INF_NAME)); + _talk->center(); + _talk->gotoxy(_talk->_x, _talk->_y - 20); + _talk->_z = 126; + _talk->_ref = INF_REF; + _vga->_showQ->insert(_talk, _vga->_showQ->last()); + } +} + + +void sayTime(Sprite *spr) { + /* + static char t[] = "00:00"; + struct time ti; + gettime(&ti); + wtom(ti.ti_hour, t+0, 10, 2); + wtom(ti.ti_min, t+3, 10, 2); + Say((*t == '0') ? (t+1) : t, spr); + */ + warning("STUB: sayTime"); +} + +void killText() { + if (_talk) { + SNPOST_(SNKILL, -1, 0, _talk); + _talk = NULL; + } +} + +} // End of namespace CGE diff --git a/engines/cge/text.h b/engines/cge/text.h new file mode 100644 index 0000000000..cf917ece61 --- /dev/null +++ b/engines/cge/text.h @@ -0,0 +1,84 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_TEXT__ +#define __CGE_TEXT__ + +#include "cge/talk.h" +#include "cge/jbw.h" + +namespace CGE { + +#ifndef SYSTXT_MAX +#define SYSTXT_MAX 1000 +#endif + +#define SAY_EXT ".SAY" + +#define NOT_VGA_TEXT 90 +#define BAD_CHIP_TEXT 91 +#define BAD_DOS_TEXT 92 +#define NO_CORE_TEXT 93 +#define BAD_MIPS_TEXT 94 +#define NO_MOUSE_TEXT 95 +#define INF_NAME 101 +#define SAY_NAME 102 +#define INF_REF 301 +#define SAY_REF 302 + + +class Text { + struct Han { + int _ref; + char *_txt; + } *_cache; + int _size; + char _fileName[MAXPATH]; + char *load(int idx, int ref); + int find(int ref); +public: + Text(CGEEngine *vm, const char *fname, int size); + ~Text(); + void clear(int from = 1, int upto = 0x7FFF); + void preload(int from = 1, int upto = 0x7FFF); + char *getText(int ref); + void say(const char *txt, Sprite *spr); +private: + CGEEngine *_vm; +}; + +extern Talk *_talk; +extern Text *_text; + +void say(const char *txt, Sprite *spr); +void sayTime(Sprite *spr); +void inf(const char *txt); +void killText(); + +} // End of namespace CGE + +#endif diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp new file mode 100644 index 0000000000..36ac060111 --- /dev/null +++ b/engines/cge/vga13h.cpp @@ -0,0 +1,1363 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "common/rect.h" +#include "graphics/palette.h" +#include "cge/general.h" +#include "cge/vga13h.h" +#include "cge/bitmap.h" +#include "cge/vol.h" +#include "cge/text.h" +#include "cge/cge_main.h" +#include "cge/cge.h" + +namespace CGE { + +#define FADE_STEP 2 +#define TMR_DIV ((0x8000/TMR_RATE)*2) +#define NREP 9 +#define FREP 24 + +static VgaRegBlk VideoMode[] = { + { 0x04, VGASEQ, 0x08, 0x04 }, // memory mode + { 0x03, VGAGRA, 0xFF, 0x00 }, // data rotate = 0 + { 0x05, VGAGRA, 0x03, 0x00 }, // R/W mode = 0 + { 0x06, VGAGRA, 0x02, 0x00 }, // misc + { 0x14, VGACRT, 0x40, 0x00 }, // underline + { 0x13, VGACRT, 0xFF, 0x28 }, // screen width + { 0x17, VGACRT, 0xFF, 0xC3 }, // mode control + { 0x11, VGACRT, 0x80, 0x00 }, // vert retrace end + { 0x09, VGACRT, 0xEF, 0x01 }, // max scan line + { 0x30, VGAATR, 0x00, 0x20 }, // 256 color mode +// { 0x12, VGACRT, 0xFF, 0x6E }, // vert display end +// { 0x15, VGACRT, 0xFF, 0x7F }, // start vb +// { 0x10, VGACRT, 0xFF, 0x94 }, // start vr + { 0x00, 0x00, 0x00, 0x00 } +}; + +bool SpeedTest = false; +Seq _seq1[] = { { 0, 0, 0, 0, 0 } }; +Seq _seq2[] = { { 0, 1, 0, 0, 0 }, { 1, 0, 0, 0, 0 } }; + +extern "C" void SNDMIDIPlay(); + +/* +static void Video() { + static uint16 SP_S; + + asm push bx + asm push bp + asm push si + asm push di + asm push es + asm xor bx,bx // video page #0 + SP_S = _SP; + asm int VIDEO + _SP = SP_S; + asm pop es + asm pop di + asm pop si + asm pop bp + asm pop bx +} +*/ + + +uint16 *SaveScreen() { + /* + uint16 cxy, cur, siz, * scr = NULL, * sav; + + // horizontal size of text mode screen + asm mov ah,0x0F // get current video mode + Video(); // BIOS video service + asm xchg ah,al // answer in ah + asm push ax // preserve width + + // vertical size of text mode screen + asm mov dl,24 // last row on std screen + asm xor bx,bx // valid request in BH + asm mov ax,0x1130 // get EGA's last row # + Video(); // BIOS video service + asm inc dl // # of rows = last+1 + + // compute screen size in words + asm pop ax // restore width + asm mul dl // width * height + + siz = _AX; + + asm mov ax,0x40 // system data segment + asm mov es,ax + asm mov ax,0B000H // Mono + asm cmp byte ptr es:[0x49],0x07 + asm je sto + asm mov ax,0B800H // Color + sto: // store screen address + asm mov word ptr scr+2,ax + + _AH = 0x0F; Video(); // active page + + // take cursor shape + _AH = 0x03; Video(); // get cursor size + cur = _CX; + + // take cursor position + _DH = 0; + _AH = 0x03; Video(); // get cursor + cxy = _DX; + + sav = farnew(uint16, siz+3); // +3 extra uint16s for size and cursor + if (sav) + { + sav[0] = siz; + sav[1] = cur; + sav[2] = cxy; + memcpy(sav+3, scr, siz * 2); + } + return sav; + */ + warning("STUB: SaveScreen"); + return 0; +} + + +void RestoreScreen(uint16 * &sav) { + /* + uint16 * scr = NULL; + + asm mov ax,0x40 // system data segment + asm mov es,ax + asm mov ax,0B000H // Mono + asm cmp byte ptr es:[0x49],0x07 + asm je sto + asm mov ax,0B800H // Color + sto: // store screen address + asm mov word ptr scr+2,ax + + memcpy(scr, sav+3, sav[0] * 2); + + _AH = 0x0F; Video(); // active page + + // set cursor shape + _CX = sav[1]; + _AH = 0x01; Video(); // set cursor size + + // set cursor position + _DX = sav[2]; + _AH = 0x02; Video(); // set cursor + + free(sav); + sav = NULL; + */ + warning("STUB: RestoreScreen"); +} + + +Dac mkDac(uint8 r, uint8 g, uint8 b) { + static Dac x; + x._r = r; + x._g = g; + x._b = b; + return x; +} + + +Rgb mkRgb(uint8 r, uint8 g, uint8 b) { + static Trgb x; + x._dac._r = r; + x._dac._g = g; + x._dac._b = b; + return x._rgb; +} + + +Sprite *locate(int ref) { + Sprite *spr = _vga->_showQ->locate(ref); + return (spr) ? spr : _vga->_spareQ->locate(ref); +} + + +Heart::Heart() + : Engine_(TMR_DIV) { + _enable = false; + _xTimer = NULL; +} + + +/* +extern "C" void TimerProc() { + static SPRITE * spr; + static uint8 run = 0; + + // decrement external timer uint16 + if (_heart->_xTimer) { + if (*_heart->_xTimer) + *_heart->_xTimer--; + else + _heart->_xTimer = NULL; + } + + if (!run && _heart->_enable) { // check overrun flag + static uint16 oldSP, oldSS; + run++; // disable 2nd call until current lasts + asm mov ax,ds + asm mov oldSS,ss + asm mov oldSP,sp + asm mov ss,ax + asm mov sp,0xFF80 + + // system pseudo-sprite + if (Sys) { + if (Sys->Time) { + if (--Sys->Time == 0) + Sys->Tick(); + } + } + for (spr = VGA::ShowQ.First(); spr; spr = spr->Next) { + if (spr->Time) { + if (!spr->_flags.Hide) { + if (-- spr->Time == 0) + spr->Tick(); + } + } + } + asm mov ss,oldSS + asm mov sp,oldSP + run--; + } +} +*/ + + +void Engine_::newTimer(...) { + /* + static SPRITE *spr; + static uint8 run = 0, cntr1 = TMR_RATE1, cntr2 = TMR_RATE2; + ___1152_Hz___: + + SNDMIDIPlay(); + asm dec cntr1 + asm jz ___72_Hz___ + asm mov al,0x20 // send... + asm out 0x020,al // ...e-o-i + return; + + ___72_Hz___: + + asm mov cntr1,TMR_RATE1 + asm dec cntr2 + asm jnz my_eoi + + ___18_Hz___: + + OldTimer(); + asm mov cntr2,TMR_RATE2 + asm jmp short my_int + + // send E-O-I + my_eoi: + asm mov al,0x20 + asm out 0x020,al + asm sti // enable interrupts + + my_int: //------72Hz-------// + + // decrement external timer uint16 + if (_heart->XTimer) { + if (*_heart->XTimer) + *_heart->XTimer--; + else + _heart->XTimer = NULL; + } + + if (! run && _heart->Enable) { // check overrun flag + static uint16 oldSP, oldSS; + + run++; // disable 2nd call until current lasts + asm mov ax,ds + asm mov oldSS,ss + asm mov oldSP,sp + asm mov ss,ax + asm mov sp,0xFF80 + + // system pseudo-sprite + if (Sys) { + if (Sys->Time) { + if (--Sys->Time == 0) + Sys->Tick(); + } + } + + for (spr = VGA::ShowQ.First(); spr; spr = spr->Next) { + if (spr->Time) { + if (!spr->_flags.Hide) { + if (--spr->Time == 0) + spr->Tick(); + } + } + } + asm mov ss,oldSS + asm mov sp,oldSP + run--; + } + + */ + warning("STUB: Engine_::NewTimer"); +} + + +void Heart::setXTimer(uint16 *ptr) { + if (_xTimer && ptr != _xTimer) + *_xTimer = 0; + _xTimer = ptr; +} + + +void Heart::setXTimer(uint16 *ptr, uint16 time) { + setXTimer(ptr); + *ptr = time; +} + + +Sprite::Sprite(CGEEngine *vm, BMP_PTR *shpP) + : _x(0), _y(0), _z(0), _nearPtr(0), _takePtr(0), + _next(NULL), _prev(NULL), _seqPtr(NO_SEQ), _time(0), //Delay(0), + _ext(NULL), _ref(-1), _cave(0), _vm(vm) { + memset(_file, 0, sizeof(_file)); + *((uint16 *)&_flags) = 0; + _ref = 0; + _x = _y = 0; + _w = _h = 0; + _time = 0; + _seqPtr = 0; + _shpCnt = 0; + _prev = _next = NULL; + + setShapeList(shpP); +} + + +Sprite::~Sprite() { + if (_sprite == this) + _sprite = NULL; + contract(); +} + + +BMP_PTR Sprite::shp() { + register SprExt *e = _ext; + if (e) + if (e->_seq) { + int i = e->_seq[_seqPtr]._now; + if (i >= _shpCnt) { + //char s[256]; + //sprintf(s, "Seq=%p ShpCnt=%d SeqPtr=%d Now=%d Next=%d", + // Seq, ShpCnt, SeqPtr, Seq[SeqPtr].Now, Seq[SeqPtr].Next); + //VGA::Exit(s, File); + error("Invalid PHASE in SPRITE::Shp() %s", _file); + } + return e->_shpList[i]; + } + return NULL; +} + + +BMP_PTR *Sprite::setShapeList(BMP_PTR *shpP) { + BMP_PTR *r = (_ext) ? _ext->_shpList : NULL; + + _shpCnt = 0; + _w = 0; + _h = 0; + + if (shpP) { + BMP_PTR *p; + for (p = shpP; *p; p++) { + BMP_PTR b = (*p); // ->Code(); + if (b->_w > _w) + _w = b->_w; + if (b->_h > _h) + _h = b->_h; + _shpCnt++; + } + expand(); + _ext->_shpList = shpP; + if (!_ext->_seq) + setSeq((_shpCnt < 2) ? _seq1 : _seq2); + } + return r; +} + + +void Sprite::moveShapes(uint8 *buf) { + BMP_PTR *p; + for (p = _ext->_shpList; *p; p++) { + buf += (*p)->moveVmap(buf); + } +} + + +bool Sprite::works(Sprite *spr) { + if (spr) + if (spr->_ext) { + Snail::Com *c = spr->_ext->_take; + if (c != NULL) { + c += spr->_takePtr; + if (c->_ref == _ref) + if (c->_com != SNLABEL || (c->_val == 0 || c->_val == _vm->_now)) + return true; + } + } + return false; +} + + +Seq *Sprite::setSeq(Seq *seq) { + expand(); + register Seq *s = _ext->_seq; + _ext->_seq = seq; + if (_seqPtr == NO_SEQ) + step(0); + else if (_time == 0) + step(_seqPtr); + return s; +} + + +bool Sprite::seqTest(int n) { + if (n >= 0) + return (_seqPtr == n); + if (_ext) + return (_ext->_seq[_seqPtr]._next == _seqPtr); + return true; +} + + +Snail::Com *Sprite::snList(SNLIST type) { + register SprExt *e = _ext; + if (e) + return (type == NEAR) ? e->_near : e->_take; + return NULL; +} + + +void Sprite::setName(char *n) { + if (_ext) { + if (_ext->_name) { + delete[] _ext->_name; + _ext->_name = NULL; + } + if (n) { + if ((_ext->_name = new char[strlen(n) + 1]) != NULL) + strcpy(_ext->_name, n); + else + error("No core [%s]", n); + } + } +} + + +Sprite *Sprite::expand() { + if (!_ext) { + bool enbl = _heart->_enable; + _heart->_enable = false; + if ((_ext = new SprExt) == NULL) + error("No core"); + if (*_file) { + static const char *Comd[] = { "Name", "Phase", "Seq", "Near", "Take", NULL }; + char line[LINE_MAX], fname[MAXPATH]; + BMP_PTR *shplist = new BMP_PTR[_shpCnt + 1]; + Seq *seq = NULL; + int shpcnt = 0, + seqcnt = 0, + neacnt = 0, + takcnt = 0, + maxnow = 0, + maxnxt = 0; + + Snail::Com *nea = NULL; + Snail::Com *tak = NULL; + mergeExt(fname, _file, SPR_EXT); + if (INI_FILE::exist(fname)) { // sprite description file exist + INI_FILE sprf(fname); + if (!(sprf._error==0)) + error("Bad SPR [%s]", fname); + int len = 0, lcnt = 0; + while ((len = sprf.read((uint8 *)line)) != 0) { + ++lcnt; + if (len && line[len - 1] == '\n') + line[-- len] = '\0'; + if (len == 0 || *line == '.') + continue; + + switch (takeEnum(Comd, strtok(line, " =\t"))) { + case 0 : { // Name + setName(strtok(NULL, "")); + break; + } + case 1 : { // Phase + shplist[shpcnt++] = new Bitmap(strtok(NULL, " \t,;/"), true); + break; + } + case 2 : { // Seq + seq = (Seq *) realloc(seq, (seqcnt + 1) * sizeof(*seq)); + if (seq == NULL) + error("No core [%s]", fname); + Seq *s = &seq[seqcnt++]; + s->_now = atoi(strtok(NULL, " \t,;/")); + if (s->_now > maxnow) + maxnow = s->_now; + s->_next = atoi(strtok(NULL, " \t,;/")); + switch (s->_next) { + case 0xFF : + s->_next = seqcnt; + break; + case 0xFE : + s->_next = seqcnt - 1; + break; + } + if (s->_next > maxnxt) + maxnxt = s->_next; + s->_dx = atoi(strtok(NULL, " \t,;/")); + s->_dy = atoi(strtok(NULL, " \t,;/")); + s->_dly = atoi(strtok(NULL, " \t,;/")); + break; + } + case 3 : { // Near + if (_nearPtr != NO_PTR) { + nea = (Snail::Com *) realloc(nea, (neacnt + 1) * sizeof(*nea)); + if (nea == NULL) + error("No core [%s]", fname); + else { + Snail::Com *c = &nea[neacnt++]; + if ((c->_com = (SNCOM)takeEnum(Snail::_comTxt, strtok(NULL, " \t,;/"))) < 0) + error("Bad NEAR in %d [%s]", lcnt, fname); + c->_ref = atoi(strtok(NULL, " \t,;/")); + c->_val = atoi(strtok(NULL, " \t,;/")); + c->_ptr = NULL; + } + } + } + break; + case 4 : { // Take + if (_takePtr != NO_PTR) { + tak = (Snail::Com *) realloc(tak, (takcnt + 1) * sizeof(*tak)); + if (tak == NULL) + error("No core [%s]", fname); + else { + Snail::Com *c = &tak[takcnt++]; + if ((c->_com = (SNCOM)takeEnum(Snail::_comTxt, strtok(NULL, " \t,;/"))) < 0) + error("Bad NEAR in %d [%s]", lcnt, fname); + c->_ref = atoi(strtok(NULL, " \t,;/")); + c->_val = atoi(strtok(NULL, " \t,;/")); + c->_ptr = NULL; + } + } + break; + } + } + } + } else { // no sprite description: try to read immediately from .BMP + shplist[shpcnt++] = new Bitmap(_file, true); + } + shplist[shpcnt] = NULL; + if (seq) { + if (maxnow >= shpcnt) + error("Bad PHASE in SEQ [%s]", fname); + if (maxnxt >= seqcnt) + error("Bad JUMP in SEQ [%s]", fname); + setSeq(seq); + } else + setSeq((_shpCnt == 1) ? _seq1 : _seq2); + //disable(); // disable interupt + + setShapeList(shplist); + //enable(); // enable interupt + if (nea) + nea[neacnt - 1]._ptr = _ext->_near = nea; + else + _nearPtr = NO_PTR; + if (tak) + tak[takcnt - 1]._ptr = _ext->_take = tak; + else + _takePtr = NO_PTR; + } + _heart->_enable = enbl; + } + return this; +} + + +Sprite *Sprite::contract() { + register SprExt *e = _ext; + if (e) { + if (e->_name) + delete[] e->_name; + if (_flags._bDel && e->_shpList) { + int i; + for (i = 0; e->_shpList[i]; i++) + delete e->_shpList[i]; + if (memType(e->_shpList) == NEAR_MEM) + delete[] e->_shpList; + } + if (memType(e->_seq) == NEAR_MEM) + free(e->_seq); + if (e->_near) + free(e->_near); + if (e->_take) + free(e->_take); + delete e; + _ext = NULL; + } + return this; +} + + +Sprite *Sprite::backShow(bool fast) { + expand(); + show(2); + show(1); + if (fast) + show(0); + contract(); + return this; +} + + +void Sprite::step(int nr) { + if (nr >= 0) + _seqPtr = nr; + if (_ext) { + Seq *seq; + if (nr < 0) + _seqPtr = _ext->_seq[_seqPtr]._next; + seq = _ext->_seq + _seqPtr; + if (seq->_dly >= 0) { + gotoxy(_x + (seq->_dx), _y + (seq->_dy)); + _time = seq->_dly; + } + } +} + + +void Sprite::tick() { + step(); +} + + +void Sprite::makeXlat(uint8 *x) { + if (_ext) { + BMP_PTR *b; + + if (_flags._xlat) + killXlat(); + for (b = _ext->_shpList; *b; b++) + (*b)->_m = x; + _flags._xlat = true; + } +} + + +void Sprite::killXlat() { + if (_flags._xlat && _ext) { + BMP_PTR *b; + uint8 *m = (*_ext->_shpList)->_m; + + switch (memType(m)) { + case NEAR_MEM : + delete[](uint8 *) m; + break; + case FAR_MEM : + free(m); + break; + default: + warning("Unhandled MemType in Sprite::KillXlat()"); + break; + } + for (b = _ext->_shpList; *b; b++) + (*b)->_m = NULL; + _flags._xlat = false; + } +} + + +void Sprite::gotoxy(int x, int y) { + int xo = _x, yo = _y; + if (_x < SCR_WID) { + if (x < 0) + x = 0; + if (x + _w > SCR_WID) + x = (SCR_WID - _w); + _x = x; + } + if (_h < SCR_HIG) { + if (y < 0) + y = 0; + if (y + _h > SCR_HIG) + y = (SCR_HIG - _h); + _y = y; + } + if (_next) + if (_next->_flags._slav) + _next->gotoxy(_next->_x - xo + _x, _next->_y - yo + _y); + if (_flags._shad) + _prev->gotoxy(_prev->_x - xo + _x, _prev->_y - yo + _y); +} + + +void Sprite::center() { + gotoxy((SCR_WID - _w) / 2, (SCR_HIG - _h) / 2); +} + + +void Sprite::show() { + register SprExt *e; +// asm cli // critic section... + e = _ext; + e->_x0 = e->_x1; + e->_y0 = e->_y1; + e->_b0 = e->_b1; + e->_x1 = _x; + e->_y1 = _y; + e->_b1 = shp(); +// asm sti // ...done! + if (!_flags._hide) { + if (_flags._xlat) + e->_b1->xShow(e->_x1, e->_y1); + else + e->_b1->show(e->_x1, e->_y1); + } +} + + +void Sprite::show(uint16 pg) { + Graphics::Surface *a = Vga::_page[1]; + Vga::_page[1] = Vga::_page[pg & 3]; + shp()->show(_x, _y); + Vga::_page[1] = a; +} + + +void Sprite::hide() { + register SprExt *e = _ext; + if (e->_b0) + e->_b0->hide(e->_x0, e->_y0); +} + + +BMP_PTR Sprite::ghost() { + register SprExt *e = _ext; + if (e->_b1) { + BMP_PTR bmp = new Bitmap(0, 0, (uint8 *)NULL); + if (bmp == NULL) + error("No core"); + bmp->_w = e->_b1->_w; + bmp->_h = e->_b1->_h; + if ((bmp->_b = farnew(HideDesc, bmp->_h)) == NULL) + error("No Core"); + bmp->_v = (uint8 *) memcpy(bmp->_b, e->_b1->_b, sizeof(HideDesc) * bmp->_h); + // TODO offset correctly in the surface using y1 pitch and x1 and not via offset segment + //bmp->_m = (uint8 *) MK_FP(e->y1, e->x1); + warning("FIXME: SPRITE::Ghost"); + return bmp; + } + return NULL; +} + +void Sprite::sync(Common::Serializer &s) { + uint16 unused; + + s.syncAsUint16LE(unused); + s.syncAsUint16LE(unused); // _ext + s.syncAsUint16LE(_ref); + s.syncAsByte(_cave); + s.syncBytes((byte *)&_flags, 2); + s.syncAsUint16LE(_x); + s.syncAsUint16LE(_y); + s.syncAsByte(_z); + s.syncAsUint16LE(_w); + s.syncAsUint16LE(_h); + s.syncAsUint16LE(_time); + s.syncAsByte(_nearPtr); + s.syncAsByte(_takePtr); + s.syncAsSint16LE(_seqPtr); + s.syncAsUint16LE(_shpCnt); + s.syncBytes((byte *)&_file[0], 9); + _file[8] = '\0'; + + s.syncAsUint16LE(unused); // _prev + s.syncAsUint16LE(unused); // _next +} + +Sprite *spriteAt(int x, int y) { + Sprite *spr = NULL, * tail = _vga->_showQ->last(); + if (tail) { + for (spr = tail->_prev; spr; spr = spr->_prev) { + if (! spr->_flags._hide && ! spr->_flags._tran) { + if (spr->shp()->solidAt(x - spr->_x, y - spr->_y)) + break; + } + } + } + return spr; +} + + +Queue::Queue(bool show) : _head(NULL), _tail(NULL), _show(show) { +} + + +Queue::~Queue() { + clear(); +} + + +void Queue::clear() { + while (_head) { + Sprite *s = remove(_head); + if (s->_flags._kill) + delete s; + } +} + + +void Queue::forAll(void (*fun)(Sprite *)) { + Sprite *s = _head; + while (s) { + Sprite *n = s->_next; + fun(s); + s = n; + } +} + + +void Queue::append(Sprite *spr) { + if (_tail) { + spr->_prev = _tail; + _tail->_next = spr; + } else + _head = spr; + _tail = spr; + if (_show) + spr->expand(); + else + spr->contract(); +} + + +void Queue::insert(Sprite *spr, Sprite *nxt) { + if (nxt == _head) { + spr->_next = _head; + _head = spr; + if (!_tail) + _tail = spr; + } else { + spr->_next = nxt; + spr->_prev = nxt->_prev; + if (spr->_prev) + spr->_prev->_next = spr; + } + if (spr->_next) + spr->_next->_prev = spr; + if (_show) + spr->expand(); + else + spr->contract(); +} + + +void Queue::insert(Sprite *spr) { + Sprite *s; + for (s = _head; s; s = s->_next) + if (s->_z > spr->_z) + break; + if (s) + insert(spr, s); + else + append(spr); + if (_show) + spr->expand(); + else + spr->contract(); +} + + +Sprite *Queue::remove(Sprite *spr) { + if (spr == _head) + _head = spr->_next; + if (spr == _tail) + _tail = spr->_prev; + if (spr->_next) + spr->_next->_prev = spr->_prev; + if (spr->_prev) + spr->_prev->_next = spr->_next; + spr->_prev = NULL; + spr->_next = NULL; + return spr; +} + + +Sprite *Queue::locate(int ref) { + Sprite *spr; + for (spr = _head; spr; spr = spr->_next) { + if (spr->_ref == ref) + return spr; + } + return NULL; +} + + +//extern const char Copr[]; +Graphics::Surface *Vga::_page[4]; +Dac *Vga::_sysPal; + +void Vga::init() { + for (int idx = 0; idx < 4; ++idx) { + _page[idx] = new Graphics::Surface(); + _page[idx]->create(320, 200, Graphics::PixelFormat::createFormatCLUT8()); + } + + _sysPal = new Dac[PAL_CNT]; +} + +void Vga::deinit() { + for (int idx = 0; idx < 4; ++idx) { + _page[idx]->free(); + delete _page[idx]; + } + + delete[] _sysPal; +} + +Vga::Vga(int mode) + : _frmCnt(0), _oldMode(0), _oldScreen(NULL), _statAdr(VGAST1_), + _msg(NULL), _nam(NULL), _setPal(false), _mono(0) { + _oldColors = NULL; + _newColors = NULL; + _showQ = new Queue(true); + _spareQ = new Queue(false); + + bool std = true; + int i; + for (i = 10; i < 20; i++) { + char *txt = _text->getText(i); + if (txt) { + debugN("%s", txt); + std = false; + } + } + if (std) +// warning(Copr); + warning("TODO: Fix Copr"); + + setStatAdr(); + if (_statAdr != VGAST1_) + _mono++; + if (isVga()) { + _oldColors = farnew(Dac, 256); + _newColors = farnew(Dac, 256); + _oldScreen = SaveScreen(); + getColors(_oldColors); + sunset(); + _oldMode = setMode(mode); + setColors(); + setup(VideoMode); + clear(0); + } +} + + +Vga::~Vga() { + _mono = 0; + if (isVga()) { + Common::String buffer = ""; +/* + clear(0); + setMode(_oldMode); + setColors(); + restoreScreen(_oldScreen); + sunrise(_oldColors); +*/ + if (_oldColors) + free(_oldColors); + if (_newColors) + free(_newColors); + if (_msg) + buffer = Common::String(_msg); + if (_nam) + buffer = buffer + " [" + _nam + "]"; + + debugN("%s", buffer.c_str()); + } + + delete _showQ; + delete _spareQ; +} + + +void Vga::setStatAdr() { + /* + asm mov dx,VGAMIr_ + asm in al,dx + asm test al,1 // CGA addressing mode flag + asm mov ax,VGAST1_ // CGA addressing + asm jnz set_mode_adr + asm xor al,0x60 // MDA addressing + set_mode_adr: + StatAdr = _AX; + */ + warning("STUB: VGA::setStatADR"); +} + + +#pragma argsused +void Vga::waitVR(bool on) { + // Since some of the game parts rely on using vertical sync as a delay mechanism, + // we're introducing a short delay to simulate it + g_system->delayMillis(10); +} + + +void Vga::setup(VgaRegBlk *vrb) { + /* + waitVR(); // *--LOOK!--* resets VGAATR logic + asm cld + asm mov si, vrb // take address of parameter table + asm mov dh,0x03 // higher byte of I/O address is always 3 + + s: + asm lodsw // take lower byte of I/O address and index + asm or ah,ah // 0 = end of table + asm jz xit // no more: exit + asm or al,al // indexed register? + asm js single // 7th bit set means single register + asm mov dl,ah // complete I/O address + asm out dx,al // put index into control register + asm inc dx // data register is next to control + asm in al,dx // take old data + + write: + asm mov cl,al // preserve old data + asm lodsw // take 2 masks from table + asm xor al,0xFF // invert mask bits + asm and al,cl // clear bits with "clr" mask + asm or al,ah // set bits with "set" mask + asm cmp dl,0xC1 // special case? + asm jne std2 // no: standard job, otherwise... + asm dec dx // data out reg shares address with index + std2: + asm out dx,al // write new value to register + asm jmp s + + single: // read address in al, write address in ah + asm mov dl,al // complete I/O read address + asm in al,dx // take old data + asm mov dl,ah // complete I/O write address + asm jmp write // continue standard routine + + xit: + */ + warning("STUB: VGA::setup"); +} + + +int Vga::setMode(int mode) { + // ScummVM provides it's own vieo services + return 0; +} + + +void Vga::getColors(Dac *tab) { + byte palData[PAL_SIZ]; + g_system->getPaletteManager()->grabPalette(palData, 0, PAL_CNT); + palToDac(palData, tab); +} + +void Vga::palToDac(const byte *palData, Dac *tab) { + const byte *colP = palData; + for (int idx = 0; idx < PAL_CNT; ++idx, colP += 3) { + tab[idx]._r = *colP >> 2; + tab[idx]._g = *(colP + 1) >> 2; + tab[idx]._b = *(colP + 2) >> 2; + } +} + +void Vga::dacToPal(const Dac *tab, byte *palData) { + for (int idx = 0; idx < PAL_CNT; ++idx, palData += 3) { + *palData = tab[idx]._r << 2; + *(palData + 1) = tab[idx]._g << 2; + *(palData + 2) = tab[idx]._b << 2; + } +} + +void Vga::setColors(Dac *tab, int lum) { + Dac *palP = tab, *destP = _newColors; + for (int idx = 0; idx < PAL_CNT; ++idx, ++palP, ++destP) { + destP->_r = (palP->_r * lum) >> 6; + destP->_g = (palP->_g * lum) >> 6; + destP->_b = (palP->_b * lum) >> 6; + } + + if (_mono) { + destP = _newColors; + for (int idx = 0; idx < PAL_CNT; ++idx, ++palP) { + // Form a greyscalce colour from 30% R, 59% G, 11% B + uint8 intensity = (destP->_r * 77) + (destP->_g * 151) + (destP->_b * 28); + destP->_r = intensity; + destP->_g = intensity; + destP->_b = intensity; + } + } + + _setPal = true; +} + + +void Vga::setColors() { + memset(_newColors, 0, PAL_SIZ); + updateColors(); +} + + +void Vga::sunrise(Dac *tab) { + for (int i = 0; i <= 64; i += FADE_STEP) { + setColors(tab, i); + waitVR(true); + updateColors(); + } +} + + +void Vga::sunset() { + Dac tab[256]; + getColors(tab); + for (int i = 64; i >= 0; i -= FADE_STEP) { + setColors(tab, i); + waitVR(true); + updateColors(); + } +} + + +void Vga::show() { + Sprite *spr = _showQ->first(); + + for (spr = _showQ->first(); spr; spr = spr->_next) + spr->show(); + update(); + for (spr = _showQ->first(); spr; spr = spr->_next) + spr->hide(); + + _frmCnt++; +} + + +void Vga::updateColors() { + byte palData[PAL_SIZ]; + dacToPal(_newColors, palData); + g_system->getPaletteManager()->setPalette(palData, 0, 256); +} + + +void Vga::update() { + SWAP(Vga::_page[0], Vga::_page[1]); + + if (_setPal) { + updateColors(); + _setPal = false; + } + + g_system->copyRectToScreen((const byte *)Vga::_page[0]->getBasePtr(0, 0), SCR_WID, 0, 0, SCR_WID, SCR_HIG); + g_system->updateScreen(); +} + + +void Vga::clear(uint8 color) { + for (int paneNum = 0; paneNum < 4; ++paneNum) + _page[paneNum]->fillRect(Common::Rect(0, 0, SCR_WID, SCR_HIG), color); +} + + +void Vga::copyPage(uint16 d, uint16 s) { + _page[d]->copyFrom(*_page[s]); +} + +//-------------------------------------------------------------------------- + +void Bitmap::xShow(int x, int y) { + /* + uint8 rmsk = x % 4, + mask = 1 << rmsk, + *scr = VGA::Page[1] + y * (SCR_WID / 4) + x / 4; + uint8 *m = (char *) M; + uint8 *v = V; + + asm push bx + asm push si + asm push ds + + asm cld + asm les di,scr + asm lds si,v + asm mov bx,m + + asm mov al,0x02 // map mask register + asm mov ah,mask + + plane: + // enable output plane + asm mov dx,VGASEQ_ + asm out dx,ax + asm push ax + + // select input plane + asm mov dx,VGAGRA_ + asm mov al,0x04 // read map select register + asm mov ah,rmsk + asm out dx,ax + + asm push di + + block: + asm lodsw + asm mov cx,ax + asm and ch,0x3F + asm test ah,0xC0 + asm jz endpl + asm jns skip + asm jnp incsi // replicate? + asm add si,cx // skip over data block + asm dec si // fix it before following inc + + incsi: + asm inc si + tint: + asm mov al,es:[di] + //----------------------------------------------- + // asm xlat ss:0 // unsupported with BASM! + __emit__(0x36, 0xD7); // this stands for above! + //----------------------------------------------- + asm stosb + asm loop tint + asm jmp block + + skip: + asm add di,cx + asm jmp block + + endpl: + asm pop di + asm pop ax + asm inc rmsk + asm shl ah,1 + asm test ah,0x10 + asm jz x_chk + asm mov ah,0x01 + asm mov rmsk,0 + asm inc di + x_chk: + asm cmp ah,mask + asm jne plane + asm pop ds + asm pop si + asm pop bx + */ + warning("STUB: BITMAP::xShow"); +} + + +void Bitmap::show(int x, int y) { + const byte *srcP = (const byte *)_v; + byte *destEndP = (byte *)Vga::_page[1]->pixels + (SCR_WID * SCR_HIG); + + // Loop through processing data for each plane. The game originally ran in plane mapped mode, where a + // given plane holds each fourth pixel sequentially. So to handle an entire picture, each plane's data + // must be decompressed and inserted into the surface + for (int planeCtr = 0; planeCtr < 4; ++planeCtr) { + byte *destP = (byte *)Vga::_page[1]->getBasePtr(x + planeCtr, y); + + for (;;) { + uint16 v = READ_LE_UINT16(srcP); + srcP += 2; + int cmd = v >> 14; + int count = v & 0x3FFF; + + if (cmd == 0) { + // End of image + break; + } + + assert(destP < destEndP); + + // Handle a set of pixels + while (count-- > 0) { + // Transfer operation + switch (cmd) { + case 1: + // SKIP + break; + case 2: + // REPEAT + *destP = *srcP; + break; + case 3: + // COPY + *destP = *srcP++; + break; + } + + // Move to next dest position + destP += 4; + } + + if (cmd == 2) + ++srcP; + } + } +/* + DEBUG code to display image immediately + // Temporary + g_system->copyRectToScreen((const byte *)VGA::Page[1]->getBasePtr(0, 0), SCR_WID, 0, 0, SCR_WID, SCR_HIG); + byte palData[PAL_SIZ]; + VGA::DAC2pal(VGA::SysPal, palData); + g_system->getPaletteManager()->setPalette(palData, 0, PAL_CNT); + + g_system->updateScreen(); + g_system->delayMillis(5000); +*/ +} + + +void Bitmap::hide(int x, int y) { + for (int yp = y; yp < y + _h; ++yp) { + const byte *srcP = (const byte *)Vga::_page[2]->getBasePtr(x, yp); + byte *destP = (byte *)Vga::_page[1]->getBasePtr(x, yp); + + Common::copy(srcP, srcP + _w, destP); + } +} + +} // End of namespace CGE diff --git a/engines/cge/vga13h.h b/engines/cge/vga13h.h new file mode 100644 index 0000000000..b0cba4dcc0 --- /dev/null +++ b/engines/cge/vga13h.h @@ -0,0 +1,352 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_VGA13H__ +#define __CGE_VGA13H__ + +#include "common/serializer.h" +#include "graphics/surface.h" +#include "cge/general.h" +#include "cge/bitmap.h" +#include "cge/snail.h" +#include "cge/cge.h" + +namespace CGE { + +#define TMR_RATE1 16 +#define TMR_RATE2 4 +#define TMR_RATE (TMR_RATE1 * TMR_RATE2) + +#define MAX_NAME 20 +#define VIDEO 0x10 + +#define NO_CLEAR 0x80 +#define TEXT_MODE 0x03 +#define M13H 0x13 + +#ifndef SCR_WID +#define SCR_WID 320 +#endif + +#ifndef SCR_HIG +#define SCR_HIG 200 +#endif + + +#if 0 +#define LIGHT 0xFF +#define DARK 0x00 +#define DGRAY 0xF6 +#define GRAY 0xFC +#define LGRAY 0xFF +#else +#define LIGHT 0xFF +#define DARK 207 +#define DGRAY 225 /*219*/ +#define GRAY 231 +#define LGRAY 237 +#endif + +#define NO_SEQ (-1) +#define NO_PTR ((uint8)-1) + +#define SPR_EXT ".SPR" + +#define IsFile(s) (access(s, 0) == 0) +#define IsWrit(s) (access(s, 2) == 0) + + + +struct Rgb { + uint16 _r : 2; + uint16 _R : 6; + uint16 _g : 2; + uint16 _G : 6; + uint16 _b : 2; + uint16 _B : 6; +}; + +typedef union { + Dac _dac; + Rgb _rgb; +} Trgb; + +struct VgaRegBlk { + uint8 _idx; + uint8 _adr; + uint8 _clr; + uint8 _set; +}; + +struct Seq { + uint8 _now; + uint8 _next; + int8 _dx; + int8 _dy; + int _dly; +}; + +extern Seq _seq1[]; +extern Seq _seq2[]; +//extern SEQ * Compass[]; +//extern SEQ TurnToS[]; + +#define PAL_CNT 256 +#define PAL_SIZ (PAL_CNT * 3) +#define VGAATR_ 0x3C0 +#define VGAMIw_ 0x3C0 +#define VGASEQ_ 0x3C4 +#define VGAMIr_ 0x3CC +#define VGAGRA_ 0x3CE +#define VGACRT_ 0x3D4 +#define VGAST1_ 0x3DA +#define VGAATR (VGAATR_ & 0xFF) +#define VGAMIw (VGAMIw_ & 0xFF) +#define VGASEQ (VGASEQ_ & 0xFF) +#define VGAMIr (VGAMIr_ & 0xFF) +#define VGAGRA (VGAGRA_ & 0xFF) +#define VGACRT (VGACRT_ & 0xFF) +#define VGAST1 (VGAST1_ & 0xFF) + + +class Heart : public Engine_ { + friend class Engine_; +public: + Heart(); + + bool _enable; + uint16 *_xTimer; + + void setXTimer(uint16 *ptr); + void setXTimer(uint16 *ptr, uint16 time); +}; + + +class SprExt { +public: + int _x0, _y0; + int _x1, _y1; + BMP_PTR _b0, _b1; + BMP_PTR *_shpList; + Seq *_seq; + char *_name; + Snail::Com *_near, *_take; + SprExt() : + _x0(0), _y0(0), + _x1(0), _y1(0), + _b0(NULL), _b1(NULL), + _shpList(NULL), _seq(NULL), + _name(NULL), _near(NULL), _take(NULL) + {} +}; + + +class Sprite { +protected: + SprExt *_ext; +public: + int _ref; + signed char _cave; + struct Flags { + uint16 _hide : 1; // general visibility switch + uint16 _near : 1; // Near action lock + uint16 _drag : 1; // sprite is moveable + uint16 _hold : 1; // sprite is held with mouse + uint16 _____ : 1; // intrrupt driven animation + uint16 _slav : 1; // slave object + uint16 _syst : 1; // system object + uint16 _kill : 1; // dispose memory after remove + uint16 _xlat : 1; // 2nd way display: xlat table + uint16 _port : 1; // portable + uint16 _kept : 1; // kept in pocket + uint16 _east : 1; // talk to east (in opposite to west) + uint16 _shad : 1; // shadow + uint16 _back : 1; // 'send to background' request + uint16 _bDel : 1; // delete bitmaps in ~SPRITE + uint16 _tran : 1; // transparent (untouchable) + } _flags; + int _x; + int _y; + signed char _z; + uint16 _w; + uint16 _h; + uint16 _time; + uint8 _nearPtr; + uint8 _takePtr; + int _seqPtr; + int _shpCnt; + char _file[MAXFILE]; + Sprite *_prev; + Sprite *_next; + + bool works(Sprite *spr); + bool seqTest(int n); + inline bool active() { + return _ext != NULL; + } + Sprite(CGEEngine *vm, BMP_PTR *shp); + virtual ~Sprite(); + BMP_PTR shp(); + BMP_PTR *setShapeList(BMP_PTR *shp); + void moveShapes(uint8 *buf); + Sprite *expand(); + Sprite *contract(); + Sprite *backShow(bool fast = false); + void setName(char *n); + inline char *name() { + return (_ext) ? _ext->_name : NULL; + } + void gotoxy(int x, int y); + void center(); + void show(); + void hide(); + BMP_PTR ghost(); + void show(uint16 pg); + void makeXlat(uint8 *x); + void killXlat(); + void step(int nr = -1); + Seq *setSeq(Seq *seq); + Snail::Com *snList(SNLIST type); + virtual void touch(uint16 mask, int x, int y); + virtual void tick(); + void sync(Common::Serializer &s); +private: + CGEEngine *_vm; +}; + + +class Queue { + Sprite *_head; + Sprite *_tail; +public: + Queue(bool show); + ~Queue(); + + bool _show; + + void append(Sprite *spr); + void insert(Sprite *spr, Sprite *nxt); + void insert(Sprite *spr); + Sprite *remove(Sprite *spr); + void forAll(void (*fun)(Sprite *)); + Sprite *first() { + return _head; + } + Sprite *last() { + return _tail; + } + Sprite *locate(int ref); + void clear(); +}; + + +class Vga { + uint16 _oldMode; + uint16 *_oldScreen; + uint16 _statAdr; + bool _setPal; + Dac *_oldColors; + Dac *_newColors; + const char *_msg; + const char *_nam; + + int setMode(int mode); + void updateColors(); + void setColors(); + void setStatAdr(); + void waitVR(bool on); +public: + uint32 _frmCnt; + Queue *_showQ; + Queue *_spareQ; + int _mono; + static Graphics::Surface *_page[4]; + static Dac *_sysPal; + + Vga(int mode); + ~Vga(); + static void init(); + static void deinit(); + + void setup(VgaRegBlk *vrb); + void getColors(Dac *tab); + void setColors(Dac *tab, int lum); + void clear(uint8 color); + void copyPage(uint16 d, uint16 s); + void sunrise(Dac *tab); + void sunset(); + void show(); + void update(); + + static void palToDac(const byte *palData, Dac *tab); + static void dacToPal(const Dac *tab, byte *palData); +}; + + +Dac mkDac(uint8 r, uint8 g, uint8 b); +Rgb mkRgb(uint8 r, uint8 g, uint8 b); + + +template <class CBLK> +uint8 closest(CBLK *pal, CBLK x) { +#define f(col, lum) ((((uint16)(col)) << 8) / lum) + uint16 i, dif = 0xFFFF, found = 0; + uint16 L = x._r + x._g + x._b; + if (!L) + ++L; + uint16 R = f(x._r, L), G = f(x._g, L), B = f(x._b, L); + for (i = 0; i < 256; i++) { + uint16 l = pal[i]._r + pal[i]._g + pal[i]._b; + if (! l) + ++l; + int r = f(pal[i]._r, l), g = f(pal[i]._g, l), b = f(pal[i]._b, l); + uint16 D = ((r > R) ? (r - R) : (R - r)) + + ((g > G) ? (g - G) : (G - g)) + + ((b > B) ? (b - B) : (B - b)) + + ((l > L) ? (l - L) : (L - l)) * 10 ; + + if (D < dif) { + found = i; + dif = D; + if (D == 0) + break; // exact! + } + } + return found; +#undef f +} + +uint16 *saveScreen(); +void restoreScreen(uint16 * &sav); +Sprite *spriteAt(int x, int y); +Sprite *locate(int ref); + +extern bool _speedTest; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/vmenu.cpp b/engines/cge/vmenu.cpp new file mode 100644 index 0000000000..8fef6307b1 --- /dev/null +++ b/engines/cge/vmenu.cpp @@ -0,0 +1,155 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/vmenu.h" +#include "cge/events.h" +#include "cge/cge_main.h" + +namespace CGE { + + +#define RELIEF 1 +#if RELIEF +#define MB_LT LGRAY +#define MB_RB DGRAY +#else +#define MB_LT DGRAY +#define MB_RB LGRAY +#endif + + + + +MenuBar::MenuBar(CGEEngine *vm, uint16 w) : Talk(vm), _vm(vm) { + int h = FONT_HIG + 2 * MB_VM, i = (w += 2 * MB_HM) * h; + uint8 *p = farnew(uint8, i), * p1, * p2; + + memset(p + w, TRANS, i - 2 * w); + memset(p, MB_LT, w); + memset(p + i - w, MB_RB, w); + p1 = p; + p2 = p + i - 1; + for (i = 0; i < h; i++) { + *p1 = MB_LT; + *p2 = MB_RB; + p1 += w; + p2 -= w; + } + _ts[0] = new Bitmap(w, h, p); + setShapeList(_ts); + _flags._slav = true; + _flags._tran = true; + _flags._kill = true; + _flags._bDel = true; +} + + +static char *vmgt; + + +char *VMGather(Choice *list) { + Choice *cp; + int len = 0, h = 0; + + for (cp = list; cp->_text; cp++) { + len += strlen(cp->_text); + h++; + } + vmgt = new char[len + h]; + if (vmgt) { + *vmgt = '\0'; + for (cp = list; cp->_text; cp++) { + if (*vmgt) + strcat(vmgt, "|"); + strcat(vmgt, cp->_text); + h++; + } + } + return vmgt; +} + + +Vmenu *Vmenu::_addr = NULL; +int Vmenu::_recent = -1; + + +Vmenu::Vmenu(CGEEngine *vm, Choice *list, int x, int y) + : Talk(vm, VMGather(list), RECT), _menu(list), _bar(NULL), _vm(vm) { + Choice *cp; + + _addr = this; + delete[] vmgt; + _items = 0; + for (cp = list; cp->_text; cp++) + _items++; + _flags._bDel = true; + _flags._kill = true; + if (x < 0 || y < 0) + center(); + else + gotoxy(x - _w / 2, y - (TEXT_VM + FONT_HIG / 2)); + _vga->_showQ->insert(this, _vga->_showQ->last()); + _bar = new MenuBar(_vm, _w - 2 * TEXT_HM); + _bar->gotoxy(_x + TEXT_HM - MB_HM, _y + TEXT_VM - MB_VM); + _vga->_showQ->insert(_bar, _vga->_showQ->last()); +} + + +Vmenu::~Vmenu() { + _addr = NULL; +} + + +void Vmenu::touch(uint16 mask, int x, int y) { + uint16 h = FONT_HIG + TEXT_LS; + bool ok = false; + + if (_items) { + Sprite::touch(mask, x, y); + + y -= TEXT_VM - 1; + int n = 0; + if (y >= 0) { + n = y / h; + if (n < _items) + ok = (x >= TEXT_HM && x < _w - TEXT_HM/* && y % h < FONT_HIG*/); + else + n = _items - 1; + } + + _bar->gotoxy(_x + TEXT_HM - MB_HM, _y + TEXT_VM + n * h - MB_VM); + + if (ok && (mask & L_UP)) { + _items = 0; + SNPOST_(SNKILL, -1, 0, this); + //_menu[_recent = n].Proc(); + warning("Missing call to proc()"); + } + } +} + +} // End of namespace CGE diff --git a/engines/cge/vmenu.h b/engines/cge/vmenu.h new file mode 100644 index 0000000000..6b4eb85a53 --- /dev/null +++ b/engines/cge/vmenu.h @@ -0,0 +1,69 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_VMENU__ +#define __CGE_VMENU__ + +#include "cge/talk.h" + +namespace CGE { + +#define MB_VM 1 +#define MB_HM 3 + + +struct Choice { + const char *_text; + void (CGEEngine::*Proc)(); +}; + + +class MenuBar : public Talk { +public: + MenuBar(CGEEngine *vm, uint16 w); +private: + CGEEngine *_vm; +}; + + +class Vmenu : public Talk { + uint16 _items; + Choice *_menu; +public: + static Vmenu *_addr; + static int _recent; + MenuBar *_bar; + Vmenu(CGEEngine *vm, Choice *list, int x, int y); + ~Vmenu(); + virtual void touch(uint16 mask, int x, int y); +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/vol.cpp b/engines/cge/vol.cpp new file mode 100644 index 0000000000..04a9189682 --- /dev/null +++ b/engines/cge/vol.cpp @@ -0,0 +1,122 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/vol.h" +#include "common/system.h" +#include "common/str.h" + +namespace CGE { + +Dat *VFile::_dat = NULL; +BtFile *VFile::_cat = NULL; +VFile *VFile::_recent = NULL; + +/*-----------------------------------------------------------------------*/ + +Dat::Dat(): +#ifdef VOL_UPD + _file(DAT_NAME, UPD, CRP) +#else + _file(DAT_NAME, REA, CRP) +#endif +{ +} + +/*-----------------------------------------------------------------------*/ + +void VFile::init() { + _dat = new Dat(); +#ifdef VOL_UPD + _cat = new BtFile(CAT_NAME, UPD, CRP); +#else + _cat = new BtFile(CAT_NAME, REA, CRP); +#endif + + _recent = NULL; +} + +void VFile::deinit() { + delete _dat; + delete _cat; +} + +VFile::VFile(const char *name, IOMODE mode) + : IoBuf(mode) { + if (mode == REA) { + if (_dat->_file._error || _cat->_error) + error("Bad volume data"); + BtKeypack *kp = _cat->find(name); + if (scumm_stricmp(kp->_key, name) != 0) + _error = 1; + _endMark = (_bufMark = _begMark = kp->_mark) + kp->_size; + } +#ifdef VOL_UPD + else + Make(name); +#endif +} + + +VFile::~VFile() { + if (_recent == this) + _recent = NULL; +} + + +bool VFile::exist(const char *name) { + return scumm_stricmp(_cat->find(name)->_key, name) == 0; +} + + +void VFile::readBuff() { + if (_recent != this) { + _dat->_file.seek(_bufMark + _lim); + _recent = this; + } + _bufMark = _dat->_file.mark(); + long n = _endMark - _bufMark; + if (n > IOBUF_SIZE) + n = IOBUF_SIZE; + _lim = _dat->_file.read(_buff, (uint16) n); + _ptr = 0; +} + +long VFile::mark() { + return (_bufMark + _ptr) - _begMark; +} + +long VFile::size() { + return _endMark - _begMark; +} + +long VFile::seek(long pos) { + _recent = NULL; + _lim = 0; + return (_bufMark = _begMark + pos); +} + +} // End of namespace CGE diff --git a/engines/cge/vol.h b/engines/cge/vol.h new file mode 100644 index 0000000000..8ed33d0ab4 --- /dev/null +++ b/engines/cge/vol.h @@ -0,0 +1,92 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_VOL__ +#define __CGE_VOL__ + +#include "cge/btfile.h" +#include "cge/cfile.h" + +namespace CGE { + +#define CAT_NAME "VOL.CAT" +#define DAT_NAME "VOL.DAT" + +#ifndef CRP +#define CRP XCrypt +#endif + +#define XMASK 0xA5 + +#ifdef VOL_UPD +#define VOLBASE IOHAND +#else +#define VOLBASE CFile +#endif + + +class Dat { + friend class VFile; + VOLBASE _file; +public: + Dat(); + + bool append(uint8 *buf, uint16 len); + bool write(CFile &f); + bool read(long org, uint16 len, uint8 *buf); +}; + + +class VFile : public IoBuf { +private: + static Dat *_dat; + static BtFile *_cat; + static VFile *_recent; + + long _begMark; + long _endMark; + + void readBuff(); + void writeBuff() { } + void make(const char *fspec); +public: + VFile(const char *name, IOMODE mode = REA); + ~VFile(); + + static void init(); + static void deinit(); + static bool exist(const char *name); + static const char *next(); + long mark(); + long size(); + long seek(long pos); +}; + + +} // End of namespace CGE + +#endif diff --git a/engines/cge/wav.h b/engines/cge/wav.h new file mode 100644 index 0000000000..c3e67f5f95 --- /dev/null +++ b/engines/cge/wav.h @@ -0,0 +1,148 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE_WAV__ +#define __CGE_WAV__ + +#include "cge/general.h" + +namespace CGE { + +#define WAVE_FORMAT_PCM 0x0001 +#define IBM_FORMAT_MULAW 0x0101 +#define IBM_FORMAT_ALAW 0x0102 +#define IBM_FORMAT_ADPCM 0x0103 + +typedef char FourCC[4]; // Four-character code + +class ChunkId { // Chunk type identifier + union { + FourCC _tx; + uint32 _id; + }; +protected: + static XFile *ckFile; +public: + ChunkId(FourCC t) { + memcpy(_tx, t, sizeof(_tx)); + } + ChunkId(uint32 d) { + _id = d; + } + ChunkId(XFile *xf) { + (ckFile = xf)->read(_tx, sizeof(_tx)); + } + bool operator !=(ChunkId &X) { + return _id != X._id; + } + bool operator ==(ChunkId &X) { + return _id == X._id; + } + const char *name(); +}; + + +class CkHea : public ChunkId { +protected: + uint32 _ckSize; // Chunk size field (size of ckData) +public: + CkHea(XFile *xf) : ChunkId(xf) { + XRead(xf, &_ckSize); + } + CkHea(char id[]) : ChunkId(id), _ckSize(0) { } + void skip(); + uint32 size() { + return _ckSize; + } +}; + + +class FmtCk : public CkHea { + struct Wav { + uint16 _wFormatTag; // Format category + uint16 _wChannels; // Number of channels + uint32 _dwSamplesPerSec; // Sampling rate + uint32 _dwAvgBytesPerSec; // For buffer estimation + uint16 _wBlockAlign; // Data block size + } _wav; + + union { + struct { + uint16 _wBitsPerSample; // Sample size + } _pcm; + }; +public: + FmtCk(CkHea &hea); + inline uint16 channels() { + return _wav._wChannels; + } + inline uint32 smplRate() { + return _wav._dwSamplesPerSec; + } + inline uint32 byteRate() { + return _wav._dwAvgBytesPerSec; + } + inline uint16 blckSize() { + return _wav._wBlockAlign; + } + inline uint16 smplSize() { + return _pcm._wBitsPerSample; + } +}; + + +class DataCk : public CkHea { + bool _e; + union { + uint8 *_buf; + Ems *_eBuf; + }; +public: + DataCk(CkHea &hea); + DataCk(CkHea &hea, Emm *emm); + DataCk(int first, int last); + ~DataCk(); + inline uint8 *addr() { + return _buf; + } + inline Ems *eAddr() { + return _eBuf; + } +}; + + +extern ChunkId _riff; +extern ChunkId _wave; +extern ChunkId _fmt; +extern ChunkId _data; + + +DataCk *loadWave(XFile *file, Emm *emm = NULL); + +} // End of namespace CGE + +#endif diff --git a/engines/engines.mk b/engines/engines.mk index dc09fbd54e..07364a5bd3 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -26,6 +26,11 @@ DEFINES += -DENABLE_AGOS2 endif endif +ifdef ENABLE_CGE +DEFINES += -DENABLE_CGE=$(ENABLE_CGE) +MODULES += engines/cge +endif + ifdef ENABLE_CINE DEFINES += -DENABLE_CINE=$(ENABLE_CINE) MODULES += engines/cine |