scummvm/sky/intro.cpp

565 lines
11 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
#include "stdafx.h"
#include <string.h>
#include "common/scummsys.h"
#include "sky/skydefs.h"
#include "sky/sky.h"
#define WAIT_SEQUENCE while (_tseqFrames != 0) { checkCommands(commandPtr); delay(50); CHECK_ESC }
#define CHECK_ESC if (_key_pressed == 27) { _tseqFrames = 0; REMOVE_INTRO return; }
#define FREE_IF_NOT_0(ptr) if (ptr != NULL) { free (ptr); ptr = 0; }
#define REMOVE_INTRO commandPtr = (uint32 *)zeroCommands; \
FREE_IF_NOT_0(_vgaData) \
FREE_IF_NOT_0(_diffData) \
FREE_IF_NOT_0(_workBase) \
FREE_IF_NOT_0(_tempPal) \
FREE_IF_NOT_0(seq1) \
FREE_IF_NOT_0(seq2) \
FREE_IF_NOT_0(_introTextSpace) \
FREE_IF_NOT_0(_introTextSave)
#define INTRO_TEXT_WIDTH 128
#define FN_A_PAL 60080
#define FN_1A_LOG 60081
#define FN_1A 60082
#define FN_1B 60083
#define FN_1C 60084
#define FN_1D 60085
#define FN_1E 60086
#define FN_4A 60087
#define FN_4B_LOG 60088
#define FN_4B 60089
#define FN_4C_LOG 60090
#define FN_4C 60091
#define FN_5_PAL 60092
#define FN_5_LOG 60093
#define FN_5 60094
#define FN_6_PAL 60095
#define FN_6_LOG 60096
#define FN_6A 60097
#define FN_6B 60098
#define IC_PREPARE_TEXT 0
#define IC_SHOW_TEXT 1
#define IC_REMOVE_TEXT 2
#define IC_MAKE_SOUND 3
#define IC_FX_VOLUME 4
uint32 cockpitCommands[] = {
1000, //do straight away
IC_PREPARE_TEXT,
77,
220,
IC_SHOW_TEXT, //radar detects jamming signal
20,
160,
105,
IC_REMOVE_TEXT,
105,
IC_PREPARE_TEXT,
81,
105,
IC_SHOW_TEXT, //well switch to override you fool
170,
86,
35,
IC_REMOVE_TEXT,
35,
IC_PREPARE_TEXT,
477,
35,
IC_SHOW_TEXT,
30,
160,
3,
IC_REMOVE_TEXT,
0
};
uint32 zeroCommands[] = { 0 };
uint32 anim5Commands[] = {
31,
IC_MAKE_SOUND,
2,
127,
0
};
uint32 anim4aCommands[] = {
136,
IC_MAKE_SOUND,
1,
70,
90,
IC_FX_VOLUME,
80,
50,
IC_FX_VOLUME,
90,
5,
IC_FX_VOLUME,
100,
0
};
uint32 anim4cCommands[] = {
1000,
IC_FX_VOLUME,
100,
25,
IC_FX_VOLUME,
110,
15,
IC_FX_VOLUME,
120,
4,
IC_FX_VOLUME,
127,
0
};
uint32 anim6aCommands[] = {
1000,
IC_PREPARE_TEXT,
478,
13,
IC_SHOW_TEXT,
175,
155,
0
};
uint32 anim6bCommands[] = {
131,
IC_REMOVE_TEXT,
131,
IC_PREPARE_TEXT,
479,
74,
IC_SHOW_TEXT,
175,
155,
45,
IC_REMOVE_TEXT,
45,
IC_PREPARE_TEXT,
162,
44,
IC_SHOW_TEXT,
175,
155,
4,
IC_REMOVE_TEXT,
0
};
typedef void (SkyState::*commandRoutinesProc)(uint32 *&cmdPtr);
static const commandRoutinesProc commandRoutines[] = {
&SkyState::prepareText,
&SkyState::showIntroText,
&SkyState::removeText,
&SkyState::introFx,
&SkyState::introVol,
};
void SkyState::initVirgin() {
_tempPal = _skyDisk->loadFile(60111, NULL);
if (_tempPal != NULL)
setPalette(_tempPal);
_workScreen = _skyDisk->loadFile(60110, NULL);
if (_workScreen != NULL)
showScreen();
// free the memory that was malloc'ed indirectly via load_file
free(_workScreen);
free(_tempPal);
}
void SkyState::intro(void) {
uint8 *seq1 = 0;
uint8 *seq2 = 0;
uint32 *commandPtr = (uint32 *)zeroCommands;
_workScreen = _skyDisk->loadFile(60112, NULL); //while virgin screen is up, load rev screen
_tempPal = _skyDisk->loadFile(60113, NULL);
_skyMusic->loadSectionMusic(0);
delay(3000); //keep virgin screen up for 3 seconds
CHECK_ESC
if (!isCDVersion(_gameVersion))
_skyMusic->startMusic(1);
delay(3000); //and another 3 seconds.
CHECK_ESC
fnFadeDown(0); //remove virgin screen
showScreen();
paletteFadeUp(_tempPal);
free (_tempPal);
free (_workScreen);
//while rev is up, load gibbons screen
_workScreen = _skyDisk->loadFile(60114, NULL);
_tempPal = _skyDisk->loadFile(60115, NULL);
_introTextSpace = (uint8 *)calloc(10000, 1);
_introTextSave = (uint8 *)calloc(10000, 1);
_skyText->getText(77);
delay(8000); // keep revolution up for 8 seconds
CHECK_ESC
fnFadeDown(0);
showScreen();
paletteFadeUp(_tempPal);
free (_tempPal);
free (_workScreen);
if (isCDVersion(_gameVersion)) {
doCDIntro();
} else {
_tempPal = _skyDisk->loadFile(FN_A_PAL, NULL);
_workScreen = _skyDisk->loadFile(FN_1A_LOG, NULL);
seq2 = _skyDisk->loadFile(FN_1A, NULL);
//keep gibbo up for 2 seconds
delay(2000);
CHECK_ESC
fnFadeDown(0);
showScreen();
paletteFadeUp(_tempPal);
startTimerSequence(seq2);
free(_tempPal);
seq1 = _skyDisk->loadFile(FN_1B, NULL);
WAIT_SEQUENCE;
free (seq2);
seq2 = _skyDisk->loadFile(FN_1C, NULL);
startTimerSequence(seq1);
WAIT_SEQUENCE;
startTimerSequence(seq2);
WAIT_SEQUENCE;
free(seq1);
free(seq2);
seq1 = _skyDisk->loadFile(FN_1D, NULL);
seq2 = _skyDisk->loadFile(FN_1E, NULL);
startTimerSequence(seq1);
WAIT_SEQUENCE;
startTimerSequence(seq2);
free(seq1);
_vgaData = _skyDisk->loadFile(60100, NULL);
_vgaPointer = _vgaData;
_diffData = _skyDisk->loadFile(60101, NULL);
_noFrames = READ_LE_UINT16(_diffData);
_diffPointer = _diffData + 2;
seq1 = _skyDisk->loadFile(FN_4A, NULL);
WAIT_SEQUENCE;
free (seq2);
//set up the scrolling intro
_workBase = (byte *)malloc(GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT * 2);
//clear the base
memset(_workBase, 0, GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT);
WAIT_SEQUENCE; //1e
memcpy(_workBase + (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT), _workScreen, GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT);
free(_workScreen);
_workScreen = _workBase + (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT);
_workScreenEnd = _workScreen + (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT);
_frameCounter = 1;
byte scrollByte;
while (_frameCounter < _noFrames) {
scrollByte = *_diffPointer++;
if (scrollByte) {
_workScreen -= scrollByte * GAME_SCREEN_WIDTH;
_workScreenEnd -= scrollByte * GAME_SCREEN_WIDTH;
}
delay(40);
if (_key_pressed == 27) {
_workScreen = (byte *)calloc(FULL_SCREEN_WIDTH * FULL_SCREEN_HEIGHT, 1);
REMOVE_INTRO;
return;
}
//non-scrolling frame update
introFrame();
}
startTimerSequence(seq1);
free(_vgaData);
_vgaData = 0;
free(_diffData);
_diffData = 0;
WAIT_SEQUENCE;
free(_workBase);
_workBase = 0;
_workScreen = _skyDisk->loadFile(FN_4B_LOG, NULL);
seq2 = _skyDisk->loadFile(FN_4B, NULL);
showScreen();
commandPtr = (uint32 *)anim4aCommands;
WAIT_SEQUENCE;
commandPtr = (uint32 *)cockpitCommands;
startTimerSequence(seq2);
checkCommands(commandPtr);
checkCommands(commandPtr);
WAIT_SEQUENCE; //4b
free (_workScreen);
_workScreen = 0;
free (seq1);
_workScreen = _skyDisk->loadFile(FN_4C_LOG, NULL);
seq1 = _skyDisk->loadFile(FN_4C, NULL);
showScreen();
startTimerSequence(seq1);
free(seq2);
commandPtr = (uint32 *)anim4cCommands;
WAIT_SEQUENCE; //4c
free (_workScreen);
_tempPal = _skyDisk->loadFile(FN_5_PAL, NULL);
_workScreen = _skyDisk->loadFile(FN_5_LOG, NULL);
seq2 = _skyDisk->loadFile(FN_5, NULL);
fnFadeDown(0);
showScreen();
paletteFadeUp(_tempPal);
startTimerSequence(seq2);
free (_tempPal);
free (seq1);
commandPtr = (uint32 *)anim5Commands;
WAIT_SEQUENCE;
free (_workScreen);
_tempPal = _skyDisk->loadFile(FN_6_PAL, NULL);
_workScreen = _skyDisk->loadFile(FN_6_LOG, NULL);
seq1 = _skyDisk->loadFile(FN_6A, NULL);
fnFadeDown(0);
showScreen();
_skyMusic->startMusic(2);
paletteFadeUp(_tempPal);
startTimerSequence(seq1);
free (seq2);
seq2 = _skyDisk->loadFile(FN_6B, NULL);
commandPtr = (uint32 *)anim6aCommands;
WAIT_SEQUENCE; //6a
free (seq1);
free (_tempPal);
startTimerSequence(seq2);
commandPtr = (uint32 *)anim6bCommands;
WAIT_SEQUENCE; //6b
free (seq2);
}
}
void SkyState::showScreen(void) {
_system->copy_rect(_workScreen, 320, 0, 0, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT);
_system->update_screen();
}
void SkyState::introFrame(void) {
_frameCounter++;
byte *diffPtr = _diffPointer;
byte *vgaPtr = _vgaPointer;
byte *scrPtr = _workScreen;
byte count;
do {
do {
count = *diffPtr++;
scrPtr += count;
} while (count == 255);
do {
count = *diffPtr++;
memcpy(scrPtr, vgaPtr, count);
scrPtr += count;
vgaPtr += count;
} while (*(diffPtr - 1) == 255);
} while (scrPtr < _workScreenEnd);
_diffPointer = diffPtr;
_vgaPointer = vgaPtr;
showScreen();
}
void SkyState::checkCommands(uint32 *&cmdPtr) {
//check for sequence commands
assert (cmdPtr != NULL);
uint32 afterFrame = *(cmdPtr);
if (afterFrame >= _tseqFrames) {
//do a command
uint32 command = *(cmdPtr + 1);
(this->*commandRoutines[command])(cmdPtr);
}
}
void SkyState::prepareText(uint32 *&cmdPtr) {
uint32 textNum = *(cmdPtr + 2);
_skyText->getText(textNum);
_skyText->displayText(_introTextSpace, true, INTRO_TEXT_WIDTH, 255);
cmdPtr += 3;
}
void SkyState::showIntroText(uint32 *&cmdPtr) {
uint32 xPos = *(cmdPtr + 2);
uint32 yPos = *(cmdPtr + 3);
uint32 startPos = (yPos * FULL_SCREEN_WIDTH) + xPos;
byte *destBuf = _introTextSpace;
byte *saveBuf = _introTextSave;
uint16 width = FROM_LE_16(((struct dataFileHeader *)destBuf)->s_width);
uint16 height = FROM_LE_16(((struct dataFileHeader *)destBuf)->s_height);
*(uint32 *)saveBuf = TO_LE_32(startPos);
*(uint32 *)(saveBuf + 4) = TO_LE_32(height);
*(uint32 *)(saveBuf + 8) = TO_LE_32(width);
saveBuf += 12;
//save current screen contents
byte *savePtr = (byte *)_workScreen + startPos;
uint i, j;
for (i = 0; i < height; i++) {
memcpy(saveBuf, savePtr, width);
saveBuf += width;
savePtr += GAME_SCREEN_WIDTH;
}
//now print the text
byte *textBuf = _introTextSpace + sizeof(struct dataFileHeader);
byte *curPos = (byte *)_workScreen + startPos;
for (i = 0; i < height; i++) {
byte *prevPos = curPos;
for (j = 0; j < width; j++) {
uint8 pixel = *textBuf++;
if (pixel)
*curPos = pixel;
curPos++;
}
curPos = prevPos + GAME_SCREEN_WIDTH;
}
cmdPtr += 4;
}
void SkyState::removeText(uint32 *&cmdPtr) {
byte *saveBuf = _introTextSave;
uint32 startPos = READ_LE_UINT32(saveBuf);
uint32 height = READ_LE_UINT32(saveBuf + 4);
uint32 width = READ_LE_UINT32(saveBuf + 8);
byte *dest = _workScreen + startPos;
saveBuf += 12;
for (unsigned int i = 0; i < height; i++) {
memcpy(dest, saveBuf, width);
saveBuf += width;
dest += FULL_SCREEN_WIDTH;
}
cmdPtr += 2;
}
void SkyState::introFx(uint32 *&cmdPtr) {
warning("introFx() not implemented yet");
cmdPtr += 4;
}
void SkyState::introVol(uint32 *&cmdPtr) {
warning("introVol() not implemented yet");
cmdPtr += 3;
}