diff options
author | David Corrales | 2007-07-08 16:58:54 +0000 |
---|---|---|
committer | David Corrales | 2007-07-08 16:58:54 +0000 |
commit | 9bfe5d53540af7dc9bf0214202f4e35b272320ea (patch) | |
tree | 69dcaf6f735e9fd0913a3e2f163852d4b9af87e3 /engines | |
parent | 256e4d9521b79160d1f9ed670656097a96dc5a34 (diff) | |
parent | 17da12ca07a1f18f3fe1ef5b0c2c0cd9fd8359b4 (diff) | |
download | scummvm-rg350-9bfe5d53540af7dc9bf0214202f4e35b272320ea.tar.gz scummvm-rg350-9bfe5d53540af7dc9bf0214202f4e35b272320ea.tar.bz2 scummvm-rg350-9bfe5d53540af7dc9bf0214202f4e35b272320ea.zip |
Merged the FSNode branch with trunk r27681:27969
svn-id: r27970
Diffstat (limited to 'engines')
137 files changed, 2526 insertions, 1106 deletions
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index 74795271fc..0839b7de99 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -334,7 +334,7 @@ void AgiEngine::replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, case ADD_PIC: debugC(8, kDebugLevelMain, "--- decoding picture %d ---", p1); agiLoadResource(rPICTURE, p1); - _picture->decodePicture(p1, p2); + _picture->decodePicture(p1, p2, p3 != 0); break; case ADD_VIEW: agiLoadResource(rVIEW, p1); diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 56ae1288b8..01db2acb23 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -247,6 +247,18 @@ enum { }; /** + * Different monitor types. + * Used with AGI variable 26 i.e. vMonitor. + */ +enum AgiMonitorType { + kAgiMonitorCga = 0, + // kAgiMonitorTandy = 1, // Not sure about this + kAgiMonitorHercules = 2, + kAgiMonitorEga = 3 + // kAgiMonitorVga = 4 // Not sure about this +}; + +/** * AGI flags */ enum { diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp index 22d2582021..bd8fcb0394 100644 --- a/engines/agi/cycle.cpp +++ b/engines/agi/cycle.cpp @@ -367,7 +367,26 @@ int AgiEngine::runGame() { setvar(vComputer, 0); /* IBM PC (4 = Atari ST) */ setvar(vSoundgen, 1); /* IBM PC SOUND */ - setvar(vMonitor, 0x3); /* EGA monitor */ + + // Set monitor type (v26 i.e. vMonitor) + switch (_renderMode) { + case Common::kRenderCGA: + setvar(vMonitor, kAgiMonitorCga); + break; + case Common::kRenderHercG: + case Common::kRenderHercA: + setvar(vMonitor, kAgiMonitorHercules); + break; + // Don't know if Amiga AGI games use a different value than kAgiMonitorEga + // for vMonitor so I just use kAgiMonitorEga for them (As was done before too). + case Common::kRenderAmiga: + case Common::kRenderDefault: + case Common::kRenderEGA: + default: + setvar(vMonitor, kAgiMonitorEga); + break; + } + setvar(vMaxInputChars, 38); _game.inputMode = INPUT_NONE; _game.inputEnabled = 0; diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp index 2d64a4352e..54f1783d83 100644 --- a/engines/agi/graphics.cpp +++ b/engines/agi/graphics.cpp @@ -624,8 +624,7 @@ int GfxMgr::keypress() { /** * Initialize the color palette * This function initializes the color palette using the specified 16-color - * RGB palette and creates 16 extra palette entries with translucent colors - * for the interpreter console. + * RGB palette. * @param p A pointer to the 16-color RGB palette. */ void GfxMgr::initPalette(uint8 *p) { @@ -633,7 +632,6 @@ void GfxMgr::initPalette(uint8 *p) { for (i = 0; i < 48; i++) { _palette[i] = p[i]; - _palette[i + 48] = (p[i] + 0x30) >> 2; } } @@ -642,13 +640,13 @@ void GfxMgr::gfxSetPalette() { byte pal[256 * 4]; if (!(_vm->getFeatures() & (GF_AGI256 | GF_AGI256_2))) { - for (i = 0; i < 32; i++) { + for (i = 0; i < 16; i++) { pal[i * 4 + 0] = _palette[i * 3 + 0] << 2; pal[i * 4 + 1] = _palette[i * 3 + 1] << 2; pal[i * 4 + 2] = _palette[i * 3 + 2] << 2; pal[i * 4 + 3] = 0; } - g_system->setPalette(pal, 0, 32); + g_system->setPalette(pal, 0, 16); } else { for (i = 0; i < 256; i++) { pal[i * 4 + 0] = vgaPalette[i * 3 + 0]; @@ -715,19 +713,107 @@ void GfxMgr::gfxPutBlock(int x1, int y1, int x2, int y2) { g_system->copyRectToScreen(_screen + y1 * 320 + x1, 320, x1, y1, x2 - x1 + 1, y2 - y1 + 1); } -static const byte mouseCursorArrow[] = { - // This is the same arrow cursor that was later used in early SCI games - 0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, - 0x78, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x7F, 0x00, - 0x7F, 0x80, 0x7F, 0xC0, 0x7C, 0x00, 0x46, 0x00, - 0x06, 0x00, 0x03, 0x00, 0x03, 0x00, 0x01, 0x80, - 0xC0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x88, 0x00, - 0x84, 0x00, 0x82, 0x00, 0x81, 0x00, 0x80, 0x80, - 0x80, 0x40, 0x80, 0x20, 0x82, 0x00, 0xA9, 0x00, - 0xC9, 0x00, 0x04, 0x80, 0x04, 0x80, 0x02, 0x40 +/** + * A black and white SCI-style arrow cursor (11x16). + * 0 = Transparent. + * 1 = Black (#000000 in 24-bit RGB). + * 2 = White (#FFFFFF in 24-bit RGB). + */ +static const byte sciMouseCursor[] = { + 1,1,0,0,0,0,0,0,0,0,0, + 1,2,1,0,0,0,0,0,0,0,0, + 1,2,2,1,0,0,0,0,0,0,0, + 1,2,2,2,1,0,0,0,0,0,0, + 1,2,2,2,2,1,0,0,0,0,0, + 1,2,2,2,2,2,1,0,0,0,0, + 1,2,2,2,2,2,2,1,0,0,0, + 1,2,2,2,2,2,2,2,1,0,0, + 1,2,2,2,2,2,2,2,2,1,0, + 1,2,2,2,2,2,2,2,2,2,1, + 1,2,2,2,2,2,1,0,0,0,0, + 1,2,1,0,1,2,2,1,0,0,0, + 1,1,0,0,1,2,2,1,0,0,0, + 0,0,0,0,0,1,2,2,1,0,0, + 0,0,0,0,0,1,2,2,1,0,0, + 0,0,0,0,0,0,1,2,2,1,0 +}; + +/** + * RGBA-palette for the black and white SCI-style arrow cursor. + */ +static const byte sciMouseCursorPalette[] = { + 0x00, 0x00, 0x00, 0x00, // Black + 0xFF, 0xFF, 0xFF, 0x00 // White +}; + +/** + * An Amiga-style arrow cursor (8x11). + * 0 = Transparent. + * 1 = Black (#000000 in 24-bit RGB). + * 2 = Red (#DE2021 in 24-bit RGB). + * 3 = Light red (#FFCFAD in 24-bit RGB). + */ +static const byte amigaMouseCursor[] = { + 2,3,1,0,0,0,0,0, + 2,2,3,1,0,0,0,0, + 2,2,2,3,1,0,0,0, + 2,2,2,2,3,1,0,0, + 2,2,2,2,2,3,1,0, + 2,2,2,2,2,2,3,1, + 2,0,2,2,3,1,0,0, + 0,0,0,2,3,1,0,0, + 0,0,0,2,2,3,1,0, + 0,0,0,0,2,3,1,0, + 0,0,0,0,2,2,3,1 +}; + +/** + * RGBA-palette for the Amiga-style arrow cursor + * and the Amiga-style busy cursor. + */ +static const byte amigaMouseCursorPalette[] = { + 0x00, 0x00, 0x00, 0x00, // Black + 0xDE, 0x20, 0x21, 0x00, // Red + 0xFF, 0xCF, 0xAD, 0x00 // Light red }; /** + * An Amiga-style busy cursor showing an hourglass (13x16). + * 0 = Transparent. + * 1 = Black (#000000 in 24-bit RGB). + * 2 = Red (#DE2021 in 24-bit RGB). + * 3 = Light red (#FFCFAD in 24-bit RGB). + */ +static const byte busyAmigaMouseCursor[] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,2,2,2,2,2,2,2,2,2,2,2,1, + 1,2,2,2,2,2,2,2,2,2,2,2,1, + 0,1,3,3,3,3,3,3,3,3,3,1,0, + 0,0,1,3,3,3,3,3,3,3,1,0,0, + 0,0,0,1,3,3,3,3,3,1,0,0,0, + 0,0,0,0,1,3,3,3,1,0,0,0,0, + 0,0,0,0,0,1,3,1,0,0,0,0,0, + 0,0,0,0,0,1,3,1,0,0,0,0,0, + 0,0,0,0,1,2,3,2,1,0,0,0,0, + 0,0,0,1,2,2,3,2,2,1,0,0,0, + 0,0,1,2,2,2,3,2,2,2,1,0,0, + 0,1,2,2,2,3,3,3,2,2,2,1,0, + 1,3,3,3,3,3,3,3,3,3,3,3,1, + 1,3,3,3,3,3,3,3,3,3,3,3,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1 +}; + +void GfxMgr::setCursor(bool amigaStyleCursor) { + if (!amigaStyleCursor) { + CursorMan.replaceCursorPalette(sciMouseCursorPalette, 1, ARRAYSIZE(sciMouseCursorPalette) / 4); + CursorMan.replaceCursor(sciMouseCursor, 11, 16, 1, 1, 0); + } else { // amigaStyleCursor + CursorMan.replaceCursorPalette(amigaMouseCursorPalette, 1, ARRAYSIZE(amigaMouseCursorPalette) / 4); + CursorMan.replaceCursor(amigaMouseCursor, 8, 11, 1, 1, 0); + } +} + +/** * Initialize graphics device. * * @see deinit_video() @@ -743,31 +829,7 @@ int GfxMgr::initVideo() { gfxSetPalette(); - byte mouseCursor[16 * 16]; - const byte *src = mouseCursorArrow; - for (int i = 0; i < 32; ++i) { - int offs = i * 8; - for (byte mask = 0x80; mask != 0; mask >>= 1) { - if (src[0] & mask) { - mouseCursor[offs] = 2; - } else if (src[32] & mask) { - mouseCursor[offs] = 0; - } else { - mouseCursor[offs] = 0xFF; - } - ++offs; - } - ++src; - } - - const byte cursorPalette[] = { - 0, 0, 0, 0, - 0, 0, 0, 0, - 255, 255, 255, 0 - }; - - CursorMan.replaceCursorPalette(cursorPalette, 0, 3); - CursorMan.replaceCursor(mouseCursor, 16, 16, 1, 1); + setCursor(_vm->_renderMode == Common::kRenderAmiga); return errOK; } @@ -804,23 +866,26 @@ int GfxMgr::deinitMachine() { * @param x x coordinate of the row start (AGI coord.) * @param y y coordinate of the row start (AGI coord.) * @param n number of pixels in the row - * @param p pointer to the row start in the AGI screen + * @param p pointer to the row start in the AGI screen (Always use sbuf16c as base, not sbuf256c) + * FIXME: CGA rendering doesn't work correctly with AGI256 or AGI256-2. */ void GfxMgr::putPixelsA(int x, int y, int n, uint8 *p) { + const uint rShift = _vm->_debug.priority ? 4 : 0; // Priority information is in the top 4 bits of a byte taken from sbuf16c. + + // Choose the correct screen to read from. If AGI256 or AGI256-2 is used and we're not trying to show the priority information, + // then choose the 256 color screen, otherwise choose the 16 color screen (Which also has the priority information). + p += _vm->getFeatures() & (GF_AGI256 | GF_AGI256_2) && !_vm->_debug.priority ? FROM_SBUF16_TO_SBUF256_OFFSET : 0; + if (_vm->_renderMode == Common::kRenderCGA) { for (x *= 2; n--; p++, x += 2) { register uint16 q = (cgaMap[(*p & 0xf0) >> 4] << 4) | cgaMap[*p & 0x0f]; - if (_vm->_debug.priority) - q >>= 4; - *(uint16 *)&_agiScreen[x + y * GFX_WIDTH] = q & 0x0f0f; + *(uint16 *)&_agiScreen[x + y * GFX_WIDTH] = (q >> rShift) & 0x0f0f; } } else { - const uint16 mask = _vm->getFeatures() & (GF_AGI256 | GF_AGI256_2) ? 0xffff : 0x0f0f; + const uint16 mask = _vm->getFeatures() & (GF_AGI256 | GF_AGI256_2) && !_vm->_debug.priority ? 0xffff : 0x0f0f; for (x *= 2; n--; p++, x += 2) { register uint16 q = ((uint16) * p << 8) | *p; - if (_vm->_debug.priority) - q >>= 4; - *(uint16 *)&_agiScreen[x + y * GFX_WIDTH] = q & mask; + *(uint16 *)&_agiScreen[x + y * GFX_WIDTH] = (q >> rShift) & mask; } } } diff --git a/engines/agi/graphics.h b/engines/agi/graphics.h index cdbae8d6e6..b1f9c0e1d7 100644 --- a/engines/agi/graphics.h +++ b/engines/agi/graphics.h @@ -41,7 +41,7 @@ class GfxMgr { private: AgiEngine *_vm; - uint8 _palette[32 * 3]; + uint8 _palette[16 * 3]; uint8 *_agiScreen; unsigned char *_screen; @@ -87,6 +87,7 @@ public: void putPixel(int, int, int); void putBlock(int x1, int y1, int x2, int y2); void gfxSetPalette(); + void setCursor(bool amigaStyleCursor = false); int keypress(); int getKey(); diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp index 17865e1f3a..3acc81ddff 100644 --- a/engines/agi/keyboard.cpp +++ b/engines/agi/keyboard.cpp @@ -29,6 +29,9 @@ #include "agi/graphics.h" #include "agi/keyboard.h" #include "agi/menu.h" +#ifdef __DS__ +#include "wordcompletion.h" +#endif namespace Agi { @@ -308,6 +311,9 @@ void AgiEngine::handleKeys(int key) { debugC(3, kDebugLevelInput, "clear lines"); clearLines(l, l + 1, bg); flushLines(l, l + 1); +#ifdef __DS__ + DS::findWordCompletions((char *) _game.inputBuffer); +#endif break; case KEY_ESCAPE: @@ -324,6 +330,10 @@ void AgiEngine::handleKeys(int key) { _game.inputBuffer[--_game.cursorPos] = 0; /* Print cursor */ _gfx->printCharacter(_game.cursorPos + 1, l, _game.cursorChar, fg, bg); + +#ifdef __DS__ + DS::findWordCompletions((char *) _game.inputBuffer); +#endif break; default: /* Ignore invalid keystrokes */ @@ -337,6 +347,10 @@ void AgiEngine::handleKeys(int key) { _game.inputBuffer[_game.cursorPos++] = key; _game.inputBuffer[_game.cursorPos] = 0; +#ifdef __DS__ + DS::findWordCompletions((char *) _game.inputBuffer); +#endif + /* echo */ _gfx->printCharacter(_game.cursorPos, l, _game.inputBuffer[_game.cursorPos - 1], fg, bg); diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp index c51514f237..588ee1dd30 100644 --- a/engines/agi/op_cmd.cpp +++ b/engines/agi/op_cmd.cpp @@ -153,6 +153,18 @@ cmd(toggle_v) { cmd(new_room) { g_agi->newRoom(p0); + + // WORKAROUND: Works around intro skipping bug (#1737343) in Gold Rush. + // Intro was skipped because the enter-keypress finalizing the entering + // of the copy protection string (Copy protection is in logic.128) was + // left over to the intro scene (Starts with room 73 i.e. logic.073). + // The intro scene checks for any keys pressed and if it finds any it + // jumps to the game's start (Room 1 i.e. logic.001). We clear the + // keyboard buffer when the intro sequence's first room (Room 73) is + // loaded so that no keys from the copy protection scene can be left + // over to cause the intro to skip to the game's start. + if (g_agi->getGameID() == GID_GOLDRUSH && p0 == 73) + game.keypress = 0; } cmd(new_room_f) { diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp index cd8ef83de0..144e965465 100644 --- a/engines/agi/picture.cpp +++ b/engines/agi/picture.cpp @@ -652,7 +652,7 @@ int PictureMgr::decodePicture(int n, int clear, bool agi256) { if (clear) _vm->clearImageStack(); - _vm->recordImageStackCall(ADD_PIC, n, clear, 0, 0, 0, 0, 0); + _vm->recordImageStackCall(ADD_PIC, n, clear, agi256, 0, 0, 0, 0); return errOK; } @@ -686,7 +686,7 @@ void PictureMgr::showPic() { i = 0; offset = _vm->_game.lineMinPrint * CHAR_LINES; for (y = 0; y < _HEIGHT; y++) { - _gfx->putPixelsA(0, y + offset, _WIDTH, &_vm->_game.sbuf[i]); + _gfx->putPixelsA(0, y + offset, _WIDTH, &_vm->_game.sbuf16c[i]); i += _WIDTH; } diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp index ab5f818d17..9144dae96c 100644 --- a/engines/agi/saveload.cpp +++ b/engines/agi/saveload.cpp @@ -519,41 +519,48 @@ int AgiEngine::selectSlot() { _gfx->drawButton(buttonX[i], buttonY, buttonText[i], 0, 0, MSG_BOX_TEXT, MSG_BOX_COLOUR); AllowSyntheticEvents on(this); + int oldFirstSlot = _firstSlot + 1; + int oldActive = active + 1; for (;;) { - char dstr[64]; - for (i = 0; i < NUM_VISIBLE_SLOTS; i++) { - sprintf(dstr, "[%2d. %-28.28s]", i + _firstSlot, desc[i]); - printText(dstr, 0, hm + 1, vm + 4 + i, - (40 - 2 * hm) - 1, i == active ? MSG_BOX_COLOUR : MSG_BOX_TEXT, - i == active ? MSG_BOX_TEXT : MSG_BOX_COLOUR); - } + int sbPos; - char upArrow[] = "^"; - char downArrow[] = "v"; - char scrollBar[] = " "; + if (oldFirstSlot != _firstSlot || oldActive != active) { + char dstr[64]; + for (i = 0; i < NUM_VISIBLE_SLOTS; i++) { + sprintf(dstr, "[%2d. %-28.28s]", i + _firstSlot, desc[i]); + printText(dstr, 0, hm + 1, vm + 4 + i, + (40 - 2 * hm) - 1, i == active ? MSG_BOX_COLOUR : MSG_BOX_TEXT, + i == active ? MSG_BOX_TEXT : MSG_BOX_COLOUR); + } - int sbPos; + char upArrow[] = "^"; + char downArrow[] = "v"; + char scrollBar[] = " "; + + // Use the extreme scrollbar positions only if the + // extreme slots are in sight. + + if (_firstSlot == 0) + sbPos = 1; + else if (_firstSlot == NUM_SLOTS - NUM_VISIBLE_SLOTS) + sbPos = NUM_VISIBLE_SLOTS - 2; + else { + sbPos = 2 + (_firstSlot * (NUM_VISIBLE_SLOTS - 4)) / (NUM_SLOTS - NUM_VISIBLE_SLOTS - 1); + if (sbPos >= NUM_VISIBLE_SLOTS - 3) + sbPos = NUM_VISIBLE_SLOTS - 3; + } - // Use the extreme scrollbar positions only if the extreme - // slots are in sight. - - if (_firstSlot == 0) - sbPos = 1; - else if (_firstSlot == NUM_SLOTS - NUM_VISIBLE_SLOTS) - sbPos = NUM_VISIBLE_SLOTS - 2; - else { - sbPos = 2 + (_firstSlot * (NUM_VISIBLE_SLOTS - 4)) / (NUM_SLOTS - NUM_VISIBLE_SLOTS - 1); - if (sbPos >= NUM_VISIBLE_SLOTS - 3) - sbPos = NUM_VISIBLE_SLOTS - 3; - } + for (i = 1; i < NUM_VISIBLE_SLOTS - 1; i++) + printText(scrollBar, 35, hm + 1, vm + 4 + i, 1, MSG_BOX_COLOUR, 7, true); - for (i = 1; i < NUM_VISIBLE_SLOTS - 1; i++) - printText(scrollBar, 35, hm + 1, vm + 4 + i, 1, MSG_BOX_COLOUR, 7, true); + printText(upArrow, 35, hm + 1, vm + 4, 1, 8, 7); + printText(downArrow, 35, hm + 1, vm + 4 + NUM_VISIBLE_SLOTS - 1, 1, 8, 7); + printText(scrollBar, 35, hm + 1, vm + 4 + sbPos, 1, MSG_BOX_COLOUR, MSG_BOX_TEXT); - printText(upArrow, 35, hm + 1, vm + 4, 1, 8, 7); - printText(downArrow, 35, hm + 1, vm + 4 + NUM_VISIBLE_SLOTS - 1, 1, 8, 7); - printText(scrollBar, 35, hm + 1, vm + 4 + sbPos, 1, MSG_BOX_COLOUR, MSG_BOX_TEXT); + oldActive = active; + oldFirstSlot = _firstSlot; + } _gfx->pollTimer(); /* msdos driver -> does nothing */ key = doPollKeyboard(); diff --git a/engines/agi/sprite.cpp b/engines/agi/sprite.cpp index 3d69968075..006e3dddee 100644 --- a/engines/agi/sprite.cpp +++ b/engines/agi/sprite.cpp @@ -215,7 +215,8 @@ void SpritesMgr::objsRestoreArea(Sprite *s) { int y, offset; int16 xPos = s->xPos, yPos = s->yPos; int16 xSize = s->xSize, ySize = s->ySize; - uint8 *p0, *q; + uint8 *q; + uint32 pos0; if (xPos + xSize > _WIDTH) xSize = _WIDTH - xPos; @@ -236,14 +237,14 @@ void SpritesMgr::objsRestoreArea(Sprite *s) { if (xSize <= 0 || ySize <= 0) return; - p0 = &_vm->_game.sbuf[xPos + yPos * _WIDTH]; + pos0 = xPos + yPos * _WIDTH; q = s->buffer; offset = _vm->_game.lineMinPrint * CHAR_LINES; for (y = 0; y < ySize; y++) { - memcpy(p0, q, xSize); - _gfx->putPixelsA(xPos, yPos + y + offset, xSize, p0); + memcpy(&_vm->_game.sbuf[pos0], q, xSize); + _gfx->putPixelsA(xPos, yPos + y + offset, xSize, &_vm->_game.sbuf16c[pos0]); q += xSize; - p0 += _WIDTH; + pos0 += _WIDTH; } } @@ -728,7 +729,7 @@ void SpritesMgr::commitBlock(int x1, int y1, int x2, int y2) { debugC(7, kDebugLevelSprites, "%d, %d, %d, %d", x1, y1, x2, y2); w = x2 - x1 + 1; - q = &_vm->_game.sbuf[x1 + _WIDTH * y1]; + q = &_vm->_game.sbuf16c[x1 + _WIDTH * y1]; offset = _vm->_game.lineMinPrint * CHAR_LINES; for (i = y1; i <= y2; i++) { _gfx->putPixelsA(x1, i + offset, w, q); diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp index 5fc3c3bca9..ed33b9463a 100644 --- a/engines/agi/words.cpp +++ b/engines/agi/words.cpp @@ -88,7 +88,7 @@ void AgiEngine::unloadWords() { * Uses an algorithm hopefully like the one Sierra used. Returns the ID * of the word and the length in flen. Returns -1 if not found. * - * Thomas Åkesson, November 2001 + * Thomas Akesson, November 2001 */ int AgiEngine::findWord(char *word, int *flen) { int mchr = 0; /* matched chars */ diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index c98257f028..ae7f692c3f 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -110,8 +110,6 @@ AGOSEngine::AGOSEngine(OSystem *syst) _debugger = 0; - _keyPressed = 0; - _gameFile = 0; _opcode = 0; @@ -746,10 +744,12 @@ void AGOSEngine_Simon2::setupGame() { _tableIndexBase = 1580 / 4; _textIndexBase = 1500 / 4; _numVideoOpcodes = 75; -#ifndef PALMOS_68K - _vgaMemSize = 2000000; -#else +#if defined(__DS__) + _vgaMemSize = 1300000; +#elif defined(PALMOS_68K) _vgaMemSize = gVars->memory[kMemSimon2Games]; +#else + _vgaMemSize = 2000000; #endif _itemMemSize = 20000; _tableMemSize = 100000; @@ -958,8 +958,8 @@ GUI::Debugger *AGOSEngine::getDebugger() { } void AGOSEngine::pause() { - _keyPressed = 1; - _pause = 1; + _keyPressed.reset(); + _pause = true; bool ambient_status = _ambientPaused; bool music_status = _musicPaused; @@ -969,8 +969,8 @@ void AGOSEngine::pause() { while (_pause) { delay(1); - if (_keyPressed == 'p') - _pause = 0; + if (_keyPressed.keycode == Common::KEYCODE_p) + _pause = false; } _midi.pause(music_status); diff --git a/engines/agos/agos.h b/engines/agos/agos.h index e487c38cc7..d233d0bfeb 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -28,6 +28,7 @@ #include "engines/engine.h" +#include "common/keyboard.h" #include "common/rect.h" #include "common/util.h" @@ -216,7 +217,7 @@ protected: const GameSpecificSettings *gss; - byte _keyPressed; + Common::KeyState _keyPressed; Common::File *_gameFile; @@ -875,8 +876,8 @@ public: void vc36_setWindowImage(); void vc38_ifVarNotZero(); void vc39_setVar(); - void vc40(); - void vc41(); + void vc40_scrollRight(); + void vc41_scrollLeft(); void vc42_delayIfNotEQ(); // Video Script Opcodes, Elvira 1 @@ -1316,7 +1317,9 @@ public: void oe2_moveDirn(); void oe2_doClass(); void oe2_pObj(); + void oe2_isCalled(); void oe2_loadGame(); + void oe2_menu(); void oe2_drawItem(); void oe2_doTable(); void oe2_pauseGame(); @@ -1410,7 +1413,6 @@ public: void oww_setLongText(); void oww_printLongText(); void oww_whereTo(); - void oww_menu(); void oww_textMenu(); void oww_pauseGame(); void oww_boxMessage(); diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index 8748cff54e..8d5238259d 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -130,8 +130,11 @@ void MoviePlayer::play() { return; } - if (!_fd) { - return; + if (_omniTVFile) { + // Clear any paused OmniTV video + _mixer->stopHandle(_omniTVSound); + delete _omniTVFile; + _omniTVFile = 0; } _leftButtonDown = false; diff --git a/engines/agos/contain.cpp b/engines/agos/contain.cpp index b5ca344905..891ac36d30 100644 --- a/engines/agos/contain.cpp +++ b/engines/agos/contain.cpp @@ -34,8 +34,8 @@ int AGOSEngine::canPlace(Item *x, Item *y) { Item *z = derefItem(x->parent); if (getGameType() == GType_ELVIRA1) { - SubPlayer *p = (SubPlayer *)findChildOfType(y, 3); - SubContainer *c = (SubContainer *)findChildOfType(y, 7); + SubPlayer *p = (SubPlayer *)findChildOfType(y, kPlayerType); + SubContainer *c = (SubContainer *)findChildOfType(y, kContainerType); int cap = 0; int wt; @@ -59,7 +59,7 @@ int AGOSEngine::canPlace(Item *x, Item *y) { return -2; /* Too heavy */ } } else { - SubObject *o = (SubObject *)findChildOfType(y, 2); + SubObject *o = (SubObject *)findChildOfType(y, kObjectType); int ct; int cap = 0; @@ -120,11 +120,11 @@ int AGOSEngine::sizeRec(Item *x, int d) { } int AGOSEngine::sizeOfRec(Item *i, int d) { - SubObject *o = (SubObject *)findChildOfType(i, 2); + SubObject *o = (SubObject *)findChildOfType(i, kObjectType); if (getGameType() == GType_ELVIRA1) { - SubPlayer *p = (SubPlayer *)findChildOfType(i, 3); - SubContainer *c = (SubContainer *)findChildOfType(i, 7); + SubPlayer *p = (SubPlayer *)findChildOfType(i, kPlayerType); + SubContainer *c = (SubContainer *)findChildOfType(i, kContainerType); if ((c) && (c->flags & 1)) { if (o) @@ -174,10 +174,10 @@ int AGOSEngine::weightRec(Item *x, int d) { } int AGOSEngine::weightOf(Item *x) { - SubObject *o = (SubObject *)findChildOfType(x, 2); + SubObject *o = (SubObject *)findChildOfType(x, kObjectType); if (getGameType() == GType_ELVIRA1) { - SubPlayer *p = (SubPlayer *)findChildOfType(x, 3); + SubPlayer *p = (SubPlayer *)findChildOfType(x, kPlayerType); if (o) return o->objectWeight; if (p) diff --git a/engines/agos/debugger.cpp b/engines/agos/debugger.cpp index ce50460621..3fc5a1f967 100644 --- a/engines/agos/debugger.cpp +++ b/engines/agos/debugger.cpp @@ -174,7 +174,7 @@ bool Debugger::Cmd_SetObjectFlag(int argc, const char **argv) { prop = atoi(argv[2]); if (obj >= 1 && obj < _vm->_itemArraySize) { - SubObject *o = (SubObject *)_vm->findChildOfType(_vm->derefItem(obj), 2); + SubObject *o = (SubObject *)_vm->findChildOfType(_vm->derefItem(obj), kObjectType); if (o != NULL) { if (o->objectFlags & (1 << prop) && prop < 16) { uint offs = _vm->getOffsetOfChild2Param(o, 1 << prop); diff --git a/engines/agos/detection_tables.h b/engines/agos/detection_tables.h index cb6123dc54..5efcaa3b86 100644 --- a/engines/agos/detection_tables.h +++ b/engines/agos/detection_tables.h @@ -426,7 +426,7 @@ static const AGOSGameDescription gameDescriptions[] = { { "gamepc", GAME_BASEFILE, "4bf28ab00f5324fd938e632595742382", -1}, { "icon.dat", GAME_ICONFILE, "83a7278bff55c82fbb3aef92981866c9", -1}, { "menus.dat", GAME_MENUFILE, "a2fdc88a77c8bdffec6b36cbeda4d955", -1}, - { "start", GAME_RESTFILE, "4d380a35ba941d03ee5084c71d20055b", -1}, + { "start", GAME_RESTFILE, "016107aced82d0cc5d758a9fba716270", -1}, { "stripped.txt", GAME_STRFILE, "c3a8f644551a27c8a2fec0f8070b46b7", -1}, { "tbllist", GAME_TBLFILE, "8252660df0edbdbc3e6377e155bbd0c5", -1}, { NULL, 0, NULL, 0} diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp index 32329f34d9..5c673de700 100644 --- a/engines/agos/event.cpp +++ b/engines/agos/event.cpp @@ -500,10 +500,7 @@ void AGOSEngine::delay(uint amount) { } // Make sure backspace works right (this fixes a small issue on OS X) - if (event.kbd.keycode == Common::KEYCODE_BACKSPACE) - _keyPressed = 8; - else - _keyPressed = (byte)event.kbd.ascii; + _keyPressed = event.kbd; break; case Common::EVENT_MOUSEMOVE: break; diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp index ef0791dc10..0f1c234b79 100644 --- a/engines/agos/input.cpp +++ b/engines/agos/input.cpp @@ -195,7 +195,8 @@ void AGOSEngine::waitForInput() { _dragAccept = 1; for (;;) { - if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) && _keyPressed == 35) + if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) && + _keyPressed.keycode == Common::KEYCODE_HASH) displayBoxStars(); if (processSpecialKeys()) { if ((getGameType() == GType_PP && getGameId() != GID_DIMP) || @@ -238,7 +239,6 @@ void AGOSEngine::waitForInput() { _dragMode = 0; _dragCount = 0; _dragEnd = 0; - continue; } } while (!_dragEnd); @@ -472,39 +472,39 @@ bool AGOSEngine::processSpecialKeys() { } } - switch (_keyPressed) { - case 17: // Up + switch (_keyPressed.keycode) { + case Common::KEYCODE_UP: if (getGameType() == GType_PP) _verbHitArea = 302; else if (getGameType() == GType_WW) _verbHitArea = 239; verbCode = true; break; - case 18: // Down + case Common::KEYCODE_DOWN: if (getGameType() == GType_PP) _verbHitArea = 304; else if (getGameType() == GType_WW) _verbHitArea = 241; verbCode = true; break; - case 19: // Right + case Common::KEYCODE_RIGHT: if (getGameType() == GType_PP) _verbHitArea = 303; else if (getGameType() == GType_WW) _verbHitArea = 240; verbCode = true; break; - case 20: // Left + case Common::KEYCODE_LEFT: if (getGameType() == GType_PP) _verbHitArea = 301; else if (getGameType() == GType_WW) _verbHitArea = 242; verbCode = true; break; - case 27: // escape + case Common::KEYCODE_ESCAPE: _exitCutscene = true; break; - case 59: // F1 + case Common::KEYCODE_F1: if (getGameType() == GType_SIMON2) { vcWriteVar(5, 50); vcWriteVar(86, 0); @@ -513,7 +513,7 @@ bool AGOSEngine::processSpecialKeys() { vcWriteVar(86, 0); } break; - case 60: // F2 + case Common::KEYCODE_F2: if (getGameType() == GType_SIMON2) { vcWriteVar(5, 75); vcWriteVar(86, 1); @@ -522,7 +522,7 @@ bool AGOSEngine::processSpecialKeys() { vcWriteVar(86, 1); } break; - case 61: // F3 + case Common::KEYCODE_F3: if (getGameType() == GType_SIMON2) { vcWriteVar(5, 125); vcWriteVar(86, 2); @@ -531,19 +531,19 @@ bool AGOSEngine::processSpecialKeys() { vcWriteVar(86, 2); } break; - case 63: // F5 + case Common::KEYCODE_F5: if (getGameType() == GType_SIMON2 || getGameType() == GType_FF) _exitCutscene = true; break; - case 65: // F7 + case Common::KEYCODE_F7: if (getGameType() == GType_FF && getBitFlag(76)) _variableArray[254] = 70; break; - case 67: // F9 + case Common::KEYCODE_F9: if (getGameType() == GType_FF) setBitFlag(73, !getBitFlag(73)); break; - case 37: // F12 + case Common::KEYCODE_F12: if (getGameType() == GType_PP && getGameId() != GID_DIMP) { if (!getBitFlag(110)) { setBitFlag(107, !getBitFlag(107)); @@ -551,73 +551,77 @@ bool AGOSEngine::processSpecialKeys() { } } break; - case 'p': + case Common::KEYCODE_p: pause(); break; - case 't': + case Common::KEYCODE_t: if (getGameType() == GType_FF || (getGameType() == GType_SIMON2 && (getFeatures() & GF_TALKIE)) || ((getFeatures() & GF_TALKIE) && _language != Common::EN_ANY && _language != Common::DE_DEU)) { if (_speech) _subtitles ^= 1; } break; - case 'v': + case Common::KEYCODE_v: if (getGameType() == GType_FF || (getGameType() == GType_SIMON2 && (getFeatures() & GF_TALKIE))) { if (_subtitles) _speech ^= 1; } - case '+': + case Common::KEYCODE_PLUS: + case Common::KEYCODE_KP_PLUS: if (_midiEnabled) { _midi.setVolume(_midi.getVolume() + 16); } _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) + 16); break; - case '-': + case Common::KEYCODE_MINUS: + case Common::KEYCODE_KP_MINUS: if (_midiEnabled) { _midi.setVolume(_midi.getVolume() - 16); } _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) - 16); break; - case 'm': + case Common::KEYCODE_m: _musicPaused ^= 1; if (_midiEnabled) { _midi.pause(_musicPaused); } _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, (_musicPaused) ? 0 : ConfMan.getInt("music_volume")); break; - case 's': + case Common::KEYCODE_s: if (getGameId() == GID_SIMON1DOS) { _midi._enable_sfx ^= 1; } else { _sound->effectsPause(_effectsPaused ^= 1); } break; - case 'b': + case Common::KEYCODE_b: _sound->ambientPause(_ambientPaused ^= 1); break; - case 'r': + case Common::KEYCODE_r: if (_debugMode) _startMainScript ^= 1; break; - case 'o': + case Common::KEYCODE_o: if (_debugMode) _continousMainScript ^= 1; break; - case 'a': + case Common::KEYCODE_a: if (_debugMode) _startVgaScript ^= 1; break; - case 'g': + case Common::KEYCODE_g: if (_debugMode) _continousVgaScript ^= 1; break; - case 'd': + case Common::KEYCODE_d: if (_debugMode) _dumpImages ^=1; break; + default: + break; } - _keyPressed = 0; + _keyPressed.reset(); return verbCode; } diff --git a/engines/agos/intern.h b/engines/agos/intern.h index a863dc7c0f..44d38fbeed 100644 --- a/engines/agos/intern.h +++ b/engines/agos/intern.h @@ -28,6 +28,20 @@ namespace AGOS { +enum ChildType { + kRoomType = 1, + kObjectType = 2, + kPlayerType = 3, + kGenExitType = 4, // Elvira 1 specific + kSuperRoomType = 4, // Elvira 2 specific + + kContainerType = 7, + kChainType = 8, + kUserFlagType = 9, + + kInheritType = 255 +}; + struct Child { Child *next; uint16 type; diff --git a/engines/agos/items.cpp b/engines/agos/items.cpp index a911bee5a5..9a46b6e8ac 100644 --- a/engines/agos/items.cpp +++ b/engines/agos/items.cpp @@ -66,7 +66,7 @@ bool AGOSEngine::hasIcon(Item *item) { if (getGameType() == GType_ELVIRA1) { return (getUserFlag(item, 7) != 0); } else { - SubObject *child = (SubObject *)findChildOfType(item, 2); + SubObject *child = (SubObject *)findChildOfType(item, kObjectType); return (child && (child->objectFlags & kOFIcon) != 0); } } @@ -75,7 +75,7 @@ uint AGOSEngine::itemGetIconNumber(Item *item) { if (getGameType() == GType_ELVIRA1) { return getUserFlag(item, 7); } else { - SubObject *child = (SubObject *)findChildOfType(item, 2); + SubObject *child = (SubObject *)findChildOfType(item, kObjectType); uint offs; if (child == NULL || !(child->objectFlags & kOFIcon)) @@ -97,7 +97,7 @@ void AGOSEngine::createPlayer() { _currentPlayer->adjective = -1; _currentPlayer->noun = 10000; - p = (SubPlayer *)allocateChildBlock(_currentPlayer, 3, sizeof(SubPlayer)); + p = (SubPlayer *)allocateChildBlock(_currentPlayer, kPlayerType, sizeof(SubPlayer)); if (p == NULL) error("createPlayer: player create failure"); @@ -135,14 +135,14 @@ Child *AGOSEngine::findChildOfType(Item *i, uint type) { int AGOSEngine::getUserFlag(Item *item, int a) { SubUserFlag *subUserFlag; - subUserFlag = (SubUserFlag *) findChildOfType(item, 9); + subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (subUserFlag == NULL) return 0; if (a < 0 || a > 7) return 0; - return subUserFlag->userFlags[a]; + return subUserFlag->userFlags[a]; } int AGOSEngine::getUserFlag1(Item *item, int a) { @@ -151,7 +151,7 @@ int AGOSEngine::getUserFlag1(Item *item, int a) { if (item == NULL || item == _dummyItem2 || item == _dummyItem3) return -1; - subUserFlag = (SubUserFlag *) findChildOfType(item, 9); + subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (subUserFlag == NULL) return 0; @@ -164,9 +164,9 @@ int AGOSEngine::getUserFlag1(Item *item, int a) { void AGOSEngine::setUserFlag(Item *item, int a, int b) { SubUserFlag *subUserFlag; - subUserFlag = (SubUserFlag *) findChildOfType(item, 9); + subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (subUserFlag == NULL) { - subUserFlag = (SubUserFlag *) allocateChildBlock(item, 9, sizeof(SubUserFlag)); + subUserFlag = (SubUserFlag *)allocateChildBlock(item, kUserFlagType, sizeof(SubUserFlag)); } if (a < 0 || a > 7) @@ -178,7 +178,7 @@ void AGOSEngine::setUserFlag(Item *item, int a, int b) { int AGOSEngine::getUserItem(Item *item, int n) { SubUserFlag *subUserFlag; - subUserFlag = (SubUserFlag *) findChildOfType(item, 9); + subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (subUserFlag == NULL) return 0; @@ -191,9 +191,9 @@ int AGOSEngine::getUserItem(Item *item, int n) { void AGOSEngine::setUserItem(Item *item, int n, int m) { SubUserFlag *subUserFlag; - subUserFlag = (SubUserFlag *) findChildOfType(item, 9); + subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (subUserFlag == NULL) { - subUserFlag = (SubUserFlag *) allocateChildBlock(item, 9, sizeof(SubUserFlag)); + subUserFlag = (SubUserFlag *)allocateChildBlock(item, kUserFlagType, sizeof(SubUserFlag)); } if (n == 0) @@ -201,15 +201,15 @@ void AGOSEngine::setUserItem(Item *item, int n, int m) { } bool AGOSEngine::isRoom(Item *item) { - return findChildOfType(item, 1) != NULL; + return findChildOfType(item, kRoomType) != NULL; } bool AGOSEngine::isObject(Item *item) { - return findChildOfType(item, 2) != NULL; + return findChildOfType(item, kObjectType) != NULL; } bool AGOSEngine::isPlayer(Item *item) { - return findChildOfType(item, 3) != NULL; + return findChildOfType(item, kPlayerType) != NULL; } uint AGOSEngine::getOffsetOfChild2Param(SubObject *child, uint prop) { diff --git a/engines/agos/menus.cpp b/engines/agos/menus.cpp index 6dd1a356d8..81df34c311 100644 --- a/engines/agos/menus.cpp +++ b/engines/agos/menus.cpp @@ -199,7 +199,7 @@ uint AGOSEngine::menuFor_e2(Item *item) { if (item == NULL || item == _dummyItem2 || item == _dummyItem3) return 0xFFFF; - SubObject *subObject = (SubObject *)findChildOfType(item, 2); + SubObject *subObject = (SubObject *)findChildOfType(item, kObjectType); if (subObject != NULL && subObject->objectFlags & kOFMenu) { uint offs = getOffsetOfChild2Param(subObject, kOFMenu); return subObject->objectFlagValue[offs]; @@ -216,7 +216,7 @@ uint AGOSEngine::menuFor_ww(Item *item, uint id) { if (item == NULL || item == _dummyItem2 || item == _dummyItem3) return _agosMenu; - SubObject *subObject = (SubObject *)findChildOfType(item, 2); + SubObject *subObject = (SubObject *)findChildOfType(item, kObjectType); if (subObject != NULL && subObject->objectFlags & kOFMenu) { uint offs = getOffsetOfChild2Param(subObject, kOFMenu); return subObject->objectFlagValue[offs]; diff --git a/engines/agos/oracle.cpp b/engines/agos/oracle.cpp index 787596a966..c7ad0ee8b7 100644 --- a/engines/agos/oracle.cpp +++ b/engines/agos/oracle.cpp @@ -464,37 +464,37 @@ void AGOSEngine_Feeble::saveUserGame(int slot) { windowPutChar(window, 0x7f); for (;;) { - _keyPressed = 0; + _keyPressed.reset(); delay(1); - if (_keyPressed == 0 || _keyPressed >= 127) + if (_keyPressed.ascii == 0 || _keyPressed.ascii >= 127) continue; window->textColumn -= getFeebleFontSize(127); name[len] = 0; windowBackSpace(_windowArray[3]); - if (_keyPressed == 27) { - _variableArray[55] = _keyPressed; + if (_keyPressed.keycode == Common::KEYCODE_ESCAPE) { + _variableArray[55] = 27; break; } - if (_keyPressed == 10 || _keyPressed == 13) { + if (_keyPressed.keycode == Common::KEYCODE_KP_ENTER || _keyPressed.keycode == Common::KEYCODE_RETURN) { if (!saveGame(readVariable(55), name)) _variableArray[55] = (int16)0xFFFF; else _variableArray[55] = 0; break; } - if (_keyPressed == 8 && len != 0) { + if (_keyPressed.keycode == Common::KEYCODE_BACKSPACE && len != 0) { len--; byte chr = name[len]; window->textColumn -= getFeebleFontSize(chr); name[len] = 0; windowBackSpace(_windowArray[3]); } - if (_keyPressed >= 32 && window->textColumn + 26 <= window->width) { - name[len++] = _keyPressed; - windowPutChar(_windowArray[3], _keyPressed); + if (_keyPressed.ascii >= 32 && window->textColumn + 26 <= window->width) { + name[len++] = _keyPressed.ascii; + windowPutChar(_windowArray[3], _keyPressed.ascii); } windowPutChar(window, 0x7f); diff --git a/engines/agos/res.cpp b/engines/agos/res.cpp index 394c4956ae..4898cc9a45 100644 --- a/engines/agos/res.cpp +++ b/engines/agos/res.cpp @@ -350,13 +350,13 @@ void AGOSEngine::readItemFromGamePc(Common::SeekableReadStream *in, Item *item) } void AGOSEngine::readItemChildren(Common::SeekableReadStream *in, Item *item, uint type) { - if (type == 1) { - SubRoom *subRoom = (SubRoom *)allocateChildBlock(item, 1, sizeof(SubRoom)); + if (type == kRoomType) { + SubRoom *subRoom = (SubRoom *)allocateChildBlock(item, kRoomType, sizeof(SubRoom)); subRoom->roomShort = in->readUint32BE(); subRoom->roomLong = in->readUint32BE(); subRoom->flags = in->readUint16BE(); - } else if (type == 2) { - SubObject *subObject = (SubObject *)allocateChildBlock(item, 2, sizeof(SubObject)); + } else if (type == kObjectType) { + SubObject *subObject = (SubObject *)allocateChildBlock(item, kObjectType, sizeof(SubObject)); in->readUint32BE(); in->readUint32BE(); in->readUint32BE(); @@ -364,8 +364,8 @@ void AGOSEngine::readItemChildren(Common::SeekableReadStream *in, Item *item, ui subObject->objectSize = in->readUint16BE(); subObject->objectWeight = in->readUint16BE(); subObject->objectFlags = in->readUint16BE(); - } else if (type == 4) { - SubGenExit *genExit = (SubGenExit *)allocateChildBlock(item, 4, sizeof(SubGenExit)); + } else if (type == kGenExitType) { + SubGenExit *genExit = (SubGenExit *)allocateChildBlock(item, kGenExitType, sizeof(SubGenExit)); genExit->dest[0] = (uint16)fileReadItemID(in); genExit->dest[1] = (uint16)fileReadItemID(in); genExit->dest[2] = (uint16)fileReadItemID(in); @@ -378,14 +378,14 @@ void AGOSEngine::readItemChildren(Common::SeekableReadStream *in, Item *item, ui fileReadItemID(in); fileReadItemID(in); fileReadItemID(in); - } else if (type == 7) { - SubContainer *container = (SubContainer *)allocateChildBlock(item, 7, sizeof(SubContainer)); + } else if (type == kContainerType) { + SubContainer *container = (SubContainer *)allocateChildBlock(item, kContainerType, sizeof(SubContainer)); container->volume = in->readUint16BE(); container->flags = in->readUint16BE(); - } else if (type == 8) { - SubChain *chain = (SubChain *)allocateChildBlock(item, 8, sizeof(SubChain)); + } else if (type == kChainType) { + SubChain *chain = (SubChain *)allocateChildBlock(item, kChainType, sizeof(SubChain)); chain->chChained = (uint16)fileReadItemID(in); - } else if (type == 9) { + } else if (type == kUserFlagType) { setUserFlag(item, 0, in->readUint16BE()); setUserFlag(item, 1, in->readUint16BE()); setUserFlag(item, 2, in->readUint16BE()); @@ -394,13 +394,13 @@ void AGOSEngine::readItemChildren(Common::SeekableReadStream *in, Item *item, ui setUserFlag(item, 5, in->readUint16BE()); setUserFlag(item, 6, in->readUint16BE()); setUserFlag(item, 7, in->readUint16BE()); - SubUserFlag *subUserFlag = (SubUserFlag *) findChildOfType(item, 9); + SubUserFlag *subUserFlag = (SubUserFlag *)findChildOfType(item, kUserFlagType); subUserFlag->userItems[0] = (uint16)fileReadItemID(in); fileReadItemID(in); fileReadItemID(in); fileReadItemID(in); - } else if (type == 255) { - SubInherit *inherit = (SubInherit *)allocateChildBlock(item, 255, sizeof(SubInherit)); + } else if (type == kInheritType) { + SubInherit *inherit = (SubInherit *)allocateChildBlock(item, kInheritType, sizeof(SubInherit)); inherit->inMaster = (uint16)fileReadItemID(in); } else { error("readItemChildren: invalid type %d", type); @@ -408,7 +408,7 @@ void AGOSEngine::readItemChildren(Common::SeekableReadStream *in, Item *item, ui } void AGOSEngine_Elvira2::readItemChildren(Common::SeekableReadStream *in, Item *item, uint type) { - if (type == 1) { + if (type == kRoomType) { uint fr1 = in->readUint16BE(); uint fr2 = in->readUint16BE(); uint i, size; @@ -420,14 +420,14 @@ void AGOSEngine_Elvira2::readItemChildren(Common::SeekableReadStream *in, Item * if (j & 3) size += sizeof(subRoom->roomExit[0]); - subRoom = (SubRoom *)allocateChildBlock(item, 1, size); + subRoom = (SubRoom *)allocateChildBlock(item, kRoomType, size); subRoom->subroutine_id = fr1; subRoom->roomExitStates = fr2; for (i = k = 0, j = fr2; i != 6; i++, j >>= 2) if (j & 3) subRoom->roomExit[k++] = (uint16)fileReadItemID(in); - } else if (type == 2) { + } else if (type == kObjectType) { uint32 fr = in->readUint32BE(); uint i, k, size; SubObject *subObject; @@ -437,7 +437,7 @@ void AGOSEngine_Elvira2::readItemChildren(Common::SeekableReadStream *in, Item * if (fr & (1 << i)) size += sizeof(subObject->objectFlagValue[0]); - subObject = (SubObject *)allocateChildBlock(item, 2, size); + subObject = (SubObject *)allocateChildBlock(item, kObjectType, size); subObject->objectFlags = fr; k = 0; @@ -450,7 +450,7 @@ void AGOSEngine_Elvira2::readItemChildren(Common::SeekableReadStream *in, Item * if (getGameType() != GType_ELVIRA2) subObject->objectName = (uint16)in->readUint32BE(); - } else if (type == 4) { + } else if (type == kSuperRoomType) { assert(getGameType() == GType_ELVIRA2); uint i, j, k, size; @@ -467,7 +467,7 @@ void AGOSEngine_Elvira2::readItemChildren(Common::SeekableReadStream *in, Item * for (i = 0; i != j; i++) size += sizeof(subSuperRoom->roomExitStates[0]); - subSuperRoom = (SubSuperRoom *)allocateChildBlock(item, 4, size); + subSuperRoom = (SubSuperRoom *)allocateChildBlock(item, kSuperRoomType, size); subSuperRoom->subroutine_id = id; subSuperRoom->roomX = x; subSuperRoom->roomY = y; @@ -475,20 +475,20 @@ void AGOSEngine_Elvira2::readItemChildren(Common::SeekableReadStream *in, Item * for (i = k = 0; i != j; i++) subSuperRoom->roomExitStates[k++] = in->readUint16BE(); - } else if (type == 7) { - SubContainer *container = (SubContainer *)allocateChildBlock(item, 7, sizeof(SubContainer)); + } else if (type == kContainerType) { + SubContainer *container = (SubContainer *)allocateChildBlock(item, kContainerType, sizeof(SubContainer)); container->volume = in->readUint16BE(); container->flags = in->readUint16BE(); - } else if (type == 8) { - SubChain *chain = (SubChain *)allocateChildBlock(item, 8, sizeof(SubChain)); + } else if (type == kChainType) { + SubChain *chain = (SubChain *)allocateChildBlock(item, kChainType, sizeof(SubChain)); chain->chChained = (uint16)fileReadItemID(in); - } else if (type == 9) { + } else if (type == kUserFlagType) { setUserFlag(item, 0, in->readUint16BE()); setUserFlag(item, 1, in->readUint16BE()); setUserFlag(item, 2, in->readUint16BE()); setUserFlag(item, 3, in->readUint16BE()); - } else if (type == 255) { - SubInherit *inherit = (SubInherit *)allocateChildBlock(item, 255, sizeof(SubInherit)); + } else if (type == kInheritType) { + SubInherit *inherit = (SubInherit *)allocateChildBlock(item, kInheritType, sizeof(SubInherit)); inherit->inMaster = (uint16)fileReadItemID(in); } else { error("readItemChildren: invalid type %d", type); diff --git a/engines/agos/rooms.cpp b/engines/agos/rooms.cpp index af1bd0fe93..5e612080df 100644 --- a/engines/agos/rooms.cpp +++ b/engines/agos/rooms.cpp @@ -49,7 +49,7 @@ uint16 AGOSEngine::getDoorState(Item *item, uint16 d) { uint16 mask = 3; uint16 n; - SubRoom *subRoom = (SubRoom *)findChildOfType(item, 1); + SubRoom *subRoom = (SubRoom *)findChildOfType(item, kRoomType); if (subRoom == NULL) return 0; @@ -66,7 +66,7 @@ uint16 AGOSEngine::getExitOf(Item *item, uint16 d) { uint16 x; uint16 y = 0; - subRoom = (SubRoom *)findChildOfType(item, 1); + subRoom = (SubRoom *)findChildOfType(item, kRoomType); if (subRoom == NULL) return 0; x = d; @@ -93,7 +93,7 @@ void AGOSEngine::setDoorState(Item *i, uint16 d, uint16 n) { uint16 d1; uint16 y = 0; - r = (SubRoom *)findChildOfType(i, 1); + r = (SubRoom *)findChildOfType(i, kRoomType); if (r == NULL) return; d1 = d; @@ -107,7 +107,7 @@ void AGOSEngine::setDoorState(Item *i, uint16 d, uint16 n) { j = derefItem(r->roomExit[d1]); if (j == NULL) return; - r1 = (SubRoom *)findChildOfType(j, 1); + r1 = (SubRoom *)findChildOfType(j, kRoomType); if (r1 == NULL) return; d = getBackExit(d); @@ -130,7 +130,7 @@ Item *AGOSEngine::getDoorOf(Item *i, uint16 d) { SubGenExit *g; Item *x; - g = (SubGenExit *)findChildOfType(i, 4); + g = (SubGenExit *)findChildOfType(i, kGenExitType); if (g == NULL) return 0; @@ -146,7 +146,7 @@ Item *AGOSEngine::getExitOf_e1(Item *item, uint16 d) { SubGenExit *g; Item *x; - g = (SubGenExit *)findChildOfType(item, 4); + g = (SubGenExit *)findChildOfType(item, kGenExitType); if (g == NULL) return 0; @@ -192,10 +192,10 @@ void AGOSEngine_Elvira2::moveDirn(Item *i, uint x) { return; p = derefItem(i->parent); - if (findChildOfType(p, 4)) { + if (findChildOfType(p, kSuperRoomType)) { n = getExitState(p, _superRoomNumber,x); if (n == 1) { - sr = (SubSuperRoom *)findChildOfType(p, 4); + sr = (SubSuperRoom *)findChildOfType(p, kSuperRoomType); switch (x) { case 0: a = -(sr->roomX); break; case 1: a = 1; break; @@ -319,7 +319,7 @@ uint16 AGOSEngine_Elvira2::getExitState(Item *i, uint16 x, uint16 d) { uint16 mask = 3; uint16 n; - sr = (SubSuperRoom *)findChildOfType(i, 4); + sr = (SubSuperRoom *)findChildOfType(i, kSuperRoomType); if (sr == NULL) return 0; @@ -331,7 +331,7 @@ uint16 AGOSEngine_Elvira2::getExitState(Item *i, uint16 x, uint16 d) { } void AGOSEngine_Elvira2::setExitState(Item *i, uint16 n, uint16 d, uint16 s) { - SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(i, 4); + SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(i, kSuperRoomType); if (sr) changeExitStates(sr, n, d, s); } @@ -339,7 +339,7 @@ void AGOSEngine_Elvira2::setExitState(Item *i, uint16 n, uint16 d, uint16 s) { void AGOSEngine_Elvira2::setSRExit(Item *i, int n, int d, uint16 s) { uint16 mask = 3; - SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(i, 4); + SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(i, kSuperRoomType); if (sr) { n--; d <<= 1; diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index eb2266550a..32b767073a 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -257,12 +257,12 @@ restart: for (;;) { windowPutChar(window, 128); - _keyPressed = 0; + _keyPressed.reset(); for (;;) { delay(10); - if (_keyPressed && _keyPressed < 128) { - i = _keyPressed; + if (_keyPressed.ascii && _keyPressed.ascii < 128) { + i = _keyPressed.ascii; break; } } @@ -490,16 +490,16 @@ int AGOSEngine_Elvira2::userGameGetKey(bool *b, char *buf, uint maxChar) { HitArea *ha; *b = true; - _keyPressed = 0; + _keyPressed.reset(); for (;;) { _lastHitArea = NULL; _lastHitArea3 = NULL; do { - if (_saveLoadEdit && _keyPressed && _keyPressed < maxChar) { + if (_saveLoadEdit && _keyPressed.ascii && _keyPressed.ascii < maxChar) { *b = false; - return _keyPressed; + return _keyPressed.ascii; } delay(10); } while (_lastHitArea3 == 0); @@ -759,16 +759,16 @@ int AGOSEngine_Simon1::userGameGetKey(bool *b, char *buf, uint maxChar) { listSaveGames(buf); } - _keyPressed = 0; + _keyPressed.reset(); for (;;) { _lastHitArea = NULL; _lastHitArea3 = NULL; do { - if (_saveLoadEdit && _keyPressed && _keyPressed < maxChar) { + if (_saveLoadEdit && _keyPressed.ascii && _keyPressed.ascii < maxChar) { *b = false; - return _keyPressed; + return _keyPressed.ascii; } delay(10); } while (_lastHitArea3 == 0); @@ -999,13 +999,13 @@ bool AGOSEngine::loadGame(const char *filename, bool restartMode) { item->state = f->readUint16BE(); item->classFlags = f->readUint16BE(); - SubObject *o = (SubObject *)findChildOfType(item, 2); + SubObject *o = (SubObject *)findChildOfType(item, kObjectType); if (o) { o->objectSize = f->readUint16BE(); o->objectWeight = f->readUint16BE(); } - SubPlayer *p = (SubPlayer *)findChildOfType(item, 3); + SubPlayer *p = (SubPlayer *)findChildOfType(item, kPlayerType); if (p) { p->score = f->readUint32BE(); p->level = f->readUint16BE(); @@ -1014,7 +1014,7 @@ bool AGOSEngine::loadGame(const char *filename, bool restartMode) { p->strength = f->readUint16BE(); } - SubUserFlag *u = (SubUserFlag *) findChildOfType(item, 9); + SubUserFlag *u = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (u) { for (i = 0; i != 8; i++) { u->userFlags[i] = f->readUint16BE(); @@ -1083,13 +1083,13 @@ bool AGOSEngine::saveGame(uint slot, const char *caption) { f->writeUint16BE(item->state); f->writeUint16BE(item->classFlags); - SubObject *o = (SubObject *)findChildOfType(item, 2); + SubObject *o = (SubObject *)findChildOfType(item, kObjectType); if (o) { f->writeUint16BE(o->objectSize); f->writeUint16BE(o->objectWeight); } - SubPlayer *p = (SubPlayer *)findChildOfType(item, 3); + SubPlayer *p = (SubPlayer *)findChildOfType(item, kPlayerType); if (p) { f->writeUint32BE(p->score); f->writeUint16BE(p->level); @@ -1098,7 +1098,7 @@ bool AGOSEngine::saveGame(uint slot, const char *caption) { f->writeUint16BE(p->strength); } - SubUserFlag *u = (SubUserFlag *) findChildOfType(item, 9); + SubUserFlag *u = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (u) { for (i = 0; i != 8; i++) { f->writeUint16BE(u->userFlags[i]); @@ -1204,19 +1204,19 @@ bool AGOSEngine_Elvira2::loadGame(const char *filename, bool restartMode) { item->state = f->readUint16BE(); item->classFlags = f->readUint16BE(); - SubRoom *r = (SubRoom *)findChildOfType(item, 1); + SubRoom *r = (SubRoom *)findChildOfType(item, kRoomType); if (r) { r->roomExitStates = f->readUint16BE(); } - SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(item, 4); + SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(item, kSuperRoomType); if (sr) { uint16 n = sr->roomX * sr->roomY * sr->roomZ; for (i = j = 0; i != n; i++) sr->roomExitStates[j++] = f->readUint16BE(); } - SubObject *o = (SubObject *)findChildOfType(item, 2); + SubObject *o = (SubObject *)findChildOfType(item, kObjectType); if (o) { o->objectFlags = f->readUint32BE(); i = o->objectFlags & 1; @@ -1228,7 +1228,7 @@ bool AGOSEngine_Elvira2::loadGame(const char *filename, bool restartMode) { } } - SubUserFlag *u = (SubUserFlag *) findChildOfType(item, 9); + SubUserFlag *u = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (u) { for (i = 0; i != 4; i++) { u->userFlags[i] = f->readUint16BE(); @@ -1283,9 +1283,12 @@ bool AGOSEngine_Elvira2::saveGame(uint slot, const char *caption) { Common::OutSaveFile *f; uint item_index, num_item, i, j; TimeEvent *te; - uint32 curTime = 0; uint32 gsc = _gameStoppedClock; + uint32 curTime = 0; + if (getGameType() != GType_SIMON1 && getGameType() != GType_SIMON2) + curTime = time(NULL); + _lockWord |= 0x100; f = _saveFileMan->openForSaving(genSaveName(slot)); @@ -1299,7 +1302,6 @@ bool AGOSEngine_Elvira2::saveGame(uint slot, const char *caption) { // No caption } else if (getGameType() == GType_FF) { f->write(caption, 100); - curTime = time(NULL); } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { f->write(caption, 18); } else { @@ -1308,7 +1310,7 @@ bool AGOSEngine_Elvira2::saveGame(uint slot, const char *caption) { f->writeUint32BE(_itemArrayInited - 1); f->writeUint32BE(0xFFFFFFFF); - f->writeUint32BE(0); + f->writeUint32BE(curTime); f->writeUint32BE(0); i = 0; @@ -1345,19 +1347,19 @@ bool AGOSEngine_Elvira2::saveGame(uint slot, const char *caption) { f->writeUint16BE(item->state); f->writeUint16BE(item->classFlags); - SubRoom *r = (SubRoom *)findChildOfType(item, 1); + SubRoom *r = (SubRoom *)findChildOfType(item, kRoomType); if (r) { f->writeUint16BE(r->roomExitStates); } - SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(item, 4); + SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(item, kSuperRoomType); if (sr) { uint16 n = sr->roomX * sr->roomY * sr->roomZ; for (i = j = 0; i != n; i++) f->writeUint16BE(sr->roomExitStates[j++]); } - SubObject *o = (SubObject *)findChildOfType(item, 2); + SubObject *o = (SubObject *)findChildOfType(item, kObjectType); if (o) { f->writeUint32BE(o->objectFlags); i = o->objectFlags & 1; @@ -1369,7 +1371,7 @@ bool AGOSEngine_Elvira2::saveGame(uint slot, const char *caption) { } } - SubUserFlag *u = (SubUserFlag *)findChildOfType(item, 9); + SubUserFlag *u = (SubUserFlag *)findChildOfType(item, kUserFlagType); if (u) { for (i = 0; i != 4; i++) { f->writeUint16BE(u->userFlags[i]); diff --git a/engines/agos/script.cpp b/engines/agos/script.cpp index c5cf6c5872..ace0b9d50f 100644 --- a/engines/agos/script.cpp +++ b/engines/agos/script.cpp @@ -206,7 +206,7 @@ void AGOSEngine::o_state() { void AGOSEngine::o_oflag() { // 28: item has prop - SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); + SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); uint num = getVarOrByte(); setScriptCondition(subObject != NULL && (subObject->objectFlags & (1 << num)) != 0); } @@ -326,7 +326,7 @@ void AGOSEngine::o_goto() { void AGOSEngine::o_oset() { // 56: set child2 fr bit - SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); + SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); int value = getVarOrByte(); if (subObject != NULL && value >= 16) subObject->objectFlags |= (1 << value); @@ -334,7 +334,7 @@ void AGOSEngine::o_oset() { void AGOSEngine::o_oclear() { // 57: clear child2 fr bit - SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); + SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); int value = getVarOrByte(); if (subObject != NULL && value >= 16) subObject->objectFlags &= ~(1 << value); @@ -426,7 +426,7 @@ void AGOSEngine::o_if2() { void AGOSEngine::o_isCalled() { // 79: childstruct fr2 is - SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); + SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); uint stringId = getNextStringID(); setScriptCondition((subObject != NULL) && subObject->objectName == stringId); } @@ -753,7 +753,7 @@ void AGOSEngine::o_setAdjNoun() { void AGOSEngine::o_saveUserGame() { // 132: save user game if (getGameId() == GID_SIMON1CD32) { - // The Amiga CD32 version of Simon the Sorcerer 1uses a single slot + // The Amiga CD32 version of Simon the Sorcerer 1 uses a single slot if (!saveGame(0, "Default Saved Game")) { vc33_setMouseOn(); fileError(_windowArray[5], true); @@ -799,7 +799,7 @@ void AGOSEngine::o_freezeZones() { freezeBottom(); if (!_copyProtection && !(getFeatures() & GF_TALKIE)) { - if ((getGameType() == GType_SIMON1 && _subroutine == 2924) || + if ((getGameType() == GType_SIMON1 && _subroutine == 2924) || (getGameType() == GType_SIMON2 && _subroutine == 1322)) { _variableArray[134] = 3; _variableArray[135] = 3; @@ -985,10 +985,10 @@ Child *nextSub(Child *sub, int16 key) { } void AGOSEngine::synchChain(Item *i) { - SubChain *c = (SubChain *)findChildOfType(i, 8); + SubChain *c = (SubChain *)findChildOfType(i, kChainType); while (c) { setItemState(derefItem(c->chChained), i->state); - c = (SubChain *)nextSub((Child *)c, 8); + c = (SubChain *)nextSub((Child *)c, kChainType); } } diff --git a/engines/agos/script_e1.cpp b/engines/agos/script_e1.cpp index b003a7262f..5a1d7d104b 100644 --- a/engines/agos/script_e1.cpp +++ b/engines/agos/script_e1.cpp @@ -419,7 +419,7 @@ void AGOSEngine_Elvira1::oe1_notPresent() { void AGOSEngine_Elvira1::oe1_worn() { // 4: worn Item *item = getNextItemPtr(); - SubObject *subObject = (SubObject *)findChildOfType(item, 2); + SubObject *subObject = (SubObject *)findChildOfType(item, kObjectType); if (item->parent != getItem1ID() || subObject == NULL) setScriptCondition(false); @@ -430,7 +430,7 @@ void AGOSEngine_Elvira1::oe1_worn() { void AGOSEngine_Elvira1::oe1_notWorn() { // 5: not worn Item *item = getNextItemPtr(); - SubObject *subObject = (SubObject *)findChildOfType(item, 2); + SubObject *subObject = (SubObject *)findChildOfType(item, kObjectType); if (item->parent != getItem1ID() || subObject == NULL) setScriptCondition(false); @@ -532,7 +532,7 @@ void AGOSEngine_Elvira1::oe1_moveDirn() { void AGOSEngine_Elvira1::oe1_score() { // 90: score - SubPlayer *p = (SubPlayer *) findChildOfType(me(), 3); + SubPlayer *p = (SubPlayer *)findChildOfType(me(), kPlayerType); showMessageFormat("Your score is %ld.\n", p->score); } @@ -542,9 +542,9 @@ void AGOSEngine_Elvira1::oe1_look() { if (i == NULL) return; - SubRoom *r = (SubRoom *)findChildOfType(i, 1); - SubObject *o = (SubObject *)findChildOfType(i, 2); - SubPlayer *p = (SubPlayer *)findChildOfType(i, 3); + SubRoom *r = (SubRoom *)findChildOfType(i, kRoomType); + SubObject *o = (SubObject *)findChildOfType(i, kObjectType); + SubPlayer *p = (SubPlayer *)findChildOfType(i, kPlayerType); if (p == NULL) return; @@ -594,7 +594,7 @@ void AGOSEngine_Elvira1::oe1_doClass() { void AGOSEngine_Elvira1::oe1_pObj() { // 112: print object - SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); + SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); getVarOrWord(); if (subObject != NULL) @@ -624,7 +624,7 @@ void AGOSEngine_Elvira1::oe1_isCalled() { void AGOSEngine_Elvira1::oe1_cFlag() { // 162: check container flag - SubContainer *c = (SubContainer *)findChildOfType(getNextItemPtr(), 7); + SubContainer *c = (SubContainer *)findChildOfType(getNextItemPtr(), kContainerType); uint bit = getVarOrWord(); if (c == NULL) @@ -678,7 +678,7 @@ void AGOSEngine_Elvira1::oe1_doorExit() { int16 f = getVarOrWord(); int16 ct = 0; - c = (SubChain *)findChildOfType(d, 8); + c = (SubChain *)findChildOfType(d, kChainType); if (c) a = derefItem(c->chChained); while (ct < 6) { @@ -986,7 +986,7 @@ void AGOSEngine_Elvira1::oe1_printMonsterHit() { } int16 AGOSEngine::levelOf(Item *item) { - SubPlayer *p = (SubPlayer *) findChildOfType(item, 3); + SubPlayer *p = (SubPlayer *)findChildOfType(item, kPlayerType); if (p == NULL) return 0; @@ -998,7 +998,7 @@ int16 AGOSEngine::moreText(Item *i) { i = derefItem(i->next); while (i) { - o = (SubObject *)findChildOfType(i, 2); + o = (SubObject *)findChildOfType(i, kObjectType); if ((o) && (o->objectFlags & 1)) goto l1; if (i != me()) @@ -1014,7 +1014,7 @@ void AGOSEngine::lobjFunc(Item *i, const char *f) { SubObject *o; while (i) { - o = (SubObject *)findChildOfType(i, 2); + o = (SubObject *)findChildOfType(i, kObjectType); if ((o) && (o->objectFlags & 1)) goto l1; if (i == me()) diff --git a/engines/agos/script_e2.cpp b/engines/agos/script_e2.cpp index 00f0848ed9..77df3feecb 100644 --- a/engines/agos/script_e2.cpp +++ b/engines/agos/script_e2.cpp @@ -132,7 +132,7 @@ void AGOSEngine_Elvira2::setupOpcodes() { OPCODE(o_when), OPCODE(o_if1), OPCODE(o_if2), - OPCODE(oe1_isCalled), + OPCODE(oe2_isCalled), /* 80 */ OPCODE(o_is), OPCODE(o_invalid), @@ -165,7 +165,7 @@ void AGOSEngine_Elvira2::setupOpcodes() { OPCODE(o_cls), /* 104 */ OPCODE(o_closeWindow), - OPCODE(o_invalid), + OPCODE(oe2_menu), OPCODE(o_invalid), OPCODE(o_addBox), /* 108 */ @@ -309,12 +309,19 @@ void AGOSEngine_Elvira2::oe2_doClass() { void AGOSEngine_Elvira2::oe2_pObj() { // 73: print object - SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); + SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); if (subObject != NULL && subObject->objectFlags & kOFText) showMessageFormat("%s\n", (const char *)getStringPtrByID(subObject->objectFlagValue[0])); // Difference } +void AGOSEngine_Elvira2::oe2_isCalled() { + // 79: childstruct fr2 is + Item *i = getNextItemPtr(); + uint stringId = getNextStringID(); + setScriptCondition(i->itemName == stringId); +} + void AGOSEngine_Elvira2::oe2_loadGame() { // 89: load game uint16 stringId = getNextStringID(); @@ -326,6 +333,11 @@ void AGOSEngine_Elvira2::oe2_loadGame() { } } +void AGOSEngine_Elvira2::oe2_menu() { + // 105: set agos menu + _agosMenu = getVarOrByte(); +} + void AGOSEngine_Elvira2::oe2_drawItem() { // 113: draw item Item *i = getNextItemPtr(); @@ -341,7 +353,7 @@ void AGOSEngine_Elvira2::oe2_doTable() { // 143: start item sub Item *i = getNextItemPtr(); - SubRoom *r = (SubRoom *)findChildOfType(i, 1); + SubRoom *r = (SubRoom *)findChildOfType(i, kRoomType); if (r != NULL) { Subroutine *sub = getSubroutineByID(r->subroutine_id); if (sub) { @@ -351,7 +363,7 @@ void AGOSEngine_Elvira2::oe2_doTable() { } if (getGameType() == GType_ELVIRA2) { - SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(i, 4); + SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(i, kSuperRoomType); if (sr != NULL) { Subroutine *sub = getSubroutineByID(sr->subroutine_id); if (sub) { @@ -478,7 +490,7 @@ void AGOSEngine_Elvira2::oe2_bNotZero() { void AGOSEngine_Elvira2::oe2_getOValue() { // 157: get item int prop Item *item = getNextItemPtr(); - SubObject *subObject = (SubObject *)findChildOfType(item, 2); + SubObject *subObject = (SubObject *)findChildOfType(item, kObjectType); uint prop = getVarOrByte(); if (subObject != NULL && subObject->objectFlags & (1 << prop) && prop < 16) { @@ -492,7 +504,7 @@ void AGOSEngine_Elvira2::oe2_getOValue() { void AGOSEngine_Elvira2::oe2_setOValue() { // 158: set item prop Item *item = getNextItemPtr(); - SubObject *subObject = (SubObject *)findChildOfType(item, 2); + SubObject *subObject = (SubObject *)findChildOfType(item, kObjectType); uint prop = getVarOrByte(); int value = getVarOrWord(); @@ -640,6 +652,16 @@ void AGOSEngine_Elvira2::oe2_isAdjNoun() { // 179: item unk1 unk2 is Item *item = getNextItemPtr(); int16 a = getNextWord(), b = getNextWord(); + + if (getGameType() == GType_ELVIRA2) { + // WORKAROUND: A NULL item can occur when interacting with Wine Bottles + if (item == NULL) { + warning("Please report where exactly this occurs in Elvira 2"); + setScriptCondition(false); + return; + } + } + setScriptCondition(item->adjective == a && item->noun == b); } @@ -707,7 +729,7 @@ void AGOSEngine_Elvira2::printStats() { if (val > 9999) val = 9999; writeChar(window, 30, y, 6, val / 100); - writeChar(window, 32, y, 2, val / 10); + writeChar(window, 32, y, 2, val % 100); mouseOn(); } diff --git a/engines/agos/script_ff.cpp b/engines/agos/script_ff.cpp index c3e6dc5192..8b7af31a66 100644 --- a/engines/agos/script_ff.cpp +++ b/engines/agos/script_ff.cpp @@ -528,7 +528,7 @@ void AGOSEngine_Feeble::off_screenTextPObj() { TextLocation *tl = NULL; char buf[256]; - SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); + SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); if (subObject != NULL && subObject->objectFlags & kOFText) { string_ptr = (const char *)getStringPtrByID(subObject->objectFlagValue[0]); tl = getTextLocation(vgaSpriteId); diff --git a/engines/agos/script_s1.cpp b/engines/agos/script_s1.cpp index 93b907e688..1a4f956b8b 100644 --- a/engines/agos/script_s1.cpp +++ b/engines/agos/script_s1.cpp @@ -311,29 +311,29 @@ void AGOSEngine_Simon1::os1_pauseGame() { _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); // If all else fails, use English as fallback. - byte keyYes = 'y'; - byte keyNo = 'n'; + Common::KeyCode keyYes = Common::KEYCODE_y; + Common::KeyCode keyNo = Common::KEYCODE_n; switch (_language) { case Common::RU_RUS: break; case Common::PL_POL: - keyYes = 't'; + keyYes = Common::KEYCODE_t; break; case Common::HB_ISR: - keyYes = 'f'; + keyYes = Common::KEYCODE_f; break; case Common::ES_ESP: - keyYes = 's'; + keyYes = Common::KEYCODE_s; break; case Common::IT_ITA: - keyYes = 's'; + keyYes = Common::KEYCODE_s; break; case Common::FR_FRA: - keyYes = 'o'; + keyYes = Common::KEYCODE_o; break; case Common::DE_DEU: - keyYes = 'j'; + keyYes = Common::KEYCODE_j; break; default: break; @@ -343,17 +343,17 @@ void AGOSEngine_Simon1::os1_pauseGame() { delay(1); #ifdef _WIN32_WCE if (isSmartphone()) { - if (_keyPressed) { - if (_keyPressed == 13) + if (_keyPressed.keycode) { + if (_keyPressed.keycode == Common::KEYCODE_RETURN) shutdown(); else break; } } #endif - if (_keyPressed == keyYes || _keyPressed == (keyYes - 32)) + if (_keyPressed.keycode == keyYes) shutdown(); - else if (_keyPressed == keyNo || _keyPressed == (keyNo - 32)) + else if (_keyPressed.keycode == keyNo) break; } @@ -419,7 +419,7 @@ void AGOSEngine_Simon1::os1_screenTextPObj() { uint vgaSpriteId = getVarOrByte(); uint color = getVarOrByte(); - SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); + SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); if (getFeatures() & GF_TALKIE) { if (subObject != NULL && subObject->objectFlags & kOFVoice) { uint offs = getOffsetOfChild2Param(subObject, kOFVoice); diff --git a/engines/agos/script_s2.cpp b/engines/agos/script_s2.cpp index dfc1200d7c..00addce396 100644 --- a/engines/agos/script_s2.cpp +++ b/engines/agos/script_s2.cpp @@ -355,7 +355,7 @@ void AGOSEngine_Simon2::os2_screenTextPObj() { uint vgaSpriteId = getVarOrByte(); uint color = getVarOrByte(); - SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); + SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); if (getFeatures() & GF_TALKIE) { if (subObject != NULL && subObject->objectFlags & kOFVoice) { uint speechId = subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFVoice)]; diff --git a/engines/agos/script_ww.cpp b/engines/agos/script_ww.cpp index 377b49ae3f..fc472fd3c3 100644 --- a/engines/agos/script_ww.cpp +++ b/engines/agos/script_ww.cpp @@ -167,7 +167,7 @@ void AGOSEngine_Waxworks::setupOpcodes() { OPCODE(o_cls), /* 104 */ OPCODE(o_closeWindow), - OPCODE(oww_menu), + OPCODE(oe2_menu), OPCODE(oww_textMenu), OPCODE(o_addBox), /* 108 */ @@ -355,11 +355,6 @@ void AGOSEngine_Waxworks::oww_whereTo() { _objectItem = derefItem(getExitOf(i, d)); } -void AGOSEngine_Waxworks::oww_menu() { - // 105: set agos menu - _agosMenu = getVarOrByte(); -} - void AGOSEngine_Waxworks::oww_textMenu() { // 106: set text menu byte slot = getVarOrByte(); @@ -419,7 +414,7 @@ void AGOSEngine_Waxworks::oww_printBox() { void AGOSEngine_Waxworks::oww_boxPObj() { // 188: print object name to box - SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); + SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), kObjectType); if (subObject != NULL && subObject->objectFlags & kOFText) boxTextMsg((const char *)getStringPtrByID(subObject->objectFlagValue[0])); diff --git a/engines/agos/string.cpp b/engines/agos/string.cpp index 483f101889..521a3ab6ea 100644 --- a/engines/agos/string.cpp +++ b/engines/agos/string.cpp @@ -274,7 +274,7 @@ bool AGOSEngine::printNameOf(Item *item, uint x, uint y) { if (item == 0 || item == _dummyItem2 || item == _dummyItem3) return false; - subObject = (SubObject *)findChildOfType(item, 2); + subObject = (SubObject *)findChildOfType(item, kObjectType); if (subObject == NULL) return false; @@ -370,10 +370,12 @@ void AGOSEngine::printScreenText(uint vgaSpriteId, uint color, const char *strin if (y < 2) y = 2; - if (getGameType() == GType_SIMON1) - animate(windowNum, 2, 199 + vgaSpriteId, x, y, 12); - else + if (getGameType() == GType_SIMON1) { + uint16 id = 199 + vgaSpriteId; + animate(windowNum, id / 100, id, x, y, 12); + } else { animate(windowNum, 2, vgaSpriteId, x, y, 12); + } } // The Feeble Files specific diff --git a/engines/agos/vga.cpp b/engines/agos/vga.cpp index 2b8f6d3a09..38c401a80d 100644 --- a/engines/agos/vga.cpp +++ b/engines/agos/vga.cpp @@ -70,8 +70,8 @@ void AGOSEngine::setupVideoOpcodes(VgaOpcodeProc *op) { op[36] = &AGOSEngine::vc36_setWindowImage; op[38] = &AGOSEngine::vc38_ifVarNotZero; op[39] = &AGOSEngine::vc39_setVar; - op[40] = &AGOSEngine::vc40; - op[41] = &AGOSEngine::vc41; + op[40] = &AGOSEngine::vc40_scrollRight; + op[41] = &AGOSEngine::vc41_scrollLeft; op[42] = &AGOSEngine::vc42_delayIfNotEQ; op[43] = &AGOSEngine::vc43_ifBitSet; op[44] = &AGOSEngine::vc44_ifBitClear; @@ -124,8 +124,8 @@ void AGOSEngine_Elvira1::setupVideoOpcodes(VgaOpcodeProc *op) { op[41] = &AGOSEngine::vc37_pokePalette; op[51] = &AGOSEngine::vc38_ifVarNotZero; op[52] = &AGOSEngine::vc39_setVar; - op[53] = &AGOSEngine::vc40; - op[54] = &AGOSEngine::vc41; + op[53] = &AGOSEngine::vc40_scrollRight; + op[54] = &AGOSEngine::vc41_scrollLeft; op[56] = &AGOSEngine::vc42_delayIfNotEQ; } @@ -1257,57 +1257,38 @@ void AGOSEngine::vc39_setVar() { vcWriteVar(var, value); } -void AGOSEngine::vc40() { +void AGOSEngine::vc40_scrollRight() { uint16 var = vcReadNextWord(); int16 value = vcReadVar(var) + vcReadNextWord(); if (getGameType() == GType_SIMON2 && var == 15 && !getBitFlag(80)) { - int16 tmp; - if (_scrollCount != 0) { - if (_scrollCount >= 0) - goto no_scroll; + if ((_scrollCount < 0) || (_scrollCount == 0 && _scrollFlag == 0)) { _scrollCount = 0; - } else { - if (_scrollFlag != 0) - goto no_scroll; - } - - if (value - _scrollX >= 30) { - _scrollCount = 20; - tmp = _scrollXMax - _scrollX; - if (tmp < 20) - _scrollCount = tmp; - addVgaEvent(6, SCROLL_EVENT, NULL, 0, 0); + if (value - _scrollX >= 30) { + _scrollCount = MIN(20, _scrollXMax - _scrollX); + addVgaEvent(6, SCROLL_EVENT, NULL, 0, 0); + } } } -no_scroll:; vcWriteVar(var, value); } -void AGOSEngine::vc41() { +void AGOSEngine::vc41_scrollLeft() { uint16 var = vcReadNextWord(); int16 value = vcReadVar(var) - vcReadNextWord(); if (getGameType() == GType_SIMON2 && var == 15 && !getBitFlag(80)) { - if (_scrollCount != 0) { - if (_scrollCount < 0) - goto no_scroll; - _scrollCount = 0; - } else { - if (_scrollFlag != 0) - goto no_scroll; - } - if ((uint16)(value - _scrollX) < 11) { - _scrollCount = -20; - if (_scrollX < 20) - _scrollCount = -_scrollX; - addVgaEvent(6, SCROLL_EVENT, NULL, 0, 0); + if ((_scrollCount > 0) || (_scrollCount == 0 && _scrollFlag == 0)) { + _scrollCount = 0; + if ((uint16)(value - _scrollX) < 11) { + _scrollCount = -MIN(20, (int)_scrollX); + addVgaEvent(6, SCROLL_EVENT, NULL, 0, 0); + } } } -no_scroll:; vcWriteVar(var, value); } diff --git a/engines/agos/vga.h b/engines/agos/vga.h index 37c5d37106..1994f59f7f 100644 --- a/engines/agos/vga.h +++ b/engines/agos/vga.h @@ -40,20 +40,20 @@ struct VgaFileHeader2_Feeble { uint16 x_4; uint16 animationTable; uint16 x_5; -}; +} PACKED_STRUCT; struct ImageHeader_Feeble { uint16 id; uint16 x_1; uint16 scriptOffs; uint16 x_2; -}; +} PACKED_STRUCT; struct AnimationHeader_Feeble { uint16 scriptOffs; uint16 x_2; uint16 id; -}; +} PACKED_STRUCT; // Simon 1/2 struct ImageHeader_Simon { @@ -61,13 +61,13 @@ struct ImageHeader_Simon { uint16 color; uint16 x_2; uint16 scriptOffs; -}; +} PACKED_STRUCT; struct AnimationHeader_Simon { uint16 id; uint16 x_2; uint16 scriptOffs; -}; +} PACKED_STRUCT; // Elvira 1/2 and Waxworks @@ -76,14 +76,14 @@ struct ImageHeader_WW { uint16 color; uint16 x_2; uint16 scriptOffs; -}; +} PACKED_STRUCT; struct AnimationHeader_WW { uint16 id; uint16 x_1; uint16 x_2; uint16 scriptOffs; -}; +} PACKED_STRUCT; // Common struct VgaFileHeader2_Common { @@ -96,7 +96,7 @@ struct VgaFileHeader2_Common { uint16 x_4; uint16 animationTable; uint16 x_5; -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 281c4807b8..49b10b6b14 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -2458,6 +2458,7 @@ void drawFailureMessage(byte cmd) { void drawOverlays(void) { overlayHeadElement *currentOverlay; + overlayHeadElement *nextOverlay; backupOverlayPage(); @@ -2468,6 +2469,8 @@ void drawOverlays(void) { currentOverlay = currentOverlay->next; while (currentOverlay) { + nextOverlay = currentOverlay->next; + switch (currentOverlay->type) { case 0: // sprite { @@ -2630,7 +2633,7 @@ void drawOverlays(void) { } } - currentOverlay = currentOverlay->next; + currentOverlay = nextOverlay; } } diff --git a/engines/cruise/saveload.cpp b/engines/cruise/saveload.cpp index d6b2c9ec93..ffda142e66 100644 --- a/engines/cruise/saveload.cpp +++ b/engines/cruise/saveload.cpp @@ -177,12 +177,12 @@ int loadSavegameData(int saveGameIdx) { fileHandle = fopen(buffer, "rb"); if (!fileHandle) { - printInfoBlackBox("Sauvegarde non trouvée..."); + printInfoBlackBox("Savegame not found..."); waitForPlayerInput(); return (-1); } - printInfoBlackBox("Chargement en cours..."); + printInfoBlackBox("Loading in progress..."); fread(saveIdentBuffer, 6, 1, fileHandle); diff --git a/engines/engine.cpp b/engines/engine.cpp index 05e2235cc9..f2b7198510 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -54,7 +54,8 @@ Engine::Engine(OSystem *syst) _eventMan(_system->getEventManager()), _saveFileMan(_system->getSavefileManager()), _targetName(ConfMan.getActiveDomainName()), - _gameDataPath(ConfMan.get("path")) { + _gameDataPath(ConfMan.get("path")), + _pauseLevel(0) { g_engine = this; _autosavePeriod = ConfMan.getInt("autosave_period"); @@ -180,3 +181,23 @@ void Engine::GUIErrorMessage(const Common::String msg) { GUI::MessageDialog dialog(msg); dialog.runModal(); } + +void Engine::pauseEngine(bool pause) { + assert((pause && _pauseLevel >= 0) || (!pause && _pauseLevel)); + + if (pause) + _pauseLevel++; + else + _pauseLevel--; + + if (_pauseLevel == 1) { + pauseEngineIntern(true); + } else if (_pauseLevel == 0) { + pauseEngineIntern(false); + } +} + +void Engine::pauseEngineIntern(bool pause) { + // By default, just (un)pause all digital sounds + _mixer->pauseAll(pause); +} diff --git a/engines/engine.h b/engines/engine.h index 7b40a377ef..f9aeb7718f 100644 --- a/engines/engine.h +++ b/engines/engine.h @@ -56,7 +56,18 @@ protected: const Common::String _gameDataPath; private: + /** + * The autosave interval, given in second. Used by shouldPerformAutoSave. + */ int _autosavePeriod; + + /** + * The pause level, 0 means 'running', a positive value indicates + * how often the engine has been paused (and hence how often it has + * to be un-paused before it resumes running). This makes it possible + * to nest code which pauses the engine. + */ + int _pauseLevel; public: Engine(OSystem *syst); @@ -79,22 +90,49 @@ public: /** Specific for each engine: prepare error string. */ virtual void errorString(const char *buf_input, char *buf_output); + /** + * Return the engine's debugger instance, if any. Used by error() to + * invoke the debugger when a severe error is reported. + */ + virtual GUI::Debugger *getDebugger() { return 0; } + + /** + * Pause or resume the engine. This should stop/resume any audio playback + * and other stuff. Called right before the system runs a global dialog + * (like a global pause, main menu, options or 'confirm exit' dialog). + * + * This is a convenience tracker which automatically keeps track on how + * often the engine has been paused, ensuring that after pausing an engine + * e.g. twice, it has to be unpaused twice before actuallying resuming. + * + * @param pause true to pause the engine, false to resume it + */ + void pauseEngine(bool pause); + + /** + * Return whether the engine is currently paused or not. + */ + bool isPaused() const { return _pauseLevel != 0; } + +public: + + /** Setup the backend's graphics mode. */ void initCommonGFX(bool defaultTo1XScaler); /** On some systems, check if the game appears to be run from CD. */ void checkCD(); - /* Indicate if an autosave should be performed. */ + /** Indicate whether an autosave should be performed. */ bool shouldPerformAutoSave(int lastSaveTime); /** Initialized graphics and shows error message. */ void GUIErrorMessage(const Common::String msg); - + /** - * Return the engine's debugger instance, if any. Used by error() to - * invoke the debugger when a severe error is reported. + * Actual implementation of pauseEngine by subclasses. See there + * for details. */ - virtual GUI::Debugger *getDebugger() { return 0; } + virtual void pauseEngineIntern(bool pause); }; extern Engine *g_engine; diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 9dfbf534d4..1c275185ca 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -757,14 +757,30 @@ static const GOBGameDescription gameDescriptions[] = { { "gob3", "", - AD_ENTRY1("intro.stk", "32b0f57f5ae79a9ae97e8011df38af42"), - UNK_LANG, + AD_ENTRY1s("intro.stk", "32b0f57f5ae79a9ae97e8011df38af42", 157084), + EN_GRB, kPlatformPC, Common::ADGF_NO_FLAGS }, GF_GOB3, "intro" }, + { // Supplied by fac76 in bug report #1742716 + { + "gob3", + "", + { + {"intro.stk", 0, "32b0f57f5ae79a9ae97e8011df38af42", 157084}, + {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, + {NULL, 0, NULL, 0} + }, + EN_GRB, + kPlatformMacintosh, + Common::ADGF_NO_FLAGS + }, + GF_GOB3, + "intro" + }, { { "gob3", diff --git a/engines/gob/game.h b/engines/gob/game.h index 4a1796c6d9..2181d219f2 100644 --- a/engines/gob/game.h +++ b/engines/gob/game.h @@ -48,7 +48,7 @@ public: uint16 funcEnter; uint16 funcLeave; uint16 funcSub; - }; + } PACKED_STRUCT; #define szGame_TotResItem (4 + 2 + 2 + 2) struct TotResItem { @@ -57,7 +57,7 @@ public: int16 size; int16 width; int16 height; - }; + } PACKED_STRUCT; #define szGame_TotResTable (2 + 1) struct TotResTable { @@ -65,7 +65,7 @@ public: byte unknown; TotResItem *items; byte *dataPtr; - }; + } PACKED_STRUCT; #define szGame_ExtItem (4 + 2 + 2 + 2) struct ExtItem { @@ -73,34 +73,34 @@ public: uint16 size; int16 width; // width & 0x7FFF: width, width & 0x8000: pack flag int16 height; // not zero - }; + } PACKED_STRUCT; #define szGame_ExtTable (2 + 1) struct ExtTable { int16 itemsCount; byte unknown; ExtItem* items; - }; + } PACKED_STRUCT; #define szGame_TotTextItem (2 + 2) struct TotTextItem { int16 offset; int16 size; - }; + } PACKED_STRUCT; #define szGame_TotTextTable (2) struct TotTextTable { int16 itemsCount; TotTextItem *items; byte *dataPtr; - }; + } PACKED_STRUCT; struct InputDesc { int16 fontIndex; int16 backColor; int16 frontColor; byte *ptr; - }; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/gob/goblin.h b/engines/gob/goblin.h index 61ac9dff5e..38c19a48d3 100644 --- a/engines/gob/goblin.h +++ b/engines/gob/goblin.h @@ -51,7 +51,7 @@ public: int16 freq; // high/low byte * 100 - frequency int16 repCount; // high/low byte - repeat count int16 sndFrame; - }; + } PACKED_STRUCT; typedef Gob_State *Gob_PState; @@ -90,12 +90,12 @@ public: char multObjIndex; char unk14; char visible; - }; + } PACKED_STRUCT; struct Gob_Pos { char x; char y; - }; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/gob/imd.h b/engines/gob/imd.h index 3d04f18c6d..27d95cd579 100644 --- a/engines/gob/imd.h +++ b/engines/gob/imd.h @@ -41,7 +41,7 @@ public: int16 top; int16 right; int16 bottom; - }; + } PACKED_STRUCT; struct Imd { int16 handle; @@ -65,7 +65,7 @@ public: int32 frameDataSize; int32 vidBufferSize; Video::Color *extraPalette; - }; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index fcf825b4c3..a3277047e7 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -1647,6 +1647,13 @@ bool Inter_v1::o1_keyFunc(OpFuncParams ¶ms) { lastCalled = now; _noBusyWait = false; + // WORKAROUND for bug #1726130: Ween busy-waits in the intro for a counter + // to become 5000. We deliberately slow down busy-waiting, so we shorten + // the counting, too. + if (((_vm->_global->_inter_execPtr - _vm->_game->_totFileData) == 729) && + (VAR(59) < 4000) && !scumm_stricmp(_vm->_game->_curTotFile, "intro5.tot")) + WRITE_VAR(59, 4000); + switch (cmd) { case 0: _vm->_draw->_showCursor &= ~2; diff --git a/engines/gob/map.h b/engines/gob/map.h index 9b45c5c04e..0e0a80aad3 100644 --- a/engines/gob/map.h +++ b/engines/gob/map.h @@ -51,7 +51,7 @@ public: int16 x; int16 y; int16 notWalkable; - }; + } PACKED_STRUCT; #define szMap_ItemPos 3 @@ -59,7 +59,7 @@ public: int8 x; int8 y; int8 orient; - }; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/gob/mult.h b/engines/gob/mult.h index 194126cd8b..edfbb682ea 100644 --- a/engines/gob/mult.h +++ b/engines/gob/mult.h @@ -63,7 +63,7 @@ public: int8 redrawAnimation; int8 redrawLayer; uint8 redrawFrame; - }; + } PACKED_STRUCT; struct Mult_GobState { int16 animation; // . @@ -74,7 +74,7 @@ public: int16 freq; // |- [1+] int8 repCount; // | uint8 speaker; // ' - }; + } PACKED_STRUCT; struct Mult_Object { int32 *pPosX; @@ -104,12 +104,12 @@ public: int16 newTop; int16 newRight; int16 newBottom; - }; + } PACKED_STRUCT; struct Mult_StaticKey { int16 frame; int16 layer; - }; + } PACKED_STRUCT; struct Mult_AnimKey { int16 frame; @@ -117,14 +117,14 @@ public: int16 posX; int16 posY; int16 order; - }; + } PACKED_STRUCT; struct Mult_TextKey { int16 frame; int16 cmd; char unknown[18]; byte script[6]; - }; + } PACKED_STRUCT; struct Mult_PalKey { int16 frame; @@ -133,14 +133,14 @@ public: int16 unknown0; int16 unknown1; int8 subst[16][4]; - }; + } PACKED_STRUCT; struct Mult_PalFadeKey { int16 frame; int16 fade; int16 palIndex; int8 flag; - }; + } PACKED_STRUCT; struct Mult_SndKey { int16 frame; @@ -150,7 +150,7 @@ public: int16 repCount; int16 resId; int16 soundIndex; - }; + } PACKED_STRUCT; struct Mult_ImdKey { int16 frame; @@ -162,7 +162,7 @@ public: int16 lastFrame; int8 palStart; int8 palEnd; - }; + } PACKED_STRUCT; struct Mult_Data { int16 palFadeKeysCount; @@ -212,7 +212,7 @@ public: char *imdFiles; char *somepointer10; // ? byte *execPtr; - }; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/gob/music.cpp b/engines/gob/music.cpp index 6e678c103e..0f38827363 100644 --- a/engines/gob/music.cpp +++ b/engines/gob/music.cpp @@ -268,20 +268,20 @@ void Adlib::setKey(byte voice, byte note, bool on, bool spec) { // 0x3A donne 0x2AF; // 3A // << 7 = 1D00 - // + E000 = FD00 négatif + // + E000 = FD00 negatif // * 19 = xB500 // / 2000 = -2 => Ligne 17h, colonne -1 // 2E // << 7 = 1700 - // + E000 = F700 négatif + // + E000 = F700 negatif // * 19 = x1F00 // / 2000 = short a; short lin; short col; - a = (note << 7) + 0xE000; // Volontairement tronqué + a = (note << 7) + 0xE000; // Volontairement tronque a = (short)((long)a * 25 / 0x2000); if (a < 0) { col = - ((24 - a) / 25); diff --git a/engines/gob/saveload_v3.cpp b/engines/gob/saveload_v3.cpp index 3f8aeb81bd..b376a8a75c 100644 --- a/engines/gob/saveload_v3.cpp +++ b/engines/gob/saveload_v3.cpp @@ -258,7 +258,10 @@ bool SaveLoad_v3::loadScreenshot(int16 dataVar, int32 size, int32 offset) { } in->seek(1040 + varSize * 2); - return loadSprite(*in, size); + + bool success = loadSprite(*in, size); + delete in; + return success; } else warning("Invalid attempt at loading a screenshot (%d, %d, %d, %d)", diff --git a/engines/gob/scenery.h b/engines/gob/scenery.h index 32ff727c46..acb7aecba7 100644 --- a/engines/gob/scenery.h +++ b/engines/gob/scenery.h @@ -38,7 +38,7 @@ public: int16 right; //These are stored in Little Endian format int16 top; //And should be converted by client code when accessed int16 bottom; //i.e. use FROM_LE_16() - }; + } PACKED_STRUCT; struct StaticPlane { int8 pictIndex; @@ -47,13 +47,13 @@ public: int16 destX; int16 destY; int8 transp; - }; + } PACKED_STRUCT; struct StaticLayer { int16 backResId; int16 planeCount; StaticPlane *planes; - }; + } PACKED_STRUCT; // Animations @@ -63,7 +63,7 @@ public: int8 destX; int8 destY; int8 notFinal; - }; + } PACKED_STRUCT; struct AnimLayer { int16 unknown0; @@ -74,7 +74,7 @@ public: int8 transp; int16 framesCount; AnimFramePiece *frames; - }; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/gob/sound.cpp b/engines/gob/sound.cpp index e3a4715920..b47e6795ac 100644 --- a/engines/gob/sound.cpp +++ b/engines/gob/sound.cpp @@ -35,8 +35,6 @@ namespace Gob { -#define FRAC_BITS 16 - void SoundDesc::set(SoundType type, SoundSource src, byte *data, uint32 dSize) { @@ -176,7 +174,6 @@ Snd::Snd(GobEngine *vm) : _vm(vm) { _offset = 0; _offsetFrac = 0; _offsetInc = 0; - _offsetIncFrac = 0; _cur = 0; _last = 0; @@ -325,10 +322,7 @@ void Snd::setSample(SoundDesc &sndDesc, int16 repCount, int16 frequency, _offset = 0; _offsetFrac = 0; - - uint32 incr = (_freq << FRAC_BITS) / _rate; - _offsetInc = incr >> FRAC_BITS; - _offsetIncFrac = incr & ((1UL << FRAC_BITS) - 1); + _offsetInc = (_freq << FRAC_BITS) / _rate; _last = _cur; _cur = _data[0]; @@ -393,9 +387,6 @@ void Snd::checkEndSample() { int Snd::readBuffer(int16 *buffer, const int numSamples) { Common::StackLock slock(_mutex); - int16 val; - uint32 tmp, oldOffset; - for (int i = 0; i < numSamples; i++) { if (!_data) return i; @@ -406,19 +397,18 @@ int Snd::readBuffer(int16 *buffer, const int numSamples) { // Linear interpolation. See sound/rate.cpp - val = (_last + (((_cur - _last) * _offsetFrac + - (1UL << (FRAC_BITS - 1))) >> FRAC_BITS)) << 8; - *buffer++ = (((int32) val) * _fadeVol) >> 16; + int32 val = (_last + (((_cur - _last) * _offsetFrac + + FRAC_HALF) >> FRAC_BITS)) << 8; + *buffer++ = (val * _fadeVol) >> 16; - oldOffset = _offset; - - tmp = _offsetFrac + _offsetIncFrac; - _offset += _offsetInc + (tmp >> FRAC_BITS); - _offsetFrac = tmp & ((1UL << FRAC_BITS) - 1); + _offsetFrac += _offsetInc; - if (oldOffset < _offset) { + // Was there an integral change? + if (fracToInt(_offsetFrac) > 0) { _last = _cur; - _cur = _data[oldOffset]; + _cur = _data[_offset]; + _offset += fracToInt(_offsetFrac); + _offsetFrac &= FRAC_LO_MASK; } if (_fade) { diff --git a/engines/gob/sound.h b/engines/gob/sound.h index 76b9f2b159..15909f5452 100644 --- a/engines/gob/sound.h +++ b/engines/gob/sound.h @@ -27,6 +27,7 @@ #define GOB_SOUND_H #include "common/mutex.h" +#include "common/frac.h" #include "sound/audiostream.h" #include "sound/mixer.h" @@ -175,9 +176,8 @@ protected: int32 _repCount; uint32 _offset; - uint32 _offsetFrac; - uint32 _offsetInc; - uint32 _offsetIncFrac; + frac_t _offsetFrac; + frac_t _offsetInc; int16 _cur; int16 _last; diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp index 0bc87f42d5..6f88a5a993 100644 --- a/engines/gob/video.cpp +++ b/engines/gob/video.cpp @@ -235,7 +235,7 @@ void Video::drawLine(SurfaceDesc *dest, int16 x0, int16 y0, int16 x1, /* * The original's version of the Bresenham Algorithm was a bit "unclean" - * and produced strange edges at 45°, 135°, 225° and 315°, so using the + * and produced strange edges at 45, 135, 225 and 315 degrees, so using the * version found in the Wikipedia article about the * "Bresenham's line algorithm" instead */ diff --git a/engines/gob/video.h b/engines/gob/video.h index faa9555abb..51d02bd219 100644 --- a/engines/gob/video.h +++ b/engines/gob/video.h @@ -85,7 +85,7 @@ public: byte red; byte green; byte blue; - }; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/kyra/gui.cpp b/engines/kyra/gui.cpp index 8cafb54fb8..6fc347158f 100644 --- a/engines/kyra/gui.cpp +++ b/engines/kyra/gui.cpp @@ -230,14 +230,14 @@ int KyraEngine::buttonAmuletCallback(Button *caller) { drawJewelsFadeOutEnd(jewel); _scriptInterpreter->initScript(_scriptClick, _scriptClickData); - _scriptClick->variables[3] = 0; - _scriptClick->variables[6] = jewel; + _scriptClick->regs[3] = 0; + _scriptClick->regs[6] = jewel; _scriptInterpreter->startScript(_scriptClick, 4); while (_scriptInterpreter->validScript(_scriptClick)) _scriptInterpreter->runScript(_scriptClick); - if (_scriptClick->variables[3]) + if (_scriptClick->regs[3]) return 1; _unkAmuletVar = 1; diff --git a/engines/kyra/kyra.cpp b/engines/kyra/kyra.cpp index 249a5f6c21..1664ce144f 100644 --- a/engines/kyra/kyra.cpp +++ b/engines/kyra/kyra.cpp @@ -923,16 +923,16 @@ int KyraEngine::processInputHelper(int xpos, int ypos) { int KyraEngine::clickEventHandler(int xpos, int ypos) { debugC(9, kDebugLevelMain, "KyraEngine::clickEventHandler(%d, %d)", xpos, ypos); _scriptInterpreter->initScript(_scriptClick, _scriptClickData); - _scriptClick->variables[1] = xpos; - _scriptClick->variables[2] = ypos; - _scriptClick->variables[3] = 0; - _scriptClick->variables[4] = _itemInHand; + _scriptClick->regs[1] = xpos; + _scriptClick->regs[2] = ypos; + _scriptClick->regs[3] = 0; + _scriptClick->regs[4] = _itemInHand; _scriptInterpreter->startScript(_scriptClick, 1); while (_scriptInterpreter->validScript(_scriptClick)) _scriptInterpreter->runScript(_scriptClick); - return _scriptClick->variables[3]; + return _scriptClick->regs[3]; } void KyraEngine::updateMousePointer(bool forceUpdate) { @@ -1068,10 +1068,10 @@ void KyraEngine::clickEventHandler2() { Common::Point mouse = getMousePos(); _scriptInterpreter->initScript(_scriptClick, _scriptClickData); - _scriptClick->variables[0] = _currentCharacter->sceneId; - _scriptClick->variables[1] = mouse.x; - _scriptClick->variables[2] = mouse.y; - _scriptClick->variables[4] = _itemInHand; + _scriptClick->regs[0] = _currentCharacter->sceneId; + _scriptClick->regs[1] = mouse.x; + _scriptClick->regs[2] = mouse.y; + _scriptClick->regs[4] = _itemInHand; _scriptInterpreter->startScript(_scriptClick, 6); while (_scriptInterpreter->validScript(_scriptClick)) @@ -1132,9 +1132,9 @@ void KyraEngine::runNpcScript(int func) { debugC(9, kDebugLevelMain, "KyraEngine::runNpcScript(%d)", func); _scriptInterpreter->initScript(_npcScript, _npcScriptData); _scriptInterpreter->startScript(_npcScript, func); - _npcScript->variables[0] = _currentCharacter->sceneId; - _npcScript->variables[4] = _itemInHand; - _npcScript->variables[5] = func; + _npcScript->regs[0] = _currentCharacter->sceneId; + _npcScript->regs[4] = _itemInHand; + _npcScript->regs[5] = func; while (_scriptInterpreter->validScript(_npcScript)) _scriptInterpreter->runScript(_npcScript); diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp index 319845c22c..2425444be1 100644 --- a/engines/kyra/resource.cpp +++ b/engines/kyra/resource.cpp @@ -195,15 +195,22 @@ uint8 *Resource::fileData(const char *file, uint32 *size) const { if (!(*cur)->isOpen()) continue; - uint32 fileSize = (*cur)->getFileSize(fileHash); - if (!fileSize) - continue; + uint8* result = (*cur)->getFile(fileHash); + + if (result) { + uint32 fileSize = (*cur)->getFileSize(fileHash); + + if (!fileSize) + continue; + + if (size) + *size = fileSize; + + return result; + } - if (size) - *size = fileSize; - return (*cur)->getFile(fileHash); } } @@ -221,13 +228,15 @@ bool Resource::getFileHandle(const char *file, uint32 *size, Common::File &fileh if (!(*start)->isOpen()) continue; - *size = (*start)->getFileSize(fileHash); + if ((*start)->getFileHandle(fileHash, filehandle)) { + + *size = (*start)->getFileSize(fileHash); - if (!(*size)) - continue; + if (!(*size)) + continue; - if ((*start)->getFileHandle(fileHash, filehandle)) return true; + } } return false; diff --git a/engines/kyra/scene.cpp b/engines/kyra/scene.cpp index 2ba1870fcd..a92fd9ce7c 100644 --- a/engines/kyra/scene.cpp +++ b/engines/kyra/scene.cpp @@ -450,8 +450,8 @@ void KyraEngine::startSceneScript(int brandonAlive) { _scriptInterpreter->unloadScript(_scriptClickData); _scriptInterpreter->loadScript(fileNameBuffer, _scriptClickData, &_opcodes); _scriptInterpreter->startScript(_scriptClick, 0); - _scriptClick->variables[0] = _currentCharacter->sceneId; - _scriptClick->variables[7] = brandonAlive; + _scriptClick->regs[0] = _currentCharacter->sceneId; + _scriptClick->regs[7] = brandonAlive; while (_scriptInterpreter->validScript(_scriptClick)) _scriptInterpreter->runScript(_scriptClick); @@ -620,8 +620,8 @@ void KyraEngine::initSceneData(int facing, int unk1, int brandonAlive) { if (unk1 && brandonAlive == 0) moveCharacterToPos(0, facing, xpos2, ypos2); - _scriptClick->variables[4] = _itemInHand; - _scriptClick->variables[7] = brandonAlive; + _scriptClick->regs[4] = _itemInHand; + _scriptClick->regs[7] = brandonAlive; _scriptInterpreter->startScript(_scriptClick, 3); while (_scriptInterpreter->validScript(_scriptClick)) _scriptInterpreter->runScript(_scriptClick); @@ -852,7 +852,7 @@ void KyraEngine::initSceneScreen(int brandonAlive) { if (!_scriptInterpreter->startScript(_scriptClick, 2)) error("Could not start script function 2 of scene script"); - _scriptClick->variables[7] = brandonAlive; + _scriptClick->regs[7] = brandonAlive; while (_scriptInterpreter->validScript(_scriptClick)) _scriptInterpreter->runScript(_scriptClick); diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 02eb1c9ea7..641a034eab 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -504,7 +504,12 @@ void Screen::copyToPage0(int y, int h, uint8 page, uint8 *seqBuf) { dstPage += SCREEN_W; } addDirtyRect(0, y, SCREEN_W, h); - clearOverlayRect(0, 0, y, SCREEN_W, h); + // This would remove the text in the end sequence of + // the FM-Towns version. + // Since this method is just used for the Seqplayer + // this shouldn't be a problem anywhere else, so it's + // safe to disable the call here. + //clearOverlayRect(0, 0, y, SCREEN_W, h); } void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage, int flags) { diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp index c2ec984d5c..b43cd3b471 100644 --- a/engines/kyra/script.cpp +++ b/engines/kyra/script.cpp @@ -49,12 +49,12 @@ ScriptHelper::ScriptHelper(KyraEngine *vm) : _vm(vm) { COMMAND(c1_push), // 0x04 COMMAND(c1_push), - COMMAND(c1_pushVar), + COMMAND(c1_pushReg), COMMAND(c1_pushBPNeg), COMMAND(c1_pushBPAdd), // 0x08 COMMAND(c1_popRetOrPos), - COMMAND(c1_popVar), + COMMAND(c1_popReg), COMMAND(c1_popBPNeg), COMMAND(c1_popBPAdd), // 0x0C @@ -324,8 +324,8 @@ void ScriptHelper::c1_push(ScriptState* script) { script->stack[--script->sp] = _parameter; } -void ScriptHelper::c1_pushVar(ScriptState* script) { - script->stack[--script->sp] = script->variables[_parameter]; +void ScriptHelper::c1_pushReg(ScriptState* script) { + script->stack[--script->sp] = script->regs[_parameter]; } void ScriptHelper::c1_pushBPNeg(ScriptState* script) { @@ -359,8 +359,8 @@ void ScriptHelper::c1_popRetOrPos(ScriptState* script) { } } -void ScriptHelper::c1_popVar(ScriptState* script) { - script->variables[_parameter] = script->stack[script->sp++]; +void ScriptHelper::c1_popReg(ScriptState* script) { + script->regs[_parameter] = script->stack[script->sp++]; } void ScriptHelper::c1_popBPNeg(ScriptState* script) { diff --git a/engines/kyra/script.h b/engines/kyra/script.h index dfca7700a1..5e43039110 100644 --- a/engines/kyra/script.h +++ b/engines/kyra/script.h @@ -70,8 +70,8 @@ struct ScriptState { int16 retValue; uint16 bp; uint16 sp; - int16 variables[30]; - int16 stack[61]; + int16 regs[30]; // VM registers + int16 stack[61]; // VM stack }; class ScriptHelper { @@ -99,7 +99,7 @@ protected: typedef void (ScriptHelper::*CommandProc)(ScriptState*); struct CommandEntry { CommandProc proc; - const char* desc; + const char *desc; }; const CommandEntry *_commands; @@ -109,11 +109,11 @@ private: void c1_pushRetOrPos(ScriptState*); void c1_push(ScriptState*); //void c1_push(); same as 03 - void c1_pushVar(ScriptState*); + void c1_pushReg(ScriptState*); void c1_pushBPNeg(ScriptState*); void c1_pushBPAdd(ScriptState*); void c1_popRetOrPos(ScriptState*); - void c1_popVar(ScriptState*); + void c1_popReg(ScriptState*); void c1_popBPNeg(ScriptState*); void c1_popBPAdd(ScriptState*); void c1_addSP(ScriptState*); diff --git a/engines/kyra/script_v1.cpp b/engines/kyra/script_v1.cpp index 8e604b972b..87123222fb 100644 --- a/engines/kyra/script_v1.cpp +++ b/engines/kyra/script_v1.cpp @@ -1379,8 +1379,8 @@ int KyraEngine_v1::o1_waitForConfirmationMouseClick(ScriptState *script) { processButtonList(_buttonList); _skipFlag = false; Common::Point mouse = getMousePos(); - script->variables[1] = mouse.x; - script->variables[2] = mouse.y; + script->regs[1] = mouse.x; + script->regs[2] = mouse.y; return 0; } diff --git a/engines/kyra/sound_digital.cpp b/engines/kyra/sound_digital.cpp index e2f92c9925..72d19ffd32 100644 --- a/engines/kyra/sound_digital.cpp +++ b/engines/kyra/sound_digital.cpp @@ -29,7 +29,7 @@ namespace Kyra { -// Thanks to Torbjörn Andersson (eriktorbjorn) for his aud player on which +// Thanks to Torbjorn Andersson (eriktorbjorn) for his aud player on which // this code is based on // TODO: cleanup of whole AUDStream diff --git a/engines/lure/res_struct.h b/engines/lure/res_struct.h index 59581b9c7d..b5e4aef724 100644 --- a/engines/lure/res_struct.h +++ b/engines/lure/res_struct.h @@ -47,7 +47,7 @@ struct VersionStructure { uint16 id; byte vMajor; byte vMinor; -}; +} PACKED_STRUCT; struct FileEntry { uint16 id; @@ -55,7 +55,7 @@ struct FileEntry { byte sizeExtension; uint16 size; uint16 offset; -}; +} PACKED_STRUCT; struct HotspotResource { uint16 hotspotId; @@ -91,7 +91,7 @@ struct HotspotResource { uint16 delayCtr; byte flags2; byte hdrFlags; -}; +} PACKED_STRUCT; struct HotspotAnimResource { uint16 animRecordId; @@ -105,18 +105,18 @@ struct HotspotAnimResource { uint8 downFrame; uint8 leftFrame; uint8 rightFrame; -}; +} PACKED_STRUCT; struct MovementResource { uint16 frameNumber; int16 xChange; int16 yChange; -}; +} PACKED_STRUCT; struct RoomRect { int16 xs, xe; int16 ys, ye; -}; +} PACKED_STRUCT; struct RoomResource { uint16 roomNumber; @@ -133,7 +133,7 @@ struct RoomResource { uint8 areaFlag; RoomRect walkBounds; uint16 numExits; -}; +} PACKED_STRUCT; struct RoomExitResource { int16 xs, xe, ys, ye; @@ -141,12 +141,12 @@ struct RoomExitResource { uint8 newRoom; uint8 direction; int16 newRoomX, newRoomY; -}; +} PACKED_STRUCT; struct HotspotOverrideResource { uint16 hotspotId; int16 xs, xe, ys, ye; -}; +} PACKED_STRUCT; struct RoomExitHotspotResource { uint16 hotspotId; @@ -154,7 +154,7 @@ struct RoomExitHotspotResource { int16 ys, ye; uint16 cursorNum; uint16 destRoomNumber; -}; +} PACKED_STRUCT; struct RoomExitJoinResource { uint16 hotspot1Id; @@ -168,41 +168,41 @@ struct RoomExitJoinResource { uint8 h2OpenSound; uint8 h2CloseSound; byte blocked; -}; +} PACKED_STRUCT; struct HotspotActionResource { byte action; uint16 sequenceOffset; -}; +} PACKED_STRUCT; struct TalkHeaderResource { uint16 hotspotId; uint16 offset; -}; +} PACKED_STRUCT; struct TalkDataHeaderResource { uint16 recordId; uint16 listOffset; uint16 responsesOffset; -}; +} PACKED_STRUCT; struct TalkDataResource { uint16 preSequenceId; uint16 descId; uint16 postSequenceId; -}; +} PACKED_STRUCT; struct TalkResponseResource { uint16 sequenceId1; uint16 sequenceId2; uint16 sequenceId3; -}; +} PACKED_STRUCT; struct RoomExitCoordinateResource { int16 x; int16 y; uint16 roomNumber; -}; +} PACKED_STRUCT; #define ROOM_EXIT_COORDINATES_NUM_ENTRIES 6 #define ROOM_EXIT_COORDINATES_NUM_ROOMS 52 @@ -210,20 +210,20 @@ struct RoomExitCoordinateResource { struct RoomExitCoordinateEntryResource { uint8 roomIndex[ROOM_EXIT_COORDINATES_NUM_ROOMS]; RoomExitCoordinateResource entries[ROOM_EXIT_COORDINATES_NUM_ENTRIES]; -}; +} PACKED_STRUCT; #define MAX_SCHEDULE_ENTRY_PARAMS 5 struct CharacterScheduleResource { uint16 action; uint16 params[MAX_SCHEDULE_ENTRY_PARAMS]; -}; +} PACKED_STRUCT; struct RoomExitIndexedHotspotResource { uint8 roomNumber; uint8 hotspotIndex; uint16 hotspotId; -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/parallaction/animation.cpp b/engines/parallaction/animation.cpp index 33caaa1b58..d4f538c451 100644 --- a/engines/parallaction/animation.cpp +++ b/engines/parallaction/animation.cpp @@ -166,15 +166,19 @@ void jobDisplayAnimations(void *parm, Job *j) { if ((v18->_flags & kFlagsActive) && ((v18->_flags & kFlagsRemove) == 0)) { v14._width = v18->width(); v14._height = v18->height(); - v14._data0 = v18->getFrameData(v18->_frame); -// v14._data1 = v18->_cnv->field_8[v18->_frame]; + + int16 frame = CLIP((int)v18->_frame, 0, v18->getFrameNum()-1); + + v14._data0 = v18->getFrameData(frame); +// v14._data1 = v18->_cnv->field_8[frame]; if (v18->_flags & kFlagsNoMasked) _si = 3; else _si = _vm->_gfx->queryMask(v18->_top + v18->height()); - debugC(9, kDebugLocation, "jobDisplayAnimations(%s, x:%i, y:%i, z:%i, w:%i, h:%i, %p)", v18->_label._text, v18->_left, v18->_top, _si, v14._width, v14._height, v14._data0); + debugC(9, kDebugLocation, "jobDisplayAnimations(%s, x:%i, y:%i, z:%i, w:%i, h:%i, f:%i/%i, %p)", v18->_label._text, v18->_left, v18->_top, _si, v14._width, v14._height, + frame, v18->getFrameNum(), v14._data0); _vm->_gfx->blitCnv(&v14, v18->_left, v18->_top, _si, Gfx::kBitBack); } diff --git a/engines/parallaction/archive.cpp b/engines/parallaction/archive.cpp index b678b6df3c..9eef3f44e9 100644 --- a/engines/parallaction/archive.cpp +++ b/engines/parallaction/archive.cpp @@ -37,7 +37,7 @@ namespace Parallaction { // Amiga version of Nippon Safes, and one archive ('fr') in the Amiga Demo of // Nippon Safes used different internal offsets than all the other archives. // -// When an archive is opened in the Amiga demo, its size is checked against +// When an archive is opened in the Amiga demo, its size is checked against // SIZEOF_SMALL_ARCHIVE to detect when the smaller archive is used. // // When an archive is opened in Amiga multi-lingual version, the header is @@ -72,6 +72,8 @@ void Archive::open(const char *file) { if (!_archive.open(path)) error("archive '%s' not found", path); + _archiveName = file; + bool isSmallArchive = false; if (_vm->getPlatform() == Common::kPlatformAmiga) { if (_vm->getFeatures() & GF_DEMO) { @@ -105,8 +107,12 @@ void Archive::close() { resetArchivedFile(); _archive.close(); + _archiveName.clear(); } +Common::String Archive::name() const { + return _archiveName; +} bool Archive::openArchivedFile(const char *filename) { debugC(3, kDebugDisk, "Archive::openArchivedFile(%s)", filename); diff --git a/engines/parallaction/callables.cpp b/engines/parallaction/callables.cpp index 1154250ffa..be92ca1daa 100644 --- a/engines/parallaction/callables.cpp +++ b/engines/parallaction/callables.cpp @@ -253,7 +253,7 @@ void _c_endComment(void *param) { _vm->_gfx->floodFill(Gfx::kBitFront, r, 1); _vm->_gfx->setFont(kFontDialogue); - _vm->_gfx->displayWrappedString(_vm->_location._endComment, 3, 5, 130, 0); + _vm->_gfx->displayWrappedString(_vm->_location._endComment, 3, 5, 0, 130); _vm->_gfx->updateScreen(); uint32 di = 0; diff --git a/engines/parallaction/defs.h b/engines/parallaction/defs.h index d7dc3388e7..c41130670e 100644 --- a/engines/parallaction/defs.h +++ b/engines/parallaction/defs.h @@ -28,6 +28,7 @@ #include "common/stdafx.h" #include "common/list.h" +#include "common/rect.h" namespace Parallaction { diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index b3de3e5da3..7d2224164a 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -46,10 +46,6 @@ namespace Parallaction { #define ANSWER_CHARACTER_X 10 #define ANSWER_CHARACTER_Y 80 - -void enterDialogue(); -void exitDialogue(); - int16 selectAnswer(Question *q, StaticCnv*); int16 getHoverAnswer(int16 x, int16 y, Question *q); @@ -62,110 +58,109 @@ int16 _answerBalloonH[10] = { 0 }; Dialogue *Parallaction::parseDialogue(Script &script) { // printf("parseDialogue()\n"); - uint16 num_questions = 0; - uint16 v50[20]; - Table _questions_names(20); - Question *_questions[20]; + uint16 numQuestions = 0; - for (uint16 _si = 0; _si < 20; _si++) { - v50[_si] = 0; - } + Dialogue *dialogue = new Dialogue; + + Table forwards(20); fillBuffers(script, true); while (scumm_stricmp(_tokens[0], "enddialogue")) { if (scumm_stricmp(_tokens[0], "Question")) continue; - _questions[num_questions] = new Dialogue; - Dialogue *vB4 = _questions[num_questions]; + Question *question = new Question; + dialogue->_questions[numQuestions] = question; - _questions_names.addData(_tokens[1]); + forwards.addData(_tokens[1]); - vB4->_text = parseDialogueString(script); -// printf("Question: '%s'\n", vB4->_text); + question->_text = parseDialogueString(script); fillBuffers(script, true); - vB4->_mood = atoi(_tokens[0]); + question->_mood = atoi(_tokens[0]); - uint16 _di = 0; + uint16 numAnswers = 0; fillBuffers(script, true); while (scumm_stricmp(_tokens[0], "endquestion")) { // parse answers - vB4->_answers[_di] = new Answer; + Answer *answer = new Answer; + question->_answers[numAnswers] = answer; if (_tokens[1][0]) { - Table* v60 = _localFlagNames; - uint16 v56 = 1; + Table* flagNames; + uint16 token; if (!scumm_stricmp(_tokens[1], "global")) { - v56 = 2; - v60 = _globalTable; - vB4->_answers[_di]->_yesFlags |= kFlagsGlobal; + token = 2; + flagNames = _globalTable; + answer->_yesFlags |= kFlagsGlobal; + } else { + token = 1; + flagNames = _localFlagNames; } do { - if (!scumm_strnicmp(_tokens[v56], "no", 2)) { - byte _al = v60->lookup(_tokens[v56]+2); - vB4->_answers[_di]->_noFlags |= 1 << (_al - 1); + if (!scumm_strnicmp(_tokens[token], "no", 2)) { + byte _al = flagNames->lookup(_tokens[token]+2); + answer->_noFlags |= 1 << (_al - 1); } else { - byte _al = v60->lookup(_tokens[v56]); - vB4->_answers[_di]->_yesFlags |= 1 << (_al - 1); + byte _al = flagNames->lookup(_tokens[token]); + answer->_yesFlags |= 1 << (_al - 1); } - v56++; + token++; - } while (!scumm_stricmp(_tokens[v56++], "|")); + } while (!scumm_stricmp(_tokens[token++], "|")); } - vB4->_answers[_di]->_text = parseDialogueString(script); - -// printf("answer[%i]: '%s'\n", _di, vB4->_answers[_di]); + answer->_text = parseDialogueString(script); fillBuffers(script, true); - vB4->_answers[_di]->_mood = atoi(_tokens[0]); - vB4->_answers[_di]->_following._name = parseDialogueString(script); + answer->_mood = atoi(_tokens[0]); + answer->_following._name = parseDialogueString(script); fillBuffers(script, true); if (!scumm_stricmp(_tokens[0], "commands")) { - parseCommands(script, vB4->_answers[_di]->_commands); + parseCommands(script, answer->_commands); fillBuffers(script, true); } - _di++; + numAnswers++; } fillBuffers(script, true); - num_questions++; + numQuestions++; } - for (uint16 _si = 0; _si <num_questions; _si++) { + // link questions + byte v50[20]; + memset(v50, 0, 20); - for (uint16 v5A = 0; v5A < 5; v5A++) { - if (_questions[_si]->_answers[v5A] == 0) continue; + for (uint16 i = 0; i < numQuestions; i++) { + Question *question = dialogue->_questions[i]; - int16 v58 = _questions_names.lookup(_questions[_si]->_answers[v5A]->_following._name); - free(_questions[_si]->_answers[v5A]->_following._name); + for (uint16 j = 0; j < NUM_ANSWERS; j++) { + Answer *answer = question->_answers[j]; + if (answer == 0) continue; - if (v58 == -1) { - _questions[_si]->_answers[v5A]->_following._question = 0; - } else { - _questions[_si]->_answers[v5A]->_following._question = _questions[v58-1]; + int16 index = forwards.lookup(answer->_following._name); + free(answer->_following._name); + + if (index == -1) + answer->_following._question = 0; + else + answer->_following._question = dialogue->_questions[index - 1]; - if (v50[v58]) { - _questions[_si]->_answers[v5A]->_mood |= 0x10; - } - v50[v58] = 1; - } } } - return _questions[0]; + return dialogue; } @@ -183,7 +178,7 @@ char *Parallaction::parseDialogueString(Script &script) { } while (strlen(vD0) == 0); vD0[strlen(vD0)-1] = '\0'; // deletes the trailing '0xA' - // this is critical for Gfx::displayBalloonString to work properly + // this is critical for Gfx::displayWrappedString to work properly char *vCC = (char*)malloc(strlen(vD0)+1); strcpy(vCC, vD0); @@ -191,23 +186,71 @@ char *Parallaction::parseDialogueString(Script &script) { return vCC; } -uint16 Parallaction::askDialoguePassword(Dialogue *q, StaticCnv *face) { +class DialogueManager { + + Parallaction *_vm; + SpeakData *_data; + Dialogue *_dialogue; + + bool _askPassword; + + bool isNpc; + Cnv *_questioner; + Cnv *_answerer; + + Question *_q; + +public: + DialogueManager(Parallaction *vm, SpeakData *data) : _vm(vm), _data(data) { + _dialogue = _data->_dialogue; + isNpc = scumm_stricmp(_data->_name, "yourself") && _data->_name[0] != '\0'; + _questioner = isNpc ? _vm->_disk->loadTalk(_data->_name) : _vm->_char._talk; + _answerer = _vm->_char._talk; + } + + ~DialogueManager() { + if (isNpc) { + delete _questioner; + } + } + + void run(); + +protected: + void clear() { + _vm->_gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + } + + void displayQuestion(); + bool displayAnswers(); + bool displayAnswer(uint16 i); + + uint16 getAnswer(); + int16 selectAnswer(); + uint16 askPassword(); + int16 getHoverAnswer(int16 x, int16 y); + +}; + +uint16 DialogueManager::askPassword() { debugC(1, kDebugDialogue, "checkDialoguePassword()"); char password[100]; uint16 passwordLen = 0; while (true) { + clear(); + strcpy(password, "......."); - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); Common::Rect r(_answerBalloonW[0], _answerBalloonH[0]); r.moveTo(_answerBalloonX[0], _answerBalloonY[0]); - _gfx->drawBalloon(r, 1); - _gfx->displayWrappedString(q->_answers[0]->_text, _answerBalloonX[0], _answerBalloonY[0], MAX_BALLOON_WIDTH, 3); - _gfx->flatBlitCnv(face, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y, Gfx::kBitFront); - _gfx->displayBalloonString(_answerBalloonX[0] + 5, _answerBalloonY[0] + _answerBalloonH[0] - 15, "> ", 0); + _vm->_gfx->drawBalloon(r, 1); + _vm->_gfx->displayWrappedString(_q->_answers[0]->_text, _answerBalloonX[0], _answerBalloonY[0], 3, MAX_BALLOON_WIDTH); + _vm->_gfx->flatBlitCnv(_answerer, 0, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y, Gfx::kBitFront); + _vm->_gfx->displayString(_answerBalloonX[0] + 5, _answerBalloonY[0] + _answerBalloonH[0] - 15, "> ", 0); + _vm->_gfx->updateScreen(); Common::Event e; while (e.kbd.ascii != Common::KEYCODE_RETURN && passwordLen < MAX_PASSWORD_LENGTH) { @@ -223,15 +266,15 @@ uint16 Parallaction::askDialoguePassword(Dialogue *q, StaticCnv *face) { passwordLen++; password[passwordLen] = '\0'; - _gfx->displayBalloonString(_answerBalloonX[0] + 5, _answerBalloonY[0] + _answerBalloonH[0] - 15, password, 0); - _gfx->updateScreen(); + _vm->_gfx->displayString(_answerBalloonX[0] + 10, _answerBalloonY[0] + _answerBalloonH[0] - 15, password, 0); + _vm->_gfx->updateScreen(); g_system->delayMillis(20); } - if ((!scumm_stricmp(_characterName, _doughName) && !scumm_strnicmp(password, "1732461", 7)) || - (!scumm_stricmp(_characterName, _donnaName) && !scumm_strnicmp(password, "1622", 4)) || - (!scumm_stricmp(_characterName, _dinoName) && !scumm_strnicmp(password, "179", 3))) { + if ((!scumm_stricmp(_vm->_characterName, _doughName) && !scumm_strnicmp(password, "1732461", 7)) || + (!scumm_stricmp(_vm->_characterName, _donnaName) && !scumm_strnicmp(password, "1622", 4)) || + (!scumm_stricmp(_vm->_characterName, _dinoName) && !scumm_strnicmp(password, "179", 3))) { break; @@ -243,165 +286,135 @@ uint16 Parallaction::askDialoguePassword(Dialogue *q, StaticCnv *face) { } -bool _askPassword; -bool Parallaction::displayAnswer(Dialogue *q, uint16 i) { - uint32 v28 = _localFlags[_currentLocationIndex]; - if (q->_answers[i]->_yesFlags & kFlagsGlobal) +bool DialogueManager::displayAnswer(uint16 i) { + + uint32 v28 = _localFlags[_vm->_currentLocationIndex]; + if (_q->_answers[i]->_yesFlags & kFlagsGlobal) v28 = _commandFlags | kFlagsGlobal; // display suitable answers - if (((q->_answers[i]->_yesFlags & v28) == q->_answers[i]->_yesFlags) && ((q->_answers[i]->_noFlags & ~v28) == q->_answers[i]->_noFlags)) { + if (((_q->_answers[i]->_yesFlags & v28) == _q->_answers[i]->_yesFlags) && ((_q->_answers[i]->_noFlags & ~v28) == _q->_answers[i]->_noFlags)) { - _gfx->getStringExtent(q->_answers[i]->_text, MAX_BALLOON_WIDTH, &_answerBalloonW[i], &_answerBalloonH[i]); + _vm->_gfx->getStringExtent(_q->_answers[i]->_text, MAX_BALLOON_WIDTH, &_answerBalloonW[i], &_answerBalloonH[i]); Common::Rect r(_answerBalloonW[i], _answerBalloonH[i]); r.moveTo(_answerBalloonX[i], _answerBalloonY[i]); - _gfx->drawBalloon(r, 1); + _vm->_gfx->drawBalloon(r, 1); _answerBalloonY[i+1] = 10 + _answerBalloonY[i] + _answerBalloonH[i]; - _askPassword = _gfx->displayWrappedString(q->_answers[i]->_text, _answerBalloonX[i], _answerBalloonY[i], MAX_BALLOON_WIDTH, 3); + _askPassword = _vm->_gfx->displayWrappedString(_q->_answers[i]->_text, _answerBalloonX[i], _answerBalloonY[i], 3, MAX_BALLOON_WIDTH); return true; } + _answerBalloonY[i+1] = _answerBalloonY[i]; + _answerBalloonY[i] = SKIPPED_ANSWER; + return false; } -bool Parallaction::displayAnswers(Dialogue *q) { +bool DialogueManager::displayAnswers() { bool displayed = false; uint16 i = 0; - while (i < NUM_ANSWERS && q->_answers[i]) { - if (displayAnswer(q, i)) { + while (i < NUM_ANSWERS && _q->_answers[i]) { + if (displayAnswer(i)) displayed = true; - } else { - _answerBalloonY[i+1] = _answerBalloonY[i]; - _answerBalloonY[i] = SKIPPED_ANSWER; - } + i++; } - _gfx->updateScreen(); + _vm->_gfx->updateScreen(); return displayed; } -void Parallaction::displayQuestion(Dialogue *q, Cnv *cnv) { +void DialogueManager::displayQuestion() { int16 w = 0, h = 0; - if (!scumm_stricmp(q->_text, "NULL")) return; - - StaticCnv face; - face._width = cnv->_width; - face._height = cnv->_height; - face._data0 = cnv->getFramePtr(q->_mood & 0xF); - face._data1 = NULL; // cnv->field_8[v60->_mood & 0xF]; + if (!scumm_stricmp(_q->_text, "NULL")) return; - _gfx->flatBlitCnv(&face, QUESTION_CHARACTER_X, QUESTION_CHARACTER_Y, Gfx::kBitFront); - _gfx->getStringExtent(q->_text, MAX_BALLOON_WIDTH, &w, &h); + _vm->_gfx->flatBlitCnv(_questioner, _q->_mood & 0xF, QUESTION_CHARACTER_X, QUESTION_CHARACTER_Y, Gfx::kBitFront); + _vm->_gfx->getStringExtent(_q->_text, MAX_BALLOON_WIDTH, &w, &h); Common::Rect r(w, h); r.moveTo(QUESTION_BALLOON_X, QUESTION_BALLOON_Y); - _gfx->drawBalloon(r, q->_mood & 0x10); - _gfx->displayWrappedString(q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, MAX_BALLOON_WIDTH, 0); - _gfx->updateScreen(); + _vm->_gfx->drawBalloon(r, _q->_mood & 0x10); + _vm->_gfx->displayWrappedString(_q->_text, QUESTION_BALLOON_X, QUESTION_BALLOON_Y, 0, MAX_BALLOON_WIDTH); + _vm->_gfx->updateScreen(); waitUntilLeftClick(); - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + clear(); return; } -uint16 Parallaction::getDialogueAnswer(Dialogue *q, Cnv *cnv) { +uint16 DialogueManager::getAnswer() { uint16 answer = 0; - StaticCnv face; - face._width = cnv->_width; - face._height = cnv->_height; - face._data0 = cnv->getFramePtr(0); - face._data1 = NULL; // cnv->field_8[0]; - - _gfx->flatBlitCnv(&face, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y, Gfx::kBitFront); - if (_askPassword == false) { - answer = selectAnswer(q, &face); + answer = selectAnswer(); } else { - answer = askDialoguePassword(q, &face); + answer = askPassword(); } - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); // erase answer screen + clear(); debugC(1, kDebugDialogue, "runDialogue: user selected answer #%i", answer); return answer; } -void Parallaction::runDialogue(SpeakData *data) { - debugC(1, kDebugDialogue, "runDialogue: starting dialogue '%s'", data->_name); - - enterDialogue(); - - _gfx->setFont(kFontDialogue); - - bool isNpc = scumm_stricmp(data->_name, "yourself") && data->_name[0] != '\0'; - Cnv *face = isNpc ? _disk->loadTalk(data->_name) : _char._talk; +void DialogueManager::run() { _askPassword = false; CommandList *cmdlist = NULL; - uint16 answer; - Dialogue *q = data->_dialogue; - while (q) { + _q = _dialogue->_questions[0]; + int16 answer; + + while (_q) { answer = 0; - displayQuestion(q, face); - if (q->_answers[0] == NULL) break; + displayQuestion(); + if (_q->_answers[0] == NULL) break; _answerBalloonY[0] = 10; - if (scumm_stricmp(q->_answers[0]->_text, "NULL")) { - if (!displayAnswers(q)) break; - answer = getDialogueAnswer(q, _char._talk); - cmdlist = &q->_answers[answer]->_commands; + if (scumm_stricmp(_q->_answers[0]->_text, "NULL")) { + if (!displayAnswers()) break; + answer = getAnswer(); + cmdlist = &_q->_answers[answer]->_commands; } - q = q->_answers[answer]->_following._question; + _q = _q->_answers[answer]->_following._question; } - debugC(1, kDebugDialogue, "runDialogue: out of dialogue loop"); - - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); - - if (isNpc) { - delete face; - } + clear(); - exitDialogue(); if (cmdlist) - runCommands(*cmdlist); - - return; + _vm->runCommands(*cmdlist); } -int16 Parallaction::selectAnswer(Question *q, StaticCnv *cnv) { +int16 DialogueManager::selectAnswer() { int16 numAvailableAnswers = 0; int16 _si = 0; int16 _di = 0; int16 i = 0; - for (; q->_answers[i]; i++) { + for (; _q->_answers[i]; i++) { if (_answerBalloonY[i] == SKIPPED_ANSWER) continue; _di = i; @@ -410,11 +423,9 @@ int16 Parallaction::selectAnswer(Question *q, StaticCnv *cnv) { _answerBalloonY[i] = 2000; if (numAvailableAnswers == 1) { - _gfx->displayWrappedString(q->_answers[_di]->_text, _answerBalloonX[_di], _answerBalloonY[_di], MAX_BALLOON_WIDTH, 0); - cnv->_data0 = _char._talk->getFramePtr(q->_answers[_di]->_mood & 0xF); -// cnv->_data1 = _char._talk->field_8[q->_answers[_di]->_mood & 0xF]; - _gfx->flatBlitCnv(cnv, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y, Gfx::kBitFront); - _gfx->updateScreen(); + _vm->_gfx->displayWrappedString(_q->_answers[_di]->_text, _answerBalloonX[_di], _answerBalloonY[_di], 0, MAX_BALLOON_WIDTH); + _vm->_gfx->flatBlitCnv(_answerer, _q->_answers[_di]->_mood & 0xF, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y, Gfx::kBitFront); + _vm->_gfx->updateScreen(); waitUntilLeftClick(); return _di; } @@ -424,20 +435,18 @@ int16 Parallaction::selectAnswer(Question *q, StaticCnv *cnv) { _mouseButtons = kMouseNone; while (_mouseButtons != kMouseLeftUp) { - updateInput(); - _si = getHoverAnswer(_mousePos.x, _mousePos.y, q); + _vm->updateInput(); + _si = getHoverAnswer(_vm->_mousePos.x, _vm->_mousePos.y); if (_si != v2) { if (v2 != -1) - _gfx->displayWrappedString(q->_answers[v2]->_text, _answerBalloonX[v2], _answerBalloonY[v2], MAX_BALLOON_WIDTH, 3); + _vm->_gfx->displayWrappedString(_q->_answers[v2]->_text, _answerBalloonX[v2], _answerBalloonY[v2], 3, MAX_BALLOON_WIDTH); - _gfx->displayWrappedString(q->_answers[_si]->_text, _answerBalloonX[_si], _answerBalloonY[_si], MAX_BALLOON_WIDTH, 0); - cnv->_data0 = _char._talk->getFramePtr(q->_answers[_si]->_mood & 0xF); -// cnv->_data1 = _char._talk->field_8[q->_answers[_si]->_mood & 0xF]; - _gfx->flatBlitCnv(cnv, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y, Gfx::kBitFront); + _vm->_gfx->displayWrappedString(_q->_answers[_si]->_text, _answerBalloonX[_si], _answerBalloonY[_si], 0, MAX_BALLOON_WIDTH); + _vm->_gfx->flatBlitCnv(_answerer, _q->_answers[_si]->_mood & 0xF, ANSWER_CHARACTER_X, ANSWER_CHARACTER_Y, Gfx::kBitFront); } - _gfx->updateScreen(); + _vm->_gfx->updateScreen(); g_system->delayMillis(30); v2 = _si; } @@ -449,13 +458,13 @@ int16 Parallaction::selectAnswer(Question *q, StaticCnv *cnv) { // // finds out which answer is currently selected // -int16 getHoverAnswer(int16 x, int16 y, Question *q) { +int16 DialogueManager::getHoverAnswer(int16 x, int16 y) { int16 top = 1000; int16 bottom = 1000; for (int16 _si = 0; _si < NUM_ANSWERS; _si++) { - if (q->_answers[_si] == NULL) break; + if (_q->_answers[_si] == NULL) break; if (_answerBalloonY[_si] != SKIPPED_ANSWER) { top = _answerBalloonY[_si]; @@ -476,21 +485,21 @@ int16 getHoverAnswer(int16 x, int16 y, Question *q) { } -void Parallaction::enterDialogue() { - showCursor(false); - - return; -} +void Parallaction::runDialogue(SpeakData *data) { + debugC(1, kDebugDialogue, "runDialogue: starting dialogue '%s'", data->_name); -// rebuilds inventory -// -void Parallaction::exitDialogue() { + _gfx->setFont(kFontDialogue); - refreshInventory(_characterName); + if (_vm->getPlatform() == Common::kPlatformPC) + showCursor(false); + DialogueManager man(this, data); + man.run(); + + refreshInventory(_characterName); showCursor(true); - + return; } @@ -503,12 +512,8 @@ Answer::Answer() { } Answer::~Answer() { - if (_mood & 0x10) - delete _following._question; - if (_text) free(_text); - } Question::Question() { diff --git a/engines/parallaction/disk.cpp b/engines/parallaction/disk.cpp index 7b11fbbbed..2e6d9e4820 100644 --- a/engines/parallaction/disk.cpp +++ b/engines/parallaction/disk.cpp @@ -26,6 +26,8 @@ #include "common/stdafx.h" #include "graphics/iff.h" +#include "graphics/surface.h" + #include "parallaction/parallaction.h" @@ -90,8 +92,10 @@ void Disk::errorFileNotFound(const char *s) { } -void Disk::selectArchive(const char *name) { - _resArchive.open(name); +Common::String Disk::selectArchive(const Common::String& name) { + Common::String oldName = _resArchive.name(); + _resArchive.open(name.c_str()); + return oldName; } void Disk::setLanguage(uint16 language) { @@ -691,33 +695,106 @@ AmigaDisk::~AmigaDisk() { #define NUM_PLANES 5 -// FIXME: no mask is loaded -void AmigaDisk::unpackBitmap(byte *dst, byte *src, uint16 numFrames, uint16 planeSize) { +/* + unpackFrame transforms images from 5-bitplanes format to + 8-bit color-index mode +*/ +void AmigaDisk::unpackFrame(byte *dst, byte *src, uint16 planeSize) { byte s0, s1, s2, s3, s4, mask, t0, t1, t2, t3, t4; - for (uint32 i = 0; i < numFrames; i++) { - for (uint32 j = 0; j < planeSize; j++) { - s0 = src[j]; - s1 = src[j+planeSize]; - s2 = src[j+planeSize*2]; - s3 = src[j+planeSize*3]; - s4 = src[j+planeSize*4]; - - for (uint32 k = 0; k < 8; k++) { - mask = 1 << (7 - k); - t0 = (s0 & mask ? 1 << 0 : 0); - t1 = (s1 & mask ? 1 << 1 : 0); - t2 = (s2 & mask ? 1 << 2 : 0); - t3 = (s3 & mask ? 1 << 3 : 0); - t4 = (s4 & mask ? 1 << 4 : 0); - *dst++ = t0 | t1 | t2 | t3 | t4; + for (uint32 j = 0; j < planeSize; j++) { + s0 = src[j]; + s1 = src[j+planeSize]; + s2 = src[j+planeSize*2]; + s3 = src[j+planeSize*3]; + s4 = src[j+planeSize*4]; + + for (uint32 k = 0; k < 8; k++) { + mask = 1 << (7 - k); + t0 = (s0 & mask ? 1 << 0 : 0); + t1 = (s1 & mask ? 1 << 1 : 0); + t2 = (s2 & mask ? 1 << 2 : 0); + t3 = (s3 & mask ? 1 << 3 : 0); + t4 = (s4 & mask ? 1 << 4 : 0); + *dst++ = t0 | t1 | t2 | t3 | t4; + } + + } + +} + +/* + patchFrame applies DLTA data (dlta) to specified buffer (dst) +*/ +void AmigaDisk::patchFrame(byte *dst, byte *dlta, uint16 bytesPerPlane, uint16 height) { + + uint32 *dataIndex = (uint32*)dlta; + uint32 *ofslenIndex = (uint32*)dlta + 8; + + uint16 *base = (uint16*)dlta; + uint16 wordsPerLine = bytesPerPlane >> 1; + + for (uint j = 0; j < NUM_PLANES; j++) { + uint16 *dst16 = (uint16*)(dst + j * bytesPerPlane * height); + + uint16 *data = base + READ_BE_UINT32(dataIndex); + dataIndex++; + uint16 *ofslen = base + READ_BE_UINT32(ofslenIndex); + ofslenIndex++; + + while (*ofslen != 0xFFFF) { + + uint16 ofs = READ_BE_UINT16(ofslen); + ofslen++; + uint16 size = READ_BE_UINT16(ofslen); + ofslen++; + + while (size > 0) { + dst16[ofs] ^= *data++; + ofs += wordsPerLine; + size--; } } - src += planeSize * NUM_PLANES; } + +} + +// FIXME: no mask is loaded +void AmigaDisk::unpackBitmap(byte *dst, byte *src, uint16 numFrames, uint16 bytesPerPlane, uint16 height) { + + byte *baseFrame = src; + byte *tempBuffer = 0; + + uint16 planeSize = bytesPerPlane * height; + + for (uint32 i = 0; i < numFrames; i++) { + if (READ_BE_UINT32(src) == MKID_BE('DLTA')) { + + uint size = READ_BE_UINT32(src + 4); + + if (tempBuffer == 0) + tempBuffer = (byte*)malloc(planeSize * NUM_PLANES); + + memcpy(tempBuffer, baseFrame, planeSize * NUM_PLANES); + + patchFrame(tempBuffer, src + 8, bytesPerPlane, height); + unpackFrame(dst, tempBuffer, planeSize); + + src += (size + 8); + dst += planeSize * 8; + } else { + unpackFrame(dst, src, planeSize); + src += planeSize * NUM_PLANES; + dst += planeSize * 8; + } + } + + if (tempBuffer) + free(tempBuffer); + } StaticCnv* AmigaDisk::makeStaticCnv(Common::SeekableReadStream &stream) { @@ -737,7 +814,7 @@ StaticCnv* AmigaDisk::makeStaticCnv(Common::SeekableReadStream &stream) { uint32 decsize = width * height; byte *data = (byte*)calloc(decsize, 1); - unpackBitmap(data, buf, 1, height * bytesPerPlane); + unpackBitmap(data, buf, 1, bytesPerPlane, height); free(buf); @@ -767,7 +844,7 @@ Cnv* AmigaDisk::makeCnv(Common::SeekableReadStream &stream) { uint32 decsize = numFrames * width * height; byte *data = (byte*)calloc(decsize, 1); - unpackBitmap(data, buf, numFrames, height * bytesPerPlane); + unpackBitmap(data, buf, numFrames, bytesPerPlane, height); free(buf); diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index bfef6d81df..14ea4f0e16 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -60,6 +60,7 @@ protected: uint32 _fileCursor; uint32 _fileEndOffset; + Common::String _archiveName; char _archiveDir[MAX_ARCHIVE_ENTRIES][32]; uint32 _archiveLenghts[MAX_ARCHIVE_ENTRIES]; uint32 _archiveOffsets[MAX_ARCHIVE_ENTRIES]; @@ -74,9 +75,11 @@ protected: public: Archive(); - void open(const char *file); + void open(const char* file); void close(); + Common::String name() const; + bool openArchivedFile(const char *name); void closeArchivedFile(); @@ -103,7 +106,7 @@ public: Disk(Parallaction *vm); virtual ~Disk(); - void selectArchive(const char *name); + Common::String selectArchive(const Common::String &name); void setLanguage(uint16 language); virtual Script* loadLocation(const char *name) = 0; @@ -163,7 +166,9 @@ class AmigaDisk : public Disk { protected: Cnv* makeCnv(Common::SeekableReadStream &stream); StaticCnv* makeStaticCnv(Common::SeekableReadStream &stream); - void unpackBitmap(byte *dst, byte *src, uint16 numFrames, uint16 planeSize); + void patchFrame(byte *dst, byte *dlta, uint16 bytesPerPlane, uint16 height); + void unpackFrame(byte *dst, byte *src, uint16 planeSize); + void unpackBitmap(byte *dst, byte *src, uint16 numFrames, uint16 bytesPerPlane, uint16 height); Common::SeekableReadStream *openArchivedFile(const char* name, bool errorOnFileNotFound = false); Font *createFont(const char *name, Common::SeekableReadStream &stream); void loadMask(const char *name); diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index aab35f8562..59645381b6 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -306,8 +306,6 @@ void Gfx::floodFill(Gfx::Buffers buffer, const Common::Rect& r, byte color) { d += SCREEN_WIDTH; } - if (buffer == kBitFront) updateScreen(); - return; } @@ -350,8 +348,6 @@ void Gfx::flatBlit(const Common::Rect& r, byte *data, Gfx::Buffers buffer) { d += (SCREEN_WIDTH - q.width()); } - if (buffer == kBitFront) updateScreen(); - return; } @@ -389,8 +385,6 @@ void Gfx::blit(const Common::Rect& r, uint16 z, byte *data, Gfx::Buffers buffer) d += (SCREEN_WIDTH - q.right + q.left); } - if (buffer == kBitFront) updateScreen(); - return; } @@ -480,6 +474,18 @@ void Gfx::setMousePointer(int16 index) { // // Cnv management // +void Gfx::flatBlitCnv(Cnv *cnv, uint16 frame, int16 x, int16 y, Gfx::Buffers buffer) { + + StaticCnv scnv; + + scnv._width = cnv->_width; + scnv._height = cnv->_height; + scnv._data0 = cnv->getFramePtr(frame); + scnv._data1 = NULL; // _questioner->field_8[v60->_mood & 0xF]; + + flatBlitCnv(&scnv, x, y, buffer); +} + void Gfx::flatBlitCnv(StaticCnv *cnv, int16 x, int16 y, Gfx::Buffers buffer) { Common::Rect r(cnv->_width, cnv->_height); r.moveTo(x, y); @@ -577,30 +583,19 @@ void Gfx::makeCnvFromString(StaticCnv *cnv, char *text) { } -void Gfx::displayString(uint16 x, uint16 y, const char *text) { - assert(_font == _fonts[kFontMenu]); - +void Gfx::displayString(uint16 x, uint16 y, const char *text, byte color) { byte *dst = _buffers[kBitFront] + x + y*SCREEN_WIDTH; - _font->setColor(1); + _font->setColor(color); _font->drawString(dst, SCREEN_WIDTH, text); } void Gfx::displayCenteredString(uint16 y, const char *text) { uint16 x = (SCREEN_WIDTH - getStringWidth(text)) / 2; - displayString(x, y, text); -} - -void Gfx::displayBalloonString(uint16 x, uint16 y, const char *text, byte color) { - assert(_font == _fonts[kFontDialogue]); - - byte *dst = _buffers[kBitFront] + x + y*SCREEN_WIDTH; - - _font->setColor(color); - _font->drawString(dst, SCREEN_WIDTH, text); + displayString(x, y, text, 1); } -bool Gfx::displayWrappedString(char *text, uint16 x, uint16 y, uint16 maxwidth, byte color) { -// printf("Gfx::displayWrappedString(%s, %i, %i, %i, %i)...", text, x, y, maxwidth, color); +bool Gfx::displayWrappedString(char *text, uint16 x, uint16 y, byte color, uint16 wrapwidth) { +// printf("Gfx::displayWrappedString(%s, %i, %i, %i, %i)...", text, x, y, color, wrapwidth); uint16 lines = 0; bool rv = false; @@ -613,10 +608,10 @@ bool Gfx::displayWrappedString(char *text, uint16 x, uint16 y, uint16 maxwidth, while (strlen(text) > 0) { - text = parseNextToken(text, token, 40, " "); + text = parseNextToken(text, token, 40, " ", true); linewidth += getStringWidth(token); - if (linewidth > maxwidth) { + if (linewidth > wrapwidth) { // wrap line lines++; rx = x + 10; // x @@ -630,7 +625,7 @@ bool Gfx::displayWrappedString(char *text, uint16 x, uint16 y, uint16 maxwidth, if (!scumm_stricmp(token, "%p")) { rv = true; } else - displayBalloonString(rx, ry, token, color); + displayString(rx, ry, token, color); rx += getStringWidth(token) + getStringWidth(" "); linewidth += getStringWidth(" "); @@ -658,7 +653,7 @@ void Gfx::getStringExtent(char *text, uint16 maxwidth, int16* width, int16* heig while (strlen(text) != 0) { - text = parseNextToken(text, token, 40, " "); + text = parseNextToken(text, token, 40, " ", true); w += getStringWidth(token); if (w > maxwidth) { diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 1f0c467293..d535d3cf05 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -67,7 +67,7 @@ struct PaletteFxRange { byte _first; byte _last; -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING @@ -165,10 +165,9 @@ public: // dialogue and text void drawBalloon(const Common::Rect& r, uint16 arg_8); - void displayBalloonString(uint16 x, uint16 y, const char *text, byte color); - void displayString(uint16 x, uint16 y, const char *text); + void displayString(uint16 x, uint16 y, const char *text, byte color); void displayCenteredString(uint16 y, const char *text); - bool displayWrappedString(char *text, uint16 x, uint16 y, uint16 maxwidth, byte color); + bool displayWrappedString(char *text, uint16 x, uint16 y, byte color, uint16 wrapwidth = SCREEN_WIDTH); uint16 getStringWidth(const char *text); void getStringExtent(char *text, uint16 maxwidth, int16* width, int16* height); @@ -204,6 +203,8 @@ public: // DOS version didn't make use of it, but it is probably needed for Amiga stuff. void flatBlitCnv(StaticCnv *cnv, int16 x, int16 y, Gfx::Buffers buffer); void blitCnv(StaticCnv *cnv, int16 x, int16 y, uint16 z, Gfx::Buffers buffer); + void flatBlitCnv(Cnv *cnv, uint16 frame, int16 x, int16 y, Gfx::Buffers buffer); + // palette void setPalette(Palette palette, uint32 first = FIRST_BASE_COLOR, uint32 num = BASE_PALETTE_COLORS); diff --git a/engines/parallaction/location.cpp b/engines/parallaction/location.cpp index 4d8efa3255..3c54460692 100644 --- a/engines/parallaction/location.cpp +++ b/engines/parallaction/location.cpp @@ -38,6 +38,7 @@ void Parallaction::parseLocation(const char *filename) { _gfx->setFont(kFontLabel); Script *_locationScript = _disk->loadLocation(filename); + _hasLocationSound = false; fillBuffers(*_locationScript, true); while (scumm_stricmp(_tokens[0], "ENDLOCATION")) { @@ -140,16 +141,15 @@ void Parallaction::parseLocation(const char *filename) { parseAnimation(*_locationScript, _animations, _tokens[1]); } if (!scumm_stricmp(_tokens[0], "SOUND")) { - strcpy(_soundFile, _tokens[1]); + if (getPlatform() == Common::kPlatformAmiga) { + strcpy(_locationSound, _tokens[1]); + _hasLocationSound = true; + } } if (!scumm_stricmp(_tokens[0], "MUSIC")) { if (getPlatform() == Common::kPlatformAmiga) _soundMan->setMusicFile(_tokens[1]); } - if (!scumm_stricmp(_tokens[0], "SOUND")) { -// if (getPlatform() == Common::kPlatformAmiga) -// _soundMan->loadSfx(_tokens[1], atoi(_tokens[2])); - } fillBuffers(*_locationScript, true); } @@ -182,14 +182,14 @@ void Parallaction::freeLocation() { if (_localFlagNames) delete _localFlagNames; - + // HACK: prevents leakage. A routine like this // should allocate memory at all, though. if ((_engineFlags & kEngineQuit) == 0) { _localFlagNames = new Table(120); _localFlagNames->addData("visited"); } - + _location._walkNodes.clear(); // TODO (LIST): helperNode should be rendered useless by the use of a Common::List<> @@ -379,11 +379,11 @@ void Parallaction::changeLocation(char *location) { runJobs(); _gfx->swapBuffers(); } - + if (_location._comment) { doLocationEnterTransition(); } - + runJobs(); _gfx->swapBuffers(); @@ -392,7 +392,8 @@ void Parallaction::changeLocation(char *location) { runCommands(_location._aCommands); } -// _soundMan->playSfx(0); + if (_hasLocationSound) + _soundMan->playSfx(_locationSound, 0, true); debugC(1, kDebugLocation, "changeLocation() done"); @@ -416,7 +417,7 @@ void Parallaction::doLocationEnterTransition() { debugC(3, kDebugLocation, "skipping location transition"); return; // visited } - + byte pal[PALETTE_SIZE]; _gfx->buildBWPalette(pal); _gfx->setPalette(pal); @@ -437,7 +438,7 @@ void Parallaction::doLocationEnterTransition() { _gfx->floodFill(Gfx::kBitFront, r, 0); r.grow(-1); _gfx->floodFill(Gfx::kBitFront, r, 1); - _gfx->displayWrappedString(_location._comment, 3, 5, 130, 0); + _gfx->displayWrappedString(_location._comment, 3, 5, 0, 130); _gfx->updateScreen(); waitUntilLeftClick(); diff --git a/engines/parallaction/menu.cpp b/engines/parallaction/menu.cpp index b1b6fb44c8..427f24a467 100644 --- a/engines/parallaction/menu.cpp +++ b/engines/parallaction/menu.cpp @@ -201,7 +201,7 @@ uint16 Menu::chooseLanguage() { _vm->_gfx->setPalette(_vm->_gfx->_palette); _vm->_gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); - _vm->_gfx->displayString(60, 30, "SELECT LANGUAGE"); + _vm->_gfx->displayString(60, 30, "SELECT LANGUAGE", 1); _vm->_gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); _vm->_gfx->copyScreen(Gfx::kBitBack, Gfx::kBit2); @@ -287,10 +287,10 @@ uint16 Menu::selectGame() { if (_si != 0) { // load a game - _vm->_gfx->displayString(60, 30, loadGameMsg[_language]); + _vm->_gfx->displayString(60, 30, loadGameMsg[_language], 1); } else { // new game - _vm->_gfx->displayString(60, 30, newGameMsg[_language]); + _vm->_gfx->displayString(60, 30, newGameMsg[_language], 1); } _vm->_gfx->updateScreen(); @@ -353,7 +353,7 @@ void Menu::selectCharacter() { askPassword = false; _di = 0; - _vm->_gfx->displayString(60, 30, introMsg1[_language]); // displays message + _vm->_gfx->displayString(60, 30, introMsg1[_language], 1); // displays message _vm->_gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); _donna_points = 0; @@ -415,7 +415,7 @@ void Menu::selectCharacter() { if (askPassword == false) break; _vm->_gfx->copyScreen(Gfx::kBit2, Gfx::kBitFront); - _vm->_gfx->displayString(60, 30, introMsg2[_language]); + _vm->_gfx->displayString(60, 30, introMsg2[_language], 1); _vm->_gfx->updateScreen(); g_system->delayMillis(2000); diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index e0291c5a2a..c830b575a9 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -84,7 +84,6 @@ Command * _forwardedCommands[20] = { char _forwardedAnimationNames[20][20]; uint16 _numForwards = 0; -char _soundFile[20]; uint32 _commandFlags = 0; uint16 _introSarcData3 = 200; @@ -158,6 +157,8 @@ int Parallaction::init() { _localFlagNames = NULL; initResources(); + _hasLocationSound = false; + _skipMenu = false; _transCurrentHoverItem = 0; @@ -369,6 +370,9 @@ void Parallaction::runGame() { if (_location._comment) doLocationEnterTransition(); + if (_hasLocationSound) + _soundMan->playSfx(_locationSound, 0, true); + changeCursor(kCursorArrow); if (_location._aCommands.size() > 0) @@ -759,10 +763,13 @@ void Parallaction::changeCharacter(const char *name) { // character for sanity before memory is freed freeCharacter(); - _disk->selectArchive((_vm->getPlatform() == Common::kPlatformAmiga) ? "disk0" : "disk1"); + Common::String oldArchive = _disk->selectArchive((_vm->getFeatures() & GF_LANG_MULT) ? "disk1" : "disk0"); _vm->_char._ani._cnv = _disk->loadFrames(fullName); if (!IS_DUMMY_CHARACTER(name)) { + if (_vm->getPlatform() == Common::kPlatformAmiga && (_vm->getFeatures() & GF_LANG_MULT)) + _disk->selectArchive("disk0"); + _vm->_char._head = _disk->loadHead(baseName); _vm->_char._talk = _disk->loadTalk(baseName); _vm->_char._objs = _disk->loadObjects(baseName); @@ -774,6 +781,9 @@ void Parallaction::changeCharacter(const char *name) { if (!(getFeatures() & GF_DEMO)) parseLocation("common"); } + + if (!oldArchive.empty()) + _disk->selectArchive(oldArchive); } strcpy(_characterName1, fullName); diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 38db16ce99..561b15acc9 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -27,8 +27,7 @@ #define PARALLACTION_H #include "common/str.h" -#include "gui/dialog.h" -#include "gui/widget.h" + #include "engines/engine.h" @@ -62,7 +61,7 @@ enum { enum { GF_DEMO = 1 << 0, GF_LANG_EN = 1 << 1, - GF_LANG_FR = 1 << 2, + GF_LANG_FR = 1 << 2, GF_LANG_DE = 1 << 3, GF_LANG_IT = 1 << 4, GF_LANG_MULT = 1 << 5 @@ -177,7 +176,6 @@ extern uint32 _localFlags[]; extern Command *_forwardedCommands[]; extern char _forwardedAnimationNames[][20]; extern uint16 _numForwards; -extern char _soundFile[]; extern char _slideText[][40]; extern uint16 _introSarcData3; // sarcophagus stuff to be saved extern uint16 _introSarcData2; // sarcophagus stuff to be saved @@ -398,7 +396,7 @@ protected: // data bool _skipMenu; bool _mouseHidden; - + // input-only InputData _input; bool _actionAfterWalk; // actived when the character needs to move before taking an action @@ -417,6 +415,9 @@ protected: // data Common::String _saveFileName; + bool _hasLocationSound; + char _locationSound[50]; + protected: // members bool detectGame(void); @@ -461,15 +462,6 @@ protected: // members void freeCharacter(); - uint16 askDialoguePassword(Dialogue *q, StaticCnv *face); - bool displayAnswer(Dialogue *q, uint16 i); - bool displayAnswers(Dialogue *q); - void displayQuestion(Dialogue *q, Cnv *cnv); - uint16 getDialogueAnswer(Dialogue *q, Cnv *cnv); - int16 selectAnswer(Question *q, StaticCnv *cnv); - void enterDialogue(); - void exitDialogue(); - int addInventoryItem(uint16 item); void dropItem(uint16 item); int16 pickupItem(Zone *z); @@ -480,33 +472,6 @@ protected: // members // FIXME: remove global extern Parallaction *_vm; -class SaveLoadChooser : public GUI::Dialog { - typedef Common::String String; - typedef Common::StringList StringList; -protected: - GUI::ListWidget *_list; - GUI::ButtonWidget *_chooseButton; - GUI::GraphicsWidget *_gfxWidget; - GUI::StaticTextWidget *_date; - GUI::StaticTextWidget *_time; - GUI::StaticTextWidget *_playtime; - GUI::ContainerWidget *_container; - Parallaction *_vm; - - uint8 _fillR, _fillG, _fillB; - -public: - SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction *engine); - ~SaveLoadChooser(); - - virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); - const String &getResultString() const; - void setList(const StringList& list); - int runModal(); - - virtual void reflowLayout(); -}; - } // namespace Parallaction diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp index f044e6c3c7..44aae6c1cc 100644 --- a/engines/parallaction/parser.cpp +++ b/engines/parallaction/parser.cpp @@ -119,24 +119,72 @@ void clearTokens() { } -// looks for next token in a string // -// scans 's' until one of the stop-chars in 'brk' is found -// builds a token and return the part of the string which hasn't been parsed - -char *parseNextToken(char *s, char *tok, uint16 count, const char *brk) { - - while (*s != '\0') { +// Scans 's' until one of the stop-chars in 'brk' is found, building a token. +// If the routine encounters quotes, it will extract the contained text and +// make a proper token. When scanning inside quotes, 'brk' is ignored and +// only newlines are considered stop-chars. +// +// The routine returns the unparsed portion of the input string 's'. +// +char *parseNextToken(char *s, char *tok, uint16 count, const char *brk, bool ignoreQuotes) { + + enum STATES { NORMAL, QUOTED }; + + STATES state = NORMAL; + + char *t = s; + + while (count > 0) { + + switch (state) { + case NORMAL: + if (*s == '\0') { + *tok = '\0'; + return s; + } + + if (strchr(brk, *s)) { + *tok = '\0'; + return ++s; + } + + if (*s == '"') { + if (ignoreQuotes) { + *tok++ = *s++; + count--; + } else { + state = QUOTED; + s++; + } + } else { + *tok++ = *s++; + count--; + } + break; - if (brk[0] == *s) break; - if (brk[1] == *s) break; - if (brk[2] == *s) break; + case QUOTED: + if (*s == '\0') { + *tok = '\0'; + return s; + } + if (*s == '"' || *s == '\n' || *s == '\t') { + *tok = '\0'; + return ++s; + } + + *tok++ = *s++; + count--; + break; + } - *tok++ = *s++; } *tok = '\0'; - return s; + warning("token was truncated from line '%s'", t); + + return tok; + } uint16 fillTokens(char* line) { @@ -144,15 +192,6 @@ uint16 fillTokens(char* line) { uint16 i = 0; while (strlen(line) > 0 && i < 20) { line = parseNextToken(line, _tokens[i], 40, " \t\n"); - if (_tokens[i][0] == '"' && _tokens[i][strlen(_tokens[i]) - 1] != '"') { - - line = parseNextToken(line, _tokens[i+1], 40, "\""); - strcat(_tokens[i], _tokens[i+1]); - _tokens[i][0] = ' '; - line++; - - } - line = Common::ltrim(line); i++; } diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index e27095bd16..aa3929a52c 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -33,7 +33,7 @@ namespace Parallaction { uint16 fillBuffers(Common::SeekableReadStream &stream, bool errorOnEOF = false); -char *parseNextToken(char *s, char *tok, uint16 count, const char *brk); +char *parseNextToken(char *s, char *tok, uint16 count, const char *brk, bool ignoreQuotes = false); extern char _tokens[][40]; diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp index f1dc53539d..2a9431ef94 100644 --- a/engines/parallaction/saveload.cpp +++ b/engines/parallaction/saveload.cpp @@ -26,6 +26,7 @@ #include "common/stdafx.h" #include "common/savefile.h" +#include "gui/dialog.h" #include "gui/widget.h" #include "gui/ListWidget.h" #include "gui/message.h" @@ -48,6 +49,37 @@ namespace Parallaction { extern char _gameNames[][20]; + +class SaveLoadChooser : public GUI::Dialog { + typedef Common::String String; + typedef Common::StringList StringList; +protected: + GUI::ListWidget *_list; + GUI::ButtonWidget *_chooseButton; + GUI::GraphicsWidget *_gfxWidget; + GUI::StaticTextWidget *_date; + GUI::StaticTextWidget *_time; + GUI::StaticTextWidget *_playtime; + GUI::ContainerWidget *_container; + Parallaction *_vm; + + uint8 _fillR, _fillG, _fillB; + +public: + SaveLoadChooser(const String &title, const String &buttonLabel, Parallaction *engine); + ~SaveLoadChooser(); + + virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); + const String &getResultString() const; + void setList(const StringList& list); + int runModal(); + + virtual void reflowLayout(); +}; + + + + void Parallaction::doLoadGame(uint16 slot) { _introSarcData3 = 200; diff --git a/engines/parallaction/zone.cpp b/engines/parallaction/zone.cpp index 7d74a6a59f..d9bd36a1f5 100644 --- a/engines/parallaction/zone.cpp +++ b/engines/parallaction/zone.cpp @@ -216,22 +216,13 @@ void Parallaction::parseZoneTypeBlock(Script &script, Zone *z) { strcpy(vC8, _tokens[1]); - StaticCnv vE0; u->door->_cnv = _disk->loadFrames(vC8); - - vE0._width = u->door->_cnv->_width; - vE0._height = u->door->_cnv->_height; - uint16 _ax = (z->_flags & kFlagsClosed ? 0 : 1); - vE0._data0 = u->door->_cnv->getFramePtr(_ax); - -// _ax = (z->_flags & kFlagsClosed ? 0 : 1); -// vE0._data1 = doorcnv->field_8[_ax]; - u->door->_background = (byte*)malloc(vE0._width*vE0._height); + u->door->_background = (byte*)malloc(u->door->_cnv->_width * u->door->_cnv->_height); _gfx->backupDoorBackground(u->door, z->_left, z->_top); - _gfx->flatBlitCnv(&vE0, z->_left, z->_top, Gfx::kBitBack); + _gfx->flatBlitCnv(u->door->_cnv, _ax, z->_left, z->_top, Gfx::kBitBack); } if (!scumm_stricmp(_tokens[0], "startpos")) { @@ -304,21 +295,15 @@ void Parallaction::parseZoneTypeBlock(Script &script, Zone *z) { void Parallaction::displayCharacterComment(ExamineData *data) { if (data->_description == NULL) return; - StaticCnv v3C; - v3C._width = _char._talk->_width; - v3C._height = _char._talk->_height; - v3C._data0 = _char._talk->getFramePtr(0); - v3C._data1 = NULL; //_talk->field_8[0]; - _gfx->setFont(kFontDialogue); - _gfx->flatBlitCnv(&v3C, 190, 80, Gfx::kBitFront); + _gfx->flatBlitCnv(_char._talk, 0, 190, 80, Gfx::kBitFront); int16 v26, v28; _gfx->getStringExtent(data->_description, 130, &v28, &v26); Common::Rect r(v28, v26); r.moveTo(140, 10); _gfx->drawBalloon(r, 0); - _gfx->displayWrappedString(data->_description, 140, 10, 130, 0); + _gfx->displayWrappedString(data->_description, 140, 10, 0, 130); _gfx->updateScreen(); @@ -359,7 +344,7 @@ void Parallaction::displayItemComment(ExamineData *data) { r.moveTo(0, 90); _gfx->drawBalloon(r, 0); _gfx->flatBlitCnv(_vm->_char._head, 100, 152, Gfx::kBitFront); - _gfx->displayWrappedString(data->_description, 0, 90, 130, 0); + _gfx->displayWrappedString(data->_description, 0, 90, 0, 130); jobEraseAnimations((void*)1, NULL); _gfx->updateScreen(); @@ -441,10 +426,8 @@ void jobToggleDoor(void *parm, Job *j) { uint16 _ax = (z->_flags & kFlagsClosed ? 0 : 1); - v14._data0 = z->u.door->_cnv->getFramePtr(_ax); - - _vm->_gfx->flatBlitCnv(&v14, z->_left, z->_top, Gfx::kBitBack); - _vm->_gfx->flatBlitCnv(&v14, z->_left, z->_top, Gfx::kBit2); + _vm->_gfx->flatBlitCnv(z->u.door->_cnv, _ax, z->_left, z->_top, Gfx::kBitBack); + _vm->_gfx->flatBlitCnv(z->u.door->_cnv, _ax, z->_left, z->_top, Gfx::kBit2); } count++; diff --git a/engines/parallaction/zone.h b/engines/parallaction/zone.h index 9cc0fd6767..634a1364aa 100644 --- a/engines/parallaction/zone.h +++ b/engines/parallaction/zone.h @@ -68,7 +68,8 @@ enum ZoneFlags { }; -#define NUM_ANSWERS 5 +#define NUM_QUESTIONS 20 +#define NUM_ANSWERS 5 struct Command; struct Question; @@ -97,7 +98,9 @@ struct Question { ~Question(); }; -typedef Question Dialogue; +struct Dialogue { + Question *_questions[NUM_QUESTIONS]; +}; struct GetData { // size = 24 uint32 _icon; diff --git a/engines/saga/actor.cpp b/engines/saga/actor.cpp index e0e9415cab..d7882a78fd 100644 --- a/engines/saga/actor.cpp +++ b/engines/saga/actor.cpp @@ -268,6 +268,8 @@ Actor::Actor(SagaEngine *vm) : _vm(vm) { _pathRect.top = _vm->getDisplayInfo().pathStartY; _pathRect.bottom = _vm->_scene->getHeight(); + _showActors = true; + // Get actor resource file context _actorContext = _vm->_resource->getContext(GAME_RESOURCEFILE); if (_actorContext == NULL) { @@ -1130,7 +1132,7 @@ void Actor::handleSpeech(int msec) { } if (_activeSpeech.stringsCount == 0) { - _vm->_script->wakeUpThreadsDelayed(kWaitTypeSpeech, ticksToMSec(kScriptTimeTicksPerSecond / 3)); + _vm->_script->wakeUpThreadsDelayed(kWaitTypeSpeech, _vm->ticksToMSec(kScriptTimeTicksPerSecond / 3)); } return; @@ -1808,6 +1810,10 @@ void Actor::drawActors() { return; } + if (!_showActors) { + return; + } + CommonObjectOrderList::iterator drawOrderIterator; CommonObjectDataPointer drawObject; int frameNumber; @@ -2349,6 +2355,11 @@ void Actor::simulSpeech(const char *string, uint16 *actorIds, int actorIdsCount, } void Actor::abortAllSpeeches() { + // WORKAROUND: Don't abort speeches in scene 31 (tree with beehive). This prevents the + // making fire animation from breaking + if (_vm->getGameType() == GType_ITE && _vm->_scene->currentSceneNumber() == 31) + return; + abortSpeech(); if (_vm->_script->_abortEnabled) diff --git a/engines/saga/actor.h b/engines/saga/actor.h index 1557abffb9..b9ec62337c 100644 --- a/engines/saga/actor.h +++ b/engines/saga/actor.h @@ -612,6 +612,8 @@ public: void freeObjList(); void loadObjList(int objectCount, int objectsResourceID); + void showActors(bool flag) { _showActors = flag; } + /* uint16 _currentFrameIndex; void frameTest() { @@ -712,6 +714,7 @@ private: int _xCellCount; int _yCellCount; Rect _pathRect; + bool _showActors; PathDirectionData *_pathDirectionList; int _pathDirectionListCount; diff --git a/engines/saga/animation.cpp b/engines/saga/animation.cpp index 59c3339c9b..d29fc6ebe6 100644 --- a/engines/saga/animation.cpp +++ b/engines/saga/animation.cpp @@ -445,6 +445,18 @@ void Anim::play(uint16 animId, int vectorTime, bool playing) { if (anim->completed < anim->cycles) { frame = anim->currentFrame; + + // WORKAROUND for a buggy animation in IHNM. Animation 0 in scene 67 (the mob of angry prisoners) should + // start from frame 0, not frame 1. Frame 0 is the background of the animation (the mob of prisoners), whereas + // the rest of the frames are their animated arms. Therefore, in order for the prisoners to appear correctly, + // frame 0 should be displayed as the first frame, but anim->currentframe is set to 1, which means that the + // prisoners will never be shown. In the original, the prisoners (first frame in the animation) are shown a + // bit after the animation is started (which is wrong again, but not that apparent), whereas in ScummVM the + // first frame is never shown. Therefore, make sure that for this animation, frame 0 is shown first + if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 4 && + _vm->_scene->currentSceneNumber() == 67 && animId == 0 && anim->completed == 1) + frame = 0; + // FIXME: if start > 0, then this works incorrectly decodeFrame(anim, anim->frameOffsets[frame], displayBuffer, _vm->getDisplayWidth() * _vm->getDisplayHeight()); _vm->_frameCount++; diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h index 631a1a4e83..da06255a82 100644 --- a/engines/saga/detection_tables.h +++ b/engines/saga/detection_tables.h @@ -481,6 +481,37 @@ static const SAGAGameDescription gameDescriptions[] = { ITEMacPatch_Files, }, + // Inherit the earth - MAC CD Wyrmkeep version (compressed sound) + { + { + "ite", + "Wyrmkeep CD", + { + {"ite.rsc", GAME_RESOURCEFILE, "4f7fa11c5175980ed593392838523060", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "adf1f46c1d0589083996a7060c798ad0", -1}, + {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, + {"inherit the earth voices.cmp",GAME_VOICEFILE, NULL, -1}, + {"music.cmp", GAME_MUSICFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformMacintosh, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_MACCD, + GF_BIG_ENDIAN_DATA | GF_WYRMKEEP | GF_CD_FX | GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITEWINDEMO_GameFonts), + ITEWINDEMO_GameFonts, + &ITEMACCD_GameSound, + &ITEMACCD_GameSound, + &ITEMACCD_GameMusic, + ARRAYSIZE(ITEMacPatch_Files), + ITEMacPatch_Files, + }, + // Inherit the earth - Linux Demo version // Note: it should be before GID_ITE_WINDEMO2 version { @@ -640,6 +671,42 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, + // Inherit the earth - Wyrmkeep combined Windows/Mac/Linux CD (compressed sound) + + // version is different from the other Wyrmkeep re-releases in that it does + // not have any substitute files. Presumably the ite.rsc file has been + // modified to include the Wyrmkeep changes. The resource files are little- + // endian, except for the voice file which is big-endian. + { + { + "ite", + "Multi-OS CD Version", + { + {"ite.rsc", GAME_RESOURCEFILE, "a6433e34b97b15e64fe8214651012db9", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, + {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, + {"inherit the earth voices.cmp",GAME_VOICEFILE | GAME_SWAPENDIAN, NULL, -1}, + {"music.cmp", GAME_MUSICFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformUnknown, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_MULTICD, + GF_WYRMKEEP | GF_CD_FX | GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITECD_GameFonts), + ITECD_GameFonts, + &ITEMACCD_GameSound, + &ITECD_GameSound, + &ITEMACCD_GameMusic, + 0, + NULL, + }, + // Inherit the earth - Wyrmkeep Linux CD version { { @@ -671,6 +738,37 @@ static const SAGAGameDescription gameDescriptions[] = { ITELinPatch_Files, }, + // Inherit the earth - Wyrmkeep Linux CD version (compressed sound) + { + { + "ite", + "CD Version", + { + {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, + {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, + {"voices.cmp", GAME_VOICEFILE, NULL, -1}, + {"music.cmp", GAME_MUSICFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformLinux, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_LINCD, + GF_WYRMKEEP | GF_CD_FX | GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITECD_GameFonts), + ITECD_GameFonts, + &ITECD_GameSound, + &ITECD_GameSound, + &ITEMACCD_GameMusic, + ARRAYSIZE(ITELinPatch_Files), + ITELinPatch_Files, + }, + // Inherit the earth - Wyrmkeep Windows CD version { { @@ -701,6 +799,36 @@ static const SAGAGameDescription gameDescriptions[] = { ITEWinPatch1_Files, }, + // Inherit the earth - Wyrmkeep Windows CD version (compressed sound) + { + { + "ite", + "CD Version", + { + {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, + {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, + {"voices.cmp", GAME_VOICEFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformWindows, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_WINCD, + GF_WYRMKEEP | GF_CD_FX | GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITECD_GameFonts), + ITECD_GameFonts, + &ITECD_GameSound, + &ITECD_GameSound, + NULL, + ARRAYSIZE(ITEWinPatch1_Files), + ITEWinPatch1_Files, + }, + // Inherit the earth - DOS CD version { { @@ -731,6 +859,36 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, + // Inherit the earth - DOS CD version (compressed sound) + { + { + "ite", + "CD Version", + { + {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "50a0d2d7003c926a3832d503c8534e90", -1}, + {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, + {"voices.cmp", GAME_VOICEFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_CD_G, + GF_CD_FX | GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITECD_GameFonts), + ITECD_GameFonts, + &ITECD_GameSound, + &ITECD_GameSound, + NULL, + 0, + NULL, + }, + // Inherit the earth - DOS CD version with digital music { { @@ -762,6 +920,37 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, + // Inherit the earth - DOS CD version with digital music (compressed sound) + { + { + "ite", + "CD Version", + { + {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "50a0d2d7003c926a3832d503c8534e90", -1}, + {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, + {"voices.cmp", GAME_VOICEFILE, NULL, -1}, + {"music.cmp", GAME_MUSICFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_CD_G2, + GF_CD_FX | GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITECD_GameFonts), + ITECD_GameFonts, + &ITECD_GameSound, + &ITECD_GameSound, + &ITEMACCD_GameMusic, + 0, + NULL, + }, + // Inherit the earth - DOS CD German version // reported by mld. Bestsellergamers cover disk { @@ -793,6 +982,37 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, + // Inherit the earth - DOS CD German version (compressed sound) + // reported by mld. Bestsellergamers cover disk + { + { + "ite", + "CD Version", + { + {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, + {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, + {"voices.cmp", GAME_VOICEFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_CD_DE, + GF_CD_FX | GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITECD_GameFonts), + ITECD_GameFonts, + &ITECD_GameSound, + &ITECD_GameSound, + NULL, + 0, + NULL, + }, + // Inherit the earth - DOS CD German version with digital music { { @@ -824,6 +1044,37 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, + // Inherit the earth - DOS CD German version with digital music (compressed sound) + { + { + "ite", + "CD Version", + { + {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, + {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, + {"voices.cmp", GAME_VOICEFILE, NULL, -1}, + {"music.cmp", GAME_MUSICFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_CD_DE2, + GF_CD_FX | GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITECD_GameFonts), + ITECD_GameFonts, + &ITECD_GameSound, + &ITECD_GameSound, + &ITEMACCD_GameMusic, + 0, + NULL, + }, + // Inherit the earth - CD version { { @@ -854,6 +1105,36 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, + // Inherit the earth - CD version (compressed sound) + { + { + "ite", + "CD Version", + { + {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "a891405405edefc69c9d6c420c868b84", -1}, + {"sounds.cmp", GAME_SOUNDFILE, NULL, -1}, + {"voices.cmp", GAME_VOICEFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_CD, + GF_CD_FX | GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITECD_GameFonts), + ITECD_GameFonts, + &ITECD_GameSound, + &ITECD_GameSound, + NULL, + 0, + NULL, + }, + // Inherit the earth - German Floppy version { { @@ -883,6 +1164,35 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, + // Inherit the earth - German Floppy version (compressed sound) + { + { + "ite", + "Floppy", + { + {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, + {"voices.cmp", GAME_SOUNDFILE | GAME_VOICEFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_DISK_DE, + GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITEDISK_GameFonts), + ITEDISK_GameFonts, + &ITEDISK_GameSound, + &ITEDISK_GameSound, + NULL, + 0, + NULL, + }, + // Inherit the earth - German Floppy version with digital music { { @@ -913,6 +1223,36 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, + // Inherit the earth - German Floppy version with digital music (compressed sound) + { + { + "ite", + "Floppy", + { + {"ite.rsc", GAME_RESOURCEFILE, "869fc23c8f38f575979ec67152914fee", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, + {"voices.cmp", GAME_SOUNDFILE | GAME_VOICEFILE, NULL, -1}, + {"music.cmp", GAME_MUSICFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_DISK_DE2, + GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITEDISK_GameFonts), + ITEDISK_GameFonts, + &ITEDISK_GameSound, + &ITEDISK_GameSound, + &ITEMACCD_GameMusic, + 0, + NULL, + }, + // Inherit the earth - Disk version { { @@ -942,6 +1282,35 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, + // Inherit the earth - Disk version (compressed sound) + { + { + "ite", + "Floppy", + { + {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, + {"voices.cmp", GAME_SOUNDFILE | GAME_VOICEFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_DISK_G, + GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITEDISK_GameFonts), + ITEDISK_GameFonts, + &ITEDISK_GameSound, + &ITEDISK_GameSound, + NULL, + 0, + NULL, + }, + // Inherit the earth - Disk version with digital music { { @@ -972,6 +1341,36 @@ static const SAGAGameDescription gameDescriptions[] = { NULL, }, + // Inherit the earth - Disk version with digital music (compressed sound) + { + { + "ite", + "Floppy", + { + {"ite.rsc", GAME_RESOURCEFILE, "8f4315a9bb10ec839253108a032c8b54", -1}, + {"scripts.rsc", GAME_SCRIPTFILE, "516f7330f8410057b834424ea719d1ef", -1}, + {"voices.cmp", GAME_SOUNDFILE | GAME_VOICEFILE, NULL, -1}, + {"music.cmp", GAME_MUSICFILE, NULL, -1}, + { NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + GType_ITE, + GID_ITE_DISK_G2, + GF_COMPRESSED_SOUNDS, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITEDISK_GameFonts), + ITEDISK_GameFonts, + &ITEDISK_GameSound, + &ITEDISK_GameSound, + &ITEMACCD_GameMusic, + 0, + NULL, + }, + // I Have No Mouth And I Must Scream - Demo version { { diff --git a/engines/saga/events.cpp b/engines/saga/events.cpp index 191ea4ed61..b93c6017c7 100644 --- a/engines/saga/events.cpp +++ b/engines/saga/events.cpp @@ -341,6 +341,7 @@ int Events::handleOneShot(Event *event) { _vm->_gfx->setPalette(palPointer); } } + _vm->_actor->showActors(true); } break; case kAnimEvent: diff --git a/engines/saga/gfx.h b/engines/saga/gfx.h index 8658e6d992..0fa7aab742 100644 --- a/engines/saga/gfx.h +++ b/engines/saga/gfx.h @@ -85,7 +85,7 @@ struct PalEntry { byte red; byte green; byte blue; -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp index 03fc0beb7a..55b2b0a996 100644 --- a/engines/saga/interface.cpp +++ b/engines/saga/interface.cpp @@ -1478,6 +1478,7 @@ void Interface::setOption(PanelButton *panelButton) { case kTextLoad: if (_vm->getSaveFilesCount() > 0) { if (_vm->isSaveListFull() || (_optionSaveFileTitleNumber > 0)) { + debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber); fileName = _vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber); setMode(kPanelMain); _vm->load(fileName); diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp index 27729247ef..71b6964530 100644 --- a/engines/saga/music.cpp +++ b/engines/saga/music.cpp @@ -354,7 +354,7 @@ bool Music::isPlaying() { void Music::play(uint32 resourceId, MusicFlags flags) { Audio::AudioStream *audioStream = NULL; MidiParser *parser; - ResourceContext *context; + ResourceContext *context = NULL; byte *resourceData; size_t resourceSize; uint32 loopStart; @@ -413,7 +413,61 @@ void Music::play(uint32 resourceId, MusicFlags flags) { loopStart = 4 * 18727; } - audioStream = new RAWInputStream(_vm, _musicContext, resourceId - 9, flags == MUSIC_LOOP, loopStart); + if (!(_vm->getFeatures() & GF_COMPRESSED_SOUNDS)) { + // uncompressed digital music + audioStream = new RAWInputStream(_vm, _musicContext, resourceId - 9, flags == MUSIC_LOOP, loopStart); + } else { + // compressed digital music + ResourceData * musicResourceData; + Common::File *_file; + byte compressedHeader[10]; + GameSoundTypes soundType; + + musicResourceData = _vm->_resource->getResourceData(_musicContext, resourceId - 9); + _file = _musicContext->getFile(musicResourceData); + + if (_vm->getMusicInfo() == NULL) { + error("RAWInputStream() wrong musicInfo"); + } + + _file->seek((long)musicResourceData->offset, SEEK_SET); + + _file->read(compressedHeader, 9); + + if (compressedHeader[0] == char(0)) { + soundType = kSoundMP3; + } else if (compressedHeader[0] == char(1)) { + soundType = kSoundOGG; + } else if (compressedHeader[0] == char(2)) { + soundType = kSoundFLAC; + } + + switch (soundType) { +#ifdef USE_MAD + case kSoundMP3: + debug(1, "Playing MP3 compressed digital music"); + audioStream = Audio::makeMP3Stream(_file, musicResourceData->size); + break; +#endif +#ifdef USE_VORBIS + case kSoundOGG: + debug(1, "Playing OGG compressed digital music"); + audioStream = Audio::makeVorbisStream(_file, musicResourceData->size); + break; +#endif +#ifdef USE_FLAC + case kSoundFLAC: + debug(1, "Playing FLAC compressed digital music"); + audioStream = Audio::makeFlacStream(_file, musicResourceData->size); + break; +#endif + default: + // Unknown compression + error("Trying to play a compressed digital music, but the compression is not known"); + break; + } + + } } } } diff --git a/engines/saga/music.h b/engines/saga/music.h index 125c85aa9b..96d8608bcd 100644 --- a/engines/saga/music.h +++ b/engines/saga/music.h @@ -31,6 +31,9 @@ #include "sound/audiocd.h" #include "sound/mididrv.h" #include "sound/midiparser.h" +#include "sound/mp3.h" +#include "sound/vorbis.h" +#include "sound/flac.h" namespace Saga { diff --git a/engines/saga/render.cpp b/engines/saga/render.cpp index 4e5d98bbf9..16536f762e 100644 --- a/engines/saga/render.cpp +++ b/engines/saga/render.cpp @@ -77,7 +77,7 @@ void Render::drawScene() { assert(_initialized); - _frameCount++; + _renderedFrameCount++; backBufferSurface = _vm->_gfx->getBackBuffer(); @@ -183,8 +183,8 @@ void Render::fpsTimerCallback(void *refCon) { } void Render::fpsTimer(void) { - _fps = _frameCount; - _frameCount = 0; + _fps = _renderedFrameCount; + _renderedFrameCount = 0; } } // End of namespace Saga diff --git a/engines/saga/render.h b/engines/saga/render.h index c97de8efc9..4c6e3ee5b1 100644 --- a/engines/saga/render.h +++ b/engines/saga/render.h @@ -85,7 +85,7 @@ private: Surface _backGroundSurface; unsigned int _fps; - unsigned int _frameCount; + unsigned int _renderedFrameCount; uint32 _flags; }; diff --git a/engines/saga/saga.h b/engines/saga/saga.h index 9532d2fd56..844a738418 100644 --- a/engines/saga/saga.h +++ b/engines/saga/saga.h @@ -152,7 +152,8 @@ enum GameFeatures { GF_BIG_ENDIAN_DATA = 1 << 0, GF_WYRMKEEP = 1 << 1, GF_CD_FX = 1 << 2, - GF_SCENE_SUBSTITUTES = 1 << 3 + GF_SCENE_SUBSTITUTES = 1 << 3, + GF_COMPRESSED_SOUNDS = 1 << 4 }; enum VerbTypeIds { @@ -224,7 +225,10 @@ enum GameSoundTypes { kSoundVOX = 1, kSoundVOC = 2, kSoundWAV = 3, - kSoundMacPCM = 4 + kSoundMacPCM = 4, + kSoundMP3 = 5, + kSoundOGG = 6, + kSoundFLAC = 7 }; enum TextStringIds { @@ -335,6 +339,7 @@ enum GameObjectTypes { enum ScriptTimings { kScriptTimeTicksPerSecond = (728L/10L), + kScriptTimeTicksPerSecondIHNM = 72, kRepeatSpeedTicks = (728L/10L)/3, kNormalFadeDuration = 320, // 64 steps, 5 msec each kQuickFadeDuration = 64, // 64 steps, 1 msec each @@ -455,10 +460,6 @@ struct SaveGameHeader { char name[SAVE_TITLE_SIZE]; }; -inline int ticksToMSec(int tick) { - return tick * 1000 / kScriptTimeTicksPerSecond; -} - inline int clamp(int minValue, int value, int maxValue) { if (value <= minValue) { return minValue; @@ -591,6 +592,13 @@ public: return _leftMouseButtonPressed || _rightMouseButtonPressed; } + inline int ticksToMSec(int tick) { + if (getGameType() == GType_ITE) + return tick * 1000 / kScriptTimeTicksPerSecond; + else + return tick * 1000 / kScriptTimeTicksPerSecondIHNM; + } + private: uint _saveFilesMaxCount; uint _saveFilesCount; diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index 84d1b45114..362b212b14 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -570,6 +570,8 @@ void Scene::loadScene(LoadSceneParams *loadSceneParams) { _chapterPointsChanged = false; + _vm->_actor->showActors(false); + if ((_vm->getGameType() == GType_IHNM) && (loadSceneParams->chapter != NO_CHAPTER_CHANGE)) { if (loadSceneParams->loadFlag != kLoadBySceneNumber) { error("loadScene wrong usage"); diff --git a/engines/saga/script.h b/engines/saga/script.h index ec3a7e1cf4..5adfb6181a 100644 --- a/engines/saga/script.h +++ b/engines/saga/script.h @@ -598,7 +598,7 @@ private: void sfClearGlobalFlag(SCRIPTFUNC_PARAMS); void sfTestGlobalFlag(SCRIPTFUNC_PARAMS); void sfSetPoints(SCRIPTFUNC_PARAMS); - void sf103(SCRIPTFUNC_PARAMS); + void sfQueueMusic(SCRIPTFUNC_PARAMS); void sfDisableAbortSpeeches(SCRIPTFUNC_PARAMS); void SF_stub(const char *name, ScriptThread *thread, int nArgs); diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp index e713326661..4954188a6e 100644 --- a/engines/saga/sfuncs.cpp +++ b/engines/saga/sfuncs.cpp @@ -240,7 +240,7 @@ static const ScriptFunctionDescription IHNMscriptFunctionsList[IHNM_SCRIPT_FUNCT OPCODE(sfSetSpeechBox), OPCODE(sfDebugShowData), OPCODE(sfWaitFramesEsc), - OPCODE(sf103), + OPCODE(sfQueueMusic), OPCODE(sfDisableAbortSpeeches) }; if (_vm->getGameType() == GType_IHNM) @@ -266,7 +266,7 @@ void Script::sfWait(SCRIPTFUNC_PARAMS) { time = thread->pop(); if (!_skipSpeeches) { - thread->waitDelay(ticksToMSec(time)); // put thread to sleep + thread->waitDelay(_vm->ticksToMSec(time)); // put thread to sleep } } @@ -437,7 +437,7 @@ void Script::sfStartBgdAnim(SCRIPTFUNC_PARAMS) { int16 cycles = thread->pop(); _vm->_anim->setCycles(animId, cycles); - _vm->_anim->setFrameTime(animId, ticksToMSec(kRepeatSpeedTicks)); + _vm->_anim->setFrameTime(animId, _vm->ticksToMSec(kRepeatSpeedTicks)); _vm->_anim->play(animId, 0); debug(1, "sfStartBgdAnim(%d, %d)", animId, cycles); @@ -548,23 +548,30 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) { sceneNumber = thread->pop(); entrance = thread->pop(); - if (_vm->getGameType() == GType_IHNM) + if (_vm->getGameType() == GType_IHNM) { transition = thread->pop(); - if (sceneNumber < 0) { - if (_vm->getGameType() == GType_ITE) { - _vm->shutDown(); - return; - } + _vm->_gfx->setCursor(kCursorBusy); } - if (_vm->getGameType() == GType_IHNM) { - warning("FIXME: implement sfScriptGotoScene differences for IHNM"); + if ((_vm->getGameType() == GType_ITE && sceneNumber < 0) || + (_vm->getGameType() == GType_IHNM && sceneNumber == 0)) { + // TODO: set creditsFlag to true for IHNM + _vm->shutDown(); + return; + } + if (_vm->getGameType() == GType_IHNM) { // Since it doesn't look like the IHNM scripts remove the // cutaway after the intro, this is probably the best place to // to it. - _vm->_anim->clearCutaway(); + Event event; + event.type = kEvTImmediate; + event.code = kCutawayEvent; + event.op = kEventClear; + event.time = 0; + event.duration = 0; + _vm->_events->queue(&event); } // It is possible to leave scene when converse panel is on, @@ -574,6 +581,7 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) { _vm->_interface->setMode(kPanelMain); } + // changeScene calls loadScene which calls setVerb. setVerb resets all pending objects and object flags if (sceneNumber == -1 && _vm->getGameType() == GType_IHNM) { // TODO: This is used to return back to the character selection screen in IHNM. // However, it seems more than this is needed, AM's speech is wrong and no actors @@ -583,10 +591,19 @@ void Script::sfScriptGotoScene(SCRIPTFUNC_PARAMS) { _vm->_scene->changeScene(sceneNumber, entrance, (sceneNumber == ITE_SCENE_ENDCREDIT1) ? kTransitionFade : kTransitionNoFade); } - //TODO: placard stuff + if (_vm->_interface->getMode() == kPanelPlacard || + _vm->_interface->getMode() == kPanelCutaway || + _vm->_interface->getMode() == kPanelVideo) { + _vm->_gfx->showCursor(true); + _vm->_interface->setMode(kPanelMain); + } + _pendingVerb = _vm->_script->getVerbType(kVerbNone); _currentObject[0] = _currentObject[1] = ID_NOTHING; - showVerb(); + showVerb(); // calls setStatusText("") + + if (_vm->getGameType() == GType_IHNM) + _vm->_gfx->setCursor(kCursorNormal); } // Script function #17 (0x11) @@ -684,7 +701,7 @@ void Script::sfSetBgdAnimSpeed(SCRIPTFUNC_PARAMS) { int16 animId = thread->pop(); int16 speed = thread->pop(); - _vm->_anim->setFrameTime(animId, ticksToMSec(speed)); + _vm->_anim->setFrameTime(animId, _vm->ticksToMSec(speed)); debug(1, "sfSetBgdAnimSpeed(%d, %d)", animId, speed); } @@ -712,7 +729,7 @@ void Script::sfStartBgdAnimSpeed(SCRIPTFUNC_PARAMS) { int16 speed = thread->pop(); _vm->_anim->setCycles(animId, cycles); - _vm->_anim->setFrameTime(animId, ticksToMSec(speed)); + _vm->_anim->setFrameTime(animId, _vm->ticksToMSec(speed)); _vm->_anim->play(animId, 0); debug(1, "sfStartBgdAnimSpeed(%d, %d, %d)", animId, cycles, speed); @@ -1008,7 +1025,13 @@ void Script::sfCycleFrames(SCRIPTFUNC_PARAMS) { actor->_actorFlags |= kActorRandom; } if (flags & kCycleReverse) { - actor->_actorFlags |= kActorBackwards; + if (_vm->getGameType() == GType_IHNM && + _vm->_scene->currentChapterNumber() == 2 && _vm->_scene->currentSceneNumber() == 41) { + // Prevent Benny from walking backwards after talking to the child via the monitor. This occurs in the + // original as well, and is fixed by not setting the kActorBackwards flag at this point + } else { + actor->_actorFlags |= kActorBackwards; + } } actor->_cycleFrameSequence = cycleFrameSequence; @@ -1075,7 +1098,7 @@ void Script::sfChainBgdAnim(SCRIPTFUNC_PARAMS) { if (speed >= 0) { _vm->_anim->setCycles(animId, cycles); _vm->_anim->stop(animId); - _vm->_anim->setFrameTime(animId, ticksToMSec(speed)); + _vm->_anim->setFrameTime(animId, _vm->ticksToMSec(speed)); } _vm->_anim->link(animId1, animId); @@ -2108,8 +2131,41 @@ void Script::sfWaitFramesEsc(SCRIPTFUNC_PARAMS) { thread->_returnValue = _vm->_framesEsc; } -void Script::sf103(SCRIPTFUNC_PARAMS) { - SF_stub("sf103", thread, nArgs); +void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) { + int16 param1 = thread->pop(); + int16 param2 = thread->pop(); + Event event; + + if (param1 < 0) { + _vm->_music->stop(); + return; + } + + if (param1 >= _vm->_music->_songTableLen) { + warning("sfQueueMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTableLen - 1); + } else { + _vm->_music->setVolume(-1, 1); + event.type = kEvTOneshot; + event.code = kMusicEvent; + event.param = _vm->_music->_songTable[param1]; + event.param2 = param2 ? MUSIC_LOOP : MUSIC_NORMAL; + event.op = kEventPlay; + event.time = _vm->ticksToMSec(500); // I find the delay in the original to be too long, so I've set it to + // wait for half the time, which sounds better when chapter points + // change + // FIXME: If this is too short for other cases apart from chapter + // point change, set it back to 1000 + + _vm->_events->queue(&event); + + if (!_vm->_scene->haveChapterPointsChanged()) { + _vm->_scene->setCurrentMusicTrack(param1); + _vm->_scene->setCurrentMusicRepeat(param2); + } else { + // Don't save this music track when saving in IHNM + _vm->_scene->setChapterPointsChanged(false); + } + } } void Script::sfDisableAbortSpeeches(SCRIPTFUNC_PARAMS) { diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp index c0442c75de..ceb1ebf630 100644 --- a/engines/saga/sndres.cpp +++ b/engines/saga/sndres.cpp @@ -156,7 +156,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff return false; } - _vm->_resource->loadResource(context, resourceId, soundResource, soundResourceLength); if ((context->fileType & GAME_VOICEFILE) != 0) { @@ -175,9 +174,20 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff if (soundResourceLength >= 8) { if (!memcmp(soundResource, "Creative", 8)) { resourceType = kSoundVOC; - } else if (!memcmp(soundResource, "RIFF", 4) != 0) { + } else if (!memcmp(soundResource, "RIFF", 4) != 0) { resourceType = kSoundWAV; + } + + if (_vm->getFeatures() & GF_COMPRESSED_SOUNDS) { + if (soundResource[0] == char(0)) { + resourceType = kSoundMP3; + } else if (soundResource[0] == char(1)) { + resourceType = kSoundOGG; + } else if (soundResource[0] == char(2)) { + resourceType = kSoundFLAC; + } } + } @@ -266,6 +276,29 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff } free(soundResource); break; + case kSoundMP3: + case kSoundOGG: + case kSoundFLAC: + ResourceData *resourceData; + resourceData = _vm->_resource->getResourceData(context, resourceId); + + // Read compressed sfx header + readS.seek(1); // Skip compression identifier byte + buffer.frequency = readS.readUint16LE(); + buffer.originalSize = readS.readUint32LE(); + buffer.sampleBits = readS.readByte(); + buffer.stereo = (readS.readByte() == char(0)) ? false : true; + + buffer.size = soundResourceLength; + buffer.soundType = resourceType; + buffer.soundFile = context->getFile(resourceData); + buffer.fileOffset = resourceData->offset + 9; // skip compressed sfx header: byte + uint16 + uint32 + byte + byte + + buffer.buffer = NULL; + + result = true; + free(soundResource); + break; default: error("SndRes::load Unknown sound type"); } @@ -286,7 +319,10 @@ int SndRes::getVoiceLength(uint32 resourceId) { return -1; } - msDouble = (double)buffer.size; + if (!(_vm->getFeatures() & GF_COMPRESSED_SOUNDS)) + msDouble = (double)buffer.size; + else + msDouble = (double)buffer.originalSize; if (buffer.sampleBits == 16) { msDouble /= 2.0; } diff --git a/engines/saga/sound.cpp b/engines/saga/sound.cpp index a4ce79b9c4..6c2516c8a3 100644 --- a/engines/saga/sound.cpp +++ b/engines/saga/sound.cpp @@ -80,7 +80,40 @@ void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int if (!buffer.isSigned) flags |= Audio::Mixer::FLAG_UNSIGNED; - _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, buffer.size, buffer.frequency, flags, -1, volume); + if (!(_vm->getFeatures() & GF_COMPRESSED_SOUNDS)) { + _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer, buffer.size, buffer.frequency, flags, -1, volume); + } else { + buffer.soundFile->seek((long)buffer.fileOffset, SEEK_SET); + Audio::AudioStream *stream = NULL; + + switch (buffer.soundType) { +#ifdef USE_MAD + case kSoundMP3: + debug(1, "Playing MP3 compressed sound"); + stream = Audio::makeMP3Stream(buffer.soundFile, buffer.size); + break; +#endif +#ifdef USE_VORBIS + case kSoundOGG: + debug(1, "Playing OGG compressed sound"); + stream = Audio::makeVorbisStream(buffer.soundFile, buffer.size); + break; +#endif +#ifdef USE_FLAC + case kSoundFLAC: + debug(1, "Playing FLAC compressed sound"); + stream = Audio::makeFlacStream(buffer.soundFile, buffer.size); + break; +#endif + default: + // Unknown compression + error("Trying to play a compressed sound, but the compression is not known"); + break; + } + + if (stream != NULL) + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, handle, stream, -1, volume, 0, true, false); + } } void Sound::playSound(SoundBuffer &buffer, int volume, bool loop) { diff --git a/engines/saga/sound.h b/engines/saga/sound.h index 3abea583ba..961f8eba56 100644 --- a/engines/saga/sound.h +++ b/engines/saga/sound.h @@ -28,7 +28,11 @@ #ifndef SAGA_SOUND_H #define SAGA_SOUND_H +#include "common/file.h" #include "sound/mixer.h" +#include "sound/mp3.h" +#include "sound/vorbis.h" +#include "sound/flac.h" namespace Saga { @@ -46,7 +50,11 @@ struct SoundBuffer { byte *buffer; size_t size; + size_t originalSize; bool isBigEndian; + GameSoundTypes soundType; + Common::File *soundFile; + size_t fileOffset; }; enum sndHandleType { diff --git a/engines/scumm/akos.cpp b/engines/scumm/akos.cpp index 2a51464341..c8667d7ab2 100644 --- a/engines/scumm/akos.cpp +++ b/engines/scumm/akos.cpp @@ -47,12 +47,12 @@ struct AkosHeader { uint16 num_anims; uint16 unk_3; uint16 codec; -}; +} PACKED_STRUCT; struct AkosOffset { uint32 akcd; // offset into the akcd data uint16 akci; // offset into the akci data -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/scumm/base-costume.h b/engines/scumm/base-costume.h index e6ef618a3e..155bbff97f 100644 --- a/engines/scumm/base-costume.h +++ b/engines/scumm/base-costume.h @@ -37,7 +37,7 @@ struct CostumeInfo { uint16 width, height; int16 rel_x, rel_y; int16 move_x, move_y; -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/scumm/boxes.cpp b/engines/scumm/boxes.cpp index 424e5d891e..e79cea4359 100644 --- a/engines/scumm/boxes.cpp +++ b/engines/scumm/boxes.cpp @@ -80,7 +80,7 @@ struct Box { /* Internal walkbox file format */ uint32 unk3; } v8; }; -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 8624f80fe7..e9430337ff 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -765,19 +765,22 @@ PluginError Engine_SCUMM_create(OSystem *syst, Engine **engine) { // narrow down the list a bit more. if (results.size() > 1 && ConfMan.hasKey("platform")) { Common::Platform platform = Common::parsePlatform(ConfMan.get("platform")); + Common::List<DetectorResult> tmp; + + // Copy only those candidates which match the platform setting for (Common::List<DetectorResult>::iterator x = results.begin(); x != results.end(); ) { - if (x->game.platform != platform) { - x = results.erase(x); - } else { - ++x; + if (x->game.platform == platform) { + tmp.push_back(*x); } } - } - // If we narrowed it down too much, abort - if (results.empty()) { - warning("Engine_SCUMM_create: Game data inconsistent with platform override"); - return kNoGameDataFoundError; + // If we narrowed it down too much, print a warning, else use the list + // we just computed as new candidates list. + if (tmp.empty()) { + warning("Engine_SCUMM_create: Game data inconsistent with platform override"); + } else { + results = tmp; + } } // Still no unique match found -> print a warning diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp index 85a7a4b675..16fe72531b 100644 --- a/engines/scumm/dialogs.cpp +++ b/engines/scumm/dialogs.cpp @@ -825,26 +825,26 @@ PauseDialog::PauseDialog(ScummEngine *scumm, int res) : InfoDialog(scumm, res) { } -void PauseDialog::handleKeyDown(uint16 ascii, int keycode, int modifiers) { - if (ascii == ' ') // Close pause dialog if space key is pressed +void PauseDialog::handleKeyDown(Common::KeyState state) { + if (state.ascii == ' ') // Close pause dialog if space key is pressed close(); else - ScummDialog::handleKeyDown(ascii, keycode, modifiers); + ScummDialog::handleKeyDown(state); } ConfirmDialog::ConfirmDialog(ScummEngine *scumm, int res) : InfoDialog(scumm, res) { } -void ConfirmDialog::handleKeyDown(uint16 ascii, int keycode, int modifiers) { - if (tolower(ascii) == 'n') { +void ConfirmDialog::handleKeyDown(Common::KeyState state) { + if (state.keycode == Common::KEYCODE_n) { setResult(0); close(); - } else if (tolower(ascii) == 'y') { + } else if (state.keycode == Common::KEYCODE_y) { setResult(1); close(); } else - ScummDialog::handleKeyDown(ascii, keycode, modifiers); + ScummDialog::handleKeyDown(state); } #pragma mark - @@ -892,11 +892,11 @@ void ValueDisplayDialog::reflowLayout() { _h = height; } -void ValueDisplayDialog::handleKeyDown(uint16 ascii, int keycode, int modifiers) { - if (ascii == _incKey || ascii == _decKey) { - if (ascii == _incKey && _value < _max) +void ValueDisplayDialog::handleKeyDown(Common::KeyState state) { + if (state.ascii == _incKey || state.ascii == _decKey) { + if (state.ascii == _incKey && _value < _max) _value++; - else if (ascii == _decKey && _value > _min) + else if (state.ascii == _decKey && _value > _min) _value--; setResult(_value); @@ -924,8 +924,8 @@ void SubtitleSettingsDialog::handleTickle() { close(); } -void SubtitleSettingsDialog::handleKeyDown(uint16 ascii, int keycode, int modifiers) { - if (keycode == 't' && modifiers == Common::KBD_CTRL) { +void SubtitleSettingsDialog::handleKeyDown(Common::KeyState state) { + if (state.keycode == 't' && state.flags == Common::KBD_CTRL) { cycleValue(); reflowLayout(); @@ -959,11 +959,11 @@ Indy3IQPointsDialog::Indy3IQPointsDialog(ScummEngine *scumm, char* text) : InfoDialog(scumm, text) { } -void Indy3IQPointsDialog::handleKeyDown(uint16 ascii, int keycode, int modifiers) { - if (ascii == 'i') +void Indy3IQPointsDialog::handleKeyDown(Common::KeyState state) { + if (state.ascii == 'i') close(); else - ScummDialog::handleKeyDown(ascii, keycode, modifiers); + ScummDialog::handleKeyDown(state); } } // End of namespace Scumm diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h index b69e989f8a..23c63d8992 100644 --- a/engines/scumm/dialogs.h +++ b/engines/scumm/dialogs.h @@ -169,8 +169,8 @@ public: setResult(0); close(); } - virtual void handleKeyDown(uint16 ascii, int keycode, int modifiers) { - setResult(ascii); + virtual void handleKeyDown(Common::KeyState state) { + setResult(state.ascii); close(); } @@ -189,7 +189,7 @@ protected: class PauseDialog : public InfoDialog { public: PauseDialog(ScummEngine *scumm, int res); - virtual void handleKeyDown(uint16 ascii, int keycode, int modifiers); + virtual void handleKeyDown(Common::KeyState state); }; /** @@ -199,7 +199,7 @@ public: class ConfirmDialog : public InfoDialog { public: ConfirmDialog(ScummEngine *scumm, int res); - virtual void handleKeyDown(uint16 ascii, int keycode, int modifiers); + virtual void handleKeyDown(Common::KeyState state); }; /** @@ -216,7 +216,7 @@ public: virtual void handleMouseDown(int x, int y, int button, int clickCount) { close(); } - virtual void handleKeyDown(uint16 ascii, int keycode, int modifiers); + virtual void handleKeyDown(Common::KeyState state); virtual void reflowLayout(); @@ -247,7 +247,7 @@ public: virtual void handleMouseDown(int x, int y, int button, int clickCount) { close(); } - virtual void handleKeyDown(uint16 ascii, int keycode, int modifiers); + virtual void handleKeyDown(Common::KeyState state); protected: int _value; uint32 _timer; @@ -259,7 +259,7 @@ protected: class Indy3IQPointsDialog : public InfoDialog { public: Indy3IQPointsDialog(ScummEngine *scumm, char* text); - virtual void handleKeyDown(uint16 ascii, int keycode, int modifiers); + virtual void handleKeyDown(Common::KeyState state); }; } // End of namespace Scumm diff --git a/engines/scumm/file.cpp b/engines/scumm/file.cpp index 3ab3e1a2e0..2c7f9ead5b 100644 --- a/engines/scumm/file.cpp +++ b/engines/scumm/file.cpp @@ -1257,10 +1257,11 @@ struct _lfl_index { uint16 script_addr[200]; byte sound_lfl[100]; uint16 sound_addr[100]; -} lfl_index; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING +_lfl_index lfl_index; bool ScummNESFile::generateResource(int res) { const LFL *lfl = &lfls[res - 1]; diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h index 54eb470c26..84ad8adb3b 100644 --- a/engines/scumm/he/intern_he.h +++ b/engines/scumm/he/intern_he.h @@ -250,7 +250,7 @@ protected: int32 dim2start; //0C int32 dim2end; //10 byte data[1]; //14 - }; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/scumm/he/resource_he.h b/engines/scumm/he/resource_he.h index 757cf13b7c..d7f4d99754 100644 --- a/engines/scumm/he/resource_he.h +++ b/engines/scumm/he/resource_he.h @@ -172,7 +172,7 @@ class Win32ResExtractor : public ResExtractor { byte *memory; byte *first_resource; int total_size; - }; + } PACKED_STRUCT; struct WinResource { char id[256]; @@ -183,7 +183,7 @@ class Win32ResExtractor : public ResExtractor { bool is_directory; char *get_resource_id_quoted(); - }; + } PACKED_STRUCT; struct Win32IconResDir { @@ -191,12 +191,12 @@ class Win32ResExtractor : public ResExtractor { byte height; byte color_count; byte reserved; - }; + } PACKED_STRUCT; struct Win32CursorDir { uint16 width; uint16 height; - }; + } PACKED_STRUCT; struct Win32CursorIconDirEntry { union { @@ -207,14 +207,14 @@ class Win32ResExtractor : public ResExtractor { uint16 bit_count; uint32 bytes_in_res; uint16 res_id; - }; + } PACKED_STRUCT; struct Win32CursorIconDir { uint16 reserved; uint16 type; uint16 count; Win32CursorIconDirEntry entries[1]; - }; + } PACKED_STRUCT; struct Win32CursorIconFileDirEntry { byte width; @@ -225,14 +225,14 @@ class Win32ResExtractor : public ResExtractor { uint16 hotspot_y; uint32 dib_size; uint32 dib_offset; - }; + } PACKED_STRUCT; struct Win32CursorIconFileDir { uint16 reserved; uint16 type; uint16 count; Win32CursorIconFileDirEntry entries[1]; - }; + } PACKED_STRUCT; struct Win32BitmapInfoHeader { uint32 size; @@ -246,25 +246,25 @@ class Win32ResExtractor : public ResExtractor { int32 y_pels_per_meter; uint32 clr_used; uint32 clr_important; - }; + } PACKED_STRUCT; struct Win32RGBQuad { byte blue; byte green; byte red; byte reserved; - }; + } PACKED_STRUCT; struct Win32ImageResourceDirectoryEntry { uint32 name; uint32 offset_to_data; - }; + } PACKED_STRUCT; struct Win16NETypeInfo { uint16 type_id; uint16 count; uint32 resloader; // FARPROC16 - smaller? uint16? - }; + } PACKED_STRUCT; struct DOSImageHeader { uint16 magic; @@ -286,7 +286,7 @@ class Win32ResExtractor : public ResExtractor { uint16 oeminfo; uint16 res2[10]; uint32 lfanew; - }; + } PACKED_STRUCT; struct Win32ImageFileHeader { uint16 machine; @@ -296,12 +296,12 @@ class Win32ResExtractor : public ResExtractor { uint32 number_of_symbols; uint16 size_of_optional_header; uint16 characteristics; - }; + } PACKED_STRUCT; struct Win32ImageDataDirectory { uint32 virtual_address; uint32 size; - }; + } PACKED_STRUCT; struct Win32ImageOptionalHeader { uint16 magic; @@ -335,13 +335,13 @@ class Win32ResExtractor : public ResExtractor { uint32 loader_flags; uint32 number_of_rva_and_sizes; Win32ImageDataDirectory data_directory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; - }; + } PACKED_STRUCT; struct Win32ImageNTHeaders { uint32 signature; Win32ImageFileHeader file_header; Win32ImageOptionalHeader optional_header; - }; + } PACKED_STRUCT; struct Win32ImageSectionHeader { byte name[IMAGE_SIZEOF_SHORT_NAME]; @@ -357,14 +357,14 @@ class Win32ResExtractor : public ResExtractor { uint16 number_of_relocations; uint16 number_of_linenumbers; uint32 characteristics; - }; + } PACKED_STRUCT; struct Win32ImageResourceDataEntry { uint32 offset_to_data; uint32 size; uint32 code_page; uint32 resource_handle; - }; + } PACKED_STRUCT; struct Win32ImageResourceDirectory { uint32 characteristics; @@ -373,7 +373,7 @@ class Win32ResExtractor : public ResExtractor { uint16 minor_version; uint16 number_of_named_entries; uint16 number_of_id_entries; - }; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/scumm/imuse/instrument.cpp b/engines/scumm/imuse/instrument.cpp index 23b325c20b..b6ed064bc9 100644 --- a/engines/scumm/imuse/instrument.cpp +++ b/engines/scumm/imuse/instrument.cpp @@ -149,7 +149,7 @@ private: #include "common/pack-start.h" // START STRUCT PACKING - struct { + struct AdlibInstrument { byte flags_1; byte oplvl_1; byte atdec_1; @@ -166,10 +166,12 @@ private: byte flags_b; struct { byte a,b,c,d,e,f,g,h; } extra_b; byte duration; - } _instrument; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING + AdlibInstrument _instrument; + public: Instrument_Adlib(const byte *data); Instrument_Adlib(Serializer *s); @@ -241,7 +243,7 @@ private: byte tva_env_sustain_level; } partial[4]; byte checksum; - }; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index 2d7401fe57..ffcb7d03f2 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -75,83 +75,53 @@ void ScummEngine::parseEvents() { sprintf(_saveLoadName, "Quicksave %d", _saveLoadSlot); _saveLoadFlag = (event.kbd.flags == Common::KBD_ALT) ? 1 : 2; _saveTemporaryState = false; - } else if (event.kbd.flags == Common::KBD_CTRL) { - if (event.kbd.keycode == 'f') - _fastMode ^= 1; - else if (event.kbd.keycode == 'g') - _fastMode ^= 2; - else if (event.kbd.keycode == 'd') - _debugger->attach(); - else if (event.kbd.keycode == 's') - _res->resourceStats(); - else - _keyPressed = event.kbd; // Normal key press, pass on to the game. - } else if (event.kbd.flags & Common::KBD_ALT) { - // Handle KBD_ALT combos. We know that the result must be 273 for Alt-W - // because that's what MI2 looks for in its "instant win" cheat. - - // FIXME: Handle this specific property of MI2 inside processKeyboard ? - _keyPressed = event.kbd; - _keyPressed.ascii = event.kbd.keycode + 154; + } else if (event.kbd.flags == Common::KBD_CTRL && event.kbd.keycode == 'f') { + _fastMode ^= 1; + } else if (event.kbd.flags == Common::KBD_CTRL && event.kbd.keycode == 'g') { + _fastMode ^= 2; + } else if ((event.kbd.flags == Common::KBD_CTRL && event.kbd.keycode == 'd') || + event.kbd.ascii == '~' || event.kbd.ascii == '#') { + _debugger->attach(); + } else if (event.kbd.flags == Common::KBD_CTRL && event.kbd.keycode == 's') { + _res->resourceStats(); } else { // Normal key press, pass on to the game. _keyPressed = event.kbd; } - if (event.kbd.keycode >= Common::KEYCODE_UP && event.kbd.keycode <= Common::KEYCODE_LEFT) { - if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformSegaCD) { - _keyPressed = event.kbd; - _keyPressed.ascii = event.kbd.ascii - Common::KEYCODE_UP + 54; - } else if (_game.version < 7) { - // FIXME: Handle this specific property inside processKeyboard ? - - // Don't let game see arrow keys. This fixes bug with up arrow (273) - // corresponding to the "instant win" cheat in MI2 mentioned above. - // - // This is not applicable to V7+ games, which need to see the arrow keys, - // too, else certain things (derby scene, asterorid lander) won't work. - _keyPressed.reset(); - } - } - if (_game.heversion >= 80) { // Keyboard is controlled via variable - int _keyState = 0; + int keyState = 0; if (event.kbd.keycode == Common::KEYCODE_LEFT) // Left - _keyState = 1; + keyState = 1; if (event.kbd.keycode == Common::KEYCODE_RIGHT) // Right - _keyState |= 2; + keyState |= 2; if (event.kbd.keycode == Common::KEYCODE_UP) // Up - _keyState |= 4; + keyState |= 4; if (event.kbd.keycode == Common::KEYCODE_DOWN) // Down - _keyState |= 8; + keyState |= 8; if (event.kbd.flags == Common::KBD_SHIFT) - _keyState |= 16; + keyState |= 16; if (event.kbd.flags == Common::KBD_CTRL) - _keyState |= 32; + keyState |= 32; - VAR(VAR_KEY_STATE) = _keyState; + VAR(VAR_KEY_STATE) = keyState; } - // FIXME: There is a discrepancy between EVENT_KEYDOWN and EVENT_KEYUP here: - // For EVENT_KEYDOWN, we use _keyPressed.keycode, which has potentially been - // modified, while for EVENT_KEYUP we use the unfiltered event.kbd.keycode. - // This could lead problems (like a key becoming 'stuck'). - - // FIXME #2: We are mixing ascii and keycode values here. We probably should - // be using keycodes, but at least INSANE checks for "Shift-V" by looking for - // the 'V' key being pressed. It would be easy to solve that by also storing the - // the modifier flags. However, since getKeyState() is also called by scripts, - // we have to be very careful with semantic changes. - // Nevertheless, it's bad to rely on "ascii" holdoing keycode values for special - // keys (like the function keys), so this should be fixed. - + // FIXME: We are using ASCII values to index the _keyDownMap here, + // yet later one code which checks _keyDownMap will use KEYCODEs + // to do so. That is, we are mixing ascii and keycode values here, + // which is bad. We probably should be only using keycodes, but at + // least INSANE checks for "Shift-V" by looking for the 'V' key + // being pressed. It would be easy to solve that by also storing + // the modifier flags. However, since getKeyState() is also called + // by scripts, we have to be careful with semantic changes. if (_keyPressed.ascii >= 512) debugC(DEBUG_GENERAL, "_keyPressed > 512 (%d)", _keyPressed.ascii); else @@ -159,11 +129,9 @@ void ScummEngine::parseEvents() { break; case Common::EVENT_KEYUP: - // FIXME: for some reason Common::KBD_ALT is set sometimes - // possible to a bug in sdl-common.cpp - if (event.kbd.ascii >= 512) + if (event.kbd.ascii >= 512) { debugC(DEBUG_GENERAL, "keyPressed > 512 (%d)", event.kbd.ascii); - else { + } else { _keyDownMap[event.kbd.ascii] = false; // Due to some weird bug with capslock key pressed @@ -173,6 +141,8 @@ void ScummEngine::parseEvents() { // both upper and lower letters are unpressed on keyup event // // Fixes bug #1709430: "FT: CAPSLOCK + V enables cheating for all fights" + // + // Fingolfin remarks: This wouldn't be a problem if we used keycodes. _keyDownMap[toupper(event.kbd.ascii)] = false; } break; @@ -204,24 +174,21 @@ void ScummEngine::parseEvents() { _rightBtnPressed &= ~msDown; break; - // The following two cases enable dialog choices to be - // scrolled through in the SegaCD version of MI - // as nothing else uses the wheel don't bother - // checking the gameid. Values are taken from script-14. - + // The following two cases enable dialog choices to be scrolled + // through in the SegaCD version of MI. Values are taken from script-14. + // See bug report #1193185 for details. case Common::EVENT_WHEELDOWN: - _keyPressed = Common::KeyState(Common::KEYCODE_7, 55); // '7' + if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformSegaCD) + _keyPressed = Common::KeyState(Common::KEYCODE_7, 55); // '7' break; case Common::EVENT_WHEELUP: - _keyPressed = Common::KeyState(Common::KEYCODE_6, 54); // '6' + if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformSegaCD) + _keyPressed = Common::KeyState(Common::KEYCODE_6, 54); // '6' break; case Common::EVENT_QUIT: - if (ConfMan.getBool("confirm_exit")) - confirmExitDialog(); - else - _quit = true; + _quit = true; break; default: @@ -446,11 +413,6 @@ void ScummEngine_v2::processKeyboard(Common::KeyState lastKeyHit) { // Fall back to default behavior ScummEngine::processKeyboard(lastKeyHit); - // Store the input type. So far we can't distinguish - // between 1, 3 and 5. - // 1) Verb 2) Scene 3) Inv. 4) Key - // 5) Sentence Bar - if (VAR_KEYPRESS != 0xFF && _mouseAndKeyboardStat) { // Key Input if (315 <= _mouseAndKeyboardStat && _mouseAndKeyboardStat <= 323) { // Convert F-Keys for V1/V2 games (they start at 1) @@ -503,12 +465,6 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) { if (_game.id == GID_CMI) mainmenuKeyEnabled = true; -/* - FIXME: We also used to force-enable F5 in Sam&Max and HE >= 72 games -- why? - if ((_game.version <= 3) || (_game.id == GID_SAMNMAX) || (_game.id == GID_CMI) || (_game.heversion >= 72)) - mainmenuKeyEnabled = true; -*/ - if (mainmenuKeyEnabled && (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.flags == 0)) { if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0) runScript(VAR(VAR_SAVELOAD_SCRIPT), 0, 0, 0); @@ -569,15 +525,35 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) { if (VAR_CHARINC != 0xFF) VAR(VAR_CHARINC) = _defaultTalkDelay; - } else if (lastKeyHit.ascii == '~' || lastKeyHit.ascii == '#') { // Debug console - _debugger->attach(); - } else { - // FIXME: Possibly convert even more keycode/ascii pairs to their SCUMM counterparts? - if (lastKeyHit.keycode >= Common::KEYCODE_F1 && lastKeyHit.keycode <= Common::KEYCODE_F9) + + if (lastKeyHit.keycode >= Common::KEYCODE_F1 && + lastKeyHit.keycode <= Common::KEYCODE_F9) { _mouseAndKeyboardStat = lastKeyHit.keycode - Common::KEYCODE_F1 + 315; - else + + } else if (_game.id == GID_MONKEY2 && (lastKeyHit.flags & Common::KBD_ALT)) { + // Handle KBD_ALT combos in MI2. We know that the result must be 273 for Alt-W + // because that's what MI2 looks for in its "instant win" cheat. + _mouseAndKeyboardStat = lastKeyHit.keycode + 154; + + } else if (lastKeyHit.keycode >= Common::KEYCODE_UP && + lastKeyHit.keycode <= Common::KEYCODE_LEFT) { + if (_game.id == GID_MONKEY && _game.platform == Common::kPlatformSegaCD) { + // Map arrow keys to number keys in the SEGA version of MI to support + // scrolling to conversation choices. See bug report #1193185 for details. + _mouseAndKeyboardStat = lastKeyHit.keycode - Common::KEYCODE_UP + 54; + } else if (_game.version >= 7) { + // Don't let pre-V7 game see arrow keys. This fixes bug with up arrow (273) + // corresponding to the "instant win" cheat in MI2 mentioned above. + // + // This is not applicable to V7+ games, which need to see the arrow keys, + // too, else certain things (derby scene, asterorid lander) won't work. + _mouseAndKeyboardStat = lastKeyHit.ascii; + } + + } else { _mouseAndKeyboardStat = lastKeyHit.ascii; + } } } diff --git a/engines/scumm/intern.h b/engines/scumm/intern.h index 008c2995e5..6723081dfe 100644 --- a/engines/scumm/intern.h +++ b/engines/scumm/intern.h @@ -313,7 +313,7 @@ protected: virtual void readGlobalObjects(); virtual void loadCharset(int no); - virtual void runInputScript(int a, int cmd, int mode); + virtual void runInputScript(int clickArea, int val, int mode); virtual void runInventoryScript(int i); virtual int getVar(); @@ -554,7 +554,7 @@ protected: int16 type; int16 dim2; byte data[1]; - }; + } PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk index d7b858a312..d8ef669410 100644 --- a/engines/scumm/module.mk +++ b/engines/scumm/module.mk @@ -82,6 +82,12 @@ MODULE_OBJS += \ smush/saud_channel.o \ smush/smush_mixer.o \ smush/smush_font.o + +ifdef USE_ARM_SMUSH_ASM +MODULE_OBJS += \ + smush/codec47ARM.o +endif + endif ifndef DISABLE_HE diff --git a/engines/scumm/object.h b/engines/scumm/object.h index bf38d42289..f27e6a501e 100644 --- a/engines/scumm/object.h +++ b/engines/scumm/object.h @@ -91,7 +91,7 @@ struct RoomHeader { uint32 transparency; } v8; }; -}; +} PACKED_STRUCT; struct CodeHeader { union { @@ -123,7 +123,7 @@ struct CodeHeader { } v7; }; -}; +} PACKED_STRUCT; struct ImageHeader { /* file format */ union { @@ -172,7 +172,7 @@ struct ImageHeader { /* file format */ } hotspot[15]; } v8; }; -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/scumm/player_v2.h b/engines/scumm/player_v2.h index 43771d295f..cd88d57602 100644 --- a/engines/scumm/player_v2.h +++ b/engines/scumm/player_v2.h @@ -61,7 +61,7 @@ struct channel_data { uint16 unknown[4]; // 38 - 44 uint16 music_timer; // 46 uint16 music_script_nr; // 48 -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 9578b05c1f..9d0d0ad654 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -200,8 +200,6 @@ bool ScummEngine::loadState(int slot, bool compat) { _engineStartTime = _system->getMillis() / 1000; } - _dialogStartTime = _system->getMillis() / 1000; - // Due to a bug in scummvm up to and including 0.3.0, save games could be saved // in the V8/V9 format but were tagged with a V7 mark. Ouch. So we just pretend V7 == V8 here if (hdr.ver == VER(7)) @@ -213,7 +211,7 @@ bool ScummEngine::loadState(int slot, bool compat) { // state for temporary state saves - such as certain cutscenes in DOTT, // FOA, Sam and Max, etc. // - // Thusly, we should probably not stop music when restoring from one of + // Thus, we should probably not stop music when restoring from one of // these saves. This change stops the Mole Man theme from going quiet in // Sam & Max when Doug tells you about the Ball of Twine, as mentioned in // patch #886058. @@ -378,9 +376,6 @@ bool ScummEngine::loadState(int slot, bool compat) { _sound->pauseSounds(false); - _engineStartTime += _system->getMillis() / 1000 - _dialogStartTime; - _dialogStartTime = 0; - return true; } diff --git a/engines/scumm/script.cpp b/engines/scumm/script.cpp index 46e4e64347..cc56adf622 100644 --- a/engines/scumm/script.cpp +++ b/engines/scumm/script.cpp @@ -1156,39 +1156,39 @@ void ScummEngine::checkAndRunSentenceScript() { runScript(sentenceScript, 0, 0, localParamList); } -void ScummEngine_v2::runInputScript(int a, int cmd, int mode) { +void ScummEngine_v2::runInputScript(int clickArea, int val, int mode) { int args[24]; int verbScript; verbScript = 4; - VAR(VAR_CLICK_AREA) = a; - switch (a) { - case 1: // Verb clicked - VAR(VAR_CLICK_VERB) = cmd; + VAR(VAR_CLICK_AREA) = clickArea; + switch (clickArea) { + case kVerbClickArea: // Verb clicked + VAR(VAR_CLICK_VERB) = val; break; - case 3: // Inventory clicked - VAR(VAR_CLICK_OBJECT) = cmd; + case kInventoryClickArea: // Inventory clicked + VAR(VAR_CLICK_OBJECT) = val; break; } memset(args, 0, sizeof(args)); - args[0] = a; - args[1] = cmd; + args[0] = clickArea; + args[1] = val; args[2] = mode; if (verbScript) runScript(verbScript, 0, 0, args); } -void ScummEngine::runInputScript(int a, int cmd, int mode) { +void ScummEngine::runInputScript(int clickArea, int val, int mode) { int args[24]; int verbScript; verbScript = VAR(VAR_VERB_SCRIPT); memset(args, 0, sizeof(args)); - args[0] = a; - args[1] = cmd; + args[0] = clickArea; + args[1] = val; args[2] = mode; // All HE 72+ games but only some HE 71 games. if (_game.heversion >= 71) { @@ -1198,18 +1198,18 @@ void ScummEngine::runInputScript(int a, int cmd, int mode) { // Macintosh verison of indy3ega used different interface, so adjust values. if (_game.id == GID_INDY3 && _game.platform == Common::kPlatformMacintosh) { - if (a == 1 && (cmd >= 101 && cmd <= 108)) { - if (cmd == 107) { + if (clickArea == kVerbClickArea && (val >= 101 && val <= 108)) { + if (val == 107) { VAR(67) -= 2; inventoryScript(); return; - } else if (cmd == 108) { + } else if (val == 108) { VAR(67) += 2; inventoryScript(); return; } else { args[0] = 3; - args[1] = VAR(83 + (cmd - 101)); + args[1] = VAR(83 + (val - 101)); } } } diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 840940caa3..cd48ef4d02 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Fri Jun 08 10:51:50 2007 + This file was generated by the md5table tool on Mon Jul 2 22:44:41 2007 DO NOT EDIT MANUALLY! */ @@ -254,6 +254,7 @@ static const MD5Table md5table[] = { { "6886e5d08cee329b1f2e743ae2e3ceed", "monkey2", "", "", 11135, Common::DE_DEU, Common::kPlatformPC }, { "695fe0b3963333b7e15b37514db3c745", "thinkerk", "", "Demo", 29789, Common::EN_USA, Common::kPlatformUnknown }, { "697c9b7c55a05d8199c48b48e379d2c8", "puttmoon", "", "", -1, Common::HB_ISR, Common::kPlatformPC }, + { "69d70269fafc4445adbb0d223e4f9a3f", "indy3", "EGA", "EGA", 5361, Common::EN_ANY, Common::kPlatformPC }, { "69ea626f1f87eecb78ea0d6c6b983a1d", "monkey2", "", "", -1, Common::IT_ITA, Common::kPlatformPC }, { "69ffe29185b8d71f09f6199f8b2a87cb", "lost", "HE 100", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "6a30a07f353a75cdc602db27d73e1b42", "puttputt", "HE 70", "", -1, Common::EN_ANY, Common::kPlatformWindows }, @@ -486,7 +487,7 @@ static const MD5Table md5table[] = { { "d8d07efcb88f396bee0b402b10c3b1c9", "maniac", "NES", "", -1, Common::EN_USA, Common::kPlatformNES }, { "d917f311a448e3cc7239c31bddb00dd2", "samnmax", "", "CD", 9080, Common::EN_ANY, Common::kPlatformUnknown }, { "d9d0dd93d16ab4dec55cabc2b86bbd17", "samnmax", "", "Demo", 6478, Common::EN_ANY, Common::kPlatformPC }, - { "da09e666fc8f5b78d7b0ac65d1a3b56e", "monkey2", "", "", -1, Common::EN_ANY, Common::kPlatformFMTowns }, + { "da09e666fc8f5b78d7b0ac65d1a3b56e", "monkey2", "", "", 11135, Common::EN_ANY, Common::kPlatformFMTowns }, { "da6269b18fcb08189c0aa9c95533cce2", "monkey", "CD", "CD", 8955, Common::IT_ITA, Common::kPlatformPC }, { "da669b20271b85182e9c17a2a37ea02e", "monkey2", "", "", -1, Common::DE_DEU, Common::kPlatformAmiga }, { "db21a6e338fe3b70c2723b6530865bf2", "PuttTime", "HE 85", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 4b3a365394..2140b15544 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -120,7 +120,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr) _gdi = new Gdi(this); } _res = new ResourceManager(this); - + // Convert MD5 checksum back into a digest for (int i = 0; i < 16; ++i) { char tmpStr[3] = "00"; @@ -2236,31 +2236,39 @@ void ScummEngine::startManiac() { #pragma mark --- GUI --- #pragma mark - -int ScummEngine::runDialog(Dialog &dialog) { - _dialogStartTime = _system->getMillis() / 1000; - - // Pause sound & video - bool old_soundsPaused = _sound->_soundsPaused; - _sound->pauseSounds(true); +void ScummEngine::pauseEngineIntern(bool pause) { + if (pause) { + // Record start of the pause, so that we can later + // adjust _engineStartTime accordingly. + _pauseStartTime = _system->getMillis(); - bool visible = CursorMan.isVisible(); + // Pause sound & video + _oldSoundsPaused = _sound->_soundsPaused; + _sound->pauseSounds(true); + + } else { + // Update the screen to make it less likely that the player will see a + // brief cursor palette glitch when the GUI is disabled. + _system->updateScreen(); - // Open & run the dialog - int result = dialog.runModal(); + // Resume sound & video + _sound->pauseSounds(_oldSoundsPaused); - // Restore old cursor - updateCursor(); - CursorMan.showMouse(visible); + // Adjust engine start time + _engineStartTime += (_system->getMillis() - _pauseStartTime) / 1000; + _pauseStartTime = 0; + } +} - // Update the screen to make it less likely that the player will see a - // brief cursor palette glitch when the GUI is disabled. - _system->updateScreen(); +int ScummEngine::runDialog(Dialog &dialog) { + // Pause engine + pauseEngine(true); - // Resume sound & video - _sound->pauseSounds(old_soundsPaused); + // Open & run the dialog + int result = dialog.runModal(); - _engineStartTime += (_system->getMillis() / 1000) - _dialogStartTime; - _dialogStartTime = 0; + // Resume engine + pauseEngine(false); // Return the result return result; diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 8c8124714d..4146846856 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -406,9 +406,6 @@ class ScummEngine : public Engine { friend class CharsetRenderer; friend class ResourceManager; - GUI::Debugger *getDebugger(); - void errorString(const char *buf_input, char *buf_output); - public: /* Put often used variables at the top. * That results in a shorter form of the opcode @@ -437,17 +434,20 @@ public: protected: VirtualMachineState vm; + + bool _oldSoundsPaused; public: // Constructor / Destructor ScummEngine(OSystem *syst, const DetectorResult &dr); virtual ~ScummEngine(); - /** Startup function, main loop. */ - int go(); - - // Init functions - int init(); + // Engine APIs + virtual int init(); + virtual int go(); + virtual void errorString(const char *buf_input, char *buf_output); + virtual GUI::Debugger *getDebugger(); + virtual void pauseEngineIntern(bool pause); protected: virtual void setupScumm(); @@ -638,7 +638,7 @@ protected: void saveInfos(Common::OutSaveFile* file); int32 _engineStartTime; - int32 _dialogStartTime; + int32 _pauseStartTime; protected: /* Script VM - should be in Script class */ @@ -863,7 +863,7 @@ protected: void verbMouseOver(int verb); int findVerbAtPos(int x, int y) const; virtual void drawVerb(int verb, int mode); - virtual void runInputScript(int a, int cmd, int mode); + virtual void runInputScript(int clickArea, int val, int mode); void restoreVerbBG(int verb); void drawVerbBitmap(int verb, int x, int y); int getVerbSlot(int id, int mode) const; diff --git a/engines/scumm/smush/codec47.cpp b/engines/scumm/smush/codec47.cpp index 34d61d1c8a..6904e96c11 100644 --- a/engines/scumm/smush/codec47.cpp +++ b/engines/scumm/smush/codec47.cpp @@ -342,6 +342,24 @@ void Codec47Decoder::makeTables47(int width) { } while (c < 32768); } +#ifdef USE_ARM_SMUSH_ASM + +extern "C" void ARM_Smush_decode2( byte *dst, + const byte *src, + int width, + int height, + const byte *param_ptr, + int16 *_table, + byte *_tableBig, + int32 offset1, + int32 offset2, + byte *_tableSmall); + +#define decode2(SRC,DST,WIDTH,HEIGHT,PARAM) \ + ARM_Smush_decode2(SRC,DST,WIDTH,HEIGHT,PARAM,_table,_tableBig, \ + _offset1,_offset2,_tableSmall) + +#else void Codec47Decoder::level3(byte *d_dst) { int32 tmp; byte code = *_d_src++; @@ -503,6 +521,7 @@ void Codec47Decoder::decode2(byte *dst, const byte *src, int width, int height, dst += next_line; } while (--bh); } +#endif Codec47Decoder::Codec47Decoder(int width, int height) { _width = width; diff --git a/engines/scumm/smush/codec47ARM.s b/engines/scumm/smush/codec47ARM.s new file mode 100644 index 0000000000..d96049a32c --- /dev/null +++ b/engines/scumm/smush/codec47ARM.s @@ -0,0 +1,372 @@ +@ 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:$ +@ +@ @author Robin Watts (robin@wss.co.uk) +@ +@ This file, provides an ARM optimised version of sections of codec47.cpp. +@ The algorithm is essentially the same as that within codec47.cpp +@ so to understand this file you should understand codec47.cpp first. + + .text + + .global ARM_Smush_decode2 + +ARM_Smush_decode2: + @ r0 = dst + @ r1 = src + @ r2 = width + @ r3 = height + @ r4 = param + @ <> = _table + @ <> = _tableBig + @ <> = _offset1 + @ <> = _offset2 + @ <> = _tableSmall + STMFD r13!,{r2,r4-r11,R14} + + LDR r4,[r13,#(9+1)*4] @ r4 = param + @ stall + @ stall + SUB r4,r4,#0xF8 + + @ r0 = dst + @ r1 = _d_src + @ r2 = _d_pitch + @ r3 = height + @ r4 = param + ADD r7,r2,#7 @ r14 = bw + MOV r7,r7,LSR #3 +y_loop: +x_loop: + @ LEVEL 1 + LDRB r6,[r1],#1 @ r6 = *_d_src++ + @ stall + @ stall + CMP r6,#0xF8 + BLT level1codeSMALL + CMP r6,#0xFC + BLT level1codeMID + BEQ level1codeFC + CMP r6,#0xFE + BGT level1codeFF + BEQ level1codeFE +level1codeFD: + LDRB r6,[r1],#1 @ r6 = tmp = *_d_src++ + LDR r8,[r13,#(9+1+2)*4] @ r8 = _tableBig + @ stall + ADD r12,r6,r6,LSL #1 @ r12= tmp*3 + ADD r6,r6,r12,LSL #5 @ r6 = tmp*97 + ADD r8,r8,r6,LSL #2 @ r8 = _tableBig + tmp*388 + LDRB r9,[r8,#384] @ r9 = l = tmp_ptr[384] + LDRB r6,[r1],#1 @ r6 = val = *_d_src++ + ADD r12,r8,#384 @ r12= &tmp_ptr[384] + @ I don't really believe the next 2 lines are necessary, but... + CMP r9,#0 + BEQ level1codeFD_over1 +level1codeFD_loop1: + LDRB r10,[r8],#1 + LDRB r11,[r8],#1 + SUBS r9,r9,#1 + ADD r10,r10,r0 + STRB r6,[r10,r11,LSL #8] @ *(_d_dst + (*tmp_ptr2++)) = val + BGT level1codeFD_loop1 +level1codeFD_over1: + LDRB r9,[r12,#1] @ r9 = l = tmp_ptr[385] + LDRB r6,[r1],#1 @ r6 = val = *_d_src++ + SUB r12,r12,#384-128 @ r12= &tmp_ptr[128] + @ I don't really believe the next 2 lines are necessary, but... + CMP r9,#0 + BEQ level1codeFD_over2 +level1codeFD_loop2: + LDRB r10,[r12],#1 + LDRB r11,[r12],#1 + SUBS r9,r9,#1 + ADD r10,r10,r0 + STRB r6,[r10,r11,LSL #8] @ *(_d_dst + (*tmp_ptr2++)) = val + BGT level1codeFD_loop2 +level1codeFD_over2: +level1_end: + + ADD r0,r0,#8 + SUBS r7,r7,#1 + BGT x_loop + + ADD r7,r2,#7 + MOV r7,r7,LSR #3 + ADD r0,r0,r2,LSL #3 + SUB r0,r0,r7,LSL #3 @ r0 = dst += next_line + SUBS r3,r3,#8 @ if (--bh > 0) + BGT y_loop @ loop back + + LDMFD r13!,{r2,r4-r11,PC} + +level1codeSMALL: + LDR r8,[r13,#(9+1+1)*4] @ r8 = _table + LDR r9,[r13,#(9+1+3)*4] @ r9 = _offset1 + MOV r6,r6,LSL #1 @ r6 = code<<1 + LDRSH r8,[r8,r6] @ tmp2 = _table[code] +level1codeFC: + @ EQ => FC + LDREQ r9,[r13,#(9+1+4)*4] @ r9 = _offset2 + MOVEQ r8,#0 + SUB r11,r2,#7 @ r11 = _d_pitch-7 + ADD r9,r9,r0 @ tmp2 = _d_dst+_offset + ADD r8,r8,r9 @ tmp2 = _d_dst+_table[code]+_offset + @ r8 = &_dst[tmp2] + MOV r12,#8 +level1codeSMALL_loop: + LDRB r5, [r8],#1 @ r5 = d_dst[tmp2] + LDRB r6, [r8],#1 @ r10 = d_dst[tmp2] + LDRB r9, [r8],#1 @ r10 = d_dst[tmp2] + LDRB r10,[r8],#1 @ r10 = d_dst[tmp2] + STRB r5, [r0],#1 @ d_dst[0] = r5 + STRB r6, [r0],#1 @ d_dst[1] = r6 + STRB r9, [r0],#1 @ d_dst[2] = r9 + STRB r10,[r0],#1 @ d_dst[3] = r10 + LDRB r5, [r8],#1 @ r5 = d_dst[tmp2] + LDRB r6, [r8],#1 @ r10 = d_dst[tmp2] + LDRB r9, [r8],#1 @ r10 = d_dst[tmp2] + LDRB r10,[r8],r11 @ r10 = d_dst[tmp2] + STRB r5, [r0],#1 @ d_dst[4] = r5 + STRB r6, [r0],#1 @ d_dst[5] = r6 + STRB r9, [r0],#1 @ d_dst[6] = r9 + STRB r10,[r0],r11 @ d_dst[7] = r10 d_dst += d_pitch + SUBS r12,r12,#1 + BGT level1codeSMALL_loop + SUB r0,r0,r2,LSL #3 @ revert d_dst + B level1_end + +level1codeMID: + @ LT => F8<=code<FC case + @ EQ => FE case + LDRB r6,[r4,r6] @ r6 = t = _paramPtr[code] +level1codeFE: + LDREQB r6,[r1],#1 @ r6 = t = *_d_src++ + MOV r12,#8 + SUB r11,r2,#7 @ r11 = _d_pitch-7 +level1codeMID_loop: + STRB r6,[r0],#1 + STRB r6,[r0],#1 + STRB r6,[r0],#1 + STRB r6,[r0],#1 + STRB r6,[r0],#1 + STRB r6,[r0],#1 + STRB r6,[r0],#1 + STRB r6,[r0],r11 + SUBS r12,r12,#1 + BGT level1codeMID_loop + SUB r0,r0,r2,LSL #3 @ revert d_dst + B level1_end + +level1codeFF: + BL level2 + ADD r0,r0,#4 + BL level2 + ADD r0,r0,r2,LSL #2 + SUB r0,r0,#4 + BL level2 + ADD r0,r0,#4 + BL level2 + SUB r0,r0,#4 + SUB r0,r0,r2,LSL #2 + B level1_end + +level2: + @ r0 = _d_dst + @ r1 = _d_src + @ r2 = _d_pitch + @ r3 = PRESERVE + @ r4 = param + @ r7 = PRESERVE + @ r14= return address + LDRB r6,[r1],#1 @ r6 = *_d_src++ + @ stall + @ stall + CMP r6,#0xF8 + BLT level2codeSMALL + CMP r6,#0xFC + BLT level2codeMID + BEQ level2codeFC + CMP r6,#0xFE + BGT level2codeFF + BEQ level2codeFE +level2codeFD: + LDRB r6,[r1],#1 @ r6 = tmp = *_d_src++ + LDR r8,[r13,#(9+1+5)*4] @ r8 = _tableSmall + @ stall + @ stall + ADD r8,r8,r6,LSL #7 @ r8 = _tableSmall + tmp*128 + LDRB r9,[r8,#96] @ r9 = l = tmp_ptr[96] + LDRB r6,[r1],#1 @ r6 = val = *_d_src++ + ADD r12,r8,#32 @ r12 = tmp_ptr + 32 + @ I don't really believe the next 2 lines are necessary, but... + CMP r9,#0 + BEQ level2codeFD_over1 +level2codeFD_loop1: + LDRB r10,[r8],#1 + LDRB r11,[r8],#1 + SUBS r9,r9,#1 + ADD r10,r10,r0 + STRB r6,[r10,r11,LSL #8] @ *(_d_dst + (*tmp_ptr2++)) = val + BGT level2codeFD_loop1 +level2codeFD_over1: + LDRB r9,[r12,#97-32] @ r9 = l = tmp_ptr[97] + LDRB r6,[r1],#1 @ r6 = val = *_d_src++ + @ I don't really believe the next 2 lines are necessary, but... + CMP r9,#0 + MOVEQ PC,R14 +level2codeFD_loop2: + LDRB r10,[r12],#1 + LDRB r11,[r12],#1 + SUBS r9,r9,#1 + ADD r10,r10,r0 + STRB r6,[r10,r11,LSL #8] @ *(_d_dst + (*tmp_ptr2++)) = val + BGT level2codeFD_loop2 + + MOV PC,R14 + +level2codeSMALL: + LDR r8,[r13,#(9+1+1)*4] @ r8 = _table + LDR r9,[r13,#(9+1+3)*4] @ r9 = _offset1 + MOV r6,r6,LSL #1 @ r6 = code<<1 + LDRSH r8,[r8,r6] @ tmp2 = _table[code] +level2codeFC: + @ EQ => FC + LDREQ r9,[r13,#(9+1+4)*4] @ r9 = _offset2 + MOVEQ r8,#0 + SUB r11,r2,#3 @ r11 = _d_pitch-3 + ADD r9,r9,r0 @ tmp2 = _d_dst + _table[code] + ADD r8,r8,r9 @ tmp2 = _d_dst+_table[code]+_offset1 + @ r8 = &_dst[tmp2] + MOV r12,#4 +level2codeSMALL_loop: + LDRB r5, [r8],#1 @ r5 = d_dst[tmp2] + LDRB r6, [r8],#1 @ r10 = d_dst[tmp2] + LDRB r9, [r8],#1 @ r10 = d_dst[tmp2] + LDRB r10,[r8],r11 @ r10 = d_dst[tmp2] + STRB r5, [r0],#1 @ d_dst[4] = r5 + STRB r6, [r0],#1 @ d_dst[5] = r6 + STRB r9, [r0],#1 @ d_dst[6] = r9 + STRB r10,[r0],r11 @ d_dst[7] = r10 d_dst += d_pitch + SUBS r12,r12,#1 + BGT level2codeSMALL_loop + SUB r0,r0,r2,LSL #2 @ revert d_dst + MOV PC,R14 + +level2codeMID: + @ LT => F8<=code<FC case + @ EQ => FE case + LDRB r6,[r4,r6] @ r6 = t = _paramPtr[code] +level2codeFE: + LDREQB r6,[r1],#1 @ r6 = t = *_d_src++ + MOV r12,#4 + SUB r11,r2,#3 @ r11 = _d_pitch-7 +level2codeMID_loop: + STRB r6,[r0],#1 + STRB r6,[r0],#1 + STRB r6,[r0],#1 + STRB r6,[r0],r11 + SUBS r12,r12,#1 + BGT level2codeMID_loop + SUB r0,r0,r2,LSL #2 @ revert d_dst + MOV PC,R14 + +level2codeFF: + MOV r5,r14 + BL level3 + ADD r0,r0,#2 + BL level3 + ADD r0,r0,r2,LSL #1 + SUB r0,r0,#2 + BL level3 + ADD r0,r0,#2 + BL level3 + SUB r0,r0,#2 + SUB r0,r0,r2,LSL #1 + MOV PC,R5 + +level3: + @ r0 = _d_dst + @ r1 = _d_src + @ r2 = _d_pitch + @ r3 = PRESERVE + @ r4 = param + @ r5 = preserve + @ r7 = PRESERVE + @ r14= return address + LDRB r6,[r1],#1 @ r6 = code = *_d_src++ + @ stall + @ stall + CMP r6,#0xF8 + BLT level3codeSMALL + CMP r6,#0xFC + BLT level3codeMID + BEQ level3codeFC + CMP r6,#0xFE + BGT level3codeFF +level3codeFE: + LDRB r6,[r1],#1 @ r6 = t = *_d_src++ +level3codeMID: + @ LT => F8<=code<FC case + @ EQ => FE case + LDRLTB r6,[r4,r6] @ r6 = t = _paramPtr[code] + @ stall + @ stall + STRB r6,[r0,#1] + STRB r6,[r0],r2 + STRB r6,[r0,#1] + STRB r6,[r0],-r2 + MOV PC,R14 + +level3codeFF: + LDRB r6,[r1],#1 + LDRB r9,[r1],#1 + LDRB r10,[r1],#1 + LDRB r11,[r1],#1 + STRB r9, [r0,#1] + STRB r6, [r0],r2 + STRB r11,[r0,#1] + STRB r10,[r0],-r2 + MOV PC,R14 + +level3codeSMALL: + LDR r8,[r13,#(9+1+1)*4] @ r8 = _table + LDR r9,[r13,#(9+1+3)*4] @ r9 = _offset1 + MOV r6,r6,LSL #1 @ r6 = code<<1 + LDRSH r8,[r8,r6] @ tmp2 = _table[code] +level3codeFC: + @ EQ => FC + LDREQ r9,[r13,#(9+1+4)*4] @ r9 = _offset2 + MOVEQ r8,#0 + ADD r9,r9,r0 @ tmp2 = _d_dst+offset + ADD r8,r8,r9 @ tmp2 = _d_dst+_table[code]+_offset + @ r8 = &_dst[tmp2] + LDRB r6, [r8,#1] @ r6 = d_dst[tmp2+1] + LDRB r9, [r8],r2 @ r9 = d_dst[tmp2+0] + LDRB r10,[r8,#1] @ r10= d_dst[tmp2+dst+1] + LDRB r11,[r8],-r2 @ r11= d_dst[tmp2+dst] + STRB r6, [r0,#1] @ d_dst[1 ] = r6 + STRB r9, [r0],r2 @ d_dst[0 ] = r9 + STRB r10,[r0,#1] @ d_dst[dst+1] = r10 + STRB r11,[r0],-r2 @ d_dst[dst ] = r11 + MOV PC,R14 diff --git a/engines/scumm/verbs.cpp b/engines/scumm/verbs.cpp index edd8004d30..56ee454240 100644 --- a/engines/scumm/verbs.cpp +++ b/engines/scumm/verbs.cpp @@ -385,7 +385,7 @@ void ScummEngine_v2::checkV2Inventory(int x, int y) { runObject(_activeInventory, _activeVerb); } } else { - runInputScript(3, object, 0); + runInputScript(kInventoryClickArea, object, 0); } } } @@ -537,7 +537,7 @@ void ScummEngine::checkExecVerbs() { if (vs->verbid && vs->saveid == 0 && vs->curmode == 1) { if (_mouseAndKeyboardStat == vs->key) { // Trigger verb as if the user clicked it - runInputScript(1, vs->verbid, 1); + runInputScript(kVerbClickArea, vs->verbid, 1); return; } } @@ -580,14 +580,14 @@ void ScummEngine::checkExecVerbs() { // Check if person is available (see script 23 from ZAK_FM-TOWNS and script 4 from ZAK_PC). // Zak: Var[144 Bit 15], Annie: Var[145 Bit 0], Melissa: Var[145 Bit 1], Leslie: Var[145 Bit 2] if (!readVar(0x890E + fKey)) { - runInputScript(1, 36 + fKey, 0); + runInputScript(kVerbClickArea, 36 + fKey, 0); } } return; } // Generic keyboard input - runInputScript(4, _mouseAndKeyboardStat, 1); + runInputScript(kKeyClickArea, _mouseAndKeyboardStat, 1); } else if (_mouseAndKeyboardStat & MBS_MOUSE_MASK) { VirtScreen *zone = findVirtScreen(_mouse.y); byte code = _mouseAndKeyboardStat & MBS_LEFT_CLICK ? 1 : 2; @@ -600,7 +600,7 @@ void ScummEngine::checkExecVerbs() { if (_game.version <= 2 && zone->number == kVerbVirtScreen && _mouse.y <= zone->topline + 8) { // Click into V2 sentence line - runInputScript(5, 0, 0); + runInputScript(kSentenceClickArea, 0, 0); } else if (_game.version <= 2 && zone->number == kVerbVirtScreen && _mouse.y > zone->topline + inventoryArea) { // Click into V2 inventory ((ScummEngine_v2 *)this)->checkV2Inventory(_mouse.x, _mouse.y); @@ -608,10 +608,10 @@ void ScummEngine::checkExecVerbs() { over = findVerbAtPos(_mouse.x, _mouse.y); if (over != 0) { // Verb was clicked - runInputScript(1, _verbs[over].verbid, code); + runInputScript(kVerbClickArea, _verbs[over].verbid, code); } else { // Scene was clicked - runInputScript((zone->number == kMainVirtScreen) ? 2 : 1, 0, code); + runInputScript((zone->number == kMainVirtScreen) ? kSceneClickArea : kVerbClickArea, 0, code); } } } diff --git a/engines/scumm/verbs.h b/engines/scumm/verbs.h index 47fa98a9de..96a49a7ced 100644 --- a/engines/scumm/verbs.h +++ b/engines/scumm/verbs.h @@ -30,6 +30,18 @@ namespace Scumm { +/** + * The area in which some click (or key press) occured and which is passed + * to the input script. + */ +enum ClickArea { + kVerbClickArea = 1, + kSceneClickArea = 2, + kInventoryClickArea = 3, + kKeyClickArea = 4, + kSentenceClickArea = 5 +}; + enum { kTextVerbType = 0, kImageVerbType = 1 diff --git a/engines/sky/music/mt32music.cpp b/engines/sky/music/mt32music.cpp index 4f816c6856..2be19a0651 100644 --- a/engines/sky/music/mt32music.cpp +++ b/engines/sky/music/mt32music.cpp @@ -120,7 +120,7 @@ bool MT32Music::processPatchSysEx(uint8 *sysExData) { crc -= sysExBuf[cnt]; sysExBuf[14] = crc & 0x7F; // crc _midiDrv->sysEx(sysExBuf, 15); - g_system->delayMillis(5); + g_system->delayMillis(40); return true; } @@ -170,7 +170,7 @@ void MT32Music::startDriver(void) { sendBuf[len] = crc & 0x7F; len++; _midiDrv->sysEx(sendBuf, len); - g_system->delayMillis (5); + g_system->delayMillis(40); } while (processPatchSysEx(sysExData)) diff --git a/engines/sky/sound.cpp b/engines/sky/sound.cpp index cf769cb3e9..c0dc227718 100644 --- a/engines/sky/sound.cpp +++ b/engines/sky/sound.cpp @@ -46,13 +46,13 @@ struct RoomList { uint8 room; uint8 adlibVolume; uint8 rolandVolume; -}; +} PACKED_STRUCT; struct Sfx { uint8 soundNo; uint8 flags; RoomList roomList[10]; -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/sky/struc.h b/engines/sky/struc.h index 25f0b3d772..cd7155f282 100644 --- a/engines/sky/struc.h +++ b/engines/sky/struc.h @@ -55,7 +55,7 @@ struct dataFileHeader { int16 s_offset_x; int16 s_offset_y; uint16 s_compressed_size; -}; +} PACKED_STRUCT; struct TurnTable { uint16 turnTableUp[5]; @@ -63,7 +63,7 @@ struct TurnTable { uint16 turnTableLeft[5]; uint16 turnTableRight[5]; uint16 turnTableTalk[5]; -}; +} PACKED_STRUCT; struct MegaSet { uint16 gridWidth; // 0 @@ -82,7 +82,7 @@ struct MegaSet { uint16 standRightId; // 11 uint16 standTalkId; // 12 uint16 turnTableId; // 13 -}; +} PACKED_STRUCT; struct Compact { uint16 logic; // 0: Entry in logic table to run (byte as <256entries in logic table @@ -165,7 +165,7 @@ struct Compact { MegaSet megaSet1; // MegaSet megaSet2; // MegaSet megaSet3; // -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/sword1/control.cpp b/engines/sword1/control.cpp index 1ebfaedb2e..c5b968aabe 100644 --- a/engines/sword1/control.cpp +++ b/engines/sword1/control.cpp @@ -650,14 +650,7 @@ bool Control::getConfirm(const uint8 *title) { } bool Control::keyAccepted(uint16 ascii) { - // this routine needs changes for Czech keys... No idea how to do that, though. - // FIXME: It is not a good idea to put non-ASCII chars into a C source file, - // since there is no way to specify which encoding you are using. - // It is better to encode them as hex/octal. Although in this particular - // case, it seems questionable to do this at all, since we currently - // do not at all specify which encoding keyboard events use, so this - // check here is probably not portable anyway... - static const char allowedSpecials[] = "éèáàúùäöüÄÖÜß,.:-()?! \"\'"; + static const char allowedSpecials[] = ",.:-()?! \"\'"; if (((ascii >= 'A') && (ascii <= 'Z')) || ((ascii >= 'a') && (ascii <= 'z')) || ((ascii >= '0') && (ascii <= '9')) || diff --git a/engines/sword1/mouse.h b/engines/sword1/mouse.h index 92b26c3573..f2c800d63b 100644 --- a/engines/sword1/mouse.h +++ b/engines/sword1/mouse.h @@ -60,7 +60,7 @@ struct MousePtr { uint16 hotSpotX; uint16 hotSpotY; uint8 dummyData[0x30]; -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/sword1/object.h b/engines/sword1/object.h index ba65002918..87cbce7b84 100644 --- a/engines/sword1/object.h +++ b/engines/sword1/object.h @@ -40,7 +40,7 @@ namespace Sword1 { struct OEventSlot { //receiving event list in the compact - int32 o_event; //array of these with O_TOTAL_EVENTS elements int32 o_event_script; -}; // size = 2*int32 = 8 bytes +} PACKED_STRUCT; // size = 2*int32 = 8 bytes #define TOTAL_script_levels 5 @@ -48,12 +48,12 @@ struct ScriptTree { //this is a logic tree, used by OBJECTs int32 o_script_level; //logic level int32 o_script_id[TOTAL_script_levels]; //script id's (are unique to each level) int32 o_script_pc[TOTAL_script_levels]; //pc of script for each (if script_manager) -}; // size = 11*int32 = 44 bytes +} PACKED_STRUCT; // size = 11*int32 = 44 bytes struct TalkOffset { int32 x; int32 y; -}; // size = 2*int32 = 8 bytes +} PACKED_STRUCT; // size = 2*int32 = 8 bytes struct WalkData { int32 frame; @@ -61,7 +61,7 @@ struct WalkData { int32 y; int32 step; int32 dir; -}; // size = 5*int32 = 20 bytes +} PACKED_STRUCT; // size = 5*int32 = 20 bytes struct Object { int32 o_type; // 0 broad description of type - object, floor, etc. @@ -119,7 +119,7 @@ struct Object { WalkData o_route[O_WALKANIM_SIZE]; // 340 size = 600*20 bytes = 12000 // mega size = 12340 bytes (+ 8 byte offset table + 20 byte header = 12368) -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/sword1/router.h b/engines/sword1/router.h index 67be8d0593..60456cc5c8 100644 --- a/engines/sword1/router.h +++ b/engines/sword1/router.h @@ -44,7 +44,7 @@ struct BarData { int16 dx; // x2 - x1 int16 dy; // y2 - y1 int32 co; // co = (y1*dx) - (x1*dy) from an equation for a line y*dx = x*dy + co -}; +} PACKED_STRUCT; struct NodeData { int16 x; @@ -52,7 +52,7 @@ struct NodeData { int16 level; int16 prev; int16 dist; -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp index 4d8601a0d8..492672fad8 100644 --- a/engines/sword1/sound.cpp +++ b/engines/sword1/sound.cpp @@ -33,6 +33,7 @@ #include "sword1/logic.h" #include "sword1/sword1.h" +#include "sound/flac.h" #include "sound/mp3.h" #include "sound/vorbis.h" #include "sound/wave.h" @@ -197,10 +198,10 @@ bool Sound::startSpeech(uint16 roomNo, uint16 localNo) { if (data) _mixer->playRaw(Audio::Mixer::kSpeechSoundType, &_speechHandle, data, size, 11025, SPEECH_FLAGS, SOUND_SPEECH_ID, speechVol, speechPan); } -#ifdef USE_MAD - else if (_cowMode == CowMp3) { +#ifdef USE_FLAC + else if (_cowMode == CowFlac) { _cowFile.seek(index); - _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, Audio::makeMP3Stream(&_cowFile, sampleSize), SOUND_SPEECH_ID, speechVol, speechPan); + _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, Audio::makeFlacStream(&_cowFile, sampleSize), SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) @@ -212,6 +213,19 @@ bool Sound::startSpeech(uint16 roomNo, uint16 localNo) { else if (_cowMode == CowVorbis) { _cowFile.seek(index); _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, Audio::makeVorbisStream(&_cowFile, sampleSize), SOUND_SPEECH_ID, speechVol, speechPan); + // with compressed audio, we can't calculate the wave volume. + // so default to talking. + for (int cnt = 0; cnt < 480; cnt++) + _waveVolume[cnt] = true; + _waveVolPos = 0; + } +#endif +#ifdef USE_MAD + else if (_cowMode == CowMp3) { + _cowFile.seek(index); + _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, Audio::makeMP3Stream(&_cowFile, sampleSize), SOUND_SPEECH_ID, speechVol, speechPan); + // with compressed audio, we can't calculate the wave volume. + // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; @@ -332,6 +346,16 @@ void Sound::initCowSystem(void) { /* look for speech1/2.clu in the data dir and speech/speech.clu (running from cd or using cd layout) */ +#ifdef USE_FLAC + if (!_cowFile.isOpen()) { + sprintf(cowName, "SPEECH%d.CLF", SwordEngine::_systemVars.currentCD); + _cowFile.open(cowName); + if (_cowFile.isOpen()) { + debug(1, "Using Flac compressed Speech Cluster"); + _cowMode = CowFlac; + } + } +#endif #ifdef USE_VORBIS if (!_cowFile.isOpen()) { sprintf(cowName, "SPEECH%d.CLV", SwordEngine::_systemVars.currentCD); diff --git a/engines/sword1/sound.h b/engines/sword1/sound.h index fb608a9631..fafc9c2d06 100644 --- a/engines/sword1/sound.h +++ b/engines/sword1/sound.h @@ -66,8 +66,9 @@ class ResMan; enum CowMode { CowWave = 0, - CowMp3, + CowFlac, CowVorbis, + CowMp3, CowDemo }; diff --git a/engines/sword1/staticres.cpp b/engines/sword1/staticres.cpp index 366e2c7608..08e6a108c4 100644 --- a/engines/sword1/staticres.cpp +++ b/engines/sword1/staticres.cpp @@ -5158,7 +5158,7 @@ const FxDef Sound::_fxList[312] = { }, }, //------------------------ - // 198 Ambient sound for Montfauçon Square + // 198 Ambient sound for Montfaucon Square { FX_MONTAMB, // sampleId FX_LOOP, // type diff --git a/engines/sword1/sword1.cpp b/engines/sword1/sword1.cpp index d899d25df5..b5152f33bc 100644 --- a/engines/sword1/sword1.cpp +++ b/engines/sword1/sword1.cpp @@ -355,14 +355,18 @@ const CdFile SwordEngine::_pcCdFileList[] = { { "cows.mad", FLAG_DEMO }, { "speech1.clu", FLAG_SPEECH1 }, { "speech2.clu", FLAG_SPEECH2 } -#ifdef USE_MAD - ,{ "speech1.cl3", FLAG_SPEECH1 }, - { "speech2.cl3", FLAG_SPEECH2 } +#ifdef USE_FLAC + ,{ "speech1.clf", FLAG_SPEECH1 }, + { "speech2.clf", FLAG_SPEECH2 } #endif #ifdef USE_VORBIS ,{ "speech1.clv", FLAG_SPEECH1 }, { "speech2.clv", FLAG_SPEECH2 } #endif +#ifdef USE_MAD + ,{ "speech1.cl3", FLAG_SPEECH1 }, + { "speech2.cl3", FLAG_SPEECH2 } +#endif }; const CdFile SwordEngine::_macCdFileList[] = { @@ -383,14 +387,18 @@ const CdFile SwordEngine::_macCdFileList[] = { { "text.clm", FLAG_CD1 | FLAG_DEMO }, { "speech1.clu", FLAG_SPEECH1 }, { "speech2.clu", FLAG_SPEECH2 } -#ifdef USE_MAD - ,{ "speech1.cl3", FLAG_SPEECH1 }, - { "speech2.cl3", FLAG_SPEECH2 } +#ifdef USE_FLAC + ,{ "speech1.clf", FLAG_SPEECH1 }, + { "speech2.clf", FLAG_SPEECH2 } #endif #ifdef USE_VORBIS ,{ "speech1.clv", FLAG_SPEECH1 }, { "speech2.clv", FLAG_SPEECH2 } #endif +#ifdef USE_MAD + ,{ "speech1.cl3", FLAG_SPEECH1 }, + { "speech2.cl3", FLAG_SPEECH2 } +#endif }; diff --git a/engines/sword1/sworddefs.h b/engines/sword1/sworddefs.h index aedc38ef7e..e90eafe825 100644 --- a/engines/sword1/sworddefs.h +++ b/engines/sword1/sworddefs.h @@ -100,7 +100,7 @@ struct Header { uint32 comp_length; char compression[4]; uint32 decomp_length; -}; +} PACKED_STRUCT; struct FrameHeader { uint8 runTimeComp[4]; @@ -115,25 +115,25 @@ struct ParallaxHeader { char type[16]; uint16 sizeX; uint16 sizeY; -}; +} PACKED_STRUCT; struct AnimUnit { uint32 animX; uint32 animY; uint32 animFrame; -}; +} PACKED_STRUCT; struct AnimSet { uint32 cdt; uint32 spr; -}; +} PACKED_STRUCT; struct WalkGridHeader { int32 scaleA; int32 scaleB; int32 numBars; int32 numNodes; -}; +} PACKED_STRUCT; #include "common/pack-end.h" // END STRUCT PACKING diff --git a/engines/touche/ui.cpp b/engines/touche/ui.cpp index ef8f5a0d7d..15dc64aaf2 100644 --- a/engines/touche/ui.cpp +++ b/engines/touche/ui.cpp @@ -381,6 +381,11 @@ void ToucheEngine::handleOptions(int forceDisplay) { } } } + if (doRedraw) { + redrawMenu(&menuData); + updateScreenArea(90, 102, 460, 196); + doRedraw = false; + } Common::Event event; while (_eventMan->pollEvent(event)) { const Button *button = 0; @@ -419,11 +424,6 @@ void ToucheEngine::handleOptions(int forceDisplay) { break; } } - if (doRedraw) { - redrawMenu(&menuData); - updateScreenArea(90, 102, 460, 196); - doRedraw = false; - } _system->updateScreen(); _system->delayMillis(10); } |