scummvm/engines/simon/items.cpp
2006-02-13 10:29:25 +00:00

1702 lines
36 KiB
C++

/* ScummVM - Scumm Interpreter
* 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 "simon/simon.h"
#include "simon/intern.h"
#include "common/system.h"
#ifdef _WIN32_WCE
extern bool isSmartphone(void);
#endif
namespace Simon {
int SimonEngine::runScript() {
byte opcode;
bool flag, condition;
do {
if (_continousMainScript)
dumpOpcode(_codePtr);
opcode = getByte();
if (opcode == 0xFF)
return 0;
if (_runScriptReturn1)
return 1;
/* Invert condition? */
flag = false;
if (opcode == 0) {
flag = true;
opcode = getByte();
if (opcode == 0xFF)
return 0;
}
condition = true;
switch (opcode) {
case 1:{ /* ptrA parent is */
condition = (getItem1Ptr()->parent == getNextItemID());
}
break;
case 2:{ /* ptrA parent is not */
condition = (getItem1Ptr()->parent != getNextItemID());
}
break;
case 5:{ /* parent is 1 */
condition = (getNextItemPtr()->parent == getItem1ID());
}
break;
case 6:{ /* parent isnot 1 */
condition = (getNextItemPtr()->parent != getItem1ID());
}
break;
case 7:{ /* parent is */
Item *item = getNextItemPtr();
condition = (item->parent == getNextItemID());
}
break;
case 11:{ /* is zero */
condition = (getNextVarContents() == 0);
}
break;
case 12:{ /* isnot zero */
condition = (getNextVarContents() != 0);
}
break;
case 13:{ /* equal */
uint tmp = getNextVarContents();
condition = (tmp == getVarOrWord());
}
break;
case 14:{ /* not equal */
uint tmp = getNextVarContents();
condition = (tmp != getVarOrWord());
}
break;
case 15:{ /* is greater */
uint tmp = getNextVarContents();
condition = (tmp > getVarOrWord());
}
break;
case 16:{ /* is less */
uint tmp = getNextVarContents();
condition = (tmp < getVarOrWord());
}
break;
case 17:{ /* is eq f */
uint tmp = getNextVarContents();
condition = (tmp == getNextVarContents());
}
break;
case 18:{ /* is not equal f */
uint tmp = getNextVarContents();
condition = (tmp != getNextVarContents());
}
break;
case 19:{ /* is greater f */
uint tmp = getNextVarContents();
condition = (tmp < getNextVarContents());
}
break;
case 20:{ /* is less f */
uint tmp = getNextVarContents();
condition = (tmp > getNextVarContents());
}
break;
case 23:{
condition = o_chance(getVarOrWord());
}
break;
case 25:{ /* is room */
condition = isRoom(getNextItemPtr());
}
break;
case 26:{ /* is object */
condition = isObject(getNextItemPtr());
}
break;
case 27:{ /* item state is */
Item *item = getNextItemPtr();
condition = ((uint) item->state == getVarOrWord());
}
break;
case 28:{ /* item has prop */
Child2 *child = (Child2 *)findChildOfType(getNextItemPtr(), 2);
byte num = getVarOrByte();
condition = child != NULL && (child->avail_props & (1 << num)) != 0;
} break;
case 31:{ /* set no parent */
setItemParent(getNextItemPtr(), NULL);
}
break;
case 33:{ /* set item parent */
Item *item = getNextItemPtr();
setItemParent(item, getNextItemPtr());
}
break;
case 36:{ /* copy var */
uint value = getNextVarContents();
writeNextVarContents(value);
}
break;
case 41:{ /* zero var */
writeNextVarContents(0);
}
break;
case 42:{ /* set var */
uint var = getVarOrByte();
writeVariable(var, getVarOrWord());
}
break;
case 43:{ /* add */
uint var = getVarOrByte();
writeVariable(var, readVariable(var) + getVarOrWord());
}
break;
case 44:{ /* sub */
uint var = getVarOrByte();
writeVariable(var, readVariable(var) - getVarOrWord());
}
break;
case 45:{ /* add f */
uint var = getVarOrByte();
writeVariable(var, readVariable(var) + getNextVarContents());
}
break;
case 46:{ /* sub f */
uint var = getVarOrByte();
writeVariable(var, readVariable(var) - getNextVarContents());
}
break;
case 47:{ /* mul */
uint var = getVarOrByte();
writeVariable(var, readVariable(var) * getVarOrWord());
}
break;
case 48:{ /* div */
uint var = getVarOrByte();
int value = getVarOrWord();
if (value == 0)
error("Division by zero in div");
writeVariable(var, readVariable(var) / value);
}
break;
case 49:{ /* mul f */
uint var = getVarOrByte();
writeVariable(var, readVariable(var) * getNextVarContents());
}
break;
case 50:{ /* div f */
uint var = getVarOrByte();
int value = getNextVarContents();
if (value == 0)
error("Division by zero in div f");
writeVariable(var, readVariable(var) / value);
}
break;
case 51:{ /* mod */
uint var = getVarOrByte();
int value = getVarOrWord();
if (value == 0)
error("Division by zero in mod");
writeVariable(var, readVariable(var) % value);
}
break;
case 52:{ /* mod f */
uint var = getVarOrByte();
int value = getNextVarContents();
if (value == 0)
error("Division by zero in mod f");
writeVariable(var, readVariable(var) % value);
}
break;
case 53:{ /* random */
uint var = getVarOrByte();
uint value = (uint16)getVarOrWord();
// Disable random in simon1amiga for now
// Since copy protection screen is currently unreadable
if (getPlatform() == Common::kPlatformAmiga)
writeVariable(var, 4);
else
writeVariable(var, _rnd.getRandomNumber(value - 1));
}
break;
case 55:{ /* set itemA parent */
setItemParent(getItem1Ptr(), getNextItemPtr());
}
break;
case 56:{ /* set child2 fr bit */
Child2 *child = (Child2 *)findChildOfType(getNextItemPtr(), 2);
int value = getVarOrByte();
if (child != NULL && value >= 0x10)
child->avail_props |= 1 << value;
}
break;
case 57:{ /* clear child2 fr bit */
Child2 *child = (Child2 *)findChildOfType(getNextItemPtr(), 2);
int value = getVarOrByte();
if (child != NULL && value >= 0x10)
child->avail_props &= ~(1 << value);
}
break;
case 58:{ /* make siblings */
Item *item = getNextItemPtr();
setItemParent(item, derefItem(getNextItemPtr()->parent));
}
break;
case 59:{ /* item inc state */
Item *item = getNextItemPtr();
if (item->state <= 30000)
setItemState(item, item->state + 1);
}
break;
case 60:{ /* item dec state */
Item *item = getNextItemPtr();
if (item->state >= 0)
setItemState(item, item->state - 1);
}
break;
case 61:{ /* item set state */
Item *item = getNextItemPtr();
int value = getVarOrWord();
if (value < 0)
value = 0;
if (value > 30000)
value = 30000;
setItemState(item, value);
}
break;
case 62:{ /* show int */
showMessageFormat("%d", getNextVarContents());
}
break;
case 63:{ /* show string nl */
showMessageFormat("%s\n", getStringPtrByID(getNextStringID()));
}
break;
case 64:{ /* show string */
showMessageFormat("%s", getStringPtrByID(getNextStringID()));
}
break;
case 65:{ /* add hit area */
int id = getVarOrWord();
int x = getVarOrWord();
int y = getVarOrWord();
int w = getVarOrWord();
int h = getVarOrWord();
int number = getVarOrByte();
if (number < 20)
addNewHitArea(id, x, y, w, h, (number << 8) + 129, 0xD0, _dummyItem2);
}
break;
case 66:{ /* set item name */
uint var = getVarOrByte();
uint string_id = getNextStringID();
if (var < 20)
_stringIdArray2[var] = string_id;
}
break;
case 67:{ /* set item description */
uint var = getVarOrByte();
uint string_id = getNextStringID();
if (getFeatures() & GF_TALKIE) {
uint speechId = getNextWord();
if (var < 20) {
_stringIdArray3[var] = string_id;
_speechIdArray4[var] = speechId;
}
} else {
if (var < 20) {
_stringIdArray3[var] = string_id;
}
}
}
break;
case 68:{ /* exit interpreter */
shutdown();
}
break;
case 69:{ /* return 1 */
return 1;
}
case 70:{ /* show string from array */
const char *str = (const char *)getStringPtrByID(_stringIdArray3[getVarOrByte()]);
if (getGameType() == GType_SIMON2) {
writeVariable(51, strlen(str) / 53 * 8 + 8);
}
showMessageFormat("%s\n", str);
}
break;
case 71:{ /* start subroutine */
Subroutine *sub = getSubroutineByID(getVarOrWord());
if (sub != NULL)
startSubroutine(sub);
}
break;
case 76:{ /* add timeout */
uint timeout = getVarOrWord();
addTimeEvent(timeout, getVarOrWord());
}
break;
case 77:{ /* has item minus 1 */
condition = _subjectItem != NULL;
}
break;
case 78:{ /* has item minus 3 */
condition = _objectItem != NULL;
}
break;
case 79:{ /* childstruct fr2 is */
Child2 *child = (Child2 *)findChildOfType(getNextItemPtr(), 2);
uint string_id = getNextStringID();
condition = (child != NULL) && child->string_id == string_id;
}
break;
case 80:{ /* item equal */
condition = getNextItemPtr() == getNextItemPtr();
}
break;
case 82:{ /* debug opcode */
getVarOrByte();
}
break;
case 83:{ /* restart subroutine */
if (getGameType() == GType_SIMON2 || getGameType() == GType_FF)
o_83_helper();
return -10;
}
case 87:{ /* comment */
getNextStringID();
}
break;
case 88:{ /* stop animation */
_lockWord |= 0x10;
}
break;
case 89:{ /* restart animation */
_lockWord &= ~0x10;
}
break;
case 90:{ /* set minusitem to parent */
Item *item = derefItem(getNextItemPtr()->parent);
switch (getVarOrByte()) {
case 0:
_objectItem = item;
break;
case 1:
_subjectItem = item;
break;
default:
error("set minusitem to parent, invalid subcode");
}
}
break;
case 91:{ /* set minusitem to sibling */
Item *item = derefItem(getNextItemPtr()->sibling);
switch (getVarOrByte()) {
case 0:
_objectItem = item;
break;
case 1:
_subjectItem = item;
break;
default:
error("set minusitem to sibling, invalid subcode");
}
}
break;
case 92:{ /* set minusitem to child */
Item *item = derefItem(getNextItemPtr()->child);
switch (getVarOrByte()) {
case 0:
_objectItem = item;
break;
case 1:
_subjectItem = item;
break;
default:
error("set minusitem to child, invalid subcode");
}
}
break;
case 96:{
uint val = getVarOrWord();
o_set_video_mode(getVarOrByte(), val);
}
break;
case 97:{ /* load vga */
o_loadZone(getVarOrWord());
}
break;
case 98:{ /* start vga */
uint vga_res, vgaSpriteId, windowNum, x, y, palette;
if (getGameType() == GType_SIMON1) {
vgaSpriteId = getVarOrWord();
vga_res = vgaSpriteId / 100;
} else {
vga_res = getVarOrWord();
vgaSpriteId = getVarOrWord();
}
windowNum = getVarOrByte();
x = getVarOrWord();
y = getVarOrWord();
palette = getVarOrWord();
loadSprite(windowNum, vga_res, vgaSpriteId, x, y, palette);
}
break;
case 99:{ /* kill sprite */
if (getGameType() == GType_SIMON1) {
o_kill_sprite_simon1(getVarOrWord());
} else {
uint a = getVarOrWord();
uint b = getVarOrWord();
o_kill_sprite_simon2(a, b);
}
}
break;
case 100:{ /* vga reset */
o_vga_reset();
}
break;
case 101:{
uint a = getVarOrByte();
uint b = getVarOrWord();
uint c = getVarOrWord();
uint d = getVarOrWord();
uint e = getVarOrWord();
uint f = getVarOrWord();
uint g = getVarOrWord();
o_defineWindow(a, b, c, d, e, f, g, 0);
}
break;
case 102:{
changeWindow(getVarOrByte() & 7);
}
break;
case 103:{
o_unk_103();
}
break;
case 104:{
closeWindow(getVarOrByte() & 7);
}
break;
case 107:{ /* add item hitarea */
uint flags = 0;
uint id = getVarOrWord();
uint params = id / 1000;
uint x, y, w, h, unk3;
Item *item;
id = id % 1000;
if (params & 1)
flags |= 8;
if (params & 2)
flags |= 4;
if (params & 4)
flags |= 0x80;
if (params & 8)
flags |= 1;
if (params & 16)
flags |= 0x10;
x = getVarOrWord();
y = getVarOrWord();
w = getVarOrWord();
h = getVarOrWord();
item = getNextItemPtrStrange();
unk3 = getVarOrWord();
if (x >= 1000) {
unk3 += 0x4000;
x -= 1000;
}
addNewHitArea(id, x, y, w, h, flags, unk3, item);
}
break;
case 108:{ /* delete hitarea */
delete_hitarea(getVarOrWord());
}
break;
case 109:{ /* clear hitarea bit 0x40 */
clear_hitarea_bit_0x40(getVarOrWord());
}
break;
case 110:{ /* set hitarea bit 0x40 */
set_hitarea_bit_0x40(getVarOrWord());
}
break;
case 111:{ /* set hitarea xy */
uint hitarea_id = getVarOrWord();
uint x = getVarOrWord();
uint y = getVarOrWord();
set_hitarea_x_y(hitarea_id, x, y);
}
break;
case 114:{
Item *item = getNextItemPtr();
uint fcs_index = getVarOrByte();
mouseOff();
drawIconArray(fcs_index, item, 0, 0);
mouseOn();
}
break;
case 115:{ /* item has flag */
Item *item = getNextItemPtr();
condition = (item->classFlags & (1 << getVarOrByte())) != 0;
}
break;
case 116:{ /* item set flag */
Item *item = getNextItemPtr();
item->classFlags |= (1 << getVarOrByte());
}
break;
case 117:{ /* item clear flag */
Item *item = getNextItemPtr();
item->classFlags &= ~(1 << getVarOrByte());
}
break;
case 119:{ /* wait vga */
uint var = getVarOrWord();
_scriptVar2 = (var == 200);
if (var != 200 || !_skipVgaWait)
o_waitForSync(var);
_skipVgaWait = false;
}
break;
case 120:{
o_sync(getVarOrWord());
}
break;
case 121:{ /* set vga item */
uint slot = getVarOrByte();
_vcItemArray[slot] = getNextItemPtr();
}
break;
case 122:{ /* oracle text down */
if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2)
goto invalid_opcode;
warning("STUB: script opcode 122");
}
break;
case 123:{ /* oracle text down */
if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2)
goto invalid_opcode;
warning("STUB: script opcode 123");
}
break;
case 124:{ /* if time */
if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2)
goto invalid_opcode;
uint time = getVarOrWord();
condition = 1;
warning("STUB: script opcode 124 (%d)", time);
}
break;
case 125:{ /* item is sibling with item 1 */
Item *item = getNextItemPtr();
condition = (getItem1Ptr()->parent == item->parent);
}
break;
case 126:{
Item *item = getNextItemPtr();
uint fcs_index = getVarOrByte();
uint a = 1 << getVarOrByte();
mouseOff();
drawIconArray(fcs_index, item, 1, a);
mouseOn();
}
break;
case 127:{ /* deals with music */
o_playMusic();
}
break;
case 128:{ /* dummy instruction */
getVarOrWord();
}
break;
case 129:{ /* dummy instruction */
getVarOrWord();
condition = true;
}
break;
case 130:{ /* set adj noun */
uint var = getVarOrByte();
if (var == 1) {
_scriptAdj1 = getNextWord();
_scriptNoun1 = getNextWord();
} else {
_scriptAdj2 = getNextWord();
_scriptNoun2 = getNextWord();
}
}
break;
case 132:{ /* save game */
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
o_saveGame();
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
}
break;
case 133:{ /* load game */
if (getGameType() == GType_FF) {
loadGame(readVariable(55));
} else {
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
o_loadGame();
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
}
}
break;
case 134:{ /* dummy opcode? */
if (getGameType() == GType_FF) {
warning("STUB: script opcode 134");
} else {
midi.stop();
_lastMusicPlayed = -1;
}
}
break;
case 135:{ /* quit if user presses y */
if (getGameType() == GType_FF) {
// Switch CD
debug(1, "Switch to CD number %d", readVariable(97));
} else {
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
o_confirmQuit();
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
}
}
break;
case 136:{ /* set var to item unk3 */
Item *item = getNextItemPtr();
writeNextVarContents(item->state);
}
break;
case 137:{
o_restoreIconArray(getVarOrByte());
}
break;
case 138:{ /* vga pointer op 4 */
o_freezeBottom();
}
break;
case 139:{ /* set parent special */
Item *item = getNextItemPtr();
_noParentNotify = true;
setItemParent(item, getNextItemPtr());
_noParentNotify = false;
}
break;
case 140:{ /* del te and add one */
killAllTimers();
addTimeEvent(3, 0xA0);
}
break;
case 141:{ /* set m1 or m3 */
uint which = getVarOrByte();
Item *item = getNextItemPtr();
if (which == 1) {
_subjectItem = item;
} else {
_objectItem = item;
}
}
break;
case 142:{ /* is hitarea 0x40 clear */
condition = is_hitarea_0x40_clear(getVarOrWord());
}
break;
case 143:{ /* start item sub */
Child1 *child = (Child1 *)findChildOfType(getNextItemPtr(), 1);
if (child != NULL) {
Subroutine *sub = getSubroutineByID(child->subroutine_id);
if (sub)
startSubroutine(sub);
}
}
break;
case 151:{ /* set array6 to item */
uint var = getVarOrByte();
Item *item = getNextItemPtr();
_itemArray6[var] = item;
}
break;
case 152:{ /* set m1 or m3 to array6 */
Item *item = _itemArray6[getVarOrByte()];
uint var = getVarOrByte();
if (var == 1) {
_subjectItem = item;
} else {
_objectItem = item;
}
}
break;
case 153:{ /* set bit */
uint bit = getVarOrByte();
_bitArray[bit / 16] |= 1 << (bit & 15);
break;
}
case 154:{ /* clear bit */
uint bit = getVarOrByte();
_bitArray[bit / 16] &= ~(1 << (bit & 15));
break;
}
case 155:{ /* is bit clear */
uint bit = getVarOrByte();
condition = (_bitArray[bit / 16] & (1 << (bit & 15))) == 0;
}
break;
case 156:{ /* is bit set */
uint bit = getVarOrByte();
if (getGameType() == GType_SIMON1 && _subroutine == 2962 && bit == 63) {
bit = 50;
}
condition = (_bitArray[bit / 16] & (1 << (bit & 15))) != 0;
}
break;
case 157:{ /* get item int prop */
Item *item = getNextItemPtr();
Child2 *child = (Child2 *)findChildOfType(item, 2);
uint prop = getVarOrByte();
if (child != NULL && child->avail_props & (1 << prop) && prop < 16) {
uint offs = getOffsetOfChild2Param(child, 1 << prop);
writeNextVarContents(child->array[offs]);
} else {
writeNextVarContents(0);
}
}
break;
case 158:{ /* set item prop */
Item *item = getNextItemPtr();
Child2 *child = (Child2 *)findChildOfType(item, 2);
uint prop = getVarOrByte();
int value = getVarOrWord();
if (child != NULL && child->avail_props & (1 << prop) && prop < 16) {
uint offs = getOffsetOfChild2Param(child, 1 << prop);
child->array[offs] = value;
}
}
break;
case 160:{
o_unk_160(getVarOrByte());
}
break;
case 161:{ /* setup text */
TextLocation *tl = getTextLocation(getVarOrByte());
tl->x = getVarOrWord();
tl->y = getVarOrByte();
tl->width = getVarOrWord();
}
break;
case 162:{ /* print string */
o_printStr();
}
break;
case 163:{ /* play sound */
o_playSFX(getVarOrWord());
}
break;
case 164:{
_showPreposition = true;
o_setup_cond_c();
_showPreposition = false;
}
break;
case 165:{ /* item unk1 unk2 is */
Item *item = getNextItemPtr();
int16 a = getNextWord(), b = getNextWord();
condition = (item->adjective == a && item->noun == b);
} break;
case 166:{ /* set bit2 */
uint bit = getVarOrByte();
_bitArray[(bit / 16) + 16] |= 1 << (bit & 15);
}
break;
case 167:{ /* clear bit2 */
uint bit = getVarOrByte();
_bitArray[(bit / 16) + 16] &= ~(1 << (bit & 15));
}
break;
case 168:{ /* is bit2 clear */
uint bit = getVarOrByte();
condition = (_bitArray[(bit / 16) + 16] & (1 << (bit & 15))) == 0;
}
break;
case 169:{ /* is bit2 set */
uint bit = getVarOrByte();
condition = (_bitArray[(bit / 16) + 16] & (1 << (bit & 15))) != 0;
}
break;
case 171:{ /* oracle hyperlink on */
if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2)
goto invalid_opcode;
hyperLinkOn(getVarOrWord());
}
break;
case 172:{ /* oracle hyperlink off */
if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2)
goto invalid_opcode;
hyperLinkOff();
}
break;
case 175:{ /* vga pointer op 1 */
o_lockZone();
}
break;
case 176:{ /* vga pointer op 2 */
o_unlockZone();
}
break;
case 177:{ /* inventory descriptions */
o_inventory_descriptions();
}
break;
case 178:{ /* path find */
uint a = getVarOrWord();
uint b = getVarOrWord();
uint c = getVarOrByte();
uint d = getVarOrByte();
o_pathfind(a, b, c, d);
}
break;
case 179:{ /* conversation responses */
uint vgaSpriteId = getVarOrByte(); /* and room descriptions */
uint color = getVarOrByte();
uint string_id = getVarOrByte();
uint speechId = 0;
const char *string_ptr = (const char *)getStringPtrByID(_stringIdArray3[string_id]);
TextLocation *tl = getTextLocation(vgaSpriteId);
if (getFeatures() & GF_TALKIE)
speechId = _speechIdArray4[string_id];
if (_speech && speechId != 0)
playSpeech(speechId, vgaSpriteId);
if (string_ptr != NULL && _subtitles)
printText(vgaSpriteId, color, string_ptr, tl->x, tl->y, tl->width);
}
break;
case 180:{ /* force mouseOn */
o_mouseOn();
}
break;
case 181:{ /* force mouseOff */
o_mouseOff();
if (getGameType() == GType_SIMON2) {
changeWindow(1);
showMessageFormat("\xC");
}
}
break;
case 182:{ /* load beard */
if (getGameType() == GType_FF) {
// Load video file
debug(1,"Load video file: %s", getStringPtrByID(getNextStringID()));
} else if (getGameType() == GType_SIMON2) {
goto invalid_opcode;
} else {
o_loadBeard();
}
}
break;
case 183:{ /* unload beard */
if (getGameType() == GType_FF) {
// Play video
debug(1, "Play video");
} else if (getGameType() == GType_SIMON2) {
goto invalid_opcode;
} else {
o_unloadBeard();
}
}
break;
case 184:{ /* clear vgapointer entry */
o_unloadZone(getVarOrWord());
}
break;
case 185:{ /* load sound files */
if (getGameType() == GType_SIMON2)
goto invalid_opcode;
_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);
}
}
break;
case 186:{ /* vga pointer op 3 */
o_unfreezeBottom();
}
break;
case 187:{ /* fade to black */
if (getGameType() == GType_SIMON2)
goto invalid_opcode;
o_fadeToBlack();
}
break;
case 188: /* string2 is */
if (getGameType() == GType_SIMON1)
goto invalid_opcode;
{
uint i = getVarOrByte();
uint str = getNextStringID();
condition = (str < 20 && _stringIdArray2[i] == str);
}
break;
case 189:{ /* clear_op189_flag */
if (getGameType() == GType_SIMON1)
goto invalid_opcode;
_marks = 0;
}
break;
case 190:{
uint i;
if (getGameType() == GType_SIMON1)
goto invalid_opcode;
i = getVarOrByte();
if (!(_marks & (1 << i)))
o_waitForMark(i);
}
break;
// Feeble opcodes
case 191:
if (_bitArray[5] & 0x0008) {
_PVCount1 = 0;
_GPVCount1 = 0;
} else {
_PVCount = 0;
_GPVCount = 0;
}
break;
case 192:{
uint8 a = getVarOrByte();
uint8 b = getVarOrByte();
uint8 c = getVarOrByte();
uint8 d = getVarOrByte();
if (_bitArray[5] & 0x0008) {
_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;
}
}
break;
case 193:
// pause clock
warning("STUB: script opcode 193");
break;
case 194:
// resume clock
warning("STUB: script opcode 194");
break;
case 195:{
// Set palette colour?
uint blue = getVarOrByte();
uint green = getVarOrByte();
uint red = getVarOrByte();
uint color = getVarOrByte();
warning("STUB: script opcode 195 (%d, %d, %d, %d)", blue, green, red, color);
}
break;
case 196:{ /* set bit3 */
uint bit = getVarOrByte();
_bitArray[(bit / 16) + 32] |= 1 << (bit & 15);
}
break;
case 197:{ /* clear bit3 */
uint bit = getVarOrByte();
_bitArray[(bit / 16) + 32] &= ~(1 << (bit & 15));
}
break;
case 198:{ /* is bit3 clear */
uint bit = getVarOrByte();
condition = (_bitArray[(bit / 16) + 32] & (1 << (bit & 15))) == 0;
}
break;
case 199:{ /* is bit3 set */
uint bit = getVarOrByte();
condition = (_bitArray[(bit / 16) + 32] & (1 << (bit & 15))) != 0;
}
break;
default:
invalid_opcode:;
error("Invalid opcode '%d'", opcode);
}
} while (condition != flag);
return 0;
}
int SimonEngine::startSubroutine(Subroutine *sub) {
int result = -1;
SubroutineLine *sl;
const byte *old_code_ptr;
if (_startMainScript)
dumpSubroutine(sub);
old_code_ptr = _codePtr;
if (++_recursionDepth > 40)
error("Recursion error");
sl = (SubroutineLine *)((byte *)sub + sub->first);
while ((byte *)sl != (byte *)sub) {
if (checkIfToRunSubroutineLine(sl, sub)) {
result = 0;
_codePtr = (byte *)sl;
if (sub->id)
_codePtr += 2;
else
_codePtr += 8;
if (_continousMainScript)
fprintf(_dumpFile, "; %d\n", sub->id);
result = runScript();
if (result != 0) {
/* result -10 means restart subroutine */
if (result == -10) {
delay(0); /* maybe leave control to the VGA */
sl = (SubroutineLine *)((byte *)sub + sub->first);
continue;
}
break;
}
}
sl = (SubroutineLine *)((byte *)sub + sl->next);
}
_codePtr = old_code_ptr;
_recursionDepth--;
return result;
}
int SimonEngine::startSubroutineEx(Subroutine *sub) {
return startSubroutine(sub);
}
bool SimonEngine::checkIfToRunSubroutineLine(SubroutineLine *sl, Subroutine *sub) {
if (sub->id)
return true;
if (sl->verb != -1 && sl->verb != _scriptVerb &&
(sl->verb != -2 || _scriptVerb != -1))
return false;
if (sl->noun1 != -1 && sl->noun1 != _scriptNoun1 &&
(sl->noun1 != -2 || _scriptNoun1 != -1))
return false;
if (sl->noun2 != -1 && sl->noun2 != _scriptNoun2 &&
(sl->noun2 != -2 || _scriptNoun2 != -1))
return false;
return true;
}
void SimonEngine::o_83_helper() {
if (_exitCutscene) {
if (vcGetBit(9)) {
endCutscene();
}
} else {
processSpecialKeys();
}
}
void SimonEngine::o_waitForMark(uint i) {
_exitCutscene = false;
while (!(_marks & (1 << i))) {
if (_exitCutscene) {
if (vcGetBit(9)) {
endCutscene();
break;
}
} else {
processSpecialKeys();
}
delay(10);
}
}
bool SimonEngine::o_chance(uint a) {
if (a == 0)
return 0;
if (a == 100)
return 1;
a += _scriptUnk1;
if (a <= 0) {
_scriptUnk1 = 0;
return 0;
}
if ((uint)_rnd.getRandomNumber(99) < a) {
if (_scriptUnk1 <= 0)
_scriptUnk1 -= 5;
else
_scriptUnk1 = 0;
return 1;
}
if (_scriptUnk1 >= 0)
_scriptUnk1 += 5;
else
_scriptUnk1 = 0;
return 0;
}
void SimonEngine::o_inventory_descriptions() {
uint vgaSpriteId = getVarOrByte();
uint color = getVarOrByte();
const char *string_ptr = NULL;
TextLocation *tl = NULL;
char buf[256];
Child2 *child = (Child2 *)findChildOfType(getNextItemPtr(), 2);
if (child != NULL && child->avail_props & 1) {
string_ptr = (const char *)getStringPtrByID(child->array[0]);
tl = getTextLocation(vgaSpriteId);
}
if ((getGameType() == GType_SIMON2) && (getFeatures() & GF_TALKIE)) {
if (child != NULL && child->avail_props & 0x200) {
uint speechId = child->array[getOffsetOfChild2Param(child, 0x200)];
if (child->avail_props & 0x100) {
uint speechIdOffs = child->array[getOffsetOfChild2Param(child, 0x100)];
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("o_177: invalid case %d", speechIdOffs);
}
}
}
if (_speech)
playSpeech(speechId, vgaSpriteId);
}
} else if (getFeatures() & GF_TALKIE) {
if (child != NULL && child->avail_props & 0x200) {
uint offs = getOffsetOfChild2Param(child, 0x200);
playSpeech(child->array[offs], vgaSpriteId);
} else if (child != NULL && child->avail_props & 0x100) {
uint offs = getOffsetOfChild2Param(child, 0x100);
playSpeech(child->array[offs] + 3550, vgaSpriteId);
}
}
if (child != NULL && (child->avail_props & 1) && _subtitles) {
if (child->avail_props & 0x100) {
sprintf(buf, "%d%s", child->array[getOffsetOfChild2Param(child, 0x100)], string_ptr);
string_ptr = buf;
}
if (string_ptr != NULL)
printText(vgaSpriteId, color, string_ptr, tl->x, tl->y, tl->width);
}
}
void SimonEngine::o_confirmQuit() {
// 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)
shutdown();
else if (_keyPressed == keyNo)
break;
}
}
void SimonEngine::o_restoreIconArray(uint fcs_index) {
FillOrCopyStruct *fcs;
fcs = _windowArray[fcs_index & 7];
if (fcs->fcs_data == NULL)
return;
drawIconArray(fcs_index, fcs->fcs_data->item_ptr, fcs->fcs_data->unk1, fcs->fcs_data->unk2);
}
void SimonEngine::o_freezeBottom() {
_vgaBufStart = _vgaBufFreeStart;
_vgaFileBufOrg = _vgaBufFreeStart;
}
void SimonEngine::o_unfreezeBottom() {
_vgaBufFreeStart = _vgaFileBufOrg2;
_vgaBufStart = _vgaFileBufOrg2;
_vgaFileBufOrg = _vgaFileBufOrg2;
}
void SimonEngine::o_lockZone() {
_vgaBufStart = _vgaBufFreeStart;
}
void SimonEngine::o_unlockZone() {
_vgaBufFreeStart = _vgaFileBufOrg;
_vgaBufStart = _vgaFileBufOrg;
}
int SimonEngine::o_unk_132_helper(bool *b, char *buf) {
HitArea *ha;
*b = true;
if (!_saveLoadFlag) {
strange_jump:;
_saveLoadFlag = false;
saveGameDialog(buf);
}
start_over:;
_keyPressed = 0;
start_over_2:;
_lastHitArea = _lastHitArea3 = 0;
do {
if (_keyPressed != 0) {
if (_saveLoadFlag) {
*b = false;
return _keyPressed;
}
goto start_over;
}
delay(100);
} while (_lastHitArea3 == 0);
ha = _lastHitArea;
if (ha == NULL || ha->id < 205)
goto start_over_2;
if (ha->id == 205)
return ha->id;
if (ha->id == 206) {
if (_saveLoadRowCurPos == 1)
goto start_over_2;
if (_saveLoadRowCurPos < 7)
_saveLoadRowCurPos = 1;
else
_saveLoadRowCurPos -= 6;
goto strange_jump;
}
if (ha->id == 207) {
if (!_saveDialogFlag)
goto start_over_2;
_saveLoadRowCurPos += 6;
if (_saveLoadRowCurPos >= _numSaveGameRows)
_saveLoadRowCurPos = _numSaveGameRows;
goto strange_jump;
}
if (ha->id >= 214)
goto start_over_2;
return ha->id - 208;
}
void SimonEngine::o_unk_132_helper_3() {
for (int i = 208; i != 208 + 6; i++)
set_hitarea_bit_0x40(i);
}
void SimonEngine::o_clearCharacter(FillOrCopyStruct *fcs, int x, byte b) {
byte old_text;
video_putchar(fcs, x, b);
old_text = fcs->text_color;
fcs->text_color = fcs->fill_color;
if (_language == Common::HB_ISR) { //Hebrew
x = 128;
} else {
x += 120;
if (x != 128)
x = 129;
}
video_putchar(fcs, x);
fcs->text_color = old_text;
video_putchar(fcs, 8);
}
void SimonEngine::o_playMusic() {
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 (getGameType() == GType_SIMON2) {
int loop = getVarOrByte();
midi.setLoop (loop != 0);
if (_lastMusicPlayed != music)
_nextMusicToPlay = music;
else
midi.startTrack (track);
} else {
if (music != _lastMusicPlayed) {
_lastMusicPlayed = music;
loadMusic (music);
midi.startTrack (track);
}
}
}
void SimonEngine::o_sync(uint a) {
uint16 id = to16Wrapper(a);
_lockWord |= 0x8000;
_vcPtr = (byte *)&id;
vc15_wakeup_id();
_lockWord &= ~0x8000;
}
void SimonEngine::o_playSFX(uint sound_id) {
if (getGameId() == GID_SIMON1DOS)
playSting(sound_id);
else
_sound->playEffects(sound_id);
}
void SimonEngine::o_unk_160(uint a) {
fcs_setTextColor(_windowArray[_curWindow], a);
}
void SimonEngine::o_unk_103() {
mouseOff();
removeIconArray(_curWindow);
if (getGameType() == GType_FF)
showMessageFormat("\x0E");
else
showMessageFormat("\x0C");
mouseOn();
}
void SimonEngine::o_kill_sprite_simon1(uint a) {
uint16 b = to16Wrapper(a);
_lockWord |= 0x8000;
_vcPtr = (byte *)&b;
vc60_killSprite();
_lockWord &= ~0x8000;
}
void SimonEngine::o_kill_sprite_simon2(uint a, uint b) {
uint16 items[2];
items[0] = to16Wrapper(a);
items[1] = to16Wrapper(b);
_lockWord |= 0x8000;
_vcPtr = (byte *)&items;
vc60_killSprite();
_lockWord &= ~0x8000;
}
/* OK */
void SimonEngine::o_defineWindow(uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h) {
a &= 7;
if (_windowArray[a])
closeWindow(a);
_windowArray[a] = openWindow(b, c, d, e, f, g, h);
if (a == _curWindow) {
_textWindow = _windowArray[a];
showmessage_helper_3(_textWindow->textLength, _textWindow->textMaxLength);
}
}
} // End of namespace Simon