mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-11 19:54:03 +00:00
1733 lines
44 KiB
C++
1733 lines
44 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/endian.h"
|
|
#include "common/str.h"
|
|
#include "common/translation.h"
|
|
|
|
#include "gui/message.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/expression.h"
|
|
#include "gob/script.h"
|
|
#include "gob/resources.h"
|
|
#include "gob/hotspots.h"
|
|
#include "gob/goblin.h"
|
|
#include "gob/map.h"
|
|
#include "gob/mult.h"
|
|
#include "gob/scenery.h"
|
|
#include "gob/video.h"
|
|
#include "gob/save/saveload.h"
|
|
#include "gob/videoplayer.h"
|
|
#include "gob/sound/sound.h"
|
|
|
|
namespace Gob {
|
|
|
|
#define OPCODEVER Inter_v2
|
|
#define OPCODEDRAW(i, x) _opcodesDraw[i]._OPCODEDRAW(OPCODEVER, x)
|
|
#define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x)
|
|
#define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x)
|
|
|
|
Inter_v2::Inter_v2(GobEngine *vm) : Inter_v1(vm) {
|
|
}
|
|
|
|
void Inter_v2::setupOpcodesDraw() {
|
|
Inter_v1::setupOpcodesDraw();
|
|
|
|
OPCODEDRAW(0x01, o2_playMult);
|
|
OPCODEDRAW(0x02, o2_freeMultKeys);
|
|
|
|
OPCODEDRAW(0x0A, o2_setRenderFlags);
|
|
|
|
OPCODEDRAW(0x13, o2_multSub);
|
|
|
|
OPCODEDRAW(0x14, o2_initMult);
|
|
|
|
OPCODEDRAW(0x17, o2_loadMultObject);
|
|
|
|
OPCODEDRAW(0x1C, o2_renderStatic);
|
|
OPCODEDRAW(0x1D, o2_loadCurLayer);
|
|
|
|
OPCODEDRAW(0x20, o2_playCDTrack);
|
|
OPCODEDRAW(0x21, o2_waitCDTrackEnd);
|
|
OPCODEDRAW(0x22, o2_stopCD);
|
|
OPCODEDRAW(0x23, o2_readLIC);
|
|
|
|
OPCODEDRAW(0x24, o2_freeLIC);
|
|
OPCODEDRAW(0x25, o2_getCDTrackPos);
|
|
|
|
OPCODEDRAW(0x30, o2_loadFontToSprite);
|
|
|
|
OPCODEDRAW(0x40, o2_totSub);
|
|
OPCODEDRAW(0x41, o2_switchTotSub);
|
|
OPCODEDRAW(0x42, o2_pushVars);
|
|
OPCODEDRAW(0x43, o2_popVars);
|
|
|
|
OPCODEDRAW(0x50, o2_loadMapObjects);
|
|
OPCODEDRAW(0x51, o2_freeGoblins);
|
|
OPCODEDRAW(0x52, o2_moveGoblin);
|
|
OPCODEDRAW(0x53, o2_writeGoblinPos);
|
|
|
|
OPCODEDRAW(0x54, o2_stopGoblin);
|
|
OPCODEDRAW(0x55, o2_setGoblinState);
|
|
OPCODEDRAW(0x56, o2_placeGoblin);
|
|
|
|
OPCODEDRAW(0x80, o2_initScreen);
|
|
OPCODEDRAW(0x81, o2_scroll);
|
|
OPCODEDRAW(0x82, o2_setScrollOffset);
|
|
OPCODEDRAW(0x83, o2_playImd);
|
|
|
|
OPCODEDRAW(0x84, o2_getImdInfo);
|
|
OPCODEDRAW(0x85, o2_openItk);
|
|
OPCODEDRAW(0x86, o2_closeItk);
|
|
OPCODEDRAW(0x87, o2_setImdFrontSurf);
|
|
|
|
OPCODEDRAW(0x88, o2_resetImdFrontSurf);
|
|
}
|
|
|
|
void Inter_v2::setupOpcodesFunc() {
|
|
Inter_v1::setupOpcodesFunc();
|
|
|
|
OPCODEFUNC(0x09, o2_assign);
|
|
|
|
OPCODEFUNC(0x11, o2_printText);
|
|
|
|
OPCODEFUNC(0x17, o2_animPalInit);
|
|
|
|
OPCODEFUNC(0x18, o2_addHotspot);
|
|
OPCODEFUNC(0x19, o2_removeHotspot);
|
|
OPCODEFUNC(0x1A, o2_getTotTextItemPart);
|
|
|
|
OPCODEFUNC(0x25, o2_goblinFunc);
|
|
|
|
OPCODEFUNC(0x39, o2_stopSound);
|
|
OPCODEFUNC(0x3A, o2_loadSound);
|
|
|
|
OPCODEFUNC(0x3E, o2_getFreeMem);
|
|
OPCODEFUNC(0x3F, o2_checkData);
|
|
|
|
OPCODEFUNC(0x4D, o2_readData);
|
|
OPCODEFUNC(0x4E, o2_writeData);
|
|
}
|
|
|
|
void Inter_v2::setupOpcodesGob() {
|
|
OPCODEGOB( 0, o2_loadInfogramesIns);
|
|
OPCODEGOB( 1, o2_startInfogrames);
|
|
OPCODEGOB( 2, o2_stopInfogrames);
|
|
|
|
OPCODEGOB( 10, o2_playInfogrames);
|
|
|
|
OPCODEGOB(100, o2_handleGoblins);
|
|
|
|
OPCODEGOB(500, o2_playProtracker);
|
|
OPCODEGOB(501, o2_stopProtracker);
|
|
}
|
|
|
|
void Inter_v2::checkSwitchTable(uint32 &offset) {
|
|
byte type;
|
|
int16 len;
|
|
int32 value;
|
|
bool found;
|
|
|
|
found = false;
|
|
offset = 0;
|
|
|
|
type = _vm->_game->_script->peekByte();
|
|
|
|
value = (uint16) _vm->_game->_script->readVarIndex();
|
|
|
|
switch (type) {
|
|
case TYPE_VAR_INT8:
|
|
case TYPE_ARRAY_INT8:
|
|
value = (int8) READ_VARO_UINT8(value);
|
|
break;
|
|
|
|
case TYPE_VAR_INT32:
|
|
case TYPE_ARRAY_INT32:
|
|
value = READ_VARO_UINT32(value);
|
|
break;
|
|
|
|
default:
|
|
value = (int16) READ_VARO_UINT16(value);
|
|
break;
|
|
}
|
|
|
|
if (_terminate)
|
|
return;
|
|
|
|
len = _vm->_game->_script->readInt8();
|
|
while (len != -5) {
|
|
for (int i = 0; i < len; i++) {
|
|
type = _vm->_game->_script->peekByte();
|
|
|
|
switch (type) {
|
|
case TYPE_IMM_INT32:
|
|
_vm->_game->_script->skip(1);
|
|
if (!found &&
|
|
(value == _vm->_game->_script->peekInt32()))
|
|
found = true;
|
|
_vm->_game->_script->skip(5);
|
|
break;
|
|
|
|
case TYPE_IMM_INT16:
|
|
_vm->_game->_script->skip(1);
|
|
if (!found &&
|
|
(value == _vm->_game->_script->peekInt16()))
|
|
found = true;
|
|
_vm->_game->_script->skip(3);
|
|
break;
|
|
|
|
case TYPE_IMM_INT8:
|
|
_vm->_game->_script->skip(1);
|
|
if (!found && (value == _vm->_game->_script->peekInt8()))
|
|
found = true;
|
|
_vm->_game->_script->skip(2);
|
|
break;
|
|
|
|
default:
|
|
if (!found) {
|
|
_vm->_game->_script->evalExpr(nullptr);
|
|
if (value == _vm->_game->_script->getResultInt())
|
|
found = true;
|
|
} else
|
|
_vm->_game->_script->skipExpr(99);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found && (offset == 0))
|
|
offset = _vm->_game->_script->pos();
|
|
|
|
_vm->_game->_script->skip(_vm->_game->_script->peekUint16(2) + 2);
|
|
len = _vm->_game->_script->readInt8();
|
|
}
|
|
|
|
if ((_vm->_game->_script->peekByte() >> 4) != 4)
|
|
return;
|
|
|
|
_vm->_game->_script->skip(1);
|
|
if (offset == 0)
|
|
offset = _vm->_game->_script->pos();
|
|
|
|
_vm->_game->_script->skip(_vm->_game->_script->peekUint16(2) + 2);
|
|
}
|
|
|
|
void Inter_v2::o2_playMult() {
|
|
int16 checkEscape;
|
|
|
|
checkEscape = _vm->_game->_script->readInt16();
|
|
|
|
_vm->_mult->setMultData(checkEscape >> 1);
|
|
_vm->_mult->playMult(VAR(57), -1, checkEscape & 0x1, 0);
|
|
}
|
|
|
|
void Inter_v2::o2_freeMultKeys() {
|
|
uint16 index = _vm->_game->_script->readUint16();
|
|
|
|
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->_game->_script->readValExpr();
|
|
|
|
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->_game->_script->readValExpr());
|
|
}
|
|
|
|
void Inter_v2::o2_initMult() {
|
|
int16 oldAnimHeight;
|
|
int16 oldAnimWidth;
|
|
int16 oldObjCount;
|
|
uint16 posXVar;
|
|
uint16 posYVar;
|
|
uint16 animDataVar;
|
|
|
|
oldAnimWidth = _vm->_mult->_animWidth;
|
|
oldAnimHeight = _vm->_mult->_animHeight;
|
|
oldObjCount = _vm->_mult->_objCount;
|
|
|
|
_vm->_mult->_animLeft = _vm->_game->_script->readInt16();
|
|
_vm->_mult->_animTop = _vm->_game->_script->readInt16();
|
|
_vm->_mult->_animWidth = _vm->_game->_script->readInt16();
|
|
_vm->_mult->_animHeight = _vm->_game->_script->readInt16();
|
|
_vm->_mult->_objCount = _vm->_game->_script->readInt16();
|
|
posXVar = _vm->_game->_script->readVarIndex();
|
|
posYVar = _vm->_game->_script->readVarIndex();
|
|
animDataVar = _vm->_game->_script->readVarIndex();
|
|
|
|
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 = nullptr;
|
|
_vm->_mult->_renderObjs = nullptr;
|
|
_vm->_mult->_orderArray = nullptr;
|
|
}
|
|
|
|
if (_vm->_mult->_objects == nullptr) {
|
|
_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->_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(Draw::kAnimSurface);
|
|
_vm->_mult->_animSurf.reset();
|
|
}
|
|
|
|
_vm->_draw->adjustCoords(0,
|
|
&_vm->_mult->_animWidth, &_vm->_mult->_animHeight);
|
|
if (!_vm->_mult->_animSurf) {
|
|
_vm->_draw->initSpriteSurf(Draw::kAnimSurface, _vm->_mult->_animWidth,
|
|
_vm->_mult->_animHeight, 0);
|
|
_vm->_mult->_animSurf = _vm->_draw->_spritesArray[Draw::kAnimSurface];
|
|
if (_terminate)
|
|
return;
|
|
}
|
|
|
|
_vm->_draw->adjustCoords(1,
|
|
&_vm->_mult->_animWidth, &_vm->_mult->_animHeight);
|
|
_vm->_draw->_sourceSurface = Draw::kBackSurface;
|
|
_vm->_draw->_destSurface = Draw::kAnimSurface;
|
|
_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() {
|
|
assert(_vm->_mult->_objects);
|
|
|
|
uint16 objIndex = _vm->_game->_script->readValExpr();
|
|
|
|
debugC(4, kDebugGameFlow, "Loading mult object %d", objIndex);
|
|
|
|
Mult::Mult_Object &obj = _vm->_mult->_objects[objIndex];
|
|
Mult::Mult_AnimData &objAnim = *(obj.pAnimData);
|
|
|
|
*obj.pPosX = _vm->_game->_script->readValExpr();
|
|
*obj.pPosY = _vm->_game->_script->readValExpr();
|
|
|
|
byte *multData = (byte *) &objAnim;
|
|
for (int i = 0; i < 11; i++) {
|
|
if (_vm->_game->_script->peekByte() != 99)
|
|
multData[i] = _vm->_game->_script->readValExpr();
|
|
else
|
|
_vm->_game->_script->skip(1);
|
|
}
|
|
|
|
if ((objAnim.animType == 100) && (objIndex < _vm->_goblin->_gobsCount)) {
|
|
|
|
uint8 posX = *(obj.pPosX) % 256;
|
|
obj.destX = posX;
|
|
obj.gobDestX = posX;
|
|
obj.goblinX = posX;
|
|
|
|
uint8 posY = *(obj.pPosY) % 256;
|
|
obj.destY = posY;
|
|
obj.gobDestY = posY;
|
|
obj.goblinY = posY;
|
|
|
|
*(obj.pPosX) *= _vm->_map->getTilesWidth();
|
|
|
|
int16 layer = objAnim.layer;
|
|
int16 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->hasBigTiles())
|
|
*(obj.pPosY) = (obj.goblinY + 1) * _vm->_map->getTilesHeight()
|
|
- (_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
|
|
else
|
|
*(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->getTilesHeight()) -
|
|
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) -
|
|
((obj.goblinY + 1) / 2);
|
|
*(obj.pPosX) = obj.goblinX * _vm->_map->getTilesWidth();
|
|
|
|
} else if ((objAnim.animType == 101) && (objIndex < _vm->_goblin->_gobsCount)) {
|
|
|
|
int16 layer = objAnim.layer;
|
|
int16 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->closeVideo(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->_game->_script->readValExpr();
|
|
layer = _vm->_game->_script->readValExpr();
|
|
_vm->_scenery->renderStatic(index, layer);
|
|
}
|
|
|
|
void Inter_v2::o2_loadCurLayer() {
|
|
_vm->_scenery->_curStatic = _vm->_game->_script->readValExpr();
|
|
_vm->_scenery->_curStaticLayer = _vm->_game->_script->readValExpr();
|
|
}
|
|
|
|
void Inter_v2::o2_playCDTrack() {
|
|
if (!(_vm->_draw->_renderFlags & RENDERFLAG_NOBLITINVALIDATED))
|
|
_vm->_draw->blitInvalidated();
|
|
|
|
_vm->_sound->cdPlay(_vm->_game->_script->evalString());
|
|
}
|
|
|
|
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() {
|
|
Common::String file = _vm->_game->_script->evalString();
|
|
file += ".LIC";
|
|
|
|
_vm->_sound->cdLoadLIC(file.c_str());
|
|
}
|
|
|
|
void Inter_v2::o2_freeLIC() {
|
|
_vm->_sound->cdUnloadLIC();
|
|
}
|
|
|
|
void Inter_v2::o2_getCDTrackPos() {
|
|
int16 varPos;
|
|
int16 varName;
|
|
|
|
_vm->_util->longDelay(1);
|
|
|
|
varPos = _vm->_game->_script->readVarIndex();
|
|
varName = _vm->_game->_script->readVarIndex();
|
|
|
|
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 = _vm->_game->_script->readInt16();
|
|
|
|
_vm->_draw->_fontToSprite[i].sprite = _vm->_game->_script->readByte();
|
|
_vm->_game->_script->skip(1);
|
|
_vm->_draw->_fontToSprite[i].base = _vm->_game->_script->readByte();
|
|
_vm->_game->_script->skip(1);
|
|
_vm->_draw->_fontToSprite[i].width = _vm->_game->_script->readByte();
|
|
_vm->_game->_script->skip(1);
|
|
_vm->_draw->_fontToSprite[i].height = _vm->_game->_script->readByte();
|
|
_vm->_game->_script->skip(1);
|
|
}
|
|
|
|
void Inter_v2::o2_totSub() {
|
|
uint8 length = _vm->_game->_script->readByte();
|
|
if ((length & 0x7F) > 13)
|
|
error("Length in o2_totSub is greater than 13 (%d)", length);
|
|
|
|
Common::String totFile;
|
|
if (length & 0x80)
|
|
totFile = _vm->_game->_script->evalString();
|
|
else
|
|
for (uint8 i = 0; i < length; i++)
|
|
totFile += _vm->_game->_script->readChar();
|
|
|
|
// WORKAROUND: There is a race condition in the script when opening the notepad
|
|
if (!totFile.equalsIgnoreCase("edit"))
|
|
_vm->_util->forceMouseUp();
|
|
|
|
// WORKAROUND: For some reason, the variable indicating which TOT to load next
|
|
// is overwritten in the guard house card game in Woodruff
|
|
if ((_vm->getGameType() == kGameTypeWoodruff) && (totFile == "6"))
|
|
totFile = "EMAP2011";
|
|
|
|
uint8 flags = _vm->_game->_script->readByte();
|
|
|
|
_vm->_game->totSub(flags, totFile);
|
|
}
|
|
|
|
void Inter_v2::o2_switchTotSub() {
|
|
int16 index;
|
|
int16 function;
|
|
|
|
index = _vm->_game->_script->readInt16();
|
|
function = _vm->_game->_script->readInt16();
|
|
|
|
_vm->_game->switchTotSub(index, function);
|
|
}
|
|
|
|
void Inter_v2::o2_pushVars() {
|
|
uint8 count = _vm->_game->_script->readByte();
|
|
for (int i = 0; i < count; i++) {
|
|
if ((_vm->_game->_script->peekByte() == 25) ||
|
|
(_vm->_game->_script->peekByte() == 28)) {
|
|
|
|
int16 varOff = _vm->_game->_script->readVarIndex();
|
|
_vm->_game->_script->skip(1);
|
|
|
|
_varStack.pushData(*_variables, varOff, _vm->_global->_inter_animDataSize * 4);
|
|
|
|
} else {
|
|
int16 value;
|
|
|
|
if (_vm->_game->_script->evalExpr(&value) != 20)
|
|
value = 0;
|
|
|
|
_varStack.pushInt((uint16)value);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Inter_v2::o2_popVars() {
|
|
uint8 count = _vm->_game->_script->readByte();
|
|
for (int i = 0; i < count; i++) {
|
|
int16 varOff = _vm->_game->_script->readVarIndex();
|
|
|
|
_varStack.pop(*_variables, varOff);
|
|
}
|
|
}
|
|
|
|
void Inter_v2::o2_loadMapObjects() {
|
|
_vm->_map->loadMapObjects(nullptr);
|
|
}
|
|
|
|
void Inter_v2::o2_freeGoblins() {
|
|
_vm->_goblin->freeObjects();
|
|
}
|
|
|
|
void Inter_v2::o2_moveGoblin() {
|
|
int16 destX, destY;
|
|
int16 index;
|
|
|
|
destX = _vm->_game->_script->readValExpr();
|
|
destY = _vm->_game->_script->readValExpr();
|
|
index = _vm->_game->_script->readValExpr();
|
|
_vm->_goblin->move(destX, destY, index);
|
|
}
|
|
|
|
void Inter_v2::o2_writeGoblinPos() {
|
|
int16 varX, varY;
|
|
int16 index;
|
|
|
|
varX = _vm->_game->_script->readVarIndex();
|
|
varY = _vm->_game->_script->readVarIndex();
|
|
index = _vm->_game->_script->readValExpr();
|
|
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->_game->_script->readValExpr();
|
|
|
|
_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->_game->_script->readValExpr();
|
|
state = _vm->_game->_script->readValExpr();
|
|
type = _vm->_game->_script->readValExpr();
|
|
|
|
Mult::Mult_Object &obj = _vm->_mult->_objects[index];
|
|
Mult::Mult_AnimData &objAnim = *(obj.pAnimData);
|
|
|
|
objAnim.stateType = type;
|
|
if (!obj.goblinStates || !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->hasBigTiles())
|
|
*(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->getTilesHeight()) -
|
|
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop) -
|
|
((obj.goblinY + 1) / 2);
|
|
else
|
|
*(obj.pPosY) = ((obj.goblinY + 1) * _vm->_map->getTilesHeight()) -
|
|
(_vm->_scenery->_animBottom - _vm->_scenery->_animTop);
|
|
*(obj.pPosX) = obj.goblinX * _vm->_map->getTilesWidth();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Inter_v2::o2_placeGoblin() {
|
|
int16 index;
|
|
int16 x, y;
|
|
int16 state;
|
|
|
|
index = _vm->_game->_script->readValExpr();
|
|
x = _vm->_game->_script->readValExpr();
|
|
y = _vm->_game->_script->readValExpr();
|
|
state = _vm->_game->_script->readValExpr();
|
|
|
|
_vm->_goblin->placeObject(nullptr, 0, index, x, y, state);
|
|
}
|
|
|
|
void Inter_v2::o2_initScreen() {
|
|
int16 offY;
|
|
int16 videoMode;
|
|
int16 width, height;
|
|
|
|
offY = _vm->_game->_script->readInt16();
|
|
|
|
videoMode = offY & 0xFF;
|
|
offY = (offY >> 8) & 0xFF;
|
|
|
|
width = _vm->_game->_script->readValExpr();
|
|
height = _vm->_game->_script->readValExpr();
|
|
|
|
_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();
|
|
|
|
} 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();
|
|
|
|
}
|
|
}
|
|
|
|
_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->_game->_script->readValExpr(), 0,
|
|
_vm->_video->_surfWidth - _vm->_width);
|
|
startY = CLIP((int)_vm->_game->_script->readValExpr(), 0,
|
|
_vm->_video->_surfHeight - _vm->_height);
|
|
endX = CLIP((int)_vm->_game->_script->readValExpr(), 0,
|
|
_vm->_video->_surfWidth - _vm->_width);
|
|
endY = CLIP((int)_vm->_game->_script->readValExpr(), 0,
|
|
_vm->_video->_surfHeight - _vm->_height);
|
|
stepX = _vm->_game->_script->readValExpr();
|
|
stepY = _vm->_game->_script->readValExpr();
|
|
|
|
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->_game->_script->readValExpr();
|
|
offsetY = _vm->_game->_script->readValExpr();
|
|
|
|
if (offsetX == -1) {
|
|
_vm->_game->_preventScroll = !_vm->_game->_preventScroll;
|
|
|
|
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() {
|
|
VideoPlayer::Properties props;
|
|
|
|
Common::String imd = _vm->_game->_script->evalString();
|
|
if (imd.size() > 8)
|
|
imd = Common::String(imd.c_str(), 8);
|
|
|
|
props.x = _vm->_game->_script->readValExpr();
|
|
props.y = _vm->_game->_script->readValExpr();
|
|
props.startFrame = _vm->_game->_script->readValExpr();
|
|
props.lastFrame = _vm->_game->_script->readValExpr();
|
|
props.breakKey = _vm->_game->_script->readValExpr();
|
|
props.flags = _vm->_game->_script->readValExpr();
|
|
props.palStart = _vm->_game->_script->readValExpr();
|
|
props.palEnd = _vm->_game->_script->readValExpr();
|
|
props.palCmd = 1 << (props.flags & 0x3F);
|
|
|
|
debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, "
|
|
"paletteCmd %d (%d - %d), flags %X", imd.c_str(),
|
|
props.x, props.y, props.startFrame, props.lastFrame,
|
|
props.palCmd, props.palStart, props.palEnd, props.flags);
|
|
|
|
int slot = 0;
|
|
if (!imd.empty()) {
|
|
_vm->_vidPlayer->evaluateFlags(props);
|
|
if ((slot = _vm->_vidPlayer->openVideo(true, imd, props)) < 0) {
|
|
WRITE_VAR(11, (uint32) -1);
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool close = (props.lastFrame == -1);
|
|
if (props.startFrame == -2) {
|
|
props.startFrame = 0;
|
|
props.lastFrame = 0;
|
|
close = false;
|
|
}
|
|
|
|
if (props.startFrame >= 0)
|
|
_vm->_vidPlayer->play(slot, props);
|
|
|
|
if (close)
|
|
_vm->_vidPlayer->closeVideo(slot);
|
|
}
|
|
|
|
void Inter_v2::o2_getImdInfo() {
|
|
Common::String imd = _vm->_game->_script->evalString();
|
|
|
|
int16 varX = _vm->_game->_script->readVarIndex();
|
|
int16 varY = _vm->_game->_script->readVarIndex();
|
|
int16 varFrames = _vm->_game->_script->readVarIndex();
|
|
int16 varWidth = _vm->_game->_script->readVarIndex();
|
|
int16 varHeight = _vm->_game->_script->readVarIndex();
|
|
|
|
// 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) &&
|
|
imd.equalsIgnoreCase("noixroule"))
|
|
imd = "noixroul";
|
|
|
|
_vm->_vidPlayer->writeVideoInfo(imd, varX, varY, varFrames, varWidth, varHeight);
|
|
}
|
|
|
|
void Inter_v2::o2_openItk() {
|
|
Common::String file = _vm->_game->_script->evalString();
|
|
if (!file.contains('.'))
|
|
file += ".ITK";
|
|
|
|
_vm->_dataIO->openArchive(file, false);
|
|
}
|
|
|
|
void Inter_v2::o2_closeItk() {
|
|
_vm->_dataIO->closeArchive(false);
|
|
|
|
// NOTE: Lost in Time might close a data file without explicitely closing a video in it.
|
|
// So we make sure that all open videos are still available.
|
|
_vm->_vidPlayer->reopenAll();
|
|
}
|
|
|
|
void Inter_v2::o2_setImdFrontSurf() {
|
|
}
|
|
|
|
void Inter_v2::o2_resetImdFrontSurf() {
|
|
}
|
|
|
|
void Inter_v2::o2_assign(OpFuncParams ¶ms) {
|
|
byte destType = _vm->_game->_script->peekByte();
|
|
int16 dest = _vm->_game->_script->readVarIndex();
|
|
|
|
byte loopCount;
|
|
if (_vm->_game->_script->peekByte() == 99) {
|
|
_vm->_game->_script->skip(1);
|
|
loopCount = _vm->_game->_script->readByte();
|
|
} else
|
|
loopCount = 1;
|
|
|
|
for (int i = 0; i < loopCount; i++) {
|
|
int16 result;
|
|
int16 srcType = _vm->_game->_script->evalExpr(&result);
|
|
|
|
switch (destType) {
|
|
case TYPE_VAR_INT8:
|
|
case TYPE_ARRAY_INT8:
|
|
WRITE_VARO_UINT8(dest + i, _vm->_game->_script->getResultInt());
|
|
break;
|
|
|
|
case TYPE_VAR_INT16:
|
|
case TYPE_ARRAY_INT16:
|
|
WRITE_VARO_UINT16(dest + i * 2, _vm->_game->_script->getResultInt());
|
|
break;
|
|
|
|
case TYPE_VAR_INT32:
|
|
case TYPE_ARRAY_INT32:
|
|
WRITE_VAR_OFFSET(dest + i * 4, _vm->_game->_script->getResultInt());
|
|
break;
|
|
|
|
case TYPE_VAR_INT32_AS_INT16:
|
|
WRITE_VARO_UINT16(dest + i * 4, _vm->_game->_script->getResultInt());
|
|
break;
|
|
|
|
case TYPE_VAR_STR:
|
|
case TYPE_ARRAY_STR:
|
|
if (srcType == TYPE_IMM_INT16)
|
|
WRITE_VARO_UINT8(dest, result);
|
|
else
|
|
WRITE_VARO_STR(dest, _vm->_game->_script->getResultStr());
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Inter_v2::o2_printText(OpFuncParams ¶ms) {
|
|
char buf[60];
|
|
int i;
|
|
|
|
_vm->_draw->_destSpriteX = _vm->_game->_script->readValExpr();
|
|
_vm->_draw->_destSpriteY = _vm->_game->_script->readValExpr();
|
|
|
|
_vm->_draw->_backColor = _vm->_game->_script->readValExpr();
|
|
_vm->_draw->_frontColor = _vm->_game->_script->readValExpr();
|
|
_vm->_draw->_fontIndex = _vm->_game->_script->readValExpr();
|
|
_vm->_draw->_destSurface = Draw::kBackSurface;
|
|
_vm->_draw->_textToPrint = buf;
|
|
_vm->_draw->_transparency = 0;
|
|
|
|
SurfacePtr surface = _vm->_draw->_spritesArray[_vm->_draw->_destSurface];
|
|
uint16 destWidth = surface ? surface->getWidth() : 0;
|
|
uint16 destHeight = surface ? surface->getHeight() : 0;
|
|
|
|
if (_vm->_draw->_backColor == 16) {
|
|
_vm->_draw->_backColor = 0;
|
|
_vm->_draw->_transparency = 1;
|
|
}
|
|
|
|
do {
|
|
for (i = 0; i < 59 && (_vm->_game->_script->peekChar() != '.') &&
|
|
(_vm->_game->_script->peekByte() != 200); i++) {
|
|
buf[i] = _vm->_game->_script->readChar();
|
|
}
|
|
|
|
const int limit = MAX(60 - i, 0);
|
|
if (_vm->_game->_script->peekByte() != 200) {
|
|
_vm->_game->_script->skip(1);
|
|
switch (_vm->_game->_script->peekByte()) {
|
|
case TYPE_VAR_INT8:
|
|
case TYPE_ARRAY_INT8:
|
|
snprintf(buf + i, limit, "%d",
|
|
(int8) READ_VARO_UINT8(_vm->_game->_script->readVarIndex()));
|
|
break;
|
|
|
|
case TYPE_VAR_INT16:
|
|
case TYPE_VAR_INT32_AS_INT16:
|
|
case TYPE_ARRAY_INT16:
|
|
snprintf(buf + i, limit, "%d",
|
|
(int16) READ_VARO_UINT16(_vm->_game->_script->readVarIndex()));
|
|
break;
|
|
|
|
case TYPE_VAR_INT32:
|
|
case TYPE_ARRAY_INT32:
|
|
snprintf(buf + i, limit, "%d",
|
|
(int32)VAR_OFFSET(_vm->_game->_script->readVarIndex()));
|
|
break;
|
|
|
|
case TYPE_VAR_STR:
|
|
case TYPE_ARRAY_STR:
|
|
snprintf(buf + i, limit, "%s",
|
|
GET_VARO_STR(_vm->_game->_script->readVarIndex()));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
_vm->_game->_script->skip(1);
|
|
} else
|
|
buf[i] = 0;
|
|
|
|
if ((_vm->_draw->_destSpriteX < destWidth) &&
|
|
(_vm->_draw->_destSpriteY < destHeight))
|
|
_vm->_draw->spriteOperation(DRAW_PRINTTEXT);
|
|
|
|
} while (_vm->_game->_script->peekByte() != 200);
|
|
|
|
_vm->_game->_script->skip(1);
|
|
}
|
|
|
|
void Inter_v2::o2_animPalInit(OpFuncParams ¶ms) {
|
|
int16 index;
|
|
|
|
index = _vm->_game->_script->readInt16();
|
|
if (index > 0) {
|
|
index--;
|
|
_animPalLowIndex[index] = _vm->_game->_script->readValExpr();
|
|
_animPalHighIndex[index] = _vm->_game->_script->readValExpr();
|
|
_animPalDir[index] = 1;
|
|
} else if (index == 0) {
|
|
memset(_animPalDir, 0, 8 * sizeof(int16));
|
|
_vm->_game->_script->readValExpr();
|
|
_vm->_game->_script->readValExpr();
|
|
} else {
|
|
index = -index - 1;
|
|
_animPalLowIndex[index] = _vm->_game->_script->readValExpr();
|
|
_animPalHighIndex[index] = _vm->_game->_script->readValExpr();
|
|
_animPalDir[index] = -1;
|
|
}
|
|
}
|
|
|
|
void Inter_v2::o2_addHotspot(OpFuncParams ¶ms) {
|
|
int16 id = _vm->_game->_script->readValExpr();
|
|
uint16 funcPos = _vm->_game->_script->pos();
|
|
int16 left = _vm->_game->_script->readValExpr();
|
|
int16 top = _vm->_game->_script->readValExpr();
|
|
uint16 width = _vm->_game->_script->readValExpr();
|
|
uint16 height = _vm->_game->_script->readValExpr();
|
|
uint16 flags = _vm->_game->_script->readValExpr();
|
|
uint16 key = _vm->_game->_script->readInt16();
|
|
|
|
if (key == 0)
|
|
key = ABS(id) + 41960;
|
|
|
|
if (left < 0) {
|
|
width += left;
|
|
left = 0;
|
|
}
|
|
|
|
if (top < 0) {
|
|
height += top;
|
|
top = 0;
|
|
}
|
|
|
|
if (id < 0)
|
|
_vm->_game->_hotspots->add(0xD000 - id, left & 0xFFFC, top & 0xFFFC,
|
|
left + width + 3, top + height + 3, flags, key, 0, 0, funcPos);
|
|
else
|
|
_vm->_game->_hotspots->add(0xE000 + id, left, top,
|
|
left + width - 1, top + height - 1, flags, key, 0, 0, funcPos);
|
|
}
|
|
|
|
void Inter_v2::o2_removeHotspot(OpFuncParams ¶ms) {
|
|
int16 id = _vm->_game->_script->readValExpr();
|
|
uint8 stateType1 = Hotspots::kStateFilledDisabled | Hotspots::kStateType1;
|
|
uint8 stateType2 = Hotspots::kStateFilledDisabled | Hotspots::kStateType2;
|
|
|
|
if (id == -2)
|
|
_vm->_game->_hotspots->removeState(stateType1);
|
|
else if (id == -1)
|
|
_vm->_game->_hotspots->removeState(stateType2);
|
|
else
|
|
_vm->_game->_hotspots->remove((stateType2 << 12) + id);
|
|
}
|
|
|
|
void Inter_v2::o2_getTotTextItemPart(OpFuncParams ¶ms) {
|
|
byte *totData;
|
|
int16 totTextItem;
|
|
int16 part, curPart = 0;
|
|
int16 offX = 0, offY = 0;
|
|
int16 collId = 0, collCmd;
|
|
uint32 stringStartVar, stringVar;
|
|
bool end;
|
|
|
|
totTextItem = _vm->_game->_script->readInt16();
|
|
stringStartVar = _vm->_game->_script->readVarIndex();
|
|
part = _vm->_game->_script->readValExpr();
|
|
|
|
stringVar = stringStartVar;
|
|
if (part == -1) {
|
|
warning("o2_getTotTextItemPart, part == -1");
|
|
_vm->_draw->_hotspotText = GET_VARO_STR(stringVar);
|
|
}
|
|
|
|
WRITE_VARO_UINT8(stringVar, 0);
|
|
|
|
TextItem *textItem = _vm->_game->_resources->getTextItem(totTextItem);
|
|
if (!textItem)
|
|
return;
|
|
|
|
totData = textItem->getData();
|
|
|
|
// Skip background rectangles
|
|
while (((int16) READ_LE_UINT16(totData)) != -1)
|
|
totData += 9;
|
|
totData += 2;
|
|
|
|
while (*totData != 1) {
|
|
switch (*totData) {
|
|
case 2:
|
|
case 5:
|
|
totData++;
|
|
offX = READ_LE_UINT16(totData);
|
|
offY = READ_LE_UINT16(totData + 2);
|
|
totData += 4;
|
|
break;
|
|
|
|
case 3:
|
|
case 4:
|
|
totData += 2;
|
|
break;
|
|
|
|
case 6:
|
|
totData++;
|
|
|
|
collCmd = *totData++;
|
|
if (collCmd & 0x80) {
|
|
collId = READ_LE_UINT16(totData);
|
|
totData += 2;
|
|
}
|
|
|
|
// Skip collision coordinates
|
|
if (collCmd & 0x40)
|
|
totData += 8;
|
|
|
|
if ((collCmd & 0x8F) && ((-collId - 1) == part)) {
|
|
int n = 0;
|
|
|
|
while (1) {
|
|
if ((*totData < 1) || (*totData > 7)) {
|
|
if (*totData >= 32) {
|
|
WRITE_VARO_UINT8(stringVar++, *totData++);
|
|
n++;
|
|
} else
|
|
totData++;
|
|
continue;
|
|
}
|
|
|
|
if ((n != 0) || (*totData == 1) ||
|
|
(*totData == 6) || (*totData == 7)) {
|
|
WRITE_VARO_UINT8(stringVar, 0);
|
|
delete textItem;
|
|
return;
|
|
}
|
|
|
|
switch (*totData) {
|
|
case 2:
|
|
case 5:
|
|
totData += 5;
|
|
break;
|
|
|
|
case 3:
|
|
case 4:
|
|
totData += 2;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
totData++;
|
|
break;
|
|
|
|
case 10:
|
|
if (curPart == part) {
|
|
WRITE_VARO_UINT8(stringVar++, 0xFF);
|
|
WRITE_VARO_UINT16(stringVar, offX);
|
|
WRITE_VARO_UINT16(stringVar + 2, offY);
|
|
WRITE_VARO_UINT16(stringVar + 4,
|
|
totData - _vm->_game->_resources->getTexts());
|
|
WRITE_VARO_UINT8(stringVar + 6, 0);
|
|
delete textItem;
|
|
return;
|
|
}
|
|
|
|
end = false;
|
|
while (!end) {
|
|
switch (*totData) {
|
|
case 2:
|
|
case 5:
|
|
if (ABS(offY - READ_LE_UINT16(totData + 3)) > 1)
|
|
end = true;
|
|
else
|
|
totData += 5;
|
|
break;
|
|
|
|
case 3:
|
|
totData += 2;
|
|
break;
|
|
|
|
case 10:
|
|
totData += totData[1] * 2 + 2;
|
|
break;
|
|
|
|
default:
|
|
if (*totData < 32)
|
|
end = true;
|
|
while (*totData >= 32)
|
|
totData++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (part >= 0)
|
|
curPart++;
|
|
break;
|
|
|
|
default:
|
|
while (1) {
|
|
|
|
while (*totData >= 32)
|
|
WRITE_VARO_UINT8(stringVar++, *totData++);
|
|
WRITE_VARO_UINT8(stringVar, 0);
|
|
|
|
if (((*totData != 2) && (*totData != 5)) ||
|
|
(ABS(offY - READ_LE_UINT16(totData + 3)) > 1)) {
|
|
|
|
if (curPart == part) {
|
|
delete textItem;
|
|
return;
|
|
}
|
|
|
|
stringVar = stringStartVar;
|
|
WRITE_VARO_UINT8(stringVar, 0);
|
|
|
|
while (*totData >= 32)
|
|
totData++;
|
|
|
|
if (part >= 0)
|
|
curPart++;
|
|
break;
|
|
|
|
} else
|
|
totData += 5;
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
delete textItem;
|
|
}
|
|
|
|
void Inter_v2::o2_goblinFunc(OpFuncParams ¶ms) {
|
|
OpGobParams gobParams;
|
|
int16 cmd;
|
|
|
|
cmd = _vm->_game->_script->readInt16();
|
|
|
|
gobParams.paramCount = _vm->_game->_script->readInt16();
|
|
gobParams.extraData = cmd;
|
|
|
|
if (cmd != 101)
|
|
executeOpcodeGob(cmd, gobParams);
|
|
}
|
|
|
|
void Inter_v2::o2_stopSound(OpFuncParams ¶ms) {
|
|
int16 expr;
|
|
|
|
expr = _vm->_game->_script->readValExpr();
|
|
|
|
if (expr < 0) {
|
|
_vm->_sound->adlibStop();
|
|
} else
|
|
_vm->_sound->blasterStop(expr);
|
|
|
|
_soundEndTimeKey = 0;
|
|
}
|
|
|
|
void Inter_v2::o2_loadSound(OpFuncParams ¶ms) {
|
|
loadSound(0);
|
|
}
|
|
|
|
void Inter_v2::o2_getFreeMem(OpFuncParams ¶ms) {
|
|
uint16 freeVar;
|
|
uint16 maxFreeVar;
|
|
|
|
freeVar = _vm->_game->_script->readVarIndex();
|
|
maxFreeVar = _vm->_game->_script->readVarIndex();
|
|
|
|
// HACK
|
|
WRITE_VAR_OFFSET(freeVar , 1000000);
|
|
WRITE_VAR_OFFSET(maxFreeVar, 1000000);
|
|
WRITE_VAR(16, _vm->_game->_script->getVariablesCount() * 4);
|
|
}
|
|
|
|
void Inter_v2::o2_checkData(OpFuncParams ¶ms) {
|
|
Common::String file = _vm->_game->_script->evalString();
|
|
int16 varOff = _vm->_game->_script->readVarIndex();
|
|
|
|
// WORKAROUND: For some reason, the variable indicating which TOT to load next
|
|
// is overwritten in the guard house card game in Woodruff.
|
|
if ((_vm->getGameType() == kGameTypeWoodruff) && file.equalsIgnoreCase("6.tot"))
|
|
file = "EMAP2011.TOT";
|
|
|
|
int32 size = -1;
|
|
SaveLoad::SaveMode mode = _vm->_saveLoad ? _vm->_saveLoad->getSaveMode(file.c_str()) : SaveLoad::kSaveModeNone;
|
|
if (mode == SaveLoad::kSaveModeNone) {
|
|
|
|
size = _vm->_dataIO->fileSize(file);
|
|
if (size == -1)
|
|
warning("File \"%s\" not found", file.c_str());
|
|
|
|
} else if (mode == SaveLoad::kSaveModeSave)
|
|
size = _vm->_saveLoad->getSize(file.c_str());
|
|
else if (mode == SaveLoad::kSaveModeExists)
|
|
size = 23;
|
|
|
|
debugC(2, kDebugFileIO, "Requested size of file \"%s\": %d", file.c_str(), size);
|
|
|
|
WRITE_VAR_OFFSET(varOff, (size == -1) ? -1 : 50);
|
|
WRITE_VAR(16, (uint32) size);
|
|
}
|
|
|
|
void Inter_v2::o2_readData(OpFuncParams ¶ms) {
|
|
const char *file = _vm->_game->_script->evalString();
|
|
|
|
uint16 dataVar = _vm->_game->_script->readVarIndex();
|
|
int32 size = _vm->_game->_script->readValExpr();
|
|
int32 offset = _vm->_game->_script->evalInt();
|
|
int32 retSize = 0;
|
|
|
|
debugC(2, kDebugFileIO, "Read from file \"%s\" (%d, %d bytes at %d)",
|
|
file, dataVar, size, offset);
|
|
|
|
SaveLoad::SaveMode mode = _vm->_saveLoad ? _vm->_saveLoad->getSaveMode(file) : SaveLoad::kSaveModeNone;
|
|
if (mode == SaveLoad::kSaveModeSave) {
|
|
|
|
WRITE_VAR(1, 1);
|
|
|
|
if (!_vm->_saveLoad->load(file, dataVar, size, offset)) {
|
|
|
|
GUI::MessageDialog dialog(_("Failed to load saved game from file."));
|
|
dialog.runModal();
|
|
|
|
} else
|
|
WRITE_VAR(1, 0);
|
|
|
|
return;
|
|
|
|
} else if (mode == SaveLoad::kSaveModeIgnore)
|
|
return;
|
|
|
|
if (size < 0) {
|
|
warning("Attempted to read a raw sprite from file \"%s\"",
|
|
file);
|
|
return;
|
|
} else if (size == 0) {
|
|
dataVar = 0;
|
|
size = _vm->_game->_script->getVariablesCount() * 4;
|
|
}
|
|
|
|
byte *buf = _variables->getAddressOff8(dataVar);
|
|
|
|
if (file[0] == 0) {
|
|
WRITE_VAR(1, size);
|
|
return;
|
|
}
|
|
|
|
WRITE_VAR(1, 1);
|
|
Common::SeekableReadStream *stream = _vm->_dataIO->getFile(file);
|
|
if (!stream)
|
|
return;
|
|
|
|
_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::kPlatformDOS) && (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;
|
|
}
|
|
|
|
void Inter_v2::o2_writeData(OpFuncParams ¶ms) {
|
|
const char *file = _vm->_game->_script->evalString();
|
|
|
|
int16 dataVar = _vm->_game->_script->readVarIndex();
|
|
int32 size = _vm->_game->_script->readValExpr();
|
|
int32 offset = _vm->_game->_script->evalInt();
|
|
|
|
debugC(2, kDebugFileIO, "Write to file \"%s\" (%d, %d bytes at %d)",
|
|
file, dataVar, size, offset);
|
|
|
|
WRITE_VAR(1, 1);
|
|
|
|
SaveLoad::SaveMode mode = _vm->_saveLoad ? _vm->_saveLoad->getSaveMode(file) : SaveLoad::kSaveModeNone;
|
|
if (mode == SaveLoad::kSaveModeSave) {
|
|
|
|
if (!_vm->_saveLoad->save(file, dataVar, size, offset)) {
|
|
|
|
GUI::MessageDialog dialog(_("Failed to save game to file."));
|
|
dialog.runModal();
|
|
|
|
} else
|
|
WRITE_VAR(1, 0);
|
|
|
|
} else if (mode == SaveLoad::kSaveModeIgnore)
|
|
return;
|
|
else if (mode == SaveLoad::kSaveModeNone)
|
|
warning("Attempted to write to file \"%s\"", file);
|
|
}
|
|
|
|
void Inter_v2::o2_loadInfogramesIns(OpGobParams ¶ms) {
|
|
int16 varName;
|
|
char fileName[20];
|
|
|
|
varName = _vm->_game->_script->readInt16();
|
|
|
|
Common::strlcpy(fileName, GET_VAR_STR(varName), 16);
|
|
strcat(fileName, ".INS");
|
|
|
|
_vm->_sound->infogramesLoadInstruments(fileName);
|
|
}
|
|
|
|
void Inter_v2::o2_playInfogrames(OpGobParams ¶ms) {
|
|
int16 varName;
|
|
char fileName[20];
|
|
|
|
varName = _vm->_game->_script->readInt16();
|
|
|
|
Common::strlcpy(fileName, GET_VAR_STR(varName), 16);
|
|
strcat(fileName, ".DUM");
|
|
|
|
_vm->_sound->infogramesLoadSong(fileName);
|
|
_vm->_sound->infogramesPlay();
|
|
}
|
|
|
|
void Inter_v2::o2_startInfogrames(OpGobParams ¶ms) {
|
|
_vm->_game->_script->readInt16();
|
|
|
|
_vm->_sound->infogramesPlay();
|
|
}
|
|
|
|
void Inter_v2::o2_stopInfogrames(OpGobParams ¶ms) {
|
|
_vm->_game->_script->readInt16();
|
|
|
|
_vm->_sound->infogramesStop();
|
|
}
|
|
|
|
void Inter_v2::o2_playProtracker(OpGobParams ¶ms) {
|
|
_vm->_sound->protrackerPlay("mod.babayaga");
|
|
}
|
|
|
|
void Inter_v2::o2_stopProtracker(OpGobParams ¶ms) {
|
|
_vm->_sound->protrackerStop();
|
|
}
|
|
|
|
void Inter_v2::o2_handleGoblins(OpGobParams ¶ms) {
|
|
_vm->_goblin->_gob1NoTurn = VAR(_vm->_game->_script->readInt16()) != 0;
|
|
_vm->_goblin->_gob2NoTurn = VAR(_vm->_game->_script->readInt16()) != 0;
|
|
_vm->_goblin->_gob1RelaxTimeVar = _vm->_game->_script->readInt16();
|
|
_vm->_goblin->_gob2RelaxTimeVar = _vm->_game->_script->readInt16();
|
|
_vm->_goblin->_gob1Busy = VAR(_vm->_game->_script->readInt16()) != 0;
|
|
_vm->_goblin->_gob2Busy = VAR(_vm->_game->_script->readInt16()) != 0;
|
|
_vm->_goblin->handleGoblins();
|
|
}
|
|
|
|
int16 Inter_v2::loadSound(int16 search) {
|
|
int16 id;
|
|
int16 slot;
|
|
uint16 slotIdMask;
|
|
SoundType type;
|
|
|
|
type = SOUND_SND;
|
|
slotIdMask = 0;
|
|
|
|
if (!search) {
|
|
slot = _vm->_game->_script->readValExpr();
|
|
if (slot < 0) {
|
|
type = SOUND_ADL;
|
|
slot = -slot;
|
|
}
|
|
id = _vm->_game->_script->readInt16();
|
|
} else {
|
|
id = _vm->_game->_script->readInt16();
|
|
|
|
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];
|
|
|
|
Common::strlcpy(sndfile, _vm->_game->_script->readString(9), 10);
|
|
|
|
if (type == SOUND_ADL)
|
|
strcat(sndfile, ".ADL");
|
|
else
|
|
strcat(sndfile, ".SND");
|
|
|
|
int32 dataSize;
|
|
byte *dataPtr = _vm->_dataIO->getFile(sndfile, dataSize);
|
|
if (!dataPtr)
|
|
return 0;
|
|
|
|
if (!sample->load(type, dataPtr, dataSize)) {
|
|
delete[] dataPtr;
|
|
return 0;
|
|
}
|
|
|
|
sample->_id = id;
|
|
return slot | slotIdMask;
|
|
}
|
|
|
|
Resource *resource = _vm->_game->_resources->getResource(id);
|
|
if (!resource)
|
|
return 0;
|
|
|
|
if (!sample->load(type, resource)) {
|
|
delete resource;
|
|
return 0;
|
|
}
|
|
|
|
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
|