scummvm/simon/vga.cpp

2034 lines
45 KiB
C++
Raw Normal View History

/* ScummVM - Scumm Interpreter
2005-01-01 16:09:25 +00:00
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Header$
*
*/
// Video script opcodes for Simon1/Simon2
#include "common/stdafx.h"
2002-08-21 16:07:07 +00:00
#include "simon/simon.h"
#include "simon/intern.h"
#include "simon/vga.h"
#include "common/system.h"
2003-10-03 19:42:27 +00:00
namespace Simon {
// Opcode tables
void SimonEngine::setupVgaOpcodes() {
static const VgaOpcodeProc vga_opcode_table[] = {
NULL,
&SimonEngine::vc1_fadeOut,
&SimonEngine::vc2_call,
&SimonEngine::vc3_loadSprite,
&SimonEngine::vc4_fadeIn,
&SimonEngine::vc5_skip_if_neq,
&SimonEngine::vc6_skip_ifn_sib_with_a,
&SimonEngine::vc7_skip_if_sib_with_a,
&SimonEngine::vc8_skip_if_parent_is,
&SimonEngine::vc9_skip_if_unk3_is,
&SimonEngine::vc10_draw,
&SimonEngine::vc11_clearPathFinder,
&SimonEngine::vc12_delay,
&SimonEngine::vc13_addToSpriteX,
&SimonEngine::vc14_addToSpriteY,
&SimonEngine::vc15_wakeup_id,
&SimonEngine::vc16_sleep_on_id,
&SimonEngine::vc17_setPathfinderItem,
&SimonEngine::vc18_jump,
&SimonEngine::vc19_chain_to_script,
&SimonEngine::vc20_setRepeat,
&SimonEngine::vc21_endRepeat,
&SimonEngine::vc22_setSpritePalette,
&SimonEngine::vc23_setSpritePriority,
&SimonEngine::vc24_setSpriteXY,
&SimonEngine::vc25_halt_sprite,
&SimonEngine::vc26_setSubWindow,
&SimonEngine::vc27_resetSprite,
&SimonEngine::vc28_dummy_op,
&SimonEngine::vc29_stopAllSounds,
&SimonEngine::vc30_setFrameRate,
&SimonEngine::vc31_setWindow,
&SimonEngine::vc32_copyVar,
&SimonEngine::vc33_setMouseOn,
&SimonEngine::vc34_setMouseOff,
&SimonEngine::vc35_clearWindow,
&SimonEngine::vc36_setWindowImage,
&SimonEngine::vc37_addToSpriteY,
&SimonEngine::vc38_skipIfVarZero,
&SimonEngine::vc39_setVar,
&SimonEngine::vc40,
&SimonEngine::vc41,
&SimonEngine::vc42_delayIfNotEQ,
&SimonEngine::vc43_skipIfBitClear,
&SimonEngine::vc44_skipIfBitSet,
&SimonEngine::vc45_setSpriteX,
&SimonEngine::vc46_setSpriteY,
&SimonEngine::vc47_addToVar,
&SimonEngine::vc48_setPathFinder,
&SimonEngine::vc49_setBit,
&SimonEngine::vc50_clearBit,
&SimonEngine::vc51_clear_hitarea_bit_0x40,
&SimonEngine::vc52_playSound,
&SimonEngine::vc53_no_op,
&SimonEngine::vc54_no_op,
&SimonEngine::vc55_offset_hit_area,
&SimonEngine::vc56_delay,
&SimonEngine::vc57_no_op,
&SimonEngine::vc58,
&SimonEngine::vc59,
&SimonEngine::vc60_killSprite,
&SimonEngine::vc61_changeSprite,
&SimonEngine::vc62_fastFadeOut,
&SimonEngine::vc63_fastFadeIn,
&SimonEngine::vc64_skipIfSpeechEnded,
&SimonEngine::vc65_slowFadeIn,
&SimonEngine::vc66_skipIfNotEqual,
&SimonEngine::vc67_skipIfGE,
&SimonEngine::vc68_skipIfLE,
&SimonEngine::vc69_playTrack,
&SimonEngine::vc70_queueMusic,
&SimonEngine::vc71_checkMusicQueue,
&SimonEngine::vc72_play_track_2,
&SimonEngine::vc73_setMark,
&SimonEngine::vc74_clearMark,
&SimonEngine::vc75_setScale,
&SimonEngine::vc76_setScaleXOffs,
&SimonEngine::vc77_setScaleYOffs,
&SimonEngine::vc78_pathUnk1,
&SimonEngine::vc79_pathUnk2,
&SimonEngine::vc80_setOverlayImage,
&SimonEngine::vc81_setRandom,
&SimonEngine::vc82_pathUnk3,
&SimonEngine::vc83_playSoundLoop,
&SimonEngine::vc84_stopSoundLoop,
};
_vga_opcode_table = vga_opcode_table;
}
// Script parser
void SimonEngine::run_vga_script() {
2002-07-07 19:06:48 +00:00
for (;;) {
uint opcode;
if (_continousVgaScript) {
if (_vcPtr != (const byte *)&_vc_get_out_of_code) {
fprintf(_dumpFile, "%.5d %.5X: %5d %4d ", _vgaTickCounter, _vcPtr - _curVgaFile1, _vgaCurSpriteId, _vgaCurFileId);
dump_video_script(_vcPtr, true);
2003-03-06 19:16:24 +00:00
}
}
if (_game & GF_SIMON1) {
opcode = READ_BE_UINT16(_vcPtr);
_vcPtr += 2;
} else {
opcode = *_vcPtr++;
}
2003-12-01 00:45:16 +00:00
if (opcode >= NUM_VIDEO_OP_CODES)
error("Invalid VGA opcode '%d' encountered", opcode);
if (opcode == 0)
return;
(this->*_vga_opcode_table[opcode]) ();
}
}
int SimonEngine::vc_read_var_or_word() {
int16 var = vc_read_next_word();
if (var < 0)
var = vc_read_var(-var);
return var;
}
uint SimonEngine::vc_read_next_word() {
2005-10-07 06:59:49 +00:00
uint a;
a = readUint16Wrapper(_vcPtr);
_vcPtr += 2;
return a;
}
uint SimonEngine::vc_read_next_byte() {
return *_vcPtr++;
}
void SimonEngine::vc_skip_next_instruction() {
static const byte opcode_param_len_simon1[] = {
2002-07-07 19:06:48 +00:00
0, 6, 2, 10, 6, 4, 2, 2,
4, 4, 10, 0, 2, 2, 2, 2,
2, 0, 2, 0, 4, 2, 4, 2,
2002-07-07 19:06:48 +00:00
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 opcode_param_len_simon2[] = {
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 opcode_param_len_feeblefiles[] = {
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
};
if (_game == GAME_FEEBLEFILES) {
uint opcode = vc_read_next_byte();
_vcPtr += opcode_param_len_feeblefiles[opcode];
} else if (_game & GF_SIMON2) {
uint opcode = vc_read_next_byte();
_vcPtr += opcode_param_len_simon2[opcode];
} else {
uint opcode = vc_read_next_word();
_vcPtr += opcode_param_len_simon1[opcode];
}
if (_continousVgaScript)
fprintf(_dumpFile, "; skipped\n");
}
2005-11-10 00:53:00 +00:00
void SimonEngine::o_unloadBeard() {
2003-03-06 19:16:24 +00:00
// Simon1 Only
2005-11-10 00:53:00 +00:00
if (_beardLoaded == true) {
_beardLoaded = false;
2005-10-23 11:17:15 +00:00
_lockWord |= 0x8000;
read_vga_from_datfile_1(23);
2005-10-23 11:17:15 +00:00
_lockWord &= ~0x8000;
}
}
2005-11-10 00:53:00 +00:00
void SimonEngine::o_loadBeard() {
2003-03-06 19:16:24 +00:00
// Simon1 Only
2005-11-10 00:53:00 +00:00
if (_beardLoaded == false) {
_beardLoaded = true;
2005-10-23 11:17:15 +00:00
_lockWord |= 0x8000;
read_vga_from_datfile_1(328);
2005-10-23 11:17:15 +00:00
_lockWord &= ~0x8000;
}
}
// VGA Script commands
2005-10-05 12:16:49 +00:00
void SimonEngine::vc1_fadeOut() {
/* dummy opcode */
_vcPtr += 6;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc2_call() {
VgaPointersEntry *vpe;
uint num;
uint res;
byte *old_file_1, *old_file_2;
byte *b, *bb;
const byte *vc_ptr_org;
num = vc_read_var_or_word();
old_file_1 = _curVgaFile1;
old_file_2 = _curVgaFile2;
2002-07-07 19:06:48 +00:00
for (;;) {
res = num / 100;
vpe = &_vgaBufferPointers[res];
_curVgaFile1 = vpe->vgaFile1;
_curVgaFile2 = vpe->vgaFile2;
if (vpe->vgaFile1 != NULL)
break;
if (_vgaCurFile2 != res)
_videoVar7 = _vgaCurFile2;
ensureVgaResLoaded(res);
_videoVar7 = 0xFFFF;
2002-07-07 19:06:48 +00:00
}
bb = _curVgaFile1;
if (_game == GAME_FEEBLEFILES) {
b = bb + READ_LE_UINT16(&((VgaFileHeader_Feeble *) bb)->hdr2_start);
b = bb + READ_LE_UINT16(&((VgaFileHeader2_Feeble *) b)->imageTable);
while (READ_LE_UINT16(&((ImageHeader_Feeble *) b)->id) != num)
b += sizeof(ImageHeader_Feeble);
} else {
b = bb + READ_BE_UINT16(&((VgaFileHeader_Simon *) bb)->hdr2_start);
b = bb + READ_BE_UINT16(&((VgaFileHeader2_Simon *) b)->imageTable);
while (READ_BE_UINT16(&((ImageHeader_Simon *) b)->id) != num)
b += sizeof(ImageHeader_Simon);
}
vc_ptr_org = _vcPtr;
if (_game == GAME_FEEBLEFILES) {
_vcPtr = _curVgaFile1 + READ_LE_UINT16(&((ImageHeader_Feeble *) b)->scriptOffs);
} else {
_vcPtr = _curVgaFile1 + READ_BE_UINT16(&((ImageHeader_Simon *) b)->scriptOffs);
}
2002-07-07 19:06:48 +00:00
//dump_vga_script(_vcPtr, res, num);
run_vga_script();
2002-07-07 19:06:48 +00:00
_curVgaFile1 = old_file_1;
_curVgaFile2 = old_file_2;
_vcPtr = vc_ptr_org;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc3_loadSprite() {
2005-10-05 11:37:26 +00:00
uint16 windowNum, fileId, palette, x, y, vgaSpriteId;
uint16 res;
VgaSprite *vsp;
VgaPointersEntry *vpe;
2002-07-07 19:06:48 +00:00
byte *p, *pp;
byte *old_file_1;
2005-10-05 11:37:26 +00:00
windowNum = vc_read_next_word(); /* 0 */
if (_game & GF_SIMON2) {
2005-05-06 13:22:48 +00:00
fileId = vc_read_next_word(); /* 0 */
vgaSpriteId = vc_read_next_word(); /* 2 */
} else {
vgaSpriteId = vc_read_next_word(); /* 2 */
2005-05-06 13:22:48 +00:00
fileId = vgaSpriteId / 100;
}
2003-10-21 10:34:56 +00:00
x = vc_read_next_word(); /* 4 */
y = vc_read_next_word(); /* 6 */
2005-10-05 11:37:26 +00:00
palette = vc_read_next_word(); /* 8 */
/* 2nd param ignored with simon1 */
2005-05-06 13:22:48 +00:00
if (isSpriteLoaded(vgaSpriteId, fileId))
return;
vsp = _vgaSprites;
2002-07-07 19:06:48 +00:00
while (vsp->id)
vsp++;
2005-10-05 11:37:26 +00:00
vsp->palette = palette;
vsp->windowNum = windowNum;
vsp->priority = 0;
vsp->flags = 0;
vsp->image = 0;
2003-10-21 10:34:56 +00:00
vsp->x = x;
vsp->y = y;
vsp->id = vgaSpriteId;
2005-05-06 13:22:48 +00:00
vsp->fileId = res = fileId;
old_file_1 = _curVgaFile1;
2002-07-07 19:06:48 +00:00
for (;;) {
vpe = &_vgaBufferPointers[res];
_curVgaFile1 = vpe->vgaFile1;
if (vpe->vgaFile1 != NULL)
break;
if (_vgaCurFile2 != res)
_videoVar7 = _vgaCurFile2;
ensureVgaResLoaded(res);
_videoVar7 = 0xFFFF;
}
pp = _curVgaFile1;
if (_game == GAME_FEEBLEFILES) {
p = pp + READ_LE_UINT16(&((VgaFileHeader_Feeble *) pp)->hdr2_start);
p = pp + READ_LE_UINT16(&((VgaFileHeader2_Feeble *) p)->animationTable);
while (READ_LE_UINT16(&((AnimationHeader_Feeble *) p)->id) != vgaSpriteId)
p += sizeof(AnimationHeader_Feeble);
} else {
p = pp + READ_BE_UINT16(&((VgaFileHeader_Simon *) pp)->hdr2_start);
p = pp + READ_BE_UINT16(&((VgaFileHeader2_Simon *) p)->animationTable);
2002-07-07 19:06:48 +00:00
while (READ_BE_UINT16(&((AnimationHeader_Simon *) p)->id) != vgaSpriteId)
p += sizeof(AnimationHeader_Simon);
}
#ifdef DUMP_FILE_NR
2002-07-07 19:06:48 +00:00
{
static bool dumped = false;
if (res == DUMP_FILE_NR && !dumped) {
dumped = true;
dump_vga_file(_curVgaFile1);
2002-07-07 19:06:48 +00:00
}
}
#endif
#ifdef DUMP_BITMAPS_FILE_NR
2002-07-07 19:06:48 +00:00
{
static bool dumped = false;
if (res == DUMP_BITMAPS_FILE_NR && !dumped) {
dumped = true;
dump_vga_bitmaps(_curVgaFile2, _curVgaFile1, res);
2002-07-07 19:06:48 +00:00
}
}
#endif
if (_startVgaScript) {
if (_game == GAME_FEEBLEFILES) {
dump_vga_script(_curVgaFile1 + READ_LE_UINT16(&((AnimationHeader_Feeble*)p)->scriptOffs), res, vgaSpriteId);
} else {
dump_vga_script(_curVgaFile1 + READ_BE_UINT16(&((AnimationHeader_Simon*)p)->scriptOffs), res, vgaSpriteId);
}
}
if (_game == GAME_FEEBLEFILES) {
add_vga_timer(VGA_DELAY_BASE, _curVgaFile1 + READ_LE_UINT16(&((AnimationHeader_Feeble *) p)->scriptOffs), vgaSpriteId, res);
} else {
add_vga_timer(VGA_DELAY_BASE, _curVgaFile1 + READ_BE_UINT16(&((AnimationHeader_Simon *) p)->scriptOffs), vgaSpriteId, res);
}
_curVgaFile1 = old_file_1;
}
2005-10-05 12:16:49 +00:00
void SimonEngine::vc4_fadeIn() {
/* dummy opcode */
_vcPtr += 6;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc5_skip_if_neq() {
uint var = vc_read_next_word();
uint value = vc_read_next_word();
if (vc_read_var(var) != value)
vc_skip_next_instruction();
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc6_skip_ifn_sib_with_a() {
2003-03-07 03:26:30 +00:00
if (!itemIsSiblingOf(vc_read_next_word()))
vc_skip_next_instruction();
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc7_skip_if_sib_with_a() {
2003-03-07 03:26:30 +00:00
if (itemIsSiblingOf(vc_read_next_word()))
vc_skip_next_instruction();
}
void SimonEngine::vc8_skip_if_parent_is() {
uint a = vc_read_next_word();
uint b = vc_read_next_word();
2003-03-07 03:26:30 +00:00
if (!itemIsParentOf(a, b))
vc_skip_next_instruction();
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc9_skip_if_unk3_is() {
uint a = vc_read_next_word();
uint b = vc_read_next_word();
2002-07-07 19:06:48 +00:00
if (!vc_maybe_skip_proc_1(a, b))
vc_skip_next_instruction();
}
2005-05-06 13:22:48 +00:00
byte *vc10_depack_column(VC10_state * vs) {
int8 a = vs->depack_cont;
const byte *src = vs->depack_src;
byte *dst = vs->depack_dest;
byte dh = vs->dh;
byte color;
2004-03-14 17:53:19 +00:00
if (a == -0x80)
a = *src++;
2002-07-07 19:06:48 +00:00
for (;;) {
if (a >= 0) {
color = *src++;
do {
*dst++ = color;
if (!--dh) {
2002-07-07 19:06:48 +00:00
if (--a < 0)
a = -0x80;
else
src--;
goto get_out;
}
2002-07-07 19:06:48 +00:00
} while (--a >= 0);
} else {
do {
*dst++ = *src++;
if (!--dh) {
2002-07-07 19:06:48 +00:00
if (++a == 0)
a = -0x80;
goto get_out;
}
2002-07-07 19:06:48 +00:00
} while (++a != 0);
}
2004-03-14 17:53:19 +00:00
a = *src++;
}
get_out:;
vs->depack_src = src;
vs->depack_cont = a;
return vs->depack_dest + vs->y_skip;
}
2005-05-06 13:22:48 +00:00
void vc10_skip_cols(VC10_state *vs) {
vs->depack_cont = -0x80;
2002-07-07 19:06:48 +00:00
while (vs->x_skip) {
2005-05-06 13:22:48 +00:00
vc10_depack_column(vs);
vs->x_skip--;
}
}
2005-11-08 11:34:56 +00:00
byte *SimonEngine::vc10_uncompressFlip(const byte *src, uint w, uint h) {
w *= 8;
2005-11-08 11:34:56 +00:00
byte *src_org, *dst_org;
byte color;
int8 cur = -0x80;
uint i, w_cur = w;
2002-07-07 19:06:48 +00:00
2005-11-08 11:34:56 +00:00
dst_org = _videoBuf1 + w;
2005-11-08 11:34:56 +00:00
do {
byte *dst = dst_org;
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);
}
2005-11-08 11:34:56 +00:00
cur = *src++;
}
next_line:
dst_org++;
} while (--w_cur);
2005-11-08 11:34:56 +00:00
src_org = dst_org = _videoBuf1 + w;
do {
byte *dst = dst_org;
for (i = 0; i != w; ++i) {
byte b = src_org[i];
b = (b >> 4) | (b << 4);
*--dst = b;
}
src_org += w;
dst_org += w;
} while (--h);
return _videoBuf1;
}
2005-11-08 11:34:56 +00:00
byte *SimonEngine::vc10_flip(const byte *src, uint w, uint h) {
if (src == _vc10BasePtrOld)
return _videoBuf1;
_vc10BasePtrOld = src;
2005-11-08 11:34:56 +00:00
byte *dst_org, *src_org;
uint i;
w *= 8;
src_org = dst_org = _videoBuf1 + w;
do {
2005-11-08 11:34:56 +00:00
byte *dst = dst_org;
for (i = 0; i != w; ++i) {
byte b = src_org[i];
b = (b >> 4) | (b << 4);
*--dst = b;
}
src_org += w;
dst_org += w;
} while (--h);
return _videoBuf1;
}
/* must not be const */
static uint16 _video_windows[128] = {
0, 0, 20, 200,
2002-07-07 19:06:48 +00:00
0, 0, 3, 136,
17, 0, 3, 136,
0, 0, 20, 200,
0, 0, 20, 134
};
/* simon2 specific */
void SimonEngine::decodeStripA(byte *dst, const byte *src, int height) {
const uint pitch = _dxSurfacePitch;
int8 reps = (int8)0x80;
byte color;
byte *dst_org = dst;
2003-03-07 03:26:30 +00:00
uint h = height, w = 8;
2002-07-07 19:06:48 +00:00
for (;;) {
reps = *src++;
if (reps >= 0) {
color = *src++;
2002-07-07 19:06:48 +00:00
do {
*dst = color;
dst += pitch;
/* reached bottom? */
if (--h == 0) {
2002-07-07 19:06:48 +00:00
/* reached right edge? */
if (--w == 0)
return;
dst = ++dst_org;
2003-03-07 03:26:30 +00:00
h = height;
}
2002-07-07 19:06:48 +00:00
} while (--reps >= 0);
} else {
2002-07-07 19:06:48 +00:00
do {
*dst = *src++;
dst += pitch;
/* reached bottom? */
if (--h == 0) {
2002-07-07 19:06:48 +00:00
/* reached right edge? */
if (--w == 0)
return;
dst = ++dst_org;
2003-03-07 03:26:30 +00:00
h = height;
}
} while (++reps != 0);
}
}
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc10_draw() {
byte *p2;
2002-07-07 19:06:48 +00:00
uint width, height;
byte flags;
const uint16 *vlut;
VC10_state state;
2002-07-07 19:06:48 +00:00
int cur;
state.image = (int16)vc_read_next_word();
2002-07-07 19:06:48 +00:00
if (state.image == 0)
return;
2005-10-05 11:37:26 +00:00
state.palette = (_vcPtr[1] << 4);
_vcPtr += 2;
state.x = (int16)vc_read_next_word();
if (_game & GF_SIMON2) {
2005-10-05 11:37:26 +00:00
state.x -= _scrollX;
}
state.y = (int16)vc_read_next_word();
if (!(_game & GF_SIMON2)) {
state.flags = vc_read_next_word();
} else {
state.flags = vc_read_next_byte();
}
if (state.image < 0)
state.image = vc_read_var(-state.image);
p2 = _curVgaFile2 + state.image * 8;
state.depack_src = _curVgaFile2 + READ_BE_UINT32(p2);
2005-10-07 06:59:49 +00:00
if (_game == GAME_FEEBLEFILES) {
2005-11-08 11:34:56 +00:00
state.depack_src = _curVgaFile2 + READ_LE_UINT32(p2);
2005-10-07 06:59:49 +00:00
width = READ_LE_UINT16(p2 + 6);
2005-11-08 11:34:56 +00:00
height = p2[4];
flags = p2[5];
2005-10-07 06:59:49 +00:00
} else {
2005-11-08 11:34:56 +00:00
state.depack_src = _curVgaFile2 + READ_BE_UINT32(p2);
2005-10-07 06:59:49 +00:00
width = READ_BE_UINT16(p2 + 6) >> 4;
2005-11-08 11:34:56 +00:00
height = p2[5];
flags = p2[4];
2005-10-07 06:59:49 +00:00
}
debug(1, "Width %d Height %d Flags 0x%x", width, height, flags);
2005-10-07 06:59:49 +00:00
2002-07-07 19:06:48 +00:00
if (height == 0 || width == 0)
return;
if (_dumpImages)
dump_single_bitmap(_vgaCurFileId, state.image, state.depack_src, width * 16, height,
2005-10-05 11:37:26 +00:00
state.palette);
// TODO::Add support for image scaling
if (_game == GAME_FEEBLEFILES)
return;
if (flags & 0x80 && !(state.flags & 0x10)) {
if (state.flags & 1) {
state.flags &= ~1;
state.flags |= 0x10;
} else {
state.flags |= 0x8;
}
}
2005-10-07 07:06:21 +00:00
uint maxWidth = (_game == GAME_FEEBLEFILES) ? 641 : 21;
if (_game & GF_SIMON2 && width >= maxWidth) {
const byte *src;
byte *dst;
uint w;
2005-10-05 11:37:26 +00:00
_scrollXMax = width * 2 - 40;
_scrollImage = state.depack_src;
_scrollHeight = height;
2002-07-07 19:06:48 +00:00
if (_variableArray[34] == -1)
state.x = _variableArray[251];
2005-10-05 11:37:26 +00:00
_scrollX = state.x;
vc_write_var(251, _scrollX);
dst = dx_lock_attached();
2005-10-05 11:37:26 +00:00
src = state.depack_src + _scrollX * 4;
2002-07-07 19:06:48 +00:00
2003-03-07 03:26:30 +00:00
for (w = 0; w < 40; w++) {
decodeStripA(dst, src + READ_BE_UINT32(src), height);
dst += 8;
src += 4;
2003-03-07 03:26:30 +00:00
}
2002-07-07 19:06:48 +00:00
dx_unlock_attached();
2002-07-07 19:06:48 +00:00
return;
}
if (state.flags & 0x10) {
2005-11-08 11:34:56 +00:00
state.depack_src = vc10_uncompressFlip(state.depack_src, width, height);
} else if (state.flags & 1) {
2005-11-08 11:34:56 +00:00
state.depack_src = vc10_flip(state.depack_src, width, height);
}
2005-10-05 11:37:26 +00:00
vlut = &_video_windows[_windowNum * 4];
2002-07-07 19:06:48 +00:00
state.draw_width = width << 1; /* cl */
state.draw_height = height; /* ch */
2002-07-07 19:06:48 +00:00
state.x_skip = 0; /* colums to skip = bh */
state.y_skip = 0; /* rows to skip = bl */
cur = state.x;
if (cur < 0) {
do {
2002-07-07 19:06:48 +00:00
if (!--state.draw_width)
return;
state.x_skip++;
2002-07-07 19:06:48 +00:00
} while (++cur);
}
state.x = cur;
2002-07-07 19:06:48 +00:00
cur += state.draw_width - (vlut[2] << 1);
if (cur > 0) {
do {
2002-07-07 19:06:48 +00:00
if (!--state.draw_width)
return;
} while (--cur);
}
2002-07-07 19:06:48 +00:00
cur = state.y;
if (cur < 0) {
do {
2002-07-07 19:06:48 +00:00
if (!--state.draw_height)
return;
state.y_skip++;
2002-07-07 19:06:48 +00:00
} while (++cur);
}
state.y = cur;
cur += state.draw_height - vlut[3];
if (cur > 0) {
do {
2002-07-07 19:06:48 +00:00
if (!--state.draw_height)
return;
} while (--cur);
}
2002-07-07 19:06:48 +00:00
assert(state.draw_width != 0 && state.draw_height != 0);
2002-07-07 19:06:48 +00:00
state.draw_width <<= 2;
state.surf2_addr = dx_lock_2();
state.surf2_pitch = _dxSurfacePitch;
state.surf_addr = dx_lock_attached();
state.surf_pitch = _dxSurfacePitch;
{
uint offs, offs2;
// Allow one section of Simon the Sorcerer 1 introduction to be displayed
// in lower half of screen
if ((_game & GF_SIMON1) && _subroutine == 2926) {
offs = ((vlut[0]) * 2 + state.x) * 8;
offs2 = (vlut[1] + state.y);
} else {
offs = ((vlut[0] - _video_windows[16]) * 2 + state.x) * 8;
offs2 = (vlut[1] - _video_windows[17] + state.y);
}
state.surf2_addr += offs + offs2 * state.surf2_pitch;
state.surf_addr += offs + offs2 * state.surf_pitch;
}
if (state.flags & 0x20) {
byte *mask, *src, *dst;
byte h;
uint w;
2002-07-07 19:06:48 +00:00
state.x_skip <<= 2;
state.dl = width;
state.dh = height;
2002-07-07 19:06:48 +00:00
2005-05-06 13:22:48 +00:00
vc10_skip_cols(&state);
2002-07-07 19:06:48 +00:00
w = 0;
do {
2005-05-06 13:22:48 +00:00
mask = vc10_depack_column(&state); /* esi */
2002-07-07 19:06:48 +00:00
src = state.surf2_addr + w * 2; /* ebx */
dst = state.surf_addr + w * 2; /* edi */
h = state.draw_height;
if ((_game & GF_SIMON1) && vc_get_bit(88)) {
/* transparency */
do {
if (mask[0] & 0xF0) {
if ((dst[0] & 0x0F0) == 0x20)
dst[0] = src[0];
}
if (mask[0] & 0x0F) {
if ((dst[1] & 0x0F0) == 0x20)
dst[1] = src[1];
}
mask++;
dst += state.surf_pitch;
src += state.surf2_pitch;
} while (--h);
} else {
/* no transparency */
do {
if (mask[0] & 0xF0)
dst[0] = src[0];
if (mask[0] & 0x0F)
dst[1] = src[1];
mask++;
dst += state.surf_pitch;
src += state.surf2_pitch;
} while (--h);
}
2002-07-07 19:06:48 +00:00
} while (++w != state.draw_width);
2005-05-06 13:22:48 +00:00
/* vc10_helper_5 */
2005-10-23 11:17:15 +00:00
} else if (((_lockWord & 0x20) && state.palette == 0) || state.palette == 0xC0) {
const byte *src;
byte *dst;
2002-07-07 19:06:48 +00:00
uint h, i;
if (!(state.flags & 8)) {
2002-07-07 19:06:48 +00:00
src = state.depack_src + (width * state.y_skip << 4) + (state.x_skip << 3);
dst = state.surf_addr;
state.draw_width *= 2;
2002-07-07 19:06:48 +00:00
if (state.flags & 2) {
/* no transparency */
h = state.draw_height;
do {
2002-07-07 19:06:48 +00:00
memcpy(dst, src, state.draw_width);
dst += _screenWidth;
src += width * 16;
2002-07-07 19:06:48 +00:00
} while (--h);
} else {
/* transparency */
h = state.draw_height;
do {
2002-07-07 19:06:48 +00:00
for (i = 0; i != state.draw_width; i++)
if (src[i])
dst[i] = src[i];
dst += _screenWidth;
src += width * 16;
2002-07-07 19:06:48 +00:00
} while (--h);
}
} else {
byte *dst_org = state.surf_addr;
src = state.depack_src;
/* AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE
* aaaaabbb bbcccccd ddddeeee efffffgg ggghhhhh
*/
2002-07-07 19:06:48 +00:00
if (state.flags & 2) {
/* no transparency */
do {
2002-07-07 19:06:48 +00:00
uint count = state.draw_width >> 2;
dst = dst_org;
do {
2002-07-07 19:06:48 +00:00
uint32 bits = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | (src[3]);
dst[0] = (byte)((bits >> (32 - 5)) & 31);
dst[1] = (byte)((bits >> (32 - 10)) & 31);
dst[2] = (byte)((bits >> (32 - 15)) & 31);
dst[3] = (byte)((bits >> (32 - 20)) & 31);
dst[4] = (byte)((bits >> (32 - 25)) & 31);
dst[5] = (byte)((bits >> (32 - 30)) & 31);
bits = (bits << 8) | src[4];
dst[6] = (byte)((bits >> (40 - 35)) & 31);
dst[7] = (byte)((bits) & 31);
dst += 8;
src += 5;
} while (--count);
dst_org += _screenWidth;
} while (--state.draw_height);
} else {
/* transparency */
do {
2002-07-07 19:06:48 +00:00
uint count = state.draw_width >> 2;
dst = dst_org;
do {
2002-07-07 19:06:48 +00:00
uint32 bits = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | (src[3]);
byte tmp;
2002-07-07 19:06:48 +00:00
tmp = (byte)((bits >> (32 - 5)) & 31);
if (tmp)
dst[0] = tmp;
tmp = (byte)((bits >> (32 - 10)) & 31);
if (tmp)
dst[1] = tmp;
tmp = (byte)((bits >> (32 - 15)) & 31);
if (tmp)
dst[2] = tmp;
tmp = (byte)((bits >> (32 - 20)) & 31);
if (tmp)
dst[3] = tmp;
tmp = (byte)((bits >> (32 - 25)) & 31);
if (tmp)
dst[4] = tmp;
tmp = (byte)((bits >> (32 - 30)) & 31);
if (tmp)
dst[5] = tmp;
bits = (bits << 8) | src[4];
tmp = (byte)((bits >> (40 - 35)) & 31);
if (tmp)
dst[6] = tmp;
tmp = (byte)((bits) & 31);
if (tmp)
dst[7] = tmp;
dst += 8;
src += 5;
2002-07-07 19:06:48 +00:00
} while (--count);
dst_org += _screenWidth;
} while (--state.draw_height);
}
}
2005-05-06 13:22:48 +00:00
/* vc10_helper_4 */
} else {
if (_game & GF_SIMON2 && state.flags & 0x4 && _bitArray[10] & 0x800) {
state.surf_addr = state.surf2_addr;
state.surf_pitch = state.surf2_pitch;
2002-07-07 19:06:48 +00:00
}
if (state.flags & 0x8) {
2002-07-07 19:06:48 +00:00
uint w, h;
byte *src, *dst, *dst_org;
2002-07-07 19:06:48 +00:00
state.x_skip <<= 2; /* reached */
state.dl = width;
state.dh = height;
2005-05-06 13:22:48 +00:00
vc10_skip_cols(&state);
if (state.flags & 2) {
dst_org = state.surf_addr;
w = 0;
do {
2005-05-06 13:22:48 +00:00
src = vc10_depack_column(&state);
dst = dst_org;
2002-07-07 19:06:48 +00:00
h = 0;
do {
2005-10-05 11:37:26 +00:00
dst[0] = (*src >> 4) | state.palette;
dst[1] = (*src & 15) | state.palette;
dst += _screenWidth;
src++;
} while (++h != state.draw_height);
dst_org += 2;
} while (++w != state.draw_width);
} else {
dst_org = state.surf_addr;
if (state.flags & 0x40) { /* reached */
dst_org += vc_read_var(252);
}
w = 0;
do {
byte color;
2005-05-06 13:22:48 +00:00
src = vc10_depack_column(&state);
dst = dst_org;
2002-07-07 19:06:48 +00:00
h = 0;
do {
color = (*src >> 4);
2002-07-07 19:06:48 +00:00
if (color)
2005-10-05 11:37:26 +00:00
dst[0] = color | state.palette;
2002-07-07 19:06:48 +00:00
color = (*src & 15);
if (color)
2005-10-05 11:37:26 +00:00
dst[1] = color | state.palette;
dst += _screenWidth;
src++;
} while (++h != state.draw_height);
dst_org += 2;
2002-07-07 19:06:48 +00:00
} while (++w != state.draw_width);
}
2005-05-06 13:22:48 +00:00
/* vc10_helper_6 */
} else {
const byte *src;
byte *dst;
uint count;
src = state.depack_src + (width * state.y_skip) * 8;
dst = state.surf_addr;
state.x_skip <<= 2;
if (state.flags & 2) {
do {
2002-07-07 19:06:48 +00:00
for (count = 0; count != state.draw_width; count++) {
2005-10-05 11:37:26 +00:00
dst[count * 2] = (src[count + state.x_skip] >> 4) | state.palette;
dst[count * 2 + 1] = (src[count + state.x_skip] & 15) | state.palette;
}
dst += _screenWidth;
src += width * 8;
} while (--state.draw_height);
} else {
do {
2002-07-07 19:06:48 +00:00
for (count = 0; count != state.draw_width; count++) {
byte color;
2002-07-07 19:06:48 +00:00
color = (src[count + state.x_skip] >> 4);
if (color)
2005-10-05 11:37:26 +00:00
dst[count * 2] = color | state.palette;
2002-07-07 19:06:48 +00:00
color = (src[count + state.x_skip] & 15);
if (color)
2005-10-05 11:37:26 +00:00
dst[count * 2 + 1] = color | state.palette;
}
dst += _screenWidth;
src += width * 8;
} while (--state.draw_height);
}
2005-05-06 13:22:48 +00:00
/* vc10_helper_7 */
}
}
dx_unlock_2();
dx_unlock_attached();
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc11_clearPathFinder() {
memset(&_pathFindArray, 0, sizeof(_pathFindArray));
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc12_delay() {
VgaSprite *vsp = find_cur_sprite();
uint num;
if (_game & GF_SIMON1) {
num = vc_read_var_or_word();
} else {
2005-10-05 11:37:26 +00:00
num = vc_read_next_byte() * _frameRate;
}
// Work around to allow inventory arrows to be
// shown in some versions of Simon the Sorcerer 1
if ((_game & GF_SIMON1) && vsp->id == 0x80)
num = 0;
else
num += VGA_DELAY_BASE;
2003-10-26 04:37:11 +00:00
add_vga_timer(num, _vcPtr, _vgaCurSpriteId, _vgaCurFileId);
_vcPtr = (byte *)&_vc_get_out_of_code;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc13_addToSpriteX() {
VgaSprite *vsp = find_cur_sprite();
2003-05-29 07:02:14 +00:00
vsp->x += (int16)vc_read_next_word();
_vgaSpriteChanged++;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc14_addToSpriteY() {
VgaSprite *vsp = find_cur_sprite();
2003-05-29 07:02:14 +00:00
vsp->y += (int16)vc_read_next_word();
_vgaSpriteChanged++;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc15_wakeup_id() {
VgaSleepStruct *vfs = _vgaSleepStructs, *vfs_tmp;
uint16 id = vc_read_next_word();
while (vfs->ident != 0) {
if (vfs->ident == id) {
2003-12-01 00:45:16 +00:00
add_vga_timer(VGA_DELAY_BASE, 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++;
}
}
/* clear a wait event */
if (id == _vgaWaitFor)
_vgaWaitFor = 0;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc16_sleep_on_id() {
VgaSleepStruct *vfs = _vgaSleepStructs;
while (vfs->ident)
vfs++;
vfs->ident = vc_read_next_word();
vfs->code_ptr = _vcPtr;
vfs->sprite_id = _vgaCurSpriteId;
vfs->cur_vga_file = _vgaCurFileId;
2002-07-07 19:06:48 +00:00
_vcPtr = (byte *)&_vc_get_out_of_code;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc17_setPathfinderItem() {
uint a = vc_read_next_word();
_pathFindArray[a - 1] = (const uint16 *)_vcPtr;
int end = (_game == GAME_FEEBLEFILES) ? 9999 : 999;
while (readUint16Wrapper(_vcPtr) != end)
_vcPtr += 4;
_vcPtr += 2;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc18_jump() {
int16 offs = vc_read_next_word();
_vcPtr += offs;
}
/* chain to script? */
2005-05-06 13:22:48 +00:00
void SimonEngine::vc19_chain_to_script() {
/* unused */
2005-05-06 13:22:48 +00:00
error("vc19_chain_to_script: not implemented");
}
/* helper routines */
2005-10-05 12:16:49 +00:00
void SimonEngine::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 = vc_read_next_word();
WRITE_LE_UINT16(const_cast<byte *>(_vcPtr), a);
_vcPtr += 2;
}
2005-10-05 12:16:49 +00:00
void SimonEngine::vc21_endRepeat() {
2003-07-28 11:48:07 +00:00
int16 a = vc_read_next_word();
const byte *tmp = _vcPtr + a;
2003-07-28 11:48:07 +00:00
if (_game & GF_SIMON2)
tmp += 3;
else
tmp += 4;
uint16 val = READ_LE_UINT16(tmp);
2003-07-28 11:48:07 +00:00
if (val != 0) {
// Decrement counter
WRITE_LE_UINT16(const_cast<byte *>(tmp), val - 1);
_vcPtr = tmp + 2;
}
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc22_setSpritePalette() {
uint a = vc_read_next_word();
uint b = vc_read_next_word();
2002-07-07 19:06:48 +00:00
uint num = a == 0 ? 0x20 : 0x10;
byte *palptr, *src;
2002-07-07 19:06:48 +00:00
palptr = &_palette[(a << 6)];
src = _curVgaFile1 + 6 + b * 96;
2002-07-07 19:06:48 +00:00
do {
2002-07-07 19:06:48 +00:00
palptr[0] = src[0] << 2;
palptr[1] = src[1] << 2;
palptr[2] = src[2] << 2;
palptr[3] = 0;
palptr += 4;
src += 3;
} while (--num);
_videoVar9 = 2;
_vgaSpriteChanged++;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc23_setSpritePriority() {
VgaSprite *vsp = find_cur_sprite(), *vus2;
uint16 pri = vc_read_next_word();
VgaSprite bak;
if (vsp->id == 0)
2003-07-16 12:21:09 +00:00
return;
memcpy(&bak, vsp, sizeof(bak));
bak.priority = pri;
2005-10-05 11:37:26 +00:00
bak.windowNum |= 0x8000;
vus2 = vsp;
if (vsp != _vgaSprites && pri < vsp[-1].priority) {
do {
vsp--;
} while (vsp != _vgaSprites && pri < vsp[-1].priority);
do {
2002-07-07 19:06:48 +00:00
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 {
2002-07-07 19:06:48 +00:00
memcpy(vus2, vus2 + 1, sizeof(VgaSprite));
} while (++vus2 != vsp);
memcpy(vus2, &bak, sizeof(VgaSprite));
} else {
vsp->priority = pri;
}
_vgaSpriteChanged++;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc24_setSpriteXY() {
VgaSprite *vsp = find_cur_sprite();
vsp->image = vc_read_var_or_word();
vsp->x += (int16)vc_read_next_word();
vsp->y += (int16)vc_read_next_word();
if (_game & GF_SIMON1) {
vsp->flags = vc_read_next_word();
} else {
vsp->flags = vc_read_next_byte();
}
_vgaSpriteChanged++;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc25_halt_sprite() {
VgaSprite *vsp = find_cur_sprite();
while (vsp->id != 0) {
2002-07-07 19:06:48 +00:00
memcpy(vsp, vsp + 1, sizeof(VgaSprite));
vsp++;
}
_vcPtr = (byte *)&_vc_get_out_of_code;
_vgaSpriteChanged++;
}
2005-10-05 12:16:49 +00:00
void SimonEngine::vc26_setSubWindow() {
uint16 *as = &_video_windows[vc_read_next_word() * 4]; // number
as[0] = vc_read_next_word(); // x
as[1] = vc_read_next_word(); // y
as[2] = vc_read_next_word(); // width
as[3] = vc_read_next_word(); // height
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc27_resetSprite() {
2002-07-07 19:06:48 +00:00
VgaSprite bak, *vsp;
VgaSleepStruct *vfs;
2002-07-07 19:06:48 +00:00
VgaTimerEntry *vte, *vte2;
_lockWord |= 8;
2002-07-07 19:06:48 +00:00
memset(&bak, 0, sizeof(bak));
vsp = _vgaSprites;
while (vsp->id) {
if ((_game & GF_SIMON1) && vsp->id == 0x80) {
2002-07-07 19:06:48 +00:00
memcpy(&bak, vsp, sizeof(VgaSprite));
}
vsp->id = 0;
vsp++;
}
if (bak.id != 0)
memcpy(_vgaSprites, &bak, sizeof(VgaSprite));
vfs = _vgaSleepStructs;
while (vfs->ident) {
vfs->ident = 0;
vfs++;
}
vte = _vgaTimerList;
while (vte->delay) {
if ((_game & GF_SIMON1) && vsp->id == 0x80) {
vte++;
} else {
vte2 = vte;
while (vte2->delay) {
2002-07-07 19:06:48 +00:00
memcpy(vte2, vte2 + 1, sizeof(VgaTimerEntry));
vte2++;
}
}
}
vc_write_var(0xFE, 0);
2002-07-07 19:06:48 +00:00
_lockWord &= ~8;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc28_dummy_op() {
/* unused */
_vcPtr += 8;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc29_stopAllSounds() {
2002-11-24 12:53:01 +00:00
_sound->stopAll();
}
2005-10-05 11:37:26 +00:00
void SimonEngine::vc30_setFrameRate() {
_frameRate = vc_read_next_word();
}
2005-10-05 11:37:26 +00:00
void SimonEngine::vc31_setWindow() {
_windowNum = vc_read_next_word();
}
uint SimonEngine::vc_read_var(uint var) {
2002-07-07 19:06:48 +00:00
assert(var < 255);
return (uint16)_variableArray[var];
}
void SimonEngine::vc_write_var(uint var, int16 value) {
_variableArray[var] = value;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc32_copyVar() {
uint16 a = vc_read_var(vc_read_next_word());
vc_write_var(vc_read_next_word(), a);
}
2005-10-05 12:16:49 +00:00
void SimonEngine::vc33_setMouseOn() {
if (_lockCounter != 0) {
_lockCounter = 1;
unlock();
}
}
2005-10-05 12:16:49 +00:00
void SimonEngine::vc34_setMouseOff() {
lock();
_lockCounter = 200;
_leftButtonDown = 0;
}
2005-10-05 12:16:49 +00:00
void SimonEngine::vc35_clearWindow() {
/* unused */
_vcPtr += 4;
_vgaSpriteChanged++;
}
2005-10-05 12:16:49 +00:00
void SimonEngine::vc36_setWindowImage() {
_updateScreen = false;
uint vga_res = vc_read_next_word();
2005-10-05 12:16:49 +00:00
uint windowNum = vc_read_next_word();
if (_game & GF_SIMON1) {
2005-10-05 12:16:49 +00:00
if (windowNum == 16) {
_copyPartialMode = 2;
} else {
2005-10-05 12:16:49 +00:00
set_video_mode_internal(windowNum, vga_res);
}
} else {
2005-10-05 12:16:49 +00:00
set_video_mode_internal(windowNum, vga_res);
}
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc37_addToSpriteY() {
VgaSprite *vsp = find_cur_sprite();
vsp->y += vc_read_var(vc_read_next_word());
_vgaSpriteChanged++;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc38_skipIfVarZero() {
uint var = vc_read_next_word();
if (vc_read_var(var) == 0)
vc_skip_next_instruction();
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc39_setVar() {
uint var = vc_read_next_word();
int16 value = vc_read_next_word();
2002-07-07 19:06:48 +00:00
vc_write_var(var, value);
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc40() {
uint var = vc_read_next_word();
int16 value = vc_read_var(var) + vc_read_next_word();
if ((_game & GF_SIMON2) && var == 0xF && !(_bitArray[5] & 1)) {
int16 tmp;
2005-10-05 11:37:26 +00:00
if (_scrollCount != 0) {
if (_scrollCount >= 0)
2002-07-07 19:06:48 +00:00
goto no_scroll;
2005-10-05 11:37:26 +00:00
_scrollCount = 0;
} else {
2005-10-05 11:37:26 +00:00
if (_scrollFlag != 0)
2002-07-07 19:06:48 +00:00
goto no_scroll;
}
2005-10-05 11:37:26 +00:00
if (value - _scrollX >= 30) {
_scrollCount = 20;
tmp = _scrollXMax - _scrollX;
if (tmp < 20)
2005-10-05 11:37:26 +00:00
_scrollCount = tmp;
add_vga_timer(6, NULL, 0, 0); /* special timer */
}
}
no_scroll:;
vc_write_var(var, value);
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc41() {
uint var = vc_read_next_word();
int16 value = vc_read_var(var) - vc_read_next_word();
if ((_game & GF_SIMON2) && var == 0xF && !(_bitArray[5] & 1)) {
int16 tmp;
2005-10-05 11:37:26 +00:00
if (_scrollCount != 0) {
if (_scrollCount < 0)
2002-07-07 19:06:48 +00:00
goto no_scroll;
2005-10-05 11:37:26 +00:00
_scrollCount = 0;
} else {
2005-10-05 11:37:26 +00:00
if (_scrollFlag != 0)
2002-07-07 19:06:48 +00:00
goto no_scroll;
}
2005-10-05 11:37:26 +00:00
if ((uint16)(value - _scrollX) < 11) {
_scrollCount = -20;
tmp = _scrollXMax - _scrollX;
if (_scrollX < 20)
_scrollCount = -_scrollX;
add_vga_timer(6, NULL, 0, 0); /* special timer */
}
}
no_scroll:;
vc_write_var(var, value);
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc42_delayIfNotEQ() {
uint val = vc_read_var(vc_read_next_word());
2003-12-20 07:59:42 +00:00
if (val != vc_read_next_word()) {
2002-07-07 19:06:48 +00:00
2005-10-05 11:37:26 +00:00
add_vga_timer(_frameRate + 1, _vcPtr - 4, _vgaCurSpriteId, _vgaCurFileId);
_vcPtr = (byte *)&_vc_get_out_of_code;
}
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc43_skipIfBitClear() {
if (!vc_get_bit(vc_read_next_word())) {
vc_skip_next_instruction();
}
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc44_skipIfBitSet() {
if (vc_get_bit(vc_read_next_word())) {
vc_skip_next_instruction();
}
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc45_setSpriteX() {
VgaSprite *vsp = find_cur_sprite();
vsp->x = vc_read_var(vc_read_next_word());
_vgaSpriteChanged++;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc46_setSpriteY() {
VgaSprite *vsp = find_cur_sprite();
vsp->y = vc_read_var(vc_read_next_word());
_vgaSpriteChanged++;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc47_addToVar() {
uint var = vc_read_next_word();
vc_write_var(var, vc_read_var(var) + vc_read_var(vc_read_next_word()));
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc48_setPathFinder() {
uint a = (uint16)_variableArray[12];
uint b = (uint16)_variableArray[13];
int c = _variableArray[14];
const uint16 *p = _pathFindArray[a - 1];
int step;
2002-07-07 19:06:48 +00:00
int y1, y2;
int16 *vp;
2002-07-07 19:06:48 +00:00
p += b * 2 + 1;
step = 2;
2002-07-07 19:06:48 +00:00
if (c < 0) {
c = -c;
step = -2;
}
vp = &_variableArray[20];
2002-07-07 19:06:48 +00:00
do {
y2 = readUint16Wrapper(p);
p += step;
y1 = readUint16Wrapper(p) - y2;
2002-07-07 19:06:48 +00:00
vp[0] = y1 >> 1;
vp[1] = y1 - (y1 >> 1);
vp += 2;
} while (--c);
}
void SimonEngine::vc_set_bit_to(uint bit, bool value) {
uint16 *bits = &_bitArray[bit >> 4];
2002-07-07 19:06:48 +00:00
*bits = (*bits & ~(1 << (bit & 15))) | (value << (bit & 15));
}
bool SimonEngine::vc_get_bit(uint bit) {
uint16 *bits = &_bitArray[bit >> 4];
2002-07-07 19:06:48 +00:00
return (*bits & (1 << (bit & 15))) != 0;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc49_setBit() {
vc_set_bit_to(vc_read_next_word(), true);
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc50_clearBit() {
vc_set_bit_to(vc_read_next_word(), false);
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc51_clear_hitarea_bit_0x40() {
clear_hitarea_bit_0x40(vc_read_next_word());
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc52_playSound() {
2003-10-21 10:34:56 +00:00
uint16 sound_id = vc_read_next_word();
if (_game == GAME_FEEBLEFILES) {
uint16 pan = vc_read_next_word();
uint16 vol = vc_read_next_word();
debug(0, "STUB: vc52_playSound: snd %d pan %d vol %d", sound_id, pan, vol);
} else if (_game & GF_SIMON2) {
2003-10-21 10:34:56 +00:00
if (sound_id >= 0x8000) {
sound_id = -sound_id;
_sound->playAmbient(sound_id);
} else {
2003-10-21 10:34:56 +00:00
_sound->playEffects(sound_id);
}
} else if (_game & GF_TALKIE) {
_sound->playEffects(sound_id);
} else {
playSting(sound_id);
}
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc53_no_op() {
// Start sound effect, panning it with the animation
int snd = vc_read_next_word();
int xoffs = vc_read_next_word();
int vol = vc_read_next_word();
debug(0, "STUB: vc53_no_op: snd %d xoffs %d vol %d", snd, xoffs, vol);
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc54_no_op() {
/* unused */
_vcPtr += 6;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc55_offset_hit_area() {
HitArea *ha = _hitAreas;
uint count = ARRAYSIZE(_hitAreas);
uint16 id = vc_read_next_word();
int16 x = vc_read_next_word();
int16 y = vc_read_next_word();
2002-07-07 19:06:48 +00:00
for (;;) {
if (ha->id == id) {
ha->x += x;
ha->y += y;
break;
}
ha++;
if (!--count)
break;
}
2002-07-07 19:06:48 +00:00
_needHitAreaRecalc++;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc56_delay() {
if (_game & GF_SIMON2) {
2005-10-05 11:37:26 +00:00
uint num = vc_read_var_or_word() * _frameRate;
add_vga_timer(num + VGA_DELAY_BASE, _vcPtr, _vgaCurSpriteId, _vgaCurFileId);
_vcPtr = (byte *)&_vc_get_out_of_code;
}
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc59() {
if (_game & GF_SIMON2) {
uint file = vc_read_next_word();
uint start = vc_read_next_word();
uint end = vc_read_next_word() + 1;
2002-07-07 19:06:48 +00:00
do {
2003-05-24 12:26:28 +00:00
vc_kill_sprite(file, start);
} while (++start != end);
} else {
if (!_sound->isVoiceActive())
vc_skip_next_instruction();
}
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc58() {
uint sprite = _vgaCurSpriteId;
uint file = _vgaCurFileId;
const byte *vc_ptr_org;
uint16 tmp;
2002-07-07 19:06:48 +00:00
_vgaCurFileId = vc_read_next_word();
_vgaCurSpriteId = vc_read_next_word();
tmp = to16Wrapper(vc_read_next_word());
2002-07-07 19:06:48 +00:00
vc_ptr_org = _vcPtr;
_vcPtr = (byte *)&tmp;
2005-05-06 13:22:48 +00:00
vc23_setSpritePriority();
_vcPtr = vc_ptr_org;
_vgaCurSpriteId = sprite;
_vgaCurFileId = file;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc57_no_op() {
/* unused */
}
void SimonEngine::vc_kill_sprite(uint file, uint sprite) {
uint16 old_sprite_id, old_cur_file_id;
VgaSleepStruct *vfs;
VgaSprite *vsp;
VgaTimerEntry *vte;
const byte *vc_ptr_org;
old_sprite_id = _vgaCurSpriteId;
old_cur_file_id = _vgaCurFileId;
vc_ptr_org = _vcPtr;
2002-07-07 19:06:48 +00:00
_vgaCurFileId = file;
_vgaCurSpriteId = sprite;
2002-07-07 19:06:48 +00:00
vfs = _vgaSleepStructs;
while (vfs->ident != 0) {
2005-05-06 12:29:37 +00:00
if (vfs->sprite_id == _vgaCurSpriteId && ((_game & GF_SIMON1) || vfs->cur_vga_file == _vgaCurFileId)) {
2002-07-07 19:06:48 +00:00
while (vfs->ident != 0) {
memcpy(vfs, vfs + 1, sizeof(VgaSleepStruct));
vfs++;
}
break;
}
vfs++;
}
2002-07-07 19:06:48 +00:00
vsp = find_cur_sprite();
if (vsp->id) {
2005-05-06 13:22:48 +00:00
vc25_halt_sprite();
vte = _vgaTimerList;
while (vte->delay != 0) {
2005-05-06 12:29:37 +00:00
if (vte->sprite_id == _vgaCurSpriteId && ((_game & GF_SIMON1) || vte->cur_vga_file == _vgaCurFileId)) {
delete_vga_timer(vte);
break;
}
vte++;
}
}
_vgaCurFileId = old_cur_file_id;
_vgaCurSpriteId = old_sprite_id;
_vcPtr = vc_ptr_org;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc60_killSprite() {
uint file;
if (_game & GF_SIMON2) {
file = vc_read_next_word();
} else {
file = _vgaCurFileId;
}
uint sprite = vc_read_next_word();
2003-05-24 12:26:28 +00:00
vc_kill_sprite(file, sprite);
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc61_changeSprite() {
2002-07-07 19:06:48 +00:00
VgaSprite *vsp = find_cur_sprite();
vsp->image = vc_read_var_or_word();
vsp->x += vc_read_next_word();
vsp->y += vc_read_next_word();
vsp->flags = 0x24;
_vgaSpriteChanged++;
}
2005-10-05 11:37:26 +00:00
void SimonEngine::vc62_fastFadeOut() {
uint i;
2005-05-06 13:22:48 +00:00
vc29_stopAllSounds();
2002-07-07 19:06:48 +00:00
if (!_videoVar3) {
_videoVar3 = true;
_videoNumPalColors = 256;
2005-10-05 11:37:26 +00:00
if (_windowNum == 4)
_videoNumPalColors = 208;
memcpy(_videoBuf1, _paletteBackup, _videoNumPalColors * sizeof(uint32));
for (i = NUM_PALETTE_FADEOUT; i != 0; --i) {
palette_fadeout((uint32 *)_videoBuf1, _videoNumPalColors);
_system->setPalette(_videoBuf1, 0, _videoNumPalColors);
if (_fade)
_system->updateScreen();
delay(5);
}
if (_game & GF_SIMON1) {
2005-05-06 13:22:48 +00:00
uint16 params[5]; /* parameters to vc10_draw */
VgaSprite *vsp;
VgaPointersEntry *vpe;
const byte *vc_ptr_org = _vcPtr;
vsp = _vgaSprites;
while (vsp->id != 0) {
if (vsp->id == 0x80) {
byte *old_file_1 = _curVgaFile1;
byte *old_file_2 = _curVgaFile2;
2005-10-05 11:37:26 +00:00
uint palmode = _windowNum;
2005-05-06 13:22:48 +00:00
vpe = &_vgaBufferPointers[vsp->fileId];
_curVgaFile1 = vpe->vgaFile1;
_curVgaFile2 = vpe->vgaFile2;
2005-10-05 11:37:26 +00:00
_windowNum = vsp->windowNum;
params[0] = READ_BE_UINT16(&vsp->image);
2005-10-05 11:37:26 +00:00
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;
2005-05-06 13:22:48 +00:00
vc10_draw();
2005-10-05 11:37:26 +00:00
_windowNum = palmode;
_curVgaFile1 = old_file_1;
_curVgaFile2 = old_file_2;
break;
}
vsp++;
}
_vcPtr = vc_ptr_org;
}
// Allow one section of Simon the Sorcerer 1 introduction to be displayed
// in lower half of screen
if ((_game & GF_SIMON1) && (_subroutine == 2923 || _subroutine == 2926))
dx_clear_surfaces(200);
else
2005-10-05 11:37:26 +00:00
dx_clear_surfaces(_windowNum == 4 ? 134 : 200);
}
if (_game & GF_SIMON2) {
if (_nextMusicToPlay != -1)
loadMusic(_nextMusicToPlay);
}
}
2005-10-05 11:37:26 +00:00
void SimonEngine::vc63_fastFadeIn() {
_paletteColorCount = 208;
2005-10-05 11:37:26 +00:00
if (_windowNum != 4) {
_paletteColorCount = 256;
}
_videoVar3 = false;
}
2005-10-05 11:37:26 +00:00
void SimonEngine::vc64_skipIfSpeechEnded() {
2003-03-06 19:16:24 +00:00
// Simon2
if (!_sound->isVoiceActive() || (_subtitles && _language != 20))
vc_skip_next_instruction();
}
2005-10-05 11:37:26 +00:00
void SimonEngine::vc65_slowFadeIn() {
2003-03-06 19:16:24 +00:00
// Simon2
_paletteColorCount = 624;
_videoNumPalColors = 208;
2005-10-05 11:37:26 +00:00
if (_windowNum != 4) {
_paletteColorCount = 768;
_videoNumPalColors = 256;
}
_paletteColorCount |= 0x8000;
_videoVar3 = false;
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc66_skipIfNotEqual() {
2003-03-06 19:16:24 +00:00
// Simon2
uint a = vc_read_next_word();
uint b = vc_read_next_word();
if (vc_read_var(a) != vc_read_var(b))
vc_skip_next_instruction();
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc67_skipIfGE() {
2003-03-06 19:16:24 +00:00
// Simon2
uint a = vc_read_next_word();
uint b = vc_read_next_word();
if (vc_read_var(a) >= vc_read_var(b))
vc_skip_next_instruction();
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc68_skipIfLE() {
2003-03-06 19:16:24 +00:00
// Simon2
uint a = vc_read_next_word();
uint b = vc_read_next_word();
if (vc_read_var(a) <= vc_read_var(b))
vc_skip_next_instruction();
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc69_playTrack() {
2003-03-06 19:16:24 +00:00
// Simon2
int16 track = vc_read_next_word();
2003-05-21 04:36:09 +00:00
int16 loop = vc_read_next_word();
// Jamieson630:
2003-05-21 04:36:09 +00:00
// This is a "play track". The original
// design stored the track to play if one was
// already in progress, so that the next time a
// "fill MIDI stream" event occured, the MIDI
// player would find the change and switch
// tracks. We use a different architecture that
// allows for an immediate response here, but
// we'll simulate the variable changes so other
// scripts don't get thrown off.
// NOTE: This opcode looks very similar in function
2005-05-06 13:22:48 +00:00
// to vc72(), except that vc72() may allow for
// specifying a non-valid track number (999 or -1)
// as a means of stopping what music is currently
// playing.
2003-09-24 06:33:59 +00:00
midi.setLoop(loop != 0);
midi.startTrack(track);
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc70_queueMusic() {
2003-03-06 19:16:24 +00:00
// Simon2
2003-05-21 04:36:09 +00:00
uint16 track = vc_read_next_word();
uint16 loop = vc_read_next_word();
// Jamieson630:
// This sets the "on end of track" action.
// It specifies whether to loop the current
// track and, if not, whether to switch to
// a different track upon completion.
2003-05-21 11:23:53 +00:00
if (track != 0xFFFF && track != 999)
2003-09-24 06:33:59 +00:00
midi.queueTrack(track, loop != 0);
else
2003-09-24 06:33:59 +00:00
midi.setLoop(loop != 0);
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc71_checkMusicQueue() {
2003-03-06 19:16:24 +00:00
// Simon2
2003-05-21 04:36:09 +00:00
// Jamieson630:
// This command skips the next instruction
// unless (1) there is a track playing, AND
// (2) there is a track queued to play after it.
if (!midi.isPlaying (true))
vc_skip_next_instruction();
}
2005-05-06 13:22:48 +00:00
void SimonEngine::vc72_play_track_2() {
2003-03-06 19:16:24 +00:00
// Simon2
// Jamieson630:
// This is a "play or stop track". Note that
// this opcode looks very similar in function
2005-05-06 13:22:48 +00:00
// to vc69(), except that this opcode may allow
// for specifying a track of 999 or -1 in order to
// stop the music. We'll code it that way for now.
2003-05-21 04:36:09 +00:00
// NOTE: It's possible that when "stopping" a track,
// we're supposed to just go on to the next queued
// track, if any. Must find out if there is ANY
// case where this is used to stop a track in the
// first place.
int16 track = vc_read_next_word();
2003-05-21 04:36:09 +00:00
int16 loop = vc_read_next_word();
if (track == -1 || track == 999) {
midi.stop();
} else {
midi.setLoop (loop != 0);
2003-05-21 06:13:47 +00:00
midi.startTrack (track);
}
}
2005-10-05 11:37:26 +00:00
void SimonEngine::vc73_setMark() {
2003-03-06 19:16:24 +00:00
// Simon2
vc_read_next_byte();
2005-10-05 11:37:26 +00:00
_marks |= 1 << vc_read_next_byte();
}
2005-10-05 11:37:26 +00:00
void SimonEngine::vc74_clearMark() {
2003-03-06 19:16:24 +00:00
// Simon2
vc_read_next_byte();
2005-10-05 11:37:26 +00:00
_marks &= ~(1 << vc_read_next_byte());
}
2003-10-03 19:42:27 +00:00
void SimonEngine::vc75_setScale() {
// Set scale
int baseY = vc_read_next_word();
int scale = vc_read_next_word();
debug(0, "STUB: vc75_setScale: baseY %d scale %d", baseY, scale);
}
void SimonEngine::vc76_setScaleXOffs() {
// Scale X related
int image = vc_read_next_word();
int xoffs = vc_read_next_word();
int var = vc_read_next_word();
debug(0, "STUB: vc76_setScaleXOffs: image %d xoffs %d flag %d", image, xoffs, var);
}
void SimonEngine::vc77_setScaleYOffs() {
// Scale Y related
int image = vc_read_next_word();
int yoffs = vc_read_next_word();
int var = vc_read_next_word();
debug(0, "STUB: vc77_setScaleYOffs: image %d yoffs %d flag %d", image, yoffs, var);
}
void SimonEngine::vc78_pathUnk1() {
// Pathfinder related
debug(0, "STUB: vc78_pathUnk1");
}
void SimonEngine::vc79_pathUnk2() {
// Pathfinder related
debug(0, "STUB: vc79_pathUnk2");
}
void SimonEngine::vc80_setOverlayImage() {
VgaSprite *vsp = find_cur_sprite();
vsp->image = vc_read_var_or_word();
vsp->x += vc_read_next_word();
vsp->y += vc_read_next_word();
vsp->flags = 0x10;
_vgaSpriteChanged++;
}
void SimonEngine::vc81_setRandom() {
uint var = vc_read_next_word();
uint value = vc_read_next_word();
writeVariable(var, _rnd.getRandomNumber(value - 1));
}
void SimonEngine::vc82_pathUnk3() {
// Set var to path position
int var = vc_read_next_word();
debug(0, "STUB: vc82_pathUnk3: var %d", var);
}
void SimonEngine::vc83_playSoundLoop() {
// Start looping sound effect
int snd = vc_read_next_word();
int vol = vc_read_next_word();
int pan = vc_read_next_word();
debug(0, "STUB: vc83_playSoundLoop: snd %d vol %d pan %d", snd, vol, pan);
}
void SimonEngine::vc84_stopSoundLoop() {
// Stop looping sound effect
debug(0, "STUB: vc84_stopSoundLoop");
}
2003-10-03 19:42:27 +00:00
} // End of namespace Simon