mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-15 14:28:28 +00:00
64043ff1fc
logic misinterpretation. I assume these were added for readability, but (a) names suggestet that they're class variables but they didn't (b) their use wasn't consistent, i.e. there were places where variables were used directly, not by means of the macros (c) they didn't save that much space because they are used in few places. svn-id: r15179
2131 lines
46 KiB
C++
2131 lines
46 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2001 Ludvig Strigeus
|
|
* Copyright (C) 2001-2004 The ScummVM project
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* $Header$
|
|
*
|
|
*/
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "common/config-manager.h"
|
|
|
|
#include "scumm/actor.h"
|
|
#include "scumm/charset.h"
|
|
#include "scumm/intern.h"
|
|
#include "scumm/object.h"
|
|
#include "scumm/resource.h"
|
|
#include "scumm/resource_v7he.h"
|
|
#include "scumm/scumm.h"
|
|
#include "scumm/sound.h"
|
|
#include "scumm/verbs.h"
|
|
|
|
#include "sound/mididrv.h"
|
|
#include "sound/mixer.h"
|
|
|
|
namespace Scumm {
|
|
|
|
#define OPCODE(x) { &ScummEngine_v72he::x, #x }
|
|
|
|
void ScummEngine_v72he::setupOpcodes() {
|
|
static const OpcodeEntryV72he opcodes[256] = {
|
|
/* 00 */
|
|
OPCODE(o6_pushByte),
|
|
OPCODE(o6_pushWord),
|
|
OPCODE(o72_pushDWord),
|
|
OPCODE(o6_pushWordVar),
|
|
/* 04 */
|
|
OPCODE(o72_addMessageToStack),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o72_wordArrayRead),
|
|
/* 08 */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o72_wordArrayIndexedRead),
|
|
/* 0C */
|
|
OPCODE(o6_dup),
|
|
OPCODE(o6_not),
|
|
OPCODE(o6_eq),
|
|
OPCODE(o6_neq),
|
|
/* 10 */
|
|
OPCODE(o6_gt),
|
|
OPCODE(o6_lt),
|
|
OPCODE(o6_le),
|
|
OPCODE(o6_ge),
|
|
/* 14 */
|
|
OPCODE(o6_add),
|
|
OPCODE(o6_sub),
|
|
OPCODE(o6_mul),
|
|
OPCODE(o6_div),
|
|
/* 18 */
|
|
OPCODE(o6_land),
|
|
OPCODE(o6_lor),
|
|
OPCODE(o6_pop),
|
|
OPCODE(o72_isAnyOf),
|
|
/* 1C */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
/* 20 */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
/* 24 */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
/* 28 */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
/* 2C */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
/* 30 */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
/* 34 */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
/* 38 */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
/* 3C */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
/* 40 */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_writeWordVar),
|
|
/* 44 */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o72_wordArrayWrite),
|
|
/* 48 */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o72_wordArrayIndexedWrite),
|
|
/* 4C */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_wordVarInc),
|
|
/* 50 */
|
|
OPCODE(o72_unknown50),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o72_findObjectWithClassOf),
|
|
OPCODE(o72_wordArrayInc),
|
|
/* 54 */
|
|
OPCODE(o72_objectX),
|
|
OPCODE(o72_objectY),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_wordVarDec),
|
|
/* 58 */
|
|
OPCODE(o72_getTimer),
|
|
OPCODE(o72_setTimer),
|
|
OPCODE(o72_unknown5A),
|
|
OPCODE(o72_wordArrayDec),
|
|
/* 5C */
|
|
OPCODE(o6_if),
|
|
OPCODE(o6_ifNot),
|
|
OPCODE(o72_startScript),
|
|
OPCODE(o6_startScriptQuick),
|
|
/* 60 */
|
|
OPCODE(o72_startObject),
|
|
OPCODE(o72_drawObject),
|
|
OPCODE(o72_printWizImage),
|
|
OPCODE(o72_getArrayDimSize),
|
|
/* 64 */
|
|
OPCODE(o72_getNumFreeArrays),
|
|
OPCODE(o6_stopObjectCode),
|
|
OPCODE(o6_stopObjectCode),
|
|
OPCODE(o6_endCutscene),
|
|
/* 68 */
|
|
OPCODE(o6_cutscene),
|
|
OPCODE(o6_stopMusic),
|
|
OPCODE(o6_freezeUnfreeze),
|
|
OPCODE(o6_cursorCommand),
|
|
/* 6C */
|
|
OPCODE(o6_breakHere),
|
|
OPCODE(o6_ifClassOfIs),
|
|
OPCODE(o6_setClass),
|
|
OPCODE(o6_getState),
|
|
/* 70 */
|
|
OPCODE(o6he_setState),
|
|
OPCODE(o6_setOwner),
|
|
OPCODE(o6_getOwner),
|
|
OPCODE(o6_jump),
|
|
/* 74 */
|
|
OPCODE(o70he_startSound),
|
|
OPCODE(o6_stopSound),
|
|
OPCODE(o6_startMusic),
|
|
OPCODE(o6_stopObjectScript),
|
|
/* 78 */
|
|
OPCODE(o6_panCameraTo),
|
|
OPCODE(o6_actorFollowCamera),
|
|
OPCODE(o6_setCameraAt),
|
|
OPCODE(o6_loadRoom),
|
|
/* 7C */
|
|
OPCODE(o6_stopScript),
|
|
OPCODE(o6_walkActorToObj),
|
|
OPCODE(o6_walkActorTo),
|
|
OPCODE(o6_putActorAtXY),
|
|
/* 80 */
|
|
OPCODE(o6_putActorAtObject),
|
|
OPCODE(o6_faceActor),
|
|
OPCODE(o6_animateActor),
|
|
OPCODE(o6_doSentence),
|
|
/* 84 */
|
|
OPCODE(o70he_pickupObject),
|
|
OPCODE(o6_loadRoomWithEgo),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_getRandomNumber),
|
|
/* 88 */
|
|
OPCODE(o6_getRandomNumberRange),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_getActorMoving),
|
|
OPCODE(o6_isScriptRunning),
|
|
/* 8C */
|
|
OPCODE(o70he_getActorRoom),
|
|
OPCODE(o6_getObjectX),
|
|
OPCODE(o6_getObjectY),
|
|
OPCODE(o6_getObjectOldDir),
|
|
/* 90 */
|
|
OPCODE(o6_getActorWalkBox),
|
|
OPCODE(o6_getActorCostume),
|
|
OPCODE(o6_findInventory),
|
|
OPCODE(o6_getInventoryCount),
|
|
/* 94 */
|
|
OPCODE(o6_getVerbFromXY),
|
|
OPCODE(o6_beginOverride),
|
|
OPCODE(o6_endOverride),
|
|
OPCODE(o6_setObjectName),
|
|
/* 98 */
|
|
OPCODE(o6_isSoundRunning),
|
|
OPCODE(o6_setBoxFlags),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o70he_resourceRoutines),
|
|
/* 9C */
|
|
OPCODE(o6he_roomOps),
|
|
OPCODE(o72_actorOps),
|
|
OPCODE(o72_verbOps),
|
|
OPCODE(o6_getActorFromXY),
|
|
/* A0 */
|
|
OPCODE(o72_findObject),
|
|
OPCODE(o6_pseudoRoom),
|
|
OPCODE(o6_getActorElevation),
|
|
OPCODE(o6_getVerbEntrypoint),
|
|
/* A4 */
|
|
OPCODE(o72_arrayOps),
|
|
OPCODE(o6_saveRestoreVerbs),
|
|
OPCODE(o6_drawBox),
|
|
OPCODE(o6_pop),
|
|
/* A8 */
|
|
OPCODE(o6_getActorWidth),
|
|
OPCODE(o6he_wait),
|
|
OPCODE(o6_getActorScaleX),
|
|
OPCODE(o6_getActorAnimCounter1),
|
|
/* AC */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_isAnyOf),
|
|
OPCODE(o70he_quitPauseRestart),
|
|
OPCODE(o6_isActorInBox),
|
|
/* B0 */
|
|
OPCODE(o6_delay),
|
|
OPCODE(o6_delaySeconds),
|
|
OPCODE(o6_delayMinutes),
|
|
OPCODE(o6_stopSentence),
|
|
/* B4 */
|
|
OPCODE(o6_printLine),
|
|
OPCODE(o6_printCursor),
|
|
OPCODE(o6_printDebug),
|
|
OPCODE(o6_printSystem),
|
|
/* B8 */
|
|
OPCODE(o6_printActor),
|
|
OPCODE(o6_printEgo),
|
|
OPCODE(o6_talkActor),
|
|
OPCODE(o6_talkEgo),
|
|
/* BC */
|
|
OPCODE(o72_dimArray),
|
|
OPCODE(o6_stopObjectCode),
|
|
OPCODE(o6_startObjectQuick),
|
|
OPCODE(o6_startScriptQuick2),
|
|
/* C0 */
|
|
OPCODE(o72_dim2dimArray),
|
|
OPCODE(o72_unknownC1),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
/* C4 */
|
|
OPCODE(o6_abs),
|
|
OPCODE(o6_distObjectObject),
|
|
OPCODE(o6_distObjectPt),
|
|
OPCODE(o6_distPtPt),
|
|
/* C8 */
|
|
OPCODE(o6he_kernelGetFunctions),
|
|
OPCODE(o70he_kernelSetFunctions),
|
|
OPCODE(o6_delayFrames),
|
|
OPCODE(o6_pickOneOf),
|
|
/* CC */
|
|
OPCODE(o6_pickOneOfDefault),
|
|
OPCODE(o6_stampObject),
|
|
OPCODE(o72_drawWizImage),
|
|
OPCODE(o72_unknownCF),
|
|
/* D0 */
|
|
OPCODE(o6_getDateTime),
|
|
OPCODE(o6_stopTalking),
|
|
OPCODE(o6_getAnimateVariable),
|
|
OPCODE(o6_invalid),
|
|
/* D4 */
|
|
OPCODE(o72_shuffle),
|
|
OPCODE(o72_jumpToScript),
|
|
OPCODE(o6_band),
|
|
OPCODE(o6_bor),
|
|
/* D8 */
|
|
OPCODE(o6_isRoomScriptRunning),
|
|
OPCODE(o6he_closeFile),
|
|
OPCODE(o72_openFile),
|
|
OPCODE(o72_readFile),
|
|
/* DC */
|
|
OPCODE(o72_writeFile),
|
|
OPCODE(o72_findAllObjects),
|
|
OPCODE(o72_deleteFile),
|
|
OPCODE(o6he_rename),
|
|
/* E0 */
|
|
OPCODE(o6he_soundOps),
|
|
OPCODE(o72_getPixel),
|
|
OPCODE(o6he_localizeArray),
|
|
OPCODE(o72_pickVarRandom),
|
|
/* E4 */
|
|
OPCODE(o6_setBoxSet),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
/* E8 */
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6he_seekFilePos),
|
|
OPCODE(o72_redimArray),
|
|
OPCODE(o6he_readFilePos),
|
|
/* EC */
|
|
OPCODE(o72_unknownEC),
|
|
OPCODE(o72_unknownED),
|
|
OPCODE(o70he_stringLen),
|
|
OPCODE(o72_unknownEF),
|
|
/* F0 */
|
|
OPCODE(o72_unknownF0),
|
|
OPCODE(o72_unknownF1),
|
|
OPCODE(o72_checkGlobQueue),
|
|
OPCODE(o72_readINI),
|
|
/* F4 */
|
|
OPCODE(o72_writeINI),
|
|
OPCODE(o72_unknownF5),
|
|
OPCODE(o72_unknownF6),
|
|
OPCODE(o6_invalid),
|
|
/* F8 */
|
|
OPCODE(o72_unknownF8),
|
|
OPCODE(o72_setFilePath),
|
|
OPCODE(o72_unknownFA),
|
|
OPCODE(o70he_polygonOps),
|
|
/* FC */
|
|
OPCODE(o70he_polygonHit),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
OPCODE(o6_invalid),
|
|
};
|
|
|
|
_opcodesV72he = opcodes;
|
|
}
|
|
|
|
void ScummEngine_v72he::executeOpcode(byte i) {
|
|
OpcodeProcV72he op = _opcodesV72he[i].proc;
|
|
(this->*op) ();
|
|
}
|
|
|
|
const char *ScummEngine_v72he::getOpcodeDesc(byte i) {
|
|
return _opcodesV72he[i].desc;
|
|
}
|
|
|
|
static int arrayDataSizes[] = {0, 1, 4, 8, 8, 16, 32};
|
|
|
|
ScummEngine_v72he::ArrayHeader *ScummEngine_v72he::defineArray(int array, int type, int dim2start, int dim2end,
|
|
int dim1start, int dim1end) {
|
|
int id;
|
|
int size;
|
|
ArrayHeader *ah;
|
|
|
|
assert(dim2start >= 0 && dim2start <= dim2end);
|
|
assert(dim1start >= 0 && dim1start <= dim1end);
|
|
assert(0 <= type && type <= 6);
|
|
|
|
|
|
if (type == kBitArray || type == kNibbleArray)
|
|
type = kByteArray;
|
|
|
|
nukeArray(array);
|
|
|
|
id = findFreeArrayId();
|
|
|
|
debug(5,"defineArray (array %d, dim2start %d, dim2end %d dim1start %d dim1end %d", id, dim2start, dim2end, dim1start, dim1end);
|
|
|
|
if (array & 0x80000000) {
|
|
error("Can't define bit variable as array pointer");
|
|
}
|
|
|
|
size = arrayDataSizes[type];
|
|
|
|
writeVar(array, id);
|
|
|
|
size *= dim2end - dim2start + 1;
|
|
size *= dim1end - dim1start + 1;
|
|
size >>= 3;
|
|
|
|
ah = (ArrayHeader *)createResource(rtString, id, size + sizeof(ArrayHeader));
|
|
|
|
ah->type = TO_LE_32(type);
|
|
ah->dim1start = TO_LE_32(dim1start);
|
|
ah->dim1end = TO_LE_32(dim1end);
|
|
ah->dim2start = TO_LE_32(dim2start);
|
|
ah->dim2end = TO_LE_32(dim2end);
|
|
|
|
return ah;
|
|
}
|
|
|
|
int ScummEngine_v72he::readArray(int array, int idx2, int idx1) {
|
|
debug(5, "readArray (array %d, idx2 %d, idx1 %d)", readVar(array), idx2, idx1);
|
|
|
|
if (readVar(array) == 0)
|
|
error("readArray: Reference to zeroed array pointer");
|
|
|
|
ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
|
|
|
|
if (ah == NULL || ah->data == NULL)
|
|
error("readArray: invalid array %d (%d)", array, readVar(array));
|
|
|
|
if (idx2 < (int)FROM_LE_32(ah->dim2start) || idx2 > (int)FROM_LE_32(ah->dim2end) ||
|
|
idx1 < (int)FROM_LE_32(ah->dim1start) || idx1 > (int)FROM_LE_32(ah->dim1end)) {
|
|
error("readArray: array %d out of bounds: [%d, %d] exceeds [%d..%d, %d..%d]",
|
|
array, idx1, idx2, FROM_LE_32(ah->dim1start), FROM_LE_32(ah->dim1end),
|
|
FROM_LE_32(ah->dim2start), FROM_LE_32(ah->dim2end));
|
|
}
|
|
|
|
const int offset = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
|
|
(idx2 - FROM_LE_32(ah->dim2start)) - FROM_LE_32(ah->dim1start) + idx1;
|
|
|
|
switch (FROM_LE_32(ah->type)) {
|
|
case kByteArray:
|
|
case kStringArray:
|
|
return ah->data[offset];
|
|
|
|
case kIntArray:
|
|
return (int16)READ_LE_UINT16(ah->data + offset * 2);
|
|
|
|
case kDwordArray:
|
|
return (int32)READ_LE_UINT32(ah->data + offset * 4);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ScummEngine_v72he::writeArray(int array, int idx2, int idx1, int value) {
|
|
debug(5, "writeArray (array %d, idx2 %d, idx1 %d, value %d)", readVar(array), idx2, idx1, value);
|
|
|
|
if (readVar(array) == 0)
|
|
error("writeArray: Reference to zeroed array pointer");
|
|
|
|
ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array));
|
|
|
|
if (!ah)
|
|
error("writeArray: Invalid array (%d) reference", readVar(array));
|
|
|
|
if (idx2 < (int)FROM_LE_32(ah->dim2start) || idx2 > (int)FROM_LE_32(ah->dim2end) ||
|
|
idx1 < (int)FROM_LE_32(ah->dim1start) || idx1 > (int)FROM_LE_32(ah->dim1end)) {
|
|
error("writeArray: array %d out of bounds: [%d, %d] exceeds [%d..%d, %d..%d]",
|
|
array, idx1, idx2, FROM_LE_32(ah->dim1start), FROM_LE_32(ah->dim1end),
|
|
FROM_LE_32(ah->dim2start), FROM_LE_32(ah->dim2end));
|
|
}
|
|
|
|
const int offset = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
|
|
(idx2 - FROM_LE_32(ah->dim2start)) - FROM_LE_32(ah->dim1start) + idx1;
|
|
|
|
switch (FROM_LE_32(ah->type)) {
|
|
case kByteArray:
|
|
case kStringArray:
|
|
ah->data[offset] = value;
|
|
break;
|
|
|
|
case kIntArray:
|
|
WRITE_LE_UINT16(ah->data + offset * 2, value);
|
|
break;
|
|
|
|
case kDwordArray:
|
|
WRITE_LE_UINT32(ah->data + offset * 4, value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::readArrayFromIndexFile() {
|
|
int num;
|
|
int a, b, c;
|
|
|
|
while ((num = _fileHandle.readUint16LE()) != 0) {
|
|
a = _fileHandle.readUint16LE();
|
|
b = _fileHandle.readUint16LE();
|
|
c = _fileHandle.readUint16LE();
|
|
|
|
if (c == 1)
|
|
defineArray(num, kBitArray, 0, a, 0, b);
|
|
else
|
|
defineArray(num, kDwordArray, 0, a, 0, b);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::arrrays_unk2(int dst, int src, int len2, int len) {
|
|
int edi, value;
|
|
int i = 0;
|
|
|
|
if (len == -1) {
|
|
len = resStrLen(getStringAddress(src));
|
|
len2 = 0;
|
|
}
|
|
|
|
edi = resStrLen(getStringAddress(dst));
|
|
|
|
len -= len2;
|
|
len++;
|
|
|
|
while (i < len) {
|
|
writeVar(0, src);
|
|
value = readArray(0, 0, len2 + i);
|
|
writeVar(0, dst);
|
|
writeArray(0, 0, edi + i, value);
|
|
i++;
|
|
}
|
|
|
|
writeArray(0, 0, edi + i, 0);
|
|
}
|
|
|
|
void ScummEngine_v72he::copyScriptString(byte *dst) {
|
|
int i = 0;
|
|
byte b;
|
|
|
|
int array = pop();
|
|
if (array == -1) {
|
|
int len = resStrLen(_stringBuffer) + 1;
|
|
while (len--)
|
|
*dst++ = _stringBuffer[i++];
|
|
} else {
|
|
writeVar(0, array);
|
|
while ((b = readArray(0, 0, i)) != 0) {
|
|
*dst++ = b;
|
|
i++;
|
|
}
|
|
}
|
|
*dst = 0;
|
|
}
|
|
|
|
void ScummEngine_v72he::decodeScriptString(byte *dst, bool scriptString) {
|
|
int args[31];
|
|
int num = 0, val = 0;
|
|
int len;
|
|
byte chr, string[256];
|
|
memset(string, 0, sizeof(string));
|
|
|
|
getStackList(args, ARRAYSIZE(args));
|
|
int id = pop();
|
|
|
|
if (scriptString) {
|
|
addMessageToStack(_scriptPointer, string, sizeof(string));
|
|
len = resStrLen(_scriptPointer);
|
|
_scriptPointer += len + 1;
|
|
} else {
|
|
copyScriptString(string);
|
|
len = resStrLen(string) + 1;
|
|
}
|
|
|
|
while (len--) {
|
|
chr = string[num++];
|
|
if (chr == '%') {
|
|
chr = string[num++];
|
|
if (chr == 'd') {
|
|
dst += snprintf((char *)dst, 10, "%d", args[val++]);
|
|
continue;
|
|
} else if (chr == 's') {
|
|
dst += addStringToStack(dst, 512, id++);
|
|
continue;
|
|
}
|
|
}
|
|
*dst++ = chr;
|
|
}
|
|
*dst = 0;
|
|
}
|
|
|
|
int ScummEngine_v72he::findObject(int x, int y, int *args) {
|
|
int i, b;
|
|
byte a;
|
|
const int mask = 0xF;
|
|
|
|
for (i = 1; i < _numLocalObjects; i++) {
|
|
if ((_objs[i].obj_nr < 1) || getClass(_objs[i].obj_nr, kObjectClassUntouchable))
|
|
continue;
|
|
|
|
if (polygonDefined(_objs[i].obj_nr))
|
|
if (polygonHit(_objs[i].obj_nr, x, y) != 0)
|
|
return _objs[i].obj_nr;
|
|
|
|
//if (VAR(VAR_POLYGONS_ONLY))
|
|
// continue;
|
|
|
|
b = i;
|
|
do {
|
|
a = _objs[b].parentstate;
|
|
b = _objs[b].parent;
|
|
if (b == 0) {
|
|
if (_objs[i].x_pos <= x && _objs[i].width + _objs[i].x_pos > x &&
|
|
_objs[i].y_pos <= y && _objs[i].height + _objs[i].y_pos > y)
|
|
return _objs[i].obj_nr;
|
|
break;
|
|
}
|
|
} while ((_objs[b].state & mask) == a);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
const byte *ScummEngine_v72he::findWrappedBlock(uint32 tag, const byte *ptr, int state, bool errorFlag) {
|
|
if (READ_UINT32(ptr) == MKID('MULT')) {
|
|
error("findWrappedBlock: multi blocks aren't implemented");
|
|
} else {
|
|
return findResourceData(tag, ptr);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_pushDWord() {
|
|
int a;
|
|
if (*_lastCodePtr + sizeof(MemBlkHeader) != _scriptOrgPointer) {
|
|
uint32 oldoffs = _scriptPointer - _scriptOrgPointer;
|
|
getScriptBaseAddress();
|
|
_scriptPointer = _scriptOrgPointer + oldoffs;
|
|
}
|
|
a = READ_LE_UINT32(_scriptPointer);
|
|
_scriptPointer += 4;
|
|
push(a);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_addMessageToStack() {
|
|
_stringLength = resStrLen(_scriptPointer) + 1;
|
|
addMessageToStack(_scriptPointer, _stringBuffer, _stringLength);
|
|
|
|
debug(0,"o72_addMessageToStack(\"%s\")", _scriptPointer);
|
|
|
|
_scriptPointer += _stringLength;
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_wordArrayRead() {
|
|
int base = pop();
|
|
push(readArray(fetchScriptWord(), 0, base));
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_wordArrayIndexedRead() {
|
|
int base = pop();
|
|
int idx = pop();
|
|
push(readArray(fetchScriptWord(), idx, base));
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_isAnyOf() {
|
|
int args[128], i = 0;
|
|
int num = getStackList(args, ARRAYSIZE(args));
|
|
int value = pop();
|
|
|
|
while (i < num) {
|
|
if (args[i] == value) {
|
|
push(1);
|
|
return;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
push(0);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_wordArrayWrite() {
|
|
int a = pop();
|
|
writeArray(fetchScriptWord(), 0, pop(), a);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_wordArrayIndexedWrite() {
|
|
int val = pop();
|
|
int base = pop();
|
|
writeArray(fetchScriptWord(), pop(), base, val);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknown50() {
|
|
int idx;
|
|
|
|
idx = vm.cutSceneStackPointer;
|
|
vm.cutSceneStackPointer = 0;
|
|
vm.cutScenePtr[idx] = 0;
|
|
vm.cutSceneScript[idx] = 0;
|
|
|
|
VAR(VAR_OVERRIDE) = 0;
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_findObjectWithClassOf() {
|
|
int args[16];
|
|
|
|
getStackList(args, ARRAYSIZE(args));
|
|
int y = pop();
|
|
int x = pop();
|
|
int r = findObject(x, y, args);
|
|
push(r);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_wordArrayInc() {
|
|
int var = fetchScriptWord();
|
|
int base = pop();
|
|
writeArray(var, 0, base, readArray(var, 0, base) + 1);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_objectX() {
|
|
int object = pop();
|
|
int objnum = getObjectIndex(object);
|
|
|
|
if (objnum == -1) {
|
|
push(0);
|
|
return;
|
|
}
|
|
|
|
push(_objs[objnum].x_pos);
|
|
}
|
|
|
|
|
|
void ScummEngine_v72he::o72_objectY() {
|
|
int object = pop();
|
|
int objnum = getObjectIndex(object);
|
|
|
|
if (objnum == -1) {
|
|
push(0);
|
|
return;
|
|
}
|
|
|
|
push(_objs[objnum].y_pos);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_getTimer() {
|
|
int timer = pop();
|
|
int cmd = fetchScriptByte();
|
|
|
|
if (cmd == 10) {
|
|
checkRange(3, 1, timer, "o72_getTimer: Timer %d out of range(%d)");
|
|
int diff = _system->get_msecs() - _timers[timer];
|
|
push(diff);
|
|
} else {
|
|
push(0);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_setTimer() {
|
|
int timer = pop();
|
|
int cmd = fetchScriptByte();
|
|
|
|
if (cmd == 158) {
|
|
checkRange(3, 1, timer, "o72_setTimer: Timer %d out of range(%d)");
|
|
_timers[timer] = _system->get_msecs();
|
|
} else {
|
|
error("TIMER command %d?", cmd);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknown5A() {
|
|
// Seems to get length of sound already played
|
|
int snd = pop();
|
|
int r = _mixer->getChannelElapsedTime(_sound->_musicChannelHandle);
|
|
|
|
push(r * 10);
|
|
debug(1,"o72_unknown5A stub (%d)", snd);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_wordArrayDec() {
|
|
int var = fetchScriptWord();
|
|
int base = pop();
|
|
writeArray(var, 0, base, readArray(var, 0, base) - 1);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_startScript() {
|
|
int args[16];
|
|
int script, flags;
|
|
|
|
getStackList(args, ARRAYSIZE(args));
|
|
script = pop();
|
|
flags = fetchScriptByte();
|
|
|
|
runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_startObject() {
|
|
int args[16];
|
|
int script, entryp;
|
|
int flags;
|
|
getStackList(args, ARRAYSIZE(args));
|
|
entryp = pop();
|
|
script = pop();
|
|
flags = fetchScriptByte();
|
|
runObjectScript(script, entryp, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_drawObject() {
|
|
int subOp = fetchScriptByte();
|
|
int state = 0, y = -1, x = -1;
|
|
|
|
switch (subOp) {
|
|
case 62:
|
|
state = pop();
|
|
y = pop();
|
|
x = pop();
|
|
break;
|
|
case 63:
|
|
state = pop();
|
|
if (state == 0)
|
|
state = 1;
|
|
break;
|
|
case 65:
|
|
state = 1;
|
|
y = pop();
|
|
x = pop();
|
|
break;
|
|
default:
|
|
error("o72_drawObject: default case %d", subOp);
|
|
}
|
|
|
|
int object = pop();
|
|
int objnum = getObjectIndex(object);
|
|
if (objnum == -1)
|
|
return;
|
|
|
|
if (y != -1 && x != -1) {
|
|
_objs[objnum].x_pos = x * 8;
|
|
_objs[objnum].y_pos = y * 8;
|
|
}
|
|
|
|
if (state != -1) {
|
|
addObjectToDrawQue(objnum);
|
|
putState(object, state);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_printWizImage() {
|
|
int resnum = pop();
|
|
drawWizImage(rtImage, resnum, 0, 0, 0, 4);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_getArrayDimSize() {
|
|
int subOp = fetchScriptByte();
|
|
int32 val1, val2;
|
|
ArrayHeader *ah;
|
|
|
|
switch (subOp) {
|
|
case 1:
|
|
case 3:
|
|
ah = (ArrayHeader *)getResourceAddress(rtString, readVar(fetchScriptWord()));
|
|
val1 = FROM_LE_32(ah->dim1end);
|
|
val2 = FROM_LE_32(ah->dim1start);
|
|
push(val1 - val2 + 1);
|
|
break;
|
|
case 2:
|
|
ah = (ArrayHeader *)getResourceAddress(rtString, readVar(fetchScriptWord()));
|
|
val1 = FROM_LE_32(ah->dim2end);
|
|
val2 = FROM_LE_32(ah->dim2start);
|
|
push(val1 - val2 + 1);
|
|
break;
|
|
default:
|
|
error("o72_getArrayDimSize: default case %d", subOp);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_getNumFreeArrays() {
|
|
byte **addr = res.address[rtString];
|
|
int i, num = 0;
|
|
|
|
for (i = 1; i < _numArray; i++) {
|
|
if (!addr[i])
|
|
num++;
|
|
}
|
|
|
|
push (num);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_actorOps() {
|
|
Actor *a;
|
|
int i, j, k;
|
|
int args[32];
|
|
byte b;
|
|
byte name[256];
|
|
|
|
b = fetchScriptByte();
|
|
if (b == 197) {
|
|
_curActor = pop();
|
|
return;
|
|
}
|
|
|
|
a = derefActorSafe(_curActor, "o6he_actorOps");
|
|
if (!a)
|
|
return;
|
|
|
|
switch (b) {
|
|
case 21: // HE 80+
|
|
k = getStackList(args, ARRAYSIZE(args));
|
|
for (i = 0; i < k; ++i) {
|
|
a->setUserCondition(args[i] & 0x7F, args[i] & 0x80);
|
|
}
|
|
debug(1,"o72_actorOps: case 21 (%d)", k);
|
|
break;
|
|
case 24: // HE 80+
|
|
k = pop();
|
|
a->talkUnk = 1;
|
|
a->setTalkCondition(k);
|
|
debug(1,"o72_actorOps: case 24 (%d)", k);
|
|
break;
|
|
case 43: // HE 90+
|
|
k = pop();
|
|
debug(1,"o72_actorOps: case 43 (%d)", k);
|
|
break;
|
|
case 64:
|
|
_actorClipOverride.bottom = pop();
|
|
_actorClipOverride.right = pop();
|
|
_actorClipOverride.top = pop();
|
|
_actorClipOverride.left = pop();
|
|
break;
|
|
case 65: // HE 98+
|
|
i = pop();
|
|
j = pop();
|
|
debug(1,"o72_actorOps: case 65 (%d, %d)", i, j);
|
|
break;
|
|
case 68: // HE 90+
|
|
k = pop();
|
|
debug(1,"o72_actorOps: case 68 (%d)", k);
|
|
break;
|
|
case 76: // SO_COSTUME
|
|
a->setActorCostume(pop());
|
|
break;
|
|
case 77: // SO_STEP_DIST
|
|
j = pop();
|
|
i = pop();
|
|
a->setActorWalkSpeed(i, j);
|
|
break;
|
|
case 78: // SO_SOUND
|
|
k = getStackList(args, ARRAYSIZE(args));
|
|
for (i = 0; i < k; i++)
|
|
a->sound[i] = args[i];
|
|
break;
|
|
case 79: // SO_WALK_ANIMATION
|
|
a->walkFrame = pop();
|
|
break;
|
|
case 80: // SO_TALK_ANIMATION
|
|
a->talkStopFrame = pop();
|
|
a->talkStartFrame = pop();
|
|
break;
|
|
case 81: // SO_STAND_ANIMATION
|
|
a->standFrame = pop();
|
|
break;
|
|
case 82: // SO_ANIMATION
|
|
// dummy case in scumm6
|
|
pop();
|
|
pop();
|
|
pop();
|
|
break;
|
|
case 83: // SO_DEFAULT
|
|
a->initActor(0);
|
|
break;
|
|
case 84: // SO_ELEVATION
|
|
a->setElevation(pop());
|
|
break;
|
|
case 85: // SO_ANIMATION_DEFAULT
|
|
a->initFrame = 1;
|
|
a->walkFrame = 2;
|
|
a->standFrame = 3;
|
|
a->talkStartFrame = 4;
|
|
a->talkStopFrame = 5;
|
|
break;
|
|
case 86: // SO_PALETTE
|
|
j = pop();
|
|
i = pop();
|
|
checkRange(255, 0, i, "Illegal palette slot %d");
|
|
a->remapActorPaletteColor(i, j);
|
|
break;
|
|
case 87: // SO_TALK_COLOR
|
|
a->talkColor = pop();
|
|
break;
|
|
case 88: // SO_ACTOR_NAME
|
|
copyScriptString(name);
|
|
loadPtrToResource(rtActorName, a->number, name);
|
|
break;
|
|
case 89: // SO_INIT_ANIMATION
|
|
a->initFrame = pop();
|
|
break;
|
|
case 91: // SO_ACTOR_WIDTH
|
|
a->width = pop();
|
|
break;
|
|
case 92: // SO_SCALE
|
|
i = pop();
|
|
a->setScale(i, i);
|
|
break;
|
|
case 93: // SO_NEVER_ZCLIP
|
|
a->forceClip = 0;
|
|
break;
|
|
case 94: // SO_ALWAYS_ZCLIP
|
|
a->forceClip = pop();
|
|
break;
|
|
case 95: // SO_IGNORE_BOXES
|
|
a->ignoreBoxes = 1;
|
|
a->forceClip = 0;
|
|
if (a->isInCurrentRoom())
|
|
a->putActor(a->_pos.x, a->_pos.y, a->room);
|
|
break;
|
|
case 96: // SO_FOLLOW_BOXES
|
|
a->ignoreBoxes = 0;
|
|
a->forceClip = 0;
|
|
if (a->isInCurrentRoom())
|
|
a->putActor(a->_pos.x, a->_pos.y, a->room);
|
|
break;
|
|
case 97: // SO_ANIMATION_SPEED
|
|
a->setAnimSpeed(pop());
|
|
break;
|
|
case 98: // SO_SHADOW
|
|
a->shadow_mode = pop();
|
|
debug(0, "Set actor XMAP idx to %d\n", a->shadow_mode);
|
|
break;
|
|
case 99: // SO_TEXT_OFFSET
|
|
a->talkPosY = pop();
|
|
a->talkPosX = pop();
|
|
break;
|
|
case 156: // HE 7.2
|
|
a->charset = pop();
|
|
break;
|
|
case 198: // SO_ACTOR_VARIABLE
|
|
i = pop();
|
|
a->setAnimVar(pop(), i);
|
|
break;
|
|
case 215: // SO_ACTOR_IGNORE_TURNS_ON
|
|
a->ignoreTurns = true;
|
|
break;
|
|
case 216: // SO_ACTOR_IGNORE_TURNS_OFF
|
|
a->ignoreTurns = false;
|
|
break;
|
|
case 217: // SO_ACTOR_NEW
|
|
a->initActor(2);
|
|
break;
|
|
case 218:
|
|
{
|
|
int top_actor = a->top;
|
|
int bottom_actor = a->bottom;
|
|
a->drawToBackBuf = true;
|
|
a->needRedraw = true;
|
|
a->drawActorCostume();
|
|
a->drawToBackBuf = false;
|
|
a->needRedraw = true;
|
|
a->drawActorCostume();
|
|
a->needRedraw = false;
|
|
|
|
if (a->top > top_actor)
|
|
a->top = top_actor;
|
|
if (a->bottom < bottom_actor)
|
|
a->bottom = bottom_actor;
|
|
|
|
}
|
|
break;
|
|
case 219:
|
|
a->drawToBackBuf = false;
|
|
a->needRedraw = true;
|
|
a->needBgReset = true;
|
|
break;
|
|
case 225:
|
|
{
|
|
byte string[128];
|
|
copyScriptString(string);
|
|
int slot = pop();
|
|
|
|
int len = resStrLen(string) + 1;
|
|
addMessageToStack(string, _queueTalkString[slot], len);
|
|
|
|
_queueTalkPosX[slot] = a->talkPosX;
|
|
_queueTalkPosY[slot] = a->talkPosY;
|
|
_queueTalkColor[slot] = a->talkColor;
|
|
break;
|
|
}
|
|
default:
|
|
error("o72_actorOps: default case %d", b);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_verbOps() {
|
|
int slot, a, b;
|
|
VerbSlot *vs;
|
|
byte op;
|
|
byte name[200];
|
|
|
|
op = fetchScriptByte();
|
|
if (op == 196) {
|
|
_curVerb = pop();
|
|
_curVerbSlot = getVerbSlot(_curVerb, 0);
|
|
checkRange(_numVerbs - 1, 0, _curVerbSlot, "Illegal new verb slot %d");
|
|
return;
|
|
}
|
|
vs = &_verbs[_curVerbSlot];
|
|
slot = _curVerbSlot;
|
|
switch (op) {
|
|
case 124: // SO_VERB_IMAGE
|
|
a = pop();
|
|
if (_curVerbSlot) {
|
|
setVerbObject(_roomResource, a, slot);
|
|
vs->type = kImageVerbType;
|
|
vs->imgindex = a;
|
|
}
|
|
break;
|
|
case 125: // SO_VERB_NAME
|
|
copyScriptString(name);
|
|
loadPtrToResource(rtVerb, slot, name);
|
|
vs->type = kTextVerbType;
|
|
vs->imgindex = 0;
|
|
break;
|
|
case 126: // SO_VERB_COLOR
|
|
vs->color = pop();
|
|
break;
|
|
case 127: // SO_VERB_HICOLOR
|
|
vs->hicolor = pop();
|
|
break;
|
|
case 128: // SO_VERB_AT
|
|
vs->curRect.top = pop();
|
|
vs->curRect.left = pop();
|
|
break;
|
|
case 129: // SO_VERB_ON
|
|
vs->curmode = 1;
|
|
break;
|
|
case 130: // SO_VERB_OFF
|
|
vs->curmode = 0;
|
|
break;
|
|
case 131: // SO_VERB_DELETE
|
|
slot = getVerbSlot(pop(), 0);
|
|
killVerb(slot);
|
|
break;
|
|
case 132: // SO_VERB_NEW
|
|
slot = getVerbSlot(_curVerb, 0);
|
|
if (slot == 0) {
|
|
for (slot = 1; slot < _numVerbs; slot++) {
|
|
if (_verbs[slot].verbid == 0)
|
|
break;
|
|
}
|
|
if (slot == _numVerbs)
|
|
error("Too many verbs");
|
|
_curVerbSlot = slot;
|
|
}
|
|
vs = &_verbs[slot];
|
|
vs->verbid = _curVerb;
|
|
vs->color = 2;
|
|
vs->hicolor = 0;
|
|
vs->dimcolor = 8;
|
|
vs->type = kTextVerbType;
|
|
vs->charset_nr = _string[0]._default.charset;
|
|
vs->curmode = 0;
|
|
vs->saveid = 0;
|
|
vs->key = 0;
|
|
vs->center = 0;
|
|
vs->imgindex = 0;
|
|
break;
|
|
case 133: // SO_VERB_DIMCOLOR
|
|
vs->dimcolor = pop();
|
|
break;
|
|
case 134: // SO_VERB_DIM
|
|
vs->curmode = 2;
|
|
break;
|
|
case 135: // SO_VERB_KEY
|
|
vs->key = pop();
|
|
break;
|
|
case 136: // SO_VERB_CENTER
|
|
vs->center = 1;
|
|
break;
|
|
case 137: // SO_VERB_NAME_STR
|
|
a = pop();
|
|
if (a == 0) {
|
|
loadPtrToResource(rtVerb, slot, (const byte *)"");
|
|
} else {
|
|
loadPtrToResource(rtVerb, slot, getStringAddress(a));
|
|
}
|
|
vs->type = kTextVerbType;
|
|
vs->imgindex = 0;
|
|
break;
|
|
case 139: // SO_VERB_IMAGE_IN_ROOM
|
|
b = pop();
|
|
a = pop();
|
|
|
|
if (slot && a != vs->imgindex) {
|
|
setVerbObject(b, a, slot);
|
|
vs->type = kImageVerbType;
|
|
vs->imgindex = a;
|
|
}
|
|
break;
|
|
case 140: // SO_VERB_BAKCOLOR
|
|
vs->bkcolor = pop();
|
|
break;
|
|
case 255:
|
|
drawVerb(slot, 0);
|
|
verbMouseOver(0);
|
|
break;
|
|
default:
|
|
error("o72_verbops: default case %d", op);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_findObject() {
|
|
int y = pop();
|
|
int x = pop();
|
|
int r = findObject(x, y, 0);
|
|
push(r);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_arrayOps() {
|
|
byte subOp = fetchScriptByte();
|
|
int array = fetchScriptWord();
|
|
int a, b, c, d;
|
|
int id, len = 0;
|
|
ArrayHeader *ah;
|
|
int list[128];
|
|
byte string[2048];
|
|
|
|
switch (subOp) {
|
|
case 7: // SO_ASSIGN_STRING
|
|
copyScriptString(string);
|
|
len = resStrLen(string) + 1;
|
|
ah = defineArray(array, kStringArray, 0, 0, 0, len);
|
|
memcpy(ah->data, string, len);
|
|
break;
|
|
|
|
case 126:
|
|
len = getStackList(list, ARRAYSIZE(list));
|
|
a = pop();
|
|
b = pop();
|
|
c = pop();
|
|
d = pop();
|
|
id = readVar(array);
|
|
if (id == 0) {
|
|
defineArray(array, kDwordArray, d, c, b, a);
|
|
}
|
|
// TODO write array
|
|
break;
|
|
case 127:
|
|
// TODO
|
|
fetchScriptWord();
|
|
pop();
|
|
pop();
|
|
pop();
|
|
pop();
|
|
pop();
|
|
pop();
|
|
pop();
|
|
pop();
|
|
break;
|
|
case 128:
|
|
a = pop();
|
|
b = pop();
|
|
c = pop();
|
|
d = pop();
|
|
id = readVar(array);
|
|
if (id == 0) {
|
|
defineArray(array, kDwordArray, d, c, b, a);
|
|
}
|
|
// TODO write array
|
|
break;
|
|
case 194: // SO_ASSIGN_STRING
|
|
decodeScriptString(string);
|
|
len = resStrLen(string) + 1;
|
|
ah = defineArray(array, kStringArray, 0, 0, 0, len);
|
|
memcpy(ah->data, string, len);
|
|
break;
|
|
case 208: // SO_ASSIGN_INT_LIST
|
|
b = pop();
|
|
c = pop();
|
|
id = readVar(array);
|
|
if (id == 0) {
|
|
defineArray(array, kDwordArray, 0, 0, 0, b + c);
|
|
}
|
|
while (c--) {
|
|
writeArray(array, 0, b + c, pop());
|
|
}
|
|
break;
|
|
case 212: // SO_ASSIGN_2DIM_LIST
|
|
len = getStackList(list, ARRAYSIZE(list));
|
|
id = readVar(array);
|
|
if (id == 0)
|
|
error("Must DIM a two dimensional array before assigning");
|
|
c = pop();
|
|
while (--len >= 0) {
|
|
writeArray(array, c, len, list[len]);
|
|
}
|
|
break;
|
|
default:
|
|
error("o72_arrayOps: default case %d (array %d)", subOp, array);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_dimArray() {
|
|
int data;
|
|
int type = fetchScriptByte();
|
|
|
|
switch (type) {
|
|
case 2: // SO_BIT_ARRAY
|
|
data = kBitArray;
|
|
break;
|
|
case 3: // SO_NIBBLE_ARRAY
|
|
data = kNibbleArray;
|
|
break;
|
|
case 4: // SO_BYTE_ARRAY
|
|
data = kByteArray;
|
|
break;
|
|
case 5: // SO_INT_ARRAY
|
|
data = kIntArray;
|
|
break;
|
|
case 6:
|
|
data = kDwordArray;
|
|
break;
|
|
case 7: // SO_STRING_ARRAY
|
|
data = kStringArray;
|
|
break;
|
|
case 204: // SO_UNDIM_ARRAY
|
|
nukeArray(fetchScriptWord());
|
|
return;
|
|
default:
|
|
error("o72_dimArray: default case %d", type);
|
|
}
|
|
|
|
defineArray(fetchScriptWord(), data, 0, 0, 0, pop());
|
|
}
|
|
|
|
|
|
void ScummEngine_v72he::o72_dim2dimArray() {
|
|
int a, b, data;
|
|
int type = fetchScriptByte();
|
|
switch (type) {
|
|
case 2: // SO_BIT_ARRAY
|
|
data = kBitArray;
|
|
break;
|
|
case 3: // SO_NIBBLE_ARRAY
|
|
data = kNibbleArray;
|
|
break;
|
|
case 4: // SO_BYTE_ARRAY
|
|
data = kByteArray;
|
|
break;
|
|
case 5: // SO_INT_ARRAY
|
|
data = kIntArray;
|
|
break;
|
|
case 6:
|
|
data = kDwordArray;
|
|
break;
|
|
case 7: // SO_STRING_ARRAY
|
|
data = kStringArray;
|
|
break;
|
|
default:
|
|
error("o72_dim2dimArray: default case %d", type);
|
|
}
|
|
|
|
b = pop();
|
|
a = pop();
|
|
defineArray(fetchScriptWord(), data, 0, a, 0, b);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknownC1() {
|
|
byte string[80];
|
|
|
|
copyScriptString(string);
|
|
pop();
|
|
|
|
//debug(1, "stub o72_unknownC1(%s)", string);
|
|
}
|
|
|
|
void ScummEngine_v72he::drawWizImage(int restype, int resnum, int state, int x1, int y1, int flags) {
|
|
if (flags & 64)
|
|
error("Polygon Wiz image is unimplemented");
|
|
|
|
const uint8 *dataPtr = getResourceAddress(restype, resnum);
|
|
if (dataPtr) {
|
|
const uint8 *wizh = findWrappedBlock(MKID('WIZH'), dataPtr, state, 0);
|
|
assert(wizh);
|
|
uint32 comp = READ_LE_UINT32(wizh + 0x0);
|
|
uint32 width = READ_LE_UINT32(wizh + 0x4);
|
|
uint32 height = READ_LE_UINT32(wizh + 0x8);
|
|
if (comp != 1) {
|
|
warning("%d has invalid compression type %d", resnum, comp);
|
|
}
|
|
const uint8 *wizd = findWrappedBlock(MKID('WIZD'), dataPtr, state, 0);
|
|
assert(wizd);
|
|
if (flags & 1) {
|
|
const uint8 *pal = findWrappedBlock(MKID('RGBS'), dataPtr, state, 0);
|
|
assert(pal);
|
|
setPaletteFromPtr(pal, 256);
|
|
}
|
|
if (flags & 2) {
|
|
warning("unhandled Wiz image w/ rmap palette");
|
|
}
|
|
if (flags & 4) {
|
|
warning("printing Wiz image is unimplemented");
|
|
return;
|
|
}
|
|
|
|
uint8 *dst = 0;
|
|
if (flags & 0x24) { // printing (0x4) or rendering to memory (0x20)
|
|
dst = (uint8 *)malloc(width * height);
|
|
memset(dst, 255, width * height); // make transparent
|
|
|
|
if (flags & 0x20) {
|
|
// copy width * height bytes from VAR_117 to dst
|
|
|
|
// FIXME: dirty hack until missing bits are implemented
|
|
Common::Rect rScreen(0, 0, width-1, height-1);
|
|
gdi.copyWizImage(dst, wizd, width, height, 0, 0, width, height, &rScreen);
|
|
setCursorFromBuffer(dst, width, height, width);
|
|
free(dst);
|
|
return;
|
|
}
|
|
}
|
|
|
|
VirtScreen *pvs = &virtscr[kMainVirtScreen];
|
|
if (flags & 0x10) {
|
|
dst = pvs->getPixels(0, pvs->topline);
|
|
} else if (!(flags & 0x20)) {
|
|
dst = pvs->getBackPixels(0, pvs->topline);
|
|
}
|
|
Common::Rect rScreen(0, 0, pvs->w, pvs->h);
|
|
gdi.copyWizImage(dst, wizd, pvs->w, pvs->h, x1, y1, width, height, &rScreen);
|
|
|
|
Common::Rect rImage(x1, y1, x1 + width, y1 + height);
|
|
if (rImage.intersects(rScreen)) {
|
|
rImage.clip(rScreen);
|
|
if (flags & 0x18) {
|
|
++rImage.bottom;
|
|
markRectAsDirty(kMainVirtScreen, rImage);
|
|
} else {
|
|
--rImage.right;
|
|
--rImage.bottom;
|
|
gdi.copyVirtScreenBuffers(rImage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::redrawBGAreas() {
|
|
ScummEngine_v7he::redrawBGAreas();
|
|
flushWizBuffer();
|
|
}
|
|
|
|
void ScummEngine_v72he::flushWizBuffer() {
|
|
for (int i = 0; i < _wizImagesNum; ++i) {
|
|
WizImage *pwi = &_wizImages[i];
|
|
drawWizImage(rtImage, pwi->resnum, 0, pwi->x1, pwi->y1, pwi->flags);
|
|
}
|
|
_wizImagesNum = 0;
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_drawWizImage() {
|
|
int flags = pop();
|
|
int y1 = pop();
|
|
int x1 = pop();
|
|
int resnum = pop();
|
|
|
|
if (_fullRedraw) {
|
|
assert(_wizImagesNum < ARRAYSIZE(_wizImages));
|
|
WizImage *pwi = &_wizImages[_wizImagesNum];
|
|
pwi->resnum = resnum;
|
|
pwi->x1 = x1;
|
|
pwi->y1 = y1;
|
|
pwi->flags = flags;
|
|
++_wizImagesNum;
|
|
} else {
|
|
drawWizImage(rtImage, resnum, 0, x1, y1, flags);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknownCF() {
|
|
//ArrayHeader *ah;
|
|
byte string[255];
|
|
|
|
copyScriptString(string);
|
|
int len = resStrLen(string) + 1;
|
|
|
|
writeVar(0, 0);
|
|
//ah = defineArray(0, kStringArray, 0, 0, 0, len);
|
|
defineArray(0, kStringArray, 0, 0, 0, len);
|
|
writeArray(0, 0, 0, 0);
|
|
//memcpy(ah->data, string, len);
|
|
|
|
push(readVar(0));
|
|
}
|
|
|
|
void ScummEngine_v72he::shuffleArray(int num, int minIdx, int maxIdx) {
|
|
int range = maxIdx - minIdx;
|
|
int count = range * 2;
|
|
|
|
// Shuffle the array 'num'
|
|
while (count--) {
|
|
// Determine two random elements...
|
|
int rand1 = _rnd.getRandomNumber(range) + minIdx;
|
|
int rand2 = _rnd.getRandomNumber(range) + minIdx;
|
|
|
|
// ...and swap them
|
|
int val1 = readArray(num, 0, rand1);
|
|
int val2 = readArray(num, 0, rand2);
|
|
writeArray(num, 0, rand1, val2);
|
|
writeArray(num, 0, rand2, val1);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_shuffle() {
|
|
int b = pop();
|
|
int a = pop();
|
|
shuffleArray(fetchScriptWord(), a, b);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_jumpToScript() {
|
|
int args[16];
|
|
int script, flags;
|
|
|
|
getStackList(args, ARRAYSIZE(args));
|
|
script = pop();
|
|
flags = fetchScriptByte();
|
|
stopObjectCode();
|
|
runScript(script, (flags == 199 || flags == 200), (flags == 195 || flags == 200), args);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_openFile() {
|
|
int mode, slot, l, r;
|
|
byte filename[100];
|
|
|
|
mode = pop();
|
|
copyScriptString(filename);
|
|
// The boot script in some HE games doen't set the
|
|
// complete data file name. So we work around that.
|
|
if (!strcmp((char *)filename,".he3")) {
|
|
memset(filename, 0, sizeof(filename));
|
|
sprintf((char *)filename, "%s.he3", _gameName.c_str());
|
|
}
|
|
|
|
debug(1,"File %s", filename);
|
|
|
|
for (r = strlen((char*)filename); r != 0; r--) {
|
|
if (filename[r - 1] == '\\')
|
|
break;
|
|
}
|
|
|
|
slot = -1;
|
|
for (l = 0; l < 17; l++) {
|
|
if (_hFileTable[l].isOpen() == false) {
|
|
slot = l;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (slot != -1) {
|
|
if (mode == 1)
|
|
_hFileTable[slot].open((char*)filename + r, File::kFileReadMode);
|
|
else if (mode == 2)
|
|
_hFileTable[slot].open((char*)filename + r, File::kFileWriteMode);
|
|
else
|
|
error("o6he_openFile(): wrong open file mode %d", mode);
|
|
|
|
if (_hFileTable[slot].isOpen() == false)
|
|
slot = -1;
|
|
|
|
}
|
|
debug(1, "o72_openFile: slot %d, mode %d", slot, mode);
|
|
push(slot);
|
|
}
|
|
|
|
int ScummEngine_v72he::readFileToArray(int slot, int32 size) {
|
|
if (size == 0)
|
|
size = _hFileTable[slot].size() - _hFileTable[slot].pos();
|
|
|
|
writeVar(0, 0);
|
|
|
|
ArrayHeader *ah = defineArray(0, kByteArray, 0, 0, 0, size);
|
|
_hFileTable[slot].read(ah->data, size);
|
|
|
|
return readVar(0);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_readFile() {
|
|
int slot, val;
|
|
int32 size;
|
|
int subOp = fetchScriptByte();
|
|
|
|
switch (subOp) {
|
|
case 4:
|
|
slot = pop();
|
|
val = _hFileTable[slot].readByte();
|
|
push(val);
|
|
break;
|
|
case 5:
|
|
slot = pop();
|
|
val = _hFileTable[slot].readUint16LE();
|
|
push(val);
|
|
break;
|
|
case 6:
|
|
slot = pop();
|
|
val = _hFileTable[slot].readUint32LE();
|
|
push(val);
|
|
break;
|
|
case 8:
|
|
fetchScriptByte();
|
|
size = pop();
|
|
slot = pop();
|
|
val = readFileToArray(slot, size);
|
|
push(val);
|
|
break;
|
|
default:
|
|
error("o72_readFile: default case %d", subOp);
|
|
}
|
|
debug(1, "o72_readFile: slot %d, subOp %d val %d", slot, subOp, val);
|
|
}
|
|
|
|
void ScummEngine_v72he::writeFileFromArray(int slot, int resID) {
|
|
ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resID);
|
|
int32 size = (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
|
|
(FROM_LE_32(ah->dim2end) - FROM_LE_32(ah->dim2start) + 1);
|
|
|
|
_hFileTable[slot].write(ah->data, size);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_writeFile() {
|
|
int16 resID = pop();
|
|
int slot = pop();
|
|
int subOp = fetchScriptByte();
|
|
|
|
switch (subOp) {
|
|
case 4:
|
|
_hFileTable[slot].writeByte(resID);
|
|
break;
|
|
case 5:
|
|
_hFileTable[slot].writeUint16LE(resID);
|
|
break;
|
|
case 6:
|
|
_hFileTable[slot].writeUint32LE(resID);
|
|
break;
|
|
case 8:
|
|
fetchScriptByte();
|
|
writeFileFromArray(slot, resID);
|
|
break;
|
|
default:
|
|
error("o72_writeFile: default case %d", subOp);
|
|
}
|
|
debug(1, "o72_writeFile: slot %d, subOp %d", slot, subOp);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_findAllObjects() {
|
|
int room = pop();
|
|
int i = 1;
|
|
|
|
if (room != _currentRoom)
|
|
warning("o72_findAllObjects: current room is not %d", room);
|
|
writeVar(0, 0);
|
|
defineArray(0, kDwordArray, 0, 0, 0, _numLocalObjects + 1);
|
|
writeArray(0, 0, 0, _numLocalObjects);
|
|
|
|
while (i < _numLocalObjects) {
|
|
writeArray(0, 0, i, _objs[i].obj_nr);
|
|
i++;
|
|
}
|
|
|
|
push(readVar(0));
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_deleteFile() {
|
|
byte filename[100];
|
|
|
|
copyScriptString(filename);
|
|
|
|
debug(1, "stub o72_deleteFile(%s)", filename);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_getPixel() {
|
|
byte area;
|
|
int x = pop();
|
|
int y = pop();
|
|
int subOp = fetchScriptByte();
|
|
|
|
if (subOp != 218 && subOp != 219)
|
|
return;
|
|
|
|
VirtScreen *vs = findVirtScreen(y);
|
|
if (vs == NULL || x > _screenWidth - 1 || x < 0) {
|
|
push(-1);
|
|
return;
|
|
}
|
|
|
|
if (subOp == 218)
|
|
area = *vs->getBackPixels(x, y - vs->topline);
|
|
else
|
|
area = *vs->getPixels(x, y - vs->topline);
|
|
push(area);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_pickVarRandom() {
|
|
int num;
|
|
int args[100];
|
|
int32 dim1end;
|
|
|
|
num = getStackList(args, ARRAYSIZE(args));
|
|
int value = fetchScriptWord();
|
|
|
|
if (readVar(value) == 0) {
|
|
defineArray(value, kDwordArray, 0, 0, 0, num);
|
|
if (num > 0) {
|
|
int16 counter = 0;
|
|
do {
|
|
writeArray(value, 0, counter + 1, args[counter]);
|
|
} while (++counter < num);
|
|
}
|
|
|
|
shuffleArray(value, 1, num);
|
|
writeArray(value, 0, 0, 2);
|
|
push(readArray(value, 0, 1));
|
|
return;
|
|
}
|
|
|
|
num = readArray(value, 0, 0);
|
|
|
|
ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(value));
|
|
dim1end = FROM_LE_32(ah->dim1end);
|
|
|
|
if (dim1end < num) {
|
|
int16 var_2 = readArray(value, 0, num - 1);
|
|
shuffleArray(value, 1, dim1end);
|
|
if (readArray(value, 0, 1) == var_2) {
|
|
num = 2;
|
|
} else {
|
|
num = 1;
|
|
}
|
|
}
|
|
|
|
writeArray(value, 0, 0, num + 1);
|
|
push(readArray(value, 0, num));
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_redimArray() {
|
|
int subcode, newX, newY;
|
|
newY = pop();
|
|
newX = pop();
|
|
|
|
subcode = fetchScriptByte();
|
|
switch (subcode) {
|
|
case 5:
|
|
redimArray(fetchScriptWord(), 0, newX, 0, newY, kIntArray);
|
|
break;
|
|
case 4:
|
|
redimArray(fetchScriptWord(), 0, newX, 0, newY, kByteArray);
|
|
break;
|
|
case 6:
|
|
redimArray(fetchScriptWord(), 0, newX, 0, newY, kDwordArray);
|
|
break;
|
|
default:
|
|
error("o72_redimArray: default type %d", subcode);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::redimArray(int arrayId, int newDim2start, int newDim2end,
|
|
int newDim1start, int newDim1end, int type) {
|
|
int newSize, oldSize;
|
|
|
|
if (readVar(arrayId) == 0)
|
|
error("redimArray: Reference to zeroed array pointer");
|
|
|
|
ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(arrayId));
|
|
|
|
if (!ah)
|
|
error("redimArray: Invalid array (%d) reference", readVar(arrayId));
|
|
|
|
newSize = arrayDataSizes[type];
|
|
oldSize = arrayDataSizes[FROM_LE_32(ah->type)];
|
|
|
|
newSize *= (newDim1end - newDim1start + 1) * (newDim2end - newDim2start + 1);
|
|
oldSize *= (FROM_LE_32(ah->dim1end) - FROM_LE_32(ah->dim1start) + 1) *
|
|
(FROM_LE_32(ah->dim2end) - FROM_LE_32(ah->dim2start) + 1);
|
|
|
|
newSize >>= 3;
|
|
oldSize >>= 3;
|
|
|
|
if (newSize != oldSize)
|
|
error("redimArray: array %d redim mismatch", readVar(arrayId));
|
|
|
|
ah->type = TO_LE_32(type);
|
|
ah->dim1start = TO_LE_32(newDim1start);
|
|
ah->dim1end = TO_LE_32(newDim1end);
|
|
ah->dim2start = TO_LE_32(newDim2start);
|
|
ah->dim2end = TO_LE_32(newDim2end);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknownEC() {
|
|
int dst, size;
|
|
int src = pop();
|
|
|
|
size = resStrLen(getStringAddress(src)) + 1;
|
|
|
|
writeVar(0, 0);
|
|
defineArray(0, kStringArray, 0, 0, 0, size);
|
|
writeArray(0, 0, 0, 0);
|
|
dst = readVar(0);
|
|
|
|
arrrays_unk2(dst, src, -1, -1);
|
|
|
|
push(dst);
|
|
debug(1,"stub o72_unknownEC");
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknownED() {
|
|
int array, pos, len;
|
|
int chr, result = 0;
|
|
|
|
len = pop();
|
|
pos = pop();
|
|
array = pop();
|
|
|
|
if (len == -1) {
|
|
pos = 0;
|
|
len = resStrLen(getStringAddress(array));
|
|
}
|
|
|
|
writeVar(0, array);
|
|
while (pos <= len) {
|
|
chr = readArray(0, 0, pos);
|
|
if (chr)
|
|
result += _charset->getCharWidth(chr);
|
|
pos++;
|
|
}
|
|
|
|
push(result);
|
|
debug(1,"stub o72_unknownED");
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknownEF() {
|
|
int dst, size;
|
|
int b = pop();
|
|
int a = pop();
|
|
int src = pop();
|
|
|
|
size = b - a + 2;
|
|
|
|
writeVar(0, 0);
|
|
defineArray(0, kStringArray, 0, 0, 0, size);
|
|
writeArray(0, 0, 0, 0);
|
|
|
|
dst = readVar(0);
|
|
|
|
arrrays_unk2(dst, src, a, b);
|
|
|
|
push(dst);
|
|
debug(1,"stub o72_unknownEF");
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknownF0() {
|
|
int dst, size;
|
|
|
|
int src2 = pop();
|
|
int src1 = pop();
|
|
|
|
size = resStrLen(getStringAddress(src1));
|
|
size += resStrLen(getStringAddress(src2)) + 1;
|
|
|
|
writeVar(0, 0);
|
|
defineArray(0, kStringArray, 0, 0, 0, size);
|
|
writeArray(0, 0, 0, 0);
|
|
|
|
dst = readVar(0);
|
|
|
|
arrrays_unk2(dst, src1, 0, -1);
|
|
arrrays_unk2(dst, src2, 0, -1);
|
|
|
|
push(dst);
|
|
debug(1,"stub o72_unknownF0");
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknownF1() {
|
|
byte *addr, *addr2;
|
|
|
|
int id = pop();
|
|
int id2 = pop();
|
|
|
|
addr = getStringAddress(id);
|
|
if (!addr)
|
|
error("o72_stringLen: Reference to zeroed array pointer (%d)", id);
|
|
|
|
addr2 = getStringAddress(id2);
|
|
if (!addr)
|
|
error("o72_stringLen: Reference to zeroed array pointer (%d)", id);
|
|
|
|
while (*addr == *addr2) {
|
|
if (addr == 0) {
|
|
push(0);
|
|
return;
|
|
}
|
|
addr++;
|
|
addr2++;
|
|
}
|
|
|
|
push (1);
|
|
debug(1,"o70he_unknownF1 stub (%d, %d)", id, id2);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_checkGlobQueue() {
|
|
int subOp = fetchScriptByte();
|
|
int idx = pop();
|
|
|
|
debug(1,"o72_checkGlobQueue stub (%d, %d)", subOp, idx);
|
|
push(100);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_readINI() {
|
|
byte option[100];
|
|
int type, retval;
|
|
|
|
// we pretend that we don't have .ini file
|
|
copyScriptString(option);
|
|
type = fetchScriptByte();
|
|
|
|
switch (type) {
|
|
case 6: // number
|
|
if (!strcmp((char *)option, "ReadPagesAutomatically"))
|
|
push(1);
|
|
else if (!strcmp((char *)option, "NoPrinting"))
|
|
push(1);
|
|
else
|
|
push(0);
|
|
break;
|
|
case 7: // string
|
|
writeVar(0, 0);
|
|
defineArray(0, kStringArray, 0, 0, 0, 0);
|
|
retval = readVar(0);
|
|
writeArray(0, 0, 0, 0);
|
|
push(retval); // var ID string
|
|
break;
|
|
default:
|
|
error("o72_readINI: default type %d", type);
|
|
}
|
|
debug(1, "o72_readINI (%d) %s", type, option);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_writeINI() {
|
|
int type, value;
|
|
byte option[256], string[1024];
|
|
|
|
type = fetchScriptByte();
|
|
|
|
switch (type) {
|
|
case 6: // number
|
|
value = pop();
|
|
copyScriptString(option);
|
|
debug(1,"o72_writeINI: %s set to %d", option, value);
|
|
break;
|
|
case 7: // string
|
|
copyScriptString(string);
|
|
copyScriptString(option);
|
|
debug(1,"o72_writeINI: %s set to %s", option, string);
|
|
break;
|
|
default:
|
|
error("o72_writeINI: default type %d", type);
|
|
}
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknownF5() {
|
|
int chr, max;
|
|
int array, len, pos, result = 0;
|
|
max = pop();
|
|
pos = pop();
|
|
array = pop();
|
|
|
|
len = resStrLen(getStringAddress(array));
|
|
|
|
writeVar(0, array);
|
|
while (pos <= len) {
|
|
chr = readArray(0, 0, pos);
|
|
result += _charset->getCharWidth(chr);
|
|
if (result >= max) {
|
|
push(pos);
|
|
return;
|
|
}
|
|
pos++;
|
|
}
|
|
|
|
push(len);
|
|
debug(1,"stub o72_unknownF5 (%d)", result);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknownF6() {
|
|
int len, edi, pos, value, id;
|
|
value = pop();
|
|
edi = pop();
|
|
pos = pop();
|
|
id = pop();
|
|
|
|
if (edi >= 0) {
|
|
len = resStrLen(getStringAddress(id));
|
|
if (len < edi)
|
|
edi = len;
|
|
} else {
|
|
edi = 0;
|
|
}
|
|
|
|
if (pos < 0)
|
|
pos = 0;
|
|
|
|
writeVar(0, id);
|
|
if (edi > pos) {
|
|
while (edi >= pos) {
|
|
if (readArray(0, 0, pos) == value) {
|
|
push(pos);
|
|
return;
|
|
}
|
|
pos++;
|
|
}
|
|
} else {
|
|
while (edi <= pos) {
|
|
if (readArray(0, 0, pos) == value) {
|
|
push(pos);
|
|
return;
|
|
}
|
|
pos--;
|
|
}
|
|
}
|
|
|
|
push(-1);
|
|
debug(1,"stub o72_unknownF6");
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknownF8() {
|
|
int id = pop();
|
|
byte subOp = fetchScriptByte();
|
|
push(10);
|
|
|
|
debug(1,"stub o72_unknownF8: subOp %d, id %d", subOp, id);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_setFilePath() {
|
|
// File related
|
|
byte filename[100];
|
|
copyScriptString(filename);
|
|
debug(1,"o72_setFilePath: %s", filename);
|
|
}
|
|
|
|
void ScummEngine_v72he::o72_unknownFA() {
|
|
byte name[100];
|
|
copyScriptString(name);
|
|
int id = fetchScriptByte();
|
|
|
|
debug(1,"o72_unknownFA: (%d) %s", id, name);
|
|
}
|
|
|
|
void ScummEngine_v72he::decodeParseString(int m, int n) {
|
|
byte b, *ptr;
|
|
int i, color, size;
|
|
int args[31];
|
|
byte name[1024];
|
|
|
|
b = fetchScriptByte();
|
|
|
|
switch (b) {
|
|
case 65: // SO_AT
|
|
_string[m].ypos = pop();
|
|
_string[m].xpos = pop();
|
|
_string[m].overhead = false;
|
|
break;
|
|
case 66: // SO_COLOR
|
|
_string[m].color = pop();
|
|
break;
|
|
case 67: // SO_CLIPPED
|
|
_string[m].right = pop();
|
|
break;
|
|
case 69: // SO_CENTER
|
|
_string[m].center = true;
|
|
_string[m].overhead = false;
|
|
break;
|
|
case 71: // SO_LEFT
|
|
_string[m].center = false;
|
|
_string[m].overhead = false;
|
|
break;
|
|
case 72: // SO_OVERHEAD
|
|
_string[m].overhead = true;
|
|
_string[m].no_talk_anim = false;
|
|
break;
|
|
case 73: // SO_SAY_VOICE
|
|
error("decodeParseString: case 73");
|
|
break;
|
|
case 74: // SO_MUMBLE
|
|
_string[m].no_talk_anim = true;
|
|
break;
|
|
case 75: // SO_TEXTSTRING
|
|
printString(m, _scriptPointer);
|
|
_scriptPointer += resStrLen(_scriptPointer) + 1;
|
|
break;
|
|
case 194:
|
|
decodeScriptString(name, true);
|
|
printString(m, name);
|
|
break;
|
|
case 0xE1:
|
|
ptr = getResourceAddress(rtTalkie, pop());
|
|
size = READ_BE_UINT32(ptr + 12);
|
|
memcpy(name, ptr + 16, size);
|
|
printString(m, name);
|
|
break;
|
|
case 0xF9:
|
|
color = pop();
|
|
if (color == 1) {
|
|
_string[m].color = pop();
|
|
} else {
|
|
push(color);
|
|
getStackList(args, ARRAYSIZE(args));
|
|
for (i = 0; i < 16; i++)
|
|
_charsetColorMap[i] = _charsetData[_string[1]._default.charset][i] = (unsigned char)args[i];
|
|
_string[m].color = color;
|
|
}
|
|
break;
|
|
case 0xFE:
|
|
_string[m].loadDefault();
|
|
if (n)
|
|
_actorToPrintStrFor = pop();
|
|
break;
|
|
case 0xFF:
|
|
_string[m].saveDefault();
|
|
break;
|
|
default:
|
|
error("decodeParseString: default case 0x%x", b);
|
|
}
|
|
}
|
|
|
|
} // End of namespace Scumm
|