diff options
author | Christopher Page | 2008-08-16 04:30:01 +0000 |
---|---|---|
committer | Christopher Page | 2008-08-16 04:30:01 +0000 |
commit | 909b66ef54f8d6d6dfeb0fdee2aa018f2065b6c9 (patch) | |
tree | c2f2668391fa3026a6a79b38ebfad797ce1b376c /engines/cine | |
parent | c22f9b23588121d41fe0a12ce44926d683d7a18d (diff) | |
parent | f2111eeb45dc8c41afb3e63bf3b86a09bf9a3532 (diff) | |
download | scummvm-rg350-909b66ef54f8d6d6dfeb0fdee2aa018f2065b6c9.tar.gz scummvm-rg350-909b66ef54f8d6d6dfeb0fdee2aa018f2065b6c9.tar.bz2 scummvm-rg350-909b66ef54f8d6d6dfeb0fdee2aa018f2065b6c9.zip |
Merged revisions 33777,33781-33788,33790,33792-33793,33795,33797,33805,33807-33812,33815-33817,33819,33822,33826,33829,33837,33839,33844,33847,33858-33861,33864,33871-33873,33875,33877-33879,33886,33889-33892,33894,33896,33900,33902-33903,33919 via svnmerge from
https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk
svn-id: r33924
Diffstat (limited to 'engines/cine')
-rw-r--r-- | engines/cine/cine.cpp | 12 | ||||
-rw-r--r-- | engines/cine/gfx.cpp | 143 | ||||
-rw-r--r-- | engines/cine/gfx.h | 6 | ||||
-rw-r--r-- | engines/cine/main_loop.cpp | 8 | ||||
-rw-r--r-- | engines/cine/msg.cpp | 45 | ||||
-rw-r--r-- | engines/cine/pal.cpp | 36 | ||||
-rw-r--r-- | engines/cine/pal.h | 2 | ||||
-rw-r--r-- | engines/cine/part.cpp | 53 | ||||
-rw-r--r-- | engines/cine/part.h | 6 | ||||
-rw-r--r-- | engines/cine/sound.cpp | 1 | ||||
-rw-r--r-- | engines/cine/texte.cpp | 186 | ||||
-rw-r--r-- | engines/cine/texte.h | 24 | ||||
-rw-r--r-- | engines/cine/various.cpp | 145 | ||||
-rw-r--r-- | engines/cine/various.h | 5 |
14 files changed, 396 insertions, 276 deletions
diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index c30cac63a5..ea4b2512f5 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -68,14 +68,9 @@ CineEngine::CineEngine(OSystem *syst, const CINEGameDescription *gameDesc) : Eng CineEngine::~CineEngine() { if (g_cine->getGameType() == Cine::GType_OS) { - freePoldatDat(); freeErrmessDat(); } Common::clearAllSpecialDebugLevels(); - - free(palPtr); - free(partBuffer); - free(textDataPtr); } int CineEngine::init() { @@ -152,15 +147,16 @@ void CineEngine::initialize() { } collisionPage = new byte[320 * 200]; - textDataPtr = (byte *)malloc(8000); - partBuffer = (PartBuffer *)malloc(NUM_MAX_PARTDATA * sizeof(PartBuffer)); + // 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(); if (g_cine->getGameType() == Cine::GType_OS) { readVolCnf(); } - loadTextData("texte.dat", textDataPtr); + loadTextData("texte.dat"); if (g_cine->getGameType() == Cine::GType_OS && !(g_cine->getFeatures() & GF_DEMO)) { loadPoldatDat("poldat.dat"); diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index c6c5faf464..cb900e8850 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -31,6 +31,7 @@ #include "common/endian.h" #include "common/system.h" +#include "common/events.h" #include "graphics/cursorman.h" @@ -91,7 +92,7 @@ static const byte cursorPalette[] = { */ FWRenderer::FWRenderer() : _background(NULL), _palette(NULL), _cmd(""), _cmdY(0), _messageBg(0), _backBuffer(new byte[_screenSize]), - _activeLowPal(NULL), _changePal(0) { + _activeLowPal(NULL), _changePal(0), _showCollisionPage(false) { assert(_backBuffer); @@ -125,6 +126,7 @@ void FWRenderer::clear() { _cmdY = 0; _messageBg = 0; _changePal = 0; + _showCollisionPage = false; } /*! \brief Draw 1bpp sprite using selected color @@ -225,14 +227,18 @@ void FWRenderer::drawCommand() { * \param x Top left message box corner coordinate * \param y Top left message box corner coordinate * \param width Message box width - * \param color Message box background color + * \param color Message box background color (Or if negative draws only the text) + * \note Negative colors are used in Operation Stealth's timed cutscenes + * (e.g. when first meeting The Movement for the Liberation of Santa Paragua). */ -void FWRenderer::drawMessage(const char *str, int x, int y, int width, byte color) { +void FWRenderer::drawMessage(const char *str, int x, int y, int width, int color) { int i, tx, ty, tw; int line = 0, words = 0, cw = 0; int space = 0, extraSpace = 0; - drawPlainBox(x, y, width, 4, color); + if (color >= 0) { + drawPlainBox(x, y, width, 4, color); + } tx = x + 4; ty = str[0] ? y - 5 : y + 4; tw = width - 8; @@ -252,7 +258,9 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, byte colo } ty += 9; - drawPlainBox(x, ty, width, 9, color); + if (color >= 0) { + drawPlainBox(x, ty, width, 9, color); + } tx = x + 4; } @@ -269,8 +277,10 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, byte colo } ty += 9; - drawPlainBox(x, ty, width, 4, color); - drawDoubleBorder(x, y, width, ty - y + 4, 2); + if (color >= 0) { + drawPlainBox(x, ty, width, 4, color); + drawDoubleBorder(x, y, width, ty - y + 4, 2); + } } /*! \brief Draw rectangle on screen @@ -279,54 +289,44 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, byte colo * \param width Rectangle width (Negative values draw the box horizontally flipped) * \param height Rectangle height (Negative values draw the box vertically flipped) * \param color Fill color - * \note Rectangle's drawn width is always at least one. - * \note Rectangle's drawn height is always at least one. + * \note An on-screen rectangle's drawn width is always at least one. + * \note An on-screen rectangle's drawn height is always at least one. */ void FWRenderer::drawPlainBox(int x, int y, int width, int height, byte color) { - int i; + // Make width's and height's absolute values at least one + // which forces this function to always draw something if the + // drawing position is inside screen bounds. This fixes at least + // the showing of the oxygen gauge meter in Operation Stealth's + // first arcade sequence where this function is called with a + // height of zero. + if (width == 0) { + width = 1; + } + if (height == 0) { + height = 1; + } // Handle horizontally flipped boxes if (width < 0) { - x += width; width = ABS(width); + x -= width; } // Handle vertically flipped boxes if (height < 0) { - y += height; height = ABS(height); + y -= height; } - // Handle horizontal boundaries - if (x < 0) { - width += x; // Remove invisible columns - x = 0; // Start drawing at the screen's left border - } else if (x > 319) { - // Nothing left to draw as we're over the screen's right border - width = 0; - } - - // Handle vertical boundaries - if (y < 0) { - height += y; // Remove invisible rows - y = 0; // Start drawing at the screen's top border - } else if (y > 199) { - // Nothing left to draw as we're below the screen's bottom border - height = 0; - } + // Clip the rectangle to screen dimensions + Common::Rect boxRect(x, y, x + width, y + height); + Common::Rect screenRect(320, 200); + boxRect.clip(screenRect); - // Make width and height at least one - // which forces this function to always draw something. - // This fixes at least the showing of the oxygen gauge meter in - // Operation Stealth's first arcade sequence where this function - // is called with a height of zero. - width = MAX(1, width); - height = MAX(1, height); - - // Draw the filled rectangle - byte *dest = _backBuffer + y * 320 + x; - for (i = 0; i < height; i++) { - memset(dest + i * 320, color, width); + // Draw the filled rectangle + byte *dest = _backBuffer + boxRect.top * 320 + boxRect.left; + for (int i = 0; i < boxRect.height(); i++) { + memset(dest + i * 320, color, boxRect.width()); } } @@ -366,8 +366,8 @@ int FWRenderer::drawChar(char character, int x, int y) { if (character == ' ') { x += 5; - } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) { - idx = fontParamTable[(unsigned char)character].characterIdx; + } else if ((width = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterWidth)) { + idx = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterIdx; drawSpriteRaw(g_cine->_textHandler.textTable[idx][0], g_cine->_textHandler.textTable[idx][1], 16, 8, _backBuffer, x, y); x += width + 1; } @@ -513,16 +513,28 @@ void FWRenderer::drawFrame() { blit(); } +/*! + * \brief Turn on or off the showing of the collision page. + * If turned on the blitting routine shows the collision page instead of the back buffer. + * \note Useful for debugging collision page related problems. + */ +void FWRenderer::showCollisionPage(bool state) { + _showCollisionPage = state; +} + /*! \brief Update screen */ void FWRenderer::blit() { - g_system->copyRectToScreen(_backBuffer, 320, 0, 0, 320, 200); + // Show the back buffer or the collision page. Normally the back + // buffer but showing the collision page is useful for debugging. + byte *source = (_showCollisionPage ? collisionPage : _backBuffer); + g_system->copyRectToScreen(source, 320, 0, 0, 320, 200); } /*! \brief Set player command string * \param cmd New command string */ -void FWRenderer::setCommand(const char *cmd) { +void FWRenderer::setCommand(Common::String cmd) { _cmd = cmd; } @@ -1023,8 +1035,8 @@ int OSRenderer::drawChar(char character, int x, int y) { if (character == ' ') { x += 5; - } else if ((width = fontParamTable[(unsigned char)character].characterWidth)) { - idx = fontParamTable[(unsigned char)character].characterIdx; + } else if ((width = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterWidth)) { + idx = g_cine->_textHandler.fontParamTable[(unsigned char)character].characterIdx; drawSpriteRaw2(g_cine->_textHandler.textTable[idx][0], 0, 16, 8, _backBuffer, x, y); x += width + 1; } @@ -1063,10 +1075,11 @@ void OSRenderer::drawBackground() { * \todo Add handling of type 22 overlays */ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { - int len; + int len, idx, width, height; objectStruct *obj; AnimData *sprite; byte *mask; + byte color; switch (it->type) { // color sprite @@ -1096,6 +1109,19 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { } break; + // action failure message + case 3: + idx = it->objIdx * 4 + g_cine->_rnd.getRandomNumber(3); + len = strlen(failureMessages[idx]); + _messageLen += len; + width = 6 * len + 20; + width = width > 300 ? 300 : width; + + // The used color here differs from Future Wars + drawMessage(failureMessages[idx], (320 - width) / 2, 80, width, _messageBg); + waitForPlayerClick = 1; + break; + // bitmap case 4: if (objectTable[it->objIdx].frame >= 0) { @@ -1117,26 +1143,25 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { maskBgOverlay(_bgTable[it->x].bg, sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, obj->x, obj->y); break; - // FIXME: Looking at Operation Stealth's disassembly I can't find any codepath that - // will draw a type 21 overlay. But looking at the first arcade sequence's scripts - // it looks like the oxygen gauge meter is implemented using a type 21 overlay. - // So for the time being I'm simply drawing type 21 overlays as type 22 overlays - // and hoping for the best. - // TODO: Check how the original game looks under DOSBox to see if the oxygen gauge works in it + // FIXME: Implement correct drawing of type 21 overlays. + // Type 21 overlays aren't just filled rectangles, I found their drawing routine + // from Operation Stealth's drawSprite routine. So they're likely some kind of sprites + // and it's just a coincidence that the oxygen meter during the first arcade sequence + // works even somehow currently. I tried the original under DOSBox and the oxygen gauge + // is a long red bar that gets shorter as the air runs out. case 21: // A filled rectangle: - case 22: { + 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]; - byte color = obj->part & 0x0F; - int width = obj->frame; - int height = obj->costume; + color = obj->part & 0x0F; + width = obj->frame; + height = obj->costume; drawPlainBox(obj->x, obj->y, width, height, color); debug(5, "renderOverlay: type=%d, x=%d, y=%d, width=%d, height=%d, color=%d", it->type, obj->x, obj->y, width, height, color); break; - } // something else default: diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h index 078954e3b9..c07214028c 100644 --- a/engines/cine/gfx.h +++ b/engines/cine/gfx.h @@ -62,13 +62,14 @@ protected: byte *_backBuffer; ///< Screen backbuffer uint16 *_activeLowPal; ///< Active 16 color palette int _changePal; ///< Load active palette to video backend on next frame + bool _showCollisionPage; ///< Should we show the collision page instead of the back buffer? Used for debugging. void fillSprite(const objectStruct &obj, uint8 color = 0); void drawMaskedSprite(const objectStruct &obj, const byte *mask); virtual void drawSprite(const objectStruct &obj); void drawCommand(); - void drawMessage(const char *str, int x, int y, int width, byte color); + void drawMessage(const char *str, int x, int y, int width, int color); void drawPlainBox(int x, int y, int width, int height, byte color); void drawBorder(int x, int y, int width, int height, byte color); void drawDoubleBorder(int x, int y, int width, int height, byte color); @@ -94,7 +95,7 @@ public: void drawFrame(); void blit(); - void setCommand(const char *cmd); + void setCommand(Common::String cmd); virtual void incrustMask(const objectStruct &obj, uint8 color = 0); virtual void incrustSprite(const objectStruct &obj); @@ -124,6 +125,7 @@ public: void drawInputBox(const char *info, const char *input, int cursor, int x, int y, int width); virtual void fadeToBlack(); + void showCollisionPage(bool state); }; /*! \brief Operation Stealth renderer diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 3b0dc80bfb..04c6f5c769 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -121,6 +121,9 @@ static void processEvent(Common::Event &event) { g_cine->makeSystemMenu(); } break; + case Common::KEYCODE_F11: + renderer->showCollisionPage(true); + break; case Common::KEYCODE_MINUS: case Common::KEYCODE_KP_MINUS: g_cine->modifyGameSpeed(-1); // Slower @@ -164,6 +167,9 @@ static void processEvent(Common::Event &event) { break; case Common::EVENT_KEYUP: switch (event.kbd.keycode) { + case Common::KEYCODE_F11: + renderer->showCollisionPage(false); + break; case Common::KEYCODE_KP5: // Emulated left mouse button click case Common::KEYCODE_LEFT: // Left case Common::KEYCODE_KP4: // Left @@ -276,7 +282,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { menuCommandLen = 0; playerCommand = -1; - strcpy(commandBuffer, ""); + commandBuffer = ""; globalVars[VAR_MOUSE_X_POS] = 0; globalVars[VAR_MOUSE_Y_POS] = 0; diff --git a/engines/cine/msg.cpp b/engines/cine/msg.cpp index 55eb627309..c826db3bf3 100644 --- a/engines/cine/msg.cpp +++ b/engines/cine/msg.cpp @@ -34,29 +34,40 @@ namespace Cine { Common::StringList messageTable; void loadMsg(char *pMsgName) { - int i, count, len; - byte *ptr, *dataPtr; - const char *messagePtr; + uint32 sourceSize; checkDataDisk(-1); - messageTable.clear(); - - ptr = dataPtr = readBundleFile(findFileInBundle(pMsgName)); + byte *dataPtr = readBundleFile(findFileInBundle(pMsgName), &sourceSize); setMouseCursor(MOUSE_CURSOR_DISK); - count = READ_BE_UINT16(ptr); - ptr += 2; - - messagePtr = (const char*)(ptr + 2 * count); - - for (i = 0; i < count; i++) { - len = READ_BE_UINT16(ptr); - ptr += 2; - - messageTable.push_back(messagePtr); - messagePtr += len; + uint count = READ_BE_UINT16(dataPtr); + uint messageLenPos = 2; + uint messageDataPos = messageLenPos + 2 * count; + + // Read in the messages + for (uint i = 0; i < count; i++) { + // Read message's length + uint messageLen = READ_BE_UINT16(dataPtr + messageLenPos); + messageLenPos += 2; + + // Store the read message. + // 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)); + } 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); + } else { + 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(""); + } + // Jump to the next message + messageDataPos += messageLen; } free(dataPtr); diff --git a/engines/cine/pal.cpp b/engines/cine/pal.cpp index 3e6f5adf40..7f6307c640 100644 --- a/engines/cine/pal.cpp +++ b/engines/cine/pal.cpp @@ -28,10 +28,7 @@ namespace Cine { -uint16 palEntriesCount; - -PalEntry *palPtr = NULL; - +Common::Array<PalEntry> palArray; static byte paletteBuffer1[16]; static byte paletteBuffer2[16]; @@ -41,27 +38,20 @@ void loadPal(const char *fileName) { removeExtention(buffer, fileName); strcat(buffer, ".PAL"); - - if (palPtr) { - free(palPtr); - palPtr = NULL; - } - - palEntriesCount = 0; + palArray.clear(); Common::File palFileHandle; if (!palFileHandle.open(buffer)) error("loadPal(): Cannot open file %s", fileName); - palEntriesCount = palFileHandle.readUint16LE(); + uint16 palEntriesCount = palFileHandle.readUint16LE(); palFileHandle.readUint16LE(); // entry size - palPtr = (PalEntry *)malloc(palEntriesCount * sizeof(PalEntry)); - assert(palPtr); - for (int i = 0; i < palEntriesCount; ++i) { - palFileHandle.read(palPtr[i].name, 10); - palFileHandle.read(palPtr[i].pal1, 16); - palFileHandle.read(palPtr[i].pal2, 16); + 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); } palFileHandle.close(); } @@ -81,8 +71,8 @@ int16 findPaletteFromName(const char *fileName) { position++; } - for (i = 0; i < palEntriesCount; i++) { - if (!strcmp(buffer, palPtr[i].name)) { + for (i = 0; i < palArray.size(); i++) { + if (!strcmp(buffer, palArray[i].name)) { return i; } } @@ -105,9 +95,9 @@ void loadRelatedPalette(const char *fileName) { paletteBuffer1[i] = paletteBuffer2[i] = (i << 4) + i; } } else { - assert(paletteIndex < palEntriesCount); - memcpy(paletteBuffer1, palPtr[paletteIndex].pal1, 16); - memcpy(paletteBuffer2, palPtr[paletteIndex].pal2, 16); + assert(paletteIndex < (int32)palArray.size()); + memcpy(paletteBuffer1, palArray[paletteIndex].pal1, 16); + memcpy(paletteBuffer2, palArray[paletteIndex].pal2, 16); } } diff --git a/engines/cine/pal.h b/engines/cine/pal.h index 768cf0d27d..819680973c 100644 --- a/engines/cine/pal.h +++ b/engines/cine/pal.h @@ -34,7 +34,7 @@ struct PalEntry { byte pal2[16]; }; -extern PalEntry *palPtr; +extern Common::Array<PalEntry> palArray; void loadPal(const char *fileName); diff --git a/engines/cine/part.cpp b/engines/cine/part.cpp index d605bdd623..657471be4e 100644 --- a/engines/cine/part.cpp +++ b/engines/cine/part.cpp @@ -31,13 +31,10 @@ namespace Cine { -uint16 numElementInPart; - -PartBuffer *partBuffer; +Common::Array<PartBuffer> partBuffer; void loadPart(const char *partName) { - memset(partBuffer, 0, sizeof(PartBuffer) * NUM_MAX_PARTDATA); - numElementInPart = 0; + partBuffer.clear(); g_cine->_partFileHandle.close(); @@ -48,13 +45,14 @@ void loadPart(const char *partName) { setMouseCursor(MOUSE_CURSOR_DISK); - numElementInPart = g_cine->_partFileHandle.readUint16BE(); + uint16 numElementInPart = g_cine->_partFileHandle.readUint16BE(); + partBuffer.resize(numElementInPart); g_cine->_partFileHandle.readUint16BE(); // entry size if (currentPartName != partName) strcpy(currentPartName, partName); - for (uint16 i = 0; i < numElementInPart; i++) { + 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(); @@ -190,7 +188,7 @@ void CineEngine::readVolCnf() { int16 findFileInBundle(const char *fileName) { if (g_cine->getGameType() == Cine::GType_OS) { // look first in currently loaded resource file - for (int i = 0; i < numElementInPart; i++) { + for (uint i = 0; i < partBuffer.size(); i++) { if (!scumm_stricmp(fileName, partBuffer[i].partName)) { return i; } @@ -204,7 +202,7 @@ int16 findFileInBundle(const char *fileName) { const char *part = (*it)._value; loadPart(part); } - for (int i = 0; i < numElementInPart; i++) { + for (uint i = 0; i < partBuffer.size(); i++) { if (!scumm_stricmp(fileName, partBuffer[i].partName)) { return i; } @@ -212,26 +210,35 @@ int16 findFileInBundle(const char *fileName) { return -1; } -void readFromPart(int16 idx, byte *dataPtr) { +void readFromPart(int16 idx, byte *dataPtr, uint32 maxSize) { setMouseCursor(MOUSE_CURSOR_DISK); g_cine->_partFileHandle.seek(partBuffer[idx].offset, SEEK_SET); - g_cine->_partFileHandle.read(dataPtr, partBuffer[idx].packedSize); + g_cine->_partFileHandle.read(dataPtr, MIN(partBuffer[idx].packedSize, maxSize)); } -byte *readBundleFile(int16 foundFileIdx) { - assert(foundFileIdx >= 0 && foundFileIdx < numElementInPart); +byte *readBundleFile(int16 foundFileIdx, uint32 *size) { + assert(foundFileIdx >= 0 && foundFileIdx < (int32)partBuffer.size()); + bool error = false; byte *dataPtr = (byte *)calloc(partBuffer[foundFileIdx].unpackedSize, 1); - if (partBuffer[foundFileIdx].unpackedSize != partBuffer[foundFileIdx].packedSize) { - byte *unpackBuffer = (byte *)malloc(partBuffer[foundFileIdx].packedSize); - readFromPart(foundFileIdx, unpackBuffer); + readFromPart(foundFileIdx, dataPtr, partBuffer[foundFileIdx].unpackedSize); + if (partBuffer[foundFileIdx].unpackedSize > partBuffer[foundFileIdx].packedSize) { CineUnpacker cineUnpacker; - if (!cineUnpacker.unpack(unpackBuffer, partBuffer[foundFileIdx].packedSize, dataPtr, partBuffer[foundFileIdx].unpackedSize)) { - warning("Error unpacking '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName); - } - free(unpackBuffer); - } else { - readFromPart(foundFileIdx, dataPtr); + error = !cineUnpacker.unpack(dataPtr, partBuffer[foundFileIdx].packedSize, dataPtr, partBuffer[foundFileIdx].unpackedSize); + } else if (partBuffer[foundFileIdx].unpackedSize < partBuffer[foundFileIdx].packedSize) { + // Unpacked size of a file should never be less than its packed size + error = true; + } else { // partBuffer[foundFileIdx].unpackedSize == partBuffer[foundFileIdx].packedSize + debugC(5, kCineDebugPart, "Loaded non-compressed file '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName); + } + + if (error) { + warning("Error unpacking '%s' from bundle file '%s'", partBuffer[foundFileIdx].partName, currentPartName); + } + + // Set the size variable if a pointer to it has been given + if (size != NULL) { + *size = partBuffer[foundFileIdx].unpackedSize; } return dataPtr; @@ -300,7 +307,7 @@ void dumpBundle(const char *fileName) { strcpy(tmpPart, currentPartName); loadPart(fileName); - for (int i = 0; i < numElementInPart; i++) { + for (uint i = 0; i < partBuffer.size(); i++) { byte *data = readBundleFile(i); debug(0, "%s", partBuffer[i].partName); diff --git a/engines/cine/part.h b/engines/cine/part.h index 72dc944db3..755f843b4a 100644 --- a/engines/cine/part.h +++ b/engines/cine/part.h @@ -37,16 +37,16 @@ struct PartBuffer { #define NUM_MAX_PARTDATA 255 -extern PartBuffer *partBuffer; +extern Common::Array<PartBuffer> partBuffer; void loadPart(const char *partName); void closePart(void); int16 findFileInBundle(const char *fileName); -void readFromPart(int16 idx, byte *dataPtr); +void readFromPart(int16 idx, byte *dataPtr, uint32 maxSize); -byte *readBundleFile(int16 foundFileIdx); +byte *readBundleFile(int16 foundFileIdx, uint32 *size = NULL); byte *readBundleSoundFile(const char *entryName, uint32 *size = 0); byte *readFile(const char *filename, bool crypted = false); diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp index f26032fe98..3618350476 100644 --- a/engines/cine/sound.cpp +++ b/engines/cine/sound.cpp @@ -604,6 +604,7 @@ bool PCSoundFxPlayer::load(const char *song) { _instrumentsData[i] = NULL; char instrument[64]; + memset(instrument, 0, 64); // Clear the data first memcpy(instrument, _sfxData + 20 + i * 30, 12); instrument[63] = '\0'; diff --git a/engines/cine/texte.cpp b/engines/cine/texte.cpp index e4fd334926..33c16159ec 100644 --- a/engines/cine/texte.cpp +++ b/engines/cine/texte.cpp @@ -29,70 +29,53 @@ namespace Cine { -byte *textDataPtr; - const char **failureMessages; const CommandeType *defaultActionCommand; const CommandeType *systemMenu; const CommandeType *confirmMenu; const char **otherMessages; -const char *commandPrepositionOn; +const char *defaultCommandPreposition; +const char **commandPrepositionTable; void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency); -void loadTextData(const char *pFileName, byte *pDestinationBuffer) { - Common::File pFileHandle; - uint16 entrySize; - uint16 numEntry; - uint16 i; - byte *tempBuffer; - uint16 dataSize; - - assert(pFileName); - assert(pDestinationBuffer); +void loadTextData(const char *filename) { + Common::File fileHandle; + assert(filename); - if (!pFileHandle.open(pFileName)) - error("loadTextData(): Cannot open file %s", pFileName); + if (!fileHandle.open(filename)) + error("loadTextData(): Cannot open file %s", filename); - entrySize = pFileHandle.readUint16BE(); - numEntry = pFileHandle.readUint16BE(); + uint entrySize = fileHandle.readUint16BE(); + uint numEntry = fileHandle.readUint16BE(); - dataSize = numEntry * entrySize; - pFileHandle.read(pDestinationBuffer, numEntry * entrySize); - - tempBuffer = pDestinationBuffer; + uint sourceSize = numEntry * entrySize; + Common::Array<byte> source; + source.resize(sourceSize); + fileHandle.read(source.begin(), sourceSize); + const int fontHeight = 8; + const int fontWidth = (g_cine->getGameType() == Cine::GType_FW) ? 16 : 8; + uint numCharacters; + uint bytesPerCharacter; if (g_cine->getGameType() == Cine::GType_FW) { - int numCharacters; - if (g_cine->getFeatures() & GF_ALT_FONT) { - numCharacters = 85; - } else { - numCharacters = 78; - } - - dataSize = dataSize / numCharacters; - - loadRelatedPalette(pFileName); - - for (i = 0; i < numCharacters; i++) { - gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 16, 8); - generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 16 * 8, 0); - tempBuffer += dataSize; - } + numCharacters = (g_cine->getFeatures() & GF_ALT_FONT) ? 85 : 78; + bytesPerCharacter = sourceSize / numCharacters; // TODO: Check if this could be replaced with fontWidth * fontHeight + loadRelatedPalette(filename); } else { - for (i = 0; i < 90; i++) { - gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], tempBuffer, 8, 8); - generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], 8 * 8, 0); - tempBuffer += 0x40; - } + numCharacters = 90; + bytesPerCharacter = fontWidth * fontHeight; } - pFileHandle.close(); -} + for (uint i = 0; i < numCharacters; i++) { + gfxConvertSpriteToRaw(g_cine->_textHandler.textTable[i][0], &source[i * bytesPerCharacter], fontWidth, fontHeight); + generateMask(g_cine->_textHandler.textTable[i][0], g_cine->_textHandler.textTable[i][1], fontWidth * fontHeight, 0); + } -const CharacterEntry *fontParamTable; + fileHandle.close(); +} -const CharacterEntry fontParamTable_standard[256] = { +static const CharacterEntry fontParamTable_standard[NUM_FONT_CHARS] = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, @@ -129,7 +112,7 @@ const CharacterEntry fontParamTable_standard[256] = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} }; -const CharacterEntry fontParamTable_alt[256] = { +static const CharacterEntry fontParamTable_alt[NUM_FONT_CHARS] = { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, @@ -208,6 +191,16 @@ void initLanguage(Common::Language lang) { "NOACTION" }; + static const char *commandPrepositionTable_EN[] = { + "", // EXAMINE + "", // TAKE + "", // INVENTORY + "on", // USE + "", // OPERATE + "to", // SPEAK + "" // NOACTION + }; + static const CommandeType systemMenu_EN[] = { "Pause", "Restart Game", @@ -223,9 +216,8 @@ void initLanguage(Common::Language lang) { "PAUSE", "Loading | %s", "Loading canceled ...", - "No baclup in the drive...", - "Please enter the backup name", - "on" + "No backup in the drive...", + "Please enter the backup name" }; static const CommandeType confirmMenu_EN[] = { @@ -276,6 +268,16 @@ void initLanguage(Common::Language lang) { "NOACTION" }; + static const char *commandPrepositionTable_FR[] = { + "", // EXAMINER + "", // PRENDRE + "", // INVENTAIRE + "sur", // UTILISER + "", // ACTIONNER + "a", // PARLER + "" // NOACTION + }; + static const CommandeType systemMenu_FR[] = { "Pause", "Nouvelle partie", @@ -297,8 +299,7 @@ void initLanguage(Common::Language lang) { "Sauvegarde de | %s", "Sauvegarde Annul\x82""e ...", "Aucune sauvegarde dans le lecteur ...", - "Veuillez entrer le Nom de la Sauvegarde .", - "sur" + "Veuillez entrer le Nom de la Sauvegarde ." }; static const char *failureMessages_ES[] = { @@ -344,6 +345,16 @@ void initLanguage(Common::Language lang) { "NOACTION" }; + static const char *commandPrepositionTable_ES[] = { + "", // EXAMINAR + "", // COGER + "", // INVENTARIO + "donde", // USAR + "", // ACCIONAR + "a", // HABLAR + "" // NOACTION + }; + static const CommandeType systemMenu_ES[] = { "Pause", "Nueva partida", @@ -365,8 +376,7 @@ void initLanguage(Common::Language lang) { "Gabacion de| %s", "Rrabacion anulada", "No hay partidas grabadas en este disco...", - "Teclea el nombre de la partida grabada", - "donde" + "Teclea el nombre de la partida grabada" }; static const char *failureMessages_DE[] = { @@ -403,15 +413,25 @@ void initLanguage(Common::Language lang) { }; static const CommandeType defaultActionCommand_DE[] = { - "Pr\x81""fe", + "Pr\x81""fe", // FIXME? The third letter should be Latin Small Letter U with diaeresis "Nimm", "Bestand", "Benutze", - "Bet\x84tige", + "Bet\x84tige", // FIXME? The fourth letter should be Latin Small Letter A with diaeresis "Sprich", "NOACTION" }; + static const char *commandPrepositionTable_DE[] = { + "", // Prufe + "", // Nimm + "", // Bestand + "gegen", // Benutze + "", // Betatige + "a", // Sprich + "" // NOACTION + }; + static const CommandeType systemMenu_DE[] = { "Pause", "Spiel Neu Starten", @@ -433,8 +453,7 @@ void initLanguage(Common::Language lang) { "Er L\x84""dt | %s", "Ladevorgang Abgebrochen...", "Kein Backup im Laufwerk...", - "Geben Sie den Namen|der Sicherungsdiskette ein", - "gegen" + "Geben Sie den Namen|der Sicherungsdiskette ein" }; static const char *failureMessages_IT[] = { @@ -480,6 +499,16 @@ void initLanguage(Common::Language lang) { "NOACTION" }; + static const char *commandPrepositionTable_IT[] = { + "", // ESAMINARE + "", // PRENDERE + "", // INVENTARIO + "su", // UTILIZZARE + "", // AZIONARE + "a", // PARLARE + "" // NOACTION + }; + static const CommandeType systemMenu_IT[] = { "Pausa", "Parte nuova", @@ -501,8 +530,7 @@ void initLanguage(Common::Language lang) { "Caricamento di| %s", "Caricamento annullato...", "Nessun salvataggio su questo disco...", - "Vogliate accedere con il nome del salvataggio", - "su" + "Vogliate accedere con il nome del salvataggio" }; switch (lang) { @@ -512,7 +540,8 @@ void initLanguage(Common::Language lang) { systemMenu = systemMenu_FR; confirmMenu = confirmMenu_FR; otherMessages = otherMessages_FR; - commandPrepositionOn = otherMessages_FR[7]; + defaultCommandPreposition = commandPrepositionTable_FR[3]; + commandPrepositionTable = commandPrepositionTable_FR; break; case Common::ES_ESP: @@ -521,7 +550,8 @@ void initLanguage(Common::Language lang) { systemMenu = systemMenu_ES; confirmMenu = confirmMenu_ES; otherMessages = otherMessages_ES; - commandPrepositionOn = otherMessages_ES[7]; + defaultCommandPreposition = commandPrepositionTable_ES[3]; + commandPrepositionTable = commandPrepositionTable_ES; break; case Common::DE_DEU: @@ -530,7 +560,8 @@ void initLanguage(Common::Language lang) { systemMenu = systemMenu_DE; confirmMenu = confirmMenu_DE; otherMessages = otherMessages_DE; - commandPrepositionOn = otherMessages_DE[7]; + defaultCommandPreposition = commandPrepositionTable_DE[3]; + commandPrepositionTable = commandPrepositionTable_DE; break; case Common::IT_ITA: @@ -539,7 +570,8 @@ void initLanguage(Common::Language lang) { systemMenu = systemMenu_IT; confirmMenu = confirmMenu_IT; otherMessages = otherMessages_IT; - commandPrepositionOn = otherMessages_IT[7]; + defaultCommandPreposition = commandPrepositionTable_IT[3]; + commandPrepositionTable = commandPrepositionTable_IT; break; default: @@ -548,14 +580,17 @@ void initLanguage(Common::Language lang) { systemMenu = systemMenu_EN; confirmMenu = confirmMenu_EN; otherMessages = otherMessages_EN; - commandPrepositionOn = otherMessages_EN[7]; + defaultCommandPreposition = commandPrepositionTable_EN[3]; + commandPrepositionTable = commandPrepositionTable_EN; break; } if (g_cine->getFeatures() & GF_ALT_FONT) { - fontParamTable = fontParamTable_alt; + // Copy alternative font parameter table to the current font parameter table + Common::copy(fontParamTable_alt, fontParamTable_alt + NUM_FONT_CHARS, g_cine->_textHandler.fontParamTable); } else { - fontParamTable = fontParamTable_standard; + // Copy standard font parameter to the current font parameter table + Common::copy(fontParamTable_standard, fontParamTable_standard + NUM_FONT_CHARS, g_cine->_textHandler.fontParamTable); } } @@ -590,25 +625,16 @@ void loadPoldatDat(const char *fname) { in.open(fname); if (in.isOpen()) { - CharacterEntry *ptr = (CharacterEntry *)malloc(sizeof(CharacterEntry) * 256); - - for (int i = 0; i < 256; i++) { - ptr[i].characterIdx = (int)in.readByte(); - ptr[i].characterWidth = (int)in.readByte(); + for (int i = 0; i < NUM_FONT_CHARS; i++) { + g_cine->_textHandler.fontParamTable[i].characterIdx = in.readByte(); + g_cine->_textHandler.fontParamTable[i].characterWidth = in.readByte(); } - fontParamTable = ptr; - in.close(); } else { error("Cannot open file %s for reading", fname); } } -void freePoldatDat() { - free(const_cast<Cine::CharacterEntry *>(fontParamTable)); - fontParamTable = 0; -} - /*! \brief Fit a substring of text into one line of fixed width text box * \param str Text to fit * \param maxWidth Text box width @@ -633,7 +659,7 @@ int fitLine(const char *str, int maxWidth, int &words, int &width) { bkpWidth = width; bkpLen = i + 1; } else { - charWidth = fontParamTable[(unsigned char)str[i]].characterWidth + 1; + charWidth = g_cine->_textHandler.fontParamTable[(unsigned char)str[i]].characterWidth + 1; width += charWidth; } diff --git a/engines/cine/texte.h b/engines/cine/texte.h index f471c3c49e..bc4beac492 100644 --- a/engines/cine/texte.h +++ b/engines/cine/texte.h @@ -33,10 +33,17 @@ namespace Cine { typedef char CommandeType[20]; -extern byte *textDataPtr; +// Number of characters in a font +#define NUM_FONT_CHARS 256 + +struct CharacterEntry { + byte characterIdx; + byte characterWidth; +}; struct TextHandler { - byte textTable[256][2][16 * 8]; + byte textTable[NUM_FONT_CHARS][2][16 * 8]; + CharacterEntry fontParamTable[NUM_FONT_CHARS]; }; extern const char **failureMessages; @@ -44,20 +51,13 @@ extern const CommandeType *defaultActionCommand; extern const CommandeType *systemMenu; extern const CommandeType *confirmMenu; extern const char **otherMessages; -extern const char *commandPrepositionOn; - -struct CharacterEntry { - byte characterIdx; - byte characterWidth; -}; - -extern const CharacterEntry *fontParamTable; +extern const char *defaultCommandPreposition; +extern const char **commandPrepositionTable; -void loadTextData(const char *pFileName, byte *pDestinationBuffer); +void loadTextData(const char *filename); void loadErrmessDat(const char *fname); void freeErrmessDat(void); void loadPoldatDat(const char *fname); -void freePoldatDat(void); int fitLine(const char *ptr, int maxWidth, int &words, int &width); diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 2fe2701e52..5e4c0eee30 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -77,7 +77,7 @@ byte _danKeysPressed; int16 playerCommand; -char commandBuffer[80]; +Common::String commandBuffer; char currentPrcName[20]; char currentRelName[20]; char currentObjectName[20]; @@ -316,6 +316,18 @@ void saveCommandVariables(Common::OutSaveFile &out) { } } +/*! \brief Save the 80 bytes long command buffer padded to that length with zeroes. */ +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); + // 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); + } +} + void saveAnimDataTable(Common::OutSaveFile &out) { out.writeUint16BE(NUM_MAX_ANIMDATA); // Entry count out.writeUint16BE(0x1E); // Entry size @@ -633,7 +645,7 @@ void CineEngine::resetEngine() { playerCommand = -1; isDrawCommandEnabled = 0; - strcpy(commandBuffer, ""); + commandBuffer = ""; globalVars[VAR_MOUSE_X_POS] = 0; globalVars[VAR_MOUSE_Y_POS] = 0; @@ -834,7 +846,10 @@ bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) { globalVars.load(in, NUM_MAX_VAR); loadZoneData(in); loadCommandVariables(in); - in.read(commandBuffer, 0x50); + char tempCommandBuffer[kMaxCommandBufferSize]; + in.read(tempCommandBuffer, kMaxCommandBufferSize); + commandBuffer = tempCommandBuffer; + renderer->setCommand(commandBuffer); loadZoneQuery(in); // TODO: Use the loaded string (Current music name (String, 13 bytes)). @@ -971,7 +986,9 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor loadCommandVariables(in); // At 0x22A9 (i.e. 0x22A1 + 4 * 2): - in.read(commandBuffer, 0x50); + char tempCommandBuffer[kMaxCommandBufferSize]; + in.read(tempCommandBuffer, kMaxCommandBufferSize); + commandBuffer = tempCommandBuffer; renderer->setCommand(commandBuffer); // At 0x22F9 (i.e. 0x22A9 + 0x50): @@ -1119,7 +1136,7 @@ void CineEngine::makeSaveFW(Common::OutSaveFile &out) { globalVars.save(out, NUM_MAX_VAR); saveZoneData(out); saveCommandVariables(out); - out.write(commandBuffer, 0x50); + saveCommandBuffer(out); out.writeUint16BE(renderer->_cmdY); out.writeUint16BE(bgVar0); @@ -1334,7 +1351,7 @@ void CineEngine::makeSaveOS(Common::OutSaveFile &out) { globalVars.save(out, NUM_MAX_VAR); saveZoneData(out); saveCommandVariables(out); - out.write(commandBuffer, 0x50); + saveCommandBuffer(out); saveZoneQuery(out); // FIXME: Save a proper name here, saving an empty string currently. @@ -1397,19 +1414,38 @@ void drawDoubleMessageBox(int16 x, int16 y, int16 width, int16 currentY, int16 c } void processInventory(int16 x, int16 y) { - int16 listSize = buildObjectListCommand(-2); uint16 button; + int menuWidth; + int listSize; + int commandParam; + + if (g_cine->getGameType() == Cine::GType_FW) { + menuWidth = 140; + commandParam = -2; + } else { // Operation Stealth + menuWidth = 160; + commandParam = -3; + } + + listSize = buildObjectListCommand(commandParam); if (!listSize) return; - renderer->drawMenu(objectListCommand, listSize, x, y, 140, -1); + renderer->drawMenu(objectListCommand, listSize, x, y, menuWidth, -1); renderer->blit(); do { manageEvents(); getMouseData(mouseUpdateStatus, &button, &dummyU16, &dummyU16); } while (!button); + + do { + manageEvents(); + getMouseData(mouseUpdateStatus, &button, &dummyU16, &dummyU16); + } while (button); + + // TODO: Both Future Wars and Operation Stealth call showMouse, drawMouse or something similar here. } int16 buildObjectListCommand(int16 param) { @@ -1453,6 +1489,8 @@ int16 selectSubObject(int16 x, int16 y, int16 param) { return objListTab[selectedObject]; } +// TODO: Make separate functions for Future Wars's and Operation Stealth's version of this function, this is getting too messy +// TODO: Add support for using the different prepositions for different verbs (Doesn't work currently) void makeCommandLine(void) { uint16 x, y; @@ -1460,9 +1498,9 @@ void makeCommandLine(void) { commandVar2 = -10; if (playerCommand != -1) { - strcpy(commandBuffer, defaultActionCommand[playerCommand]); + commandBuffer = defaultActionCommand[playerCommand]; } else { - strcpy(commandBuffer, ""); + commandBuffer = ""; } if ((playerCommand != -1) && (choiceResultTable[playerCommand] == 2)) { // need object selection ? @@ -1477,8 +1515,12 @@ void makeCommandLine(void) { } if (si < 0) { - playerCommand = -1; - strcpy(commandBuffer, ""); + if (g_cine->getGameType() == Cine::GType_OS) { + canUseOnObject = 0; + } else { // Future Wars + playerCommand = -1; + commandBuffer = ""; + } } else { if (g_cine->getGameType() == Cine::GType_OS) { if (si >= 8000) { @@ -1491,23 +1533,28 @@ void makeCommandLine(void) { commandVar3[0] = si; commandVar1 = 1; - - strcat(commandBuffer, " "); - strcat(commandBuffer, objectTable[commandVar3[0]].name); - strcat(commandBuffer, " "); - strcat(commandBuffer, commandPrepositionOn); + commandBuffer += " "; + commandBuffer += objectTable[commandVar3[0]].name; + commandBuffer += " "; + if (g_cine->getGameType() == Cine::GType_OS) { + commandBuffer += commandPrepositionTable[playerCommand]; + } else { // Future Wars + commandBuffer += defaultCommandPreposition; + } } - } else { + } + + if (g_cine->getGameType() == Cine::GType_OS || !(playerCommand != -1 && choiceResultTable[playerCommand] == 2)) { if (playerCommand == 2) { getMouseData(mouseUpdateStatus, &dummyU16, &x, &y); processInventory(x, y + 8); playerCommand = -1; commandVar1 = 0; - strcpy(commandBuffer, ""); + commandBuffer = ""; } } - if (g_cine->getGameType() == Cine::GType_OS) { + if (g_cine->getGameType() == Cine::GType_OS && playerCommand != 2) { if (playerCommand != -1 && canUseOnObject != 0) { // call use on sub object int16 si; @@ -1515,34 +1562,37 @@ void makeCommandLine(void) { si = selectSubObject(x, y + 8, -subObjectUseTable[playerCommand]); - if (si) { + if (si >= 0) { if (si >= 8000) { si -= 8000; } commandVar3[commandVar1] = si; - commandVar1++; - - // TODO: add command message draw + commandBuffer += " "; + commandBuffer += objectTable[si].name; } + } - isDrawCommandEnabled = 1; + isDrawCommandEnabled = 1; - if (playerCommand != -1 && choiceResultTable[playerCommand] == commandVar1) { - SelectedObjStruct obj; - obj.idx = commandVar3[0]; - obj.param = commandVar3[1]; - int16 di = getRelEntryForObject(playerCommand, commandVar1, &obj); + if (playerCommand != -1 && choiceResultTable[playerCommand] == commandVar1) { + SelectedObjStruct obj; + obj.idx = commandVar3[0]; + obj.param = commandVar3[1]; + int16 di = getRelEntryForObject(playerCommand, commandVar1, &obj); - if (di != -1) { - runObjectScript(di); - } - } + if (di != -1) { + runObjectScript(di); + } // TODO: else addFailureMessage(playerCommand) + + playerCommand = -1; + commandVar1 = 0; + commandBuffer = ""; } } - if (!disableSystemMenu) { + if (g_cine->getGameType() == Cine::GType_OS || !disableSystemMenu) { isDrawCommandEnabled = 1; renderer->setCommand(commandBuffer); } @@ -1759,8 +1809,9 @@ uint16 executePlayerInput(void) { commandVar3[commandVar1] = si; commandVar1++; - strcat(commandBuffer, " "); - strcat(commandBuffer, objectTable[si].name); + commandBuffer += " "; + commandBuffer += objectTable[si].name; + isDrawCommandEnabled = 1; @@ -1782,8 +1833,8 @@ uint16 executePlayerInput(void) { playerCommand = -1; commandVar1 = 0; - strcpy(commandBuffer, ""); - renderer->setCommand(""); + commandBuffer = ""; + renderer->setCommand(commandBuffer); } } else { globalVars[VAR_MOUSE_X_POS] = mouseX; @@ -1804,13 +1855,7 @@ uint16 executePlayerInput(void) { if (commandVar2 != objIdx) { if (objIdx != -1) { - char command[256]; - - strcpy(command, commandBuffer); - strcat(command, " "); - strcat(command, objectTable[objIdx].name); - - renderer->setCommand(command); + renderer->setCommand(commandBuffer + " " + objectTable[objIdx].name); } else { isDrawCommandEnabled = 1; } @@ -1986,6 +2031,14 @@ uint16 executePlayerInput(void) { } } + // Update Operation Stealth specific global variables. + // This fixes swimming at the bottom of the ocean after + // having been thrown into it with the girl. + if (g_cine->getGameType() == Cine::GType_OS) { + globalVars[251] = globalVars[VAR_MOUSE_X_POS]; + globalVars[252] = globalVars[VAR_MOUSE_Y_POS]; + } + return var_5E; } diff --git a/engines/cine/various.h b/engines/cine/various.h index 926a1821d9..b841908c65 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -33,6 +33,9 @@ namespace Cine { +// Maximum size of the command buffer including the trailing zero +#define kMaxCommandBufferSize 80 + void initLanguage(Common::Language lang); int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, uint16 Y, uint16 width, bool recheckValue = false); @@ -85,7 +88,7 @@ extern byte _danKeysPressed; extern int16 playerCommand; -extern char commandBuffer[80]; +extern Common::String commandBuffer; extern char currentPrcName[20]; extern char currentRelName[20]; |