scummvm/scumm/script_v6he.cpp
Eugene Sandulenko 154c4af8dc Mass-renamed all variables of Actor object according to our current code
formatting standards. Earlier we had half of vars named with leading
underscore and half without it.

Now code in actor.cpp is considerably more readable.

svn-id: r17068
2005-03-11 01:10:06 +00:00

1346 lines
29 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2001 Ludvig Strigeus
* Copyright (C) 2001-2005 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 "common/savefile.h"
#include "scumm/actor.h"
#include "scumm/charset.h"
#include "scumm/imuse.h"
#include "scumm/intern.h"
#include "scumm/object.h"
#include "scumm/resource.h"
#include "scumm/scumm.h"
#include "scumm/sound.h"
#include "scumm/verbs.h"
namespace Scumm {
struct vsUnpackCtx {
uint8 size;
uint8 type;
uint8 b;
uint8 *ptr;
};
struct vsPackCtx {
int size;
uint8 buf[256];
};
static void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len);
static void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b);
static uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data);
static int virtScreenSavePack(byte *dst, byte *src, int len, int unk);
// Compatibility notes:
//
// FBEAR (fbear, fbeardemo)
// transparency in akos.cpp
// negative size in file read/write
#define OPCODE(x) _OPCODE(ScummEngine_v60he, x)
void ScummEngine_v60he::setupOpcodes() {
static const OpcodeEntryv60he opcodes[256] = {
/* 00 */
OPCODE(o6_pushByte),
OPCODE(o6_pushWord),
OPCODE(o6_pushByteVar),
OPCODE(o6_pushWordVar),
/* 04 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_byteArrayRead),
OPCODE(o6_wordArrayRead),
/* 08 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_byteArrayIndexedRead),
OPCODE(o6_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(o6_invalid),
/* 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_writeByteVar),
OPCODE(o6_writeWordVar),
/* 44 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_byteArrayWrite),
OPCODE(o6_wordArrayWrite),
/* 48 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_byteArrayIndexedWrite),
OPCODE(o6_wordArrayIndexedWrite),
/* 4C */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_byteVarInc),
OPCODE(o6_wordVarInc),
/* 50 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_byteArrayInc),
OPCODE(o6_wordArrayInc),
/* 54 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_byteVarDec),
OPCODE(o6_wordVarDec),
/* 58 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_byteArrayDec),
OPCODE(o6_wordArrayDec),
/* 5C */
OPCODE(o6_if),
OPCODE(o6_ifNot),
OPCODE(o6_startScript),
OPCODE(o6_startScriptQuick),
/* 60 */
OPCODE(o6_startObject),
OPCODE(o6_drawObject),
OPCODE(o6_drawObjectAt),
OPCODE(o6_invalid),
/* 64 */
OPCODE(o6_invalid),
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(o60_setState),
OPCODE(o6_setOwner),
OPCODE(o6_getOwner),
OPCODE(o6_jump),
/* 74 */
OPCODE(o6_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(o6_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(o6_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(o6_resourceRoutines),
/* 9C */
OPCODE(o60_roomOps),
OPCODE(o60_actorOps),
OPCODE(o6_verbOps),
OPCODE(o6_getActorFromXY),
/* A0 */
OPCODE(o6_findObject),
OPCODE(o6_pseudoRoom),
OPCODE(o6_getActorElevation),
OPCODE(o6_getVerbEntrypoint),
/* A4 */
OPCODE(o6_arrayOps),
OPCODE(o6_saveRestoreVerbs),
OPCODE(o6_drawBox),
OPCODE(o6_pop),
/* A8 */
OPCODE(o6_getActorWidth),
OPCODE(o60_wait),
OPCODE(o6_getActorScaleX),
OPCODE(o6_getActorAnimCounter1),
/* AC */
OPCODE(o6_invalid),
OPCODE(o6_isAnyOf),
OPCODE(o6_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(o6_dimArray),
OPCODE(o6_stopObjectCode),
OPCODE(o6_startObjectQuick),
OPCODE(o6_startScriptQuick2),
/* C0 */
OPCODE(o6_dim2dimArray),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* C4 */
OPCODE(o6_abs),
OPCODE(o6_distObjectObject),
OPCODE(o6_distObjectPt),
OPCODE(o6_distPtPt),
/* C8 */
OPCODE(o60_kernelGetFunctions),
OPCODE(o60_kernelSetFunctions),
OPCODE(o6_delayFrames),
OPCODE(o6_pickOneOf),
/* CC */
OPCODE(o6_pickOneOfDefault),
OPCODE(o6_stampObject),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* D0 */
OPCODE(o6_getDateTime),
OPCODE(o6_stopTalking),
OPCODE(o6_getAnimateVariable),
OPCODE(o6_invalid),
/* D4 */
OPCODE(o6_shuffle),
OPCODE(o6_jumpToScript),
OPCODE(o6_band),
OPCODE(o6_bor),
/* D8 */
OPCODE(o6_isRoomScriptRunning),
OPCODE(o60_closeFile),
OPCODE(o60_openFile),
OPCODE(o60_readFile),
/* DC */
OPCODE(o60_writeFile),
OPCODE(o6_findAllObjects),
OPCODE(o60_deleteFile),
OPCODE(o60_rename),
/* E0 */
OPCODE(o60_soundOps),
OPCODE(o6_getPixel),
OPCODE(o60_localizeArrayToScript),
OPCODE(o6_pickVarRandom),
/* E4 */
OPCODE(o6_setBoxSet),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* E8 */
OPCODE(o6_invalid),
OPCODE(o60_seekFilePos),
OPCODE(o60_redimArray),
OPCODE(o60_readFilePos),
/* EC */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* F0 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* F4 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* F8 */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
/* FC */
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
OPCODE(o6_invalid),
};
_opcodesv60he = opcodes;
}
void ScummEngine_v60he::executeOpcode(byte i) {
OpcodeProcv60he op = _opcodesv60he[i].proc;
(this->*op) ();
}
const char *ScummEngine_v60he::getOpcodeDesc(byte i) {
return _opcodesv60he[i].desc;
}
void ScummEngine_v60he::o60_setState() {
int state = pop();
int obj = pop();
if (state & 0x8000) {
state &= 0x7FFF;
putState(obj, state);
if (_heversion >= 72)
removeObjectFromDrawQue(obj);
return;
}
putState(obj, state);
markObjectRectAsDirty(obj);
if (_bgNeedsRedraw)
clearDrawObjectQueue();
}
void ScummEngine_v60he::o60_roomOps() {
int a, b, c, d, e;
byte op;
op = fetchScriptByte();
switch (op) {
case 172: // SO_ROOM_SCROLL
b = pop();
a = pop();
if (a < (_screenWidth / 2))
a = (_screenWidth / 2);
if (b < (_screenWidth / 2))
b = (_screenWidth / 2);
if (a > _roomWidth - (_screenWidth / 2))
a = _roomWidth - (_screenWidth / 2);
if (b > _roomWidth - (_screenWidth / 2))
b = _roomWidth - (_screenWidth / 2);
VAR(VAR_CAMERA_MIN_X) = a;
VAR(VAR_CAMERA_MAX_X) = b;
break;
case 174: // SO_ROOM_SCREEN
b = pop();
a = pop();
if (_heversion >= 71)
initScreens(a, _screenHeight);
else
initScreens(a, b);
break;
case 175: // SO_ROOM_PALETTE
d = pop();
c = pop();
b = pop();
a = pop();
setPalColor(d, a, b, c);
break;
case 176: // SO_ROOM_SHAKE_ON
setShake(1);
break;
case 177: // SO_ROOM_SHAKE_OFF
setShake(0);
break;
case 179: // SO_ROOM_INTENSITY
c = pop();
b = pop();
a = pop();
darkenPalette(a, a, a, b, c);
break;
case 180: // SO_ROOM_SAVEGAME
_saveTemporaryState = true;
_saveLoadSlot = pop();
_saveLoadFlag = pop();
break;
case 181: // SO_ROOM_FADE
a = pop();
if (_heversion >= 70) {
// Defaults to 1 but doesn't use fade effects
} else if (a) {
_switchRoomEffect = (byte)(a & 0xFF);
_switchRoomEffect2 = (byte)(a >> 8);
} else {
fadeIn(_newEffect);
}
break;
case 182: // SO_RGB_ROOM_INTENSITY
e = pop();
d = pop();
c = pop();
b = pop();
a = pop();
darkenPalette(a, b, c, d, e);
break;
case 183: // SO_ROOM_SHADOW
e = pop();
d = pop();
c = pop();
b = pop();
a = pop();
if (_heversion == 60)
setupShadowPalette(a, b, c, d, e, 0, 256);
break;
case 184: // SO_SAVE_STRING
error("save string not implemented");
break;
case 185: // SO_LOAD_STRING
error("load string not implemented");
break;
case 186: // SO_ROOM_TRANSFORM
d = pop();
c = pop();
b = pop();
a = pop();
palManipulateInit(a, b, c, d);
break;
case 187: // SO_CYCLE_SPEED
b = pop();
a = pop();
checkRange(16, 1, a, "o60_roomOps: 187: color cycle out of range (%d)");
_colorCycle[a - 1].delay = (b != 0) ? 0x4000 / (b * 0x4C) : 0;
break;
case 213: // SO_ROOM_NEW_PALETTE
a = pop();
setPalette(a, _roomResource);
break;
case 220:
a = pop();
b = pop();
copyPalColor(a, b);
break;
case 221:
int len;
len = resStrLen(_scriptPointer);
_scriptPointer += len + 1;
_saveLoadFlag = pop();
_saveLoadSlot = 1;
_saveTemporaryState = true;
break;
case 234: // HE 7.2
b = pop();
a = pop();
swapObjects(a, b);
break;
case 236: // HE 7.2
b = pop();
a = pop();
setPalette(a, b);
break;
default:
error("o60_roomOps: default case %d", op);
}
}
void ScummEngine_v60he::swapObjects(int object1, int object2) {
int idx1 = -1, idx2 = -1;
if (_numObjectsInRoom >= 0) { // how could it be negative?
for (int i = 0; i < _numObjectsInRoom; i++) {
if (_objs[i].obj_nr == object1)
idx1 = i;
if (_objs[i].obj_nr == object2)
idx2 = i;
}
}
if (idx1 == -1 || idx2 == -1 || idx1 >= idx2)
return;
stopObjectScript(object1);
stopObjectScript(object2);
ObjectData tmpOd;
memcpy(&tmpOd, &_objs[idx1], sizeof(tmpOd));
memcpy(&_objs[idx1], &_objs[idx2], sizeof(tmpOd));
memcpy(&_objs[idx2], &tmpOd, sizeof(tmpOd));
}
void ScummEngine_v60he::o60_actorOps() {
Actor *a;
int i, j, k;
int args[8];
byte subOp;
subOp = fetchScriptByte();
if (subOp == 197) {
_curActor = pop();
return;
}
a = derefActorSafe(_curActor, "o60_actorOps");
if (!a)
return;
switch (subOp) {
case 30:
// _heversion >= 70
_actorClipOverride.bottom = pop();
_actorClipOverride.right = pop();
_actorClipOverride.top = pop();
_actorClipOverride.left = pop();
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);
a->_needRedraw = true;
break;
case 87: // SO_TALK_COLOR
a->_talkColor = pop();
break;
case 88: // SO_ACTOR_NAME
loadPtrToResource(rtActorName, a->_number, NULL);
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->_shadowMode = pop();
a->_needRedraw = true;
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, a->_heTalkQueue[slot].sentence, len);
a->_heTalkQueue[slot].posX = a->_talkPosX;
a->_heTalkQueue[slot].posY = a->_talkPosY;
a->_heTalkQueue[slot].color = a->_talkColor;
break;
}
default:
error("o60_actorOps: default case %d", subOp);
}
}
void ScummEngine_v60he::o60_wait() {
int actnum;
int offs = -2;
Actor *a;
byte subOp = fetchScriptByte();
switch (subOp) {
case 168: // SO_WAIT_FOR_ACTOR Wait for actor
offs = fetchScriptWordSigned();
actnum = pop();
a = derefActor(actnum, "o60_wait:168");
if (a->_moving)
break;
return;
case 169: // SO_WAIT_FOR_MESSAGE Wait for message
if (VAR(VAR_HAVE_MSG))
break;
return;
case 170: // SO_WAIT_FOR_CAMERA Wait for camera
if (camera._cur.x / 8 != camera._dest.x / 8)
break;
return;
case 171: // SO_WAIT_FOR_SENTENCE
if (_sentenceNum) {
if (_sentence[_sentenceNum - 1].freezeCount && !isScriptInUse(VAR(VAR_SENTENCE_SCRIPT)))
return;
break;
}
if (!isScriptInUse(VAR(VAR_SENTENCE_SCRIPT)))
return;
break;
default:
error("o60_wait: default case 0x%x", subOp);
}
_scriptPointer += offs;
o6_breakHere();
}
void ScummEngine_v60he::o60_kernelSetFunctions() {
int args[29];
int num;
num = getStackList(args, ARRAYSIZE(args));
switch (args[0]) {
case 1:
// Used to restore images when decorating cake in
// Fatty Bear's Birthday Surprise
virtScreenLoad(args[1], args[2], args[3], args[4], args[5]);
break;
case 3:
case 4:
case 5:
//Used before mini games in 3DO versions, seems safe to ignore.
break;
default:
error("o60_kernelSetFunctions: default case %d (param count %d)", args[0], num);
}
}
void ScummEngine_v60he::virtScreenLoad(int resIdx, int x1, int y1, int x2, int y2) {
vsUnpackCtx ctx;
memset(&ctx, 0, sizeof(ctx));
VirtScreen &vs = virtscr[kMainVirtScreen]; // XXX gdi_virtScreen = 0;
ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resIdx);
virtScreenLoadUnpack(&ctx, ah->data);
for (int j = y1; j <= y2; ++j) {
uint8 *p1 = vs.getPixels(x1, j - vs.topline);
uint8 *p2 = vs.getBackPixels(x1, j - vs.topline);
if (x2 >= x1) {
uint32 w = x2 - x1 + 1;
while (w--) {
uint8 decByte = virtScreenLoadUnpack(&ctx, 0);
*p1++ = decByte;
*p2++ = decByte;
}
}
}
markRectAsDirty(kMainVirtScreen, x1, x2, y1, y2 + 1); // XXX , 0x4000);
}
uint8 virtScreenLoadUnpack(vsUnpackCtx *ctx, byte *data) {
uint8 decByte;
if (data != 0) {
ctx->type = 0;
ctx->ptr = data;
decByte = 0;
} else {
uint8 a;
if (ctx->type == 0) {
a = *(ctx->ptr)++;
if (a & 1) {
ctx->type = 1;
ctx->b = *(ctx->ptr)++;
} else {
ctx->type = 2;
}
ctx->size = a;
a = (a >> 1) + 1;
} else {
a = ctx->size;
}
if (ctx->type == 2) {
ctx->b = *(ctx->ptr)++;
}
ctx->size = a - 1;
if (ctx->size == 0) {
ctx->type = 0;
}
decByte = ctx->b;
}
return decByte;
}
void ScummEngine_v60he::o60_kernelGetFunctions() {
int args[29];
ArrayHeader *ah;
getStackList(args, ARRAYSIZE(args));
switch (args[0]) {
case 1:
// Used to store images when decorating cake in
// Fatty Bear's Birthday Surprise
writeVar(0, 0);
ah = defineArray(0, kByteArray, 0, virtScreenSave(0, args[1], args[2], args[3], args[4]));
virtScreenSave(ah->data, args[1], args[2], args[3], args[4]);
push(readVar(0));
break;
default:
error("o60_kernelGetFunctions: default case %d", args[0]);
}
}
int ScummEngine_v60he::virtScreenSave(byte *dst, int x1, int y1, int x2, int y2) {
int packedSize = 0;
VirtScreen &vs = virtscr[kMainVirtScreen]; // XXX gdi_virtScreen = 0;
for (int j = y1; j <= y2; ++j) {
uint8 *p = vs.getBackPixels(x1, j - vs.topline);
int size = virtScreenSavePack(dst, p, x2 - x1 + 1, 0);
if (dst != 0) {
dst += size;
}
packedSize += size;
}
return packedSize;
}
int virtScreenSavePack(byte *dst, byte *src, int len, int unk) {
vsPackCtx ctx;
memset(&ctx, 0, sizeof(ctx));
uint8 prevByte, curByte;
ctx.buf[0] = prevByte = *src++;
int flag = 0;
int iend = 1;
int ibeg = 0;
for (--len; len != 0; --len, prevByte = curByte) {
bool pass = false;
assert(iend < 0x100);
ctx.buf[iend] = curByte = *src++;
++iend;
if (flag == 0) {
if (iend > 0x80) {
virtScreenSavePackBuf(&ctx, dst, iend - 1);
ctx.buf[0] = curByte;
iend = 1;
ibeg = 0;
continue;
}
if (prevByte != curByte) {
ibeg = iend - 1;
continue;
}
if (iend - ibeg < 3) {
if (ibeg != 0) {
pass = true;
} else {
flag = 1;
}
} else {
if (ibeg > 0) {
virtScreenSavePackBuf(&ctx, dst, ibeg);
}
flag = 1;
}
}
if (flag == 1 || pass) {
if (prevByte != curByte || iend - ibeg > 0x80) {
virtScreenSavePackByte(&ctx, dst, iend - ibeg - 1, prevByte);
ctx.buf[0] = curByte;
iend = 1;
ibeg = 0;
flag = 0;
}
}
}
if (flag == 0) {
virtScreenSavePackBuf(&ctx, dst, iend);
} else if (flag == 1) {
virtScreenSavePackByte(&ctx, dst, iend - ibeg, prevByte);
}
return ctx.size;
}
void virtScreenSavePackBuf(vsPackCtx *ctx, uint8 *&dst, int len) {
if (dst) {
*dst++ = (len - 1) * 2;
}
++ctx->size;
if (len > 0) {
ctx->size += len;
if (dst) {
memcpy(dst, ctx->buf, len);
dst += len;
}
}
}
void virtScreenSavePackByte(vsPackCtx *ctx, uint8 *&dst, int len, uint8 b) {
if (dst) {
*dst++ = ((len - 1) * 2) | 1;
}
++ctx->size;
if (dst) {
*dst++ = b;
}
++ctx->size;
}
void ScummEngine_v60he::o60_openFile() {
int mode, len, slot, l, r;
byte filename[100];
addMessageToStack(_scriptPointer, filename, sizeof(filename));
len = resStrLen(_scriptPointer);
_scriptPointer += len + 1;
for (r = strlen((char*)filename); r != 0; r--) {
if (filename[r - 1] == '\\')
break;
}
mode = pop();
slot = -1;
for (l = 0; l < 17; l++) {
if (_hFileTable[l].isOpen() == false) {
slot = l;
break;
}
}
if (slot != -1) {
switch(mode) {
case 1:
_hFileTable[slot].open((char*)filename + r, File::kFileReadMode, _saveFileMan->getSavePath());
if (_hFileTable[slot].isOpen() == false)
_hFileTable[slot].open((char*)filename + r, File::kFileReadMode);
break;
case 2:
_hFileTable[slot].open((char*)filename + r, File::kFileWriteMode, _saveFileMan->getSavePath());
break;
default:
error("o60_openFile(): wrong open file mode %d", mode);
}
if (_hFileTable[slot].isOpen() == false)
slot = -1;
}
push(slot);
}
void ScummEngine_v60he::o60_closeFile() {
int slot = pop();
if (slot != -1)
_hFileTable[slot].close();
}
void ScummEngine_v60he::o60_deleteFile() {
int len, r;
byte filename[100];
addMessageToStack(_scriptPointer, filename, sizeof(filename));
len = resStrLen(_scriptPointer);
_scriptPointer += len + 1;
for (r = strlen((char*)filename); r != 0; r--) {
if (filename[r - 1] == '\\')
break;
}
debug(1, "stub o60_deleteFile(\"%s\")", filename + r);
}
void ScummEngine_v60he::o60_rename() {
int len, r1, r2;
byte filename[100],filename2[100];
addMessageToStack(_scriptPointer, filename, sizeof(filename));
len = resStrLen(_scriptPointer);
_scriptPointer += len + 1;
for (r1 = strlen((char*)filename); r1 != 0; r1--) {
if (filename[r1 - 1] == '\\')
break;
}
addMessageToStack(_scriptPointer, filename2, sizeof(filename2));
len = resStrLen(_scriptPointer);
_scriptPointer += len + 1;
for (r2 = strlen((char*)filename2); r2 != 0; r2--) {
if (filename2[r2 - 1] == '\\')
break;
}
debug(1, "stub o60_rename(\"%s\" to \"%s\")", filename + r1, filename2 + r2);
}
int ScummEngine_v60he::readFileToArray(int slot, int32 size) {
if (size == 0)
size = _hFileTable[slot].size() - _hFileTable[slot].pos();
writeVar(0, 0);
ArrayHeader *ah = defineArray(0, kByteArray, 0, size);
_hFileTable[slot].read(ah->data, size);
return readVar(0);
}
void ScummEngine_v60he::o60_readFile() {
int32 size = pop();
int slot = pop();
int val;
// Fatty Bear uses positive values
if ((_features & GF_PC) && (_gameId == GID_FBEAR))
size = -size;
if (size == -2) {
val = _hFileTable[slot].readUint16LE();
push(val);
} else if (size == -1) {
val = _hFileTable[slot].readByte();
push(val);
} else {
val = readFileToArray(slot, size);
push(val);
}
}
void ScummEngine_v60he::writeFileFromArray(int slot, int resID) {
ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, resID);
int32 size = FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2);
_hFileTable[slot].write(ah->data, size);
}
void ScummEngine_v60he::o60_writeFile() {
int32 size = pop();
int16 resID = pop();
int slot = pop();
// Fatty Bear uses positive values
if ((_features & GF_PC) && (_gameId == GID_FBEAR))
size = -size;
if (size == -2) {
_hFileTable[slot].writeUint16LE(resID);
} else if (size == -1) {
_hFileTable[slot].writeByte(resID);
} else {
writeFileFromArray(slot, resID);
}
}
void ScummEngine_v60he::o60_soundOps() {
byte subOp = fetchScriptByte();
int arg = pop();
switch (subOp) {
case 0xde:
_imuse->setMusicVolume(arg);
break;
case 0xdf:
// Used in fbear introduction
break;
case 0xe0:
// Fatty Bear's Birthday surprise uses this when playing the
// piano, but only when using one of the digitized instruments.
// See also o6_startSound().
_sound->setOverrideFreq(arg);
break;
default:
error("o60_soundOps: default case 0x%x", subOp);
}
}
void ScummEngine_v60he::localizeArray(int slot, byte script) {
if (slot >= _numArray)
error("o60_localizeArrayToScript(%d): array slot out of range", slot);
_arraySlot[slot] = script;
}
void ScummEngine_v60he::o60_localizeArrayToScript() {
int slot = pop();
localizeArray(slot, vm.slot[_currentScript].number);
}
void ScummEngine_v60he::o60_seekFilePos() {
int mode, offset, slot;
mode = pop();
offset = pop();
slot = pop();
seekFilePos(slot, offset, mode - 1);
}
void ScummEngine_v60he::seekFilePos(int slot, int offset, int mode) {
if (slot == 1)
return;
switch (mode) {
case 0:
_hFileTable[slot].seek(offset, SEEK_SET);
break;
case 1:
_hFileTable[slot].seek(offset, SEEK_CUR);
break;
case 2:
_hFileTable[slot].seek(offset, SEEK_END);
break;
default:
error("seekFilePos: default case 0x%x", mode);
}
}
void ScummEngine_v60he::o60_readFilePos() {
int slot = pop();
if (slot == -1) {
push(0);
return;
}
push(_hFileTable[slot].pos());
}
void ScummEngine_v60he::o60_redimArray() {
int subcode, newX, newY;
newY = pop();
newX = pop();
if (newY == 0)
SWAP(newX, newY);
subcode = fetchScriptByte();
switch (subcode) {
case 199:
redimArray(fetchScriptWord(), newX, newY, kIntArray);
break;
case 202:
redimArray(fetchScriptWord(), newX, newY, kByteArray);
break;
default:
error("o60_redimArray: default type %d", subcode);
}
}
void ScummEngine_v60he::redimArray(int arrayId, int newX, int newY, int type) {
// Used in mini game at Cosmic Dust Diner in puttmoon
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 = (type == kIntArray) ? 2 : 1;
oldSize = (ah->type == kIntArray) ? 2 : 1;
newSize *= (newX + 1) * (newY + 1);
oldSize *= FROM_LE_16(ah->dim1) * FROM_LE_16(ah->dim2);
if (newSize != oldSize)
error("redimArray: array %d redim mismatch", readVar(arrayId));
ah->type = TO_LE_16(type);
ah->dim1 = TO_LE_16(newY + 1);
ah->dim2 = TO_LE_16(newX + 1);
}
void ScummEngine_v60he::decodeParseString(int m, int n) {
byte b;
int i, colors;
int args[31];
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 0xF9:
colors = pop();
if (colors == 1) {
_string[m].color = pop();
} else {
push(colors);
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 = _charsetColorMap[0];
}
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