scummvm/engines/agos/vga_e2.cpp
2011-05-12 01:16:22 +02:00

408 lines
9.5 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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.
*
*/
// Video script opcodes for Simon1/Simon2
#include "agos/agos.h"
#include "agos/intern.h"
#include "common/system.h"
#include "graphics/surface.h"
#include "graphics/palette.h"
namespace AGOS {
void AGOSEngine_Elvira2::setupVideoOpcodes(VgaOpcodeProc *op) {
AGOSEngine::setupVideoOpcodes(op);
op[17] = &AGOSEngine::vc17_waitEnd;
op[19] = &AGOSEngine::vc19_loop;
op[22] = &AGOSEngine::vc22_setPalette;
op[28] = &AGOSEngine::vc28_playSFX;
op[32] = &AGOSEngine::vc32_saveScreen;
op[37] = &AGOSEngine::vc37_pokePalette;
op[45] = &AGOSEngine::vc45_setWindowPalette;
op[46] = &AGOSEngine::vc46_setPaletteSlot1;
op[47] = &AGOSEngine::vc47_setPaletteSlot2;
op[48] = &AGOSEngine::vc48_setPaletteSlot3;
op[53] = &AGOSEngine::vc53_dissolveIn;
op[54] = &AGOSEngine::vc54_dissolveOut;
op[57] = &AGOSEngine::vc57_blackPalette;
op[56] = &AGOSEngine::vc56_fullScreen;
op[58] = &AGOSEngine::vc58_checkCodeWheel;
op[59] = &AGOSEngine::vc59_ifEGA;
}
void AGOSEngine::vc43_ifBitSet() {
if (!getBitFlag(vcReadNextWord())) {
vcSkipNextInstruction();
}
}
void AGOSEngine::vc44_ifBitClear() {
if (getBitFlag(vcReadNextWord())) {
vcSkipNextInstruction();
}
}
void AGOSEngine::vc45_setWindowPalette() {
uint16 num = vcReadNextWord();
uint16 color = vcReadNextWord();
const uint16 *vlut = &_videoWindows[num * 4];
uint8 width = vlut[2] * 8;
uint8 height = vlut[3];
if (num == 4) {
byte *dst = (byte *)_window4BackScn->pixels;
for (uint8 h = 0; h < height; h++) {
for (uint8 w = 0; w < width; w++) {
uint16 val = READ_LE_UINT16(dst + w * 2);
val &= 0xF0F;
val |= color * 16;
WRITE_LE_UINT16(dst + w * 2, val);
}
dst += width * 2;
}
} else {
Graphics::Surface *screen = _system->lockScreen();
byte *dst = (byte *)screen->getBasePtr(vlut[0] * 16, vlut[1]);
if (getGameType() == GType_ELVIRA2 && num == 7) {
dst -= 8;
width += 4;
}
for (uint8 h = 0; h < height; h++) {
for (uint8 w = 0; w < width; w++) {
uint16 val = READ_LE_UINT16(dst + w * 2);
val &= 0xF0F;
val |= color * 16;
WRITE_LE_UINT16(dst + w * 2, val);
}
dst += screen->pitch;
}
_system->unlockScreen();
}
}
void AGOSEngine::setPaletteSlot(uint16 srcOffs, uint8 dstOffs) {
byte *offs, *palptr, *src;
uint16 num;
palptr = _displayPalette + dstOffs * 3 * 16;
offs = _curVgaFile1 + READ_BE_UINT16(_curVgaFile1 + 6);
src = offs + srcOffs * 32;
num = 16;
do {
uint16 color = READ_BE_UINT16(src);
palptr[0] = ((color & 0xf00) >> 8) * 32;
palptr[1] = ((color & 0x0f0) >> 4) * 32;
palptr[2] = ((color & 0x00f) >> 0) * 32;
palptr += 3;
src += 2;
} while (--num);
_paletteFlag = 2;
}
void AGOSEngine::vc46_setPaletteSlot1() {
uint16 srcOffs = vcReadNextWord();
setPaletteSlot(srcOffs, 1);
}
void AGOSEngine::vc47_setPaletteSlot2() {
uint16 srcOffs = vcReadNextWord();
setPaletteSlot(srcOffs, 2);
}
void AGOSEngine::vc48_setPaletteSlot3() {
uint16 srcOffs = vcReadNextWord();
setPaletteSlot(srcOffs, 3);
}
void AGOSEngine::vc49_setBit() {
uint16 bit = vcReadNextWord();
if (getGameType() == GType_FF && bit == 82) {
_variableArrayPtr = _variableArray2;
}
setBitFlag(bit, true);
}
void AGOSEngine::vc50_clearBit() {
uint16 bit = vcReadNextWord();
if (getGameType() == GType_FF && bit == 82) {
_variableArrayPtr = _variableArray;
}
setBitFlag(bit, false);
}
void AGOSEngine::vc51_enableBox() {
enableBox(vcReadNextWord());
}
void AGOSEngine::vc52_playSound() {
bool ambient = false;
uint16 sound = vcReadNextWord();
if (sound >= 0x8000) {
ambient = true;
sound = -sound;
}
if (getGameType() == GType_FF || getGameType() == GType_PP) {
int16 pan = vcReadNextWord();
int16 vol = vcReadNextWord();
if (ambient)
loadSound(sound, pan, vol, Sound::TYPE_AMBIENT);
else
loadSound(sound, pan, vol, Sound::TYPE_SFX);
} 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);
} else if (getGameType() == GType_WW) {
// TODO: Sound effects in PC version only
} else {
loadSound(sound, 0, 0);
}
}
void AGOSEngine::vc53_dissolveIn() {
uint16 num = vcReadNextWord();
uint16 speed = vcReadNextWord() + 1;
byte *src, *dst, *srcOffs, *srcOffs2, *dstOffs, *dstOffs2;
int16 xoffs, yoffs;
uint8 color = 0;
// Only uses Video Window 4
num = 4;
uint16 dissolveX = _videoWindows[num * 4 + 2] * 8;
uint16 dissolveY = (_videoWindows[num * 4 + 3] + 1) / 2;
uint16 dissolveCheck = dissolveY * dissolveX * 4;
uint16 dissolveDelay = dissolveCheck * 2 / speed;
uint16 dissolveCount = dissolveCheck * 2 / speed;
int16 x = _videoWindows[num * 4 + 0] * 16;
int16 y = _videoWindows[num * 4 + 1];
uint16 count = dissolveCheck * 2;
while (count--) {
Graphics::Surface *screen = _system->lockScreen();
byte *dstPtr = (byte *)screen->pixels + x + y * screen->pitch;
yoffs = _rnd.getRandomNumber(dissolveY);
dst = dstPtr + yoffs * screen->pitch;
src = (byte *)_window4BackScn->pixels + yoffs * _window4BackScn->pitch;
xoffs = _rnd.getRandomNumber(dissolveX);
dst += xoffs;
src += xoffs;
*dst &= color;
*dst |= *src & 0xF;
dstOffs = dst;
srcOffs = src;
xoffs = dissolveX * 2 - 1 - (xoffs * 2);
dst += xoffs;
src += xoffs;
*dst &= color;
*dst |= *src & 0xF;
srcOffs2 = src;
dstOffs2 = dst;
yoffs = (dissolveY - 1) * 2 - (yoffs * 2);
src = srcOffs + yoffs * _window4BackScn->pitch;
dst = dstOffs + yoffs * screen->pitch;
color = 0xF0;
*dst &= color;
*dst |= *src & 0xF;
dst = dstOffs2 + yoffs * screen->pitch;
src = srcOffs2 + yoffs * _window4BackScn->pitch;
*dst &= color;
*dst |= *src & 0xF;
_system->unlockScreen();
dissolveCount--;
if (!dissolveCount) {
if (count >= dissolveCheck)
dissolveDelay++;
dissolveCount = dissolveDelay;
delay(1);
}
}
}
void AGOSEngine::vc54_dissolveOut() {
uint16 num = vcReadNextWord();
uint16 color = vcReadNextWord();
uint16 speed = vcReadNextWord() + 1;
byte *dst, *dstOffs;
int16 xoffs, yoffs;
uint16 dissolveX = _videoWindows[num * 4 + 2] * 8;
uint16 dissolveY = (_videoWindows[num * 4 + 3] + 1) / 2;
uint16 dissolveCheck = dissolveY * dissolveX * 4;
uint16 dissolveDelay = dissolveCheck * 2 / speed;
uint16 dissolveCount = dissolveCheck * 2 / speed;
int16 x = _videoWindows[num * 4 + 0] * 16;
int16 y = _videoWindows[num * 4 + 1];
uint16 count = dissolveCheck * 2;
while (count--) {
Graphics::Surface *screen = _system->lockScreen();
byte *dstPtr = (byte *)screen->pixels + x + y * screen->pitch;
color |= dstPtr[0] & 0xF0;
yoffs = _rnd.getRandomNumber(dissolveY);
xoffs = _rnd.getRandomNumber(dissolveX);
dst = dstPtr + xoffs + yoffs * screen->pitch;
*dst = color;
dstOffs = dst;
xoffs = dissolveX * 2 - 1 - (xoffs * 2);
dst += xoffs;
*dst = color;
yoffs = (dissolveY - 1) * 2 - (yoffs * 2);
dst = dstOffs + yoffs * screen->pitch;
*dst = color;
dst += xoffs;
*dst = color;
_system->unlockScreen();
dissolveCount--;
if (!dissolveCount) {
if (count >= dissolveCheck)
dissolveDelay++;
dissolveCount = dissolveDelay;
delay(1);
}
}
}
void AGOSEngine::vc55_moveBox() {
HitArea *ha = _hitAreas;
uint count = ARRAYSIZE(_hitAreas);
uint16 id = vcReadNextWord();
int16 x = vcReadNextWord();
int16 y = vcReadNextWord();
for (;;) {
if (ha->id == id) {
ha->x += x;
ha->y += y;
break;
}
ha++;
if (!--count)
break;
}
_needHitAreaRecalc++;
}
void AGOSEngine::fullFade() {
uint8 *srcPal, *dstPal;
int c, p;
for (c = 64; c != 0; c --) {
srcPal = _curVgaFile2 + 32;
dstPal = _currentPalette;
for (p = 768; p !=0; p -= 3) {
uint8 r = srcPal[0] * 4;
if (dstPal[0] != r)
dstPal[0] += 4;
uint8 g = srcPal[1] * 4;
if (dstPal[1] != g)
dstPal[1] += 4;
uint8 b = srcPal[2] * 4;
if (dstPal[2] != b)
dstPal[2] += 4;
srcPal += 3;
dstPal += 3;
}
_system->getPaletteManager()->setPalette(_currentPalette, 0, 256);
delay(5);
}
}
void AGOSEngine::vc56_fullScreen() {
Graphics::Surface *screen = _system->lockScreen();
byte *dst = (byte *)screen->pixels;
byte *src = _curVgaFile2 + 800;
for (int i = 0; i < _screenHeight; i++) {
memcpy(dst, src, _screenWidth);
src += 320;
dst += screen->pitch;
}
_system->unlockScreen();
fullFade();
}
void AGOSEngine::vc57_blackPalette() {
memset(_currentPalette, 0, sizeof(_currentPalette));
_system->getPaletteManager()->setPalette(_currentPalette, 0, 256);
}
void AGOSEngine::vc58_checkCodeWheel() {
_variableArray[0] = 0;
}
void AGOSEngine::vc59_ifEGA() {
// Skip if not EGA
vcSkipNextInstruction();
}
} // End of namespace AGOS