mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-22 18:02:05 +00:00
1622 lines
40 KiB
C++
1622 lines
40 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.
|
|
*
|
|
*/
|
|
|
|
#ifdef ENABLE_EOB
|
|
|
|
#include "kyra/eobcommon.h"
|
|
#include "kyra/screen_eob.h"
|
|
#include "kyra/script_eob.h"
|
|
#include "kyra/resource.h"
|
|
#include "kyra/sound.h"
|
|
|
|
#include "common/system.h"
|
|
|
|
namespace Kyra {
|
|
|
|
void EoBCoreEngine::runLevelScript(int block, int flags) {
|
|
_inf->run(block, flags);
|
|
}
|
|
|
|
void EoBCoreEngine::setScriptFlags(uint32 flags) {
|
|
_inf->setFlags(flags);
|
|
}
|
|
|
|
void EoBCoreEngine::clearScriptFlags(uint32 flags) {
|
|
_inf->clearFlags(flags);
|
|
}
|
|
|
|
bool EoBCoreEngine::checkScriptFlags(uint32 flags) {
|
|
return _inf->checkFlags(flags);
|
|
}
|
|
|
|
const uint8 *EoBCoreEngine::initScriptTimers(const uint8 *pos) {
|
|
_scriptTimersCount = 0;
|
|
|
|
while (((int16)READ_LE_UINT16(pos)) != -1) {
|
|
_scriptTimers[_scriptTimersCount].func = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
uint16 ticks = READ_LE_UINT16(pos) * 18;
|
|
_scriptTimers[_scriptTimersCount].ticks = ticks;
|
|
pos += 2;
|
|
_scriptTimers[_scriptTimersCount++].next = _system->getMillis() + ticks * _tickLength;
|
|
}
|
|
|
|
return pos;
|
|
}
|
|
|
|
void EoBCoreEngine::updateScriptTimers() {
|
|
bool timerUpdate = false;
|
|
if ((_scriptTimersMode & 2) && _stepsUntilScriptCall && _stepCounter > _stepsUntilScriptCall) {
|
|
_inf->run(0, 0x20);
|
|
_stepCounter = 0;
|
|
timerUpdate = true;
|
|
}
|
|
|
|
if (_scriptTimersMode & 1) {
|
|
for (int i = 0; i < _scriptTimersCount; i++) {
|
|
if (_scriptTimers[i].next < _system->getMillis()) {
|
|
_inf->run(_scriptTimers[i].func, _flags.gameID == GI_EOB1 ? 0x20 : 0x80);
|
|
_scriptTimers[i].next = _system->getMillis() + _scriptTimers[i].ticks * _tickLength;
|
|
_sceneUpdateRequired = true;
|
|
timerUpdate = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (timerUpdate)
|
|
updateScriptTimersExtra();
|
|
}
|
|
|
|
EoBInfProcessor::EoBInfProcessor(EoBCoreEngine *engine, Screen_EoB *screen) : _vm(engine), _screen(screen),
|
|
_commandMin(engine->game() == GI_EOB1 ? -27 : -31) {
|
|
|
|
#define Opcode(x) _opcodes.push_back(new InfOpcode(new InfProc(this, &EoBInfProcessor::x), #x))
|
|
#define OpcodeAlt(x) if (_vm->game() == GI_EOB1) { Opcode(x##_v1); } else { Opcode(x##_v2); }
|
|
Opcode(oeob_setWallType);
|
|
Opcode(oeob_toggleWallState);
|
|
Opcode(oeob_openDoor);
|
|
Opcode(oeob_closeDoor);
|
|
Opcode(oeob_replaceMonster);
|
|
Opcode(oeob_movePartyOrObject);
|
|
Opcode(oeob_moveInventoryItemToBlock);
|
|
OpcodeAlt(oeob_printMessage);
|
|
Opcode(oeob_setFlags);
|
|
Opcode(oeob_playSoundEffect);
|
|
Opcode(oeob_removeFlags);
|
|
Opcode(oeob_modifyCharacterHitPoints);
|
|
Opcode(oeob_calcAndInflictCharacterDamage);
|
|
Opcode(oeob_jump);
|
|
Opcode(oeob_end);
|
|
Opcode(oeob_returnFromSubroutine);
|
|
Opcode(oeob_callSubroutine);
|
|
OpcodeAlt(oeob_eval);
|
|
Opcode(oeob_deleteItem);
|
|
Opcode(oeob_loadNewLevelOrMonsters);
|
|
Opcode(oeob_increasePartyExperience);
|
|
OpcodeAlt(oeob_createItem);
|
|
Opcode(oeob_launchObject);
|
|
Opcode(oeob_changeDirection);
|
|
Opcode(oeob_identifyItems);
|
|
Opcode(oeob_sequence);
|
|
Opcode(oeob_delay);
|
|
Opcode(oeob_drawScene);
|
|
Opcode(oeob_dialogue);
|
|
Opcode(oeob_specialEvent);
|
|
#undef Opcode
|
|
#undef OpcodeAlt
|
|
|
|
_scriptData = 0;
|
|
_scriptSize = 0;
|
|
|
|
_abortScript = 0;
|
|
_abortAfterSubroutine = 0;
|
|
_dlgResult = 0;
|
|
_preventRest = 0;
|
|
|
|
_lastScriptFunc = 0;
|
|
_lastScriptFlags = 0;
|
|
|
|
_subroutineStack = new int8*[10];
|
|
memset(_subroutineStack, 0, 10 * sizeof(int8 *));
|
|
_subroutineStackPos = 0;
|
|
|
|
_flagTable = new uint32[18];
|
|
memset(_flagTable, 0, 18 * sizeof(uint32));
|
|
|
|
_stack = new int16[30];
|
|
memset(_stack, 0, 30 * sizeof(int16));
|
|
_stackIndex = 0;
|
|
|
|
_activeCharacter = -1;
|
|
}
|
|
|
|
EoBInfProcessor::~EoBInfProcessor() {
|
|
delete[] _subroutineStack;
|
|
delete[] _flagTable;
|
|
delete[] _stack;
|
|
delete[] _scriptData;
|
|
|
|
for (Common::Array<const InfOpcode *>::const_iterator a = _opcodes.begin(); a != _opcodes.end(); ++a)
|
|
delete *a;
|
|
|
|
_opcodes.clear();
|
|
}
|
|
|
|
void EoBInfProcessor::loadData(const uint8 *data, uint32 dataSize) {
|
|
delete[] _scriptData;
|
|
_scriptSize = dataSize;
|
|
_scriptData = new int8[_scriptSize];
|
|
memcpy(_scriptData, data, _scriptSize);
|
|
}
|
|
|
|
void EoBInfProcessor::run(int func, int flags) {
|
|
int o = _vm->_levelBlockProperties[func].assignedObjects;
|
|
if (!o)
|
|
return;
|
|
|
|
uint16 f = _vm->_levelBlockProperties[func].flags;
|
|
|
|
uint16 subFlags = ((f & 0xFFF8) >> 3) | 0xE0;
|
|
if (!(flags & subFlags))
|
|
return;
|
|
|
|
_abortScript = 0;
|
|
_abortAfterSubroutine = 0;
|
|
_dlgResult = 0;
|
|
_activeCharacter = -1;
|
|
|
|
_lastScriptFunc = func;
|
|
_lastScriptFlags = flags;
|
|
|
|
int8 *pos = (int8 *)(_scriptData + o);
|
|
|
|
do {
|
|
int8 cmd = *pos++;
|
|
if (cmd <= _commandMin || cmd >= 0)
|
|
continue;
|
|
debugC(3, kDebugLevelScript, "[0x%.04X] EoBInfProcessor::%s()", (uint32)(pos - _scriptData), _opcodes[-(cmd + 1)]->desc.c_str());
|
|
pos += (*_opcodes[-(cmd + 1)]->proc)(pos);
|
|
} while (!_abortScript && !_abortAfterSubroutine);
|
|
}
|
|
|
|
void EoBInfProcessor::setFlags(uint32 flags) {
|
|
_flagTable[17] |= flags;
|
|
}
|
|
|
|
void EoBInfProcessor::clearFlags(uint32 flags) {
|
|
_flagTable[17] &= ~flags;
|
|
}
|
|
|
|
bool EoBInfProcessor::checkFlags(uint32 flags) const {
|
|
return ((_flagTable[17] & flags) == flags) ? true : false;
|
|
}
|
|
|
|
bool EoBInfProcessor::preventRest() const {
|
|
return _preventRest ? true : false;
|
|
}
|
|
|
|
void EoBInfProcessor::loadState(Common::SeekableSubReadStreamEndian &in, bool origFile) {
|
|
_preventRest = (_vm->game() == GI_EOB1 && origFile) ? 0 : in.readByte();
|
|
int numFlags = (_vm->game() == GI_EOB1 && origFile) ? 12 : 18;
|
|
for (int i = 0; i < numFlags; i++)
|
|
_flagTable[i] = in.readUint32();
|
|
if (_vm->game() == GI_EOB1 && origFile)
|
|
setFlags(in.readUint32());
|
|
}
|
|
|
|
void EoBInfProcessor::saveState(Common::OutSaveFile *out, bool origFile) {
|
|
if (_vm->game() == GI_EOB2 || !origFile)
|
|
out->writeByte(_preventRest);
|
|
int numFlags = (_vm->game() == GI_EOB1 && origFile) ? 12 : 18;
|
|
for (int i = 0; i < numFlags; i++) {
|
|
if (origFile)
|
|
out->writeUint32LE(_flagTable[i]);
|
|
else
|
|
out->writeUint32BE(_flagTable[i]);
|
|
}
|
|
if (_vm->game() == GI_EOB1 && origFile)
|
|
out->writeUint32LE(_flagTable[17]);
|
|
}
|
|
|
|
void EoBInfProcessor::reset() {
|
|
_preventRest = 0;
|
|
memset(_flagTable, 0, 18 * sizeof(uint32));
|
|
}
|
|
|
|
const char *EoBInfProcessor::getString(uint16 index) {
|
|
if (index == 0xFFFF)
|
|
return 0;
|
|
|
|
int8 *res = _scriptData + READ_LE_UINT16(_scriptData);
|
|
|
|
while (index) {
|
|
if (*res++)
|
|
continue;
|
|
index--;
|
|
}
|
|
|
|
return (const char *)res;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_setWallType(int8 *data) {
|
|
int8 *pos = data;
|
|
|
|
uint16 block = 0;
|
|
int8 dir = 0;
|
|
|
|
switch (*pos++) {
|
|
case -23:
|
|
block = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
dir = *pos++;
|
|
_vm->_levelBlockProperties[block].walls[dir] = *pos++;
|
|
_vm->checkSceneUpdateNeed(block);
|
|
break;
|
|
|
|
case -19:
|
|
_vm->_currentDirection = *pos++;
|
|
break;
|
|
|
|
case -9:
|
|
block = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
dir = *pos++;
|
|
memset(_vm->_levelBlockProperties[block].walls, dir, 4 * sizeof(uint8));
|
|
_vm->checkSceneUpdateNeed(block);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_toggleWallState(int8 *data) {
|
|
int8 *pos = data;
|
|
|
|
uint16 block = 0;
|
|
int8 dir = 0;
|
|
uint8 a = 0;
|
|
uint8 b = 0;
|
|
|
|
switch (*pos++) {
|
|
case -23:
|
|
block = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
dir = *pos++;
|
|
a = (uint8)*pos++;
|
|
b = (uint8)*pos++;
|
|
a = (_vm->_levelBlockProperties[block].walls[dir] == a) ? b : a;
|
|
_vm->_levelBlockProperties[block].walls[dir] = a;
|
|
_vm->checkSceneUpdateNeed(block);
|
|
break;
|
|
|
|
case -22:
|
|
_vm->processDoorSwitch(READ_LE_UINT16(pos), 0);
|
|
pos += 2;
|
|
break;
|
|
|
|
case -9:
|
|
block = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
a = (uint8)*pos++;
|
|
b = (uint8)*pos++;
|
|
a = (_vm->_levelBlockProperties[block].walls[dir] == a) ? b : a;
|
|
memset(_vm->_levelBlockProperties[block].walls, a, 4 * sizeof(uint8));
|
|
_vm->checkSceneUpdateNeed(block);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_openDoor(int8 *data) {
|
|
int8 *pos = data;
|
|
_vm->openDoor(READ_LE_UINT16(pos));
|
|
pos += 2;
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_closeDoor(int8 *data) {
|
|
int8 *pos = data;
|
|
_vm->closeDoor(READ_LE_UINT16(pos));
|
|
pos += 2;
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_replaceMonster(int8 *data) {
|
|
int8 *pos = data;
|
|
_vm->replaceMonster(pos[1], READ_LE_UINT16(pos + 2), pos[4], pos[5], pos[6], pos[7], pos[8], pos[9], READ_LE_UINT16(pos + 10), READ_LE_UINT16(pos + 12));
|
|
pos += 14;
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_movePartyOrObject(int8 *data) {
|
|
int8 *pos = data;
|
|
|
|
int8 a = *pos++;
|
|
uint16 b = 0xFFFF;
|
|
uint16 c = 0;
|
|
uint16 d = 0;
|
|
|
|
if (_vm->game() == GI_EOB2 && a == -31) {
|
|
b = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
}
|
|
|
|
if (_vm->game() == GI_EOB1) {
|
|
if (a != -15) {
|
|
c = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
}
|
|
d = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
}
|
|
|
|
if (_vm->game() == GI_EOB2 && a != -31 && a != -11) {
|
|
c = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
d = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
}
|
|
|
|
if (a == -13) {
|
|
// move monster from block c to block d
|
|
for (int i = 0; i < 30; i++) {
|
|
if (_vm->_monsters[i].block != c)
|
|
continue;
|
|
_vm->placeMonster(&_vm->_monsters[i], d, _vm->_monsters[i].pos);
|
|
}
|
|
debugC(5, kDebugLevelScript, " - move monsters on block '0x%.04X' to block '0x%.04X'", c, d);
|
|
|
|
} else if (a == -24) {
|
|
// move party to block d
|
|
int ba = _dlgResult;
|
|
int bb = _lastScriptFunc;
|
|
int bc = _lastScriptFlags;
|
|
int bd = _abortScript;
|
|
int be = _activeCharacter;
|
|
int bf = _subroutineStackPos;
|
|
|
|
_vm->moveParty(d);
|
|
debugC(5, kDebugLevelScript, " - move party to block '0x%.04X'", d);
|
|
|
|
_dlgResult = ba;
|
|
_lastScriptFunc = bb;
|
|
_lastScriptFlags = bc;
|
|
_abortScript = bd;
|
|
_activeCharacter = be;
|
|
if (!_abortAfterSubroutine)
|
|
_subroutineStackPos = bf;
|
|
_vm->_sceneDefaultUpdate = 0;
|
|
|
|
} else if ((a == -31 && _vm->game() == GI_EOB2) || a == -11) {
|
|
// move item
|
|
int8 e = _vm->_currentLevel;
|
|
int8 f = _vm->_currentLevel;
|
|
|
|
if (_vm->game() == GI_EOB2) {
|
|
e = (*pos++ == -21) ? _vm->_currentLevel : *pos++;
|
|
c = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
f = (*pos++ == -21) ? _vm->_currentLevel : *pos++;
|
|
d = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
}
|
|
|
|
if (e == _vm->_currentLevel) {
|
|
int i = _vm->countQueuedItems(_vm->_levelBlockProperties[c].drawObjects, -1, (int16)b, 0, 1);
|
|
while (i) {
|
|
int p = _vm->_items[i].pos;
|
|
_vm->getQueuedItem((Item *)&_vm->_levelBlockProperties[c].drawObjects, 0, i);
|
|
if (_vm->_currentLevel == f) {
|
|
_vm->setItemPosition((Item *)&_vm->_levelBlockProperties[d].drawObjects, d, i, p);
|
|
} else {
|
|
_vm->_items[i].level = f;
|
|
_vm->_items[i].block = d;
|
|
if (p < 8)
|
|
_vm->_items[i].pos = p & 3;
|
|
}
|
|
i = _vm->countQueuedItems(_vm->_levelBlockProperties[c].drawObjects, -1, (int16)b, 0, 1);
|
|
}
|
|
|
|
for (i = 0; i < 10; i++) {
|
|
if (_vm->_flyingObjects[i].enable != 1 || _vm->_flyingObjects[i].curBlock != c)
|
|
continue;
|
|
if (f == _vm->_currentLevel || _vm->game() == GI_EOB1)
|
|
_vm->_flyingObjects[i].curBlock = d;
|
|
else
|
|
_vm->_flyingObjects[i].enable = 0;
|
|
}
|
|
|
|
} else {
|
|
for (int i = 0; i < 600; i++) {
|
|
if (_vm->_items[i].level != e || _vm->_items[i].block != c)
|
|
continue;
|
|
_vm->_items[i].level = f;
|
|
_vm->_items[i].block = d;
|
|
}
|
|
}
|
|
debugC(5, kDebugLevelScript, " - move items from level '%d', block '0x%.04X' to level '%d', block '0x%.04X'", c, e, d, f);
|
|
}
|
|
|
|
_vm->_sceneUpdateRequired = true;
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_moveInventoryItemToBlock(int8 *data) {
|
|
int8 *pos = data;
|
|
int8 c = *pos++;
|
|
uint16 block = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
int8 p = *pos++;
|
|
|
|
if (c == -1)
|
|
c = _vm->rollDice(1, 6, -1);
|
|
|
|
while (!(_vm->_characters[c].flags & 1)) {
|
|
if (++c == 5)
|
|
c = 0;
|
|
}
|
|
|
|
if (_vm->_currentControlMode && (_vm->_updateCharNum == c))
|
|
return pos - data;
|
|
|
|
int slot = _vm->rollDice(1, 27, 0);
|
|
int itm = 0;
|
|
int i = 0;
|
|
|
|
for (; i < 27; i++) {
|
|
if ((!_vm->_currentControlMode && slot > 1) || slot == 16)
|
|
continue;
|
|
|
|
itm = _vm->_characters[c].inventory[slot];
|
|
|
|
if (!itm)
|
|
continue;
|
|
|
|
if (_vm->_dscItemShapeMap[_vm->_items[itm].icon] >= 15)
|
|
break;
|
|
|
|
if (++slot == 27)
|
|
slot = 0;
|
|
}
|
|
|
|
if (i < 27 && itm) {
|
|
_vm->_characters[c].inventory[slot] = 0;
|
|
_vm->setItemPosition((Item *)&_vm->_levelBlockProperties[block].drawObjects, block, itm, p);
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_printMessage_v1(int8 *data) {
|
|
static const char colorConfig[] = "\x6\x21\x2\x21";
|
|
char col[5];
|
|
int8 *pos = data;
|
|
|
|
strcpy(col, colorConfig);
|
|
const char *str = (const char *)pos;
|
|
pos += (strlen(str) + 1);
|
|
|
|
col[1] = *pos++;
|
|
col[3] = *pos++;
|
|
_vm->txt()->printMessage(col);
|
|
_vm->txt()->printMessage(str);
|
|
|
|
col[1] = _screen->_curDim->unk8;
|
|
col[3] = _screen->_curDim->unkA;
|
|
_vm->txt()->printMessage(col);
|
|
_vm->txt()->printMessage("\r");
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_printMessage_v2(int8 *data) {
|
|
int8 *pos = data;
|
|
uint16 str = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
uint8 col = (uint8)*pos;
|
|
pos += 2;
|
|
|
|
int c = 0;
|
|
if (_activeCharacter == -1) {
|
|
c = _vm->rollDice(1, 6, -1);
|
|
while (!_vm->testCharacter(c, 3))
|
|
c = (c + 1) % 6;
|
|
} else {
|
|
c = _activeCharacter;
|
|
}
|
|
|
|
_vm->txt()->printMessage(getString(str), col, _vm->_characters[c].name);
|
|
_vm->txt()->printMessage("\r");
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_setFlags(int8 *data) {
|
|
int8 *pos = data;
|
|
int8 b = 0;
|
|
|
|
switch (*pos++) {
|
|
case -47:
|
|
_preventRest = 0;
|
|
debugC(5, kDebugLevelScript, " - set preventRest to 0");
|
|
break;
|
|
|
|
case -28:
|
|
_dlgResult = 1;
|
|
debugC(5, kDebugLevelScript, " - set dlgResult to 1");
|
|
break;
|
|
|
|
case -17:
|
|
_flagTable[_vm->_currentLevel] |= (1 << (*pos++));
|
|
debugC(5, kDebugLevelScript, " - set level flag '%d' for current level (current level = '%d')", *(pos - 1), _vm->_currentLevel);
|
|
break;
|
|
|
|
case -16:
|
|
_flagTable[17] |= (1 << (*pos++));
|
|
debugC(5, kDebugLevelScript, " - set global flag '%d'", *(pos - 1));
|
|
break;
|
|
|
|
case -13:
|
|
b = *pos++;
|
|
_vm->_monsters[b].flags |= (1 << (*pos++));
|
|
_vm->_monsters[b].mode = 0;
|
|
debugC(5, kDebugLevelScript, " - set monster flag '%d' for monster '%d'", *(pos - 1), b);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_playSoundEffect(int8 *data) {
|
|
int8 *pos = data;
|
|
uint16 block = READ_LE_UINT16(pos + 1);
|
|
|
|
if (block) {
|
|
_vm->snd_processEnvironmentalSoundEffect(pos[0], block);
|
|
} else {
|
|
_vm->snd_playSoundEffect(pos[0]);
|
|
}
|
|
|
|
pos += 3;
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_removeFlags(int8 *data) {
|
|
int8 *pos = data;
|
|
int8 a = *pos++;
|
|
|
|
switch (a) {
|
|
case -47:
|
|
_preventRest = 1;
|
|
debugC(5, kDebugLevelScript, " - set preventRest to 1");
|
|
break;
|
|
|
|
case -28:
|
|
_dlgResult = 0;
|
|
debugC(5, kDebugLevelScript, " - set dlgResult to 0");
|
|
break;
|
|
|
|
case -17:
|
|
_flagTable[_vm->_currentLevel] &= ~(1 << (*pos++));
|
|
debugC(5, kDebugLevelScript, " - clear level flag '%d' for current level (current level = '%d')", *(pos - 1), _vm->_currentLevel);
|
|
break;
|
|
|
|
case -16:
|
|
_flagTable[17] &= ~(1 << (*pos++));
|
|
debugC(5, kDebugLevelScript, " - clear global flag '%d'", *(pos - 1));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_modifyCharacterHitPoints(int8 *data) {
|
|
int8 *pos = data;
|
|
int8 c = *pos++;
|
|
int8 p = *pos++;
|
|
|
|
if (c == -1) {
|
|
for (c = 0; c < 6; c++)
|
|
_vm->modifyCharacterHitpoints(c, p);
|
|
} else {
|
|
_vm->modifyCharacterHitpoints(c, p);
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_calcAndInflictCharacterDamage(int8 *data) {
|
|
int8 *pos = data;
|
|
int charIndex = *pos++;
|
|
int times = *pos++;
|
|
int itemOrPips = *pos++;
|
|
int useStrModifierOrBase = *pos++;
|
|
|
|
int flg = (charIndex == -1) ? 4 : 0;
|
|
int savingThrowType = 5;
|
|
int savingThrowEffect = 1;
|
|
|
|
if (_vm->game() == GI_EOB2) {
|
|
flg = *pos++;
|
|
savingThrowType = *pos++;
|
|
savingThrowEffect = *pos++;
|
|
} else if (!itemOrPips) {
|
|
useStrModifierOrBase = times;
|
|
times = 0;
|
|
}
|
|
|
|
if (charIndex == -1) {
|
|
for (int i = 0; i < 6; i++)
|
|
_vm->calcAndInflictCharacterDamage(i, times, itemOrPips, useStrModifierOrBase, flg, savingThrowType, savingThrowEffect);
|
|
} else {
|
|
_vm->calcAndInflictCharacterDamage(charIndex, times, itemOrPips, useStrModifierOrBase, flg, savingThrowType, savingThrowEffect);
|
|
}
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_jump(int8 *data) {
|
|
int8 *pos = data;
|
|
pos = _scriptData + READ_LE_UINT16(pos);
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_end(int8 *data) {
|
|
_abortScript = 1;
|
|
_subroutineStackPos = 0;
|
|
return 0;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_returnFromSubroutine(int8 *data) {
|
|
int8 *pos = data;
|
|
|
|
if (_subroutineStackPos)
|
|
pos = _subroutineStack[--_subroutineStackPos];
|
|
else
|
|
_abortScript = 1;
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_callSubroutine(int8 *data) {
|
|
int8 *pos = data;
|
|
uint16 offs = READ_LE_UINT16(pos);
|
|
assert(offs < _scriptSize);
|
|
pos += 2;
|
|
|
|
if (_subroutineStackPos < 10) {
|
|
_subroutineStack[_subroutineStackPos++] = pos;
|
|
pos = _scriptData + offs;
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_eval_v1(int8 *data) {
|
|
int8 *pos = data;
|
|
int8 cmd = *pos++;
|
|
|
|
int a = 0;
|
|
int b = 0;
|
|
int i = 0;
|
|
EoBItem *itm = &_vm->_items[_vm->_itemInHand];
|
|
Common::String tempString1;
|
|
Common::String tempString2;
|
|
|
|
while (cmd != -18) {
|
|
switch (cmd + 38) {
|
|
case 0:
|
|
a = 1;
|
|
for (i = 0; i < 6; i++) {
|
|
if (!(_vm->_characters[i].flags & 1))
|
|
continue;
|
|
if (_vm->_characters[i].effectFlags & 0x40)
|
|
continue;
|
|
a = 0;
|
|
break;
|
|
}
|
|
_stack[_stackIndex++] = a;
|
|
debugC(5, kDebugLevelScript, " - check if whole party is invisible - PUSH result: '%d'", a);
|
|
break;
|
|
|
|
case 1:
|
|
_stack[_stackIndex++] = _vm->rollDice(pos[0], pos[1], pos[2]);
|
|
debugC(9, kDebugLevelScript, " - throw dice(s): num = '%d', pips = '%d', offset = '%d' - PUSH result: '%d'", pos[0], pos[1], pos[2], _stack[_stackIndex - 1]);
|
|
pos += 3;
|
|
break;
|
|
|
|
case 2:
|
|
cmd = *pos++;
|
|
b = 0;
|
|
for (i = 0; i < 6; i++) {
|
|
if (!(_vm->_characters[i].flags & 1))
|
|
continue;
|
|
if (_vm->_classModifierFlags[_vm->_characters[i].cClass] & cmd) {
|
|
b = 1;
|
|
break;
|
|
}
|
|
}
|
|
_stack[_stackIndex++] = b;
|
|
debugC(5, kDebugLevelScript, " - check if character with class flags '0x%.02X' is present - PUSH result: '%d'", cmd, b);
|
|
break;
|
|
|
|
case 3:
|
|
cmd = *pos++;
|
|
b = 0;
|
|
for (i = 0; i < 6; i++) {
|
|
if (!(_vm->_characters[i].flags & 1))
|
|
continue;
|
|
if ((_vm->_characters[i].raceSex >> 1) == cmd) {
|
|
b = 1;
|
|
break;
|
|
}
|
|
}
|
|
_stack[_stackIndex++] = b;
|
|
debugC(5, kDebugLevelScript, " - check if character with race '%d' is present - PUSH result: '%d'", cmd, b);
|
|
break;
|
|
|
|
case 6:
|
|
_stack[_stackIndex++] = _lastScriptFlags;
|
|
debugC(5, kDebugLevelScript, " - get script execution flags - PUSH result: '%d'", _lastScriptFlags);
|
|
break;
|
|
|
|
case 13:
|
|
itm = &_vm->_items[_vm->_itemInHand];
|
|
switch (*pos++) {
|
|
case -31:
|
|
_stack[_stackIndex++] = itm->type;
|
|
debugC(5, kDebugLevelScript, " - get hand item type (hand item number = '%d') - PUSH result: '%d'", _vm->_itemInHand, itm->type);
|
|
break;
|
|
|
|
case -11:
|
|
_stack[_stackIndex++] = _vm->_itemInHand;
|
|
debugC(5, kDebugLevelScript, " - get hand item number - PUSH result: '%d'", _vm->_itemInHand);
|
|
break;
|
|
|
|
default:
|
|
_stack[_stackIndex++] = itm->value;
|
|
debugC(5, kDebugLevelScript, " - get hand item value (hand item number = '%d') - PUSH result: '%d'", _vm->_itemInHand, itm->value);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 15:
|
|
_stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos + 1)].walls[pos[0]];
|
|
debugC(5, kDebugLevelScript, " - get wall index for block '0x%.04X', direction '%d' - PUSH result: '%d'", READ_LE_UINT16(pos + 1), pos[0], _stack[_stackIndex - 1]);
|
|
pos += 3;
|
|
break;
|
|
|
|
case 19:
|
|
_stack[_stackIndex++] = _vm->_currentDirection;
|
|
debugC(5, kDebugLevelScript, " - get current direction - PUSH result: '%d'", _vm->_currentDirection);
|
|
break;
|
|
|
|
case 21:
|
|
_stack[_stackIndex++] = (_flagTable[_vm->_currentLevel] & (1 << (*pos++))) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - test level flag '%d' (current level = '%d') - PUSH result: '%d'", *(pos - 1), _vm->_currentLevel, _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
case 22:
|
|
_stack[_stackIndex++] = (_flagTable[17] & (1 << (*pos++))) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - test global flag '%d' - PUSH result: '%d'", *(pos - 1), _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
case 23:
|
|
_stack[_stackIndex++] = (_vm->_currentBlock == READ_LE_UINT16(pos)) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - compare current block with block '0x%.04X' (current block = '0x%.04X') - PUSH result: '%d'", _vm->_currentBlock, READ_LE_UINT16(pos), _stack[_stackIndex - 1]);
|
|
pos += 2;
|
|
break;
|
|
|
|
case 24:
|
|
a = (int16)READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
b = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
_stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[b].drawObjects, a, -1, 0, 1);
|
|
debugC(5, kDebugLevelScript, " - find item number '%d' on block '0x%.04X' - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
case 25:
|
|
_stack[_stackIndex++] = (_vm->_levelBlockProperties[READ_LE_UINT16(pos)].flags & 1) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - test block flag '1' for block '0x%.04X' - PUSH result: '%d'", READ_LE_UINT16(pos), _stack[_stackIndex - 1]);
|
|
pos += 2;
|
|
break;
|
|
|
|
case 27:
|
|
b = *pos++;
|
|
i = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
_stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[i].drawObjects, -1, b, 1, 1);
|
|
debugC(5, kDebugLevelScript, " - count items of type '%d' on block '0x%.04X' - PUSH result: '%d'", b, i, _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
case 29:
|
|
_stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos)].walls[0];
|
|
debugC(5, kDebugLevelScript, " - get wall index 0 for block '0x%.04X' - PUSH result: '%d'", READ_LE_UINT16(pos), _stack[_stackIndex - 1]);
|
|
pos += 2;
|
|
break;
|
|
|
|
case 30:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a || b) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - evaluate: POP('%d') || POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
case 31:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a && b) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - evaluate: POP('%d') && POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
case 32:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a <= b) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - evaluate: POP('%d') <= POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
case 33:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a < b) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - evaluate: POP('%d') < POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
case 34:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a >= b) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - evaluate: POP('%d') >= POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
case 35:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a > b) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - evaluate: POP('%d') > POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
case 36:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a != b) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - evaluate: POP('%d') != POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
case 37:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a == b) ? 1 : 0;
|
|
debugC(5, kDebugLevelScript, " - evaluate: POP('%d') == POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
|
|
break;
|
|
|
|
default:
|
|
a = cmd;
|
|
if (a >= 0 && a < 128)
|
|
_stack[_stackIndex++] = a;
|
|
debugC(5, kDebugLevelScript, " - PUSH value: '%d'", a);
|
|
break;
|
|
}
|
|
cmd = *pos++;
|
|
}
|
|
|
|
cmd = _stack[--_stackIndex];
|
|
if (cmd)
|
|
pos += 2;
|
|
else
|
|
pos = _scriptData + READ_LE_UINT16(pos);
|
|
debugC(5, kDebugLevelScript, " - conditional jump depending on POP('%d')", cmd);
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_eval_v2(int8 *data) {
|
|
int8 *pos = data;
|
|
int8 cmd = *pos++;
|
|
|
|
int a = 0;
|
|
int b = 0;
|
|
int i = 0;
|
|
EoBItem *itm = (_vm->_itemInHand != -1) ? &_vm->_items[_vm->_itemInHand] : 0;
|
|
Common::String tempString1;
|
|
Common::String tempString2;
|
|
|
|
while (cmd != -18) {
|
|
switch (cmd + 50) {
|
|
case 0:
|
|
a = 0;
|
|
b = *pos++;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
if (!_vm->testCharacter(i, 5))
|
|
continue;
|
|
|
|
if (_vm->_characters[i].portrait != b) {
|
|
a = 1;
|
|
_activeCharacter = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
_stack[_stackIndex++] = a;
|
|
break;
|
|
|
|
case 4:
|
|
_stack[_stackIndex++] = (int16)READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
break;
|
|
|
|
case 9:
|
|
switch (*pos++) {
|
|
case -36:
|
|
_stack[_stackIndex++] = _vm->_itemTypes[_vm->_items[_vm->_lastUsedItem].type].extraProperties & 0x7F;
|
|
break;
|
|
case -31:
|
|
_stack[_stackIndex++] = _vm->_items[_vm->_lastUsedItem].type;
|
|
break;
|
|
case -11:
|
|
_stack[_stackIndex++] = _vm->_lastUsedItem;
|
|
break;
|
|
case -10:
|
|
_stack[_stackIndex++] = _vm->_items[_vm->_lastUsedItem].value;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 12:
|
|
a = 1;
|
|
for (i = 0; i < 6; i++) {
|
|
if (!(_vm->_characters[i].flags & 1))
|
|
continue;
|
|
if (_vm->_characters[i].effectFlags & 0x40)
|
|
continue;
|
|
a = 0;
|
|
break;
|
|
}
|
|
_stack[_stackIndex++] = a;
|
|
break;
|
|
|
|
case 13:
|
|
_stack[_stackIndex++] = _vm->rollDice(pos[0], pos[1], pos[2]);
|
|
pos += 3;
|
|
break;
|
|
|
|
case 14:
|
|
cmd = *pos++;
|
|
a = _vm->rollDice(1, 6);
|
|
b = 0;
|
|
for (i = 0; i < 6 && b == 0; i++) {
|
|
if (++a > 5)
|
|
a = 0;
|
|
if (_vm->testCharacter(a, 5)) {
|
|
if (_vm->_classModifierFlags[_vm->_characters[a].cClass] & cmd) {
|
|
_activeCharacter = a;
|
|
b = 1;
|
|
}
|
|
}
|
|
}
|
|
_stack[_stackIndex++] = b;
|
|
break;
|
|
|
|
case 15:
|
|
cmd = *pos++;
|
|
a = _vm->rollDice(1, 6);
|
|
b = 0;
|
|
for (i = 0; i < 6; i++) {
|
|
if (++a > 5)
|
|
a = 0;
|
|
if (_vm->testCharacter(a, 5)) {
|
|
if ((_vm->_characters[a].raceSex >> 1) == cmd) {
|
|
_activeCharacter = a;
|
|
b = 1;
|
|
}
|
|
}
|
|
}
|
|
_stack[_stackIndex++] = b;
|
|
break;
|
|
|
|
case 17:
|
|
_stack[_stackIndex++] = _vm->_activeSpell;
|
|
break;
|
|
|
|
case 18:
|
|
_stack[_stackIndex++] = _lastScriptFlags;
|
|
break;
|
|
|
|
case 22:
|
|
_stack[_stackIndex++] = _dlgResult;
|
|
break;
|
|
|
|
case 25:
|
|
itm = &_vm->_items[_vm->_itemInHand];
|
|
|
|
switch (*pos++) {
|
|
case -49:
|
|
a = *pos++;
|
|
tempString1 = _vm->_itemNames[itm->nameId];
|
|
tempString1.toUppercase();
|
|
tempString2 = (const char *)pos;
|
|
tempString2.toUppercase();
|
|
pos += a;
|
|
_stack[_stackIndex++] = tempString1.contains(tempString2) ? 1 : 0;
|
|
break;
|
|
|
|
case -48:
|
|
a = *pos++;
|
|
tempString1 = _vm->_itemNames[itm->nameUnid];
|
|
tempString1.toUppercase();
|
|
tempString2 = (const char *)pos;
|
|
tempString2.toUppercase();
|
|
pos += a;
|
|
_stack[_stackIndex++] = tempString1.contains(tempString2) ? 1 : 0;
|
|
break;
|
|
|
|
case -31:
|
|
_stack[_stackIndex++] = itm->type;
|
|
break;
|
|
|
|
case -11:
|
|
_stack[_stackIndex++] = _vm->_itemInHand;
|
|
break;
|
|
|
|
case -10:
|
|
_stack[_stackIndex++] = itm->value;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case 26:
|
|
a = 0;
|
|
for (i = 0; i < 6; i++) {
|
|
if (_vm->testCharacter(i, 0x0F))
|
|
a++;
|
|
}
|
|
_stack[_stackIndex++] = a;
|
|
break;
|
|
|
|
case 27:
|
|
_stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos + 1)].walls[pos[0]];
|
|
pos += 3;
|
|
break;
|
|
|
|
case 31:
|
|
_stack[_stackIndex++] = _vm->_currentDirection;
|
|
break;
|
|
|
|
case 33:
|
|
_stack[_stackIndex++] = (_flagTable[_vm->_currentLevel] & (1 << (*pos++))) ? 1 : 0;
|
|
break;
|
|
|
|
case 34:
|
|
_stack[_stackIndex++] = (_flagTable[17] & (1 << (*pos++))) ? 1 : 0;
|
|
break;
|
|
|
|
case 35:
|
|
if (*pos++ == -11) {
|
|
a = (int16)READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
b = (int16)READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
_stack[_stackIndex++] = _vm->countCharactersWithSpecificItems(a, b);
|
|
} else {
|
|
_stack[_stackIndex++] = (_vm->_currentBlock == READ_LE_UINT16(pos)) ? 1 : 0;
|
|
pos += 2;
|
|
}
|
|
break;
|
|
|
|
case 36:
|
|
a = (int16)READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
b = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
_stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[b].drawObjects, a, -1, 0, 0);
|
|
break;
|
|
|
|
case 37:
|
|
if (*pos++ == -1) {
|
|
_stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos)].flags & 7;
|
|
pos += 2;
|
|
} else {
|
|
do {
|
|
a += _vm->countSpecificMonsters(*pos++);
|
|
} while (*pos != -1);
|
|
pos++;
|
|
_stack[_stackIndex++] = a;
|
|
}
|
|
break;
|
|
|
|
case 39:
|
|
a = *pos++;
|
|
b = *pos++;
|
|
i = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
_stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[i].drawObjects, -1, b, 1, a);
|
|
break;
|
|
|
|
case 41:
|
|
_stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos)].walls[0];
|
|
pos += 2;
|
|
break;
|
|
|
|
case 42:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a || b) ? 1 : 0;
|
|
break;
|
|
|
|
case 43:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a && b) ? 1 : 0;
|
|
break;
|
|
|
|
case 44:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a <= b) ? 1 : 0;
|
|
break;
|
|
|
|
case 45:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a < b) ? 1 : 0;
|
|
break;
|
|
|
|
case 46:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a >= b) ? 1 : 0;
|
|
break;
|
|
|
|
case 47:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a > b) ? 1 : 0;
|
|
break;
|
|
|
|
case 48:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a != b) ? 1 : 0;
|
|
break;
|
|
|
|
case 49:
|
|
a = _stack[--_stackIndex];
|
|
b = _stack[--_stackIndex];
|
|
_stack[_stackIndex++] = (a == b) ? 1 : 0;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
cmd = *pos++;
|
|
}
|
|
|
|
cmd = _stack[--_stackIndex];
|
|
if (cmd)
|
|
pos += 2;
|
|
else
|
|
pos = _scriptData + READ_LE_UINT16(pos);
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_deleteItem(int8 *data) {
|
|
int8 *pos = data;
|
|
int8 c = *pos++;
|
|
|
|
if (c == -1) {
|
|
_vm->deleteInventoryItem(0, -1);
|
|
debugC(5, kDebugLevelScript, " - delete hand item");
|
|
} else {
|
|
_vm->deleteBlockItem(READ_LE_UINT16(pos), (c == -2) ? -1 : c);
|
|
debugC(5, kDebugLevelScript, " - delete item(s) of type '%d' on block '0x%.04X'", (c == -2) ? -1 : c, READ_LE_UINT16(pos));
|
|
pos += 2;
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_loadNewLevelOrMonsters(int8 *data) {
|
|
int8 *pos = data;
|
|
_vm->gui_updateControls();
|
|
|
|
int8 cmd = *pos++;
|
|
int8 index = *pos++;
|
|
int res = 0;
|
|
|
|
if (cmd == -27 || _vm->game() == GI_EOB1) {
|
|
cmd = _vm->game() == GI_EOB2 ? *pos++ : 0;
|
|
_vm->_currentBlock = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
uint8 dir = (uint8)*pos++;
|
|
|
|
if (dir != 0xFF)
|
|
_vm->_currentDirection = dir;
|
|
|
|
for (int i = 0; i < 30; i++)
|
|
_vm->_monsters[i].curAttackFrame = 0;
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
EoBFlyingObject *fo = &_vm->_flyingObjects[i];
|
|
if (fo->enable == 1) {
|
|
_vm->_items[fo->item].pos &= 3;
|
|
run(_vm->_items[fo->item].block, 4);
|
|
}
|
|
fo->enable = 0;
|
|
}
|
|
|
|
_vm->completeDoorOperations();
|
|
|
|
_vm->generateTempData();
|
|
_vm->txt()->removePageBreakFlag();
|
|
_screen->setScreenDim(7);
|
|
|
|
_vm->loadLevel(index, cmd);
|
|
debugC(5, kDebugLevelScript, " - entering level '%d', sub level '%d', start block '0x%.04X', start direction '%d'", index, cmd, _vm->_currentBlock, _vm->_currentDirection);
|
|
|
|
if (_vm->_dialogueField)
|
|
_vm->restoreAfterDialogueSequence();
|
|
|
|
_vm->moveParty(_vm->_currentBlock);
|
|
|
|
_abortScript = 1;
|
|
_abortAfterSubroutine = 1;
|
|
_vm->_sceneUpdateRequired = true;
|
|
|
|
_vm->gui_drawAllCharPortraitsWithStats();
|
|
_subroutineStackPos = 0;
|
|
|
|
} else {
|
|
cmd = *pos++;
|
|
_vm->releaseMonsterShapes(cmd * 18, 18);
|
|
_vm->loadMonsterShapes((const char *)pos, cmd * 18, true, index * 18);
|
|
debugC(5, kDebugLevelScript, " - loading monster shapes '%s', monster number '%d', encode type '%d'", (const char *)pos, cmd, index);
|
|
pos += 13;
|
|
_vm->gui_restorePlayField();
|
|
res = pos - data;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_increasePartyExperience(int8 *data) {
|
|
int8 *pos = data;
|
|
if (*pos++ == -30) {
|
|
_vm->increasePartyExperience((int16)READ_LE_UINT16(pos));
|
|
debugC(5, kDebugLevelScript, " - award '%d' experience points", READ_LE_UINT16(pos));
|
|
pos += 2;
|
|
}
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_createItem_v1(int8 *data) {
|
|
int8 *pos = data;
|
|
uint16 itm = _vm->duplicateItem(READ_LE_UINT16(pos));
|
|
pos += 2;
|
|
uint16 block = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
uint8 itmPos = *pos++;
|
|
|
|
if (itm) {
|
|
if (block == 0xFFFF && !_vm->_itemInHand) {
|
|
_vm->setHandItem(itm);
|
|
debugC(5, kDebugLevelScript, " - create hand item '%d'", itm);
|
|
} else if (block != 0xFFFF) {
|
|
_vm->setItemPosition((Item *)&_vm->_levelBlockProperties[block & 0x3FF].drawObjects, block, itm, itmPos);
|
|
debugC(5, kDebugLevelScript, " - create item '%d' on block '0x%.04X', position '%d'", itm, block, itmPos);
|
|
}
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_createItem_v2(int8 *data) {
|
|
static const uint8 _itemPos[] = { 0, 1, 2, 3, 1, 3, 0, 2, 3, 2, 1, 0, 2, 0, 3, 1 };
|
|
int8 *pos = data;
|
|
|
|
uint16 itm = _vm->duplicateItem(READ_LE_UINT16(pos));
|
|
pos += 2;
|
|
uint16 block = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
uint8 itmPos = *pos++;
|
|
uint8 flg = *pos++;
|
|
|
|
if (flg & 1)
|
|
_vm->_items[itm].value = *pos++;
|
|
|
|
if (flg & 2)
|
|
_vm->_items[itm].flags = *pos++;
|
|
|
|
if (flg & 4)
|
|
_vm->_items[itm].icon = *pos++;
|
|
|
|
if (!itm)
|
|
return pos - data;
|
|
|
|
if (block == 0xFFFF) {
|
|
if (!_vm->_itemInHand) {
|
|
_vm->setHandItem(itm);
|
|
debugC(5, kDebugLevelScript, " - create hand item '%d' (value '%d', flags '0x%X', icon number '%d')", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon);
|
|
} else {
|
|
_vm->setItemPosition((Item *)&_vm->_levelBlockProperties[_vm->_currentBlock & 0x3FF].drawObjects, _vm->_currentBlock, itm, _itemPos[_vm->rollDice(1, 2, -1)]);
|
|
debugC(5, kDebugLevelScript, " - create item '%d' (value '%d', flags '0x%X', icon number '%d') on current block", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon);
|
|
}
|
|
} else if (block == 0xFFFE) {
|
|
_vm->setItemPosition((Item *)&_vm->_levelBlockProperties[_vm->_currentBlock & 0x3FF].drawObjects, _vm->_currentBlock, itm, _itemPos[(_vm->_currentDirection << 2) + _vm->rollDice(1, 2, -1)]);
|
|
debugC(5, kDebugLevelScript, " - create item '%d' (value '%d', flags '0x%X', icon number '%d') on current block", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon);
|
|
} else {
|
|
_vm->setItemPosition((Item *)&_vm->_levelBlockProperties[block & 0x3FF].drawObjects, block, itm, itmPos);
|
|
debugC(5, kDebugLevelScript, " - create item '%d' (value '%d', flags '0x%X', icon number '%d') on block '0x%.04X', position '%d'", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon, block, itmPos);
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_launchObject(int8 *data) {
|
|
static const uint8 startPos[] = { 2, 3, 0, 2, 1, 0, 3, 1 };
|
|
|
|
int8 *pos = data;
|
|
bool m = (*pos++ == -33);
|
|
int i = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
uint16 block = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
int dir = *pos++;
|
|
int dirOffs = *pos++;
|
|
|
|
if (m) {
|
|
uint8 openBookType = _vm->_openBookType;
|
|
_vm->_openBookType = 0;
|
|
_vm->launchMagicObject(-1, i, block, startPos[dir * 2 + dirOffs], dir);
|
|
_vm->_openBookType = openBookType;
|
|
} else {
|
|
Item itm = _vm->duplicateItem(i);
|
|
if (itm) {
|
|
if (!_vm->launchObject(-1, itm, block, startPos[dir * 2 + dirOffs], dir, _vm->_items[itm].type))
|
|
_vm->_items[itm].block = -1;
|
|
}
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_changeDirection(int8 *data) {
|
|
int8 *pos = data;
|
|
|
|
int8 cmd = *pos++;
|
|
int8 dir = *pos++;
|
|
|
|
if (cmd == -15) {
|
|
_vm->_currentDirection = (_vm->_currentDirection + dir) & 3;
|
|
//_vm->_keybControlUnk = -1;
|
|
_vm->_sceneUpdateRequired = true;
|
|
|
|
} else if (cmd == -11) {
|
|
for (int i = 0; i < 10; i++) {
|
|
if (_vm->_flyingObjects[i].enable)
|
|
_vm->_flyingObjects[i].direction = (_vm->_flyingObjects[i].direction + dir) & 3;
|
|
}
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_identifyItems(int8 *data) {
|
|
int8 *pos = data;
|
|
uint16 block = READ_LE_UINT16(pos);
|
|
|
|
if (block == _vm->_currentBlock) {
|
|
for (int i = 0; i < 6; i++) {
|
|
if (!(_vm->_characters[i].flags & 1))
|
|
continue;
|
|
|
|
for (int ii = 0; ii < 27; ii++) {
|
|
int inv = _vm->_characters[i].inventory[ii];
|
|
if (inv)
|
|
_vm->_items[inv].flags |= 0x40;
|
|
}
|
|
|
|
_vm->identifyQueuedItems(_vm->_characters[i].inventory[16]);
|
|
}
|
|
}
|
|
|
|
_vm->identifyQueuedItems(_vm->_levelBlockProperties[block].drawObjects);
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_sequence(int8 *data) {
|
|
int8 *pos = data;
|
|
_vm->_npcSequenceSub = -1;
|
|
_vm->txt()->setWaitButtonMode(0);
|
|
_vm->gui_updateControls();
|
|
_vm->drawScene(1);
|
|
|
|
int cmd = *pos++;
|
|
|
|
if (_vm->game() == GI_EOB1) {
|
|
if (cmd == 10)
|
|
cmd = -1;
|
|
else if (cmd == 9)
|
|
cmd = -3;
|
|
else if (cmd == 8)
|
|
cmd = -2;
|
|
}
|
|
|
|
switch (cmd) {
|
|
case -3:
|
|
_vm->seq_xdeath();
|
|
_vm->_runFlag = false;
|
|
_vm->_playFinale = true;
|
|
_abortScript = 1;
|
|
return 0;
|
|
|
|
case -2:
|
|
_vm->seq_portal();
|
|
break;
|
|
|
|
case -1:
|
|
_vm->_runFlag = _vm->checkPassword();
|
|
break;
|
|
|
|
default:
|
|
_vm->npcSequence(cmd);
|
|
break;
|
|
}
|
|
_vm->screen()->setScreenDim(7);
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_delay(int8 *data) {
|
|
int8 *pos = data;
|
|
_vm->delay(READ_LE_UINT16(pos) * _vm->tickLength());
|
|
pos += 2;
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_drawScene(int8 *data) {
|
|
_vm->drawScene(1);
|
|
return 0;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_dialogue(int8 *data) {
|
|
int8 *pos = data;
|
|
|
|
switch (*pos++) {
|
|
case -45:
|
|
_vm->drawSequenceBitmap((const char *)pos, pos[13], READ_LE_UINT16(pos + 14), READ_LE_UINT16(pos + 16), READ_LE_UINT16(pos + 18));
|
|
pos += 20;
|
|
break;
|
|
|
|
case -44:
|
|
_vm->restoreAfterDialogueSequence();
|
|
break;
|
|
|
|
case -43:
|
|
_vm->initDialogueSequence();
|
|
break;
|
|
|
|
case -42:
|
|
_vm->gui_drawDialogueBox();
|
|
break;
|
|
|
|
case -40:
|
|
_dlgResult = _vm->runDialogue(READ_LE_UINT16(pos), READ_LE_UINT16(pos + 6) == 0xFFFF ? 2 : 3, getString(READ_LE_UINT16(pos + 2)), getString(READ_LE_UINT16(pos + 4)), getString(READ_LE_UINT16(pos + 6)));
|
|
pos += 8;
|
|
break;
|
|
|
|
case -8:
|
|
_vm->txt()->printDialogueText(READ_LE_UINT16(pos), getString(READ_LE_UINT16(pos + 2)));
|
|
pos += 4;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
int EoBInfProcessor::oeob_specialEvent(int8 *data) {
|
|
int8 *pos = data;
|
|
uint16 cmd = READ_LE_UINT16(pos);
|
|
pos += 2;
|
|
|
|
uint32 endTime = 0;
|
|
int i = 0;
|
|
|
|
switch (cmd) {
|
|
case 0:
|
|
_vm->drawScene(1);
|
|
_screen->_curPage = 2;
|
|
_screen->copyRegion(72, 0, 0, 0, 32, 120, 2, 12, Screen::CR_NO_P_CHECK);
|
|
|
|
for (; i < 4; i++) {
|
|
endTime = _vm->_system->getMillis() + _vm->_tickLength;
|
|
_vm->drawLightningColumn();
|
|
_screen->copyRegion(72, 0, 72, 0, 32, 120, 2, 0, Screen::CR_NO_P_CHECK);
|
|
_screen->updateScreen();
|
|
_screen->copyRegion(0, 0, 72, 0, 32, 120, 12, 2, Screen::CR_NO_P_CHECK);
|
|
_vm->delayUntil(endTime);
|
|
}
|
|
|
|
_screen->_curPage = 0;
|
|
_vm->_sceneUpdateRequired = true;
|
|
break;
|
|
|
|
case 1:
|
|
_dlgResult = _vm->charSelectDialogue();
|
|
break;
|
|
|
|
case 2:
|
|
_vm->characterLevelGain(_dlgResult);
|
|
break;
|
|
|
|
case 3:
|
|
_dlgResult = _vm->resurrectionSelectDialogue();
|
|
break;
|
|
|
|
case 4:
|
|
if (_vm->prepareForNewPartyMember(33, 5))
|
|
_vm->initNpc(4);
|
|
break;
|
|
|
|
case 5:
|
|
_vm->deletePartyItems(46, 5);
|
|
_vm->deletePartyItems(46, 6);
|
|
break;
|
|
|
|
case 6:
|
|
_vm->loadVcnData(0, 0);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return pos - data;
|
|
}
|
|
|
|
} // End of namespace Kyra
|
|
|
|
#endif // ENABLE_EOB
|