mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-25 19:25:20 +00:00
400 lines
10 KiB
C++
400 lines
10 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.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* This code is based on the original source code of Lord Avalot d'Argent version 1.3.
|
|
* Copyright (c) 1994-1995 Mike: Mark and Thomas Thurman.
|
|
*/
|
|
|
|
#include "avalanche/avalanche.h"
|
|
#include "avalanche/ghostroom.h"
|
|
|
|
#include "common/random.h"
|
|
#include "common/system.h"
|
|
|
|
namespace Avalanche {
|
|
|
|
const int8 GhostRoom::kAdjustment[5] = { 7, 0, 7, 7, 7 };
|
|
const byte GhostRoom::kWaveOrder[5] = { 4, 0, 1, 2, 3 };
|
|
const byte GhostRoom::kGlerkFade[26] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 0 };
|
|
const byte GhostRoom::kGreldetFade[18] = { 0, 1, 2, 3, 4, 5, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0 };
|
|
|
|
GhostRoom::GhostRoom(AvalancheEngine *vm) {
|
|
_vm = vm;
|
|
|
|
_glerkStage = 0;
|
|
_batX = 0;
|
|
_batY = 0;
|
|
_batCount = 0;
|
|
_aarghCount = 0;
|
|
_greldetX = _greldetY = 0;
|
|
_greldetCount = 0;
|
|
_redGreldet = false;
|
|
_wasLoaded = false;
|
|
|
|
_ghost = nullptr;
|
|
_glerk = nullptr;
|
|
}
|
|
|
|
GhostRoom::~GhostRoom() {
|
|
for (int i = 0; i < 2; i++)
|
|
_eyes[i].free();
|
|
|
|
_exclamation.free();
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
_bat[i].free();
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
_aargh[i].free();
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
_greenEyes[i].free();
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int j = 0; j < 6; j++)
|
|
_greldet[j][i].free();
|
|
}
|
|
|
|
if (_wasLoaded) {
|
|
for (int i = 0; i < 5; i++) {
|
|
for (int j = 0; j < 2; j++) {
|
|
for (int y = 0; y < 66; y++) {
|
|
delete[] _ghost[i][j][y];
|
|
}
|
|
delete[] _ghost[i][j];
|
|
}
|
|
delete[] _ghost[i];
|
|
}
|
|
delete[] _ghost;
|
|
|
|
for (int i = 0; i < 6; i++) {
|
|
for (int j = 0; j < 4; j++) {
|
|
for (int y = 0; y < 35; y++) {
|
|
delete[] _glerk[i][j][y];
|
|
}
|
|
delete[] _glerk[i][j];
|
|
}
|
|
delete[] _glerk[i];
|
|
}
|
|
delete[] _glerk;
|
|
}
|
|
}
|
|
|
|
void GhostRoom::wait(uint16 howLong) {
|
|
for (int i = 0; i < howLong; i++) {
|
|
Common::Event event;
|
|
_vm->getEvent(event);
|
|
if (event.type == Common::EVENT_KEYDOWN)
|
|
_vm->_sound->playNote(6177, 1);
|
|
_vm->_system->delayMillis(1);
|
|
}
|
|
}
|
|
|
|
void GhostRoom::doBat() {
|
|
_batCount++;
|
|
|
|
int8 dx = 0;
|
|
int8 iy = 0;
|
|
byte batImage = 0;
|
|
if ((_batCount % 2) == 1) {
|
|
if ((1 <= _batCount) && (_batCount <= 90)) {
|
|
dx = 2;
|
|
iy = 1;
|
|
batImage = 0;
|
|
} else if ((91 <= _batCount) && (_batCount <= 240)) {
|
|
dx = 1;
|
|
iy = 1;
|
|
batImage = 1;
|
|
} else if((241 <= _batCount) && (_batCount <= 260)) {
|
|
dx = 1;
|
|
iy = 4;
|
|
batImage = 2;
|
|
}
|
|
|
|
if ((_batCount == 91) || (_batCount == 241)) // When the bat changes, blank out the old one.
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(_batX + _bat[batImage].w, _batY, _batX + _bat[batImage - 1].w, _batY + _bat[batImage - 1].h), kColorBlack);
|
|
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(_batX, _batY, _batX + _bat[batImage].w, _batY + iy), kColorBlack);
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(_batX + _bat[batImage].w - dx, _batY, _batX + _bat[batImage].w, _batY + _bat[batImage].h), kColorBlack);
|
|
|
|
_batX -= dx;
|
|
_batY++;
|
|
_vm->_graphics->ghostDrawPicture(_bat[batImage], _batX, _batY);
|
|
}
|
|
}
|
|
|
|
void GhostRoom::bigGreenEyes(byte how) {
|
|
_vm->_graphics->ghostDrawPicture(_greenEyes[how], 330, 103);
|
|
_vm->_graphics->ghostDrawPicture(_greenEyes[how], 376, 103);
|
|
_vm->_graphics->refreshScreen();
|
|
}
|
|
|
|
ChunkBlock GhostRoom::readChunkBlock(Common::File &file) {
|
|
ChunkBlock cb;
|
|
cb._flavour = (Flavour)file.readByte();
|
|
cb._x = file.readSint16LE();
|
|
cb._y = file.readSint16LE();
|
|
cb._width = file.readSint16LE();
|
|
cb._height = file.readSint16LE();
|
|
cb._size = file.readSint32LE();
|
|
return cb;
|
|
}
|
|
|
|
void GhostRoom::loadPictures() {
|
|
Common::File file;
|
|
|
|
if (!file.open("spooky.avd"))
|
|
error("AVALANCHE: GhostRoom: File not found: spooky.avd");
|
|
|
|
file.seek(44);
|
|
|
|
// Initializing ghost's array.
|
|
_ghost = new byte***[5];
|
|
for (int i = 0; i < 5; i++) {
|
|
_ghost[i] = new byte**[2];
|
|
for (int j = 0; j < 2; j++) {
|
|
_ghost[i][j] = new byte*[66];
|
|
for (int y = 0; y < 66; y++) {
|
|
_ghost[i][j][y] = new byte[26];
|
|
for (int x = 0; x < 26; x++)
|
|
_ghost[i][j][y][x] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read in the pictures of the ghost.
|
|
for (int i = 0; i < 5; i++) {
|
|
ChunkBlock cb = readChunkBlock(file);
|
|
for (int j = 0; j < 2; j++) {
|
|
for (int y = 0; y <= cb._height; y++)
|
|
file.read(_ghost[i][j][y], cb._width / 8);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
_eyes[i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);
|
|
|
|
_exclamation = _vm->_graphics->ghostLoadPicture(file, dummyCoord);
|
|
|
|
// Actually this function not just loads, but also draws the images, but they are part of the background
|
|
// and they are need to be drawn only once.
|
|
_vm->_graphics->ghostDrawBackgroundItems(file);
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
_bat[i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);
|
|
|
|
// Initializing glerk's array.
|
|
_glerk = new byte***[6];
|
|
for (int i = 0; i < 6; i++) {
|
|
_glerk[i] = new byte**[4];
|
|
for (int j = 0; j < 4; j++) {
|
|
_glerk[i][j] = new byte*[35];
|
|
for (int y = 0; y < 35; y++) {
|
|
_glerk[i][j][y] = new byte[9];
|
|
for (int x = 0; x < 9; x++)
|
|
_glerk[i][j][y][x] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read in the pictures of the "glerk".
|
|
for (int i = 0; i < 6; i++) {
|
|
ChunkBlock cb = readChunkBlock(file);
|
|
for (int j = 0; j < 4; j++) {
|
|
for (int y = 0; y <= cb._height; y++)
|
|
file.read(_glerk[i][j][y], cb._width / 8);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
_aargh[i] = _vm->_graphics->ghostLoadPicture(file, _aarghWhere[i]);
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
_greenEyes[i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int j = 0; j < 6; j++)
|
|
_greldet[j][i] = _vm->_graphics->ghostLoadPicture(file, dummyCoord);
|
|
}
|
|
|
|
file.close();
|
|
}
|
|
|
|
void GhostRoom::run() {
|
|
CursorMan.showMouse(false);
|
|
_vm->_graphics->saveScreen();
|
|
_vm->fadeOut();
|
|
_vm->_graphics->blackOutScreen();
|
|
_vm->fadeIn();
|
|
|
|
// Only load the pictures if it's our first time walking into the room.
|
|
// After that we simply use the already loaded images.
|
|
if (!_wasLoaded) {
|
|
loadPictures();
|
|
_wasLoaded = true;
|
|
}
|
|
|
|
// Avvy walks over:
|
|
_glerkStage = 0;
|
|
_batX = 277;
|
|
_batY = 40;
|
|
_batCount = 0;
|
|
|
|
for (int x = 500; x >= 217; x--) {
|
|
// The floating eyeballs:
|
|
int xBound = x % 30;
|
|
if ((22 <= xBound) && (xBound <= 27)) {
|
|
if (xBound == 27)
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(x, 135, x + 17, 137), kColorBlack);
|
|
_vm->_graphics->ghostDrawPicture(_eyes[0], x, 136);
|
|
_vm->_graphics->drawDot(x + 16, 137, kColorBlack);
|
|
} else {
|
|
if (xBound == 21)
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(x, 137, x + 18, 139), kColorBlack);
|
|
_vm->_graphics->ghostDrawPicture(_eyes[0], x, 135);
|
|
_vm->_graphics->drawDot(x + 16, 136, kColorBlack); // Eyes would leave a trail 1 pixel high behind them.
|
|
}
|
|
|
|
// Plot the Glerk:
|
|
if ((x % 10) == 0) {
|
|
if (_glerkStage > 25)
|
|
break;
|
|
|
|
_vm->_graphics->ghostDrawMonster(_glerk[kGlerkFade[_glerkStage]], 456, 14, kMonsterTypeGlerk);
|
|
_glerkStage++;
|
|
}
|
|
|
|
doBat();
|
|
|
|
_vm->_graphics->refreshScreen();
|
|
|
|
wait(15);
|
|
}
|
|
|
|
// Blank out the Glerk's space.
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(456, 14, 531, 51), kColorBlack);
|
|
_vm->_graphics->refreshScreen();
|
|
|
|
|
|
// Here comes the descending ghost:
|
|
for (int y = -64; y <= 103; y++) {
|
|
_vm->_graphics->ghostDrawMonster(_ghost[1 + (abs(y / 7) % 2) * 3], 0, y, kMonsterTypeGhost);
|
|
if (y > 0)
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(0, y - 1, 26 * 8 + 1, y + 1), kColorBlack);
|
|
_vm->_graphics->refreshScreen();
|
|
|
|
wait(27);
|
|
}
|
|
|
|
// Then it waves:
|
|
_aarghCount = -15;
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
for (int j = 0; j < 5; j++) {
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(0, 96, 26 * 8, 170), kColorBlack);
|
|
_vm->_graphics->ghostDrawMonster(_ghost[kWaveOrder[j]], 0, 96 + kAdjustment[j], kMonsterTypeGhost);
|
|
|
|
_aarghCount++;
|
|
|
|
if (_aarghCount >= 0) {
|
|
for (int k = 0; k <= _aarghCount; k++)
|
|
_vm->_graphics->ghostDrawPicture(_aargh[k], _aarghWhere[k].x, _aarghWhere[k].y);
|
|
}
|
|
|
|
_vm->_graphics->refreshScreen();
|
|
|
|
wait(177);
|
|
}
|
|
}
|
|
|
|
// The exclamation mark appears:
|
|
_vm->_graphics->ghostDrawPicture(_exclamation, 246, 127);
|
|
_vm->_graphics->refreshScreen();
|
|
wait(777);
|
|
|
|
// Erase "aargh":
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(172, 78, 348, 112), kColorBlack);
|
|
_vm->_graphics->refreshScreen();
|
|
|
|
for (int i = 4; i >= 0; i--) {
|
|
wait(377);
|
|
bigGreenEyes(i);
|
|
}
|
|
|
|
// Erase the exclamation mark:
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(246, 127, 252, 134), kColorBlack);
|
|
_vm->_graphics->refreshScreen();
|
|
|
|
// Avvy hurries back:
|
|
_glerkStage = 0;
|
|
_greldetCount = 18;
|
|
_redGreldet = false;
|
|
|
|
for (int x = 217; x <= 479; x++) {
|
|
// The floating eyeballs again:
|
|
int xBound = x % 30;
|
|
if ((22 <= xBound) && (xBound <= 27)) {
|
|
if (xBound == 22)
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(x + 22, 134, x + 39, 138), kColorBlack);
|
|
_vm->_graphics->ghostDrawPicture(_eyes[1], x + 23, 136);
|
|
_vm->_graphics->drawDot(x + 22, 137, kColorBlack);
|
|
} else {
|
|
if (xBound == 28)
|
|
_vm->_graphics->drawFilledRectangle(Common::Rect(x + 22, 135, x + 39, 139), kColorBlack);
|
|
_vm->_graphics->ghostDrawPicture(_eyes[1], x + 23, 135);
|
|
_vm->_graphics->drawDot(x + 22, 136, kColorBlack); // Eyes would leave a trail 1 pixel high behind them.
|
|
}
|
|
|
|
// Plot the Green Eyes:
|
|
if ((x % 53) == 5) {
|
|
bigGreenEyes(_glerkStage);
|
|
_glerkStage++;
|
|
}
|
|
|
|
// Plot the Greldet:
|
|
if (_greldetCount == 18) {
|
|
_greldetX = _vm->_rnd->getRandomNumber(599);
|
|
_greldetY = _vm->_rnd->getRandomNumber(79);
|
|
_greldetCount = 0;
|
|
_redGreldet = !_redGreldet;
|
|
}
|
|
|
|
_vm->_graphics->ghostDrawPicture(_greldet[kGreldetFade[_greldetCount]][_redGreldet], _greldetX, _greldetY);
|
|
_greldetCount++;
|
|
|
|
_vm->_graphics->refreshScreen();
|
|
|
|
wait(10);
|
|
}
|
|
|
|
CursorMan.showMouse(true);
|
|
|
|
_vm->fadeOut();
|
|
_vm->_graphics->restoreScreen();
|
|
_vm->_graphics->removeBackup();
|
|
_vm->_animation->animLink();
|
|
_vm->fadeIn();
|
|
}
|
|
|
|
} // End of namespace Avalanche
|