diff options
Diffstat (limited to 'engines')
315 files changed, 16917 insertions, 6688 deletions
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp index fa23f5fa1a..72629a833e 100644 --- a/engines/advancedDetector.cpp +++ b/engines/advancedDetector.cpp @@ -122,7 +122,7 @@ bool cleanupPirated(ADGameDescList &matched) { // We ruled out all variants and now have nothing if (matched.empty()) { - warning("Illegitimate game copy detected. We give no support in such cases %d", matched.size()); + warning("Illegitimate game copy detected. We provide no support in such cases"); return true; } } diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp index 392ee08ea1..c26fbe3331 100644 --- a/engines/agos/midi.cpp +++ b/engines/agos/midi.cpp @@ -235,10 +235,6 @@ void MidiPlayer::startTrack(int track) { _music.parser = parser; // That plugs the power cord into the wall } else if (_music.parser) { if (!_music.parser->setTrack(track)) { - // The Roland MT32 music in Simon the Sorcerer 2 - // is missing the extra tracks in many scenes, - // like the introduction sequence. - stop(); return; } _currentTrack = (byte)track; diff --git a/engines/cge/cge.h b/engines/cge/cge.h index a65069ff46..c43358f252 100644 --- a/engines/cge/cge.h +++ b/engines/cge/cge.h @@ -80,12 +80,6 @@ class Talk; #define kSayTheEnd 41 -enum GameType { - kGameTypeNone = 0, - kGameTypeSoltys, - kGameTypeSfinx -}; - // our engine debug channels enum { kCGEDebugBitmap = 1 << 0, diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp index 4c2f81c1ae..022ff4df95 100644 --- a/engines/cge/detection.cpp +++ b/engines/cge/detection.cpp @@ -33,7 +33,6 @@ namespace CGE { struct CgeGameDescription { ADGameDescription desc; - GameType gameType; }; #define GAMEOPTION_COLOR_BLIND_DEFAULT_OFF GUIO_GAMEOPTIONS1 @@ -42,117 +41,81 @@ struct CgeGameDescription { static const PlainGameDescriptor CGEGames[] = { { "soltys", "Soltys" }, - { "sfinx", "Sfinx" }, { 0, 0 } }; namespace CGE { -static const CgeGameDescription gameDescriptions[] = { - - { - { - "soltys", "", - { - {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176}, - {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437572}, - AD_LISTEND - }, - Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0() - }, - kGameTypeSoltys - }, +static const ADGameDescription gameDescriptions[] = { { + "soltys", "", { - "soltys", "Soltys Freeware", - { - {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176}, - {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676}, - AD_LISTEND - }, - Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) + {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176}, + {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437572}, + AD_LISTEND }, - kGameTypeSoltys + Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0() }, { + "soltys", "Freeware", { - "soltys", "Soltys Demo (not supported)", - { - {"vol.cat", 0, "1e077c8ff58109a187f07ac54b0c873a", 18788}, - {"vol.dat", 0, "75d385a6074c58b69f7730481f256051", 1796710}, - AD_LISTEND - }, - Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) + {"vol.cat", 0, "0c33e2c304821a2444d297fc5e2d67c6", 50176}, + {"vol.dat", 0, "f9ae2e7f8f7cac91378cdafca43faf1e", 8437676}, + AD_LISTEND }, - kGameTypeSoltys + Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) }, { + "soltys", "Demo (not supported)", { - "soltys", "Soltys Demo (not supported)", - { - {"vol.cat", 0, "f17987487fab1ebddd781d8d02fedecc", 7168}, - {"vol.dat", 0, "c5d9b15863cab61dc125551576dece04", 1075272}, - AD_LISTEND - }, - Common::PL_POL, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) + {"vol.cat", 0, "1e077c8ff58109a187f07ac54b0c873a", 18788}, + {"vol.dat", 0, "75d385a6074c58b69f7730481f256051", 1796710}, + AD_LISTEND }, - kGameTypeSoltys + Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) }, { + "soltys", "Demo (not supported)", { - "soltys", "Soltys Freeware v1.0", - { - {"vol.cat", 0, "f1675684c68ab90272f5776f8f2c3974", 50176}, - {"vol.dat", 0, "4ffeff4abc99ac5999b55ccfc56ab1df", 8430868}, - AD_LISTEND - }, - Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) + {"vol.cat", 0, "f17987487fab1ebddd781d8d02fedecc", 7168}, + {"vol.dat", 0, "c5d9b15863cab61dc125551576dece04", 1075272}, + AD_LISTEND }, - kGameTypeSoltys + Common::PL_POL, Common::kPlatformDOS, ADGF_DEMO , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) }, { + "soltys", "Freeware v1.0", { - "soltys", "Soltys Freeware v1.0", - { - {"vol.cat", 0, "20fdce799adb618100ef9ee2362be875", 50176}, - {"vol.dat", 0, "0e43331c846094d77f5dd201827e0a3b", 8439339}, - AD_LISTEND - }, - Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) + {"vol.cat", 0, "f1675684c68ab90272f5776f8f2c3974", 50176}, + {"vol.dat", 0, "4ffeff4abc99ac5999b55ccfc56ab1df", 8430868}, + AD_LISTEND }, - kGameTypeSoltys + Common::EN_ANY, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) }, { + "soltys", "Freeware v1.0", { - "soltys", "Soltys Freeware v1.0", - { - {"vol.cat", 0, "fcae86b20eaa5cedec17b24fa5e85eb4", 50176}, - {"vol.dat", 0, "ff10d54acc2c95696c57e05819b6906f", 8450151}, - AD_LISTEND - }, - Common::ES_ESP, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) + {"vol.cat", 0, "20fdce799adb618100ef9ee2362be875", 50176}, + {"vol.dat", 0, "0e43331c846094d77f5dd201827e0a3b", 8439339}, + AD_LISTEND }, - kGameTypeSoltys + Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) }, { + "soltys", "Freeware v1.0", { - // Polish version, provided by Strangerke - "sfinx", "Sfinx Freeware", - { - {"vol.cat", 0, "21197b287d397c53261b6616bf0dd880", 129024}, - {"vol.dat", 0, "de14291869a8eb7c2732ab783c7542ef", 34180844}, - AD_LISTEND - }, - Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) + {"vol.cat", 0, "fcae86b20eaa5cedec17b24fa5e85eb4", 50176}, + {"vol.dat", 0, "ff10d54acc2c95696c57e05819b6906f", 8450151}, + AD_LISTEND }, - kGameTypeSfinx + Common::ES_ESP, Common::kPlatformDOS, ADGF_NO_FLAGS , GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) }, - {AD_TABLE_END_MARKER, kGameTypeNone} + AD_TABLE_END_MARKER }; static const ADFileBasedFallback fileBasedFallback[] = { - { &gameDescriptions[0].desc, { "vol.cat", "vol.dat", 0 } }, + { &gameDescriptions[0], { "vol.cat", "vol.dat", 0 } }, { 0, { 0 } } }; } // End of namespace CGE diff --git a/engines/cge/fileio.cpp b/engines/cge/fileio.cpp index 2b1f74db02..d910e275eb 100644 --- a/engines/cge/fileio.cpp +++ b/engines/cge/fileio.cpp @@ -228,7 +228,7 @@ uint32 EncryptedStream::read(byte *dataPtr, uint32 dataSize) { } bool EncryptedStream::err() { - return (_error & _readStream->err()); + return (_error || _readStream->err()); } bool EncryptedStream::eos() { diff --git a/engines/cge/vga13h.cpp b/engines/cge/vga13h.cpp index d7dccd2c65..babcb7e667 100644 --- a/engines/cge/vga13h.cpp +++ b/engines/cge/vga13h.cpp @@ -482,39 +482,39 @@ void Sprite::sync(Common::Serializer &s) { uint16 flags = 0; if (s.isLoading()) { s.syncAsUint16LE(flags); - _flags._hide = flags & 0x0001 ? true : false; - _flags._near = flags & 0x0002 ? true : false; - _flags._drag = flags & 0x0004 ? true : false; - _flags._hold = flags & 0x0008 ? true : false; - _flags._dummy = flags & 0x0010 ? true : false; - _flags._slav = flags & 0x0020 ? true : false; - _flags._syst = flags & 0x0040 ? true : false; - _flags._kill = flags & 0x0080 ? true : false; - _flags._xlat = flags & 0x0100 ? true : false; - _flags._port = flags & 0x0200 ? true : false; - _flags._kept = flags & 0x0400 ? true : false; - _flags._east = flags & 0x0800 ? true : false; - _flags._shad = flags & 0x1000 ? true : false; - _flags._back = flags & 0x2000 ? true : false; - _flags._bDel = flags & 0x4000 ? true : false; - _flags._tran = flags & 0x8000 ? true : false; + _flags._hide = flags & 0x0001; + _flags._near = flags & 0x0002; + _flags._drag = flags & 0x0004; + _flags._hold = flags & 0x0008; + _flags._dummy = flags & 0x0010; + _flags._slav = flags & 0x0020; + _flags._syst = flags & 0x0040; + _flags._kill = flags & 0x0080; + _flags._xlat = flags & 0x0100; + _flags._port = flags & 0x0200; + _flags._kept = flags & 0x0400; + _flags._east = flags & 0x0800; + _flags._shad = flags & 0x1000; + _flags._back = flags & 0x2000; + _flags._bDel = flags & 0x4000; + _flags._tran = flags & 0x8000; } else { - flags = (flags << 1) | _flags._tran; - flags = (flags << 1) | _flags._bDel; - flags = (flags << 1) | _flags._back; - flags = (flags << 1) | _flags._shad; - flags = (flags << 1) | _flags._east; - flags = (flags << 1) | _flags._kept; - flags = (flags << 1) | _flags._port; - flags = (flags << 1) | _flags._xlat; - flags = (flags << 1) | _flags._kill; - flags = (flags << 1) | _flags._syst; - flags = (flags << 1) | _flags._slav; - flags = (flags << 1) | _flags._dummy; - flags = (flags << 1) | _flags._hold; - flags = (flags << 1) | _flags._drag; - flags = (flags << 1) | _flags._near; - flags = (flags << 1) | _flags._hide; + flags = (flags << 1) | (_flags._tran ? 1 : 0); + flags = (flags << 1) | (_flags._bDel ? 1 : 0); + flags = (flags << 1) | (_flags._back ? 1 : 0); + flags = (flags << 1) | (_flags._shad ? 1 : 0); + flags = (flags << 1) | (_flags._east ? 1 : 0); + flags = (flags << 1) | (_flags._kept ? 1 : 0); + flags = (flags << 1) | (_flags._port ? 1 : 0); + flags = (flags << 1) | (_flags._xlat ? 1 : 0); + flags = (flags << 1) | (_flags._kill ? 1 : 0); + flags = (flags << 1) | (_flags._syst ? 1 : 0); + flags = (flags << 1) | (_flags._slav ? 1 : 0); + flags = (flags << 1) | (_flags._dummy ? 1 : 0); + flags = (flags << 1) | (_flags._hold ? 1 : 0); + flags = (flags << 1) | (_flags._drag ? 1 : 0); + flags = (flags << 1) | (_flags._near ? 1 : 0); + flags = (flags << 1) | (_flags._hide ? 1 : 0); s.syncAsUint16LE(flags); } diff --git a/engines/cge/vga13h.h b/engines/cge/vga13h.h index 9511559df0..a976d7078c 100644 --- a/engines/cge/vga13h.h +++ b/engines/cge/vga13h.h @@ -88,22 +88,22 @@ public: int _ref; signed char _scene; 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 _dummy : 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) + bool _hide; // general visibility switch + bool _near; // Near action lock + bool _drag; // sprite is moveable + bool _hold; // sprite is held with mouse + bool _dummy; // interrupt driven animation + bool _slav; // slave object + bool _syst; // system object + bool _kill; // dispose memory after remove + bool _xlat; // 2nd way display: xlat table + bool _port; // portable + bool _kept; // kept in pocket + bool _east; // talk to east (in opposite to west) + bool _shad; // shadow + bool _back; // 'send to background' request + bool _bDel; // delete bitmaps in ~SPRITE + bool _tran; // transparent (untouchable) } _flags; int _x; int _y; diff --git a/engines/cge2/bitmap.cpp b/engines/cge2/bitmap.cpp new file mode 100644 index 0000000000..0f442b8c77 --- /dev/null +++ b/engines/cge2/bitmap.cpp @@ -0,0 +1,458 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge2/bitmap.h" +#include "cge2/cge2.h" +#include "cge2/vga13h.h" +#include "cge2/talk.h" +#include "common/system.h" +#include "common/debug.h" +#include "common/debug-channels.h" + +namespace CGE2 { + +Bitmap::Bitmap() : _w(0), _h(0), _v(nullptr), _b(nullptr), _map(0), _vm(nullptr) { +} + +void Bitmap::setVM(CGE2Engine *vm) { + _vm = vm; +} + +Bitmap::Bitmap(CGE2Engine *vm, const char *fname) : _w(0), _h(0), _v(nullptr), _b(nullptr), _map(0), _vm(vm) { + Common::String path; + + if (!strcmp(fname, "04tal201")) { + path = "04tal202"; + warning("Workaround for missing VBM: 04tal201"); + } else if (!strcmp(fname, "11oqlist-")) { + path = "11oqlist"; + warning("Workaround for wrong VBM name: 11oqlist-"); + } else + path = fname; + + path = setExtension(path, ".VBM"); + + if (_vm->_resman->exist(path.c_str())) { + EncryptedStream file(_vm, path.c_str()); + if (file.err()) + error("Unable to find VBM [%s]", fname); + if (!loadVBM(&file)) + error("Bad VBM [%s]", fname); + } else { + warning("Missing VBM [%s]", path.c_str()); + } +} + +Bitmap::Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 *map) : _w(w), _h(h), _v(nullptr), _map(0), _b(nullptr), _vm(vm) { + if (map) + code(map); +} + +// following routine creates filled rectangle +// immediately as VGA video chunks, in near memory as fast as possible, +// especially for text line real time display +Bitmap::Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 fill) + : _w((w + 3) & ~3), // only full uint32 allowed! + _h(h), _map(0), _b(nullptr), _vm(vm) { + + uint16 dsiz = _w >> 2; // data size (1 plane line size) + uint16 lsiz = 2 + dsiz + 2; // uint16 for line header, uint16 for gap + uint16 psiz = _h * lsiz; // - last gape, but + plane trailer + uint8 *v = new uint8[4 * psiz + _h * sizeof(*_b)];// the same for 4 planes + // + room for wash table + + WRITE_LE_UINT16(v, (kBmpCPY | dsiz)); // data chunk hader + memset(v + 2, fill, dsiz); // data bytes + WRITE_LE_UINT16(v + lsiz - 2, (kBmpSKP | ((kScrWidth / 4) - dsiz))); // gap + + // Replicate lines + byte *destP; + for (destP = v + lsiz; destP < (v + psiz); destP += lsiz) + Common::copy(v, v + lsiz, destP); + + WRITE_LE_UINT16(v + psiz - 2, kBmpEOI); // plane trailer uint16 + + // Replicate planes + for (destP = v + psiz; destP < (v + 4 * psiz); destP += psiz) + Common::copy(v, v + psiz, destP); + + HideDesc *b = (HideDesc *)(v + 4 * psiz); + b->_skip = (kScrWidth - _w) >> 2; + b->_hide = _w >> 2; + + // Replicate across the entire table + for (HideDesc *hdP = b + 1; hdP < (b + _h); hdP++) + *hdP = *b; + + b->_skip = 0; // fix the first entry + _v = v; + _b = b; +} + +Bitmap::Bitmap(CGE2Engine *vm, const Bitmap &bmp) : _w(bmp._w), _h(bmp._h), _v(nullptr), _map(0), _b(nullptr), _vm(vm) { + uint8 *v0 = bmp._v; + if (!v0) + return; + + uint16 vsiz = (uint8 *)(bmp._b) - (uint8 *)(v0); + uint16 siz = vsiz + _h * sizeof(HideDesc); + uint8 *v1 = new uint8[siz]; + memcpy(v1, v0, siz); + _b = (HideDesc *)((_v = v1) + vsiz); +} + +Bitmap::~Bitmap() { + release(); +} + +void Bitmap::release() { + if (_v != nullptr) + delete[] _v; + _v = nullptr; +} + +Bitmap &Bitmap::operator=(const Bitmap &bmp) { + if (this == &bmp) + return *this; + + uint8 *v0 = bmp._v; + _w = bmp._w; + _h = bmp._h; + _map = 0; + _vm = bmp._vm; + delete[] _v; + _v = nullptr; + + if (v0) { + uint16 vsiz = (uint8 *)bmp._b - (uint8 *)v0; + uint16 siz = vsiz + _h * sizeof(HideDesc); + uint8 *v1 = new uint8[siz]; + memcpy(v1, v0, siz); + _b = (HideDesc *)((_v = v1) + vsiz); + } + return *this; +} + +// Blatant rip from hopkins engine where it's ripped from gob engine. Hi DrMcCoy, hi Strangerke! ;> +Common::String Bitmap::setExtension(const Common::String &str, const Common::String &ext) { + if (str.empty()) + return str; + + const char *dot = strrchr(str.c_str(), '.'); + if (dot) + return Common::String(str.c_str(), dot - str.c_str()) + ext; + + return str + ext; +} + +BitmapPtr Bitmap::code(uint8 *map) { + if (!map) + return nullptr; + + uint16 cnt; + + if (_v) { // old X-map exists, so remove it + delete[] _v; + _v = nullptr; + } + + while (true) { // at most 2 times: for (V == NULL) & for allocated block; + uint8 *im = _v + 2; + uint16 *cp = (uint16 *) _v; + + if (_v) { // 2nd pass - fill the hide table + for (uint i = 0; i < _h; i++) { + _b[i]._skip = 0xFFFF; + _b[i]._hide = 0x0000; + } + } + for (int bpl = 0; bpl < 4; bpl++) { // once per each bitplane + uint8 *bm = map; + bool skip = (bm[bpl] == kPixelTransp); + uint16 j; + + cnt = 0; + for (uint i = 0; i < _h; i++) { // once per each line + uint8 pix; + for (j = bpl; j < _w; j += 4) { + pix = bm[j]; + if (_v && (pix != kPixelTransp)) { + if (j < _b[i]._skip) + _b[i]._skip = j; + + if (j >= _b[i]._hide) + _b[i]._hide = j + 1; + } + if (((pix == kPixelTransp) != skip) || (cnt >= 0x3FF0)) { // end of block + cnt |= (skip) ? kBmpSKP : kBmpCPY; + if (_v) + WRITE_LE_UINT16(cp, cnt); // store block description uint16 + + cp = (uint16 *) im; + im += 2; + skip = (pix == kPixelTransp); + cnt = 0; + } + if (!skip) { + if (_v) + *im = pix; + im++; + } + cnt++; + } + + bm += _w; + if (_w < kScrWidth) { + if (skip) + cnt += (kScrWidth - j + 3) / 4; + else { + cnt |= kBmpCPY; + if (_v) + WRITE_LE_UINT16(cp, cnt); + + cp = (uint16 *) im; + im += 2; + skip = true; + cnt = (kScrWidth - j + 3) / 4; + } + } + } + if (cnt && ! skip) { + cnt |= kBmpCPY; + if (_v) + WRITE_LE_UINT16(cp, cnt); + + cp = (uint16 *) im; + im += 2; + } + if (_v) + WRITE_LE_UINT16(cp, kBmpEOI); + cp = (uint16 *) im; + im += 2; + } + if (_v) + break; + + uint16 sizV = (uint16)(im - 2 - _v); + _v = new uint8[sizV + _h * sizeof(*_b)]; + _b = (HideDesc *)(_v + sizV); + } + cnt = 0; + for (uint i = 0; i < _h; i++) { + if (_b[i]._skip == 0xFFFF) { // whole line is skipped + _b[i]._skip = (cnt + kScrWidth) >> 2; + cnt = 0; + } else { + uint16 s = _b[i]._skip & ~3; + uint16 h = (_b[i]._hide + 3) & ~3; + _b[i]._skip = (cnt + s) >> 2; + _b[i]._hide = (h - s) >> 2; + cnt = kScrWidth - h; + } + } + + return this; +} + +bool Bitmap::solidAt(V2D pos) { + pos.x += _w >> 1; + pos.y = _h - pos.y; + + if (!pos.limited(V2D(_vm, _w, _h))) + return false; + + uint8 *m = _v; + uint16 r = static_cast<uint16>(pos.x) % 4; + uint16 n0 = (kScrWidth * pos.y + pos.x) / 4; + uint16 n = 0; + + while (r) { + uint16 w, t; + + w = READ_LE_UINT16(m); + m += 2; + t = w & 0xC000; + w &= 0x3FFF; + + switch (t) { + case kBmpEOI: + r--; + // No break on purpose + case kBmpSKP: + w = 0; + break; + case kBmpREP: + w = 1; + break; + } + m += w; + } + + while (true) { + uint16 w, t; + + w = READ_LE_UINT16(m); + m += 2; + t = w & 0xC000; + w &= 0x3FFF; + + if (n > n0) + return false; + + n += w; + switch (t) { + case kBmpEOI: + return false; + case kBmpSKP: + w = 0; + break; + case kBmpREP: + case kBmpCPY: + if ((n - w <= n0) && (n > n0)) + return true; + break; + } + m += ((t == kBmpREP) ? 1 : w); + } +} + +bool Bitmap::loadVBM(EncryptedStream *f) { + uint16 p = 0, n = 0; + if (!f->err()) + f->read((uint8 *)&p, sizeof(p)); + p = FROM_LE_16(p); + + if (!f->err()) + f->read((uint8 *)&n, sizeof(n)); + n = FROM_LE_16(n); + + if (!f->err()) + f->read((uint8 *)&_w, sizeof(_w)); + _w = FROM_LE_16(_w); + + if (!f->err()) + f->read((uint8 *)&_h, sizeof(_h)); + _h = FROM_LE_16(_h); + + if (!f->err()) { + if (p) { + if (_vm->_bitmapPalette) { + // Read in the palette + byte palData[kPalSize]; + f->read(palData, kPalSize); + + const byte *srcP = palData; + for (int idx = 0; idx < kPalCount; idx++, srcP += 3) { + _vm->_bitmapPalette[idx]._r = *srcP; + _vm->_bitmapPalette[idx]._g = *(srcP + 1); + _vm->_bitmapPalette[idx]._b = *(srcP + 2); + } + } else + f->seek(f->pos() + kPalSize); + } + } + _v = new uint8[n]; + + if (!f->err()) + f->read(_v, n); + + _b = (HideDesc *)(_v + n - _h * sizeof(HideDesc)); + return (!f->err()); +} + +void Bitmap::xLatPos(V2D& p) { + p.x -= (_w >> 1); + p.y = kWorldHeight - p.y - _h; +} + +#define _ kPixelTransp, +#define L 1, +#define G 2, +#define D 3, +#define kDesignSize 240 + +uint8 *Bitmap::makeSpeechBubbleTail(int which, uint8 colorSet[][4]) { + static const uint8 kSLDesign[kDesignSize] = { + 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 const uint8 kSRDesign[kDesignSize] = { + _ _ _ _ _ _ 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 _ _ _ _ _ _ _ _ _ _ _ _ _ _ + }; + + uint8 *des = new uint8[kDesignSize]; + switch (which) { + case 0: + memcpy(des, kSLDesign, sizeof(kSLDesign)); + break; + case 1: + memcpy(des, kSRDesign, sizeof(kSRDesign)); + break; + default: + error("Wrong parameter in Bitmap::makeSpeechBubbleTail!"); + break; + } + + for (int i = 0; i < kDesignSize; i++) { + if ((des[i] >= 1) && (des[i] <= 3)) + des[i] = colorSet[kCBSay][des[i]]; + } + + return des; +} + +} // End of namespace CGE2 diff --git a/engines/cge2/bitmap.h b/engines/cge2/bitmap.h new file mode 100644 index 0000000000..613222fc6e --- /dev/null +++ b/engines/cge2/bitmap.h @@ -0,0 +1,94 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_BITMAP_H +#define CGE2_BITMAP_H + +#include "cge2/general.h" +#include "common/file.h" + +namespace CGE2 { + +class CGE2Engine; +class EncryptedStream; +class V2D; + +#define kMaxPath 128 + +enum { + kBmpEOI = 0x0000, + kBmpSKP = 0x4000, + kBmpREP = 0x8000, + kBmpCPY = 0xC000 +}; + +#include "common/pack-start.h" + +struct HideDesc { + uint16 _skip; + uint16 _hide; +}; + +#include "common/pack-end.h" + +class Bitmap { + CGE2Engine *_vm; + + Common::String setExtension(const Common::String &str, const Common::String &ext); + bool loadVBM(EncryptedStream *f); +public: + uint16 _w; + uint16 _h; + uint8 *_v; + int32 _map; + HideDesc *_b; + + Bitmap(); + Bitmap(CGE2Engine *vm, const char *fname); + Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 *map); + Bitmap(CGE2Engine *vm, uint16 w, uint16 h, uint8 fill); + Bitmap(CGE2Engine *vm, const Bitmap &bmp); + ~Bitmap(); + + void setVM(CGE2Engine *vm); + Bitmap *code(uint8 *map); + Bitmap &operator=(const Bitmap &bmp); + void release(); + void hide(V2D pos); + void show(V2D pos); + bool solidAt(V2D pos); + void xLatPos(V2D &p); + + static uint8 *makeSpeechBubbleTail(int des, uint8 colorSet[][4]); +}; + + +typedef Bitmap *BitmapPtr; + +} // End of namespace CGE2 + +#endif // CGE2_BITMAP_H diff --git a/engines/cge2/cge2.cpp b/engines/cge2/cge2.cpp new file mode 100644 index 0000000000..852b7afb22 --- /dev/null +++ b/engines/cge2/cge2.cpp @@ -0,0 +1,206 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "engines/util.h" +#include "common/config-manager.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "cge2/cge2.h" +#include "cge2/bitmap.h" +#include "cge2/vga13h.h" +#include "cge2/sound.h" +#include "cge2/text.h" +#include "cge2/hero.h" +#include "cge2/general.h" +#include "cge2/spare.h" +#include "cge2/talk.h" +#include "cge2/cge2_main.h" +#include "cge2/map.h" + +namespace CGE2 { + +CGE2Engine::CGE2Engine(OSystem *syst, const ADGameDescription *gameDescription) + : Engine(syst), _gameDescription(gameDescription), _randomSource("cge2") { + + // Debug/console setup + DebugMan.addDebugChannel(kCGE2DebugOpcode, "opcode", "CGE2 opcode debug channel"); + + _resman = nullptr; + _vga = nullptr; + _midiPlayer = nullptr; + _fx = nullptr; + _sound = nullptr; + _text = nullptr; + for (int i = 0; i < 2; i++) + _heroTab[i] = nullptr; + _eye = nullptr; + for (int i = 0; i < kSceneMax; i++) + _eyeTab[i] = nullptr; + _spare = nullptr; + _commandHandler = nullptr; + _commandHandlerTurbo = nullptr; + _font = nullptr; + _infoLine = nullptr; + _mouse = nullptr; + _keyboard = nullptr; + _talk = nullptr; + for (int i = 0; i < kMaxPoint; i++) + _point[i] = nullptr; + _sys = nullptr; + _busyPtr = nullptr; + for (int i = 0; i < 2; i++) + _vol[i] = nullptr; + _eventManager = nullptr; + _map = nullptr; + _quitFlag = false; + _bitmapPalette = nullptr; + _gamePhase = kPhaseIntro; + _now = 1; + _sex = 1; + _mouseTop = kWorldHeight / 3; + _dark = false; + _lastFrame = 0; + _lastTick = 0; + _waitSeq = 0; + _waitRef = 0; + _soundStat._wait = nullptr; + _soundStat._ref[0] = 0; + _soundStat._ref[1] = 0; + _taken = false; + _endGame = false; + _req = 1; + _midiNotify = nullptr; + _spriteNotify = nullptr; + _startGameSlot = 0; + + _sayCap = ConfMan.getBool("subtitles"); + _sayVox = !ConfMan.getBool("speech_mute"); + _muteAll = ConfMan.getBool("mute"); + if (_muteAll) { + _oldMusicVolume = _oldSfxVolume = 0; + _music = _sayVox = false; + } else { + _oldMusicVolume = ConfMan.getInt("music_volume"); + _oldSfxVolume = ConfMan.getInt("sfx_volume"); + _music = _oldMusicVolume != 0; + } +} + +void CGE2Engine::init() { + // Create debugger console + _console = new CGE2Console(this); + _resman = new ResourceManager(); + _vga = new Vga(this); + _fx = new Fx(this, 16); + _sound = new Sound(this); + _midiPlayer = new MusicPlayer(this); + _text = new Text(this, "CGE"); + + for (int i = 0; i < 2; i++) + _heroTab[i] = new HeroTab(this); + + _eye = new V3D(); + for (int i = 0; i < kSceneMax; i++) + _eyeTab[i] = new V3D(); + + _spare = new Spare(this); + _commandHandler = new CommandHandler(this, false); + _commandHandlerTurbo = new CommandHandler(this, true); + _font = new Font(this); + _infoLine = new InfoLine(this, kInfoW); + _mouse = new Mouse(this); + _keyboard = new Keyboard(this); + + for (int i = 0; i < kMaxPoint; i++) + _point[i] = new V3D(); + + _sys = new System(this); + _eventManager = new EventManager(this); + _map = new Map(this); + _startGameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1; +} + +void CGE2Engine::deinit() { + // Remove all of our debug levels here + DebugMan.clearAllDebugChannels(); + + delete _console; + + delete _spare; + delete _resman; + delete _vga; + delete _fx; + delete _sound; + delete _midiPlayer; + delete _text; + + for (int i = 0; i < 2; i++) + delete _heroTab[i]; + + for (int i = 0; i < kSceneMax; i++) + delete _eyeTab[i]; + + delete _eye; + delete _commandHandler; + delete _commandHandlerTurbo; + delete _font; + delete _infoLine; + delete _mouse; + delete _keyboard; + + if (_talk != nullptr) + delete _talk; + + for (int i = 0; i < kMaxPoint; i++) + delete _point[i]; + + delete _sys; + delete _eventManager; + delete _map; +} + +bool CGE2Engine::hasFeature(EngineFeature f) const { + return (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime) + || (f == kSupportsRTL); +} + +Common::Error CGE2Engine::run() { + syncSoundSettings(); + initGraphics(kScrWidth, kScrHeight, false); + + init(); + cge2_main(); + deinit(); + + ConfMan.setBool("subtitles", _sayCap); + ConfMan.setBool("speech_mute", !_sayVox); + ConfMan.flushToDisk(); + + return Common::kNoError; +} + +} // End of namespace CGE2 diff --git a/engines/cge2/cge2.h b/engines/cge2/cge2.h new file mode 100644 index 0000000000..1f1cb17b48 --- /dev/null +++ b/engines/cge2/cge2.h @@ -0,0 +1,341 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_H +#define CGE2_H + +#include "common/random.h" +#include "common/savefile.h" +#include "common/serializer.h" +#include "engines/engine.h" +#include "engines/advancedDetector.h" +#include "common/system.h" +#include "cge2/fileio.h" +#include "cge2/console.h" +#include "audio/mixer.h" + +namespace CGE2 { + +class Vga; +class Sprite; +class MusicPlayer; +class Fx; +class Sound; +class Text; +struct HeroTab; +class FXP; +class V3D; +class V2D; +struct Dac; +class Spare; +class CommandHandler; +class InfoLine; +class Mouse; +class Keyboard; +class Talk; +class Hero; +class Bitmap; +class System; +class EventManager; +class Font; +class Map; +struct SavegameHeader; + +#define kScrWidth 320 +#define kScrHeight 240 +#define kScrDepth 480 +#define kPanHeight 40 +#define kWorldHeight (kScrHeight - kPanHeight) +#define kMaxFile 128 +#define kPathMax 128 +#define kDimMax 8 +#define kWayMax 10 +#define kPocketMax 4 +#define kSceneMax 100 +#define kMaxPoint 4 +#define kInfoX 160 +#define kInfoY -11 +#define kInfoW 180 +#define kPocketsWidth 59 +#define kLineMax 512 + +#define kIntroExt ".I80" +#define kTabName "CGE.TAB" +#define kPocketFull 170 +#define kGameFrameDelay (750 / 50) +#define kGameTickDelay (750 / 62) + +#define kMusicRef 122 +#define kPowerRef 123 +#define kDvolRef 124 +#define kMvolRef 125 +#define kRef 126 +#define kBusyRef 127 +#define kCapRef 128 +#define kVoxRef 129 + +#define kOffUseCount 130 +#define kOffUseText 131 + +#define kSysTimeRate 6 // 12 Hz +#define kBlinkRate 4 // 3 Hz + +#define kQuitTitle 200 +#define kQuitText 201 +#define kNoQuitText 202 + +#define kSavegameVersion 1 +#define kSavegameStrSize 12 +#define kSavegameStr "SCUMMVM_CGE2" + +#define kColorNum 6 + +struct SavegameHeader { + uint8 version; + Common::String saveName; + Graphics::Surface *thumbnail; + int saveYear, saveMonth, saveDay; + int saveHour, saveMinutes; +}; + +enum ColorBank { kCBRel, kCBStd, kCBSay, kCBInf, kCBMnu, kCBWar }; + +enum GamePhase { kPhaseInGame, kPhaseIntro, kPhaseOver }; + +// our engine debug channels +enum { + kCGE2DebugOpcode = 1 << 0 +}; + +enum CallbackType { + kNullCB = 0, kQGame, kXScene +}; + +enum Action { kNear, kMTake, kFTake, kActions }; + +typedef void (CGE2Engine::*NotifyFunctionType)(); + +class CGE2Engine : public Engine { +private: + uint32 _lastFrame, _lastTick; + void tick(); + + CGE2Console *_console; + void init(); + void deinit(); + + Common::String generateSaveName(int slot); + void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header); + void saveGame(int slotNumber, const Common::String &desc); + bool loadGame(int slotNumber); + void syncHeader(Common::Serializer &s); + void syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream); + void resetGame(); +public: + CGE2Engine(OSystem *syst, const ADGameDescription *gameDescription); + virtual bool hasFeature(EngineFeature f) const; + virtual bool canSaveGameStateCurrently(); + virtual bool canLoadGameStateCurrently(); + virtual Common::Error saveGameState(int slot, const Common::String &desc); + virtual Common::Error loadGameState(int slot); + virtual Common::Error run(); + + static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header); + + GUI::Debugger *getDebugger() { + return _console; + } + + bool showTitle(const char *name); + void cge2_main(); + char *mergeExt(char *buf, const char *name, const char *ext); + void inf(const char *text, ColorBank col = kCBInf); + void movie(const char *ext); + void runGame(); + void loadHeroes(); + void loadScript(const char *fname, bool onlyToolbar = false); + Sprite *loadSprite(const char *fname, int ref, int scene, V3D &pos); + void badLab(const char *fn); + void sceneUp(int cav); + void sceneDown(); + void closePocket(); + void switchScene(int scene); + void storeHeroPos(); + void showBak(int ref); + void loadTab(); + int newRandom(int range); + void openPocket(); + void selectPocket(int n); + void busy(bool on); + void feedSnail(Sprite *spr, Action snq, Hero *hero); + int freePockets(int sx); + int findActivePocket(int ref); + void pocFul(); + void killText(); + void mainLoop(); + void handleFrame(); + Sprite *locate(int ref); + bool isHero(Sprite *spr); + void loadUser(); + void loadPos(); + void releasePocket(Sprite *spr); + void switchHero(int sex); + void offUse(); + void setAutoColors(); + bool cross(const V2D &a, const V2D &b, const V2D &c, const V2D &d); + bool contain(const V2D &a, const V2D &b, const V2D &p); + long det(const V2D &a, const V2D &b, const V2D &c); + int sgn(long n); + int mapCross(const V2D &a, const V2D &b); + Sprite *spriteAt(V2D pos); + void keyClick(); + void swapInPocket(Sprite *spr, Sprite *xspr); + void busyStep(); + + void optionTouch(int opt, uint16 mask); + void switchColorMode(); + void switchMusic(); + void quit(); + void setVolume(int idx, int cnt); + void checkVolumeSwitches(); + void switchCap(); + void switchVox(); + void switchSay(); + void initToolbar(); + void initVolumeSwitch(Sprite *volSwitch, int val); + void checkMute(); + + void checkSounds(); + + void setEye(const V3D &e); + void setEye(const V2D& e2, int z = -kScrWidth); + void setEye(const char *s); + + int number(char *s); + char *token(char *s); + char *tail(char *s); + int takeEnum(const char **tab, const char *text); + ID ident(const char *s); + bool testBool(char *s); + + void snKill(Sprite *spr); + void snHide(Sprite *spr, int val); + void snMidi(int val); + void snSeq(Sprite *spr, int val); + void snRSeq(Sprite *spr, int val); + void snSend(Sprite *spr, int val); + void snSwap(Sprite *spr, int val); + void snCover(Sprite *spr, int val); + void snUncover(Sprite *spr, Sprite *spr2); + void snKeep(Sprite *spr, int val); + void snGive(Sprite *spr, int val); + void snGoto(Sprite *spr, int val); + void snPort(Sprite *spr, int port); + void snMouse(bool on); + void snNNext(Sprite *spr, Action act, int val); + void snRNNext(Sprite *spr, int val); + void snRMTNext(Sprite *spr, int val); + void snRFTNext(Sprite *spr, int val); + void snRmNear(Sprite *spr); + void snRmMTake(Sprite *spr); + void snRmFTake(Sprite *spr); + void snSetRef(Sprite *spr, int val); + void snFlash(bool on); + void snCycle(int cnt); + void snWalk(Sprite *spr, int val); + void snReach(Sprite *spr, int val); + void snSound(Sprite *spr, int wav, Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType); + void snRoom(Sprite *spr, bool on); + void snGhost(Bitmap *bmp); + void snSay(Sprite *spr, int val); + + void hide1(Sprite *spr); + Sprite *expandSprite(Sprite *spr); + void qGame(); + void xScene(); + + const ADGameDescription *_gameDescription; + + Common::RandomSource _randomSource; + + bool _quitFlag; + Dac *_bitmapPalette; + GamePhase _gamePhase; // Original name: startupmode + int _now; + int _sex; + int _mouseTop; + bool _dark; + int _waitSeq; + int _waitRef; + + struct { + int *_wait; + int _ref[2]; + } _soundStat; + + bool _taken; + bool _endGame; + int _req; + NotifyFunctionType _midiNotify; + NotifyFunctionType _spriteNotify; + int _startGameSlot; + + bool _sayCap; + bool _sayVox; + int _oldMusicVolume; + int _oldSfxVolume; + bool _music; + bool _muteAll; + + ResourceManager *_resman; + Vga *_vga; + MusicPlayer *_midiPlayer; + Fx *_fx; + Sound *_sound; + Text *_text; + HeroTab *_heroTab[2]; + V3D *_eye; + V3D *_eyeTab[kSceneMax]; + Spare *_spare; + CommandHandler *_commandHandler; + CommandHandler *_commandHandlerTurbo; + Font *_font; + InfoLine *_infoLine; + Mouse *_mouse; + Keyboard *_keyboard; + Talk *_talk; + V3D *_point[kMaxPoint]; + System *_sys; + Sprite *_busyPtr; + Sprite *_vol[2]; + EventManager *_eventManager; + Map *_map; +}; + +} // End of namespace CGE2 + +#endif // CGE2_H diff --git a/engines/cge2/cge2_main.cpp b/engines/cge2/cge2_main.cpp new file mode 100644 index 0000000000..1057b00089 --- /dev/null +++ b/engines/cge2/cge2_main.cpp @@ -0,0 +1,960 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "sound.h" +#include "cge2/cge2_main.h" +#include "cge2/cge2.h" +#include "cge2/vga13h.h" +#include "cge2/text.h" +#include "cge2/snail.h" +#include "cge2/hero.h" +#include "cge2/spare.h" +#include "cge2/map.h" + +namespace CGE2 { + +System::System(CGE2Engine *vm) : Sprite(vm), _vm(vm) { + _blinkCounter = 0; + _blinkSprite = nullptr; + tick(); +} + +void System::touch(uint16 mask, V2D pos, Common::KeyCode keyCode) { + if (mask & kEventKeyb) { + if (keyCode == Common::KEYCODE_ESCAPE) { + // The original was calling keyClick() + // The sound is uselessly annoying and noisy, so it has been removed + _vm->killText(); + if (_vm->_gamePhase == kPhaseIntro) { + _vm->_commandHandler->addCommand(kCmdClear, -1, 0, nullptr); + return; + } + } + } else { + if (_vm->_gamePhase != kPhaseInGame) + return; + _vm->_infoLine->setText(nullptr); + + if (mask & kMouseLeftUp) { + if (pos.y >= 0) { // world + if (!_vm->_talk && pos.y < _vm->_mouseTop) + _vm->_heroTab[_vm->_sex]->_ptr->walkTo(pos); + } else { // panel + if (_vm->_commandHandler->idle()) { + int sex = pos.x < kPocketsWidth; + if (sex || pos.x >= kScrWidth - kPocketsWidth) { + _vm->switchHero(sex); + if (_vm->_sex == sex) { + int dx = kPocketsWidth >> 1, + dy = 1 - (kPanHeight >> 1); + Sprite *s; + if (!sex) + pos.x -= kScrWidth - kPocketsWidth; + dx -= pos.x; + dy -= pos.y; + if (dx * dx + dy * dy > 10 * 10) { + int n = 0; + if (1 - pos.y >= (kPanHeight >> 1)) + n += 2; + if (pos.x >= (kPocketsWidth >> 1)) + ++n; + s = _vm->_heroTab[_vm->_sex]->_pocket[n]; + if (_vm->_sys->_blinkSprite) + _vm->_sys->_blinkSprite->_flags._hide = false; + if (_vm->_sys->_blinkSprite == s) + _vm->_sys->_blinkSprite = nullptr; + else + _vm->_sys->_blinkSprite = s; + } + } + } + } + } + } + } +} + +void System::tick() { + _time = kSysTimeRate; + + if (_blinkCounter) + --_blinkCounter; + else { + if (_blinkSprite) + _blinkSprite->_flags._hide ^= 1; + _blinkCounter = kBlinkRate; + } +} + +int CGE2Engine::number(char *str) { + char *s = token(str); + if (s == nullptr) + error("Wrong input for CGE2Engine::number()"); + int r = atoi(s); + char *pp = strchr(s, ':'); + if (pp) + r = (r << 8) + atoi(pp + 1); + return r; +} + +char *CGE2Engine::token(char *s) { + return strtok(s, " =\t,;/()"); +} + +char *CGE2Engine::tail(char *s) { + if (s && (*s == '=')) + s++; + return s; +} + +int CGE2Engine::takeEnum(const char **tab, const char *text) { + if (text) { + for (const char **e = tab; *e; e++) { + if (scumm_stricmp(text, *e) == 0) + return e - tab; + } + } + return -1; +} + +ID CGE2Engine::ident(const char *s) { + return ID(takeEnum(EncryptedStream::kIdTab, s)); +} + +bool CGE2Engine::testBool(char *s) { + return number(s) != 0; +} + +void CGE2Engine::badLab(const char *fn) { + error("Misplaced label in %s!", fn); +} + +Sprite *CGE2Engine::loadSprite(const char *fname, int ref, int scene, V3D &pos) { + int shpcnt = 0; + int seqcnt = 0; + int cnt[kActions]; + + for (int i = 0; i < kActions; i++) + cnt[i] = 0; + + ID section = kIdPhase; + bool frnt = true; + bool east = false; + bool port = false; + bool tran = false; + Hero *h; + ID id; + + char tmpStr[kLineMax + 1]; + mergeExt(tmpStr, fname, kSprExt); + + if (_resman->exist(tmpStr)) { // sprite description file exist + EncryptedStream sprf(this, tmpStr); + if (sprf.err()) + error("Bad SPR [%s]", tmpStr); + + int label = kNoByte; + Common::String line; + + for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()){ + if (line.empty()) + continue; + Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr)); + + char *p = token(tmpStr); + if (*p == '@') { + if (label != kNoByte) + badLab(fname); + label = atoi(p + 1); + continue; + } + + id = ident(p); + switch (id) { + case kIdName: // will be taken in Expand routine + if (label != kNoByte) + badLab(fname); + break; + case kIdType: + if (label != kNoByte) + badLab(fname); + break; + case kIdNear: + case kIdMTake: + case kIdFTake: + case kIdPhase: + case kIdSeq: + if (label != kNoByte) + badLab(fname); + section = id; + break; + case kIdFront: + if (label != kNoByte) + badLab(fname); + p = token(nullptr); + frnt = testBool(p); + break; + case kIdEast: + if (label != kNoByte) + badLab(fname); + p = token(nullptr); + east = testBool(p); + break; + case kIdPortable: + if (label != kNoByte) + badLab(fname); + p = token(nullptr); + port = testBool(p); + break; + case kIdTransparent: + if (label != kNoByte) + badLab(fname); + p = token(nullptr); + tran = testBool(p); + break; + default: + if (id >= kIdNear) + break; + switch (section) { + case kIdNear: + case kIdMTake: + case kIdFTake: + if (_commandHandler->getComId(p) >= 0) + ++cnt[section]; + else + error("Bad line %d [%s]", sprf.getLineCount(), tmpStr); + break; + case kIdPhase: + if (label != kNoByte) + badLab(fname); + ++shpcnt; + break; + case kIdSeq: + if (label != kNoByte) + badLab(fname); + ++seqcnt; + break; + default: + break; + } + break; + } + label = kNoByte; + } + + if (!shpcnt) + error("No shapes - %s", fname); + } else // No sprite description: mono-shaped sprite with only .BMP file. + ++shpcnt; + + // Make sprite of chosen type: + Sprite *sprite = nullptr; + char c = *fname | 0x20; + if (c >= 'a' && c <= 'z' && fname[1] == '0' && fname[2] == '\0') { + h = new Hero(this); + h->gotoxyz(pos); + sprite = h; + } else { + sprite = new Sprite(this); + sprite->gotoxyz(pos); + } + + if (sprite) { + sprite->_ref = ref; + sprite->_scene = scene; + + sprite->_flags._frnt = frnt; + sprite->_flags._east = east; + sprite->_flags._port = port; + sprite->_flags._tran = tran; + sprite->_flags._kill = true; + + // Extract the filename, without the extension + Common::strlcpy(sprite->_file, fname, sizeof(sprite->_file)); + char *p = strchr(sprite->_file, '.'); + if (p) + *p = '\0'; + + sprite->_shpCnt = shpcnt; + sprite->_seqCnt = seqcnt; + + for (int i = 0; i < kActions; i++) + sprite->_actionCtrl[i]._cnt = cnt[i]; + } + + return sprite; +} + +void CGE2Engine::loadScript(const char *fname, bool onlyToolbar) { + EncryptedStream scrf(this, fname); + + if (scrf.err()) + return; + + bool ok = true; + int lcnt = 0; + + char tmpStr[kLineMax + 1]; + Common::String line; + + for (line = scrf.readLine(); !scrf.eos(); line = scrf.readLine()) { + if (line.empty()) + continue; + + lcnt++; + Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr)); + + ok = false; // not OK if break + + V3D P; + + // sprite ident number + int SpI = number(tmpStr); + + if (onlyToolbar && SpI >= 141) + return; + + // sprite file name + char *SpN; + if ((SpN = token(nullptr)) == nullptr) + break; + + // sprite scene + int SpA = number(nullptr); + + // sprite column + P._x = number(nullptr); + + // sprite row + P._y = number(nullptr); + + // sprite Z pos + P._z = number(nullptr); + + // sprite life + bool BkG = number(nullptr) == 0; + + ok = true; // no break: OK + + Sprite *sprite = loadSprite(SpN, SpI, SpA, P); + if (sprite) { + if (BkG) + sprite->_flags._back = true; + + int n = _spare->count(); + if (_spare->locate(sprite->_ref) == nullptr) + _spare->dispose(sprite); + else + delete sprite; + + if (_spare->count() == n) + error("Duplicate reference! %s", SpN); + } + } + + if (!ok) + error("Bad INI line %d [%s]", scrf.getLineCount(), fname); +} + +void CGE2Engine::movie(const char *ext) { + assert(ext); + + if (_quitFlag) + return; + + char fn[12]; + snprintf(fn, 12, "CGE%s", ext); + + if (_resman->exist(fn)) { + int now = _now; + _now = atoi(ext + 2); + loadScript(fn); + sceneUp(_now); + _keyboard->setClient(_sys); + + while (!_commandHandler->idle() && !_quitFlag) + mainLoop(); + + _keyboard->setClient(nullptr); + _commandHandler->addCommand(kCmdClear, -1, 0, nullptr); + _commandHandlerTurbo->addCommand(kCmdClear, -1, 0, nullptr); + _spare->clear(); + _vga->_showQ->clear(); + _now = now; + } +} + +void CGE2Engine::sceneUp(int cav) { + _now = cav; + int bakRef = _now << 8; + if (_music) + _midiPlayer->loadMidi(bakRef); + showBak(bakRef); + *_eye = *(_eyeTab[_now]); + _mouseTop = V2D(this, V3D(0, 1, kScrDepth)).y; + _map->load(_now); + _spare->takeScene(_now); + openPocket(); + + for (int i = 0; i < 2; i++) { + Hero *h = _heroTab[i]->_ptr; + if (h && h->_scene == _now) { + V2D p = *_heroTab[i]->_posTab[_now]; + h->gotoxyz(V3D(p.x, 0, p.y)); + h->clrHide(); + _vga->_showQ->insert(h); + h->park(); + h->setCurrent(); + h->setContact(); + } + } + + _sound->stop(); + _fx->clear(); + + selectPocket(-1); + _infoLine->setText(nullptr); + busy(false); + + if (!_dark) + _vga->sunset(); + + _vga->show(); + _vga->copyPage(1, 0); + _vga->show(); + _vga->sunrise(_vga->_sysPal); + + _dark = false; + + if (_gamePhase == kPhaseInGame) + _mouse->on(); + + feedSnail(_vga->_showQ->locate(bakRef + 255), kNear, _heroTab[_sex]->_ptr); +} + +void CGE2Engine::sceneDown() { + busy(true); + _soundStat._wait = nullptr; // unlock snail + Sprite *spr = _vga->_showQ->locate((_now << 8) | 254); + + if (spr) + feedSnail(spr, kNear, _heroTab[_sex]->_ptr); + + while (!(_commandHandler->idle() && _commandHandlerTurbo->idle())) { + _commandHandlerTurbo->runCommand(); + _commandHandler->runCommand(); + } + + closePocket(); + for (int i = 0; i < 2; i++) + _spare->update(_vga->_showQ->remove(_heroTab[i]->_ptr)); + _spare->dispose(); +} + +void CGE2Engine::switchScene(int scene) { + if (scene == _now) + return; + + _req = scene; + storeHeroPos(); + *(_eyeTab[_now]) = *_eye; + + if (scene < 0) + _commandHandler->addCallback(kCmdExec, -1, 0, kQGame); // quit game + else { + if (_heroTab[_sex]->_ptr->_scene == _now) { + _heroTab[_sex]->_ptr->setScene(scene); + if (_heroTab[!_sex]->_ptr->_scene == _now) + _heroTab[!_sex]->_ptr->setScene(scene); + } + _mouse->off(); + if (_heroTab[_sex]->_ptr) + _heroTab[_sex]->_ptr->park(); + killText(); + _commandHandler->addCallback(kCmdExec, -1, 0, kXScene); // switch scene + } +} + +void CGE2Engine::storeHeroPos() { + for (int i = 0; i < 2; i++) { + Hero *h = _heroTab[i]->_ptr; + if (h->_scene == _now) { + delete _heroTab[i]->_posTab[_now]; + V2D *temp = new V2D(this, h->_pos3D._x.trunc(), h->_pos3D._z.trunc()); + _heroTab[i]->_posTab[_now] = temp; + } + } +} + +void CGE2Engine::showBak(int ref) { + Sprite *spr = _spare->locate(ref); + if (spr != nullptr) { + _bitmapPalette = _vga->_sysPal; + spr->expand(); + _bitmapPalette = nullptr; + spr->show(2); + _vga->copyPage(1, 2); + } +} + +void CGE2Engine::mainLoop() { + if (_gamePhase == kPhaseInGame) + checkSounds(); + + _vga->show(); + _commandHandlerTurbo->runCommand(); + _commandHandler->runCommand(); + + // Handle a delay between game frames + handleFrame(); + + // Handle any pending events + _eventManager->poll(); + + // Check shouldQuit() + _quitFlag = shouldQuit(); +} + +void CGE2Engine::checkSounds() { + checkMute(); + _sound->checkSoundHandles(); + checkVolumeSwitches(); + _midiPlayer->syncVolume(); + syncSoundSettings(); +} + +void CGE2Engine::handleFrame() { + // Game frame delay + uint32 millis = g_system->getMillis(); + while (!_quitFlag && (millis < (_lastFrame + kGameFrameDelay))) { + // Handle any pending events + _eventManager->poll(); + + if (millis >= (_lastTick + kGameTickDelay)) { + // Dispatch the tick to any active objects + tick(); + _lastTick = millis; + } + + // Slight delay + g_system->delayMillis(5); + millis = g_system->getMillis(); + } + _lastFrame = millis; + + if (millis >= (_lastTick + kGameTickDelay)) { + // Dispatch the tick to any active objects + tick(); + _lastTick = millis; + } +} + +Sprite *CGE2Engine::locate(int ref) { + _taken = false; + Sprite *spr = _vga->_showQ->locate(ref); + if (!spr) { + spr = _spare->locate(ref); + if (spr) + _taken = true; + } + return spr; +} + +bool CGE2Engine::isHero(Sprite *spr) { + return spr && spr->_ref / 10 == 14; +} + +void CGE2Engine::tick() { + // system pseudo-sprite + if (_sys && _sys->_time && (--_sys->_time == 0)) + _sys->tick(); + + for (Sprite *spr = _vga->_showQ->first(); spr; spr = spr->_next) { + if (spr->_time && (--spr->_time == 0)) + spr->tick(); + + if (_waitRef && (_waitRef == spr->_ref) && spr->seqTest(_waitSeq)) + _waitRef = 0; + } + + _mouse->tick(); +} + +void CGE2Engine::busy(bool on) { + if (on) { + _spriteNotify = _midiNotify = &CGE2::CGE2Engine::busyStep; + busyStep(); + } else { + if (_busyPtr) + _busyPtr->step(0); + _spriteNotify = _midiNotify = nullptr; + } +} + +void CGE2Engine::busyStep() { + if (_busyPtr) { + _busyPtr->step((_busyPtr->_seqPtr) ? -1 : 1); + _busyPtr->show(0); + } +} + +void CGE2Engine::runGame() { + if (_quitFlag) + return; + + loadUser(); + sceneUp(_now); + initToolbar(); + + // main loop + while (!_endGame && !_quitFlag) + mainLoop(); + + // If leaving the game (close window, return to launcher, etc. + // - except finishing the game), explicitly save it's state: + if (!_endGame && canSaveGameStateCurrently()) + qGame(); + + _keyboard->setClient(nullptr); + _commandHandler->addCommand(kCmdClear, -1, 0, nullptr); + _commandHandlerTurbo->addCommand(kCmdClear, -1, 0, nullptr); + _mouse->off(); +} + +void CGE2Engine::loadUser() { + loadPos(); + + if (_startGameSlot != -1) + loadGame(_startGameSlot); + else { + loadScript("CGE.INI"); + loadHeroes(); + } +} + +void CGE2Engine::loadHeroes() { // Original name: loadGame() + // load sprites & pocket + + Sprite *s; + Hero *h = nullptr; + + // initialize Andzia/Anna + s = _spare->take(142); + if (s) { + h = new Hero(this); + *(Sprite*)h = *s; + delete s; + h->expand(); + _spare->update(h); + } + _heroTab[0]->_ptr = h; + s = _spare->locate(152); + _vga->_showQ->insert(s); + _heroTab[0]->_face = s; + + // initialize Wacek/Vincent + s = _spare->take(141); + if (s) { + h = new Hero(this); + *(Sprite*)h = *s; + delete s; + h->expand(); + _spare->update(h); + } + _heroTab[1]->_ptr = h; + s = _spare->locate(151); + _vga->_showQ->insert(s); + _heroTab[1]->_face = s; + + //--- start! + switchHero(_sex); +} + +void CGE2Engine::loadPos() { + if (_resman->exist("CGE.HXY")) { + for (int cav = 0; cav < kSceneMax; cav++) + _heroTab[1]->_posTab[cav] = new V2D(this, 180, 10); + + EncryptedStream file(this, "CGE.HXY"); + + for (int cav = 0; cav < kSceneMax; cav++) { + _heroTab[0]->_posTab[cav] = new V2D(this); + _heroTab[0]->_posTab[cav]->x = file.readSint16LE(); + _heroTab[0]->_posTab[cav]->y = file.readSint16LE(); + } + + for (int cav = 0; cav < 41; cav++) { // (564 - 400) / 4 = 41 + _heroTab[1]->_posTab[cav]->x = file.readSint16LE(); + _heroTab[1]->_posTab[cav]->y = file.readSint16LE(); + } + } else + error("Missing file: CGE.HXY"); +} + +void CGE2Engine::loadTab() { + setEye(_text->getText(240)); + for (int i = 0; i < kSceneMax; i++) + *(_eyeTab[i]) = *_eye; + + if (_resman->exist(kTabName)) { + EncryptedStream f(this, kTabName); + uint32 v; + + for (int i = 0; i < kSceneMax; i++) { + v = f.readUint32LE(); + _eyeTab[i]->_x = FXP(v >> 8, static_cast<int>((int8)(v & 0xff))); + + v = f.readUint32LE(); + _eyeTab[i]->_y = FXP(v >> 8, static_cast<int>((int8)(v & 0xff))); + + v = f.readUint32LE(); + _eyeTab[i]->_z = FXP(v >> 8, static_cast<int>((int8)(v & 0xff))); + } + } +} + +void CGE2Engine::cge2_main() { + loadTab(); + + if (_startGameSlot != -1) { + // Starting up a savegame from the launcher + runGame(); + return; + } + + if (showTitle("WELCOME")) { + movie(kIntroExt); + + if (_text->getText(255) != nullptr) { + runGame(); + _gamePhase = kPhaseOver; + } + + _vga->sunset(); + } else + _vga->sunset(); +} + +char *CGE2Engine::mergeExt(char *buf, const char *name, const char *ext) { + strcpy(buf, name); + char *dot = strrchr(buf, '.'); + if (!dot) + strcat(buf, ext); + + return buf; +} + +void CGE2Engine::setEye(const V3D &e) { + *_eye = e; +} + +void CGE2Engine::setEye(const V2D& e2, int z) { + _eye->_x = e2.x; + _eye->_y = e2.y; + _eye->_z = z; +} + +void CGE2Engine::setEye(const char *s) { + char *tempStr = new char[strlen(s) + 1]; + strcpy(tempStr, s); + _eye->_x = atoi(token(tempStr)); + _eye->_y = atoi(token(nullptr)); + _eye->_z = atoi(token(nullptr)); + delete[] tempStr; +} + +int CGE2Engine::newRandom(int range) { + if (!range) + return 0; + + return _randomSource.getRandomNumber(range - 1); +} + +bool CGE2Engine::showTitle(const char *name) { + if (_quitFlag) + return false; + + _bitmapPalette = _vga->_sysPal; + BitmapPtr LB = new Bitmap[1]; + LB[0] = Bitmap(this, name); + _bitmapPalette = nullptr; + + Sprite D(this, LB, 1); + D._flags._kill = true; + D.gotoxyz(kScrWidth >> 1, -(kPanHeight >> 1)); + + _vga->sunset(); + D.show(2); + _vga->copyPage(1, 2); + _vga->copyPage(0, 1); + _vga->sunrise(_vga->_sysPal); + _vga->update(); + + g_system->delayMillis(2500); + + return true; +} + +void CGE2Engine::killText() { + if (!_talk) + return; + + _commandHandlerTurbo->addCommand(kCmdKill, -1, 0, _talk); + _talk = nullptr; +} + +void CGE2Engine::switchHero(int sex) { + if (sex != _sex) { + int scene = _heroTab[sex]->_ptr->_scene; + if (_sys->_blinkSprite) { + _sys->_blinkSprite->_flags._hide = false; + _sys->_blinkSprite = nullptr; + } + + if (scene >= 0) { + _commandHandler->addCommand(kCmdSeq, -1, 2, _heroTab[_sex]->_face); + _sex ^= 1; + switchScene(scene); + } + } + Sprite *face = _heroTab[_sex]->_face; + if (face->_seqPtr == 0) + _commandHandler->addCommand(kCmdSeq, -1, 1, face); +} + +void Sprite::touch(uint16 mask, V2D pos, Common::KeyCode keyCode) { + if ((mask & kEventAttn) != 0) + return; + + if (_vm->_gamePhase == kPhaseInGame) + _vm->_infoLine->setText(name()); + + if (_ref < 0) + return; // cannot access system sprites + + if (_ref / 10 == 12) { + _vm->optionTouch(_ref % 10, mask); + return; + } + + if ((mask & kMouseLeftUp) && _vm->_commandHandler->idle()) { + if (_vm->isHero(this) && !_vm->_sys->_blinkSprite) { + _vm->switchHero((this == _vm->_heroTab[1]->_ptr) ? 1 : 0); + } else if (_flags._kept) { // sprite in pocket + for (int sex = 0; sex < 2; ++sex) { + for (int p = 0; p < kPocketMax; ++p) { + if (_vm->_heroTab[sex]->_pocket[p] == this) { + _vm->switchHero(sex); + if (_vm->_sex == sex) { + if (_vm->_sys->_blinkSprite) + _vm->_sys->_blinkSprite->_flags._hide = false; + + if (_vm->_sys->_blinkSprite == this) + _vm->_sys->_blinkSprite = nullptr; + else + _vm->_sys->_blinkSprite = this; + } + } + } + } + } else { // sprite NOT in pocket + Hero *h = _vm->_heroTab[_vm->_sex]->_ptr; + if (!_vm->_talk) { + // the "+3" is a hack used to work around a script issue in scene 5 + if ((_ref & 0xFF) < 200 && h->distance(this) > (h->_maxDist << 1) + 3) + h->walkTo(this); + else if (_vm->_sys->_blinkSprite) { + if (works(_vm->_sys->_blinkSprite)) { + _vm->feedSnail(_vm->_sys->_blinkSprite, (_vm->_sex) ? kMTake : kFTake, _vm->_heroTab[_vm->_sex]->_ptr); + _vm->_sys->_blinkSprite->_flags._hide = false; + _vm->_sys->_blinkSprite = nullptr; + } else + _vm->offUse(); + + _vm->selectPocket(-1); + // else, no pocket sprite selected + } else if (_flags._port) { // portable + if (_vm->findActivePocket(-1) < 0) + _vm->pocFul(); + else { + _vm->_commandHandler->addCommand(kCmdReach, -2, _ref, nullptr); + _vm->_commandHandler->addCommand(kCmdKeep, -1, -1, this); + _flags._port = false; + } + } else { // non-portable + Action a = h->action(); + if (_actionCtrl[a]._cnt) { + CommandHandler::Command *cmdList = snList(a); + if (cmdList[_actionCtrl[a]._ptr]._commandType == kCmdNext) + _vm->offUse(); + else + _vm->feedSnail(this, a, h); + } else + _vm->offUse(); + } + } + } + } +} + +void CGE2Engine::keyClick() { + _commandHandlerTurbo->addCommand(kCmdSound, -1, 5, nullptr); +} + +void CGE2Engine::offUse() { + int seq = 0; + int offUseCount = atoi(_text->getText(kOffUseCount)); + + // This fixes the issue of empty speech bubbles in the original. + // Now we only let this cycle pass if it randoms a valid value for getText(). + int txt = 0; + do { + txt = kOffUseText + _sex * offUseCount + newRandom(offUseCount); + } while (_text->getText(txt) == nullptr); + + Hero *h = _heroTab[_sex]->_ptr; + h->park(); + _commandHandler->addCommand(kCmdWait, -1, -1, h); + _commandHandler->addCommand(kCmdSeq, -1, seq, h); + if (!_sayVox) + _commandHandler->addCommand(kCmdSound, -1, 6 + _sex, h); + _commandHandler->addCommand(kCmdWait, -1, -1, h); + _commandHandler->addCommand(kCmdSay, -1, txt, h); +} + +Sprite *CGE2Engine::spriteAt(V2D pos) { + Sprite *spr; + + for (spr = _vga->_showQ->last(); spr; spr = spr->_prev) { + if (!spr->_flags._hide && !spr->_flags._tran && (spr->getShp()->solidAt(pos - spr->_pos2D))) + break; + } + + return spr; +} + +} // End of namespace CGE2 diff --git a/engines/cge2/cge2_main.h b/engines/cge2/cge2_main.h new file mode 100644 index 0000000000..88cca1cc1e --- /dev/null +++ b/engines/cge2/cge2_main.h @@ -0,0 +1,52 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_MAIN_H +#define CGE2_MAIN_H + +#include "cge2/events.h" + +namespace CGE2 { + +#define kShowScummVMVersion 15 + +class System : public Sprite { +public: + int _blinkCounter; + Sprite *_blinkSprite; + + System(CGE2Engine *vm); + + virtual void touch(uint16 mask, V2D pos, Common::KeyCode keyCode); + void tick(); +private: + CGE2Engine *_vm; +}; + +} // End of namespace CGE2 + +#endif // CGE2_MAIN_H diff --git a/engines/cge2/configure.engine b/engines/cge2/configure.engine new file mode 100644 index 0000000000..6ccbfee088 --- /dev/null +++ b/engines/cge2/configure.engine @@ -0,0 +1,3 @@ +# This file is included from the main "configure" script +# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] +add_engine cge2 "CGE2" no diff --git a/engines/cge2/console.cpp b/engines/cge2/console.cpp new file mode 100644 index 0000000000..c67c7ab788 --- /dev/null +++ b/engines/cge2/console.cpp @@ -0,0 +1,33 @@ +/* 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 "cge2/console.h" + +namespace CGE2 { + +CGE2Console::CGE2Console(CGE2Engine *vm) : GUI::Debugger() { +} + +CGE2Console::~CGE2Console() { +} + +} // End of namespace CGE diff --git a/engines/cge2/console.h b/engines/cge2/console.h new file mode 100644 index 0000000000..15956bf728 --- /dev/null +++ b/engines/cge2/console.h @@ -0,0 +1,40 @@ +/* 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 CGE2_CONSOLE_H +#define CGE2_CONSOLE_H + +#include "gui/debugger.h" + +namespace CGE2 { + +class CGE2Engine; + +class CGE2Console : public GUI::Debugger { +public: + CGE2Console(CGE2Engine *vm); + virtual ~CGE2Console(); +}; + +} // End of namespace CGE + +#endif // CGE2_CONSOLE_H diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp new file mode 100644 index 0000000000..605a3fe377 --- /dev/null +++ b/engines/cge2/detection.cpp @@ -0,0 +1,245 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge2/cge2.h" +#include "engines/advancedDetector.h" +#include "common/translation.h" +#include "graphics/surface.h" + +namespace CGE2 { + +#define GAMEOPTION_COLOR_BLIND_DEFAULT_OFF GUIO_GAMEOPTIONS1 + +static const PlainGameDescriptor CGE2Games[] = { + { "sfinx", "Sfinx" }, + { 0, 0 } +}; + +static const ADGameDescription gameDescriptions[] = { + { + "sfinx", "Freeware", + { + { "vol.cat", 0, "21197b287d397c53261b6616bf0dd880", 129024 }, + { "vol.dat", 0, "de14291869a8eb7c2732ab783c7542ef", 34180844 }, + AD_LISTEND + }, + Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) + }, + + { + "sfinx", "Freeware v1.0", + { + {"vol.cat", 0, "aa402aed24a72c53a4d1211c456b79dd", 129024}, + {"vol.dat", 0, "5966ac26d91d664714349669f9dd09b5", 34180164}, + AD_LISTEND + }, + Common::PL_POL, Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF) + }, + + AD_TABLE_END_MARKER +}; + +static const ADExtraGuiOptionsMap optionsList[] = { + { + GAMEOPTION_COLOR_BLIND_DEFAULT_OFF, + { + _s("Color Blind Mode"), + _s("Enable Color Blind Mode by default"), + "enable_color_blind", + false + } + }, + + AD_EXTRA_GUI_OPTIONS_TERMINATOR +}; + +class CGE2MetaEngine : public AdvancedMetaEngine { +public: + CGE2MetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), CGE2Games, optionsList) { + _singleid = "sfinx"; + } + + virtual const char *getName() const { + return "CGE2"; + } + + virtual const char *getOriginalCopyright() const { + return "Sfinx (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon"; + } + + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + virtual bool hasFeature(MetaEngineFeature f) const; + 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; + + const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const; +}; + +bool CGE2MetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + if (desc) + *engine = new CGE2::CGE2Engine(syst, desc); + + return desc != 0; +} + +bool CGE2MetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSavesSupportCreationDate) || + (f == kSupportsListSaves) || + (f == kSupportsLoadingDuringStartup); +} + +const ADGameDescription *CGE2MetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { + static ADGameDescription desc; + + for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { + if (file->isDirectory()) + continue; + + if (file->getName().equalsIgnoreCase("lang.eng")) { + Common::File dataFile; + if (!dataFile.open(*file)) + continue; + + desc.gameid = "sfinx"; + desc.extra = "Translation Alpha v0.3"; + desc.language = Common::EN_ANY; + desc.platform = Common::kPlatformDOS; + desc.flags = ADGF_NO_FLAGS; + desc.guioptions = GUIO1(GAMEOPTION_COLOR_BLIND_DEFAULT_OFF); + + return (const ADGameDescription *)&desc; + } + } + return 0; +} + +int CGE2MetaEngine::getMaximumSaveSlot() const { + return 99; +} + +SaveStateList CGE2MetaEngine::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; + 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 + int slotNum = atoi(filename->c_str() + filename->size() - 3); + + if (slotNum >= 0 && slotNum <= 99) { + + Common::InSaveFile *file = saveFileMan->openForLoading(*filename); + if (file) { + CGE2::SavegameHeader header; + + // Check to see if it's a ScummVM savegame or not + char buffer[kSavegameStrSize + 1]; + file->read(buffer, kSavegameStrSize + 1); + + if (!strncmp(buffer, kSavegameStr, kSavegameStrSize + 1)) { + // Valid savegame + if (CGE2::CGE2Engine::readSavegameHeader(file, header)) { + saveList.push_back(SaveStateDescriptor(slotNum, header.saveName)); + if (header.thumbnail) { + header.thumbnail->free(); + delete header.thumbnail; + } + } + } else { + // Must be an original format savegame + saveList.push_back(SaveStateDescriptor(slotNum, "Unknown")); + } + + delete file; + } + } + } + + return saveList; +} + +SaveStateDescriptor CGE2MetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.%03d", target, slot); + Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName); + + if (f) { + CGE2::SavegameHeader header; + + // Check to see if it's a ScummVM savegame or not + char buffer[kSavegameStrSize + 1]; + f->read(buffer, kSavegameStrSize + 1); + + bool hasHeader = !strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) && + CGE2::CGE2Engine::readSavegameHeader(f, header); + delete f; + + if (!hasHeader) { + // Original savegame perhaps? + SaveStateDescriptor desc(slot, "Unknown"); + return desc; + } else { + // Create the return descriptor + SaveStateDescriptor desc(slot, header.saveName); + desc.setThumbnail(header.thumbnail); + desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay); + desc.setSaveTime(header.saveHour, header.saveMinutes); + + // Slot 0 is used for the 'automatic save on exit' save in Soltys, thus + // we prevent it from being deleted or overwritten by accident. + desc.setDeletableFlag(slot != 0); + desc.setWriteProtectedFlag(slot == 0); + + return desc; + } + } + + return SaveStateDescriptor(); +} + +void CGE2MetaEngine::removeSaveState(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.%03d", target, slot); + g_system->getSavefileManager()->removeSavefile(fileName); +} + +} // End of namespace CGE2 + +#if PLUGIN_ENABLED_DYNAMIC(CGE2) + REGISTER_PLUGIN_DYNAMIC(CGE2, PLUGIN_TYPE_ENGINE, CGE2::CGE2MetaEngine); +#else + REGISTER_PLUGIN_STATIC(CGE2, PLUGIN_TYPE_ENGINE, CGE2::CGE2MetaEngine); +#endif diff --git a/engines/cge2/events.cpp b/engines/cge2/events.cpp new file mode 100644 index 0000000000..ed1ec66bb1 --- /dev/null +++ b/engines/cge2/events.cpp @@ -0,0 +1,293 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "gui/saveload.h" +#include "gui/about.h" +#include "gui/message.h" +#include "common/config-manager.h" +#include "common/events.h" +#include "engines/advancedDetector.h" +#include "cge2/events.h" +#include "cge2/text.h" +#include "cge2/cge2_main.h" + +namespace CGE2 { + +/*----------------- KEYBOARD interface -----------------*/ + +Keyboard::Keyboard(CGE2Engine *vm) : _client(nullptr), _vm(vm) { +} + +Keyboard::~Keyboard() { +} + +Sprite *Keyboard::setClient(Sprite *spr) { + SWAP(_client, spr); + return spr; +} + +bool Keyboard::getKey(Common::Event &event) { + Common::KeyCode keycode = event.kbd.keycode; + + switch (keycode) { + case Common::KEYCODE_F1: + if (event.type == Common::EVENT_KEYUP) + return false; + // Display ScummVM version and translation strings + for (int i = 0; i < 3; i++) + _vm->_commandHandler->addCommand(kCmdInf, 1, kShowScummVMVersion + i, NULL); + return false; + case Common::KEYCODE_F5: + if (_vm->canSaveGameStateCurrently()) { + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save", true); + int16 savegameId = dialog->runModalWithCurrentTarget(); + Common::String savegameDescription = dialog->getResultString(); + delete dialog; + + if (savegameId != -1) + _vm->saveGameState(savegameId, savegameDescription); + } + return false; + case Common::KEYCODE_F7: + if (_vm->canLoadGameStateCurrently()) { + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false); + int16 savegameId = dialog->runModalWithCurrentTarget(); + delete dialog; + + if (savegameId != -1) + _vm->loadGameState(savegameId); + } + return false; + case Common::KEYCODE_d: + if (event.kbd.flags & Common::KBD_CTRL) { + // Start the debugger + _vm->getDebugger()->attach(); + _vm->getDebugger()->onFrame(); + return false; + } + break; + case Common::KEYCODE_x: + if (event.kbd.flags & Common::KBD_ALT) { + _vm->quit(); + return false; + } + break; + case Common::KEYCODE_F10: + if (_vm->_commandHandler->idle()) + _vm->switchScene(-1); // Exits the game. + return false; + default: + break; + } + + return true; +} + +void Keyboard::newKeyboard(Common::Event &event) { + if (!getKey(event)) + return; + + if ((event.type == Common::EVENT_KEYDOWN) && _client) { + CGE2Event &evt = _vm->_eventManager->getNextEvent(); + evt._x = 0; + evt._y = 0; + evt._keyCode = event.kbd.keycode; // Keycode + evt._mask = kEventKeyb; // Event mask + evt._spritePtr = _client; // Sprite pointer + } +} + +/*----------------- MOUSE interface -----------------*/ + +Mouse::Mouse(CGE2Engine *vm) : Sprite(vm), _busy(nullptr), _hold(nullptr), _hx(0), _point(vm), _vm(vm) { + _hold = nullptr; + _hx = 0; + _hy = 0; + _exist = true; + _buttons = 0; + _busy = nullptr; + _active = false; + _flags._kill = false; + + setSeq(_stdSeq8); + + BitmapPtr MC = new Bitmap[2]; + MC[0] = Bitmap(_vm, "MOUSE"); + MC[1] = Bitmap(_vm, "DUMMY"); + setShapeList(MC, 2); + + step(1); + on(); + off(); +} + +Mouse::~Mouse() { + off(); +} + +void Mouse::on() { + if (_seqPtr && _exist) { + _active = true; + step(0); + if (_busy) + _busy->step(0); + } +} + +void Mouse::off() { + if (_seqPtr == 0) { + if (_exist) + _active = false; + + step(1); + if (_busy) + _busy->step(1); + } +} + +void Mouse::newMouse(Common::Event &event) { + if (!_active) + return; + + CGE2Event &evt = _vm->_eventManager->getNextEvent(); + evt._x = event.mouse.x; + evt._y = event.mouse.y; + evt._keyCode = Common::KEYCODE_INVALID; + evt._spritePtr = _vm->spriteAt(V2D(_vm, evt._x, evt._y)); + + switch (event.type) { + case Common::EVENT_MOUSEMOVE: + evt._mask = kMouseRoll; + break; + case Common::EVENT_LBUTTONDOWN: + evt._mask = kMouseLeftDown; + _buttons |= 1; + break; + case Common::EVENT_LBUTTONUP: + evt._mask = kMouseLeftUp; + _buttons &= ~1; + break; + case Common::EVENT_RBUTTONDOWN: + evt._mask = kMouseRightDown; + _buttons |= 2; + break; + case Common::EVENT_RBUTTONUP: + evt._mask = kMouseRightUp; + _buttons &= ~2; + break; + default: + break; + } +} + +/*----------------- EventManager interface -----------------*/ + +EventManager::EventManager(CGE2Engine *vm) : _vm(vm) { + _eventQueueHead = 0; + _eventQueueTail = 0; + memset(&_eventQueue, 0, kEventMax * sizeof(CGE2Event)); + memset(&_event, 0, sizeof(Common::Event)); +} + +void EventManager::poll() { + while (g_system->getEventManager()->pollEvent(_event)) { + _event.mouse.y = kWorldHeight - _event.mouse.y; + switch (_event.type) { + case Common::EVENT_KEYDOWN: + case Common::EVENT_KEYUP: + // Handle keyboard events + _vm->_keyboard->newKeyboard(_event); + handleEvents(); + break; + case Common::EVENT_MOUSEMOVE: + case Common::EVENT_LBUTTONDOWN: + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: + // Handle mouse events + _vm->_mouse->newMouse(_event); + handleEvents(); + break; + default: + break; + } + } +} + +void EventManager::handleEvents() { + while (_eventQueueTail != _eventQueueHead) { + CGE2Event e = _eventQueue[_eventQueueTail]; + _vm->_mouse->_point = V2D(_vm, e._x, e._y); + if (e._mask) { + if (e._mask & kMouseMask) { + e._spritePtr = _vm->spriteAt(_vm->_mouse->_point); + e._x += (_vm->_mouse->_siz.x >> 1); + e._y -= _vm->_mouse->_siz.y; + if (_vm->_mouse->_hold && (e._spritePtr != _vm->_mouse->_hold)) { + _vm->_mouse->_hold->touch(e._mask | kEventAttn, + V2D(_vm, e._x - _vm->_mouse->_hold->_pos2D.x, e._y - _vm->_mouse->_hold->_pos2D.y), e._keyCode); + } + // update mouse cursor position + if (e._mask & kMouseRoll) + _vm->_mouse->gotoxyz(V2D(_vm, e._x, e._y)); + } + + // activate current touched SPRITE + if (e._spritePtr) { + if (e._mask & kEventKeyb) + e._spritePtr->touch(e._mask, _vm->_mouse->_point, e._keyCode); + else + e._spritePtr->touch(e._mask, _vm->_mouse->_point - e._spritePtr->_pos2D, e._keyCode); + } else if (_vm->_sys) + _vm->_sys->touch(e._mask, _vm->_mouse->_point, e._keyCode); + + // discard Text if button released + if (e._mask & (kMouseLeftUp | kMouseRightUp)) + _vm->killText(); + } + _eventQueueTail = (_eventQueueTail + 1) % kEventMax; + } +} + +void EventManager::clearEvent(Sprite *spr) { + if (spr) { + for (uint16 e = _eventQueueTail; e != _eventQueueHead; e = (e + 1) % kEventMax) { + if (_eventQueue[e]._spritePtr == spr) + _eventQueue[e]._mask = 0; + } + } else + _eventQueueTail = _eventQueueHead; +} + +CGE2Event &EventManager::getNextEvent() { + CGE2Event &evt = _eventQueue[_eventQueueHead]; + _eventQueueHead = (_eventQueueHead + 1) % kEventMax; + + return evt; +} + +} // End of namespace CGE2 diff --git a/engines/cge2/events.h b/engines/cge2/events.h new file mode 100644 index 0000000000..d1aaca2ded --- /dev/null +++ b/engines/cge2/events.h @@ -0,0 +1,116 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_EVENTS_H +#define CGE2_EVENTS_H + +#include "common/events.h" +#include "cge2/talk.h" +#include "cge2/vga13h.h" + +namespace CGE2 { + +/*----------------- KEYBOARD interface -----------------*/ + +#define kEventMax 256 + +enum EventMask { + kMouseRoll = 1 << 0, + kMouseLeftDown = 1 << 1, + kMouseLeftUp = 1 << 2, + kMouseRightDown = 1 << 3, + kMouseRightUp = 1 << 4, + kEventAttn = 1 << 5, + kMouseMask = (kMouseRoll | kMouseLeftDown | kMouseLeftUp | kMouseRightDown | kMouseRightUp), + kEventKeyb = 1 << 7 +}; + +class Keyboard { +private: + bool getKey(Common::Event &event); + CGE2Engine *_vm; +public: + Sprite *_client; + + void newKeyboard(Common::Event &event); + Sprite *setClient(Sprite *spr); + + Keyboard(CGE2Engine *vm); + ~Keyboard(); +}; + +/*----------------- MOUSE interface -----------------*/ + +struct CGE2Event { + uint16 _mask; + uint16 _x; + uint16 _y; + Common::KeyCode _keyCode; + Sprite *_spritePtr; +}; + +class Mouse : public Sprite { +public: + V2D _point; + Sprite *_hold; + bool _active; + int _hx; + int _hy; + bool _exist; + int _buttons; + Sprite *_busy; + Mouse(CGE2Engine *vm); + ~Mouse(); + void on(); + void off(); + void newMouse(Common::Event &event); +private: + CGE2Engine *_vm; +}; + +/*----------------- EventManager interface -----------------*/ + +class EventManager { +private: + CGE2Engine *_vm; + Common::Event _event; + CGE2Event _eventQueue[kEventMax]; + uint16 _eventQueueHead; + uint16 _eventQueueTail; + + void handleEvents(); +public: + EventManager(CGE2Engine *vm); + void poll(); + void clearEvent(Sprite *spr); + + CGE2Event &getNextEvent(); +}; + +} // End of namespace CGE + +#endif // #define CGE2_EVENTS_H diff --git a/engines/cge2/fileio.cpp b/engines/cge2/fileio.cpp new file mode 100644 index 0000000000..6f8009716b --- /dev/null +++ b/engines/cge2/fileio.cpp @@ -0,0 +1,272 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "common/system.h" +#include "common/str.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/memstream.h" +#include "cge2/cge2.h" +#include "cge2/fileio.h" + +namespace CGE2 { + +/*----------------------------------------------------------------------- + * BtPage + *-----------------------------------------------------------------------*/ +void BtPage::readBTree(Common::ReadStream &s) { + _header._count = s.readUint16LE(); + _header._down = s.readUint16LE(); + + if (_header._down == kBtValNone) { + // Leaf list + for (int i = 0; i < kBtLeafCount; ++i) { + s.read(_leaf[i]._key, kBtKeySize); + _leaf[i]._pos = s.readUint32LE(); + _leaf[i]._size = s.readUint32LE(); + } + } else { + // Root index + for (int i = 0; i < kBtInnerCount; ++i) { + s.read(_inner[i]._key, kBtKeySize); + _inner[i]._down = s.readUint16LE(); + } + } +} + +/*----------------------------------------------------------------------- + * ResourceManager + *-----------------------------------------------------------------------*/ +ResourceManager::ResourceManager() { + _datFile = new Common::File(); + _datFile->open(kDatName); + + _catFile = new Common::File(); + _catFile->open(kCatName); + + if (!_datFile->isOpen() || !_catFile->isOpen()) + error("Unable to open data files"); + + for (int i = 0; i < kBtLevel; i++) { + _buff[i]._page = new BtPage; + _buff[i]._pageNo = kBtValNone; + _buff[i]._index = -1; + assert(_buff[i]._page != nullptr); + } +} + +ResourceManager::~ResourceManager() { + _datFile->close(); + delete _datFile; + + _catFile->close(); + delete _catFile; + + for (int i = 0; i < kBtLevel; i++) + delete _buff[i]._page; +} + +void ResourceManager::xCrypt(byte *buf, uint16 length) { + byte *b = buf; + + for (uint16 i = 0; i < length; i++) + *b++ ^= kCryptSeed; +} + +bool ResourceManager::seek(int32 offs, int whence) { + return _datFile->seek(offs, whence); +} + +uint16 ResourceManager::read(byte *buf, uint16 length) { + if (!_datFile->isOpen()) + return 0; + + uint16 bytesRead = _datFile->read(buf, length); + if (!bytesRead) + error("Read %s - %d bytes", _datFile->getName(), length); + xCrypt(buf, length); + return bytesRead; +} + +BtPage *ResourceManager::getPage(int level, uint16 pageId) { + if (_buff[level]._pageNo != pageId) { + int32 pos = pageId * kBtSize; + _buff[level]._pageNo = pageId; + assert(_catFile->size() > pos); + // In the original, there was a check verifying if the + // purpose was to write a new file. This should only be + // to create a new file, thus it was removed. + _catFile->seek(pageId * kBtSize, SEEK_SET); + + // Read in the page + byte buffer[kBtSize]; + int bytesRead = catRead(buffer, kBtSize); + + // Unpack it into the page structure + Common::MemoryReadStream stream(buffer, bytesRead, DisposeAfterUse::NO); + _buff[level]._page->readBTree(stream); + _buff[level]._index = -1; + } + return _buff[level]._page; +} + +BtKeypack *ResourceManager::find(const char *key) { + int lev = 0; + uint16 nxt = kBtValRoot; + while (!_catFile->eos()) { + BtPage *pg = getPage(lev, nxt); + // search + if (pg->_header._down != kBtValNone) { + int i; + for (i = 0; i < pg->_header._count; i++) { + // Does this work, or does it have to compare the entire buffer? + if (scumm_strnicmp((const char *)key, (const char*)pg->_inner[i]._key, kBtKeySize) < 0) + break; + } + nxt = (i) ? pg->_inner[i - 1]._down : pg->_header._down; + _buff[lev]._index = i - 1; + lev++; + } else { + int i; + for (i = 0; i < pg->_header._count - 1; i++) { + if (scumm_stricmp((const char *)key, (const char *)pg->_leaf[i]._key) <= 0) + break; + } + + // Hack to work around a mix between 24piram_ and 24pirami + if (!strcmp(key, "24piram_.SPR") && (scumm_stricmp((const char *)key, (const char *)pg->_leaf[i]._key) < 0)) + ++i; + // + + _buff[lev]._index = i; + return &pg->_leaf[i]; + } + } + return nullptr; +} + +bool ResourceManager::exist(const char *name) { + return scumm_stricmp(find(name)->_key, name) == 0; +} + +uint16 ResourceManager::catRead(byte *buf, uint16 length) { + if (!_catFile->isOpen()) + return 0; + + uint16 bytesRead = _catFile->read(buf, length); + if (!bytesRead) + error("Read %s - %d bytes", _catFile->getName(), length); + xCrypt(buf, length); + return bytesRead; +} + +/*----------------------------------------------------------------------- + * EncryptedStream + *-----------------------------------------------------------------------*/ +EncryptedStream::EncryptedStream(CGE2Engine *vm, const char *name) : _vm(vm), _lineCount(0) { + _error = false; + BtKeypack *kp = _vm->_resman->find(name); + if (scumm_stricmp(kp->_key, name) != 0) + _error = true; + + _vm->_resman->seek(kp->_pos); + byte *dataBuffer; + int bufSize; + + if ((strlen(name) > 4) && (scumm_stricmp(name + strlen(name) - 4, ".SPR") == 0)) { + // SPR files have some inconsistencies. Some have extra 0x1A at the end, some others + // do not have a carriage return at the end of the last line + // Therefore, we remove this ending 0x1A and add extra new lines. + // This fixes bug #3537527 + dataBuffer = (byte *)malloc(kp->_size + 2); + _vm->_resman->read(dataBuffer, kp->_size); + if (dataBuffer[kp->_size - 1] == 0x1A) + dataBuffer[kp->_size - 1] = '\n'; + dataBuffer[kp->_size] = '\n'; + dataBuffer[kp->_size + 1] = '\n'; + bufSize = kp->_size + 2; + } else { + dataBuffer = (byte *)malloc(kp->_size); + _vm->_resman->read(dataBuffer, kp->_size); + bufSize = kp->_size; + } + + _readStream = new Common::MemoryReadStream(dataBuffer, bufSize, DisposeAfterUse::YES); +} + +uint32 EncryptedStream::read(byte *dataPtr, uint32 dataSize) { + return _readStream->read(dataPtr, dataSize); +} + +int16 EncryptedStream::readSint16LE() { + return _readStream->readSint16LE(); +} + +uint32 EncryptedStream::readUint32LE() { + return _readStream->readUint32LE(); +} + +bool EncryptedStream::err() { + return (_error || _readStream->err()); +} + +bool EncryptedStream::eos() { + return _readStream->eos(); +} + +bool EncryptedStream::seek(int32 offset) { + return _readStream->seek(offset); +} + +Common::String EncryptedStream::readLine() { + _lineCount++; + Common::String line = _readStream->readLine(); + if (!line.empty() && (line[0] == ';' || line[0] == '.' || line[0] == '*')) + line.clear(); // Returns an empty string, if the line is invalid. + return line; +} + +int32 EncryptedStream::size() { + return _readStream->size(); +} + +int32 EncryptedStream::pos() { + return _readStream->pos(); +} + +EncryptedStream::~EncryptedStream() { + delete _readStream; +} + +const char *EncryptedStream::kIdTab[] = { + "[near]", "[mtake]", "[ftake]", "[phase]", "[seq]", + "Name", "Type", "Front", "East", + "Portable", "Transparent", + nullptr +}; + +} // End of namespace CGE2 diff --git a/engines/cge2/fileio.h b/engines/cge2/fileio.h new file mode 100644 index 0000000000..e236c73b49 --- /dev/null +++ b/engines/cge2/fileio.h @@ -0,0 +1,133 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_FILEIO_H +#define CGE2_FILEIO_H + +#include "common/file.h" + +namespace CGE2 { + +class CGE2Engine; + +#define kBtSize 2048 +#define kBtKeySize 13 +#define kBtLevel 2 +#define kBtInnerCount ((kBtSize - 4 /*sizeof(Header) */) / (kBtKeySize + 2 /*sizeof(Inner) */)) +#define kBtLeafCount ((kBtSize - 4 /*sizeof(Header) */) / (kBtKeySize + 4 + 4 /*sizeof(BtKeypack) */)) +#define kBtValNone 0xFFFF +#define kBtValRoot 0 +#define kCatName "VOL.CAT" +#define kDatName "VOL.DAT" +#define kCryptSeed 0xA5 + +enum ID { + kIdNear, kIdMTake, kIdFTake, kIdPhase, kIdSeq, + kIdName, kIdType, kIdFront, kIdEast, + kIdPortable, kIdTransparent, + kIdNone = -1 +}; + +struct BtKeypack { + char _key[kBtKeySize]; + uint32 _pos; + uint32 _size; +}; + +struct Inner { + uint8 _key[kBtKeySize]; + uint16 _down; +}; + +struct Header { + uint16 _count; + uint16 _down; +}; + +struct BtPage { + Header _header; + union { + // dummy filler to make proper size of union + uint8 _data[kBtSize - 4]; /* 4 is the size of struct Header */ + // inner version of data: key + word-sized page link + Inner _inner[kBtInnerCount]; + // leaf version of data: key + all user data + BtKeypack _leaf[kBtLeafCount]; + }; + + void readBTree(Common::ReadStream &s); +}; + +class ResourceManager { +private: + struct { + BtPage *_page; + uint16 _pageNo; + int _index; + } _buff[kBtLevel]; + + BtPage *getPage(int level, uint16 pageId); + uint16 catRead(byte *buf, uint16 length); + Common::File *_catFile; + Common::File *_datFile; + void xCrypt(byte *buf, uint16 length); +public: + ResourceManager(); + ~ResourceManager(); + uint16 read(byte *buf, uint16 length); + bool seek(int32 offs, int whence = SEEK_SET); + + BtKeypack *find(const char *key); + bool exist(const char *name); +}; + +class EncryptedStream { +private: + CGE2Engine *_vm; + Common::SeekableReadStream *_readStream; + int _lineCount; + bool _error; +public: + EncryptedStream(CGE2Engine *vm, const char *name); + ~EncryptedStream(); + bool err(); + bool eos(); + bool seek(int32 offset); + int32 pos(); + int32 size(); + uint32 read(byte *dataPtr, uint32 dataSize); + int16 readSint16LE(); + uint32 readUint32LE(); + Common::String readLine(); + int getLineCount() { return _lineCount; } + + static const char *kIdTab[]; +}; + +} // End of namespace CGE2 + +#endif // CGE2_FILEIO_H diff --git a/engines/cge2/general.h b/engines/cge2/general.h new file mode 100644 index 0000000000..7213c2e24d --- /dev/null +++ b/engines/cge2/general.h @@ -0,0 +1,45 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_GENERAL_H +#define CGE2_GENERAL_H + +#include "common/file.h" + +namespace CGE2 { + +class CGE2Engine; + +struct Dac { + uint8 _r; + uint8 _g; + uint8 _b; +}; + +} // End of namespace CGE2 + +#endif // CGE2_GENERAL_H diff --git a/engines/cge2/hero.cpp b/engines/cge2/hero.cpp new file mode 100644 index 0000000000..86bd7ac953 --- /dev/null +++ b/engines/cge2/hero.cpp @@ -0,0 +1,620 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge2/hero.h" +#include "cge2/text.h" +#include "cge2/map.h" + +namespace CGE2 { + +Hero::Hero(CGE2Engine *vm) + : Sprite(vm), _contact(nullptr), _dir(kNoDir), + _curDim(0), _tracePtr(-1), _ignoreMap(false), _maxDist(0) { + + for (int i = 0; i < kDimMax; i++) { + _dim[i] = nullptr; + } +} + +Hero::~Hero() { + contract(); +} + +Sprite *Hero::expand() { + if (_ext) + return this; + + char fname[kMaxPath]; + _vm->mergeExt(fname, _file, kSprExt); + + if (_ext != nullptr) + delete _ext; + + _ext = new SprExt(_vm); + + if (!*_file) + return this; + + for (int i = 0; i < kDimMax; i++) { + if (_dim[i] != nullptr) { + delete[] _dim[i]; + _dim[i] = nullptr; + } + } + for (int i = 0; i < kDimMax; i++) { + _dim[i] = new Bitmap[_shpCnt]; + for (int j = 0; j < _shpCnt; j++) + _dim[i][j].setVM(_vm); + } + + int cnt[kActions]; + + for (int i = 0; i < kActions; i++) + cnt[i] = 0; + + for (int i = 0; i < kActions; i++) { + byte n = _actionCtrl[i]._cnt; + if (n) + _ext->_actions[i] = new CommandHandler::Command[n]; + else + _ext->_actions[i] = nullptr; + } + + Seq *curSeq = nullptr; + if (_seqCnt) + curSeq = new Seq[_seqCnt]; + + if (_vm->_resman->exist(fname)) { // sprite description file exist + EncryptedStream sprf(_vm, fname); + if (sprf.err()) + error("Bad SPR [%s]", fname); + + ID section = kIdPhase; + ID id; + Common::String line; + char tmpStr[kLineMax + 1]; + int shpcnt = 0; + int seqcnt = 0; + int maxnow = 0; + int maxnxt = 0; + + for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()) { + if (line.empty()) + continue; + Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr)); + + char *p = _vm->token(tmpStr); + + id = _vm->ident(p); + switch (id) { + case kIdNear: + case kIdMTake: + case kIdFTake: + case kIdPhase: + case kIdSeq: + section = id; + break; + case kIdName: + Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr)); + for (p = tmpStr; *p != '='; p++); // We search for the = + setName(_vm->tail(p)); + break; + default: + if (id >= kIdNear) + break; + Seq *s; + switch (section) { + case kIdNear: + case kIdMTake: + case kIdFTake: + id = (ID)_vm->_commandHandler->getComId(p); + if (_actionCtrl[section]._cnt) { + CommandHandler::Command *c = &_ext->_actions[section][cnt[section]++]; + c->_commandType = CommandType(id); + c->_ref = _vm->number(nullptr); + c->_val = _vm->number(nullptr); + c->_spritePtr = nullptr; + } + break; + case kIdSeq: + s = &curSeq[seqcnt++]; + s->_now = atoi(p); + if (s->_now > maxnow) + maxnow = s->_now; + s->_next = _vm->number(nullptr); + 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 = _vm->number(nullptr); + s->_dy = _vm->number(nullptr); + s->_dz = _vm->number(nullptr); + s->_dly = _vm->number(nullptr); + break; + case kIdPhase: + for (int i = 0; i < kDimMax; i++) { + char *q = p; + q[1] = '0' + i; + Bitmap b(_vm, q); + _dim[i][shpcnt] = b; + if (!shpcnt) + _hig[i] = b._h; + } + ++shpcnt; + break; + default: + break; + } + } + } + + if (curSeq) { + if (maxnow >= shpcnt) + error("Bad PHASE in SEQ %s", fname); + if (maxnxt >= seqcnt) + error("Bad JUMP in SEQ %s", fname); + setSeq(curSeq); + } else + setSeq(_stdSeq8); + + setShapeList(_dim[0], shpcnt); + } + + char *tempStr = _vm->_text->getText(_ref + 100); + char *text = new char[strlen(tempStr) + 1]; + strcpy(text, tempStr); + _reachStart = atoi(_vm->token(text)); + _reachCycle = atoi(_vm->token(nullptr)); + _sayStart = atoi(_vm->token(nullptr)); + _funStart = atoi(_vm->token(nullptr)); + _funDel = _funDel0 = (72 / _ext->_seq[0]._dly) * atoi(_vm->token(nullptr)); + delete[] text; + + int i = stepSize() / 2; + _maxDist = sqrt(double(i * i * 2)); + setCurrent(); + + return this; +} + +Sprite *Hero::contract() { + for (int i = 0; i < kDimMax; i++) { + if (_dim[i] != nullptr) { + delete[] _dim[i]; + if (_ext->_shpList == _dim[i]) + _ext->_shpList = nullptr; + _dim[i] = nullptr; + } + } + Sprite::contract(); + return this; +} + +void Hero::setCurrent() { + FXP m = _vm->_eye->_z / (_pos3D._z - _vm->_eye->_z); + FXP tmp = m * _siz.y; + int h = -(tmp.trunc()); + + int i = 0; + for (; i < kDimMax - 1; i++) { + if (h >= (_hig[i] + _hig[i + 1]) / 2) + break; + } + + _ext->_shpList = _dim[_curDim = i]; +} + +void Hero::hStep() { + if (!_ignoreMap && _ext) { + Seq *seq = _ext->_seq; + int ptr = seq[_seqPtr]._next; + seq += ptr; + if (seq->_dx | seq->_dz) { + V2D p0(_vm, _pos3D._x.round(), _pos3D._z.round()); + V2D p1(_vm, p0.x + seq->_dx, p0.y + seq->_dz); + if (mapCross(p0, p1)) { + park(); + return; + } + } + } + step(); +} + +Sprite *Hero::setContact() { + Sprite *spr; + int md = _maxDist << 1; + for (spr = _vm->_vga->_showQ->first(); spr; spr = spr->_next) { + if (spr->_actionCtrl[kNear]._cnt && ((spr->_ref & 255) != 255) && (distance(spr) <= md)) { + if (spr == _contact) + return nullptr; + else + break; + } + } + return (_contact = spr); +} + +void Hero::tick() { + int z = _pos3D._z.trunc(); + //-- maybe not exactly wid/2, but wid/3 ? + int d = ((_siz.x / 2) * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z); + + if (_dir != kNoDir) { // just walking... + if (_flags._hold || _tracePtr < 0) + park(); + else { + Sprite *spr = setContact(); + if (spr) + _vm->feedSnail(spr, kNear, this); + } + } + //--------------------------------------------------------------- + if (_tracePtr >= 0) { + if (distance(_trace[_tracePtr]) <= _maxDist) + --_tracePtr; + + if (_tracePtr < 0) + park(); + else { + int stp = stepSize() / 2; + int dx = _trace[_tracePtr]._x.round() - _pos3D._x.round(); + int dz = _trace[_tracePtr]._z.round() - _pos3D._z.round(); + Dir dir = (dx > stp) ? kEE : ((-dx > stp) ? kWW : ((dz > stp) ? kNN : kSS)); + turn(dir); + } + } + + //--------------------------------------------------------------- + hStep(); + setCurrent(); + switch (_dir) { + case kSS: + if (_pos3D._z < stepSize() / 2) + park(); + break; + case kWW: + if (_pos2D.x <= d) + park(); + break; + case kNN: + if (_pos3D._z > kScrDepth) + park(); + break; + case kEE: + if (_pos2D.x >= kScrWidth - 1 - d) + park(); + break; + default: + break; + } + if (_flags._trim) + gotoxyz_(_pos2D); + + if (_pos3D._z.trunc() != z) + _flags._zmov = true; + + if (--_funDel == 0) + fun(); +} + +int Hero::distance(V3D pos) { + V3D di = _pos3D - pos; + int x = di._x.round(); + int z = di._z.round(); + int retval = (int)sqrt((double)x * x + z * z); + return retval; +} + +int Hero::distance(Sprite *spr) { + V3D pos = spr->_pos3D; + int mdx = (spr->_siz.x >> 1) + (_siz.x >> 1); + int dx = (_pos3D._x - spr->_pos3D._x).round(); + if (dx < 0) { + mdx = -mdx; + if (dx > mdx) + pos._x = _pos3D._x; + else + pos._x += mdx; + } else if (dx < mdx) + pos._x = _pos3D._x; + else + pos._x += mdx; + + return distance(pos); +} + +void Hero::turn(Dir d) { + Dir dir = (_dir == kNoDir) ? kSS : _dir; + if (d != _dir) { + step((d == dir) ? 57 : (8 + 4 * dir + d)); + _dir = d; + } + resetFun(); +} + +void Hero::park() { + if (_dir != kNoDir) { + step(8 + 5 * _dir); + _dir = kNoDir; + _trace[0] = _pos3D; + _tracePtr = -1; + setCurrent(); + _flags._zmov = true; + } + _ignoreMap = false; + if (_time == 0) + ++_time; +} + +bool Hero::lower(Sprite * spr) { + return (spr->_pos3D._y + (spr->_siz.y >> 2) < 10); +} + +void Hero::reach(int mode) { + Sprite *spr = nullptr; + if (mode >= 4) { + spr = _vm->_vga->_showQ->locate(mode); + if (spr) { + mode = !spr->_flags._east; // 0-1 + if (lower(spr)) // 2-3 + mode += 2; + } + } + // note: insert SNAIL commands in reverse order + _vm->_commandHandler->insertCommand(kCmdPause, -1, 24, nullptr); + _vm->_commandHandler->insertCommand(kCmdSeq, -1, _reachStart + _reachCycle * mode, this); + if (spr) { + _vm->_commandHandler->insertCommand(kCmdWait, -1, -1, this); + _vm->_commandHandler->insertCommand(kCmdWalk, -1, spr->_ref, this); + } + // sequence is not finished, + // now it is just at sprite appear (disappear) point + resetFun(); +} + +void Hero::fun() { + if (_vm->_commandHandler->idle()) { + park(); + _vm->_commandHandler->addCommand(kCmdWait, -1, -1, this); + _vm->_commandHandler->addCommand(kCmdSeq, -1, _funStart, this); + } + _funDel = _funDel0 >> 2; +} + +int Hero::len(V2D v) { + return sqrt(double(v.x * v.x + v.y * v.y)); +} + +bool Hero::findWay(){ + V2D p0(_vm, _pos3D._x.round(), _pos3D._z.round()); + V2D p1(_vm, _trace[_tracePtr]._x.round(), _trace[_tracePtr]._z.round()); + V2D ph(_vm, p1.x, p0.y); + V2D pv(_vm, p0.x, p1.y); + bool pvOk = (!mapCross(p0, pv) && !mapCross(pv, p1)); + bool phOk = (!mapCross(p0, ph) && !mapCross(ph, p1)); + int md = (_maxDist >> 1); + if (pvOk && (len(ph - p0) <= md || len(p1 - ph) <= md)) + return true; + + if (phOk && (len(pv - p0) <= md || len(p1 - pv) <= md)) + return true; + + if (pvOk) { + _trace[++_tracePtr] = V3D(pv.x, 0, pv.y); + return true; + } + + if (phOk) { + _trace[++_tracePtr] = V3D(ph.x, 0, ph.y); + return true; + } + + return false; +} + +int Hero::snap(int p, int q, int grid) { + int d = abs(q - p) % grid; + if (d > (grid >> 1)) + d -= grid; + return (q >= p) ? (q - d) : (q + d); +} + +void Hero::walkTo(V3D pos) { + if (distance(pos) <= _maxDist) + return; + + int stp = stepSize(); + pos._x = snap(_pos3D._x.round(), pos._x.round(), stp); + pos._y = 0; + pos._z = snap(_pos3D._z.round(), pos._z.round(), stp); + + V2D p0(_vm, _pos3D._x.round(), _pos3D._z.round()); + V2D p1(_vm, pos._x.round(), pos._z.round()); + resetFun(); + int cnt = mapCross(p0, p1); + if ((cnt & 1) == 0) { // even == way exists + _trace[_tracePtr = 0] = pos; + if (!findWay()) { + int i; + ++_tracePtr; + for (i = stp; i < kMaxTry; i += stp) { + _trace[_tracePtr] = pos + V3D(i, 0, 0); + if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay()) + break; + + _trace[_tracePtr] = pos + V3D(-i, 0, 0); + if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay()) + break; + + _trace[_tracePtr] = pos + V3D(0, 0, i); + if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay()) + break; + + _trace[_tracePtr] = pos + V3D(0, 0, -i); + if (!mapCross(_trace[_tracePtr - 1], _trace[_tracePtr]) && findWay()) + break; + } + if (i >= kMaxTry) + _trace[_tracePtr] = V3D(_pos3D._x, 0, pos._z); // not found + } + } +} + +void Hero::walkTo(Sprite *spr) { + int mdx = _siz.x >> 1; + int stp = (stepSize() + 1) / 2; + if (!spr->_flags._east) + mdx = -mdx; + walkTo(spr->_pos3D + V3D(mdx, 0, (!spr->_flags._frnt || spr->_pos3D._z < 8) ? stp : -stp)); +} + +V3D Hero::screenToGround(V2D pos) { + FXP z = _vm->_eye->_z + (_vm->_eye->_y * _vm->_eye->_z) / (FXP(pos.y) - _vm->_eye->_y); + FXP x = _vm->_eye->_x - ((FXP(pos.x) - _vm->_eye->_x) * (z - _vm->_eye->_z)) / _vm->_eye->_z; + return V3D(x.round(), 0, z.round()); +} + +int Hero::cross(const V2D &a, const V2D &b) { + int x = _pos3D._x.trunc(); + int z = _pos3D._z.trunc(); + int r = ((_siz.x / 3) * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z); + return _vm->cross(a, b, V2D(_vm, x - r, z), V2D(_vm, x + r, z)) << 1; +} + +bool CGE2Engine::cross(const V2D &a, const V2D &b, const V2D &c, const V2D &d) { + if (contain(a, b, c) || contain(a, b, d) || contain(c, d, a) || contain(c, d, b)) + return true; + + return sgn(det(a, b, c)) != sgn(det(a, b, d)) && sgn(det(c, d, a)) != sgn(det(c, d, b)); +} + +bool CGE2Engine::contain(const V2D &a, const V2D &b, const V2D &p) { + if (det(a, b, p)) + return false; + + return ((long)(a.x - p.x) * (p.x - b.x) >= 0 && (long)(a.y - p.y) * (p.y - b.y) >= 0); +} + +long CGE2Engine::det(const V2D &a, const V2D &b, const V2D &c) { + return ((long)a.x * b.y + (long)b.x * c.y + (long)c.x * a.y) - ((long)c.x * b.y + (long)b.x * a.y + (long)a.x * c.y); +} + +int CGE2Engine::sgn(long n) { + return (n == 0) ? 0 : ((n > 0) ? 1 : -1); +} + +int Hero::mapCross(const V2D &a, const V2D &b) { + Hero *o = other(); + int n = (o->_scene == _scene) ? o->cross(a, b) : 0; + if (!_ignoreMap) + n += _vm->mapCross(a, b); + + return n; +} + +int Hero::mapCross(const V3D &a, const V3D &b) { + return mapCross(V2D(_vm, a._x.round(), a._z.round()), V2D(_vm, b._x.round(), b._z.round())); +} + +int CGE2Engine::mapCross(const V2D &a, const V2D &b) { + int cnt = 0; + V2D *n0 = nullptr; + V2D *p = nullptr; + for (int i = 0; i < _map->size(); i++) { + V2D *n = _map->getCoord(i); + if (p) { + if (cross(a, b, *n0, *n)) + ++cnt; + + if (*n == *p) + p = nullptr; + } else { + p = n; + } + n0 = n; + } + return cnt; +} + +void Hero::setScene(int c) { + Sprite::setScene(c); + resetFun(); +} + +void Hero::operator++() { + if (_curDim > 0) + _ext->_shpList = _dim[--_curDim]; +} + +void Hero::operator--() { + if (_curDim < kDimMax - 1) + _ext->_shpList = _dim[++_curDim]; +} + +bool Sprite::works(Sprite *spr) { + if (!spr || !spr->_ext) + return false; + + bool ok = false; + + Action a = _vm->_heroTab[_vm->_sex]->_ptr->action(); + CommandHandler::Command *ct = spr->_ext->_actions[a]; + if (ct) { + int i = spr->_actionCtrl[a]._ptr; + int n = spr->_actionCtrl[a]._cnt; + while (i < n && !ok) { + CommandHandler::Command *c = &ct[i++]; + if (c->_commandType != kCmdUse) + break; + ok = (c->_ref == _ref); + if (c->_val > 255) { + if (ok) { + int p = spr->labVal(a, c->_val >> 8); + if (p >= 0) + spr->_actionCtrl[a]._ptr = p; + else + ok = false; + } + } else { + if (c->_val && c->_val != _vm->_now) + ok = false; + break; + } + } + } + + return ok; +} + +} // End of namespace CGE2 diff --git a/engines/cge2/hero.h b/engines/cge2/hero.h new file mode 100644 index 0000000000..3b5329e12c --- /dev/null +++ b/engines/cge2/hero.h @@ -0,0 +1,114 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_HERO_H +#define CGE2_HERO_H + +#include "cge2/cge2.h" +#include "cge2/vga13h.h" +#include "cge2/snail.h" + +namespace CGE2 { + +#define kMaxTry 400 + +class Hero; + +struct HeroTab { + Hero *_ptr; + Sprite *_face; + Sprite *_pocket[kPocketMax + 1]; + int _downPocketId[kPocketMax + 1]; + int _pocPtr; + V2D *_posTab[kSceneMax]; + HeroTab(CGE2Engine *vm) { + _ptr = nullptr; + _face = nullptr; + for (int i = 0; i < kPocketMax + 1; i++) { + _pocket[i] = nullptr; + _downPocketId[i] = -1; + } + _pocPtr = 0; + for (int i = 0; i < kSceneMax; i++) + _posTab[i] = nullptr; + } + ~HeroTab() { + for (int i = 0; i < kSceneMax; i++) + delete _posTab[i]; + } +}; + +class Hero : public Sprite { + int _hig[kDimMax]; + Sprite *_contact; +public: + BitmapPtr _dim[kDimMax]; + V3D _trace[kWayMax]; + enum Dir { kNoDir = -1, kSS, kWW, kNN, kEE } _dir; + int _curDim; + int _tracePtr; + int _reachStart, _reachCycle, _sayStart, _funStart; + int _funDel0, _funDel; + int _maxDist; + bool _ignoreMap; + Hero(CGE2Engine *vm); + ~Hero(); + void tick(); + Sprite *expand(); + Sprite *contract(); + Sprite *setContact(); + int stepSize() { return _ext->_seq[7]._dx; } + int distance(V3D pos); + int distance(Sprite * spr); + void turn(Dir d); + void park(); + int len(V2D v); + bool findWay(); + static int snap(int p, int q, int grid); + void walkTo(V3D pos); + void walkTo(V2D pos) { walkTo(screenToGround(pos)); } + V3D screenToGround(V2D pos); + void walkTo(Sprite *spr); + void say() { step(_sayStart); } + void fun(); + void resetFun() { _funDel = _funDel0; } + void hStep(); + bool lower(Sprite * spr); + int cross(const V2D &a, const V2D &b); + int mapCross(const V2D &a, const V2D &b); + int mapCross(const V3D &a, const V3D &b); + Hero *other() { return _vm->_heroTab[!(_ref & 1)]->_ptr;} + Action action() { return (Action)(_ref % 10); } + void reach(int mode); + void setCurrent(); + void setScene(int c); + void operator++(); + void operator--(); +}; + +} // End of namespace CGE2 + +#endif // CGE2_HERO_H diff --git a/engines/cge2/inventory.cpp b/engines/cge2/inventory.cpp new file mode 100644 index 0000000000..e62aa01e99 --- /dev/null +++ b/engines/cge2/inventory.cpp @@ -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 Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge2/cge2.h" +#include "cge2/hero.h" + +namespace CGE2 { + +int CGE2Engine::findActivePocket(int ref) { + for (int i = 0; i < kPocketMax; i++) { + Sprite *spr = _heroTab[_sex]->_pocket[i]; + if (ref >= 0) { + if (spr && (spr->_ref == ref)) + return i; + } else if (!spr) + return i; + } + return -1; +} + +void CGE2Engine::selectPocket(int n) { + Sprite **p = _heroTab[_sex]->_pocket; + int &pp = _heroTab[_sex]->_pocPtr; + if ((n < 0) || (pp == n)) { + n = findActivePocket(-1); + if (n >= 0) + pp = n; + } else if (p[n]) + pp = n; +} + +void CGE2Engine::pocFul() { + Hero *h = _heroTab[_sex]->_ptr; + h->park(); + _commandHandler->addCommand(kCmdWait, -1, -1, h); + _commandHandler->addCommand(kCmdSound, -1, 2, h); + _commandHandler->addCommand(kCmdSay, -1, kPocketFull + _sex, h); +} + +void CGE2Engine::releasePocket(Sprite *spr) { + for (int i = 0; i < 2; i++) { + for (int j = 0; j < kPocketMax; j++) { + Sprite *&poc = _heroTab[i]->_pocket[j]; + if (poc == spr) { + spr->_flags._kept = false; + poc = nullptr; + return; + } + } + } +} + +int CGE2Engine::freePockets(int sx) { + int n = 0; + for (int i = 0; i < kPocketMax; i++){ + if (_heroTab[sx]->_pocket[i] == nullptr) + ++n; + } + return n; +} + +void CGE2Engine::openPocket() { + for (int i = 0; i < 2; i++) { + for (int j = 0; j < kPocketMax + 1; j++) { + int ref = (int)_heroTab[i]->_downPocketId[j]; + _heroTab[i]->_pocket[j] = (ref == -1) ? nullptr : _vga->_showQ->locate(ref); + } + } +} + +void CGE2Engine::closePocket() { + for (int i = 0; i < 2; i++) { + for (int j = 0; j < kPocketMax + 1; j++) { + Sprite *spr = _heroTab[i]->_pocket[j]; + _heroTab[i]->_downPocketId[j] = (spr) ? spr->_ref : -1; + } + } +} + +} // End of namespace CGE2 diff --git a/engines/cge2/map.cpp b/engines/cge2/map.cpp new file mode 100644 index 0000000000..1ed0ea7daf --- /dev/null +++ b/engines/cge2/map.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 Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge2/map.h" + +namespace CGE2 { + +Map::Map(CGE2Engine *vm) :_vm(vm) {} + +Map::~Map() { + _container.clear(); +} + +void Map::clear() { + _container.clear(); +} + +void Map::load(int scene) { + clear(); + + char fname[] = "%.2d.MAP\0"; + Common::String fileName = Common::String::format(fname, scene); + if (!_vm->_resman->exist(fileName.c_str())) + return; + + EncryptedStream file(_vm, fileName.c_str()); + + Common::String line; + for (line = file.readLine(); !file.eos(); line = file.readLine()) { + if (line.empty()) + continue; + + char tmpStr[kLineMax + 1]; + Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr)); + + char *currPos = tmpStr; + int x = nextNum(currPos); + while (true) { + int y = nextNum(nullptr); + _container.push_back(V2D(_vm, convertCoord(x), convertCoord(y))); + x = nextNum(nullptr); + if (x == -1) // We stop if there are no more data left to process in the current line. + break; + } + } +} + +int Map::nextNum(char *currPos) { + currPos = strtok(currPos, " (),"); + if (currPos == nullptr) + return -1; + int num = atoi(currPos); + return num; +} + +int Map::convertCoord(int coord) { + return (coord + (kMapGrid >> 1)) & kMapMask; +} + +int Map::size() { + return _container.size(); +} + +V2D *Map::getCoord(int idx) { + return &_container[idx]; +} + +} // End of namespace CGE2 diff --git a/engines/cge2/map.h b/engines/cge2/map.h new file mode 100644 index 0000000000..206479b929 --- /dev/null +++ b/engines/cge2/map.h @@ -0,0 +1,55 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_MAP_H +#define CGE2_MAP_H + +#include "cge2/vga13h.h" + +namespace CGE2 { + +#define kMapGrid 4 +#define kMapMask (~(kMapGrid - 1)) + +class Map { + CGE2Engine *_vm; + Common::Array<V2D> _container; + + int convertCoord(int coord); + int nextNum(char *currPos); +public: + Map(CGE2Engine *vm); + ~Map(); + void clear(); + void load(int scene); + int size(); + V2D *getCoord(int idx); +}; + +} // End of namespace CGE2 + +#endif // CGE2_MAP_H diff --git a/engines/cge2/module.mk b/engines/cge2/module.mk new file mode 100644 index 0000000000..4b321d88a8 --- /dev/null +++ b/engines/cge2/module.mk @@ -0,0 +1,30 @@ +MODULE := engines/cge2 + +MODULE_OBJS = \ + cge2.o \ + detection.o \ + fileio.o \ + vga13h.o \ + bitmap.o \ + sound.o \ + cge2_main.o \ + text.o \ + hero.o \ + snail.o \ + spare.o \ + talk.o \ + events.o \ + map.o \ + vmenu.o \ + saveload.o \ + toolbar.o \ + inventory.o \ + console.o + +# This module can be built as a plugin +ifeq ($(ENABLE_CGE2), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/cge2/saveload.cpp b/engines/cge2/saveload.cpp new file mode 100644 index 0000000000..fd60422dff --- /dev/null +++ b/engines/cge2/saveload.cpp @@ -0,0 +1,279 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "common/config-manager.h" +#include "common/savefile.h" +#include "common/system.h" +#include "graphics/thumbnail.h" +#include "graphics/surface.h" +#include "graphics/palette.h" +#include "graphics/scaler.h" +#include "cge2/events.h" +#include "cge2/snail.h" +#include "cge2/hero.h" +#include "cge2/text.h" +#include "cge2/sound.h" +#include "cge2/cge2_main.h" + +namespace CGE2 { + +#define kSavegameCheckSum (1997 + _now + _sex + kWorldHeight) +#define kBadSVG 99 + +bool CGE2Engine::canSaveGameStateCurrently() { + return (_gamePhase == kPhaseInGame) && _mouse->_active && + _commandHandler->idle() && (_soundStat._wait == nullptr); +} + +Common::Error CGE2Engine::saveGameState(int slot, const Common::String &desc) { + storeHeroPos(); + saveGame(slot, desc); + sceneUp(_now); + return Common::kNoError; +} + +void CGE2Engine::saveGame(int slotNumber, const Common::String &desc) { + // Set up the serializer + Common::String slotName = generateSaveName(slotNumber); + Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving(slotName); + + // Write out the ScummVM savegame header + SavegameHeader header; + header.saveName = desc; + header.version = kSavegameVersion; + writeSavegameHeader(saveFile, header); + + // Write out the data of the savegame + sceneDown(); + syncGame(nullptr, saveFile); + + // Finish writing out game data + saveFile->finalize(); + delete saveFile; +} + +bool CGE2Engine::canLoadGameStateCurrently() { + return (_gamePhase == kPhaseInGame) && _mouse->_active; +} + +Common::Error CGE2Engine::loadGameState(int slot) { + _commandHandler->clear(); + _commandHandlerTurbo->clear(); + sceneDown(); + if (!loadGame(slot)) + return Common::kReadingFailed; + sceneUp(_now); + initToolbar(); + return Common::kNoError; +} + +bool CGE2Engine::loadGame(int slotNumber) { + Common::MemoryReadStream *readStream; + + // Open up the savegame file + Common::String slotName = generateSaveName(slotNumber); + Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName); + + // Read the data into a data buffer + int size = saveFile->size(); + byte *dataBuffer = (byte *)malloc(size); + saveFile->read(dataBuffer, size); + readStream = new Common::MemoryReadStream(dataBuffer, size, DisposeAfterUse::YES); + delete saveFile; + + // Check to see if it's a ScummVM savegame or not + char buffer[kSavegameStrSize + 1]; + readStream->read(buffer, kSavegameStrSize + 1); + + if (strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) != 0) { + delete readStream; + return false; + } else { + SavegameHeader saveHeader; + + if (!readSavegameHeader(readStream, saveHeader)) { + delete readStream; + return false; + } + + // Delete the thumbnail + saveHeader.thumbnail->free(); + delete saveHeader.thumbnail; + } + + resetGame(); + + // Get in the savegame + syncGame(readStream, nullptr); + delete readStream; + + loadHeroes(); + + return true; +} + +void CGE2Engine::resetGame() { + _busyPtr = nullptr; + busy(false); + _spare->clear(); + _vga->_showQ->clear(); + loadScript("CGE.INI", true); + delete _infoLine; + _infoLine = new InfoLine(this, kInfoW); +} + +void CGE2Engine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header) { + // Write out a savegame header + out->write(kSavegameStr, kSavegameStrSize + 1); + + out->writeByte(kSavegameVersion); + + // Write savegame name + out->write(header.saveName.c_str(), header.saveName.size() + 1); + + // Get the active palette + uint8 thumbPalette[256 * 3]; + g_system->getPaletteManager()->grabPalette(thumbPalette, 0, 256); + + // Stop the heroes from moving and redraw them before taking the picture. + for (int i = 0; i < 2; i++) + _heroTab[i]->_ptr->park(); + _vga->show(); + + // Create a thumbnail and save it + Graphics::Surface *thumb = new Graphics::Surface(); + Graphics::Surface *s = _vga->_page[0]; + ::createThumbnail(thumb, (const byte *)s->getPixels(), kScrWidth, kScrHeight, thumbPalette); + Graphics::saveThumbnail(*out, *thumb); + thumb->free(); + delete thumb; + + // Write out the save date/time + TimeDate td; + g_system->getTimeAndDate(td); + out->writeSint16LE(td.tm_year + 1900); + out->writeSint16LE(td.tm_mon + 1); + out->writeSint16LE(td.tm_mday); + out->writeSint16LE(td.tm_hour); + out->writeSint16LE(td.tm_min); +} + +bool CGE2Engine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) { + header.thumbnail = nullptr; + + // Get the savegame version + header.version = in->readByte(); + if (header.version > kSavegameVersion) + return false; + + // Read in the string + header.saveName.clear(); + char ch; + while ((ch = (char)in->readByte()) != '\0') + header.saveName += ch; + + // Get the thumbnail + header.thumbnail = Graphics::loadThumbnail(*in); + if (!header.thumbnail) + return false; + + // Read in save date/time + header.saveYear = in->readSint16LE(); + header.saveMonth = in->readSint16LE(); + header.saveDay = in->readSint16LE(); + header.saveHour = in->readSint16LE(); + header.saveMinutes = in->readSint16LE(); + + return true; +} + +void CGE2Engine::syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream) { + Common::Serializer s(readStream, writeStream); + + // Synchronise header data + syncHeader(s); + + // Synchronise _spare + _spare->sync(s); + + if (s.isSaving()) { + // Save the references of the items in the heroes pockets: + for (int i = 0; i < 2; i++) { + for (int j = 0; j < kPocketMax; j++) { + int ref = _heroTab[i]->_downPocketId[j]; + s.syncAsSint16LE(ref); + } + } + } else { + // Load items to the pockets + for (int i = 0; i < 2; i++) { + for (int j = 0; j < kPocketMax; j++) { + int ref = 0; + s.syncAsSint16LE(ref); + _heroTab[i]->_downPocketId[j] = ref; + } + } + } + + // Heroes' _posTabs + for (int i = 0; i < 2; i++) { + for (int j = 0; j < kSceneMax; j++) { + s.syncAsSint16LE(_heroTab[i]->_posTab[j]->x); + s.syncAsSint16LE(_heroTab[i]->_posTab[j]->y); + } + } +} + +void CGE2Engine::syncHeader(Common::Serializer &s) { + s.syncAsUint16LE(_now); + s.syncAsUint16LE(_sex); + s.syncAsUint16LE(_vga->_rot._len); + s.syncAsUint16LE(_waitSeq); + s.syncAsUint16LE(_waitRef); + + if (s.isSaving()) { + // Write checksum + int checksum = kSavegameCheckSum; + s.syncAsUint16LE(checksum); + } else { + // Read checksum and validate it + uint16 checksum = 0; + s.syncAsUint16LE(checksum); + if (checksum != kSavegameCheckSum) + error("%s", _text->getText(kBadSVG)); + } +} + +/** +* Support method that generates a savegame name +* @param slot Slot number +*/ +Common::String CGE2Engine::generateSaveName(int slot) { + return Common::String::format("%s.%03d", _targetName.c_str(), slot); +} + +} // End of namespace CGE2 diff --git a/engines/cge2/snail.cpp b/engines/cge2/snail.cpp new file mode 100644 index 0000000000..0bf63839e9 --- /dev/null +++ b/engines/cge2/snail.cpp @@ -0,0 +1,865 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge2/snail.h" +#include "cge2/fileio.h" +#include "cge2/hero.h" +#include "cge2/text.h" +#include "cge2/sound.h" +#include "cge2/events.h" + +namespace CGE2 { + +const char *CommandHandler::_commandText[] = { + "NOP", "USE", "PAUSE", "INF", "CAVE", "SETX", "SETY", "SETZ", "ADD", + "FLASH", "CYCLE", "CLEAR", "MOUSE", "MAP", "MIDI", ".DUMMY.", "WAIT", + "HIDE", "ROOM", "SAY", "SOUND", "KILL", "RSEQ", "SEQ", "SEND", "SWAP", + "KEEP", "GIVE", "GETPOS", "GOTO", "PORT", "NEXT", "NNEXT", "MTNEXT", + "FTNEXT", "RNNEXT", "RMTNEXT", "RFTNEXT", "RMNEAR", "RMMTAKE", "RMFTAKE", + "SETREF", "WALKTO", "REACH", "COVER", "UNCOVER", "EXEC", "GHOST", + nullptr }; + +CommandHandler::CommandHandler(CGE2Engine *vm, bool turbo) + : _turbo(turbo), _textDelay(false), _timerExpiry(0), _talkEnable(true), + _head(0), _tail(0), _commandList((Command *)malloc(sizeof(Command)* 256)), + _vm(vm) { +} + +CommandHandler::~CommandHandler() { + free(_commandList); +} + +void CommandHandler::runCommand() { + if (!_turbo && _vm->_soundStat._wait) { + if (*(_vm->_soundStat._wait)) + return; + + ++_vm->_soundStat._ref[0]; + if (_vm->_fx->exist(_vm->_soundStat._ref[1], _vm->_soundStat._ref[0])) { + int16 oldRepeat = _vm->_sound->getRepeat(); + _vm->_sound->setRepeat(1); + _vm->_sound->play(Audio::Mixer::kSFXSoundType, _vm->_fx->load(_vm->_soundStat._ref[1], _vm->_soundStat._ref[0]), _vm->_sound->_smpinf._span); + _vm->_sound->setRepeat(oldRepeat); + return; + } + _vm->_soundStat._wait = nullptr; + } + + uint8 tmpHead = _head; + while (_tail != tmpHead) { + Command tailCmd = _commandList[_tail]; + + if (!_turbo) { // only for the slower one + if (_vm->_waitRef) + break; + + if (_timerExpiry) { + // Delay in progress + if (_timerExpiry > g_system->getMillis()) + // Delay not yet ended + break; + + // Delay is finished + _timerExpiry = 0; + } else if (_textDelay) { + if (_vm->_talk) { + _vm->snKill((Sprite *)_vm->_talk); + _vm->_talk = nullptr; + } + _textDelay = false; + } + + if (_vm->_talk && tailCmd._commandType != kCmdPause) + break; + } + ++_tail; + _vm->_taken = false; + Sprite *spr = nullptr; + if (tailCmd._commandType > kCmdSpr) + spr = (tailCmd._ref < 0) ? ((Sprite *)tailCmd._spritePtr) : _vm->locate(tailCmd._ref); + + Common::String sprStr; + if (spr && *spr->_file && (tailCmd._commandType != kCmdGhost)) + // In case of kCmdGhost _spritePtr stores a pointer to a Bitmap, not to a Sprite... + sprStr = Common::String(spr->_file); + else + sprStr = "None"; + + if (sprStr.empty()) + sprStr = "None"; + debugC(1, kCGE2DebugOpcode, "Command: %s; Ref: %d; Val: %d; Sprite: %s;", getComStr(tailCmd._commandType), tailCmd._ref, tailCmd._val, sprStr.c_str()); + + switch (tailCmd._commandType) { + case kCmdUse: + break; + case kCmdPause: + _timerExpiry = g_system->getMillis() + tailCmd._val * kCommandFrameDelay; + if (_vm->_talk) + _textDelay = true; + break; + case kCmdWait: + if (spr && spr->active() && (spr->_scene == _vm->_now || spr->_scene == 0)) { + _vm->_waitSeq = tailCmd._val; + _vm->_waitRef = spr->_ref; + } + break; + case kCmdHide: + _vm->snHide(spr, tailCmd._val); + break; + case kCmdSay: + _vm->snSay(spr, tailCmd._val); + break; + case kCmdInf: + if (_talkEnable) + _vm->inf(((tailCmd._val) >= 0) ? _vm->_text->getText(tailCmd._val) : (const char *)tailCmd._spritePtr); + break; + case kCmdCave: + _vm->switchScene(tailCmd._val); + break; + case kCmdMidi: + _vm->snMidi(tailCmd._val); + break; + case kCmdKill: + _vm->snKill(spr); + break; + case kCmdSeq: + _vm->snSeq(spr, tailCmd._val); + break; + case kCmdRSeq: + _vm->snRSeq(spr, tailCmd._val); + break; + case kCmdSend: + _vm->snSend(spr, tailCmd._val); + break; + case kCmdSwap: + _vm->snSwap(spr, tailCmd._val); + break; + case kCmdCover: + _vm->snCover(spr, tailCmd._val); + break; + case kCmdUncover: + _vm->snUncover(spr, (tailCmd._val >= 0) ? _vm->locate(tailCmd._val) : ((Sprite *)tailCmd._spritePtr)); + break; + case kCmdKeep: + _vm->snKeep(spr, tailCmd._val); + break; + case kCmdGive: + _vm->snGive(spr, tailCmd._val); + break; + case kCmdSetX: + _vm->_point[tailCmd._val]->_x = tailCmd._ref; + break; + case kCmdSetY: + _vm->_point[tailCmd._val]->_y = tailCmd._ref; + break; + case kCmdSetZ: + _vm->_point[tailCmd._val]->_z = tailCmd._ref; + break; + case kCmdAdd: + *(_vm->_point[tailCmd._ref]) = *(_vm->_point[tailCmd._ref]) + *(_vm->_point[tailCmd._val]); + break; + case kCmdGetPos: + if (spr) + *(_vm->_point[tailCmd._val]) = spr->_pos3D; + break; + case kCmdGoto: + _vm->snGoto(spr, tailCmd._val); + break; + case kCmdPort: + _vm->snPort(spr, tailCmd._val); + break; + case kCmdNext: + break; + case kCmdMouse: + _vm->snMouse(tailCmd._val != 0); + break; + case kCmdNNext: + _vm->snNNext(spr, kNear, tailCmd._val); + break; + case kCmdMTNext: + _vm->snNNext(spr, kMTake, tailCmd._val); + break; + case kCmdFTNext: + _vm->snNNext(spr, kFTake, tailCmd._val); + break; + case kCmdRNNext: + _vm->snRNNext(spr, tailCmd._val); + break; + case kCmdRMTNext: + _vm->snRMTNext(spr, tailCmd._val); + break; + case kCmdRFTNext: + _vm->snRFTNext(spr, tailCmd._val); + break; + case kCmdRMNear: + _vm->snRmNear(spr); + break; + case kCmdRMMTake: + _vm->snRmMTake(spr); + break; + case kCmdRMFTake: + _vm->snRmFTake(spr); + break; + case kCmdSetRef: + _vm->snSetRef(spr, tailCmd._val); + break; + case kCmdFlash: + _vm->snFlash(tailCmd._val != 0); + break; + case kCmdCycle: + _vm->snCycle(tailCmd._val); + break; + case kCmdWalk: + _vm->snWalk(spr, tailCmd._val); + break; + case kCmdReach: + _vm->snReach(spr, tailCmd._val); + break; + case kCmdSound: + _vm->snSound(spr, tailCmd._val); + _vm->_sound->setRepeat(1); + break; + case kCmdMap: + _vm->_heroTab[tailCmd._ref & 1]->_ptr->_ignoreMap = tailCmd._val == 0; + break; + case kCmdRoom: + _vm->snRoom(spr, tailCmd._val); + break; + case kCmdExec: + switch (tailCmd._cbType) { + case kQGame: + _vm->qGame(); + break; + case kXScene: + _vm->xScene(); + break; + default: + error("Unknown Callback Type in SNEXEC"); + break; + } + break; + case kCmdGhost: + _vm->snGhost((Bitmap *)tailCmd._spritePtr); + break; + case kCmdNop: // Do nothing. + break; + default: + warning("Unhandled command"); + break; + } + + if (_vm->_taken && spr) + _vm->_spare->dispose(spr); + + if (!_turbo) + break; + } +} + +void CGE2Engine::snKill(Sprite *spr) { + if (spr) { + if (spr->_flags._kept) + releasePocket(spr); + Sprite *nx = spr->_next; + hide1(spr); + _vga->_showQ->remove(spr); + _eventManager->clearEvent(spr); + if (spr->_flags._kill) { + _spare->take(spr->_ref); + delete spr; + } else { + spr->setScene(-1); + _spare->dispose(spr); + } + if (nx && nx->_flags._slav) + snKill(nx); + } +} + +void CGE2Engine::snHide(Sprite *spr, int val) { + if (spr) { + spr->_flags._hide = (val >= 0) ? (val != 0) : (!spr->_flags._hide); + if (spr->_flags._shad) + spr->_prev->_flags._hide = spr->_flags._hide; + } +} + +void CGE2Engine::snMidi(int val) { + if (val < 0) + _midiPlayer->killMidi(); + else if (_music) + _midiPlayer->loadMidi(val); +} + +void CGE2Engine::snSeq(Sprite *spr, int val) { + if (spr) { + if (isHero(spr) && (val == 0)) + ((Hero*)spr)->park(); + else + spr->step(val); + } +} + +void CGE2Engine::snRSeq(Sprite *spr, int val) { + if (spr) + snSeq(spr, spr->_seqPtr + val); +} + +void CGE2Engine::snSend(Sprite *spr, int val) { + if (!spr) + return; + + // Sending", spr->_file + // from scene", spr->_scene + // to scene", val + bool was1 = (_vga->_showQ->locate(spr->_ref) != nullptr); + bool val1 = (val == 0 || val == _now); + spr->_scene = val; + releasePocket(spr); + if (val1 != was1) { + if (was1) { + // deactivating + hide1(spr); + spr->_flags._slav = false; + if ((spr == _heroTab[_sex]->_ptr) && (_heroTab[!_sex]->_ptr->_scene == _now)) + switchHero(!_sex); + _spare->dispose(spr); + } else { + // activating + if (byte(spr->_ref) == 0) + _bitmapPalette = _vga->_sysPal; + _vga->_showQ->insert(spr); + if (isHero(spr)) { + V2D p = *_heroTab[spr->_ref & 1]->_posTab[val]; + spr->gotoxyz(V3D(p.x, 0, p.y)); + ((Hero*)spr)->setCurrent(); + } + _taken = false; + _bitmapPalette = nullptr; + } + } +} + +void CGE2Engine::snSwap(Sprite *spr, int val) { + bool tak = _taken; + Sprite *xspr = locate(val); + if (spr && xspr) { + bool was1 = (_vga->_showQ->locate(spr->_ref) != nullptr); + bool xwas1 = (_vga->_showQ->locate(val) != nullptr); + + int tmp = spr->_scene; + spr->setScene(xspr->_scene); + xspr->setScene(tmp); + + SWAP(spr->_pos2D, xspr->_pos2D); + SWAP(spr->_pos3D, xspr->_pos3D); + if (spr->_flags._kept) + swapInPocket(spr, xspr); + if (xwas1 != was1) { + if (was1) { + hide1(spr); + _spare->dispose(spr); + } else + expandSprite(spr); + if (xwas1) { + hide1(xspr); + _spare->dispose(xspr); + } else { + expandSprite(xspr); + _taken = false; + } + } + } + if (_taken) + _spare->dispose(xspr); + _taken = tak; +} + +void CGE2Engine::snCover(Sprite *spr, int val) { + bool tak = _taken; + Sprite *xspr = locate(val); + if (spr && xspr) { + spr->_flags._hide = true; + xspr->setScene(spr->_scene); + xspr->gotoxyz(spr->_pos3D); + expandSprite(xspr); + if ((xspr->_flags._shad = spr->_flags._shad) == true) { + _vga->_showQ->insert(_vga->_showQ->remove(spr->_prev), xspr); + spr->_flags._shad = false; + } + feedSnail(xspr, kNear, _heroTab[_sex]->_ptr); + _taken = false; + } + if (_taken) + _spare->dispose(xspr); + _taken = tak; +} + +void CGE2Engine::snUncover(Sprite *spr, Sprite *spr2) { + if (spr && spr2) { + spr->_flags._hide = false; + spr->setScene(spr2->_scene); + if ((spr->_flags._shad = spr2->_flags._shad) == true) { + _vga->_showQ->insert(_vga->_showQ->remove(spr2->_prev), spr); + spr2->_flags._shad = false; + } + spr->gotoxyz(spr2->_pos3D); + snSend(spr2, -1); + if (spr->_time == 0) + ++spr->_time; + } +} + +void CGE2Engine::snKeep(Sprite *spr, int stp) { + int sex = _sex; + if (stp > 127) { + _sex = stp & 1; // for another hero + stp = -1; + } + HeroTab *ht = _heroTab[_sex]; + selectPocket(-1); + int pp = ht->_pocPtr; + + if (spr && !spr->_flags._kept && ht->_pocket[pp] == nullptr) { + V3D pos(14, -10, -1); + int16 oldRepeat = _sound->getRepeat(); + _sound->setRepeat(1); + snSound(ht->_ptr, 3); + _sound->setRepeat(oldRepeat); + if (_taken) { + _vga->_showQ->insert(spr); + _taken = false; + } + ht->_pocket[pp] = spr; + spr->setScene(0); + spr->_flags._kept = true; + if (!_sex) + pos._x += kScrWidth - 58; + if (pp & 1) + pos._x += 29; + if (pp >> 1) + pos._y -= 20; + pos._y -= (spr->_siz.y / 2); + spr->gotoxyz(pos); + if (stp >= 0) + spr->step(stp); + } + _sex = sex; + selectPocket(-1); +} + +void CGE2Engine::snGive(Sprite *spr, int val) { + if (spr) { + int p = findActivePocket(spr->_ref); + if (p >= 0) { + releasePocket(spr); + spr->setScene(_now); + if (val >= 0) + spr->step(val); + } + } + selectPocket(-1); +} + +void CGE2Engine::snGoto(Sprite *spr, int val) { + if (spr) { + V3D eye = *_eye; + if (spr->_scene > 0) + setEye(*_eyeTab[spr->_scene]); + spr->gotoxyz(*_point[val]); + setEye(eye); + } +} + +void CGE2Engine::snPort(Sprite *spr, int port) { + if (spr) + spr->_flags._port = (port < 0) ? !spr->_flags._port : (port != 0); +} + +void CGE2Engine::snMouse(bool on) { + if (on) + _mouse->on(); + else + _mouse->off(); +} + +void CGE2Engine::snNNext(Sprite *spr, Action act, int val) { + if (spr) { + if (val > 255) + val = spr->labVal(act, val >> 8); + spr->_actionCtrl[act]._ptr = val; + } +} + +void CGE2Engine::snRNNext(Sprite *spr, int val) { + if (spr) + spr->_actionCtrl[kNear]._ptr += val; +} + +void CGE2Engine::snRMTNext(Sprite *spr, int val) { + if (spr) + spr->_actionCtrl[kMTake]._ptr += val; +} + +void CGE2Engine::snRFTNext(Sprite * spr, int val) { + if (spr) + spr->_actionCtrl[kFTake]._ptr += val; +} + +void CGE2Engine::snRmNear(Sprite *spr) { + if (spr) + spr->_actionCtrl[kNear]._cnt = 0; +} + +void CGE2Engine::snRmMTake(Sprite *spr) { + if (spr) + spr->_actionCtrl[kMTake]._cnt = 0; +} + +void CGE2Engine::snRmFTake(Sprite *spr) { + if (spr) + spr->_actionCtrl[kFTake]._cnt = 0; +} + +void CGE2Engine::snSetRef(Sprite *spr, int val) { + if (spr) + spr->_ref = val; +} + +void CGE2Engine::snFlash(bool on) { + if (on) { + Dac *pal = (Dac *)malloc(sizeof(Dac) * kPalCount); + if (pal) { + memcpy(pal, _vga->_sysPal, kPalSize); + for (int i = 0; i < kPalCount; 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); + } + + free(pal); + } else + _vga->setColors(_vga->_sysPal, 64); + _dark = false; +} + +void CGE2Engine::snCycle(int cnt) { + _vga->_rot._len = cnt; +} + +void CGE2Engine::snWalk(Sprite *spr, int val) { + if (isHero(spr)) { + if (val < kMaxPoint) + ((Hero *)spr)->walkTo(*_point[val]); + else { + Sprite *s = _vga->_showQ->locate(val); + if (s) + ((Hero *)spr)->walkTo(s); + } + ((Hero *)spr)->_time = 1; + } +} + +void CGE2Engine::snReach(Sprite *spr, int val) { + if (isHero(spr)) + ((Hero *)spr)->reach(val); +} + +void CGE2Engine::snSound(Sprite *spr, int wav, Audio::Mixer::SoundType soundType) { + if (wav == -1) + _sound->stop(); + else { + if (_sound->_smpinf._counter && wav < 20) + return; + if (_soundStat._wait && ((wav & 255) > 80)) + return; + + _soundStat._ref[1] = wav; + _soundStat._ref[0] = !_fx->exist(_soundStat._ref[1]); + _sound->play(soundType, _fx->load(_soundStat._ref[1], _soundStat._ref[0]), + (spr) ? (spr->_pos2D.x / (kScrWidth / 16)) : 8); + } +} + +void CGE2Engine::snRoom(Sprite *spr, bool on) { + if (!isHero(spr)) + return; + + int sex = spr->_ref & 1; + Sprite **p = _heroTab[sex]->_pocket; + if (on) { + if (freePockets(sex) == 0 && p[kPocketMax] == nullptr) { + SWAP(p[kPocketMax], p[kPocketMax - 1]); + snHide(p[kPocketMax], 1); + } + } else if (p[kPocketMax]) { + for (int i = 0; i < kPocketMax; i++) { + if (p[i] == nullptr) { + snHide(p[kPocketMax], 0); + SWAP(p[kPocketMax], p[i]); + break; + } + } + } +} + +void CGE2Engine::snGhost(Bitmap *bmp) { + V2D p(this, bmp->_map & 0xFFFF, bmp->_map >> 16); + bmp->hide(p); + bmp->release(); + delete[] bmp->_b; + bmp->_b = nullptr; + delete bmp; + bmp = nullptr; +} + +void CGE2Engine::snSay(Sprite *spr, int val) { + if (spr && spr->active() && _commandHandler->_talkEnable) { + //-- mouth animation + if (isHero(spr) && spr->seqTest(-1)) + ((Hero *)spr)->say(); + if (_sayCap) + _text->say(_text->getText(val), spr); + if (_sayVox) { + int i = val; + if (i < 256) + i -= 100; + int16 oldRepeat = _sound->getRepeat(); + _sound->setRepeat(1); + snSound(spr, i, Audio::Mixer::kSpeechSoundType); + _sound->setRepeat(oldRepeat); + _soundStat._wait = &_sound->_smpinf._counter; + } + } +} + +void CGE2Engine::hide1(Sprite *spr) { + _commandHandlerTurbo->addCommand(kCmdGhost, -1, 0, spr->ghost()); +} + +void CGE2Engine::swapInPocket(Sprite *spr, Sprite *xspr) { + for (int i = 0; i < 2; i++) { + for (int j = 0; j < kPocketMax; j++) { + Sprite *&poc = _heroTab[i]->_pocket[j]; + if (poc == spr) { + spr->_flags._kept = false; + poc = xspr; + xspr->_flags._kept = true; + xspr->_flags._port = false; + return; + } + } + } +} + +Sprite *CGE2Engine::expandSprite(Sprite *spr) { + if (spr) + _vga->_showQ->insert(spr); + return spr; +} + +void CGE2Engine::qGame() { + // Write out the user's progress + saveGame(0, Common::String("Automatic Savegame")); + + busy(false); + _vga->sunset(); + _endGame = true; +} + +void CGE2Engine::xScene() { + sceneDown(); + sceneUp(_req); +} + +void CommandHandler::addCommand(CommandType com, int ref, int val, void *ptr) { + if (ref == -2) + ref = 142 - _vm->_sex; + Command *headCmd = &_commandList[_head++]; + headCmd->_commandType = com; + headCmd->_ref = ref; + headCmd->_val = val; + headCmd->_spritePtr = ptr; + headCmd->_cbType = kNullCB; + if (headCmd->_commandType == kCmdClear) { + clear(); + } +} + +void CommandHandler::addCallback(CommandType com, int ref, int val, CallbackType cbType) { + Command *headCmd = &_commandList[_head++]; + headCmd->_commandType = com; + headCmd->_ref = ref; + headCmd->_val = val; + headCmd->_spritePtr = nullptr; + headCmd->_cbType = cbType; + if (headCmd->_commandType == kCmdClear) { + _tail = _head; + _vm->killText(); + _timerExpiry = 0; + } +} + +void CommandHandler::insertCommand(CommandType com, int ref, int val, void *ptr) { + if (ref == -2) + ref = 142 - _vm->_sex; + --_tail; + Command *tailCmd = &_commandList[_tail]; + tailCmd->_commandType = com; + tailCmd->_ref = ref; + tailCmd->_val = val; + tailCmd->_spritePtr = ptr; + tailCmd->_cbType = kNullCB; + if (com == kCmdClear) { + _tail = _head; + _vm->killText(); + _timerExpiry = 0; + } +} + +bool CommandHandler::idle() { + return (!_vm->_waitRef && _head == _tail); +} + +void CommandHandler::clear() { + _tail = _head; + _vm->killText(); + _timerExpiry = 0; +} + +int CommandHandler::getComId(const char *com) { + int i = _vm->takeEnum(_commandText, com); + return (i < 0) ? i : i + kCmdCom0 + 1; +} + +const char *CommandHandler::getComStr(CommandType cmdType) { + return _commandText[cmdType - kCmdNop]; +} + +void CGE2Engine::feedSnail(Sprite *spr, Action snq, Hero *hero) { + if (!spr || !spr->active()) + return; + + int cnt = spr->_actionCtrl[snq]._cnt; + if (cnt) { + byte ptr = spr->_actionCtrl[snq]._ptr; + CommandHandler::Command *comtab = spr->snList(snq); + CommandHandler::Command *c = &comtab[ptr]; + CommandHandler::Command *q = &comtab[cnt]; + + if (hero != nullptr) { + int pocFre = freePockets(hero->_ref & 1); + int pocReq = 0; + CommandHandler::Command *p = c; + for (; p < q && p->_commandType != kCmdNext; p++) { // scan commands + // drop from pocket? + if ((p->_commandType == kCmdSend && p->_val != _now) + || p->_commandType == kCmdGive) { + int ref = p->_ref; + if (ref < 0) + ref = spr->_ref; + if (findActivePocket(ref) >= 0) + --pocReq; + } + // make/dispose additional room? + if (p->_commandType == kCmdRoom) { + if (p->_val == 0) + ++pocReq; + else + --pocReq; + } + // put into pocket? + if (p->_commandType == kCmdKeep) + ++pocReq; + // overloaded? + if (pocReq > pocFre) { + pocFul(); + return; + } + } + } + + while (c < q) { + if ((c->_val == -1) && (c->_commandType == kCmdWalk || c->_commandType == kCmdReach)) + c->_val = spr->_ref; + + if (c->_commandType == kCmdNext) { + Sprite *s; + + switch (c->_ref) { + case -2: + s = hero; + break; + case -1: + s = spr; + break; + default: + s = _vga->_showQ->locate(c->_ref); + break; + } + + if (s && s->_actionCtrl[snq]._cnt) { + int v; + switch (c->_val) { + case -1: + v = int(c - comtab + 1); + break; + case -2: + v = int(c - comtab); + break; + case -3: + v = -1; + break; + default: + v = c->_val; + if ((v > 255) && s) + v = s->labVal(snq, v >> 8); + break; + } + if (v >= 0) + s->_actionCtrl[snq]._ptr = v; + } + + if (s == spr) + break; + } + + _commandHandler->addCommand(c->_commandType, c->_ref, c->_val, spr); + + ++c; + } + } + +} + +} // End of namespace CGE2. diff --git a/engines/cge2/snail.h b/engines/cge2/snail.h new file mode 100644 index 0000000000..7e618daac8 --- /dev/null +++ b/engines/cge2/snail.h @@ -0,0 +1,129 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_SNAIL_H +#define CGE2_SNAIL_H + +#include "cge2/cge2.h" + +namespace CGE2 { + +#define kCommandFrameRate 80 +#define kCommandFrameDelay (1000 / kCommandFrameRate) +#define kNoByte -1 // Recheck this! We have no proof for it's original value. + + +enum CommandType { + kCmdCom0 = 128, + kCmdNop, // NOP :: do nothing + kCmdUse, // USE <spr> <cav>|<lab> :: hint for using + kCmdPause, // PAUSE -1 <dly> :: delay <dly>/72 seconds + kCmdInf, // INF -1 <ref> :: show text referrenced by <ref> + kCmdCave, // CAVE -1 <cav> :: go to board <cav> + kCmdSetX, // SETX <x> <idx> :: set sprite shift in x axis + kCmdSetY, // SETX <y> <idx> :: set sprite shift in y axis + kCmdSetZ, // SETX <z> <idx> :: set sprite shift in z axis + kCmdAdd, // ADD <idx1> <idx2> :: sum vectors + kCmdFlash, // FLASH -1 0|1 :: lighten whole image (on/off) + kCmdCycle, // CYCLE <cnt> :: rotate <cnt> colors from 1 + kCmdClear, // CLEAR -1 0 :: clear kCmdAIL queue + kCmdMouse, // MOUSE -1 0|1 :: enable mouse (on/off) + kCmdMap, // MAP 0|1 0 :: temporarily turn off map for hero + kCmdMidi, // MIDI -1 <midi> :: play MIDI referenced by <midi> (-1 = off) + + kCmdSpr, + + kCmdWait, // WAIT <spr> <seq>|-1 :: wait for SEQ <seq> (-1 = freeze) + kCmdHide, // HIDE <spr> 0|1 :: visibility of sprite + kCmdRoom, // ROOM <hero> 0|1 :: additional room in pocket (no/yes) + kCmdSay, // SAY <spr> <ref> :: say text referenced by <ref> + kCmdSound, // SOUND <spr> <ref> :: play sound effect referenced by <ref> + kCmdKill, // KILL <spr> 0 :: remove sprite + kCmdRSeq, // RSEQ <spr> <nr> :: relative jump SEQ <nr> lines + kCmdSeq, // SEQ <spr> <seq> :: jump to certain SEQ + kCmdSend, // SEND <spr> <cav> :: move sprite to board <cav> + kCmdSwap, // SWAP <spr1> spr2> :: sprite exchange + kCmdKeep, // KEEP <spr> <seq> :: take sprite into pocket and jump to <seq> + kCmdGive, // GIVE <spr> <seq> :: remove sprite from pocket and jump to <seq> + kCmdGetPos, // GETPOS <spr> <idx> :: take sprite's position + kCmdGoto, // GOTO <spr> <idx> :: move sprite to position + kCmdPort, // PORT <spr> 0|1 :: clear/set "takeability" of sprite + kCmdNext, // NEXT <spr> <nr> :: jump to <nr> - NEAR or TAKE + kCmdNNext, // NNEXT <spr> <nr> :: jump to <nr> - NEAR + kCmdMTNext, // MTNEXT <spr> <nr> :: jump to <nr> - TAKE + kCmdFTNext, // FTNEXT <spr> <nr> :: jump to <nr> - TAKE + kCmdRNNext, // RNNEXT <spr> <nr> :: relative jump to <nr> - NEAR + kCmdRMTNext, // RMTNEXT <spr> <nr> :: relative jump to <nr> - TAKE + kCmdRFTNext, // RFTNEXT <spr> <nr> :: relative jump to <nr> - TAKE + kCmdRMNear, // RMNEAR <spr> 0 :: remove NEAR list + kCmdRMMTake, // RMMTAKE <spr> 0 :: remove TAKE list + kCmdRMFTake, // RMFTAKE <spr> 0 :: remove TAKE list + kCmdSetRef, // SETREF <spr> <ref> :: change reference of sprite <spr> to <ref> + kCmdWalk, // WALKTO <hero> <ref>|<point> :: go close to the sprite or point + kCmdReach, // REACH <hero> <ref>|<m> :: reach the sprite or point with <m> method + kCmdCover, // COVER <sp1> <sp2> :: cover sprite <sp1> with sprite <sp2> + kCmdUncover, // UNCOVER <sp1> <sp2> :: restore the state before COVER + + kCmdExec, + kCmdGhost +}; + +class CommandHandler { +public: + struct Command { + CommandType _commandType; + byte _lab; + int _ref; + int _val; + void *_spritePtr; + CallbackType _cbType; + } *_commandList; + static const char *_commandText[]; + bool _talkEnable; + + CommandHandler(CGE2Engine *vm, bool turbo); + ~CommandHandler(); + void runCommand(); + void addCommand(CommandType com, int ref, int val, void *ptr); + void addCallback(CommandType com, int ref, int val, CallbackType cbType); + void insertCommand(CommandType com, int ref, int val, void *ptr); + bool idle(); + void clear(); + int getComId(const char *com); + const char *getComStr(CommandType cmdType); +private: + CGE2Engine *_vm; + bool _turbo; + uint8 _head; + uint8 _tail; + bool _textDelay; + uint32 _timerExpiry; // "pause" in the original. +}; + +} // End of namespace CGE2 + +#endif diff --git a/engines/cge2/sound.cpp b/engines/cge2/sound.cpp new file mode 100644 index 0000000000..32f94b17b9 --- /dev/null +++ b/engines/cge2/sound.cpp @@ -0,0 +1,273 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge2/sound.h" +#include "common/config-manager.h" +#include "common/memstream.h" +#include "audio/decoders/raw.h" +#include "audio/audiostream.h" +#include "cge2/cge2.h" + +namespace CGE2 { + +DataCk::DataCk(byte *buf, int bufSize) { + _buf = buf; + _ckSize = bufSize; +} + +DataCk::~DataCk() { + free(_buf); +} + +Sound::Sound(CGE2Engine *vm) : _vm(vm) { + _audioStream = nullptr; + _soundRepeatCount = 1; + open(); +} + +Sound::~Sound() { + close(); +} + +void Sound::close() { + _vm->_midiPlayer->killMidi(); +} + +void Sound::open() { + setRepeat(1); + if (_vm->_commandHandlerTurbo != nullptr) + _vm->switchSay(); + play(Audio::Mixer::kSFXSoundType, _vm->_fx->load(99, 99)); +} + +void Sound::setRepeat(int16 count) { + _soundRepeatCount = count; +} + +int16 Sound::getRepeat() { + return _soundRepeatCount; +} + +void Sound::play(Audio::Mixer::SoundType soundType, DataCk *wav, int pan) { + if (wav) { + stop(); + _smpinf._saddr = &*(wav->addr()); + _smpinf._slen = (uint16)wav->size(); + _smpinf._span = pan; + _smpinf._counter = getRepeat(); + sndDigiStart(&_smpinf, soundType); + } +} + +void Sound::sndDigiStart(SmpInfo *PSmpInfo, Audio::Mixer::SoundType soundType) { + // Create an audio stream wrapper for sound + Common::MemoryReadStream *stream = new Common::MemoryReadStream(PSmpInfo->_saddr, + PSmpInfo->_slen, DisposeAfterUse::NO); + _audioStream = Audio::makeWAVStream(stream, DisposeAfterUse::YES); + + // Decide which handle to use + Audio::SoundHandle *handle = nullptr; + switch (soundType) { + case Audio::Mixer::kSFXSoundType: + handle = &_sfxHandle; + break; + case Audio::Mixer::kSpeechSoundType: + handle = &_speechHandle; + break; + default: + error("Wrong sound type passed to sndDigiStart()"); + } + + // Start the new sound + _vm->_mixer->playStream(soundType, handle, + Audio::makeLoopingAudioStream(_audioStream, (uint)PSmpInfo->_counter)); + + // CGE pan: + // 8 = Center + // Less = Left + // More = Right + _vm->_mixer->setChannelBalance(*handle, (int8)CLIP(((PSmpInfo->_span - 8) * 16), -127, 127)); +} + +void Sound::stop() { + sndDigiStop(_sfxHandle); + sndDigiStop(_speechHandle); + _audioStream = nullptr; +} + +void Sound::checkSoundHandles() { + if (!_vm->_mixer->isSoundHandleActive(_speechHandle) && !_vm->_mixer->isSoundHandleActive(_sfxHandle)) + _smpinf._counter = 0; +} + +void Sound::sndDigiStop(Audio::SoundHandle &handle) { + if (_vm->_mixer->isSoundHandleActive(handle)) + _vm->_mixer->stopHandle(handle); +} + +Fx::Fx(CGE2Engine *vm, int size) : _current(nullptr), _vm(vm) { +} + +Fx::~Fx() { + clear(); +} + +void Fx::clear() { + if (_current) + delete _current; + _current = nullptr; +} + +Common::String Fx::name(int ref, int sub) { + char fxname[] = "%.2dfx%.2d.WAV\0"; + char subName[] = "%.2dfx%.2d?.WAV\0"; + char *p = (sub) ? subName : fxname; + Common::String filename = Common::String::format(p, ref >> 8, ref & 0xFF); + if (sub) + filename.setChar('@' + sub, 6); + return filename; +} + +bool Fx::exist(int ref, int sub) { + return _vm->_resman->exist(name(ref, sub).c_str()); +} + +DataCk *Fx::load(int ref, int sub) { + Common::String filename = name(ref, sub); + EncryptedStream file(_vm, filename.c_str()); + clear(); + return (_current = loadWave(&file)); +} + +DataCk *Fx::loadWave(EncryptedStream *file) { + byte *data = (byte *)malloc(file->size()); + + if (!data) + return 0; + + file->read(data, file->size()); + + return new DataCk(data, file->size()); +} + +MusicPlayer::MusicPlayer(CGE2Engine *vm) : _vm(vm) { + _data = nullptr; + _isGM = false; + + MidiPlayer::createDriver(); + + int ret = _driver->open(); + if (ret == 0) { + if (_nativeMT32) + _driver->sendMT32Reset(); + else + _driver->sendGMReset(); + + // TODO: Load cmf.ins with the instrument table. It seems that an + // interface for such an operation is supported for AdLib. Maybe for + // this card, setting instruments is necessary. + + _driver->setTimerCallback(this, &timerCallback); + } + _dataSize = -1; +} + +MusicPlayer::~MusicPlayer() { + killMidi(); +} + +void MusicPlayer::killMidi() { + Audio::MidiPlayer::stop(); + + free(_data); + _data = nullptr; +} + +void MusicPlayer::loadMidi(int ref) { + if (_vm->_midiNotify != nullptr) + (_vm->*_vm->_midiNotify)(); + + // Work out the filename and check the given MIDI file exists + Common::String filename = Common::String::format("%.2dSG%.2d.MID", ref >> 8, ref & 0xFF); + if (!_vm->_resman->exist(filename.c_str())) + return; + + // Stop any currently playing MIDI file + killMidi(); + + // Read in the data for the file + EncryptedStream mid(_vm, filename.c_str()); + _dataSize = mid.size(); + _data = (byte *)malloc(_dataSize); + mid.read(_data, _dataSize); + + // Start playing the music + sndMidiStart(); +} + +void MusicPlayer::sndMidiStart() { + _isGM = true; + + MidiParser *parser = MidiParser::createParser_SMF(); + if (parser->loadMusic(_data, _dataSize)) { + parser->setTrack(0); + parser->setMidiDriver(this); + parser->setTimerRate(_driver->getBaseTempo()); + parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); + + _parser = parser; + + syncVolume(); + + // Al the tracks are supposed to loop + _isLooping = true; + _isPlaying = true; + } +} + +void MusicPlayer::send(uint32 b) { + if (((b & 0xF0) == 0xC0) && !_isGM && !_nativeMT32) { + b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8; + } + + Audio::MidiPlayer::send(b); +} + +void MusicPlayer::sendToChannel(byte channel, uint32 b) { + if (!_channelsTable[channel]) { + _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel(); + // If a new channel is allocated during the playback, make sure + // its volume is correctly initialized. + if (_channelsTable[channel]) + _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255); + } + + if (_channelsTable[channel]) + _channelsTable[channel]->send(b); +} + +} // End of namespace CGE2 diff --git a/engines/cge2/sound.h b/engines/cge2/sound.h new file mode 100644 index 0000000000..6673b67b7a --- /dev/null +++ b/engines/cge2/sound.h @@ -0,0 +1,131 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_SOUND_H +#define CGE2_SOUND_H + +#include "cge2/fileio.h" +#include "audio/audiostream.h" +#include "audio/decoders/wave.h" +#include "audio/fmopl.h" +#include "audio/mididrv.h" +#include "audio/midiparser.h" +#include "audio/midiplayer.h" +#include "audio/mixer.h" +#include "common/memstream.h" + +namespace CGE2 { + +class CGE2Engine; + +// sample info +struct SmpInfo { + const uint8 *_saddr; // address + uint16 _slen; // length + uint16 _span; // left/right pan (0-15) + int _counter; // number of time the sample should be played +}; + +class DataCk { + byte *_buf; + int _ckSize; +public: + DataCk(byte *buf, int bufSize); + ~DataCk(); + inline const byte *addr() { + return _buf; + } + inline int size() { + return _ckSize; + } +}; + +class Sound { +public: + SmpInfo _smpinf; + + Sound(CGE2Engine *vm); + ~Sound(); + void open(); + void close(); + void play(Audio::Mixer::SoundType soundType, DataCk *wav, int pan = 8); + int16 getRepeat(); + void setRepeat(int16 count); + void stop(); + void checkSoundHandles(); +private: + int _soundRepeatCount; + CGE2Engine *_vm; + Audio::SoundHandle _sfxHandle; + Audio::SoundHandle _speechHandle; + Audio::RewindableAudioStream *_audioStream; + + void sndDigiStart(SmpInfo *PSmpInfo, Audio::Mixer::SoundType soundType); + void sndDigiStop(Audio::SoundHandle &handle); +}; + +class Fx { + CGE2Engine *_vm; + + DataCk *loadWave(EncryptedStream *file); + Common::String name(int ref, int sub); +public: + DataCk *_current; + + Fx(CGE2Engine *vm, int size); + ~Fx(); + void clear(); + bool exist(int ref, int sub = 0); + DataCk *load(int ref, int sub = 0); +}; + +class MusicPlayer: public Audio::MidiPlayer { +private: + CGE2Engine *_vm; + byte *_data; + int _dataSize; + bool _isGM; + + // Start MIDI File + void sndMidiStart(); + + // Stop MIDI File + void sndMidiStop(); +public: + MusicPlayer(CGE2Engine *vm); + ~MusicPlayer(); + + void loadMidi(int ref); + void killMidi(); + + virtual void send(uint32 b); + virtual void sendToChannel(byte channel, uint32 b); +}; + +} // End of namespace CGE2 + +#endif // CGE2_SOUND_H diff --git a/engines/cge2/spare.cpp b/engines/cge2/spare.cpp new file mode 100644 index 0000000000..76bdbfa7ef --- /dev/null +++ b/engines/cge2/spare.cpp @@ -0,0 +1,128 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge2/spare.h" + +namespace CGE2 { + +void Spare::sync(Common::Serializer &s) { + int size = 0; + if (s.isSaving()) { + for (uint i = 0; i < _container.size(); i++) + if (_container[i]->_ref >= 141) + size++; + s.syncAsSint16LE(size); + + for (uint i = 0; i < _container.size(); i++) { + if (_container[i]->_ref >= 141) + _container[i]->sync(s); + } + } else { + s.syncAsSint16LE(size); + + for (int i = 0; i < size; i++) { + Sprite *sprite = new Sprite(_vm); + sprite->sync(s); + update(sprite); + } + } +} + +void Spare::clear() { + for (uint i = 0; i < _container.size(); i++) + delete _container[i]; + + _container.clear(); +} + +Sprite *Spare::locate(int ref) { + for (uint i = 0; i < _container.size(); ++i) { + if (_container[i]->_ref == ref) + return _container[i]; + } + return nullptr; +} + +Sprite *Spare::take(int ref) { + Sprite *spr = nullptr; + if ((spr = locate(ref)) != nullptr) { + for (uint i = 0; i < _container.size(); ++i) { + if (spr == _container[i]) { + _container.remove_at(i); + break; + } + } + } + return spr; +} + +void Spare::takeScene(int cav) { + int bakRef = cav << 8; + Common::Array<Sprite*> tempCont = _container; + for (uint i = 0; i < tempCont.size(); ++i) { + Sprite *spr = tempCont[i]; + int c = spr->_scene; + if ((c == _vm->_now || c == 0) && spr->_ref != bakRef) { + spr = locate(spr->_ref); + _vm->_vga->_showQ->insert(spr); + } + } +} + +void Spare::store(Sprite *spr) { + _container.push_back(spr); +} + +void Spare::update(Sprite *spr) { + Sprite *sp = locate(spr->_ref); + if (sp == nullptr) + store(spr); + else { + sp->contract(); + *sp = *spr; + } +} + +void Spare::dispose(Sprite *spr) { + if (spr) { + _vm->_vga->_showQ->remove(spr); + update(spr->contract()); + } +} + +void Spare::dispose(int ref) { + dispose(_vm->_vga->_showQ->locate(ref)); +} + +void Spare::dispose() { + for (uint i = 0; i < _container.size(); ++i) { + if (_container[i]->_ref > 255) + dispose(_container[i]); + } +} + +} // End of namespace CGE2 diff --git a/engines/cge2/spare.h b/engines/cge2/spare.h new file mode 100644 index 0000000000..7dc6ce60f5 --- /dev/null +++ b/engines/cge2/spare.h @@ -0,0 +1,56 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_SPARE_H +#define CGE2_SPARE_H + +#include "cge2/vga13h.h" + +namespace CGE2 { + +class Spare { + CGE2Engine *_vm; + Common::Array<Sprite*> _container; +public: + Spare(CGE2Engine *vm) : _vm(vm) {} + ~Spare() { clear(); } + void store(Sprite *spr); + Sprite *locate(int ref); + Sprite *take(int ref); + void takeScene(int cav); + void update(Sprite *spr); + void dispose(Sprite *spr); + void dispose(int ref); + void dispose(); + void sync(Common::Serializer &s); + uint16 count() { return _container.size(); } + void clear(); +}; + +} // End of namespace CGE2 + +#endif // CGE2_SPARE_H diff --git a/engines/cge2/talk.cpp b/engines/cge2/talk.cpp new file mode 100644 index 0000000000..9109da90f1 --- /dev/null +++ b/engines/cge2/talk.cpp @@ -0,0 +1,312 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge2/general.h" +#include "cge2/talk.h" + +namespace CGE2 { + +void CGE2Engine::setAutoColors() { + Dac def[4] = { + { 0, 0, 0 }, + { 220 >> 2, 220 >> 2, 220 >> 2 }, + { 190 >> 2, 190 >> 2, 190 >> 2 }, + { 160 >> 2, 160 >> 2, 160 >> 2 }, + }; + Dac pal[kPalCount]; + _vga->getColors(pal); + for (int i = 0; i < 4; i++) + _font->_colorSet[kCBRel][i] = _vga->closest(pal, def[i]); +} + +Font::Font(CGE2Engine *vm) : _vm(vm) { + _map = new uint8[kMapSize]; + _pos = new uint16[kPosSize]; + _widthArr = new uint8[kWidSize]; + + load(); +} + +Font::~Font() { + delete[] _map; + delete[] _pos; + delete[] _widthArr; +} + +void Font::load() { + char path[10]; + strcpy(path, "CGE.CFT"); + if (!_vm->_resman->exist(path)) + error("Missing Font file! %s", path); + + EncryptedStream fontFile(_vm, path); + assert(!fontFile.err()); + + fontFile.read(_widthArr, kWidSize); + assert(!fontFile.err()); + + uint16 p = 0; + for (uint16 i = 0; i < kPosSize; i++) { + _pos[i] = p; + p += _widthArr[i]; + } + fontFile.read(_map, p); + + strcpy(path, "CGE.TXC"); + if (!_vm->_resman->exist(path)) + error("Missing Color file! %s", path); + + // Reading in _colorSet: + EncryptedStream colorFile(_vm, path); + assert(!colorFile.err()); + + char tmpStr[kLineMax + 1]; + int n = 0; + + for (Common::String line = colorFile.readLine(); !colorFile.eos(); line = colorFile.readLine()){ + if (line.empty()) + continue; + Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr)); + _colorSet[n][0] = _vm->number(tmpStr); + + for (int i = 1; i < 4; i++) + _colorSet[n][i] = _vm->number(nullptr); + + n++; + } +} + +uint16 Font::width(const char *text) { + uint16 w = 0; + if (!text) + return 0; + while (*text) + w += _widthArr[(unsigned char)*(text++)]; + return w; +} + +Talk::Talk(CGE2Engine *vm, const char *text, TextBoxStyle mode, ColorBank color, bool wideSpace) + : Sprite(vm), _mode(mode), _created(false), _wideSpace(wideSpace), _vm(vm) { + _color = _vm->_font->_colorSet[color]; + + if (color == kCBRel) + _vm->setAutoColors(); + update(text); +} + +Talk::Talk(CGE2Engine *vm, ColorBank color) + : Sprite(vm), _mode(kTBPure), _created(false), _wideSpace(false), _vm(vm) { + _color = _vm->_font->_colorSet[color]; + + if (color == kCBRel) + _vm->setAutoColors(); +} + +uint8 *Talk::box(V2D siz) { + uint16 n, r = (_mode == kTBRound) ? kTextRoundCorner : 0; + const byte lt = _color[1], bg = _color[2], dk = _color[3]; + + if (siz.x < 8) + siz.x = 8; + if (siz.y < 8) + siz.y = 8; + uint8 *b = new uint8[n = siz.area()]; + memset(b, bg, n); + + if (_mode) { + uint8 *p = b; + uint8 *q = b + n - siz.x; + memset(p, lt, siz.x); + memset(q, dk, siz.x); + while (p < q) { + p += siz.x; + *(p - 1) = dk; + *p = lt; + } + p = b; + for (int i = 0; i < r; i++) { + int j = 0; + for (; j < r - i; j++) { + p[j] = kPixelTransp; + p[siz.x - j - 1] = kPixelTransp; + q[j] = kPixelTransp; + q[siz.x - j - 1] = kPixelTransp; + } + p[j] = lt; + p[siz.x - j - 1] = dk; + q[j] = lt; + q[siz.x - j - 1] = dk; + p += siz.x; + q -= siz.x; + } + } + return b; +} + +void Talk::update(const char *text) { + const uint16 vmarg = (_mode) ? kTextVMargin : 0; + const uint16 hmarg = (_mode) ? kTextHMargin : 0; + uint16 mw; + uint16 mh; + uint16 ln = vmarg; + uint8 *m; + uint8 *map; + uint8 fg = _color[0]; + + if (_created) { + mw = _ext->_shpList->_w; + mh = _ext->_shpList->_h; + delete _ext->_shpList; + } else { + uint16 k = 2 * hmarg; + mh = 2 * vmarg + kFontHigh; + mw = 0; + for (const char *p = text; *p; p++) { + if ((*p == '|') || (*p == '\n')) { + mh += kFontHigh + kTextLineSpace; + if (k > mw) + mw = k; + k = 2 * hmarg; + } else if ((*p == 0x20) && (_vm->_font->_widthArr[(unsigned char)*p] > 4) && (!_wideSpace)) + k += _vm->_font->_widthArr[(unsigned char)*p] - 2; + else + k += _vm->_font->_widthArr[(unsigned char)*p]; + } + if (k > mw) + mw = k; + + _created = true; + } + + V2D sz(_vm, mw, mh); + map = box(sz); + + m = map + ln * mw + hmarg; + + while (*text) { + if ((*text == '|') || (*text == '\n')) + m = map + (ln += kFontHigh + kTextLineSpace) * mw + hmarg; + else { + int cw = _vm->_font->_widthArr[(unsigned char)*text]; + uint8 *f = _vm->_font->_map + _vm->_font->_pos[(unsigned char)*text]; + + // Handle properly space size, after it was enlarged to display properly + // 'F1' text. + int8 fontStart = 0; + if ((*text == 0x20) && (cw > 4) && (!_wideSpace)) + fontStart = 2; + + for (int i = fontStart; i < cw; i++) { + uint8 *pp = m; + uint16 n; + uint16 b = *(f++); + for (n = 0; n < kFontHigh; n++) { + if (b & 1) + *pp = fg; + b >>= 1; + pp += mw; + } + m++; + } + } + text++; + } + BitmapPtr b = new Bitmap[1]; + b[0] = Bitmap(_vm, sz.x, sz.y, map); + delete[] map; + setShapeList(b, 1); +} + +InfoLine::InfoLine(CGE2Engine *vm, uint16 w, ColorBank color) +: Talk(vm), _oldText(nullptr), _newText(nullptr), _realTime(false), _vm(vm) { + _wideSpace = false; + BitmapPtr b = new Bitmap[1]; + if (color == kCBRel) + _vm->setAutoColors(); + _color = _vm->_font->_colorSet[color]; + V2D siz = V2D(_vm, w, kFontHigh); + b[0] = Bitmap(_vm, siz.x, siz.y, _color[2]); + setShapeList(b, 1); +} + +void InfoLine::update(const char *text) { + if (!_realTime && (text == _oldText)) + return; + + _oldText = text; + + uint16 w = _ext->_shpList->_w; + uint16 h = _ext->_shpList->_h; + uint8 *v = _ext->_shpList->_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 + uint8 fg = _color[0]; + uint8 bg = _color[2]; + + // clear whole rectangle + memset(v + 2, bg, dsiz); // data bytes + for (byte *pDest = v + lsiz; pDest < (v + psiz); pDest += lsiz) { + Common::copy(v, v + lsiz, pDest); + } + *(uint16 *)(v + psiz - 2) = TO_LE_16(kBmpEOI); // plane trailer uint16 + for (byte *pDest = v + psiz; pDest < (v + 4 * psiz); pDest += psiz) { + Common::copy(v, v + psiz, pDest); + } + + // paint text line + if (_newText) { + uint8 *p = v + 2, *q = p + size; + + while (*text) { + uint16 cw = _vm->_font->_widthArr[(unsigned char)*text]; + uint8 *fp = _vm->_font->_map + _vm->_font->_pos[(unsigned char)*text]; + + // Handle properly space size, after it was enlarged to display properly + // 'F1' text. + int8 fontStart = 0; + if ((*text == 0x20) && (cw > 4) && (!_wideSpace)) + fontStart = 2; + + for (int i = fontStart; i < cw; i++) { + uint16 b = fp[i]; + for (uint16 n = 0; n < kFontHigh; n++) { + if (b & 1) + *p = fg; + b >>= 1; + p += lsiz; + } + if (p >= q) + p = p - size + 1; + } + text++; + } + } +} + +} // End of namespace CGE2 diff --git a/engines/cge2/talk.h b/engines/cge2/talk.h new file mode 100644 index 0000000000..d7484655cc --- /dev/null +++ b/engines/cge2/talk.h @@ -0,0 +1,94 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_TALK_H +#define CGE2_TALK_H + +#include "cge2/general.h" +#include "cge2/vga13h.h" + +namespace CGE2 { + +#define kTextHMargin (6&~1) // EVEN horizontal margins! +#define kTextVMargin 5 // vertical margins +#define kTextLineSpace 2 // line spacing +#define kTextRoundCorner 3 // rounded corners +#define kWidSize 256 +#define kPosSize 256 +#define kMapSize (256*8) +#define kFontHigh 8 +#define kCaptionSide 24 +#define kInfName 101 +#define kSayName 102 + +class Font { + void load(); + CGE2Engine *_vm; +public: + uint8 *_widthArr; + uint16 *_pos; + uint8 *_map; + uint8 _colorSet[kColorNum][4]; + Font(CGE2Engine *vm); + ~Font(); + uint16 width(const char *text); +}; + +enum TextBoxStyle { kTBPure, kTBRect, kTBRound }; + +class Talk : public Sprite { +protected: + TextBoxStyle _mode; + bool _created; + uint8 *box(V2D siz); + bool _wideSpace; +public: + uint8 *_color; + + Talk(CGE2Engine *vm, const char *text, TextBoxStyle mode = kTBPure, ColorBank color = kCBStd, bool wideSpace = false); + Talk(CGE2Engine *vm, ColorBank color = kCBStd); + + void update(const char *text); +private: + CGE2Engine *_vm; +}; + +class InfoLine : public Talk { + const char *_oldText, *_newText; +public: + bool _realTime; + InfoLine(CGE2Engine *vm, uint16 wid, ColorBank color = kCBStd); + void update(const char *text); + void update() { update(_newText); } + void setText(const char *txt) { _newText = txt; } +private: + CGE2Engine *_vm; +}; + +} // End of namespace CGE2 + +#endif // CGE2_TALK_H diff --git a/engines/cge2/text.cpp b/engines/cge2/text.cpp new file mode 100644 index 0000000000..d51c04843d --- /dev/null +++ b/engines/cge2/text.cpp @@ -0,0 +1,197 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge2/text.h" +#include "common/str.h" + +namespace CGE2 { + +Text::Text(CGE2Engine *vm, const char *fname) : _vm(vm) { + _vm->mergeExt(_fileName, fname, kSayExt); + if (!_vm->_resman->exist(_fileName)) + error("No talk (%s)", _fileName); + _txtCount = count(); + if (_txtCount == -1) + error("Unable to read dialog file %s", _fileName); + + _txtCount += 2; + _cache = new Handler[_txtCount]; + for (_size = 0; _size < _txtCount; _size++) { + _cache[_size]._ref = 0; + _cache[_size]._text = nullptr; + } + load(); + + _cache[_txtCount - 1]._ref = -1; + _cache[_txtCount - 1]._text = new char[3]; + strcpy(_cache[_txtCount - 1]._text, ""); +} + +Text::~Text() { + clear(); + delete[] _cache; +} + +int16 Text::count() { + EncryptedStream tf(_vm, _fileName); + if (tf.err()) + return -1; + + Common::String line; + char tmpStr[kLineMax + 1]; + + int counter = 0; + + for (line = tf.readLine(); !tf.eos(); line = tf.readLine()) { + char *s; + assert(line.size() <= 513); + Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr)); + if ((s = strtok(tmpStr, " =,;/\t\n")) == nullptr) + continue; + if (!Common::isDigit(*s)) + continue; + + counter++; + } + return counter; +} + +void Text::clear() { + for (int i = 0; i < _txtCount; i++) { + if (_cache[i]._ref) { + _cache[i]._ref = 0; + delete[] _cache[i]._text; + _cache[i]._text = nullptr; + } + } +} + +void Text::load() { + EncryptedStream tf(_vm, _fileName); + assert(!tf.err()); + + Common::String line; + char tmpStr[kLineMax + 1]; + int idx; + + for (idx = 0, line = tf.readLine(); !tf.eos(); line = tf.readLine()) { + int n = line.size(); + char *s; + Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr)); + if ((s = strtok(tmpStr, " =,;/\t\n")) == nullptr) + continue; + if (!Common::isDigit(*s)) + continue; + + int r = _vm->number(s); + + s += strlen(s); + if (s < tmpStr + n) + ++s; + + _cache[idx]._ref = r; + _cache[idx]._text = new char[strlen(s) + 1]; + strcpy(_cache[idx]._text, s); + idx++; + } +} + +char *Text::getText(int ref) { + int i; + for (i = 0; (i < _size) && (_cache[i]._ref != ref); i++) + ; + + if (i < _size) + return _cache[i]._text; + + warning("getText: Unable to find ref %d:%d", ref / 256, ref % 256); + return nullptr; +} + +void Text::say(const char *text, Sprite *spr) { + _vm->killText(); + + _vm->_talk = new Talk(_vm, text, kTBRound, kCBSay); + + Speaker *speaker = new Speaker(_vm); + + bool east = spr->_flags._east; + V2D d(_vm, 20, spr->_siz.y - 2); + if (!east) + d.x = -d.x; + if (_vm->isHero(spr)) + d = d.scale(spr->_pos3D._z.trunc()); + V2D pos = spr->_pos2D + d; + uint16 sw = (speaker->_siz.x >> 1); + if (!east) + sw = -sw; + + if (east) { + if (pos.x + sw + kTextRoundCorner + kCaptionSide >= kScrWidth) + east = false; + } else if (pos.x <= kCaptionSide + kTextRoundCorner - sw) + east = true; + + if (east != (d.x > 0)) { + d.x = -d.x; + sw = -sw; + } + pos.x = spr->_pos2D.x + d.x + sw; + + _vm->_talk->_flags._kill = true; + _vm->_talk->setName(getText(kSayName)); + _vm->_talk->gotoxyz(pos.x, pos.y + speaker->_siz.y - 1, 0); + + speaker->gotoxyz(pos.x, _vm->_talk->_pos3D._y.trunc() - speaker->_siz.y + 1, 0); + speaker->_flags._slav = true; + speaker->_flags._kill = true; + speaker->setName(getText(kSayName)); + speaker->step(east); + + _vm->_vga->_showQ->append(_vm->_talk); + _vm->_vga->_showQ->append(speaker); +} + +void CGE2Engine::inf(const char *text, ColorBank col) { + killText(); + _talk = new Talk(this, text, kTBRect, col, true); + _talk->_flags._kill = true; + _talk->setName(_text->getText(kInfName)); + _talk->center(); + _vga->_showQ->append(_talk); +} + +void Text::sayTime(Sprite *spr) { + TimeDate curTime; + _vm->_system->getTimeAndDate(curTime); + + char t[6]; + snprintf(t, 6, "%d:%02d", curTime.tm_hour, curTime.tm_min); + say(t, spr); +} + +} // End of namespace CGE2 diff --git a/engines/cge2/text.h b/engines/cge2/text.h new file mode 100644 index 0000000000..88ed501158 --- /dev/null +++ b/engines/cge2/text.h @@ -0,0 +1,68 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_TEXT_H +#define CGE2_TEXT_H + +#include "cge2/talk.h" +#include "cge2/cge2.h" + +namespace CGE2 { + +#define kSayExt ".SAY" +#define kSysTextMax 1000 +#define kTextNoMouse 95 +#define kInfName 101 +#define kSayName 102 +#define kInfRef 301 +#define kSayRef 302 + + +class Text { + struct Handler { + int _ref; + char *_text; + } *_cache; + int _size; + int16 _txtCount; + char _fileName[kPathMax]; + void load(); + int16 count(); +public: + Text(CGE2Engine *vm, const char *fname); + ~Text(); + void clear(); + char *getText(int ref); + void say(const char *text, Sprite *spr); + void sayTime(Sprite *spr); +private: + CGE2Engine *_vm; +}; + +} // End of namespace CGE2 + +#endif // CGE2_TEXT_H diff --git a/engines/cge2/toolbar.cpp b/engines/cge2/toolbar.cpp new file mode 100644 index 0000000000..6af64b1f5c --- /dev/null +++ b/engines/cge2/toolbar.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 Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "sound.h" +#include "common/config-manager.h" +#include "cge2/cge2.h" +#include "cge2/events.h" +#include "cge2/vmenu.h" +#include "cge2/text.h" +#include "cge2/cge2_main.h" + +namespace CGE2 { + +#define kSoundNumtoStateRate 25.7 +// == 257 / 10; where 10 equals to the volume switches' number of states [0..9] +// and ScummVM has a scale of 257 different values for setting sounds. + +#define kSoundStatetoNumRate 28.45 +// == 256 / 9 + 0.1; where 256 is the positive range of numbers we can set the volume to +// and the 10 states of a switch cut this range up to 9 equally big parts. +// We don't take into account 0 regarding the 256 different values (it would be the 257th), +// since 0 * x == 0. +// 0.1 is only for correct rounding at the 10th state. + +void CGE2Engine::optionTouch(int opt, uint16 mask) { + bool notMuted = !ConfMan.getBool("mute"); + switch (opt) { + case 1: + if (mask & kMouseLeftUp) + switchColorMode(); + break; + case 2: + if ((mask & kMouseLeftUp) && notMuted) + switchMusic(); + break; + case 3: + if (mask & kMouseLeftUp) + quit(); + break; + case 4: + if ((mask & (kMouseLeftUp | kMouseRightUp)) && notMuted) + setVolume(opt - 4, (mask & kMouseLeftUp) ? 1 : -1); + break; + case 5: + if ((mask & (kMouseLeftUp | kMouseRightUp)) && notMuted) + setVolume(opt - 4, (mask & kMouseLeftUp) ? 1 : -1); + break; + case 8: + if ((mask & kMouseLeftUp) && notMuted) + switchCap(); + break; + case 9: + if ((mask & kMouseLeftUp) && notMuted) + switchVox(); + break; + default: + break; + } +} + +void CGE2Engine::switchColorMode() { + _commandHandlerTurbo->addCommand(kCmdSeq, 121, _vga->_mono = !_vga->_mono, nullptr); + ConfMan.setBool("enable_color_blind", _vga->_mono); + ConfMan.flushToDisk(); + keyClick(); + _vga->setColors(_vga->_sysPal, 64); +} + +void CGE2Engine::switchMusic() { + _music = !_music; + _mixer->muteSoundType(Audio::Mixer::kMusicSoundType, !_music); + _commandHandlerTurbo->addCommand(kCmdSeq, kMusicRef, _music, nullptr); + keyClick(); + _commandHandlerTurbo->addCommand(kCmdMidi, -1, _music ? (_now << 8) : -1, nullptr); +} + +void CGE2Engine::quit() { + if (_commandHandler->idle()) { + if (VMenu::_addr) { + _commandHandlerTurbo->addCommand(kCmdKill, -1, 0, VMenu::_addr); + ReturnToGameChoice rqsChoice(this); + rqsChoice.proc(); + } else { + Common::Array<Choice *> quitMenu; // Deleted in VMenu's destructor. + quitMenu.push_back(new ExitGameChoice(this)); + quitMenu.push_back(new ReturnToGameChoice(this)); + (new VMenu(this, quitMenu, V2D(this, -1, -1), kCBMnu))->setName(_text->getText(kQuitTitle)); + _commandHandlerTurbo->addCommand(kCmdSeq, kPowerRef, 0, nullptr); + keyClick(); + } + } +} + +void CGE2Engine::setVolume(int idx, int cnt) { + if (cnt && _vol[idx]) { + int p = _vol[idx]->_seqPtr + cnt; + if ((p >= 0) && (p < _vol[idx]->_seqCnt)) { + _vol[idx]->step(p); + int newVolume = p * kSoundStatetoNumRate; + switch (idx) { + case 0: + _oldSfxVolume = ConfMan.getInt("sfx_volume"); + ConfMan.setInt("sfx_volume", newVolume); + break; + case 1: + _oldMusicVolume = ConfMan.getInt("music_volume"); + ConfMan.setInt("music_volume", newVolume); + break; + default: + break; + } + } + } +} + +void CGE2Engine::checkVolumeSwitches() { + int musicVolume = ConfMan.getInt("music_volume"); + if (musicVolume != _oldMusicVolume) + _vol[1]->step(musicVolume / kSoundNumtoStateRate); + + int sfxVolume = ConfMan.getInt("sfx_volume"); + if (sfxVolume != _oldSfxVolume) + _vol[0]->step(sfxVolume / kSoundNumtoStateRate); +} + +void CGE2Engine::switchCap() { + _sayCap = !_sayCap; + if (!_sayCap) + _sayVox = true; + keyClick(); + switchSay(); +} + +void CGE2Engine::switchVox() { + _sayVox = !_sayVox; + _mixer->muteSoundType(Audio::Mixer::kSpeechSoundType, _sayVox); + if (!_sayVox) + _sayCap = true; + keyClick(); + switchSay(); +} + +void CGE2Engine::switchSay() { + _commandHandlerTurbo->addCommand(kCmdSeq, 129, _sayVox, nullptr); + _commandHandlerTurbo->addCommand(kCmdSeq, 128, _sayCap, nullptr); +} + +void CGE2Engine::initToolbar() { + selectPocket(-1); + + _commandHandlerTurbo->addCommand(kCmdSeq, kMusicRef, _music, nullptr); + if (!_music) + _midiPlayer->killMidi(); + + switchSay(); + + _infoLine->gotoxyz(V3D(kInfoX, kInfoY, 0)); + _infoLine->setText(nullptr); + _vga->_showQ->insert(_infoLine); + + _gamePhase = kPhaseInGame; + _mouse->center(); + _mouse->off(); + _mouse->on(); + + _keyboard->setClient(_sys); + _commandHandler->addCommand(kCmdSeq, kPowerRef, 1, nullptr); + + _busyPtr = _vga->_showQ->locate(kBusyRef); + + _vol[0] = _vga->_showQ->locate(kDvolRef); + _vol[1] = _vga->_showQ->locate(kMvolRef); + + if (_vol[0]) { + int val = ConfMan.getInt("sfx_volume"); + initVolumeSwitch(_vol[0], val); + } + + if (_vol[1]) { + int val = ConfMan.getInt("music_volume"); + initVolumeSwitch(_vol[1], val); + } +} + +void CGE2Engine::initVolumeSwitch(Sprite *volSwitch, int val) { + int state = 0; + state = val / kSoundNumtoStateRate; + volSwitch->step(state); +} + +void CGE2Engine::checkMute() { + bool mute = ConfMan.getBool("mute"); + bool mutedChanged = mute != _muteAll; + if (mutedChanged) { + switchMusic(); + switchVox(); + _muteAll = mute; + } +} + +} // End of namespace CGE2 diff --git a/engines/cge2/vga13h.cpp b/engines/cge2/vga13h.cpp new file mode 100644 index 0000000000..db96682237 --- /dev/null +++ b/engines/cge2/vga13h.cpp @@ -0,0 +1,1218 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "common/array.h" +#include "common/config-manager.h" +#include "common/rect.h" +#include "graphics/palette.h" +#include "cge2/general.h" +#include "cge2/vga13h.h" +#include "cge2/bitmap.h" +#include "cge2/text.h" +#include "cge2/cge2_main.h" +#include "cge2/cge2.h" +#include "cge2/vga13h.h" + +namespace CGE2 { + +void V3D::sync(Common::Serializer &s) { + _x.sync(s); + _y.sync(s); + _z.sync(s); +} + +FXP FXP::operator*(const FXP& x) const { + FXP y; + int32 t1 = (v >> 8) * x.v; + int32 t2 = ((v & 0xFF) * x.v) >> 8; + + y.v = t1 + t2; + return y; +} + +FXP FXP::operator/(const FXP& x) const { + FXP y; + if (x.v != 0) { + int32 v1 = this->v; + int32 v2 = x.v; + bool negFlag = false; + + if (v1 < 0) { + v1 = -v1; + negFlag = true; + } + if (v2 < 0) { + v2 = -v2; + negFlag ^= true; + } + + int32 v3 = v1 / v2; + v1 -= v3 * v2; + v3 <<= 8; + + if (v1 < 0xFFFFFF) + v1 <<= 8; + else + v2 >>= 8; + + v3 += v1 / v2; + + if (negFlag) + v3 = -v3; + + y.v = v3; + } + + return y; +} + +void FXP::sync(Common::Serializer &s) { + s.syncAsSint32LE(v); +} + +Seq *getConstantSeq(bool seqFlag) { + const Seq seq1[] = { { 0, 0, 0, 0, 0, 0 } }; + const Seq seq2[] = { { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0 } }; + + Seq *seq; + if (seqFlag) { + seq = (Seq *)malloc(1 * sizeof(Seq)); + *seq = seq1[0]; + } else { + seq = (Seq *)malloc(2 * sizeof(Seq)); + seq[0] = seq2[0]; + seq[1] = seq2[1]; + } + + return seq; +} + +byte Sprite::_constY = 0; +byte Sprite::_follow = 0; + +Seq Sprite::_stdSeq8[] = +{ { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0 }, + { 3, 3, 0, 0, 0, 0 }, + { 4, 4, 0, 0, 0, 0 }, + { 5, 5, 0, 0, 0, 0 }, + { 6, 6, 0, 0, 0, 0 }, + { 7, 7, 0, 0, 0, 0 }, +}; + +SprExt::SprExt(CGE2Engine *vm) + : _p0(vm, 0, 0), _p1(vm, 0, 0), + _b0(nullptr), _b1(nullptr), _shpList(nullptr), + _location(0), _seq(nullptr), _name(nullptr) { + for (int i = 0; i < kActions; i++) + _actions[i] = nullptr; +} + +Sprite::Sprite(CGE2Engine *vm) + : _siz(_vm, 0, 0), _seqPtr(kNoSeq), _seqCnt(0), _shpCnt(0), + _next(nullptr), _prev(nullptr), _time(0), + _ext(nullptr), _ref(-1), _scene(0), _vm(vm), + _pos2D(_vm, kScrWidth >> 1, 0), _pos3D(kScrWidth >> 1, 0, 0) { + memset(_actionCtrl, 0, sizeof(_actionCtrl)); + memset(_file, 0, sizeof(_file)); + memset(&_flags, 0, sizeof(_flags)); + _flags._frnt = 1; +} + +Sprite::Sprite(CGE2Engine *vm, BitmapPtr shpP, int cnt) + : _siz(_vm, 0, 0), _seqPtr(kNoSeq), _seqCnt(0), _shpCnt(0), + _next(nullptr), _prev(nullptr), _time(0), + _ext(nullptr), _ref(-1), _scene(0), _vm(vm), + _pos2D(_vm, kScrWidth >> 1, 0), _pos3D(kScrWidth >> 1, 0, 0) { + memset(_actionCtrl, 0, sizeof(_actionCtrl)); + memset(_file, 0, sizeof(_file)); + memset(&_flags, 0, sizeof(_flags)); + _flags._frnt = 1; + + setShapeList(shpP, cnt); +} + +Sprite::~Sprite() { + contract(); +} + +BitmapPtr Sprite::getShp() { + SprExt *e = _ext; + if (!e || !e->_seq) + return nullptr; + + int i = e->_seq[_seqPtr]._now; + if (i >= _shpCnt) + error("Invalid PHASE in SPRITE::Shp() %s - %d", _file, i); + return e->_shpList + i; +} + +void Sprite::setShapeList(BitmapPtr shp, int cnt) { + _shpCnt = cnt; + _siz.x = 0; + _siz.y = 0; + + if (shp) { + for (int i = 0; i < cnt; i++) { + BitmapPtr p = shp + i; + if (p->_w > _siz.x) + _siz.x = p->_w; + if (p->_h > _siz.y) + _siz.y = p->_h; + } + expand(); + _ext->_shpList = shp; + if (!_ext->_seq) { + setSeq(_stdSeq8); + _seqCnt = (cnt < ARRAYSIZE(_stdSeq8)) ? cnt : ARRAYSIZE(_stdSeq8); + } + } +} + +Seq *Sprite::setSeq(Seq *seq) { + expand(); + + Seq *s = _ext->_seq; + _ext->_seq = seq; + if (_seqPtr == kNoSeq) + step(0); + else if (_time == 0) + step(_seqPtr); + return s; +} + +bool Sprite::seqTest(int n) { + if (n >= 0) + return (_seqPtr == n); + if (_ext) + return (_ext->_seq[_seqPtr]._next == _seqPtr); + return true; +} + +void Sprite::setName(char *newName) { + if (!_ext) + return; + + if (_ext->_name) { + delete[] _ext->_name; + _ext->_name = nullptr; + } + if (newName) { + _ext->_name = new char[strlen(newName) + 1]; + strcpy(_ext->_name, newName); + } +} + +int Sprite::labVal(Action snq, int lab) { + int lv = -1; + if (active()) { + int count = _actionCtrl[snq]._cnt; + CommandHandler::Command *com = snList(snq); + + int i = 0; + for (; i < count; i++) { + if (com[i]._lab == lab) + break; + } + + if (i < count) + return i; + } else { + char tmpStr[kLineMax + 1]; + _vm->mergeExt(tmpStr, _file, kSprExt); + + if (_vm->_resman->exist(tmpStr)) { // sprite description file exist + EncryptedStream sprf(_vm, tmpStr); + if (sprf.err()) + error("Bad SPR [%s]", tmpStr); + + int cnt = 0; + ID section = kIdPhase; + ID id; + Common::String line; + + while (lv == -1 && !sprf.eos()) { + line = sprf.readLine(); + if (line.empty()) + continue; + + Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr)); + + char *p; + p = _vm->token(tmpStr); + + if (*p == '@') { + if ((int)section == (int)snq && atoi(p + 1) == lab) + lv = cnt; + } else { + id = _vm->ident(p); + switch (id) { + case kIdMTake: + case kIdFTake: + case kIdNear: + case kIdPhase: + case kIdSeq: + section = id; + break; + default: + if (id < 0 && (int)section == (int)snq) + ++cnt; + break; + } + } + } + } + } + return lv; +} + +CommandHandler::Command *Sprite::snList(Action type) { + SprExt *e = _ext; + return (e) ? e->_actions[type] : nullptr; +} + +Sprite *Sprite::expand() { + if (_ext) + return this; + + if (_vm->_spriteNotify != nullptr) + (_vm->*_vm->_spriteNotify)(); + + char fname[kPathMax]; + _vm->mergeExt(fname, _file, kSprExt); + + if (_ext != nullptr) + delete _ext; + _ext = new SprExt(_vm); + + if (!*_file) + return this; + + BitmapPtr shplist = new Bitmap[_shpCnt]; + + int cnt[kActions], + shpcnt = 0, + seqcnt = 0, + maxnow = 0, + maxnxt = 0; + + for (int i = 0; i < kActions; i++) + cnt[i] = 0; + + for (int i = 0; i < kActions; i++){ + byte n = _actionCtrl[i]._cnt; + if (n) + _ext->_actions[i] = new CommandHandler::Command[n]; + else + _ext->_actions[i] = nullptr; + } + + Seq *curSeq = nullptr; + if (_seqCnt) + curSeq = new Seq[_seqCnt]; + + if (_vm->_resman->exist(fname)) { // sprite description file exist + EncryptedStream sprf(_vm, fname); + if (sprf.err()) + error("Bad SPR [%s]", fname); + + int label = kNoByte; + ID section = kIdPhase; + ID id; + Common::String line; + char tmpStr[kLineMax + 1]; + + for (line = sprf.readLine(); !sprf.eos(); line = sprf.readLine()) { + if (line.empty()) + continue; + Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr)); + + char *p = _vm->token(tmpStr); + if (*p == '@') { + label = atoi(p + 1); + continue; + } + + id = _vm->ident(p); + switch (id) { + case kIdType: + break; + case kIdNear: + case kIdMTake: + case kIdFTake: + case kIdPhase: + case kIdSeq: + section = id; + break; + case kIdName: + Common::strlcpy(tmpStr, line.c_str(), sizeof(tmpStr)); + for (p = tmpStr; *p != '='; p++); // We search for the = + setName(_vm->tail(p)); + break; + default: + if (id >= kIdNear) + break; + Seq *s; + switch (section) { + case kIdNear: + case kIdMTake: + case kIdFTake: + id = (ID)_vm->_commandHandler->getComId(p); + if (_actionCtrl[section]._cnt) { + CommandHandler::Command *c = &_ext->_actions[section][cnt[section]++]; + c->_commandType = CommandType(id); + c->_lab = label; + c->_ref = _vm->number(nullptr); + c->_val = _vm->number(nullptr); + c->_spritePtr = nullptr; + } + break; + case kIdSeq: + s = &curSeq[seqcnt++]; + s->_now = atoi(p); + if (s->_now > maxnow) + maxnow = s->_now; + s->_next = _vm->number(nullptr); + 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 = _vm->number(nullptr); + s->_dy = _vm->number(nullptr); + s->_dz = _vm->number(nullptr); + s->_dly = _vm->number(nullptr); + break; + case kIdPhase: + shplist[shpcnt] = Bitmap(_vm, p); + shpcnt++; + break; + default: + break; + } + break; + } + label = kNoByte; + } + + if (!shpcnt) + error("No shapes - %s", fname); + } else // no sprite description: try to read immediately from .BMP + shplist[shpcnt++] = Bitmap(_vm, _file); + + if (curSeq) { + if (maxnow >= shpcnt) + error("Bad PHASE in SEQ %s", fname); + if (maxnxt && (maxnxt >= seqcnt)) + error("Bad JUMP in SEQ %s", fname); + setSeq(curSeq); + } else { + setSeq(_stdSeq8); + _seqCnt = (shpcnt < ARRAYSIZE(_stdSeq8)) ? shpcnt : ARRAYSIZE(_stdSeq8); + } + + setShapeList(shplist, shpcnt); + + if (_file[2] == '~') { // FLY-type sprite + Seq *nextSeq = _ext->_seq; + int x = (nextSeq + 1)->_dx, y = (nextSeq + 1)->_dy, z = (nextSeq + 1)->_dz; + // random position + nextSeq->_dx = _vm->newRandom(x + x) - x; + nextSeq->_dy = _vm->newRandom(y + y) - y; + nextSeq->_dz = _vm->newRandom(z + z) - z; + gotoxyz(_pos3D + V3D(nextSeq->_dx, nextSeq->_dy, nextSeq->_dz)); + } + + return this; +} + +Sprite *Sprite::contract() { + SprExt *e = _ext; + if (!e) + return this; + + if (_file[2] == '~') { // FLY-type sprite + Seq *curSeq = _ext->_seq; + // return to middle + gotoxyz(_pos3D - V3D(curSeq->_dx, curSeq->_dy, curSeq->_dz)); + curSeq->_dx = curSeq->_dy = curSeq->_dz = 0; + } + + if (_vm->_spriteNotify != nullptr) + (_vm->*_vm->_spriteNotify)(); + + if (e->_name) { + delete[] e->_name; + e->_name = nullptr; + } + + if (e->_shpList) { + for (int i = 0; i < _shpCnt; i++) + e->_shpList[i].release(); + delete[] e->_shpList; + e->_shpList = nullptr; + } + + if (e->_seq) { + if (e->_seq == _stdSeq8) + _seqCnt = 0; + else { + delete[] e->_seq; + e->_seq = nullptr; + } + } + + for (int i = 0; i < kActions; i++) { + if (e->_actions[i]) { + delete[] e->_actions[i]; + e->_actions[i] = nullptr; + } + } + + delete _ext; + _ext = nullptr; + + return this; +} + +void Sprite::backShow() { + expand(); + show(2); + show(1); + _vm->_spare->dispose(this); +} + +void Sprite::step(int nr) { + if (nr >= 0) + _seqPtr = nr; + + if (_ext && _ext->_seq) { + V3D p = _pos3D; + Seq *seq = nullptr; + + if (nr < 0) + _seqPtr = _ext->_seq[_seqPtr]._next; + + if (_file[2] == '~') { // FLY-type sprite + seq = _ext->_seq; + // return to middle + p._x -= seq->_dx; + p._y -= seq->_dy; + p._z -= seq->_dz; + // generate motion + if (_vm->newRandom(10) < 5) { + if ((seq + 1)->_dx) + seq->_dx += _vm->newRandom(3) - 1; + if ((seq + 1)->_dy) + seq->_dy += _vm->newRandom(3) - 1; + if ((seq + 1)->_dz) + seq->_dz += _vm->newRandom(3) - 1; + } + if (seq->_dx < -(seq + 1)->_dx) + seq->_dx += 2; + if (seq->_dx >= (seq + 1)->_dx) + seq->_dx -= 2; + if (seq->_dy < -(seq + 1)->_dy) + seq->_dy += 2; + if (seq->_dy >= (seq + 1)->_dy) + seq->_dy -= 2; + if (seq->_dz < -(seq + 1)->_dz) + seq->_dz += 2; + if (seq->_dz >= (seq + 1)->_dz) + seq->_dz -= 2; + p._x += seq->_dx; + p._y += seq->_dy; + p._z += seq->_dz; + gotoxyz(p); + } else { + seq = _ext->_seq + _seqPtr; + if (seq) { + if (seq->_dz == 127 && seq->_dx != 0) { + _vm->_commandHandlerTurbo->addCommand(kCmdSound, -1, 256 * seq->_dy + seq->_dx, this); + } else { + p._x += seq->_dx; + p._y += seq->_dy; + p._z += seq->_dz; + gotoxyz(p); + } + } + } + if (seq && (seq->_dly >= 0)) + _time = seq->_dly; + } else if (_vm->_waitRef && _vm->_waitRef == _ref) + _vm->_waitRef = 0; +} + +void Sprite::tick() { + step(); +} + +void Sprite::setScene(int c) { + _scene = c; +} + +void Sprite::gotoxyz(int x, int y, int z) { + gotoxyz(V3D(x, y, z)); +} + +void Sprite::gotoxyz() { + gotoxyz(_pos3D); +} + +void Sprite::gotoxyz(V2D pos) { + V2D o = _pos2D; + int ctr = _siz.x >> 1; + int rem = _siz.x - ctr; + byte trim = 0; + + if (_ref / 10 == 14) { // HERO + int z = _pos3D._z.trunc(); + ctr = (ctr * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z); + rem = (rem * _vm->_eye->_z.trunc()) / (_vm->_eye->_z.trunc() - z); + ctr = (ctr * 3) / 4; + rem = (rem * 3) / 4; + } + + if (pos.x - ctr < 0) { + pos.x = ctr; + ++trim; + } + if (pos.x + rem > kScrWidth) { + pos.x = kScrWidth - rem; + ++trim; + } + _pos2D.x = pos.x; + + if (pos.y < -kPanHeight) { + pos.y = -kPanHeight; + ++trim; + } + if (pos.y + _siz.y > kWorldHeight) { + pos.y = kWorldHeight - _siz.y; + ++trim; + } + _pos2D.y = pos.y; + + _flags._trim = (trim != 0); + + if (!_follow) { + FXP m = _vm->_eye->_z / (_pos3D._z - _vm->_eye->_z); + _pos3D._x = (_vm->_eye->_x + (_vm->_eye->_x - _pos2D.x) / m); + _pos3D._x.round(); + + if (!_constY) { + _pos3D._y = _vm->_eye->_y + (_vm->_eye->_y - _pos2D.y) / m; + _pos3D._y.round(); + } + } + + if (_next && _next->_flags._slav) + _next->gotoxyz(_next->_pos2D - o + _pos2D); + + if (_flags._shad) + _prev->gotoxyz(_prev->_pos2D - o + _pos2D); +} + +void Sprite::gotoxyz_(V2D pos) { + _constY++; + gotoxyz(pos); + --_constY; +} + +void Sprite::gotoxyz(V3D pos) { + _follow++; + if (pos._z != _pos3D._z) + _flags._zmov = true; + gotoxyz(V2D(_vm, _pos3D = pos)); + --_follow; +} + +void Sprite::center() { + gotoxyz(kScrWidth >> 1, (kWorldHeight - _siz.y) >> 1, 0); +} + +void Sprite::show() { + SprExt *e = _ext; + if (e) { + e->_p0 = e->_p1; + e->_b0 = e->_b1; + e->_p1 = _pos2D; + e->_b1 = getShp(); + + if (!_flags._hide) + e->_b1->show(e->_p1); + } +} + +void Sprite::show(uint16 pg) { + assert(pg < 4); + Graphics::Surface *a = _vm->_vga->_page[1]; + _vm->_vga->_page[1] = _vm->_vga->_page[pg]; + getShp()->show(_pos2D); + _vm->_vga->_page[1] = a; +} + +void Sprite::hide() { + SprExt *e = _ext; + if (e->_b0) + e->_b0->hide(e->_p0); +} + +BitmapPtr Sprite::ghost() { + SprExt *e = _ext; + if (!e->_b1) + return nullptr; + + BitmapPtr bmp = new Bitmap(_vm, 0, 0, (uint8 *)nullptr); + bmp->_w = e->_b1->_w; + bmp->_h = e->_b1->_h; + bmp->_b = new HideDesc[bmp->_h]; + memcpy(bmp->_b, e->_b1->_b, sizeof(HideDesc)* bmp->_h); + uint8 *v = new uint8[1]; + *v = (e->_p1.y << 16) + e->_p1.x; + bmp->_v = v; + bmp->_map = (e->_p1.y << 16) + e->_p1.x; + + return bmp; +} + +void Sprite::sync(Common::Serializer &s) { + s.syncAsUint16LE(_ref); + s.syncAsByte(_scene); + + // bitfield in-memory storage is unpredictable, so to avoid + // any issues, pack/unpack everything manually + uint16 flags = 0; + if (s.isLoading()) { + s.syncAsUint16LE(flags); + _flags._hide = flags & 0x0001; + _flags._drag = flags & 0x0002; + _flags._hold = flags & 0x0004; + _flags._trim = flags & 0x0008; + _flags._slav = flags & 0x0010; + _flags._kill = flags & 0x0020; + _flags._xlat = flags & 0x0040; + _flags._port = flags & 0x0080; + _flags._kept = flags & 0x0100; + _flags._frnt = flags & 0x0200; + _flags._east = flags & 0x0400; + _flags._near = flags & 0x0800; + _flags._shad = flags & 0x1000; + _flags._back = flags & 0x2000; + _flags._zmov = flags & 0x4000; + _flags._tran = flags & 0x8000; + } else { + flags = (flags << 1) | (_flags._tran ? 1 : 0); + flags = (flags << 1) | (_flags._zmov ? 1 : 0); + flags = (flags << 1) | (_flags._back ? 1 : 0); + flags = (flags << 1) | (_flags._shad ? 1 : 0); + flags = (flags << 1) | (_flags._near ? 1 : 0); + flags = (flags << 1) | (_flags._east ? 1 : 0); + flags = (flags << 1) | (_flags._frnt ? 1 : 0); + flags = (flags << 1) | (_flags._kept ? 1 : 0); + flags = (flags << 1) | (_flags._port ? 1 : 0); + flags = (flags << 1) | (_flags._xlat ? 1 : 0); + flags = (flags << 1) | (_flags._kill ? 1 : 0); + flags = (flags << 1) | (_flags._slav ? 1 : 0); + flags = (flags << 1) | (_flags._trim ? 1 : 0); + flags = (flags << 1) | (_flags._hold ? 1 : 0); + flags = (flags << 1) | (_flags._drag ? 1 : 0); + flags = (flags << 1) | (_flags._hide ? 1 : 0); + s.syncAsUint16LE(flags); + } + + s.syncAsSint16LE(_pos2D.x); + s.syncAsSint16LE(_pos2D.y); + + _pos3D.sync(s); + + s.syncAsSint16LE(_siz.x); + s.syncAsSint16LE(_siz.y); + + s.syncAsUint16LE(_time); + for (int i = 0; i < kActions; i++){ + s.syncAsByte(_actionCtrl[i]._ptr); + s.syncAsByte(_actionCtrl[i]._cnt); + } + s.syncAsSint16LE(_seqPtr); + s.syncAsSint16LE(_seqCnt); + s.syncAsUint16LE(_shpCnt); + s.syncBytes((byte *)&_file[0], 9); + _file[8] = '\0'; +} + +Queue::Queue(bool show) : _head(nullptr), _tail(nullptr) { +} + +void Queue::append(Sprite *spr) { + if (spr->_flags._back) + spr->backShow(); + else { + spr->expand(); + if (_tail) { + spr->_prev = _tail; + _tail->_next = spr; + } else + _head = spr; + + _tail = spr; + } +} + +void Queue::insert(Sprite *spr, Sprite *nxt) { + if (spr->_flags._back) + spr->backShow(); + else { + spr->expand(); + if (nxt == _head) { + spr->_next = _head; + _head = spr; + if (!_tail) + _tail = spr; + } else { + spr->_next = nxt; + spr->_prev = nxt->_prev; + if (spr->_prev) + spr->_prev->_next = spr; + } + if (spr->_next) + spr->_next->_prev = spr; + } +} + +void Queue::insert(Sprite *spr) { + if (locate(spr)) + return; // We only queue it if it's not already queued. + + Sprite *s; + for (s = _head; s; s = s->_next) { + if (s->_pos3D._z < spr->_pos3D._z) + break; + } + + if (s) + insert(spr, s); + else + append(spr); +} + +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 = nullptr; + spr->_next = nullptr; + return spr; +} + +Sprite *Queue::locate(int ref) { + for (Sprite *spr = _head; spr; spr = spr->_next) { + if (spr->_ref == ref) + return spr; + } + return nullptr; +} + +bool Queue::locate(Sprite *spr) { + Sprite *s; + for (s = _head; s; s = s->_next) { + if (s == spr) + return true; + } + + return false; +} + +Vga::Vga(CGE2Engine *vm) : _frmCnt(0), _msg(nullptr), _name(nullptr), _setPal(false), _vm(vm) { + _rot._org = 1; + _rot._len = 0; + _rot._cnt = 0; + _rot._dly = 1; + + _oldColors = nullptr; + _newColors = nullptr; + _showQ = new Queue(true); + _sysPal = new Dac[kPalCount]; + + for (int idx = 0; idx < 4; idx++) { + _page[idx] = new Graphics::Surface(); + _page[idx]->create(kScrWidth, kScrHeight, Graphics::PixelFormat::createFormatCLUT8()); + } + + _mono = ConfMan.getBool("enable_color_blind"); + + _oldColors = (Dac *)malloc(sizeof(Dac) * kPalCount); + _newColors = (Dac *)malloc(sizeof(Dac) * kPalCount); + getColors(_oldColors); + sunset(); + setColors(); + clear(0); +} + +Vga::~Vga() { + Common::String buffer = ""; + + free(_oldColors); + free(_newColors); + if (_msg) + buffer = Common::String(_msg); + + if (_name) + buffer = buffer + " [" + _name + "]"; + + debugN("%s", buffer.c_str()); + + delete _showQ; + delete[] _sysPal; + + for (int idx = 0; idx < 4; idx++) { + _page[idx]->free(); + delete _page[idx]; + } +} + +void Vga::waitVR() { + // Since some of the game parts rely on using vertical sync as a delay mechanism, + // we're introducing a short delay to simulate it + g_system->delayMillis(5); +} + +void Vga::getColors(Dac *tab) { + byte palData[kPalSize]; + g_system->getPaletteManager()->grabPalette(palData, 0, kPalCount); + palToDac(palData, tab); +} + +uint8 Vga::closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB) { +#define f(col, lum) ((((uint16)(col)) << 8) / lum) + uint16 i, dif = 0xFFFF, found = 0; + uint16 L = colR + colG + colB; + if (!L) + L++; + uint16 R = f(colR, L), G = f(colG, L), B = f(colB, L); + for (i = 0; i < 256; i++) { + uint16 l = pal[i]._r + pal[i]._g + pal[i]._b; + if (!l) + l++; + int r = f(pal[i]._r, l), g = f(pal[i]._g, l), b = f(pal[i]._b, l); + uint16 D = ((r > R) ? (r - R) : (R - r)) + + ((g > G) ? (g - G) : (G - g)) + + ((b > B) ? (b - B) : (B - b)) + + ((l > L) ? (l - L) : (L - l)) * 10 ; + + if (D < dif) { + found = i; + dif = D; + if (D == 0) + break; // exact! + } + } + return found; +#undef f +} + +uint8 Vga::closest(Dac *pal, Dac x) { + int exp = (sizeof(long) * 8 - 1); + long D = (1 << exp) - 1; // Maximum value of long. + long R = x._r; + long G = x._g; + long B = x._b; + int idx = 255; + for (int n = 0; n < 256; n++) { + long dR = R - pal[n]._r; + long dG = G - pal[n]._g; + long dB = B - pal[n]._b, + d = dR * dR + dG * dG + dB * dB; + if (d < D) { + idx = n; + D = d; + if (!d) + break; + } + } + return idx; +} + +uint8 *Vga::glass(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB) { + uint8 *x = (uint8 *)malloc(256); + if (x) { + for (uint16 i = 0; i < 256; i++) { + x[i] = closest(pal, ((uint16)(pal[i]._r) * colR) / 255, + ((uint16)(pal[i]._g) * colG) / 255, + ((uint16)(pal[i]._b) * colB) / 255); + } + } + return x; +} + +void Vga::palToDac(const byte *palData, Dac *tab) { + const byte *colP = palData; + for (int idx = 0; idx < kPalCount; idx++, colP += 3) { + tab[idx]._r = *colP >> 2; + tab[idx]._g = *(colP + 1) >> 2; + tab[idx]._b = *(colP + 2) >> 2; + } +} + +void Vga::dacToPal(const Dac *tab, byte *palData) { + for (int idx = 0; idx < kPalCount; idx++, palData += 3) { + *palData = tab[idx]._r << 2; + *(palData + 1) = tab[idx]._g << 2; + *(palData + 2) = tab[idx]._b << 2; + } +} + +void Vga::setColors(Dac *tab, int lum) { + Dac *palP = tab, *destP = _newColors; + for (int idx = 0; idx < kPalCount; idx++, palP++, destP++) { + destP->_r = (palP->_r * lum) >> 6; + destP->_g = (palP->_g * lum) >> 6; + destP->_b = (palP->_b * lum) >> 6; + } + + if (_mono) { + destP = _newColors; + for (int idx = 0; idx < kPalCount; idx++, destP++) { + // Form a grayscale color from 30% R, 59% G, 11% B + uint8 intensity = (((int)destP->_r * 77) + ((int)destP->_g * 151) + ((int)destP->_b * 28)) >> 8; + destP->_r = intensity; + destP->_g = intensity; + destP->_b = intensity; + } + } + + _setPal = true; +} + +void Vga::setColors() { + memset(_newColors, 0, kPalSize); + updateColors(); +} + +void Vga::sunrise(Dac *tab) { + for (int i = 0; i <= 64; i += kFadeStep) { + setColors(tab, i); + waitVR(); + updateColors(); + g_system->updateScreen(); + } +} + +void Vga::sunset() { + Dac tab[256]; + getColors(tab); + for (int i = 64; i >= 0; i -= kFadeStep) { + setColors(tab, i); + waitVR(); + updateColors(); + g_system->updateScreen(); + } +} + +void Vga::show() { + _vm->_infoLine->update(); + + for (Sprite *spr = _showQ->first(); spr; spr = spr->_next) { + spr->show(); + } + + _vm->_mouse->show(); + update(); + rotate(); + + for (Sprite *spr = _showQ->first(); spr; spr = spr->_next) { + spr->hide(); + if (spr->_flags._zmov) { + Sprite *s = nullptr; + Sprite *p = spr->_prev; + Sprite *n = spr->_next; + + if (spr->_flags._shad) { + s = p; + p = s->_prev; + } + + if ((p && spr->_pos3D._z > p->_pos3D._z) || + (n && spr->_pos3D._z < n->_pos3D._z)) { + _showQ->insert(_showQ->remove(spr)); + } + spr->_flags._zmov = false; + } + } + _vm->_mouse->hide(); +} + +void Vga::updateColors() { + byte palData[kPalSize]; + dacToPal(_newColors, palData); + g_system->getPaletteManager()->setPalette(palData, 0, 256); +} + +void Vga::update() { + SWAP(Vga::_page[0], Vga::_page[1]); + + if (_setPal) { + updateColors(); + _setPal = false; + } + + g_system->copyRectToScreen(Vga::_page[0]->getPixels(), kScrWidth, 0, 0, kScrWidth, kScrHeight); + g_system->updateScreen(); +} + +void Vga::rotate() { + if (_rot._len) { + Dac c; + getColors(_newColors); + c = _newColors[_rot._org]; + memmove(_newColors + _rot._org, _newColors + _rot._org + 1, (_rot._len - 1) * sizeof(Dac)); + _newColors[_rot._org + _rot._len - 1] = c; + _setPal = true; + } +} + +void Vga::clear(uint8 color) { + for (int paneNum = 0; paneNum < 4; paneNum++) + _page[paneNum]->fillRect(Common::Rect(0, 0, kScrWidth, kScrHeight), color); +} + +void Vga::copyPage(uint16 d, uint16 s) { + _page[d]->copyFrom(*_page[s]); +} + +void Bitmap::show(V2D pos) { + xLatPos(pos); + + const byte *srcP = (const byte *)_v; + byte *screenStartP = (byte *)_vm->_vga->_page[1]->getPixels(); + byte *screenEndP = (byte *)_vm->_vga->_page[1]->getBasePtr(0, kScrHeight); + + // Loop through processing data for each plane. The game originally ran in plane mapped mode, where a + // given plane holds each fourth pixel sequentially. So to handle an entire picture, each plane's data + // must be decompressed and inserted into the surface + for (int planeCtr = 0; planeCtr < 4; planeCtr++) { + byte *destP = (byte *)_vm->_vga->_page[1]->getBasePtr(pos.x + planeCtr, pos.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; + } + + // Handle a set of pixels + while (count-- > 0) { + // Transfer operation + switch (cmd) { + case 1: + // SKIP + break; + case 2: + // REPEAT + if (destP >= screenStartP && destP < screenEndP) + *destP = *srcP; + break; + case 3: + // COPY + if (destP >= screenStartP && destP < screenEndP) + *destP = *srcP; + srcP++; + break; + } + + // Move to next dest position + destP += 4; + } + + if (cmd == 2) + srcP++; + } + } +} + +void Bitmap::hide(V2D pos) { + xLatPos(pos); + + // Perform clipping to screen + int w = MIN<int>(_w, kScrWidth - pos.x); + int h = MIN<int>(_h, kScrHeight - pos.y); + if (pos.x < 0) { + w -= -pos.x; + pos.x = 0; + if (w < 0) + return; + } + if (pos.y < 0) { + h -= -pos.y; + pos.y = 0; + if (h < 0) + return; + } + + // Perform copying of screen section + for (int yp = pos.y; yp < pos.y + h; yp++) { + if (yp >= 0 && yp < kScrHeight) { + const byte *srcP = (const byte *)_vm->_vga->_page[2]->getBasePtr(pos.x, yp); + byte *destP = (byte *)_vm->_vga->_page[1]->getBasePtr(pos.x, yp); + + Common::copy(srcP, srcP + w, destP); + } + } +} + +Speaker::Speaker(CGE2Engine *vm): Sprite(vm), _vm(vm) { + // Set the sprite list + BitmapPtr SP = new Bitmap[2]; + uint8 *map = Bitmap::makeSpeechBubbleTail(0, _vm->_font->_colorSet); + SP[0] = Bitmap(_vm, 15, 16, map); + delete[] map; + map = Bitmap::makeSpeechBubbleTail(1, _vm->_font->_colorSet); + SP[1] = Bitmap(_vm, 15, 16, map); + delete[] map; + setShapeList(SP, 2); +} + +} // End of namespace CGE2 diff --git a/engines/cge2/vga13h.h b/engines/cge2/vga13h.h new file mode 100644 index 0000000000..553f183de4 --- /dev/null +++ b/engines/cge2/vga13h.h @@ -0,0 +1,308 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_VGA13H_H +#define CGE2_VGA13H_H + +#include "common/serializer.h" +#include "common/events.h" +#include "graphics/surface.h" +#include "cge2/general.h" +#include "cge2/bitmap.h" +#include "cge2/snail.h" +#include "cge2/spare.h" +#include "cge2/cge2.h" + +namespace CGE2 { + +#define kFadeStep 2 +#define kVgaColDark 207 +#define kVgaColDarkGray 225 /*219*/ +#define kVgaColGray 231 +#define kVgaColLightGray 237 +#define kPixelTransp 0xFE +#define kNoSeq (-1) +#define kNoPtr ((uint8)-1) +#define kSprExt ".SPR" +#define kPalCount 256 +#define kPalSize (kPalCount * 3) + +class FXP { + int32 v; +public: + FXP(void) : v(0) {} + FXP (int i0, int f0 = 0) : v((i0 * 256) + ((i0 < 0) ? -f0 : f0)) {} + FXP &operator=(const int &x) { v = x << 8; return *this; } + FXP operator+(const FXP &x) const { FXP y; y.v = v + x.v; return y; } + FXP operator-(const FXP &x) const { FXP y; y.v = v - x.v; return y; } + FXP operator*(const FXP &x) const; + FXP operator/(const FXP &x) const; + + friend int &operator+=(int &a, const FXP &b) { return a += b.trunc(); } + friend int &operator-=(int &a, const FXP &b) { return a -= b.trunc(); } + friend FXP &operator+=(FXP &a, const int &b) { a.v += b << 8; return a; } + friend FXP &operator-=(FXP &a, const int &b) { a.v -= b << 8; return a; } + friend bool operator==(const FXP &a, const FXP &b) { return a.v == b.v; } + friend bool operator!=(const FXP &a, const FXP &b) { return a.v != b.v; } + friend bool operator<(const FXP &a, const FXP &b) { return a.v < b.v; } + friend bool operator>(const FXP &a, const FXP &b) { return a.v > b.v; } + int trunc(void) const { return v >> 8; } + int round(void) const { return (v + 0x80) >> 8; } + bool empty() const { return v == 0; } + void sync(Common::Serializer &s); +}; + +class V3D { +public: + FXP _x, _y, _z; + V3D() { } + V3D(FXP x, FXP y, FXP z = 0) : _x(x), _y(y), _z(z) { } + V3D(const V3D &p) : _x(p._x), _y(p._y), _z(p._z) { } + V3D operator+(const V3D &p) const { return V3D(_x + p._x, _y + p._y, _z + p._z); } + V3D operator-(const V3D &p) const { return V3D(_x - p._x, _y - p._y, _z - p._z); } + V3D operator*(long n) const { return V3D(_x * n, _y * n, _z * n); } + V3D operator/ (long n) const { return V3D(_x / n, _y / n, _z / n); } + bool operator==(const V3D &p) const { return _x == p._x && _y == p._y && _z == p._z; } + bool operator!=(const V3D &p) const { return _x != p._x || _y != p._y || _z != p._z; } + V3D& operator+=(const V3D &x) { return *this = *this + x; } + V3D& operator-=(const V3D &x) { return *this = *this - x; } + void sync(Common::Serializer &s); +}; + +class V2D : public Common::Point { + CGE2Engine *_vm; +public: + V2D &operator=(const V3D &p3) { + FXP m = _vm->_eye->_z / (p3._z - _vm->_eye->_z); + FXP posx = _vm->_eye->_x + (_vm->_eye->_x - p3._x) * m; + x = posx.round(); + FXP posy = _vm->_eye->_y + (_vm->_eye->_y - p3._y) * m; + y = posy.round(); + return *this; + } + V2D(CGE2Engine *vm) : _vm(vm) { } + V2D(CGE2Engine *vm, const V3D &p3) : _vm(vm) { *this = p3; } + V2D(CGE2Engine *vm, int posx, int posy) : _vm(vm), Common::Point(posx, posy) { } + bool operator<(const V2D &p) const { return (x < p.x) && (y < p.y); } + bool operator<=(const V2D &p) const { return (x <= p.x) && (y <= p.y); } + bool operator>(const V2D &p) const { return (x > p.x) && (y > p.y); } + bool operator>=(const V2D &p) const { return (x >= p.x) && (y >= p.y); } + V2D operator+(const V2D &p) const { return V2D(_vm, x + p.x, y + p.y); } + V2D operator-(const V2D &p) const { return V2D(_vm, x - p.x, y - p.y); } + bool operator==(const V3D &p) const { V3D tmp(x, y); return tmp._x == p._x && tmp._y == p._y && tmp._z == p._z; } + bool operator!=(const V3D &p) const { V3D tmp(x, y); return tmp._x != p._x || tmp._y != p._y || tmp._z == p._z; } + bool operator==(const V2D &p) const { return x == p.x && y == p.y; } + uint16 area() { return x * y; } + bool limited(const V2D &p) { + return ((x < p.x) && (y < p.y)); + } + V2D scale (int z) { + FXP m = _vm->_eye->_z / (_vm->_eye->_z - z); + FXP posx = m * x; + FXP posy = m * y; + return V2D(_vm, posx.trunc(), posy.trunc()); + } +}; + +struct Seq { + uint8 _now; + uint8 _next; + int8 _dx; + int8 _dy; + int8 _dz; + int _dly; +}; + +class SprExt { +public: + V2D _p0; + V2D _p1; + BitmapPtr _b0; + BitmapPtr _b1; + BitmapPtr _shpList; + int _location; + Seq *_seq; + char *_name; + CommandHandler::Command *_actions[kActions]; + SprExt(CGE2Engine *vm); +}; + +class Sprite { +protected: + SprExt *_ext; + CGE2Engine *_vm; +public: + int _ref; + signed char _scene; + struct Flags { + bool _hide; // general visibility switch + bool _drag; // sprite is moveable + bool _hold; // sprite is held with mouse + bool _trim; // Trim flag + bool _slav; // slave object + bool _kill; // dispose memory after remove + bool _xlat; // 2nd way display: xlat table + bool _port; // portable + bool _kept; // kept in pocket + bool _frnt; // stay in front of sprite + bool _east; // talk to east (in opposite to west) + bool _near; // Near action lock + bool _shad; // shadow + bool _back; // 'send to background' request + bool _zmov; // sprite needs Z-update in queue + bool _tran; // transparent (untouchable) + } _flags; + V2D _pos2D; + V3D _pos3D; + V2D _siz; + uint16 _time; + struct { byte _ptr, _cnt; } _actionCtrl[kActions]; + int _seqPtr; + int _seqCnt; + int _shpCnt; + char _file[kMaxFile]; + // Following trailer is not saved with the game: + Sprite *_prev; + Sprite *_next; + static byte _constY; + static byte _follow; + static Seq _stdSeq8[]; + + bool works(Sprite *spr); + bool seqTest(int n); + inline bool active() { + return _ext != nullptr; + } + Sprite(CGE2Engine *vm); + Sprite(CGE2Engine *vm, BitmapPtr shp, int cnt); + virtual ~Sprite(); + BitmapPtr getShp(); + void setShapeList(BitmapPtr shp, int cnt); + void moveShapesHi(); + void moveShapesLo(); + int labVal(Action snq, int lab); + virtual Sprite *expand(); + virtual Sprite *contract(); + void backShow(); + void setName(char *newName); + inline char *name() { + return (_ext) ? _ext->_name : nullptr; + } + void gotoxyz(int x, int y, int z = 0); + void gotoxyz(); + void gotoxyz(V2D pos); + void gotoxyz_(V2D pos); + void gotoxyz(V3D pos); + void center(); + void show(uint16 pg); + void hide(uint16 pg); + void show(); + void hide(); + BitmapPtr ghost(); + void step(int nr = -1); + Seq *setSeq(Seq *seq); + CommandHandler::Command *snList(Action type); + virtual void touch(uint16 mask, V2D pos, Common::KeyCode keyCode); + virtual void tick(); + virtual void setScene(int c); + void clrHide() { if (_ext) _ext->_b0 = nullptr; } + + void sync(Common::Serializer &s); + + static void (*notify) (); +}; + +class Queue { + Sprite *_head; + Sprite *_tail; +public: + Queue(bool show); + + void append(Sprite *spr); + void insert(Sprite *spr, Sprite *nxt); + void insert(Sprite *spr); + Sprite *remove(Sprite *spr); + Sprite *first() { + return _head; + } + Sprite *last() { + return _tail; + } + Sprite *locate(int ref); + bool locate(Sprite *spr); + void clear() { _head = _tail = nullptr; } +}; + +class Vga { + CGE2Engine *_vm; + bool _setPal; + Dac *_oldColors; + Dac *_newColors; + const char *_msg; + const char *_name; + + void updateColors(); + void setColors(); + void waitVR(); + uint8 closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB); + +public: + uint32 _frmCnt; + Queue *_showQ; + bool _mono; + Graphics::Surface *_page[4]; + Dac *_sysPal; + struct { uint8 _org, _len, _cnt, _dly; } _rot; + + Vga(CGE2Engine *vm); + ~Vga(); + + uint8 *glass(Dac *pal, const uint8 colR, const uint8 colG, const uint8 colB); + void getColors(Dac *tab); + void setColors(Dac *tab, int lum); + void clear(uint8 color); + void copyPage(uint16 d, uint16 s); + void sunrise(Dac *tab); + void sunset(); + void show(); + void update(); + void rotate(); + uint8 closest(Dac *pal, Dac x); + + void palToDac(const byte *palData, Dac *tab); + void dacToPal(const Dac *tab, byte *palData); +}; + +class Speaker: public Sprite { + CGE2Engine *_vm; +public: + Speaker(CGE2Engine *vm); +}; + +} // End of namespace CGE2 + +#endif // CGE2_VGA13H_H diff --git a/engines/cge2/vmenu.cpp b/engines/cge2/vmenu.cpp new file mode 100644 index 0000000000..6afe5e9a61 --- /dev/null +++ b/engines/cge2/vmenu.cpp @@ -0,0 +1,162 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#include "cge2/text.h" +#include "cge2/vmenu.h" +#include "cge2/events.h" + +namespace CGE2 { + +Choice::Choice(CGE2Engine *vm) : _vm(vm), _text(nullptr) {} + +ExitGameChoice::ExitGameChoice(CGE2Engine *vm) : Choice(vm) { + _text = _vm->_text->getText(kQuitText); +} + +void ExitGameChoice::proc() { + _vm->switchScene(-1); +} + +ReturnToGameChoice::ReturnToGameChoice(CGE2Engine *vm) : Choice(vm) { + _text = _vm->_text->getText(kNoQuitText); +} + +void ReturnToGameChoice::proc() { + _vm->_commandHandlerTurbo->addCommand(kCmdSeq, kPowerRef, 1, nullptr); + _vm->keyClick(); +} + +MenuBar::MenuBar(CGE2Engine *vm, uint16 w, byte *c) : Talk(vm) { + _color = c; + int h = kFontHigh + 2 * kMenuBarVerticalMargin, i = (w += 2 * kMenuBarHorizontalMargin) * h; + uint8 *p = new uint8[i]; + uint8 *p1; + uint8 *p2; + uint8 lt = _color[kLt]; + uint8 rb = _color[kRb]; + BitmapPtr b; + + memset(p + w, kPixelTransp, i - 2 * w); + memset(p, lt, w); + memset(p + i - w, rb, w); + p1 = p; + p2 = p + i - 1; + for (i = 0; i < h; i++) { + *p1 = lt; + *p2 = rb; + p1 += w; + p2 -= w; + } + b = new Bitmap[1]; + b[0] = Bitmap(vm, w, h, p); + delete[] p; + setShapeList(b, 1); + _flags._slav = true; + _flags._tran = true; + _flags._kill = true; +} + +VMenu *VMenu::_addr = nullptr; + +VMenu::VMenu(CGE2Engine *vm, Common::Array<Choice *> list, V2D pos, ColorBank col) + : Talk(vm, vmGather(list), kTBRect, col), _menu(list), _bar(nullptr), _items(list.size()), _vm(vm) { + delete[] _vmgt; // Lefotver of vmGather. + + _addr = this; + _recent = -1; + _flags._kill = true; + + if (pos.x < 0 || pos.y < 0) + center(); + else + gotoxyz(V2D(_vm, pos.x - _siz.x / 2, pos.y - (kTextVMargin + kFontHigh / 2))); + + _vm->_vga->_showQ->append(this); + _bar = new MenuBar(_vm, _siz.x - 2 * kTextHMargin, _color); + _bar->gotoxyz(V2D(_vm, _pos2D.x, _pos2D.y + kTextVMargin - kMenuBarVerticalMargin)); + _vm->_vga->_showQ->append(_bar); +} + +char *VMenu::vmGather(Common::Array<Choice *> list) { + int len = 0; + int h = 0; + + for (uint i = 0; i < list.size(); i++) { + len += strlen(list[i]->_text); + ++h; + } + _vmgt = new char[len + h]; + *_vmgt = '\0'; + for (uint i = 0; i < list.size(); i++) { + if (*_vmgt) + strcat(_vmgt, "|"); + strcat(_vmgt, list[i]->_text); + ++h; + } + + return _vmgt; +} + + +VMenu::~VMenu() { + _addr = nullptr; + + for (uint i = 0; i < _menu.size(); i++) { + delete _menu[i]; + } +} + +void VMenu::touch(uint16 mask, V2D pos, Common::KeyCode keyCode) { + if (_items) { + Sprite::touch(mask, pos, keyCode); + + int n = 0; + bool ok = false; + int h = kFontHigh + kTextLineSpace; + pos.y -= kTextVMargin - 1; + if (pos.y >= 0) { + if (pos.x < 0) + pos.x = -pos.x; + n = pos.y / h; + if (n < _items) + ok = (pos.x <= (_siz.x >> 1) - kTextHMargin); + else + n = _items - 1; + } + + _bar->gotoxyz(V2D(_vm, _pos2D.x, _pos2D.y + kTextVMargin + n * h - kMenuBarVerticalMargin)); + n = _items - 1 - n; + + if (ok && (mask & kMouseLeftUp)) { + _items = 0; + _vm->_commandHandlerTurbo->addCommand(kCmdKill, -1, 0, this); + _menu[_recent = n]->proc(); + } + } +} + +} // End of namespace CGE2 diff --git a/engines/cge2/vmenu.h b/engines/cge2/vmenu.h new file mode 100644 index 0000000000..f34812dcf4 --- /dev/null +++ b/engines/cge2/vmenu.h @@ -0,0 +1,89 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This code is based on original Sfinx source code + * Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon + */ + +#ifndef CGE2_VMENU_H +#define CGE2_VMENU_H + +#define kMenuBarVerticalMargin 1 +#define kMenuBarHorizontalMargin 3 +#define kLt 3 +#define kRb 1 + +#include "cge2/cge2.h" +#include "cge2/talk.h" + +namespace CGE2 { + +class Choice { +protected: + CGE2Engine *_vm; +public: + char *_text; + + virtual void proc() = 0; + + Choice(CGE2Engine *vm); + virtual ~Choice() {}; +}; + +class ExitGameChoice : public Choice { +public: + ExitGameChoice(CGE2Engine *vm); + void proc(); +}; + +class ReturnToGameChoice : public Choice { +public: + ReturnToGameChoice(CGE2Engine *vm); + void proc(); +}; + +class MenuBar : public Talk { +public: + MenuBar(CGE2Engine *vm, uint16 w, byte *c); +}; + +class VMenu : public Talk { + CGE2Engine *_vm; + + uint16 _items; + Common::Array<Choice *> _menu; +public: + char *_vmgt; + static VMenu *_addr; + int _recent; + MenuBar *_bar; + + VMenu(CGE2Engine *vm, Common::Array<Choice *> list, V2D pos, ColorBank col); + ~VMenu(); + void touch(uint16 mask, V2D pos, Common::KeyCode keyCode); + char *vmGather(Common::Array<Choice *> list); +}; + +} // End of namespace CGE2 + +#endif // CGE2_VMENU_H diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp index 471a29030b..f070338978 100644 --- a/engines/composer/composer.cpp +++ b/engines/composer/composer.cpp @@ -135,7 +135,7 @@ Common::Error ComposerEngine::run() { else loadLibrary(_pendingPageChanges[i]._pageId); - lastDrawTime = _system->getMillis(); + lastDrawTime = 0; } _pendingPageChanges.clear(); @@ -168,9 +168,10 @@ Common::Error ComposerEngine::run() { else lastDrawTime += frameTime; + tickOldScripts(); + redraw(); - tickOldScripts(); processAnimFrame(); } else if (_needsUpdate) { redraw(); diff --git a/engines/composer/scripting.cpp b/engines/composer/scripting.cpp index 94ca2c1bc8..cd78202ecd 100644 --- a/engines/composer/scripting.cpp +++ b/engines/composer/scripting.cpp @@ -746,6 +746,7 @@ void ComposerEngine::stopOldScript(uint16 id) { for (Common::List<OldScript *>::iterator i = _oldScripts.begin(); i != _oldScripts.end(); i++) { if ((*i)->_id == id) { + removeSprite(0, id); delete *i; i = _oldScripts.reverse_erase(i); } diff --git a/engines/cruise/cruise.cpp b/engines/cruise/cruise.cpp index 5c1a37a8eb..eebd8fdc15 100644 --- a/engines/cruise/cruise.cpp +++ b/engines/cruise/cruise.cpp @@ -53,8 +53,7 @@ CruiseEngine::CruiseEngine(OSystem * syst, const CRUISEGameDescription *gameDesc PCFadeFlag = false; _preLoad = false; _savedCursor = CURSOR_NOMOUSE; - lastTick = 0; - lastTickDebug = 0; + _lastTick = 0; _gameSpeed = GAME_FRAME_DELAY_1; _speedFlag = false; _polyStructs = nullptr; diff --git a/engines/cruise/cruise.h b/engines/cruise/cruise.h index c81e5dd5ec..8624ba693e 100644 --- a/engines/cruise/cruise.h +++ b/engines/cruise/cruise.h @@ -60,7 +60,7 @@ private: PCSound *_sound; Common::StringArray _langStrings; CursorType _savedCursor; - uint32 lastTick, lastTickDebug; + uint32 _lastTick; int _gameSpeed; bool _speedFlag; diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp index f2f7e0c2b0..0ad1416df2 100644 --- a/engines/cruise/cruise_main.cpp +++ b/engines/cruise/cruise_main.cpp @@ -934,8 +934,11 @@ bool createDialog(int objOvl, int objIdx, int x, int y) { else color = -1; - ptr = getObjectName(ptrHead->obj1Number, ovl3->arrayNameObj); - addSelectableMenuEntry(j, i, menuTable[0], 1, color, ptr); + if (ovl3) { + ptr = getObjectName(ptrHead->obj1Number, ovl3->arrayNameObj); + addSelectableMenuEntry(j, i, menuTable[0], 1, color, ptr); + } else + error("Unexpected null pointer in createDialog()"); } } } @@ -1157,7 +1160,7 @@ void callSubRelation(menuElementSubStruct *pMenuElement, int nOvl, int nObj) { createTextObject(&cellHead, ovlIdx, pHeader->id, x, y, 200, findHighColor(), masterScreen, 0, 0); } - userWait = 1; + userWait = true; autoOvl = ovlIdx; autoMsg = pHeader->id; @@ -1186,7 +1189,7 @@ void callSubRelation(menuElementSubStruct *pMenuElement, int nOvl, int nObj) { pTrack->flag = 1; autoTrack = true; - userWait = 0; + userWait = false; userEnabled = 0; freezeCell(&cellHead, ovlIdx, pHeader->id, 5, -1, 0, 9998); } @@ -1303,7 +1306,7 @@ void callRelation(menuElementSubStruct *pMenuElement, int nObj2) { createTextObject(&cellHead, ovlIdx, pHeader->id, x, y, 200, findHighColor(), masterScreen, 0, 0); } - userWait = 1; + userWait = true; autoOvl = ovlIdx; autoMsg = pHeader->id; @@ -1334,7 +1337,7 @@ void callRelation(menuElementSubStruct *pMenuElement, int nObj2) { pTrack->flag = 1; autoTrack = true; - userWait = 0; + userWait = false; userEnabled = 0; freezeCell(&cellHead, ovlIdx, pHeader->id, 5, -1, 0, 9998); } @@ -1455,7 +1458,7 @@ int CruiseEngine::processInput() { if (userWait) { // Check for left mouse button click or Space to end user waiting if ((keyboardCode == Common::KEYCODE_SPACE) || (button == CRS_MB_LEFT)) - userWait = 0; + userWait = false; keyboardCode = Common::KEYCODE_INVALID; return 0; @@ -1772,9 +1775,7 @@ void CruiseEngine::mainLoop() { currentActiveMenu = -1; autoMsg = -1; linkedRelation = 0; - main21 = 0; - main22 = 0; - userWait = 0; + userWait = false; autoTrack = false; initAllData(); @@ -1829,10 +1830,7 @@ void CruiseEngine::mainLoop() { if (!skipEvents || bFastMode) skipEvents = manageEvents(); - if (bFastMode) { - if (currentTick >= (lastTickDebug + 10)) - lastTickDebug = currentTick; - } else { + if (!bFastMode) { g_system->delayMillis(10); currentTick = g_system->getMillis(); } @@ -1841,11 +1839,11 @@ void CruiseEngine::mainLoop() { break; _vm->getDebugger()->onFrame(); - } while (currentTick < lastTick + _gameSpeed && !bFastMode); + } while (currentTick < _lastTick + _gameSpeed && !bFastMode); if (_playerDontAskQuit) break; - lastTick = g_system->getMillis(); + _lastTick = g_system->getMillis(); // Handle switchover in game speed after intro if (!_speedFlag && canLoadGameStateCurrently()) { @@ -1860,7 +1858,7 @@ void CruiseEngine::mainLoop() { // readKeyboard(); - bool isUserWait = userWait != 0; + bool isUserWait = userWait; // WORKAROUND: This prevents hotspots responding during // delays i.e. Menu opening if you click fast on another // hotspot after trying to open a locked door, which @@ -1941,7 +1939,7 @@ void CruiseEngine::mainLoop() { mainDraw(userWait); flipScreen(); - if (userWait == 1) { + if (userWait) { // Waiting for press - original wait loop has been integrated into the // main event loop continue; @@ -1956,7 +1954,7 @@ void CruiseEngine::mainLoop() { char* pText = getText(autoMsg, autoOvl); if (strlen(pText)) - userWait = 1; + userWait = true; } changeScriptParamInList(-1, -1, &relHead, 9998, 0); diff --git a/engines/cruise/function.cpp b/engines/cruise/function.cpp index 33f3bbaf4a..3f794c4e70 100644 --- a/engines/cruise/function.cpp +++ b/engines/cruise/function.cpp @@ -1512,6 +1512,9 @@ int16 Op_Itoa() { int param[160]; char txt[40]; + for (int i = 0; i < 160; ++i) + param[i] = 0; + for (int i = nbp - 1; i >= 0; i--) param[i] = popVar(); @@ -1829,7 +1832,7 @@ int16 Op_ThemeReset() { } int16 Op_UserWait() { - userWait = 1; + userWait = true; if (currentScriptPtr->type == scriptType_PROC) { changeScriptParamInList(currentScriptPtr->overlayNumber, currentScriptPtr->scriptNumber, &procHead, -1, 9999); } else if (currentScriptPtr->type == scriptType_REL) { diff --git a/engines/cruise/mainDraw.cpp b/engines/cruise/mainDraw.cpp index 98e7e66aa6..5777b846b4 100644 --- a/engines/cruise/mainDraw.cpp +++ b/engines/cruise/mainDraw.cpp @@ -1377,7 +1377,7 @@ int getValueFromObjectQuerry(objectParamsQuery *params, int idx) { return 0; } -void mainDraw(int16 param) { +void mainDraw(bool waitFl) { uint8 *bgPtr; cellStruct *currentObjPtr; int16 currentObjIdx; @@ -1461,7 +1461,7 @@ void mainDraw(int16 param) { } // automatic animation process - if (currentObjPtr->animStep && !param) { + if (currentObjPtr->animStep && !waitFl) { if (currentObjPtr->animCounter <= 0) { bool change = true; diff --git a/engines/cruise/mainDraw.h b/engines/cruise/mainDraw.h index bb71b9759b..1af403fca5 100644 --- a/engines/cruise/mainDraw.h +++ b/engines/cruise/mainDraw.h @@ -33,7 +33,7 @@ extern int m_color; int upscaleValue(int value, int scale); void pixel(int x, int y, char color); -void mainDraw(int16 param); +void mainDraw(bool waitFl); void flipScreen(); void buildPolyModel(int X, int Y, int scale, char *ptr2, char *destBuffer, char *dataPtr); void drawSprite(int width, int height, cellStruct *currentObjPtr, const uint8 *dataIn, int ys, int xs, uint8 *output, const uint8 *dataBuf); diff --git a/engines/cruise/menu.cpp b/engines/cruise/menu.cpp index c72192fc1b..cf0b872646 100644 --- a/engines/cruise/menu.cpp +++ b/engines/cruise/menu.cpp @@ -160,7 +160,7 @@ int processMenu(menuStruct *pMenu) { int si; currentActiveMenu = 0; - mainDraw(1); + mainDraw(true); flipScreen(); di = 0; @@ -179,7 +179,7 @@ int processMenu(menuStruct *pMenu) { di = 1; } - mainDraw(1); + mainDraw(true); flipScreen(); manageEvents(); @@ -190,7 +190,7 @@ int processMenu(menuStruct *pMenu) { currentActiveMenu = -1; - mainDraw(1); + mainDraw(true); flipScreen(); if (mouseButton & 1) { diff --git a/engines/cruise/saveload.cpp b/engines/cruise/saveload.cpp index 8e64faa14c..a62648df08 100644 --- a/engines/cruise/saveload.cpp +++ b/engines/cruise/saveload.cpp @@ -947,7 +947,7 @@ Common::Error loadSavegameData(int saveGameIdx) { // to finish changeCursor(CURSOR_NORMAL); - mainDraw(1); + mainDraw(true); flipScreen(); return Common::kNoError; diff --git a/engines/cruise/sound.cpp b/engines/cruise/sound.cpp index cc9a17eb9a..0b0fab8c4a 100644 --- a/engines/cruise/sound.cpp +++ b/engines/cruise/sound.cpp @@ -607,6 +607,13 @@ PCSoundFxPlayer::PCSoundFxPlayer(PCSoundDriver *driver) _sfxData = NULL; _fadeOutCounter = 0; _driver->setUpdateCallback(updateCallback, this); + + _currentPos = 0; + _currentOrder = 0; + _numOrders = 0; + _eventsDelay = 0; + _looping = false; + _updateTicksCounter = 0; } PCSoundFxPlayer::~PCSoundFxPlayer() { @@ -792,6 +799,7 @@ PCSound::PCSound(Audio::Mixer *mixer, CruiseEngine *vm) { _mixer = mixer; _soundDriver = new AdLibSoundDriverADL(_mixer); _player = new PCSoundFxPlayer(_soundDriver); + _genVolume = 0; } PCSound::~PCSound() { diff --git a/engines/cruise/vars.cpp b/engines/cruise/vars.cpp index 9a59c8a714..e9b68968ef 100644 --- a/engines/cruise/vars.cpp +++ b/engines/cruise/vars.cpp @@ -53,9 +53,7 @@ char nextOverlay[38]; int16 currentActiveMenu; int16 autoMsg; menuElementSubStruct* linkedRelation; -int16 main21; -int16 main22; -int16 userWait; +bool userWait; int16 autoTrack; int16 currentDiskNumber = 1; diff --git a/engines/cruise/vars.h b/engines/cruise/vars.h index fe3f7d6303..e7c687d5fb 100644 --- a/engines/cruise/vars.h +++ b/engines/cruise/vars.h @@ -156,9 +156,7 @@ extern char nextOverlay[38]; extern int16 currentActiveMenu; extern int16 autoMsg; extern menuElementSubStruct* linkedRelation; -extern int16 main21; -extern int16 main22; -extern int16 userWait; +extern bool userWait; extern int16 autoTrack; extern int16 currentDiskNumber; diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp index b158969f46..5009a62e84 100644 --- a/engines/drascula/animation.cpp +++ b/engines/drascula/animation.cpp @@ -45,9 +45,6 @@ void DrasculaEngine::updateAnim(int y, int destX, int destY, int width, int heig void DrasculaEngine::animation_1_1() { debug(4, "animation_1_1()"); - int l, l2, p; - //int pixelPos[6]; - while (term_int == 0 && !shouldQuit()) { playMusic(29); playFLI("logoddm.bin", 9); @@ -119,8 +116,8 @@ void DrasculaEngine::animation_1_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit()) break; - for (l2 = 0; l2 < 3; l2++) - for (l = 0; l < 7; l++) { + for (int l2 = 0; l2 < 3; l2++) + for (int l = 0; l < 7; l++) { copyBackground(); copyBackground(interf_x[l], interf_y[l], 156, 45, 63, 31, drawSurface2, screenSurface); updateScreen(); @@ -133,9 +130,7 @@ void DrasculaEngine::animation_1_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit()) break; - l2 = 0; p = 0; - - for (l = 0; l < 180; l++) { + for (int l = 0, l2 = 0, p = 0; l < 180; l++) { copyBackground(0, 0, 320 - l, 0, l, 200, drawSurface3, screenSurface); copyBackground(l, 0, 0, 0, 320 - l, 200, bgSurface, screenSurface); @@ -703,17 +698,15 @@ void DrasculaEngine::animation_4_2() { void DrasculaEngine::animation_14_2() { debug(4, "animation_14_2()"); - int cY = -160; - int l = 0; - loadPic("an14_2.alg", backSurface); + int l = 0; for (int n = -160; n <= 0; n = n + 5 + l) { copyBackground(); updateRefresh_pre(); moveCharacters(); moveVonBraun(); - cY = n; + int cY = n; copyRect(150, 6, 69, cY, 158, 161, backSurface, screenSurface); updateRefresh(); updateScreen(); @@ -959,8 +952,6 @@ void DrasculaEngine::animation_23_2() { void DrasculaEngine::animation_25_2() { debug(4, "animation_25_2()"); - int cY = 0; - loadPic("an14_2.alg", backSurface); loadPic(18, bgSurface); @@ -975,8 +966,7 @@ void DrasculaEngine::animation_25_2() { moveCharacters(); moveVonBraun(); - cY = n; - + int cY = n; copyRect(150, 6, 69, cY, 158, 161, backSurface, screenSurface); updateRefresh(); @@ -1594,20 +1584,18 @@ void DrasculaEngine::animation_1_6() { void DrasculaEngine::animation_5_6() { debug(4, "animation_5_6()"); - int pY = -125; - animate("man.bin", 14); for (int n = -125; n <= 0; n = n + 2) { copyBackground(); updateRefresh_pre(); - pY = n; + int pY = n; copyRect(1, 29, 204, pY, 18, 125, drawSurface3, screenSurface); updateRefresh(); - updateScreen(); updateEvents(); + pause(2); } diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index 35461f1d71..797b6d94b0 100644 --- a/engines/drascula/drascula.cpp +++ b/engines/drascula/drascula.cpp @@ -194,6 +194,9 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam _console = 0; + const Common::FSNode gameDataDir(ConfMan.get("path")); + SearchMan.addSubDirectoryMatching(gameDataDir, "audio"); + int cd_num = ConfMan.getInt("cdrom"); if (cd_num >= 0) _system->getAudioCDManager()->openCD(cd_num); diff --git a/engines/fullpipe/configure.engine b/engines/fullpipe/configure.engine index fce5951e26..a9042449db 100644 --- a/engines/fullpipe/configure.engine +++ b/engines/fullpipe/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine fullpipe "Full Pipe" no +add_engine fullpipe "Full Pipe" no "" "" "16bit" diff --git a/engines/fullpipe/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp index f4444ef707..bb0838395d 100644 --- a/engines/fullpipe/fullpipe.cpp +++ b/engines/fullpipe/fullpipe.cpp @@ -34,6 +34,7 @@ #include "fullpipe/modal.h" #include "fullpipe/input.h" #include "fullpipe/motion.h" +#include "fullpipe/statics.h" #include "fullpipe/scenes.h" #include "fullpipe/floaters.h" #include "fullpipe/console.h" @@ -83,6 +84,7 @@ FullpipeEngine::FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc) _currentCheatPos = 0; _modalObject = 0; + _origFormat = 0; _liftEnterMQ = 0; _liftExitMQ = 0; @@ -242,12 +244,14 @@ void FullpipeEngine::restartGame() { } Common::Error FullpipeEngine::run() { - const Graphics::PixelFormat format(2, 5, 6, 5, 0, 11, 5, 0, 0); + const Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0); // Initialize backend initGraphics(800, 600, true, &format); _backgroundSurface.create(800, 600, format); + _origFormat = new Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); + _console = new Console(this); initialize(); @@ -413,21 +417,34 @@ void FullpipeEngine::updateEvents() { } } - -#if 0 - warning("STUB: FullpipeEngine::updateEvents() <mainWindowProc>"); - if (Msg == MSG_SC11_SHOWSWING && _modalObject) { - _modalObject->method14(); - } -#endif + // pollEvent() is implemented only for video player. So skip it. + //if (event.kbd.keycode == MSG_SC11_SHOWSWING && _modalObject) { + // _modalObject->pollEvent(); + //} } void FullpipeEngine::freeGameLoader() { - warning("STUB: FullpipeEngine::freeGameLoader()"); + setCursor(0); + delete _movTable; + _floaters->stopAll(); + delete _gameLoader; + _currentScene = 0; + _scene2 = 0; + _loaderScene = 0; } void FullpipeEngine::cleanup() { - warning("STUB: FullpipeEngine::cleanup()"); + //cleanRecorder(); + clearMessageHandlers(); + clearMessages(); + _globalMessageQueueList->compact(); + + for (uint i = 0; i < _globalMessageQueueList->size(); i++) + delete (*_globalMessageQueueList)[i]; + + stopAllSoundStreams(); + + delete _origFormat; } void FullpipeEngine::updateScreen() { diff --git a/engines/fullpipe/fullpipe.h b/engines/fullpipe/fullpipe.h index afdc493258..7f20a6d6af 100644 --- a/engines/fullpipe/fullpipe.h +++ b/engines/fullpipe/fullpipe.h @@ -32,7 +32,7 @@ #include "audio/mixer.h" -#include "graphics/surface.h" +#include "graphics/transparent_surface.h" #include "engines/engine.h" @@ -108,6 +108,7 @@ public: void updateEvents(); Graphics::Surface _backgroundSurface; + Graphics::PixelFormat *_origFormat; GameLoader *_gameLoader; GameProject *_gameProject; @@ -242,6 +243,7 @@ public: int (*_updateCursorCallback)(); void drawAlphaRectangle(int x1, int y1, int x2, int y2, int alpha); + void sceneFade(Scene *sc, bool direction); int _cursorId; int _minCursorId; diff --git a/engines/fullpipe/gameloader.cpp b/engines/fullpipe/gameloader.cpp index c8b01939dd..fbf96b3060 100644 --- a/engines/fullpipe/gameloader.cpp +++ b/engines/fullpipe/gameloader.cpp @@ -84,7 +84,29 @@ GameLoader::~GameLoader() { delete _interactionController; delete _inputController; - warning("STUB: GameLoader::~GameLoader()"); + g_fp->_gameLoader = 0; + + for (uint i = 0; i < _sc2array.size(); i++) { + if (_sc2array[i]._defPicAniInfos) + delete _sc2array[i]._defPicAniInfos; + + if (_sc2array[i]._picAniInfos) + delete _sc2array[i]._picAniInfos; + + if (_sc2array[i]._motionController) + delete _sc2array[i]._motionController; + + if (_sc2array[i]._data1) + free(_sc2array[i]._data1); + + if (_sc2array[i]._entranceData) + free(_sc2array[i]._entranceData); + } + + delete _gameVar; + _gameVar = 0; + + _sc2array.clear(); } bool GameLoader::load(MfcArchive &file) { @@ -635,7 +657,16 @@ bool readSavegameHeader(Common::InSaveFile *in, FullpipeSavegameHeader &header) } void GameLoader::restoreDefPicAniInfos() { - warning("STUB: restoreDefPicAniInfos()"); + for (uint i = 0; i < _sc2array.size(); i++) { + if (_sc2array[i]._picAniInfos) { + free(_sc2array[i]._picAniInfos); + _sc2array[i]._picAniInfos = 0; + _sc2array[i]._picAniInfosCount = 0; + } + + if (_sc2array[i]._scene) + applyPicAniInfos(_sc2array[i]._scene, _sc2array[i]._defPicAniInfos, _sc2array[i]._defPicAniInfosCount); + } } GameVar *FullpipeEngine::getGameLoaderGameVar() { diff --git a/engines/fullpipe/gfx.cpp b/engines/fullpipe/gfx.cpp index 520e81835b..61fbf7192f 100644 --- a/engines/fullpipe/gfx.cpp +++ b/engines/fullpipe/gfx.cpp @@ -33,51 +33,6 @@ namespace Fullpipe { -Bitmap::Bitmap() { - _x = 0; - _y = 0; - _width = 0; - _height = 0; - _pixels = 0; - _type = 0; - _dataSize = 0; - _flags = 0; -} - -Bitmap::Bitmap(Bitmap *src) { - _x = src->_x; - _y = src->_y; - _flags = src->_flags; - _dataSize = src->_dataSize; - _type = src->_type; - _width = src->_width; - _height = src->_height; - _pixels = src->_pixels; -} - -Bitmap::~Bitmap() { - if (_pixels) - free(_pixels); - - _pixels = 0; -} - -void Bitmap::load(Common::ReadStream *s) { - debug(5, "Bitmap::load()"); - - _x = s->readUint32LE(); - _y = s->readUint32LE(); - _width = s->readUint32LE(); - _height = s->readUint32LE(); - s->readUint32LE(); // pixels - _type = s->readUint32LE(); - _dataSize = s->readUint32LE(); - _flags = s->readUint32LE(); - - debug(8, "Bitmap: x: %d y: %d w: %d h: %d dataSize: 0x%x", _x, _y, _width, _height, _dataSize); - debug(8, "Bitmap: type: %s (0x%04x) flags: 0x%x", Common::tag2string(_type).c_str(), _type, _flags); -} - Background::Background() { _x = 0; _y = 0; @@ -514,7 +469,7 @@ void Picture::freePicture() { if (_bitmap) { if (testFlags() && !_field_54) { freeData(); - free(_bitmap); + //free(_bitmap); _bitmap = 0; } } @@ -633,6 +588,10 @@ void Picture::getDibInfo() { _bitmap->load(s); _bitmap->_pixels = _data; + + _bitmap->decode((int32 *)(_paletteData ? _paletteData : g_fp->_globalPalette)); + + _bitmap->_pixels = 0; } Bitmap *Picture::getPixelData() { @@ -677,12 +636,12 @@ void Picture::draw(int x, int y, int style, int angle) { case 1: //flip getDimensions(&point); - _bitmap->flipVertical()->drawShaded(1, x1, y1 + 30 + point.y, pal); + _bitmap->flipVertical()->drawShaded(1, x1, y1 + 30 + point.y, pal, _alpha); break; case 2: //vrtSetFadeRatio(g_vrtDrawHandle, 0.34999999); //vrtSetFadeTable(g_vrtDrawHandle, &unk_477F88, 1.0, 1000.0, 0, 0); - _bitmap->drawShaded(2, x1, y1, pal); + _bitmap->drawShaded(2, x1, y1, pal, _alpha); //vrtSetFadeRatio(g_vrtDrawHandle, 0.0); //vrtSetFadeTable(g_vrtDrawHandle, &unk_477F90, 1.0, 1000.0, 0, 0); break; @@ -690,7 +649,7 @@ void Picture::draw(int x, int y, int style, int angle) { if (angle) drawRotated(x1, y1, angle); else { - _bitmap->putDib(x1, y1, (int32 *)pal); + _bitmap->putDib(x1, y1, (int32 *)pal, _alpha); } } } @@ -789,54 +748,71 @@ int Picture::getPixelAtPosEx(int x, int y) { return 0; } -bool Bitmap::isPixelHitAtPos(int x, int y) { - if (x < _x || x >= _width + _x || y < _y || y >= _y + _height) - return false; +Bitmap::Bitmap() { + _x = 0; + _y = 0; + _width = 0; + _height = 0; + _pixels = 0; + _type = 0; + _dataSize = 0; + _flags = 0; + _surface = 0; + _flipping = Graphics::FLIP_NONE; +} - int off; +Bitmap::Bitmap(Bitmap *src) { + _x = src->_x; + _y = src->_y; + _flags = src->_flags; + _dataSize = src->_dataSize; + _type = src->_type; + _width = src->_width; + _height = src->_height; + _pixels = src->_pixels; + _surface = new Graphics::TransparentSurface(*src->_surface); + _flipping = src->_flipping; +} - if (_type == 'CB\x05e') - off = 2 * ((_width + 1) / 2); - else - off = 4 * ((_width + 3) / 4); +Bitmap::~Bitmap() { + if (_pixels) + free(_pixels); - off = x + off * (_y + _height - y - 1) - _x; + delete _surface; - if (_flags & 0x1000000) { - switch (_type) { - case 'CB\0\0': - if (_pixels[off] == (_flags & 0xff)) - return false; - break; - case 'CB\x05e': - if (!*(int16 *)&_pixels[2 * off]) - return false; - break; - case 'RB\0\0': - return isPixelAtHitPosRB(x, y); - } - } - return true; + _pixels = 0; } -bool Bitmap::isPixelAtHitPosRB(int x, int y) { - int ox = _x; - int oy = _y; +void Bitmap::load(Common::ReadStream *s) { + debug(5, "Bitmap::load()"); + + _x = s->readUint32LE(); + _y = s->readUint32LE(); + _width = s->readUint32LE(); + _height = s->readUint32LE(); + s->readUint32LE(); // pixels + _type = s->readUint32LE(); + _dataSize = s->readUint32LE(); + _flags = s->readUint32LE(); + + debug(8, "Bitmap: x: %d y: %d w: %d h: %d dataSize: 0x%x", _x, _y, _width, _height, _dataSize); + debug(8, "Bitmap: type: %s (0x%04x) flags: 0x%x", Common::tag2string(_type).c_str(), _type, _flags); +} - _x = _y = 0; +bool Bitmap::isPixelHitAtPos(int x, int y) { + if (x < _x || x >= _width + _x || y < _y || y >= _y + _height) + return false; - bool res = putDibRB(0, x, y); - _x = ox; - _y = oy; + if (!_surface) + return false; - return res; + return ((*((int32 *)_surface->getBasePtr(x, y)) & 0xff000000) != 0); } -void Bitmap::putDib(int x, int y, int32 *palette) { - debug(7, "Bitmap::putDib(%d, %d)", x, y); +void Bitmap::decode(int32 *palette) { + _surface = new Graphics::TransparentSurface; - _x = x - g_fp->_sceneRect.left; - _y = y - g_fp->_sceneRect.top; + _surface->create(_width, _height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); if (_type == MKTAG('R', 'B', '\0', '\0')) putDibRB(palette); @@ -844,46 +820,64 @@ void Bitmap::putDib(int x, int y, int32 *palette) { putDibCB(palette); } -bool Bitmap::putDibRB(int32 *palette, int pX, int pY) { - uint16 *curDestPtr; +void Bitmap::putDib(int x, int y, int32 *palette, int alpha) { + debug(7, "Bitmap::putDib(%d, %d)", x, y); + + int x1 = x - g_fp->_sceneRect.left; + int y1 = y - g_fp->_sceneRect.top; + + if (!_width || !_height || !_surface) + return; + + Common::Rect sub(0, 0, _width, _height); + + if (x1 < 0) { + sub.left = -x1; + x1 = 0; + } + + if (y1 < 0) { + sub.top = -y1; + y1 = 0; + } + + if (x1 + sub.width() > 799) + sub.right -= x1 + sub.width() - 799; + + if (y1 + sub.height() > 599) + sub.bottom -= y1 + sub.height() - 599; + + if (sub.width() <= 0 || sub.height() <= 0) + return; + + int alphac = TS_ARGB(0xff, alpha, 0xff, 0xff); + + _surface->blit(g_fp->_backgroundSurface, x1, y1, _flipping, &sub, alphac); + g_fp->_system->copyRectToScreen(g_fp->_backgroundSurface.getBasePtr(x1, y1), g_fp->_backgroundSurface.pitch, x1, y1, sub.width(), sub.height()); +} + +bool Bitmap::putDibRB(int32 *palette) { + uint32 *curDestPtr; int endy; int x; int start1; int fillLen; uint16 pixel; - int endx; int y; uint16 *srcPtr2; uint16 *srcPtr; - if (!palette && pX == -1) { + if (!palette) { debug(2, "Bitmap::putDibRB(): Both global and local palettes are empty"); return false; } debug(8, "Bitmap::putDibRB()"); - endx = _width + _x - 1; - endy = _height + _y - 1; - - if (_x > 799 || endx < 0 || _y > 599 || endy < 0) - return false; - - if (pX == -1) { - if (endy > 599) - endy = 599; - - if (endx > 799) - endx = 799; - } - - int startx = _x; - if (startx < 0) - startx = 0; + endy = _height - 1; - int starty = _y; - if (starty < 0) - starty = 0; + int startx = 0; + int starty = 0; y = endy; @@ -927,14 +921,9 @@ bool Bitmap::putDibRB(int32 *palette, int pX, int pY) { if (fillLen > 0 || start1 >= 0) { if (x <= 799 + 1 || (fillLen += 799 - x + 1, fillLen > 0)) { if (y <= endy) { - if (pX == -1) { - int bgcolor = palette[(pixel >> 8) & 0xff]; - curDestPtr = (uint16 *)g_fp->_backgroundSurface.getBasePtr(start1, y); - colorFill(curDestPtr, fillLen, bgcolor); - } else { - if (y == pY && pX >= start1 && pX < start1 + fillLen) - return true; - } + int bgcolor = palette[(pixel >> 8) & 0xff]; + curDestPtr = (uint32 *)_surface->getBasePtr(start1, y); + colorFill(curDestPtr, fillLen, bgcolor); } } } @@ -959,45 +948,26 @@ bool Bitmap::putDibRB(int32 *palette, int pX, int pY) { } if (y <= endy) { - if (pX == -1) { - curDestPtr = (uint16 *)g_fp->_backgroundSurface.getBasePtr(start1, y); - paletteFill(curDestPtr, (byte *)srcPtr2, fillLen, (int32 *)palette); - } else { - if (y == pY && pX >= start1 && pX < start1 + fillLen) - return true; - } + curDestPtr = (uint32 *)_surface->getBasePtr(start1, y); + paletteFill(curDestPtr, (byte *)srcPtr2, fillLen, (int32 *)palette); } } } } - if (pX == -1) - g_fp->_system->copyRectToScreen(g_fp->_backgroundSurface.getBasePtr(startx, starty), g_fp->_backgroundSurface.pitch, startx, starty, endx + 1 - startx, endy + 1 - starty); - return false; } void Bitmap::putDibCB(int32 *palette) { - uint16 *curDestPtr; + uint32 *curDestPtr; int endx; int endy; int bpp; uint pitch; bool cb05_format; - endx = _width + _x - 1; - endy = _height + _y - 1; - - debug(8, "Bitmap::putDibCB(): %d, %d, %d, %d [%d, %d]", _x, _y, endx, endy, _width, _height); - - if (_x > 799 || endx < 0 || _y > 599 || endy < 0) - return; - - if (endy > 599) - endy = 599; - - if (endx > 799) - endx = 799; + endx = _width - 1; + endy = _height - 1; cb05_format = (_type == MKTAG('C', 'B', '\05', 'e')); @@ -1007,39 +977,28 @@ void Bitmap::putDibCB(int32 *palette) { bpp = cb05_format ? 2 : 1; pitch = (bpp * _width + 3) & 0xFFFFFFFC; - byte *srcPtr = &_pixels[pitch * (endy - _y)]; + byte *srcPtr = &_pixels[pitch * endy]; - if (endy - _y < _height) + if (endy < _height) srcPtr = &_pixels[pitch * (_height - 1)]; - int starty = _y; - if (starty < 0) { - starty = 0; - srcPtr = &_pixels[pitch * (_height + _y)]; - } - - int startx = _x; - if (startx < 0) { - srcPtr += bpp * -_x; - startx = 0; - } + int starty = 0; + int startx = 0; if (_flags & 0x1000000) { for (int y = starty; y <= endy; srcPtr -= pitch, y++) { - curDestPtr = (uint16 *)g_fp->_backgroundSurface.getBasePtr(startx, y); + curDestPtr = (uint32 *)_surface->getBasePtr(startx, y); copierKeyColor(curDestPtr, srcPtr, endx - startx + 1, _flags & 0xff, (int32 *)palette, cb05_format); } } else { for (int y = starty; y <= endy; srcPtr -= pitch, y++) { - curDestPtr = (uint16 *)g_fp->_backgroundSurface.getBasePtr(startx, y); + curDestPtr = (uint32 *)_surface->getBasePtr(startx, y); copier(curDestPtr, srcPtr, endx - startx + 1, (int32 *)palette, cb05_format); } } - - g_fp->_system->copyRectToScreen(g_fp->_backgroundSurface.getBasePtr(startx, starty), g_fp->_backgroundSurface.pitch, startx, starty, endx + 1 - startx, endy + 1 - starty); } -void Bitmap::colorFill(uint16 *dest, int len, int32 color) { +void Bitmap::colorFill(uint32 *dest, int len, int32 color) { #if 0 if (blendMode) { if (blendMode != 1) @@ -1050,12 +1009,17 @@ void Bitmap::colorFill(uint16 *dest, int len, int32 color) { colorFill = ptrfillColor16bit; } #endif + byte r, g, b; + + g_fp->_origFormat->colorToRGB(color, r, g, b); + + uint32 c = TS_ARGB(0xff, r, g, b); for (int i = 0; i < len; i++) - *dest++ = (int16)(color & 0xffff); + *dest++ = c; } -void Bitmap::paletteFill(uint16 *dest, byte *src, int len, int32 *palette) { +void Bitmap::paletteFill(uint32 *dest, byte *src, int len, int32 *palette) { #if 0 if (blendMode) { if (blendMode != 1) @@ -1067,11 +1031,16 @@ void Bitmap::paletteFill(uint16 *dest, byte *src, int len, int32 *palette) { } #endif - for (int i = 0; i < len; i++) - *dest++ = READ_LE_UINT32(&palette[*src++]) & 0xffff; + byte r, g, b; + + for (int i = 0; i < len; i++) { + g_fp->_origFormat->colorToRGB(READ_LE_UINT32(&palette[*src++]) & 0xffff, r, g, b); + + *dest++ = TS_ARGB(0xff, r, g, b); + } } -void Bitmap::copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format) { +void Bitmap::copierKeyColor(uint32 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format) { #if 0 if (blendMode) { if (blendMode == 1) { @@ -1089,10 +1058,14 @@ void Bitmap::copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int3 } #endif + byte r, g, b; + if (!cb05_format) { for (int i = 0; i < len; i++) { - if (*src != keyColor) - *dest = READ_LE_UINT32(&palette[*src]) & 0xffff; + if (*src != keyColor) { + g_fp->_origFormat->colorToRGB(READ_LE_UINT32(&palette[*src]) & 0xffff, r, g, b); + *dest = TS_ARGB(0xff, r, g, b); + } dest++; src++; @@ -1101,8 +1074,10 @@ void Bitmap::copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int3 int16 *src16 = (int16 *)src; for (int i = 0; i < len; i++) { - if (*src16 != 0) - *dest = *src16; + if (*src16 != 0) { + g_fp->_origFormat->colorToRGB(READ_LE_UINT16(src16) & 0xffff, r, g, b); + *dest = TS_ARGB(0xff, r, g, b); + } dest++; src16++; @@ -1110,7 +1085,7 @@ void Bitmap::copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int3 } } -void Bitmap::copier(uint16 *dest, byte *src, int len, int32 *palette, bool cb05_format) { +void Bitmap::copier(uint32 *dest, byte *src, int len, int32 *palette, bool cb05_format) { #if 0 if (blendMode) { if (blendMode == 1) { @@ -1128,100 +1103,49 @@ void Bitmap::copier(uint16 *dest, byte *src, int len, int32 *palette, bool cb05_ } #endif - if (!cb05_format) { - for (int i = 0; i < len; i++) - *dest++ = READ_LE_UINT32(&palette[*src++]) & 0xffff; - } else { - int16 *src16 = (int16 *)src; - - for (int i = 0; i < len; i++) - *dest++ = *src16++; - } -} - -Bitmap *Bitmap::reverseImage() { - switch (_type) { - case MKTAG('R', 'B', '\0', '\0'): - return reverseImageRB(); - case MKTAG('C', 'B', '\0', '\0'): - return reverseImageCB(); - case MKTAG('C', 'B', '\05', 'e'): - return reverseImageCB05(); - default: - error("Bitmap::reverseImage: Unknown image type: %x", _type); - } - - return 0; -} - -Bitmap *Bitmap::reverseImageRB() { - uint16 *newpixels = (uint16 *)calloc(((_dataSize + 15) & 0xfffffff0) + sizeof(Bitmap), 1); - uint16 *srcPtr = (uint16 *)_pixels; - - int idx = 0; - while (srcPtr[idx] != 0x100) { - uint16 *srcPtr2 = &srcPtr[idx]; + byte r, g, b; - int prevIdx = idx; - int i = idx; + if (!cb05_format) { + for (int i = 0; i < len; i++) { + g_fp->_origFormat->colorToRGB(READ_LE_UINT32(&palette[*src++]) & 0xffff, r, g, b); - while (*srcPtr2) { - ++srcPtr2; - ++idx; + *dest++ = TS_ARGB(0xff, r, g, b); } + } else { + int16 *src16 = (int16 *)src; - int idx2 = idx; - - newpixels[idx] = srcPtr[idx]; - - while (i != idx) { - int fillLen = 2 - ((srcPtr[prevIdx] & 0xff) != 0 ? 1 : 0); - idx2 -= fillLen; - memcpy(&newpixels[idx2], &srcPtr[prevIdx], 2 * fillLen); - prevIdx = fillLen + i; - i += fillLen; + for (int i = 0; i < len; i++) { + g_fp->_origFormat->colorToRGB(READ_LE_UINT32(src16++) & 0xffff, r, g, b); + *dest++ = TS_ARGB(0xff, r, g, b); } - ++idx; } - newpixels[idx] = 256; - - int oldBmp = ((_dataSize + 15) >> 1) & 0x7FFFFFF8; - memcpy(&newpixels[oldBmp], &srcPtr[oldBmp], sizeof(Bitmap)); - - Bitmap *res = new Bitmap(this); - res->_pixels = (byte *)newpixels; - - return res; } -Bitmap *Bitmap::reverseImageCB() { - warning("STUB: Bitmap::reverseImageCB()"); - - return this; -} - -Bitmap *Bitmap::reverseImageCB05() { - warning("STUB: Bitmap::reverseImageCB05()"); +Bitmap *Bitmap::reverseImage(bool flip) { + if (flip) + _flipping = Graphics::FLIP_H; + else + _flipping = Graphics::FLIP_NONE; return this; } Bitmap *Bitmap::flipVertical() { - warning("STUB: Bitmap::flipVertical()"); + _flipping = Graphics::FLIP_V; return this; } -void Bitmap::drawShaded(int type, int x, int y, byte *palette) { +void Bitmap::drawShaded(int type, int x, int y, byte *palette, int alpha) { warning("STUB: Bitmap::drawShaded(%d, %d, %d)", type, x, y); - putDib(x, y, (int32 *)palette); + putDib(x, y, (int32 *)palette, alpha); } - void Bitmap::drawRotated(int x, int y, int angle, byte *palette) { +void Bitmap::drawRotated(int x, int y, int angle, byte *palette, int alpha) { warning("STUB: Bitmap::drawShaded(%d, %d, %d)", x, y, angle); - putDib(x, y, (int32 *)palette); + putDib(x, y, (int32 *)palette, alpha); } bool BigPicture::load(MfcArchive &file) { @@ -1251,7 +1175,7 @@ void BigPicture::draw(int x, int y, int style, int angle) { //vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, v9); } - _bitmap->putDib(nx, ny, 0); + _bitmap->putDib(nx, ny, 0, 0xff); if (_alpha < 0xFF) { //vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); @@ -1332,4 +1256,23 @@ void FullpipeEngine::drawAlphaRectangle(int x1, int y1, int x2, int y2, int alph warning("STUB: FullpipeEngine::drawAlphaRectangle()"); } +void FullpipeEngine::sceneFade(Scene *sc, bool direction) { + warning("STUB: FullpipeEngine::sceneFade()"); + +#if 0 + for (int dim = 0; dim < 255; dim += 20) { + v5 = GetTickCount(); + vrtSetAlphaBlendMode(*(_DWORD *)virt, 0, 255); + sc->draw(); + drawAlphaRectangle(0, 0, 800, 600, direction ? 255 - dim : dim); + vrtFlush(*(_DWORD *)virt); + v7 = GetTickCount(); + if ( v7 - v5 < 42 ) + Sleep(v5 - v7 + 42); + } + vrtSetAlphaBlendMode(*(_DWORD *)virt, 0, 255); +#endif + +} + } // End of namespace Fullpipe diff --git a/engines/fullpipe/gfx.h b/engines/fullpipe/gfx.h index 191df7709a..d94dd40452 100644 --- a/engines/fullpipe/gfx.h +++ b/engines/fullpipe/gfx.h @@ -38,32 +38,31 @@ struct Bitmap { int _type; int _dataSize; int _flags; + Graphics::TransparentSurface *_surface; + int _flipping; Bitmap(); Bitmap(Bitmap *src); ~Bitmap(); void load(Common::ReadStream *s); - void putDib(int x, int y, int32 *palette); - bool putDibRB(int32 *palette, int x = -1, int y = -1); + void decode(int32 *palette); + void putDib(int x, int y, int32 *palette, int alpha); + bool putDibRB(int32 *palette); void putDibCB(int32 *palette); - void colorFill(uint16 *dest, int len, int32 color); - void paletteFill(uint16 *dest, byte *src, int len, int32 *palette); - void copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format); - void copier(uint16 *dest, byte *src, int len, int32 *palette, bool cb05_format); + void colorFill(uint32 *dest, int len, int32 color); + void paletteFill(uint32 *dest, byte *src, int len, int32 *palette); + void copierKeyColor(uint32 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format); + void copier(uint32 *dest, byte *src, int len, int32 *palette, bool cb05_format); - Bitmap *reverseImage(); - Bitmap *reverseImageRB(); - Bitmap *reverseImageCB(); - Bitmap *reverseImageCB05(); + Bitmap *reverseImage(bool flip = true); Bitmap *flipVertical(); - void drawShaded(int type, int x, int y, byte *palette); - void drawRotated(int x, int y, int angle, byte *palette); + void drawShaded(int type, int x, int y, byte *palette, int alpha); + void drawRotated(int x, int y, int angle, byte *palette, int alpha); bool isPixelHitAtPos(int x, int y); - bool isPixelAtHitPosRB(int x, int y); }; class Picture : public MemoryObject { diff --git a/engines/fullpipe/mgm.cpp b/engines/fullpipe/mgm.cpp new file mode 100644 index 0000000000..aacfd5452a --- /dev/null +++ b/engines/fullpipe/mgm.cpp @@ -0,0 +1,719 @@ +/* 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 "fullpipe/fullpipe.h" + +#include "fullpipe/utils.h" +#include "fullpipe/statics.h" +#include "fullpipe/motion.h" +#include "fullpipe/messages.h" + +namespace Fullpipe { + +void MGM::clear() { + _items.clear(); +} + +MessageQueue *MGM::genMQ(StaticANIObject *ani, int staticsIndex, int staticsId, int *resStatId, Common::Point **pointArr) { + int idx = getItemIndexById(ani->_id); + + if (idx == -1) + return 0; + + int stid = staticsId; + + if (!staticsId) { + if (ani->_movement) { + stid = ani->_movement->_staticsObj2->_staticsId; + } else { + if (!ani->_statics) + return 0; + + stid = ani->_statics->_staticsId; + } + } + + if (stid == staticsIndex) + return new MessageQueue(g_fp->_globalMessageQueueList->compact()); + + int startidx = getStaticsIndexById(idx, stid); + int endidx = getStaticsIndexById(idx, staticsIndex); + int subidx = startidx + endidx * _items[idx]->statics.size(); + + if (!_items[idx]->subItems[subidx]->movement) { + clearMovements2(idx); + recalcOffsets(idx, startidx, endidx, 0, 1); + } + + if (!_items[idx]->subItems[subidx]->movement) + return 0; + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + Common::Point point; + ExCommand *ex; + + int i = 0; + do { + subidx = startidx + endidx * _items[idx]->statics.size(); + + _items[idx]->subItems[subidx]->movement->calcSomeXY(point, 0, -1); + + if (pointArr) { + int sz; + + if (_items[idx]->subItems[subidx]->movement->_currMovement) + sz = _items[idx]->subItems[subidx]->movement->_currMovement->_dynamicPhases.size(); + else + sz = _items[idx]->subItems[subidx]->movement->_dynamicPhases.size(); + + ex = new ExCommand2(20, ani->_id, &pointArr[i], sz); + + ex->_messageNum = _items[idx]->subItems[subidx]->movement->_id; + } else { + ex = new ExCommand(ani->_id, 1, _items[idx]->subItems[subidx]->movement->_id, 0, 0, 0, 1, 0, 0, 0); + } + + ex->_keyCode = ani->_okeyCode; + ex->_field_3C = 1; + ex->_field_24 = 1; + + mq->addExCommandToEnd(ex); + + if (resStatId) + *resStatId = _items[idx]->subItems[subidx]->movement->_id; + + startidx = _items[idx]->subItems[subidx]->staticsIndex; + + uint step; + + if (_items[idx]->subItems[subidx]->movement->_currMovement) + step = _items[idx]->subItems[subidx]->movement->_currMovement->_dynamicPhases.size(); + else + step = _items[idx]->subItems[subidx]->movement->_dynamicPhases.size(); + + i += step; + } while (startidx != endidx); + + return mq; +} + +MGMItem::MGMItem() { + objId = 0; +} + +MGMSubItem::MGMSubItem() { + movement = 0; + staticsIndex = 0; + field_8 = 0; + field_C = 0; + x = 0; + y = 0; +} + +void MGM::addItem(int objId) { + if (getItemIndexById(objId) == -1) { + MGMItem *item = new MGMItem(); + + item->objId = objId; + _items.push_back(item); + } + rebuildTables(objId); +} + +void MGM::rebuildTables(int objId) { + int idx = getItemIndexById(objId); + + if (idx == -1) + return; + + _items[idx]->subItems.clear(); + _items[idx]->statics.clear(); + _items[idx]->movements1.clear(); + _items[idx]->movements2.clear(); + + StaticANIObject *obj = g_fp->_currentScene->getStaticANIObject1ById(objId, -1); + + if (!obj) + return; + + for (uint i = 0; i < obj->_staticsList.size(); i++) + _items[idx]->statics.push_back((Statics *)obj->_staticsList[i]); + + for (uint i = 0; i < obj->_movements.size(); i++) + _items[idx]->movements1.push_back((Movement *)obj->_movements[i]); + + _items[idx]->subItems.clear(); +} + +int MGM::getItemIndexById(int objId) { + for (uint i = 0; i < _items.size(); i++) + if (_items[i]->objId == objId) + return i; + + return -1; +} + +MessageQueue *MGM::genMovement(MGMInfo *mgminfo) { + if (!mgminfo->ani) + return 0; + + Movement *mov = mgminfo->ani->_movement; + + if (!mov && !mgminfo->ani->_statics) + return 0; + + if (!(mgminfo->flags & 1)) { + if (mov) + mgminfo->staticsId1 = mov->_staticsObj2->_staticsId; + else + mgminfo->staticsId1 = mgminfo->ani->_statics->_staticsId; + } + + Common::Point point; + + if (!(mgminfo->flags & 0x10) || !(mgminfo->flags & 0x20)) { + int nx = mgminfo->ani->_ox; + int ny = mgminfo->ani->_oy; + + if (mgminfo->ani->_movement) { + mgminfo->ani->calcNextStep(&point); + + nx += point.x; + ny += point.y; + } + + if (!(mgminfo->flags & 0x10)) + mgminfo->x2 = nx; + + if (!(mgminfo->flags & 0x20)) + mgminfo->y2 = ny; + } + + mov = mgminfo->ani->getMovementById(mgminfo->movementId); + + if (!mov) + return 0; + + int itemIdx = getItemIndexById(mgminfo->ani->_id); + int subIdx = getStaticsIndexById(itemIdx, mgminfo->staticsId1); + int st2idx = getStaticsIndexById(itemIdx, mov->_staticsObj1->_staticsId); + int st1idx = getStaticsIndexById(itemIdx, mov->_staticsObj2->_staticsId); + int subOffset = getStaticsIndexById(itemIdx, mgminfo->staticsId2); + + clearMovements2(itemIdx); + recalcOffsets(itemIdx, subIdx, st2idx, 0, 1); + clearMovements2(itemIdx); + recalcOffsets(itemIdx, st1idx, subOffset, 0, 1); + + MGMSubItem *sub1 = _items[itemIdx]->subItems[subIdx + st2idx * _items[itemIdx]->statics.size()]; + MGMSubItem *sub2 = _items[itemIdx]->subItems[st1idx + subOffset * _items[itemIdx]->statics.size()]; + + if (subIdx != st2idx && !sub1->movement) + return 0; + + if (st1idx != subOffset && !sub2->movement) + return 0; + + int n1x = mgminfo->x1 - mgminfo->x2 - sub1->x - sub2->x; + int n1y = mgminfo->y1 - mgminfo->y2 - sub1->y - sub2->y; + + Common::Point point1; + + mov->calcSomeXY(point1, 0, -1); + + int n2x = point1.x; + int n2y = point1.y; + int mult; + int len = -1; + + if (mgminfo->flags & 0x40) { + mult = mgminfo->field_10; + len = -1; + n2x *= mult; + n2y *= mult; + } else { + calcLength(&point, mov, n1x, n1y, &mult, &len, 1); + n2x = point.x; + n2y = point.y; + } + + if (!(mgminfo->flags & 2)) { + len = -1; + n2x = mult * point1.x; + n1x = mult * point1.x; + mgminfo->x1 = mgminfo->x2 + mult * point1.x + sub1->x + sub2->x; + } + + if (!(mgminfo->flags & 4)) { + n2y = mult * point1.y; + n1y = mult * point1.y; + len = -1; + mgminfo->y1 = mgminfo->y2 + mult * point1.y + sub1->y + sub2->y; + } + + int px = 0; + int py = 0; + + if (sub1->movement) { + px = countPhases(itemIdx, subIdx, st2idx, 1); + py = countPhases(itemIdx, subIdx, st2idx, 2); + } + + if (mult > 1) { + px += (mult - 1) * mov->countPhasesWithFlag(-1, 1); + py += (mult - 1) * mov->countPhasesWithFlag(-1, 2); + } + + if (mult > 0) { + px += mov->countPhasesWithFlag(len, 1); + py += mov->countPhasesWithFlag(len, 2); + } + + if (sub2->movement) { + px += countPhases(itemIdx, st1idx, subOffset, 1); + py += countPhases(itemIdx, st1idx, subOffset, 2); + } + + int dx1 = n1x - n2x; + int dy1 = n1y - n2y; + int x1, y1; + + if (px) { + x1 = (int)((double)dx1 / (double)px); + } else { + x1 = 0; + } + + if (py) { + y1 = (int)((double)dy1 / (double)py); + } else { + y1 = 0; + } + + Common::Point x2, y2; + + y2.x = dx1 - px * x1; + y2.y = dy1 - py * y1; + + if (n1x - n2x == px * x1) + x2.x = 0; + else + x2.x = (dx1 - px * x1) / abs(dx1 - px * x1); + + if (dy1 == py * y1) + x2.y = 0; + else + x2.y = (dy1 - py * y1) / abs(dy1 - py * y1); + + MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); + ExCommand2 *ex2; + + for (int i = subIdx; i != st2idx;) { + MGMSubItem *s = _items[itemIdx]->subItems[i + subOffset * _items[itemIdx]->statics.size()]; + + ex2 = buildExCommand2(s->movement, mgminfo->ani->_id, x1, y1, &x2, &y2, -1); + ex2->_parId = mq->_id; + ex2->_keyCode = mgminfo->ani->_okeyCode; + + mq->addExCommandToEnd(ex2); + + i = s->staticsIndex; + } + + for (int i = 0; i < mult; ++i) { + int plen; + + if (i == mult - 1) + plen = len; + else + plen = -1; + + ex2 = buildExCommand2(mov, mgminfo->ani->_id, x1, y1, &x2, &y2, plen); + ex2->_parId = mq->_id; + ex2->_keyCode = mgminfo->ani->_okeyCode; + + mq->addExCommandToEnd(ex2); + } + + for (int j = st1idx; j != subOffset;) { + MGMSubItem *s = _items[itemIdx]->subItems[j + subOffset * _items[itemIdx]->statics.size()]; + + ex2 = buildExCommand2(s->movement, mgminfo->ani->_id, x1, y1, &x2, &y2, -1); + ex2->_parId = mq->_id; + ex2->_keyCode = mgminfo->ani->_okeyCode; + + mq->addExCommandToEnd(ex2); + + j = s->staticsIndex; + } + + ExCommand *ex = new ExCommand(mgminfo->ani->_id, 5, -1, mgminfo->x1, mgminfo->y1, 0, 1, 0, 0, 0); + + ex->_field_14 = mgminfo->field_1C; + ex->_keyCode = mgminfo->ani->_okeyCode; + ex->_field_24 = 0; + ex->_excFlags |= 3; + + mq->addExCommandToEnd(ex); + + return mq; +} + +int MGM::countPhases(int idx, int subIdx, int endIdx, int flag) { + int res = 0; + + if (endIdx < 0) + return 0; + + while (subIdx != endIdx) { + if (subIdx < 0) + break; + + res += _items[idx]->subItems[subIdx + endIdx * _items[idx]->statics.size()]->movement->countPhasesWithFlag(-1, flag); + + subIdx = _items[idx]->subItems[subIdx + 6 * endIdx * _items[idx]->statics.size()]->staticsIndex; + } + + return res; +} +void MGM::updateAnimStatics(StaticANIObject *ani, int staticsId) { + if (getItemIndexById(ani->_id) == -1) + return; + + if (ani->_movement) { + ani->queueMessageQueue(0); + ani->_movement->gotoLastFrame(); + ani->_statics = ani->_movement->_staticsObj2; + + int x = ani->_movement->_ox; + int y = ani->_movement->_oy; + + ani->_movement = 0; + + ani->setOXY(x, y); + } + + if (ani->_statics) { + Common::Point point; + + getPoint(&point, ani->_id, ani->_statics->_staticsId, staticsId); + + ani->setOXY(ani->_ox + point.x, ani->_oy + point.y); + + ani->_statics = ani->getStaticsById(staticsId); + } +} + +Common::Point *MGM::getPoint(Common::Point *point, int objectId, int staticsId1, int staticsId2) { + int idx = getItemIndexById(objectId); + + if (idx == -1) { + point->x = -1; + point->y = -1; + } else { + int st1idx = getStaticsIndexById(idx, staticsId1); + int st2idx = getStaticsIndexById(idx, staticsId2); + + if (st1idx == st2idx) { + point->x = 0; + point->y = 0; + } else { + int subidx = st1idx + st2idx * _items[idx]->statics.size(); + + if (!_items[idx]->subItems[subidx]->movement) { + clearMovements2(idx); + recalcOffsets(idx, st1idx, st2idx, false, true); + + if (!_items[idx]->subItems[subidx]->movement) { + clearMovements2(idx); + recalcOffsets(idx, st1idx, st2idx, true, false); + } + } + + MGMSubItem *sub = _items[idx]->subItems[subidx]; + + if (sub->movement) { + point->x = sub->x; + point->y = sub->y; + } else { + point->x = 0; + point->y = 0; + } + } + } + + return point; +} + +int MGM::getStaticsIndexById(int idx, int16 id) { + if (!_items[idx]->statics.size()) + return -1; + + for (uint i = 0; i < _items[idx]->statics.size(); i++) { + if (_items[idx]->statics[i]->_staticsId == id) + return i; + } + + return 0; +} + +int MGM::getStaticsIndex(int idx, Statics *st) { + if (!_items[idx]->statics.size()) + return -1; + + for (uint i = 0; i < _items[idx]->statics.size(); i++) { + if (_items[idx]->statics[i] == st) + return i; + } + + return 0; +} + +void MGM::clearMovements2(int idx) { + _items[idx]->movements2.clear(); +} + +int MGM::recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop) { + MGMItem *item = _items[idx]; + int subIdx = st1idx + st2idx * item->statics.size(); + + if (st1idx == st2idx) { + memset(&item->subItems[subIdx], 0, sizeof(item->subItems[subIdx])); + return 0; + } + + if (item->subItems[subIdx]) + return item->subItems[subIdx]->field_8; + + Common::Point point; + + for (uint i = 0; i < item->movements1.size(); i++) { + Movement *mov = item->movements1[i]; + + if (mov->_staticsObj1 == item->statics[st1idx]) { + if (!item->movements2[i] && (!flop || mov->_field_50)) { + item->movements2[i] = 1; + + int stidx = getStaticsIndex(idx, item->movements1[i]->_staticsObj2); + int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop); + int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + int newsz = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C; + + if (recalc >= 0) { + if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1 || + (item->subItems[subIdx]->field_8 == recalc + 1 && item->subItems[subIdx]->field_C > newsz)) { + item->subItems[subIdx]->movement = mov; + item->subItems[subIdx]->staticsIndex = stidx; + item->subItems[subIdx]->field_8 = recalc + 1; + item->subItems[subIdx]->field_C = newsz; + + mov->calcSomeXY(point, 0, -1); + + item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x + point.x; + item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y + point.y; + } + } + } + } else if (flip) { + if (mov->_staticsObj2 == item->statics[st1idx]) { + if (!item->movements2[i] && (!flop || mov->_field_50)) { + item->movements2[i] = 1; + + int stidx = getStaticsIndex(idx, mov->_staticsObj1); + int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop); + + if (recalc >= 0) { + if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1) { + item->subItems[subIdx]->movement = mov; + item->subItems[subIdx]->staticsIndex = stidx; + item->subItems[subIdx]->field_8 = recalc + 1; + + int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + + item->subItems[subIdx]->field_C = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C; + + mov->calcSomeXY(point, 0, -1); + + item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x - point.x; + item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y - point.y; + } + } + } + } + } + } + + if (item->subItems[subIdx]->movement) + return item->subItems[subIdx]->field_8; + + return -1; +} + +int MGM::refreshOffsets(int objectId, int idx1, int idx2) { + int idx = getItemIndexById(objectId); + + if (idx != -1) { + int from = getStaticsIndexById(idx, idx1); + int to = getStaticsIndexById(idx, idx2); + + MGMSubItem *sub = _items[idx]->subItems[from + to * _items[idx]->statics.size()]; + + if (sub->movement) { + idx = sub->field_8; + } else { + clearMovements2(idx); + idx = recalcOffsets(idx, from, to, 0, 1); + } + } + + return idx; +} + +Common::Point *MGM::calcLength(Common::Point *pRes, Movement *mov, int x, int y, int *mult, int *len, int flag) { + Common::Point point; + + mov->calcSomeXY(point, 0, -1); + int p1x = point.x; + int p1y = point.y; + + int newmult = 0; + int oldlen = *len; + + if (abs(p1y) > abs(p1x)) { + if (mov->calcSomeXY(point, 0, -1)->y) + newmult = (int)((double)y / mov->calcSomeXY(point, 0, -1)->y); + } else if (mov->calcSomeXY(point, 0, -1)->x) { + newmult = (int)((double)x / mov->calcSomeXY(point, 0, -1)->x); + } + + if (newmult < 0) + newmult = 0; + + *mult = newmult; + + int phase = 1; + int sz; + + if (flag) { + if (abs(p1y) > abs(p1x)) { + while (abs(p1y * newmult + mov->calcSomeXY(point, 0, phase)->y) < abs(y)) { + sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + + if (phase > sz) + break; + + phase++; + } + } else { + while (abs(p1x * newmult + mov->calcSomeXY(point, 0, phase)->x) < abs(x)) { + sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); + + if (phase >= sz) + break; + + phase++; + } + } + + *len = phase - 1; + } else { + *len = -1; + } + + int p2x = 0; + int p2y = 0; + + if (!oldlen) + oldlen = -1; + + if (oldlen > 0) { + ++*mult; + + mov->calcSomeXY(point, 0, oldlen); + p2x = point.x; + p2y = point.y; + + if (abs(p1y) > abs(p1x)) + p2x = p1x; + else + p2y = p1y; + } + + pRes->x = p2x + p1x * newmult; + pRes->y = p2y + p1y * newmult; + + return pRes; +} + +ExCommand2 *MGM::buildExCommand2(Movement *mov, int objId, int x1, int y1, Common::Point *x2, Common::Point *y2, int len) { + uint cnt; + + if (mov->_currMovement) + cnt = mov->_currMovement->_dynamicPhases.size(); + else + cnt = mov->_dynamicPhases.size(); + + if (len > 0 && cnt > (uint)len) + cnt = len; + + Common::Point **points = (Common::Point **)malloc(sizeof(Common::Point *) * cnt); + + for (uint i = 0; i < cnt; i++) { + int flags = mov->getDynamicPhaseByIndex(i)->getDynFlags(); + + points[i] = new Common::Point; + + if (flags & 1) { + points[i]->x = x1 + x2->x; + + y2->x -= x2->x; + + if (!y2->x) + x2->x = 0; + } + + if (flags & 2) { + points[i]->y = y1 + x2->y; + + y2->y -= x2->y; + + if (!y2->y) + x2->y = 0; + } + } + + ExCommand2 *ex = new ExCommand2(20, objId, points, cnt); + ex->_excFlags = 2; + ex->_messageNum = mov->_id; + ex->_field_14 = len; + ex->_field_24 = 1; + ex->_keyCode = -1; + + for (uint i = 0; i < cnt; i++) + delete points[i]; + + free(points); + + return ex; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/mgm.h b/engines/fullpipe/mgm.h new file mode 100644 index 0000000000..13195891da --- /dev/null +++ b/engines/fullpipe/mgm.h @@ -0,0 +1,95 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_MGM_H +#define FULLPIPE_MGM_H + +namespace Fullpipe { + +class ExCommand2; +class Movement; +class Statics; + +struct MGMSubItem { + Movement *movement; + int staticsIndex; + int field_8; + int field_C; + int x; + int y; + + MGMSubItem(); +}; + +struct MGMItem { + int16 objId; + Common::Array<MGMSubItem *> subItems; + Common::Array<Statics *> statics; + Common::Array<Movement *> movements1; + Common::Array<int> movements2; + + MGMItem(); +}; + +struct MGMInfo { + StaticANIObject *ani; + int staticsId1; + int staticsId2; + int movementId; + int field_10; + int x1; + int y1; + int field_1C; + int x2; + int y2; + int flags; + + MGMInfo() { memset(this, 0, sizeof(MGMInfo)); } +}; + +class MGM : public CObject { +public: + Common::Array<MGMItem *> _items; + +public: + void clear(); + void addItem(int objId); + void rebuildTables(int objId); + int getItemIndexById(int objId); + + MessageQueue *genMovement(MGMInfo *mgminfo); + void updateAnimStatics(StaticANIObject *ani, int staticsId); + Common::Point *getPoint(Common::Point *point, int aniId, int staticsId1, int staticsId2); + int getStaticsIndexById(int idx, int16 id); + int getStaticsIndex(int idx, Statics *st); + void clearMovements2(int idx); + int recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop); + Common::Point *calcLength(Common::Point *point, Movement *mov, int x, int y, int *mult, int *len, int flag); + ExCommand2 *buildExCommand2(Movement *mov, int objId, int x1, int y1, Common::Point *x2, Common::Point *y2, int len); + MessageQueue *genMQ(StaticANIObject *ani, int staticsIndex, int staticsId, int *resStatId, Common::Point **pointArr); + int countPhases(int idx, int subIdx, int subOffset, int flag); + int refreshOffsets(int objectId, int idx1, int idx2); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MGM_H */ diff --git a/engines/fullpipe/modal.cpp b/engines/fullpipe/modal.cpp index 3dbbeb78c4..2fd7ef0c21 100644 --- a/engines/fullpipe/modal.cpp +++ b/engines/fullpipe/modal.cpp @@ -198,11 +198,9 @@ bool ModalIntro::init(int counterdiff) { } void ModalIntro::update() { - warning("STUB: ModalIntro::update()"); - if (g_fp->_currentScene) { if (_introFlags & 1) { - //sceneFade(virt, g_currentScene, 1); + g_fp->sceneFade(g_fp->_currentScene, true); _stillRunning = 255; _introFlags &= 0xfe; @@ -210,12 +208,12 @@ void ModalIntro::update() { g_fp->playSound(SND_INTR_019, 0); } else if (_introFlags & 2) { if (g_vars->sceneIntro_needBlackout) { - //vrtRectangle(*(_DWORD *)virt, 0, 0, 0, 800, 600); + g_fp->drawAlphaRectangle(0, 0, 800, 600, 0); g_vars->sceneIntro_needBlackout = 0; _stillRunning = 0; _introFlags &= 0xfd; } else { - //sceneFade(virt, g_currentScene, 0); + g_fp->sceneFade(g_fp->_currentScene, false); _stillRunning = 0; _introFlags &= 0xfd; } @@ -728,8 +726,6 @@ bool ModalCredits::init(int counterdiff) { } void ModalCredits::update() { - warning("STUB: ModalCredits::update()"); - if (_fadeOut) { if (_fadeIn) { _sceneTitles->draw(); @@ -737,14 +733,14 @@ void ModalCredits::update() { return; } } else if (_fadeIn) { - //sceneFade(virt, this->_sceneTitles, 1); // TODO + g_fp->sceneFade(_sceneTitles, true); _fadeOut = 1; return; } if (_fadeOut) { - //sceneFade(virt, this->_sceneTitles, 0); // TODO + g_fp->sceneFade(_sceneTitles, false); _fadeOut = 0; return; } @@ -922,7 +918,7 @@ bool ModalMainMenu::init(int counterdiff) { g_fp->_modalObject = mq; mq->_parentObj = this; - mq->create(_scene, (PictureObject *)_scene->_picObjList[0], PIC_MEX_BGR); + mq->create(_scene, _scene, PIC_MEX_BGR); _hoverAreaId = 0; @@ -1322,7 +1318,7 @@ void ModalHelp::launch() { } ModalQuery::ModalQuery() { - _picObjList = 0; + _bgScene = 0; _bg = 0; _okBtn = 0; _cancelBtn = 0; @@ -1335,7 +1331,7 @@ ModalQuery::~ModalQuery() { _okBtn->_flags &= 0xFFFB; } -bool ModalQuery::create(Scene *sc, PictureObject *picObjList, int id) { +bool ModalQuery::create(Scene *sc, Scene *bgScene, int id) { if (id == PIC_MEX_BGR) { _bg = sc->getPictureObjectById(PIC_MEX_BGR, 0); @@ -1372,14 +1368,14 @@ bool ModalQuery::create(Scene *sc, PictureObject *picObjList, int id) { } _queryResult = -1; - _picObjList = picObjList; + _bgScene = bgScene; return true; } void ModalQuery::update() { - if (_picObjList) - _picObjList->draw(); + if (_bgScene) + _bgScene->draw(); _bg->draw(); @@ -1430,9 +1426,12 @@ bool ModalQuery::init(int counterdiff) { _okBtn->_flags &= 0xFFFB; if (_queryResult == 1) { + if (_bgScene) + g_fp->sceneFade(_bgScene, false); + warning("STUB: ModalQuery::init()"); - //sceneFade(g_vrtDrawHandle, (Scene *)this->_picObjList, 0); + // Quit game //if (inputArFlag) { // g_needRestart = 1; // return 0; @@ -1596,7 +1595,7 @@ void ModalSaveGame::setup(Scene *sc, int mode) { fileinfo = new FileInfo; memset(fileinfo, 0, sizeof(FileInfo)); - strncpy(fileinfo->filename, getSavegameFile(i), 160); + Common::strlcpy(fileinfo->filename, getSavegameFile(i), 160); if (!getFileInfo(i, fileinfo)) { fileinfo->empty = true; diff --git a/engines/fullpipe/modal.h b/engines/fullpipe/modal.h index 01d8e6b0ee..a08cb3bce2 100644 --- a/engines/fullpipe/modal.h +++ b/engines/fullpipe/modal.h @@ -235,12 +235,12 @@ public: virtual void update(); virtual void saveload() {} - bool create(Scene *sc, PictureObject *picObjList, int picId); + bool create(Scene *sc, Scene *bgScene, int picId); int getQueryResult() { return _queryResult; } private: - PictureObject *_picObjList; + Scene *_bgScene; PictureObject *_bg; PictureObject *_okBtn; PictureObject *_cancelBtn; diff --git a/engines/fullpipe/module.mk b/engines/fullpipe/module.mk index 3962fe64ba..96bd91fd39 100644 --- a/engines/fullpipe/module.mk +++ b/engines/fullpipe/module.mk @@ -15,6 +15,7 @@ MODULE_OBJS = \ lift.o \ messagehandlers.o \ messages.o \ + mgm.o \ modal.o \ motion.o \ ngiarchive.o \ diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp index 321df7fd22..49cf88434e 100644 --- a/engines/fullpipe/motion.cpp +++ b/engines/fullpipe/motion.cpp @@ -22,15 +22,10 @@ #include "fullpipe/fullpipe.h" -#include "common/file.h" -#include "common/array.h" -#include "common/list.h" - -#include "fullpipe/objects.h" +#include "fullpipe/utils.h" #include "fullpipe/statics.h" #include "fullpipe/gameloader.h" #include "fullpipe/motion.h" -#include "fullpipe/messages.h" namespace Fullpipe { @@ -1470,12 +1465,12 @@ Common::Array<MovArr *> *MovGraph::genMovArr(int x, int y, int *arrSize, int fla return arr; } -void MovGraph::shuffleTree(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<MovGraphLink *> &tempObList1, Common::Array<MovGraphLink *> &tempObList2) { +void MovGraph::findAllPaths(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<MovGraphLink *> &tempObList1, Common::Array<MovGraphLink *> &allPaths) { if (lnk == lnk2) { for (uint i = 0; i < tempObList1.size(); i++) - tempObList2.push_back(tempObList1[i]); + allPaths.push_back(tempObList1[i]); - tempObList2.push_back(lnk); + allPaths.push_back(lnk); } else { lnk->_flags |= 0x80000000; @@ -1492,39 +1487,42 @@ void MovGraph::shuffleTree(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array< } if (!(l->_flags & 0xA0000000)) - shuffleTree(l, lnk2, tempObList1, tempObList2); + findAllPaths(l, lnk2, tempObList1, allPaths); } lnk->_flags &= 0x7FFFFFFF; } } -Common::Array<MovItem *> *MovGraph::calcMovItems(MovArr *movarr1, MovArr *movarr2, int *listCount) { +// Returns a list of possible paths two points in graph space +Common::Array<MovItem *> *MovGraph::calcMovItems(MovArr *currPos, MovArr *destPos, int *pathCount) { Common::Array<MovGraphLink *> tempObList1; - Common::Array<MovGraphLink *> tempObList2; + Common::Array<MovGraphLink *> allPaths; - shuffleTree(movarr1->_link, movarr2->_link, tempObList1, tempObList2); + // Get all paths between two edges of the graph + findAllPaths(currPos->_link, destPos->_link, tempObList1, allPaths); - *listCount = 0; + *pathCount = 0; - if (!tempObList2.size()) + if (!allPaths.size()) return 0; - *listCount = tempObList2.size(); + *pathCount = allPaths.size(); Common::Array<MovItem *> *res = new Common::Array<MovItem *>; - for (int i = 0; i < *listCount; i++) { + for (int i = 0; i < *pathCount; i++) { MovItem *r = new MovItem; - genMovItem(r, tempObList2[i], movarr1, movarr2); + genMovItem(r, allPaths[i], currPos, destPos); res->push_back(r); - delete tempObList2[i]; + delete allPaths[i]; } - movarr2->_link = movarr1->_link; + // Start the resulting path from current position + destPos->_link = currPos->_link; return res; } @@ -2430,7 +2428,7 @@ MessageQueue *MovGraph2::genMovement(MovInfo1 *info) { int y = info->pt2.y - info->pt1.y - my2 - my1; int x = info->pt2.x - info->pt1.x - mx2 - mx1; - int a2; + int a2 = 0; int mgmLen; _mgm.calcLength(&point, _items2[info->index]->_subItems[info->subIndex]._walk[1]._mov, x, y, &mgmLen, &a2, info->flags & 1); @@ -2776,693 +2774,6 @@ MovGraphNode *MovGraph::calcOffset(int ox, int oy) { return res; } -void MGM::clear() { - _items.clear(); -} - -MessageQueue *MGM::genMQ(StaticANIObject *ani, int staticsIndex, int staticsId, int *resStatId, Common::Point **pointArr) { - int idx = getItemIndexById(ani->_id); - - if (idx == -1) - return 0; - - int stid = staticsId; - - if (!staticsId) { - if (ani->_movement) { - stid = ani->_movement->_staticsObj2->_staticsId; - } else { - if (!ani->_statics) - return 0; - - stid = ani->_statics->_staticsId; - } - } - - if (stid == staticsIndex) - return new MessageQueue(g_fp->_globalMessageQueueList->compact()); - - int startidx = getStaticsIndexById(idx, stid); - int endidx = getStaticsIndexById(idx, staticsIndex); - int subidx = startidx + endidx * _items[idx]->statics.size(); - - if (!_items[idx]->subItems[subidx]->movement) { - clearMovements2(idx); - recalcOffsets(idx, startidx, endidx, 0, 1); - } - - if (!_items[idx]->subItems[subidx]->movement) - return 0; - - MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); - Common::Point point; - ExCommand *ex; - - int i = 0; - do { - subidx = startidx + endidx * _items[idx]->statics.size(); - - _items[idx]->subItems[subidx]->movement->calcSomeXY(point, 0, -1); - - if (pointArr) { - int sz; - - if (_items[idx]->subItems[subidx]->movement->_currMovement) - sz = _items[idx]->subItems[subidx]->movement->_currMovement->_dynamicPhases.size(); - else - sz = _items[idx]->subItems[subidx]->movement->_dynamicPhases.size(); - - ex = new ExCommand2(20, ani->_id, &pointArr[i], sz); - - ex->_messageNum = _items[idx]->subItems[subidx]->movement->_id; - } else { - ex = new ExCommand(ani->_id, 1, _items[idx]->subItems[subidx]->movement->_id, 0, 0, 0, 1, 0, 0, 0); - } - - ex->_keyCode = ani->_okeyCode; - ex->_field_3C = 1; - ex->_field_24 = 1; - - mq->addExCommandToEnd(ex); - - if (resStatId) - *resStatId = _items[idx]->subItems[subidx]->movement->_id; - - startidx = _items[idx]->subItems[subidx]->staticsIndex; - - uint step; - - if (_items[idx]->subItems[subidx]->movement->_currMovement) - step = _items[idx]->subItems[subidx]->movement->_currMovement->_dynamicPhases.size(); - else - step = _items[idx]->subItems[subidx]->movement->_dynamicPhases.size(); - - i += step; - } while (startidx != endidx); - - return mq; -} - -MGMItem::MGMItem() { - objId = 0; -} - -MGMSubItem::MGMSubItem() { - movement = 0; - staticsIndex = 0; - field_8 = 0; - field_C = 0; - x = 0; - y = 0; -} - -void MGM::addItem(int objId) { - if (getItemIndexById(objId) == -1) { - MGMItem *item = new MGMItem(); - - item->objId = objId; - _items.push_back(item); - } - rebuildTables(objId); -} - -void MGM::rebuildTables(int objId) { - int idx = getItemIndexById(objId); - - if (idx == -1) - return; - - _items[idx]->subItems.clear(); - _items[idx]->statics.clear(); - _items[idx]->movements1.clear(); - _items[idx]->movements2.clear(); - - StaticANIObject *obj = g_fp->_currentScene->getStaticANIObject1ById(objId, -1); - - if (!obj) - return; - - for (uint i = 0; i < obj->_staticsList.size(); i++) - _items[idx]->statics.push_back((Statics *)obj->_staticsList[i]); - - for (uint i = 0; i < obj->_movements.size(); i++) - _items[idx]->movements1.push_back((Movement *)obj->_movements[i]); - - _items[idx]->subItems.clear(); -} - -int MGM::getItemIndexById(int objId) { - for (uint i = 0; i < _items.size(); i++) - if (_items[i]->objId == objId) - return i; - - return -1; -} - -MessageQueue *MGM::genMovement(MGMInfo *mgminfo) { - if (!mgminfo->ani) - return 0; - - Movement *mov = mgminfo->ani->_movement; - - if (!mov && !mgminfo->ani->_statics) - return 0; - - if (!(mgminfo->flags & 1)) { - if (mov) - mgminfo->staticsId1 = mov->_staticsObj2->_staticsId; - else - mgminfo->staticsId1 = mgminfo->ani->_statics->_staticsId; - } - - Common::Point point; - - if (!(mgminfo->flags & 0x10) || !(mgminfo->flags & 0x20)) { - int nx = mgminfo->ani->_ox; - int ny = mgminfo->ani->_oy; - - if (mgminfo->ani->_movement) { - mgminfo->ani->calcNextStep(&point); - - nx += point.x; - ny += point.y; - } - - if (!(mgminfo->flags & 0x10)) - mgminfo->x2 = nx; - - if (!(mgminfo->flags & 0x20)) - mgminfo->y2 = ny; - } - - mov = mgminfo->ani->getMovementById(mgminfo->movementId); - - if (!mov) - return 0; - - int itemIdx = getItemIndexById(mgminfo->ani->_id); - int subIdx = getStaticsIndexById(itemIdx, mgminfo->staticsId1); - int st2idx = getStaticsIndexById(itemIdx, mov->_staticsObj1->_staticsId); - int st1idx = getStaticsIndexById(itemIdx, mov->_staticsObj2->_staticsId); - int subOffset = getStaticsIndexById(itemIdx, mgminfo->staticsId2); - - clearMovements2(itemIdx); - recalcOffsets(itemIdx, subIdx, st2idx, 0, 1); - clearMovements2(itemIdx); - recalcOffsets(itemIdx, st1idx, subOffset, 0, 1); - - MGMSubItem *sub1 = _items[itemIdx]->subItems[subIdx + st2idx * _items[itemIdx]->statics.size()]; - MGMSubItem *sub2 = _items[itemIdx]->subItems[st1idx + subOffset * _items[itemIdx]->statics.size()]; - - if (subIdx != st2idx && !sub1->movement) - return 0; - - if (st1idx != subOffset && !sub2->movement) - return 0; - - int n1x = mgminfo->x1 - mgminfo->x2 - sub1->x - sub2->x; - int n1y = mgminfo->y1 - mgminfo->y2 - sub1->y - sub2->y; - - Common::Point point1; - - mov->calcSomeXY(point1, 0, -1); - - int n2x = point1.x; - int n2y = point1.y; - int mult; - int len = -1; - - if (mgminfo->flags & 0x40) { - mult = mgminfo->field_10; - len = -1; - n2x *= mult; - n2y *= mult; - } else { - calcLength(&point, mov, n1x, n1y, &mult, &len, 1); - n2x = point.x; - n2y = point.y; - } - - if (!(mgminfo->flags & 2)) { - len = -1; - n2x = mult * point1.x; - n1x = mult * point1.x; - mgminfo->x1 = mgminfo->x2 + mult * point1.x + sub1->x + sub2->x; - } - - if (!(mgminfo->flags & 4)) { - n2y = mult * point1.y; - n1y = mult * point1.y; - len = -1; - mgminfo->y1 = mgminfo->y2 + mult * point1.y + sub1->y + sub2->y; - } - - int px = 0; - int py = 0; - - if (sub1->movement) { - px = countPhases(itemIdx, subIdx, st2idx, 1); - py = countPhases(itemIdx, subIdx, st2idx, 2); - } - - if (mult > 1) { - px += (mult - 1) * mov->countPhasesWithFlag(-1, 1); - py += (mult - 1) * mov->countPhasesWithFlag(-1, 2); - } - - if (mult > 0) { - px += mov->countPhasesWithFlag(len, 1); - py += mov->countPhasesWithFlag(len, 2); - } - - if (sub2->movement) { - px += countPhases(itemIdx, st1idx, subOffset, 1); - py += countPhases(itemIdx, st1idx, subOffset, 2); - } - - int dx1 = n1x - n2x; - int dy1 = n1y - n2y; - int x1, y1; - - if (px) { - x1 = (int)((double)dx1 / (double)px); - } else { - x1 = 0; - } - - if (py) { - y1 = (int)((double)dy1 / (double)py); - } else { - y1 = 0; - } - - Common::Point x2, y2; - - y2.x = dx1 - px * x1; - y2.y = dy1 - py * y1; - - if (n1x - n2x == px * x1) - x2.x = 0; - else - x2.x = (dx1 - px * x1) / abs(dx1 - px * x1); - - if (dy1 == py * y1) - x2.y = 0; - else - x2.y = (dy1 - py * y1) / abs(dy1 - py * y1); - - MessageQueue *mq = new MessageQueue(g_fp->_globalMessageQueueList->compact()); - ExCommand2 *ex2; - - for (int i = subIdx; i != st2idx;) { - MGMSubItem *s = _items[itemIdx]->subItems[i + subOffset * _items[itemIdx]->statics.size()]; - - ex2 = buildExCommand2(s->movement, mgminfo->ani->_id, x1, y1, &x2, &y2, -1); - ex2->_parId = mq->_id; - ex2->_keyCode = mgminfo->ani->_okeyCode; - - mq->addExCommandToEnd(ex2); - - i = s->staticsIndex; - } - - for (int i = 0; i < mult; ++i) { - int plen; - - if (i == mult - 1) - plen = len; - else - plen = -1; - - ex2 = buildExCommand2(mov, mgminfo->ani->_id, x1, y1, &x2, &y2, plen); - ex2->_parId = mq->_id; - ex2->_keyCode = mgminfo->ani->_okeyCode; - - mq->addExCommandToEnd(ex2); - } - - for (int j = st1idx; j != subOffset;) { - MGMSubItem *s = _items[itemIdx]->subItems[j + subOffset * _items[itemIdx]->statics.size()]; - - ex2 = buildExCommand2(s->movement, mgminfo->ani->_id, x1, y1, &x2, &y2, -1); - ex2->_parId = mq->_id; - ex2->_keyCode = mgminfo->ani->_okeyCode; - - mq->addExCommandToEnd(ex2); - - j = s->staticsIndex; - } - - ExCommand *ex = new ExCommand(mgminfo->ani->_id, 5, -1, mgminfo->x1, mgminfo->y1, 0, 1, 0, 0, 0); - - ex->_field_14 = mgminfo->field_1C; - ex->_keyCode = mgminfo->ani->_okeyCode; - ex->_field_24 = 0; - ex->_excFlags |= 3; - - mq->addExCommandToEnd(ex); - - return mq; -} - -int MGM::countPhases(int idx, int subIdx, int endIdx, int flag) { - int res = 0; - - if (endIdx < 0) - return 0; - - while (subIdx != endIdx) { - if (subIdx < 0) - break; - - res += _items[idx]->subItems[subIdx + endIdx * _items[idx]->statics.size()]->movement->countPhasesWithFlag(-1, flag); - - subIdx = _items[idx]->subItems[subIdx + 6 * endIdx * _items[idx]->statics.size()]->staticsIndex; - } - - return res; -} -void MGM::updateAnimStatics(StaticANIObject *ani, int staticsId) { - if (getItemIndexById(ani->_id) == -1) - return; - - if (ani->_movement) { - ani->queueMessageQueue(0); - ani->_movement->gotoLastFrame(); - ani->_statics = ani->_movement->_staticsObj2; - - int x = ani->_movement->_ox; - int y = ani->_movement->_oy; - - ani->_movement = 0; - - ani->setOXY(x, y); - } - - if (ani->_statics) { - Common::Point point; - - getPoint(&point, ani->_id, ani->_statics->_staticsId, staticsId); - - ani->setOXY(ani->_ox + point.x, ani->_oy + point.y); - - ani->_statics = ani->getStaticsById(staticsId); - } -} - -Common::Point *MGM::getPoint(Common::Point *point, int objectId, int staticsId1, int staticsId2) { - int idx = getItemIndexById(objectId); - - if (idx == -1) { - point->x = -1; - point->y = -1; - } else { - int st1idx = getStaticsIndexById(idx, staticsId1); - int st2idx = getStaticsIndexById(idx, staticsId2); - - if (st1idx == st2idx) { - point->x = 0; - point->y = 0; - } else { - int subidx = st1idx + st2idx * _items[idx]->statics.size(); - - if (!_items[idx]->subItems[subidx]->movement) { - clearMovements2(idx); - recalcOffsets(idx, st1idx, st2idx, false, true); - - if (!_items[idx]->subItems[subidx]->movement) { - clearMovements2(idx); - recalcOffsets(idx, st1idx, st2idx, true, false); - } - } - - MGMSubItem *sub = _items[idx]->subItems[subidx]; - - if (sub->movement) { - point->x = sub->x; - point->y = sub->y; - } else { - point->x = 0; - point->y = 0; - } - } - } - - return point; -} - -int MGM::getStaticsIndexById(int idx, int16 id) { - if (!_items[idx]->statics.size()) - return -1; - - for (uint i = 0; i < _items[idx]->statics.size(); i++) { - if (_items[idx]->statics[i]->_staticsId == id) - return i; - } - - return 0; -} - -int MGM::getStaticsIndex(int idx, Statics *st) { - if (!_items[idx]->statics.size()) - return -1; - - for (uint i = 0; i < _items[idx]->statics.size(); i++) { - if (_items[idx]->statics[i] == st) - return i; - } - - return 0; -} - -void MGM::clearMovements2(int idx) { - _items[idx]->movements2.clear(); -} - -int MGM::recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop) { - MGMItem *item = _items[idx]; - int subIdx = st1idx + st2idx * item->statics.size(); - - if (st1idx == st2idx) { - memset(&item->subItems[subIdx], 0, sizeof(item->subItems[subIdx])); - return 0; - } - - if (item->subItems[subIdx]) - return item->subItems[subIdx]->field_8; - - Common::Point point; - - for (uint i = 0; i < item->movements1.size(); i++) { - Movement *mov = item->movements1[i]; - - if (mov->_staticsObj1 == item->statics[st1idx]) { - if (!item->movements2[i] && (!flop || mov->_field_50)) { - item->movements2[i] = 1; - - int stidx = getStaticsIndex(idx, item->movements1[i]->_staticsObj2); - int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop); - int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); - int newsz = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C; - - if (recalc >= 0) { - if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1 || - (item->subItems[subIdx]->field_8 == recalc + 1 && item->subItems[subIdx]->field_C > newsz)) { - item->subItems[subIdx]->movement = mov; - item->subItems[subIdx]->staticsIndex = stidx; - item->subItems[subIdx]->field_8 = recalc + 1; - item->subItems[subIdx]->field_C = newsz; - - mov->calcSomeXY(point, 0, -1); - - item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x + point.x; - item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y + point.y; - } - } - } - } else if (flip) { - if (mov->_staticsObj2 == item->statics[st1idx]) { - if (!item->movements2[i] && (!flop || mov->_field_50)) { - item->movements2[i] = 1; - - int stidx = getStaticsIndex(idx, mov->_staticsObj1); - int recalc = recalcOffsets(idx, stidx, st2idx, flip, flop); - - if (recalc >= 0) { - if (!item->subItems[subIdx]->movement || item->subItems[subIdx]->field_8 > recalc + 1) { - item->subItems[subIdx]->movement = mov; - item->subItems[subIdx]->staticsIndex = stidx; - item->subItems[subIdx]->field_8 = recalc + 1; - - int sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); - - item->subItems[subIdx]->field_C = sz + item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->field_C; - - mov->calcSomeXY(point, 0, -1); - - item->subItems[subIdx]->x = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->x - point.x; - item->subItems[subIdx]->y = item->subItems[stidx + 6 * st2idx * _items[idx]->statics.size()]->y - point.y; - } - } - } - } - } - } - - if (item->subItems[subIdx]->movement) - return item->subItems[subIdx]->field_8; - - return -1; -} - -int MGM::refreshOffsets(int objectId, int idx1, int idx2) { - int idx = getItemIndexById(objectId); - - if (idx != -1) { - int from = getStaticsIndexById(idx, idx1); - int to = getStaticsIndexById(idx, idx2); - - MGMSubItem *sub = _items[idx]->subItems[from + to * _items[idx]->statics.size()]; - - if (sub->movement) { - idx = sub->field_8; - } else { - clearMovements2(idx); - idx = recalcOffsets(idx, from, to, 0, 1); - } - } - - return idx; -} - -Common::Point *MGM::calcLength(Common::Point *pRes, Movement *mov, int x, int y, int *mult, int *len, int flag) { - Common::Point point; - - mov->calcSomeXY(point, 0, -1); - int p1x = point.x; - int p1y = point.y; - - int newmult = 0; - int oldlen = *len; - - if (abs(p1y) > abs(p1x)) { - if (mov->calcSomeXY(point, 0, -1)->y) - newmult = (int)((double)y / mov->calcSomeXY(point, 0, -1)->y); - } else if (mov->calcSomeXY(point, 0, -1)->x) { - newmult = (int)((double)x / mov->calcSomeXY(point, 0, -1)->x); - } - - if (newmult < 0) - newmult = 0; - - *mult = newmult; - - int phase = 1; - int sz; - - if (flag) { - if (abs(p1y) > abs(p1x)) { - while (abs(p1y * newmult + mov->calcSomeXY(point, 0, phase)->y) < abs(y)) { - sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); - - if (phase > sz) - break; - - phase++; - } - } else { - while (abs(p1x * newmult + mov->calcSomeXY(point, 0, phase)->x) < abs(x)) { - sz = mov->_currMovement ? mov->_currMovement->_dynamicPhases.size() : mov->_dynamicPhases.size(); - - if (phase >= sz) - break; - - phase++; - } - } - - *len = phase - 1; - } else { - *len = -1; - } - - int p2x = 0; - int p2y = 0; - - if (!oldlen) - oldlen = -1; - - if (oldlen > 0) { - ++*mult; - - mov->calcSomeXY(point, 0, oldlen); - p2x = point.x; - p2y = point.y; - - if (abs(p1y) > abs(p1x)) - p2x = p1x; - else - p2y = p1y; - } - - pRes->x = p2x + p1x * newmult; - pRes->y = p2y + p1y * newmult; - - return pRes; -} - -ExCommand2 *MGM::buildExCommand2(Movement *mov, int objId, int x1, int y1, Common::Point *x2, Common::Point *y2, int len) { - uint cnt; - - if (mov->_currMovement) - cnt = mov->_currMovement->_dynamicPhases.size(); - else - cnt = mov->_dynamicPhases.size(); - - if (len > 0 && cnt > (uint)len) - cnt = len; - - Common::Point **points = (Common::Point **)malloc(sizeof(Common::Point *) * cnt); - - for (uint i = 0; i < cnt; i++) { - int flags = mov->getDynamicPhaseByIndex(i)->getDynFlags(); - - points[i] = new Common::Point; - - if (flags & 1) { - points[i]->x = x1 + x2->x; - - y2->x -= x2->x; - - if (!y2->x) - x2->x = 0; - } - - if (flags & 2) { - points[i]->y = y1 + x2->y; - - y2->y -= x2->y; - - if (!y2->y) - x2->y = 0; - } - } - - ExCommand2 *ex = new ExCommand2(20, objId, points, cnt); - ex->_excFlags = 2; - ex->_messageNum = mov->_id; - ex->_field_14 = len; - ex->_field_24 = 1; - ex->_keyCode = -1; - - for (uint i = 0; i < cnt; i++) - delete points[i]; - - free(points); - - return ex; -} - MovGraphLink::MovGraphLink() { _distance = 0; _angle = 0; diff --git a/engines/fullpipe/motion.h b/engines/fullpipe/motion.h index 2cbf999f86..c488039e22 100644 --- a/engines/fullpipe/motion.h +++ b/engines/fullpipe/motion.h @@ -23,14 +23,13 @@ #ifndef FULLPIPE_MOTION_H #define FULLPIPE_MOTION_H +#include "fullpipe/mgm.h" + namespace Fullpipe { -class Statics; -class Movement; class MctlConnectionPoint; class MovGraphLink; class MessageQueue; -class ExCommand2; struct MovArr; struct MovItem; @@ -124,67 +123,6 @@ public: MotionController *getMotionController(int num) { return _motionControllers[num]->_motionControllerObj; } }; -struct MGMSubItem { - Movement *movement; - int staticsIndex; - int field_8; - int field_C; - int x; - int y; - - MGMSubItem(); -}; - -struct MGMItem { - int16 objId; - Common::Array<MGMSubItem *> subItems; - Common::Array<Statics *> statics; - Common::Array<Movement *> movements1; - Common::Array<int> movements2; - - MGMItem(); -}; - -struct MGMInfo { - StaticANIObject *ani; - int staticsId1; - int staticsId2; - int movementId; - int field_10; - int x1; - int y1; - int field_1C; - int x2; - int y2; - int flags; - - MGMInfo() { memset(this, 0, sizeof(MGMInfo)); } -}; - -class MGM : public CObject { -public: - Common::Array<MGMItem *> _items; - -public: - void clear(); - void addItem(int objId); - void rebuildTables(int objId); - int getItemIndexById(int objId); - - MessageQueue *genMovement(MGMInfo *mgminfo); - void updateAnimStatics(StaticANIObject *ani, int staticsId); - Common::Point *getPoint(Common::Point *point, int aniId, int staticsId1, int staticsId2); - int getStaticsIndexById(int idx, int16 id); - int getStaticsIndex(int idx, Statics *st); - void clearMovements2(int idx); - int recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop); - Common::Point *calcLength(Common::Point *point, Movement *mov, int x, int y, int *mult, int *len, int flag); - ExCommand2 *buildExCommand2(Movement *mov, int objId, int x1, int y1, Common::Point *x2, Common::Point *y2, int len); - MessageQueue *genMQ(StaticANIObject *ani, int staticsIndex, int staticsId, int *resStatId, Common::Point **pointArr); - int countPhases(int idx, int subIdx, int subOffset, int flag); - int refreshOffsets(int objectId, int idx1, int idx2); -}; - struct MctlLadderMovementVars { int varUpGo; int varDownGo; @@ -370,7 +308,7 @@ public: MovGraphNode *calcOffset(int ox, int oy); int getItemIndexByStaticAni(StaticANIObject *ani); Common::Array<MovArr *> *genMovArr(int x, int y, int *arrSize, int flag1, int flag2); - void shuffleTree(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<MovGraphLink *> &tempObList1, Common::Array<MovGraphLink *> &tempObList2); + void findAllPaths(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<MovGraphLink *> &tempObList1, Common::Array<MovGraphLink *> &tempObList2); Common::Array<MovItem *> *calcMovItems(MovArr *movarr1, MovArr *movarr2, int *listCount); void genMovItem(MovItem *movitem, MovGraphLink *grlink, MovArr *movarr1, MovArr *movarr2); bool calcChunk(int idx, int x, int y, MovArr *arr, int a6); diff --git a/engines/fullpipe/scene.cpp b/engines/fullpipe/scene.cpp index 1247d9380e..8463b3ab40 100644 --- a/engines/fullpipe/scene.cpp +++ b/engines/fullpipe/scene.cpp @@ -654,7 +654,7 @@ void Scene::drawContent(int minPri, int maxPri, bool drawBg) { g_fp->_globalPalette = _palette->_data; } - debug(8, "Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); + debug(1, "Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); if (_picObjList.size() > 2) { // We need to z-sort them objectList_sortByPriority(_picObjList, true); @@ -666,11 +666,17 @@ void Scene::drawContent(int minPri, int maxPri, bool drawBg) { if (maxPri == -1) maxPri = 60000; - debug(8, "-> Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); + debug(1, "-> Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); Common::Point point; - debug(8, "_bigPict: %d objlist: %d", _bigPictureArray1Count, _picObjList.size()); + debug(1, "_bigPict: %d objlist: %d", _bigPictureArray1Count, _picObjList.size()); + + for (uint i = 0; i < _picObjList.size(); i++) { + debug(1, "%d: %d", i, ((PictureObject *)_picObjList[i])->_priority); + } + + if (drawBg && _bigPictureArray1Count && _picObjList.size()) { _bigPictureArray[0][0]->getDimensions(&point); diff --git a/engines/fullpipe/scenes/scene04.cpp b/engines/fullpipe/scenes/scene04.cpp index 0a69335bea..fd1ececdf2 100644 --- a/engines/fullpipe/scenes/scene04.cpp +++ b/engines/fullpipe/scenes/scene04.cpp @@ -633,6 +633,7 @@ MessageQueue *sceneHandler04_kozFly5(StaticANIObject *ani, double phase) { mq1->addExCommandToEnd(mq2->getExCommandByIndex(0)->createClone()); delete mq2; + mq2 = 0; ExCommand *ex = new ExCommand(ANI_KOZAWKA, 1, MV_KZW_STANDUP, 0, 0, 0, 1, 0, 0, 0); ex->_excFlags |= 2; @@ -662,6 +663,9 @@ MessageQueue *sceneHandler04_kozFly5(StaticANIObject *ani, double phase) { mq1->addExCommandToEnd(ex); } + if (mq2) + delete mq2; + return mq1; } diff --git a/engines/fullpipe/scenes/scene29.cpp b/engines/fullpipe/scenes/scene29.cpp index 2d5127137d..8f82e99ad1 100644 --- a/engines/fullpipe/scenes/scene29.cpp +++ b/engines/fullpipe/scenes/scene29.cpp @@ -972,7 +972,7 @@ int sceneHandler29(ExCommand *cmd) { break; case MSG_SC29_SHOWLASTRED: - if (g_vars->scene29_balls.numBalls) { + if (g_vars->scene29_redBalls.numBalls) { // original uses scene29_balls which looks like a copy/paste error g_vars->scene29_redBalls.field_8->ani->show1(-1, -1, -1, 0); g_vars->scene29_redBalls.field_8->ani->startAnim(MV_SHR_HITASS, 0, -1); } diff --git a/engines/fullpipe/sound.cpp b/engines/fullpipe/sound.cpp index 65c9bf84ca..a4ca06f489 100644 --- a/engines/fullpipe/sound.cpp +++ b/engines/fullpipe/sound.cpp @@ -268,7 +268,7 @@ void FullpipeEngine::setSceneMusicParameters(GameVar *gvar) { while (sub) { if (_musicAllowed & sub->_value.intValue) { - strcpy(_sceneTracks[_numSceneTracks], sub->_varName); + Common::strlcpy(_sceneTracks[_numSceneTracks], sub->_varName, 260); _numSceneTracks++; } @@ -286,7 +286,7 @@ void FullpipeEngine::setSceneMusicParameters(GameVar *gvar) { if (seq) { _sceneTrackHasSequence = true; - strcpy(_trackName, seq->_value.stringValue); + Common::strlcpy(_trackName, seq->_value.stringValue, 2600); } if (_musicLocal) @@ -432,7 +432,7 @@ void FullpipeEngine::playTrack(GameVar *sceneVar, const char *name, bool delayed while (sub) { if (_musicAllowed & sub->_value.intValue) { - strcpy(_sceneTracks[_numSceneTracks], sub->_varName); + Common::strlcpy(_sceneTracks[_numSceneTracks], sub->_varName, 260); _numSceneTracks++; } @@ -450,7 +450,7 @@ void FullpipeEngine::playTrack(GameVar *sceneVar, const char *name, bool delayed if (seq) { _sceneTrackHasSequence = true; - strcpy(_trackName, seq->_value.stringValue); + Common::strlcpy(_trackName, seq->_value.stringValue, 2600); } if (delayed) { diff --git a/engines/fullpipe/stateloader.cpp b/engines/fullpipe/stateloader.cpp index 41641457d3..141196c7d7 100644 --- a/engines/fullpipe/stateloader.cpp +++ b/engines/fullpipe/stateloader.cpp @@ -162,7 +162,43 @@ GameVar::GameVar() { } GameVar::~GameVar() { - warning("STUB: GameVar::~GameVar()"); + if (_varType == 2) + free(_value.stringValue); + + if (_parentVarObj && !_prevVarObj ) { + if (_parentVarObj->_subVars == this) { + _parentVarObj->_subVars = _nextVarObj; + } else if (_parentVarObj->_field_14 == this) { + _parentVarObj->_field_14 = _nextVarObj; + } else { + _parentVarObj = 0; + } + } + + if (_prevVarObj) + _prevVarObj->_nextVarObj = _nextVarObj; + + if (_nextVarObj) + _nextVarObj->_prevVarObj = _prevVarObj; + + _prevVarObj = 0; + _nextVarObj = 0; + + GameVar *s = _subVars; + + while (s) { + delete s; + s = _subVars; + } + + s = _field_14; + + while (s) { + delete s; + s = _field_14; + } + + free(_varName); } bool GameVar::load(MfcArchive &file) { diff --git a/engines/fullpipe/statics.cpp b/engines/fullpipe/statics.cpp index 292ef08914..717de84925 100644 --- a/engines/fullpipe/statics.cpp +++ b/engines/fullpipe/statics.cpp @@ -528,15 +528,15 @@ void Movement::draw(bool flipFlag, int angle) { if (_currMovement) { bmp = _currDynamicPhase->getPixelData()->reverseImage(); } else { - bmp = _currDynamicPhase->getPixelData(); + bmp = _currDynamicPhase->getPixelData()->reverseImage(false); } if (flipFlag) { - bmp->flipVertical()->drawShaded(1, x, y + 30 + _currDynamicPhase->_rect->bottom, _currDynamicPhase->_paletteData); + bmp->flipVertical()->drawShaded(1, x, y + 30 + _currDynamicPhase->_rect->bottom, _currDynamicPhase->_paletteData, _currDynamicPhase->_alpha); } if (angle) { - bmp->drawRotated(x, y, angle, _currDynamicPhase->_paletteData); + bmp->drawRotated(x, y, angle, _currDynamicPhase->_paletteData, _currDynamicPhase->_alpha); } else { - bmp->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData); + bmp->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData, _currDynamicPhase->_alpha); } if (_currDynamicPhase->_rect->top) { @@ -549,11 +549,11 @@ void Movement::draw(bool flipFlag, int angle) { if (_currDynamicPhase->_convertedBitmap) { if (_currMovement) { //vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, LOBYTE(_currDynamicPhase->rect.top)); - _currDynamicPhase->_convertedBitmap->reverseImage()->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData); + _currDynamicPhase->_convertedBitmap->reverseImage()->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData, _currDynamicPhase->_alpha); //vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); } else { //vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, LOBYTE(_currDynamicPhase->rect.top)); - _currDynamicPhase->_convertedBitmap->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData); + _currDynamicPhase->_convertedBitmap->reverseImage(false)->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData, _currDynamicPhase->_alpha); //vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); } } @@ -1454,14 +1454,8 @@ bool Statics::load(MfcArchive &file) { void Statics::init() { Picture::init(); - if (_staticsId & 0x4000) { - Bitmap *bmp = _bitmap->reverseImage(); - - freePixelData(); - - _bitmap = bmp; - _data = bmp->_pixels; - } + if (_staticsId & 0x4000) + _bitmap->reverseImage(); } Common::Point *Statics::getSomeXY(Common::Point &p) { @@ -2212,9 +2206,12 @@ DynamicPhase::DynamicPhase(DynamicPhase *src, bool reverse) { _libHandle = src->_libHandle; _bitmap = src->_bitmap; - if (_bitmap) + if (_bitmap) { _field_54 = 1; + _bitmap = src->_bitmap->reverseImage(false); + } + _someX = src->_someX; _someY = src->_someY; } diff --git a/engines/gob/detection/tables_ween.h b/engines/gob/detection/tables_ween.h index 66a83aff0f..bf65685d46 100644 --- a/engines/gob/detection/tables_ween.h +++ b/engines/gob/detection/tables_ween.h @@ -228,93 +228,6 @@ 0, 0, 0 }, -// -- DOS VGA Floppy -- - -{ - { - "ween", - "", - AD_ENTRY1("intro.stk", "2bb8878a8042244dd2b96ff682381baa"), - EN_GRB, - kPlatformDOS, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 -}, -{ - { - "ween", - "", - AD_ENTRY1s("intro.stk", "de92e5c6a8c163007ffceebef6e67f7d", 7117568), - EN_USA, - kPlatformDOS, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 -}, -{ // Supplied by cybot_tmin in bug report #1667743 - { - "ween", - "", - AD_ENTRY1s("intro.stk", "6d60f9205ecfbd8735da2ee7823a70dc", 7014426), - ES_ESP, - kPlatformDOS, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 -}, -{ - { - "ween", - "", - AD_ENTRY1("intro.stk", "4b10525a3782aa7ecd9d833b5c1d308b"), - FR_FRA, - kPlatformDOS, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 -}, -{ // Supplied by cartman_ on #scummvm - { - "ween", - "", - AD_ENTRY1("intro.stk", "63170e71f04faba88673b3f510f9c4c8"), - DE_DEU, - kPlatformDOS, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 -}, -{ // Supplied by glorfindel in bugreport #1722142 - { - "ween", - "", - AD_ENTRY1s("intro.stk", "8b57cd510da8a3bbd99e3a0297a8ebd1", 7018771), - IT_ITA, - kPlatformDOS, - ADGF_NO_FLAGS, - GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH) - }, - kGameTypeWeen, - kFeaturesAdLib, - 0, 0, 0 -}, - // -- Demos -- { diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp index f2a9637dfe..e1f864ddd2 100644 --- a/engines/kyra/items_lol.cpp +++ b/engines/kyra/items_lol.cpp @@ -265,7 +265,7 @@ bool LoLEngine::addItemToInventory(Item itemIndex) { gui_drawInventory(); } - assert(pos > 0 && pos < 48); + assert(pos >= 0 && pos < 48); _inventory[pos] = itemIndex; gui_drawInventory(); diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp index f950f9d5aa..89ee41e859 100644 --- a/engines/kyra/sound_adlib.cpp +++ b/engines/kyra/sound_adlib.cpp @@ -61,7 +61,7 @@ public: ~AdLibDriver(); void initDriver(); - void setSoundData(uint8 *data); + void setSoundData(uint8 *data, uint32 size); void queueTrack(int track, int volume); bool isChannelPlaying(int channel) const; void stopAllChannels(); @@ -130,13 +130,13 @@ private: struct Channel { bool lock; // New to ScummVM uint8 opExtraLevel2; - uint8 *dataptr; + const uint8 *dataptr; uint8 duration; uint8 repeatCounter; int8 baseOctave; uint8 priority; uint8 dataptrStackPos; - uint8 *dataptrStack[4]; + const uint8 *dataptrStack[4]; int8 baseNote; uint8 unk29; uint8 unk31; @@ -194,7 +194,7 @@ private: void setupDuration(uint8 duration, Channel &channel); void setupNote(uint8 rawNote, Channel &channel, bool flag = false); - void setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel); + void setupInstrument(uint8 regOffset, const uint8 *dataptr, Channel &channel); void noteOn(Channel &channel); void adjustVolume(Channel &channel); @@ -216,14 +216,24 @@ private: // * One for instruments, starting at offset 500. uint8 *getProgram(int progId) { - uint16 offset = READ_LE_UINT16(_soundData + 2 * progId); - //TODO: Check in LoL CD AdLib driver - if (offset == 0xFFFF) - return 0; - return _soundData + READ_LE_UINT16(_soundData + 2 * progId); + const uint16 offset = READ_LE_UINT16(_soundData + 2 * progId); + + // In case an invalid offset is specified we return nullptr to + // indicate an error. 0xFFFF seems to indicate "this is not a valid + // program/instrument". However, 0 is also invalid because it points + // inside the offset table itself. We also ignore any offsets outside + // of the actual data size. + // The original does not contain any safety checks and will simply + // read outside of the valid sound data in case an invalid offset is + // encountered. + if (offset == 0 || offset >= _soundDataSize) { + return nullptr; + } else { + return _soundData + offset; + } } - uint8 *getInstrument(int instrumentId) { + const uint8 *getInstrument(int instrumentId) { return getProgram(_numPrograms + instrumentId); } @@ -231,7 +241,7 @@ private: void executePrograms(); struct ParserOpcode { - typedef int (AdLibDriver::*POpcode)(uint8 *&dataptr, Channel &channel, uint8 value); + typedef int (AdLibDriver::*POpcode)(const uint8 *&dataptr, Channel &channel, uint8 value); POpcode function; const char *name; }; @@ -240,61 +250,61 @@ private: const ParserOpcode *_parserOpcodeTable; int _parserOpcodeTableSize; - int update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value); - int update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value); - int update_jump(uint8 *&dataptr, Channel &channel, uint8 value); - int update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value); - int update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value); - int update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value); - int update_playRest(uint8 *&dataptr, Channel &channel, uint8 value); - int update_writeAdLib(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); - int update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value); - int update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); - int update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value); - int update_playNote(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value); - int update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value); - int update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value); - int update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value); - int update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value); - int update_pitchBend(uint8 *&dataptr, Channel &channel, uint8 value); - int update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value); - int update_nop(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value); - int update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value); - int update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value); - int update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value); - int update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value); - int updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value); + int update_setRepeat(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_checkRepeat(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupProgram(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_jump(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_jumpToSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_returnFromSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setBaseOctave(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_stopChannel(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_playRest(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_writeAdLib(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupNoteAndDuration(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setBaseNote(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_stopOtherChannel(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_waitForEndOfProgram(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupInstrument(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupPrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_removePrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setBaseFreq(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupPrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setPriority(const uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback23(const uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback24(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupDuration(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_playNote(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setFractionalNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setTempo(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_removeSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setExtraLevel3(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_changeExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setAMDepth(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setVibratoDepth(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_changeExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback38(const uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback39(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_removePrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_pitchBend(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_resetToGlobalTempo(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_nop(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setDurationRandomness(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_changeChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback46(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setupRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_playRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_removeRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback51(const uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback52(const uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback53(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setSoundTrigger(const uint8 *&dataptr, Channel &channel, uint8 value); + int update_setTempoReset(const uint8 *&dataptr, Channel &channel, uint8 value); + int updateCallback56(const uint8 *&dataptr, Channel &channel, uint8 value); private: // These variables have not yet been named, but some of them are partly // known nevertheless: @@ -358,6 +368,7 @@ private: FM_OPL *_adlib; uint8 *_soundData; + uint32 _soundDataSize; struct QueueEntry { QueueEntry() : data(0), id(0), volume(0) {} @@ -421,6 +432,7 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) { memset(_channels, 0, sizeof(_channels)); _soundData = 0; + _soundDataSize = 0; _vibratoAndAMDepthBits = _curRegOffset = 0; @@ -522,7 +534,7 @@ void AdLibDriver::initDriver() { resetAdLibState(); } -void AdLibDriver::setSoundData(uint8 *data) { +void AdLibDriver::setSoundData(uint8 *data, uint32 size) { Common::StackLock lock(_mutex); // Drop all tracks that are still queued. These would point to the old @@ -536,6 +548,7 @@ void AdLibDriver::setSoundData(uint8 *data) { } _soundData = data; + _soundDataSize = size; } void AdLibDriver::queueTrack(int track, int volume) { @@ -791,7 +804,7 @@ void AdLibDriver::executePrograms() { // This fixes a subtle music bug where the // wrong music would play when getting the // quill in Kyra 1. - uint8 *dataptr = channel.dataptr; + const uint8 *dataptr = channel.dataptr; while (dataptr) { uint8 opcode = *dataptr++; uint8 param = *dataptr++; @@ -1030,7 +1043,7 @@ void AdLibDriver::setupNote(uint8 rawNote, Channel &channel, bool flag) { writeOPL(0xB0 + _curChannel, channel.regBx); } -void AdLibDriver::setupInstrument(uint8 regOffset, uint8 *dataptr, Channel &channel) { +void AdLibDriver::setupInstrument(uint8 regOffset, const uint8 *dataptr, Channel &channel) { debugC(9, kDebugLevelSound, "setupInstrument(%d, %p, %lu)", regOffset, (const void *)dataptr, (long)(&channel - _channels)); if (_curChannel >= 9) @@ -1340,12 +1353,12 @@ uint8 AdLibDriver::calculateOpLevel2(Channel &channel) { // parser opcodes -int AdLibDriver::update_setRepeat(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setRepeat(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.repeatCounter = value; return 0; } -int AdLibDriver::update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_checkRepeat(const uint8 *&dataptr, Channel &channel, uint8 value) { ++dataptr; if (--channel.repeatCounter) { int16 add = READ_LE_UINT16(dataptr - 2); @@ -1354,14 +1367,23 @@ int AdLibDriver::update_checkRepeat(uint8 *&dataptr, Channel &channel, uint8 val return 0; } -int AdLibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setupProgram(const uint8 *&dataptr, Channel &channel, uint8 value) { if (value == 0xFF) return 0; - uint8 *ptr = getProgram(value); - //TODO: Check in LoL CD AdLib driver - if (!ptr) + const uint8 *ptr = getProgram(value); + + // In case we encounter an invalid program we simply ignore it and do + // nothing instead. The original did not care about invalid programs and + // simply tried to play them anyway... But to avoid crashes due we ingore + // them. + // This, for example, happens in the Lands of Lore intro when Scotia gets + // the ring in the intro. + if (!ptr) { + debugC(3, kDebugLevelSound, "AdLibDriver::update_setupProgram: Invalid program %d specified", value); return 0; + } + uint8 chan = *ptr++; uint8 priority = *ptr++; @@ -1390,12 +1412,12 @@ int AdLibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 va return 0; } -int AdLibDriver::update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.spacing1 = value; return 0; } -int AdLibDriver::update_jump(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_jump(const uint8 *&dataptr, Channel &channel, uint8 value) { --dataptr; int16 add = READ_LE_UINT16(dataptr); dataptr += 2; if (_version == 1) @@ -1407,7 +1429,7 @@ int AdLibDriver::update_jump(uint8 *&dataptr, Channel &channel, uint8 value) { return 0; } -int AdLibDriver::update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_jumpToSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value) { --dataptr; int16 add = READ_LE_UINT16(dataptr); dataptr += 2; channel.dataptrStack[channel.dataptrStackPos++] = dataptr; @@ -1418,17 +1440,17 @@ int AdLibDriver::update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint return 0; } -int AdLibDriver::update_returnFromSubroutine(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_returnFromSubroutine(const uint8 *&dataptr, Channel &channel, uint8 value) { dataptr = channel.dataptrStack[--channel.dataptrStackPos]; return 0; } -int AdLibDriver::update_setBaseOctave(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setBaseOctave(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.baseOctave = value; return 0; } -int AdLibDriver::update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_stopChannel(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.priority = 0; if (_curChannel != 9) noteOff(channel); @@ -1436,30 +1458,30 @@ int AdLibDriver::update_stopChannel(uint8 *&dataptr, Channel &channel, uint8 val return 2; } -int AdLibDriver::update_playRest(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_playRest(const uint8 *&dataptr, Channel &channel, uint8 value) { setupDuration(value, channel); noteOff(channel); return (value != 0); } -int AdLibDriver::update_writeAdLib(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_writeAdLib(const uint8 *&dataptr, Channel &channel, uint8 value) { writeOPL(value, *dataptr++); return 0; } -int AdLibDriver::update_setupNoteAndDuration(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setupNoteAndDuration(const uint8 *&dataptr, Channel &channel, uint8 value) { setupNote(value, channel); value = *dataptr++; setupDuration(value, channel); return (value != 0); } -int AdLibDriver::update_setBaseNote(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setBaseNote(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.baseNote = value; return 0; } -int AdLibDriver::update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setupSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.unk18 = value; channel.unk19 = value; channel.unk20 = channel.unk21 = *dataptr++; @@ -1483,7 +1505,7 @@ int AdLibDriver::update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel, return 0; } -int AdLibDriver::update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_stopOtherChannel(const uint8 *&dataptr, Channel &channel, uint8 value) { Channel &channel2 = _channels[value]; channel2.duration = 0; channel2.priority = 0; @@ -1491,8 +1513,16 @@ int AdLibDriver::update_stopOtherChannel(uint8 *&dataptr, Channel &channel, uint return 0; } -int AdLibDriver::update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, uint8 value) { - uint8 *ptr = getProgram(value); +int AdLibDriver::update_waitForEndOfProgram(const uint8 *&dataptr, Channel &channel, uint8 value) { + const uint8 *ptr = getProgram(value); + + // Safety check in case an invalid program is specified. This would make + // getProgram return a nullptr and thus cause invalid memory reads. + if (!ptr) { + debugC(3, kDebugLevelSound, "AdLibDriver::update_waitForEndOfProgram: Invalid program %d specified", value); + return 0; + } + uint8 chan = *ptr; if (!_channels[chan].dataptr) @@ -1502,12 +1532,25 @@ int AdLibDriver::update_waitForEndOfProgram(uint8 *&dataptr, Channel &channel, u return 2; } -int AdLibDriver::update_setupInstrument(uint8 *&dataptr, Channel &channel, uint8 value) { - setupInstrument(_curRegOffset, getInstrument(value), channel); +int AdLibDriver::update_setupInstrument(const uint8 *&dataptr, Channel &channel, uint8 value) { + const uint8 *instrument = getInstrument(value); + + // We add a safety check to avoid setting up invalid instruments. This is + // not done in the original. However, to avoid crashes due to invalid + // memory reads we simply ignore the request. + // This happens, for example, in Hand of Fate when using the swampsnake + // potion on Zanthia to scare off the rat in the cave in the first chapter + // of the game. + if (!instrument) { + debugC(3, kDebugLevelSound, "AdLibDriver::update_setupInstrument: Invalid instrument %d specified", value); + return 0; + } + + setupInstrument(_curRegOffset, instrument, channel); return 0; } -int AdLibDriver::update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setupPrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.unk29 = value; channel.unk30 = READ_BE_UINT16(dataptr); dataptr += 2; @@ -1516,19 +1559,19 @@ int AdLibDriver::update_setupPrimaryEffect1(uint8 *&dataptr, Channel &channel, u return 0; } -int AdLibDriver::update_removePrimaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_removePrimaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) { --dataptr; channel.primaryEffect = 0; channel.unk30 = 0; return 0; } -int AdLibDriver::update_setBaseFreq(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setBaseFreq(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.baseFreq = value; return 0; } -int AdLibDriver::update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setupPrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.unk32 = value; channel.unk33 = *dataptr++; uint8 temp = *dataptr++; @@ -1539,12 +1582,12 @@ int AdLibDriver::update_setupPrimaryEffect2(uint8 *&dataptr, Channel &channel, u return 0; } -int AdLibDriver::update_setPriority(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setPriority(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.priority = value; return 0; } -int AdLibDriver::updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::updateCallback23(const uint8 *&dataptr, Channel &channel, uint8 value) { value >>= 1; _unkValue1 = _unkValue2 = value; _callbackTimer = 0xFF; @@ -1552,7 +1595,7 @@ int AdLibDriver::updateCallback23(uint8 *&dataptr, Channel &channel, uint8 value return 0; } -int AdLibDriver::updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::updateCallback24(const uint8 *&dataptr, Channel &channel, uint8 value) { if (_unkValue5) { if (_unkValue4 & value) { _unkValue5 = 0; @@ -1568,50 +1611,50 @@ int AdLibDriver::updateCallback24(uint8 *&dataptr, Channel &channel, uint8 value return 2; } -int AdLibDriver::update_setExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.opExtraLevel1 = value; adjustVolume(channel); return 0; } -int AdLibDriver::update_setupDuration(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setupDuration(const uint8 *&dataptr, Channel &channel, uint8 value) { setupDuration(value, channel); return (value != 0); } -int AdLibDriver::update_playNote(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_playNote(const uint8 *&dataptr, Channel &channel, uint8 value) { setupDuration(value, channel); noteOn(channel); return (value != 0); } -int AdLibDriver::update_setFractionalNoteSpacing(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setFractionalNoteSpacing(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.fractionalSpacing = value & 7; return 0; } -int AdLibDriver::update_setTempo(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setTempo(const uint8 *&dataptr, Channel &channel, uint8 value) { _tempo = value; return 0; } -int AdLibDriver::update_removeSecondaryEffect1(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_removeSecondaryEffect1(const uint8 *&dataptr, Channel &channel, uint8 value) { --dataptr; channel.secondaryEffect = 0; return 0; } -int AdLibDriver::update_setChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.tempo = value; return 0; } -int AdLibDriver::update_setExtraLevel3(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setExtraLevel3(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.opExtraLevel3 = value; return 0; } -int AdLibDriver::update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value) { int channelBackUp = _curChannel; _curChannel = value; @@ -1623,7 +1666,7 @@ int AdLibDriver::update_setExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 return 0; } -int AdLibDriver::update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_changeExtraLevel2(const uint8 *&dataptr, Channel &channel, uint8 value) { int channelBackUp = _curChannel; _curChannel = value; @@ -1638,7 +1681,7 @@ int AdLibDriver::update_changeExtraLevel2(uint8 *&dataptr, Channel &channel, uin // Apart from initializing to zero, these two functions are the only ones that // modify _vibratoAndAMDepthBits. -int AdLibDriver::update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setAMDepth(const uint8 *&dataptr, Channel &channel, uint8 value) { if (value & 1) _vibratoAndAMDepthBits |= 0x80; else @@ -1648,7 +1691,7 @@ int AdLibDriver::update_setAMDepth(uint8 *&dataptr, Channel &channel, uint8 valu return 0; } -int AdLibDriver::update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setVibratoDepth(const uint8 *&dataptr, Channel &channel, uint8 value) { if (value & 1) _vibratoAndAMDepthBits |= 0x40; else @@ -1658,13 +1701,13 @@ int AdLibDriver::update_setVibratoDepth(uint8 *&dataptr, Channel &channel, uint8 return 0; } -int AdLibDriver::update_changeExtraLevel1(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_changeExtraLevel1(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.opExtraLevel1 += value; adjustVolume(channel); return 0; } -int AdLibDriver::updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::updateCallback38(const uint8 *&dataptr, Channel &channel, uint8 value) { int channelBackUp = _curChannel; _curChannel = value; @@ -1693,7 +1736,7 @@ int AdLibDriver::updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value return 0; } -int AdLibDriver::updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::updateCallback39(const uint8 *&dataptr, Channel &channel, uint8 value) { if (_curChannel >= 9) return 0; @@ -1714,35 +1757,35 @@ int AdLibDriver::updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value return 0; } -int AdLibDriver::update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_removePrimaryEffect2(const uint8 *&dataptr, Channel &channel, uint8 value) { --dataptr; channel.primaryEffect = 0; return 0; } -int AdLibDriver::update_pitchBend(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_pitchBend(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.pitchBend = value; setupNote(channel.rawNote, channel, true); return 0; } -int AdLibDriver::update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_resetToGlobalTempo(const uint8 *&dataptr, Channel &channel, uint8 value) { --dataptr; channel.tempo = _tempo; return 0; } -int AdLibDriver::update_nop(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_nop(const uint8 *&dataptr, Channel &channel, uint8 value) { --dataptr; return 0; } -int AdLibDriver::update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setDurationRandomness(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.durationRandomness = value; return 0; } -int AdLibDriver::update_changeChannelTempo(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_changeChannelTempo(const uint8 *&dataptr, Channel &channel, uint8 value) { int tempo = channel.tempo + (int8)value; if (tempo <= 0) @@ -1754,7 +1797,7 @@ int AdLibDriver::update_changeChannelTempo(uint8 *&dataptr, Channel &channel, ui return 0; } -int AdLibDriver::updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::updateCallback46(const uint8 *&dataptr, Channel &channel, uint8 value) { uint8 entry = *dataptr++; _tablePtr1 = _unkTable2[entry++]; _tablePtr2 = _unkTable2[entry]; @@ -1765,27 +1808,43 @@ int AdLibDriver::updateCallback46(uint8 *&dataptr, Channel &channel, uint8 value return 0; } -int AdLibDriver::update_setupRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setupRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value) { int channelBackUp = _curChannel; int regOffsetBackUp = _curRegOffset; _curChannel = 6; _curRegOffset = _regOffset[6]; - setupInstrument(_curRegOffset, getInstrument(value), channel); + const uint8 *instrument; + instrument = getInstrument(value); + if (instrument) { + setupInstrument(_curRegOffset, instrument, channel); + } else { + debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 6 specified", value); + } _unkValue6 = channel.opLevel2; _curChannel = 7; _curRegOffset = _regOffset[7]; - setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel); + instrument = getInstrument(*dataptr++); + if (instrument) { + setupInstrument(_curRegOffset, instrument, channel); + } else { + debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 7 specified", value); + } _unkValue7 = channel.opLevel1; _unkValue8 = channel.opLevel2; _curChannel = 8; _curRegOffset = _regOffset[8]; - setupInstrument(_curRegOffset, getInstrument(*dataptr++), channel); + instrument = getInstrument(*dataptr++); + if (instrument) { + setupInstrument(_curRegOffset, instrument, channel); + } else { + debugC(3, kDebugLevelSound, "AdLibDriver::update_setupRhythmSection: Invalid instrument %d for channel 8 specified", value); + } _unkValue9 = channel.opLevel1; _unkValue10 = channel.opLevel2; @@ -1810,7 +1869,7 @@ int AdLibDriver::update_setupRhythmSection(uint8 *&dataptr, Channel &channel, ui return 0; } -int AdLibDriver::update_playRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_playRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value) { // Any instrument that we want to play, and which was already playing, // is temporarily keyed off. Instruments that were off already, or // which we don't want to play, retain their old on/off status. This is @@ -1830,7 +1889,7 @@ int AdLibDriver::update_playRhythmSection(uint8 *&dataptr, Channel &channel, uin return 0; } -int AdLibDriver::update_removeRhythmSection(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_removeRhythmSection(const uint8 *&dataptr, Channel &channel, uint8 value) { --dataptr; _rhythmSectionBits = 0; @@ -1841,7 +1900,7 @@ int AdLibDriver::update_removeRhythmSection(uint8 *&dataptr, Channel &channel, u return 0; } -int AdLibDriver::updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::updateCallback51(const uint8 *&dataptr, Channel &channel, uint8 value) { uint8 value2 = *dataptr++; if (value & 1) { @@ -1882,7 +1941,7 @@ int AdLibDriver::updateCallback51(uint8 *&dataptr, Channel &channel, uint8 value return 0; } -int AdLibDriver::updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::updateCallback52(const uint8 *&dataptr, Channel &channel, uint8 value) { uint8 value2 = *dataptr++; if (value & 1) { @@ -1923,7 +1982,7 @@ int AdLibDriver::updateCallback52(uint8 *&dataptr, Channel &channel, uint8 value return 0; } -int AdLibDriver::updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::updateCallback53(const uint8 *&dataptr, Channel &channel, uint8 value) { uint8 value2 = *dataptr++; if (value & 1) { @@ -1964,17 +2023,17 @@ int AdLibDriver::updateCallback53(uint8 *&dataptr, Channel &channel, uint8 value return 0; } -int AdLibDriver::update_setSoundTrigger(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setSoundTrigger(const uint8 *&dataptr, Channel &channel, uint8 value) { _soundTrigger = value; return 0; } -int AdLibDriver::update_setTempoReset(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::update_setTempoReset(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.tempoReset = value; return 0; } -int AdLibDriver::updateCallback56(uint8 *&dataptr, Channel &channel, uint8 value) { +int AdLibDriver::updateCallback56(const uint8 *&dataptr, Channel &channel, uint8 value) { channel.unk39 = value; channel.unk40 = *dataptr++; return 0; @@ -2487,13 +2546,13 @@ void SoundAdLibPC::internalLoadFile(Common::String file) { _soundDataPtr = new uint8[soundDataSize]; assert(_soundDataPtr); - memcpy(_soundDataPtr, p, soundDataSize*sizeof(uint8)); + memcpy(_soundDataPtr, p, soundDataSize); delete[] fileData; fileData = p = 0; fileSize = 0; - _driver->setSoundData(_soundDataPtr); + _driver->setSoundData(_soundDataPtr, soundDataSize); _soundFileLoaded = file; } diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp index 57943f9a8d..a6cecc7408 100644 --- a/engines/lastexpress/debug.cpp +++ b/engines/lastexpress/debug.cpp @@ -653,7 +653,6 @@ bool Debugger::cmdPlayNis(int argc, const char **argv) { // Make sure we are not called in a loop _numParams = 0; - // Check if we got a nis filename or an animation index if (name.contains('.')) { Animation animation; @@ -796,7 +795,10 @@ bool Debugger::cmdFight(int argc, const char **argv) { break; } - loadArchive(index); + if (!loadArchive(index)) { + debugPrintf("Error: failed to load archive %d\n", index); + return true; + } // Store command if (!hasCommand()) { @@ -854,7 +856,10 @@ error: bool Debugger::cmdBeetle(int argc, const char **argv) { if (argc == 1) { // Load proper data file (beetle game in in Cd2) - loadArchive(kArchiveCd2); + if (!loadArchive(kArchiveCd2)) { + debugPrintf("Error: failed to load archive 2"); + return true; + } // Store command if (!hasCommand()) { @@ -924,7 +929,6 @@ bool Debugger::cmdBeetle(int argc, const char **argv) { break; } - case Common::EVENT_LBUTTONUP: case Common::EVENT_RBUTTONUP: // Update coordinates diff --git a/engines/lastexpress/entities/abbot.cpp b/engines/lastexpress/entities/abbot.cpp index 5393410add..1581916e07 100644 --- a/engines/lastexpress/entities/abbot.cpp +++ b/engines/lastexpress/entities/abbot.cpp @@ -415,7 +415,7 @@ IMPLEMENT_FUNCTION(22, Abbot, haveLunch) break; case kActionNone: - Entity::timeCheckSavepoint(kTime1971000, params->param1, kEntityAbbot, kEntityServers0, kAction218586752); + Entity::timeCheckSavepoint(kTime1971000, params->param1, kEntityAbbot, kEntityWaiter1, kAction218586752); if (getState()->time > kTime1989000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) { getData()->inventoryItem = kItemNone; @@ -476,7 +476,7 @@ IMPLEMENT_FUNCTION(23, Abbot, leaveLunch) case 1: getEntities()->updatePositionExit(kEntityAbbot, kCarRestaurant, 67); - getSavePoints()->push(kEntityAbbot, kEntityServers0, kAction270068760); + getSavePoints()->push(kEntityAbbot, kEntityWaiter1, kAction270068760); getSavePoints()->push(kEntityAbbot, kEntityAnna, kAction238936000); getEntities()->drawSequenceRight(kEntityAbbot, "804DS"); @@ -1324,7 +1324,7 @@ IMPLEMENT_FUNCTION(41, Abbot, chapter4Handler) break; case kActionNone: - Entity::timeCheckSavepoint(kTime2358000, params->param1, kEntityAbbot, kEntityServers0, kAction218128129); + Entity::timeCheckSavepoint(kTime2358000, params->param1, kEntityAbbot, kEntityWaiter1, kAction218128129); if (getState()->time > kTime2389500 && getEntities()->isSomebodyInsideRestaurantOrSalon()) setup_leaveDinner(); @@ -1368,7 +1368,7 @@ IMPLEMENT_FUNCTION(42, Abbot, leaveDinner) case 1: getEntities()->updatePositionExit(kEntityAbbot, kCarRestaurant, 67); - getSavePoints()->push(kEntityAbbot, kEntityServers0, kAction270068760); + getSavePoints()->push(kEntityAbbot, kEntityWaiter1, kAction270068760); getEntities()->drawSequenceRight(kEntityAbbot, "804DS"); if (getEntities()->isInRestaurant(kEntityPlayer)) @@ -1779,7 +1779,7 @@ IMPLEMENT_FUNCTION(49, Abbot, catchCath) getData()->location = kLocationInsideCompartment; getSavePoints()->call(kEntityAbbot, kEntityTables4, kActionDrawTablesWithChairs, "029G"); - getSavePoints()->push(kEntityAbbot, kEntityServers0, kAction270068760); + getSavePoints()->push(kEntityAbbot, kEntityWaiter1, kAction270068760); getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction125039808); getObjects()->update(kObjectCompartment2, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand); getObjects()->update(kObjectHandleInsideBathroom, kEntityAbbot, kObjectLocation1, kCursorHandKnock, kCursorHand); diff --git a/engines/lastexpress/entities/alexei.cpp b/engines/lastexpress/entities/alexei.cpp index 9b56fca39f..5ea3ff4898 100644 --- a/engines/lastexpress/entities/alexei.cpp +++ b/engines/lastexpress/entities/alexei.cpp @@ -607,7 +607,7 @@ IMPLEMENT_FUNCTION(19, Alexei, returnCompartment) case 7: getEntities()->updatePositionExit(kEntityAlexei, kCarRestaurant, 63); - getSavePoints()->push(kEntityAlexei, kEntityServers1, kAction302996448); + getSavePoints()->push(kEntityAlexei, kEntityWaiter2, kAction302996448); setCallback(8); setup_draw("934"); diff --git a/engines/lastexpress/entities/anna.cpp b/engines/lastexpress/entities/anna.cpp index ff65be9772..3354964af2 100644 --- a/engines/lastexpress/entities/anna.cpp +++ b/engines/lastexpress/entities/anna.cpp @@ -907,7 +907,7 @@ IMPLEMENT_FUNCTION(23, Anna, waitingDinner) case kActionDefault: getEntities()->drawSequenceLeft(kEntityAnna, "001D"); - getSavePoints()->push(kEntityAnna, kEntityServers0, kAction270410280); + getSavePoints()->push(kEntityAnna, kEntityWaiter1, kAction270410280); getSavePoints()->push(kEntityAnna, kEntityTables0, kAction136455232); setCallback(1); @@ -931,7 +931,7 @@ IMPLEMENT_FUNCTION(23, Anna, waitingDinner) break; case 3: - getSavePoints()->push(kEntityAnna, kEntityServers0, kAction203859488); + getSavePoints()->push(kEntityAnna, kEntityWaiter1, kAction203859488); setup_waitingDinner2(); break; } @@ -964,7 +964,7 @@ IMPLEMENT_FUNCTION(24, Anna, waitingDinner2) break; case 2: - getSavePoints()->push(kEntityAnna, kEntityServers0, kAction136702400); + getSavePoints()->push(kEntityAnna, kEntityWaiter1, kAction136702400); setup_eatingDinner(); break; } @@ -1034,7 +1034,7 @@ IMPLEMENT_FUNCTION(26, Anna, leaveDinner) case 1: getEntities()->updatePositionExit(kEntityAnna, kCarRestaurant, 62); - getSavePoints()->push(kEntityAnna, kEntityServers0, kAction237485916); + getSavePoints()->push(kEntityAnna, kEntityWaiter1, kAction237485916); getEntities()->drawSequenceRight(kEntityAnna, "801DS"); if (getEntities()->isInRestaurant(kEntityPlayer)) @@ -2145,7 +2145,7 @@ label_callback_4: break; case 2: - getSavePoints()->push(kEntityAnna, kEntityServers0, kAction218983616); + getSavePoints()->push(kEntityAnna, kEntityWaiter1, kAction218983616); break; case 3: @@ -2285,7 +2285,7 @@ IMPLEMENT_FUNCTION(51, Anna, afterLunch) getData()->location = kLocationInsideCompartment; getEntities()->drawSequenceLeft(kEntityAnna, "112B"); getEntities()->updatePositionExit(kEntityAnna, kCarRestaurant, 57); - getSavePoints()->push(kEntityAnna, kEntityServers1, kAction219377792); + getSavePoints()->push(kEntityAnna, kEntityWaiter2, kAction219377792); break; case 2: @@ -3473,7 +3473,7 @@ IMPLEMENT_FUNCTION(69, Anna, goSalon4) case 3: getData()->location = kLocationInsideCompartment; getEntities()->drawSequenceLeft(kEntityAnna, "127B"); - getSavePoints()->push(kEntityAnna, kEntityServers1, kAction258136010); + getSavePoints()->push(kEntityAnna, kEntityWaiter2, kAction258136010); break; case 4: diff --git a/engines/lastexpress/entities/august.cpp b/engines/lastexpress/entities/august.cpp index c5029537ad..14dcf200f0 100644 --- a/engines/lastexpress/entities/august.cpp +++ b/engines/lastexpress/entities/august.cpp @@ -452,11 +452,17 @@ IMPLEMENT_FUNCTION_I(20, August, function20, bool) } if (params->param1) { - strcpy((char *)¶meters->seq2, Common::String::format("%s%s", (char *)¶meters->seq1, "Gc").c_str()); + Common::String sequence = Common::String::format("%s%s", (char *)¶meters->seq1, "Gc"); + assert(sequence.size() <= 13); + + strcpy((char *)¶meters->seq2, sequence.c_str()); getObjects()->update(kObjectCompartment3, kEntityPlayer, kObjectLocation1, kCursorKeepValue, kCursorKeepValue); } else { - strcpy((char *)¶meters->seq2, Common::String::format("%s%s", (char *)¶meters->seq1, "Ec").c_str()); + Common::String sequence = Common::String::format("%s%s", (char *)¶meters->seq1, "Ec"); + assert(sequence.size() <= 13); + + strcpy((char *)¶meters->seq2, sequence.c_str()); } setCallback(1); @@ -484,15 +490,22 @@ IMPLEMENT_FUNCTION_I(20, August, function20, bool) setCallback(2); setup_playSound("AUG2094"); } + } break; case 2: - case 3: + case 3: { getSavePoints()->push(kEntityAugust, kEntityMertens, kAction269436673); - strcpy((char *)¶meters->seq2, Common::String::format("%s%s", (char *)¶meters->seq1, "Qc").c_str()); + + Common::String sequence = Common::String::format("%s%s", (char *)¶meters->seq1, "Qc"); + assert(sequence.size() <= 13); + + strcpy((char *)¶meters->seq2, sequence.c_str()); getEntities()->drawSequenceLeft(kEntityAugust, (char *)¶meters->seq2); + + } break; } break; @@ -1162,7 +1175,7 @@ IMPLEMENT_FUNCTION(25, August, chapter1Handler) break; case 1: - getSavePoints()->push(kEntityAugust, kEntityServers0, kAction204704037); + getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction204704037); getEntities()->drawSequenceRight(kEntityAugust, "803DS"); if (getEntities()->isInRestaurant(kEntityPlayer)) getEntities()->updateFrame(kEntityAugust); @@ -1195,7 +1208,7 @@ IMPLEMENT_FUNCTION(25, August, chapter1Handler) break; case 5: - getSavePoints()->push(kEntityAugust, kEntityServers0, kAction204704037); + getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction204704037); getEntities()->drawSequenceRight(kEntityAugust, "803DS"); if (getEntities()->isInRestaurant(kEntityPlayer)) getEntities()->updateFrame(kEntityAugust); @@ -1366,7 +1379,7 @@ IMPLEMENT_FUNCTION(28, August, function28) params->param1 = kItemInvalid; getEntities()->drawSequenceLeft(kEntityAugust, "010B"); - getSavePoints()->push(kEntityAugust, kEntityServers0, kAction304061224); + getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction304061224); getData()->inventoryItem = (InventoryItem)params->param1; break; @@ -1376,13 +1389,13 @@ IMPLEMENT_FUNCTION(28, August, function28) break; case 1: - getSavePoints()->push(kEntityAugust, kEntityServers0, kAction203859488); + getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction203859488); getData()->inventoryItem = (InventoryItem)params->param1; getEntities()->drawSequenceLeft(kEntityAugust, "010B"); break; case 2: - getSavePoints()->push(kEntityAugust, kEntityServers0, kAction136702400); + getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction136702400); getEntities()->drawSequenceLeft(kEntityAugust, "010B"); setup_function29(); break; @@ -1399,7 +1412,7 @@ IMPLEMENT_FUNCTION(28, August, function28) case kAction170016384: getData()->inventoryItem = kItemNone; - getEntities()->drawSequenceLeft(kEntityServers0, "BLANK"); + getEntities()->drawSequenceLeft(kEntityWaiter1, "BLANK"); getEntities()->drawSequenceLeft(kEntityAugust, "010G"); setCallback(2); @@ -1551,7 +1564,7 @@ IMPLEMENT_FUNCTION(30, August, restaurant) break; case 3: - getSavePoints()->push(kEntityAugust, kEntityServers0, kAction292758554); + getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction292758554); getSavePoints()->push(kEntityAugust, kEntityAnna, kAction122358304); getEntities()->drawSequenceLeft(kEntityAugust, "001K"); getSound()->playSound(kEntityAugust, "AUG1003"); @@ -1815,7 +1828,7 @@ IMPLEMENT_FUNCTION(36, August, chapter2Handler) break; case kActionNone: - Entity::timeCheckSavepoint(kTime1755000, params->param2, kEntityAugust, kEntityServers0, kAction252568704); + Entity::timeCheckSavepoint(kTime1755000, params->param2, kEntityAugust, kEntityWaiter1, kAction252568704); if (getState()->time > kTime1773000 && params->param1 && getEntities()->isSomebodyInsideRestaurantOrSalon()) { getData()->inventoryItem = kItemNone; @@ -1863,7 +1876,7 @@ IMPLEMENT_FUNCTION(36, August, chapter2Handler) break; case 3: - getSavePoints()->push(kEntityAugust, kEntityServers0, kAction286534136); + getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction286534136); setCallback(4); setup_updateEntity(kCarGreenSleeping, kPosition_6470); @@ -1882,7 +1895,7 @@ IMPLEMENT_FUNCTION(36, August, chapter2Handler) if (!getEvent(kEventAugustGoodMorning)) getData()->inventoryItem = kItemInvalid; - getSavePoints()->push(kEntityAugust, kEntityServers0, kAction219522616); + getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction219522616); getEntities()->drawSequenceLeft(kEntityAugust, "016B"); params->param1 = 1; break; @@ -3044,7 +3057,7 @@ IMPLEMENT_FUNCTION(60, August, function60) } if (pushSavepoint) - getSavePoints()->push(kEntityAugust, kEntityServers0, kAction207330561); + getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction207330561); if (!params->param1) break; @@ -3074,7 +3087,7 @@ IMPLEMENT_FUNCTION(60, August, function60) break; case 2: - getSavePoints()->push(kEntityAugust, kEntityServers0, kAction286403504); + getSavePoints()->push(kEntityAugust, kEntityWaiter1, kAction286403504); setup_function61(); break; } @@ -3199,7 +3212,7 @@ IMPLEMENT_FUNCTION(62, August, function62) case 5: getEntities()->drawSequenceLeft(kEntityAugust, "122B"); - getSavePoints()->push(kEntityAugust, kEntityServers1, kAction291721418); + getSavePoints()->push(kEntityAugust, kEntityWaiter2, kAction291721418); break; } break; diff --git a/engines/lastexpress/entities/boutarel.cpp b/engines/lastexpress/entities/boutarel.cpp index 979381afb0..32507b0d63 100644 --- a/engines/lastexpress/entities/boutarel.cpp +++ b/engines/lastexpress/entities/boutarel.cpp @@ -310,7 +310,7 @@ IMPLEMENT_FUNCTION_I(14, Boutarel, function14, bool) break; case 2: - getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction326144276); + getSavePoints()->push(kEntityBoutarel, kEntityWaiter2, kAction326144276); getEntities()->drawSequenceRight(kEntityBoutarel, "812DS"); if (getEntities()->isInRestaurant(kEntityPlayer)) getEntities()->updateFrame(kEntityBoutarel); @@ -674,7 +674,7 @@ IMPLEMENT_FUNCTION(20, Boutarel, function20) break; case 2: - getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction256200848); + getSavePoints()->push(kEntityBoutarel, kEntityWaiter2, kAction256200848); break; case 3: @@ -937,7 +937,7 @@ IMPLEMENT_FUNCTION(29, Boutarel, function29) case kActionNone: if (Entity::updateParameter(params->param2, getState()->time, 450)) { - getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction256200848); + getSavePoints()->push(kEntityBoutarel, kEntityWaiter2, kAction256200848); } if (!params->param1) @@ -1086,7 +1086,7 @@ IMPLEMENT_FUNCTION(33, Boutarel, function33) break; case 2: - getSavePoints()->push(kEntityBoutarel, kEntityServers1, kAction256200848); + getSavePoints()->push(kEntityBoutarel, kEntityWaiter2, kAction256200848); break; case 3: diff --git a/engines/lastexpress/entities/chapters.cpp b/engines/lastexpress/entities/chapters.cpp index fe977a577f..f1a7d02384 100644 --- a/engines/lastexpress/entities/chapters.cpp +++ b/engines/lastexpress/entities/chapters.cpp @@ -44,13 +44,13 @@ #include "lastexpress/entities/pascale.h" #include "lastexpress/entities/rebecca.h" #include "lastexpress/entities/salko.h" -#include "lastexpress/entities/servers0.h" -#include "lastexpress/entities/servers1.h" #include "lastexpress/entities/sophie.h" #include "lastexpress/entities/tatiana.h" #include "lastexpress/entities/vassili.h" #include "lastexpress/entities/verges.h" #include "lastexpress/entities/vesna.h" +#include "lastexpress/entities/waiter1.h" +#include "lastexpress/entities/waiter2.h" #include "lastexpress/entities/yasmin.h" #include "lastexpress/game/action.h" @@ -77,7 +77,7 @@ Chapters::Chapters(LastExpressEngine *engine) : Entity(engine, kEntityChapters) ADD_CALLBACK_FUNCTION(Chapters, exitStation); ADD_CALLBACK_FUNCTION(Chapters, chapter1); ADD_CALLBACK_FUNCTION(Chapters, resetMainEntities); - ADD_CALLBACK_FUNCTION(Chapters, chapter1End); + ADD_CALLBACK_FUNCTION(Chapters, firstDream); ADD_CALLBACK_FUNCTION(Chapters, chapter1Init); ADD_CALLBACK_FUNCTION(Chapters, chapter1Handler); ADD_CALLBACK_FUNCTION(Chapters, chapter1Next); @@ -154,7 +154,8 @@ IMPLEMENT_FUNCTION(5, Chapters, resetMainEntities) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(6, Chapters, chapter1End) +IMPLEMENT_FUNCTION(6, Chapters, firstDream) + // Chapter 1 end switch (savepoint.action) { default: break; @@ -207,9 +208,9 @@ IMPLEMENT_FUNCTION(6, Chapters, chapter1End) case kActionDefault: RESET_ENTITY_STATE(kEntityPascale, Pascale, setup_function19); - RESET_ENTITY_STATE(kEntityServers0, Servers0, setup_function22); - RESET_ENTITY_STATE(kEntityServers1, Servers1, setup_function16); - RESET_ENTITY_STATE(kEntityCooks, Cooks, setup_function7); + RESET_ENTITY_STATE(kEntityWaiter1, Waiter1, setup_function22); + RESET_ENTITY_STATE(kEntityWaiter2, Waiter2, setup_function16); + RESET_ENTITY_STATE(kEntityCooks, Cooks, setup_lockUp); RESET_ENTITY_STATE(kEntityMertens, Mertens, setup_function42); RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_chapter1Handler); @@ -220,7 +221,7 @@ IMPLEMENT_FUNCTION(6, Chapters, chapter1End) getSavePoints()->push(kEntityChapters, kEntityVerges, kAction201431954); RESET_ENTITY_STATE(kEntityKronos, Kronos, setup_function10); - RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_function13); + RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_cathDone); RESET_ENTITY_STATE(kEntityAnna, Anna, setup_asleep); RESET_ENTITY_STATE(kEntityAugust, August, setup_function34); RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_function24); @@ -270,7 +271,6 @@ IMPLEMENT_FUNCTION(6, Chapters, chapter1End) if (getSoundQueue()->isBuffered("ZFX1007B")) getSoundQueue()->processEntry("ZFX1007B"); - getSound()->playSound(kEntityPlayer, "MUS008", kFlagDefault); getInventory()->unselectItem(); @@ -385,6 +385,7 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(8, Chapters, chapter1Handler) + // Moving at night switch (savepoint.action) { default: break; @@ -705,7 +706,7 @@ label_chapter1_next: setup_chapter1Next(); } else { setCallback(23); - setup_chapter1End(); + setup_firstDream(); } break; } @@ -918,6 +919,7 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(15, Chapters, chapter3Handler) + // Moving during the afternoon switch (savepoint.action) { default: break; @@ -1078,6 +1080,7 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(16, Chapters, viennaEvents) + // End in Vienna switch (savepoint.action) { default: break; @@ -1225,6 +1228,7 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(19, Chapters, chapter4Handler) + // Moving during the second night switch (savepoint.action) { default: break; @@ -1518,8 +1522,8 @@ label_callback_4: RESET_ENTITY_STATE(kEntityAugust, August, setup_function65); RESET_ENTITY_STATE(kEntityMertens, Mertens, setup_function48); RESET_ENTITY_STATE(kEntityCoudert, Coudert, setup_function53); - RESET_ENTITY_STATE(kEntityServers0, Servers0, setup_chapter4Handler); - RESET_ENTITY_STATE(kEntityServers1, Servers1, setup_chapter4Handler); + RESET_ENTITY_STATE(kEntityWaiter1, Waiter1, setup_serving4); + RESET_ENTITY_STATE(kEntityWaiter2, Waiter2, setup_serving4); RESET_ENTITY_STATE(kEntityPascale, Pascale, setup_chapter4Handler); RESET_ENTITY_STATE(kEntityVerges, Verges, setup_chapter4Handler); RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_function49); @@ -1535,12 +1539,12 @@ label_callback_4: RESET_ENTITY_STATE(kEntityYasmin, Yasmin, setup_function17); RESET_ENTITY_STATE(kEntityHadija, Hadija, setup_function19); RESET_ENTITY_STATE(kEntityAlouan, Alouan, setup_function19); - RESET_ENTITY_STATE(kEntityMax, Max, setup_chapter4Handler); + RESET_ENTITY_STATE(kEntityMax, Max, setup_inCageFriendly); getSavePoints()->push(kEntityChapters, kEntityAnna, kAction201431954); getSavePoints()->push(kEntityChapters, kEntityMertens, kAction201431954); getSavePoints()->push(kEntityChapters, kEntityCoudert, kAction201431954); - getSavePoints()->push(kEntityChapters, kEntityServers0, kAction201431954); - getSavePoints()->push(kEntityChapters, kEntityServers1, kAction201431954); + getSavePoints()->push(kEntityChapters, kEntityWaiter1, kAction201431954); + getSavePoints()->push(kEntityChapters, kEntityWaiter2, kAction201431954); getSavePoints()->push(kEntityChapters, kEntityPascale, kAction201431954); getSavePoints()->push(kEntityChapters, kEntityVerges, kAction201431954); @@ -1754,7 +1758,6 @@ IMPLEMENT_FUNCTION(22, Chapters, chapter5Handler) } IMPLEMENT_FUNCTION_END - ////////////////////////////////////////////////////////////////////////// // Private functions ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/entities/chapters.h b/engines/lastexpress/entities/chapters.h index 39739aa92e..abc464845f 100644 --- a/engines/lastexpress/entities/chapters.h +++ b/engines/lastexpress/entities/chapters.h @@ -70,7 +70,7 @@ public: /** * Handle end of Chapter 1 events */ - DECLARE_FUNCTION(chapter1End) + DECLARE_FUNCTION(firstDream) /** * Init Chapter 1 data diff --git a/engines/lastexpress/entities/cooks.cpp b/engines/lastexpress/entities/cooks.cpp index e24180e58d..749e93999b 100644 --- a/engines/lastexpress/entities/cooks.cpp +++ b/engines/lastexpress/entities/cooks.cpp @@ -37,17 +37,17 @@ namespace LastExpress { Cooks::Cooks(LastExpressEngine *engine) : Entity(engine, kEntityCooks) { ADD_CALLBACK_FUNCTION(Cooks, draw); ADD_CALLBACK_FUNCTION(Cooks, playSound); - ADD_CALLBACK_FUNCTION(Cooks, function3); - ADD_CALLBACK_FUNCTION(Cooks, function4); + ADD_CALLBACK_FUNCTION(Cooks, uptrainVersion); + ADD_CALLBACK_FUNCTION(Cooks, downtrainVersion); ADD_CALLBACK_FUNCTION(Cooks, chapter1); - ADD_CALLBACK_FUNCTION(Cooks, chapter1Handler); - ADD_CALLBACK_FUNCTION(Cooks, function7); + ADD_CALLBACK_FUNCTION(Cooks, inKitchenDinner); + ADD_CALLBACK_FUNCTION(Cooks, lockUp); ADD_CALLBACK_FUNCTION(Cooks, chapter2); - ADD_CALLBACK_FUNCTION(Cooks, chapter2Handler); + ADD_CALLBACK_FUNCTION(Cooks, inKitchenBreakfast); ADD_CALLBACK_FUNCTION(Cooks, chapter3); - ADD_CALLBACK_FUNCTION(Cooks, chapter3Handler); + ADD_CALLBACK_FUNCTION(Cooks, inKitchenLunch); ADD_CALLBACK_FUNCTION(Cooks, chapter4); - ADD_CALLBACK_FUNCTION(Cooks, chapter4Handler); + ADD_CALLBACK_FUNCTION(Cooks, inKitchenDinner2); ADD_CALLBACK_FUNCTION(Cooks, chapter5); } @@ -62,7 +62,7 @@ IMPLEMENT_FUNCTION_S(2, Cooks, playSound) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(3, Cooks, function3) +IMPLEMENT_FUNCTION(3, Cooks, uptrainVersion) switch (savepoint.action) { default: break; @@ -147,7 +147,7 @@ IMPLEMENT_FUNCTION(3, Cooks, function3) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(4, Cooks, function4) +IMPLEMENT_FUNCTION(4, Cooks, downtrainVersion) switch (savepoint.action) { default: break; @@ -239,7 +239,7 @@ IMPLEMENT_FUNCTION(5, Cooks, chapter1) break; case kActionNone: - Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Cooks, setup_chapter1Handler)); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Cooks, setup_inKitchenDinner)); break; case kActionDefault: @@ -254,7 +254,7 @@ IMPLEMENT_FUNCTION(5, Cooks, chapter1) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(6, Cooks, chapter1Handler) +IMPLEMENT_FUNCTION(6, Cooks, inKitchenDinner) switch (savepoint.action) { default: break; @@ -281,7 +281,7 @@ IMPLEMENT_FUNCTION(6, Cooks, chapter1Handler) if (params->param1) { if (getEntities()->isPlayerPosition(kCarRestaurant, 73)) { setCallback(1); - setup_function3(); + setup_uptrainVersion(); } } else { if (params->param3) { @@ -311,7 +311,7 @@ IMPLEMENT_FUNCTION(6, Cooks, chapter1Handler) break; case kAction101632192: - setup_function7(); + setup_lockUp(); break; case kAction224849280: @@ -322,7 +322,7 @@ IMPLEMENT_FUNCTION(6, Cooks, chapter1Handler) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(7, Cooks, function7) +IMPLEMENT_FUNCTION(7, Cooks, lockUp) switch (savepoint.action) { default: break; @@ -350,7 +350,7 @@ IMPLEMENT_FUNCTION(8, Cooks, chapter2) break; case kActionNone: - setup_chapter2Handler(); + setup_inKitchenBreakfast(); break; case kActionDefault: @@ -368,7 +368,7 @@ IMPLEMENT_FUNCTION(8, Cooks, chapter2) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(9, Cooks, chapter2Handler) +IMPLEMENT_FUNCTION(9, Cooks, inKitchenBreakfast) switch (savepoint.action) { default: break; @@ -411,7 +411,7 @@ IMPLEMENT_FUNCTION(10, Cooks, chapter3) break; case kActionNone: - setup_chapter3Handler(); + setup_inKitchenLunch(); break; case kActionDefault: @@ -428,7 +428,7 @@ IMPLEMENT_FUNCTION(10, Cooks, chapter3) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(11, Cooks, chapter3Handler) +IMPLEMENT_FUNCTION(11, Cooks, inKitchenLunch) switch (savepoint.action) { default: break; @@ -459,7 +459,7 @@ IMPLEMENT_FUNCTION(11, Cooks, chapter3Handler) if (params->param1) { if (getEntities()->isPlayerPosition(kCarRestaurant, 80)) { setCallback(1); - setup_function4(); + setup_downtrainVersion(); } } else { if (params->param3) { @@ -502,7 +502,7 @@ IMPLEMENT_FUNCTION(12, Cooks, chapter4) break; case kActionNone: - setup_chapter4Handler(); + setup_inKitchenDinner2(); break; case kActionDefault: @@ -520,7 +520,7 @@ IMPLEMENT_FUNCTION(12, Cooks, chapter4) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(13, Cooks, chapter4Handler) +IMPLEMENT_FUNCTION(13, Cooks, inKitchenDinner2) switch (savepoint.action) { default: break; @@ -553,7 +553,6 @@ IMPLEMENT_FUNCTION(13, Cooks, chapter4Handler) } break; - case kActionCallback: // Play the next part of background sound if (getCallback() == 1 || getCallback() == 2) { diff --git a/engines/lastexpress/entities/cooks.h b/engines/lastexpress/entities/cooks.h index 79addb0a02..6a65a25801 100644 --- a/engines/lastexpress/entities/cooks.h +++ b/engines/lastexpress/entities/cooks.h @@ -48,9 +48,9 @@ public: */ DECLARE_FUNCTION_1(playSound, const char *filename) - DECLARE_FUNCTION(function3) + DECLARE_FUNCTION(uptrainVersion) - DECLARE_FUNCTION(function4) + DECLARE_FUNCTION(downtrainVersion) /** * Setup Chapter 1 @@ -58,21 +58,21 @@ public: DECLARE_FUNCTION(chapter1) /** - * Handle Chapter 1 events + * Chapter 1: Prepare dinner in kitchen */ - DECLARE_FUNCTION(chapter1Handler) + DECLARE_FUNCTION(inKitchenDinner) - DECLARE_FUNCTION(function7) + DECLARE_FUNCTION(lockUp) /** * Setup Chapter 2 */ DECLARE_FUNCTION(chapter2) - /** - * Handle Chapter 2 events + /* + * Chapter 2: Prepare breakfast in kitchen */ - DECLARE_FUNCTION(chapter2Handler) + DECLARE_FUNCTION(inKitchenBreakfast) /** * Setup Chapter 3 @@ -80,9 +80,9 @@ public: DECLARE_FUNCTION(chapter3) /** - * Handle Chapter 3 events + * Chapter 3: Prepare lunch in kitchen */ - DECLARE_FUNCTION(chapter3Handler) + DECLARE_FUNCTION(inKitchenLunch) /** * Setup Chapter 4 @@ -90,9 +90,9 @@ public: DECLARE_FUNCTION(chapter4) /** - * Handle Chapter 4 events + * Chapter 4: Prepare second dinner in kitchen */ - DECLARE_FUNCTION(chapter4Handler) + DECLARE_FUNCTION(inKitchenDinner2) /** * Setup Chapter 5 diff --git a/engines/lastexpress/entities/entity.cpp b/engines/lastexpress/entities/entity.cpp index 07e82d296e..170248de52 100644 --- a/engines/lastexpress/entities/entity.cpp +++ b/engines/lastexpress/entities/entity.cpp @@ -51,6 +51,9 @@ EntityData::EntityCallData::~EntityCallData() { } void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::String &string, uint length) const { + assert(length <= 13); + assert(string.size() <= 13); + char seqName[13]; memset(&seqName, 0, length); @@ -972,5 +975,4 @@ bool Entity::timeCheckPlaySoundUpdatePosition(TimeValue timeValue, uint ¶met return false; } - } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/gendarmes.cpp b/engines/lastexpress/entities/gendarmes.cpp index 7b31c592cd..b628b8dfe7 100644 --- a/engines/lastexpress/entities/gendarmes.cpp +++ b/engines/lastexpress/entities/gendarmes.cpp @@ -37,16 +37,16 @@ namespace LastExpress { Gendarmes::Gendarmes(LastExpressEngine *engine) : Entity(engine, kEntityGendarmes) { ADD_CALLBACK_FUNCTION(Gendarmes, reset); ADD_CALLBACK_FUNCTION(Gendarmes, chapter1); - ADD_CALLBACK_FUNCTION(Gendarmes, arrestDraw); - ADD_CALLBACK_FUNCTION(Gendarmes, arrestPlaysound); - ADD_CALLBACK_FUNCTION(Gendarmes, arrestPlaysound16); - ADD_CALLBACK_FUNCTION(Gendarmes, arrestCallback); + ADD_CALLBACK_FUNCTION(Gendarmes, doDraw); + ADD_CALLBACK_FUNCTION(Gendarmes, doDialog); + ADD_CALLBACK_FUNCTION(Gendarmes, doDialogFullVolume); + ADD_CALLBACK_FUNCTION(Gendarmes, doWait); ADD_CALLBACK_FUNCTION(Gendarmes, savegame); - ADD_CALLBACK_FUNCTION(Gendarmes, arrestUpdateEntity); - ADD_CALLBACK_FUNCTION(Gendarmes, function9); - ADD_CALLBACK_FUNCTION(Gendarmes, function10); + ADD_CALLBACK_FUNCTION(Gendarmes, doWalk); + ADD_CALLBACK_FUNCTION(Gendarmes, doCompartment); + ADD_CALLBACK_FUNCTION(Gendarmes, trappedCath); ADD_CALLBACK_FUNCTION(Gendarmes, chapter1Handler); - ADD_CALLBACK_FUNCTION(Gendarmes, function12); + ADD_CALLBACK_FUNCTION(Gendarmes, searchTrain); ADD_CALLBACK_FUNCTION(Gendarmes, function13); ADD_CALLBACK_FUNCTION(Gendarmes, chapter2); ADD_CALLBACK_FUNCTION(Gendarmes, chapter3); @@ -76,23 +76,23 @@ IMPLEMENT_FUNCTION(2, Gendarmes, chapter1) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_S(3, Gendarmes, arrestDraw) - arrest(savepoint); +IMPLEMENT_FUNCTION_S(3, Gendarmes, doDraw) + handleAction(savepoint); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_S(4, Gendarmes, arrestPlaysound) - arrest(savepoint, true); +IMPLEMENT_FUNCTION_S(4, Gendarmes, doDialog) + handleAction(savepoint, true); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_S(5, Gendarmes, arrestPlaysound16) - arrest(savepoint, true, kFlagDefault); +IMPLEMENT_FUNCTION_S(5, Gendarmes, doDialogFullVolume) + handleAction(savepoint, true, kFlagDefault); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_I(6, Gendarmes, arrestCallback, uint32) - arrest(savepoint, true, kFlagInvalid, true); +IMPLEMENT_FUNCTION_I(6, Gendarmes, doWait, uint32) + handleAction(savepoint, true, kFlagInvalid, true); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// @@ -101,12 +101,12 @@ IMPLEMENT_FUNCTION_II(7, Gendarmes, savegame, SavegameType, uint32) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_II(8, Gendarmes, arrestUpdateEntity, CarIndex, EntityPosition) - arrest(savepoint, true, kFlagInvalid, false, true); +IMPLEMENT_FUNCTION_II(8, Gendarmes, doWalk, CarIndex, EntityPosition) + handleAction(savepoint, true, kFlagInvalid, false, true); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition) +IMPLEMENT_FUNCTION_IISS(9, Gendarmes, doCompartment, CarIndex, EntityPosition) EntityData::EntityParametersSSS *parameters1 = (EntityData::EntityParametersSSS*)_data->getCurrentParameters(1); EntityData::EntityParametersISII *parameters2 = (EntityData::EntityParametersISII*)_data->getCurrentParameters(2); @@ -169,6 +169,9 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition) strcpy((char *)¶meters1->seq3, "632F"); } + // The sequence 3 string needs to be a maximum of 9 characters, leaving 5 characters after the initial setup + assert(Common::String(params->seq1).size() <= 5); + strcat((char *)¶meters1->seq1, (char *)¶ms->seq1); strcat((char *)¶meters1->seq2, (char *)¶ms->seq1); strcat((char *)¶meters1->seq3, (char *)¶ms->seq1); @@ -178,13 +181,13 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition) || (params->param1 == kCarGreenSleeping && params->param2 == kPosition_8200 && getEntities()->isOutsideAlexeiWindow())) && !getEntities()->isInsideCompartment(kEntityPlayer, kCarRedSleeping, kPosition_7850)) { setCallback(1); - setup_function10((CarIndex)params->param1, (EntityPosition)params->param2, (ObjectIndex)parameters2->param5); + setup_trappedCath((CarIndex)params->param1, (EntityPosition)params->param2, (ObjectIndex)parameters2->param5); } else { getEntities()->drawSequenceLeft(kEntityGendarmes, (char *)¶meters1->seq1); getEntities()->enterCompartment(kEntityGendarmes, (ObjectIndex)CURRENT_PARAM(2, 5)); setCallback(parameters2->param6 ? 2 : 3); - setup_arrestPlaysound(parameters2->param6 ? "POL1044A" : "POL1044B"); + setup_doDialog(parameters2->param6 ? "POL1044A" : "POL1044B"); } break; @@ -202,14 +205,14 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition) getEntities()->drawSequenceLeft(kEntityGendarmes, (char *)¶meters1->seq2); if (getEntities()->isNobodyInCompartment((CarIndex)params->param1, (EntityPosition)params->param2) || !strcmp(params->seq2, "NODIALOG")) { setCallback(4); - setup_arrestCallback(150); + setup_doWait(150); } else { char *arrestSound = (char *)¶meters2->seq; strcpy(arrestSound, "POL1045"); strcat(arrestSound, (char *)¶ms->seq2); setCallback(5); - setup_arrestPlaysound(arrestSound); + setup_doDialog(arrestSound); } break; @@ -226,7 +229,7 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition) getData()->location = kLocationInsideCompartment; setCallback(6); - setup_arrestDraw((char *)¶meters1->seq3); + setup_doDraw((char *)¶meters1->seq3); break; case 6: @@ -240,7 +243,7 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, function9, CarIndex, EntityPosition) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, ObjectIndex) +IMPLEMENT_FUNCTION_III(10, Gendarmes, trappedCath, CarIndex, EntityPosition, ObjectIndex) switch (savepoint.action) { default: break; @@ -287,7 +290,7 @@ IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, Obje getObjects()->update((ObjectIndex)params->param3, kEntityGendarmes, getObjects()->get((ObjectIndex)params->param3).status, kCursorNormal, kCursorNormal); setCallback(5); - setup_arrestPlaysound16("POL1046B"); + setup_doDialogFullVolume("POL1046B"); break; case kActionOpenDoor: @@ -299,7 +302,7 @@ IMPLEMENT_FUNCTION_III(10, Gendarmes, function10, CarIndex, EntityPosition, Obje getObjects()->update((ObjectIndex)params->param3, kEntityGendarmes, getObjects()->get((ObjectIndex)params->param3).status, kCursorNormal, kCursorNormal); setCallback(1); - setup_arrestPlaysound16("POL1046"); + setup_doDialogFullVolume("POL1046"); break; case kActionCallback: @@ -351,12 +354,12 @@ IMPLEMENT_FUNCTION_END IMPLEMENT_FUNCTION(11, Gendarmes, chapter1Handler) if (savepoint.action == kAction169499649) { getSavePoints()->push(kEntityGendarmes, kEntityMertens, kAction190082817); - setup_function12(); + setup_searchTrain(); } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(12, Gendarmes, function12) +IMPLEMENT_FUNCTION(12, Gendarmes, searchTrain) switch (savepoint.action) { default: break; @@ -369,7 +372,7 @@ IMPLEMENT_FUNCTION(12, Gendarmes, function12) getProgress().field_14 = 29; setCallback(1); - setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_5540); + setup_doWalk(kCarGreenSleeping, kPosition_5540); break; case kActionCallback: @@ -379,42 +382,42 @@ IMPLEMENT_FUNCTION(12, Gendarmes, function12) case 1: setCallback(2); - setup_function9(kCarGreenSleeping, kPosition_5790, "d", "A"); + setup_doCompartment(kCarGreenSleeping, kPosition_5790, "d", "A"); break; case 2: setCallback(3); - setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_6220); + setup_doWalk(kCarGreenSleeping, kPosition_6220); break; case 3: setCallback(4); - setup_function9(kCarGreenSleeping, kPosition_6470, "c", "B"); + setup_doCompartment(kCarGreenSleeping, kPosition_6470, "c", "B"); break; case 4: setCallback(5); - setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_7250); + setup_doWalk(kCarGreenSleeping, kPosition_7250); break; case 5: setCallback(6); - setup_function9(kCarGreenSleeping, kPosition_7500, "b", "C"); + setup_doCompartment(kCarGreenSleeping, kPosition_7500, "b", "C"); break; case 6: setCallback(7); - setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_7950); + setup_doWalk(kCarGreenSleeping, kPosition_7950); break; case 7: setCallback(8); - setup_function9(kCarGreenSleeping, kPosition_8200, "a", "NODIALOG"); + setup_doCompartment(kCarGreenSleeping, kPosition_8200, "a", "NODIALOG"); break; case 8: setCallback(9); - setup_arrestUpdateEntity(kCarGreenSleeping, kPosition_9460); + setup_doWalk(kCarGreenSleeping, kPosition_9460); break; case 9: @@ -427,77 +430,77 @@ IMPLEMENT_FUNCTION(12, Gendarmes, function12) } setCallback(10); - setup_arrestUpdateEntity(kCarRedSleeping, kPosition_2490); + setup_doWalk(kCarRedSleeping, kPosition_2490); break; case 10: setCallback(11); - setup_function9(kCarRedSleeping, kPosition_2740, "h", "NODIALOG"); + setup_doCompartment(kCarRedSleeping, kPosition_2740, "h", "NODIALOG"); break; case 11: setCallback(12); - setup_arrestUpdateEntity(kCarRedSleeping, kPosition_3820); + setup_doWalk(kCarRedSleeping, kPosition_3820); break; case 12: setCallback(13); - setup_function9(kCarRedSleeping, kPosition_4070, "f", "E"); + setup_doCompartment(kCarRedSleeping, kPosition_4070, "f", "E"); break; case 13: setCallback(14); - setup_arrestUpdateEntity(kCarRedSleeping, kPosition_4590); + setup_doWalk(kCarRedSleeping, kPosition_4590); break; case 14: setCallback(15); - setup_function9(kCarRedSleeping, kPosition_4840, "e", "F"); + setup_doCompartment(kCarRedSleeping, kPosition_4840, "e", "F"); break; case 15: setCallback(16); - setup_arrestUpdateEntity(kCarRedSleeping, kPosition_5540); + setup_doWalk(kCarRedSleeping, kPosition_5540); break; case 16: setCallback(17); - setup_function9(kCarRedSleeping, kPosition_5790, "d", "G"); + setup_doCompartment(kCarRedSleeping, kPosition_5790, "d", "G"); break; case 17: setCallback(18); - setup_arrestUpdateEntity(kCarRedSleeping, kPosition_6220); + setup_doWalk(kCarRedSleeping, kPosition_6220); break; case 18: setCallback(19); - setup_function9(kCarRedSleeping, kPosition_6470, "c", "H"); + setup_doCompartment(kCarRedSleeping, kPosition_6470, "c", "H"); break; case 19: setCallback(20); - setup_arrestUpdateEntity(kCarRedSleeping, kPosition_7250); + setup_doWalk(kCarRedSleeping, kPosition_7250); break; case 20: setCallback(21); - setup_function9(kCarRedSleeping, kPosition_7500, "b", "J"); + setup_doCompartment(kCarRedSleeping, kPosition_7500, "b", "J"); break; case 21: setCallback(22); - setup_arrestUpdateEntity(kCarRedSleeping, kPosition_7950); + setup_doWalk(kCarRedSleeping, kPosition_7950); break; case 22: setCallback(23); - setup_function9(kCarRedSleeping, kPosition_8200, "a", "NODIALOG"); + setup_doCompartment(kCarRedSleeping, kPosition_8200, "a", "NODIALOG"); break; case 23: setCallback(24); - setup_arrestUpdateEntity(kCarRedSleeping, kPosition_9460); + setup_doWalk(kCarRedSleeping, kPosition_9460); break; case 24: @@ -544,7 +547,7 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// // Private functions ////////////////////////////////////////////////////////////////////////// -void Gendarmes::arrest(const SavePoint &savepoint, bool shouldPlaySound, SoundFlag flag, bool checkCallback, bool shouldUpdateEntity) { +void Gendarmes::handleAction(const SavePoint &savepoint, bool shouldPlaySound, SoundFlag flag, bool checkCallback, bool shouldUpdateEntity) { switch (savepoint.action) { default: break; diff --git a/engines/lastexpress/entities/gendarmes.h b/engines/lastexpress/entities/gendarmes.h index 8475c50799..1cde626a22 100644 --- a/engines/lastexpress/entities/gendarmes.h +++ b/engines/lastexpress/entities/gendarmes.h @@ -46,10 +46,10 @@ public: */ DECLARE_FUNCTION(chapter1) - DECLARE_FUNCTION_1(arrestDraw, const char *sequence) - DECLARE_FUNCTION_1(arrestPlaysound, const char *soundName) - DECLARE_FUNCTION_1(arrestPlaysound16, const char *soundName) - DECLARE_FUNCTION_1(arrestCallback, uint32 timeValue) + DECLARE_FUNCTION_1(doDraw, const char *sequence) + DECLARE_FUNCTION_1(doDialog, const char *soundName) + DECLARE_FUNCTION_1(doDialogFullVolume, const char *soundName) + DECLARE_FUNCTION_1(doWait, uint32 timeValue) /** * Saves the game @@ -59,11 +59,11 @@ public: */ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param) - DECLARE_FUNCTION_2(arrestUpdateEntity, CarIndex car, EntityPosition entityPosition) - DECLARE_FUNCTION_4(function9, CarIndex car, EntityPosition entityPosition, const char *sequence1, const char *sequence2) - DECLARE_FUNCTION_3(function10, CarIndex car, EntityPosition entityPosition, ObjectIndex object) + DECLARE_FUNCTION_2(doWalk, CarIndex car, EntityPosition entityPosition) + DECLARE_FUNCTION_4(doCompartment, CarIndex car, EntityPosition entityPosition, const char *sequence1, const char *sequence2) + DECLARE_FUNCTION_3(trappedCath, CarIndex car, EntityPosition entityPosition, ObjectIndex object) DECLARE_FUNCTION(chapter1Handler) - DECLARE_FUNCTION(function12) + DECLARE_FUNCTION(searchTrain) DECLARE_FUNCTION(function13) /** @@ -87,7 +87,7 @@ public: DECLARE_FUNCTION(chapter5) private: - void arrest(const SavePoint &savepoint, bool playSound = false, SoundFlag flag = kFlagInvalid, bool checkCallback = false, bool shouldUpdateEntity = false); + void handleAction(const SavePoint &savepoint, bool playSound = false, SoundFlag flag = kFlagInvalid, bool checkCallback = false, bool shouldUpdateEntity = false); }; } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/hadija.cpp b/engines/lastexpress/entities/hadija.cpp index 14d5b714ca..eb255d77f8 100644 --- a/engines/lastexpress/entities/hadija.cpp +++ b/engines/lastexpress/entities/hadija.cpp @@ -38,10 +38,10 @@ Hadija::Hadija(LastExpressEngine *engine) : Entity(engine, kEntityHadija) { ADD_CALLBACK_FUNCTION(Hadija, playSound); ADD_CALLBACK_FUNCTION(Hadija, updateFromTime); ADD_CALLBACK_FUNCTION(Hadija, updateEntity); - ADD_CALLBACK_FUNCTION(Hadija, compartment6); - ADD_CALLBACK_FUNCTION(Hadija, compartment8); - ADD_CALLBACK_FUNCTION(Hadija, compartment6to8); - ADD_CALLBACK_FUNCTION(Hadija, compartment8to6); + ADD_CALLBACK_FUNCTION(Hadija, peekF); + ADD_CALLBACK_FUNCTION(Hadija, peekH); + ADD_CALLBACK_FUNCTION(Hadija, goFtoH); + ADD_CALLBACK_FUNCTION(Hadija, goHtoF); ADD_CALLBACK_FUNCTION(Hadija, chapter1); ADD_CALLBACK_FUNCTION(Hadija, chapter1Handler); ADD_CALLBACK_FUNCTION(Hadija, function12); @@ -55,7 +55,7 @@ Hadija::Hadija(LastExpressEngine *engine) : Entity(engine, kEntityHadija) { ADD_CALLBACK_FUNCTION(Hadija, chapter5); ADD_CALLBACK_FUNCTION(Hadija, chapter5Handler); ADD_CALLBACK_FUNCTION(Hadija, function22); - ADD_CALLBACK_FUNCTION(Hadija, function23); + ADD_CALLBACK_FUNCTION(Hadija, hiding); ADD_NULL_FUNCTION(); } @@ -85,22 +85,22 @@ IMPLEMENT_FUNCTION_II(5, Hadija, updateEntity, CarIndex, EntityPosition) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(6, Hadija, compartment6) +IMPLEMENT_FUNCTION(6, Hadija, peekF) Entity::goToCompartment(savepoint, kObjectCompartment6, kPosition_4070, "619Cf", "619Df"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(7, Hadija, compartment8) +IMPLEMENT_FUNCTION(7, Hadija, peekH) Entity::goToCompartment(savepoint, kObjectCompartment8, kPosition_2740, "619Ch", "619Dh"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(8, Hadija, compartment6to8) +IMPLEMENT_FUNCTION(8, Hadija, goFtoH) Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment6, kPosition_4070, "619Bf", kObjectCompartment8, kPosition_2740, "619Ah"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(9, Hadija, compartment8to6) +IMPLEMENT_FUNCTION(9, Hadija, goHtoF) Entity::goToCompartmentFromCompartment(savepoint, kObjectCompartment8, kPosition_2740, "619Bh", kObjectCompartment6, kPosition_4070, "619Af"); IMPLEMENT_FUNCTION_END @@ -134,7 +134,7 @@ IMPLEMENT_FUNCTION(11, Hadija, chapter1Handler) break; label_callback1: - if (Entity::timeCheckCallback(kTime1084500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8))) + if (Entity::timeCheckCallback(kTime1084500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goFtoH))) break; label_callback2: @@ -147,7 +147,7 @@ label_callback2: if (!params->param3) { setCallback(3); - setup_compartment8(); + setup_peekH(); return; } } @@ -159,11 +159,11 @@ label_callback2: params->param3 = kTimeInvalid; setCallback(3); - setup_compartment8(); + setup_peekH(); } label_callback3: - if (Entity::timeCheckCallback(kTime1156500, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6))) + if (Entity::timeCheckCallback(kTime1156500, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF))) break; label_callback4: @@ -175,7 +175,7 @@ label_callback4: if (!params->param5) { setCallback(5); - setup_compartment6(); + setup_peekF(); return; } } @@ -187,7 +187,7 @@ label_callback4: params->param5 = kTimeInvalid; setCallback(5); - setup_compartment6(); + setup_peekF(); } break; @@ -254,7 +254,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler) } if (params->param2 == kTimeInvalid || getState()->time <= kTime1786500) { - Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)); + Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF)); break; } @@ -264,7 +264,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler) params->param2 = (uint)getState()->time + 75; if (params->param2 >= getState()->time) { - Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)); + Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF)); break; } } @@ -272,7 +272,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler) params->param2 = kTimeInvalid; setCallback(1); - setup_compartment8(); + setup_peekH(); break; case kActionCallback: @@ -281,7 +281,7 @@ IMPLEMENT_FUNCTION(14, Hadija, chapter2Handler) break; case 1: - Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6)); + Entity::timeCheckCallback(kTime1822500, params->param3, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF)); break; case 2: @@ -321,24 +321,24 @@ IMPLEMENT_FUNCTION(16, Hadija, chapter3Handler) break; case kActionNone: - if (Entity::timeCheckCallback(kTime1998000, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8))) + if (Entity::timeCheckCallback(kTime1998000, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_goFtoH))) break; label_callback1: - if (Entity::timeCheckCallback(kTime2020500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6))) + if (Entity::timeCheckCallback(kTime2020500, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF))) break; label_callback2: - if (Entity::timeCheckCallback(kTime2079000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8))) + if (Entity::timeCheckCallback(kTime2079000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_goFtoH))) break; label_callback3: - if (Entity::timeCheckCallback(kTime2187000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6))) + if (Entity::timeCheckCallback(kTime2187000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF))) break; label_callback4: if (params->param5 != kTimeInvalid && getState()->time > kTime2196000) { - if (Entity::timeCheckCar(kTime2254500, params->param5, 5, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6))) + if (Entity::timeCheckCar(kTime2254500, params->param5, 5, WRAP_SETUP_FUNCTION(Hadija, setup_peekF))) break; } break; @@ -394,21 +394,21 @@ IMPLEMENT_FUNCTION(18, Hadija, chapter4Handler) case kActionNone: if (params->param1 != kTimeInvalid) { - if (Entity::timeCheckCar(kTime1714500, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6))) + if (Entity::timeCheckCar(kTime1714500, params->param1, 1, WRAP_SETUP_FUNCTION(Hadija, setup_peekF))) break; } label_callback1: - if (Entity::timeCheckCallback(kTime2367000, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6to8))) + if (Entity::timeCheckCallback(kTime2367000, params->param2, 2, WRAP_SETUP_FUNCTION(Hadija, setup_goFtoH))) break; label_callback2: - if (Entity::timeCheckCallback(kTime2421000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_compartment8to6))) + if (Entity::timeCheckCallback(kTime2421000, params->param3, 3, WRAP_SETUP_FUNCTION(Hadija, setup_goHtoF))) break; label_callback3: if (params->param4 != kTimeInvalid && getState()->time > kTime2425500) { - if (Entity::timeCheckCar(kTime2484000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_compartment6))) + if (Entity::timeCheckCar(kTime2484000, params->param4, 4, WRAP_SETUP_FUNCTION(Hadija, setup_peekF))) break; } break; @@ -483,7 +483,7 @@ IMPLEMENT_FUNCTION(22, Hadija, function22) if (!Entity::updateParameter(params->param1, getState()->time, 2700)) break; - setup_function23(); + setup_hiding(); break; case kActionDefault: @@ -494,14 +494,14 @@ IMPLEMENT_FUNCTION(22, Hadija, function22) case kActionDrawScene: if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarGreenSleeping)) { - setup_function23(); + setup_hiding(); } break; } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(23, Hadija, function23) +IMPLEMENT_FUNCTION(23, Hadija, hiding) switch (savepoint.action) { default: break; diff --git a/engines/lastexpress/entities/hadija.h b/engines/lastexpress/entities/hadija.h index 8e92dc6891..a66aa33628 100644 --- a/engines/lastexpress/entities/hadija.h +++ b/engines/lastexpress/entities/hadija.h @@ -70,10 +70,10 @@ public: */ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition) - DECLARE_FUNCTION(compartment6) - DECLARE_FUNCTION(compartment8) - DECLARE_FUNCTION(compartment6to8) - DECLARE_FUNCTION(compartment8to6) + DECLARE_FUNCTION(peekF) + DECLARE_FUNCTION(peekH) + DECLARE_FUNCTION(goFtoH) + DECLARE_FUNCTION(goHtoF) /** * Setup Chapter 1 @@ -130,7 +130,7 @@ public: DECLARE_FUNCTION(chapter5Handler) DECLARE_FUNCTION(function22) - DECLARE_FUNCTION(function23) + DECLARE_FUNCTION(hiding) DECLARE_NULL_FUNCTION() }; diff --git a/engines/lastexpress/entities/ivo.cpp b/engines/lastexpress/entities/ivo.cpp index b7697d0c52..12a23e7d37 100644 --- a/engines/lastexpress/entities/ivo.cpp +++ b/engines/lastexpress/entities/ivo.cpp @@ -47,29 +47,29 @@ Ivo::Ivo(LastExpressEngine *engine) : Entity(engine, kEntityIvo) { ADD_CALLBACK_FUNCTION(Ivo, playSound); ADD_CALLBACK_FUNCTION(Ivo, callbackActionRestaurantOrSalon); ADD_CALLBACK_FUNCTION(Ivo, savegame); - ADD_CALLBACK_FUNCTION(Ivo, function11); + ADD_CALLBACK_FUNCTION(Ivo, goCompartment); ADD_CALLBACK_FUNCTION(Ivo, sitAtTableWithSalko); ADD_CALLBACK_FUNCTION(Ivo, leaveTableWithSalko); ADD_CALLBACK_FUNCTION(Ivo, chapter1); ADD_CALLBACK_FUNCTION(Ivo, chapter1Handler); - ADD_CALLBACK_FUNCTION(Ivo, function16); + ADD_CALLBACK_FUNCTION(Ivo, inCompartment); ADD_CALLBACK_FUNCTION(Ivo, function17); ADD_CALLBACK_FUNCTION(Ivo, chapter2); - ADD_CALLBACK_FUNCTION(Ivo, function19); - ADD_CALLBACK_FUNCTION(Ivo, function20); + ADD_CALLBACK_FUNCTION(Ivo, goBreakfast); + ADD_CALLBACK_FUNCTION(Ivo, atBreakfast); ADD_CALLBACK_FUNCTION(Ivo, function21); ADD_CALLBACK_FUNCTION(Ivo, chapter3); ADD_CALLBACK_FUNCTION(Ivo, chapter3Handler); ADD_CALLBACK_FUNCTION(Ivo, chapter4); ADD_CALLBACK_FUNCTION(Ivo, chapter4Handler); - ADD_CALLBACK_FUNCTION(Ivo, function26); - ADD_CALLBACK_FUNCTION(Ivo, function27); - ADD_CALLBACK_FUNCTION(Ivo, function28); + ADD_CALLBACK_FUNCTION(Ivo, returnCompartment4); + ADD_CALLBACK_FUNCTION(Ivo, inCompartment4); + ADD_CALLBACK_FUNCTION(Ivo, hiding); ADD_CALLBACK_FUNCTION(Ivo, function29); ADD_CALLBACK_FUNCTION(Ivo, chapter5); ADD_CALLBACK_FUNCTION(Ivo, chapter5Handler); - ADD_CALLBACK_FUNCTION(Ivo, fight); - ADD_CALLBACK_FUNCTION(Ivo, function33); + ADD_CALLBACK_FUNCTION(Ivo, fightCath); + ADD_CALLBACK_FUNCTION(Ivo, knockedOut); ADD_CALLBACK_FUNCTION(Ivo, function34); } @@ -129,7 +129,7 @@ IMPLEMENT_FUNCTION_II(10, Ivo, savegame, SavegameType, uint32) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(11, Ivo, function11) +IMPLEMENT_FUNCTION(11, Ivo, goCompartment) switch (savepoint.action) { default: break; @@ -279,12 +279,12 @@ IMPLEMENT_FUNCTION(15, Ivo, chapter1Handler) case 1: setCallback(2); - setup_function11(); + setup_goCompartment(); break; case 2: getSavePoints()->push(kEntityIvo, kEntityMilos, kAction135024800); - setup_function16(); + setup_inCompartment(); break; } break; @@ -297,7 +297,7 @@ IMPLEMENT_FUNCTION(15, Ivo, chapter1Handler) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(16, Ivo, function16) +IMPLEMENT_FUNCTION(16, Ivo, inCompartment) switch (savepoint.action) { default: break; @@ -371,7 +371,7 @@ IMPLEMENT_FUNCTION(18, Ivo, chapter2) break; case kActionNone: - Entity::timeCheck(kTime1777500, params->param1, WRAP_SETUP_FUNCTION(Ivo, setup_function19)); + Entity::timeCheck(kTime1777500, params->param1, WRAP_SETUP_FUNCTION(Ivo, setup_goBreakfast)); break; case kActionDefault: @@ -391,7 +391,7 @@ IMPLEMENT_FUNCTION(18, Ivo, chapter2) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(19, Ivo, function19) +IMPLEMENT_FUNCTION(19, Ivo, goBreakfast) switch (savepoint.action) { default: break; @@ -434,7 +434,7 @@ IMPLEMENT_FUNCTION(19, Ivo, function19) case 5: getData()->location = kLocationInsideCompartment; - setup_function20(); + setup_atBreakfast(); break; } break; @@ -447,7 +447,7 @@ IMPLEMENT_FUNCTION(19, Ivo, function19) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(20, Ivo, function20) +IMPLEMENT_FUNCTION(20, Ivo, atBreakfast) switch (savepoint.action) { default: break; @@ -464,7 +464,7 @@ IMPLEMENT_FUNCTION(20, Ivo, function20) break; case kActionDefault: - getSavePoints()->push(kEntityIvo, kEntityServers1, kAction189688608); + getSavePoints()->push(kEntityIvo, kEntityWaiter2, kAction189688608); getEntities()->drawSequenceLeft(kEntityIvo, "023B"); break; @@ -474,18 +474,18 @@ IMPLEMENT_FUNCTION(20, Ivo, function20) break; case 1: - getSavePoints()->push(kEntityIvo, kEntityServers1, kAction101106391); + getSavePoints()->push(kEntityIvo, kEntityWaiter2, kAction101106391); getEntities()->drawSequenceLeft(kEntityIvo, "023B"); params->param1 = 1; break; case 2: setCallback(3); - setup_function11(); + setup_goCompartment(); break; case 3: - getSavePoints()->push(kEntityIvo, kEntityServers1, kAction236237423); + getSavePoints()->push(kEntityIvo, kEntityWaiter2, kAction236237423); setup_function21(); break; } @@ -567,7 +567,7 @@ IMPLEMENT_FUNCTION(25, Ivo, chapter4Handler) case kActionNone: if (getState()->time > kTime2361600 && getEntities()->isSomebodyInsideRestaurantOrSalon()) { getData()->location = kLocationOutsideCompartment; - setup_function26(); + setup_returnCompartment4(); } break; @@ -579,7 +579,7 @@ IMPLEMENT_FUNCTION(25, Ivo, chapter4Handler) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(26, Ivo, function26) +IMPLEMENT_FUNCTION(26, Ivo, returnCompartment4) switch (savepoint.action) { default: break; @@ -596,11 +596,11 @@ IMPLEMENT_FUNCTION(26, Ivo, function26) case 1: setCallback(2); - setup_function11(); + setup_goCompartment(); break; case 2: - setup_function27(); + setup_inCompartment4(); break; } break; @@ -608,7 +608,7 @@ IMPLEMENT_FUNCTION(26, Ivo, function26) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(27, Ivo, function27) +IMPLEMENT_FUNCTION(27, Ivo, inCompartment4) switch (savepoint.action) { default: break; @@ -634,7 +634,7 @@ IMPLEMENT_FUNCTION(27, Ivo, function27) case 2: getEntities()->clearSequences(kEntityIvo); - setup_function28(); + setup_hiding(); break; case 3: @@ -676,7 +676,7 @@ IMPLEMENT_FUNCTION(27, Ivo, function27) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(28, Ivo, function28) +IMPLEMENT_FUNCTION(28, Ivo, hiding) switch (savepoint.action) { default: break; @@ -745,11 +745,11 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(31, Ivo, chapter5Handler) if (savepoint.action == kActionProceedChapter5) - setup_fight(); + setup_fightCath(); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(32, Ivo, fight) +IMPLEMENT_FUNCTION(32, Ivo, fightCath) switch (savepoint.action) { default: break; @@ -783,7 +783,7 @@ IMPLEMENT_FUNCTION(32, Ivo, fight) getLogic()->gameOver(kSavegameTypeIndex, 0, kSceneNone, true); } else { getScenes()->loadSceneFromPosition(kCarBaggageRear, 96); - setup_function33(); + setup_knockedOut(); } break; } @@ -792,7 +792,7 @@ IMPLEMENT_FUNCTION(32, Ivo, fight) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(33, Ivo, function33) +IMPLEMENT_FUNCTION(33, Ivo, knockedOut) switch (savepoint.action) { default: break; diff --git a/engines/lastexpress/entities/ivo.h b/engines/lastexpress/entities/ivo.h index a23d06cd3f..3646bc19f2 100644 --- a/engines/lastexpress/entities/ivo.h +++ b/engines/lastexpress/entities/ivo.h @@ -102,7 +102,7 @@ public: */ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param) - DECLARE_FUNCTION(function11) + DECLARE_FUNCTION(goCompartment) DECLARE_FUNCTION(sitAtTableWithSalko) DECLARE_FUNCTION(leaveTableWithSalko) @@ -116,7 +116,7 @@ public: */ DECLARE_FUNCTION(chapter1Handler) - DECLARE_FUNCTION(function16) + DECLARE_FUNCTION(inCompartment) DECLARE_FUNCTION(function17) /** @@ -124,8 +124,8 @@ public: */ DECLARE_FUNCTION(chapter2) - DECLARE_FUNCTION(function19) - DECLARE_FUNCTION(function20) + DECLARE_FUNCTION(goBreakfast) + DECLARE_FUNCTION(atBreakfast) DECLARE_FUNCTION(function21) /** @@ -148,9 +148,9 @@ public: */ DECLARE_FUNCTION(chapter4Handler) - DECLARE_FUNCTION(function26) - DECLARE_FUNCTION(function27) - DECLARE_FUNCTION(function28) + DECLARE_FUNCTION(returnCompartment4) + DECLARE_FUNCTION(inCompartment4) + DECLARE_FUNCTION(hiding) DECLARE_FUNCTION(function29) /** @@ -163,8 +163,8 @@ public: */ DECLARE_FUNCTION(chapter5Handler) - DECLARE_FUNCTION(fight) - DECLARE_FUNCTION(function33) + DECLARE_FUNCTION(fightCath) + DECLARE_FUNCTION(knockedOut) DECLARE_FUNCTION(function34) }; diff --git a/engines/lastexpress/entities/kahina.cpp b/engines/lastexpress/entities/kahina.cpp index b7af87751f..bbb2853721 100644 --- a/engines/lastexpress/entities/kahina.cpp +++ b/engines/lastexpress/entities/kahina.cpp @@ -43,28 +43,28 @@ Kahina::Kahina(LastExpressEngine *engine) : Entity(engine, kEntityKahina) { ADD_CALLBACK_FUNCTION(Kahina, savegame); ADD_CALLBACK_FUNCTION(Kahina, updateFromTime); ADD_CALLBACK_FUNCTION(Kahina, updateFromTicks); - ADD_CALLBACK_FUNCTION(Kahina, function6); + ADD_CALLBACK_FUNCTION(Kahina, lookingForCath); ADD_CALLBACK_FUNCTION(Kahina, updateEntity2); ADD_CALLBACK_FUNCTION(Kahina, updateEntity); ADD_CALLBACK_FUNCTION(Kahina, enterExitCompartment); ADD_CALLBACK_FUNCTION(Kahina, chapter1); ADD_CALLBACK_FUNCTION(Kahina, chapter1Handler); - ADD_CALLBACK_FUNCTION(Kahina, function12); - ADD_CALLBACK_FUNCTION(Kahina, function13); + ADD_CALLBACK_FUNCTION(Kahina, awaitingCath); + ADD_CALLBACK_FUNCTION(Kahina, cathDone); ADD_CALLBACK_FUNCTION(Kahina, function14); - ADD_CALLBACK_FUNCTION(Kahina, function15); + ADD_CALLBACK_FUNCTION(Kahina, searchTrain); ADD_CALLBACK_FUNCTION(Kahina, chapter2); - ADD_CALLBACK_FUNCTION(Kahina, chapter2Handler); + ADD_CALLBACK_FUNCTION(Kahina, inSeclusionPart2); ADD_CALLBACK_FUNCTION(Kahina, chapter3); ADD_CALLBACK_FUNCTION(Kahina, function19); - ADD_CALLBACK_FUNCTION(Kahina, chapter3Handler); - ADD_CALLBACK_FUNCTION(Kahina, function21); - ADD_CALLBACK_FUNCTION(Kahina, function22); - ADD_CALLBACK_FUNCTION(Kahina, function23); - ADD_CALLBACK_FUNCTION(Kahina, function24); - ADD_CALLBACK_FUNCTION(Kahina, function25); - ADD_CALLBACK_FUNCTION(Kahina, function26); - ADD_CALLBACK_FUNCTION(Kahina, function27); + ADD_CALLBACK_FUNCTION(Kahina, beforeConcert); + ADD_CALLBACK_FUNCTION(Kahina, concert); + ADD_CALLBACK_FUNCTION(Kahina, finished); + ADD_CALLBACK_FUNCTION(Kahina, findFirebird); + ADD_CALLBACK_FUNCTION(Kahina, seekCath); + ADD_CALLBACK_FUNCTION(Kahina, searchCath); + ADD_CALLBACK_FUNCTION(Kahina, searchTatiana); + ADD_CALLBACK_FUNCTION(Kahina, killCathAnywhere); ADD_CALLBACK_FUNCTION(Kahina, chapter4); ADD_CALLBACK_FUNCTION(Kahina, chapter5); } @@ -100,7 +100,7 @@ IMPLEMENT_FUNCTION_NOSETUP(5, Kahina, updateFromTicks) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_I(6, Kahina, function6, TimeValue) +IMPLEMENT_FUNCTION_I(6, Kahina, lookingForCath, TimeValue) switch (savepoint.action) { default: break; @@ -270,17 +270,17 @@ IMPLEMENT_FUNCTION(11, Kahina, chapter1Handler) Entity::timeCheckSavepoint(kTime1107000, params->param1, kEntityKahina, kEntityMertens, kAction238732837); if (getProgress().eventMertensKronosInvitation) - setup_function12(); + setup_awaitingCath(); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(12, Kahina, function12) +IMPLEMENT_FUNCTION(12, Kahina, awaitingCath) switch (savepoint.action) { default: break; case kActionNone: - Entity::timeCheck(kTime1485000, params->param2, WRAP_SETUP_FUNCTION(Kahina, setup_function13)); + Entity::timeCheck(kTime1485000, params->param2, WRAP_SETUP_FUNCTION(Kahina, setup_cathDone)); break; case kActionKnock: @@ -316,13 +316,13 @@ IMPLEMENT_FUNCTION(12, Kahina, function12) break; case kAction137685712: - setup_function13(); + setup_cathDone(); break; } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(13, Kahina, function13) +IMPLEMENT_FUNCTION(13, Kahina, cathDone) switch (savepoint.action) { default: break; @@ -347,7 +347,7 @@ IMPLEMENT_FUNCTION(13, Kahina, function13) label_callback: setCallback(1); - setup_function15(); + setup_searchTrain(); break; case kActionDefault: @@ -387,7 +387,7 @@ IMPLEMENT_FUNCTION(14, Kahina, function14) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(15, Kahina, function15) +IMPLEMENT_FUNCTION(15, Kahina, searchTrain) switch (savepoint.action) { default: break; @@ -554,7 +554,7 @@ IMPLEMENT_FUNCTION(16, Kahina, chapter2) break; case kActionNone: - setup_chapter2Handler(); + setup_inSeclusionPart2(); break; case kActionDefault: @@ -573,7 +573,7 @@ IMPLEMENT_FUNCTION(16, Kahina, chapter2) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(17, Kahina, chapter2Handler) +IMPLEMENT_FUNCTION(17, Kahina, inSeclusionPart2) switch (savepoint.action) { default: break; @@ -700,7 +700,7 @@ IMPLEMENT_FUNCTION(18, Kahina, chapter3) break; case kActionNone: - setup_chapter3Handler(); + setup_beforeConcert(); break; case kActionDefault: @@ -724,7 +724,7 @@ IMPLEMENT_FUNCTION_II(19, Kahina, function19, CarIndex, EntityPosition) case kActionNone: if (getEvent(kEventAnnaBaggageArgument)) { - RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_function22); + RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_finished); } if (getEntities()->updateEntity(kEntityKahina, (CarIndex)params->param1, (EntityPosition)params->param2)) @@ -750,7 +750,7 @@ IMPLEMENT_FUNCTION_II(19, Kahina, function19, CarIndex, EntityPosition) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(20, Kahina, chapter3Handler) +IMPLEMENT_FUNCTION(20, Kahina, beforeConcert) switch (savepoint.action) { default: break; @@ -781,7 +781,7 @@ label_callback_2: if (getEntities()->isInKronosSalon(kEntityPlayer)) getScenes()->loadSceneFromPosition(kCarKronos, 87); - setup_function21(); + setup_concert(); break; } @@ -917,7 +917,7 @@ label_callback_2: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(21, Kahina, function21) +IMPLEMENT_FUNCTION(21, Kahina, concert) switch (savepoint.action) { default: break; @@ -930,7 +930,7 @@ IMPLEMENT_FUNCTION(21, Kahina, function21) if (params->param6 != kTimeInvalid) { if (Entity::updateParameterTime((TimeValue)params->param3, (getEntities()->isPlayerPosition(kCarKronos, 80) || getEntities()->isPlayerPosition(kCarKronos, 88)), params->param5, 0)) { setCallback(2); - setup_function23(); + setup_findFirebird(); break; } } @@ -961,10 +961,10 @@ label_callback_2: if (location == kObjectLocation3 || location == kObjectLocation7) { setCallback(3); - setup_function25(); + setup_searchCath(); } else if (location == kObjectLocation1 || location == kObjectLocation2) { setCallback(4); - setup_function26(); + setup_searchTatiana(); } } break; @@ -997,17 +997,17 @@ label_callback_2: case kAction92186062: if (params->param1) { setCallback(1); - setup_function23(); + setup_findFirebird(); } break; case kAction134611040: if (getEvent(kEventConcertLeaveWithBriefcase)) - setup_function24(); + setup_seekCath(); break; case kAction137503360: - setup_function22(); + setup_finished(); break; case kAction237555748: @@ -1017,7 +1017,7 @@ label_callback_2: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(22, Kahina, function22) +IMPLEMENT_FUNCTION(22, Kahina, finished) switch (savepoint.action) { default: break; @@ -1028,10 +1028,10 @@ IMPLEMENT_FUNCTION(22, Kahina, function22) if (ENTITY_PARAM(0, 3) || location == kObjectLocation3 || location == kObjectLocation7) { setCallback(1); - setup_function25(); + setup_searchCath(); } else if (location == kObjectLocation2 || location == kObjectLocation1) { setCallback(2); - setup_function26(); + setup_searchTatiana(); } } break; @@ -1050,7 +1050,7 @@ IMPLEMENT_FUNCTION(22, Kahina, function22) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(23, Kahina, function23) +IMPLEMENT_FUNCTION(23, Kahina, findFirebird) switch (savepoint.action) { default: break; @@ -1133,7 +1133,7 @@ IMPLEMENT_FUNCTION(23, Kahina, function23) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(24, Kahina, function24) +IMPLEMENT_FUNCTION(24, Kahina, seekCath) switch (savepoint.action) { default: break; @@ -1149,12 +1149,12 @@ IMPLEMENT_FUNCTION(24, Kahina, function24) if (getEntities()->isInsideTrainCar(kEntityPlayer, kCarKronos)) getSavePoints()->push(kEntityKahina, kEntityKronos, kActionOpenDoor); else - setup_function27(); + setup_killCathAnywhere(); break; case kActionDefault: setCallback(1); - setup_function6(kTime2241000); + setup_lookingForCath(kTime2241000); break; case kActionCallback: @@ -1170,12 +1170,12 @@ IMPLEMENT_FUNCTION(24, Kahina, function24) getProgress().field_44 = 0; - setup_function22(); + setup_finished(); } else if (ENTITY_PARAM(0, 1)) { setCallback(2); setup_savegame(kSavegameTypeEvent, kEventKahinaGunYellow); } else { - setup_function27(); + setup_killCathAnywhere(); } break; @@ -1205,13 +1205,13 @@ IMPLEMENT_FUNCTION(24, Kahina, function24) getProgress().field_44 = 0; - setup_function22(); + setup_finished(); break; } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(25, Kahina, function25) +IMPLEMENT_FUNCTION(25, Kahina, searchCath) switch (savepoint.action) { default: break; @@ -1369,7 +1369,7 @@ IMPLEMENT_FUNCTION(25, Kahina, function25) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(26, Kahina, function26) +IMPLEMENT_FUNCTION(26, Kahina, searchTatiana) switch (savepoint.action) { default: break; @@ -1470,7 +1470,7 @@ IMPLEMENT_FUNCTION(26, Kahina, function26) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(27, Kahina, function27) +IMPLEMENT_FUNCTION(27, Kahina, killCathAnywhere) switch (savepoint.action) { default: break; diff --git a/engines/lastexpress/entities/kahina.h b/engines/lastexpress/entities/kahina.h index ee9ccf5c81..15c446c53d 100644 --- a/engines/lastexpress/entities/kahina.h +++ b/engines/lastexpress/entities/kahina.h @@ -69,7 +69,7 @@ public: */ DECLARE_FUNCTION_NOSETUP(updateFromTicks) - DECLARE_FUNCTION_1(function6, TimeValue timeValue) + DECLARE_FUNCTION_1(lookingForCath, TimeValue timeValue) /** * Updates the entity @@ -105,20 +105,16 @@ public: */ DECLARE_FUNCTION(chapter1Handler) - DECLARE_FUNCTION(function12) - DECLARE_FUNCTION(function13) + DECLARE_FUNCTION(awaitingCath) + DECLARE_FUNCTION(cathDone) DECLARE_FUNCTION(function14) - DECLARE_FUNCTION(function15) + DECLARE_FUNCTION(searchTrain) /** * Setup Chapter 2 */ DECLARE_FUNCTION(chapter2) - - /** - * Handle Chapter 2 events - */ - DECLARE_FUNCTION(chapter2Handler) + DECLARE_FUNCTION(inSeclusionPart2) /** * Setup Chapter 3 @@ -133,18 +129,14 @@ public: */ DECLARE_FUNCTION_2(function19, CarIndex car, EntityPosition entityPosition) - /** - * Handle Chapter 3 events - */ - DECLARE_FUNCTION(chapter3Handler) - - DECLARE_FUNCTION(function21) - DECLARE_FUNCTION(function22) - DECLARE_FUNCTION(function23) - DECLARE_FUNCTION(function24) - DECLARE_FUNCTION(function25) - DECLARE_FUNCTION(function26) - DECLARE_FUNCTION(function27) + DECLARE_FUNCTION(beforeConcert) + DECLARE_FUNCTION(concert) + DECLARE_FUNCTION(finished) + DECLARE_FUNCTION(findFirebird) + DECLARE_FUNCTION(seekCath) + DECLARE_FUNCTION(searchCath) + DECLARE_FUNCTION(searchTatiana) + DECLARE_FUNCTION(killCathAnywhere) /** * Setup Chapter 4 diff --git a/engines/lastexpress/entities/kronos.cpp b/engines/lastexpress/entities/kronos.cpp index 8bf158943b..1fe478fea9 100644 --- a/engines/lastexpress/entities/kronos.cpp +++ b/engines/lastexpress/entities/kronos.cpp @@ -70,21 +70,21 @@ Kronos::Kronos(LastExpressEngine *engine) : Entity(engine, kEntityKronos) { ADD_CALLBACK_FUNCTION(Kronos, updateFromTicks); ADD_CALLBACK_FUNCTION(Kronos, chapter1); ADD_CALLBACK_FUNCTION(Kronos, chapter1Handler); - ADD_CALLBACK_FUNCTION(Kronos, function9); + ADD_CALLBACK_FUNCTION(Kronos, greetCath); ADD_CALLBACK_FUNCTION(Kronos, function10); ADD_CALLBACK_FUNCTION(Kronos, function11); ADD_CALLBACK_FUNCTION(Kronos, chapter2); ADD_CALLBACK_FUNCTION(Kronos, chapter3); ADD_CALLBACK_FUNCTION(Kronos, chapter3Handler); ADD_CALLBACK_FUNCTION(Kronos, function15); - ADD_CALLBACK_FUNCTION(Kronos, function16); - ADD_CALLBACK_FUNCTION(Kronos, function17); - ADD_CALLBACK_FUNCTION(Kronos, function18); - ADD_CALLBACK_FUNCTION(Kronos, function19); - ADD_CALLBACK_FUNCTION(Kronos, function20); - ADD_CALLBACK_FUNCTION(Kronos, function21); - ADD_CALLBACK_FUNCTION(Kronos, function22); - ADD_CALLBACK_FUNCTION(Kronos, function23); + ADD_CALLBACK_FUNCTION(Kronos, visitSalon); + ADD_CALLBACK_FUNCTION(Kronos, returnCompartment); + ADD_CALLBACK_FUNCTION(Kronos, preConcert); + ADD_CALLBACK_FUNCTION(Kronos, startConcert); + ADD_CALLBACK_FUNCTION(Kronos, duringConcert); + ADD_CALLBACK_FUNCTION(Kronos, afterConcert); + ADD_CALLBACK_FUNCTION(Kronos, awaitingCath); + ADD_CALLBACK_FUNCTION(Kronos, finished); ADD_CALLBACK_FUNCTION(Kronos, chapter4); ADD_CALLBACK_FUNCTION(Kronos, chapter5); } @@ -155,13 +155,13 @@ IMPLEMENT_FUNCTION(8, Kronos, chapter1Handler) break; case kAction202621266: - setup_function9(); + setup_greetCath(); break; } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(9, Kronos, function9) +IMPLEMENT_FUNCTION(9, Kronos, greetCath) switch (savepoint.action) { default: break; @@ -294,7 +294,7 @@ IMPLEMENT_FUNCTION(15, Kronos, function15) case kActionNone: if (params->param1 && !getEntities()->isInSalon(kEntityBoutarel)) { if (Entity::updateParameter(params->param2, getState()->timeTicks, 75)) { - setup_function16(); + setup_visitSalon(); break; } } @@ -311,13 +311,13 @@ IMPLEMENT_FUNCTION(15, Kronos, function15) params->param3 = kTimeInvalid; if (getEntities()->isInSalon(kEntityPlayer)) { - setup_function16(); + setup_visitSalon(); } else { getSavePoints()->push(kEntityKronos, kEntityAnna, kAction101169422); getSavePoints()->push(kEntityKronos, kEntityTatiana, kAction101169422); getSavePoints()->push(kEntityKronos, kEntityAbbot, kAction101169422); - setup_function18(); + setup_preConcert(); } } break; @@ -333,7 +333,7 @@ IMPLEMENT_FUNCTION(15, Kronos, function15) case kActionDrawScene: if (params->param1 && getEntities()->isPlayerPosition(kCarRestaurant, 51) && !getEntities()->isInSalon(kEntityBoutarel)) - setup_function16(); + setup_visitSalon(); else params->param1 = getEntities()->isPlayerPosition(kCarRestaurant, 60) || getEntities()->isPlayerPosition(kCarRestaurant, 59) @@ -345,7 +345,7 @@ IMPLEMENT_FUNCTION(15, Kronos, function15) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(16, Kronos, function16) +IMPLEMENT_FUNCTION(16, Kronos, visitSalon) switch (savepoint.action) { default: break; @@ -363,14 +363,14 @@ IMPLEMENT_FUNCTION(16, Kronos, function16) getSavePoints()->push(kEntityKronos, kEntityAbbot, kAction101169422); getScenes()->loadSceneFromPosition(kCarRestaurant, 60); - setup_function17(); + setup_returnCompartment(); } break; } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(17, Kronos, function17) +IMPLEMENT_FUNCTION(17, Kronos, returnCompartment) switch (savepoint.action) { default: break; @@ -386,13 +386,13 @@ IMPLEMENT_FUNCTION(17, Kronos, function17) case kActionCallback: if (getCallback() == 1) - setup_function18(); + setup_preConcert(); break; } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(18, Kronos, function18) +IMPLEMENT_FUNCTION(18, Kronos, preConcert) switch (savepoint.action) { default: break; @@ -405,7 +405,7 @@ IMPLEMENT_FUNCTION(18, Kronos, function18) params->param2 = 1; } - if (!Entity::timeCheck(kTime2106000, params->param3, WRAP_SETUP_FUNCTION(Kronos, setup_function19))) { + if (!Entity::timeCheck(kTime2106000, params->param3, WRAP_SETUP_FUNCTION(Kronos, setup_startConcert))) { if (params->param1 && getEntities()->isInKronosSanctum(kEntityPlayer)) { setCallback(1); setup_savegame(kSavegameTypeEvent, kEventKahinaPunchSuite4); @@ -429,7 +429,7 @@ IMPLEMENT_FUNCTION(18, Kronos, function18) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(19, Kronos, function19) +IMPLEMENT_FUNCTION(19, Kronos, startConcert) switch (savepoint.action) { default: break; @@ -465,7 +465,7 @@ IMPLEMENT_FUNCTION(19, Kronos, function19) RESET_ENTITY_STATE(kEntityAnna, Anna, setup_concert); RESET_ENTITY_STATE(kEntityTatiana, Tatiana, setup_function35); - setup_function20(); + setup_duringConcert(); break; } break; @@ -473,7 +473,7 @@ IMPLEMENT_FUNCTION(19, Kronos, function19) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(20, Kronos, function20) +IMPLEMENT_FUNCTION(20, Kronos, duringConcert) switch (savepoint.action) { default: break; @@ -585,7 +585,7 @@ IMPLEMENT_FUNCTION(20, Kronos, function20) getSound()->playSound(kEntityPlayer, "BUMP"); getScenes()->loadSceneFromPosition(kCarGreenSleeping, 26); - setup_function21(); + setup_afterConcert(); break; } @@ -602,7 +602,7 @@ IMPLEMENT_FUNCTION(20, Kronos, function20) break; } - setup_function21(); + setup_afterConcert(); break; case kActionOpenDoor: @@ -668,7 +668,7 @@ IMPLEMENT_FUNCTION(20, Kronos, function20) getData()->entityPosition = kPosition_6000; getAction()->playAnimation(kEventConcertLeaveWithBriefcase); - RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_function21); + RESET_ENTITY_STATE(kEntityKahina, Kahina, setup_concert); getScenes()->loadSceneFromPosition(kCarKronos, 87); break; @@ -678,7 +678,7 @@ IMPLEMENT_FUNCTION(20, Kronos, function20) getSound()->playSound(kEntityPlayer, "BUMP"); getScenes()->loadSceneFromPosition(kCarGreenSleeping, 26); - setup_function21(); + setup_afterConcert(); break; } break; @@ -686,7 +686,7 @@ IMPLEMENT_FUNCTION(20, Kronos, function20) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(21, Kronos, function21) +IMPLEMENT_FUNCTION(21, Kronos, afterConcert) switch (savepoint.action) { default: break; @@ -703,7 +703,7 @@ IMPLEMENT_FUNCTION(21, Kronos, function21) getObjects()->update(kObjectCompartmentKronos, kEntityPlayer, kObjectLocation3, kCursorNormal, kCursorNormal); getSavePoints()->push(kEntityKronos, kEntityRebecca, kAction191668032); if (!getEvent(kEventConcertLeaveWithBriefcase)) - setup_function22(); + setup_awaitingCath(); break; case kActionCallback: @@ -722,13 +722,13 @@ IMPLEMENT_FUNCTION(21, Kronos, function21) break; case kAction235599361: - setup_function22(); + setup_awaitingCath(); break; } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(22, Kronos, function22) +IMPLEMENT_FUNCTION(22, Kronos, awaitingCath) switch (savepoint.action) { default: break; @@ -791,7 +791,7 @@ IMPLEMENT_FUNCTION(22, Kronos, function22) getInventory()->removeItem(kItemFirebird); getInventory()->removeItem(kItemScarf); - setup_function23(); + setup_finished(); break; case 2: @@ -800,7 +800,7 @@ IMPLEMENT_FUNCTION(22, Kronos, function22) getInventory()->removeItem(kItemFirebird); getInventory()->get(kItemFirebird)->location = kObjectLocation5; - setup_function23(); + setup_finished(); break; case 3: @@ -809,7 +809,7 @@ IMPLEMENT_FUNCTION(22, Kronos, function22) getAction()->playAnimation(kEventKronosBringEgg); getScenes()->loadSceneFromPosition(kCarKronos, 87); getInventory()->addItem(kItemBriefcase); - setup_function23(); + setup_finished(); break; case 4: @@ -835,12 +835,12 @@ IMPLEMENT_FUNCTION(22, Kronos, function22) break; case kAction138085344: - setup_function23(); + setup_finished(); } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(23, Kronos, function23) +IMPLEMENT_FUNCTION(23, Kronos, finished) switch (savepoint.action) { default: break; diff --git a/engines/lastexpress/entities/kronos.h b/engines/lastexpress/entities/kronos.h index 48da419a6e..00564b8ce5 100644 --- a/engines/lastexpress/entities/kronos.h +++ b/engines/lastexpress/entities/kronos.h @@ -89,7 +89,7 @@ public: */ DECLARE_FUNCTION(chapter1Handler) - DECLARE_FUNCTION(function9) + DECLARE_FUNCTION(greetCath) DECLARE_FUNCTION(function10) DECLARE_FUNCTION(function11) @@ -109,14 +109,14 @@ public: DECLARE_FUNCTION(chapter3Handler) DECLARE_FUNCTION(function15) - DECLARE_FUNCTION(function16) - DECLARE_FUNCTION(function17) - DECLARE_FUNCTION(function18) - DECLARE_FUNCTION(function19) - DECLARE_FUNCTION(function20) - DECLARE_FUNCTION(function21) - DECLARE_FUNCTION(function22) - DECLARE_FUNCTION(function23) + DECLARE_FUNCTION(visitSalon) + DECLARE_FUNCTION(returnCompartment) + DECLARE_FUNCTION(preConcert) + DECLARE_FUNCTION(startConcert) + DECLARE_FUNCTION(duringConcert) + DECLARE_FUNCTION(afterConcert) + DECLARE_FUNCTION(awaitingCath) + DECLARE_FUNCTION(finished) /** * Setup Chapter 4 diff --git a/engines/lastexpress/entities/max.cpp b/engines/lastexpress/entities/max.cpp index 1056e7fd7a..d75b6af7f5 100644 --- a/engines/lastexpress/entities/max.cpp +++ b/engines/lastexpress/entities/max.cpp @@ -42,16 +42,16 @@ Max::Max(LastExpressEngine *engine) : Entity(engine, kEntityMax) { ADD_CALLBACK_FUNCTION(Max, draw); ADD_CALLBACK_FUNCTION(Max, enterExitCompartment); ADD_CALLBACK_FUNCTION(Max, savegame); - ADD_CALLBACK_FUNCTION(Max, chapter12_handler); - ADD_CALLBACK_FUNCTION(Max, function7); - ADD_CALLBACK_FUNCTION(Max, chapter4Handler); + ADD_CALLBACK_FUNCTION(Max, withAnna); + ADD_CALLBACK_FUNCTION(Max, guardingCompartment); + ADD_CALLBACK_FUNCTION(Max, inCageFriendly); ADD_CALLBACK_FUNCTION(Max, function9); ADD_CALLBACK_FUNCTION(Max, chapter1); ADD_CALLBACK_FUNCTION(Max, chapter2); ADD_CALLBACK_FUNCTION(Max, chapter3); ADD_CALLBACK_FUNCTION(Max, chapter3Handler); - ADD_CALLBACK_FUNCTION(Max, freeFromCage); - ADD_CALLBACK_FUNCTION(Max, function15); + ADD_CALLBACK_FUNCTION(Max, inCageMad); + ADD_CALLBACK_FUNCTION(Max, letMeIn); ADD_CALLBACK_FUNCTION(Max, chapter4); ADD_CALLBACK_FUNCTION(Max, function17); ADD_CALLBACK_FUNCTION(Max, chapter5); @@ -83,7 +83,7 @@ IMPLEMENT_FUNCTION_II(5, Max, savegame, SavegameType, uint32) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(6, Max, chapter12_handler) +IMPLEMENT_FUNCTION(6, Max, withAnna) switch (savepoint.action) { default: break; @@ -105,7 +105,7 @@ IMPLEMENT_FUNCTION(6, Max, chapter12_handler) case kAction71277948: setCallback(1); - setup_function7(); + setup_guardingCompartment(); break; case kAction158007856: @@ -118,7 +118,7 @@ IMPLEMENT_FUNCTION(6, Max, chapter12_handler) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(7, Max, function7) +IMPLEMENT_FUNCTION(7, Max, guardingCompartment) switch (savepoint.action) { default: break; @@ -208,7 +208,7 @@ IMPLEMENT_FUNCTION(7, Max, function7) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(8, Max, chapter4Handler) +IMPLEMENT_FUNCTION(8, Max, inCageFriendly) switch (savepoint.action) { default: break; @@ -296,7 +296,7 @@ IMPLEMENT_FUNCTION(9, Max, function9) setup_functions: if (getProgress().chapter == kChapter3) - setup_function15(); + setup_letMeIn(); if (getProgress().chapter == kChapter4) setup_function17(); @@ -324,7 +324,7 @@ IMPLEMENT_FUNCTION(10, Max, chapter1) break; case kActionNone: - Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Max, setup_chapter12_handler)); + Entity::timeCheck(kTimeChapter1, params->param1, WRAP_SETUP_FUNCTION(Max, setup_withAnna)); break; case kActionDefault: @@ -343,7 +343,7 @@ IMPLEMENT_FUNCTION(11, Max, chapter2) break; case kActionNone: - setup_chapter12_handler(); + setup_withAnna(); break; case kActionDefault: @@ -413,7 +413,7 @@ IMPLEMENT_FUNCTION(13, Max, chapter3Handler) case kAction71277948: setCallback(1); - setup_function7(); + setup_guardingCompartment(); break; case kAction122358304: @@ -421,7 +421,7 @@ IMPLEMENT_FUNCTION(13, Max, chapter3Handler) break; case kActionMaxFreeFromCage: - setup_freeFromCage(); + setup_inCageMad(); break; case kAction158007856: @@ -437,7 +437,7 @@ IMPLEMENT_FUNCTION(13, Max, chapter3Handler) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(14, Max, freeFromCage) +IMPLEMENT_FUNCTION(14, Max, inCageMad) switch (savepoint.action) { default: break; @@ -504,7 +504,7 @@ IMPLEMENT_FUNCTION(14, Max, freeFromCage) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(15, Max, function15) +IMPLEMENT_FUNCTION(15, Max, letMeIn) switch (savepoint.action) { default: break; @@ -551,7 +551,7 @@ IMPLEMENT_FUNCTION(15, Max, function15) case kActionMaxFreeFromCage: getEntities()->exitCompartment(kEntityMax, kObjectCompartmentF, true); - setup_chapter4Handler(); + setup_inCageFriendly(); break; } IMPLEMENT_FUNCTION_END @@ -563,7 +563,7 @@ IMPLEMENT_FUNCTION(16, Max, chapter4) break; case kActionNone: - setup_chapter4Handler(); + setup_inCageFriendly(); break; case kActionDefault: @@ -606,7 +606,7 @@ IMPLEMENT_FUNCTION(17, Max, function17) case kActionMaxFreeFromCage: getEntities()->exitCompartment(kEntityMax, kObjectCompartmentF, true); - setup_chapter4Handler(); + setup_inCageFriendly(); break; } IMPLEMENT_FUNCTION_END diff --git a/engines/lastexpress/entities/max.h b/engines/lastexpress/entities/max.h index 7b7780742b..e12b4b6dad 100644 --- a/engines/lastexpress/entities/max.h +++ b/engines/lastexpress/entities/max.h @@ -70,18 +70,9 @@ public: */ DECLARE_FUNCTION_2(savegame, SavegameType savegameType, uint32 param) - /** - * Handle Chapter 1 & 2 events - */ - DECLARE_FUNCTION(chapter12_handler) - - DECLARE_FUNCTION(function7) - - /** - * Handle Chapter 4 events - */ - DECLARE_FUNCTION(chapter4Handler) - + DECLARE_FUNCTION(withAnna) + DECLARE_FUNCTION(guardingCompartment) + DECLARE_FUNCTION(inCageFriendly) DECLARE_FUNCTION(function9) /** @@ -104,8 +95,8 @@ public: */ DECLARE_FUNCTION(chapter3Handler) - DECLARE_FUNCTION(freeFromCage) - DECLARE_FUNCTION(function15) + DECLARE_FUNCTION(inCageMad) + DECLARE_FUNCTION(letMeIn) /** * Setup Chapter 4 diff --git a/engines/lastexpress/entities/milos.cpp b/engines/lastexpress/entities/milos.cpp index 601187b672..90a397c7cb 100644 --- a/engines/lastexpress/entities/milos.cpp +++ b/engines/lastexpress/entities/milos.cpp @@ -722,7 +722,7 @@ IMPLEMENT_FUNCTION(15, Milos, chapter1Handler) break; case kActionNone: - Entity::timeCheckSavepoint(kTime1071000, params->param3, kEntityMilos, kEntityServers1, kAction223002560); + Entity::timeCheckSavepoint(kTime1071000, params->param3, kEntityMilos, kEntityWaiter2, kAction223002560); if (getState()->time > kTime1089000 && getEntities()->isSomebodyInsideRestaurantOrSalon()) { setup_function16(); @@ -801,7 +801,7 @@ IMPLEMENT_FUNCTION(16, Milos, function16) break; case 1: - getSavePoints()->push(kEntityMilos, kEntityServers1, kAction269485588); + getSavePoints()->push(kEntityMilos, kEntityWaiter2, kAction269485588); getSavePoints()->push(kEntityMilos, kEntityIvo, kAction125242096); getEntities()->drawSequenceRight(kEntityMilos, "807DS"); if (getEntities()->isInRestaurant(kEntityPlayer)) diff --git a/engines/lastexpress/entities/pascale.cpp b/engines/lastexpress/entities/pascale.cpp index b6356a0acb..24b7f0409b 100644 --- a/engines/lastexpress/entities/pascale.cpp +++ b/engines/lastexpress/entities/pascale.cpp @@ -46,29 +46,29 @@ Pascale::Pascale(LastExpressEngine *engine) : Entity(engine, kEntityPascale) { ADD_CALLBACK_FUNCTION(Pascale, welcomeSophieAndRebecca); ADD_CALLBACK_FUNCTION(Pascale, sitSophieAndRebecca); ADD_CALLBACK_FUNCTION(Pascale, welcomeCath); - ADD_CALLBACK_FUNCTION(Pascale, function11); + ADD_CALLBACK_FUNCTION(Pascale, seatCath); ADD_CALLBACK_FUNCTION(Pascale, chapter1); - ADD_CALLBACK_FUNCTION(Pascale, getMessageFromAugustToTyler); - ADD_CALLBACK_FUNCTION(Pascale, sitAnna); - ADD_CALLBACK_FUNCTION(Pascale, welcomeAnna); - ADD_CALLBACK_FUNCTION(Pascale, serveTatianaVassili); - ADD_CALLBACK_FUNCTION(Pascale, chapter1Handler); + ADD_CALLBACK_FUNCTION(Pascale, greetAugust); + ADD_CALLBACK_FUNCTION(Pascale, seatAnna); + ADD_CALLBACK_FUNCTION(Pascale, greetAnna); + ADD_CALLBACK_FUNCTION(Pascale, greetTatiana); + ADD_CALLBACK_FUNCTION(Pascale, servingDinner); ADD_CALLBACK_FUNCTION(Pascale, function18); ADD_CALLBACK_FUNCTION(Pascale, function19); ADD_CALLBACK_FUNCTION(Pascale, chapter2); ADD_CALLBACK_FUNCTION(Pascale, chapter3); ADD_CALLBACK_FUNCTION(Pascale, chapter3Handler); - ADD_CALLBACK_FUNCTION(Pascale, function23); + ADD_CALLBACK_FUNCTION(Pascale, abbotSeatMe3); ADD_CALLBACK_FUNCTION(Pascale, welcomeAbbot); ADD_CALLBACK_FUNCTION(Pascale, chapter4); ADD_CALLBACK_FUNCTION(Pascale, chapter4Handler); - ADD_CALLBACK_FUNCTION(Pascale, function27); - ADD_CALLBACK_FUNCTION(Pascale, messageFromAnna); - ADD_CALLBACK_FUNCTION(Pascale, function29); - ADD_CALLBACK_FUNCTION(Pascale, function30); + ADD_CALLBACK_FUNCTION(Pascale, meetCoudert); + ADD_CALLBACK_FUNCTION(Pascale, tellAugust); + ADD_CALLBACK_FUNCTION(Pascale, walkDownTrain); + ADD_CALLBACK_FUNCTION(Pascale, walkUpTrain); ADD_CALLBACK_FUNCTION(Pascale, chapter5); ADD_CALLBACK_FUNCTION(Pascale, chapter5Handler); - ADD_CALLBACK_FUNCTION(Pascale, function33); + ADD_CALLBACK_FUNCTION(Pascale, hiding); ADD_NULL_FUNCTION(); } @@ -118,6 +118,7 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(8, Pascale, welcomeSophieAndRebecca) + // Welcomes Sophie And Rebecca switch (savepoint.action) { default: break; @@ -244,7 +245,7 @@ IMPLEMENT_FUNCTION(10, Pascale, welcomeCath) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(11, Pascale, function11) +IMPLEMENT_FUNCTION(11, Pascale, seatCath) switch (savepoint.action) { default: break; @@ -295,7 +296,7 @@ IMPLEMENT_FUNCTION(12, Pascale, chapter1) break; case kActionNone: - setup_chapter1Handler(); + setup_servingDinner(); break; case kActionDefault: @@ -319,7 +320,7 @@ IMPLEMENT_FUNCTION(12, Pascale, chapter1) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(13, Pascale, getMessageFromAugustToTyler) +IMPLEMENT_FUNCTION(13, Pascale, greetAugust) switch (savepoint.action) { default: break; @@ -372,7 +373,7 @@ IMPLEMENT_FUNCTION(13, Pascale, getMessageFromAugustToTyler) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(14, Pascale, sitAnna) +IMPLEMENT_FUNCTION(14, Pascale, seatAnna) switch (savepoint.action) { default: break; @@ -394,7 +395,7 @@ IMPLEMENT_FUNCTION(14, Pascale, sitAnna) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(15, Pascale, welcomeAnna) +IMPLEMENT_FUNCTION(15, Pascale, greetAnna) switch (savepoint.action) { default: break; @@ -416,7 +417,7 @@ IMPLEMENT_FUNCTION(15, Pascale, welcomeAnna) getSound()->playSound(kEntityPascale, "ANN1047"); setCallback(2); - setup_sitAnna(); + setup_seatAnna(); break; case 2: @@ -439,7 +440,7 @@ IMPLEMENT_FUNCTION(15, Pascale, welcomeAnna) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(16, Pascale, serveTatianaVassili) +IMPLEMENT_FUNCTION(16, Pascale, greetTatiana) switch (savepoint.action) { default: break; @@ -492,7 +493,7 @@ IMPLEMENT_FUNCTION(16, Pascale, serveTatianaVassili) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(17, Pascale, chapter1Handler) +IMPLEMENT_FUNCTION(17, Pascale, servingDinner) switch (savepoint.action) { default: break; @@ -521,28 +522,28 @@ switch (savepoint.action) { if (params->param1 && !params->param2 && getEntities()->isPlayerPosition(kCarRestaurant, 61)) { setCallback(1); - setup_function11(); + setup_seatCath(); break; } label_callback1: if (ENTITY_PARAM(0, 1) && !ENTITY_PARAM(1, 3)) { setCallback(2); - setup_getMessageFromAugustToTyler(); + setup_greetAugust(); break; } label_callback2: if (ENTITY_PARAM(0, 3)) { setCallback(3); - setup_serveTatianaVassili(); + setup_greetTatiana(); break; } label_callback3: if (ENTITY_PARAM(0, 2)) { setCallback(4); - setup_welcomeAnna(); + setup_greetAnna(); break; } @@ -584,8 +585,8 @@ IMPLEMENT_FUNCTION(18, Pascale, function18) if (getState()->time > kTime1242000 && !params->param1) { params->param1 = 1; - getSavePoints()->push(kEntityPascale, kEntityServers0, kAction101632192); - getSavePoints()->push(kEntityPascale, kEntityServers1, kAction101632192); + getSavePoints()->push(kEntityPascale, kEntityWaiter1, kAction101632192); + getSavePoints()->push(kEntityPascale, kEntityWaiter2, kAction101632192); getSavePoints()->push(kEntityPascale, kEntityCooks, kAction101632192); getSavePoints()->push(kEntityPascale, kEntityVerges, kAction101632192); @@ -674,7 +675,7 @@ IMPLEMENT_FUNCTION(22, Pascale, chapter3Handler) if (ENTITY_PARAM(0, 7)) { setCallback(1); - setup_function23(); + setup_abbotSeatMe3(); break; } @@ -693,7 +694,7 @@ label_callback: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(23, Pascale, function23) +IMPLEMENT_FUNCTION(23, Pascale, abbotSeatMe3) switch (savepoint.action) { default: break; @@ -806,7 +807,7 @@ IMPLEMENT_FUNCTION(26, Pascale, chapter4Handler) if (getEntities()->isSomebodyInsideRestaurantOrSalon()) { if (ENTITY_PARAM(0, 8)) { setCallback(1); - setup_function27(); + setup_meetCoudert(); break; } @@ -820,7 +821,7 @@ label_callback1: if (params->param3 < getState()->time) { params->param5 = kTimeInvalid; setCallback(2); - setup_messageFromAnna(); + setup_tellAugust(); break; } @@ -830,7 +831,7 @@ label_callback1: if (params->param5 < getState()->time) { params->param5 = kTimeInvalid; setCallback(2); - setup_messageFromAnna(); + setup_tellAugust(); break; } } @@ -839,7 +840,7 @@ label_callback1: label_callback2: if (params->param1 && !params->param2 && getEntities()->isPlayerPosition(kCarRestaurant, 61)) { setCallback(3); - setup_function11(); + setup_seatCath(); break; } } @@ -906,7 +907,7 @@ label_callback3: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(27, Pascale, function27) +IMPLEMENT_FUNCTION(27, Pascale, meetCoudert) switch (savepoint.action) { default: break; @@ -920,7 +921,7 @@ IMPLEMENT_FUNCTION(27, Pascale, function27) case kActionDefault: setCallback(1); - setup_function29(); + setup_walkDownTrain(); break; case kActionCallback: @@ -941,7 +942,7 @@ IMPLEMENT_FUNCTION(27, Pascale, function27) case 3: setCallback(4); - setup_function30(); + setup_walkUpTrain(); break; case 4: @@ -959,7 +960,8 @@ IMPLEMENT_FUNCTION(27, Pascale, function27) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(28, Pascale, messageFromAnna) +IMPLEMENT_FUNCTION(28, Pascale, tellAugust) + // Tell August the message from Anna switch (savepoint.action) { default: break; @@ -1005,7 +1007,7 @@ IMPLEMENT_FUNCTION(28, Pascale, messageFromAnna) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(29, Pascale, function29) +IMPLEMENT_FUNCTION(29, Pascale, walkDownTrain) switch (savepoint.action) { default: break; @@ -1043,7 +1045,7 @@ IMPLEMENT_FUNCTION(29, Pascale, function29) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(30, Pascale, function30) +IMPLEMENT_FUNCTION(30, Pascale, walkUpTrain) switch (savepoint.action) { default: break; @@ -1104,11 +1106,11 @@ IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// IMPLEMENT_FUNCTION(32, Pascale, chapter5Handler) if (savepoint.action == kActionProceedChapter5) - setup_function33(); + setup_hiding(); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(33, Pascale, function33) +IMPLEMENT_FUNCTION(33, Pascale, hiding) switch (savepoint.action) { default: break; diff --git a/engines/lastexpress/entities/pascale.h b/engines/lastexpress/entities/pascale.h index 1b7777dec9..c8df7587ae 100644 --- a/engines/lastexpress/entities/pascale.h +++ b/engines/lastexpress/entities/pascale.h @@ -88,22 +88,22 @@ public: DECLARE_FUNCTION(welcomeSophieAndRebecca) DECLARE_FUNCTION(sitSophieAndRebecca) DECLARE_FUNCTION(welcomeCath) - DECLARE_FUNCTION(function11) + DECLARE_FUNCTION(seatCath) /** * Setup Chapter 1 */ DECLARE_FUNCTION(chapter1) - DECLARE_FUNCTION(getMessageFromAugustToTyler) - DECLARE_FUNCTION(sitAnna) - DECLARE_FUNCTION(welcomeAnna) - DECLARE_FUNCTION(serveTatianaVassili) + DECLARE_FUNCTION(greetAugust) + DECLARE_FUNCTION(seatAnna) + DECLARE_FUNCTION(greetAnna) + DECLARE_FUNCTION(greetTatiana) /** * Handle Chapter 1 events */ - DECLARE_FUNCTION(chapter1Handler) + DECLARE_FUNCTION(servingDinner) DECLARE_FUNCTION(function18) DECLARE_FUNCTION(function19) @@ -123,7 +123,7 @@ public: */ DECLARE_FUNCTION(chapter3Handler) - DECLARE_FUNCTION(function23) + DECLARE_FUNCTION(abbotSeatMe3) DECLARE_FUNCTION(welcomeAbbot) /** @@ -136,10 +136,10 @@ public: */ DECLARE_FUNCTION(chapter4Handler) - DECLARE_FUNCTION(function27) - DECLARE_FUNCTION(messageFromAnna) - DECLARE_FUNCTION(function29) - DECLARE_FUNCTION(function30) + DECLARE_FUNCTION(meetCoudert) + DECLARE_FUNCTION(tellAugust) + DECLARE_FUNCTION(walkDownTrain) + DECLARE_FUNCTION(walkUpTrain) /** * Setup Chapter 5 @@ -151,7 +151,7 @@ public: */ DECLARE_FUNCTION(chapter5Handler) - DECLARE_FUNCTION(function33) + DECLARE_FUNCTION(hiding) DECLARE_NULL_FUNCTION() }; diff --git a/engines/lastexpress/entities/rebecca.cpp b/engines/lastexpress/entities/rebecca.cpp index 05211663bd..40175ad8c4 100644 --- a/engines/lastexpress/entities/rebecca.cpp +++ b/engines/lastexpress/entities/rebecca.cpp @@ -437,7 +437,7 @@ IMPLEMENT_FUNCTION(19, Rebecca, function19) break; case 2: - getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction337548856); + getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction337548856); getEntities()->drawSequenceRight(kEntityRebecca, "810DS"); if (getEntities()->isInRestaurant(kEntityPlayer)) getEntities()->updateFrame(kEntityRebecca); @@ -850,7 +850,7 @@ IMPLEMENT_FUNCTION(24, Rebecca, function24) break; case kActionNone: - Entity::timeCheckSavepoint(kTime1134000, params->param2, kEntityRebecca, kEntityServers0, kAction223712416); + Entity::timeCheckSavepoint(kTime1134000, params->param2, kEntityRebecca, kEntityWaiter1, kAction223712416); if (!params->param1) break; @@ -920,7 +920,7 @@ IMPLEMENT_FUNCTION(24, Rebecca, function24) break; case 8: - getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction136702400); + getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction136702400); getEntities()->drawSequenceLeft(kEntityRebecca, "012G"); params->param1 = 1; break; @@ -928,7 +928,7 @@ IMPLEMENT_FUNCTION(24, Rebecca, function24) break; case kAction123712592: - getEntities()->drawSequenceLeft(kEntityServers0, "BLANK"); + getEntities()->drawSequenceLeft(kEntityWaiter1, "BLANK"); getEntities()->drawSequenceLeft(kEntityRebecca, "012E"); setCallback(8); @@ -1244,7 +1244,7 @@ IMPLEMENT_FUNCTION(34, Rebecca, function34) params->param2 = kTimeInvalid; - getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction223712416); + getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction223712416); } Entity::timeCheckCallback(kTime2052000, params->param3, 1, WRAP_SETUP_FUNCTION(Rebecca, setup_function19)); @@ -1280,7 +1280,7 @@ IMPLEMENT_FUNCTION(34, Rebecca, function34) break; case 4: - getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction136702400); + getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction136702400); getEntities()->drawSequenceLeft(kEntityRebecca, "012G"); params->param1 = 1; break; @@ -1288,7 +1288,7 @@ IMPLEMENT_FUNCTION(34, Rebecca, function34) break; case kAction123712592: - getEntities()->drawSequenceLeft(kEntityServers0, "BLANK"); + getEntities()->drawSequenceLeft(kEntityWaiter1, "BLANK"); getSound()->playSound(kEntityRebecca, "Reb3003"); setCallback(4); @@ -1624,7 +1624,7 @@ IMPLEMENT_FUNCTION(44, Rebecca, function44) params->param3 = kTimeInvalid; - getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction223712416); + getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction223712416); } label_next: @@ -1684,7 +1684,7 @@ label_callback_2: break; case 4: - getSavePoints()->push(kEntityRebecca, kEntityServers0, kAction136702400); + getSavePoints()->push(kEntityRebecca, kEntityWaiter1, kAction136702400); getEntities()->drawSequenceLeft(kEntityRebecca, "012G"); params->param2 = 1; break; diff --git a/engines/lastexpress/entities/tatiana.cpp b/engines/lastexpress/entities/tatiana.cpp index c6788fd4b2..951e89d595 100644 --- a/engines/lastexpress/entities/tatiana.cpp +++ b/engines/lastexpress/entities/tatiana.cpp @@ -507,7 +507,7 @@ IMPLEMENT_FUNCTION(20, Tatiana, function20) case 2: getEntities()->updatePositionExit(kEntityTatiana, kCarRestaurant, 67); - getSavePoints()->push(kEntityTatiana, kEntityServers0, kAction188893625); + getSavePoints()->push(kEntityTatiana, kEntityWaiter1, kAction188893625); setCallback(3); setup_function18(); @@ -917,7 +917,7 @@ IMPLEMENT_FUNCTION(29, Tatiana, function29) case 2: getEntities()->updatePositionExit(kEntityTatiana, kCarRestaurant, 63); - getSavePoints()->push(kEntityTatiana, kEntityServers1, kAction302203328); + getSavePoints()->push(kEntityTatiana, kEntityWaiter2, kAction302203328); getEntities()->drawSequenceRight(kEntityTatiana, "805DS"); if (getEntities()->isInRestaurant(kEntityPlayer)) diff --git a/engines/lastexpress/entities/servers0.cpp b/engines/lastexpress/entities/waiter1.cpp index 590efa7157..80ec471f1b 100644 --- a/engines/lastexpress/entities/servers0.cpp +++ b/engines/lastexpress/entities/waiter1.cpp @@ -20,7 +20,7 @@ * */ -#include "lastexpress/entities/servers0.h" +#include "lastexpress/entities/waiter1.h" #include "lastexpress/game/entities.h" #include "lastexpress/game/logic.h" @@ -39,69 +39,69 @@ namespace LastExpress { break; \ } -Servers0::Servers0(LastExpressEngine *engine) : Entity(engine, kEntityServers0) { - ADD_CALLBACK_FUNCTION(Servers0, callSavepoint); - ADD_CALLBACK_FUNCTION(Servers0, updateFromTime); - ADD_CALLBACK_FUNCTION(Servers0, draw); - ADD_CALLBACK_FUNCTION(Servers0, updatePosition); - ADD_CALLBACK_FUNCTION(Servers0, callbackActionOnDirection); - ADD_CALLBACK_FUNCTION(Servers0, playSound); - ADD_CALLBACK_FUNCTION(Servers0, function7); - ADD_CALLBACK_FUNCTION(Servers0, function8); - ADD_CALLBACK_FUNCTION(Servers0, function9); - ADD_CALLBACK_FUNCTION(Servers0, function10); - ADD_CALLBACK_FUNCTION(Servers0, chapter1); - ADD_CALLBACK_FUNCTION(Servers0, function12); - ADD_CALLBACK_FUNCTION(Servers0, function13); - ADD_CALLBACK_FUNCTION(Servers0, function14); - ADD_CALLBACK_FUNCTION(Servers0, function15); - ADD_CALLBACK_FUNCTION(Servers0, function16); - ADD_CALLBACK_FUNCTION(Servers0, function17); - ADD_CALLBACK_FUNCTION(Servers0, function18); - ADD_CALLBACK_FUNCTION(Servers0, function19); - ADD_CALLBACK_FUNCTION(Servers0, chapter1Handler); - ADD_CALLBACK_FUNCTION(Servers0, function21); - ADD_CALLBACK_FUNCTION(Servers0, function22); - ADD_CALLBACK_FUNCTION(Servers0, chapter2); - ADD_CALLBACK_FUNCTION(Servers0, chapter2Handler); - ADD_CALLBACK_FUNCTION(Servers0, function25); - ADD_CALLBACK_FUNCTION(Servers0, function26); - ADD_CALLBACK_FUNCTION(Servers0, chapter3); - ADD_CALLBACK_FUNCTION(Servers0, chapter3Handler); - ADD_CALLBACK_FUNCTION(Servers0, augustAnnaDateOrder); - ADD_CALLBACK_FUNCTION(Servers0, function30); - ADD_CALLBACK_FUNCTION(Servers0, chapter4); - ADD_CALLBACK_FUNCTION(Servers0, chapter4Handler); - ADD_CALLBACK_FUNCTION(Servers0, augustOrderSteak); - ADD_CALLBACK_FUNCTION(Servers0, augustServeDuck); - ADD_CALLBACK_FUNCTION(Servers0, function35); - ADD_CALLBACK_FUNCTION(Servers0, chapter5); - ADD_CALLBACK_FUNCTION(Servers0, chapter5Handler); +Waiter1::Waiter1(LastExpressEngine *engine) : Entity(engine, kEntityWaiter1) { + ADD_CALLBACK_FUNCTION(Waiter1, callSavepoint); + ADD_CALLBACK_FUNCTION(Waiter1, updateFromTime); + ADD_CALLBACK_FUNCTION(Waiter1, draw); + ADD_CALLBACK_FUNCTION(Waiter1, updatePosition); + ADD_CALLBACK_FUNCTION(Waiter1, callbackActionOnDirection); + ADD_CALLBACK_FUNCTION(Waiter1, playSound); + ADD_CALLBACK_FUNCTION(Waiter1, rebeccaFeedUs); + ADD_CALLBACK_FUNCTION(Waiter1, rebeccaClearOurTable); + ADD_CALLBACK_FUNCTION(Waiter1, abbotCheckMe); + ADD_CALLBACK_FUNCTION(Waiter1, abbotClearTable); + ADD_CALLBACK_FUNCTION(Waiter1, chapter1); + ADD_CALLBACK_FUNCTION(Waiter1, annaOrder); + ADD_CALLBACK_FUNCTION(Waiter1, augustOrder); + ADD_CALLBACK_FUNCTION(Waiter1, serveAnna); + ADD_CALLBACK_FUNCTION(Waiter1, serveAugust); + ADD_CALLBACK_FUNCTION(Waiter1, clearAnna); + ADD_CALLBACK_FUNCTION(Waiter1, clearTatiana); + ADD_CALLBACK_FUNCTION(Waiter1, clearAugust1); + ADD_CALLBACK_FUNCTION(Waiter1, clearAugust2); + ADD_CALLBACK_FUNCTION(Waiter1, servingDinner); + ADD_CALLBACK_FUNCTION(Waiter1, function21); + ADD_CALLBACK_FUNCTION(Waiter1, function22); + ADD_CALLBACK_FUNCTION(Waiter1, chapter2); + ADD_CALLBACK_FUNCTION(Waiter1, inKitchen); + ADD_CALLBACK_FUNCTION(Waiter1, augustComeHere2); + ADD_CALLBACK_FUNCTION(Waiter1, augustClearTable2); + ADD_CALLBACK_FUNCTION(Waiter1, chapter3); + ADD_CALLBACK_FUNCTION(Waiter1, serving3); + ADD_CALLBACK_FUNCTION(Waiter1, annaComeHere3); + ADD_CALLBACK_FUNCTION(Waiter1, abbotServeLunch3); + ADD_CALLBACK_FUNCTION(Waiter1, chapter4); + ADD_CALLBACK_FUNCTION(Waiter1, serving4); + ADD_CALLBACK_FUNCTION(Waiter1, augustOrder4); + ADD_CALLBACK_FUNCTION(Waiter1, serveAugust4); + ADD_CALLBACK_FUNCTION(Waiter1, augustClearTable); + ADD_CALLBACK_FUNCTION(Waiter1, chapter5); + ADD_CALLBACK_FUNCTION(Waiter1, chapter5Handler); ADD_NULL_FUNCTION(); } ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_SIIS(1, Servers0, callSavepoint, EntityIndex, ActionIndex) +IMPLEMENT_FUNCTION_SIIS(1, Waiter1, callSavepoint, EntityIndex, ActionIndex) Entity::callSavepoint(savepoint, true); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_NOSETUP(2, Servers0, updateFromTime) +IMPLEMENT_FUNCTION_NOSETUP(2, Waiter1, updateFromTime) Entity::updateFromTime(savepoint); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_S(3, Servers0, draw) +IMPLEMENT_FUNCTION_S(3, Waiter1, draw) Entity::draw(savepoint, true); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_NOSETUP(4, Servers0, updatePosition) +IMPLEMENT_FUNCTION_NOSETUP(4, Waiter1, updatePosition) Entity::updatePosition(savepoint, true); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_NOSETUP(5, Servers0, callbackActionOnDirection) +IMPLEMENT_FUNCTION_NOSETUP(5, Waiter1, callbackActionOnDirection) EXPOSE_PARAMS(EntityData::EntityParametersIIII); switch (savepoint.action) { @@ -119,7 +119,7 @@ IMPLEMENT_FUNCTION_NOSETUP(5, Servers0, callbackActionOnDirection) case kActionExcuseMeCath: if (!params->param1) { - getSound()->excuseMe(kEntityServers0); + getSound()->excuseMe(kEntityWaiter1); params->param1 = 1; } break; @@ -127,12 +127,12 @@ IMPLEMENT_FUNCTION_NOSETUP(5, Servers0, callbackActionOnDirection) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_S(6, Servers0, playSound) +IMPLEMENT_FUNCTION_S(6, Waiter1, playSound) Entity::playSound(savepoint); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(7, Servers0, function7) +IMPLEMENT_FUNCTION(7, Waiter1, rebeccaFeedUs) switch (savepoint.action) { default: break; @@ -153,12 +153,12 @@ IMPLEMENT_FUNCTION(7, Servers0, function7) break; case 1: - getEntities()->clearSequences(kEntityServers0); - getSavePoints()->push(kEntityServers0, kEntityRebecca, kAction123712592); + getEntities()->clearSequences(kEntityWaiter1); + getSavePoints()->push(kEntityWaiter1, kEntityRebecca, kAction123712592); break; case 2: - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); getData()->entityPosition = kPosition_5900; callbackAction(); break; @@ -173,12 +173,12 @@ IMPLEMENT_FUNCTION(7, Servers0, function7) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(8, Servers0, function8) +IMPLEMENT_FUNCTION(8, Waiter1, rebeccaClearOurTable) serveTable(savepoint, "911", kEntityTables3, "010L", "010M", "913", &ENTITY_PARAM(1, 2)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(9, Servers0, function9) +IMPLEMENT_FUNCTION(9, Waiter1, abbotCheckMe) switch (savepoint.action) { default: break; @@ -197,15 +197,15 @@ IMPLEMENT_FUNCTION(9, Servers0, function9) break; case 1: - getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122358304); - getEntities()->drawSequenceLeft(kEntityServers0, "029D"); + getSavePoints()->push(kEntityWaiter1, kEntityAbbot, kAction122358304); + getEntities()->drawSequenceLeft(kEntityWaiter1, "029D"); setCallback(2); setup_playSound(getProgress().chapter == kChapter3 ? "Abb3016" : "Abb4001"); break; case 2: - getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122288808); + getSavePoints()->push(kEntityWaiter1, kEntityAbbot, kAction122288808); setCallback(3); setup_draw("917"); @@ -213,7 +213,7 @@ IMPLEMENT_FUNCTION(9, Servers0, function9) case 3: getData()->entityPosition = kPosition_5900; - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); ENTITY_PARAM(2, 2) = 0; ENTITY_PARAM(1, 6) = 0; @@ -225,37 +225,37 @@ IMPLEMENT_FUNCTION(9, Servers0, function9) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(10, Servers0, function10) +IMPLEMENT_FUNCTION(10, Waiter1, abbotClearTable) serveTable(savepoint, "916", kEntityTables4, "014E", "014F", "918", &ENTITY_PARAM(2, 3), false); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(11, Servers0, chapter1) +IMPLEMENT_FUNCTION(11, Waiter1, chapter1) switch (savepoint.action) { default: break; case kActionNone: - setup_chapter1Handler(); + setup_servingDinner(); break; case kActionDefault: - getSavePoints()->addData(kEntityServers0, kAction270410280, 0); - getSavePoints()->addData(kEntityServers0, kAction304061224, 1); - getSavePoints()->addData(kEntityServers0, kAction252568704, 10); - getSavePoints()->addData(kEntityServers0, kAction286534136, 11); - getSavePoints()->addData(kEntityServers0, kAction218983616, 12); - getSavePoints()->addData(kEntityServers0, kAction218586752, 13); - getSavePoints()->addData(kEntityServers0, kAction207330561, 14); - getSavePoints()->addData(kEntityServers0, kAction286403504, 16); - getSavePoints()->addData(kEntityServers0, kAction218128129, 17); - getSavePoints()->addData(kEntityServers0, kAction270068760, 18); - getSavePoints()->addData(kEntityServers0, kAction223712416, 2); - getSavePoints()->addData(kEntityServers0, kAction237485916, 5); - getSavePoints()->addData(kEntityServers0, kAction188893625, 8); - getSavePoints()->addData(kEntityServers0, kAction204704037, 6); - getSavePoints()->addData(kEntityServers0, kAction292758554, 7); - getSavePoints()->addData(kEntityServers0, kAction337548856, 9); + getSavePoints()->addData(kEntityWaiter1, kAction270410280, 0); + getSavePoints()->addData(kEntityWaiter1, kAction304061224, 1); + getSavePoints()->addData(kEntityWaiter1, kAction252568704, 10); + getSavePoints()->addData(kEntityWaiter1, kAction286534136, 11); + getSavePoints()->addData(kEntityWaiter1, kAction218983616, 12); + getSavePoints()->addData(kEntityWaiter1, kAction218586752, 13); + getSavePoints()->addData(kEntityWaiter1, kAction207330561, 14); + getSavePoints()->addData(kEntityWaiter1, kAction286403504, 16); + getSavePoints()->addData(kEntityWaiter1, kAction218128129, 17); + getSavePoints()->addData(kEntityWaiter1, kAction270068760, 18); + getSavePoints()->addData(kEntityWaiter1, kAction223712416, 2); + getSavePoints()->addData(kEntityWaiter1, kAction237485916, 5); + getSavePoints()->addData(kEntityWaiter1, kAction188893625, 8); + getSavePoints()->addData(kEntityWaiter1, kAction204704037, 6); + getSavePoints()->addData(kEntityWaiter1, kAction292758554, 7); + getSavePoints()->addData(kEntityWaiter1, kAction337548856, 9); getData()->entityPosition = kPosition_5900; getData()->location = kLocationOutsideCompartment; @@ -265,47 +265,47 @@ IMPLEMENT_FUNCTION(11, Servers0, chapter1) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(12, Servers0, function12) +IMPLEMENT_FUNCTION(12, Waiter1, annaOrder) handleServer(savepoint, "907", kEntityAnna, kAction268773672, &ENTITY_PARAM(0, 1)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(13, Servers0, function13) +IMPLEMENT_FUNCTION(13, Waiter1, augustOrder) handleServer(savepoint, "911", kEntityAugust, kAction268773672, &ENTITY_PARAM(0, 2), "010F"); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(14, Servers0, function14) +IMPLEMENT_FUNCTION(14, Waiter1, serveAnna) handleServer(savepoint, "908", kEntityAnna, kAction170016384, &ENTITY_PARAM(0, 4)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(15, Servers0, function15) +IMPLEMENT_FUNCTION(15, Waiter1, serveAugust) handleServer(savepoint, "912", kEntityAugust, kAction170016384, &ENTITY_PARAM(0, 5)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(16, Servers0, function16) +IMPLEMENT_FUNCTION(16, Waiter1, clearAnna) serveTable(savepoint, "907", kEntityTables0, "001N", "001P", "909", &ENTITY_PARAM(0, 6)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(17, Servers0, function17) +IMPLEMENT_FUNCTION(17, Waiter1, clearTatiana) serveTable(savepoint, "915", kEntityTables4, "014E", "014F", "917", &ENTITY_PARAM(1, 1), true, false, 67); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(18, Servers0, function18) +IMPLEMENT_FUNCTION(18, Waiter1, clearAugust1) serveTable(savepoint, "911", kEntityTables3, "010L", "010H", "913", &ENTITY_PARAM(0, 7)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(19, Servers0, function19) +IMPLEMENT_FUNCTION(19, Waiter1, clearAugust2) serveTable(savepoint, "911", kEntityTables3, "010L", "010M", "913", &ENTITY_PARAM(0, 8), true, true); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler) +IMPLEMENT_FUNCTION(20, Waiter1, servingDinner) switch (savepoint.action) { default: break; @@ -325,19 +325,19 @@ IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler) } } - if (!getEntities()->isInKitchen(kEntityServers0) && !getEntities()->isSomebodyInsideRestaurantOrSalon()) + if (!getEntities()->isInKitchen(kEntityWaiter1) && !getEntities()->isSomebodyInsideRestaurantOrSalon()) break; - HANDLE_TABLE(0, 1, 1, setup_function12); - HANDLE_TABLE(0, 2, 2, setup_function13); - HANDLE_TABLE(0, 3, 3, setup_function7); - HANDLE_TABLE(0, 4, 4, setup_function14); - HANDLE_TABLE(0, 5, 5, setup_function15); - HANDLE_TABLE(0, 6, 6, setup_function16); - HANDLE_TABLE(1, 1, 7, setup_function17); - HANDLE_TABLE(0, 7, 8, setup_function18); - HANDLE_TABLE(0, 8, 9, setup_function19); - HANDLE_TABLE(1, 2, 10, setup_function8); + HANDLE_TABLE(0, 1, 1, setup_annaOrder); + HANDLE_TABLE(0, 2, 2, setup_augustOrder); + HANDLE_TABLE(0, 3, 3, setup_rebeccaFeedUs); + HANDLE_TABLE(0, 4, 4, setup_serveAnna); + HANDLE_TABLE(0, 5, 5, setup_serveAugust); + HANDLE_TABLE(0, 6, 6, setup_clearAnna); + HANDLE_TABLE(1, 1, 7, setup_clearTatiana); + HANDLE_TABLE(0, 7, 8, setup_clearAugust1); + HANDLE_TABLE(0, 8, 9, setup_clearAugust2); + HANDLE_TABLE(1, 2, 10, setup_rebeccaClearOurTable); break; case kActionCallback: @@ -346,13 +346,13 @@ IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler) break; case 10: - getSavePoints()->push(kEntityServers0, kEntityPascale, kAction352703104); + getSavePoints()->push(kEntityWaiter1, kEntityPascale, kAction352703104); setup_function21(); break; case 11: case 12: - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); getData()->entityPosition = kPosition_5900; if (getCallback() == 11) @@ -363,7 +363,7 @@ IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler) case 13: case 14: - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); getData()->entityPosition = kPosition_5900; break; } @@ -382,7 +382,7 @@ IMPLEMENT_FUNCTION(20, Servers0, chapter1Handler) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(21, Servers0, function21) +IMPLEMENT_FUNCTION(21, Waiter1, function21) switch (savepoint.action) { default: break; @@ -398,28 +398,28 @@ IMPLEMENT_FUNCTION(21, Servers0, function21) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(22, Servers0, function22) +IMPLEMENT_FUNCTION(22, Waiter1, function22) if (savepoint.action == kActionDefault) { getData()->entityPosition = kPosition_5900; getData()->location = kLocationOutsideCompartment; getData()->car = kCarRestaurant; - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(23, Servers0, chapter2) +IMPLEMENT_FUNCTION(23, Waiter1, chapter2) switch (savepoint.action) { default: break; case kActionNone: - setup_chapter2Handler(); + setup_inKitchen(); break; case kActionDefault: - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); getData()->entityPosition = kPosition_5900; getData()->location = kLocationOutsideCompartment; @@ -434,28 +434,28 @@ IMPLEMENT_FUNCTION(23, Servers0, chapter2) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(24, Servers0, chapter2Handler) +IMPLEMENT_FUNCTION(24, Waiter1, inKitchen) switch (savepoint.action) { default: break; case kActionNone: - if (!getEntities()->isInKitchen(kEntityServers0) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) + if (!getEntities()->isInKitchen(kEntityWaiter1) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) break; - HANDLE_TABLE(1, 3, 1, setup_function25); - HANDLE_TABLE(1, 4, 2, setup_function26); + HANDLE_TABLE(1, 3, 1, setup_augustComeHere2); + HANDLE_TABLE(1, 4, 2, setup_augustClearTable2); break; case kActionCallback: if (getCallback() == 1) - HANDLE_TABLE(1, 4, 2, setup_function26); + HANDLE_TABLE(1, 4, 2, setup_augustClearTable2); break; } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(25, Servers0, function25) +IMPLEMENT_FUNCTION(25, Waiter1, augustComeHere2) switch (savepoint.action) { default: break; @@ -474,13 +474,13 @@ IMPLEMENT_FUNCTION(25, Servers0, function25) break; case 1: - getSavePoints()->push(kEntityServers0, kEntityAugust, kAction123712592); - getEntities()->drawSequenceLeft(kEntityServers0, "BLANK"); + getSavePoints()->push(kEntityWaiter1, kEntityAugust, kAction123712592); + getEntities()->drawSequenceLeft(kEntityWaiter1, "BLANK"); break; case 2: getData()->entityPosition = kPosition_5900; - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); ENTITY_PARAM(1, 3) = 0; callbackAction(); @@ -496,22 +496,22 @@ IMPLEMENT_FUNCTION(25, Servers0, function25) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(26, Servers0, function26) +IMPLEMENT_FUNCTION(26, Waiter1, augustClearTable2) serveTable(savepoint, "957", kEntityTables0, "016E", "016D", "959", &ENTITY_PARAM(1, 4)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(27, Servers0, chapter3) +IMPLEMENT_FUNCTION(27, Waiter1, chapter3) switch (savepoint.action) { default: break; case kActionNone: - setup_chapter3Handler(); + setup_serving3(); break; case kActionDefault: - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); getData()->entityPosition = kPosition_5900; getData()->location = kLocationOutsideCompartment; @@ -530,53 +530,53 @@ IMPLEMENT_FUNCTION(27, Servers0, chapter3) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(28, Servers0, chapter3Handler) +IMPLEMENT_FUNCTION(28, Waiter1, serving3) switch (savepoint.action) { default: break; case kActionNone: - if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) + if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) break; if (ENTITY_PARAM(1, 5)) { setCallback(1); - setup_augustAnnaDateOrder(); + setup_annaComeHere3(); break; } label_callback_1: if (ENTITY_PARAM(1, 6)) { setCallback(2); - setup_function9(); + setup_abbotCheckMe(); break; } label_callback_2: if (ENTITY_PARAM(2, 4)) { setCallback(3); - setup_function30(); + setup_abbotServeLunch3(); break; } label_callback_3: if (ENTITY_PARAM(2, 3)) { setCallback(4); - setup_function10(); + setup_abbotClearTable(); break; } label_callback_4: if (ENTITY_PARAM(0, 3)) { setCallback(5); - setup_function7(); + setup_rebeccaFeedUs(); break; } label_callback_5: if (ENTITY_PARAM(1, 2)) { setCallback(6); - setup_function8(); + setup_rebeccaClearOurTable(); break; } break; @@ -606,7 +606,8 @@ label_callback_5: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(29, Servers0, augustAnnaDateOrder) +IMPLEMENT_FUNCTION(29, Waiter1, annaComeHere3) + // August and Anna order dinner switch (savepoint.action) { default: break; @@ -625,15 +626,15 @@ IMPLEMENT_FUNCTION(29, Servers0, augustAnnaDateOrder) break; case 1: - getSavePoints()->push(kEntityServers0, kEntityAnna, kAction122358304); - getEntities()->drawSequenceLeft(kEntityServers0, "026D"); + getSavePoints()->push(kEntityWaiter1, kEntityAnna, kAction122358304); + getEntities()->drawSequenceLeft(kEntityWaiter1, "026D"); setCallback(2); setup_playSound("Ann3138"); break; case 2: - getSavePoints()->push(kEntityServers0, kEntityAnna, kAction122288808); + getSavePoints()->push(kEntityWaiter1, kEntityAnna, kAction122288808); setCallback(3); setup_draw("913"); @@ -641,7 +642,7 @@ IMPLEMENT_FUNCTION(29, Servers0, augustAnnaDateOrder) case 3: getData()->entityPosition = kPosition_5900; - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); ENTITY_PARAM(1, 5) = 0; callbackAction(); @@ -652,7 +653,7 @@ IMPLEMENT_FUNCTION(29, Servers0, augustAnnaDateOrder) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(30, Servers0, function30) +IMPLEMENT_FUNCTION(30, Waiter1, abbotServeLunch3) switch (savepoint.action) { default: break; @@ -671,15 +672,15 @@ IMPLEMENT_FUNCTION(30, Servers0, function30) break; case 1: - getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122358304); - getEntities()->drawSequenceLeft(kEntityServers0, "029D"); + getSavePoints()->push(kEntityWaiter1, kEntityAbbot, kAction122358304); + getEntities()->drawSequenceLeft(kEntityWaiter1, "029D"); setCallback(2); setup_playSound("Abb3016a"); break; case 2: - getSavePoints()->push(kEntityServers0, kEntityAbbot, kAction122288808); + getSavePoints()->push(kEntityWaiter1, kEntityAbbot, kAction122288808); setCallback(3); setup_draw("918"); @@ -687,7 +688,7 @@ IMPLEMENT_FUNCTION(30, Servers0, function30) case 3: getData()->entityPosition = kPosition_5900; - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); ENTITY_PARAM(2, 4) = 0; callbackAction(); @@ -698,17 +699,17 @@ IMPLEMENT_FUNCTION(30, Servers0, function30) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(31, Servers0, chapter4) +IMPLEMENT_FUNCTION(31, Waiter1, chapter4) switch (savepoint.action) { default: break; case kActionNone: - setup_chapter4Handler(); + setup_serving4(); break; case kActionDefault: - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); getData()->entityPosition = kPosition_5900; getData()->location = kLocationOutsideCompartment; @@ -727,7 +728,7 @@ IMPLEMENT_FUNCTION(31, Servers0, chapter4) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(32, Servers0, chapter4Handler) +IMPLEMENT_FUNCTION(32, Waiter1, serving4) switch (savepoint.action) { default: break; @@ -738,47 +739,47 @@ IMPLEMENT_FUNCTION(32, Servers0, chapter4Handler) params->param1 = 0; } - if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) + if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) break; if (ENTITY_PARAM(1, 7)) { setCallback(1); - setup_augustOrderSteak(); + setup_augustOrder4(); break; } label_callback_1: if (ENTITY_PARAM(1, 8)) { setCallback(2); - setup_augustServeDuck(); + setup_serveAugust4(); break; } label_callback_2: if (ENTITY_PARAM(2, 1)) { setCallback(3); - setup_function35(); + setup_augustClearTable(); break; } label_callback_3: if (ENTITY_PARAM(2, 2)) { setCallback(4); - setup_function9(); + setup_abbotCheckMe(); break; } label_callback_4: if (ENTITY_PARAM(2, 3)) { setCallback(5); - setup_function10(); + setup_abbotClearTable(); break; } label_callback_5: if (ENTITY_PARAM(0, 3)) { setCallback(6); - setup_function7(); + setup_rebeccaFeedUs(); break; } break; @@ -821,7 +822,8 @@ label_callback_5: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak) +IMPLEMENT_FUNCTION(33, Waiter1, augustOrder4) + // August orders a steak switch (savepoint.action) { default: break; @@ -837,7 +839,7 @@ IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak) break; case 1: - getEntities()->drawSequenceLeft(kEntityServers0, "010F3"); + getEntities()->drawSequenceLeft(kEntityWaiter1, "010F3"); getEntities()->drawSequenceLeft(kEntityAugust, "010D3"); setCallback(2); @@ -845,7 +847,7 @@ IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak) break; case 2: - getSavePoints()->push(kEntityServers0, kEntityAugust, kAction122288808); + getSavePoints()->push(kEntityWaiter1, kEntityAugust, kAction122288808); setCallback(3); setup_draw("913"); @@ -853,7 +855,7 @@ IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak) case 3: getData()->entityPosition = kPosition_5900; - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); ENTITY_PARAM(1, 7) = 0; callbackAction(); @@ -864,7 +866,8 @@ IMPLEMENT_FUNCTION(33, Servers0, augustOrderSteak) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(34, Servers0, augustServeDuck) +IMPLEMENT_FUNCTION(34, Waiter1, serveAugust4) + // August is being served switch (savepoint.action) { default: break; @@ -880,15 +883,15 @@ IMPLEMENT_FUNCTION(34, Servers0, augustServeDuck) break; case 1: - getSavePoints()->push(kEntityServers0, kEntityAugust, kAction122358304); - getSound()->playSound(kEntityServers0, "AUG1053"); + getSavePoints()->push(kEntityWaiter1, kEntityAugust, kAction122358304); + getSound()->playSound(kEntityWaiter1, "AUG1053"); setCallback(2); setup_draw("010G3"); break; case 2: - getSavePoints()->push(kEntityServers0, kEntityAugust, kAction201964801); + getSavePoints()->push(kEntityWaiter1, kEntityAugust, kAction201964801); setCallback(3); setup_draw("914"); @@ -896,7 +899,7 @@ IMPLEMENT_FUNCTION(34, Servers0, augustServeDuck) case 3: getData()->entityPosition = kPosition_5900; - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); ENTITY_PARAM(1, 8) = 0; callbackAction(); @@ -907,12 +910,12 @@ IMPLEMENT_FUNCTION(34, Servers0, augustServeDuck) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(35, Servers0, function35) +IMPLEMENT_FUNCTION(35, Waiter1, augustClearTable) serveTable(savepoint, "911", kEntityTables3, "010L", "010M", "914", &ENTITY_PARAM(2, 1), false, true); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(36, Servers0, chapter5) +IMPLEMENT_FUNCTION(36, Waiter1, chapter5) switch (savepoint.action) { default: break; @@ -922,7 +925,7 @@ IMPLEMENT_FUNCTION(36, Servers0, chapter5) break; case kActionDefault: - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); getData()->entityPosition = kPosition_3969; getData()->location = kLocationInsideCompartment; @@ -933,19 +936,19 @@ IMPLEMENT_FUNCTION(36, Servers0, chapter5) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(37, Servers0, chapter5Handler) +IMPLEMENT_FUNCTION(37, Waiter1, chapter5Handler) if (savepoint.action == kActionProceedChapter5) setup_nullfunction(); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_NULL_FUNCTION(38, Servers0) +IMPLEMENT_NULL_FUNCTION(38, Waiter1) ////////////////////////////////////////////////////////////////////////// // Private functions ////////////////////////////////////////////////////////////////////////// -void Servers0::handleServer(const SavePoint &savepoint, const char *name, EntityIndex entity, ActionIndex action, uint *parameter, const char *name2) { +void Waiter1::handleServer(const SavePoint &savepoint, const char *name, EntityIndex entity, ActionIndex action, uint *parameter, const char *name2) { switch (savepoint.action) { default: break; @@ -962,11 +965,11 @@ void Servers0::handleServer(const SavePoint &savepoint, const char *name, Entity if (getCallback() == 1) { // Prepare or draw sequences depending of value of string if (strcmp(name2, "")) - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); else - getEntities()->drawSequenceLeft(kEntityServers0, name2); + getEntities()->drawSequenceLeft(kEntityWaiter1, name2); - getSavePoints()->push(kEntityServers0, entity, action); + getSavePoints()->push(kEntityWaiter1, entity, action); *parameter = 0; callbackAction(); @@ -976,7 +979,7 @@ void Servers0::handleServer(const SavePoint &savepoint, const char *name, Entity } ////////////////////////////////////////////////////////////////////////// -void Servers0::serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, bool shouldUpdatePosition, bool pushSavepoint, Position position) { +void Waiter1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, bool shouldUpdatePosition, bool pushSavepoint, Position position) { switch (savepoint.action) { default: break; @@ -998,9 +1001,9 @@ void Servers0::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn case 1: if (position) - getEntities()->updatePositionEnter(kEntityServers0, kCarRestaurant, position); + getEntities()->updatePositionEnter(kEntityWaiter1, kCarRestaurant, position); - getSavePoints()->push(kEntityServers0, entity, kAction136455232); + getSavePoints()->push(kEntityWaiter1, entity, kAction136455232); setCallback(2); setup_callSavepoint(seq2, entity, kActionDrawTablesWithChairs, seq3); @@ -1008,7 +1011,7 @@ void Servers0::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn case 2: if (position) - getEntities()->updatePositionExit(kEntityServers0, kCarRestaurant, position); + getEntities()->updatePositionExit(kEntityWaiter1, kCarRestaurant, position); setCallback(3); setup_draw(seq4); @@ -1019,9 +1022,9 @@ void Servers0::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn // Special case for functions 19 & 35 if (pushSavepoint) - getSavePoints()->push(kEntityServers0, kEntityRebecca, kAction224253538); + getSavePoints()->push(kEntityWaiter1, kEntityRebecca, kAction224253538); - getEntities()->clearSequences(kEntityServers0); + getEntities()->clearSequences(kEntityWaiter1); *parameter = 0; callbackAction(); diff --git a/engines/lastexpress/entities/servers0.h b/engines/lastexpress/entities/waiter1.h index 70f06596b0..64c66550af 100644 --- a/engines/lastexpress/entities/servers0.h +++ b/engines/lastexpress/entities/waiter1.h @@ -20,8 +20,8 @@ * */ -#ifndef LASTEXPRESS_SERVERS0_H -#define LASTEXPRESS_SERVERS0_H +#ifndef LASTEXPRESS_WAITER1_H +#define LASTEXPRESS_WAITER1_H #include "lastexpress/entities/entity.h" @@ -29,10 +29,10 @@ namespace LastExpress { class LastExpressEngine; -class Servers0 : public Entity { +class Waiter1 : public Entity { public: - Servers0(LastExpressEngine *engine); - ~Servers0() {} + Waiter1(LastExpressEngine *engine); + ~Waiter1() {} /** * Call a savepoint (or draw sequence in default case) @@ -80,29 +80,24 @@ public: */ DECLARE_FUNCTION_1(playSound, const char *filename) - DECLARE_FUNCTION(function7) - DECLARE_FUNCTION(function8) - DECLARE_FUNCTION(function9) - DECLARE_FUNCTION(function10) + DECLARE_FUNCTION(rebeccaFeedUs) + DECLARE_FUNCTION(rebeccaClearOurTable) + DECLARE_FUNCTION(abbotCheckMe) + DECLARE_FUNCTION(abbotClearTable) /** * Setup Chapter 1 */ DECLARE_FUNCTION(chapter1) - DECLARE_FUNCTION(function12) - DECLARE_FUNCTION(function13) - DECLARE_FUNCTION(function14) - DECLARE_FUNCTION(function15) - DECLARE_FUNCTION(function16) - DECLARE_FUNCTION(function17) - DECLARE_FUNCTION(function18) - DECLARE_FUNCTION(function19) - - /** - * Handle Chapter 1 events - */ - DECLARE_FUNCTION(chapter1Handler) - + DECLARE_FUNCTION(annaOrder) + DECLARE_FUNCTION(augustOrder) + DECLARE_FUNCTION(serveAnna) + DECLARE_FUNCTION(serveAugust) + DECLARE_FUNCTION(clearAnna) + DECLARE_FUNCTION(clearTatiana) + DECLARE_FUNCTION(clearAugust1) + DECLARE_FUNCTION(clearAugust2) + DECLARE_FUNCTION(servingDinner) DECLARE_FUNCTION(function21) DECLARE_FUNCTION(function22) @@ -110,41 +105,26 @@ public: * Setup Chapter 2 */ DECLARE_FUNCTION(chapter2) - - /** - * Handle Chapter 2 events - */ - DECLARE_FUNCTION(chapter2Handler) - - DECLARE_FUNCTION(function25) - DECLARE_FUNCTION(function26) + DECLARE_FUNCTION(inKitchen) + DECLARE_FUNCTION(augustComeHere2) + DECLARE_FUNCTION(augustClearTable2) /** * Setup Chapter 3 */ DECLARE_FUNCTION(chapter3) - - /** - * Handle Chapter 3 events - */ - DECLARE_FUNCTION(chapter3Handler) - - DECLARE_FUNCTION(augustAnnaDateOrder) - DECLARE_FUNCTION(function30) + DECLARE_FUNCTION(serving3) + DECLARE_FUNCTION(annaComeHere3) + DECLARE_FUNCTION(abbotServeLunch3) /** * Setup Chapter 4 */ DECLARE_FUNCTION(chapter4) - - /** - * Handle Chapter 4 events - */ - DECLARE_FUNCTION(chapter4Handler) - - DECLARE_FUNCTION(augustOrderSteak) - DECLARE_FUNCTION(augustServeDuck) - DECLARE_FUNCTION(function35) + DECLARE_FUNCTION(serving4) + DECLARE_FUNCTION(augustOrder4) + DECLARE_FUNCTION(serveAugust4) + DECLARE_FUNCTION(augustClearTable) /** * Setup Chapter 5 @@ -165,4 +145,4 @@ private: } // End of namespace LastExpress -#endif // LASTEXPRESS_SERVERS0_H +#endif // LASTEXPRESS_WAITER1_H diff --git a/engines/lastexpress/entities/servers1.cpp b/engines/lastexpress/entities/waiter2.cpp index 153c2b66da..52a48a77d5 100644 --- a/engines/lastexpress/entities/servers1.cpp +++ b/engines/lastexpress/entities/waiter2.cpp @@ -20,7 +20,7 @@ * */ -#include "lastexpress/entities/servers1.h" +#include "lastexpress/entities/waiter2.h" #include "lastexpress/game/entities.h" #include "lastexpress/game/logic.h" @@ -32,61 +32,61 @@ namespace LastExpress { -Servers1::Servers1(LastExpressEngine *engine) : Entity(engine, kEntityServers1) { - ADD_CALLBACK_FUNCTION(Servers1, updateFromTime); - ADD_CALLBACK_FUNCTION(Servers1, draw); - ADD_CALLBACK_FUNCTION(Servers1, updatePosition); - ADD_CALLBACK_FUNCTION(Servers1, callbackActionOnDirection); - ADD_CALLBACK_FUNCTION(Servers1, callSavepoint); - ADD_CALLBACK_FUNCTION(Servers1, playSound); - ADD_CALLBACK_FUNCTION(Servers1, function7); - ADD_CALLBACK_FUNCTION(Servers1, chapter1); - ADD_CALLBACK_FUNCTION(Servers1, function9); - ADD_CALLBACK_FUNCTION(Servers1, function10); - ADD_CALLBACK_FUNCTION(Servers1, function11); - ADD_CALLBACK_FUNCTION(Servers1, function12); - ADD_CALLBACK_FUNCTION(Servers1, function13); - ADD_CALLBACK_FUNCTION(Servers1, chapter1Handler); - ADD_CALLBACK_FUNCTION(Servers1, function15); - ADD_CALLBACK_FUNCTION(Servers1, function16); - ADD_CALLBACK_FUNCTION(Servers1, chapter2); - ADD_CALLBACK_FUNCTION(Servers1, chapter2Handler); - ADD_CALLBACK_FUNCTION(Servers1, function19); - ADD_CALLBACK_FUNCTION(Servers1, function20); - ADD_CALLBACK_FUNCTION(Servers1, function21); - ADD_CALLBACK_FUNCTION(Servers1, chapter3); - ADD_CALLBACK_FUNCTION(Servers1, chapter3Handler); - ADD_CALLBACK_FUNCTION(Servers1, function24); - ADD_CALLBACK_FUNCTION(Servers1, chapter4); - ADD_CALLBACK_FUNCTION(Servers1, chapter4Handler); - ADD_CALLBACK_FUNCTION(Servers1, function27); - ADD_CALLBACK_FUNCTION(Servers1, function28); - ADD_CALLBACK_FUNCTION(Servers1, function29); - ADD_CALLBACK_FUNCTION(Servers1, chapter5); - ADD_CALLBACK_FUNCTION(Servers1, chapter5Handler); +Waiter2::Waiter2(LastExpressEngine *engine) : Entity(engine, kEntityWaiter2) { + ADD_CALLBACK_FUNCTION(Waiter2, updateFromTime); + ADD_CALLBACK_FUNCTION(Waiter2, draw); + ADD_CALLBACK_FUNCTION(Waiter2, updatePosition); + ADD_CALLBACK_FUNCTION(Waiter2, callbackActionOnDirection); + ADD_CALLBACK_FUNCTION(Waiter2, callSavepoint); + ADD_CALLBACK_FUNCTION(Waiter2, playSound); + ADD_CALLBACK_FUNCTION(Waiter2, monsieurServeUs); + ADD_CALLBACK_FUNCTION(Waiter2, chapter1); + ADD_CALLBACK_FUNCTION(Waiter2, milosOrder); + ADD_CALLBACK_FUNCTION(Waiter2, monsieurOrder); + ADD_CALLBACK_FUNCTION(Waiter2, clearAlexei); + ADD_CALLBACK_FUNCTION(Waiter2, clearMilos); + ADD_CALLBACK_FUNCTION(Waiter2, clearMonsieur); + ADD_CALLBACK_FUNCTION(Waiter2, servingDinner); + ADD_CALLBACK_FUNCTION(Waiter2, function15); + ADD_CALLBACK_FUNCTION(Waiter2, function16); + ADD_CALLBACK_FUNCTION(Waiter2, chapter2); + ADD_CALLBACK_FUNCTION(Waiter2, inKitchen); + ADD_CALLBACK_FUNCTION(Waiter2, tatianaClearTableB); + ADD_CALLBACK_FUNCTION(Waiter2, ivoComeHere); + ADD_CALLBACK_FUNCTION(Waiter2, ivoClearTableC); + ADD_CALLBACK_FUNCTION(Waiter2, chapter3); + ADD_CALLBACK_FUNCTION(Waiter2, serving3); + ADD_CALLBACK_FUNCTION(Waiter2, annaBringTea3); + ADD_CALLBACK_FUNCTION(Waiter2, chapter4); + ADD_CALLBACK_FUNCTION(Waiter2, serving4); + ADD_CALLBACK_FUNCTION(Waiter2, augustNeedsADrink); + ADD_CALLBACK_FUNCTION(Waiter2, serveAugustADrink); + ADD_CALLBACK_FUNCTION(Waiter2, annaNeedsADrink); + ADD_CALLBACK_FUNCTION(Waiter2, chapter5); + ADD_CALLBACK_FUNCTION(Waiter2, chapter5Handler); ADD_NULL_FUNCTION() } ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_NOSETUP(1, Servers1, updateFromTime) +IMPLEMENT_FUNCTION_NOSETUP(1, Waiter2, updateFromTime) Entity::updateFromTime(savepoint); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_S(2, Servers1, draw) +IMPLEMENT_FUNCTION_S(2, Waiter2, draw) Entity::draw(savepoint, true); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_SII(3, Servers1, updatePosition, CarIndex, Position) +IMPLEMENT_FUNCTION_SII(3, Waiter2, updatePosition, CarIndex, Position) Entity::updatePosition(savepoint, true); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(4, Servers1, callbackActionOnDirection) +IMPLEMENT_FUNCTION(4, Waiter2, callbackActionOnDirection) if (savepoint.action == kActionExcuseMeCath) { if (!params->param1) { - getSound()->excuseMe(kEntityServers1); + getSound()->excuseMe(kEntityWaiter2); params->param1 = 1; } } @@ -95,17 +95,17 @@ IMPLEMENT_FUNCTION(4, Servers1, callbackActionOnDirection) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_SIIS(5, Servers1, callSavepoint, EntityIndex, ActionIndex) +IMPLEMENT_FUNCTION_SIIS(5, Waiter2, callSavepoint, EntityIndex, ActionIndex) Entity::callSavepoint(savepoint, true); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_S(6, Servers1, playSound) +IMPLEMENT_FUNCTION_S(6, Waiter2, playSound) Entity::playSound(savepoint); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(7, Servers1, function7) +IMPLEMENT_FUNCTION(7, Waiter2, monsieurServeUs) switch (savepoint.action) { default: break; @@ -124,19 +124,19 @@ IMPLEMENT_FUNCTION(7, Servers1, function7) break; case 1: - getSavePoints()->push(kEntityServers1, kEntityBoutarel, kAction122358304); + getSavePoints()->push(kEntityWaiter2, kEntityBoutarel, kAction122358304); setCallback(2); setup_draw("008C"); break; case 2: - getSavePoints()->push(kEntityServers1, kEntityBoutarel, kAction122288808); + getSavePoints()->push(kEntityWaiter2, kEntityBoutarel, kAction122288808); setCallback(2); setup_draw("926"); break; case 3: - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); getData()->entityPosition = kPosition_5900; ENTITY_PARAM(1, 2) = 0; @@ -148,27 +148,27 @@ IMPLEMENT_FUNCTION(7, Servers1, function7) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(8, Servers1, chapter1) +IMPLEMENT_FUNCTION(8, Waiter2, chapter1) switch (savepoint.action) { default: break; case kActionNone: - setup_chapter1Handler(); + setup_servingDinner(); break; case kActionDefault: - getSavePoints()->addData(kEntityServers1, kAction223002560, 0); - getSavePoints()->addData(kEntityServers1, kAction302996448, 2); - getSavePoints()->addData(kEntityServers1, kAction269485588, 3); - getSavePoints()->addData(kEntityServers1, kAction326144276, 4); - getSavePoints()->addData(kEntityServers1, kAction302203328, 5); - getSavePoints()->addData(kEntityServers1, kAction189688608, 6); - getSavePoints()->addData(kEntityServers1, kAction236237423, 7); - getSavePoints()->addData(kEntityServers1, kAction219377792, 8); - getSavePoints()->addData(kEntityServers1, kAction256200848, 9); - getSavePoints()->addData(kEntityServers1, kAction291721418, 10); - getSavePoints()->addData(kEntityServers1, kAction258136010, 11); + getSavePoints()->addData(kEntityWaiter2, kAction223002560, 0); + getSavePoints()->addData(kEntityWaiter2, kAction302996448, 2); + getSavePoints()->addData(kEntityWaiter2, kAction269485588, 3); + getSavePoints()->addData(kEntityWaiter2, kAction326144276, 4); + getSavePoints()->addData(kEntityWaiter2, kAction302203328, 5); + getSavePoints()->addData(kEntityWaiter2, kAction189688608, 6); + getSavePoints()->addData(kEntityWaiter2, kAction236237423, 7); + getSavePoints()->addData(kEntityWaiter2, kAction219377792, 8); + getSavePoints()->addData(kEntityWaiter2, kAction256200848, 9); + getSavePoints()->addData(kEntityWaiter2, kAction291721418, 10); + getSavePoints()->addData(kEntityWaiter2, kAction258136010, 11); getData()->entityPosition = kPosition_5900; getData()->location = kLocationOutsideCompartment; @@ -178,7 +178,7 @@ IMPLEMENT_FUNCTION(8, Servers1, chapter1) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(9, Servers1, function9) +IMPLEMENT_FUNCTION(9, Waiter2, milosOrder) switch (savepoint.action) { default: break; @@ -198,7 +198,7 @@ IMPLEMENT_FUNCTION(9, Servers1, function9) case 1: getEntities()->drawSequenceLeft(kEntityMilos, "BLANK"); - getEntities()->drawSequenceLeft(kEntityServers1, "009B"); + getEntities()->drawSequenceLeft(kEntityWaiter2, "009B"); setCallback(2); setup_playSound("WAT1001"); @@ -212,7 +212,7 @@ IMPLEMENT_FUNCTION(9, Servers1, function9) break; case 3: - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); getData()->entityPosition = kPosition_5900; ENTITY_PARAM(0, 1) = 0; @@ -224,7 +224,7 @@ IMPLEMENT_FUNCTION(9, Servers1, function9) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(10, Servers1, function10) +IMPLEMENT_FUNCTION(10, Waiter2, monsieurOrder) switch (savepoint.action) { default: break; @@ -244,21 +244,21 @@ IMPLEMENT_FUNCTION(10, Servers1, function10) case 1: getEntities()->drawSequenceLeft(kEntityBoutarel, "BLANK"); - getEntities()->drawSequenceLeft(kEntityServers1, "008C"); + getEntities()->drawSequenceLeft(kEntityWaiter2, "008C"); setCallback(2); setup_playSound("MRB1077"); break; case 2: - getSavePoints()->push(kEntityServers1, kEntityBoutarel, kAction168717392); + getSavePoints()->push(kEntityWaiter2, kEntityBoutarel, kAction168717392); setCallback(3); setup_draw("926"); break; case 3: - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); getData()->entityPosition = kPosition_5900; ENTITY_PARAM(0, 2) = 0; @@ -270,63 +270,63 @@ IMPLEMENT_FUNCTION(10, Servers1, function10) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(11, Servers1, function11) +IMPLEMENT_FUNCTION(11, Waiter2, clearAlexei) serveTable(savepoint, "919", kEntityTables1, "005H", "005J", "921", &ENTITY_PARAM(0, 3), 63); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(12, Servers1, function12) +IMPLEMENT_FUNCTION(12, Waiter2, clearMilos) serveTable(savepoint, "923", kEntityTables2, "009F", "009G", "926", &ENTITY_PARAM(0, 4)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(13, Servers1, function13) +IMPLEMENT_FUNCTION(13, Waiter2, clearMonsieur) serveTable(savepoint, "923", kEntityTables2, "009F", "009G", "926", &ENTITY_PARAM(0, 5)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(14, Servers1, chapter1Handler) +IMPLEMENT_FUNCTION(14, Waiter2, servingDinner) switch (savepoint.action) { default: break; case kActionDefault: - if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) + if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) break; if (ENTITY_PARAM(0, 1)) { setCallback(1); - setup_function9(); + setup_milosOrder(); break; } if (ENTITY_PARAM(1, 2)) { setCallback(2); - setup_function10(); + setup_monsieurOrder(); break; } if (ENTITY_PARAM(0, 3)) { setCallback(3); - setup_function11(); + setup_clearAlexei(); break; } if (ENTITY_PARAM(0, 4)) { setCallback(4); - setup_function12(); + setup_clearMilos(); break; } if (ENTITY_PARAM(0, 5)) { setCallback(5); - setup_function13(); + setup_clearMonsieur(); } break; case kActionCallback: if (getCallback() == 5) { - getSavePoints()->push(kEntityServers1, kEntityPascale, kAction352768896); + getSavePoints()->push(kEntityWaiter2, kEntityPascale, kAction352768896); setup_function15(); } break; @@ -334,7 +334,7 @@ switch (savepoint.action) { IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(15, Servers1, function15) +IMPLEMENT_FUNCTION(15, Waiter2, function15) switch (savepoint.action) { default: break; @@ -350,28 +350,28 @@ IMPLEMENT_FUNCTION(15, Servers1, function15) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(16, Servers1, function16) +IMPLEMENT_FUNCTION(16, Waiter2, function16) if (savepoint.action == kActionDefault) { getData()->entityPosition = kPosition_5900; getData()->location = kLocationOutsideCompartment; getData()->car = kCarRestaurant; - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(17, Servers1, chapter2) +IMPLEMENT_FUNCTION(17, Waiter2, chapter2) switch (savepoint.action) { default: break; case kActionNone: - setup_chapter2Handler(); + setup_inKitchen(); break; case kActionDefault: - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); getData()->entityPosition = kPosition_5900; getData()->location = kLocationOutsideCompartment; @@ -387,32 +387,32 @@ IMPLEMENT_FUNCTION(17, Servers1, chapter2) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(18, Servers1, chapter2Handler) +IMPLEMENT_FUNCTION(18, Waiter2, inKitchen) switch (savepoint.action) { default: break; case kActionNone: - if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) + if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) break; if (ENTITY_PARAM(0, 6)) { setCallback(1); - setup_function19(); + setup_tatianaClearTableB(); break; } label_callback_1: if (ENTITY_PARAM(0, 7)) { setCallback(2); - setup_function20(); + setup_ivoComeHere(); break; } label_callback_2: if (ENTITY_PARAM(0, 8) || ENTITY_PARAM(0, 5)) { setCallback(3); - setup_function21(); + setup_ivoClearTableC(); } break; @@ -428,7 +428,7 @@ label_callback_2: goto label_callback_2; case 4: - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); getData()->entityPosition = kPosition_5900; break; } @@ -442,12 +442,12 @@ label_callback_2: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(19, Servers1, function19) +IMPLEMENT_FUNCTION(19, Waiter2, tatianaClearTableB) serveTable(savepoint, "969", kEntityTables1, "005H2", "018A", "971", &ENTITY_PARAM(0, 6), 63); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(20, Servers1, function20) +IMPLEMENT_FUNCTION(20, Waiter2, ivoComeHere) switch (savepoint.action) { default: break; @@ -462,8 +462,8 @@ IMPLEMENT_FUNCTION(20, Servers1, function20) case kActionCallback: if (getCallback() == 1) { - getSavePoints()->push(kEntityServers1, kEntityIvo, kAction123712592); - getEntities()->drawSequenceLeft(kEntityServers1, "BLANK"); + getSavePoints()->push(kEntityWaiter2, kEntityIvo, kAction123712592); + getEntities()->drawSequenceLeft(kEntityWaiter2, "BLANK"); ENTITY_PARAM(0, 7) = 0; callbackAction(); @@ -473,22 +473,22 @@ IMPLEMENT_FUNCTION(20, Servers1, function20) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(21, Servers1, function21) +IMPLEMENT_FUNCTION(21, Waiter2, ivoClearTableC) serveTable(savepoint, "974", kEntityTables2, "009F2", "009G", "976", &ENTITY_PARAM(0, 8), 0, true, &ENTITY_PARAM(0, 5)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(22, Servers1, chapter3) +IMPLEMENT_FUNCTION(22, Waiter2, chapter3) switch (savepoint.action) { default: break; case kActionNone: - setup_chapter3Handler(); + setup_serving3(); break; case kActionDefault: - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); getData()->entityPosition = kPosition_5900; getData()->location = kLocationOutsideCompartment; @@ -503,49 +503,49 @@ IMPLEMENT_FUNCTION(22, Servers1, chapter3) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(23, Servers1, chapter3Handler) +IMPLEMENT_FUNCTION(23, Waiter2, serving3) if (savepoint.action != kActionNone) return; - if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) + if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) return; if (ENTITY_PARAM(1, 1)) { setCallback(1); - setup_function24(); + setup_annaBringTea3(); return; } if (ENTITY_PARAM(1, 2)) { setCallback(2); - setup_function7(); + setup_monsieurServeUs(); } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(24, Servers1, function24) +IMPLEMENT_FUNCTION(24, Waiter2, annaBringTea3) serveSalon(savepoint, "927", "Ann3143A", kEntityAnna, "Ann31444", "112C", kAction122288808, "928", &ENTITY_PARAM(1, 1)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(25, Servers1, chapter4) +IMPLEMENT_FUNCTION(25, Waiter2, chapter4) switch (savepoint.action) { default: break; case kActionNone: - setup_chapter4Handler(); + setup_serving4(); break; case kActionDefault: - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); getData()->entityPosition = kPosition_5900; getData()->location = kLocationOutsideCompartment; getData()->car = kCarRestaurant; getData()->inventoryItem = kItemNone; - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); ENTITY_PARAM(1, 2) = 0; ENTITY_PARAM(1, 3) = 0; @@ -556,7 +556,7 @@ IMPLEMENT_FUNCTION(25, Servers1, chapter4) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(26, Servers1, chapter4Handler) +IMPLEMENT_FUNCTION(26, Waiter2, serving4) switch (savepoint.action) { default: break; @@ -569,24 +569,30 @@ IMPLEMENT_FUNCTION(26, Servers1, chapter4Handler) } } - if (!getEntities()->isInKitchen(kEntityServers1) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) + if (!getEntities()->isInKitchen(kEntityWaiter2) || !getEntities()->isSomebodyInsideRestaurantOrSalon()) break; + if (ENTITY_PARAM(1, 3)) { + setCallback(1); + setup_augustNeedsADrink(); + break; + } + if (ENTITY_PARAM(1, 5)) { setCallback(2); - setup_function28(); + setup_serveAugustADrink(); break; } if (ENTITY_PARAM(1, 4)) { setCallback(3); - setup_function29(); + setup_annaNeedsADrink(); break; } if (ENTITY_PARAM(1, 2)) { setCallback(4); - setup_function7(); + setup_monsieurServeUs(); } break; @@ -608,22 +614,22 @@ IMPLEMENT_FUNCTION(26, Servers1, chapter4Handler) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(27, Servers1, function27) +IMPLEMENT_FUNCTION(27, Waiter2, augustNeedsADrink) serveSalon(savepoint, "929", "", kEntityAugust, "Aug4003", "122D", kAction134486752, "930", &ENTITY_PARAM(1, 3)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(28, Servers1, function28) +IMPLEMENT_FUNCTION(28, Waiter2, serveAugustADrink) serveSalon(savepoint, "931", "", kEntityAugust, "Aug4004", "122E", kAction125826561, "930", &ENTITY_PARAM(1, 5)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(29, Servers1, function29) +IMPLEMENT_FUNCTION(29, Waiter2, annaNeedsADrink) serveSalon(savepoint, "932", "", kEntityAnna, "Ann4151", "127D", kAction122288808, "930", &ENTITY_PARAM(1, 4)); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(30, Servers1, chapter5) +IMPLEMENT_FUNCTION(30, Waiter2, chapter5) switch (savepoint.action) { default: break; @@ -633,7 +639,7 @@ IMPLEMENT_FUNCTION(30, Servers1, chapter5) break; case kActionDefault: - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); getData()->entityPosition = kPosition_3969; getData()->location = kLocationInsideCompartment; @@ -644,19 +650,19 @@ IMPLEMENT_FUNCTION(30, Servers1, chapter5) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(31, Servers1, chapter5Handler) +IMPLEMENT_FUNCTION(31, Waiter2, chapter5Handler) if (savepoint.action == kActionProceedChapter5) setup_nullfunction(); IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_NULL_FUNCTION(32, Servers1) +IMPLEMENT_NULL_FUNCTION(32, Waiter2) ////////////////////////////////////////////////////////////////////////// // Private functions ////////////////////////////////////////////////////////////////////////// -void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, Position position, bool shouldUpdatePosition, uint *parameter2) { +void Waiter2::serveTable(const SavePoint &savepoint, const char *seq1, EntityIndex entity, const char *seq2, const char *seq3, const char *seq4, uint *parameter, Position position, bool shouldUpdatePosition, uint *parameter2) { switch (savepoint.action) { default: break; @@ -678,9 +684,9 @@ void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn case 1: if (position) - getEntities()->updatePositionEnter(kEntityServers1, kCarRestaurant, position); + getEntities()->updatePositionEnter(kEntityWaiter2, kCarRestaurant, position); - getSavePoints()->push(kEntityServers1, entity, kAction136455232); + getSavePoints()->push(kEntityWaiter2, entity, kAction136455232); setCallback(2); setup_callSavepoint(seq2, entity, kActionDrawTablesWithChairs, seq3); @@ -688,7 +694,7 @@ void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn case 2: if (position) - getEntities()->updatePositionExit(kEntityServers1, kCarRestaurant, position); + getEntities()->updatePositionExit(kEntityWaiter2, kCarRestaurant, position); setCallback(3); setup_draw(seq4); @@ -696,7 +702,7 @@ void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn case 3: getData()->entityPosition = kPosition_5900; - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); *parameter = 0; if (parameter2 != NULL) @@ -710,7 +716,7 @@ void Servers1::serveTable(const SavePoint &savepoint, const char *seq1, EntityIn } ////////////////////////////////////////////////////////////////////////// -void Servers1::serveSalon(const SavePoint &savepoint, const char *seq1, const char *snd1, EntityIndex entity, const char *snd2, const char *seq2, ActionIndex action, const char *seq3, uint *parameter) { +void Waiter2::serveSalon(const SavePoint &savepoint, const char *seq1, const char *snd1, EntityIndex entity, const char *snd2, const char *seq2, ActionIndex action, const char *seq3, uint *parameter) { switch (savepoint.action) { default: break; @@ -729,46 +735,46 @@ void Servers1::serveSalon(const SavePoint &savepoint, const char *seq1, const ch break; case 1: - getEntities()->drawSequenceRight(kEntityServers1, seq1); + getEntities()->drawSequenceRight(kEntityWaiter2, seq1); if (getEntities()->isInRestaurant(kEntityPlayer)) - getEntities()->updateFrame(kEntityServers1); + getEntities()->updateFrame(kEntityWaiter2); if (!strcmp(snd1, "")) - getSound()->playSound(kEntityServers1, snd1); + getSound()->playSound(kEntityWaiter2, snd1); setCallback(2); setup_callbackActionOnDirection(); break; case 2: - getSavePoints()->push(kEntityServers1, entity, kAction122358304); + getSavePoints()->push(kEntityWaiter2, entity, kAction122358304); - getSound()->playSound(kEntityServers1, snd2); + getSound()->playSound(kEntityWaiter2, snd2); setCallback(3); setup_updatePosition(seq2, kCarRestaurant, 57); break; case 3: - getSavePoints()->push(kEntityServers1, entity, action); + getSavePoints()->push(kEntityWaiter2, entity, action); setCallback(4); setup_draw(seq3); break; case 4: - getEntities()->drawSequenceRight(kEntityServers1, "816UD"); + getEntities()->drawSequenceRight(kEntityWaiter2, "816UD"); if (getEntities()->isInSalon(kEntityPlayer)) - getEntities()->updateFrame(kEntityServers1); + getEntities()->updateFrame(kEntityWaiter2); setCallback(5); setup_callbackActionOnDirection(); break; case 5: - getEntities()->clearSequences(kEntityServers1); + getEntities()->clearSequences(kEntityWaiter2); getData()->entityPosition = kPosition_5900; *parameter = 0; diff --git a/engines/lastexpress/entities/servers1.h b/engines/lastexpress/entities/waiter2.h index 58566cd4d3..e8dc8f48e0 100644 --- a/engines/lastexpress/entities/servers1.h +++ b/engines/lastexpress/entities/waiter2.h @@ -20,8 +20,8 @@ * */ -#ifndef LASTEXPRESS_SERVERS1_H -#define LASTEXPRESS_SERVERS1_H +#ifndef LASTEXPRESS_WAITER2_H +#define LASTEXPRESS_WAITER2_H #include "lastexpress/entities/entity.h" @@ -29,10 +29,10 @@ namespace LastExpress { class LastExpressEngine; -class Servers1 : public Entity { +class Waiter2 : public Entity { public: - Servers1(LastExpressEngine *engine); - ~Servers1() {} + Waiter2(LastExpressEngine *engine); + ~Waiter2() {} /** * Updates parameter 2 using time value @@ -80,24 +80,19 @@ public: */ DECLARE_FUNCTION_1(playSound, const char *filename) - DECLARE_FUNCTION(function7) + DECLARE_FUNCTION(monsieurServeUs) /** * Setup Chapter 1 */ DECLARE_FUNCTION(chapter1) - DECLARE_FUNCTION(function9) - DECLARE_FUNCTION(function10) - DECLARE_FUNCTION(function11) - DECLARE_FUNCTION(function12) - DECLARE_FUNCTION(function13) - - /** - * Handle Chapter 1 events - */ - DECLARE_FUNCTION(chapter1Handler) - + DECLARE_FUNCTION(milosOrder) + DECLARE_FUNCTION(monsieurOrder) + DECLARE_FUNCTION(clearAlexei) + DECLARE_FUNCTION(clearMilos) + DECLARE_FUNCTION(clearMonsieur) + DECLARE_FUNCTION(servingDinner) DECLARE_FUNCTION(function15) DECLARE_FUNCTION(function16) @@ -105,41 +100,26 @@ public: * Setup Chapter 2 */ DECLARE_FUNCTION(chapter2) - - /** - * Handle Chapter 2 events - */ - DECLARE_FUNCTION(chapter2Handler) - - DECLARE_FUNCTION(function19) - DECLARE_FUNCTION(function20) - DECLARE_FUNCTION(function21) + DECLARE_FUNCTION(inKitchen) + DECLARE_FUNCTION(tatianaClearTableB) + DECLARE_FUNCTION(ivoComeHere) + DECLARE_FUNCTION(ivoClearTableC) /** * Setup Chapter 3 */ DECLARE_FUNCTION(chapter3) - - /** - * Handle Chapter 3 events - */ - DECLARE_FUNCTION(chapter3Handler) - - DECLARE_FUNCTION(function24) + DECLARE_FUNCTION(serving3) + DECLARE_FUNCTION(annaBringTea3) /** * Setup Chapter 4 */ DECLARE_FUNCTION(chapter4) - - /** - * Handle Chapter 4 events - */ - DECLARE_FUNCTION(chapter4Handler) - - DECLARE_FUNCTION(function27) - DECLARE_FUNCTION(function28) - DECLARE_FUNCTION(function29) + DECLARE_FUNCTION(serving4) + DECLARE_FUNCTION(augustNeedsADrink) + DECLARE_FUNCTION(serveAugustADrink) + DECLARE_FUNCTION(annaNeedsADrink) /** * Setup Chapter 5 @@ -160,4 +140,4 @@ private: } // End of namespace LastExpress -#endif // LASTEXPRESS_SERVERS1_H +#endif // LASTEXPRESS_WAITER2_H diff --git a/engines/lastexpress/game/action.cpp b/engines/lastexpress/game/action.cpp index 986c56cb1b..96b97db939 100644 --- a/engines/lastexpress/game/action.cpp +++ b/engines/lastexpress/game/action.cpp @@ -1456,7 +1456,7 @@ IMPLEMENT_ACTION(playMusicChapterSetupTrain) if (!getSoundQueue()->isBuffered(filename) && hotspot.param3 & id) { getSound()->playSound(kEntityPlayer, filename, kFlagDefault); - getSavePoints()->call(kEntityPlayer, kEntityTrain, kAction203863200, filename.c_str()); + getSavePoints()->call(kEntityPlayer, kEntityTrain, kAction203863200, filename); getSavePoints()->push(kEntityPlayer, kEntityTrain, kAction222746496, hotspot.param2); } diff --git a/engines/lastexpress/game/entities.cpp b/engines/lastexpress/game/entities.cpp index b4b5527f8d..b881d34ebe 100644 --- a/engines/lastexpress/game/entities.cpp +++ b/engines/lastexpress/game/entities.cpp @@ -51,8 +51,6 @@ #include "lastexpress/entities/pascale.h" #include "lastexpress/entities/rebecca.h" #include "lastexpress/entities/salko.h" -#include "lastexpress/entities/servers0.h" -#include "lastexpress/entities/servers1.h" #include "lastexpress/entities/sophie.h" #include "lastexpress/entities/tables.h" #include "lastexpress/entities/tatiana.h" @@ -60,6 +58,8 @@ #include "lastexpress/entities/vassili.h" #include "lastexpress/entities/verges.h" #include "lastexpress/entities/vesna.h" +#include "lastexpress/entities/waiter1.h" +#include "lastexpress/entities/waiter2.h" #include "lastexpress/entities/yasmin.h" // Game @@ -134,8 +134,8 @@ Entities::Entities(LastExpressEngine *engine) : _engine(engine) { ADD_ENTITY(Mertens); ADD_ENTITY(Coudert); ADD_ENTITY(Pascale); - ADD_ENTITY(Servers0); - ADD_ENTITY(Servers1); + ADD_ENTITY(Waiter1); + ADD_ENTITY(Waiter2); ADD_ENTITY(Cooks); ADD_ENTITY(Verges); ADD_ENTITY(Tatiana); @@ -389,7 +389,6 @@ void Entities::resetState(EntityIndex entityIndex) { getLogic()->updateCursor(); } - void Entities::updateFields() const { if (!getFlags()->isGameRunning) return; @@ -897,7 +896,6 @@ void Entities::computeCurrentFrame(EntityIndex entityIndex) const { } break; - case kDirectionLeft: if (data->currentFrame == -1 || data->currentFrame >= (int32)data->sequence->count()) { data->currentFrame = 0; @@ -1772,8 +1770,7 @@ void Entities::enterCompartment(EntityIndex entity, ObjectIndex compartment, boo // Update compartments int index = (compartment < 32 ? compartment - 1 : compartment - 24); - if (index >= 16) - error("[Entities::enterCompartment] Invalid compartment index"); + assert(index < 16); if (useCompartment1) _compartments1[index] |= STORE_VALUE(entity); @@ -1858,8 +1855,7 @@ void Entities::exitCompartment(EntityIndex entity, ObjectIndex compartment, bool // Update compartments int index = (compartment < 32 ? compartment - 1 : compartment - 24); - if (index >= 16) - error("[Entities::exitCompartment] Invalid compartment index"); + assert(index < 16); if (useCompartment1) _compartments1[index] &= ~STORE_VALUE(entity); diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp index 9e02b3bc1d..622d547542 100644 --- a/engines/lastexpress/game/inventory.cpp +++ b/engines/lastexpress/game/inventory.cpp @@ -40,7 +40,6 @@ #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" - namespace LastExpress { Inventory::Inventory(LastExpressEngine *engine) : _engine(engine), _selectedItem(kItemNone), _highlightedItemIndex(0), _itemsShown(0), @@ -534,18 +533,18 @@ Common::String Inventory::toString() { // Private methods ////////////////////////////////////////////////////////////////////////// InventoryItem Inventory::getFirstExaminableItem() const { - int index = 0; - InventoryEntry entry = _entries[index]; - while (!entry.inPocket || !entry.cursor || entry.floating) { - index++; - entry = _entries[index]; + do { + InventoryEntry entry = _entries[index]; - if (index >= kPortraitOriginal) - return kItemNone; - } + // Check if it is an examinable item + if (entry.inPocket && entry.cursor && !entry.floating) + return (InventoryItem)index; + + index++; + } while (index < kPortraitOriginal); - return (InventoryItem)index; + return kItemNone; } bool Inventory::isItemSceneParameter(InventoryItem item) const { diff --git a/engines/lastexpress/game/savepoint.cpp b/engines/lastexpress/game/savepoint.cpp index b0186a4ccc..a8483e6d5c 100644 --- a/engines/lastexpress/game/savepoint.cpp +++ b/engines/lastexpress/game/savepoint.cpp @@ -28,7 +28,6 @@ #include "lastexpress/lastexpress.h" - namespace LastExpress { SavePoints::SavePoints(LastExpressEngine *engine) : _engine(engine) { @@ -57,7 +56,7 @@ void SavePoints::push(EntityIndex entity2, EntityIndex entity1, ActionIndex acti _savepoints.push_back(point); } -void SavePoints::push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param) { +void SavePoints::push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const Common::String param) { if (_savepoints.size() >= _savePointsMaxSize) return; @@ -65,7 +64,9 @@ void SavePoints::push(EntityIndex entity2, EntityIndex entity1, ActionIndex acti point.entity1 = entity1; point.action = action; point.entity2 = entity2; - strcpy((char *)&point.param.charValue, param); + + assert(param.size() <= 5); + strncpy((char *)&point.param.charValue, param.c_str(), 5); _savepoints.push_back(point); } @@ -76,7 +77,6 @@ SavePoint SavePoints::pop() { return point; } - void SavePoints::pushAll(EntityIndex entity, ActionIndex action, uint32 param) { for (uint32 index = 1; index < 40; index++) { if ((EntityIndex)index != entity) @@ -156,16 +156,18 @@ void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex acti } } -void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param) const { +void SavePoints::call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const Common::String param) const { SavePoint point; point.entity1 = entity1; point.action = action; point.entity2 = entity2; - strcpy((char *)&point.param.charValue, param); + + assert(param.size() <= 5); + strncpy((char *)&point.param.charValue, param.c_str(), 5); Callback *callback = getCallback(entity1); if (callback != NULL && callback->isValid()) { - debugC(8, kLastExpressDebugLogic, "Savepoint: entity1=%s, action=%s, entity2=%s, param=%s", ENTITY_NAME(entity1), ACTION_NAME(action), ENTITY_NAME(entity2), param); + debugC(8, kLastExpressDebugLogic, "Savepoint: entity1=%s, action=%s, entity2=%s, param=%s", ENTITY_NAME(entity1), ACTION_NAME(action), ENTITY_NAME(entity2), param.c_str()); (*callback)(point); } } diff --git a/engines/lastexpress/game/savepoint.h b/engines/lastexpress/game/savepoint.h index 068c54eb0f..ab6490796b 100644 --- a/engines/lastexpress/game/savepoint.h +++ b/engines/lastexpress/game/savepoint.h @@ -101,7 +101,7 @@ public: // Savepoints void push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, uint32 param = 0); - void push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param); + void push(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const Common::String param); void pushAll(EntityIndex entity, ActionIndex action, uint32 param = 0); void process(); void reset(); @@ -113,7 +113,7 @@ public: void setCallback(EntityIndex index, Callback *callback); Callback *getCallback(EntityIndex entity) const; void call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, uint32 param = 0) const; - void call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const char *param) const; + void call(EntityIndex entity2, EntityIndex entity1, ActionIndex action, const Common::String param) const; void callAndProcess(); // Serializable diff --git a/engines/lastexpress/lastexpress.cpp b/engines/lastexpress/lastexpress.cpp index 293c3ab725..90b684ab0b 100644 --- a/engines/lastexpress/lastexpress.cpp +++ b/engines/lastexpress/lastexpress.cpp @@ -48,7 +48,7 @@ const char *g_actionNames[] = {"None", "Action1", "Action2", "ExitCompartment", "Action4", "ExcuseMeCath", "ExcuseMe", "INVALID", "Knock", "OpenDoor", "Action10", "Action11", "Default", "INVALID", "INVALID", "INVALID", "Action16", "DrawScene", "Callback"}; const char *g_directionNames[] = { "None", "Up", "Down", "Left", "Right", "Switch"}; -const char *g_entityNames[] = { "Player", "Anna", "August", "Mertens", "Coudert", "Pascale", "Servers0", "Servers1", "Cooks", "Verges", "Tatiana", "Vassili", "Alexei", "Abbot", "Milos", "Vesna", "Ivo", "Salko", "Kronos", "Kahina", "Francois", "MmeBoutarel", "Boutarel", "Rebecca", "Sophie", "Mahmud", "Yasmin", "Hadija", "Alouan", "Gendarmes", "Max", "Chapters", "Train", "Tables0", "Tables1", "Tables2", "Tables3", "Tables4", "Tables5", "Entity39"}; +const char *g_entityNames[] = { "Player", "Anna", "August", "Mertens", "Coudert", "Pascale", "Waiter1", "Waiter2", "Cooks", "Verges", "Tatiana", "Vassili", "Alexei", "Abbot", "Milos", "Vesna", "Ivo", "Salko", "Kronos", "Kahina", "Francois", "MmeBoutarel", "Boutarel", "Rebecca", "Sophie", "Mahmud", "Yasmin", "Hadija", "Alouan", "Gendarmes", "Max", "Chapters", "Train", "Tables0", "Tables1", "Tables2", "Tables3", "Tables4", "Tables5", "Entity39"}; namespace LastExpress { diff --git a/engines/lastexpress/module.mk b/engines/lastexpress/module.mk index 8b3287d5d7..afce0b0749 100644 --- a/engines/lastexpress/module.mk +++ b/engines/lastexpress/module.mk @@ -35,8 +35,6 @@ MODULE_OBJS := \ entities/pascale.o \ entities/rebecca.o \ entities/salko.o \ - entities/servers0.o \ - entities/servers1.o \ entities/sophie.o \ entities/tables.o \ entities/tatiana.o \ @@ -44,6 +42,8 @@ MODULE_OBJS := \ entities/vassili.o \ entities/verges.o \ entities/vesna.o \ + entities/waiter1.o \ + entities/waiter2.o \ entities/yasmin.o \ fight/fight.o \ fight/fighter.o \ diff --git a/engines/lastexpress/shared.h b/engines/lastexpress/shared.h index c0099db7ac..724c4b3fb4 100644 --- a/engines/lastexpress/shared.h +++ b/engines/lastexpress/shared.h @@ -1006,8 +1006,8 @@ enum EntityIndex { kEntityMertens, kEntityCoudert, kEntityPascale, // 5 - kEntityServers0, - kEntityServers1, + kEntityWaiter1, + kEntityWaiter2, kEntityCooks, kEntityVerges, kEntityTatiana, // 10 @@ -1409,7 +1409,7 @@ enum ActionIndex { kAction169032608 = 169032608, kAction189426612 = 189426612, kAction203859488 = 203859488, - kAction219522616 = 219522616, // Servers0 + kAction219522616 = 219522616, // Waiter1 kAction225182640 = 225182640, kAction235257824 = 235257824, @@ -1520,7 +1520,7 @@ enum ActionIndex { kAction71277948 = 71277948, kAction158007856 = 158007856, kAction101687594 = 101687594, - kAction122358304 = 122358304, // also Servers1/Boutarel? + kAction122358304 = 122358304, // also Waiter2/Boutarel? kActionMaxFreeFromCage = 135204609, kAction156622016 = 156622016, diff --git a/engines/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp index 6bf1ebc9de..697e6e1269 100644 --- a/engines/lastexpress/sound/entry.cpp +++ b/engines/lastexpress/sound/entry.cpp @@ -33,7 +33,6 @@ #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" - namespace LastExpress { #define SOUNDCACHE_ENTRY_SIZE 92160 @@ -267,6 +266,8 @@ void SoundEntry::update(uint val) { } bool SoundEntry::updateSound() { + assert(_name2.size() <= 16); + bool result; char sub[16]; @@ -279,6 +280,7 @@ bool SoundEntry::updateSound() { _status.status &= ~0x8000; strcpy(sub, _name2.c_str()); + // FIXME: Rewrite and document expected behavior int l = strlen(sub) + 1; if (l - 1 > 4) sub[l - (1 + 4)] = 0; @@ -361,7 +363,10 @@ void SoundEntry::showSubtitle(Common::String filename) { } void SoundEntry::saveLoadWithSerializer(Common::Serializer &s) { - if (_name2.matchString("NISSND?") && (_status.status & kFlagType7) != kFlag3) { + assert(_name1.size() <= 16); + assert(_name2.size() <= 16); + + if (_name2.matchString("NISSND?") && (_status.status & kFlagType9) != kFlag3) { s.syncAsUint32LE(_status.status); s.syncAsUint32LE(_type); s.syncAsUint32LE(_blockCount); // field_8; diff --git a/engines/lastexpress/sound/sound.cpp b/engines/lastexpress/sound/sound.cpp index 5f55f4e74e..3a2d0c075c 100644 --- a/engines/lastexpress/sound/sound.cpp +++ b/engines/lastexpress/sound/sound.cpp @@ -984,22 +984,22 @@ void SoundManager::excuseMe(EntityIndex entity, EntityIndex entity2, SoundFlag f playSound(kEntityPlayer, (rnd(2) ? "HDE1002" : "HED1002A"), flag); break; - case kEntityServers0: - case kEntityServers1: + case kEntityWaiter1: + case kEntityWaiter2: switch(rnd(3)) { default: break; case 0: - playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002" : "WAT1003", flag); + playSound(kEntityPlayer, (entity == kEntityWaiter1) ? "WAT1002" : "WAT1003", flag); break; case 1: - playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002A" : "WAT1003A", flag); + playSound(kEntityPlayer, (entity == kEntityWaiter1) ? "WAT1002A" : "WAT1003A", flag); break; case 2: - playSound(kEntityPlayer, (entity == kEntityServers0) ? "WAT1002B" : "WAT1003B", flag); + playSound(kEntityPlayer, (entity == kEntityWaiter1) ? "WAT1002B" : "WAT1003B", flag); break; } break; diff --git a/engines/made/database.cpp b/engines/made/database.cpp index 85a8a5ca4a..a9855ba1fe 100644 --- a/engines/made/database.cpp +++ b/engines/made/database.cpp @@ -456,7 +456,7 @@ void GameDatabaseV2::load(Common::SeekableReadStream &sourceS) { for (int section = 0; section < 2; section++) { while (!sourceS.eos()) { int16 objIndex = sourceS.readUint16LE(); - debug("objIndex = %04X; section = %d", objIndex, section); + debug(1, "objIndex = %04X; section = %d", objIndex, section); if (objIndex == 0) break; Object *obj = new ObjectV1(); diff --git a/engines/made/resource.cpp b/engines/made/resource.cpp index 1bb328c7a2..2c75965976 100644 --- a/engines/made/resource.cpp +++ b/engines/made/resource.cpp @@ -441,7 +441,8 @@ void ResourceReader::openResourceBlocks() { } void ResourceReader::openResourceBlock(const char *filename, Common::File *blockFile, uint32 resType) { - blockFile->open(filename); + if (!blockFile->open(filename)) + error("Failed to open '%s'", filename); blockFile->readUint16LE(); // Skip unused uint16 count = blockFile->readUint16LE(); diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp index c27b781dda..edccb68953 100644 --- a/engines/made/screen.cpp +++ b/engines/made/screen.cpp @@ -368,6 +368,9 @@ uint16 Screen::drawFlex(uint16 flexIndex, int16 x, int16 y, int16 flipX, int16 f return 0; PictureResource *flex = _vm->_res->getPicture(flexIndex); + if (!flex) + error("Failed to find picture %d", flexIndex); + Graphics::Surface *sourceSurface = flex->getPicture(); drawSurface(sourceSurface, x, y, flipX, flipY, mask, clipInfo); diff --git a/engines/mads/debugger.cpp b/engines/mads/debugger.cpp index 1ff42c5e2b..6bc6cf572d 100644 --- a/engines/mads/debugger.cpp +++ b/engines/mads/debugger.cpp @@ -21,6 +21,7 @@ */ #include "common/file.h" +#include "mads/compression.h" #include "mads/mads.h" #include "mads/debugger.h" @@ -169,8 +170,10 @@ bool Debugger::Cmd_ShowCodes(int argc, const char **argv) { } bool Debugger::Cmd_DumpFile(int argc, const char **argv) { - if (argc != 2) { - debugPrintf("Usage: %s <resource>\n", argv[0]); + if (argc < 2) { + debugPrintf("Usage: %s <resource> <unpack>\n", argv[0]); + debugPrintf(" resource: the resource name\n"); + debugPrintf(" unpack: optional, when specified, the FAB/MADSPACK compressed resource is unpacked\n"); } else { Common::DumpFile outFile; Common::File inFile; @@ -179,10 +182,32 @@ bool Debugger::Cmd_DumpFile(int argc, const char **argv) { debugPrintf("Specified resource does not exist\n"); } else { outFile.open(argv[1]); - byte *data = new byte[inFile.size()]; - - inFile.read(data, inFile.size()); - outFile.write(data, inFile.size()); + bool unpack = ((argc >= 3) && !scumm_stricmp(argv[2], "unpack")); + + byte *data; + int totalSize = 0; + + if (!unpack) { + totalSize = inFile.size(); + data = new byte[totalSize]; + inFile.read(data, totalSize); + } else { + MadsPack dataPack(&inFile); + int count = dataPack.getCount(); + for (int i = 0; i < count; i++) { + totalSize += dataPack.getItem(i)._size; + } + data = new byte[totalSize]; + byte *ptr = data; + + for (int i = 0; i < count; i++) { + Common::SeekableReadStream *readStream = dataPack.getItemStream(i); + readStream->read(ptr, readStream->size()); + ptr += readStream->size(); + } + } + + outFile.write(data, totalSize); outFile.flush(); delete[] data; diff --git a/engines/mads/dialogs.h b/engines/mads/dialogs.h index aad29f6551..c586a6f1fe 100644 --- a/engines/mads/dialogs.h +++ b/engines/mads/dialogs.h @@ -201,7 +201,9 @@ public: enum DialogId { DIALOG_NONE = 0, DIALOG_GAME_MENU = 1, DIALOG_SAVE = 2, DIALOG_RESTORE = 3, - DIALOG_OPTIONS = 4, DIALOG_DIFFICULTY = 5, DIALOG_ERROR = 6 + DIALOG_OPTIONS = 4, DIALOG_DIFFICULTY = 5, DIALOG_ERROR = 6, + DIALOG_MAIN_MENU = 7, DIALOG_TEXTVIEW = 8, DIALOG_ANIMVIEW = 9, + DIALOG_ADVERT = 10 }; class Dialogs { diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.cpp b/engines/mads/dragonsphere/dragonsphere_scenes.cpp index 59d7914378..f32d17d9c9 100644 --- a/engines/mads/dragonsphere/dragonsphere_scenes.cpp +++ b/engines/mads/dragonsphere/dragonsphere_scenes.cpp @@ -201,9 +201,10 @@ Common::String DragonsphereScene::formAnimName(char sepChar, int suffixNum) { /*------------------------------------------------------------------------*/ void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) { - File f(Resources::formatName(RESPREFIX_RM, _sceneId, ".DAT")); + Common::String ext = Common::String::format(".WW%d", variant); + File f(Resources::formatName(RESPREFIX_RM, _sceneId, ext)); MadsPack codesPack(&f); - Common::SeekableReadStream *stream = codesPack.getItemStream(variant + 1); + Common::SeekableReadStream *stream = codesPack.getItemStream(0); loadCodes(depthSurface, stream); @@ -213,22 +214,20 @@ void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) { void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) { byte *destP = depthSurface.getData(); - byte *endP = depthSurface.getBasePtr(0, depthSurface.h); - - byte runLength = stream->readByte(); - while (destP < endP && runLength > 0) { - byte runValue = stream->readByte(); - - // Write out the run length - Common::fill(destP, destP + runLength, runValue); - destP += runLength; - - // Get the next run length - runLength = stream->readByte(); + byte *walkMap = new byte[stream->size()]; + stream->read(walkMap, stream->size()); + + for (int y = 0; y < 156; ++y) { + for (int x = 0; x < 320; ++x) { + int offset = x + (y * 320); + if ((walkMap[offset / 8] << (offset % 8)) & 0x80) + *destP++ = 1; // walkable + else + *destP++ = 0; + } } - if (destP < endP) - Common::fill(destP, endP, 0); + delete[] walkMap; } } // End of namespace Dragonsphere diff --git a/engines/mads/dragonsphere/game_dragonsphere.cpp b/engines/mads/dragonsphere/game_dragonsphere.cpp index 9d9b48dd66..3836adb6d2 100644 --- a/engines/mads/dragonsphere/game_dragonsphere.cpp +++ b/engines/mads/dragonsphere/game_dragonsphere.cpp @@ -42,6 +42,10 @@ GameDragonsphere::GameDragonsphere(MADSEngine *vm) } void GameDragonsphere::startGame() { + _scene._priorSceneId = 0; + _scene._currentSceneId = -1; + _scene._nextSceneId = 101; + initializeGlobals(); } diff --git a/engines/mads/events.cpp b/engines/mads/events.cpp index c3e6d5c122..de4dc3c070 100644 --- a/engines/mads/events.cpp +++ b/engines/mads/events.cpp @@ -46,6 +46,7 @@ EventsManager::EventsManager(MADSEngine *vm) { _mouseMoved = false; _vD8 = 0; _rightMousePressed = false; + _eventTarget = nullptr; } EventsManager::~EventsManager() { @@ -138,6 +139,12 @@ void EventsManager::pollEvents() { Common::Event event; while (g_system->getEventManager()->pollEvent(event)) { + // If an event target is specified, pass the event to it + if (_eventTarget) { + _eventTarget->onEvent(event); + continue; + } + // Handle keypress switch (event.type) { case Common::EVENT_QUIT: @@ -191,7 +198,7 @@ void EventsManager::pollEvents() { } } -void EventsManager::checkForNextFrameCounter() { +bool EventsManager::checkForNextFrameCounter() { // Check for next game frame uint32 milli = g_system->getMillis(); if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) { @@ -209,7 +216,11 @@ void EventsManager::checkForNextFrameCounter() { // Signal the ScummVM debugger _vm->_debugger->onFrame(); + + return true; } + + return false; } void EventsManager::delay(int cycles) { diff --git a/engines/mads/events.h b/engines/mads/events.h index 3d7504c0bd..54df337efd 100644 --- a/engines/mads/events.h +++ b/engines/mads/events.h @@ -39,6 +39,12 @@ enum CursorType { CURSOR_NONE = 0, CURSOR_ARROW = 1, CURSOR_WAIT = 2, CURSOR_GO_ class MADSEngine; +class EventTarget { +public: + virtual ~EventTarget() {} + virtual bool onEvent(Common::Event &event) { return false; } +}; + class EventsManager { private: MADSEngine *_vm; @@ -46,16 +52,12 @@ private: uint32 _priorFrameTime; Common::Point _mousePos; Common::Point _currentPos; + EventTarget *_eventTarget; /** * Updates the cursor image when the current cursor changes */ void changeCursor(); - - /** - * Checks for whether the next game frame number has been reached. - */ - void checkForNextFrameCounter(); public: SpriteAsset *_cursorSprites; CursorType _cursorId; @@ -127,6 +129,11 @@ public: void pollEvents(); /** + * Sets an event handler other than the events manager + */ + void setEventTarget(EventTarget *target) { _eventTarget = target; } + + /** * Return the current mouse position */ Common::Point mousePos() const { return _mousePos; } @@ -147,6 +154,11 @@ public: void waitForNextFrame(); /** + * Checks for whether the next game frame number has been reached. + */ + bool checkForNextFrameCounter(); + + /** * Gets the current frame counter */ uint32 getFrameCounter() const { return _frameCounter; } diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp index 8639f59418..b544eff2db 100644 --- a/engines/mads/game.cpp +++ b/engines/mads/game.cpp @@ -64,6 +64,7 @@ Game::Game(MADSEngine *vm) _loadGameSlot = -1; _lastSave = -1; _saveFile = nullptr; + _saveThumb = nullptr; _statusFlag = 0; _sectionHandler = nullptr; _sectionNumber = 1; @@ -93,6 +94,11 @@ Game::Game(MADSEngine *vm) } Game::~Game() { + if (_saveThumb) { + _saveThumb->free(); + delete _saveThumb; + } + delete _saveFile; delete _surface; delete _sectionHandler; @@ -548,16 +554,14 @@ void Game::writeSavegameHeader(Common::OutSaveFile *out, MADSSavegameHeader &hea out->write(header._saveName.c_str(), header._saveName.size()); out->writeByte('\0'); - // Get the active palette - uint8 thumbPalette[256 * 3]; - g_system->getPaletteManager()->grabPalette(thumbPalette, 0, 256); - - // Create a thumbnail and save it - Graphics::Surface *thumb = new Graphics::Surface(); - ::createThumbnail(thumb, _vm->_screen.getData(), MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT, thumbPalette); - Graphics::saveThumbnail(*out, *thumb); - thumb->free(); - delete thumb; + // Handle the thumbnail. If there's already one set by the game, create one + if (!_saveThumb) + createThumbnail(); + Graphics::saveThumbnail(*out, *_saveThumb); + + _saveThumb->free(); + delete _saveThumb; + _saveThumb = nullptr; // Write out the save date/time TimeDate td; @@ -570,4 +574,16 @@ void Game::writeSavegameHeader(Common::OutSaveFile *out, MADSSavegameHeader &hea out->writeUint32LE(_vm->_events->getFrameCounter()); } +void Game::createThumbnail() { + if (_saveThumb) { + _saveThumb->free(); + delete _saveThumb; + } + + uint8 thumbPalette[PALETTE_SIZE]; + _vm->_palette->grabPalette(thumbPalette, 0, PALETTE_COUNT); + _saveThumb = new Graphics::Surface(); + ::createThumbnail(_saveThumb, _vm->_screen.getData(), MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT, thumbPalette); +} + } // End of namespace MADS diff --git a/engines/mads/game.h b/engines/mads/game.h index 08cd7e7843..1a61fc8ac8 100644 --- a/engines/mads/game.h +++ b/engines/mads/game.h @@ -82,6 +82,7 @@ protected: int _lastSave; Common::String _saveName; Common::InSaveFile *_saveFile; + Graphics::Surface *_saveThumb; /** * Constructor @@ -226,6 +227,11 @@ public: * Read in a savegame header */ static bool readSavegameHeader(Common::InSaveFile *in, MADSSavegameHeader &header); + + /** + * Creates a temporary thumbnail for use in saving games + */ + void createThumbnail(); }; } // End of namespace MADS diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp index 59eec40bcc..d56994ab8e 100644 --- a/engines/mads/mads.cpp +++ b/engines/mads/mads.cpp @@ -55,6 +55,7 @@ MADSEngine::MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc) : _resources = nullptr; _sound = nullptr; _audio = nullptr; + _opl = nullptr; } MADSEngine::~MADSEngine() { @@ -68,6 +69,9 @@ MADSEngine::~MADSEngine() { delete _resources; delete _sound; delete _audio; + + _mixer->stopAll(); + delete _opl; } void MADSEngine::initialize() { @@ -76,6 +80,9 @@ void MADSEngine::initialize() { DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts"); DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics handling"); + _opl = OPL::Config::create(); + _opl->init(11025); + // Initial sub-system engine references MSurface::setVm(this); MSprite::setVm(this); @@ -89,7 +96,7 @@ void MADSEngine::initialize() { Font::init(this); _font = new Font(); _screen.init(); - _sound = new SoundManager(this, _mixer); + _sound = new SoundManager(this, _mixer, _opl); _audio = new AudioPlayer(_mixer, getGameID()); _game = Game::init(this); @@ -103,9 +110,6 @@ Common::Error MADSEngine::run() { // Run the game _game->run(); - // Dummy loop to keep application active - _events->delay(9999); - return Common::kNoError; } diff --git a/engines/mads/mads.h b/engines/mads/mads.h index 9a8f2152a1..8fc2788c28 100644 --- a/engines/mads/mads.h +++ b/engines/mads/mads.h @@ -99,6 +99,7 @@ public: ScreenSurface _screen; SoundManager *_sound; AudioPlayer *_audio; + FM_OPL *_opl; bool _easyMouse; bool _invObjectsAnimated; bool _textWindowStill; diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp index 9b2d6f3114..e83b69d210 100644 --- a/engines/mads/messages.cpp +++ b/engines/mads/messages.cpp @@ -546,10 +546,9 @@ void TextDisplayList::draw(MSurface *s) { for (uint idx = 0; idx < size(); ++idx) { TextDisplay &td = (*this)[idx]; if (td._active && (td._expire >= 0)) { + Common::Point destPos(td._bounds.left, td._bounds.top); td._font->setColors(0xFF, td._color1, td._color2, 0); - td._font->writeString(s, td._msg, - Common::Point(td._bounds.left, td._bounds.top), - td._spacing, td._bounds.width()); + td._font->writeString(s, td._msg, destPos, td._spacing, td._bounds.width()); } } } diff --git a/engines/mads/module.mk b/engines/mads/module.mk index 61e810e215..96353e9ae5 100644 --- a/engines/mads/module.mk +++ b/engines/mads/module.mk @@ -8,6 +8,7 @@ MODULE_OBJS := \ nebular/dialogs_nebular.o \ nebular/game_nebular.o \ nebular/globals_nebular.o \ + nebular/menu_nebular.o \ nebular/sound_nebular.o \ nebular/nebular_scenes.o \ nebular/nebular_scenes1.o \ diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp index 18a9a4f547..349f4a5f23 100644 --- a/engines/mads/msurface.cpp +++ b/engines/mads/msurface.cpp @@ -527,7 +527,7 @@ MSurface *MSurface::flipHorizontal() const { /*------------------------------------------------------------------------*/ int DepthSurface::getDepth(const Common::Point &pt) { - if (_vm->_game->_scene._sceneInfo->_depthStyle == 2) { + if (_depthStyle == 2) { int bits = (3 - (pt.x % 4)) * 2; byte v = *getBasePtr(pt.x >> 2, pt.y); return v >> bits; @@ -540,7 +540,7 @@ int DepthSurface::getDepth(const Common::Point &pt) { } int DepthSurface::getDepthHighBit(const Common::Point &pt) { - if (_vm->_game->_scene._sceneInfo->_depthStyle == 2) { + if (_depthStyle == 2) { int bits = (3 - (pt.x % 4)) * 2; byte v = *getBasePtr(pt.x >> 2, pt.y); return (v >> bits) & 2; @@ -552,5 +552,4 @@ int DepthSurface::getDepthHighBit(const Common::Point &pt) { } } - } // End of namespace MADS diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h index ef2bbd6784..3a5bf22eed 100644 --- a/engines/mads/msurface.h +++ b/engines/mads/msurface.h @@ -51,10 +51,9 @@ struct SpriteInfo { * MADS graphics surface */ class MSurface : public Graphics::Surface { -private: - bool _freeFlag; protected: static MADSEngine *_vm; + bool _freeFlag; public: /** * Sets the engine refrence used all surfaces @@ -223,9 +222,14 @@ private: MADSEngine *_vm; public: /** + * Depth style + */ + int _depthStyle; + + /** * Constructor */ - DepthSurface(MADSEngine *vm) : _vm(vm) {} + DepthSurface(MADSEngine *vm) : _vm(vm), _depthStyle(0) {} /** * Returns the depth at a given position diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp index 99fa01c34f..35a7d3bdc6 100644 --- a/engines/mads/nebular/dialogs_nebular.cpp +++ b/engines/mads/nebular/dialogs_nebular.cpp @@ -23,12 +23,17 @@ #include "common/scummsys.h" #include "common/config-manager.h" #include "common/util.h" +#include "common/translation.h" + +#include "gui/saveload.h" + #include "mads/mads.h" #include "mads/screen.h" #include "mads/msurface.h" #include "mads/staticres.h" #include "mads/nebular/dialogs_nebular.h" #include "mads/nebular/game_nebular.h" +#include "mads/nebular/menu_nebular.h" namespace MADS { @@ -265,20 +270,99 @@ bool DialogsNebular::commandCheck(const char *idStr, Common::String &valStr, } void DialogsNebular::showDialog() { - switch (_pendingDialog) { - case DIALOG_GAME_MENU: - //GameMenuDialog::show(); - break; - case DIALOG_DIFFICULTY: { -/* - DifficultyDialog *dlg = new DifficultyDialog(_vm); - dlg->show(); - delete dlg; -*/ - break; + while (_pendingDialog != DIALOG_NONE && !_vm->shouldQuit()) { + DialogId dialogId = _pendingDialog; + _pendingDialog = DIALOG_NONE; + + switch (dialogId) { + case DIALOG_MAIN_MENU: { + MainMenu *menu = new MainMenu(_vm); + menu->show(); + delete menu; + break; + } + case DIALOG_DIFFICULTY: { + DifficultyDialog *dlg = new DifficultyDialog(_vm); + dlg->show(); + delete dlg; + break; + } + case DIALOG_GAME_MENU: { + GameMenuDialog *dlg = new GameMenuDialog(_vm); + dlg->show(); + delete dlg; + break; + } + case DIALOG_SAVE: { + showScummVMSaveDialog(); + break; + } + case DIALOG_RESTORE: { + showScummVMRestoreDialog(); + break; + } + case DIALOG_OPTIONS: { + OptionsDialog *dlg = new OptionsDialog(_vm); + dlg->show(); + delete dlg; + break; + } + case DIALOG_ADVERT: { + AdvertView *dlg = new AdvertView(_vm); + dlg->show(); + delete dlg; + break; + } + case DIALOG_TEXTVIEW: { + TextView *dlg = new TextView(_vm); + dlg->show(); + delete dlg; + break; + } + case DIALOG_ANIMVIEW: { + AnimationView *dlg = new AnimationView(_vm); + dlg->show(); + delete dlg; + break; + } + default: + break; + } } - default: - break; +} + +void DialogsNebular::showScummVMSaveDialog() { + Nebular::GameNebular &game = *(Nebular::GameNebular *)_vm->_game; + Scene *scene = &(game._scene); + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); + + int slot = dialog->runModalWithCurrentTarget(); + if (slot >= 0) { + Common::String desc = dialog->getResultString(); + + if (desc.empty()) { + // create our own description for the saved game, the user didn't enter it + desc = dialog->createDefaultSaveDescription(slot); + } + + scene->_spriteSlots.reset(); + scene->loadScene(scene->_currentSceneId, game._aaName, true); + scene->_userInterface.noInventoryAnim(); + game._scene.drawElements(kTransitionFadeIn, false); + + game.saveGame(slot, desc); + } +} + +void DialogsNebular::showScummVMRestoreDialog() { + Nebular::GameNebular &game = *(Nebular::GameNebular *)_vm->_game; + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); + + int slot = dialog->runModalWithCurrentTarget(); + if (slot >= 0) { + game._loadGameSlot = slot; + game._scene._currentSceneId = -1; + game._currentSectionNumber = -1; } } @@ -469,15 +553,78 @@ void PictureDialog::restore() { /*------------------------------------------------------------------------*/ -ScreenDialog::DialogLine::DialogLine() { +FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) { + _screenId = 990; + _palFlag = true; +} + +FullScreenDialog::~FullScreenDialog() { + _vm->_screen.resetClipBounds(); + _vm->_game->_scene.restrictScene(); +} + +void FullScreenDialog::display() { + Game &game = *_vm->_game; + Scene &scene = game._scene; + + int nextSceneId = scene._nextSceneId; + int currentSceneId = scene._currentSceneId; + int priorSceneId = scene._priorSceneId; + + if (_screenId > 0) { + SceneInfo *sceneInfo = SceneInfo::init(_vm); + sceneInfo->load(_screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface); + } + + scene._priorSceneId = priorSceneId; + scene._currentSceneId = currentSceneId; + scene._nextSceneId = nextSceneId; + + _vm->_events->initVars(); + game._kernelMode = KERNEL_ROOM_INIT; + + byte pal[768]; + if (_vm->_screenFade) { + Common::fill(&pal[0], &pal[PALETTE_SIZE], 0); + _vm->_palette->setFullPalette(pal); + } else { + _vm->_palette->getFullPalette(pal); + _vm->_palette->fadeOut(pal, nullptr, 0, PALETTE_COUNT, 0, 1, 1, 16); + } + + // Set Fx state and palette entries + game._fx = _vm->_screenFade == SCREEN_FADE_SMOOTH ? kTransitionFadeIn : kCenterVertTransition; + game._trigger = 0; + + // Clear the screen and draw the upper and lower horizontal lines + _vm->_screen.empty(); + _vm->_palette->setLowRange(); + _vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2); + _vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2); + _vm->_screen.copyRectToScreen(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT)); + + // Restrict the screen to the area between the two lines + _vm->_screen.setClipBounds(Common::Rect(0, DIALOG_TOP, MADS_SCREEN_WIDTH, + DIALOG_TOP + MADS_SCENE_HEIGHT)); + _vm->_game->_scene.restrictScene(); + + if (_screenId > 0) + scene._spriteSlots.fullRefresh(); +} + +/*------------------------------------------------------------------------*/ + +GameDialog::DialogLine::DialogLine() { _active = true; _state = DLGSTATE_UNSELECTED; _textDisplayIndex = -1; _font = nullptr; _widthAdjust = 0; + _msg = ""; } -ScreenDialog::DialogLine::DialogLine(const Common::String &s) { +GameDialog::DialogLine::DialogLine(const Common::String &s) { + _active = true; _state = DLGSTATE_UNSELECTED; _textDisplayIndex = -1; _font = nullptr; @@ -487,16 +634,17 @@ ScreenDialog::DialogLine::DialogLine(const Common::String &s) { /*------------------------------------------------------------------------*/ -ScreenDialog::ScreenDialog(MADSEngine *vm) : _vm(vm) { +GameDialog::GameDialog(MADSEngine *vm) : FullScreenDialog(vm) { Game &game = *_vm->_game; Scene &scene = game._scene; - _v1 = 0; - _v2 = 0; - _v3 = false; - _selectedLine = 0; + _tempLine = 0; + _movedFlag = false; + _redrawFlag = false; + _selectedLine = -1; _dirFlag = false; _textLineCount = 0; + _lineIndex = -1; _screenId = 920; chooseBackground(); @@ -508,64 +656,42 @@ ScreenDialog::ScreenDialog(MADSEngine *vm) : _vm(vm) { scene.clearVocab(); scene._dynamicHotspots.clear(); _vm->_dialogs->_defaultPosition = Common::Point(-1, -1); + _menuSpritesIndex = 0; +} - bool palFlag = false; - int nextSceneId = scene._nextSceneId; - int currentSceneId = scene._currentSceneId; - int priorSceneId = scene._priorSceneId; - - if (_vm->_dialogs->_pendingDialog == DIALOG_DIFFICULTY) { - palFlag = true; - } else { - _vm->_palette->initPalette(); - } - scene.loadScene(_screenId, game._aaName, palFlag); +void GameDialog::display() { + FullScreenDialog::display(); - scene._priorSceneId = priorSceneId; - scene._currentSceneId = currentSceneId; - scene._nextSceneId = nextSceneId; - scene._posAdjust.y = 22; - _vm->_sound->pauseNewCommands(); - _vm->_events->initVars(); - game._kernelMode = KERNEL_ROOM_INIT; + Palette &palette = *_vm->_palette; + palette.setEntry(10, 0, 63, 0); + palette.setEntry(11, 0, 45, 0); + palette.setEntry(12, 63, 63, 0); + palette.setEntry(13, 45, 45, 0); + palette.setEntry(14, 63, 63, 63); + palette.setEntry(15, 45, 45, 45); + Scene &scene = _vm->_game->_scene; SpriteAsset *menuSprites = new SpriteAsset(_vm, "*MENU", 0); _menuSpritesIndex = scene._sprites.add(menuSprites); - byte pal[768]; - if (_vm->_screenFade) { - Common::fill(&pal[0], &pal[PALETTE_SIZE], 0); - _vm->_palette->setFullPalette(pal); - } else { - _vm->_palette->getFullPalette(pal); - _vm->_palette->fadeOut(pal, nullptr, 0, PALETTE_COUNT, 0, 1, 1, 16); - } - - _vm->_screen.empty(); - _vm->_screen.hLine(0, 0, MADS_SCREEN_WIDTH, 2); + _lineIndex = -1; + setClickableLines(); - game._fx = _vm->_screenFade == SCREEN_FADE_SMOOTH ? kTransitionFadeIn : kCenterVertTransition; - game._trigger = 0; _vm->_events->setCursor(CURSOR_ARROW); +} - _vm->_palette->setEntry(10, 0, 63, 0); - _vm->_palette->setEntry(11, 0, 45, 0); - _vm->_palette->setEntry(12, 63, 63, 0); - _vm->_palette->setEntry(13, 45, 45, 0); - _vm->_palette->setEntry(14, 63, 63, 63); - _vm->_palette->setEntry(15, 45, 45, 45); - - _lineIndex = -1; +GameDialog::~GameDialog() { + _vm->_screen.resetClipBounds(); } -void ScreenDialog::clearLines() { +void GameDialog::clearLines() { Scene &scene = _vm->_game->_scene; - _v2 = 0; + _movedFlag = false; _lines.clear(); scene._spriteSlots.fullRefresh(true); } -void ScreenDialog::setClickableLines() { +void GameDialog::setClickableLines() { ScreenObjects &screenObjects = _vm->_game->_screenObjects; for (uint idx = 0; idx < _lines.size(); ++idx) { @@ -586,19 +712,17 @@ void ScreenDialog::setClickableLines() { } } -void ScreenDialog::addQuote(int id1, int id2, DialogTextAlign align, +void GameDialog::addQuote(int id1, int id2, DialogTextAlign align, const Common::Point &pt, Font *font) { - Common::String msg = _vm->_game->getQuote(id1); + Common::String msg = _vm->_game->getQuote(id1).c_str(); // c_str() because we need a copy - if (id2 > 0) { - msg += " "; + if (id2 > 0) msg += _vm->_game->getQuote(id2); - } addLine(msg, align, pt, font); } -void ScreenDialog::addLine(const Common::String &msg, DialogTextAlign align, +void GameDialog::addLine(const Common::String &msg, DialogTextAlign align, const Common::Point &pt, Font *font) { Scene &scene = _vm->_game->_scene; DialogLine *line; @@ -641,6 +765,10 @@ void ScreenDialog::addLine(const Common::String &msg, DialogTextAlign align, int xOffset; switch (align) { + case ALIGN_NONE: + // No adjustment + break; + case ALIGN_CENTER: xOffset = (MADS_SCREEN_WIDTH / 2) - font->getWidth(msg, -1) / 2; line->_pos.x += xOffset; @@ -653,6 +781,10 @@ void ScreenDialog::addLine(const Common::String &msg, DialogTextAlign align, xOffset = (MADS_SCREEN_WIDTH / 2) - font->getWidth( Common::String(msgP, ch), line->_widthAdjust); line->_pos.x += xOffset; + + Common::String newMsg = msg.c_str(); + newMsg.deleteChar(ch - msgP); + line->_msg = newMsg; } break; } @@ -669,14 +801,14 @@ void ScreenDialog::addLine(const Common::String &msg, DialogTextAlign align, ++_lineIndex; } -void ScreenDialog::initVars() { - _v1 = -1; +void GameDialog::initVars() { + _tempLine = -1; _selectedLine = -1; _lineIndex = 0; _textLineCount = 0; } -void ScreenDialog::chooseBackground() { +void GameDialog::chooseBackground() { switch (_vm->_game->_currentSectionNumber) { case 1: case 2: @@ -700,27 +832,35 @@ void ScreenDialog::chooseBackground() { } } -void ScreenDialog::setFrame(int frameNumber, int depth) { +void GameDialog::setFrame(int frameNumber, int depth) { Scene &scene = _vm->_game->_scene; + SpriteAsset *menuSprites = scene._sprites[_menuSpritesIndex]; + MSprite *frame = menuSprites->getFrame(frameNumber - 1); + SpriteSlot &spriteSlot = scene._spriteSlots[scene._spriteSlots.add()]; spriteSlot._flags = IMG_UPDATE; spriteSlot._seqIndex = 1; spriteSlot._spritesIndex = _menuSpritesIndex; spriteSlot._frameNumber = frameNumber; + spriteSlot._position = frame->_offset; + spriteSlot._depth = depth; + spriteSlot._scale = 100; } -void ScreenDialog::show() { +void GameDialog::show() { + display(); + Scene &scene = _vm->_game->_scene; while (_selectedLine < 1 && !_vm->shouldQuit()) { handleEvents(); - if (_v3) { - if (!_v1) - _v1 = -1; + if (_redrawFlag) { + if (!_tempLine) + _tempLine = -1; refreshText(); scene.drawElements(_vm->_game->_fx, _vm->_game->_fx); - _v3 = false; + _redrawFlag = false; } _vm->_events->waitForNextFrame(); @@ -728,11 +868,11 @@ void ScreenDialog::show() { } } -void ScreenDialog::handleEvents() { +void GameDialog::handleEvents() { ScreenObjects &screenObjects = _vm->_game->_screenObjects; EventsManager &events = *_vm->_events; Nebular::DialogsNebular &dialogs = *(Nebular::DialogsNebular *)_vm->_dialogs; - int v1 = _v1; + int tempLine = _tempLine; // Mark all the lines as initially unselected for (uint i = 0; i < _lines.size(); ++i) @@ -742,10 +882,11 @@ void ScreenDialog::handleEvents() { _vm->_events->pollEvents(); // Scan for objects in the dialog - int objIndex = screenObjects.scan(events.currentPos() - _vm->_screen._offset, LAYER_GUI); + Common::Point mousePos = events.currentPos() - Common::Point(0, DIALOG_TOP); + int objIndex = screenObjects.scan(mousePos, LAYER_GUI); - if (_v2) { - int yp = events.currentPos().y - _vm->_screen._offset.y; + if (_movedFlag) { + int yp = mousePos.y; if (yp < screenObjects[1]._bounds.top) { if (!events._mouseReleased) _lines[1]._state = DLGSTATE_SELECTED; @@ -760,7 +901,7 @@ void ScreenDialog::handleEvents() { } int line = -1; - if (objIndex > 0 || events._mouseButtons) { + if (objIndex > 0 && (events._mouseStatus || events._mouseReleased)) { line = screenObjects[objIndex]._descId; if (dialogs._pendingDialog == DIALOG_SAVE || dialogs._pendingDialog == DIALOG_RESTORE) { if (line > 7 && line <= 14) { @@ -768,9 +909,9 @@ void ScreenDialog::handleEvents() { line -= 7; } - int v2 = (line > 0 && line < 8) ? 1 : 0; + bool movedFlag = line > 0 && line < 8; if (events._mouseMoved) - _v2 = v2; + _movedFlag = movedFlag; } if (screenObjects[objIndex]._category == CAT_COMMAND) { @@ -784,17 +925,17 @@ void ScreenDialog::handleEvents() { line = -1; if (events._mouseReleased) { - if (!_v2 || line <= 18) + if (!_movedFlag || line <= 18) _selectedLine = line; - _v3 = true; + _redrawFlag = true; } - _v1 = line; - if (v1 == line || _selectedLine >= 0) - _v3 = true; + _tempLine = line; + if (tempLine != line || _selectedLine >= 0) + _redrawFlag = true; } -void ScreenDialog::refreshText() { +void GameDialog::refreshText() { Scene &scene = _vm->_game->_scene; for (uint i = 0; i < _lines.size(); ++i) { @@ -834,10 +975,9 @@ void ScreenDialog::refreshText() { /*------------------------------------------------------------------------*/ -DifficultyDialog::DifficultyDialog(MADSEngine *vm) : ScreenDialog(vm) { - setFrame(8, 2); +DifficultyDialog::DifficultyDialog(MADSEngine *vm) : GameDialog(vm) { setLines(); - setClickableLines(); + _vm->_palette->resetGamePalette(18, 10); } void DifficultyDialog::setLines() { @@ -853,19 +993,24 @@ void DifficultyDialog::setLines() { } } +void DifficultyDialog::display() { + GameDialog::display(); + setFrame(8, 2); +} + void DifficultyDialog::show() { - ScreenDialog::show(); + GameDialog::show(); Nebular::GameNebular &game = *(Nebular::GameNebular *)_vm->_game; switch (_selectedLine) { case 1: - game._difficulty = Nebular::DIFFICULTY_HARD; + game._difficulty = Nebular::DIFFICULTY_EASY; break; case 2: game._difficulty = Nebular::DIFFICULTY_MEDIUM; break; case 3: - game._difficulty = Nebular::DIFFICULTY_EASY; + game._difficulty = Nebular::DIFFICULTY_HARD; break; default: _vm->quitGame(); @@ -874,16 +1019,161 @@ void DifficultyDialog::show() { /*------------------------------------------------------------------------*/ -GameMenuDialog::GameMenuDialog(MADSEngine *vm) : ScreenDialog(vm) { +GameMenuDialog::GameMenuDialog(MADSEngine *vm) : GameDialog(vm) { + setLines(); +} + +void GameMenuDialog::setLines() { + Font *font = _vm->_font->getFont(FONT_CONVERSATION); + + int yp = 64 - ((font->getHeight() + 1) * 4 + 6) / 2; + + addQuote(10, 0, ALIGN_CENTER, Common::Point(0, yp), font); + yp += 6; + + for (int id = 11; id <= 15; ++id) { + yp += font->getHeight(); + addQuote(id, 0, ALIGN_CENTER, Common::Point(0, yp)); + } +} + +void GameMenuDialog::display() { + GameDialog::display(); setFrame(1, 2); } -void GameMenuDialog::addLines() { - initVars(); +void GameMenuDialog::show() { + GameDialog::show(); + + switch (_selectedLine) { + case 1: + _vm->_dialogs->_pendingDialog = DIALOG_SAVE; + _vm->_dialogs->showDialog(); + break; + case 2: + _vm->_dialogs->_pendingDialog = DIALOG_RESTORE; + _vm->_dialogs->showDialog(); + break; + case 3: + _vm->_dialogs->_pendingDialog = DIALOG_OPTIONS; + _vm->_dialogs->showDialog(); + break; + case 4: + // Resume game + break; + case 5: + default: + _vm->quitGame(); + } +} + +/*------------------------------------------------------------------------*/ + +OptionsDialog::OptionsDialog(MADSEngine *vm) : GameDialog(vm) { + setLines(); +} + +int OptionsDialog::getOptionQuote(int option) { + Nebular::GameNebular &game = *(Nebular::GameNebular *)_vm->_game; + + // TODO: Hook the rest of the options to the current config + switch (option) { + case 17: // Music + return 24; // 24: ON, 25: OFF + case 18: // Sound + return 26; // 26: ON, 27: OFF + case 19: // Interface + return !_vm->_easyMouse ? 28 : 29; // 28: Standard, 29: Easy + case 20: // Inventory + return _vm->_invObjectsAnimated ? 30 : 31; // 30: Spinning, 31: Still + case 21: // Text window + return !_vm->_textWindowStill ? 32 : 33; // 32: Animated, 33: Still + case 22: // Screen fade + return 34 + _vm->_screenFade; // 34: Smooth, 35: Medium, 36: Fast + case 23: // Storyline + return (game._storyMode == STORYMODE_NAUGHTY) ? 37 : 38; // 37: Naughty, 38: Nice + default: + error("getOptionQuote: Unknown option"); + } +} + +void OptionsDialog::setLines() { Font *font = _vm->_font->getFont(FONT_CONVERSATION); - int top = 78 - (font->getHeight() + 2) * 12; - addQuote(10, 0, ALIGN_CENTER, Common::Point(0, top), font); - // TODO + + int yp = 40 - ((font->getHeight() + 1) * 4 + 6) / 2; + + addQuote(16, 0, ALIGN_CENTER, Common::Point(0, yp), font); + yp += 6; + + for (int id = 17; id <= 23; ++id) { + yp += font->getHeight(); + addQuote(id, getOptionQuote(id), ALIGN_AT_CENTER, Common::Point(0, yp)); + } + + yp += 28; + addQuote(1, 0, ALIGN_NONE, Common::Point(90, yp)); + addQuote(2, 0, ALIGN_NONE, Common::Point(190, yp)); +} + +void OptionsDialog::display() { + GameDialog::display(); + setFrame(2, 2); +} + +void OptionsDialog::show() { + Nebular::GameNebular &game = *(Nebular::GameNebular *)_vm->_game; + do { + _selectedLine = 0; + GameDialog::show(); + + switch (_selectedLine) { + case 1: // Music + warning("STUB: Music toggle"); + break; + case 2: // Sound + warning("STUB: Sound toggle"); + break; + case 3: // Interface + _vm->_easyMouse = !_vm->_easyMouse; + break; + case 4: // Inventory + _vm->_invObjectsAnimated = !_vm->_invObjectsAnimated; + break; + case 5: // Text window + _vm->_textWindowStill = !_vm->_textWindowStill; + break; + case 6: // Screen fade + if (_vm->_screenFade == SCREEN_FADE_FAST) + _vm->_screenFade = SCREEN_FADE_MEDIUM; + else if (_vm->_screenFade == SCREEN_FADE_MEDIUM) + _vm->_screenFade = SCREEN_FADE_SMOOTH; + else + _vm->_screenFade = SCREEN_FADE_FAST; + break; + case 7: // Storyline + game._storyMode = (game._storyMode == STORYMODE_NAUGHTY) ? STORYMODE_NICE : STORYMODE_NAUGHTY; + break; + default: + break; + } + + // Reload menu + _lineIndex = -1; + clearLines(); + setLines(); + setClickableLines(); + } while (_selectedLine <= 7); + + switch (_selectedLine) { + case 8: // Done + // TODO: Copy from temporary config + break; + case 9: // Cancel + // TODO: Ignore all changes to temporary config + break; + default: + break; + } } } // End of namespace Nebular diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h index a144ee9d83..f64f992611 100644 --- a/engines/mads/nebular/dialogs_nebular.h +++ b/engines/mads/nebular/dialogs_nebular.h @@ -31,6 +31,8 @@ namespace MADS { namespace Nebular { +#define DIALOG_TOP 22 + enum CapitalizationMode { kUppercase = 0, kLowercase = 1, kUpperAndLower = 2 }; class DialogsNebular : public Dialogs { @@ -46,6 +48,10 @@ private: bool textNoun(Common::String &dest, int nounId, const Common::String &source); bool commandCheck(const char *idStr, Common::String &valStr, const Common::String &command); + + void showScummVMSaveDialog(); + void showScummVMRestoreDialog(); + public: virtual void showDialog(); @@ -99,11 +105,41 @@ public: virtual ~PictureDialog(); }; -enum DialogTextAlign { ALIGN_CENTER = -1, ALIGN_AT_CENTER = -2, ALIGN_RIGHT = -3 }; +enum DialogTextAlign { ALIGN_NONE = 0, ALIGN_CENTER = -1, ALIGN_AT_CENTER = -2, ALIGN_RIGHT = -3 }; enum DialogState { DLGSTATE_UNSELECTED = 0, DLGSTATE_SELECTED = 1, DLGSTATE_FOCUSED = 2 }; -class ScreenDialog { +class FullScreenDialog: public EventTarget { +protected: + /** + * Engine reference + */ + MADSEngine *_vm; + + /** + * Screen/scene to show background from + */ + int _screenId; + + /** + * Flag for palette initialization + */ + bool _palFlag; + + /** + * Handles displaying the screen background and dialog + */ + virtual void display(); +public: + /** + * Constructor + */ + FullScreenDialog(MADSEngine *vm); + + virtual ~FullScreenDialog(); +}; + +class GameDialog: public FullScreenDialog { struct DialogLine { bool _active; DialogState _state; @@ -112,22 +148,25 @@ class ScreenDialog { Common::String _msg; Font *_font; int _widthAdjust; - + DialogLine(); DialogLine(const Common::String &s); }; protected: - MADSEngine *_vm; Common::Array<DialogLine> _lines; - int _v1; - int _v2; - bool _v3; + int _tempLine; + bool _movedFlag; + bool _redrawFlag; int _selectedLine; bool _dirFlag; - int _screenId; int _menuSpritesIndex; int _lineIndex; int _textLineCount; + + /** + * Display the dialog + */ + virtual void display(); /** * Reset the lines list for the dialog @@ -177,12 +216,12 @@ public: /** * Constructor */ - ScreenDialog(MADSEngine *vm); + GameDialog(MADSEngine *vm); /** * Destructor */ - virtual ~ScreenDialog() {} + virtual ~GameDialog(); /** * Show the dialog @@ -190,30 +229,69 @@ public: virtual void show(); }; -class DifficultyDialog : public ScreenDialog { +class DifficultyDialog : public GameDialog { private: /** - * Set the lines for the dialog + * Set the lines for the dialog */ void setLines(); public: DifficultyDialog(MADSEngine *vm); /** + * Display the dialog + */ + virtual void display(); + + /** * Show the dialog */ virtual void show(); }; -class GameMenuDialog : public ScreenDialog { +class GameMenuDialog : public GameDialog { private: /** - * Add the lines for the Game Menu dialog + * Set the lines for the dialog */ - void addLines(); + void setLines(); public: GameMenuDialog(MADSEngine *vm); + /** + * Display the dialog + */ + virtual void display(); + + /** + * Show the dialog + */ + virtual void show(); +}; + +class OptionsDialog : public GameDialog { +private: + /** + * Set the lines for the dialog + */ + void setLines(); + + /** + * Gets the quote to be shown for an option + */ + int getOptionQuote(int option); +public: + OptionsDialog(MADSEngine *vm); + + /** + * Display the dialog + */ + virtual void display(); + + /** + * Show the dialog + */ + virtual void show(); }; } // End of namespace Nebular diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp index d6d7a07e52..902f42507a 100644 --- a/engines/mads/nebular/game_nebular.cpp +++ b/engines/mads/nebular/game_nebular.cpp @@ -22,6 +22,7 @@ #include "common/scummsys.h" #include "common/config-manager.h" +#include "graphics/scaler.h" #include "mads/mads.h" #include "mads/game.h" #include "mads/screen.h" @@ -59,9 +60,7 @@ ProtectionResult GameNebular::checkCopyProtection() { } void GameNebular::startGame() { - // Show the main menu - // TODO: Show the main menu here - + /* // Check copy protection ProtectionResult protectionResult = checkCopyProtection(); switch (protectionResult) { @@ -79,11 +78,13 @@ void GameNebular::startGame() { // Copy protection check succeeded break; } + */ initSection(_sectionNumber); _statusFlag = true; - _vm->_dialogs->_pendingDialog = DIALOG_DIFFICULTY; + // Show the main menu + _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU; _vm->_dialogs->showDialog(); _vm->_dialogs->_pendingDialog = DIALOG_NONE; @@ -310,6 +311,11 @@ void GameNebular::setSectionHandler() { void GameNebular::checkShowDialog() { if (_vm->_dialogs->_pendingDialog && _player._stepEnabled && !_globals[kCopyProtectFailed]) { _player.releasePlayerSprites(); + + // Make a thumbnail in case it's needed for making a savegame + _vm->_game->createThumbnail(); + + // Show the dialog _vm->_dialogs->showDialog(); _vm->_dialogs->_pendingDialog = DIALOG_NONE; } diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp new file mode 100644 index 0000000000..4d3beb3382 --- /dev/null +++ b/engines/mads/nebular/menu_nebular.cpp @@ -0,0 +1,986 @@ +/* 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 "mads/game.h" +#include "mads/mads.h" +#include "mads/resources.h" +#include "mads/scene.h" +#include "mads/screen.h" +#include "mads/nebular/menu_nebular.h" + +namespace MADS { + +namespace Nebular { + +#define NEBULAR_MENUSCREEN 990 +#define MADS_MENU_Y ((MADS_SCREEN_HEIGHT - MADS_SCENE_HEIGHT) / 2) +#define MADS_MENU_ANIM_DELAY 70 + +MenuView::MenuView(MADSEngine *vm) : FullScreenDialog(vm) { + _breakFlag = false; + _redrawFlag = true; + _palFlag = false; +} + +void MenuView::show() { + Scene &scene = _vm->_game->_scene; + EventsManager &events = *_vm->_events; + _vm->_screenFade = SCREEN_FADE_FAST; + + scene._spriteSlots.reset(true); + display(); + + events.setEventTarget(this); + events.hideCursor(); + + while (!_breakFlag && !_vm->shouldQuit()) { + if (_redrawFlag) { + _vm->_game->_scene.drawElements(_vm->_game->_fx, _vm->_game->_fx); + _redrawFlag = false; + } + + _vm->_events->waitForNextFrame(); + _vm->_game->_fx = kTransitionNone; + doFrame(); + } + + events.setEventTarget(nullptr); + _vm->_sound->stop(); +} + +void MenuView::display() { + _vm->_palette->resetGamePalette(4, 8); + + FullScreenDialog::display(); +} + +bool MenuView::onEvent(Common::Event &event) { + if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) { + _breakFlag = true; + _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU; + return true; + } + + return false; +} + +/*------------------------------------------------------------------------*/ + +MainMenu::MainMenu(MADSEngine *vm): MenuView(vm) { + Common::fill(&_menuItems[0], &_menuItems[7], (SpriteAsset *)nullptr); + Common::fill(&_menuItemIndexes[0], &_menuItemIndexes[7], -1); + _delayTimeout = 0; + _menuItemIndex = -1; + _frameIndex = 0; + _skipFlag = false; + _highlightedIndex = -1; + _selectedIndex = -1; + _buttonDown = false; + + for (int i = 0; i < 7; ++i) + _menuItems[i] = nullptr; +} + +MainMenu::~MainMenu() { + Scene &scene = _vm->_game->_scene; + for (int i = 0; i < 7; ++i) { + if (_menuItemIndexes[i] != -1) + scene._sprites.remove(_menuItemIndexes[i]); + } + + scene._spriteSlots.reset(); +} + +void MainMenu::display() { + MenuView::display(); + Scene &scene = _vm->_game->_scene; + ScreenObjects &screenObjects = _vm->_game->_screenObjects; + screenObjects.clear(); + + // Load each of the menu item assets and add to the scene sprites list + for (int i = 0; i < 7; ++i) { + Common::String spritesName = Resources::formatName(NEBULAR_MENUSCREEN, + 'A', i + 1, EXT_SS, ""); + _menuItems[i] = new SpriteAsset(_vm, spritesName, 0); + _menuItemIndexes[i] = scene._sprites.add(_menuItems[i]); + + // Register the menu item area in the screen objects + MSprite *frame0 = _menuItems[i]->getFrame(0); + Common::Point pt(frame0->_offset.x - (frame0->w / 2), + frame0->_offset.y - frame0->h); + screenObjects.add( + Common::Rect(pt.x, pt.y + DIALOG_TOP, pt.x + frame0->w, + pt.y + frame0->h + DIALOG_TOP), LAYER_GUI, CAT_COMMAND, i); + } + + // Set the cursor for when it's shown + _vm->_events->setCursor(CURSOR_ARROW); +} + +void MainMenu::doFrame() { + // Delay between animation frames on the menu + uint32 currTime = g_system->getMillis(); + if (currTime < _delayTimeout) + return; + _delayTimeout = currTime + MADS_MENU_ANIM_DELAY; + + // If an item has already been selected, handle rotating out the other menu items + if (_selectedIndex != -1) { + if (_frameIndex == _menuItems[0]->getCount()) { + handleAction((MADSGameAction)_selectedIndex); + } else { + for (_menuItemIndex = 0; _menuItemIndex < 6; ++_menuItemIndex) { + if (_menuItemIndex != _selectedIndex) { + addSpriteSlot(); + } + } + + // Move the menu items to the next frame + ++_frameIndex; + } + return; + } + + // If we've alerady reached the end of the menuitem animation, exit immediately + if (_menuItemIndex == 6) + return; + + // If the user has chosen to skip the animation, show the full menu immediately + if (_skipFlag && _menuItemIndex >= 0) { + // Quickly loop through all the menu items to display each's final frame + for (; _menuItemIndex < 6; ++_menuItemIndex) { + // Draw the final frame of the menuitem + _frameIndex = 0; + addSpriteSlot(); + } + + _vm->_events->showCursor(); + } else { + if ((_menuItemIndex == -1) || (_frameIndex == 0)) { + if (++_menuItemIndex == 6) { + // Reached end of display animation + _vm->_events->showCursor(); + return; + } + + _frameIndex = _menuItems[_menuItemIndex]->getCount() - 1; + } else { + --_frameIndex; + } + + // Move to the next menuitem frame + addSpriteSlot(); + } +} + +void MainMenu::addSpriteSlot() { + Scene &scene = _vm->_game->_scene; + SpriteSlots &spriteSlots = scene._spriteSlots; + + int seqIndex = (_menuItemIndex < 6) ? _menuItemIndex : _frameIndex; + spriteSlots.deleteTimer(seqIndex); + + SpriteAsset *menuItem = _menuItems[_menuItemIndex]; + MSprite *spr = menuItem->getFrame(_frameIndex); + + SpriteSlot &slot = spriteSlots[spriteSlots.add()]; + slot._flags = IMG_UPDATE; + slot._seqIndex = seqIndex; + slot._spritesIndex = _menuItemIndexes[_menuItemIndex]; + slot._frameNumber = _frameIndex + 1; + slot._position = spr->_offset; + slot._depth = 1; + slot._scale = 100; + + _redrawFlag = true; +} + +bool MainMenu::onEvent(Common::Event &event) { + Scene &scene = _vm->_game->_scene; + if (_selectedIndex != -1) + return false; + + // Handle keypresses - these can be done at any time, even when the menu items are being drawn + if (event.type == Common::EVENT_KEYDOWN) { + switch (event.kbd.keycode) { + case Common::KEYCODE_ESCAPE: + case Common::KEYCODE_F6: + handleAction(EXIT); + break; + + case Common::KEYCODE_F1: + handleAction(START_GAME); + break; + + case Common::KEYCODE_F2: + handleAction(RESUME_GAME); + break; + + case Common::KEYCODE_F3: + handleAction(SHOW_INTRO); + break; + + case Common::KEYCODE_F4: + handleAction(CREDITS); + break; + + case Common::KEYCODE_F5: + handleAction(QUOTES); + break; + + case Common::KEYCODE_s: { + // Goodness knows why, but Rex has a key to restart the menuitem animations + // Restart the animation + _menuItemIndex = -1; + for (int i = 0; i < 6; ++i) + scene._spriteSlots.deleteTimer(i); + + _skipFlag = false; + _vm->_events->hideCursor(); + break; + } + + default: + // Any other key skips the menu animation + _skipFlag = true; + return false; + } + + return true; + } + + switch (event.type) { + case Common::EVENT_LBUTTONDOWN: + if (_vm->_events->isCursorVisible()) { + _buttonDown = true; + int menuIndex = getHighlightedItem(event.mouse); + + if (menuIndex != _highlightedIndex) { + scene._spriteSlots.deleteTimer(menuIndex); + + _highlightedIndex = menuIndex; + if (_highlightedIndex != -1) { + _frameIndex = _highlightedIndex; + addSpriteSlot(); + } + } + } else { + // Skip the menu animation + _skipFlag = true; + } + return true; + + case Common::EVENT_MOUSEMOVE: + if (_buttonDown) { + int menuIndex = getHighlightedItem(event.mouse); + if (menuIndex != _highlightedIndex) { + if (_highlightedIndex != -1) { + // Revert to the unselected menu item + unhighlightItem(); + } + + if (menuIndex != -1) { + // Highlight new item + _highlightedIndex = menuIndex; + _frameIndex = _highlightedIndex; + addSpriteSlot(); + } + } + } + break; + + case Common::EVENT_LBUTTONUP: + _buttonDown = false; + if (_highlightedIndex != -1) { + _selectedIndex = _highlightedIndex; + unhighlightItem(); + _frameIndex = 0; + } + + return true; + + default: + break; + } + + return false; +} + +int MainMenu::getHighlightedItem(const Common::Point &pt) { + return _vm->_game->_screenObjects.scan(pt, LAYER_GUI) - 1; +} + +void MainMenu::unhighlightItem() { + // Revert to the unselected menu item + _vm->_game->_scene._spriteSlots.deleteTimer(_highlightedIndex); + _menuItemIndex = _highlightedIndex; + _frameIndex = 0; + addSpriteSlot(); + + _menuItemIndex = 6; + _highlightedIndex = -1; +} + +void MainMenu::handleAction(MADSGameAction action) { + _vm->_events->hideCursor(); + _breakFlag = true; + + switch (action) { + case START_GAME: + // Show the difficulty dialog + _vm->_dialogs->_pendingDialog = DIALOG_DIFFICULTY; + break; + + case RESUME_GAME: + // The original resumed the most recently saved game. Instead, + // just show the load game scren + _vm->_dialogs->_pendingDialog = DIALOG_RESTORE; + return; + + case SHOW_INTRO: + AnimationView::execute(_vm, "rexopen"); + break; + + case CREDITS: + TextView::execute(_vm, "credits"); + return; + + case QUOTES: + TextView::execute(_vm, "quotes"); + return; + + case EXIT: + _vm->_dialogs->_pendingDialog = DIALOG_ADVERT; + break; + default: + break; + } +} + +/*------------------------------------------------------------------------*/ + +AdvertView::AdvertView(MADSEngine *vm): EventTarget(), _vm(vm) { + _breakFlag = false; +} + +void AdvertView::show() { + bool altAdvert = _vm->getRandomNumber(1000) >= 500; + int screenId = altAdvert ? 995 : 996; + uint32 expiryTime = g_system->getMillis() + 10 * 1000; + + _vm->_palette->resetGamePalette(4, 8); + + // Load the advert background onto the screen + SceneInfo *sceneInfo = SceneInfo::init(_vm); + sceneInfo->load(screenId, 0, Common::String(), 0, _vm->_game->_scene._depthSurface, + _vm->_screen); + _vm->_screen.copyRectToScreen(_vm->_screen.getBounds()); + _vm->_palette->setFullPalette(_vm->_palette->_mainPalette); + + delete sceneInfo; + + EventsManager &events = *_vm->_events; + events.setEventTarget(this); + events.hideCursor(); + + while (!_breakFlag && !_vm->shouldQuit()) { + _vm->_events->waitForNextFrame(); + _vm->_game->_fx = kTransitionNone; + + _breakFlag |= g_system->getMillis() >= expiryTime; + } + + events.setEventTarget(nullptr); + _vm->quitGame(); + events.pollEvents(); +} + +bool AdvertView::onEvent(Common::Event &event) { + if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_LBUTTONDOWN) { + _breakFlag = true; + return true; + } + + return false; +} + +/*------------------------------------------------------------------------*/ + +char TextView::_resourceName[100]; +#define TEXTVIEW_LINE_SPACING 2 +#define TEXT_ANIMATION_DELAY 100 +#define TV_NUM_FADE_STEPS 40 +#define TV_FADE_DELAY_MILLI 50 + +void TextView::execute(MADSEngine *vm, const Common::String &resName) { + assert(resName.size() < 100); + strncpy(_resourceName, resName.c_str(), sizeof(_resourceName)); + vm->_dialogs->_pendingDialog = DIALOG_TEXTVIEW; +} + +TextView::TextView(MADSEngine *vm) : MenuView(vm) { + _animating = false; + _panSpeed = 0; + _spareScreen = nullptr; + _scrollCount = 0; + _lineY = -1; + _scrollTimeout = 0; + _panCountdown = 0; + _translationX = 0; + _screenId = -1; + + _font = _vm->_font->getFont(FONT_CONVERSATION); + _vm->_palette->resetGamePalette(4, 0); + load(); +} + +TextView::~TextView() { +} + +void TextView::load() { + Common::String scriptName(_resourceName); + scriptName += ".txr"; + + if (!_script.open(scriptName)) + error("Could not open resource %s", _resourceName); + + processLines(); +} + +void TextView::processLines() { + if (_script.eos()) + error("Attempted to read past end of response file"); + + while (!_script.eos()) { + // Read in the next line + _script.readLine(_currentLine, 79); + char *p = _currentLine + strlen(_currentLine) - 1; + if (*p == '\n') + *p = '\0'; + + // Commented out line, so go loop for another + if (_currentLine[0] == '#') + continue; + + // Process the line + char *cStart = strchr(_currentLine, '['); + if (cStart) { + while (cStart) { + // Loop for possible multiple commands on one line + char *cEnd = strchr(_currentLine, ']'); + if (!cEnd) + error("Unterminated command '%s' in response file", _currentLine); + + *cEnd = '\0'; + processCommand(); + + // Copy rest of line (if any) to start of buffer + strncpy(_currentLine, cEnd + 1, sizeof(_currentLine)); + + cStart = strchr(_currentLine, '['); + } + + if (_currentLine[0]) { + processText(); + break; + } + + } else { + processText(); + break; + } + } +} + +void TextView::processCommand() { + Scene &scene = _vm->_game->_scene; + Common::String scriptLine(_currentLine + 1); + scriptLine.toUppercase(); + const char *paramP; + const char *commandStr = scriptLine.c_str(); + + if (!strncmp(commandStr, "BACKGROUND", 10)) { + // Set the background + paramP = commandStr + 10; + resetPalette(); + int screenId = getParameter(¶mP); + + SceneInfo *sceneInfo = SceneInfo::init(_vm); + sceneInfo->load(screenId, 0, "", 0, scene._depthSurface, scene._backgroundSurface); + scene._spriteSlots.fullRefresh(); + _redrawFlag = true; + + } else if (!strncmp(commandStr, "GO", 2)) { + _animating = true; + + } else if (!strncmp(commandStr, "PAN", 3)) { + // Set panning values + paramP = commandStr + 3; + int panX = getParameter(¶mP); + int panY = getParameter(¶mP); + int panSpeed = getParameter(¶mP); + + if ((panX != 0) || (panY != 0)) { + _pan = Common::Point(panX, panY); + _panSpeed = panSpeed; + } + + } else if (!strncmp(commandStr, "DRIVER", 6)) { + // Set the driver to use + paramP = commandStr + 7; + + if (!strncmp(paramP, "#SOUND.00", 9)) { + int driverNum = paramP[9] - '0'; + _vm->_sound->init(driverNum); + } + } else if (!strncmp(commandStr, "SOUND", 5)) { + // Set sound number + paramP = commandStr + 5; + int soundId = getParameter(¶mP); + _vm->_sound->command(soundId); + + } else if (!strncmp(commandStr, "COLOR", 5) && ((commandStr[5] == '0') || + (commandStr[5] == '1'))) { + // Set the text colors + int index = commandStr[5] - '0'; + paramP = commandStr + 6; + + byte r = getParameter(¶mP); + byte g = getParameter(¶mP); + byte b = getParameter(¶mP); + + _vm->_palette->setEntry(5 + index, r, g, b); + + } else if (!strncmp(commandStr, "SPARE", 5)) { + // Sets a secondary background number that can be later switched in with a PAGE command + paramP = commandStr + 6; + int spareIndex = commandStr[5] - '0'; + assert(spareIndex < 4); + int screenId = getParameter(¶mP); + + // Load the spare background + SceneInfo *sceneInfo = SceneInfo::init(_vm); + sceneInfo->_width = MADS_SCREEN_WIDTH; + sceneInfo->_height = MADS_SCENE_HEIGHT; + _spareScreens[spareIndex].setSize(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT); + sceneInfo->loadMadsV1Background(screenId, "", SCENEFLAG_TRANSLATE, + _spareScreens[spareIndex]); + delete sceneInfo; + + } else if (!strncmp(commandStr, "PAGE", 4)) { + // Signals to change to a previous specified secondary background + paramP = commandStr + 4; + int spareIndex = getParameter(¶mP); + + // Only allow background switches if one isn't currently in progress + if (!_spareScreen && _spareScreens[spareIndex].getPixels() != nullptr) { + _spareScreen = &_spareScreens[spareIndex]; + _translationX = 0; + } + + } else { + error("Unknown response command: '%s'", commandStr); + } +} + +int TextView::getParameter(const char **paramP) { + if ((**paramP != '=') && (**paramP != ',')) + return 0; + + int result = 0; + ++*paramP; + while ((**paramP >= '0') && (**paramP <= '9')) { + result = result * 10 + (**paramP - '0'); + ++*paramP; + } + + return result; +} + +void TextView::processText() { + int lineWidth, xStart; + + if (!strcmp(_currentLine, "***")) { + // Special signifier for end of script + _scrollCount = _font->getHeight() * 13; + _lineY = -1; + return; + } + + _lineY = 0; + + // Lines are always centered, except if line contains a '@', in which case the + // '@' marks the position that must be horizontally centered + char *centerP = strchr(_currentLine, '@'); + if (centerP) { + *centerP = '\0'; + xStart = (MADS_SCREEN_WIDTH / 2) - _font->getWidth(_currentLine); + + // Delete the @ character and shift back the remainder of the string + char *p = centerP + 1; + if (*p == ' ') ++p; + strcpy(centerP, p); + + } else { + lineWidth = _font->getWidth(_currentLine); + xStart = (MADS_SCREEN_WIDTH - lineWidth) / 2; + } + + // Add the new line to the list of pending lines + TextLine tl; + tl._pos = Common::Point(xStart, MADS_SCENE_HEIGHT); + tl._line = _currentLine; + tl._textDisplayIndex = -1; + _textLines.push_back(tl); +} + +void TextView::display() { + FullScreenDialog::display(); + _sceneChanged = true; +} + +void TextView::resetPalette() { + _vm->_palette->resetGamePalette(8, 8); + _vm->_palette->setEntry(5, 0, 63, 63); + _vm->_palette->setEntry(6, 0, 45, 45); +} + +void TextView::doFrame() { + Scene &scene = _vm->_game->_scene; + if (!_animating) + return; + + // Only update state if wait period has expired + uint32 currTime = g_system->getMillis(); + + // If a screen transition is in progress and it's time for another column, handle it + if (_spareScreen) { + byte *srcP = _spareScreen->getBasePtr(_translationX, 0); + byte *bgP = scene._backgroundSurface.getBasePtr(_translationX, 0); + byte *screenP = (byte *)_vm->_screen.getBasePtr(_translationX, 0); + + for (int y = 0; y < MADS_SCENE_HEIGHT; ++y, srcP += MADS_SCREEN_WIDTH, + bgP += MADS_SCREEN_WIDTH, screenP += MADS_SCREEN_WIDTH) { + *bgP = *srcP; + *screenP = *srcP; + } + + // Flag the column of the screen is modified + _vm->_screen.copyRectToScreen(Common::Rect(_translationX, 0, + _translationX + 1, MADS_SCENE_HEIGHT)); + + // Keep moving the column to copy to the right + if (++_translationX == MADS_SCREEN_WIDTH) { + // Surface transition is complete + _spareScreen = nullptr; + } + } + + // Make sure it's time for an update + if (currTime < _scrollTimeout) + return; + _scrollTimeout = g_system->getMillis() + TEXT_ANIMATION_DELAY; + _redrawFlag = true; + + // If any panning values are set, pan the background surface + if ((_pan.x != 0) || (_pan.y != 0)) { + if (_panCountdown > 0) { + --_panCountdown; + return; + } + + // Handle horizontal panning + if (_pan.x != 0) { + byte *lineTemp = new byte[_pan.x]; + for (int y = 0; y < MADS_SCENE_HEIGHT; ++y) { + byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, y); + + // Copy the first X pixels into temp buffer, move the rest of the line + // to the start of the line, and then move temp buffer pixels to end of line + Common::copy(pixelsP, pixelsP + _pan.x, lineTemp); + Common::copy(pixelsP + _pan.x, pixelsP + MADS_SCREEN_WIDTH, pixelsP); + Common::copy(lineTemp, lineTemp + _pan.x, pixelsP + MADS_SCREEN_WIDTH - _pan.x); + } + + delete[] lineTemp; + } + + // Handle vertical panning + if (_pan.y != 0) { + // Store the bottom Y lines into a temp buffer, move the rest of the lines down, + // and then copy the stored lines back to the top of the screen + byte *linesTemp = new byte[_pan.y * MADS_SCREEN_WIDTH]; + byte *pixelsP = (byte *)scene._backgroundSurface.getBasePtr(0, MADS_SCENE_HEIGHT - _pan.y); + Common::copy(pixelsP, pixelsP + MADS_SCREEN_WIDTH * _pan.y, linesTemp); + + for (int y = MADS_SCENE_HEIGHT - 1; y >= _pan.y; --y) { + byte *destP = (byte *)scene._backgroundSurface.getBasePtr(0, y); + byte *srcP = (byte *)scene._backgroundSurface.getBasePtr(0, y - _pan.y); + Common::copy(srcP, srcP + MADS_SCREEN_WIDTH, destP); + } + + Common::copy(linesTemp, linesTemp + _pan.y * MADS_SCREEN_WIDTH, + (byte *)scene._backgroundSurface.getPixels()); + delete[] linesTemp; + } + + // Flag for a full screen refresh + scene._spriteSlots.fullRefresh(); + } + + // Scroll all active text lines up + for (int i = _textLines.size() - 1; i >= 0; --i) { + TextLine &tl = _textLines[i]; + if (tl._textDisplayIndex != -1) + // Expire the text line that's already on-screen + scene._textDisplay.expire(tl._textDisplayIndex); + + tl._pos.y--; + if (tl._pos.y < 0) { + _textLines.remove_at(i); + } else { + tl._textDisplayIndex = scene._textDisplay.add(tl._pos.x, tl._pos.y, + 0x605, -1, tl._line, _font); + } + } + + if (_scrollCount > 0) { + // Handling final scrolling of text off of screen + if (--_scrollCount == 0) { + scriptDone(); + return; + } + } else { + // Handling a text row + if (++_lineY == (_font->getHeight() + TEXTVIEW_LINE_SPACING)) + processLines(); + } +} + +void TextView::scriptDone() { + _breakFlag = true; + _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU; +} + +/*------------------------------------------------------------------------*/ + +char AnimationView::_resourceName[100]; + +void AnimationView::execute(MADSEngine *vm, const Common::String &resName) { + assert(resName.size() < 100); + strncpy(_resourceName, resName.c_str(), sizeof(_resourceName)); + vm->_dialogs->_pendingDialog = DIALOG_ANIMVIEW; +} + +AnimationView::AnimationView(MADSEngine *vm) : MenuView(vm) { + _soundDriverLoaded = false; + _previousUpdate = 0; + _screenId = -1; + _showWhiteBars = true; + _resetPalette = false; + _resyncMode = NEVER; + + load(); +} + +void AnimationView::load() { + Common::String resName(_resourceName); + if (!resName.hasSuffix(".")) + resName += ".res"; + + if (!_script.open(resName)) + error("Could not open resource %s", resName.c_str()); + + processLines(); +} + +bool AnimationView::onEvent(Common::Event &event) { + // Wait for the Escape key or a mouse press + if (((event.type == Common::EVENT_KEYDOWN) && (event.kbd.keycode == Common::KEYCODE_ESCAPE)) || + (event.type == Common::EVENT_RBUTTONUP)) { + scriptDone(); + return true; + } + + return false; +} + +void AnimationView::doFrame() { + Scene &scene = _vm->_game->_scene; + int bgNumber = 0; + + // Only update state if wait period has expired + if (_previousUpdate > 0) { + if (g_system->getMillis() - _previousUpdate < 3000) { + return; + } else { + // time for an update + _previousUpdate = g_system->getMillis(); + } + } else { + _previousUpdate = g_system->getMillis(); + return; + } + /* + char bgFile[10]; + strncpy(bgFile, _currentFile, 5); + bgFile[0] = bgFile[2]; + bgFile[1] = bgFile[3]; + bgFile[2] = bgFile[4]; + bgFile[3] = '\0'; + bgNumber = atoi(bgFile); + sprintf(bgFile, "rm%i.art", bgNumber); + + // Not all scenes have a background. If there is one, refresh it + if (Common::File::exists(bgFile)) { + _vm->_palette->resetGamePalette(4, 8); + SceneInfo *sceneInfo = SceneInfo::init(_vm); + sceneInfo->load(bgNumber, 0, Common::String(), 0, scene._depthSurface, + scene._backgroundSurface); + } + */ +} + +void AnimationView::scriptDone() { + _breakFlag = true; + _vm->_dialogs->_pendingDialog = DIALOG_MAIN_MENU; +} + +void AnimationView::processLines() { + if (_script.eos()) { + // end of script, end animation + scriptDone(); + return; + } + + char c; + while (!_script.eos()) { + // Get in next line + _currentLine.empty(); + while (!_script.eos() && (c = _script.readByte()) != '\n') { + if (c != '\r') + _currentLine += c; + } + + // Process the line + while (!_currentLine.empty()) { + if (_currentLine.hasPrefix("-")) { + _currentLine.deleteChar(0); + + processCommand(); + } else { + // Get resource name + Common::String resName; + while (!_currentLine.empty() && (c = _currentLine[0]) != ' ') { + _currentLine.deleteChar(0); + resName += c; + } + + _resources.push_back(ResourceEntry(resName, _sfx)); + _sfx = 0; + } + + // Skip any spaces + while (_currentLine.hasPrefix(" ")) + _currentLine.deleteChar(0); + } + } +} + +void AnimationView::processCommand() { + // Get the command character + char commandChar = toupper(_currentLine[0]); + _currentLine.deleteChar(0); + + // Handle the command + switch (commandChar) { + case 'H': + // -h[:ex] Disable EMS / XMS high memory support + if (_currentLine.hasPrefix(":")) + _currentLine.deleteChar(0); + while (_currentLine.hasPrefix("e") || _currentLine.hasPrefix("x")) + _currentLine.deleteChar(0); + break; + case 'O': + // -o:xxx Specify opening special effect + assert(_currentLine[0] == ':'); + _currentLine.deleteChar(0); + _sfx = getParameter(); + break; + case 'P': + // Switch to CONCAT mode, which is ignored anyway + break; + case 'R': { + // Resynch timer (always, beginning, never) + assert(_currentLine[0] == ':'); + _currentLine.deleteChar(0); + + char v = toupper(_currentLine[0]); + _currentLine.deleteChar(0); + if (v == 'N') + _resyncMode = NEVER; + else if (v == 'A') + _resyncMode = ALWAYS; + else if (v == 'B') + _resyncMode = BEGINNING; + else + error("Unknown parameter"); + break; + } + case 'W': + // Switch white bars being visible + _showWhiteBars = !_showWhiteBars; + break; + case 'X': + // Exit after animation finishes. Ignore + break; + case 'Y': + // Reset palette on startup + _resetPalette = true; + break; + default: + error("Unknown command char: '%c'", commandChar); + } +} + +int AnimationView::getParameter() { + int result = 0; + + while (!_currentLine.empty()) { + char c = _currentLine[0]; + + if (c >= '0' && c <= '9') { + _currentLine.deleteChar(0); + result = result * 10 + (c - '0'); + } else { + break; + } + } + + return result; +} + + +} // End of namespace Nebular + +} // End of namespace MADS diff --git a/engines/mads/nebular/menu_nebular.h b/engines/mads/nebular/menu_nebular.h new file mode 100644 index 0000000000..7abe3c8892 --- /dev/null +++ b/engines/mads/nebular/menu_nebular.h @@ -0,0 +1,287 @@ +/* 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 MADS_MENU_NEBULAR_H +#define MADS_MENU_NEBULAR_H + +#include "common/scummsys.h" +#include "mads/game.h" +#include "mads/msurface.h" +#include "mads/nebular/dialogs_nebular.h" + +namespace MADS { + +class MADSEngine; + +namespace Nebular { + +enum MADSGameAction { START_GAME, RESUME_GAME, SHOW_INTRO, CREDITS, QUOTES, EXIT }; + +class MenuView: public FullScreenDialog { +protected: + bool _breakFlag; + bool _redrawFlag; + + virtual void doFrame() = 0; + + virtual void display(); + + /** + * Event handler + */ + virtual bool onEvent(Common::Event &event); +public: + MenuView(MADSEngine *vm); + + virtual ~MenuView() {} + + virtual void show(); +}; + +class MainMenu: public MenuView { +private: + SpriteAsset *_menuItems[7]; + int _menuItemIndexes[7]; + int _menuItemIndex; + int _frameIndex; + uint32 _delayTimeout; + bool _skipFlag; + + /** + * Currently highlighted menu item + */ + int _highlightedIndex; + + /** + * Flag for mouse button being pressed + */ + bool _buttonDown; + + /** + * Stores menu item selection + */ + int _selectedIndex; + + /** + * Get the highlighted menu item under the cursor + */ + int getHighlightedItem(const Common::Point &pt); + + /** + * Un-highlight a currently highlighted item + */ + void unhighlightItem(); + + /** + * Execute a given menuitem + */ + void handleAction(MADSGameAction action); + + /** + * Add a sprite slot for the current menuitem frame + */ + void addSpriteSlot(); +protected: + /** + * Display the menu + */ + virtual void display(); + + /** + * Handle the menu item animations + */ + virtual void doFrame(); + + /** + * Event handler + */ + virtual bool onEvent(Common::Event &event); +public: + MainMenu(MADSEngine *vm); + + virtual ~MainMenu(); +}; + +class AdvertView : public EventTarget { +private: + /** + * Engine reference + */ + MADSEngine *_vm; + + /** + * Signals when to close the dialog + */ + bool _breakFlag; +protected: + /** + * Event handler + */ + virtual bool onEvent(Common::Event &event); +public: + AdvertView(MADSEngine *vm); + + virtual ~AdvertView() {} + + /** + * Show the dialog + */ + void show(); +}; + +struct TextLine { + Common::Point _pos; + Common::String _line; + int _textDisplayIndex; +}; + +/** + * Scrolling text view + */ +class TextView : public MenuView { +private: + static char _resourceName[100]; + + bool _animating; + bool _sceneChanged; + Common::Array<TextLine> _textLines; + Common::Point _pan; + int _panSpeed; + MSurface _spareScreens[4]; + int _scrollCount; + int _lineY; + uint32 _scrollTimeout; + int _panCountdown; + int _translationX; + Common::File _script; + char _currentLine[80]; + MSurface *_spareScreen; + Font *_font; +private: + /** + * Load the text resource + */ + void load(); + + /** + * Process the lines + */ + void processLines(); + + /** + * Process a command from the script file + */ + void processCommand(); + + /** + * Process text from the script file + */ + void processText(); + + /** + * Get a parameter from line + */ + int getParameter(const char **paramP); + + /** + * Called when the script is finished + */ + void scriptDone(); + + /** + * Reset the game palette + */ + void resetPalette(); +protected: + virtual void display(); + + virtual void doFrame(); +public: + /** + * Queue the given text resource for display + */ + static void execute(MADSEngine *vm, const Common::String &resName); + + TextView(MADSEngine *vm); + + virtual ~TextView(); +}; + +enum ResyncMode { NEVER, ALWAYS, BEGINNING }; + +struct ResourceEntry { + Common::String _resourceName; + int _sfx; + + ResourceEntry() {} + ResourceEntry(const Common::String &resName, int sfx) { + _resourceName = resName; + _sfx = sfx; + } +}; + +/** +* Animation cutscene view +*/ +class AnimationView : public MenuView { +private: + static char _resourceName[100]; + + Common::File _script; + uint32 _previousUpdate; + Common::String _currentLine; + bool _soundDriverLoaded; + bool _showWhiteBars; + bool _resetPalette; + ResyncMode _resyncMode; + int _sfx; + Common::Array<ResourceEntry> _resources; +private: + void load(); + + void processLines(); + + void processCommand(); + + int getParameter(); + + void scriptDone(); +protected: + virtual void doFrame(); + + virtual bool onEvent(Common::Event &event); +public: + /** + * Queue the given text resource for display + */ + static void execute(MADSEngine *vm, const Common::String &resName); + + AnimationView(MADSEngine *vm); + + virtual ~AnimationView() {} +}; + +} // End of namespace Nebular + +} // End of namespace MADS + +#endif /* MADS_MENU_NEBULAR_H */ diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp index c71512ed4c..b5e2491624 100644 --- a/engines/mads/nebular/nebular_scenes.cpp +++ b/engines/mads/nebular/nebular_scenes.cpp @@ -331,7 +331,7 @@ void SceneInfoNebular::loadCodes(MSurface &depthSurface, Common::SeekableReadStr byte runValue = stream->readByte(); // Write out the run length - Common::fill(destP, destP + runLength, runValue); + Common::fill(destP, MIN(endP, destP + runLength), runValue); destP += runLength; // Get the next run length diff --git a/engines/mads/nebular/nebular_scenes1.cpp b/engines/mads/nebular/nebular_scenes1.cpp index a81f11b8a5..ab072c1d3c 100644 --- a/engines/mads/nebular/nebular_scenes1.cpp +++ b/engines/mads/nebular/nebular_scenes1.cpp @@ -1033,7 +1033,7 @@ void Scene102::actions() { _action._inProgress = false; return; } - } else if (_action.isAction(VERB_LOOK) || (_game._difficulty != DIFFICULTY_EASY)) { + } else if (_action.isAction(VERB_LOOK) || (_game._difficulty != DIFFICULTY_HARD)) { _vm->_dialogs->show(10222); _action._inProgress = false; return; diff --git a/engines/mads/nebular/nebular_scenes8.cpp b/engines/mads/nebular/nebular_scenes8.cpp index 6039135794..14f36756de 100644 --- a/engines/mads/nebular/nebular_scenes8.cpp +++ b/engines/mads/nebular/nebular_scenes8.cpp @@ -1121,8 +1121,6 @@ void Scene804::actions() { } else { _action._inProgress = false; - //saveGame("REX000.SAV"); - _vm->_dialogs->show(80424); _pullThrottleReally = true; _scene->_kernelMessages.add(Common::Point(78, 75), 0x1110, 0, 0, diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp index fc2755db2f..5ce362e053 100644 --- a/engines/mads/nebular/sound_nebular.cpp +++ b/engines/mads/nebular/sound_nebular.cpp @@ -149,7 +149,7 @@ AdlibSample::AdlibSample(Common::SeekableReadStream &s) { /*-----------------------------------------------------------------------*/ -ASound::ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffset) { +ASound::ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename, int dataOffset) { // Open up the appropriate sound file if (!_soundFile.open(filename)) error("Could not open file - %s", filename.c_str()); @@ -197,8 +197,7 @@ ASound::ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffs // Store passed parameters, and setup OPL _dataOffset = dataOffset; _mixer = mixer; - _opl = OPL::Config::create(); - assert(_opl); + _opl = opl; _opl->init(getRate()); _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, @@ -217,7 +216,6 @@ ASound::~ASound() { delete[] (*i)._data; _mixer->stopHandle(_soundHandle); - delete _opl; } void ASound::adlibInit() { @@ -941,8 +939,8 @@ const ASound1::CommandPtr ASound1::_commandList[42] = { &ASound1::command40, &ASound1::command41 }; -ASound1::ASound1(Audio::Mixer *mixer) - : ASound(mixer, "asound.001", 0x1520) { +ASound1::ASound1(Audio::Mixer *mixer, FM_OPL *opl) + : ASound(mixer, opl, "asound.001", 0x1520) { _cmd23Toggle = false; // Load sound samples @@ -1242,7 +1240,7 @@ const ASound2::CommandPtr ASound2::_commandList[44] = { &ASound2::command40, &ASound2::command41, &ASound2::command42, &ASound2::command43 }; -ASound2::ASound2(Audio::Mixer *mixer) : ASound(mixer, "asound.002", 0x15E0) { +ASound2::ASound2(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) { _command12Param = 0xFD; // Load sound samples @@ -1613,7 +1611,7 @@ const ASound3::CommandPtr ASound3::_commandList[61] = { &ASound3::command60 }; -ASound3::ASound3(Audio::Mixer *mixer) : ASound(mixer, "asound.003", 0x15B0) { +ASound3::ASound3(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.003", 0x15B0) { _command39Flag = false; // Load sound samples @@ -2017,7 +2015,7 @@ const ASound4::CommandPtr ASound4::_commandList[61] = { &ASound4::command60 }; -ASound4::ASound4(Audio::Mixer *mixer) : ASound(mixer, "asound.004", 0x14F0) { +ASound4::ASound4(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.004", 0x14F0) { // Load sound samples _soundFile.seek(_dataOffset + 0x122); for (int i = 0; i < 210; ++i) @@ -2273,7 +2271,7 @@ const ASound5::CommandPtr ASound5::_commandList[42] = { &ASound5::command40, &ASound5::command41 }; -ASound5::ASound5(Audio::Mixer *mixer) : ASound(mixer, "asound.002", 0x15E0) { +ASound5::ASound5(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.002", 0x15E0) { // Load sound samples _soundFile.seek(_dataOffset + 0x144); for (int i = 0; i < 164; ++i) @@ -2514,7 +2512,7 @@ const ASound6::CommandPtr ASound6::_commandList[30] = { &ASound6::nullCommand, &ASound6::command29 }; -ASound6::ASound6(Audio::Mixer *mixer) : ASound(mixer, "asound.006", 0x1390) { +ASound6::ASound6(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.006", 0x1390) { // Load sound samples _soundFile.seek(_dataOffset + 0x122); for (int i = 0; i < 200; ++i) @@ -2670,7 +2668,7 @@ const ASound7::CommandPtr ASound7::_commandList[38] = { &ASound7::command36, &ASound7::command37 }; -ASound7::ASound7(Audio::Mixer *mixer) : ASound(mixer, "asound.007", 0x1460) { +ASound7::ASound7(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.007", 0x1460) { // Load sound samples _soundFile.seek(_dataOffset + 0x122); for (int i = 0; i < 214; ++i) @@ -2876,7 +2874,7 @@ const ASound8::CommandPtr ASound8::_commandList[38] = { &ASound8::command36, &ASound8::command37 }; -ASound8::ASound8(Audio::Mixer *mixer) : ASound(mixer, "asound.008", 0x1490) { +ASound8::ASound8(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.008", 0x1490) { // Load sound samples _soundFile.seek(_dataOffset + 0x122); for (int i = 0; i < 174; ++i) @@ -3114,6 +3112,313 @@ int ASound8::command37() { return 0; } +/*-----------------------------------------------------------------------*/ + +const ASound9::CommandPtr ASound9::_commandList[52] = { + &ASound9::command0, &ASound9::command1, &ASound9::command2, &ASound9::command3, + &ASound9::command4, &ASound9::command5, &ASound9::command6, &ASound9::command7, + &ASound9::command8, &ASound9::command9, &ASound9::command10, &ASound9::command11, + &ASound9::command12, &ASound9::command13, &ASound9::command14, &ASound9::command15, + &ASound9::command16, &ASound9::command17, &ASound9::command18, &ASound9::command19, + &ASound9::command20, &ASound9::command21, &ASound9::command22, &ASound9::command23, + &ASound9::command24, &ASound9::command25, &ASound9::command26, &ASound9::command27, + &ASound9::command28, &ASound9::command29, &ASound9::command30, &ASound9::command31, + &ASound9::command32, &ASound9::command33, &ASound9::command34, &ASound9::command35, + &ASound9::command36, &ASound9::command37, &ASound9::command38, &ASound9::command39, + &ASound9::command40, &ASound9::command41, &ASound9::command42, &ASound9::command43, + &ASound9::command44_46, &ASound9::command45, &ASound9::command44_46, &ASound9::command47, + &ASound9::command48, &ASound9::command49, &ASound9::command50, &ASound9::command51 +}; + +ASound9::ASound9(Audio::Mixer *mixer, FM_OPL *opl) : ASound(mixer, opl, "asound.009", 0x16F0) { + _v1 = _v2 = 0; + _soundPtr = nullptr; + + // Load sound samples + _soundFile.seek(_dataOffset + 0x50); + for (int i = 0; i < 94; ++i) + _samples.push_back(AdlibSample(_soundFile)); +} + +int ASound9::command(int commandId, int param) { + if (commandId > 60) + return 0; + + _commandParam = param; + _frameCounter = 0; + return (this->*_commandList[commandId])(); +} + +int ASound9::command9() { + _v1 = 1848; + _v2 = 84; + _channels[0].load(loadData(0xAA4, 470)); + _channels[1].load(loadData(0xE4C, 450)); + _channels[2].load(loadData(0x1466, 702)); + _channels[3].load(loadData(0x137E, 232)); + _channels[4].load(loadData(0x1014, 65)); + _channels[5].load(loadData(0x11C4, 44)); + _channels[6].load(loadData(0XC7A, 466)); + return 0; +} + +int ASound9::command10() { + _channels[0].load(loadData(0x1724, 24)); + _channels[1].load(loadData(0x173C, 24)); + _channels[2].load(loadData(0x1754, 20)); + _channels[3].load(loadData(0x1768, 20)); + _channels[4].load(loadData(0x177C, 20)); + _channels[5].load(loadData(0x1790, 20)); + return 0; +} + +int ASound9::command11() { + playSound(0x8232, 168); + playSound(0x82DA, 170); + return 0; +} + +int ASound9::command12() { + playSound(0x80DA, 12); + playSound(0x80E6, 12); + return 0; +} + +int ASound9::command13() { + playSound(0x80F2, 38); + playSound(0x8118, 42); + return 0; +} + +int ASound9::command14() { + playSound(0x81F6, 22); + return 0; +} + +int ASound9::command15() { + playSound(0x818A, 32); + playSound(0x81AA, 32); + return 0; +} + +int ASound9::command16() { + playSound(0x8022, 36); + playSound(0x8046, 42); + return 0; +} + +int ASound9::command17() { + command29(); + playSound(0x858C, 11); + return 0; +} + +int ASound9::command18() { + playSound(0x80C2, 24); + return 0; +} + +int ASound9::command19() { + playSound(0x80A0, 34); + return 0; +} + +int ASound9::command20() { + int v = (getRandomNumber() & 0x10) | 0x4D; + byte *pData = loadData(0x8142, 8); + pData[4] = v & 0x7F; + playSoundData(pData); + return 0; +} + +int ASound9::command21() { + playSound(0x815A, 16); + return 0; +} + +int ASound9::command22() { + playSound(0x816A, 16); + return 0; +} + +int ASound9::command23() { + playSound(0x814A, 16); + return 0; +} + +int ASound9::command24() { + playSound(0x7FE2, 34); + return 0; +} + +int ASound9::command25() { + playSound(0x8004, 30); + return 0; +} + +int ASound9::command26() { + _channels[6].load(loadData(0x8384, 156)); + _channels[7].load(loadData(0x8420, 160)); + return 0; +} + +int ASound9::command27() { + playSound(0x84C0, 140); + return 0; +} + +int ASound9::command28() { + playSound(0x81CA, 10); + return 0; +} + +int ASound9::command29() { + playSound(0x81D4, 10); + return 0; +} + +int ASound9::command30() { + playSound(0x817A, 16); + return 0; +} + +int ASound9::command31() { + playSound(0x820C, 14); + playSound(0x821A, 24); + return 0; +} + +int ASound9::command32() { + playSound(0x8070, 8); + return 0; +} + +int ASound9::command33() { + playSound(0x8078, 16); + playSound(0x8088, 16); + return 0; +} + +int ASound9::command34() { + // Skipped stuff in original + _channels[0].load(loadData(0x17A4, 24)); + _channels[1].load(loadData(0x1CDE, 62)); + _channels[2].load(loadData(0x2672, 980)); + _channels[3].load(loadData(0x3336, 1000)); + _channels[4].load(loadData(0x469E, 176)); + _channels[5].load(loadData(0x57F2, 138)); + + return 0; +} + +int ASound9::command35() { + playSound(0x854C, 64); + return 0; +} + +int ASound9::command36() { + playSound(0x81DE, 10); + playSound(0x81E8, 14); + return 0; +} + +int ASound9::command37() { + byte *pData = loadData(0x8098, 8); + int v = getRandomNumber(); + if ((v &= 0x40) != 0) + v |= 8; + else + v += 0x4A; + + pData[6] = v; + playSoundData(pData); + return 0; +} + +int ASound9::command38() { + playSound(0x100E, 6); + return 0; +} + +int ASound9::command39() { + _soundPtr = loadData(0x1055, 128); + return 0; +} + +int ASound9::command40() { + _soundPtr = loadData(0x118C, 50); + return 0; +} + +int ASound9::command41() { + _soundPtr = loadData(0x11BE, 6); + return 0; +} + +int ASound9::command42() { + _soundPtr = loadData(0x11F0, 50); + return 0; +} + +int ASound9::command43() { + _v1 = _v2 = 80; + _channels[0].load(loadData(0x626A, 90)); + _channels[1].load(loadData(0x67F2, 92)); + _channels[2].load(loadData(0x6CFE, 232)); + _channels[3].load(loadData(0x7146, 236)); + + return 0; +} + +int ASound9::command44_46() { + _soundPtr = loadData(0x10D5, 38); + return 0; +} + +int ASound9::command45() { + _soundPtr = loadData(0x10FB, 38); + return 0; +} + +int ASound9::command47() { + _soundPtr = loadData(0x1121, 107); + return 0; +} + +int ASound9::command48() { + playSound(0x7FD0, 8); + playSound(0x7FD8, 10); + return 0; +} + +int ASound9::command49() { + _channels[0].load(loadData(0x7AD6, 92)); + _channels[1].load(loadData(0x7B32, 90)); + _channels[2].load(loadData(0x7B8C, 738)); + _channels[3].load(loadData(0x7E6E, 28)); + _channels[4].load(loadData(0x7E8A, 30)); + _channels[5].load(loadData(0x7EA8, 30)); + _channels[6].load(loadData(0x7EC6, 195)); + return 0; +} + +int ASound9::command50() { + _soundPtr = loadData(0x1222, 348); + return 0; +} + +int ASound9::command51() { + // Skipped stuff in original + _channels[0].load(loadData(0x17BC, 1282)); + _channels[1].load(loadData(0x1CFC, 2422)); + _channels[2].load(loadData(0x2A46, 2288)); + _channels[3].load(loadData(0x371E, 3964)); + _channels[4].load(loadData(0x474E, 1863)); + _channels[5].load(loadData(0x587C, 2538)); + return 0; +} + + } // End of namespace Nebular } // End of namespace MADS diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h index c485bd7955..abb6516030 100644 --- a/engines/mads/nebular/sound_nebular.h +++ b/engines/mads/nebular/sound_nebular.h @@ -305,10 +305,12 @@ public: public: /** * Constructor + * @param mixer Mixer + * @param opl OPL * @param filename Specifies the adlib sound player file to use * @param dataOffset Offset in the file of the data segment */ - ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffset); + ASound(Audio::Mixer *mixer, FM_OPL *opl, const Common::String &filename, int dataOffset); /** * Destructor @@ -408,7 +410,7 @@ private: void command111213(); int command2627293032(); public: - ASound1(Audio::Mixer *mixer); + ASound1(Audio::Mixer *mixer, FM_OPL *opl); virtual int command(int commandId, int param); }; @@ -460,7 +462,7 @@ private: void command9Randomize(); void command9Apply(byte *data, int val, int incr); public: - ASound2(Audio::Mixer *mixer); + ASound2(Audio::Mixer *mixer, FM_OPL *opl); virtual int command(int commandId, int param); }; @@ -520,7 +522,7 @@ private: void command9Randomize(); void command9Apply(byte *data, int val, int incr); public: - ASound3(Audio::Mixer *mixer); + ASound3(Audio::Mixer *mixer, FM_OPL *opl); virtual int command(int commandId, int param); }; @@ -558,7 +560,7 @@ private: void method1(); public: - ASound4(Audio::Mixer *mixer); + ASound4(Audio::Mixer *mixer, FM_OPL *opl); virtual int command(int commandId, int param); }; @@ -604,7 +606,7 @@ private: int command42(); int command43(); public: - ASound5(Audio::Mixer *mixer); + ASound5(Audio::Mixer *mixer, FM_OPL *opl); virtual int command(int commandId, int param); }; @@ -633,7 +635,7 @@ private: int command25(); int command29(); public: - ASound6(Audio::Mixer *mixer); + ASound6(Audio::Mixer *mixer, FM_OPL *opl); virtual int command(int commandId, int param); }; @@ -665,7 +667,7 @@ private: int command36(); int command37(); public: - ASound7(Audio::Mixer *mixer); + ASound7(Audio::Mixer *mixer, FM_OPL *opl); virtual int command(int commandId, int param); }; @@ -708,7 +710,66 @@ private: void method1(byte *pData); void adjustRange(byte *pData, byte v, int incr); public: - ASound8(Audio::Mixer *mixer); + ASound8(Audio::Mixer *mixer, FM_OPL *opl); + + virtual int command(int commandId, int param); +}; + +class ASound9 : public ASound { +private: + int _v1, _v2; + byte *_soundPtr; + + typedef int (ASound9::*CommandPtr)(); + static const CommandPtr _commandList[52]; + + int command9(); + int command10(); + int command11(); + int command12(); + int command13(); + int command14(); + int command15(); + int command16(); + int command17(); + int command18(); + int command19(); + int command20(); + int command21(); + int command22(); + int command23(); + int command24(); + int command25(); + int command26(); + int command27(); + int command28(); + int command29(); + int command30(); + int command31(); + int command32(); + int command33(); + int command34(); + int command35(); + int command36(); + int command37(); + int command38(); + int command39(); + int command40(); + int command41(); + int command42(); + int command43(); + int command44_46(); + int command45(); + int command47(); + int command48(); + int command49(); + int command50(); + int command51(); + int command57(); + int command59(); + int command60(); +public: + ASound9(Audio::Mixer *mixer, FM_OPL *opl); virtual int command(int commandId, int param); }; diff --git a/engines/mads/palette.h b/engines/mads/palette.h index 975167a458..9b8b7146db 100644 --- a/engines/mads/palette.h +++ b/engines/mads/palette.h @@ -297,7 +297,7 @@ public: /** * Resets the game palette */ - void resetGamePalette(int v1, int v2); + void resetGamePalette(int lowRange, int highRange); /** * Initializes the main palette diff --git a/engines/mads/phantom/game_phantom.cpp b/engines/mads/phantom/game_phantom.cpp index b0b1bf7836..ba2179fcbf 100644 --- a/engines/mads/phantom/game_phantom.cpp +++ b/engines/mads/phantom/game_phantom.cpp @@ -42,6 +42,10 @@ GamePhantom::GamePhantom(MADSEngine *vm) } void GamePhantom::startGame() { + _scene._priorSceneId = 0; + _scene._currentSceneId = -1; + _scene._nextSceneId = 101; + initializeGlobals(); } diff --git a/engines/mads/phantom/phantom_scenes.cpp b/engines/mads/phantom/phantom_scenes.cpp index dbce014525..7fd7ce642d 100644 --- a/engines/mads/phantom/phantom_scenes.cpp +++ b/engines/mads/phantom/phantom_scenes.cpp @@ -169,9 +169,10 @@ Common::String PhantomScene::formAnimName(char sepChar, int suffixNum) { /*------------------------------------------------------------------------*/ void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) { - File f(Resources::formatName(RESPREFIX_RM, _sceneId, ".DAT")); + Common::String ext = Common::String::format(".WW%d", variant); + File f(Resources::formatName(RESPREFIX_RM, _sceneId, ext)); MadsPack codesPack(&f); - Common::SeekableReadStream *stream = codesPack.getItemStream(variant + 1); + Common::SeekableReadStream *stream = codesPack.getItemStream(0); loadCodes(depthSurface, stream); @@ -181,22 +182,20 @@ void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) { void SceneInfoPhantom::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) { byte *destP = depthSurface.getData(); - byte *endP = depthSurface.getBasePtr(0, depthSurface.h); - - byte runLength = stream->readByte(); - while (destP < endP && runLength > 0) { - byte runValue = stream->readByte(); - - // Write out the run length - Common::fill(destP, destP + runLength, runValue); - destP += runLength; - - // Get the next run length - runLength = stream->readByte(); + byte *walkMap = new byte[stream->size()]; + stream->read(walkMap, stream->size()); + + for (int y = 0; y < 156; ++y) { + for (int x = 0; x < 320; ++x) { + int offset = x + (y * 320); + if ((walkMap[offset / 8] << (offset % 8)) & 0x80) + *destP++ = 1; // walkable + else + *destP++ = 0; + } } - if (destP < endP) - Common::fill(destP, endP, 0); + delete[] walkMap; } } // End of namespace Phantom diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp index ffeed6cda8..ad24dd4f60 100644 --- a/engines/mads/scene.cpp +++ b/engines/mads/scene.cpp @@ -63,8 +63,7 @@ Scene::Scene(MADSEngine *vm) _paletteUsageF.push_back(PaletteUsage::UsageEntry(0xF)); // Set up a scene surface that maps to our physical screen drawing surface - _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH, - _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8()); + restrictScene(); // Set up the verb list _verbList.push_back(VerbInit(VERB_LOOK, VERB_THAT, PREP_NONE)); @@ -82,6 +81,12 @@ Scene::Scene(MADSEngine *vm) Scene::~Scene() { delete _sceneLogic; delete _sceneInfo; + delete _animationData; +} + +void Scene::restrictScene() { + _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH, + _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8()); } void Scene::clearVocab() { @@ -196,21 +201,24 @@ void Scene::loadScene(int sceneId, const Common::String &prefix, bool palFlag) { } void Scene::loadHotspots() { - File f(Resources::formatName(RESPREFIX_RM, _currentSceneId, ".HH")); - MadsPack madsPack(&f); - bool isV2 = (_vm->getGameID() != GType_RexNebular); + _hotspots.clear(); - Common::SeekableReadStream *stream = madsPack.getItemStream(0); - int count = stream->readUint16LE(); - delete stream; + Common::File f; + if (f.open(Resources::formatName(RESPREFIX_RM, _currentSceneId, ".HH"))) { + MadsPack madsPack(&f); + bool isV2 = (_vm->getGameID() != GType_RexNebular); - stream = madsPack.getItemStream(1); - _hotspots.clear(); - for (int i = 0; i < count; ++i) - _hotspots.push_back(Hotspot(*stream, isV2)); + Common::SeekableReadStream *stream = madsPack.getItemStream(0); + int count = stream->readUint16LE(); + delete stream; - delete stream; - f.close(); + stream = madsPack.getItemStream(1); + for (int i = 0; i < count; ++i) + _hotspots.push_back(Hotspot(*stream, isV2)); + + delete stream; + f.close(); + } } void Scene::loadVocab() { @@ -346,7 +354,7 @@ void Scene::loop() { // Handle drawing a game frame doFrame(); - // TODO: Verify correctness of frame wait + // Wait for the next frame _vm->_events->waitForNextFrame(); if (_vm->_dialogs->_pendingDialog != DIALOG_NONE && !_vm->_game->_trigger @@ -507,7 +515,7 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) { _vm->_sound->startQueuedCommands(); } else { // Copy dirty areas to the screen - _dirtyAreas.copyToScreen(_vm->_screen._offset); + _dirtyAreas.copyToScreen(); } _spriteSlots.cleanUp(); diff --git a/engines/mads/scene.h b/engines/mads/scene.h index 407d70dc85..ee7864cfee 100644 --- a/engines/mads/scene.h +++ b/engines/mads/scene.h @@ -142,6 +142,8 @@ public: */ ~Scene(); + void restrictScene(); + /** * Clear the vocabulary list */ diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp index 1494f62d7a..174579a624 100644 --- a/engines/mads/scene_data.cpp +++ b/engines/mads/scene_data.cpp @@ -151,30 +151,34 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName, _sceneId = sceneId; } - // TODO: The following isn't quite right for V2 games (it's all 0) - _artFileNum = infoStream->readUint16LE(); - _depthStyle = infoStream->readUint16LE(); - _width = infoStream->readUint16LE(); - _height = infoStream->readUint16LE(); - - // HACK for V2 games (for now) - if (_vm->getGameID() != GType_RexNebular) { + int nodeCount = 20; + + if (_vm->getGameID() == GType_RexNebular) { + _artFileNum = infoStream->readUint16LE(); + _depthStyle = infoStream->readUint16LE(); + _width = infoStream->readUint16LE(); + _height = infoStream->readUint16LE(); + + infoStream->skip(24); + + nodeCount = infoStream->readUint16LE(); + _yBandsEnd = infoStream->readUint16LE(); + _yBandsStart = infoStream->readUint16LE(); + _maxScale = infoStream->readUint16LE(); + _minScale = infoStream->readUint16LE(); + for (int i = 0; i < DEPTH_BANDS_SIZE; ++i) + _depthList[i] = infoStream->readUint16LE(); + _field4A = infoStream->readUint16LE(); + } else { + _artFileNum = sceneId; + _depthStyle = 0; _width = 320; _height = 156; - } - infoStream->skip(24); - - int nodeCount = infoStream->readUint16LE(); - _yBandsEnd = infoStream->readUint16LE(); - _yBandsStart = infoStream->readUint16LE(); - _maxScale = infoStream->readUint16LE(); - _minScale = infoStream->readUint16LE(); - for (int i = 0; i < DEPTH_BANDS_SIZE; ++i) - _depthList[i] = infoStream->readUint16LE(); - _field4A = infoStream->readUint16LE(); + infoStream->skip(140); + } - // Load the set of objects that are associated with the scene + // Load the scene's walk nodes for (int i = 0; i < 20; ++i) { WalkNode node; node.load(infoStream); @@ -223,21 +227,16 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName, depthSurface.setSize(width, height); } - if (_vm->getGameID() == GType_RexNebular) { - // Load the depth surface with the scene codes - Common::SeekableReadStream *depthStream = infoPack.getItemStream(variant + 1); - loadCodes(depthSurface, depthStream); - delete depthStream; - } - + loadCodes(depthSurface, variant); + depthSurface._depthStyle = _depthStyle; infoFile.close(); if (_vm->getGameID() == GType_RexNebular) { - loadMadsV1Background(sceneId, resName, flags, bgSurface); - loadPalette(sceneId, _artFileNum, resName, flags, bgSurface); + loadMadsV1Background(_sceneId, resName, flags, bgSurface); + loadPalette(_sceneId, _artFileNum, resName, flags, bgSurface); } else { - loadMadsV2Background(sceneId, resName, flags, bgSurface); - loadPalette(sceneId, sceneId, resName, flags, bgSurface); + loadMadsV2Background(_sceneId, resName, flags, bgSurface); + loadPalette(_sceneId, _sceneId, resName, flags, bgSurface); } Common::Array<SpriteAsset *> spriteSets; @@ -334,7 +333,7 @@ void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName, // Get the ART resource if (sceneFlag) { - resourceName = Resources::formatName(RESPREFIX_RM, _artFileNum, ".ART"); + resourceName = Resources::formatName(RESPREFIX_RM, sceneId, ".ART"); } else { resourceName = "*" + Resources::formatResource(resName, resName); } @@ -347,9 +346,27 @@ void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName, assert(_width == bgSurface.w && _height == bgSurface.h); stream = artResource.getItemStream(1); stream->read(bgSurface.getPixels(), bgSurface.w * bgSurface.h); + delete stream; + + if (flags & SCENEFLAG_TRANSLATE) { + // Load in the palette and translate it + Common::SeekableReadStream *palStream = artResource.getItemStream(0); + Common::Array<RGB6> palette; + + palStream->skip(4); // Skip width and height + int numColors = palStream->readUint16LE(); + assert(numColors <= 252); + palette.resize(numColors); + for (int i = 0; i < numColors; ++i) + palette[i].load(palStream); + delete palStream; + + // Translate the surface + _vm->_palette->_paletteUsage.process(palette, 0); + bgSurface.translate(palette); + } // Close the ART file - delete stream; artFile.close(); } diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h index 783a9ab8a9..41e094b8f5 100644 --- a/engines/mads/scene_data.h +++ b/engines/mads/scene_data.h @@ -55,7 +55,8 @@ class SpriteSlot; enum { SCENEFLAG_DITHER = 0x01, // Dither to 16 colors - SCENEFLAG_LOAD_SHADOW = 0x10 // Load hard shadows + SCENEFLAG_LOAD_SHADOW = 0x10, // Load hard shadows + SCENEFLAG_TRANSLATE = 0x10000 // Translate palette of loaded background }; class VerbInit { diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp index 7e8710db56..590e63ac9e 100644 --- a/engines/mads/screen.cpp +++ b/engines/mads/screen.cpp @@ -212,24 +212,22 @@ void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common: Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y, srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y); + Common::Point destPos(bounds.left, bounds.top); if ((*this)[i]._active && bounds.isValidRect()) { - srcSurface->copyTo(destSurface, bounds, Common::Point(bounds.left, bounds.top)); + srcSurface->copyTo(destSurface, bounds, destPos); } } } -void DirtyAreas::copyToScreen(const Common::Point &posAdjust) { +void DirtyAreas::copyToScreen() { for (uint i = 0; i < size(); ++i) { - const Common::Rect &srcBounds = (*this)[i]._bounds; + const Common::Rect &bounds = (*this)[i]._bounds; // Check if this is a sane rectangle before attempting to create it - if (srcBounds.left >= srcBounds.right || srcBounds.top >= srcBounds.bottom) + if (bounds.left >= bounds.right || bounds.top >= bounds.bottom) continue; - Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y, - srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y); - if ((*this)[i]._active && (*this)[i]._bounds.isValidRect()) { _vm->_screen.copyRectToScreen(bounds); } @@ -559,23 +557,32 @@ void ScreenObjects::synchronize(Common::Serializer &s) { ScreenSurface::ScreenSurface() { _shakeCountdown = -1; _random = 0x4D2; + _surfacePixels = nullptr; } void ScreenSurface::init() { - setSize(g_system->getWidth(), g_system->getHeight()); -} + // Set the size for the screen + setSize(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT); -void ScreenSurface::copyRectToScreen(const Common::Point &destPos, - const Common::Rect &bounds) { - const byte *buf = getBasePtr(destPos.x, destPos.y); + // Store a copy of the raw pixels pointer for the screen, since the surface + // itself may be later changed to only a subset of the screen + _surfacePixels = (byte *)getPixels(); + _freeFlag = false; +} - if (bounds.width() != 0 && bounds.height() != 0) - g_system->copyRectToScreen(buf, this->pitch, bounds.left, bounds.top, - bounds.width(), bounds.height()); +ScreenSurface::~ScreenSurface() { + delete[] _surfacePixels; } void ScreenSurface::copyRectToScreen(const Common::Rect &bounds) { - copyRectToScreen(Common::Point(bounds.left, bounds.top), bounds); + const byte *buf = getBasePtr(bounds.left, bounds.top); + + Common::Rect destBounds = bounds; + destBounds.translate(_clipBounds.left, _clipBounds.top); + + if (bounds.width() != 0 && bounds.height() != 0) + g_system->copyRectToScreen(buf, this->pitch, destBounds.left, destBounds.top, + destBounds.width(), destBounds.height()); } void ScreenSurface::updateScreen() { @@ -628,21 +635,28 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag case kTransitionBoxInBottomRight: case kTransitionBoxInTopLeft: case kTransitionBoxInTopRight: - error("TODO: transition"); + warning("TODO: box transition"); + transition(kTransitionFadeIn, surfaceFlag); break; case kTransitionPanLeftToRight: case kTransitionPanRightToLeft: - error("TODO: transition"); + warning("TODO: pan transition"); + transition(kTransitionFadeIn, surfaceFlag); + break; case kTransitionCircleIn1: case kTransitionCircleIn2: case kTransitionCircleIn3: case kTransitionCircleIn4: - error("TODO circle transition"); + warning("TODO circle transition"); + transition(kTransitionFadeIn, surfaceFlag); + break; case kCenterVertTransition: - error("TODO: center vert transition"); + warning("TODO: center vert transition"); + transition(kTransitionFadeIn, surfaceFlag); + break; default: // Quick transitions @@ -650,4 +664,15 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag } } +void ScreenSurface::setClipBounds(const Common::Rect &r) { + _clipBounds = r; + setPixels(_surfacePixels + pitch * r.top + r.left, r.width(), r.height()); + this->pitch = MADS_SCREEN_WIDTH; +} + +void ScreenSurface::resetClipBounds() { + setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT)); +} + + } // End of namespace MADS diff --git a/engines/mads/screen.h b/engines/mads/screen.h index 7937e15456..9d01ca82e3 100644 --- a/engines/mads/screen.h +++ b/engines/mads/screen.h @@ -117,8 +117,8 @@ public: /** * Use the lsit of dirty areas to copy areas of the screen surface to * the physical screen - * @param posAdjust Position adjustment */ - void copyToScreen(const Common::Point &posAdjust); + */ + void copyToScreen(); void reset(); }; @@ -205,8 +205,9 @@ public: class ScreenSurface : public MSurface { private: uint16 _random; + byte *_surfacePixels; + Common::Rect _clipBounds; public: - Common::Point _offset; int _shakeCountdown; public: /** @@ -215,17 +216,14 @@ public: ScreenSurface(); /** - * Initialize the surface + * Destructor */ - void init(); + ~ScreenSurface(); /** - * Copys an area of the screen surface to a given destination position on - * the ScummVM physical screen buffer - * @param destPos Destination position - * @param bounds Area of screen surface to copy + * Initialize the surface */ - void copyRectToScreen(const Common::Point &destPos, const Common::Rect &bounds); + void init(); /** * Copys an area of the screen surface to the ScmmVM physical screen buffer @@ -239,6 +237,12 @@ public: void updateScreen(); void transition(ScreenTransition transitionType, bool surfaceFlag); + + void setClipBounds(const Common::Rect &r); + + void resetClipBounds(); + + const Common::Rect &getClipBounds() { return _clipBounds; } }; } // End of namespace MADS diff --git a/engines/mads/sound.cpp b/engines/mads/sound.cpp index bd99aed2f4..12109895b5 100644 --- a/engines/mads/sound.cpp +++ b/engines/mads/sound.cpp @@ -29,9 +29,10 @@ namespace MADS { -SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer) { +SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer, FM_OPL *opl) { _vm = vm; _mixer = mixer; + _opl = opl; _driver = nullptr; _pollSoundEnabled = false; _soundPollFlag = false; @@ -49,31 +50,32 @@ void SoundManager::init(int sectionNumber) { case GType_RexNebular: switch (sectionNumber) { case 1: - _driver = new Nebular::ASound1(_mixer); + _driver = new Nebular::ASound1(_mixer, _opl); break; case 2: - _driver = new Nebular::ASound2(_mixer); + _driver = new Nebular::ASound2(_mixer, _opl); break; case 3: - _driver = new Nebular::ASound3(_mixer); + _driver = new Nebular::ASound3(_mixer, _opl); break; case 4: - _driver = new Nebular::ASound4(_mixer); + _driver = new Nebular::ASound4(_mixer, _opl); break; case 5: - _driver = new Nebular::ASound5(_mixer); + _driver = new Nebular::ASound5(_mixer, _opl); break; case 6: - _driver = new Nebular::ASound6(_mixer); + _driver = new Nebular::ASound6(_mixer, _opl); break; case 7: - _driver = new Nebular::ASound7(_mixer); + _driver = new Nebular::ASound7(_mixer, _opl); break; case 8: - _driver = new Nebular::ASound8(_mixer); + _driver = new Nebular::ASound8(_mixer, _opl); break; case 9: - error("Sound driver 9 not implemented"); + _driver = new Nebular::ASound9(_mixer, _opl); + break; default: _driver = nullptr; break; diff --git a/engines/mads/sound.h b/engines/mads/sound.h index 9a251f9dd0..b2af7e2346 100644 --- a/engines/mads/sound.h +++ b/engines/mads/sound.h @@ -37,13 +37,14 @@ class SoundManager { private: MADSEngine *_vm; Audio::Mixer *_mixer; + FM_OPL *_opl; Nebular::ASound *_driver; bool _pollSoundEnabled; bool _soundPollFlag; bool _newSoundsPaused; Common::Queue<int> _queuedCommands; public: - SoundManager(MADSEngine *vm, Audio::Mixer *mixer); + SoundManager(MADSEngine *vm, Audio::Mixer *mixer, FM_OPL *opl); ~SoundManager(); /** diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h index 8a9c0f70fa..7632cde294 100644 --- a/engines/mohawk/detection_tables.h +++ b/engines/mohawk/detection_tables.h @@ -294,7 +294,7 @@ static const MohawkGameDescription gameDescriptions[] = { }, // Riven: The Sequel to Myst - // Version 1.? (5CD) + // Version 1.? (5CD) - Spanish // From jvprat { { @@ -312,6 +312,24 @@ static const MohawkGameDescription gameDescriptions[] = { }, // Riven: The Sequel to Myst + // Version 1.0 (5CD) - Italian + // From dodomorandi on bug #6629 + { + { + "riven", + "", + AD_ENTRY1("a_Data.MHK", "0e21e89df7788f32056b6521abf2e81a"), + Common::IT_ITA, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO1(GUIO_NOASPECT) + }, + GType_RIVEN, + 0, + 0, + }, + + // Riven: The Sequel to Myst // Version 1.? (DVD, From "Myst 10th Anniversary Edition") // From Clone2727 { diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp index 710c36ac8d..d8dbeef641 100644 --- a/engines/mohawk/myst_stacks/stoneship.cpp +++ b/engines/mohawk/myst_stacks/stoneship.cpp @@ -42,6 +42,7 @@ Stoneship::Stoneship(MohawkEngine_Myst *vm) : _tunnelRunning = false; + _state.lightState = 0; _state.generatorDepletionTime = 0; _state.generatorDuration = 0; _cabinMystBookPresent = 0; diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp index d07aa9d5ec..3e54017df8 100644 --- a/engines/mohawk/myst_state.cpp +++ b/engines/mohawk/myst_state.cpp @@ -100,6 +100,9 @@ bool MystGameState::load(const Common::String &filename) { syncGameState(s, size == 664); delete loadFile; + // Set Channelwood elevator state to down, because we start on the lower level + _channelwood.elevatorState = 0; + // Switch us back to the intro stack, to the linking book _vm->changeToStack(kIntroStack, 5, 0, 0); diff --git a/engines/mortevielle/detection_tables.h b/engines/mortevielle/detection_tables.h index 3e1e5aaefe..0aa27b89eb 100644 --- a/engines/mortevielle/detection_tables.h +++ b/engines/mortevielle/detection_tables.h @@ -57,21 +57,21 @@ static const MortevielleGameDescription MortevielleGameDescriptions[] = { }, // German, improved translation - { - { - "mortevielle", - "Improved Translation", - { - {"menual.mor", 0, "792aea282b07a1d74c4a4abeabc90c19", 144}, - {"dxx.mor", 0, "949e68e829ecd5ad29e36a00347a9e7e", 207744}, - AD_LISTEND - }, - Common::DE_DEU, - Common::kPlatformDOS, - ADGF_NO_FLAGS, - GUIO0() - }, Common::DE_DEU, kUseEngineDataFile - }, +// { +// { +// "mortevielle", +// "Improved Translation", +// { +// {"menual.mor", 0, "792aea282b07a1d74c4a4abeabc90c19", 144}, +// {"dxx.mor", 0, "949e68e829ecd5ad29e36a00347a9e7e", 207744}, +// AD_LISTEND +// }, +// Common::DE_DEU, +// Common::kPlatformDOS, +// ADGF_NO_FLAGS, +// GUIO0() +// }, Common::DE_DEU, kUseEngineDataFile +// }, // DOS English version doesn't exist. Technically, they are French or German versions, // using English strings stored mort.dat diff --git a/engines/neverhood/graphics.cpp b/engines/neverhood/graphics.cpp index 939428ed19..89792d2659 100644 --- a/engines/neverhood/graphics.cpp +++ b/engines/neverhood/graphics.cpp @@ -114,7 +114,15 @@ void BaseSurface::drawMouseCursorResource(MouseCursorResource &mouseCursorResour } void BaseSurface::copyFrom(Graphics::Surface *sourceSurface, int16 x, int16 y, NDrawRect &sourceRect) { - // Copy a rectangle from sourceSurface, no clipping is performed, 0 is the transparent color + // Copy a rectangle from sourceSurface, 0 is the transparent color + // Clipping is performed against the right/bottom border since x, y will always be >= 0 + + if (x + sourceRect.width > _surface->w) + sourceRect.width = _surface->w - x - 1; + + if (y + sourceRect.height > _surface->h) + sourceRect.height = _surface->h - y - 1; + byte *source = (byte*)sourceSurface->getBasePtr(sourceRect.x, sourceRect.y); byte *dest = (byte*)_surface->getBasePtr(x, y); int height = sourceRect.height; diff --git a/engines/neverhood/modules/module1400.cpp b/engines/neverhood/modules/module1400.cpp index 551b6874ff..465ad5909a 100644 --- a/engines/neverhood/modules/module1400.cpp +++ b/engines/neverhood/modules/module1400.cpp @@ -709,13 +709,14 @@ Scene1405::Scene1405(NeverhoodEngine *vm, Module *parentModule) void Scene1405::update() { Scene::update(); + // Check if the player chose a wrong tile, in which case the whole grid gets reset if (_countdown != 0 && (--_countdown == 0)) { _tilesLeft = 48; - _tiles[_firstTileIndex]->hide(); - _tiles[_secondTileIndex]->hide(); + _tiles[_firstTileIndex]->hide(true); + _tiles[_secondTileIndex]->hide(false); for (uint32 i = 0; i < 48; i++) { if (getSubVar(VA_IS_TILE_MATCH, i)) { - _tiles[i]->hide(); + _tiles[i]->hide(false); setSubVar(VA_IS_TILE_MATCH, i, 0); } } diff --git a/engines/neverhood/modules/module1400_sprites.cpp b/engines/neverhood/modules/module1400_sprites.cpp index 30a5c340c9..99a2a314a7 100644 --- a/engines/neverhood/modules/module1400_sprites.cpp +++ b/engines/neverhood/modules/module1400_sprites.cpp @@ -873,10 +873,11 @@ void AsScene1405Tile::show() { } } -void AsScene1405Tile::hide() { +void AsScene1405Tile::hide(bool playClickSound) { if (_isShowing) { _isShowing = false; - playSound(0); + if (playClickSound) + playSound(0); setVisible(false); } } diff --git a/engines/neverhood/modules/module1400_sprites.h b/engines/neverhood/modules/module1400_sprites.h index fe0db66d27..e709193aab 100644 --- a/engines/neverhood/modules/module1400_sprites.h +++ b/engines/neverhood/modules/module1400_sprites.h @@ -155,7 +155,7 @@ class AsScene1405Tile : public AnimatedSprite { public: AsScene1405Tile(NeverhoodEngine *vm, Scene1405 *parentScene, uint32 tileIndex); void show(); - void hide(); + void hide(bool playClickSound); protected: Scene1405 *_parentScene; bool _isShowing; diff --git a/engines/neverhood/modules/module1600_sprites.cpp b/engines/neverhood/modules/module1600_sprites.cpp index 09e3d0afe1..6a4de86517 100644 --- a/engines/neverhood/modules/module1600_sprites.cpp +++ b/engines/neverhood/modules/module1600_sprites.cpp @@ -30,6 +30,8 @@ AsCommonCar::AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 createSurface(200, 556, 328); _x = x; _y = y; + _destX = x; + _destY = y; _inMainArea = false; _exitDirection = 0; @@ -48,6 +50,7 @@ AsCommonCar::AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 _soundCounter = 0; _pathPoints = NULL; _currMoveDirection = 0; + _newMoveDirection = 0; startAnimation(0xD4220027, 0, -1); setDoDeltaX(getGlobalVar(V_CAR_DELTA_X)); diff --git a/engines/neverhood/sprite.cpp b/engines/neverhood/sprite.cpp index a566b8ee3b..3611ce1ba2 100644 --- a/engines/neverhood/sprite.cpp +++ b/engines/neverhood/sprite.cpp @@ -31,8 +31,20 @@ Sprite::Sprite(NeverhoodEngine *vm, int objectPriority) : Entity(vm, objectPriority), _x(0), _y(0), _spriteUpdateCb(NULL), _filterXCb(NULL), _filterYCb(NULL), _dataResource(vm), _doDeltaX(false), _doDeltaY(false), _needRefresh(false), _flags(0), _surface(NULL) { - SetMessageHandler(&Sprite::handleMessage); + _drawOffset.x = 0; + _drawOffset.y = 0; + _drawOffset.width = 0; + _drawOffset.height = 0; + _collisionBounds.x1 = 0; + _collisionBounds.y1 = 0; + _collisionBounds.x2 = 0; + _collisionBounds.y2 = 0; + _collisionBoundsOffset.x = 0; + _collisionBoundsOffset.y = 0; + _collisionBoundsOffset.width = 0; + _collisionBoundsOffset.height = 0; + SetMessageHandler(&Sprite::handleMessage); } Sprite::~Sprite() { diff --git a/engines/pegasus/energymonitor.cpp b/engines/pegasus/energymonitor.cpp index 40e54afb89..d3cc208e41 100644 --- a/engines/pegasus/energymonitor.cpp +++ b/engines/pegasus/energymonitor.cpp @@ -68,7 +68,9 @@ void Blinker::timeChanged(const TimeValue time) { } } -static const NotificationFlags kEnergyExpiredFlag = 1; +enum { + kEnergyExpiredFlag = 1 +}; EnergyMonitor *g_energyMonitor = 0; diff --git a/engines/pegasus/interaction.cpp b/engines/pegasus/interaction.cpp new file mode 100644 index 0000000000..143bdebaba --- /dev/null +++ b/engines/pegasus/interaction.cpp @@ -0,0 +1,38 @@ +/* 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. + * + * Additional copyright for this file: + * Copyright (C) 1995-1997 Presto Studios, Inc. + * + * 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 "pegasus/interaction.h" +#include "pegasus/neighborhood/neighborhood.h" + +namespace Pegasus { + +GameInteraction::GameInteraction(const InteractionID id, Neighborhood *nextHandler) : IDObject(id), InputHandler(nextHandler) { + _isInteracting = false; + _savedHandler = 0; + _owner = nextHandler; +} + +} // End of namespace Pegasus + diff --git a/engines/pegasus/interaction.h b/engines/pegasus/interaction.h index 293ee6be83..ca168b4cb7 100644 --- a/engines/pegasus/interaction.h +++ b/engines/pegasus/interaction.h @@ -37,11 +37,7 @@ class Neighborhood; class GameInteraction : public IDObject, public InputHandler { public: - GameInteraction(const InteractionID id, Neighborhood *nextHandler) : IDObject(id), InputHandler((InputHandler *)nextHandler) { - _isInteracting = false; - _savedHandler = 0; - _owner = nextHandler; - } + GameInteraction(const InteractionID id, Neighborhood *nextHandler); // If the interaction is open (_isInteracting == true), it's too late to do anything // about it here. diff --git a/engines/pegasus/module.mk b/engines/pegasus/module.mk index cb44a04171..6d69d6ea58 100644 --- a/engines/pegasus/module.mk +++ b/engines/pegasus/module.mk @@ -12,6 +12,7 @@ MODULE_OBJS = \ graphics.o \ hotspot.o \ input.o \ + interaction.o \ interface.o \ menu.o \ movie.o \ diff --git a/engines/pegasus/neighborhood/caldoria/caldoria.cpp b/engines/pegasus/neighborhood/caldoria/caldoria.cpp index 9d2d6723a9..ed52851338 100644 --- a/engines/pegasus/neighborhood/caldoria/caldoria.cpp +++ b/engines/pegasus/neighborhood/caldoria/caldoria.cpp @@ -42,109 +42,119 @@ namespace Pegasus { -static const int16 kVidPhoneAngle = 30; -static const int16 kReplicatorAngle = 50; -static const int16 kDrawersAngle = -30; -static const int16 kCaldoria53Angle = 45; -static const int16 kCaldoria55Angle = -45; +enum { + kVidPhoneAngle = 30, + kReplicatorAngle = 50, + kDrawersAngle = -30, + kCaldoria53Angle = 45, + kCaldoria55Angle = -45 +}; -static const TimeValue kSinclairInterruptionTime1 = 2955; -static const TimeValue kSinclairInterruptionTime2 = 6835; -static const TimeValue kSinclairInterruptionTime3 = 9835; -static const TimeValue kSinclairInterruptionTime4 = 12555; +enum { + kSinclairInterruptionTime1 = 2955, + kSinclairInterruptionTime2 = 6835, + kSinclairInterruptionTime3 = 9835, + kSinclairInterruptionTime4 = 12555 +}; -static const InputBits kPullbackInterruptFilter = kFilterAllInput; -static const InputBits kRecalibrationInterruptFilter = kFilterAllInput; +enum { + kPullbackInterruptFilter = kFilterAllInput, + kRecalibrationInterruptFilter = kFilterAllInput +}; -static const TimeValue kCaldoriaReplicatorIntroIn = 4933; -static const TimeValue kCaldoriaReplicatorIntroOut = 6557; +enum { + kCaldoriaReplicatorIntroIn = 4933, + kCaldoriaReplicatorIntroOut = 6557, -static const TimeValue kCaldoriaReplicatorWrongChoiceIn = 6557; -static const TimeValue kCaldoriaReplicatorWrongChoiceOut = 8586; + kCaldoriaReplicatorWrongChoiceIn = 6557, + kCaldoriaReplicatorWrongChoiceOut = 8586, -static const TimeValue kCaldoriaReplicatorOJChoiceIn = 8586; -static const TimeValue kCaldoriaReplicatorOJChoiceOut = 11687; + kCaldoriaReplicatorOJChoiceIn = 8586, + kCaldoriaReplicatorOJChoiceOut = 11687, -static const TimeValue kCaldoriaMessagesIntroIn = 11687; -static const TimeValue kCaldoriaMessagesIntroOut = 13641; + kCaldoriaMessagesIntroIn = 11687, + kCaldoriaMessagesIntroOut = 13641, -static const TimeValue kCaldoriaFirstMessageIn = 13641; -static const TimeValue kCaldoriaFirstMessageOut = 14203; + kCaldoriaFirstMessageIn = 13641, + kCaldoriaFirstMessageOut = 14203, -static const TimeValue kCaldoriaSecondMessageIn = 14203; -static const TimeValue kCaldoriaSecondMessageOut = 14750; + kCaldoriaSecondMessageIn = 14203, + kCaldoriaSecondMessageOut = 14750, -static const TimeValue kCaldoriaDoorCloseIn = 14750; -static const TimeValue kCaldoriaDoorCloseOut = 15472; + kCaldoriaDoorCloseIn = 14750, + kCaldoriaDoorCloseOut = 15472, -static const TimeValue kCaldoriaElevatorCloseIn = 15472; -static const TimeValue kCaldoriaElevatorCloseOut = 16336; + kCaldoriaElevatorCloseIn = 15472, + kCaldoriaElevatorCloseOut = 16336, -static const TimeValue kCaldoriaShowerCloseIn = 16336; -static const TimeValue kCaldoriaShowerCloseOut = 17101; + kCaldoriaShowerCloseIn = 16336, + kCaldoriaShowerCloseOut = 17101, -static const TimeValue kCaldoriaGTDoorCloseIn = 17101; -static const TimeValue kCaldoriaGTDoorCloseOut = 18523; + kCaldoriaGTDoorCloseIn = 17101, + kCaldoriaGTDoorCloseOut = 18523, -static const TimeValue kCaldoriaNobodyHomeIn = 18523; -static const TimeValue kCaldoriaNobodyHomeOut = 21469; + kCaldoriaNobodyHomeIn = 18523, + kCaldoriaNobodyHomeOut = 21469, -static const TimeValue kCaldoriaNoOtherFloorIn = 21469; -static const TimeValue kCaldoriaNoOtherFloorOut = 28013; + kCaldoriaNoOtherFloorIn = 21469, + kCaldoriaNoOtherFloorOut = 28013, -static const TimeValue kCaldoria4DInstructionsIn = 28013; -static const TimeValue kCaldoria4DInstructionsOut = 29730; + kCaldoria4DInstructionsIn = 28013, + kCaldoria4DInstructionsOut = 29730, -static const TimeValue kCaldoriaDrinkOJIn = 33910; -static const TimeValue kCaldoriaDrinkOJOut = 35846; + kCaldoriaDrinkOJIn = 33910, + kCaldoriaDrinkOJOut = 35846, -static const TimeValue kCaldoriaNoOtherDestinationIn = 35846; -static const TimeValue kCaldoriaNoOtherDestinationOut = 37877; + kCaldoriaNoOtherDestinationIn = 35846, + kCaldoriaNoOtherDestinationOut = 37877, -static const TimeValue kCaldoriaUhghIn = 37877; -static const TimeValue kCaldoriaUhghOut = 38025; + kCaldoriaUhghIn = 37877, + kCaldoriaUhghOut = 38025, -static const TimeValue kCaldoriaSinclairShootsOSIn = 38025; -static const TimeValue kCaldoriaSinclairShootsOSOut = 40649; + kCaldoriaSinclairShootsOSIn = 38025, + kCaldoriaSinclairShootsOSOut = 40649, -static const TimeValue kCaldoriaScreamingAfterIn = 40649; -static const TimeValue kCaldoriaScreamingAfterOut = 47661; + kCaldoriaScreamingAfterIn = 40649, + kCaldoriaScreamingAfterOut = 47661 +}; -static const TimeValue k4FloorTime = 0; +enum { + k4FloorTime = 0, -static const TimeValue k4To1Start = 40; -static const TimeValue k4To1Stop = 7720; + k4To1Start = 40, + k4To1Stop = 7720, -static const TimeValue k4To5Start = 7720; -static const TimeValue k4To5Stop = 10280; + k4To5Start = 7720, + k4To5Stop = 10280, -static const TimeValue k4To2Time = 10280; + k4To2Time = 10280, -static const TimeValue k4To3Time = 10320; + k4To3Time = 10320, -static const TimeValue k1FloorTime = 10360; + k1FloorTime = 10360, -static const TimeValue k1To4Start = 10400; -static const TimeValue k1To4Stop = 18080; + k1To4Start = 10400, + k1To4Stop = 18080, -static const TimeValue k1To5Start = 18080; -static const TimeValue k1To5Stop = 28320; + k1To5Start = 18080, + k1To5Stop = 28320, -static const TimeValue k1To2Time = 28320; + k1To2Time = 28320, -static const TimeValue k1To3Time = 28360; + k1To3Time = 28360, -static const TimeValue k5FloorTime = 28400; + k5FloorTime = 28400, -static const TimeValue k5To1Start = 28440; -static const TimeValue k5To1Stop = 38680; + k5To1Start = 28440, + k5To1Stop = 38680, -static const TimeValue k5To4Start = 38680; -static const TimeValue k5To4Stop = 41240; + k5To4Start = 38680, + k5To4Stop = 41240, -static const TimeValue k5To2Time = 41240; + k5To2Time = 41240, -static const TimeValue k5To3Time = 41280; + k5To3Time = 41280 +}; // FuseFunction functions... diff --git a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp index 0494753661..688fb7860d 100644 --- a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp +++ b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp @@ -30,34 +30,36 @@ namespace Pegasus { -static const TimeValue kSwitchableSlop = 3 * kCaldoriaFrameDuration; -// Two seconds - some slop -static const TimeValue kSwitchableDuration = kCaldoriaMovieScale * 2 - kSwitchableSlop; -// Twelve frames + some slop -static const TimeValue kNonswitchableDuration = kCaldoriaFrameDuration * 12 + kSwitchableSlop; +enum { + kSwitchableSlop = 3 * kCaldoriaFrameDuration, + // Two seconds - some slop + kSwitchableDuration = kCaldoriaMovieScale * 2 - kSwitchableSlop, + // Twelve frames + some slop + kNonswitchableDuration = kCaldoriaFrameDuration * 12 + kSwitchableSlop, -static const TimeValue kSwitchable1Start = 0; -static const TimeValue kSwitchable1Stop = kSwitchable1Start + kSwitchableDuration; + kSwitchable1Start = 0, + kSwitchable1Stop = kSwitchable1Start + kSwitchableDuration, -static const TimeValue kSwitchable2Start = kSwitchable1Stop + kNonswitchableDuration; -static const TimeValue kSwitchable2Stop = kSwitchable2Start + kSwitchableDuration; + kSwitchable2Start = kSwitchable1Stop + kNonswitchableDuration, + kSwitchable2Stop = kSwitchable2Start + kSwitchableDuration, -static const TimeValue kSwitchable3Start = kSwitchable2Stop + kNonswitchableDuration; -static const TimeValue kSwitchable3Stop = kSwitchable3Start + kSwitchableDuration; + kSwitchable3Start = kSwitchable2Stop + kNonswitchableDuration, + kSwitchable3Stop = kSwitchable3Start + kSwitchableDuration, -static const NotificationFlags kVidPhoneDoneFlag = 1; + kVidPhoneDoneFlag = 1, -static const TimeValue kRockMusicLoopIn = 0; -static const TimeValue kRockMusicLoopOut = 2088; + kRockMusicLoopIn = 0, + kRockMusicLoopOut = 2088, -static const TimeValue kOrchestralMusicLoopIn = 2088; -static const TimeValue kOrchestralMusicLoopOut = 4985; + kOrchestralMusicLoopIn = 2088, + kOrchestralMusicLoopOut = 4985, -static const TimeValue kRhythmsMusicLoopIn = 4985; -static const TimeValue kRhythmsMusicLoopOut = 6824; + kRhythmsMusicLoopIn = 4985, + kRhythmsMusicLoopOut = 6824, -static const TimeValue kAcousticMusicLoopIn = 6824; -static const TimeValue kAcousticMusicLoopOut = 9387; + kAcousticMusicLoopIn = 6824, + kAcousticMusicLoopOut = 9387 +}; enum { k4DVideoMenu, diff --git a/engines/pegasus/neighborhood/mars/shuttlehud.cpp b/engines/pegasus/neighborhood/mars/shuttlehud.cpp index 11e826278b..2d894f7b95 100644 --- a/engines/pegasus/neighborhood/mars/shuttlehud.cpp +++ b/engines/pegasus/neighborhood/mars/shuttlehud.cpp @@ -30,26 +30,28 @@ namespace Pegasus { -static const CoordType kHUDTargetGridLeft = kShuttleWindowLeft + 16; -static const CoordType kHUDTargetGridTop = kShuttleWindowTop + 8; -static const CoordType kHUDTargetGridWidth = 328; -static const CoordType kHUDTargetGridHeight = 206; - -static const CoordType kHUDRS232Left = kHUDTargetGridLeft + 264; -static const CoordType kHUDRS232Top = kHUDTargetGridTop + 2; - -static const CoordType kHUDLockLeft = kShuttleWindowLeft + 101; -static const CoordType kHUDLockTop = kShuttleWindowTop + 49; -static const CoordType kHUDLockWidth = 145; -static const CoordType kHUDLockHeight = 124; - -static const CoordType kTractorLockWidth = 50; -static const CoordType kTractorLockHeight = 30; - -static const CoordType kTractorLockLeft = kShuttleWindowMidH - kTractorLockWidth / 2; -static const CoordType kTractorLockTop = kShuttleWindowMidV - kTractorLockHeight / 2; -static const CoordType kTractorLockRight = kTractorLockLeft + kTractorLockWidth; -static const CoordType kTractorLockBottom = kTractorLockTop + kTractorLockHeight; +enum { + kHUDTargetGridLeft = kShuttleWindowLeft + 16, + kHUDTargetGridTop = kShuttleWindowTop + 8, + kHUDTargetGridWidth = 328, + kHUDTargetGridHeight = 206, + + kHUDRS232Left = kHUDTargetGridLeft + 264, + kHUDRS232Top = kHUDTargetGridTop + 2, + + kHUDLockLeft = kShuttleWindowLeft + 101, + kHUDLockTop = kShuttleWindowTop + 49, + kHUDLockWidth = 145, + kHUDLockHeight = 124, + + kTractorLockWidth = 50, + kTractorLockHeight = 30, + + kTractorLockLeft = kShuttleWindowMidH - kTractorLockWidth / 2, + kTractorLockTop = kShuttleWindowMidV - kTractorLockHeight / 2, + kTractorLockRight = kTractorLockLeft + kTractorLockWidth, + kTractorLockBottom = kTractorLockTop + kTractorLockHeight +}; static const uint16 s_RS232Data[] = { 0xF0E1, 0xCE70, diff --git a/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp index e2a0267231..1478a74744 100644 --- a/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp +++ b/engines/pegasus/neighborhood/norad/alpha/ecrmonitor.cpp @@ -45,7 +45,9 @@ static const TimeValue kSection2Start = 26; static const TimeValue kSection2Stop = 1000; // Seems to be a good value for a 20 second pan. -static const CoordType kPanPixelsPerFrame = 8; +enum { + kPanPixelsPerFrame = 8 +}; // Interesting times are in seconds. static const TimeValue s_ECRInterestingTimes[] = { diff --git a/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp index 3491f161c7..e85a3e699f 100644 --- a/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp +++ b/engines/pegasus/neighborhood/norad/alpha/fillingstation.cpp @@ -65,64 +65,66 @@ static const ItemID kCO2Item = 10000; static const ItemID kHeItem = 10001; // Interactive points. -static const TimeValue kFSPowerUpStartStart = 0; -static const TimeValue kFSPowerUpStartStop = 600; -static const TimeValue kFSSplashStart = 600; -static const TimeValue kFSSplashStop = 7800; -static const TimeValue kFSSplashIntakeStart = 7800; -static const TimeValue kFSSplashIntakeStop = 18600; - -static const TimeValue kFSMainMenu = 18600; -static const TimeValue kFSIntakeHiliteStart = 19200; -static const TimeValue kFSIntakeHiliteStop = 19800; -static const TimeValue kFSDispenseHiliteStart = 19800; -static const TimeValue kFSDispenseHiliteStop = 20400; - -static const TimeValue kFSDispenseMenu = 20400; - -static const TimeValue kFSArHiliteStart = 21000; -static const TimeValue kFSArHiliteStop = 21600; -static const TimeValue kFSArAttach = 21600; -static const TimeValue kFSArFilledStart = 22200; -static const TimeValue kFSArFilledStop = 25200; -static const TimeValue kFSArIncompatibleStart = 25200; -static const TimeValue kFSArIncompatibleStop = 30000; - -static const TimeValue kFSCO2HiliteStart = 30000; -static const TimeValue kFSCO2HiliteStop = 30600; -static const TimeValue kFSCO2Attach = 30600; -static const TimeValue kFSCO2FilledStart = 31200; -static const TimeValue kFSCO2FilledStop = 34200; -static const TimeValue kFSCO2IncompatibleStart = 34200; -static const TimeValue kFSCO2IncompatibleStop = 39000; - -static const TimeValue kFSHeHiliteStart = 39000; -static const TimeValue kFSHeHiliteStop = 39600; -static const TimeValue kFSHeAttach = 39600; -static const TimeValue kFSHeFilledStart = 40200; -static const TimeValue kFSHeFilledStop = 43200; -static const TimeValue kFSHeIncompatibleStart = 43200; -static const TimeValue kFSHeIncompatibleStop = 48000; - -static const TimeValue kFSOHiliteStart = 48000; -static const TimeValue kFSOHiliteStop = 48600; -static const TimeValue kFSOAttach = 48600; -static const TimeValue kFSOFilledStart = 49200; -static const TimeValue kFSOFilledStop = 52200; -static const TimeValue kFSOIncompatibleStart = 52200; -static const TimeValue kFSOIncompatibleStop = 57000; - -static const TimeValue kFSNHiliteStart = 57000; -static const TimeValue kFSNHiliteStop = 57600; -static const TimeValue kFSNAttach = 57600; -static const TimeValue kFSNFilledStart = 58200; -static const TimeValue kFSNFilledStop = 61200; -static const TimeValue kFSNIncompatibleStart = 61200; -static const TimeValue kFSNIncompatibleStop = 66000; - -static const TimeValue kFSIntakeMenu = 66000; -static const TimeValue kFSIntakeInProgressStart = 66600; -static const TimeValue kFSIntakeInProgressStop = 69600; +enum { + kFSPowerUpStartStart = 0, + kFSPowerUpStartStop = 600, + kFSSplashStart = 600, + kFSSplashStop = 7800, + kFSSplashIntakeStart = 7800, + kFSSplashIntakeStop = 18600, + + kFSMainMenu = 18600, + kFSIntakeHiliteStart = 19200, + kFSIntakeHiliteStop = 19800, + kFSDispenseHiliteStart = 19800, + kFSDispenseHiliteStop = 20400, + + kFSDispenseMenu = 20400, + + kFSArHiliteStart = 21000, + kFSArHiliteStop = 21600, + kFSArAttach = 21600, + kFSArFilledStart = 22200, + kFSArFilledStop = 25200, + kFSArIncompatibleStart = 25200, + kFSArIncompatibleStop = 30000, + + kFSCO2HiliteStart = 30000, + kFSCO2HiliteStop = 30600, + kFSCO2Attach = 30600, + kFSCO2FilledStart = 31200, + kFSCO2FilledStop = 34200, + kFSCO2IncompatibleStart = 34200, + kFSCO2IncompatibleStop = 39000, + + kFSHeHiliteStart = 39000, + kFSHeHiliteStop = 39600, + kFSHeAttach = 39600, + kFSHeFilledStart = 40200, + kFSHeFilledStop = 43200, + kFSHeIncompatibleStart = 43200, + kFSHeIncompatibleStop = 48000, + + kFSOHiliteStart = 48000, + kFSOHiliteStop = 48600, + kFSOAttach = 48600, + kFSOFilledStart = 49200, + kFSOFilledStop = 52200, + kFSOIncompatibleStart = 52200, + kFSOIncompatibleStop = 57000, + + kFSNHiliteStart = 57000, + kFSNHiliteStop = 57600, + kFSNAttach = 57600, + kFSNFilledStart = 58200, + kFSNFilledStop = 61200, + kFSNIncompatibleStart = 61200, + kFSNIncompatibleStop = 66000, + + kFSIntakeMenu = 66000, + kFSIntakeInProgressStart = 66600, + kFSIntakeInProgressStop = 69600 +}; NoradAlphaFillingStation::NoradAlphaFillingStation(Neighborhood *owner) : GameInteraction(kNoradFillingStationInteractionID, owner), _rightSideMovie(kN01RightSideID), _rightSideNotification(kNoradFillingStationNotificationID, ((PegasusEngine *)g_engine)) { diff --git a/engines/pegasus/neighborhood/norad/delta/globegame.cpp b/engines/pegasus/neighborhood/norad/delta/globegame.cpp index 5c321a8e8a..9ea3036024 100644 --- a/engines/pegasus/neighborhood/norad/delta/globegame.cpp +++ b/engines/pegasus/neighborhood/norad/delta/globegame.cpp @@ -394,20 +394,22 @@ static const NotificationFlags kGlobeNotificationFlags = kGlobeSplash1Finished | kGlobeTimerExpired | kMaxDeactivatedFinished; -static const int16 kSplash1End = 4; -static const int16 kSplash2End = 5; -static const int16 kSplash3Start = 8; -static const int16 kSplash3Stop = 9; -static const int16 kSplash4Start = 9; -static const int16 kSplash4Stop = 10; -static const int16 kNewLaunchSiloTime = 10; -static const int16 kSiloDeactivatedTime = 11; -static const int16 kMissileLaunchedTime = 12; -static const int16 kMaxDeactivatedStart = 13; -static const int16 kMaxDeactivatedStop = 23; - -static const int16 kGamePlaying = 1; -static const int16 kGameOver = 2; +enum { + kSplash1End = 4, + kSplash2End = 5, + kSplash3Start = 8, + kSplash3Stop = 9, + kSplash4Start = 9, + kSplash4Stop = 10, + kNewLaunchSiloTime = 10, + kSiloDeactivatedTime = 11, + kMissileLaunchedTime = 12, + kMaxDeactivatedStart = 13, + kMaxDeactivatedStop = 23, + + kGamePlaying = 1, + kGameOver = 2 +}; enum { kGameIntro, diff --git a/engines/pegasus/neighborhood/norad/subcontrolroom.cpp b/engines/pegasus/neighborhood/norad/subcontrolroom.cpp index d48481e925..1b14c529d8 100644 --- a/engines/pegasus/neighborhood/norad/subcontrolroom.cpp +++ b/engines/pegasus/neighborhood/norad/subcontrolroom.cpp @@ -34,110 +34,113 @@ namespace Pegasus { // Right Monitor times -static const TimeValue kAlphaClawSplashStart = 0; -static const TimeValue kAlphaClawSplashStop = 4000; - -static const TimeValue kDeltaClawSplashStart = 4000; -static const TimeValue kDeltaClawSplashStop = 8000; - -static const TimeValue kClawAtATime = 8000; -static const TimeValue kClawAtAPinchedTime = 8600; -static const TimeValue kClawAtATurnedTime = 9200; -static const TimeValue kClawAtAWithRobotPinchedTime = 9800; - -static const TimeValue kClawAtBTime = 10400; -static const TimeValue kClawAtBPinchedTime = 11000; -static const TimeValue kClawAtBTurnedTime = 11600; -static const TimeValue kClawAtBWithRobotTime = 12200; -static const TimeValue kClawAtBWithRobotPinchedTime = 12800; - -static const TimeValue kClawAtCTime = 13400; -static const TimeValue kClawAtCPinchedTime = 14000; -static const TimeValue kClawAtCTurnedTime = 14600; - -static const TimeValue kClawAtDTime = 15200; -static const TimeValue kClawAtDPinchedTime = 15800; -static const TimeValue kClawAtDTurnedTime = 16400; - -static const TimeValue kAToBStart = 17000; -static const TimeValue kAToBStop = 18680; -static const TimeValue kAPinchStart = 18680; -static const TimeValue kAPinchStop = 20200; -static const TimeValue kACCWStart = 20200; -static const TimeValue kACCWStop = 21600; -static const TimeValue kACWStart = 21600; -static const TimeValue kACWStop = 23000; - -static const TimeValue kBToAStart = 23000; -static const TimeValue kBToAStop = 24680; -static const TimeValue kBToCStart = 24680; -static const TimeValue kBToCStop = 26520; -static const TimeValue kBToDStart = 26520; -static const TimeValue kBToDStop = 28320; -static const TimeValue kBPinchStart = 28320; -static const TimeValue kBPinchStop = 29680; -static const TimeValue kBCCWStart = 29680; -static const TimeValue kBCCWStop = 31200; -static const TimeValue kBCWStart = 31200; -static const TimeValue kBCWStop = 32720; - -static const TimeValue kCToBStart = 32720; -static const TimeValue kCToBStop = 34560; -static const TimeValue kCPinchStart = 34560; -static const TimeValue kCPinchStop = 36400; -static const TimeValue kCCCWStart = 36400; -static const TimeValue kCCCWStop = 37840; -static const TimeValue kCCWStart = 37840; -static const TimeValue kCCWStop = 39280; - -static const TimeValue kDToBStart = 39280; -static const TimeValue kDToBStop = 41080; -static const TimeValue kDPinchStart = 41080; -static const TimeValue kDPinchStop = 42600; -static const TimeValue kDCCWStart = 42600; -static const TimeValue kDCCWStop = 44000; -static const TimeValue kDCWStart = 44000; -static const TimeValue kDCWStop = 45400; - -static const TimeValue kRobotApproachStart = 45400; -static const TimeValue kRobotApproachStop = 56800; - -static const TimeValue kCToBWithRobotStart = 56800; -static const TimeValue kCToBWithRobotStop = 58600; - -static const TimeValue kBPinchWithRobotStart = 58600; -static const TimeValue kBPinchWithRobotStop = 60400; -static const TimeValue kBToAWithRobotStart = 60400; -static const TimeValue kBToAWithRobotStop = 62240; +enum { + kAlphaClawSplashStart = 0, + kAlphaClawSplashStop = 4000, + + kDeltaClawSplashStart = 4000, + kDeltaClawSplashStop = 8000, + + kClawAtATime = 8000, + kClawAtAPinchedTime = 8600, + kClawAtATurnedTime = 9200, + kClawAtAWithRobotPinchedTime = 9800, + + kClawAtBTime = 10400, + kClawAtBPinchedTime = 11000, + kClawAtBTurnedTime = 11600, + kClawAtBWithRobotTime = 12200, + kClawAtBWithRobotPinchedTime = 12800, + + kClawAtCTime = 13400, + kClawAtCPinchedTime = 14000, + kClawAtCTurnedTime = 14600, + + kClawAtDTime = 15200, + kClawAtDPinchedTime = 15800, + kClawAtDTurnedTime = 16400, + + kAToBStart = 17000, + kAToBStop = 18680, + kAPinchStart = 18680, + kAPinchStop = 20200, + kACCWStart = 20200, + kACCWStop = 21600, + kACWStart = 21600, + kACWStop = 23000, + + kBToAStart = 23000, + kBToAStop = 24680, + kBToCStart = 24680, + kBToCStop = 26520, + kBToDStart = 26520, + kBToDStop = 28320, + kBPinchStart = 28320, + kBPinchStop = 29680, + kBCCWStart = 29680, + kBCCWStop = 31200, + kBCWStart = 31200, + kBCWStop = 32720, + + kCToBStart = 32720, + kCToBStop = 34560, + kCPinchStart = 34560, + kCPinchStop = 36400, + kCCCWStart = 36400, + kCCCWStop = 37840, + kCCWStart = 37840, + kCCWStop = 39280, + + kDToBStart = 39280, + kDToBStop = 41080, + kDPinchStart = 41080, + kDPinchStop = 42600, + kDCCWStart = 42600, + kDCCWStop = 44000, + kDCWStart = 44000, + kDCWStop = 45400, + + kRobotApproachStart = 45400, + kRobotApproachStop = 56800, + + kCToBWithRobotStart = 56800, + kCToBWithRobotStop = 58600, + + kBPinchWithRobotStart = 58600, + kBPinchWithRobotStop = 60400, + kBToAWithRobotStart = 60400, + kBToAWithRobotStop = 62240 +}; // As usual, times here are in seconds. // Left monitor times. +enum { + kAlphaSplashStart = 0, + kAlphaSplashStop = 2, -static const TimeValue kAlphaSplashStart = 0; -static const TimeValue kAlphaSplashStop = 2; - -static const TimeValue kMainMenuTime = 2; -static const TimeValue kLaunchPrepRolloverTime = 3; -static const TimeValue kLaunchPrepHighlightStart = 4; -static const TimeValue kLaunchPrepHighlightStop = 5; -static const TimeValue kClawControlRolloverTime = 5; -static const TimeValue kClawControlHighlightStart = 6; -static const TimeValue kClawControlHighlightStop = 7; + kMainMenuTime = 2, + kLaunchPrepRolloverTime = 3, + kLaunchPrepHighlightStart = 4, + kLaunchPrepHighlightStop = 5, + kClawControlRolloverTime = 5, + kClawControlHighlightStart = 6, + kClawControlHighlightStop = 7, -static const TimeValue kAlphaLaunchPrepStart = 7; -static const TimeValue kAlphaLaunchPrepStop = 17; + kAlphaLaunchPrepStart = 7, + kAlphaLaunchPrepStop = 17, -static const TimeValue kClawMenuStart = 17; -static const TimeValue kClawMenuStop = 18; + kClawMenuStart = 17, + kClawMenuStop = 18, -static const TimeValue kClawMenuTime = 18; + kClawMenuTime = 18, -static const TimeValue kDeltaSplashStart = 19; -static const TimeValue kDeltaSplashStop = 21; + kDeltaSplashStart = 19, + kDeltaSplashStop = 21, -static const TimeValue kDeltaLaunchPrepStart = 21; -static const TimeValue kDeltaLaunchPrepStop = 30; + kDeltaLaunchPrepStart = 21, + kDeltaLaunchPrepStop = 30 +}; // Right monitor times. diff --git a/engines/pegasus/neighborhood/tsa/fulltsa.cpp b/engines/pegasus/neighborhood/tsa/fulltsa.cpp index 92b79c038e..f7996fabf5 100644 --- a/engines/pegasus/neighborhood/tsa/fulltsa.cpp +++ b/engines/pegasus/neighborhood/tsa/fulltsa.cpp @@ -41,41 +41,45 @@ namespace Pegasus { // TSA PICTs: -static const ResIDType kTBPCloseBoxPICTID = 800; -static const ResIDType kTBPRewindPICTID = 801; -static const ResIDType kUnresolvedPICTID = 802; -static const ResIDType kResolvedPICTID = 803; -static const ResIDType kJumpMenuPICTID = 804; -static const ResIDType kJumpMenuHilitedPICTID = 805; -static const ResIDType kExitPICTID = 806; -static const ResIDType kExitHilitedPICTID = 807; -static const ResIDType kLeftRipPICTID = 808; -static const ResIDType kComparisonCloseBoxPICTID = 809; -static const ResIDType kComparisonLeftRewindPICTID = 810; -static const ResIDType kComparisonRightRewindPICTID = 811; -static const ResIDType kComparisonHiliteNoradPICTID = 812; -static const ResIDType kComparisonHiliteMarsPICTID = 813; -static const ResIDType kComparisonHiliteCaldoriaPICTID = 814; -static const ResIDType kComparisonHiliteWSCPICTID = 815; -static const ResIDType kComparisonChancesNoradPICTID = 816; -static const ResIDType kComparisonChancesMarsPICTID = 817; -static const ResIDType kComparisonChancesCaldoriaPICTID = 818; -static const ResIDType kComparisonChancesWSCPICTID = 819; -static const ResIDType kRedirectionCCRolloverPICTID = 820; -static const ResIDType kRedirectionRRRolloverPICTID = 821; -static const ResIDType kRedirectionFDRolloverPICTID = 822; -static const ResIDType kRedirectionCCDoorPICTID = 823; -static const ResIDType kRedirectionRRDoorPICTID = 824; -static const ResIDType kRedirectionFDDoorPICTID = 825; -static const ResIDType kRedirectionSecuredPICTID = 826; -static const ResIDType kRedirectionNewTargetPICTID = 827; -static const ResIDType kRedirectionClosePICTID = 828; +enum { + kTBPCloseBoxPICTID = 800, + kTBPRewindPICTID = 801, + kUnresolvedPICTID = 802, + kResolvedPICTID = 803, + kJumpMenuPICTID = 804, + kJumpMenuHilitedPICTID = 805, + kExitPICTID = 806, + kExitHilitedPICTID = 807, + kLeftRipPICTID = 808, + kComparisonCloseBoxPICTID = 809, + kComparisonLeftRewindPICTID = 810, + kComparisonRightRewindPICTID = 811, + kComparisonHiliteNoradPICTID = 812, + kComparisonHiliteMarsPICTID = 813, + kComparisonHiliteCaldoriaPICTID = 814, + kComparisonHiliteWSCPICTID = 815, + kComparisonChancesNoradPICTID = 816, + kComparisonChancesMarsPICTID = 817, + kComparisonChancesCaldoriaPICTID = 818, + kComparisonChancesWSCPICTID = 819, + kRedirectionCCRolloverPICTID = 820, + kRedirectionRRRolloverPICTID = 821, + kRedirectionFDRolloverPICTID = 822, + kRedirectionCCDoorPICTID = 823, + kRedirectionRRDoorPICTID = 824, + kRedirectionFDDoorPICTID = 825, + kRedirectionSecuredPICTID = 826, + kRedirectionNewTargetPICTID = 827, + kRedirectionClosePICTID = 828 +}; static const int16 kCompassShift = 15; -static const TimeScale kFullTSAMovieScale = 600; -static const TimeScale kFullTSAFramesPerSecond = 15; -static const TimeScale kFullTSAFrameDuration = 40; +enum { + kFullTSAMovieScale = 600, + kFullTSAFramesPerSecond = 15, + kFullTSAFrameDuration = 40 +}; // Alternate IDs. static const AlternateID kAltTSANormal = 0; @@ -84,416 +88,425 @@ static const AlternateID kAltTSARobotsAtFrontDoor = 2; static const AlternateID kAltTSARedAlert = 3; // Room IDs. -static const RoomID kTSA01 = 1; -static const RoomID kTSA02 = 2; -static const RoomID kTSA03 = 3; -static const RoomID kTSA04 = 4; -static const RoomID kTSA05 = 5; -static const RoomID kTSA0A = 6; -static const RoomID kTSA06 = 7; -static const RoomID kTSA07 = 8; -static const RoomID kTSA08 = 9; -static const RoomID kTSA09 = 10; -static const RoomID kTSA10 = 11; -static const RoomID kTSA11 = 12; -static const RoomID kTSA12 = 13; -static const RoomID kTSA13 = 14; -static const RoomID kTSA14 = 15; -static const RoomID kTSA15 = 16; -static const RoomID kTSA16 = 17; -static const RoomID kTSA17 = 18; -static const RoomID kTSA18 = 19; -static const RoomID kTSA19 = 20; -static const RoomID kTSA0B = 21; -static const RoomID kTSA21Cyan = 22; -static const RoomID kTSA22Cyan = 23; -static const RoomID kTSA23Cyan = 24; -static const RoomID kTSA24Cyan = 25; -static const RoomID kTSA25Cyan = 26; -static const RoomID kTSA21Red = 27; -static const RoomID kTSA23Red = 29; -static const RoomID kTSA24Red = 30; -static const RoomID kTSA25Red = 31; -static const RoomID kTSA26 = 32; -static const RoomID kTSA27 = 33; -static const RoomID kTSA28 = 34; -static const RoomID kTSA29 = 35; -static const RoomID kTSA30 = 36; -static const RoomID kTSA31 = 37; -static const RoomID kTSA32 = 38; -static const RoomID kTSA33 = 39; -static const RoomID kTSA34 = 40; -static const RoomID kTSA35 = 41; -static const RoomID kTSADeathRoom = 43; +enum { + kTSA01 = 1, + kTSA02 = 2, + kTSA03 = 3, + kTSA04 = 4, + kTSA05 = 5, + kTSA0A = 6, + kTSA06 = 7, + kTSA07 = 8, + kTSA08 = 9, + kTSA09 = 10, + kTSA10 = 11, + kTSA11 = 12, + kTSA12 = 13, + kTSA13 = 14, + kTSA14 = 15, + kTSA15 = 16, + kTSA16 = 17, + kTSA17 = 18, + kTSA18 = 19, + kTSA19 = 20, + kTSA0B = 21, + kTSA21Cyan = 22, + kTSA22Cyan = 23, + kTSA23Cyan = 24, + kTSA24Cyan = 25, + kTSA25Cyan = 26, + kTSA21Red = 27, + kTSA23Red = 29, + kTSA24Red = 30, + kTSA25Red = 31, + kTSA26 = 32, + kTSA27 = 33, + kTSA28 = 34, + kTSA29 = 35, + kTSA30 = 36, + kTSA31 = 37, + kTSA32 = 38, + kTSA33 = 39, + kTSA34 = 40, + kTSA35 = 41, + kTSADeathRoom = 43 +}; // Hot Spot Activation IDs. -static const HotSpotActivationID kActivateTSAReadyForCard = 1; -static const HotSpotActivationID kActivateTSAReadyToTransport = 2; -static const HotSpotActivationID kActivateTSARobotsAwake = 3; -static const HotSpotActivationID kActivateTSA0BZoomedOut = 4; -static const HotSpotActivationID kActivateTSA0BZoomedIn = 5; -static const HotSpotActivationID kActivateTSA0BComparisonVideo = 6; -static const HotSpotActivationID kActivationLogReaderOpen = 7; -static const HotSpotActivationID kActivateTSA0BTBPVideo = 8; -static const HotSpotActivationID kActivationDoesntHaveKey = 9; -static const HotSpotActivationID kActivationKeyVaultOpen = 10; -static const HotSpotActivationID kActivationDoesntHaveChips = 11; -static const HotSpotActivationID kActivationChipVaultOpen = 12; -static const HotSpotActivationID kActivationJumpToPrehistoric = 13; -static const HotSpotActivationID kActivationJumpToNorad = 14; -static const HotSpotActivationID kActivationJumpToMars = 15; -static const HotSpotActivationID kActivationJumpToWSC = 16; -static const HotSpotActivationID kActivationReadyToExit = 17; -static const HotSpotActivationID kActivationReadyForJumpMenu = 18; -static const HotSpotActivationID kActivationMainJumpMenu = 19; +enum { + kActivateTSAReadyForCard = 1, + kActivateTSAReadyToTransport = 2, + kActivateTSARobotsAwake = 3, + kActivateTSA0BZoomedOut = 4, + kActivateTSA0BZoomedIn = 5, + kActivateTSA0BComparisonVideo = 6, + kActivationLogReaderOpen = 7, + kActivateTSA0BTBPVideo = 8, + kActivationDoesntHaveKey = 9, + kActivationKeyVaultOpen = 10, + kActivationDoesntHaveChips = 11, + kActivationChipVaultOpen = 12, + kActivationJumpToPrehistoric = 13, + kActivationJumpToNorad = 14, + kActivationJumpToMars = 15, + kActivationJumpToWSC = 16, + kActivationReadyToExit = 17, + kActivationReadyForJumpMenu = 18, + kActivationMainJumpMenu = 19 +}; // Hot Spot IDs. -static const HotSpotID kTSAGTCardDropSpotID = 5000; -static const HotSpotID kTSAGTTokyoSpotID = 5001; -static const HotSpotID kTSAGTCaldoriaSpotID = 5002; -static const HotSpotID kTSAGTBeachSpotID = 5003; -static const HotSpotID kTSAGTOtherSpotID = 5004; -static const HotSpotID kTSA02DoorSpotID = 5005; -static const HotSpotID kTSA03EastJimenezSpotID = 5006; -static const HotSpotID kTSA03WestCrenshawSpotID = 5007; -static const HotSpotID kTSA04EastMatsumotoSpotID = 5008; -static const HotSpotID kTSA04WestCastilleSpotID = 5009; -static const HotSpotID kTSA05EastSinclairSpotID = 5010; -static const HotSpotID kTSA05WestWhiteSpotID = 5011; -static const HotSpotID kTSA0AEastSpotID = 5012; -static const HotSpotID kTSA0AWastSpotID = 5013; -static const HotSpotID kTSA0BEastMonitorSpotID = 5014; -static const HotSpotID kTSA0BEastMonitorOutSpotID = 5015; -static const HotSpotID kTSA0BEastCompareNoradSpotID = 5016; -static const HotSpotID kTSA0BEastCompareMarsSpotID = 5017; -static const HotSpotID kTSA0BEastCompareCaldoriaSpotID = 5018; -static const HotSpotID kTSA0BEastCompareWSCSpotID = 5019; -static const HotSpotID kTSA0BEastLeftRewindSpotID = 5020; -static const HotSpotID kTSA0BEastLeftPlaySpotID = 5021; -static const HotSpotID kTSA0BEastRightRewindSpotID = 5022; -static const HotSpotID kTSA0BEastRightPlaySpotID = 5023; -static const HotSpotID kTSA0BEastCloseVideoSpotID = 5024; -static const HotSpotID kTSA0BNorthMonitorSpotID = 5025; -static const HotSpotID kTSA0BNorthMonitorOutSpotID = 5026; -static const HotSpotID kTSA0BNorthHistLogSpotID = 5027; -static const HotSpotID kTSA0BNorthRobotsToCommandCenterSpotID = 5028; -static const HotSpotID kTSA0BNorthRobotsToReadyRoomSpotID = 5029; -static const HotSpotID kTSA0BNorthRobotsToFrontDoorSpotID = 5030; -static const HotSpotID kTSA0BWestMonitorSpotID = 5031; -static const HotSpotID kTSA0BWestMonitorOutSpotID = 5032; -static const HotSpotID kTSA0BWestTheorySpotID = 5033; -static const HotSpotID kTSA0BWestBackgroundSpotID = 5034; -static const HotSpotID kTSA0BWestProcedureSpotID = 5035; -static const HotSpotID kTSA0BWestCloseVideoSpotID = 5036; -static const HotSpotID kTSA0BWestPlayVideoSpotID = 5037; -static const HotSpotID kTSA0BWestRewindVideoSpotID = 5038; -static const HotSpotID kTSA22EastMonitorSpotID = 5039; -static const HotSpotID kTSA22EastKeySpotID = 5040; -static const HotSpotID kTSA23WestMonitorSpotID = 5041; -static const HotSpotID kTSA23WestChipsSpotID = 5042; -static const HotSpotID kTSA34NorthDoorSpotID = 5043; -static const HotSpotID kTSA37NorthJumpToPrehistoricSpotID = 5044; -static const HotSpotID kTSA37NorthJumpToNoradSpotID = 5045; -static const HotSpotID kTSA37NorthCancelNoradSpotID = 5046; -static const HotSpotID kTSA37NorthJumpToMarsSpotID = 5047; -static const HotSpotID kTSA37NorthCancelMarsSpotID = 5048; -static const HotSpotID kTSA37NorthJumpToWSCSpotID = 5049; -static const HotSpotID kTSA37NorthCancelWSCSpotID = 5050; -static const HotSpotID kTSA37NorthExitSpotID = 5051; -static const HotSpotID kTSA37NorthJumpMenuSpotID = 5052; -static const HotSpotID kTSA37NorthNoradMenuSpotID = 5053; -static const HotSpotID kTSA37NorthMarsMenuSpotID = 5054; -static const HotSpotID kTSA37NorthWSCMenuSpotID = 5055; +enum { + kTSAGTCardDropSpotID = 5000, + kTSAGTTokyoSpotID = 5001, + kTSAGTCaldoriaSpotID = 5002, + kTSAGTBeachSpotID = 5003, + kTSAGTOtherSpotID = 5004, + kTSA02DoorSpotID = 5005, + kTSA03EastJimenezSpotID = 5006, + kTSA03WestCrenshawSpotID = 5007, + kTSA04EastMatsumotoSpotID = 5008, + kTSA04WestCastilleSpotID = 5009, + kTSA05EastSinclairSpotID = 5010, + kTSA05WestWhiteSpotID = 5011, + kTSA0AEastSpotID = 5012, + kTSA0AWastSpotID = 5013, + kTSA0BEastMonitorSpotID = 5014, + kTSA0BEastMonitorOutSpotID = 5015, + kTSA0BEastCompareNoradSpotID = 5016, + kTSA0BEastCompareMarsSpotID = 5017, + kTSA0BEastCompareCaldoriaSpotID = 5018, + kTSA0BEastCompareWSCSpotID = 5019, + kTSA0BEastLeftRewindSpotID = 5020, + kTSA0BEastLeftPlaySpotID = 5021, + kTSA0BEastRightRewindSpotID = 5022, + kTSA0BEastRightPlaySpotID = 5023, + kTSA0BEastCloseVideoSpotID = 5024, + kTSA0BNorthMonitorSpotID = 5025, + kTSA0BNorthMonitorOutSpotID = 5026, + kTSA0BNorthHistLogSpotID = 5027, + kTSA0BNorthRobotsToCommandCenterSpotID = 5028, + kTSA0BNorthRobotsToReadyRoomSpotID = 5029, + kTSA0BNorthRobotsToFrontDoorSpotID = 5030, + kTSA0BWestMonitorSpotID = 5031, + kTSA0BWestMonitorOutSpotID = 5032, + kTSA0BWestTheorySpotID = 5033, + kTSA0BWestBackgroundSpotID = 5034, + kTSA0BWestProcedureSpotID = 5035, + kTSA0BWestCloseVideoSpotID = 5036, + kTSA0BWestPlayVideoSpotID = 5037, + kTSA0BWestRewindVideoSpotID = 5038, + kTSA22EastMonitorSpotID = 5039, + kTSA22EastKeySpotID = 5040, + kTSA23WestMonitorSpotID = 5041, + kTSA23WestChipsSpotID = 5042, + kTSA34NorthDoorSpotID = 5043, + kTSA37NorthJumpToPrehistoricSpotID = 5044, + kTSA37NorthJumpToNoradSpotID = 5045, + kTSA37NorthCancelNoradSpotID = 5046, + kTSA37NorthJumpToMarsSpotID = 5047, + kTSA37NorthCancelMarsSpotID = 5048, + kTSA37NorthJumpToWSCSpotID = 5049, + kTSA37NorthCancelWSCSpotID = 5050, + kTSA37NorthExitSpotID = 5051, + kTSA37NorthJumpMenuSpotID = 5052, + kTSA37NorthNoradMenuSpotID = 5053, + kTSA37NorthMarsMenuSpotID = 5054, + kTSA37NorthWSCMenuSpotID = 5055 +}; // Extra sequence IDs. -static const ExtraID kTSATransporterArrowLoop = 0; -static const ExtraID kTSAArriveFromCaldoria = 1; -static const ExtraID kTSAGTOtherChoice = 2; -static const ExtraID kTSAGTCardSwipe = 3; -static const ExtraID kTSAGTSelectCaldoria = 4; -static const ExtraID kTSAGTGoToCaldoria = 5; -static const ExtraID kTSAGTSelectBeach = 6; -static const ExtraID kTSAGTGoToBeach = 7; -static const ExtraID kTSAGTArriveAtBeach = 8; -static const ExtraID kTSAGTSelectTokyo = 9; -static const ExtraID kTSAGTGoToTokyo = 10; -static const ExtraID kTSAGTArriveAtTokyo = 11; -static const ExtraID kTSA02NorthZoomIn = 12; -static const ExtraID kTSA02NorthTenSecondDoor = 13; -static const ExtraID kTSA02NorthZoomOut = 14; -static const ExtraID kTSA02NorthDoorWithAgent3 = 15; -static const ExtraID kTSA03JimenezZoomIn = 16; -static const ExtraID kTSA03JimenezSpeech = 17; -static const ExtraID kTSA03JimenezZoomOut = 18; -static const ExtraID kTSA03CrenshawZoomIn = 19; -static const ExtraID kTSA03CrenshawSpeech = 20; -static const ExtraID kTSA03CrenshawZoomOut = 21; -static const ExtraID kTSA03SouthRobotDeath = 22; -static const ExtraID kTSA04NorthRobotGreeting = 23; -static const ExtraID kTSA04MatsumotoZoomIn = 24; -static const ExtraID kTSA04MatsumotoSpeech = 25; -static const ExtraID kTSA04MatsumotoZoomOut = 26; -static const ExtraID kTSA04CastilleZoomIn = 27; -static const ExtraID kTSA04CastilleSpeech = 28; -static const ExtraID kTSA04CastilleZoomOut = 29; -static const ExtraID kTSA05SinclairZoomIn = 30; -static const ExtraID kTSA05SinclairSpeech = 31; -static const ExtraID kTSA05SinclairZoomOut = 32; -static const ExtraID kTSA05WhiteZoomIn = 33; -static const ExtraID kTSA05WhiteSpeech = 34; -static const ExtraID kTSA05WhiteZoomOut = 35; -static const ExtraID kTSA0AEastRobot = 36; -static const ExtraID kTSA0AWestRobot = 37; -static const ExtraID kTSA16NorthRobotDeath = 38; -static const ExtraID kTSA0BEastZoomIn = 39; -static const ExtraID kTSA0BEastZoomedView = 40; -static const ExtraID kTSA0BEastZoomOut = 41; -static const ExtraID kTSA0BEastTurnLeft = 42; -static const ExtraID kTSA0BComparisonStartup = 43; -static const ExtraID kTSA0BComparisonView0000 = 44; -static const ExtraID kTSA0BComparisonView0002 = 45; -static const ExtraID kTSA0BComparisonView0020 = 46; -static const ExtraID kTSA0BComparisonView0022 = 47; -static const ExtraID kTSA0BComparisonView0200 = 48; -static const ExtraID kTSA0BComparisonView0202 = 49; -static const ExtraID kTSA0BComparisonView0220 = 50; -static const ExtraID kTSA0BComparisonView0222 = 51; -static const ExtraID kTSA0BComparisonView2000 = 52; -static const ExtraID kTSA0BComparisonView2002 = 53; -static const ExtraID kTSA0BComparisonView2020 = 54; -static const ExtraID kTSA0BComparisonView2022 = 55; -static const ExtraID kTSA0BComparisonView2200 = 56; -static const ExtraID kTSA0BComparisonView2202 = 57; -static const ExtraID kTSA0BComparisonView2220 = 58; -static const ExtraID kTSA0BComparisonView2222 = 59; -static const ExtraID kTSA0BNoradComparisonView = 60; -static const ExtraID kTSA0BNoradUnaltered = 61; -static const ExtraID kTSA0BNoradAltered = 62; -static const ExtraID kTSA0BMarsComparisonView = 63; -static const ExtraID kTSA0BMarsUnaltered = 64; -static const ExtraID kTSA0BMarsAltered = 65; -static const ExtraID kTSA0BWSCComparisonView = 66; -static const ExtraID kTSA0BWSCUnaltered = 67; -static const ExtraID kTSA0BWSCAltered = 68; -static const ExtraID kTSA0BCaldoriaComparisonView = 69; -static const ExtraID kTSA0BCaldoriaUnaltered = 70; -static const ExtraID kTSA0BCaldoriaAltered = 71; -static const ExtraID kTSA0BNorthZoomIn = 72; -static const ExtraID kTSA0BNorthZoomedView = 73; -static const ExtraID kTSA0BNorthZoomOut = 74; -static const ExtraID kTSA0BNorthTurnLeft = 75; -static const ExtraID kTSA0BNorthTurnRight = 76; -static const ExtraID kTSA0BNorthHistLogOpen = 77; -static const ExtraID kTSA0BNorthHistLogClose = 78; -static const ExtraID kTSA0BNorthHistLogCloseWithLog = 79; -static const ExtraID kTSA0BNorthCantChangeHistory = 80; -static const ExtraID kTSA0BNorthYoureBusted = 81; -static const ExtraID kTSA0BNorthFinallyHappened = 82; -static const ExtraID kTSA0BShowRip1 = 83; -static const ExtraID kTSA0BNorthRipView1 = 84; -static const ExtraID kTSA0BShowRip2 = 85; -static const ExtraID kTSA0BShowGuardRobots = 86; -static const ExtraID kTSA0BAIInterruption = 87; -static const ExtraID kTSA0BRobotsToCommandCenter = 88; -static const ExtraID kTSA0BNorthRobotsAtCCView = 89; -static const ExtraID kTSA0BNorthRobotsAtRRView = 90; -static const ExtraID kTSA0BNorthRobotsAtFDView = 91; -static const ExtraID kTSA0BRobotsFromCommandCenterToReadyRoom = 92; -static const ExtraID kTSA0BRobotsFromReadyRoomToCommandCenter = 93; -static const ExtraID kTSA0BRobotsFromCommandCenterToFrontDoor = 94; -static const ExtraID kTSA0BRobotsFromFrontDoorToCommandCenter = 95; -static const ExtraID kTSA0BRobotsFromFrontDoorToReadyRoom = 96; -static const ExtraID kTSA0BRobotsFromReadyRoomToFrontDoor = 97; -static const ExtraID kTSA0BWestZoomIn = 98; -static const ExtraID kTSA0BWestZoomedView = 99; -static const ExtraID kTSA0BWestZoomOut = 100; -static const ExtraID kTSA0BWestTurnRight = 101; -static const ExtraID kTSA0BTBPTheoryHighlight = 102; -static const ExtraID kTSA0BTBPBackgroundHighlight = 103; -static const ExtraID kTSA0BTBPProcedureHighlight = 104; -static const ExtraID kTSA0BTBPTheory = 105; -static const ExtraID kTSA0BTBPBackground = 106; -static const ExtraID kTSA0BTBPProcedure = 107; -static const ExtraID kTSA0BRipAlarmScreen = 108; -static const ExtraID kTSA22RedEastZoomInSequence = 109; -static const ExtraID kTSA22RedEastVaultViewWithKey = 110; -static const ExtraID kTSA22RedEastVaultViewNoKey = 111; -static const ExtraID kTSA23RedWestVaultZoomInSequence = 112; -static const ExtraID kTSA23RedWestVaultViewWithChips = 113; -static const ExtraID kTSA23RedWestVaultViewNoChips = 114; -static const ExtraID kTSA25NorthDeniedNoKey = 115; -static const ExtraID kTSA25NorthDeniedNoChip = 116; -static const ExtraID kTSA25NorthPutOnSuit = 117; -static const ExtraID kTSA25NorthAlreadyHaveSuit = 118; -static const ExtraID kTSA25NorthDescending1 = 119; -static const ExtraID kTSA25NorthDescending2 = 120; -static const ExtraID kTSA37HorseToAI1 = 121; -static const ExtraID kTSA37PegasusAI1 = 122; -static const ExtraID kTSA37AI1ToCommissioner1 = 123; -static const ExtraID kTSA37Commissioner1 = 124; -static const ExtraID kTSA37Commissioner1ToZoom = 125; -static const ExtraID kTSA37ZoomToPrehistoric = 126; -static const ExtraID kTSA37PrehistoricToAI2 = 127; -static const ExtraID kTSA37PegasusAI2 = 128; -static const ExtraID kTSA37AI2ToPrehistoric = 129; -static const ExtraID kTSA37PrehistoricToDepart = 130; -static const ExtraID kTSA37PegasusDepart = 131; -static const ExtraID kTSA37TimeJumpToPegasus = 132; -static const ExtraID kTSA37RecallToDownload = 133; -static const ExtraID kTSA37DownloadToColonel1 = 134; -static const ExtraID kTSA37Colonel1 = 135; -static const ExtraID kTSA37Colonel1ToReviewRequired = 136; -static const ExtraID kTSA37ReviewRequiredToExit = 137; -static const ExtraID kTSA37ExitHilited = 138; -static const ExtraID kTSA37ExitToHorse = 139; -static const ExtraID kTSA37HorseToColonel2 = 140; -static const ExtraID kTSA37Colonel2 = 141; -static const ExtraID kTSA37PegasusAI3 = 142; -static const ExtraID kTSA37AI3ToHorse = 143; -static const ExtraID kTSA37HorseToZoom = 144; -static const ExtraID kTSA37ZoomToMainMenu = 145; -static const ExtraID kTSA37MainMenuToAI4 = 146; -static const ExtraID kTSA37PegasusAI4 = 147; -static const ExtraID kTSA37AI4ToMainMenu = 148; -static const ExtraID kTSA37JumpMenu000 = 149; -static const ExtraID kTSA37JumpMenu001 = 150; -static const ExtraID kTSA37JumpMenu010 = 151; -static const ExtraID kTSA37JumpMenu011 = 152; -static const ExtraID kTSA37JumpMenu100 = 153; -static const ExtraID kTSA37JumpMenu101 = 154; -static const ExtraID kTSA37JumpMenu110 = 155; -static const ExtraID kTSA37JumpMenu111 = 156; -static const ExtraID kTSA37JumpToWSCMenu = 157; -static const ExtraID kTSA37CancelWSC = 158; -static const ExtraID kTSA37JumpToWSC = 159; -static const ExtraID kTSA37WSCToAI5 = 160; -static const ExtraID kTSA37PegasusAI5 = 161; -static const ExtraID kTSA37AI5ToWSC = 162; -static const ExtraID kTSA37WSCToDepart = 163; -static const ExtraID kTSA37JumpToMarsMenu = 164; -static const ExtraID kTSA37CancelMars = 165; -static const ExtraID kTSA37JumpToMars = 166; -static const ExtraID kTSA37MarsToAI6 = 167; -static const ExtraID kTSA37PegasusAI6 = 168; -static const ExtraID kTSA37AI6ToMars = 169; -static const ExtraID kTSA37MarsToDepart = 170; -static const ExtraID kTSA37JumpToNoradMenu = 171; -static const ExtraID kTSA37CancelNorad = 172; -static const ExtraID kTSA37JumpToNorad = 173; -static const ExtraID kTSA37NoradToAI7 = 174; -static const ExtraID kTSA37PegasusAI7 = 175; -static const ExtraID kTSA37AI7ToNorad = 176; -static const ExtraID kTSA37NoradToDepart = 177; -static const ExtraID kTSA37EnvironmentalScan = 178; -static const ExtraID kTSA37DownloadToMainMenu = 179; -static const ExtraID kTSA37DownloadToOpMemReview = 180; -static const ExtraID kTSA37OpMemReviewToMainMenu = 181; -static const ExtraID kTSA37OpMemReviewToAllClear = 182; -static const ExtraID kTSA37AllClearToCongratulations = 183; -static const ExtraID kTSA37Congratulations = 184; -static const ExtraID kTSA37CongratulationsToExit = 185; +enum { + kTSATransporterArrowLoop = 0, + kTSAArriveFromCaldoria = 1, + kTSAGTOtherChoice = 2, + kTSAGTCardSwipe = 3, + kTSAGTSelectCaldoria = 4, + kTSAGTGoToCaldoria = 5, + kTSAGTSelectBeach = 6, + kTSAGTGoToBeach = 7, + kTSAGTArriveAtBeach = 8, + kTSAGTSelectTokyo = 9, + kTSAGTGoToTokyo = 10, + kTSAGTArriveAtTokyo = 11, + kTSA02NorthZoomIn = 12, + kTSA02NorthTenSecondDoor = 13, + kTSA02NorthZoomOut = 14, + kTSA02NorthDoorWithAgent3 = 15, + kTSA03JimenezZoomIn = 16, + kTSA03JimenezSpeech = 17, + kTSA03JimenezZoomOut = 18, + kTSA03CrenshawZoomIn = 19, + kTSA03CrenshawSpeech = 20, + kTSA03CrenshawZoomOut = 21, + kTSA03SouthRobotDeath = 22, + kTSA04NorthRobotGreeting = 23, + kTSA04MatsumotoZoomIn = 24, + kTSA04MatsumotoSpeech = 25, + kTSA04MatsumotoZoomOut = 26, + kTSA04CastilleZoomIn = 27, + kTSA04CastilleSpeech = 28, + kTSA04CastilleZoomOut = 29, + kTSA05SinclairZoomIn = 30, + kTSA05SinclairSpeech = 31, + kTSA05SinclairZoomOut = 32, + kTSA05WhiteZoomIn = 33, + kTSA05WhiteSpeech = 34, + kTSA05WhiteZoomOut = 35, + kTSA0AEastRobot = 36, + kTSA0AWestRobot = 37, + kTSA16NorthRobotDeath = 38, + kTSA0BEastZoomIn = 39, + kTSA0BEastZoomedView = 40, + kTSA0BEastZoomOut = 41, + kTSA0BEastTurnLeft = 42, + kTSA0BComparisonStartup = 43, + kTSA0BComparisonView0000 = 44, + kTSA0BComparisonView0002 = 45, + kTSA0BComparisonView0020 = 46, + kTSA0BComparisonView0022 = 47, + kTSA0BComparisonView0200 = 48, + kTSA0BComparisonView0202 = 49, + kTSA0BComparisonView0220 = 50, + kTSA0BComparisonView0222 = 51, + kTSA0BComparisonView2000 = 52, + kTSA0BComparisonView2002 = 53, + kTSA0BComparisonView2020 = 54, + kTSA0BComparisonView2022 = 55, + kTSA0BComparisonView2200 = 56, + kTSA0BComparisonView2202 = 57, + kTSA0BComparisonView2220 = 58, + kTSA0BComparisonView2222 = 59, + kTSA0BNoradComparisonView = 60, + kTSA0BNoradUnaltered = 61, + kTSA0BNoradAltered = 62, + kTSA0BMarsComparisonView = 63, + kTSA0BMarsUnaltered = 64, + kTSA0BMarsAltered = 65, + kTSA0BWSCComparisonView = 66, + kTSA0BWSCUnaltered = 67, + kTSA0BWSCAltered = 68, + kTSA0BCaldoriaComparisonView = 69, + kTSA0BCaldoriaUnaltered = 70, + kTSA0BCaldoriaAltered = 71, + kTSA0BNorthZoomIn = 72, + kTSA0BNorthZoomedView = 73, + kTSA0BNorthZoomOut = 74, + kTSA0BNorthTurnLeft = 75, + kTSA0BNorthTurnRight = 76, + kTSA0BNorthHistLogOpen = 77, + kTSA0BNorthHistLogClose = 78, + kTSA0BNorthHistLogCloseWithLog = 79, + kTSA0BNorthCantChangeHistory = 80, + kTSA0BNorthYoureBusted = 81, + kTSA0BNorthFinallyHappened = 82, + kTSA0BShowRip1 = 83, + kTSA0BNorthRipView1 = 84, + kTSA0BShowRip2 = 85, + kTSA0BShowGuardRobots = 86, + kTSA0BAIInterruption = 87, + kTSA0BRobotsToCommandCenter = 88, + kTSA0BNorthRobotsAtCCView = 89, + kTSA0BNorthRobotsAtRRView = 90, + kTSA0BNorthRobotsAtFDView = 91, + kTSA0BRobotsFromCommandCenterToReadyRoom = 92, + kTSA0BRobotsFromReadyRoomToCommandCenter = 93, + kTSA0BRobotsFromCommandCenterToFrontDoor = 94, + kTSA0BRobotsFromFrontDoorToCommandCenter = 95, + kTSA0BRobotsFromFrontDoorToReadyRoom = 96, + kTSA0BRobotsFromReadyRoomToFrontDoor = 97, + kTSA0BWestZoomIn = 98, + kTSA0BWestZoomedView = 99, + kTSA0BWestZoomOut = 100, + kTSA0BWestTurnRight = 101, + kTSA0BTBPTheoryHighlight = 102, + kTSA0BTBPBackgroundHighlight = 103, + kTSA0BTBPProcedureHighlight = 104, + kTSA0BTBPTheory = 105, + kTSA0BTBPBackground = 106, + kTSA0BTBPProcedure = 107, + kTSA0BRipAlarmScreen = 108, + kTSA22RedEastZoomInSequence = 109, + kTSA22RedEastVaultViewWithKey = 110, + kTSA22RedEastVaultViewNoKey = 111, + kTSA23RedWestVaultZoomInSequence = 112, + kTSA23RedWestVaultViewWithChips = 113, + kTSA23RedWestVaultViewNoChips = 114, + kTSA25NorthDeniedNoKey = 115, + kTSA25NorthDeniedNoChip = 116, + kTSA25NorthPutOnSuit = 117, + kTSA25NorthAlreadyHaveSuit = 118, + kTSA25NorthDescending1 = 119, + kTSA25NorthDescending2 = 120, + kTSA37HorseToAI1 = 121, + kTSA37PegasusAI1 = 122, + kTSA37AI1ToCommissioner1 = 123, + kTSA37Commissioner1 = 124, + kTSA37Commissioner1ToZoom = 125, + kTSA37ZoomToPrehistoric = 126, + kTSA37PrehistoricToAI2 = 127, + kTSA37PegasusAI2 = 128, + kTSA37AI2ToPrehistoric = 129, + kTSA37PrehistoricToDepart = 130, + kTSA37PegasusDepart = 131, + kTSA37TimeJumpToPegasus = 132, + kTSA37RecallToDownload = 133, + kTSA37DownloadToColonel1 = 134, + kTSA37Colonel1 = 135, + kTSA37Colonel1ToReviewRequired = 136, + kTSA37ReviewRequiredToExit = 137, + kTSA37ExitHilited = 138, + kTSA37ExitToHorse = 139, + kTSA37HorseToColonel2 = 140, + kTSA37Colonel2 = 141, + kTSA37PegasusAI3 = 142, + kTSA37AI3ToHorse = 143, + kTSA37HorseToZoom = 144, + kTSA37ZoomToMainMenu = 145, + kTSA37MainMenuToAI4 = 146, + kTSA37PegasusAI4 = 147, + kTSA37AI4ToMainMenu = 148, + kTSA37JumpMenu000 = 149, + kTSA37JumpMenu001 = 150, + kTSA37JumpMenu010 = 151, + kTSA37JumpMenu011 = 152, + kTSA37JumpMenu100 = 153, + kTSA37JumpMenu101 = 154, + kTSA37JumpMenu110 = 155, + kTSA37JumpMenu111 = 156, + kTSA37JumpToWSCMenu = 157, + kTSA37CancelWSC = 158, + kTSA37JumpToWSC = 159, + kTSA37WSCToAI5 = 160, + kTSA37PegasusAI5 = 161, + kTSA37AI5ToWSC = 162, + kTSA37WSCToDepart = 163, + kTSA37JumpToMarsMenu = 164, + kTSA37CancelMars = 165, + kTSA37JumpToMars = 166, + kTSA37MarsToAI6 = 167, + kTSA37PegasusAI6 = 168, + kTSA37AI6ToMars = 169, + kTSA37MarsToDepart = 170, + kTSA37JumpToNoradMenu = 171, + kTSA37CancelNorad = 172, + kTSA37JumpToNorad = 173, + kTSA37NoradToAI7 = 174, + kTSA37PegasusAI7 = 175, + kTSA37AI7ToNorad = 176, + kTSA37NoradToDepart = 177, + kTSA37EnvironmentalScan = 178, + kTSA37DownloadToMainMenu = 179, + kTSA37DownloadToOpMemReview = 180, + kTSA37OpMemReviewToMainMenu = 181, + kTSA37OpMemReviewToAllClear = 182, + kTSA37AllClearToCongratulations = 183, + kTSA37Congratulations = 184, + kTSA37CongratulationsToExit = 185 +}; const DisplayOrder kRipTimerOrder = kMonitorLayer; +enum { + kUnresolvedLeft = kNavAreaLeft + 14, + kUnresolvedTop = kNavAreaTop + 236, -const CoordType kUnresolvedLeft = kNavAreaLeft + 14; -const CoordType kUnresolvedTop = kNavAreaTop + 236; - -const CoordType kResolvedLeft = kNavAreaLeft + 36; -const CoordType kResolvedTop = kNavAreaTop + 236; + kResolvedLeft = kNavAreaLeft + 36, + kResolvedTop = kNavAreaTop + 236, -const CoordType kJumpMenuLeft = kNavAreaLeft + 360; -const CoordType kJumpMenuTop = kNavAreaTop + 202; + kJumpMenuLeft = kNavAreaLeft + 360, + kJumpMenuTop = kNavAreaTop + 202, -const CoordType kJumpMenuHilitedLeft = kNavAreaLeft + 354; -const CoordType kJumpMenuHilitedTop = kNavAreaTop + 196; + kJumpMenuHilitedLeft = kNavAreaLeft + 354, + kJumpMenuHilitedTop = kNavAreaTop + 196, -const CoordType kExitLeft = kNavAreaLeft + 360; -const CoordType kExitTop = kNavAreaTop + 216; + kExitLeft = kNavAreaLeft + 360, + kExitTop = kNavAreaTop + 216, -const CoordType kExitHilitedLeft = kNavAreaLeft + 354; -const CoordType kExitHilitedTop = kNavAreaTop + 210; + kExitHilitedLeft = kNavAreaLeft + 354, + kExitHilitedTop = kNavAreaTop + 210, -const CoordType kRipTimerLeft = kNavAreaLeft + 95; -const CoordType kRipTimerTop = kNavAreaTop + 87; + kRipTimerLeft = kNavAreaLeft + 95, + kRipTimerTop = kNavAreaTop + 87, -const CoordType kTBPCloseLeft = kNavAreaLeft + 30; -const CoordType kTBPCloseTop = kNavAreaTop + 16; + kTBPCloseLeft = kNavAreaLeft + 30, + kTBPCloseTop = kNavAreaTop + 16, -const CoordType kTBPRewindLeft = kNavAreaLeft + 86; -const CoordType kTBPRewindTop = kNavAreaTop + 218; + kTBPRewindLeft = kNavAreaLeft + 86, + kTBPRewindTop = kNavAreaTop + 218, -const CoordType kComparisonCloseLeft = kNavAreaLeft + 50; -const CoordType kComparisonCloseTop = kNavAreaTop + 14; + kComparisonCloseLeft = kNavAreaLeft + 50, + kComparisonCloseTop = kNavAreaTop + 14, -const CoordType kComparisonLeftRewindLeft = kNavAreaLeft + 96; -const CoordType kComparisonLeftRewindTop = kNavAreaTop + 190; + kComparisonLeftRewindLeft = kNavAreaLeft + 96, + kComparisonLeftRewindTop = kNavAreaTop + 190, -const CoordType kComparisonRightRewindLeft = kNavAreaLeft + 282; -const CoordType kComparisonRightRewindTop = kNavAreaTop + 190; + kComparisonRightRewindLeft = kNavAreaLeft + 282, + kComparisonRightRewindTop = kNavAreaTop + 190, -const CoordType kComparisonHiliteSpriteLeft = kNavAreaLeft + 45; -const CoordType kComparisonHiliteSpriteTop = kNavAreaTop + 65; + kComparisonHiliteSpriteLeft = kNavAreaLeft + 45, + kComparisonHiliteSpriteTop = kNavAreaTop + 65, -const CoordType kComparisonHiliteNoradLeft = kNavAreaLeft + 45; -const CoordType kComparisonHiliteNoradTop = kNavAreaTop + 65; + kComparisonHiliteNoradLeft = kNavAreaLeft + 45, + kComparisonHiliteNoradTop = kNavAreaTop + 65, -const CoordType kComparisonHiliteMarsLeft = kNavAreaLeft + 45 + 4; -const CoordType kComparisonHiliteMarsTop = kNavAreaTop + 65 + 23; + kComparisonHiliteMarsLeft = kNavAreaLeft + 45 + 4, + kComparisonHiliteMarsTop = kNavAreaTop + 65 + 23, -const CoordType kComparisonHiliteCaldoriaLeft = kNavAreaLeft + 45 + 7; -const CoordType kComparisonHiliteCaldoriaTop = kNavAreaTop + 65 + 46; + kComparisonHiliteCaldoriaLeft = kNavAreaLeft + 45 + 7, + kComparisonHiliteCaldoriaTop = kNavAreaTop + 65 + 46, -const CoordType kComparisonHiliteWSCLeft = kNavAreaLeft + 45 + 11; -const CoordType kComparisonHiliteWSCTop = kNavAreaTop + 65 + 68; + kComparisonHiliteWSCLeft = kNavAreaLeft + 45 + 11, + kComparisonHiliteWSCTop = kNavAreaTop + 65 + 68, -const CoordType kComparisonChancesSpriteLeft = kNavAreaLeft + 148; -const CoordType kComparisonChancesSpriteTop = kNavAreaTop + 162; + kComparisonChancesSpriteLeft = kNavAreaLeft + 148, + kComparisonChancesSpriteTop = kNavAreaTop + 162, -const CoordType kComparisonChancesNoradLeft = kNavAreaLeft + 148; -const CoordType kComparisonChancesNoradTop = kNavAreaTop + 162; + kComparisonChancesNoradLeft = kNavAreaLeft + 148, + kComparisonChancesNoradTop = kNavAreaTop + 162, -const CoordType kComparisonChancesMarsLeft = kNavAreaLeft + 148; -const CoordType kComparisonChancesMarsTop = kNavAreaTop + 162; + kComparisonChancesMarsLeft = kNavAreaLeft + 148, + kComparisonChancesMarsTop = kNavAreaTop + 162, -const CoordType kComparisonChancesCaldoriaLeft = kNavAreaLeft + 148; -const CoordType kComparisonChancesCaldoriaTop = kNavAreaTop + 162 + 1; + kComparisonChancesCaldoriaLeft = kNavAreaLeft + 148, + kComparisonChancesCaldoriaTop = kNavAreaTop + 162 + 1, -const CoordType kComparisonChancesWSCLeft = kNavAreaLeft + 148; -const CoordType kComparisonChancesWSCTop = kNavAreaTop + 162; + kComparisonChancesWSCLeft = kNavAreaLeft + 148, + kComparisonChancesWSCTop = kNavAreaTop + 162, -const CoordType kRedirectionSprite1Left = kNavAreaLeft + 58; -const CoordType kRedirectionSprite1Top = kNavAreaTop + 16; + kRedirectionSprite1Left = kNavAreaLeft + 58, + kRedirectionSprite1Top = kNavAreaTop + 16, -const CoordType kRedirectionSprite2Left = kNavAreaLeft + 36; -const CoordType kRedirectionSprite2Top = kNavAreaTop + 166; + kRedirectionSprite2Left = kNavAreaLeft + 36, + kRedirectionSprite2Top = kNavAreaTop + 166, -const CoordType kRedirectionCCRolloverLeft = kNavAreaLeft + 58; -const CoordType kRedirectionCCRolloverTop = kNavAreaTop + 16; + kRedirectionCCRolloverLeft = kNavAreaLeft + 58, + kRedirectionCCRolloverTop = kNavAreaTop + 16, -const CoordType kRedirectionRRRolloverLeft = kNavAreaLeft + 430; -const CoordType kRedirectionRRRolloverTop = kNavAreaTop + 30; + kRedirectionRRRolloverLeft = kNavAreaLeft + 430, + kRedirectionRRRolloverTop = kNavAreaTop + 30, -const CoordType kRedirectionFDRolloverLeft = kNavAreaLeft + 278; -const CoordType kRedirectionFDRolloverTop = kNavAreaTop + 160; + kRedirectionFDRolloverLeft = kNavAreaLeft + 278, + kRedirectionFDRolloverTop = kNavAreaTop + 160, -const CoordType kRedirectionCCDoorLeft = kNavAreaLeft + 174; -const CoordType kRedirectionCCDoorTop = kNavAreaTop + 36; + kRedirectionCCDoorLeft = kNavAreaLeft + 174, + kRedirectionCCDoorTop = kNavAreaTop + 36, -const CoordType kRedirectionRRDoorLeft = kNavAreaLeft + 418; -const CoordType kRedirectionRRDoorTop = kNavAreaTop + 32; + kRedirectionRRDoorLeft = kNavAreaLeft + 418, + kRedirectionRRDoorTop = kNavAreaTop + 32, -const CoordType kRedirectionFDDoorLeft = kNavAreaLeft + 298; -const CoordType kRedirectionFDDoorTop = kNavAreaTop + 240; + kRedirectionFDDoorLeft = kNavAreaLeft + 298, + kRedirectionFDDoorTop = kNavAreaTop + 240, -const CoordType kRedirectionSecuredLeft = kNavAreaLeft + 36; -const CoordType kRedirectionSecuredTop = kNavAreaTop + 166; + kRedirectionSecuredLeft = kNavAreaLeft + 36, + kRedirectionSecuredTop = kNavAreaTop + 166, -const CoordType kRedirectionNewTargetLeft = kNavAreaLeft + 36; -const CoordType kRedirectionNewTargetTop = kNavAreaTop + 166; + kRedirectionNewTargetLeft = kNavAreaLeft + 36, + kRedirectionNewTargetTop = kNavAreaTop + 166, -const CoordType kRedirectionCloseLeft = kNavAreaLeft + 56; -const CoordType kRedirectionCloseTop = kNavAreaTop + 220; + kRedirectionCloseLeft = kNavAreaLeft + 56, + kRedirectionCloseTop = kNavAreaTop + 220 +}; static const TimeValue kTSABumpIntoWallIn = 0; static const TimeValue kTSABumpIntoWallOut = 148; @@ -516,10 +529,12 @@ static const TimeValue kTSAVaultCloseOut = 5388; static const TimeValue kTSAPegasusDoorCloseIn = 5388; static const TimeValue kTSAPegasusDoorCloseOut = 6457; -static const bool kPegasusUnresolved = false; -static const bool kPegasusResolved = true; -static const bool kPegasusCantExit = false; -static const bool kPegasusCanExit = true; +enum { + kPegasusUnresolved = false, + kPegasusResolved = true, + kPegasusCantExit = false, + kPegasusCanExit = true +}; // Monitor modes enum { @@ -582,15 +597,17 @@ static const ExtraID s_historicalLogViews[16] = { kTSA0BComparisonView2222 }; -static const int kRedirectionCCRolloverSprite = 0; -static const int kRedirectionRRRolloverSprite = 1; -static const int kRedirectionFDRolloverSprite = 2; -static const int kRedirectionCCDoorSprite = 3; -static const int kRedirectionRRDoorSprite = 4; -static const int kRedirectionFDDoorSprite = 5; -static const int kRedirectionCloseSprite = 6; -static const int kRedirectionSecuredSprite = 0; -static const int kRedirectionNewTargetSprite = 1; +enum { + kRedirectionCCRolloverSprite = 0, + kRedirectionRRRolloverSprite = 1, + kRedirectionFDRolloverSprite = 2, + kRedirectionCCDoorSprite = 3, + kRedirectionRRDoorSprite = 4, + kRedirectionFDDoorSprite = 5, + kRedirectionCloseSprite = 6, + kRedirectionSecuredSprite = 0, + kRedirectionNewTargetSprite = 1 +}; void RipTimer::initImage() { _middle = -1; diff --git a/engines/pegasus/neighborhood/tsa/tinytsa.cpp b/engines/pegasus/neighborhood/tsa/tinytsa.cpp index c808325b0f..0c29e06f41 100644 --- a/engines/pegasus/neighborhood/tsa/tinytsa.cpp +++ b/engines/pegasus/neighborhood/tsa/tinytsa.cpp @@ -38,71 +38,81 @@ namespace Pegasus { static const int16 kCompassShift = 30; -static const TimeScale kTinyTSAMovieScale = 600; -static const TimeScale kTinyTSAFramesPerSecond = 15; -static const TimeScale kTinyTSAFrameDuration = 40; +enum { + kTinyTSAMovieScale = 600, + kTinyTSAFramesPerSecond = 15, + kTinyTSAFrameDuration = 40 +}; // Alternate IDs. -static const AlternateID kAltTinyTSANormal = 0; +enum { + kAltTinyTSANormal = 0 +}; // Hot Spot Activation IDs. -static const HotSpotActivationID kActivationTinyTSAJumpToNorad = 1; -static const HotSpotActivationID kActivationTinyTSAJumpToMars = 2; -static const HotSpotActivationID kActivationTinyTSAJumpToWSC = 3; -static const HotSpotActivationID kActivationTinyTSAReadyForJumpMenu = 4; -static const HotSpotActivationID kActivationTinyTSAMainJumpMenu = 5; +enum { + kActivationTinyTSAJumpToNorad = 1, + kActivationTinyTSAJumpToMars = 2, + kActivationTinyTSAJumpToWSC = 3, + kActivationTinyTSAReadyForJumpMenu = 4, + kActivationTinyTSAMainJumpMenu = 5 +}; // Hot Spot IDs. -static const HotSpotID kTinyTSA37NorthJumpToNoradSpotID = 5000; -static const HotSpotID kTinyTSA37NorthCancelNoradSpotID = 5001; -static const HotSpotID kTinyTSA37NorthJumpToMarsSpotID = 5002; -static const HotSpotID kTinyTSA37NorthCancelMarsSpotID = 5003; -static const HotSpotID kTinyTSA37NorthJumpToWSCSpotID = 5004; -static const HotSpotID kTinyTSA37NorthCancelWSCSpotID = 5005; -static const HotSpotID kTinyTSA37NorthJumpMenuSpotID = 5006; -static const HotSpotID kTinyTSA37NorthNoradMenuSpotID = 5007; -static const HotSpotID kTinyTSA37NorthMarsMenuSpotID = 5008; -static const HotSpotID kTinyTSA37NorthWSCMenuSpotID = 5009; +enum { + kTinyTSA37NorthJumpToNoradSpotID = 5000, + kTinyTSA37NorthCancelNoradSpotID = 5001, + kTinyTSA37NorthJumpToMarsSpotID = 5002, + kTinyTSA37NorthCancelMarsSpotID = 5003, + kTinyTSA37NorthJumpToWSCSpotID = 5004, + kTinyTSA37NorthCancelWSCSpotID = 5005, + kTinyTSA37NorthJumpMenuSpotID = 5006, + kTinyTSA37NorthNoradMenuSpotID = 5007, + kTinyTSA37NorthMarsMenuSpotID = 5008, + kTinyTSA37NorthWSCMenuSpotID = 5009 +}; // Extra sequence IDs. -static const ExtraID kTinyTSA37PegasusDepart = 0; -static const ExtraID kTinyTSA37TimeJumpToPegasus = 1; -static const ExtraID kTinyTSA37RecallToDownload = 2; -static const ExtraID kTinyTSA37ExitHilited = 3; -static const ExtraID kTinyTSA37ExitToHorse = 4; -static const ExtraID kTinyTSA37JumpMenu000 = 5; -static const ExtraID kTinyTSA37JumpMenu001 = 6; -static const ExtraID kTinyTSA37JumpMenu010 = 7; -static const ExtraID kTinyTSA37JumpMenu011 = 8; -static const ExtraID kTinyTSA37JumpMenu100 = 9; -static const ExtraID kTinyTSA37JumpMenu101 = 10; -static const ExtraID kTinyTSA37JumpMenu110 = 11; -static const ExtraID kTinyTSA37JumpMenu111 = 12; -static const ExtraID kTinyTSA37JumpToWSCMenu = 13; -static const ExtraID kTinyTSA37CancelWSC = 14; -static const ExtraID kTinyTSA37JumpToWSC = 15; -static const ExtraID kTinyTSA37WSCToAI5 = 16; -static const ExtraID kTinyTSA37PegasusAI5 = 17; -static const ExtraID kTinyTSA37AI5ToWSC = 18; -static const ExtraID kTinyTSA37WSCToDepart = 19; -static const ExtraID kTinyTSA37JumpToMarsMenu = 20; -static const ExtraID kTinyTSA37CancelMars = 21; -static const ExtraID kTinyTSA37JumpToMars = 22; -static const ExtraID kTinyTSA37MarsToAI6 = 23; -static const ExtraID kTinyTSA37PegasusAI6 = 24; -static const ExtraID kTinyTSA37AI6ToMars = 25; -static const ExtraID kTinyTSA37MarsToDepart = 26; -static const ExtraID kTinyTSA37JumpToNoradMenu = 27; -static const ExtraID kTinyTSA37CancelNorad = 28; -static const ExtraID kTinyTSA37JumpToNorad = 29; -static const ExtraID kTinyTSA37NoradToAI7 = 30; -static const ExtraID kTinyTSA37PegasusAI7 = 31; -static const ExtraID kTinyTSA37AI7ToNorad = 32; -static const ExtraID kTinyTSA37NoradToDepart = 33; -static const ExtraID kTinyTSA37EnvironmentalScan = 34; -static const ExtraID kTinyTSA37DownloadToMainMenu = 35; -static const ExtraID kTinyTSA37DownloadToOpMemReview = 36; -static const ExtraID kTinyTSA37OpMemReviewToMainMenu = 37; +enum { + kTinyTSA37PegasusDepart = 0, + kTinyTSA37TimeJumpToPegasus = 1, + kTinyTSA37RecallToDownload = 2, + kTinyTSA37ExitHilited = 3, + kTinyTSA37ExitToHorse = 4, + kTinyTSA37JumpMenu000 = 5, + kTinyTSA37JumpMenu001 = 6, + kTinyTSA37JumpMenu010 = 7, + kTinyTSA37JumpMenu011 = 8, + kTinyTSA37JumpMenu100 = 9, + kTinyTSA37JumpMenu101 = 10, + kTinyTSA37JumpMenu110 = 11, + kTinyTSA37JumpMenu111 = 12, + kTinyTSA37JumpToWSCMenu = 13, + kTinyTSA37CancelWSC = 14, + kTinyTSA37JumpToWSC = 15, + kTinyTSA37WSCToAI5 = 16, + kTinyTSA37PegasusAI5 = 17, + kTinyTSA37AI5ToWSC = 18, + kTinyTSA37WSCToDepart = 19, + kTinyTSA37JumpToMarsMenu = 20, + kTinyTSA37CancelMars = 21, + kTinyTSA37JumpToMars = 22, + kTinyTSA37MarsToAI6 = 23, + kTinyTSA37PegasusAI6 = 24, + kTinyTSA37AI6ToMars = 25, + kTinyTSA37MarsToDepart = 26, + kTinyTSA37JumpToNoradMenu = 27, + kTinyTSA37CancelNorad = 28, + kTinyTSA37JumpToNorad = 29, + kTinyTSA37NoradToAI7 = 30, + kTinyTSA37PegasusAI7 = 31, + kTinyTSA37AI7ToNorad = 32, + kTinyTSA37NoradToDepart = 33, + kTinyTSA37EnvironmentalScan = 34, + kTinyTSA37DownloadToMainMenu = 35, + kTinyTSA37DownloadToOpMemReview = 36, + kTinyTSA37OpMemReviewToMainMenu = 37 +}; TinyTSA::TinyTSA(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "Tiny TSA", kTinyTSAID) { } diff --git a/engines/pegasus/neighborhood/wsc/wsc.cpp b/engines/pegasus/neighborhood/wsc/wsc.cpp index f009b35cdc..5e35d8ccc1 100644 --- a/engines/pegasus/neighborhood/wsc/wsc.cpp +++ b/engines/pegasus/neighborhood/wsc/wsc.cpp @@ -87,81 +87,85 @@ static const int kTimerEventPlasmaHit = 0; static const int kTimerEventPlayerGawkingAtRobot = 1; static const int kTimerEventPlayerGawkingAtRobot2 = 2; -static const TimeValue kWSCMolecule1In = 0; -static const TimeValue kWSCMolecule1Out = 937; +enum { + kWSCMolecule1In = 0, + kWSCMolecule1Out = 937, -static const TimeValue kWSCMolecule2In = 937; -static const TimeValue kWSCMolecule2Out = 1864; + kWSCMolecule2In = 937, + kWSCMolecule2Out = 1864, -static const TimeValue kWSCMolecule3In = 1864; -static const TimeValue kWSCMolecule3Out = 2790; + kWSCMolecule3In = 1864, + kWSCMolecule3Out = 2790, -static const TimeValue kWSCClick1In = 2790; -static const TimeValue kWSCClick1Out = 2890; + kWSCClick1In = 2790, + kWSCClick1Out = 2890, -static const TimeValue kWSCClick2In = 2890; -static const TimeValue kWSCClick2Out = 3059; + kWSCClick2In = 2890, + kWSCClick2Out = 3059, -static const TimeValue kWSCClick3In = 3059; -static const TimeValue kWSCClick3Out = 3156; + kWSCClick3In = 3059, + kWSCClick3Out = 3156, -static const TimeValue kWSCFlashlightClickIn = 3156; -static const TimeValue kWSCFlashlightClickOut = 3211; + kWSCFlashlightClickIn = 3156, + kWSCFlashlightClickOut = 3211, -static const TimeValue kWSCBumpIntoWallIn = 3211; -static const TimeValue kWSCBumpIntoWallOut = 3514; + kWSCBumpIntoWallIn = 3211, + kWSCBumpIntoWallOut = 3514, -static const TimeValue kWSCCantTransportIn = 3514; -static const TimeValue kWSCCantTransportOut = 7791; + kWSCCantTransportIn = 3514, + kWSCCantTransportOut = 7791, -static const TimeValue kHernandezNotHomeIn = 7791; -static const TimeValue kHernandezNotHomeOut = 10199; + kHernandezNotHomeIn = 7791, + kHernandezNotHomeOut = 10199, -static const TimeValue kWashingtonNotHomeIn = 10199; -static const TimeValue kWashingtonNotHomeOut = 12649; + kWashingtonNotHomeIn = 10199, + kWashingtonNotHomeOut = 12649, -static const TimeValue kSullivanNotHomeIn = 12649; -static const TimeValue kSullivanNotHomeOut = 15031; + kSullivanNotHomeIn = 12649, + kSullivanNotHomeOut = 15031, -static const TimeValue kNakamuraNotHomeIn = 15031; -static const TimeValue kNakamuraNotHomeOut = 17545; + kNakamuraNotHomeIn = 15031, + kNakamuraNotHomeOut = 17545, -static const TimeValue kGrailisNotHomeIn = 17545; -static const TimeValue kGrailisNotHomeOut = 19937; + kGrailisNotHomeIn = 17545, + kGrailisNotHomeOut = 19937, -static const TimeValue kTheriaultNotHomeIn = 19937; -static const TimeValue kTheriaultNotHomeOut = 22395; + kTheriaultNotHomeIn = 19937, + kTheriaultNotHomeOut = 22395, -static const TimeValue kGlennerNotHomeIn = 22395; -static const TimeValue kGlennerNotHomeOut = 24770; + kGlennerNotHomeIn = 22395, + kGlennerNotHomeOut = 24770, -static const TimeValue kSinclairNotHomeIn = 24770; -static const TimeValue kSinclairNotHomeOut = 27328; + kSinclairNotHomeIn = 24770, + kSinclairNotHomeOut = 27328, -static const TimeValue kWSCLabClosedIn = 27328; -static const TimeValue kWSCLabClosedOut = 28904; + kWSCLabClosedIn = 27328, + kWSCLabClosedOut = 28904, -static const TimeValue kSlidingDoorCloseIn = 28904; -static const TimeValue kSlidingDoorCloseOut = 29295; + kSlidingDoorCloseIn = 28904, + kSlidingDoorCloseOut = 29295, -static const TimeValue kSlimyDoorCloseIn = 29295; -static const TimeValue kSlimyDoorCloseOut = 29788; + kSlimyDoorCloseIn = 29295, + kSlimyDoorCloseOut = 29788, -static const TimeValue kPaging1In = 29788; -static const TimeValue kPaging1Out = 32501; + kPaging1In = 29788, + kPaging1Out = 32501, -static const TimeValue kPaging2In = 32501; -static const TimeValue kPaging2Out = 34892; + kPaging2In = 32501, + kPaging2Out = 34892, -static const TimeValue kCheckInIn = 34892; -static const TimeValue kCheckInOut = 37789; + kCheckInIn = 34892, + kCheckInOut = 37789, -static const TimeValue kDrinkAntidoteIn = 37789; -static const TimeValue kDrinkAntidoteOut = 39725; + kDrinkAntidoteIn = 37789, + kDrinkAntidoteOut = 39725 +}; -static const TimeScale kWSCMovieScale = 600; -static const TimeScale kWSCFramesPerSecond = 15; -static const TimeScale kWSCFrameDuration = 40; +enum { + kWSCMovieScale = 600, + kWSCFramesPerSecond = 15, + kWSCFrameDuration = 40 +}; // Alternate IDs. static const AlternateID kAltWSCNormal = 0; @@ -170,304 +174,312 @@ static const AlternateID kAltWSCW0ZDoorOpen = 2; static const AlternateID kAltWSCPeopleAtW19North = 3; // Room IDs. -static const RoomID kWSC02 = 1; -static const RoomID kWSC03 = 4; -static const RoomID kWSC04 = 5; -static const RoomID kWSC06 = 6; -static const RoomID kWSC07 = 7; -static const RoomID kWSC08 = 8; -static const RoomID kWSC09 = 9; -static const RoomID kWSC10 = 10; -static const RoomID kWSC11 = 11; -static const RoomID kWSC13 = 12; -static const RoomID kWSC14 = 13; -static const RoomID kWSC15 = 14; -static const RoomID kWSC16 = 15; -static const RoomID kWSC17 = 16; -static const RoomID kWSC18 = 17; -static const RoomID kWSC19 = 18; -static const RoomID kWSC20 = 19; -static const RoomID kWSC21 = 20; -static const RoomID kWSC22 = 21; -static const RoomID kWSC23 = 22; -static const RoomID kWSC24 = 23; -static const RoomID kWSC25 = 24; -static const RoomID kWSC26 = 25; -static const RoomID kWSC27 = 26; -static const RoomID kWSC28 = 27; -static const RoomID kWSC29 = 28; -static const RoomID kWSC31 = 29; -static const RoomID kWSC32 = 30; -static const RoomID kWSC33 = 31; -static const RoomID kWSC34 = 32; -static const RoomID kWSC35 = 33; -static const RoomID kWSC36 = 34; -static const RoomID kWSC37 = 35; -static const RoomID kWSC38 = 36; -static const RoomID kWSC39 = 37; -static const RoomID kWSC40 = 38; -static const RoomID kWSC41 = 39; -static const RoomID kWSC42 = 40; -static const RoomID kWSC43 = 41; -static const RoomID kWSC44 = 42; -static const RoomID kWSC45 = 43; -static const RoomID kWSC46 = 44; -static const RoomID kWSC47 = 45; -static const RoomID kWSC48 = 46; -static const RoomID kWSC49 = 47; -static const RoomID kWSC50 = 48; -static const RoomID kWSC52 = 49; -static const RoomID kWSC53 = 50; -static const RoomID kWSC54 = 51; -static const RoomID kWSC55 = 52; -static const RoomID kWSC56 = 53; -static const RoomID kWSC57 = 54; -static const RoomID kWSC58 = 55; -static const RoomID kWSC60 = 56; -static const RoomID kWSC60East = 57; -static const RoomID kWSC60North = 58; -static const RoomID kWSC61 = 59; -static const RoomID kWSC61South = 60; -static const RoomID kWSC61West = 61; -static const RoomID kWSC63 = 63; -static const RoomID kWSC64 = 64; -static const RoomID kWSC65 = 65; -static const RoomID kWSC65Screen = 66; -static const RoomID kWSC66 = 67; -static const RoomID kWSC67 = 68; -static const RoomID kWSC68 = 69; -static const RoomID kWSC69 = 70; -static const RoomID kWSC70 = 71; -static const RoomID kWSC71 = 72; -static const RoomID kWSC72 = 73; -static const RoomID kWSC73 = 74; -static const RoomID kWSC74 = 75; -static const RoomID kWSC75 = 76; -static const RoomID kWSC0Z = 77; -static const RoomID kWSC76 = 78; -static const RoomID kWSC77 = 79; -static const RoomID kWSC78 = 80; -static const RoomID kWSC79 = 81; -static const RoomID kWSC80 = 82; -static const RoomID kWSC81 = 83; -static const RoomID kWSC82 = 84; -static const RoomID kWSC83 = 85; -static const RoomID kWSC84 = 86; -static const RoomID kWSC85 = 87; -static const RoomID kWSC86 = 88; -static const RoomID kWSC87 = 89; -static const RoomID kWSC88 = 90; -static const RoomID kWSC89 = 91; -static const RoomID kWSC90 = 92; -static const RoomID kWSC91 = 93; -static const RoomID kWSC92 = 94; -static const RoomID kWSC93 = 95; -static const RoomID kWSC94 = 96; -static const RoomID kWSC95 = 97; -static const RoomID kWSC96 = 98; -static const RoomID kWSC97 = 99; -static const RoomID kWSC98 = 100; -static const RoomID kWSCDeathRoom = 101; +enum { + kWSC02 = 1, + kWSC03 = 4, + kWSC04 = 5, + kWSC06 = 6, + kWSC07 = 7, + kWSC08 = 8, + kWSC09 = 9, + kWSC10 = 10, + kWSC11 = 11, + kWSC13 = 12, + kWSC14 = 13, + kWSC15 = 14, + kWSC16 = 15, + kWSC17 = 16, + kWSC18 = 17, + kWSC19 = 18, + kWSC20 = 19, + kWSC21 = 20, + kWSC22 = 21, + kWSC23 = 22, + kWSC24 = 23, + kWSC25 = 24, + kWSC26 = 25, + kWSC27 = 26, + kWSC28 = 27, + kWSC29 = 28, + kWSC31 = 29, + kWSC32 = 30, + kWSC33 = 31, + kWSC34 = 32, + kWSC35 = 33, + kWSC36 = 34, + kWSC37 = 35, + kWSC38 = 36, + kWSC39 = 37, + kWSC40 = 38, + kWSC41 = 39, + kWSC42 = 40, + kWSC43 = 41, + kWSC44 = 42, + kWSC45 = 43, + kWSC46 = 44, + kWSC47 = 45, + kWSC48 = 46, + kWSC49 = 47, + kWSC50 = 48, + kWSC52 = 49, + kWSC53 = 50, + kWSC54 = 51, + kWSC55 = 52, + kWSC56 = 53, + kWSC57 = 54, + kWSC58 = 55, + kWSC60 = 56, + kWSC60East = 57, + kWSC60North = 58, + kWSC61 = 59, + kWSC61South = 60, + kWSC61West = 61, + kWSC63 = 63, + kWSC64 = 64, + kWSC65 = 65, + kWSC65Screen = 66, + kWSC66 = 67, + kWSC67 = 68, + kWSC68 = 69, + kWSC69 = 70, + kWSC70 = 71, + kWSC71 = 72, + kWSC72 = 73, + kWSC73 = 74, + kWSC74 = 75, + kWSC75 = 76, + kWSC0Z = 77, + kWSC76 = 78, + kWSC77 = 79, + kWSC78 = 80, + kWSC79 = 81, + kWSC80 = 82, + kWSC81 = 83, + kWSC82 = 84, + kWSC83 = 85, + kWSC84 = 86, + kWSC85 = 87, + kWSC86 = 88, + kWSC87 = 89, + kWSC88 = 90, + kWSC89 = 91, + kWSC90 = 92, + kWSC91 = 93, + kWSC92 = 94, + kWSC93 = 95, + kWSC94 = 96, + kWSC95 = 97, + kWSC96 = 98, + kWSC97 = 99, + kWSC98 = 100, + kWSCDeathRoom = 101 +}; // Hot Spot Activation IDs. -static const HotSpotActivationID kActivationZoomedInToAnalyzer = 1; -static const HotSpotActivationID kActivationShotByRobot = 2; -static const HotSpotActivationID kActivationWarnedAboutPoison = 3; -static const HotSpotActivationID kActivationMorphScreenOff = 4; -static const HotSpotActivationID kActivationReadyForMorph = 5; -static const HotSpotActivationID kActivationMorphLooping = 6; -static const HotSpotActivationID kActivationMorphInterrupted = 7; -static const HotSpotActivationID kActivationW03NorthOff = 8; -static const HotSpotActivationID kActivationW03NorthReadyForInstructions = 9; -static const HotSpotActivationID kActivationW03NorthSawInstructions = 10; -static const HotSpotActivationID kActivationW03NorthInGame = 11; -static const HotSpotActivationID kActivationReadyForSynthesis = 12; -static const HotSpotActivationID kActivationSynthesizerLooping = 13; -static const HotSpotActivationID kActivationReadyForMap = 14; -static const HotSpotActivationID kActivationSinclairOfficeLocked = 15; -static const HotSpotActivationID kActivationW58SouthDoorLocked = 16; -static const HotSpotActivationID kActivationW61SouthOff = 17; -static const HotSpotActivationID kActivationW61SouthOn = 18; -static const HotSpotActivationID kActivationW61MessagesOff = 19; -static const HotSpotActivationID kActivationW61MessagesOn = 20; -static const HotSpotActivationID kActivationWSCRobotHeadOpen = 21; -static const HotSpotActivationID kActivationRobotTurning = 22; -static const HotSpotActivationID kActivationRobotDead = 23; -static const HotSpotActivationID kActivationRobotGone = 24; +enum { + kActivationZoomedInToAnalyzer = 1, + kActivationShotByRobot = 2, + kActivationWarnedAboutPoison = 3, + kActivationMorphScreenOff = 4, + kActivationReadyForMorph = 5, + kActivationMorphLooping = 6, + kActivationMorphInterrupted = 7, + kActivationW03NorthOff = 8, + kActivationW03NorthReadyForInstructions = 9, + kActivationW03NorthSawInstructions = 10, + kActivationW03NorthInGame = 11, + kActivationReadyForSynthesis = 12, + kActivationSynthesizerLooping = 13, + kActivationReadyForMap = 14, + kActivationSinclairOfficeLocked = 15, + kActivationW58SouthDoorLocked = 16, + kActivationW61SouthOff = 17, + kActivationW61SouthOn = 18, + kActivationW61MessagesOff = 19, + kActivationW61MessagesOn = 20, + kActivationWSCRobotHeadOpen = 21, + kActivationRobotTurning = 22, + kActivationRobotDead = 23, + kActivationRobotGone = 24 +}; // Hot Spot IDs. -static const HotSpotID kWSCDropDartSpotID = 5000; -static const HotSpotID kWSCTurnOnAnalyzerSpotID = 5001; -static const HotSpotID kWSCAnalyzerScreenSpotID = 5002; -static const HotSpotID kWSCSpinRobotSpotID = 5003; -static const HotSpotID kWSC01YesSpotID = 5004; -static const HotSpotID kWSC01NoSpotID = 5005; -static const HotSpotID kWSC01AcknowledgeWarningSpotID = 5006; -static const HotSpotID kWSC02SouthMorphSpotID = 5007; -static const HotSpotID kWSC02SouthMessagesSpotID = 5008; -static const HotSpotID kWSC02SouthMorphOutSpotID = 5009; -static const HotSpotID kWSC02ActivateMorphScreenSpotID = 5010; -static const HotSpotID kWSC02SouthStartMorphSpotID = 5011; -static const HotSpotID kWSC02SouthInterruptMorphSpotID = 5012; -static const HotSpotID kWSC02SouthMorphFinishedSpotID = 5013; -static const HotSpotID kWSC02SouthTakeArgonSpotID = 5014; -static const HotSpotID kWSC02SouthMessagesOutSpotID = 5015; -static const HotSpotID kWSC02SouthTakeNitrogenSpotID = 5016; -static const HotSpotID kWSC02SouthPlayMessagesSpotID = 5017; -static const HotSpotID kWSC03NorthActivateScreenSpotID = 5018; -static const HotSpotID kWSC03NorthBuildMoleculeSpotID = 5019; -static const HotSpotID kWSC03NorthProceedSpotID = 5020; -static const HotSpotID kWSC03NorthMolecule1SpotID = 5021; -static const HotSpotID kWSC03NorthMolecule2SpotID = 5022; -static const HotSpotID kWSC03NorthMolecule3SpotID = 5023; -static const HotSpotID kWSC03NorthMolecule4SpotID = 5024; -static const HotSpotID kWSC03NorthMolecule5SpotID = 5025; -static const HotSpotID kWSC03NorthMolecule6SpotID = 5026; -static const HotSpotID kWSC03SouthActivateSynthesizerSpotID = 5027; -static const HotSpotID kWSC03SouthPickUpAntidoteSpotID = 5028; -static const HotSpotID kWSC07SouthMapSpotID = 5029; -static const HotSpotID kW42EastUnlockDoorSpotID = 5030; -static const HotSpotID kW56NorthMapSpotID = 5031; -static const HotSpotID kW58SouthPryDoorSpotID = 5032; -static const HotSpotID kWSC60EastSpotID = 5033; -static const HotSpotID kWSC60NorthSpotID = 5034; -static const HotSpotID kWSC60EastOutSpotID = 5035; -static const HotSpotID kWSC60NorthOutSpotID = 5036; -static const HotSpotID kWSC61EastSpotID = 5037; -static const HotSpotID kWSC61SouthSpotID = 5038; -static const HotSpotID kW61SouthMachineGunSpotID = 5039; -static const HotSpotID kW61SouthDropMachineGunSpotID = 5040; -static const HotSpotID kWSC61WestSpotID = 5041; -static const HotSpotID kWSC61SouthOutSpotID = 5042; -static const HotSpotID kW61SouthActivateSpotID = 5043; -static const HotSpotID kW61SmartAlloysSpotID = 5044; -static const HotSpotID kW61MorphingSpotID = 5045; -static const HotSpotID kW61TimeBendingSpotID = 5046; -static const HotSpotID kWSC61WestOutSpotID = 5047; -static const HotSpotID kW61TurnOnMessagesSpotID = 5048; -static const HotSpotID kW61WhiteMessageSpotID = 5049; -static const HotSpotID kW61WalchekMessageSpotID = 5050; -static const HotSpotID kWSC65SouthScreenSpotID = 5051; -static const HotSpotID kWSC65SouthScreenOutSpotID = 5052; -static const HotSpotID kW98RetinalChipSpotID = 5053; -static const HotSpotID kW98MapChipSpotID = 5054; -static const HotSpotID kW98OpticalChipSpotID = 5055; -static const HotSpotID kW98DropArgonSpotID = 5056; -static const HotSpotID kW98GrabCableSpotID = 5057; -static const HotSpotID kW98OpenRobotSpotID = 5058; -static const HotSpotID kW98StunGunSpotID = 5059; +enum { + kWSCDropDartSpotID = 5000, + kWSCTurnOnAnalyzerSpotID = 5001, + kWSCAnalyzerScreenSpotID = 5002, + kWSCSpinRobotSpotID = 5003, + kWSC01YesSpotID = 5004, + kWSC01NoSpotID = 5005, + kWSC01AcknowledgeWarningSpotID = 5006, + kWSC02SouthMorphSpotID = 5007, + kWSC02SouthMessagesSpotID = 5008, + kWSC02SouthMorphOutSpotID = 5009, + kWSC02ActivateMorphScreenSpotID = 5010, + kWSC02SouthStartMorphSpotID = 5011, + kWSC02SouthInterruptMorphSpotID = 5012, + kWSC02SouthMorphFinishedSpotID = 5013, + kWSC02SouthTakeArgonSpotID = 5014, + kWSC02SouthMessagesOutSpotID = 5015, + kWSC02SouthTakeNitrogenSpotID = 5016, + kWSC02SouthPlayMessagesSpotID = 5017, + kWSC03NorthActivateScreenSpotID = 5018, + kWSC03NorthBuildMoleculeSpotID = 5019, + kWSC03NorthProceedSpotID = 5020, + kWSC03NorthMolecule1SpotID = 5021, + kWSC03NorthMolecule2SpotID = 5022, + kWSC03NorthMolecule3SpotID = 5023, + kWSC03NorthMolecule4SpotID = 5024, + kWSC03NorthMolecule5SpotID = 5025, + kWSC03NorthMolecule6SpotID = 5026, + kWSC03SouthActivateSynthesizerSpotID = 5027, + kWSC03SouthPickUpAntidoteSpotID = 5028, + kWSC07SouthMapSpotID = 5029, + kW42EastUnlockDoorSpotID = 5030, + kW56NorthMapSpotID = 5031, + kW58SouthPryDoorSpotID = 5032, + kWSC60EastSpotID = 5033, + kWSC60NorthSpotID = 5034, + kWSC60EastOutSpotID = 5035, + kWSC60NorthOutSpotID = 5036, + kWSC61EastSpotID = 5037, + kWSC61SouthSpotID = 5038, + kW61SouthMachineGunSpotID = 5039, + kW61SouthDropMachineGunSpotID = 5040, + kWSC61WestSpotID = 5041, + kWSC61SouthOutSpotID = 5042, + kW61SouthActivateSpotID = 5043, + kW61SmartAlloysSpotID = 5044, + kW61MorphingSpotID = 5045, + kW61TimeBendingSpotID = 5046, + kWSC61WestOutSpotID = 5047, + kW61TurnOnMessagesSpotID = 5048, + kW61WhiteMessageSpotID = 5049, + kW61WalchekMessageSpotID = 5050, + kWSC65SouthScreenSpotID = 5051, + kWSC65SouthScreenOutSpotID = 5052, + kW98RetinalChipSpotID = 5053, + kW98MapChipSpotID = 5054, + kW98OpticalChipSpotID = 5055, + kW98DropArgonSpotID = 5056, + kW98GrabCableSpotID = 5057, + kW98OpenRobotSpotID = 5058, + kW98StunGunSpotID = 5059 +}; // Extra sequence IDs. -static const ExtraID kWSCArrivalFromTSA = 0; -static const ExtraID kWSCShotByRobot = 1; -static const ExtraID kWSCDartScan1 = 2; -static const ExtraID kWSCDartScan2 = 3; -static const ExtraID kWSCDartScanNo = 4; -static const ExtraID kWSCDartScan3 = 5; -static const ExtraID kWSCAnalyzerPowerUp = 6; -static const ExtraID kWSCAnalyzerPowerUpWithDart = 7; -static const ExtraID kWSCDropDartIntoAnalyzer = 8; -static const ExtraID kWSCAnalyzeDart = 9; -static const ExtraID kWSCZoomOutFromAnalyzer = 10; -static const ExtraID kWSCSpinRobot = 11; -static const ExtraID kWSC02MorphZoomNoArgon = 12; -static const ExtraID kWSC02MessagesZoomNoNitrogen = 13; -static const ExtraID kWSC02ZoomOutNoArgon = 14; -static const ExtraID kWSC02TurnOnMorphScreen = 15; -static const ExtraID kWSC02DropToMorphExperiment = 16; -static const ExtraID kWSC02MorphLoop = 17; -static const ExtraID kWSC02MorphInterruption = 18; -static const ExtraID kWSC02MorphFinished = 19; -static const ExtraID kWSC02TurnOffMorphScreen = 20; -static const ExtraID kWSC02SouthViewNoArgon = 21; -static const ExtraID kMessagesMovedToOffice = 22; -static const ExtraID kMessagesOff = 23; -static const ExtraID kMessagesZoomOutNoNitrogen = 24; -static const ExtraID kMessagesMovedToOfficeNoNitrogen = 25; -static const ExtraID kMessagesOffNoNitrogen = 26; -static const ExtraID kMessagesViewNoNitrogen = 27; -static const ExtraID kMessagesViewMachineOnNoNitrogen = 28; -static const ExtraID kW03NorthActivate = 29; -static const ExtraID kW03NorthGetData = 30; -static const ExtraID kW03NorthInstructions = 31; -static const ExtraID kW03NorthPrepMolecule1 = 32; -static const ExtraID kW03NorthPrepMolecule2 = 33; -static const ExtraID kW03NorthPrepMolecule3 = 34; -static const ExtraID kW03NorthFinishSynthesis = 35; -static const ExtraID kW03SouthCreateAntidote = 36; -static const ExtraID kW03SouthAntidoteLoop = 37; -static const ExtraID kW03SouthDeactivate = 38; -static const ExtraID kW03SouthViewNoAntidote = 39; -static const ExtraID kWSC07SouthMap = 40; -static const ExtraID kW17WestPeopleCrossing = 41; -static const ExtraID kW17WestPeopleCrossingView = 42; -static const ExtraID kW21SouthPeopleCrossing = 43; -static const ExtraID kW24SouthPeopleCrossing = 44; -static const ExtraID kW34EastPeopleCrossing = 45; -static const ExtraID kW36WestPeopleCrossing = 46; -static const ExtraID kW38NorthPeopleCrossing = 47; -static const ExtraID kW46SouthPeopleCrossing = 48; -static const ExtraID kW49NorthPeopleCrossing = 49; -static const ExtraID kW49NorthPeopleCrossingView = 50; -static const ExtraID kWSC56SouthMap = 51; -static const ExtraID kNerdAtTheDoor1 = 52; -static const ExtraID kNerdAtTheDoor2 = 53; -static const ExtraID kW61SouthZoomInNoGun = 54; -static const ExtraID kW61Brochure = 55; -static const ExtraID kW61SouthScreenOnWithGun = 56; -static const ExtraID kW61SouthScreenOffWithGun = 57; -static const ExtraID kW61SouthSmartAlloysWithGun = 58; -static const ExtraID kW61SouthMorphingWithGun = 59; -static const ExtraID kW61SouthTimeBendingWithGun = 60; -static const ExtraID kW61SouthZoomOutNoGun = 61; -static const ExtraID kW61SouthScreenOnNoGun = 62; -static const ExtraID kW61SouthScreenOffNoGun = 63; -static const ExtraID kW61SouthSmartAlloysNoGun = 64; -static const ExtraID kW61SouthMorphingNoGun = 65; -static const ExtraID kW61SouthTimeBendingNoGun = 66; -static const ExtraID kW61MessagesOn = 67; -static const ExtraID kW61MessagesOff = 68; -static const ExtraID kW61WhiteMessage = 69; -static const ExtraID kW61WalchekMessage = 70; -static const ExtraID kW61WalchekEasterEgg1 = 71; -static const ExtraID kW62SouthPlasmaRobotAppears = 72; -static const ExtraID kW62ZoomToRobot = 73; -static const ExtraID kW62ZoomOutFromRobot = 74; -static const ExtraID kW62PlasmaDodgeSurvive = 75; -static const ExtraID kW62PlasmaDodgeDie = 76; -static const ExtraID kW65SouthSinclairLecture = 77; -static const ExtraID kW73WestPeopleCrossing = 78; -static const ExtraID kW73WestPeopleCrossingView = 79; -static const ExtraID kW0ZSpottedByWomen = 80; -static const ExtraID kW95RobotShoots = 81; -static const ExtraID kW98MorphsToRobot = 82; -static const ExtraID kW98RobotShoots = 83; -static const ExtraID kW98RobotShocked = 84; -static const ExtraID kW98RobotGassed = 85; -static const ExtraID kW98RobotHeadOpensDark = 86; -static const ExtraID kW98RobotHead000Dark = 87; -static const ExtraID kW98RobotHead001Dark = 88; -static const ExtraID kW98RobotHead010Dark = 89; -static const ExtraID kW98RobotHead011Dark = 90; -static const ExtraID kW98RobotHead100Dark = 91; -static const ExtraID kW98RobotHead101Dark = 92; -static const ExtraID kW98RobotHead110Dark = 93; -static const ExtraID kW98RobotHead111Dark = 94; -static const ExtraID kW98RobotHeadClosesDark = 95; -static const ExtraID kW98WestViewWithGunDark = 96; -static const ExtraID kW98WestViewNoGunDark = 97; -static const ExtraID kW98RobotHeadOpensLight = 98; -static const ExtraID kW98RobotHead000Light = 99; -static const ExtraID kW98RobotHead001Light = 100; -static const ExtraID kW98RobotHead010Light = 101; -static const ExtraID kW98RobotHead011Light = 102; -static const ExtraID kW98RobotHead100Light = 103; -static const ExtraID kW98RobotHead101Light = 104; -static const ExtraID kW98RobotHead110Light = 105; -static const ExtraID kW98RobotHead111Light = 106; -static const ExtraID kW98RobotHeadClosesLight = 107; -static const ExtraID kW98WestViewWithGunLight = 108; -static const ExtraID kW98WestViewNoGunLight = 109; +enum { + kWSCArrivalFromTSA = 0, + kWSCShotByRobot = 1, + kWSCDartScan1 = 2, + kWSCDartScan2 = 3, + kWSCDartScanNo = 4, + kWSCDartScan3 = 5, + kWSCAnalyzerPowerUp = 6, + kWSCAnalyzerPowerUpWithDart = 7, + kWSCDropDartIntoAnalyzer = 8, + kWSCAnalyzeDart = 9, + kWSCZoomOutFromAnalyzer = 10, + kWSCSpinRobot = 11, + kWSC02MorphZoomNoArgon = 12, + kWSC02MessagesZoomNoNitrogen = 13, + kWSC02ZoomOutNoArgon = 14, + kWSC02TurnOnMorphScreen = 15, + kWSC02DropToMorphExperiment = 16, + kWSC02MorphLoop = 17, + kWSC02MorphInterruption = 18, + kWSC02MorphFinished = 19, + kWSC02TurnOffMorphScreen = 20, + kWSC02SouthViewNoArgon = 21, + kMessagesMovedToOffice = 22, + kMessagesOff = 23, + kMessagesZoomOutNoNitrogen = 24, + kMessagesMovedToOfficeNoNitrogen = 25, + kMessagesOffNoNitrogen = 26, + kMessagesViewNoNitrogen = 27, + kMessagesViewMachineOnNoNitrogen = 28, + kW03NorthActivate = 29, + kW03NorthGetData = 30, + kW03NorthInstructions = 31, + kW03NorthPrepMolecule1 = 32, + kW03NorthPrepMolecule2 = 33, + kW03NorthPrepMolecule3 = 34, + kW03NorthFinishSynthesis = 35, + kW03SouthCreateAntidote = 36, + kW03SouthAntidoteLoop = 37, + kW03SouthDeactivate = 38, + kW03SouthViewNoAntidote = 39, + kWSC07SouthMap = 40, + kW17WestPeopleCrossing = 41, + kW17WestPeopleCrossingView = 42, + kW21SouthPeopleCrossing = 43, + kW24SouthPeopleCrossing = 44, + kW34EastPeopleCrossing = 45, + kW36WestPeopleCrossing = 46, + kW38NorthPeopleCrossing = 47, + kW46SouthPeopleCrossing = 48, + kW49NorthPeopleCrossing = 49, + kW49NorthPeopleCrossingView = 50, + kWSC56SouthMap = 51, + kNerdAtTheDoor1 = 52, + kNerdAtTheDoor2 = 53, + kW61SouthZoomInNoGun = 54, + kW61Brochure = 55, + kW61SouthScreenOnWithGun = 56, + kW61SouthScreenOffWithGun = 57, + kW61SouthSmartAlloysWithGun = 58, + kW61SouthMorphingWithGun = 59, + kW61SouthTimeBendingWithGun = 60, + kW61SouthZoomOutNoGun = 61, + kW61SouthScreenOnNoGun = 62, + kW61SouthScreenOffNoGun = 63, + kW61SouthSmartAlloysNoGun = 64, + kW61SouthMorphingNoGun = 65, + kW61SouthTimeBendingNoGun = 66, + kW61MessagesOn = 67, + kW61MessagesOff = 68, + kW61WhiteMessage = 69, + kW61WalchekMessage = 70, + kW61WalchekEasterEgg1 = 71, + kW62SouthPlasmaRobotAppears = 72, + kW62ZoomToRobot = 73, + kW62ZoomOutFromRobot = 74, + kW62PlasmaDodgeSurvive = 75, + kW62PlasmaDodgeDie = 76, + kW65SouthSinclairLecture = 77, + kW73WestPeopleCrossing = 78, + kW73WestPeopleCrossingView = 79, + kW0ZSpottedByWomen = 80, + kW95RobotShoots = 81, + kW98MorphsToRobot = 82, + kW98RobotShoots = 83, + kW98RobotShocked = 84, + kW98RobotGassed = 85, + kW98RobotHeadOpensDark = 86, + kW98RobotHead000Dark = 87, + kW98RobotHead001Dark = 88, + kW98RobotHead010Dark = 89, + kW98RobotHead011Dark = 90, + kW98RobotHead100Dark = 91, + kW98RobotHead101Dark = 92, + kW98RobotHead110Dark = 93, + kW98RobotHead111Dark = 94, + kW98RobotHeadClosesDark = 95, + kW98WestViewWithGunDark = 96, + kW98WestViewNoGunDark = 97, + kW98RobotHeadOpensLight = 98, + kW98RobotHead000Light = 99, + kW98RobotHead001Light = 100, + kW98RobotHead010Light = 101, + kW98RobotHead011Light = 102, + kW98RobotHead100Light = 103, + kW98RobotHead101Light = 104, + kW98RobotHead110Light = 105, + kW98RobotHead111Light = 106, + kW98RobotHeadClosesLight = 107, + kW98WestViewWithGunLight = 108, + kW98WestViewNoGunLight = 109 +}; static const CoordType kMoleculesMovieLeft = kNavAreaLeft + 112; static const CoordType kMoleculesMovieTop = kNavAreaTop + 40; diff --git a/engines/pegasus/pegasus.cpp b/engines/pegasus/pegasus.cpp index 0010180d8d..0c8ea2e4ee 100644 --- a/engines/pegasus/pegasus.cpp +++ b/engines/pegasus/pegasus.cpp @@ -2514,7 +2514,7 @@ void PegasusEngine::initKeymap() { { Common::KEYCODE_t, "TMA", _("Toggle Center Data Display") }, { Common::KEYCODE_i, "TIN", _("Display/Hide Info Screen") }, { Common::KEYCODE_ESCAPE, "PM", _("Display/Hide Pause Menu") }, - { Common::KEYCODE_e, "WTF", _("???") } // easter egg key (without being completely upfront about it) + { Common::KEYCODE_e, "WTF", "???" } // easter egg key (without being completely upfront about it) }; for (uint i = 0; i < ARRAYSIZE(keyActionEntries); i++) { diff --git a/engines/saga/console.cpp b/engines/saga/console.cpp index 0b801eef3e..8ad7fd5aaa 100644 --- a/engines/saga/console.cpp +++ b/engines/saga/console.cpp @@ -25,8 +25,10 @@ #include "saga/saga.h" #include "saga/actor.h" #include "saga/animation.h" +#include "saga/music.h" #include "saga/scene.h" #include "saga/script.h" +#include "saga/sndres.h" #include "saga/console.h" @@ -45,6 +47,11 @@ Console::Console(SagaEngine *vm) : GUI::Debugger() { registerCmd("cutaway_info", WRAP_METHOD(Console, cmdCutawayInfo)); registerCmd("play_cutaway", WRAP_METHOD(Console, cmdPlayCutaway)); + // Sound commands + registerCmd("play_music", WRAP_METHOD(Console, cmdPlayMusic)); + registerCmd("play_sound", WRAP_METHOD(Console, cmdPlaySound)); + registerCmd("play_voice", WRAP_METHOD(Console, cmdPlayVoice)); + // Game stuff #if 0 @@ -117,6 +124,45 @@ bool Console::cmdPlayCutaway(int argc, const char **argv) { return true; } +bool Console::cmdPlayMusic(int argc, const char **argv) { + if (argc != 2) { + debugPrintf("Usage: %s <Music number>\n", argv[0]); + } else { + if (_vm->getGameId() == GID_ITE) + _vm->_music->play(atoi(argv[1]) + 9); + else + _vm->_music->play(atoi(argv[1])); + } + return true; +} + +bool Console::cmdPlaySound(int argc, const char **argv) { + if (argc != 2) + debugPrintf("Usage: %s <Sound number>\n", argv[0]); + else + _vm->_sndRes->playSound(atoi(argv[1]), 255, false); + return true; +} + +bool Console::cmdPlayVoice(int argc, const char **argv) { + if (argc < 2) { + debugPrintf("Usage: %s <Voice number> <Voice bank>\n", argv[0]); + } else { + int voiceBank = 0; + + if (argc == 3) { + voiceBank = _vm->_sndRes->getVoiceBank(); + _vm->_sndRes->setVoiceBank(atoi(argv[2])); + } + + _vm->_sndRes->playVoice(atoi(argv[1])); + + if (argc == 3) + _vm->_sndRes->setVoiceBank(voiceBank); + } + return true; +} + bool Console::cmdCurrentScene(int argc, const char **argv) { debugPrintf("Current Scene is: %i, scene resource id: %i\n", _vm->_scene->currentSceneNumber(), _vm->_scene->currentSceneResourceId()); diff --git a/engines/saga/console.h b/engines/saga/console.h index 625e6f57ad..cec964301c 100644 --- a/engines/saga/console.h +++ b/engines/saga/console.h @@ -41,6 +41,10 @@ private: bool cmdCutawayInfo(int argc, const char **argv); bool cmdPlayCutaway(int argc, const char **argv); + bool cmdPlayMusic(int argc, const char **argv); + bool cmdPlaySound(int argc, const char **argv); + bool cmdPlayVoice(int argc, const char **argv); + bool cmdCurrentScene(int argc, const char **argv); bool cmdCurrentChapter(int argc, const char **argv); bool cmdSceneChange(int argc, const char **argv); diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h index 72187a1a13..2f72e7a13c 100644 --- a/engines/saga/detection_tables.h +++ b/engines/saga/detection_tables.h @@ -595,6 +595,30 @@ static const SAGAGameDescription gameDescriptions[] = { ITEPatch_Files, }, + // Inherit the earth - Chinese Disk version + { + { + "ite", + "Floppy", + { + {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", 8901704}, + {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", 281071}, + { NULL, 0, NULL, 0} + }, + Common::ZH_CNA, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO1(GUIO_NOSPEECH) + }, + GID_ITE, + GF_ITE_FLOPPY, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITE_GameFonts), + ITE_GameFonts, + ITEPatch_Files, + }, + // ITE Amiga versions ///////////////////////////////////////////////////////////////////////////////////// // TODO: Add the Amiga versions here (not supported yet) diff --git a/engines/saga/events.cpp b/engines/saga/events.cpp index 013b019c9f..b7c3fa4d6e 100644 --- a/engines/saga/events.cpp +++ b/engines/saga/events.cpp @@ -583,6 +583,18 @@ EventColumns *Events::chain(EventColumns *eventColumns, const Event &event) { return eventColumns; } +EventColumns *Events::chainMusic(EventColumns *eventColumns, long musicId, bool loop, long time) { + Event event; + + event.type = kEvTOneshot; + event.code = kMusicEvent; + event.param = musicId; + event.param2 = loop ? MUSIC_NORMAL : MUSIC_LOOP; + event.op = kEventPlay; + event.time = time; + return chain(eventColumns, event); +} + void Events::initializeEvent(Event &event) { switch (event.type) { case kEvTOneshot: diff --git a/engines/saga/events.h b/engines/saga/events.h index 6c423abb8c..84a62f5a3a 100644 --- a/engines/saga/events.h +++ b/engines/saga/events.h @@ -172,9 +172,18 @@ class Events { return chain(NULL, event); } + // Schedules a music event in the event list; returns a pointer to the scheduled + // event columns suitable for chaining if desired. + EventColumns *queueMusic(long musicId, bool loop = false, long time = 0) { + return chainMusic(NULL, musicId, loop, time); + } + // Places a 'event' on the end of an event columns given by 'eventColumns' EventColumns *chain(EventColumns *eventColumns, const Event &event); + // Places a music 'event' on the end of an event columns given by 'eventColumns' + EventColumns *chainMusic(EventColumns *eventColumns, long musicId, bool loop = false, long time = 0); + private: int handleContinuous(Event *event); int handleOneShot(Event *event); diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp index 680b2274f5..44581f26fc 100644 --- a/engines/saga/interface.cpp +++ b/engines/saga/interface.cpp @@ -710,6 +710,11 @@ bool Interface::processAscii(Common::KeyState keystate) { } void Interface::setStatusText(const char *text, int statusColor) { + if (_vm->getGameId() == GID_FTA2 || _vm->getGameId() == GID_DINO) { + warning("setStatusText not implemented for SAGA2"); + return; + } + if (_vm->getGameId() == GID_IHNM) { // Don't show the status text for the IHNM chapter selection screens (chapter 8), or // scene 0 (IHNM demo introduction) diff --git a/engines/saga/introproc_ite.cpp b/engines/saga/introproc_ite.cpp index 91b1d3db95..0c1a2ce233 100644 --- a/engines/saga/introproc_ite.cpp +++ b/engines/saga/introproc_ite.cpp @@ -28,6 +28,7 @@ #include "saga/animation.h" #include "saga/events.h" #include "saga/font.h" +#include "saga/itedata.h" #include "saga/sndres.h" #include "saga/palanim.h" #include "saga/music.h" @@ -37,10 +38,15 @@ namespace Saga { -using Common::UNK_LANG; -using Common::EN_ANY; -using Common::DE_DEU; -using Common::IT_ITA; +#define INTRO_FRAMETIME 90 +#define INTRO_CAPTION_Y 170 +#define INTRO_DE_CAPTION_Y 160 +#define INTRO_IT_CAPTION_Y 160 +#define INTRO_VOICE_PAD 50 +#define INTRO_VOICE_LETTERLEN 90 + +#define DISSOLVE_DURATION 3000 +#define LOGO_DISSOLVE_DURATION 1000 // Intro scenes #define RID_ITE_INTRO_ANIM_SCENE 1538 @@ -54,8 +60,8 @@ using Common::IT_ITA; #define RID_ITE_FAIRETENT_SCENE 1567 // ITE intro music -#define MUSIC_1 9 -#define MUSIC_2 10 +#define MUSIC_INTRO 9 +#define MUSIC_TITLE_THEME 10 LoadSceneParams ITE_IntroList[] = { {RID_ITE_INTRO_ANIM_SCENE, kLoadByResourceId, Scene::SC_ITEIntroAnimProc, false, kTransitionNoFade, 0, NO_CHAPTER_CHANGE}, @@ -98,11 +104,11 @@ int Scene::ITEStartProc() { return SUCCESS; } -EventColumns *Scene::ITEQueueDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]) { +EventColumns *Scene::queueIntroDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]) { TextListEntry textEntry; TextListEntry *entry; Event event; - int voice_len; + int voiceLength; int i; // Queue narrator dialogue list @@ -132,7 +138,7 @@ EventColumns *Scene::ITEQueueDialogue(EventColumns *eventColumns, int n_dialogue event.code = kTextEvent; event.op = kEventDisplay; event.data = entry; - event.time = (i == 0) ? 0 : VOICE_PAD; + event.time = (i == 0) ? 0 : INTRO_VOICE_PAD; eventColumns = _vm->_events->chain(eventColumns, event); } @@ -146,9 +152,10 @@ EventColumns *Scene::ITEQueueDialogue(EventColumns *eventColumns, int n_dialogue _vm->_events->chain(eventColumns, event); } - voice_len = _vm->_sndRes->getVoiceLength(dialogue[i].i_voice_rn); - if (voice_len < 0) { - voice_len = strlen(dialogue[i].i_str) * VOICE_LETTERLEN; + voiceLength = _vm->_sndRes->getVoiceLength(dialogue[i].i_voice_rn); + if (voiceLength < 0) { + // Set a default length if no speech file is present + voiceLength = strlen(dialogue[i].i_str) * INTRO_VOICE_LETTERLEN; } // Remove text @@ -156,31 +163,17 @@ EventColumns *Scene::ITEQueueDialogue(EventColumns *eventColumns, int n_dialogue event.code = kTextEvent; event.op = kEventRemove; event.data = entry; - event.time = voice_len; + event.time = voiceLength; _vm->_events->chain(eventColumns, event); } return eventColumns; } -enum { - kCHeader, - kCText -}; - -enum { - kITEPC = (1 << 0), - kITEPCCD = (1 << 1), - kITEMac = (1 << 2), - kITEWyrmKeep = (1 << 3), - kITEAny = 0xffff, - kITENotWyrmKeep = kITEAny & ~kITEWyrmKeep -}; - // Queue a page of credits text. The original interpreter did word-wrapping // automatically. We currently don't. -EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]) { +EventColumns *Scene::queueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]) { int game; Common::Language lang; bool hasWyrmkeepCredits = (Common::File::exists("credit3n.dlt") || // PC @@ -192,13 +185,13 @@ EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits lang = _vm->getLanguage(); if (hasWyrmkeepCredits) - game = kITEWyrmKeep; + game = kITECreditsWyrmKeep; else if (_vm->getPlatform() == Common::kPlatformMacintosh) - game = kITEMac; + game = kITECreditsMac; else if (_vm->getFeatures() & GF_EXTRA_ITE_CREDITS) - game = kITEPCCD; + game = kITECreditsPCCD; else - game = kITEPC; + game = kITECreditsPC; int line_spacing = 0; int paragraph_spacing; @@ -209,7 +202,7 @@ EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits int credits_height = 0; for (i = 0; i < n_credits; i++) { - if (credits[i].lang != lang && credits[i].lang != UNK_LANG) { + if (credits[i].lang != lang && credits[i].lang != Common::UNK_LANG) { continue; } @@ -218,12 +211,12 @@ EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits } switch (credits[i].type) { - case kCHeader: + case kITECreditsHeader: font = kKnownFontSmall; line_spacing = 4; n_paragraphs++; break; - case kCText: + case kITECreditsText: font = kKnownFontMedium; line_spacing = 2; break; @@ -250,7 +243,7 @@ EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits textEntry.point.x = 160; for (i = 0; i < n_credits; i++) { - if (credits[i].lang != lang && credits[i].lang != UNK_LANG) { + if (credits[i].lang != lang && credits[i].lang != Common::UNK_LANG) { continue; } @@ -259,12 +252,12 @@ EventColumns *Scene::ITEQueueCredits(int delta_time, int duration, int n_credits } switch (credits[i].type) { - case kCHeader: + case kITECreditsHeader: font = kKnownFontSmall; line_spacing = 4; y += paragraph_spacing; break; - case kCText: + case kITECreditsText: font = kKnownFontMedium; line_spacing = 2; break; @@ -328,7 +321,7 @@ int Scene::ITEIntroAnimProc(int param) { debug(3, "Intro animation procedure started."); debug(3, "Linking animation resources..."); - _vm->_anim->setFrameTime(0, ITE_INTRO_FRAMETIME); + _vm->_anim->setFrameTime(0, INTRO_FRAMETIME); // Link this scene's animation resources for continuous // playback @@ -355,13 +348,7 @@ int Scene::ITEIntroAnimProc(int param) { _vm->_events->chain(eventColumns, event); // Queue intro music playback - event.type = kEvTOneshot; - event.code = kMusicEvent; - event.param = MUSIC_1; - event.param2 = MUSIC_LOOP; - event.op = kEventPlay; - event.time = 0; - _vm->_events->chain(eventColumns, event); + _vm->_events->chainMusic(eventColumns, MUSIC_INTRO, true); } break; case SCENE_END: @@ -374,14 +361,11 @@ int Scene::ITEIntroAnimProc(int param) { return 0; } -int Scene::SC_ITEIntroCave1Proc(int param, void *refCon) { - return ((Scene *)refCon)->ITEIntroCave1Proc(param); -} - -// Handles first introductory cave painting scene -int Scene::ITEIntroCave1Proc(int param) { +int Scene::ITEIntroCaveCommonProc(int param, int caveScene) { Event event; - EventColumns *eventColumns; + EventColumns *eventColumns = NULL; + const IntroDialogue *dialogue; + int lang = 0; if (_vm->getLanguage() == Common::DE_DEU) @@ -389,202 +373,62 @@ int Scene::ITEIntroCave1Proc(int param) { else if (_vm->getLanguage() == Common::IT_ITA) lang = 2; - static const IntroDialogue dialogue[][4] = { - { { // English - 0, // cave voice 0 - "We see the sky, we see the land, we see the water, " - "and we wonder: Are we the only ones?" - }, - { - 1, // cave voice 1 - "Long before we came to exist, the humans ruled the " - "Earth." - }, - { - 2, // cave voice 2 - "They made marvelous things, and moved whole " - "mountains." - }, - { - 3, // cave voice 3 - "They knew the Secret of Flight, the Secret of " - "Happiness, and other secrets beyond our imagining." - } }, - // ----------------------------------------------------- - { { // German - 0, // cave voice 0 - "Um uns sind der Himmel, das Land und die Seen; und " - "wir fragen uns - sind wir die einzigen?" - }, - { - 1, // cave voice 1 - "Lange vor unserer Zeit herrschten die Menschen " - "\201ber die Erde." - }, - { - 2, // cave voice 2 - "Sie taten wundersame Dinge und versetzten ganze " - "Berge." - }, - { - 3, // cave voice 3 - "Sie kannten das Geheimnis des Fluges, das Geheimnis " - "der Fr\224hlichkeit und andere Geheimnisse, die " - "unsere Vorstellungskraft \201bersteigen." - } }, - // ----------------------------------------------------- - { { // Italian fan translation - 0, // cave voice 0 - "Guardiamo il cielo, guardiamo la terra, guardiamo " - "l'acqua, e ci chiediamo: Siamo forse soli?" - }, - { - 1, // cave voice 1 - "Molto tempo prima che noi esistessimo, gli Umani " - "dominavano la terra." - }, - { - 2, // cave voice 2 - "Fecero cose meravigliose, e mossero intere " - "montagne." - }, - { - 3, // cave voice 3 - "Conoscevano il Segreto del Volo, il Segreto della " - "Felicit\205, ed altri segreti oltre ogni nostra " - "immaginazione." - } } - }; - - int n_dialogues = ARRAYSIZE(dialogue[lang]); - - switch (param) { - case SCENE_BEGIN: - // Begin palette cycling animation for candles - event.type = kEvTOneshot; - event.code = kPalAnimEvent; - event.op = kEventCycleStart; - event.time = 0; - eventColumns = _vm->_events->queue(event); - - // Queue narrator dialogue list - ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]); - - // End scene after last dialogue over - event.type = kEvTOneshot; - event.code = kSceneEvent; - event.op = kEventEnd; - event.time = VOICE_PAD; - _vm->_events->chain(eventColumns, event); - + int n_dialogues = 0; + + switch (caveScene) { + case 1: + n_dialogues = ARRAYSIZE(introDialogueCave1[lang]); + dialogue = introDialogueCave1[lang]; break; - case SCENE_END: + case 2: + n_dialogues = ARRAYSIZE(introDialogueCave2[lang]); + dialogue = introDialogueCave2[lang]; break; - - default: - warning("Illegal scene procedure parameter"); + case 3: + n_dialogues = ARRAYSIZE(introDialogueCave3[lang]); + dialogue = introDialogueCave3[lang]; break; + case 4: + n_dialogues = ARRAYSIZE(introDialogueCave4[lang]); + dialogue = introDialogueCave4[lang]; + break; + default: + error("Invalid cave scene"); } - return 0; -} - -int Scene::SC_ITEIntroCave2Proc(int param, void *refCon) { - return ((Scene *)refCon)->ITEIntroCave2Proc(param); -} - -// Handles second introductory cave painting scene -int Scene::ITEIntroCave2Proc(int param) { - Event event; - EventColumns *eventColumns; - int lang = 0; - - if (_vm->getLanguage() == Common::DE_DEU) - lang = 1; - else if (_vm->getLanguage() == Common::IT_ITA) - lang = 2; - - static const IntroDialogue dialogue[][3] = { - { { // English - 4, // cave voice 4 - "The humans also knew the Secret of Life, and they " - "used it to give us the Four Great Gifts:" - }, - { - 5, // cave voice 5 - "Thinking minds, feeling hearts, speaking mouths, and " - "reaching hands." - }, - { - 6, // cave voice 6 - "We are their children." - } }, - // ----------------------------------------------------- - { { // German - 4, // cave voice 4 - "Au$erdem kannten die Menschen das Geheimnis des " - "Lebens. Und sie nutzten es, um uns die vier gro$en " - "Geschenke zu geben -" - }, - { - 5, // cave voice 5 - "den denkenden Geist, das f\201hlende Herz, den " - "sprechenden Mund und die greifende Hand." - }, - { - 6, // cave voice 6 - "Wir sind ihre Kinder." - } }, - // ----------------------------------------------------- - { { // Italian fan translation - 4, // cave voice 4 - "Gli Umani conoscevano anche il Segreto della Vita, " - "e lo usarono per darci i Quattro Grandi Doni:" - - }, - { - 5, // cave voice 5 - "Il pensiero, le emozioni, la parola e la manualit\205." - - }, - { - 6, // cave voice 6 - "Siamo i loro figli." - } } - }; - - int n_dialogues = ARRAYSIZE(dialogue[lang]); - switch (param) { case SCENE_BEGIN: - // Start 'dissolve' transition to new scene background - event.type = kEvTContinuous; - event.code = kTransitionEvent; - event.op = kEventDissolve; - event.time = 0; - event.duration = DISSOLVE_DURATION; - eventColumns = _vm->_events->queue(event); + if (caveScene > 1) { + // Start 'dissolve' transition to new scene background + event.type = kEvTContinuous; + event.code = kTransitionEvent; + event.op = kEventDissolve; + event.time = 0; + event.duration = DISSOLVE_DURATION; + eventColumns = _vm->_events->queue(event); + } // Begin palette cycling animation for candles event.type = kEvTOneshot; event.code = kPalAnimEvent; event.op = kEventCycleStart; event.time = 0; - _vm->_events->chain(eventColumns, event); + eventColumns = _vm->_events->chain(eventColumns, event); // Queue narrator dialogue list - ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]); + queueIntroDialogue(eventColumns, n_dialogues, dialogue); // End scene after last dialogue over event.type = kEvTOneshot; event.code = kSceneEvent; event.op = kEventEnd; - event.time = VOICE_PAD; + event.time = INTRO_VOICE_PAD; _vm->_events->chain(eventColumns, event); break; case SCENE_END: break; + default: warning("Illegal scene procedure parameter"); break; @@ -593,227 +437,24 @@ int Scene::ITEIntroCave2Proc(int param) { return 0; } -int Scene::SC_ITEIntroCave3Proc(int param, void *refCon) { - return ((Scene *)refCon)->ITEIntroCave3Proc(param); +// Handles first introductory cave painting scene +int Scene::SC_ITEIntroCave1Proc(int param, void *refCon) { + return ((Scene *)refCon)->ITEIntroCaveCommonProc(param, 1); } -// Handles third introductory cave painting scene -int Scene::ITEIntroCave3Proc(int param) { - Event event; - EventColumns *eventColumns; - int lang = 0; - - if (_vm->getLanguage() == Common::DE_DEU) - lang = 1; - else if (_vm->getLanguage() == Common::IT_ITA) - lang = 2; - - static const IntroDialogue dialogue[][3] = { - { { // English - 7, // cave voice 7 - "They taught us how to use our hands, and how to " - "speak." - }, - { - 8, // cave voice 8 - "They showed us the joy of using our minds." - }, - { - 9, // cave voice 9 - "They loved us, and when we were ready, they surely " - "would have given us the Secret of Happiness." - } }, - // ----------------------------------------------------- - { { // German - 7, // cave voice 7 - "Sie lehrten uns zu sprechen und unsere H\204nde zu " - "benutzen." - }, - { - 8, // cave voice 8 - "Sie zeigten uns die Freude am Denken." - }, - { - 9, // cave voice 9 - "Sie liebten uns, und w\204ren wir bereit gewesen, " - "h\204tten sie uns sicherlich das Geheimnis der " - "Fr\224hlichkeit offenbart." - } }, - // ----------------------------------------------------- - { { // Italian fan translation - 7, // cave voice 7 - "Ci insegnarono come usare le mani e come parlare. " - - }, - { - 8, // cave voice 8 - "Ci mostrarono le gioie che l'uso della mente " - "pu\225 dare. " - }, - { - 9, // cave voice 9 - "Ci amarono, ed una volta pronti, ci avrebbero " - "sicuramente svelato il Segreto della Felicit\205." - - } } - }; - - int n_dialogues = ARRAYSIZE(dialogue[lang]); - - switch (param) { - case SCENE_BEGIN: - // Start 'dissolve' transition to new scene background - event.type = kEvTContinuous; - event.code = kTransitionEvent; - event.op = kEventDissolve; - event.time = 0; - event.duration = DISSOLVE_DURATION; - eventColumns = _vm->_events->queue(event); - - // Begin palette cycling animation for candles - event.type = kEvTOneshot; - event.code = kPalAnimEvent; - event.op = kEventCycleStart; - event.time = 0; - _vm->_events->chain(eventColumns, event); - - // Queue narrator dialogue list - ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]); - - // End scene after last dialogue over - event.type = kEvTOneshot; - event.code = kSceneEvent; - event.op = kEventEnd; - event.time = VOICE_PAD; - _vm->_events->chain(eventColumns, event); - - break; - case SCENE_END: - break; - default: - warning("Illegal scene procedure parameter"); - break; - } - - return 0; +// Handles second introductory cave painting scene +int Scene::SC_ITEIntroCave2Proc(int param, void *refCon) { + return ((Scene *)refCon)->ITEIntroCaveCommonProc(param, 2); } -int Scene::SC_ITEIntroCave4Proc(int param, void *refCon) { - return ((Scene *)refCon)->ITEIntroCave4Proc(param); +// Handles third introductory cave painting scene +int Scene::SC_ITEIntroCave3Proc(int param, void *refCon) { + return ((Scene *)refCon)->ITEIntroCaveCommonProc(param, 3); } // Handles fourth introductory cave painting scene -int Scene::ITEIntroCave4Proc(int param) { - Event event; - EventColumns *eventColumns; - int lang = 0; - - if (_vm->getLanguage() == Common::DE_DEU) - lang = 1; - else if (_vm->getLanguage() == Common::IT_ITA) - lang = 2; - - static const IntroDialogue dialogue[][4] = { - { { // English - 10, // cave voice 10 - "And now we see the sky, the land, and the water that " - "we are heirs to, and we wonder: why did they leave?" - }, - { - 11, // cave voice 11 - "Do they live still, in the stars? In the oceans " - "depths? In the wind?" - }, - { - 12, // cave voice 12 - "We wonder, was their fate good or evil?" - }, - { - 13, // cave voice 13 - "And will we also share the same fate one day?" - } }, - // ----------------------------------------------------- - { { // German - 10, // cave voice 10 - "Und nun sehen wir den Himmel, das Land und die " - "Seen - unser Erbe. Und wir fragen uns - warum " - "verschwanden sie?" - }, - { - 11, // cave voice 11 - "Leben sie noch in den Sternen? In den Tiefen des " - "Ozeans? Im Wind?" - }, - { - 12, // cave voice 12 - "Wir fragen uns - war ihr Schicksal gut oder b\224se?" - }, - { - 13, // cave voice 13 - "Und wird uns eines Tages das gleiche Schicksal " - "ereilen?" - } }, - // ----------------------------------------------------- - { { // Italian fan translation - 10, // cave voice 10 - "Ed ora che guardiamo il cielo, la terra e l'acqua " - "che abbiamo ereditato, pensiamo: Perch\202 partirono?" - - }, - { - 11, // cave voice 11 - "Vivono ancora, nelle stelle? Nelle profondit\205 " - "dell'oceano? Nel vento?" - }, - { - 12, // cave voice 12 - "Ci domandiamo, il loro destino fu felice o nefasto?" - }, - { - 13, // cave voice 13 - "E un giorno, condivideremo anche noi lo stesso " - "destino?" - } } - }; - - int n_dialogues = ARRAYSIZE(dialogue[lang]); - - switch (param) { - case SCENE_BEGIN: - // Start 'dissolve' transition to new scene background - event.type = kEvTContinuous; - event.code = kTransitionEvent; - event.op = kEventDissolve; - event.time = 0; - event.duration = DISSOLVE_DURATION; - eventColumns = _vm->_events->queue(event); - - // Begin palette cycling animation for candles - event.type = kEvTOneshot; - event.code = kPalAnimEvent; - event.op = kEventCycleStart; - event.time = 0; - _vm->_events->chain(eventColumns, event); - - // Queue narrator dialogue list - ITEQueueDialogue(eventColumns, n_dialogues, dialogue[lang]); - - // End scene after last dialogue over - event.type = kEvTOneshot; - event.code = kSceneEvent; - event.op = kEventEnd; - event.time = VOICE_PAD; - _vm->_events->chain(eventColumns, event); - - break; - case SCENE_END: - break; - default: - warning("Illegal scene procedure parameter"); - break; - } - - return 0; +int Scene::SC_ITEIntroCave4Proc(int param, void *refCon) { + return ((Scene *)refCon)->ITEIntroCaveCommonProc(param, 4); } int Scene::SC_ITEIntroValleyProc(int param, void *refCon) { @@ -825,23 +466,7 @@ int Scene::ITEIntroValleyProc(int param) { Event event; EventColumns *eventColumns; - static const IntroCredit credits[] = { - {EN_ANY, kITEAny, kCHeader, "Producer"}, - {DE_DEU, kITEAny, kCHeader, "Produzent"}, - {IT_ITA, kITEAny, kCHeader, "Produttore"}, - {UNK_LANG, kITEAny, kCText, "Walter Hochbrueckner"}, - {EN_ANY, kITEAny, kCHeader, "Executive Producer"}, - {DE_DEU, kITEAny, kCHeader, "Ausf\201hrender Produzent"}, - {IT_ITA, kITEAny, kCHeader, "Produttore Esecutivo"}, - {UNK_LANG, kITEAny, kCText, "Robert McNally"}, - {UNK_LANG, kITEWyrmKeep, kCHeader, "2nd Executive Producer"}, - {EN_ANY, kITENotWyrmKeep, kCHeader, "Publisher"}, - {DE_DEU, kITENotWyrmKeep, kCHeader, "Herausgeber"}, - {IT_ITA, kITENotWyrmKeep, kCHeader, "Editore"}, - {UNK_LANG, kITEAny, kCText, "Jon Van Caneghem"} - }; - - int n_credits = ARRAYSIZE(credits); + int n_credits = ARRAYSIZE(creditsValley); switch (param) { case SCENE_BEGIN: @@ -858,13 +483,7 @@ int Scene::ITEIntroValleyProc(int param) { // Begin ITE title theme music _vm->_music->stop(); - event.type = kEvTOneshot; - event.code = kMusicEvent; - event.param = MUSIC_2; - event.param2 = MUSIC_NORMAL; - event.op = kEventPlay; - event.time = 0; - _vm->_events->chain(eventColumns, event); + _vm->_events->chainMusic(eventColumns, MUSIC_TITLE_THEME); // Pause animation before logo event.type = kEvTOneshot; @@ -899,7 +518,7 @@ int Scene::ITEIntroValleyProc(int param) { _vm->_events->chain(eventColumns, event); // Queue game credits list - eventColumns = ITEQueueCredits(9000, CREDIT_DURATION1, n_credits, credits); + eventColumns = queueCredits(9000, CREDIT_DURATION1, n_credits, creditsValley); // End scene after credit display event.type = kEvTOneshot; @@ -928,47 +547,8 @@ int Scene::ITEIntroTreeHouseProc(int param) { Event event; EventColumns *eventColumns; - static const IntroCredit credits1[] = { - {EN_ANY, kITEAny, kCHeader, "Game Design"}, - {DE_DEU, kITEAny, kCHeader, "Spielentwurf"}, - {IT_ITA, kITEAny, kCHeader, "Progetto"}, - {UNK_LANG, kITEAny, kCText, "Talin, Joe Pearce, Robert McNally"}, - {EN_ANY, kITEAny, kCText, "and Carolly Hauksdottir"}, - {DE_DEU, kITEAny, kCText, "und Carolly Hauksdottir"}, - {IT_ITA, kITEAny, kCText, "e Carolly Hauksdottir"}, - {EN_ANY, kITEAny, kCHeader, "Screenplay and Dialog"}, - {EN_ANY, kITEAny, kCText, "Robert Leh, Len Wein, and Bill Rotsler"}, - {DE_DEU, kITEAny, kCHeader, "Geschichte und Dialoge"}, - {DE_DEU, kITEAny, kCText, "Robert Leh, Len Wein und Bill Rotsler"}, - {IT_ITA, kITEAny, kCHeader, "Sceneggiatura e Dialoghi"}, - {IT_ITA, kITEAny, kCText, "Robert Leh, Len Wein e Bill Rotsler"} - }; - - int n_credits1 = ARRAYSIZE(credits1); - - static const IntroCredit credits2[] = { - {UNK_LANG, kITEWyrmKeep, kCHeader, "Art Direction"}, - {UNK_LANG, kITEWyrmKeep, kCText, "Allison Hershey"}, - {EN_ANY, kITEAny, kCHeader, "Art"}, - {DE_DEU, kITEAny, kCHeader, "Grafiken"}, - {IT_ITA, kITEAny, kCHeader, "Grafica"}, - {UNK_LANG, kITEWyrmKeep, kCText, "Ed Lacabanne, Glenn Price, April Lee,"}, - {UNK_LANG, kITENotWyrmKeep, kCText, "Edward Lacabanne, Glenn Price, April Lee,"}, - {UNK_LANG, kITEWyrmKeep, kCText, "Lisa Sample, Brian Dowrick, Reed Waller,"}, - {EN_ANY, kITEWyrmKeep, kCText, "Allison Hershey and Talin"}, - {DE_DEU, kITEWyrmKeep, kCText, "Allison Hershey und Talin"}, - {IT_ITA, kITEWyrmKeep, kCText, "Allison Hershey e Talin"}, - {EN_ANY, kITENotWyrmKeep, kCText, "Lisa Iennaco, Brian Dowrick, Reed"}, - {EN_ANY, kITENotWyrmKeep, kCText, "Waller, Allison Hershey and Talin"}, - {DE_DEU, kITEAny, kCText, "Waller, Allison Hershey und Talin"}, - {IT_ITA, kITEAny, kCText, "Waller, Allison Hershey e Talin"}, - {EN_ANY, kITENotWyrmKeep, kCHeader, "Art Direction"}, - {DE_DEU, kITENotWyrmKeep, kCHeader, "Grafische Leitung"}, - {IT_ITA, kITENotWyrmKeep, kCHeader, "Direzione Grafica"}, - {UNK_LANG, kITENotWyrmKeep, kCText, "Allison Hershey"} - }; - - int n_credits2 = ARRAYSIZE(credits2); + int n_credits1 = ARRAYSIZE(creditsTreeHouse1); + int n_credits2 = ARRAYSIZE(creditsTreeHouse2); switch (param) { case SCENE_BEGIN: @@ -993,8 +573,8 @@ int Scene::ITEIntroTreeHouseProc(int param) { } // Queue game credits list - ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1); - eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, credits2); + queueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, creditsTreeHouse1); + eventColumns = queueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, creditsTreeHouse2); // End scene after credit display event.type = kEvTOneshot; @@ -1023,34 +603,8 @@ int Scene::ITEIntroFairePathProc(int param) { Event event; EventColumns *eventColumns; - static const IntroCredit credits1[] = { - {EN_ANY, kITEAny, kCHeader, "Programming"}, - {DE_DEU, kITEAny, kCHeader, "Programmiert von"}, - {IT_ITA, kITEAny, kCHeader, "Programmazione"}, - {UNK_LANG, kITEAny, kCText, "Talin, Walter Hochbrueckner,"}, - {EN_ANY, kITEAny, kCText, "Joe Burks and Robert Wiggins"}, - {DE_DEU, kITEAny, kCText, "Joe Burks und Robert Wiggins"}, - {IT_ITA, kITEAny, kCText, "Joe Burks e Robert Wiggins"}, - {EN_ANY, kITEPCCD | kITEWyrmKeep, kCHeader, "Additional Programming"}, - {EN_ANY, kITEPCCD | kITEWyrmKeep, kCText, "John Bolton"}, - {UNK_LANG, kITEMac, kCHeader, "Macintosh Version"}, - {UNK_LANG, kITEMac, kCText, "Michael McNally and Robert McNally"}, - {EN_ANY, kITEAny, kCHeader, "Music and Sound"}, - {DE_DEU, kITEAny, kCHeader, "Musik und Sound"}, - {IT_ITA, kITEAny, kCHeader, "Musica e Sonoro"}, - {UNK_LANG, kITEAny, kCText, "Matt Nathan"} - }; - - int n_credits1 = ARRAYSIZE(credits1); - - static const IntroCredit credits2[] = { - {EN_ANY, kITEAny, kCHeader, "Directed by"}, - {DE_DEU, kITEAny, kCHeader, "Regie"}, - {IT_ITA, kITEAny, kCHeader, "Regia"}, - {UNK_LANG, kITEAny, kCText, "Talin"} - }; - - int n_credits2 = ARRAYSIZE(credits2); + int n_credits1 = ARRAYSIZE(creditsFairePath1); + int n_credits2 = ARRAYSIZE(creditsFairePath2); switch (param) { case SCENE_BEGIN: @@ -1073,8 +627,8 @@ int Scene::ITEIntroFairePathProc(int param) { _vm->_events->chain(eventColumns, event); // Queue game credits list - ITEQueueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, credits1); - eventColumns = ITEQueueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, credits2); + queueCredits(DISSOLVE_DURATION + 2000, CREDIT_DURATION1, n_credits1, creditsFairePath1); + eventColumns = queueCredits(DISSOLVE_DURATION + 7000, CREDIT_DURATION1, n_credits2, creditsFairePath2); // End scene after credit display event.type = kEvTOneshot; diff --git a/engines/saga/introproc_saga2.cpp b/engines/saga/introproc_saga2.cpp index 710236b0c4..0b773b03f0 100644 --- a/engines/saga/introproc_saga2.cpp +++ b/engines/saga/introproc_saga2.cpp @@ -43,9 +43,6 @@ int Scene::DinoStartProc() { playMovie("testvid.smk"); - // HACK: Forcibly quit here - _vm->quitGame(); - return SUCCESS; } @@ -55,9 +52,6 @@ int Scene::FTA2StartProc() { playMovie("trimark.smk"); playMovie("intro.smk"); - // HACK: Forcibly quit here - _vm->quitGame(); - return SUCCESS; } diff --git a/engines/saga/itedata.cpp b/engines/saga/itedata.cpp index 87b71c2cb7..da70733f4e 100644 --- a/engines/saga/itedata.cpp +++ b/engines/saga/itedata.cpp @@ -444,111 +444,437 @@ const RawPoint pieceOrigins[PUZZLE_PIECES] = { }; const char *pieceNames[][PUZZLE_PIECES] = { - { "screwdriver", "pliers", "c-clamp", "wood clamp", "level", - "twine", "wood plane", "claw hammer", "tape measure", "hatchet", - "shears", "ruler", "saw", "mallet", "paint brush" + { + "screwdriver", "pliers", "c-clamp", "wood clamp", "level", + "twine", "wood plane", "claw hammer", "tape measure", "hatchet", + "shears", "ruler", "saw", "mallet", "paint brush" }, - { "Schraubendreher", "Zange", "Schraubzwinge", "Holzzwinge", "Wasserwaage", - "Bindfaden", "Hobel", "Schusterhammer", "Bandma$", "Beil", - "Schere", "Winkel", "S\204ge", "Hammer", "Pinsel" + { + "Schraubendreher", "Zange", "Schraubzwinge", "Holzzwinge", "Wasserwaage", + "Bindfaden", "Hobel", "Schusterhammer", "Bandma$", "Beil", + "Schere", "Winkel", "S\204ge", "Hammer", "Pinsel" }, - { "cacciavite", "pinze", "morsa", "morsa da legno", "livella", - "spago", "pialla", "martello", "metro a nastro", "accetta", - "cesoie", "righello", "sega", "mazza", "pennello" + { + "cacciavite", "pinze", "morsa", "morsa da legno", "livella", + "spago", "pialla", "martello", "metro a nastro", "accetta", + "cesoie", "righello", "sega", "mazza", "pennello" } }; const char *hintStr[][4] = { - { "Check which pieces could fit in each corner first.", - "Check which corner has the least number of pieces that can fit and start from there.", - "Check each new corner and any new side for pieces that fit.", - "I don't see anything out of place." - }, - { "\232berpr\201fe zun\204chst, welche die Eckteile sein k\224nnten.", - "Schau, in welche Ecke die wenigsten Teile passen, und fang dort an.", - "Untersuche jede Ecke und jede Seite auf Teile, die dort passen k\224nnen.", - "Ich sehe nichts an der falschen Stelle." - }, - { "Controlla prima quali pezzi si inseriscono meglio in ogni angolo.", - "Controlla quale angolo ha il minor numero di pezzi che combaciano, e parti da quello.", - "Controlla ogni nuovo angolo e lato per ogni pezzo che combacia.", - "Non vedo nulla fuori posto." + { + "Check which pieces could fit in each corner first.", + "Check which corner has the least number of pieces that can fit and start from there.", + "Check each new corner and any new side for pieces that fit.", + "I don't see anything out of place." + }, + { + "\232berpr\201fe zun\204chst, welche die Eckteile sein k\224nnten.", + "Schau, in welche Ecke die wenigsten Teile passen, und fang dort an.", + "Untersuche jede Ecke und jede Seite auf Teile, die dort passen k\224nnen.", + "Ich sehe nichts an der falschen Stelle." + }, + { + "Controlla prima quali pezzi si inseriscono meglio in ogni angolo.", + "Controlla quale angolo ha il minor numero di pezzi che combaciano, e parti da quello.", + "Controlla ogni nuovo angolo e lato per ogni pezzo che combacia.", + "Non vedo nulla fuori posto." } }; const char *solicitStr[][NUM_SOLICIT_REPLIES] = { - { "Hey, Fox! Would you like a hint?", - "Would you like some help?", - "Umm...Umm...", - "Psst! want a hint?", - "I would have done this differently, you know." - }, - { "Hey, Fuchs! Brauchst Du \047nen Tip?", - "M\224chtest Du etwas Hilfe?" - "\231hm...\216hm..." - "Psst! \047n Tip vielleicht?" - "Ja, wei$t Du... ich h\204tte das anders gemacht." - }, - { "Hey, Volpe! Serve un suggerimento?", - "Hai bisogno di aiuto?", - "Umm...Umm...", - "Psst! Serve un aiutino?", - "Io, sai, l'avrei fatto diversamente." + { + "Hey, Fox! Would you like a hint?", + "Would you like some help?", + "Umm...Umm...", + "Psst! want a hint?", + "I would have done this differently, you know." + }, + { + "Hey, Fuchs! Brauchst Du \047nen Tip?", + "M\224chtest Du etwas Hilfe?" + "\231hm...\216hm..." + "Psst! \047n Tip vielleicht?" + "Ja, wei$t Du... ich h\204tte das anders gemacht." + }, + { + "Hey, Volpe! Serve un suggerimento?", + "Hai bisogno di aiuto?", + "Umm...Umm...", + "Psst! Serve un aiutino?", + "Io, sai, l'avrei fatto diversamente." } }; const char *sakkaStr[][NUM_SAKKA] = { - { "Hey, you're not supposed to help the applicants!", - "Guys! This is supposed to be a test!", - "C'mon fellows, that's not in the rules!" + { + "Hey, you're not supposed to help the applicants!", + "Guys! This is supposed to be a test!", + "C'mon fellows, that's not in the rules!" }, - { "Hey, Du darfst dem Pr\201fling nicht helfen!", - "Hallo?! Dies soll eine Pr\201fung sein!", - "Also, Jungs. Schummeln steht nicht in den Regeln!" + { + "Hey, Du darfst dem Pr\201fling nicht helfen!", + "Hallo?! Dies soll eine Pr\201fung sein!", + "Also, Jungs. Schummeln steht nicht in den Regeln!" }, - { "Hey, non si dovrebbero aiutare i candidati!", - "Ragazzi! Questo dovrebbe essere un test!", - "Forza ragazzi, non si pu\225!" + { + "Hey, non si dovrebbero aiutare i candidati!", + "Ragazzi! Questo dovrebbe essere un test!", + "Forza ragazzi, non si pu\225!" } }; const char *whineStr[][NUM_WHINES] = { - { "Aww, c'mon Sakka!", - "One hint won't hurt, will it?", - "Sigh...", - "I think that clipboard has gone to your head, Sakka!", - "Well, I don't recall any specific rule against hinting." - }, - { "Och, sei nicht so, Sakka!" - "EIN Tip wird schon nicht schaden, oder?", - "Seufz..." - "Ich glaube, Du hast ein Brett vor dem Kopf, Sakka!", - "Hm, ich kann mich an keine Regel erinnern, die Tips verbietet." - }, - { "Ooo, suvvia Sakka!", - "Un indizio non guaster\205, no?", - "Sigh...", - "Credo che questa faccenda ti abbia dato alla testa, Sakka!", - "Beh, non ricordo regole specifiche contro i suggerimenti." + { + "Aww, c'mon Sakka!", + "One hint won't hurt, will it?", + "Sigh...", + "I think that clipboard has gone to your head, Sakka!", + "Well, I don't recall any specific rule against hinting." + }, + { + "Och, sei nicht so, Sakka!" + "EIN Tip wird schon nicht schaden, oder?", + "Seufz..." + "Ich glaube, Du hast ein Brett vor dem Kopf, Sakka!", + "Hm, ich kann mich an keine Regel erinnern, die Tips verbietet." + }, + { + "Ooo, suvvia Sakka!", + "Un indizio non guaster\205, no?", + "Sigh...", + "Credo che questa faccenda ti abbia dato alla testa, Sakka!", + "Beh, non ricordo regole specifiche contro i suggerimenti." } }; const char *optionsStr[][4] = { - { "\"I'll do this puzzle later.\"", - "\"Yes, I'd like a hint please.\"", - "\"No, thank you, I'd like to try and solve it myself.\"", - "I think the %s is in the wrong place." - }, - { "\"Ich l\224se das Puzzle sp\204ter.\"", - "\"Ja, ich m\224chte einen Tip, bitte.\"", - "\"Nein danke, ich m\224chte das alleine l\224sen.\"", - "Pssst... %s... falsche Stelle..." - }, - { "\"Far\225 questo puzzle pi\227 tardi.\"", - "\"Si, grazie. Ne avrei bisogno.\"", - "\"No, grazie, voglio provare a risolverlo da solo.\"", - "Penso che la tessera %s sia nel posto sbagliato." + { + "\"I'll do this puzzle later.\"", + "\"Yes, I'd like a hint please.\"", + "\"No, thank you, I'd like to try and solve it myself.\"", + "I think the %s is in the wrong place." + }, + { + "\"Ich l\224se das Puzzle sp\204ter.\"", + "\"Ja, ich m\224chte einen Tip, bitte.\"", + "\"Nein danke, ich m\224chte das alleine l\224sen.\"", + "Pssst... %s... falsche Stelle..." + }, + { + "\"Far\225 questo puzzle pi\227 tardi.\"", + "\"Si, grazie. Ne avrei bisogno.\"", + "\"No, grazie, voglio provare a risolverlo da solo.\"", + "Penso che la tessera %s sia nel posto sbagliato." } }; +const IntroDialogue introDialogueCave1[][4] = { + { { // English + 0, // cave voice 0 + "We see the sky, we see the land, we see the water, " + "and we wonder: Are we the only ones?" + }, + { + 1, // cave voice 1 + "Long before we came to exist, the humans ruled the " + "Earth." + }, + { + 2, // cave voice 2 + "They made marvelous things, and moved whole " + "mountains." + }, + { + 3, // cave voice 3 + "They knew the Secret of Flight, the Secret of " + "Happiness, and other secrets beyond our imagining." + } }, + // ----------------------------------------------------- + { { // German + 0, // cave voice 0 + "Um uns sind der Himmel, das Land und die Seen; und " + "wir fragen uns - sind wir die einzigen?" + }, + { + 1, // cave voice 1 + "Lange vor unserer Zeit herrschten die Menschen " + "\201ber die Erde." + }, + { + 2, // cave voice 2 + "Sie taten wundersame Dinge und versetzten ganze " + "Berge." + }, + { + 3, // cave voice 3 + "Sie kannten das Geheimnis des Fluges, das Geheimnis " + "der Fr\224hlichkeit und andere Geheimnisse, die " + "unsere Vorstellungskraft \201bersteigen." + } }, + // ----------------------------------------------------- + { { // Italian fan translation + 0, // cave voice 0 + "Guardiamo il cielo, guardiamo la terra, guardiamo " + "l'acqua, e ci chiediamo: Siamo forse soli?" + }, + { + 1, // cave voice 1 + "Molto tempo prima che noi esistessimo, gli Umani " + "dominavano la terra." + }, + { + 2, // cave voice 2 + "Fecero cose meravigliose, e mossero intere " + "montagne." + }, + { + 3, // cave voice 3 + "Conoscevano il Segreto del Volo, il Segreto della " + "Felicit\205, ed altri segreti oltre ogni nostra " + "immaginazione." + } } +}; + +const IntroDialogue introDialogueCave2[][3] = { + { { // English + 4, // cave voice 4 + "The humans also knew the Secret of Life, and they " + "used it to give us the Four Great Gifts:" + }, + { + 5, // cave voice 5 + "Thinking minds, feeling hearts, speaking mouths, and " + "reaching hands." + }, + { + 6, // cave voice 6 + "We are their children." + } }, + // ----------------------------------------------------- + { { // German + 4, // cave voice 4 + "Au$erdem kannten die Menschen das Geheimnis des " + "Lebens. Und sie nutzten es, um uns die vier gro$en " + "Geschenke zu geben -" + }, + { + 5, // cave voice 5 + "den denkenden Geist, das f\201hlende Herz, den " + "sprechenden Mund und die greifende Hand." + }, + { + 6, // cave voice 6 + "Wir sind ihre Kinder." + } }, + // ----------------------------------------------------- + { { // Italian fan translation + 4, // cave voice 4 + "Gli Umani conoscevano anche il Segreto della Vita, " + "e lo usarono per darci i Quattro Grandi Doni:" + + }, + { + 5, // cave voice 5 + "Il pensiero, le emozioni, la parola e la manualit\205." + + }, + { + 6, // cave voice 6 + "Siamo i loro figli." + } } +}; + +const IntroDialogue introDialogueCave3[][3] = { + { { // English + 7, // cave voice 7 + "They taught us how to use our hands, and how to " + "speak." + }, + { + 8, // cave voice 8 + "They showed us the joy of using our minds." + }, + { + 9, // cave voice 9 + "They loved us, and when we were ready, they surely " + "would have given us the Secret of Happiness." + } }, + // ----------------------------------------------------- + { { // German + 7, // cave voice 7 + "Sie lehrten uns zu sprechen und unsere H\204nde zu " + "benutzen." + }, + { + 8, // cave voice 8 + "Sie zeigten uns die Freude am Denken." + }, + { + 9, // cave voice 9 + "Sie liebten uns, und w\204ren wir bereit gewesen, " + "h\204tten sie uns sicherlich das Geheimnis der " + "Fr\224hlichkeit offenbart." + } }, + // ----------------------------------------------------- + { { // Italian fan translation + 7, // cave voice 7 + "Ci insegnarono come usare le mani e come parlare. " + + }, + { + 8, // cave voice 8 + "Ci mostrarono le gioie che l'uso della mente " + "pu\225 dare. " + }, + { + 9, // cave voice 9 + "Ci amarono, ed una volta pronti, ci avrebbero " + "sicuramente svelato il Segreto della Felicit\205." + + } } +}; + +const IntroDialogue introDialogueCave4[][4] = { + { { // English + 10, // cave voice 10 + "And now we see the sky, the land, and the water that " + "we are heirs to, and we wonder: why did they leave?" + }, + { + 11, // cave voice 11 + "Do they live still, in the stars? In the oceans " + "depths? In the wind?" + }, + { + 12, // cave voice 12 + "We wonder, was their fate good or evil?" + }, + { + 13, // cave voice 13 + "And will we also share the same fate one day?" + } }, + // ----------------------------------------------------- + { { // German + 10, // cave voice 10 + "Und nun sehen wir den Himmel, das Land und die " + "Seen - unser Erbe. Und wir fragen uns - warum " + "verschwanden sie?" + }, + { + 11, // cave voice 11 + "Leben sie noch in den Sternen? In den Tiefen des " + "Ozeans? Im Wind?" + }, + { + 12, // cave voice 12 + "Wir fragen uns - war ihr Schicksal gut oder b\224se?" + }, + { + 13, // cave voice 13 + "Und wird uns eines Tages das gleiche Schicksal " + "ereilen?" + } }, + // ----------------------------------------------------- + { { // Italian fan translation + 10, // cave voice 10 + "Ed ora che guardiamo il cielo, la terra e l'acqua " + "che abbiamo ereditato, pensiamo: Perch\202 partirono?" + + }, + { + 11, // cave voice 11 + "Vivono ancora, nelle stelle? Nelle profondit\205 " + "dell'oceano? Nel vento?" + }, + { + 12, // cave voice 12 + "Ci domandiamo, il loro destino fu felice o nefasto?" + }, + { + 13, // cave voice 13 + "E un giorno, condivideremo anche noi lo stesso " + "destino?" + } } +}; + +const IntroCredit creditsValley[] = { + {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Producer"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Produzent"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Produttore"}, + {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Walter Hochbrueckner"}, + {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Executive Producer"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Ausf\201hrender Produzent"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Produttore Esecutivo"}, + {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Robert McNally"}, + {Common::UNK_LANG, kITECreditsWyrmKeep, kITECreditsHeader, "2nd Executive Producer"}, + {Common::EN_ANY, kITECreditsNotWyrmKeep, kITECreditsHeader, "Publisher"}, + {Common::DE_DEU, kITECreditsNotWyrmKeep, kITECreditsHeader, "Herausgeber"}, + {Common::IT_ITA, kITECreditsNotWyrmKeep, kITECreditsHeader, "Editore"}, + {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Jon Van Caneghem"} +}; + +const IntroCredit creditsTreeHouse1[] = { + {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Game Design"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Spielentwurf"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Progetto"}, + {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Talin, Joe Pearce, Robert McNally"}, + {Common::EN_ANY, kITECreditsAny, kITECreditsText, "and Carolly Hauksdottir"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsText, "und Carolly Hauksdottir"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsText, "e Carolly Hauksdottir"}, + {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Screenplay and Dialog"}, + {Common::EN_ANY, kITECreditsAny, kITECreditsText, "Robert Leh, Len Wein, and Bill Rotsler"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Geschichte und Dialoge"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsText, "Robert Leh, Len Wein und Bill Rotsler"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Sceneggiatura e Dialoghi"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsText, "Robert Leh, Len Wein e Bill Rotsler"} +}; + +const IntroCredit creditsTreeHouse2[] = { + {Common::UNK_LANG, kITECreditsWyrmKeep, kITECreditsHeader, "Art Direction"}, + {Common::UNK_LANG, kITECreditsWyrmKeep, kITECreditsText, "Allison Hershey"}, + {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Art"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Grafiken"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Grafica"}, + {Common::UNK_LANG, kITECreditsWyrmKeep, kITECreditsText, "Ed Lacabanne, Glenn Price, April Lee,"}, + {Common::UNK_LANG, kITECreditsNotWyrmKeep, kITECreditsText, "Edward Lacabanne, Glenn Price, April Lee,"}, + {Common::UNK_LANG, kITECreditsWyrmKeep, kITECreditsText, "Lisa Sample, Brian Dowrick, Reed Waller,"}, + {Common::EN_ANY, kITECreditsWyrmKeep, kITECreditsText, "Allison Hershey and Talin"}, + {Common::DE_DEU, kITECreditsWyrmKeep, kITECreditsText, "Allison Hershey und Talin"}, + {Common::IT_ITA, kITECreditsWyrmKeep, kITECreditsText, "Allison Hershey e Talin"}, + {Common::EN_ANY, kITECreditsNotWyrmKeep, kITECreditsText, "Lisa Iennaco, Brian Dowrick, Reed"}, + {Common::EN_ANY, kITECreditsNotWyrmKeep, kITECreditsText, "Waller, Allison Hershey and Talin"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsText, "Waller, Allison Hershey und Talin"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsText, "Waller, Allison Hershey e Talin"}, + {Common::EN_ANY, kITECreditsNotWyrmKeep, kITECreditsHeader, "Art Direction"}, + {Common::DE_DEU, kITECreditsNotWyrmKeep, kITECreditsHeader, "Grafische Leitung"}, + {Common::IT_ITA, kITECreditsNotWyrmKeep, kITECreditsHeader, "Direzione Grafica"}, + {Common::UNK_LANG, kITECreditsNotWyrmKeep, kITECreditsText, "Allison Hershey"} +}; + +const IntroCredit creditsFairePath1[] = { + {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Programming"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Programmiert von"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Programmazione"}, + {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Talin, Walter Hochbrueckner,"}, + {Common::EN_ANY, kITECreditsAny, kITECreditsText, "Joe Burks and Robert Wiggins"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsText, "Joe Burks und Robert Wiggins"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsText, "Joe Burks e Robert Wiggins"}, + {Common::EN_ANY, kITECreditsPCCD | kITECreditsWyrmKeep, kITECreditsHeader, "Additional Programming"}, + {Common::EN_ANY, kITECreditsPCCD | kITECreditsWyrmKeep, kITECreditsText, "John Bolton"}, + {Common::UNK_LANG, kITECreditsMac, kITECreditsHeader, "Macintosh Version"}, + {Common::UNK_LANG, kITECreditsMac, kITECreditsText, "Michael McNally and Robert McNally"}, + {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Music and Sound"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Musik und Sound"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Musica e Sonoro"}, + {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Matt Nathan"} +}; + +const IntroCredit creditsFairePath2[] = { + {Common::EN_ANY, kITECreditsAny, kITECreditsHeader, "Directed by"}, + {Common::DE_DEU, kITECreditsAny, kITECreditsHeader, "Regie"}, + {Common::IT_ITA, kITECreditsAny, kITECreditsHeader, "Regia"}, + {Common::UNK_LANG, kITECreditsAny, kITECreditsText, "Talin"} +}; + } // End of namespace Saga diff --git a/engines/saga/itedata.h b/engines/saga/itedata.h index d27b84781f..f9416652bf 100644 --- a/engines/saga/itedata.h +++ b/engines/saga/itedata.h @@ -79,6 +79,32 @@ struct IteFxTable { byte vol; }; +struct IntroDialogue { + uint32 i_voice_rn; + const char *i_str; +}; + +struct IntroCredit { + Common::Language lang; + int game; + int type; + const char *string; +}; + +enum { + kITECreditsHeader, + kITECreditsText +}; + +enum { + kITECreditsPC = (1 << 0), + kITECreditsPCCD = (1 << 1), + kITECreditsMac = (1 << 2), + kITECreditsWyrmKeep = (1 << 3), + kITECreditsAny = 0xffff, + kITECreditsNotWyrmKeep = kITECreditsAny & ~kITECreditsWyrmKeep +}; + #define ITE_OBJECTCOUNT 39 #define ITE_SFXCOUNT 63 @@ -106,6 +132,17 @@ extern const char *hintStr[][4]; extern const char portraitList[]; extern const char *optionsStr[][4]; +extern const IntroDialogue introDialogueCave1[][4]; +extern const IntroDialogue introDialogueCave2[][3]; +extern const IntroDialogue introDialogueCave3[][3]; +extern const IntroDialogue introDialogueCave4[][4]; + +extern const IntroCredit creditsValley[13]; +extern const IntroCredit creditsTreeHouse1[13]; +extern const IntroCredit creditsTreeHouse2[19]; +extern const IntroCredit creditsFairePath1[15]; +extern const IntroCredit creditsFairePath2[4]; + } // End of namespace Saga #endif diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index e444900967..d20882ca26 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -147,7 +147,7 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { if (!_musicContext) { if (_vm->getGameId() == GID_ITE) { _musicContext = _vm->_resource->getContext(GAME_RESOURCEFILE); - } else { + } else if (_vm->getGameId() == GID_IHNM) { // I've listened to music from both the FM and the GM // file, and I've tentatively reached the conclusion // that they are both General MIDI. My guess is that @@ -173,6 +173,8 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { // Note that the IHNM demo has only got one music file // (music.rsc). It is assumed that it contains FM music _musicContext = _vm->_resource->getContext(GAME_MUSICFILE_FM); + } else if (_vm->getGameId() == GID_DINO || _vm->getGameId() == GID_FTA2) { + _musicContext = _vm->_resource->getContext(GAME_SOUNDFILE); } } @@ -255,19 +257,18 @@ void Music::play(uint32 resourceId, MusicFlags flags) { _mixer->stopHandle(_musicHandle); _player->stop(); - int realTrackNumber; + int realTrackNumber = 0; if (_vm->getGameId() == GID_ITE) { - if (flags == MUSIC_DEFAULT) { - if (resourceId == 13 || resourceId == 19) { - flags = MUSIC_NORMAL; - } else { - flags = MUSIC_LOOP; - } - } + if (flags == MUSIC_NORMAL && (resourceId == 13 || resourceId == 19)) + flags = MUSIC_LOOP; realTrackNumber = resourceId - 8; - } else { + } else if (_vm->getGameId() == GID_IHNM) { + realTrackNumber = resourceId + 1; + } else if (_vm->getGameId() == GID_DINO || _vm->getGameId() == GID_FTA2) { realTrackNumber = resourceId + 1; + uint32 musicTrackTag = MKTAG('X','M','I', (byte)(resourceId + 1)); + resourceId = _musicContext->getEntryNum(musicTrackTag); } // Try to open standalone digital track @@ -359,9 +360,6 @@ void Music::play(uint32 resourceId, MusicFlags flags) { return; } - if (flags == MUSIC_DEFAULT) - flags = MUSIC_NORMAL; - // Load MIDI/XMI resource data if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) { // Load the external music file for Mac IHNM diff --git a/engines/saga/music.h b/engines/saga/music.h index ba44c3ca71..2106fb6fa6 100644 --- a/engines/saga/music.h +++ b/engines/saga/music.h @@ -37,8 +37,7 @@ namespace Saga { enum MusicFlags { MUSIC_NORMAL = 0, - MUSIC_LOOP = 0x0001, - MUSIC_DEFAULT = 0xffff + MUSIC_LOOP = 0x0001 }; class MusicDriver : public Audio::MidiPlayer { @@ -72,7 +71,7 @@ public: bool isPlaying(); bool hasDigitalMusic() { return _digitalMusic; } - void play(uint32 resourceId, MusicFlags flags = MUSIC_DEFAULT); + void play(uint32 resourceId, MusicFlags flags = MUSIC_NORMAL); void pause(); void resume(); void stop(); diff --git a/engines/saga/resource.cpp b/engines/saga/resource.cpp index cdf674dc66..1fb9ac1c04 100644 --- a/engines/saga/resource.cpp +++ b/engines/saga/resource.cpp @@ -304,21 +304,13 @@ void Resource::clearContexts() { } void Resource::loadResource(ResourceContext *context, uint32 resourceId, ByteArray &resourceBuffer) { - Common::File *file; - uint32 resourceOffset; - ResourceData *resourceData; - - - resourceData = context->getResourceData(resourceId); - - file = context->getFile(resourceData); - - resourceOffset = resourceData->offset; + ResourceData *resourceData = context->getResourceData(resourceId); + Common::File *file = context->getFile(resourceData); + uint32 resourceOffset = resourceData->offset; debug(8, "loadResource %d 0x%X:0x%X", resourceId, resourceOffset, uint(resourceData->size)); resourceBuffer.resize(resourceData->size); - file->seek((long)resourceOffset, SEEK_SET); if (file->read(resourceBuffer.getBuffer(), resourceBuffer.size()) != resourceBuffer.size()) { diff --git a/engines/saga/resource.h b/engines/saga/resource.h index 252e92c967..2a1aaf3103 100644 --- a/engines/saga/resource.h +++ b/engines/saga/resource.h @@ -60,12 +60,13 @@ struct PatchData { struct ResourceData { uint32 id; // SAGA2 + uint32 category; // SAGA2 size_t offset; size_t size; PatchData *patchData; ResourceData() : - id(0), offset(0), size(0), patchData(NULL) { + id(0), category(0), offset(0), size(0), patchData(NULL) { } ~ResourceData() { @@ -130,10 +131,15 @@ public: // SAGA 2 int32 getEntryNum(uint32 id) { int32 num = 0; + uint32 miloCategory = MKTAG('M', 'I', 'L', 'O'); + for (ResourceDataArray::const_iterator i = _table.begin(); i != _table.end(); ++i) { - if (i->id == id) { + //uint32 c = i->category; + //debug("%c%c%c%c, offset: %d, size: %d", (c >> 24), (c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF, i->offset, i->size); + // Ignore low quality music resources (MILO) + if (i->id == id && i->category != miloCategory) return num; - } + num++; } return -1; @@ -282,6 +288,10 @@ protected: return loadResV2(contextSize); } bool loadResV2(uint32 contextSize); + + void readCategory(ResourceData &element); + void readEntry(ResourceData &element); + uint32 getCategory(uint32 resourceOffset); }; class Resource_HRS : public Resource { diff --git a/engines/saga/resource_hrs.cpp b/engines/saga/resource_hrs.cpp index 09da9cf0bb..ba58830269 100644 --- a/engines/saga/resource_hrs.cpp +++ b/engines/saga/resource_hrs.cpp @@ -39,13 +39,35 @@ namespace Saga { -void readElement(Common::File &file, Saga::ResourceData &element) { - element.id = file.readUint32BE(); - element.offset = file.readUint32LE(); - element.size = file.readUint32LE(); +void ResourceContext_HRS::readCategory(ResourceData &element) { + element.id = _file.readUint32BE(); + element.offset = _file.readUint32LE(); + element.size = _file.readUint32LE(); + element.category = 0; + debug(3, "Category: id %u, offset %u, size %u", element.id, (uint)element.offset, (uint)element.size); +} + +void ResourceContext_HRS::readEntry(ResourceData &element) { + element.id = _file.readUint32BE(); + element.offset = _file.readUint32LE(); + element.size = _file.readUint32LE(); + element.category = getCategory(_file.pos()); debug(3, "Entry: id %u, offset %u, size %u", element.id, (uint)element.offset, (uint)element.size); } +uint32 ResourceContext_HRS::getCategory(uint32 resourceOffset) { + for (int i = _categories.size() - 1; i >= 0; --i) { + if (resourceOffset >= _categories[i].offset) + return _categories[i].id; + } + + error("Unknown category for offset %d", resourceOffset); +} + +static bool categorySortHelper(const ResourceData &r1, const ResourceData &r2) { + return r1.offset < r2.offset; +} + bool ResourceContext_HRS::loadResV2(uint32 contextSize) { ResourceData origin; uint32 firstEntryOffset; @@ -56,7 +78,7 @@ bool ResourceContext_HRS::loadResV2(uint32 contextSize) { debug(3, "Context %s =====", _fileName); _file.seek(0, SEEK_SET); - readElement(_file, origin); + readCategory(origin); // Check if the file is valid if (origin.id != MKTAG('H','R','E','S')) { // header @@ -74,18 +96,23 @@ bool ResourceContext_HRS::loadResV2(uint32 contextSize) { // Read categories count = origin.size / resourceSize; - debug(3, "Categories: %d =====", count); + debug(3, "File: %s, categories: %d =====", _file.getName(), count); for (i = 0; i < count; i++) { - readElement(_file, _categories[i]); + readCategory(_categories[i]); + //uint32 id = _categories[i].id; + //debug("%i: %c%c%c%c, offset: %d, size: %d", i, (id >> 24), (id >> 16) & 0xFF, (id >> 8) & 0xFF, id & 0xFF, _categories[i].offset, _categories[i].size); } + Common::sort(_categories.begin(), _categories.end(), categorySortHelper); + _file.seek(firstEntryOffset, SEEK_SET); // Read table entries count = tableSize / resourceSize; - debug(3, "Entries: %d =====", count); + debug(3, "File: %s, entries: %d =====", _file.getName(), count); for (i = 0; i < count; i++) { - readElement(_file, _table[i]); + readEntry(_table[i]); + //debug("%i: offset: %d, size: %d", i, _table[i].offset, _table[i].size); } return true; } diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp index b15d161ba3..3d38b3ea52 100644 --- a/engines/saga/saga.cpp +++ b/engines/saga/saga.cpp @@ -341,7 +341,6 @@ Common::Error SagaEngine::run() { syncSoundSettings(); } else { _framesEsc = 0; - //_sndRes->playVoice(0); // SAGA 2 sound test _scene->startScene(); } diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index 04776bd5dc..f19645dd99 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -789,13 +789,7 @@ void Scene::loadScene(LoadSceneParams &loadSceneParams) { if (_vm->getGameId() == GID_ITE) { if (_sceneDescription.musicResourceId >= 0) { - event.type = kEvTOneshot; - event.code = kMusicEvent; - event.param = _sceneDescription.musicResourceId; - event.param2 = MUSIC_DEFAULT; - event.op = kEventPlay; - event.time = 0; - _vm->_events->queue(event); + _vm->_events->queueMusic(_sceneDescription.musicResourceId); } else { event.type = kEvTOneshot; event.code = kMusicEvent; diff --git a/engines/saga/scene.h b/engines/saga/scene.h index 0a3b98b33f..6a9571d282 100644 --- a/engines/saga/scene.h +++ b/engines/saga/scene.h @@ -182,34 +182,8 @@ typedef Common::List<LoadSceneParams> SceneQueueList; #define IHNM_TITLE_TIME_GM 28750 #define IHNM_TITLE_TIME_FM 19500 -///// ITE-specific stuff -#define ITE_INTRO_FRAMETIME 90 - -#define INTRO_CAPTION_Y 170 -#define INTRO_DE_CAPTION_Y 160 -#define INTRO_IT_CAPTION_Y 160 -#define VOICE_PAD 50 -#define VOICE_LETTERLEN 90 - -#define PALETTE_FADE_DURATION 1000 -#define DISSOLVE_DURATION 3000 -#define LOGO_DISSOLVE_DURATION 1000 - #define CREDIT_DURATION1 4000 -struct IntroDialogue { - uint32 i_voice_rn; - const char *i_str; -}; - -struct IntroCredit { - Common::Language lang; - int game; - int type; - const char *string; -}; - - class Scene { public: Scene(SagaEngine *vm); @@ -431,13 +405,10 @@ class Scene { static int SC_ITEIntroFaireTentProc(int param, void *refCon); private: - EventColumns *ITEQueueDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]); - EventColumns *ITEQueueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]); + EventColumns *queueIntroDialogue(EventColumns *eventColumns, int n_dialogues, const IntroDialogue dialogue[]); + EventColumns *queueCredits(int delta_time, int duration, int n_credits, const IntroCredit credits[]); int ITEIntroAnimProc(int param); - int ITEIntroCave1Proc(int param); - int ITEIntroCave2Proc(int param); - int ITEIntroCave3Proc(int param); - int ITEIntroCave4Proc(int param); + int ITEIntroCaveCommonProc(int param, int caveScene); int ITEIntroValleyProc(int param); int ITEIntroTreeHouseProc(int param); int ITEIntroFairePathProc(int param); diff --git a/engines/saga/sfuncs_ihnm.cpp b/engines/saga/sfuncs_ihnm.cpp index 6957360942..e3e3c1ca11 100644 --- a/engines/saga/sfuncs_ihnm.cpp +++ b/engines/saga/sfuncs_ihnm.cpp @@ -421,14 +421,7 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) { warning("sfQueueMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTable.size() - 1); } else { _vm->_music->setVolume(_vm->_musicVolume, 1); - event.type = kEvTOneshot; - event.code = kMusicEvent; - event.param = _vm->_music->_songTable[param1]; - event.param2 = param2 ? MUSIC_LOOP : MUSIC_NORMAL; - event.op = kEventPlay; - event.time = _vm->ticksToMSec(1000); - - _vm->_events->queue(event); + _vm->_events->queueMusic(_vm->_music->_songTable[param1], param2, _vm->ticksToMSec(1000)); if (!_vm->_scene->haveChapterPointsChanged()) { _vm->_scene->setCurrentMusicTrack(param1); diff --git a/engines/saga/shorten.cpp b/engines/saga/shorten.cpp index 426430c892..edb12a3dd9 100644 --- a/engines/saga/shorten.cpp +++ b/engines/saga/shorten.cpp @@ -29,6 +29,8 @@ // Based on etree's Shorten tool, version 3.6.1 // http://etree.org/shnutils/shorten/ +// and +// https://github.com/soiaf/Java-Shorten-decoder // FIXME: This doesn't work yet correctly @@ -154,6 +156,7 @@ uint32 ShortenGolombReader::getUint32(uint32 numBits) { byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, byte &flags) { int32 *buffer[2], *offset[2]; // up to 2 channels + int32 *oldValues[2]; byte *unpackedBuffer = 0; byte *pBuf = unpackedBuffer; int prevSize = 0; @@ -190,15 +193,18 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by switch (type) { case kTypeS8: + mean = 0; break; case kTypeU8: flags |= Audio::FLAG_UNSIGNED; + mean = 0x80; break; case kTypeS16LH: flags |= Audio::FLAG_LITTLE_ENDIAN; // fallthrough case kTypeS16HL: flags |= Audio::FLAG_16BITS; + mean = 0; break; case kTypeU16LH: flags |= Audio::FLAG_LITTLE_ENDIAN; @@ -206,6 +212,7 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by case kTypeU16HL: flags |= Audio::FLAG_16BITS; flags |= Audio::FLAG_UNSIGNED; + mean = 0x8000; break; case kTypeWAV: // TODO: Perhaps implement this if we find WAV Shorten encoded files @@ -264,8 +271,10 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by for (i = 0; i < channels; i++) { buffer[i] = (int32 *)malloc((blockSize + wrap) * 4); offset[i] = (int32 *)malloc((MAX<uint32>(1, mean)) * 4); + oldValues[i] = (int32 *)malloc(64 * 4); memset(buffer[i], 0, (blockSize + wrap) * 4); memset(offset[i], 0, (MAX<uint32>(1, mean)) * 4); + memset(oldValues[i], 0, 64 * 4); } if (maxLPC > 0) @@ -329,9 +338,6 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by channelOffset = (channelOffset >> (bitShift - 1)) >> 1; } - // FIXME: The original code in this bit tries to modify memory outside of the array (negative indices) - // in cases kCmdDiff1, kCmdDiff2 and kCmdDiff3 - // I've removed those invalid writes, since they happen all the time (even when curChannel is 0) switch (cmd) { case kCmdZero: for (i = 0; i < blockSize; i++) @@ -342,22 +348,34 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by buffer[curChannel][i] = gReader->getSRice(energy) + channelOffset; break; case kCmdDiff1: - gReader->getSRice(energy); // i = 0 (to fix invalid table/memory access) - for (i = 1; i < blockSize; i++) - buffer[curChannel][i] = gReader->getSRice(energy) + buffer[curChannel][i - 1]; + for (i = 0; i < blockSize; i++) { + if (i == 0) + buffer[curChannel][i] = gReader->getSRice(energy) + oldValues[curChannel][0]; + else + buffer[curChannel][i] = gReader->getSRice(energy) + buffer[curChannel][i - 1]; + } break; case kCmdDiff2: - gReader->getSRice(energy); // i = 0 (to fix invalid table/memory access) - gReader->getSRice(energy); // i = 1 (to fix invalid table/memory access) - for (i = 2; i < blockSize; i++) - buffer[curChannel][i] = gReader->getSRice(energy) + 2 * buffer[curChannel][i - 1] - buffer[curChannel][i - 2]; + for (i = 0; i < blockSize; i++) { + if (i == 0) + buffer[curChannel][i] = gReader->getSRice(energy) + 2 * oldValues[curChannel][0] - oldValues[curChannel][1]; + else if (i == 1) + buffer[curChannel][i] = gReader->getSRice(energy) + 2 * buffer[curChannel][0] - oldValues[curChannel][0]; + else + buffer[curChannel][i] = gReader->getSRice(energy) + 2 * buffer[curChannel][i - 1] - buffer[curChannel][i - 2]; + } break; case kCmdDiff3: - gReader->getSRice(energy); // i = 0 (to fix invalid table/memory access) - gReader->getSRice(energy); // i = 1 (to fix invalid table/memory access) - gReader->getSRice(energy); // i = 2 (to fix invalid table/memory access) - for (i = 3; i < blockSize; i++) - buffer[curChannel][i] = gReader->getSRice(energy) + 3 * (buffer[curChannel][i - 1] - buffer[curChannel][i - 2]) + buffer[curChannel][i - 3]; + for (i = 0; i < blockSize; i++) { + if (i == 0) + buffer[curChannel][i] = gReader->getSRice(energy) + 3 * (oldValues[curChannel][0] - oldValues[curChannel][1]) + oldValues[curChannel][2]; + else if (i == 1) + buffer[curChannel][i] = gReader->getSRice(energy) + 3 * (buffer[curChannel][0] - oldValues[curChannel][0]) + oldValues[curChannel][1]; + else if (i == 2) + buffer[curChannel][i] = gReader->getSRice(energy) + 3 * (buffer[curChannel][1] - buffer[curChannel][0]) + oldValues[curChannel][0]; + else + buffer[curChannel][i] = gReader->getSRice(energy) + 3 * (buffer[curChannel][i - 1] - buffer[curChannel][i - 2]) + buffer[curChannel][i - 3]; + } break; case kCmdQLPC: lpcNum = gReader->getURice(2); @@ -417,10 +435,12 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by // Do the wrap - // FIXME: removed for now, as this corrupts the heap, because it - // accesses negative array indices - //for (int32 k = -wrap; k < 0; k++) - // buffer[curChannel][k] = buffer[curChannel][k + blockSize]; + for (i = 0; i < 64; ++i) + oldValues[curChannel][i] = 0; + + int arrayTerminator = MIN<int>(64, blockSize); + for (i = 0; i < arrayTerminator; ++i) + oldValues[curChannel][i] = buffer[curChannel][blockSize - (i + 1)]; // Fix bitshift if (bitShift > 0) { @@ -495,6 +515,7 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by for (i = 0; i < channels; i++) { free(buffer[i]); free(offset[i]); + free(oldValues[i]); } if (maxLPC > 0) @@ -516,6 +537,7 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by for (i = 0; i < channels; i++) { free(buffer[i]); free(offset[i]); + free(oldValues[i]); } if (maxLPC > 0) diff --git a/engines/saga/sndres.h b/engines/saga/sndres.h index 554eed4a27..5115873d76 100644 --- a/engines/saga/sndres.h +++ b/engines/saga/sndres.h @@ -45,6 +45,7 @@ public: void playVoice(uint32 resourceId); int getVoiceLength(uint32 resourceId); void setVoiceBank(int serial); + int getVoiceBank() { return _voiceSerial; } Common::Array<FxTable> _fxTable; diff --git a/engines/savestate.h b/engines/savestate.h index 970e01485d..54eff0f8cb 100644 --- a/engines/savestate.h +++ b/engines/savestate.h @@ -140,7 +140,7 @@ public: * Sets the time the game was played before the save state was created. * * @param hours How many hours the user played the game so far. - * @param min How many minutes the user played the game so far. + * @param minutes How many minutes the user played the game so far. */ void setPlayTime(int hours, int minutes); diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 344298ce9a..91b3c45c6e 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -2607,6 +2607,25 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Phantasmagoria - French DOS + // Supplied by Kervala in bug #6574 + {"phantasmagoria", "", { + {"resmap.001", 0, "4da82dd336d4b9cd8c16f3cc11f0c615", 11524}, + {"ressci.001", 0, "3aae6559aa1df273bc542d5ac6330d75", 69963685}, + {"resmap.002", 0, "4f40f43f2b60bf765864433069752bb9", 12064}, + {"ressci.002", 0, "3aae6559aa1df273bc542d5ac6330d75", 78362841}, + {"resmap.003", 0, "6a392a86f14b6ddb4422978ee71e54ac", 12340}, + {"ressci.003", 0, "3aae6559aa1df273bc542d5ac6330d75", 80431189}, + {"resmap.004", 0, "df2e9462c41202de5f3843908c95a715", 12562}, + {"ressci.004", 0, "3aae6559aa1df273bc542d5ac6330d75", 82542844}, + {"resmap.005", 0, "43efd3fe834286c70a2c8b4cd747c1e2", 12616}, + {"ressci.005", 0, "3aae6559aa1df273bc542d5ac6330d75", 83790486}, + {"resmap.006", 0, "b3065e54a00190752a06dacd201b5058", 12538}, + {"ressci.006", 0, "3aae6559aa1df273bc542d5ac6330d75", 85415107}, + {"resmap.007", 0, "5633960bc106c39ca91d2d8fce18fd2d", 7984}, + AD_LISTEND}, + Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // Phantasmagoria - English DOS Demo // Executable scanning reports "2.100.002" {"phantasmagoria", "Demo", { diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index 31e7ca4931..be062dba64 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -344,9 +344,9 @@ bool GameFeatures::autoDetectGfxFunctionsType(int methodNum) { if (kFuncNum == 8) { // kDrawPic (SCI0 - SCI11) // If kDrawPic is called with 6 parameters from the overlay // selector, the game is using old graphics functions. - // Otherwise, if it's called with 8 parameters, it's using new - // graphics functions. - _gfxFunctionsType = (argc == 8) ? SCI_VERSION_0_LATE : SCI_VERSION_0_EARLY; + // Otherwise, if it's called with 8 parameters (e.g. SQ3) or 4 parameters + // (e.g. Hoyle 1/2), it's using new graphics functions. + _gfxFunctionsType = (argc == 6) ? SCI_VERSION_0_EARLY : SCI_VERSION_0_LATE; return true; } } diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index fc46d16b8d..0c2fd4e3ea 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -468,7 +468,8 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(TimesSin), SIG_EVERYWHERE, "ii", NULL, NULL }, { "SinMult", kTimesSin, SIG_EVERYWHERE, "ii", NULL, NULL }, { MAP_CALL(TimesTan), SIG_EVERYWHERE, "ii", NULL, NULL }, - { MAP_CALL(UnLoad), SIG_EVERYWHERE, "i[ri]", NULL, kUnLoad_workarounds }, + { MAP_CALL(UnLoad), SIG_EVERYWHERE, "i[ir!]", NULL, kUnLoad_workarounds }, + // ^ We allow invalid references here (e.g. bug #6600), since they will be invalidated anyway by the call itself { MAP_CALL(ValidPath), SIG_EVERYWHERE, "r", NULL, NULL }, { MAP_CALL(Wait), SIG_EVERYWHERE, "i", NULL, NULL }, diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 3738fd3dcb..58c2b8d3e3 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -371,7 +371,7 @@ void SegManager::freeHunkEntry(reg_t addr) { HunkTable *ht = (HunkTable *)getSegment(addr.getSegment(), SEG_TYPE_HUNK); if (!ht) { - warning("Attempt to free Hunk from address %04x:%04x: Invalid segment type", PRINT_REG(addr)); + warning("Attempt to free Hunk from address %04x:%04x: Invalid segment type %d", PRINT_REG(addr), getSegmentType(addr.getSegment())); return; } diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 37e46b7a96..ea4dc2fe71 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -44,7 +44,8 @@ const SciWorkaroundEntry arithmeticWorkarounds[] = { { GID_MOTHERGOOSEHIRES,90, 90, 0, "newGameButton", "select", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_ge: MUMG Deluxe, when selecting "New Game" in the main menu. It tries to compare an integer with a list. Needs to return false for the game to continue. { GID_PHANTASMAGORIA, 902, 0, 0, "", "export 7", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_shr: when starting a chapter in Phantasmagoria { GID_QFG1VGA, 301, 928, 0, "Blink", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_div: when entering the inn, gets called with 1 parameter, but 2nd parameter is used for div which happens to be an object - { GID_QFG2, 200, 200, 0, "astro", "messages", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_lsi: when getting asked for your name by the astrologer bug #5152 + { GID_QFG2, 200, 200, 0, "astro", "messages", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_lsi: when getting asked for your name by the astrologer - bug #5152 + { GID_QFG3, 780, 999, 0, "", "export 6", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_add: trying to talk to yourself at the top of the giant tree - bug #6692 { GID_QFG4, 710,64941, 0, "RandCycle", "doit", -1, 0, { WORKAROUND_FAKE, 1 } }, // op_gt: when the tentacle appears in the third room of the caves SCI_WORKAROUNDENTRY_TERMINATOR }; diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index a322eb8e61..91b5b25e99 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -782,9 +782,13 @@ void GfxFrameout::kernelFrameout() { // TODO: For some reason, the top left nsRect coordinates get // swapped in the GK1 inventory screen, investigate why. + // This is also needed for GK1 rooms 710 and 720 (catacombs, inner and + // outer circle), for handling the tiles and talking to Wolfgang. // HACK: Fix the coordinates by explicitly setting them here. Common::Rect objNSRect = g_sci->_gfxCompare->getNSRect(itemEntry->object); - if (objNSRect.top == nsRect.left && objNSRect.left == nsRect.top && nsRect.top != 0 && nsRect.left != 0) { + uint16 roomNumber = g_sci->getEngineState()->currentRoomNumber(); + if (objNSRect.top == nsRect.left && objNSRect.left == nsRect.top && nsRect.top != 0 && nsRect.left != 0 || + (g_sci->getGameId() == GID_GK1 && (roomNumber == 710 || roomNumber == 720))) { g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); } } diff --git a/engines/sci/parser/said.cpp b/engines/sci/parser/said.cpp index 693bbec744..27ebc58704 100644 --- a/engines/sci/parser/said.cpp +++ b/engines/sci/parser/said.cpp @@ -186,8 +186,7 @@ static bool parseList(ParseTreeNode* parentNode); static bool parseListEntry(ParseTreeNode* parentNode); static bool parseWord(ParseTreeNode* parentNode); -static bool parseWord(ParseTreeNode* parentNode) -{ +static bool parseWord(ParseTreeNode* parentNode) { int token = said_tokens[said_token]; if (token & 0x8000) return false; @@ -201,8 +200,7 @@ static bool parseWord(ParseTreeNode* parentNode) return true; } -static bool parsePart2(ParseTreeNode* parentNode, bool& nonempty) -{ +static bool parsePart2(ParseTreeNode* parentNode, bool& nonempty) { // Store current state for rolling back if we fail int curToken = said_token; int curTreePos = said_tree_pos; @@ -259,8 +257,7 @@ static bool parsePart2(ParseTreeNode* parentNode, bool& nonempty) return false; } -static bool parsePart3(ParseTreeNode* parentNode, bool& nonempty) -{ +static bool parsePart3(ParseTreeNode* parentNode, bool& nonempty) { // Store current state for rolling back if we fail int curToken = said_token; int curTreePos = said_tree_pos; @@ -318,8 +315,7 @@ static bool parsePart3(ParseTreeNode* parentNode, bool& nonempty) } -static bool parseSlash(ParseTreeNode* parentNode) -{ +static bool parseSlash(ParseTreeNode* parentNode) { // Store current state for rolling back if we fail int curToken = said_token; int curTreePos = said_tree_pos; @@ -343,8 +339,7 @@ static bool parseSlash(ParseTreeNode* parentNode) } -static bool parseRef(ParseTreeNode* parentNode) -{ +static bool parseRef(ParseTreeNode* parentNode) { // Store current state for rolling back if we fail int curToken = said_token; int curTreePos = said_tree_pos; @@ -411,8 +406,7 @@ static bool parseRef(ParseTreeNode* parentNode) return false; } -static bool parseComma(ParseTreeNode* parentNode) -{ +static bool parseComma(ParseTreeNode* parentNode) { // Store current state for rolling back if we fail int curToken = said_token; int curTreePos = said_tree_pos; @@ -435,8 +429,7 @@ static bool parseComma(ParseTreeNode* parentNode) return false; } -static bool parseListEntry(ParseTreeNode* parentNode) -{ +static bool parseListEntry(ParseTreeNode* parentNode) { // Store current state for rolling back if we fail int curToken = said_token; int curTreePos = said_tree_pos; @@ -494,8 +487,7 @@ static bool parseListEntry(ParseTreeNode* parentNode) return false; } -static bool parseList(ParseTreeNode* parentNode) -{ +static bool parseList(ParseTreeNode* parentNode) { // Store current state for rolling back if we fail int curToken = said_token; int curTreePos = said_tree_pos; @@ -524,8 +516,7 @@ static bool parseList(ParseTreeNode* parentNode) return false; } -static bool parseExpr(ParseTreeNode* parentNode) -{ +static bool parseExpr(ParseTreeNode* parentNode) { // Store current state for rolling back if we fail int curToken = said_token; int curTreePos = said_tree_pos; @@ -546,7 +537,6 @@ static bool parseExpr(ParseTreeNode* parentNode) said_attach_subtree(newParent, 0x141, 0x14F, newNode); newParent = newParent->right; - } found = parseRef(newParent); @@ -561,8 +551,7 @@ static bool parseExpr(ParseTreeNode* parentNode) return false; } -static bool parseSpec(ParseTreeNode* parentNode) -{ +static bool parseSpec(ParseTreeNode* parentNode) { // Store current state for rolling back if we fail int curToken = said_token; int curTreePos = said_tree_pos; @@ -748,9 +737,7 @@ static void node_print_desc(ParseTreeNode *) { } - -static int matchTrees(ParseTreeNode* parseT, ParseTreeNode* saidT) -{ +static int matchTrees(ParseTreeNode* parseT, ParseTreeNode* saidT) { outputDepth++; scidprintf("%*smatchTrees on ", outputDepth, ""); node_print_desc(parseT); diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp index b4a223dcff..3344b79e26 100644 --- a/engines/sci/parser/vocabulary.cpp +++ b/engines/sci/parser/vocabulary.cpp @@ -530,18 +530,19 @@ bool Vocabulary::tokenizeString(ResultWordListList &retval, const char *sentence *error = NULL; do { - c = sentence[pos_in_sentence++]; + if (Common::isAlnum(c) || (c == '-' && wordLen) || (c >= 0x80)) { currentWord[wordLen] = lowerCaseMap[c]; ++wordLen; - } - // Continue on this word */ - // Words may contain a '-', but may not - // start with one. - else { - if (wordLen) { // Finished a word? + } else if (c == '\'' && wordLen && (sentence[pos_in_sentence] == 's' || sentence[pos_in_sentence] == 'S')) { + // Skip apostrophe-s at the end of the word, if it exists + pos_in_sentence++; // skip the 's' + } else { + // Continue on this word. Words may contain a '-', but may not start with + // one. + if (wordLen) { // Finished a word? ResultWordList lookup_result; // Look it up diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp index 31c9d90de8..80a72b9a6f 100644 --- a/engines/sci/sound/drivers/midi.cpp +++ b/engines/sci/sound/drivers/midi.cpp @@ -398,8 +398,7 @@ void MidiPlayer_Midi::playSwitch(bool play) { } } -bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size) -{ +bool MidiPlayer_Midi::isMt32GmPatch(const byte *data, int size) { if (size < 1155) return false; if (size > 16889) @@ -957,7 +956,7 @@ int MidiPlayer_Midi::open(ResourceManager *resMan) { if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY) warning("The automatic mapping for General MIDI hasn't been worked on for " "SCI1 games. Music might sound wrong or broken. Please choose another " - "music driver for this game (e.g. Adlib or MT-32) if you are " + "music driver for this game (e.g. AdLib or MT-32) if you are " "experiencing issues with music"); // Modify velocity map to make low velocity notes a little louder diff --git a/engines/scumm/cdda.cpp b/engines/scumm/cdda.cpp new file mode 100644 index 0000000000..adb414ecce --- /dev/null +++ b/engines/scumm/cdda.cpp @@ -0,0 +1,120 @@ +/* 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 "scumm/cdda.h" +#include "common/stream.h" +#include "audio/audiostream.h" + +namespace Scumm { + + +#pragma mark - +#pragma mark --- CDDA stream --- +#pragma mark - + +#define START_OF_CDDA_DATA 800 +#define BLOCK_SIZE 1177 + +class CDDAStream : public Audio::SeekableAudioStream { +private: + Common::SeekableReadStream *_stream; + DisposeAfterUse::Flag _disposeAfterUse; + byte _shiftLeft; + byte _shiftRight; + uint32 _pos; + Audio::Timestamp _length; + +public: + CDDAStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse); + virtual ~CDDAStream(); + + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return true; } + int getRate() const { return 44100; } + bool endOfData() const { return _stream->eos(); } + bool seek(const Audio::Timestamp &where); + Audio::Timestamp getLength() const { return _length; } +}; + +CDDAStream::CDDAStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) : + _stream(stream), _disposeAfterUse(disposeAfterUse), _pos(START_OF_CDDA_DATA) { + _stream->seek(START_OF_CDDA_DATA, SEEK_SET); + // The total size of CDDA.SOU is 289,808,802 bytes or (289808802 - 800) / 1177 = 246226 blocks + // We also deduct the shift values to return the correct length + uint32 blocks = (_stream->size() - START_OF_CDDA_DATA) / BLOCK_SIZE; + _length = Audio::Timestamp(0, (_stream->size() - START_OF_CDDA_DATA - blocks) / (isStereo() ? 2 : 1), getRate()); +} + +CDDAStream::~CDDAStream() { + if (_disposeAfterUse == DisposeAfterUse::YES) + delete _stream; +} + +bool CDDAStream::seek(const Audio::Timestamp &where) { + const uint32 seekSample = convertTimeToStreamPos(where, getRate(), isStereo()).totalNumberOfFrames(); + uint32 blocks = seekSample / 1176; + + // Before seeking, read the shift values from the beginning of that block + _stream->seek(START_OF_CDDA_DATA + blocks * BLOCK_SIZE, SEEK_SET); + byte shiftVal = _stream->readByte(); + _shiftLeft = shiftVal >> 4; + _shiftRight = shiftVal & 0x0F; + + _pos = START_OF_CDDA_DATA + blocks + seekSample; + return _stream->seek(_pos, SEEK_SET); +} + +int CDDAStream::readBuffer(int16 *buffer, const int numSamples) { + int samples; + + for (samples = 0 ; samples < numSamples && !_stream->eos() ; ) { + if (!((_pos - START_OF_CDDA_DATA) % BLOCK_SIZE)) { + byte shiftVal = _stream->readByte(); + _shiftLeft = shiftVal >> 4; + _shiftRight = shiftVal & 0x0F; + _pos++; + } + buffer[samples++] = _stream->readSByte() << _shiftLeft; + buffer[samples++] = _stream->readSByte() << _shiftRight; + _pos += 2; + } + return samples; +} + +#pragma mark - +#pragma mark --- CDDA factory functions --- +#pragma mark - + +Audio::SeekableAudioStream *makeCDDAStream( + Common::SeekableReadStream *stream, + DisposeAfterUse::Flag disposeAfterUse) { + Audio::SeekableAudioStream *s = new CDDAStream(stream, disposeAfterUse); + if (s && s->endOfData()) { + delete s; + return 0; + } else { + return s; + } + return 0; +} + +} // End of namespace Scumm diff --git a/engines/scumm/cdda.h b/engines/scumm/cdda.h new file mode 100644 index 0000000000..c1e6e82c9e --- /dev/null +++ b/engines/scumm/cdda.h @@ -0,0 +1,57 @@ +/* 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. + * + */ + +/** + * @file + * CD audio decoder used in the Steam versions of Loom + */ + +#ifndef SCUMM_CDDA_H +#define SCUMM_CDDA_H + +#include "common/types.h" + +namespace Common { +class SeekableReadStream; +} + +namespace Audio { +class SeekableAudioStream; +} + +namespace Scumm { + +/** + * Create a new SeekableAudioStream from the CDDA data in the given stream. + * Allows for seeking (which is why we require a SeekableReadStream). + * + * @param stream The SeekableReadStream from which to read the CDDA data + * @param disposeAfterUse Whether to delete the stream after use + * @return a new SeekableAudioStream, or NULL, if an error occurred + */ +Audio::SeekableAudioStream *makeCDDAStream( + Common::SeekableReadStream *stream, + DisposeAfterUse::Flag disposeAfterUse); + +} // End of namespace Audio + +#endif // #ifndef SCUMM_CDDA_H diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index 185ebbce6e..e546c805b5 100644 --- a/engines/scumm/charset.cpp +++ b/engines/scumm/charset.cpp @@ -253,7 +253,7 @@ CharsetRenderer::~CharsetRenderer() { CharsetRendererCommon::CharsetRendererCommon(ScummEngine *vm) : CharsetRenderer(vm), _bytesPerPixel(0), _fontHeight(0), _numChars(0) { - _shadowMode = false; + _enableShadow = false; _shadowColor = 0; } @@ -392,6 +392,10 @@ int CharsetRenderer::getStringWidth(int arg, const byte *text) { } else if (chr & 0x80) { pos++; width += _vm->_2byteWidth; + // Original keeps glyph width and character dimensions separately + if (_vm->_language == Common::KO_KOR || _vm->_language == Common::ZH_TWN) { + width++; + } continue; } } @@ -478,6 +482,12 @@ void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) { } else if (chr & 0x80) { pos++; curw += _vm->_2byteWidth; + // Original keeps glyph width and character dimensions separately + if (_vm->_language == Common::KO_KOR || _vm->_language == Common::ZH_TWN) { + curw++; + } + } else { + curw += getCharWidth(chr); } } else { curw += getCharWidth(chr); @@ -507,12 +517,17 @@ int CharsetRendererV3::getCharWidth(uint16 chr) { return spacing; } -void CharsetRendererV3::enableShadow(bool enable) { +void CharsetRendererPC::enableShadow(bool enable) { _shadowColor = 0; - _shadowMode = enable; + _enableShadow = enable; + + if (_vm->_game.version >= 7 && _vm->_language == Common::KO_KOR) + _shadowType = kHorizontalShadowType; + else + _shadowType = kNormalShadowType; } -void CharsetRendererV3::drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height) { +void CharsetRendererPC::drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height) { byte *dst = (byte *)dest.getBasePtr(x, y); byte bits = 0; @@ -525,8 +540,12 @@ void CharsetRendererV3::drawBits1(Graphics::Surface &dest, int x, int y, const b if ((x % 8) == 0) bits = *src++; if ((bits & revBitMask(x % 8)) && y + drawTop >= 0) { - if (_shadowMode) - dst[1] = dst2[0] = dst2[1] = _shadowColor; + if (_enableShadow) { + if (_shadowType == kNormalShadowType) + dst[1] = dst2[0] = dst2[1] = _shadowColor; + else if (_shadowType == kHorizontalShadowType) + dst[1] = _shadowColor; + } dst[0] = col; } dst += dest.format.bytesPerPixel; @@ -615,7 +634,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) { if (_left + origWidth > _right + 1) return; - if (_shadowMode) { + if (_enableShadow) { width++; height++; } @@ -658,7 +677,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) { if (_str.right < _left) { _str.right = _left; - if (_shadowMode) + if (_enableShadow) _str.right++; } @@ -776,11 +795,15 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) { printCharIntern(is2byte, _charPtr, _origWidth, _origHeight, _width, _height, vs, ignoreCharsetMask); + // Original keeps glyph width and character dimensions separately + if ((_vm->_language == Common::ZH_TWN || _vm->_language == Common::KO_KOR) && is2byte) + _origWidth++; + _left += _origWidth; if (_str.right < _left) { _str.right = _left; - if (_vm->_game.platform != Common::kPlatformFMTowns && _shadowMode) + if (_vm->_game.platform != Common::kPlatformFMTowns && _enableShadow) _str.right++; } @@ -844,7 +867,10 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr, drawTop = _top - _vm->_screenTop; } - drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight); + if (is2byte && _vm->_game.platform != Common::kPlatformFMTowns) + drawBits1(dstSurface, _left, drawTop, charPtr, drawTop, origWidth, origHeight); + else + drawBitsN(dstSurface, dstPtr, charPtr, *_fontPtr, drawTop, origWidth, origHeight); if (_blitAlso && vs->hasTwoBuffers) { // FIXME: Revisiting this code, I think the _blitAlso mode is likely broken @@ -884,6 +910,24 @@ void CharsetRendererClassic::printCharIntern(bool is2byte, const byte *charPtr, } bool CharsetRendererClassic::prepareDraw(uint16 chr) { + bool is2byte = (chr >= 256 && _vm->_useCJKMode); + if (is2byte) { + if (_vm->_language == Common::KO_KOR) + enableShadow(true); + + _charPtr = _vm->get2byteCharPtr(chr); + _width = _origWidth = _vm->_2byteWidth; + _height = _origHeight = _vm->_2byteHeight; + _offsX = _offsY = 0; + + if (_enableShadow) { + _width++; + _height++; + } + + return true; + } + uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4); assert(charOffs < 0x14000); if (!charOffs) @@ -908,8 +952,14 @@ bool CharsetRendererClassic::prepareDraw(uint16 chr) { void CharsetRendererClassic::drawChar(int chr, Graphics::Surface &s, int x, int y) { if (!prepareDraw(chr)) return; + byte *dst = (byte *)s.getBasePtr(x, y); - drawBitsN(s, dst, _charPtr, *_fontPtr, y, _width, _height); + + bool is2byte = (_vm->_useCJKMode && chr >= 256); + if (is2byte) + drawBits1(s, x, y, _charPtr, y, _width, _height); + else + drawBitsN(s, dst, _charPtr, *_fontPtr, y, _width, _height); } void CharsetRendererClassic::drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height) { @@ -982,7 +1032,7 @@ int CharsetRendererTownsV3::getFontHeight() { void CharsetRendererTownsV3::enableShadow(bool enable) { _shadowColor = 8; - _shadowMode = enable; + _enableShadow = enable; #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE _shadowColor = 0x88; @@ -1027,13 +1077,13 @@ void CharsetRendererTownsV3::drawBits1(Graphics::Surface &dest, int x, int y, co bits = *src++; if ((bits & revBitMask(x % 8)) && y + drawTop >= 0) { if (dest.format.bytesPerPixel == 2) { - if (_shadowMode) { + if (_enableShadow) { WRITE_UINT16(dst + 2, _vm->_16BitPalette[_shadowColor]); WRITE_UINT16(dst + dest.pitch, _vm->_16BitPalette[_shadowColor]); } WRITE_UINT16(dst, _vm->_16BitPalette[_color]); } else { - if (_shadowMode) { + if (_enableShadow) { #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE if (scale2x) { dst[2] = dst[3] = dst2[2] = dst2[3] = _shadowColor; @@ -1124,11 +1174,11 @@ void CharsetRendererPCE::drawBits1(Graphics::Surface &dest, int x, int y, const bits = *src++; if ((bits & revBitMask(bitCount % 8)) && y + drawTop >= 0) { if (dest.format.bytesPerPixel == 2) { - if (_shadowMode) + if (_enableShadow) WRITE_UINT16(dst + dest.pitch + 2, _vm->_16BitPalette[_shadowColor]); WRITE_UINT16(dst, _vm->_16BitPalette[_color]); } else { - if (_shadowMode) + if (_enableShadow) *(dst + dest.pitch + 1) = _shadowColor; *dst = _color; } @@ -1227,7 +1277,8 @@ void CharsetRendererNut::printChar(int chr, bool ignoreCharsetMask) { int width = _current->getCharWidth(chr); int height = _current->getCharHeight(chr); - if (chr >= 256 && _vm->_useCJKMode) + bool is2byte = chr >= 256 && _vm->_useCJKMode; + if (is2byte) width = _vm->_2byteWidth; shadow.right = _left + width; @@ -1259,8 +1310,8 @@ void CharsetRendererNut::printChar(int chr, bool ignoreCharsetMask) { _str.left = _left; // Original keeps glyph width and character dimensions separately - if (_vm->_language == Common::ZH_TWN && width == 16) - width = 17; + if ((_vm->_language == Common::ZH_TWN || _vm->_language == Common::KO_KOR) && is2byte) + width++; _left += width; @@ -1327,7 +1378,7 @@ void CharsetRendererNES::printChar(int chr, bool ignoreCharsetMask) { if (_str.right < _left) { _str.right = _left; - if (_shadowMode) + if (_enableShadow) _str.right++; } @@ -1483,7 +1534,7 @@ bool CharsetRendererTownsClassic::prepareDraw(uint16 chr) { _origHeight = _height = _vm->_2byteHeight; _charPtr = _vm->get2byteCharPtr(chr); _offsX = _offsY = 0; - if (_shadowMode) { + if (_enableShadow) { _width++; _height++; } @@ -1495,7 +1546,7 @@ bool CharsetRendererTownsClassic::prepareDraw(uint16 chr) { } void CharsetRendererTownsClassic::setupShadowMode() { - _shadowMode = true; + _enableShadow = true; _shadowColor = _vm->_townsCharsetColorMap[0]; assert(_vm->_cjkFont); diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h index 5a9977b7d6..b4b3d88ccd 100644 --- a/engines/scumm/charset.h +++ b/engines/scumm/charset.h @@ -100,7 +100,7 @@ protected: int _numChars; byte _shadowColor; - bool _shadowMode; + bool _enableShadow; public: CharsetRendererCommon(ScummEngine *vm); @@ -110,7 +110,24 @@ public: virtual int getFontHeight(); }; -class CharsetRendererClassic : public CharsetRendererCommon { +class CharsetRendererPC : public CharsetRendererCommon { + enum ShadowType { + kNoShadowType, + kNormalShadowType, + kHorizontalShadowType + }; + + ShadowType _shadowType; + +protected: + virtual void enableShadow(bool enable); + virtual void drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height); + +public: + CharsetRendererPC(ScummEngine *vm) : CharsetRendererCommon(vm), _shadowType(kNoShadowType) { } +}; + +class CharsetRendererClassic : public CharsetRendererPC { protected: virtual void drawBitsN(const Graphics::Surface &s, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height); void printCharIntern(bool is2byte, const byte *charPtr, int origWidth, int origHeight, int width, int height, VirtScreen *vs, bool ignoreCharsetMask); @@ -124,7 +141,7 @@ protected: VirtScreenNumber _drawScreen; public: - CharsetRendererClassic(ScummEngine *vm) : CharsetRendererCommon(vm) {} + CharsetRendererClassic(ScummEngine *vm) : CharsetRendererPC(vm) {} void printChar(int chr, bool ignoreCharsetMask); void drawChar(int chr, Graphics::Surface &s, int x, int y); @@ -170,10 +187,8 @@ public: int getCharWidth(uint16 chr) { return 8; } }; -class CharsetRendererV3 : public CharsetRendererCommon { +class CharsetRendererV3 : public CharsetRendererPC { protected: - virtual void enableShadow(bool enable); - virtual void drawBits1(Graphics::Surface &dest, int x, int y, const byte *src, int drawTop, int width, int height); virtual int getDrawWidthIntern(uint16 chr); virtual int getDrawHeightIntern(uint16 chr); virtual void setDrawCharIntern(uint16 chr) {} @@ -181,7 +196,7 @@ protected: const byte *_widthTable; public: - CharsetRendererV3(ScummEngine *vm) : CharsetRendererCommon(vm) {} + CharsetRendererV3(ScummEngine *vm) : CharsetRendererPC(vm) {} void printChar(int chr, bool ignoreCharsetMask); void drawChar(int chr, Graphics::Surface &s, int x, int y); diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index b7a25808a5..7cd50e1f4c 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -79,10 +79,12 @@ Common::String ScummEngine::generateFilename(const int room) const { } else { switch (_filenamePattern.genMethod) { case kGenDiskNum: + case kGenDiskNumSteam: result = Common::String::format(_filenamePattern.pattern, diskNumber); break; case kGenRoomNum: + case kGenRoomNumSteam: result = Common::String::format(_filenamePattern.pattern, room); break; @@ -209,7 +211,32 @@ Common::String ScummEngine_v70he::generateFilename(const int room) const { return result; } -static Common::String generateFilenameForDetection(const char *pattern, FilenameGenMethod genMethod) { +// The following table includes all the index files, which are embedded in the +// main game executables in Steam versions. +static const SteamIndexFile steamIndexFiles[] = { + { GID_INDY3, Common::kPlatformWindows, "%02d.LFL", "00.LFL", "Indiana Jones and the Last Crusade.exe", 162056, 6295 }, + { GID_INDY3, Common::kPlatformMacintosh, "%02d.LFL", "00.LFL", "The Last Crusade", 150368, 6295 }, + { GID_INDY4, Common::kPlatformWindows, "atlantis.%03d", "ATLANTIS.000", "Indiana Jones and the Fate of Atlantis.exe", 224336, 12035 }, + { GID_INDY4, Common::kPlatformMacintosh, "atlantis.%03d", "ATLANTIS.000", "The Fate of Atlantis", 260224, 12035 }, + { GID_LOOM, Common::kPlatformWindows, "%03d.LFL", "000.LFL", "Loom.exe", 187248, 8307 }, + { GID_LOOM, Common::kPlatformMacintosh, "%03d.LFL", "000.LFL", "Loom", 170464, 8307 }, +#ifdef ENABLE_SCUMM_7_8 + { GID_DIG, Common::kPlatformWindows, "dig.la%d", "DIG.LA0", "The Dig.exe", 340632, 16304 }, + { GID_DIG, Common::kPlatformMacintosh, "dig.la%d", "DIG.LA0", "The Dig", 339744, 16304 }, +#endif + { 0, Common::kPlatformUnknown, nullptr, nullptr, nullptr, 0, 0 } +}; + +const SteamIndexFile *lookUpSteamIndexFile(Common::String pattern, Common::Platform platform) { + for (const SteamIndexFile *indexFile = steamIndexFiles; indexFile->len; ++indexFile) { + if (platform == indexFile->platform && pattern.equalsIgnoreCase(indexFile->pattern)) + return indexFile; + } + + return nullptr; +} + +static Common::String generateFilenameForDetection(const char *pattern, FilenameGenMethod genMethod, Common::Platform platform) { Common::String result; switch (genMethod) { @@ -217,6 +244,16 @@ static Common::String generateFilenameForDetection(const char *pattern, Filename case kGenRoomNum: result = Common::String::format(pattern, 0); break; + + case kGenDiskNumSteam: + case kGenRoomNumSteam: { + const SteamIndexFile *indexFile = lookUpSteamIndexFile(pattern, platform); + if (!indexFile) { + error("Unable to find Steam executable from detection pattern"); + } else { + result = indexFile->executableName; + } + } break; case kGenHEPC: case kGenHEIOS: @@ -528,7 +565,8 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul DetectorResult dr; // Dive one level down since mac indy3/loom has its files split into directories. See Bug #1438631 - composeFileHashMap(fileMD5Map, fslist, 2, directoryGlobs); + // Dive two levels down for Mac Steam games + composeFileHashMap(fileMD5Map, fslist, 3, directoryGlobs); // Iterate over all filename patterns. for (const GameFilenamePattern *gfp = gameFilenamesTable; gfp->gameid; ++gfp) { @@ -540,7 +578,7 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul // Generate the detectname corresponding to the gfp. If the file doesn't // exist in the directory we are looking at, we can skip to the next // one immediately. - Common::String file(generateFilenameForDetection(gfp->pattern, gfp->genMethod)); + Common::String file(generateFilenameForDetection(gfp->pattern, gfp->genMethod, gfp->platform)); if (!fileMD5Map.contains(file)) continue; @@ -1025,7 +1063,7 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co Common::FSNode dir(ConfMan.get("path")); if (!dir.isDirectory()) return Common::kPathNotDirectory; - if (!dir.getChildren(fslist, Common::FSNode::kListFilesOnly)) + if (!dir.getChildren(fslist, Common::FSNode::kListAll)) return Common::kNoGameDataFoundError; // Invoke the detector, but fixed to the specified gameid. @@ -1081,7 +1119,7 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co md5Warning += Common::String::format(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n", res.game.gameid, - generateFilenameForDetection(res.fp.pattern, res.fp.genMethod).c_str(), + generateFilenameForDetection(res.fp.pattern, res.fp.genMethod, Common::kPlatformUnknown).c_str(), res.md5.c_str()); g_system->logMessage(LogMessageType::kWarning, md5Warning.c_str()); diff --git a/engines/scumm/detection.h b/engines/scumm/detection.h index f714812a9c..0587c3fab1 100644 --- a/engines/scumm/detection.h +++ b/engines/scumm/detection.h @@ -95,7 +95,9 @@ struct GameSettings { enum FilenameGenMethod { kGenDiskNum, + kGenDiskNumSteam, kGenRoomNum, + kGenRoomNumSteam, kGenHEMac, kGenHEMacNoParens, kGenHEPC, diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index c876af1256..ae334c201c 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -52,6 +52,8 @@ namespace Scumm { */ static const char *const directoryGlobs[] = { "rooms *", // Mac version of indy3/loom + "Contents", // Mac Steam versions + "MacOS", // Mac Steam versions 0 }; @@ -221,6 +223,7 @@ static const GameSettings gameVariantsTable[] = { {"indy3", "EGA", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, 0, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, {"indy3", "No AdLib", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, {"indy3", "VGA", "vga", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, + {"indy3", "Steam", "steam", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, {"indy3", "FM-TOWNS", 0, GID_INDY3, 3, 0, MDT_TOWNS, GF_OLD256 | GF_FEW_LOCALS | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_NOASPECT)}, {"loom", "EGA", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_NOSPEECH)}, @@ -230,6 +233,7 @@ static const GameSettings gameVariantsTable[] = { #endif {"loom", "FM-TOWNS", 0, GID_LOOM, 3, 0, MDT_TOWNS, GF_AUDIOTRACKS | GF_OLD256, Common::kPlatformFMTowns, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_NOASPECT)}, {"loom", "VGA", "vga", GID_LOOM, 4, 0, MDT_NONE, GF_AUDIOTRACKS, Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, + {"loom", "Steam", "steam", GID_LOOM, 4, 0, MDT_NONE, GF_AUDIOTRACKS, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, {"pass", 0, 0, GID_PASS, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, GF_16COLOR, Common::kPlatformDOS, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)}, @@ -245,6 +249,7 @@ static const GameSettings gameVariantsTable[] = { {"monkey2", "FM-TOWNS", 0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_NOASPECT)}, {"atlantis", "", 0, GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()}, + {"atlantis", "Steam", "steam", GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()}, {"atlantis", "Floppy", 0, GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_NOSPEECH)}, {"atlantis", "FM-TOWNS", 0, GID_INDY4, 5, 0, MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO4(GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_NOASPECT)}, @@ -257,7 +262,8 @@ static const GameSettings gameVariantsTable[] = { #ifdef ENABLE_SCUMM_7_8 {"ft", 0, 0, GID_FT, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)}, - {"dig", 0, 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)}, + {"dig", "", 0, GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)}, + {"dig", "Steam", "steam", GID_DIG, 7, 0, MDT_NONE, 0, UNK, GUIO1(GUIO_NOMIDI)}, {"comi", 0, 0, GID_CMI, 8, 0, MDT_NONE, 0, Common::kPlatformWindows, GUIO2(GUIO_NOMIDI, GUIO_NOASPECT)}, #endif @@ -383,7 +389,7 @@ static const GameSettings gameVariantsTable[] = { {"freddicove", "HE 100", 0, GID_HEGAME, 6, 100, MDT_NONE, GF_USE_KEY | GF_HE_LOCALIZED | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, // Restructured the Scumm engine - {"pjgames", 0, 0, GID_HEGAME, 6, 100, MDT_NONE, GF_USE_KEY | GF_HE_LOCALIZED | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"pjgames", 0, 0, GID_PJGAMES, 6, 100, MDT_NONE, GF_USE_KEY | GF_HE_LOCALIZED | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, // Added the use of bink videos {"Soccer2004", 0, 0, GID_SOCCER2004, 6, 100, MDT_NONE, GF_USE_KEY | GF_16BIT_COLOR, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, @@ -422,10 +428,10 @@ static const GameSettings gameVariantsTable[] = { using Common::UNK_LANG; // The following describes how Fingolfin thinks this table might be used one day; -// this is work in progress, so read this with a salt of grain... +// this is work in progress, so read this with a grain of salt... // // The following table maps gameids to possible filename variants for that game. -// This information is used by the detector to determin possible "detect files". +// This information is used by the detector to determine possible "detect files". // It is also later used by the engine creation code to verify the game to be // launched is present. Finally, the correct GameFilenamePattern entry is passed on // to the engine which uses it to locate the files for the game. @@ -451,6 +457,8 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "zak", "zak1.d64", kGenUnchanged, UNK_LANG, Common::kPlatformC64, "V1" }, // ... and zak2.d64 { "indy3", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, + { "indy3", "%02d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" }, + { "indy3", "%02d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" }, { "indyloom", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, { "indyzak", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, @@ -458,6 +466,8 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "loom", "%02d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, { "loom", "%03d.LFL", kGenRoomNum, UNK_LANG, UNK, "VGA" }, // Loom CD + { "loom", "%03d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" }, + { "loom", "%03d.LFL", kGenRoomNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" }, { "pass", "%03d.LFL", kGenRoomNum, UNK_LANG, UNK, 0 }, @@ -471,6 +481,8 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "monkey2", "mi2demo.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, { "atlantis", "atlantis.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, + { "atlantis", "atlantis.%03d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" }, + { "atlantis", "atlantis.%03d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" }, { "atlantis", "fate.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, { "atlantis", "playfate.%03d", kGenDiskNum, UNK_LANG, UNK, 0 }, { "atlantis", "indy4.%03d", kGenDiskNum, Common::JA_JPN, Common::kPlatformFMTowns, "FM-TOWNS" }, @@ -494,6 +506,8 @@ static const GameFilenamePattern gameFilenamesTable[] = { #ifdef ENABLE_SCUMM_7_8 { "dig", "dig.la%d", kGenDiskNum, UNK_LANG, UNK, 0 }, + { "dig", "dig.la%d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformWindows, "Steam" }, + { "dig", "dig.la%d", kGenDiskNumSteam, UNK_LANG, Common::kPlatformMacintosh, "Steam" }, { "dig", "thedig.la%d", kGenDiskNum, UNK_LANG, UNK, "Demo" }, // Used by an alternate version of the demo { "dig", "The Dig Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "dig", "The Dig Demo Data", kGenUnchanged, UNK_LANG, Common::kPlatformMacintosh, "Demo" }, diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 8321daa583..52120949cc 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -428,7 +428,9 @@ const Common::String InfoDialog::queryResString(int stringno) { if (stringno == 0) return String(); - if (_vm->_game.version == 8) + if (_vm->_game.heversion >= 80) + return _(string_map_table_v6[stringno - 1].string); + else if (_vm->_game.version == 8) result = (const byte *)string_map_table_v8[stringno - 1].string; else if (_vm->_game.version == 7) result = _vm->getStringAddressVar(string_map_table_v7[stringno - 1].num); diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp index 9c161ff1cc..475ffa3238 100644 --- a/engines/scumm/file.cpp +++ b/engines/scumm/file.cpp @@ -185,6 +185,30 @@ uint32 ScummFile::read(void *dataPtr, uint32 dataSize) { } #pragma mark - +#pragma mark --- ScummSteamFile --- +#pragma mark - + +bool ScummSteamFile::open(const Common::String &filename) { + if (filename.equalsIgnoreCase(_indexFile.indexFileName)) { + return openWithSubRange(_indexFile.executableName, _indexFile.start, _indexFile.len); + } else { + // Regular non-bundled file + return ScummFile::open(filename); + } +} + +bool ScummSteamFile::openWithSubRange(const Common::String &filename, int32 subFileStart, int32 subFileLen) { + if (ScummFile::open(filename)) { + _subFileStart = subFileStart; + _subFileLen = subFileLen; + seek(0, SEEK_SET); + return true; + } else { + return false; + } +} + +#pragma mark - #pragma mark --- ScummDiskImage --- #pragma mark - diff --git a/engines/scumm/file.h b/engines/scumm/file.h index d6dbc06ddc..e7c1eb6d71 100644 --- a/engines/scumm/file.h +++ b/engines/scumm/file.h @@ -53,7 +53,7 @@ public: }; class ScummFile : public BaseScummFile { -private: +protected: int32 _subFileStart; int32 _subFileLen; bool _myEos; // Have we read past the end of the subfile? @@ -64,7 +64,7 @@ private: public: ScummFile(); - bool open(const Common::String &filename); + virtual bool open(const Common::String &filename); bool openSubFile(const Common::String &filename); void clearErr() { _myEos = false; BaseScummFile::clearErr(); } @@ -120,6 +120,29 @@ public: uint32 read(void *dataPtr, uint32 dataSize); }; +struct SteamIndexFile { + byte id; + Common::Platform platform; + const char *pattern; + const char *indexFileName; + const char *executableName; + int32 start; + int32 len; +}; + +const SteamIndexFile *lookUpSteamIndexFile(Common::String pattern, Common::Platform platform); + +class ScummSteamFile : public ScummFile { +private: + const SteamIndexFile &_indexFile; + + bool openWithSubRange(const Common::String &filename, int32 subFileStart, int32 subFileLen); +public: + ScummSteamFile(const SteamIndexFile &indexFile) : ScummFile(), _indexFile(indexFile) {} + + bool open(const Common::String &filename); +}; + } // End of namespace Scumm #endif diff --git a/engines/scumm/he/sprite_he.cpp b/engines/scumm/he/sprite_he.cpp index 218f2ec59c..245a986531 100644 --- a/engines/scumm/he/sprite_he.cpp +++ b/engines/scumm/he/sprite_he.cpp @@ -264,6 +264,13 @@ int Sprite::getSpriteFlagRemapPalette(int spriteId) { int Sprite::getSpriteFlagAutoAnim(int spriteId) { assertRange(1, spriteId, _varNumSprites, "sprite"); + // WORKAROUND: Two scripts (room 2 script 2070/2071) compare against + // a return value of one, but the original game returned the flag value + // (0x200000) for true. These scripts bugs caused problems (infinite loop + // and beans not appearing) in the Jumping Beans mini games under ScummVM. + if (_vm->_game.id == GID_PJGAMES) + return 0; + return ((_spriteTable[spriteId].flags & kSFAutoAnim) != 0) ? 1 : 0; } @@ -793,6 +800,11 @@ void Sprite::resetSprite(int spriteId) { _spriteTable[spriteId].field_84 = 0; _spriteTable[spriteId].imgFlags = 0; _spriteTable[spriteId].field_90 = 0; + + if (_vm->_game.heversion >= 100) { + _spriteTable[spriteId].flags &= ~kSFMarkDirty; + _spriteTable[spriteId].flags |= kSFAutoAnim | kSFBlitDirectly; + } } void Sprite::setSpriteImage(int spriteId, int imageNum) { @@ -820,6 +832,8 @@ void Sprite::setSpriteImage(int spriteId, int imageNum) { } else { if (_vm->VAR(139)) _spriteTable[spriteId].flags &= ~kSFActive; + else if (_vm->_game.heversion >= 100 && origResId == 0) + _spriteTable[spriteId].flags = 0; else if (_spriteTable[spriteId].flags & kSFImageless) _spriteTable[spriteId].flags = 0; else diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index 5e2566dc32..824dfec144 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -435,8 +435,9 @@ void ScummEngine_v6::processKeyboard(Common::KeyState lastKeyHit) { break; } - if (VAR_VOICE_MODE != 0xFF) - VAR(VAR_VOICE_MODE) = _voiceMode; + // We need to sync the current sound settings here to make sure that + // we actually update the mute state of speech properly. + syncSoundSettings(); return; } diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index d43db1e5f1..416a8f7ef9 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -7,6 +7,7 @@ MODULE_OBJS := \ bomp.o \ boxes.o \ camera.o \ + cdda.o \ charset.o \ charset-fontdata.o \ costume.o \ diff --git a/engines/scumm/nut_renderer.cpp b/engines/scumm/nut_renderer.cpp index 1d5761ef48..d8672c473c 100644 --- a/engines/scumm/nut_renderer.cpp +++ b/engines/scumm/nut_renderer.cpp @@ -395,10 +395,6 @@ void NutRenderer::drawChar(const Graphics::Surface &s, byte c, int x, int y, byt } void NutRenderer::draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color) { - // FIXME: This gets passed a const destination Surface. Intuitively this - // should never get written to. But sadly it does... For now we simply - // cast the const qualifier away. - byte *dst = (byte *)const_cast<void *>(s.getBasePtr(x, y)); const int width = _vm->_2byteWidth; const int height = MIN(_vm->_2byteHeight, s.h - y); const byte *src = _vm->get2byteCharPtr(c); @@ -408,17 +404,50 @@ void NutRenderer::draw2byte(const Graphics::Surface &s, int c, int x, int y, byt return; } - for (int ty = 0; ty < height; ty++) { - for (int tx = 0; tx < width; tx++) { - if ((tx & 7) == 0) - bits = *src++; - if (x + tx < 0 || x + tx >= s.w || y + ty < 0) - continue; - if (bits & revBitMask(tx % 8)) { - dst[tx] = color; + enum ShadowMode { + kNone, + kKoreanV8ShadowMode + }; + + ShadowMode shadowMode = kNone; + + if (_vm->_language == Common::KO_KOR && _vm->_game.version == 8) { + shadowMode = kKoreanV8ShadowMode; + } + + int shadowOffsetXTable[4] = {-1, 0, 1, 0}; + int shadowOffsetYTable[4] = {0, 1, 0, 0}; + int shadowOffsetColorTable[4] = {0, 0, 0, color}; + + int shadowIdx = 3; + if (shadowMode == kKoreanV8ShadowMode) + shadowIdx = 0; + + const byte *origSrc = src; + + for (; shadowIdx < 4; shadowIdx++) { + int offX = x + shadowOffsetXTable[shadowIdx]; + int offY = y + shadowOffsetYTable[shadowIdx]; + byte drawColor = shadowOffsetColorTable[shadowIdx]; + + // FIXME: This gets passed a const destination Surface. Intuitively this + // should never get written to. But sadly it does... For now we simply + // cast the const qualifier away. + byte *dst = (byte *)const_cast<void *>(s.getBasePtr(offX, offY)); + src = origSrc; + + for (int ty = 0; ty < height; ty++) { + for (int tx = 0; tx < width; tx++) { + if ((tx & 7) == 0) + bits = *src++; + if (offX + tx < 0 || offX + tx >= s.w || offY + ty < 0) + continue; + if (bits & revBitMask(tx % 8)) { + dst[tx] = drawColor; + } } + dst += s.pitch; } - dst += s.pitch; } } diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp index 5ed50ab65c..adcda68e10 100644 --- a/engines/scumm/players/player_ad.cpp +++ b/engines/scumm/players/player_ad.cpp @@ -137,6 +137,18 @@ void Player_AD::startSound(int sound) { if (startSfx(sfx, res)) { // Lock the new resource _vm->_res->lock(rtSound, sound); + } else { + // When starting the sfx failed we need to reset the slot. + sfx->resource = -1; + + for (int i = 0; i < ARRAYSIZE(sfx->channels); ++i) { + sfx->channels[i].state = kChannelStateOff; + + if (sfx->channels[i].hardwareChannel != -1) { + freeHWChannel(sfx->channels[i].hardwareChannel); + sfx->channels[i].hardwareChannel = -1; + } + } } } } @@ -290,34 +302,43 @@ void Player_AD::setupVolume() { } int Player_AD::allocateHWChannel(int priority, SfxSlot *owner) { - // First pass: Check whether there's any unallocated channel + // We always reaLlocate the channel with the lowest priority in case none + // is free. + int channel = -1; + int minPrio = priority; + for (int i = 0; i < _numHWChannels; ++i) { if (!_hwChannels[i].allocated) { - _hwChannels[i].allocated = true; - _hwChannels[i].priority = priority; - _hwChannels[i].sfxOwner = owner; - return i; + channel = i; + break; + } + + // We don't allow SFX to reallocate their own channels. Otherwise we + // would call stopSfx in the midst of startSfx and that can lead to + // horrible states... + // We also prevent the music from reallocating its own channels like + // in the original. + if (_hwChannels[i].priority <= minPrio && _hwChannels[i].sfxOwner != owner) { + minPrio = _hwChannels[i].priority; + channel = i; } } - // Second pass: Reassign channels based on priority - for (int i = 0; i < _numHWChannels; ++i) { - if (_hwChannels[i].priority <= priority) { - // In case the HW channel belongs to a SFX we will completely - // stop playback of that SFX. - // TODO: Maybe be more fine grained in the future and allow - // detachment of individual channels of a SFX? - if (_hwChannels[i].sfxOwner) { - stopSfx(_hwChannels[i].sfxOwner); - } - _hwChannels[i].allocated = true; - _hwChannels[i].priority = priority; - _hwChannels[i].sfxOwner = owner; - return i; + if (channel != -1) { + // In case the HW channel belongs to a SFX we will completely + // stop playback of that SFX. + // TODO: Maybe be more fine grained in the future and allow + // detachment of individual channels of a SFX? + if (_hwChannels[channel].allocated && _hwChannels[channel].sfxOwner) { + stopSfx(_hwChannels[channel].sfxOwner); } + + _hwChannels[channel].allocated = true; + _hwChannels[channel].priority = priority; + _hwChannels[channel].sfxOwner = owner; } - return -1; + return channel; } void Player_AD::freeHWChannel(int channel) { @@ -747,23 +768,26 @@ const uint Player_AD::_rhythmChannelTable[6] = { // SFX Player_AD::SfxSlot *Player_AD::allocateSfxSlot(int priority) { - // First pass: Check whether there's a unused slot + // We always reaLlocate the slot with the lowest priority in case none is + // free. + SfxSlot *sfx = nullptr; + int minPrio = priority; + for (int i = 0; i < ARRAYSIZE(_sfx); ++i) { if (_sfx[i].resource == -1) { return &_sfx[i]; + } else if (_sfx[i].priority <= minPrio) { + minPrio = _sfx[i].priority; + sfx = &_sfx[i]; } } - // Second pass: Look for a slot with lower priority - for (int i = 0; i < ARRAYSIZE(_sfx); ++i) { - if (_sfx[i].priority <= priority) { - // Stop the old sfx - stopSfx(&_sfx[i]); - return &_sfx[i]; - } + // In case we reallocate a slot stop the old one. + if (sfx) { + stopSfx(sfx); } - return nullptr; + return sfx; } bool Player_AD::startSfx(SfxSlot *sfx, const byte *resource) { @@ -1163,7 +1187,7 @@ const uint Player_AD::_noteAdjustTable[16] = { 0, 4369, 8738, 13107, 17476, 21845, 26214, 30583, 34952, 39321, 43690, 48059, - 52428, 46797, 61166, 65535 + 52428, 56797, 61166, 65535 }; const bool Player_AD::_useOperatorTable[7] = { diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 0aaff4c094..7eadb042fb 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -1453,7 +1453,7 @@ void ScummEngine::saveOrLoad(Serializer *s) { // forever, then resume playing it. This helps a lot when the audio CD // is used to provide ambient music (see bug #788195). if (s->isLoading() && info.playing && info.numLoops < 0) - _system->getAudioCDManager()->play(info.track, info.numLoops, info.start, info.duration); + _sound->playCDTrackInternal(info.track, info.numLoops, info.start, info.duration); } diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp index 2c672ccc89..2fe5333bfc 100644 --- a/engines/scumm/script.cpp +++ b/engines/scumm/script.cpp @@ -972,6 +972,18 @@ void ScummEngine::runEntryScript() { runScript(VAR(VAR_ENTRY_SCRIPT2), 0, 0, 0); } +void ScummEngine::runQuitScript() { + if (VAR_QUIT_SCRIPT != 0xFF && VAR(VAR_QUIT_SCRIPT)) { + int args[NUM_SCRIPT_LOCAL]; + + memset(args, 0, sizeof(args)); + args[0] = 2; + args[1] = 1003; + + runScript(VAR(VAR_QUIT_SCRIPT), 0, 0, args); + } +} + void ScummEngine::killScriptsAndResources() { ScriptSlot *ss; int i; diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp index 2cda9898af..91afa859a9 100644 --- a/engines/scumm/script_v5.cpp +++ b/engines/scumm/script_v5.cpp @@ -544,7 +544,7 @@ void ScummEngine_v5::o5_setClass() { } else if (cls == 0) { // Class '0' means: clean all class data _classData[obj] = 0; - if ((_game.features & GF_SMALL_HEADER) && obj <= _numActors) { + if ((_game.features & GF_SMALL_HEADER) && objIsActor(obj)) { Actor *a = derefActor(obj, "o5_setClass"); a->_ignoreBoxes = false; a->_forceClip = 0; diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index ae80f306af..0eeff57ff7 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Fri Sep 27 05:44:12 2013 + This file was generated by the md5table tool on Wed Jun 25 10:34:07 2014 DO NOT EDIT MANUALLY! */ @@ -17,6 +17,7 @@ static const MD5Table md5table[] = { { "008e76ec3ae58d0add637ea7aa299a2c", "freddi3", "", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, { "02cae0e7ff8504f73618391873d5781a", "freddi3", "HE 98.5", "", -1, Common::DE_DEU, Common::kPlatformWindows }, { "0305e850382b812fec6e5998ef88a966", "pajama", "", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, + { "0354ee0d14cde1264ec762261c04c14a", "loom", "Steam", "Steam", 585728, Common::EN_ANY, Common::kPlatformWindows }, { "035deab53b47bc43abc763560d0f8d4b", "atlantis", "Floppy", "Demo", -1, Common::EN_ANY, Common::kPlatformDOS }, { "037385a953789190298494d92b89b3d0", "catalog", "HE 72", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "03d3b18ee3fd68114e2a687c871e38d5", "freddi4", "HE 99", "Mini Game", -1, Common::EN_USA, Common::kPlatformWindows }, @@ -194,6 +195,7 @@ static const MD5Table md5table[] = { { "45152f7cf2ba8f43cf8a8ea2e740ae09", "monkey", "VGA", "VGA", 8357, Common::ES_ESP, Common::kPlatformDOS }, { "4521138d15d1fd7649c31fb981746231", "pajama2", "HE 98.5", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "4522564b3c31aaf218b6a96826a549fd", "maze", "HE 99", "", -1, Common::EN_USA, Common::kPlatformWindows }, + { "45adb5065e77559196dc0477e0f91fb9", "freddi3", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows }, { "46b53fd430adcfbed791b48a0d4b079f", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatformDOS }, { "470c45b636139bb40716daa1c7edaad0", "loom", "EGA", "EGA", -1, Common::DE_DEU, Common::kPlatformDOS }, { "477dbafbd66a53c98416dc01aef019ad", "monkey", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformDOS }, @@ -298,6 +300,7 @@ static const MD5Table md5table[] = { { "69ffe29185b8d71f09f6199f8b2a87cb", "lost", "HE 100", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "6a30a07f353a75cdc602db27d73e1b42", "puttputt", "HE 70", "", -1, Common::EN_ANY, Common::kPlatformWindows }, { "6a60d395b78b205c93a956100b1bf5ae", "pajama2", "HE 98.5", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, + { "6a8133b63d46f6663fbcbb49d5a2edb1", "atlantis", "Steam", "Steam", 520548, Common::EN_ANY, Common::kPlatformMacintosh }, { "6af2419fe3db5c2fdb091ae4e5833770", "puttrace", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "6b19d0e25cbf720d05822379b8b90ed9", "PuttTime", "HE 90", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "6b257bb2827dd894b8109a50a1a18b5a", "freddicove", "HE 100", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, @@ -356,6 +359,7 @@ static const MD5Table md5table[] = { { "7edd665bbede7ea8b7233f8e650be6f8", "samnmax", "", "CD", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7f45ddd6dbfbf8f80c0c0efea4c295bc", "maniac", "V1", "V1", 1972, Common::EN_ANY, Common::kPlatformDOS }, { "7f945525abcd48015adf1632637a44a1", "pajama", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown }, + { "7fbcff27c323499beaedd605e1ebd47d", "indy3", "Steam", "Steam", 561152, Common::EN_ANY, Common::kPlatformWindows }, { "7fc6cdb46b4c9d384c52327f4bca6416", "football", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "810a9da887aefa597b0cf3c77d262897", "BluesABCTime", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "822807c3cd3b43a925cab2767ca6b453", "BluesTreasureHunt", "", "Disc 1", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -438,6 +442,7 @@ static const MD5Table md5table[] = { { "a095616d2d23ccf43b8e257711202cba", "football2002", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "a095e33061606d231ff37dca4c64c8ac", "pajama", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "a0a7dea72003933b8b3f8b99b9f7ddeb", "loom", "No AdLib", "EGA", -1, Common::EN_ANY, Common::kPlatformAtariST }, + { "a15d6e1e2c52bbd0ff7fa6b63ab7f796", "indy3", "Steam", "Steam", 680340, Common::EN_ANY, Common::kPlatformMacintosh }, { "a194f15f51ee62badab74b9e7da97693", "baseball2001", "", "Demo", 20507, Common::EN_ANY, Common::kPlatformUnknown }, { "a197a87ae77f3b3333f09a7a2c448fe2", "freddi", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "a22af0ad0e3126d19d22707b0267a37d", "balloon", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows }, @@ -466,6 +471,7 @@ static const MD5Table md5table[] = { { "aa8a0cb65f3afbbe2c14c3f9f92775a3", "monkey", "CD", "CD", 8955, Common::FR_FRA, Common::kPlatformDOS }, { "aaa587701cde7e74692c68c1024b85eb", "puttrace", "HE 99", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "aaa7f36a253f277dd29dd1c051b0e4b9", "indy3", "No AdLib", "EGA", -1, Common::DE_DEU, Common::kPlatformAtariST }, + { "aad201302286c1cfee92321cd406e427", "dig", "Steam", "Steam", 811008, Common::EN_ANY, Common::kPlatformWindows }, { "ab0693e9324cfcf498fdcbb12acf8bb4", "puttcircus", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "ac1642b6edfb8521ca03760126f1c250", "tentacle", "", "Demo", -1, Common::DE_DEU, Common::kPlatformDOS }, { "ac62d50e39492ee3738b4e83a5ac780f", "freddi2", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows }, @@ -479,6 +485,7 @@ static const MD5Table md5table[] = { { "b250d0f9cc83f80ced56fe11a4fb057c", "maniac", "V2", "V2", 1988, Common::EN_ANY, Common::kPlatformDOS }, { "b289a2a8cbedbf45786e0b4ad2f510f1", "samnmax", "Floppy", "Floppy", -1, Common::IT_ITA, Common::kPlatformDOS }, { "b47be81e39a9710f6f595f7b527b60f8", "puttrace", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformWindows }, + { "b4a677bf27c010a747975705108ff1e6", "loom", "Steam", "Steam", 393572, Common::EN_ANY, Common::kPlatformMacintosh }, { "b5298a5c15ffbe8b381d51ea4e26d35c", "freddi4", "HE 99", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "b597e0403cc0002f69170e6caba7edd9", "indy3", "EGA", "EGA Demo", 5361, Common::EN_ANY, Common::kPlatformDOS }, { "b628506f7def772e40de0aa5440fb8e1", "activity", "HE 70", "", -1, Common::EN_ANY, Common::kPlatformWindows }, @@ -568,6 +575,7 @@ static const MD5Table md5table[] = { { "d7b247c26bf1f01f8f7daf142be84de3", "balloon", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "d8323015ecb8b10bf53474f6e6b0ae33", "dig", "", "", 16304, Common::UNK_LANG, Common::kPlatformUnknown }, { "d917f311a448e3cc7239c31bddb00dd2", "samnmax", "", "CD", 9080, Common::EN_ANY, Common::kPlatformUnknown }, + { "d93cc8be628ed5d3b3a29188fc7105d3", "dig", "Steam", "Steam", 1061296, Common::EN_ANY, Common::kPlatformMacintosh }, { "d9d0dd93d16ab4dec55cabc2b86bbd17", "samnmax", "", "Demo", 6478, Common::EN_ANY, Common::kPlatformDOS }, { "da09e666fc8f5b78d7b0ac65d1a3b56e", "monkey2", "FM-TOWNS", "", 11135, Common::EN_ANY, Common::kPlatformFMTowns }, { "da6269b18fcb08189c0aa9c95533cce2", "monkey", "CD", "CD", 8955, Common::IT_ITA, Common::kPlatformDOS }, @@ -628,6 +636,7 @@ static const MD5Table md5table[] = { { "f237bf8a5ef9af78b2a6a4f3901da341", "pajama", "", "Demo", 18354, Common::EN_ANY, Common::kPlatformUnknown }, { "f27b1ba0eadaf2a6617b2b58192d1dbf", "samnmax", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformDOS }, { "f2ec78e50bdc63b70044e9758be10914", "spyfox", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformMacintosh }, + { "f3c5d9bf3f091bd1f18dc1013fba5396", "atlantis", "Steam", "Steam", 638976, Common::EN_ANY, Common::kPlatformWindows }, { "f3d55aea441e260e9e9c7d2a187097e0", "puttzoo", "", "Demo", 14337, Common::EN_ANY, Common::kPlatformWindows }, { "f40a7f495f59188ca57a9d1d50301bb6", "puttputt", "HE 60", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "f5228b0cc1c19e6ea8268ba2eeb61f60", "freddi", "HE 73", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 34c231e5d4..475b146a7b 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -467,6 +467,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) VAR_NUM_SCRIPT_CYCLES = 0xFF; VAR_SCRIPT_CYCLE = 0xFF; + VAR_QUIT_SCRIPT = 0xFF; + VAR_NUM_GLOBAL_OBJS = 0xFF; // Use g_scumm from error() ONLY @@ -1026,6 +1028,35 @@ Common::Error ScummEngine::init() { } #endif + // Extra directories needed for the Steam versions + if (_filenamePattern.genMethod == kGenDiskNumSteam || _filenamePattern.genMethod == kGenRoomNumSteam) { + if (_game.platform == Common::kPlatformWindows) { + switch (_game.id) { + case GID_INDY3 : + SearchMan.addSubDirectoryMatching(gameDataDir, "indy3"); + break; + case GID_INDY4 : + SearchMan.addSubDirectoryMatching(gameDataDir, "atlantis"); + break; + case GID_LOOM : + SearchMan.addSubDirectoryMatching(gameDataDir, "loom"); + break; +#ifdef ENABLE_SCUMM_7_8 + case GID_DIG : + SearchMan.addSubDirectoryMatching(gameDataDir, "dig"); + SearchMan.addSubDirectoryMatching(gameDataDir, "dig/video"); + break; +#endif + default: + break; + } + } else { + SearchMan.addSubDirectoryMatching(gameDataDir, "Contents"); + SearchMan.addSubDirectoryMatching(gameDataDir, "Contents/MacOS"); + SearchMan.addSubDirectoryMatching(gameDataDir, "Contents/Resources"); + SearchMan.addSubDirectoryMatching(gameDataDir, "Contents/Resources/video"); + } + } // The kGenUnchanged method is only used for 'container files', i.e. files // that contain the real game files bundled together in an archive format. @@ -1126,15 +1157,30 @@ Common::Error ScummEngine::init() { error("Couldn't find known subfile inside container file '%s'", _containerFile.c_str()); _fileHandle->close(); - } else { error("kGenUnchanged used with unsupported platform"); } } else { - // Regular access, no container file involved - _fileHandle = new ScummFile(); + if (_filenamePattern.genMethod == kGenDiskNumSteam || _filenamePattern.genMethod == kGenRoomNumSteam) { + // Steam game versions have the index file embedded in the main executable + const SteamIndexFile *indexFile = lookUpSteamIndexFile(_filenamePattern.pattern, _game.platform); + if (!indexFile || indexFile->id != _game.id) { + error("Couldn't find index file description for Steam version"); + } else { + _fileHandle = new ScummSteamFile(*indexFile); + } + } else { + // Regular access, no container file involved + _fileHandle = new ScummFile(); + } } + // Steam Win and Mac versions share the same DOS data files. We show Windows or Mac + // for the platform the detector, but internally we force the platform to DOS, so that + // the code for handling the original DOS data files is used. + if (_filenamePattern.genMethod == kGenDiskNumSteam || _filenamePattern.genMethod == kGenRoomNumSteam) + _game.platform = Common::kPlatformDOS; + // Load CJK font, if present // Load it earlier so _useCJKMode variable could be set loadCJKFont(); @@ -1218,7 +1264,7 @@ Common::Error ScummEngine::init() { void ScummEngine::setupScumm() { // On some systems it's not safe to run CD audio games from the CD. - if (_game.features & GF_AUDIOTRACKS) { + if (_game.features & GF_AUDIOTRACKS && !Common::File::exists("CDDA.SOU")) { checkCD(); int cd_num = ConfMan.getInt("cdrom"); @@ -2029,6 +2075,7 @@ Common::Error ScummEngine::go() { if (shouldQuit()) { // TODO: Maybe perform an autosave on exit? + runQuitScript(); } } diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index be5a83d8c9..af118a89a1 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -256,6 +256,7 @@ enum ScummGameId { GID_BASEBALL2003, GID_BASKETBALL, GID_MOONBASE, + GID_PJGAMES, GID_HECUP // CUP demos }; @@ -670,6 +671,7 @@ protected: virtual void checkAndRunSentenceScript(); void runExitScript(); void runEntryScript(); + void runQuitScript(); void runAllScripts(); void freezeScripts(int scr); void unfreezeScripts(); @@ -1360,6 +1362,8 @@ public: byte VAR_SCRIPT_CYCLE; // Used in runScript()/runObjectScript() byte VAR_NUM_SCRIPT_CYCLES; // Used in runAllScripts() + + byte VAR_QUIT_SCRIPT; // Used in confirmExitDialog() // Exists both in V7 and in V72HE: byte VAR_NUM_GLOBAL_OBJS; diff --git a/engines/scumm/smush/smush_font.cpp b/engines/scumm/smush/smush_font.cpp index 4c04901b42..e2f75a6862 100644 --- a/engines/scumm/smush/smush_font.cpp +++ b/engines/scumm/smush/smush_font.cpp @@ -115,9 +115,7 @@ int SmushFont::drawChar(byte *buffer, int dst_width, int x, int y, byte chr) { int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) { int w = _vm->_2byteWidth; int h = _vm->_2byteHeight; - - byte *src = _vm->get2byteCharPtr(idx); - byte *dst = buffer + dst_width * (y + (_vm->_game.id == GID_CMI ? 7 : (_vm->_game.id == GID_DIG ? 2 : 0))) + x; + const byte *src = _vm->get2byteCharPtr(idx); byte bits = 0; char color = (_color != -1) ? _color : 1; @@ -128,18 +126,60 @@ int SmushFont::draw2byte(byte *buffer, int dst_width, int x, int y, int idx) { if (_vm->_game.id == GID_FT) color = 1; - for (int j = 0; j < h; j++) { - for (int i = 0; i < w; i++) { - if ((i % 8) == 0) - bits = *src++; - if (bits & revBitMask(i % 8)) { - dst[i + 1] = 0; - dst[dst_width + i] = 0; - dst[dst_width + i + 1] = 0; - dst[i] = color; + enum ShadowMode { + kNone, + kNormalShadowMode, + kKoreanV7ShadowMode, + kKoreanV8ShadowMode + }; + + ShadowMode shadowMode = kNone; + + if (_vm->_language == Common::KO_KOR) { + if (_vm->_game.version == 8) + shadowMode = kKoreanV8ShadowMode; + else + shadowMode = kKoreanV7ShadowMode; + } + + int shadowOffsetXTable[4] = {-1, 0, 1, 0}; + int shadowOffsetYTable[4] = {0, 1, 0, 0}; + int shadowOffsetColorTable[4] = {0, 0, 0, color}; + + int shadowIdx = 3; + if (shadowMode == kKoreanV8ShadowMode) + shadowIdx = 0; + else if (shadowMode == kKoreanV7ShadowMode) + shadowIdx = 2; + + const byte *origSrc = src; + + for (; shadowIdx < 4; shadowIdx++) { + int offX = x + shadowOffsetXTable[shadowIdx]; + int offY = y + shadowOffsetYTable[shadowIdx]; + byte drawColor = shadowOffsetColorTable[shadowIdx]; + + src = origSrc; + + byte *dst = buffer + dst_width * (offY + (_vm->_game.id == GID_CMI ? 7 : (_vm->_game.id == GID_DIG ? 2 : 0))) + offX; + + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + if (offX + i < 0) + continue; + if ((i % 8) == 0) + bits = *src++; + if (bits & revBitMask(i % 8)) { + if (shadowMode == kNormalShadowMode) { + dst[i + 1] = 0; + dst[dst_width + i] = 0; + dst[dst_width + i + 1] = 0; + } + dst[i] = drawColor; + } } + dst += dst_width; } - dst += dst_width; } return w + 1; } diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 01bdefc7c0..cb428d1c15 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -27,6 +27,7 @@ #include "common/substream.h" #include "scumm/actor.h" +#include "scumm/cdda.h" #include "scumm/file.h" #include "scumm/imuse/imuse.h" #include "scumm/imuse_digi/dimuse.h" @@ -36,8 +37,6 @@ #include "scumm/sound.h" #include "scumm/util.h" -#include "backends/audiocd/audiocd.h" - #include "audio/decoders/adpcm.h" #include "audio/decoders/flac.h" #include "audio/mididrv.h" @@ -89,11 +88,21 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer) memset(_mouthSyncTimes, 0, sizeof(_mouthSyncTimes)); _musicType = MDT_NONE; + + _loomSteamCD.playing = false; + _loomSteamCD.track = 0; + _loomSteamCD.start = 0; + _loomSteamCD.duration = 0; + _loomSteamCD.numLoops = 0; + _loomSteamCD.volume = Audio::Mixer::kMaxChannelVolume; + _loomSteamCD.balance = 0; + + _isLoomSteam = _vm->_game.id == GID_LOOM && Common::File::exists("CDDA.SOU"); } Sound::~Sound() { stopCDTimer(); - g_system->getAudioCDManager()->stop(); + stopCD(); free(_offsetTable); } @@ -649,7 +658,11 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle _vm->_imuseDigital->startVoice(kTalkSoundID, input); #endif } else { - _mixer->playStream(Audio::Mixer::kSpeechSoundType, handle, input, id); + if (mode == 1) { + _mixer->playStream(Audio::Mixer::kSFXSoundType, handle, input, id); + } else { + _mixer->playStream(Audio::Mixer::kSpeechSoundType, handle, input, id); + } } } } @@ -838,9 +851,6 @@ void Sound::soundKludge(int *list, int num) { } void Sound::talkSound(uint32 a, uint32 b, int mode, int channel) { - if (_vm->_game.version >= 5 && ConfMan.getBool("speech_mute")) - return; - if (mode == 1) { _talk_sound_a1 = a; _talk_sound_b1 = b; @@ -1033,7 +1043,7 @@ void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) { // Play it if (!_soundsPaused) - g_system->getAudioCDManager()->play(track, numLoops, startFrame, duration); + playCDTrackInternal(track, numLoops, startFrame, duration); // Start the timer after starting the track. Starting an MP3 track is // almost instantaneous, but a CD player may take some time. Hopefully @@ -1041,16 +1051,59 @@ void Sound::playCDTrack(int track, int numLoops, int startFrame, int duration) { startCDTimer(); } +void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int duration) { + _loomSteamCD.track = track; + _loomSteamCD.numLoops = numLoops; + _loomSteamCD.start = startFrame; + _loomSteamCD.duration = duration; + + if (!_isLoomSteam) { + g_system->getAudioCDManager()->play(track, numLoops, startFrame, duration); + } else { + // Stop any currently playing track + _mixer->stopHandle(_loomSteamCDAudioHandle); + + Common::File *cddaFile = new Common::File(); + if (cddaFile->open("CDDA.SOU")) { + Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75); + Audio::Timestamp end = Audio::Timestamp(0, startFrame + duration, 75); + Audio::SeekableAudioStream *stream = makeCDDAStream(cddaFile, DisposeAfterUse::YES); + + _mixer->playStream(Audio::Mixer::kMusicSoundType, &_loomSteamCDAudioHandle, + Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops)); + } else { + delete cddaFile; + } + } +} + void Sound::stopCD() { - g_system->getAudioCDManager()->stop(); + if (!_isLoomSteam) + g_system->getAudioCDManager()->stop(); + else + _mixer->stopHandle(_loomSteamCDAudioHandle); } int Sound::pollCD() const { - return g_system->getAudioCDManager()->isPlaying(); + if (!_isLoomSteam) + return g_system->getAudioCDManager()->isPlaying(); + else + return _mixer->isSoundHandleActive(_loomSteamCDAudioHandle); } void Sound::updateCD() { - g_system->getAudioCDManager()->updateCD(); + if (!_isLoomSteam) + g_system->getAudioCDManager()->updateCD(); +} + +AudioCDManager::Status Sound::getCDStatus() { + if (!_isLoomSteam) + return g_system->getAudioCDManager()->getStatus(); + else { + AudioCDManager::Status info = _loomSteamCD; + info.playing = _mixer->isSoundHandleActive(_loomSteamCDAudioHandle); + return info; + } } void Sound::saveLoadWithSerializer(Serializer *ser) { diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h index a96d2b8ed5..a479ad5731 100644 --- a/engines/scumm/sound.h +++ b/engines/scumm/sound.h @@ -27,6 +27,7 @@ #include "audio/audiostream.h" #include "audio/mididrv.h" #include "audio/mixer.h" +#include "backends/audiocd/audiocd.h" #include "scumm/saveload.h" namespace Audio { @@ -86,6 +87,10 @@ protected: int16 _currentCDSound; int16 _currentMusic; + Audio::SoundHandle _loomSteamCDAudioHandle; + bool _isLoomSteam; + AudioCDManager::Status _loomSteamCD; + public: Audio::SoundHandle _talkChannelHandle; // Handle of mixer channel actor is talking on @@ -119,9 +124,11 @@ public: void stopCDTimer(); void playCDTrack(int track, int numLoops, int startFrame, int duration); + void playCDTrackInternal(int track, int numLoops, int startFrame, int duration); void stopCD(); int pollCD() const; void updateCD(); + AudioCDManager::Status getCDStatus(); int getCurrentCDSound() const { return _currentCDSound; } // Used by the save/load system: diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp index 79d7ed03da..a903ac5804 100644 --- a/engines/scumm/vars.cpp +++ b/engines/scumm/vars.cpp @@ -320,6 +320,7 @@ void ScummEngine_v90he::setupScummVars() { ScummEngine_v80he::setupScummVars(); VAR_TIMER = 97; + VAR_QUIT_SCRIPT = 102; VAR_SCRIPT_CYCLE = 103; VAR_NUM_SCRIPT_CYCLES = 104; diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 0257a805ff..ac358e774b 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -542,7 +542,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * Video::VideoDecoder *dxaDecoder = new Video::DXADecoder(); return new MoviePlayer(vm, textMan, resMan, system, dxaDecoder, kVideoDecoderDXA); #else - GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK")); + GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib"), _("OK")); dialog.runModal(); return 0; #endif @@ -558,7 +558,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * Video::VideoDecoder *aviDecoder = new Video::AVIDecoder(12); return new MoviePlayer(vm, textMan, resMan, system, aviDecoder, kVideoDecoderMP2); #else - GUI::MessageDialog dialog(_("MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"), _("OK")); + GUI::MessageDialog dialog(_("MPEG-2 cutscenes found but ScummVM has been built without MPEG-2 support"), _("OK")); dialog.runModal(); return 0; #endif diff --git a/engines/sword1/console.cpp b/engines/sword1/console.cpp index 3eb3b93a19..7fabc62192 100644 --- a/engines/sword1/console.cpp +++ b/engines/sword1/console.cpp @@ -22,14 +22,37 @@ #include "sword1/console.h" #include "sword1/sword1.h" +#include "sword1/sound.h" +#include "common/config-manager.h" +#include "common/str.h" namespace Sword1 { SwordConsole::SwordConsole(SwordEngine *vm) : GUI::Debugger(), _vm(vm) { assert(_vm); + if (scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1mac") == 0 || scumm_stricmp(ConfMan.get("gameid").c_str(), "sword1macdemo") == 0) + registerCmd("speechEndianness", WRAP_METHOD(SwordConsole, Cmd_SpeechEndianness)); } SwordConsole::~SwordConsole() { } + +bool SwordConsole::Cmd_SpeechEndianness(int argc, const char **argv) { + if (argc == 1) { + debugPrintf("Using %s speech\n", _vm->_sound->_bigEndianSpeech ? "be" : "le"); + return true; + } + if (argc == 2) { + if (scumm_stricmp(argv[1], "le") == 0) { + _vm->_sound->_bigEndianSpeech = false; + return false; + } else if (scumm_stricmp(argv[1], "be") == 0) { + _vm->_sound->_bigEndianSpeech = true; + return false; + } + } + debugPrintf("Usage: %s [le | be]\n", argv[0]); + return true; +} } // End of namespace Sword diff --git a/engines/sword1/console.h b/engines/sword1/console.h index a2bb51f9a4..88ee756151 100644 --- a/engines/sword1/console.h +++ b/engines/sword1/console.h @@ -36,6 +36,7 @@ public: private: SwordEngine *_vm; + bool Cmd_SpeechEndianness(int argc, const char **argv); }; } // End of namespace Sword1 diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp index 0b4d3829d6..a6e6d3917e 100644 --- a/engines/sword1/sound.cpp +++ b/engines/sword1/sound.cpp @@ -116,7 +116,7 @@ void Sound::checkSpeechFileEndianness() { return; // I picked the sample to use randomly (I just made sure it is long enough so that there is - // a fair change of the heuristic to have a stable result and work for every language). + // a fair chance of the heuristic to have a stable result and work for every language). int roomNo = _currentCowFile == 1 ? 1 : 129; int localNo = _currentCowFile == 1 ? 2 : 933; // Get the speech data and apply the heuristic @@ -125,31 +125,46 @@ void Sound::checkSpeechFileEndianness() { uint32 index = _cowHeader[locIndex + (localNo * 2) - 1]; if (sampleSize) { uint32 size; - double be_diff_sum = 0., le_diff_sum = 0.; + // Compute average of difference between two consecutive samples for both BE and LE + // The way uncompressSpeech works we may get un incorrect number of identical consecutive samples + // when using the wrong endianess. To avoid biasing the result we this we skip all duplicate values. _bigEndianSpeech = false; int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size); - // Compute average of difference between two consecutive samples for both BE and LE if (data) { - if (size > 4000) - size = 2000; - else - size /= 2; - int16 prev_be_value = (int16)SWAP_BYTES_16(*((uint16 *)(data))); - for (uint32 i = 1; i < size; ++i) { - le_diff_sum += fabs((double)(data[i] - data[i - 1])); - int16 be_value = (int16)SWAP_BYTES_16(*((uint16 *)(data + i))); - be_diff_sum += fabs((double)(be_value - prev_be_value)); - prev_be_value = be_value; + uint32 max_cpt = size > 2000 ? 2000 : size; + double le_diff_sum = 0.; + uint32 le_cpt = 0; + for (uint32 i = 1; i < size && le_cpt < max_cpt; ++i) { + if (data[i] != data[i-1]) { + le_diff_sum += fabs((double)(data[i] - data[i - 1])); + ++le_cpt; + } } + le_diff_sum /= le_cpt; delete[] data; + _bigEndianSpeech = true; + data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size); + if (data) { + double be_diff_sum = 0.; + uint32 be_cpt = 0; + for (uint32 i = 1; i < size && be_cpt < le_cpt; ++i) { + if (data[i] != data[i-1]) { + be_diff_sum += fabs((double)(data[i] - data[i - 1])); + ++be_cpt; + } + } + be_diff_sum /= be_cpt; + delete [] data; + // Set the big endian flag + _bigEndianSpeech = (be_diff_sum < le_diff_sum); + if (_bigEndianSpeech) + debug(6, "Mac version: using big endian speech file"); + else + debug(6, "Mac version: using little endian speech file"); + debug(8, "Speech endianness heuristic: average = %f for BE (%d samples) and %f for LE (%d samples)", be_diff_sum, be_cpt, le_diff_sum, le_cpt); + } else + _bigEndianSpeech = false; } - // Set the big endian flag - _bigEndianSpeech = (be_diff_sum < le_diff_sum); - if (_bigEndianSpeech) - debug(6, "Mac version: using big endian speech file"); - else - debug(6, "Mac version: using little endian speech file"); - debug(8, "Speech endianness heuristic: average = %f for BE and %f for LE, computed on %d samples)", be_diff_sum / (size - 1), le_diff_sum / (size - 1), size); } } diff --git a/engines/sword1/sound.h b/engines/sword1/sound.h index 666598dba0..54006bd8b4 100644 --- a/engines/sword1/sound.h +++ b/engines/sword1/sound.h @@ -79,6 +79,7 @@ enum CowMode { }; class Sound { + friend class SwordConsole; public: Sound(Audio::Mixer *mixer, ResMan *pResMan); ~Sound(); diff --git a/engines/sword1/sword1.h b/engines/sword1/sword1.h index c58e97e353..eb24ef70fa 100644 --- a/engines/sword1/sword1.h +++ b/engines/sword1/sword1.h @@ -79,6 +79,7 @@ struct SystemVars { }; class SwordEngine : public Engine { + friend class SwordConsole; public: SwordEngine(OSystem *syst); virtual ~SwordEngine(); diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index 92fa9d0e44..e93f27f76c 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -442,7 +442,7 @@ MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system Video::DXADecoder *dxaDecoder = new Video::DXADecoder(); return new MoviePlayer(vm, system, dxaDecoder, kVideoDecoderDXA); #else - GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK")); + GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib"), _("OK")); dialog.runModal(); return NULL; #endif diff --git a/engines/sword25/gfx/animation.cpp b/engines/sword25/gfx/animation.cpp index eeb78857ea..e2662fb2b3 100644 --- a/engines/sword25/gfx/animation.cpp +++ b/engines/sword25/gfx/animation.cpp @@ -189,14 +189,14 @@ bool Animation::doRender(RectangleList *updateRects) { bool result; if (isScalingAllowed() && (_width != pBitmapResource->getWidth() || _height != pBitmapResource->getHeight())) { result = pBitmapResource->blit(_absoluteX, _absoluteY, - (animationDescriptionPtr->getFrame(_currentFrame).flipV ? BitmapResource::FLIP_V : 0) | - (animationDescriptionPtr->getFrame(_currentFrame).flipH ? BitmapResource::FLIP_H : 0), + (animationDescriptionPtr->getFrame(_currentFrame).flipV ? Graphics::FLIP_V : 0) | + (animationDescriptionPtr->getFrame(_currentFrame).flipH ? Graphics::FLIP_H : 0), 0, _modulationColor, _width, _height, updateRects); } else { result = pBitmapResource->blit(_absoluteX, _absoluteY, - (animationDescriptionPtr->getFrame(_currentFrame).flipV ? BitmapResource::FLIP_V : 0) | - (animationDescriptionPtr->getFrame(_currentFrame).flipH ? BitmapResource::FLIP_H : 0), + (animationDescriptionPtr->getFrame(_currentFrame).flipV ? Graphics::FLIP_V : 0) | + (animationDescriptionPtr->getFrame(_currentFrame).flipH ? Graphics::FLIP_H : 0), 0, _modulationColor, -1, -1, updateRects); } diff --git a/engines/sword25/gfx/bitmapresource.h b/engines/sword25/gfx/bitmapresource.h index 7a4daedd84..2ae891f5cd 100644 --- a/engines/sword25/gfx/bitmapresource.h +++ b/engines/sword25/gfx/bitmapresource.h @@ -40,22 +40,6 @@ namespace Sword25 { class BitmapResource : public Resource { public: - /** - @brief Die möglichen Flippingparameter für die Blit-Methode. - */ - enum FLIP_FLAGS { - /// Das Bild wird nicht gespiegelt. - FLIP_NONE = 0, - /// Das Bild wird an der horizontalen Achse gespiegelt. - FLIP_H = 1, - /// Das Bild wird an der vertikalen Achse gespiegelt. - FLIP_V = 2, - /// Das Bild wird an der horizontalen und vertikalen Achse gespiegelt. - FLIP_HV = FLIP_H | FLIP_V, - /// Das Bild wird an der horizontalen und vertikalen Achse gespiegelt. - FLIP_VH = FLIP_H | FLIP_V - }; - BitmapResource(const Common::String &filename, Image *pImage) : _pImage(pImage), Resource(filename, Resource::TYPE_BITMAP) {} virtual ~BitmapResource() { delete _pImage; } @@ -120,7 +104,7 @@ public: - IsColorModulationAllowed() */ bool blit(int posX = 0, int posY = 0, - int flipping = FLIP_NONE, + int flipping = Graphics::FLIP_NONE, Common::Rect *pSrcPartRect = NULL, uint color = BS_ARGB(255, 255, 255, 255), int width = -1, int height = -1, diff --git a/engines/sword25/gfx/dynamicbitmap.cpp b/engines/sword25/gfx/dynamicbitmap.cpp index ce9c056d08..a335f87fa5 100644 --- a/engines/sword25/gfx/dynamicbitmap.cpp +++ b/engines/sword25/gfx/dynamicbitmap.cpp @@ -86,8 +86,8 @@ bool DynamicBitmap::doRender(RectangleList *updateRects) { // a bit slow when drawing videos, but it's not the main // bottleneck. result = _image->blit(_absoluteX, _absoluteY, - (_flipV ? BitmapResource::FLIP_V : 0) | - (_flipH ? BitmapResource::FLIP_H : 0), + (_flipV ? Graphics::FLIP_V : 0) | + (_flipH ? Graphics::FLIP_H : 0), 0, _modulationColor, -1, -1, updateRects); #else @@ -105,8 +105,8 @@ bool DynamicBitmap::doRender(RectangleList *updateRects) { return true; } else { result = _image->blit(_absoluteX, _absoluteY, - (_flipV ? BitmapResource::FLIP_V : 0) | - (_flipH ? BitmapResource::FLIP_H : 0), + (_flipV ? Graphics::FLIP_V : 0) | + (_flipH ? Graphics::FLIP_H : 0), 0, _modulationColor, _width, _height, updateRects); } diff --git a/engines/sword25/gfx/graphicengine.cpp b/engines/sword25/gfx/graphicengine.cpp index 2a870c021d..f887c3cd51 100644 --- a/engines/sword25/gfx/graphicengine.cpp +++ b/engines/sword25/gfx/graphicengine.cpp @@ -183,7 +183,7 @@ bool GraphicEngine::fill(const Common::Rect *fillRectPtr, uint color) { if (rect.width() > 0 && rect.height() > 0) { if (ca == 0xff) { - _backSurface.fillRect(rect, color); + _backSurface.fillRect(rect, BS_ARGB(cr, cg, cb, ca)); } else { byte *outo = (byte *)_backSurface.getBasePtr(rect.left, rect.top); byte *out; @@ -192,23 +192,23 @@ bool GraphicEngine::fill(const Common::Rect *fillRectPtr, uint color) { out = outo; for (int j = rect.left; j < rect.right; j++) { #if defined(SCUMM_LITTLE_ENDIAN) + *out = 255; + out++; *out += (byte)(((cb - *out) * ca) >> 8); out++; *out += (byte)(((cg - *out) * ca) >> 8); out++; *out += (byte)(((cr - *out) * ca) >> 8); out++; - *out = 255; - out++; #else - *out = 255; - out++; *out += (byte)(((cr - *out) * ca) >> 8); out++; *out += (byte)(((cg - *out) * ca) >> 8); out++; *out += (byte)(((cb - *out) * ca) >> 8); out++; + *out = 255; + out++; #endif } diff --git a/engines/sword25/gfx/image/image.h b/engines/sword25/gfx/image/image.h index 8fbf802501..f8cb0dfec0 100644 --- a/engines/sword25/gfx/image/image.h +++ b/engines/sword25/gfx/image/image.h @@ -43,6 +43,7 @@ #include "sword25/kernel/common.h" #include "common/rect.h" #include "sword25/gfx/graphicengine.h" +#include "graphics/transparent_surface.h" namespace Sword25 { @@ -52,23 +53,6 @@ class Image { public: virtual ~Image() {} - // Enums - /** - @brief The possible flipping parameters for the blit methode. - */ - enum FLIP_FLAGS { - /// The image will not be flipped. - FLIP_NONE = 0, - /// The image will be flipped at the horizontal axis. - FLIP_H = 1, - /// The image will be flipped at the vertical axis. - FLIP_V = 2, - /// The image will be flipped at the horizontal and vertical axis. - FLIP_HV = FLIP_H | FLIP_V, - /// The image will be flipped at the horizontal and vertical axis. - FLIP_VH = FLIP_H | FLIP_V - }; - //@{ /** @name Accessor methods */ @@ -100,7 +84,7 @@ public: @param PosY the position on the Y-axis in the target image in pixels where the image is supposed to be rendered.<br> The default value is 0. @param Flipping how the the image should be flipped.<br> - The default value is BS_Image::FLIP_NONE (no flipping) + The default value is Graphics::FLIP_NONE (no flipping) @param pSrcPartRect Pointer on Common::Rect which specifies the section to be rendered. If the whole image has to be rendered the Pointer is NULL.<br> This referes to the unflipped and unscaled image.<br> The default value is NULL. @@ -128,7 +112,7 @@ public: - IsSetContentAllowed() */ virtual bool blit(int posX = 0, int posY = 0, - int flipping = FLIP_NONE, + int flipping = Graphics::FLIP_NONE, Common::Rect *pPartRect = NULL, uint color = BS_ARGB(255, 255, 255, 255), int width = -1, int height = -1, diff --git a/engines/sword25/gfx/image/imgloader.cpp b/engines/sword25/gfx/image/imgloader.cpp index b4b3030de8..f299cee9d1 100644 --- a/engines/sword25/gfx/image/imgloader.cpp +++ b/engines/sword25/gfx/image/imgloader.cpp @@ -45,7 +45,7 @@ bool ImgLoader::decodePNGImage(const byte *fileDataPtr, uint fileSize, byte *&un error("Error while reading PNG image"); const Graphics::Surface *sourceSurface = png.getSurface(); - Graphics::Surface *pngSurface = sourceSurface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24), png.getPalette()); + Graphics::Surface *pngSurface = sourceSurface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), png.getPalette()); width = pngSurface->w; height = pngSurface->h; @@ -70,7 +70,7 @@ bool ImgLoader::decodeThumbnailImage(const byte *pFileData, uint fileSize, byte uint32 totalSize = pitch * height; pUncompressedData = new byte[totalSize]; uint32 *dst = (uint32 *)pUncompressedData; // treat as uint32, for pixelformat output - const Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24); + const Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); byte r, g, b; for (uint32 i = 0; i < totalSize / 4; i++) { diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp index 107b4cd402..8c6369a790 100644 --- a/engines/sword25/gfx/image/renderedimage.cpp +++ b/engines/sword25/gfx/image/renderedimage.cpp @@ -100,9 +100,6 @@ static byte *readSavegameThumbnail(const Common::String &filename, uint &fileSiz } RenderedImage::RenderedImage(const Common::String &filename, bool &result) : - _data(0), - _width(0), - _height(0), _isTransparent(true) { result = false; @@ -130,10 +127,18 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) : // Uncompress the image int pitch; + byte *dst; + int w, h; if (isPNG) - result = ImgLoader::decodePNGImage(pFileData, fileSize, _data, _width, _height, pitch); + result = ImgLoader::decodePNGImage(pFileData, fileSize, dst, w, h, pitch); else - result = ImgLoader::decodeThumbnailImage(pFileData, fileSize, _data, _width, _height, pitch); + result = ImgLoader::decodeThumbnailImage(pFileData, fileSize, dst, w, h, pitch); + + _surface.w = w; + _surface.h = h; + _surface.pitch = w * 4; + _surface.setPixels(dst); + _surface.format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); if (!result) { error("Could not decode image."); @@ -157,12 +162,9 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) : // ----------------------------------------------------------------------------- RenderedImage::RenderedImage(uint width, uint height, bool &result) : - _width(width), - _height(height), _isTransparent(true) { - _data = new byte[width * height * 4]; - Common::fill(_data, &_data[width * height * 4], 0); + _surface.create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); _backSurface = Kernel::getInstance()->getGfx()->getSurface(); @@ -172,9 +174,11 @@ RenderedImage::RenderedImage(uint width, uint height, bool &result) : return; } -RenderedImage::RenderedImage() : _width(0), _height(0), _data(0), _isTransparent(true) { +RenderedImage::RenderedImage() : _isTransparent(true) { _backSurface = Kernel::getInstance()->getGfx()->getSurface(); + _surface.format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); + _doCleanup = false; return; @@ -183,8 +187,6 @@ RenderedImage::RenderedImage() : _width(0), _height(0), _data(0), _isTransparent // ----------------------------------------------------------------------------- RenderedImage::~RenderedImage() { - if (_doCleanup) - delete[] _data; } // ----------------------------------------------------------------------------- @@ -198,17 +200,17 @@ bool RenderedImage::fill(const Common::Rect *pFillRect, uint color) { bool RenderedImage::setContent(const byte *pixeldata, uint size, uint offset, uint stride) { // Check if PixelData contains enough pixel to create an image with image size equals width * height - if (size < static_cast<uint>(_width * _height * 4)) { - error("PixelData vector is too small to define a 32 bit %dx%d image.", _width, _height); + if (size < static_cast<uint>(_surface.w * _surface.h * 4)) { + error("PixelData vector is too small to define a 32 bit %dx%d image.", _surface.w, _surface.h); return false; } const byte *in = &pixeldata[offset]; - byte *out = _data; + byte *out = (byte *)_surface.getPixels(); - for (int i = 0; i < _height; i++) { - memcpy(out, in, _width * 4); - out += _width * 4; + for (int i = 0; i < _surface.h; i++) { + memcpy(out, in, _surface.w * 4); + out += _surface.w * 4; in += stride; } @@ -216,9 +218,10 @@ bool RenderedImage::setContent(const byte *pixeldata, uint size, uint offset, ui } void RenderedImage::replaceContent(byte *pixeldata, int width, int height) { - _width = width; - _height = height; - _data = pixeldata; + _surface.w = width; + _surface.h = height; + _surface.pitch = width * 4; + _surface.setPixels(pixeldata); } // ----------------------------------------------------------------------------- @@ -230,251 +233,26 @@ uint RenderedImage::getPixel(int x, int y) { // ----------------------------------------------------------------------------- bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, RectangleList *updateRects) { - int ca = (color >> 24) & 0xff; - - // Check if we need to draw anything at all - if (ca == 0) - return true; - - int cr = (color >> 16) & 0xff; - int cg = (color >> 8) & 0xff; - int cb = (color >> 0) & 0xff; - - // Create an encapsulating surface for the data - Graphics::Surface srcImage; - // TODO: Is the data really in the screen format? - srcImage.init(_width, _height, _width * 4, _data, g_system->getScreenFormat()); - - if (pPartRect) { - srcImage.setPixels(&_data[pPartRect->top * srcImage.pitch + pPartRect->left * 4]); - srcImage.w = pPartRect->right - pPartRect->left; - srcImage.h = pPartRect->bottom - pPartRect->top; - - debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, - pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height); - } else { - - debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0, - srcImage.w, srcImage.h, color, width, height); - } - - if (width == -1) - width = srcImage.w; - if (height == -1) - height = srcImage.h; - -#ifdef SCALING_TESTING - // Hardcode scaling to 66% to test scaling - width = width * 2 / 3; - height = height * 2 / 3; -#endif - - Graphics::Surface *img; - Graphics::Surface *imgScaled = NULL; - byte *savedPixels = NULL; - if ((width != srcImage.w) || (height != srcImage.h)) { - // Scale the image - img = imgScaled = scale(srcImage, width, height); - savedPixels = (byte *)img->getPixels(); - } else { - img = &srcImage; - } - - for (RectangleList::iterator it = updateRects->begin(); it != updateRects->end(); ++it) { - const Common::Rect &clipRect = *it; - - int skipLeft = 0, skipTop = 0; - int drawX = posX, drawY = posY; - int drawWidth = img->w; - int drawHeight = img->h; - - // Handle clipping - if (drawX < clipRect.left) { - skipLeft = clipRect.left - drawX; - drawWidth -= skipLeft; - drawX = clipRect.left; - } - - if (drawY < clipRect.top) { - skipTop = clipRect.top - drawY; - drawHeight -= skipTop; - drawY = clipRect.top; - } - - if (drawX + drawWidth >= clipRect.right) - drawWidth = clipRect.right - drawX; - - if (drawY + drawHeight >= clipRect.bottom) - drawHeight = clipRect.bottom - drawY; - - if ((drawWidth > 0) && (drawHeight > 0)) { - int xp = 0, yp = 0; - - int inStep = 4; - int inoStep = img->pitch; - if (flipping & Image::FLIP_V) { - inStep = -inStep; - xp = img->w - 1 - skipLeft; - } else { - xp = skipLeft; - } - - if (flipping & Image::FLIP_H) { - inoStep = -inoStep; - yp = img->h - 1 - skipTop; - } else { - yp = skipTop; - } - - byte *ino = (byte *)img->getBasePtr(xp, yp); - byte *outo = (byte *)_backSurface->getBasePtr(drawX, drawY); - -#if defined(SCUMM_LITTLE_ENDIAN) - // Simple memcpy if the source bitmap doesn't have transparent pixels and the drawing transparency is 255 - // NOTE Only possible with LE-machines at the moment, maybe it would be feasible to convert the bitmap pixels at loading time? - if (!_isTransparent && ca == 255) { - for (int i = 0; i < drawHeight; i++) { - memcpy(outo, ino, drawWidth * 4); - outo += _backSurface->pitch; - ino += inoStep; - } - } else -#endif - { - byte *in, *out; - for (int i = 0; i < drawHeight; i++) { - out = outo; - in = ino; - for (int j = 0; j < drawWidth; j++) { - uint32 pix = *(uint32 *)in; - int a = (pix >> 24) & 0xff; - in += inStep; - - if (ca != 255) { - a = a * ca >> 8; - } - - if (a == 0) { - // Full transparency - out += 4; - continue; - } - - int b = (pix >> 0) & 0xff; - int g = (pix >> 8) & 0xff; - int r = (pix >> 16) & 0xff; - - if (a == 255) { -#if defined(SCUMM_LITTLE_ENDIAN) - if (cb != 255) - b = (b * cb) >> 8; - if (cg != 255) - g = (g * cg) >> 8; - if (cr != 255) - r = (r * cr) >> 8; - *(uint32 *)out = (255 << 24) | (r << 16) | (g << 8) | b; - out += 4; -#else - *out++ = a; - if (cr != 255) - *out++ = (r * cr) >> 8; - else - *out++ = r; - if (cg != 255) - *out++ = (g * cg) >> 8; - else - *out++ = g; - if (cb != 255) - *out++ = (b * cb) >> 8; - else - *out++ = b; -#endif - } else { -#if defined(SCUMM_LITTLE_ENDIAN) - pix = *(uint32 *)out; - int outb = ((pix >> 0) & 0xff) * (255 - a); - int outg = ((pix >> 8) & 0xff) * (255 - a); - int outr = ((pix >> 16) & 0xff) * (255 - a); - if (cb == 0) - outb = outb >> 8; - else if (cb != 255) - outb = ((outb << 8) + b * a * cb) >> 16; - else - outb = (outb + b * a) >> 8; - if (cg == 0) - outg = outg >> 8; - else if (cg != 255) - outg = ((outg << 8) + g * a * cg) >> 16; - else - outg = (outg + g * a) >> 8; - if (cr == 0) - outr = outr >> 8; - else if (cr != 255) - outr = ((outr << 8) + r * a * cr) >> 16; - else - outr = (outr + r * a) >> 8; - *(uint32 *)out = (255 << 24) | (outr << 16) | (outg << 8) | outb; - out += 4; -#else - *out = 255; - out++; - if (cr == 0) - *out = (*out * (255-a)) >> 8; - else if (cr != 255) - *out = (((*out * (255-a)) << 8) + r * a * cr) >> 16; - else - *out = ((*out * (255-a)) + r * a) >> 8; - out++; - if (cg == 0) - *out = (*out * (255-a)) >> 8; - else if (cg != 255) - *out = (((*out * (255-a)) << 8) + g * a * cg) >> 16; - else - *out = ((*out * (255-a)) + g * a) >> 8; - out++; - if (cb == 0) - *out = (*out * (255-a)) >> 8; - else if (cb != 255) - *out = (((*out * (255-a)) << 8) + b * a * cb) >> 16; - else - *out = ((*out * (255-a)) + b * a) >> 8; - out++; -#endif - } - } - outo += _backSurface->pitch; - ino += inoStep; - } - } - - } - - } - - if (imgScaled) { - imgScaled->setPixels(savedPixels); - imgScaled->free(); - delete imgScaled; - } + _surface.blit(*_backSurface, posX, posY, (((flipping & 1) ? Graphics::FLIP_V : 0) | ((flipping & 2) ? Graphics::FLIP_H : 0)), pPartRect, color, width, height); return true; } void RenderedImage::copyDirectly(int posX, int posY) { - byte *data = _data; - int w = _width; - int h = _height; + byte *data = (byte *)_surface.getPixels(); + int w = _surface.w; + int h = _surface.h; // Handle off-screen clipping if (posY < 0) { - h = MAX(0, (int)_height - -posY); - data = (byte *)_data + _width * -posY; + h = MAX(0, (int)_surface.h - -posY); + data = (byte *)_surface.getPixels() + _surface.w * -posY; posY = 0; } if (posX < 0) { - w = MAX(0, (int)_width - -posX); - data = (byte *)_data + (-posX * 4); + w = MAX(0, (int)_surface.h - -posX); + data = (byte *)_surface.getPixels() + (-posX * 4); posX = 0; } @@ -487,9 +265,9 @@ void RenderedImage::copyDirectly(int posX, int posY) { void RenderedImage::checkForTransparency() { // Check if the source bitmap has any transparent pixels at all _isTransparent = false; - byte *data = _data; - for (int i = 0; i < _height; i++) { - for (int j = 0; j < _width; j++) { + byte *data = (byte *)_surface.getPixels(); + for (int i = 0; i < _surface.h; i++) { + for (int j = 0; j < _surface.w; j++) { _isTransparent = data[3] != 0xff; if (_isTransparent) return; diff --git a/engines/sword25/gfx/image/renderedimage.h b/engines/sword25/gfx/image/renderedimage.h index 3cc9725b12..5b65a27355 100644 --- a/engines/sword25/gfx/image/renderedimage.h +++ b/engines/sword25/gfx/image/renderedimage.h @@ -39,6 +39,7 @@ #include "sword25/kernel/common.h" #include "sword25/gfx/image/image.h" #include "sword25/gfx/graphicengine.h" +#include "graphics/transparent_surface.h" namespace Sword25 { @@ -60,10 +61,10 @@ public: virtual ~RenderedImage(); virtual int getWidth() const { - return _width; + return _surface.w; } virtual int getHeight() const { - return _height; + return _surface.h; } virtual GraphicEngine::COLOR_FORMATS getColorFormat() const { return GraphicEngine::CF_ARGB32; @@ -72,7 +73,7 @@ public: void copyDirectly(int posX, int posY); virtual bool blit(int posX = 0, int posY = 0, - int flipping = Image::FLIP_NONE, + int flipping = Graphics::FLIP_NONE, Common::Rect *pPartRect = NULL, uint color = BS_ARGB(255, 255, 255, 255), int width = -1, int height = -1, @@ -108,9 +109,7 @@ public: virtual bool isSolid() const { return !_isTransparent; } private: - byte *_data; - int _width; - int _height; + Graphics::TransparentSurface _surface; bool _doCleanup; bool _isTransparent; diff --git a/engines/sword25/gfx/image/swimage.h b/engines/sword25/gfx/image/swimage.h index b31c2318ec..60978eb6cc 100644 --- a/engines/sword25/gfx/image/swimage.h +++ b/engines/sword25/gfx/image/swimage.h @@ -55,7 +55,7 @@ public: } virtual bool blit(int posX = 0, int posY = 0, - int flipping = Image::FLIP_NONE, + int flipping = Graphics::FLIP_NONE, Common::Rect *pPartRect = NULL, uint color = BS_ARGB(255, 255, 255, 255), int width = -1, int height = -1, diff --git a/engines/sword25/gfx/image/vectorimage.h b/engines/sword25/gfx/image/vectorimage.h index a99d532e75..057064fc6a 100644 --- a/engines/sword25/gfx/image/vectorimage.h +++ b/engines/sword25/gfx/image/vectorimage.h @@ -209,7 +209,7 @@ public: } virtual bool setContent(const byte *pixeldata, uint size, uint offset, uint stride); virtual bool blit(int posX = 0, int posY = 0, - int flipping = FLIP_NONE, + int flipping = Graphics::FLIP_NONE, Common::Rect *pPartRect = NULL, uint color = BS_ARGB(255, 255, 255, 255), int width = -1, int height = -1, diff --git a/engines/sword25/gfx/image/vectorimagerenderer.cpp b/engines/sword25/gfx/image/vectorimagerenderer.cpp index c7a79fd3c4..c69cb497c1 100644 --- a/engines/sword25/gfx/image/vectorimagerenderer.cpp +++ b/engines/sword25/gfx/image/vectorimagerenderer.cpp @@ -52,7 +52,7 @@ void art_rgb_fill_run1(byte *buf, byte r, byte g, byte b, int n) { memset(buf, g, n + n + n + n); } else { uint32 *alt = (uint32 *)buf; - uint32 color = Graphics::ARGBToColor<Graphics::ColorMasks<8888> >(0xff, r, g, b); + uint32 color = Graphics::ARGBToColor<Graphics::ColorMasks<8888> >(r, g, b, 0xff); for (i = 0; i < n; i++) *alt++ = color; @@ -66,22 +66,22 @@ void art_rgb_run_alpha1(byte *buf, byte r, byte g, byte b, int alpha, int n) { for (i = 0; i < n; i++) { #if defined(SCUMM_LITTLE_ENDIAN) v = *buf; + *buf++ = MIN(v + alpha, 0xff); + v = *buf; *buf++ = v + (((b - v) * alpha + 0x80) >> 8); v = *buf; *buf++ = v + (((g - v) * alpha + 0x80) >> 8); v = *buf; *buf++ = v + (((r - v) * alpha + 0x80) >> 8); - v = *buf; - *buf++ = MIN(v + alpha, 0xff); #else v = *buf; - *buf++ = MIN(v + alpha, 0xff); - v = *buf; *buf++ = v + (((r - v) * alpha + 0x80) >> 8); v = *buf; *buf++ = v + (((g - v) * alpha + 0x80) >> 8); v = *buf; *buf++ = v + (((b - v) * alpha + 0x80) >> 8); + v = *buf; + *buf++ = MIN(v + alpha, 0xff); #endif } } diff --git a/engines/sword25/gfx/staticbitmap.cpp b/engines/sword25/gfx/staticbitmap.cpp index 14e2012d80..1a6c812508 100644 --- a/engines/sword25/gfx/staticbitmap.cpp +++ b/engines/sword25/gfx/staticbitmap.cpp @@ -98,14 +98,14 @@ bool StaticBitmap::doRender(RectangleList *updateRects) { bool result; if (_scaleFactorX == 1.0f && _scaleFactorY == 1.0f) { result = bitmapResourcePtr->blit(_absoluteX, _absoluteY, - (_flipV ? BitmapResource::FLIP_V : 0) | - (_flipH ? BitmapResource::FLIP_H : 0), + (_flipV ? Graphics::FLIP_V : 0) | + (_flipH ? Graphics::FLIP_H : 0), 0, _modulationColor, -1, -1, updateRects); } else { result = bitmapResourcePtr->blit(_absoluteX, _absoluteY, - (_flipV ? BitmapResource::FLIP_V : 0) | - (_flipH ? BitmapResource::FLIP_H : 0), + (_flipV ? Graphics::FLIP_V : 0) | + (_flipH ? Graphics::FLIP_H : 0), 0, _modulationColor, _width, _height, updateRects); } diff --git a/engines/sword25/gfx/text.cpp b/engines/sword25/gfx/text.cpp index b0a9e4ed3f..904435fcb0 100644 --- a/engines/sword25/gfx/text.cpp +++ b/engines/sword25/gfx/text.cpp @@ -99,7 +99,7 @@ void Text::setText(const Common::String &text) { } void Text::setColor(uint32 modulationColor) { - uint32 newModulationColor = (modulationColor & 0x00ffffff) | (_modulationColor & 0xff000000); + uint32 newModulationColor = (modulationColor & 0xffffff00) | (_modulationColor & 0x000000ff); if (newModulationColor != _modulationColor) { _modulationColor = newModulationColor; forceRefresh(); @@ -108,7 +108,7 @@ void Text::setColor(uint32 modulationColor) { void Text::setAlpha(int alpha) { assert(alpha >= 0 && alpha < 256); - uint32 newModulationColor = (_modulationColor & 0x00ffffff) | alpha << 24; + uint32 newModulationColor = (_modulationColor & 0xffffff00) | alpha; if (newModulationColor != _modulationColor) { _modulationColor = newModulationColor; forceRefresh(); @@ -173,7 +173,7 @@ bool Text::doRender(RectangleList *updateRects) { Common::Rect renderRect(curX, curY, curX + curRect.width(), curY + curRect.height()); renderRect.translate(curRect.left - curX, curRect.top - curY); - result = charMapPtr->blit(curX, curY, Image::FLIP_NONE, &renderRect, _modulationColor, -1, -1, updateRects); + result = charMapPtr->blit(curX, curY, Graphics::FLIP_NONE, &renderRect, _modulationColor, -1, -1, updateRects); if (!result) break; diff --git a/engines/sword25/sword25.cpp b/engines/sword25/sword25.cpp index 259deb2ea8..bb0aab3ad4 100644 --- a/engines/sword25/sword25.cpp +++ b/engines/sword25/sword25.cpp @@ -97,7 +97,7 @@ Common::Error Sword25Engine::run() { Common::Error Sword25Engine::appStart() { // Initialize the graphics mode to ARGB8888 - Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24); + Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); initGraphics(800, 600, true, &format); if (format != g_system->getScreenFormat()) return Common::kUnsupportedColorMode; diff --git a/engines/testbed/sound.cpp b/engines/testbed/sound.cpp index aebd981826..998afbf7db 100644 --- a/engines/testbed/sound.cpp +++ b/engines/testbed/sound.cpp @@ -235,7 +235,7 @@ TestExitStatus SoundSubsystem::sampleRates() { Common::Point pt(0, 100); mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, s1); - Testsuite::writeOnScreen(Common::String::format("Playing at smaple rate: %d", s1->getRate()), pt); + Testsuite::writeOnScreen(Common::String::format("Playing at sample rate: %d", s1->getRate()), pt); g_system->delayMillis(1000); mixer->stopHandle(handle); g_system->delayMillis(1000); diff --git a/engines/toltecs/detection.cpp b/engines/toltecs/detection.cpp index b6c7ad3d2b..e8f08bcc61 100644 --- a/engines/toltecs/detection.cpp +++ b/engines/toltecs/detection.cpp @@ -86,6 +86,20 @@ static const ToltecsGameDescription gameDescriptions[] = { }, { + // 3 Skulls of the Toltecs PIRATE CD-RIP version (no audio) + // == DO NOT RE-ADD == + { + "toltecs", + 0, + AD_ENTRY1s("WESTERN", "56d0da91ec3db8ac869594357584e851", 104804435), + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_PIRATED, + GUIO1(GUIO_NONE) + }, + }, + + { // 3 Skulls of the Toltecs Russian version { "toltecs", diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp index 14e7d104d2..2f5051c157 100644 --- a/engines/toon/toon.cpp +++ b/engines/toon/toon.cpp @@ -2037,23 +2037,19 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) { } } - int32 myId = 0; char *myLine; - if (dialogid < 1000) { + if (dialogid < 1000) myLine = _roomTexts->getText(dialogid); - myId = dialogid; - } else { + else myLine = _genericTexts->getText(dialogid - 1000); - myId = dialogid - 1000; - } if (!myLine) return 0; bool oldMouseHidden = _gameState->_mouseHidden; - if (blocking) { + if (blocking) _gameState->_mouseHidden = true; - } + // get what is before the string int a = READ_LE_UINT16(myLine - 2); @@ -2090,10 +2086,8 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) { while ((waitChar->getAnimFlag() & 0x10) == 0x10 && !_shouldQuit) doFrame(); } - } else { - if (_audioManager->voiceStillPlaying()) - _audioManager->stopCurrentVoice(); - } + } else if (_audioManager->voiceStillPlaying()) + _audioManager->stopCurrentVoice(); for (int32 i = 0; i < numParticipants - 1; i++) { // listener @@ -2133,10 +2127,10 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) { getTextPosition(talkerId, &_currentTextLineX, &_currentTextLineY); if (dialogid < 1000) { - myId = _roomTexts->getId(dialogid); + int myId = _roomTexts->getId(dialogid); _audioManager->playVoice(myId, false); } else { - myId = _genericTexts->getId(dialogid - 1000); + int myId = _genericTexts->getId(dialogid - 1000); _audioManager->playVoice(myId, true); } diff --git a/engines/tsage/ringworld/ringworld_scenes10.cpp b/engines/tsage/ringworld/ringworld_scenes10.cpp index c4874c0f59..99c953217c 100644 --- a/engines/tsage/ringworld/ringworld_scenes10.cpp +++ b/engines/tsage/ringworld/ringworld_scenes10.cpp @@ -1004,7 +1004,7 @@ void Scene9450::postInit(SceneObjectList *OwnerList) { _hotspot8.setDetails(110, 0, 199, 117, 9450, 7, 8); _hotspot9.setDetails(101, 104, 130, 174, 9450, 9, 10); _hotspot10.setDetails(110, 246, 149, 319, 9450, 11, 12); - _hotspot11.setDetails(16, 34, 74, 62, 6450, 13, 14); + _hotspot11.setDetails(16, 34, 74, 62, 9450, 13, 14); _hotspot12.setDetails(19, 108, 72, 134, 9450, 15, 16); _hotspot13.setDetails(18, 215, 71, 237, 9450, 17, 18); _hotspot14.setDetails(15, 288, 76, 314, 9450, 19, 20); diff --git a/engines/tsage/ringworld2/ringworld2_logic.h b/engines/tsage/ringworld2/ringworld2_logic.h index 31d801fa55..d95f279e27 100644 --- a/engines/tsage/ringworld2/ringworld2_logic.h +++ b/engines/tsage/ringworld2/ringworld2_logic.h @@ -320,7 +320,7 @@ public: int pixelToCellXY(Common::Point &pt); virtual Common::String getClassName() { return "MazeUI"; } - void synchronize(Serializer &s); + virtual void synchronize(Serializer &s); virtual void reposition(); virtual void draw(); }; diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.cpp b/engines/tsage/ringworld2/ringworld2_scenes1.cpp index 29646d1612..e2c22bd0b4 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp @@ -1919,7 +1919,7 @@ void Scene1200::process(Event &event) { return; } } else if (event.eventType == EVENT_KEYPRESS) { - if (_field414 == 0) { + if (_field414) { event.handled = false; return; } diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.cpp b/engines/tsage/ringworld2/ringworld2_scenes3.cpp index 3f32503fdf..9eaead630b 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes3.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes3.cpp @@ -2843,8 +2843,8 @@ void Scene3400::signal() { R2_INVENTORY.setObjectScene(R2_SAPPHIRE_BLUE, 0); _stripManager.start(3307, this); if (R2_GLOBALS._player._characterIndex == R2_SEEKER) { - _sceneMode = 3400; - R2_GLOBALS._player.setAction(&_sequenceManager, this, 3400, &R2_GLOBALS._player, &_teal, &_sapphire, NULL); + _sceneMode = 3404; + R2_GLOBALS._player.setAction(&_sequenceManager, this, 3404, &R2_GLOBALS._player, &_teal, &_sapphire, NULL); } else { _sceneMode = 3408; _companion1.setAction(&_sequenceManager, this, 3408, &_companion1, &_teal, &_sapphire, NULL); @@ -3668,11 +3668,12 @@ void Scene3500::postInit(SceneObjectList *OwnerList) { _horizontalSpeedDisplay.setPosition(Common::Point(126, 108)); _horizontalSpeedDisplay.fixPriority(200); + _action1._turningFl = false; + + _mazeUI.postInit(); _mazeUI.setDisplayBounds(Rect(160, 89, 299, 182)); _mazeUI.load(2); _mazeUI.setMazePosition(_mazePosition); - - _action1._turningFl = false; _mazeUI.draw(); _directionChangesEnabled = true; @@ -3876,6 +3877,11 @@ void Scene3500::dispatch() { Rect tmpRect; Scene::dispatch(); + // WORKAROUND: The _mazeUI wasn't originally added to the scene in postInit. + // This is only needed to fix old savegames + if (!R2_GLOBALS._sceneObjects->contains(&_mazeUI)) + _mazeUI.draw(); + if (((_shuttle._frame % 2) == 0) && (!_action1._turningFl)) { _shuttle.setFrame(_shuttle.changeFrame()); _mazeDirection = _shuttle._frame; @@ -4215,7 +4221,6 @@ void Scene3500::dispatch() { _rotation->_idxChange = 0; } - _mazeUI.draw(); if (_exitCounter != 0) ++_exitCounter; } diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp index c5c38505a7..b95b614f09 100644 --- a/engines/tsage/sound.cpp +++ b/engines/tsage/sound.cpp @@ -164,7 +164,7 @@ Common::List<SoundDriverEntry> &SoundManager::buildDriverList(bool detectFlag) { sd._status = detectFlag ? SNDSTATUS_DETECTED : SNDSTATUS_SKIPPED; sd._field2 = 0; sd._field6 = 15000; - sd._shortDescription = "Adlib or SoundBlaster"; + sd._shortDescription = "AdLib or SoundBlaster"; sd._longDescription = "3812fm"; _availableDrivers.push_back(sd); @@ -379,7 +379,6 @@ void SoundManager::updateSoundLoop(Sound *sound) { } void SoundManager::rethinkVoiceTypes() { - Common::StackLock slock(sfManager()._serverSuspendedMutex); sfRethinkVoiceTypes(); } @@ -1442,8 +1441,6 @@ bool SoundManager::sfDoRemoveFromPlayList(Sound *sound) { } void SoundManager::sfDoUpdateVolume(Sound *sound) { - Common::StackLock slock(sfManager()._serverSuspendedMutex); - for (int voiceIndex = 0; voiceIndex < SOUND_ARR_SIZE; ++voiceIndex) { VoiceTypeStruct *vs = sfManager()._voiceTypeStructPtrs[voiceIndex]; if (!vs) @@ -1707,8 +1704,6 @@ void Sound::pause(bool flag) { } void Sound::mute(bool flag) { - Common::StackLock slock(g_globals->_soundManager._serverSuspendedMutex); - if (flag) ++_mutedCount; else if (_mutedCount > 0) diff --git a/engines/voyeur/configure.engine b/engines/voyeur/configure.engine index 23891fccb7..c53530a9ed 100644 --- a/engines/voyeur/configure.engine +++ b/engines/voyeur/configure.engine @@ -1,4 +1,4 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine voyeur "Voyeur" no +add_engine voyeur "Voyeur" yes diff --git a/engines/voyeur/files_threads.cpp b/engines/voyeur/files_threads.cpp index b1960a23ac..0615c67ba0 100644 --- a/engines/voyeur/files_threads.cpp +++ b/engines/voyeur/files_threads.cpp @@ -1007,8 +1007,11 @@ int ThreadResource::doApt() { if (_vm->_loadGameSlot != -1) { // Load a savegame - _vm->loadGame(_vm->_loadGameSlot); + int slot = _vm->_loadGameSlot; _vm->_loadGameSlot = -1; + _vm->loadGame(slot); + + _vm->_eventsManager->showCursor(); } _vm->_eventsManager->getMouseInfo(); @@ -1596,7 +1599,9 @@ void ThreadResource::loadTheApt() { _vm->_voy->_aptLoadMode = -1; if (_vm->_voy->_aptLoadMode != -1) { - doAptAnim(1); + if (_vm->_loadGameSlot != -1) + doAptAnim(1); + _vm->_bVoy->getBoltGroup(_vm->_playStampGroupId); _vm->_voy->_aptLoadMode = -1; _vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry( diff --git a/engines/voyeur/voyeur.cpp b/engines/voyeur/voyeur.cpp index 681f431635..dad634c9bb 100644 --- a/engines/voyeur/voyeur.cpp +++ b/engines/voyeur/voyeur.cpp @@ -556,6 +556,7 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) { PictureResource *pic = NULL; if (videoId == 42) { + _bVoy->getBoltGroup(0xE00); _eventsManager->_videoDead = 0; pic = _bVoy->boltEntry(0xE00 + _eventsManager->_videoDead)._picResource; } @@ -602,6 +603,9 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) { pic->_imgData = imgData; _voy->_eventFlags &= ~EVTFLAG_8; } + + if (videoId == 42) + _bVoy->freeBoltGroup(0xE00); } void VoyeurEngine::playAudio(int audioId) { diff --git a/engines/wintermute/base/base_file_manager.cpp b/engines/wintermute/base/base_file_manager.cpp index 1f78303f52..58684b66a0 100644 --- a/engines/wintermute/base/base_file_manager.cpp +++ b/engines/wintermute/base/base_file_manager.cpp @@ -209,10 +209,15 @@ bool BaseFileManager::registerPackages() { // than the equivalent of using equalsIgnoreCase. Common::String fileName = fileIt->getName(); fileName.toLowercase(); + bool searchSignature = false; - if (!fileName.hasSuffix(".dcp")) { + if (!fileName.hasSuffix(".dcp") && !fileName.hasSuffix(".exe")) { continue; } + if (fileName.hasSuffix(".exe")) { + searchSignature = true; + } + // HACK: for Reversion1, avoid loading xlanguage_pt.dcp from the main folder: if (_language != Common::PT_BRA && targetName.hasPrefix("reversion1")) { if (fileName == "xlanguage_pt.dcp") { @@ -263,7 +268,7 @@ bool BaseFileManager::registerPackages() { } } debugC(kWintermuteDebugFileAccess, "Registering %s %s", fileIt->getPath().c_str(), fileIt->getName().c_str()); - registerPackage((*fileIt)); + registerPackage((*fileIt), "", searchSignature); } } diff --git a/engines/wintermute/base/base_file_manager.h b/engines/wintermute/base/base_file_manager.h index 653721c8f5..d953e44704 100644 --- a/engines/wintermute/base/base_file_manager.h +++ b/engines/wintermute/base/base_file_manager.h @@ -63,7 +63,6 @@ private: Common::SeekableReadStream *openFileRaw(const Common::String &filename); Common::SeekableReadStream *openPkgFile(const Common::String &filename); Common::FSList _packagePaths; - bool findPackageSignature(Common::SeekableReadStream *f, uint32 *offset); bool registerPackage(Common::FSNode package, const Common::String &filename = "", bool searchSignature = false); bool _detectionMode; Common::SearchSet _packages; diff --git a/engines/wintermute/base/base_frame.cpp b/engines/wintermute/base/base_frame.cpp index f2c24b8f6a..471185f2d2 100644 --- a/engines/wintermute/base/base_frame.cpp +++ b/engines/wintermute/base/base_frame.cpp @@ -76,7 +76,7 @@ BaseFrame::~BaseFrame() { ////////////////////////////////////////////////////////////////////// -bool BaseFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, bool allFrames, float rotate, TSpriteBlendMode blendMode) { +bool BaseFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, bool allFrames, float rotate, Graphics::TSpriteBlendMode blendMode) { bool res; for (uint32 i = 0; i < _subframes.size(); i++) { diff --git a/engines/wintermute/base/base_frame.h b/engines/wintermute/base/base_frame.h index 49a56592bb..ff9e67a166 100644 --- a/engines/wintermute/base/base_frame.h +++ b/engines/wintermute/base/base_frame.h @@ -31,6 +31,7 @@ #include "engines/wintermute/base/base_scriptable.h" #include "engines/wintermute/coll_templ.h" +#include "graphics/transform_struct.h" namespace Wintermute { class BaseSound; @@ -51,7 +52,7 @@ public: int32 _moveX; uint32 _delay; BaseArray<BaseSubFrame *> _subframes; - bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, bool allFrames = false, float rotate = 0.0f, TSpriteBlendMode blendMode = BLEND_NORMAL); + bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, bool allFrames = false, float rotate = 0.0f, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL); bool loadBuffer(char *buffer, int lifeTime, bool keepLoaded); BaseFrame(BaseGame *inGame); diff --git a/engines/wintermute/base/base_game.cpp b/engines/wintermute/base/base_game.cpp index d37a22e2a6..8df39c825a 100644 --- a/engines/wintermute/base/base_game.cpp +++ b/engines/wintermute/base/base_game.cpp @@ -3110,6 +3110,10 @@ bool BaseGame::persist(BasePersistenceManager *persistMgr) { persistMgr->transferUint32(TMEMBER(_autoSaveSlot)); persistMgr->transferBool(TMEMBER(_cursorHidden)); + if (persistMgr->checkVersion(1, 3, 1)) { + _settings->persist(persistMgr); + } + if (!persistMgr->getIsSaving()) { _quitting = false; } diff --git a/engines/wintermute/base/base_game_settings.cpp b/engines/wintermute/base/base_game_settings.cpp index 3b54384cc7..61c5894be3 100644 --- a/engines/wintermute/base/base_game_settings.cpp +++ b/engines/wintermute/base/base_game_settings.cpp @@ -219,4 +219,8 @@ char *BaseGameSettings::getKeyFromStringTable(const char *str) const { return _stringTable->getKey(str); } +bool BaseGameSettings::persist(BasePersistenceManager *persistMgr) { + return _stringTable->persist(persistMgr); +} + } // End of namespace Wintermute diff --git a/engines/wintermute/base/base_game_settings.h b/engines/wintermute/base/base_game_settings.h index fe0e9907e6..2059cb075e 100644 --- a/engines/wintermute/base/base_game_settings.h +++ b/engines/wintermute/base/base_game_settings.h @@ -34,6 +34,7 @@ namespace Wintermute { class BaseStringTable; class BaseGame; +class BasePersistenceManager; class BaseGameSettings { public: const char *getGameFile() const { return (_gameFile ? _gameFile : "default.game"); } @@ -46,6 +47,8 @@ public: bool loadStringTable(const char *filename, bool clearOld); void expandStringByStringTable(char **str) const; char *getKeyFromStringTable(const char *str) const; + + bool persist(BasePersistenceManager *persistMgr); private: char *_gameFile; int _resWidth; diff --git a/engines/wintermute/base/base_object.cpp b/engines/wintermute/base/base_object.cpp index 708df8def1..cce3561f67 100644 --- a/engines/wintermute/base/base_object.cpp +++ b/engines/wintermute/base/base_object.cpp @@ -95,7 +95,7 @@ BaseObject::BaseObject(BaseGame *inGame) : BaseScriptHolder(inGame) { _sFXType = SFX_NONE; _sFXParam1 = _sFXParam2 = _sFXParam3 = _sFXParam4 = 0; - _blendMode = BLEND_NORMAL; + _blendMode = Graphics::BLEND_NORMAL; } @@ -807,10 +807,10 @@ bool BaseObject::scSetProperty(const char *name, ScValue *value) { ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "BlendMode") == 0) { int i = value->getInt(); - if (i < BLEND_NORMAL || i >= NUM_BLEND_MODES) { - i = BLEND_NORMAL; + if (i < Graphics::BLEND_NORMAL || i >= Graphics::NUM_BLEND_MODES) { + i = Graphics::BLEND_NORMAL; } - _blendMode = (TSpriteBlendMode)i; + _blendMode = (Graphics::TSpriteBlendMode)i; return STATUS_OK; } diff --git a/engines/wintermute/base/base_object.h b/engines/wintermute/base/base_object.h index f5036f4ec4..8ca8ffc246 100644 --- a/engines/wintermute/base/base_object.h +++ b/engines/wintermute/base/base_object.h @@ -33,6 +33,7 @@ #include "engines/wintermute/base/base_script_holder.h" #include "engines/wintermute/persistent.h" #include "common/events.h" +#include "graphics/transform_struct.h" namespace Wintermute { @@ -75,7 +76,7 @@ protected: int32 _iD; char *_soundEvent; public: - TSpriteBlendMode _blendMode; + Graphics::TSpriteBlendMode _blendMode; virtual bool afterMove(); float _scale; uint32 _alphaColor; diff --git a/engines/wintermute/base/base_persistence_manager.cpp b/engines/wintermute/base/base_persistence_manager.cpp index bea55fb857..bb5e0c4091 100644 --- a/engines/wintermute/base/base_persistence_manager.cpp +++ b/engines/wintermute/base/base_persistence_manager.cpp @@ -36,7 +36,7 @@ #include "engines/wintermute/base/gfx/base_image.h" #include "engines/wintermute/base/save_thumb_helper.h" #include "engines/wintermute/base/sound/base_sound.h" -#include "engines/wintermute/graphics/transparent_surface.h" +#include "graphics/transparent_surface.h" #include "engines/wintermute/wintermute.h" #include "graphics/scaler.h" #include "image/bmp.h" @@ -173,7 +173,7 @@ void BasePersistenceManager::getSaveStateDesc(int slot, SaveStateDescriptor &des Image::BitmapDecoder bmpDecoder; if (bmpDecoder.loadStream(thumbStream)) { const Graphics::Surface *bmpSurface = bmpDecoder.getSurface(); - TransparentSurface *scaleableSurface = new TransparentSurface(*bmpSurface, false); + Graphics::TransparentSurface *scaleableSurface = new Graphics::TransparentSurface(*bmpSurface, false); Graphics::Surface *scaled = scaleableSurface->scale(kThumbnailWidth, kThumbnailHeight2); Graphics::Surface *thumb = scaled->convertTo(g_system->getOverlayFormat()); desc.setThumbnail(thumb); diff --git a/engines/wintermute/base/base_sprite.cpp b/engines/wintermute/base/base_sprite.cpp index 2e00998037..04060bff32 100644 --- a/engines/wintermute/base/base_sprite.cpp +++ b/engines/wintermute/base/base_sprite.cpp @@ -418,7 +418,7 @@ bool BaseSprite::getCurrentFrame(float zoomX, float zoomY) { ////////////////////////////////////////////////////////////////////// -bool BaseSprite::display(int x, int y, BaseObject *registerVal, float zoomX, float zoomY, uint32 alpha, float rotate, TSpriteBlendMode blendMode) { +bool BaseSprite::display(int x, int y, BaseObject *registerVal, float zoomX, float zoomY, uint32 alpha, float rotate, Graphics::TSpriteBlendMode blendMode) { if (_currentFrame < 0 || _currentFrame >= (int32)_frames.size()) { return STATUS_OK; } diff --git a/engines/wintermute/base/base_sprite.h b/engines/wintermute/base/base_sprite.h index 92287995d9..ec71512ec9 100644 --- a/engines/wintermute/base/base_sprite.h +++ b/engines/wintermute/base/base_sprite.h @@ -32,7 +32,7 @@ #include "engines/wintermute/coll_templ.h" #include "engines/wintermute/base/base_script_holder.h" -#include "engines/wintermute/graphics/transform_tools.h" +#include "graphics/transform_tools.h" namespace Wintermute { class BaseFrame; @@ -45,17 +45,17 @@ public: void setDefaults(); DECLARE_PERSISTENT(BaseSprite, BaseScriptHolder) - bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = kDefaultZoomX, float scaleY = kDefaultZoomY); + bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = Graphics::kDefaultZoomX, float scaleY = Graphics::kDefaultZoomY); int32 _moveY; int32 _moveX; - bool display(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY, uint32 alpha = kDefaultRgbaMod, float rotate = kDefaultAngle, TSpriteBlendMode blendMode = BLEND_NORMAL); - bool getCurrentFrame(float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY); + bool display(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = Graphics::kDefaultZoomX, float zoomY = Graphics::kDefaultZoomY, uint32 alpha = Graphics::kDefaultRgbaMod, float rotate = Graphics::kDefaultAngle, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL); + bool getCurrentFrame(float zoomX = Graphics::kDefaultZoomX, float zoomY = Graphics::kDefaultZoomY); void reset(); bool isChanged(); bool isFinished(); bool loadBuffer(char *buffer, bool compete = true, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL); bool loadFile(const Common::String &filename, int lifeTime = -1, TSpriteCacheType cacheType = CACHE_ALL); - bool draw(int x, int y, BaseObject *Register = nullptr, float zoomX = kDefaultZoomX, float zoomY = kDefaultZoomY, uint32 alpha = kDefaultRgbaMod); + bool draw(int x, int y, BaseObject *Register = nullptr, float zoomX = Graphics::kDefaultZoomX, float zoomY = Graphics::kDefaultZoomY, uint32 alpha = Graphics::kDefaultRgbaMod); bool _looping; int32 _currentFrame; bool addFrame(const char *filename, uint32 delay = 0, int hotspotX = 0, int hotspotY = 0, Rect32 *rect = nullptr); diff --git a/engines/wintermute/base/base_string_table.cpp b/engines/wintermute/base/base_string_table.cpp index 9adbbdf7be..89407a7b0e 100644 --- a/engines/wintermute/base/base_string_table.cpp +++ b/engines/wintermute/base/base_string_table.cpp @@ -189,8 +189,10 @@ bool BaseStringTable::loadFile(const char *filename, bool clearOld) { BaseEngine::LOG(0, "Loading string table..."); if (clearOld) { + _filenames.clear(); _strings.clear(); } + _filenames.push_back(Common::String(filename)); uint32 size; byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename, &size); @@ -253,4 +255,27 @@ bool BaseStringTable::loadFile(const char *filename, bool clearOld) { return STATUS_OK; } +bool BaseStringTable::persist(BasePersistenceManager *persistMgr) { + // Do nothing if the save game is too old. + if (!persistMgr->checkVersion(1, 3, 1)) { + return true; + } + uint32 numFiles = _filenames.size(); + persistMgr->transferUint32("NumFiles", &numFiles); + if (persistMgr->getIsSaving()) { + for (uint i = 0; i < numFiles; i++) { + persistMgr->transferString("Filename", &_filenames[i]); + } + } else { + _strings.clear(); + _filenames.clear(); + for (uint i = 0; i < numFiles; i++) { + Common::String filename = ""; + persistMgr->transferString("Filename", &filename); + loadFile(filename.c_str(), false); + } + } + return true; +} + } // End of namespace Wintermute diff --git a/engines/wintermute/base/base_string_table.h b/engines/wintermute/base/base_string_table.h index 9e915a1ad9..cdcf11917d 100644 --- a/engines/wintermute/base/base_string_table.h +++ b/engines/wintermute/base/base_string_table.h @@ -35,6 +35,8 @@ namespace Wintermute { +class BasePersistenceManager; + class BaseStringTable : public BaseClass { public: bool loadFile(const char *filename, bool deleteAll = true); @@ -44,8 +46,10 @@ public: BaseStringTable(BaseGame *inGame); virtual ~BaseStringTable(); char *getKey(const char *str) const; + bool persist(BasePersistenceManager *persistMgr); private: Common::HashMap<Common::String, Common::String> _strings; + Common::Array<Common::String> _filenames; typedef Common::HashMap<Common::String, Common::String>::const_iterator StringsIter; }; diff --git a/engines/wintermute/base/base_sub_frame.cpp b/engines/wintermute/base/base_sub_frame.cpp index 3a6e28b1f2..4388942064 100644 --- a/engines/wintermute/base/base_sub_frame.cpp +++ b/engines/wintermute/base/base_sub_frame.cpp @@ -37,8 +37,8 @@ #include "engines/wintermute/base/gfx/base_renderer.h" #include "engines/wintermute/base/scriptables/script_value.h" #include "engines/wintermute/base/scriptables/script_stack.h" -#include "engines/wintermute/graphics/transform_tools.h" -#include "engines/wintermute/graphics/transform_struct.h" +#include "graphics/transform_tools.h" +#include "graphics/transform_struct.h" namespace Wintermute { @@ -47,9 +47,9 @@ IMPLEMENT_PERSISTENT(BaseSubFrame, false) ////////////////////////////////////////////////////////////////////////// BaseSubFrame::BaseSubFrame(BaseGame *inGame) : BaseScriptable(inGame, true) { _surface = nullptr; - _hotspotX = kDefaultHotspotX; - _hotspotY = kDefaultHotspotY; - _alpha = kDefaultRgbaMod; + _hotspotX = Graphics::kDefaultHotspotX; + _hotspotY = Graphics::kDefaultHotspotY; + _alpha = Graphics::kDefaultRgbaMod; _transparent = 0xFFFF00FF; _wantsDefaultRect = false; @@ -234,7 +234,7 @@ const char* BaseSubFrame::getSurfaceFilename() { } ////////////////////////////////////////////////////////////////////// -bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, float rotate, TSpriteBlendMode blendMode) { +bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, float zoomY, bool precise, uint32 alpha, float rotate, Graphics::TSpriteBlendMode blendMode) { rotate = fmod(rotate, 360.0f); if (rotate < 0) { @@ -246,7 +246,7 @@ bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, fl } if (registerOwner != nullptr && !_decoration) { - if (zoomX == kDefaultZoomX && zoomY == kDefaultZoomY) { + if (zoomX == Graphics::kDefaultZoomX && zoomY == Graphics::kDefaultZoomY) { BaseEngine::getRenderer()->addRectToList(new BaseActiveRect(_gameRef, registerOwner, this, x - _hotspotX + getRect().left, y - _hotspotY + getRect().top, getRect().right - getRect().left, getRect().bottom - getRect().top, zoomX, zoomY, precise)); } else { BaseEngine::getRenderer()->addRectToList(new BaseActiveRect(_gameRef, registerOwner, this, (int)(x - (_hotspotX + getRect().left) * (zoomX / 100)), (int)(y - (_hotspotY + getRect().top) * (zoomY / 100)), (int)((getRect().right - getRect().left) * (zoomX / 100)), (int)((getRect().bottom - getRect().top) * (zoomY / 100)), zoomX, zoomY, precise)); @@ -259,24 +259,26 @@ bool BaseSubFrame::draw(int x, int y, BaseObject *registerOwner, float zoomX, fl bool res; //if (Alpha==0xFFFFFFFF) Alpha = _alpha; // TODO: better (combine owner's and self alpha) - if (_alpha != kDefaultRgbaMod) { + if (_alpha != Graphics::kDefaultRgbaMod) { alpha = _alpha; } - if (rotate != kDefaultAngle) { - Point32 boxOffset, rotatedHotspot, hotspotOffset, newOrigin; - Point32 origin(x, y); - Rect32 oldRect = getRect(); - Point32 newHotspot; - TransformStruct transform = TransformStruct(zoomX, zoomY, (uint32)rotate, _hotspotX, _hotspotY, blendMode, alpha, _mirrorX, _mirrorY, 0, 0); - Rect32 newRect = TransformTools::newRect (oldRect, transform, &newHotspot); + if (rotate != Graphics::kDefaultAngle) { + Point32 boxOffset, rotatedHotspot, hotspotOffset; + Common::Point origin(x, y); + Common::Point newOrigin; + Rect32 oldRect1 = getRect(); + Common::Rect oldRect(oldRect1.top, oldRect1.left, oldRect1.bottom, oldRect1.right); + Common::Point newHotspot; + Graphics::TransformStruct transform = Graphics::TransformStruct(zoomX, zoomY, (uint32)rotate, _hotspotX, _hotspotY, blendMode, alpha, _mirrorX, _mirrorY, 0, 0); + Rect32 newRect = Graphics::TransformTools::newRect(oldRect, transform, &newHotspot); newOrigin = origin - newHotspot; res = _surface->displayTransform(newOrigin.x, newOrigin.y, oldRect, newRect, transform); } else { - if (zoomX == kDefaultZoomX && zoomY == kDefaultZoomY) { + if (zoomX == Graphics::kDefaultZoomX && zoomY == Graphics::kDefaultZoomY) { res = _surface->displayTrans(x - _hotspotX, y - _hotspotY, getRect(), alpha, blendMode, _mirrorX, _mirrorY); } else { - res = _surface->displayTransZoom((int)(x - _hotspotX * (zoomX / kDefaultZoomX)), (int)(y - _hotspotY * (zoomY / kDefaultZoomY)), getRect(), zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY); + res = _surface->displayTransZoom((int)(x - _hotspotX * (zoomX / Graphics::kDefaultZoomX)), (int)(y - _hotspotY * (zoomY / Graphics::kDefaultZoomY)), getRect(), zoomX, zoomY, alpha, blendMode, _mirrorX, _mirrorY); } } diff --git a/engines/wintermute/base/base_sub_frame.h b/engines/wintermute/base/base_sub_frame.h index b2859fa3f3..f156c332d6 100644 --- a/engines/wintermute/base/base_sub_frame.h +++ b/engines/wintermute/base/base_sub_frame.h @@ -32,6 +32,7 @@ #include "engines/wintermute/base/base.h" #include "engines/wintermute/base/base_scriptable.h" +#include "graphics/transform_struct.h" namespace Wintermute { class BaseObject; @@ -52,7 +53,7 @@ public: BaseSubFrame(BaseGame *inGame); virtual ~BaseSubFrame(); bool loadBuffer(char *buffer, int lifeTime, bool keepLoaded); - bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, float rotate = 0.0f, TSpriteBlendMode blendMode = BLEND_NORMAL); + bool draw(int x, int y, BaseObject *registerOwner = nullptr, float zoomX = 100, float zoomY = 100, bool precise = true, uint32 alpha = 0xFFFFFFFF, float rotate = 0.0f, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL); bool getBoundingRect(Rect32 *rect, int x, int y, float scaleX = 100, float scaleY = 100); const char* getSurfaceFilename(); diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp index df9a8648db..f27b565a7f 100644 --- a/engines/wintermute/base/font/base_font_truetype.cpp +++ b/engines/wintermute/base/font/base_font_truetype.cpp @@ -234,7 +234,7 @@ void BaseFontTT::drawText(const byte *text, int x, int y, int width, TTextAlign color = BYTETORGBA(RGBCOLGetR(color), RGBCOLGetG(color), RGBCOLGetB(color), RGBCOLGetA(renderer->_forceAlphaColor)); renderer->_forceAlphaColor = 0; } - surface->displayTransOffset(x, y - textOffset, rc, color, BLEND_NORMAL, false, false, _layers[i]->_offsetX, _layers[i]->_offsetY); + surface->displayTransOffset(x, y - textOffset, rc, color, Graphics::BLEND_NORMAL, false, false, _layers[i]->_offsetX, _layers[i]->_offsetY); renderer->_forceAlphaColor = origForceAlpha; } diff --git a/engines/wintermute/base/gfx/base_image.cpp b/engines/wintermute/base/gfx/base_image.cpp index e676fafdbf..a1548b83ea 100644 --- a/engines/wintermute/base/gfx/base_image.cpp +++ b/engines/wintermute/base/gfx/base_image.cpp @@ -28,7 +28,7 @@ #include "engines/wintermute/base/gfx/base_image.h" #include "engines/wintermute/base/base_file_manager.h" -#include "engines/wintermute/graphics/transparent_surface.h" +#include "graphics/transparent_surface.h" #include "graphics/surface.h" #include "image/png.h" #include "image/jpeg.h" @@ -112,7 +112,7 @@ bool BaseImage::saveBMPFile(const Common::String &filename) const { ////////////////////////////////////////////////////////////////////////// bool BaseImage::resize(int newWidth, int newHeight) { // WME Lite used FILTER_BILINEAR with FreeImage_Rescale here. - TransparentSurface temp(*_surface, true); + Graphics::TransparentSurface temp(*_surface, true); if (_deletableSurface) { _deletableSurface->free(); delete _deletableSurface; @@ -216,7 +216,7 @@ bool BaseImage::writeBMPToStream(Common::WriteStream *stream) const { bool BaseImage::copyFrom(BaseImage *origImage, int newWidth, int newHeight) { // WME Lite used FILTER_BILINEAR with FreeImage_Rescale here. - TransparentSurface temp(*origImage->_surface, false); + Graphics::TransparentSurface temp(*origImage->_surface, false); if (_deletableSurface) { _deletableSurface->free(); delete _deletableSurface; diff --git a/engines/wintermute/base/gfx/base_renderer.h b/engines/wintermute/base/gfx/base_renderer.h index 42ff2cb9e1..6b1a4f97f4 100644 --- a/engines/wintermute/base/gfx/base_renderer.h +++ b/engines/wintermute/base/gfx/base_renderer.h @@ -72,7 +72,6 @@ public: * Fade the screen to black * * @param alpha amount to fade by (alpha value of black) - * @return */ virtual void fade(uint16 alpha) = 0; /** diff --git a/engines/wintermute/base/gfx/base_surface.cpp b/engines/wintermute/base/gfx/base_surface.cpp index ec42a63c77..f8b96b5baf 100644 --- a/engines/wintermute/base/gfx/base_surface.cpp +++ b/engines/wintermute/base/gfx/base_surface.cpp @@ -75,7 +75,7 @@ bool BaseSurface::displayHalfTrans(int x, int y, Rect32 rect) { } ////////////////////////////////////////////////////////////////////////// -bool BaseSurface::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) { +bool BaseSurface::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const Graphics::TransformStruct &transform) { return displayTransform(x, y, rect, newRect, transform); } diff --git a/engines/wintermute/base/gfx/base_surface.h b/engines/wintermute/base/gfx/base_surface.h index 7bd9bcbaea..ea743bdaf2 100644 --- a/engines/wintermute/base/gfx/base_surface.h +++ b/engines/wintermute/base/gfx/base_surface.h @@ -32,7 +32,7 @@ #include "engines/wintermute/base/base.h" #include "engines/wintermute/math/rect32.h" #include "graphics/surface.h" -#include "engines/wintermute/graphics/transform_struct.h" +#include "graphics/transform_struct.h" namespace Wintermute { @@ -50,12 +50,12 @@ public: virtual bool displayHalfTrans(int x, int y, Rect32 rect); virtual bool isTransparentAt(int x, int y); - virtual bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; - virtual bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; - virtual bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) = 0; - virtual bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; - virtual bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) = 0; - virtual bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; + virtual bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; + virtual bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; + virtual bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) = 0; + virtual bool display(int x, int y, Rect32 rect, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; + virtual bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const Graphics::TransformStruct &transform) = 0; + virtual bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, bool transparent = false, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0; virtual bool displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY) = 0; virtual bool restore(); virtual bool create(const Common::String &filename, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) = 0; diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp index 601fcc0ffa..0f6a184cb3 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp @@ -35,7 +35,7 @@ #include "engines/wintermute/base/base_game.h" #include "engines/wintermute/base/base_sprite.h" #include "common/system.h" -#include "engines/wintermute/graphics/transparent_surface.h" +#include "graphics/transparent_surface.h" #include "common/queue.h" #include "common/config-manager.h" @@ -254,7 +254,7 @@ void BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a) { Common::Rect sizeRect(fillRect); sizeRect.translate(-fillRect.top, -fillRect.left); surf.fillRect(fillRect, col); - TransformStruct temp = TransformStruct(); + Graphics::TransformStruct temp = Graphics::TransformStruct(); temp._alphaDisable = false; drawSurface(nullptr, &surf, &sizeRect, &fillRect, temp); surf.free(); @@ -268,7 +268,7 @@ Graphics::PixelFormat BaseRenderOSystem::getPixelFormat() const { return _renderSurface->format; } -void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform) { +void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, Graphics::TransformStruct &transform) { if (_disableDirtyRects) { RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform); diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.h b/engines/wintermute/base/gfx/osystem/base_render_osystem.h index c9b8a52282..bc267fd656 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.h @@ -33,7 +33,7 @@ #include "common/rect.h" #include "graphics/surface.h" #include "common/list.h" -#include "engines/wintermute/graphics/transform_struct.h" +#include "graphics/transform_struct.h" namespace Wintermute { class BaseSurfaceOSystem; @@ -110,7 +110,7 @@ public: virtual bool startSpriteBatch() override; virtual bool endSpriteBatch() override; void endSaveLoad(); - void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct &transform); + void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, Graphics::TransformStruct &transform); BaseSurface *createSurface() override; private: /** diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp index 983f9c1296..a2a0032e26 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp @@ -32,8 +32,8 @@ #include "engines/wintermute/base/gfx/osystem/base_render_osystem.h" #include "engines/wintermute/base/gfx/base_image.h" #include "engines/wintermute/platform_osystem.h" -#include "engines/wintermute/graphics/transparent_surface.h" -#include "engines/wintermute/graphics/transform_tools.h" +#include "graphics/transparent_surface.h" +#include "graphics/transform_tools.h" #include "graphics/pixelformat.h" #include "graphics/surface.h" #include "common/stream.h" @@ -45,7 +45,7 @@ namespace Wintermute { BaseSurfaceOSystem::BaseSurfaceOSystem(BaseGame *inGame) : BaseSurface(inGame) { _surface = new Graphics::Surface(); _alphaMask = nullptr; - _alphaType = TransparentSurface::ALPHA_FULL; + _alphaType = Graphics::ALPHA_FULL; _lockPixels = nullptr; _lockPitch = 0; _loaded = false; @@ -68,10 +68,10 @@ BaseSurfaceOSystem::~BaseSurfaceOSystem() { renderer->invalidateTicketsFromSurface(this); } -TransparentSurface::AlphaType hasTransparencyType(const Graphics::Surface *surf) { +Graphics::AlphaType hasTransparencyType(const Graphics::Surface *surf) { if (surf->format.bytesPerPixel != 4) { warning("hasTransparencyType:: non 32 bpp surface passed as argument"); - return TransparentSurface::ALPHA_OPAQUE; + return Graphics::ALPHA_OPAQUE; } uint8 r, g, b, a; bool seenAlpha = false; @@ -93,11 +93,11 @@ TransparentSurface::AlphaType hasTransparencyType(const Graphics::Surface *surf) } } if (seenFullAlpha) { - return TransparentSurface::ALPHA_FULL; + return Graphics::ALPHA_FULL; } else if (seenAlpha) { - return TransparentSurface::ALPHA_BINARY; + return Graphics::ALPHA_BINARY; } else { - return TransparentSurface::ALPHA_OPAQUE; + return Graphics::ALPHA_OPAQUE; } } @@ -175,7 +175,7 @@ bool BaseSurfaceOSystem::finishLoad() { } if (needsColorKey) { - TransparentSurface trans(*_surface); + Graphics::TransparentSurface trans(*_surface); trans.applyColorKey(_ckRed, _ckGreen, _ckBlue, replaceAlpha); } @@ -328,46 +328,46 @@ bool BaseSurfaceOSystem::endPixelOp() { ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { +bool BaseSurfaceOSystem::display(int x, int y, Rect32 rect, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { _rotation = 0; - return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, mirrorX, mirrorY)); + return drawSprite(x, y, &rect, nullptr, Graphics::TransformStruct(Graphics::kDefaultZoomX, Graphics::kDefaultZoomY, mirrorX, mirrorY)); } ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::displayTrans(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { +bool BaseSurfaceOSystem::displayTrans(int x, int y, Rect32 rect, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { _rotation = 0; - return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, blendMode, alpha, mirrorX, mirrorY)); + return drawSprite(x, y, &rect, nullptr, Graphics::TransformStruct(Graphics::kDefaultZoomX, Graphics::kDefaultZoomY, blendMode, alpha, mirrorX, mirrorY)); } ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::displayTransOffset(int x, int y, Rect32 rect, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) { +bool BaseSurfaceOSystem::displayTransOffset(int x, int y, Rect32 rect, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) { _rotation = 0; - return drawSprite(x, y, &rect, nullptr, TransformStruct(kDefaultZoomX, kDefaultZoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY, offsetX, offsetY)); + return drawSprite(x, y, &rect, nullptr, Graphics::TransformStruct(Graphics::kDefaultZoomX, Graphics::kDefaultZoomY, Graphics::kDefaultAngle, Graphics::kDefaultHotspotX, Graphics::kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY, offsetX, offsetY)); } ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { +bool BaseSurfaceOSystem::displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { _rotation = 0; - return drawSprite(x, y, &rect, nullptr, TransformStruct((int32)zoomX, (int32)zoomY, blendMode, alpha, mirrorX, mirrorY)); + return drawSprite(x, y, &rect, nullptr, Graphics::TransformStruct((int32)zoomX, (int32)zoomY, blendMode, alpha, mirrorX, mirrorY)); } ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, bool transparent, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { +bool BaseSurfaceOSystem::displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha, bool transparent, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) { _rotation = 0; - TransformStruct transform; + Graphics::TransformStruct transform; if (transparent) { - transform = TransformStruct((int32)zoomX, (int32)zoomY, kDefaultAngle, kDefaultHotspotX, kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY); + transform = Graphics::TransformStruct((int32)zoomX, (int32)zoomY, Graphics::kDefaultAngle, Graphics::kDefaultHotspotX, Graphics::kDefaultHotspotY, blendMode, alpha, mirrorX, mirrorY); } else { - transform = TransformStruct((int32)zoomX, (int32)zoomY, mirrorX, mirrorY); + transform = Graphics::TransformStruct((int32)zoomX, (int32)zoomY, mirrorX, mirrorY); } return drawSprite(x, y, &rect, nullptr, transform); } ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) { +bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const Graphics::TransformStruct &transform) { _rotation = (uint32)transform._angle; if (transform._angle < 0.0f) { warning("Negative rotation: %d %d", transform._angle, _rotation); @@ -380,13 +380,13 @@ bool BaseSurfaceOSystem::displayTransform(int x, int y, Rect32 rect, Rect32 newR ////////////////////////////////////////////////////////////////////////// bool BaseSurfaceOSystem::displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY) { assert(numTimesX > 0 && numTimesY > 0); - TransformStruct transform(numTimesX, numTimesY); + Graphics::TransformStruct transform(numTimesX, numTimesY); return drawSprite(x, y, &rect, nullptr, transform); } ////////////////////////////////////////////////////////////////////////// -bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transform) { +bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, Graphics::TransformStruct transform) { BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer); if (!_loaded) { @@ -414,13 +414,13 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, position.setHeight(newRect->height()); } else { - Rect32 r; + Common::Rect r; r.top = 0; r.left = 0; r.setWidth(rect->width()); r.setHeight(rect->height()); - r = TransformTools::newRect(r, transform, 0); + r = Graphics::TransformTools::newRect(r, transform, 0); position.top = r.top + y + transform._offset.y; position.left = r.left + x + transform._offset.x; @@ -433,7 +433,7 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, // But no checking is in place for that yet. // Optimize by not doing alpha-blits if we lack alpha - if (_alphaType == TransparentSurface::ALPHA_OPAQUE && !transform._alphaDisable) { + if (_alphaType == Graphics::ALPHA_OPAQUE && !transform._alphaDisable) { transform._alphaDisable = true; } @@ -452,9 +452,9 @@ bool BaseSurfaceOSystem::putSurface(const Graphics::Surface &surface, bool hasAl _surface->copyFrom(surface); } if (hasAlpha) { - _alphaType = TransparentSurface::ALPHA_FULL; + _alphaType = Graphics::ALPHA_FULL; } else { - _alphaType = TransparentSurface::ALPHA_OPAQUE; + _alphaType = Graphics::ALPHA_OPAQUE; } BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer); renderer->invalidateTicketsFromSurface(this); diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h index 4a05b2c66c..9fbbe1d498 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h @@ -30,7 +30,7 @@ #define WINTERMUTE_BASE_SURFACESDL_H #include "graphics/surface.h" -#include "engines/wintermute/graphics/transparent_surface.h" +#include "graphics/transparent_surface.h" #include "engines/wintermute/base/gfx/base_surface.h" #include "common/list.h" @@ -52,12 +52,12 @@ public: bool endPixelOp() override; - bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; - bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; - bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = kDefaultRgbaMod, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override; - bool display(int x, int y, Rect32 rect, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; - bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = kDefaultRgbaMod, bool transparent = false, TSpriteBlendMode blendMode = BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; - bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const TransformStruct &transform) override; + bool displayTransZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = Graphics::kDefaultRgbaMod, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; + bool displayTrans(int x, int y, Rect32 rect, uint32 alpha = Graphics::kDefaultRgbaMod, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; + bool displayTransOffset(int x, int y, Rect32 rect, uint32 alpha = Graphics::kDefaultRgbaMod, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override; + bool display(int x, int y, Rect32 rect, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; + bool displayZoom(int x, int y, Rect32 rect, float zoomX, float zoomY, uint32 alpha = Graphics::kDefaultRgbaMod, bool transparent = false, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override; + bool displayTransform(int x, int y, Rect32 rect, Rect32 newRect, const Graphics::TransformStruct &transform) override; virtual bool displayTiled(int x, int y, Rect32 rect, int numTimesX, int numTimesY); virtual bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) override; /* static unsigned DLL_CALLCONV ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle); @@ -82,17 +82,17 @@ public: return _height; } - TransparentSurface::AlphaType getAlphaType() const { return _alphaType; } + Graphics::AlphaType getAlphaType() const { return _alphaType; } private: Graphics::Surface *_surface; bool _loaded; bool finishLoad(); - bool drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, TransformStruct transformStruct); + bool drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, Graphics::TransformStruct transformStruct); void genAlphaMask(Graphics::Surface *surface); uint32 getPixelAt(Graphics::Surface *surface, int x, int y); uint32 _rotation; - TransparentSurface::AlphaType _alphaType; + Graphics::AlphaType _alphaType; void *_lockPixels; int _lockPitch; byte *_alphaMask; diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp index f8579dfd41..afe884300a 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp +++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp @@ -29,12 +29,12 @@ #include "engines/wintermute/base/gfx/osystem/render_ticket.h" #include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h" -#include "engines/wintermute/graphics/transform_tools.h" +#include "graphics/transform_tools.h" #include "common/textconsole.h" namespace Wintermute { -RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, TransformStruct transform) : +RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, Graphics::TransformStruct transform) : _owner(owner), _srcRect(*srcRect), _dstRect(*dstRect), @@ -57,8 +57,8 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s // NB: Mirroring and rotation are probably done in the wrong order. // (Mirroring should most likely be done before rotation. See also // TransformTools.) - if (_transform._angle != kDefaultAngle) { - TransparentSurface src(*_surface, false); + if (_transform._angle != Graphics::kDefaultAngle) { + Graphics::TransparentSurface src(*_surface, false); Graphics::Surface *temp = src.rotoscale(transform); _surface->free(); delete _surface; @@ -66,7 +66,7 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s } else if ((dstRect->width() != srcRect->width() || dstRect->height() != srcRect->height()) && _transform._numTimesX * _transform._numTimesY == 1) { - TransparentSurface src(*_surface, false); + Graphics::TransparentSurface src(*_surface, false); Graphics::Surface *temp = src.scale(dstRect->width(), dstRect->height()); _surface->free(); delete _surface; @@ -97,7 +97,7 @@ bool RenderTicket::operator==(const RenderTicket &t) const { // Replacement for SDL2's SDL_RenderCopy void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const { - TransparentSurface src(*getSurface(), false); + Graphics::TransparentSurface src(*getSurface(), false); Common::Rect clipRect; clipRect.setWidth(getSurface()->w); @@ -105,7 +105,7 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const { if (_owner) { if (_transform._alphaDisable) { - src.setAlphaMode(TransparentSurface::ALPHA_OPAQUE); + src.setAlphaMode(Graphics::ALPHA_OPAQUE); } else { src.setAlphaMode(_owner->getAlphaType()); } @@ -126,7 +126,7 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const { } void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const { - TransparentSurface src(*getSurface(), false); + Graphics::TransparentSurface src(*getSurface(), false); bool doDelete = false; if (!clipRect) { doDelete = true; @@ -137,7 +137,7 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect if (_owner) { if (_transform._alphaDisable) { - src.setAlphaMode(TransparentSurface::ALPHA_OPAQUE); + src.setAlphaMode(Graphics::ALPHA_OPAQUE); } else { src.setAlphaMode(_owner->getAlphaType()); } diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.h b/engines/wintermute/base/gfx/osystem/render_ticket.h index de95273021..3d3bd2e844 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.h +++ b/engines/wintermute/base/gfx/osystem/render_ticket.h @@ -29,7 +29,7 @@ #ifndef WINTERMUTE_RENDER_TICKET_H #define WINTERMUTE_RENDER_TICKET_H -#include "engines/wintermute/graphics/transparent_surface.h" +#include "graphics/transparent_surface.h" #include "graphics/surface.h" #include "common/rect.h" @@ -51,8 +51,8 @@ class BaseSurfaceOSystem; */ class RenderTicket { public: - RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, TransformStruct transform); - RenderTicket() : _isValid(true), _wantsDraw(false), _transform(TransformStruct()) {} + RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, Graphics::TransformStruct transform); + RenderTicket() : _isValid(true), _wantsDraw(false), _transform(Graphics::TransformStruct()) {} ~RenderTicket(); const Graphics::Surface *getSurface() const { return _surface; } // Non-dirty-rects: @@ -65,7 +65,7 @@ public: bool _isValid; bool _wantsDraw; - TransformStruct _transform; + Graphics::TransformStruct _transform; BaseSurfaceOSystem *_owner; bool operator==(const RenderTicket &a) const; diff --git a/engines/wintermute/base/sound/base_sound_manager.cpp b/engines/wintermute/base/sound/base_sound_manager.cpp index 539dc0dd1d..41cfe5ea62 100644 --- a/engines/wintermute/base/sound/base_sound_manager.cpp +++ b/engines/wintermute/base/sound/base_sound_manager.cpp @@ -87,6 +87,7 @@ bool BaseSoundMgr::initialize() { setMasterVolumePercent(volumeMasterPercent); _soundAvailable = true; + g_engine->syncSoundSettings(); return STATUS_OK; } diff --git a/engines/wintermute/dcgf.h b/engines/wintermute/dcgf.h index 78503b8c3b..c919180e45 100644 --- a/engines/wintermute/dcgf.h +++ b/engines/wintermute/dcgf.h @@ -32,8 +32,8 @@ ////////////////////////////////////////////////////////////////////////// #define DCGF_VER_MAJOR 1 -#define DCGF_VER_MINOR 2 -#define DCGF_VER_BUILD 2 +#define DCGF_VER_MINOR 3 +#define DCGF_VER_BUILD 1 #define DCGF_VER_SUFFIX "ScummVM" #define DCGF_VER_BETA true diff --git a/engines/wintermute/dctypes.h b/engines/wintermute/dctypes.h index 33e1cc4018..90340f437d 100644 --- a/engines/wintermute/dctypes.h +++ b/engines/wintermute/dctypes.h @@ -200,14 +200,6 @@ enum TTextEncoding { NUM_TEXT_ENCODINGS }; -enum TSpriteBlendMode { - BLEND_UNKNOWN = -1, - BLEND_NORMAL = 0, - BLEND_ADDITIVE = 1, - BLEND_SUBTRACTIVE = 2, - NUM_BLEND_MODES -}; - enum TTTSType { TTS_CAPTION = 0, TTS_TALK, diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h index 6087e60ece..8206ca9643 100644 --- a/engines/wintermute/detection_tables.h +++ b/engines/wintermute/detection_tables.h @@ -39,41 +39,50 @@ static const PlainGameDescriptor wintermuteGames[] = { {"carolreed8", "Carol Reed 8 - Amber's Blood"}, {"carolreed9", "Carol Reed 9 - Cold Case Summer"}, {"chivalry", "Chivalry is Not Dead"}, - {"corrosion", "Corrosion: Cold Winter Waiting"}, + {"conspiracao", "Conspiracao Dumont"}, + {"corrosion", "Corrosion: Cold Winter Waiting"}, {"deadcity", "Dead City"}, {"dreaming", "Des Reves Elastiques Avec Mille Insectes Nommes Georges"}, {"dirtysplit", "Dirty Split"}, {"dreamscape", "Dreamscape"}, {"escapemansion", "Escape from the Mansion"}, + {"four", "Four"}, {"framed", "Framed"}, {"ghostsheet", "Ghost in the Sheet"}, {"hamlet", "Hamlet or the last game without MMORPS features, shaders and product placement"}, {"helga", "Helga Deep In Trouble"}, {"jamesperis", "James Peris: No License Nor Control"}, {"kulivocko", "Kulivocko"}, + {"lifein3minutes", "Life In 3 Minutes"}, {"lonelyrobot", "Project Lonely Robot"}, {"looky", "Looky"}, {"julia", "J.U.L.I.A."}, {"mirage", "Mirage"}, + {"nighttrain", "Night Train"}, {"oknytt", "Oknytt"}, {"paintaria", "Paintaria"}, {"pigeons", "Pigeons in the Park"}, {"projectdoom", "Project: Doom"}, + {"projectjoe", "Project Joe"}, {"reversion1", "Reversion: The Escape"}, {"reversion2", "Reversion: The Meeting"}, - {"rhiannon", "Rhiannon: Curse of the four Branches"}, - {"ritter", "1 1/2 Ritter: Auf der Suche nach der hinreissenden Herzelinde"}, + {"rhiannon", "Rhiannon: Curse of the four Branches"}, + {"ritter", "1 1/2 Ritter: Auf der Suche nach der hinreissenden Herzelinde"}, {"rosemary", "Rosemary"}, + {"satanandson", "Satan and Son"}, {"securanote", "Securanote"}, {"shaban", "Shaban"}, {"shinestar", "The Shine of a Star"}, {"spaceinvaders", "Space Invaders"}, {"spacemadness", "Space Madness"}, + {"sofiasdebt", "Sofia's Debt"}, + {"theancientmark1", "The Ancient Mark - Episode 1"}, {"thebox", "The Box"}, - {"thekite", "The Kite"}, + {"thekite", "The Kite"}, {"tib", "Fairy Tales About Toshechka and Boshechka"}, {"tradestory", "The Trader of Stories"}, {"twc", "the white chamber"}, + {"war", "War"}, {"vsevolod", "Vsevolod"}, {"wintermute", "Wintermute engine game"}, {"wtetris", "Wilma Tetris"}, @@ -275,6 +284,17 @@ static const ADGameDescription gameDescriptions[] = { ADGF_TESTING, GUIO0() }, + // Conspiracao Dumont + { + "conspiracao", + "", + AD_ENTRY1s("ConspiracaoDumont.exe", "106f3f2c8f18bb5ffffeed634ace256c", 32908032), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE | + ADGF_DEMO, + GUIO0() + }, // Corrosion: Cold Winter Waiting { "corrosion", @@ -466,6 +486,16 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Four + { + "four", + "", + AD_ENTRY1s("data.dcp", "ec05cd5e37c9a524053b8859635a4234", 62599855), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // Framed { "framed", @@ -645,6 +675,16 @@ static const ADGameDescription gameDescriptions[] = { ADGF_DEMO, GUIO0() }, + // Life In 3 Minutes + { + "lifein3minutes", + "", + AD_ENTRY1s("data.dcp", "c6368950e37a95bf098b02b4eaa5b929", 141787214), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // Looky Demo (English) { "looky", @@ -709,6 +749,17 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Night Train Demo + { + "nighttrain", + "", + AD_ENTRY1s("data.dcp", "5a027ef84b083a730c9a4c85ec1d3a32", 131760816), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE | + ADGF_DEMO, + GUIO0() + }, // Paintaria { "paintaria", @@ -739,6 +790,17 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Project Joe + { + "projectjoe", + "", + AD_ENTRY1s("data.dcp", "ada3c08542901295076b5349e655e73f", 160780037), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE | + ADGF_DEMO, + GUIO0() + }, // Project Lonely Robot { "lonelyrobot", @@ -1138,6 +1200,17 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Satan and Son + { + "satanandson", + "", + AD_ENTRY1s("data.dcp", "16a6ba8174b697bbba9299619d1e20c4", 67539054), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE | + ADGF_DEMO, + GUIO0() + }, // Rosemary { "rosemary", @@ -1178,6 +1251,16 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Sofia's Debt + { + "sofiasdebt", + "", + AD_ENTRY1s("SD.exe", "e9515f9ba1a2925bb6733476a826a650", 9915047), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // Space Invaders (Demo) { "spaceinvaders", @@ -1199,6 +1282,16 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // The Ancient Mark - Episode 1 + { + "theancientmark1", + "", + AD_ENTRY1s("data.dcp", "ca04c26f03b2bd307368b306b297ddd7", 364664692), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // The Box { "thebox", @@ -1301,6 +1394,16 @@ static const ADGameDescription gameDescriptions[] = { ADGF_DEMO, GUIO0() }, + // War + { + "war", + "", + AD_ENTRY1s("data.dcp", "003e317cda6d0137bbd5e5d7f089ee4d", 32591890), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // Wilma Tetris { "wtetris", diff --git a/engines/wintermute/graphics/transform_struct.cpp b/engines/wintermute/graphics/transform_struct.cpp deleted file mode 100644 index 9483975d94..0000000000 --- a/engines/wintermute/graphics/transform_struct.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* 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 "engines/wintermute/graphics/transform_struct.h" -#include "engines/wintermute/graphics/transparent_surface.h" - -namespace Wintermute { -void TransformStruct::init(Point32 zoom, uint32 angle, Point32 hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, Point32 offset) { - _zoom = zoom; - _angle = angle; - _hotspot = hotspot; - _blendMode = blendMode; - _rgbaMod = rgbaMod; - _alphaDisable = alphaDisable; - _flip = 0; - _flip += TransparentSurface::FLIP_H * mirrorX; - _flip += TransparentSurface::FLIP_V * mirrorY; - _offset = offset; - _numTimesX = 1; - _numTimesY = 1; -} - -TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) { - init(Point32(zoomX, zoomY), - angle, - Point32(hotspotX, hotspotY), - false, - blendMode, - rgbaMod, - mirrorX, mirrorY, - Point32(offsetX, offsetY)); -} - -TransformStruct::TransformStruct(float zoomX, float zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY, int32 offsetX, int32 offsetY) { - init(Point32((int32)(zoomX / 100.0 * kDefaultZoomX), - (int32)(zoomY / 100.0 * kDefaultZoomY)), - angle, - Point32(hotspotX, hotspotY), - false, - blendMode, - rgbaMod, - mirrorX, mirrorY, - Point32(offsetX, offsetY)); -} - -TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 rgbaMod, bool mirrorX, bool mirrorY) { - init(Point32(zoomX, zoomY), - kDefaultAngle, - Point32(kDefaultHotspotX, kDefaultHotspotY), - false, - blendMode, - rgbaMod, - mirrorX, - mirrorY, - Point32(kDefaultOffsetX, kDefaultOffsetY)); -} - -TransformStruct::TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY) { - init(Point32(zoomX, zoomY), - angle, - Point32(hotspotX, hotspotY), - true, - BLEND_NORMAL, - kDefaultRgbaMod, - false, false, - Point32(kDefaultOffsetX, kDefaultOffsetY)); -} - -TransformStruct::TransformStruct(int32 numTimesX, int32 numTimesY) { - init(Point32(kDefaultZoomX, kDefaultZoomY), - kDefaultAngle, - Point32(kDefaultHotspotX, kDefaultHotspotY), - false, - BLEND_NORMAL, - kDefaultRgbaMod, - false, false, - Point32(kDefaultOffsetX, kDefaultOffsetY)); - _numTimesX = numTimesX; - _numTimesY = numTimesY; -} - -TransformStruct::TransformStruct() { - init(Point32(kDefaultZoomX, kDefaultZoomY), - kDefaultAngle, - Point32(kDefaultHotspotX, kDefaultHotspotY), - true, - BLEND_NORMAL, - kDefaultRgbaMod, - false, false, - Point32(kDefaultOffsetX, kDefaultOffsetY)); -} - -bool TransformStruct::getMirrorX() const { - return (bool)(_flip & TransparentSurface::FLIP_H); -} - -bool TransformStruct::getMirrorY() const { - return (bool)(_flip & TransparentSurface::FLIP_V); -} -} // End of namespace Wintermute diff --git a/engines/wintermute/graphics/transform_struct.h b/engines/wintermute/graphics/transform_struct.h deleted file mode 100644 index f80b0967cb..0000000000 --- a/engines/wintermute/graphics/transform_struct.h +++ /dev/null @@ -1,89 +0,0 @@ -/* 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 WINTERMUTE_TRANSFORM_STRUCT_H -#define WINTERMUTE_TRANSFORM_STRUCT_H - -#include "engines/wintermute/math/rect32.h" -#include "engines/wintermute/dctypes.h" - -namespace Wintermute { -/** - * Contains all the required information that define a transform. - * Same source sprite + same TransformStruct = Same resulting sprite. - * Has a number of overloaded constructors to accomodate various argument lists. - */ - -const int32 kDefaultZoomX = 100; -const int32 kDefaultZoomY = 100; -const uint32 kDefaultRgbaMod = 0xFFFFFFFF; -const int32 kDefaultHotspotX = 0; -const int32 kDefaultHotspotY = 0; -const int32 kDefaultOffsetX = 0; -const int32 kDefaultOffsetY = 0; -const int32 kDefaultAngle = 0; - -struct TransformStruct { -private: - void init(Point32 zoom, uint32 angle, Point32 hotspot, bool alphaDisable, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX, bool mirrorY, Point32 offset); - -public: - TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false, int32 offsetX = 0, int32 offsetY = 0); - TransformStruct(float zoomX, float zoomY, uint32 angle, int32 hotspotX, int32 hotspotY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false, int32 offsetX = 0, int32 offsetY = 0); - TransformStruct(int32 zoomX, int32 zoomY, TSpriteBlendMode blendMode, uint32 alpha, bool mirrorX = false, bool mirrorY = false); - TransformStruct(int32 zoomX, int32 zoomY, uint32 angle, int32 hotspotX = 0, int32 hotspotY = 0); - TransformStruct(int32 numTimesX, int32 numTimesY); - TransformStruct(); - - Point32 _zoom; ///< Zoom; 100 = no zoom - Point32 _hotspot; ///< Position of the hotspot - int32 _angle; ///< Rotation angle, in degrees - byte _flip; ///< Bitflag: see TransparentSurface::FLIP_XXX - bool _alphaDisable; - TSpriteBlendMode _blendMode; - uint32 _rgbaMod; ///< RGBa - Point32 _offset; - int32 _numTimesX; - int32 _numTimesY; - - bool getMirrorX() const; - bool getMirrorY() const; - - bool operator==(const TransformStruct &compare) const { - return (compare._angle == _angle && - compare._flip == _flip && - compare._zoom == _zoom && - compare._offset == _offset && - compare._alphaDisable == _alphaDisable && - compare._rgbaMod == _rgbaMod && - compare._blendMode == _blendMode && - compare._numTimesX == _numTimesX && - compare._numTimesY == _numTimesY - ); - } - - bool operator!=(const TransformStruct &compare) const { - return !(compare == *this); - } -}; -} // End of namespace Wintermute -#endif diff --git a/engines/wintermute/graphics/transform_tools.cpp b/engines/wintermute/graphics/transform_tools.cpp deleted file mode 100644 index 7a009c26fa..0000000000 --- a/engines/wintermute/graphics/transform_tools.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* 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 "engines/wintermute/graphics/transform_tools.h" -#include <math.h> - -namespace Wintermute { - -FloatPoint TransformTools::transformPoint(FloatPoint point, const float rotate, const Point32 &zoom, const bool mirrorX, const bool mirrorY) { - float rotateRad = rotate * M_PI / 180.0f; - float x = point.x; - float y = point.y; - x = (x * zoom.x) / kDefaultZoomX; - y = (y * zoom.y) / kDefaultZoomY; -#if 0 - // TODO: Mirroring should be done before rotation, but the blitting - // code does the inverse, so we match that for now. - if (mirrorX) - x *= -1; - if (mirrorY) - y *= -1; -#endif - FloatPoint newPoint; - newPoint.x = x * cos(rotateRad) - y * sin(rotateRad); - newPoint.y = x * sin(rotateRad) + y * cos(rotateRad); - if (mirrorX) { - newPoint.x *= -1; - } - if (mirrorY) { - newPoint.y *= -1; - } - return newPoint; -} - -Rect32 TransformTools::newRect(const Rect32 &oldRect, const TransformStruct &transform, Point32 *newHotspot) { - Point32 nw(oldRect.left, oldRect.top); - Point32 ne(oldRect.right, oldRect.top); - Point32 sw(oldRect.left, oldRect.bottom); - Point32 se(oldRect.right, oldRect.bottom); - - FloatPoint nw1, ne1, sw1, se1; - - nw1 = transformPoint(nw - transform._hotspot, transform._angle, transform._zoom); - ne1 = transformPoint(ne - transform._hotspot, transform._angle, transform._zoom); - sw1 = transformPoint(sw - transform._hotspot, transform._angle, transform._zoom); - se1 = transformPoint(se - transform._hotspot, transform._angle, transform._zoom); - - float top = MIN(nw1.y, MIN(ne1.y, MIN(sw1.y, se1.y))); - float bottom = MAX(nw1.y, MAX(ne1.y, MAX(sw1.y, se1.y))); - float left = MIN(nw1.x, MIN(ne1.x, MIN(sw1.x, se1.x))); - float right = MAX(nw1.x, MAX(ne1.x, MAX(sw1.x, se1.x))); - - if (newHotspot) { - newHotspot->y = (uint32)(-floor(top)); - newHotspot->x = (uint32)(-floor(left)); - } - - Rect32 res; - res.top = (int32)(floor(top)) + transform._hotspot.y; - res.bottom = (int32)(ceil(bottom)) + transform._hotspot.y; - res.left = (int32)(floor(left)) + transform._hotspot.x; - res.right = (int32)(ceil(right)) + transform._hotspot.x; - - return res; -} - -} // End of namespace Wintermute diff --git a/engines/wintermute/graphics/transform_tools.h b/engines/wintermute/graphics/transform_tools.h deleted file mode 100644 index e259db04e5..0000000000 --- a/engines/wintermute/graphics/transform_tools.h +++ /dev/null @@ -1,53 +0,0 @@ -/* 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 WINTERMUTE_TRANSFORM_TOOLS_H -#define WINTERMUTE_TRANSFORM_TOOLS_H - -#include "engines/wintermute/math/rect32.h" -#include "engines/wintermute/math/floatpoint.h" -#include "engines/wintermute/graphics/transform_struct.h" - -namespace Wintermute { - -class TransformTools { -public: - /** - * Basic transform (scale + rotate) for a single point - */ - static FloatPoint transformPoint(FloatPoint point, const float rotate, const Point32 &zoom, const bool mirrorX = false, const bool mirrorY = false); - - /** - * @param &point the point on which the transform is to be applied - * @param rotate the angle in degrees - * @param &zoom zoom x,y in percent - * @param mirrorX flip along the vertical axis? - * @param mirrorY flip along the horizontal axis? - * @return the smallest rect that can contain the transformed sprite - * and, as a side-effect, "newHotspot" will tell you where the hotspot will - * have ended up in the new rect, for centering. - */ - static Rect32 newRect(const Rect32 &oldRect, const TransformStruct &transform, Point32 *newHotspot); -}; - -} // End of namespace Wintermute -#endif diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp deleted file mode 100644 index 5fe0d13766..0000000000 --- a/engines/wintermute/graphics/transparent_surface.cpp +++ /dev/null @@ -1,950 +0,0 @@ -/* 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. - * - * - * The bottom part of this is file is adapted from SDL_rotozoom.c. The - * relevant copyright notice for those specific functions can be found at the - * top of that section. - * - */ - - - -#include "common/algorithm.h" -#include "common/endian.h" -#include "common/util.h" -#include "common/rect.h" -#include "common/math.h" -#include "common/textconsole.h" -#include "graphics/primitives.h" -#include "engines/wintermute/graphics/transparent_surface.h" -#include "engines/wintermute/graphics/transform_tools.h" - -//#define ENABLE_BILINEAR - -namespace Wintermute { - -void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep); -void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep); - -// These gather together various blendPixel functions for use with templates. - -class BlenderAdditive { -public: - inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); - inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); - inline void blendPixel(byte *in, byte *out); - inline void blendPixel(byte *in, byte *out, int colorMod); -}; - -class BlenderSubtractive { -public: - inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); - inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); - inline void blendPixel(byte *in, byte *out); - inline void blendPixel(byte *in, byte *out, int colorMod); -}; - -class BlenderNormal { -public: - inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); - inline void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); - inline void blendPixel(byte *in, byte *out); - inline void blendPixel(byte *in, byte *out, int colorMod); -}; - -/** - * Perform additive blending of a pixel, applying beforehand a given colormod. - * @param ina, inr, ing, inb: the input pixel, split into its components. - * @param *outa, *outr, *outg, *outb pointer to the output pixel. - * @param *outa, *outr, *outg, *outb pointer to the colormod components. - */ -void BlenderAdditive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) { - if (*ca != 255) { - ina = (ina) * (*ca) >> 8; - } - - if (ina == 0) { - return; - } else { - if (*cb != 255) { - *outb = MIN(*outb + ((inb * (*cb) * ina) >> 16), 255); - } else { - *outb = MIN(*outb + (inb * ina >> 8), 255); - } - - if (*cg != 255) { - *outg = MIN(*outg + ((ing * (*cg) * ina) >> 16), 255); - } else { - *outg = MIN(*outg + (ing * ina >> 8), 255); - } - - if (*cr != 255) { - *outr = MIN(*outr + ((inr * (*cr) * ina) >> 16), 255); - } else { - *outr = MIN(*outr + (inr * ina >> 8), 255); - } - } -} - -/** - * Perform subtractive blending of a pixel, applying beforehand a given colormod. - * @param ina, inr, ing, inb: the input pixel, split into its components. - * @param *outa, *outr, *outg, *outb pointer to the output pixel. - * @param *outa, *outr, *outg, *outb pointer to the colormod components. - */ -void BlenderSubtractive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) { - //if (*ca != 255) { - // ina = ina * (*ca) >> 8; - // } - - // As weird as it is, evidence suggests that alphamod is ignored when doing - // subtractive... - - // TODO if ina == 255 fast version - - if (ina == 0) { - return; - } else { - if (*cb != 255) { - *outb = MAX(*outb - ((inb * (*cb) * (*outb) * ina) >> 24), 0); - } else { - *outb = MAX(*outb - (inb * (*outb) * ina >> 16), 0); - } - - if (*cg != 255) { - *outg = MAX(*outg - ((ing * (*cg) * (*outg) * ina) >> 24), 0); - } else { - *outg = MAX(*outg - (ing * (*outg) * ina >> 16), 0); - } - - if (*cr != 255) { - *outr = MAX(*outr - ((inr * (*cr) * (*outr) * ina) >> 24), 0); - } else { - *outr = MAX(*outr - (inr * (*outr) * ina >> 16), 0); - } - } -} - -/** - * Perform "regular" alphablending of a pixel, applying beforehand a given colormod. - * @param ina, inr, ing, inb: the input pixel, split into its components. - * @param *outa, *outr, *outg, *outb pointer to the output pixel. - * @param *outa, *outr, *outg, *outb pointer to the colormod components. - */ - -void BlenderNormal::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) { - if (*ca != 255) { - ina = ina * (*ca) >> 8; - } - - if (ina == 0) { - return; - } else if (ina == 255) { - if (*cb != 255) { - *outb = (inb * (*cb)) >> 8; - } else { - *outb = inb; - } - - if (*cr != 255) { - *outr = (inr * (*cr)) >> 8; - } else { - *outr = inr; - } - - if (*cg != 255) { - *outg = (ing * (*cg)) >> 8; - } else { - *outg = ing; - } - - *outa = ina; - - return; - - } else { - - *outa = 255; - *outb = (*outb * (255 - ina) >> 8); - *outr = (*outr * (255 - ina) >> 8); - *outg = (*outg * (255 - ina) >> 8); - - if (*cb == 0) { - *outb = *outb; - } else if (*cb != 255) { - *outb = *outb + (inb * ina * (*cb) >> 16); - } else { - *outb = *outb + (inb * ina >> 8); - } - - if (*cr == 0) { - *outr = *outr; - } else if (*cr != 255) { - *outr = *outr + (inr * ina * (*cr) >> 16); - } else { - *outr = *outr + (inr * ina >> 8); - } - - if (*cg == 0) { - *outg = *outg; - } else if (*cg != 255) { - *outg = *outg + (ing * ina * (*cg) >> 16); - } else { - *outg = *outg + (ing * ina >> 8); - } - - return; - } -} - -/** - * Perform "regular" alphablending of a pixel. - * @param ina, inr, ing, inb: the input pixel, split into its components. - * @param *outa, *outr, *outg, *outb pointer to the output pixel. - */ - -void BlenderNormal::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) { - - if (ina == 0) { - return; - } else if (ina == 255) { - *outb = inb; - *outg = ing; - *outr = inr; - *outa = ina; - return; - } else { - *outa = 255; - *outb = ((inb * ina) + *outb * (255 - ina)) >> 8; - *outg = ((ing * ina) + *outg * (255 - ina)) >> 8; - *outr = ((inr * ina) + *outr * (255 - ina)) >> 8; - } -} - -/** - * Perform subtractive blending of a pixel. - * @param ina, inr, ing, inb: the input pixel, split into its components. - * @param *outa, *outr, *outg, *outb pointer to the output pixel. - */ -void BlenderSubtractive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) { - - if (ina == 0) { - return; - } else if (ina == 255) { - *outa = *outa; - *outr = *outr - (inr * (*outr) >> 8); - *outg = *outg - (ing * (*outg) >> 8); - *outb = *outb - (inb * (*outb) >> 8); - return; - } else { - *outa = *outa; - *outb = MAX(*outb - ((inb * (*outb)) * ina >> 16), 0); - *outg = MAX(*outg - ((ing * (*outg)) * ina >> 16), 0); - *outr = MAX(*outr - ((inr * (*outr)) * ina >> 16), 0); - return; - } -} - -/** - * Perform additive blending of a pixel. - * @param ina, inr, ing, inb: the input pixel, split into its components. - * @param *outa, *outr, *outg, *outb pointer to the output pixel. - */ -void BlenderAdditive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) { - - if (ina == 0) { - return; - } else if (ina == 255) { - *outa = *outa; - *outr = MIN(*outr + inr, 255); - *outg = MIN(*outg + ing, 255); - *outb = MIN(*outb + inb, 255); - return; - } else { - *outa = *outa; - *outb = MIN((inb * ina >> 8) + *outb, 255); - *outg = MIN((ing * ina >> 8) + *outg, 255); - *outr = MIN((inr * ina >> 8) + *outr, 255); - return; - } -} - - -TransparentSurface::TransparentSurface() : Surface(), _alphaMode(ALPHA_FULL) {} - -TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Surface(), _alphaMode(ALPHA_FULL) { - if (copyData) { - copyFrom(surf); - } else { - w = surf.w; - h = surf.h; - pitch = surf.pitch; - format = surf.format; - // We need to cast the const qualifier away here because 'pixels' - // always needs to be writable. 'surf' however is a constant Surface, - // thus getPixels will always return const pixel data. - pixels = const_cast<void *>(surf.getPixels()); - } -} - -/** - * Optimized version of doBlit to be used w/opaque blitting (no alpha). - */ -void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { - - byte *in; - byte *out; - - for (uint32 i = 0; i < height; i++) { - out = outo; - in = ino; - memcpy(out, in, width * 4); - for (uint32 j = 0; j < width; j++) { - out[TransparentSurface::kAIndex] = 0xFF; - out += 4; - } - outo += pitch; - ino += inoStep; - } -} - -/** - * Optimized version of doBlit to be used w/binary blitting (blit or no-blit, no blending). - */ -void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { - - byte *in; - byte *out; - - for (uint32 i = 0; i < height; i++) { - out = outo; - in = ino; - for (uint32 j = 0; j < width; j++) { - uint32 pix = *(uint32 *)in; - int a = (pix >> TransparentSurface::kAShift) & 0xff; - - if (a == 0) { // Full transparency - } else { // Full opacity (Any value not exactly 0 is Opaque here) - *(uint32 *)out = pix; - out[TransparentSurface::kAIndex] = 0xFF; - } - out += 4; - in += inStep; - } - outo += pitch; - ino += inoStep; - } -} - -/** - * What we have here is a template method that calls blendPixel() from a different - * class - the one we call it with - thus performing a different type of blending. - * - * @param ino a pointer to the input surface - * @param outo a pointer to the output surface - * @param width width of the input surface - * @param height height of the input surface - * @param pitch pitch of the output surface - that is, width in bytes of every row, usually bpp * width of the TARGET surface (the area we are blitting to might be smaller, do the math) - * @inStep size in bytes to skip to address each pixel, usually bpp of the source surface - * @inoStep width in bytes of every row on the *input* surface / kind of like pitch - * @color colormod in 0xAARRGGBB format - 0xFFFFFFFF for no colormod - */ - -template<class Blender> -void doBlit(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) { - Blender b; - byte *in; - byte *out; - - if (color == 0xffffffff) { - - for (uint32 i = 0; i < height; i++) { - out = outo; - in = ino; - for (uint32 j = 0; j < width; j++) { - - byte *outa = &out[TransparentSurface::kAIndex]; - byte *outr = &out[TransparentSurface::kRIndex]; - byte *outg = &out[TransparentSurface::kGIndex]; - byte *outb = &out[TransparentSurface::kBIndex]; - - b.blendPixel(in[TransparentSurface::kAIndex], - in[TransparentSurface::kRIndex], - in[TransparentSurface::kGIndex], - in[TransparentSurface::kBIndex], - outa, outr, outg, outb); - - in += inStep; - out += 4; - } - outo += pitch; - ino += inoStep; - } - } else { - - byte ca = (color >> TransparentSurface::kAModShift) & 0xFF; - byte cr = (color >> TransparentSurface::kRModShift) & 0xFF; - byte cg = (color >> TransparentSurface::kGModShift) & 0xFF; - byte cb = (color >> TransparentSurface::kBModShift) & 0xFF; - - for (uint32 i = 0; i < height; i++) { - out = outo; - in = ino; - for (uint32 j = 0; j < width; j++) { - - byte *outa = &out[TransparentSurface::kAIndex]; - byte *outr = &out[TransparentSurface::kRIndex]; - byte *outg = &out[TransparentSurface::kGIndex]; - byte *outb = &out[TransparentSurface::kBIndex]; - - b.blendPixel(in[TransparentSurface::kAIndex], - in[TransparentSurface::kRIndex], - in[TransparentSurface::kGIndex], - in[TransparentSurface::kBIndex], - outa, outr, outg, outb, &ca, &cr, &cg, &cb); - in += inStep; - out += 4; - } - outo += pitch; - ino += inoStep; - } - } -} - -Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, TSpriteBlendMode blendMode) { - - Common::Rect retSize; - retSize.top = 0; - retSize.left = 0; - retSize.setWidth(0); - retSize.setHeight(0); - // Check if we need to draw anything at all - int ca = (color >> 24) & 0xff; - - if (ca == 0) { - return retSize; - } - - // Create an encapsulating surface for the data - TransparentSurface srcImage(*this, false); - // TODO: Is the data really in the screen format? - if (format.bytesPerPixel != 4) { - warning("TransparentSurface can only blit 32 bpp images"); - return retSize; - } - - if (pPartRect) { - - int xOffset = pPartRect->left; - int yOffset = pPartRect->top; - - if (flipping & FLIP_V) { - yOffset = srcImage.h - pPartRect->bottom; - } - - if (flipping & FLIP_H) { - xOffset = srcImage.w - pPartRect->right; - } - - srcImage.pixels = getBasePtr(xOffset, yOffset); - srcImage.w = pPartRect->width(); - srcImage.h = pPartRect->height(); - - debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, - pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height); - } else { - - debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0, - srcImage.w, srcImage.h, color, width, height); - } - - if (width == -1) { - width = srcImage.w; - } - if (height == -1) { - height = srcImage.h; - } - -#ifdef SCALING_TESTING - // Hardcode scaling to 66% to test scaling - width = width * 2 / 3; - height = height * 2 / 3; -#endif - - Graphics::Surface *img = nullptr; - Graphics::Surface *imgScaled = nullptr; - byte *savedPixels = nullptr; - if ((width != srcImage.w) || (height != srcImage.h)) { - // Scale the image - img = imgScaled = srcImage.scale(width, height); - savedPixels = (byte *)img->getPixels(); - } else { - img = &srcImage; - } - - // Handle off-screen clipping - if (posY < 0) { - img->h = MAX(0, (int)img->h - -posY); - img->setPixels((byte *)img->getBasePtr(0, -posY)); - posY = 0; - } - - if (posX < 0) { - img->w = MAX(0, (int)img->w - -posX); - img->setPixels((byte *)img->getBasePtr(-posX, 0)); - posX = 0; - } - - img->w = CLIP((int)img->w, 0, (int)MAX((int)target.w - posX, 0)); - img->h = CLIP((int)img->h, 0, (int)MAX((int)target.h - posY, 0)); - - if ((img->w > 0) && (img->h > 0)) { - int xp = 0, yp = 0; - - int inStep = 4; - int inoStep = img->pitch; - if (flipping & TransparentSurface::FLIP_H) { - inStep = -inStep; - xp = img->w - 1; - } - - if (flipping & TransparentSurface::FLIP_V) { - inoStep = -inoStep; - yp = img->h - 1; - } - - byte *ino = (byte *)img->getBasePtr(xp, yp); - byte *outo = (byte *)target.getBasePtr(posX, posY); - - if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_OPAQUE) { - doBlitOpaqueFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); - } else if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_BINARY) { - doBlitBinaryFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); - } else { - if (blendMode == BLEND_ADDITIVE) { - doBlit<BlenderAdditive>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color); - } else if (blendMode == BLEND_SUBTRACTIVE) { - doBlit<BlenderSubtractive>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color); - } else { - assert(blendMode == BLEND_NORMAL); - doBlit<BlenderNormal>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color); - } - } - - } - - retSize.setWidth(img->w); - retSize.setHeight(img->h); - - if (imgScaled) { - imgScaled->setPixels(savedPixels); - imgScaled->free(); - delete imgScaled; - } - - return retSize; -} - -/** - * Writes a color key to the alpha channel of the surface - * @param rKey the red component of the color key - * @param gKey the green component of the color key - * @param bKey the blue component of the color key - * @param overwriteAlpha if true, all other alpha will be set fully opaque - */ -void TransparentSurface::applyColorKey(uint8 rKey, uint8 gKey, uint8 bKey, bool overwriteAlpha) { - assert(format.bytesPerPixel == 4); - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - uint32 pix = ((uint32 *)pixels)[i * w + j]; - uint8 r, g, b, a; - format.colorToARGB(pix, a, r, g, b); - if (r == rKey && g == gKey && b == bKey) { - a = 0; - ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b); - } else if (overwriteAlpha) { - a = 255; - ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b); - } - } - } -} - -TransparentSurface::AlphaType TransparentSurface::getAlphaMode() const { - return _alphaMode; -} - -void TransparentSurface::setAlphaMode(TransparentSurface::AlphaType mode) { - _alphaMode = mode; -} - - - - - - -/* - -The below two functions are adapted from SDL_rotozoom.c, -taken from SDL_gfx-2.0.18. - -Its copyright notice: - -============================================================================= -SDL_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces - -Copyright (C) 2001-2012 Andreas Schiffler - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not -claim that you wrote the original software. If you use this software -in a product, an acknowledgment in the product documentation would be -appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and must not be -misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. - -Andreas Schiffler -- aschiffler at ferzkopp dot net -============================================================================= - - -The functions have been adapted for different structures and coordinate -systems. - -*/ - - - - - -TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transform) const { - - assert(transform._angle != 0); // This would not be ideal; rotoscale() should never be called in conditional branches where angle = 0 anyway. - - Point32 newHotspot; - Common::Rect srcRect(0, 0, (int16)w, (int16)h); - Rect32 rect = TransformTools::newRect(Rect32(srcRect), transform, &newHotspot); - Common::Rect dstRect(0, 0, (int16)(rect.right - rect.left), (int16)(rect.bottom - rect.top)); - - TransparentSurface *target = new TransparentSurface(); - assert(format.bytesPerPixel == 4); - - int srcW = w; - int srcH = h; - int dstW = dstRect.width(); - int dstH = dstRect.height(); - - target->create((uint16)dstW, (uint16)dstH, this->format); - - if (transform._zoom.x == 0 || transform._zoom.y == 0) { - return target; - } - - uint32 invAngle = 360 - (transform._angle % 360); - float invCos = cos(invAngle * M_PI / 180.0); - float invSin = sin(invAngle * M_PI / 180.0); - - struct tColorRGBA { byte r; byte g; byte b; byte a; }; - int icosx = (int)(invCos * (65536.0f * kDefaultZoomX / transform._zoom.x)); - int isinx = (int)(invSin * (65536.0f * kDefaultZoomX / transform._zoom.x)); - int icosy = (int)(invCos * (65536.0f * kDefaultZoomY / transform._zoom.y)); - int isiny = (int)(invSin * (65536.0f * kDefaultZoomY / transform._zoom.y)); - - - bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor - - int xd = (srcRect.left + transform._hotspot.x) << 16; - int yd = (srcRect.top + transform._hotspot.y) << 16; - int cx = newHotspot.x; - int cy = newHotspot.y; - - int ax = -icosx * cx; - int ay = -isiny * cx; - int sw = srcW - 1; - int sh = srcH - 1; - - tColorRGBA *pc = (tColorRGBA*)target->getBasePtr(0, 0); - - for (int y = 0; y < dstH; y++) { - int t = cy - y; - int sdx = ax + (isinx * t) + xd; - int sdy = ay - (icosy * t) + yd; - for (int x = 0; x < dstW; x++) { - int dx = (sdx >> 16); - int dy = (sdy >> 16); - if (flipx) { - dx = sw - dx; - } - if (flipy) { - dy = sh - dy; - } - -#ifdef ENABLE_BILINEAR - if ((dx > -1) && (dy > -1) && (dx < sw) && (dy < sh)) { - const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy); - tColorRGBA c00, c01, c10, c11, cswap; - c00 = *sp; - sp += 1; - c01 = *sp; - sp += (this->pitch / 4); - c11 = *sp; - sp -= 1; - c10 = *sp; - if (flipx) { - cswap = c00; c00=c01; c01=cswap; - cswap = c10; c10=c11; c11=cswap; - } - if (flipy) { - cswap = c00; c00=c10; c10=cswap; - cswap = c01; c01=c11; c11=cswap; - } - /* - * Interpolate colors - */ - int ex = (sdx & 0xffff); - int ey = (sdy & 0xffff); - int t1, t2; - t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff; - t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff; - pc->r = (((t2 - t1) * ey) >> 16) + t1; - t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff; - t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff; - pc->g = (((t2 - t1) * ey) >> 16) + t1; - t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff; - t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff; - pc->b = (((t2 - t1) * ey) >> 16) + t1; - t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff; - t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff; - pc->a = (((t2 - t1) * ey) >> 16) + t1; - } -#else - if ((dx >= 0) && (dy >= 0) && (dx < srcW) && (dy < srcH)) { - const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy); - *pc = *sp; - } -#endif - sdx += icosx; - sdy += isiny; - pc++; - } - } - return target; -} - -TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) const { - - Common::Rect srcRect(0, 0, (int16)w, (int16)h); - Common::Rect dstRect(0, 0, (int16)newWidth, (int16)newHeight); - - TransparentSurface *target = new TransparentSurface(); - - assert(format.bytesPerPixel == 4); - - int srcW = srcRect.width(); - int srcH = srcRect.height(); - int dstW = dstRect.width(); - int dstH = dstRect.height(); - - target->create((uint16)dstW, (uint16)dstH, this->format); - -#ifdef ENABLE_BILINEAR - - // NB: The actual order of these bytes may not be correct, but - // since all values are treated equal, that does not matter. - struct tColorRGBA { byte r; byte g; byte b; byte a; }; - - bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor - - - int *sax = new int[dstW + 1]; - int *say = new int[dstH + 1]; - assert(sax && say); - - /* - * Precalculate row increments - */ - int spixelw = (srcW - 1); - int spixelh = (srcH - 1); - int sx = (int) (65536.0f * (float) spixelw / (float) (dstW - 1)); - int sy = (int) (65536.0f * (float) spixelh / (float) (dstH - 1)); - - /* Maximum scaled source size */ - int ssx = (srcW << 16) - 1; - int ssy = (srcH << 16) - 1; - - /* Precalculate horizontal row increments */ - int csx = 0; - int *csax = sax; - for (int x = 0; x <= dstW; x++) { - *csax = csx; - csax++; - csx += sx; - - /* Guard from overflows */ - if (csx > ssx) { - csx = ssx; - } - } - - /* Precalculate vertical row increments */ - int csy = 0; - int *csay = say; - for (int y = 0; y <= dstH; y++) { - *csay = csy; - csay++; - csy += sy; - - /* Guard from overflows */ - if (csy > ssy) { - csy = ssy; - } - } - - const tColorRGBA *sp = (const tColorRGBA *) getBasePtr(0, 0); - tColorRGBA *dp = (tColorRGBA *) target->getBasePtr(0, 0); - int spixelgap = srcW; - - if (flipx) { - sp += spixelw; - } - if (flipy) { - sp += spixelgap * spixelh; - } - - csay = say; - for (int y = 0; y < dstH; y++) { - const tColorRGBA *csp = sp; - csax = sax; - for (int x = 0; x < dstW; x++) { - /* - * Setup color source pointers - */ - int ex = (*csax & 0xffff); - int ey = (*csay & 0xffff); - int cx = (*csax >> 16); - int cy = (*csay >> 16); - - const tColorRGBA *c00, *c01, *c10, *c11; - c00 = sp; - c01 = sp; - c10 = sp; - if (cy < spixelh) { - if (flipy) { - c10 -= spixelgap; - } else { - c10 += spixelgap; - } - } - c11 = c10; - if (cx < spixelw) { - if (flipx) { - c01--; - c11--; - } else { - c01++; - c11++; - } - } - - /* - * Draw and interpolate colors - */ - int t1, t2; - t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff; - t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff; - dp->r = (((t2 - t1) * ey) >> 16) + t1; - t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff; - t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff; - dp->g = (((t2 - t1) * ey) >> 16) + t1; - t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff; - t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff; - dp->b = (((t2 - t1) * ey) >> 16) + t1; - t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff; - t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff; - dp->a = (((t2 - t1) * ey) >> 16) + t1; - - /* - * Advance source pointer x - */ - int *salastx = csax; - csax++; - int sstepx = (*csax >> 16) - (*salastx >> 16); - if (flipx) { - sp -= sstepx; - } else { - sp += sstepx; - } - - /* - * Advance destination pointer x - */ - dp++; - } - /* - * Advance source pointer y - */ - int *salasty = csay; - csay++; - int sstepy = (*csay >> 16) - (*salasty >> 16); - sstepy *= spixelgap; - if (flipy) { - sp = csp - sstepy; - } else { - sp = csp + sstepy; - } - } - - delete[] sax; - delete[] say; - -#else - - int *scaleCacheX = new int[dstW]; - for (int x = 0; x < dstW; x++) { - scaleCacheX[x] = (x * srcW) / dstW; - } - - for (int y = 0; y < dstH; y++) { - uint32 *destP = (uint32 *)target->getBasePtr(0, y); - const uint32 *srcP = (const uint32 *)getBasePtr(0, (y * srcH) / dstH); - for (int x = 0; x < dstW; x++) { - *destP++ = srcP[scaleCacheX[x]]; - } - } - delete[] scaleCacheX; - -#endif - - return target; - -} - -} // End of namespace Wintermute diff --git a/engines/wintermute/graphics/transparent_surface.h b/engines/wintermute/graphics/transparent_surface.h deleted file mode 100644 index 4ad9bf07eb..0000000000 --- a/engines/wintermute/graphics/transparent_surface.h +++ /dev/null @@ -1,176 +0,0 @@ -/* 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 GRAPHICS_TRANSPARENTSURFACE_H -#define GRAPHICS_TRANSPARENTSURFACE_H - -#include "graphics/surface.h" -#include "engines/wintermute/graphics/transform_struct.h" - -/* - * This code is based on Broken Sword 2.5 engine - * - * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer - * - * Licensed under GNU GPL v2 - * - */ - -// TODO: Find a better solution for this. -#define BS_RGB(R,G,B) (0xFF000000 | ((R) << 16) | ((G) << 8) | (B)) -#define BS_ARGB(A,R,G,B) (((A) << 24) | ((R) << 16) | ((G) << 8) | (B)) - -namespace Wintermute { - -/** - * A transparent graphics surface, which implements alpha blitting. - */ -struct TransparentSurface : public Graphics::Surface { - TransparentSurface(); - TransparentSurface(const Graphics::Surface &surf, bool copyData = false); - - void setColorKey(char r, char g, char b); - void disableColorKey(); - - // Enums - /** - @brief The possible flipping parameters for the blit methode. - */ - enum FLIP_FLAGS { - /// The image will not be flipped. - FLIP_NONE = 0, - /// The image will be flipped at the horizontal axis. - FLIP_H = 1, - /// The image will be flipped at the vertical axis. - FLIP_V = 2, - /// The image will be flipped at the horizontal and vertical axis. - FLIP_HV = FLIP_H | FLIP_V, - /// The image will be flipped at the horizontal and vertical axis. - FLIP_VH = FLIP_H | FLIP_V - }; - - enum AlphaType { - ALPHA_OPAQUE = 0, - ALPHA_BINARY = 1, - ALPHA_FULL = 2 - }; - -#ifdef SCUMM_LITTLE_ENDIAN - static const int kAIndex = 0; - static const int kBIndex = 1; - static const int kGIndex = 2; - static const int kRIndex = 3; -#else - static const int kAIndex = 3; - static const int kBIndex = 2; - static const int kGIndex = 1; - static const int kRIndex = 0; -#endif - - static const int kBShift = 8;//img->format.bShift; - static const int kGShift = 16;//img->format.gShift; - static const int kRShift = 24;//img->format.rShift; - static const int kAShift = 0;//img->format.aShift; - - - static const int kBModShift = 0;//img->format.bShift; - static const int kGModShift = 8;//img->format.gShift; - static const int kRModShift = 16;//img->format.rShift; - static const int kAModShift = 24;//img->format.aShift; - - - /** - @brief renders the surface to another surface - @param target a pointer to the target surface. In most cases this is the framebuffer. - @param posX the position on the X-axis in the target image in pixels where the image is supposed to be rendered.<br> - The default value is 0. - @param posY the position on the Y-axis in the target image in pixels where the image is supposed to be rendered.<br> - The default value is 0. - @param flipping how the the image should be flipped.<br> - The default value is BS_Image::FLIP_NONE (no flipping) - @param pPartRect Pointer on Common::Rect which specifies the section to be rendered. If the whole image has to be rendered the Pointer is NULL.<br> - This referes to the unflipped and unscaled image.<br> - The default value is NULL. - @param color an ARGB color value, which determines the parameters for the color modulation und alpha blending.<br> - The alpha component of the color determines the alpha blending parameter (0 = no covering, 255 = full covering).<br> - The color components determines the color for color modulation.<br> - The default value is BS_ARGB(255, 255, 255, 255) (full covering, no color modulation). - The macros BS_RGB and BS_ARGB can be used for the creation of the color value. - @param width the output width of the screen section. - The images will be scaled if the output width of the screen section differs from the image section.<br> - The value -1 determines that the image should not be scaled.<br> - The default value is -1. - @param height the output height of the screen section. - The images will be scaled if the output width of the screen section differs from the image section.<br> - The value -1 determines that the image should not be scaled.<br> - The default value is -1. - @return returns false if the rendering failed. - */ - Common::Rect blit(Graphics::Surface &target, int posX = 0, int posY = 0, - int flipping = FLIP_NONE, - Common::Rect *pPartRect = nullptr, - uint color = BS_ARGB(255, 255, 255, 255), - int width = -1, int height = -1, - TSpriteBlendMode blend = BLEND_NORMAL); - void applyColorKey(uint8 r, uint8 g, uint8 b, bool overwriteAlpha = false); - - /** - * @brief Scale function; this returns a transformed version of this surface after rotation and - * scaling. Please do not use this if angle != 0, use rotoscale. - * - * @param newWidth the resulting width. - * @param newHeight the resulting height. - * @see TransformStruct - */ - TransparentSurface *scale(uint16 newWidth, uint16 newHeight) const; - - /** - * @brief Rotoscale function; this returns a transformed version of this surface after rotation and - * scaling. Please do not use this if angle == 0, use plain old scaling function. - * - * @param transform a TransformStruct wrapping the required info. @see TransformStruct - * - */ - TransparentSurface *rotoscale(const TransformStruct &transform) const; - AlphaType getAlphaMode() const; - void setAlphaMode(AlphaType); -private: - AlphaType _alphaMode; - -}; - -/** - * A deleter for Surface objects which can be used with SharedPtr. - * - * This deleter assures Surface::free is called on deletion. - */ -/*struct SharedPtrTransparentSurfaceDeleter { - void operator()(TransparentSurface *ptr) { - ptr->free(); - delete ptr; - } -};*/ - -} // End of namespace Wintermute - - -#endif diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk index 19fb3d6717..1b6c52e0b7 100644 --- a/engines/wintermute/module.mk +++ b/engines/wintermute/module.mk @@ -89,9 +89,6 @@ MODULE_OBJS := \ base/save_thumb_helper.o \ base/timer.o \ detection.o \ - graphics/transform_struct.o \ - graphics/transform_tools.o \ - graphics/transparent_surface.o \ math/math_util.o \ math/matrix4.o \ math/vector2.o \ diff --git a/engines/wintermute/utils/utils.cpp b/engines/wintermute/utils/utils.cpp index d592019418..dc6476d4ea 100644 --- a/engines/wintermute/utils/utils.cpp +++ b/engines/wintermute/utils/utils.cpp @@ -32,11 +32,6 @@ namespace Wintermute { -////////////////////////////////////////////////////////////////////// -static inline unsigned Sqr(int x) { - return (x * x); -} - ////////////////////////////////////////////////////////////////////////////////// // Swap - swaps two integers ////////////////////////////////////////////////////////////////////////////////// diff --git a/engines/zvision/scripting/actions.cpp b/engines/zvision/scripting/actions.cpp index e854378ae4..517278e155 100644 --- a/engines/zvision/scripting/actions.cpp +++ b/engines/zvision/scripting/actions.cpp @@ -155,7 +155,7 @@ bool ActionEnableControl::execute(ZVision *engine) { ActionMusic::ActionMusic(const Common::String &line) : _volume(255) { uint type; - char fileNameBuffer[25]; + char fileNameBuffer[26]; uint loop; uint volume = 255; @@ -211,7 +211,7 @@ bool ActionMusic::execute(ZVision *engine) { ////////////////////////////////////////////////////////////////////////////// ActionPreloadAnimation::ActionPreloadAnimation(const Common::String &line) { - char fileName[25]; + char fileName[26]; // The two %*u are always 0 and dont seem to have a use sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%25s %*u %*u %u %u)", &_key, fileName, &_mask, &_framerate); @@ -238,7 +238,7 @@ bool ActionPreloadAnimation::execute(ZVision *engine) { ////////////////////////////////////////////////////////////////////////////// ActionPlayAnimation::ActionPlayAnimation(const Common::String &line) { - char fileName[25]; + char fileName[26]; // The two %*u are always 0 and dont seem to have a use sscanf(line.c_str(), @@ -312,7 +312,7 @@ bool ActionRandom::execute(ZVision *engine) { ////////////////////////////////////////////////////////////////////////////// ActionSetPartialScreen::ActionSetPartialScreen(const Common::String &line) { - char fileName[25]; + char fileName[26]; uint color; sscanf(line.c_str(), "%*[^(](%u %u %25s %*u %u)", &_x, &_y, fileName, &color); @@ -342,7 +342,7 @@ bool ActionSetPartialScreen::execute(ZVision *engine) { ////////////////////////////////////////////////////////////////////////////// ActionSetScreen::ActionSetScreen(const Common::String &line) { - char fileName[25]; + char fileName[26]; sscanf(line.c_str(), "%*[^(](%25[^)])", fileName); _fileName = Common::String(fileName); @@ -360,7 +360,7 @@ bool ActionSetScreen::execute(ZVision *engine) { ////////////////////////////////////////////////////////////////////////////// ActionStreamVideo::ActionStreamVideo(const Common::String &line) { - char fileName[25]; + char fileName[26]; uint skippable; sscanf(line.c_str(), "%*[^(](%25s %u %u %u %u %u %u)", fileName, &_x1, &_y1, &_x2, &_y2, &_flags, &skippable); diff --git a/engines/zvision/scripting/controls/input_control.cpp b/engines/zvision/scripting/controls/input_control.cpp index 5cf5086691..a35548d02e 100644 --- a/engines/zvision/scripting/controls/input_control.cpp +++ b/engines/zvision/scripting/controls/input_control.cpp @@ -75,7 +75,7 @@ InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStre } else if (line.matchString("*next_tabstop*", true)) { sscanf(line.c_str(), "%*[^(](%u)", &_nextTabstop); } else if (line.matchString("*cursor_animation*", true)) { - char fileName[25]; + char fileName[26]; sscanf(line.c_str(), "%*[^(](%25s %*u)", fileName); |