/* 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. * * $URL$ * $Id$ * */ #include "common/system.h" #include "graphics/surface.h" #include "agos/agos.h" #include "agos/intern.h" namespace AGOS { byte *AGOSEngine::getBackBuf() { return (byte *)_backBuf->pixels; } byte *AGOSEngine::getBackGround() { return (byte *)_backGroundBuf->pixels; } byte *AGOSEngine::getScaleBuf() { return (byte *)_scaleBuf->pixels; } void AGOSEngine_Feeble::animateSpritesByY() { VgaSprite *vsp; VgaPointersEntry *vpe; int16 spriteTable[180][2]; byte *src; int height, slot, y; uint i, numSprites = 0; vsp = _vgaSprites; while (vsp->id) { if (vsp->flags & kDFScaled) { y = vsp->y; } else if (vsp->flags & kDFMasked) { vpe = &_vgaBufferPointers[vsp->zoneNum]; src = vpe->vgaFile2 + vsp->image * 8; height = READ_LE_UINT16(src + 4) & 0x7FFF; y = vsp->y + height; } else { y = vsp->priority; } spriteTable[numSprites][0] = y; spriteTable[numSprites][1] = numSprites; numSprites++; vsp++; } while (1) { y = spriteTable[0][0]; slot = spriteTable[0][1]; for (i = 0; i < numSprites; i++) { if (y >= spriteTable[i][0]) { y = spriteTable[i][0]; slot = spriteTable[i][1]; } } if (y == 9999) break; for (i = 0; i < numSprites; i++) { if (slot == spriteTable[i][1]) { spriteTable[i][0] = 9999; break; } } vsp = &_vgaSprites[slot]; vsp->windowNum &= ~0x8000; vpe = &_vgaBufferPointers[vsp->zoneNum]; _curVgaFile1 = vpe->vgaFile1; _curVgaFile2 = vpe->vgaFile2; _curSfxFile = vpe->sfxFile; _windowNum = vsp->windowNum; _vgaCurSpriteId = vsp->id; _vgaCurSpritePriority = vsp->priority; drawImage_init(vsp->image, vsp->palette, vsp->x, vsp->y, vsp->flags); } _displayScreen = true; } void AGOSEngine_Feeble::animateSprites() { VgaSprite *vsp; VgaPointersEntry *vpe; if (_paletteFlag == 2) _paletteFlag = 1; if (_scrollCount) { scrollEvent(); } if (getBitFlag(84)) { animateSpritesByY(); return; } vsp = _vgaSprites; while (vsp->id) { vsp->windowNum &= ~0x8000; vpe = &_vgaBufferPointers[vsp->zoneNum]; _curVgaFile1 = vpe->vgaFile1; _curVgaFile2 = vpe->vgaFile2; _curSfxFile = vpe->sfxFile; _windowNum = vsp->windowNum; _vgaCurSpriteId = vsp->id; _vgaCurSpritePriority = vsp->priority; drawImage_init(vsp->image, vsp->palette, vsp->x, vsp->y, vsp->flags); vsp++; } _displayScreen = true; } void AGOSEngine::animateSprites() { VgaSprite *vsp; VgaPointersEntry *vpe; if (_copyScnFlag) { _copyScnFlag--; _vgaSpriteChanged++; } if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2) { const uint8 var = (getGameType() == GType_ELVIRA1) ? 293 : 71; if (_wallOn && !_variableArray[var]) { _wallOn--; VC10_state state; state.srcPtr = getBackGround() + 3 * _backGroundBuf->pitch + 3 * 16; state.height = state.draw_height = 127; state.width = state.draw_width = 14; state.y = 0; state.x = 0; state.palette = 0; state.paletteMod = 0; state.flags = kDFNonTrans; _windowNum = 4; _backFlag = 1; drawImage(&state); _backFlag = 0; _vgaSpriteChanged++; } } if (!_scrollFlag && !_vgaSpriteChanged) { return; } _vgaSpriteChanged = 0; if (_paletteFlag == 2) _paletteFlag = 1; if (getGameType() == GType_SIMON2 && _scrollFlag) { scrollScreen(); } if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { dirtyClips(); } restoreBackGround(); vsp = _vgaSprites; for (; vsp->id !=0; vsp++) { if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) && !(vsp->windowNum & 0x8000)) { continue; } vsp->windowNum &= ~0x8000; vpe = &_vgaBufferPointers[vsp->zoneNum]; _curVgaFile1 = vpe->vgaFile1; _curVgaFile2 = vpe->vgaFile2; _curSfxFile = vpe->sfxFile; _windowNum = vsp->windowNum; _vgaCurSpriteId = vsp->id; saveBackGround(vsp); drawImage_init(vsp->image, vsp->palette, vsp->x, vsp->y, vsp->flags); } if (getGameType() == GType_ELVIRA1 && _variableArray[293]) { // Used by the Fire Wall and Ice Wall spells debug(0, "Using special wall"); uint8 color, h, len; byte *dst = (byte *)_window4BackScn->pixels; color = (_variableArray[293] & 1) ? 13 : 15; _wallOn = 2; h = 127; while (h) { len = 112; while (len--) { *dst++ = color; dst++; } h--; if (h == 0) break; len = 112; while (len--) { dst++; *dst++ = color; } h--; } _window4Flag = 1; setMoveRect(0, 0, 224, 127); } else if (getGameType() == GType_ELVIRA2 && _variableArray[71] & 2) { // Used by the Unholy Barrier spell uint8 color, h, len; byte *dst = (byte *)_window4BackScn->pixels; color = 1; _wallOn = 2; h = 43; while (h) { len = 56; while (len--) { *dst++ = color; dst += 3; } h--; if (h == 0) break; dst += 448; len = 56; while (len--) { dst += 2; *dst++ = color; dst += 1; } dst += 448; h--; } _window4Flag = 1; setMoveRect(0, 0, 224, 127); } if (_window6Flag == 1) _window6Flag++; if (_window4Flag == 1) _window4Flag++; _displayScreen = true; } void AGOSEngine::dirtyClips() { int16 x, y, w, h; restart: _newDirtyClip = 0; VgaSprite *vsp = _vgaSprites; while (vsp->id != 0) { if (vsp->windowNum & 0x8000) { x = vsp->x; y = vsp->y; w = 1; h = 1; if (vsp->image != 0) { VgaPointersEntry *vpe = &_vgaBufferPointers[vsp->zoneNum]; const byte *ptr = vpe->vgaFile2 + vsp->image * 8; w = READ_BE_UINT16(ptr + 6) / 8; h = ptr[5]; } dirtyClipCheck(x, y, w, h); } vsp++; } AnimTable *animTable = _screenAnim1; while (animTable->srcPtr != 0) { if (animTable->windowNum & 0x8000) { x = animTable->x + _scrollX; y = animTable->y; w = animTable->width * 2; h = animTable->height; dirtyClipCheck(x, y, w, h); } animTable++; } if (_newDirtyClip != 0) goto restart; } void AGOSEngine::dirtyClipCheck(int16 x, int16 y, int16 w, int16 h) { int16 width, height, tmp; VgaSprite *vsp = _vgaSprites; for (; vsp->id != 0; vsp++) { if (vsp->windowNum & 0x8000) continue; if (vsp->image == 0) continue; VgaPointersEntry *vpe = &_vgaBufferPointers[vsp->zoneNum]; const byte *ptr = vpe->vgaFile2 + vsp->image * 8; width = READ_BE_UINT16(ptr + 6) / 8; height = ptr[5]; tmp = vsp->x; if (tmp >= x) { tmp -= w; if (tmp >= x) continue; } else { tmp += width; if (tmp < x) continue; } tmp = vsp->y; if (tmp >= y) { tmp -= h; if (tmp >= y) continue; } else { tmp += height; if (tmp < y) continue; } vsp->windowNum |= 0x8000; _newDirtyClip = 1; } AnimTable *animTable = _screenAnim1; for (; animTable->srcPtr != 0; animTable++) { if (animTable->windowNum & 0x8000) continue; width = animTable->width * 2; height = animTable->height; tmp = animTable->x + _scrollX; if (tmp >= x) { tmp -= w; if (tmp >= x) continue; } else { tmp += width; if (tmp < x) continue; } tmp = animTable->y; if (tmp >= y) { tmp -= h; if (tmp >= y) continue; } else { tmp += height; if (tmp < y) continue; } animTable->windowNum |= 0x8000; _newDirtyClip = 1; } } void AGOSEngine::restoreBackGround() { AnimTable *animTable; uint images = 0; animTable = _screenAnim1; while (animTable->srcPtr) { animTable++; images++; } while (images--) { animTable--; if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) && !(animTable->windowNum & 0x8000)) { continue; } _windowNum = animTable->windowNum & ~0x8000; VC10_state state; state.srcPtr = animTable->srcPtr; state.height = state.draw_height = animTable->height; state.width = state.draw_width = animTable->width; state.y = animTable->y; state.x = animTable->x; state.palette = 0; state.paletteMod = 0; state.flags = kDFNonTrans; _backFlag = 1; drawImage(&state); if (getGameType() != GType_SIMON1 && getGameType() != GType_SIMON2) { animTable->srcPtr = 0; } } _backFlag = 0; if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { AnimTable *animTableTmp; animTable = animTableTmp = _screenAnim1; while (animTable->srcPtr) { if (!(animTable->windowNum & 0x8000)) { memmove(animTableTmp, animTable, sizeof(AnimTable)); animTableTmp++; } animTable++; } animTableTmp->srcPtr = 0; } } void AGOSEngine::saveBackGround(VgaSprite *vsp) { if (getGameType() == GType_ELVIRA1 && getPlatform() == Common::kPlatformAtariST && (getFeatures() & GF_DEMO)) { return; } if ((vsp->flags & kDFSkipStoreBG) || !vsp->image) return; AnimTable *animTable = _screenAnim1; while (animTable->srcPtr) animTable++; const byte *ptr = _curVgaFile2 + vsp->image * 8; int16 x = vsp->x - _scrollX; int16 y = vsp->y - _scrollY; if (_window3Flag == 1) { animTable->srcPtr = (const byte *)_window4BackScn->pixels; } else { int xoffs = (_videoWindows[vsp->windowNum * 4 + 0] * 2 + x) * 8; int yoffs = (_videoWindows[vsp->windowNum * 4 + 1] + y); animTable->srcPtr = getBackGround() + yoffs * _backGroundBuf->pitch + xoffs; } animTable->x = x; animTable->y = y; animTable->width = READ_BE_UINT16(ptr + 6) / 16; if (vsp->flags & 0x40) { animTable->width++; } animTable->height = ptr[5]; animTable->windowNum = vsp->windowNum; animTable->id = vsp->id; animTable->zoneNum = vsp->zoneNum; animTable++; animTable->srcPtr = 0; } void AGOSEngine::displayBoxStars() { HitArea *ha, *dha; uint count; uint y_, x_; byte *dst; uint b, color; o_haltAnimation(); if (getGameType() == GType_SIMON2) color = 236; else color = 225; uint curHeight = (getGameType() == GType_SIMON2) ? _boxStarHeight : 134; for (int i = 0; i < 5; i++) { ha = _hitAreas; count = ARRAYSIZE(_hitAreas); Graphics::Surface *screen = _system->lockScreen(); do { if (ha->id != 0 && ha->flags & kBFBoxInUse && !(ha->flags & kBFBoxDead)) { dha = _hitAreas; if (ha->flags & kBFTextBox) { while (dha != ha && dha->flags != ha->flags) ++dha; if (dha != ha && dha->flags == ha->flags) continue; } else { dha = _hitAreas; while (dha != ha && dha->itemPtr != ha->itemPtr) ++dha; if (dha != ha && dha->itemPtr == ha->itemPtr) continue; } if (ha->y >= curHeight) continue; y_ = (ha->height / 2) - 4 + ha->y; x_ = (ha->width / 2) - 4 + ha->x - (_scrollX * 8); if (x_ >= 311) continue; dst = (byte *)screen->pixels; dst += (((screen->pitch / 4) * y_) * 4) + x_; b = screen->pitch; dst[4] = color; dst[b+1] = color; dst[b+4] = color; dst[b+7] = color; b += screen->pitch; dst[b+2] = color; dst[b+4] = color; dst[b+6] = color; b += screen->pitch; dst[b+3] = color; dst[b+5] = color; b += screen->pitch; dst[b] = color; dst[b+1] = color; dst[b+2] = color; dst[b+6] = color; dst[b+7] = color; dst[b+8] = color; b += screen->pitch; dst[b+3] = color; dst[b+5] = color; b += screen->pitch; dst[b+2] = color; dst[b+4] = color; dst[b+6] = color; b += screen->pitch; dst[b+1] = color; dst[b+4] = color; dst[b+7] = color; b += screen->pitch; dst[b+4] = color; } } while (ha++, --count); _system->unlockScreen(); delay(100); setMoveRect(0, 0, 320, curHeight); _window4Flag = 2; displayScreen(); delay(100); } o_restartAnimation(); } void AGOSEngine::scrollScreen() { byte *dst; const byte *src; uint x, y; dst = getBackGround(); if (_scrollXMax == 0) { uint screenSize = 8 * _screenWidth; if (_scrollFlag < 0) { memmove(dst + screenSize, dst, _scrollWidth * _screenHeight - screenSize); } else { memmove(dst, dst + screenSize, _scrollWidth * _screenHeight - screenSize); } y = _scrollY - 8; if (_scrollFlag > 0) { dst += _screenHeight * _screenWidth - screenSize; y += 488; } src = _scrollImage + y / 2; decodeRow(dst, src + readUint32Wrapper(src), _scrollWidth, _backGroundBuf->pitch); _scrollY += _scrollFlag; vcWriteVar(250, _scrollY); fillBackFromBackGround(_screenHeight, _scrollWidth); } else { if (_scrollFlag < 0) { memmove(dst + 8, dst, _screenWidth * _scrollHeight - 8); } else { memmove(dst, dst + 8, _screenWidth * _scrollHeight - 8); } x = _scrollX; x -= (getGameType() == GType_FF) ? 8 : 1; if (_scrollFlag > 0) { dst += _screenWidth - 8; x += (getGameType() == GType_FF) ? 648 : 41; } if (getGameType() == GType_FF) src = _scrollImage + x / 2; else src = _scrollImage + x * 4; decodeColumn(dst, src + readUint32Wrapper(src), _scrollHeight, _backGroundBuf->pitch); _scrollX += _scrollFlag; vcWriteVar(251, _scrollX); if (getGameType() == GType_SIMON2) { src = getBackGround(); dst = (byte *)_window4BackScn->pixels; for (int i = 0; i < _scrollHeight; i++) { memcpy(dst, src, _screenWidth); src += _backGroundBuf->pitch; dst += _window4BackScn->pitch; } } else { fillBackFromBackGround(_scrollHeight, _screenWidth); } setMoveRect(0, 0, 320, _scrollHeight); _window4Flag = 1; } _scrollFlag = 0; if (getGameType() == GType_SIMON2) { AnimTable *animTable = _screenAnim1; while (animTable->srcPtr) { animTable->srcPtr = 0; animTable++; } VgaSprite *vsp = _vgaSprites; while (vsp->id) { vsp->windowNum |= 0x8000; vsp++; } } } void AGOSEngine::clearSurfaces() { _system->fillScreen(0); if (_backBuf) { memset(getBackBuf(), 0, _backBuf->h * _backBuf->pitch); } } void AGOSEngine::fillBackFromBackGround(uint16 height, uint16 width) { byte *src = getBackGround(); byte *dst = getBackBuf(); for (int i = 0; i < height; i++) { memcpy(dst, src, width); src += _backGroundBuf->pitch; dst += _backBuf->pitch; } } void AGOSEngine::fillBackFromFront() { Graphics::Surface *screen = _system->lockScreen(); byte *src = (byte *)screen->pixels; byte *dst = getBackBuf(); for (int i = 0; i < _screenHeight; i++) { memcpy(dst, src, _screenWidth); src += screen->pitch; dst += _backBuf->pitch; } _system->unlockScreen(); } void AGOSEngine::fillBackGroundFromBack() { byte *src = getBackBuf(); byte *dst = getBackGround(); for (int i = 0; i < _screenHeight; i++) { memcpy(dst, src, _screenWidth); src += _backBuf->pitch; dst += _backGroundBuf->pitch; } } void AGOSEngine::fillBackGroundFromFront() { Graphics::Surface *screen = _system->lockScreen(); byte *src = (byte *)screen->pixels; byte *dst = getBackGround(); for (int i = 0; i < _screenHeight; i++) { memcpy(dst, src, _screenWidth); src += screen->pitch; dst += _backGroundBuf->pitch; } _system->unlockScreen(); } void AGOSEngine::setMoveRect(uint16 x, uint16 y, uint16 width, uint16 height) { if (x < _moveXMin) _moveXMin = x; if (y < _moveYMin) _moveYMin = y; if (width > _moveXMax) _moveXMax = width; if (height > _moveYMax) _moveYMax = height; } void AGOSEngine::displayScreen() { if (_fastFadeInFlag == 0 && _paletteFlag == 1) { _paletteFlag = 0; if (memcmp(_displayPalette, _currentPalette, 1024)) { memcpy(_currentPalette, _displayPalette, 1024); _system->setPalette(_displayPalette, 0, 256); } } Graphics::Surface *screen = _system->lockScreen(); if (getGameType() == GType_PP || getGameType() == GType_FF) { byte *src = getBackBuf(); byte *dst = (byte *)screen->pixels; for (int i = 0; i < _screenHeight; i++) { memcpy(dst, src, _screenWidth); src += _backBuf->pitch; dst += screen->pitch; } if (getGameId() != GID_DIMP) fillBackFromBackGround(_screenHeight, _screenWidth); } else { if (_window4Flag == 2) { _window4Flag = 0; uint16 srcWidth, width, height; byte *dst = (byte *)screen->pixels; const byte *src = (const byte *)_window4BackScn->pixels; if (_window3Flag == 1) { src = getBackGround(); } dst += (_moveYMin + _videoWindows[17]) * screen->pitch; dst += (_videoWindows[16] * 16) + _moveXMin; src += (_videoWindows[18] * 16 * _moveYMin); src += _moveXMin; srcWidth = _videoWindows[18] * 16; width = _moveXMax - _moveXMin; height = _moveYMax - _moveYMin; for (; height > 0; height--) { memcpy(dst, src, width); dst += screen->pitch; src += srcWidth; } _moveXMin = 0xFFFF; _moveYMin = 0xFFFF; _moveXMax = 0; _moveYMax = 0; } if (_window6Flag == 2) { _window6Flag = 0; byte *src = (byte *)_window6BackScn->pixels; byte *dst = (byte *)screen->pixels + 51 * screen->pitch; for (int i = 0; i < 80; i++) { memcpy(dst, src, _window6BackScn->w); dst += screen->pitch; src += _window6BackScn->pitch; } } } _system->unlockScreen(); if (getGameType() == GType_FF && _scrollFlag) { scrollScreen(); } if (_fastFadeInFlag) { fastFadeIn(); } } void AGOSEngine::fastFadeIn() { if (_fastFadeInFlag & 0x8000) { slowFadeIn(); } else { _paletteFlag = false; memcpy(_currentPalette, _displayPalette, 1024); _system->setPalette(_displayPalette, 0, _fastFadeInFlag); _fastFadeInFlag = 0; } } void AGOSEngine::slowFadeIn() { uint8 *src, *dst; int c, p; _fastFadeInFlag &= ~0x8000; _paletteFlag = false; memset(_videoBuf1, 0, 1024); memcpy(_currentPalette, _displayPalette, 1024); memcpy(_videoBuf1 + 1024, _displayPalette, 1024); for (c = 255; c >= 0; c -= 4) { src = _videoBuf1 + 1024; dst = _videoBuf1; for (p = _fastFadeInFlag; p !=0 ; p -= 3) { if (src[0] >= c) dst[0] += 4; if (src[1] >= c) dst[1] += 4; if (src[2] >= c) dst[2] += 4; src += 4; dst += 4; } _system->setPalette(_videoBuf1, 0, _fastFadeCount); delay(5); } _fastFadeInFlag = 0; } } // End of namespace AGOS