diff options
55 files changed, 11716 insertions, 0 deletions
diff --git a/base/plugins.cpp b/base/plugins.cpp index 4c2fd2cffc..46fd646563 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -94,6 +94,9 @@ public: #if PLUGIN_ENABLED_STATIC(AGOS) LINK_PLUGIN(AGOS) #endif + #if PLUGIN_ENABLED_STATIC(CGE) + LINK_PLUGIN(CGE) + #endif #if PLUGIN_ENABLED_STATIC(CINE) LINK_PLUGIN(CINE) #endif @@ -83,6 +83,7 @@ add_engine he "HE71+ games" yes add_engine agi "AGI" yes add_engine agos "AGOS" yes "agos2" add_engine agos2 "AGOS 2 games" yes +add_engine cge "CGE" no add_engine cine "Cinematique evo 1" yes add_engine cruise "Cinematique evo 2" yes add_engine draci "Dragon History" yes diff --git a/engines/cge/bitmap.cpp b/engines/cge/bitmap.cpp new file mode 100644 index 0000000000..ab5c1ff3c7 --- /dev/null +++ b/engines/cge/bitmap.cpp @@ -0,0 +1,483 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/bitmap.h" +#include "cge/cfile.h" +#include "cge/jbw.h" +#include "cge/vol.h" +#include "cge/cfile.h" +#include "cge/vga13h.h" +#include "common/system.h" + +namespace CGE { + +DAC *Bitmap::Pal = NULL; +#define MAXPATH 128 + +void Bitmap::init() { + Pal = NULL; +} + +void Bitmap::deinit() { +} + +#pragma argsused +Bitmap::Bitmap(const char *fname, bool rem) : _m(NULL), _v(NULL) { + char pat[MAXPATH]; + ForceExt(pat, fname, ".VBM"); + +#if (BMP_MODE < 2) + if (rem && PIC_FILE::Exist(pat)) { + PIC_FILE file(pat); + if ((file.Error == 0) && (!VBMLoad(&file))) + error("Bad VBM [%s]", fname); + } else +#endif + { +#if (BMP_MODE) + ForceExt(pat, fname, ".BMP"); + PIC_FILE file(pat); + if (file.Error == 0) { + if (BMPLoad(&file)) { + Code(); + if (rem) { + free(_m); + _m = NULL; + } + } else + error("Bad BMP [%s]", fname); + } +#else + error("Bad VBM [%s]", fname); +#endif + } +} + + +Bitmap::Bitmap(uint16 w, uint16 h, uint8 *map) : _w(w), _h(h), _m(map), _v(NULL) { + if (map) + Code(); +} + + +// following routine creates filled rectangle +// immediately as VGA video chunks, in near memory as fast as possible, +// especially for text line real time display +Bitmap::Bitmap(uint16 w, uint16 h, uint8 fill) + : _w((w + 3) & ~3), // only full uint32 allowed! + _h(h), + _m(NULL) { + uint16 dsiz = _w >> 2; // data size (1 plane line size) + uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap + uint16 psiz = _h * lsiz; // - last gape, but + plane trailer + uint8 *v = new uint8[4 * psiz + _h * sizeof(*_b)];// the same for 4 planes + // + room for wash table + if (v == NULL) + error("No core"); + + *(uint16 *) v = CPY | dsiz; // data chunk hader + memset(v + 2, fill, dsiz); // data bytes + *(uint16 *)(v + lsiz - 2) = SKP | ((SCR_WID / 4) - dsiz); // gap + memcpy(v + lsiz, v, psiz - lsiz); // tricky replicate lines + *(uint16 *)(v + psiz - 2) = EOI; // plane trailer uint16 + memcpy(v + psiz, v, 3 * psiz); // tricky replicate planes + HideDesc *b = (HideDesc *)(v + 4 * psiz); + b->skip = (SCR_WID - _w) >> 2; + b->hide = _w >> 2; + memcpy(b + 1, b, (_h - 1) * sizeof(*b)); // tricky fill entire table + b->skip = 0; // fix the first entry + _v = v; + _b = b; +} + + +Bitmap::Bitmap(const Bitmap &bmp) : _w(bmp._w), _h(bmp._h), _m(NULL), _v(NULL) { + uint8 *v0 = bmp._v; + if (v0) { + uint16 vsiz = (uint8 *)(bmp._b) - (uint8 *)(v0); + uint16 siz = vsiz + _h * sizeof(HideDesc); + uint8 *v1 = farnew(uint8, siz); + if (v1 == NULL) + error("No core"); + memcpy(v1, v0, siz); + _b = (HideDesc *)((_v = v1) + vsiz); + } +} + + +Bitmap::~Bitmap(void) { + if (MemType(_m) == FAR_MEM) + free(_m); + + switch (MemType(_v)) { + case NEAR_MEM : + delete[](uint8 *) _v; + break; + case FAR_MEM : + free(_v); + default: + warning("Unhandled MemType in Bitmap destructor"); + break; + break; + } +} + + +Bitmap &Bitmap::operator = (const Bitmap &bmp) { + uint8 *v0 = bmp._v; + _w = bmp._w; + _h = bmp._h; + _m = NULL; + if (MemType(_v) == FAR_MEM) + free(_v); + if (v0 == NULL) + _v = NULL; + else { + uint16 vsiz = (uint8 *)bmp._b - (uint8 *)v0; + uint16 siz = vsiz + _h * sizeof(HideDesc); + uint8 *v1 = farnew(uint8, siz); + if (v1 == NULL) + error("No core"); + memcpy(v1, v0, siz); + _b = (HideDesc *)((_v = v1) + vsiz); + } + return *this; +} + + +uint16 Bitmap::MoveVmap(uint8 *buf) { + if (_v) { + uint16 vsiz = (uint8 *)_b - (uint8 *)_v; + uint16 siz = vsiz + _h * sizeof(HideDesc); + memcpy(buf, _v, siz); + if (MemType(_v) == FAR_MEM) + free(_v); + _b = (HideDesc *)((_v = buf) + vsiz); + return siz; + } + return 0; +} + + +BMP_PTR Bitmap::Code(void) { + if (_m) { + uint16 i, cnt; + + if (_v) { // old X-map exists, so remove it + switch (MemType(_v)) { + case NEAR_MEM : + delete[](uint8 *) _v; + break; + case FAR_MEM : + free(_v); + break; + default: + warning("Unhandled MemType in Bitmap::Code()"); + break; + } + _v = NULL; + } + + while (true) { // at most 2 times: for (V == NULL) & for allocated block; + uint8 *im = _v + 2; + uint16 *cp = (uint16 *) _v; + int bpl; + + if (_v) { // 2nd pass - fill the hide table + for (i = 0; i < _h; i++) { + _b[i].skip = 0xFFFF; + _b[i].hide = 0x0000; + } + } + for (bpl = 0; bpl < 4; bpl++) { // once per each bitplane + uint8 *bm = _m; + bool skip = (bm[bpl] == TRANS); + uint16 j; + + cnt = 0; + for (i = 0; i < _h; i++) { // once per each line + uint8 pix; + for (j = bpl; j < _w; j += 4) { + pix = bm[j]; + if (_v && pix != TRANS) { + if (j < _b[i].skip) + _b[i].skip = j; + + if (j >= _b[i].hide) + _b[i].hide = j + 1; + } + if ((pix == TRANS) != skip || cnt >= 0x3FF0) { // end of block + cnt |= (skip) ? SKP : CPY; + if (_v) + *cp = cnt; // store block description uint16 + + cp = (uint16 *) im; + im += 2; + skip = (pix == TRANS); + cnt = 0; + } + if (! skip) { + if (_v) + *im = pix; + ++ im; + } + ++ cnt; + } + + bm += _w; + if (_w < SCR_WID) { + if (skip) { + cnt += (SCR_WID - j + 3) / 4; + } else { + cnt |= CPY; + if (_v) + *cp = cnt; + + cp = (uint16 *) im; + im += 2; + skip = true; + cnt = (SCR_WID - j + 3) / 4; + } + } + } + if (cnt && ! skip) { + cnt |= CPY; + if (_v) + *cp = cnt; + + cp = (uint16 *) im; + im += 2; + } + if (_v) + *cp = EOI; + cp = (uint16 *) im; + im += 2; + } + if (_v) + break; + + uint16 sizV = (uint16)(im - 2 - _v); + _v = farnew(uint8, sizV + _h * sizeof(*_b)); + if (!_v) + error("No core"); + + _b = (HideDesc *)(_v + sizV); + } + cnt = 0; + for (i = 0; i < _h; i++) { + if (_b[i].skip == 0xFFFF) { // whole line is skipped + _b[i].skip = (cnt + SCR_WID) >> 2; + cnt = 0; + } else { + uint16 s = _b[i].skip & ~3; + uint16 h = (_b[i].hide + 3) & ~3; + _b[i].skip = (cnt + s) >> 2; + _b[i].hide = (h - s) >> 2; + cnt = SCR_WID - h; + } + } + } + return this; +} + + +bool Bitmap::SolidAt(int x, int y) { + uint8 *m; + uint16 r, n, n0; + + if ((x >= _w) || (y >= _h)) + return false; + + m = _v; + r = x % 4; + n0 = (SCR_WID * y + x) / 4, n = 0; + + while (r) { + uint16 w, t; + + w = *(uint16 *) m; + m += 2; + t = w & 0xC000; + w &= 0x3FFF; + + switch (t) { + case EOI : + r--; + case SKP : + w = 0; + break; + case REP : + w = 1; + break; + } + m += w; + } + + while (true) { + uint16 w, t; + + w = *(uint16 *) m; + m += 2; + t = w & 0xC000; + w &= 0x3FFF; + + if (n > n0) + return false; + + n += w; + switch (t) { + case EOI : + return false; + case SKP : + w = 0; + break; + case REP : + case CPY : + if (n - w <= n0 && n > n0) + return true; + break; + } + m += ((t == REP) ? 1 : w); + } +} + + +bool Bitmap::VBMSave(XFILE *f) { + uint16 p = (Pal != NULL), + n = ((uint16)(((uint8 *)_b) - _v)) + _h * sizeof(HideDesc); + if (f->Error == 0) + f->Write((uint8 *)&p, sizeof(p)); + + if (f->Error == 0) + f->Write((uint8 *)&n, sizeof(n)); + + if (f->Error == 0) + f->Write((uint8 *)&_w, sizeof(_w)); + + if (f->Error == 0) + f->Write((uint8 *)&_h, sizeof(_h)); + + if (f->Error == 0) + if (p) + f->Write((uint8 *)Pal, 256 * 3); + + if (f->Error == 0) + f->Write(_v, n); + + return (f->Error == 0); +} + + +bool Bitmap::VBMLoad(XFILE *f) { + uint16 p = 0, n = 0; + if (f->Error == 0) + f->Read((uint8 *)&p, sizeof(p)); + + if (f->Error == 0) + f->Read((uint8 *)&n, sizeof(n)); + + if (f->Error == 0) + f->Read((uint8 *)&_w, sizeof(_w)); + + if (f->Error == 0) + f->Read((uint8 *)&_h, sizeof(_h)); + + if (f->Error == 0) { + if (p) { + if (Pal) { + byte palData[PAL_SIZ]; + f->Read(palData, PAL_SIZ); + VGA::pal2DAC(palData, Pal); + } else + f->Seek(f->Mark() + PAL_SIZ); + } + } + if ((_v = farnew(uint8, n)) == NULL) + return false; + + if (f->Error == 0) + f->Read(_v, n); + + _b = (HideDesc *)(_v + n - _h * sizeof(HideDesc)); + return (f->Error == 0); +} + +bool Bitmap::BMPLoad (XFILE * f) { + struct { + char BM[2]; + union { int16 len; int32 len_; }; + union { int16 _06; int32 _06_; }; + union { int16 hdr; int32 hdr_; }; + union { int16 _0E; int32 _0E_; }; + union { int16 wid; int32 wid_; }; + union { int16 hig; int32 hig_; }; + union { int16 _1A; int32 _1A_; }; + union { int16 _1E; int32 _1E_; }; + union { int16 _22; int32 _22_; }; + union { int16 _26; int32 _26_; }; + union { int16 _2A; int32 _2A_; }; + union { int16 _2E; int32 _2E_; }; + union { int16 _32; int32 _32_; }; + } hea; + BGR4 bpal[256]; + + f->Read((byte *)&hea, sizeof(hea)); + if (f->Error == 0) { + if (hea.hdr == 0x436L) { + int16 i = (hea.hdr - sizeof(hea)) / sizeof(BGR4); + f->Read((byte *)&bpal, sizeof(bpal)); + if (f->Error == 0) { + if (Pal) { + for (i = 0; i < 256; i ++) { + Pal[i].R = bpal[i].R; + Pal[i].G = bpal[i].G; + Pal[i].B = bpal[i].B; + } + Pal = NULL; + } + _h = hea.hig; + _w = hea.wid; + if ((_m = farnew(byte, _h * _w)) != NULL) { + int16 r = (4 - (hea.wid & 3)) % 4; + byte buf[3]; int i; + for (i = _h - 1; i >= 0; i--) { + f->Read(_m + (_w * i), _w); + if (r && f->Error == 0) + f->Read(buf, r); + if (f->Error) + break; + } + if (i < 0) + return true; + } + } + } + } + return false; +} + +} // End of namespace CGE diff --git a/engines/cge/bitmap.h b/engines/cge/bitmap.h new file mode 100644 index 0000000000..cfa7830f39 --- /dev/null +++ b/engines/cge/bitmap.h @@ -0,0 +1,97 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __BITMAP__ +#define __BITMAP__ + +#include "cge/general.h" + +namespace CGE { + +#define EOI 0x0000 +#define SKP 0x4000 +#define REP 0x8000 +#define CPY 0xC000 + +#define TRANS 0xFE + +#include "common/pack-start.h" + +struct BGR4 { + uint16 b : 2; + uint16 B : 6; + uint16 g : 2; + uint16 G : 6; + uint16 r : 2; + uint16 R : 6; + uint16 Z : 8; +}; + + +struct HideDesc { + uint16 skip; + uint16 hide; +}; + +#include "common/pack-end.h" + +class Bitmap { + bool BMPLoad(XFILE *f); + bool VBMLoad(XFILE *f); +public: + static DAC *Pal; + uint16 _w; + uint16 _h; + uint8 *_m; + uint8 *_v; + HideDesc *_b; + + Bitmap(const char *fname, bool rem = true); + Bitmap(uint16 w, uint16 h, uint8 *map); + Bitmap(uint16 w, uint16 h, uint8 fill); + Bitmap(const Bitmap &bmp); + ~Bitmap(void); + static void init(); + static void deinit(); + + Bitmap *FlipH(void); + Bitmap *Code(); + Bitmap &operator = (const Bitmap &bmp); + void Hide(int x, int y); + void Show(int x, int y); + void XShow(int x, int y); + bool SolidAt(int x, int y); + bool VBMSave(XFILE *f); + uint16 MoveVmap(uint8 *buf); +}; + + +typedef Bitmap *BMP_PTR; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/bitmaps.cpp b/engines/cge/bitmaps.cpp new file mode 100644 index 0000000000..5e8757ae73 --- /dev/null +++ b/engines/cge/bitmaps.cpp @@ -0,0 +1,229 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/bitmaps.h" +/* + +#define W 255, +#define x 252, +#define _ TRANS, +#define o 0, +#define L LGRAY, +#define G GRAY, +#define D DGRAY, + +static uint8 MCDesign0[]= { W W W W W W _ + W W W W W o _ + W W W W o _ _ + W W W W W _ _ + W W o W W W _ + W o _ o W W W + o _ _ _ o W W + _ _ _ _ _ o o }; + + +static uint8 MCDesign1[]= { _ }; + + + +static uint8 SLDesign[] = { G G G G G G G G G _ _ _ _ _ _ + L G G G G G G G G D _ _ _ _ _ + _ L G G G G G G G D _ _ _ _ _ + _ _ L G G G G G G G D _ _ _ _ + _ _ _ L G G G G G G D _ _ _ _ + _ _ _ _ L G G G G G D _ _ _ _ + _ _ _ _ _ L G G G G G D _ _ _ + _ _ _ _ _ _ L G G G G D _ _ _ + _ _ _ _ _ _ _ L G G G D _ _ _ + _ _ _ _ _ _ _ _ L G G G D _ _ + _ _ _ _ _ _ _ _ _ L G G D _ _ + _ _ _ _ _ _ _ _ _ _ L G D _ _ + _ _ _ _ _ _ _ _ _ _ _ L G D _ + _ _ _ _ _ _ _ _ _ _ _ _ L D _ + _ _ _ _ _ _ _ _ _ _ _ _ _ L D + _ _ _ _ _ _ _ _ _ _ _ _ _ _ D + }; + +static uint8 SRDesign[] = { _ _ _ _ _ _ G G G G G G G G G + _ _ _ _ _ L G G G G G G G G D + _ _ _ _ _ L G G G G G G G D _ + _ _ _ _ L G G G G G G G D _ _ + _ _ _ _ L G G G G G G D _ _ _ + _ _ _ _ L G G G G G D _ _ _ _ + _ _ _ L G G G G G D _ _ _ _ _ + _ _ _ L G G G G D _ _ _ _ _ _ + _ _ _ L G G G D _ _ _ _ _ _ _ + _ _ L G G G D _ _ _ _ _ _ _ _ + _ _ L G G D _ _ _ _ _ _ _ _ _ + _ _ L G D _ _ _ _ _ _ _ _ _ _ + _ L G D _ _ _ _ _ _ _ _ _ _ _ + _ L D _ _ _ _ _ _ _ _ _ _ _ _ + L D _ _ _ _ _ _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ _ _ _ _ _ _ + }; + +static uint8 MapBrick[] = { L L L L L L L G + L G G G G G G D + L G G G G G G D + G D D D D D D D + }; + +#undef W +#undef _ +#undef x +#undef o +#undef L +#undef G +#undef D + + +#if 0 + +#define _ TRANS, +#define A 213, +#define B 207, +#define C 225, +#define D 219, +#define E 231, + +static uint8 PRDesign[] = { A E E E C C D A B + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + C _ _ _ _ _ _ D A + B A A A A A A A B + B B B B B B B B B + }; + +#else + +#define _ TRANS, +#define A 213, +#define B 207, +#define C 225, // DGRAY +#define D 219, +#define E 231, +#define F 237, + +static uint8 PRDesign[] = { D D D D D D D D _ + D D D D D D D D _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ _ _ + D _ _ _ _ _ _ C _ + D C C C C C C C _ + _ _ _ _ _ _ _ _ _ + }; +#endif + + +#undef _ +#undef A +#undef B +#undef C +#undef D +#undef E + + + +#define _ 0x00, +#define x 0xFF, +#define A _ x _ x _ x _ x +#define B A A A A A A A A + +static uint8 HLDesign[] = { B B B B B }; + +#undef _ +#undef x +#undef A +#undef B + + +// 228 yellow +// 211 red +// 226 light green +// 221 blue + +#define A 208, +#define B 214, +#define C 220, +#define D 226, +#define E 255, + +static uint8 LIDesign[][9] = { { A A A + A B A + A A A }, + + { A B A + B C B + A B A }, + + { B C B + C D C + B C B }, + + { C D C + D E D + C D C }, + }; + +#undef A +#undef B +#undef C +#undef D +#undef E + + +#define R 211, +#define G 0, +//226, + +static uint8 MEDesign[][9] = { { R R R R R R R R R }, // 0 + { R R R R R R R R G }, // 1 + { R R R R R R R G G }, // 2 + { R R R R R R G G G }, // 3 + { R R R R R G G G G }, // 4 + { R R R R G G G G G }, // 5 + { R R R G G G G G G }, // 6 + { R R G G G G G G G }, // 7 + { R G G G G G G G G }, // 8 + { G G G G G G G G G }, // 9 + }; + +#undef R +#undef G +*/ + +namespace CGE { + + + +} // End of namespace CGE diff --git a/engines/cge/bitmaps.h b/engines/cge/bitmaps.h new file mode 100644 index 0000000000..40b1158b21 --- /dev/null +++ b/engines/cge/bitmaps.h @@ -0,0 +1,44 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __BITMAPS__ +#define __BITMAPS__ + +#include "cge/vga13h.h" + +namespace CGE { + +extern Bitmap *MB[]; +extern Bitmap *HL[]; +extern Bitmap *MC[]; +extern Bitmap *PR[]; +extern Bitmap *SP[]; +extern Bitmap *LI[]; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/boot.h b/engines/cge/boot.h new file mode 100644 index 0000000000..ab4dcde0e2 --- /dev/null +++ b/engines/cge/boot.h @@ -0,0 +1,79 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __BOOT__ +#define __BOOT__ + +#include "cge/jbw.h" + +namespace CGE { + +#define BOOTSECT_SIZ 512 +#define BOOTHEAD_SIZ 62 +#define BOOTCODE_SIZ BOOTSECT_SIZ-BOOTHEAD_SIZ +#define FreeBoot(b) free(b) + +#ifndef EC +#define EC +#endif + +typedef struct { + uint8 Jmp[3]; // NEAR jump machine code + char OEM_ID[8]; // OEM name and version + uint16 SectSize; // bytes per sector + uint8 ClustSize; // sectors per cluster + uint16 ResSecs; // sectors before 1st FAT + uint8 FatCnt; // number of FATs + uint16 RootSize; // root directory entries + uint16 TotSecs; // total sectors on disk + uint8 Media; // media descriptor byte + uint16 FatSize; // sectors per FAT + uint16 TrkSecs; // sectors per track + uint16 HeadCnt; // number of sufraces + uint16 HidnSecs; // special hidden sectors + uint16 _; // (unknown: reserved?) + uint32 lTotSecs; // total number of sectors + uint16 DriveNum; // physical drive number + uint8 XSign; // extended boot signature + uint32 Serial; // volume serial number + char Label[11]; // volume label + char FileSysID[8]; // file system ID + char Code[BOOTCODE_SIZ - 8]; // 8 = length of following + uint32 Secret; // long secret number + uint8 BootCheck; // boot sector checksum + uint8 BootFlags; // secret flags + uint16 BootSig; // boot signature 0xAA55 +} Boot; + + +EC Boot *ReadBoot(int drive); +EC uint8 CheckBoot(Boot *boot); +EC bool WriteBoot(int drive, Boot *boot); + +} // End of namespace CGE + +#endif diff --git a/engines/cge/btfile.cpp b/engines/cge/btfile.cpp new file mode 100644 index 0000000000..db0ebc2d5f --- /dev/null +++ b/engines/cge/btfile.cpp @@ -0,0 +1,151 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/btfile.h" +#include "common/system.h" +#include "common/str.h" +#include <string.h> + +namespace CGE { + +#ifndef BT_SIZE +#define BT_SIZE K(1) +#endif + +#ifndef BT_KEYLEN +#define BT_KEYLEN 13 +#endif + +BTFILE::BTFILE(const char *name, IOMODE mode, CRYPT *crpt) + : IOHAND(name, mode, crpt) { + for (int i = 0; i < BT_LEVELS; i++) { + Buff[i].Page = new BT_PAGE; + Buff[i].PgNo = BT_NONE; + Buff[i].Indx = -1; + Buff[i].Updt = false; + if (Buff[i].Page == NULL) + error("No core"); + } +} + + +BTFILE::~BTFILE(void) { + for (int i = 0; i < BT_LEVELS; i++) { + PutPage(i); + delete Buff[i].Page; + } +} + + +void BTFILE::PutPage(int lev, bool hard) { + if (hard || Buff[lev].Updt) { + Seek(Buff[lev].PgNo * sizeof(BT_PAGE)); + Write((uint8 *) Buff[lev].Page, sizeof(BT_PAGE)); + Buff[lev].Updt = false; + } +} + + +BT_PAGE *BTFILE::GetPage(int lev, uint16 pgn) { + if (Buff[lev].PgNo != pgn) { + int32 pos = pgn * sizeof(BT_PAGE); + PutPage(lev); + Buff[lev].PgNo = pgn; + if (Size() > pos) { + Seek((uint32) pgn * sizeof(BT_PAGE)); + Read((uint8 *) Buff[lev].Page, sizeof(BT_PAGE)); + Buff[lev].Updt = false; + } else { + Buff[lev].Page->Hea.Count = 0; + Buff[lev].Page->Hea.Down = BT_NONE; + memset(Buff[lev].Page->Data, '\0', sizeof(Buff[lev].Page->Data)); + Buff[lev].Updt = true; + } + Buff[lev].Indx = -1; + } + return Buff[lev].Page; +} + +BT_KEYPACK *BTFILE::Find(const char *key) { + int lev = 0; + uint16 nxt = BT_ROOT; + while (! Error) { + BT_PAGE *pg = GetPage(lev, nxt); + // search + if (pg->Hea.Down != BT_NONE) { + int i; + for (i = 0; i < pg->Hea.Count; i++) { + // Does this work, or does it have to compare the entire buffer? + if (scumm_strnicmp((const char *) key, (const char*)pg->Inn[i].Key, BT_KEYLEN) < 0) + break; + } + nxt = (i) ? pg->Inn[i - 1].Down : pg->Hea.Down; + Buff[lev].Indx = i - 1; + ++ lev; + } else { + int i; + for (i = 0; i < pg->Hea.Count - 1; i++) { + if (scumm_stricmp((const char *)key, (const char *)pg->Lea[i].Key) <= 0) + break; + } + Buff[lev].Indx = i; + return &pg->Lea[i]; + } + } + return NULL; +} + + +int keycomp(const void *k1, const void *k2) { + return scumm_strnicmp((const char *) k1, (const char*) k2, BT_KEYLEN); +} + + +void BTFILE::Make(BT_KEYPACK *keypack, uint16 count) { +#if BT_LEVELS != 2 +#error This tiny BTREE implementation works with exactly 2 levels! +#endif + _fqsort(keypack, count, sizeof(*keypack), keycomp); + uint16 n = 0; + BT_PAGE *Root = GetPage(0, n++), + *Leaf = GetPage(1, n); + Root->Hea.Down = n; + PutPage(0, true); + while (count--) { + if (Leaf->Hea.Count >= ArrayCount(Leaf->Lea)) { + PutPage(1, true); // save filled page + Leaf = GetPage(1, ++n); // take empty page + memcpy(Root->Inn[Root->Hea.Count].Key, keypack->Key, BT_KEYLEN); + Root->Inn[Root->Hea.Count++].Down = n; + Buff[0].Updt = true; + } + Leaf->Lea[Leaf->Hea.Count++] = *(keypack++); + Buff[1].Updt = true; + } +} + +} // End of namespace CGE diff --git a/engines/cge/btfile.h b/engines/cge/btfile.h new file mode 100644 index 0000000000..449f200140 --- /dev/null +++ b/engines/cge/btfile.h @@ -0,0 +1,92 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __BTFILE__ +#define __BTFILE__ + +#include "cge/general.h" + +namespace CGE { + +#define BT_SIZE K(1) +#define BT_KEYLEN 13 +#define BT_LEVELS 2 + +#define BT_NONE 0xFFFF +#define BT_ROOT 0 + +#include "common/pack-start.h" // START STRUCT PACKING + +struct BT_KEYPACK { + char Key[BT_KEYLEN]; + uint32 Mark; + uint16 Size; +}; + +typedef struct { + uint8 Key[BT_KEYLEN]; + uint16 Down; +} INNER; + +struct BT_PAGE { + struct HEA { + uint16 Count; + uint16 Down; + } Hea; + union { + // dummy filler to make proper size of union + uint8 Data[BT_SIZE - sizeof(HEA)]; + // inner version of data: key + word-sized page link + INNER Inn[(BT_SIZE - sizeof(HEA)) / sizeof(INNER)]; + // leaf version of data: key + all user data + BT_KEYPACK Lea[(BT_SIZE - sizeof(HEA)) / sizeof(BT_KEYPACK)]; + }; +}; + +#include "common/pack-end.h" // END STRUCT PACKING + + +class BTFILE : public IOHAND { + struct { + BT_PAGE *Page; + uint16 PgNo; + int Indx; + bool Updt; + } Buff[BT_LEVELS]; + void PutPage(int lev, bool hard = false); + BT_PAGE *GetPage(int lev, uint16 pgn); +public: + BTFILE(const char *name, IOMODE mode = REA, CRYPT *crpt = NULL); + virtual ~BTFILE(void); + BT_KEYPACK *Find(const char *key); + BT_KEYPACK *Next(void); + void Make(BT_KEYPACK *keypack, uint16 count); +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/cfile.cpp b/engines/cge/cfile.cpp new file mode 100644 index 0000000000..85e51a94c1 --- /dev/null +++ b/engines/cge/cfile.cpp @@ -0,0 +1,262 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/cfile.h" +#include <fcntl.h> +#include <string.h> +#include "common/system.h" + +namespace CGE { + +IOBUF::IOBUF(IOMODE mode, CRYPT *crpt) + : IOHAND(mode, crpt), + BufMark(0), + Ptr(0), + Lim(0) { + Buff = farnew(uint8, IOBUF_SIZE); + if (Buff == NULL) + error("No core for I/O"); +} + + +IOBUF::IOBUF(const char *name, IOMODE mode, CRYPT *crpt) + : IOHAND(name, mode, crpt), + BufMark(0), + Ptr(0), + Lim(0) { + Buff = farnew(uint8, IOBUF_SIZE); + if (Buff == NULL) + error("No core for I/O [%s]", name); +} + +IOBUF::~IOBUF(void) { + if (Mode > REA) + WriteBuff(); + if (Buff) + free(Buff); +} + + +void IOBUF::ReadBuff(void) { + BufMark = IOHAND::Mark(); + Lim = IOHAND::Read(Buff, IOBUF_SIZE); + Ptr = 0; +} + + +void IOBUF::WriteBuff(void) { + if (Lim) { + IOHAND::Write(Buff, Lim); + BufMark = IOHAND::Mark(); + Lim = 0; + } +} + + +uint16 IOBUF::Read(void *buf, uint16 len) { + uint16 total = 0; + while (len) { + if (Ptr >= Lim) + ReadBuff(); + uint16 n = Lim - Ptr; + if (n) { + if (len < n) + n = len; + memcpy(buf, Buff + Ptr, n); + buf = (uint8 *)buf + n; + len -= n; + total += n; + Ptr += n; + } else + break; + } + return total; +} + + +uint16 IOBUF::Read(uint8 *buf) { + uint16 total = 0; + + while (total < LINE_MAX - 2) { + if (Ptr >= Lim) + ReadBuff(); + uint8 *p = Buff + Ptr; + uint16 n = Lim - Ptr; + if (n) { + if (total + n >= LINE_MAX - 2) + n = LINE_MAX - 2 - total; + uint8 *eol = (uint8 *) memchr(p, '\r', n); + if (eol) + n = (uint16)(eol - p); + uint8 *eof = (uint8 *) memchr(p, '\32', n); + if (eof) { // end-of-file + n = (uint16)(eof - p); + Ptr = (uint16)(eof - Buff); + } + if (n) + memcpy(buf, p, n); + buf += n; + total += n; + if (eof) + break; + Ptr += n; + if (eol) { + ++ Ptr; + *(buf++) = '\n'; + ++ total; + if (Ptr >= Lim) + ReadBuff(); + if (Ptr < Lim) + if (Buff[Ptr] == '\n') + ++Ptr; + break; + } + } else + break; + } + *buf = '\0'; + return total; +} + + +uint16 IOBUF::Write(void *buf, uint16 len) { + uint16 tot = 0; + while (len) { + uint16 n = IOBUF_SIZE - Lim; + if (n > len) + n = len; + if (n) { + memcpy(Buff + Lim, buf, n); + Lim += n; + len -= n; + buf = (uint8 *)buf + n; + tot += n; + } else + WriteBuff(); + } + return tot; +} + + +uint16 IOBUF::Write(uint8 *buf) { + uint16 len = 0; + if (buf) { + len = strlen((const char *) buf); + if (len) + if (buf[len - 1] == '\n') + --len; + len = Write(buf, len); + if (len) { + static char EOL[] = "\r\n"; + uint16 n = Write(EOL, sizeof(EOL) - 1); + len += n; + } + } + return len; +} + + +int IOBUF::Read(void) { + if (Ptr >= Lim) { + ReadBuff(); + if (Lim == 0) + return -1; + } + return Buff[Ptr++]; +} + + +void IOBUF::Write(uint8 b) { + if (Lim >= IOBUF_SIZE) + WriteBuff(); + Buff[Lim++] = b; +} + + +uint16 CFILE::MaxLineLen = LINE_MAX; + + +CFILE::CFILE(const char *name, IOMODE mode, CRYPT *crpt) + : IOBUF(name, mode, crpt) { +} + + +CFILE::~CFILE(void) { +} + + +void CFILE::Flush(void) { + if (Mode > REA) + WriteBuff(); + else + Lim = 0; + + /* + _BX = Handle; + _AH = 0x68; // Flush buffer + asm int 0x21 + */ + warning("FIXME: CFILE::Flush"); +} + + +long CFILE::Mark(void) { + return BufMark + ((Mode > REA) ? Lim : Ptr); +} + + +long CFILE::Seek(long pos) { + if (pos >= BufMark && pos < BufMark + Lim) { + ((Mode == REA) ? Ptr : Lim) = (uint16)(pos - BufMark); + return pos; + } else { + if (Mode > REA) + WriteBuff(); + else + Lim = 0; + + Ptr = 0; + return BufMark = IOHAND::Seek(pos); + } +} + + +void CFILE::Append(CFILE &f) { + Seek(Size()); + if (f.Error == 0) { + while (true) { + if ((Lim = f.IOHAND::Read(Buff, IOBUF_SIZE)) == IOBUF_SIZE) + WriteBuff(); + else + break; + if ((Error = f.Error) != 0) + break; + } + } +} + +} // End of namespace CGE diff --git a/engines/cge/cfile.h b/engines/cge/cfile.h new file mode 100644 index 0000000000..f045c48c0f --- /dev/null +++ b/engines/cge/cfile.h @@ -0,0 +1,79 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CFILE__ +#define __CFILE__ + +#include "cge/general.h" + +namespace CGE { + +#define LINE_MAX 512 + +#ifndef IOBUF_SIZE +#define IOBUF_SIZE K(2) +#endif + +#define CFREAD(x) Read((uint8 *)(x),sizeof(*(x))) + + +class IOBUF : public IOHAND { +protected: + uint8 *Buff; + uint16 Ptr, Lim; + long BufMark; + uint16 Seed; + CRYPT *Crypt; + virtual void ReadBuff(void); + virtual void WriteBuff(void); +public: + IOBUF(IOMODE mode, CRYPT *crpt = NULL); + IOBUF(const char *name, IOMODE mode, CRYPT *crpt = NULL); + virtual ~IOBUF(void); + uint16 Read(void *buf, uint16 len); + uint16 Read(uint8 *buf); + int Read(void); + uint16 Write(void *buf, uint16 len); + uint16 Write(uint8 *buf); + void Write(uint8 b); +}; + + +class CFILE : public IOBUF { +public: + static uint16 MaxLineLen; + CFILE(const char *name, IOMODE mode = REA, CRYPT *crpt = NULL); + virtual ~CFILE(void); + void Flush(void); + long Mark(void); + long Seek(long pos); + void Append(CFILE &f); +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/cge.cpp b/engines/cge/cge.cpp new file mode 100644 index 0000000000..885aa4d492 --- /dev/null +++ b/engines/cge/cge.cpp @@ -0,0 +1,164 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" +#include "common/config-manager.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/error.h" +#include "common/EventRecorder.h" +#include "common/file.h" +#include "common/fs.h" +#include "engines/util.h" +#include "cge/cge.h" +#include "cge/vga13h.h" +#include "cge/cge_main.h" +#include "cge/talk.h" +#include "cge/text.h" +#include "cge/bitmaps.h" +#include "cge/vol.h" + + +namespace CGE { + +CGEEngine::CGEEngine(OSystem *syst, const ADGameDescription *gameDescription) + : Engine(syst), _gameDescription(gameDescription) { + + // Debug/console setup + DebugMan.addDebugChannel(kCGEDebug, "general", "CGE general debug channel"); + + _isDemo = _gameDescription->flags & ADGF_DEMO; + +} + +void CGEEngine::setup() { + // Create debugger console + _console = new CGEConsole(this); + + // Initialise classes that have static members + VGA::init(); + VFILE::init(); + Bitmap::init(); + TALK::init(); + + // Initialise engine objects + Text = new TEXT(this, ProgName(), 128); + Vga = new VGA(M13H); + _heart = new Heart; + Hero = new WALK(this, NULL); + Sys = new SYSTEM(this); + _pocLight = new Sprite(this, LI); + Mouse = new MOUSE(this); + for (int i = 0; i < POCKET_NX; i++) + _pocket[i] = new Sprite(this, NULL); + _sprite = new Sprite(this, NULL); + _miniCave = new Sprite(this, NULL); + _shadow = new Sprite(this, NULL); + _horzLine = new Sprite(this, HL); + InfoLine = new INFO_LINE(this, INFO_W); + _cavLight = new Sprite(this, PR); + DebugLine = new INFO_LINE(this, SCR_WID); + MB[0] = new Bitmap("BRICK"); + MB[1] = NULL; + HL[0] = new Bitmap("HLINE"); + HL[1] = NULL; + MC[0] = new Bitmap("MOUSE"); + MC[1] = new Bitmap("DUMMY"); + MC[2] = NULL; + PR[0] = new Bitmap("PRESS"); + PR[1] = NULL; + SP[0] = new Bitmap("SPK_L"); + SP[1] = new Bitmap("SPK_R"); + SP[2] = NULL; + LI[0] = new Bitmap("LITE0"); + LI[1] = new Bitmap("LITE1"); + LI[2] = new Bitmap("LITE2"); + LI[3] = new Bitmap("LITE3"); + LI[4] = NULL; + Snail = new SNAIL(this, false); + Snail_ = new SNAIL(this, true); + + OffUseCount = atoi(Text->getText(OFF_USE_COUNT)); +} + +CGEEngine::~CGEEngine() { + debug("CGEEngine::~CGEEngine"); + + // Call classes with static members to clear them up + TALK::deinit(); + Bitmap::deinit(); + VFILE::deinit(); + VGA::deinit(); + + // Remove all of our debug levels here + DebugMan.clearAllDebugChannels(); + + _console = new CGEConsole(this); + + // Delete engine objects + delete Text; + delete Vga; + delete _heart; + delete Hero; + delete Sys; + delete _pocLight; + delete Mouse; + for (int i = 0; i < POCKET_NX; i++) + delete _pocket[i]; + delete _sprite; + delete _miniCave; + delete _shadow; + delete _horzLine; + delete InfoLine; + delete _cavLight; + delete DebugLine; + delete MB[0]; + delete HL[0]; + delete MC[0]; + delete MC[1]; + delete PR[0]; + delete SP[0]; + delete SP[1]; + delete LI[0]; + delete LI[1]; + delete LI[2]; + delete LI[3]; + delete Snail; + delete Snail_; +} + +Common::Error CGEEngine::run() { + // Initialize graphics using following: + initGraphics(320, 200, false); + + // Setup necessary game objects + setup(); + + // Additional setup. + debug("CGEEngine::init"); + + cge_main(); + + return Common::kNoError; +} + +} // End of namespace CGE diff --git a/engines/cge/cge.h b/engines/cge/cge.h new file mode 100644 index 0000000000..c3f241b2fe --- /dev/null +++ b/engines/cge/cge.h @@ -0,0 +1,108 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#ifndef CGE_H +#define CGE_H + +#include "cge/general.h" +#include "common/random.h" +#include "engines/engine.h" +#include "gui/debugger.h" +#include "graphics/surface.h" +#include "engines/advancedDetector.h" +#include "cge/console.h" + +#define CGE_SAVEGAME_VERSION 1 + +namespace CGE { + +class Console; + +// our engine debug channels +enum { + kCGEDebug = 1 << 0 +}; + +class CGEEngine : public Engine { +public: + CGEEngine(OSystem *syst, const ADGameDescription *gameDescription); + ~CGEEngine(); + + const ADGameDescription *_gameDescription; + bool _isDemo; + + virtual Common::Error run(); + GUI::Debugger *getDebugger() { + return _console; + } + + void cge_main(); + void SwitchCave(int cav); + void StartCountDown(); + void Quit(); + void ResetQSwitch(); + void OptionTouch(int opt, uint16 mask); + void LoadGame(XFILE &file, bool tiny); + void SetMapBrick(int x, int z); + void SwitchMapping(); + void LoadSprite(const char *fname, int ref, int cav, int col, int row, int pos); + void LoadScript(const char *fname); + void LoadUser(); + void RunGame(); + bool ShowTitle(const char *name); + void Movie(const char *ext); + void TakeName(); + void Inf(const char *txt); + void SelectSound(); + void SNSelect(); + void dummy() {} + void NONE(); + void SB(); + void CaveDown(); + void XCave(); + void QGame(); + void SBM(); + void GUS(); + void GUSM(); + void MIDI(); + void AUTO(); + void SetPortD(); + void SetPortM(); + void SetIRQ(); + void SetDMA(); + void MainLoop(); + +private: + CGEConsole *_console; + void setup(); +}; + +// Example console class +class Console : public GUI::Debugger { +public: + Console(CGEEngine *vm) {} + virtual ~Console(void) {} +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/cge_main.cpp b/engines/cge/cge_main.cpp new file mode 100644 index 0000000000..1e1b952f77 --- /dev/null +++ b/engines/cge/cge_main.cpp @@ -0,0 +1,1874 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "common/scummsys.h" +#include "cge/general.h" +#include "cge/boot.h" +#include "cge/ident.h" +#include "cge/sound.h" +#include "cge/startup.h" +#include "cge/config.h" +#include "cge/vga13h.h" +#include "cge/snail.h" +#include "cge/text.h" +#include "cge/game.h" +#include "cge/mouse.h" +#include "cge/keybd.h" +#include "cge/cfile.h" +#include "cge/vol.h" +#include "cge/talk.h" +#include "cge/vmenu.h" +#include "cge/gettext.h" +#include "cge/mixer.h" +#include "cge/cge_main.h" +#include "cge/cge.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include "common/str.h" + +namespace CGE { + +#define STACK_SIZ (K(2)) +#define SVGCHKSUM (1956 + Now + OldLev + Game + Music + DemoText) + +#define SVG0NAME ("{{INIT}}" SVG_EXT) +#define SVG0FILE INI_FILE + +extern uint16 _stklen = (STACK_SIZ * 2); + +VGA *Vga; +Heart *_heart; +WALK *Hero; +SYSTEM *Sys; +Sprite *_pocLight; +MOUSE *Mouse; +Sprite *_pocket[POCKET_NX]; +Sprite *_sprite; +Sprite *_miniCave; +Sprite *_shadow; +Sprite *_horzLine; +INFO_LINE *InfoLine; +Sprite *_cavLight; +INFO_LINE *DebugLine; + +BMP_PTR MB[2]; +BMP_PTR HL[2]; +BMP_PTR MC[3]; +BMP_PTR PR[2]; +BMP_PTR SP[3]; +BMP_PTR LI[5]; + +SNAIL *Snail; +SNAIL *Snail_; + +// 0.75 - 17II95 - full sound support +// 0.76 - 18II95 - small MiniEMS in DEMO, +// unhide CavLight in SNLEVEL +// keyclick suppress in startup +// keyclick on key service in: SYSTEM, GET_TEXT +// 1.01 - 17VII95 - default savegame with sound ON +// coditionals EVA for 2-month evaluation version + +/* + char Copr[] = "Common Game Engine " + #ifdef EVA + "ú" + #else + #ifdef CD + "ù" + #else + " " + #endif + #endif + " version 1.05 [" + #if sizeof(INI_FILE) == sizeof(VFILE) + "I" + #else + "i" + #endif + #if sizeof(PIC_FILE) == sizeof(VFILE) + "B" + #else + "b" + #endif + "]\n" + "Copyright (c) 1994 by Janusz B. Wi$niewski"; +*/ +char Copr[] = "To be fixed - Copr[]"; + +static char UsrFnam[15] = "\0ɱ%^þúȼ´ ÇÉ"; +static int OldLev = 0; +static int DemoText = DEMO_TEXT; + +//-------------------------------------------------------------------------- + +bool JBW = false; + +//------------------------------------------------------------------------- +int PocPtr = 0; + +static EMS *Mini = MiniEmm.Alloc((uint16)MINI_EMM_SIZE); +static BMP_PTR *MiniShpList = NULL; +static BMP_PTR MiniShp[] = { NULL, NULL }; +static KEYBOARD Keyboard; +static bool Finis = false; +static int Startup = 1; +int OffUseCount; +uint16 *intStackPtr = false; + +HXY HeroXY[CAVE_MAX] = {{0, 0}}; +BAR Barriers[1 + CAVE_MAX] = { { 0xFF, 0xFF } }; + + +extern int FindPocket(Sprite *); + +extern DAC StdPal[58]; + +void FeedSnail(Sprite *spr, SNLIST snq); // defined in SNAIL +uint8 CLUSTER::Map[MAP_ZCNT][MAP_XCNT]; + + +uint8 &CLUSTER::Cell(void) { + return Map[B][A]; +} + + +bool CLUSTER::Protected(void) { +/* + if (A == Barriers[Now].Vert || B == Barriers[Now].Horz) + return true; + + _DX = (MAP_ZCNT << 8) + MAP_XCNT; + _BX = (uint16) this; + + asm mov ax,1 + asm mov cl,[bx].(COUPLE)A + asm mov ch,[bx].(COUPLE)B + asm test cx,0x8080 // (A < 0) || (B < 0) + asm jnz xit + + asm cmp cl,dl + asm jge xit + asm cmp ch,dh + asm jge xit + + // if (A < 0 || A >= MAP_XCNT || B < 0 || B >= MAP_ZCNT) return true; + + asm mov al,dl + asm mul ch + asm xor ch,ch + asm add ax,cx + asm mov bx,ax + _BX += (uint16) Map; + //asm add bx,offset CLUSTER::Map + asm mov al,[bx] + asm and ax,0xFF + asm jz xit + asm mov ax,1 + + // return Map[B][A] != 0; + + xit: return _AX; + */ + + warning("STUB: CLUSTER::Protected()"); + return true; +} + + +CLUSTER XZ(int x, int y) { + if (y < MAP_TOP) + y = MAP_TOP; + + if (y > MAP_TOP + MAP_HIG - MAP_ZGRID) + y = MAP_TOP + MAP_HIG - MAP_ZGRID; + + return CLUSTER(x / MAP_XGRID, (y - MAP_TOP) / MAP_ZGRID); +} + + +CLUSTER XZ(COUPLE xy) { + signed char x, y; + xy.Split(x, y); + return XZ(x, y); +} + + +int pocref[POCKET_NX]; +uint8 volume[2]; + +struct SavTab { + void *Ptr; + int Len; + uint8 Flg; +}; + +SavTab _savTab[] = { + { &Now, sizeof(Now), 1 }, + { &OldLev, sizeof(OldLev), 1 }, + { &DemoText, sizeof(DemoText), 1 }, + { &Game, sizeof(Game), 1 }, + { &Game, sizeof(Game), 1 }, // spare 1 + { &Game, sizeof(Game), 1 }, // spare 2 + { &Game, sizeof(Game), 1 }, // spare 3 + { &Game, sizeof(Game), 1 }, // spare 4 +// { &VGA::Mono, sizeof(VGA::Mono), 0 }, + { &Music, sizeof(Music), 1 }, + { volume, sizeof(volume), 1 }, + { Flag, sizeof(Flag), 1 }, + { HeroXY, sizeof(HeroXY), 1 }, + { Barriers, sizeof(Barriers), 1 }, + { pocref, sizeof(pocref), 1 }, + { NULL, 0, 0 } +}; + + +void CGEEngine::LoadGame(XFILE &file, bool tiny = false) { + SavTab *st; + Sprite *spr; + int i; + + for (st = _savTab; st->Ptr; st++) { + if (file.Error) + error("Bad SVG"); + file.Read((uint8 *)((tiny || st->Flg) ? st->Ptr : &i), st->Len); + } + + file.Read((uint8 *) &i, sizeof(i)); + if (i != SVGCHKSUM) + error("%s", Text->getText(BADSVG_TEXT)); + + if (STARTUP::Core < CORE_HIG) + Music = false; + + if (STARTUP::SoundOk == 1 && STARTUP::Mode == 0) { + SNDDrvInfo.VOL2.D = volume[0]; + SNDDrvInfo.VOL2.M = volume[1]; + SNDSetVolume(); + } + + if (! tiny) { // load sprites & pocket + while (! file.Error) { + Sprite S(this, NULL); + uint16 n = file.Read((uint8 *) &S, sizeof(S)); + + if (n != sizeof(S)) + break; + + S._prev = S._next = NULL; + spr = (scumm_stricmp(S.File + 2, "MUCHA") == 0) ? new FLY(this, NULL) + : new Sprite(this, NULL); + if (spr == NULL) + error("No core"); + *spr = S; + Vga->SpareQ->Append(spr); + } + + for (i = 0; i < POCKET_NX; i++) { + register int r = pocref[i]; + _pocket[i] = (r < 0) ? NULL : Vga->SpareQ->Locate(r); + } + } +} + + +static void SaveSound(void) { + CFILE cfg(UsrPath(ProgName(CFG_EXT)), WRI); + if (! cfg.Error) cfg.Write(&SNDDrvInfo, sizeof(SNDDrvInfo) - sizeof(SNDDrvInfo.VOL2)); +} + + +static void SaveGame(XFILE &file) { + SavTab *st; + Sprite *spr; + int i; + + for (i = 0; i < POCKET_NX; i++) { + register Sprite *s = _pocket[i]; + pocref[i] = (s) ? s->_ref : -1; + } + + volume[0] = SNDDrvInfo.VOL2.D; + volume[1] = SNDDrvInfo.VOL2.M; + + for (st = _savTab; st->Ptr; st++) { + if (file.Error) + error("Bad SVG"); + file.Write((uint8 *) st->Ptr, st->Len); + } + + file.Write((uint8 *) & (i = SVGCHKSUM), sizeof(i)); + + for (spr = Vga->SpareQ->First(); spr; spr = spr->_next) + if (spr->_ref >= 1000) + if (!file.Error) + file.Write((uint8 *)spr, sizeof(*spr)); +} + + +static void HeroCover(int cvr) { + SNPOST(SNCOVER, 1, cvr, NULL); +} + + +static void Trouble(int seq, int txt) { + Hero->Park(); + SNPOST(SNWAIT, -1, -1, Hero); + SNPOST(SNSEQ, -1, seq, Hero); + SNPOST(SNSOUND, -1, 2, Hero); + SNPOST(SNWAIT, -1, -1, Hero); + SNPOST(SNSAY, 1, txt, Hero); +} + + +static void OffUse(void) { + Trouble(OFF_USE, OFF_USE_TEXT + new_random(OffUseCount)); +} + + +static void TooFar(void) { + Trouble(TOO_FAR, TOO_FAR_TEXT); +} + + +// Used in stubbed function, do not remove! +static void NoWay(void) { + Trouble(NO_WAY, NO_WAY_TEXT); +} + + +static void LoadHeroXY(void) { + INI_FILE cf(ProgName(".HXY")); + memset(HeroXY, 0, sizeof(HeroXY)); + if (! cf.Error) + cf.CFREAD(&HeroXY); +} + + +static void LoadMapping(void) { + if (Now <= CAVE_MAX) { + INI_FILE cf(ProgName(".TAB")); + if (! cf.Error) { + memset(CLUSTER::Map, 0, sizeof(CLUSTER::Map)); + cf.Seek((Now - 1) * sizeof(CLUSTER::Map)); + cf.Read((uint8 *) CLUSTER::Map, sizeof(CLUSTER::Map)); + } + } +} + + +CLUSTER Trace[MAX_FIND_LEVEL]; +int FindLevel; + + +WALK::WALK(CGEEngine *vm, BMP_PTR *shpl) + : Sprite(vm, shpl), Dir(NO_DIR), TracePtr(-1), _vm(vm) { +} + + +void WALK::Tick(void) { + if (_flags._hide) + return; + + Here = XZ(_x + _w / 2, _y + _h); + + if (Dir != NO_DIR) { + Sprite *spr; + Sys->FunTouch(); + for (spr = Vga->ShowQ->First(); spr; spr = spr->_next) { + if (Distance(spr) < 2) { + if (!spr->_flags._near) { + FeedSnail(spr, NEAR); + spr->_flags._near = true; + } + } else { + spr->_flags._near = false; + } + } + } + + if (_flags._hold || TracePtr < 0) + Park(); + else { + if (Here == Trace[TracePtr]) { + if (--TracePtr < 0) + Park(); + } else { + signed char dx, dz; + (Trace[TracePtr] - Here).Split(dx, dz); + DIR d = (dx) ? ((dx > 0) ? EE : WW) : ((dz > 0) ? SS : NN); + Turn(d); + } + } + Step(); + if ((Dir == WW && _x <= 0) || + (Dir == EE && _x + _w >= SCR_WID) || + (Dir == SS && _y + _w >= WORLD_HIG - 2)) + Park(); + else { + signed char x; // dummy var + Here.Split(x, _z); // take current Z position + SNPOST_(SNZTRIM, -1, 0, this); // update Hero's pos in show queue + } +} + + +int WALK::Distance(Sprite *spr) { + int dx, dz; + dx = spr->_x - (_x + _w - WALKSIDE); + if (dx < 0) + dx = (_x + WALKSIDE) - (spr->_x + spr->_w); + + if (dx < 0) + dx = 0; + + dx /= MAP_XGRID; + dz = spr->_z - _z; + if (dz < 0) + dz = - dz; + + dx = dx * dx + dz * dz; + for (dz = 1; dz * dz < dx; dz++) + ; + + return dz - 1; +} + + +void WALK::Turn(DIR d) { + DIR dir = (Dir == NO_DIR) ? SS : Dir; + if (d != Dir) { + Step((d == dir) ? (1 + dir + dir) : (9 + 4 * dir + d)); + Dir = d; + } +} + + +void WALK::Park(void) { + if (_time == 0) + ++_time; + + if (Dir != NO_DIR) { + Step(9 + 4 * Dir + Dir); + Dir = NO_DIR; + TracePtr = -1; + } +} + + +void WALK::FindWay(CLUSTER c) { + warning("STUB: Find1Way"); + /* + bool Find1Way(void); + extern uint16 Target; + + if (c != Here) { + for (FindLevel = 1; FindLevel <= MAX_FIND_LEVEL; FindLevel++) { + signed char x, z; + Here.Split(x, z); + Target = (z << 8) | x; + c.Split(x, z); + _CX = (z << 8) | x; + if (Find1Way()) + break; + } + TracePtr = (FindLevel > MAX_FIND_LEVEL) ? -1 : (FindLevel - 1); + if (TracePtr < 0) + NoWay(); + Time = 1; + } +*/ +} + + +void WALK::FindWay(Sprite *spr) { + if (spr && spr != this) { + int x = spr->_x; + int z = spr->_z; + if (spr->_flags._east) + x += spr->_w + _w / 2 - WALKSIDE; + else + x -= _w / 2 - WALKSIDE; + FindWay(CLUSTER((x / MAP_XGRID), + ((z < MAP_ZCNT - MAX_DISTANCE) ? (z + 1) + : (z - 1)))); + } +} + + +bool WALK::Lower(Sprite *spr) { + return (spr->_y > _y + (_h * 3) / 5); +} + + +void WALK::Reach(Sprite *spr, int mode) { + if (spr) { + Hero->FindWay(spr); + if (mode < 0) { + mode = spr->_flags._east; + if (Lower(spr)) + mode += 2; + } + } + // note: insert SNAIL commands in reverse order + SNINSERT(SNPAUSE, -1, 64, NULL); + SNINSERT(SNSEQ, -1, TSEQ + mode, this); + if (spr) { + SNINSERT(SNWAIT, -1, -1, Hero); /////--------$$$$$$$ + //SNINSERT(SNWALK, -1, -1, spr); + } + // sequence is not finished, + // now it is just at sprite appear (disappear) point +} + + +class SQUARE : public Sprite { +public: + SQUARE(CGEEngine *vm); + void Touch(uint16 mask, int x, int y); +private: + CGEEngine *_vm; +}; + + +SQUARE::SQUARE(CGEEngine *vm) + : Sprite(vm, MB), _vm(vm) { + _flags._kill = true; + _flags._bDel = false; +} + + +void SQUARE::Touch(uint16 mask, int x, int y) { + Sprite::Touch(mask, x, y); + if (mask & L_UP) { + XZ(_x + x, _y + y).Cell() = 0; + SNPOST_(SNKILL, -1, 0, this); + } +} + + +void CGEEngine::SetMapBrick(int x, int z) { + SQUARE *s = new SQUARE(this); + if (s) { + static char n[] = "00:00"; + s->Goto(x * MAP_XGRID, MAP_TOP + z * MAP_ZGRID); + wtom(x, n + 0, 10, 2); + wtom(z, n + 3, 10, 2); + CLUSTER::Map[z][x] = 1; + s->SetName(n); + Vga->ShowQ->Insert(s, Vga->ShowQ->First()); + } +} + +static void SwitchColorMode(void); +static void SwitchDebug(void); +static void SwitchMusic(void); +static void KillSprite(void); +static void PushSprite(void); +static void PullSprite(void); +static void NextStep(void); +static void SaveMapping(void); + +static void KeyClick(void) { + SNPOST_(SNSOUND, -1, 5, NULL); +} + + +void CGEEngine::ResetQSwitch() { + SNPOST_(SNSEQ, 123, 0, NULL); + KeyClick(); +} + + +void CGEEngine::Quit() { + static CHOICE QuitMenu[] = { + { NULL, &CGEEngine::StartCountDown }, + { NULL, &CGEEngine::ResetQSwitch }, + { NULL, &CGEEngine::dummy } + }; + + if (Snail->Idle() && ! Hero->_flags._hide) { + if (VMENU::Addr) { + SNPOST_(SNKILL, -1, 0, VMENU::Addr); + ResetQSwitch(); + } else { + QuitMenu[0].Text = Text->getText(QUIT_TEXT); + QuitMenu[1].Text = Text->getText(NOQUIT_TEXT); + (new VMENU(this, QuitMenu, -1, -1))->SetName(Text->getText(QUIT_TITLE)); + SNPOST_(SNSEQ, 123, 1, NULL); + KeyClick(); + } + } +} + + +static void AltCtrlDel(void) { + SNPOST_(SNSAY, -1, A_C_D_TEXT, Hero); +} + +// Used in stubbed function, do not remove! +static void MiniStep(int stp) { + if (stp < 0) + _miniCave->_flags._hide = true; + else { + &*Mini; + *MiniShp[0] = *MiniShpList[stp]; + if (Fx.Current) + &*(Fx.Current->EAddr()); + + _miniCave->_flags._hide = false; + } +} + + +static void PostMiniStep(int stp) { + //static int recent = -2; + //TODO Change the SNPOST message send to a special way to send function pointer + //if (MiniCave && stp != recent) SNPOST_(SNEXEC, -1, recent = stp, (void *)&MiniStep); + warning("STUB: PostMiniStep()"); +} + +void SYSTEM::SetPal(void) { + uint i; + DAC *p = VGA::SysPal + 256 - ArrayCount(StdPal); + for (i = 0; i < ArrayCount(StdPal); i++) { + p[i].R = StdPal[i].R >> 2; + p[i].G = StdPal[i].G >> 2; + p[i].B = StdPal[i].B >> 2; + } +} + + +void SYSTEM::FunTouch(void) { + uint16 n = (PAIN) ? HEROFUN1 : HEROFUN0; + if (Talk == NULL || n > FunDel) + FunDel = n; +} + + +static void ShowBak(int ref) { + Sprite *spr = Vga->SpareQ->Locate(ref); + if (spr) { + Bitmap::Pal = VGA::SysPal; + spr->Expand(); + Bitmap::Pal = NULL; + spr->Show(2); + Vga->CopyPage(1, 2); + Sys->SetPal(); + spr->Contract(); + } +} + + +static void CaveUp(void) { + int BakRef = 1000 * Now; + if (Music) + LoadMIDI(Now); + + ShowBak(BakRef); + LoadMapping(); + Text->Preload(BakRef, BakRef + 1000); + Sprite *spr = Vga->SpareQ->First(); + while (spr) { + Sprite *n = spr->_next; + if (spr->_cave == Now || spr->_cave == 0) + if (spr->_ref != BakRef) { + if (spr->_flags._back) + spr->BackShow(); + else + ExpandSprite(spr); + } + spr = n; + } + if (SNDDrvInfo.DDEV) { + Sound.Stop(); + Fx.Clear(); + Fx.Preload(0); + Fx.Preload(BakRef); + } + + if (Hero) { + Hero->Goto(HeroXY[Now - 1]._x, HeroXY[Now - 1]._y); + // following 2 lines trims Hero's Z position! + Hero->Tick(); + Hero->_time = 1; + Hero->_flags._hide = false; + } + + if (! Dark) + Vga->Sunset(); + + Vga->CopyPage(0, 1); + SelectPocket(-1); + if (Hero) + Vga->ShowQ->Insert(Vga->ShowQ->Remove(Hero)); + + if (_shadow) { + Vga->ShowQ->Remove(_shadow); + _shadow->MakeXlat(Glass(VGA::SysPal, 204, 204, 204)); + Vga->ShowQ->Insert(_shadow, Hero); + _shadow->_z = Hero->_z; + } + FeedSnail(Vga->ShowQ->Locate(BakRef + 999), TAKE); + Vga->Show(); + Vga->CopyPage(1, 0); + Vga->Show(); + Vga->Sunrise(VGA::SysPal); + Dark = false; + if (! Startup) + Mouse->On(); + + _heart->_enable = true; +} + + +void CGEEngine::CaveDown() { + Sprite *spr; + if (!_horzLine->_flags._hide) + SwitchMapping(); + + for (spr = Vga->ShowQ->First(); spr;) { + Sprite *n = spr->_next; + if (spr->_ref >= 1000 /*&& spr->_cave*/) { + if (spr->_ref % 1000 == 999) + FeedSnail(spr, TAKE); + Vga->SpareQ->Append(Vga->ShowQ->Remove(spr)); + } + spr = n; + } + Text->Clear(1000); +} + + +void CGEEngine::XCave() { + CaveDown(); + CaveUp(); +} + + +void CGEEngine::QGame() { + CaveDown(); + OldLev = Lev; + SaveSound(); + CFILE file = CFILE(UsrPath(UsrFnam), WRI, RCrypt); + SaveGame(file); + Vga->Sunset(); + Finis = true; +} + + +void CGEEngine::SwitchCave(int cav) { + if (cav != Now) { + _heart->_enable = false; + if (cav < 0) { + SNPOST(SNLABEL, -1, 0, NULL); // wait for repaint + //TODO Change the SNPOST message send to a special way to send function pointer + //SNPOST(SNEXEC, -1, 0, (void *)&QGame); // switch cave + warning("SwitchCave() - SNPOST"); + } else { + Now = cav; + Mouse->Off(); + if (Hero) { + Hero->Park(); + Hero->Step(0); + if (!_isDemo) + ///// protection: auto-destruction on! ---------------------- + Vga->SpareQ->Show = STARTUP::Summa * (cav <= CAVE_MAX); + /////-------------------------------------------------------- + } + _cavLight->Goto(CAVE_X + ((Now - 1) % CAVE_NX) * CAVE_DX + CAVE_SX, + CAVE_Y + ((Now - 1) / CAVE_NX) * CAVE_DY + CAVE_SY); + KillText(); + if (! Startup) + KeyClick(); + SNPOST(SNLABEL, -1, 0, NULL); // wait for repaint + //TODO Change the SNPOST message send to a special way to send function pointer + //SNPOST(SNEXEC, 0, 0, (void *)&XCave); // switch cave + warning("SwitchCave() - SNPOST"); + } + } +} + +SYSTEM::SYSTEM(CGEEngine *vm) : Sprite(vm, NULL), _vm(vm) { + FunDel = HEROFUN0; + SetPal(); + Tick(); +} + +void SYSTEM::Touch(uint16 mask, int x, int y) { + static int pp = 0; + + FunTouch(); + + if (mask & KEYB) { + int pp0; + KeyClick(); + KillText(); + if (Startup == 1) { + SNPOST(SNCLEAR, -1, 0, NULL); + return; + } + pp0 = pp; + switch (x) { + case Del: + if (KEYBOARD::Key[ALT] && KEYBOARD::Key[CTRL]) + AltCtrlDel(); + else + KillSprite(); + break; + case 'F': + if (KEYBOARD::Key[ALT]) { + Sprite *m = Vga->ShowQ->Locate(17001); + if (m) { + m->Step(1); + m->_time = 216; // 3s + } + } + break; + case PgUp: + PushSprite(); + break; + case PgDn: + PullSprite(); + break; + case '+': + NextStep(); + break; + case '`': + if (KEYBOARD::Key[ALT]) + SaveMapping(); + else + _vm->SwitchMapping(); + break; + case F1: + SwitchDebug(); + break; + case F3: + Hero->Step(TSEQ + 4); + break; + case F4: + Hero->Step(TSEQ + 5); + break; + case F5: + Hero->Step(TSEQ + 0); + break; + case F6: + Hero->Step(TSEQ + 1); + break; + case F7: + Hero->Step(TSEQ + 2); + break; + case F8: + Hero->Step(TSEQ + 3); + break; + case F9: + Sys->FunDel = 1; + break; + case 'X': + if (KEYBOARD::Key[ALT]) + Finis = true; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + if (KEYBOARD::Key[ALT]) { + SNPOST(SNLEVEL, -1, x - '0', NULL); + break; + } + case '5': + case '6': + case '7': + case '8': + case '9': + if (_sprite) + _sprite->Step(x - '0'); + break; + case F10 : + if (Snail->Idle() && ! Hero->_flags._hide) + _vm->StartCountDown(); + break; + case 'J': + if (pp == 0) + ++pp; + break; + case 'B': + if (pp == 1) + ++pp; + break; + case 'W': + if (pp == 2) + JBW = !JBW; + break; + } + if (pp == pp0) + pp = 0; + } else { + if (Startup) + return; + int cav = 0; + InfoLine->Update(NULL); + if (y >= WORLD_HIG) { + if (x < BUTTON_X) { // select cave? + if (y >= CAVE_Y && y < CAVE_Y + CAVE_NY * CAVE_DY && + x >= CAVE_X && x < CAVE_X + CAVE_NX * CAVE_DX && ! Game) { + cav = ((y - CAVE_Y) / CAVE_DY) * CAVE_NX + (x - CAVE_X) / CAVE_DX + 1; + if (cav > MaxCave) + cav = 0; + } else { + cav = 0; + } + } else if (mask & L_UP) { + if (y >= POCKET_Y && y < POCKET_Y + POCKET_NY * POCKET_DY && + x >= POCKET_X && x < POCKET_X + POCKET_NX * POCKET_DX) { + int n = ((y - POCKET_Y) / POCKET_DY) * POCKET_NX + (x - POCKET_X) / POCKET_DX; + SelectPocket(n); + } + } + } + + PostMiniStep(cav - 1); + + if (mask & L_UP) { + if (cav && Snail->Idle() && Hero->TracePtr < 0) + _vm->SwitchCave(cav); + + if (!_horzLine->_flags._hide) { + if (y >= MAP_TOP && y < MAP_TOP + MAP_HIG) { + int8 x1, z1; + XZ(x, y).Split(x1, z1); + CLUSTER::Map[z1][x1] = 1; + _vm->SetMapBrick(x1, z1); + } + } else + { + if (! Talk && Snail->Idle() && Hero + && y >= MAP_TOP && y < MAP_TOP + MAP_HIG && ! Game) { + Hero->FindWay(XZ(x, y)); + } + } + } + } +} + + +void SYSTEM::Tick(void) { + if (! Startup) if (-- FunDel == 0) { + KillText(); + if (Snail->Idle()) { + if (PAIN) + HeroCover(9); + else if (STARTUP::Core >= CORE_MID) { + int n = new_random(100); + if (n > 96) + HeroCover(6 + (Hero->_x + Hero->_w / 2 < SCR_WID / 2)); + else { + if (n > 90) + HeroCover(5); + else { + if (n > 60) + HeroCover(4); + else + HeroCover(3); + } + } + } + } + FunTouch(); + } + _time = SYSTIMERATE; +} + + +/* +static void SpkOpen(void) { + asm in al,0x61 + asm or al,0x03 + asm out 0x61,al + asm mov al,0x90 + asm out 0x43,al +} + + +static void SpkClose(void) { + asm in al,0x61 + asm and al,0xFC + asm out 0x61,al +} + +*/ + + +static void SwitchColorMode(void) { + SNPOST_(SNSEQ, 121, Vga->Mono = !Vga->Mono, NULL); + KeyClick(); + Vga->SetColors(VGA::SysPal, 64); +} + + + +static void SwitchMusic(void) { + if (KEYBOARD::Key[ALT]) { + if (VMENU::Addr) + SNPOST_(SNKILL, -1, 0, VMENU::Addr); + else { + SNPOST_(SNSEQ, 122, (Music = false), NULL); + //TODO Change the SNPOST message send to a special way to send function pointer + // SNPOST(SNEXEC, -1, 0, (void *)&SelectSound); + warning("SwitchMusic() - SNPOST"); + } + } else { + if (STARTUP::Core < CORE_HIG) + SNPOST(SNINF, -1, NOMUSIC_TEXT, NULL); + else { + SNPOST_(SNSEQ, 122, (Music = ! Music), NULL); + KeyClick(); + } + } + if (Music) + LoadMIDI(Now); + else + KillMIDI(); +} + + +void CGEEngine::StartCountDown() { + //SNPOST(SNSEQ, 123, 0, NULL); + SwitchCave(-1); +} + + +void CGEEngine::TakeName() { + if (GET_TEXT::Ptr) + SNPOST_(SNKILL, -1, 0, GET_TEXT::Ptr); + else { + GET_TEXT *tn = new GET_TEXT(this, Text->getText(GETNAME_PROMPT), UsrFnam, 8, KeyClick); + if (tn) { + tn->SetName(Text->getText(GETNAME_TITLE)); + tn->Center(); + tn->Goto(tn->_x, tn->_y - 10); + tn->_z = 126; + Vga->ShowQ->Insert(tn); + } + } +} + + +void CGEEngine::SwitchMapping() { + if (_horzLine->_flags._hide) { + int i; + for (i = 0; i < MAP_ZCNT; i++) { + int j; + for (j = 0; j < MAP_XCNT; j++) { + if (CLUSTER::Map[i][j]) + SetMapBrick(j, i); + } + } + } else { + Sprite *s; + for (s = Vga->ShowQ->First(); s; s = s->_next) + if (s->_w == MAP_XGRID && s->_h == MAP_ZGRID) + SNPOST_(SNKILL, -1, 0, s); + } + _horzLine->_flags._hide = !_horzLine->_flags._hide; +} + + +static void KillSprite(void) { + _sprite->_flags._kill = true; + _sprite->_flags._bDel = true; + SNPOST_(SNKILL, -1, 0, _sprite); + _sprite = NULL; +} + + +static void PushSprite(void) { + Sprite *spr = _sprite->_prev; + if (spr) { + Vga->ShowQ->Insert(Vga->ShowQ->Remove(_sprite), spr); + while (_sprite->_z > _sprite->_next->_z) + _sprite->_z--; + } else + SNPOST_(SNSOUND, -1, 2, NULL); +} + + +static void PullSprite(void) { + bool ok = false; + Sprite *spr = _sprite->_next; + if (spr) { + spr = spr->_next; + if (spr) + ok = (!spr->_flags._slav); + } + if (ok) { + Vga->ShowQ->Insert(Vga->ShowQ->Remove(_sprite), spr); + if (_sprite->_prev) + while (_sprite->_z < _sprite->_prev->_z) + _sprite->_z++; + } else + SNPOST_(SNSOUND, -1, 2, NULL); +} + + +static void NextStep(void) { + SNPOST_(SNSTEP, 0, 0, _sprite); +} + + +static void SaveMapping(void) { + { + IOHAND cf(ProgName(".TAB"), UPD); + if (!cf.Error) { + cf.Seek((Now - 1) * sizeof(CLUSTER::Map)); + cf.Write((uint8 *) CLUSTER::Map, sizeof(CLUSTER::Map)); + } + } + { + IOHAND cf(ProgName(".HXY"), WRI); + if (!cf.Error) { + HeroXY[Now - 1]._x = Hero->_x; + HeroXY[Now - 1]._y = Hero->_y; + cf.Write((uint8 *) HeroXY, sizeof(HeroXY)); + } + } +} + +// 1111111111222222222233333333 334444444444555555555566666666667777777777 +// 01234567890123456789012345678901234567 890123456789012345678901234567890123456789 +static char DebugText[] = " N=00000 F=000000 X=000 Y=000 FPS=0000\0S=00:00 000:000:000 000:000 00 "; + +#define NFRE (DebugText + 3) +#define FFRE (DebugText + 11) +#define ABSX (DebugText + 20) +#define ABSY (DebugText + 26) +#define FRPS (DebugText + 34) +#define XSPR (DebugText + 38) +#define SP_N (DebugText + 41) +#define SP_S (DebugText + 44) + +#define SP_X (DebugText + 47) +#define SP_Y (DebugText + 51) +#define SP_Z (DebugText + 55) +#define SP_W (DebugText + 59) +#define SP_H (DebugText + 63) +#define SP_F (DebugText + 67) +#define SP__ (DebugText + 70) + +static void SayDebug(void) { + if (!DebugLine->_flags._hide) { + static long t = -1L; + long t1 = Timer(); + + if (t1 - t >= 18) { + static uint32 old = 0L; + uint32 now = Vga->FrmCnt; + dwtom(now - old, FRPS, 10, 4); + old = now; + t = t1; + } + + dwtom(Mouse->_x, ABSX, 10, 3); + dwtom(Mouse->_y, ABSY, 10, 3); +// dwtom(coreleft(), NFRE, 10, 5); +// dwtom(farcoreleft(), FFRE, 10, 6); + + // sprite queue size + uint16 n = 0; + Sprite *spr; + for (spr = Vga->ShowQ->First(); spr; spr = spr->_next) { + ++ n; + if (spr == _sprite) { + *XSPR = ' '; + dwtom(n, SP_N, 10, 2); + dwtom(_sprite->_x, SP_X, 10, 3); + dwtom(_sprite->_y, SP_Y, 10, 3); + dwtom(_sprite->_z, SP_Z, 10, 3); + dwtom(_sprite->_w, SP_W, 10, 3); + dwtom(_sprite->_h, SP_H, 10, 3); + dwtom(*(uint16 *)(&_sprite->_flags), SP_F, 16, 2); + } + } + dwtom(n, SP_S, 10, 2); +// *SP__ = (heapcheck() < 0) ? '!' : ' '; + DebugLine->Update(DebugText); + } +} + + +static void SwitchDebug(void) { + DebugLine->_flags._hide = ! DebugLine->_flags._hide; +} + + +void CGEEngine::OptionTouch(int opt, uint16 mask) { + switch (opt) { + case 1 : + if (mask & L_UP) + SwitchColorMode(); + break; + case 2 : + if (mask & L_UP) + SwitchMusic(); + else if (mask & R_UP) + if (! MIXER::Appear) { + MIXER::Appear = true; + new MIXER(this, BUTTON_X, BUTTON_Y); + } + break; + case 3 : + if (mask & L_UP) + Quit(); + break; + } +} + + +#pragma argsused +void Sprite::Touch(uint16 mask, int x, int y) { + Sys->FunTouch(); + if ((mask & ATTN) == 0) { + InfoLine->Update(Name()); + if (mask & (R_DN | L_DN)) + _sprite = this; + if (_ref / 10 == 12) { + _vm->OptionTouch(_ref % 10, mask); + return; + } + if (_flags._syst) + return; // cannot access system sprites + if (Game) if (mask & L_UP) { + mask &= ~L_UP; + mask |= R_UP; + } + if ((mask & R_UP) && Snail->Idle()) { + Sprite *ps = (_pocLight->_seqPtr) ? _pocket[PocPtr] : NULL; + if (ps) { + if (_flags._kept || Hero->Distance(this) < MAX_DISTANCE) { + if (Works(ps)) { + FeedSnail(ps, TAKE); + } else + OffUse(); + SelectPocket(-1); + } else + TooFar(); + } else { + if (_flags._kept) + mask |= L_UP; + else { + if (Hero->Distance(this) < MAX_DISTANCE) { + /// + if (_flags._port) { + if (FindPocket(NULL) < 0) + PocFul(); + else { + SNPOST(SNREACH, -1, -1, this); + SNPOST(SNKEEP, -1, -1, this); + _flags._port = false; + } + } else { + if (TakePtr != NO_PTR) { + if (SnList(TAKE)[TakePtr].Com == SNNEXT) + OffUse(); + else + FeedSnail(this, TAKE); + } else + OffUse(); + } + }/// + else + TooFar(); + } + } + } + if ((mask & L_UP) && Snail->Idle()) { + if (_flags._kept) { + int n; + for (n = 0; n < POCKET_NX; n++) { + if (_pocket[n] == this) { + SelectPocket(n); + break; + } + } + } else + SNPOST(SNWALK, -1, -1, this); // Hero->FindWay(this); + } + } +} + + +void CGEEngine::LoadSprite(const char *fname, int ref, int cav, int col = 0, int row = 0, int pos = 0) { + static const char *Comd[] = { "Name", "Type", "Phase", "East", + "Left", "Right", "Top", "Bottom", + "Seq", "Near", "Take", + "Portable", "Transparent", + NULL + }; + static const char *Type[] = { "DEAD", "AUTO", "WALK", "NEWTON", "LISSAJOUS", + "FLY", NULL + }; + char line[LINE_MAX]; + + int shpcnt = 0; + int type = 0; // DEAD + bool east = false; + bool port = false; + bool tran = false; + int i, lcnt = 0; + uint16 len; + + MergeExt(line, fname, SPR_EXT); + if (INI_FILE::Exist(line)) { // sprite description file exist + INI_FILE sprf(line); + if (sprf.Error) + error("Bad SPR [%s]", line); + + while ((len = sprf.Read((uint8 *)line)) != 0) { + ++ lcnt; + if (len && line[len - 1] == '\n') + line[-- len] = '\0'; + if (len == 0 || *line == '.') + continue; + + if ((i = TakeEnum(Comd, strtok(line, " =\t"))) < 0) + error("%s [%s]", NumStr("Bad line ######", lcnt), (const char *)fname); + + + switch (i) { + case 0 : // Name - will be taken in Expand routine + break; + case 1 : // Type + if ((type = TakeEnum(Type, strtok(NULL, " \t,;/"))) < 0) + error("%s [%s]", NumStr("Bad line ######", lcnt), (const char *)fname); + break; + case 2 : // Phase + ++ shpcnt; + break; + case 3 : // East + east = (atoi(strtok(NULL, " \t,;/")) != 0); + break; + case 11 : // Portable + port = (atoi(strtok(NULL, " \t,;/")) != 0); + break; + case 12 : // Transparent + tran = (atoi(strtok(NULL, " \t,;/")) != 0); + break; + } + } + if (! shpcnt) + error("No shapes [%s]", fname); + } else { // no sprite description: mono-shaped sprite with only .BMP file + ++shpcnt; + } + + // make sprite of choosen type + switch (type) { + case 1 : { // AUTO + _sprite = new Sprite(this, NULL); + if (_sprite) { + _sprite->Goto(col, row); + //Sprite->Time = 1;//-----------$$$$$$$$$$$$$$$$ + } + break; + } + case 2 : { // WALK + WALK *w = new WALK(this, NULL); + if (w && ref == 1) { + w->Goto(col, row); + if (Hero) + error("2nd HERO [%s]", fname); + Hero = w; + } + _sprite = w; + break; + } + /* + case 3 : // NEWTON + NEWTON * n = new NEWTON(NULL); + if (n) + { + n->Ay = (bottom-n->H); + n->By = 90; + n->Cy = 3; + n->Bx = 99; + n->Cx = 3; + n->Goto(col, row); + } + _sprite = n; + break; + */ + case 4 : { // LISSAJOUS + error("Bad type [%s]", fname); + /* + LISSAJOUS * l = new LISSAJOUS(NULL); + if (l) + { + l->Ax = SCR_WID/2; + l->Ay = SCR_HIG/2; + l->Bx = 7; + l->By = 13; + l->Cx = 300; + l->Cy = 500; + *(long *) &l->Dx = 0; // movex * cnt + l->Goto(col, row); + } + _sprite = l; + */ + break; + } + case 5 : { // FLY + FLY *f = new FLY(this, NULL); + _sprite = f; + //////Sprite->Time = 1;//-----------$$$$$$$$$$$$$$ + break; + } + default: { // DEAD + _sprite = new Sprite(this, NULL); + if (_sprite) + _sprite->Goto(col, row); + break; + } + } + if (_sprite) { + _sprite->_ref = ref; + _sprite->_cave = cav; + _sprite->_z = pos; + _sprite->_flags._east = east; + _sprite->_flags._port = port; + _sprite->_flags._tran = tran; + _sprite->_flags._kill = true; + _sprite->_flags._bDel = true; + + // Extract the filename, without the extension + strcpy(_sprite->File, fname); + char *p = strchr(_sprite->File, '.'); + if (p) + *p = '\0'; + + _sprite->_shpCnt = shpcnt; + Vga->SpareQ->Append(_sprite); + } +} + + +void CGEEngine::LoadScript(const char *fname) { + char line[LINE_MAX]; + char *SpN; + int SpI, SpA, SpX, SpY, SpZ; + bool BkG = false; + INI_FILE scrf(fname); + int lcnt = 0; + bool ok = true; + + if (scrf.Error) + return; + + while (scrf.Read((uint8 *)line) != 0) { + char *p; + + ++lcnt; + if (*line == 0 || *line == '\n' || *line == '.') + continue; + + ok = false; // not OK if break + // sprite ident number + if ((p = strtok(line, " \t\n")) == NULL) + break; + SpI = atoi(p); + // sprite file name + if ((SpN = strtok(NULL, " ,;/\t\n")) == NULL) + break; + // sprite cave + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) + break; + SpA = atoi(p); + // sprite column + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) + break; + SpX = atoi(p); + // sprite row + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) + break; + SpY = atoi(p); + // sprite Z pos + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) + break; + SpZ = atoi(p); + // sprite life + if ((p = strtok(NULL, " ,;/\t\n")) == NULL) + break; + BkG = atoi(p) == 0; + + ok = true; // no break: OK + + _sprite = NULL; + LoadSprite(SpN, SpI, SpA, SpX, SpY, SpZ); + if (_sprite && BkG) + _sprite->_flags._back = true; + } + if (! ok) + error("%s [%s]", NumStr("Bad INI line ######", lcnt), fname); +} + + +void CGEEngine::MainLoop() { + SayDebug(); + + if (_isDemo) { +// static uint32 tc = 0; + if (/* FIXME: TimerCount - tc >= ((182L * 6L) * 5L) && */ Talk == NULL && Snail->Idle()) { + if (Text->getText(DemoText)) { + SNPOST(SNSOUND, -1, 4, NULL); // drumla + SNPOST(SNINF, -1, DemoText, NULL); + SNPOST(SNLABEL, -1, -1, NULL); + if (Text->getText(++ DemoText) == NULL) + DemoText = DEMO_TEXT + 1; + } + //FIXME: tc = TimerCount; + } + } + Vga->Show(); + Snail_->RunCom(); + Snail->RunCom(); + + // Delay to slow things down + g_system->delayMillis(10); +} + + +void CGEEngine::LoadUser() { + // set scene + if (STARTUP::Mode == 0) { // user .SVG file found + CFILE cfile = CFILE(UsrPath(UsrFnam), REA, RCrypt); + LoadGame(cfile); + } else { + if (STARTUP::Mode == 1) { + SVG0FILE file = SVG0FILE(SVG0NAME); + LoadGame(file); + } else { + LoadScript(ProgName(INI_EXT)); + Music = true; + CFILE file = CFILE(SVG0NAME, WRI); + SaveGame(file); + error("Ok [%s]", SVG0NAME); + } + } + LoadScript(ProgName(IN0_EXT)); +} + + +void CGEEngine::RunGame() { + Text->Clear(); + Text->Preload(100, 1000); + LoadHeroXY(); + + _cavLight->_flags._tran = true; + Vga->ShowQ->Append(_cavLight); + _cavLight->_flags._hide = true; + + static Seq pocSeq[] = { { 0, 0, 0, 0, 20 }, + { 1, 2, 0, 0, 4 }, + { 2, 3, 0, 0, 4 }, + { 3, 4, 0, 0, 16 }, + { 2, 5, 0, 0, 4 }, + { 1, 6, 0, 0, 4 }, + { 0, 1, 0, 0, 16 }, + }; + _pocLight->SetSeq(pocSeq); + _pocLight->_flags._tran = true; + _pocLight->_time = 1; + _pocLight->_z = 120; + Vga->ShowQ->Append(_pocLight); + SelectPocket(-1); + + // FIXME: Allow ScummVM to handle mouse display +// Vga->ShowQ->Append(Mouse); + +// ___________ + LoadUser(); +// ~~~~~~~~~~~ + + if ((_sprite = Vga->SpareQ->Locate(121)) != NULL) + SNPOST_(SNSEQ, -1, Vga->Mono, _sprite); + if ((_sprite = Vga->SpareQ->Locate(122)) != NULL) + _sprite->Step(Music); + SNPOST_(SNSEQ, -1, Music, _sprite); + if (! Music) + KillMIDI(); + + if (Mini && INI_FILE::Exist("MINI.SPR")) { + uint8 *ptr = (uint8 *) &*Mini; + if (ptr != NULL) { + LoadSprite("MINI", -1, 0, MINI_X, MINI_Y); + ExpandSprite(_miniCave = _sprite); // NULL is ok + if (_miniCave) { + _miniCave->_flags._hide = true; + _miniCave->MoveShapes(ptr); + MiniShp[0] = new Bitmap(*_miniCave->Shp()); + MiniShpList = _miniCave->SetShapeList(MiniShp); + PostMiniStep(-1); + } + } + } + + if (Hero) { + ExpandSprite(Hero); + Hero->Goto(HeroXY[Now - 1]._x, HeroXY[Now - 1]._y); + if (INI_FILE::Exist("00SHADOW.SPR")) { + LoadSprite("00SHADOW", -1, 0, Hero->_x + 14, Hero->_y + 51); + if ((_shadow = _sprite) != NULL) { + _shadow->_ref = 2; + _shadow->_flags._tran = true; + Hero->_flags._shad = true; + Vga->ShowQ->Insert(Vga->SpareQ->Remove(_shadow), Hero); + } + } + } + + InfoLine->Goto(INFO_X, INFO_Y); + InfoLine->_flags._tran = true; + InfoLine->Update(NULL); + Vga->ShowQ->Insert(InfoLine); + + DebugLine->_z = 126; + Vga->ShowQ->Insert(DebugLine); + + _horzLine->_y = MAP_TOP - (MAP_TOP > 0); + _horzLine->_z = 126; + Vga->ShowQ->Insert(_horzLine); + + Mouse->Busy = Vga->SpareQ->Locate(BUSY_REF); + if (Mouse->Busy) + ExpandSprite(Mouse->Busy); + + Startup = 0; + + SNPOST(SNLEVEL, -1, OldLev, &_cavLight); + _cavLight->Goto(CAVE_X + ((Now - 1) % CAVE_NX) * CAVE_DX + CAVE_SX, + CAVE_Y + ((Now - 1) / CAVE_NX) * CAVE_DY + CAVE_SY); + CaveUp(); + + KEYBOARD::SetClient(Sys); + // main loop + while (! Finis) { + //TODO Change the SNPOST message send to a special way to send function pointer + // if (FINIS) SNPOST(SNEXEC, -1, 0, (void *)&QGame); + warning("RunGame: problematic use of SNPOST"); + MainLoop(); + } + + KEYBOARD::SetClient(NULL); + _heart->_enable = false; + SNPOST(SNCLEAR, -1, 0, NULL); + SNPOST_(SNCLEAR, -1, 0, NULL); + Mouse->Off(); + Vga->ShowQ->Clear(); + Vga->SpareQ->Clear(); + Hero = NULL; + _shadow = NULL; +} + + +void CGEEngine::Movie(const char *ext) { + const char *fn = ProgName(ext); + if (INI_FILE::Exist(fn)) { + LoadScript(fn); + ExpandSprite(Vga->SpareQ->Locate(999)); + FeedSnail(Vga->ShowQ->Locate(999), TAKE); + + // FIXME: Allow ScummVM to handle mouse display + //Vga->ShowQ->Append(Mouse); + + _heart->_enable = true; + KEYBOARD::SetClient(Sys); + while (!Snail->Idle()) + MainLoop(); + + KEYBOARD::SetClient(NULL); + _heart->_enable = false; + SNPOST(SNCLEAR, -1, 0, NULL); + SNPOST_(SNCLEAR, -1, 0, NULL); + Vga->ShowQ->Clear(); + Vga->SpareQ->Clear(); + } +} + + +bool CGEEngine::ShowTitle(const char *name) { + Bitmap::Pal = VGA::SysPal; + BMP_PTR LB[] = { new Bitmap(name), NULL }; + Bitmap::Pal = NULL; + bool usr_ok = false; + + Sprite D(this, LB); + D._flags._kill = true; + D._flags._bDel = true; + D.Center(); + D.Show(2); + + if (STARTUP::Mode == 2) { + Inf(SVG0NAME); + Talk->Show(2); + } + + Vga->Sunset(); + Vga->CopyPage(1, 2); + Vga->CopyPage(0, 1); + SelectPocket(-1); + Vga->Sunrise(VGA::SysPal); + + if (STARTUP::Mode < 2 && !STARTUP::SoundOk) { + Vga->CopyPage(1, 2); + Vga->CopyPage(0, 1); + Vga->ShowQ->Append(Mouse); + _heart->_enable = true; + Mouse->On(); + for (SelectSound(); !Snail->Idle() || VMENU::Addr;) + MainLoop(); + Mouse->Off(); + _heart->_enable = false; + Vga->ShowQ->Clear(); + Vga->CopyPage(0, 2); + STARTUP::SoundOk = 2; + if (Music) + LoadMIDI(0); + } + + if (STARTUP::Mode < 2) { + if (_isDemo) { + strcpy(UsrFnam, ProgName(SVG_EXT)); + usr_ok = true; + } else { + //----------------------------------------- +#ifndef EVA +#ifdef CD + STARTUP::Summa |= (0xC0 + (DriveCD(0) << 6)) & 0xFF; +#else +// Boot * b = ReadBoot(getdisk()); + warning("ShowTitle: FIXME ReadBoot"); + Boot *b = ReadBoot(0); + uint32 sn = (b->XSign == 0x29) ? b->Serial : b->lTotSecs; + free(b); + sn -= ((IDENT *)Copr)->disk; + STARTUP::Summa |= Lo(sn) | Hi(sn); +#endif + //----------------------------------------- + Movie("X00"); // paylist + Vga->CopyPage(1, 2); + Vga->CopyPage(0, 1); + Vga->ShowQ->Append(Mouse); + //Mouse.On(); + _heart->_enable = true; + for (TakeName(); GET_TEXT::Ptr;) + MainLoop(); + _heart->_enable = false; + if (KEYBOARD::Last() == Enter && *UsrFnam) + usr_ok = true; + if (usr_ok) + strcat(UsrFnam, SVG_EXT); + //Mouse.Off(); + Vga->ShowQ->Clear(); + Vga->CopyPage(0, 2); +#endif + } + + if (usr_ok && STARTUP::Mode == 0) { + const char *n = UsrPath(UsrFnam); + if (CFILE::Exist(n)) { + CFILE file = CFILE(n, REA, RCrypt); + LoadGame(file, true); // only system vars + Vga->SetColors(VGA::SysPal, 64); + Vga->Update(); + if (FINIS) { + ++ STARTUP::Mode; + FINIS = false; + } + } else + ++STARTUP::Mode; + } + } + + if (STARTUP::Mode < 2) + Movie("X01"); // wink + + Vga->CopyPage(0, 2); + + if (_isDemo) + return true; + else + return (STARTUP::Mode == 2 || usr_ok); +} + + +/* +void StkDump (void) { + CFILE f("!STACK.DMP", BFW); + f.Write((uint8 *) (intStackPtr-STACK_SIZ/2), STACK_SIZ*2); +} +*/ + + +void CGEEngine::cge_main(void) { + uint16 intStack[STACK_SIZ / 2]; + intStackPtr = intStack; + + //Debug( memset((void *) (-K(2)), 0, K(1)); ) + //Debug( memset((void *) (-K(4)), 0, K(1)); ) + memset(Barriers, 0xFF, sizeof(Barriers)); + + if (!Mouse->Exist) + error("%s", Text->getText(NO_MOUSE_TEXT)); + + if (!SVG0FILE::Exist(SVG0NAME)) + STARTUP::Mode = 2; + + DebugLine->_flags._hide = true; + _horzLine->_flags._hide = true; + + //srand((uint16) Timer()); + Sys = new SYSTEM(this); + + if (Music && STARTUP::SoundOk) + LoadMIDI(0); + if (STARTUP::Mode < 2) + Movie(LGO_EXT); + if (ShowTitle("WELCOME")) { + if ((!_isDemo) && (STARTUP::Mode == 1)) + Movie("X02"); // intro + RunGame(); + Startup = 2; + if (FINIS) + Movie("X03"); + } else + Vga->Sunset(); + error("%s", Text->getText(EXIT_OK_TEXT + FINIS)); +} + +} // End of namespace CGE diff --git a/engines/cge/cge_main.h b/engines/cge/cge_main.h new file mode 100644 index 0000000000..8b2f87aad9 --- /dev/null +++ b/engines/cge/cge_main.h @@ -0,0 +1,196 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CGE__ +#define __CGE__ + +#include "cge/wav.h" +#include "cge/vga13h.h" +#include "cge/mouse.h" + +namespace CGE { + +#define TSEQ 96 +#define HTALK (TSEQ + 4) +#define TOO_FAR (TSEQ + 5) +#define NO_WAY (TSEQ + 5) +#define POC_FUL (TSEQ + 5) +#define OFF_USE (TSEQ + 6) +#define EXIT_OK_TEXT 40 +#define NOMUSIC_TEXT 98 +#define BADSVG_TEXT 99 +#define OFF_USE_COUNT 600 +#define OFF_USE_TEXT 601 +#define NO_WAY_TEXT 671 +#define TOO_FAR_TEXT 681 +#define POC_FUL_TEXT 691 +#define A_C_D_TEXT 777 +#define GETNAME_PROMPT 50 +#define GETNAME_TITLE 51 +#define QUIT_TITLE 200 +#define QUIT_TEXT 201 +#define NOQUIT_TEXT 202 +#define DEMO_TEXT 300 +#define NOSOUND_TEXT 310 +#define PAN_HIG 40 +#define WORLD_HIG (SCR_HIG - PAN_HIG) +#define INFO_X 177 +#define INFO_Y 164 +#define INFO_W 140 +#define CAVE_X 4 +#define CAVE_Y 166 +#define CAVE_SX 0 +#define CAVE_SY 0 + +#ifdef DEMO +#define CAVE_DX 23 +#define CAVE_DY 29 +#define CAVE_NX 3 +#define CAVE_NY 1 +#else +#define CAVE_DX 9 +#define CAVE_DY 10 +#define CAVE_NX 8 +#define CAVE_NY 3 +#endif + +#define BUTTON_X 151 +#define BUTTON_Y 164 +#define BUTTON_DX 19 +#define BUTTON_DY 11 +#define BUTTON_NX 1 +#define BUTTON_NY 3 +#define MINI_X 86 +#define MINI_Y 162 +#define MAP_XCNT 40 +#define MAP_ZCNT 20 +#define MAP_TOP 80 +#define MAP_HIG 80 +#define MAP_XGRID (SCR_WID / MAP_XCNT) +#define MAP_ZGRID (MAP_HIG / MAP_ZCNT) +#define LINE_MAX 512 +#define USER_MAX 100 +#define SHP_MAX 1024 +#define STD_DELAY 3 +#define LEV_MAX 5 +#define CAVE_MAX (CAVE_NX * CAVE_NY) +#define MAX_FIND_LEVEL 3 +#define MAX_DISTANCE 3 +#define INI_EXT ".INI" +#define IN0_EXT ".IN0" +#define LGO_EXT ".LGO" +#define SVG_EXT ".SVG" +#define WALKSIDE 10 +#define BUSY_REF 500 +#define SYSTIMERATE 6 // 12 Hz +#define HEROFUN0 (40 * 12) +#define HEROFUN1 ( 2 * 12) +#define PAIN (Flag[0]) +#define FINIS (Flag[3]) + + +class SYSTEM : public Sprite { + int lum; +public: + int FunDel; + + SYSTEM(CGEEngine *vm); + + void SetPal(); + void FunTouch(); + void Touch(uint16 mask, int x, int y); + void Tick(); +private: + CGEEngine *_vm; +}; + + +class CLUSTER : public COUPLE { +public: + static uint8 Map[MAP_ZCNT][MAP_XCNT]; + uint8 &Cell(void); + CLUSTER(void) : COUPLE() { } + CLUSTER(int a, int b) : COUPLE(a, b) { } + bool Protected(void); +}; + + +class WALK : public Sprite { +public: + CLUSTER Here; + int TracePtr; + + enum DIR { NO_DIR = -1, NN, EE, SS, WW } Dir; + WALK(CGEEngine *vm, BMP_PTR *shpl); + void Tick(void); + void FindWay(CLUSTER c); + void FindWay(Sprite *spr); + int Distance(Sprite *spr); + void Turn(DIR d); + void Park(void); + bool Lower(Sprite *spr); + void Reach(Sprite *spr, int mode = -1); +private: + CGEEngine *_vm; + +}; + + +CLUSTER XZ(int x, int y); +CLUSTER XZ(COUPLE xy); + +void ExpandSprite(Sprite *spr); +void ContractSprite(Sprite *spr); + +extern WALK *Hero; +extern VGA *Vga; +extern Heart *_heart; +extern SYSTEM *Sys; +extern int OffUseCount; +extern Sprite *_pocLight; +extern MOUSE *Mouse; +extern Sprite *_pocket[]; +extern Sprite *_sprite; +extern Sprite *_miniCave; +extern Sprite *_shadow; +extern Sprite *_horzLine; +extern INFO_LINE *InfoLine; +extern Sprite *_cavLight; +extern INFO_LINE *DebugLine; +extern BMP_PTR MB[2]; +extern BMP_PTR MB[2]; +extern BMP_PTR HL[2]; +extern BMP_PTR MC[3]; +extern BMP_PTR PR[2]; +extern BMP_PTR SP[3]; +extern BMP_PTR LI[5]; +extern SNAIL *Snail; +extern SNAIL *Snail_; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/config.cpp b/engines/cge/config.cpp new file mode 100644 index 0000000000..2673143285 --- /dev/null +++ b/engines/cge/config.cpp @@ -0,0 +1,282 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/config.h" +#include "cge/sound.h" +#include "cge/vmenu.h" +#include "cge/text.h" +#include "cge/cge_main.h" + +namespace CGE { + +/* + 51=wska§ typ posiadanej karty d¦wi‘kowej + 52=wybierz numer portu dla karty d¦wi‘kowej + 53=wybierz numer przerwania dla karty d¦wi‘kowej + 54=wybierz numer kana’u DMA dla karty d¦wi‘kowej + 55=wybierz numer portu dla General MIDI + 55=konfiguracja karty d¦wi‘kowej +*/ +#define STYPE_TEXT 51 +#define SPORT_TEXT 52 +#define SIRQ_TEXT 53 +#define SDMA_TEXT 54 +#define MPORT_TEXT 55 +#define MENU_TEXT 56 + +#define NONE_TEXT 60 +#define SB_TEXT 61 +#define SBM_TEXT 62 +#define GUS_TEXT 63 +#define GUSM_TEXT 64 +#define MIDI_TEXT 65 +#define AUTO_TEXT 66 + +#define DETECT 0xFFFF + + +static int DevName[] = { + NONE_TEXT, SB_TEXT, SBM_TEXT, GUS_TEXT, GUSM_TEXT, + MIDI_TEXT, AUTO_TEXT +}; + +static CHOICE DevMenu[] = { + { NULL, &CGEEngine::NONE }, + { NULL, &CGEEngine::SB }, + { NULL, &CGEEngine::SBM }, + { NULL, &CGEEngine::GUS }, + { NULL, &CGEEngine::GUSM }, + { NULL, &CGEEngine::MIDI }, + { NULL, &CGEEngine::AUTO }, + { NULL, NULL } +}; + + +static CHOICE DigiPorts[] = { + { " 210h", &CGEEngine::SetPortD }, + { " 220h", &CGEEngine::SetPortD }, + { " 230h", &CGEEngine::SetPortD }, + { " 240h", &CGEEngine::SetPortD }, + { " 250h", &CGEEngine::SetPortD }, + { " 260h", &CGEEngine::SetPortD }, + { "AUTO ", &CGEEngine::SetPortD }, + { NULL, NULL } +}; + +static CHOICE MIDIPorts[] = { + { " 220h", &CGEEngine::SetPortM }, + { " 230h", &CGEEngine::SetPortM }, + { " 240h", &CGEEngine::SetPortM }, + { " 250h", &CGEEngine::SetPortM }, + { " 300h", &CGEEngine::SetPortM }, + { " 320h", &CGEEngine::SetPortM }, + { " 330h", &CGEEngine::SetPortM }, + { " 340h", &CGEEngine::SetPortM }, + { " 350h", &CGEEngine::SetPortM }, + { " 360h", &CGEEngine::SetPortM }, + { "AUTO ", &CGEEngine::SetPortM }, + { NULL, NULL } +}; + +static CHOICE BlsterIRQ[] = { + { "IRQ 2", &CGEEngine::SetIRQ }, + { "IRQ 5", &CGEEngine::SetIRQ }, + { "IRQ 7", &CGEEngine::SetIRQ }, + { "IRQ 10", &CGEEngine::SetIRQ }, + { "AUTO ", &CGEEngine::SetIRQ }, + { NULL, NULL } +}; + +static CHOICE GravisIRQ[] = { + { "IRQ 2", &CGEEngine::SetIRQ }, + { "IRQ 5", &CGEEngine::SetIRQ }, + { "IRQ 7", &CGEEngine::SetIRQ }, + { "IRQ 11", &CGEEngine::SetIRQ }, + { "IRQ 12", &CGEEngine::SetIRQ }, + { "IRQ 15", &CGEEngine::SetIRQ }, + { "AUTO ", &CGEEngine::SetIRQ }, + { NULL, NULL } +}; + +static CHOICE GravisDMA[] = { + { "DMA 1", &CGEEngine::SetDMA }, + { "DMA 3", &CGEEngine::SetDMA }, + { "DMA 5", &CGEEngine::SetDMA }, + { "DMA 6", &CGEEngine::SetDMA }, + { "DMA 7", &CGEEngine::SetDMA }, + { "AUTO ", &CGEEngine::SetDMA }, + { NULL, NULL } +}; + +static CHOICE BlsterDMA[] = { + { "DMA 0", &CGEEngine::SetDMA }, + { "DMA 1", &CGEEngine::SetDMA }, + { "DMA 3", &CGEEngine::SetDMA }, + { "AUTO ", &CGEEngine::SetDMA }, + { NULL, NULL } +}; + + +void CGEEngine::SelectSound() { + int i; + Sound.Close(); + if (VMENU::Addr) + SNPOST_(SNKILL, -1, 0, VMENU::Addr); + Inf(Text->getText(STYPE_TEXT)); + Talk->Goto(Talk->_x, FONT_HIG / 2); + for (i = 0; i < ArrayCount(DevName); i++) + DevMenu[i].Text = Text->getText(DevName[i]); + (new VMENU(this, DevMenu, SCR_WID / 2, Talk->_y + Talk->_h + TEXT_VM + FONT_HIG))->SetName(Text->getText(MENU_TEXT)); +} + + +static void Reset(void) { + SNDDrvInfo.DBASE = SNDDrvInfo.DIRQ = SNDDrvInfo.DDMA = SNDDrvInfo.MBASE = DETECT; +} + + +static uint16 deco(const char *str, uint16(*dco)(const char *)) { + while (*str && ! IsDigit(*str)) + ++str; + if (*str) + return dco(str); + else + return DETECT; +} + + +static uint16 ddeco(const char *str) { + return deco(str, atow); +} + + +static uint16 xdeco(const char *str) { + return deco(str, xtow); +} + + +static CHOICE *Cho; +static int Hlp; + +void CGEEngine::SNSelect() { + Inf(Text->getText(Hlp)); + Talk->Goto(Talk->_x, FONT_HIG / 2); + (new VMENU(this, Cho, SCR_WID / 2, Talk->_y + Talk->_h + TEXT_VM + FONT_HIG))->SetName(Text->getText(MENU_TEXT)); +} + + +static void Select(CHOICE *cho, int hlp) { + Cho = cho; + Hlp = hlp; + //TODO Change the SNPOST message send to a special way to send function pointer + //SNPOST(SNEXEC, -1, 0, (void *)&SNSelect); + warning("STUB: Select"); +} + + +void CGEEngine::NONE() { + SNDDrvInfo.DDEV = DEV_QUIET; + SNDDrvInfo.MDEV = DEV_QUIET; + Sound.Open(); +} + + +void CGEEngine::SB() { + SNDDrvInfo.DDEV = DEV_SB; + SNDDrvInfo.MDEV = DEV_SB; + Reset(); + Select(DigiPorts, SPORT_TEXT); +} + + +void CGEEngine::SBM() { + SNDDrvInfo.DDEV = DEV_SB; + SNDDrvInfo.MDEV = DEV_GM; + Reset(); + Select(DigiPorts, SPORT_TEXT); +} + + +void CGEEngine::GUS() { + SNDDrvInfo.DDEV = DEV_GUS; + SNDDrvInfo.MDEV = DEV_GUS; + Reset(); + Select(DigiPorts, SPORT_TEXT); +} + + +void CGEEngine::GUSM() { + SNDDrvInfo.DDEV = DEV_GUS; + SNDDrvInfo.MDEV = DEV_GM; + Reset(); + Select(DigiPorts, SPORT_TEXT); +} + + +void CGEEngine::MIDI() { + SNDDrvInfo.DDEV = DEV_QUIET; + SNDDrvInfo.MDEV = DEV_GM; + SNDDrvInfo.MBASE = DETECT; + Select(MIDIPorts, MPORT_TEXT); +} + + +void CGEEngine::AUTO() { + SNDDrvInfo.DDEV = DEV_AUTO; + SNDDrvInfo.MDEV = DEV_AUTO; + Reset(); + Sound.Open(); +} + + +void CGEEngine::SetPortD() { + SNDDrvInfo.DBASE = xdeco(DigiPorts[VMENU::Recent].Text); + Select((SNDDrvInfo.DDEV == DEV_SB) ? BlsterIRQ : GravisIRQ, SIRQ_TEXT); +} + + +void CGEEngine::SetPortM() { + SNDDrvInfo.MBASE = xdeco(MIDIPorts[VMENU::Recent].Text); + Sound.Open(); +} + + +void CGEEngine::SetIRQ() { + SNDDrvInfo.DIRQ = ddeco(((SNDDrvInfo.DDEV == DEV_SB) ? BlsterIRQ : GravisIRQ)[VMENU::Recent].Text); + Select((SNDDrvInfo.DDEV == DEV_SB) ? BlsterDMA : GravisDMA, SDMA_TEXT); +} + + +void CGEEngine::SetDMA() { + SNDDrvInfo.DDMA = ddeco(((SNDDrvInfo.DDEV == DEV_SB) ? BlsterDMA : GravisDMA)[VMENU::Recent].Text); + if (SNDDrvInfo.MDEV != SNDDrvInfo.DDEV) + Select(MIDIPorts, MPORT_TEXT); + else + Sound.Open(); +} + +} // End of namespace CGE diff --git a/engines/cge/config.h b/engines/cge/config.h new file mode 100644 index 0000000000..e3fe094681 --- /dev/null +++ b/engines/cge/config.h @@ -0,0 +1,37 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __CONFIG__ +#define __CONFIG__ + +namespace CGE { + +void SelectSound(void); + +} // End of namespace CGE + +#endif diff --git a/engines/cge/console.cpp b/engines/cge/console.cpp new file mode 100644 index 0000000000..71eedf34ea --- /dev/null +++ b/engines/cge/console.cpp @@ -0,0 +1,34 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "cge/console.h" +#include "cge/cge.h" + +namespace CGE { + +CGEConsole::CGEConsole(CGEEngine *vm) : GUI::Debugger(), _vm(vm) { +} + +CGEConsole::~CGEConsole() { +} + +} // End of namespace CGE diff --git a/engines/cge/console.h b/engines/cge/console.h new file mode 100644 index 0000000000..7f265202ea --- /dev/null +++ b/engines/cge/console.h @@ -0,0 +1,43 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef CGE_CONSOLE_H +#define CGE_CONSOLE_H + +#include "gui/debugger.h" + +namespace CGE { + +class CGEEngine; + +class CGEConsole : public GUI::Debugger { +public: + CGEConsole(CGEEngine *vm); + virtual ~CGEConsole(void); + +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp new file mode 100644 index 0000000000..31bf629fcf --- /dev/null +++ b/engines/cge/detection.cpp @@ -0,0 +1,238 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/config-manager.h" +#include "engines/advancedDetector.h" +#include "common/savefile.h" +#include "common/system.h" +#include "base/plugins.h" +#include "graphics/thumbnail.h" +#include "cge/cge.h" + +static const PlainGameDescriptor CGEGames[] = { + { "soltys", "Soltys" }, + { 0, 0 } +}; + +namespace CGE { + +using Common::GUIO_NONE; + +static const ADGameDescription gameDescriptions[] = { + + { + "soltys", "", + { + {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176}, + {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437572}, + AD_LISTEND + }, + Common::PL_POL, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + }, + { + "soltys", "Soltys Freeware", + { + {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176}, + {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676}, + AD_LISTEND + }, + Common::PL_POL, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + }, + { + "soltys", "Soltys Demo", + { + {"vol.cat", 0, "1e077c8ff58109a187f07ac54b0c873a", 18788}, + {"vol.dat", 0, "75d385a6074c58b69f7730481f256051", 1796710}, + AD_LISTEND + }, + Common::PL_POL, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE + }, + { + "soltys", "Soltys Demo", + { + {"vol.cat", 0, "f17987487fab1ebddd781d8d02fedecc", 7168}, + {"vol.dat", 0, "c5d9b15863cab61dc125551576dece04", 1075272}, + AD_LISTEND + }, + Common::PL_POL, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE + }, + AD_TABLE_END_MARKER +}; + +static const ADFileBasedFallback fileBasedFallback[] = { + { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } }, + { 0, { 0 } } +}; + +} // End of namespace CGE + +class CGEMetaEngine : public AdvancedMetaEngine { +public: + CGEMetaEngine() : AdvancedMetaEngine(CGE::gameDescriptions, sizeof(ADGameDescription), CGEGames) { + _singleid = "Soltys"; + } + + virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { + return detectGameFilebased(allFiles, CGE::fileBasedFallback); + } + + virtual const char *getName() const { + return "CGE"; + } + + virtual const char *getOriginalCopyright() const { + return "Soltys (c) 1994-1996 L.K. Avalon"; + } + + virtual bool hasFeature(MetaEngineFeature f) const; + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + virtual int getMaximumSaveSlot() const; + virtual SaveStateList listSaves(const char *target) const; + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; + virtual void removeSaveState(const char *target, int slot) const; +}; + +bool CGEMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsListSaves) || + (f == kSupportsLoadingDuringStartup) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSavesSupportCreationDate); +} + +void CGEMetaEngine::removeSaveState(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.%03d", target, slot); + g_system->getSavefileManager()->removeSavefile(fileName); +} + +int CGEMetaEngine::getMaximumSaveSlot() const { + return 99; +} + +SaveStateList CGEMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray filenames; + Common::String pattern = target; + pattern += ".???"; + + filenames = saveFileMan->listSavefiles(pattern); + sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + + SaveStateList saveList; + int slotNum = 0; + for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); filename++) { + // Obtain the last 3 digits of the filename, since they correspond to the save slot + slotNum = atoi(filename->c_str() + filename->size() - 3); + + if (slotNum >= 0 && slotNum <= 99) { + Common::InSaveFile *file = saveFileMan->openForLoading(*filename); + if (file) { + int32 version = file->readSint32BE(); + if (version != CGE_SAVEGAME_VERSION) { + delete file; + continue; + } + + // read name + uint16 nameSize = file->readUint16BE(); + if (nameSize >= 255) { + delete file; + continue; + } + char name[256]; + file->read(name, nameSize); + name[nameSize] = 0; + + saveList.push_back(SaveStateDescriptor(slotNum, name)); + delete file; + } + } + } + + return saveList; +} + +SaveStateDescriptor CGEMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.%03d", target, slot); + Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName); + + if (file) { + + int32 version = file->readSint32BE(); + if (version != CGE_SAVEGAME_VERSION) { + delete file; + return SaveStateDescriptor(); + } + + uint32 saveNameLength = file->readUint16BE(); + char saveName[256]; + file->read(saveName, saveNameLength); + saveName[saveNameLength] = 0; + + SaveStateDescriptor desc(slot, saveName); + + Graphics::Surface *thumbnail = new Graphics::Surface(); + assert(thumbnail); + if (!Graphics::loadThumbnail(*file, *thumbnail)) { + delete thumbnail; + thumbnail = 0; + } + desc.setThumbnail(thumbnail); + + desc.setDeletableFlag(true); + desc.setWriteProtectedFlag(false); + + uint32 saveDate = file->readUint32BE(); + uint16 saveTime = file->readUint16BE(); + + int day = (saveDate >> 24) & 0xFF; + int month = (saveDate >> 16) & 0xFF; + int year = saveDate & 0xFFFF; + + desc.setSaveDate(year, month, day); + + int hour = (saveTime >> 8) & 0xFF; + int minutes = saveTime & 0xFF; + + desc.setSaveTime(hour, minutes); + + delete file; + return desc; + } + + return SaveStateDescriptor(); +} + +bool CGEMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + if (desc) { + *engine = new CGE::CGEEngine(syst, desc); + } + return desc != 0; +} + +#if PLUGIN_ENABLED_DYNAMIC(CGE) +REGISTER_PLUGIN_DYNAMIC(CGE, PLUGIN_TYPE_ENGINE, CGEMetaEngine); +#else +REGISTER_PLUGIN_STATIC(CGE, PLUGIN_TYPE_ENGINE, CGEMetaEngine); +#endif diff --git a/engines/cge/ems.cpp b/engines/cge/ems.cpp new file mode 100644 index 0000000000..56d853f4e8 --- /dev/null +++ b/engines/cge/ems.cpp @@ -0,0 +1,225 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/general.h" + +namespace CGE { + +#define EMS_INT 0x67 +#define PAGE_MASK 0x3FFF +#define SIZ(n) ((n) ? ((long)n) : (0x10000L)) + + +enum EMM_FUN { + GET_STATUS = 0x40, GET_FRAME, GET_SIZE, OPEN_HANDLE, MAP_PAGE, + CLOSE_HANDLE, GET_VER, SAVE_CONTEXT, REST_CONTEXT, GET_PAGES = 0x4B, + GET_HANDLES, GET_INFO, CONTROL +}; + + +void *EMM::Frame = NULL; + + +EMM::EMM(long size): Han(-1), Top(0), Lim(0), List(NULL) { + /* + if (Test()) + { + asm mov ah,GET_FRAME // get EMS frame segment + asm int EMS_INT // do it! + asm or ah,ah // see status + asm jnz xit // abort on error + Frame = (void _seg *) _BX; // save frame segment + + if (size == 0) + { + asm mov ah,GET_SIZE // get EMS memory size + asm int EMS_INT // do it! + asm or ah,ah // see status + asm jnz xit // abort on error + asm or bx,bx // test page count + asm jz xit // abort if no free pages + // number of available pages in BX is ready to use by OPEN + } + else _BX = (uint16) ((size + PAGE_MASK) >> 14); + asm mov ah,OPEN_HANDLE // open EMM handle + asm int EMS_INT // do it! + asm or ah,ah // see status + asm jnz xit // abort on error + Han = _DX; + Lim = _BX; + Lim <<= 14; + _DX = Han; + asm mov ah,SAVE_CONTEXT // save mapping context + asm int EMS_INT // do it! + } + xit: + */ + warning("STUB: EMM:EMM"); +} + + +EMM::~EMM(void) { + /* FIXME + Release(); + if (Han >= 0) + { + _DX = Han; + asm mov ah,REST_CONTEXT + asm int EMS_INT + asm mov ah,CLOSE_HANDLE + asm int EMS_INT + } + */ +} + + +bool EMM::Test(void) { + /* + static char e[] = "EMMXXXX0"; + + asm mov ax,0x3D40 + asm mov dx,offset e + asm int 0x21 + asm jc fail + + asm push ax + asm mov bx,ax + asm mov ax,0x4407 + asm int 0x21 + + asm pop bx + asm push ax + asm mov ax,0x3E00 + asm int 0x21 + asm pop ax + + asm cmp al,0x00 + asm je fail + + success: + return TRUE; + fail: + return FALSE; + */ + warning("EMM::Test"); + return false; +} + + +EMS *EMM::Alloc(uint16 siz) { + /* + long size = SIZ(siz), + top = Top; + + uint16 pgn = (uint16) (top >> 14), + cnt = (uint16) ((top + size + PAGE_MASK) >> 14) - pgn; + + if (cnt > 4) + { + top = (top + PAGE_MASK) & 0xFFFFC000L; + pgn++; + cnt--; + } + + if (size <= Lim - top) + { + EMS * e = new EMS, * f; + + if (e) + { + Top = (e->Ptr = top) + (e->Siz = siz); + e->Emm = this; + + if (List) + { + for (f = List; f->Nxt; f = f->Nxt); + return (f->Nxt = e); // existing list: link to the end + } + else + { + return (List = e); // empty list: link to the head + } + } + } + fail: return NULL; + */ + warning("STUB: EMM::Alloc"); + return NULL; +} + + +void EMM::Release(void) { + while (List) { + EMS *e = List; + List = e->Nxt; + delete e; + } + Top = 0; +} + + +EMS::EMS(void) : Ptr(0), Siz(0), Nxt(NULL) { +} + + +void *EMS::operator & () const { + /* + uint16 pgn = (uint16) (Ptr >> 14), + off = (uint16) Ptr & PAGE_MASK, + cnt = (uint16) ((Ptr + SIZ(Siz) + PAGE_MASK) >> 14) - pgn, + cmd = MAP_PAGE << 8; + + _DX = Emm->Han; // take EMM handle + asm dec cnt // prapare for deferred checking + asm or dx,dx // see if valid + asm jns more // negative handle = unavailable + + fail: return NULL; + + more: + asm mov ax,cmd // command + page frame index + asm mov bx,pgn // logical page number + asm int EMS_INT // do it! + asm or ah,ah // check error code + asm jnz fail // exit on error + asm inc cmd // advance page frame index + asm inc pgn // advance logical page number + asm cmp al,byte ptr cnt // all pages? + asm jb more + + return (void *) (EMM::Frame + (void *) off); + */ + warning("STUB: EMS::operator &"); + return NULL; +} + + +uint16 EMS::Size(void) { + return Siz; +} + +} // End of namespace CGE diff --git a/engines/cge/game.cpp b/engines/cge/game.cpp new file mode 100644 index 0000000000..87daced31e --- /dev/null +++ b/engines/cge/game.cpp @@ -0,0 +1,92 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/game.h" +#include "cge/mouse.h" +#include <stdlib.h> + +namespace CGE { + +uint8 *Glass(DAC *pal, uint8 r, uint8 g, uint8 b) { + uint8 *x = new uint8[256]; + if (x) { + uint16 i; + for (i = 0; i < 256; i++) { + x[i] = Closest(pal, MkDAC(((uint16)(pal[i].R) * r) / 255, + ((uint16)(pal[i].G) * g) / 255, + ((uint16)(pal[i].B) * b) / 255)); + } + } + return x; +} + + +uint8 *Mark(DAC *pal) { +#define f(c) (c ^ 63) + uint8 *x = new uint8[256]; + if (x) { + uint16 i; + for (i = 0; i < 256; i++) { + x[i] = Closest(pal, MkDAC(f(pal[i].R), + f(pal[i].G), + f(pal[i].B))); + } + } + return x; +#undef f +} + + +int FLY::L = 20, + FLY::T = 40, + FLY::R = 110, + FLY::B = 100; + + +FLY::FLY(CGEEngine *vm, Bitmap **shpl) + : Sprite(vm, shpl), Tx(0), Ty(0), _vm(vm) { + Step(new_random(2)); + Goto(L + new_random(R - L - _w), T + new_random(B - T - _h)); +} + + +void FLY::Tick(void) { + Step(); + if (!_flags._kept) { + if (new_random(10) < 1) { + Tx = new_random(3) - 1; + Ty = new_random(3) - 1; + } + if (_x + Tx < L || _x + Tx + _w > R) + Tx = -Tx; + if (_y + Ty < T || _y + Ty + _h > B) + Ty = -Ty; + Goto(_x + Tx, _y + Ty); + } +} + +} // End of namespace CGE diff --git a/engines/cge/game.h b/engines/cge/game.h new file mode 100644 index 0000000000..a64018aa58 --- /dev/null +++ b/engines/cge/game.h @@ -0,0 +1,59 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __GAME__ +#define __GAME__ + +#include "cge/vga13h.h" +#include "cge/bitmaps.h" + +namespace CGE { + + +#define PAN_HIG 40 +#define LBound(s) (s->X <= 0) +#define RBound(s) (s->X+s->W >= SCR_WID) +#define TBound(s) (s->Y <= 0) +#define BBound(s) (s->Y+s->H >= SCR_HIG - PAN_HIG) + +int Sinus(long x); +uint8 *Glass(DAC *pal, uint8 r, uint8 g, uint8 b); +uint8 *Mark(DAC *pal); + +class FLY : public Sprite { + static int L, T, R, B; +public: + int Tx, Ty; + FLY(CGEEngine *vm, Bitmap **shpl); + void Tick(void); +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/general.cpp b/engines/cge/general.cpp new file mode 100644 index 0000000000..7bf753ff9f --- /dev/null +++ b/engines/cge/general.cpp @@ -0,0 +1,420 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/boot.h" +#include "cge/general.h" +#include "cge/snddrv.h" +#include "cge/wav.h" + +namespace CGE { + +DAC StdPal[] = {// R G B + { 0, 60, 0}, // 198 + { 0, 104, 0}, // 199 + { 20, 172, 0}, // 200 + { 82, 82, 0}, // 201 + { 0, 132, 82}, // 202 + { 132, 173, 82}, // 203 + { 82, 0, 0}, // 204 + { 206, 0, 24}, // 205 + { 255, 33, 33}, // 206 + { 123, 41, 0}, // 207 + { 0, 41, 0}, // 208 + { 0, 0, 82}, // 209 + { 132, 0, 0}, // 210 + { 255, 0, 0}, // 211 + { 255, 66, 66}, // 212 + { 148, 66, 16}, // 213 + { 0, 82, 0}, // 214 + { 0, 0, 132}, // 215 + { 173, 0, 0}, // 216 + { 255, 49, 0}, // 217 + { 255, 99, 99}, // 218 + { 181, 107, 49}, // 219 + { 0, 132, 0}, // 220 + { 0, 0, 255}, // 221 + { 173, 41, 0}, // 222 + { 255, 82, 0}, // 223 + { 255, 132, 132}, // 224 + { 214, 148, 74}, // 225 + { 41, 214, 0}, // 226 + { 0, 82, 173}, // 227 + { 255, 214, 0}, // 228 + { 247, 132, 49}, // 229 + { 255, 165, 165}, // 230 + { 239, 198, 123}, // 231 + { 173, 214, 0}, // 232 + { 0, 132, 214}, // 233 + { 57, 57, 57}, // 234 + { 247, 189, 74}, // 235 + { 255, 198, 198}, // 236 + { 255, 239, 173}, // 237 + { 214, 255, 173}, // 238 + { 82, 173, 255}, // 239 + { 107, 107, 107}, // 240 + { 247, 222, 99}, // 241 + { 255, 0, 255}, // 242 + { 255, 132, 255}, // 243 + { 132, 132, 173}, // 244 + { 148, 247, 255}, // 245 + { 148, 148, 148}, // 246 + { 82, 0, 82}, // 247 + { 112, 68, 112}, // 248 + { 176, 88, 144}, // 249 + { 214, 132, 173}, // 250 + { 206, 247, 255}, // 251 + { 198, 198, 198}, // 252 + { 0, 214, 255}, // 253 + { 96, 224, 96 }, // 254 + { 255, 255, 255}, // 255 +}; + +DRVINFO SNDDrvInfo; + +EC void _fqsort(void *base, uint16 nelem, uint16 width, int (*fcmp)(const void *, const void *)) { + warning("STUB: _fqsort"); +} + +const char *ProgName(const char *ext) { + warning("ProgName"); + + static Common::String buf = "CGE"; + if (ext) + buf += ext; + return buf.c_str(); +} + +char *MergeExt(char *buf, const char *nam, const char *ext) { +// char dr[MAXDRIVE], di[MAXDIR], na[MAXFILE], ex[MAXEXT]; +// fnmerge(buf, dr, di, na, (fnsplit(nam, dr, di, na, ex) & EXTENSION) ? ex : ext); +// return buf; + warning("MergeExt"); + + strcpy(buf, nam); + char *dot = strrchr(buf, '.'); + if (!dot) + strcat(buf, ext); + + return buf; +} + +char *ForceExt(char *buf, const char *nam, const char *ext) { +// char dr[MAXDRIVE], di[MAXDIR], na[MAXFILE], ex[MAXEXT]; +// fnsplit(nam, dr, di, na, ex); +// fnmerge(buf, dr, di, na, ext); +// return buf; + strcpy(buf, nam); + char *dot = strrchr(buf, '.'); + if (dot) + *dot = '\0'; + strcat(buf, ext); + + return buf; +} + +static unsigned Seed = 1; + +unsigned FastRand(void) { + return Seed = 257 * Seed + 817; +} +unsigned FastRand(unsigned s) { + return Seed = 257 * s + 817; +} + +uint16 RCrypt(void *buf, uint16 siz, uint16 seed) { + if (buf && siz) { + byte *b = static_cast<byte *>(buf); + byte *q = b + (siz - 1); + seed = FastRand(seed); + *b++ ^= seed; + while (buf < q) + *b++ ^= FastRand(); + if (buf == q) + *b ^= (seed = FastRand()); + } + return seed; +} + +uint16 XCrypt(void *buf, uint16 siz, uint16 seed) { + byte *b = static_cast<byte *>(buf); + + for (uint16 i = 0; i < siz; i++) + *b++ ^= seed; + + return seed; +} + +uint16 atow(const char *a) { + uint16 w = 0; + if (a) + while (IsDigit(*a)) + w = (10 * w) + (*(a++) & 0xF); + return w; +} + +uint16 xtow(const char *x) { + uint16 w = 0; + if (x) { + while (IsHxDig(*x)) { + register uint16 d = *(x++); + if (d > '9') + d -= 'A' - ('9' + 1); + w = (w << 4) | (d & 0xF); + } + } + return w; +} + +char *wtom(uint16 val, char *str, int radix, int len) { + while (--len >= 0) { + uint16 w = val % radix; + if (w > 9) + w += ('A' - ('9' + 1)); + str[len] = '0' + w; + val /= radix; + } + return str; +} + +char *dwtom(uint32 val, char *str, int radix, int len) { + while (--len >= 0) { + uint16 w = (uint16) (val % radix); + if (w > 9) + w += ('A' - ('9' + 1)); + str[len] = '0' + w; + val /= radix; + } + return str; +} + +IOHAND::IOHAND(IOMODE mode, CRYPT *crpt) + : XFILE(mode), Crypt(crpt), Seed(SEED) { + _file = new Common::File(); +} + +IOHAND::IOHAND(const char *name, IOMODE mode, CRYPT *crpt) + : XFILE(mode), Crypt(crpt), Seed(SEED) { + // TODO: Check if WRI and/or UPD modes are needed, and map to a save file + assert(mode == REA); + + _file = new Common::File(); + _file->open(name); +} + +IOHAND::~IOHAND(void) { + _file->close(); + delete _file; +} + +uint16 IOHAND::Read(void *buf, uint16 len) { + if (Mode == WRI || !_file->isOpen()) + return 0; + + uint16 bytesRead = _file->read(buf, len); + if (!bytesRead) + error("Read %s - %d bytes", _file->getName(), len); + if (Crypt) + Seed = Crypt(buf, len, Seed); + return bytesRead; +} + +uint16 IOHAND::Write(void *buf, uint16 len) { + error("IOHAND::Write not supported"); +/* + if (len) { + if (Mode == REA || Handle < 0) + return 0; + if (Crypt) + Seed = Crypt(buf, len, Seed); + Error = _dos_write(Handle, buf, len, &len); + if (Crypt) + Seed = Crypt(buf, len, Seed); //------$$$$$$$ + } + return len; +*/ +} + +long IOHAND::Mark(void) { + return _file->pos(); +} + +long IOHAND::Seek(long pos) { + _file->seek(pos, SEEK_SET); + return _file->pos(); +} + +long IOHAND::Size(void) { + return _file->size(); +} + +bool IOHAND::Exist(const char *name) { + Common::File f; + return f.exists(name); +} + +//#define EMS_ADR(a) (FP_SEG(a) > 0xA000) +//#define HNODE_OK(p) (heapchecknode(p)==4) + +MEM_TYPE MemType(void *mem) { + /* if (FP_SEG(mem) == _DS) { + if (heapchecknode((void *)mem)==4) + return NEAR_MEM; + } else { + if (FP_SEG(mem) > 0xA000) + return EMS_MEM; + else if (farheapchecknode(mem)==4) + return FAR_MEM; + } + return BAD_MEM; + */ + warning("STUB: MemType"); + return FAR_MEM; +} + +bool IsVga() { + return true; +} + +EC void SNDInit() { + warning("STUB: SNDInit"); +} + +EC void SNDDone() { + // FIXME: STUB: SNDDone +} + +EC void SNDSetVolume() { + warning("STUB: SNDSetVolume"); +} + +EC void SNDDigiStart(SMPINFO *PSmpInfo) { + warning("STUB: SNDDigitStart"); +} + +EC void SNDDigiStop(SMPINFO *PSmpInfo) { + warning("STUB: SNDDigiStop"); +} + +EC void SNDMIDIStart(uint8 *MIDFile) { + warning("STUB: SNDMIDIStart"); +} + +EC void SNDMIDIStop() { + // FIXME: STUB: SNDMIDIStop +} + +DATACK *LoadWave(XFILE *file, EMM *emm) { + warning("STUB: LoadWave"); + return NULL; +} + +int TakeEnum(const char **tab, const char *txt) { + const char **e; + if (txt) { + for (e = tab; *e; e++) { + if (scumm_stricmp(txt, *e) == 0) { + return e - tab; + } + } + } + return -1; +} + +Boot *ReadBoot(int drive) { + /* + struct fatinfo fi; Boot *b; + getfat(drive+1, &fi); + if (fi.fi_sclus & 0x80) return NULL; + if ((b = malloc(fi.fi_bysec)) == NULL) return NULL; + // read boot sector + if (absread(drive, 1, 0L, b) == 0) return b; + free(b); + return NULL; + */ + warning("STUB: ReadBoot"); + return NULL; +} + +long Timer(void) { +/* + asm mov ax,0x40 + asm mov es,ax + asm mov cx,es:[0x6C] + asm mov dx,es:[0x6E] + return ((long) _DX << 16) | _CX; +*/ + warning("STUB: Timer"); + return 0; +} + +int new_random(int range) { + warning("STUB: new_random(a)"); + return 0; +} + +#define TIMER_INT 0x08 +//void interrupt (* ENGINE::OldTimer) (...) = NULL; + +ENGINE::ENGINE (uint16 tdiv) +{ +/* + // steal timer interrupt + OldTimer = getvect(TIMER_INT); + setvect(TIMER_INT, NewTimer); + + // set turbo-timer mode + asm mov al,0x36 + asm out 0x43,al + asm mov ax,TMR_DIV + asm out 0x40,al + asm mov al,ah + asm out 0x40,al +*/ + warning("STUB: ENGINE::ENGINE"); +} + +ENGINE::~ENGINE (void) +{ +/* + // reset timer + asm mov al,0x36 + asm out 0x43,al + asm xor al,al + asm out 0x40,al + asm out 0x40,al + // bring back timer interrupt + setvect(TIMER_INT, OldTimer); +*/ + warning("STUB: ENGINE::~ENGINE"); +} + +DATACK::~DATACK (void) +{ + if (!e && Buf) free(Buf); +} +} // End of namespace CGE + diff --git a/engines/cge/general.h b/engines/cge/general.h new file mode 100644 index 0000000000..4946e40c7b --- /dev/null +++ b/engines/cge/general.h @@ -0,0 +1,240 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __GENERAL__ +#define __GENERAL__ + +#include "common/system.h" +#include "common/file.h" +#include "common/random.h" +#include "common/textconsole.h" +#include "common/str.h" +#include "cge/jbw.h" +#include "cge/boot.h" + +namespace CGE { + +#define SEED 0xA5 + +#define SCR_WID_ 320 +#define SCR_HIG_ 200 +#define SCR_WID ((uint16)SCR_WID_) +#define SCR_HIG ((uint16)SCR_HIG_) +#define SCR_SEG 0xA000 +#define SCR_ADR ((uint8 *) MK_FP(SCR_SEG, 0)) + + + +//enum CPU { _8086, _80186, _80286, _80386, _80486 }; +enum MEM_TYPE { BAD_MEM, EMS_MEM, NEAR_MEM, FAR_MEM }; +enum ALLOC_MODE { FIRST_FIT, BEST_FIT, LAST_FIT }; +enum IOMODE { REA, WRI, UPD }; + +typedef struct { + uint8 R, G, B; +} DAC; + +typedef uint16 CRYPT(void *buf, uint16 siz, uint16 seed); + +class COUPLE { +protected: + signed char A; + signed char B; +public: + COUPLE(void) { } + COUPLE(const signed char a, const signed char b) : A(a), B(b) { } + COUPLE operator + (COUPLE c) { + return COUPLE(A + c.A, B + c.B); + } + + void operator += (COUPLE c) { + A += c.A; + B += c.B; + } + + COUPLE operator - (COUPLE c) { + return COUPLE(A - c.A, B - c.B); + } + + void operator -= (COUPLE c) { + A -= c.A; + B -= c.B; + } + + bool operator == (COUPLE c) { + return ((A - c.A) | (B - c.B)) == 0; + } + + bool operator != (COUPLE c) { + return !(operator == (c)); + } + + void Split(signed char &a, signed char &b) { + a = A; + b = B; + } +}; + + +class ENGINE { +protected: + static void (* OldTimer)(...); + static void NewTimer(...); +public: + ENGINE(uint16 tdiv); + ~ENGINE(void); +}; + + +class EMS; + + +class EMM { + friend class EMS; + bool Test(void); + long Top, Lim; + EMS *List; + int Han; + static void *Frame; +public: + EMM(long size = 0); + ~EMM(void); + EMS *Alloc(uint16 siz); + void Release(void); +}; + + +class EMS { + friend class EMM; + EMM *Emm; + long Ptr; + uint16 Siz; + EMS *Nxt; +public: + EMS(void); + void *operator & () const; + uint16 Size(void); +}; + + +template <class T> +void Swap(T &A, T &B) { + T a = A; + A = B; + B = a; +} + + +#ifdef __cplusplus +template <class T> +T max(T A, T B) { + return (A > B) ? A : B; +} + +template <class T> +T min(T A, T B) { + return (A < B) ? A : B; +} +#endif + + +class XFILE { +public: + IOMODE Mode; + uint16 Error; + XFILE(void) : Mode(REA), Error(0) { } + XFILE(IOMODE mode) : Mode(mode), Error(0) { } + virtual uint16 Read(void *buf, uint16 len) = 0; + virtual uint16 Write(void *buf, uint16 len) = 0; + virtual long Mark(void) = 0; + virtual long Size(void) = 0; + virtual long Seek(long pos) = 0; + virtual ~XFILE() { } +}; + + +template <class T> +inline uint16 XRead(XFILE *xf, T *t) { + return xf->Read((uint8 *) t, sizeof(*t)); +} + + +class IOHAND : public XFILE { +protected: + Common::File *_file; + uint16 Seed; + CRYPT *Crypt; +public: + IOHAND(const char *name, IOMODE mode = REA, CRYPT crypt = NULL); + IOHAND(IOMODE mode = REA, CRYPT *crpt = NULL); + virtual ~IOHAND(void); + static bool Exist(const char *name); + uint16 Read(void *buf, uint16 len); + uint16 Write(void *buf, uint16 len); + long Mark(void); + long Size(void); + long Seek(long pos); + //timeb Time (void); +// void SetTime (timeb t); +}; + + +CRYPT XCrypt; +CRYPT RCrypt; +MEM_TYPE MemType(void *mem); +uint16 atow(const char *a); +uint16 xtow(const char *x); +char *wtom(uint16 val, char *str, int radix, int len); +char *dwtom(uint32 val, char *str, int radix, int len); +int TakeEnum(const char **tab, const char *txt); +uint16 ChkSum(void *m, uint16 n); +long Timer(void); +char *MergeExt(char *buf, const char *nam, const char *ext); +char *ForceExt(char *buf, const char *nam, const char *ext); +int DriveCD(unsigned drv); +bool IsVga(void); + + +// MISSING FUNCTIONS +EC void _fqsort(void *base, uint16 nelem, uint16 width, int (*fcmp)(const void *, const void *)); +const char *ProgName(const char *ext = NULL); +char *MergeExt(char *buf, const char *nam, const char *ext); +char *ForceExt(char *buf, const char *nam, const char *ext); +unsigned FastRand(void); +unsigned FastRand(unsigned s); +uint16 RCrypt(void *buf, uint16 siz, uint16 seed); +uint16 atow(const char *a); +uint16 xtow(const char *x); +char *wtom(uint16 val, char *str, int radix, int len); +char *dwtom(uint32 val, char * str, int radix, int len); +int TakeEnum(const char **tab, const char *txt); +Boot *ReadBoot(int drive); +long Timer(void); +int new_random(int range); +} // End of namespace CGE + +#endif diff --git a/engines/cge/gettext.cpp b/engines/cge/gettext.cpp new file mode 100644 index 0000000000..e3c60b6e21 --- /dev/null +++ b/engines/cge/gettext.cpp @@ -0,0 +1,122 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/gettext.h" +#include "cge/keybd.h" +#include "cge/mouse.h" +#include "cge/cge_main.h" +#include <string.h> + +namespace CGE { + +GET_TEXT *GET_TEXT::Ptr = NULL; + + +GET_TEXT::GET_TEXT(CGEEngine *vm, const char *info, char *text, int size, void (*click)(void)) + : TALK(vm), Text(text), Size(min<int>(size, GTMAX)), Len(min<int>(Size, strlen(text))), + Cntr(GTBLINK), Click(click), OldKeybClient(KEYBOARD::SetClient(this)), _vm(vm) { + int i = 2 * TEXT_HM + _Font->Width(info); + Ptr = this; + Mode = RECT; + TS[0] = Box((i + 3) & ~3, 2 * TEXT_VM + 2 * FONT_HIG + TEXT_LS); + SetShapeList(TS); + _flags._bDel = true; + _flags._kill = true; + memcpy(Buff, text, Len); + Buff[Len] = ' '; + Buff[Len + 1] = '\0'; + PutLine(0, info); + Tick(); +} + + +GET_TEXT::~GET_TEXT(void) { + KEYBOARD::SetClient(OldKeybClient); + Ptr = NULL; +} + + +void GET_TEXT::Tick(void) { + if (++ Cntr >= GTBLINK) { + Buff[Len] ^= (' ' ^ '_'); + Cntr = 0; + } + PutLine(1, Buff); + _time = GTTIME; +} + + +void GET_TEXT::Touch(uint16 mask, int x, int y) { + static char ogon[] = "•œ¥£˜ ¡"; + static char bezo[] = "ACELNOSXZ"; + char *p; + + if (mask & KEYB) { + if (Click) + Click(); + switch (x) { + case Enter : + Buff[Len] = '\0'; + strcpy(Text, Buff); + for (p = Text; *p; p++) { + char *q = strchr(ogon, *p); + if (q) + *p = bezo[q - ogon]; + } + case Esc : + SNPOST_(SNKILL, -1, 0, this); + break; + case BSp : + if (Len) { + --Len; + Buff[Len] = Buff[Len + 1]; + Buff[Len + 1] = Buff[Len + 2]; + } + break; + default : + if (x < 'A' || x > 'Z') { + if (OldKeybClient) + OldKeybClient->Touch(mask, x, y); + } else { + if (KEYBOARD::Key[ALT]) { + p = strchr(bezo, x); + if (p) + x = ogon[p - bezo]; + } + if (Len < Size && 2 * TEXT_HM + _Font->Width(Buff) + _Font->Wid[x] <= _w) { + Buff[Len + 2] = Buff[Len + 1]; + Buff[Len + 1] = Buff[Len]; + Buff[Len++] = x; + } + } + break; + } + } else + Sprite::Touch(mask, x, y); +} + +} // End of namespace CGE diff --git a/engines/cge/gettext.h b/engines/cge/gettext.h new file mode 100644 index 0000000000..33210758af --- /dev/null +++ b/engines/cge/gettext.h @@ -0,0 +1,59 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __GETTEXT__ +#define __GETTEXT__ + +#include "cge/general.h" +#include "cge/talk.h" + +namespace CGE { + +#define GTMAX 24 +#define GTBLINK 6 +#define GTTIME 6 + +class GET_TEXT : public TALK { + char Buff[GTMAX + 2], * Text; + uint16 Size, Len; + uint16 Cntr; + Sprite *OldKeybClient; + void (*Click)(); +public: + static GET_TEXT *Ptr; + GET_TEXT(CGEEngine *vm, const char *info, char *text, int size, void (*click)(void) = NULL); + ~GET_TEXT(); + void Touch(uint16 mask, int x, int y); + void Tick(); + +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/ident.h b/engines/cge/ident.h new file mode 100644 index 0000000000..da36bfa682 --- /dev/null +++ b/engines/cge/ident.h @@ -0,0 +1,42 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __IDENT__ +#define __IDENT__ + +namespace CGE { + +struct IDENT { + char copr[83]; + char fill[8]; + unsigned long disk; + unsigned char cork; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/jbw.h b/engines/cge/jbw.h new file mode 100644 index 0000000000..12c6609f4e --- /dev/null +++ b/engines/cge/jbw.h @@ -0,0 +1,156 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __JBW__ +#define __JBW__ + +#include "common/scummsys.h" + +namespace CGE { + +// Defines found in cge.mak +#define VOL +#define INI_FILE VFILE // Or is it CFILE? +#define PIC_FILE VFILE +#define BMP_MODE 0 +// + +#define BEL 7 +#define BS 8 +#define HT 9 +#define LF 10 +#define FF 12 +#define CR 13 +#define MAXFILE 128 + +#define IsWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') +#define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') +#define IsLower(c) ((c) >= 'a' && (c) <= 'z') +#define IsDigit(c) ((c) >= '0' && (c) <= '9') +#define IsAlpha(c) (IsLower(c) || IsUpper(c) || (c) == '_') +#define IsAlNum(c) (IsAlpha(c) || IsDigit(c)) +#define IsHxDig(c) (IsDigit(c) || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) + +#define farnew(t, n) ((t *) malloc(sizeof(t) * (n))) +#define ArrayCount(a) (sizeof(a) / sizeof((a)[0])) +#define MAX_TIMER 0x1800B0L + +typedef void (MouseFunType)(void); + +#define Lo(d) (((int *) &d)[0]) +#define Hi(d) (((int *) &d)[1]) +#define LoWord(d) ((uint16) Lo(d)) +#define HiWord(d) ((uint16) Hi(d)) +#define K(n) (1024 * (n)) +#define MASK(n) ((1 << n) - 1) + +typedef enum { + NoKey = 0, CtrlA, CtrlB, CtrlC, CtrlD, CtrlE, CtrlF, CtrlG, CtrlH, + CtrlI, CtrlJ, CtrlK, CtrlL, CtrlM, CtrlN, CtrlO, CtrlP, + CtrlQ, CtrlR, CtrlS, CtrlT, CtrlU, CtrlV, CtrlW, CtrlX, + CtrlY, CtrlZ, + BSp = 8, + Tab = 9, + Enter = 13, + Eof = 26, + Esc = 27, + AltQ = 256 + 16, AltW, AltE, AltR, AltT, AltY, AltU, AltI, AltO, AltP, + AltA = 256 + 30, AltS, AltD, AltF, AltG, AltH, AltJ, AltK, AltL, + AltZ = 256 + 44, AltX, AltC, AltV, AltB, AltN, AltM, + F11 = 256 + 87, F12, + F1 = 256 + 59, F2, F3, F4, F5, F6, F7, F8, F9, F10, + ShiftTab = 256 + 15, + ShiftF1 = 256 + 84, ShiftF2, ShiftF3, ShiftF4, ShiftF5, + ShiftF6, ShiftF7, ShiftF8, ShiftF9, ShiftF10, + CtrlF1 = 256 + 94, CtrlF2, CtrlF3, CtrlF4, CtrlF5, + CtrlF6, CtrlF7, CtrlF8, CtrlF9, CtrlF10, + AltF1 = 256 + 104, AltF2, AltF3, AltF4, AltF5, + AltF6, AltF7, AltF8, AltF9, AltF10, + Home = 256 + 71, + Up, + PgUp, + Left = 256 + 75, + Ctr, + Right, + End = 256 + 79, + Down, + PgDn, + Ins, + Del, + CtrlLeft = 256 + 115, + CtrlRight, + CtrlEnd, + CtrlPgDn, + CtrlHome, + CtrlPgUp = 256 + 132, + + MouseLeft = 512 + 1, + MouseRight, + TwiceLeft = 512 + 256 + 1, + TwiceRight +} Keys; + +struct KeyStatStruct { + int RShift : 1; + int LShift : 1; + int Ctrl : 1; + int Alt : 1; + + int ScrollLock : 1; + int NumLock : 1; + int CapsLock : 1; + int Ins : 1; + + int LeftCtrl : 1; + int LeftAlt : 1; + int Unused : 6; +}; + +#define HGC_Cursor 0x0B0C +#define CGA_Cursor 0x0607 +#define OFF_Cursor 0x2000 + +#define TimerCount (*((volatile long *) ((void _seg *) 0x40 + (void *) 0x6C))) +#define KeyStat (*((volatile struct KeyStatStruct *) ((void _seg *) 0x40 + (void *) 0x17))) +#define BreakFlag (*((volatile uint8 *) ((void _seg *) 0x40 + (void *) 0x71))) +#define PostFlag (*((volatile uint16 *) ((void _seg *) 0x40 + (void *) 0x72))) +#define POST ((void (*)(void)) ((void _seg *) 0xF000 + (void *) 0xFFF0)) + + +#ifdef __cplusplus +#define EC extern "C" +#else +#define EC +#endif + + +extern uint16 _stklen; +extern uint16 _heaplen; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/keybd.cpp b/engines/cge/keybd.cpp new file mode 100644 index 0000000000..8530815b16 --- /dev/null +++ b/engines/cge/keybd.cpp @@ -0,0 +1,151 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/keybd.h" +#include "cge/mouse.h" + +namespace CGE { + +Sprite *KEYBOARD::Client = NULL; +uint8 KEYBOARD::Key[0x60] = { 0 }; +uint16 KEYBOARD::Current = 0; +uint16 KEYBOARD::Code[0x60] = { + 0, Esc, '1', '2', '3', + '4', '5', '6', '7', '8', + '9', '0', '-', '+', BSp, + Tab, 'Q', 'W', 'E', 'R', + 'T', 'Y', 'U', 'I', 'O', + 'P', '[', ']', Enter, 0/*Ctrl*/, + 'A', 'S', 'D', 'F', 'G', + 'H', 'J', 'K', 'L', ';', + '\'', '`', 0/*LShift*/, '\\', 'Z', + 'X', 'C', 'V', 'B', 'N', + 'M', ',', '.', '/', 0/*RShift*/, + '*', 0/*Alt*/, ' ', 0/*Caps*/, F1, + F2, F3, F4, F5, F6, + F7, F8, F9, F10, 0/*NumLock*/, + 0/*ScrollLock*/, Home, Up, PgUp, '-', + Left, Ctr, Right, '+', End, + Down, PgDn, Ins, Del, 0 * 0x54, + 0 * 0x55, 0 * 0x56, F11, F12, 0 * 0x59, + 0 * 0x5A, 0 * 0x5B, 0 * 0x5C, 0 * 0x5D, 0 * 0x5E, + 0 * 0x5F +}; + +void (* KEYBOARD::OldKeyboard)(...); + + +KEYBOARD::KEYBOARD(void) { + // steal keyboard interrupt + /* TODO replace totally by scummvm handling + OldKeyboard = getvect(KEYBD_INT); + setvect(KEYBD_INT, NewKeyboard); + */ + warning("STUB: KEYBOARD::KEYBOARD"); +} + + +KEYBOARD::~KEYBOARD(void) { + // bring back keyboard interrupt + /* TODO replace totally by scummvm handling + setvect(KEYBD_INT, OldKeyboard); + */ + // FIXME: STUB: KEYBOARD::~KEYBOARD +} + + +Sprite *KEYBOARD::SetClient(Sprite *spr) { + Swap(Client, spr); + return spr; +} + + +void KEYBOARD::NewKeyboard(...) { + // table address + /* + _SI = (uint16) Key; + + // take keyboard code + asm in al,60h + asm mov bl,al + asm and bx,007Fh + asm cmp bl,60h + asm jae xit + asm cmp al,bl + asm je ok // key pressed + + // key released... + asm cmp [si+bx],bh // BH == 0 + asm jne ok + // ...but not pressed: call the original service + OldKeyboard(); + return; + + ok: + asm shl ax,1 + asm and ah,1 + asm xor ah,1 + asm mov [si+bx],ah + asm jz xit // released: exit + + // pressed: lock ASCII code + _SI = (uint16) Code; + asm add bx,bx // uint16 size + asm mov ax,[si+bx] + asm or ax,ax + asm jz xit // zero means NO KEY + Current = _AX; + + _SI = (uint16) Client; + asm or si,si + asm jz xit // if (Client) ... + //--- fill current event entry with mask, key code and sprite + asm mov bx,EvtHead // take queue head pointer + asm inc byte ptr EvtHead // update queue head pointer + asm shl bx,3 // * 8 + _AX = Current; + asm mov Evt[bx].(struct EVENT)X,ax // key code + asm mov ax,KEYB // event mask + asm mov Evt[bx].(struct EVENT)Msk,ax // event mask + //asm mov Evt[bx].(struct EVENT)Y,dx // row + asm mov Evt[bx].(struct EVENT)Ptr,si // SPRITE pointer + + xit: + + asm in al,61h // kbd control lines + asm push ax // save it + asm or al,80h // set the "enable kbd" bit + asm out 61h,al // and write it out + asm pop ax // original control port value + asm out 61h,al // write it back + asm mov al,20h // send End-Of-Interrupt + asm out 20h,al // to the 8259 IC + */ + warning("STUB: KEYBOARD::NewKeyboard"); +} + +} // End of namespace CGE diff --git a/engines/cge/keybd.h b/engines/cge/keybd.h new file mode 100644 index 0000000000..2cdbd558d8 --- /dev/null +++ b/engines/cge/keybd.h @@ -0,0 +1,63 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __KEYBD__ +#define __KEYBD__ + +#include "cge/jbw.h" +#include "cge/vga13h.h" + +namespace CGE { + +#define KEYBD_INT 9 +#define LSHIFT 42 +#define RSHIFT 54 +#define CTRL 29 +#define ALT 56 + + +class KEYBOARD { +public: + static void (* OldKeyboard)(...); + static void NewKeyboard(...); + static uint16 Code[0x60]; + static uint16 Current; + static Sprite *Client; + static uint8 Key[0x60]; + static uint16 Last(void) { + uint16 cur = Current; + Current = 0; + return cur; + } + static Sprite *SetClient(Sprite *spr); + KEYBOARD(void); + ~KEYBOARD(void); +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/mixer.cpp b/engines/cge/mixer.cpp new file mode 100644 index 0000000000..7b9ce59f5e --- /dev/null +++ b/engines/cge/mixer.cpp @@ -0,0 +1,145 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/mixer.h" +#include "cge/text.h" +#include "cge/snail.h" +#include "cge/mouse.h" +#include "cge/snddrv.h" +#include "cge/cge_main.h" +#include <string.h> + +namespace CGE { + +extern MOUSE *Mouse; + +bool MIXER::Appear = false; + + +MIXER::MIXER(CGEEngine *vm, int x, int y) : Sprite(vm, NULL), Fall(MIX_FALL), _vm(vm) { + Appear = true; + mb[0] = new Bitmap("VOLUME"); + mb[1] = NULL; + SetShapeList(mb); + SetName(Text->getText(MIX_NAME)); + _flags._syst = true; + _flags._kill = true; + _flags._bDel = true; + Goto(x, y); + _z = MIX_Z; + + // slaves + + uint i; + for (i = 0; i < MIX_MAX; i++) { + static char fn[] = "V00"; + wtom(i, fn + 1, 10, 2); + lb[i] = new Bitmap(fn); + ls[i].Now = ls[i].Next = i; + ls[i].Dx = ls[i].Dy = ls[i].Dly = 0; + } + lb[i] = NULL; + + for (i = 0; i < ArrayCount(Led); i++) { + register Sprite *spr = new Sprite(_vm, lb); + spr->SetSeq(ls); + spr->Goto(x + 2 + 12 * i, y + 8); + spr->_flags._tran = true; + spr->_flags._kill = true; + spr->_flags._bDel = false; + spr->_z = MIX_Z; + Led[i] = spr; + } + Led[ArrayCount(Led) - 1]->_flags._bDel = true; + + Vga->ShowQ->Insert(this); + for (i = 0; i < ArrayCount(Led); i++) + Vga->ShowQ->Insert(Led[i]); + + //--- reset balance + i = (SNDDrvInfo.VOL4.ML + SNDDrvInfo.VOL4.MR) / 2; + SNDDrvInfo.VOL4.ML = i; + SNDDrvInfo.VOL4.MR = i; + i = (SNDDrvInfo.VOL4.DL + SNDDrvInfo.VOL4.DR) / 2; + SNDDrvInfo.VOL4.DL = i; + SNDDrvInfo.VOL4.DR = i; + Update(); + _time = MIX_DELAY; +} + +MIXER::~MIXER(void) { + Appear = false; +} + + +#pragma argsused +void MIXER::Touch(uint16 mask, int x, int y) { + Sprite::Touch(mask, x, y); + if (mask & L_UP) { + uint8 *vol = (&SNDDrvInfo.VOL2.D) + (x < _w / 2); + if (y < MIX_BHIG) { + if (*vol < 0xFF) + *vol += 0x11; + } else if (y >= _h - MIX_BHIG) { + if (*vol > 0x00) + *vol -= 0x11; + } + Update(); + } +} + + +void MIXER::Tick(void) { + int x = Mouse->_x; + int y = Mouse->_y; + if (SpriteAt(x, y) == this) { + Fall = MIX_FALL; + if (_flags._hold) + Touch(L_UP, x - _x, y - _y); + } else { + if (Fall) + --Fall; + else { + for (uint i = 0; i < ArrayCount(Led); i++) + SNPOST_(SNKILL, -1, 0, Led[i]); + SNPOST_(SNKILL, -1, 0, this); + } + } + _time = MIX_DELAY; +} + + +void MIXER::Update(void) { + Led[0]->Step(SNDDrvInfo.VOL4.ML); + Led[1]->Step(SNDDrvInfo.VOL4.DL); + + //TODO Change the SNPOST message send to a special way to send function pointer + //SNPOST_(SNEXEC, -1, 0, (void*)&SNDSetVolume); + warning("STUB: MIXER::Update"); +} + +} // End of namespace CGE diff --git a/engines/cge/mixer.h b/engines/cge/mixer.h new file mode 100644 index 0000000000..d42d25ca24 --- /dev/null +++ b/engines/cge/mixer.h @@ -0,0 +1,61 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __MIXER__ +#define __MIXER__ + +#include "cge/vga13h.h" + +namespace CGE { + +#define MIX_MAX 16 // count of Leds +#define MIX_Z 64 // mixer Z position +#define MIX_DELAY 12 // 6/s +#define MIX_FALL 6 // in MIX_DELAY units +#define MIX_BHIG 6 // mixer button high +#define MIX_NAME 105 // sprite name + +class MIXER : public Sprite { + BMP_PTR mb[2]; + BMP_PTR lb[MIX_MAX + 1]; + Seq ls[MIX_MAX]; + Sprite *Led[2]; + int Fall; + void Update(void); +public: + static bool Appear; + MIXER(CGEEngine *vm, int x, int y); + ~MIXER(); + void Touch(uint16 mask, int x, int y); + void Tick(); +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/module.mk b/engines/cge/module.mk new file mode 100644 index 0000000000..70967667a5 --- /dev/null +++ b/engines/cge/module.mk @@ -0,0 +1,39 @@ +MODULE := engines/cge + +MODULE_OBJS := \ + bitmap.o \ + bitmaps.o \ + btfile.o \ + cfile.o \ + cge.o \ + cge_main.o \ + config.o \ + console.o \ + detection.o \ + ems.o \ + game.o \ + general.o \ + gettext.o \ + keybd.o \ + mixer.o \ + mouse.o \ + snail.o \ + sound.o \ + startup.o \ + talk.o \ + text.o \ + vga13h.o \ + vmenu.o \ + vol.o + +MODULE_DIRS += \ + engines/cge + +# This module can be built as a plugin +ifeq ($(ENABLE_CGE), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk + diff --git a/engines/cge/mouse.cpp b/engines/cge/mouse.cpp new file mode 100644 index 0000000000..5bdf7449fc --- /dev/null +++ b/engines/cge/mouse.cpp @@ -0,0 +1,194 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/mouse.h" +#include "cge/text.h" +#include "cge/cge_main.h" + +namespace CGE { + +Event Evt[EVT_MAX]; + +uint16 EvtHead = 0, EvtTail = 0; + +MOUSE_FUN *MOUSE::OldMouseFun = NULL; +uint16 MOUSE::OldMouseMask = 0; + + +MOUSE::MOUSE(CGEEngine *vm, Bitmap **shpl) : Sprite(vm, shpl), Busy(NULL), Hold(NULL), hx(0), _vm(vm) { + static Seq ms[] = { + { 0, 0, 0, 0, 1 }, + { 1, 1, 0, 0, 1 } + }; + + SetSeq(ms); + + /* TODO Mouse handling + // Mouse reset + _AX = 0x0000; // soft & hard reset (0x0021 soft reset does not work) + __int__(0x33); + Exist = (_AX != 0); + Buttons = _BX; + + Goto(SCR_WID/2, SCR_HIG/2); + Z = 127; + Step(1); + */ + Exist = true; + warning("STUB: MOUSE::MOUSE"); +} + + +MOUSE::~MOUSE(void) { + Off(); +} + + +//void MOUSE::SetFun (void) +//{ +//} + + +void MOUSE::On(void) { + /* + if (SeqPtr && Exist) + { + _CX = X + X; // horizontal position + _DX = Y; // vertical position + _AX = 0x0004; // Set Mouse Position + __int__(0x33); + // set new mouse fun + _ES = FP_SEG(NewMouseFun); + _DX = FP_OFF(NewMouseFun); + _CX = 0x001F; // 11111b = all events + _AX = 0x0014; // Swap User-Interrupt Vector + __int__(0x33); + // save old mouse fun + OldMouseMask = _CX; + OldMouseFun = (MOUSE_FUN *) MK_FP(_ES, _DX); + + // set X bounds + _DX = (SCR_WID - W) * 2; // right limit + _CX = 0; // left limit + _AX = 0x0007; // note: each pixel = 2 + __int__(0x33); + + // set Y bounds + _DX = SCR_HIG - H; // bottom limit + _CX = 0; // top limit + _AX = 0x0008; + __int__(0x33); + + Step(0); + if (Busy) Busy->Step(0); + } + */ + warning("STUB: MOUSE::On"); +} + + +void MOUSE::Off(void) { +/* + if (SeqPtr == 0) + { + if (Exist) + { + // bring back old mouse fun + _ES = FP_SEG(OldMouseFun); + _DX = FP_OFF(OldMouseFun); + _CX = OldMouseMask; + _AX = 0x0014; // Swap User-Interrupt Vector + __int__(0x33); + } + Step(1); + if (Busy) Busy->Step(1); + } + */ + warning("STUB: MOUSE::Off"); +} + + +void MOUSE::ClrEvt(Sprite *spr) { + if (spr) { + uint16 e; + for (e = EvtTail; e != EvtHead; e = (e + 1) % EVT_MAX) + if (Evt[e]._ptr == spr) + Evt[e]._msk = 0; + } else + EvtTail = EvtHead; +} + + +void MOUSE::Tick(void) { + Step(); + while (EvtTail != EvtHead) { + Event e = Evt[EvtTail]; + if (e._msk) { + if (Hold && e._ptr != Hold) + Hold->Touch(e._msk | ATTN, e._x - Hold->_x, e._y - Hold->_y); + + // update mouse cursor position + if (e._msk & ROLL) + Goto(e._x, e._y); + + // activate current touched SPRITE + if (e._ptr) { + if (e._msk & KEYB) + e._ptr->Touch(e._msk, e._x, e._y); + else + e._ptr->Touch(e._msk, e._x - e._ptr->_x, e._y - e._ptr->_y); + } else if (Sys) + Sys->Touch(e._msk, e._x, e._y); + + if (e._msk & L_DN) { + Hold = e._ptr; + if (Hold) { + Hold->_flags._hold = true; + hx = e._x - Hold->_x; + hy = e._y - Hold->_y; + } + } + + if (e._msk & L_UP) { + if (Hold) { + Hold->_flags._hold = false; + Hold = NULL; + } + } + ///Touched = e.Ptr; + + // discard Text if button released + if (e._msk & (L_UP | R_UP)) + KillText(); + } + EvtTail = (EvtTail + 1) % EVT_MAX; + } + if (Hold) + Hold->Goto(_x - hx, _y - hy); +} + +} // End of namespace CGE diff --git a/engines/cge/mouse.h b/engines/cge/mouse.h new file mode 100644 index 0000000000..4d95f10423 --- /dev/null +++ b/engines/cge/mouse.h @@ -0,0 +1,85 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __MOUSE__ +#define __MOUSE__ + +#include "cge/game.h" +#include "cge/talk.h" + +namespace CGE { + +#define EVT_MAX 256 +#define ROLL 0x01 +#define L_DN 0x02 +#define L_UP 0x04 +#define R_DN 0x08 +#define R_UP 0x10 +#define ATTN 0x20 // 0x40 +#define KEYB 0x80 + + +extern TALK *Talk; + +struct Event { + uint16 _msk; + uint16 _x; + uint16 _y; + Sprite *_ptr; +}; + +extern Event Evt[EVT_MAX]; +extern uint16 EvtHead, EvtTail; +typedef void (MOUSE_FUN)(void); + + +class MOUSE : public Sprite { + static MOUSE_FUN *OldMouseFun; + static MOUSE_FUN NewMouseFun; + static uint16 OldMouseMask; + Sprite *Hold; + int hx, hy; + //void SetFun (void); + //void ResetFun (void); +public: + bool Exist; + int Buttons; + Sprite *Busy; + //Sprite *Touched; + MOUSE(CGEEngine *vm, Bitmap **shpl = MC); + ~MOUSE(); + void On(); + void Off(); + static void ClrEvt(Sprite *spr = NULL); + void Tick(); +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/snail.cpp b/engines/cge/snail.cpp new file mode 100644 index 0000000000..565c7d33f0 --- /dev/null +++ b/engines/cge/snail.cpp @@ -0,0 +1,1135 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/general.h" +#include "cge/sound.h" +#include "cge/snail.h" +#include "cge/vga13h.h" +#include "cge/bitmaps.h" +#include "cge/text.h" +#include "cge/mouse.h" +#include "cge/cge_main.h" +#include <stdio.h> +#include <stdlib.h> +#include "cge/keybd.h" + +namespace CGE { + +static void _enable() { + warning("STUB: _enable"); +} + +static void _disable() { + warning("STUB: _disable"); +} + +int MaxCave = 0; + +SCB Scb = { NULL, 0, NULL }; +bool Flag[4]; +bool Dark = false; +bool Game = false; +int Now = 1; +int Lev = -1; + +extern Sprite *_pocLight; + +//------------------------------------------------------------------------- +// SPRITE * Pocket[POCKET_NX]={ NULL, NULL, NULL, NULL, +// NULL, NULL, NULL, NULL, }; +// int PocPtr = 0; +//------------------------------------------------------------------------- +extern Sprite *_pocket[]; +extern int PocPtr; + +static void SNGame(Sprite *spr, int num) { + switch (num) { + case 1 : { +#define STAGES 8 +#define DRESSED 3 + static Sprite *dup[3] = { NULL, NULL, NULL }; + int buref = 0; + int Stage = 0; + + for (dup[0] = Vga->ShowQ->First(); dup[0]; dup[0] = dup[0]->_next) { + buref = dup[0]->_ref; + if (buref / 1000 == 16 && buref % 100 == 6) { + Stage = (buref / 100) % 10; + break; + } + } + if (dup[1] == NULL) { + dup[1] = Vga->ShowQ->Locate(16003); // pan + dup[2] = Vga->ShowQ->Locate(16004); // pani + } + + if (Game) { // continue game + int i = new_random(3), hand = (dup[0]->_shpCnt == 6); + Stage++; + if (hand && Stage > DRESSED) + ++hand; + if (i >= 0 || (dup[i] == spr && new_random(3) == 0)) { + SNPOST(SNSEQ, -1, 3, dup[0]); // yes + SNPOST(SNSEQ, -1, 3, dup[1]); // yes + SNPOST(SNSEQ, -1, 3, dup[2]); // yes + SNPOST(SNTNEXT, -1, 0, dup[0]); // reset Take + SNPOST(SNTNEXT, -1, 0, dup[1]); // reset Take + SNPOST(SNTNEXT, -1, 0, dup[2]); // reset Take + SNPOST(SNNNEXT, -1, 0, dup[0]); // reset Near + SNPOST(SNPAUSE, -1, 72, NULL); // little rest + SNPOST(SNSAY, 1, 16009, NULL); // hura + SNPOST(SNSAY, buref, 16010, NULL); // siadaj + SNPOST(SNSAY, 1, 16011, NULL); // postoj‘ + + if (hand) { + SNPOST(SNSEND, 16060 + hand, 16, NULL); // dawaj r‘k‘ + SNPOST(SNSEQ, buref, 4, NULL); // zdejmowanie + SNPOST(SNSEQ, 16060 + hand, 1, NULL); // ruch + SNPOST(SNSOUND, 16060 + hand, 16002, NULL); // szelest + SNPOST(SNWAIT, 16060 + hand, 3, NULL); // podniesie + SNPOST(SNSWAP, buref, buref + 100, NULL); // rozdziana + SNPOST(SNSEQ, 16016, Stage, NULL); // rožnie kupa + SNPOST(SNSEND, 16060 + hand, -1, NULL); // chowaj r‘k‘ + SNPOST(SNWAIT, 16060 + hand, -1, NULL); // r‘ka zamar’a + } else { + SNPOST(SNSEQ, buref, 4, NULL); // zdejmowanie + SNPOST(SNSOUND, 16060 + hand, 16002, NULL); // szelest + SNPOST(SNWAIT, buref, -1, NULL); // zdejmie + SNPOST(SNSWAP, buref, buref + 100, NULL); // rozdziana + SNPOST(SNSEQ, 16016, Stage, NULL); // rožnie kupa + } + //SNPOST(SNSEQ, buref+100, 0, NULL); // reset + SNPOST(SNPAUSE, -1, 72, NULL); // chwilk‘... + + SNPOST(SNSEQ, -1, 0, dup[1]); // odstaw Go + SNPOST(SNSETXY, -1, 203 + SCR_WID * 49, dup[1]); + SNPOST(SNSETZ, -1, 7, dup[1]); + + SNPOST(SNSEQ, -1, 0, dup[2]); // odstaw J† + SNPOST(SNSETXY, -1, 182 + SCR_WID * 62, dup[2]); + SNPOST(SNSETZ, -1, 9, dup[2]); + Game = 0; + return; + } else { + SNPOST(SNSEQ, -1, 2, dup[0]); // no + SNPOST(SNSEQ, -1, 2, dup[1]); // no + SNPOST(SNSEQ, -1, 2, dup[2]); // no + SNPOST(SNPAUSE, -1, 72, NULL); // 1 sec + } + } + SNPOST(SNWALK, 198, 134, NULL); // na miejsce + SNPOST(SNWAIT, 1, -1, NULL); // stoi + SNPOST(SNCOVER, 1, 16101, NULL); // ch’op do bicia + SNPOST(SNSEQ, 16101, 1, NULL); // wystaw + SNPOST(SNWAIT, 16101, 5, NULL); // czekaj + SNPOST(SNPAUSE, 16101, 24, NULL); // czekaj chwil‘ + SNPOST(SNSEQ, 16040, 1, NULL); // plask + SNPOST(SNSOUND, 16101, 16001, NULL); // plask! + SNPOST(SNPAUSE, 16101, 24, NULL); // czekaj chwil‘ + SNPOST(SNSEQ, 16040, 0, NULL); // schowaj plask + SNPOST(SNWAIT, 16101, -1, NULL); // stoi + SNPOST(SNUNCOVER, 1, 16101, NULL); // SDS + if (! Game) { + SNPOST(SNSAY, buref, 16008, NULL); // zgadnij! + Game = true; + } +#undef STEPS +#undef DRESSED + } + break; + //-------------------------------------------------------------------- + case 2 : { + static Sprite *k = NULL, * k1, * k2, * k3; + static int count = 0; + + if (k == NULL) { + k = Vga->ShowQ->Locate(20700); + k1 = Vga->ShowQ->Locate(20701); + k2 = Vga->ShowQ->Locate(20702); + k3 = Vga->ShowQ->Locate(20703); + } + + if (! Game) { // init + SNPOST(SNGAME, 20002, 2, NULL); + Game = true; + } else { // cont + k1->Step(new_random(6)); + k2->Step(new_random(6)); + k3->Step(new_random(6)); + ///-------------------- + if (spr->_ref == 1 && KEYBOARD::Key[ALT]) { + k1->Step(5); + k2->Step(5); + k3->Step(5); + } + ///-------------------- + SNPOST(SNSETZ, 20700, 0, NULL); + bool hit = (k1->_seqPtr + k2->_seqPtr + k3->_seqPtr == 15); + if (hit) { + if (spr->_ref == 1) { + SNPOST(SNSAY, 1, 20003, NULL); // hura! + SNPOST(SNSEQ, 20011, 2, NULL); // kamera won + SNPOST(SNSEND, 20701, -1, NULL); // k1 won + SNPOST(SNSEND, 20702, -1, NULL); // k2 won + SNPOST(SNSEND, 20703, -1, NULL); // k3 won + SNPOST(SNSEND, 20700, -1, NULL); // tv won + SNPOST(SNKEEP, 20007, 0, NULL); // do kieszeni + SNPOST(SNSEND, 20006, 20, NULL); // bilon + SNPOST(SNSOUND, 20006, 20002, NULL); // bilon! + SNPOST(SNSAY, 20002, 20004, NULL); + SNPOST(SNSEND, 20010, 20, NULL); // papier + SNPOST(SNSOUND, 20010, 20003, NULL); // papier! + SNPOST(SNSAY, 20001, 20005, NULL); + Game = false; + return; + } else + k3->Step(new_random(5)); + } + if (count < 100) { + switch (count) { + case 15 : + SNPOST(SNSAY, 20003, 20021, NULL); + break; + case 30 : + case 45 : + case 60 : + case 75 : + SNPOST(SNSAY, 20003, 20022, NULL); + break; + } + ++ count; + } + switch (spr->_ref) { + case 1 : + SNPOST(SNSAY, 20001, 20011, NULL); // zapro + SNPOST(SNSEQ, 20001, 1, NULL); // rzu + SNPOST(SNWAIT, 20001, 1, NULL); // czekaj + SNPOST(SNSETZ, 20700, 2, NULL); // skryj k + SNPOST(SNHIDE, 20007, 1, NULL); // skryj k + SNPOST(SNWAIT, 20001, 16, NULL); // czekaj + SNPOST(SNSEQ, 20007, 1, NULL); // lec† + SNPOST(SNHIDE, 20007, 0, NULL); // poka§ + SNPOST(SNSOUND, 20007, 20001, NULL); // grzech + SNPOST(SNWAIT, 20007, -1, NULL); // koniec + SNPOST(SNGAME, 20001, 2, NULL); // again! + break; + case 20001: + SNPOST(SNSAY, 20002, 20012, NULL); // zapro + SNPOST(SNSEQ, 20002, 1, NULL); // rzu + SNPOST(SNWAIT, 20002, 3, NULL); // czekaj + SNPOST(SNSETZ, 20700, 2, NULL); // skryj k + SNPOST(SNHIDE, 20007, 1, NULL); // skryj k + SNPOST(SNWAIT, 20002, 10, NULL); // czekaj + SNPOST(SNSEQ, 20007, 2, NULL); // lec† + SNPOST(SNHIDE, 20007, 0, NULL); // poka§ + SNPOST(SNSOUND, 20007, 20001, NULL); // grzech + SNPOST(SNWAIT, 20007, -1, NULL); // koniec + SNPOST(SNGAME, 20002, 2, NULL); // again! + break; + case 20002: + SNPOST(SNSAY, 20002, 20010, NULL); // zapro + SNPOST(SNWALK, 20005, -1, NULL); // do stol + SNPOST(SNWAIT, 1, -1, NULL); // stoi + SNPOST(SNCOVER, 1, 20101, NULL); // grasol + SNPOST(SNSEQ, 20101, 1, NULL); // rzu + SNPOST(SNWAIT, 20101, 5, NULL); // czekaj + SNPOST(SNSETZ, 20700, 2, NULL); // skryj k + SNPOST(SNHIDE, 20007, 1, NULL); // skryj k + SNPOST(SNWAIT, 20101, 15, NULL); // czekaj + SNPOST(SNSEQ, 20007, 1, NULL); // lec† + SNPOST(SNHIDE, 20007, 0, NULL); // poka§ + SNPOST(SNSOUND, 20007, 20001, NULL); // grzech + SNPOST(SNWAIT, 20101, -1, NULL); // koniec + SNPOST(SNUNCOVER, 1, 20101, NULL); // SDS + SNPOST(SNGAME, 1, 2, NULL); // again! + break; + } + } + } + break; + } +} + + +void ExpandSprite(Sprite *spr) { + if (spr) + Vga->ShowQ->Insert(Vga->SpareQ->Remove(spr)); +} + + +void ContractSprite(Sprite *spr) { + if (spr) + Vga->SpareQ->Append(Vga->ShowQ->Remove(spr)); +} + +int FindPocket(Sprite *spr) { + for (int i = 0; i < POCKET_NX; i++) + if (_pocket[i] == spr) + return i; + return -1; +} + + +void SelectPocket(int n) { + if (n < 0 || (_pocLight->_seqPtr && PocPtr == n)) { + _pocLight->Step(0); + n = FindPocket(NULL); + if (n >= 0) + PocPtr = n; + } else { + if (_pocket[n] != NULL) { + PocPtr = n; + _pocLight->Step(1); + } + } + _pocLight->Goto(POCKET_X + PocPtr * POCKET_DX + POCKET_SX, POCKET_Y + POCKET_SY); +} + + +void PocFul(void) { + Hero->Park(); + SNPOST(SNWAIT, -1, -1, Hero); + SNPOST(SNSEQ, -1, POC_FUL, Hero); + SNPOST(SNSOUND, -1, 2, Hero); + SNPOST(SNWAIT, -1, -1, Hero); + SNPOST(SNSAY, 1, POC_FUL_TEXT, Hero); +} + + +void Hide1(Sprite *spr) { + SNPOST_(SNGHOST, -1, 0, spr->Ghost()); +} + + +void SNGhost(Bitmap *bmp) { + // TODO : Get x and y from M but not using segment / offset + //bmp->Hide(FP_OFF(bmp->_m), FP_SEG(bmp->_m)); + bmp->_m = NULL; + delete bmp; + warning("STUB: SNGhost"); +} + + +void FeedSnail(Sprite *spr, SNLIST snq) { + if (spr) + if (spr->Active()) { + uint8 ptr = (snq == TAKE) ? spr->TakePtr : spr->NearPtr; + + if (ptr != NO_PTR) { + SNAIL::COM *comtab = spr->SnList(snq); + SNAIL::COM *c = comtab + ptr; + + if (FindPocket(NULL) < 0) { // no empty pockets? + SNAIL::COM *p; + for (p = c; p->Com != SNNEXT; p++) { // find KEEP command + if (p->Com == SNKEEP) { + PocFul(); + return; + } + if (p->Ptr) + break; + } + } + while (true) { + if (c->Com == SNTALK) { + if ((Snail->TalkEnable = (c->Val != 0)) == false) + KillText(); + } + if (c->Com == SNNEXT) { + Sprite *s = (c->Ref < 0) ? spr : Locate(c->Ref); + if (s) { + uint8 *idx = (snq == TAKE) ? &s->TakePtr : &s->NearPtr; + if (*idx != NO_PTR) { + int v; + switch (c->Val) { + case -1 : + v = c - comtab + 1; + break; + case -2 : + v = c - comtab; + break; + case -3 : + v = -1; + break; + default : + v = c->Val; + break; + } + if (v >= 0) + *idx = v; + } + } + if (s == spr) + break; + } + if (c->Com == SNIF) { + Sprite *s = (c->Ref < 0) ? spr : Locate(c->Ref); + if (s) { // sprite extsts + if (! s->SeqTest(-1)) + c = comtab + c->Val; // not parked + else + ++c; + } else + ++c; + } else { + SNPOST(c->Com, c->Ref, c->Val, spr); + if (c->Ptr) + break; + else + ++c; + } + } + } + } +} + + +const char *SNAIL::ComTxt[] = { + "LABEL", "PAUSE", "WAIT", "LEVEL", "HIDE", + "SAY", "INF", "TIME", "CAVE", "KILL", + "RSEQ", "SEQ", "SEND", "SWAP", "KEEP", + "GIVE", "IF", "GAME", "SETX0", "SETY0", + "SLAVE", "SETXY", "RELX", "RELY", "RELZ", + "SETX", "SETY", "SETZ", "TRANS", "PORT", + "NEXT", "NNEXT", "TNEXT", "RNNEXT", "RTNEXT", + "RMNEAR", "RMTAKE", "FLAG", "SETREF", "BACKPT", + "FLASH", "LIGHT", "SETHB", "SETVB", "WALK", + "REACH", "COVER", "UNCOVER", "CLEAR", "TALK", + "MOUSE", "SOUND", "COUNT", NULL +}; + + +SNAIL::SNAIL(CGEEngine *vm, bool turbo) + : Turbo(turbo), Busy(false), TextDelay(false), + Pause(0), TalkEnable(true), + Head(0), Tail(0), SNList(farnew(COM, 256)), _vm(vm) { +} + + +SNAIL::~SNAIL(void) { + if (SNList) + free(SNList); +} + + +void SNAIL::AddCom(SNCOM com, int ref, int val, void *ptr) { + _disable(); + COM *snc = &SNList[Head++]; + snc->Com = com; + snc->Ref = ref; + snc->Val = val; + snc->Ptr = ptr; + if (com == SNCLEAR) { + Tail = Head; + KillText(); + Pause = 0; + } + _enable(); +} + + +void SNAIL::InsCom(SNCOM com, int ref, int val, void *ptr) { + COM *snc; + + _disable(); + if (Busy) { + SNList[(Tail - 1) & 0xFF] = SNList[Tail]; + snc = &SNList[Tail]; + } else + snc = &SNList[(Tail - 1) & 0xFF]; + --Tail; + snc->Com = com; + snc->Ref = ref; + snc->Val = val; + snc->Ptr = ptr; + if (com == SNCLEAR) { + Tail = Head; + KillText(); + Pause = 0; + } + _enable(); +} + + +static void SNNNext(Sprite *sprel, int p) { + if (sprel) + if (sprel->NearPtr != NO_PTR) + sprel->NearPtr = p; +} + + +static void SNTNext(Sprite *sprel, int p) { + if (sprel) + if (sprel->TakePtr != NO_PTR) + sprel->TakePtr = p; +} + + +static void SNRNNext(Sprite *sprel, int p) { + if (sprel) + if (sprel->NearPtr != NO_PTR) + sprel->NearPtr += p; +} + + +static void SNRTNext(Sprite *sprel, int p) { + if (sprel) + if (sprel->TakePtr != NO_PTR) + sprel->TakePtr += p; +} + + +static void SNZTrim(Sprite *spr) { + if (spr) + if (spr->Active()) { + bool en = _heart->_enable; + Sprite *s; + _heart->_enable = false; + s = (spr->_flags._shad) ? spr->_prev : NULL; + Vga->ShowQ->Insert(Vga->ShowQ->Remove(spr)); + if (s) { + s->_z = spr->_z; + Vga->ShowQ->Insert(Vga->ShowQ->Remove(s), spr); + } + _heart->_enable = en; + } +} + + +static void SNHide(Sprite *spr, int val) { + if (spr) { + spr->_flags._hide = (val >= 0) ? (val != 0) : (!spr->_flags._hide); + if (spr->_flags._shad) + spr->_prev->_flags._hide = spr->_flags._hide; + } +} + + +static void SNRmNear(Sprite *spr) { + if (spr) + spr->NearPtr = NO_PTR; +} + + +static void SNRmTake(Sprite *spr) { + if (spr) + spr->TakePtr = NO_PTR; +} + + +void SNSeq(Sprite *spr, int val) { + if (spr) { + if (spr == Hero && val == 0) + Hero->Park(); + else + spr->Step(val); + } +} + + +void SNRSeq(Sprite *spr, int val) { + if (spr) + SNSeq(spr, spr->_seqPtr + val); +} + + +void SNSend(Sprite *spr, int val) { + if (spr) { + int was = spr->_cave; + bool was1 = (was == 0 || was == Now); + bool val1 = (val == 0 || val == Now); + spr->_cave = val; + if (val1 != was1) { + if (was1) { + if (spr->_flags._kept) { + int n = FindPocket(spr); + if (n >= 0) + _pocket[n] = NULL; + } + Hide1(spr); + ContractSprite(spr); + spr->_flags._slav = false; + } else { + if (spr->_ref % 1000 == 0) + Bitmap::Pal = VGA::SysPal; + if (spr->_flags._back) + spr->BackShow(true); + else + ExpandSprite(spr); + Bitmap::Pal = NULL; + } + } + } +} + + +void SNSwap(Sprite *spr, int xref) { + Sprite *xspr = Locate(xref); + if (spr && xspr) { + int was = spr->_cave; + int xwas = xspr->_cave; + bool was1 = (was == 0 || was == Now); + bool xwas1 = (xwas == 0 || xwas == Now); + + Swap(spr->_cave, xspr->_cave); + Swap(spr->_x, xspr->_x); + Swap(spr->_y, xspr->_y); + Swap(spr->_z, xspr->_z); + if (spr->_flags._kept) { + int n = FindPocket(spr); + if (n >= 0) + _pocket[n] = xspr; + xspr->_flags._kept = true; + xspr->_flags._port = false; + } + if (xwas1 != was1) { + if (was1) { + Hide1(spr); + ContractSprite(spr); + } else + ExpandSprite(spr); + if (xwas1) { + Hide1(xspr); + ContractSprite(xspr); + } else + ExpandSprite(xspr); + } + } +} + + +void SNCover(Sprite *spr, int xref) { + Sprite *xspr = Locate(xref); + if (spr && xspr) { + spr->_flags._hide = true; + xspr->_z = spr->_z; + xspr->_cave = spr->_cave; + xspr->Goto(spr->_x, spr->_y); + ExpandSprite(xspr); + if ((xspr->_flags._shad = spr->_flags._shad) == 1) { + Vga->ShowQ->Insert(Vga->ShowQ->Remove(spr->_prev), xspr); + spr->_flags._shad = false; + } + FeedSnail(xspr, NEAR); + } +} + + +void SNUncover(Sprite *spr, Sprite *xspr) { + if (spr && xspr) { + spr->_flags._hide = false; + spr->_cave = xspr->_cave; + spr->Goto(xspr->_x, xspr->_y); + if ((spr->_flags._shad = xspr->_flags._shad) == 1) { + Vga->ShowQ->Insert(Vga->ShowQ->Remove(xspr->_prev), spr); + xspr->_flags._shad = false; + } + spr->_z = xspr->_z; + SNSend(xspr, -1); + if (spr->_time == 0) + ++spr->_time; + } +} + + +void SNSetX0(int cav, int x0) { + HeroXY[cav - 1]._x = x0; +} + + +void SNSetY0(int cav, int y0) { + HeroXY[cav - 1]._y = y0; +} + + +void SNSetXY(Sprite *spr, uint16 xy) { + if (spr) + spr->Goto(xy % SCR_WID, xy / SCR_WID); +} + + +void SNRelX(Sprite *spr, int x) { + if (spr && Hero) + spr->Goto(Hero->_x + x, spr->_y); +} + + +void SNRelY(Sprite *spr, int y) { + if (spr && Hero) + spr->Goto(spr->_x, Hero->_y + y); +} + + +void SNRelZ(Sprite *spr, int z) { + if (spr && Hero) { + spr->_z = Hero->_z + z; + SNZTrim(spr); + } +} + + +void SNSetX(Sprite *spr, int x) { + if (spr) + spr->Goto(x, spr->_y); +} + + +void SNSetY(Sprite *spr, int y) { + if (spr) + spr->Goto(spr->_x, y); +} + + +void SNSetZ(Sprite *spr, int z) { + if (spr) { + spr->_z = z; + //SNPOST_(SNZTRIM, -1, 0, spr); + SNZTrim(spr); + } +} + + +void SNSlave(Sprite *spr, int ref) { + Sprite *slv = Locate(ref); + if (spr && slv) { + if (spr->Active()) { + SNSend(slv, spr->_cave); + slv->_flags._slav = true; + slv->_z = spr->_z; + Vga->ShowQ->Insert(Vga->ShowQ->Remove(slv), spr->_next); + } + } +} + + +void SNTrans(Sprite *spr, int trans) { + if (spr) + spr->_flags._tran = (trans < 0) ? !spr->_flags._tran : (trans != 0); +} + + +void SNPort(Sprite *spr, int port) { + if (spr) + spr->_flags._port = (port < 0) ? !spr->_flags._port : (port != 0); +} + + +void SNKill(Sprite *spr) { + if (spr) { + if (spr->_flags._kept) { + int n = FindPocket(spr); + if (n >= 0) + _pocket[n] = NULL; + } + Sprite *nx = spr->_next; + Hide1(spr); + Vga->ShowQ->Remove(spr); + MOUSE::ClrEvt(spr); + if (spr->_flags._kill) + delete spr; + else { + spr->_cave = -1; + Vga->SpareQ->Append(spr); + } + if (nx) { + if (nx->_flags._slav) + SNKill(nx); + } + } +} + + +static void SNSound(Sprite *spr, int wav, int cnt) { + if (SNDDrvInfo.DDEV) { + if (wav == -1) + Sound.Stop(); + else + Sound.Play(Fx[wav], (spr) ? ((spr->_x + spr->_w / 2) / (SCR_WID / 16)) : 8, cnt); + } +} + + +void SNKeep(Sprite *spr, int stp) { + SelectPocket(-1); + if (spr && ! spr->_flags._kept && _pocket[PocPtr] == NULL) { + SNSound(spr, 3, 1); + _pocket[PocPtr] = spr; + spr->_cave = 0; + spr->_flags._kept = true; + spr->Goto(POCKET_X + POCKET_DX * PocPtr + POCKET_DX / 2 - spr->_w / 2, + POCKET_Y + POCKET_DY / 2 - spr->_h / 2); + if (stp >= 0) + spr->Step(stp); + } + SelectPocket(-1); +} + + +void SNGive(Sprite *spr, int stp) { + if (spr) { + int p = FindPocket(spr); + if (p >= 0) { + _pocket[p] = NULL; + spr->_cave = Now; + spr->_flags._kept = false; + if (stp >= 0) + spr->Step(stp); + } + } + SelectPocket(-1); +} + + +static void SNBackPt(Sprite *spr, int stp) { + if (spr) { + if (stp >= 0) + spr->Step(stp); + spr->BackShow(true); + } +} + + +static void SNLevel(Sprite *spr, int lev) { +#ifdef DEMO + static int maxcav[] = { CAVE_MAX }; +#else + static int maxcav[] = { 1, 8, 16, 23, 24 }; +#endif + while (Lev < lev) { + ++Lev; + spr = Vga->SpareQ->Locate(100 + Lev); + if (spr) { + spr->BackShow(true); + spr->_cave = 0; + } + } + MaxCave = maxcav[Lev]; + if (spr) + spr->_flags._hide = false; +} + + +static void SNFlag(int fn, bool v) { + Flag[fn] = v; +} + + +static void SNSetRef(Sprite *spr, int nr) { + if (spr) + spr->_ref = nr; +} + + +void SNFlash(bool on) { + if (on) { + DAC *pal = farnew(DAC, PAL_CNT); + if (pal) { + memcpy(pal, VGA::SysPal, PAL_SIZ); + for (int i = 0; i < PAL_CNT; i++) { + register int c; + c = pal[i].R << 1; + pal[i].R = (c < 64) ? c : 63; + c = pal[i].G << 1; + pal[i].G = (c < 64) ? c : 63; + c = pal[i].B << 1; + pal[i].B = (c < 64) ? c : 63; + } + Vga->SetColors(pal, 64); + } + } else + Vga->SetColors(VGA::SysPal, 64); + Dark = false; +} + + +static void SNLight(bool in) { + if (in) + Vga->Sunrise(VGA::SysPal); + else + Vga->Sunset(); + Dark = ! in; +} + + +static void SNBarrier(int cav, int bar, bool horz) { + ((uint8 *)(Barriers + ((cav > 0) ? cav : Now)))[horz] = bar; +} + + +static void SNWalk(Sprite *spr, int x, int y) { + if (Hero) { + if (spr && y < 0) + Hero->FindWay(spr); + else + Hero->FindWay(XZ(x, y)); + } +} + + +static void SNReach(Sprite *spr, int mode) { + if (Hero) + Hero->Reach(spr, mode); +} + + +static void SNMouse(bool on) { + if (on) + Mouse->On(); + else + Mouse->Off(); +} + + +void SNAIL::RunCom(void) { + static int count = 1; + if (! Busy) { + Busy = true; + uint8 tmphea = Head; + while (Tail != tmphea) { + COM *snc = &SNList[Tail]; + + if (! Turbo) { // only for the slower one + if (Pause) + break; + else { + if (TextDelay) { + KillText(); + TextDelay = false; + } + } + if (Talk && snc->Com != SNPAUSE) + break; + } + + Sprite *sprel = ((snc->Ref >= 0) ? Locate(snc->Ref) : ((Sprite *) snc->Ptr)); + switch (snc->Com) { + case SNLABEL : + break; + case SNPAUSE : + _heart->setXTimer(&Pause, snc->Val); + if (Talk) + TextDelay = true; + break; + case SNWAIT : + if (sprel) { + if (sprel->SeqTest(snc->Val) && + (snc->Val >= 0 || sprel != Hero || Hero->TracePtr < 0)) { + _heart->setXTimer(&Pause, sprel->_time); + } else + goto xit; + } + break; + case SNLEVEL : + SNLevel(sprel, snc->Val); + break; + case SNHIDE : + SNHide(sprel, snc->Val); + break; + case SNSAY : + if (sprel && TalkEnable) { + if (sprel == Hero && sprel->SeqTest(-1)) + sprel->Step(HTALK); + Text->Say(Text->getText(snc->Val), sprel); + Sys->FunDel = HEROFUN0; + } + break; + case SNINF : + if (TalkEnable) { + _vm->Inf(Text->getText(snc->Val)); + Sys->FunDel = HEROFUN0; + } + break; + case SNTIME : + if (sprel && TalkEnable) { + if (sprel == Hero && sprel->SeqTest(-1)) + sprel->Step(HTALK); + SayTime(sprel); + } + break; + case SNCAVE : + // SwitchCave(snc->Val); + warning("Problematic call of SwitchCave in SNAIL::RunCom"); + break; + case SNKILL : + SNKill(sprel); + break; + case SNSEQ : + SNSeq(sprel, snc->Val); + break; + case SNRSEQ : + SNRSeq(sprel, snc->Val); + break; + case SNSEND : + SNSend(sprel, snc->Val); + break; + case SNSWAP : + SNSwap(sprel, snc->Val); + break; + case SNCOVER : + SNCover(sprel, snc->Val); + break; + case SNUNCOVER : + SNUncover(sprel, (snc->Val >= 0) ? Locate(snc->Val) : ((Sprite *) snc->Ptr)); + break; + case SNKEEP : + SNKeep(sprel, snc->Val); + break; + case SNGIVE : + SNGive(sprel, snc->Val); + break; + case SNGAME : + SNGame(sprel, snc->Val); + break; + case SNSETX0 : + SNSetX0(snc->Ref, snc->Val); + break; + case SNSETY0 : + SNSetY0(snc->Ref, snc->Val); + break; + case SNSETXY : + SNSetXY(sprel, snc->Val); + break; + case SNRELX : + SNRelX(sprel, snc->Val); + break; + case SNRELY : + SNRelY(sprel, snc->Val); + break; + case SNRELZ : + SNRelZ(sprel, snc->Val); + break; + case SNSETX : + SNSetX(sprel, snc->Val); + break; + case SNSETY : + SNSetY(sprel, snc->Val); + break; + case SNSETZ : + SNSetZ(sprel, snc->Val); + break; + case SNSLAVE : + SNSlave(sprel, snc->Val); + break; + case SNTRANS : + SNTrans(sprel, snc->Val); + break; + case SNPORT : + SNPort(sprel, snc->Val); + break; + case SNNEXT : + break; + case SNIF : + break; + case SNTALK : + break; + case SNMOUSE : + SNMouse(snc->Val != 0); + break; + case SNNNEXT : + SNNNext(sprel, snc->Val); + break; + case SNTNEXT : + SNTNext(sprel, snc->Val); + break; + case SNRNNEXT : + SNRNNext(sprel, snc->Val); + break; + case SNRTNEXT : + SNRTNext(sprel, snc->Val); + break; + case SNRMNEAR : + SNRmNear(sprel); + break; + case SNRMTAKE : + SNRmTake(sprel); + break; + case SNFLAG : + SNFlag(snc->Ref & 3, snc->Val != 0); + break; + case SNSETREF : + SNSetRef(sprel, snc->Val); + break; + case SNBACKPT : + SNBackPt(sprel, snc->Val); + break; + case SNFLASH : + SNFlash(snc->Val != 0); + break; + case SNLIGHT : + SNLight(snc->Val != 0); + break; + case SNSETHB : + SNBarrier(snc->Ref, snc->Val, true); + break; + case SNSETVB : + SNBarrier(snc->Ref, snc->Val, false); + break; + case SNWALK : + SNWalk(sprel, snc->Ref, snc->Val); + break; + case SNREACH : + SNReach(sprel, snc->Val); + break; + case SNSOUND : + SNSound(sprel, snc->Val, count); + count = 1; + break; + case SNCOUNT : + count = snc->Val; + break; + case SNEXEC : + // TODO: Handle correctly the execution of function pointer coming from Message send SNPOST + // ((void(*)(int)) (snc->Ptr))(snc->Val); break; + warning("STUB: SNEXEC code"); + case SNSTEP : + sprel->Step(); + break; + case SNZTRIM : + SNZTrim(sprel); + break; + case SNGHOST : + SNGhost((Bitmap *) snc->Ptr); + break; + default : + warning("Unhandled snc->Com in SNMouse(bool)"); + break; + } + Tail++; + if (!Turbo) + break; + } +xit: + Busy = false; + } +} + + +bool SNAIL::Idle(void) { + return (Head == Tail); +} + +} // End of namespace CGE diff --git a/engines/cge/snail.h b/engines/cge/snail.h new file mode 100644 index 0000000000..e1df628d3b --- /dev/null +++ b/engines/cge/snail.h @@ -0,0 +1,126 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __SNAIL__ +#define __SNAIL__ + +#include "cge/jbw.h" +#include "cge/cge.h" + +namespace CGE { + +#define POCKET_X 174 +#define POCKET_Y 176 +#define POCKET_DX 18 +#define POCKET_DY 22 +#define POCKET_NX 8 +#define POCKET_NY 1 + +#define POCKET_SX 8 +#define POCKET_SY 3 + +#define SNINSERT(c,r,v,p) Snail->InsCom(c,r,v,p) +#define SNPOST(c,r,v,p) Snail->AddCom(c,r,v,p) +#define SNPOST_(c,r,v,p) Snail_->AddCom(c,r,v,p) + + +typedef struct { + uint8 Horz, Vert; +} BAR; + + +struct SCB { + uint8 *Ptr; + uint16 Siz; + SCB *Nxt; +}; + + +enum SNCOM { + SNLABEL, SNPAUSE, SNWAIT, SNLEVEL, SNHIDE, + SNSAY, SNINF, SNTIME, SNCAVE, SNKILL, + SNRSEQ, SNSEQ, SNSEND, SNSWAP, SNKEEP, + SNGIVE, SNIF, SNGAME, SNSETX0, SNSETY0, + SNSLAVE, SNSETXY, SNRELX, SNRELY, SNRELZ, + SNSETX, SNSETY, SNSETZ, SNTRANS, SNPORT, + SNNEXT, SNNNEXT, SNTNEXT, SNRNNEXT, SNRTNEXT, + SNRMNEAR, SNRMTAKE, SNFLAG, SNSETREF, SNBACKPT, + SNFLASH, SNLIGHT, SNSETHB, SNSETVB, SNWALK, + SNREACH, SNCOVER, SNUNCOVER, SNCLEAR, SNTALK, + SNMOUSE, SNSOUND, SNCOUNT, SNEXEC, SNSTEP, + SNZTRIM, SNGHOST +}; + +enum SNLIST { NEAR, TAKE }; + +class SNAIL { +public: + struct COM { + SNCOM Com; + int Ref; + int Val; + void *Ptr; + } *SNList; + uint8 Head, Tail; + bool Turbo, Busy, TextDelay; + uint16 Pause; + static const char *ComTxt[]; + bool TalkEnable; + SNAIL(CGEEngine *vm, bool turbo = false); + ~SNAIL(); + void RunCom(void); + void AddCom(SNCOM com, int ref = 0, int val = 0, void *ptr = NULL); + void InsCom(SNCOM com, int ref = 0, int val = 0, void *ptr = NULL); + bool Idle(void); +private: + CGEEngine *_vm; +}; + + +void SelectPocket(int n); +void PocFul(void); + + +extern SCB Scb; +extern bool Flag[4]; +extern bool Game; +extern bool Dark; +//extern SNAIL *Snail; +//extern SNAIL *Snail_; +extern int Now; +extern int Lev; +extern int MaxCave; +extern int PocPtr; +extern BAR Barriers[]; +extern struct HXY { + int _x; + int _y; +} HeroXY[]; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/snddrv.h b/engines/cge/snddrv.h new file mode 100644 index 0000000000..3d1658e1e0 --- /dev/null +++ b/engines/cge/snddrv.h @@ -0,0 +1,130 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +// ****************************************************** +// * Sound Driver by Hedges (c) 1995 LK AVALON * +// * Ver 1.00: 01-Mar-95 * +// * Ver 1.10: 03-Mar-95 * +// * Ver 1.20: 07-Mar-95 * +// * Ver 1.30: 09-Mar-95 * +// * Ver 1.40: 11-Mar-95 * +// ****************************************************** + +#ifndef __SNDDRV__ +#define __SNDDRV__ + +namespace CGE { + +// ****************************************************** +// * Constants * +// ****************************************************** +// available devices + +enum DEV_TYPE { DEV_AUTO = -1, // auto-detect mode + DEV_QUIET, // disable sound + DEV_SB, // sb/pro/16/awe32 + DEV_GUS, // gus/max + DEV_GM // general midi + }; + +#define SERR_OK 0 // no error +#define SERR_INITFAIL 1 // couldn't initialize +#define SERR_BADDDEV 128 // bad device + +// driver info +struct DRVINFO { + DEV_TYPE DDEV; // digi device + DEV_TYPE MDEV; // midi device + uint16 DBASE; // digi base port + uint16 DDMA; // digi dma no + uint16 DIRQ; // digi irq no + uint16 MBASE; // midi base port + union { + struct { + uint16 DR : 4; + uint16 DL : 4; + uint16 MR : 4; + uint16 ML : 4; + } VOL4; + struct { + uint8 D; // digi volume + uint8 M; // midi volume + } VOL2; + }; +}; + +// sample info +struct SMPINFO { + uint8 *saddr; // address + uint16 slen; // length + uint16 span; // left/right pan (0-15) + int sflag; // flag +}; + +// ****************************************************** +// * Data * +// ****************************************************** +// driver info +extern DRVINFO SNDDrvInfo; + +// midi player flag (1 means we are playing) +extern uint16 MIDIPlayFlag; + +// midi song end flag (1 means we have crossed end mark) +extern uint16 MIDIEndFlag; + +// ****************************************************** +// * Driver Code * +// ****************************************************** +// Init Digi Device +EC void SNDInit(void); + +// Close Digi Device +EC void SNDDone(void); + +// Set Volume +EC void SNDSetVolume(void); + +// Start Digi +EC void SNDDigiStart(SMPINFO *PSmpInfo); + +// Stop Digi +EC void SNDDigiStop(SMPINFO *PSmpInfo); + +// Start MIDI File +EC void SNDMIDIStart(uint8 *MIDFile); + +// Stop MIDI File +EC void SNDMIDIStop(void); + +// Play MIDI File (to be called while interrupting) +// WARNING: Uses ALL registers! +EC void SNDMIDIPlay(void); + +} // End of namespace CGE + +#endif diff --git a/engines/cge/sound.cpp b/engines/cge/sound.cpp new file mode 100644 index 0000000000..4a7b63fb08 --- /dev/null +++ b/engines/cge/sound.cpp @@ -0,0 +1,228 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/general.h" +#include "cge/startup.h" +#include "cge/sound.h" +#include "cge/text.h" +#include "cge/cfile.h" +#include "cge/vol.h" + + +namespace CGE { + +bool Music = true; +FX Fx = 16; // must precede SOUND!! +SOUND Sound; + + +SOUND::SOUND(void) { + if (STARTUP::SoundOk) + Open(); +} + + +SOUND::~SOUND(void) { + Close(); +} + + +void SOUND::Close(void) { + KillMIDI(); + SNDDone(); +} + + +void SOUND::Open(void) { + SNDInit(); + Play(Fx[30000], 8); +} + + +void SOUND::Play(DATACK *wav, int pan, int cnt) { + if (wav) { + Stop(); + smpinf.saddr = (uint8 *) &*(wav->EAddr()); + smpinf.slen = (uint16)wav->Size(); + smpinf.span = pan; + smpinf.sflag = cnt; + SNDDigiStart(&smpinf); + } +} + + +void SOUND::Stop(void) { + SNDDigiStop(&smpinf); +} + + +FX::FX(int size) : Emm(0L), Current(NULL) { + Cache = new HAN[size]; + for (Size = 0; Size < size; Size++) { + Cache[Size].Ref = 0; + Cache[Size].Wav = NULL; + } +} + + +FX::~FX(void) { + Clear(); + delete[] Cache; +} + + +void FX::Clear(void) { + HAN *p, * q; + for (p = Cache, q = p + Size; p < q; p++) { + if (p->Ref) { + p->Ref = 0; + delete p->Wav; + p->Wav = NULL; + } + } + Emm.Release(); + Current = NULL; +} + + +int FX::Find(int ref) { + HAN *p, * q; + int i = 0; + for (p = Cache, q = p + Size; p < q; p++) { + if (p->Ref == ref) + break; + else + ++i; + } + return i; +} + + +void FX::Preload(int ref0) { + HAN *CacheLim = Cache + Size; + int ref; + + for (ref = ref0; ref < ref0 + 10; ref++) { + static char fname[] = "FX00000.WAV"; + wtom(ref, fname + 2, 10, 5); + INI_FILE file = INI_FILE(fname); + DATACK *wav = LoadWave(&file, &Emm); + if (wav) { + HAN *p = &Cache[Find(0)]; + if (p >= CacheLim) + break; + p->Wav = wav; + p->Ref = ref; + } + } +} + + +DATACK *FX::Load(int idx, int ref) { + static char fname[] = "FX00000.WAV"; + wtom(ref, fname + 2, 10, 5); + + INI_FILE file = INI_FILE(fname); + DATACK *wav = LoadWave(&file, &Emm); + if (wav) { + HAN *p = &Cache[idx]; + p->Wav = wav; + p->Ref = ref; + } + return wav; +} + + +DATACK *FX::operator [](int ref) { + int i; + if ((i = Find(ref)) < Size) + Current = Cache[i].Wav; + else { + if ((i = Find(0)) >= Size) { + Clear(); + i = 0; + } + Current = Load(i, ref); + } + return Current; +} + + +static uint8 *midi = NULL; + + +void KillMIDI(void) { + SNDMIDIStop(); + if (midi) { + delete[] midi; + midi = NULL; + } +} + + +void LoadMIDI(int ref) { + static char fn[] = "00.MID"; + wtom(ref, fn, 10, 2); + if (INI_FILE::Exist(fn)) { + KillMIDI(); + INI_FILE mid = fn; + if (mid.Error == 0) { + uint16 siz = (uint16) mid.Size(); + midi = new uint8[siz]; + if (midi) { + mid.Read(midi, siz); + if (mid.Error) + KillMIDI(); + else + SNDMIDIStart(midi); + } + } + } +} + + +EC void *Patch(int pat) { + void *p = NULL; + static char fn[] = "PATCH000.SND"; + + wtom(pat, fn + 5, 10, 3); + INI_FILE snd = fn; + if (! snd.Error) { + uint16 siz = (uint16) snd.Size(); + p = (uint8 *) malloc(siz); + if (p) { + snd.Read(p, siz); + if (snd.Error) { + free(p); + p = NULL; + } + } + } + return p; +} + +} // End of namespace CGE diff --git a/engines/cge/sound.h b/engines/cge/sound.h new file mode 100644 index 0000000000..b617891268 --- /dev/null +++ b/engines/cge/sound.h @@ -0,0 +1,82 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __SOUND__ +#define __SOUND__ + +#include "cge/wav.h" +#include "cge/snddrv.h" + +namespace CGE { + +#define BAD_SND_TEXT 97 +#define BAD_MIDI_TEXT 98 + + +class SOUND { +public: + SMPINFO smpinf; + SOUND(void); + ~SOUND(void); + void Open(void); + void Close(void); + void Play(DATACK *wav, int pan, int cnt = 1); + void Stop(void); +}; + + +class FX { + EMM Emm; + struct HAN { + int Ref; + DATACK *Wav; + } *Cache; + int Size; + DATACK *Load(int idx, int ref); + int Find(int ref); +public: + DATACK *Current; + FX(int size = 16); + ~FX(void); + void Clear(void); + void Preload(int ref0); + DATACK *operator[](int ref); +}; + + +extern bool Music; +extern SOUND Sound; +extern FX Fx; + + +void LoadMIDI(int ref); +void KillMIDI(void); + +} // End of namespace CGE + +#endif + diff --git a/engines/cge/startup.cpp b/engines/cge/startup.cpp new file mode 100644 index 0000000000..4895ce9861 --- /dev/null +++ b/engines/cge/startup.cpp @@ -0,0 +1,176 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/startup.h" +#include "cge/text.h" +#include "cge/sound.h" +#include "cge/ident.h" +#include "cge/cfile.h" +#include "cge/snddrv.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +namespace CGE { + +extern char Copr[]; + +#define id (*(IDENT*)Copr) + + +EMM MiniEmm = MINI_EMM_SIZE; + +static STARTUP StartUp; + + +int STARTUP::Mode = 0; +int STARTUP::Core; +int STARTUP::SoundOk = 0; +uint16 STARTUP::Summa; + + +void quit_now(int ref) { + error("%s", Text->getText(ref)); +} + + +bool STARTUP::get_parms(void) { + /* + int i = _argc; + while (i > 1) + { + static char *PrmTab[] = { "NEW", "MK0SVG", "QUIET", "SB", "GUS", "MIDI", + "P", "D", "I", "M" }; + int n = TakeEnum(PrmTab, strtok(_argv[--i], " =:(")); + uint16 p = xtow(strtok(NULL, " h,)")); + switch (n) + { + case 0 : if (Mode != 2) Mode = 1; break; + case 1 : Mode = 2; break; + case 2 : SNDDrvInfo.DDEV = DEV_QUIET; break; + case 3 : SNDDrvInfo.DDEV = DEV_SB; break; + case 4 : SNDDrvInfo.DDEV = DEV_GUS; break; + case 5 : SNDDrvInfo.MDEV = DEV_GM; break; + case 6 : SNDDrvInfo.DBASE = p; break; + case 7 : SNDDrvInfo.DDMA = p; break; + case 8 : SNDDrvInfo.DIRQ = p; break; + case 9 : SNDDrvInfo.MBASE = p; + SNDDrvInfo.MDEV = DEV_GM; break; + default: return false; + } + if (n >= 2) SoundOk = 2; + } + #ifdef DEMO + // protection disabled + Summa = 0; + #else + #ifdef EVA + { + union { dosdate_t d; uint32 n; } today; + _dos_getdate(&today.d); + id.disk += (id.disk < today.n); + } + #endif + #ifdef CD + Summa = 0; + #else + // disk signature checksum + Summa = ChkSum(Copr, sizeof(IDENT)); + #endif + #endif + if (SNDDrvInfo.MDEV != DEV_GM) SNDDrvInfo.MDEV = SNDDrvInfo.DDEV; + return true; + */ + warning("STUB: STARTUP::get_parms"); + return true; +} + + +STARTUP::STARTUP(void) { + /* + uint32 m = farcoreleft() >> 10; + if (m < 0x7FFF) Core = (int) m; else Core = 0x7FFF; + + if (! IsVga()) quit_now(NOT_VGA_TEXT); + if (Cpu() < _80286) quit_now(BAD_CHIP_TEXT); + if (100 * _osmajor + _osminor < 330) quit_now(BAD_DOS_TEXT); + + if (! get_parms()) quit_now(BAD_ARG_TEXT); + //--- load sound configuration + const char * fn = UsrPath(ProgName(CFG_EXT)); + if (! STARTUP::SoundOk && CFILE::Exist(fn)) + { + CFILE cfg(fn, REA); + if (! cfg.Error) + { + cfg.Read(&SNDDrvInfo, sizeof(SNDDrvInfo)-sizeof(SNDDrvInfo.VOL2)); + if (! cfg.Error) STARTUP::SoundOk = 1; + } + } + */ + warning("STUB: STARTUP::STARTUP"); +} + + +const char *UsrPath(const char *nam) { + static char buf[MAXPATH] = ".\\", *p = buf + 2; +#if defined(CD) + if (DriveCD(0)) { + bool ok = false; + CFILE ini = Text[CDINI_FNAME]; + if (!ini.Error) { + char *key = Text[GAME_ID]; + int i = strlen(key); + while (ini.Read(buf) && !ok) { + int j = strlen(buf); + if (j) + if (buf[--j] == '\n') + buf[j] = '\0'; + if (scumm_strnicmp((const char *) buf, (const char*) key, i) == 0) + ok = true; + } + if (ok) { + strcpy(buf, buf + i); + p = buf + strlen(buf); + if (*(p - 1) != '\\') + *(p++) = '\\'; + strcpy(p, "NUL"); + if (_dos_open(buf, 0, &i) == 0) + _dos_close(i); + else + ok = false; + } + } + if (!ok) + quit_now(BADCD_TEXT); + } +#endif + strcpy(p, nam); + return buf; +} + +} // End of namespace CGE diff --git a/engines/cge/startup.h b/engines/cge/startup.h new file mode 100644 index 0000000000..5bfa9876d6 --- /dev/null +++ b/engines/cge/startup.h @@ -0,0 +1,79 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __STARTUP__ +#define __STARTUP__ + + +#include "cge/general.h" + +namespace CGE { + +#define GAME_ID 45 +#define CDINI_FNAME 46 + +#define NOT_VGA_TEXT 90 +#define BAD_CHIP_TEXT 91 +#define BAD_DOS_TEXT 92 +#define NO_CORE_TEXT 93 +#define BAD_MIPS_TEXT 94 +#define NO_MOUSE_TEXT 95 +#define BAD_ARG_TEXT 96 +#define BADCD_TEXT 97 + +#define CFG_EXT ".CFG" + +#if defined(DEMO) +#define MINI_EMM_SIZE 0x00004000L +#define CORE_HIG 400 +#else +#define MINI_EMM_SIZE 0x00010000L +#define CORE_HIG 450 +#endif + +#define CORE_MID (CORE_HIG - 20) +#define CORE_LOW (CORE_MID - 20) + + +class STARTUP { + static bool get_parms(void); +public: + static int Mode; + static int Core; + static int SoundOk; + static uint16 Summa; + STARTUP(void); +}; + + +extern EMM MiniEmm; + +const char *UsrPath(const char *nam); + +} // End of namespace CGE + +#endif diff --git a/engines/cge/talk.cpp b/engines/cge/talk.cpp new file mode 100644 index 0000000000..5aa5e44b8d --- /dev/null +++ b/engines/cge/talk.cpp @@ -0,0 +1,334 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/general.h" +#include "cge/talk.h" +#include "cge/vol.h" +#include "cge/game.h" +#include "cge/mouse.h" + +namespace CGE { + +#define WID_SIZ 256 +#define POS_SIZ 256 +#define MAP_SIZ (256*8) + +//uint8 FONT::Wid[WID_SIZ]; +//uint16 FONT::Pos[POS_SIZ]; +//uint8 FONT::Map[MAP_SIZ]; + + +FONT::FONT(const char *name) { + Map = farnew(uint8, MAP_SIZ); + Pos = farnew(uint16, POS_SIZ); + Wid = farnew(uint8, WID_SIZ); + if ((Map == NULL) || (Pos == NULL) || (Wid == NULL)) + error("No core"); + MergeExt(Path, name, FONT_EXT); + Load(); +} + + +FONT::~FONT(void) { + free(Map); + free(Pos); + free(Wid); +} + + +void FONT::Load(void) { + INI_FILE f(Path); + if (! f.Error) { + f.Read(Wid, WID_SIZ); + if (! f.Error) { + uint16 i, p = 0; + for (i = 0; i < POS_SIZ; i++) { + Pos[i] = p; + p += Wid[i]; + } + f.Read(Map, p); + } + } +} + + +uint16 FONT::Width(const char *text) { + uint16 w = 0; + if (text) + while (* text) + w += Wid[*(text++)]; + return w; +} + + +/* +void FONT::Save(void) { + CFILE f((const char *) Path, WRI); + if (! f.Error) { + f.Write(Wid, WID_SIZ); + if (! f.Error) + f.Write(Map, Pos[POS_SIZ - 1] + Wid[WID_SIZ - 1]); + } +} +*/ + + +TALK::TALK(CGEEngine *vm, const char *tx, TBOX_STYLE mode) + : Sprite(vm, NULL), Mode(mode), _vm(vm) { + TS[0] = TS[1] = NULL; + _flags._syst = true; + Update(tx); +} + + +TALK::TALK(CGEEngine *vm) + : Sprite(vm, NULL), Mode(PURE), _vm(vm) { + TS[0] = TS[1] = NULL; + _flags._syst = true; +} + + +/* +TALK::~TALK (void) { + for (uint16 i = 0; i < ShpCnt; i++) { + if (FP_SEG(ShpList[i]) != _DS) { // small model: always false + delete ShpList[i]; + ShpList[i] = NULL; + } + } +} +*/ + +FONT *TALK::_Font; + +void TALK::init() { + _Font = new FONT(ProgName()); +} + +void TALK::deinit() { + delete _Font; +} + + +void TALK::Update(const char *tx) { + uint16 vmarg = (Mode) ? TEXT_VM : 0; + uint16 hmarg = (Mode) ? TEXT_HM : 0; + uint16 mw = 0, mh, ln = vmarg; + const char *p; + uint8 *m; + + if (!TS[0]) { + uint16 k = 2 * hmarg; + mh = 2 * vmarg + FONT_HIG; + for (p = tx; *p; p++) { + if (*p == '|' || *p == '\n') { + mh += FONT_HIG + TEXT_LS; + if (k > mw) + mw = k; + k = 2 * hmarg; + } else + k += _Font->Wid[*p]; + } + if (k > mw) + mw = k; + TS[0] = Box(mw, mh); + } + + m = TS[0]->_m + ln * mw + hmarg; + + while (* tx) { + if (*tx == '|' || *tx == '\n') + m = TS[0]->_m + (ln += FONT_HIG + TEXT_LS) * mw + hmarg; + else { + int cw = _Font->Wid[*tx], i; + uint8 *f = _Font->Map + _Font->Pos[*tx]; + for (i = 0; i < cw; i++) { + uint8 *pp = m; + uint16 n; + register uint16 b = *(f++); + for (n = 0; n < FONT_HIG; n++) { + if (b & 1) + *pp = TEXT_FG; + b >>= 1; + pp += mw; + } + m++; + } + } + tx++; + } + TS[0]->Code(); + SetShapeList(TS); +} + + + + +Bitmap *TALK::Box(uint16 w, uint16 h) { + uint8 *b, * p, * q; + uint16 n, r = (Mode == ROUND) ? TEXT_RD : 0; + + if (w < 8) + w = 8; + if (h < 8) + h = 8; + b = farnew(uint8, n = w * h); + if (! b) + error("No core"); + memset(b, TEXT_BG, n); + + if (Mode) { + p = b; + q = b + n - w; + memset(p, LGRAY, w); + memset(q, DGRAY, w); + while (p < q) { + p += w; + *(p - 1) = DGRAY; + *p = LGRAY; + } + p = b; + for (int i = 0; i < r; i++) { + int j; + for (j = 0; j < r - i; j++) { + p[j] = TRANS; + p[w - j - 1] = TRANS; + q[j] = TRANS; + q[w - j - 1] = TRANS; + } + p[j] = LGRAY; + p[w - j - 1] = DGRAY; + q[j] = LGRAY; + q[w - j - 1] = DGRAY; + p += w; + q -= w; + } + } + return new Bitmap(w, h, b); +} + + +void TALK::PutLine(int line, const char *text) { +// Note: (TS[0].W % 4) have to be 0 + uint16 w = TS[0]->_w, h = TS[0]->_h; + uint8 *v = TS[0]->_v, * p; + uint16 dsiz = w >> 2; // data size (1 plane line size) + uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap + uint16 psiz = h * lsiz; // - last gap, but + plane trailer + uint16 size = 4 * psiz; // whole map size + uint16 rsiz = FONT_HIG * lsiz; // length of whole text row map + + // set desired line pointer + v += (TEXT_VM + (FONT_HIG + TEXT_LS) * line) * lsiz; + + // clear whole rectangle + p = v; // assume blanked line above text + memcpy(p, p - lsiz, rsiz); + p += psiz; // tricky replicate lines for plane 0 + memcpy(p, p - lsiz, rsiz); + p += psiz; // same for plane 1 + memcpy(p, p - lsiz, rsiz); + p += psiz; // same for plane 2 + memcpy(p, p - lsiz, rsiz); // same for plane 3 + + // paint text line + if (text) { + uint8 *q; + p = v + 2 + TEXT_HM / 4 + (TEXT_HM % 4) * psiz; + q = v + size; + + while (* text) { + uint16 cw = _Font->Wid[*text], i; + uint8 *fp = _Font->Map + _Font->Pos[*text]; + + for (i = 0; i < cw; i++) { + register uint16 b = fp[i]; + uint16 n; + for (n = 0; n < FONT_HIG; n++) { + if (b & 1) + *p = TEXT_FG; + b >>= 1; + p += lsiz; + } + p = p - rsiz + psiz; + if (p >= q) + p = p - size + 1; + } + text++; + } + } +} + + +INFO_LINE::INFO_LINE(CGEEngine *vm, uint16 w) : TALK(vm), OldTxt(NULL), _vm(vm) { + TS[0] = new Bitmap(w, FONT_HIG, TEXT_BG); + SetShapeList(TS); +} + + +void INFO_LINE::Update(const char *tx) { + if (tx != OldTxt) { + uint16 w = TS[0]->_w, h = TS[0]->_h; + uint8 *v = (uint8 *) TS[0]->_v; + uint16 dsiz = w >> 2; // data size (1 plane line size) + uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap + uint16 psiz = h * lsiz; // - last gape, but + plane trailer + uint16 size = 4 * psiz; // whole map size + + // claer whole rectangle + memset(v + 2, TEXT_BG, dsiz); // data bytes + memcpy(v + lsiz, v, psiz - lsiz); // tricky replicate lines + *(uint16 *)(v + psiz - 2) = EOI; // plane trailer uint16 + memcpy(v + psiz, v, 3 * psiz); // tricky replicate planes + + // paint text line + if (tx) { + uint8 *p = v + 2, * q = p + size; + + while (*tx) { + uint16 cw = _Font->Wid[*tx]; + uint8 *fp = _Font->Map + _Font->Pos[*tx]; + + for (uint16 i = 0; i < cw; i++) { + register uint16 b = fp[i]; + for (uint16 n = 0; n < FONT_HIG; n++) { + if (b & 1) + *p = TEXT_FG; + b >>= 1; + p += lsiz; + } + if (p >= q) + p = p - size + 1; + } + tx++; + } + } + OldTxt = tx; + } +} + +} // End of namespace CGE diff --git a/engines/cge/talk.h b/engines/cge/talk.h new file mode 100644 index 0000000000..60f7f213d4 --- /dev/null +++ b/engines/cge/talk.h @@ -0,0 +1,104 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __TALK__ +#define __TALK__ + +#include "cge/vga13h.h" +#include "cge/general.h" +#include "cge/jbw.h" + +namespace CGE { + +#define TEXT_FG DARK // foreground color +#define TEXT_BG GRAY // background color +#define TEXT_HM (6&~1) // EVEN horizontal margins! +#define TEXT_VM 5 // vertical margins +#define TEXT_LS 2 // line spacing +#define TEXT_RD 3 // rounded corners + +#define FONT_HIG 8 +#define FONT_EXT ".CFT" + + + +#define MAXPATH 128 + +class FONT { + char Path[MAXPATH]; + void Load(void); +public: +// static uint8 Wid[256]; +// static uint16 Pos[256]; +// static uint8 Map[256*8]; + uint8 *Wid; + uint16 *Pos; + uint8 *Map; + FONT(const char *name); + ~FONT(void); + uint16 Width(const char *text); + void Save(void); +}; + + +enum TBOX_STYLE { PURE, RECT, ROUND }; + + +class TALK : public Sprite { +protected: + TBOX_STYLE Mode; + Bitmap *TS[2]; + Bitmap *Box(uint16 w, uint16 h); +public: + TALK(CGEEngine *vm, const char *tx, TBOX_STYLE mode = PURE); + TALK(CGEEngine *vm); + //~TALK (void); + + static FONT *_Font; + static void init(); + static void deinit(); + + virtual void Update(const char *tx); + virtual void Update(void) {} + void PutLine(int line, const char *text); +private: + CGEEngine *_vm; +}; + + +class INFO_LINE : public TALK { + const char *OldTxt; +public: + INFO_LINE(CGEEngine *vm, uint16 wid); + void Update(const char *tx); +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/text.cpp b/engines/cge/text.cpp new file mode 100644 index 0000000000..7b191b492b --- /dev/null +++ b/engines/cge/text.cpp @@ -0,0 +1,259 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/general.h" +#include "cge/text.h" +#include "cge/talk.h" +#include "cge/vol.h" +#include "cge/bitmaps.h" +#include "cge/game.h" +#include "cge/snail.h" +#include "cge/cge_main.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +namespace CGE { + +TEXT *Text; +TALK *Talk = NULL; + +TEXT::TEXT(CGEEngine *vm, const char *fname, int size) : _vm(vm) { + Cache = new HAN[size]; + MergeExt(FileName, fname, SAY_EXT); + if (!INI_FILE::Exist(FileName)) + error("No talk (%s)\n", FileName); + + for (Size = 0; Size < size; Size++) { + Cache[Size].Ref = 0; + Cache[Size].Txt = NULL; + } +} + + +TEXT::~TEXT() { + Clear(); + delete[] Cache; +} + + +void TEXT::Clear(int from, int upto) { + HAN *p, * q; + for (p = Cache, q = p + Size; p < q; p++) { + if (p->Ref && p->Ref >= from && p->Ref < upto) { + p->Ref = 0; + delete p->Txt; + p->Txt = NULL; + } + } +} + + +int TEXT::Find(int ref) { + HAN *p, * q; + int i = 0; + for (p = Cache, q = p + Size; p < q; p++) { + if (p->Ref == ref) + break; + else + ++i; + } + return i; +} + + +void TEXT::Preload(int from, int upto) { + INI_FILE tf = FileName; + if (! tf.Error) { + HAN *CacheLim = Cache + Size; + char line[LINE_MAX + 1]; + int n; + + while ((n = tf.Read((uint8 *)line)) != 0) { + char *s; + int ref; + + if (line[n - 1] == '\n') + line[-- n] = '\0'; + if ((s = strtok(line, " =,;/\t\n")) == NULL) + continue; + if (! IsDigit(*s)) + continue; + ref = atoi(s); + if (ref && ref >= from && ref < upto) { + HAN *p; + + p = &Cache[Find(ref)]; + if (p < CacheLim) { + delete[] p->Txt; + p->Txt = NULL; + } else + p = &Cache[Find(0)]; + if (p >= CacheLim) + break; + s += strlen(s); + if (s < line + n) + ++s; + if ((p->Txt = new char[strlen(s) + 1]) == NULL) + break; + p->Ref = ref; + strcpy(p->Txt, s); + } + } + } +} + + +char *TEXT::Load(int idx, int ref) { + INI_FILE tf = FileName; + if (! tf.Error) { + HAN *p = &Cache[idx]; + char line[LINE_MAX + 1]; + int n; + + while ((n = tf.Read((uint8 *)line)) != 0) { + char *s; + + if (line[n - 1] == '\n') + line[-- n] = '\0'; + if ((s = strtok(line, " =,;/\t\n")) == NULL) + continue; + if (! IsDigit(*s)) + continue; + + int r = atoi(s); + if (r < ref) + continue; + if (r > ref) + break; + // (r == ref) + s += strlen(s); + if (s < line + n) + ++s; + p->Ref = ref; + if ((p->Txt = new char[strlen(s) + 1]) == NULL) + return NULL; + return strcpy(p->Txt, s); + } + } + return NULL; +} + + +char *TEXT::getText(int ref) { + int i; + if ((i = Find(ref)) < Size) + return Cache[i].Txt; + + if ((i = Find(0)) >= Size) { + Clear(SYSTXT_MAX); // clear non-system + if ((i = Find(0)) >= Size) { + Clear(); // clear all + i = 0; + } + } + return Load(i, ref); +} + + +void TEXT::Say(const char *txt, Sprite *spr) { + KillText(); + Talk = new TALK(_vm, txt, ROUND); + if (Talk) { + bool east = spr->_flags._east; + int x = (east) ? (spr->_x + spr->_w - 2) : (spr->_x + 2); + int y = spr->_y + 2; + Sprite *spike = new Sprite(_vm, SP); + uint16 sw = spike->_w; + + if (east) { + if (x + sw + TEXT_RD + 5 >= SCR_WID) + east = false; + } else { + if (x <= 5 + TEXT_RD + sw) + east = true; + } + x = (east) ? (spr->_x + spr->_w - 2) : (spr->_x + 2 - sw); + if (spr->_ref == 1) + x += ((east) ? -10 : 10); // Hero + + Talk->_flags._kill = true; + Talk->_flags._bDel = true; + Talk->SetName(Text->getText(SAY_NAME)); + Talk->Goto(x - (Talk->_w - sw) / 2 - 3 + 6 * east, y - spike->_h - Talk->_h + 1); + Talk->_z = 125; + Talk->_ref = SAY_REF; + + spike->Goto(x, Talk->_y + Talk->_h - 1); + spike->_z = 126; + spike->_flags._slav = true; + spike->_flags._kill = true; + spike->SetName(Text->getText(SAY_NAME)); + spike->Step(east); + spike->_ref = SAY_REF; + + Vga->ShowQ->Insert(Talk, Vga->ShowQ->Last()); + Vga->ShowQ->Insert(spike, Vga->ShowQ->Last()); + } +} + +void CGEEngine::Inf(const char *txt) { + KillText(); + Talk = new TALK(this, txt, RECT); + if (Talk) { + Talk->_flags._kill = true; + Talk->_flags._bDel = true; + Talk->SetName(Text->getText(INF_NAME)); + Talk->Center(); + Talk->Goto(Talk->_x, Talk->_y - 20); + Talk->_z = 126; + Talk->_ref = INF_REF; + Vga->ShowQ->Insert(Talk, Vga->ShowQ->Last()); + } +} + + +void SayTime(Sprite *spr) { + /* + static char t[] = "00:00"; + struct time ti; + gettime(&ti); + wtom(ti.ti_hour, t+0, 10, 2); + wtom(ti.ti_min, t+3, 10, 2); + Say((*t == '0') ? (t+1) : t, spr); + */ + warning("STUB: SayTime"); +} + +void KillText(void) { + if (Talk) { + SNPOST_(SNKILL, -1, 0, Talk); + Talk = NULL; + } +} + +} // End of namespace CGE diff --git a/engines/cge/text.h b/engines/cge/text.h new file mode 100644 index 0000000000..874a640ad0 --- /dev/null +++ b/engines/cge/text.h @@ -0,0 +1,86 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __TEXT__ +#define __TEXT__ + +#include "cge/talk.h" +#include "cge/jbw.h" + +namespace CGE { + +#ifndef SYSTXT_MAX +#define SYSTXT_MAX 1000 +#endif + +#define SAY_EXT ".SAY" + +#define NOT_VGA_TEXT 90 +#define BAD_CHIP_TEXT 91 +#define BAD_DOS_TEXT 92 +#define NO_CORE_TEXT 93 +#define BAD_MIPS_TEXT 94 +#define NO_MOUSE_TEXT 95 +#define INF_NAME 101 +#define SAY_NAME 102 +#define INF_REF 301 +#define SAY_REF 302 + + +class TEXT { + struct HAN { + int Ref; + char *Txt; + } *Cache; + int Size; + char FileName[MAXPATH]; + char *Load(int idx, int ref); + int Find(int ref); +public: + TEXT(CGEEngine *vm, const char *fname, int size); + ~TEXT(void); + void Clear(int from = 1, int upto = 0x7FFF); + void Preload(int from = 1, int upto = 0x7FFF); + char *getText(int ref); + void Say(const char *txt, Sprite *spr); +private: + CGEEngine *_vm; +}; + + +extern TALK *Talk; +extern TEXT *Text; + + +void Say(const char *txt, Sprite *spr); +void SayTime(Sprite *spr); +void Inf(const char *txt); +void KillText(void); + +} // End of namespace CGE + +#endif diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp new file mode 100644 index 0000000000..673d6036d8 --- /dev/null +++ b/engines/cge/vga13h.cpp @@ -0,0 +1,1391 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "common/rect.h" +#include "graphics/palette.h" +#include "cge/general.h" +#include "cge/vga13h.h" +#include "cge/bitmap.h" +#include "cge/vol.h" +#include "cge/text.h" +#include "cge/cge_main.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include "cge/cge.h" + +namespace CGE { + +#define FADE_STEP 2 +#define TMR_DIV ((0x8000/TMR_RATE)*2) +#define NREP 9 +#define FREP 24 + +static VgaRegBlk VideoMode[] = { + { 0x04, VGASEQ, 0x08, 0x04 }, // memory mode + { 0x03, VGAGRA, 0xFF, 0x00 }, // data rotate = 0 + { 0x05, VGAGRA, 0x03, 0x00 }, // R/W mode = 0 + { 0x06, VGAGRA, 0x02, 0x00 }, // misc + { 0x14, VGACRT, 0x40, 0x00 }, // underline + { 0x13, VGACRT, 0xFF, 0x28 }, // screen width + { 0x17, VGACRT, 0xFF, 0xC3 }, // mode control + { 0x11, VGACRT, 0x80, 0x00 }, // vert retrace end + { 0x09, VGACRT, 0xEF, 0x01 }, // max scan line + { 0x30, VGAATR, 0x00, 0x20 }, // 256 color mode +// { 0x12, VGACRT, 0xFF, 0x6E }, // vert display end +// { 0x15, VGACRT, 0xFF, 0x7F }, // start vb +// { 0x10, VGACRT, 0xFF, 0x94 }, // start vr + { 0x00, 0x00, 0x00, 0x00 } +}; + +bool SpeedTest = false; +Seq _seq1[] = { { 0, 0, 0, 0, 0 } }; +Seq _seq2[] = { { 0, 1, 0, 0, 0 }, { 1, 0, 0, 0, 0 } }; + +extern "C" void SNDMIDIPlay(void); + +char *NumStr(char *str, int num) { + char *p = strchr(str, '#'); + if (p) + wtom(num, p, 10, 5); + return str; +} + + +/* +static void Video() { + static uint16 SP_S; + + asm push bx + asm push bp + asm push si + asm push di + asm push es + asm xor bx,bx // video page #0 + SP_S = _SP; + asm int VIDEO + _SP = SP_S; + asm pop es + asm pop di + asm pop si + asm pop bp + asm pop bx +} +*/ + + +uint16 *SaveScreen(void) { + /* + uint16 cxy, cur, siz, * scr = NULL, * sav; + + // horizontal size of text mode screen + asm mov ah,0x0F // get current video mode + Video(); // BIOS video service + asm xchg ah,al // answer in ah + asm push ax // preserve width + + // vertical size of text mode screen + asm mov dl,24 // last row on std screen + asm xor bx,bx // valid request in BH + asm mov ax,0x1130 // get EGA's last row # + Video(); // BIOS video service + asm inc dl // # of rows = last+1 + + // compute screen size in words + asm pop ax // restore width + asm mul dl // width * height + + siz = _AX; + + asm mov ax,0x40 // system data segment + asm mov es,ax + asm mov ax,0B000H // Mono + asm cmp byte ptr es:[0x49],0x07 + asm je sto + asm mov ax,0B800H // Color + sto: // store screen address + asm mov word ptr scr+2,ax + + _AH = 0x0F; Video(); // active page + + // take cursor shape + _AH = 0x03; Video(); // get cursor size + cur = _CX; + + // take cursor position + _DH = 0; + _AH = 0x03; Video(); // get cursor + cxy = _DX; + + sav = farnew(uint16, siz+3); // +3 extra uint16s for size and cursor + if (sav) + { + sav[0] = siz; + sav[1] = cur; + sav[2] = cxy; + memcpy(sav+3, scr, siz * 2); + } + return sav; + */ + warning("STUB: SaveScreen"); + return 0; +} + + +void RestoreScreen(uint16 * &sav) { + /* + uint16 * scr = NULL; + + asm mov ax,0x40 // system data segment + asm mov es,ax + asm mov ax,0B000H // Mono + asm cmp byte ptr es:[0x49],0x07 + asm je sto + asm mov ax,0B800H // Color + sto: // store screen address + asm mov word ptr scr+2,ax + + memcpy(scr, sav+3, sav[0] * 2); + + _AH = 0x0F; Video(); // active page + + // set cursor shape + _CX = sav[1]; + _AH = 0x01; Video(); // set cursor size + + // set cursor position + _DX = sav[2]; + _AH = 0x02; Video(); // set cursor + + free(sav); + sav = NULL; + */ + warning("STUB: RestoreScreen"); +} + + +DAC MkDAC(uint8 r, uint8 g, uint8 b) { + static DAC x; + x.R = r; + x.G = g; + x.B = b; + return x; +} + + +Rgb MkRGB(uint8 r, uint8 g, uint8 b) { + static TRGB x; + x.dac.R = r; + x.dac.G = g; + x.dac.B = b; + return x.rgb; +} + + +Sprite *Locate(int ref) { + Sprite *spr = Vga->ShowQ->Locate(ref); + return (spr) ? spr : Vga->SpareQ->Locate(ref); +} + + +Heart::Heart(void) + : ENGINE(TMR_DIV) { + _enable = false; + _xTimer = NULL; +} + + +/* +extern "C" void TimerProc() { + static SPRITE * spr; + static uint8 run = 0; + + // decrement external timer uint16 + if (_heart->_xTimer) { + if (*_heart->_xTimer) + *_heart->_xTimer--; + else + _heart->_xTimer = NULL; + } + + if (!run && _heart->_enable) { // check overrun flag + static uint16 oldSP, oldSS; + run++; // disable 2nd call until current lasts + asm mov ax,ds + asm mov oldSS,ss + asm mov oldSP,sp + asm mov ss,ax + asm mov sp,0xFF80 + + // system pseudo-sprite + if (Sys) { + if (Sys->Time) { + if (--Sys->Time == 0) + Sys->Tick(); + } + } + for (spr = VGA::ShowQ.First(); spr; spr = spr->Next) { + if (spr->Time) { + if (!spr->Flags.Hide) { + if (-- spr->Time == 0) + spr->Tick(); + } + } + } + asm mov ss,oldSS + asm mov sp,oldSP + run--; + } +} +*/ + + +void ENGINE::NewTimer(...) { + /* + static SPRITE *spr; + static uint8 run = 0, cntr1 = TMR_RATE1, cntr2 = TMR_RATE2; + ___1152_Hz___: + + SNDMIDIPlay(); + asm dec cntr1 + asm jz ___72_Hz___ + asm mov al,0x20 // send... + asm out 0x020,al // ...e-o-i + return; + + ___72_Hz___: + + asm mov cntr1,TMR_RATE1 + asm dec cntr2 + asm jnz my_eoi + + ___18_Hz___: + + OldTimer(); + asm mov cntr2,TMR_RATE2 + asm jmp short my_int + + // send E-O-I + my_eoi: + asm mov al,0x20 + asm out 0x020,al + asm sti // enable interrupts + + my_int: //------72Hz-------// + + // decrement external timer uint16 + if (_heart->XTimer) { + if (*_heart->XTimer) + *_heart->XTimer--; + else + _heart->XTimer = NULL; + } + + if (! run && _heart->Enable) { // check overrun flag + static uint16 oldSP, oldSS; + + run++; // disable 2nd call until current lasts + asm mov ax,ds + asm mov oldSS,ss + asm mov oldSP,sp + asm mov ss,ax + asm mov sp,0xFF80 + + // system pseudo-sprite + if (Sys) { + if (Sys->Time) { + if (--Sys->Time == 0) + Sys->Tick(); + } + } + + for (spr = VGA::ShowQ.First(); spr; spr = spr->Next) { + if (spr->Time) { + if (!spr->Flags.Hide) { + if (--spr->Time == 0) + spr->Tick(); + } + } + } + asm mov ss,oldSS + asm mov sp,oldSP + run--; + } + + */ + warning("STUB: ENGINE::NewTimer"); +} + + +void Heart::setXTimer(uint16 *ptr) { + if (_xTimer && ptr != _xTimer) + *_xTimer = 0; + _xTimer = ptr; +} + + +void Heart::setXTimer(uint16 *ptr, uint16 time) { + setXTimer(ptr); + *ptr = time; +} + + +Sprite::Sprite(CGEEngine *vm, BMP_PTR *shp) + : _x(0), _y(0), _z(0), NearPtr(0), TakePtr(0), + _next(NULL), _prev(NULL), _seqPtr(NO_SEQ), _time(0), //Delay(0), + _ext(NULL), _ref(-1), _cave(0), _vm(vm) { + memset(File, 0, sizeof(File)); + *((uint16 *)&_flags) = 0; + SetShapeList(shp); +} + + +Sprite::~Sprite() { + Contract(); +} + + +BMP_PTR Sprite::Shp() { + register SprExt *e = _ext; + if (e) + if (e->_seq) { + int i = e->_seq[_seqPtr].Now; + if (i >= _shpCnt) { + //char s[256]; + //sprintf(s, "Seq=%p ShpCnt=%d SeqPtr=%d Now=%d Next=%d", + // Seq, ShpCnt, SeqPtr, Seq[SeqPtr].Now, Seq[SeqPtr].Next); + //VGA::Exit(s, File); + error("Invalid PHASE in SPRITE::Shp() %s", File); + } + return e->_shpList[i]; + } + return NULL; +} + + +BMP_PTR *Sprite::SetShapeList(BMP_PTR *shp) { + BMP_PTR *r = (_ext) ? _ext->_shpList : NULL; + + _shpCnt = 0; + _w = 0; + _h = 0; + + if (shp) { + BMP_PTR *p; + for (p = shp; *p; p++) { + BMP_PTR b = (*p); // ->Code(); + if (b->_w > _w) + _w = b->_w; + if (b->_h > _h) + _h = b->_h; + _shpCnt++; + } + Expand(); + _ext->_shpList = shp; + if (!_ext->_seq) + SetSeq((_shpCnt < 2) ? _seq1 : _seq2); + } + return r; +} + + +void Sprite::MoveShapes(uint8 *buf) { + BMP_PTR *p; + for (p = _ext->_shpList; *p; p++) { + buf += (*p)->MoveVmap(buf); + } +} + + +bool Sprite::Works(Sprite *spr) { + if (spr) + if (spr->_ext) { + SNAIL::COM *c = spr->_ext->_take; + if (c != NULL) { + c += spr->TakePtr; + if (c->Ref == _ref) + if (c->Com != SNLABEL || (c->Val == 0 || c->Val == Now)) + return true; + } + } + return false; +} + + +Seq *Sprite::SetSeq(Seq *seq) { + Expand(); + register Seq *s = _ext->_seq; + _ext->_seq = seq; + if (_seqPtr == NO_SEQ) + Step(0); + else if (_time == 0) + Step(_seqPtr); + return s; +} + + +bool Sprite::SeqTest(int n) { + if (n >= 0) + return (_seqPtr == n); + if (_ext) + return (_ext->_seq[_seqPtr].Next == _seqPtr); + return true; +} + + +SNAIL::COM *Sprite::SnList(SNLIST type) { + register SprExt *e = _ext; + if (e) + return (type == NEAR) ? e->_near : e->_take; + return NULL; +} + + +void Sprite::SetName(char *n) { + if (_ext) { + if (_ext->_name) { + delete[] _ext->_name; + _ext->_name = NULL; + } + if (n) { + if ((_ext->_name = new char[strlen(n) + 1]) != NULL) + strcpy(_ext->_name, n); + else + error("No core [%s]", n); + } + } +} + + +Sprite *Sprite::Expand(void) { + if (!_ext) { + bool enbl = _heart->_enable; + _heart->_enable = false; + if ((_ext = new SprExt) == NULL) + error("No core"); + if (*File) { + static const char *Comd[] = { "Name", "Phase", "Seq", "Near", "Take", NULL }; + char line[LINE_MAX], fname[MAXPATH]; + BMP_PTR *shplist = new BMP_PTR [_shpCnt + 1]; + Seq *seq = NULL; + int shpcnt = 0, + seqcnt = 0, + neacnt = 0, + takcnt = 0, + maxnow = 0, + maxnxt = 0; + + SNAIL::COM *nea = NULL; + SNAIL::COM *tak = NULL; + MergeExt(fname, File, SPR_EXT); + if (INI_FILE::Exist(fname)) { // sprite description file exist + INI_FILE sprf(fname); + if (! (sprf.Error==0)) + error("Bad SPR [%s]", fname); + int len = 0, lcnt = 0; + while ((len = sprf.Read((uint8 *)line)) != 0) { + ++lcnt; + if (len && line[len - 1] == '\n') + line[-- len] = '\0'; + if (len == 0 || *line == '.') + continue; + + switch (TakeEnum(Comd, strtok(line, " =\t"))) { + case 0 : { // Name + SetName(strtok(NULL, "")); + break; + } + case 1 : { // Phase + shplist[shpcnt++] = new Bitmap(strtok(NULL, " \t,;/")); + break; + } + case 2 : { // Seq + seq = (Seq *) realloc(seq, (seqcnt + 1) * sizeof(*seq)); + if (seq == NULL) + error("No core [%s]", fname); + Seq *s = &seq[seqcnt++]; + s->Now = atoi(strtok(NULL, " \t,;/")); + if (s->Now > maxnow) + maxnow = s->Now; + s->Next = atoi(strtok(NULL, " \t,;/")); + switch (s->Next) { + case 0xFF : + s->Next = seqcnt; + break; + case 0xFE : + s->Next = seqcnt - 1; + break; + } + if (s->Next > maxnxt) + maxnxt = s->Next; + s->Dx = atoi(strtok(NULL, " \t,;/")); + s->Dy = atoi(strtok(NULL, " \t,;/")); + s->Dly = atoi(strtok(NULL, " \t,;/")); + break; + } + case 3 : { // Near + if (NearPtr != NO_PTR) { + nea = (SNAIL::COM *) realloc(nea, (neacnt + 1) * sizeof(*nea)); + if (nea == NULL) + error("No core [%s]", fname); + else { + SNAIL::COM *c = &nea[neacnt++]; + if ((c->Com = (SNCOM) TakeEnum(SNAIL::ComTxt, strtok(NULL, " \t,;/"))) < 0) + error("%s [%s]", (const char*)NumStr("Bad NEAR in ######", lcnt), (const char*)fname); + c->Ref = atoi(strtok(NULL, " \t,;/")); + c->Val = atoi(strtok(NULL, " \t,;/")); + c->Ptr = NULL; + } + } + } + break; + case 4 : { // Take + if (TakePtr != NO_PTR) { + tak = (SNAIL::COM *) realloc(tak, (takcnt + 1) * sizeof(*tak)); + if (tak == NULL) + error("No core [%s]", fname); + else { + SNAIL::COM *c = &tak[takcnt++]; + if ((c->Com = (SNCOM) TakeEnum(SNAIL::ComTxt, strtok(NULL, " \t,;/"))) < 0) + error("%s [%s]", NumStr("Bad NEAR in ######", lcnt), (const char *)fname); + c->Ref = atoi(strtok(NULL, " \t,;/")); + c->Val = atoi(strtok(NULL, " \t,;/")); + c->Ptr = NULL; + } + } + break; + } + } + } + } else { // no sprite description: try to read immediately from .BMP + shplist[shpcnt++] = new Bitmap(File); + } + shplist[shpcnt] = NULL; + if (seq) { + if (maxnow >= shpcnt) + error("Bad PHASE in SEQ [%s]", fname); + if (maxnxt >= seqcnt) + error("Bad JUMP in SEQ [%s]", fname); + SetSeq(seq); + } else + SetSeq((_shpCnt == 1) ? _seq1 : _seq2); + //disable(); // disable interupt + + SetShapeList(shplist); + //enable(); // enable interupt + if (nea) + nea[neacnt - 1].Ptr = _ext->_near = nea; + else + NearPtr = NO_PTR; + if (tak) + tak[takcnt - 1].Ptr = _ext->_take = tak; + else + TakePtr = NO_PTR; + } + _heart->_enable = enbl; + } + return this; +} + + +Sprite *Sprite::Contract(void) { + register SprExt *e = _ext; + if (e) { + if (e->_name) + delete[] e->_name; + if (_flags._bDel && e->_shpList) { + int i; + for (i = 0; e->_shpList[i]; i++) + delete e->_shpList[i]; + if (MemType(e->_shpList) == NEAR_MEM) + delete[] e->_shpList; + } + if (MemType(e->_seq) == NEAR_MEM) + free(e->_seq); + if (e->_near) + free(e->_near); + if (e->_take) + free(e->_take); + delete e; + _ext = NULL; + } + return this; +} + + +Sprite *Sprite::BackShow(bool fast) { + Expand(); + Show(2); + Show(1); + if (fast) + Show(0); + Contract(); + return this; +} + + +void Sprite::Step(int nr) { + if (nr >= 0) + _seqPtr = nr; + if (_ext) { + Seq *seq; + if (nr < 0) + _seqPtr = _ext->_seq[_seqPtr].Next; + seq = _ext->_seq + _seqPtr; + if (seq->Dly >= 0) { + Goto(_x + (seq->Dx), _y + (seq->Dy)); + _time = seq->Dly; + } + } +} + + +void Sprite::Tick(void) { + Step(); +} + + +void Sprite::MakeXlat(uint8 *x) { + if (_ext) { + BMP_PTR *b; + + if (_flags._xlat) + KillXlat(); + for (b = _ext->_shpList; *b; b++) + (*b)->_m = x; + _flags._xlat = true; + } +} + + +void Sprite::KillXlat(void) { + if (_flags._xlat && _ext) { + BMP_PTR *b; + uint8 *m = (*_ext->_shpList)->_m; + + switch (MemType(m)) { + case NEAR_MEM : + delete[](uint8 *) m; + break; + case FAR_MEM : + free(m); + break; + default: + warning("Unhandled MemType in Sprite::KillXlat()"); + break; + } + for (b = _ext->_shpList; *b; b++) + (*b)->_m = NULL; + _flags._xlat = false; + } +} + + +void Sprite::Goto(int x, int y) { + int xo = _x, yo = _y; + if (_x < SCR_WID) { + if (x < 0) + x = 0; + if (x + _w > SCR_WID) + x = (SCR_WID - _w); + _x = x; + } + if (_h < SCR_HIG) { + if (y < 0) + y = 0; + if (y + _h > SCR_HIG) + y = (SCR_HIG - _h); + _y = y; + } + if (_next) + if (_next->_flags._slav) + _next->Goto(_next->_x - xo + _x, _next->_y - yo + _y); + if (_flags._shad) + _prev->Goto(_prev->_x - xo + _x, _prev->_y - yo + _y); +} + + +void Sprite::Center(void) { + Goto((SCR_WID - _w) / 2, (SCR_HIG - _h) / 2); +} + + +void Sprite::Show(void) { + register SprExt *e; +// asm cli // critic section... + e = _ext; + e->_x0 = e->_x1; + e->_y0 = e->_y1; + e->_b0 = e->_b1; + e->_x1 = _x; + e->_y1 = _y; + e->_b1 = Shp(); +// asm sti // ...done! + if (!_flags._hide) { + if (_flags._xlat) + e->_b1->XShow(e->_x1, e->_y1); + else + e->_b1->Show(e->_x1, e->_y1); + } +} + + +void Sprite::Show(uint16 pg) { + Graphics::Surface *a = VGA::Page[1]; + VGA::Page[1] = VGA::Page[pg & 3]; + Shp()->Show(_x, _y); + VGA::Page[1] = a; +} + + +void Sprite::Hide(void) { + register SprExt *e = _ext; + if (e->_b0) + e->_b0->Hide(e->_x0, e->_y0); +} + + +BMP_PTR Sprite::Ghost(void) { + register SprExt *e = _ext; + if (e->_b1) { + BMP_PTR bmp = new Bitmap(0, 0, (uint8 *)NULL); + if (bmp == NULL) + error("No core"); + bmp->_w = e->_b1->_w; + bmp->_h = e->_b1->_h; + if ((bmp->_b = farnew(HideDesc, bmp->_h)) == NULL) + error("No Core"); + bmp->_v = (uint8 *) memcpy(bmp->_b, e->_b1->_b, sizeof(HideDesc) * bmp->_h); + // TODO offset correctly in the surface using y1 pitch and x1 and not via offset segment + //bmp->_m = (uint8 *) MK_FP(e->y1, e->x1); + warning("FIXME: SPRITE::Ghost"); + return bmp; + } + return NULL; +} + + +Sprite *SpriteAt(int x, int y) { + Sprite *spr = NULL, * tail = Vga->ShowQ->Last(); + if (tail) { + for (spr = tail->_prev; spr; spr = spr->_prev) { + if (! spr->_flags._hide && ! spr->_flags._tran) { + if (spr->Shp()->SolidAt(x - spr->_x, y - spr->_y)) + break; + } + } + } + return spr; +} + + +QUEUE::QUEUE(bool show) : Head(NULL), Tail(NULL), Show(show) { +} + + +QUEUE::~QUEUE(void) { + Clear(); +} + + +void QUEUE::Clear(void) { + while (Head) { + Sprite *s = Remove(Head); + if (s->_flags._kill) + delete s; + } +} + + +void QUEUE::ForAll(void (*fun)(Sprite *)) { + Sprite *s = Head; + while (s) { + Sprite *n = s->_next; + fun(s); + s = n; + } +} + + +void QUEUE::Append(Sprite *spr) { + if (Tail) { + spr->_prev = Tail; + Tail->_next = spr; + } else + Head = spr; + Tail = spr; + if (Show) + spr->Expand(); + else + spr->Contract(); +} + + +void QUEUE::Insert(Sprite *spr, Sprite *nxt) { + if (nxt == Head) { + spr->_next = Head; + Head = spr; + if (! Tail) + Tail = spr; + } else { + spr->_next = nxt; + spr->_prev = nxt->_prev; + if (spr->_prev) + spr->_prev->_next = spr; + } + if (spr->_next) + spr->_next->_prev = spr; + if (Show) + spr->Expand(); + else + spr->Contract(); +} + + +void QUEUE::Insert(Sprite *spr) { + Sprite *s; + for (s = Head; s; s = s->_next) + if (s->_z > spr->_z) + break; + if (s) + Insert(spr, s); + else + Append(spr); + if (Show) + spr->Expand(); + else + spr->Contract(); +} + + +Sprite *QUEUE::Remove(Sprite *spr) { + if (spr == Head) + Head = spr->_next; + if (spr == Tail) + Tail = spr->_prev; + if (spr->_next) + spr->_next->_prev = spr->_prev; + if (spr->_prev) + spr->_prev->_next = spr->_next; + spr->_prev = NULL; + spr->_next = NULL; + return spr; +} + + +Sprite *QUEUE::Locate(int ref) { + Sprite *spr; + for (spr = Head; spr; spr = spr->_next) { + if (spr->_ref == ref) + return spr; + } + return NULL; +} + + +//extern const char Copr[]; +Graphics::Surface *VGA::Page[4]; +DAC *VGA::SysPal; + +void VGA::init() { + for (int idx = 0; idx < 4; ++idx) { + Page[idx] = new Graphics::Surface(); + Page[idx]->create(320, 200, Graphics::PixelFormat::createFormatCLUT8()); + } + + SysPal = new DAC[PAL_CNT]; +} + +void VGA::deinit() { + for (int idx = 0; idx < 4; ++idx) + delete Page[idx]; + + delete[] SysPal; +} + +VGA::VGA(int mode) + : FrmCnt(0), OldMode(0), OldScreen(NULL), StatAdr(VGAST1_), + Msg(NULL), Nam(NULL), SetPal(false), Mono(0) { + OldColors = NULL; + NewColors = NULL; + ShowQ = new QUEUE(true); + SpareQ = new QUEUE(false); + + bool std = true; + int i; + for (i = 10; i < 20; i++) { + char *txt = Text->getText(i); + if (txt) { + warning("%s", txt); + std = false; + } + } + if (std) +// warning(Copr); + warning("TODO: Fix Copr"); + + SetStatAdr(); + if (StatAdr != VGAST1_) + ++Mono; + if (IsVga()) { + OldColors = farnew(DAC, 256); + NewColors = farnew(DAC, 256); + OldScreen = SaveScreen(); + GetColors(OldColors); + Sunset(); + OldMode = SetMode(mode); + SetColors(); + Setup(VideoMode); + Clear(0); + } +} + + +VGA::~VGA(void) { + Mono = 0; + if (IsVga()) { + Common::String buffer = ""; + Clear(0); + SetMode(OldMode); + SetColors(); + RestoreScreen(OldScreen); + Sunrise(OldColors); + if (OldColors) + free(OldColors); + if (NewColors) + free(NewColors); + if (Msg) + buffer = Common::String(Msg); + if (Nam) + buffer = buffer + " [" + Nam + "]"; + + warning("%s", buffer.c_str()); + } +} + + +void VGA::SetStatAdr(void) { + /* + asm mov dx,VGAMIr_ + asm in al,dx + asm test al,1 // CGA addressing mode flag + asm mov ax,VGAST1_ // CGA addressing + asm jnz set_mode_adr + asm xor al,0x60 // MDA addressing + set_mode_adr: + StatAdr = _AX; + */ + warning("STUB: VGA::SetStatADR"); +} + + +#pragma argsused +void VGA::WaitVR(bool on) { + // Since some of the game parts rely on using vertical sync as a delay mechanism, + // we're introducing a short delay to simulate it + g_system->delayMillis(10); +} + + +void VGA::Setup(VgaRegBlk *vrb) { + /* + WaitVR(); // *--LOOK!--* resets VGAATR logic + asm cld + asm mov si, vrb // take address of parameter table + asm mov dh,0x03 // higher byte of I/O address is always 3 + + s: + asm lodsw // take lower byte of I/O address and index + asm or ah,ah // 0 = end of table + asm jz xit // no more: exit + asm or al,al // indexed register? + asm js single // 7th bit set means single register + asm mov dl,ah // complete I/O address + asm out dx,al // put index into control register + asm inc dx // data register is next to control + asm in al,dx // take old data + + write: + asm mov cl,al // preserve old data + asm lodsw // take 2 masks from table + asm xor al,0xFF // invert mask bits + asm and al,cl // clear bits with "clr" mask + asm or al,ah // set bits with "set" mask + asm cmp dl,0xC1 // special case? + asm jne std2 // no: standard job, otherwise... + asm dec dx // data out reg shares address with index + std2: + asm out dx,al // write new value to register + asm jmp s + + single: // read address in al, write address in ah + asm mov dl,al // complete I/O read address + asm in al,dx // take old data + asm mov dl,ah // complete I/O write address + asm jmp write // continue standard routine + + xit: + */ + warning("STUB: VGA::Setup"); +} + + +int VGA::SetMode(int mode) { + // ScummVM provides it's own vieo services + return 0; +} + + +void VGA::GetColors(DAC *tab) { + byte palData[PAL_SIZ]; + g_system->getPaletteManager()->grabPalette(palData, 0, PAL_CNT); + pal2DAC(palData, tab); +} + +void VGA::pal2DAC(const byte *palData, DAC *tab) { + const byte *colP = palData; + for (int idx = 0; idx < PAL_CNT; ++idx, colP += 3) { + tab[idx].R = *colP; + tab[idx].G = *(colP + 1); + tab[idx].B = *(colP + 2); + } +} + +void VGA::DAC2pal(const DAC *tab, byte *palData) { + for (int idx = 0; idx < PAL_CNT; ++idx, palData += 3) { + *palData = tab[idx].R << 2; + *(palData + 1) = tab[idx].G << 2; + *(palData + 2) = tab[idx].B << 2; + } +} + +void VGA::SetColors(DAC *tab, int lum) { + DAC *palP = tab; + for (int idx = 0; idx < PAL_CNT; ++idx, ++palP) { + palP->R = (palP->R * lum) >> 6; + palP->G = (palP->G * lum) >> 6; + palP->B = (palP->B * lum) >> 6; + } + + if (Mono) { + palP = tab; + for (int idx = 0; idx < PAL_CNT; ++idx, ++palP) { + // Form a greyscalce colour from 30% R, 59% G, 11% B + uint8 intensity = (palP->R * 77) + (palP->G * 151) + (palP->B * 28); + palP->R = intensity; + palP->G = intensity; + palP->B = intensity; + } + } + + SetPal = true; +} + + +void VGA::SetColors(void) { + memset(NewColors, 0, PAL_SIZ); + UpdateColors(); +} + + +void VGA::Sunrise(DAC *tab) { + for (int i = 0; i <= 64; i += FADE_STEP) { + SetColors(tab, i); + WaitVR(true); + UpdateColors(); + } +} + + +void VGA::Sunset(void) { + DAC tab[256]; + GetColors(tab); + for (int i = 64; i >= 0; i -= FADE_STEP) { + SetColors(tab, i); + WaitVR(true); + UpdateColors(); + } +} + + +void VGA::Show(void) { + Sprite *spr = ShowQ->First(); + + for (spr = ShowQ->First(); spr; spr = spr->_next) + spr->Show(); + Update(); + for (spr = ShowQ->First(); spr; spr = spr->_next) + spr->Hide(); + + ++ FrmCnt; +} + + +void VGA::UpdateColors(void) { + byte palData[PAL_SIZ]; + DAC2pal(NewColors, palData); + g_system->getPaletteManager()->setPalette(palData, 0, 256); +} + + +void VGA::Update(void) { + SWAP(VGA::Page[0], VGA::Page[1]); + + if (SetPal) { + UpdateColors(); + SetPal = false; + } + + g_system->copyRectToScreen((const byte *)VGA::Page[0]->getBasePtr(0, 0), SCR_WID, 0, 0, SCR_WID, SCR_HIG); + g_system->updateScreen(); +} + + +void VGA::Clear(uint8 color) { + for (int paneNum = 0; paneNum < 4; ++paneNum) + Page[paneNum]->fillRect(Common::Rect(0, 0, SCR_WID, SCR_HIG), color); +} + + +void VGA::CopyPage(uint16 d, uint16 s) { + Page[d]->copyFrom(*Page[s]); +} + +//-------------------------------------------------------------------------- + +void Bitmap::XShow(int x, int y) { + /* + uint8 rmsk = x % 4, + mask = 1 << rmsk, + *scr = VGA::Page[1] + y * (SCR_WID / 4) + x / 4; + uint8 *m = (char *) M; + uint8 *v = V; + + asm push bx + asm push si + asm push ds + + asm cld + asm les di,scr + asm lds si,v + asm mov bx,m + + asm mov al,0x02 // map mask register + asm mov ah,mask + + plane: + // enable output plane + asm mov dx,VGASEQ_ + asm out dx,ax + asm push ax + + // select input plane + asm mov dx,VGAGRA_ + asm mov al,0x04 // read map select register + asm mov ah,rmsk + asm out dx,ax + + asm push di + + block: + asm lodsw + asm mov cx,ax + asm and ch,0x3F + asm test ah,0xC0 + asm jz endpl + asm jns skip + asm jnp incsi // replicate? + asm add si,cx // skip over data block + asm dec si // fix it before following inc + + incsi: + asm inc si + tint: + asm mov al,es:[di] + //----------------------------------------------- + // asm xlat ss:0 // unsupported with BASM! + __emit__(0x36, 0xD7); // this stands for above! + //----------------------------------------------- + asm stosb + asm loop tint + asm jmp block + + skip: + asm add di,cx + asm jmp block + + endpl: + asm pop di + asm pop ax + asm inc rmsk + asm shl ah,1 + asm test ah,0x10 + asm jz x_chk + asm mov ah,0x01 + asm mov rmsk,0 + asm inc di + x_chk: + asm cmp ah,mask + asm jne plane + asm pop ds + asm pop si + asm pop bx + */ + warning("STUB: BITMAP::XShow"); +} + + +void Bitmap::Show(int x, int y) { + const byte *srcP = (const byte *)_v; + byte *destEndP = (byte *)VGA::Page[1]->pixels + (SCR_WID * SCR_HIG); + + // Loop through processing data for each plane. The game originally ran in plane mapped mode, where a + // given plane holds each fourth pixel sequentially. So to handle an entire picture, each plane's data + // must be decompressed and inserted into the surface + for (int planeCtr = 0; planeCtr < 4; ++planeCtr) { + byte *destP = (byte *)VGA::Page[1]->getBasePtr(x + planeCtr, y); + + for (;;) { + uint16 v = READ_LE_UINT16(srcP); + srcP += 2; + int cmd = v >> 14; + int count = v & 0x3FFF; + + if (cmd == 0) { + // End of image + break; + } + + assert(destP < destEndP); + + // Handle a set of pixels + while (count-- > 0) { + // Transfer operation + switch (cmd) { + case 1: + // SKIP + break; + case 2: + // REPEAT + *destP = *srcP; + break; + case 3: + // COPY + *destP = *srcP++; + break; + } + + // Move to next dest position + destP += 4; + } + + if (cmd == 2) + ++srcP; + } + } +/* + DEBUG code to display image immediately + // Temporary + g_system->copyRectToScreen((const byte *)VGA::Page[1]->getBasePtr(0, 0), SCR_WID, 0, 0, SCR_WID, SCR_HIG); + byte palData[PAL_SIZ]; + VGA::DAC2pal(VGA::SysPal, palData); + g_system->getPaletteManager()->setPalette(palData, 0, PAL_CNT); + + g_system->updateScreen(); + g_system->delayMillis(5000); +*/ +} + + +void Bitmap::Hide(int x, int y) { + /* + uint8 *scr = VGA::Page[1] + y * (SCR_WID / 4) + x / 4; + uint16 d = FP_OFF(VGA::Page[2]) - FP_OFF(VGA::Page[1]); + HideDesc *b = B; + uint16 extra = ((x & 3) != 0); + uint16 h = H; + + // asm push bx + asm push si + asm push ds + + asm cld + asm les di,scr + asm mov si,di + asm add si,d // take bytes from background page + asm lds bx,b + + asm mov dx,VGAGRA_ + asm mov al,0x05 // R/W mode + asm out dx,al + asm inc dx + asm in al,dx + asm and al,0xF4 + asm push ax + asm push dx + asm or al,0x01 + asm out dx,al + + asm mov dx,VGASEQ_ + asm mov ax,0x0F02 // enable all planes + asm out dx,ax + + asm mov dx,ds // save DS + + row: + // skip block + asm mov cx,[bx] + asm add si,cx + asm add di,cx + asm mov cx,[bx+2] + asm add bx,4 + asm add cx,extra + + asm push es + asm pop ds // set DS to video seg + asm rep movsb // move bytes fast + asm sub si,extra + asm sub di,extra + asm mov ds,dx // restore DS + + asm dec h + asm jnz row + + asm pop dx + asm pop ax + asm out dx,al // end of copy mode + + + asm pop ds + asm pop si + // asm pop bx + */ + warning("STUB: Bitmap::Hide"); +} + +} // End of namespace CGE diff --git a/engines/cge/vga13h.h b/engines/cge/vga13h.h new file mode 100644 index 0000000000..0c75dd6ba9 --- /dev/null +++ b/engines/cge/vga13h.h @@ -0,0 +1,346 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __VGA13H__ +#define __VGA13H__ + +#include "graphics/surface.h" +#include "cge/general.h" +#include <stddef.h> +#include "cge/bitmap.h" +#include "cge/snail.h" +#include "cge/cge.h" + +namespace CGE { + +#define TMR_RATE1 16 +#define TMR_RATE2 4 +#define TMR_RATE (TMR_RATE1 * TMR_RATE2) + +#define MAX_NAME 20 +#define VIDEO 0x10 + +#define NO_CLEAR 0x80 +#define TEXT_MODE 0x03 +#define M13H 0x13 + +#ifndef SCR_WID +#define SCR_WID 320 +#endif + +#ifndef SCR_HIG +#define SCR_HIG 200 +#endif + + +#if 0 +#define LIGHT 0xFF +#define DARK 0x00 +#define DGRAY 0xF6 +#define GRAY 0xFC +#define LGRAY 0xFF +#else +#define LIGHT 0xFF +#define DARK 207 +#define DGRAY 225 /*219*/ +#define GRAY 231 +#define LGRAY 237 +#endif + +#define NO_SEQ (-1) +#define NO_PTR ((uint8)-1) + +#define SPR_EXT ".SPR" + +#define IsFile(s) (access(s, 0) == 0) +#define IsWrit(s) (access(s, 2) == 0) + + + +struct Rgb { + uint16 r : 2; + uint16 R : 6; + uint16 g : 2; + uint16 G : 6; + uint16 b : 2; + uint16 B : 6; +}; + +typedef union { + DAC dac; + Rgb rgb; +} TRGB; + +struct VgaRegBlk { + uint8 idx; + uint8 adr; + uint8 clr; + uint8 set; +}; + +struct Seq { + uint8 Now; + uint8 Next; + int8 Dx; + int8 Dy; + int Dly; +}; + +extern Seq _seq1[]; +extern Seq _seq2[]; +//extern SEQ * Compass[]; +//extern SEQ TurnToS[]; + +#define PAL_CNT 256 +#define PAL_SIZ (PAL_CNT * 3) +#define VGAATR_ 0x3C0 +#define VGAMIw_ 0x3C0 +#define VGASEQ_ 0x3C4 +#define VGAMIr_ 0x3CC +#define VGAGRA_ 0x3CE +#define VGACRT_ 0x3D4 +#define VGAST1_ 0x3DA +#define VGAATR (VGAATR_ & 0xFF) +#define VGAMIw (VGAMIw_ & 0xFF) +#define VGASEQ (VGASEQ_ & 0xFF) +#define VGAMIr (VGAMIr_ & 0xFF) +#define VGAGRA (VGAGRA_ & 0xFF) +#define VGACRT (VGACRT_ & 0xFF) +#define VGAST1 (VGAST1_ & 0xFF) + + +class Heart : public ENGINE { + friend class ENGINE; +public: + Heart(); + + bool _enable; + uint16 *_xTimer; + + void setXTimer(uint16 *ptr); + void setXTimer(uint16 *ptr, uint16 time); +}; + + +class SprExt { +public: + int _x0, _y0; + int _x1, _y1; + BMP_PTR _b0, _b1; + BMP_PTR *_shpList; + Seq *_seq; + char *_name; + SNAIL::COM *_near, *_take; + SprExt() : + _x0(0), _y0(0), + _x1(0), _y1(0), + _b0(NULL), _b1(NULL), + _shpList(NULL), _seq(NULL), + _name(NULL), _near(NULL), _take(NULL) + {} +}; + + +class Sprite { +protected: + SprExt *_ext; +public: + int _ref; + signed char _cave; + struct FLAGS { + uint16 _hide : 1; // general visibility switch + uint16 _near : 1; // Near action lock + uint16 _drag : 1; // sprite is moveable + uint16 _hold : 1; // sprite is held with mouse + uint16 _____ : 1; // intrrupt driven animation + uint16 _slav : 1; // slave object + uint16 _syst : 1; // system object + uint16 _kill : 1; // dispose memory after remove + uint16 _xlat : 1; // 2nd way display: xlat table + uint16 _port : 1; // portable + uint16 _kept : 1; // kept in pocket + uint16 _east : 1; // talk to east (in opposite to west) + uint16 _shad : 1; // shadow + uint16 _back : 1; // 'send to background' request + uint16 _bDel : 1; // delete bitmaps in ~SPRITE + uint16 _tran : 1; // transparent (untouchable) + } _flags; + int _x; + int _y; + signed char _z; + uint16 _w; + uint16 _h; + uint16 _time; + uint8 NearPtr, TakePtr; + int _seqPtr; + int _shpCnt; + char File[MAXFILE]; + Sprite *_prev; + Sprite *_next; + bool Works(Sprite *spr); + bool SeqTest(int n); + inline bool Active(void) { + return _ext != NULL; + } + Sprite(CGEEngine *vm, BMP_PTR *shp); + virtual ~Sprite(void); + BMP_PTR Shp(void); + BMP_PTR *SetShapeList(BMP_PTR *shp); + void MoveShapes(uint8 *buf); + Sprite *Expand(void); + Sprite *Contract(void); + Sprite *BackShow(bool fast = false); + void SetName(char *n); + inline char *Name(void) { + return (_ext) ? _ext->_name : NULL; + } + void Goto(int x, int y); + void Center(void); + void Show(void); + void Hide(void); + BMP_PTR Ghost(void); + void Show(uint16 pg); + void MakeXlat(uint8 *x); + void KillXlat(void); + void Step(int nr = -1); + Seq *SetSeq(Seq *seq); + SNAIL::COM *SnList(SNLIST type); + virtual void Touch(uint16 mask, int x, int y); + virtual void Tick(void); +private: + CGEEngine *_vm; +}; + + +class QUEUE { + Sprite *Head, * Tail; +public: + bool Show; + QUEUE(bool show); + ~QUEUE(void); + void Append(Sprite *spr); + void Insert(Sprite *spr, Sprite *nxt); + void Insert(Sprite *spr); + Sprite *Remove(Sprite *spr); + void ForAll(void (*fun)(Sprite *)); + Sprite *First(void) { + return Head; + } + Sprite *Last(void) { + return Tail; + } + Sprite *Locate(int ref); + void Clear(void); +}; + + +class VGA { + uint16 OldMode; + uint16 *OldScreen; + uint16 StatAdr; + bool SetPal; + DAC *OldColors, *NewColors; + const char *Msg; + const char *Nam; + + int SetMode(int mode); + void UpdateColors(void); + void SetColors(void); + void SetStatAdr(void); + void WaitVR(bool on); +public: + uint32 FrmCnt; + QUEUE *ShowQ, *SpareQ; + int Mono; + static Graphics::Surface *Page[4]; + static DAC *SysPal; + + VGA(int mode); + ~VGA(void); + static void init(); + static void deinit(); + + void Setup(VgaRegBlk *vrb); + void GetColors(DAC *tab); + void SetColors(DAC *tab, int lum); + void Clear(uint8 color); + void CopyPage(uint16 d, uint16 s); + void Sunrise(DAC *tab); + void Sunset(void); + void Show(void); + void Update(void); + + static void pal2DAC(const byte *palData, DAC *tab); + static void DAC2pal(const DAC *tab, byte *palData); +}; + + +DAC MkDAC(uint8 r, uint8 g, uint8 b); +Rgb MkRGB(uint8 r, uint8 g, uint8 b); + + +template <class CBLK> +uint8 Closest(CBLK *pal, CBLK x) { +#define f(col, lum) ((((uint16)(col)) << 8) / lum) + uint16 i, dif = 0xFFFF, found = 0; + uint16 L = x.R + x.G + x.B; + if (!L) + ++L; + uint16 R = f(x.R, L), G = f(x.G, L), B = f(x.B, L); + for (i = 0; i < 256; i++) { + uint16 l = pal[i].R + pal[i].G + pal[i].B; + if (! l) + ++l; + int r = f(pal[i].R, l), g = f(pal[i].G, l), b = f(pal[i].B, l); + uint16 D = ((r > R) ? (r - R) : (R - r)) + + ((g > G) ? (g - G) : (G - g)) + + ((b > B) ? (b - B) : (B - b)) + + ((l > L) ? (l - L) : (L - l)) * 10 ; + + if (D < dif) { + found = i; + dif = D; + if (D == 0) + break; // exact! + } + } + return found; +#undef f +} + +char *NumStr(char *str, int num); +//static void Video (void); +uint16 *SaveScreen(void); +void RestoreScreen(uint16 * &sav); +Sprite *SpriteAt(int x, int y); +Sprite *Locate(int ref); + +extern bool SpeedTest; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/vmenu.cpp b/engines/cge/vmenu.cpp new file mode 100644 index 0000000000..ed07a1269f --- /dev/null +++ b/engines/cge/vmenu.cpp @@ -0,0 +1,156 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/vmenu.h" +#include "cge/mouse.h" +#include "cge/cge_main.h" +#include <string.h> + +namespace CGE { + + +#define RELIEF 1 +#if RELIEF +#define MB_LT LGRAY +#define MB_RB DGRAY +#else +#define MB_LT DGRAY +#define MB_RB LGRAY +#endif + + + + +MENU_BAR::MENU_BAR(CGEEngine *vm, uint16 w) : TALK(vm), _vm(vm) { + int h = FONT_HIG + 2 * MB_VM, i = (w += 2 * MB_HM) * h; + uint8 *p = farnew(uint8, i), * p1, * p2; + + memset(p + w, TRANS, i - 2 * w); + memset(p, MB_LT, w); + memset(p + i - w, MB_RB, w); + p1 = p; + p2 = p + i - 1; + for (i = 0; i < h; i++) { + *p1 = MB_LT; + *p2 = MB_RB; + p1 += w; + p2 -= w; + } + TS[0] = new Bitmap(w, h, p); + SetShapeList(TS); + _flags._slav = true; + _flags._tran = true; + _flags._kill = true; + _flags._bDel = true; +} + + +static char *vmgt; + + +char *VMGather(CHOICE *list) { + CHOICE *cp; + int len = 0, h = 0; + + for (cp = list; cp->Text; cp++) { + len += strlen(cp->Text); + h++; + } + vmgt = new char[len + h]; + if (vmgt) { + *vmgt = '\0'; + for (cp = list; cp->Text; cp++) { + if (*vmgt) + strcat(vmgt, "|"); + strcat(vmgt, cp->Text); + h++; + } + } + return vmgt; +} + + +VMENU *VMENU::Addr = NULL; +int VMENU::Recent = -1; + + +VMENU::VMENU(CGEEngine *vm, CHOICE *list, int x, int y) + : TALK(vm, VMGather(list), RECT), Menu(list), Bar(NULL), _vm(vm) { + CHOICE *cp; + + Addr = this; + delete[] vmgt; + Items = 0; + for (cp = list; cp->Text; cp++) + Items++; + _flags._bDel = true; + _flags._kill = true; + if (x < 0 || y < 0) + Center(); + else + Goto(x - _w / 2, y - (TEXT_VM + FONT_HIG / 2)); + Vga->ShowQ->Insert(this, Vga->ShowQ->Last()); + Bar = new MENU_BAR(_vm, _w - 2 * TEXT_HM); + Bar->Goto(_x + TEXT_HM - MB_HM, _y + TEXT_VM - MB_VM); + Vga->ShowQ->Insert(Bar, Vga->ShowQ->Last()); +} + + +VMENU::~VMENU(void) { + Addr = NULL; +} + + +void VMENU::Touch(uint16 mask, int x, int y) { + uint16 h = FONT_HIG + TEXT_LS; + bool ok = false; + + if (Items) { + Sprite::Touch(mask, x, y); + + y -= TEXT_VM - 1; + int n = 0; + if (y >= 0) { + n = y / h; + if (n < Items) + ok = (x >= TEXT_HM && x < _w - TEXT_HM/* && y % h < FONT_HIG*/); + else + n = Items - 1; + } + + Bar->Goto(_x + TEXT_HM - MB_HM, _y + TEXT_VM + n * h - MB_VM); + + if (ok && (mask & L_UP)) { + Items = 0; + SNPOST_(SNKILL, -1, 0, this); + //Menu[Recent = n].Proc(); + warning("Missing call to proc()"); + } + } +} + +} // End of namespace CGE diff --git a/engines/cge/vmenu.h b/engines/cge/vmenu.h new file mode 100644 index 0000000000..3c38576a40 --- /dev/null +++ b/engines/cge/vmenu.h @@ -0,0 +1,69 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __VMENU__ +#define __VMENU__ + +#include "cge/talk.h" + +namespace CGE { + +#define MB_VM 1 +#define MB_HM 3 + + +typedef struct { + const char *Text; + void (CGEEngine::*Proc)(); +} CHOICE; + + +class MENU_BAR : public TALK { +public: + MENU_BAR(CGEEngine *vm, uint16 w); +private: + CGEEngine *_vm; +}; + + +class VMENU : public TALK { + uint16 Items; + CHOICE *Menu; +public: + static VMENU *Addr; + static int Recent; + MENU_BAR *Bar; + VMENU(CGEEngine *vm, CHOICE *list, int x, int y); + ~VMENU(); + void Touch(uint16 mask, int x, int y); +private: + CGEEngine *_vm; +}; + +} // End of namespace CGE + +#endif diff --git a/engines/cge/vol.cpp b/engines/cge/vol.cpp new file mode 100644 index 0000000000..c76914c003 --- /dev/null +++ b/engines/cge/vol.cpp @@ -0,0 +1,111 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge/vol.h" +#include "common/system.h" +#include "common/str.h" +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +namespace CGE { + +DAT *VFILE::_Dat = NULL; +BTFILE *VFILE::_Cat = NULL; +VFILE *VFILE::_Recent = NULL; + +/*-----------------------------------------------------------------------*/ + +DAT::DAT(): +#ifdef VOL_UPD + _File(DAT_NAME, UPD, CRP) +#else + _File(DAT_NAME, REA, CRP) +#endif +{ +} + +/*-----------------------------------------------------------------------*/ + +void VFILE::init() { + _Dat = new DAT(); +#ifdef VOL_UPD + _Cat = new BTFILE(CAT_NAME, UPD, CRP); +#else + _Cat = new BTFILE(CAT_NAME, REA, CRP); +#endif + + _Recent = NULL; +} + +void VFILE::deinit() { + delete _Dat; + delete _Cat; +} + +VFILE::VFILE(const char *name, IOMODE mode) + : IOBUF(mode) { + if (mode == REA) { + if (_Dat->_File.Error || _Cat->Error) + error("Bad volume data"); + BT_KEYPACK *kp = _Cat->Find(name); + if (scumm_stricmp(kp->Key, name) != 0) + Error = 1; + EndMark = (BufMark = BegMark = kp->Mark) + kp->Size; + } +#ifdef VOL_UPD + else + Make(name); +#endif +} + + +VFILE::~VFILE(void) { + if (_Recent == this) + _Recent = NULL; +} + + +bool VFILE::Exist(const char *name) { + return scumm_stricmp(_Cat->Find(name)->Key, name) == 0; +} + + +void VFILE::ReadBuff(void) { + if (_Recent != this) { + _Dat->_File.Seek(BufMark + Lim); + _Recent = this; + } + BufMark = _Dat->_File.Mark(); + long n = EndMark - BufMark; + if (n > IOBUF_SIZE) + n = IOBUF_SIZE; + Lim = _Dat->_File.Read(Buff, (uint16) n); + Ptr = 0; +} + +} // End of namespace CGE diff --git a/engines/cge/vol.h b/engines/cge/vol.h new file mode 100644 index 0000000000..a910aa7209 --- /dev/null +++ b/engines/cge/vol.h @@ -0,0 +1,98 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __VOL__ +#define __VOL__ + +#include "cge/btfile.h" +#include "cge/cfile.h" + +namespace CGE { + +#define CAT_NAME "VOL.CAT" +#define DAT_NAME "VOL.DAT" + +#ifndef CRP +#define CRP XCrypt +#endif + +#define XMASK 0xA5 + +#ifdef VOL_UPD +#define VOLBASE IOHAND +#else +#define VOLBASE CFILE +#endif + + +class DAT { + friend class VFILE; + VOLBASE _File; +public: + DAT(); + + bool Append(uint8 *buf, uint16 len); + bool Write(CFILE &f); + bool Read(long org, uint16 len, uint8 *buf); +}; + + +class VFILE : public IOBUF { +private: + static DAT *_Dat; + static BTFILE *_Cat; + static VFILE *_Recent; + + long BegMark, EndMark; + void ReadBuff(void); + void WriteBuff(void) { } + void Make(const char *fspec); +public: + VFILE(const char *name, IOMODE mode = REA); + ~VFILE(void); + static void init(); + static void deinit(); + + static bool Exist(const char *name); + static const char *Next(void); + long Mark(void) { + return (BufMark + Ptr) - BegMark; + } + long Size(void) { + return EndMark - BegMark; + } + long Seek(long pos) { + _Recent = NULL; + Lim = 0; + return (BufMark = BegMark + pos); + } +}; + + +} // End of namespace CGE + +#endif diff --git a/engines/cge/wav.h b/engines/cge/wav.h new file mode 100644 index 0000000000..304c2827d8 --- /dev/null +++ b/engines/cge/wav.h @@ -0,0 +1,152 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Soltys source code + * Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef __WAV__ +#define __WAV__ + +#include "cge/general.h" +#include <string.h> + +namespace CGE { + +#define WAVE_FORMAT_PCM 0x0001 +#define IBM_FORMAT_MULAW 0x0101 +#define IBM_FORMAT_ALAW 0x0102 +#define IBM_FORMAT_ADPCM 0x0103 + + +typedef char FOURCC[4]; // Four-character code +typedef uint32 CKSIZE; // 32-bit unsigned size + + +class CKID { // Chunk type identifier + union { + FOURCC Tx; + uint32 Id; + }; +protected: + static XFILE *ckFile; +public: + CKID(FOURCC t) { + memcpy(Tx, t, sizeof(Tx)); + } + CKID(uint32 d) { + Id = d; + } + CKID(XFILE *xf) { + (ckFile = xf)->Read(Tx, sizeof(Tx)); + } + bool operator !=(CKID &X) { + return Id != X.Id; + } + bool operator ==(CKID &X) { + return Id == X.Id; + } + const char *Name(void); +}; + + +class CKHEA : public CKID { +protected: + CKSIZE ckSize; // Chunk size field (size of ckData) +public: + CKHEA(XFILE *xf) : CKID(xf) { + XRead(xf, &ckSize); + } + CKHEA(char id[]) : CKID(id), ckSize(0) { } + void Skip(void); + CKSIZE Size(void) { + return ckSize; + } +}; + + +class FMTCK : public CKHEA { + struct WAV { + uint16 wFormatTag; // Format category + uint16 wChannels; // Number of channels + uint32 dwSamplesPerSec; // Sampling rate + uint32 dwAvgBytesPerSec; // For buffer estimation + uint16 wBlockAlign; // Data block size + } Wav; + + union { + struct { + uint16 wBitsPerSample; // Sample size + } Pcm; + }; +public: + FMTCK(CKHEA &hea); + inline uint16 Channels(void) { + return Wav.wChannels; + } + inline uint32 SmplRate(void) { + return Wav.dwSamplesPerSec; + } + inline uint32 ByteRate(void) { + return Wav.dwAvgBytesPerSec; + } + inline uint16 BlckSize(void) { + return Wav.wBlockAlign; + } + inline uint16 SmplSize(void) { + return Pcm.wBitsPerSample; + } +}; + + +class DATACK : public CKHEA { + bool e; + union { + uint8 *Buf; + EMS *EBuf; + }; +public: + DATACK(CKHEA &hea); + DATACK(CKHEA &hea, EMM *emm); + DATACK(int first, int last); + ~DATACK(void); + inline uint8 *Addr(void) { + return Buf; + } + inline EMS *EAddr(void) { + return EBuf; + } +}; + + +extern CKID RIFF; +extern CKID WAVE; +extern CKID FMT; +extern CKID DATA; + + +DATACK *LoadWave(XFILE *file, EMM *emm = NULL); + +} // End of namespace CGE + +#endif diff --git a/engines/engines.mk b/engines/engines.mk index dc09fbd54e..07364a5bd3 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -26,6 +26,11 @@ DEFINES += -DENABLE_AGOS2 endif endif +ifdef ENABLE_CGE +DEFINES += -DENABLE_CGE=$(ENABLE_CGE) +MODULES += engines/cge +endif + ifdef ENABLE_CINE DEFINES += -DENABLE_CINE=$(ENABLE_CINE) MODULES += engines/cine |