mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 13:50:13 +00:00
1059 lines
29 KiB
C++
1059 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;
|
|
default:
|
|
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 #2952. 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 #2962. 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 #2966. 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 #3305. 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
|