diff options
author | Max Horn | 2006-02-11 22:45:04 +0000 |
---|---|---|
committer | Max Horn | 2006-02-11 22:45:04 +0000 |
commit | 26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch) | |
tree | 26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/simon/vga.cpp | |
parent | 2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff) | |
download | scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2 scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip |
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/simon/vga.cpp')
-rw-r--r-- | engines/simon/vga.cpp | 2299 |
1 files changed, 2299 insertions, 0 deletions
diff --git a/engines/simon/vga.cpp b/engines/simon/vga.cpp new file mode 100644 index 0000000000..d7d0731539 --- /dev/null +++ b/engines/simon/vga.cpp @@ -0,0 +1,2299 @@ +/* ScummVM - Scumm Interpreter + * 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 "simon/simon.h" +#include "simon/intern.h" +#include "simon/vga.h" + +#include "common/system.h" + +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_setMaskImage, + &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_computeXY, + &SimonEngine::vc79_computePosNum, + &SimonEngine::vc80_setOverlayImage, + &SimonEngine::vc81_setRandom, + &SimonEngine::vc82_getPathValue, + &SimonEngine::vc83_playSoundLoop, + &SimonEngine::vc84_stopSoundLoop, + }; + + _vga_opcode_table = vga_opcode_table; +} + +// Script parser +void SimonEngine::run_vga_script() { + 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); + } + } + + if (getGameType() == GType_SIMON1) { + opcode = READ_BE_UINT16(_vcPtr); + _vcPtr += 2; + } else { + opcode = *_vcPtr++; + } + + if (opcode >= NUM_VIDEO_OP_CODES) + error("Invalid VGA opcode '%d' encountered", opcode); + + if (opcode == 0) + return; + + (this->*_vga_opcode_table[opcode]) (); + } +} + +int SimonEngine::vcReadVarOrWord() { + int16 var = vcReadNextWord(); + if (var < 0) + var = vcReadVar(-var); + return var; +} + +uint SimonEngine::vcReadNextWord() { + uint a; + a = readUint16Wrapper(_vcPtr); + _vcPtr += 2; + return a; +} + +uint SimonEngine::vcReadNextByte() { + return *_vcPtr++; +} + +void SimonEngine::vcSkipNextInstruction() { + 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 + }; + + if (getGameType() == GType_FF) { + uint opcode = vcReadNextByte(); + _vcPtr += opcodeParamLenFeebleFiles[opcode]; + } else if (getGameType() == GType_SIMON2) { + uint opcode = vcReadNextByte(); + _vcPtr += opcodeParamLenSimon2[opcode]; + } else { + uint opcode = vcReadNextWord(); + _vcPtr += opcodeParamLenSimon1[opcode]; + } + + if (_continousVgaScript) + fprintf(_dumpFile, "; skipped\n"); +} + +void SimonEngine::o_unloadBeard() { + // Simon1 Only + if (_beardLoaded == true) { + _beardLoaded = false; + _lockWord |= 0x8000; + read_vga_from_datfile_1(23); + _lockWord &= ~0x8000; + } +} + +void SimonEngine::o_loadBeard() { + // Simon1 Only + if (_beardLoaded == false) { + _beardLoaded = true; + _lockWord |= 0x8000; + read_vga_from_datfile_1(328); + _lockWord &= ~0x8000; + } +} + +// VGA Script commands +void SimonEngine::vc1_fadeOut() { + /* dummy opcode */ + _vcPtr += 6; +} + +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 = vcReadVarOrWord(); + + old_file_1 = _curVgaFile1; + old_file_2 = _curVgaFile2; + + for (;;) { + res = num / 100; + vpe = &_vgaBufferPointers[res]; + + _curVgaFile1 = vpe->vgaFile1; + _curVgaFile2 = vpe->vgaFile2; + if (vpe->vgaFile1 != NULL) + break; + if (_vgaCurFile2 != res) + _videoVar7 = _vgaCurFile2; + + loadZone(res); + _videoVar7 = 0xFFFF; + } + + + bb = _curVgaFile1; + if (getGameType() == GType_FF) { + 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 (getGameType() == GType_FF) { + _vcPtr = _curVgaFile1 + READ_LE_UINT16(&((ImageHeader_Feeble *) b)->scriptOffs); + } else { + _vcPtr = _curVgaFile1 + READ_BE_UINT16(&((ImageHeader_Simon *) b)->scriptOffs); + } + + //dump_vga_script(_vcPtr, res, num); + run_vga_script(); + + _curVgaFile1 = old_file_1; + _curVgaFile2 = old_file_2; + + _vcPtr = vc_ptr_org; +} + +void SimonEngine::vc3_loadSprite() { + uint16 windowNum, fileId, palette, x, y, vgaSpriteId; + uint16 res; + VgaSprite *vsp; + VgaPointersEntry *vpe; + byte *p, *pp; + byte *old_file_1; + + windowNum = vcReadNextWord(); /* 0 */ + + if (getGameType() == GType_SIMON1) { + vgaSpriteId = vcReadNextWord(); /* 2 */ + fileId = vgaSpriteId / 100; + } else { + fileId = vcReadNextWord(); /* 0 */ + vgaSpriteId = vcReadNextWord(); /* 2 */ + } + + x = vcReadNextWord(); /* 4 */ + y = vcReadNextWord(); /* 6 */ + palette = vcReadNextWord(); /* 8 */ + + /* 2nd param ignored with simon1 */ + if (isSpriteLoaded(vgaSpriteId, fileId)) + return; + + vsp = _vgaSprites; + while (vsp->id) + vsp++; + + vsp->palette = palette; + vsp->windowNum = windowNum; + vsp->priority = 0; + vsp->flags = 0; + vsp->image = 0; + vsp->x = x; + vsp->y = y; + vsp->id = vgaSpriteId; + vsp->fileId = res = fileId; + + old_file_1 = _curVgaFile1; + for (;;) { + vpe = &_vgaBufferPointers[res]; + _curVgaFile1 = vpe->vgaFile1; + + if (vpe->vgaFile1 != NULL) + break; + if (_vgaCurFile2 != res) + _videoVar7 = _vgaCurFile2; + + loadZone(res); + _videoVar7 = 0xFFFF; + } + + pp = _curVgaFile1; + if (getGameType() == GType_FF) { + 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); + + while (READ_BE_UINT16(&((AnimationHeader_Simon *) p)->id) != vgaSpriteId) + p += sizeof(AnimationHeader_Simon); + } + +#ifdef DUMP_FILE_NR + { + static bool dumped = false; + if (res == DUMP_FILE_NR && !dumped) { + dumped = true; + dump_vga_file(_curVgaFile1); + } + } +#endif + +#ifdef DUMP_BITMAPS_FILE_NR + { + static bool dumped = false; + if (res == DUMP_BITMAPS_FILE_NR && !dumped) { + dumped = true; + dump_vga_bitmaps(_curVgaFile2, _curVgaFile1, res); + } + } +#endif + + if (_startVgaScript) { + if (getGameType() == GType_FF) { + 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 (getGameType() == GType_FF) { + 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; +} + +void SimonEngine::vc4_fadeIn() { + /* dummy opcode */ + _vcPtr += 6; +} + +void SimonEngine::vc5_skip_if_neq() { + uint var = vcReadNextWord(); + uint value = vcReadNextWord(); + if (vcReadVar(var) != value) + vcSkipNextInstruction(); +} + +void SimonEngine::vc6_skip_ifn_sib_with_a() { + if (!itemIsSiblingOf(vcReadNextWord())) + vcSkipNextInstruction(); +} + +void SimonEngine::vc7_skip_if_sib_with_a() { + if (itemIsSiblingOf(vcReadNextWord())) + vcSkipNextInstruction(); +} + +void SimonEngine::vc8_skip_if_parent_is() { + uint a = vcReadNextWord(); + uint b = vcReadNextWord(); + if (!itemIsParentOf(a, b)) + vcSkipNextInstruction(); +} + +void SimonEngine::vc9_skip_if_unk3_is() { + uint a = vcReadNextWord(); + uint b = vcReadNextWord(); + if (!vc_maybe_skip_proc_1(a, b)) + vcSkipNextInstruction(); +} + +byte *vc10_depack_column(VC10_state * vs) { + int8 a = vs->depack_cont; + const byte *src = vs->depack_src; + byte *dst = vs->depack_dest; + uint16 dh = vs->dh; + byte color; + + if (a == -0x80) + a = *src++; + + for (;;) { + if (a >= 0) { + color = *src++; + do { + *dst++ = color; + if (!--dh) { + if (--a < 0) + a = -0x80; + else + src--; + goto get_out; + } + } while (--a >= 0); + } else { + do { + *dst++ = *src++; + if (!--dh) { + if (++a == 0) + a = -0x80; + goto get_out; + } + } while (++a != 0); + } + a = *src++; + } + +get_out:; + vs->depack_src = src; + vs->depack_cont = a; + return vs->depack_dest + vs->y_skip; +} + +void vc10_skip_cols(VC10_state *vs) { + vs->depack_cont = -0x80; + while (vs->x_skip) { + vc10_depack_column(vs); + vs->x_skip--; + } +} + +byte *SimonEngine::vc10_uncompressFlip(const byte *src, uint w, uint h) { + w *= 8; + + byte *src_org, *dst_org; + byte color; + int8 cur = -0x80; + uint i, w_cur = w; + + dst_org = _videoBuf1 + w; + + 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); + } + cur = *src++; + } + next_line: + dst_org++; + } while (--w_cur); + + + 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; +} + +byte *SimonEngine::vc10_flip(const byte *src, uint w, uint h) { + if (src == _vc10BasePtrOld) + return _videoBuf1; + + _vc10BasePtrOld = src; + + byte *dst_org, *src_org; + uint i; + + w *= 8; + 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; +} + +/* must not be const */ +static uint16 _video_windows[128] = { + 0, 0, 20, 200, + 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; + uint h = height, w = 8; + + for (;;) { + reps = *src++; + if (reps >= 0) { + color = *src++; + + do { + *dst = color; + dst += pitch; + + /* reached bottom? */ + if (--h == 0) { + /* reached right edge? */ + if (--w == 0) + return; + dst = ++dst_org; + h = height; + } + } while (--reps >= 0); + } else { + + do { + *dst = *src++; + dst += pitch; + + /* reached bottom? */ + if (--h == 0) { + /* reached right edge? */ + if (--w == 0) + return; + dst = ++dst_org; + h = height; + } + } while (++reps != 0); + } + } +} + +void SimonEngine::vc10_draw() { + byte *p2; + uint width, height; + uint maxWidth, maxHeight; + byte flags; + const uint16 *vlut; + VC10_state state; + + int cur; + + state.image = (int16)vcReadNextWord(); + if (state.image == 0) + return; + + if (getGameType() == GType_FF) { + state.palette = (_vcPtr[0] * 16); + } else { + state.palette = (_vcPtr[1] * 16); + } + _vcPtr += 2; + state.x = (int16)vcReadNextWord(); + + if (getGameType() == GType_SIMON2) { + state.x -= _scrollX; + } + state.y = (int16)vcReadNextWord(); + + if (getGameType() == GType_SIMON1) { + state.flags = vcReadNextWord(); + } else { + state.flags = vcReadNextByte(); + } + + if (state.image < 0) + state.image = vcReadVar(-state.image); + + debug(1, "vc10_draw: image %d palette %d x %d y %d flags 0x0%x\n", state.image, state.palette, state.x, state.y, state.flags); + + p2 = _curVgaFile2 + state.image * 8; + if (getGameType() == GType_FF) { + state.depack_src = _curVgaFile2 + READ_LE_UINT32(p2); + width = READ_LE_UINT16(p2 + 6); + height = READ_LE_UINT16(p2 + 4) & 0x7FFF; + flags = p2[5]; + + debug(1, "Width %d Height %d Flags 0x%x", width, height, flags); + } else { + state.depack_src = _curVgaFile2 + READ_BE_UINT32(p2); + width = READ_BE_UINT16(p2 + 6) / 16; + height = p2[5]; + flags = p2[4]; + } + + if (height == 0 || width == 0) + return; + + if (_dumpImages) + dump_single_bitmap(_vgaCurFileId, state.image, state.depack_src, width * 16, height, + state.palette); + // TODO::Add support for image overlay and scaling in Feeble Files + + if (flags & 0x80 && !(state.flags & 0x10)) { + if (state.flags & 1) { + state.flags &= ~1; + state.flags |= 0x10; + } else { + state.flags |= 0x8; + } + } + + if (getGameType() == GType_FF) { + if (width > 640) { + debug(0, "Horizontal scrolling not supported"); + return; + } + if (height > 480) { + debug(0, "Vertical scrolling not supported"); + return; + } + } + if (getGameType() == GType_SIMON2 && width > 20) { + const byte *src; + byte *dst; + uint w; + + _scrollXMax = width * 2 - 40; + _scrollImage = state.depack_src; + _scrollHeight = height; + if (_variableArray[34] == -1) + state.x = _variableArray[251]; + + _scrollX = state.x; + + vcWriteVar(251, _scrollX); + + dst = dx_lock_attached(); + src = state.depack_src + _scrollX * 4; + + for (w = 0; w < 40; w++) { + decodeStripA(dst, src + READ_BE_UINT32(src), height); + dst += 8; + src += 4; + } + + dx_unlock_attached(); + + return; + } + + if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { + if (state.flags & 0x10) { + state.depack_src = vc10_uncompressFlip(state.depack_src, width, height); + } else if (state.flags & 1) { + state.depack_src = vc10_flip(state.depack_src, width, height); + } + } + + vlut = &_video_windows[_windowNum * 4]; + + state.width = state.draw_width = width; /* cl */ + state.height = state.draw_height = height; /* ch */ + + if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { + state.draw_width = width * 2; + } + + state.x_skip = 0; /* colums to skip = bh */ + state.y_skip = 0; /* rows to skip = bl */ + + cur = state.x; + if (cur < 0) { + do { + if (!--state.draw_width) + return; + state.x_skip++; + } while (++cur); + } + state.x = cur; + + maxWidth = (getGameType() == GType_FF) ? 640 : (vlut[2] * 2); + cur += state.draw_width - maxWidth; + if (cur > 0) { + do { + if (!--state.draw_width) + return; + } while (--cur); + } + + cur = state.y; + if (cur < 0) { + do { + if (!--state.draw_height) + return; + state.y_skip++; + } while (++cur); + } + state.y = cur; + + maxHeight = (getGameType() == GType_FF) ? 480 : vlut[3]; + cur += state.draw_height - maxHeight; + if (cur > 0) { + do { + if (!--state.draw_height) + return; + } while (--cur); + } + + assert(state.draw_width != 0 && state.draw_height != 0); + + if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { + state.draw_width *= 4; + } + + state.surf2_addr = dx_lock_2(); + state.surf2_pitch = _dxSurfacePitch; + + state.surf_addr = dx_lock_attached(); + state.surf_pitch = _dxSurfacePitch; + + if (getGameType() == GType_FF) { + drawImages_Feeble(&state); + } else { + drawImages(&state); + } + + dx_unlock_2(); + dx_unlock_attached(); +} + +void SimonEngine::drawImages_Feeble(VC10_state *state) { + state->surf2_addr += state->x + state->y * state->surf2_pitch; + state->surf_addr += state->x + state->y * state->surf_pitch; + + if (state->flags & 0x20) { + if (vcGetBit(81) == false) { + // TODO: Compare Feeble rect + } + + uint w, h; + byte *src, *dst, *dst_org; + + state->dl = state->width; + state->dh = state->height; + + vc10_skip_cols(state); + + dst_org = state->surf_addr; + w = 0; + do { + byte color; + + src = vc10_depack_column(state); + dst = dst_org; + + h = 0; + do { + color = *src; + if (color) + *dst = color; + dst += _screenWidth; + src++; + } while (++h != state->draw_height); + dst_org++; + } while (++w != state->draw_width); + } else { + if (state->flags & 0x8) { + uint w, h; + byte *src, *dst, *dst_org; + + state->dl = state->width; + state->dh = state->height; + + vc10_skip_cols(state); + + if (state->flags & 2) { + dst_org = state->surf_addr; + w = 0; + do { + src = vc10_depack_column(state); + dst = dst_org; + + h = 0; + do { + *dst = *src; + dst += _screenWidth; + src++; + } while (++h != state->draw_height); + dst_org++; + } while (++w != state->draw_width); + } else { + dst_org = state->surf_addr; + w = 0; + do { + byte color; + + src = vc10_depack_column(state); + dst = dst_org; + + h = 0; + do { + color = *src; + if (color) + *dst = color; + dst += _screenWidth; + src++; + } while (++h != state->draw_height); + dst_org++; + } while (++w != state->draw_width); + } + } else { + const byte *src; + byte *dst; + uint count; + + src = state->depack_src + state->width * state->y_skip; + dst = state->surf_addr; + if (state->flags & 0x80) { + do { + for (count = 0; count != state->draw_width; count++) { + byte color; + color = src[count + state->x_skip]; + if (color) { + if (color == 220) + color = 244; + + dst[count] = color; + } + } + dst += _screenWidth; + src += state->width; + } while (--state->draw_height); + } else { + do { + for (count = 0; count != state->draw_width; count++) { + byte color; + color = src[count + state->x_skip]; + if (color) + dst[count] = color; + } + dst += _screenWidth; + src += state->width; + } while (--state->draw_height); + } + } + } +} + +void SimonEngine::drawImages(VC10_state *state) { + const uint16 *vlut = &_video_windows[_windowNum * 4]; + + uint offs, offs2; + // Allow one section of Simon the Sorcerer 1 introduction to be displayed + // in lower half of screen + if ((getGameType() == GType_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; + + state->x_skip *= 4; + state->dl = state->width; + state->dh = state->height; + + vc10_skip_cols(state); + + w = 0; + do { + mask = vc10_depack_column(state); /* esi */ + src = state->surf2_addr + w * 2; /* ebx */ + dst = state->surf_addr + w * 2; /* edi */ + + h = state->draw_height; + if ((getGameType() == GType_SIMON1) && vcGetBit(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); + } + } while (++w != state->draw_width); + + /* vc10_helper_5 */ + } else if (((_lockWord & 0x20) && state->palette == 0) || state->palette == 0xC0) { + const byte *src; + byte *dst; + uint h, i; + + if (!(state->flags & 8)) { + src = state->depack_src + (state->width * state->y_skip * 16) + (state->x_skip * 8); + dst = state->surf_addr; + + state->draw_width *= 2; + + if (state->flags & 2) { + /* no transparency */ + h = state->draw_height; + do { + memcpy(dst, src, state->draw_width); + dst += _screenWidth; + src += state->width * 16; + } while (--h); + } else { + /* transparency */ + h = state->draw_height; + do { + for (i = 0; i != state->draw_width; i++) + if (src[i]) + dst[i] = src[i]; + dst += _screenWidth; + src += state->width * 16; + } while (--h); + } + + } else { + byte *dst_org = state->surf_addr; + src = state->depack_src; + /* AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE + * aaaaabbb bbcccccd ddddeeee efffffgg ggghhhhh + */ + + if (state->flags & 2) { + /* no transparency */ + do { + uint count = state->draw_width / 4; + + dst = dst_org; + do { + 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 { + uint count = state->draw_width / 4; + + dst = dst_org; + do { + uint32 bits = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | (src[3]); + byte tmp; + + 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; + } while (--count); + dst_org += _screenWidth; + } while (--state->draw_height); + } + } + /* vc10_helper_4 */ + } else { + if (getGameType() == GType_SIMON2 && state->flags & 0x4 && _bitArray[10] & 0x800) { + state->surf_addr = state->surf2_addr; + state->surf_pitch = state->surf2_pitch; + } + + if (state->flags & 0x8) { + uint w, h; + byte *src, *dst, *dst_org; + + state->x_skip *= 4; /* reached */ + + state->dl = state->width; + state->dh = state->height; + + vc10_skip_cols(state); + + if (state->flags & 2) { + dst_org = state->surf_addr; + w = 0; + do { + src = vc10_depack_column(state); + dst = dst_org; + + h = 0; + do { + dst[0] = (*src / 16) | 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 += vcReadVar(252); + } + w = 0; + do { + byte color; + + src = vc10_depack_column(state); + dst = dst_org; + + h = 0; + do { + color = (*src / 16); + if (color) + dst[0] = color | state->palette; + color = (*src & 15); + if (color) + dst[1] = color | state->palette; + dst += _screenWidth; + src++; + } while (++h != state->draw_height); + dst_org += 2; + } while (++w != state->draw_width); + } + /* vc10_helper_6 */ + } else { + const byte *src; + byte *dst; + uint count; + + src = state->depack_src + (state->width * state->y_skip) * 8; + dst = state->surf_addr; + state->x_skip *= 4; + if (state->flags & 2) { + do { + for (count = 0; count != state->draw_width; count++) { + dst[count * 2] = (src[count + state->x_skip] / 16) | state->palette; + dst[count * 2 + 1] = (src[count + state->x_skip] & 15) | state->palette; + } + dst += _screenWidth; + src += state->width * 8; + } while (--state->draw_height); + } else { + do { + for (count = 0; count != state->draw_width; count++) { + byte color; + color = (src[count + state->x_skip] / 16); + if (color) + dst[count * 2] = color | state->palette; + color = (src[count + state->x_skip] & 15); + if (color) + dst[count * 2 + 1] = color | state->palette; + } + dst += _screenWidth; + src += state->width * 8; + } while (--state->draw_height); + + } + + /* vc10_helper_7 */ + } + } + +} + +void SimonEngine::vc11_clearPathFinder() { + memset(&_pathFindArray, 0, sizeof(_pathFindArray)); +} + +void SimonEngine::vc12_delay() { + VgaSprite *vsp = findCurSprite(); + uint num; + + if (getGameType() == GType_SIMON1) { + num = vcReadVarOrWord(); + } else { + num = vcReadNextByte() * _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 += VGA_DELAY_BASE; + + add_vga_timer(num, _vcPtr, _vgaCurSpriteId, _vgaCurFileId); + _vcPtr = (byte *)&_vc_get_out_of_code; +} + +void SimonEngine::vc13_addToSpriteX() { + VgaSprite *vsp = findCurSprite(); + vsp->x += (int16)vcReadNextWord(); + _vgaSpriteChanged++; +} + +void SimonEngine::vc14_addToSpriteY() { + VgaSprite *vsp = findCurSprite(); + vsp->y += (int16)vcReadNextWord(); + _vgaSpriteChanged++; +} + +void SimonEngine::vc15_wakeup_id() { + VgaSleepStruct *vfs = _vgaSleepStructs, *vfs_tmp; + uint16 id = vcReadNextWord(); + while (vfs->ident != 0) { + if (vfs->ident == id) { + 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; +} + +void SimonEngine::vc16_sleep_on_id() { + VgaSleepStruct *vfs = _vgaSleepStructs; + while (vfs->ident) + vfs++; + + vfs->ident = vcReadNextWord(); + vfs->code_ptr = _vcPtr; + vfs->sprite_id = _vgaCurSpriteId; + vfs->cur_vga_file = _vgaCurFileId; + + _vcPtr = (byte *)&_vc_get_out_of_code; +} + +void SimonEngine::vc17_setPathfinderItem() { + uint a = vcReadNextWord(); + _pathFindArray[a - 1] = (const uint16 *)_vcPtr; + + int end = (getGameType() == GType_FF) ? 9999 : 999; + while (readUint16Wrapper(_vcPtr) != end) + _vcPtr += 4; + _vcPtr += 2; +} + +void SimonEngine::vc18_jump() { + int16 offs = vcReadNextWord(); + _vcPtr += offs; +} + +/* chain to script? */ +void SimonEngine::vc19_chain_to_script() { + /* unused */ + error("vc19_chain_to_script: not implemented"); +} + +/* helper routines */ + +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 = vcReadNextWord(); + WRITE_LE_UINT16(const_cast<byte *>(_vcPtr), a); + _vcPtr += 2; +} + +void SimonEngine::vc21_endRepeat() { + int16 a = vcReadNextWord(); + const byte *tmp = _vcPtr + a; + if (getGameType() == GType_SIMON1) + tmp += 4; + else + tmp += 3; + + uint16 val = READ_LE_UINT16(tmp); + if (val != 0) { + // Decrement counter + WRITE_LE_UINT16(const_cast<byte *>(tmp), val - 1); + _vcPtr = tmp + 2; + } +} + +void SimonEngine::vc22_setSpritePalette() { + uint a = vcReadNextWord(); + uint b = vcReadNextWord(); + uint num = a == 0 ? 32 : 16; + uint palSize = 96; + byte *palptr, *src; + + if (getGameType() == GType_FF) { + a = 0; + num = 256; + palSize = 768; + } + + palptr = &_palette[(a * 64)]; + src = _curVgaFile1 + 6 + b * palSize; + + do { + palptr[0] = src[0] * 4; + palptr[1] = src[1] * 4; + palptr[2] = src[2] * 4; + palptr[3] = 0; + + palptr += 4; + src += 3; + } while (--num); + + _paletteFlag = 2; + _vgaSpriteChanged++; +} + +void SimonEngine::vc23_setSpritePriority() { + 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 SimonEngine::vc24_setSpriteXY() { + VgaSprite *vsp = findCurSprite(); + vsp->image = vcReadVarOrWord(); + + vsp->x += (int16)vcReadNextWord(); + vsp->y += (int16)vcReadNextWord(); + if (getGameType() == GType_SIMON1) { + vsp->flags = vcReadNextWord(); + } else { + vsp->flags = vcReadNextByte(); + } + + _vgaSpriteChanged++; +} + +void SimonEngine::vc25_halt_sprite() { + VgaSprite *vsp = findCurSprite(); + while (vsp->id != 0) { + memcpy(vsp, vsp + 1, sizeof(VgaSprite)); + vsp++; + } + _vcPtr = (byte *)&_vc_get_out_of_code; + _vgaSpriteChanged++; +} + +void SimonEngine::vc26_setSubWindow() { + uint16 *as = &_video_windows[vcReadNextWord() * 4]; // number + as[0] = vcReadNextWord(); // x + as[1] = vcReadNextWord(); // y + as[2] = vcReadNextWord(); // width + as[3] = vcReadNextWord(); // height +} + +void SimonEngine::vc27_resetSprite() { + VgaSprite bak, *vsp; + VgaSleepStruct *vfs; + VgaTimerEntry *vte, *vte2; + + _lockWord |= 8; + + 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 = _vgaSleepStructs; + while (vfs->ident) { + vfs->ident = 0; + vfs++; + } + + vte = _vgaTimerList; + while (vte->delay) { + if ((getGameType() == GType_SIMON1) && vsp->id == 128) { + vte++; + } else { + vte2 = vte; + while (vte2->delay) { + memcpy(vte2, vte2 + 1, sizeof(VgaTimerEntry)); + vte2++; + } + } + } + + vcWriteVar(254, 0); + + _lockWord &= ~8; +} + +void SimonEngine::vc28_dummy_op() { + /* unused */ + _vcPtr += 8; +} + +void SimonEngine::vc29_stopAllSounds() { + _sound->stopAll(); +} + +void SimonEngine::vc30_setFrameRate() { + _frameRate = vcReadNextWord(); +} + +void SimonEngine::vc31_setWindow() { + _windowNum = vcReadNextWord(); +} + +uint SimonEngine::vcReadVar(uint var) { + assert(var < 255); + return (uint16)_variableArray[var]; +} + +void SimonEngine::vcWriteVar(uint var, int16 value) { + _variableArray[var] = value; +} + +void SimonEngine::vc32_copyVar() { + uint16 a = vcReadVar(vcReadNextWord()); + vcWriteVar(vcReadNextWord(), a); +} + +void SimonEngine::vc33_setMouseOn() { + if (_mouseHideCount != 0) { + _mouseHideCount = 1; + mouseOn(); + } +} + +void SimonEngine::vc34_setMouseOff() { + mouseOff(); + _mouseHideCount = 200; + _leftButtonDown = 0; +} + +void SimonEngine::vc35_clearWindow() { + /* unused */ + _vcPtr += 4; + _vgaSpriteChanged++; +} + +void SimonEngine::vc36_setWindowImage() { + _updateScreen = false; + uint vga_res = vcReadNextWord(); + uint windowNum = vcReadNextWord(); + + if (getGameType() == GType_SIMON1) { + if (windowNum == 16) { + _copyPartialMode = 2; + } else { + set_video_mode_internal(windowNum, vga_res); + } + } else { + set_video_mode_internal(windowNum, vga_res); + } +} + +void SimonEngine::vc37_addToSpriteY() { + VgaSprite *vsp = findCurSprite(); + vsp->y += vcReadVar(vcReadNextWord()); + _vgaSpriteChanged++; +} + +void SimonEngine::vc38_skipIfVarZero() { + uint var = vcReadNextWord(); + if (vcReadVar(var) == 0) + vcSkipNextInstruction(); +} + +void SimonEngine::vc39_setVar() { + uint var = vcReadNextWord(); + int16 value = vcReadNextWord(); + vcWriteVar(var, value); +} + +void SimonEngine::vc40() { + uint var = vcReadNextWord(); + int16 value = vcReadVar(var) + vcReadNextWord(); + + if ((getGameType() == GType_SIMON2) && var == 15 && !(_bitArray[5] & 1)) { + 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; + add_vga_timer(6, NULL, 0, 0); /* special timer */ + } + } +no_scroll:; + + vcWriteVar(var, value); +} + +void SimonEngine::vc41() { + uint var = vcReadNextWord(); + int16 value = vcReadVar(var) - vcReadNextWord(); + + if ((getGameType() == GType_SIMON2) && var == 15 && !(_bitArray[5] & 1)) { + int16 tmp; + + 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; + tmp = _scrollXMax - _scrollX; + if (_scrollX < 20) + _scrollCount = -_scrollX; + add_vga_timer(6, NULL, 0, 0); /* special timer */ + } + } +no_scroll:; + + vcWriteVar(var, value); +} + +void SimonEngine::vc42_delayIfNotEQ() { + uint val = vcReadVar(vcReadNextWord()); + if (val != vcReadNextWord()) { + + add_vga_timer(_frameRate + 1, _vcPtr - 4, _vgaCurSpriteId, _vgaCurFileId); + _vcPtr = (byte *)&_vc_get_out_of_code; + } +} + +void SimonEngine::vc43_skipIfBitClear() { + if (!vcGetBit(vcReadNextWord())) { + vcSkipNextInstruction(); + } +} + +void SimonEngine::vc44_skipIfBitSet() { + if (vcGetBit(vcReadNextWord())) { + vcSkipNextInstruction(); + } +} + +void SimonEngine::vc45_setSpriteX() { + VgaSprite *vsp = findCurSprite(); + vsp->x = vcReadVar(vcReadNextWord()); + _vgaSpriteChanged++; +} + +void SimonEngine::vc46_setSpriteY() { + VgaSprite *vsp = findCurSprite(); + vsp->y = vcReadVar(vcReadNextWord()); + _vgaSpriteChanged++; +} + +void SimonEngine::vc47_addToVar() { + uint var = vcReadNextWord(); + vcWriteVar(var, vcReadVar(var) + vcReadVar(vcReadNextWord())); +} + +void SimonEngine::vc48_setPathFinder() { + uint a = (uint16)_variableArray[12]; + const uint16 *p = _pathFindArray[a - 1]; + + if (getGameType() == GType_FF) { + VgaSprite *vsp = findCurSprite(); + int16 x, x2, y, y1, y2, ydiff; + uint pos = 0; + + while(vsp->x > readUint16Wrapper(p + 2)) { + p += 2; + pos++; + } + + y1 = readUint16Wrapper(p + 1); + x2 = readUint16Wrapper(p + 2); + y2 = readUint16Wrapper(p + 3); + + if (x2 != 9999) { + ydiff = y2 - y1; + if (ydiff < 0) { + ydiff = -ydiff; + x = vsp->x & 7; + ydiff *= x; + ydiff /= 8; + ydiff = -ydiff; + } else { + x = vsp->x & 7; + ydiff *= x; + ydiff /= 8; + } + y1 += ydiff; + } + + y = vsp->y; + vsp->y = y1; + //checkScrollY(y, diff); + + _variableArray[11] = readUint16Wrapper(p); + _variableArray[13] = pos; + } else { + uint b = (uint16)_variableArray[13]; + p += b * 2 + 1; + int c = _variableArray[14]; + + int step; + int y1, y2; + int16 *vp; + + step = 2; + if (c < 0) { + c = -c; + step = -2; + } + + vp = &_variableArray[20]; + + do { + y2 = readUint16Wrapper(p); + p += step; + y1 = readUint16Wrapper(p) - y2; + + vp[0] = y1 / 2; + vp[1] = y1 - (y1 / 2); + + vp += 2; + } while (--c); + } +} + +void SimonEngine::vcSetBitTo(uint bit, bool value) { + uint16 *bits = &_bitArray[bit >> 4]; + *bits = (*bits & ~(1 << (bit & 15))) | (value << (bit & 15)); +} + +bool SimonEngine::vcGetBit(uint bit) { + uint16 *bits = &_bitArray[bit >> 4]; + return (*bits & (1 << (bit & 15))) != 0; +} + +void SimonEngine::vc49_setBit() { + vcSetBitTo(vcReadNextWord(), true); +} + +void SimonEngine::vc50_clearBit() { + vcSetBitTo(vcReadNextWord(), false); +} + +void SimonEngine::vc51_clear_hitarea_bit_0x40() { + clear_hitarea_bit_0x40(vcReadNextWord()); +} + +void SimonEngine::vc52_playSound() { + bool ambient = false; + + uint16 sound = vcReadNextWord(); + if (sound >= 0x8000) { + ambient = true; + sound = -sound; + } + + if (getGameType() == GType_FF) { + uint16 pan = vcReadNextWord(); + uint16 vol = vcReadNextWord(); + _sound->playSoundData(_curSfxFile, sound, pan, vol, ambient); + } 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 SimonEngine::vc53_no_op() { + // Start sound effect, panning it with the animation + int snd = vcReadNextWord(); + int xoffs = vcReadNextWord(); + int vol = vcReadNextWord(); + debug(0, "STUB: vc53_no_op: snd %d xoffs %d vol %d", snd, xoffs, vol); +} + +void SimonEngine::vc54_no_op() { + /* unused */ + _vcPtr += 6; +} + +void SimonEngine::vc55_offset_hit_area() { + 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 SimonEngine::vc56_delay() { + uint num = vcReadVarOrWord() * _frameRate; + + add_vga_timer(num + VGA_DELAY_BASE, _vcPtr, _vgaCurSpriteId, _vgaCurFileId); + _vcPtr = (byte *)&_vc_get_out_of_code; +} + +void SimonEngine::vc59() { + if (getGameType() == GType_SIMON1) { + if (!_sound->isVoiceActive()) + vcSkipNextInstruction(); + } else { + uint file = vcReadNextWord(); + uint start = vcReadNextWord(); + uint end = vcReadNextWord() + 1; + + do { + vc_kill_sprite(file, start); + } while (++start != end); + } +} + +void SimonEngine::vc58() { + uint sprite = _vgaCurSpriteId; + uint file = _vgaCurFileId; + const byte *vc_ptr_org; + uint16 tmp; + + _vgaCurFileId = vcReadNextWord(); + _vgaCurSpriteId = vcReadNextWord(); + + tmp = to16Wrapper(vcReadNextWord()); + + vc_ptr_org = _vcPtr; + _vcPtr = (byte *)&tmp; + vc23_setSpritePriority(); + + _vcPtr = vc_ptr_org; + _vgaCurSpriteId = sprite; + _vgaCurFileId = file; +} + +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; + + _vgaCurFileId = file; + _vgaCurSpriteId = sprite; + + vfs = _vgaSleepStructs; + while (vfs->ident != 0) { + if (vfs->sprite_id == _vgaCurSpriteId && ((getGameType() == GType_SIMON1) || vfs->cur_vga_file == _vgaCurFileId)) { + 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 == _vgaCurFileId)) { + delete_vga_timer(vte); + break; + } + vte++; + } + } + + _vgaCurFileId = old_cur_file_id; + _vgaCurSpriteId = old_sprite_id; + _vcPtr = vc_ptr_org; +} + +void SimonEngine::vc60_killSprite() { + uint file; + + if (getGameType() == GType_SIMON1) { + file = _vgaCurFileId; + } else { + file = vcReadNextWord(); + } + uint sprite = vcReadNextWord(); + vc_kill_sprite(file, sprite); +} + +void SimonEngine::vc61_setMaskImage() { + VgaSprite *vsp = findCurSprite(); + + vsp->image = vcReadVarOrWord(); + + vsp->x += vcReadNextWord(); + vsp->y += vcReadNextWord(); + vsp->flags = 0x24; + + _vgaSpriteChanged++; +} + +void SimonEngine::vc62_fastFadeOut() { + uint i; + + vc29_stopAllSounds(); + + if (!_fastFadeOutFlag) { + _fastFadeOutFlag = true; + + _videoNumPalColors = 256; + if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { + if (_windowNum == 4) + _videoNumPalColors = 208; + } + + memcpy(_videoBuf1, _paletteBackup, _videoNumPalColors * 4); + 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 (getGameType() == GType_SIMON1) { + 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 == 128) { + byte *old_file_1 = _curVgaFile1; + byte *old_file_2 = _curVgaFile2; + uint palmode = _windowNum; + + vpe = &_vgaBufferPointers[vsp->fileId]; + _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 = vc_ptr_org; + } + + // 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)) { + dx_clear_surfaces(200); + } else if (getGameType() == GType_FF) { + dx_clear_surfaces(480); + } else { + dx_clear_surfaces(_windowNum == 4 ? 134 : 200); + } + } + if (getGameType() == GType_SIMON2) { + if (_nextMusicToPlay != -1) + loadMusic(_nextMusicToPlay); + } + +} + +void SimonEngine::vc63_fastFadeIn() { + if (getGameType() == GType_FF) { + _paletteColorCount = 256; + } else { + _paletteColorCount = 208; + if (_windowNum != 4) { + _paletteColorCount = 256; + } + } + _fastFadeOutFlag = false; +} + +void SimonEngine::vc64_skipIfSpeechEnded() { + if (!_sound->isVoiceActive() || (_subtitles && _language != Common::HB_ISR)) + vcSkipNextInstruction(); +} + +void SimonEngine::vc65_slowFadeIn() { + _paletteColorCount = 624; + _videoNumPalColors = 208; + if (_windowNum != 4) { + _paletteColorCount = 768; + _videoNumPalColors = 256; + } + _paletteColorCount |= 0x8000; + _fastFadeOutFlag = false; +} + +void SimonEngine::vc66_skipIfNotEqual() { + uint a = vcReadNextWord(); + uint b = vcReadNextWord(); + + if (vcReadVar(a) != vcReadVar(b)) + vcSkipNextInstruction(); +} + +void SimonEngine::vc67_skipIfGE() { + uint a = vcReadNextWord(); + uint b = vcReadNextWord(); + + if (vcReadVar(a) >= vcReadVar(b)) + vcSkipNextInstruction(); +} + +void SimonEngine::vc68_skipIfLE() { + uint a = vcReadNextWord(); + uint b = vcReadNextWord(); + + if (vcReadVar(a) <= vcReadVar(b)) + vcSkipNextInstruction(); +} + +void SimonEngine::vc69_playTrack() { + int16 track = vcReadNextWord(); + int16 loop = vcReadNextWord(); + + // Jamieson630: + // 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 + // 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. + midi.setLoop(loop != 0); + midi.startTrack(track); +} + +void SimonEngine::vc70_queueMusic() { + // Simon2 + uint16 track = vcReadNextWord(); + uint16 loop = vcReadNextWord(); + + // 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. + if (track != 0xFFFF && track != 999) + midi.queueTrack(track, loop != 0); + else + midi.setLoop(loop != 0); +} + +void SimonEngine::vc71_checkMusicQueue() { + // 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)) + vcSkipNextInstruction(); +} + +void SimonEngine::vc72_play_track_2() { + // Jamieson630: + // This is a "play or stop track". Note that + // this opcode looks very similar in function + // 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. + + // 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 = vcReadNextWord(); + int16 loop = vcReadNextWord(); + + if (track == -1 || track == 999) { + midi.stop(); + } else { + midi.setLoop (loop != 0); + midi.startTrack (track); + } +} + +void SimonEngine::vc73_setMark() { + vcReadNextByte(); + _marks |= 1 << vcReadNextByte(); +} + +void SimonEngine::vc74_clearMark() { + vcReadNextByte(); + _marks &= ~(1 << vcReadNextByte()); +} + +int SimonEngine::getScale(int y, int x) { + int z; + + if (y > _baseY) { + return((int)(x * (1 + ((y - _baseY) * _scale)))); + } else { + if (x == 0) + return(0); + if (x < 0) { + z = ((int)((x * (1 - ((_baseY - y)* _scale))) - 0.5)); + if (z >- 2) + return(-2); + return(z); + } + + z=((int)((x * (1 - ((_baseY-y) * _scale))) + 0.5)); + if (z < 2) + return(2); + + return(z); + } +} + +void SimonEngine::vc75_setScale() { + _baseY = vcReadNextWord(); + _scale = (float)vcReadNextWord() / 1000000.; +} + +void SimonEngine::vc76_setScaleXOffs() { + VgaSprite *vsp = findCurSprite(); + + vsp->image = vcReadNextWord(); + int16 x = vcReadNextWord(); + int var = vcReadNextWord(); + + vsp->x += getScale(vsp->y, x); + _variableArray[var] = vsp->x; + + if (_scrollXMax) { + // TODO: Scroll check + } + + vsp->flags = 0x40; +} + +void SimonEngine::vc77_setScaleYOffs() { + VgaSprite *vsp = findCurSprite(); + + vsp->image = vcReadNextWord(); + int16 x = vcReadNextWord(); + int var = vcReadNextWord(); + + vsp->y += getScale(vsp->y, x); + _variableArray[var] = vsp->y; + vsp->flags = 0x40; +} + +void SimonEngine::vc78_computeXY() { + VgaSprite *vsp = findCurSprite(); + + uint a = (uint16)_variableArray[12]; + uint b = (uint16)_variableArray[13]; + + const uint16 *p = _pathFindArray[a - 1]; + p += b * 2; + + uint16 posx = readUint16Wrapper(p); + _variableArray[15] = posx; + vsp->x = posx; + + uint16 posy = readUint16Wrapper(p + 1); + _variableArray[16] = posy; + vsp->y = posy; + + vcSetBitTo(85, false); + if (vcGetBit(74) == true) { + //centreScroll(); + } +} + +void SimonEngine::vc79_computePosNum() { + uint a = (uint16)_variableArray[12]; + const uint16 *p = _pathFindArray[a - 1]; + uint pos = 0; + + int16 y = _variableArray[16]; + while(y > readUint16Wrapper(p + 1)) { + p += 2; + pos++; + } + + _variableArray[13] = pos; +} + +void SimonEngine::vc80_setOverlayImage() { + VgaSprite *vsp = findCurSprite(); + + vsp->image = vcReadVarOrWord(); + + vsp->x += vcReadNextWord(); + vsp->y += vcReadNextWord(); + vsp->flags = 0x10; + + _vgaSpriteChanged++; +} + +void SimonEngine::vc81_setRandom() { + uint var = vcReadNextWord(); + uint value = vcReadNextWord(); + writeVariable(var, _rnd.getRandomNumber(value - 1)); +} + +void SimonEngine::vc82_getPathValue() { + uint8 val; + + uint16 var = vcReadNextWord(); + + if (vcGetBit(82) == true) { + val = _pathValues1[_GPVCount1++]; + } else { + val = _pathValues[_GPVCount++]; + } + + writeVariable(var, val); +} + +void SimonEngine::vc83_playSoundLoop() { + // Start looping sound effect + int snd = vcReadNextWord(); + int vol = vcReadNextWord(); + int pan = vcReadNextWord(); + 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"); +} + +} // End of namespace Simon |