scummvm/engines/agos/vga.cpp
Travis Howell 10f2c7cc57 Fix regression, due to lost code
svn-id: r24401
2006-10-21 10:50:19 +00:00

2050 lines
48 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2001 Ludvig Strigeus
* Copyright (C) 2001-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*
*/
// Video script opcodes for Simon1/Simon2
#include "common/stdafx.h"
#include "agos/agos.h"
#include "agos/intern.h"
#include "agos/vga.h"
#include "common/system.h"
namespace AGOS {
// Opcode tables
void AGOSEngine::setupCommonVideoOpcodes(VgaOpcodeProc *op) {
op[1] = &AGOSEngine::vc1_fadeOut;
op[2] = &AGOSEngine::vc2_call;
op[3] = &AGOSEngine::vc3_loadSprite;
op[4] = &AGOSEngine::vc4_fadeIn;
op[5] = &AGOSEngine::vc5_skip_if_neq;
op[6] = &AGOSEngine::vc6_skip_ifn_sib_with_a;
op[7] = &AGOSEngine::vc7_skip_if_sib_with_a;
op[8] = &AGOSEngine::vc8_skip_if_parent_is;
op[9] = &AGOSEngine::vc9_skip_if_unk3_is;
op[10] = &AGOSEngine::vc10_draw;
op[12] = &AGOSEngine::vc12_delay;
op[13] = &AGOSEngine::vc13_addToSpriteX;
op[14] = &AGOSEngine::vc14_addToSpriteY;
op[15] = &AGOSEngine::vc15_sync;
op[16] = &AGOSEngine::vc16_waitSync;
op[18] = &AGOSEngine::vc18_jump;
op[20] = &AGOSEngine::vc20_setRepeat;
op[21] = &AGOSEngine::vc21_endRepeat;
op[23] = &AGOSEngine::vc23_setPriority;
op[24] = &AGOSEngine::vc24_setSpriteXY;
op[25] = &AGOSEngine::vc25_halt_sprite;
op[26] = &AGOSEngine::vc26_setSubWindow;
op[27] = &AGOSEngine::vc27_resetSprite;
op[29] = &AGOSEngine::vc29_stopAllSounds;
op[30] = &AGOSEngine::vc30_setFrameRate;
op[31] = &AGOSEngine::vc31_setWindow;
op[33] = &AGOSEngine::vc33_setMouseOn;
op[34] = &AGOSEngine::vc34_setMouseOff;
op[35] = &AGOSEngine::vc35_clearWindow;
op[36] = &AGOSEngine::vc36_setWindowImage;
op[38] = &AGOSEngine::vc38_skipIfVarZero;
op[39] = &AGOSEngine::vc39_setVar;
op[40] = &AGOSEngine::vc40;
op[41] = &AGOSEngine::vc41;
op[42] = &AGOSEngine::vc42_delayIfNotEQ;
op[43] = &AGOSEngine::vc43_skipIfBitClear;
op[44] = &AGOSEngine::vc44_skipIfBitSet;
op[45] = &AGOSEngine::vc45_setSpriteX;
op[46] = &AGOSEngine::vc46_setSpriteY;
op[47] = &AGOSEngine::vc47_addToVar;
op[49] = &AGOSEngine::vc49_setBit;
op[50] = &AGOSEngine::vc50_clearBit;
op[51] = &AGOSEngine::vc51_enableBox;
op[52] = &AGOSEngine::vc52_playSound;
op[55] = &AGOSEngine::vc55_moveBox;
}
void AGOSEngine::setupElvira1VideoOpcodes(VgaOpcodeProc *op) {
op[1] = &AGOSEngine::vc1_fadeOut;
op[2] = &AGOSEngine::vc2_call;
op[3] = &AGOSEngine::vc3_loadSprite;
op[4] = &AGOSEngine::vc4_fadeIn;
op[5] = &AGOSEngine::vc5_skip_if_neq;
op[6] = &AGOSEngine::vc6_skip_ifn_sib_with_a;
op[7] = &AGOSEngine::vc7_skip_if_sib_with_a;
op[8] = &AGOSEngine::vc8_skip_if_parent_is;
op[9] = &AGOSEngine::vc9_skip_if_unk3_is;
op[10] = &AGOSEngine::vc10_draw;
op[13] = &AGOSEngine::vc12_delay;
op[14] = &AGOSEngine::vc13_addToSpriteX;
op[15] = &AGOSEngine::vc14_addToSpriteY;
op[16] = &AGOSEngine::vc15_sync;
op[17] = &AGOSEngine::vc16_waitSync;
op[18] = &AGOSEngine::vc17_waitEnd;
op[19] = &AGOSEngine::vc18_jump;
op[20] = &AGOSEngine::vc19_loop;
op[21] = &AGOSEngine::vc20_setRepeat;
op[22] = &AGOSEngine::vc21_endRepeat;
op[23] = &AGOSEngine::vc22_setPaletteOld;
op[24] = &AGOSEngine::vc23_setPriority;
op[25] = &AGOSEngine::vc24_setSpriteXY;
op[26] = &AGOSEngine::vc25_halt_sprite;
op[27] = &AGOSEngine::vc26_setSubWindow;
op[28] = &AGOSEngine::vc27_resetSprite;
op[29] = &AGOSEngine::vc28_playSFX;
op[30] = &AGOSEngine::vc29_stopAllSounds;
op[31] = &AGOSEngine::vc30_setFrameRate;
op[32] = &AGOSEngine::vc31_setWindow;
op[33] = &AGOSEngine::vc32_saveScreen;
op[34] = &AGOSEngine::vc33_setMouseOn;
op[35] = &AGOSEngine::vc34_setMouseOff;
op[38] = &AGOSEngine::vc35_clearWindow;
op[40] = &AGOSEngine::vc36_setWindowImage;
op[41] = &AGOSEngine::vc37_pokePalette;
op[51] = &AGOSEngine::vc38_skipIfVarZero;
op[52] = &AGOSEngine::vc39_setVar;
op[53] = &AGOSEngine::vc40;
op[54] = &AGOSEngine::vc41;
}
void AGOSEngine::setupElvira2VideoOpcodes(VgaOpcodeProc *op) {
setupCommonVideoOpcodes(op);
op[11] = &AGOSEngine::vc11;
op[17] = &AGOSEngine::vc17_waitEnd;
op[19] = &AGOSEngine::vc19_loop;
op[22] = &AGOSEngine::vc22_setPaletteOld;
op[28] = &AGOSEngine::vc28_playSFX;
op[32] = &AGOSEngine::vc32_saveScreen;
op[37] = &AGOSEngine::vc37_pokePalette;
op[45] = &AGOSEngine::vc45_setWindowPalette;
op[46] = &AGOSEngine::vc46_setPaletteSlot1;
op[47] = &AGOSEngine::vc47_setPaletteSlot2;
op[48] = &AGOSEngine::vc48_setPaletteSlot3;
op[53] = &AGOSEngine::vc53_dissolveIn;
op[54] = &AGOSEngine::vc54_dissolveOut;
op[57] = &AGOSEngine::vc57_blackPalette;
op[56] = &AGOSEngine::vc56_fullScreen;
op[59] = &AGOSEngine::vc59_skipIfNotEGA;
}
void AGOSEngine::setupWaxworksVideoOpcodes(VgaOpcodeProc *op) {
setupElvira2VideoOpcodes(op);
op[58] = &AGOSEngine::vc58_checkCodeWheel;
op[60] = &AGOSEngine::vc60_stopAnimation;
op[61] = &AGOSEngine::vc61;
op[62] = &AGOSEngine::vc62_fastFadeOut;
op[63] = &AGOSEngine::vc63_fastFadeIn;
}
void AGOSEngine::setupVgaOpcodes() {
memset(_vga_opcode_table, 0, sizeof(_vga_opcode_table));
switch (getGameType()) {
case GType_ELVIRA1:
setupElvira1VideoOpcodes(_vga_opcode_table);
break;
case GType_ELVIRA2:
setupElvira2VideoOpcodes(_vga_opcode_table);
break;
case GType_WW:
setupWaxworksVideoOpcodes(_vga_opcode_table);
break;
case GType_SIMON1:
setupSimon1VideoOpcodes(_vga_opcode_table);
break;
case GType_SIMON2:
setupSimon2VideoOpcodes(_vga_opcode_table);
break;
case GType_FF:
case GType_PP:
setupFeebleVideoOpcodes(_vga_opcode_table);
break;
default:
error("setupVgaOpcodes: Unknown game");
}
}
// Script parser
void AGOSEngine::runVgaScript() {
for (;;) {
uint opcode;
if (_continousVgaScript) {
if (_vcPtr != (const byte *)&_vc_get_out_of_code) {
printf("%.5d %.5X: %5d %4d ", _vgaTickCounter, (unsigned int)(_vcPtr - _curVgaFile1), _vgaCurSpriteId, _vgaCurZoneNum);
dumpVideoScript(_vcPtr, true);
}
}
if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) {
opcode = *_vcPtr++;
} else {
opcode = READ_BE_UINT16(_vcPtr);
_vcPtr += 2;
}
if (opcode == 0)
return;
debug(1, "runVgaScript: Video opcode %d", opcode);
if (opcode >= _numVideoOpcodes || !_vga_opcode_table[opcode])
error("Invalid VGA opcode '%d' encountered", opcode);
(this->*_vga_opcode_table[opcode]) ();
}
}
bool AGOSEngine::itemIsSiblingOf(uint16 a) {
Item *item;
CHECK_BOUNDS(a, _objectArray);
item = _objectArray[a];
if (item == NULL)
return true;
return me()->parent == item->parent;
}
bool AGOSEngine::itemIsParentOf(uint16 a, uint16 b) {
Item *item_a, *item_b;
CHECK_BOUNDS(a, _objectArray);
CHECK_BOUNDS(b, _objectArray);
item_a = _objectArray[a];
item_b = _objectArray[b];
if (item_a == NULL || item_b == NULL)
return true;
return derefItem(item_a->parent) == item_b;
}
bool AGOSEngine::isSpriteLoaded(uint16 id, uint16 zoneNum) {
VgaSprite *vsp = _vgaSprites;
while (vsp->id) {
if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) {
if (vsp->id == id && vsp->zoneNum == zoneNum)
return true;
} else {
if (vsp->id == id)
return true;
}
vsp++;
}
return false;
}
bool AGOSEngine::vc_maybe_skip_proc_1(uint16 a, int16 b) {
Item *item;
CHECK_BOUNDS(a, _objectArray);
item = _objectArray[a];
if (item == NULL)
return true;
return item->state == b;
}
VgaSprite *AGOSEngine::findCurSprite() {
VgaSprite *vsp = _vgaSprites;
while (vsp->id) {
if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) {
if (vsp->id == _vgaCurSpriteId && vsp->zoneNum == _vgaCurZoneNum)
break;
} else {
if (vsp->id == _vgaCurSpriteId)
break;
}
vsp++;
}
return vsp;
}
int AGOSEngine::vcReadVarOrWord() {
if (getGameType() == GType_ELVIRA1) {
return vcReadNextWord();
} else {
int16 var = vcReadNextWord();
if (var < 0)
var = vcReadVar(-var);
return var;
}
}
uint AGOSEngine::vcReadNextWord() {
uint a;
a = readUint16Wrapper(_vcPtr);
_vcPtr += 2;
return a;
}
uint AGOSEngine::vcReadNextByte() {
return *_vcPtr++;
}
uint AGOSEngine::vcReadVar(uint var) {
assert(var < _numVars);
return (uint16)_variableArrayPtr[var];
}
void AGOSEngine::vcWriteVar(uint var, int16 value) {
assert(var < _numVars);
_variableArrayPtr[var] = value;
}
void AGOSEngine::vcSkipNextInstruction() {
static const byte opcodeParamLenElvira1[] = {
0, 6, 2, 10, 6, 4, 2, 2,
4, 4, 8, 2, 0, 2, 2, 2,
2, 2, 2, 2, 0, 4, 2, 2,
2, 8, 0, 10, 0, 8, 0, 2,
2, 0, 0, 0, 0, 2, 4, 2,
4, 4, 0, 0, 2, 2, 2, 4,
4, 0, 18, 2, 4, 4, 4, 0,
4
};
static const byte opcodeParamLenWW[] = {
0, 6, 2, 10, 6, 4, 2, 2,
4, 4, 8, 2, 2, 2, 2, 2,
2, 2, 2, 0, 4, 2, 2, 2,
8, 0, 10, 0, 8, 0, 2, 2,
0, 0, 0, 4, 4, 4, 2, 4,
4, 4, 4, 2, 2, 4, 2, 2,
2, 2, 2, 2, 2, 4, 6, 6,
0, 0, 0, 0, 2, 2, 0, 0,
};
static const byte opcodeParamLenSimon1[] = {
0, 6, 2, 10, 6, 4, 2, 2,
4, 4, 10, 0, 2, 2, 2, 2,
2, 0, 2, 0, 4, 2, 4, 2,
8, 0, 10, 0, 8, 0, 2, 2,
4, 0, 0, 4, 4, 2, 2, 4,
4, 4, 4, 2, 2, 2, 2, 4,
0, 2, 2, 2, 2, 4, 6, 6,
0, 0, 0, 0, 2, 6, 0, 0,
};
static const byte opcodeParamLenSimon2[] = {
0, 6, 2, 12, 6, 4, 2, 2,
4, 4, 9, 0, 1, 2, 2, 2,
2, 0, 2, 0, 4, 2, 4, 2,
7, 0, 10, 0, 8, 0, 2, 2,
4, 0, 0, 4, 4, 2, 2, 4,
4, 4, 4, 2, 2, 2, 2, 4,
0, 2, 2, 2, 2, 4, 6, 6,
2, 0, 6, 6, 4, 6, 0, 0,
0, 0, 4, 4, 4, 4, 4, 0,
4, 2, 2
};
static const byte opcodeParamLenFeebleFiles[] = {
0, 6, 2, 12, 6, 4, 2, 2,
4, 4, 9, 0, 1, 2, 2, 2,
2, 0, 2, 0, 4, 2, 4, 2,
7, 0, 10, 0, 8, 0, 2, 2,
4, 0, 0, 4, 4, 2, 2, 4,
4, 4, 4, 2, 2, 2, 2, 4,
0, 2, 2, 2, 6, 6, 6, 6,
2, 0, 6, 6, 4, 6, 0, 0,
0, 0, 4, 4, 4, 4, 4, 0,
4, 2, 2, 4, 6, 6, 0, 0,
6, 4, 2, 6, 0
};
uint16 opcode;
if (getGameType() == GType_FF || getGameType() == GType_PP) {
opcode = vcReadNextByte();
_vcPtr += opcodeParamLenFeebleFiles[opcode];
} else if (getGameType() == GType_SIMON2) {
opcode = vcReadNextByte();
_vcPtr += opcodeParamLenSimon2[opcode];
} else if (getGameType() == GType_SIMON1) {
opcode = vcReadNextWord();
_vcPtr += opcodeParamLenSimon1[opcode];
} else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
opcode = vcReadNextWord();
_vcPtr += opcodeParamLenWW[opcode];
} else {
opcode = vcReadNextWord();
_vcPtr += opcodeParamLenElvira1[opcode];
}
if (_continousVgaScript)
printf("; skipped\n");
}
// VGA Script commands
void AGOSEngine::vc1_fadeOut() {
/* dummy opcode */
_vcPtr += 6;
}
void AGOSEngine::vc2_call() {
uint16 num;
byte *old_file_1, *old_file_2;
if (getGameType() == GType_ELVIRA2) {
num = vcReadNextWord();
} else {
num = vcReadVarOrWord();
}
old_file_1 = _curVgaFile1;
old_file_2 = _curVgaFile2;
setImage(num, false);
_curVgaFile1 = old_file_1;
_curVgaFile2 = old_file_2;
}
void AGOSEngine::vc3_loadSprite() {
uint16 windowNum, zoneNum, palette, x, y, vgaSpriteId;
byte *old_file_1;
if (getGameType() == GType_PP && getBitFlag(100)) {
startAnOverlayAnim();
return;
}
windowNum = vcReadNextWord(); /* 0 */
if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) {
zoneNum = vcReadNextWord(); /* 0 */
vgaSpriteId = vcReadNextWord(); /* 2 */
} else {
vgaSpriteId = vcReadNextWord(); /* 2 */
zoneNum = vgaSpriteId / 100;
}
x = vcReadNextWord(); /* 4 */
y = vcReadNextWord(); /* 6 */
palette = vcReadNextWord(); /* 8 */
old_file_1 = _curVgaFile1;
animate(windowNum, zoneNum, vgaSpriteId, x, y, palette, false);
_curVgaFile1 = old_file_1;
}
void AGOSEngine::vc4_fadeIn() {
/* dummy opcode */
_vcPtr += 6;
}
void AGOSEngine::vc5_skip_if_neq() {
uint16 var;
if (getGameType() == GType_PP)
var = vcReadVarOrWord();
else
var = vcReadNextWord();
uint16 value = vcReadNextWord();
if (vcReadVar(var) != value)
vcSkipNextInstruction();
}
void AGOSEngine::vc6_skip_ifn_sib_with_a() {
if (!itemIsSiblingOf(vcReadNextWord()))
vcSkipNextInstruction();
}
void AGOSEngine::vc7_skip_if_sib_with_a() {
if (itemIsSiblingOf(vcReadNextWord()))
vcSkipNextInstruction();
}
void AGOSEngine::vc8_skip_if_parent_is() {
uint16 a = vcReadNextWord();
uint16 b = vcReadNextWord();
if (!itemIsParentOf(a, b))
vcSkipNextInstruction();
}
void AGOSEngine::vc9_skip_if_unk3_is() {
uint16 a = vcReadNextWord();
uint16 b = vcReadNextWord();
if (!vc_maybe_skip_proc_1(a, b))
vcSkipNextInstruction();
}
byte *AGOSEngine::vc10_uncompressFlip(const byte *src, uint w, uint h) {
w *= 8;
byte *dst, *dstPtr, *srcPtr;
byte color;
int8 cur = -0x80;
uint i, w_cur = w;
dstPtr = _videoBuf1 + w;
do {
dst = dstPtr;
uint h_cur = h;
if (cur == -0x80)
cur = *src++;
for (;;) {
if (cur >= 0) {
/* rle_same */
color = *src++;
do {
*dst = color;
dst += w;
if (!--h_cur) {
if (--cur < 0)
cur = -0x80;
else
src--;
goto next_line;
}
} while (--cur >= 0);
} else {
/* rle_diff */
do {
*dst = *src++;
dst += w;
if (!--h_cur) {
if (++cur == 0)
cur = -0x80;
goto next_line;
}
} while (++cur != 0);
}
cur = *src++;
}
next_line:
dstPtr++;
} while (--w_cur);
srcPtr = dstPtr = _videoBuf1 + w;
do {
dst = dstPtr;
for (i = 0; i != w; ++i) {
byte b = srcPtr[i];
b = (b >> 4) | (b << 4);
*--dst = b;
}
srcPtr += w;
dstPtr += w;
} while (--h);
return _videoBuf1;
}
byte *AGOSEngine::vc10_flip(const byte *src, uint w, uint h) {
w *= 8;
byte *dstPtr;
uint i;
dstPtr = _videoBuf1 + w;
do {
byte *dst = dstPtr;
for (i = 0; i != w; ++i) {
byte b = src[i];
b = (b >> 4) | (b << 4);
*--dst = b;
}
src += w;
dstPtr += w;
} while (--h);
return _videoBuf1;
}
void AGOSEngine::vc10_draw() {
byte *p2;
uint width, height;
byte flags;
VC10_state state;
state.image = (int16)vcReadNextWord();
if (state.image == 0)
return;
if (getGameType() == GType_FF || getGameType() == GType_PP) {
state.palette = (_vcPtr[0] * 16);
_vcPtr += 2;
} else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
state.palette = (_vcPtr[1] * 16);
_vcPtr += 2;
} else {
state.palette = 0;
}
if (getFeatures() & GF_32COLOR) {
state.palette = 0;
}
state.x = (int16)vcReadNextWord();
state.x -= _scrollX;
state.y = (int16)vcReadNextWord();
state.y -= _scrollY;
if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) {
state.flags = vcReadNextByte();
} else {
state.flags = vcReadNextWord();
}
if (state.image < 0)
state.image = vcReadVar(-state.image);
p2 = _curVgaFile2 + state.image * 8;
state.depack_src = _curVgaFile2 + readUint32Wrapper(p2);
if (getGameType() == GType_FF || getGameType() == GType_PP) {
width = READ_LE_UINT16(p2 + 6);
height = READ_LE_UINT16(p2 + 4) & 0x7FFF;
flags = p2[5];
} else {
width = READ_BE_UINT16(p2 + 6) / 16;
height = p2[5];
flags = p2[4];
}
if (height == 0 || width == 0)
return;
if (_dumpImages)
dumpSingleBitmap(_vgaCurZoneNum, state.image, state.depack_src, width, height,
state.palette);
// Check if image is compressed
if (getGameType() == GType_FF || getGameType() == GType_PP) {
if (flags & 0x80) {
state.flags |= kDFCompressed;
}
} else {
if (flags & 0x80 && !(state.flags & kDFCompressedFlip)) {
if (state.flags & kDFFlip) {
state.flags &= ~kDFFlip;
state.flags |= kDFCompressedFlip;
} else {
state.flags |= kDFCompressed;
}
}
}
state.width = state.draw_width = width; /* cl */
state.height = state.draw_height = height; /* ch */
state.depack_cont = -0x80;
state.x_skip = 0; /* colums to skip = bh */
state.y_skip = 0; /* rows to skip = bl */
uint maxWidth = (getGameType() == GType_FF || getGameType() == GType_PP) ? 640 : 20;
if ((getGameType() == GType_SIMON2 || getGameType() == GType_FF) && width > maxWidth) {
horizontalScroll(&state);
return;
}
if (getGameType() == GType_FF && height > 480) {
verticalScroll(&state);
return;
}
if (getGameType() != GType_FF && getGameType() != GType_PP) {
if (state.flags & kDFCompressedFlip) {
state.depack_src = vc10_uncompressFlip(state.depack_src, width, height);
} else if (state.flags & kDFFlip) {
state.depack_src = vc10_flip(state.depack_src, width, height);
}
}
state.surf2_addr = getFrontBuf();
state.surf2_pitch = _dxSurfacePitch;
state.surf_addr = getBackBuf();
state.surf_pitch = _dxSurfacePitch;
if (getGameType() == GType_FF || getGameType() == GType_PP) {
drawImages_Feeble(&state);
} else {
drawImages(&state);
}
}
void AGOSEngine::vc11() {
uint a = vcReadNextWord();
debug(0, "vc11: stub (%d)", a);
}
void AGOSEngine::vc12_delay() {
VgaSprite *vsp = findCurSprite();
uint16 num;
if (getGameType() == GType_FF || getGameType() == GType_PP) {
num = vcReadNextByte();
} else if (getGameType() == GType_SIMON2) {
num = vcReadNextByte() * _frameRate;
} else {
num = vcReadVarOrWord() * _frameRate;
}
// Work around to allow inventory arrows to be
// shown in some versions of Simon the Sorcerer 1
if ((getGameType() == GType_SIMON1) && vsp->id == 128)
num = 0;
else
num += _vgaBaseDelay;
addVgaEvent(num, _vcPtr, _vgaCurSpriteId, _vgaCurZoneNum);
_vcPtr = (byte *)&_vc_get_out_of_code;
}
void AGOSEngine::vc13_addToSpriteX() {
VgaSprite *vsp = findCurSprite();
vsp->x += (int16)vcReadNextWord();
_vgaSpriteChanged++;
}
void AGOSEngine::vc14_addToSpriteY() {
VgaSprite *vsp = findCurSprite();
vsp->y += (int16)vcReadNextWord();
_vgaSpriteChanged++;
}
void AGOSEngine::vc15_sync() {
VgaSleepStruct *vfs = _waitSyncTable, *vfs_tmp;
uint16 id = vcReadNextWord();
while (vfs->ident != 0) {
if (vfs->ident == id) {
addVgaEvent(_vgaBaseDelay, vfs->code_ptr, vfs->sprite_id, vfs->cur_vga_file);
vfs_tmp = vfs;
do {
memcpy(vfs_tmp, vfs_tmp + 1, sizeof(VgaSleepStruct));
vfs_tmp++;
} while (vfs_tmp->ident != 0);
} else {
vfs++;
}
}
_lastVgaWaitFor = id;
/* clear a wait event */
if (id == _vgaWaitFor)
_vgaWaitFor = 0;
}
void AGOSEngine::vc16_waitSync() {
VgaSleepStruct *vfs = _waitSyncTable;
while (vfs->ident)
vfs++;
vfs->ident = vcReadNextWord();
vfs->code_ptr = _vcPtr;
vfs->sprite_id = _vgaCurSpriteId;
vfs->cur_vga_file = _vgaCurZoneNum;
_vcPtr = (byte *)&_vc_get_out_of_code;
}
void AGOSEngine::checkWaitEndTable() {
VgaSleepStruct *vfs = _waitEndTable, *vfs_tmp;
while (vfs->ident != 0) {
if (vfs->ident == _vgaCurSpriteId) {
addVgaEvent(_vgaBaseDelay, vfs->code_ptr, vfs->sprite_id, vfs->cur_vga_file);
vfs_tmp = vfs;
do {
memcpy(vfs_tmp, vfs_tmp + 1, sizeof(VgaSleepStruct));
vfs_tmp++;
} while (vfs_tmp->ident != 0);
} else {
vfs++;
}
}
}
void AGOSEngine::vc17_waitEnd() {
VgaSleepStruct *vfs = _waitEndTable;
while (vfs->ident)
vfs++;
vfs->ident = vcReadNextWord();
vfs->code_ptr = _vcPtr;
vfs->sprite_id = _vgaCurSpriteId;
vfs->cur_vga_file = _vgaCurZoneNum;
_vcPtr = (byte *)&_vc_get_out_of_code;
}
void AGOSEngine::vc18_jump() {
int16 offs = vcReadNextWord();
_vcPtr += offs;
}
void AGOSEngine::vc19_loop() {
uint16 count;
byte *b, *bb;
bb = _curVgaFile1;
b = _curVgaFile1 + READ_BE_UINT16(bb + 10);
b += 20;
count = READ_BE_UINT16(&((VgaFileHeader2_Common *) b)->animationCount);
b = bb + READ_BE_UINT16(&((VgaFileHeader2_Common *) b)->animationTable);
while (count--) {
if (READ_BE_UINT16(&((AnimationHeader_WW *) b)->id) == _vgaCurSpriteId)
break;
b += sizeof(AnimationHeader_WW);
}
assert(READ_BE_UINT16(&((AnimationHeader_WW *) b)->id) == _vgaCurSpriteId);
_vcPtr = _curVgaFile1 + READ_BE_UINT16(&((AnimationHeader_WW *) b)->scriptOffs);
}
void AGOSEngine::vc20_setRepeat() {
/* FIXME: This opcode is somewhat strange: it first reads a BE word from
* the script (advancing the script pointer in doing so); then it writes
* back the same word, this time as LE, into the script.
*/
uint16 a = vcReadNextWord();
WRITE_LE_UINT16(const_cast<byte *>(_vcPtr), a);
_vcPtr += 2;
}
void AGOSEngine::vc21_endRepeat() {
int16 a = vcReadNextWord();
const byte *tmp = _vcPtr + a;
if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP)
tmp += 3;
else
tmp += 4;
uint16 val = READ_LE_UINT16(tmp);
if (val != 0) {
// Decrement counter
WRITE_LE_UINT16(const_cast<byte *>(tmp), val - 1);
_vcPtr = tmp + 2;
}
}
void AGOSEngine::vc22_setPaletteOld() {
byte *offs, *palptr, *src;
uint16 b, num;
b = vcReadNextWord();
num = 16;
palptr = _displayPalette;
_bottomPalette = 1;
if (getGameType() == GType_ELVIRA1) {
if (b >= 1000) {
b -= 1000;
_bottomPalette = 0;
} else {
const byte extraColors[19 * 3] = {
40, 0, 0, 24, 24, 16, 48, 48, 40,
0, 0, 0, 16, 0, 0, 8, 8, 0,
48, 24, 0, 56, 40, 0, 0, 0, 24,
8, 16, 24, 24, 32, 40, 16, 24, 0,
24, 8, 0, 16, 16, 0, 40, 40, 32,
32, 32, 24, 40, 0, 0, 24, 24, 16,
48, 48, 40
};
num = 13;
for (int i = 0; i < 19; i++) {
palptr[(13 + i) * 4 + 0] = extraColors[i * 3 + 0] * 4;
palptr[(13 + i) * 4 + 1] = extraColors[i * 3 + 1] * 4;
palptr[(13 + i) * 4 + 2] = extraColors[i * 3 + 2] * 4;
palptr[(13 + i) * 4 + 3] = 0;
}
}
}
offs = _curVgaFile1 + READ_BE_UINT16(_curVgaFile1 + 6);
src = offs + b * 32;
do {
uint16 color = READ_BE_UINT16(src);
palptr[0] = ((color & 0xf00) >> 8) * 32;
palptr[1] = ((color & 0x0f0) >> 4) * 32;
palptr[2] = ((color & 0x00f) >> 0) * 32;
palptr[3] = 0;
palptr += 4;
src += 2;
} while (--num);
_paletteFlag = 2;
_vgaSpriteChanged++;
}
void AGOSEngine::vc23_setPriority() {
VgaSprite *vsp = findCurSprite(), *vus2;
uint16 pri = vcReadNextWord();
VgaSprite bak;
if (vsp->id == 0)
return;
memcpy(&bak, vsp, sizeof(bak));
bak.priority = pri;
bak.windowNum |= 0x8000;
vus2 = vsp;
if (vsp != _vgaSprites && pri < vsp[-1].priority) {
do {
vsp--;
} while (vsp != _vgaSprites && pri < vsp[-1].priority);
do {
memcpy(vus2, vus2 - 1, sizeof(VgaSprite));
} while (--vus2 != vsp);
memcpy(vus2, &bak, sizeof(VgaSprite));
} else if (vsp[1].id != 0 && pri >= vsp[1].priority) {
do {
vsp++;
} while (vsp[1].id != 0 && pri >= vsp[1].priority);
do {
memcpy(vus2, vus2 + 1, sizeof(VgaSprite));
} while (++vus2 != vsp);
memcpy(vus2, &bak, sizeof(VgaSprite));
} else {
vsp->priority = pri;
}
_vgaSpriteChanged++;
}
void AGOSEngine::vc24_setSpriteXY() {
VgaSprite *vsp = findCurSprite();
if (getGameType() == GType_ELVIRA2) {
vsp->image = vcReadNextWord();
} else {
vsp->image = vcReadVarOrWord();
}
vsp->x += (int16)vcReadNextWord();
vsp->y += (int16)vcReadNextWord();
if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) {
vsp->flags = vcReadNextByte();
} else {
vsp->flags = vcReadNextWord();
}
_vgaSpriteChanged++;
}
void AGOSEngine::vc25_halt_sprite() {
checkWaitEndTable();
VgaSprite *vsp = findCurSprite();
while (vsp->id != 0) {
memcpy(vsp, vsp + 1, sizeof(VgaSprite));
vsp++;
}
_vcPtr = (byte *)&_vc_get_out_of_code;
_vgaSpriteChanged++;
}
void AGOSEngine::vc26_setSubWindow() {
uint16 *as = &_videoWindows[vcReadNextWord() * 4]; // number
as[0] = vcReadNextWord(); // x
as[1] = vcReadNextWord(); // y
as[2] = vcReadNextWord(); // width
as[3] = vcReadNextWord(); // height
}
void AGOSEngine::vc27_resetSprite() {
VgaSprite bak, *vsp;
VgaSleepStruct *vfs;
VgaTimerEntry *vte, *vte2;
_lockWord |= 8;
_lastVgaWaitFor = 0;
memset(&bak, 0, sizeof(bak));
vsp = _vgaSprites;
while (vsp->id) {
if ((getGameType() == GType_SIMON1) && vsp->id == 128) {
memcpy(&bak, vsp, sizeof(VgaSprite));
}
vsp->id = 0;
vsp++;
}
if (bak.id != 0)
memcpy(_vgaSprites, &bak, sizeof(VgaSprite));
vfs = _waitEndTable;
while (vfs->ident) {
vfs->ident = 0;
vfs++;
}
vfs = _waitSyncTable;
while (vfs->ident) {
vfs->ident = 0;
vfs++;
}
vte = _vgaTimerList;
while (vte->delay) {
if ((getGameType() == GType_SIMON1) && vte->sprite_id == 128) {
vte++;
} else {
vte2 = vte;
while (vte2->delay) {
memcpy(vte2, vte2 + 1, sizeof(VgaTimerEntry));
vte2++;
}
}
}
vcWriteVar(254, 0);
if (getGameType() == GType_FF || getGameType() == GType_PP)
setBitFlag(42, true);
_lockWord &= ~8;
}
void AGOSEngine::vc28_playSFX() {
byte *dst;
uint sound, channels, frequency, flags;
uint offs, size;
sound = vcReadNextWord();
channels = vcReadNextWord();
frequency = vcReadNextWord();
flags = vcReadNextWord();
debug(0, "vc28_playSFX: (%d, %d, %d, %d)", sound, channels, frequency, flags);
if (_curSfxFile == NULL)
return;
dst = _curSfxFile;
if (getGameType() == GType_WW) {
uint tmp = sound;
while (tmp--)
dst += READ_LE_UINT16(dst) + 4;
size = READ_LE_UINT16(dst);
offs = 4;
} else {
while (READ_BE_UINT16(dst + 6) != sound)
dst += 12;
size = READ_BE_UINT16(dst + 2);
offs = READ_BE_UINT32(dst + 8);
}
_sound->playRawData(dst + offs, sound, size);
}
void AGOSEngine::vc29_stopAllSounds() {
if (getGameType() != GType_PP)
_sound->stopVoice();
_sound->stopAllSfx();
}
void AGOSEngine::vc30_setFrameRate() {
_frameRate = vcReadNextWord();
}
void AGOSEngine::vc31_setWindow() {
_windowNum = vcReadNextWord();
}
void AGOSEngine::vc32_saveScreen() {
// TODO
debug(0, "vc32_saveScreen: stub");
}
void AGOSEngine::vc33_setMouseOn() {
if (_mouseHideCount != 0) {
_mouseHideCount = 1;
mouseOn();
}
}
void AGOSEngine::vc34_setMouseOff() {
mouseOff();
_mouseHideCount = 200;
_leftButtonDown = 0;
}
void AGOSEngine::clearWindow(uint num, uint color) {
if (getGameType() == GType_ELVIRA1) {
if (num == 2 || num == 6)
return;
} else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
if (num != 4 && num < 10)
return;
}
if (num == 3) {
memset(getBackBuf(), 0, _screenWidth * _screenHeight);
} else {
const uint16 *vlut = &_videoWindows[num * 4];
byte *dst = getBackBuf() + vlut[0] * 16 + vlut[1] * _dxSurfacePitch;
for (uint h = 0; h < vlut[3]; h++) {
memset(dst, 0, vlut[2] * 16);
dst += _screenWidth;
}
}
}
void AGOSEngine::vc35_clearWindow() {
uint16 num = vcReadNextWord();
uint16 color = vcReadNextWord();
clearWindow(num, color);
}
void AGOSEngine::vc36_setWindowImage() {
_updateScreen = false;
uint16 vga_res = vcReadNextWord();
uint16 windowNum = vcReadNextWord();
if (getGameType() == GType_FF || getGameType() == GType_PP) {
_copyPartialMode = 2;
} else if (getGameType() == GType_SIMON1) {
if (windowNum == 16) {
_copyPartialMode = 2;
} else {
setWindowImage(windowNum, vga_res);
}
} else {
setWindowImage(windowNum, vga_res);
}
}
void AGOSEngine::vc37_pokePalette() {
// TODO
uint a = vcReadNextWord();
uint b = vcReadNextWord();
debug(0, "vc37_pokePalette: stub (%d, %d)", a, b);
}
void AGOSEngine::vc38_skipIfVarZero() {
uint16 var;
if (getGameType() == GType_PP)
var = vcReadVarOrWord();
else
var = vcReadNextWord();
if (vcReadVar(var) == 0)
vcSkipNextInstruction();
}
void AGOSEngine::vc39_setVar() {
uint16 var;
if (getGameType() == GType_PP)
var = vcReadVarOrWord();
else
var = vcReadNextWord();
int16 value = vcReadNextWord();
vcWriteVar(var, value);
}
void AGOSEngine::vc40() {
uint16 var = vcReadNextWord();
int16 value = vcReadVar(var) + vcReadNextWord();
if ((getGameType() == GType_SIMON2) && var == 15 && !getBitFlag(80)) {
int16 tmp;
if (_scrollCount != 0) {
if (_scrollCount >= 0)
goto no_scroll;
_scrollCount = 0;
} else {
if (_scrollFlag != 0)
goto no_scroll;
}
if (value - _scrollX >= 30) {
_scrollCount = 20;
tmp = _scrollXMax - _scrollX;
if (tmp < 20)
_scrollCount = tmp;
addVgaEvent(6, NULL, 0, 0); /* scroll event */
}
}
no_scroll:;
vcWriteVar(var, value);
}
void AGOSEngine::vc41() {
uint16 var = vcReadNextWord();
int16 value = vcReadVar(var) - vcReadNextWord();
if ((getGameType() == GType_SIMON2) && var == 15 && !getBitFlag(80)) {
if (_scrollCount != 0) {
if (_scrollCount < 0)
goto no_scroll;
_scrollCount = 0;
} else {
if (_scrollFlag != 0)
goto no_scroll;
}
if ((uint16)(value - _scrollX) < 11) {
_scrollCount = -20;
if (_scrollX < 20)
_scrollCount = -_scrollX;
addVgaEvent(6, NULL, 0, 0); /* scroll event */
}
}
no_scroll:;
vcWriteVar(var, value);
}
void AGOSEngine::vc42_delayIfNotEQ() {
uint16 val = vcReadVar(vcReadNextWord());
if (val != vcReadNextWord()) {
addVgaEvent(_frameRate + 1, _vcPtr - 4, _vgaCurSpriteId, _vgaCurZoneNum);
_vcPtr = (byte *)&_vc_get_out_of_code;
}
}
void AGOSEngine::vc43_skipIfBitClear() {
if (!getBitFlag(vcReadNextWord())) {
vcSkipNextInstruction();
}
}
void AGOSEngine::vc44_skipIfBitSet() {
if (getBitFlag(vcReadNextWord())) {
vcSkipNextInstruction();
}
}
void AGOSEngine::vc45_setWindowPalette() {
uint num = vcReadNextWord();
uint color = vcReadNextWord();
const uint16 *vlut = &_videoWindows[num * 4];
uint16 *dst = (uint16 *)getBackBuf() + vlut[0] * 8 + vlut[1] * _dxSurfacePitch / 2;
for (uint h = 0; h < vlut[3]; h++) {
uint width = vlut[2] * 8;
for (uint w = 0; w < width; w++) {
dst[w] &= 0xF0F;
dst[w] |= color * 16;
}
dst += _dxSurfacePitch / 2;
}
}
void AGOSEngine::setPaletteSlot(uint srcOffs, uint dstOffs) {
byte *offs, *palptr, *src;
uint16 num;
palptr = _displayPalette + dstOffs * 64;
offs = _curVgaFile1 + READ_BE_UINT16(_curVgaFile1 + 6);
src = offs + srcOffs * 32;
num = 16;
do {
uint16 color = READ_BE_UINT16(src);
palptr[0] = ((color & 0xf00) >> 8) * 32;
palptr[1] = ((color & 0x0f0) >> 4) * 32;
palptr[2] = ((color & 0x00f) >> 0) * 32;
palptr[3] = 0;
palptr += 4;
src += 2;
} while (--num);
_paletteFlag = 2;
}
void AGOSEngine::vc46_setPaletteSlot1() {
uint srcOffs = vcReadNextWord();
setPaletteSlot(srcOffs, 1);
}
void AGOSEngine::vc47_setPaletteSlot2() {
uint srcOffs = vcReadNextWord();
setPaletteSlot(srcOffs, 2);
}
void AGOSEngine::vc48_setPaletteSlot3() {
uint srcOffs = vcReadNextWord();
setPaletteSlot(srcOffs, 3);
}
void AGOSEngine::setBitFlag(uint bit, bool value) {
uint16 *bits = &_bitArray[bit / 16];
*bits = (*bits & ~(1 << (bit & 15))) | (value << (bit & 15));
}
bool AGOSEngine::getBitFlag(uint bit) {
uint16 *bits = &_bitArray[bit / 16];
return (*bits & (1 << (bit & 15))) != 0;
}
void AGOSEngine::vc49_setBit() {
uint16 bit = vcReadNextWord();
if (getGameType() == GType_FF && bit == 82) {
_variableArrayPtr = _variableArray2;
}
setBitFlag(bit, true);
}
void AGOSEngine::vc50_clearBit() {
uint16 bit = vcReadNextWord();
if (getGameType() == GType_FF && bit == 82) {
_variableArrayPtr = _variableArray;
}
setBitFlag(bit, false);
}
void AGOSEngine::vc51_enableBox() {
enableBox(vcReadNextWord());
}
void AGOSEngine::vc52_playSound() {
bool ambient = false;
uint16 sound = vcReadNextWord();
if (sound >= 0x8000) {
ambient = true;
sound = -sound;
}
if (getGameType() == GType_FF || getGameType() == GType_PP) {
int16 pan = vcReadNextWord();
int16 vol = vcReadNextWord();
if (ambient)
loadSound(sound, pan, vol, 2);
else
loadSound(sound, pan, vol, 1);
} else if (getGameType() == GType_SIMON2) {
if (ambient)
_sound->playAmbient(sound);
else
_sound->playEffects(sound);
} else if (getFeatures() & GF_TALKIE) {
_sound->playEffects(sound);
} else if (getGameId() == GID_SIMON1DOS) {
playSting(sound);
}
}
void AGOSEngine::vc53_dissolveIn() {
// TODO
uint num = vcReadNextWord();
uint speed = vcReadNextWord();
debug(0, "vc53_dissolveIn: stub (%d, %d)", num, speed);
}
void AGOSEngine::vc54_dissolveOut() {
// TODO
uint num = vcReadNextWord();
uint color = vcReadNextWord();
uint speed = vcReadNextWord();
debug(0, "vc54_dissolveOut: stub (%d, %d, %d)", num, color, speed);
}
void AGOSEngine::vc55_moveBox() {
HitArea *ha = _hitAreas;
uint count = ARRAYSIZE(_hitAreas);
uint16 id = vcReadNextWord();
int16 x = vcReadNextWord();
int16 y = vcReadNextWord();
for (;;) {
if (ha->id == id) {
ha->x += x;
ha->y += y;
break;
}
ha++;
if (!--count)
break;
}
_needHitAreaRecalc++;
}
void AGOSEngine::vc56_fullScreen() {
byte *src = _curVgaFile2 + 32;
byte *dst = getBackBuf();
memcpy(dst, src + 768, _screenHeight * _screenWidth);
//fullFade();
uint8 palette[1024];
for (int i = 0; i < 256; i++) {
palette[i * 4 + 0] = *src++ * 4;
palette[i * 4 + 1] = *src++ * 4;
palette[i * 4 + 2] = *src++ * 4;
palette[i * 4 + 3] = 0;
}
_system->setPalette(palette, 0, 256);
}
void AGOSEngine::vc57_blackPalette() {
uint8 palette[1024];
memset(palette, 0, sizeof(palette));
_system->setPalette(palette, 0, 256);
}
void AGOSEngine::vc58_checkCodeWheel() {
// TODO
debug(0, "vc58_checkCodeWheel: stub");
}
void AGOSEngine::vc59_skipIfNotEGA() {
// Skip if not EGA
vcSkipNextInstruction();
}
void AGOSEngine::vcStopAnimation(uint file, uint sprite) {
uint16 old_sprite_id, old_cur_file_id;
VgaSleepStruct *vfs;
VgaSprite *vsp;
VgaTimerEntry *vte;
const byte *vcPtrOrg;
old_sprite_id = _vgaCurSpriteId;
old_cur_file_id = _vgaCurZoneNum;
vcPtrOrg = _vcPtr;
_vgaCurZoneNum = file;
_vgaCurSpriteId = sprite;
vfs = _waitSyncTable;
while (vfs->ident != 0) {
if (vfs->sprite_id == _vgaCurSpriteId && ((getGameType() == GType_SIMON1) || vfs->cur_vga_file == _vgaCurZoneNum)) {
while (vfs->ident != 0) {
memcpy(vfs, vfs + 1, sizeof(VgaSleepStruct));
vfs++;
}
break;
}
vfs++;
}
vsp = findCurSprite();
if (vsp->id) {
vc25_halt_sprite();
vte = _vgaTimerList;
while (vte->delay != 0) {
if (vte->sprite_id == _vgaCurSpriteId && ((getGameType() == GType_SIMON1) || vte->cur_vga_file == _vgaCurZoneNum)) {
deleteVgaEvent(vte);
break;
}
vte++;
}
}
_vgaCurZoneNum = old_cur_file_id;
_vgaCurSpriteId = old_sprite_id;
_vcPtr = vcPtrOrg;
}
void AGOSEngine::vc60_stopAnimation() {
uint16 sprite, zoneNum;
if (getGameType() == GType_PP) {
zoneNum = vcReadNextWord();
sprite = vcReadVarOrWord();
} else if (getGameType() == GType_SIMON2 || getGameType() == GType_FF) {
zoneNum = vcReadNextWord();
sprite = vcReadNextWord();
} else {
zoneNum = _vgaCurZoneNum;
sprite = vcReadNextWord();
}
vcStopAnimation(zoneNum, sprite);
}
void AGOSEngine::vc61() {
uint16 a = vcReadNextWord();
byte *src, *dst, *dstPtr;
uint h, tmp;
if (a == 6) {
src = _curVgaFile2 + 800;
dstPtr = getBackBuf();
memcpy(dstPtr, src, 64000);
tmp = 4 - 1;
} else {
dstPtr = getFrontBuf();
tmp = a - 1;
}
src = _curVgaFile2 + 3840 * 16 + 3360;
while (tmp--)
src += 1536 * 16 + 1712;
src += 800;
if (a != 5) {
dst = dstPtr + 7448;
for (h = 0; h < 177; h++) {
memcpy(dst, src, 144);
src += 144;
dst += _screenWidth;
}
if (a != 6)
return;
src = _curVgaFile2 + 9984 * 16 + 15344;
}
dst = dstPtr + 50296;
for (h = 0; h < 17; h++) {
memcpy(dst, src, 208);
src += 208;
dst += _screenWidth;
}
if (a == 6) {
//fullFade();
src = _curVgaFile2 + 32;
uint8 palette[1024];
for (int i = 0; i < 256; i++) {
palette[i * 4 + 0] = *src++ * 4;
palette[i * 4 + 1] = *src++ * 4;
palette[i * 4 + 2] = *src++ * 4;
palette[i * 4 + 3] = 0;
}
_system->setPalette(palette, 0, 256);
}
}
void AGOSEngine::vc62_fastFadeOut() {
vc29_stopAllSounds();
if (!_fastFadeOutFlag) {
uint i, fadeSize, fadeCount;
//if (getGameType() != GType_WW)
// _fastFadeOutFlag = true;
_fastFadeCount = 256;
if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
if (_windowNum == 4)
_fastFadeCount = 208;
}
memcpy(_videoBuf1, _currentPalette, _fastFadeCount * 4);
if ((getGameType() == GType_FF || getGameType() == GType_PP) && !getBitFlag(75)) {
fadeCount = 32;
fadeSize = 8;
} else {
fadeCount = 4;
fadeSize = 64;
}
for (i = fadeCount; i != 0; --i) {
paletteFadeOut(_videoBuf1, _fastFadeCount, fadeSize);
_system->setPalette(_videoBuf1, 0, _fastFadeCount);
delay(5);
}
if (getGameType() == GType_SIMON1) {
uint16 params[5]; /* parameters to vc10_draw */
VgaSprite *vsp;
VgaPointersEntry *vpe;
const byte *vcPtrOrg = _vcPtr;
vsp = _vgaSprites;
while (vsp->id != 0) {
if (vsp->id == 128) {
byte *old_file_1 = _curVgaFile1;
byte *old_file_2 = _curVgaFile2;
uint palmode = _windowNum;
vpe = &_vgaBufferPointers[vsp->zoneNum];
_curVgaFile1 = vpe->vgaFile1;
_curVgaFile2 = vpe->vgaFile2;
_windowNum = vsp->windowNum;
params[0] = READ_BE_UINT16(&vsp->image);
params[1] = READ_BE_UINT16(&vsp->palette);
params[2] = READ_BE_UINT16(&vsp->x);
params[3] = READ_BE_UINT16(&vsp->y);
params[4] = READ_BE_UINT16(&vsp->flags);
_vcPtr = (byte *)params;
vc10_draw();
_windowNum = palmode;
_curVgaFile1 = old_file_1;
_curVgaFile2 = old_file_2;
break;
}
vsp++;
}
_vcPtr = vcPtrOrg;
}
// Allow one section of Simon the Sorcerer 1 introduction to be displayed
// in lower half of screen
if ((getGameType() == GType_SIMON1) && (_subroutine == 2923 || _subroutine == 2926)) {
clearSurfaces(200);
} else if (getGameType() == GType_FF || getGameType() == GType_PP) {
clearSurfaces(480);
} else {
clearSurfaces(_windowNum == 4 ? 134 : 200);
}
}
if (getGameType() == GType_SIMON2) {
if (_nextMusicToPlay != -1)
loadMusic(_nextMusicToPlay);
}
}
void AGOSEngine::vc63_fastFadeIn() {
if (getGameType() == GType_PP) {
_fastFadeInFlag = 256;
if (getBitFlag(100)) {
startOverlayAnims();
} else if (getBitFlag(103)) {
printf("NameAndTime\n");
} else if (getBitFlag(104)) {
printf("HiScoreTable\n");
}
} else if (getGameType() == GType_FF) {
_fastFadeInFlag = 256;
} else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
_fastFadeInFlag = 208;
if (_windowNum != 4) {
_fastFadeInFlag = 256;
}
}
_fastFadeOutFlag = false;
}
void AGOSEngine::animate(uint windowNum, uint zoneNum, uint vgaSpriteId, uint x, uint y, uint palette, bool setZone) {
VgaSprite *vsp;
VgaPointersEntry *vpe;
byte *p, *pp;
uint count;
if (isSpriteLoaded(vgaSpriteId, zoneNum))
return;
vsp = _vgaSprites;
while (vsp->id != 0)
vsp++;
vsp->windowNum = windowNum;
vsp->priority = 0;
vsp->flags = 0;
vsp->y = y;
vsp->x = x;
vsp->image = 0;
if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW)
vsp->palette = 0;
else
vsp->palette = palette;
vsp->id = vgaSpriteId;
if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP)
vsp->zoneNum = zoneNum;
else
vsp->zoneNum = zoneNum = vgaSpriteId / 100;
for (;;) {
vpe = &_vgaBufferPointers[zoneNum];
_curVgaFile1 = vpe->vgaFile1;
if (setZone) {
_zoneNumber = zoneNum;
if (vpe->vgaFile1 != NULL)
break;
loadZone(zoneNum);
} else {
if (vpe->vgaFile1 != NULL)
break;
if (_zoneNumber != zoneNum)
_noOverWrite = _zoneNumber;
loadZone(zoneNum);
_noOverWrite = 0xFFFF;
}
}
pp = _curVgaFile1;
if (getGameType() == GType_FF || getGameType() == GType_PP) {
p = pp + READ_LE_UINT16(pp + 2);
count = READ_LE_UINT16(&((VgaFileHeader2_Feeble *) p)->animationCount);
p = pp + READ_LE_UINT16(&((VgaFileHeader2_Feeble *) p)->animationTable);
while (count--) {
if (READ_LE_UINT16(&((AnimationHeader_Feeble *) p)->id) == vgaSpriteId)
break;
p += sizeof(AnimationHeader_Feeble);
}
assert(READ_LE_UINT16(&((AnimationHeader_Feeble *) p)->id) == vgaSpriteId);
} else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
p = pp + READ_BE_UINT16(pp + 4);
count = READ_BE_UINT16(&((VgaFileHeader2_Common *) p)->animationCount);
p = pp + READ_BE_UINT16(&((VgaFileHeader2_Common *) p)->animationTable);
while (count--) {
if (READ_BE_UINT16(&((AnimationHeader_Simon *) p)->id) == vgaSpriteId)
break;
p += sizeof(AnimationHeader_Simon);
}
assert(READ_BE_UINT16(&((AnimationHeader_Simon *) p)->id) == vgaSpriteId);
} else {
p = pp + READ_BE_UINT16(pp + 10);
p += 20;
count = READ_BE_UINT16(&((VgaFileHeader2_Common *) p)->animationCount);
p = pp + READ_BE_UINT16(&((VgaFileHeader2_Common *) p)->animationTable);
while (count--) {
if (READ_BE_UINT16(&((AnimationHeader_WW *) p)->id) == vgaSpriteId)
break;
p += sizeof(AnimationHeader_WW);
}
assert(READ_BE_UINT16(&((AnimationHeader_WW *) p)->id) == vgaSpriteId);
}
#ifdef DUMP_FILE_NR
{
static bool dumped = false;
if (res == DUMP_FILE_NR && !dumped) {
dumped = true;
dumpVgaFile(_curVgaFile1);
}
}
#endif
#ifdef DUMP_BITMAPS_FILE_NR
{
static bool dumped = false;
if (res == DUMP_BITMAPS_FILE_NR && !dumped) {
dumped = true;
dumpVgaBitmaps(_curVgaFile2, _curVgaFile1, zoneNum);
}
}
#endif
if (_startVgaScript) {
if (getGameType() == GType_FF || getGameType() == GType_PP) {
dumpVgaScript(_curVgaFile1 + READ_LE_UINT16(&((AnimationHeader_Feeble*)p)->scriptOffs), zoneNum, vgaSpriteId);
} else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
dumpVgaScript(_curVgaFile1 + READ_BE_UINT16(&((AnimationHeader_Simon*)p)->scriptOffs), zoneNum, vgaSpriteId);
} else {
dumpVgaScript(_curVgaFile1 + READ_BE_UINT16(&((AnimationHeader_WW*)p)->scriptOffs), zoneNum, vgaSpriteId);
}
}
if (getGameType() == GType_FF || getGameType() == GType_PP) {
addVgaEvent(_vgaBaseDelay, _curVgaFile1 + READ_LE_UINT16(&((AnimationHeader_Feeble *) p)->scriptOffs), vgaSpriteId, zoneNum);
} else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
addVgaEvent(_vgaBaseDelay, _curVgaFile1 + READ_BE_UINT16(&((AnimationHeader_Simon *) p)->scriptOffs), vgaSpriteId, zoneNum);
} else {
addVgaEvent(_vgaBaseDelay, _curVgaFile1 + READ_BE_UINT16(&((AnimationHeader_WW *) p)->scriptOffs), vgaSpriteId, zoneNum);
}
}
void AGOSEngine::setImage(uint16 vga_res_id, bool setZone) {
uint zoneNum;
VgaPointersEntry *vpe;
byte *bb, *b;
uint16 count;
const byte *vc_ptr_org;
zoneNum = vga_res_id / 100;
for (;;) {
vpe = &_vgaBufferPointers[zoneNum];
_curVgaFile1 = vpe->vgaFile1;
_curVgaFile2 = vpe->vgaFile2;
if (setZone) {
_curSfxFile = vpe->sfxFile;
_zoneNumber = zoneNum;
if (vpe->vgaFile1 != NULL)
break;
loadZone(zoneNum);
} else {
if (vpe->vgaFile1 != NULL)
break;
if (_zoneNumber != zoneNum)
_noOverWrite = _zoneNumber;
loadZone(zoneNum);
_noOverWrite = 0xFFFF;
}
}
bb = _curVgaFile1;
if (getGameType() == GType_FF || getGameType() == GType_PP) {
b = bb + READ_LE_UINT16(bb + 2);
count = READ_LE_UINT16(&((VgaFileHeader2_Feeble *) b)->imageCount);
b = bb + READ_LE_UINT16(&((VgaFileHeader2_Feeble *) b)->imageTable);
while (count--) {
if (READ_LE_UINT16(&((ImageHeader_Feeble *) b)->id) == vga_res_id)
break;
b += sizeof(ImageHeader_Feeble);
}
assert(READ_LE_UINT16(&((ImageHeader_Feeble *) b)->id) == vga_res_id);
} else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
b = bb + READ_BE_UINT16(bb + 4);
count = READ_BE_UINT16(&((VgaFileHeader2_Common *) b)->imageCount);
b = bb + READ_BE_UINT16(&((VgaFileHeader2_Common *) b)->imageTable);
while (count--) {
if (READ_BE_UINT16(&((ImageHeader_Simon *) b)->id) == vga_res_id)
break;
b += sizeof(ImageHeader_Simon);
}
assert(READ_BE_UINT16(&((ImageHeader_Simon *) b)->id) == vga_res_id);
} else {
b = bb + READ_BE_UINT16(bb + 10);
b += 20;
count = READ_BE_UINT16(&((VgaFileHeader2_Common *) b)->imageCount);
b = bb + READ_BE_UINT16(&((VgaFileHeader2_Common *) b)->imageTable);
while (count--) {
if (READ_BE_UINT16(&((ImageHeader_WW *) b)->id) == vga_res_id)
break;
b += sizeof(ImageHeader_WW);
}
assert(READ_BE_UINT16(&((ImageHeader_WW *) b)->id) == vga_res_id);
clearWindow(_windowNum, READ_BE_UINT16(&((ImageHeader_WW *) b)->color));
}
if (_startVgaScript) {
if (getGameType() == GType_FF || getGameType() == GType_PP) {
dumpVgaScript(_curVgaFile1 + READ_LE_UINT16(&((ImageHeader_Feeble*)b)->scriptOffs), zoneNum, vga_res_id);
} else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
dumpVgaScript(_curVgaFile1 + READ_BE_UINT16(&((ImageHeader_Simon*)b)->scriptOffs), zoneNum, vga_res_id);
} else {
dumpVgaScript(_curVgaFile1 + READ_BE_UINT16(&((ImageHeader_WW*)b)->scriptOffs), zoneNum, vga_res_id);
}
}
vc_ptr_org = _vcPtr;
if (getGameType() == GType_FF || getGameType() == GType_PP) {
_vcPtr = _curVgaFile1 + READ_LE_UINT16(&((ImageHeader_Feeble *) b)->scriptOffs);
} else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
_vcPtr = _curVgaFile1 + READ_BE_UINT16(&((ImageHeader_Simon *) b)->scriptOffs);
} else {
_vcPtr = _curVgaFile1 + READ_BE_UINT16(&((ImageHeader_WW *) b)->scriptOffs);
}
runVgaScript();
_vcPtr = vc_ptr_org;
}
void AGOSEngine::setWindowImage(uint16 mode, uint16 vga_res_id) {
uint num_lines;
uint16 updateWindow;
_windowNum = updateWindow = mode;
_lockWord |= 0x20;
if (getGameType() == GType_FF || getGameType() == GType_PP) {
vc27_resetSprite();
}
if (vga_res_id == 0) {
if (getGameType() == GType_SIMON1) {
_unkPalFlag = true;
} else if (getGameType() == GType_SIMON2) {
_useBackGround = true;
_restoreWindow6 = true;
}
}
if (getGameType() == GType_SIMON1) {
if (vga_res_id == 16300) {
clearBackFromTop(134);
_usePaletteDelay = true;
}
} else if (getGameType() == GType_SIMON2 || getGameType() == GType_FF) {
_scrollX = 0;
_scrollY = 0;
_scrollXMax = 0;
_scrollYMax = 0;
_scrollCount = 0;
_scrollFlag = 0;
_scrollHeight = 134;
_variableArrayPtr = _variableArray;
if (_variableArray[34] >= 0) {
if (getGameType() == GType_FF)
_variableArray[250] = 0;
_variableArray[251] = 0;
}
}
setImage(vga_res_id, true);
if (getGameType() == GType_FF || getGameType() == GType_PP) {
fillFrontFromBack(0, 0, _screenWidth, _screenHeight);
fillBackGroundFromBack(_screenHeight);
_syncFlag2 = 1;
} else if (getGameType() == GType_SIMON2) {
if (!_useBackGround) {
num_lines = _windowNum == 4 ? 134 : 200;
_boxStarHeight = num_lines;
fillFrontFromBack(0, 0, _screenWidth, num_lines);
fillBackGroundFromBack(num_lines);
_syncFlag2 = 1;
}
_useBackGround = false;
} else if (getGameType() == GType_SIMON1) {
// Allow one section of Simon the Sorcerer 1 introduction to be displayed
// in lower half of screen
if (_subroutine == 2923 || _subroutine == 2926)
num_lines = 200;
else
num_lines = _windowNum == 4 ? 134 : 200;
fillFrontFromBack(0, 0, _screenWidth, num_lines);
fillBackGroundFromBack(num_lines);
_syncFlag2 = 1;
_timer5 = 0;
} else {
num_lines = _windowNum == 4 ? 134 : 200;
fillFrontFromBack(0, 0, _screenWidth, num_lines);
fillBackGroundFromBack(num_lines);
_syncFlag2 = 1;
_timer5 = 0;
}
if (getGameType() == GType_ELVIRA1 && updateWindow == 3 && _bottomPalette != 0) {
byte *dst = getBackBuf() + 42560;
int size = 21440;
while (size--) {
*dst += 0x10;
dst++;
}
}
_lockWord &= ~0x20;
if (getGameType() == GType_SIMON1) {
if (_unkPalFlag) {
_unkPalFlag = false;
while (_fastFadeInFlag != 0) {
delay(10);
}
}
}
}
void AGOSEngine::waitForSync(uint a) {
const uint maxCount = (getGameType() == GType_SIMON1) ? 500 : 1000;
if (getGameType() == GType_SIMON1 && (getFeatures() & GF_TALKIE)) {
if (a != 200) {
uint16 tmp = _lastVgaWaitFor;
_lastVgaWaitFor = 0;
if (tmp == a)
return;
}
}
_vgaWaitFor = a;
_syncCount = 0;
_exitCutscene = false;
_rightButtonDown = false;
while (_vgaWaitFor != 0) {
if (_rightButtonDown) {
if (_vgaWaitFor == 200 && (getGameType() == GType_FF || !getBitFlag(14))) {
skipSpeech();
break;
}
}
if (_exitCutscene) {
if (getGameType() == GType_ELVIRA1) {
if (_variableArray[105] == 0) {
_variableArray[105] = 255;
break;
}
} else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
if (_vgaWaitFor == 51) {
setBitFlag(244, 1);
break;
}
} else {
if (getBitFlag(9)) {
endCutscene();
break;
}
}
}
processSpecialKeys();
if (_syncCount >= maxCount) {
warning("waitForSync: wait timed out");
break;
}
delay(1);
}
}
} // End of namespace AGOS