diff options
Diffstat (limited to 'engines')
114 files changed, 2836 insertions, 2116 deletions
diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index 5ddc5d625f..747c9221ee 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -49,8 +49,6 @@ struct AnimHeader2Struct { uint16 field_E; }; -Common::Array<AnimData> animDataTable; - static const AnimDataEntry transparencyData[] = { {"ALPHA", 0xF}, {"TITRE2", 0xF}, @@ -400,7 +398,7 @@ void AnimData::save(Common::OutSaveFile &fHandle) const { */ void freeAnimDataRange(byte startIdx, byte numIdx) { for (byte i = 0; i < numIdx; i++) { - animDataTable[startIdx + i].clear(); + g_cine->_animDataTable[startIdx + i].clear(); } } @@ -514,7 +512,7 @@ void loadAnimHeader(AnimHeaderStruct &animHeader, Common::MemoryReadStream readS */ int emptyAnimSpace(int start = 0) { for (; start < NUM_MAX_ANIMDATA; start++) { - if (!animDataTable[start].data()) { + if (!g_cine->_animDataTable[start].data()) { return start; } } @@ -540,7 +538,7 @@ int loadSpl(const char *resourceName, int16 idx) { entry = idx < 0 ? emptyAnimSpace() : idx; assert(entry >= 0); - animDataTable[entry].load(dataPtr, ANIM_RAW, partBuffer[foundFileIdx].unpackedSize, 1, foundFileIdx, 0, currentPartName); + g_cine->_animDataTable[entry].load(dataPtr, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize, 1, foundFileIdx, 0, currentPartName); free(dataPtr); return entry + 1; @@ -570,7 +568,7 @@ int loadMsk(const char *resourceName, int16 idx) { entry = idx < 0 ? emptyAnimSpace() : idx; assert(entry >= 0); for (int16 i = 0; i < animHeader.numFrames; i++, entry++) { - animDataTable[entry].load(ptr, ANIM_MASK, animHeader.frameWidth, animHeader.frameHeight, foundFileIdx, i, currentPartName); + g_cine->_animDataTable[entry].load(ptr, ANIM_MASK, animHeader.frameWidth, animHeader.frameHeight, foundFileIdx, i, currentPartName); ptr += animHeader.frameWidth * animHeader.frameHeight; } @@ -621,7 +619,7 @@ int loadAni(const char *resourceName, int16 idx) { transparentColor = i < 1 ? 0xE : 0; } - animDataTable[entry].load(ptr, ANIM_MASKSPRITE, animHeader.frameWidth, animHeader.frameHeight, foundFileIdx, i, currentPartName, transparentColor); + g_cine->_animDataTable[entry].load(ptr, ANIM_MASKSPRITE, animHeader.frameWidth, animHeader.frameHeight, foundFileIdx, i, currentPartName, transparentColor); ptr += animHeader.frameWidth * animHeader.frameHeight; } @@ -737,7 +735,7 @@ int loadSet(const char *resourceName, int16 idx) { type = ANIM_FULLSPRITE; } - animDataTable[entry].load(dataPtr, type, header2.width, header2.height, foundFileIdx, i, currentPartName); + g_cine->_animDataTable[entry].load(dataPtr, type, header2.width, header2.height, foundFileIdx, i, currentPartName); } free(origDataPtr); @@ -759,7 +757,7 @@ int loadSeq(const char *resourceName, int16 idx) { byte *dataPtr = readBundleFile(foundFileIdx); int entry = idx < 0 ? emptyAnimSpace() : idx; - animDataTable[entry].load(dataPtr+0x16, ANIM_RAW, partBuffer[foundFileIdx].unpackedSize-0x16, 1, foundFileIdx, 0, currentPartName); + g_cine->_animDataTable[entry].load(dataPtr+0x16, ANIM_RAW, g_cine->_partBuffer[foundFileIdx].unpackedSize-0x16, 1, foundFileIdx, 0, currentPartName); free(dataPtr); return entry + 1; } diff --git a/engines/cine/anim.h b/engines/cine/anim.h index e67237aac0..2012ef875e 100644 --- a/engines/cine/anim.h +++ b/engines/cine/anim.h @@ -99,8 +99,6 @@ public: #define NUM_MAX_ANIMDATA 255 -extern Common::Array<AnimData> animDataTable; - void freeAnimDataTable(); void freeAnimDataRange(byte startIdx, byte numIdx); int loadResource(const char *resourceName, int16 idx = -1); diff --git a/engines/cine/bg_list.cpp b/engines/cine/bg_list.cpp index 26351becf1..3ecda4125d 100644 --- a/engines/cine/bg_list.cpp +++ b/engines/cine/bg_list.cpp @@ -36,14 +36,13 @@ namespace Cine { uint32 var8; -Common::List<BGIncrust> bgIncrustList; /** * Add masked sprite to the background * @param objIdx Sprite description */ void addToBGList(int16 objIdx) { - renderer->incrustSprite(objectTable[objIdx]); + renderer->incrustSprite(g_cine->_objectTable[objIdx]); createBgIncrustListElement(objIdx, 0); } @@ -53,7 +52,7 @@ void addToBGList(int16 objIdx) { * @param objIdx Sprite description */ void addSpriteFilledToBGList(int16 objIdx) { - renderer->incrustMask(objectTable[objIdx]); + renderer->incrustMask(g_cine->_objectTable[objIdx]); createBgIncrustListElement(objIdx, 1); } @@ -69,12 +68,12 @@ void createBgIncrustListElement(int16 objIdx, int16 param) { tmp.unkPtr = 0; tmp.objIdx = objIdx; tmp.param = param; - tmp.x = objectTable[objIdx].x; - tmp.y = objectTable[objIdx].y; - tmp.frame = objectTable[objIdx].frame; - tmp.part = objectTable[objIdx].part; + tmp.x = g_cine->_objectTable[objIdx].x; + tmp.y = g_cine->_objectTable[objIdx].y; + tmp.frame = g_cine->_objectTable[objIdx].frame; + tmp.part = g_cine->_objectTable[objIdx].part; - bgIncrustList.push_back(tmp); + g_cine->_bgIncrustList.push_back(tmp); } /** @@ -104,12 +103,12 @@ void loadBgIncrustFromSave(Common::SeekableReadStream &fHandle) { tmp.frame = fHandle.readUint16BE(); tmp.part = fHandle.readUint16BE(); - bgIncrustList.push_back(tmp); + g_cine->_bgIncrustList.push_back(tmp); if (tmp.param == 0) { - renderer->incrustSprite(objectTable[tmp.objIdx]); + renderer->incrustSprite(g_cine->_objectTable[tmp.objIdx]); } else { - renderer->incrustMask(objectTable[tmp.objIdx]); + renderer->incrustMask(g_cine->_objectTable[tmp.objIdx]); } } } diff --git a/engines/cine/bg_list.h b/engines/cine/bg_list.h index 409b16dbd5..8c1b3cb6ec 100644 --- a/engines/cine/bg_list.h +++ b/engines/cine/bg_list.h @@ -42,7 +42,6 @@ struct BGIncrust { int16 part; }; -extern Common::List<BGIncrust> bgIncrustList; extern uint32 var8; void addToBGList(int16 objIdx); diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index e6ac2859cf..5c2119c1e4 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -123,24 +123,26 @@ int CineEngine::modifyGameSpeed(int speedChange) { } void CineEngine::initialize() { + _globalVars.reinit(NUM_MAX_VAR + 1); + // Initialize all savegames' descriptions to empty strings memset(currentSaveName, 0, sizeof(currentSaveName)); // Resize object table to its correct size and reset all its elements - objectTable.resize(NUM_MAX_OBJECT); + g_cine->_objectTable.resize(NUM_MAX_OBJECT); resetObjectTable(); // Resize animation data table to its correct size and reset all its elements - animDataTable.resize(NUM_MAX_ANIMDATA); + g_cine->_animDataTable.resize(NUM_MAX_ANIMDATA); freeAnimDataTable(); // Resize zone data table to its correct size and reset all its elements - zoneData.resize(NUM_MAX_ZONE); - Common::set_to(zoneData.begin(), zoneData.end(), 0); + g_cine->_zoneData.resize(NUM_MAX_ZONE); + Common::set_to(g_cine->_zoneData.begin(), g_cine->_zoneData.end(), 0); // Resize zone query table to its correct size and reset all its elements - zoneQuery.resize(NUM_MAX_ZONE); - Common::set_to(zoneQuery.begin(), zoneQuery.end(), 0); + g_cine->_zoneQuery.resize(NUM_MAX_ZONE); + Common::set_to(g_cine->_zoneQuery.begin(), g_cine->_zoneQuery.end(), 0); _timerDelayMultiplier = 12; // Set default speed setupOpcodes(); @@ -159,7 +161,7 @@ void CineEngine::initialize() { // Clear part buffer as there's nothing loaded into it yet. // Its size will change when loading data into it with the loadPart function. - partBuffer.clear(); + g_cine->_partBuffer.clear(); if (getGameType() == Cine::GType_OS) { readVolCnf(); @@ -173,14 +175,14 @@ void CineEngine::initialize() { } // in case ScummVM engines can be restarted in the future - scriptTable.clear(); - relTable.clear(); - objectScripts.clear(); - globalScripts.clear(); - bgIncrustList.clear(); + g_cine->_scriptTable.clear(); + g_cine->_relTable.clear(); + g_cine->_objectScripts.clear(); + g_cine->_globalScripts.clear(); + g_cine->_bgIncrustList.clear(); freeAnimDataTable(); - overlayList.clear(); - messageTable.clear(); + g_cine->_overlayList.clear(); + g_cine->_messageTable.clear(); resetObjectTable(); var8 = 0; diff --git a/engines/cine/cine.h b/engines/cine/cine.h index 6f2c2243e2..114d98d442 100644 --- a/engines/cine/cine.h +++ b/engines/cine/cine.h @@ -47,6 +47,8 @@ #include "cine/pal.h" #include "cine/gfx.h" #include "cine/anim.h" +#include "cine/bg_list.h" +#include "cine/various.h" //#define DUMP_SCRIPTS @@ -93,6 +95,7 @@ enum CineGameFeatures { }; struct CINEGameDescription; +struct SeqListElement; typedef Common::HashMap<Common::String, const char *> StringPtrHashMap; @@ -150,6 +153,36 @@ private: bool _preLoad; int _timerDelayMultiplier; + + public: + // TODO: These are pseudo-global vars + // They better belong to appropriate classes + Common::Array<AnimData> _animDataTable; + Common::List<BGIncrust> _bgIncrustList; + Common::StringArray _messageTable; + Common::Array<ObjectStruct> _objectTable; + Common::List<overlay> _overlayList; + Common::Array<PalEntry> _palArray; + Common::Array<PartBuffer> _partBuffer; + ScriptList _globalScripts; + ScriptList _objectScripts; + RawObjectScriptArray _relTable; ///< Object script bytecode table + + /** + * Global variables. + * 255 of these are saved, but there's one more that's used for bypassing the copy protection. + * In CineEngine::mainLoop(int bootScriptIdx) there's this code: globalVars[VAR_BYPASS_PROTECTION] = 0; + * And as VAR_BYPASS_PROTECTION is 255 that's why we're allocating one more than we otherwise would. + */ + ScriptVars _globalVars; + RawScriptArray _scriptTable; ///< Table of script bytecode + + Common::Array<uint16> _zoneData; + Common::Array<uint16> _zoneQuery; ///< Only exists in Operation Stealth + + Common::List<SeqListElement> _seqList; + + Common::String _commandBuffer; }; extern CineEngine *g_cine; diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index 1f747c5a01..4d61be102b 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -160,13 +160,13 @@ void FWRenderer::clear() { * @param fillColor Sprite color */ void FWRenderer::fillSprite(const ObjectStruct &obj, uint8 color) { - const byte *data = animDataTable[obj.frame].data(); + const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height; x = obj.x; y = obj.y; - width = animDataTable[obj.frame]._realWidth; - height = animDataTable[obj.frame]._height; + width = g_cine->_animDataTable[obj.frame]._realWidth; + height = g_cine->_animDataTable[obj.frame]._height; gfxFillSprite(data, width, height, _backBuffer, x, y, color); } @@ -177,13 +177,13 @@ void FWRenderer::fillSprite(const ObjectStruct &obj, uint8 color) { * @param fillColor Sprite color */ void FWRenderer::incrustMask(const ObjectStruct &obj, uint8 color) { - const byte *data = animDataTable[obj.frame].data(); + const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height; x = obj.x; y = obj.y; - width = animDataTable[obj.frame]._realWidth; - height = animDataTable[obj.frame]._height; + width = g_cine->_animDataTable[obj.frame]._realWidth; + height = g_cine->_animDataTable[obj.frame]._height; gfxFillSprite(data, width, height, _background, x, y, color); } @@ -194,13 +194,13 @@ void FWRenderer::incrustMask(const ObjectStruct &obj, uint8 color) { * @param mask External mask */ void FWRenderer::drawMaskedSprite(const ObjectStruct &obj, const byte *mask) { - const byte *data = animDataTable[obj.frame].data(); + const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height; x = obj.x; y = obj.y; - width = animDataTable[obj.frame]._realWidth; - height = animDataTable[obj.frame]._height; + width = g_cine->_animDataTable[obj.frame]._realWidth; + height = g_cine->_animDataTable[obj.frame]._height; assert(mask); @@ -212,7 +212,7 @@ void FWRenderer::drawMaskedSprite(const ObjectStruct &obj, const byte *mask) { * @param obj Object info */ void FWRenderer::drawSprite(const ObjectStruct &obj) { - const byte *mask = animDataTable[obj.frame].mask(); + const byte *mask = g_cine->_animDataTable[obj.frame].mask(); drawMaskedSprite(obj, mask); } @@ -221,14 +221,14 @@ void FWRenderer::drawSprite(const ObjectStruct &obj) { * @param obj Object info */ void FWRenderer::incrustSprite(const ObjectStruct &obj) { - const byte *data = animDataTable[obj.frame].data(); - const byte *mask = animDataTable[obj.frame].mask(); + const byte *data = g_cine->_animDataTable[obj.frame].data(); + const byte *mask = g_cine->_animDataTable[obj.frame].mask(); int x, y, width, height; x = obj.x; y = obj.y; - width = animDataTable[obj.frame]._realWidth; - height = animDataTable[obj.frame]._height; + width = g_cine->_animDataTable[obj.frame]._realWidth; + height = g_cine->_animDataTable[obj.frame]._height; // There was an assert(mask) here before but it made savegame loading // in Future Wars sometimes fail the assertion (e.g. see bug #2055912). @@ -502,27 +502,27 @@ void FWRenderer::drawLine(int x, int y, int width, int height, byte color) { * @param it Overlay info from overlayList */ void FWRenderer::remaskSprite(byte *mask, Common::List<overlay>::iterator it) { - AnimData &sprite = animDataTable[objectTable[it->objIdx].frame]; + AnimData &sprite = g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; int x, y, width, height, idx; int mx, my, mw, mh; - x = objectTable[it->objIdx].x; - y = objectTable[it->objIdx].y; + x = g_cine->_objectTable[it->objIdx].x; + y = g_cine->_objectTable[it->objIdx].y; width = sprite._realWidth; height = sprite._height; - for (++it; it != overlayList.end(); ++it) { + for (++it; it != g_cine->_overlayList.end(); ++it) { if (it->type != 5) { continue; } - idx = ABS(objectTable[it->objIdx].frame); - mx = objectTable[it->objIdx].x; - my = objectTable[it->objIdx].y; - mw = animDataTable[idx]._realWidth; - mh = animDataTable[idx]._height; + idx = ABS(g_cine->_objectTable[it->objIdx].frame); + mx = g_cine->_objectTable[it->objIdx].x; + my = g_cine->_objectTable[it->objIdx].y; + mw = g_cine->_animDataTable[idx]._realWidth; + mh = g_cine->_animDataTable[idx]._height; - gfxUpdateSpriteMask(mask, x, y, width, height, animDataTable[idx].data(), mx, my, mw, mh); + gfxUpdateSpriteMask(mask, x, y, width, height, g_cine->_animDataTable[idx].data(), mx, my, mw, mh); } } @@ -547,26 +547,26 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { switch (it->type) { // color sprite case 0: - if (objectTable[it->objIdx].frame < 0) { + if (g_cine->_objectTable[it->objIdx].frame < 0) { return; } - sprite = &animDataTable[objectTable[it->objIdx].frame]; + sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; len = sprite->_realWidth * sprite->_height; mask = new byte[len]; memcpy(mask, sprite->mask(), len); remaskSprite(mask, it); - drawMaskedSprite(objectTable[it->objIdx], mask); + drawMaskedSprite(g_cine->_objectTable[it->objIdx], mask); delete[] mask; break; // game message case 2: - if (it->objIdx >= messageTable.size()) { + if (it->objIdx >= g_cine->_messageTable.size()) { return; } - _messageLen += messageTable[it->objIdx].size(); - drawMessage(messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color); + _messageLen += g_cine->_messageTable[it->objIdx].size(); + drawMessage(g_cine->_messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color); waitForPlayerClick = 1; break; @@ -585,13 +585,13 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { // bitmap case 4: assert(it->objIdx < NUM_MAX_OBJECT); - obj = &objectTable[it->objIdx]; + obj = &g_cine->_objectTable[it->objIdx]; if (obj->frame < 0) { return; } - if (!animDataTable[obj->frame].data()) { + if (!g_cine->_animDataTable[obj->frame].data()) { return; } @@ -606,7 +606,7 @@ void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { void FWRenderer::drawOverlays() { Common::List<overlay>::iterator it; - for (it = overlayList.begin(); it != overlayList.end(); ++it) { + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { renderOverlay(it); } } @@ -1122,13 +1122,13 @@ void OSRenderer::clear() { * @param fillColor Sprite color */ void OSRenderer::incrustMask(const ObjectStruct &obj, uint8 color) { - const byte *data = animDataTable[obj.frame].data(); + const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height; x = obj.x; y = obj.y; - width = animDataTable[obj.frame]._realWidth; - height = animDataTable[obj.frame]._height; + width = g_cine->_animDataTable[obj.frame]._realWidth; + height = g_cine->_animDataTable[obj.frame]._height; if (_bgTable[_currentBg].bg) { gfxFillSprite(data, width, height, _bgTable[_currentBg].bg, x, y, color); @@ -1140,14 +1140,14 @@ void OSRenderer::incrustMask(const ObjectStruct &obj, uint8 color) { * @param obj Object info */ void OSRenderer::drawSprite(const ObjectStruct &obj) { - const byte *data = animDataTable[obj.frame].data(); + const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height, transColor; x = obj.x; y = obj.y; transColor = obj.part; - width = animDataTable[obj.frame]._realWidth; - height = animDataTable[obj.frame]._height; + width = g_cine->_animDataTable[obj.frame]._realWidth; + height = g_cine->_animDataTable[obj.frame]._height; drawSpriteRaw2(data, transColor, width, height, _backBuffer, x, y); } @@ -1157,14 +1157,14 @@ void OSRenderer::drawSprite(const ObjectStruct &obj) { * @param obj Object info */ void OSRenderer::incrustSprite(const ObjectStruct &obj) { - const byte *data = animDataTable[obj.frame].data(); + const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height, transColor; x = obj.x; y = obj.y; transColor = obj.part; - width = animDataTable[obj.frame]._realWidth; - height = animDataTable[obj.frame]._height; + width = g_cine->_animDataTable[obj.frame]._realWidth; + height = g_cine->_animDataTable[obj.frame]._height; if (_bgTable[_currentBg].bg) { drawSpriteRaw2(data, transColor, width, height, _bgTable[_currentBg].bg, x, y); @@ -1233,26 +1233,26 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { switch (it->type) { // color sprite case 0: - if (objectTable[it->objIdx].frame < 0) { + if (g_cine->_objectTable[it->objIdx].frame < 0) { break; } - sprite = &animDataTable[objectTable[it->objIdx].frame]; + sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; len = sprite->_realWidth * sprite->_height; mask = new byte[len]; - generateMask(sprite->data(), mask, len, objectTable[it->objIdx].part); + generateMask(sprite->data(), mask, len, g_cine->_objectTable[it->objIdx].part); remaskSprite(mask, it); - drawMaskedSprite(objectTable[it->objIdx], mask); + drawMaskedSprite(g_cine->_objectTable[it->objIdx], mask); delete[] mask; break; // game message case 2: - if (it->objIdx >= messageTable.size()) { + if (it->objIdx >= g_cine->_messageTable.size()) { return; } - _messageLen += messageTable[it->objIdx].size(); - drawMessage(messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color); + _messageLen += g_cine->_messageTable[it->objIdx].size(); + drawMessage(g_cine->_messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color); if (it->color >= 0) { // This test isn't in Future Wars's implementation waitForPlayerClick = 1; } @@ -1273,7 +1273,7 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { // bitmap case 4: - if (objectTable[it->objIdx].frame >= 0) { + if (g_cine->_objectTable[it->objIdx].frame >= 0) { FWRenderer::renderOverlay(it); } break; @@ -1282,8 +1282,8 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { case 20: assert(it->objIdx < NUM_MAX_OBJECT); var5 = it->x; // A global variable updated here! - obj = &objectTable[it->objIdx]; - sprite = &animDataTable[obj->frame]; + obj = &g_cine->_objectTable[it->objIdx]; + sprite = &g_cine->_animDataTable[obj->frame]; if (obj->frame < 0 || it->x < 0 || it->x > 8 || !_bgTable[it->x].bg || sprite->_bpp != 1) { break; @@ -1303,7 +1303,7 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { case 22: // TODO: Check it this implementation really works correctly (Some things might be wrong, needs testing). assert(it->objIdx < NUM_MAX_OBJECT); - obj = &objectTable[it->objIdx]; + obj = &g_cine->_objectTable[it->objIdx]; color = obj->part & 0x0F; width = obj->frame; height = obj->costume; @@ -1797,17 +1797,17 @@ void maskBgOverlay(const byte *bgPtr, const byte *maskPtr, int16 width, int16 he maskPtr = backup; // incrust pass - for (it = bgIncrustList.begin(); it != bgIncrustList.end(); ++it) { - tmpWidth = animDataTable[it->frame]._realWidth; - tmpHeight = animDataTable[it->frame]._height; + for (it = g_cine->_bgIncrustList.begin(); it != g_cine->_bgIncrustList.end(); ++it) { + tmpWidth = g_cine->_animDataTable[it->frame]._realWidth; + tmpHeight = g_cine->_animDataTable[it->frame]._height; mask = (byte*)malloc(tmpWidth * tmpHeight); if (it->param == 0) { - generateMask(animDataTable[it->frame].data(), mask, tmpWidth * tmpHeight, it->part); + generateMask(g_cine->_animDataTable[it->frame].data(), mask, tmpWidth * tmpHeight, it->part); gfxUpdateIncrustMask(mask, it->x, it->y, tmpWidth, tmpHeight, maskPtr, x, y, width, height); - gfxDrawMaskedSprite(animDataTable[it->frame].data(), mask, tmpWidth, tmpHeight, page, it->x, it->y); + gfxDrawMaskedSprite(g_cine->_animDataTable[it->frame].data(), mask, tmpWidth, tmpHeight, page, it->x, it->y); } else { - memcpy(mask, animDataTable[it->frame].data(), tmpWidth * tmpHeight); + memcpy(mask, g_cine->_animDataTable[it->frame].data(), tmpWidth * tmpHeight); gfxUpdateIncrustMask(mask, it->x, it->y, tmpWidth, tmpHeight, maskPtr, x, y, width, height); gfxFillSprite(mask, tmpWidth, tmpHeight, page, it->x, it->y); } diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 414aed394c..3d280c20ef 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -241,11 +241,11 @@ int getKeyData() { /** Removes elements from seqList that have their member variable var4 set to value -1. */ void purgeSeqList() { - Common::List<SeqListElement>::iterator it = seqList.begin(); - while (it != seqList.end()) { + Common::List<SeqListElement>::iterator it = g_cine->_seqList.begin(); + while (it != g_cine->_seqList.end()) { if (it->var4 == -1) { // Erase the element and jump to the next element - it = seqList.erase(it); + it = g_cine->_seqList.erase(it); } else { // Let the element be and jump to the next element it++; @@ -283,15 +283,15 @@ void CineEngine::mainLoop(int bootScriptIdx) { menuCommandLen = 0; playerCommand = -1; - commandBuffer = ""; + g_cine->_commandBuffer = ""; - globalVars[VAR_MOUSE_X_POS] = 0; - globalVars[VAR_MOUSE_Y_POS] = 0; + g_cine->_globalVars[VAR_MOUSE_X_POS] = 0; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = 0; if (g_cine->getGameType() == Cine::GType_OS) { - globalVars[VAR_MOUSE_X_POS_2ND] = 0; - globalVars[VAR_MOUSE_Y_POS_2ND] = 0; - globalVars[VAR_BYPASS_PROTECTION] = 0; // set to 1 to bypass the copy protection - globalVars[VAR_LOW_MEMORY] = 0; // set to 1 to disable some animations, sounds etc. + g_cine->_globalVars[VAR_MOUSE_X_POS_2ND] = 0; + g_cine->_globalVars[VAR_MOUSE_Y_POS_2ND] = 0; + g_cine->_globalVars[VAR_BYPASS_PROTECTION] = 0; // set to 1 to bypass the copy protection + g_cine->_globalVars[VAR_LOW_MEMORY] = 0; // set to 1 to disable some animations, sounds etc. } strcpy(newPrcName, ""); @@ -315,7 +315,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { if (bgName == "28.PI1" || bgName == "29.PI1" || bgName == "30.PI1") { static const uint oxygenObjNum = 202, maxOxygen = 264; // Force the amount of oxygen left to the maximum. - objectTable[oxygenObjNum].x = maxOxygen; + g_cine->_objectTable[oxygenObjNum].x = maxOxygen; } } @@ -332,8 +332,8 @@ void CineEngine::mainLoop(int bootScriptIdx) { // flower shop scene is AIRPORT.PRC's 13th script. // FIXME: Remove the hack and solve what's really causing the problem in the first place. if (g_cine->getGameType() == Cine::GType_OS) { - if (scumm_stricmp(renderer->getBgName(), "21.PI1") == 0 && objectTable[1].x == 204 && objectTable[1].y == 110) { - objectTable[1].y--; // Move the player character upward on-screen by one pixel + if (scumm_stricmp(renderer->getBgName(), "21.PI1") == 0 && g_cine->_objectTable[1].x == 204 && g_cine->_objectTable[1].y == 110) { + g_cine->_objectTable[1].y--; // Move the player character upward on-screen by one pixel } } @@ -342,7 +342,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { // Clear the zoneQuery table (Operation Stealth specific) if (g_cine->getGameType() == Cine::GType_OS) { - Common::set_to(zoneQuery.begin(), zoneQuery.end(), 0); + Common::set_to(g_cine->_zoneQuery.begin(), g_cine->_zoneQuery.end(), 0); } if (g_cine->getGameType() == Cine::GType_OS) { diff --git a/engines/cine/msg.cpp b/engines/cine/msg.cpp index 45f81f7d05..a01afd147b 100644 --- a/engines/cine/msg.cpp +++ b/engines/cine/msg.cpp @@ -31,15 +31,11 @@ namespace Cine { -// FIXME: Global C++ objects affect portability negatively. -// Turn this into a class member instead. -Common::StringArray messageTable; - void loadMsg(char *pMsgName) { uint32 sourceSize; checkDataDisk(-1); - messageTable.clear(); + g_cine->_messageTable.clear(); byte *dataPtr = readBundleFile(findFileInBundle(pMsgName), &sourceSize); setMouseCursor(MOUSE_CURSOR_DISK); @@ -58,7 +54,7 @@ void loadMsg(char *pMsgName) { // This code works around input data that has empty strings residing outside the input // buffer (e.g. message indexes 58-254 in BATEAU.MSG in PROCS08 in Operation Stealth). if (messageDataPos < sourceSize) { - messageTable.push_back((const char *)(dataPtr + messageDataPos)); + g_cine->_messageTable.push_back((const char *)(dataPtr + messageDataPos)); } else { if (messageLen > 0) { // Only warn about overflowing non-empty strings warning("loadMsg(%s): message (%d. / %d) is overflowing the input buffer. Replacing it with an empty string", pMsgName, i + 1, count); @@ -66,7 +62,7 @@ void loadMsg(char *pMsgName) { debugC(5, kCineDebugPart, "loadMsg(%s): empty message (%d. / %d) resides outside input buffer", pMsgName, i + 1, count); } // Message resides outside the input buffer so we replace it with an empty string - messageTable.push_back(""); + g_cine->_messageTable.push_back(""); } // Jump to the next message messageDataPos += messageLen; diff --git a/engines/cine/msg.h b/engines/cine/msg.h index cf51cdb48f..fbf99d4b44 100644 --- a/engines/cine/msg.h +++ b/engines/cine/msg.h @@ -32,8 +32,6 @@ namespace Cine { #define NUM_MAX_MESSAGE 255 -extern Common::StringArray messageTable; - void loadMsg(char *pMsgName); } // End of namespace Cine diff --git a/engines/cine/object.cpp b/engines/cine/object.cpp index 116b57c267..82dc0a6ef1 100644 --- a/engines/cine/object.cpp +++ b/engines/cine/object.cpp @@ -35,12 +35,9 @@ namespace Cine { -Common::Array<ObjectStruct> objectTable; -Common::List<overlay> overlayList; - /** Resets all elements in the object table. */ void resetObjectTable() { - for (Common::Array<ObjectStruct>::iterator it = objectTable.begin(); it != objectTable.end(); ++it) { + for (Common::Array<ObjectStruct>::iterator it = g_cine->_objectTable.begin(); it != g_cine->_objectTable.end(); ++it) { it->clear(); } } @@ -64,23 +61,23 @@ void loadObject(char *pObjectName) { assert(numEntry <= NUM_MAX_OBJECT); for (i = 0; i < numEntry; i++) { - if (objectTable[i].costume != -2) { // flag is keep ? + if (g_cine->_objectTable[i].costume != -2) { // flag is keep ? Common::MemoryReadStream readS(ptr, entrySize); - objectTable[i].x = readS.readSint16BE(); - objectTable[i].y = readS.readSint16BE(); - objectTable[i].mask = readS.readUint16BE(); - objectTable[i].frame = readS.readSint16BE(); - objectTable[i].costume = readS.readSint16BE(); - readS.read(objectTable[i].name, 20); - objectTable[i].part = readS.readUint16BE(); + g_cine->_objectTable[i].x = readS.readSint16BE(); + g_cine->_objectTable[i].y = readS.readSint16BE(); + g_cine->_objectTable[i].mask = readS.readUint16BE(); + g_cine->_objectTable[i].frame = readS.readSint16BE(); + g_cine->_objectTable[i].costume = readS.readSint16BE(); + readS.read(g_cine->_objectTable[i].name, 20); + g_cine->_objectTable[i].part = readS.readUint16BE(); } ptr += entrySize; } if (!strcmp(pObjectName, "INTRO.OBJ")) { for (i = 0; i < 10; i++) { - objectTable[i].costume = 0; + g_cine->_objectTable[i].costume = 0; } } @@ -95,9 +92,9 @@ void loadObject(char *pObjectName) { int removeOverlay(uint16 objIdx, uint16 param) { Common::List<overlay>::iterator it; - for (it = overlayList.begin(); it != overlayList.end(); ++it) { + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { if (it->objIdx == objIdx && it->type == param) { - overlayList.erase(it); + g_cine->_overlayList.erase(it); return 1; } } @@ -115,9 +112,9 @@ void addOverlay(uint16 objIdx, uint16 type) { Common::List<overlay>::iterator it; overlay tmp; - for (it = overlayList.begin(); it != overlayList.end(); ++it) { + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { // This is done for both Future Wars and Operation Stealth - if (objectTable[it->objIdx].mask >= objectTable[objIdx].mask) { + if (g_cine->_objectTable[it->objIdx].mask >= g_cine->_objectTable[objIdx].mask) { break; } @@ -128,7 +125,7 @@ void addOverlay(uint16 objIdx, uint16 type) { } // In Operation Stealth's implementation we might bail out early - if (g_cine->getGameType() == Cine::GType_OS && it != overlayList.end() && it->objIdx == objIdx && it->type == type) { + if (g_cine->getGameType() == Cine::GType_OS && it != g_cine->_overlayList.end() && it->objIdx == objIdx && it->type == type) { return; } @@ -139,7 +136,7 @@ void addOverlay(uint16 objIdx, uint16 type) { tmp.width = 0; tmp.color = 0; - overlayList.insert(it, tmp); + g_cine->_overlayList.insert(it, tmp); } /** @@ -151,13 +148,13 @@ void addGfxElement(int16 objIdx, int16 param, int16 type) { Common::List<overlay>::iterator it; overlay tmp; - for (it = overlayList.begin(); it != overlayList.end(); ++it) { - if (objectTable[it->objIdx].mask >= objectTable[objIdx].mask || it->type == 2 || it->type == 3) { + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { + if (g_cine->_objectTable[it->objIdx].mask >= g_cine->_objectTable[objIdx].mask || it->type == 2 || it->type == 3) { break; } } - if (it != overlayList.end() && it->objIdx == objIdx && it->type == type && it->x == param) { + if (it != g_cine->_overlayList.end() && it->objIdx == objIdx && it->type == type && it->x == param) { return; } @@ -168,7 +165,7 @@ void addGfxElement(int16 objIdx, int16 param, int16 type) { tmp.width = 0; tmp.color = 0; - overlayList.insert(it, tmp); + g_cine->_overlayList.insert(it, tmp); } /** @@ -180,19 +177,19 @@ void addGfxElement(int16 objIdx, int16 param, int16 type) { void removeGfxElement(int16 objIdx, int16 param, int16 type) { Common::List<overlay>::iterator it; - for (it = overlayList.begin(); it != overlayList.end(); ++it) { + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { if (it->objIdx == objIdx && it->type == type && it->x == param) { - overlayList.erase(it); + g_cine->_overlayList.erase(it); return; } } } void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint16 param4) { - objectTable[objIdx].x = param1; - objectTable[objIdx].y = param2; - objectTable[objIdx].mask = param3; - objectTable[objIdx].frame = param4; + g_cine->_objectTable[objIdx].x = param1; + g_cine->_objectTable[objIdx].y = param2; + g_cine->_objectTable[objIdx].mask = param3; + g_cine->_objectTable[objIdx].frame = param4; if (g_cine->getGameType() == Cine::GType_OS) { resetGfxEntityEntry(objIdx); @@ -219,13 +216,13 @@ void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue) { switch (paramIdx) { case 1: - objectTable[objIdx].x = newValue; + g_cine->_objectTable[objIdx].x = newValue; break; case 2: - objectTable[objIdx].y = newValue; + g_cine->_objectTable[objIdx].y = newValue; break; case 3: - objectTable[objIdx].mask = newValue; + g_cine->_objectTable[objIdx].mask = newValue; if (g_cine->getGameType() == Cine::GType_OS) { // Operation Stealth specific resetGfxEntityEntry(objIdx); @@ -236,18 +233,18 @@ void modifyObjectParam(byte objIdx, byte paramIdx, int16 newValue) { } break; case 4: - objectTable[objIdx].frame = newValue; + g_cine->_objectTable[objIdx].frame = newValue; break; case 5: // TODO: Test if this really breaks the newspaper machine on the airport in Operation Stealth. if (g_cine->getGameType() == Cine::GType_FW && newValue == -1) { - objectTable[objIdx].costume = globalVars[0]; + g_cine->_objectTable[objIdx].costume = g_cine->_globalVars[0]; } else { - objectTable[objIdx].costume = newValue; + g_cine->_objectTable[objIdx].costume = newValue; } break; case 6: - objectTable[objIdx].part = newValue; + g_cine->_objectTable[objIdx].part = newValue; break; } } @@ -263,8 +260,8 @@ bool compareRanges(uint16 aStart, uint16 aEnd, uint16 bStart, uint16 bEnd) { uint16 compareObjectParamRanges(uint16 objIdx1, uint16 xAdd1, uint16 yAdd1, uint16 maskAdd1, uint16 objIdx2, uint16 xAdd2, uint16 yAdd2, uint16 maskAdd2) { assert(objIdx1 < NUM_MAX_OBJECT && objIdx2 < NUM_MAX_OBJECT); - const ObjectStruct &obj1 = objectTable[objIdx1]; - const ObjectStruct &obj2 = objectTable[objIdx2]; + const ObjectStruct &obj1 = g_cine->_objectTable[objIdx1]; + const ObjectStruct &obj2 = g_cine->_objectTable[objIdx2]; if (compareRanges(obj1.x, obj1.x + xAdd1, obj2.x, obj2.x + xAdd2) && compareRanges(obj1.y, obj1.y + yAdd1, obj2.y, obj2.y + yAdd2) && @@ -304,17 +301,17 @@ int16 getObjectParam(uint16 objIdx, uint16 paramIdx) { switch (paramIdx) { case 0: - return objectTable[objIdx].x; + return g_cine->_objectTable[objIdx].x; case 1: - return objectTable[objIdx].y; + return g_cine->_objectTable[objIdx].y; case 2: - return objectTable[objIdx].mask; + return g_cine->_objectTable[objIdx].mask; case 3: - return objectTable[objIdx].frame; + return g_cine->_objectTable[objIdx].frame; case 4: - return objectTable[objIdx].costume; + return g_cine->_objectTable[objIdx].costume; case 5: - return objectTable[objIdx].part; + return g_cine->_objectTable[objIdx].part; } return 0; diff --git a/engines/cine/object.h b/engines/cine/object.h index daf515bf0f..5a5ea91286 100644 --- a/engines/cine/object.h +++ b/engines/cine/object.h @@ -63,9 +63,6 @@ struct overlay { #define NUM_MAX_OBJECT 255 #define NUM_MAX_VAR 255 -extern Common::Array<ObjectStruct> objectTable; -extern Common::List<overlay> overlayList; - void resetObjectTable(); void loadObject(char *pObjectName); void setupObject(byte objIdx, uint16 param1, uint16 param2, uint16 param3, uint16 param4); diff --git a/engines/cine/pal.cpp b/engines/cine/pal.cpp index 6e730aedd9..27d0e593da 100644 --- a/engines/cine/pal.cpp +++ b/engines/cine/pal.cpp @@ -30,7 +30,6 @@ namespace Cine { -Common::Array<PalEntry> palArray; static byte paletteBuffer1[16]; static byte paletteBuffer2[16]; @@ -40,7 +39,7 @@ void loadPal(const char *fileName) { removeExtention(buffer, fileName); strcat(buffer, ".PAL"); - palArray.clear(); + g_cine->_palArray.clear(); Common::File palFileHandle; if (!palFileHandle.open(buffer)) @@ -49,11 +48,11 @@ void loadPal(const char *fileName) { uint16 palEntriesCount = palFileHandle.readUint16LE(); palFileHandle.readUint16LE(); // entry size - palArray.resize(palEntriesCount); - for (uint i = 0; i < palArray.size(); ++i) { - palFileHandle.read(palArray[i].name, 10); - palFileHandle.read(palArray[i].pal1, 16); - palFileHandle.read(palArray[i].pal2, 16); + g_cine->_palArray.resize(palEntriesCount); + for (uint i = 0; i < g_cine->_palArray.size(); ++i) { + palFileHandle.read(g_cine->_palArray[i].name, 10); + palFileHandle.read(g_cine->_palArray[i].pal1, 16); + palFileHandle.read(g_cine->_palArray[i].pal2, 16); } palFileHandle.close(); } @@ -73,8 +72,8 @@ int16 findPaletteFromName(const char *fileName) { position++; } - for (i = 0; i < palArray.size(); i++) { - if (!strcmp(buffer, palArray[i].name)) { + for (i = 0; i < g_cine->_palArray.size(); i++) { + if (!strcmp(buffer, g_cine->_palArray[i].name)) { return i; } } @@ -97,9 +96,9 @@ void loadRelatedPalette(const char *fileName) { paletteBuffer1[i] = paletteBuffer2[i] = (i << 4) + i; } } else { - assert(paletteIndex < (int32)palArray.size()); - memcpy(paletteBuffer1, palArray[paletteIndex].pal1, 16); - memcpy(paletteBuffer2, palArray[paletteIndex].pal2, 16); + assert(paletteIndex < (int32)g_cine->_palArray.size()); + memcpy(paletteBuffer1, g_cine->_palArray[paletteIndex].pal1, 16); + memcpy(paletteBuffer2, g_cine->_palArray[paletteIndex].pal2, 16); } } diff --git a/engines/cine/pal.h b/engines/cine/pal.h index 0086711636..e5b318b24d 100644 --- a/engines/cine/pal.h +++ b/engines/cine/pal.h @@ -49,8 +49,6 @@ struct PalEntry { byte pal2[16]; }; -extern Common::Array<PalEntry> palArray; - void loadPal(const char *fileName); void loadRelatedPalette(const char *fileName); diff --git a/engines/cine/part.cpp b/engines/cine/part.cpp index ad5aaf54b0..95f3789abd 100644 --- a/engines/cine/part.cpp +++ b/engines/cine/part.cpp @@ -32,10 +32,8 @@ namespace Cine { -Common::Array<PartBuffer> partBuffer; - void loadPart(const char *partName) { - partBuffer.clear(); + g_cine->_partBuffer.clear(); g_cine->_partFileHandle.close(); @@ -47,17 +45,17 @@ void loadPart(const char *partName) { setMouseCursor(MOUSE_CURSOR_DISK); uint16 numElementInPart = g_cine->_partFileHandle.readUint16BE(); - partBuffer.resize(numElementInPart); + g_cine->_partBuffer.resize(numElementInPart); g_cine->_partFileHandle.readUint16BE(); // entry size if (currentPartName != partName) strcpy(currentPartName, partName); - for (uint16 i = 0; i < partBuffer.size(); i++) { - g_cine->_partFileHandle.read(partBuffer[i].partName, 14); - partBuffer[i].offset = g_cine->_partFileHandle.readUint32BE(); - partBuffer[i].packedSize = g_cine->_partFileHandle.readUint32BE(); - partBuffer[i].unpackedSize = g_cine->_partFileHandle.readUint32BE(); + for (uint16 i = 0; i < g_cine->_partBuffer.size(); i++) { + g_cine->_partFileHandle.read(g_cine->_partBuffer[i].partName, 14); + g_cine->_partBuffer[i].offset = g_cine->_partFileHandle.readUint32BE(); + g_cine->_partBuffer[i].packedSize = g_cine->_partFileHandle.readUint32BE(); + g_cine->_partBuffer[i].unpackedSize = g_cine->_partFileHandle.readUint32BE(); g_cine->_partFileHandle.readUint32BE(); // unused } @@ -189,8 +187,8 @@ void CineEngine::readVolCnf() { int16 findFileInBundle(const char *fileName) { if (g_cine->getGameType() == Cine::GType_OS) { // look first in currently loaded resource file - for (uint i = 0; i < partBuffer.size(); i++) { - if (!scumm_stricmp(fileName, partBuffer[i].partName)) { + for (uint i = 0; i < g_cine->_partBuffer.size(); i++) { + if (!scumm_stricmp(fileName, g_cine->_partBuffer[i].partName)) { return i; } } @@ -203,8 +201,8 @@ int16 findFileInBundle(const char *fileName) { const char *part = (*it)._value; loadPart(part); } - for (uint i = 0; i < partBuffer.size(); i++) { - if (!scumm_stricmp(fileName, partBuffer[i].partName)) { + for (uint i = 0; i < g_cine->_partBuffer.size(); i++) { + if (!scumm_stricmp(fileName, g_cine->_partBuffer[i].partName)) { return i; } } @@ -212,31 +210,31 @@ int16 findFileInBundle(const char *fileName) { } void readFromPart(int16 idx, byte *dataPtr, uint32 maxSize) { - assert(maxSize >= partBuffer[idx].packedSize); + assert(maxSize >= g_cine->_partBuffer[idx].packedSize); setMouseCursor(MOUSE_CURSOR_DISK); - g_cine->_partFileHandle.seek(partBuffer[idx].offset, SEEK_SET); - g_cine->_partFileHandle.read(dataPtr, partBuffer[idx].packedSize); + g_cine->_partFileHandle.seek(g_cine->_partBuffer[idx].offset, SEEK_SET); + g_cine->_partFileHandle.read(dataPtr, g_cine->_partBuffer[idx].packedSize); } byte *readBundleFile(int16 foundFileIdx, uint32 *size) { - assert(foundFileIdx >= 0 && foundFileIdx < (int32)partBuffer.size()); + assert(foundFileIdx >= 0 && foundFileIdx < (int32)g_cine->_partBuffer.size()); bool error = false; - byte *dataPtr = (byte *)calloc(partBuffer[foundFileIdx].unpackedSize, 1); - byte *packedData = (byte *)calloc(partBuffer[foundFileIdx].packedSize, 1); + byte *dataPtr = (byte *)calloc(g_cine->_partBuffer[foundFileIdx].unpackedSize, 1); + byte *packedData = (byte *)calloc(g_cine->_partBuffer[foundFileIdx].packedSize, 1); assert(dataPtr && packedData); - readFromPart(foundFileIdx, packedData, partBuffer[foundFileIdx].packedSize); + readFromPart(foundFileIdx, packedData, g_cine->_partBuffer[foundFileIdx].packedSize); CineUnpacker cineUnpacker; - error = !cineUnpacker.unpack(packedData, partBuffer[foundFileIdx].packedSize, dataPtr, partBuffer[foundFileIdx].unpackedSize); + error = !cineUnpacker.unpack(packedData, g_cine->_partBuffer[foundFileIdx].packedSize, dataPtr, g_cine->_partBuffer[foundFileIdx].unpackedSize); free(packedData); if (error) { - warning("Error unpacking '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName); + warning("Error unpacking '%s' from bundle file '%s'", g_cine->_partBuffer[foundFileIdx].partName, currentPartName); } // Set the size variable if a pointer to it has been given if (size != NULL) { - *size = partBuffer[foundFileIdx].unpackedSize; + *size = g_cine->_partBuffer[foundFileIdx].unpackedSize; } return dataPtr; @@ -255,7 +253,7 @@ byte *readBundleSoundFile(const char *entryName, uint32 *size) { if (index != -1) { data = readBundleFile(index); if (size) { - *size = partBuffer[index].unpackedSize; + *size = g_cine->_partBuffer[index].unpackedSize; } } if (g_cine->getGameType() == Cine::GType_FW) { @@ -305,14 +303,14 @@ void dumpBundle(const char *fileName) { strcpy(tmpPart, currentPartName); loadPart(fileName); - for (uint i = 0; i < partBuffer.size(); i++) { + for (uint i = 0; i < g_cine->_partBuffer.size(); i++) { byte *data = readBundleFile(i); - debug(0, "%s", partBuffer[i].partName); + debug(0, "%s", g_cine->_partBuffer[i].partName); Common::DumpFile out; - if (out.open(Common::String("dumps/") + partBuffer[i].partName)) { - out.write(data, partBuffer[i].unpackedSize); + if (out.open(Common::String("dumps/") + g_cine->_partBuffer[i].partName)) { + out.write(data, g_cine->_partBuffer[i].unpackedSize); out.close(); } diff --git a/engines/cine/part.h b/engines/cine/part.h index 2f1af7141f..53ebafaa37 100644 --- a/engines/cine/part.h +++ b/engines/cine/part.h @@ -37,8 +37,6 @@ struct PartBuffer { #define NUM_MAX_PARTDATA 255 -extern Common::Array<PartBuffer> partBuffer; - void loadPart(const char *partName); void closePart(); diff --git a/engines/cine/prc.cpp b/engines/cine/prc.cpp index e1ef14bbbf..183a537416 100644 --- a/engines/cine/prc.cpp +++ b/engines/cine/prc.cpp @@ -35,9 +35,6 @@ namespace Cine { -ScriptList globalScripts; -ScriptList objectScripts; - //char currentPrcName[20]; /** @@ -52,8 +49,8 @@ bool loadPrc(const char *pPrcName) { assert(pPrcName); - globalScripts.clear(); - scriptTable.clear(); + g_cine->_globalScripts.clear(); + g_cine->_scriptTable.clear(); // This is copy protection. Used to hang the machine if (!scumm_stricmp(pPrcName, COPY_PROT_FAIL_PRC_NAME)) { @@ -83,14 +80,14 @@ bool loadPrc(const char *pPrcName) { RawScriptPtr tmp(new RawScript(READ_BE_UINT16(scriptPtr))); scriptPtr += 2; assert(tmp); - scriptTable.push_back(tmp); + g_cine->_scriptTable.push_back(tmp); } for (i = 0; i < numScripts; i++) { - uint16 size = scriptTable[i]->_size; + uint16 size = g_cine->_scriptTable[i]->_size; // TODO: delete the test? if (size) { - scriptTable[i]->setData(*scriptInfo, scriptPtr); + g_cine->_scriptTable[i]->setData(*scriptInfo, scriptPtr); scriptPtr += size; } } diff --git a/engines/cine/prc.h b/engines/cine/prc.h index 05bb240372..84058426fa 100644 --- a/engines/cine/prc.h +++ b/engines/cine/prc.h @@ -28,9 +28,6 @@ namespace Cine { -extern ScriptList globalScripts; -extern ScriptList objectScripts; - bool loadPrc(const char *pPrcName); } // End of namespace Cine diff --git a/engines/cine/rel.cpp b/engines/cine/rel.cpp index 17ab14bfe5..4a11995ee1 100644 --- a/engines/cine/rel.cpp +++ b/engines/cine/rel.cpp @@ -31,8 +31,6 @@ namespace Cine { -RawObjectScriptArray relTable; ///< Object script bytecode table - /** * @todo Is script size of 0 valid? * @todo Fix script dump code @@ -45,8 +43,8 @@ void loadRel(char *pRelName) { checkDataDisk(-1); - objectScripts.clear(); - relTable.clear(); + g_cine->_objectScripts.clear(); + g_cine->_relTable.clear(); ptr = dataPtr = readBundleFile(findFileInBundle(pRelName)); @@ -61,14 +59,14 @@ void loadRel(char *pRelName) { p3 = READ_BE_UINT16(ptr); ptr += 2; RawObjectScriptPtr tmp(new RawObjectScript(size, p1, p2, p3)); assert(tmp); - relTable.push_back(tmp); + g_cine->_relTable.push_back(tmp); } for (i = 0; i < numEntry; i++) { - size = relTable[i]->_size; + size = g_cine->_relTable[i]->_size; // TODO: delete the test? if (size) { - relTable[i]->setData(*scriptInfo, ptr); + g_cine->_relTable[i]->setData(*scriptInfo, ptr); ptr += size; } } @@ -82,10 +80,10 @@ void loadRel(char *pRelName) { char buffer[256]; for (s = 0; s < numEntry; s++) { - if (relTable[s]->_size) { + if (g_cine->_relTable[s]->_size) { sprintf(buffer, "%s_%03d.txt", pRelName, s); - decompileScript((const byte *)relTable[s]->getString(0), relTable[s]->_size, s); + decompileScript((const byte *)g_cine->_relTable[s]->getString(0), g_cine->_relTable[s]->_size, s); dumpScript(buffer); } } diff --git a/engines/cine/rel.h b/engines/cine/rel.h index 84926f76c4..8d712dc416 100644 --- a/engines/cine/rel.h +++ b/engines/cine/rel.h @@ -29,8 +29,6 @@ #include "cine/script.h" namespace Cine { -extern RawObjectScriptArray relTable; - void loadRel(char *pRelName); } // End of namespace Cine diff --git a/engines/cine/saveload.cpp b/engines/cine/saveload.cpp index f9dfcc7737..0f7c50b7e5 100644 --- a/engines/cine/saveload.cpp +++ b/engines/cine/saveload.cpp @@ -200,13 +200,13 @@ void loadScriptFromSave(Common::SeekableReadStream &fHandle, bool isGlobal) { // original code loaded everything into globalScripts, this should be // the correct behavior if (isGlobal) { - ScriptPtr tmp(scriptInfo->create(*scriptTable[idx], idx, labels, localVars, compare, pos)); + ScriptPtr tmp(scriptInfo->create(*g_cine->_scriptTable[idx], idx, labels, localVars, compare, pos)); assert(tmp); - globalScripts.push_back(tmp); + g_cine->_globalScripts.push_back(tmp); } else { - ScriptPtr tmp(scriptInfo->create(*relTable[idx], idx, labels, localVars, compare, pos)); + ScriptPtr tmp(scriptInfo->create(*g_cine->_relTable[idx], idx, labels, localVars, compare, pos)); assert(tmp); - objectScripts.push_back(tmp); + g_cine->_objectScripts.push_back(tmp); } } @@ -227,7 +227,7 @@ void loadOverlayFromSave(Common::SeekableReadStream &fHandle) { tmp.width = fHandle.readSint16BE(); tmp.color = fHandle.readSint16BE(); - overlayList.push_back(tmp); + g_cine->_overlayList.push_back(tmp); } bool loadObjectTable(Common::SeekableReadStream &in) { @@ -235,20 +235,20 @@ bool loadObjectTable(Common::SeekableReadStream &in) { in.readUint16BE(); // Entry size for (int i = 0; i < NUM_MAX_OBJECT; i++) { - objectTable[i].x = in.readSint16BE(); - objectTable[i].y = in.readSint16BE(); - objectTable[i].mask = in.readUint16BE(); - objectTable[i].frame = in.readSint16BE(); - objectTable[i].costume = in.readSint16BE(); - in.read(objectTable[i].name, 20); - objectTable[i].part = in.readUint16BE(); + g_cine->_objectTable[i].x = in.readSint16BE(); + g_cine->_objectTable[i].y = in.readSint16BE(); + g_cine->_objectTable[i].mask = in.readUint16BE(); + g_cine->_objectTable[i].frame = in.readSint16BE(); + g_cine->_objectTable[i].costume = in.readSint16BE(); + in.read(g_cine->_objectTable[i].name, 20); + g_cine->_objectTable[i].part = in.readUint16BE(); } return !(in.eos() || in.err()); } bool loadZoneData(Common::SeekableReadStream &in) { for (int i = 0; i < 16; i++) { - zoneData[i] = in.readUint16BE(); + g_cine->_zoneData[i] = in.readUint16BE(); } return !(in.eos() || in.err()); } @@ -313,14 +313,14 @@ bool loadSeqList(Common::SeekableReadStream &in) { tmp.var1A = in.readSint16BE(); tmp.var1C = in.readSint16BE(); tmp.var1E = in.readSint16BE(); - seqList.push_back(tmp); + g_cine->_seqList.push_back(tmp); } return !(in.eos() || in.err()); } bool loadZoneQuery(Common::SeekableReadStream &in) { for (int i = 0; i < 16; i++) { - zoneQuery[i] = in.readUint16BE(); + g_cine->_zoneQuery[i] = in.readUint16BE(); } return !(in.eos() || in.err()); } @@ -330,19 +330,19 @@ void saveObjectTable(Common::OutSaveFile &out) { out.writeUint16BE(0x20); // Entry size for (int i = 0; i < NUM_MAX_OBJECT; i++) { - out.writeUint16BE(objectTable[i].x); - out.writeUint16BE(objectTable[i].y); - out.writeUint16BE(objectTable[i].mask); - out.writeUint16BE(objectTable[i].frame); - out.writeUint16BE(objectTable[i].costume); - out.write(objectTable[i].name, 20); - out.writeUint16BE(objectTable[i].part); + out.writeUint16BE(g_cine->_objectTable[i].x); + out.writeUint16BE(g_cine->_objectTable[i].y); + out.writeUint16BE(g_cine->_objectTable[i].mask); + out.writeUint16BE(g_cine->_objectTable[i].frame); + out.writeUint16BE(g_cine->_objectTable[i].costume); + out.write(g_cine->_objectTable[i].name, 20); + out.writeUint16BE(g_cine->_objectTable[i].part); } } void saveZoneData(Common::OutSaveFile &out) { for (int i = 0; i < 16; i++) { - out.writeUint16BE(zoneData[i]); + out.writeUint16BE(g_cine->_zoneData[i]); } } @@ -356,8 +356,8 @@ void saveCommandVariables(Common::OutSaveFile &out) { void saveCommandBuffer(Common::OutSaveFile &out) { // Let's make sure there's space for the trailing zero // (That's why we subtract one from the maximum command buffer size here). - uint32 size = MIN<uint32>(commandBuffer.size(), kMaxCommandBufferSize - 1); - out.write(commandBuffer.c_str(), size); + uint32 size = MIN<uint32>(g_cine->_commandBuffer.size(), kMaxCommandBufferSize - 1); + out.write(g_cine->_commandBuffer.c_str(), size); // Write the rest as zeroes (Here we also write the string's trailing zero) for (uint i = 0; i < kMaxCommandBufferSize - size; i++) { out.writeByte(0); @@ -369,7 +369,7 @@ void saveAnimDataTable(Common::OutSaveFile &out) { out.writeUint16BE(0x1E); // Entry size for (int i = 0; i < NUM_MAX_ANIMDATA; i++) { - animDataTable[i].save(out); + g_cine->_animDataTable[i].save(out); } } @@ -385,16 +385,16 @@ void saveScreenParams(Common::OutSaveFile &out) { void saveGlobalScripts(Common::OutSaveFile &out) { ScriptList::const_iterator it; - out.writeUint16BE(globalScripts.size()); - for (it = globalScripts.begin(); it != globalScripts.end(); ++it) { + out.writeUint16BE(g_cine->_globalScripts.size()); + for (it = g_cine->_globalScripts.begin(); it != g_cine->_globalScripts.end(); ++it) { (*it)->save(out); } } void saveObjectScripts(Common::OutSaveFile &out) { ScriptList::const_iterator it; - out.writeUint16BE(objectScripts.size()); - for (it = objectScripts.begin(); it != objectScripts.end(); ++it) { + out.writeUint16BE(g_cine->_objectScripts.size()); + for (it = g_cine->_objectScripts.begin(); it != g_cine->_objectScripts.end(); ++it) { (*it)->save(out); } } @@ -402,9 +402,9 @@ void saveObjectScripts(Common::OutSaveFile &out) { void saveOverlayList(Common::OutSaveFile &out) { Common::List<overlay>::const_iterator it; - out.writeUint16BE(overlayList.size()); + out.writeUint16BE(g_cine->_overlayList.size()); - for (it = overlayList.begin(); it != overlayList.end(); ++it) { + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { out.writeUint32BE(0); // next out.writeUint32BE(0); // previous? out.writeUint16BE(it->objIdx); @@ -418,9 +418,9 @@ void saveOverlayList(Common::OutSaveFile &out) { void saveBgIncrustList(Common::OutSaveFile &out) { Common::List<BGIncrust>::const_iterator it; - out.writeUint16BE(bgIncrustList.size()); + out.writeUint16BE(g_cine->_bgIncrustList.size()); - for (it = bgIncrustList.begin(); it != bgIncrustList.end(); ++it) { + for (it = g_cine->_bgIncrustList.begin(); it != g_cine->_bgIncrustList.end(); ++it) { out.writeUint32BE(0); // next out.writeUint32BE(0); // previous? out.writeUint16BE(it->objIdx); @@ -434,15 +434,15 @@ void saveBgIncrustList(Common::OutSaveFile &out) { void saveZoneQuery(Common::OutSaveFile &out) { for (int i = 0; i < 16; i++) { - out.writeUint16BE(zoneQuery[i]); + out.writeUint16BE(g_cine->_zoneQuery[i]); } } void saveSeqList(Common::OutSaveFile &out) { Common::List<SeqListElement>::const_iterator it; - out.writeUint16BE(seqList.size()); + out.writeUint16BE(g_cine->_seqList.size()); - for (it = seqList.begin(); it != seqList.end(); ++it) { + for (it = g_cine->_seqList.begin(); it != g_cine->_seqList.end(); ++it) { out.writeSint16BE(it->var4); out.writeUint16BE(it->objIdx); out.writeSint16BE(it->var8); @@ -567,13 +567,13 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { loadObjectTable(in); renderer->restorePalette(in, hdr.version); - globalVars.load(in, NUM_MAX_VAR); + g_cine->_globalVars.load(in, NUM_MAX_VAR); loadZoneData(in); loadCommandVariables(in); char tempCommandBuffer[kMaxCommandBufferSize]; in.read(tempCommandBuffer, kMaxCommandBufferSize); - commandBuffer = tempCommandBuffer; - renderer->setCommand(commandBuffer); + g_cine->_commandBuffer = tempCommandBuffer; + renderer->setCommand(g_cine->_commandBuffer); loadZoneQuery(in); // TODO: Use the loaded string (Current music name (String, 13 bytes)). @@ -701,7 +701,7 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor renderer->restorePalette(in, 0); // At 0x2083 (i.e. 0x2043 + 16 * 2 * 2): - globalVars.load(in, NUM_MAX_VAR); + g_cine->_globalVars.load(in, NUM_MAX_VAR); // At 0x2281 (i.e. 0x2083 + 255 * 2): loadZoneData(in); @@ -712,8 +712,8 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor // At 0x22A9 (i.e. 0x22A1 + 4 * 2): char tempCommandBuffer[kMaxCommandBufferSize]; in.read(tempCommandBuffer, kMaxCommandBufferSize); - commandBuffer = tempCommandBuffer; - renderer->setCommand(commandBuffer); + g_cine->_commandBuffer = tempCommandBuffer; + renderer->setCommand(g_cine->_commandBuffer); // At 0x22F9 (i.e. 0x22A9 + 0x50): renderer->_cmdY = in.readUint16BE(); @@ -855,7 +855,7 @@ void CineEngine::makeSaveFW(Common::OutSaveFile &out) { saveObjectTable(out); renderer->savePalette(out); - globalVars.save(out, NUM_MAX_VAR); + g_cine->_globalVars.save(out, NUM_MAX_VAR); saveZoneData(out); saveCommandVariables(out); saveCommandBuffer(out); @@ -912,7 +912,7 @@ void CineEngine::makeSaveOS(Common::OutSaveFile &out) { saveObjectTable(out); renderer->savePalette(out); - globalVars.save(out, NUM_MAX_VAR); + g_cine->_globalVars.save(out, NUM_MAX_VAR); saveZoneData(out); saveCommandVariables(out); saveCommandBuffer(out); @@ -1045,7 +1045,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam loadPart(name); } - animName = partBuffer[foundFileIdx].partName; + animName = g_cine->_partBuffer[foundFileIdx].partName; loadRelatedPalette(animName); // Is this for Future Wars only? const int16 prevAnim = currentAnim; currentAnim = loadResource(animName, currentAnim); diff --git a/engines/cine/script.h b/engines/cine/script.h index 1c3b496375..756bc930e8 100644 --- a/engines/cine/script.h +++ b/engines/cine/script.h @@ -67,6 +67,7 @@ public: ScriptVars(const ScriptVars &src); ~ScriptVars(); + void reinit(unsigned int len); ScriptVars &operator=(const ScriptVars &src); int16 &operator[](unsigned int idx); int16 operator[](unsigned int idx) const; @@ -368,9 +369,7 @@ typedef Common::Array<RawObjectScriptPtr> RawObjectScriptArray; #define NUM_MAX_SCRIPT 50 -extern RawScriptArray scriptTable; extern FWScriptInfo *scriptInfo; -extern ScriptVars globalVars; void setupOpcodes(); diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index e71fec8898..430a32ac69 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -38,14 +38,6 @@ namespace Cine { -/** - * Global variables. - * 255 of these are saved, but there's one more that's used for bypassing the copy protection. - * In CineEngine::mainLoop(int bootScriptIdx) there's this code: globalVars[VAR_BYPASS_PROTECTION] = 0; - * And as VAR_BYPASS_PROTECTION is 255 that's why we're allocating one more than we otherwise would. - */ -ScriptVars globalVars(NUM_MAX_VAR + 1); - uint16 compareVars(int16 a, int16 b); @@ -216,7 +208,6 @@ void FWScript::setupTable() { } FWScriptInfo *scriptInfo; ///< Script factory -RawScriptArray scriptTable; ///< Table of script bytecode /** * @todo replace with script subsystem @@ -257,6 +248,14 @@ ScriptVars::ScriptVars(Common::SeekableReadStream &fHandle, unsigned int len) load(fHandle); } +void ScriptVars::reinit(unsigned int len) { + delete _vars; + + _size = len; + _vars = new int16[len]; + reset(); +} + /** * Copy constructor */ @@ -606,7 +605,7 @@ RawObjectScript::RawObjectScript(const FWScriptInfo &info, const byte *data, FWScript::FWScript(const RawScript &script, int16 idx) : _script(script), _pos(0), _line(0), _compare(0), _index(idx), _labels(script.labels()), _localVars(LOCAL_VARS_SIZE), - _globalVars(globalVars), _info(new FWScriptInfo) { } + _globalVars(g_cine->_globalVars), _info(new FWScriptInfo) { } /** * Copy constructor @@ -624,7 +623,7 @@ FWScript::FWScript(const FWScript &src) : _script(src._script), _pos(src._pos), FWScript::FWScript(const RawScript &script, int16 idx, FWScriptInfo *info) : _script(script), _pos(0), _line(0), _compare(0), _index(idx), _labels(script.labels()), _localVars(LOCAL_VARS_SIZE), - _globalVars(globalVars), _info(info) { } + _globalVars(g_cine->_globalVars), _info(info) { } /** * Constructor for object scripts in derived classes @@ -634,7 +633,7 @@ FWScript::FWScript(const RawScript &script, int16 idx, FWScriptInfo *info) : FWScript::FWScript(RawObjectScript &script, int16 idx, FWScriptInfo *info) : _script(script), _pos(0), _line(0), _compare(0), _index(idx), _labels(script.labels()), _localVars(LOCAL_VARS_SIZE), - _globalVars(globalVars), _info(info) { + _globalVars(g_cine->_globalVars), _info(info) { _localVars[0] = script.run(); } @@ -964,11 +963,11 @@ int FWScript::o1_loadVar() { break; case 8: debugC(5, kCineDebugScript, "Line: %d: var[%d] = file[%d].packedSize", _line, varIdx, dataIdx); - _localVars[varIdx] = partBuffer[dataIdx].packedSize; + _localVars[varIdx] = g_cine->_partBuffer[dataIdx].packedSize; break; case 9: debugC(5, kCineDebugScript, "Line: %d: var[%d] = file[%d].unpackedSize", _line, varIdx, dataIdx); - _localVars[varIdx] = partBuffer[dataIdx].unpackedSize; + _localVars[varIdx] = g_cine->_partBuffer[dataIdx].unpackedSize; break; default: error("executeScript: o1_loadVar: Unknown variable type %d", varType); @@ -1196,7 +1195,7 @@ int FWScript::o1_addSpriteFilledToBgList() { int FWScript::o1_op1B() { debugC(5, kCineDebugScript, "Line: %d: freeBgIncrustList", _line); - bgIncrustList.clear(); + g_cine->_bgIncrustList.clear(); return 0; } @@ -1343,9 +1342,9 @@ int FWScript::o1_endGlobalScript() { debugC(5, kCineDebugScript, "Line: %d: stopGlobalScript(%d)", _line, scriptIdx); - ScriptList::iterator it = globalScripts.begin(); + ScriptList::iterator it = g_cine->_globalScripts.begin(); - for (; it != globalScripts.end(); ++it) { + for (; it != g_cine->_globalScripts.end(); ++it) { if ((*it)->_index == scriptIdx) { (*it)->_index = -1; } @@ -1369,7 +1368,7 @@ int FWScript::o1_loadBg() { debugC(5, kCineDebugScript, "Line: %d: loadBg(\"%s\")", _line, param); loadBg(param); - bgIncrustList.clear(); + g_cine->_bgIncrustList.clear(); bgVar0 = 0; return 0; } @@ -1627,7 +1626,7 @@ int FWScript::o1_freePartRange() { int FWScript::o1_unloadAllMasks() { debugC(5, kCineDebugScript, "Line: %d: unloadAllMasks()", _line); - overlayList.clear(); + g_cine->_overlayList.clear(); return 0; } @@ -1656,7 +1655,7 @@ int FWScript::o1_initializeZoneData() { debugC(5, kCineDebugScript, "Line: %d: initializeZoneData()", _line); for (int i = 0; i < NUM_MAX_ZONE; i++) { - zoneData[i] = i; + g_cine->_zoneData[i] = i; } return 0; } @@ -1666,7 +1665,7 @@ int FWScript::o1_setZoneDataEntry() { uint16 var = getNextWord(); debugC(5, kCineDebugScript, "Line: %d: setZone[%d] = %d", _line, zoneIdx, var); - zoneData[zoneIdx] = var; + g_cine->_zoneData[zoneIdx] = var; return 0; } @@ -1674,7 +1673,7 @@ int FWScript::o1_getZoneDataEntry() { byte zoneIdx = getNextByte(); byte var = getNextByte(); - _localVars[var] = zoneData[zoneIdx]; + _localVars[var] = g_cine->_zoneData[zoneIdx]; return 0; } @@ -1796,7 +1795,7 @@ int FWScript::o1_playSample() { int16 volume = getNextWord(); uint16 size = getNextWord(); - const byte *data = animDataTable[anim].data(); + const byte *data = g_cine->_animDataTable[anim].data(); if (!data) { return 0; @@ -1804,7 +1803,7 @@ int FWScript::o1_playSample() { if (g_cine->getPlatform() == Common::kPlatformAmiga || g_cine->getPlatform() == Common::kPlatformAtariST) { if (size == 0xFFFF) { - size = animDataTable[anim]._width * animDataTable[anim]._height; + size = g_cine->_animDataTable[anim]._width * g_cine->_animDataTable[anim]._height; } if (channel < 10) { // || _currentOpcode == 0x78 int channel1, channel2; @@ -1874,9 +1873,9 @@ int FWScript::o1_unloadMask5() { //----------------------------------------------------------------------- void addScriptToGlobalScripts(uint16 idx) { - ScriptPtr tmp(scriptInfo->create(*scriptTable[idx], idx)); + ScriptPtr tmp(scriptInfo->create(*g_cine->_scriptTable[idx], idx)); assert(tmp); - globalScripts.push_back(tmp); + g_cine->_globalScripts.push_back(tmp); } int16 getZoneFromPosition(byte *page, int16 x, int16 y, int16 width) { @@ -1916,8 +1915,8 @@ int16 getZoneFromPositionRaw(byte *page, int16 x, int16 y, int16 width) { } int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneIdx) { - int16 lx = objectTable[objIdx].x + x; - int16 ly = objectTable[objIdx].y + y; + int16 lx = g_cine->_objectTable[objIdx].x + x; + int16 ly = g_cine->_objectTable[objIdx].y + y; int16 idx; int16 result = 0; @@ -1935,12 +1934,12 @@ int16 checkCollision(int16 objIdx, int16 x, int16 y, int16 numZones, int16 zoneI // The zoneQuery table is updated here only in Operation Stealth if (g_cine->getGameType() == Cine::GType_OS) { - if (zoneData[idx] < NUM_MAX_ZONE) { - zoneQuery[zoneData[idx]]++; + if (g_cine->_zoneData[idx] < NUM_MAX_ZONE) { + g_cine->_zoneQuery[g_cine->_zoneData[idx]]++; } } - if (zoneData[idx] == zoneIdx) { + if (g_cine->_zoneData[idx] == zoneIdx) { result = 1; // Future Wars breaks out early on the first match, but // Operation Stealth doesn't because it needs to update @@ -1969,10 +1968,10 @@ uint16 compareVars(int16 a, int16 b) { } void executeObjectScripts() { - ScriptList::iterator it = objectScripts.begin(); - for (; it != objectScripts.end();) { + ScriptList::iterator it = g_cine->_objectScripts.begin(); + for (; it != g_cine->_objectScripts.end();) { if ((*it)->_index < 0 || (*it)->execute() < 0) { - it = objectScripts.erase(it); + it = g_cine->_objectScripts.erase(it); } else { ++it; } @@ -1980,10 +1979,10 @@ void executeObjectScripts() { } void executeGlobalScripts() { - ScriptList::iterator it = globalScripts.begin(); - for (; it != globalScripts.end();) { + ScriptList::iterator it = g_cine->_globalScripts.begin(); + for (; it != g_cine->_globalScripts.end();) { if ((*it)->_index < 0 || (*it)->execute() < 0) { - it = globalScripts.erase(it); + it = g_cine->_globalScripts.erase(it); } else { ++it; } diff --git a/engines/cine/script_os.cpp b/engines/cine/script_os.cpp index d03b118443..ab1ad7ff9c 100644 --- a/engines/cine/script_os.cpp +++ b/engines/cine/script_os.cpp @@ -420,16 +420,16 @@ int FWScript::o2_playSampleAlt() { uint16 size = getNextWord(); if (size == 0xFFFF) { - size = animDataTable[num]._width * animDataTable[num]._height; + size = g_cine->_animDataTable[num]._width * g_cine->_animDataTable[num]._height; } - if (animDataTable[num].data()) { + if (g_cine->_animDataTable[num].data()) { if (g_cine->getPlatform() == Common::kPlatformPC) { // if speaker output is available, play sound on it // if it's another device, don't play anything // TODO: implement this, it's used in the introduction for example // on each letter displayed } else { - g_sound->playSound(channel, frequency, animDataTable[num].data(), size, 0, 0, 63, 0); + g_sound->playSound(channel, frequency, g_cine->_animDataTable[num].data(), size, 0, 0, 63, 0); } } return 0; @@ -611,9 +611,9 @@ int FWScript::o2_stopObjectScript() { byte param = getNextByte(); debugC(5, kCineDebugScript, "Line: %d: stopObjectScript(%d)", _line, param); - ScriptList::iterator it = objectScripts.begin(); + ScriptList::iterator it = g_cine->_objectScripts.begin(); - for (; it != objectScripts.end(); ++it) { + for (; it != g_cine->_objectScripts.end(); ++it) { if ((*it)->_index == param) { (*it)->_index = -1; } @@ -699,7 +699,7 @@ int FWScript::o2_loadBg() { int FWScript::o2_wasZoneChecked() { byte param = getNextByte(); - _compare = (param < NUM_MAX_ZONE && zoneQuery[param]) ? 1 : 0; + _compare = (param < NUM_MAX_ZONE && g_cine->_zoneQuery[param]) ? 1 : 0; debugC(5, kCineDebugScript, "Line: %d: o2_wasZoneChecked(%d)", _line, param); return 0; } diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 82c40a2f50..cf7135a6b5 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -81,7 +81,6 @@ uint16 _messageLen; int16 playerCommand; -Common::String commandBuffer; char currentPrcName[20]; char currentRelName[20]; char currentObjectName[20]; @@ -137,9 +136,6 @@ static const int16 canUseOnItemTable[] = { 1, 0, 0, 1, 1, 0, 0 }; CommandeType objectListCommand[20]; int16 objListTab[20]; -Common::Array<uint16> zoneData; -Common::Array<uint16> zoneQuery; ///< Only exists in Operation Stealth - /** * Move the player character using the keyboard * @param x Negative values move left, positive right, zero not at all @@ -174,9 +170,9 @@ void stopMusicAfterFadeOut() { } void runObjectScript(int16 entryIdx) { - ScriptPtr tmp(scriptInfo->create(*relTable[entryIdx], entryIdx)); + ScriptPtr tmp(scriptInfo->create(*g_cine->_relTable[entryIdx], entryIdx)); assert(tmp); - objectScripts.push_back(tmp); + g_cine->_objectScripts.push_back(tmp); } /** @@ -190,19 +186,19 @@ void addPlayerCommandMessage(int16 cmd) { tmp.objIdx = cmd; tmp.type = 3; - overlayList.push_back(tmp); + g_cine->_overlayList.push_back(tmp); } int16 getRelEntryForObject(uint16 param1, uint16 param2, SelectedObjStruct *pSelectedObject) { int16 i; int16 found = -1; - for (i = 0; i < (int16)relTable.size(); i++) { - if (relTable[i]->_param1 == param1 && relTable[i]->_param2 == pSelectedObject->idx) { + for (i = 0; i < (int16)g_cine->_relTable.size(); i++) { + if (g_cine->_relTable[i]->_param1 == param1 && g_cine->_relTable[i]->_param2 == pSelectedObject->idx) { if (param2 == 1) { found = i; } else if (param2 == 2) { - if (relTable[i]->_param3 == pSelectedObject->param) { + if (g_cine->_relTable[i]->_param3 == pSelectedObject->param) { found = i; } } @@ -228,19 +224,19 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) { int width; // reverse_iterator would be nice - for (it = overlayList.reverse_begin(); it != overlayList.end(); --it) { - if (it->type >= 2 || !objectTable[it->objIdx].name[0]) { + for (it = g_cine->_overlayList.reverse_begin(); it != g_cine->_overlayList.end(); --it) { + if (it->type >= 2 || !g_cine->_objectTable[it->objIdx].name[0]) { continue; } - objX = objectTable[it->objIdx].x; - objY = objectTable[it->objIdx].y; + objX = g_cine->_objectTable[it->objIdx].x; + objY = g_cine->_objectTable[it->objIdx].y; - frame = ABS((int16)(objectTable[it->objIdx].frame)); - part = objectTable[it->objIdx].part; + frame = ABS((int16)(g_cine->_objectTable[it->objIdx].frame)); + part = g_cine->_objectTable[it->objIdx].part; // Additional case for negative frame values in Operation Stealth - if (g_cine->getGameType() == Cine::GType_OS && objectTable[it->objIdx].frame < 0) { + if (g_cine->getGameType() == Cine::GType_OS && g_cine->_objectTable[it->objIdx].frame < 0) { if ((it->type == 1) && (x >= objX) && (objX + frame >= x) && (y >= objY) && (objY + part >= y)) { return it->objIdx; } else { @@ -249,18 +245,18 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) { } if (it->type == 0) { - threshold = animDataTable[frame]._var1; + threshold = g_cine->_animDataTable[frame]._var1; } else { - threshold = animDataTable[frame]._width / 2; + threshold = g_cine->_animDataTable[frame]._width / 2; } - height = animDataTable[frame]._height; - width = animDataTable[frame]._realWidth; + height = g_cine->_animDataTable[frame]._height; + width = g_cine->_animDataTable[frame]._realWidth; xdif = x - objX; ydif = y - objY; - if ((xdif < 0) || ((threshold << 4) <= xdif) || (ydif <= 0) || (ydif >= height) || !animDataTable[frame].data()) { + if ((xdif < 0) || ((threshold << 4) <= xdif) || (ydif <= 0) || (ydif >= height) || !g_cine->_animDataTable[frame].data()) { continue; } @@ -272,17 +268,17 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) { continue; } - if (it->type == 0 && animDataTable[frame].getColor(xdif, ydif) != (part & 0x0F)) { + if (it->type == 0 && g_cine->_animDataTable[frame].getColor(xdif, ydif) != (part & 0x0F)) { return it->objIdx; - } else if (it->type == 1 && gfxGetBit(xdif, ydif, animDataTable[frame].data(), animDataTable[frame]._width * 4)) { + } else if (it->type == 1 && gfxGetBit(xdif, ydif, g_cine->_animDataTable[frame].data(), g_cine->_animDataTable[frame]._width * 4)) { return it->objIdx; } } else if (it->type == 0) { // use generated mask - if (gfxGetBit(xdif, ydif, animDataTable[frame].mask(), animDataTable[frame]._width)) { + if (gfxGetBit(xdif, ydif, g_cine->_animDataTable[frame].mask(), g_cine->_animDataTable[frame]._width)) { return it->objIdx; } } else if (it->type == 1) { // is mask - if (gfxGetBit(xdif, ydif, animDataTable[frame].data(), animDataTable[frame]._width * 4)) { + if (gfxGetBit(xdif, ydif, g_cine->_animDataTable[frame].data(), g_cine->_animDataTable[frame]._width * 4)) { return it->objIdx; } } @@ -294,18 +290,18 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) { void CineEngine::resetEngine() { g_sound->stopMusic(); freeAnimDataTable(); - overlayList.clear(); - bgIncrustList.clear(); + g_cine->_overlayList.clear(); + g_cine->_bgIncrustList.clear(); closePart(); - objectScripts.clear(); - globalScripts.clear(); - relTable.clear(); - scriptTable.clear(); - messageTable.clear(); + g_cine->_objectScripts.clear(); + g_cine->_globalScripts.clear(); + g_cine->_relTable.clear(); + g_cine->_scriptTable.clear(); + g_cine->_messageTable.clear(); resetObjectTable(); - globalVars.reset(); + g_cine->_globalVars.reset(); var2 = var3 = var4 = var5 = 0; @@ -320,10 +316,10 @@ void CineEngine::resetEngine() { playerCommand = -1; isDrawCommandEnabled = 0; - commandBuffer = ""; + g_cine->_commandBuffer = ""; - globalVars[VAR_MOUSE_X_POS] = 0; - globalVars[VAR_MOUSE_Y_POS] = 0; + g_cine->_globalVars[VAR_MOUSE_X_POS] = 0; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = 0; fadeRequired = false; @@ -332,7 +328,7 @@ void CineEngine::resetEngine() { checkForPendingDataLoadSwitch = 0; if (g_cine->getGameType() == Cine::GType_OS) { - seqList.clear(); + g_cine->_seqList.clear(); currentAdditionalBgIdx = 0; currentAdditionalBgIdx2 = 0; // TODO: Add resetting of the following variables @@ -539,8 +535,8 @@ int16 buildObjectListCommand(int16 param) { } for (i = 0; i < 255; i++) { - if (objectTable[i].name[0] && objectTable[i].costume == param) { - strcpy(objectListCommand[j], objectTable[i].name); + if (g_cine->_objectTable[i].name[0] && g_cine->_objectTable[i].costume == param) { + strcpy(objectListCommand[j], g_cine->_objectTable[i].name); objListTab[j] = i; j++; } @@ -581,9 +577,9 @@ void makeCommandLine() { commandVar2 = -10; if (playerCommand != -1) { - commandBuffer = defaultActionCommand[playerCommand]; + g_cine->_commandBuffer = defaultActionCommand[playerCommand]; } else { - commandBuffer = ""; + g_cine->_commandBuffer = ""; } if ((playerCommand != -1) && (choiceResultTable[playerCommand] == 2)) { // need object selection ? @@ -602,7 +598,7 @@ void makeCommandLine() { canUseOnObject = 0; } else { // Future Wars playerCommand = -1; - commandBuffer = ""; + g_cine->_commandBuffer = ""; } } else { if (g_cine->getGameType() == Cine::GType_OS) { @@ -616,13 +612,13 @@ void makeCommandLine() { commandVar3[0] = si; commandVar1 = 1; - commandBuffer += " "; - commandBuffer += objectTable[commandVar3[0]].name; - commandBuffer += " "; + g_cine->_commandBuffer += " "; + g_cine->_commandBuffer += g_cine->_objectTable[commandVar3[0]].name; + g_cine->_commandBuffer += " "; if (g_cine->getGameType() == Cine::GType_OS) { - commandBuffer += commandPrepositionTable[playerCommand]; + g_cine->_commandBuffer += commandPrepositionTable[playerCommand]; } else { // Future Wars - commandBuffer += defaultCommandPreposition; + g_cine->_commandBuffer += defaultCommandPreposition; } } } @@ -634,7 +630,7 @@ void makeCommandLine() { processInventory(x, y + 8); playerCommand = -1; commandVar1 = 0; - commandBuffer = ""; + g_cine->_commandBuffer = ""; CursorMan.showMouse(true); } } @@ -654,8 +650,8 @@ void makeCommandLine() { commandVar3[commandVar1] = si; commandVar1++; - commandBuffer += " "; - commandBuffer += objectTable[si].name; + g_cine->_commandBuffer += " "; + g_cine->_commandBuffer += g_cine->_objectTable[si].name; } } @@ -673,13 +669,13 @@ void makeCommandLine() { playerCommand = -1; commandVar1 = 0; - commandBuffer = ""; + g_cine->_commandBuffer = ""; } } if (g_cine->getGameType() == Cine::GType_OS || !disableSystemMenu) { isDrawCommandEnabled = 1; - renderer->setCommand(commandBuffer); + renderer->setCommand(g_cine->_commandBuffer); } } @@ -858,7 +854,7 @@ uint16 executePlayerInput() { if (allowPlayerInput) { // Player input is allowed if (isDrawCommandEnabled) { - renderer->setCommand(commandBuffer); + renderer->setCommand(g_cine->_commandBuffer); } isDrawCommandEnabled = 0; limitMouseCheckCount = true; @@ -906,8 +902,8 @@ uint16 executePlayerInput() { commandVar3[commandVar1] = si; commandVar1++; - commandBuffer += " "; - commandBuffer += objectTable[si].name; + g_cine->_commandBuffer += " "; + g_cine->_commandBuffer += g_cine->_objectTable[si].name; isDrawCommandEnabled = 1; @@ -929,27 +925,27 @@ uint16 executePlayerInput() { playerCommand = -1; commandVar1 = 0; - commandBuffer = ""; + g_cine->_commandBuffer = ""; } else if (g_cine->getGameType() == Cine::GType_OS) { isDrawCommandEnabled = 1; - commandBuffer += commandPrepositionTable[playerCommand]; + g_cine->_commandBuffer += commandPrepositionTable[playerCommand]; } - renderer->setCommand(commandBuffer); + renderer->setCommand(g_cine->_commandBuffer); } else { - globalVars[VAR_MOUSE_X_POS] = mouseX; + g_cine->_globalVars[VAR_MOUSE_X_POS] = mouseX; if (!mouseX) { - globalVars[VAR_MOUSE_X_POS]++; + g_cine->_globalVars[VAR_MOUSE_X_POS]++; } - globalVars[VAR_MOUSE_Y_POS] = mouseY; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = mouseY; if (g_cine->getGameType() == Cine::GType_OS) { if (!mouseY) { - globalVars[VAR_MOUSE_Y_POS]++; + g_cine->_globalVars[VAR_MOUSE_Y_POS]++; } - globalVars[VAR_MOUSE_X_POS_2ND] = globalVars[VAR_MOUSE_X_POS]; - globalVars[VAR_MOUSE_Y_POS_2ND] = globalVars[VAR_MOUSE_Y_POS]; + g_cine->_globalVars[VAR_MOUSE_X_POS_2ND] = g_cine->_globalVars[VAR_MOUSE_X_POS]; + g_cine->_globalVars[VAR_MOUSE_Y_POS_2ND] = g_cine->_globalVars[VAR_MOUSE_Y_POS]; } } } @@ -961,7 +957,7 @@ uint16 executePlayerInput() { if (g_cine->getGameType() == Cine::GType_OS || commandVar2 != objIdx) { if (objIdx != -1) { - renderer->setCommand(commandBuffer + " " + objectTable[objIdx].name); + renderer->setCommand(g_cine->_commandBuffer + " " + g_cine->_objectTable[objIdx].name); } else { isDrawCommandEnabled = 1; } @@ -976,19 +972,19 @@ uint16 executePlayerInput() { int16 objIdx; int16 relEntry; - globalVars[VAR_MOUSE_X_POS] = mouseX; + g_cine->_globalVars[VAR_MOUSE_X_POS] = mouseX; if (!mouseX) { - globalVars[VAR_MOUSE_X_POS]++; + g_cine->_globalVars[VAR_MOUSE_X_POS]++; } - globalVars[VAR_MOUSE_Y_POS] = mouseY; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = mouseY; if (g_cine->getGameType() == Cine::GType_OS) { if (!mouseY) { - globalVars[VAR_MOUSE_Y_POS]++; + g_cine->_globalVars[VAR_MOUSE_Y_POS]++; } - globalVars[VAR_MOUSE_X_POS_2ND] = globalVars[VAR_MOUSE_X_POS]; - globalVars[VAR_MOUSE_Y_POS_2ND] = globalVars[VAR_MOUSE_Y_POS]; + g_cine->_globalVars[VAR_MOUSE_X_POS_2ND] = g_cine->_globalVars[VAR_MOUSE_X_POS]; + g_cine->_globalVars[VAR_MOUSE_Y_POS_2ND] = g_cine->_globalVars[VAR_MOUSE_Y_POS]; } objIdx = getObjectUnderCursor(mouseX, mouseY); @@ -1020,97 +1016,97 @@ uint16 executePlayerInput() { // Handle possible horizontal movement by keyboard if (xMoveKeyb != kKeybMoveCenterX && allowPlayerInput) { if (xMoveKeyb == kKeybMoveRight) { // moving right - const int16 playerFrame = objectTable[1].frame; - const int16 playerX = objectTable[1].x; + const int16 playerFrame = g_cine->_objectTable[1].frame; + const int16 playerX = g_cine->_objectTable[1].x; // TODO: Check if multiplying _width by two here is correct or not - const int16 newX = animDataTable[playerFrame]._width * 2 + playerX + 8; - globalVars[VAR_MOUSE_X_POS] = globalVars[VAR_MOUSE_X_POS_2ND] = newX; + const int16 newX = g_cine->_animDataTable[playerFrame]._width * 2 + playerX + 8; + g_cine->_globalVars[VAR_MOUSE_X_POS] = g_cine->_globalVars[VAR_MOUSE_X_POS_2ND] = newX; } else { // moving left - const int16 playerX = objectTable[1].x; + const int16 playerX = g_cine->_objectTable[1].x; const int16 newX = playerX - 8; - globalVars[VAR_MOUSE_X_POS] = globalVars[VAR_MOUSE_X_POS_2ND] = newX; + g_cine->_globalVars[VAR_MOUSE_X_POS] = g_cine->_globalVars[VAR_MOUSE_X_POS_2ND] = newX; } // Restrain horizontal position to range 0-319 - if (globalVars[VAR_MOUSE_X_POS] < 0) { - globalVars[VAR_MOUSE_X_POS] = globalVars[VAR_MOUSE_X_POS_2ND] = 0; - } else if (globalVars[VAR_MOUSE_X_POS] > 319) { - globalVars[VAR_MOUSE_X_POS] = globalVars[VAR_MOUSE_X_POS_2ND] = 319; + if (g_cine->_globalVars[VAR_MOUSE_X_POS] < 0) { + g_cine->_globalVars[VAR_MOUSE_X_POS] = g_cine->_globalVars[VAR_MOUSE_X_POS_2ND] = 0; + } else if (g_cine->_globalVars[VAR_MOUSE_X_POS] > 319) { + g_cine->_globalVars[VAR_MOUSE_X_POS] = g_cine->_globalVars[VAR_MOUSE_X_POS_2ND] = 319; } } // Handle possible vertical movement by keyboard if (yMoveKeyb != kKeybMoveCenterY && allowPlayerInput) { if (yMoveKeyb == kKeybMoveDown) { // moving down - const int16 playerFrame = objectTable[1].frame; - const int16 playerY = objectTable[1].y; + const int16 playerFrame = g_cine->_objectTable[1].frame; + const int16 playerY = g_cine->_objectTable[1].y; // TODO: Check if multiplying _height by two here is correct or not - const int16 newY = animDataTable[playerFrame]._height * 2 + playerY - 1; - globalVars[VAR_MOUSE_Y_POS] = globalVars[VAR_MOUSE_Y_POS_2ND] = newY; + const int16 newY = g_cine->_animDataTable[playerFrame]._height * 2 + playerY - 1; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = g_cine->_globalVars[VAR_MOUSE_Y_POS_2ND] = newY; } else { // moving up - const int16 playerY = objectTable[1].y; + const int16 playerY = g_cine->_objectTable[1].y; const int16 newY = playerY - 8; - globalVars[VAR_MOUSE_Y_POS] = globalVars[VAR_MOUSE_Y_POS_2ND] = newY; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = g_cine->_globalVars[VAR_MOUSE_Y_POS_2ND] = newY; } // Restrain vertical position to range 0-199 - if (globalVars[VAR_MOUSE_Y_POS] < 0) { - globalVars[VAR_MOUSE_Y_POS] = globalVars[VAR_MOUSE_Y_POS_2ND] = 0; - } else if (globalVars[VAR_MOUSE_Y_POS] > 199) { - globalVars[VAR_MOUSE_Y_POS] = globalVars[VAR_MOUSE_Y_POS_2ND] = 199; + if (g_cine->_globalVars[VAR_MOUSE_Y_POS] < 0) { + g_cine->_globalVars[VAR_MOUSE_Y_POS] = g_cine->_globalVars[VAR_MOUSE_Y_POS_2ND] = 0; + } else if (g_cine->_globalVars[VAR_MOUSE_Y_POS] > 199) { + g_cine->_globalVars[VAR_MOUSE_Y_POS] = g_cine->_globalVars[VAR_MOUSE_Y_POS_2ND] = 199; } } } else if (egoMovedWithKeyboard && allowPlayerInput) { // FW: Move using keyboard egoMovedWithKeyboard = false; - switch (globalVars[VAR_MOUSE_X_MODE]) { + switch (g_cine->_globalVars[VAR_MOUSE_X_MODE]) { case 1: - mouseX = objectTable[1].x + 12; + mouseX = g_cine->_objectTable[1].x + 12; break; case 2: - mouseX = objectTable[1].x + 7; + mouseX = g_cine->_objectTable[1].x + 7; break; default: - mouseX = globalVars[VAR_MOUSE_X_POS]; + mouseX = g_cine->_globalVars[VAR_MOUSE_X_POS]; break; } - switch (globalVars[VAR_MOUSE_Y_MODE]) { + switch (g_cine->_globalVars[VAR_MOUSE_Y_MODE]) { case 1: - mouseY = objectTable[1].y + 34; + mouseY = g_cine->_objectTable[1].y + 34; break; case 2: - mouseY = objectTable[1].y + 28; + mouseY = g_cine->_objectTable[1].y + 28; break; default: - mouseY = globalVars[VAR_MOUSE_Y_POS]; + mouseY = g_cine->_globalVars[VAR_MOUSE_Y_POS]; break; } if (var_5E == bgVar0) { var_5E = 0; - globalVars[VAR_MOUSE_X_POS] = mouseX; - globalVars[VAR_MOUSE_Y_POS] = mouseY; + g_cine->_globalVars[VAR_MOUSE_X_POS] = mouseX; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = mouseY; } else { if (xMoveKeyb) { if (xMoveKeyb == kKeybMoveLeft) { - globalVars[VAR_MOUSE_X_POS] = 1; + g_cine->_globalVars[VAR_MOUSE_X_POS] = 1; } else { - globalVars[VAR_MOUSE_X_POS] = 320; + g_cine->_globalVars[VAR_MOUSE_X_POS] = 320; } } else { - globalVars[VAR_MOUSE_X_POS] = mouseX; + g_cine->_globalVars[VAR_MOUSE_X_POS] = mouseX; } if (yMoveKeyb) { if (yMoveKeyb == kKeybMoveUp) { - globalVars[VAR_MOUSE_Y_POS] = 1; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = 1; } else { - globalVars[VAR_MOUSE_Y_POS] = 200; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = 200; } } else { - globalVars[VAR_MOUSE_Y_POS] = mouseY; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = mouseY; } } @@ -1167,27 +1163,27 @@ void drawSprite(Common::List<overlay>::iterator it, const byte *spritePtr, const msk = (byte *)malloc(width * height); if (g_cine->getGameType() == Cine::GType_OS) { - generateMask(spritePtr, msk, width * height, objectTable[it->objIdx].part); + generateMask(spritePtr, msk, width * height, g_cine->_objectTable[it->objIdx].part); } else { memcpy(msk, maskPtr, width * height); } - for (++it; it != overlayList.end(); ++it) { + for (++it; it != g_cine->_overlayList.end(); ++it) { if (it->type != 5) { continue; } - maskX = objectTable[it->objIdx].x; - maskY = objectTable[it->objIdx].y; + maskX = g_cine->_objectTable[it->objIdx].x; + maskY = g_cine->_objectTable[it->objIdx].y; - maskSpriteIdx = ABS((int16)(objectTable[it->objIdx].frame)); + maskSpriteIdx = ABS((int16)(g_cine->_objectTable[it->objIdx].frame)); - maskWidth = animDataTable[maskSpriteIdx]._realWidth; - maskHeight = animDataTable[maskSpriteIdx]._height; - gfxUpdateSpriteMask(msk, x, y, width, height, animDataTable[maskSpriteIdx].data(), maskX, maskY, maskWidth, maskHeight); + maskWidth = g_cine->_animDataTable[maskSpriteIdx]._realWidth; + maskHeight = g_cine->_animDataTable[maskSpriteIdx]._height; + gfxUpdateSpriteMask(msk, x, y, width, height, g_cine->_animDataTable[maskSpriteIdx].data(), maskX, maskY, maskWidth, maskHeight); #ifdef DEBUG_SPRITE_MASK - gfxFillSprite(animDataTable[maskSpriteIdx].data(), maskWidth, maskHeight, page, maskX, maskY, 1); + gfxFillSprite(g_cine->_animDataTable[maskSpriteIdx].data(), maskWidth, maskHeight, page, maskX, maskY, 1); #endif } @@ -1199,7 +1195,7 @@ void removeMessages() { Common::List<overlay>::iterator it; bool remove; - for (it = overlayList.begin(); it != overlayList.end(); ) { + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ) { if (g_cine->getGameType() == Cine::GType_OS) { // NOTE: These are really removeOverlay calls that have been deferred. // In Operation Stealth's disassembly elements are removed from the @@ -1213,7 +1209,7 @@ void removeMessages() { } if (remove) { - it = overlayList.erase(it); + it = g_cine->_overlayList.erase(it); } else { ++it; } @@ -1255,7 +1251,7 @@ void checkForPendingDataLoad() { } if (newObjectName[0] != 0) { - overlayList.clear(); + g_cine->_overlayList.clear(); loadObject(newObjectName); @@ -1294,15 +1290,13 @@ void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 par tmp.width = param4; tmp.color = param5; - overlayList.push_back(tmp); + g_cine->_overlayList.push_back(tmp); } -Common::List<SeqListElement> seqList; - void removeSeq(uint16 param1, uint16 param2, uint16 param3) { Common::List<SeqListElement>::iterator it; - for (it = seqList.begin(); it != seqList.end(); ++it) { + for (it = g_cine->_seqList.begin(); it != g_cine->_seqList.end(); ++it) { if (it->objIdx == param1 && it->var4 == param2 && it->varE == param3) { it->var4 = -1; break; @@ -1313,7 +1307,7 @@ void removeSeq(uint16 param1, uint16 param2, uint16 param3) { bool isSeqRunning(uint16 param1, uint16 param2, uint16 param3) { Common::List<SeqListElement>::iterator it; - for (it = seqList.begin(); it != seqList.end(); ++it) { + for (it = g_cine->_seqList.begin(); it != g_cine->_seqList.end(); ++it) { if (it->objIdx == param1 && it->var4 == param2 && it->varE == param3) { // Just to be on the safe side there's a restriction of the // addition's result to 16-bit arithmetic here like in the @@ -1329,7 +1323,7 @@ void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, i Common::List<SeqListElement>::iterator it; SeqListElement tmp; - for (it = seqList.begin(); it != seqList.end() && it->varE < param7; ++it) ; + for (it = g_cine->_seqList.begin(); it != g_cine->_seqList.end() && it->varE < param7; ++it) ; tmp.objIdx = objIdx; tmp.var4 = param1; @@ -1346,12 +1340,12 @@ void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, i tmp.var1C = 0; tmp.var1E = 0; - seqList.insert(it, tmp); + g_cine->_seqList.insert(it, tmp); } void modifySeqListElement(uint16 objIdx, int16 var4Test, int16 param1, int16 param2, int16 param3, int16 param4) { // Find a suitable list element and modify it - for (Common::List<SeqListElement>::iterator it = seqList.begin(); it != seqList.end(); ++it) { + for (Common::List<SeqListElement>::iterator it = g_cine->_seqList.begin(); it != g_cine->_seqList.end(); ++it) { if (it->objIdx == objIdx && it->var4 == var4Test) { it->varC = param1; it->var18 = param2; @@ -1425,7 +1419,7 @@ uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &ele // In the original an error string is set and 0 is returned if the following doesn't hold assert(*ptrData); - di = (objectTable[objIdx].costume + 1) % (*ptrData); + di = (g_cine->_objectTable[objIdx].costume + 1) % (*ptrData); ++ptrData; // Jump over the just read byte // Here ptr2 seems to be indexing a table of structs (8 bytes per struct): // struct { @@ -1446,18 +1440,18 @@ uint16 addAni(uint16 param1, uint16 objIdx, const int8 *ptr, SeqListElement &ele return 0; } - objectTable[objIdx].x += ptr2[4]; - objectTable[objIdx].y += ptr2[5]; - objectTable[objIdx].mask += ptr2[6]; + g_cine->_objectTable[objIdx].x += ptr2[4]; + g_cine->_objectTable[objIdx].y += ptr2[5]; + g_cine->_objectTable[objIdx].mask += ptr2[6]; if (ptr2[6]) { resetGfxEntityEntry(objIdx); } - objectTable[objIdx].frame = ptr2[7] + element.var8; + g_cine->_objectTable[objIdx].frame = ptr2[7] + element.var8; if (param3 || !element.var14) { - objectTable[objIdx].costume = di; + g_cine->_objectTable[objIdx].costume = di; } else { assert(param4); *param4 = di; @@ -1476,7 +1470,7 @@ void resetGfxEntityEntry(uint16 objIdx) { bool foundCutPoint = false; // Go through the overlay list and partition the whole list into two categories (Type A and type B objects) - for (it = overlayList.begin(); it != overlayList.end(); ++it) { + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { if (it->objIdx == objIdx && it->type != 2 && it->type != 3) { // Type A object aReverseObjs.push_front(*it); } else { // Type B object @@ -1485,10 +1479,10 @@ void resetGfxEntityEntry(uint16 objIdx) { if (it->type == 2 || it->type == 3) { objectMask = 10000; } else { - objectMask = objectTable[it->objIdx].mask; + objectMask = g_cine->_objectTable[it->objIdx].mask; } - if (objectTable[objIdx].mask > objectMask) { // Check for B objects' cut point + if (g_cine->_objectTable[objIdx].mask > objectMask) { // Check for B objects' cut point bObjsCutPoint = bObjs.reverse_begin(); foundCutPoint = true; } @@ -1496,26 +1490,26 @@ void resetGfxEntityEntry(uint16 objIdx) { } // Recreate the overlay list in a different order. - overlayList.clear(); + g_cine->_overlayList.clear(); if (foundCutPoint) { // If a cut point was found the order is: // B objects before the cut point, the cut point, A objects in reverse order, B objects after cut point. ++bObjsCutPoint; // Include the cut point in the first list insertion - overlayList.insert(overlayList.end(), bObjs.begin(), bObjsCutPoint); - overlayList.insert(overlayList.end(), aReverseObjs.begin(), aReverseObjs.end()); - overlayList.insert(overlayList.end(), bObjsCutPoint, bObjs.end()); + g_cine->_overlayList.insert(g_cine->_overlayList.end(), bObjs.begin(), bObjsCutPoint); + g_cine->_overlayList.insert(g_cine->_overlayList.end(), aReverseObjs.begin(), aReverseObjs.end()); + g_cine->_overlayList.insert(g_cine->_overlayList.end(), bObjsCutPoint, bObjs.end()); } else { // If no cut point was found the order is: // A objects in reverse order, B objects. - overlayList.insert(overlayList.end(), aReverseObjs.begin(), aReverseObjs.end()); - overlayList.insert(overlayList.end(), bObjs.begin(), bObjs.end()); + g_cine->_overlayList.insert(g_cine->_overlayList.end(), aReverseObjs.begin(), aReverseObjs.end()); + g_cine->_overlayList.insert(g_cine->_overlayList.end(), bObjs.begin(), bObjs.end()); } } void processSeqListElement(SeqListElement &element) { - int16 x = objectTable[element.objIdx].x; - int16 y = objectTable[element.objIdx].y; - const int8 *ptr1 = (const int8 *) animDataTable[element.frame].data(); + int16 x = g_cine->_objectTable[element.objIdx].x; + int16 y = g_cine->_objectTable[element.objIdx].y; + const int8 *ptr1 = (const int8 *) g_cine->_animDataTable[element.frame].data(); int16 var_10; int16 var_4; int16 var_2; @@ -1548,8 +1542,8 @@ void processSeqListElement(SeqListElement &element) { int16 x2 = element.var18; int16 y2 = element.var1A; if (element.varC) { - x2 += objectTable[element.varC].x; - y2 += objectTable[element.varC].y; + x2 += g_cine->_objectTable[element.varC].x; + y2 += g_cine->_objectTable[element.varC].y; } computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, x2, y2); } else { @@ -1558,7 +1552,7 @@ void processSeqListElement(SeqListElement &element) { if (xMoveKeyb != kKeybMoveRight) { adder = -adder; } - globalVars[VAR_MOUSE_X_POS] = globalVars[VAR_MOUSE_X_POS_2ND] = ptr1[4] + x + adder; + g_cine->_globalVars[VAR_MOUSE_X_POS] = g_cine->_globalVars[VAR_MOUSE_X_POS_2ND] = ptr1[4] + x + adder; } if (yMoveKeyb && allowPlayerInput) { @@ -1566,11 +1560,11 @@ void processSeqListElement(SeqListElement &element) { if (yMoveKeyb != kKeybMoveDown) { adder = -adder; } - globalVars[VAR_MOUSE_Y_POS] = globalVars[VAR_MOUSE_Y_POS_2ND] = ptr1[5] + y + adder; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = g_cine->_globalVars[VAR_MOUSE_Y_POS_2ND] = ptr1[5] + y + adder; } - if (globalVars[VAR_MOUSE_X_POS] || globalVars[VAR_MOUSE_Y_POS]) { - computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, globalVars[VAR_MOUSE_X_POS], globalVars[VAR_MOUSE_Y_POS]); + if (g_cine->_globalVars[VAR_MOUSE_X_POS] || g_cine->_globalVars[VAR_MOUSE_Y_POS]) { + computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, g_cine->_globalVars[VAR_MOUSE_X_POS], g_cine->_globalVars[VAR_MOUSE_Y_POS]); } else { element.var16 = 0; element.var14 = 0; @@ -1590,27 +1584,27 @@ void processSeqListElement(SeqListElement &element) { && !addAni(3, element.objIdx, ptr1, element, 0, &var_4)) || (element.var16 == 2 && !addAni(2, element.objIdx, ptr1, element, 0, &var_4))) { if (element.varC == 255) { - globalVars[VAR_MOUSE_Y_POS] = 0; + g_cine->_globalVars[VAR_MOUSE_Y_POS] = 0; } } if ((element.var14 == 1 && !addAni(0, element.objIdx, ptr1, element, 1, &var_2))) { if (element.varC == 255) { - globalVars[VAR_MOUSE_X_POS] = 0; + g_cine->_globalVars[VAR_MOUSE_X_POS] = 0; if (var_4 != -1) { - objectTable[element.objIdx].costume = var_4; + g_cine->_objectTable[element.objIdx].costume = var_4; } } } if ((element.var14 == 2 && !addAni(1, element.objIdx, ptr1, element, 1, &var_2))) { if (element.varC == 255) { - globalVars[VAR_MOUSE_X_POS] = 0; + g_cine->_globalVars[VAR_MOUSE_X_POS] = 0; if (var_4 != -1) { - objectTable[element.objIdx].costume = var_4; + g_cine->_objectTable[element.objIdx].costume = var_4; } } } @@ -1618,7 +1612,7 @@ void processSeqListElement(SeqListElement &element) { if (element.var16 + element.var14 == 0) { if (element.var1C) { if (element.var1E) { - objectTable[element.objIdx].costume = 0; + g_cine->_objectTable[element.objIdx].costume = 0; element.var1E = 0; } @@ -1633,7 +1627,7 @@ void processSeqListElement(SeqListElement &element) { void processSeqList() { Common::List<SeqListElement>::iterator it; - for (it = seqList.begin(); it != seqList.end(); ++it) { + for (it = g_cine->_seqList.begin(); it != g_cine->_seqList.end(); ++it) { if (it->var4 == -1) { continue; } diff --git a/engines/cine/various.h b/engines/cine/various.h index 3f362b1ad6..3a14328035 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -66,8 +66,6 @@ struct SeqListElement { int16 var1E; }; -extern Common::List<SeqListElement> seqList; - extern uint16 var2; extern uint16 var3; extern uint16 var4; @@ -95,8 +93,6 @@ extern uint16 _messageLen; extern int16 playerCommand; -extern Common::String commandBuffer; - extern char currentPrcName[20]; extern char currentRelName[20]; extern char currentObjectName[20]; @@ -137,8 +133,6 @@ struct SelectedObjStruct { }; #define NUM_MAX_ZONE 16 -extern Common::Array<uint16> zoneData; -extern Common::Array<uint16> zoneQuery; void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 param5); diff --git a/engines/cruise/actor.cpp b/engines/cruise/actor.cpp index 81e39600f5..9cbc3dd9ae 100644 --- a/engines/cruise/actor.cpp +++ b/engines/cruise/actor.cpp @@ -74,8 +74,8 @@ int flag_aff_chemin; void getPixel(int x, int y) { - for (uint i = 0; i < polyStructs->size(); ++i) { - CtStruct &ct = (*polyStructs)[i]; + for (uint i = 0; i < _vm->_polyStructs->size(); ++i) { + CtStruct &ct = (*_vm->_polyStructs)[i]; numPoly = ct.num; if (walkboxState[numPoly] == 0 && ct.bounds.contains(x, y)) { @@ -293,7 +293,7 @@ int point_proche(int16 table[][2]) { int x1, y1, i, x, y, p; int d1 = 1000; - polyStructs = &polyStructNorm; + _vm->_polyStructs = &_vm->_polyStructNorm; if (nclick_noeud == 1) { x = x_mouse; @@ -301,19 +301,19 @@ int point_proche(int16 table[][2]) { x1 = table_ptselect[0][0]; y1 = table_ptselect[0][1]; - polyStructs = &polyStructExp; + _vm->_polyStructs = &_vm->_polyStructExp; getPixel(x, y); if (!flag_obstacle) { - polyStructs = &polyStructNorm; + _vm->_polyStructs = &_vm->_polyStructNorm; getPixel(x, y); if (flag_obstacle) { polydroite(x1, y1, x, y); } - polyStructs = &polyStructExp; + _vm->_polyStructs = &_vm->_polyStructExp; } if (!flag_obstacle) { /* dans flag_obstacle --> couleur du point */ x1 = table_ptselect[0][0]; @@ -325,7 +325,7 @@ int point_proche(int16 table[][2]) { y_mouse = Y; } } - polyStructs = &polyStructNorm; + _vm->_polyStructs = &_vm->_polyStructNorm; p = -1; for (i = 0; i < ctp_routeCoordCount; i++) { @@ -453,7 +453,7 @@ void valide_noeud(int16 table[], int16 p, int *nclick, int16 solution0[20 + 3][2 table_ptselect[*nclick][0] = x_mouse; table_ptselect[*nclick][1] = y_mouse; (*nclick)++; - polyStructs = &polyStructNorm; + _vm->_polyStructs = &_vm->_polyStructNorm; if (*nclick == 2) { // second point x1 = table_ptselect[0][0]; @@ -464,7 +464,7 @@ void valide_noeud(int16 table[], int16 p, int *nclick, int16 solution0[20 + 3][2 return; } flag_aff_chemin = 1; - polyStructs = &polyStructExp; + _vm->_polyStructs = &_vm->_polyStructExp; // can we go there directly ? polydroite(x1, y1, x2, y2); @@ -472,7 +472,7 @@ void valide_noeud(int16 table[], int16 p, int *nclick, int16 solution0[20 + 3][2 if (!flag_obstacle) { solution0[0][0] = x1; solution0[0][1] = y1; - polyStructs = &polyStructExp; + _vm->_polyStructs = &_vm->_polyStructExp; poly2(x2, y2, ctp_routeCoords[select_noeud[1]][0], ctp_routeCoords[select_noeud[1]][1]); @@ -516,7 +516,7 @@ void valide_noeud(int16 table[], int16 p, int *nclick, int16 solution0[20 + 3][2 solution0[++i][1] = ctp_routeCoords[p1][1]; } - polyStructs = &polyStructExp; + _vm->_polyStructs = &_vm->_polyStructExp; poly2(x2, y2, ctp_routeCoords[select_noeud[1]][0], ctp_routeCoords[select_noeud[1]][1]); @@ -541,7 +541,7 @@ void valide_noeud(int16 table[], int16 p, int *nclick, int16 solution0[20 + 3][2 while (flag_obstacle && i != d) { x2 = solution0[i][0]; y2 = solution0[i][1]; - polyStructs = &polyStructExp; + _vm->_polyStructs = &_vm->_polyStructExp; polydroite(x1, y1, x2, y2); i--; } @@ -569,7 +569,7 @@ int16 computePathfinding(MovementEntry &moveInfo, int16 x, int16 y, int16 destX, persoStruct *perso; int num; - if (!polyStruct) { + if (!_vm->_polyStruct) { moveInfo.x = -1; moveInfo.y = -1; @@ -621,7 +621,7 @@ int16 computePathfinding(MovementEntry &moveInfo, int16 x, int16 y, int16 destX, } nclick_noeud = 0; - polyStructs = &polyStructNorm; + _vm->_polyStructs = &_vm->_polyStructNorm; flag_aff_chemin = 0; if (x == destX && y == destY) { diff --git a/engines/cruise/cruise.cpp b/engines/cruise/cruise.cpp index 2f38aa98ba..3af77f3ef3 100644 --- a/engines/cruise/cruise.cpp +++ b/engines/cruise/cruise.cpp @@ -133,8 +133,8 @@ void CruiseEngine::initialize() { } void CruiseEngine::deinitialise() { - polyStructNorm.clear(); - polyStructExp.clear(); + _vm->_polyStructNorm.clear(); + _vm->_polyStructExp.clear(); // Clear any backgrounds for (int i = 0; i < 8; ++i) { diff --git a/engines/cruise/cruise.h b/engines/cruise/cruise.h index 0428240167..94f5c68ca0 100644 --- a/engines/cruise/cruise.h +++ b/engines/cruise/cruise.h @@ -40,10 +40,10 @@ /** * This is the namespace of the Cruise engine. * - * Status of this engine: ??? + * Status of this engine: Game is completable, engine needs objectifying * * Supported games: - * - ??? + * - Cruise for a Corpse */ namespace Cruise { @@ -112,6 +112,22 @@ public: void initAllData(); Common::RandomSource _rnd; + + Common::List<byte *> _memList; + + typedef Common::List<Common::Rect> RectList; + + RectList _dirtyRects; + RectList _priorFrameRects; + + Common::File _currentVolumeFile; + + Common::Array<CtStruct> _polyStructNorm; + Common::Array<CtStruct> _polyStructExp; + Common::Array<CtStruct> *_polyStructs; + Common::Array<CtStruct> *_polyStruct; + + Common::File _PAL_file; }; extern CruiseEngine *_vm; diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp index 65d8b57366..aa78f84e3d 100644 --- a/engines/cruise/cruise_main.cpp +++ b/engines/cruise/cruise_main.cpp @@ -42,13 +42,11 @@ unsigned int timer = 0; gfxEntryStruct* linkedMsgList = NULL; -Common::List<byte *> memList; - void MemoryList() { - if (!memList.empty()) { + if (!_vm->_memList.empty()) { printf("Current list of un-freed memory blocks:\n"); Common::List<byte *>::iterator i; - for (i = memList.begin(); i != memList.end(); ++i) { + for (i = _vm->_memList.begin(); i != _vm->_memList.end(); ++i) { byte *v = *i; printf("%s - %d\n", (const char *)(v - 68), *((int32 *)(v - 72))); } @@ -73,7 +71,7 @@ void *MemoryAlloc(uint32 size, bool clearFlag, int32 lineNum, const char *fname) // Add the block to the memory list result = v + 64 + 8; - memList.push_back(result); + _vm->_memList.push_back(result); } else result = (byte *)malloc(size); @@ -91,7 +89,7 @@ void MemoryFree(void *v) { byte *p = (byte *)v; assert(*((uint32 *) (p - 4)) == 0x41424344); - memList.remove(p); + _vm->_memList.remove(p); free(p - 8 - 64); } else free(v); @@ -105,8 +103,8 @@ void drawBlackSolidBoxSmall() { void loadPackedFileToMem(int fileIdx, uint8 *buffer) { changeCursor(CURSOR_DISK); - currentVolumeFile.seek(volumePtrToFileDescriptor[fileIdx].offset, SEEK_SET); - currentVolumeFile.read(buffer, volumePtrToFileDescriptor[fileIdx].size); + _vm->_currentVolumeFile.seek(volumePtrToFileDescriptor[fileIdx].offset, SEEK_SET); + _vm->_currentVolumeFile.read(buffer, volumePtrToFileDescriptor[fileIdx].size); } int getNumObjectsByClass(int scriptIdx, int param) { diff --git a/engines/cruise/ctp.cpp b/engines/cruise/ctp.cpp index 59f3cae942..4f6c21e0e4 100644 --- a/engines/cruise/ctp.cpp +++ b/engines/cruise/ctp.cpp @@ -23,6 +23,7 @@ * */ +#include "cruise/cruise.h" #include "cruise/cruise_main.h" #include "common/endian.h" #include "common/util.h" @@ -31,11 +32,6 @@ namespace Cruise { uint8 *ctpVar17; -Common::Array<CtStruct> polyStructNorm; -Common::Array<CtStruct> polyStructExp; -Common::Array<CtStruct> *polyStructs = NULL; -Common::Array<CtStruct> *polyStruct = NULL; - int currentWalkBoxCenterX; int currentWalkBoxCenterY; int currentWalkBoxCenterXBis; @@ -324,16 +320,16 @@ int initCt(const char *ctpName) { // Load the polyStructNorm list for (int i = numberOfWalkboxes - 1; i >= 0; i--) { - makeCtStruct(polyStructNorm, ctp_walkboxTable, i, 0); + makeCtStruct(_vm->_polyStructNorm, ctp_walkboxTable, i, 0); } // Load the polyStructExp list for (int i = numberOfWalkboxes - 1; i >= 0; i--) { - makeCtStruct(polyStructExp, ctp_walkboxTable, i, walkboxZoom[i] * 20); + makeCtStruct(_vm->_polyStructExp, ctp_walkboxTable, i, walkboxZoom[i] * 20); } - polyStruct = polyStructs = &polyStructNorm; + _vm->_polyStruct = _vm->_polyStructs = &_vm->_polyStructNorm; return (1); } diff --git a/engines/cruise/ctp.h b/engines/cruise/ctp.h index 6cc5ea48ef..3c6c9582cc 100644 --- a/engines/cruise/ctp.h +++ b/engines/cruise/ctp.h @@ -64,11 +64,6 @@ public: extern uint8 *ctpVar17; -extern Common::Array<CtStruct> polyStructNorm; -extern Common::Array<CtStruct> polyStructExp; -extern Common::Array<CtStruct> *polyStructs; -extern Common::Array<CtStruct> *polyStruct; - int initCt(const char * ctpName); int computeDistance(int varX, int varY, int paramX, int paramY); diff --git a/engines/cruise/gfxModule.cpp b/engines/cruise/gfxModule.cpp index dbc8160ac6..4a88e6ed5e 100644 --- a/engines/cruise/gfxModule.cpp +++ b/engines/cruise/gfxModule.cpp @@ -43,10 +43,6 @@ palEntry lpalette[256]; int palDirtyMin = 256; int palDirtyMax = -1; -typedef Common::List<Common::Rect> RectList; -RectList _dirtyRects; -RectList _priorFrameRects; - bool _dirtyRectScreen = false; gfxModuleDataStruct gfxModuleData = { @@ -238,7 +234,7 @@ void gfxModuleData_flipScreen() { } void gfxModuleData_addDirtyRect(const Common::Rect &r) { - _dirtyRects.push_back(Common::Rect( MAX(r.left, (int16)0), MAX(r.top, (int16)0), + _vm->_dirtyRects.push_back(Common::Rect( MAX(r.left, (int16)0), MAX(r.top, (int16)0), MIN(r.right, (int16)320), MIN(r.bottom, (int16)200))); } @@ -255,11 +251,11 @@ static bool unionRectangle(Common::Rect &pDest, const Common::Rect &pSrc1, const } static void mergeClipRects() { - RectList::iterator rOuter, rInner; + CruiseEngine::RectList::iterator rOuter, rInner; - for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) { + for (rOuter = _vm->_dirtyRects.begin(); rOuter != _vm->_dirtyRects.end(); ++rOuter) { rInner = rOuter; - while (++rInner != _dirtyRects.end()) { + while (++rInner != _vm->_dirtyRects.end()) { if ((*rOuter).intersects(*rInner)) { // these two rectangles overlap, so translate it to a bigger rectangle @@ -267,7 +263,7 @@ static void mergeClipRects() { unionRectangle(*rOuter, *rOuter, *rInner); // remove the inner rect from the list - _dirtyRects.erase(rInner); + _vm->_dirtyRects.erase(rInner); // move back to beginning of list rInner = rOuter; @@ -298,32 +294,32 @@ void gfxModuleData_updateScreen() { } void flip() { - RectList::iterator dr; + CruiseEngine::RectList::iterator dr; // Update the palette gfxModuleData_updatePalette(); // Make a copy of the prior frame's dirty rects, and then backup the current frame's rects - RectList tempList = _priorFrameRects; - _priorFrameRects = _dirtyRects; + CruiseEngine::RectList tempList = _vm->_priorFrameRects; + _vm->_priorFrameRects = _vm->_dirtyRects; // Merge the prior frame's dirty rects into the current frame's list for (dr = tempList.begin(); dr != tempList.end(); ++dr) { Common::Rect &r = *dr; - _dirtyRects.push_back(Common::Rect(r.left, r.top, r.right, r.bottom)); + _vm->_dirtyRects.push_back(Common::Rect(r.left, r.top, r.right, r.bottom)); } // Merge any overlapping rects to simplify the drawing process mergeClipRects(); // Copy any modified areas - for (dr = _dirtyRects.begin(); dr != _dirtyRects.end(); ++dr) { + for (dr = _vm->_dirtyRects.begin(); dr != _vm->_dirtyRects.end(); ++dr) { Common::Rect &r = *dr; g_system->copyRectToScreen(globalScreen + 320 * r.top + r.left, 320, r.left, r.top, r.width(), r.height()); } - _dirtyRects.clear(); + _vm->_dirtyRects.clear(); // Allow the screen to update g_system->updateScreen(); diff --git a/engines/cruise/perso.cpp b/engines/cruise/perso.cpp index 27d3c8cb7d..e86daa5bef 100644 --- a/engines/cruise/perso.cpp +++ b/engines/cruise/perso.cpp @@ -23,6 +23,7 @@ * */ +#include "cruise/cruise.h" #include "cruise/cruise_main.h" #include "common/util.h" @@ -45,14 +46,14 @@ void freeCTP() { freePerso(i); } - if (polyStruct) { - polyStructNorm.clear(); - polyStructExp.clear(); - polyStruct = NULL; + if (_vm->_polyStruct) { + _vm->_polyStructNorm.clear(); + _vm->_polyStructExp.clear(); + _vm->_polyStruct = NULL; } ctpVar17 = NULL; - polyStruct = NULL; + _vm->_polyStruct = NULL; strcpy((char *)currentCtpName, ""); } diff --git a/engines/cruise/saveload.cpp b/engines/cruise/saveload.cpp index 6e50ef8cdb..24ea2facfe 100644 --- a/engines/cruise/saveload.cpp +++ b/engines/cruise/saveload.cpp @@ -579,10 +579,10 @@ static void syncPerso(Common::Serializer &s, persoStruct &p) { } static void syncCT(Common::Serializer &s) { - int v = (polyStruct) ? 1 : 0; + int v = (_vm->_polyStruct) ? 1 : 0; s.syncAsSint32LE(v); if (s.isLoading()) - polyStruct = (v != 0) ? &polyStructNorm : NULL; + _vm->_polyStruct = (v != 0) ? &_vm->_polyStructNorm : NULL; if (v == 0) // There is no further data to load or save diff --git a/engines/cruise/script.cpp b/engines/cruise/script.cpp index f2877a7730..d6c1aa47f3 100644 --- a/engines/cruise/script.cpp +++ b/engines/cruise/script.cpp @@ -618,13 +618,13 @@ int executeScripts(scriptInstanceStruct *ptr) { positionInStack = 0; do { -#ifdef SKIP_INTRO +//#ifdef SKIP_INTRO if (currentScriptPtr->scriptOffset == 290 && currentScriptPtr->overlayNumber == 4 && currentScriptPtr->scriptNumber == 0) { currentScriptPtr->scriptOffset = 923; } -#endif +//#endif opcodeType = getByteFromScript(); debugC(5, kCruiseDebugScript, "Script %s/%d ip=%d opcode=%d", diff --git a/engines/cruise/vars.cpp b/engines/cruise/vars.cpp index bab5d171fd..c61cedc503 100644 --- a/engines/cruise/vars.cpp +++ b/engines/cruise/vars.cpp @@ -64,8 +64,6 @@ int16 autoTrack; int16 currentDiskNumber = 1; -Common::File currentVolumeFile; - int16 volumeNumEntry; fileEntry *volumePtrToFileDescriptor = NULL; diff --git a/engines/cruise/vars.h b/engines/cruise/vars.h index 3cb09602cc..af39993f2f 100644 --- a/engines/cruise/vars.h +++ b/engines/cruise/vars.h @@ -167,8 +167,6 @@ extern int16 autoTrack; extern int16 currentDiskNumber; -extern Common::File currentVolumeFile; - extern int16 volumeNumEntry; extern fileEntry *volumePtrToFileDescriptor; diff --git a/engines/cruise/volume.cpp b/engines/cruise/volume.cpp index 3b856b4440..5535d5a016 100644 --- a/engines/cruise/volume.cpp +++ b/engines/cruise/volume.cpp @@ -23,11 +23,11 @@ * */ +#include "cruise/cruise.h" #include "cruise/cruise_main.h" namespace Cruise { -Common::File PAL_file; uint8 *PAL_ptr = NULL; int16 numLoadedPal; @@ -40,25 +40,25 @@ void loadPal(volumeDataStruct *entry) { #if 0 char name[20]; - if (PAL_file.isOpen()) - PAL_file.close(); + if (_vm->_PAL_file.isOpen()) + _vm->_PAL_file.close(); removeExtention(entry->ident, name); strcat(name, ".PAL"); - if (!PAL_file.open(name)) + if (!_vm->_PAL_file.open(name)) return; - numLoadedPal = PAL_file.readSint16BE(); - fileData2 = PAL_file.readSint16BE(); + numLoadedPal = _vm->_PAL_file.readSint16BE(); + fileData2 = _vm->_PAL_file.readSint16BE(); PAL_ptr = (uint8 *)MemAlloc(numLoadedPal * fileData2); #endif } void closePal() { - if (PAL_file.isOpen()) { - PAL_file.close(); + if (_vm->_PAL_file.isOpen()) { + _vm->_PAL_file.close(); MemFree(PAL_ptr); PAL_ptr = NULL; @@ -69,15 +69,15 @@ void closePal() { } int closeBase() { - if (currentVolumeFile.isOpen()) { - currentVolumeFile.close(); + if (_vm->_currentVolumeFile.isOpen()) { + _vm->_currentVolumeFile.close(); MemFree(volumePtrToFileDescriptor); strcpy(currentBaseName, ""); } - if (PAL_file.isOpen()) { + if (_vm->_PAL_file.isOpen()) { closePal(); } @@ -91,7 +91,7 @@ int getVolumeDataEntry(volumeDataStruct *entry) { volumeNumEntry = 0; volumeNumberOfEntry = 0; - if (currentVolumeFile.isOpen()) { + if (_vm->_currentVolumeFile.isOpen()) { freeDisk(); } @@ -99,16 +99,16 @@ int getVolumeDataEntry(volumeDataStruct *entry) { strcpy(buffer, entry->ident); - currentVolumeFile.open(buffer); + _vm->_currentVolumeFile.open(buffer); - if (!currentVolumeFile.isOpen()) { + if (!_vm->_currentVolumeFile.isOpen()) { return (-14); } changeCursor(CURSOR_DISK); - volumeNumberOfEntry = currentVolumeFile.readSint16BE(); - volumeSizeOfEntry = currentVolumeFile.readSint16BE(); + volumeNumberOfEntry = _vm->_currentVolumeFile.readSint16BE(); + volumeSizeOfEntry = _vm->_currentVolumeFile.readSint16BE(); volumeNumEntry = volumeNumberOfEntry; @@ -125,11 +125,11 @@ int getVolumeDataEntry(volumeDataStruct *entry) { } for (i = 0; i < volumeNumEntry; i++) { - currentVolumeFile.read(&volumePtrToFileDescriptor[i].name, 14); - volumePtrToFileDescriptor[i].offset = currentVolumeFile.readSint32BE(); - volumePtrToFileDescriptor[i].size = currentVolumeFile.readSint32BE(); - volumePtrToFileDescriptor[i].extSize = currentVolumeFile.readSint32BE(); - volumePtrToFileDescriptor[i].unk3 = currentVolumeFile.readSint32BE(); + _vm->_currentVolumeFile.read(&volumePtrToFileDescriptor[i].name, 14); + volumePtrToFileDescriptor[i].offset = _vm->_currentVolumeFile.readSint32BE(); + volumePtrToFileDescriptor[i].size = _vm->_currentVolumeFile.readSint32BE(); + volumePtrToFileDescriptor[i].extSize = _vm->_currentVolumeFile.readSint32BE(); + volumePtrToFileDescriptor[i].unk3 = _vm->_currentVolumeFile.readSint32BE(); } strcpy(currentBaseName, entry->ident); @@ -178,8 +178,8 @@ int32 findFileInDisksSub1(const char *fileName) { } void freeDisk() { - if (currentVolumeFile.isOpen()) { - currentVolumeFile.close(); + if (_vm->_currentVolumeFile.isOpen()) { + _vm->_currentVolumeFile.close(); MemFree(volumePtrToFileDescriptor); } @@ -194,7 +194,7 @@ void freeDisk() { int16 findFileInList(char *fileName) { int i; - if (!currentVolumeFile.isOpen()) { + if (!_vm->_currentVolumeFile.isOpen()) { return (-1); } @@ -248,7 +248,7 @@ int16 findFileInDisks(const char *name) { if (!volumeDataLoaded) { debug(1, "CNF wasn't loaded, reading now..."); - if (currentVolumeFile.isOpen()) { + if (_vm->_currentVolumeFile.isOpen()) { askDisk(-1); freeDisk(); } @@ -257,7 +257,7 @@ int16 findFileInDisks(const char *name) { readVolCnf(); } - if (currentVolumeFile.isOpen()) { + if (_vm->_currentVolumeFile.isOpen()) { askDisk(-1); } @@ -274,7 +274,7 @@ int16 findFileInDisks(const char *name) { debug(1, "File found on disk %d", disk); - if (currentVolumeFile.isOpen()) { + if (_vm->_currentVolumeFile.isOpen()) { askDisk(-1); } diff --git a/engines/gob/demos/demoplayer.cpp b/engines/gob/demos/demoplayer.cpp index 38e20a46ee..25cd470f04 100644 --- a/engines/gob/demos/demoplayer.cpp +++ b/engines/gob/demos/demoplayer.cpp @@ -152,12 +152,13 @@ void DemoPlayer::playVideo(const char *fileName) { debugC(1, kDebugDemo, "Playing video \"%s\"", file); - int16 x = _rebase0 ? 0 : -1; - int16 y = _rebase0 ? 0 : -1; - if (_vm->_vidPlayer->primaryOpen(file, x, y)) { - bool videoSupportsDouble = - ((_vm->_vidPlayer->getFeatures() & Graphics::CoktelVideo::kFeaturesSupportsDouble) != 0); + VideoPlayer::Properties props; + props.x = _rebase0 ? 0 : -1; + props.y = _rebase0 ? 0 : -1; + + int slot; + if ((slot = _vm->_vidPlayer->openVideo(true, file, props)) >= 0) { if (_autoDouble) { int16 defX = _rebase0 ? 0 : _vm->_vidPlayer->getDefaultX(); int16 defY = _rebase0 ? 0 : _vm->_vidPlayer->getDefaultY(); @@ -167,16 +168,12 @@ void DemoPlayer::playVideo(const char *fileName) { _doubleMode = ((right < 320) && (bottom < 200)); } - if (_doubleMode) { - if (videoSupportsDouble) { - _vm->_vidPlayer->slotSetDoubleMode(-1, true); - playVideoNormal(); - } else - playVideoDoubled(); - } else - playVideoNormal(); + if (_doubleMode) + playVideoDoubled(slot); + else + playVideoNormal(slot); - _vm->_vidPlayer->primaryClose(); + _vm->_vidPlayer->closeVideo(slot); if (waitTime > 0) _vm->_util->longDelay(waitTime); @@ -210,51 +207,67 @@ void DemoPlayer::playADL(const char *params) { playADL(fileName, waitEsc, repeat); } -void DemoPlayer::playVideoNormal() { - _vm->_vidPlayer->primaryPlay(); +void DemoPlayer::playVideoNormal(int slot) { + VideoPlayer::Properties props; + + _vm->_vidPlayer->play(slot, props); } -void DemoPlayer::playVideoDoubled() { - Common::String fileNameOpened = _vm->_vidPlayer->getFileName(); - _vm->_vidPlayer->primaryClose(); +void DemoPlayer::playVideoDoubled(int slot) { + Common::String fileNameOpened = _vm->_vidPlayer->getFileName(slot); + _vm->_vidPlayer->closeVideo(slot); - int16 x = _rebase0 ? 0 : -1; - int16 y = _rebase0 ? 0 : -1; - if (_vm->_vidPlayer->primaryOpen(fileNameOpened.c_str(), x, y, - VideoPlayer::kFlagScreenSurface)) { + VideoPlayer::Properties props; - for (int i = 0; i < _vm->_vidPlayer->getFramesCount(); i++) { - _vm->_vidPlayer->playFrame(i); + props.x = _rebase0 ? 0 : -1; + props.y = _rebase0 ? 0 : -1; + props.flags = VideoPlayer::kFlagScreenSurface; + props.waitEndFrame = false; - Graphics::CoktelVideo::State state = _vm->_vidPlayer->getState(); + _vm->_vidPlayer->evaluateFlags(props); + + slot = _vm->_vidPlayer->openVideo(true, fileNameOpened, props); + if (slot < 0) + return; - int16 w = state.right - state.left + 1; - int16 h = state.bottom - state.top + 1; - int16 wD = (state.left * 2) + (w * 2); - int16 hD = (state.top * 2) + (h * 2); + for (uint i = 0; i < _vm->_vidPlayer->getFrameCount(slot); i++) { + props.startFrame = _vm->_vidPlayer->getCurrentFrame(slot) + 1; + props.lastFrame = _vm->_vidPlayer->getCurrentFrame(slot) + 1; + + _vm->_vidPlayer->play(slot, props); + + const Common::List<Common::Rect> *rects = _vm->_vidPlayer->getDirtyRects(slot); + if (rects) { + for (Common::List<Common::Rect>::const_iterator rect = rects->begin(); rect != rects->end(); ++rect) { + int16 w = rect->right - rect->left; + int16 h = rect->bottom - rect->top; + int16 wD = (rect->left * 2) + (w * 2); + int16 hD = (rect->top * 2) + (h * 2); _vm->_video->drawSpriteDouble(*_vm->_draw->_spritesArray[0], *_vm->_draw->_frontSurface, - state.left, state.top, state.right, state.bottom, state.left, state.top, 0); + rect->left, rect->top, rect->right - 1, rect->bottom - 1, rect->left, rect->top, 0); _vm->_draw->dirtiedRect(_vm->_draw->_frontSurface, - state.left * 2, state.top * 2, wD, hD); - _vm->_video->retrace(); + rect->left * 2, rect->top * 2, wD, hD); + } + } - _vm->_util->processInput(); - if (_vm->shouldQuit()) - break; + _vm->_video->retrace(); - int16 key; - bool end = false; - while (_vm->_util->checkKey(key)) - if (key == kKeyEscape) - end = true; - if (end) - break; + _vm->_util->processInput(); + if (_vm->shouldQuit()) + break; - _vm->_vidPlayer->slotWaitEndFrame(); + int16 key; + bool end = false; + while (_vm->_util->checkKey(key)) + if (key == kKeyEscape) + end = true; + if (end) + break; - } + _vm->_vidPlayer->waitEndFrame(slot); } + } void DemoPlayer::playADL(const Common::String &fileName, bool waitEsc, int32 repeat) { diff --git a/engines/gob/demos/demoplayer.h b/engines/gob/demos/demoplayer.h index f0672b9645..207b050363 100644 --- a/engines/gob/demos/demoplayer.h +++ b/engines/gob/demos/demoplayer.h @@ -59,8 +59,8 @@ protected: void playVideo(const char *fileName); void playADL(const char *params); - void playVideoNormal(); - void playVideoDoubled(); + void playVideoNormal(int slot); + void playVideoDoubled(int slot); void playADL(const Common::String &fileName, bool waitEsc = true, int32 repeat = -1); private: diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp index ff6d558998..b572ccb566 100644 --- a/engines/gob/draw.cpp +++ b/engines/gob/draw.cpp @@ -538,8 +538,6 @@ void Draw::activeWin(int16 id) { SurfaceDescPtr tempSrf; SurfaceDescPtr oldSrf[10]; - warning ("activeWindow %d", id); - if (_fascinWin[id].id == -1) return; @@ -682,9 +680,8 @@ int16 Draw::openWin(int16 id) { _fascinWin[id].top = VAR((_winVarArrayTop / 4) + id); _fascinWin[id].width = VAR((_winVarArrayWidth / 4) + id); _fascinWin[id].height = VAR((_winVarArrayHeight / 4) + id); - _fascinWin[id].savedSurface = _vm->_video->initSurfDesc(_vm->_global->_videoMode, _winMaxWidth + 7, _winMaxHeight, 0); - warning("Draw::openWin id %d- left %d top %d l %d h%d", id, _fascinWin[id].left, _fascinWin[id].top, _fascinWin[id].width, _fascinWin[id].height); + _fascinWin[id].savedSurface = _vm->_video->initSurfDesc(_vm->_global->_videoMode, _winMaxWidth + 7, _winMaxHeight, 0); saveWin(id); WRITE_VAR((_winVarArrayStatus / 4) + id, VAR((_winVarArrayStatus / 4) + id) & 0xFFFFFFFE); @@ -693,7 +690,6 @@ int16 Draw::openWin(int16 id) { } void Draw::restoreWin(int16 i) { - warning("restoreWin"); _vm->_video->drawSprite(*_fascinWin[i].savedSurface, *_backSurface, _fascinWin[i].left & 7, 0, (_fascinWin[i].left & 7) + _fascinWin[i].width - 1, _fascinWin[i].height - 1, @@ -704,7 +700,6 @@ void Draw::restoreWin(int16 i) { } void Draw::saveWin(int16 id) { - warning("saveWin"); _vm->_video->drawSprite(*_backSurface, *_fascinWin[id].savedSurface, _fascinWin[id].left, _fascinWin[id].top, _fascinWin[id].left + _fascinWin[id].width - 1, @@ -765,7 +760,6 @@ void Draw::handleWinBorder(int16 id) { int16 maxX = 320; int16 minY = 0; int16 maxY = 200; - warning("handleWinBorder %d", id); if (VAR((_winVarArrayStatus / 4) + id) & 8) minX = (int16)(VAR((_winVarArrayLimitsX / 4) + id) >> 16L); @@ -884,8 +878,6 @@ int16 Draw::handleCurWin() { } void Draw::winDecomp(int16 x, int16 y, SurfaceDescPtr destPtr) { - warning("winDecomp %d %d - getResource %d %d %d", x, y, _spriteLeft, _spriteRight, _spriteBottom); - Resource *resource; resource = _vm->_game->_resources->getResource((uint16) _spriteLeft, &_spriteRight, &_spriteBottom); @@ -906,15 +898,13 @@ void Draw::winDraw(int16 fct) { int16 width; int16 height; - warning("winDraw %d", fct); - bool found = false; int len; Resource *resource; int table[10]; SurfaceDescPtr tempSrf; - if (_destSurface == 21) { + if (_destSurface == kBackSurface) { if (_vm->_global->_curWinId) { if (_fascinWin[_vm->_global->_curWinId].id == -1) @@ -1032,7 +1022,7 @@ void Draw::winDraw(int16 fct) { table[_fascinWin[i].id] = i; } - if ((_sourceSurface == 21) && (fct == 0)) { + if ((_sourceSurface == kBackSurface) && (fct == 0)) { _vm->_video->drawSprite(*_spritesArray[_sourceSurface], *_spritesArray[_destSurface], _spriteLeft, _spriteTop, _spriteLeft + _spriteRight - 1, _spriteTop + _spriteBottom - 1, _destSpriteX, _destSpriteY, _transparency); @@ -1267,11 +1257,11 @@ void Draw::winDraw(int16 fct) { } if (_renderFlags & 16) { - if (_sourceSurface == 21) { + if (_sourceSurface == kBackSurface) { _spriteLeft -= _backDeltaX; _spriteTop -= _backDeltaY; } - if (_destSurface == 21) { + if (_destSurface == kBackSurface) { _destSpriteX -= _backDeltaX; _destSpriteY -= _backDeltaY; } @@ -1323,9 +1313,9 @@ void Draw::forceBlit(bool backwards) { return; if (_frontSurface == _backSurface) return; - if (_spritesArray[20] != _frontSurface) + if (_spritesArray[kFrontSurface] != _frontSurface) return; - if (_spritesArray[21] != _backSurface) + if (_spritesArray[kBackSurface] != _backSurface) return; if (!backwards) { diff --git a/engines/gob/draw.h b/engines/gob/draw.h index 8997c53362..fa3cbb84cc 100644 --- a/engines/gob/draw.h +++ b/engines/gob/draw.h @@ -45,7 +45,12 @@ namespace Gob { class Draw { public: - static const int kFontCount = 8; + static const int kFontCount = 8; + static const int kFrontSurface = 20; + static const int kBackSurface = 21; + static const int kAnimSurface = 22; + static const int kCursorSurface = 23; + static const int kCaptureSurface = 30; struct FontToSprite { int8 sprite; diff --git a/engines/gob/draw_fascin.cpp b/engines/gob/draw_fascin.cpp index 9d30faa972..1e01db7dfb 100644 --- a/engines/gob/draw_fascin.cpp +++ b/engines/gob/draw_fascin.cpp @@ -53,12 +53,12 @@ void Draw_Fascination::spriteOperation(int16 operation) { _destSurface -= 80; if ((_renderFlags & RENDERFLAG_USEDELTAS) && !deltaVeto) { - if ((_sourceSurface == 21) && (operation != DRAW_LOADSPRITE)) { + if ((_sourceSurface == kBackSurface) && (operation != DRAW_LOADSPRITE)) { _spriteLeft += _backDeltaX; _spriteTop += _backDeltaY; } - if (_destSurface == 21) { + if (_destSurface == kBackSurface) { _destSpriteX += _backDeltaX; _destSpriteY += _backDeltaY; if ((operation == DRAW_DRAWLINE) || @@ -70,7 +70,7 @@ void Draw_Fascination::spriteOperation(int16 operation) { } if (_renderFlags & 0x20) { - if (_destSurface == 21 || (operation == 0 && _sourceSurface == 21)) { + if (_destSurface == kBackSurface || (operation == 0 && _sourceSurface == kBackSurface)) { winDraw(operation); return; } @@ -86,7 +86,7 @@ void Draw_Fascination::spriteOperation(int16 operation) { int16 destSurface = _destSurface; int16 sourceSurface = _sourceSurface; - if (_vm->_video->_splitSurf && ((_destSurface == 20) || (_destSurface == 21))) { + if (_vm->_video->_splitSurf && ((_destSurface == kFrontSurface) || (_destSurface == kBackSurface))) { if ((_destSpriteY >= _vm->_video->_splitStart)) { _destSpriteY -= _vm->_video->_splitStart; if ((operation == DRAW_DRAWLINE) || @@ -340,12 +340,12 @@ void Draw_Fascination::spriteOperation(int16 operation) { } if ((_renderFlags & RENDERFLAG_USEDELTAS) && !deltaVeto) { - if (_sourceSurface == 21) { + if (_sourceSurface == kBackSurface) { _spriteLeft -= _backDeltaX; _spriteTop -= _backDeltaY; } - if (_destSurface == 21) { + if (_destSurface == kBackSurface) { _destSpriteX -= _backDeltaX; _destSpriteY -= _backDeltaY; } diff --git a/engines/gob/draw_playtoons.cpp b/engines/gob/draw_playtoons.cpp index 862cdd33eb..583d13986e 100644 --- a/engines/gob/draw_playtoons.cpp +++ b/engines/gob/draw_playtoons.cpp @@ -53,12 +53,12 @@ void Draw_Playtoons::spriteOperation(int16 operation) { _destSurface -= 80; if ((_renderFlags & RENDERFLAG_USEDELTAS) && !deltaVeto) { - if ((_sourceSurface == 21) && (operation != DRAW_LOADSPRITE)) { + if ((_sourceSurface == kBackSurface) && (operation != DRAW_LOADSPRITE)) { _spriteLeft += _backDeltaX; _spriteTop += _backDeltaY; } - if (_destSurface == 21) { + if (_destSurface == kBackSurface) { _destSpriteX += _backDeltaX; _destSpriteY += _backDeltaY; if ((operation == DRAW_DRAWLINE) || @@ -78,7 +78,7 @@ void Draw_Playtoons::spriteOperation(int16 operation) { int16 destSurface = _destSurface; int16 sourceSurface = _sourceSurface; - if (_vm->_video->_splitSurf && ((_destSurface == 20) || (_destSurface == 21))) { + if (_vm->_video->_splitSurf && ((_destSurface == kFrontSurface) || (_destSurface == kBackSurface))) { if ((_destSpriteY >= _vm->_video->_splitStart)) { _destSpriteY -= _vm->_video->_splitStart; if ((operation == DRAW_DRAWLINE) || @@ -409,12 +409,12 @@ void Draw_Playtoons::spriteOperation(int16 operation) { } if ((_renderFlags & RENDERFLAG_USEDELTAS) && !deltaVeto) { - if (_sourceSurface == 21) { + if (_sourceSurface == kBackSurface) { _spriteLeft -= _backDeltaX; _spriteTop -= _backDeltaY; } - if (_destSurface == 21) { + if (_destSurface == kBackSurface) { _destSpriteX -= _backDeltaX; _destSpriteY -= _backDeltaY; } diff --git a/engines/gob/draw_v1.cpp b/engines/gob/draw_v1.cpp index 719945fd6f..1cec15ce04 100644 --- a/engines/gob/draw_v1.cpp +++ b/engines/gob/draw_v1.cpp @@ -184,7 +184,7 @@ void Draw_v1::printTotText(int16 id) { _destSpriteY = destY; _spriteRight = spriteRight; _spriteBottom = spriteBottom; - _destSurface = 21; + _destSurface = kBackSurface; _backColor = *ptr++; _transparency = 1; @@ -326,12 +326,12 @@ void Draw_v1::spriteOperation(int16 operation) { _destSurface -= 80; if (_renderFlags & RENDERFLAG_USEDELTAS) { - if (_sourceSurface == 21) { + if (_sourceSurface == kBackSurface) { _spriteLeft += _backDeltaX; _spriteTop += _backDeltaY; } - if (_destSurface == 21) { + if (_destSurface == kBackSurface) { _destSpriteX += _backDeltaX; _destSpriteY += _backDeltaY; if ((operation == DRAW_DRAWLINE) || @@ -508,12 +508,12 @@ void Draw_v1::spriteOperation(int16 operation) { } if (_renderFlags & RENDERFLAG_USEDELTAS) { - if (_sourceSurface == 21) { + if (_sourceSurface == kBackSurface) { _spriteLeft -= _backDeltaX; _spriteTop -= _backDeltaY; } - if (_destSurface == 21) { + if (_destSurface == kBackSurface) { _destSpriteX -= _backDeltaX; _destSpriteY -= _backDeltaY; } diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp index 985f84aaef..5d001f4b59 100644 --- a/engines/gob/draw_v2.cpp +++ b/engines/gob/draw_v2.cpp @@ -51,30 +51,30 @@ void Draw_v2::initScreen() { _scrollOffsetX = 0; _scrollOffsetY = 0; - initSpriteSurf(21, _vm->_video->_surfWidth, _vm->_video->_surfHeight, 0); - _backSurface = _spritesArray[21]; + initSpriteSurf(kBackSurface, _vm->_video->_surfWidth, _vm->_video->_surfHeight, 0); + _backSurface = _spritesArray[kBackSurface]; _vm->_video->clearSurf(*_backSurface); - if (!_spritesArray[23]) { - initSpriteSurf(23, 32, 16, 2); - _cursorSpritesBack = _spritesArray[23]; + if (!_spritesArray[kCursorSurface]) { + initSpriteSurf(kCursorSurface, 32, 16, 2); + _cursorSpritesBack = _spritesArray[kCursorSurface]; _cursorSprites = _cursorSpritesBack; _scummvmCursor = _vm->_video->initSurfDesc(_vm->_global->_videoMode, 16, 16, SCUMMVM_CURSOR); } - _spritesArray[20] = _frontSurface; - _spritesArray[21] = _backSurface; + _spritesArray[kFrontSurface] = _frontSurface; + _spritesArray[kBackSurface ] = _backSurface; _vm->_video->dirtyRectsAll(); } void Draw_v2::closeScreen() { - //freeSprite(23); + //freeSprite(kCursorSurface); //_cursorSprites = 0; //_cursorSpritesBack = 0; //_scummvmCursor = 0; - freeSprite(21); + freeSprite(kBackSurface); } void Draw_v2::blitCursor() { @@ -273,7 +273,7 @@ void Draw_v2::printTotText(int16 id) { _destSpriteY = destY; _spriteRight = spriteRight; _spriteBottom = spriteBottom; - _destSurface = 21; + _destSurface = kBackSurface; _backColor = *ptr++; _transparency = 1; @@ -629,12 +629,12 @@ void Draw_v2::spriteOperation(int16 operation) { _destSurface -= 80; if ((_renderFlags & RENDERFLAG_USEDELTAS) && !deltaVeto) { - if ((_sourceSurface == 21) && (operation != DRAW_LOADSPRITE)) { + if ((_sourceSurface == kBackSurface) && (operation != DRAW_LOADSPRITE)) { _spriteLeft += _backDeltaX; _spriteTop += _backDeltaY; } - if (_destSurface == 21) { + if (_destSurface == kBackSurface) { _destSpriteX += _backDeltaX; _destSpriteY += _backDeltaY; if ((operation == DRAW_DRAWLINE) || @@ -654,7 +654,7 @@ void Draw_v2::spriteOperation(int16 operation) { int16 destSurface = _destSurface; int16 sourceSurface = _sourceSurface; - if (_vm->_video->_splitSurf && ((_destSurface == 20) || (_destSurface == 21))) { + if (_vm->_video->_splitSurf && ((_destSurface == kFrontSurface) || (_destSurface == kBackSurface))) { if ((_destSpriteY >= _vm->_video->_splitStart)) { _destSpriteY -= _vm->_video->_splitStart; if ((operation == DRAW_DRAWLINE) || @@ -908,12 +908,12 @@ void Draw_v2::spriteOperation(int16 operation) { } if ((_renderFlags & RENDERFLAG_USEDELTAS) && !deltaVeto) { - if (_sourceSurface == 21) { + if (_sourceSurface == kBackSurface) { _spriteLeft -= _backDeltaX; _spriteTop -= _backDeltaY; } - if (_destSurface == 21) { + if (_destSurface == kBackSurface) { _destSpriteX -= _backDeltaX; _destSpriteY -= _backDeltaY; } diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp index ddf095a5d1..1a8823b156 100644 --- a/engines/gob/game.cpp +++ b/engines/gob/game.cpp @@ -286,8 +286,8 @@ void Game::playTot(int16 skipPlay) { _vm->_mult->initAll(); _vm->_mult->zeroMultData(); - _vm->_draw->_spritesArray[20] = _vm->_draw->_frontSurface; - _vm->_draw->_spritesArray[21] = _vm->_draw->_backSurface; + _vm->_draw->_spritesArray[Draw::kFrontSurface] = _vm->_draw->_frontSurface; + _vm->_draw->_spritesArray[Draw::kBackSurface ] = _vm->_draw->_backSurface; _vm->_draw->_cursorSpritesBack = _vm->_draw->_cursorSprites; } else _vm->_inter->initControlVars(0); @@ -299,7 +299,7 @@ void Game::playTot(int16 skipPlay) { break; if (skipPlay == -2) { - _vm->_vidPlayer->primaryClose(); + _vm->_vidPlayer->closeVideo(); skipPlay = 0; } @@ -397,10 +397,10 @@ void Game::capturePush(int16 left, int16 top, int16 width, int16 height) { left &= 0xFFF0; right |= 0xF; - _vm->_draw->initSpriteSurf(30 + _captureCount, right - left + 1, height, 0); + _vm->_draw->initSpriteSurf(Draw::kCaptureSurface + _captureCount, right - left + 1, height, 0); - _vm->_draw->_sourceSurface = 21; - _vm->_draw->_destSurface = 30 + _captureCount; + _vm->_draw->_sourceSurface = Draw::kBackSurface; + _vm->_draw->_destSurface = Draw::kCaptureSurface + _captureCount; _vm->_draw->_spriteLeft = left; _vm->_draw->_spriteRight = right - left + 1; @@ -425,13 +425,13 @@ void Game::capturePop(char doDraw) { _captureStack[_captureCount].height(); _vm->_draw->_transparency = 0; - _vm->_draw->_sourceSurface = 30 + _captureCount; - _vm->_draw->_destSurface = 21; + _vm->_draw->_sourceSurface = Draw::kCaptureSurface + _captureCount; + _vm->_draw->_destSurface = Draw::kBackSurface; _vm->_draw->_spriteLeft = _vm->_draw->_destSpriteX & 0xF; _vm->_draw->_spriteTop = 0; _vm->_draw->spriteOperation(0); } - _vm->_draw->freeSprite(30 + _captureCount); + _vm->_draw->freeSprite(Draw::kCaptureSurface + _captureCount); } void Game::freeSoundSlot(int16 slot) { diff --git a/engines/gob/hotspots.cpp b/engines/gob/hotspots.cpp index abdf513393..1edb7fc0cb 100644 --- a/engines/gob/hotspots.cpp +++ b/engines/gob/hotspots.cpp @@ -257,7 +257,7 @@ uint16 Hotspots::add(const Hotspot &hotspot) { // Remember the current script spot.script = _vm->_game->_script; - debugC(1, kDebugHotspots, "Adding hotspot %03d: %3d+%3d+%3d+%3d - %04X, %04X, %04X - %5d, %5d, %5d", + debugC(1, kDebugHotspots, "Adding hotspot %03d: Coord:%3d+%3d+%3d+%3d - id:%04X, key:%04X, flag:%04X - fcts:%5d, %5d, %5d", i, spot.left, spot.top, spot.right, spot.bottom, spot.id, spot.key, spot.flags, spot.funcEnter, spot.funcLeave, spot.funcPos); @@ -537,10 +537,12 @@ int16 Hotspots::curWindow(int16 &dx, int16 &dy) const { if (_vm->_global->_inter_mouseX < _vm->_draw->_fascinWin[i].left + 12 && _vm->_global->_inter_mouseY < _vm->_draw->_fascinWin[i].top + 12 && (VAR((_vm->_draw->_winVarArrayStatus / 4) + i) & 2)) + // Cursor on 'Close Window' return(5); if (_vm->_global->_inter_mouseX >= _vm->_draw->_fascinWin[i].left + _vm->_draw->_fascinWin[i].width - 12 && _vm->_global->_inter_mouseY < _vm->_draw->_fascinWin[i].top + 12 && (VAR((_vm->_draw->_winVarArrayStatus / 4) + i) & 4)) + // Cursor on 'Move Window' return(6); return(-i); } @@ -637,7 +639,6 @@ uint16 Hotspots::checkMouse(Type type, uint16 &id, uint16 &index) const { return kKeyEscape; return 0; - } return 0; @@ -798,11 +799,11 @@ uint16 Hotspots::check(uint8 handleMouse, int16 delay, uint16 &id, uint16 &index if (isValid(_currentKey, _currentId, _currentIndex)) enter(_currentIndex); } else { - WRITE_VAR(16, (int32) i); + WRITE_VAR(16, (int32)i); if (id) - id=0; + id = 0; if (index) - index=0; + index = 0; return(0); } } else @@ -1104,7 +1105,6 @@ uint16 Hotspots::updateInput(uint16 xPos, uint16 yPos, uint16 width, uint16 heig // Add character _vm->_util->insertStr(tempStr, str, pos - 1); } - } } } @@ -1204,13 +1204,13 @@ void Hotspots::evaluateNew(uint16 i, uint16 *ids, InputDesc *inputs, // Type and window byte type = _vm->_game->_script->readByte(); - byte window = 0; + byte windowNum = 0; if ((type & 0x40) != 0) { // Got a window ID type -= 0x40; - window = _vm->_game->_script->readByte(); + windowNum = _vm->_game->_script->readByte(); } // Coordinates @@ -1238,21 +1238,21 @@ void Hotspots::evaluateNew(uint16 i, uint16 *ids, InputDesc *inputs, _vm->_draw->_invalidatedRights[0] = 319; _vm->_draw->_invalidatedBottoms[0] = 199; _vm->_draw->_invalidatedCount = 1; - if (window == 0) { + if (windowNum == 0) { _vm->_video->drawLine(*_vm->_draw->_spritesArray[_vm->_draw->_destSurface], left + width - 1, top, left + width - 1, top + height - 1, 0); _vm->_video->drawLine(*_vm->_draw->_spritesArray[_vm->_draw->_destSurface], left, top, left, top + height - 1, 0); _vm->_video->drawLine(*_vm->_draw->_spritesArray[_vm->_draw->_destSurface], left, top, left + width - 1, top, 0); _vm->_video->drawLine(*_vm->_draw->_spritesArray[_vm->_draw->_destSurface], left, top + height - 1, left + width - 1, top + height - 1, 0); } else - if ((_vm->_draw->_fascinWin[window].id != -1) && (_vm->_draw->_fascinWin[window].id == _vm->_draw->_winCount - 1)) { - left += _vm->_draw->_fascinWin[window].left; - top += _vm->_draw->_fascinWin[window].top; + if ((_vm->_draw->_fascinWin[windowNum].id != -1) && (_vm->_draw->_fascinWin[windowNum].id == _vm->_draw->_winCount - 1)) { + left += _vm->_draw->_fascinWin[windowNum].left; + top += _vm->_draw->_fascinWin[windowNum].top; _vm->_video->drawLine(*_vm->_draw->_spritesArray[_vm->_draw->_destSurface], left + width - 1, top, left + width - 1, top + height - 1, 0); _vm->_video->drawLine(*_vm->_draw->_spritesArray[_vm->_draw->_destSurface], left, top, left, top + height - 1, 0); _vm->_video->drawLine(*_vm->_draw->_spritesArray[_vm->_draw->_destSurface], left, top, left + width - 1, top, 0); _vm->_video->drawLine(*_vm->_draw->_spritesArray[_vm->_draw->_destSurface], left, top + height - 1, left + width - 1, top + height - 1, 0); - left -= _vm->_draw->_fascinWin[window].left; - top -= _vm->_draw->_fascinWin[window].top; + left -= _vm->_draw->_fascinWin[windowNum].left; + top -= _vm->_draw->_fascinWin[windowNum].top; } } type &= 0x7F; @@ -1296,6 +1296,9 @@ void Hotspots::evaluateNew(uint16 i, uint16 *ids, InputDesc *inputs, Font *font = 0; uint32 funcEnter = 0, funcLeave = 0; + if ((windowNum != 0) && (type != 0) && (type != 2)) + warning("evaluateNew - type %d, win %d\n",type, windowNum); + // Evaluate parameters for the new hotspot switch (type) { case kTypeNone: @@ -1308,7 +1311,7 @@ void Hotspots::evaluateNew(uint16 i, uint16 *ids, InputDesc *inputs, _vm->_game->_script->skipBlock(); key = i + ((kStateFilled | kStateType2) << 12); - flags = type + (window << 8); + flags = type + (windowNum << 8); break; case kTypeMove: @@ -1325,7 +1328,7 @@ void Hotspots::evaluateNew(uint16 i, uint16 *ids, InputDesc *inputs, if (key == 0) key = i + ((kStateFilled | kStateType2) << 12); - flags = type + (window << 8) + (flags << 4); + flags = type + (windowNum << 8) + (flags << 4); break; case kTypeInput1NoLeave: @@ -1390,12 +1393,15 @@ void Hotspots::evaluateNew(uint16 i, uint16 *ids, InputDesc *inputs, ids[i] = _vm->_game->_script->readInt16(); flags = _vm->_game->_script->readInt16(); + if (flags > 3) + warning("evaluateNew: Warning, use of type 2 or 20. flags = %d, should be %d\n", flags, flags&3); + funcEnter = 0; funcLeave = _vm->_game->_script->pos(); _vm->_game->_script->skipBlock(); - flags = ((uint16) kTypeClick) + (window << 8) + (flags << 4); + flags = ((uint16) kTypeClick) + (windowNum << 8) + (flags << 4); break; case kTypeClickEnter: @@ -1408,7 +1414,7 @@ void Hotspots::evaluateNew(uint16 i, uint16 *ids, InputDesc *inputs, funcLeave = 0; - flags = ((uint16) kTypeClick) + (window << 8) + (flags << 4); + flags = ((uint16) kTypeClick) + (windowNum << 8) + (flags << 4); break; } @@ -1418,8 +1424,10 @@ void Hotspots::evaluateNew(uint16 i, uint16 *ids, InputDesc *inputs, } bool Hotspots::evaluateFind(uint16 key, int16 timeVal, const uint16 *ids, - uint16 hotspotIndex1, uint16 hotspotIndex2, uint16 endIndex, - int16 &duration, uint16 &id, uint16 &index, bool &finished) { + uint16 leaveWindowIndex, uint16 hotspotIndex1, uint16 hotspotIndex2, + uint16 endIndex, int16 &duration, uint16 &id, uint16 &index, bool &finished) { + + bool fascinCheck = false; if (id != 0) // We already found a hotspot, nothing to do @@ -1442,8 +1450,10 @@ bool Hotspots::evaluateFind(uint16 key, int16 timeVal, const uint16 *ids, return false; } + if ((_vm->getGameType() == kGameTypeFascination) && (getCurrentHotspot())) + fascinCheck = true; - if (duration != 0) { + if ((duration != 0) && (!fascinCheck)) { // We've got a time duration if (hotspotIndex1 != 0) { @@ -1473,6 +1483,12 @@ bool Hotspots::evaluateFind(uint16 key, int16 timeVal, const uint16 *ids, return true; return false; + } else { + if (leaveWindowIndex != 0) + findNthPlain(leaveWindowIndex, endIndex, id, index); + + if (id != 0) + return true; } return false; @@ -1500,6 +1516,11 @@ void Hotspots::evaluate() { // Parameters of this block _vm->_game->_handleMouse = _vm->_game->_script->peekByte(0); int16 duration = _vm->_game->_script->peekByte(1); + + byte leaveWindowIndex = 0; + if ( _vm->getGameType() == kGameTypeFascination ) + leaveWindowIndex = _vm->_game->_script->peekByte(2); + byte hotspotIndex1 = _vm->_game->_script->peekByte(3); byte hotspotIndex2 = _vm->_game->_script->peekByte(4); bool needRecalculation = _vm->_game->_script->peekByte(5) != 0; @@ -1562,7 +1583,7 @@ void Hotspots::evaluate() { key = convertSpecialKey(key); // Try to find a fitting hotspot - Hotspots::evaluateFind(key, timeVal, ids, hotspotIndex1, hotspotIndex2, endIndex, + evaluateFind(key, timeVal, ids, leaveWindowIndex, hotspotIndex1, hotspotIndex2, endIndex, duration, id, index, finishedDuration); if (finishedDuration) @@ -1623,9 +1644,9 @@ int16 Hotspots::findCursor(uint16 x, uint16 y) const { int16 deltax = 0; int16 deltay = 0; - if ( _vm->getGameType() == kGameTypeFascination ) { + if ( _vm->getGameType() == kGameTypeFascination ) cursor = curWindow(deltax, deltay); - } + if (cursor == 0) { for (int i = 0; (i < kHotspotCount) && !_hotspots[i].isEnd(); i++) { const Hotspot &spot = _hotspots[i]; @@ -2082,7 +2103,7 @@ void Hotspots::getTextCursorPos(const Font &font, const char *str, } void Hotspots::fillRect(uint16 x, uint16 y, uint16 width, uint16 height, uint16 color) const { - _vm->_draw->_destSurface = 21; + _vm->_draw->_destSurface = Draw::kBackSurface; _vm->_draw->_destSpriteX = x; _vm->_draw->_destSpriteY = y; _vm->_draw->_spriteRight = width; diff --git a/engines/gob/hotspots.h b/engines/gob/hotspots.h index a7cbf9d6e8..cba400d5b6 100644 --- a/engines/gob/hotspots.h +++ b/engines/gob/hotspots.h @@ -104,7 +104,6 @@ public: /** implementation of oPlaytoons_F_1B code*/ void oPlaytoons_F_1B(); - private: struct Hotspot { uint16 id; @@ -225,8 +224,8 @@ private: uint16 &inputId, bool &hasInput, uint16 &inputCount); /** Find the hotspot requested by script commands. */ bool evaluateFind(uint16 key, int16 timeVal, const uint16 *ids, - uint16 hotspotIndex1, uint16 hotspotIndex2, uint16 endIndex, - int16 &duration, uint16 &id, uint16 &index, bool &finished); + uint16 leaveWindowIndex, uint16 hotspotIndex1, uint16 hotspotIndex2, + uint16 endIndex, int16 &duration, uint16 &id, uint16 &index, bool &finished); // Finding specific hotspots /** Find the hotspot index that corresponds to the input index. */ diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp index 24a8e0a390..3da71a2ba6 100644 --- a/engines/gob/init.cpp +++ b/engines/gob/init.cpp @@ -174,9 +174,11 @@ void Init::initGame() { _vm->_util->longDelay(200); // Letting everything settle - if (_vm->_vidPlayer->primaryOpen("coktel.imd")) { - _vm->_vidPlayer->primaryPlay(); - _vm->_vidPlayer->primaryClose(); + VideoPlayer::Properties props; + int slot; + if ((slot = _vm->_vidPlayer->openVideo(true, "coktel.imd", props)) >= 0) { + _vm->_vidPlayer->play(slot, props); + _vm->_vidPlayer->closeVideo(slot); } _vm->_draw->closeScreen(); diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp index da8ca103aa..5c56196641 100644 --- a/engines/gob/inter_bargon.cpp +++ b/engines/gob/inter_bargon.cpp @@ -72,17 +72,47 @@ void Inter_Bargon::setupOpcodesGob() { } void Inter_Bargon::oBargon_intro0(OpGobParams ¶ms) { - if (_vm->_vidPlayer->primaryOpen("scaa", 0, 160)) { - _vm->_vidPlayer->primaryPlay(0, 92, 27, 0, 0, 0); - _vm->_vidPlayer->primaryClose(); - } + VideoPlayer::Properties props; + + props.x = 0; + props.y = 160; + props.startFrame = 0; + props.lastFrame = 92; + props.palCmd = 0; + props.palStart = 0; + props.palEnd = 0; + + int slot; + if ((slot = _vm->_vidPlayer->openVideo(true, "scaa", props)) < 0) + return; + + _vm->_vidPlayer->play(slot, props); + _vm->_vidPlayer->closeVideo(slot); } void Inter_Bargon::oBargon_intro1(OpGobParams ¶ms) { - if (_vm->_vidPlayer->primaryOpen("scaa", 0, 160)) { - _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0, 0, 0, true, 23); - _vm->_vidPlayer->primaryClose(); - } + VideoPlayer::Properties props; + + props.x = 0; + props.y = 160; + props.palCmd = 0; + props.palStart = 0; + props.palEnd = 0; + props.fade = true; + + int slot; + if ((slot = _vm->_vidPlayer->openVideo(true, "scaa", props)) < 0) + return; + + _vm->_vidPlayer->play(slot, props); + + props.startFrame = -1; + props.lastFrame = _vm->_vidPlayer->getFrameCount(slot) - 23; + props.fade = false; + + _vm->_vidPlayer->play(slot, props); + + _vm->_vidPlayer->closeVideo(slot); } void Inter_Bargon::oBargon_intro2(OpGobParams ¶ms) { @@ -178,45 +208,106 @@ void Inter_Bargon::oBargon_intro3(OpGobParams ¶ms) { } void Inter_Bargon::oBargon_intro4(OpGobParams ¶ms) { - if (_vm->_vidPlayer->primaryOpen("scba", 191, 54)) { - _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0, 0, 0, true); - _vm->_vidPlayer->primaryClose(); - } + VideoPlayer::Properties props; + + props.x = 191; + props.y = 54; + props.palCmd = 0; + props.palStart = 0; + props.palEnd = 0; + props.fade = true; + + int slot; + if ((slot = _vm->_vidPlayer->openVideo(true, "scba", props)) < 0) + return; + + _vm->_vidPlayer->play(slot, props); + _vm->_vidPlayer->closeVideo(slot); } void Inter_Bargon::oBargon_intro5(OpGobParams ¶ms) { - if (_vm->_vidPlayer->primaryOpen("scbb", 191, 54)) { - _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0); - _vm->_vidPlayer->primaryClose(); - } + VideoPlayer::Properties props; + + props.x = 191; + props.y = 54; + props.palCmd = 0; + props.palStart = 0; + props.palEnd = 0; + + int slot; + if ((slot = _vm->_vidPlayer->openVideo(true, "scbb", props)) < 0) + return; + + _vm->_vidPlayer->play(slot, props); + _vm->_vidPlayer->closeVideo(slot); } void Inter_Bargon::oBargon_intro6(OpGobParams ¶ms) { - if (_vm->_vidPlayer->primaryOpen("scbc", 191, 54)) { - _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0); - _vm->_vidPlayer->primaryClose(); - } + VideoPlayer::Properties props; + + props.x = 191; + props.y = 54; + props.palCmd = 0; + props.palStart = 0; + props.palEnd = 0; + + int slot; + if ((slot = _vm->_vidPlayer->openVideo(true, "scbc", props)) < 0) + return; + + _vm->_vidPlayer->play(slot, props); + _vm->_vidPlayer->closeVideo(slot); } void Inter_Bargon::oBargon_intro7(OpGobParams ¶ms) { - if (_vm->_vidPlayer->primaryOpen("scbf", 191, 54)) { - _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0); - _vm->_vidPlayer->primaryClose(); - } + VideoPlayer::Properties props; + + props.x = 191; + props.y = 54; + props.palCmd = 0; + props.palStart = 0; + props.palEnd = 0; + + int slot; + if ((slot = _vm->_vidPlayer->openVideo(true, "scbf", props)) < 0) + return; + + _vm->_vidPlayer->play(slot, props); + _vm->_vidPlayer->closeVideo(slot); } void Inter_Bargon::oBargon_intro8(OpGobParams ¶ms) { - if (_vm->_vidPlayer->primaryOpen("scbc", 191, 54)) { - _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0); - _vm->_vidPlayer->primaryClose(); - } + VideoPlayer::Properties props; + + props.x = 191; + props.y = 54; + props.palCmd = 0; + props.palStart = 0; + props.palEnd = 0; + + int slot; + if ((slot = _vm->_vidPlayer->openVideo(true, "scbc", props)) < 0) + return; + + _vm->_vidPlayer->play(slot, props); + _vm->_vidPlayer->closeVideo(slot); } void Inter_Bargon::oBargon_intro9(OpGobParams ¶ms) { - if (_vm->_vidPlayer->primaryOpen("scbd", 191, 54)) { - _vm->_vidPlayer->primaryPlay(0, -1, 27, 0, 0, 0); - _vm->_vidPlayer->primaryClose(); - } + VideoPlayer::Properties props; + + props.x = 191; + props.y = 54; + props.palCmd = 0; + props.palStart = 0; + props.palEnd = 0; + + int slot; + if ((slot = _vm->_vidPlayer->openVideo(true, "scbd", props)) < 0) + return; + + _vm->_vidPlayer->play(slot, props); + _vm->_vidPlayer->closeVideo(slot); } } // End of namespace Gob diff --git a/engines/gob/inter_fascin.cpp b/engines/gob/inter_fascin.cpp index 5738197539..304f02f4fa 100644 --- a/engines/gob/inter_fascin.cpp +++ b/engines/gob/inter_fascin.cpp @@ -131,21 +131,41 @@ bool Inter_Fascination::oFascin_copySprite(OpFuncParams ¶ms) { void Inter_Fascination::oFascin_playTirb(OpGobParams ¶ms) { warning("funcPlayImd with parameter : 'tirb.imd'"); - if (_vm->_vidPlayer->primaryOpen("tirb", 150, 88, VideoPlayer::kFlagFrontSurface, - VideoPlayer::kVideoTypePreIMD, 128, 80)) { - _vm->_vidPlayer->primaryPlay(); - _vm->_vidPlayer->primaryClose(); - } + VideoPlayer::Properties vidProps; + + vidProps.type = VideoPlayer::kVideoTypePreIMD; + vidProps.sprite = Draw::kFrontSurface; + vidProps.x = 150; + vidProps.y = 88; + vidProps.width = 128; + vidProps.height = 80; + + int vidSlot = _vm->_vidPlayer->openVideo(true, "tirb", vidProps); + if (vidSlot < 0) + return; + + _vm->_vidPlayer->play(vidSlot, vidProps); + _vm->_vidPlayer->closeVideo(vidSlot); } void Inter_Fascination::oFascin_playTira(OpGobParams ¶ms) { warning("funcPlayImd with parameter : 'tira.imd'"); - if (_vm->_vidPlayer->primaryOpen("tira", 88, 66, VideoPlayer::kFlagFrontSurface, - VideoPlayer::kVideoTypePreIMD, 128, 80)) { - _vm->_vidPlayer->primaryPlay(); - _vm->_vidPlayer->primaryClose(); - } + VideoPlayer::Properties vidProps; + + vidProps.type = VideoPlayer::kVideoTypePreIMD; + vidProps.sprite = Draw::kFrontSurface; + vidProps.x = 88; + vidProps.y = 66; + vidProps.width = 128; + vidProps.height = 80; + + int vidSlot = _vm->_vidPlayer->openVideo(true, "tira", vidProps); + if (vidSlot < 0) + return; + + _vm->_vidPlayer->play(vidSlot, vidProps); + _vm->_vidPlayer->closeVideo(vidSlot); } void Inter_Fascination::oFascin_loadExtasy(OpGobParams ¶ms) { diff --git a/engines/gob/inter_playtoons.cpp b/engines/gob/inter_playtoons.cpp index 142467b47f..befed4b1c2 100644 --- a/engines/gob/inter_playtoons.cpp +++ b/engines/gob/inter_playtoons.cpp @@ -107,7 +107,7 @@ bool Inter_Playtoons::oPlaytoons_printText(OpFuncParams ¶ms) { _vm->_draw->_backColor = _vm->_game->_script->readValExpr(); _vm->_draw->_frontColor = _vm->_game->_script->readValExpr(); _vm->_draw->_fontIndex = _vm->_game->_script->readValExpr(); - _vm->_draw->_destSurface = 21; + _vm->_draw->_destSurface = Draw::kBackSurface; _vm->_draw->_textToPrint = buf; _vm->_draw->_transparency = 0; diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index 9e841e7e68..11fe0c9c5e 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -328,7 +328,7 @@ void Inter_v1::o1_initCursor() { (height != _vm->_draw->_cursorHeight) || (_vm->_draw->_cursorSprites->getWidth() != (width * count))) { - _vm->_draw->freeSprite(23); + _vm->_draw->freeSprite(Draw::kCursorSurface); _vm->_draw->_cursorSprites.reset(); _vm->_draw->_cursorSpritesBack.reset(); _vm->_draw->_scummvmCursor.reset(); @@ -344,9 +344,9 @@ void Inter_v1::o1_initCursor() { if (count > 0x80) count -= 0x80; - _vm->_draw->initSpriteSurf(23, _vm->_draw->_cursorWidth * count, + _vm->_draw->initSpriteSurf(Draw::kCursorSurface, _vm->_draw->_cursorWidth * count, _vm->_draw->_cursorHeight, 2); - _vm->_draw->_cursorSpritesBack = _vm->_draw->_spritesArray[23]; + _vm->_draw->_cursorSpritesBack = _vm->_draw->_spritesArray[Draw::kCursorSurface]; _vm->_draw->_cursorSprites = _vm->_draw->_cursorSpritesBack; _vm->_draw->_scummvmCursor = @@ -482,14 +482,14 @@ void Inter_v1::o1_initMult() { if (_vm->_mult->_animSurf && ((oldAnimWidth != _vm->_mult->_animWidth) || (oldAnimHeight != _vm->_mult->_animHeight))) { - _vm->_draw->freeSprite(22); + _vm->_draw->freeSprite(Draw::kAnimSurface); _vm->_mult->_animSurf.reset(); } if (!_vm->_mult->_animSurf) { - _vm->_draw->initSpriteSurf(22, _vm->_mult->_animWidth, + _vm->_draw->initSpriteSurf(Draw::kAnimSurface, _vm->_mult->_animWidth, _vm->_mult->_animHeight, 0); - _vm->_mult->_animSurf = _vm->_draw->_spritesArray[22]; + _vm->_mult->_animSurf = _vm->_draw->_spritesArray[Draw::kAnimSurface]; } _vm->_video->drawSprite(*_vm->_draw->_backSurface, *_vm->_mult->_animSurf, @@ -922,7 +922,7 @@ bool Inter_v1::o1_printText(OpFuncParams ¶ms) { _vm->_draw->_backColor = _vm->_game->_script->readValExpr(); _vm->_draw->_frontColor = _vm->_game->_script->readValExpr(); _vm->_draw->_fontIndex = _vm->_game->_script->readValExpr(); - _vm->_draw->_destSurface = 21; + _vm->_draw->_destSurface = Draw::kBackSurface; _vm->_draw->_textToPrint = buf; _vm->_draw->_transparency = 0; diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index 72764eec8d..0003332e47 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -360,24 +360,24 @@ void Inter_v2::o2_initMult() { if (_vm->_mult->_animSurf && ((oldAnimWidth != _vm->_mult->_animWidth) || (oldAnimHeight != _vm->_mult->_animHeight))) { - _vm->_draw->freeSprite(22); + _vm->_draw->freeSprite(Draw::kAnimSurface); _vm->_mult->_animSurf.reset(); } _vm->_draw->adjustCoords(0, &_vm->_mult->_animWidth, &_vm->_mult->_animHeight); if (!_vm->_mult->_animSurf) { - _vm->_draw->initSpriteSurf(22, _vm->_mult->_animWidth, + _vm->_draw->initSpriteSurf(Draw::kAnimSurface, _vm->_mult->_animWidth, _vm->_mult->_animHeight, 0); - _vm->_mult->_animSurf = _vm->_draw->_spritesArray[22]; + _vm->_mult->_animSurf = _vm->_draw->_spritesArray[Draw::kAnimSurface]; if (_terminate) return; } _vm->_draw->adjustCoords(1, &_vm->_mult->_animWidth, &_vm->_mult->_animHeight); - _vm->_draw->_sourceSurface = 21; - _vm->_draw->_destSurface = 22; + _vm->_draw->_sourceSurface = Draw::kBackSurface; + _vm->_draw->_destSurface = Draw::kAnimSurface; _vm->_draw->_spriteLeft = _vm->_mult->_animLeft; _vm->_draw->_spriteTop = _vm->_mult->_animTop; _vm->_draw->_spriteRight = _vm->_mult->_animWidth; @@ -481,7 +481,7 @@ void Inter_v2::o2_loadMultObject() { if ((((int32) *(obj.pPosX)) == -1234) && (((int32) *(obj.pPosY)) == -4321)) { if (obj.videoSlot > 0) - _vm->_vidPlayer->slotClose(obj.videoSlot - 1); + _vm->_vidPlayer->closeVideo(obj.videoSlot - 1); obj.videoSlot = 0; obj.lastLeft = -1; @@ -959,50 +959,50 @@ void Inter_v2::o2_setScrollOffset() { void Inter_v2::o2_playImd() { char imd[128]; - int16 x, y; - int16 startFrame; - int16 lastFrame; - int16 breakKey; - int16 flags; - int16 palStart; - int16 palEnd; - uint16 palCmd; bool close; _vm->_game->_script->evalExpr(0); _vm->_game->_script->getResultStr()[8] = 0; strncpy0(imd, _vm->_game->_script->getResultStr(), 127); - x = _vm->_game->_script->readValExpr(); - y = _vm->_game->_script->readValExpr(); - startFrame = _vm->_game->_script->readValExpr(); - lastFrame = _vm->_game->_script->readValExpr(); - breakKey = _vm->_game->_script->readValExpr(); - flags = _vm->_game->_script->readValExpr(); - palStart = _vm->_game->_script->readValExpr(); - palEnd = _vm->_game->_script->readValExpr(); - palCmd = 1 << (flags & 0x3F); + VideoPlayer::Properties props; - debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " - "paletteCmd %d (%d - %d), flags %X", _vm->_game->_script->getResultStr(), x, y, - startFrame, lastFrame, palCmd, palStart, palEnd, flags); + props.x = _vm->_game->_script->readValExpr(); + props.y = _vm->_game->_script->readValExpr(); + props.startFrame = _vm->_game->_script->readValExpr(); + props.lastFrame = _vm->_game->_script->readValExpr(); + props.breakKey = _vm->_game->_script->readValExpr(); + props.flags = _vm->_game->_script->readValExpr(); + props.palStart = _vm->_game->_script->readValExpr(); + props.palEnd = _vm->_game->_script->readValExpr(); + props.palCmd = 1 << (props.flags & 0x3F); - if ((imd[0] != 0) && !_vm->_vidPlayer->primaryOpen(imd, x, y, flags)) { - WRITE_VAR(11, (uint32) -1); - return; + debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " + "paletteCmd %d (%d - %d), flags %X", imd, + props.x, props.y, props.startFrame, props.lastFrame, + props.palCmd, props.palStart, props.palEnd, props.flags); + + int slot = 0; + if (imd[0] != 0) { + _vm->_vidPlayer->evaluateFlags(props); + if ((slot = _vm->_vidPlayer->openVideo(true, imd, props)) < 0) { + WRITE_VAR(11, (uint32) -1); + return; + } } - close = (lastFrame == -1); - if (startFrame == -2) { - startFrame = lastFrame = 0; + close = (props.lastFrame == -1); + if (props.startFrame == -2) { + props.startFrame = 0; + props.lastFrame = 0; close = false; } - if (startFrame >= 0) - _vm->_vidPlayer->primaryPlay(startFrame, lastFrame, breakKey, palCmd, palStart, palEnd, 0); + if (props.startFrame >= 0) + _vm->_vidPlayer->play(slot, props); if (close) - _vm->_vidPlayer->primaryClose(); + _vm->_vidPlayer->closeVideo(slot); } void Inter_v2::o2_getImdInfo() { @@ -1011,10 +1011,10 @@ void Inter_v2::o2_getImdInfo() { int16 varWidth, varHeight; _vm->_game->_script->evalExpr(0); - varX = _vm->_game->_script->readVarIndex(); - varY = _vm->_game->_script->readVarIndex(); + varX = _vm->_game->_script->readVarIndex(); + varY = _vm->_game->_script->readVarIndex(); varFrames = _vm->_game->_script->readVarIndex(); - varWidth = _vm->_game->_script->readVarIndex(); + varWidth = _vm->_game->_script->readVarIndex(); varHeight = _vm->_game->_script->readVarIndex(); // WORKAROUND: The nut rolling animation in the administration center @@ -1106,7 +1106,7 @@ bool Inter_v2::o2_printText(OpFuncParams ¶ms) { _vm->_draw->_backColor = _vm->_game->_script->readValExpr(); _vm->_draw->_frontColor = _vm->_game->_script->readValExpr(); _vm->_draw->_fontIndex = _vm->_game->_script->readValExpr(); - _vm->_draw->_destSurface = 21; + _vm->_draw->_destSurface = Draw::kBackSurface; _vm->_draw->_textToPrint = buf; _vm->_draw->_transparency = 0; diff --git a/engines/gob/inter_v3.cpp b/engines/gob/inter_v3.cpp index beace1b7d8..10ed23619d 100644 --- a/engines/gob/inter_v3.cpp +++ b/engines/gob/inter_v3.cpp @@ -253,8 +253,8 @@ bool Inter_v3::o3_copySprite(OpFuncParams ¶ms) { o1_copySprite(params); // For the close-up "fading" in the CD version - if (_vm->_draw->_destSurface == 20) - _vm->_video->sparseRetrace(20); + if (_vm->_draw->_destSurface == Draw::kFrontSurface) + _vm->_video->sparseRetrace(Draw::kFrontSurface); return false; } diff --git a/engines/gob/inter_v4.cpp b/engines/gob/inter_v4.cpp index 1f6899d85c..d0824ffb58 100644 --- a/engines/gob/inter_v4.cpp +++ b/engines/gob/inter_v4.cpp @@ -142,14 +142,6 @@ void Inter_v4::o4_initScreen() { void Inter_v4::o4_playVmdOrMusic() { char fileName[128]; - int16 x, y; - int16 startFrame; - int16 lastFrame; - int16 breakKey; - int16 flags; - int16 palStart; - int16 palEnd; - uint16 palCmd; bool close; _vm->_game->_script->evalExpr(0); @@ -161,83 +153,92 @@ void Inter_v4::o4_playVmdOrMusic() { (!scumm_stricmp(fileName, "noixroule"))) strcpy(fileName, "noixroul"); - x = _vm->_game->_script->readValExpr(); - y = _vm->_game->_script->readValExpr(); - startFrame = _vm->_game->_script->readValExpr(); - lastFrame = _vm->_game->_script->readValExpr(); - breakKey = _vm->_game->_script->readValExpr(); - flags = _vm->_game->_script->readValExpr(); - palStart = _vm->_game->_script->readValExpr(); - palEnd = _vm->_game->_script->readValExpr(); - palCmd = 1 << (flags & 0x3F); + VideoPlayer::Properties props; + + props.x = _vm->_game->_script->readValExpr(); + props.y = _vm->_game->_script->readValExpr(); + props.startFrame = _vm->_game->_script->readValExpr(); + props.lastFrame = _vm->_game->_script->readValExpr(); + props.breakKey = _vm->_game->_script->readValExpr(); + props.flags = _vm->_game->_script->readValExpr(); + props.palStart = _vm->_game->_script->readValExpr(); + props.palEnd = _vm->_game->_script->readValExpr(); + props.palCmd = 1 << (props.flags & 0x3F); debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " - "paletteCmd %d (%d - %d), flags %X", fileName, x, y, startFrame, lastFrame, - palCmd, palStart, palEnd, flags); + "paletteCmd %d (%d - %d), flags %X", fileName, + props.x, props.y, props.startFrame, props.lastFrame, + props.palCmd, props.palStart, props.palEnd, props.flags); close = false; - if (lastFrame == -1) { + if (props.lastFrame == -1) { close = true; - } else if (lastFrame == -2) { - } else if (lastFrame == -3) { + } else if (props.lastFrame == -2) { + } else if (props.lastFrame == -3) { + + props.flags = VideoPlayer::kFlagOtherSurface; + props.sprite = -1; - _vm->_mult->_objects[startFrame].pAnimData->animation = -startFrame - 1; + _vm->_mult->_objects[props.startFrame].pAnimData->animation = -props.startFrame - 1; - if (_vm->_mult->_objects[startFrame].videoSlot > 0) - _vm->_vidPlayer->slotClose(_vm->_mult->_objects[startFrame].videoSlot - 1); + if (_vm->_mult->_objects[props.startFrame].videoSlot > 0) + _vm->_vidPlayer->closeVideo(_vm->_mult->_objects[props.startFrame].videoSlot - 1); - int slot = _vm->_vidPlayer->slotOpen(fileName); + int slot = _vm->_vidPlayer->openVideo(false, fileName, props); - _vm->_mult->_objects[startFrame].videoSlot = slot + 1; + _vm->_mult->_objects[props.startFrame].videoSlot = slot + 1; - if (x == -1) { - *_vm->_mult->_objects[startFrame].pPosX = _vm->_vidPlayer->getDefaultX(slot); - *_vm->_mult->_objects[startFrame].pPosY = _vm->_vidPlayer->getDefaultY(slot); + if (props.x == -1) { + *_vm->_mult->_objects[props.startFrame].pPosX = _vm->_vidPlayer->getDefaultX(slot); + *_vm->_mult->_objects[props.startFrame].pPosY = _vm->_vidPlayer->getDefaultY(slot); } else { - *_vm->_mult->_objects[startFrame].pPosX = x; - *_vm->_mult->_objects[startFrame].pPosY = y; + *_vm->_mult->_objects[props.startFrame].pPosX = props.x; + *_vm->_mult->_objects[props.startFrame].pPosY = props.y; } return; - } else if (lastFrame == -4) { + } else if (props.lastFrame == -4) { warning("Woodruff Stub: Video/Music command -4: Play background video %s", fileName); return; - } else if (lastFrame == -5) { + } else if (props.lastFrame == -5) { _vm->_sound->bgStop(); return; - } else if (lastFrame == -6) { + } else if (props.lastFrame == -6) { return; - } else if (lastFrame == -7) { + } else if (props.lastFrame == -7) { return; - } else if (lastFrame == -8) { + } else if (props.lastFrame == -8) { warning("Woodruff Stub: Video/Music command -8: Play background video %s", fileName); return; - } else if (lastFrame == -9) { + } else if (props.lastFrame == -9) { _vm->_sound->bgStop(); _vm->_sound->bgSetPlayMode(BackgroundAtmosphere::kPlayModeRandom); - _vm->_sound->bgPlay(fileName, "SND", SOUND_SND, palStart); + _vm->_sound->bgPlay(fileName, "SND", SOUND_SND, props.palStart); return; - } else if (lastFrame < 0) { - warning("Unknown Video/Music command: %d, %s", lastFrame, fileName); + } else if (props.lastFrame < 0) { + warning("Unknown Video/Music command: %d, %s", props.lastFrame, fileName); return; } - if (startFrame == -2) { - startFrame = 0; - lastFrame = -1; + if (props.startFrame == -2) { + props.startFrame = 0; + props.lastFrame = -1; close = false; } - if ((fileName[0] != 0) && !_vm->_vidPlayer->primaryOpen(fileName, x, y, flags)) { + _vm->_vidPlayer->evaluateFlags(props); + + int slot; + if ((fileName[0] != 0) && ((slot = _vm->_vidPlayer->openVideo(true, fileName, props)) < 0)) { WRITE_VAR(11, (uint32) -1); return; } - if (startFrame >= 0) - _vm->_vidPlayer->primaryPlay(startFrame, lastFrame, breakKey, palCmd, palStart, palEnd, 0); + if (props.startFrame >= 0) + _vm->_vidPlayer->play(slot, props); if (close) - _vm->_vidPlayer->primaryClose(); + _vm->_vidPlayer->closeVideo(slot); } } // End of namespace Gob diff --git a/engines/gob/inter_v6.cpp b/engines/gob/inter_v6.cpp index cbc831b5a1..73ef46bf31 100644 --- a/engines/gob/inter_v6.cpp +++ b/engines/gob/inter_v6.cpp @@ -102,88 +102,86 @@ void Inter_v6::o6_totSub() { void Inter_v6::o6_playVmdOrMusic() { char fileName[128]; - int16 x, y; - int16 startFrame; - int16 lastFrame; - int16 breakKey; - int16 flags; - int16 palStart; - int16 palEnd; - uint16 palCmd; bool close; _vm->_game->_script->evalExpr(0); strncpy0(fileName, _vm->_game->_script->getResultStr(), 127); - x = _vm->_game->_script->readValExpr(); - y = _vm->_game->_script->readValExpr(); - startFrame = _vm->_game->_script->readValExpr(); - lastFrame = _vm->_game->_script->readValExpr(); - breakKey = _vm->_game->_script->readValExpr(); - flags = _vm->_game->_script->readValExpr(); - palStart = _vm->_game->_script->readValExpr(); - palEnd = _vm->_game->_script->readValExpr(); - palCmd = 1 << (flags & 0x3F); + VideoPlayer::Properties props; + + props.x = _vm->_game->_script->readValExpr(); + props.y = _vm->_game->_script->readValExpr(); + props.startFrame = _vm->_game->_script->readValExpr(); + props.lastFrame = _vm->_game->_script->readValExpr(); + props.breakKey = _vm->_game->_script->readValExpr(); + props.flags = _vm->_game->_script->readValExpr(); + props.palStart = _vm->_game->_script->readValExpr(); + props.palEnd = _vm->_game->_script->readValExpr(); + props.palCmd = 1 << (props.flags & 0x3F); + props.forceSeek = true; debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " - "paletteCmd %d (%d - %d), flags %X", fileName, x, y, startFrame, lastFrame, - palCmd, palStart, palEnd, flags); + "paletteCmd %d (%d - %d), flags %X", fileName, + props.x, props.y, props.startFrame, props.lastFrame, + props.palCmd, props.palStart, props.palEnd, props.flags); close = false; - if (lastFrame == -1) { + if (props.lastFrame == -1) { close = true; - } else if (lastFrame == -5) { + } else if (props.lastFrame == -5) { // warning("Urban/Playtoons Stub: Stop without delay"); _vm->_sound->bgStop(); return; - } else if (lastFrame == -6) { + } else if (props.lastFrame == -6) { // warning("Urban/Playtoons Stub: Video/Music command -6 (cache video)"); return; - } else if (lastFrame == -7) { + } else if (props.lastFrame == -7) { // warning("Urban/Playtoons Stub: Video/Music command -6 (flush cache)"); return; - } else if ((lastFrame == -8) || (lastFrame == -9)) { + } else if ((props.lastFrame == -8) || (props.lastFrame == -9)) { if (!strchr(fileName, '.')) strcat(fileName, ".WA8"); probe16bitMusic(fileName); - if (lastFrame == -9) { + if (props.lastFrame == -9) { warning("Urban/Playtoons Stub: delayed stop not implemented"); } _vm->_sound->bgStop(); _vm->_sound->bgPlay(fileName, SOUND_WAV); return; - } else if (lastFrame <= -10) { - _vm->_vidPlayer->primaryClose(); - warning("Urban/Playtoons Stub: Video/Music command %d (close video?), %s", lastFrame, fileName); - if (lastFrame <= -100) - lastFrame += 100; + } else if (props.lastFrame <= -10) { + _vm->_vidPlayer->closeVideo(); + warning("Urban/Playtoons Stub: Video/Music command %d (close video?), %s", props.lastFrame, fileName); + if (props.lastFrame <= -100) + props.lastFrame += 100; - if (((-lastFrame) % 10 == 3) && (lastFrame <= -20)) + if (((-props.lastFrame) % 10 == 3) && (props.lastFrame <= -20)) _vm->_sound->bgPlay(fileName, SOUND_WAV); - } else if (lastFrame < 0) { - warning("Urban/Playtoons Stub: Unknown Video/Music command: %d, %s", lastFrame, fileName); + } else if (props.lastFrame < 0) { + warning("Urban/Playtoons Stub: Unknown Video/Music command: %d, %s", props.lastFrame, fileName); return; } - if (startFrame == -2) { - startFrame = 0; - lastFrame = -1; + if (props.startFrame == -2) { + props.startFrame = 0; + props.lastFrame = -1; close = false; } - if ((fileName[0] != 0) && !_vm->_vidPlayer->primaryOpen(fileName, x, y, flags)) { + _vm->_vidPlayer->evaluateFlags(props); + + int slot; + if ((fileName[0] != 0) && ((slot = _vm->_vidPlayer->openVideo(true, fileName, props)) < 0)) { WRITE_VAR(11, (uint32) -1); return; } - if (startFrame >= 0) - _vm->_vidPlayer->primaryPlay(startFrame, lastFrame, breakKey, - palCmd, palStart, palEnd, 0, -1, false, -1, true); + if (props.startFrame >= 0) + _vm->_vidPlayer->play(slot, props); if (close) - _vm->_vidPlayer->primaryClose(); + _vm->_vidPlayer->closeVideo(slot); } void Inter_v6::o6_openItk() { @@ -224,24 +222,30 @@ bool Inter_v6::o6_loadCursor(OpFuncParams ¶ms) { uint16 start = _vm->_game->_script->readUint16(); int8 index = _vm->_game->_script->readInt8(); - int vmdSlot = _vm->_vidPlayer->slotOpen(file); + VideoPlayer::Properties props; + props.sprite = -1; + + int vmdSlot = _vm->_vidPlayer->openVideo(false, file, props); if (vmdSlot == -1) { warning("Can't open video \"%s\" as cursor", file); return false; } - int16 framesCount = _vm->_vidPlayer->getFramesCount(vmdSlot); + int16 framesCount = _vm->_vidPlayer->getFrameCount(vmdSlot); for (int i = 0; i < framesCount; i++) { - _vm->_vidPlayer->slotPlay(vmdSlot); - _vm->_vidPlayer->slotCopyFrame(vmdSlot, _vm->_draw->_cursorSprites->getVidMem(), + props.startFrame = i; + props.lastFrame = i; + + _vm->_vidPlayer->play(vmdSlot, props); + _vm->_vidPlayer->copyFrame(vmdSlot, _vm->_draw->_cursorSprites->getVidMem(), 0, 0, _vm->_draw->_cursorWidth, _vm->_draw->_cursorWidth, (start + i) * _vm->_draw->_cursorWidth, 0, _vm->_draw->_cursorSprites->getWidth()); } - _vm->_vidPlayer->slotClose(vmdSlot); + _vm->_vidPlayer->closeVideo(vmdSlot); _vm->_draw->_cursorAnimLow[index] = start; _vm->_draw->_cursorAnimHigh[index] = framesCount + start - 1; diff --git a/engines/gob/mult.cpp b/engines/gob/mult.cpp index 327b3ed1bd..f744f14faf 100644 --- a/engines/gob/mult.cpp +++ b/engines/gob/mult.cpp @@ -146,7 +146,7 @@ void Mult::freeMult() { _orderArray = 0; _animSurf.reset(); - _vm->_draw->freeSprite(22); + _vm->_draw->freeSprite(Draw::kAnimSurface); } void Mult::checkFreeMult() { @@ -238,7 +238,7 @@ void Mult::playMult(int16 startFrame, int16 endFrame, char checkEscape, _orderArray = 0; _animSurf.reset(); - _vm->_draw->freeSprite(22); + _vm->_draw->freeSprite(Draw::kAnimSurface); _animDataAllocated = false; } @@ -452,7 +452,7 @@ void Mult::clearObjectVideos() { for (int i = 0; i < _objCount; i++) if (_objects[i].videoSlot > 0) - _vm->_vidPlayer->slotClose(_objects[i].videoSlot - 1); + _vm->_vidPlayer->closeVideo(_objects[i].videoSlot - 1); } } // End of namespace Gob diff --git a/engines/gob/mult_v1.cpp b/engines/gob/mult_v1.cpp index 1bb162c789..84869066e1 100644 --- a/engines/gob/mult_v1.cpp +++ b/engines/gob/mult_v1.cpp @@ -236,7 +236,7 @@ void Mult_v1::freeMultKeys() { _animArrayData = 0; _animSurf.reset(); - _vm->_draw->freeSprite(22); + _vm->_draw->freeSprite(Draw::kAnimSurface); _animDataAllocated = false; } @@ -318,7 +318,7 @@ void Mult_v1::playMultInit() { _animSurf = _vm->_video->initSurfDesc(_vm->_global->_videoMode, 320, 200, 0); - _vm->_draw->_spritesArray[22] = _animSurf; + _vm->_draw->_spritesArray[Draw::kAnimSurface] = _animSurf; _vm->_video->drawSprite(*_vm->_draw->_backSurface, *_animSurf, 0, 0, 319, 199, 0, 0, 0); @@ -579,8 +579,8 @@ void Mult_v1::animate() { if ((pNeedRedraw[i] == 0) || (_objects[i].lastLeft == -1)) continue; - _vm->_draw->_sourceSurface = 22; - _vm->_draw->_destSurface = 21; + _vm->_draw->_sourceSurface = Draw::kAnimSurface; + _vm->_draw->_destSurface = Draw::kBackSurface; _vm->_draw->_spriteLeft = pDirtyLefts[i] - _animLeft; _vm->_draw->_spriteTop = pDirtyTops[i] - _animTop; _vm->_draw->_spriteRight = pDirtyRights[i] - pDirtyLefts[i] + 1; diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp index 6acd096e58..66488054e7 100644 --- a/engines/gob/mult_v2.cpp +++ b/engines/gob/mult_v2.cpp @@ -579,11 +579,11 @@ void Mult_v2::playMultInit() { width = _animWidth; height = _animHeight; _vm->_draw->adjustCoords(0, &width, &height); - _vm->_draw->initSpriteSurf(22, width, height, 0); - _animSurf = _vm->_draw->_spritesArray[22]; + _vm->_draw->initSpriteSurf(Draw::kAnimSurface, width, height, 0); + _animSurf = _vm->_draw->_spritesArray[Draw::kAnimSurface]; - _vm->_video->drawSprite(*_vm->_draw->_spritesArray[21], - *_vm->_draw->_spritesArray[22], 0, 0, + _vm->_video->drawSprite(*_vm->_draw->_spritesArray[Draw::kBackSurface], + *_vm->_draw->_spritesArray[Draw::kAnimSurface], 0, 0, _vm->_video->_surfWidth, _vm->_video->_surfHeight, 0, 0, 0); for (_counter = 0; _counter < _objCount; _counter++) @@ -633,14 +633,14 @@ void Mult_v2::drawStatics(bool &stop) { READ_LE_UINT16(_multData->execPtr + layer * 2); _vm->_draw->_destSpriteX = 0; _vm->_draw->_destSpriteY = 0; - _vm->_draw->_destSurface = 21; + _vm->_draw->_destSurface = Draw::kBackSurface; _vm->_draw->_transparency = 0; _vm->_draw->spriteOperation(DRAW_LOADSPRITE); _vm->_scenery->_curStatic = -1; } - _vm->_video->drawSprite(*_vm->_draw->_spritesArray[21], - *_vm->_draw->_spritesArray[22], 0, 0, + _vm->_video->drawSprite(*_vm->_draw->_spritesArray[Draw::kBackSurface], + *_vm->_draw->_spritesArray[Draw::kAnimSurface], 0, 0, _vm->_video->_surfWidth, _vm->_video->_surfHeight, 0, 0, 0); } } @@ -710,7 +710,7 @@ void Mult_v2::newCycleAnim(Mult_Object &animObj) { } else { if (animObj.videoSlot > 0) { _vm->_video->retrace(); - _vm->_vidPlayer->slotWaitEndFrame(animObj.videoSlot - 1, true); + _vm->_vidPlayer->waitEndFrame(animObj.videoSlot - 1, true); } } @@ -736,8 +736,8 @@ void Mult_v2::newCycleAnim(Mult_Object &animObj) { if (animData.animation < 0) { if ((animObj.videoSlot > 0) && - (_vm->_vidPlayer->getCurrentFrame(animObj.videoSlot - 1) < - _vm->_vidPlayer->getFramesCount(animObj.videoSlot - 1))) { + ((_vm->_vidPlayer->getCurrentFrame(animObj.videoSlot - 1) + 1) < + _vm->_vidPlayer->getFrameCount(animObj.videoSlot - 1))) { animData.newCycle = 0; return; } @@ -775,7 +775,7 @@ void Mult_v2::newCycleAnim(Mult_Object &animObj) { animData.isStatic = 1; animData.frame = 0; if ((animData.animation < 0) && (animObj.videoSlot > 0)) { - _vm->_vidPlayer->slotClose(animObj.videoSlot - 1); + _vm->_vidPlayer->closeVideo(animObj.videoSlot - 1); animObj.videoSlot = 0; } @@ -788,7 +788,7 @@ void Mult_v2::newCycleAnim(Mult_Object &animObj) { /* if ((animData.animation < 0) && (animObj.videoSlot > 0)) { if (_vm->_vidPlayer->getFlags(animObj.videoSlot - 1) & 0x1000) { - _vm->_vidPlayer->slotClose(animObj.videoSlot - 1); + _vm->_vidPlayer->closeVideo(animObj.videoSlot - 1); animObj.videoSlot = 0; } } @@ -937,8 +937,8 @@ void Mult_v2::animate() { if ((right <= 0) || (bottom <= 0)) continue; - _vm->_draw->_sourceSurface = 22; - _vm->_draw->_destSurface = 21; + _vm->_draw->_sourceSurface = Draw::kAnimSurface; + _vm->_draw->_destSurface = Draw::kBackSurface; _vm->_draw->_spriteLeft = maxleft - _animLeft; _vm->_draw->_spriteTop = maxtop - _animTop; _vm->_draw->_spriteRight = right; @@ -1100,50 +1100,61 @@ void Mult_v2::animate() { void Mult_v2::playImd(const char *imdFile, Mult::Mult_ImdKey &key, int16 dir, int16 startFrame) { - int16 x, y; - int16 palStart, palEnd; - int16 baseFrame, palFrame, lastFrame; - uint16 flags; + + VideoPlayer::Properties props; if (_vm->_draw->_renderFlags & 0x100) { - x = VAR(55); - y = VAR(56); - } else - x = y = -1; + props.x = VAR(55); + props.y = VAR(56); + } if (key.imdFile == -1) { - _vm->_vidPlayer->primaryClose(); + _vm->_vidPlayer->closeVideo(); return; } - flags = (key.flags >> 8) & 0xFF; - if (flags & 0x20) - flags = (flags & 0x9F) | 0x80; + props.flags = (key.flags >> 8) & 0xFF; + if (props.flags & 0x20) + props.flags = (props.flags & 0x9F) | 0x80; - palStart = key.palStart; - palEnd = key.palEnd; - palFrame = key.palFrame; - lastFrame = key.lastFrame; + props.palStart = key.palStart; + props.palEnd = key.palEnd; + props.palFrame = key.palFrame; + props.lastFrame = key.lastFrame; - if ((palFrame != -1) && (lastFrame != -1)) - if ((lastFrame - palFrame) < startFrame) + if ((props.palFrame != -1) && (props.lastFrame != -1)) + if ((props.lastFrame - props.palFrame) < props.startFrame) if (!(key.flags & 0x4000)) { - _vm->_vidPlayer->primaryClose(); + _vm->_vidPlayer->closeVideo(); return; } - if (!_vm->_vidPlayer->primaryOpen(imdFile, x, y, flags)) + _vm->_vidPlayer->evaluateFlags(props); + + int slot; + if ((slot = _vm->_vidPlayer->openVideo(true, imdFile, props)) < 0) return; - if (palFrame == -1) - palFrame = 0; + if (props.palFrame == -1) + props.palFrame = 0; + + if (props.lastFrame == -1) + props.lastFrame = _vm->_vidPlayer->getFrameCount() - 1; + + uint32 baseFrame = startFrame % (props.lastFrame - props.palFrame + 1); + + props.endFrame = props.lastFrame; + props.startFrame = baseFrame + props.palFrame; + props.lastFrame = baseFrame + props.palFrame; + + props.flags &= 0x7F; - if (lastFrame == -1) - lastFrame = _vm->_vidPlayer->getFramesCount() - 1; + debugC(2, kDebugVideo, "Playing mult video \"%s\" @ %d+%d, frame %d, " + "paletteCmd %d (%d - %d; %d), flags %X", imdFile, + props.x, props.y, props.startFrame, + props.palCmd, props.palStart, props.palEnd, props.endFrame, props.flags); - baseFrame = startFrame % (lastFrame - palFrame + 1); - _vm->_vidPlayer->primaryPlay(baseFrame + palFrame, baseFrame + palFrame, 0, - flags & 0x7F, palStart, palEnd, palFrame, lastFrame); + _vm->_vidPlayer->play(slot, props); } void Mult_v2::advanceObjects(int16 index) { diff --git a/engines/gob/scenery.cpp b/engines/gob/scenery.cpp index a6d6c06544..f9587dc0b3 100644 --- a/engines/gob/scenery.cpp +++ b/engines/gob/scenery.cpp @@ -261,10 +261,10 @@ void Scenery::renderStatic(int16 scenery, int16 layer) { _vm->_draw->_spriteLeft = layerPtr->backResId; if (_vm->_draw->_spriteLeft != -1) { - _vm->_draw->_destSpriteX = 0; - _vm->_draw->_destSpriteY = 0; - _vm->_draw->_destSurface = 21; - _vm->_draw->_transparency = 0; + _vm->_draw->_destSpriteX = 0; + _vm->_draw->_destSpriteY = 0; + _vm->_draw->_destSurface = Draw::kBackSurface; + _vm->_draw->_transparency = 0; _vm->_draw->spriteOperation(DRAW_LOADSPRITE); } @@ -295,7 +295,7 @@ void Scenery::renderStatic(int16 scenery, int16 layer) { _vm->_draw->_sourceSurface = _staticPictToSprite[scenery * 7 + pictIndex]; - _vm->_draw->_destSurface = 21; + _vm->_draw->_destSurface = Draw::kBackSurface; _vm->_draw->_spriteLeft = left; _vm->_draw->_spriteTop = top; _vm->_draw->_spriteRight = right - left + 1; @@ -392,7 +392,7 @@ void Scenery::updateStatic(int16 orderFrom, byte index, byte layer) { _vm->_draw->_sourceSurface = _staticPictToSprite[index * 7 + pictIndex]; - _vm->_draw->_destSurface = 21; + _vm->_draw->_destSurface = Draw::kBackSurface; _vm->_draw->_transparency = planePtr->transp ? 3 : 0; _vm->_draw->spriteOperation(DRAW_BLITSURF); } @@ -616,26 +616,29 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, return; } - if (frame >= _vm->_vidPlayer->getFramesCount(obj.videoSlot - 1)) - frame = _vm->_vidPlayer->getFramesCount(obj.videoSlot - 1) - 1; + if (frame >= (int32)_vm->_vidPlayer->getFrameCount(obj.videoSlot - 1)) + frame = _vm->_vidPlayer->getFrameCount(obj.videoSlot - 1) - 1; - // Seek to frame - if (_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) < 256) { - while (_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) <= frame) - _vm->_vidPlayer->slotPlay(obj.videoSlot - 1); - } else { - int16 curFrame = _vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1); - uint8 frameWrap = curFrame / 256; - frame = (frame + 1) % 256; + if (frame != (int32)_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1)) { + // Seek to frame + + VideoPlayer::Properties props; + + props.forceSeek = true; + props.waitEndFrame = false; + props.lastFrame = frame; - while (_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) < (frameWrap * 256 + frame)) - _vm->_vidPlayer->slotPlay(obj.videoSlot - 1); + if ((int32)_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) < frame) + props.startFrame = _vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) + 1; + else + props.startFrame = frame; + + _vm->_vidPlayer->play(obj.videoSlot - 1, props); } - // Subtitle - Graphics::CoktelVideo::State state = _vm->_vidPlayer->getState(obj.videoSlot - 1); - if (state.flags & Graphics::CoktelVideo::kStateSpeech) - _vm->_draw->printTotText(state.speechId); + int32 subtitle = _vm->_vidPlayer->getSubtitleIndex(obj.videoSlot - 1); + if (subtitle != -1) + _vm->_draw->printTotText(subtitle); destX = 0; destY = 0; @@ -716,7 +719,7 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, _vm->_draw->_spriteLeft = _vm->_vidPlayer->getWidth(obj.videoSlot - 1) - (destX + _vm->_draw->_spriteRight); - _vm->_vidPlayer->slotCopyFrame(obj.videoSlot - 1, _vm->_draw->_backSurface->getVidMem(), + _vm->_vidPlayer->copyFrame(obj.videoSlot - 1, _vm->_draw->_backSurface->getVidMem(), _vm->_draw->_spriteLeft, _vm->_draw->_spriteTop, _vm->_draw->_spriteRight, _vm->_draw->_spriteBottom, _vm->_draw->_destSpriteX, _vm->_draw->_destSpriteY, @@ -726,13 +729,12 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, _vm->_draw->invalidateRect(_vm->_draw->_destSpriteX, _vm->_draw->_destSpriteY, _vm->_draw->_destSpriteX + _vm->_draw->_spriteRight - 1, _vm->_draw->_destSpriteY + _vm->_draw->_spriteBottom - 1); - } if (!(flags & 4)) { - _animLeft = _toRedrawLeft = left; - _animTop = _toRedrawTop = top; - _animRight = _toRedrawRight = right; + _animLeft = _toRedrawLeft = left; + _animTop = _toRedrawTop = top; + _animRight = _toRedrawRight = right; _animBottom = _toRedrawBottom = bottom; } @@ -878,7 +880,7 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, if (doDraw) { _vm->_draw->_sourceSurface = _animPictToSprite[animation * 7 + pictIndex]; - _vm->_draw->_destSurface = 21; + _vm->_draw->_destSurface = Draw::kBackSurface; _vm->_draw->_spriteLeft = left; _vm->_draw->_spriteTop = top; diff --git a/engines/gob/totfile.cpp b/engines/gob/totfile.cpp index 5cc723ba7d..178deeaf58 100644 --- a/engines/gob/totfile.cpp +++ b/engines/gob/totfile.cpp @@ -49,7 +49,7 @@ bool TOTFile::load(const Common::String &fileName) { if (!_stream) // Trying to open from video - _stream = _vm->_vidPlayer->getExtraData(fileName.c_str()); + _stream = _vm->_vidPlayer->getEmbeddedFile(fileName.c_str()); if (!_stream) return false; diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index 51bc1b88a5..9e49bfc092 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -29,7 +29,6 @@ #include "gob/global.h" #include "gob/dataio.h" #include "gob/video.h" -#include "gob/draw.h" #include "gob/game.h" #include "gob/palanim.h" #include "gob/inter.h" @@ -38,767 +37,723 @@ namespace Gob { -const char *VideoPlayer::_extensions[] = { "IMD", "IMD", "VMD", "RMD", "SMD" }; - -VideoPlayer::Video::Video(GobEngine *vm) : _vm(vm), _stream(0), _video(0) { -} - -VideoPlayer::Video::~Video() { - close(); -} - -bool VideoPlayer::Video::open(const char *fileName, Type which, int16 width, int16 height) { - close(); - - int16 handle = _vm->_dataIO->openData(fileName); - - if (handle < 0) { - warning("Couldn't open video \"%s\": No such file", fileName); - return false; - } - - _stream = _vm->_dataIO->openAsStream(handle, true); - - if (which == kVideoTypeIMD) { - _video = new Graphics::Imd(); - } else if (which == kVideoTypePreIMD) { - _video = new Graphics::PreImd(width, height); - } else if (which == kVideoTypeVMD) { - _video = new Graphics::Vmd(_vm->_video->_palLUT); - } else if (which == kVideoTypeRMD) { - _video = new Graphics::Vmd(_vm->_video->_palLUT); - } else { - warning("Couldn't open video \"%s\": Invalid video Type", fileName); - close(); - return false; - } - - if (!_video->load(_stream)) { - warning("While loading video \"%s\"", fileName); - close(); - return false; - } - - _fileName = fileName; +VideoPlayer::Properties::Properties() : type(kVideoTypeTry), sprite(Draw::kFrontSurface), + x(-1), y(-1), width(-1), height(-1), flags(kFlagFrontSurface), + startFrame(-1), lastFrame(-1), endFrame(-1), forceSeek(false), + breakKey(kShortKeyEscape), palCmd(8), palStart(0), palEnd(255), palFrame(-1), + fade(false), waitEndFrame(true), canceled(false) { - _defaultX = _video->getX(); - _defaultY = _video->getY(); - - return true; } -void VideoPlayer::Video::close() { - delete _video; - delete _stream; - - _video = 0; - _stream = 0; - _fileName.clear(); - memset(&_state, 0, sizeof(Graphics::CoktelVideo::State)); - _defaultX = _defaultY = 0; -} -bool VideoPlayer::Video::isOpen() const { - return (_video != 0); +VideoPlayer::Video::Video() : decoder(0) { } -const char *VideoPlayer::Video::getFileName() const { - return _fileName.c_str(); +bool VideoPlayer::Video::isEmpty() const { + return decoder == 0; } -Graphics::CoktelVideo *VideoPlayer::Video::getVideo() { - return _video; -} +void VideoPlayer::Video::close() { + delete decoder; -const Graphics::CoktelVideo *VideoPlayer::Video::getVideo() const { - return _video; + decoder = 0; + fileName.clear(); + surface.reset(); } -uint32 VideoPlayer::Video::getFeatures() const { - return _video->getFeatures(); -} -Graphics::CoktelVideo::State VideoPlayer::Video::getState() const { - return _state; -} +const char *VideoPlayer::_extensions[] = { "IMD", "IMD", "VMD", "RMD", "SMD" }; -int16 VideoPlayer::Video::getDefaultX() const { - return _defaultX; +VideoPlayer::VideoPlayer(GobEngine *vm) : _vm(vm), _needBlit(false), + _noCursorSwitch(false), _woodruffCohCottWorkaround(false) { } -int16 VideoPlayer::Video::getDefaultY() const { - return _defaultY; +VideoPlayer::~VideoPlayer() { + for (int i = 0; i < kVideoSlotCount; i++) + _videoSlots[i].close(); +} + +void VideoPlayer::evaluateFlags(Properties &properties) { + if (properties.flags & kFlagFrontSurface) { + properties.sprite = Draw::kFrontSurface; + } else if (properties.flags & kFlagOtherSurface) { + properties.sprite = properties.x; + properties.x = 0; + } else if (properties.flags & kFlagScreenSurface) { + properties.sprite = 0; + } else if (properties.flags & kFlagNoVideo) { + properties.sprite = 0; + } else { + properties.sprite = Draw::kBackSurface; + } } -bool VideoPlayer::Video::hasExtraData(const char *fileName) const { - if (!_video) - return false; +int VideoPlayer::openVideo(bool primary, const Common::String &file, Properties &properties) { + int slot = 0; - return _video->hasExtraData(fileName); -} - -Common::MemoryReadStream *VideoPlayer::Video::getExtraData(const char *fileName) { - if (!_video) - return 0; + Video *video = 0; + if (!primary) { + slot = getNextFreeSlot(); + if (slot < 0) { + warning("VideoPlayer::openVideo(): Can't open video \"%s\": No free slot", file.c_str()); + return -1; + } - return _video->getExtraData(fileName); -} + video = &_videoSlots[slot]; + } else + video = &_videoSlots[0]; -Graphics::CoktelVideo::State VideoPlayer::Video::nextFrame() { - if (_video) - _state = _video->nextFrame(); + // Different video already in the slot => close that video + if (!video->isEmpty() && (video->fileName.compareToIgnoreCase(file) != 0)) + video->close(); - return _state; -} + // No video => load the requested file + if (video->isEmpty()) { + // Open the video + if (!(video->decoder = openVideo(file, properties))) + return -1; + // Set the filename + video->fileName = file; -VideoPlayer::VideoPlayer(GobEngine *vm) : _vm(vm) { - _primaryVideo = new Video(vm); - _ownSurf = false; - _backSurf = false; - _needBlit = false; - _noCursorSwitch = false; - _woodruffCohCottWorkaround = false; -} + // WORKAROUND: In some rare cases, the cursor should still be + // displayed while a video is playing. + _noCursorSwitch = false; + if (primary && (_vm->getGameType() == kGameTypeLostInTime)) { + if (!file.compareToIgnoreCase("PORTA03") || + !file.compareToIgnoreCase("PORTA03A") || + !file.compareToIgnoreCase("CALE1") || + !file.compareToIgnoreCase("AMIL2") || + !file.compareToIgnoreCase("AMIL3B") || + !file.compareToIgnoreCase("DELB")) + _noCursorSwitch = true; + } -VideoPlayer::~VideoPlayer() { - delete _primaryVideo; - for (uint i = 0; i < _videoSlots.size(); i++) - delete _videoSlots[i]; -} + // WORKAROUND: In Woodruff, Coh Cott vanished in one video on her party. + // This is a bug in video, so we work around it. + _woodruffCohCottWorkaround = false; + if (primary && (_vm->getGameType() == kGameTypeWoodruff)) { + if (!file.compareToIgnoreCase("SQ32-03")) + _woodruffCohCottWorkaround = true; + } -bool VideoPlayer::findFile(char *fileName, Type &which) { - char *extStart = strrchr(fileName, '.'); - // There's no empty extension, Or the filename with its current extension is not found - if ((extStart) && ((extStart == (fileName + strlen(fileName) - 1)) || (!_vm->_dataIO->existData(fileName)))) { - *extStart = 0; - extStart = 0; - } + if (!(properties.flags & kFlagNoVideo) && (properties.sprite >= 0)) { + bool ownSurf = (properties.sprite != Draw::kFrontSurface) && (properties.sprite != Draw::kBackSurface); + bool screenSize = properties.flags & kFlagScreenSurface; - if (extStart) { - // The requested file already has an extension. Verifying. + if (ownSurf) { + _vm->_draw->_spritesArray[properties.sprite] = + _vm->_video->initSurfDesc(_vm->_global->_videoMode, + screenSize ? _vm->_width : video->decoder->getWidth(), + screenSize ? _vm->_height : video->decoder->getHeight(), 0); + } - int i; - for (i = 0; i < ARRAYSIZE(_extensions); i++) { - if (!scumm_stricmp(extStart + 1, _extensions[i])) { - if ((which != kVideoTypeTry) && (which == ((Type) i))) { - warning("Attempted to open video \"%s\", " - "but requested a different type", fileName); - return false; - } - which = (Type) i; - break; + if (!_vm->_draw->_spritesArray[properties.sprite]) { + properties.sprite = -1; + video->surface.reset(); + video->decoder->setSurfaceMemory(); + video->decoder->setXY(0, 0); + } else { + video->surface = _vm->_draw->_spritesArray[properties.sprite]; + video->decoder->setSurfaceMemory(video->surface->getVidMem(), + video->surface->getWidth(), video->surface->getHeight(), 1); + + if (!ownSurf || (ownSurf && screenSize)) { + if ((properties.x >= 0) || (properties.y >= 0)) + video->decoder->setXY((properties.x < 0) ? 0xFFFF : properties.x, + (properties.y < 0) ? 0xFFFF : properties.y); + else + video->decoder->setXY(); + } else + video->decoder->setXY(0, 0); } - } - if (i >= ARRAYSIZE(_extensions)) - extStart = 0; + } else { + properties.sprite = -1; + video->surface.reset(); + video->decoder->setSurfaceMemory(); + video->decoder->setXY(0, 0); + } } - if (!extStart) { - // No or unrecognized extension. Probing. + if (primary) + _needBlit = (properties.flags & kFlagUseBackSurfaceContent) && (properties.sprite == Draw::kFrontSurface); - int len = strlen(fileName); + if (!video->decoder->hasSound()) + video->decoder->setFrameRate(_vm->_util->getFrameRate()); - int i; - for (i = 0; i < ARRAYSIZE(_extensions); i++) { - if ((which == kVideoTypeTry) || (which == ((Type) i))) { - fileName[len] = '.'; - fileName[len + 1] = 0; - strcat(fileName, _extensions[i]); + WRITE_VAR(7, video->decoder->getFrameCount()); - if (_vm->_dataIO->existData(fileName)) { - which = (Type) i; - break; - } - } - } - if ((i >= ARRAYSIZE(_extensions)) || (which == kVideoTypeTry)) { - fileName[len] = 0; - warning("Couldn't open video \"%s\"", fileName); - return false; - } + return slot; +} - } +bool VideoPlayer::closeVideo(int slot) { + Video *video = getVideoBySlot(slot); + if (!video) + return false; + video->close(); return true; } -bool VideoPlayer::primaryOpen(const char *videoFile, int16 x, int16 y, - int32 flags, Type which, int16 width, int16 height) { - - char fileName[256]; - - strncpy0(fileName, videoFile, 250); - - if (!findFile(fileName, which)) +bool VideoPlayer::play(int slot, Properties &properties) { + Video *video = getVideoBySlot(slot); + if (!video) return false; - if (scumm_strnicmp(_primaryVideo->getFileName(), fileName, strlen(fileName))) { - if (!_primaryVideo->open(fileName, which, width, height)) - return false; + bool primary = slot == 0; - // WORKAROUND: In some rare cases, the cursor should still be - // displayed while a video is playing. - _noCursorSwitch = false; - if (_vm->getGameType() == kGameTypeLostInTime) { - if (!scumm_stricmp(fileName, "PORTA03.IMD") || - !scumm_stricmp(fileName, "PORTA03A.IMD") || - !scumm_stricmp(fileName, "CALE1.IMD") || - !scumm_stricmp(fileName, "AMIL2.IMD") || - !scumm_stricmp(fileName, "AMIL3B.IMD") || - !scumm_stricmp(fileName, "DELB.IMD")) - _noCursorSwitch = true; - } + // NOTE: For testing (and comfort?) purposes, we enable aborting of all videos) + properties.breakKey = kShortKeyEscape; - // WORKAROUND: In Woodruff, Coh Cott vanished in one video on her party. - // This is a bug in video, so we work around it. - _woodruffCohCottWorkaround = false; - if (_vm->getGameType() == kGameTypeWoodruff) { - if (!scumm_stricmp(fileName, "SQ32-03.VMD")) - _woodruffCohCottWorkaround = true; - } + if (properties.startFrame < 0) + properties.startFrame = video->decoder->getCurFrame() + 1; + if (properties.lastFrame < 0) + properties.lastFrame = video->decoder->getFrameCount() - 1; + if (properties.endFrame < 0) + properties.endFrame = properties.lastFrame; + if (properties.palFrame < 0) + properties.palFrame = properties.startFrame; - _ownSurf = false; + properties.startFrame--; + properties.endFrame--; + properties.palFrame--; - if (!(flags & kFlagNoVideo)) { - SurfaceDescPtr surf; + if (primary) { + _vm->_draw->_showCursor = _noCursorSwitch ? 3 : 0; - if (flags & kFlagOtherSurface) { - _ownSurf = true; - _backSurf = false; + if (properties.fade) + _vm->_palAnim->fade(0, -2, 0); + } - surf = _vm->_video->initSurfDesc(_vm->_global->_videoMode, - _primaryVideo->getVideo()->getWidth(), - _primaryVideo->getVideo()->getHeight(), 0); - _vm->_draw->_spritesArray[x] = surf; + bool backwards = properties.startFrame > properties.lastFrame; - x = 0; - } else if (flags & kFlagScreenSurface) { - _ownSurf = true; - _backSurf = false; + properties.canceled = false; - surf = _vm->_video->initSurfDesc(_vm->_global->_videoMode, - _vm->_width, _vm->_height, 0); - _vm->_draw->_spritesArray[0] = surf; - } else { - _backSurf = ((flags & kFlagFrontSurface) == 0); - surf = _vm->_draw->_spritesArray[_backSurf ? 21 : 20]; - } + while ((properties.startFrame != properties.lastFrame) && + (properties.startFrame < (int32)(video->decoder->getFrameCount() - 1))) { - _primaryVideo->getVideo()->setVideoMemory(surf->getVidMem(), - surf->getWidth(), surf->getHeight()); + playFrame(slot, properties); + if (properties.canceled) + break; - } else - _primaryVideo->getVideo()->setVideoMemory(); + properties.startFrame += backwards ? -1 : 1; - _needBlit = ((flags & kFlagUseBackSurfaceContent) != 0) && ((flags & kFlagFrontSurface) != 0); + evalBgShading(*video); - _primaryVideo->getVideo()->enableSound(*_vm->_mixer); - } + if (primary && properties.fade) { + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); + properties.fade = false; + } - if (!_primaryVideo->isOpen()) - return false; + if (!_noCursorSwitch && properties.waitEndFrame) + waitEndFrame(slot); + } - _primaryVideo->getVideo()->setFrameRate(_vm->_util->getFrameRate()); - _primaryVideo->getVideo()->setXY(x, y); - WRITE_VAR(7, _primaryVideo->getVideo()->getFramesCount()); + evalBgShading(*video); return true; } -bool VideoPlayer::primaryPlay(int16 startFrame, int16 lastFrame, int16 breakKey, - uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 endFrame, bool fade, int16 reverseTo, bool forceSeek) { +void VideoPlayer::waitEndFrame(int slot, bool onlySound) { + Video *video = getVideoBySlot(slot); + if (!video) + return; + + if (!onlySound || video->decoder->hasSound()) + _vm->_util->delay(video->decoder->getTimeToNextFrame()); +} - if (!_primaryVideo->isOpen()) +bool VideoPlayer::playFrame(int slot, Properties &properties) { + Video *video = getVideoBySlot(slot); + if (!video) return false; - Graphics::CoktelVideo &video = *(_primaryVideo->getVideo()); - - breakKey = 27; - if (startFrame < 0) - startFrame = video.getCurrentFrame(); - if (lastFrame < 0) - lastFrame = video.getFramesCount() - 1; - if (palFrame < 0) - palFrame = startFrame; - if (endFrame < 0) - endFrame = lastFrame; - palCmd &= 0x3F; - - int16 realStartFrame = startFrame; - if (video.getCurrentFrame() != startFrame) { - if (!forceSeek && (video.getFeatures() & Graphics::CoktelVideo::kFeaturesSound)) - startFrame = video.getCurrentFrame(); - else - video.seekFrame(startFrame); - } + bool primary = slot == 0; - _vm->_draw->_showCursor = _noCursorSwitch ? 3 : 0; + if (video->decoder->getCurFrame() != properties.startFrame) { - if (fade) - _vm->_palAnim->fade(0, -2, 0); + if (properties.startFrame != -1) { + // Seek into the middle of the video - bool canceled = false; + if (video->decoder->hasSound()) { + // But there's sound - while (startFrame <= lastFrame) { - if (doPlay(startFrame, breakKey, - palCmd, palStart, palEnd, palFrame, endFrame, startFrame < realStartFrame)) { + if (properties.forceSeek) { + // And we force seeking => Seek - canceled = true; - break; - } + video->decoder->disableSound(); + video->decoder->seek(properties.startFrame + 1, SEEK_SET, true); + } - evalBgShading(video); + } else + // No sound => We can safely seek + video->decoder->seek(properties.startFrame + 1, SEEK_SET, true); - if (fade) { - _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); - fade = false; + } else { + // Seek to the start => We can safely seek + + video->decoder->disableSound(); + video->decoder->seek(0, SEEK_SET, true); + video->decoder->enableSound(); } - if (!_noCursorSwitch) - video.waitEndFrame(); - startFrame++; } - evalBgShading(video); + if (video->decoder->getCurFrame() > properties.startFrame) + // If the video is already beyond the wanted frame, skip + return true; - if (reverseTo >= 0) { - int16 toFrame = video.getFramesCount() - reverseTo; - for (int i = video.getCurrentFrame(); i >= toFrame; i--) { - video.seekFrame(i, SEEK_SET, true); + bool modifiedPal = false; - bool b = doPlay(i, breakKey, 0, 0, 0, 0, 0); - evalBgShading(video); + if (primary) { + // Pre-decoding palette and blitting, only for primary videos - if (b) { - _vm->_palAnim->fade(0, -2, 0); - memset((char *)_vm->_draw->_vgaPalette, 0, 768); - } + if ((properties.startFrame == properties.palFrame) || + ((properties.startFrame == properties.endFrame) && (properties.palCmd == 8))) { - if (!_noCursorSwitch) - video.waitEndFrame(); - } - } + modifiedPal = true; + _vm->_draw->_applyPal = true; - evalBgShading(video); + if (properties.palCmd >= 4) + copyPalette(*video, properties.palStart, properties.palEnd); + } - return canceled; -} + if (modifiedPal && (properties.palCmd == 8) && (video->surface != _vm->_draw->_backSurface)) + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); -void VideoPlayer::primaryClose() { - _primaryVideo->close(); -} + if (_needBlit) + _vm->_draw->forceBlit(); + } -int VideoPlayer::slotOpen(const char *videoFile, Type which, int16 width, int16 height) { - Video *video = new Video(_vm); - char fileName[256]; + Graphics::Surface *surface = video->decoder->decodeNextFrame(); - strncpy0(fileName, videoFile, 250); + WRITE_VAR(11, video->decoder->getCurFrame()); - if (!findFile(fileName, which)) { - delete video; - return -1; - } - - if (!video->open(fileName, which, width, height)) { - delete video; - return -1; + uint32 ignoreBorder = 0; + if (_woodruffCohCottWorkaround && (properties.startFrame == 31)) { + // WORKAROUND: This frame mistakenly masks Coh Cott, making her vanish + // To prevent that, we'll never draw that part + ignoreBorder = 50; } - video->getVideo()->setVideoMemory(); - video->getVideo()->enableSound(*_vm->_mixer); + if (surface && primary) { + // Post-decoding palette and blitting, only for primary videos - int slot = getNextFreeSlot(); + if (_needBlit) + _vm->_draw->forceBlit(true); - _videoSlots[slot] = video; + if (modifiedPal && (properties.palCmd == 16)) { + if (video->surface == _vm->_draw->_backSurface) + _vm->_draw->forceBlit(); + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); + _vm->_draw->_noInvalidated = true; + _vm->_video->dirtyRectsAll(); + } - WRITE_VAR(7, video->getVideo()->getFramesCount()); + if (video->decoder->hasPalette() && (properties.palCmd > 1)) { + copyPalette(*video, properties.palStart, properties.palEnd); - return slot; -} + if (video->surface != _vm->_draw->_backSurface) + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + else + _vm->_draw->_applyPal = true; + } -int VideoPlayer::getNextFreeSlot() { - uint slot; + const Common::List<Common::Rect> &dirtyRects = video->decoder->getDirtyRects(); - for (slot = 0; slot < _videoSlots.size(); slot++) - if (!_videoSlots[slot]) - break; + if (modifiedPal && (properties.palCmd == 8) && (video->surface == _vm->_draw->_backSurface)) + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - if (slot == _videoSlots.size()) - _videoSlots.push_back(0); + if (video->surface == _vm->_draw->_backSurface) { - return slot; -} - -void VideoPlayer::slotPlay(int slot, int16 frame) { - if ((slot < 0) || (((uint) slot) >= _videoSlots.size()) || !_videoSlots[slot]) - return; + for (Common::List<Common::Rect>::const_iterator rect = dirtyRects.begin(); rect != dirtyRects.end(); ++rect) + _vm->_draw->invalidateRect(rect->left + ignoreBorder, rect->top, rect->right - 1, rect->bottom - 1); + _vm->_draw->blitInvalidated(); - Graphics::CoktelVideo &video = *(_videoSlots[slot]->getVideo()); + } else if (video->surface == _vm->_draw->_frontSurface) { + for (Common::List<Common::Rect>::const_iterator rect = dirtyRects.begin(); rect != dirtyRects.end(); ++rect) + _vm->_video->dirtyRectsAdd(rect->left + ignoreBorder, rect->top, rect->right - 1, rect->bottom - 1); - if (frame < 0) - frame = video.getCurrentFrame(); + } - if (frame >= video.getFramesCount()) - return; + if ((video->decoder->getCurFrame() - 1) == properties.startFrame) + // Only retrace if we're playing the frame we actually want to play + _vm->_video->retrace(); - if (video.getCurrentFrame() != frame) - video.seekFrame(frame); + int32 subtitle = video->decoder->getSubtitleIndex(); + if (subtitle != -1) + _vm->_draw->printTotText(subtitle); - _videoSlots[slot]->nextFrame(); - WRITE_VAR(11, frame); + if (modifiedPal && ((properties.palCmd == 2) || (properties.palCmd == 4))) + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); + } - evalBgShading(video); -} + if (primary && properties.waitEndFrame) + checkAbort(*video, properties); -void VideoPlayer::slotClose(int slot) { - if ((slot < 0) || (((uint) slot) >= _videoSlots.size()) || !_videoSlots[slot]) - return; + if ((video->decoder->getCurFrame() - 1) < properties.startFrame) + // The video played a frame we actually didn't want, so we have to adjust + properties.startFrame--; - delete _videoSlots[slot]; - _videoSlots[slot] = 0; + return true; } -void VideoPlayer::slotCopyFrame(int slot, byte *dest, - uint16 left, uint16 top, uint16 width, uint16 height, - uint16 x, uint16 y, uint16 pitch, int16 transp) { - - if ((slot < 0) || (((uint) slot) >= _videoSlots.size()) || !_videoSlots[slot]) - return; +void VideoPlayer::checkAbort(Video &video, Properties &properties) { + _vm->_util->processInput(); - _videoSlots[slot]->getVideo()->copyCurrentFrame(dest, - left, top, width, height, x, y, pitch, transp); -} + if (_vm->shouldQuit()) { + video.decoder->disableSound(); -void VideoPlayer::slotCopyPalette(int slot, int16 palStart, int16 palEnd) { - if ((slot < 0) || (((uint) slot) >= _videoSlots.size()) || !_videoSlots[slot]) + properties.canceled = true; return; + } - copyPalette(*(_videoSlots[slot]->getVideo()), palStart, palEnd); -} + if (properties.breakKey != 0) { + _vm->_util->getMouseState(&_vm->_global->_inter_mouseX, + &_vm->_global->_inter_mouseY, &_vm->_game->_mouseButtons); -void VideoPlayer::slotWaitEndFrame(int slot, bool onlySound) { - Video *video = getVideoBySlot(slot); + _vm->_inter->storeKey(_vm->_util->checkKey()); + if (VAR(0) == (unsigned) properties.breakKey) { + video.decoder->disableSound(); - if (video) { - Graphics::CoktelVideo &cVideo = *video->getVideo(); + // Seek to the last frame. Some scripts depend on that. + video.decoder->seek(properties.endFrame + 1, SEEK_SET, true); - if (!onlySound || (cVideo.getFeatures() & Graphics::CoktelVideo::kFeaturesSound)) - cVideo.waitEndFrame(); + properties.canceled = true; + } } } bool VideoPlayer::slotIsOpen(int slot) const { - if ((slot >= 0) && (((uint) slot) < _videoSlots.size()) && _videoSlots[slot]) - return true; - - return false; -} - -void VideoPlayer::slotSetDoubleMode(int slot, bool doubleMode) { - Video *video = getVideoBySlot(slot); - - if (video) - video->getVideo()->setDoubleMode(doubleMode); + return getVideoBySlot(slot) != 0; } -const VideoPlayer::Video *VideoPlayer::getVideoBySlot(int slot) const { - if (slot < 0) { - if (_primaryVideo->isOpen()) - return _primaryVideo; - } else if (((uint) slot) < _videoSlots.size() && _videoSlots[slot]) - return _videoSlots[slot]; +Common::String VideoPlayer::getFileName(int slot) const { + const Video *video = getVideoBySlot(slot); + if (!video) + return ""; - return 0; + return video->fileName; } -VideoPlayer::Video *VideoPlayer::getVideoBySlot(int slot) { - if (slot < 0) { - if (_primaryVideo->isOpen()) - return _primaryVideo; - } else if (((uint) slot) < _videoSlots.size() && _videoSlots[slot]) - return _videoSlots[slot]; +uint32 VideoPlayer::getFrameCount(int slot) const { + const Video *video = getVideoBySlot(slot); + if (!video) + return 0; - return 0; + return video->decoder->getFrameCount(); } -const char *VideoPlayer::getFileName(int slot) const { +uint32 VideoPlayer::getCurrentFrame(int slot) const { const Video *video = getVideoBySlot(slot); + if (!video) + return 0; - if (video) - return video->getFileName(); - - return ""; + return video->decoder->getCurFrame(); } -uint16 VideoPlayer::getFlags(int slot) const { +uint16 VideoPlayer::getWidth(int slot) const { const Video *video = getVideoBySlot(slot); + if (!video) + return 0; - if (video) - return video->getVideo()->getFlags(); - - return 0; + return video->decoder->getWidth(); } -int16 VideoPlayer::getFramesCount(int slot) const { +uint16 VideoPlayer::getHeight(int slot) const { const Video *video = getVideoBySlot(slot); + if (!video) + return 0; - if (video) - return video->getVideo()->getFramesCount(); - - return 0; + return video->decoder->getHeight(); } -int16 VideoPlayer::getCurrentFrame(int slot) const { +uint16 VideoPlayer::getDefaultX(int slot) const { const Video *video = getVideoBySlot(slot); + if (!video) + return 0; - if (video) - return video->getVideo()->getCurrentFrame(); - - return 0; + return video->decoder->getDefaultX(); } -int16 VideoPlayer::getWidth(int slot) const { +uint16 VideoPlayer::getDefaultY(int slot) const { const Video *video = getVideoBySlot(slot); + if (!video) + return 0; - if (video) - return video->getVideo()->getWidth(); - - return 0; + return video->decoder->getDefaultY(); } -int16 VideoPlayer::getHeight(int slot) const { +const Common::List<Common::Rect> *VideoPlayer::getDirtyRects(int slot) const { const Video *video = getVideoBySlot(slot); + if (!video) + return 0; - if (video) - return video->getVideo()->getHeight(); - - return 0; + return &video->decoder->getDirtyRects(); } -int16 VideoPlayer::getDefaultX(int slot) const { +bool VideoPlayer::hasEmbeddedFile(const Common::String &fileName, int slot) const { const Video *video = getVideoBySlot(slot); + if (!video) + return false; - if (video) - return video->getDefaultX(); - - return 0; + return video->decoder->hasEmbeddedFile(fileName); } -int16 VideoPlayer::getDefaultY(int slot) const { +Common::MemoryReadStream *VideoPlayer::getEmbeddedFile(const Common::String &fileName, int slot) { const Video *video = getVideoBySlot(slot); + if (!video) + return 0; - if (video) - return video->getDefaultY(); - - return 0; + return video->decoder->getEmbeddedFile(fileName); } -uint32 VideoPlayer::getFeatures(int slot) const { +int32 VideoPlayer::getSubtitleIndex(int slot) const { const Video *video = getVideoBySlot(slot); + if (!video) + return -1; - if (video) - return video->getFeatures(); - - return 0; + return video->decoder->getSubtitleIndex(); } -Graphics::CoktelVideo::State VideoPlayer::getState(int slot) const { - const Video *video = getVideoBySlot(slot); - Graphics::CoktelVideo::State state; +void VideoPlayer::writeVideoInfo(const Common::String &file, int16 varX, int16 varY, + int16 varFrames, int16 varWidth, int16 varHeight) { - if (video) - state = video->getState(); + Properties properties; - return state; -} + int slot = openVideo(false, file, properties); + if (slot >= 0) { + Video &video = _videoSlots[slot]; -bool VideoPlayer::hasExtraData(const char *fileName, int slot) const { - const Video *video = getVideoBySlot(slot); + int16 x = -1, y = -1, width = -1, height = -1; - if (video) - return video->hasExtraData(fileName); + x = video.decoder->getDefaultX(); + y = video.decoder->getDefaultY(); + width = video.decoder->getWidth(); + height = video.decoder->getHeight(); - return false; -} + if (VAR_OFFSET(varX) == 0xFFFFFFFF) + video.decoder->getFrameCoords(1, x, y, width, height); -Common::MemoryReadStream *VideoPlayer::getExtraData(const char *fileName, int slot) { - Video *video = getVideoBySlot(slot); + WRITE_VAR_OFFSET(varX , x); + WRITE_VAR_OFFSET(varY , y); + WRITE_VAR_OFFSET(varFrames, video.decoder->getFrameCount()); + WRITE_VAR_OFFSET(varWidth , width); + WRITE_VAR_OFFSET(varHeight, height); - if (video) - return video->getExtraData(fileName); + closeVideo(slot); - return 0; + } else { + WRITE_VAR_OFFSET(varX , (uint32) -1); + WRITE_VAR_OFFSET(varY , (uint32) -1); + WRITE_VAR_OFFSET(varFrames, (uint32) -1); + WRITE_VAR_OFFSET(varWidth , (uint32) -1); + WRITE_VAR_OFFSET(varHeight, (uint32) -1); + } } -void VideoPlayer::playFrame(int16 frame, int16 breakKey, - uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 endFrame, bool noRetrace) { +bool VideoPlayer::copyFrame(int slot, byte *dest, + uint16 left, uint16 top, uint16 width, uint16 height, + uint16 x, uint16 y, uint16 pitch, int16 transp) const { - if (!_primaryVideo) - return; + const Video *video = getVideoBySlot(slot); + if (!video) + return false; - Video &video = *_primaryVideo; - Graphics::CoktelVideo &cVideo = *video.getVideo(); + const Graphics::Surface *surface = video->decoder->getSurface(); + if (!surface) + return false; - if (cVideo.getCurrentFrame() != frame) - cVideo.seekFrame(frame); - if (palFrame < 0) - palFrame = 0; - if (endFrame < 0) - endFrame = cVideo.getFramesCount() - 1; + int32 w = MIN<int32>(width , surface->w); + int32 h = MIN<int32>(height, surface->h); + const byte *src = (byte*)surface->pixels + (top * surface->pitch) + left; + byte *dst = dest + (y * pitch) + x; - bool modifiedPal = false; + if (transp < 0) { + // No transparency - if ((frame == palFrame) || ((frame == endFrame) && (palCmd == 8))) { - modifiedPal = true; - _vm->_draw->_applyPal = true; + if ((x == 0) && (left == 0) && (pitch == surface->pitch) && (width == surface->w)) { + // Dimensions fit, we can copy everything at once - if (palCmd >= 4) - copyPalette(cVideo, palStart, palEnd); - } + memcpy(dst, src, w * h); + return true; + } - if (modifiedPal && (palCmd == 8) && !_backSurf) - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + // Copy row-by-row + while (h-- > 0) { + const byte *srcRow = src; + byte *dstRow = dst; - if (_needBlit) - _vm->_draw->forceBlit(); + memcpy(dstRow, srcRow, w); - Graphics::CoktelVideo::State state = video.nextFrame(); - WRITE_VAR(11, frame); + src += surface->pitch; + dst += pitch; + } - if (_woodruffCohCottWorkaround && (frame == 32)) { - // WORKAROUND: This frame mistakenly masks Coh Cott, making her vanish - // To prevent that, we'll never draw that part - state.left += 50; + return true; } - if (_needBlit) - _vm->_draw->forceBlit(true); + // Copy pixel-by-pixel + while (h-- > 0) { + const byte *srcRow = src; + byte *dstRow = dst; - if (modifiedPal && (palCmd == 16)) { - if (_backSurf) - _vm->_draw->forceBlit(); - _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); - _vm->_draw->_noInvalidated = true; - _vm->_video->dirtyRectsAll(); + for (int32 i = 0; i < w; i++, srcRow++, dstRow++) + if (*srcRow != transp) + *dstRow = *srcRow; + + src += surface->pitch; + dst += pitch; } - if ((state.flags & Graphics::CoktelVideo::kStatePalette) && (palCmd > 1)) { - copyPalette(cVideo, palStart, palEnd); + return true; +} - if (!_backSurf) - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - else - _vm->_draw->_applyPal = true; - } +const VideoPlayer::Video *VideoPlayer::getVideoBySlot(int slot) const { + if ((slot < 0) || (slot >= kVideoSlotCount)) + return 0; - if (modifiedPal && (palCmd == 8) && _backSurf) - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + if (_videoSlots[slot].isEmpty()) + return 0; + return &_videoSlots[slot]; +} - if (!_ownSurf) { - if (_backSurf) { - _vm->_draw->invalidateRect(state.left, state.top, state.right, state.bottom); - _vm->_draw->blitInvalidated(); - } else - _vm->_video->dirtyRectsAdd(state.left, state.top, state.right, state.bottom); +VideoPlayer::Video *VideoPlayer::getVideoBySlot(int slot) { + if ((slot < 0) || (slot >= kVideoSlotCount)) + return 0; - if (!noRetrace) - _vm->_video->retrace(); - } + if (_videoSlots[slot].isEmpty()) + return 0; - // Subtitle - if (state.flags & Graphics::CoktelVideo::kStateSpeech) - _vm->_draw->printTotText(state.speechId); + return &_videoSlots[slot]; +} - if (modifiedPal && ((palCmd == 2) || (palCmd == 4))) - _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); +int VideoPlayer::getNextFreeSlot() { + // Starting with 1, since 0 is reserved for the "primary" video + for (int i = 1; i < kVideoSlotCount; i++) + if (_videoSlots[i].isEmpty()) + return i; + + return -1; } -bool VideoPlayer::doPlay(int16 frame, int16 breakKey, - uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 endFrame, bool noRetrace) { +void VideoPlayer::evalBgShading(Video &video) { + if (video.decoder->isSoundPlaying()) + _vm->_sound->bgShade(); + else + _vm->_sound->bgUnshade(); +} - playFrame(frame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame, noRetrace); +Common::String VideoPlayer::findFile(const Common::String &file, Properties &properties) { - _vm->_util->processInput(); + bool hasExtension = false; - if (_vm->shouldQuit()) { - _primaryVideo->getVideo()->disableSound(); - return true; - } + Common::String base = file; + Common::String fileName = file; - if (breakKey != 0) { - _vm->_util->getMouseState(&_vm->_global->_inter_mouseX, - &_vm->_global->_inter_mouseY, &_vm->_game->_mouseButtons); + const char *posDot = strrchr(base.c_str(), '.'); + if (posDot) { + hasExtension = true; + base = Common::String(base.c_str(), posDot); + posDot++; + } - _vm->_inter->storeKey(_vm->_util->checkKey()); - if (VAR(0) == (unsigned) breakKey) { - _primaryVideo->getVideo()->disableSound(); - // Seek to the last frame. Some scripts depend on that. - _primaryVideo->getVideo()->seekFrame(endFrame, SEEK_SET, true); - return true; + if (hasExtension) { + int i; + for (i = 0; i < ARRAYSIZE(_extensions); i++) { + if (!scumm_stricmp(posDot, _extensions[i])) { + if ((properties.type != kVideoTypeTry) && (properties.type == ((Type) i))) { + warning("Attempted to open video \"%s\", but requested a different type", fileName.c_str()); + return ""; + } + properties.type = (Type) i; + break; + } } + if (i >= ARRAYSIZE(_extensions)) + hasExtension = false; } - return false; -} + if (!hasExtension) { + // No or unrecognized extension. Probing. -void VideoPlayer::copyPalette(Graphics::CoktelVideo &video, int16 palStart, int16 palEnd) { - if (!(video.getFeatures() & Graphics::CoktelVideo::kFeaturesPalette)) - return; + int i; + for (i = 0; i < ARRAYSIZE(_extensions); i++) { + if ((properties.type == kVideoTypeTry) || (properties.type == ((Type) i))) { + fileName = base + "." + _extensions[i]; - if (palStart < 0) - palStart = 0; - if (palEnd < 0) - palEnd = 255; + if (_vm->_dataIO->existData(fileName.c_str())) { + properties.type = (Type) i; + break; + } + } + } + if ((i >= ARRAYSIZE(_extensions)) || (properties.type == kVideoTypeTry)) { + warning("Couldn't open video \"%s\"", file.c_str()); + return ""; + } - memcpy(((char *)(_vm->_global->_pPaletteDesc->vgaPal)) + palStart * 3, - video.getPalette() + palStart * 3, - (palEnd - palStart + 1) * 3); -} + } -void VideoPlayer::writeVideoInfo(const char *videoFile, int16 varX, int16 varY, - int16 varFrames, int16 varWidth, int16 varHeight) { + return fileName; +} - if (primaryOpen(videoFile)) { - int16 x, y, width, height; +Graphics::CoktelDecoder *VideoPlayer::openVideo(const Common::String &file, Properties &properties) { + Common::String fileName = findFile(file, properties); + if (fileName.empty()) + return 0; - x = _primaryVideo->getVideo()->getX(); - y = _primaryVideo->getVideo()->getY(); - width = _primaryVideo->getVideo()->getWidth(); - height = _primaryVideo->getVideo()->getHeight(); + Common::SeekableReadStream *stream = _vm->_dataIO->getDataStream(fileName.c_str()); + if (!stream) + return 0; - if (VAR_OFFSET(varX) == 0xFFFFFFFF) - _primaryVideo->getVideo()->getFrameCoords(1, x, y, width, height); + Graphics::CoktelDecoder *video = 0; + if (properties.type == kVideoTypeIMD) + video = new Graphics::IMDDecoder(_vm->_mixer, Audio::Mixer::kSFXSoundType); + else if (properties.type == kVideoTypePreIMD) + video = new Graphics::PreIMDDecoder(properties.width, properties.height, _vm->_mixer, Audio::Mixer::kSFXSoundType); + else if (properties.type == kVideoTypeVMD) + video = new Graphics::VMDDecoder(_vm->_mixer, Audio::Mixer::kSFXSoundType); + else if (properties.type == kVideoTypeRMD) + video = new Graphics::VMDDecoder(_vm->_mixer, Audio::Mixer::kSFXSoundType); + else + warning("Couldn't open video \"%s\": Invalid video Type", fileName.c_str()); - WRITE_VAR_OFFSET(varX, x); - WRITE_VAR_OFFSET(varY, y); - WRITE_VAR_OFFSET(varFrames, _primaryVideo->getVideo()->getFramesCount()); - WRITE_VAR_OFFSET(varWidth, width); - WRITE_VAR_OFFSET(varHeight, height); + if (!video) { + delete stream; + return 0; + } - primaryClose(); - } else { - WRITE_VAR_OFFSET(varX, (uint32) -1); - WRITE_VAR_OFFSET(varY, (uint32) -1); - WRITE_VAR_OFFSET(varFrames, (uint32) -1); - WRITE_VAR_OFFSET(varWidth, (uint32) -1); - WRITE_VAR_OFFSET(varHeight, (uint32) -1); + if (!video->load(stream)) { + delete video; + return 0; } + + properties.width = video->getWidth(); + properties.height = video->getHeight(); + + return video; } -void VideoPlayer::evalBgShading(Graphics::CoktelVideo &video) { - if (video.isSoundPlaying()) - _vm->_sound->bgShade(); - else - _vm->_sound->bgUnshade(); +void VideoPlayer::copyPalette(const Video &video, int16 palStart, int16 palEnd) { + if (!video.decoder->hasPalette()) + return; + + if (palStart < 0) + palStart = 0; + if (palEnd < 0) + palEnd = 255; + + palStart = palStart * 3; + palEnd = (palEnd + 1) * 3; + + for (int i = palStart; i <= palEnd; i++) + ((char *)(_vm->_global->_pPaletteDesc->vgaPal))[i] = video.decoder->getPalette()[i] >> 2; } } // End of namespace Gob diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h index 8ca8aebf44..d91d0a3845 100644 --- a/engines/gob/videoplayer.h +++ b/engines/gob/videoplayer.h @@ -27,11 +27,15 @@ #define GOB_VIDEOPLAYER_H #include "common/array.h" +#include "common/list.h" +#include "common/rect.h" #include "common/str.h" -#include "graphics/video/coktelvideo/coktelvideo.h" +#include "graphics/surface.h" +#include "graphics/video/coktel_decoder.h" #include "gob/util.h" +#include "gob/draw.h" namespace Gob { @@ -41,132 +45,135 @@ class DataStream; class VideoPlayer { public: enum Flags { - kFlagNone = 0, - kFlagUseBackSurfaceContent = 0x40, - kFlagFrontSurface = 0x80, - kFlagNoVideo = 0x100, - kFlagOtherSurface = 0x800, - kFlagScreenSurface = 0x400000 + kFlagNone = 0x000000, + kFlagUseBackSurfaceContent = 0x000040, ///< Use the back surface as a video "base". + kFlagFrontSurface = 0x000080, ///< Draw directly into the front surface. + kFlagNoVideo = 0x000100, ///< Only sound. + kFlagOtherSurface = 0x000800, ///< Draw into a specific sprite. + kFlagScreenSurface = 0x400000 ///< Draw into a newly created sprite of screen dimensions. }; + /** Video format. */ enum Type { - kVideoTypeTry = -1, - kVideoTypeIMD = 0, - kVideoTypePreIMD = 1, - kVideoTypeVMD = 2, - kVideoTypeRMD = 3 + kVideoTypeTry = -1, ///< Try any format. + kVideoTypeIMD = 0, + kVideoTypePreIMD = 1, ///< Early IMD format found in Fascination. + kVideoTypeVMD = 2, + kVideoTypeRMD = 3 ///< VMD containing "reversed" video. }; - VideoPlayer(GobEngine *vm); - ~VideoPlayer(); + struct Properties { + Type type; ///< Type of the video to open. - bool primaryOpen(const char *videoFile, int16 x = -1, int16 y = -1, - int32 flags = kFlagFrontSurface, Type which = kVideoTypeTry, - int16 width = -1, int16 height = -1); - bool primaryPlay(int16 startFrame = -1, int16 lastFrame = -1, - int16 breakKey = kShortKeyEscape, - uint16 palCmd = 8, int16 palStart = 0, int16 palEnd = 255, - int16 palFrame = -1, int16 endFrame = -1, bool fade = false, - int16 reverseTo = -1, bool forceSeek = false); - void primaryClose(); - - void playFrame(int16 frame, int16 breakKey = kShortKeyEscape, - uint16 palCmd = 8, int16 palStart = 0, int16 palEnd = 255, - int16 palFrame = -1 , int16 endFrame = -1, bool noRetrace = false); - - int slotOpen(const char *videoFile, Type which = kVideoTypeTry, - int16 width = -1, int16 height = -1); - void slotPlay(int slot, int16 frame = -1); - void slotClose(int slot); - void slotCopyFrame(int slot, byte *dest, - uint16 left, uint16 top, uint16 width, uint16 height, - uint16 x, uint16 y, uint16 pitch, int16 transp = -1); - void slotCopyPalette(int slot, int16 palStart = -1, int16 palEnd = -1); - void slotWaitEndFrame(int slot = -1, bool onlySound = false); + int sprite; ///< The sprite onto which to draw the video. - void slotSetDoubleMode(int slot, bool doubleMode); + int32 x; ///< X coordinate of the video. + int32 y; ///< Y coordinate of the video. + int32 width; ///< Width of the video. + int32 height; ///< Height of the video. - bool slotIsOpen(int slot) const; + uint32 flags; ///< Video flags. - const char *getFileName(int slot = -1) const; - uint16 getFlags(int slot = -1) const; - int16 getFramesCount(int slot = -1) const; - int16 getCurrentFrame(int slot = -1) const; - int16 getWidth(int slot = -1) const; - int16 getHeight(int slot = -1) const; - int16 getDefaultX(int slot = -1) const; - int16 getDefaultY(int slot = -1) const; + int32 startFrame; ///< Frame to start playback from. + int32 lastFrame; ///< Frame to stop playback at. + int32 endFrame; ///< Last frame of this playback cycle. - Graphics::CoktelVideo::State getState(int slot = -1) const; - uint32 getFeatures(int slot = -1) const; + bool forceSeek; ///< Force the seeking to the start frame. - bool hasExtraData(const char *fileName, int slot = -1) const; - Common::MemoryReadStream *getExtraData(const char *fileName, int slot = -1); + int16 breakKey; ///< Keycode of the break/abort key. - void writeVideoInfo(const char *videoFile, int16 varX, int16 varY, - int16 varFrames, int16 varWidth, int16 varHeight); + uint16 palCmd; ///< Palette command. + int16 palStart; ///< Palette entry to start with. + int16 palEnd; ///< Palette entry to end at. + int32 palFrame; ///< Frame to apply the palette command at. -private: - class Video { - public: - Video(GobEngine *vm); - ~Video(); + bool fade; ///< Fade in? + + bool waitEndFrame; ///< Wait for the frame's time to run out? + + bool canceled; ///< Was the video canceled? + + Properties(); + }; + + VideoPlayer(GobEngine *vm); + ~VideoPlayer(); + + void evaluateFlags(Properties &properties); + + int openVideo(bool primary, const Common::String &file, Properties &properties); + bool closeVideo(int slot = 0); + + bool play(int slot, Properties &properties); + void waitEndFrame(int slot, bool onlySound = false); - bool open(const char *fileName, Type which, int16 width, int16 height); - void close(); + bool slotIsOpen(int slot = 0) const; - bool isOpen() const; + Common::String getFileName(int slot = 0) const; - const char *getFileName() const; - Graphics::CoktelVideo *getVideo(); - const Graphics::CoktelVideo *getVideo() const; + uint32 getFrameCount (int slot = 0) const; + uint32 getCurrentFrame(int slot = 0) const; + uint16 getWidth (int slot = 0) const; + uint16 getHeight (int slot = 0) const; + uint16 getDefaultX (int slot = 0) const; + uint16 getDefaultY (int slot = 0) const; - Graphics::CoktelVideo::State getState() const; - uint32 getFeatures() const; + const Common::List<Common::Rect> *getDirtyRects(int slot = 0) const; - int16 getDefaultX() const; - int16 getDefaultY() const; + bool hasEmbeddedFile(const Common::String &fileName, int slot = 0) const; + Common::MemoryReadStream *getEmbeddedFile(const Common::String &fileName, int slot = 0); - bool hasExtraData(const char *fileName) const; - Common::MemoryReadStream *getExtraData(const char *fileName); + int32 getSubtitleIndex(int slot = 0) const; - Graphics::CoktelVideo::State nextFrame(); + void writeVideoInfo(const Common::String &file, int16 varX, int16 varY, + int16 varFrames, int16 varWidth, int16 varHeight); + + bool copyFrame(int slot, byte *dest, + uint16 left, uint16 top, uint16 width, uint16 height, + uint16 x, uint16 y, uint16 pitch, int16 transp = -1) const; + +private: + struct Video { + Graphics::CoktelDecoder *decoder; + Common::String fileName; + + SurfaceDescPtr surface; - private: - GobEngine *_vm; + Video(); - Common::String _fileName; - DataStream *_stream; - Graphics::CoktelVideo *_video; - Graphics::CoktelVideo::State _state; - int16 _defaultX, _defaultY; + bool isEmpty() const; + void close(); }; + static const int kVideoSlotCount = 32; + static const char *_extensions[]; GobEngine *_vm; - Common::Array<Video *> _videoSlots; - Video *_primaryVideo; - bool _ownSurf; - bool _backSurf; + // _videoSlots[0] is reserved for the "primary" video + Video _videoSlots[kVideoSlotCount]; + bool _needBlit; - bool _noCursorSwitch; + bool _noCursorSwitch; bool _woodruffCohCottWorkaround; - bool findFile(char *fileName, Type &which); - - const Video *getVideoBySlot(int slot = -1) const; - Video *getVideoBySlot(int slot = -1); + const Video *getVideoBySlot(int slot) const; + Video *getVideoBySlot(int slot); int getNextFreeSlot(); - void copyPalette(Graphics::CoktelVideo &video, int16 palStart = -1, int16 palEnd = -1); - bool doPlay(int16 frame, int16 breakKey, - uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 endFrame, bool noRetrace = false); - void evalBgShading(Graphics::CoktelVideo &video); + Common::String findFile(const Common::String &file, Properties &properties); + + Graphics::CoktelDecoder *openVideo(const Common::String &file, Properties &properties); + + bool playFrame(int slot, Properties &properties); + + void checkAbort(Video &video, Properties &properties); + void evalBgShading(Video &video); + + void copyPalette(const Video &video, int16 palStart, int16 palEnd); }; } // End of namespace Gob diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h index fe4cc7298f..2e1d5afc17 100644 --- a/engines/kyra/detection_tables.h +++ b/engines/kyra/detection_tables.h @@ -194,7 +194,7 @@ const KYRAGameDescription adGameDescs[] = { Common::EN_ANY, Common::kPlatformAmiga, ADGF_NO_FLAGS, - Common::GUIO_NOSPEECH + Common::GUIO_NOSPEECH | Common::GUIO_MIDIAMIGA }, KYRA1_AMIGA_FLAGS }, @@ -211,7 +211,7 @@ const KYRAGameDescription adGameDescs[] = { Common::DE_DEU, Common::kPlatformAmiga, ADGF_NO_FLAGS, - Common::GUIO_NOSPEECH + Common::GUIO_NOSPEECH | Common::GUIO_MIDIAMIGA }, KYRA1_AMIGA_FLAGS }, @@ -1113,6 +1113,23 @@ const KYRAGameDescription adGameDescs[] = { "lol", "Extracted", { + { "GENERAL.PAK", 0, "0f1fabc1f67b772a30d8e05ece720ac5", -1 }, + { "CHAPTER7.PAK", 0, "482308aba1c40ee32449b91b0c63b990", -1 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, + Common::kPlatformPC, + ADGF_NO_FLAGS, + Common::GUIO_NOSPEECH | Common::GUIO_MIDIADLIB | Common::GUIO_MIDIMT32 | Common::GUIO_MIDIGM | Common::GUIO_MIDIPCSPK + }, + LOL_FLOPPY_FLAGS + }, + + { + { + "lol", + "Extracted", + { { "GENERAL.PAK", 0, "996e66e81054d36249907a1d8158da3d", -1 }, { "CHAPTER7.PAK", 0, "cabee57f00d6d84b65a732b6868a4959", -1 }, { 0, 0, 0, 0 } diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 98f0e31b69..03d52ec4ac 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -4291,7 +4291,7 @@ void LoLEngine::drawMapPage(int pageNum) { if (!_defaultLegendData[ii].enable) continue; _screen->copyBlockAndApplyOverlay(_screen->_curPage, 235, (tY << 3) + 21 + yOffset, _screen->_curPage, 235 + xOffset, (tY << 3) + 21 + yOffset, 7, 6, 0, _mapOverlay); - _screen->drawShape(_screen->_curPage, _automapShapes[_defaultLegendData[ii].shapeIndex << 2], 232 + xOffset, (tY << 3) + 18 + yOffset + _defaultLegendData[ii].x, 0, 0); + _screen->drawShape(_screen->_curPage, _automapShapes[_defaultLegendData[ii].shapeIndex << 2], 232 + xOffset, (tY << 3) + 18 + yOffset + _defaultLegendData[ii].y, 0, 0); printMapText(_defaultLegendData[ii].stringId, 244 + xOffset, (tY << 3) + 22 + yOffset); tY++; } diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index b5a657ac15..57c127a94f 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -256,7 +256,7 @@ struct LevelTempData { struct MapLegendData { uint8 shapeIndex; bool enable; - int8 x; + int8 y; uint16 stringId; }; diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 8d01d47262..d27b075906 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -65,7 +65,9 @@ bool SoundTowns::init() { if (!loadInstruments()) return false; - _driver->cdaSetVolume(1, 118, 118); + _driver->intf()->callback(68); + _driver->intf()->callback(70, 0x33); + _driver->setOutputVolume(1, 118, 118); return true; } @@ -91,7 +93,7 @@ void SoundTowns::playTrack(uint8 track) { beginFadeOut(); if (_musicEnabled == 2 && trackNum != -1) { - _driver->cdaSetVolume(1, 118, 118); + _driver->setOutputVolume(1, 118, 118); g_system->getAudioCDManager()->play(trackNum + 1, loop ? -1 : 1, 0, 0); g_system->getAudioCDManager()->updateCD(); _cdaPlaying = true; @@ -229,24 +231,24 @@ void SoundTowns::stopAllSoundEffects() { void SoundTowns::beginFadeOut() { if (_cdaPlaying) { for (int i = 118; i > 103; i--) { - _driver->cdaSetVolume(1, i, i); + _driver->setOutputVolume(1, i, i); _vm->delay(2 * _vm->tickLength()); } for (int i = 103; i > 83; i -= 2) { - _driver->cdaSetVolume(1, i, i); + _driver->setOutputVolume(1, i, i); _vm->delay(2 * _vm->tickLength()); } for (int i = 83; i > 58; i -= 2) { - _driver->cdaSetVolume(1, i, i); + _driver->setOutputVolume(1, i, i); _vm->delay(_vm->tickLength()); } for (int i = 58; i > 0; i--) - _driver->cdaSetVolume(1, i, i); + _driver->setOutputVolume(1, i, i); - _driver->cdaSetVolume(1, 0, 0); + _driver->setOutputVolume(1, 0, 0); } else { if (_lastTrack == -1) @@ -335,9 +337,9 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) { for (int i = 0; i < 32; i++) _driver->chanOrdr(i, *src++); for (int i = 0; i < 32; i++) - _driver->chanLevel(i, *src++); + _driver->chanVolumeShift(i, *src++); for (int i = 0; i < 32; i++) - _driver->chanTranspose(i, *src++); + _driver->chanNoteShift(i, *src++); src = _musicTrackData + 1748; for (int i = 0; i < 6; i++) diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 274acae22c..4b71b1d69d 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -42,7 +42,7 @@ namespace Kyra { -#define RESFILE_VERSION 71 +#define RESFILE_VERSION 72 namespace { bool checkKyraDat(Common::SeekableReadStream *file) { diff --git a/engines/kyra/staticres_lol.cpp b/engines/kyra/staticres_lol.cpp index dbf6808e37..3287ee37d6 100644 --- a/engines/kyra/staticres_lol.cpp +++ b/engines/kyra/staticres_lol.cpp @@ -372,31 +372,32 @@ void LoLEngine::initStaticResource() { _autoMapStrings = _staticres->loadRawDataBe16(kLolMapStringId, _autoMapStringsSize); - int tmpSize = 0; - const uint8 *tmp = _staticres->loadRawData(kLolLegendData, tmpSize); - tmpSize /= 5; - if (tmp) { - _defaultLegendData = new MapLegendData[tmpSize]; - for (int i = 0; i < tmpSize; i++) { + int tempSize; + const uint8 *tmp = _staticres->loadRawData(kLolLegendData, tempSize); + uint8 entrySize = tempSize / 12; + tempSize /= entrySize; + if (tempSize) { + _defaultLegendData = new MapLegendData[tempSize]; + for (int i = 0; i < tempSize; i++) { _defaultLegendData[i].shapeIndex = *tmp++; _defaultLegendData[i].enable = *tmp++ ? true : false; - _defaultLegendData[i].x = (int8)*tmp++; + _defaultLegendData[i].y = (entrySize == 5) ? (int8)*tmp++ : (i == 10 ? -5 : 0); _defaultLegendData[i].stringId = READ_LE_UINT16(tmp); tmp += 2; } _staticres->unloadId(kLolLegendData); } - tmp = _staticres->loadRawData(kLolMapCursorOvl, tmpSize); - _mapCursorOverlay = new uint8[tmpSize]; - memcpy(_mapCursorOverlay, tmp, tmpSize); + tmp = _staticres->loadRawData(kLolMapCursorOvl, tempSize); + _mapCursorOverlay = new uint8[tempSize]; + memcpy(_mapCursorOverlay, tmp, tempSize); _staticres->unloadId(kLolMapCursorOvl); _updateSpellBookCoords = _staticres->loadRawData(kLolSpellbookCoords, _updateSpellBookCoordsSize); _updateSpellBookAnimData = _staticres->loadRawData(kLolSpellbookAnim, _updateSpellBookAnimDataSize); _healShapeFrames = _staticres->loadRawData(kLolHealShapeFrames, _healShapeFramesSize); - tmp = _staticres->loadRawData(kLolLightningDefs, tmpSize); + tmp = _staticres->loadRawData(kLolLightningDefs, tempSize); if (tmp) { _lightningProps = new LightningProperty[5]; for (int i = 0; i < 5; i++) { diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 2432d84faa..7acbe56a12 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -51,7 +51,7 @@ #include "graphics/video/avi_decoder.h" #include "sci/video/seq_decoder.h" #ifdef ENABLE_SCI32 -#include "sci/video/vmd_decoder.h" +#include "graphics/video/coktel_decoder.h" #endif #include "common/file.h" @@ -234,7 +234,7 @@ void Console::postEnter() { videoDecoder = seqDecoder; #ifdef ENABLE_SCI32 } else if (_videoFile.hasSuffix(".vmd")) { - videoDecoder = new VMDDecoder(g_system->getMixer()); + videoDecoder = new Graphics::VMDDecoder(g_system->getMixer()); #endif } else if (_videoFile.hasSuffix(".avi")) { videoDecoder = new Graphics::AviDecoder(g_system->getMixer()); @@ -245,6 +245,9 @@ void Console::postEnter() { uint16 y = (g_system->getHeight() - videoDecoder->getHeight()) / 2; bool skipVideo = false; + if (videoDecoder->hasDirtyPalette()) + videoDecoder->setSystemPalette(); + while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { if (videoDecoder->needsUpdate()) { Graphics::Surface *frame = videoDecoder->decodeNextFrame(); @@ -443,6 +446,7 @@ bool Console::cmdGetVersion(int argc, const char **argv) { DebugPrintf("Resource volume version: %s\n", g_sci->getResMan()->getVolVersionDesc()); DebugPrintf("Resource map version: %s\n", g_sci->getResMan()->getMapVersionDesc()); DebugPrintf("Contains selector vocabulary (vocab.997): %s\n", hasVocab997 ? "yes" : "no"); + DebugPrintf("Has CantBeHere selector: %s\n", g_sci->getKernel()->_selectorCache.cantBeHere != -1 ? "yes" : "no"); DebugPrintf("Game version (VERSION file): %s\n", gameVersion.c_str()); DebugPrintf("\n"); diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 0614eff6e6..a74c34f517 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -643,6 +643,15 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::ES_ESP, Common::kPlatformWindows, 0, GUIO_NONE }, + // Gabriel Knight - English Macintosh + {"gk1", "", { + {"Data1", 0, "7a89c96365a4da5d3b3efdc3a94bab3e", 5831362}, + {"Data2", 0, "db70638e972c3706e4dc9e01ef3a30ea", 6696048}, + {"Data3", 0, "d740126293aea176c4f8a6c71634cff4", 3683997}, + {"Data4", 0, "f6cbf2605f618ce035bed162d66b2b8a", 3233086}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO_NONE }, + // Gabriel Knight 2 - English Windows Non-Interactive Demo // Executable scanning reports "2.100.002" {"gk2", "Demo", { @@ -2554,17 +2563,6 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH }, -#endif - - // Slater & Charlie go camping - {"slater", "", { - {"resource.000", 0, "1846b57fe84774be72f7c50ab3c90df0", 2256126}, - {"resource.map", 0, "21f85414124dc23e54544a5536dc35cd", 4044}, - {"resource.msg", 0, "c44f51fb955eae266fecf360ebcd5ad2", 1132}, - AD_LISTEND}, - Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO, GUIO_NOSPEECH }, - -#ifdef ENABLE_SCI32 // RAMA - English DOS/Windows Demo // Executable scanning reports "2.100.002", VERSION file reports "000.000.008" {"rama", "Demo", { @@ -2660,6 +2658,14 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH }, + // Slater & Charlie Go Camping - English DOS/Windows + {"slater", "", { + {"resource.000", 0, "1846b57fe84774be72f7c50ab3c90df0", 2256126}, + {"resource.map", 0, "21f85414124dc23e54544a5536dc35cd", 4044}, + {"resource.msg", 0, "c44f51fb955eae266fecf360ebcd5ad2", 1132}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH }, + // Space Quest 1 VGA Remake - English Amiga (from www.back2roots.org) // SCI interpreter version 1.000.510 (just a guess) {"sq1sci", "VGA Remake", { @@ -3010,13 +3016,16 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH }, - // Space Quest 5 - English DOS +#if 0 + // Space Quest 5 - English DOS - THIS IS THE UNOFFICIAL BETA VERSION, WHICH IS OBVIOUSLY PIRATED AND CONTAINS MANY BUGS + // ffs. http://www.akril15.com/sr/sq5alt/sq5alt.html =DO NOT RE-ADD= // SCI interpreter version 1.001.067 {"sq5", "", { {"resource.map", 0, "8bde0a9adb9a3e9aaa861826874c9834", 6473}, {"resource.000", 0, "f4a48705764544d7cc64a7bb22a610df", 6025184}, AD_LISTEND}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH }, +#endif // Space Quest 5 v1.04 - German DOS (from Tobis87, updated information by markcool from bug reports #2723935 and #2724762) // SCI interpreter version 1.001.068 diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index b2b8eb593e..e71e97e95d 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -320,7 +320,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(CosDiv), SIG_EVERYWHERE, "ii", NULL, NULL }, { MAP_CALL(DeleteKey), SIG_EVERYWHERE, "l.", NULL, NULL }, { MAP_CALL(DeviceInfo), SIG_EVERYWHERE, "i(r)(r)(i)", NULL, kDeviceInfo_workarounds }, // subop - { MAP_CALL(Display), SIG_EVERYWHERE, "[ir]([ir!]*)", NULL, NULL }, + { MAP_CALL(Display), SIG_EVERYWHERE, "[ir]([ir!]*)", NULL, kDisplay_workarounds }, // ^ we allow invalid references here, because kDisplay gets called with those in e.g. pq3 during intro // restoreBits() checks and skips invalid handles, so that's fine. Sierra SCI behaved the same { MAP_CALL(DirLoop), SIG_EVERYWHERE, "oi", NULL, NULL }, diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index e1e92b1cf9..a3f7a90da3 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -300,8 +300,8 @@ reg_t kGraphFillBoxAny(EngineState *s, int argc, reg_t *argv) { Common::Rect rect = getGraphRect(argv); int16 colorMask = argv[4].toUint16(); int16 color = argv[5].toSint16(); - int16 priority = (argc > 6) ? argv[6].toSint16() : -1; - int16 control = (argc > 7) ? argv[7].toSint16() : -1; + int16 priority = argv[6].toSint16(); // yes, we may read from stack sometimes here + int16 control = argv[7].toSint16(); // sierra did the same g_sci->_gfxPaint16->kernelGraphFillBox(rect, colorMask, color, priority, control); return s->r_acc; diff --git a/engines/sci/engine/kmath.cpp b/engines/sci/engine/kmath.cpp index f3769b653b..332fbb62f8 100644 --- a/engines/sci/engine/kmath.cpp +++ b/engines/sci/engine/kmath.cpp @@ -63,11 +63,11 @@ reg_t kRandom(EngineState *s, int argc, reg_t *argv) { } reg_t kAbs(EngineState *s, int argc, reg_t *argv) { - return make_reg(0, abs(argv[0].toSint16())); + return make_reg(0, ABS(argv[0].toSint16())); } reg_t kSqrt(EngineState *s, int argc, reg_t *argv) { - return make_reg(0, (int16) sqrt((float) abs(argv[0].toSint16()))); + return make_reg(0, (int16) sqrt((float) ABS(argv[0].toSint16()))); } reg_t kGetAngle(EngineState *s, int argc, reg_t *argv) { diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp index dfd1aa699e..8c43a35fea 100644 --- a/engines/sci/engine/kmovement.cpp +++ b/engines/sci/engine/kmovement.cpp @@ -86,7 +86,7 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) { int vy = 0; // y velocity int dxWasNegative = (dx < 0); - dx = abs(dx); + dx = ABS(dx); assert(gy >= 0); @@ -104,8 +104,8 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) { // we ensure vx will be less than sqrt(gy * dx)). if (dx + dy < 0) { // dy is negative and |dy| > |dx| - c = (2 * abs(dy)) / dx; - //tmp = abs(dy); // ALMOST the resulting value, except for obvious rounding issues + c = (2 * ABS(dy)) / dx; + //tmp = ABS(dy); // ALMOST the resulting value, except for obvious rounding issues } else { // dy is either positive, or |dy| <= |dx| c = (dx * 3 / 2 - dy) / dx; @@ -122,8 +122,8 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) { } // POST: c >= 1 tmp = c * dx + dy; - // POST: (dx != 0) ==> abs(tmp) > abs(dx) - // POST: (dx != 0) ==> abs(tmp) ~>=~ abs(dy) + // POST: (dx != 0) ==> ABS(tmp) > ABS(dx) + // POST: (dx != 0) ==> ABS(tmp) ~>=~ ABS(dy) debugC(2, kDebugLevelBresen, "c: %d, tmp: %d", c, tmp); @@ -145,7 +145,7 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) { // FIXME: This choice of vy makes t roughly (2+sqrt(2))/gy * sqrt(dy); // so if gy==3, then t is roughly sqrt(dy)... - vy = (int)sqrt((double)gy * abs(2 * dy)) + 1; + vy = (int)sqrt((double)gy * ABS(2 * dy)) + 1; } else { // As stated above, the vertical direction is correlated to the horizontal by the // (non-zero) factor c. @@ -155,7 +155,7 @@ reg_t kSetJump(EngineState *s, int argc, reg_t *argv) { } // Always force vy to be upwards - vy = -abs(vy); + vy = -ABS(vy); debugC(2, kDebugLevelBresen, "SetJump for object at %04x:%04x", PRINT_REG(object)); debugC(2, kDebugLevelBresen, "xStep: %d, yStep: %d", vx, vy); @@ -173,8 +173,8 @@ static void initialize_bresen(SegManager *segMan, int argc, reg_t *argv, reg_t m reg_t client = readSelector(segMan, mover, SELECTOR(client)); int stepx = (int16)readSelectorValue(segMan, client, SELECTOR(xStep)) * step_factor; int stepy = (int16)readSelectorValue(segMan, client, SELECTOR(yStep)) * step_factor; - int numsteps_x = stepx ? (abs(deltax) + stepx - 1) / stepx : 0; - int numsteps_y = stepy ? (abs(deltay) + stepy - 1) / stepy : 0; + int numsteps_x = stepx ? (ABS(deltax) + stepx - 1) / stepx : 0; + int numsteps_y = stepy ? (ABS(deltay) + stepy - 1) / stepy : 0; int bdi, i1; int numsteps; int deltax_step; @@ -190,22 +190,22 @@ static void initialize_bresen(SegManager *segMan, int argc, reg_t *argv, reg_t m deltax_step = numsteps ? deltax / numsteps : deltax; } -/* if (abs(deltax) > abs(deltay)) {*/ // Bresenham on y +/* if (ABS(deltax) > ABS(deltay)) {*/ // Bresenham on y if (numsteps_y < numsteps_x) { writeSelectorValue(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_Y); writeSelectorValue(segMan, mover, SELECTOR(b_incr), (deltay < 0) ? -1 : 1); - //i1 = 2 * (abs(deltay) - abs(deltay_step * numsteps)) * abs(deltax_step); - //bdi = -abs(deltax); - i1 = 2 * (abs(deltay) - abs(deltay_step * (numsteps - 1))) * abs(deltax_step); - bdi = -abs(deltax); + //i1 = 2 * (ABS(deltay) - ABS(deltay_step * numsteps)) * ABS(deltax_step); + //bdi = -ABS(deltax); + i1 = 2 * (ABS(deltay) - ABS(deltay_step * (numsteps - 1))) * ABS(deltax_step); + bdi = -ABS(deltax); } else { // Bresenham on x writeSelectorValue(segMan, mover, SELECTOR(b_xAxis), _K_BRESEN_AXIS_X); writeSelectorValue(segMan, mover, SELECTOR(b_incr), (deltax < 0) ? -1 : 1); - //i1= 2 * (abs(deltax) - abs(deltax_step * numsteps)) * abs(deltay_step); - //bdi = -abs(deltay); - i1 = 2 * (abs(deltax) - abs(deltax_step * (numsteps - 1))) * abs(deltay_step); - bdi = -abs(deltay); + //i1= 2 * (ABS(deltax) - ABS(deltax_step * numsteps)) * ABS(deltay_step); + //bdi = -ABS(deltay); + i1 = 2 * (ABS(deltax) - ABS(deltax_step * (numsteps - 1))) * ABS(deltay_step); + bdi = -ABS(deltay); } @@ -306,23 +306,17 @@ reg_t kDoBresen(EngineState *s, int argc, reg_t *argv) { if ((MOVING_ON_X && (((x < destx) && (oldx >= destx)) // Moving left, exceeded? || ((x > destx) && (oldx <= destx)) // Moving right, exceeded? - || ((x == destx) && (abs(dx) > abs(dy))) // Moving fast, reached? + || ((x == destx) && (ABS(dx) > ABS(dy))) // Moving fast, reached? // Treat this last case specially- when doing sub-pixel movements // on the other axis, we could still be far away from the destination )) || (MOVING_ON_Y && (((y < desty) && (oldy >= desty)) /* Moving upwards, exceeded? */ || ((y > desty) && (oldy <= desty)) /* Moving downwards, exceeded? */ - || ((y == desty) && (abs(dy) >= abs(dx))) /* Moving fast, reached? */ + || ((y == desty) && (ABS(dy) >= ABS(dx))) /* Moving fast, reached? */ ))) { // Whew... in short: If we have reached or passed our target position - // Sanity check: make sure that destx, desty are inside the screen coordinates. - // They can go off screen in some cases, e.g. in SQ5 while scrubbing the floor (bug #3037351) - if (destx < g_sci->_gfxScreen->getWidth() && desty < g_sci->_gfxScreen->getHeight()) { - x = destx; - y = desty; - } else { - warning("kDoBresen: destination x, y would be off-screen(%d, %d)", destx, desty); - } + x = destx; + y = desty; completed = 1; debugC(2, kDebugLevelBresen, "Finished mover %04x:%04x", PRINT_REG(mover)); diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp index fdebc0599c..07d0a31f0b 100644 --- a/engines/sci/engine/kpathing.cpp +++ b/engines/sci/engine/kpathing.cpp @@ -265,7 +265,8 @@ struct PathfindingState { static Common::Point read_point(SegManager *segMan, reg_t list, int offset) { SegmentRef list_r = segMan->dereference(list); if (!list_r.isValid() || list_r.skipByte) { - warning("read_point(): Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(list)); + // If this happens, then the code below will probably go OOB and crash + error("read_point(): Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(list)); } Common::Point point; diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index 3ad2d95f58..ac6cfb6835 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -34,7 +34,7 @@ #include "graphics/video/qt_decoder.h" #include "sci/video/seq_decoder.h" #ifdef ENABLE_SCI32 -#include "sci/video/vmd_decoder.h" +#include "graphics/video/coktel_decoder.h" #endif namespace Sci { @@ -60,6 +60,9 @@ void playVideo(Graphics::VideoDecoder *videoDecoder) { uint16 y = (screenHeight - height) / 2; bool skipVideo = false; + if (videoDecoder->hasDirtyPalette()) + videoDecoder->setSystemPalette(); + while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { if (videoDecoder->needsUpdate()) { Graphics::Surface *frame = videoDecoder->decodeNextFrame(); @@ -203,7 +206,7 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) { if (argv[2] != NULL_REG) warning("kPlayVMD: third parameter isn't 0 (it's %04x:%04x - %s)", PRINT_REG(argv[2]), s->_segMan->getObjectName(argv[2])); - videoDecoder = new VMDDecoder(g_system->getMixer()); + videoDecoder = new Graphics::VMDDecoder(g_system->getMixer()); if (!videoDecoder->loadFile(fileName)) { warning("Could not open VMD %s", fileName.c_str()); diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index a7716516e7..dfc41cc56a 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -659,8 +659,10 @@ void SegManager::reconstructClones() { CloneTable::Entry &seeker = ct->_table[j]; const Object *baseObj = getObject(seeker.getSpeciesSelector()); seeker.cloneFromObject(baseObj); - if (!baseObj) - error("Clone entry without a base class: %d", j); + if (!baseObj) { + // Can happen when loading some KQ6 savegames + warning("Clone entry without a base class: %d", j); + } } // end for } // end if } // end for diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index 645094d9ec..f4129bb1ea 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -123,6 +123,9 @@ void Script::load(ResourceManager *resMan) { assert(_bufSize >= script->size); memcpy(_buf, script->data, script->size); + // Check scripts for matching signatures and patch those, if found + matchSignatureAndPatch(_nr, _buf, script->size); + if (getSciVersion() >= SCI_VERSION_1_1) { Resource *heap = resMan->findResource(ResourceId(kResourceTypeHeap, _nr), 0); assert(heap != 0); @@ -326,12 +329,29 @@ uint16 Script::validateExportFunc(int pubfunct) { uint16 offset = READ_SCI11ENDIAN_UINT16(_exportTable + pubfunct); VERIFY(offset < _bufSize, "invalid export function pointer"); + if (offset == 0) { + // Check if the game has a second export table (e.g. script 912 in Camelot) + // Fixes bug #3039785 + if (g_sci->getGameId() != GID_CAMELOT) // cheap fix + return offset; + // we are getting assert()s in eco quest 1 (right on startup) and kq6 and maybe more + // [md5] plz look into this TODO FIXME + const uint16 *secondExportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS, 0); + + if (secondExportTable) { + secondExportTable += 3; // skip header plus 2 bytes (secondExportTable is a uint16 pointer) + offset = READ_SCI11ENDIAN_UINT16(secondExportTable + pubfunct); + VERIFY(offset < _bufSize, "invalid export function pointer"); + } + } + return offset; } -byte *Script::findBlock(int type) { +byte *Script::findBlock(int type, int skipBlockIndex) { byte *buf = _buf; bool oldScriptHeader = (getSciVersion() == SCI_VERSION_0_EARLY); + int blockIndex = 0; if (oldScriptHeader) buf += 2; @@ -341,12 +361,13 @@ byte *Script::findBlock(int type) { if (seekerType == 0) break; - if (seekerType == type) + if (seekerType == type && blockIndex != skipBlockIndex) return buf; int seekerSize = READ_LE_UINT16(buf + 2); assert(seekerSize > 0); buf += seekerSize; + blockIndex++; } while (1); return NULL; diff --git a/engines/sci/engine/script.h b/engines/sci/engine/script.h index 3817f8aae1..c60cc4b19f 100644 --- a/engines/sci/engine/script.h +++ b/engines/sci/engine/script.h @@ -33,6 +33,7 @@ namespace Sci { struct EngineState; class ResourceManager; +struct SciScriptSignature; enum ScriptObjectTypes { SCI_OBJ_TERMINATOR, @@ -100,6 +101,10 @@ public: void init(int script_nr, ResourceManager *resMan); void load(ResourceManager *resMan); + void matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize); + int32 findSignature(const SciScriptSignature *signature, const byte *scriptData, const uint32 scriptSize); + void applyPatch(const uint16 *patch, byte *scriptData, const uint32 scriptSize, int32 signatureOffset); + virtual bool isValidOffset(uint16 offset) const; virtual SegmentRef dereference(reg_t pointer); virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr) const; @@ -242,7 +247,7 @@ public: /** * Finds the pointer where a block of a specific type starts from */ - byte *findBlock(int type); + byte *findBlock(int type, int skipBlockIndex = -1); private: /** diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp new file mode 100644 index 0000000000..77818dd138 --- /dev/null +++ b/engines/sci/engine/script_patches.cpp @@ -0,0 +1,565 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "sci/sci.h" +#include "sci/engine/script.h" + +#include "common/util.h" + +namespace Sci { + +#define PATCH_END 0xFFFF +#define PATCH_ADDTOOFFSET 0x8000 +#define PATCH_GETORIGINALBYTE 0x4000 +#define PATCH_MAGICDWORD(a, b, c, d) CONSTANT_LE_32(a | (b << 8) | (c << 16) | (d << 24)) + +struct SciScriptSignature { + uint16 scriptNr; + const char *description; + uint32 magicDWord; + int magicOffset; + const byte *data; + const uint16 *patch; +}; + +// signatures are built like this: +// - first a counter of the bytes that follow +// - then the actual bytes that need to get matched +// - then another counter of bytes (0 for EOS) +// - if not EOS, an adjust offset and the actual bytes +// - rinse and repeat + +// =========================================================================== +// stayAndHelp::changeState (0) is called when ego swims to the left or right +// boundaries of room 660. Normally a textbox is supposed to get on screen +// but the call is wrong, so not only do we get an error message the script +// is also hanging because the cue won't get sent out +// This also happens in sierra sci - ffs. bug #3038387 +const byte ecoquest1SignatureStayAndHelp[] = { + 40, + 0x3f, 0x01, // link 01 + 0x87, 0x01, // lap param[1] + 0x65, 0x14, // aTop state + 0x36, // push + 0x3c, // dup + 0x35, 0x00, // ldi 00 + 0x1a, // eq? + 0x31, 0x1c, // bnt [next state] + 0x76, // push0 + 0x45, 0x01, 0x00, // callb export1 from script 0 (switching control off) + 0x38, 0x22, 0x01, // pushi 0122 + 0x78, // push1 + 0x76, // push0 + 0x81, 0x00, // lag global[0] + 0x4a, 0x06, // send 06 - ego::setMotion(0) + 0x39, 0x6e, // pushi 6e (selector init) + 0x39, 0x04, // pushi 04 + 0x76, // push0 + 0x76, // push0 + 0x39, 0x17, // pushi 17 + 0x7c, // pushSelf + 0x51, 0x82, // class EcoNarrator + 0x4a, 0x0c, // send 0c - EcoNarrator::init(0, 0, 23, self) (BADLY BROKEN!) + 0x33, // jmp [end] + 0 +}; + +const uint16 ecoquest1PatchStayAndHelp[] = { + 0x87, 0x01, // lap param[1] + 0x65, 0x14, // aTop state + 0x36, // push + 0x2f, 0x22, // bt [next state] (this optimization saves 6 bytes) + 0x39, 0x00, // pushi 0 (wasting 1 byte here) + 0x45, 0x01, 0x00, // callb export1 from script 0 (switching control off) + 0x38, 0x22, 0x01, // pushi 0122 + 0x78, // push1 + 0x76, // push0 + 0x81, 0x00, // lag global[0] + 0x4a, 0x06, // send 06 - ego::setMotion(0) + 0x39, 0x6e, // pushi 6e (selector init) + 0x39, 0x06, // pushi 06 + 0x39, 0x02, // pushi 02 (additional 2 bytes) + 0x76, // push0 + 0x76, // push0 + 0x39, 0x17, // pushi 17 + 0x7c, // pushSelf + 0x38, 0x80, 0x02, // pushi 280 (additional 3 bytes) + 0x51, 0x82, // class EcoNarrator + 0x4a, 0x10, // send 10 - EcoNarrator::init(2, 0, 0, 23, self, 640) + PATCH_END +}; + +// script, description, magic DWORD, adjust +const SciScriptSignature ecoquest1Signatures[] = { + { 660, "CD: bad messagebox and freeze", PATCH_MAGICDWORD(0x38, 0x22, 0x01, 0x78), -17, ecoquest1SignatureStayAndHelp, ecoquest1PatchStayAndHelp }, + { 0, NULL, 0, 0, NULL, NULL } +}; + +// daySixBeignet::changeState (4) is called when the cop goes out and sets cycles to 220. +// this is not enough time to get to the door, so we patch that to 23 seconds +const byte gk1SignatureDay6PoliceBeignet[] = { + 4, + 0x35, 0x04, // ldi 04 + 0x1a, // eq? + 0x30, // bnt [next state check] + +2, 5, // [skip 2 bytes, offset of bnt] + 0x38, 0x93, 0x00, // pushi 93 (selector dispose) + 0x76, // push0 + 0x72, // lofsa deskSarg + +2, 9, // [skip 2 bytes, offset of lofsa] + 0x4a, 0x04, 0x00, // send 04 + 0x34, 0xdc, 0x00, // ldi 220 + 0x65, 0x1a, // aTop cycles + 0x32, // jmp [end] + 0 +}; + +const uint16 gk1PatchDay6PoliceBeignet[] = { + PATCH_ADDTOOFFSET | +16, + 0x34, 0x17, 0x00, // ldi 23 + 0x65, 0x1c, // aTop seconds + PATCH_END +}; + +// sargSleeping::changeState (8) is called when the cop falls asleep and sets cycles to 220. +// this is not enough time to get to the door, so we patch it to 42 seconds +const byte gk1SignatureDay6PoliceSleep[] = { + 4, + 0x35, 0x08, // ldi 08 + 0x1a, // eq? + 0x31, // bnt [next state check] + +1, 6, // [skip 1 byte, offset of bnt] + 0x34, 0xdc, 0x00, // ldi 220 + 0x65, 0x1a, // aTop cycles + 0x32, // jmp [end] + 0 +}; + +const uint16 gk1PatchDay6PoliceSleep[] = { + PATCH_ADDTOOFFSET | +5, + 0x34, 0x2a, 0x00, // ldi 42 + 0x65, 0x1c, // aTop seconds + PATCH_END +}; + +// startOfDay5::changeState (20h) - when gabriel goes to the phone the script will hang +const byte gk1SignatureDay5PhoneFreeze[] = { + 5, + 0x35, 0x03, // ldi 03 + 0x65, 0x1a, // aTop cycles + 0x32, // jmp [end] + +2, 3, // [skip 2 bytes, offset of jmp] + 0x3c, // dup + 0x35, 0x21, // ldi 21 + 0 +}; + +const uint16 gk1PatchDay5PhoneFreeze[] = { + 0x35, 0x06, // ldi 06 + 0x65, 0x20, // aTop ticks + PATCH_END +}; + +// script, description, magic DWORD, adjust +const SciScriptSignature gk1Signatures[] = { + { 212, "day 5 phone freeze", PATCH_MAGICDWORD(0x35, 0x03, 0x65, 0x1a), 0, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze }, + { 230, "day 6 police beignet timer issue", PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -16, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet }, + { 230, "day 6 police sleep timer issue", PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -5, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep }, + { 0, NULL, 0, 0, NULL, NULL } +}; + +// =========================================================================== +// this here gets called on entry and when going out of game windows +// uEvt::port will not get changed after kDisposeWindow but a bit later, so +// we would get an invalid port handle to a kSetPort call. We just patch in +// resetting of the port selector. We destroy the stop/fade code in there, +// it seems it isn't used at all in the game. +const byte hoyle4SignaturePortFix[] = { + 28, + 0x39, 0x09, // pushi 09 + 0x89, 0x0b, // lsg 0b + 0x39, 0x64, // pushi 64 + 0x38, 0xc8, 0x00, // pushi 00c8 + 0x38, 0x2c, 0x01, // pushi 012c + 0x38, 0x90, 0x01, // pushi 0190 + 0x38, 0xf4, 0x01, // pushi 01f4 + 0x38, 0x58, 0x02, // pushi 0258 + 0x38, 0xbc, 0x02, // pushi 02bc + 0x38, 0x20, 0x03, // pushi 0320 + 0x46, // calle [xxxx] [xxxx] [xx] + +5, 43, // [skip 5 bytes] + 0x30, 0x27, 0x00, // bnt 0027 -> end of routine + 0x87, 0x00, // lap 00 + 0x30, 0x19, 0x00, // bnt 0019 -> fade out + 0x87, 0x01, // lap 01 + 0x30, 0x14, 0x00, // bnt 0014 -> fade out + 0x38, 0xa7, 0x00, // pushi 00a7 + 0x76, // push0 + 0x80, 0x29, 0x01, // lag 0129 + 0x4a, 0x04, // send 04 (song::stop) + 0x39, 0x27, // pushi 27 + 0x78, // push1 + 0x8f, 0x01, // lsp 01 + 0x51, 0x54, // class 54 + 0x4a, 0x06, // send 06 (PlaySong::play) + 0x33, 0x09, // jmp 09 -> end of routine + 0x38, 0xaa, 0x00, // pushi 00aa + 0x76, // push0 + 0x80, 0x29, 0x01, // lag 0129 + 0x4a, 0x04, // send 04 + 0x48, // ret + 0 +}; + +const uint16 hoyle4PatchPortFix[] = { + PATCH_ADDTOOFFSET | +33, + 0x38, 0x31, 0x01, // pushi 0131 (selector curEvent) + 0x76, // push0 + 0x80, 0x50, 0x00, // lag 0050 (global var 80h, "User") + 0x4a, 0x04, // send 04 (read User::curEvent) + + 0x38, 0x93, 0x00, // pushi 0093 (selector port) + 0x78, // push1 + 0x76, // push0 + 0x4a, 0x06, // send 06 (write 0 to that object::port) + 0x48, // ret + PATCH_END +}; + +// script, description, magic DWORD, adjust +const SciScriptSignature hoyle4Signatures[] = { + { 0, "port fix when disposing windows", PATCH_MAGICDWORD(0x64, 0x38, 0xC8, 0x00), -5, hoyle4SignaturePortFix, hoyle4PatchPortFix }, + { 0, NULL, 0, 0, NULL, NULL } +}; + +// =========================================================================== +// at least during harpy scene export 29 of script 0 is called in kq5cd and +// has an issue for those calls, where temp 3 won't get inititialized, but +// is later used to set master volume. This issue makes sierra sci set +// the volume to max. We fix the export, so volume won't get modified in +// those cases. +const byte kq5SignatureCdHarpyVolume[] = { + 34, + 0x80, 0x91, 0x01, // lag global[191h] + 0x18, // not + 0x30, 0x2c, 0x00, // bnt [jump further] (jumping, if global 191h is 1) + 0x35, 0x01, // ldi 01 + 0xa0, 0x91, 0x01, // sag global[191h] (setting global 191h to 1) + 0x38, 0x7b, 0x01, // pushi 017b + 0x76, // push0 + 0x81, 0x01, // lag global[1] + 0x4a, 0x04, // send 04 (getting KQ5::masterVolume) + 0xa5, 0x03, // sat temp[3] (store volume in temp 3) + 0x38, 0x7b, 0x01, // pushi 017b + 0x76, // push0 + 0x81, 0x01, // lag global[1] + 0x4a, 0x04, // send 04 (getting KQ5::masterVolume) + 0x36, // push + 0x35, 0x04, // ldi 04 + 0x20, // ge? (followed by bnt) + 0 +}; + +const uint16 kq5PatchCdHarpyVolume[] = { + 0x38, 0x2f, 0x02, // pushi 022f (selector theVol) (3 new bytes) + 0x76, // push0 (1 new byte) + 0x51, 0x88, // class SpeakTimer (2 new bytes) + 0x4a, 0x04, // send 04 (2 new bytes) -> read SpeakTimer::theVol + 0xa5, 0x03, // sat temp[3] (2 new bytes) -> write to temp 3 + 0x80, 0x91, 0x01, // lag global[191h] + // saving 1 byte due optimization + 0x2e, 0x23, 0x00, // bt [jump further] (jumping, if global 191h is 1) + 0x35, 0x01, // ldi 01 + 0xa0, 0x91, 0x01, // sag global[191h] (setting global 191h to 1) + 0x38, 0x7b, 0x01, // pushi 017b + 0x76, // push0 + 0x81, 0x01, // lag global[1] + 0x4a, 0x04, // send 04 (getting KQ5::masterVolume) + 0xa5, 0x03, // sat temp[3] (store volume in temp 3) + // saving 8 bytes due removing of duplicate code + 0x39, 0x04, // pushi 04 (saving 1 byte due swapping) + 0x22, // lt? (because we switched values) + PATCH_END +}; + +// script, description, magic DWORD, adjust +const SciScriptSignature kq5Signatures[] = { + { 0, "CD: harpy volume change", PATCH_MAGICDWORD(0x80, 0x91, 0x01, 0x18), 0, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume }, + { 0, NULL, 0, 0, NULL, NULL } +}; + +// =========================================================================== +// this is called on every death dialog. Problem is at least the german +// version of lsl6 gets title text that is far too long for the +// available temp space resulting in temp space corruption +// This patch moves the title text around, so this overflow +// doesn't happen anymore. We would otherwise get a crash +// calling for invalid views (this happens of course also +// in sierra sci) +const byte larry6SignatureDeathDialog[] = { + 7, + 0x3e, 0x33, 0x01, // link 0133 (offset 0x20) + 0x35, 0xff, // ldi ff + 0xa3, 0x00, // sal 00 + +255, 0, + +255, 0, + +170, 12, // [skip 680 bytes] + 0x8f, 0x01, // lsp 01 (offset 0x2cf) + 0x7a, // push2 + 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e + 0x36, // push + 0x43, 0x7c, 0x0e, // kMessage[7c] 0e + +90, 10, // [skip 90 bytes] + 0x38, 0xd6, 0x00, // pushi 00d6 (offset 0x335) + 0x78, // push1 + 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e + 0x36, // push + +76, 11, // [skip 76 bytes] + 0x38, 0xcd, 0x00, // pushi 00cd (offset 0x38b) + 0x39, 0x03, // pushi 03 + 0x5a, 0x04, 0x00, 0x0e, 0x01, // lea 0004 010e + 0x36, + 0 +}; + +const uint16 larry6PatchDeathDialog[] = { + 0x3e, 0x00, 0x02, // link 0200 + PATCH_ADDTOOFFSET | +687, + 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140 + PATCH_ADDTOOFFSET | +98, + 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140 + PATCH_ADDTOOFFSET | +82, + 0x5a, 0x04, 0x00, 0x40, 0x01, // lea 0004 0140 + PATCH_END +}; + +// script, description, magic DWORD, adjust +const SciScriptSignature larry6Signatures[] = { + { 82, "death dialog memory corruption", PATCH_MAGICDWORD(0x3e, 0x33, 0x01, 0x35), 0, larry6SignatureDeathDialog, larry6PatchDeathDialog }, + { 0, NULL, 0, 0, NULL, NULL } +}; + +// =========================================================================== +// rm560::doit was supposed to close the painting, when heimlich enters the +// room. The code is buggy, so it actually closes the painting, when heimlich +// is not in the room. We fix that. +const byte laurabow2SignaturePaintingClosing[] = { + 17, + 0x4a, 0x04, // send 04 (gets aHeimlich::room) + 0x36, // push + 0x81, 0x0b, // lag global[11d] -> current room + 0x1c, // ne? + 0x31, 0x0e, // bnt [don't close] + 0x35, 0x00, // ldi 00 + 0xa3, 0x00, // sal local[0] + 0x38, 0x92, 0x00, // pushi 0092 + 0x78, // push1 + 0x72, // lofsa sDumpSafe + 0 +}; + +const uint16 laurabow2PatchPaintingClosing[] = { + PATCH_ADDTOOFFSET | +6, + 0x2f, 0x0e, // bt [don't close] + PATCH_END +}; + +// script, description, magic DWORD, adjust +const SciScriptSignature laurabow2Signatures[] = { + { 560, "painting closing immediately", PATCH_MAGICDWORD(0x36, 0x81, 0x0b, 0x1c), -2, laurabow2SignaturePaintingClosing, laurabow2PatchPaintingClosing }, + { 0, NULL, 0, 0, NULL, NULL } +}; + +// =========================================================================== +// script 298 of sq4/floppy has an issue. object "nest" uses another property +// which isn't included in property count. We return 0 in that case, the game +// adds it to nest::x. The problem is that the script also checks if x exceeds +// we never reach that of course, so the pterodactyl-flight will go endlessly +// we could either calculate property count differently somehow fixing this +// but I think just patching it out is cleaner (ffs. bug #3037938) +const byte sq4FloppySignatureEndlessFlight[] = { + 8, + 0x39, 0x04, // pushi 04 (selector x) + 0x78, // push1 + 0x67, 0x08, // pTos 08 (property x) + 0x63, 0x44, // pToa 44 (invalid property) + 0x02, // add + 0 +}; + +const uint16 sq4FloppyPatchEndlessFlight[] = { + PATCH_ADDTOOFFSET | +5, + 0x35, 0x03, // ldi 03 (which would be the content of the property) + PATCH_END +}; + +// script, description, magic DWORD, adjust +const SciScriptSignature sq4Signatures[] = { + { 298, "Floppy: endless flight", PATCH_MAGICDWORD(0x67, 0x08, 0x63, 0x44), -3, sq4FloppySignatureEndlessFlight, sq4FloppyPatchEndlessFlight }, + { 0, NULL, 0, 0, NULL, NULL } +}; + +// =========================================================================== +// It seems to scripts warp ego outside the screen somehow (or maybe kDoBresen?) +// ego::mover is set to 0 and rm119::doit will crash in that case. This here +// fixes part of the problem and actually checks ego::mover to be 0 and skips +// TODO: this should get further investigated by waltervn and maybe properly +// patched. For now ego will shortly disappear and reappear a bit after +// this isn't good, but sierra sci also "crashed" (endless looped) so this +// is at least better than the original code +const byte sq5SignatureScrubbing[] = { + 19, + 0x18, // not + 0x31, 0x37, // bnt 37 + 0x78, // push1 (selector x) + 0x76, // push0 + 0x39, 0x38, // pushi 38 (selector mover) + 0x76, // push0 + 0x81, 0x00, // lag 00 + 0x4a, 0x04, // send 04 (read ego::mover) + 0x4a, 0x04, // send 04 (read ego::mover::x) + 0x36, // push + 0x34, 0xa0, 0x00, // ldi 00a0 + 0x1c, // ne? + 0 +}; + +const uint16 sq5PatchScrubbing[] = { + 0x18, // not + 0x31, 0x37, // bnt 37 +// 0x2f, 0x38, // bt 37 (would save another byte, isn't needed + 0x39, 0x38, // pushi 38 (selector mover) + 0x76, // push0 + 0x81, 0x00, // lag 00 + 0x4a, 0x04, // send 04 (read ego::mover) + 0x31, 0x2e, // bnt 2e (jump if ego::mover is 0) + 0x78, // push1 (selector x) + 0x76, // push0 + 0x4a, 0x04, // send 04 (read ego::mover::x) + 0x39, 0xa0, // pushi a0 (saving 2 bytes) + 0x1c, // ne? + PATCH_END +}; + +// script, description, magic DWORD, adjust +const SciScriptSignature sq5Signatures[] = { + { 119, "scrubbing send crash", PATCH_MAGICDWORD(0x18, 0x31, 0x37, 0x78), 0, sq5SignatureScrubbing, sq5PatchScrubbing }, + { 0, NULL, 0, 0, NULL, NULL } +}; + + +// will actually patch previously found signature area +void Script::applyPatch(const uint16 *patch, byte *scriptData, const uint32 scriptSize, int32 signatureOffset) { + int32 offset = signatureOffset; + uint16 patchWord = *patch; + + while (patchWord != PATCH_END) { + if (patchWord & PATCH_ADDTOOFFSET) { + offset += patchWord & ~PATCH_ADDTOOFFSET; + } else if (patchWord & PATCH_GETORIGINALBYTE) { + // TODO: implement this + } else { + scriptData[offset] = patchWord & 0xFF; + offset++; + } + patch++; + patchWord = *patch; + } +} + +// will return -1 if no match was found, otherwise an offset to the start of the signature match +int32 Script::findSignature(const SciScriptSignature *signature, const byte *scriptData, const uint32 scriptSize) { + if (scriptSize < 4) // we need to find a DWORD, so less than 4 bytes is not okay + return -1; + + const uint32 magicDWord = signature->magicDWord; // is platform-specific BE/LE form, so that the later match will work + const uint32 searchLimit = scriptSize - 3; + uint32 DWordOffset = 0; + // first search for the magic DWORD + while (DWordOffset < searchLimit) { + if (magicDWord == *(const uint32 *)(scriptData + DWordOffset)) { + // magic DWORD found, check if actual signature matches + uint32 offset = DWordOffset + signature->magicOffset; + uint32 byteOffset = offset; + const byte *signatureData = signature->data; + byte matchAdjust = 1; + while (matchAdjust) { + byte matchBytesCount = *signatureData++; + if ((byteOffset + matchBytesCount) > scriptSize) // Out-Of-Bounds? + break; + if (memcmp(signatureData, &scriptData[byteOffset], matchBytesCount)) // Byte-Mismatch? + break; + // those bytes matched, adjust offsets accordingly + signatureData += matchBytesCount; + byteOffset += matchBytesCount; + // get offset... + matchAdjust = *signatureData++; + byteOffset += matchAdjust; + } + if (!matchAdjust) // all matches worked? + return offset; + } + DWordOffset++; + } + // nothing found + return -1; +} + +void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) { + const SciScriptSignature *signatureTable = NULL; + if (g_sci->getGameId() == GID_ECOQUEST) + signatureTable = ecoquest1Signatures; + if (g_sci->getGameId() == GID_GK1) + signatureTable = gk1Signatures; +// hoyle4 now works due workaround inside GfxPorts +// if (g_sci->getGameId() == GID_HOYLE4) +// signatureTable = hoyle4Signatures; + if (g_sci->getGameId() == GID_KQ5) + signatureTable = kq5Signatures; + if (g_sci->getGameId() == GID_LAURABOW2) + signatureTable = laurabow2Signatures; + if (g_sci->getGameId() == GID_LSL6) + signatureTable = larry6Signatures; + if (g_sci->getGameId() == GID_SQ4) + signatureTable = sq4Signatures; + if (g_sci->getGameId() == GID_SQ5) + signatureTable = sq5Signatures; + + if (signatureTable) { + while (signatureTable->data) { + if (scriptNr == signatureTable->scriptNr) { + int32 foundOffset = findSignature(signatureTable, scriptData, scriptSize); + if (foundOffset != -1) { + // found, so apply the patch + warning("matched and patched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset); + applyPatch(signatureTable->patch, scriptData, scriptSize, foundOffset); + } + } + signatureTable++; + } + } +} + +} // End of namespace Sci diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index cb908979a3..b16dd5a5e5 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -414,7 +414,7 @@ int Object::locateVarSelector(SegManager *segMan, Selector slc) const { } else { const Object *obj = getClass(segMan); varnum = obj->getVariable(1).toUint16(); - buf = (byte *)obj->_baseVars; + buf = (const byte *)obj->_baseVars; } for (uint i = 0; i < varnum; i++) diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 7bcc5b43a3..0500cc601b 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -75,7 +75,6 @@ static ExecStack *add_exec_stack_entry(Common::List<ExecStack> &execStack, reg_t reg_t objp, int argc, StackPtr argp, Selector selector, int exportId, int localCallOffset, reg_t sendp, int origin, SegmentId local_segment); - /** * Adds one varselector access to the execution stack. * This function is called from send_selector only. @@ -93,8 +92,6 @@ static ExecStack *add_exec_stack_varselector(Common::List<ExecStack> &execStack, int origin); - - // validation functionality static reg_t &validate_property(Object *obj, int index) { @@ -103,14 +100,10 @@ static reg_t &validate_property(Object *obj, int index) { // may modify the value of the returned reg_t. static reg_t dummyReg = NULL_REG; - // FIXME/TODO: Where does this occur? Returning a dummy reg here could lead - // to all sorts of issues! Turned it into an error for now... // If this occurs, it means there's probably something wrong with the garbage // collector, so don't hide it with fake return values - if (!obj) { + if (!obj) error("validate_property: Sending to disposed object"); - //return dummyReg; - } if (index < 0 || (uint)index >= obj->getVarCount()) { // This is same way sierra does it and there are some games, that contain such scripts like @@ -136,12 +129,7 @@ static int validate_arithmetic(reg_t reg) { if (reg.segment) { // The results of this are likely unpredictable... It most likely means that a kernel function is returning something wrong. // If such an error occurs, we usually need to find the last kernel function called and check its return value. - if (g_sci->getGameId() == GID_QFG2 && g_sci->getEngineState()->currentRoomNumber() == 200) { - // WORKAROUND: This happens in QFG2, room 200, when talking to the astrologer (bug #3039879) - script bug. - // Returning 0 in this case. - } else { - error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]. Address: %04x:%04x", reg.segment, PRINT_REG(reg)); - } + error("[VM] Attempt to read arithmetic value from non-zero segment [%04x]. Address: %04x:%04x", reg.segment, PRINT_REG(reg)); return 0; } @@ -171,11 +159,6 @@ static bool validate_variable(reg_t *r, reg_t *stack_base, int type, int max, in error("%s. [VM] Access would be outside even of the stack (%d); access denied", txt.c_str(), total_offset); return false; } else { - // WORKAROUND: Mixed-Up Mother Goose tries to use an invalid parameter in Event::new(). - // Just skip around it here so we don't error out in validate_arithmetic. - if (g_sci->getGameId() == GID_MOTHERGOOSE && type == VAR_PARAM && index == 1) - return false; - debugC(2, kDebugLevelVM, "%s", txt.c_str()); debugC(2, kDebugLevelVM, "[VM] Access within stack boundaries; access granted."); return true; @@ -434,7 +417,9 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt printSendActions = g_sci->checkSelectorBreakpoint(send_obj, selector); #ifdef VM_DEBUG_SEND - printf("Send to %04x:%04x, selector %04x (%s):", PRINT_REG(send_obj), selector, g_sci->getKernel()->getSelectorName(selector).c_str()); + printf("Send to %04x:%04x (%s), selector %04x (%s):", PRINT_REG(send_obj), + s->_segMan->getObjectName(send_obj), selector, + g_sci->getKernel()->getSelectorName(selector).c_str()); #endif // VM_DEBUG_SEND ObjVarRef varp; @@ -462,7 +447,9 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt if (printSendActions && argc) { reg_t oldReg = *varp.getPointer(s->_segMan); reg_t newReg = argp[1]; - debug("[write to selector: change %04x:%04x to %04x:%04x]\n", PRINT_REG(oldReg), PRINT_REG(newReg)); + warning("[write to selector (%s:%s): change %04x:%04x to %04x:%04x]\n", + s->_segMan->getObjectName(send_obj), g_sci->getKernel()->getSelectorName(selector).c_str(), + PRINT_REG(oldReg), PRINT_REG(newReg)); printSendActions = false; } @@ -1144,7 +1131,7 @@ void run_vm(EngineState *s) { if (validate_unsignedInteger(r_temp, value1) && validate_unsignedInteger(s->r_acc, value2)) s->r_acc = make_reg(0, value1 & value2); else - s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc); + s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeAndWorkarounds, r_temp, s->r_acc); break; } @@ -1265,7 +1252,7 @@ void run_vm(EngineState *s) { if (validate_signedInteger(r_temp, compare1) && validate_signedInteger(s->r_acc, compare2)) s->r_acc = make_reg(0, compare1 <= compare2); else - s->r_acc = arithmetic_lookForWorkaround(opcode, NULL, r_temp, s->r_acc); + s->r_acc = arithmetic_lookForWorkaround(opcode, opcodeLeWorkarounds, r_temp, s->r_acc); } break; @@ -1809,24 +1796,32 @@ void run_vm(EngineState *s) { case op_lagi: // 0x48 (72) case op_lali: // 0x49 (73) case op_lati: // 0x4a (74) - case op_lapi: // 0x4b (75) + case op_lapi: { // 0x4b (75) // Load global, local, temp or param variable into the accumulator, // using the accumulator as an additional index var_type = opcode & 0x3; // Gets the variable type: g, l, t or p - var_number = opparams[0] + signed_validate_arithmetic(s->r_acc); + int16 value; + if (!validate_signedInteger(s->r_acc, value)) + value = arithmetic_lookForWorkaround(opcode, opcodeLaiWorkarounds, s->r_acc, NULL_REG).offset; + var_number = opparams[0] + value; s->r_acc = READ_VAR(var_type, var_number); break; + } case op_lsgi: // 0x4c (76) case op_lsli: // 0x4d (77) case op_lsti: // 0x4e (78) - case op_lspi: // 0x4f (79) + case op_lspi: { // 0x4f (79) // Load global, local, temp or param variable into the stack, // using the accumulator as an additional index var_type = opcode & 0x3; // Gets the variable type: g, l, t or p - var_number = opparams[0] + signed_validate_arithmetic(s->r_acc); + int16 value; + if (!validate_signedInteger(s->r_acc, value)) + value = arithmetic_lookForWorkaround(opcode, opcodeLsiWorkarounds, s->r_acc, NULL_REG).offset; + var_number = opparams[0] + value; PUSH32(READ_VAR(var_type, var_number)); break; + } case op_sag: // 0x50 (80) case op_sal: // 0x51 (81) diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index bc6d457f7f..95674ceaad 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -53,14 +53,39 @@ const SciWorkaroundEntry opcodeGeWorkarounds[] = { }; // gameID, room,script,lvl, object-name, method-name, call,index, workaround +const SciWorkaroundEntry opcodeLeWorkarounds[] = { + { GID_PEPPER, 370, 23, 0, "eastExitFeature", "onMe", -1, 0, { WORKAROUND_FAKE, 1 } }, // Pugh's office, when trying to use either the left or right exits, gets called on an integer and a pointer - bug #3040142 + SCI_WORKAROUNDENTRY_TERMINATOR +}; + +// gameID, room,script,lvl, object-name, method-name, call,index, workaround +const SciWorkaroundEntry opcodeLaiWorkarounds[] = { + { GID_CAMELOT, 92, 92, 0, "endingCartoon2", "changeState", 0x20d, 0, { WORKAROUND_FAKE, 0 } }, // during the ending, sub gets called with no parameters, uses parameter 1 which is theGrail in this case - bug #3044734 + SCI_WORKAROUNDENTRY_TERMINATOR +}; + +// gameID, room,script,lvl, object-name, method-name, call,index, workaround +const SciWorkaroundEntry opcodeLsiWorkarounds[] = { + { GID_QFG2, 200, 200, 0, "astro", "messages", -1, 0, { WORKAROUND_FAKE, 0 } }, // when getting asked for your name by the astrologer bug #3039879 + SCI_WORKAROUNDENTRY_TERMINATOR +}; + +// gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry opcodeMulWorkarounds[] = { { GID_FANMADE, 516, 983, 0, "Wander", "setTarget", -1, 0, { WORKAROUND_FAKE, 0 } }, // The Legend of the Lost Jewel Demo (fan made): called with object as second parameter when attacked by insects - bug #3038913 SCI_WORKAROUNDENTRY_TERMINATOR }; // gameID, room,script,lvl, object-name, method-name, call,index, workaround +const SciWorkaroundEntry opcodeAndWorkarounds[] = { + { GID_MOTHERGOOSE, -1, 999, 0, "Event", "new", -1, 0, { WORKAROUND_FAKE, 0 } }, // constantly during the game + // ^^ TODO: which of the mother goose versions is affected by this? EGA? SCI1? SCI1.1? + SCI_WORKAROUNDENTRY_TERMINATOR +}; + +// gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry opcodeOrWorkarounds[] = { - { GID_ECOQUEST2, 100, 0, 0, "Rain", "points", 0xcc6, 0, { WORKAROUND_FAKE, 0 } }, // when giving the papers to the customs officer, gets called against a pointer instead of a number - bug #3034464 + { GID_ECOQUEST2, 100, 0, 0, "Rain", "points", 0xcc6, 0, { WORKAROUND_FAKE, 0 } }, // when giving the papers to the customs officer, gets called against a pointer instead of a number - bug #3034464 SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -71,11 +96,12 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = { { GID_CNICK_KQ, 200, 0, 1, "Character", "<noname446>", -1, 505, { WORKAROUND_FAKE, 0 } }, // checkers, like in hoyle 3 { GID_CNICK_KQ, -1, 700, 0, "gcWindow", "<noname183>", -1, -1, { WORKAROUND_FAKE, 0 } }, // when entering control menu, like in hoyle 3 { GID_CNICK_LONGBOW, 0, 0, 0, "RH Budget", "<noname110>", -1, 1, { WORKAROUND_FAKE, 0 } }, // when starting the game - { GID_ECOQUEST, -1, -1, 0, NULL, "doVerb", -1, 0, { WORKAROUND_FAKE, 0 } }, // almost clicking anywhere triggers this in almost all rooms + { GID_ECOQUEST, -1, -1, 0, NULL, "doVerb", -1, 0, { WORKAROUND_FAKE, 0 } }, // almost clicking anywhere triggers this in almost all rooms { GID_FANMADE, 516, 979, 0, "", "export 0", -1, 20, { WORKAROUND_FAKE, 0 } }, // Happens in Grotesteing after the logos { GID_FANMADE, 528, 990, 0, "GDialog", "doit", -1, 4, { WORKAROUND_FAKE, 0 } }, // Happens in Cascade Quest when closing the glossary - bug #3038757 { GID_FREDDYPHARKAS, -1, 24, 0, "gcWin", "open", -1, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu { GID_FREDDYPHARKAS, -1, 31, 0, "quitWin", "open", -1, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu + { GID_FREDDYPHARKAS, 540, 540, 0, "WaverCode", "init", -1, -1, { WORKAROUND_FAKE, 0 } }, // Gun pratice mini-game (bug #3044218) { GID_GK1, -1, 64950, -1, "Feature", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // sometimes when walk-clicking { GID_GK2, -1, 11, 0, "", "export 10", -1, 3, { WORKAROUND_FAKE, 0 } }, // called when the game starts { GID_GK2, -1, 11, 0, "", "export 10", -1, 4, { WORKAROUND_FAKE, 0 } }, // called during the game @@ -85,7 +111,9 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = { { GID_HOYLE3, -1, 0, 1, "Character", "say", -1, 505, { WORKAROUND_FAKE, 0 } }, // when starting checkers or dominoes, first time a character says something { GID_HOYLE3, -1, 700, 0, "gcWindow", "open", -1, -1, { WORKAROUND_FAKE, 0 } }, // when entering control menu { GID_HOYLE4, -1, 0, 0, "gcWindow", "open", -1, -1, { WORKAROUND_FAKE, 0 } }, // when selecting "Control" from the menu (temp vars 0-3) - bug #3039294 + { GID_HOYLE4, 910, 18, 0, "Tray", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // during tutorial - bug #3042756 { GID_HOYLE4, 910, 910, 0, "IconBarList", "setup", -1, 3, { WORKAROUND_FAKE, 0 } }, // when selecting "Tutorial" from the main menu - bug #3039294 + { GID_ISLANDBRAIN, 100, 937, 0, "IconBar", "dispatchEvent", -1, 58, { WORKAROUND_FAKE, 0 } }, // when using ENTER at the startup menu - bug #3045225 { GID_ISLANDBRAIN, 140, 140, 0, "piece", "init", -1, 3, { WORKAROUND_FAKE, 1 } }, // first puzzle right at the start, some initialization variable. bnt is done on it, and it should be non-0 { GID_ISLANDBRAIN, 200, 268, 0, "anElement", "select", -1, 0, { WORKAROUND_FAKE, 0 } }, // elements puzzle, gets used before super TextIcon { GID_JONES, 1, 232, 0, "weekendText", "draw", 0x3d3, 0, { WORKAROUND_FAKE, 0 } }, // jones/cd only - gets called during the game @@ -93,8 +121,10 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = { { GID_JONES, 1, 255, 0, "", "export 0", -1, 14, { WORKAROUND_FAKE, 0 } }, // jones/cd only - called when a game ends { GID_JONES, 764, 255, 0, "", "export 0", -1, 13, { WORKAROUND_FAKE, 0 } }, // jones/ega&vga only - called when the game starts { GID_JONES, 764, 255, 0, "", "export 0", -1, 14, { WORKAROUND_FAKE, 0 } }, // jones/ega&vga only - called when the game starts - { GID_KQ5, -1, 0, 0, "", "export 29", -1, 3, { WORKAROUND_FAKE, 0 } }, // called when playing harp for the harpies or when aborting dialog in toy shop, is used for kDoAudio - bug #3034700 + //{ GID_KQ5, -1, 0, 0, "", "export 29", -1, 3, { WORKAROUND_FAKE, 0xf } }, // called when playing harp for the harpies or when aborting dialog in toy shop, is used for kDoAudio - bug #3034700 + // ^^ shouldn't be needed anymore, we got a script patch instead (kq5PatchCdHarpyVolume) { GID_KQ5, 25, 25, 0, "rm025", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // inside witch forest, when going to the room where the walking rock is + { GID_KQ5, 55, 55, 0, "helpScript", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // when giving the tambourine to the monster in the labyrinth (only happens at one of the locations) - bug #3041262 { GID_KQ6, -1, 30, 0, "rats", "changeState", -1, -1, { WORKAROUND_FAKE, 0 } }, // rats in the catacombs (temps 1 - 5) - bugs #3034597, #3035495, #3035824 { GID_KQ6, 210, 210, 0, "rm210", "scriptCheck", -1, 0, { WORKAROUND_FAKE, 1 } }, // using inventory in that room - bug #3034565 { GID_KQ6, 500, 500, 0, "rm500", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // going to island of the beast @@ -105,6 +135,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = { { GID_LAURABOW, -1, 967, 0, "myIcon", "cycle", -1, 1, { WORKAROUND_FAKE, 0 } }, // having any portrait conversation coming up (initial bug #3034985) { GID_LAURABOW2, -1, 24, 0, "gcWin", "open", -1, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu { GID_LAURABOW2, -1, 21, 0, "dropCluesCode", "doit", -1, 1, { WORKAROUND_FAKE, 0x7fff } }, // when asking some questions (e.g. the reporter about the burglary, or the policeman about Ziggy). Must be big, as the game scripts perform lt on it and start deleting journal entries - bugs #3035068, #3036274 + { GID_LAURABOW2, -1, 90, 1, "MuseumActor", "init", -1, 6, { WORKAROUND_FAKE, 0 } }, // Random actors in museum (bug #3041257) { GID_LAURABOW2, 240, 240, 0, "sSteveAnimates", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // Steve Dorian's idle animation at the docks - bug #3036291 { GID_LONGBOW, -1, 213, 0, "clear", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // When giving an answer using the druid hand sign code in any room { GID_LONGBOW, -1, 213, 0, "letter", "handleEvent", 0xa8, 1, { WORKAROUND_FAKE, 0 } }, // When using the druid hand sign code in any room - bug #3036601 @@ -119,24 +150,31 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = { { GID_LSL6HIRES, 0, 85, 0, "LL6Inv", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // on startup { GID_LSL6HIRES, -1, 64950, 1, "Feature", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // at least when entering swimming pool area { GID_LSL6HIRES, -1, 64964, 0, "DPath", "init", -1, 1, { WORKAROUND_FAKE, 0 } }, // during the game + { GID_MOTHERGOOSE, -1, 0, 0, "MG", "doit", -1, 5, { WORKAROUND_FAKE, 0 } }, // SCI1.1: When moving the cursor all the way to the left during the game (bug #3043955) { GID_MOTHERGOOSE, 18, 992, 0, "AIPath", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // DEMO: Called when walking north from mother goose's house two screens { GID_MOTHERGOOSEHIRES,-1,64950, 1, "Feature", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // right when clicking on a child at the start and probably also later { GID_MOTHERGOOSEHIRES,-1,64950, 1, "View", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // see above + { GID_PEPPER, -1, 894, 0, "Package", "doVerb", -1, 3, { WORKAROUND_FAKE, 0 } }, // using the hand on the book in the inventory - bug #3040012 { GID_QFG1, -1, 210, 0, "Encounter", "init", 0xbd0, 0, { WORKAROUND_FAKE, 0 } }, // hq1: going to the brigands hideout { GID_QFG1, -1, 210, 0, "Encounter", "init", 0xbe4, 0, { WORKAROUND_FAKE, 0 } }, // qfg1: going to the brigands hideout { GID_QFG2, -1, 71, 0, "theInvSheet", "doit", -1, 1, { WORKAROUND_FAKE, 0 } }, // accessing the inventory { GID_QFG2, -1, 701, -1, "Alley", "at", -1, 0, { WORKAROUND_FAKE, 0 } }, // when walking inside the alleys in the town - bug #3035835 & #3038367 { GID_QFG2, -1, 990, 0, "Restore", "doit", -1, 364, { WORKAROUND_FAKE, 0 } }, // when pressing enter in restore dialog w/o any saved games present - { GID_QFG2, 260, 260, 0, "abdulS", "changeState",0x2d22, -1, { WORKAROUND_FAKE, 0 } }, // During the thief's first mission (in the house), just before the second brother is about to enter the house (where you have to hide in the wardrobe), bug #3039891, temps 1 and 2 + { GID_QFG2, 260, 260, 0, "abdulS", "changeState",0x2d22, -1, { WORKAROUND_FAKE, 0 } }, // During the thief's first mission (in the house), just before Abdul is about to enter the house (where you have to hide in the wardrobe), bug #3039891, temps 1 and 2 + { GID_QFG2, 260, 260, 0, "jabbarS", "changeState",0x2d22, -1, { WORKAROUND_FAKE, 0 } }, // During the thief's first mission (in the house), just before Jabbar is about to enter the house (where you have to hide in the wardrobe), bug #3040469, temps 1 and 2 + { GID_QFG3, 140, 140, 0, "rm140", "init", 0x1008, 0, { WORKAROUND_FAKE, 0 } }, // when importing a character and selecting the previous profession - bug #3040460 { GID_QFG3, 330, 330, -1, "Teller", "doChild", -1, -1, { WORKAROUND_FAKE, 0 } }, // when talking to King Rajah about "Rajah" (bug #3036390, temp 1) or "Tarna" (temp 0), or when clicking on yourself and saying "Greet" (bug #3039774, temp 1) + { GID_QFG3, 700, 700, -1, "monsterIsDead", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // in the jungle, after winning any fight, bug #3040624 + { GID_QFG3, 470, 470, -1, "rm470", "notify", -1, 0, { WORKAROUND_FAKE, 0 } }, // closing the character screen in the Simbani village in the room with the bridge, bug #3040565 + { GID_QFG3, 490, 490, -1, "computersMove", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // when finishing awari game, bug #3040579 { GID_QFG4, -1, 15, -1, "charInitScreen", "dispatchEvent", -1, 5, { WORKAROUND_FAKE, 0 } }, // floppy version, when viewing the character screen { GID_QFG4, -1, 64917, -1, "controlPlane", "setBitmap", -1, 3, { WORKAROUND_FAKE, 0 } }, // floppy version, when entering the game menu { GID_QFG4, -1, 64917, -1, "Plane", "setBitmap", -1, 3, { WORKAROUND_FAKE, 0 } }, // floppy version, happen sometimes in fights { GID_SQ1, 103, 103, 0, "hand", "internalEvent", -1, -1, { WORKAROUND_FAKE, 0 } }, // Spanish (and maybe early versions?) only: when moving cursor over input pad, temps 1 and 2 { GID_SQ1, -1, 703, 0, "", "export 1", -1, 0, { WORKAROUND_FAKE, 0 } }, // sub that's called from several objects while on sarien battle cruiser { GID_SQ1, -1, 703, 0, "firePulsar", "changeState", 0x18a, 0, { WORKAROUND_FAKE, 0 } }, // export 1, but called locally (when shooting at aliens) - { GID_SQ4, -1, 398, 0, "showBox", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // sq4cd: called when rummaging in Software Excess bargain bin - { GID_SQ4, -1, 928, 0, "Narrator", "startText", -1, 1000, { WORKAROUND_FAKE, 1 } }, // sq4cd: method returns this to the caller + { GID_SQ4, -1, 398, 0, "showBox", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // CD: called when rummaging in Software Excess bargain bin + { GID_SQ4, -1, 928, 0, "Narrator", "startText", -1, 1000, { WORKAROUND_FAKE, 1 } }, // CD: method returns this to the caller { GID_SQ5, 201, 201, 0, "buttonPanel", "doVerb", -1, 0, { WORKAROUND_FAKE, 1 } }, // when looking at the orange or red button - bug #3038563 { GID_SQ6, 100, 0, 0, "SQ6", "init", -1, 2, { WORKAROUND_FAKE, 0 } }, // called when the game starts { GID_SQ6, 100, 64950, 0, "View", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // called when pressing "Start game" in the main menu @@ -149,21 +187,22 @@ const SciWorkaroundEntry kAbs_workarounds[] = { { GID_HOYLE1, 1, 1, 0, "room1", "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // crazy eights - called with objects instead of integers { GID_HOYLE1, 2, 2, 0, "room2", "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // old maid - called with objects instead of integers { GID_HOYLE1, 3, 3, 0, "room3", "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // hearts - called with objects instead of integers + { GID_QFG1VGA, -1, -1, 0, NULL, "doit", -1, 0, { WORKAROUND_FAKE, 0x3e9 } }, // when the game is patched with the NRS patch SCI_WORKAROUNDENTRY_TERMINATOR }; // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kCelHigh_workarounds[] = { - { GID_KQ5, -1, 255, 0, "deathIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // english floppy: when getting beaten up in the inn and probably more, called with 2nd parameter as object - bug #3037003 - { GID_PQ2, -1, 255, 0, "DIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when showing picture within windows, called with 2nd/3rd parameters as objects + { GID_KQ5, -1, 255, 0, "deathIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // english floppy: when getting beaten up in the inn and probably more, called with 2nd parameter as object - bug #3037003 + { GID_PQ2, -1, 255, 0, "DIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when showing picture within windows, called with 2nd/3rd parameters as objects { GID_SQ1, 1, 255, 0, "DIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // DEMO: Called with 2nd/3rd parameters as objects when clicking on the menu - bug #3035720 SCI_WORKAROUNDENTRY_TERMINATOR }; // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kCelWide_workarounds[] = { - { GID_KQ5, -1, 255, 0, "deathIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // english floppy: when getting beaten up in the inn and probably more, called with 2nd parameter as object - bug #3037003 - { GID_PQ2, -1, 255, 0, "DIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when showing picture within windows, called with 2nd/3rd parameters as objects + { GID_KQ5, -1, 255, 0, "deathIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // english floppy: when getting beaten up in the inn and probably more, called with 2nd parameter as object - bug #3037003 + { GID_PQ2, -1, 255, 0, "DIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when showing picture within windows, called with 2nd/3rd parameters as objects { GID_SQ1, 1, 255, 0, "DIcon", "setSize", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // DEMO: Called with 2nd/3rd parameters as objects when clicking on the menu - bug #3035720 SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -185,9 +224,12 @@ const SciWorkaroundEntry kDeviceInfo_workarounds[] = { const SciWorkaroundEntry kDisplay_workarounds[] = { { GID_ISLANDBRAIN, 300, 300, 0, "geneDude", "show", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when looking at the gene explanation chart - a parameter is an object { GID_PQ2, 23, 23, 0, "rm23Script", "elements", 0x4ae, 0, { WORKAROUND_IGNORE, 0 } }, // when looking at the 2nd page of pate's file - 0x75 as id + { GID_PQ2, 23, 23, 0, "rm23Script", "elements", 0x4c1, 0, { WORKAROUND_IGNORE, 0 } }, // when looking at the 2nd page of pate's file - 0x75 as id (another pq2 version, bug #3043904) { GID_QFG1, 11, 11, 0, "battle", "<noname90>", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: When entering battle, 0x75 as id - { GID_SQ4, 391, 391, 0, "doCatalog", "mode", 0x84, 0, { WORKAROUND_IGNORE, 0 } }, // clicking on catalog in roboter sale - a parameter is an object - { GID_SQ4, 391, 391, 0, "choosePlug", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // ordering connector in roboter sale - a parameter is an object + { GID_SQ1, -1, 700, 0, "arcadaRegion", "doit", -1, 0, { WORKAROUND_IGNORE, 0 } }, // restoring in some rooms of the arcada (right at the start) + { GID_SQ4, 397, 0, 0, "", "export 12", -1, 0, { WORKAROUND_IGNORE, 0 } }, // FLOPPY: when going into the computer store (bug #3044044) + { GID_SQ4, 391, 391, 0, "doCatalog", "mode", 0x84, 0, { WORKAROUND_IGNORE, 0 } }, // CD: clicking on catalog in roboter sale - a parameter is an object + { GID_SQ4, 391, 391, 0, "choosePlug", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // CD: ordering connector in roboter sale - a parameter is an object SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -214,7 +256,7 @@ const SciWorkaroundEntry kDoSoundFade_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kGetAngle_workarounds[] = { { GID_FANMADE, 516, 992, 0, "Motion", "init", -1, 0, { WORKAROUND_IGNORE, 0 } }, // The Legend of the Lost Jewel Demo (fan made): called with third/fourth parameters as objects - { GID_KQ6, 740, 752, 0, "throwDazzle", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // after the Genie is exposed in the Palace (short and long ending), it starts shooting lightning bolts around. An extra 5th parameter is passed - bug #3034610 + { GID_KQ6, -1, 752, 0, "throwDazzle", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // room 740/790 after the Genie is exposed in the Palace (short and long ending), it starts shooting lightning bolts around. An extra 5th parameter is passed - bug #3034610 & #3041734 SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -228,6 +270,8 @@ const SciWorkaroundEntry kFindKey_workarounds[] = { const SciWorkaroundEntry kGraphDrawLine_workarounds[] = { { GID_ISLANDBRAIN, 300, 300, 0, "dudeViewer", "show", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when looking at the gene explanation chart, gets called with 1 extra parameter { GID_SQ1, 43, 43, 0, "someoneDied", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when ordering beer, gets called with 1 extra parameter + { GID_SQ1, 71, 71, 0, "destroyXenon", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // during the Xenon destruction cutscene (which results in death), gets called with 1 extra parameter - bug #3040894 + { GID_SQ1, 53, 53, 0, "blastEgo", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // when Roger is found and zapped by the cleaning robot, gets called with 1 extra parameter - bug #3040905 SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -259,19 +303,21 @@ const SciWorkaroundEntry kGraphFillBoxForeground_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kGraphFillBoxAny_workarounds[] = { - { GID_SQ4, -1, 818, 0, "iconTextSwitch", "show", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // game menu "text/speech" display - parameter 5 is missing, but the right color number is on the stack + { GID_SQ4, -1, 818, 0, "iconTextSwitch", "show", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // CD: game menu "text/speech" display - parameter 5 is missing, but the right color number is on the stack SCI_WORKAROUNDENTRY_TERMINATOR }; // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kGraphRedrawBox_workarounds[] = { { GID_SQ4, 405, 405, 0, "swimAfterEgo", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified + { GID_SQ4, 406, 406, 0, "egoFollowed", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // FLOPPY: when getting shot by the police - accidental additional parameter specified { GID_SQ4, 406, 406, 0, "swimAndShoot", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified { GID_SQ4, 410, 410, 0, "swimAfterEgo", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified { GID_SQ4, 411, 411, 0, "swimAndShoot", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // skateOrama when "swimming" in the air - accidental additional parameter specified { GID_SQ4, -1, 704, 0, "shootEgo", "changeState", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // When shot by Droid in Super Computer Maze (Rooms 500, 505, 510...) - accidental additional parameter specified { GID_KQ5, -1, 981, 0, "myWindow", "dispose", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // Happens in the floppy version, when closing any dialog box, accidental additional parameter specified - bug #3036331 { GID_KQ5, -1, 995, 0, "invW", "doit", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // Happens in the floppy version, when closing the inventory window, accidental additional parameter specified + { GID_KQ5, -1, 995, 0, "", "export 0", -1, 0, { WORKAROUND_STILLCALL, 0 } }, // Happens in the floppy version, when opening the gem pouch, accidental additional parameter specified - bug #3039395 SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -317,11 +363,13 @@ const SciWorkaroundEntry kSetCursor_workarounds[] = { // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kSetPort_workarounds[] = { { GID_LSL6, 740, 740, 0, "rm740", "drawPic", -1, 0, { WORKAROUND_IGNORE, 0 } }, // ending scene, is called with additional 3 (!) parameters + { GID_QFG3, 830, 830, 0, "portalOpens", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when the portal appears during the end, bug #3040844 SCI_WORKAROUNDENTRY_TERMINATOR }; // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry kStrAt_workarounds[] = { + { GID_CASTLEBRAIN, 220, 220, 0, "robotJokes", "animateOnce", -1, 0, { WORKAROUND_FAKE, 0 } }, // when trying to view the terminal at the end of the maze without having collected any robot jokes - bug #3039036 { GID_ISLANDBRAIN, 300, 310, 0, "childBreed", "changeState",0x1c7c, 0, { WORKAROUND_FAKE, 0 } }, // when clicking Breed to get the second-generation cyborg hybrid (Standard difficulty), the two parameters are swapped - bug #3037835 SCI_WORKAROUNDENTRY_TERMINATOR }; @@ -332,7 +380,7 @@ const SciWorkaroundEntry kUnLoad_workarounds[] = { { GID_CAMELOT, 921, 921, 1, "Script", "init", 0x36, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: When being attacked by the boar (and other places), the reference is invalid - bug #3035000 { GID_CASTLEBRAIN, 320, 377, 0, "SWord", "upDate", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after solving the cross-word-puzzle, trying to unload invalid reference { GID_CASTLEBRAIN, 320, 377, 0, "theWord", "show", -1, 0, { WORKAROUND_IGNORE, 0 } }, // 2nd word puzzle, when exiting before solving, trying to unload invalid reference - bug #3034473 - { GID_ECOQUEST, 380, 61, 0, "gotIt", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after talking to the dolphin the first time + { GID_ECOQUEST, 380, 61, 0, "gotIt", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // after talking to the dolphin the first time { GID_LAURABOW2, 1, 1, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: during the intro, a 3rd parameter is passed by accident - bug #3034902 { GID_LAURABOW2, 2, 2, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: during the intro, a 3rd parameter is passed by accident - bug #3034902 { GID_LAURABOW2, 4, 4, 0, "sCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: inside the museum, a 3rd parameter is passed by accident - bug #3034902 diff --git a/engines/sci/engine/workarounds.h b/engines/sci/engine/workarounds.h index 8a3edb6246..55a4b8f885 100644 --- a/engines/sci/engine/workarounds.h +++ b/engines/sci/engine/workarounds.h @@ -71,7 +71,11 @@ struct SciWorkaroundEntry { extern const SciWorkaroundEntry opcodeDivWorkarounds[]; extern const SciWorkaroundEntry opcodeDptoaWorkarounds[]; extern const SciWorkaroundEntry opcodeGeWorkarounds[]; +extern const SciWorkaroundEntry opcodeLeWorkarounds[]; +extern const SciWorkaroundEntry opcodeLaiWorkarounds[]; +extern const SciWorkaroundEntry opcodeLsiWorkarounds[]; extern const SciWorkaroundEntry opcodeMulWorkarounds[]; +extern const SciWorkaroundEntry opcodeAndWorkarounds[]; extern const SciWorkaroundEntry opcodeOrWorkarounds[]; extern const SciWorkaroundEntry uninitializedReadWorkarounds[]; extern const SciWorkaroundEntry kAbs_workarounds[]; diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp index ab4362cda9..b962e819a6 100644 --- a/engines/sci/graphics/animate.cpp +++ b/engines/sci/graphics/animate.cpp @@ -190,7 +190,7 @@ void GfxAnimate::makeSortedList(List *list) { Common::sort(_list.begin(), _list.end(), sortHelper); } -void GfxAnimate::fill(byte &old_picNotValid) { +void GfxAnimate::fill(byte &old_picNotValid, bool maySetNsRect) { reg_t curObject; uint16 signal; GfxView *view = NULL; @@ -205,13 +205,28 @@ void GfxAnimate::fill(byte &old_picNotValid) { view = _cache->getView(it->viewId); // adjust loop and cel, if any of those is invalid - if (it->loopNo >= view->getLoopCount()) { + // this seems to be completely crazy code + // sierra sci checked signed int16 to be above or equal the counts and reseted to 0 in those cases + // later during view processing those are compared unsigned again and then set to maximum count - 1 + // Games rely on this behaviour. For example laura bow 1 has a knight standing around in room 37 + // which has cel set to 3. This cel does not exist and the actual knight is 0 + // In kq5 on the other hand during the intro, when the trunk is opened, cel is set to some real + // high number, which is negative when considered signed. This actually requires to get fixed to + // maximum cel, otherwise the trunk would be closed. + int16 viewLoopCount = view->getLoopCount(); + if (it->loopNo >= viewLoopCount) { it->loopNo = 0; writeSelectorValue(_s->_segMan, curObject, SELECTOR(loop), it->loopNo); + } else if (it->loopNo < 0) { + it->loopNo = viewLoopCount - 1; + // not setting selector is right, sierra sci didn't do it during view processing as well } - if (it->celNo >= view->getCelCount(it->loopNo)) { + int16 viewCelCount = view->getCelCount(it->loopNo); + if (it->celNo >= viewCelCount) { it->celNo = 0; writeSelectorValue(_s->_segMan, curObject, SELECTOR(cel), it->celNo); + } else if (it->celNo < 0) { + it->celNo = viewCelCount - 1; } // Process global scaling, if needed @@ -243,6 +258,8 @@ void GfxAnimate::fill(byte &old_picNotValid) { } } + //warning("%s view %d, loop %d, cel %d", _s->_segMan->getObjectName(curObject), it->viewId, it->loopNo, it->celNo); + if (!view->isScaleable()) { // Laura Bow 2 (especially floppy) depends on this, some views are not supposed to be scaleable // this "feature" was removed in later versions of SCI1.1 @@ -250,7 +267,7 @@ void GfxAnimate::fill(byte &old_picNotValid) { it->scaleY = it->scaleX = 128; } - bool setNsRect = true; + bool setNsRect = maySetNsRect; // Create rect according to coordinates and given cel if (it->scaleSignal & kScaleSignalDoScaling) { @@ -516,6 +533,19 @@ void GfxAnimate::reAnimate(Common::Rect rect) { } } +void GfxAnimate::preprocessAddToPicList() { + AnimateList::iterator it; + const AnimateList::iterator end = _list.end(); + + for (it = _list.begin(); it != end; ++it) { + if (it->priority == -1) + it->priority = _ports->kernelCoordinateToPriority(it->y); + + // Do not allow priority to get changed by fill() + it->signal |= kSignalFixedPriority; + } +} + void GfxAnimate::addToPicDrawCels() { reg_t curObject; GfxView *view = NULL; @@ -525,17 +555,11 @@ void GfxAnimate::addToPicDrawCels() { for (it = _list.begin(); it != end; ++it) { curObject = it->object; - if (it->priority == -1) - it->priority = _ports->kernelCoordinateToPriority(it->y); - // Get the corresponding view view = _cache->getView(it->viewId); - // Create rect according to coordinates and given cel - view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect); - // draw corresponding cel - _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo); + _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY); if ((it->signal & kSignalIgnoreActor) == 0) { it->celRect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, it->celRect.top, it->celRect.bottom - 1); _paint16->fillRect(it->celRect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15); @@ -604,7 +628,7 @@ void GfxAnimate::kernelAnimate(reg_t listReference, bool cycle, int argc, reg_t disposeLastCast(); makeSortedList(list); - fill(old_picNotValid); + fill(old_picNotValid, true); if (old_picNotValid) { // beginUpdate()/endUpdate() were introduced SCI1. @@ -679,6 +703,7 @@ void GfxAnimate::addToPicSetPicNotValid() { void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv) { List *list; + byte tempPicNotValid = 0; _ports->setPort((Port *)_ports->_picWind); @@ -687,6 +712,8 @@ void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv) error("kAddToPic called with non-list as parameter"); makeSortedList(list); + preprocessAddToPicList(); + fill(tempPicNotValid, getSciVersion() >= SCI_VERSION_1_1 ? true : false); addToPicDrawCels(); addToPicSetPicNotValid(); diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h index 7e82187eed..f25e54915e 100644 --- a/engines/sci/graphics/animate.h +++ b/engines/sci/graphics/animate.h @@ -94,12 +94,13 @@ public: void disposeLastCast(); bool invoke(List *list, int argc, reg_t *argv); void makeSortedList(List *list); - void fill(byte &oldPicNotValid); + void fill(byte &oldPicNotValid, bool maySetNsRect); void update(); void drawCels(); void updateScreen(byte oldPicNotValid); void restoreAndDelete(int argc, reg_t *argv); void reAnimate(Common::Rect rect); + void preprocessAddToPicList(); void addToPicDrawCels(); void addToPicDrawView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control); diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp index 0a186115d0..1c961b2ad6 100644 --- a/engines/sci/graphics/compare.cpp +++ b/engines/sci/graphics/compare.cpp @@ -229,39 +229,32 @@ void GfxCompare::kernelBaseSetter(reg_t object) { if (viewId == 0xFFFF) // invalid view return; - // must be something wrong with this TODO check - currently it breaks qfg3 right after the intro - //uint16 scaleSignal = 0; - //if (getSciVersion() >= SCI_VERSION_1_1) { - // scaleSignal = readSelectorValue(_segMan, object, SELECTOR(scaleSignal)) & kScaleSignalDoScaling; - // if (scaleSignal) { - // int16 scaleY = readSelectorValue(_segMan, object, SELECTOR(scaleY)); - // if (scaleY < 64) - // scaleSignal = 0; - // } - //} + uint16 scaleSignal = 0; + if (getSciVersion() >= SCI_VERSION_1_1) { + scaleSignal = readSelectorValue(_segMan, object, SELECTOR(scaleSignal)); + } Common::Rect celRect; - //if (!scaleSignal) { - GfxView *tmpView = _cache->getView(viewId); - if (tmpView->isSci2Hires()) - _screen->adjustToUpscaledCoordinates(y, x); + GfxView *tmpView = _cache->getView(viewId); + if (tmpView->isSci2Hires()) + _screen->adjustToUpscaledCoordinates(y, x); + if (scaleSignal & kScaleSignalDoScaling) { + int16 scaleX = readSelectorValue(_segMan, object, SELECTOR(scaleX)); + int16 scaleY = readSelectorValue(_segMan, object, SELECTOR(scaleY)); + tmpView->getCelScaledRect(loopNo, celNo, x, y, z, scaleX, scaleY, celRect); + } else { tmpView->getCelRect(loopNo, celNo, x, y, z, celRect); + } - if (tmpView->isSci2Hires()) { - _screen->adjustBackUpscaledCoordinates(celRect.top, celRect.left); - _screen->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right); - } + if (tmpView->isSci2Hires()) { + _screen->adjustBackUpscaledCoordinates(celRect.top, celRect.left); + _screen->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right); + } - celRect.bottom = y + 1; - celRect.top = celRect.bottom - yStep; - //} else { - // celRect.left = readSelectorValue(_segMan, object, SELECTOR(nsLeft)); - // celRect.right = readSelectorValue(_segMan, object, SELECTOR(nsRight)); - // celRect.top = readSelectorValue(_segMan, object, SELECTOR(nsTop)); - // celRect.bottom = readSelectorValue(_segMan, object, SELECTOR(nsBottom)); - //} + celRect.bottom = y + 1; + celRect.top = celRect.bottom - yStep; writeSelectorValue(_segMan, object, SELECTOR(brLeft), celRect.left); writeSelectorValue(_segMan, object, SELECTOR(brRight), celRect.right); diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp index f6e2077cb3..a906899113 100644 --- a/engines/sci/graphics/cursor.cpp +++ b/engines/sci/graphics/cursor.cpp @@ -23,10 +23,11 @@ * */ -#include "graphics/cursorman.h" -#include "common/util.h" #include "common/events.h" +#include "common/macresman.h" #include "common/system.h" +#include "common/util.h" +#include "graphics/cursorman.h" #include "sci/sci.h" #include "sci/event.h" @@ -206,7 +207,7 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu // See http://developer.apple.com/legacy/mac/library/documentation/mac/QuickDraw/QuickDraw-402.html // for more information. - // View 998 seems to be a fake resource used to call for the Mac CURS resources. + // View 998 seems to be a fake resource used to call for Mac cursor resources. // For other resources, they're still in the views, so use them. if (viewNum != 998) { kernelSetView(viewNum, loopNum, celNum, hotspot); @@ -214,43 +215,53 @@ void GfxCursor::kernelSetMacCursor(GuiResourceId viewNum, int loopNum, int celNu } // TODO: What about the 2000 resources? Inventory items? How to handle? - // TODO: What games does this work for? At least it does for KQ6. - // TODO: Stop asking rhetorical questions. - // TODO: It was fred all along! + // TODO: 1000 + celNum won't work for GK1 Resource *resource = _resMan->findResource(ResourceId(kResourceTypeCursor, 1000 + celNum), false); if (!resource) { - warning("CURS %d not found", 1000 + celNum); + warning("Mac cursor %d not found", 1000 + celNum); return; } assert(resource); - byte *cursorBitmap = new byte[16 * 16]; - byte *data = resource->data; + if (resource->size == 32 * 2 + 4) { + // Mac CURS cursor + byte *cursorBitmap = new byte[16 * 16]; + byte *data = resource->data; - // Get B&W data - for (byte i = 0; i < 32; i++) { - byte imageByte = *data++; - for (byte b = 0; b < 8; b++) - cursorBitmap[i * 8 + b] = (byte)((imageByte & (0x80 >> b)) > 0 ? 0x00 : 0xFF); - } + // Get B&W data + for (byte i = 0; i < 32; i++) { + byte imageByte = *data++; + for (byte b = 0; b < 8; b++) + cursorBitmap[i * 8 + b] = (byte)((imageByte & (0x80 >> b)) > 0 ? 0x00 : 0xFF); + } - // Apply mask data - for (byte i = 0; i < 32; i++) { - byte imageByte = *data++; - for (byte b = 0; b < 8; b++) - if ((imageByte & (0x80 >> b)) == 0) - cursorBitmap[i * 8 + b] = SCI_CURSOR_SCI0_TRANSPARENCYCOLOR; // Doesn't matter, just is transparent - } + // Apply mask data + for (byte i = 0; i < 32; i++) { + byte imageByte = *data++; + for (byte b = 0; b < 8; b++) + if ((imageByte & (0x80 >> b)) == 0) + cursorBitmap[i * 8 + b] = SCI_CURSOR_SCI0_TRANSPARENCYCOLOR; // Doesn't matter, just is transparent + } - uint16 hotspotX = READ_BE_UINT16(data); - uint16 hotspotY = READ_BE_UINT16(data + 2); + uint16 hotspotX = READ_BE_UINT16(data); + uint16 hotspotY = READ_BE_UINT16(data + 2); - CursorMan.replaceCursor(cursorBitmap, 16, 16, hotspotX, hotspotY, SCI_CURSOR_SCI0_TRANSPARENCYCOLOR); + CursorMan.replaceCursor(cursorBitmap, 16, 16, hotspotX, hotspotY, SCI_CURSOR_SCI0_TRANSPARENCYCOLOR); - delete[] cursorBitmap; + delete[] cursorBitmap; + } else { + // Mac crsr cursor + byte *cursorBitmap, *palette; + int width, height, hotspotX, hotspotY, palSize, keycolor; + Common::MacResManager::convertCrsrCursor(resource->data, resource->size, &cursorBitmap, &width, &height, &hotspotX, &hotspotY, &keycolor, true, &palette, &palSize); + CursorMan.replaceCursor(cursorBitmap, width, height, hotspotX, hotspotY, keycolor); + CursorMan.replaceCursorPalette(palette, 0, palSize); + free(cursorBitmap); + free(palette); + } kernelShow(); } diff --git a/engines/sci/graphics/helpers.h b/engines/sci/graphics/helpers.h index 8f26ca296b..4b4cd673b4 100644 --- a/engines/sci/graphics/helpers.h +++ b/engines/sci/graphics/helpers.h @@ -55,11 +55,12 @@ struct Port { bool greyedOutput; int16 penClr, backClr; int16 penMode; + uint16 counterTillFree; Port(uint16 theId) : id(theId), top(0), left(0), curTop(0), curLeft(0), fontHeight(0), fontId(0), greyedOutput(false), - penClr(0), backClr(0xFF), penMode(0) { + penClr(0), backClr(0xFF), penMode(0), counterTillFree(0) { } }; diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp index 4551e9dafc..dbc738e2f7 100644 --- a/engines/sci/graphics/paint16.cpp +++ b/engines/sci/graphics/paint16.cpp @@ -221,7 +221,7 @@ void GfxPaint16::paintRect(const Common::Rect &rect) { fillRect(rect, GFX_SCREEN_MASK_VISUAL, _ports->_curPort->penClr); } -void GfxPaint16::fillRect(const Common::Rect &rect, int16 drawFlags, byte clrPen, byte clrBack, byte bControl) { +void GfxPaint16::fillRect(const Common::Rect &rect, int16 drawFlags, byte color, byte priority, byte control) { Common::Rect r = rect; r.clip(_ports->_curPort->rect); if (r.isEmpty()) // nothing to fill @@ -238,17 +238,17 @@ void GfxPaint16::fillRect(const Common::Rect &rect, int16 drawFlags, byte clrPen for (y = r.top; y < r.bottom; y++) { for (x = r.left; x < r.right; x++) { curVisual = _screen->getVisual(x, y); - if (curVisual == clrPen) { - _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, clrBack, 0, 0); - } else if (curVisual == clrBack) { - _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, clrPen, 0, 0); + if (curVisual == color) { + _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, priority, 0, 0); + } else if (curVisual == priority) { + _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, color, 0, 0); } } } - } else { // just fill rect with ClrPen + } else { // just fill rect with color for (y = r.top; y < r.bottom; y++) { for (x = r.left; x < r.right; x++) { - _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, clrPen, 0, 0); + _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, color, 0, 0); } } } @@ -258,10 +258,14 @@ void GfxPaint16::fillRect(const Common::Rect &rect, int16 drawFlags, byte clrPen return; drawFlags &= GFX_SCREEN_MASK_PRIORITY|GFX_SCREEN_MASK_CONTROL; + // we need to isolate the bits, sierra sci saved priority and control inside one byte, we don't + priority &= 0x0f; + control &= 0x0f; + if (oldPenMode != 2) { for (y = r.top; y < r.bottom; y++) { for (x = r.left; x < r.right; x++) { - _screen->putPixel(x, y, drawFlags, 0, clrBack, bControl); + _screen->putPixel(x, y, drawFlags, 0, priority, control); } } } else { @@ -413,6 +417,7 @@ void GfxPaint16::kernelGraphFrameBox(const Common::Rect &rect, int16 color) { } void GfxPaint16::kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control) { + _ports->clipLine(startPoint, endPoint); _ports->offsetLine(startPoint, endPoint); _screen->drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, color, priority, control); } diff --git a/engines/sci/graphics/paint16.h b/engines/sci/graphics/paint16.h index e944c71bdd..4f709fd7c6 100644 --- a/engines/sci/graphics/paint16.h +++ b/engines/sci/graphics/paint16.h @@ -62,7 +62,7 @@ public: void invertRectViaXOR(const Common::Rect &rect); void eraseRect(const Common::Rect &rect); void paintRect(const Common::Rect &rect); - void fillRect(const Common::Rect &rect, int16 drawFlags, byte clrPen, byte clrBack = 0, byte bControl = 0); + void fillRect(const Common::Rect &rect, int16 drawFlags, byte color, byte priority = 0, byte control = 0); void frameRect(const Common::Rect &rect); void bitsShow(const Common::Rect &r); diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp index 2e9128cda6..dddd9b1c86 100644 --- a/engines/sci/graphics/ports.cpp +++ b/engines/sci/graphics/ports.cpp @@ -66,6 +66,8 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te _paint16 = paint16; _text16 = text16; + _freeCounter = 0; + // _menuPort has actually hardcoded id 0xFFFF. Its not meant to be known to windowmanager according to sierra sci _menuPort = new Port(0xFFFF); openPort(_menuPort); @@ -155,25 +157,37 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te // but in some games there are still windows active when restoring. Leaving those windows open // would create all sorts of issues, that's why we remove them void GfxPorts::reset() { - PortList::iterator it = _windowList.begin(); - const PortList::iterator end = _windowList.end(); - setPort(_picWind); - while (it != end) { - Port *pPort = *it; - if (pPort->id > 2) { - // found a window beyond _picWind - freeWindow((Window *)pPort); - } - it++; + // free everything after _picWind + for (uint id = PORTS_FIRSTSCRIPTWINDOWID; id < _windowsById.size(); id++) { + Window *window = (Window *)_windowsById[id]; + if (window) + freeWindow(window); } + _freeCounter = 0; _windowList.clear(); _windowList.push_front(_wmgrPort); _windowList.push_back(_picWind); } void GfxPorts::kernelSetActive(uint16 portId) { + if (_freeCounter) { + // Windows waiting to get freed + for (uint id = PORTS_FIRSTSCRIPTWINDOWID; id < _windowsById.size(); id++) { + Window *window = (Window *)_windowsById[id]; + if (window) { + if (window->counterTillFree) { + window->counterTillFree--; + if (!window->counterTillFree) { + freeWindow(window); + _freeCounter--; + } + } + } + } + } + switch (portId) { case 0: setPort(_wmgrPort); @@ -225,35 +239,14 @@ reg_t GfxPorts::kernelNewWindow(Common::Rect dims, Common::Rect restoreRect, uin void GfxPorts::kernelDisposeWindow(uint16 windowId, bool reanimate) { Window *wnd = (Window *)getPortById(windowId); - if (wnd) - removeWindow(wnd, reanimate); - else - error("GfxPorts::kernelDisposeWindow: Request to dispose invalid port id %d", windowId); - - if ((g_sci->getGameId() == GID_HOYLE4) && (!g_sci->isDemo())) { - // WORKAROUND: hoyle 4 has a broken User::handleEvent implementation - // first of all iconbar is always set and always gets called with - // events checking if event got claimed got removed inside that code - // and it will call handleEvent on gameObj afterwards. Iconbar windows - // are handled inside iconbar as well including disposing - // e.g. iconOK::doit, script 14) and claimed isn't even set. gameObj - // handleEvent calling will result in coordinate adjust with a now - // invalid port. - // We fix this by adjusting the port variable to be global - // again when hoyle4 is disposing windows. - // This worked because sierra sci leaves old port data, so the pointer - // was still valid for a short period of time - // TODO: maybe this could get implemented as script patch somehow - // although this could get quite tricky to implement (script 996) - // IconBar::handleEvent (script 937) - // maybe inside export 8 of script 0, which is called by iconOK - // and iconReplay - // or inside GameControls::hide (script 978) which is called to - // actually remove the window - reg_t eventObject = _segMan->findObjectByName("uEvt"); - if (!eventObject.isNull()) { - writeSelectorValue(_segMan, eventObject, SELECTOR(port), 0); + if (wnd) { + if (!wnd->counterTillFree) { + removeWindow(wnd, reanimate); + } else { + error("kDisposeWindow: used already disposed window id %d", windowId); } + } else { + error("kDisposeWindow: used unknown window id %d", windowId); } } @@ -293,8 +286,18 @@ void GfxPorts::endUpdate(Window *wnd) { Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restoreRect, const char *title, uint16 style, int16 priority, bool draw) { // Find an unused window/port id - uint id = 1; + uint id = PORTS_FIRSTWINDOWID; while (id < _windowsById.size() && _windowsById[id]) { + if (_windowsById[id]->counterTillFree) { + // port that is already disposed, but not freed yet + freeWindow((Window *)_windowsById[id]); + _freeCounter--; + break; // reuse the handle + // we do this especially for sq4cd. it creates and disposes the + // inventory window all the time, but reuses old handles as well + // this worked somewhat under the original interpreter, because + // it put the new window where the old was. + } ++id; } if (id == _windowsById.size()) @@ -444,15 +447,25 @@ void GfxPorts::drawWindow(Window *pWnd) { void GfxPorts::removeWindow(Window *pWnd, bool reanimate) { setPort(_wmgrPort); _paint16->bitsRestore(pWnd->hSaved1); + pWnd->hSaved1 = NULL_REG; _paint16->bitsRestore(pWnd->hSaved2); + pWnd->hSaved2 = NULL_REG; if (!reanimate) _paint16->bitsShow(pWnd->restoreRect); else _paint16->kernelGraphRedrawBox(pWnd->restoreRect); _windowList.remove(pWnd); setPort(_windowList.back()); - _windowsById[pWnd->id] = NULL; - delete pWnd; + // We will actually free this window after 15 kSetPort-calls + // Sierra sci freed the pointer immediately, but pointer to that port + // still worked till the memory got overwritten. Some games depend + // on this (dispose a window and then kSetPort to it again for once) + // Those are actually script bugs, but patching all of those out + // would be quite a hassle and this just keeps compatibility + // (examples: hoyle 4 game menu and sq4cd inventory) + // sq4cd gum wrapper requires more than 10 + pWnd->counterTillFree = 15; + _freeCounter++; } void GfxPorts::freeWindow(Window *pWnd) { @@ -460,7 +473,7 @@ void GfxPorts::freeWindow(Window *pWnd) { _segMan->freeHunkEntry(pWnd->hSaved1); if (!pWnd->hSaved2.isNull()) _segMan->freeHunkEntry(pWnd->hSaved1); - _windowsById[pWnd->id] = 0; + _windowsById[pWnd->id] = NULL; delete pWnd; } @@ -563,6 +576,13 @@ void GfxPorts::offsetLine(Common::Point &start, Common::Point &end) { end.y += _curPort->top; } +void GfxPorts::clipLine(Common::Point &start, Common::Point &end) { + start.y = CLIP<int16>(start.y, _curPort->rect.top, _curPort->rect.bottom - 1); + start.x = CLIP<int16>(start.x, _curPort->rect.left, _curPort->rect.right - 1); + end.y = CLIP<int16>(end.y, _curPort->rect.top, _curPort->rect.bottom - 1); + end.x = CLIP<int16>(end.x, _curPort->rect.left, _curPort->rect.right - 1); +} + void GfxPorts::priorityBandsInit(int16 bandCount, int16 top, int16 bottom) { int16 y; int32 bandSize; diff --git a/engines/sci/graphics/ports.h b/engines/sci/graphics/ports.h index f7f0721eb7..453cb50986 100644 --- a/engines/sci/graphics/ports.h +++ b/engines/sci/graphics/ports.h @@ -36,6 +36,9 @@ class GfxPaint16; class GfxScreen; class GfxText16; +#define PORTS_FIRSTWINDOWID 2 +#define PORTS_FIRSTSCRIPTWINDOWID 3 + /** * Ports class, includes all port managment for SCI0->SCI1.1 games. Ports are some sort of windows in SCI * this class also handles adjusting coordinates to a specific port @@ -80,6 +83,7 @@ public: void offsetRect(Common::Rect &r); void offsetLine(Common::Point &start, Common::Point &end); + void clipLine(Common::Point &start, Common::Point &end); void priorityBandsInit(int16 bandCount, int16 top, int16 bottom); void priorityBandsInit(byte *data); @@ -111,6 +115,9 @@ private: uint16 _styleUser; + // counts windows that got disposed but are not freed yet + uint16 _freeCounter; + /** The list of open 'windows' (and ports), in visual order. */ PortList _windowList; diff --git a/engines/sci/graphics/text16.cpp b/engines/sci/graphics/text16.cpp index fc07febe14..f5eb268863 100644 --- a/engines/sci/graphics/text16.cpp +++ b/engines/sci/graphics/text16.cpp @@ -92,7 +92,7 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1 const char *textCode = text; int16 textCodeSize = 0; char curCode; - unsigned char curCodeParm; + signed char curCodeParm; // Find the end of the textcode while ((++textCodeSize) && (*text != 0) && (*text++ != 0x7C)) { } @@ -105,11 +105,11 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1 if (isdigit(curCodeParm)) { curCodeParm -= '0'; } else { - curCodeParm = 0; + curCodeParm = -1; } switch (curCode) { case 'c': // set text color - if (curCodeParm == 0) { + if (curCodeParm == -1) { _ports->_curPort->penClr = orgPenColor; } else { if (curCodeParm < _codeColorsCount) { @@ -117,8 +117,8 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1 } } break; - case 'f': - if (curCodeParm == 0) { + case 'f': // set text font + if (curCodeParm == -1) { SetFont(orgFontId); } else { if (curCodeParm < _codeFontsCount) { @@ -126,6 +126,9 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1 } } break; + case 'r': // reference?! + // Used in Pepper, no idea how this works out + break; } return textCodeSize; } diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp index 1c865f6bcf..5f48574dcb 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -256,6 +256,8 @@ void GfxView::initData(GuiResourceId resourceId) { cel->scriptHeight = cel->height = READ_SCI11ENDIAN_UINT16(celData + 2); cel->displaceX = READ_SCI11ENDIAN_UINT16(celData + 4); cel->displaceY = READ_SCI11ENDIAN_UINT16(celData + 6); + if (cel->displaceY < 0) + cel->displaceY += 255; // sierra did this adjust in their sci1.1 getCelRect() - not sure about sci32 assert(cel->width && cel->height); diff --git a/engines/sci/module.mk b/engines/sci/module.mk index dae2807cc2..238209c446 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -30,6 +30,7 @@ MODULE_OBJS := \ engine/savegame.o \ engine/script.o \ engine/scriptdebug.o \ + engine/script_patches.o \ engine/selector.o \ engine/seg_manager.o \ engine/segment.o \ @@ -76,8 +77,7 @@ ifdef ENABLE_SCI32 MODULE_OBJS += \ graphics/frameout.o \ graphics/paint32.o \ - graphics/robot.o \ - video/vmd_decoder.o + graphics/robot.o endif # This module can be built as a plugin diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 4bf26ff0bf..00f50714af 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -365,8 +365,6 @@ Common::SeekableReadStream *ResourceManager::getVolumeFile(ResourceSource *sourc return NULL; } -static uint32 resTypeToMacTag(ResourceType type); - void ResourceManager::loadResource(Resource *res) { res->_source->loadResource(this, res); } @@ -382,8 +380,14 @@ void PatchResourceSource::loadResource(ResourceManager *resMan, Resource *res) { } } +static Common::Array<uint32> resTypeToMacTags(ResourceType type); + void MacResourceForkResourceSource::loadResource(ResourceManager *resMan, Resource *res) { - Common::SeekableReadStream *stream = _macResMan->getResource(resTypeToMacTag(res->getType()), res->getNumber()); + Common::SeekableReadStream *stream = 0; + Common::Array<uint32> tagArray = resTypeToMacTags(res->getType()); + + for (uint32 i = 0; i < tagArray.size() && !stream; i++) + stream = _macResMan->getResource(tagArray[i], res->getNumber()); if (!stream) error("Could not get Mac resource fork resource: %s %d", getResourceTypeName(res->getType()), res->getNumber()); @@ -989,7 +993,7 @@ void ResourceManager::unlockResource(Resource *res) { assert(res); if (res->_status != kResStatusLocked) { - warning("[resMan] Attempt to unlock unlocked resource %s", res->_id.toString().c_str()); + debugC(kDebugLevelResMan, 2, "[resMan] Attempt to unlock unlocked resource %s", res->_id.toString().c_str()); return; } @@ -1588,12 +1592,14 @@ struct { { MKID_BE('SYN '), kResourceTypeSync } }; -static uint32 resTypeToMacTag(ResourceType type) { +static Common::Array<uint32> resTypeToMacTags(ResourceType type) { + Common::Array<uint32> tags; + for (uint32 i = 0; i < ARRAYSIZE(macResTagMap); i++) if (macResTagMap[i].type == type) - return macResTagMap[i].tag; + tags.push_back(macResTagMap[i].tag); - return 0; + return tags; } void MacResourceForkResourceSource::scanSource(ResourceManager *resMan) { @@ -2051,6 +2057,15 @@ void ResourceManager::detectSciVersion() { s_sciVersion = SCI_VERSION_1_1; return; } + // FIXME: this is really difficult, lsl1 spanish has map/vol sci1late + // and the only current detection difference is movecounttype which + // is increment here, but ignore for all the regular sci1late games + // the problem is, we dont have access to that detection till later + // so maybe (part of?) that detection should get moved in here + if ((g_sci->getGameId() == GID_LSL1) && (g_sci->getLanguage() == Common::ES_ESP)) { + s_sciVersion = SCI_VERSION_1_MIDDLE; + return; + } s_sciVersion = SCI_VERSION_1_LATE; return; case kResVersionSci11: diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index d0c578bd45..7a9a786121 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -211,8 +211,11 @@ Common::Error SciEngine::run() { _console = new Console(this); _kernel = new Kernel(_resMan, segMan); _features = new GameFeatures(segMan, _kernel); - // Only SCI0 and SCI01 games used a parser + // Only SCI0, SCI01 and SCI1 EGA games used a parser _vocabulary = (getSciVersion() <= SCI_VERSION_1_EGA) ? new Vocabulary(_resMan, false) : NULL; + // Also, XMAS1990 apparently had a parser too. Refer to http://forums.scummvm.org/viewtopic.php?t=9135 + if (getGameId() == GID_CHRISTMAS1990) + _vocabulary = new Vocabulary(_resMan, false); _audio = new AudioPlayer(_resMan); _gamestate = new EngineState(segMan); _eventMan = new EventManager(_resMan->detectFontExtended()); diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp index 6ec28a8b02..769df73365 100644 --- a/engines/sci/sound/midiparser_sci.cpp +++ b/engines/sci/sound/midiparser_sci.cpp @@ -445,7 +445,12 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) { } if (_signalSet) { _signalSet = false; - _pSnd->signal = _signalToSet; + if (!_pSnd->signal) { + _pSnd->signal = _signalToSet; + } else { + // signal already set and waiting for getting to scripts, queue new one + _pSnd->signalQueue.push_back(_signalToSet); + } debugC(4, kDebugLevelSound, "signal %04x", _signalToSet); } @@ -608,7 +613,12 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) { jumpToTick(_loopTick); } else { _pSnd->status = kSoundStopped; - _pSnd->signal = SIGNAL_OFFSET; + if (!_pSnd->signal) { + _pSnd->signal = SIGNAL_OFFSET; + } else { + // signal already set and waiting for getting to scripts, queue new one + _pSnd->signalQueue.push_back(SIGNAL_OFFSET); + } debugC(4, kDebugLevelSound, "signal EOT"); } diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp index 061f380ebc..fc1e56fcea 100644 --- a/engines/sci/sound/music.cpp +++ b/engines/sci/sound/music.cpp @@ -465,6 +465,17 @@ void SciMusic::soundKill(MusicEntry *pSnd) { } void SciMusic::soundPause(MusicEntry *pSnd) { + // SCI seems not to be pausing samples played back by kDoSound at all + // It only stops looping samples (actually doesn't loop them again before they are unpaused) + // Examples: Space Quest 1 death by acid drops (pause is called even specifically for the sample, see bug #3038048) + // Eco Quest 1 during the intro when going to the abort-menu + // In both cases sierra sci keeps playing + // Leisure Suit Larry 1 doll scene - it seems that pausing here actually just stops + // further looping from happening + // This is a somewhat bigger change, I'm leaving in the old code in here just in case + // I'm currently pausing looped sounds directly, non-looped sounds won't get paused + if ((pSnd->pStreamAud) && (!pSnd->pLoopStream)) + return; pSnd->pauseCounter++; if (pSnd->status != kSoundPlaying) return; @@ -627,6 +638,14 @@ MusicEntry::~MusicEntry() { } void MusicEntry::onTimer() { + if (!signal) { + if (!signalQueue.empty()) { + // no signal set, but signal in queue, set that one + signal = signalQueue[0]; + signalQueue.remove_at(0); + } + } + if (status != kSoundPlaying) return; diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h index 37e3c30030..3cf600fcf3 100644 --- a/engines/sci/sound/music.h +++ b/engines/sci/sound/music.h @@ -51,6 +51,8 @@ enum SoundStatus { class MidiParser_SCI; class SegManager; +typedef Common::Array<uint16> SignalQueue; + class MusicEntry : public Common::Serializable { public: // Do not get these directly for the sound objects! @@ -90,6 +92,11 @@ public: MidiParser_SCI *pMidiParser; + // this is used for storing signals, when the current signal is not yet + // sent to the scripts. We shouldn't need to save it, this normally only + // happens in rare situations like lb1, knocking on the door in the attic + SignalQueue signalQueue; + // TODO: We need to revise how we store the different // audio stream objects we require. Audio::RewindableAudioStream *pStreamAud; diff --git a/engines/sci/video/vmd_decoder.cpp b/engines/sci/video/vmd_decoder.cpp deleted file mode 100644 index 680a449207..0000000000 --- a/engines/sci/video/vmd_decoder.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. - * - * $URL$ - * $Id$ - * - */ - -#ifdef ENABLE_SCI32 - -#include "sci/video/vmd_decoder.h" - -#include "common/endian.h" -#include "common/util.h" -#include "common/stream.h" -#include "common/system.h" - -#include "graphics/dither.h" - -#include "sound/mixer.h" -#include "sound/audiostream.h" - -namespace Sci { - -VMDDecoder::VMDDecoder(Audio::Mixer *mixer) : _mixer(mixer) { - _vmdDecoder = new Graphics::Vmd(new Graphics::PaletteLUT(5, Graphics::PaletteLUT::kPaletteYUV)); - _surface = 0; - _dirtyPalette = false; - _fileStream = 0; -} - -VMDDecoder::~VMDDecoder() { - close(); -} - -bool VMDDecoder::load(Common::SeekableReadStream *stream) { - close(); - - if (!_vmdDecoder->load(stream)) - return false; - - _fileStream = stream; - - if (_vmdDecoder->getFeatures() & Graphics::CoktelVideo::kFeaturesPalette) - loadPaletteFromVMD(); - - if (_vmdDecoder->getFeatures() & Graphics::CoktelVideo::kFeaturesSound) - _vmdDecoder->enableSound(*_mixer); - - if (_vmdDecoder->hasExtraData()) - warning("This VMD video has extra embedded data, which is currently not handled"); - - _surface = new Graphics::Surface(); - _surface->create(_vmdDecoder->getWidth(), _vmdDecoder->getHeight(), 1); - _vmdDecoder->setVideoMemory((byte *)_surface->pixels, _surface->w, _surface->h); - return true; -} - -void VMDDecoder::close() { - if (!_fileStream) - return; - - _vmdDecoder->unload(); - - delete _fileStream; - _fileStream = 0; - - _surface->free(); - delete _surface; - _surface = 0; - - reset(); -} - -Graphics::Surface *VMDDecoder::decodeNextFrame() { - Graphics::CoktelVideo::State state = _vmdDecoder->nextFrame(); - - if (state.flags & Graphics::CoktelVideo::kStatePalette) - loadPaletteFromVMD(); - - if (_curFrame == -1) - _startTime = g_system->getMillis(); - - _curFrame++; - return _surface; -} - -void VMDDecoder::loadPaletteFromVMD() { - const byte *pal = _vmdDecoder->getPalette(); - - for (int i = 0; i < 256; i++) { - _palette[i * 3 + 0] = pal[i * 3 + 0] << 2; - _palette[i * 3 + 1] = pal[i * 3 + 1] << 2; - _palette[i * 3 + 2] = pal[i * 3 + 2] << 2; - } - - _dirtyPalette = true; -} - -} // End of namespace Graphics - -#endif diff --git a/engines/sci/video/vmd_decoder.h b/engines/sci/video/vmd_decoder.h deleted file mode 100644 index e79064b1f7..0000000000 --- a/engines/sci/video/vmd_decoder.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. - * - * $URL$ - * $Id$ - * - */ - -#ifdef ENABLE_SCI32 - -#ifndef GRAPHICS_VIDEO_VMD_DECODER_H -#define GRAPHICS_VIDEO_VMD_DECODER_H - -#include "graphics/video/coktelvideo/coktelvideo.h" -#include "graphics/video/video_decoder.h" -#include "sound/mixer.h" - -namespace Sci { - -/** - * Wrapper for the Coktel Vision VMD video decoder - * for videos by Coktel Vision/Sierra. - * - * VMD videos were used in the following SCI21/SCI3 - * adventure games, developed by Sierra: - * - Gabriel Knight 2: The Beast Within - * - Leisure Suit Larry 7 - * - Lighthouse - * - Phantasmagoria 1 - * - RAMA - * - Shivers - * - Shivers 2: Harvest of Souls - * - Torin's Passage - */ -class VMDDecoder : public Graphics::FixedRateVideoDecoder { -public: - VMDDecoder(Audio::Mixer *mixer); - virtual ~VMDDecoder(); - - uint32 getFrameWaitTime(); - - bool load(Common::SeekableReadStream *stream); - void close(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _surface->w; } - uint16 getHeight() const { return _surface->h; } - uint32 getFrameCount() const { return _vmdDecoder->getFramesCount(); } - Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } - -protected: - Common::Rational getFrameRate() const { return _vmdDecoder->getFrameRate(); } - -private: - Graphics::Vmd *_vmdDecoder; - Audio::Mixer *_mixer; - Graphics::Surface *_surface; - Common::SeekableReadStream *_fileStream; - byte _palette[256 * 3]; - bool _dirtyPalette; - - void loadPaletteFromVMD(); -}; - -} // End of namespace Graphics - -#endif - -#endif diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index d8987c816f..f275b1c93f 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -207,37 +207,37 @@ using Common::GUIO_NOSPEECH; // only a single unique variant. This is used to help the detector quickly // decide whether it has to worry about distinguishing multiple variants or not. static const GameSettings gameVariantsTable[] = { - {"maniac", "Apple II", 0, GID_MANIAC, 0, 0, MDT_PCSPK, 0, Common::kPlatformApple2GS, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"maniac", "C64", 0, GID_MANIAC, 0, 0, MDT_PCSPK, 0, Common::kPlatformC64, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"maniac", "V1", "v1", GID_MANIAC, 1, 0, MDT_PCSPK, 0, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"maniac", "V1 Demo", "v1", GID_MANIAC, 1, 0, MDT_PCSPK, GF_DEMO, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"maniac", "Apple II", 0, GID_MANIAC, 0, 0, MDT_APPLEIIGS, 0, Common::kPlatformApple2GS, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"maniac", "C64", 0, GID_MANIAC, 0, 0, MDT_C64, 0, Common::kPlatformC64, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"maniac", "V1", "v1", GID_MANIAC, 1, 0, MDT_PCSPK | MDT_PCJR, 0, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"maniac", "V1 Demo", "v1", GID_MANIAC, 1, 0, MDT_PCSPK | MDT_PCJR, GF_DEMO, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, {"maniac", "NES", 0, GID_MANIAC, 1, 0, MDT_NONE, 0, Common::kPlatformNES, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"maniac", "V2", "v2", GID_MANIAC, 2, 0, MDT_PCSPK, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"maniac", "V2 Demo", "v2", GID_MANIAC, 2, 0, MDT_PCSPK, GF_DEMO, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"maniac", "V2", "v2", GID_MANIAC, 2, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"maniac", "V2 Demo", "v2", GID_MANIAC, 2, 0, MDT_PCSPK | MDT_PCJR, GF_DEMO, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"zak", "V1", "v1", GID_ZAK, 1, 0, MDT_PCSPK, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"zak", "V2", "v2", GID_ZAK, 2, 0, MDT_PCSPK, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"zak", "V1", "v1", GID_ZAK, 1, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"zak", "V2", "v2", GID_ZAK, 2, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, {"zak", "FM-TOWNS", 0, GID_ZAK, 3, 0, MDT_TOWNS, GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"indy3", "EGA", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_CMS | MDT_ADLIB, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"indy3", "No AdLib", "ega", GID_INDY3, 3, 0, MDT_PCSPK, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"indy3", "VGA", "vga", GID_INDY3, 3, 0, MDT_PCSPK | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"indy3", "EGA", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"indy3", "No AdLib", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"indy3", "VGA", "vga", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, {"indy3", "FM-TOWNS", 0, GID_INDY3, 3, 0, MDT_TOWNS, GF_OLD256 | GF_FEW_LOCALS | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"loom", "EGA", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH}, - {"loom", "No AdLib", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_CMS, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"loom", "EGA", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH}, + {"loom", "No AdLib", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, #ifdef USE_RGB_COLOR {"loom", "PC-Engine", 0, GID_LOOM, 3, 0, MDT_NONE, GF_AUDIOTRACKS | GF_OLD256 | GF_16BIT_COLOR, Common::kPlatformPCEngine, GUIO_NOSPEECH | GUIO_NOMIDI}, #endif {"loom", "FM-TOWNS", 0, GID_LOOM, 3, 0, MDT_TOWNS, GF_AUDIOTRACKS | GF_OLD256, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI}, {"loom", "VGA", "vga", GID_LOOM, 4, 0, MDT_NONE, GF_AUDIOTRACKS, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"pass", 0, 0, GID_PASS, 4, 0, MDT_PCSPK | MDT_ADLIB, GF_16COLOR, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"pass", 0, 0, GID_PASS, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB, GF_16COLOR, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"monkey", "VGA", "vga", GID_MONKEY_VGA, 4, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH}, - {"monkey", "EGA", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_16COLOR, Common::kPlatformPC, GUIO_NOSPEECH}, - {"monkey", "No AdLib", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK, GF_16COLOR, Common::kPlatformAtariST, GUIO_NOSPEECH | GUIO_NOMIDI}, - {"monkey", "Demo", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_ADLIB, GF_16COLOR, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"monkey", "VGA", "vga", GID_MONKEY_VGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH}, + {"monkey", "EGA", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_16COLOR, Common::kPlatformPC, GUIO_NOSPEECH}, + {"monkey", "No AdLib", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR, GF_16COLOR, Common::kPlatformAtariST, GUIO_NOSPEECH | GUIO_NOMIDI}, + {"monkey", "Demo", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB, GF_16COLOR, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI}, {"monkey", "CD", 0, GID_MONKEY, 5, 0, MDT_ADLIB, GF_AUDIOTRACKS, UNK, GUIO_NOSPEECH | GUIO_NOMIDI}, {"monkey", "FM-TOWNS", 0, GID_MONKEY, 5, 0, MDT_ADLIB, GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI}, {"monkey", "SEGA", 0, GID_MONKEY, 5, 0, MDT_NONE, GF_AUDIOTRACKS, Common::kPlatformSegaCD, GUIO_NOSPEECH | GUIO_NOMIDI}, diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp index be9f69ffb5..29f0c025d2 100644 --- a/engines/scumm/script.cpp +++ b/engines/scumm/script.cpp @@ -708,7 +708,7 @@ void ScummEngine::writeVar(uint var, int value) { error("Illegal varbits (w)"); } -void ScummEngine::getResultPos() { +void ScummEngine_v5::getResultPos() { int a; _resultVarNumber = fetchScriptWord(); @@ -723,7 +723,7 @@ void ScummEngine::getResultPos() { } } -void ScummEngine::setResult(int value) { +void ScummEngine_v5::setResult(int value) { writeVar(_resultVarNumber, value); } diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index ab7be02c48..50901b8f9e 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -214,7 +214,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _opcode = 0; vm.numNestedScripts = 0; _lastCodePtr = NULL; - _resultVarNumber = 0; _scummStackPos = 0; memset(_vmStack, 0, sizeof(_vmStack)); _fileOffset = 0; @@ -631,6 +630,10 @@ ScummEngine_v5::ScummEngine_v5(OSystem *syst, const DetectorResult &dr) _flashlight.xStrips = 7; _flashlight.yStrips = 7; _flashlight.buffer = NULL; + + memset(_saveLoadVarsFilename, 0, sizeof(_saveLoadVarsFilename)); + + _resultVarNumber = 0; } ScummEngine_v4::ScummEngine_v4(OSystem *syst, const DetectorResult &dr) @@ -1642,9 +1645,11 @@ void ScummEngine::setupMusic(int midi) { _musicType = MDT_NONE; break; case MT_PCSPK: - case MT_PCJR: _musicType = MDT_PCSPK; break; + case MT_PCJR: + _musicType = MDT_PCJR; + break; //case MT_CMS: #if 1 _musicType = MDT_ADLIB; @@ -1658,6 +1663,12 @@ void ScummEngine::setupMusic(int midi) { case MT_ADLIB: _musicType = MDT_ADLIB; break; + case MT_C64: + _musicType = MDT_C64; + break; + case MT_APPLEIIGS: + _musicType = MDT_APPLEIIGS; + break; default: _musicType = MDT_MIDI; break; @@ -1706,7 +1717,7 @@ void ScummEngine::setupMusic(int midi) { * automatically when samples need to be generated */ if (!_mixer->isReady()) { warning("Sound mixer initialization failed"); - if (_musicType == MDT_ADLIB || _musicType == MDT_PCSPK || _musicType == MDT_CMS) { + if (_musicType == MDT_ADLIB || _musicType == MDT_PCSPK || _musicType == MDT_PCJR || _musicType == MDT_CMS) { dev = 0; _musicType = MDT_NONE; warning("MIDI driver depends on sound mixer, switching to null MIDI driver"); @@ -1740,7 +1751,7 @@ void ScummEngine::setupMusic(int midi) { _musicEngine = new Player_V1(this, _mixer, MidiDriver::getMusicType(dev) != MT_PCSPK); } else if (_game.version <= 2) { _musicEngine = new Player_V2(this, _mixer, MidiDriver::getMusicType(dev) != MT_PCSPK); - } else if ((_musicType == MDT_PCSPK) && (_game.version > 2 && _game.version <= 4)) { + } else if ((_musicType == MDT_PCSPK || _musicType == MDT_PCJR) && (_game.version > 2 && _game.version <= 4)) { _musicEngine = new Player_V2(this, _mixer, MidiDriver::getMusicType(dev) != MT_PCSPK); } else if (_musicType == MDT_CMS) { _musicEngine = new Player_V2CMS(this, _mixer); diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 42322ba5a2..8c3df21238 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -689,7 +689,7 @@ protected: const byte *_scriptPointer, *_scriptOrgPointer; byte _opcode, _currentScript; const byte * const *_lastCodePtr; - int _resultVarNumber, _scummStackPos; + int _scummStackPos; int _vmStack[150]; OpcodeEntry _opcodes[256]; @@ -745,8 +745,6 @@ protected: int fetchScriptDWordSigned(); void ignoreScriptWord() { fetchScriptWord(); } void ignoreScriptByte() { fetchScriptByte(); } - virtual void getResultPos(); - void setResult(int result); void push(int a); int pop(); virtual int readVar(uint var); diff --git a/engines/scumm/scumm_v5.h b/engines/scumm/scumm_v5.h index 2580384fd8..71222470f4 100644 --- a/engines/scumm/scumm_v5.h +++ b/engines/scumm/scumm_v5.h @@ -50,6 +50,8 @@ protected: PARAM_3 = 0x20 }; + int _resultVarNumber; + public: ScummEngine_v5(OSystem *syst, const DetectorResult &dr); @@ -77,6 +79,9 @@ protected: virtual int getVarOrDirectByte(byte mask); virtual int getVarOrDirectWord(byte mask); + virtual void getResultPos(); + void setResult(int result); + virtual void animateCursor(); virtual void setBuiltinCursor(int index); diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index 840f8fc779..99ab1b23b7 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -169,7 +169,18 @@ void Sound::playSound(int soundID) { static const char tracks[20] = {3, 4, 5, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 19, 20, 21}; _currentCDSound = soundID; - playCDTrack(tracks[soundID - 13], 1, 0, 0); + + // The original game had hard-coded lengths for all + // tracks, but this one track is the only one (as far + // as we know) where this actually matters. See bug + // #3024173 - LOOM-PCE: Music stops prematurely. + + int track = tracks[soundID - 13]; + if (track == 6) { + playCDTrack(track, 1, 0, 260); + } else { + playCDTrack(track, 1, 0, 0); + } } else { if (_vm->_musicEngine) { _vm->_musicEngine->startSound(soundID); @@ -1133,7 +1144,7 @@ int ScummEngine::readSoundResource(int idx) { switch (basetag) { case MKID_BE('MIDI'): case MKID_BE('iMUS'): - if (_musicType != MDT_PCSPK) { + if (_musicType != MDT_PCSPK && _musicType != MDT_PCJR) { _fileHandle->seek(-8, SEEK_CUR); _fileHandle->read(_res->createResource(rtSound, idx, total_size + 8), total_size + 8); return 1; @@ -1176,12 +1187,12 @@ int ScummEngine::readSoundResource(int idx) { break; case MKID_BE('SPK '): pri = -1; -// if (_musicType == MDT_PCSPK) +// if (_musicType == MDT_PCSPK || _musicType == MDT_PCJR) // pri = 11; break; } - if ((_musicType == MDT_PCSPK || _musicType == MDT_CMS) && pri != 11) + if ((_musicType == MDT_PCSPK || _musicType == MDT_PCJR || _musicType == MDT_CMS) && pri != 11) pri = -1; debugC(DEBUG_RESOURCE, " tag: %s, total_size=%d, pri=%d", tag2str(tag), size, pri); @@ -2113,7 +2124,7 @@ int ScummEngine::readSoundResourceSmallHeader(int idx) { } } - if ((_musicType == MDT_PCSPK) && wa_offs != 0) { + if ((_musicType == MDT_PCSPK || _musicType == MDT_PCJR) && wa_offs != 0) { if (_game.features & GF_OLD_BUNDLE) { _fileHandle->seek(wa_offs, SEEK_SET); _fileHandle->read(_res->createResource(rtSound, idx, wa_size), wa_size); diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp index cacfd0101b..d1d3ed63a4 100644 --- a/engines/scumm/vars.cpp +++ b/engines/scumm/vars.cpp @@ -727,6 +727,9 @@ void ScummEngine::resetScummVars() { case MDT_PCSPK: VAR(VAR_SOUNDCARD) = 0; break; + case MDT_PCJR: + VAR(VAR_SOUNDCARD) = 1; + break; case MDT_CMS: VAR(VAR_SOUNDCARD) = 2; break; |