mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-16 22:58:09 +00:00
f94153f07a
op_getInventoryItem/op_setInventoryItem could operate on inventoryItems[4] while inventoryItems has only 4 elements. This effectively accesses the 'money' field right behind this array. Due to a broken assert, this was never detected. This commit fixes it by redirecting accesses to inventoryItems[4] to money, and also fixes the assert. An alternative solution would have been enlarging the array, and removing the money field, but that would require more changes in the engine.
1057 lines
29 KiB
C++
1057 lines
29 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "common/system.h"
|
|
|
|
#include "touche/touche.h"
|
|
|
|
namespace Touche {
|
|
|
|
void ToucheEngine::setupOpcodes() {
|
|
static const OpcodeProc opcodesTable[] = {
|
|
/* 0x00 */
|
|
&ToucheEngine::op_nop,
|
|
&ToucheEngine::op_jnz,
|
|
&ToucheEngine::op_jz,
|
|
&ToucheEngine::op_jmp,
|
|
/* 0x04 */
|
|
&ToucheEngine::op_true,
|
|
&ToucheEngine::op_false,
|
|
&ToucheEngine::op_push,
|
|
&ToucheEngine::op_not,
|
|
/* 0x08 */
|
|
&ToucheEngine::op_add,
|
|
&ToucheEngine::op_sub,
|
|
&ToucheEngine::op_mul,
|
|
&ToucheEngine::op_div,
|
|
/* 0x0C */
|
|
&ToucheEngine::op_mod,
|
|
&ToucheEngine::op_and,
|
|
&ToucheEngine::op_or,
|
|
&ToucheEngine::op_neg,
|
|
/* 0x10 */
|
|
&ToucheEngine::op_testGreater,
|
|
&ToucheEngine::op_testEquals,
|
|
&ToucheEngine::op_testLower,
|
|
&ToucheEngine::op_fetchScriptWord,
|
|
/* 0x14 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
/* 0x18 */
|
|
&ToucheEngine::op_testGreaterOrEquals,
|
|
&ToucheEngine::op_testLowerOrEquals,
|
|
&ToucheEngine::op_testNotEquals,
|
|
&ToucheEngine::op_endConversation,
|
|
/* 0x1C */
|
|
&ToucheEngine::op_stopScript,
|
|
&ToucheEngine::op_getFlag,
|
|
&ToucheEngine::op_setFlag,
|
|
0,
|
|
/* 0x20 */
|
|
0,
|
|
0,
|
|
0,
|
|
&ToucheEngine::op_fetchScriptByte,
|
|
/* 0x24 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
/* 0x28 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
/* 0x2C */
|
|
0,
|
|
0,
|
|
&ToucheEngine::op_getKeyCharWalkBox,
|
|
&ToucheEngine::op_startSound,
|
|
/* 0x30 */
|
|
&ToucheEngine::op_moveKeyCharToPos,
|
|
0,
|
|
0,
|
|
0,
|
|
/* 0x34 */
|
|
&ToucheEngine::op_loadRoom,
|
|
&ToucheEngine::op_updateRoom,
|
|
&ToucheEngine::op_startTalk,
|
|
&ToucheEngine::op_setKeyCharBox,
|
|
/* 0x38 */
|
|
&ToucheEngine::op_initKeyCharScript,
|
|
&ToucheEngine::op_loadSprite,
|
|
&ToucheEngine::op_loadSequence,
|
|
&ToucheEngine::op_setKeyCharFrame,
|
|
/* 0x3C */
|
|
&ToucheEngine::op_setKeyCharDirection,
|
|
&ToucheEngine::op_clearConversationChoices,
|
|
&ToucheEngine::op_addConversationChoice,
|
|
&ToucheEngine::op_removeConversationChoice,
|
|
/* 0x40 */
|
|
&ToucheEngine::op_getInventoryItem,
|
|
&ToucheEngine::op_setInventoryItem,
|
|
&ToucheEngine::op_startEpisode,
|
|
&ToucheEngine::op_setConversationNum,
|
|
/* 0x44 */
|
|
0,
|
|
&ToucheEngine::op_enableInput,
|
|
&ToucheEngine::op_disableInput,
|
|
&ToucheEngine::op_faceKeyChar,
|
|
/* 0x48 */
|
|
&ToucheEngine::op_getKeyCharCurrentAnim,
|
|
&ToucheEngine::op_getCurrentKeyChar,
|
|
&ToucheEngine::op_isKeyCharActive,
|
|
&ToucheEngine::op_setPalette,
|
|
/* 0x4C */
|
|
&ToucheEngine::op_changeWalkPath,
|
|
&ToucheEngine::op_lockWalkPath,
|
|
&ToucheEngine::op_initializeKeyChar,
|
|
&ToucheEngine::op_setupWaitingKeyChars,
|
|
/* 0x50 */
|
|
&ToucheEngine::op_updateRoomAreas,
|
|
&ToucheEngine::op_unlockWalkPath,
|
|
0,
|
|
&ToucheEngine::op_addItemToInventoryAndRedraw,
|
|
/* 0x54 */
|
|
&ToucheEngine::op_giveItemTo,
|
|
&ToucheEngine::op_setHitBoxText,
|
|
&ToucheEngine::op_fadePalette,
|
|
0,
|
|
/* 0x58 */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
/* 0x5C */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
/* 0x60 */
|
|
0,
|
|
&ToucheEngine::op_getInventoryItemFlags,
|
|
&ToucheEngine::op_drawInventory,
|
|
&ToucheEngine::op_stopKeyCharScript,
|
|
/* 0x64 */
|
|
&ToucheEngine::op_restartKeyCharScript,
|
|
&ToucheEngine::op_getKeyCharCurrentWalkBox,
|
|
&ToucheEngine::op_getKeyCharPointsDataNum,
|
|
&ToucheEngine::op_setupFollowingKeyChar,
|
|
/* 0x68 */
|
|
&ToucheEngine::op_startAnimation,
|
|
&ToucheEngine::op_setKeyCharTextColor,
|
|
0,
|
|
0,
|
|
/* 0x6C */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
/* 0x70 */
|
|
&ToucheEngine::op_startMusic,
|
|
0,
|
|
&ToucheEngine::op_sleep,
|
|
0,
|
|
/* 0x74 */
|
|
&ToucheEngine::op_setKeyCharDelay,
|
|
&ToucheEngine::op_lockHitBox,
|
|
&ToucheEngine::op_removeItemFromInventory,
|
|
&ToucheEngine::op_unlockHitBox,
|
|
/* 0x78 */
|
|
&ToucheEngine::op_addRoomArea,
|
|
&ToucheEngine::op_setKeyCharFlags,
|
|
0,
|
|
0,
|
|
/* 0x7C */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
/* 0x80 */
|
|
&ToucheEngine::op_unsetKeyCharFlags,
|
|
&ToucheEngine::op_drawSpriteOnBackdrop,
|
|
&ToucheEngine::op_loadSpeechSegment,
|
|
0,
|
|
/* 0x84 */
|
|
&ToucheEngine::op_startPaletteFadeIn,
|
|
&ToucheEngine::op_startPaletteFadeOut,
|
|
&ToucheEngine::op_setRoomAreaState
|
|
};
|
|
|
|
_opcodesTable = opcodesTable;
|
|
_numOpcodes = ARRAYSIZE(opcodesTable);
|
|
}
|
|
|
|
void ToucheEngine::op_nop() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_nop()");
|
|
}
|
|
|
|
void ToucheEngine::op_jnz() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_jnz()");
|
|
if (*_script.stackDataPtr != 0) {
|
|
_script.dataOffset = _script.readNextWord();
|
|
} else {
|
|
_script.dataOffset += 2;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_jz() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_jz()");
|
|
if (*_script.stackDataPtr == 0) {
|
|
_script.dataOffset = _script.readNextWord();
|
|
} else {
|
|
_script.dataOffset += 2;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_jmp() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_jmp()");
|
|
_script.dataOffset = _script.readNextWord();
|
|
}
|
|
|
|
void ToucheEngine::op_true() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_true()");
|
|
*_script.stackDataPtr = -1;
|
|
}
|
|
|
|
void ToucheEngine::op_false() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_false()");
|
|
*_script.stackDataPtr = 0;
|
|
}
|
|
|
|
void ToucheEngine::op_push() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_push()");
|
|
--_script.stackDataPtr;
|
|
*_script.stackDataPtr = 0;
|
|
}
|
|
|
|
void ToucheEngine::op_not() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_not()");
|
|
if (*_script.stackDataPtr == 0) {
|
|
*_script.stackDataPtr = -1;
|
|
} else {
|
|
*_script.stackDataPtr = 0;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_add() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_add()");
|
|
int16 val = *_script.stackDataPtr++;
|
|
*_script.stackDataPtr += val;
|
|
}
|
|
|
|
void ToucheEngine::op_sub() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_sub()");
|
|
int16 val = *_script.stackDataPtr++;
|
|
*_script.stackDataPtr -= val;
|
|
}
|
|
|
|
void ToucheEngine::op_mul() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_mul()");
|
|
int16 val = *_script.stackDataPtr++;
|
|
*_script.stackDataPtr *= val;
|
|
}
|
|
|
|
void ToucheEngine::op_div() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_div()");
|
|
int16 val = *_script.stackDataPtr++;
|
|
if (val != 0) {
|
|
*_script.stackDataPtr /= val;
|
|
} else {
|
|
*_script.stackDataPtr = 0;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_mod() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_mod()");
|
|
int16 val = *_script.stackDataPtr++;
|
|
if (val != 0) {
|
|
*_script.stackDataPtr %= val;
|
|
} else {
|
|
*_script.stackDataPtr = 0;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_and() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_and()");
|
|
uint16 val = *_script.stackDataPtr++;
|
|
*_script.stackDataPtr &= val;
|
|
}
|
|
|
|
void ToucheEngine::op_or() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_or()");
|
|
uint16 val = *_script.stackDataPtr++;
|
|
*_script.stackDataPtr |= val;
|
|
}
|
|
|
|
void ToucheEngine::op_neg() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_neg()");
|
|
uint16 val = *_script.stackDataPtr;
|
|
*_script.stackDataPtr = ~val;
|
|
}
|
|
|
|
void ToucheEngine::op_testGreater() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_testGreater()");
|
|
int16 val = *_script.stackDataPtr++;
|
|
if (val > *_script.stackDataPtr) {
|
|
*_script.stackDataPtr = -1;
|
|
} else {
|
|
*_script.stackDataPtr = 0;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_testEquals() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_testEquals()");
|
|
int16 val = *_script.stackDataPtr++;
|
|
if (val == *_script.stackDataPtr) {
|
|
*_script.stackDataPtr = -1;
|
|
} else {
|
|
*_script.stackDataPtr = 0;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_testLower() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_testLower()");
|
|
int16 val = *_script.stackDataPtr++;
|
|
if (val < *_script.stackDataPtr) {
|
|
*_script.stackDataPtr = -1;
|
|
} else {
|
|
*_script.stackDataPtr = 0;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_fetchScriptWord() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_fetchScriptWord()");
|
|
int16 val = _script.readNextWord();
|
|
*_script.stackDataPtr = val;
|
|
}
|
|
|
|
void ToucheEngine::op_testGreaterOrEquals() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_testGreaterOrEquals()");
|
|
int16 val = *_script.stackDataPtr++;
|
|
if (val >= *_script.stackDataPtr) {
|
|
*_script.stackDataPtr = -1;
|
|
} else {
|
|
*_script.stackDataPtr = 0;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_testLowerOrEquals() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_testLowerOrEquals()");
|
|
int16 val = *_script.stackDataPtr++;
|
|
if (val <= *_script.stackDataPtr) {
|
|
*_script.stackDataPtr = -1;
|
|
} else {
|
|
*_script.stackDataPtr = 0;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_testNotEquals() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_testNotEquals()");
|
|
int16 val = *_script.stackDataPtr++;
|
|
if (val != *_script.stackDataPtr) {
|
|
*_script.stackDataPtr = -1;
|
|
} else {
|
|
*_script.stackDataPtr = 0;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_endConversation() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_endConversation()");
|
|
_script.quitFlag = 1;
|
|
_conversationEnded = true;
|
|
_disabledInputCounter = 0;
|
|
}
|
|
|
|
void ToucheEngine::op_stopScript() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_stopScript()");
|
|
_script.quitFlag = 1;
|
|
}
|
|
|
|
void ToucheEngine::op_getFlag() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_getFlag()");
|
|
uint16 fl = _script.readNextWord();
|
|
*_script.stackDataPtr = _flagsTable[fl];
|
|
}
|
|
|
|
void ToucheEngine::op_setFlag() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setFlag()");
|
|
uint16 flag = _script.readNextWord();
|
|
int16 val = *_script.stackDataPtr;
|
|
_flagsTable[flag] = val;
|
|
switch (flag) {
|
|
case 104:
|
|
_currentKeyCharNum = val;
|
|
break;
|
|
case 611:
|
|
if (val != 0)
|
|
quitGame();
|
|
break;
|
|
case 612:
|
|
_flagsTable[613] = getRandomNumber(val);
|
|
break;
|
|
case 614:
|
|
case 615:
|
|
_fullRedrawCounter = 1;
|
|
break;
|
|
case 618:
|
|
showCursor(val == 0);
|
|
break;
|
|
case 619:
|
|
debug(0, "Unknown music flag %d", val);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_fetchScriptByte() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_fetchScriptByte()");
|
|
int16 val = _script.readNextByte();
|
|
*_script.stackDataPtr = val;
|
|
}
|
|
|
|
void ToucheEngine::op_getKeyCharWalkBox() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_getKeyCharWalkBox()");
|
|
int16 keyChar = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
*_script.stackDataPtr = _keyCharsTable[keyChar].walkDataNum;
|
|
}
|
|
|
|
void ToucheEngine::op_startSound() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_startSound()");
|
|
_newSoundNum = _script.readNextWord();
|
|
_newSoundDelay = _script.readNextWord();
|
|
_newSoundPriority = 1;
|
|
}
|
|
|
|
void ToucheEngine::op_moveKeyCharToPos() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_moveKeyCharToPos()");
|
|
int16 keyChar = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
int16 num = _script.readNextWord();
|
|
if (num == -1) {
|
|
num = _script.readNextWord();
|
|
num = _keyCharsTable[num].pointsDataNum;
|
|
}
|
|
sortPointsData(-1, num);
|
|
buildWalkPointsList(keyChar);
|
|
_keyCharsTable[keyChar].flags &= ~0x10;
|
|
if (_script.keyCharNum == keyChar) {
|
|
removeFromTalkTable(_script.keyCharNum);
|
|
_keyCharsTable[keyChar].waitingKeyCharPosTable[0] = -1;
|
|
_keyCharsTable[keyChar].waitingKeyCharPosTable[2] = -1;
|
|
_keyCharsTable[keyChar].waitingKeyChar = _script.keyCharNum;
|
|
_keyCharsTable[keyChar].waitingKeyCharPosTable[1] = num;
|
|
_script.quitFlag = 3;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_loadRoom() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_loadRoom()");
|
|
int16 num = _script.readNextWord();
|
|
res_loadRoom(num);
|
|
}
|
|
|
|
void ToucheEngine::op_updateRoom() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_updateRoom()");
|
|
int16 area = _script.readNextWord();
|
|
updateRoomAreas(area, 0);
|
|
|
|
// Workaround for bug #1618700. Beggar sign (area 25) should be displayed even
|
|
// if Henri isn't present in the room.
|
|
//
|
|
// [00B3] (1D) ST[0] = FLAGS[2]
|
|
// [00B6] (06) PUSH
|
|
// [00B7] (13) ST[0] = 0
|
|
// [00BA] (11) ST[0] = ST[1] == ST[0]
|
|
// [00BB] (02) JZ 0xF6
|
|
// [xxxx] ...
|
|
// [0192] (35) UPDATE_ROOM(16, 0)
|
|
// [0195] (35) UPDATE_ROOM(19, 0)
|
|
|
|
if (_currentEpisodeNum == 91 && area == 19 && _flagsTable[2] != 0) {
|
|
debug(0, "Workaround beggar sign disappearing bug");
|
|
updateRoomAreas(25, 0);
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_startTalk() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_startTalk()");
|
|
int16 keyChar = _script.readNextWord();
|
|
int16 num = _script.readNextWord();
|
|
if (num == 750) {
|
|
return;
|
|
}
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
num += _currentKeyCharNum & 1;
|
|
}
|
|
addToTalkTable(keyChar, num, _script.keyCharNum);
|
|
_script.quitFlag = 3;
|
|
}
|
|
|
|
void ToucheEngine::op_loadSprite() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_loadSprite()");
|
|
int16 index = _script.readNextWord();
|
|
int16 num = _script.readNextWord();
|
|
res_loadSprite(num, index);
|
|
}
|
|
|
|
void ToucheEngine::op_loadSequence() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_loadSequence()");
|
|
int16 index = _script.readNextWord();
|
|
int16 num = _script.readNextWord();
|
|
res_loadSequence(num, index);
|
|
}
|
|
|
|
void ToucheEngine::op_setKeyCharBox() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setKeyCharBox()");
|
|
int16 keyChar = _script.readNextWord();
|
|
int16 num = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
setKeyCharBox(keyChar, num);
|
|
}
|
|
|
|
void ToucheEngine::op_initKeyCharScript() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_initKeyCharScript()");
|
|
int16 keyChar = _script.readNextWord();
|
|
int16 color = _script.readNextWord();
|
|
int16 f1 = _script.readNextWord();
|
|
int16 f2 = _script.readNextWord();
|
|
int16 f3 = _script.readNextWord();
|
|
setKeyCharTextColor(keyChar, color);
|
|
initKeyCharScript(keyChar, f1, f2, f3);
|
|
|
|
// Workaround for bug #1622114. KeyChar 3 script must be running in order to complete the
|
|
// rope+torch puzzle.
|
|
//
|
|
// FLAG[500] : 1 if Cardinal cutscene has already been played
|
|
// FLAG[501] : 1 if cathedral is lightened (by the two torches)
|
|
//
|
|
// [00D3] (38) INIT_KEY_CHAR_SCRIPT(keychar=1, 254, 1, 1, 0)
|
|
|
|
if (_currentEpisodeNum == 109 && keyChar == 1 && _flagsTable[500] == 1 && _flagsTable[501] == 1 && _keyCharsTable[3].scriptDataOffset == 0) {
|
|
debug(0, "Workaround disappearing rope bug");
|
|
initKeyCharScript(3, 3, 3, 0);
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_setKeyCharFrame() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setKeyCharFrame()");
|
|
int16 keyChar = _script.readNextWord();
|
|
int16 val1 = _script.readNextWord();
|
|
int16 val2 = _script.readNextWord();
|
|
int16 val3 = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
setKeyCharFrame(keyChar, val1, val2, val3);
|
|
}
|
|
|
|
void ToucheEngine::op_setKeyCharDirection() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setKeyCharDirection()");
|
|
int16 keyChar = _script.readNextWord();
|
|
int16 dir = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
setKeyCharFacingDirection(keyChar, dir);
|
|
}
|
|
|
|
void ToucheEngine::op_clearConversationChoices() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_clearConversationChoices()");
|
|
clearConversationChoices();
|
|
}
|
|
|
|
void ToucheEngine::op_addConversationChoice() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_addConversationChoice()");
|
|
int16 num = _script.readNextWord();
|
|
addConversationChoice(num);
|
|
}
|
|
|
|
void ToucheEngine::op_removeConversationChoice() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_removeConversationChoice()");
|
|
int16 num = _script.readNextWord();
|
|
removeConversationChoice(num);
|
|
}
|
|
|
|
void ToucheEngine::op_getInventoryItem() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_getInventoryItem()");
|
|
int16 keyChar = _script.readNextWord();
|
|
uint16 item = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
|
|
if (item == 4) {
|
|
// item 4 is the 'money' field
|
|
*_script.stackDataPtr = _keyCharsTable[keyChar].money;
|
|
} else {
|
|
assert(item < ARRAYSIZE(_keyCharsTable[keyChar].inventoryItems));
|
|
*_script.stackDataPtr = _keyCharsTable[keyChar].inventoryItems[item];
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_setInventoryItem() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setInventoryItem()");
|
|
int16 keyChar = _script.readNextWord();
|
|
uint16 item = _script.readNextWord();
|
|
if (item == 4) {
|
|
setKeyCharMoney();
|
|
}
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
|
|
if (item == 4) {
|
|
// item 4 is the 'money' field
|
|
_keyCharsTable[keyChar].money = *_script.stackDataPtr;
|
|
} else {
|
|
assert(item < ARRAYSIZE(_keyCharsTable[keyChar].inventoryItems));
|
|
_keyCharsTable[keyChar].inventoryItems[item] = *_script.stackDataPtr;
|
|
}
|
|
if (item == 4 && !_hideInventoryTexts) {
|
|
drawAmountOfMoneyInInventory();
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_startEpisode() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_startEpisode()");
|
|
_newEpisodeNum = _script.readNextWord();
|
|
_flagsTable[0] = _script.readNextWord();
|
|
_disabledInputCounter = 1;
|
|
_script.quitFlag = 1;
|
|
}
|
|
|
|
void ToucheEngine::op_setConversationNum() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setConversationNum()");
|
|
_conversationNum = _script.readNextWord();
|
|
}
|
|
|
|
void ToucheEngine::op_enableInput() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_enableInput()");
|
|
++_disabledInputCounter;
|
|
}
|
|
|
|
void ToucheEngine::op_disableInput() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_disableInput()");
|
|
if (_disabledInputCounter != 0) {
|
|
--_disabledInputCounter;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_faceKeyChar() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_faceKeyChar()");
|
|
int16 keyChar1 = _script.readNextWord();
|
|
int16 keyChar2 = _script.readNextWord();
|
|
if (keyChar1 == 256) {
|
|
keyChar1 = _currentKeyCharNum;
|
|
}
|
|
if (_keyCharsTable[keyChar1].xPos <= _keyCharsTable[keyChar2].xPos) {
|
|
_keyCharsTable[keyChar2].facingDirection = 3;
|
|
} else {
|
|
_keyCharsTable[keyChar2].facingDirection = 0;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_getKeyCharCurrentAnim() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_getKeyCharCurrentAnim()");
|
|
int16 keyChar = _script.readNextWord();
|
|
assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
|
|
*_script.stackDataPtr = _keyCharsTable[keyChar].currentAnim;
|
|
}
|
|
|
|
void ToucheEngine::op_getCurrentKeyChar() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_getCurrentKeyChar()");
|
|
*_script.stackDataPtr = _currentKeyCharNum;
|
|
}
|
|
|
|
void ToucheEngine::op_isKeyCharActive() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_isKeyCharActive()");
|
|
int16 keyChar = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
|
|
*_script.stackDataPtr = _keyCharsTable[keyChar].num != 0 ? 1 : 0;
|
|
}
|
|
|
|
void ToucheEngine::op_setPalette() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setPalette()");
|
|
int16 r = _script.readNextWord();
|
|
int16 g = _script.readNextWord();
|
|
int16 b = _script.readNextWord();
|
|
setPalette(0, 240, r, g, b);
|
|
}
|
|
|
|
void ToucheEngine::op_changeWalkPath() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_changeWalkPath()");
|
|
int16 num1 = _script.readNextWord();
|
|
int16 num2 = _script.readNextWord();
|
|
int16 val = _script.readNextWord();
|
|
changeWalkPath(num1, num2, val);
|
|
}
|
|
|
|
void ToucheEngine::op_lockWalkPath() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_lockWalkPath()");
|
|
int16 num1 = _script.readNextWord();
|
|
int16 num2 = _script.readNextWord();
|
|
lockWalkPath(num1, num2);
|
|
}
|
|
|
|
void ToucheEngine::op_initializeKeyChar() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_initializeKeyChar()");
|
|
int16 keyChar = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
initKeyChars(keyChar);
|
|
}
|
|
|
|
void ToucheEngine::op_setupWaitingKeyChars() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setupWaitingKeyChars()");
|
|
int16 keyChar = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
int16 val1 = _script.readNextWord();
|
|
int16 val2 = _script.readNextWord();
|
|
if (val1 == -1) {
|
|
_waitingSetKeyCharNum2 = keyChar;
|
|
_waitingSetKeyCharNum1 = val2;
|
|
_waitingSetKeyCharNum3 = _script.keyCharNum;
|
|
_script.quitFlag = 3;
|
|
} else {
|
|
_keyCharsTable[_script.keyCharNum].waitingKeyCharPosTable[0] = -1;
|
|
_keyCharsTable[_script.keyCharNum].waitingKeyCharPosTable[1] = -1;
|
|
_keyCharsTable[_script.keyCharNum].waitingKeyCharPosTable[2] = -1;
|
|
_keyCharsTable[_script.keyCharNum].waitingKeyChar = keyChar;
|
|
assert(val1 >= 0 && val1 < 3);
|
|
_keyCharsTable[_script.keyCharNum].waitingKeyCharPosTable[val1] = val2;
|
|
_script.quitFlag = 3;
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_updateRoomAreas() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_updateRoomAreas()");
|
|
int16 area = _script.readNextWord();
|
|
updateRoomAreas(area, 1);
|
|
}
|
|
|
|
void ToucheEngine::op_unlockWalkPath() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_unlockWalkPath()");
|
|
int16 num1 = _script.readNextWord();
|
|
int16 num2 = _script.readNextWord();
|
|
unlockWalkPath(num1, num2);
|
|
}
|
|
|
|
void ToucheEngine::op_addItemToInventoryAndRedraw() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_addItemToInventoryAndRedraw()");
|
|
int16 keyChar = _script.readNextWord();
|
|
int16 item = *_script.stackDataPtr;
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
|
|
// Workaround for bug #1623356. The original script allows you to either use the
|
|
// "waxy knife" (object 72) or the dagger (object 7) on the rope. But in both
|
|
// situations, only the dagger is put back in the inventory.
|
|
//
|
|
// [1A35] (1D) ST[0] = FLAGS[119]
|
|
// [1A38] (06) PUSH
|
|
// [1A39] (13) ST[0] = 7
|
|
// [1A3C] (11) ST[0] = ST[1] == ST[0]
|
|
// [1A3D] (06) PUSH
|
|
// [1A3E] (1D) ST[0] = FLAGS[119]
|
|
// [1A41] (06) PUSH
|
|
// [1A42] (13) ST[0] = 72
|
|
// [1A45] (11) ST[0] = ST[1] == ST[0]
|
|
// [1A46] (0E) OR
|
|
// [1A47] (02) JZ 0x1B1B
|
|
// [xxxx] ...
|
|
// [1B05] (13) ST[0] = 7
|
|
// [1B08] (53) ADD_ITEM_TO_INVENTORY_AND_REDRAW(keychar=1)
|
|
|
|
if (_currentEpisodeNum == 92 && keyChar == 1 && item == 7) {
|
|
if (_flagsTable[119] == 72) {
|
|
debug(0, "Workaround waxy knife not re-appearing in the inventory");
|
|
item = 72;
|
|
}
|
|
}
|
|
|
|
addItemToInventory(keyChar, item);
|
|
if (_currentKeyCharNum == keyChar && !_hideInventoryTexts) {
|
|
drawInventory(_currentKeyCharNum, 1);
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_giveItemTo() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_giveItemTo()");
|
|
_giveItemToCounter = 1;
|
|
_giveItemToObjectNum = _script.readNextWord();
|
|
_giveItemToKeyCharNum = _script.keyCharNum;
|
|
_script.quitFlag = 3;
|
|
}
|
|
|
|
void ToucheEngine::op_setHitBoxText() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setHitBoxText()");
|
|
int16 num = _script.readNextWord();
|
|
if (num & 0x4000) {
|
|
num &= 0xFF;
|
|
_keyCharsTable[num].strNum = 1;
|
|
} else {
|
|
for (uint i = 0; i < _programHitBoxTable.size(); ++i) {
|
|
if (_programHitBoxTable[i].item == num) {
|
|
_programHitBoxTable[i].str = _programHitBoxTable[i].defaultStr;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_fadePalette() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_fadePalette()");
|
|
int16 fadeOut = _script.readNextWord();
|
|
int colorsCount = 240;
|
|
// Workaround for bug #1751149. Script triggers a palette fading, but some
|
|
// of the room graphics use palette colors >= 240.
|
|
if (_currentEpisodeNum == 104 && _currentRoomNum == 68) {
|
|
colorsCount = 256;
|
|
}
|
|
if (fadeOut) {
|
|
fadePalette(0, colorsCount, 255, -2, 128);
|
|
} else {
|
|
fadePalette(0, colorsCount, 0, 2, 128);
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_getInventoryItemFlags() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_getInventoryItemFlags()");
|
|
int16 item = _script.readNextWord();
|
|
int16 flags = _inventoryItemsInfoTable[item];
|
|
if (flags & 0x10) {
|
|
flags &= 0xF;
|
|
} else {
|
|
flags &= ~0xF;
|
|
}
|
|
*_script.stackDataPtr = flags;
|
|
}
|
|
|
|
void ToucheEngine::op_drawInventory() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_drawInventory()");
|
|
int16 num = _script.readNextWord();
|
|
drawInventory(num, 1);
|
|
}
|
|
|
|
void ToucheEngine::op_stopKeyCharScript() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_stopKeyCharScript()");
|
|
int16 keyChar = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
|
|
_keyCharsTable[keyChar].flags |= kScriptStopped;
|
|
}
|
|
|
|
void ToucheEngine::op_restartKeyCharScript() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_restartKeyCharScript()");
|
|
int16 keyChar = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
|
|
KeyChar *key = &_keyCharsTable[keyChar];
|
|
key->flags &= ~(kScriptStopped | kScriptPaused);
|
|
key->scriptDataOffset = key->scriptDataStartOffset;
|
|
key->scriptStackPtr = &key->scriptStackTable[39];
|
|
}
|
|
|
|
void ToucheEngine::op_getKeyCharCurrentWalkBox() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_getKeyCharCurrentWalkBox()");
|
|
int16 keyChar = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
|
|
*_script.stackDataPtr = _keyCharsTable[keyChar].currentWalkBox;
|
|
}
|
|
|
|
void ToucheEngine::op_getKeyCharPointsDataNum() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_getKeyCharPointsDataNum()");
|
|
int16 keyChar = _script.readNextWord();
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
|
|
*_script.stackDataPtr = _keyCharsTable[keyChar].pointsDataNum;
|
|
}
|
|
|
|
void ToucheEngine::op_setupFollowingKeyChar() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setupFollowingKeyChar()");
|
|
int16 val = _script.readNextWord();
|
|
int16 keyChar = _script.readNextWord();
|
|
assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
|
|
_keyCharsTable[keyChar].followingKeyCharNum = val;
|
|
_keyCharsTable[keyChar].flags |= 0x10;
|
|
_keyCharsTable[keyChar].followingKeyCharPos = -1;
|
|
}
|
|
|
|
void ToucheEngine::op_startAnimation() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_startAnimation()");
|
|
int16 keyChar = _script.readNextWord();
|
|
int16 pos = _script.readNextWord();
|
|
int16 num = *_script.stackDataPtr;
|
|
addToAnimationTable(num, pos, keyChar, 3);
|
|
}
|
|
|
|
void ToucheEngine::op_setKeyCharTextColor() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setKeyCharTextColor()");
|
|
int16 keyChar = _script.readNextWord();
|
|
uint16 color = _script.readNextWord();
|
|
setKeyCharTextColor(keyChar, color);
|
|
}
|
|
|
|
void ToucheEngine::op_startMusic() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_startMusic()");
|
|
_newMusicNum = _script.readNextWord();
|
|
}
|
|
|
|
void ToucheEngine::op_sleep() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_sleep()");
|
|
// this should probably be turned into a no-op/debug-op...
|
|
int cycles = _script.readNextWord() * 2;
|
|
if (!_fastMode) {
|
|
for (; cycles > 0; --cycles) {
|
|
_system->delayMillis(kCycleDelay);
|
|
_system->updateScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_setKeyCharDelay() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setKeyCharDelay()");
|
|
int16 delay = _script.readNextWord();
|
|
_keyCharsTable[_script.keyCharNum].delay = delay;
|
|
_script.quitFlag = 3;
|
|
}
|
|
|
|
void ToucheEngine::op_lockHitBox() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_lockHitBox()");
|
|
int16 num = _script.readNextWord();
|
|
lockUnlockHitBox(num, 1);
|
|
}
|
|
|
|
void ToucheEngine::op_removeItemFromInventory() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_removeItemFromInventory()");
|
|
int16 keyChar = _script.readNextWord();
|
|
int16 item = *_script.stackDataPtr;
|
|
if (keyChar == 256) {
|
|
keyChar = _currentKeyCharNum;
|
|
}
|
|
removeItemFromInventory(keyChar, item);
|
|
if (keyChar == _currentKeyCharNum && !_hideInventoryTexts) {
|
|
drawInventory(_currentKeyCharNum, 1);
|
|
}
|
|
}
|
|
|
|
void ToucheEngine::op_unlockHitBox() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_unlockHitBox()");
|
|
int16 num = _script.readNextWord();
|
|
lockUnlockHitBox(num, 0);
|
|
}
|
|
|
|
void ToucheEngine::op_addRoomArea() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_addRoomArea()");
|
|
int16 num = _script.readNextWord();
|
|
uint16 flag = _script.readNextWord();
|
|
addRoomArea(num, flag);
|
|
}
|
|
|
|
void ToucheEngine::op_setKeyCharFlags() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setKeyCharFlags()");
|
|
int16 keyChar = _script.readNextWord();
|
|
uint16 flags = _script.readNextWord();
|
|
flags &= 0xFF00;
|
|
_keyCharsTable[keyChar].flags |= flags;
|
|
}
|
|
|
|
void ToucheEngine::op_unsetKeyCharFlags() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_unsetKeyCharFlags()");
|
|
int16 keyChar = _script.readNextWord();
|
|
uint16 flags = _script.readNextWord();
|
|
flags &= 0xFF00;
|
|
_keyCharsTable[keyChar].flags &= ~flags;
|
|
}
|
|
|
|
void ToucheEngine::op_loadSpeechSegment() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_loadSpeechSegment()");
|
|
int16 num = _script.readNextWord();
|
|
res_loadSpeech(num);
|
|
}
|
|
|
|
void ToucheEngine::op_drawSpriteOnBackdrop() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_drawSpriteOnBackdrop()");
|
|
int16 num = _script.readNextWord();
|
|
int16 x = _script.readNextWord();
|
|
int16 y = _script.readNextWord();
|
|
drawSpriteOnBackdrop(num, x, y);
|
|
}
|
|
|
|
void ToucheEngine::op_startPaletteFadeIn() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_startPaletteFadeIn()");
|
|
_flagsTable[290] = 0;
|
|
_flagsTable[605] = 0;
|
|
_flagsTable[607] = 0;
|
|
_flagsTable[608] = 0xFF;
|
|
_flagsTable[609] = 0xFF;
|
|
_flagsTable[610] = 0;
|
|
_flagsTable[603] = _script.readNextWord();
|
|
}
|
|
|
|
void ToucheEngine::op_startPaletteFadeOut() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_startPaletteFadeOut()");
|
|
_flagsTable[290] = 0;
|
|
_flagsTable[605] = 0xFF;
|
|
_flagsTable[607] = 0;
|
|
_flagsTable[608] = 0xFF;
|
|
_flagsTable[609] = 0xFF;
|
|
_flagsTable[610] = 0;
|
|
_flagsTable[603] = -_script.readNextWord();
|
|
}
|
|
|
|
void ToucheEngine::op_setRoomAreaState() {
|
|
debugC(9, kDebugOpcodes, "ToucheEngine::op_setRoomAreaState()");
|
|
int16 num = _script.readNextWord();
|
|
int16 val = _script.readNextWord();
|
|
setRoomAreaState(num, val);
|
|
}
|
|
|
|
} // namespace Touche
|