aboutsummaryrefslogtreecommitdiff
path: root/engines/cine
diff options
context:
space:
mode:
authorChristopher Page2008-08-16 04:30:01 +0000
committerChristopher Page2008-08-16 04:30:01 +0000
commit909b66ef54f8d6d6dfeb0fdee2aa018f2065b6c9 (patch)
treec2f2668391fa3026a6a79b38ebfad797ce1b376c /engines/cine
parentc22f9b23588121d41fe0a12ce44926d683d7a18d (diff)
parentf2111eeb45dc8c41afb3e63bf3b86a09bf9a3532 (diff)
downloadscummvm-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.cpp12
-rw-r--r--engines/cine/gfx.cpp143
-rw-r--r--engines/cine/gfx.h6
-rw-r--r--engines/cine/main_loop.cpp8
-rw-r--r--engines/cine/msg.cpp45
-rw-r--r--engines/cine/pal.cpp36
-rw-r--r--engines/cine/pal.h2
-rw-r--r--engines/cine/part.cpp53
-rw-r--r--engines/cine/part.h6
-rw-r--r--engines/cine/sound.cpp1
-rw-r--r--engines/cine/texte.cpp186
-rw-r--r--engines/cine/texte.h24
-rw-r--r--engines/cine/various.cpp145
-rw-r--r--engines/cine/various.h5
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];