scummvm/engines/gob/inter_v2.cpp
Sven Hesse 5b7cb7ae3e Note to self: Don't sleep-deprive and code, for it makes you daft as a broom ;)
(Thanks to md5 for pointing this out to me)

svn-id: r35423
2008-12-18 16:38:28 +00:00

2197 lines
48 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.
*
* $URL$
* $Id$
*
*/
#include "common/endian.h"
#include "sound/mixer.h"
#include "sound/mods/infogrames.h"
#include "gob/gob.h"
#include "gob/inter.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/dataio.h"
#include "gob/draw.h"
#include "gob/game.h"
#include "gob/goblin.h"
#include "gob/map.h"
#include "gob/mult.h"
#include "gob/parse.h"
#include "gob/scenery.h"
#include "gob/video.h"
#include "gob/saveload.h"
#include "gob/videoplayer.h"
#include "gob/sound/sound.h"
namespace Gob {
#define OPCODE(x) _OPCODE(Inter_v2, x)
const int Inter_v2::_goblinFuncLookUp[][2] = {
{0, 0},
{1, 1},
{2, 2},
{4, 3},
{5, 4},
{6, 5},
{7, 6},
{8, 7},
{9, 8},
{10, 9},
{12, 10},
{13, 11},
{14, 12},
{15, 13},
{16, 14},
{21, 15},
{22, 16},
{23, 17},
{24, 18},
{25, 19},
{26, 20},
{27, 21},
{28, 22},
{29, 23},
{30, 24},
{32, 25},
{33, 26},
{34, 27},
{35, 28},
{36, 29},
{37, 30},
{40, 31},
{41, 32},
{42, 33},
{43, 34},
{44, 35},
{50, 36},
{52, 37},
{53, 38},
{100, 39},
{152, 40},
{200, 41},
{201, 42},
{202, 43},
{203, 44},
{204, 45},
{250, 46},
{251, 47},
{252, 48},
{500, 49},
{502, 50},
{503, 51},
{600, 52},
{601, 53},
{602, 54},
{603, 55},
{604, 56},
{605, 57},
{1000, 58},
{1001, 59},
{1002, 60},
{1003, 61},
{1004, 62},
{1005, 63},
{1006, 64},
{1008, 65},
{1009, 66},
{1010, 67},
{1011, 68},
{1015, 69},
{2005, 70}
};
Inter_v2::Inter_v2(GobEngine *vm) : Inter_v1(vm) {
setupOpcodes();
}
void Inter_v2::setupOpcodes() {
static const OpcodeDrawEntryV2 opcodesDraw[256] = {
/* 00 */
OPCODE(o1_loadMult),
OPCODE(o2_playMult),
OPCODE(o2_freeMultKeys),
{NULL, ""},
/* 04 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
OPCODE(o1_initCursor),
/* 08 */
OPCODE(o1_initCursorAnim),
OPCODE(o1_clearCursorAnim),
OPCODE(o2_setRenderFlags),
{NULL, ""},
/* 0C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 10 */
OPCODE(o1_loadAnim),
OPCODE(o1_freeAnim),
OPCODE(o1_updateAnim),
OPCODE(o2_multSub),
/* 14 */
OPCODE(o2_initMult),
OPCODE(o1_freeMult),
OPCODE(o1_animate),
OPCODE(o2_loadMultObject),
/* 18 */
OPCODE(o1_getAnimLayerInfo),
OPCODE(o1_getObjAnimSize),
OPCODE(o1_loadStatic),
OPCODE(o1_freeStatic),
/* 1C */
OPCODE(o2_renderStatic),
OPCODE(o2_loadCurLayer),
{NULL, ""},
{NULL, ""},
/* 20 */
OPCODE(o2_playCDTrack),
OPCODE(o2_waitCDTrackEnd),
OPCODE(o2_stopCD),
OPCODE(o2_readLIC),
/* 24 */
OPCODE(o2_freeLIC),
OPCODE(o2_getCDTrackPos),
{NULL, ""},
{NULL, ""},
/* 28 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 2C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 30 */
OPCODE(o2_loadFontToSprite),
OPCODE(o1_freeFontToSprite),
{NULL, ""},
{NULL, ""},
/* 34 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 38 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 3C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 40 */
OPCODE(o2_totSub),
OPCODE(o2_switchTotSub),
OPCODE(o2_pushVars),
OPCODE(o2_popVars),
/* 44 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 48 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 4C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 50 */
OPCODE(o2_loadMapObjects),
OPCODE(o2_freeGoblins),
OPCODE(o2_moveGoblin),
OPCODE(o2_writeGoblinPos),
/* 54 */
OPCODE(o2_stopGoblin),
OPCODE(o2_setGoblinState),
OPCODE(o2_placeGoblin),
{NULL, ""},
/* 58 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 5C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 60 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 64 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 68 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 6C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 70 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 74 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 78 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 7C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 80 */
OPCODE(o2_initScreen),
OPCODE(o2_scroll),
OPCODE(o2_setScrollOffset),
OPCODE(o2_playImd),
/* 84 */
OPCODE(o2_getImdInfo),
OPCODE(o2_openItk),
OPCODE(o2_closeItk),
OPCODE(o2_setImdFrontSurf),
/* 88 */
OPCODE(o2_resetImdFrontSurf),
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 8C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 90 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 94 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 98 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 9C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* A0 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* A4 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* A8 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* AC */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* B0 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* B4 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* B8 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* BC */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* C0 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* C4 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* C8 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* CC */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* D0 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* D4 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* D8 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* DC */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* E0 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* E4 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* E8 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* EC */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* F0 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* F4 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* F8 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* FC */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""}
};
static const OpcodeFuncEntryV2 opcodesFunc[80] = {
/* 00 */
OPCODE(o1_callSub),
OPCODE(o1_callSub),
OPCODE(o1_printTotText),
OPCODE(o1_loadCursor),
/* 04 */
{NULL, ""},
OPCODE(o1_switch),
OPCODE(o1_repeatUntil),
OPCODE(o1_whileDo),
/* 08 */
OPCODE(o1_if),
OPCODE(o2_evaluateStore),
OPCODE(o1_loadSpriteToPos),
{NULL, ""},
/* 0C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 10 */
{NULL, ""},
OPCODE(o2_printText),
OPCODE(o1_loadTot),
OPCODE(o1_palLoad),
/* 14 */
OPCODE(o1_keyFunc),
OPCODE(o1_capturePush),
OPCODE(o1_capturePop),
OPCODE(o2_animPalInit),
/* 18 */
OPCODE(o2_addCollision),
OPCODE(o2_freeCollision),
{NULL, ""},
{NULL, ""},
/* 1C */
{NULL, ""},
{NULL, ""},
OPCODE(o1_drawOperations),
OPCODE(o1_setcmdCount),
/* 20 */
OPCODE(o1_return),
OPCODE(o1_renewTimeInVars),
OPCODE(o1_speakerOn),
OPCODE(o1_speakerOff),
/* 24 */
OPCODE(o1_putPixel),
OPCODE(o2_goblinFunc),
OPCODE(o1_createSprite),
OPCODE(o1_freeSprite),
/* 28 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 2C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 30 */
OPCODE(o1_returnTo),
OPCODE(o1_loadSpriteContent),
OPCODE(o1_copySprite),
OPCODE(o1_fillRect),
/* 34 */
OPCODE(o1_drawLine),
OPCODE(o1_strToLong),
OPCODE(o1_invalidate),
OPCODE(o1_setBackDelta),
/* 38 */
OPCODE(o1_playSound),
OPCODE(o2_stopSound),
OPCODE(o2_loadSound),
OPCODE(o1_freeSoundSlot),
/* 3C */
OPCODE(o1_waitEndPlay),
OPCODE(o1_playComposition),
OPCODE(o2_getFreeMem),
OPCODE(o2_checkData),
/* 40 */
{NULL, ""},
OPCODE(o1_prepareStr),
OPCODE(o1_insertStr),
OPCODE(o1_cutStr),
/* 44 */
OPCODE(o1_strstr),
OPCODE(o1_istrlen),
OPCODE(o1_setMousePos),
OPCODE(o1_setFrameRate),
/* 48 */
OPCODE(o1_animatePalette),
OPCODE(o1_animateCursor),
OPCODE(o1_blitCursor),
OPCODE(o1_loadFont),
/* 4C */
OPCODE(o1_freeFont),
OPCODE(o2_readData),
OPCODE(o2_writeData),
OPCODE(o1_manageDataFile),
};
static const OpcodeGoblinEntryV2 opcodesGoblin[71] = {
/* 00 */
OPCODE(o2_loadInfogramesIns),
OPCODE(o2_startInfogrames),
OPCODE(o2_stopInfogrames),
{NULL, ""},
/* 04 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 08 */
{NULL, ""},
OPCODE(o2_playInfogrames),
{NULL, ""},
{NULL, ""},
/* 0C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 10 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 14 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 18 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 1C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 20 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 24 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
OPCODE(o2_handleGoblins),
/* 28 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 2C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 30 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 34 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 38 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 3C */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 40 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
{NULL, ""},
/* 44 */
{NULL, ""},
{NULL, ""},
{NULL, ""},
};
_opcodesDrawV2 = opcodesDraw;
_opcodesFuncV2 = opcodesFunc;
_opcodesGoblinV2 = opcodesGoblin;
}
void Inter_v2::executeDrawOpcode(byte i) {
debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)",
i, i, getOpcodeDrawDesc(i));
OpcodeDrawProcV2 op = _opcodesDrawV2[i].proc;
if (op == NULL)
warning("unimplemented opcodeDraw: %d", i);
else
(this->*op) ();
}
bool Inter_v2::executeFuncOpcode(byte i, byte j, OpFuncParams &params) {
debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s)",
i, j, i, j, getOpcodeFuncDesc(i, j));
if ((i > 4) || (j > 15)) {
warning("unimplemented opcodeFunc: %d.%d", i, j);
return false;
}
OpcodeFuncProcV2 op = _opcodesFuncV2[i*16 + j].proc;
if (op == NULL)
warning("unimplemented opcodeFunc: %d.%d", i, j);
else
return (this->*op) (params);
return false;
}
void Inter_v2::executeGoblinOpcode(int i, OpGobParams &params) {
debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)",
i, i, getOpcodeGoblinDesc(i));
OpcodeGoblinProcV2 op = NULL;
for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++)
if (_goblinFuncLookUp[j][0] == i) {
op = _opcodesGoblinV2[_goblinFuncLookUp[j][1]].proc;
break;
}
if (op == NULL) {
int16 val;
_vm->_global->_inter_execPtr -= 2;
val = load16();
_vm->_global->_inter_execPtr += val << 1;
} else
(this->*op) (params);
}
const char *Inter_v2::getOpcodeDrawDesc(byte i) {
return _opcodesDrawV2[i].desc;
}
const char *Inter_v2::getOpcodeFuncDesc(byte i, byte j) {
if ((i > 4) || (j > 15))
return "";
return _opcodesFuncV2[i*16 + j].desc;
}
const char *Inter_v2::getOpcodeGoblinDesc(int i) {
for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++)
if (_goblinFuncLookUp[j][0] == i)
return _opcodesGoblinV2[_goblinFuncLookUp[j][1]].desc;
return "";
}
void Inter_v2::checkSwitchTable(byte **ppExec) {
byte cmd;
int16 len;
int32 value;
bool found;
found = false;
*ppExec = 0;
cmd = *_vm->_global->_inter_execPtr;
value = _vm->_parse->parseVarIndex();
switch (cmd) {
case 16:
case 18:
value = (int8) READ_VARO_UINT8(value);
break;
case 23:
case 26:
value = READ_VARO_UINT32(value);
break;
default:
value = (int16) READ_VARO_UINT16(value);
break;
}
if (_terminate)
return;
len = (int8) *_vm->_global->_inter_execPtr++;
while (len != -5) {
for (int i = 0; i < len; i++) {
cmd = *_vm->_global->_inter_execPtr;
switch (cmd) {
case 19:
_vm->_global->_inter_execPtr++;
if (!found &&
(value ==
(int32) (READ_LE_UINT32(_vm->_global->_inter_execPtr))))
found = true;
_vm->_global->_inter_execPtr += 5;
break;
case 20:
_vm->_global->_inter_execPtr++;
if (!found &&
(value ==
(int16) (READ_LE_UINT16(_vm->_global->_inter_execPtr))))
found = true;
_vm->_global->_inter_execPtr += 3;
break;
case 21:
_vm->_global->_inter_execPtr++;
if (!found && (value == (int8) *_vm->_global->_inter_execPtr))
found = true;
_vm->_global->_inter_execPtr += 2;
break;
default:
if (!found) {
evalExpr(0);
if (value == _vm->_global->_inter_resVal)
found = true;
} else
_vm->_parse->skipExpr(99);
break;
}
}
if (found && !*ppExec)
*ppExec = _vm->_global->_inter_execPtr;
_vm->_global->_inter_execPtr +=
READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2;
len = (int8) *_vm->_global->_inter_execPtr++;
}
if ((*_vm->_global->_inter_execPtr >> 4) != 4)
return;
_vm->_global->_inter_execPtr++;
if (!*ppExec)
*ppExec = _vm->_global->_inter_execPtr;
_vm->_global->_inter_execPtr +=
READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2;
}
void Inter_v2::o2_playMult() {
int16 checkEscape;
checkEscape = load16();
_vm->_mult->setMultData(checkEscape >> 1);
_vm->_mult->playMult(VAR(57), -1, checkEscape & 0x1, 0);
}
void Inter_v2::o2_freeMultKeys() {
uint16 index = load16();
if (!_vm->_mult->hasMultData(index))
return;
_vm->_mult->setMultData(index);
_vm->_mult->freeMultKeys();
_vm->_mult->zeroMultData(index);
}
void Inter_v2::o2_setRenderFlags() {
int16 expr;
expr = _vm->_parse->parseValExpr();
if (expr & 0x8000) {
_vm->_draw->_renderFlags |= expr & 0x3FFF;
} else {
if (expr & 0x4000)
_vm->_draw->_renderFlags &= expr & 0x3FFF;
else
_vm->_draw->_renderFlags = expr;
}
}
void Inter_v2::o2_multSub() {
_vm->_mult->multSub(_vm->_parse->parseValExpr());
}
void Inter_v2::o2_initMult() {
int16 oldAnimHeight;
int16 oldAnimWidth;
int16 oldObjCount;
int16 posXVar;
int16 posYVar;
int16 animDataVar;
oldAnimWidth = _vm->_mult->_animWidth;
oldAnimHeight = _vm->_mult->_animHeight;
oldObjCount = _vm->_mult->_objCount;
_vm->_mult->_animLeft = load16();
_vm->_mult->_animTop = load16();
_vm->_mult->_animWidth = load16();
_vm->_mult->_animHeight = load16();
_vm->_mult->_objCount = load16();
posXVar = _vm->_parse->parseVarIndex();
posYVar = _vm->_parse->parseVarIndex();
animDataVar = _vm->_parse->parseVarIndex();
if (_vm->_mult->_objects && (oldObjCount != _vm->_mult->_objCount)) {
warning("Initializing new objects without having "
"cleaned up the old ones at first");
_vm->_mult->clearObjectVideos();
for (int i = 0; i < _vm->_mult->_objCount; i++) {
delete _vm->_mult->_objects[i].pPosX;
delete _vm->_mult->_objects[i].pPosY;
}
delete[] _vm->_mult->_objects;
delete[] _vm->_mult->_renderObjs;
delete[] _vm->_mult->_orderArray;
_vm->_mult->_objects = 0;
_vm->_mult->_renderObjs = 0;
_vm->_mult->_orderArray = 0;
}
if (_vm->_mult->_objects == 0) {
_vm->_mult->_renderObjs = new Mult::Mult_Object*[_vm->_mult->_objCount];
memset(_vm->_mult->_renderObjs, 0,
_vm->_mult->_objCount * sizeof(Mult::Mult_Object*));
if (_terminate)
return;
_vm->_mult->_orderArray = new int8[_vm->_mult->_objCount];
memset(_vm->_mult->_orderArray, 0, _vm->_mult->_objCount * sizeof(int8));
_vm->_mult->_objects = new Mult::Mult_Object[_vm->_mult->_objCount];
memset(_vm->_mult->_objects, 0,
_vm->_mult->_objCount * sizeof(Mult::Mult_Object));
for (int i = 0; i < _vm->_mult->_objCount; i++) {
uint32 offPosX = i * 4 + (posXVar / 4) * 4;
uint32 offPosY = i * 4 + (posYVar / 4) * 4;
uint32 offAnim = animDataVar + i * 4 * _vm->_global->_inter_animDataSize;
_vm->_mult->_objects[i].pPosX = new VariableReference(*_vm->_inter->_variables, offPosX);
_vm->_mult->_objects[i].pPosY = new VariableReference(*_vm->_inter->_variables, offPosY);
_vm->_mult->_objects[i].pAnimData =
(Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim,
_vm->_global->_inter_animDataSize);
_vm->_mult->_objects[i].pAnimData->isStatic = 1;
_vm->_mult->_objects[i].tick = 0;
_vm->_mult->_objects[i].lastLeft = -1;
_vm->_mult->_objects[i].lastRight = -1;
_vm->_mult->_objects[i].lastTop = -1;
_vm->_mult->_objects[i].lastBottom = -1;
_vm->_mult->_objects[i].goblinX = 1;
_vm->_mult->_objects[i].goblinY = 1;
}
}
if (_vm->_mult->_animSurf &&
((oldAnimWidth != _vm->_mult->_animWidth) ||
(oldAnimHeight != _vm->_mult->_animHeight))) {
_vm->_draw->freeSprite(22);
_vm->_mult->_animSurf = 0;
}
_vm->_draw->adjustCoords(0,
&_vm->_mult->_animWidth, &_vm->_mult->_animHeight);
if (_vm->_mult->_animSurf == 0) {
_vm->_draw->initSpriteSurf(22, _vm->_mult->_animWidth,
_vm->_mult->_animHeight, 0);
_vm->_mult->_animSurf = _vm->_draw->_spritesArray[22];
if (_terminate)
return;
}
_vm->_draw->adjustCoords(1,
&_vm->_mult->_animWidth, &_vm->_mult->_animHeight);
_vm->_draw->_sourceSurface = 21;
_vm->_draw->_destSurface = 22;
_vm->_draw->_spriteLeft = _vm->_mult->_animLeft;
_vm->_draw->_spriteTop = _vm->_mult->_animTop;
_vm->_draw->_spriteRight = _vm->_mult->_animWidth;
_vm->_draw->_spriteBottom = _vm->_mult->_animHeight;
_vm->_draw->_destSpriteX = 0;
_vm->_draw->_destSpriteY = 0;
_vm->_draw->spriteOperation(0);
debugC(4, kDebugGraphics, "o2_initMult: x = %d, y = %d, w = %d, h = %d",
_vm->_mult->_animLeft, _vm->_mult->_animTop,
_vm->_mult->_animWidth, _vm->_mult->_animHeight);
debugC(4, kDebugGraphics, " _vm->_mult->_objCount = %d, "
"animation data size = %d", _vm->_mult->_objCount,
_vm->_global->_inter_animDataSize);
}
void Inter_v2::o2_loadMultObject() {
int16 val;
int16 objIndex;
int16 animation;
int16 layer;
byte *multData;
objIndex = _vm->_parse->parseValExpr();
val = _vm->_parse->parseValExpr();
*_vm->_mult->_objects[objIndex].pPosX = val;
val = _vm->_parse->parseValExpr();
*_vm->_mult->_objects[objIndex].pPosY = val;
debugC(4, kDebugGameFlow, "Loading mult object %d", objIndex);
multData = (byte *) _vm->_mult->_objects[objIndex].pAnimData;
for (int i = 0; i < 11; i++) {
if (*_vm->_global->_inter_execPtr != 99)
multData[i] = _vm->_parse->parseValExpr();
else
_vm->_global->_inter_execPtr++;
}
Mult::Mult_Object &obj = _vm->_mult->_objects[objIndex];
Mult::Mult_AnimData &objAnim = *(obj.pAnimData);
if ((objAnim.animType == 100) && (objIndex < _vm->_goblin->_gobsCount)) {
val = *(obj.pPosX) % 256;
obj.destX = val;
obj.gobDestX = val;
obj.goblinX = val;
val = *(obj.pPosY) % 256;
obj.destY = val;
obj.gobDestY = val;
obj.goblinY = val;
*(obj.pPosX) *= _vm->_map->_tilesWidth;
layer = objAnim.layer;
animation = obj.goblinStates[layer][0].animation;
objAnim.framesLeft = objAnim.maxFrame;
objAnim.nextState = -1;
objAnim.newState = -1;
objAnim.pathExistence = 0;
objAnim.isBusy = 0;
objAnim.state = layer;
objAnim.layer = obj.goblinStates[objAnim.state][0].layer;
objAnim.animation = animation;
_vm->_scenery->updateAnim(layer, 0, animation, 0,
*(obj.pPosX), *(obj.pPosY), 0);
if (!_vm->_map->_bigTiles)
*(obj.pPosY) = (obj.goblinY + 1) * _vm->_map->_tilesHeight
- (_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
else
*(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->_tilesHeight) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) -
((obj.goblinY + 1) / 2);
*(obj.pPosX) = obj.goblinX * _vm->_map->_tilesWidth;
} else if ((objAnim.animType == 101) && (objIndex < _vm->_goblin->_gobsCount)) {
layer = objAnim.layer;
animation = obj.goblinStates[layer][0].animation;
objAnim.nextState = -1;
objAnim.newState = -1;
objAnim.state = layer;
objAnim.layer = obj.goblinStates[objAnim.state][0].layer;
objAnim.animation = animation;
if ((*(obj.pPosX) == 1000) && (*(obj.pPosY) == 1000)) {
Scenery::AnimLayer *animLayer =
_vm->_scenery->getAnimLayer(animation, objAnim.layer);
*(obj.pPosX) = animLayer->posX;
*(obj.pPosY) = animLayer->posY;
}
_vm->_scenery->updateAnim(layer, 0, animation, 0,
*(obj.pPosX), *(obj.pPosY), 0);
} else if ((objAnim.animType != 100) && (objAnim.animType != 101)) {
if ((((int32) *(obj.pPosX)) == -1234) && (((int32) *(obj.pPosY)) == -4321)) {
if (obj.videoSlot > 0)
_vm->_vidPlayer->slotClose(obj.videoSlot - 1);
obj.videoSlot = 0;
obj.lastLeft = -1;
obj.lastTop = -1;
obj.lastBottom = -1;
obj.lastRight = -1;
}
}
}
void Inter_v2::o2_renderStatic() {
int16 layer;
int16 index;
index = _vm->_parse->parseValExpr();
layer = _vm->_parse->parseValExpr();
_vm->_scenery->renderStatic(index, layer);
}
void Inter_v2::o2_loadCurLayer() {
_vm->_scenery->_curStatic = _vm->_parse->parseValExpr();
_vm->_scenery->_curStaticLayer = _vm->_parse->parseValExpr();
}
void Inter_v2::o2_playCDTrack() {
if (!(_vm->_draw->_renderFlags & RENDERFLAG_NOBLITINVALIDATED))
_vm->_draw->blitInvalidated();
evalExpr(0);
_vm->_sound->cdPlay(_vm->_global->_inter_resStr);
}
void Inter_v2::o2_waitCDTrackEnd() {
debugC(1, kDebugSound, "CDROM: Waiting for playback to end");
while (_vm->_sound->cdGetTrackPos() >= 0)
_vm->_util->longDelay(1);
}
void Inter_v2::o2_stopCD() {
_vm->_sound->cdStop();
}
void Inter_v2::o2_readLIC() {
char path[40];
evalExpr(0);
strncpy0(path, _vm->_global->_inter_resStr, 35);
strcat(path, ".LIC");
_vm->_sound->cdLoadLIC(path);
}
void Inter_v2::o2_freeLIC() {
_vm->_sound->cdUnloadLIC();
}
void Inter_v2::o2_getCDTrackPos() {
int16 varPos;
int16 varName;
_vm->_util->longDelay(1);
varPos = _vm->_parse->parseVarIndex();
varName = _vm->_parse->parseVarIndex();
WRITE_VAR_OFFSET(varPos, _vm->_sound->cdGetTrackPos(GET_VARO_STR(varName)));
WRITE_VARO_STR(varName, _vm->_sound->cdGetCurrentTrack());
}
void Inter_v2::o2_loadFontToSprite() {
int16 i = load16();
_vm->_draw->_fontToSprite[i].sprite = *_vm->_global->_inter_execPtr;
_vm->_global->_inter_execPtr += 2;
_vm->_draw->_fontToSprite[i].base = *_vm->_global->_inter_execPtr;
_vm->_global->_inter_execPtr += 2;
_vm->_draw->_fontToSprite[i].width = *_vm->_global->_inter_execPtr;
_vm->_global->_inter_execPtr += 2;
_vm->_draw->_fontToSprite[i].height = *_vm->_global->_inter_execPtr;
_vm->_global->_inter_execPtr += 2;
}
void Inter_v2::o2_totSub() {
char totFile[14];
byte length;
int flags;
int i;
length = *_vm->_global->_inter_execPtr++;
if ((length & 0x7F) > 13)
error("Length in o2_totSub is greater than 13 (%d)", length);
if (length & 0x80) {
evalExpr(0);
strcpy(totFile, _vm->_global->_inter_resStr);
} else {
for (i = 0; i < length; i++)
totFile[i] = (char) *_vm->_global->_inter_execPtr++;
totFile[i] = 0;
}
// WORKAROUND: There is a race condition in the script when opening the notepad
if (!scumm_stricmp(totFile, "edit"))
_vm->_util->forceMouseUp();
flags = *_vm->_global->_inter_execPtr++;
_vm->_game->totSub(flags, totFile);
}
void Inter_v2::o2_switchTotSub() {
int16 index;
int16 skipPlay;
index = load16();
skipPlay = load16();
_vm->_game->switchTotSub(index, skipPlay);
}
void Inter_v2::o2_pushVars() {
byte count;
int16 varOff;
count = *_vm->_global->_inter_execPtr++;
for (int i = 0; i < count; i++, _varStackPos++) {
if ((*_vm->_global->_inter_execPtr == 25) ||
(*_vm->_global->_inter_execPtr == 28)) {
varOff = _vm->_parse->parseVarIndex();
_vm->_global->_inter_execPtr++;
_variables->copyTo(varOff, _varStack + _varStackPos,
_varSizesStack + _varStackPos,
_vm->_global->_inter_animDataSize * 4);
_varStackPos += _vm->_global->_inter_animDataSize * 4;
_varStack[_varStackPos] = _vm->_global->_inter_animDataSize * 4;
_varSizesStack[_varStackPos] = _vm->_global->_inter_animDataSize * 4;
} else {
if (evalExpr(&varOff) != 20)
_vm->_global->_inter_resVal = 0;
memcpy(_varStack + _varStackPos, &_vm->_global->_inter_resVal, 4);
memcpy(_varSizesStack + _varStackPos, &_vm->_global->_inter_resVal, 4);
_varStackPos += 4;
_varStack[_varStackPos] = 4;
_varSizesStack[_varStackPos] = 4;
}
}
}
void Inter_v2::o2_popVars() {
byte count;
int16 varOff;
int16 sizeV;
int16 sizeS;
count = *_vm->_global->_inter_execPtr++;
for (int i = 0; i < count; i++) {
varOff = _vm->_parse->parseVarIndex();
sizeV = _varStack[--_varStackPos];
sizeS = _varSizesStack[_varStackPos];
assert(sizeV == sizeS);
_varStackPos -= sizeV;
_variables->copyFrom(varOff, _varStack + _varStackPos,
_varSizesStack + _varStackPos, sizeV);
}
}
void Inter_v2::o2_loadMapObjects() {
_vm->_map->loadMapObjects(0);
}
void Inter_v2::o2_freeGoblins() {
_vm->_goblin->freeObjects();
}
void Inter_v2::o2_moveGoblin() {
int16 destX, destY;
int16 index;
destX = _vm->_parse->parseValExpr();
destY = _vm->_parse->parseValExpr();
index = _vm->_parse->parseValExpr();
_vm->_goblin->move(destX, destY, index);
}
void Inter_v2::o2_writeGoblinPos() {
int16 varX, varY;
int16 index;
varX = _vm->_parse->parseVarIndex();
varY = _vm->_parse->parseVarIndex();
index = _vm->_parse->parseValExpr();
WRITE_VAR_OFFSET(varX, _vm->_mult->_objects[index].goblinX);
WRITE_VAR_OFFSET(varY, _vm->_mult->_objects[index].goblinY);
}
void Inter_v2::o2_stopGoblin() {
int16 index = _vm->_parse->parseValExpr();
_vm->_mult->_objects[index].pAnimData->pathExistence = 4;
}
void Inter_v2::o2_setGoblinState() {
int16 index;
int16 state;
int16 type;
int16 layer;
int16 animation;
int16 deltaX, deltaY;
int16 deltaWidth, deltaHeight;
index = _vm->_parse->parseValExpr();
state = _vm->_parse->parseValExpr();
type = _vm->_parse->parseValExpr();
Mult::Mult_Object &obj = _vm->_mult->_objects[index];
Mult::Mult_AnimData &objAnim = *(obj.pAnimData);
objAnim.stateType = type;
if (!obj.goblinStates[state])
return;
Scenery::AnimLayer *animLayer;
switch (type) {
case 0:
objAnim.frame = 0;
layer = obj.goblinStates[state][0].layer;
animation = obj.goblinStates[state][0].animation;
objAnim.state = state;
objAnim.layer = layer;
objAnim.animation = animation;
animLayer = _vm->_scenery->getAnimLayer(animation, layer);
*(obj.pPosX) = animLayer->posX;
*(obj.pPosY) = animLayer->posY;
objAnim.isPaused = 0;
objAnim.isStatic = 0;
objAnim.newCycle = animLayer->framesCount;
break;
case 1:
case 4:
case 6:
layer = obj.goblinStates[objAnim.state][0].layer;
animation = obj.goblinStates[objAnim.state][0].animation;
_vm->_scenery->updateAnim(layer, 0, animation, 0,
*(obj.pPosX), *(obj.pPosY), 0);
deltaHeight = _vm->_scenery->_animBottom - _vm->_scenery->_animTop;
deltaWidth = _vm->_scenery->_animRight - _vm->_scenery->_animLeft;
animLayer =
_vm->_scenery->getAnimLayer(objAnim.animation, objAnim.layer);
deltaX = animLayer->animDeltaX;
deltaY = animLayer->animDeltaY;
layer = obj.goblinStates[state][0].layer;
animation = obj.goblinStates[state][0].animation;
objAnim.state = state;
objAnim.layer = layer;
objAnim.animation = animation;
objAnim.frame = 0;
objAnim.isPaused = 0;
objAnim.isStatic = 0;
animLayer = _vm->_scenery->getAnimLayer(animation, layer);
objAnim.newCycle = animLayer->framesCount;
_vm->_scenery->updateAnim(layer, 0, animation, 0,
*(obj.pPosX), *(obj.pPosY), 0);
deltaHeight -= _vm->_scenery->_animBottom - _vm->_scenery->_animTop;
deltaWidth -= _vm->_scenery->_animRight - _vm->_scenery->_animLeft;
*(obj.pPosX) += deltaWidth + deltaX;
*(obj.pPosY) += deltaHeight + deltaY;
break;
case 11:
layer = obj.goblinStates[state][0].layer;
animation = obj.goblinStates[state][0].animation;
objAnim.state = state;
objAnim.layer = layer;
objAnim.animation = animation;
objAnim.frame = 0;
objAnim.isPaused = 0;
objAnim.isStatic = 0;
animLayer = _vm->_scenery->getAnimLayer(animation, layer);
objAnim.newCycle = animLayer->framesCount;
_vm->_scenery->updateAnim(layer, 0, animation, 0,
*(obj.pPosX), *(obj.pPosY), 0);
if (_vm->_map->_bigTiles)
*(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->_tilesHeight) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) -
((obj.goblinY + 1) / 2);
else
*(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->_tilesHeight) -
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
*(obj.pPosX) = obj.goblinX * _vm->_map->_tilesWidth;
break;
}
}
void Inter_v2::o2_placeGoblin() {
int16 index;
int16 x, y;
int16 state;
index = _vm->_parse->parseValExpr();
x = _vm->_parse->parseValExpr();
y = _vm->_parse->parseValExpr();
state = _vm->_parse->parseValExpr();
_vm->_goblin->placeObject(0, 0, index, x, y, state);
}
void Inter_v2::o2_initScreen() {
int16 offY;
int16 videoMode;
int16 width, height;
offY = load16();
videoMode = offY & 0xFF;
offY = (offY >> 8) & 0xFF;
width = _vm->_parse->parseValExpr();
height = _vm->_parse->parseValExpr();
_vm->_video->clearScreen();
// Lost in Time switches to 640x400x16 when showing the title screen
if (_vm->getGameType() == kGameTypeLostInTime) {
if (videoMode == 0x10) {
width = _vm->_width = 640;
height = _vm->_height = 400;
_vm->_global->_colorCount = 16;
_vm->_video->setSize(true);
} else if (_vm->_global->_videoMode == 0x10) {
if (width == -1)
width = 320;
if (height == -1)
height = 200;
_vm->_width = 320;
_vm->_height = 200;
_vm->_global->_colorCount = 256;
_vm->_video->setSize(false);
}
}
_vm->_global->_fakeVideoMode = videoMode;
// Some versions require this
if (videoMode == 0xD)
videoMode = _vm->_mode;
if ((videoMode == _vm->_global->_videoMode) && (width == -1))
return;
if (width > 0)
_vm->_video->_surfWidth = width;
if (height > 0)
_vm->_video->_surfHeight = height;
_vm->_video->_splitHeight1 = MIN<int16>(_vm->_height, _vm->_video->_surfHeight - offY);
_vm->_video->_splitHeight2 = offY;
_vm->_video->_splitStart = _vm->_video->_surfHeight - offY;
_vm->_video->_screenDeltaX = 0;
_vm->_video->_screenDeltaY = 0;
_vm->_global->_mouseMinX = 0;
_vm->_global->_mouseMinY = 0;
_vm->_global->_mouseMaxX = _vm->_width;
_vm->_global->_mouseMaxY = _vm->_height - _vm->_video->_splitHeight2 - 1;
_vm->_draw->closeScreen();
_vm->_util->clearPalette();
memset(_vm->_global->_redPalette, 0, 256);
memset(_vm->_global->_greenPalette, 0, 256);
memset(_vm->_global->_bluePalette, 0, 256);
_vm->_global->_videoMode = videoMode;
_vm->_video->initPrimary(videoMode);
WRITE_VAR(15, _vm->_global->_fakeVideoMode);
_vm->_global->_setAllPalette = true;
_vm->_util->setMousePos(_vm->_global->_inter_mouseX,
_vm->_global->_inter_mouseY);
_vm->_util->clearPalette();
_vm->_draw->initScreen();
_vm->_util->setScrollOffset();
}
void Inter_v2::o2_scroll() {
int16 startX;
int16 startY;
int16 endX;
int16 endY;
int16 stepX;
int16 stepY;
int16 curX;
int16 curY;
startX = CLIP((int) _vm->_parse->parseValExpr(), 0,
_vm->_video->_surfWidth - _vm->_width);
startY = CLIP((int) _vm->_parse->parseValExpr(), 0,
_vm->_video->_surfHeight - _vm->_height);
endX = CLIP((int) _vm->_parse->parseValExpr(), 0,
_vm->_video->_surfWidth - _vm->_width);
endY = CLIP((int) _vm->_parse->parseValExpr(), 0,
_vm->_video->_surfHeight - _vm->_height);
stepX = _vm->_parse->parseValExpr();
stepY = _vm->_parse->parseValExpr();
curX = startX;
curY = startY;
while (!_vm->shouldQuit() && ((curX != endX) || (curY != endY))) {
curX = stepX > 0 ? MIN(curX + stepX, (int) endX) :
MAX(curX + stepX, (int) endX);
curY = stepY > 0 ? MIN(curY + stepY, (int) endY) :
MAX(curY + stepY, (int) endY);
_vm->_draw->_scrollOffsetX = curX;
_vm->_draw->_scrollOffsetY = curY;
_vm->_util->setScrollOffset();
_vm->_video->dirtyRectsAll();
}
}
void Inter_v2::o2_setScrollOffset() {
int16 offsetX, offsetY;
offsetX = _vm->_parse->parseValExpr();
offsetY = _vm->_parse->parseValExpr();
if (offsetX == -1) {
WRITE_VAR(2, _vm->_draw->_scrollOffsetX);
WRITE_VAR(3, _vm->_draw->_scrollOffsetY);
} else {
int16 screenW = _vm->_video->_surfWidth;
int16 screenH = _vm->_video->_surfHeight;
if (screenW > _vm->_width)
screenW -= _vm->_width;
if (screenH > _vm->_height)
screenH -= _vm->_height;
_vm->_draw->_scrollOffsetX = CLIP<int16>(offsetX, 0, screenW);
_vm->_draw->_scrollOffsetY = CLIP<int16>(offsetY, 0, screenH);
_vm->_video->dirtyRectsAll();
}
_vm->_util->setScrollOffset();
_noBusyWait = true;
}
void Inter_v2::o2_playImd() {
char imd[128];
int16 x, y;
int16 startFrame;
int16 lastFrame;
int16 breakKey;
int16 flags;
int16 palStart;
int16 palEnd;
uint16 palCmd;
bool close;
evalExpr(0);
_vm->_global->_inter_resStr[8] = 0;
strncpy0(imd, _vm->_global->_inter_resStr, 127);
x = _vm->_parse->parseValExpr();
y = _vm->_parse->parseValExpr();
startFrame = _vm->_parse->parseValExpr();
lastFrame = _vm->_parse->parseValExpr();
breakKey = _vm->_parse->parseValExpr();
flags = _vm->_parse->parseValExpr();
palStart = _vm->_parse->parseValExpr();
palEnd = _vm->_parse->parseValExpr();
palCmd = 1 << (flags & 0x3F);
debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, "
"paletteCmd %d (%d - %d), flags %X", _vm->_global->_inter_resStr, x, y,
startFrame, lastFrame, palCmd, palStart, palEnd, flags);
if ((imd[0] != 0) && !_vm->_vidPlayer->primaryOpen(imd, x, y, flags)) {
WRITE_VAR(11, (uint32) -1);
return;
}
close = (lastFrame == -1);
if (startFrame == -2) {
startFrame = lastFrame = 0;
close = false;
}
if (startFrame >= 0) {
_vm->_game->_preventScroll = true;
_vm->_vidPlayer->primaryPlay(startFrame, lastFrame, breakKey, palCmd, palStart, palEnd, 0);
_vm->_game->_preventScroll = false;
}
if (close)
_vm->_vidPlayer->primaryClose();
}
void Inter_v2::o2_getImdInfo() {
int16 varX, varY;
int16 varFrames;
int16 varWidth, varHeight;
evalExpr(0);
varX = _vm->_parse->parseVarIndex();
varY = _vm->_parse->parseVarIndex();
varFrames = _vm->_parse->parseVarIndex();
varWidth = _vm->_parse->parseVarIndex();
varHeight = _vm->_parse->parseVarIndex();
// WORKAROUND: The nut rolling animation in the administration center
// in Woodruff is called "noixroul", but the scripts think it's "noixroule".
if ((_vm->getGameType() == kGameTypeWoodruff) &&
(!scumm_stricmp(_vm->_global->_inter_resStr, "noixroule")))
strcpy(_vm->_global->_inter_resStr, "noixroul");
_vm->_vidPlayer->writeVideoInfo(_vm->_global->_inter_resStr, varX, varY,
varFrames, varWidth, varHeight);
}
void Inter_v2::o2_openItk() {
char fileName[32];
evalExpr(0);
strncpy0(fileName, _vm->_global->_inter_resStr, 27);
if (!strchr(fileName, '.'))
strcat(fileName, ".ITK");
_vm->_dataIO->openDataFile(fileName, true);
}
void Inter_v2::o2_closeItk() {
_vm->_dataIO->closeDataFile(true);
}
void Inter_v2::o2_setImdFrontSurf() {
}
void Inter_v2::o2_resetImdFrontSurf() {
}
bool Inter_v2::o2_evaluateStore(OpFuncParams &params) {
byte *savedPos;
int16 varOff;
int16 token;
int16 result;
byte loopCount;
savedPos = _vm->_global->_inter_execPtr;
varOff = _vm->_parse->parseVarIndex();
if (*_vm->_global->_inter_execPtr == 99) {
_vm->_global->_inter_execPtr++;
loopCount = *_vm->_global->_inter_execPtr++;
} else
loopCount = 1;
for (int i = 0; i < loopCount; i++) {
token = evalExpr(&result);
switch (savedPos[0]) {
case 16:
case 18:
WRITE_VARO_UINT8(varOff + i, _vm->_global->_inter_resVal);
break;
case 17:
case 27:
WRITE_VARO_UINT16(varOff + i * 2, _vm->_global->_inter_resVal);
break;
case 23:
case 26:
WRITE_VAR_OFFSET(varOff + i * 4, _vm->_global->_inter_resVal);
break;
case 24:
WRITE_VARO_UINT16(varOff + i * 4, _vm->_global->_inter_resVal);
break;
case 25:
case 28:
if (token == 20)
WRITE_VARO_UINT8(varOff, result);
else
WRITE_VARO_STR(varOff, _vm->_global->_inter_resStr);
break;
}
}
return false;
}
bool Inter_v2::o2_printText(OpFuncParams &params) {
char buf[60];
int i;
_vm->_draw->_destSpriteX = _vm->_parse->parseValExpr();
_vm->_draw->_destSpriteY = _vm->_parse->parseValExpr();
_vm->_draw->_backColor = _vm->_parse->parseValExpr();
_vm->_draw->_frontColor = _vm->_parse->parseValExpr();
_vm->_draw->_fontIndex = _vm->_parse->parseValExpr();
_vm->_draw->_destSurface = 21;
_vm->_draw->_textToPrint = buf;
_vm->_draw->_transparency = 0;
if (_vm->_draw->_backColor == 16) {
_vm->_draw->_backColor = 0;
_vm->_draw->_transparency = 1;
}
do {
for (i = 0; (((char) *_vm->_global->_inter_execPtr) != '.') &&
(*_vm->_global->_inter_execPtr != 200);
i++, _vm->_global->_inter_execPtr++) {
buf[i] = (char) *_vm->_global->_inter_execPtr;
}
if (*_vm->_global->_inter_execPtr != 200) {
_vm->_global->_inter_execPtr++;
switch (*_vm->_global->_inter_execPtr) {
case 16:
case 18:
sprintf(buf + i, "%d",
(int8) READ_VARO_UINT8(_vm->_parse->parseVarIndex()));
break;
case 17:
case 24:
case 27:
sprintf(buf + i, "%d",
(int16) READ_VARO_UINT16(_vm->_parse->parseVarIndex()));
break;
case 23:
case 26:
sprintf(buf + i, "%d",
VAR_OFFSET(_vm->_parse->parseVarIndex()));
break;
case 25:
case 28:
sprintf(buf + i, "%s",
GET_VARO_STR(_vm->_parse->parseVarIndex()));
break;
}
_vm->_global->_inter_execPtr++;
} else
buf[i] = 0;
_vm->_draw->spriteOperation(DRAW_PRINTTEXT);
} while (*_vm->_global->_inter_execPtr != 200);
_vm->_global->_inter_execPtr++;
return false;
}
bool Inter_v2::o2_animPalInit(OpFuncParams &params) {
int16 index;
index = load16();
if (index > 0) {
index--;
_animPalLowIndex[index] = _vm->_parse->parseValExpr();
_animPalHighIndex[index] = _vm->_parse->parseValExpr();
_animPalDir[index] = 1;
} else if (index == 0) {
memset(_animPalDir, 0, 8 * sizeof(int16));
_vm->_parse->parseValExpr();
_vm->_parse->parseValExpr();
} else {
index = -index - 1;
_animPalLowIndex[index] = _vm->_parse->parseValExpr();
_animPalHighIndex[index] = _vm->_parse->parseValExpr();
_animPalDir[index] = -1;
}
return false;
}
bool Inter_v2::o2_addCollision(OpFuncParams &params) {
int16 id;
int16 left, top, width, height;
int16 flags;
int16 key;
int16 funcSub;
id = _vm->_parse->parseValExpr();
funcSub = _vm->_global->_inter_execPtr - _vm->_game->_totFileData;
left = _vm->_parse->parseValExpr();
top = _vm->_parse->parseValExpr();
width = _vm->_parse->parseValExpr();
height = _vm->_parse->parseValExpr();
flags = _vm->_parse->parseValExpr();
key = load16();
if (key == 0)
key = ABS(id) + 41960;
_vm->_draw->adjustCoords(0, &left, &top);
_vm->_draw->adjustCoords(2, &width, &height);
if (left < 0) {
width += left;
left = 0;
}
if (top < 0) {
height += top;
top = 0;
}
int16 index;
if (id < 0)
index = _vm->_game->addNewCollision(0xD000 - id, left & 0xFFFC, top & 0xFFFC,
left + width + 3, top + height + 3, flags, key, 0, 0);
else
index = _vm->_game->addNewCollision(0xE000 + id, left, top,
left + width - 1, top + height - 1, flags, key, 0, 0);
_vm->_game->_collisionAreas[index].funcSub = funcSub;
return false;
}
bool Inter_v2::o2_freeCollision(OpFuncParams &params) {
int16 id;
id = _vm->_parse->parseValExpr();
if (id == -2) {
for (int i = 0; i < 150; i++) {
if ((_vm->_game->_collisionAreas[i].id & 0xF000) == 0xD000)
_vm->_game->_collisionAreas[i].left = 0xFFFF;
}
} else if (id == -1) {
for (int i = 0; i < 150; i++) {
if ((_vm->_game->_collisionAreas[i].id & 0xF000) == 0xE000)
_vm->_game->_collisionAreas[i].left = 0xFFFF;
}
} else
_vm->_game->freeCollision(0xE000 + id);
return false;
}
bool Inter_v2::o2_goblinFunc(OpFuncParams &params) {
// TODO: In Inca 2, this is the big SpaceShoot0rz()-Opcode.
// It's not yet implemented, so we fudge our way through
// and pretend we've won.
if (_vm->getGameType() == kGameTypeInca2) {
_vm->_global->_inter_execPtr += 4;
uint16 resVar = (uint16) load16();
_vm->_global->_inter_execPtr += 4;
WRITE_VAR(resVar, 1);
return false;
}
OpGobParams gobParams;
int16 cmd;
cmd = load16();
_vm->_global->_inter_execPtr += 2;
if (cmd != 101)
executeGoblinOpcode(cmd, gobParams);
return false;
}
bool Inter_v2::o2_stopSound(OpFuncParams &params) {
int16 expr;
expr = _vm->_parse->parseValExpr();
if (expr < 0) {
_vm->_sound->adlibStop();
} else
_vm->_sound->blasterStop(expr);
_soundEndTimeKey = 0;
return false;
}
bool Inter_v2::o2_loadSound(OpFuncParams &params) {
loadSound(0);
return false;
}
bool Inter_v2::o2_getFreeMem(OpFuncParams &params) {
int16 freeVar;
int16 maxFreeVar;
freeVar = _vm->_parse->parseVarIndex();
maxFreeVar = _vm->_parse->parseVarIndex();
// HACK
WRITE_VAR_OFFSET(freeVar, 1000000);
WRITE_VAR_OFFSET(maxFreeVar, 1000000);
WRITE_VAR(16, READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4);
return false;
}
bool Inter_v2::o2_checkData(OpFuncParams &params) {
int16 handle;
int16 varOff;
int32 size;
SaveLoad::SaveMode mode;
evalExpr(0);
varOff = _vm->_parse->parseVarIndex();
size = -1;
handle = 1;
mode = _vm->_saveLoad->getSaveMode(_vm->_global->_inter_resStr);
if (mode == SaveLoad::kSaveModeNone) {
handle = _vm->_dataIO->openData(_vm->_global->_inter_resStr);
if (handle >= 0) {
_vm->_dataIO->closeData(handle);
size = _vm->_dataIO->getDataSize(_vm->_global->_inter_resStr);
} else
warning("File \"%s\" not found", _vm->_global->_inter_resStr);
} else if (mode == SaveLoad::kSaveModeSave)
size = _vm->_saveLoad->getSize(_vm->_global->_inter_resStr);
else if (mode == SaveLoad::kSaveModeExists)
size = 23;
if (size == -1)
handle = -1;
debugC(2, kDebugFileIO, "Requested size of file \"%s\": %d",
_vm->_global->_inter_resStr, size);
WRITE_VAR_OFFSET(varOff, handle);
WRITE_VAR(16, (uint32) size);
return false;
}
bool Inter_v2::o2_readData(OpFuncParams &params) {
int32 retSize;
int32 size;
int32 offset;
int16 dataVar;
int16 handle;
byte *buf;
SaveLoad::SaveMode mode;
evalExpr(0);
dataVar = _vm->_parse->parseVarIndex();
size = _vm->_parse->parseValExpr();
evalExpr(0);
offset = _vm->_global->_inter_resVal;
retSize = 0;
debugC(2, kDebugFileIO, "Read from file \"%s\" (%d, %d bytes at %d)",
_vm->_global->_inter_resStr, dataVar, size, offset);
mode = _vm->_saveLoad->getSaveMode(_vm->_global->_inter_resStr);
if (mode == SaveLoad::kSaveModeSave) {
WRITE_VAR(1, 1);
if (_vm->_saveLoad->load(_vm->_global->_inter_resStr, dataVar, size, offset))
WRITE_VAR(1, 0);
return false;
} else if (mode == SaveLoad::kSaveModeIgnore)
return false;
if (size < 0) {
warning("Attempted to read a raw sprite from file \"%s\"",
_vm->_global->_inter_resStr);
return false ;
} else if (size == 0) {
dataVar = 0;
size = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4;
}
buf = _variables->getAddressOff8(dataVar, size);
if (_vm->_global->_inter_resStr[0] == 0) {
WRITE_VAR(1, size);
return false;
}
WRITE_VAR(1, 1);
handle = _vm->_dataIO->openData(_vm->_global->_inter_resStr);
if (handle < 0)
return false;
DataStream *stream = _vm->_dataIO->openAsStream(handle, true);
_vm->_draw->animateCursor(4);
if (offset < 0)
stream->seek(-offset - 1, SEEK_END);
else
stream->seek(offset);
if (((dataVar >> 2) == 59) && (size == 4)) {
WRITE_VAR(59, stream->readUint32LE());
// The scripts in some versions divide through 256^3 then,
// effectively doing a LE->BE conversion
if ((_vm->getPlatform() != Common::kPlatformPC) && (VAR(59) < 256))
WRITE_VAR(59, SWAP_BYTES_32(VAR(59)));
} else
retSize = stream->read(buf, size);
if (retSize == size)
WRITE_VAR(1, 0);
delete stream;
return false;
}
bool Inter_v2::o2_writeData(OpFuncParams &params) {
int32 offset;
int32 size;
int16 dataVar;
SaveLoad::SaveMode mode;
evalExpr(0);
dataVar = _vm->_parse->parseVarIndex();
size = _vm->_parse->parseValExpr();
evalExpr(0);
offset = _vm->_global->_inter_resVal;
debugC(2, kDebugFileIO, "Write to file \"%s\" (%d, %d bytes at %d)",
_vm->_global->_inter_resStr, dataVar, size, offset);
WRITE_VAR(1, 1);
mode = _vm->_saveLoad->getSaveMode(_vm->_global->_inter_resStr);
if (mode == SaveLoad::kSaveModeSave) {
if (_vm->_saveLoad->save(_vm->_global->_inter_resStr, dataVar, size, offset))
WRITE_VAR(1, 0);
} else if (mode == SaveLoad::kSaveModeNone)
warning("Attempted to write to file \"%s\"", _vm->_global->_inter_resStr);
return false;
}
void Inter_v2::o2_loadInfogramesIns(OpGobParams &params) {
int16 varName;
char fileName[20];
varName = load16();
strncpy0(fileName, GET_VAR_STR(varName), 15);
strcat(fileName, ".INS");
_vm->_sound->infogramesLoadInstruments(fileName);
}
void Inter_v2::o2_playInfogrames(OpGobParams &params) {
int16 varName;
char fileName[20];
varName = load16();
strncpy0(fileName, GET_VAR_STR(varName), 15);
strcat(fileName, ".DUM");
_vm->_sound->infogramesLoadSong(fileName);
_vm->_sound->infogramesPlay();
}
void Inter_v2::o2_startInfogrames(OpGobParams &params) {
load16();
_vm->_sound->infogramesPlay();
}
void Inter_v2::o2_stopInfogrames(OpGobParams &params) {
load16();
_vm->_sound->infogramesStop();
}
void Inter_v2::o2_handleGoblins(OpGobParams &params) {
_vm->_goblin->_gob1NoTurn = VAR(load16()) != 0;
_vm->_goblin->_gob2NoTurn = VAR(load16()) != 0;
_vm->_goblin->_gob1RelaxTimeVar = load16();
_vm->_goblin->_gob2RelaxTimeVar = load16();
_vm->_goblin->_gob1Busy = VAR(load16()) != 0;
_vm->_goblin->_gob2Busy = VAR(load16()) != 0;
_vm->_goblin->handleGoblins();
}
int16 Inter_v2::loadSound(int16 search) {
byte *dataPtr;
int16 id;
int16 slot;
uint16 slotIdMask;
uint32 dataSize;
SoundType type;
SoundSource source;
type = SOUND_SND;
slotIdMask = 0;
dataSize = 0;
if (!search) {
slot = _vm->_parse->parseValExpr();
if (slot < 0) {
type = SOUND_ADL;
slot = -slot;
}
id = load16();
} else {
id = load16();
for (slot = 0; slot < Sound::kSoundsCount; slot++)
if (_vm->_sound->sampleGetBySlot(slot)->isId(id)) {
slotIdMask = 0x8000;
break;
}
if (slot == Sound::kSoundsCount) {
for (slot = (Sound::kSoundsCount - 1); slot >= 0; slot--) {
if (_vm->_sound->sampleGetBySlot(slot)->empty())
break;
}
if (slot == -1) {
warning("Inter_v2::loadSound(): No free slot to load sound "
"(id = %d)", id);
return 0;
}
}
}
SoundDesc *sample = _vm->_sound->sampleGetBySlot(slot);
_vm->_sound->sampleFree(sample, true, slot);
if (id == -1) {
char sndfile[14];
source = SOUND_FILE;
strncpy0(sndfile, (const char *) _vm->_global->_inter_execPtr, 9);
_vm->_global->_inter_execPtr += 9;
if (type == SOUND_ADL)
strcat(sndfile, ".ADL");
else
strcat(sndfile, ".SND");
dataPtr = (byte *) _vm->_dataIO->getData(sndfile);
if (dataPtr)
dataSize = _vm->_dataIO->getDataSize(sndfile);
} else if (id >= 30000) {
source = SOUND_EXT;
dataPtr = (byte *) _vm->_game->loadExtData(id, 0, 0, &dataSize);
} else {
int16 totSize;
source = SOUND_TOT;
dataPtr = (byte *) _vm->_game->loadTotResource(id, &totSize);
dataSize = (uint32) ((int32) totSize);
}
if (dataPtr) {
sample->load(type, source, dataPtr, dataSize);
sample->_id = id;
}
return slot | slotIdMask;
}
void Inter_v2::animPalette() {
int16 i;
int16 j;
Video::Color col;
bool first;
first = true;
for (j = 0; j < 8; j ++) {
if (_animPalDir[j] == 0)
continue;
if (first) {
_vm->_video->waitRetrace();
first = false;
}
if (_animPalDir[j] == -1) {
col = _vm->_global->_pPaletteDesc->vgaPal[_animPalLowIndex[j]];
for (i = _animPalLowIndex[j]; i < _animPalHighIndex[j]; i++)
_vm->_draw->_vgaPalette[i] = _vm->_draw->_vgaPalette[i + 1];
_vm->_global->_pPaletteDesc->vgaPal[_animPalHighIndex[j]] = col;
} else {
col = _vm->_global->_pPaletteDesc->vgaPal[_animPalHighIndex[j]];
for (i = _animPalHighIndex[j]; i > _animPalLowIndex[j]; i--)
_vm->_draw->_vgaPalette[i] = _vm->_draw->_vgaPalette[i - 1];
_vm->_global->_pPaletteDesc->vgaPal[_animPalLowIndex[j]] = col;
}
_vm->_global->_pPaletteDesc->vgaPal = _vm->_draw->_vgaPalette;
}
if (!first)
_vm->_video->setFullPalette(_vm->_global->_pPaletteDesc);
}
} // End of namespace Gob