/* ScummVM - Scumm Interpreter * Copyright (C) 2001 Ludvig Strigeus * Copyright (C) 2001-2006 The ScummVM project * * 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$ * */ // Item script opcodes for Simon1/Simon2 #include "common/stdafx.h" #include "common/system.h" #include "simon/animation.h" #include "simon/simon.h" #ifdef _WIN32_WCE extern bool isSmartphone(void); #endif namespace Simon { // Opcode table void SimonEngine::setupOpcodes() { // This opcode table is for Simon 1. Changes for Simon 2 and FF are // made below. static OpcodeProc opcode_table[200] = { // 0 - 4 NULL, &SimonEngine::o_at, &SimonEngine::o_notAt, NULL, NULL, // 5 - 9 &SimonEngine::o_carried, &SimonEngine::o_notCarried, &SimonEngine::o_isAt, NULL, NULL, // 10 - 14 NULL, &SimonEngine::o_zero, &SimonEngine::o_notZero, &SimonEngine::o_eq, &SimonEngine::o_notEq, // 15 - 19 &SimonEngine::o_gt, &SimonEngine::o_lt, &SimonEngine::o_eqf, &SimonEngine::o_notEqf, &SimonEngine::o_ltf, // 20 - 24 &SimonEngine::o_gtf, NULL, NULL, &SimonEngine::o_chance, NULL, // 25 - 29 &SimonEngine::o_isRoom, &SimonEngine::o_isObject, &SimonEngine::o_state, &SimonEngine::o_oflag, NULL, // 30 - 34 NULL, &SimonEngine::o_destroy, NULL, &SimonEngine::o_place, NULL, // 35 - 39 NULL, &SimonEngine::o_copyff, NULL, NULL, NULL, // 40 - 44 NULL, &SimonEngine::o_clear, &SimonEngine::o_let, &SimonEngine::o_add, &SimonEngine::o_sub, // 45 - 49 &SimonEngine::o_addf, &SimonEngine::o_subf, &SimonEngine::o_mul, &SimonEngine::o_div, &SimonEngine::o_mulf, // 50 - 54 &SimonEngine::o_divf, &SimonEngine::o_mod, &SimonEngine::o_modf, &SimonEngine::o_random, NULL, // 55 - 59 &SimonEngine::o_goto, &SimonEngine::o_oset, &SimonEngine::o_oclear, &SimonEngine::o_putBy, &SimonEngine::o_inc, // 60 - 64 &SimonEngine::o_dec, &SimonEngine::o_setState, &SimonEngine::o_print, &SimonEngine::o_message, &SimonEngine::o_msg, // 65 - 69 &SimonEngine::o_addTextBox, &SimonEngine::o_setShortText, &SimonEngine::o_setLongText, &SimonEngine::o_end, &SimonEngine::o_done, // 70 - 74 NULL, &SimonEngine::o_process, NULL, NULL, NULL, // 75 - 79 NULL, &SimonEngine::o_when, &SimonEngine::o_if1, &SimonEngine::o_if2, &SimonEngine::o_isCalled, // 80 - 84 &SimonEngine::o_is, NULL, &SimonEngine::o_debug, NULL, NULL, // 85 - 89 NULL, NULL, &SimonEngine::o_comment, &SimonEngine::o_haltAnimation, &SimonEngine::o_restartAnimation, // 90 - 94 &SimonEngine::o_getParent, &SimonEngine::o_getNext, &SimonEngine::o_getChildren, NULL, NULL, // 95 - 99 NULL, &SimonEngine::o_picture, &SimonEngine::o_loadZone, NULL, NULL, // 100 - 104 &SimonEngine::o_killAnimate, &SimonEngine::o_defWindow, &SimonEngine::o_window, &SimonEngine::o_cls, &SimonEngine::o_closeWindow, // 105 - 109 NULL, NULL, &SimonEngine::o_addBox, &SimonEngine::o_delBox, &SimonEngine::o_enableBox, // 110 - 114 &SimonEngine::o_disableBox, &SimonEngine::o_moveBox, NULL, NULL, &SimonEngine::o_doIcons, // 115 - 119 &SimonEngine::o_isClass, &SimonEngine::o_setClass, &SimonEngine::o_unsetClass, NULL, &SimonEngine::o_waitSync, // 120 - 124 &SimonEngine::o_sync, &SimonEngine::o_defObj, NULL, NULL, NULL, // 125 - 129 &SimonEngine::o_here, &SimonEngine::o_doClassIcons, NULL, &SimonEngine::o_waitEndTune, &SimonEngine::o_ifEndTune, // 130 - 134 &SimonEngine::o_setAdjNoun, NULL, &SimonEngine::o_saveUserGame, &SimonEngine::o_loadUserGame, &SimonEngine::o_stopTune, // 135 - 139 &SimonEngine::o_pauseGame, &SimonEngine::o_copysf, &SimonEngine::o_restoreIcons, &SimonEngine::o_freezeZones, &SimonEngine::o_placeNoIcons, // 140 - 144 &SimonEngine::o_clearTimers, &SimonEngine::o_setDollar, &SimonEngine::o_isBox, &SimonEngine::o_doTable, NULL, // 145 - 149 NULL, NULL, NULL, NULL, NULL, // 150 - 154 NULL, &SimonEngine::o_storeItem, &SimonEngine::o_getItem, &SimonEngine::o_bSet, &SimonEngine::o_bClear, // 155 - 159 &SimonEngine::o_bZero, &SimonEngine::o_bNotZero, &SimonEngine::o_getOValue, &SimonEngine::o_setOValue, NULL, // 160 - 164 &SimonEngine::o_ink, &SimonEngine::o_screenTextBox, &SimonEngine::o_screenTextMsg, &SimonEngine::o_playEffect, &SimonEngine::o_getDollar2, // 165 - 169 &SimonEngine::o_isAdjNoun, &SimonEngine::o_b2Set, &SimonEngine::o_b2Clear, &SimonEngine::o_b2Zero, &SimonEngine::o_b2NotZero, // 170 - 174 NULL, NULL, NULL, NULL, NULL, // 175 - 179 &SimonEngine::o_lockZones, &SimonEngine::o_unlockZones, NULL, &SimonEngine::o_getPathPosn, &SimonEngine::o_scnTxtLongText, // 180 - 184 &SimonEngine::o_mouseOn, NULL, NULL, NULL, &SimonEngine::o_unloadZone, // 185 - 189 NULL, &SimonEngine::o_unfreezeZones, NULL, NULL, NULL, // 190 - 194 NULL, NULL, NULL, NULL, NULL, // 195 - 199 NULL, NULL, NULL, NULL, NULL }; _opcode_table = opcode_table; _numOpcodes = ARRAYSIZE(opcode_table); switch (getGameType()) { case GType_ELVIRA: case GType_ELVIRA2: // Confirmed opcode_table[48] = &SimonEngine::o_destroy; opcode_table[51] = &SimonEngine::o_place; opcode_table[91] = &SimonEngine::o_message; opcode_table[70] = &SimonEngine::o1_printLongText; opcode_table[83] = &SimonEngine::o1_rescan; opcode_table[98] = &SimonEngine::o1_animate; opcode_table[99] = &SimonEngine::o1_stopAnimate; opcode_table[85] = &SimonEngine::oww_whereTo; opcode_table[105] = &SimonEngine::oww_menu; opcode_table[106] = &SimonEngine::oww_textMenu; opcode_table[127] = &SimonEngine::o1_playTune; opcode_table[148] = &SimonEngine::oww_ifDoorOpen; opcode_table[179] = &SimonEngine::o_isAdjNoun; opcode_table[180] = &SimonEngine::o_b2Set; opcode_table[181] = &SimonEngine::o_b2Clear; opcode_table[182] = &SimonEngine::o_b2Zero; opcode_table[183] = &SimonEngine::o_b2NotZero; // Code difference, check if triggered opcode_table[161] = NULL; opcode_table[162] = NULL; opcode_table[163] = NULL; opcode_table[164] = NULL; opcode_table[165] = NULL; opcode_table[166] = NULL; opcode_table[167] = NULL; opcode_table[168] = NULL; opcode_table[169] = NULL; opcode_table[170] = NULL; opcode_table[171] = NULL; opcode_table[172] = NULL; opcode_table[173] = NULL; opcode_table[174] = NULL; opcode_table[175] = NULL; opcode_table[176] = NULL; opcode_table[177] = NULL; opcode_table[178] = NULL; opcode_table[184] = NULL; opcode_table[185] = NULL; opcode_table[186] = NULL; opcode_table[187] = NULL; opcode_table[188] = NULL; opcode_table[189] = NULL; opcode_table[190] = NULL; break; case GType_WW: // Confirmed opcode_table[70] = &SimonEngine::o1_printLongText; opcode_table[83] = &SimonEngine::o1_rescan; opcode_table[98] = &SimonEngine::o1_animate; opcode_table[99] = &SimonEngine::o1_stopAnimate; opcode_table[85] = &SimonEngine::oww_whereTo; opcode_table[105] = &SimonEngine::oww_menu; opcode_table[106] = &SimonEngine::oww_textMenu; opcode_table[127] = &SimonEngine::o1_playTune; opcode_table[148] = &SimonEngine::oww_ifDoorOpen; opcode_table[179] = &SimonEngine::o_isAdjNoun; opcode_table[180] = &SimonEngine::o_b2Set; opcode_table[181] = &SimonEngine::o_b2Clear; opcode_table[182] = &SimonEngine::o_b2Zero; opcode_table[183] = &SimonEngine::o_b2NotZero; // Code difference, check if triggered opcode_table[161] = NULL; opcode_table[162] = NULL; opcode_table[163] = NULL; opcode_table[164] = NULL; opcode_table[165] = NULL; opcode_table[166] = NULL; opcode_table[167] = NULL; opcode_table[168] = NULL; opcode_table[169] = NULL; opcode_table[170] = NULL; opcode_table[171] = NULL; opcode_table[172] = NULL; opcode_table[173] = NULL; opcode_table[174] = NULL; opcode_table[175] = NULL; opcode_table[176] = NULL; opcode_table[177] = NULL; opcode_table[178] = NULL; opcode_table[184] = NULL; opcode_table[185] = NULL; opcode_table[186] = NULL; opcode_table[187] = NULL; opcode_table[188] = NULL; opcode_table[189] = NULL; opcode_table[190] = NULL; break; case GType_SIMON1: opcode_table[70] = &SimonEngine::o1_printLongText; opcode_table[83] = &SimonEngine::o1_rescan; opcode_table[98] = &SimonEngine::o1_animate; opcode_table[99] = &SimonEngine::o1_stopAnimate; opcode_table[127] = &SimonEngine::o1_playTune; opcode_table[177] = &SimonEngine::o1_screenTextPObj; opcode_table[181] = &SimonEngine::o1_mouseOff; opcode_table[182] = &SimonEngine::o1_loadBeard; opcode_table[183] = &SimonEngine::o1_unloadBeard; opcode_table[185] = &SimonEngine::o1_loadStrings; opcode_table[187] = &SimonEngine::o1_specialFade; break; case GType_SIMON2: opcode_table[70] = &SimonEngine::o2_printLongText; opcode_table[83] = &SimonEngine::o2_rescan; opcode_table[98] = &SimonEngine::o2_animate; opcode_table[99] = &SimonEngine::o2_stopAnimate; opcode_table[127] = &SimonEngine::o2_playTune; opcode_table[177] = &SimonEngine::o2_screenTextPObj; opcode_table[181] = &SimonEngine::o2_mouseOff; opcode_table[188] = &SimonEngine::o2_isShortText; opcode_table[189] = &SimonEngine::o2_clearMarks; opcode_table[190] = &SimonEngine::o2_waitMark; break; case GType_FF: opcode_table[23] = &SimonEngine::o3_chance; opcode_table[37] = &SimonEngine::o3_jumpOut; opcode_table[65] = &SimonEngine::o3_addTextBox; opcode_table[70] = &SimonEngine::o3_printLongText; opcode_table[83] = &SimonEngine::o2_rescan; opcode_table[98] = &SimonEngine::o2_animate; opcode_table[99] = &SimonEngine::o2_stopAnimate; opcode_table[107] = &SimonEngine::o3_addBox; opcode_table[122] = &SimonEngine::o3_oracleTextDown; opcode_table[123] = &SimonEngine::o3_oracleTextUp; opcode_table[124] = &SimonEngine::o3_ifTime; opcode_table[127] = &SimonEngine::o3_playTune; opcode_table[131] = &SimonEngine::o3_setTime; opcode_table[132] = &SimonEngine::o3_saveUserGame, opcode_table[133] = &SimonEngine::o3_loadUserGame; opcode_table[134] = &SimonEngine::o3_listSaveGames; opcode_table[135] = &SimonEngine::o3_checkCD; opcode_table[161] = &SimonEngine::o3_screenTextBox; opcode_table[165] = &SimonEngine::o3_isAdjNoun; opcode_table[171] = &SimonEngine::o3_hyperLinkOn; opcode_table[172] = &SimonEngine::o3_hyperLinkOff; opcode_table[173] = &SimonEngine::o3_checkPaths; opcode_table[177] = &SimonEngine::o3_screenTextPObj; opcode_table[181] = &SimonEngine::o3_mouseOff; opcode_table[182] = &SimonEngine::o3_loadVideo; opcode_table[183] = &SimonEngine::o3_playVideo; opcode_table[187] = &SimonEngine::o3_centreScroll; opcode_table[188] = &SimonEngine::o2_isShortText; opcode_table[189] = &SimonEngine::o2_clearMarks; opcode_table[190] = &SimonEngine::o2_waitMark; opcode_table[191] = &SimonEngine::o3_resetPVCount; opcode_table[192] = &SimonEngine::o3_setPathValues; opcode_table[193] = &SimonEngine::o3_stopClock; opcode_table[194] = &SimonEngine::o3_restartClock; opcode_table[195] = &SimonEngine::o3_setColour; opcode_table[196] = &SimonEngine::o3_b3Set; opcode_table[197] = &SimonEngine::o3_b3Clear; opcode_table[198] = &SimonEngine::o3_b3Zero; opcode_table[199] = &SimonEngine::o3_b3NotZero; break; case GType_PP: // Confirmed opcode_table[30] = &SimonEngine::o4_opcode30; opcode_table[37] = &SimonEngine::o4_checkTiles; opcode_table[38] = &SimonEngine::o4_opcode38; opcode_table[105] = &SimonEngine::o4_loadHiScores; opcode_table[106] = &SimonEngine::o4_checkHiScores; opcode_table[133] = &SimonEngine::o4_loadUserGame; opcode_table[166] = NULL; opcode_table[167] = NULL; opcode_table[168] = NULL; opcode_table[169] = NULL; opcode_table[173] = &SimonEngine::o4_saveOopsPosition; opcode_table[191] = &SimonEngine::o4_resetPVCount; opcode_table[192] = &SimonEngine::o4_setPathValues; // Code difference, check if triggered opcode_table[132] = &SimonEngine::o3_saveUserGame, opcode_table[187] = &SimonEngine::o4_resetGameTime; // Code difference. Some kind of logging? opcode_table[190] = &SimonEngine::o2_waitMark; // To check opcode_table[23] = &SimonEngine::o3_chance; opcode_table[65] = &SimonEngine::o3_addTextBox; opcode_table[70] = &SimonEngine::o3_printLongText; opcode_table[83] = &SimonEngine::o2_rescan; opcode_table[98] = &SimonEngine::o2_animate; opcode_table[99] = &SimonEngine::o2_stopAnimate; opcode_table[107] = &SimonEngine::o3_addBox; opcode_table[122] = &SimonEngine::o3_oracleTextDown; opcode_table[123] = &SimonEngine::o3_oracleTextUp; opcode_table[124] = &SimonEngine::o3_ifTime; opcode_table[127] = &SimonEngine::o3_playTune; opcode_table[131] = &SimonEngine::o3_setTime; opcode_table[134] = &SimonEngine::o3_listSaveGames; opcode_table[161] = &SimonEngine::o3_screenTextBox; opcode_table[165] = &SimonEngine::o3_isAdjNoun; opcode_table[171] = &SimonEngine::o3_hyperLinkOn; opcode_table[172] = &SimonEngine::o3_hyperLinkOff; opcode_table[177] = &SimonEngine::o3_screenTextPObj; opcode_table[181] = &SimonEngine::o3_mouseOff; opcode_table[188] = &SimonEngine::o2_isShortText; opcode_table[189] = &SimonEngine::o2_clearMarks; opcode_table[193] = &SimonEngine::o3_stopClock; opcode_table[194] = &SimonEngine::o3_restartClock; opcode_table[195] = &SimonEngine::o3_setColour; break; default: error("setupOpcodes: Unknown game"); } } void SimonEngine::setScriptCondition(bool cond) { _runScriptCondition[_recursionDepth] = cond; } bool SimonEngine::getScriptCondition() { return _runScriptCondition[_recursionDepth]; } void SimonEngine::setScriptReturn(int ret) { _runScriptReturn[_recursionDepth] = ret; } int SimonEngine::getScriptReturn() { return _runScriptReturn[_recursionDepth]; } // ----------------------------------------------------------------------- // Common Opcodes // ----------------------------------------------------------------------- void SimonEngine::o_at() { // 1: ptrA parent is setScriptCondition(me()->parent == getNextItemID()); } void SimonEngine::o_notAt() { // 2: ptrA parent is not setScriptCondition(me()->parent != getNextItemID()); } void SimonEngine::o_carried() { // 5: parent is 1 setScriptCondition(getNextItemPtr()->parent == getItem1ID()); } void SimonEngine::o_notCarried() { // 6: parent isnot 1 setScriptCondition(getNextItemPtr()->parent != getItem1ID()); } void SimonEngine::o_isAt() { // 7: parent is Item *item = getNextItemPtr(); setScriptCondition(item->parent == getNextItemID()); } void SimonEngine::o_zero() { // 11: is zero setScriptCondition(getNextVarContents() == 0); } void SimonEngine::o_notZero() { // 12: isnot zero setScriptCondition(getNextVarContents() != 0); } void SimonEngine::o_eq() { // 13: equal uint tmp = getNextVarContents(); setScriptCondition(tmp == getVarOrWord()); } void SimonEngine::o_notEq() { // 14: not equal uint tmp = getNextVarContents(); setScriptCondition(tmp != getVarOrWord()); } void SimonEngine::o_gt() { // 15: is greater uint tmp = getNextVarContents(); setScriptCondition(tmp > getVarOrWord()); } void SimonEngine::o_lt() { // 16: is less uint tmp = getNextVarContents(); setScriptCondition(tmp < getVarOrWord()); } void SimonEngine::o_eqf() { // 17: is eq f uint tmp = getNextVarContents(); setScriptCondition(tmp == getNextVarContents()); } void SimonEngine::o_notEqf() { // 18: is not equal f uint tmp = getNextVarContents(); setScriptCondition(tmp != getNextVarContents()); } void SimonEngine::o_ltf() { // 19: is greater f uint tmp = getNextVarContents(); setScriptCondition(tmp < getNextVarContents()); } void SimonEngine::o_gtf() { // 20: is less f uint tmp = getNextVarContents(); setScriptCondition(tmp > getNextVarContents()); } void SimonEngine::o_chance() { // 23 uint a = getVarOrWord(); if (a == 0) { setScriptCondition(false); return; } if (a == 100) { setScriptCondition(true); return; } a += _chanceModifier; if (a <= 0) { _chanceModifier = 0; setScriptCondition(false); } else if ((uint)_rnd.getRandomNumber(99) < a) { if (_chanceModifier <= 0) _chanceModifier -= 5; else _chanceModifier = 0; setScriptCondition(true); } else { if (_chanceModifier >= 0) _chanceModifier += 5; else _chanceModifier = 0; setScriptCondition(false); } } void SimonEngine::o_isRoom() { // 25: is room setScriptCondition(isRoom(getNextItemPtr())); } void SimonEngine::o_isObject() { // 26: is object setScriptCondition(isObject(getNextItemPtr())); } void SimonEngine::o_state() { // 27: item state is Item *item = getNextItemPtr(); setScriptCondition((uint) item->state == getVarOrWord()); } void SimonEngine::o_oflag() { // 28: item has prop SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); byte num = getVarOrByte(); setScriptCondition(subObject != NULL && (subObject->objectFlags & (1 << num)) != 0); } void SimonEngine::o_destroy() { // 31: set no parent setItemParent(getNextItemPtr(), NULL); } void SimonEngine::o_place() { // 33: set item parent Item *item = getNextItemPtr(); setItemParent(item, getNextItemPtr()); } void SimonEngine::o_copyff() { // 36: copy var uint value = getNextVarContents(); writeNextVarContents(value); } void SimonEngine::o_clear() { // 41: zero var writeNextVarContents(0); } void SimonEngine::o_let() { // 42: set var uint var = getVarWrapper(); writeVariable(var, getVarOrWord()); } void SimonEngine::o_add() { // 43: add uint var = getVarWrapper(); writeVariable(var, readVariable(var) + getVarOrWord()); } void SimonEngine::o_sub() { // 44: sub uint var = getVarWrapper(); writeVariable(var, readVariable(var) - getVarOrWord()); } void SimonEngine::o_addf() { // 45: add f uint var = getVarWrapper(); writeVariable(var, readVariable(var) + getNextVarContents()); } void SimonEngine::o_subf() { // 46: sub f uint var = getVarWrapper(); writeVariable(var, readVariable(var) - getNextVarContents()); } void SimonEngine::o_mul() { // 47: mul uint var = getVarWrapper(); writeVariable(var, readVariable(var) * getVarOrWord()); } void SimonEngine::o_div() { // 48: div uint var = getVarWrapper(); int value = getVarOrWord(); if (value == 0) error("o_div: Division by zero"); writeVariable(var, readVariable(var) / value); } void SimonEngine::o_mulf() { // 49: mul f uint var = getVarWrapper(); writeVariable(var, readVariable(var) * getNextVarContents()); } void SimonEngine::o_divf() { // 50: div f uint var = getVarWrapper(); int value = getNextVarContents(); if (value == 0) error("o_divf: Division by zero"); writeVariable(var, readVariable(var) / value); } void SimonEngine::o_mod() { // 51: mod uint var = getVarWrapper(); int value = getVarOrWord(); if (value == 0) error("o_mod: Division by zero"); writeVariable(var, readVariable(var) % value); } void SimonEngine::o_modf() { // 52: mod f uint var = getVarWrapper(); int value = getNextVarContents(); if (value == 0) error("o_modf: Division by zero"); writeVariable(var, readVariable(var) % value); } void SimonEngine::o_random() { // 53: random uint var = getVarWrapper(); uint value = (uint16)getVarOrWord(); writeVariable(var, _rnd.getRandomNumber(value - 1)); } void SimonEngine::o_goto() { // 55: set itemA parent uint item = getNextItemID(); if (_itemArrayPtr[item] == NULL) { setItemParent(me(), NULL); loadRoomItems(item); } setItemParent(me(), _itemArrayPtr[item]); } void SimonEngine::o_oset() { // 56: set child2 fr bit SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); int value = getVarOrByte(); if (subObject != NULL && value >= 0x10) subObject->objectFlags |= (1 << value); } void SimonEngine::o_oclear() { // 57: clear child2 fr bit SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); int value = getVarOrByte(); if (subObject != NULL && value >= 0x10) subObject->objectFlags &= ~(1 << value); } void SimonEngine::o_putBy() { // 58: make siblings Item *item = getNextItemPtr(); setItemParent(item, derefItem(getNextItemPtr()->parent)); } void SimonEngine::o_inc() { // 59: item inc state Item *item = getNextItemPtr(); if (item->state <= 30000) setItemState(item, item->state + 1); } void SimonEngine::o_dec() { // 60: item dec state Item *item = getNextItemPtr(); if (item->state >= 0) setItemState(item, item->state - 1); } void SimonEngine::o_setState() { // 61: item set state Item *item = getNextItemPtr(); int value = getVarOrWord(); if (value < 0) value = 0; if (value > 30000) value = 30000; setItemState(item, value); } void SimonEngine::o_print() { // 62: show int showMessageFormat("%d", getNextVarContents()); } void SimonEngine::o_message() { // 63: show string nl showMessageFormat("%s\n", getStringPtrByID(getNextStringID())); } void SimonEngine::o_msg() { // 64: show string showMessageFormat("%s", getStringPtrByID(getNextStringID())); } void SimonEngine::o_addTextBox() { // 65: add hit area uint id = getVarOrWord(); uint x = getVarOrWord(); uint y = getVarOrWord(); uint w = getVarOrWord(); uint h = getVarOrWord(); uint number = getVarOrByte(); if (number < _numTextBoxes) defineBox(id, x, y, w, h, (number << 8) + 129, 208, _dummyItem2); } void SimonEngine::o_setShortText() { // 66: set item name uint var = getVarOrByte(); uint stringId = getNextStringID(); if (var < _numTextBoxes) { _shortText[var] = stringId; if (getGameType() == GType_PP) { _shortTextX[var] = getVarOrWord(); _shortTextY[var] = getVarOrWord(); } } } void SimonEngine::o_setLongText() { // 67: set item description uint var = getVarOrByte(); uint stringId = getNextStringID(); if (getFeatures() & GF_TALKIE) { uint speechId = getNextWord(); if (var < _numTextBoxes) { _longText[var] = stringId; _longSound[var] = speechId; } } else { if (var < _numTextBoxes) { _longText[var] = stringId; } } } void SimonEngine::o_end() { // 68: exit interpreter shutdown(); } void SimonEngine::o_done() { // 69: return 1 setScriptReturn(1); } void SimonEngine::o_process() { // 71: start subroutine Subroutine *sub = getSubroutineByID(getVarOrWord()); if (sub != NULL) startSubroutine(sub); } void SimonEngine::o_when() { // 76: add timeout uint timeout = getVarOrWord(); addTimeEvent(timeout, getVarOrWord()); } void SimonEngine::o_if1() { // 77: has item minus 1 setScriptCondition(_subjectItem != NULL); } void SimonEngine::o_if2() { // 78: has item minus 3 setScriptCondition(_objectItem != NULL); } void SimonEngine::o_isCalled() { // 79: childstruct fr2 is SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); uint stringId = getNextStringID(); setScriptCondition((subObject != NULL) && subObject->objectName == stringId); } void SimonEngine::o_is() { // 80: item equal setScriptCondition(getNextItemPtr() == getNextItemPtr()); } void SimonEngine::o_debug() { // 82: debug opcode getVarOrByte(); } void SimonEngine::o_comment() { // 87: comment getNextStringID(); } void SimonEngine::o_haltAnimation() { // 88: stop animation _lockWord |= 0x10; } void SimonEngine::o_restartAnimation() { // 89: restart animation _lockWord &= ~0x10; } void SimonEngine::o_getParent() { // 90: set minusitem to parent Item *item = derefItem(getNextItemPtr()->parent); switch (getVarOrByte()) { case 0: _objectItem = item; break; case 1: _subjectItem = item; break; default: error("o_getParent: invalid subcode"); } } void SimonEngine::o_getNext() { // 91: set minusitem to sibling Item *item = derefItem(getNextItemPtr()->sibling); switch (getVarOrByte()) { case 0: _objectItem = item; break; case 1: _subjectItem = item; break; default: error("o_getNext: invalid subcode"); } } void SimonEngine::o_getChildren() { // 92: set minusitem to child Item *item = derefItem(getNextItemPtr()->child); switch (getVarOrByte()) { case 0: _objectItem = item; break; case 1: _subjectItem = item; break; default: error("o_getChildren: invalid subcode"); } } void SimonEngine::o_picture() { // 96 uint vga_res = getVarOrWord(); uint mode = getVarOrByte(); if (mode == 4) vc29_stopAllSounds(); if (_lockWord & 0x10) error("o_picture: _lockWord & 0x10"); set_video_mode_internal(mode, vga_res); } void SimonEngine::o_loadZone() { // 97: load vga uint vga_res = getVarOrWord(); _lockWord |= 0x80; loadZone(vga_res); _lockWord &= ~0x80; } void SimonEngine::o_killAnimate() { // 100: vga reset _lockWord |= 0x8000; vc27_resetSprite(); _lockWord &= ~0x8000; } void SimonEngine::o_defWindow() { // 101 uint num = getVarOrByte(); uint x = getVarOrWord(); uint y = getVarOrWord(); uint w = getVarOrWord(); uint h = getVarOrWord(); uint flags = getVarOrWord(); uint fill_color = getVarOrWord(); uint text_color = 0; num &= 7; if (_windowArray[num]) closeWindow(num); _windowArray[num] = openWindow(x, y, w, h, flags, fill_color, text_color); if (num == _curWindow) { _textWindow = _windowArray[num]; if (getGameType() == GType_FF) showmessage_helper_3(_textWindow->textColumn, _textWindow->width); else showmessage_helper_3(_textWindow->textLength, _textWindow->textMaxLength); } } void SimonEngine::o_window() { // 102 changeWindow(getVarOrByte() & 7); } void SimonEngine::o_cls() { // 103 mouseOff(); removeIconArray(_curWindow); showMessageFormat("\x0C"); _oracleMaxScrollY = 0; _noOracleScroll = 0; mouseOn(); } void SimonEngine::o_closeWindow() { // 104 closeWindow(getVarOrByte() & 7); } void SimonEngine::o_addBox() { // 107: add item hitarea uint flags = 0; uint id = getVarOrWord(); uint params = id / 1000; uint x, y, w, h, verb; Item *item; id = id % 1000; if (params & 1) flags |= kBFInvertTouch; if (params & 2) flags |= kBFNoTouchName; if (params & 4) flags |= kBFBoxItem; if (params & 8) flags |= kBFTextBox; if (params & 16) flags |= 0x10; x = getVarOrWord(); y = getVarOrWord(); w = getVarOrWord(); h = getVarOrWord(); item = getNextItemPtrStrange(); verb = getVarOrWord(); if (x >= 1000) { verb += 0x4000; x -= 1000; } defineBox(id, x, y, w, h, flags, verb, item); } void SimonEngine::o_delBox() { // 108: delete hitarea undefineBox(getVarOrWord()); } void SimonEngine::o_enableBox() { // 109: clear hitarea bit 0x40 enableBox(getVarOrWord()); } void SimonEngine::o_disableBox() { // 110: set hitarea bit 0x40 disableBox(getVarOrWord()); } void SimonEngine::o_moveBox() { // 111: set hitarea xy uint hitarea_id = getVarOrWord(); uint x = getVarOrWord(); uint y = getVarOrWord(); moveBox(hitarea_id, x, y); } void SimonEngine::o_doIcons() { // 114 Item *item = getNextItemPtr(); uint num = getVarOrByte(); mouseOff(); drawIconArray(num, item, 0, 0); mouseOn(); } void SimonEngine::o_isClass() { // 115: item has flag Item *item = getNextItemPtr(); setScriptCondition((item->classFlags & (1 << getVarOrByte())) != 0); } void SimonEngine::o_setClass() { // 116: item set flag Item *item = getNextItemPtr(); item->classFlags |= (1 << getVarOrByte()); } void SimonEngine::o_unsetClass() { // 117: item clear flag Item *item = getNextItemPtr(); item->classFlags &= ~(1 << getVarOrByte()); } void SimonEngine::o_waitSync() { // 119: wait vga uint var = getVarOrWord(); _scriptVar2 = (var == 200); if (var != 200 || !_skipVgaWait) waitForSync(var); _skipVgaWait = false; } void SimonEngine::o_sync() { // 120: sync sendSync(getVarOrWord()); } void SimonEngine::o_defObj() { // 121: set vga item uint slot = getVarOrByte(); _objectArray[slot] = getNextItemPtr(); } void SimonEngine::o_here() { // 125: item is sibling with item 1 Item *item = getNextItemPtr(); setScriptCondition(me()->parent == item->parent); } void SimonEngine::o_doClassIcons() { // 126 Item *item = getNextItemPtr(); uint num = getVarOrByte(); uint a = 1 << getVarOrByte(); mouseOff(); drawIconArray(num, item, 1, a); mouseOn(); } void SimonEngine::o_waitEndTune() { // 128: dummy instruction getVarOrWord(); } void SimonEngine::o_ifEndTune() { // 129: dummy instruction getVarOrWord(); setScriptCondition(true); } void SimonEngine::o_setAdjNoun() { // 130: set adj noun uint var = getVarOrByte(); if (var == 1) { _scriptAdj1 = getNextWord(); _scriptNoun1 = getNextWord(); } else { _scriptAdj2 = getNextWord(); _scriptNoun2 = getNextWord(); } } void SimonEngine::o_saveUserGame() { // 132: save game _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); userGame(false); _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); } void SimonEngine::o_loadUserGame() { // 133: load game _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); userGame(true); _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); } void SimonEngine::o_stopTune() { // 134: dummy opcode? midi.stop(); _lastMusicPlayed = -1; } void SimonEngine::o_pauseGame() { // 135: quit if user presses y _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); // If all else fails, use English as fallback. byte keyYes = 'y'; byte keyNo = 'n'; switch (_language) { case Common::RU_RUS: break; case Common::PL_POL: keyYes = 't'; break; case Common::HB_ISR: keyYes = 'f'; break; case Common::ES_ESP: keyYes = 's'; break; case Common::IT_ITA: keyYes = 's'; break; case Common::FR_FRA: keyYes = 'o'; break; case Common::DE_DEU: keyYes = 'j'; break; default: break; } for (;;) { delay(1); #ifdef _WIN32_WCE if (isSmartphone()) { if (_keyPressed) { if (_keyPressed == 13) shutdown(); else break; } } #endif if (_keyPressed == keyYes || _keyPressed == (keyYes - 32)) shutdown(); else if (_keyPressed == keyNo || _keyPressed == (keyNo - 32)) break; } _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); } void SimonEngine::o_copysf() { // 136: set var to item unk3 Item *item = getNextItemPtr(); writeNextVarContents(item->state); } void SimonEngine::o_restoreIcons() { // 137 uint num = getVarOrByte(); WindowBlock *window = _windowArray[num & 7]; if (window->iconPtr) drawIconArray(num, window->iconPtr->itemRef, window->iconPtr->line, window->iconPtr->classMask); } void SimonEngine::o_freezeZones() { // 138: vga pointer op 4 freezeBottom(); } void SimonEngine::o_placeNoIcons() { // 139: set parent special Item *item = getNextItemPtr(); _noParentNotify = true; setItemParent(item, getNextItemPtr()); _noParentNotify = false; } void SimonEngine::o_clearTimers() { // 140: del te and add one killAllTimers(); addTimeEvent(3, 0xA0); } void SimonEngine::o_setDollar() { // 141: set m1 to m3 uint which = getVarOrByte(); Item *item = getNextItemPtr(); if (which == 1) { _subjectItem = item; } else { _objectItem = item; } } void SimonEngine::o_isBox() { // 142: is hitarea 0x40 clear setScriptCondition(isBoxDead(getVarOrWord())); } void SimonEngine::o_doTable() { // 143: start item sub SubRoom *subRoom = (SubRoom *)findChildOfType(getNextItemPtr(), 1); if (subRoom != NULL) { Subroutine *sub = getSubroutineByID(subRoom->subroutine_id); if (sub) startSubroutine(sub); } } void SimonEngine::o_storeItem() { // 151: set array6 to item uint var = getVarOrByte(); Item *item = getNextItemPtr(); _itemStore[var] = item; } void SimonEngine::o_getItem() { // 152: set m1 to m3 to array 6 Item *item = _itemStore[getVarOrByte()]; uint var = getVarOrByte(); if (var == 1) { _subjectItem = item; } else { _objectItem = item; } } void SimonEngine::o_bSet() { // 153: set bit setBitFlag(getVarWrapper(), true); } void SimonEngine::o_bClear() { // 154: clear bit setBitFlag(getVarWrapper(), false); } void SimonEngine::o_bZero() { // 155: is bit clear setScriptCondition(!getBitFlag(getVarWrapper())); } void SimonEngine::o_bNotZero() { // 156: is bit set uint bit = getVarWrapper(); // WORKAROUND: Fix for glitch in some versions if (getGameType() == GType_SIMON1 && _subroutine == 2962 && bit == 63) { bit = 50; } setScriptCondition(getBitFlag(bit)); } void SimonEngine::o_getOValue() { // 157: get item int prop Item *item = getNextItemPtr(); SubObject *subObject = (SubObject *)findChildOfType(item, 2); uint prop = getVarOrByte(); if (subObject != NULL && subObject->objectFlags & (1 << prop) && prop < 16) { uint offs = getOffsetOfChild2Param(subObject, 1 << prop); writeNextVarContents(subObject->objectFlagValue[offs]); } else { writeNextVarContents(0); } } void SimonEngine::o_setOValue() { // 158: set item prop Item *item = getNextItemPtr(); SubObject *subObject = (SubObject *)findChildOfType(item, 2); uint prop = getVarOrByte(); int value = getVarOrWord(); if (subObject != NULL && subObject->objectFlags & (1 << prop) && prop < 16) { uint offs = getOffsetOfChild2Param(subObject, 1 << prop); subObject->objectFlagValue[offs] = value; } } void SimonEngine::o_ink() { // 160 setTextColor(getVarOrByte()); } void SimonEngine::o_screenTextBox() { // 161: setup text TextLocation *tl = getTextLocation(getVarOrByte()); tl->x = getVarOrWord(); tl->y = getVarOrByte(); tl->width = getVarOrWord(); } void SimonEngine::o_screenTextMsg() { // 162: print string uint vgaSpriteId = getVarOrByte(); uint color = getVarOrByte(); uint stringId = getNextStringID(); const byte *string_ptr = NULL; uint speechId = 0; TextLocation *tl; if (stringId != 0xFFFF) string_ptr = getStringPtrByID(stringId); if (getFeatures() & GF_TALKIE) { if (getGameType() == GType_FF || getGameType() == GType_PP) speechId = (uint16)getVarOrWord(); else speechId = (uint16)getNextWord(); } if (getGameType() == GType_FF || getGameType() == GType_PP) vgaSpriteId = 1; tl = getTextLocation(vgaSpriteId); if (_speech && speechId != 0) playSpeech(speechId, vgaSpriteId); if (((getGameType() == GType_SIMON2 && (getFeatures() & GF_TALKIE)) || getGameType() == GType_FF) && speechId == 0) { stopAnimateSimon2(2, vgaSpriteId + 2); } if (string_ptr != NULL && (speechId == 0 || _subtitles)) printScreenText(vgaSpriteId, color, (const char *)string_ptr, tl->x, tl->y, tl->width); } void SimonEngine::o_playEffect() { // 163: play sound uint soundId = getVarOrWord(); if (getGameType() == GType_FF) error("o_playEffect: triggered"); if (getGameId() == GID_SIMON1DOS) playSting(soundId); else _sound->playEffects(soundId); } void SimonEngine::o_getDollar2() { // 164 _showPreposition = true; setup_cond_c_helper(); _objectItem = _hitAreaObjectItem; if (_objectItem == _dummyItem2) _objectItem = me(); if (_objectItem == _dummyItem3) _objectItem = derefItem(me()->parent); if (_objectItem != NULL) { _scriptNoun2 = _objectItem->noun; _scriptAdj2 = _objectItem->adjective; } else { _scriptNoun2 = -1; _scriptAdj2 = -1; } _showPreposition = false; } void SimonEngine::o_isAdjNoun() { // 165: item unk1 unk2 is Item *item = getNextItemPtr(); int16 a = getNextWord(), b = getNextWord(); setScriptCondition(item->adjective == a && item->noun == b); } void SimonEngine::o_b2Set() { // 166: set bit2 uint bit = getVarOrByte(); _bitArrayTwo[bit / 16] |= (1 << (bit & 15)); } void SimonEngine::o_b2Clear() { // 167: clear bit2 uint bit = getVarOrByte(); _bitArrayTwo[bit / 16] &= ~(1 << (bit & 15)); } void SimonEngine::o_b2Zero() { // 168: is bit2 clear uint bit = getVarOrByte(); setScriptCondition((_bitArrayTwo[bit / 16] & (1 << (bit & 15))) == 0); } void SimonEngine::o_b2NotZero() { // 169: is bit2 set uint bit = getVarOrByte(); setScriptCondition((_bitArrayTwo[bit / 16] & (1 << (bit & 15))) != 0); } void SimonEngine::o_lockZones() { // 175: vga pointer op 1 _vgaMemBase = _vgaMemPtr; } void SimonEngine::o_unlockZones() { // 176: vga pointer op 2 _vgaMemPtr = _vgaFrozenBase; _vgaMemBase = _vgaFrozenBase; } void SimonEngine::o_getPathPosn() { // 178: path find uint x = getVarOrWord(); uint y = getVarOrWord(); uint var_1 = getVarOrByte(); uint var_2 = getVarOrByte(); const uint16 *p; uint i, j; uint prev_i; uint x_diff, y_diff; uint best_i = 0, best_j = 0, best_dist = 0xFFFFFFFF; uint maxPath = (getGameType() == GType_FF) ? 100 : 20; if (getGameType() == GType_FF) { x += _scrollX; y += _scrollY; } if (getGameType() == GType_SIMON2) { x += _scrollX * 8; } int end = (getGameType() == GType_FF) ? 9999 : 999; prev_i = maxPath + 1 - readVariable(12); for (i = maxPath; i != 0; --i) { p = (const uint16 *)_pathFindArray[maxPath - i]; if (!p) continue; for (j = 0; readUint16Wrapper(&p[0]) != end; j++, p += 2) { x_diff = ABS((int16)(readUint16Wrapper(&p[0]) - x)); y_diff = ABS((int16)(readUint16Wrapper(&p[1]) - 12 - y)); if (x_diff < y_diff) { x_diff /= 4; y_diff *= 4; } x_diff += y_diff /= 4; if (x_diff < best_dist || x_diff == best_dist && prev_i == i) { best_dist = x_diff; best_i = maxPath + 1 - i; best_j = j; } } } writeVariable(var_1, best_i); writeVariable(var_2, best_j); } void SimonEngine::o_scnTxtLongText() { // 179: conversation responses and room descriptions uint vgaSpriteId = getVarOrByte(); uint color = getVarOrByte(); uint stringId = getVarOrByte(); uint speechId = 0; TextLocation *tl; const char *string_ptr = (const char *)getStringPtrByID(_longText[stringId]); if (getFeatures() & GF_TALKIE) speechId = _longSound[stringId]; if (getGameType() == GType_FF) vgaSpriteId = 1; tl = getTextLocation(vgaSpriteId); if (_speech && speechId != 0) playSpeech(speechId, vgaSpriteId); if (string_ptr != NULL && _subtitles) printScreenText(vgaSpriteId, color, string_ptr, tl->x, tl->y, tl->width); } void SimonEngine::o_mouseOn() { // 180: force mouseOn scriptMouseOn(); } void SimonEngine::o_unloadZone() { // 184: clear vgapointer entry uint a = getVarOrWord(); VgaPointersEntry *vpe = &_vgaBufferPointers[a]; vpe->sfxFile = NULL; vpe->vgaFile1 = NULL; vpe->vgaFile2 = NULL; } void SimonEngine::o_unfreezeZones() { // 186: vga pointer op 3 unfreezeBottom(); } // ----------------------------------------------------------------------- // Waxworks 1 Opcodes // ----------------------------------------------------------------------- void SimonEngine::oww_whereTo() { // 85: where to Item *i = getNextItemPtr(); int16 d = getVarOrByte(); int16 f = getVarOrByte(); if (f == 1) _subjectItem = _itemArrayPtr[getExitOf(i, d)]; else _objectItem = _itemArrayPtr[getExitOf(i, d)]; } void SimonEngine::oww_menu() { // 105: menu getVarOrByte(); } void SimonEngine::oww_textMenu() { // 106: text menu /* byte tmp = getVarOrByte(); TextMenu[tmp] = getVarOrByte(); */ getVarOrByte(); getVarOrByte(); } void SimonEngine::oww_ifDoorOpen() { // 148: if door open Item *item = getNextItemPtr(); uint16 d = getVarOrByte(); setScriptCondition(getDoorState(item, d) != 0); } // ----------------------------------------------------------------------- // Simon 1 Opcodes // ----------------------------------------------------------------------- void SimonEngine::o1_printLongText() { // 70: show string from array const char *str = (const char *)getStringPtrByID(_longText[getVarOrByte()]); showMessageFormat("%s\n", str); } void SimonEngine::o1_rescan() { // 83: restart subroutine setScriptReturn(-10); } void SimonEngine::o1_animate() { // 98: start vga uint vga_res, vgaSpriteId, windowNum, x, y, palette; vgaSpriteId = getVarOrWord(); vga_res = vgaSpriteId / 100; windowNum = getVarOrByte(); x = getVarOrWord(); y = getVarOrWord(); palette = getVarOrWord(); loadSprite(windowNum, vga_res, vgaSpriteId, x, y, palette); } void SimonEngine::o1_stopAnimate() { // 99: kill sprite stopAnimateSimon1(getVarOrWord()); } void SimonEngine::o1_playTune() { // 127: deals with music int music = getVarOrWord(); int track = getVarOrWord(); // Jamieson630: // This appears to be a "load or play music" command. // The music resource is specified, and optionally // a track as well. Normally we see two calls being // made, one to load the resource and another to // actually start a track (so the resource is // effectively preloaded so there's no latency when // starting playback). if (music != _lastMusicPlayed) { _lastMusicPlayed = music; loadMusic(music); midi.startTrack(track); } } void SimonEngine::o1_screenTextPObj() { // 177: inventory descriptions uint vgaSpriteId = getVarOrByte(); uint color = getVarOrByte(); SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); if (getFeatures() & GF_TALKIE) { if (subObject != NULL && subObject->objectFlags & kOFVoice) { uint offs = getOffsetOfChild2Param(subObject, kOFVoice); playSpeech(subObject->objectFlagValue[offs], vgaSpriteId); } else if (subObject != NULL && subObject->objectFlags & kOFNumber) { uint offs = getOffsetOfChild2Param(subObject, kOFNumber); playSpeech(subObject->objectFlagValue[offs] + 3550, vgaSpriteId); } } if (subObject != NULL && subObject->objectFlags & kOFText && _subtitles) { const char *stringPtr = (const char *)getStringPtrByID(subObject->objectFlagValue[0]); TextLocation *tl = getTextLocation(vgaSpriteId); char buf[256]; int j, k; if (subObject->objectFlags & kOFNumber) { if (_language == Common::HB_ISR) { j = subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)]; k = (j % 10) * 10; k += j / 10; if (!(j % 10)) sprintf(buf,"0%d%s", k, stringPtr); else sprintf(buf,"%d%s", k, stringPtr); } else { sprintf(buf,"%d%s", subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)], stringPtr); } stringPtr = buf; } if (stringPtr != NULL) printScreenText(vgaSpriteId, color, stringPtr, tl->x, tl->y, tl->width); } } void SimonEngine::o1_mouseOff() { // 181: force mouseOff scriptMouseOff(); } void SimonEngine::o1_loadBeard() { // 182: load beard if (_beardLoaded == false) { _beardLoaded = true; _lockWord |= 0x8000; loadSimonVGAFile(328); _lockWord &= ~0x8000; } } void SimonEngine::o1_unloadBeard() { // 183: unload beard if (_beardLoaded == true) { _beardLoaded = false; _lockWord |= 0x8000; loadSimonVGAFile(23); _lockWord &= ~0x8000; } } void SimonEngine::o1_loadStrings() { // 185: load sound files _soundFileId = getVarOrWord(); if (getPlatform() == Common::kPlatformAmiga && getFeatures() & GF_TALKIE) { char buf[10]; sprintf(buf, "%d%s", _soundFileId, "Effects"); _sound->readSfxFile(buf); sprintf(buf, "%d%s", _soundFileId, "simon"); _sound->readVoiceFile(buf); } } void SimonEngine::o1_specialFade() { // 187: fade to black uint i; memcpy(_videoBuf1, _currentPalette, 4 * 256); for (i = 32; i != 0; --i) { paletteFadeOut(_videoBuf1, 32, 8); paletteFadeOut(_videoBuf1 + 4 * 48, 144, 8); paletteFadeOut(_videoBuf1 + 4 * 208, 48, 8); _system->setPalette(_videoBuf1, 0, 256); delay(5); } memcpy(_currentPalette, _videoBuf1, 1024); memcpy(_displayPalette, _videoBuf1, 1024); } // ----------------------------------------------------------------------- // Simon 2 Opcodes // ----------------------------------------------------------------------- void SimonEngine::o2_printLongText() { // 70: show string from array const char *str = (const char *)getStringPtrByID(_longText[getVarOrByte()]); writeVariable(51, strlen(str) / 53 * 8 + 8); showMessageFormat("%s\n", str); } void SimonEngine::o2_rescan() { // 83: restart subroutine if (_exitCutscene) { if (getBitFlag(9)) { endCutscene(); } } else { processSpecialKeys(); } setScriptReturn(-10); } void SimonEngine::o2_animate() { // 98: start vga uint vga_res = getVarOrWord(); uint vgaSpriteId = getVarOrWord(); uint windowNum = getVarOrByte(); uint x = getVarOrWord(); uint y = getVarOrWord(); uint palette = getVarOrWord(); loadSprite(windowNum, vga_res, vgaSpriteId, x, y, palette); } void SimonEngine::o2_stopAnimate() { // 99: kill sprite uint a = getVarOrWord(); uint b = getVarOrWord(); stopAnimateSimon2(a, b); } void SimonEngine::o2_playTune() { // 127: deals with music int music = getVarOrWord(); int track = getVarOrWord(); int loop = getVarOrByte(); // Jamieson630: // This appears to be a "load or play music" command. // The music resource is specified, and optionally // a track as well. Normally we see two calls being // made, one to load the resource and another to // actually start a track (so the resource is // effectively preloaded so there's no latency when // starting playback). midi.setLoop(loop != 0); if (_lastMusicPlayed != music) _nextMusicToPlay = music; else midi.startTrack(track); } void SimonEngine::o2_screenTextPObj() { // 177: inventory descriptions uint vgaSpriteId = getVarOrByte(); uint color = getVarOrByte(); SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); if (getFeatures() & GF_TALKIE) { if (subObject != NULL && subObject->objectFlags & kOFVoice) { uint speechId = subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFVoice)]; if (subObject->objectFlags & kOFNumber) { uint speechIdOffs = subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)]; if (speechId == 116) speechId = speechIdOffs + 115; if (speechId == 92) speechId = speechIdOffs + 98; if (speechId == 99) speechId = 9; if (speechId == 97) { switch (speechIdOffs) { case 12: speechId = 109; break; case 14: speechId = 108; break; case 18: speechId = 107; break; case 20: speechId = 106; break; case 22: speechId = 105; break; case 28: speechId = 104; break; case 90: speechId = 103; break; case 92: speechId = 102; break; case 100: speechId = 51; break; default: error("o2_screenTextPObj: invalid case %d", speechIdOffs); } } } if (_speech) playSpeech(speechId, vgaSpriteId); } } if (subObject != NULL && subObject->objectFlags & kOFText && _subtitles) { const char *stringPtr = (const char *)getStringPtrByID(subObject->objectFlagValue[0]); TextLocation *tl = getTextLocation(vgaSpriteId); char buf[256]; int j, k; if (subObject->objectFlags & kOFNumber) { if (_language == Common::HB_ISR) { j = subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)]; k = (j % 10) * 10; k += j / 10; if (!(j % 10)) sprintf(buf,"0%d%s", k, stringPtr); else sprintf(buf,"%d%s", k, stringPtr); } else { sprintf(buf,"%d%s", subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)], stringPtr); } stringPtr = buf; } if (stringPtr != NULL) printScreenText(vgaSpriteId, color, stringPtr, tl->x, tl->y, tl->width); } } void SimonEngine::o2_mouseOff() { // 181: force mouseOff scriptMouseOff(); changeWindow(1); showMessageFormat("\xC"); } void SimonEngine::o2_isShortText() { // 188: string2 is uint i = getVarOrByte(); uint str = getNextStringID(); setScriptCondition(str < _numTextBoxes && _shortText[i] == str); } void SimonEngine::o2_clearMarks() { // 189: clear_op189_flag _marks = 0; } void SimonEngine::o2_waitMark() { // 190 uint i = getVarOrByte(); if (!(_marks & (1 << i))) waitForMark(i); } // ----------------------------------------------------------------------- // Feeble Files Opcodes // ----------------------------------------------------------------------- void SimonEngine::o3_chance() { // 23 uint a = getVarOrWord(); if (a == 0) { setScriptCondition(false); return; } if (a == 100) { setScriptCondition(true); return; } if ((uint)_rnd.getRandomNumber(99) < a) setScriptCondition(true); else setScriptCondition(false); } void SimonEngine::o3_jumpOut() { // 37 getVarOrByte(); setScriptReturn(1); } void SimonEngine::o3_addTextBox() { // 65: add hit area uint flags = kBFTextBox | kBFBoxItem; uint id = getVarOrWord(); uint params = id / 1000; uint x, y, w, h, num; id %= 1000; if (params & 1) flags |= kBFInvertTouch; x = getVarOrWord(); y = getVarOrWord(); w = getVarOrWord(); h = getVarOrWord(); num = getVarOrByte(); if (num < _numTextBoxes) defineBox(id, x, y, w, h, flags + (num << 8), 208, _dummyItem2); } void SimonEngine::o3_printLongText() { // 70: show string from array int num = getVarOrByte(); const char *str = (const char *)getStringPtrByID(_longText[num]); sendInteractText(num, "%d. %s\n", num, str); } void SimonEngine::o3_addBox() { // 107: add item hitarea uint flags = 0; uint id = getVarOrWord(); uint params = id / 1000; uint x, y, w, h, verb; Item *item; id = id % 1000; if (params & 1) flags |= kBFInvertTouch; if (params & 2) flags |= kBFNoTouchName; if (params & 4) flags |= kBFBoxItem; if (params & 8) flags |= kBFTextBox; if (params & 16) flags |= 0x10; x = getVarOrWord(); y = getVarOrWord(); w = getVarOrWord(); h = getVarOrWord(); item = getNextItemPtrStrange(); verb = getVarOrWord(); defineBox(id, x, y, w, h, flags, verb, item); } void SimonEngine::o3_oracleTextDown() { // 122: oracle text down oracleTextDown(); } void SimonEngine::o3_oracleTextUp() { // 123: oracle text up oracleTextUp(); } void SimonEngine::o3_ifTime() { // 124: if time time_t t; uint a = getVarOrWord(); time(&t); t -= _gameStoppedClock; t -= a; if (t >= _timeStore) setScriptCondition(true); else setScriptCondition(false); } void SimonEngine::o3_playTune() { // 127: usually deals with music, but is a no-op in FF. getVarOrWord(); getVarOrWord(); getVarOrByte(); } void SimonEngine::o3_setTime() { // 131 time(&_timeStore); _timeStore -= _gameStoppedClock; } void SimonEngine::o3_saveUserGame() { // 132: save game _noOracleScroll = 0; _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); saveUserGame(countSaveGames() + 1 - readVariable(55)); _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); } void SimonEngine::o3_loadUserGame() { // 133: load game loadGame(readVariable(55)); } void SimonEngine::o3_listSaveGames() { // 134: dummy opcode? listSaveGames(1); } void SimonEngine::o3_checkCD() { // 135: switch CD uint disc = readVariable(97); if (!strcmp(_gameDescription->extra, "4CD")) { _sound->switchVoiceFile(gss, disc); } else if (!strcmp(_gameDescription->extra, "2CD")) { if (disc == 1 || disc == 2) _sound->switchVoiceFile(gss, 1); else if (disc == 3 || disc == 4) _sound->switchVoiceFile(gss, 2); } debug(0, "Switch to CD number %d", disc); } void SimonEngine::o3_screenTextBox() { // 161: setup text TextLocation *tl = getTextLocation(getVarOrByte()); tl->x = getVarOrWord(); tl->y = getVarOrWord(); tl->width = getVarOrWord(); } void SimonEngine::o3_isAdjNoun() { // 165: item unk1 unk2 is Item *item = getNextItemPtr(); int16 a = getNextWord(), b = getNextWord(); if (item->adjective == a && item->noun == b) setScriptCondition(true); else if (a == -1 && item->noun == b) setScriptCondition(true); else setScriptCondition(false); } void SimonEngine::o3_hyperLinkOn() { // 171: oracle hyperlink on hyperLinkOn(getVarOrWord()); } void SimonEngine::o3_hyperLinkOff() { // 172: oracle hyperlink off hyperLinkOff(); } void SimonEngine::o3_checkPaths() { // 173 check paths int i, count; const uint8 *pathVal1 = _pathValues1; bool result = false; count = _variableArray2[38]; for (i = 0; i < count; i++) { uint8 val = pathVal1[2]; if (val == _variableArray2[50] || val == _variableArray2[51] || val == _variableArray2[201] || val == _variableArray2[203] || val == _variableArray2[205] || val == _variableArray2[207] || val == _variableArray2[209] || val == _variableArray2[211] || val == _variableArray2[213] || val == _variableArray2[215] || val == _variableArray2[219] || val == _variableArray2[220] || val == _variableArray2[221] || val == _variableArray2[222] || val == _variableArray2[223] || val == _variableArray2[224] || val == _variableArray2[225] || val == _variableArray2[226]) { result = true; break; } pathVal1 += 4; } _variableArray2[52] = result; } void SimonEngine::o3_screenTextPObj() { // 177: inventory descriptions uint vgaSpriteId = getVarOrByte(); uint color = getVarOrByte(); const char *string_ptr = NULL; TextLocation *tl = NULL; char buf[256]; SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); if (subObject != NULL && subObject->objectFlags & kOFText) { string_ptr = (const char *)getStringPtrByID(subObject->objectFlagValue[0]); tl = getTextLocation(vgaSpriteId); } if (subObject != NULL && subObject->objectFlags & kOFVoice) { uint offs = getOffsetOfChild2Param(subObject, kOFVoice); playSpeech(subObject->objectFlagValue[offs], vgaSpriteId); } if (subObject != NULL && (subObject->objectFlags & kOFText) && _subtitles) { if (subObject->objectFlags & kOFNumber) { sprintf(buf, "%d%s", subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)], string_ptr); string_ptr = buf; } if (string_ptr != NULL) printScreenText(vgaSpriteId, color, string_ptr, tl->x, tl->y, tl->width); } } void SimonEngine::o3_mouseOff() { // 181: force mouseOff scriptMouseOff(); clearName(); } void SimonEngine::o3_loadVideo() { // 182: load video file const byte *filename = getStringPtrByID(getNextStringID()); _moviePlay->load((const char *)filename); } void SimonEngine::o3_playVideo() { // 183: play video _moviePlay->play(); } void SimonEngine::o3_centreScroll() { // 187 centreScroll(); } void SimonEngine::o3_resetPVCount() { // 191 if (getBitFlag(83)) { _PVCount1 = 0; _GPVCount1 = 0; } else { _PVCount = 0; _GPVCount = 0; } } void SimonEngine::o3_setPathValues() { // 192 uint8 a = getVarOrByte(); uint8 b = getVarOrByte(); uint8 c = getVarOrByte(); uint8 d = getVarOrByte(); if (getBitFlag(83)) { _pathValues1[_PVCount1++] = a; _pathValues1[_PVCount1++] = b; _pathValues1[_PVCount1++] = c; _pathValues1[_PVCount1++] = d; } else { _pathValues[_PVCount++] = a; _pathValues[_PVCount++] = b; _pathValues[_PVCount++] = c; _pathValues[_PVCount++] = d; } } void SimonEngine::o3_stopClock() { // 193: pause clock _clockStopped = time(NULL); } void SimonEngine::o3_restartClock() { // 194: resume clock if (_clockStopped != 0) _gameStoppedClock += time(NULL) - _clockStopped; _clockStopped = 0; } void SimonEngine::o3_setColour() { // 195: set palette colour uint c = getVarOrByte() * 4; uint r = getVarOrByte(); uint g = getVarOrByte(); uint b = getVarOrByte(); _displayPalette[c + 0] = r; _displayPalette[c + 1] = g; _displayPalette[c + 2] = b; _paletteFlag = 2; } void SimonEngine::o3_b3Set() { // 196: set bit3 uint bit = getVarOrByte(); _bitArrayThree[bit / 16] |= (1 << (bit & 15)); } void SimonEngine::o3_b3Clear() { // 197: clear bit3 uint bit = getVarOrByte(); _bitArrayThree[bit / 16] &= ~(1 << (bit & 15)); } void SimonEngine::o3_b3Zero() { // 198: is bit3 clear uint bit = getVarOrByte(); setScriptCondition((_bitArrayThree[bit / 16] & (1 << (bit & 15))) == 0); } void SimonEngine::o3_b3NotZero() { // 199: is bit3 set uint bit = getVarOrByte(); setScriptCondition((_bitArrayThree[bit / 16] & (1 << (bit & 15))) != 0); } // ----------------------------------------------------------------------- // Puzzle Pack Opcodes // ----------------------------------------------------------------------- void SimonEngine::o4_opcode30() { // 30 getNextItemPtr(); } void SimonEngine::o4_checkTiles() { // 37: for MahJongg game getVarOrByte(); } void SimonEngine::o4_opcode38() { // 38 getVarOrByte(); getNextItemPtr(); } void SimonEngine::o4_loadHiScores() { // 105 getVarOrByte(); } void SimonEngine::o4_checkHiScores() { // 106 getVarOrByte(); getVarOrByte(); } void SimonEngine::o4_loadUserGame() { // 133 } void SimonEngine::o4_saveOopsPosition() { // 173 } void SimonEngine::o4_resetGameTime() { // 187 } void SimonEngine::o4_resetPVCount() { // 191 _PVCount = 0; _GPVCount = 0; } void SimonEngine::o4_setPathValues() { // 192 _pathValues[_PVCount++] = getVarOrByte(); _pathValues[_PVCount++] = getVarOrByte(); _pathValues[_PVCount++] = getVarOrByte(); _pathValues[_PVCount++] = getVarOrByte(); } // ----------------------------------------------------------------------- int SimonEngine::runScript() { int opcode; bool flag; do { if (_continousMainScript) dumpOpcode(_codePtr); if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) { opcode = getVarOrWord(); if (opcode == 10000) return 0; } else { opcode = getByte(); if (opcode == 0xFF) return 0; } debug(1, "runScript: opcode %d", opcode); if (_runScriptReturn1) return 1; /* Invert condition? */ flag = false; if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) { if (opcode == 203) { flag = true; opcode = getVarOrWord(); if (opcode == 10000) return 0; } } else { if (opcode == 0) { flag = true; opcode = getByte(); if (opcode == 0xFF) return 0; } } setScriptCondition(true); setScriptReturn(0); if (opcode > _numOpcodes || !_opcode_table[opcode]) error("Invalid opcode '%d' encountered", opcode); (this->*_opcode_table[opcode]) (); } while (getScriptCondition() != flag && !getScriptReturn()); return getScriptReturn(); } void SimonEngine::scriptMouseOn() { if (getGameType() == GType_FF && _mouseCursor != 5) { resetVerbs(); _noRightClick = 0; } if (getGameType() == GType_SIMON2 && getBitFlag(79)) { _mouseCursor = 0; } _mouseHideCount = 0; } void SimonEngine::scriptMouseOff() { _lockWord |= 0x8000; vc34_setMouseOff(); _lockWord &= ~0x8000; } void SimonEngine::waitForMark(uint i) { _exitCutscene = false; while (!(_marks & (1 << i))) { if (_exitCutscene) { if (getBitFlag(9)) { endCutscene(); break; } } else { processSpecialKeys(); } delay(10); } } void SimonEngine::freezeBottom() { _vgaMemBase = _vgaMemPtr; _vgaFrozenBase = _vgaMemPtr; } void SimonEngine::unfreezeBottom() { _vgaMemPtr = _vgaRealBase; _vgaMemBase = _vgaRealBase; _vgaFrozenBase = _vgaRealBase; } void SimonEngine::sendSync(uint a) { uint16 id = to16Wrapper(a); _lockWord |= 0x8000; _vcPtr = (byte *)&id; vc15_sync(); _lockWord &= ~0x8000; } void SimonEngine::setTextColor(uint color) { WindowBlock *window; window = _windowArray[_curWindow]; window->text_color = color; } void SimonEngine::stopAnimateSimon1(uint a) { uint16 b = to16Wrapper(a); _lockWord |= 0x8000; _vcPtr = (byte *)&b; vc60_killSprite(); _lockWord &= ~0x8000; } void SimonEngine::stopAnimateSimon2(uint a, uint b) { uint16 items[2]; items[0] = to16Wrapper(a); items[1] = to16Wrapper(b); _lockWord |= 0x8000; _vcPtr = (byte *)&items; vc60_killSprite(); _lockWord &= ~0x8000; } } // End of namespace Simon