Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

2
engines/tot/POTFILES Normal file
View File

@@ -0,0 +1,2 @@
engines/tot/metaengine.cpp
engines/tot/saveload.cpp

970
engines/tot/anims.cpp Normal file
View File

@@ -0,0 +1,970 @@
/* 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

58
engines/tot/anims.h Normal file
View File

@@ -0,0 +1,58 @@
/* 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/>.
*
*/
#ifndef TOT_ANIMS_H
#define TOT_ANIMS_H
#include "common/scummsys.h"
namespace Tot {
void drawFlc(uint x, uint y, int32 offset, uint loop,
byte speed, byte eventNumber, bool fullPalette, bool isSkipAllowed,
bool limitPaletteTo200, bool &exitAnim);
/**
* Header of an Autodesk Animator FLIC file.
*/
struct FliHeader {
int32 size; // file size
uint magic, // format id
frames, // number of animation frames
width, // anim width
height, // anim height
depth, // 8 bits per pixel
flags;
int32 speed; // time delay between frames
uint reserved1; // all set to zero
int32 created; // creation date in DOS format
byte creator[3]; // serial of creator program
int32 updated; // update date in DOS format
byte updator[3]; // serial of updating program
uint aspectx, // aspect ratio
aspecty; // aspect ratio
uint reserved2[19]; // all zeroes
int32 ofsframe1, // Offset to frame 1 (FLC only)
ofsframe2; // Offset to frame 2 (FLC only)
uint reserved3[20]; // All zeroes
};
} // End of namespace Tot
#endif

70
engines/tot/chrono.cpp Normal file
View File

@@ -0,0 +1,70 @@
/* 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/system.h"
#include "tot/chrono.h"
#include "tot/tot.h"
namespace Tot {
ChronoManager::ChronoManager(/* args */) : _lastTick(0) {
}
ChronoManager::~ChronoManager() {
}
void ChronoManager::updateChrono() {
uint32 currentTime = g_system->getMillis();
if ((currentTime - _lastTick) >= static_cast<uint32>(kTickMs / _speedMultiplier)) {
_gameTick = true;
_tickCount++;
if (_tickCount == kHalfTickMultiplier) {
_tickCount = 0;
_gameTickHalfSpeed = true;
} else {
_gameTickHalfSpeed = false;
}
_lastTick = currentTime;
} else {
_gameTick = false;
}
}
void ChronoManager::changeSpeed() {
if (_speedMultiplier == 1)
_speedMultiplier = 4;
else
_speedMultiplier = 1;
}
void ChronoManager::delay(uint32 ms) {
uint32 delayStart = g_system->getMillis();
ms = ms / _speedMultiplier;
while ((g_system->getMillis() - delayStart) < ms && !g_engine->shouldQuit()) {
g_engine->_events->pollEvent();
g_engine->_screen->update();
}
}
} // End of namespace Tot

51
engines/tot/chrono.h Normal file
View File

@@ -0,0 +1,51 @@
/* 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/>.
*
*/
#ifndef TOT_CHRONO_H
#define TOT_CHRONO_H
#include "common/scummsys.h"
namespace Tot {
// const int kTickMs = 20;
const int kTickMs = 50;
const int kHalfTickMultiplier = 2;
const int kFrameEffectMs = 10;
class ChronoManager {
private:
uint32 _lastTick = 0;
byte _tickCount = 0;
byte _speedMultiplier = 1;
public:
ChronoManager();
~ChronoManager();
void updateChrono();
void delay(uint32 ms);
void changeSpeed();
bool _gameTick = false;
bool _gameTickHalfSpeed = false;
};
} // End of namespace Tot
#endif

View File

@@ -0,0 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
add_engine tot "Tot" yes "" "" ""

96
engines/tot/console.cpp Normal file
View File

@@ -0,0 +1,96 @@
/* 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 "tot/console.h"
namespace Tot {
TotConsole::TotConsole(TotEngine *engine) : _engine(engine) {
registerCmd("jumpToPart2", WRAP_METHOD(TotConsole, cmdJumpToPart2));
registerCmd("loadRoom", WRAP_METHOD(TotConsole, cmdLoadRoom));
registerCmd("showMouseGrid", WRAP_METHOD(TotConsole, cmdShowMouseGrid));
registerCmd("showGameGrid", WRAP_METHOD(TotConsole, cmdShowGameGrid));
registerCmd("showScreenGrid", WRAP_METHOD(TotConsole, cmdShowScreenGrid));
registerCmd("showObjectAreas", WRAP_METHOD(TotConsole, cmdShowObjectAreas));
registerCmd("clearLayers", WRAP_METHOD(TotConsole, cmdClearLayers));
}
TotConsole::~TotConsole() {
}
bool TotConsole::cmdShowMouseGrid(int argc, const char **argv) {
_engine->_showMouseGrid = true;
debugPrintf("Enabled mouse hotspot grid");
return true;
}
bool TotConsole::cmdShowGameGrid(int argc, const char **argv) {
_engine->_showGameGrid = true;
debugPrintf("Enabled screen base grid");
return true;
}
bool TotConsole::cmdShowScreenGrid(int argc, const char **argv) {
_engine->_showScreenGrid = true;
debugPrintf("Enabled screen walk area grid");
return true;
}
bool TotConsole::cmdShowObjectAreas(int argc, const char **argv) {
_engine->_drawObjectAreas = true;
debugPrintf("Enabled room object area display");
return true;
}
bool TotConsole::cmdClearLayers(int argc, const char **argv) {
_engine->_drawObjectAreas = false;
_engine->_showScreenGrid = false;
_engine->_showGameGrid = false;
_engine->_showMouseGrid = false;
g_engine->_graphics->drawScreen(g_engine->_sceneBackground);
debugPrintf("Cleared all debug layers");
return true;
}
bool TotConsole::cmdLoadRoom(int argc, const char **argv) {
int roomID = atoi(argv[1]);
if (roomID < 0 || roomID > 24) {
debugPrintf("Invalid RoomID %d!\n", roomID);
return true;
}
g_engine->clearAnimation();
g_engine->clearScreenLayers();
g_engine->loadScreenData(roomID);
g_engine->_graphics->drawScreen(g_engine->_sceneBackground);
debugPrintf("Loaded screen %d", roomID);
return true;
}
bool TotConsole::cmdJumpToPart2(int argc, const char **argv) {
g_engine->_list1Complete = true;
g_engine->_list2Complete = true;
debugPrintf("Moving on to part 2 of the game");
return true;
}
} // End of namespace Tot

50
engines/tot/console.h Normal file
View File

@@ -0,0 +1,50 @@
/* 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/>.
*
*/
#ifndef TOT_CONSOLE_H
#define TOT_CONSOLE_H
#include "gui/debugger.h"
#include "tot/tot.h"
namespace Tot {
class TotConsole : public GUI::Debugger {
private:
TotEngine *_engine;
bool cmdJumpToPart2(int argc, const char **argv);
bool cmdLoadRoom(int argc, const char **argv);
bool cmdShowMouseGrid(int argc, const char **argv);
bool cmdShowScreenGrid(int argc, const char **argv);
bool cmdShowGameGrid(int argc, const char **argv);
bool cmdShowObjectAreas(int argc, const char **argv);
bool cmdClearLayers(int argc, const char **argv);
public:
TotConsole(TotEngine *engine);
~TotConsole() override;
};
} // End of namespace Tot
#endif // TOT_CONSOLE_H

3
engines/tot/credits.pl Normal file
View File

@@ -0,0 +1,3 @@
begin_section("Tot");
add_person("Gabriel Sanmartín", "kelmer", "");
end_section();

957
engines/tot/cutscenes.cpp Normal file
View File

@@ -0,0 +1,957 @@
/* 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/config-manager.h"
#include "tot/anims.h"
#include "tot/tot.h"
#include "tot/util.h"
namespace Tot {
byte *drawCreditsScreen(uint &sizeAuxBG, byte *&auxBG) {
Palette intermediatePalette, darkPalette;
Common::File ppFile;
if (!ppFile.open("DIPLOMA.PAN")) {
showError(315);
}
byte *backgroundPointer = (byte *)malloc(320 * 200);
ppFile.read(intermediatePalette, 256 * 3);
ppFile.read(backgroundPointer, 320 * 200);
ppFile.close();
g_engine->_graphics->drawFullScreen(backgroundPointer);
sizeAuxBG = imagesize(0, 0, 319, 59);
// Screen is now backgroundPointer so auxBG contains a 320x60 crop of backgroundPointer
auxBG = (byte *)malloc(sizeAuxBG);
g_engine->_graphics->getImg(0, 0, 319, 59, auxBG);
for (int i = 0; i < 256; i++) {
darkPalette[i * 3 + 0] = 0;
darkPalette[i * 3 + 1] = 0;
darkPalette[i * 3 + 2] = 0;
// Adjust for 6-bit DAC color
intermediatePalette[i * 3 + 0] <<= 2;
intermediatePalette[i * 3 + 1] <<= 2;
intermediatePalette[i * 3 + 2] <<= 2;
}
g_engine->_graphics->fadePalettes(darkPalette, intermediatePalette);
g_engine->_graphics->copyPalette(intermediatePalette, g_engine->_graphics->_pal);
if (g_engine->_cpCounter2 > 9)
showError(274);
return backgroundPointer;
}
void putCreditsImg(uint x, uint y, const byte *img1, const byte *img2, bool direct) {
uint16 wImg1, hImg1;
uint horizontalAux;
wImg1 = READ_LE_UINT16(img1);
hImg1 = READ_LE_UINT16(img1 + 2);
byte * step = (byte *)malloc((wImg1 + 1) * (hImg1 + 1) + 4);
horizontalAux = wImg1 + 1;
uint yPos = hImg1 + y;
// makes sure that if the image is at the bottom of the screen we chop the bottom part
for (int i = yPos; i >= 200; i--)
hImg1 -= 1;
hImg1++;
// Copies the crop in the background corresponding to the current credit window in img1
for (int i = 0; i < hImg1; i++) {
const byte *src = img2 + (320 * (y + i)) + x;
byte *dst = step + 4 + (horizontalAux * i);
Common::copy(src, src + horizontalAux, dst);
}
for (int kk = 0; kk < hImg1; kk++) {
uint inc2 = (kk * wImg1) + 4;
yPos = kk + y;
for (int jj = 0; jj <= wImg1; jj++) {
uint inc = inc2 + jj;
if ((direct && img1[inc] > 0) || (img1[inc] > 16 && yPos >= 66 && yPos <= 192)) {
step[inc] = img1[inc];
} else if (img1[inc] > 16) {
switch (yPos) {
case 59:
case 199:
step[inc] = img1[inc] + 210;
break;
case 60:
case 198:
step[inc] = img1[inc] + 180;
break;
case 61:
case 197:
step[inc] = img1[inc] + 150;
break;
case 62:
case 196:
step[inc] = img1[inc] + 120;
break;
case 63:
case 195:
step[inc] = img1[inc] + 90;
break;
case 64:
case 194:
step[inc] = img1[inc] + 60;
break;
case 65:
case 193:
step[inc] = img1[inc] + 30;
break;
}
}
}
}
// Wait until render tick
do {
g_engine->_chrono->updateChrono();
g_system->delayMillis(10);
} while (!g_engine->_chrono->_gameTick && !g_engine->shouldQuit());
g_engine->_chrono->_gameTick = false;
// Copies the credit window directly to the screen
for (int i = 0; i < hImg1; i++) {
const byte *src = step + 4 + (horizontalAux * i);
byte *dst = ((byte *)g_engine->_screen->getPixels()) + (320 * (y + i)) + x;
Common::copy(src, src + horizontalAux, dst);
}
g_engine->_screen->addDirtyRect(Common::Rect(x, y, x + wImg1 + 1, y + hImg1 + 1));
free(step);
}
void scrollCredit(
int32 position,
uint size,
Palette &pal2,
byte *&background,
bool &exit,
int minHeight,
bool withFade,
bool refresh) {
Common::File creditFile;
if (!creditFile.open("CREDITOS.DAT")) {
showError(270);
}
creditFile.seek(position);
creditFile.read(g_engine->_sceneBackground, size);
creditFile.read(pal2, 768);
creditFile.close();
for (int i = 16; i < 256; i++) {
// Adjust for 6-bit DAC
pal2[i * 3 + 0] <<= 2;
pal2[i * 3 + 1] <<= 2;
pal2[i * 3 + 2] <<= 2;
g_engine->_graphics->_pal[i * 3 + 0] = pal2[i * 3 + 0];
g_engine->_graphics->_pal[i * 3 + 1] = pal2[i * 3 + 1];
g_engine->_graphics->_pal[i * 3 + 2] = pal2[i * 3 + 2];
}
g_engine->_graphics->setPalette(&g_engine->_graphics->_pal[16 * 3 + 0], 16, 240);
// Loops an image from the bottom of the screen to the top
for (int i = 199; i >= minHeight; i--) {
g_engine->_events->pollEvent();
putCreditsImg(85, i, g_engine->_sceneBackground, background, !withFade);
if (g_engine->_events->_keyPressed) {
exit = true;
break;
}
g_engine->_screen->update();
g_system->delayMillis(10);
if (g_engine->shouldQuit())
break;
}
if (refresh) {
g_engine->_graphics->copyFromScreen(background);
}
}
void scrollSingleCredit(
int32 pos,
uint size,
Palette &pal2,
byte *&background,
bool &exit) {
scrollCredit(
pos,
size,
pal2,
background,
exit,
8,
true,
false);
}
void removeTitle(byte *&background2) {
uint i2, j2;
for (int i1 = 1; i1 <= 15000; i1++) {
g_engine->_events->pollEvent();
i2 = g_engine->getRandomNumber(318);
j2 = getRandom(58);
byte *src = background2 + 4 + (j2 * 320) + i2;
byte *dest = ((byte *)g_engine->_screen->getPixels()) + (j2 * 320) + i2;
Common::copy(src, src + 2, dest);
byte *src2 = background2 + 4 + ((j2 + 1) * 320) + i2;
byte *dest2 = ((byte *)g_engine->_screen->getPixels()) + ((j2 + 1) * 320) + i2;
Common::copy(src2, src2 + 2, dest2);
i2 = getRandom(320);
j2 = getRandom(60);
byte *src3 = background2 + 4 + (j2 * 320) + i2;
byte *dest3 = ((byte *)g_engine->_screen->getPixels()) + (j2 * 320) + i2;
Common::copy(src3, src3 + 1, dest3);
if (i1 % 200 == 0) {
g_engine->_screen->addDirtyRect(Common::Rect(0, 0, 320, 60));
g_engine->_screen->update();
}
if (g_engine->shouldQuit()) {
break;
}
}
g_engine->_screen->addDirtyRect(Common::Rect(0, 0, 320, 60));
g_engine->_screen->update();
}
inline bool keyPressed() {
g_engine->_events->pollEvent();
return g_engine->_events->_keyPressed;
}
void TotEngine::credits() {
_saveAllowed = true;
Palette pal2;
byte *background2;
uint sizeBg2;
bool shouldExit = false;
_mouse->hide();
_graphics->totalFadeOut(0);
_sound->fadeOutMusic();
_screen->clear();
_sound->playMidi("CREDITOS", true);
_sound->fadeInMusic();
byte *background = drawCreditsScreen(sizeBg2, background2);
if (keyPressed() || shouldExit)
goto Lexit;
scrollCredit(0, 8004, pal2, background, shouldExit, 10, false, true);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(8772, 8004, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(17544, 8004, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(26316, 7504, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(34588, 7504, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(42860, 8004, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(51632, 7504, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
removeTitle(background2);
if (keyPressed())
goto Lexit;
_graphics->putImg(0, 0, background2);
if (keyPressed())
goto Lexit;
_graphics->copyFromScreen(background);
if (keyPressed())
goto Lexit;
scrollCredit(59904, 8004, pal2, background, shouldExit, 10, false, true);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(68676, 8004, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(77448, 8004, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(86220, 8004, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(94992, 8004, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(103764, 8004, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
scrollSingleCredit(112536, 8004, pal2, background, shouldExit);
if (keyPressed() || shouldExit)
goto Lexit;
removeTitle(background2);
if (keyPressed())
goto Lexit;
_graphics->putImg(0, 0, background2);
if (keyPressed())
goto Lexit;
_graphics->copyFromScreen(background);
if (keyPressed())
goto Lexit;
scrollCredit(121308, 8004, pal2, background, shouldExit, 80, false, true);
Lexit:
delay(1000);
_graphics->totalFadeOut(0);
_sound->fadeOutMusic();
_screen->clear();
_sound->playMidi("INTRODUC", true);
_sound->fadeInMusic();
_mouse->show();
free(background);
free(background2);
}
void TotEngine::introduction() {
_saveAllowed = false;
_mouse->hide();
bool exitPressed;
uint loopCount;
bool isSpanish = isLanguageSpanish();
const char *const *messages = getFullScreenMessagesByCurrentLanguage();
const int32 *offsets = getOffsetsByCurrentLanguage();
exitPressed = false;
_graphics->totalFadeOut(0);
if (_cpCounter > 6)
showError(270);
_screen->clear();
drawFlc(136, 53, offsets[2], 136, 9, 1, true, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(135, 54, offsets[3], 0, 9, 2, true, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
_graphics->totalFadeOut(0);
_screen->clear();
if (isSpanish) {
littText(25, 20, messages[0], 253);
littText(25, 35, messages[1], 253);
littText(25, 50, messages[2], 253);
littText(25, 65, messages[3], 253);
littText(25, 80, messages[4], 253);
littText(25, 95, messages[5], 253);
littText(25, 120, messages[6], 253);
littText(25, 140, messages[7], 253);
littText(25, 155, messages[8], 253);
} else {
littText(25, 35, messages[0], 253);
littText(25, 55, messages[1], 253);
littText(25, 75, messages[2], 253);
littText(25, 95, messages[3], 253);
littText(25, 115, messages[4], 253);
littText(25, 135, messages[5], 253);
}
if (shouldQuit()) {
return;
}
_graphics->totalFadeIn(0, "DEFAULT");
_screen->markAllDirty();
_screen->update();
loopCount = 0;
do {
_chrono->updateChrono();
g_engine->_events->pollEvent();
if (g_engine->_events->_keyPressed || g_engine->_events->_leftMouseButton) {
goto LexitIntro;
}
if (g_engine->_chrono->_gameTick) {
loopCount += 1;
}
g_system->delayMillis(10);
} while (loopCount < 180 && !shouldQuit());
_graphics->totalFadeOut(0);
_screen->clear();
drawFlc(0, 0, offsets[4], 0, 9, 3, true, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(110, 30, offsets[5], 2, 9, 4, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(110, 30, offsets[6], 3, 9, 5, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(110, 30, offsets[7], 0, 9, 0, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(110, 30, offsets[8], isSpanish ? 4 : 8, 9, 6, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(110, 30, offsets[9], 3, 9, 7, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(110, 30, offsets[8], isSpanish ? 3 : 8, 9, 8, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(110, 30, offsets[9], 2, 9, 9, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(0, 0, offsets[10], 0, 9, 0, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(235, 100, offsets[11], 3, 9, 10, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(150, 40, offsets[12], 0, 9, 11, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(235, 100, offsets[11], 3, 9, 12, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(150, 40, offsets[12], isSpanish ? 0 : 2, 9, 13, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(235, 100, offsets[11], isSpanish ? 3 : 8, 9, 14, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(150, 40, offsets[12], 0, 9, 15, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(173, 98, offsets[13], 0, 9, 0, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(224, 100, offsets[14], 2, 9, 16, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(0, 0, offsets[15], 0, 18, 17, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
drawFlc(150, 40, offsets[16], 0, 9, 18, false, true, false, exitPressed);
if (exitPressed)
goto LexitIntro;
delay(1000);
LexitIntro:
_graphics->totalFadeOut(0);
_screen->clear();
_mouse->show();
}
void TotEngine::firstIntroduction() {
if (!_firstTimeDone && !_isIntroSeen) {
introduction();
_firstTimeDone = true;
ConfMan.setBool("introSeen", true);
ConfMan.flushToDisk();
}
}
void TotEngine::initialLogo() {
bool foobar = false;
const int32 *offsets = getOffsetsByCurrentLanguage();
drawFlc(0, 0, offsets[0], 0, 18, 25, false, false, false, foobar);
delay(1000);
}
void TotEngine::sacrificeScene() {
_saveAllowed = false;
Palette palaux;
Common::File file;
bool isSpanish = isLanguageSpanish();
const char *const *messages = getFullScreenMessagesByCurrentLanguage();
const int32 *offsets = getOffsetsByCurrentLanguage();
_sound->stopVoc();
bool exitPressed = _currentRoomData->paletteAnimationFlag;
_currentRoomData->paletteAnimationFlag = false;
bar(0, 139, 319, 149, 0);
bar(10, 10, 310, 120, 0);
if (isSpanish) {
littText(10, 10, messages[9], 200);
littText(10, 30, messages[10], 200);
littText(10, 50, messages[11], 200);
littText(10, 70, messages[12], 200);
littText(10, 90, messages[13], 200);
} else {
littText(10, 20, messages[9], 200);
littText(10, 40, messages[10], 200);
littText(10, 60, messages[11], 200);
littText(10, 80, messages[12], 200);
littText(10, 100, messages[13], 200);
}
for (int i = 0; i <= 28; i++)
setRGBPalette(200, i * 2, i * 2, i * 2);
delay(10000);
if (shouldQuit())
return;
for (int i = 28; i >= 0; i--)
setRGBPalette(200, i * 2, i * 2, i * 2);
bar(10, 10, 310, 120, 0);
if (isSpanish) {
littText(10, 10, messages[14], 200);
littText(10, 30, messages[15], 200);
littText(10, 50, messages[16], 200);
littText(10, 70, messages[17], 200);
littText(10, 90, messages[18], 200);
} else {
littText(10, 20, messages[14], 200);
littText(10, 40, messages[15], 200);
littText(10, 60, messages[16], 200);
littText(10, 80, messages[17], 200);
}
for (int i = 0; i <= 28; i++)
setRGBPalette(200, i * 2, i * 2, i * 2);
delay(10000);
if (shouldQuit())
return;
for (int i = 28; i >= 0; i--)
setRGBPalette(200, i * 2, i * 2, i * 2);
bar(10, 10, 310, 120, 0);
if (isSpanish) {
littText(10, 10, messages[19], 200);
littText(10, 50, messages[20], 200);
littText(10, 70, messages[21], 200);
littText(10, 90, messages[22], 200);
} else {
littText(10, 30, messages[19], 200);
littText(10, 60, messages[20], 200);
littText(10, 80, messages[21], 200);
}
for (int i = 0; i <= 28; i++)
setRGBPalette(200, i * 2, i * 2, i * 2);
delay(10000);
if (shouldQuit())
return;
for (int i = 28; i >= 0; i--)
setRGBPalette(200, i * 2, i * 2, i * 2);
bar(10, 10, 310, 120, 0);
if (!file.open("SALONREC.PAN")) {
showError(318);
}
file.read(palaux, 768);
file.read(_sceneBackground, 44800);
file.close();
g_engine->_graphics->_pal[0] = 0;
g_engine->_graphics->_pal[1] = 0;
g_engine->_graphics->_pal[2] = 0;
for (int i = 1; i <= 234; i++) {
g_engine->_graphics->_pal[i * 3 + 1] = palaux[i * 3 + 1] << 2;
g_engine->_graphics->_pal[i * 3 + 2] = palaux[i * 3 + 2] << 2;
g_engine->_graphics->_pal[i * 3 + 3] = palaux[i * 3 + 3] << 2;
}
// We dont have the width and height here in the byte buffer
_graphics->drawScreen(_sceneBackground, false);
_graphics->partialFadeIn(234);
_sound->stopVoc();
if (shouldQuit())
return;
drawFlc(0, 0, offsets[17], 0, 9, 19, false, false, true, exitPressed);
_graphics->totalFadeOut(128);
_sound->stopVoc();
delay(1000);
if (shouldQuit())
return;
_sound->fadeOutMusic();
_sound->playMidi("SACRIFIC", true);
_sound->fadeInMusic();
_graphics->clear();
littText(10, 31, messages[23], 254);
littText(10, 29, messages[23], 254);
littText(11, 30, messages[23], 254);
littText(9, 30, messages[23], 254);
littText(10, 51, messages[24], 254);
littText(10, 49, messages[24], 254);
littText(11, 50, messages[24], 254);
littText(9, 50, messages[24], 254);
littText(10, 71, messages[25], 254);
littText(10, 69, messages[25], 254);
littText(11, 70, messages[25], 254);
littText(9, 70, messages[25], 254);
littText(10, 30, messages[23], 255);
littText(10, 50, messages[24], 255);
littText(10, 70, messages[25], 255);
for (int i = 0; i <= 31; i++) {
setRGBPalette(255, 32 + i, i * 2, i * 2);
setRGBPalette(254, 32 - i, 0, 0);
}
delay(10000);
if (shouldQuit())
return;
for (int i = 31; i >= 0; i--) {
setRGBPalette(255, 63 - (32 - i), i * 2, i * 2);
setRGBPalette(254, 32 - i, 0, 0);
}
delay(2000);
if (!file.open("SACRIFIC.PAN")) {
showError(318);
}
file.read(palaux, 768);
for (int i = 0; i < 256; i++) {
palaux[i * 3 + 0] <<= 2;
palaux[i * 3 + 1] <<= 2;
palaux[i * 3 + 2] <<= 2;
}
file.read(_sceneBackground, 64000);
file.close();
_graphics->drawFullScreen(_sceneBackground);
palaux[0] = 0;
palaux[1] = 0;
palaux[2] = 0;
_graphics->redFadeIn(palaux);
drawFlc(112, 57, offsets[18], 33, 9, 20, true, false, true, exitPressed);
_sound->autoPlayVoc("REZOS", 0, 0);
if (shouldQuit())
return;
drawFlc(42, 30, offsets[19], 0, 9, 27, false, false, false, exitPressed);
if (shouldQuit())
return;
_graphics->totalFadeOut(128);
_sound->stopVoc();
_graphics->clear();
littText(10, 21, messages[26], 254);
littText(10, 19, messages[26], 254);
littText(11, 20, messages[26], 254);
littText(9, 20, messages[26], 254);
littText(10, 41, messages[27], 254);
littText(10, 39, messages[27], 254);
littText(11, 40, messages[27], 254);
littText(9, 40, messages[27], 254);
littText(10, 61, messages[28], 254);
littText(10, 59, messages[28], 254);
littText(11, 60, messages[28], 254);
littText(9, 60, messages[28], 254);
littText(10, 81, messages[29], 254);
littText(10, 79, messages[29], 254);
littText(11, 80, messages[29], 254);
littText(9, 80, messages[29], 254);
littText(10, 101, messages[30], 254);
littText(10, 99, messages[30], 254);
littText(11, 100, messages[30], 254);
littText(9, 100, messages[30], 254);
littText(10, 121, messages[31], 254);
littText(10, 119, messages[31], 254);
littText(11, 120, messages[31], 254);
littText(9, 120, messages[31], 254);
littText(10, 141, messages[32], 254);
littText(10, 139, messages[32], 254);
littText(11, 140, messages[32], 254);
littText(9, 140, messages[32], 254);
if (!isSpanish) {
littText(10, 161, messages[56], 254);
littText(10, 159, messages[56], 254);
littText(11, 160, messages[56], 254);
littText(9, 160, messages[56], 254);
littText(10, 181, messages[57], 254);
littText(10, 179, messages[57], 254);
littText(11, 180, messages[57], 254);
littText(9, 180, messages[57], 254);
}
littText(10, 20, messages[26], 255);
littText(10, 40, messages[27], 255);
littText(10, 60, messages[28], 255);
littText(10, 80, messages[29], 255);
littText(10, 100, messages[30], 255);
littText(10, 120, messages[31], 255);
littText(10, 140, messages[32], 255);
if (!isSpanish) {
littText(10, 160, messages[56], 255);
littText(10, 180, messages[57], 255);
}
for (int i = 0; i <= 31; i++) {
setRGBPalette(255, 32 + i, i * 2, i * 2);
setRGBPalette(254, 32 - i, 0, 0);
}
delay(16000);
if (shouldQuit())
return;
for (int i = 31; i >= 0; i--) {
setRGBPalette(255, 63 - (32 - i), i * 2, i * 2);
setRGBPalette(254, 32 - i, 0, 0);
}
delay(2000);
if (shouldQuit())
return;
_graphics->clear();
littText(10, 21, messages[33], 254);
littText(10, 19, messages[33], 254);
littText(11, 20, messages[33], 254);
littText(9, 20, messages[33], 254);
littText(10, 41, messages[34], 254);
littText(10, 39, messages[34], 254);
littText(11, 40, messages[34], 254);
littText(9, 40, messages[34], 254);
littText(10, 61, messages[35], 254);
littText(10, 59, messages[35], 254);
littText(11, 60, messages[35], 254);
littText(9, 60, messages[35], 254);
if (isSpanish) {
littText(10, 81, messages[36], 254);
littText(10, 79, messages[36], 254);
littText(11, 80, messages[36], 254);
littText(9, 80, messages[36], 254);
littText(10, 101, messages[37], 254);
littText(10, 99, messages[37], 254);
littText(11, 100, messages[37], 254);
littText(9, 100, messages[37], 254);
littText(10, 121, messages[38], 254);
littText(10, 119, messages[38], 254);
littText(11, 120, messages[38], 254);
littText(9, 120, messages[38], 254);
littText(10, 141, messages[39], 254);
littText(10, 139, messages[39], 254);
littText(11, 140, messages[39], 254);
littText(9, 140, messages[39], 254);
}
littText(10, 20, messages[33], 255);
littText(10, 40, messages[34], 255);
littText(10, 60, messages[35], 255);
if (isSpanish) {
littText(10, 80, messages[36], 255);
littText(10, 100, messages[37], 255);
littText(10, 120, messages[38], 255);
littText(10, 140, messages[39], 255);
}
for (int i = 0; i <= 31; i++) {
setRGBPalette(255, 32 + i, i * 2, i * 2);
setRGBPalette(254, 32 - i, 0, 0);
}
delay(13000);
if (shouldQuit())
return;
for (int i = 31; i >= 0; i--) {
setRGBPalette(255, 63 - (32 - i), i * 2, i * 2);
setRGBPalette(254, 32 - i, 0, 0);
}
delay(2000);
if (shouldQuit())
return;
_graphics->clear();
littText(10, 61, messages[40], 254);
littText(10, 59, messages[40], 254);
littText(11, 60, messages[40], 254);
littText(9, 60, messages[40], 254);
littText(10, 81, messages[41], 254);
littText(10, 79, messages[41], 254);
littText(11, 80, messages[41], 254);
littText(9, 80, messages[41], 254);
littText(10, 101, messages[42], 254);
littText(10, 99, messages[42], 254);
littText(11, 100, messages[42], 254);
littText(9, 100, messages[42], 254);
littText(10, 60, messages[40], 255);
littText(10, 80, messages[41], 255);
littText(10, 100, messages[42], 255);
for (int i = 0; i <= 31; i++) {
setRGBPalette(255, 32 + i, i * 2, i * 2);
setRGBPalette(254, 32 - i, 0, 0);
}
delay(7000);
if (shouldQuit())
return;
for (int i = 31; i >= 0; i--) {
setRGBPalette(255, 63 - (32 - i), i * 2, i * 2);
setRGBPalette(254, 32 - i, 0, 0);
}
delay(2000);
_graphics->totalFadeOut(0);
_currentRoomData->paletteAnimationFlag = exitPressed;
_saveAllowed = true;
}
void TotEngine::ending() {
_saveAllowed = false;
bool exitRequested;
const char *const *messages = getFullScreenMessagesByCurrentLanguage();
const int32 *offsets = getOffsetsByCurrentLanguage();
littText(10, 41, messages[43], 249);
littText(10, 39, messages[43], 249);
littText(11, 40, messages[43], 249);
littText(9, 40, messages[43], 249);
littText(10, 61, messages[44], 249);
littText(10, 59, messages[44], 249);
littText(11, 60, messages[44], 249);
littText(9, 60, messages[44], 249);
littText(10, 40, messages[43], 253);
littText(10, 60, messages[44], 253);
if (shouldQuit()) {
return;
}
delay(4000);
_graphics->totalFadeOut(0);
_graphics->clear();
if (shouldQuit()) {
return;
}
_sound->fadeOutMusic();
_sound->playMidi("SACRIFIC", true);
_sound->fadeInMusic();
drawFlc(0, 0, offsets[30], 12, 9, 26, true, false, false, exitRequested);
if (exitRequested) {
return;
}
drawFlc(0, 0, offsets[31], 0, 9, 0, false, false, false, exitRequested);
if (exitRequested) {
return;
}
delay(1000);
_sound->playVoc("NOOO", 0, 0);
delay(3000);
_saveAllowed = true;
}
void TotEngine::wcScene() {
Palette wcPalette;
_currentZone = _currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount];
goToObject(_currentZone, _targetZone);
_graphics->copyPalette(g_engine->_graphics->_pal, wcPalette);
_mouse->hide();
_graphics->partialFadeOut(234);
const char *const *messages = getFullScreenMessagesByCurrentLanguage();
littText(10, 20, messages[45], 253);
delay(1000);
bar(10, 20, 150, 30, 0);
delay(2000);
littText(100, 50, messages[46], 255);
delay(1000);
bar(100, 50, 250, 60, 0);
delay(2000);
littText(30, 110, messages[47], 253);
delay(1000);
bar(30, 110, 210, 120, 0);
delay(3000);
littText(50, 90, messages[48], 248);
delay(1000);
_sound->playVoc("WATER", 272050, 47062);
bar(50, 90, 200, 100, 0);
delay(4000);
_characterPosX = 76 - kCharacterCorrectionX;
_characterPosY = 78 - kCharacerCorrectionY;
_graphics->copyPalette(wcPalette, g_engine->_graphics->_pal);
_graphics->restoreBackground();
assembleScreen();
_graphics->drawScreen(_sceneBackground);
_graphics->partialFadeIn(234);
_xframe2 = 0;
_currentTrajectoryIndex = 0;
_trajectoryLength = 1;
_currentZone = 8;
_targetZone = 8;
_trajectory[0].x = _characterPosX;
_trajectory[0].y = _characterPosY;
_mouse->show();
}
} // End of namespace Tot

132
engines/tot/debug.cpp Normal file
View File

@@ -0,0 +1,132 @@
/* 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 "tot/debug.h"
#include "tot/tot.h"
#include "tot/util.h"
namespace Tot {
// Debug
void drawMouseGrid(RoomFileRegister *screen) {
for (int i = 0; i < 39; i++) {
for (int j = 0; j < 27; j++) {
int color = screen->mouseGrid[i][j];
if (color == 0) continue;
int startX = i * kXGridCount + 7;
int startY = j * kYGridCount;
for (int i2 = 0; i2 < kXGridCount; i2 += 2) {
for (int j2 = 0; j2 < kYGridCount; j2++) {
int absPixel = startY + j2;
int offsetX = (absPixel % 2 == 0) ? 1 : 0;
*(byte *)g_engine->_screen->getBasePtr(startX + i2 + offsetX, startY + j2) = 255 - color;
}
}
}
}
g_engine->_screen->markAllDirty();
}
void drawScreenGrid(RoomFileRegister *screen) {
for (int i = 0; i < 39; i++) {
for (int j = 0; j < 27; j++) {
int color = screen->walkAreasGrid[i][j];
if (color == 0)
continue;
int startX = i * kXGridCount + 7;
int startY = j * kYGridCount;
for (int i2 = 0; i2 < kXGridCount; i2 += 2) {
for (int j2 = 0; j2 < kYGridCount; j2++) {
int absPixel = startY + j2;
int offsetX = (absPixel % 2 == 0) ? 1 : 0;
*(byte *)g_engine->_screen->getBasePtr(startX + i2 + offsetX, startY + j2) = 255 - color;
}
}
}
}
g_engine->_screen->markAllDirty();
}
void drawPos(uint x, uint y, byte color) {
if (x < 320 && x > 0 && y > 0 && y < 200)
*(byte *)g_engine->_screen->getBasePtr(x, y) = color;
g_engine->_screen->addDirtyRect(Common::Rect(x, y, x + 1, y + 1));
g_engine->_screen->markAllDirty();
}
void drawLine(int x, int y, int x2, int y2, byte color) {
g_engine->_screen->drawLine(x, y, x2, y2, color);
}
void printNiches() {
debug("| | %03d | %03d | %03d | %03d |", 0, 1, 2, 3);
debug("| 0 | %03d | %03d | %03d | %03d |", g_engine->_niche[0][0], g_engine->_niche[0][1], g_engine->_niche[0][2], g_engine->_niche[0][3]);
debug("| 1 | %03d | %03d | %03d | %03d |", g_engine->_niche[1][0], g_engine->_niche[1][1], g_engine->_niche[1][2], g_engine->_niche[1][3]);
debug("niche[0][niche[0][3]] = %d", g_engine->_niche[0][g_engine->_niche[0][3]]);
debug("niche[1][niche[1][3]] = %d", g_engine->_niche[1][g_engine->_niche[1][3]]);
}
void drawX(int x, int y, byte color) {
if (x > 0 && y > 0)
*(byte *)g_engine->_screen->getBasePtr(x, y) = color;
if (x - 1 > 0 && y - 1 > 0)
*(byte *)g_engine->_screen->getBasePtr(x - 1, y - 1) = color;
if (x - 1 > 0 && y + 1 < 140)
*(byte *)g_engine->_screen->getBasePtr(x - 1, y + 1) = color;
if (x + 1 < 320 && y + 1 < 140)
*(byte *)g_engine->_screen->getBasePtr(x + 1, y + 1) = color;
if (x + 1 < 320 && y - 1 > 0)
*(byte *)g_engine->_screen->getBasePtr(x + 1, y - 1) = color;
}
void drawCharacterPosition() {
drawX(g_engine->_characterPosX, g_engine->_characterPosY, 210);
drawX(g_engine->_characterPosX + kCharacterCorrectionX, g_engine->_characterPosY + kCharacerCorrectionY, 218);
}
void drawRect(byte color, int x, int y, int x2, int y2) {
rectangle(x, y, x2, y2, color);
}
void printPos(int x, int y, int screenPosX, int screenPosY, const char *label) {
g_engine->_graphics->restoreBackgroundArea(screenPosX, screenPosY, screenPosX + 100, screenPosY + 10);
g_engine->_graphics->euroText(Common::String::format("%s: %d, %d", label, x, y), screenPosX, screenPosY, Graphics::kTextAlignLeft);
}
void drawGrid() {
int horizontal = 320 / kXGridCount;
int vertical = 140 / kYGridCount;
for (int i = 0; i < horizontal; i++) {
int startX = i * kXGridCount;
g_engine->_screen->drawLine(startX, 0, startX, 140, 200);
}
for (int j = 0; j < vertical; j++) {
int startY = j * kYGridCount;
g_engine->_screen->drawLine(0, startY, 320, startY, 200);
}
g_engine->_screen->addDirtyRect(Common::Rect(0, 0, 320, 140));
}
} // End of namespace Tot

43
engines/tot/debug.h Normal file
View File

@@ -0,0 +1,43 @@
/* 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/>.
*
*/
#ifndef TOT_DEBUG_H
#define TOT_DEBUG_H
#include "tot/tot.h"
namespace Tot {
// Debug methods
void drawMouseGrid(RoomFileRegister *screen);
void drawScreenGrid(RoomFileRegister *screen);
void drawCharacterPosition();
void printPos(int x, int y, int screenPosX, int screenPosY, const char *label);
void drawPos(uint x, uint y, byte color);
void drawGrid();
void drawRect(byte color, int x, int y, int x2, int y2);
void drawX(int x, int y, byte color);
void drawLine(int x, int y, int x2, int y2, byte color);
void printNiches();
} // End of namespace Tot
#endif

View File

@@ -0,0 +1,140 @@
/* 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/stream.h"
#include "graphics/surface.h"
#include "video/flic_decoder.h"
#include "tot/decoder/TotFlicDecoder.h"
namespace Tot {
#define FLI_SETPAL 4
#define FLI_SS2 7
#define FLI_BLACK 13
#define FLI_BRUN 15
#define FLI_COPY 16
#define PSTAMP 18
#define FLC_FILE_HEADER 0x2420
bool TotFlicDecoder::loadStream(Common::SeekableReadStream *stream) {
close();
/* uint32 frameSize = */ stream->readUint32LE();
uint16 frameType = stream->readUint16LE();
// Check FLC magic number
if (frameType != FLC_FILE_HEADER) {
warning("FlicDecoder::loadStream(): attempted to load non-FLC data (type = 0x%04X)", frameType);
return false;
}
uint16 frameCount = stream->readUint16LE();
uint16 width = stream->readUint16LE();
uint16 height = stream->readUint16LE();
uint16 colorDepth = stream->readUint16LE();
if (colorDepth != 8) {
warning("FlicDecoder::loadStream(): attempted to load an FLC with a palette of color depth %d. Only 8-bit color palettes are supported", colorDepth);
return false;
}
addTrack(new TotVideoTrack(stream, frameCount, width, height));
return true;
}
TotFlicDecoder::TotVideoTrack::TotVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height) : Video::FlicDecoder::FlicVideoTrack(stream, frameCount, width, height, true) {
FlicDecoder::FlicVideoTrack::readHeader();
}
TotFlicDecoder::TotVideoTrack::~TotVideoTrack() {
}
void TotFlicDecoder::TotVideoTrack::handleFrame() {
uint16 chunkCount = _fileStream->readUint16LE();
// Note: The overridden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword)
// the frame delay is the FLIC "speed", in milliseconds.
uint16 newFrameDelay = _fileStream->readUint16LE(); // "speed", in milliseconds
if (newFrameDelay > 0)
_frameDelay = newFrameDelay;
_fileStream->readUint16LE(); // reserved, always 0
uint16 newWidth = _fileStream->readUint16LE();
uint16 newHeight = _fileStream->readUint16LE();
if ((newWidth != 0) || (newHeight != 0)) {
if (newWidth == 0)
newWidth = _surface->w;
if (newHeight == 0)
newHeight = _surface->h;
_surface->free();
delete _surface;
_surface = new Graphics::Surface();
_surface->create(newWidth, newHeight, Graphics::PixelFormat::createFormatCLUT8());
}
// Read subchunks
for (uint32 i = 0; i < chunkCount; ++i) {
uint32 frameSize = _fileStream->readUint32LE();
uint16 frameType = _fileStream->readUint16LE();
uint8 *data;
if (frameType == FLI_COPY) {
// data seems to be in a different format for COPY chunks so we adjust for that
data = new uint8[frameSize - 4];
_fileStream->read(data, frameSize - 4);
} else {
data = new uint8[frameSize - 6];
_fileStream->read(data, frameSize - 6);
}
switch (frameType) {
case FLI_SETPAL:
unpackPalette(data);
_dirtyPalette = true;
break;
case FLI_SS2:
decodeDeltaFLC(data);
break;
case FLI_BLACK:
_surface->fillRect(Common::Rect(0, 0, getWidth(), getHeight()), 0);
_dirtyRects.clear();
_dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight()));
break;
case FLI_BRUN:
decodeByteRun(data);
break;
case FLI_COPY:
copyFrame(data);
break;
case PSTAMP:
/* PSTAMP - skip for now */
break;
default:
error("FlicDecoder::decodeNextFrame(): unknown subchunk type (type = 0x%02X)", frameType);
break;
}
delete[] data;
}
}
} // End of namespace Tot

View File

@@ -0,0 +1,49 @@
/* 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/>.
*
*/
#ifndef TOT_FLICDECODER_H
#define TOT_FLICDECODER_H
#include "video/flic_decoder.h"
namespace Tot {
class TotFlicDecoder : public Video::FlicDecoder {
public:
TotFlicDecoder() : Video::FlicDecoder() {}
~TotFlicDecoder() {}
bool loadStream(Common::SeekableReadStream *stream) override;
private:
class TotVideoTrack : public Video::FlicDecoder::FlicVideoTrack {
public:
TotVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height);
~TotVideoTrack() override;
private:
void handleFrame() override;
};
};
} // End namespace Tot
#endif

38
engines/tot/detection.cpp Normal file
View File

@@ -0,0 +1,38 @@
/* 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 "tot/detection.h"
#include "tot/detection_tables.h"
const DebugChannelDef TotMetaEngineDetection::debugFlagList[] = {
{ Tot::kDebugGraphics, "Graphics", "Graphics debug level" },
{ Tot::kDebugPath, "Path", "Pathfinding debug level" },
{ Tot::kDebugFilePath, "FilePath", "File path debug level" },
{ Tot::kDebugScan, "Scan", "Scan for unrecognised games" },
{ Tot::kDebugScript, "Script", "Enable debug script dump" },
DEBUG_CHANNEL_END
};
TotMetaEngineDetection::TotMetaEngineDetection() : AdvancedMetaEngineDetection(
Tot::gameDescriptions, Tot::totGames) {
}
REGISTER_PLUGIN_STATIC(TOT_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, TotMetaEngineDetection);

72
engines/tot/detection.h Normal file
View File

@@ -0,0 +1,72 @@
/* 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/>.
*
*/
#ifndef TOT_DETECTION_H
#define TOT_DETECTION_H
#include "engines/advancedDetector.h"
namespace Tot {
enum TotDebugChannels {
kDebugGraphics = 1,
kDebugPath,
kDebugScan,
kDebugFilePath,
kDebugScript,
};
extern const PlainGameDescriptor totGames[];
extern const ADGameDescription gameDescriptions[];
#define GAMEOPTION_COPY_PROTECTION GUIO_GAMEOPTIONS1
#define GAMEOPTION_NO_TRANSITIONS GUIO_GAMEOPTIONS2
#define GAMEOPTION_ORIGINAL_SAVELOAD_DIALOG GUIO_GAMEOPTIONS3
#define GAMEOPTION_OPL3_MODE GUIO_GAMEOPTIONS4
} // End of namespace Tot
class TotMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
static const DebugChannelDef debugFlagList[];
public:
TotMetaEngineDetection();
~TotMetaEngineDetection() override {}
const char *getName() const override {
return "tot";
}
const char *getEngineName() const override {
return "Trick or Treat";
}
const char *getOriginalCopyright() const override {
return "(C) Todos los derechos reservados. ACA Soft. S.L. Granada Octubre de 1994";
}
const DebugChannelDef *getDebugChannels() const override {
return debugFlagList;
}
};
#endif // TOT_DETECTION_H

View File

@@ -0,0 +1,75 @@
/* 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 "tot/detection.h"
namespace Tot {
const PlainGameDescriptor totGames[] = {
{ "tot", "Trick or Treat" },
{ 0, 0 }
};
const ADGameDescription gameDescriptions[] = {
{
"tot",
nullptr,
AD_ENTRY3s(
"AZCCOG.DAT", "2f66724fcd7f51c5b4a715b30f088581", 79916,
"CREDITOS.DAT", "6885c1fadd25a0c0da1c88f071a30e63", 130080,
"TOT.EXE", "cf3a34941be45d3207e38f8f5d66ba00", 209520
),
Common::ES_ESP,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO5(GUIO_NOSPEECH, GAMEOPTION_COPY_PROTECTION, GAMEOPTION_NO_TRANSITIONS, GAMEOPTION_ORIGINAL_SAVELOAD_DIALOG, GAMEOPTION_OPL3_MODE)
},
{
"tot",
nullptr,
AD_ENTRY3s(
"AZCCOG.DAT", "2f66724fcd7f51c5b4a715b30f088581", 79916,
"CREDITOS.DAT", "bca1c63cfee9ec8b722f7715e21b5e8e", 130080,
"TOT.EXE", "e711989e516bd33d0da6c278c82a0493", 207280
),
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO5(GUIO_NOSPEECH, GAMEOPTION_COPY_PROTECTION, GAMEOPTION_NO_TRANSITIONS, GAMEOPTION_ORIGINAL_SAVELOAD_DIALOG, GAMEOPTION_OPL3_MODE)
},
{
"tot",
"Demo",
AD_ENTRY3s(
"CREDITOS.DAT", "6885c1fadd25a0c0da1c88f071a30e63", 130080,
"PERSONAJ.SPT", "e5e1a2caa4ba3439fa0492cff772a318", 326050,
"ANIMA.EXE", "08b1495d89ef7f05990541edf8754d94", 212880
),
Common::ES_ESP,
Common::kPlatformDOS,
ADGF_DEMO,
GUIO4(GUIO_NOSPEECH, GAMEOPTION_NO_TRANSITIONS, GAMEOPTION_ORIGINAL_SAVELOAD_DIALOG, GAMEOPTION_OPL3_MODE)
},
AD_TABLE_END_MARKER
};
} // End of namespace Tot

651
engines/tot/dialog.cpp Normal file
View File

@@ -0,0 +1,651 @@
/* 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 "tot/dialog.h"
#include "tot/tot.h"
namespace Tot {
Common::String decrypt(Common::String encryptedText) {
for (uint i = 0; i < encryptedText.size(); i++) {
encryptedText.setChar(g_engine->_decryptionKey[i] ^ (char)encryptedText[i], i);
}
return encryptedText;
}
Common::List<uint>* findDialogue(Tree tree, byte characterIndex);
static void findDownwards(Tree curTree, bool &descend) {
if (curTree != nullptr) {
if (curTree->element.spoken != '1') {
descend = true;
return;
} else {
findDownwards(leftChild(curTree), descend);
findDownwards(rightSibling(curTree), descend);
}
}
}
Common::List<uint>* findDialogue(Tree tree, byte characterIndex) {
bool speak = false, ascend = false, descend = false, border = false, forward = false, done = false;
Tree auxTree = tree->child;
Common::List<uint> *linkedList = new Common::List<uint>();
Tree step;
do {
switch (auxTree->element.spoken) {
case '0':
case '2':
case 'H':
speak = true;
break;
case '1': {
speak = false;
step = auxTree->child;
descend = false;
findDownwards(step, descend);
if (!(descend))
ascend = true;
step = nullptr;
} break;
case '3':
if (g_engine->_bookTopic[0] && (characterIndex == 3)) {
speak = false;
ascend = true;
} else
speak = true;
break;
case '4':
if (g_engine->_firstTimeTopicA[characterIndex - 1]) {
speak = false;
ascend = true;
} else
speak = true;
break;
case '5':
if (g_engine->_bookTopic[characterIndex - 1] && g_engine->_firstTimeTopicB[characterIndex - 1])
speak = true;
else {
speak = false;
ascend = true;
}
break;
case '6':
if (g_engine->_bookTopic[characterIndex - 1] && !g_engine->_firstTimeTopicB[characterIndex - 1])
speak = true;
else {
speak = false;
ascend = true;
}
break;
case '7':
if (g_engine->_bookTopic[characterIndex - 1]) {
speak = false;
ascend = true;
} else if (!g_engine->_firstTimeTopicA[characterIndex - 1])
speak = true;
else {
speak = false;
ascend = true;
}
break;
case '8':
if (g_engine->_mintTopic[characterIndex - 1] && g_engine->_firstTimeTopicC[characterIndex - 1])
speak = true;
else {
speak = false;
ascend = true;
}
break;
case '9':
if (g_engine->_mintTopic[characterIndex - 1] && !g_engine->_firstTimeTopicC[characterIndex - 1])
speak = true;
else {
speak = false;
ascend = true;
}
break;
case 'A':
if (!g_engine->_mintTopic[characterIndex - 1] && !g_engine->_firstTimeTopicA[characterIndex - 1])
speak = true;
else {
speak = false;
ascend = true;
}
break;
case 'B':
if (g_engine->_caves[0] && !g_engine->_firstTimeTopicA[8])
speak = true;
else
speak = false;
break;
case 'C':
if (g_engine->_caves[1] && !g_engine->_firstTimeTopicA[8])
speak = true;
else
speak = false;
break;
case 'D':
if ((g_engine->_caves[0] && g_engine->_caves[1]) && !g_engine->_firstTimeTopicA[8])
speak = true;
else
speak = false;
break;
case 'E':
if ((g_engine->_caves[0] && !g_engine->_caves[2]) && !g_engine->_firstTimeTopicA[8])
speak = true;
else
speak = false;
break;
case 'F':
if (!g_engine->_caves[3])
speak = true;
else
speak = false;
break;
case 'G':
if (!g_engine->_caves[4])
speak = true;
else
speak = false;
break;
case 'I':
if (!g_engine->_isSealRemoved)
speak = true;
else
speak = false;
break;
case 'Z':
speak = false;
break;
}
if (speak) {
if (auxTree->element.spoken == '2') {
if (!border) {
border = true;
switch (characterIndex) {
case 1:
if (g_engine->_firstTimeTopicA[characterIndex - 1]) {
linkedList->push_back(12);
forward = true;
} else if (g_engine->_bookTopic[characterIndex - 1]) {
forward = true;
linkedList->push_back(33);
} else {
linkedList->push_back(21);
forward = true;
}
break;
case 3:
if (g_engine->_firstTimeTopicA[characterIndex - 1]) {
linkedList->push_back(103);
forward = true;
} else {
linkedList->push_back(112);
forward = true;
}
break;
default: {
linkedList->push_back(auxTree->element.index);
forward = true;
}
}
}
} else {
linkedList->push_back(auxTree->element.index);
forward = true;
}
if (forward) {
forward = false;
}
if (rightSibling(auxTree) != nullptr)
auxTree = rightSibling(auxTree);
else {
do {
if (!isRoot(parent(auxTree)))
auxTree = parent(auxTree);
else
break;
} while (!(auxTree->element.spoken == '1' && rightSibling(auxTree) != nullptr));
if (rightSibling(auxTree) != nullptr)
auxTree = rightSibling(auxTree);
else
done = true;
}
} else if (ascend) {
ascend = false;
if (rightSibling(auxTree) != nullptr)
auxTree = rightSibling(auxTree);
else {
do {
if (!isRoot(parent(auxTree)))
auxTree = parent(auxTree);
else
break;
} while (!((auxTree->element.spoken == '1') && (rightSibling(auxTree) != nullptr)));
if (rightSibling(auxTree) != nullptr)
auxTree = rightSibling(auxTree);
else
done = true;
}
} else if (leftChild(auxTree) != nullptr)
auxTree = leftChild(auxTree);
else if (rightSibling(auxTree) != nullptr)
auxTree = rightSibling(auxTree);
else {
auxTree = parent(auxTree);
if (rightSibling(auxTree) != nullptr)
auxTree = rightSibling(auxTree);
else {
do {
auxTree = parent(auxTree);
} while (!(isRoot(auxTree) || rightSibling(auxTree) != nullptr));
if (isRoot(auxTree))
done = true;
else
auxTree = rightSibling(auxTree);
}
}
} while (!done);
auxTree = nullptr;
step = nullptr;
return linkedList;
}
void modifyTree(Tree tree, uint node) {
bool found = false;
Tree auxTree = tree->child;
do {
if (auxTree->element.index == node) {
if ((auxTree->element.spoken != '2') && (auxTree->element.spoken != 'H'))
auxTree->element.spoken = '1';
else if (auxTree->element.spoken != 'H')
auxTree->element.spoken = 'Z';
found = true;
} else {
if (leftChild(auxTree) != nullptr)
auxTree = leftChild(auxTree);
else if (rightSibling(auxTree) != nullptr)
auxTree = rightSibling(auxTree);
else {
do {
auxTree = parent(auxTree);
} while (!(rightSibling(auxTree) != nullptr));
auxTree = rightSibling(auxTree);
}
}
} while (!found);
}
void drawTalkMenu() {
byte auxTextY;
g_engine->_mouse->hide();
for (auxTextY = 25; auxTextY >= 1; auxTextY--)
rectangle(0, 175 - auxTextY, 319, 174 + auxTextY, 0);
for (auxTextY = 1; auxTextY <= 25; auxTextY++)
g_engine->buttonBorder(0, 175 - auxTextY, 319, 174 + auxTextY, 253, 253, 253, 253, 0);
g_engine->drawMenu(5);
g_engine->_mouse->show();
}
void fixTree(Tree tree) {
if (tree != nullptr) {
if (tree->element.spoken == 'Z')
tree->element.spoken = '2';
else {
fixTree(leftChild(tree));
fixTree(rightSibling(tree));
}
}
}
void showDialogOptions(
Common::String conversationMatrix[16],
uint &chosenTopic,
byte conversationIndex,
Common::ListInternal::Iterator<uint> l1,
bool &endOfConversation) {
byte firstChat = 1;
byte selectedConv = 0;
g_engine->_mouse->hide();
g_engine->drawMenu(5);
euroText(6, 151, conversationMatrix[1], 255);
euroText(6, 162, conversationMatrix[2], 255);
euroText(6, 173, conversationMatrix[3], 255);
euroText(6, 184, conversationMatrix[4], 255);
g_engine->_mouse->show();
do {
bool lMouseClicked = false;
bool rMouseClicked = false;
do {
g_engine->_chrono->updateChrono();
g_engine->_mouse->animateMouseIfNeeded();
g_engine->_events->pollEvent();
if (g_engine->_events->_leftMouseButton) {
lMouseClicked = true;
} else if (g_engine->_events->_rightMouseButton) {
rMouseClicked = true;
}
if (g_engine->_chrono->_gameTick) {
g_engine->_graphics->advancePaletteAnim();
}
g_system->delayMillis(10);
g_engine->_screen->update();
} while (!lMouseClicked && !rMouseClicked && !g_engine->shouldQuit());
if (lMouseClicked) {
if (g_engine->_mouse->mouseClickY < 143)
selectedConv = 0;
else {
if (g_engine->_mouse->mouseClickX <= 280) {
if (g_engine->_mouse->mouseClickY <= 155) {
selectedConv = firstChat;
} else if (g_engine->_mouse->mouseClickY <= 166) {
selectedConv = firstChat + 1;
} else if (g_engine->_mouse->mouseClickY <= 177) {
selectedConv = firstChat + 2;
} else if (g_engine->_mouse->mouseClickY <= 186) {
selectedConv = firstChat + 3;
}
} else if (g_engine->_mouse->mouseClickX <= 319) {
if (g_engine->_mouse->mouseClickY <= 165) {
if (firstChat > 1) {
selectedConv = 0;
firstChat -= 1;
g_engine->_mouse->hide();
g_engine->drawMenu(5);
euroText(6, 151, conversationMatrix[firstChat], 255);
euroText(6, 162, conversationMatrix[firstChat + 1], 255);
euroText(6, 173, conversationMatrix[firstChat + 2], 255);
euroText(6, 184, conversationMatrix[firstChat + 3], 255);
g_engine->_mouse->show();
}
} else if (g_engine->_mouse->mouseClickY >= 167 && g_engine->_mouse->mouseClickY <= 186) {
if (firstChat < 12) {
selectedConv = 0;
firstChat += 1;
g_engine->_mouse->hide();
g_engine->drawMenu(5);
euroText(6, 151, conversationMatrix[firstChat], 255);
euroText(6, 162, conversationMatrix[firstChat + 1], 255);
euroText(6, 173, conversationMatrix[firstChat + 2], 255);
euroText(6, 184, conversationMatrix[firstChat + 3], 255);
g_engine->_mouse->show();
}
}
}
}
} else if (rMouseClicked)
selectedConv = conversationIndex;
} while (!((selectedConv > 0) && (selectedConv <= conversationIndex)) && !g_engine->shouldQuit());
if (selectedConv == conversationIndex)
endOfConversation = true;
for (int i = 1; i <= (selectedConv - 1); i++)
l1++;
chosenTopic = *l1;
}
void talk(byte characterIndex) {
debug("Talking to person: %d", characterIndex);
uint response, newNode;
TextEntry text;
byte stringAux, insertName, invIndex;
Common::String conversationMatrix[16];
drawTalkMenu();
bool endOfConversation = false;
g_engine->readTextFile();
// The original game makes a copy of the file upon starting a new game. .007 is the current game (the game
// that resumes when clicking "continue game" in the main menu. Part of the savegame data is this 007
// conversation file which marks conversatino topics as already gone through or not.
Tree tree;
readTree(*g_engine->_conversationData, tree, characterIndex - 1);
loadTalkAnimations();
Common::ListInternal::Iterator<uint> l1;
do {
for (int i = 0; i < 16; i++) {
conversationMatrix[i] = "";
}
Common::List<uint> *linkedList = findDialogue(tree, characterIndex);
byte conversationIndex = 0;
l1 = linkedList->begin();
while (l1 != linkedList->end() && !g_engine->shouldQuit() && conversationIndex < 15) {
g_engine->_verbFile.seek(kVerbRegSize * (*l1));
conversationIndex += 1;
text = g_engine->readTextRegister();
insertName = 0;
conversationMatrix[conversationIndex] = decrypt(text.text);
for (uint i = 0; i < conversationMatrix[conversationIndex].size(); i++) {
if (conversationMatrix[conversationIndex][i] == '@')
insertName = i;
}
if (insertName > 0) {
conversationMatrix[conversationIndex].deleteChar(insertName);
conversationMatrix[conversationIndex].insertString(g_engine->_characterName, insertName);
}
if (conversationMatrix[conversationIndex].size() > 45) {
stringAux = 45;
do {
stringAux -= 1;
} while (conversationMatrix[conversationIndex][stringAux] != ' ');
conversationMatrix[conversationIndex] = conversationMatrix[conversationIndex].substr(0, stringAux);
conversationMatrix[conversationIndex].insertString(" ...", stringAux);
}
l1++;
};
l1 = linkedList->begin();
showDialogOptions(conversationMatrix, newNode, conversationIndex, l1, endOfConversation);
delete linkedList;
g_engine->sayLine(newNode, 255, 0, response, true);
stringAux = 0;
modifyTree(tree, newNode);
while (response > 0 && !g_engine->shouldQuit()) {
newNode = response;
stringAux += 1;
if (odd(stringAux))
g_engine->sayLine(newNode, 253, 249, response, true);
else
g_engine->sayLine(newNode, 255, 0, response, true);
switch (newNode) {
case 9: {
g_engine->_obtainedList1 = true;
invIndex = 0;
while (g_engine->_inventory[invIndex].code != 0) {
invIndex += 1;
}
g_engine->_inventory[invIndex].bitmapIndex = kList1Index;
g_engine->_inventory[invIndex].code = kList1code;
g_engine->_inventory[invIndex].objectName = getObjectName(0);
} break;
case 25: {
g_engine->_obtainedList2 = true;
invIndex = 0;
while (g_engine->_inventory[invIndex].code != 0) {
invIndex += 1;
}
g_engine->_inventory[invIndex].bitmapIndex = kList2Index;
g_engine->_inventory[invIndex].code = kList2code;
g_engine->_inventory[invIndex].objectName = getObjectName(1);
} break;
}
}
g_system->delayMillis(10);
} while (!endOfConversation && !g_engine->shouldQuit());
unloadTalkAnimations();
Tree step = tree;
fixTree(step);
saveConversations(g_engine->_conversationData, tree, characterIndex - 1);
g_engine->_verbFile.close();
if (g_engine->shouldQuit()) {
return;
}
delete tree;
g_engine->_mouse->hide();
for (int i = 25; i >= 1; i--)
rectangle(0, 175 - i, 319, 174 + i, 0);
g_engine->drawInventoryMask();
g_engine->drawInventory();
g_engine->_mouse->show();
if (characterIndex < 5) {
if (g_engine->_firstTimeTopicA[characterIndex - 1])
g_engine->_firstTimeTopicA[characterIndex - 1] = false;
if (g_engine->_firstTimeTopicB[characterIndex - 1])
g_engine->_firstTimeTopicB[characterIndex - 1] = false;
if (g_engine->_firstTimeTopicC[characterIndex - 1])
g_engine->_firstTimeTopicC[characterIndex - 1] = false;
} else if (characterIndex == 8)
g_engine->_firstTimeTopicA[8] = false;
}
void talkToSceneObject() {
Common::Point p = g_engine->_mouse->getClickCoordsWithinGrid();
int correctedMouseX = p.x;
int correctedMouseY = p.y;
uint sceneObject = g_engine->_currentRoomData->screenObjectIndex[g_engine->_currentRoomData->mouseGrid[correctedMouseX][correctedMouseY]]->fileIndex;
if (sceneObject == 0)
return;
g_engine->readObject(sceneObject);
g_engine->goToObject(g_engine->_currentRoomData->walkAreasGrid[(g_engine->_characterPosX + kCharacterCorrectionX) / kXGridCount][(g_engine->_characterPosY + kCharacerCorrectionY) / kYGridCount],
g_engine->_currentRoomData->walkAreasGrid[correctedMouseX][correctedMouseY]);
if (g_engine->_curObject->speaking > 0) {
talk(g_engine->_curObject->speaking);
} else {
g_engine->readTextFile();
uint foo = 0;
g_engine->sayLine((getRandom(10) + 1039), 255, 0, foo, false);
g_engine->_verbFile.close();
if (g_engine->_cpCounter > 198)
showError(274);
}
}
/**
* Loads talking animation of main and secondary character
*/
void loadTalkAnimations() {
Common::File animFile;
if (!animFile.open("TIOHABLA.SEC")) {
showError(265);
}
g_engine->_mainCharFrameSize = animFile.readUint16LE();
int32 offset = g_engine->_mainCharFrameSize * 16;
offset = (offset * g_engine->_charFacingDirection) + 2;
animFile.seek(offset);
// Will load talking anim always in the upwards direction of the walk cycle array
for (int i = 0; i < 16; i++) {
free(g_engine->_mainCharAnimation.bitmap[0][i]);
g_engine->_mainCharAnimation.bitmap[0][i] = (byte *)malloc(g_engine->_mainCharFrameSize);
animFile.read(g_engine->_mainCharAnimation.bitmap[0][i], g_engine->_mainCharFrameSize);
}
animFile.close();
if ((g_engine->_currentRoomData->animationName != "PETER") && (g_engine->_currentRoomData->animationName != "ARZCAEL")) {
g_engine->_iframe2 = 0;
bool result;
switch (g_engine->_curObject->speaking) {
case 1:
result = animFile.open("JOHN.SEC");
break;
case 5:
result = animFile.open("ALFRED.SEC");
break;
default:
result = animFile.open(Common::Path(g_engine->_currentRoomData->animationName + Common::String(".SEC")));
}
if (!result)
showError(265);
g_engine->_secondaryAnimFrameSize = animFile.readUint16LE();
g_engine->_secondaryAnimationFrameCount = animFile.readByte();
g_engine->_secondaryAnimDirCount = animFile.readByte();
newSecondaryAnimationFrame();
if (g_engine->_secondaryAnimDirCount != 0) {
g_engine->_secondaryAnimationFrameCount = g_engine->_secondaryAnimationFrameCount / 4;
for (int i = 0; i < 4; i++) {
g_engine->loadAnimationForDirection(&animFile, i);
}
} else {
g_engine->loadAnimationForDirection(&animFile, 0);
}
animFile.close();
}
}
void unloadTalkAnimations() {
Common::File animFile;
if (!animFile.open("PERSONAJ.SPT")) {
showError(265);
}
g_engine->_mainCharFrameSize = animFile.readUint16LE();
for (int i = 0; i < kWalkFrameCount; i++) {
free(g_engine->_mainCharAnimation.bitmap[0][i]);
g_engine->_mainCharAnimation.bitmap[0][i] = (byte *)malloc(g_engine->_mainCharFrameSize);
animFile.read(g_engine->_mainCharAnimation.bitmap[0][i], g_engine->_mainCharFrameSize);
}
animFile.close();
if ((g_engine->_currentRoomData->animationName != "PETER") && (g_engine->_currentRoomData->animationName != "ARZCAEL")) {
if (!animFile.open(Common::Path(g_engine->_currentRoomData->animationName + ".DAT"))) {
showError(265);
}
g_engine->_secondaryAnimFrameSize = animFile.readUint16LE();
g_engine->_secondaryAnimationFrameCount = animFile.readByte();
g_engine->_secondaryAnimDirCount = animFile.readByte();
newSecondaryAnimationFrame();
if (g_engine->_secondaryAnimDirCount != 0) {
g_engine->_secondaryAnimationFrameCount = g_engine->_secondaryAnimationFrameCount / 4;
for (int i = 0; i <= 3; i++) {
g_engine->loadAnimationForDirection(&animFile, i);
}
} else {
g_engine->loadAnimationForDirection(&animFile, 0);
}
animFile.close();
}
}
} // End of namespace Tot

36
engines/tot/dialog.h Normal file
View File

@@ -0,0 +1,36 @@
/* 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/>.
*
*/
#ifndef TOT_DIALOG_H
#define TOT_DIALOG_H
#include "common/scummsys.h"
#include "tot/forest.h"
namespace Tot {
void talkToSceneObject();
void loadTalkAnimations();
void unloadTalkAnimations();
} // End of namespace Tot
#endif

5552
engines/tot/engine.cpp Normal file

File diff suppressed because it is too large Load Diff

138
engines/tot/events.cpp Normal file
View File

@@ -0,0 +1,138 @@
/* 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 "tot/events.h"
#include "events.h"
#include "tot/util.h"
namespace Tot {
TotEventManager::TotEventManager() {
}
void TotEventManager::pollEvent(bool allowDrag) {
Common::EventManager *eventMan = g_engine->_system->getEventManager();
zeroEvents(allowDrag);
while (eventMan->pollEvent(_event)) {
if (isMouseEvent(_event)) {
g_engine->_mouse->warpMouse(_event.mouse);
g_engine->_mouse->mouseX = _event.mouse.x;
g_engine->_mouse->mouseY = _event.mouse.y;
}
switch (_event.type) {
case Common::EVENT_QUIT:
case Common::EVENT_RETURN_TO_LAUNCHER:
return;
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
// handle action
handleKey(_event);
break;
case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
break;
case Common::EVENT_KEYDOWN:
changeGameSpeed(_event);
_keyPressed = true;
_lastKeyEvent = _event;
return;
case Common::EVENT_KEYUP:
return;
case Common::EVENT_MOUSEMOVE:
_mouseX = _event.mouse.x;
_mouseY = _event.mouse.y;
break;
case Common::EVENT_LBUTTONDOWN:
_leftMouseButton = 1;
g_engine->_mouse->mouseClickX = _event.mouse.x;
g_engine->_mouse->mouseClickY = _event.mouse.y;
break;
case Common::EVENT_LBUTTONUP:
_leftMouseButton = 0;
break;
case Common::EVENT_RBUTTONDOWN:
_rightMouseButton = 0;
g_engine->_mouse->mouseClickX = _event.mouse.x;
g_engine->_mouse->mouseClickY = _event.mouse.y;
break;
case Common::EVENT_RBUTTONUP:
_rightMouseButton = 1;
break;
default:
break;
}
}
}
void TotEventManager::zeroEvents(bool allowDrag) {
if (!allowDrag) {
_leftMouseButton = 0;
_rightMouseButton = 0;
}
_escKeyFl = false;
_gameKey = KEY_NONE;
_keyPressed = 0;
_lastKeyEvent = Common::Event();
}
void TotEventManager::waitForPress() {
bool waitForKey = false;
while (!waitForKey && !g_engine->shouldQuit()) {
g_engine->_events->pollEvent();
if (g_engine->_events->_keyPressed) {
waitForKey = true;
}
g_engine->_screen->update();
g_system->delayMillis(10);
}
}
void TotEventManager::handleKey(const Common::Event &event) {
if (event.customType == kActionVolume)
_gameKey = KEY_VOLUME;
else if (event.customType == kActionSaveLoad)
_gameKey = KEY_SAVELOAD;
else if (event.customType == kActionTalk)
_gameKey = KEY_TALK;
else if (event.customType == kActionPickup)
_gameKey = KEY_PICKUP;
else if (event.customType == kActionLookAt)
_gameKey = KEY_LOOKAT;
else if (event.customType == kActionUse)
_gameKey = KEY_USE;
else if (event.customType == kActionOpen)
_gameKey = KEY_OPEN;
else if (event.customType == kActionClose)
_gameKey = KEY_CLOSE;
else if (event.customType == kActionYes)
_gameKey = KEY_YES;
else if (event.customType == kActionNo)
_gameKey = KEY_NO;
else if (event.customType == kActionEscape) {
_gameKey = KEY_ESCAPE;
_escKeyFl = true;
}
}
} // End of namespace Tot

68
engines/tot/events.h Normal file
View File

@@ -0,0 +1,68 @@
/* 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/>.
*
*/
#ifndef TOT_EVENTS_H
#define TOT_EVENTS_H
#include "common/events.h"
#include "common/scummsys.h"
namespace Tot {
enum GAME_KEY {
KEY_TALK = 0,
KEY_PICKUP = 1,
KEY_LOOKAT = 2,
KEY_USE = 3,
KEY_OPEN = 4,
KEY_CLOSE = 5,
KEY_YES = 6,
KEY_NO = 7,
KEY_SAVELOAD = 8,
KEY_VOLUME = 9,
KEY_ESCAPE = 10,
KEY_NONE = -1
};
class TotEventManager {
private:
Common::Event _event;
void handleKey(const Common::Event &event);
public:
bool _escKeyFl = false;
bool _keyPressed = false;
GAME_KEY _gameKey = KEY_NONE;
bool _leftMouseButton = 0;
bool _rightMouseButton = 0;
int16 _mouseX = 0;
int16 _mouseY = 0;
Common::Event _lastKeyEvent;
TotEventManager();
void pollEvent(bool allowDrag = false);
void zeroEvents(bool allowDrag = false);
void waitForPress();
};
} // End of namespace Tot
#endif

193
engines/tot/forest.cpp Normal file
View File

@@ -0,0 +1,193 @@
/* 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 "tot/forest.h"
namespace Tot {
void initTree(Tree &a, nodeElement data) {
a = new TreeDef;
a->element = data;
a->parent = nullptr;
a->sibling = nullptr;
a->child = nullptr;
}
bool isRoot(Tree node) {
bool root;
if (node->parent == nullptr)
root = true;
else
root = false;
return root;
}
Tree rightSibling(Tree node) {
Tree rightSibling;
rightSibling = node->sibling;
return rightSibling;
}
Tree parent(Tree node) {
Tree parent;
parent = node->parent;
return parent;
}
Tree leftChild(Tree node) {
Tree leftChild;
leftChild = node->child;
return leftChild;
}
int depth(Tree node) {
Tree aux;
int depthCount = 0;
aux = node;
while (aux->parent != nullptr) {
depthCount += 1;
aux = parent(aux);
}
return depthCount;
}
void expandNode(Tree &node, nodeElement data) {
Tree aux = node;
if (aux->child != nullptr) {
aux = leftChild(aux);
while (aux->sibling != nullptr)
aux = rightSibling(aux);
;
aux->sibling = new TreeDef;
aux = aux->sibling;
aux->element = data;
aux->sibling = nullptr;
aux->child = nullptr;
aux->parent = node;
} else {
aux->child = new TreeDef;
aux = aux->child;
aux->element = data;
aux->sibling = nullptr;
aux->child = nullptr;
aux->parent = node;
}
}
void preOrder(Tree a, Common::String &encodedString) {
if (a != nullptr) {
encodedString = Common::String::format("%s%d%cN%d@", encodedString.c_str(), a->element.index, a->element.spoken, depth(a));
preOrder(leftChild(a), encodedString);
preOrder(rightSibling(a), encodedString);
}
}
void saveExpression(Common::SeekableWriteStream *s, Common::String expression) {
s->writeByte(expression.size());
s->writeString(expression);
int paddingSize = 255 - expression.size();
if (paddingSize > 0) {
debug("Writing padding of %d", paddingSize);
char *padding = new char[paddingSize];
memset(padding, '\0', paddingSize);
// 8 max char name
s->write(padding, paddingSize);
delete[] padding;
}
}
const int chatRegSize = 256;
void saveConversations(Common::SeekableWriteStream *s, Tree a, uint offset) {
Common::String expression = "";
preOrder(a, expression);
s->seek(offset * chatRegSize, SEEK_SET);
saveExpression(s, expression);
}
void readTree(Common::SeekableReadStream &stream, Tree &a, uint position) {
const nodeElement empty = {'0', 0};
nodeElement data;
Common::String strInd, tmpExpression;
byte level;
Common::String levelAsString;
stream.seek(chatRegSize * position);
Common::String expresion = stream.readPascalString();
initTree(a, empty);
Tree aux = a;
byte pos = 0;
byte currentLevel = 0;
do {
tmpExpression = "";
do {
tmpExpression = tmpExpression + expresion[pos];
} while (expresion[pos++] != '@');
int nIndex = tmpExpression.find('N');
if (nIndex < 0)
break;
strInd = tmpExpression.substr(0, nIndex - 1);
data.spoken = tmpExpression[nIndex - 1];
data.index = atoi(strInd.c_str());
levelAsString = tmpExpression.substr(nIndex + 1, tmpExpression.size() - nIndex - 2);
level = atoi(levelAsString.c_str());
if (level == 0)
aux->element = data;
else if (level == (currentLevel + 1))
expandNode(aux, data);
else if (level > (currentLevel + 1)) {
aux = leftChild(aux);
currentLevel += 1;
while (rightSibling(aux) != nullptr)
aux = rightSibling(aux);
expandNode(aux, data);
} else {
do {
currentLevel -= 1;
aux = parent(aux);
} while (!(currentLevel < level));
expandNode(aux, data);
}
} while (pos != expresion.size());
}
void readTree(Common::String f, Tree &a, uint offset) {
Common::File treeFile;
if (!treeFile.open(Common::Path(f))) {
showError(314);
}
readTree(treeFile, a, offset);
treeFile.close();
}
} // End of namespace Tot

67
engines/tot/forest.h Normal file
View File

@@ -0,0 +1,67 @@
/* 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/>.
*
*/
#ifndef TOT_FOREST_H
#define TOT_FOREST_H
#include "tot/util.h"
namespace Tot {
struct nodeElement {
char spoken;
uint index;
};
typedef struct TreeDef *Tree;
struct TreeDef {
nodeElement element;
Tree parent, sibling, child;
~TreeDef() {
delete sibling;
delete child;
}
};
void initTree(Tree &a, nodeElement data);
bool isRoot(Tree node);
Tree rightSibling(Tree node);
Tree parent(Tree node);
Tree leftChild(Tree node);
int depth(Tree node);
void expandNode(Tree &node, nodeElement data);
void preOrder(Tree a, Common::String &string_);
void saveConversations(Common::SeekableWriteStream *s, Tree a, uint location);
void readTree(Common::SeekableReadStream &f, Tree &a, uint location);
void readTree(Common::String f, Tree &a, uint location);
} // End of namespace Tot
#endif

1050
engines/tot/graphics.cpp Normal file

File diff suppressed because it is too large Load Diff

110
engines/tot/graphics.h Normal file
View File

@@ -0,0 +1,110 @@
/* 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/>.
*
*/
#ifndef TOT_GRAPHICS_H
#define TOT_GRAPHICS_H
#include "common/system.h"
#include "graphics/fonts/bgifont.h"
namespace Tot {
const int kTextAreaSize = 320 * 70 + 4;
class GraphicsManager {
public:
GraphicsManager();
~GraphicsManager();
void init();
void fixPalette(byte *palette, uint num = 768);
byte *getPalette();
void setPalette(byte palette[768], uint start = 0, uint num = 256);
void loadPaletteFromFile(Common::String image);
void turnLightOn();
void totalFadeOut(byte red);
void partialFadeOut(byte numCol);
void totalFadeIn(uint paletteNumber, Common::String paletteName);
void redFadeIn(byte *palette);
void partialFadeIn(byte numCol);
void updatePalette(byte paletteIndex);
void fadePalettes(byte *fromPalette, byte *toPalette);
void copyPalette(byte *from, byte *to);
void putImg(uint coordx, uint coordy, byte *image, bool transparency = false);
void getImg(uint coordx1, uint coordy1, uint coordx2, uint coordy2, byte *image);
void putShape(uint coordx, uint coordy, byte *image);
void putImageArea(uint putcoordx, uint putcoordy, byte *backgroundScreen, byte *image);
void getImageArea(uint getcoordx1, uint getcoordy1, uint getcoordx2, uint getcoordy2, byte *backgroundScreen, byte *image);
void littText(const Common::String &str, int x, int y, uint32 color, Graphics::TextAlign align = Graphics::kTextAlignLeft, bool alignCenterY = false);
void euroText(const Common::String &str, int x, int y, uint32 color, Graphics::TextAlign align = Graphics::kTextAlignLeft, bool alignCenterY = false);
int euroTextWidth(const Common::String &str);
void biosText(const Common::String &str, int x, int y, uint32 color);
void clear();
void clearActionLine();
void writeActionLine(const Common::String &str);
void drawFullScreen(byte *screen);
void copyFromScreen(byte *&screen);
void drawScreen(byte *screen, bool offsetSize = true);
void restoreBackground();
void restoreBackgroundArea(uint x, uint y, uint x2, uint y2);
void sceneTransition(bool fadeToBlack, byte *screen, byte effectNumber);
void sceneTransition(bool fadeToBlack, byte *screen);
void advancePaletteAnim();
void printColor(int x, int y, int color);
void updateSceneArea(int speed = 1);
/**
* Aux for palette animation
*/
byte _paletteAnimFrame = 0;
/**
* Delay of palette animation
*/
byte _palAnimStep = 0;
/**
* 54 color palette slice.
*/
byte _palAnimSlice[768] = { 0 };
/**
* General palette
*/
byte _pal[768] = { 0 };
/**
* TextArea for animations text
*/
byte *_textAreaBackground = (byte *)malloc(kTextAreaSize);
private:
signed char fadeData[256][256];
Graphics::BgiFont *_litt;
Graphics::BgiFont *_euro;
Graphics::Font *_dosFont;
};
} // End of namespace Tot
#endif

194
engines/tot/metaengine.cpp Normal file
View File

@@ -0,0 +1,194 @@
/* 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 "backends/keymapper/action.h"
#include "backends/keymapper/keymapper.h"
#include "backends/keymapper/standard-actions.h"
#include "common/translation.h"
#include "tot/metaengine.h"
#include "tot/detection.h"
#include "tot/statics.h"
#include "tot/tot.h"
static const ADExtraGuiOptionsMap optionsList[] = {
{
GAMEOPTION_COPY_PROTECTION,
{
_s("Copy protection"),
_s("Enable copy protection"),
"copy_protection",
false,
0,
0
}
},
{
GAMEOPTION_NO_TRANSITIONS,
{
_s("Disable scene transitions"),
_s("Disable original transition effects between scenes"),
"transitions_disable",
false,
0,
0
}
},
{
GAMEOPTION_ORIGINAL_SAVELOAD_DIALOG,
{
_s("Original save/load dialog"),
_s("Use original save and load dialogs"),
"originalsaveload",
false,
0,
0
}
},
{
GAMEOPTION_OPL3_MODE,
{
_s("AdLib OPL3 mode"),
_s("When AdLib is selected, OPL3 features will be used. Depending on the game, this will prevent cut-off notes, add extra notes or instruments and/or add stereo."),
"opl3_mode",
false,
0,
0
}
},
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
const char *TotMetaEngine::getName() const {
return "tot";
}
Common::Error TotMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
*engine = new Tot::TotEngine(syst, desc);
return Common::kNoError;
}
bool TotMetaEngine::hasFeature(MetaEngineFeature f) const {
return checkExtendedSaves(f) ||
(f == kSupportsLoadingDuringStartup);
}
const ADExtraGuiOptionsMap *TotMetaEngine::getAdvancedExtraGuiOptions() const {
return optionsList;
}
Common::KeymapArray TotMetaEngine::initKeymaps(const char *target) const {
using namespace Common;
using namespace Tot;
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "tot-default", _("Default keymappings"));
Keymap *gameKeyMap = new Keymap(Keymap::kKeymapTypeGame, "game-shortcuts", _("Game keymappings"));
Keymap *quitDialogKeyMap = new Keymap(Keymap::kKeymapTypeGame, "quit-dialog", _("Quit dialog keymappings"));
Common::Language lang = Common::parseLanguage(ConfMan.get("language", target));
static const char *const *defaultTotKeys = (lang == ES_ESP) ? keys[0] : keys[1];
Action *act;
act = new Action(kStandardActionLeftClick, _("Move / Interact"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
engineKeyMap->addAction(act);
act = new Action(kStandardActionRightClick, _("Default action"));
act->setRightClickEvent();
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
engineKeyMap->addAction(act);
act = new Action("TALK", _("Talk"));
act->setCustomEngineActionEvent(kActionTalk);
act->addDefaultInputMapping(defaultTotKeys[KEY_TALK]);
gameKeyMap->addAction(act);
act = new Action("PICK", _("Pick"));
act->setCustomEngineActionEvent(kActionPickup);
act->addDefaultInputMapping(defaultTotKeys[KEY_PICKUP]);
gameKeyMap->addAction(act);
act = new Action("LOOK", _("Look"));
act->setCustomEngineActionEvent(kActionLookAt);
act->addDefaultInputMapping(defaultTotKeys[KEY_LOOKAT]);
gameKeyMap->addAction(act);
act = new Action("USE", _("Use"));
act->setCustomEngineActionEvent(kActionUse);
act->addDefaultInputMapping(defaultTotKeys[KEY_USE]);
gameKeyMap->addAction(act);
act = new Action("OPEN", _("Open"));
act->setCustomEngineActionEvent(kActionOpen);
act->addDefaultInputMapping(defaultTotKeys[KEY_OPEN]);
gameKeyMap->addAction(act);
act = new Action("CLOSE", _("Close"));
act->setCustomEngineActionEvent(kActionClose);
act->addDefaultInputMapping(defaultTotKeys[KEY_CLOSE]);
gameKeyMap->addAction(act);
act = new Action("SAVELOAD", _("Save and load game"));
act->setCustomEngineActionEvent(kActionSaveLoad);
act->addDefaultInputMapping("F2");
gameKeyMap->addAction(act);
act = new Action("VOLCONTROLS", _("Volume controls"));
act->setCustomEngineActionEvent(kActionVolume);
act->addDefaultInputMapping("F1");
gameKeyMap->addAction(act);
act = new Action("MAINMENU", _("Main menu/Exit"));
act->setCustomEngineActionEvent(kActionEscape);
act->addDefaultInputMapping("ESCAPE");
gameKeyMap->addAction(act);
act = new Action("QUITCONFIRM", _("Confirm quit"));
act->setCustomEngineActionEvent(kActionYes);
act->addDefaultInputMapping(defaultTotKeys[KEY_YES]);
act->addDefaultInputMapping("JOY_RIGHT_TRIGGER");
quitDialogKeyMap->addAction(act);
act = new Action("QUITCANCEL", _("Cancel quit"));
act->setCustomEngineActionEvent(kActionNo);
act->addDefaultInputMapping(defaultTotKeys[KEY_NO]);
act->addDefaultInputMapping("JOY_KEFT_TRIGGER");
quitDialogKeyMap->addAction(act);
KeymapArray keymaps(3);
keymaps[0] = engineKeyMap;
keymaps[1] = gameKeyMap;
keymaps[2] = quitDialogKeyMap;
return keymaps;
}
#if PLUGIN_ENABLED_DYNAMIC(TOT)
REGISTER_PLUGIN_DYNAMIC(TOT, PLUGIN_TYPE_ENGINE, TotMetaEngine);
#else
REGISTER_PLUGIN_STATIC(TOT, PLUGIN_TYPE_ENGINE, TotMetaEngine);
#endif

43
engines/tot/metaengine.h Normal file
View File

@@ -0,0 +1,43 @@
/* 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/>.
*
*/
#ifndef TOT_METAENGINE_H
#define TOT_METAENGINE_H
#include "engines/advancedDetector.h"
class TotMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
public:
const char *getName() const override;
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
/**
* Determine whether the engine supports the specified MetaEngine feature.
*
* Used by e.g. the launcher to determine whether to enable the Load button.
*/
bool hasFeature(MetaEngineFeature f) const override;
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override;
Common::KeymapArray initKeymaps(const char *target) const override;
};
#endif // TOT_METAENGINE_H

194
engines/tot/midi.cpp Normal file
View File

@@ -0,0 +1,194 @@
/* 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 "audio/midiparser.h"
#include "audio/adlib_ctmidi.h"
#include "common/config-manager.h"
#include "tot/midi.h"
namespace Tot {
MidiPlayer::MidiPlayer() {
_driver = nullptr;
_paused = false;
_musicData = nullptr;
_parserMusic = nullptr;
}
MidiPlayer::~MidiPlayer() {
stop();
if (_driver) {
_driver->setTimerCallback(nullptr, nullptr);
_driver->close();
}
if (_parserMusic)
delete _parserMusic;
if (_driver) {
delete _driver;
_driver = nullptr;
}
}
int MidiPlayer::open() {
// Don't call open() twice!
assert(!_driver);
OPL::Config::OplType oplType =
(MidiDriver_ADLIB_Multisource::detectOplType(OPL::Config::kOpl3) && ConfMan.getBool("opl3_mode")) ?
OPL::Config::kOpl3 : OPL::Config::kOpl2;
_driver = new MidiDriver_ADLIB_CTMIDI(oplType);
_parserMusic = MidiParser::createParser_SMF(0);
_driver->property(MidiDriver::PROP_USER_VOLUME_SCALING, true);
_driver->setControllerDefault(MidiDriver_Multisource::CONTROLLER_DEFAULT_PITCH_BEND);
_driver->setControllerDefault(MidiDriver_Multisource::CONTROLLER_DEFAULT_PANNING);
int returnCode = _driver->open();
if (returnCode != 0)
error("MidiPlayer::open - Failed to open MIDI music driver - error code %d.", returnCode);
syncSoundSettings();
// Connect the driver(s) and the parser(s).
_parserMusic->setMidiDriver(_driver);
_parserMusic->setTimerRate(_driver->getBaseTempo());
_driver->setTimerCallback(this, &onTimer);
return 0;
}
void MidiPlayer::onTimer(void *data) {
MidiPlayer *p = (MidiPlayer *)data;
if (p->_parserMusic) {
p->_parserMusic->onTimer();
}
}
bool MidiPlayer::isPlaying() {
return _parserMusic->isPlaying();
}
void MidiPlayer::stop() {
if (_parserMusic) {
_parserMusic->stopPlaying();
if (_driver)
_driver->deinitSource(0);
}
}
void MidiPlayer::pause(bool b) {
if (_paused == b || !_driver)
return;
_paused = b;
if (_paused) {
if (_parserMusic)
_parserMusic->pausePlaying();
} else {
if (_parserMusic)
_parserMusic->resumePlaying();
}
}
void MidiPlayer::syncSoundSettings() {
if (_driver)
_driver->syncSoundSettings();
}
void MidiPlayer::setLoop(bool loop) {
if (_parserMusic)
_parserMusic->property(MidiParser::mpAutoLoop, loop);
}
void MidiPlayer::setSourceVolume(uint8 volume) {
if (_driver)
_driver->setSourceVolume(0, volume);
}
void MidiPlayer::startFadeOut() {
if (_driver)
// Note: 40 ms is almost imperceptibly short
_driver->startFade(40, 0);
}
void MidiPlayer::startFadeIn() {
if (_driver)
_driver->startFade(40, 255);
}
bool MidiPlayer::isFading() {
return _driver ? _driver->isFading() : false;
}
void MidiPlayer::load(Common::SeekableReadStream *in, int32 size) {
MidiParser *parser = _parserMusic;
if (!parser)
return;
if (size < 0) {
// Use the parser to determine the size of the MIDI data.
int64 startPos = in->pos();
size = parser->determineDataSize(in);
if (size < 0) {
warning("MidiPlayer::load - Could not determine size of music data");
return;
}
// determineDataSize might move the stream position, so return it to
// the original position.
in->seek(startPos);
}
if (isPlaying())
stop();
parser->unloadMusic();
byte **dataPtr = &_musicData;
if (*dataPtr) {
delete[] *dataPtr;
}
*dataPtr = new byte[size];
in->read(*dataPtr, size);
parser->loadMusic(*dataPtr, size);
}
void MidiPlayer::play(int track) {
MidiParser *parser = _parserMusic;
if (!parser)
return;
if (parser->setTrack(track)) {
if (_driver)
// Reset the source volume to neutral (in case the previous track
// was faded out).
_driver->resetSourceVolume(0);
parser->startPlaying();
} else {
parser->stopPlaying();
warning("MidiPlayer::play - Could not play %s track %i", "music", track);
}
}
} // End of namespace Tot

66
engines/tot/midi.h Normal file
View File

@@ -0,0 +1,66 @@
/* 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/>.
*
*/
#ifndef TOT_MIDI_H
#define TOT_MIDI_H
#include "audio/mididrv_ms.h"
#include "audio/midiparser.h"
namespace Tot {
class MidiPlayer {
protected:
MidiDriver_Multisource *_driver;
MidiParser *_parserMusic;
byte *_musicData;
bool _paused;
static void onTimer(void *data);
public:
MidiPlayer();
~MidiPlayer();
// Creates and opens the relevant parsers and drivers
int open();
// Loads music or SFX data supported by the MidiParser
void load(Common::SeekableReadStream *in, int32 size = -1);
void play(int track);
void setLoop(bool loop);
bool isPlaying();
void stop();
void pause(bool b);
void syncSoundSettings();
void setSourceVolume(uint8 volume);
void startFadeOut();
void startFadeIn();
bool isFading();
};
} // End of namespace Tot
#endif

33
engines/tot/module.mk Normal file
View File

@@ -0,0 +1,33 @@
MODULE := engines/tot
MODULE_OBJS = \
anims.o \
chrono.o \
console.o \
cutscenes.o \
debug.o \
decoder/TotFlicDecoder.o \
dialog.o \
engine.o \
events.o \
forest.o \
graphics.o \
metaengine.o \
midi.o \
mouse.o \
resources.o \
saveload.o \
sound.o \
tot.o \
util.o
# This module can be built as a plugin
ifeq ($(ENABLE_TOT), DYNAMIC_PLUGIN)
PLUGIN := 1
endif
# Include common rules
include $(srcdir)/rules.mk
# Detection objects
DETECT_OBJS += $(MODULE)/detection.o

121
engines/tot/mouse.cpp Normal file
View File

@@ -0,0 +1,121 @@
/* 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 "graphics/cursorman.h"
#include "tot/mouse.h"
#include "tot/tot.h"
#include "tot/util.h"
namespace Tot {
MouseManager::MouseManager() {
_mouseArea = Common::Rect(0, 0, 320, 200);
loadMasks();
mouseX = 160;
mouseY = 100;
mouseClickX = mouseX;
mouseClickY = mouseY;
mouseMaskIndex = 1;
}
MouseManager::~MouseManager() {
}
void MouseManager::drawMask(int idx) {
CursorMan.replaceCursor(_mouseMasks[idx].mask, 15, 15, 0, 0, 0);
}
void MouseManager::animateMouseIfNeeded() {
if (g_engine->_chrono->_gameTick) {
setMouseMask(_currentMouseMask);
if (_currentMouseMask < 7) {
// sync this with frame time
_currentMouseMask++;
} else
_currentMouseMask = 0;
CursorMan.showMouse(true);
}
}
void MouseManager::hide() {
CursorMan.showMouse(false);
}
void MouseManager::show() {
CursorMan.showMouse(true);
}
void MouseManager::setMouseArea(Common::Rect rect) {
_mouseArea = rect;
}
void MouseManager::warpMouse(Common::Point p) {
p.x = CLIP<int16>(p.x, _mouseArea.left, _mouseArea.right);
p.y = CLIP<int16>(p.y, _mouseArea.top, _mouseArea.bottom);
g_system->warpMouse(p.x, p.y);
}
void MouseManager::printPos(int x, int y, int screenPosX, int screenPosY) {
g_engine->_graphics->restoreBackgroundArea(screenPosX, screenPosY, screenPosX + 100, screenPosY + 10);
g_engine->_graphics->euroText(Common::String::format("MousePos: %d, %d", x + 7, y + 7), screenPosX, screenPosY, Graphics::kTextAlignLeft);
}
Common::Point MouseManager::getClickCoordsWithinGrid() {
int correctedMouseX = (mouseClickX + 7) / kXGridCount;
int correctedMouseY = (mouseClickY + 7) / kYGridCount;
return Common::Point(correctedMouseX, correctedMouseY);
}
Common::Point MouseManager::getMouseCoordsWithinGrid() {
int correctedMouseX = (mouseX + 7) / kXGridCount;
int correctedMouseY = (mouseY + 7) / kYGridCount;
return Common::Point(correctedMouseX, correctedMouseY);
}
void MouseManager::warpMouse(int mask, int x, int y) {
setMouseMask(_currentMouseMask);
g_system->warpMouse(x, y);
}
void MouseManager::loadMasks() {
Common::File mouseMaskFile;
if (!mouseMaskFile.open(Common::Path("RATON.ACA")))
showError(317);
int numMouseMasks = mouseMaskFile.readByte();
int mouseMaskSize = mouseMaskFile.readUint16LE();
for (int i = 0; i < numMouseMasks; i++) {
_mouseMasks[i].width = mouseMaskFile.readUint16LE();
_mouseMasks[i].height = mouseMaskFile.readUint16LE();
_mouseMasks[i].mask = (byte *)malloc(mouseMaskSize - 4);
mouseMaskFile.read(_mouseMasks[i].mask, mouseMaskSize - 4);
}
mouseMaskFile.close();
}
void MouseManager::setMouseMask(int numMask) {
drawMask(numMask);
CursorMan.showMouse(true);
}
} // End of namespace Tot

62
engines/tot/mouse.h Normal file
View File

@@ -0,0 +1,62 @@
/* 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/>.
*
*/
#ifndef TOT_MOUSE_H
#define TOT_MOUSE_H
namespace Tot {
struct MouseMask {
void *mask;
uint width;
uint height;
};
class MouseManager {
public:
MouseManager();
~MouseManager();
void drawMask(int idx);
void warpMouse(int mask, int x, int y);
void setMask(int maskNum);
void animateMouseIfNeeded();
void hide();
void show();
void setMouseArea(Common::Rect rect);
void warpMouse(Common::Point p);
void printPos(int x, int y, int screenPosX, int screenPosY);
Common::Point getClickCoordsWithinGrid();
Common::Point getMouseCoordsWithinGrid();
uint mouseX, mouseY; // Coords of the mouse sprite
uint mouseClickX, mouseClickY; // Coords of mouse clicks
byte mouseMaskIndex; // Frame index of the mouse mask
private:
Common::Rect _mouseArea;
int _currentMouseMask = 0;
MouseMask _mouseMasks[8];
void loadMasks();
void setMouseMask(int numMask);
};
} // End of namespace Tot
#endif

393
engines/tot/resources.cpp Normal file
View File

@@ -0,0 +1,393 @@
/* 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 "tot/tot.h"
#include "tot/util.h"
namespace Tot {
void TotEngine::readBitmap(int32 bitmapPosition, byte *buf, uint bitmapSize, uint error) {
Common::File bitmapFile;
if (!bitmapFile.open("BITMAPS.DAT")) {
showError(error);
}
bitmapFile.seek(bitmapPosition);
bitmapFile.read(buf, bitmapSize);
bitmapFile.close();
}
void TotEngine::loadCharAnimation() {
Common::File characterFile;
_cpCounter = _cpCounter2;
if (!characterFile.open("PERSONAJ.SPT"))
showError(265);
_mainCharFrameSize = characterFile.readUint16LE();
for (int i = 0; i < 4; i++)
for (int j = 0; j < kWalkFrameCount; j++) {
if (g_engine->_mainCharAnimation.bitmap[i][j])
free(g_engine->_mainCharAnimation.bitmap[i][j]);
_mainCharAnimation.bitmap[i][j] = (byte *)malloc(_mainCharFrameSize);
characterFile.read(_mainCharAnimation.bitmap[i][j], _mainCharFrameSize);
}
for (int i = 0; i < 4; i++)
for (int j = kWalkFrameCount; j < (kWalkFrameCount + 10 * 3); j++) {
if (g_engine->_mainCharAnimation.bitmap[i][j])
free(g_engine->_mainCharAnimation.bitmap[i][j]);
_mainCharAnimation.bitmap[i][j] = (byte *)malloc(_mainCharFrameSize);
characterFile.read(_mainCharAnimation.bitmap[i][j], _mainCharFrameSize);
}
characterFile.close();
}
void TotEngine::readTextFile() {
if (!_verbFile.open("CONVERSA.TXT")) {
showError(313);
}
}
TextEntry TotEngine::readTextRegister(uint numRegister) {
_verbFile.seek(numRegister * kVerbRegSize);
return readTextRegister();
}
TextEntry TotEngine::readTextRegister() {
TextEntry regmht;
// Since the text is encrypted it's safer to save the size as reported by
// the pascal string, because the encrypter character might be the termination
// character
byte size = _verbFile.readByte();
_verbFile.seek(-1, SEEK_CUR);
regmht.text = _verbFile.readPascalString(false);
_verbFile.skip(255 - size);
regmht.continued = _verbFile.readByte();
regmht.response = _verbFile.readUint16LE();
regmht.pointer = _verbFile.readSint32LE();
return regmht;
}
void TotEngine::readConversationFile() {
Common::File conversationFile;
if (!conversationFile.open(Common::Path(Common::String("CONVERSA.TRE")))) {
showError(314);
}
int64 fileSize = conversationFile.size();
byte *buf = (byte *)malloc(fileSize);
conversationFile.read(buf, fileSize);
_conversationData = new Common::MemorySeekableReadWriteStream(buf, fileSize, DisposeAfterUse::YES);
conversationFile.close();
}
void saveDoorMetadata(DoorRegistry doors, Common::SeekableWriteStream *out) {
out->writeUint16LE(doors.nextScene);
out->writeUint16LE(doors.exitPosX);
out->writeUint16LE(doors.exitPosY);
out->writeByte(doors.openclosed);
out->writeByte(doors.doorcode);
}
void savePoint(Common::Point point, Common::SeekableWriteStream *out) {
out->writeUint16LE(point.x);
out->writeUint16LE(point.y);
}
void saveBitmapRegister(RoomBitmapRegister bitmap, Common::SeekableWriteStream *out) {
out->writeSint32LE(bitmap.bitmapPointer);
out->writeUint16LE(bitmap.bitmapSize);
out->writeUint16LE(bitmap.coordx);
out->writeUint16LE(bitmap.coordy);
out->writeUint16LE(bitmap.depth);
}
void saveRoomObjectList(RoomObjectListEntry objectList, Common::SeekableWriteStream *out) {
out->writeUint16LE(objectList.fileIndex);
out->writeByte(objectList.objectName.size());
int paddingSize = 20 - objectList.objectName.size();
if (paddingSize < 20) {
out->writeString(objectList.objectName);
}
if (paddingSize > 0) {
char *padding = (char *)calloc(paddingSize, 1);
out->write(padding, paddingSize);
free(padding);
}
}
void saveRoom(RoomFileRegister *room, Common::SeekableWriteStream *out) {
out->writeUint16LE(room->code);
out->writeUint32LE(room->roomImagePointer);
out->writeUint16LE(room->roomImageSize);
out->write(room->walkAreasGrid, 40 * 28);
out->write(room->mouseGrid, 40 * 28);
// read puntos
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 30; j++) {
for (int k = 0; k < 5; k++) {
savePoint(room->trajectories[i][j][k], out);
}
}
}
for (int i = 0; i < 5; i++) {
saveDoorMetadata(room->doors[i], out);
}
for (int i = 0; i < 15; i++) {
saveBitmapRegister(room->screenLayers[i], out);
}
for (int i = 0; i < 51; i++) {
saveRoomObjectList(*room->screenObjectIndex[i], out);
}
out->writeByte(room->animationFlag);
out->writeByte(room->animationName.size());
out->writeString(room->animationName);
int paddingSize = 8 - room->animationName.size();
if (paddingSize > 0) {
char *padding = (char *)calloc(paddingSize, 1);
// 8 max char name
out->write(padding, paddingSize);
free(padding);
}
out->writeByte(room->paletteAnimationFlag);
out->writeUint16LE(room->palettePointer);
for (int i = 0; i < 300; i++) {
savePoint(room->secondaryAnimTrajectory[i], out);
}
out->write(room->secondaryAnimDirections, 600);
out->writeUint16LE(room->secondaryTrajectoryLength);
}
void TotEngine::saveRoomData(RoomFileRegister *room, Common::SeekableWriteStream *out) {
_rooms->seek(room->code * kRoomRegSize, SEEK_SET);
saveRoom(room, out);
}
void TotEngine::readObject(Common::SeekableReadStream *stream, uint itemPos, ScreenObject *thisRegObj) {
stream->seek(itemPos * kItemRegSize);
thisRegObj->code = stream->readUint16LE();
thisRegObj->height = stream->readByte();
thisRegObj->name = stream->readPascalString();
stream->skip(kObjectNameLength - thisRegObj->name.size());
thisRegObj->lookAtTextRef = stream->readUint16LE();
thisRegObj->beforeUseTextRef = stream->readUint16LE();
thisRegObj->afterUseTextRef = stream->readUint16LE();
thisRegObj->pickTextRef = stream->readUint16LE();
thisRegObj->useTextRef = stream->readUint16LE();
thisRegObj->speaking = stream->readByte();
thisRegObj->openable = stream->readByte();
thisRegObj->closeable = stream->readByte();
stream->read(thisRegObj->used, 8);
thisRegObj->pickupable = stream->readByte();
thisRegObj->useWith = stream->readUint16LE();
thisRegObj->replaceWith = stream->readUint16LE();
thisRegObj->depth = stream->readByte();
thisRegObj->bitmapPointer = stream->readUint32LE();
thisRegObj->bitmapSize = stream->readUint16LE();
thisRegObj->rotatingObjectAnimation = stream->readUint32LE();
thisRegObj->rotatingObjectPalette = stream->readUint16LE();
thisRegObj->dropOverlayX = stream->readUint16LE();
thisRegObj->dropOverlayY = stream->readUint16LE();
thisRegObj->dropOverlay = stream->readUint32LE();
thisRegObj->dropOverlaySize = stream->readUint16LE();
thisRegObj->objectIconBitmap = stream->readUint16LE();
thisRegObj->xgrid1 = stream->readByte();
thisRegObj->ygrid1 = stream->readByte();
thisRegObj->xgrid2 = stream->readByte();
thisRegObj->ygrid2 = stream->readByte();
stream->read(thisRegObj->walkAreasPatch, 100);
stream->read(thisRegObj->mouseGridPatch, 100);
}
void TotEngine::readObject(uint itemPosition) {
if(_curObject != nullptr) {
delete _curObject;
_curObject = nullptr;
}
_curObject = new ScreenObject();
readObject(_sceneObjectsData, itemPosition, _curObject);
}
void TotEngine::updateObject(uint itemPosition) {
_curObject->used[0] = 9;
_sceneObjectsData->seek(itemPosition);
saveObject(_curObject, _sceneObjectsData);
}
/**
* Object files contain a single register per object, with a set of 8 flags, to mark them as used in each save.
*/
void TotEngine::initializeObjectFile() {
Common::File objFile;
if (!objFile.open(Common::Path("OBJETOS.DAT"))) {
showError(261);
}
delete (_sceneObjectsData);
byte *objectData = (byte *)malloc(objFile.size());
objFile.read(objectData, objFile.size());
_sceneObjectsData = new Common::MemorySeekableReadWriteStream(objectData, objFile.size(), DisposeAfterUse::NO);
objFile.close();
}
void TotEngine::saveObjectsData(ScreenObject *object, Common::SeekableWriteStream *out) {
out->writeUint16LE(object->code);
out->writeByte(object->height);
out->writeByte(object->name.size());
out->writeString(object->name);
int paddingSize = kObjectNameLength - object->name.size();
if (paddingSize > 0) {
char *padding = (char *)calloc(paddingSize, 1);
// 8 max char name
out->write(padding, paddingSize);
free(padding);
}
out->writeUint16LE(object->lookAtTextRef);
out->writeUint16LE(object->beforeUseTextRef);
out->writeUint16LE(object->afterUseTextRef);
out->writeUint16LE(object->pickTextRef);
out->writeUint16LE(object->useTextRef);
out->writeByte(object->speaking);
out->writeByte(object->openable);
out->writeByte(object->closeable);
out->write(object->used, 8);
out->writeByte(object->pickupable);
out->writeUint16LE(object->useWith);
out->writeUint16LE(object->replaceWith);
out->writeByte(object->depth);
out->writeUint32LE(object->bitmapPointer);
out->writeUint16LE(object->bitmapSize);
out->writeUint16LE(object->rotatingObjectAnimation);
out->writeUint16LE(object->rotatingObjectPalette);
out->writeUint16LE(object->dropOverlayX);
out->writeUint16LE(object->dropOverlayY);
out->writeUint32LE(object->dropOverlay);
out->writeUint16LE(object->dropOverlaySize);
out->writeUint16LE(object->objectIconBitmap);
out->writeByte(object->xgrid1);
out->writeByte(object->ygrid1);
out->writeByte(object->xgrid2);
out->writeByte(object->ygrid2);
out->write(object->walkAreasPatch, 100);
out->write(object->mouseGridPatch, 100);
}
void TotEngine::saveObject(ScreenObject *object, Common::SeekableWriteStream *out) {
_sceneObjectsData->seek(object->code * kItemRegSize, SEEK_SET);
saveObjectsData(object, out);
}
DoorRegistry readDoorMetadata(Common::SeekableReadStream *in) {
DoorRegistry doorMetadata;
doorMetadata.nextScene = in->readUint16LE();
doorMetadata.exitPosX = in->readUint16LE();
doorMetadata.exitPosY = in->readUint16LE();
doorMetadata.openclosed = in->readByte();
doorMetadata.doorcode = in->readByte();
return doorMetadata;
}
Common::Point readPoint(Common::SeekableReadStream *in) {
Common::Point point;
point.x = in->readUint16LE();
point.y = in->readUint16LE();
return point;
}
RoomBitmapRegister readAuxBitmaps(Common::SeekableReadStream *in) {
RoomBitmapRegister bitmapMetadata = RoomBitmapRegister();
bitmapMetadata.bitmapPointer = in->readSint32LE();
bitmapMetadata.bitmapSize = in->readUint16LE();
bitmapMetadata.coordx = in->readUint16LE();
bitmapMetadata.coordy = in->readUint16LE();
bitmapMetadata.depth = in->readUint16LE();
return bitmapMetadata;
}
RoomObjectListEntry *readRoomObjects(Common::SeekableReadStream *in) {
RoomObjectListEntry *objectMetadata = new RoomObjectListEntry();
objectMetadata->fileIndex = in->readUint16LE();
objectMetadata->objectName = in->readPascalString();
in->skip(20 - objectMetadata->objectName.size());
return objectMetadata;
}
RoomFileRegister *TotEngine::readScreenDataFile(Common::SeekableReadStream *in) {
RoomFileRegister *screenData = new RoomFileRegister();
screenData->code = in->readUint16LE();
screenData->roomImagePointer = in->readUint32LE();
screenData->roomImageSize = in->readUint16LE();
in->read(screenData->walkAreasGrid, 40 * 28);
in->read(screenData->mouseGrid, 40 * 28);
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 30; j++) {
for (int k = 0; k < 5; k++) {
screenData->trajectories[i][j][k] = readPoint(in);
}
}
}
for (int i = 0; i < 5; i++) {
screenData->doors[i] = readDoorMetadata(in);
}
for (int i = 0; i < 15; i++) {
screenData->screenLayers[i] = readAuxBitmaps(in);
}
for (int i = 0; i < 51; i++) {
screenData->screenObjectIndex[i] = readRoomObjects(in);
}
screenData->animationFlag = in->readByte();
screenData->animationName = in->readPascalString();
in->skip(8 - screenData->animationName.size());
screenData->paletteAnimationFlag = in->readByte();
screenData->palettePointer = in->readUint16LE();
for (int i = 0; i < 300; i++) {
screenData->secondaryAnimTrajectory[i] = readPoint(in);
}
in->read(screenData->secondaryAnimDirections, 600);
screenData->secondaryTrajectoryLength = in->readUint16LE();
return screenData;
}
} // End of namespace Tot

815
engines/tot/saveload.cpp Normal file
View File

@@ -0,0 +1,815 @@
/* 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/hashmap.h"
#include "common/savefile.h"
#include "common/translation.h"
#include "graphics/thumbnail.h"
#include "gui/message.h"
#include "tot/forest.h"
#include "tot/tot.h"
namespace Tot {
#define SAVEGAME_CURRENT_VERSION 1
bool syncGeneralData(Common::Serializer &s, SavedGame *game) {
// Uint16
s.syncAsUint16LE(game->roomCode);
s.syncAsUint16LE(game->trajectoryLength);
s.syncAsUint16LE(game->currentTrajectoryIndex);
s.syncAsUint16LE(game->backpackObjectCode);
s.syncAsUint16LE(game->rightSfxVol);
s.syncAsUint16LE(game->leftSfxVol);
s.syncAsUint16LE(game->musicVolRight);
s.syncAsUint16LE(game->musicVolLeft);
s.syncAsUint16LE(game->oldGridX);
s.syncAsUint16LE(game->oldGridY);
s.syncAsUint16LE(game->secAnimDepth);
s.syncAsUint16LE(game->secAnimDir);
s.syncAsUint16LE(game->secAnimX);
s.syncAsUint16LE(game->secAnimY);
s.syncAsUint16LE(game->secAnimIFrame);
// Bytes
s.syncAsByte(game->currentZone);
s.syncAsByte(game->targetZone);
s.syncAsByte(game->oldTargetZone);
s.syncAsByte(game->inventoryPosition);
s.syncAsByte(game->actionCode);
s.syncAsByte(game->oldActionCode);
s.syncAsByte(game->steps);
s.syncAsByte(game->doorIndex);
s.syncAsByte(game->characterFacingDir);
s.syncAsByte(game->iframe);
s.syncAsByte(game->gamePart);
// Booleans
s.syncAsByte(game->isSealRemoved);
s.syncAsByte(game->obtainedList1);
s.syncAsByte(game->obtainedList2);
s.syncAsByte(game->list1Complete);
s.syncAsByte(game->list2Complete);
s.syncAsByte(game->isVasePlaced);
s.syncAsByte(game->isScytheTaken);
s.syncAsByte(game->isTridentTaken);
s.syncAsByte(game->isPottersWheelDelivered);
s.syncAsByte(game->isMudDelivered);
s.syncAsByte(game->isGreenDevilDelivered);
s.syncAsByte(game->isRedDevilCaptured);
s.syncAsByte(game->isPottersManualDelivered);
s.syncAsByte(game->isCupboardOpen);
s.syncAsByte(game->isChestOpen);
s.syncAsByte(game->isTVOn);
s.syncAsByte(game->isTrapSet);
for (int i = 0; i < kInventoryIconCount; i++) {
s.syncAsUint16LE(game->mobj[i].bitmapIndex);
s.syncAsUint16LE(game->mobj[i].code);
s.syncString(game->mobj[i].objectName);
}
// integers
s.syncAsSint32LE(game->element1);
s.syncAsSint32LE(game->element2);
s.syncAsSint32LE(game->characterPosX);
s.syncAsSint32LE(game->characterPosY);
s.syncAsSint32LE(game->xframe2);
s.syncAsSint32LE(game->yframe2);
// Strings
s.syncString(game->oldInventoryObjectName);
s.syncString(game->objetomoinventoryObjectNamehila);
s.syncString(game->characterName);
for (int i = 0; i < kRoutePointCount; i++) {
s.syncAsSint16LE(game->mainRoute[i].x);
s.syncAsSint16LE(game->mainRoute[i].y);
}
for (int i = 0; i < 300; i++) {
s.syncAsSint16LE(game->trajectory[i].x);
s.syncAsSint16LE(game->trajectory[i].y);
}
for (int indiaux = 0; indiaux < kCharacterCount; indiaux++) {
// interleave them just to avoid creating many loops
s.syncAsByte(game->firstTimeTopicA[indiaux]);
s.syncAsByte(game->firstTimeTopicB[indiaux]);
s.syncAsByte(game->firstTimeTopicC[indiaux]);
s.syncAsByte(game->bookTopic[indiaux]);
s.syncAsByte(game->mintTopic[indiaux]);
}
for (int indiaux = 0; indiaux < 5; indiaux++) {
s.syncAsByte(game->caves[indiaux]);
s.syncAsUint16LE(game->firstList[indiaux]);
s.syncAsUint16LE(game->secondList[indiaux]);
}
for (int indiaux = 0; indiaux < 4; indiaux++) {
s.syncAsUint16LE(game->niche[0][indiaux]);
s.syncAsUint16LE(game->niche[1][indiaux]);
}
return true;
}
bool syncRoomData(Common::Serializer &s, Common::MemorySeekableReadWriteStream *roomStream) {
if (s.isSaving()) {
// Restore trajectory
g_engine->setRoomTrajectories(g_engine->_secondaryAnimHeight, g_engine->_secondaryAnimWidth, RESTORE);
// Make sure to save any unsaved changes in the room
g_engine->saveRoomData(g_engine->_currentRoomData, g_engine->_rooms);
// Do not fix screen grids, they will be fixed differently below
g_engine->setRoomTrajectories(g_engine->_secondaryAnimHeight, g_engine->_secondaryAnimWidth, SET_WITH_ANIM);
int size = roomStream->size();
byte *roomBuf = (byte *)malloc(size);
roomStream->seek(0, 0);
roomStream->read(roomBuf, size);
s.syncBytes(roomBuf, size);
free(roomBuf);
}
if (s.isLoading()) {
int size = g_engine->_rooms->size();
delete (g_engine->_rooms);
byte *roomBuf = (byte *)malloc(size);
s.syncBytes(roomBuf, size);
g_engine->_rooms = new Common::MemorySeekableReadWriteStream(roomBuf, size, DisposeAfterUse::NO);
}
return true;
}
bool syncConversationData(Common::Serializer &s, Common::MemorySeekableReadWriteStream *conversations) {
int size = conversations->size();
if (s.isSaving()) {
byte *convBuf = (byte *)malloc(size);
conversations->seek(0, 0);
conversations->read(convBuf, size);
s.syncBytes(convBuf, size);
free(convBuf);
}
if (s.isLoading()) {
delete (g_engine->_conversationData);
byte *convBuf = (byte *)malloc(size);
s.syncBytes(convBuf, size);
g_engine->_conversationData = new Common::MemorySeekableReadWriteStream(convBuf, size, DisposeAfterUse::NO);
}
return true;
}
bool syncItemData(Common::Serializer &s, Common::MemorySeekableReadWriteStream *sceneObjects) {
int size = sceneObjects->size();
if (s.isSaving()) {
byte *objBuf = (byte *)malloc(size);
sceneObjects->seek(0, 0);
sceneObjects->read(objBuf, size);
s.syncBytes(objBuf, size);
free(objBuf);
}
if (s.isLoading()) {
delete (g_engine->_sceneObjectsData);
byte *objBuf = (byte *)malloc(size);
s.syncBytes(objBuf, size);
g_engine->_sceneObjectsData = new Common::MemorySeekableReadWriteStream(objBuf, size, DisposeAfterUse::NO);
}
return true;
}
Common::Error syncSaveData(Common::Serializer &ser, SavedGame *game) {
if (!syncGeneralData(ser, game)) {
warning("Error while synchronizing general data");
return Common::kUnknownError;
}
if (!syncRoomData(ser, g_engine->_rooms)) {
warning("Error while synchronizing room data");
return Common::kUnknownError;
}
if (!syncItemData(ser, g_engine->_sceneObjectsData)) {
warning("Error while syncrhonizing object data");
return Common::kUnknownError;
}
if (!syncConversationData(ser, g_engine->_conversationData)) {
warning("Error while syncrhonizing conversation data");
return Common::kUnknownError;
}
if (ser.err()) {
warning("Error while synchronizing");
return Common::kUnknownError;
}
return Common::kNoError;
}
Common::Error TotEngine::syncGame(Common::Serializer &s) {
Common::Error result;
if (s.isLoading()) {
SavedGame *loadedGame = new SavedGame();
// Means we are loading from before the game has started
// if(rooms == nullptr) {
_graphics->clear();
displayLoading();
loadCharAnimation();
loadInventory();
_graphics->loadPaletteFromFile("DEFAULT");
initScreenPointers();
_graphics->totalFadeOut(0);
_graphics->clear();
initializeScreenFile();
initializeObjectFile();
readConversationFile();
result = syncSaveData(s, loadedGame);
loadGame(loadedGame);
} else {
SavedGame *saveGame = saveGameToRegister();
result = syncSaveData(s, saveGame);
free(saveGame);
}
return result;
}
Common::Error TotEngine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
const byte version = SAVEGAME_CURRENT_VERSION;
Common::Serializer s(nullptr, stream);
s.setVersion(version);
stream->writeByte(version);
return syncGame(s);
}
Common::Error TotEngine::loadGameStream(Common::SeekableReadStream *stream) {
byte version = stream->readByte();
if (version > SAVEGAME_CURRENT_VERSION) {
GUI::MessageDialog dialog(_("Saved game was created with a newer version of ScummVM. Unable to load."));
dialog.runModal();
return Common::kUnknownError;
}
Common::Serializer s(stream, nullptr);
s.setVersion(version);
return syncGame(s);
}
bool TotEngine::canLoadGameStateCurrently(Common::U32String *msg) {
return true;
}
bool TotEngine::canSaveGameStateCurrently(Common::U32String *msg) {
return _inGame && _saveAllowed;
}
SavedGame *TotEngine::saveGameToRegister() {
SavedGame *_savedGame = new SavedGame();
_savedGame->roomCode = _currentRoomData->code;
_savedGame->trajectoryLength = _trajectoryLength;
_savedGame->currentTrajectoryIndex = _currentTrajectoryIndex;
_savedGame->backpackObjectCode = _backpackObjectCode;
_savedGame->rightSfxVol = _sound->_rightSfxVol;
_savedGame->leftSfxVol = _sound->_leftSfxVol;
_savedGame->musicVolRight = _sound->_musicVolRight;
_savedGame->musicVolLeft = _sound->_musicVolLeft;
_savedGame->oldGridX = _oldGridX;
_savedGame->oldGridY = _oldGridY;
_savedGame->secAnimDepth = _secondaryAnimation.depth;
_savedGame->secAnimDir = _secondaryAnimation.dir;
_savedGame->secAnimX = _secondaryAnimation.posx;
_savedGame->secAnimY = _secondaryAnimation.posy;
_savedGame->secAnimIFrame = _iframe2;
_savedGame->currentZone = _currentZone;
_savedGame->targetZone = _targetZone;
_savedGame->oldTargetZone = _oldTargetZone;
_savedGame->inventoryPosition = _inventoryPosition;
_savedGame->actionCode = _actionCode;
_savedGame->oldActionCode = _oldActionCode;
_savedGame->steps = _trajectorySteps;
_savedGame->doorIndex = _doorIndex;
_savedGame->characterFacingDir = _charFacingDirection;
_savedGame->iframe = _iframe;
_savedGame->gamePart = _gamePart;
_savedGame->isSealRemoved = _isSealRemoved;
_savedGame->obtainedList1 = _obtainedList1;
_savedGame->obtainedList2 = _obtainedList2;
_savedGame->list1Complete = _list1Complete;
_savedGame->list2Complete = _list2Complete;
_savedGame->isVasePlaced = _isVasePlaced;
_savedGame->isScytheTaken = _isScytheTaken;
_savedGame->isTridentTaken = _isTridentTaken;
_savedGame->isPottersWheelDelivered = _isPottersWheelDelivered;
_savedGame->isMudDelivered = _isMudDelivered;
_savedGame->isGreenDevilDelivered = _isGreenDevilDelivered;
_savedGame->isRedDevilCaptured = _isRedDevilCaptured;
_savedGame->isPottersManualDelivered = _isPottersManualDelivered;
_savedGame->isCupboardOpen = _isCupboardOpen;
_savedGame->isChestOpen = _isChestOpen;
_savedGame->isTVOn = _isTVOn;
_savedGame->isTrapSet = _isTrapSet;
for (int i = 0; i < kInventoryIconCount; i++) {
_savedGame->mobj[i].bitmapIndex = _inventory[i].bitmapIndex;
_savedGame->mobj[i].code = _inventory[i].code;
_savedGame->mobj[i].objectName = _inventory[i].objectName;
}
_savedGame->element1 = _element1;
_savedGame->element2 = _element2;
_savedGame->characterPosX = _characterPosX;
_savedGame->characterPosY = _characterPosY;
_savedGame->xframe2 = _xframe2;
_savedGame->yframe2 = _yframe2;
_savedGame->oldInventoryObjectName = _oldInventoryObjectName;
_savedGame->objetomoinventoryObjectNamehila = _inventoryObjectName;
_savedGame->characterName = _characterName;
for (int i = 0; i < kRoutePointCount; i++) {
_savedGame->mainRoute[i].x = _mainRoute[i].x;
_savedGame->mainRoute[i].y = _mainRoute[i].y;
}
for (int i = 0; i < 300; i++) {
_savedGame->trajectory[i].x = _trajectory[i].x;
_savedGame->trajectory[i].y = _trajectory[i].y;
}
for (int i = 0; i < kCharacterCount; i++) {
_savedGame->firstTimeTopicA[i] = _firstTimeTopicA[i];
_savedGame->firstTimeTopicB[i] = _firstTimeTopicB[i];
_savedGame->firstTimeTopicC[i] = _firstTimeTopicC[i];
_savedGame->bookTopic[i] = _bookTopic[i];
_savedGame->mintTopic[i] = _mintTopic[i];
}
for (int i = 0; i < 5; i++) {
_savedGame->caves[i] = _caves[i];
_savedGame->firstList[i] = _firstList[i];
_savedGame->secondList[i] = _secondList[i];
}
for (int i = 0; i < 4; i++) {
_savedGame->niche[0][i] = _niche[0][i];
_savedGame->niche[1][i] = _niche[1][i];
}
return _savedGame;
}
void TotEngine::loadGame(SavedGame *game) {
clearAnimation();
clearScreenLayers();
_trajectoryLength = game->trajectoryLength;
_currentTrajectoryIndex = game->currentTrajectoryIndex;
_backpackObjectCode = game->backpackObjectCode;
_sound->_rightSfxVol = game->rightSfxVol;
_sound->_leftSfxVol = game->leftSfxVol;
_sound->_musicVolRight = game->musicVolRight;
_sound->_musicVolLeft = game->musicVolLeft;
_oldGridX = game->oldGridX;
_oldGridY = game->oldGridY;
_secondaryAnimation.depth = game->secAnimDepth;
_secondaryAnimation.dir = game->secAnimDir;
_secondaryAnimation.posx = game->secAnimX;
_secondaryAnimation.posy = game->secAnimY;
_iframe2 = game->secAnimIFrame;
_currentZone = game->currentZone;
_targetZone = game->targetZone;
_oldTargetZone = game->oldTargetZone;
_inventoryPosition = game->inventoryPosition;
_actionCode = game->actionCode;
_oldActionCode = game->oldActionCode;
_trajectorySteps = game->steps;
_doorIndex = game->doorIndex;
_charFacingDirection = game->characterFacingDir;
_iframe = game->iframe;
if (game->gamePart != _gamePart) {
_gamePart = game->gamePart;
for (int i = 0; i < kInventoryIconCount; i++) {
free(_inventoryIconBitmaps[i]);
}
loadInventory();
}
_isSealRemoved = game->isSealRemoved;
_obtainedList1 = game->obtainedList1;
_obtainedList2 = game->obtainedList2;
_list1Complete = game->list1Complete;
_list2Complete = game->list2Complete;
_isVasePlaced = game->isVasePlaced;
_isScytheTaken = game->isScytheTaken;
if (_cpCounter > 24)
showError(274);
_isTridentTaken = game->isTridentTaken;
_isPottersWheelDelivered = game->isPottersWheelDelivered;
_isMudDelivered = game->isMudDelivered;
_isGreenDevilDelivered = game->isGreenDevilDelivered;
_isRedDevilCaptured = game->isRedDevilCaptured;
_isPottersManualDelivered = game->isPottersManualDelivered;
_isCupboardOpen = game->isCupboardOpen;
_isChestOpen = game->isChestOpen;
_isTVOn = game->isTVOn;
_isTrapSet = game->isTrapSet;
for (int i = 0; i < kInventoryIconCount; i++) {
_inventory[i].bitmapIndex = game->mobj[i].bitmapIndex;
_inventory[i].code = game->mobj[i].code;
_inventory[i].objectName = game->mobj[i].objectName;
}
_element1 = game->element1;
_element2 = game->element2;
_characterPosX = game->characterPosX;
_characterPosY = game->characterPosY;
_xframe2 = game->xframe2;
_yframe2 = game->yframe2;
_oldInventoryObjectName = game->oldInventoryObjectName;
_inventoryObjectName = game->objetomoinventoryObjectNamehila;
_characterName = game->characterName;
for (int i = 0; i < kRoutePointCount; i++) {
_mainRoute[i].x = game->mainRoute[i].x;
_mainRoute[i].y = game->mainRoute[i].y;
}
for (int indiaux = 0; indiaux < 300; indiaux++) {
_trajectory[indiaux].x = game->trajectory[indiaux].x;
_trajectory[indiaux].y = game->trajectory[indiaux].y;
}
for (int i = 0; i < kCharacterCount; i++) {
_firstTimeTopicA[i] = game->firstTimeTopicA[i];
_firstTimeTopicB[i] = game->firstTimeTopicB[i];
_firstTimeTopicC[i] = game->firstTimeTopicC[i];
_bookTopic[i] = game->bookTopic[i];
_mintTopic[i] = game->mintTopic[i];
}
for (int i = 0; i < 5; i++) {
_caves[i] = game->caves[i];
_firstList[i] = game->firstList[i];
_secondList[i] = game->secondList[i];
}
for (int i = 0; i < 4; i++) {
_niche[0][i] = game->niche[0][i];
_niche[1][i] = game->niche[1][i];
}
_graphics->totalFadeOut(0);
_screen->clear();
_graphics->loadPaletteFromFile("DEFAULT");
loadScreenData(game->roomCode);
switch (_currentRoomData->code) {
case 2: {
if (_isTVOn)
_sound->autoPlayVoc("PARASITO", 355778, 20129);
else
loadTV();
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
} break;
case 4: {
_sound->loadVoc("GOTA", 140972, 1029);
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
} break;
case 5: {
_sound->setSfxVolume(_sound->_leftSfxVol, 0);
_sound->autoPlayVoc("CALDERA", 6433, 15386);
} break;
case 6: {
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
_sound->autoPlayVoc("CALDERA", 6433, 15386);
} break;
case 17: {
if (_bookTopic[0] == true && _currentRoomData->animationFlag)
disableSecondAnimation();
} break;
case 20: {
switch (_niche[0][_niche[0][3]]) {
case 0:
_currentRoomData->screenObjectIndex[9]->objectName = getObjectName(4);
break;
case 561:
_currentRoomData->screenObjectIndex[9]->objectName = getObjectName(5);
break;
case 563:
_currentRoomData->screenObjectIndex[9]->objectName = getObjectName(6);
break;
case 615:
_currentRoomData->screenObjectIndex[9]->objectName = getObjectName(7);
break;
}
} break;
case 23: {
_sound->autoPlayVoc("Fuente", 0, 0);
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
} break;
case 24: {
switch (_niche[1][_niche[1][3]]) {
case 0:
_currentRoomData->screenObjectIndex[8]->objectName = getObjectName(4);
break;
case 561:
_currentRoomData->screenObjectIndex[8]->objectName = getObjectName(5);
break;
case 615:
_currentRoomData->screenObjectIndex[8]->objectName = getObjectName(7);
break;
case 622:
_currentRoomData->screenObjectIndex[8]->objectName = getObjectName(8);
break;
case 623:
_currentRoomData->screenObjectIndex[8]->objectName = getObjectName(9);
break;
}
if (_isTrapSet) {
_currentRoomData->animationFlag = true;
loadAnimation(_currentRoomData->animationName);
_iframe2 = 0;
_currentSecondaryTrajectoryIndex = 1;
_currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x = 214 - 15;
_currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y = 115 - 42;
_secondaryAnimation.dir = _currentRoomData->secondaryAnimDirections[_currentSecondaryTrajectoryIndex - 1];
_secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x;
_secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y;
_secondaryAnimation.depth = 14;
for (int i = 0; i < _maxXGrid; i++)
for (int j = 0; j < _maxYGrid; j++) {
if (_maskGridSecondaryAnim[i][j] > 0)
_currentRoomData->walkAreasGrid[_oldposx + i][_oldposy + j] = _maskGridSecondaryAnim[i][j];
if (_maskMouseSecondaryAnim[i][j] > 0)
_currentRoomData->mouseGrid[_oldposx + i][_oldposy + j] = _maskMouseSecondaryAnim[i][j];
}
}
assembleScreen();
} break;
}
drawInventoryMask();
_inventoryPosition = 0;
drawInventory();
if (_isRedDevilCaptured == false && _currentRoomData->code == 24 && _isTrapSet == false)
runaroundRed();
_graphics->sceneTransition(false, _sceneBackground);
_saveAllowed = true;
}
const int kMaxSaveSlots = 100;
Common::String drawAndSelectSaves(int pageNumber, const Common::HashMap<int, SaveStateDescriptor> &saveMap, uint selectedSlot) {
g_engine->_mouse->hide();
const char *availableText = getHardcodedTextsByCurrentLanguage()[11];
ExtendedSavegameHeader header;
int selectedGame = selectedSlot + pageNumber * 6;
Common::String selectedGameDesc = "";
for (uint i = 0; i < 6; i++) {
int saveSlot = i + pageNumber * 6;
int color = saveSlot == selectedGame ? 255 : 253;
bar(60, 31 + (i * 15), 259, 39 + (i * 15), 251);
if (saveSlot >= kMaxSaveSlots) {
continue;
;
}
Common::String desc = "";
if (saveMap.contains(saveSlot)) {
desc = saveMap[saveSlot].getDescription();
if (saveSlot == selectedGame) {
selectedGameDesc = saveMap[saveSlot].getDescription();
}
}
if (desc.empty() == false) {
euroText(65, 29 + (i * 15), desc, color);
} else {
euroText(65, 29 + (i * 15), Common::String::format(availableText, saveSlot), color);
}
}
g_engine->_mouse->show();
return selectedGameDesc;
}
void TotEngine::originalSaveLoadScreen() {
uint oldMouseX, oldMouseY;
int selectedSlot = 1;
bool modified = false;
Common::String saveName = "";
bool exitSaveLoadMenu = false;
oldMouseX = _mouse->mouseX;
oldMouseY = _mouse->mouseY;
_mouse->hide();
uint menuBgSize = imagesize(20, 10, 300, 120);
byte *menuBgPointer = (byte *)malloc(menuBgSize);
_graphics->getImg(20, 10, 300, 120, menuBgPointer);
for (int i = 0; i < 6; i++) {
uint textY = i + 1;
buttonBorder((120 - (textY * 10)), (80 - (textY * 10)), (200 + (textY * 10)), (60 + (textY * 10)), 251, 251, 251, 251, 0);
}
drawMenu(2); // 220 x 110 at xmenu = 50;ymenu = 10;
// 50, 10, 270, 120
// Arrows are 20, 18
drawLeftArrow(20, 65);
line(20, 65, 39, 65, 255);
line(20, 65, 20, 80, 255);
line(40, 66, 40, 82, 249);
line(40, 82, 21, 82, 249);
drawRightArrow(280, 65);
line(280, 65, 299, 65, 255);
line(280, 65, 280, 80, 255);
line(300, 66, 300, 82, 249);
line(300, 82, 292, 82, 249);
if (!_saveAllowed) {
bar(61, 15, 122, 23, 253);
bar(201, 15, 259, 23, 253);
}
int pageNumber = 0;
SaveStateList listSaves = getMetaEngine()->listSaves(_targetName.c_str());
Common::HashMap<int, SaveStateDescriptor> saveMap;
// Iterate and populate
for (const SaveStateDescriptor &desc : listSaves) {
int slot = desc.getSaveSlot();
saveMap[slot] = desc;
}
saveName = drawAndSelectSaves(pageNumber, saveMap, selectedSlot);
if (_cpCounter2 > 17)
showError(274);
_mouse->mouseX = 150;
_mouse->mouseY = 60;
_mouse->mouseMaskIndex = 1;
_mouse->setMouseArea(Common::Rect(13, 13, 293, 105));
_mouse->warpMouse(1, 150, 60);
do {
bool mouseClicked = false;
bool keyPressed = false;
Common::Event lastKeyboardEvent = Common::Event();
do {
_chrono->updateChrono();
if (_chrono->_gameTick) {
_mouse->animateMouseIfNeeded();
}
_events->pollEvent();
if (_events->_leftMouseButton || _events->_rightMouseButton) {
mouseClicked = true;
} else if (_events->_keyPressed) {
keyPressed = true;
lastKeyboardEvent = _events->_lastKeyEvent;
}
_screen->update();
g_system->delayMillis(10);
} while (!keyPressed && !mouseClicked && !shouldQuit());
if (mouseClicked) {
if (_mouse->mouseX > 13 && _mouse->mouseX < 33 && _mouse->mouseY >= 58 && _mouse->mouseY <= 73) { // Left arrow
if (pageNumber > 0)
pageNumber--;
else
_sound->beep(100, 300);
saveName = drawAndSelectSaves(pageNumber, saveMap, selectedSlot);
} else if (_mouse->mouseX > 273 && _mouse->mouseX < 293 && _mouse->mouseY >= 58 && _mouse->mouseY <= 73) { // Right arrow
if (pageNumber < kMaxSaveSlots / 6)
pageNumber++;
else
_sound->beep(100, 300);
saveName = drawAndSelectSaves(pageNumber, saveMap, selectedSlot);
} else if (_mouse->mouseY >= 13 && _mouse->mouseY <= 16) {
if (_mouse->mouseX >= 54 && _mouse->mouseX <= 124) { // Save
if (selectedSlot > 0 && _saveAllowed && saveName != "") {
saveGameState(selectedSlot + pageNumber * 6, saveName, false);
_graphics->putImg(20, 10, menuBgPointer);
exitSaveLoadMenu = true;
selectedSlot = -1;
} else {
_sound->beep(100, 300);
}
} else if (_mouse->mouseX >= 130 && _mouse->mouseX <= 194) {
if (selectedSlot >= 0 && !modified) { // Load
if (selectedSlot < (int)listSaves.size()) {
_mouse->hide();
_graphics->putImg(20, 10, menuBgPointer);
free(menuBgPointer);
if (_saveAllowed) {
clearAnimation();
clearScreenLayers();
}
loadGameState(selectedSlot + pageNumber * 6);
_mouse->mouseX = oldMouseX;
_mouse->mouseY = oldMouseY;
_mouse->show();
_mouse->setMouseArea(Common::Rect(0, 0, 305, 185));
exitSaveLoadMenu = true;
selectedSlot = -1;
return;
} else {
_sound->beep(100, 300);
}
} else {
_sound->beep(100, 300);
saveName = drawAndSelectSaves(pageNumber, saveMap, selectedSlot);
_mouse->show();
}
} else if (_mouse->mouseClickX >= 200 && _mouse->mouseClickX <= 250) { // Exit
if (_inGame && _saveAllowed) {
_graphics->putImg(20, 10, menuBgPointer);
exitSaveLoadMenu = true;
selectedSlot = -1;
} else {
_sound->beep(100, 300);
}
}
} else {
if (_mouse->mouseClickY >= 24 && _mouse->mouseClickY <= 32) {
if (0 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 0;
modified = false;
}
} else if (_mouse->mouseClickY >= 39 && _mouse->mouseClickY <= 47) {
if (1 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 1;
modified = false;
}
} else if (_mouse->mouseClickY >= 54 && _mouse->mouseClickY <= 62) {
if (2 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 2;
modified = false;
}
} else if (_mouse->mouseClickY >= 69 && _mouse->mouseClickY <= 77) {
if (3 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 3;
modified = false;
}
} else if (_mouse->mouseClickY >= 84 && _mouse->mouseClickY <= 92) {
if (4 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 4;
modified = false;
}
} else if (_mouse->mouseClickY >= 99 && _mouse->mouseClickY <= 107) {
if (5 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 5;
modified = false;
}
}
saveName = drawAndSelectSaves(pageNumber, saveMap, selectedSlot);
}
}
if (keyPressed && _saveAllowed) {
_mouse->hide();
byte ytext = 29 + (selectedSlot * 15);
readAlphaGraphSmall(saveName, 30, 65, ytext, 251, 254, lastKeyboardEvent);
modified = true;
_mouse->show();
keyPressed = false;
}
} while (!exitSaveLoadMenu && !shouldQuit());
_mouse->mouseX = oldMouseX;
_mouse->mouseY = oldMouseY;
_mouse->warpMouse(_mouse->mouseMaskIndex, _mouse->mouseX, _mouse->mouseY);
free(menuBgPointer);
_mouse->setMouseArea(Common::Rect(0, 0, 305, 185));
}
} // End of namespace Tot

211
engines/tot/sound.cpp Normal file
View File

@@ -0,0 +1,211 @@
/* 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 "audio/decoders/voc.h"
#include "audio/mixer.h"
#include "audio/softsynth/pcspk.h"
#include "common/config-manager.h"
#include "tot/sound.h"
#include "tot/tot.h"
#include "tot/util.h"
namespace Tot {
SoundManager::SoundManager(Audio::Mixer *mixer) : _mixer(mixer) {
_rightSfxVol = 6;
_leftSfxVol = 6;
_musicVolRight = 3;
_musicVolLeft = 3;
_midiPlayer = new MidiPlayer();
_speaker = new Audio::PCSpeaker();
}
SoundManager::~SoundManager() {
if (_midiPlayer)
delete _midiPlayer;
delete _lastSrcStream;
delete _audioStream;
delete _speaker;
}
void SoundManager::init() {
_rightSfxVol = 6;
_leftSfxVol = 6;
_musicVolRight = 3;
_musicVolLeft = 3;
_speaker->init();
_midiPlayer->open();
setMidiVolume(3, 3);
//playMidi("SILENT", false);
setSfxVolume(6, 6);
}
void SoundManager::syncSoundSettings() {
_midiPlayer->syncSoundSettings();
}
void SoundManager::loadVoc(Common::String vocFile, int32 startPos, int16 size) {
Common::File vocResource;
if(_lastSrcStream) {
delete _lastSrcStream;
_lastSrcStream = nullptr;
}
if (size == 0) {
if (!vocResource.open(Common::Path(vocFile + ".VOC"))) {
showError(266);
}
_lastSrcStream = vocResource.readStream((uint32)vocResource.size());
} else {
if (!vocResource.open("EFECTOS.DAT")) {
showError(266);
}
vocResource.seek(startPos);
_lastSrcStream = vocResource.readStream((uint32)size);
}
if(_audioStream) {
delete _audioStream;
_audioStream = nullptr;
}
_audioStream = Audio::makeVOCStream(_lastSrcStream, Audio::FLAG_UNSIGNED, DisposeAfterUse::NO);
}
void SoundManager::autoPlayVoc(Common::String vocFile, int32 startPos, int16 vocSize) {
loadVoc(vocFile, startPos, vocSize);
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, Audio::makeLoopingAudioStream(_audioStream, 0), kSfxId, 255U, 0, DisposeAfterUse::NO);
}
void SoundManager::playVoc() {
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, _audioStream, kSfxId, 255U, 0, DisposeAfterUse::NO);
_lastSrcStream->seek(0);
_audioStream->rewind();
}
void SoundManager::playVoc(Common::String vocFile, int32 startPos, uint vocSize) {
stopVoc();
loadVoc(vocFile, startPos, vocSize);
playVoc();
}
void SoundManager::stopVoc() {
_mixer->stopHandle(_soundHandle);
}
void SoundManager::waitForSoundEnd() {
do {
g_engine->_events->pollEvent();
g_engine->_chrono->updateChrono();
g_engine->_screen->update();
g_system->delayMillis(10);
} while (g_engine->_sound->isVocPlaying());
}
bool SoundManager::isVocPlaying() {
return _mixer->isSoundIDActive(kSfxId);
}
void SoundManager::playMidi(Common::String fileName, bool loop) {
Common::File musicFile;
musicFile.open(Common::Path(fileName + ".MUS"));
if (!musicFile.isOpen()) {
showError(267);
return;
}
byte *curMidi = (byte *)malloc(musicFile.size());
musicFile.read(curMidi, musicFile.size());
playMidi(curMidi, musicFile.size(), loop);
musicFile.close();
free(curMidi);
}
void SoundManager::playMidi(byte *data, int size, bool loop) {
Common::MemoryReadStream stream = Common::MemoryReadStream(data, size);
_midiPlayer->load(&stream, size);
_midiPlayer->setLoop(loop);
_midiPlayer->play(0);
}
void SoundManager::toggleMusic() {
}
void SoundManager::beep(int32 frequency, int32 ms) {
_speaker->stop();
_speaker->play(Audio::PCSpeaker::kWaveFormSquare, frequency, ms);
}
void SoundManager::setSfxVolume(byte voll, byte volr) {
if (voll == volr) {
int volume = (voll) / (float)7 * 255;
setSfxVolume(volume);
setSfxBalance(true, true);
} else {
if (voll == 0) {
setSfxBalance(false, true);
} else {
setSfxBalance(true, false);
}
}
}
void SoundManager::setMidiVolume(byte voll, byte volr) {
if (voll != _musicVolLeft || volr != _musicVolRight) {
_musicVolLeft = voll;
_musicVolRight = volr;
setMusicVolume(voll == 0 ? 0 : 255);
}
}
void SoundManager::fadeOutMusic() {
_midiPlayer->startFadeOut();
while (_midiPlayer->isFading()) {
delay(10);
}
}
void SoundManager::fadeInMusic() {
_midiPlayer->startFadeIn();
while (_midiPlayer->isFading()) {
delay(10);
}
}
void SoundManager::setMasterVolume(byte voll, byte volr) {
}
void SoundManager::setSfxVolume(byte volume) {
_mixer->setChannelVolume(_soundHandle, volume);
}
void SoundManager::setSfxBalance(bool left, bool right) {
int balance = left ? -127 : 127;
_mixer->setChannelBalance(_soundHandle, balance);
}
void SoundManager::setMusicVolume(byte volume) {
_midiPlayer->setSourceVolume(volume);
}
} // End of namespace Tot

78
engines/tot/sound.h Normal file
View File

@@ -0,0 +1,78 @@
/* 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/>.
*
*/
#ifndef TOT_SOUND_H
#define TOT_SOUND_H
#include "audio/decoders/raw.h"
#include "audio/softsynth/pcspk.h"
#include "audio/mixer.h"
#include "common/file.h"
#include "tot/midi.h"
namespace Tot {
const int kSfxId = 1;
class SoundManager {
public:
SoundManager(Audio::Mixer *mixer);
~SoundManager();
void init();
void syncSoundSettings();
void loadVoc(Common::String vocFile, int32 startPos, int16 vocSize);
void autoPlayVoc(Common::String vocFile, int32 startPos, int16 vocSize);
void playVoc(Common::String vocFile, int32 startPos, uint vocSize);
void playVoc();
void stopVoc();
bool isVocPlaying();
void playMidi(Common::String fileName, bool loop);
void playMidi(byte *data, int size, bool loop);
void toggleMusic();
void beep(int32 frequency, int32 ms);
void waitForSoundEnd();
// Set game logic volume levels
void setSfxVolume(byte leftVol, byte rightVol);
void setMidiVolume(byte leftVol, byte rightVol);
void fadeOutMusic();
void fadeInMusic();
void setMasterVolume(byte leftVol, byte rightVol);
void setSfxBalance(bool left, bool right);
// Game logic volume settings
uint _rightSfxVol, _leftSfxVol;
uint _musicVolRight, _musicVolLeft;
private:
// Apply game logic volume levels
void setSfxVolume(byte volume);
void setMusicVolume(byte volume);
Audio::SoundHandle _soundHandle;
Audio::Mixer *_mixer;
MidiPlayer *_midiPlayer;
Audio::PCSpeaker *_speaker;
Common::SeekableReadStream *_lastSrcStream = nullptr;
Audio::SeekableAudioStream *_audioStream = nullptr;
};
} // End of namespace Tot
#endif

1298
engines/tot/statics.h Normal file

File diff suppressed because it is too large Load Diff

1333
engines/tot/tot.cpp Normal file

File diff suppressed because it is too large Load Diff

531
engines/tot/tot.h Normal file
View File

@@ -0,0 +1,531 @@
/* 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/>.
*
*/
#ifndef TOT_H
#define TOT_H
#include "common/error.h"
#include "common/events.h"
#include "common/fs.h"
#include "common/hash-str.h"
#include "common/memstream.h"
#include "common/random.h"
#include "common/scummsys.h"
#include "common/serializer.h"
#include "common/system.h"
#include "common/util.h"
#include "engines/engine.h"
#include "engines/savestate.h"
#include "graphics/screen.h"
#include "tot/chrono.h"
#include "tot/detection.h"
#include "tot/events.h"
#include "tot/graphics.h"
#include "tot/mouse.h"
#include "tot/sound.h"
#include "tot/types.h"
namespace Tot {
struct TotGameDescription;
enum TotAction {
kActionEscape,
kActionVolume,
kActionSaveLoad,
kActionTalk,
kActionPickup,
kActionLookAt,
kActionUse,
kActionOpen,
kActionClose,
kActionYes,
kActionNo
};
class TotEngine : public Engine {
private:
Common::RandomSource _randomSource;
void handleEvent(Common::Event e);
/**
* Uses a serializer to allow implementing savegame
* loading and saving using a single method
*/
Common::Error syncGame(Common::Serializer &s);
int engineStart();
int startGame();
void newGame();
void resumeGame();
void changeRoom();
void loadScrollData(uint roomCode, bool rightScroll, uint horizontalPos, int scrollCorrection);
void drawText(uint number);
void displayLoading();
void runaroundRed();
void sprites(bool drawCharacter);
SavedGame *saveGameToRegister();
void originalSaveLoadScreen();
void loadGame(SavedGame *game);
RoomFileRegister *readScreenDataFile(Common::SeekableReadStream *screenDataFile);
void lookAtObject(byte objectNumber);
void useInventoryObjectWithInventoryObject(int16 obj1, int16 obj2);
void pickupScreenObject();
void useScreenObject();
void openScreenObject();
void closeScreenObject();
void action();
void handleAction(byte invPos);
void loadInventory();
void obtainName(Common::String &playerName);
void calculateRoute(byte zone1, byte zone2, bool extraCorrection = false, bool zonavedada = false);
void wcScene();
void advanceAnimations(bool barredZone, bool animateMouse);
void updateSecondaryAnimationDepth();
void updateMainCharacterDepth();
void actionLineText(const Common::String &actionLine);
void initializeObjectFile();
void saveObjectsData(ScreenObject *object, Common::SeekableWriteStream *out);
void scrollLeft(uint horizontalPos);
void scrollRight(uint horizontalPos);
TextEntry readTextRegister(uint numRegister);
void readConversationFile();
void adjustKey();
void adjustKey2();
void animateBat();
void updateVideo();
void nicheAnimation(byte nicheDir, int32 bitmap);
void replaceBackpack(byte obj1, uint obj2);
void dropObjectInScreen(ScreenObject *replacementObject);
void calculateTrajectory(uint finalX, uint finalY);
void animatedSequence(uint numSequence);
void initScreenPointers();
void loadAnimation(const Common::String &animation);
void loadCharAnimation();
void animateGive(uint dir, uint height);
void animatePickup1(uint dir, uint height);
void animatePickup2(uint dir, uint height);
void animateOpen2(uint dir, uint height);
void loadTV();
void loadScreen();
void loadScreenLayerWithDepth(uint coordx, uint coordy, uint bitmapSize, int32 bitmapIndex, uint depth);
void loadScreenLayer(uint coordx, uint coordy, uint picSize, int32 pic, uint prof);
void readBitmap(int32 bitmapOffset, byte *bitmap, uint bitmapSize, uint errorCode);
void updateAltScreen(byte altScreenNumber);
void freeInventory();
void updateInventory(byte index);
void updateObject(uint filePos);
void readObject(Common::SeekableReadStream *stream, uint objPos, ScreenObject *thisRegObj);
void saveObject(ScreenObject *object, Common::SeekableWriteStream *stream);
void saveItemRegister();
void saveTemporaryGame();
void drawLookAtItem(RoomObjectListEntry obj);
void putIcon(uint posX, uint posY, uint iconNumber);
void drawInventory(byte direction, byte limit);
void generateDiploma(Common::String &photoName);
void credits();
void checkMouseGrid();
void introduction();
void firstIntroduction();
void readAlphaGraph(Common::String &data, int length, int x, int y, byte barColor);
void readAlphaGraphSmall(Common::String &data, int length, int x, int y, byte barColor, byte textColor, Common::Event startEvent);
void displayObjectDescription(const Common::String &text);
void copyProtection();
void initialLogo();
void mainMenu(bool fade);
void exitToDOS();
void soundControls();
void sacrificeScene();
void ending();
void loadBat();
void loadDevil();
void assembleCompleteBackground(byte *image, uint coordx, uint coordy);
void assembleScreen(bool scroll = false);
void disableSecondAnimation();
void clearGame();
// vars
void initVars();
void resetGameState();
void clearVars();
void processEvents(bool &escapePressed);
void oldProcessEvents(bool &escapePressed);
protected:
// Engine APIs
Common::Error run() override;
void syncSoundSettings() override;
public:
Graphics::Screen *_screen = nullptr;
GraphicsManager *_graphics = nullptr;
SoundManager *_sound = nullptr;
MouseManager *_mouse = nullptr;
ChronoManager *_chrono = nullptr;
Tot::TotEventManager *_events = nullptr;
const ADGameDescription *_gameDescription;
bool _showMouseGrid = false;
bool _showScreenGrid = false;
bool _showGameGrid = false;
bool _drawObjectAreas = false;
Common::Language _lang = Common::ES_ESP;
Common::MemorySeekableReadWriteStream *_conversationData = nullptr;
Common::MemorySeekableReadWriteStream *_rooms = nullptr;
Common::MemorySeekableReadWriteStream *_sceneObjectsData = nullptr;
bool _roomChange = false;
bool _isTVOn = false;
bool _isVasePlaced = false;
bool _isScytheTaken = false;
bool _isTridentTaken = false;
bool _isPottersWheelDelivered = false;
bool _isMudDelivered = false;
bool _isGreenDevilDelivered = false;
bool _isRedDevilCaptured = false;
bool _isPottersManualDelivered = false;
bool _isCupboardOpen = false;
bool _isChestOpen = false;
bool _isTrapSet = false;
bool _isPeterCoughing = false;
bool _isSealRemoved = false;
bool _inGame = false;
bool _firstTimeDone = false; // Flag for first time run of the game.
bool _isIntroSeen = false;
bool _shouldQuitGame = false;
bool _startNewGame = false; // Flag to initialize game
bool _continueGame = false; // Flag to resume game
bool _isSavingDisabled = false;
bool _isDrawingEnabled = false; // true if sprites should be drawn
bool _isSecondaryAnimationEnabled = false; // Whether room has secondary animation
InventoryEntry _inventory[kInventoryIconCount]; // These are the icons currnetly in the inventory
/**
* Keeps an array of all inventory icon bitmaps
*/
byte *_inventoryIconBitmaps[kInventoryIconCount] = { nullptr };
/**
* Position within inventory
*/
byte _inventoryPosition = 0;
/**
* Animation sequences
*/
CharacterAnim _mainCharAnimation;
uint _mainCharFrameSize = 0;
SecondaryAnim _secondaryAnimation;
uint _secondaryAnimFrameSize = 0;
/**
* Currently selected action.
*/
byte _actionCode = 0;
/**
* Previously selected action.
*/
byte _oldActionCode = 0;
/**
* Number of trajectory changes
*/
byte _trajectorySteps = 0;
/**
* index of currently selected door.
*/
byte _doorIndex = 0;
/**
* 1 first part, 2 second part
*/
byte _gamePart = 1;
/**
* Number of frames of secondary animation
*/
byte _secondaryAnimationFrameCount = 0;
/**
* Number of directions of the secondary animation
*/
byte _secondaryAnimDirCount = 0;
/**
* Data protection control
*/
byte _cpCounter = 0, _cpCounter2 = 0;
/**
* Coordinates of target step
*/
byte _destinationX = 0, _destinationY = 0;
/**
* Current character facing direction
* 0: upwards
* 1: right
* 2: downwards
* 3: left
*/
byte _charFacingDirection = 0;
/**
* Width and height of secondary animation
*/
uint _secondaryAnimWidth = 0, _secondaryAnimHeight = 0;
/**
* Code of selected object in the backpack
*/
uint _backpackObjectCode = 0;
/**
* Auxiliary vars for grid update
*/
uint _oldposx = 0, _oldposy = 0;
/**
* Amplitude of movement
*/
int _element1 = 0, _element2 = 0;
/**
* Current position of the main character
*/
uint16 _characterPosX = 0, _characterPosY = 0;
/**
* Target position of the main character?
*/
int _xframe2 = 0, _yframe2 = 0;
/**
* Text map
*/
Common::File _verbFile;
/**
* Auxiliary vars with current inventory object name.
*/
Common::String _oldInventoryObjectName, _inventoryObjectName;
/**
* Name of player
*/
Common::String _characterName = "";
Common::String _decryptionKey;
/**
* State of the niches in part 2
*/
uint _niche[2][4];
RoomFileRegister *_currentRoomData = nullptr;
ScreenObject *_curObject = nullptr; // Currently selected object in the screen
/**
* New movement to execute.
*/
Route _mainRoute;
/**
* Matrix of positions for a trajectory between two points
*/
Common::Point _trajectory[300];
/**
* Longitude of the trajectory matrix.
*/
uint _trajectoryLength = 0;
/**
* Position within the trajectory matrix
*/
uint _currentTrajectoryIndex = 0;
/**
* Position within the trajectory matrix for secondary animation
*/
uint _currentSecondaryTrajectoryIndex = 0;
/**
* Screen areas
*/
byte _currentZone = 0, _targetZone = 0, _oldTargetZone = 0;
/**
* Amplitude of grid slices
*/
byte _maxXGrid = 0, _maxYGrid = 0;
/**
* capture of movement grid of secondary animation
*/
byte _movementGridForSecondaryAnim[10][10];
/**
* capture of mouse grid of secondary animation
*/
byte _mouseGridForSecondaryAnim[10][10];
/**
* movement mask for grid of secondary animation
*/
byte _maskGridSecondaryAnim[10][10];
/**
* mouse mask for grid of secondary animation
*/
byte _maskMouseSecondaryAnim[10][10];
bool _list1Complete = false,
_list2Complete = false,
_obtainedList1 = false, // whether we've been given list 1
_obtainedList2 = false; // whether we've been given list 2
/** Conversation topic unlocks */
bool _firstTimeTopicA[kCharacterCount] = { false },
_firstTimeTopicB[kCharacterCount] = { false },
_firstTimeTopicC[kCharacterCount] = { false },
_bookTopic[kCharacterCount] = { false },
_mintTopic[kCharacterCount] = { false };
bool _caves[5] = { false };
/**
* First and second lists of objects to retrieve in the game
*/
uint16 _firstList[5] = { 0 }, _secondList[5] = { 0 };
int32 _screenSize = 65520;
/**
* Frame number for the animations
*/
byte _iframe = 0, _iframe2 = 0;
/**
* Depth of screenobjects
*/
ObjectInfo _depthMap[kNumScreenOverlays];
/**
* Bitmaps of screenobjects
*/
byte *_screenLayers[kNumScreenOverlays] = { nullptr };
/**
* Current frame of main character
*/
byte *_curCharacterAnimationFrame = nullptr;
/**
* Current frame of secondary animation
*/
byte *_curSecondaryAnimationFrame = nullptr;
/**
* Pointer storing the screen as it displays on the game
*/
byte *_sceneBackground = nullptr;
/**
* Dirty patch of screen to repaint on every frame
*/
byte *_characterDirtyRect = nullptr;
/**
* Stores a copy of the background bitmap
*/
byte *_backgroundCopy = nullptr;
uint _currentRoomNumber = 0;
bool _isLoadingFromLauncher = false;
bool _saveAllowed = false;
/**
* Previous positions of the mouse within the screen grid
*/
uint _oldGridX = 0, _oldGridY = 0;
uint _curDepth = 0;
/**
* Point of origin of the area surrounding the main character.
* Calculated using the position of the character.
*/
uint16 _dirtyMainSpriteX = 0, _dirtyMainSpriteY = 0;
/**
* End point of origin of the area surrounding the main character.
* Calculated using the position of the character + dimension
*/
uint _dirtyMainSpriteX2 = 0, _dirtyMainSpriteY2 = 0;
byte *_spriteBackground = nullptr;
public:
TotEngine(OSystem *syst, const ADGameDescription *gameDesc);
~TotEngine() override;
uint32 getFeatures() const;
/**
* Returns the game Id
*/
Common::String getGameId() const;
/**
* Gets a random number
*/
uint32 getRandomNumber(uint maxNum) {
return _randomSource.getRandomNumber(maxNum);
}
bool hasFeature(EngineFeature f) const override {
return (f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime) ||
(f == kSupportsReturnToLauncher);
};
void drawFontSurface(Graphics::BgiFont &litt);
// Save/Load
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
void loadScreenData(uint screenNumber);
void clearScreenLayers();
void clearAnimation();
void buttonBorder(uint x1, uint y1, uint x2, uint y2, byte color1, byte color2, byte color3, byte color4, byte color5);
void drawMenu(byte menuNumber);
void drawLeftArrow(uint x, uint y);
void drawRightArrow(uint x, uint y);
void readTextFile();
void loadAnimationForDirection(Common::SeekableReadStream *stream, int direction);
void sayLine(uint textRef, byte textColor, byte shadowColor, uint &responseNumber, bool isWithinConversation);
void goToObject(byte zone1, byte zone2);
void readObject(uint objPos);
TextEntry readTextRegister();
void drawInventory();
void drawInventoryMask();
void setRoomTrajectories(int height, int width, TRAJECTORIES_OP op, bool fixGrids = true);
void saveRoomData(RoomFileRegister *room, Common::SeekableWriteStream *stream);
//vars
void initializeScreenFile();
};
extern TotEngine *g_engine;
#define SHOULD_QUIT ::Tot::g_engine->shouldQuit()
} // End of namespace Tot
#endif // TOT_H

290
engines/tot/types.h Normal file
View File

@@ -0,0 +1,290 @@
/* 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/>.
*
*/
#ifndef TOT_TYPES_H
#define TOT_TYPES_H
#include "common/scummsys.h"
namespace Tot {
const int kVerbRegSize = 263;
const int kRoomRegSize = 10856;
const int kItemRegSize = 279;
const int kList1Index = 19;
const int kList2Index = 20;
const int kList1code = 149;
const int kList2code = 150;
/**
* Num of icons in the inventory
*/
const int kInventoryIconCount = 34;
const int kNumScreenOverlays = 15;
/**
* Num of depth levels
*/
const int kDepthLevelCount = 15;
/**
* Num of frames of the main character in a single direction
*/
const int kWalkFrameCount = 16;
/**
* Num of frames in the secondary animation
*/
const int kSecAnimationFrameCount = 50;
/**
* X factor of the screen grid
* This results in 320/8 = 40 quadrants.
*/
const int kXGridCount = 8;
/**
* Y factor of the screen grid
* This results in 140/5 = 28 quadrants.
*/
const int kYGridCount = 5;
/**
* Y offset of feet within character sprite (for adjustment of path finding)
*/
const int kCharacerCorrectionY = 49;
/**
* X offset of feet within character sprite (for adjustment of path finding)
*/
const int kCharacterCorrectionX = 14;
const int kObjectNameLength = 20;
const int kCharacterCount = 9;
/**
* Size of an inventory icon (39x26)
*/
const int kInventoryIconSize = 1018;
/**
* Number of points in a
*/
const int kRoutePointCount = 7;
/**
* Trajectory changes
*/
typedef Common::Point Route[kRoutePointCount];
enum TRAJECTORIES_OP {
// Subtracts the animation dimensions to the trajectory coordinates to adjust movement
SET_WITH_ANIM = false,
// Adds the animation dimensions to the trajectory coordinates to restore
RESTORE = true
};
struct ObjectInfo {
uint16 code = 0, posx = 0, posy = 0, posx2 = 0, posy2 = 0;
};
struct CharacterAnim {
uint16 depth = 0;
byte *bitmap[4][kWalkFrameCount + 30]; // 30 = 3 actions * 10 frames each
};
struct SecondaryAnim {
uint16 depth = 0, dir = 1, posx = 0, posy = 0;
byte *bitmap[4][kSecAnimationFrameCount];
};
struct InventoryEntry {
int16 bitmapIndex = -1;
int16 code = -1;
Common::String objectName = "";
};
/**
* Hypertext struct
*/
struct TextEntry {
Common::String text; // string
bool continued = false; // true if the next entry is a continuation of this one
uint16 response = 0; // entry number of reply
int32 pointer = 0;
};
struct ScreenObject {
/**
* registry number
*/
uint16 code;
byte height; /* 0 top 1 middle 2 bottom, determines character anim on use/pick*/
Common::String name; /* name for mouseover*/
uint16 lookAtTextRef; /* Text reference when looking at object */
uint16 beforeUseTextRef; /* Text reference before using object */
uint16 afterUseTextRef; /* Text reference after using object */
uint16 pickTextRef; /* Text reference when picking up object */
uint16 useTextRef; /* Text reference when using object */
byte speaking; /* whether the object talks or not */
bool openable; /* true if it can be opened */
bool closeable; /* true if it can be closed*/
byte used[8]; /* flags (one per original savegame) on whether the object has been used */
bool pickupable;
uint16 useWith,
replaceWith; /* Code of the object it should be replaced with in case a replacement is due.*/
byte depth;
uint32 bitmapPointer; /* reference to the objects bitmap in the bitmap resource file */
uint16 bitmapSize;
uint32 rotatingObjectAnimation; /* Pointer to the FLC animation of the rotatin object */
uint16 rotatingObjectPalette; /* Pointer to the palette of the above FLC animation*/
uint16 dropOverlayX, dropOverlayY; /* coords when the object requires placing an overlay on the screen */
uint32 dropOverlay; /* pointer to such overlay */
uint16 dropOverlaySize;
uint16 objectIconBitmap; /* Icon on the inventory */
byte xgrid1, ygrid1, xgrid2, ygrid2; /* position of patches below*/
byte walkAreasPatch[10][10]; /* patch on the scene's walking area (e.g. object prevents character from walking */
byte mouseGridPatch[10][10]; /* patch on the mouse grid area (i.e. selectable area of the object */
};
struct DoorRegistry {
uint16 nextScene,
exitPosX,
exitPosY;
byte openclosed,
doorcode;
};
struct RoomObjectListEntry {
uint16 fileIndex;
Common::String objectName;
};
struct RoomBitmapRegister {
uint32 bitmapPointer;
uint16 bitmapSize;
uint16 coordx, coordy, depth;
};
struct RoomFileRegister {
uint16 code;
uint32 roomImagePointer;
uint16 roomImageSize;
byte walkAreasGrid[40][28]; /* movement grid */
byte mouseGrid[40][28]; /* mousegrid with index to indexadoObjetos */
/**
* This is a preset matrix of trajectories from different areas of the game.action
* Each room is divided into a number of areas according to the screen grid [rejapantalla].action
*
* A given coordinate in the game (x,y) is mapped into a grid position by dividing the x with factorx (8)
* and the y coordinate by factory (5). With each room being 320x140 this results in
* 40 horizontal divisions and 28 vertical divisions which matches the [rejapantalla] matrix.action
*
* When obtaining the grid position a given (x,y) coordinate matches to, [rejapantalla] returns an
* area number.action
*
* trayectorias then has a precalculated route from each possible combination of two areas in the game.
* pixel by pixel translation within the area is done by bresenham algorithm in the trajectory function.
*/
Common::Point trajectories[9][30][5];
DoorRegistry doors[5]; /* doors in the room */
RoomBitmapRegister screenLayers[15];
RoomObjectListEntry *screenObjectIndex[51] = { nullptr }; /* includes name of objects for mouseover + index to object file*/
bool animationFlag; /* true if there is a secondary animation */
Common::String animationName; /* name of the secondary animation, 8 chars*/
bool paletteAnimationFlag; /* true if there exist palette animation */
uint16 palettePointer; /* points to the screen palette */
Common::Point secondaryAnimTrajectory[300]; /* trajectory of the secondary animation */
uint16 secondaryAnimDirections[300]; /* directions of the secondary trajectory. Pos 300 reflects object code. */
uint16 secondaryTrajectoryLength; /* length of the trajectory of the secondary animation */
~RoomFileRegister() {
for (int i = 0; i < 51; i++) {
delete screenObjectIndex[i];
screenObjectIndex[i] = nullptr;
}
}
};
struct SavedGame {
uint roomCode,
trajectoryLength,
currentTrajectoryIndex,
backpackObjectCode,
rightSfxVol,
leftSfxVol,
musicVolRight,
musicVolLeft,
oldGridX,
oldGridY,
secAnimDepth,
secAnimDir,
secAnimX,
secAnimY,
secAnimIFrame;
byte currentZone,
targetZone,
oldTargetZone,
inventoryPosition,
actionCode,
oldActionCode,
steps,
doorIndex,
characterFacingDir,
iframe,
gamePart;
bool isSealRemoved,
isPottersManualDelivered,
obtainedList1,
obtainedList2,
list1Complete,
list2Complete,
isVasePlaced,
isScytheTaken,
isTridentTaken,
isPottersWheelDelivered,
isMudDelivered,
isGreenDevilDelivered,
isCupboardOpen,
isChestOpen,
isTVOn,
isTrapSet,
isRedDevilCaptured;
InventoryEntry mobj[kInventoryIconCount];
int element1,
element2,
characterPosX,
characterPosY,
xframe2,
yframe2;
Common::String oldInventoryObjectName,
objetomoinventoryObjectNamehila;
Common::String characterName;
Route mainRoute;
uint16 firstList[5], secondList[5];
Common::Point trajectory[300];
// Conversation topic unlocks
bool firstTimeTopicA[kCharacterCount],
firstTimeTopicB[kCharacterCount],
firstTimeTopicC[kCharacterCount],
bookTopic[kCharacterCount],
mintTopic[kCharacterCount];
bool caves[5];
uint niche[2][4];
};
typedef byte Palette[768];
} // End of namespace Tot
#endif

524
engines/tot/util.cpp Normal file
View File

@@ -0,0 +1,524 @@
/* 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/textconsole.h"
#include "graphics/paletteman.h"
#include "tot/statics.h"
#include "tot/tot.h"
#include "tot/util.h"
#include "util.h"
namespace Tot {
// Enforces a small delay when text reveal is supposed to happen
const int kEnforcedTextAnimDelay = 0;
void showError(int code) {
const char *const *messages = (isLanguageSpanish()) ? errorMessages[0] : errorMessages[1];
switch (code) {
case 1:
error("%s", messages[0]);
break;
case 2:
error("%s", messages[1]);
break;
case 3:
error("%s", messages[2]);
break;
case 4:
error("%s", messages[3]);
break;
case 5:
error("%s", messages[4]);
break;
case 6:
error("%s", messages[5]);
break;
case 12:
error("%s", messages[6]);
break;
case 13:
case 14:
error(messages[7], code);
break;
case 15:
error("%s", messages[8]);
break;
case 16:
error("%s", messages[9]);
break;
case 17:
error("%s", messages[10]);
break;
case 18:
error("%s", messages[11]);
break;
case 100:
error("%s", messages[12]);
break;
case 101:
error("%s", messages[13]);
break;
case 102:
error("%s", messages[14]);
break;
case 103:
error("%s", messages[15]);
break;
case 104:
error("%s", messages[16]);
break;
case 105:
error("%s", messages[17]);
break;
case 106:
error("%s", messages[18]);
break;
case 150:
error("%s", messages[19]);
break;
case 151:
error("%s", messages[20]);
break;
case 152:
error("%s", messages[21]);
break;
case 153:
error("%s", messages[22]);
break;
case 154:
error("%s", messages[23]);
break;
case 155:
error(messages[24], code);
break;
case 156:
error("%s", messages[25]);
break;
case 157:
error("%s", messages[26]);
break;
case 158:
error("%s", messages[27]);
break;
case 159:
error("%s", messages[28]);
break;
case 160:
error("%s", messages[29]);
break;
case 161:
error("%s", messages[30]);
break;
case 162:
error("%s", messages[31]);
break;
case 200:
error("%s", messages[32]);
break;
case 201:
error("%s", messages[33]);
break;
case 202:
error("%s", messages[34]);
break;
case 203:
error("%s", messages[35]);
break;
case 204:
error("%s", messages[36]);
break;
case 205:
error("%s", messages[37]);
break;
case 206:
error("%s", messages[38]);
break;
case 207:
error("%s", messages[39]);
break;
case 208:
error("%s", messages[40]);
break;
case 209:
error("%s", messages[41]);
break;
case 210:
error("%s", messages[42]);
break;
case 211:
error("%s", messages[43]);
break;
case 212:
error("%s", messages[44]);
break;
case 213:
error("%s", messages[45]);
break;
case 214:
error("%s", messages[46]);
break;
case 215:
error("%s", messages[47]);
break;
case 216:
error("%s", messages[48]);
break;
case 250:
error("%s", messages[49]);
break;
case 251:
error("%s", messages[50]);
break;
case 252:
error("%s", messages[51]);
break;
case 253:
error("%s", messages[52]);
break;
case 254:
error("%s", messages[53]);
break;
case 255:
error("%s", messages[54]);
break;
case 256:
error("%s", messages[55]);
break;
case 257:
error("%s", messages[56]);
break;
case 258:
error("%s", messages[57]);
break;
case 259:
error("%s", messages[58]);
break;
case 260:
error("%s", messages[59]);
break;
case 261:
error("%s", messages[60]);
break;
case 262:
error("%s", messages[61]);
break;
case 263:
error("%s", messages[62]);
break;
case 264:
error("%s", messages[63]);
break;
case 265:
error("%s", messages[64]);
break;
case 266:
error("%s", messages[65]);
break;
case 267:
error("%s", messages[66]);
break;
case 268:
error("%s", messages[67]);
break;
case 269:
error("%s", messages[68]);
break;
case 270:
error("%s", messages[69]);
break;
case 271:
error("%s", messages[70]);
break;
case 272:
error("%s", messages[71]);
break;
case 273:
error("%s", messages[72]);
break;
case 274:
error("%s", messages[73]);
break;
case 275:
error("%s", messages[74]);
break;
case 276:
error("%s", messages[75]);
break;
case 277:
error("%s", messages[76]);
break;
case 278:
error("%s", messages[77]);
break;
case 279:
error("%s", messages[78]);
break;
case 280:
error("%s", messages[79]);
break;
case 281:
error("%s", messages[80]);
break;
case 282:
error("%s", messages[81]);
break;
case 299:
error("%s", messages[82]);
break;
case 300:
error("%s", messages[83]);
break;
case 301:
error("%s", messages[84]);
break;
case 302:
error("%s", messages[85]);
break;
case 303:
error("%s", messages[86]);
break;
case 304:
error("%s", messages[87]);
break;
case 305:
error("%s", messages[88]);
break;
case 306:
error("%s", messages[89]);
break;
case 307:
error("%s", messages[90]);
break;
case 308:
error("%s", messages[91]);
break;
case 309:
error("%s", messages[92]);
break;
case 310:
error("%s", messages[93]);
break;
case 311:
error("%s", messages[94]);
break;
case 312:
error("%s", messages[95]);
break;
case 313:
error("%s", messages[96]);
break;
case 314:
error("%s", messages[97]);
break;
case 315:
error("%s", messages[98]);
break;
case 316:
error("%s", messages[99]);
break;
case 317:
error("%s", messages[100]);
break;
case 318:
error("%s", messages[101]);
break;
case 319:
error("%s", messages[102]);
break;
case 320:
error("%s", messages[103]);
break;
case 321:
error("%s", messages[104]);
break;
case 322:
error("%s", messages[105]);
break;
case 323:
error("%s", messages[106]);
break;
default: {
if (code >= 7 && code <= 11) {
error(messages[107], code);
} else if (code >= 19 && code <= 99) {
error(messages[108], code);
} else if (code >= 107 && code <= 149) {
error(messages[109],
code);
} else if (code >= 163 && code <= 199) {
error(messages[110], code);
} else if (code >= 217 && code <= 249) {
error(messages[111], code);
} else if (code >= 283 && code <= 298) {
error(messages[112], code);
} else {
error(messages[113], code);
}
}
}
}
void delay(uint16 ms) {
g_engine->_chrono->delay(ms);
}
/*
Allows you to modify palette entries for the IBM
8514 and the VGA drivers.
*/
void setRGBPalette(int color, int r, int g, int b) {
// Take current palette
byte palbuf[768];
g_system->getPaletteManager()->grabPalette(palbuf, 0, 256);
palbuf[color * 3 + 0] = r << 2;
palbuf[color * 3 + 1] = g << 2;
palbuf[color * 3 + 2] = b << 2;
g_system->getPaletteManager()->setPalette(palbuf, 0, 256);
}
void littText(int x, int y, const Common::String &text, byte color, Graphics::TextAlign align) {
littText(x, y, text.c_str(), color, align);
}
void littText(int x, int y, const char *text, byte color, Graphics::TextAlign align) {
bool yAligned = (align == Graphics::kTextAlignCenter) ? true : false;
x = (align == Graphics::kTextAlignCenter) ? 0 : x;
y = y + 2;
g_engine->_graphics->littText(text, x, y, color, align, yAligned);
}
void euroText(int x, int y, const Common::String &text, byte color, Graphics::TextAlign align) {
euroText(x, y, text.c_str(), color, align);
}
void euroText(int x, int y, const char *text, byte color, Graphics::TextAlign align) {
bool yAligned = (align == Graphics::kTextAlignCenter) ? true : false;
x = (align == Graphics::kTextAlignCenter) ? 0 : x;
y = y + 2;
g_engine->_graphics->euroText(text, x, y, color, align, yAligned);
}
void biosText(int x, int y, const Common::String &text, byte color) {
g_engine->_graphics->biosText(text, x, y, color);
}
uint imagesize(int x, int y, int x2, int y2) {
int w = x2 - x + 1;
int h = y2 - y + 1;
return 4 + (w * h);
}
void rectangle(int x1, int y1, int x2, int y2, byte color) {
g_engine->_screen->drawLine(x1, y1, x2, y1, color);
g_engine->_screen->drawLine(x2, y1, x2, y2, color);
g_engine->_screen->drawLine(x1, y2, x2, y2, color);
g_engine->_screen->drawLine(x1, y1, x1, y2, color);
g_engine->_screen->addDirtyRect(Common::Rect(x1, y1, x2, y2));
}
void bar(int x1, int y1, int x2, int y2, byte color) {
x2 = x2 + 1;
y2 = y2 + 1;
for (int i = x1; i < x2; i++) {
for (int j = y1; j < y2; j++) {
*((byte *)g_engine->_screen->getBasePtr(i, j)) = color;
}
}
g_engine->_screen->addDirtyRect(Common::Rect(x1, y1, x2, y2));
}
void putpixel(int x, int y, byte color) {
g_engine->_screen->setPixel(x, y, color);
}
void line(uint x1, uint y1, uint x2, uint y2, byte color) {
g_engine->_screen->drawLine(x1, y1, x2, y2, color);
}
void changeGameSpeed(Common::Event e) {
if (e.type == Common::EVENT_KEYDOWN) {
if (e.kbd.hasFlags(Common::KBD_CTRL)) {
if (e.kbd.keycode == Common::KEYCODE_f) {
g_engine->_chrono->changeSpeed();
}
}
}
}
void emptyLoop() {
do {
g_engine->_events->pollEvent();
g_engine->_chrono->updateChrono();
g_engine->_screen->update();
} while (!g_engine->_chrono->_gameTick && !g_engine->shouldQuit());
}
void emptyLoop2() {
do {
g_engine->_chrono->updateChrono();
g_engine->_screen->update();
} while (!g_engine->_chrono->_gameTickHalfSpeed);
}
int getRandom(int range) { return g_engine->getRandomNumber(range - 1); }
Common::String getObjectName(int idx) {
return g_engine->_lang == Common::ES_ESP ? hardcodedTexts_ES[idx] : hardcodedTexts_EN[idx];
}
Common::String getActionLineText(int idx) {
return g_engine->_lang == Common::ES_ESP ? actionLine_ES[idx] : actionLine_EN[idx];
}
const char *const *getFullScreenMessagesByCurrentLanguage() {
return (g_engine->_lang == Common::ES_ESP) ? fullScreenMessages[0] : fullScreenMessages[1];
}
const char *const *getAnimMessagesByCurrentLanguage() {
return (g_engine->_lang == Common::ES_ESP) ? animMessages[0] : animMessages[1];
}
const char *const *getHardcodedTextsByCurrentLanguage() {
return (g_engine->_lang == Common::ES_ESP) ? hardcodedTexts_ES : hardcodedTexts_EN;
}
const int32 *getOffsetsByCurrentLanguage() {
return (g_engine->_lang == Common::ES_ESP) ? flcOffsets[0] : flcOffsets[1];
}
void newSecondaryAnimationFrame() {
if (g_engine->_curSecondaryAnimationFrame != nullptr) {
free(g_engine->_curSecondaryAnimationFrame);
}
g_engine->_curSecondaryAnimationFrame = (byte *)malloc(g_engine->_secondaryAnimFrameSize);
}
void clearScreenLayer(uint pos) {
if (g_engine->_screenLayers[pos]) {
free(g_engine->_screenLayers[pos]);
}
g_engine->_screenLayers[pos] = nullptr;
}
} // End of namespace Tot

93
engines/tot/util.h Normal file
View File

@@ -0,0 +1,93 @@
/* 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/>.
*
*/
#ifndef TOT_UTIL_H
#define TOT_UTIL_H
#include "tot/tot.h"
namespace Tot {
extern const int kEnforcedTextAnimDelay;
void showError(int code);
// Delays a specified number of milliseconds.
void delay(uint16 ms);
int engine_start();
void setRGBPalette(int color, int r, int g, int b);
void littText(int x, int y, const Common::String &text, byte color, Graphics::TextAlign align = Graphics::kTextAlignStart);
void littText(int x, int y, const char *text, byte color, Graphics::TextAlign align = Graphics::kTextAlignStart);
void euroText(int x, int y, const Common::String &text, byte color, Graphics::TextAlign align = Graphics::kTextAlignStart);
void euroText(int x, int y, const char *text, byte color, Graphics::TextAlign align = Graphics::kTextAlignStart);
void biosText(int x, int y, const Common::String &text, byte color);
uint imagesize(int x, int y, int x2, int y2);
void rectangle(int x1, int y1, int x2, int y2, byte color);
void line(uint x1, uint y1, uint x2, uint y2, byte color);
void bar(int x1, int y1, int x2, int y2, byte color);
void putpixel(int x, int y, byte color);
void emptyLoop();
void emptyLoop2();
void changeGameSpeed(Common::Event e);
inline bool odd(int32 i) { return i % 2 != 0; }
int getRandom(int range);
Common::String getObjectName(int idx);
Common::String getActionLineText(int idx);
const char *const *getFullScreenMessagesByCurrentLanguage();
const char *const *getAnimMessagesByCurrentLanguage();
const char *const *getHardcodedTextsByCurrentLanguage();
const int32 *getOffsetsByCurrentLanguage();
void newSecondaryAnimationFrame();
void clearScreenLayer(uint pos);
inline bool isLanguageSpanish() {
return g_engine->_lang == Common::ES_ESP;
}
inline bool isDemo() {
return g_engine->_gameDescription->flags & ADGF_DEMO;
}
} // End of namespace Tot
#endif