Files
2026-02-02 04:50:13 +01:00

971 lines
24 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/substream.h"
#include "tot/anims.h"
#include "tot/decoder/TotFlicDecoder.h"
#include "tot/statics.h"
#include "tot/tot.h"
#include "tot/util.h"
namespace Tot {
void drawText(uint x, uint y, const Common::String &str1, const Common::String &str2, const Common::String &str3, const Common::String &str4, const Common::String &str5, byte textColor, byte borderColor) {
littText(x, (y + 3), str1, borderColor);
littText(x, (y + 13), str2, borderColor);
littText(x, (y + 23), str3, borderColor);
littText(x, (y + 33), str4, borderColor);
littText(x, (y + 43), str5, borderColor);
littText(x, (y + 1), str1, borderColor);
littText(x, (y + 11), str2, borderColor);
littText(x, (y + 21), str3, borderColor);
littText(x, (y + 31), str4, borderColor);
littText(x, (y + 41), str5, borderColor);
g_engine->_screen->update();
littText(x + 1, (y + 2), str1, borderColor);
littText(x + 1, (y + 12), str2, borderColor);
littText(x + 1, (y + 22), str3, borderColor);
littText(x + 1, (y + 32), str4, borderColor);
littText(x + 1, (y + 42), str5, borderColor);
littText(x - 1, (y + 2), str1, borderColor);
littText(x - 1, (y + 12), str2, borderColor);
littText(x - 1, (y + 22), str3, borderColor);
littText(x - 1, (y + 32), str4, borderColor);
littText(x - 1, (y + 42), str5, borderColor);
littText(x, (y + 2), str1, textColor);
littText(x, (y + 12), str2, textColor);
littText(x, (y + 22), str3, textColor);
littText(x, (y + 32), str4, textColor);
littText(x, (y + 42), str5, textColor);
g_engine->_screen->update();
}
void removeText(uint xTextLine1, uint yTextLine1, uint xTextLine2, uint yTextLine2, byte fillColor) {
for (uint j = yTextLine1; j < yTextLine2 + 1; j++) {
for (uint i = xTextLine1; i < xTextLine2 + 1; i++) {
*((byte *)g_engine->_screen->getBasePtr(i, j)) = 0;
}
}
g_engine->_screen->addDirtyRect(Common::Rect(xTextLine1, yTextLine1, xTextLine2, yTextLine2));
}
void drawTvText(const Common::String &str1, const Common::String &str2, const Common::String &str3, const Common::String &str4, const Common::String &str5) {
drawText(80, 0, str1, str2, str3, str4, str5, 253, 0);
}
void clearTvText() {
removeText(80, 0, 319, 54, 0);
}
void drawCharacterText(const Common::String &str1, const Common::String &str2, const Common::String &str3, const Common::String &str4, const Common::String &str5) {
drawText(2, 100, str1, str2, str3, str4, str5, 255, 0);
}
void clearCharacterText() {
removeText(2, 100, 134, 199, 0);
}
void handleFlcEvent(byte eventNumber, uint loopNumber, byte frameCount) {
const char *const *messages = getAnimMessagesByCurrentLanguage();
bool isSpanish = isLanguageSpanish();
bool isEnglish = !isSpanish;
switch (eventNumber) {
case 0:
if (g_engine->_cpCounter > 103)
showError(274);
break;
case 1:
if (frameCount == 3)
switch (loopNumber) {
case 2:
drawTvText(messages[0], messages[1], messages[2], messages[3], messages[4]);
break;
case 13:
clearTvText();
break;
case 14:
drawTvText(messages[5], messages[6], messages[7], messages[8], messages[9]);
break;
case 25:
clearTvText();
break;
case 26:
drawTvText(messages[10], messages[11], messages[12], messages[13], messages[14]);
break;
case 35:
clearTvText();
break;
case 36:
drawCharacterText(messages[15], messages[16], messages[17], messages[18], messages[19]);
break;
// English only
case 40:
case 73:
case 82:
if (isEnglish) {
clearCharacterText();
}
break;
case 41:
if (isEnglish) {
drawCharacterText(messages[250], messages[251], messages[252], messages[253], messages[254]);
}
break;
case 47:
case 59:
case 102:
clearCharacterText();
break;
case 48:
drawCharacterText(messages[20], messages[21], messages[22], messages[23], messages[24]);
break;
case 60:
drawTvText(messages[25], messages[26], messages[27], messages[28], messages[29]);
break;
case 63:
drawCharacterText(messages[30], messages[31], messages[32], messages[33], messages[34]);
break;
case 70:
case 80:
if (isEnglish) {
clearTvText();
}
break;
case 71:
if (isEnglish) {
drawTvText(messages[255], messages[256], messages[257], messages[258], messages[259]);
}
break;
case 74:
if (isEnglish) {
debug(3, "Showing character text in English: %s\n", messages[35]);
drawCharacterText(
messages[35],
messages[36],
messages[37],
messages[38],
messages[39]);
}
break;
case 75:
case 89:
if (isSpanish) {
clearCharacterText();
}
break;
case 76:
if (isSpanish) {
clearTvText();
}
break;
case 77:
if (isSpanish) {
drawCharacterText(messages[35], messages[36], messages[37], messages[38], messages[39]);
}
break;
case 83:
if (isEnglish) {
drawCharacterText(messages[260], messages[261], messages[262], messages[263], messages[264]);
}
break;
case 90:
if (isSpanish) {
drawCharacterText(messages[40], messages[41], messages[42], messages[43], messages[44]);
} else {
clearCharacterText();
}
break;
case 91:
if (isEnglish) {
drawCharacterText(messages[40], messages[41], messages[42], messages[43], messages[44]);
}
break;
case 103:
drawTvText(messages[45], messages[46], messages[47], messages[48], messages[49]);
break;
case 120:
clearTvText();
break;
case 121:
drawTvText(messages[50], messages[51], messages[52], messages[53], messages[54]);
break;
case 125:
drawCharacterText(messages[55], messages[56], messages[57], messages[58], messages[59]);
break;
case 135: {
clearTvText();
clearCharacterText();
} break;
}
break;
case 2:
switch (frameCount) {
case 1: {
clearCharacterText();
clearTvText();
} break;
case 7:
g_engine->_sound->playVoc("MANDO", 142001, 11469);
break;
case 20:
drawCharacterText(messages[60], messages[61], messages[62], messages[63], messages[64]);
break;
case 58: {
clearCharacterText();
drawCharacterText(messages[65], messages[66], messages[67], messages[68], messages[69]);
} break;
case 74: {
delay(1500);
clearCharacterText();
drawCharacterText(messages[70], messages[71], messages[72], messages[73], messages[74]);
delay(4000);
clearCharacterText();
drawTvText(messages[75], messages[76], messages[77], messages[78], messages[79]);
delay(7000);
clearTvText();
drawTvText(messages[80], messages[81], messages[82], messages[83], messages[84]);
if (isEnglish) {
delay(5000);
clearTvText();
drawTvText(messages[265], messages[266], messages[267], messages[268], messages[269]);
}
delay(7000);
clearTvText();
drawTvText(messages[85], messages[86], messages[87], messages[88], messages[89]);
delay(7000);
clearTvText();
drawCharacterText(messages[90], messages[91], messages[92], messages[93], messages[94]);
delay(6000);
clearCharacterText();
drawCharacterText(messages[95], messages[96], messages[97], messages[98], messages[99]);
if (isEnglish) {
delay(6000);
clearCharacterText();
drawCharacterText(messages[95], messages[96], messages[97], messages[98], messages[99]);
}
delay(6000);
} break;
}
break;
case 3:
switch (frameCount) {
case 15:
g_engine->_sound->playVoc("FRENAZO", 165322, 15073);
break;
case 26:
delay(1000);
break;
case 43:
g_engine->_sound->playVoc("PORTAZO", 434988, 932);
break;
case 60:
g_engine->_graphics->getImg(0, 0, 319, 29, g_engine->_graphics->_textAreaBackground);
break;
}
break;
case 4:
if (frameCount == 3)
g_engine->_sound->playVoc("TIMBRAZO", 423775, 11213);
break;
case 5:
if ((loopNumber == 1) && (frameCount == 2)) {
delay(2000);
drawText(5, 1,
messages[100],
messages[101],
messages[102],
messages[103],
messages[104],
255, 249);
delay(3500);
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
g_engine->_screen->update();
drawText(5, 1,
messages[105],
messages[106],
messages[107],
messages[108],
messages[109],
255, 0);
}
break;
case 6:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[110],
messages[111],
messages[112],
messages[113],
messages[114],
255, 249);
} else if ((loopNumber == 5) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[275],
messages[276],
messages[277],
messages[278],
messages[279],
255, 249);
}
break;
case 7:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[115],
messages[116],
messages[117],
messages[118],
messages[119],
255, 0);
}
break;
case 8:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[120],
messages[121],
messages[122],
messages[123],
messages[124],
255, 249);
} else if ((loopNumber == 5) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[280],
messages[281],
messages[282],
messages[283],
messages[284],
255, 249);
}
break;
case 9:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[125],
messages[126],
messages[127],
messages[128],
messages[129],
255, 0);
}
break;
case 10:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[130],
messages[131],
messages[132],
messages[133],
messages[134],
255, 249);
}
break;
case 11:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[135],
messages[136],
messages[137],
messages[138],
messages[139],
255, 0);
}
break;
case 12:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[140],
messages[141],
messages[142],
messages[143],
messages[144],
255, 249);
}
break;
case 13:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[145],
messages[146],
messages[147],
messages[148],
messages[149],
255, 0);
}
break;
case 14:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[150],
messages[151],
messages[152],
messages[153],
messages[154],
255, 249);
} else if ((loopNumber == 5) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[285],
messages[286],
messages[287],
messages[288],
messages[289],
255, 249);
}
break;
case 15:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[155],
messages[156],
messages[157],
messages[158],
messages[159],
255, 0);
}
break;
case 16:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[160],
messages[161],
messages[162],
messages[163],
messages[164],
255, 249);
}
break;
case 17:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 17:
delay(500);
break;
case 18:
g_engine->_sound->playVoc("ACELERON", 30200, 42398);
break;
}
break;
case 18:
if ((loopNumber == 1) && (frameCount == 3)) {
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
drawText(5, 1,
messages[165],
messages[166],
messages[167],
messages[168],
messages[169],
255, 0);
}
break;
case 19:
if (frameCount == 1)
drawText(5, 121,
messages[170],
messages[171],
messages[172],
messages[173],
messages[174],
253, 249);
break;
case 20:
switch (loopNumber) {
case 1:
switch (frameCount) {
case 1:
g_engine->_graphics->getImg(0, 0, 319, 69, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(15, 1,
messages[175],
messages[176],
messages[177],
messages[178],
messages[179],
255, 0);
break;
}
break;
case 3:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(15, 1,
messages[180],
messages[181],
messages[182],
messages[183],
messages[184],
230, 249);
break;
}
break;
case 6:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(15, 1,
messages[185],
messages[186],
messages[187],
messages[188],
messages[189],
230, 249);
break;
}
break;
case 9:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(15, 1,
messages[190],
messages[191],
messages[192],
messages[193],
messages[194],
230, 249);
break;
}
break;
case 12:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(15, 1,
messages[195],
messages[196],
messages[197],
messages[198],
messages[199],
230, 249);
break;
}
break;
case 15:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(15, 1,
messages[200],
messages[201],
messages[202],
messages[203],
messages[204],
230, 249);
break;
}
break;
case 18:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(15, 1,
messages[205],
messages[206],
messages[207],
messages[208],
messages[209],
230, 249);
break;
}
break;
case 21:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(15, 1,
messages[210],
messages[211],
messages[212],
messages[213],
messages[214],
230, 249);
break;
}
break;
case 24:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(15, 1,
messages[215],
messages[216],
messages[217],
messages[218],
messages[219],
230, 249);
break;
}
break;
case 27:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(15, 1,
messages[220],
messages[221],
messages[222],
messages[223],
messages[224],
230, 249);
break;
}
break;
case 30:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(15, 1,
messages[225],
messages[226],
messages[227],
messages[228],
messages[229],
230, 249);
break;
}
break;
case 33:
if (frameCount == 17)
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
}
break;
case 21:
switch (frameCount) {
case 1:
g_engine->_sound->playVoc("TRIDEN", 409405, 14370);
break;
case 5:
g_engine->_sound->playVoc("PUFF", 191183, 18001);
break;
}
break;
case 22:
if (frameCount == 24)
g_engine->_sound->playVoc("PUFF", 191183, 18001);
break;
case 23:
switch (frameCount) {
case 8:
g_engine->_sound->playVoc("AFILAR", 0, 6433);
break;
case 18:
g_engine->_sound->playVoc();
break;
}
break;
case 24:
if (frameCount == 8)
g_engine->_sound->playVoc("DECAPITA", 354269, 1509);
break;
case 25:
if (frameCount == 97)
g_engine->_sound->playVoc("PUFF2", 209184, 14514);
break;
case 26:
switch (loopNumber) {
case 1:
switch (frameCount) {
case 2:
g_engine->_graphics->getImg(0, 0, 319, 69, g_engine->_graphics->_textAreaBackground);
break;
case 3:
drawText(65, 1,
messages[230],
messages[231],
messages[232],
messages[233],
messages[234],
253, 249);
break;
}
break;
case 2:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 2:
drawText(65, 1,
messages[235],
messages[236],
messages[237],
messages[238],
messages[239],
253, 249);
break;
}
break;
case 5:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 2:
drawText(65, 1,
messages[240],
messages[241],
messages[242],
messages[243],
messages[244],
253, 249);
break;
}
break;
case 8:
switch (frameCount) {
case 1:
g_engine->_graphics->putImg(0, 0, g_engine->_graphics->_textAreaBackground);
break;
case 2:
drawText(65, 1,
messages[245],
messages[246],
messages[247],
messages[248],
messages[249],
253, 249);
break;
}
break;
}
break;
case 27:
if (frameCount == 148)
g_engine->_sound->playVoc("DECAPITA", 354269, 1509);
break;
}
}
static void exitProcedure(bool &exitLoop, bool isSkipAllowed) {
exitLoop = false;
g_engine->_events->pollEvent();
if (isSkipAllowed && (g_engine->_events->_keyPressed || g_engine->_events->_leftMouseButton)) {
exitLoop = true;
}
}
static FliHeader readHeader(Common::File *file) {
FliHeader headerfile;
headerfile.size = file->readSint32LE();
headerfile.magic = file->readSint16LE();
headerfile.frames = file->readSint16LE();
headerfile.width = file->readSint16LE();
headerfile.height = file->readSint16LE();
headerfile.depth = file->readSint16LE();
headerfile.flags = file->readSint16LE();
headerfile.speed = file->readSint32LE();
headerfile.reserved1 = file->readSint16LE();
headerfile.created = file->readSint32LE();
file->read(headerfile.creator, 4);
headerfile.updated = file->readSint32LE();
file->read(headerfile.updator, 4);
headerfile.aspectx = file->readSint16LE();
headerfile.aspecty = file->readSint16LE();
file->read(headerfile.reserved2, 19 * 2);
headerfile.ofsframe1 = file->readSint32LE();
headerfile.ofsframe2 = file->readSint32LE();
file->read(headerfile.reserved3, 20 * 2);
return headerfile;
}
void blit(TotFlicDecoder *flic, const Graphics::Surface *src, Common::Rect bounds) {
Graphics::Surface dest = g_engine->_screen->getSubArea(bounds);
flic->copyDirtyRectsToBuffer((byte *)dest.getPixels(), dest.pitch);
g_engine->_screen->addDirtyRect(bounds);
g_engine->_screen->update();
}
void drawFlc(
uint x,
uint y,
int32 offset,
uint loop,
byte speed,
byte eventNumber,
bool fullPalette,
bool isSkipAllowed,
bool limitPaletteTo200,
bool &exitAnim) {
uint loopNumber = 0;
byte frameCount = 0;
Common::File animationsFile;
Common::String fileName;
if (loop == 60000)
fileName = "OBJGIRO.DAT";
else
fileName = "FILMS.DAT";
if (!animationsFile.open(Common::Path(fileName))) {
showError(272);
}
animationsFile.seek(offset, SEEK_SET);
// Need to read header to get the total size of the FLIC file.
FliHeader header = readHeader(&animationsFile);
Common::SeekableSubReadStream *thisFlic = new Common::SeekableSubReadStream(
&animationsFile,
offset,
offset + header.size);
TotFlicDecoder *flic = new TotFlicDecoder();
flic->loadStream(thisFlic);
flic->start();
bool skipFrame = false;
do {
exitProcedure(exitAnim, isSkipAllowed);
loopNumber++;
do {
g_engine->_chrono->updateChrono();
exitProcedure(exitAnim, isSkipAllowed);
if (exitAnim) {
goto Lexit_proc;
}
if (g_engine->_chrono->_gameTick) {
// Make sure we also update the palette animations! Esp. for part 2
if (g_engine->_currentRoomData != nullptr && !g_engine->_shouldQuitGame) {
g_engine->_graphics->advancePaletteAnim();
}
if(speed == 9) {
skipFrame = !skipFrame;
}
if (!skipFrame) {
handleFlcEvent(eventNumber, loopNumber, frameCount);
const Graphics::Surface *frame = flic->decodeNextFrame();
if (frame) {
frameCount++;
Common::Rect boundingBox = Common::Rect(x, y, x + flic->getWidth() + 1, y + flic->getHeight() + 1);
blit(flic, frame, boundingBox);
if (flic->hasDirtyPalette()) {
const byte *fliPalette = (const byte *)flic->getPalette();
byte *palette = new byte[768];
Common::copy(fliPalette, fliPalette + 768, palette);
// game fixes background to 0
palette[0] = 0;
palette[1] = 0;
palette[2] = 0;
if (fullPalette) {
byte *gamePalette = g_engine->_graphics->getPalette();
g_engine->_graphics->fadePalettes(gamePalette, palette);
free(gamePalette);
g_engine->_graphics->copyPalette(palette, g_engine->_graphics->_pal);
} else if (limitPaletteTo200) {
g_engine->_graphics->setPalette(palette, 0, 200);
for (int i = 0; i <= 200; i++) {
if (g_engine->_gamePart == 2 && !g_engine->_shouldQuitGame && (i == 131 || i == 134 || i == 143 || i == 187)) {
continue;
}
g_engine->_graphics->_pal[i * 3 + 0] = palette[i * 3 + 0];
g_engine->_graphics->_pal[i * 3 + 1] = palette[i * 3 + 1];
g_engine->_graphics->_pal[i * 3 + 2] = palette[i * 3 + 2];
}
} else {
g_engine->_graphics->setPalette(palette);
g_engine->_graphics->copyPalette(palette, g_engine->_graphics->_pal);
}
delete[] palette;
}
g_engine->_chrono->_gameTick = false;
} else {
break;
}
}
}
g_system->delayMillis(10);
} while (!flic->endOfVideo() && !g_engine->shouldQuit());
if (flic->endOfVideo()) {
if (flic->isRewindable()) {
flic->rewind();
}
frameCount = 0;
}
} while (loopNumber <= loop && !g_engine->shouldQuit());
flic->stop();
Lexit_proc:
animationsFile.close();
delete flic;
}
} // End of namespace Tot