Initial commit
This commit is contained in:
1
engines/touche/POTFILES
Normal file
1
engines/touche/POTFILES
Normal file
@@ -0,0 +1 @@
|
||||
engines/touche/metaengine.cpp
|
||||
3
engines/touche/configure.engine
Normal file
3
engines/touche/configure.engine
Normal 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] [components]
|
||||
add_engine touche "Touche: The Adventures of the Fifth Musketeer" yes "" "" "highres" "midi"
|
||||
52
engines/touche/console.cpp
Normal file
52
engines/touche/console.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/* 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 "touche/console.h"
|
||||
#include "touche/touche.h"
|
||||
|
||||
namespace Touche {
|
||||
|
||||
ToucheConsole::ToucheConsole(ToucheEngine *vm) : GUI::Debugger(), _vm(vm) {
|
||||
registerCmd("startMusic", WRAP_METHOD(ToucheConsole, Cmd_StartMusic));
|
||||
registerCmd("stopMusic", WRAP_METHOD(ToucheConsole, Cmd_StopMusic));
|
||||
}
|
||||
|
||||
ToucheConsole::~ToucheConsole() {
|
||||
}
|
||||
|
||||
bool ToucheConsole::Cmd_StartMusic(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: startMusic <num>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int num = atoi(argv[1]);
|
||||
|
||||
_vm->startMusic(num);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ToucheConsole::Cmd_StopMusic(int argc, const char **argv) {
|
||||
_vm->stopMusic();
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Touche
|
||||
45
engines/touche/console.h
Normal file
45
engines/touche/console.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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 TOUCHE_CONSOLE_H
|
||||
#define TOUCHE_CONSOLE_H
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace Touche {
|
||||
|
||||
class ToucheEngine;
|
||||
|
||||
class ToucheConsole : public GUI::Debugger {
|
||||
public:
|
||||
ToucheConsole(ToucheEngine *vm);
|
||||
~ToucheConsole(void) override;
|
||||
|
||||
private:
|
||||
ToucheEngine *_vm;
|
||||
|
||||
bool Cmd_StartMusic(int argc, const char **argv);
|
||||
bool Cmd_StopMusic(int argc, const char **argv);
|
||||
};
|
||||
|
||||
} // End of namespace Touche
|
||||
|
||||
#endif
|
||||
3
engines/touche/credits.pl
Normal file
3
engines/touche/credits.pl
Normal file
@@ -0,0 +1,3 @@
|
||||
begin_section("Touché");
|
||||
add_person("Gregory Montoir", "cyx", "(retired)");
|
||||
end_section();
|
||||
170
engines/touche/detection.cpp
Normal file
170
engines/touche/detection.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/* 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 "engines/advancedDetector.h"
|
||||
|
||||
#include "base/plugins.h"
|
||||
#include "touche/touche.h"
|
||||
|
||||
static const PlainGameDescriptor toucheGames[] = {
|
||||
{ "touche", "Touch\303\251: The Adventures of the Fifth Musketeer" },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static const DebugChannelDef debugFlagList[] = {
|
||||
{Touche::kDebugEngine, "Engine", "Engine debug level"},
|
||||
{Touche::kDebugGraphics, "Graphics", "Graphics debug level"},
|
||||
{Touche::kDebugResource, "Resource", "Resource debug level"},
|
||||
{Touche::kDebugOpcodes, "Opcodes", "Opcodes debug level"},
|
||||
{Touche::kDebugMenu, "Menu", "Menu debug level"},
|
||||
{Touche::kDebugCharset, "Charset", "Charset debug level"},
|
||||
DEBUG_CHANNEL_END
|
||||
};
|
||||
|
||||
namespace Touche {
|
||||
|
||||
static const ADGameDescription gameDescriptions[] = {
|
||||
{ // retail version
|
||||
"touche",
|
||||
"",
|
||||
AD_ENTRY1s("touche.dat", "2af0177f8887e3430f345e6b4d8b1414", 26350211),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{ // retail version - tracker item #2923
|
||||
"touche",
|
||||
"",
|
||||
AD_ENTRY1s("touche.dat", "95967f0b51d2e813e99ca00325098340", 26350190),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{ // retail version
|
||||
"touche",
|
||||
"",
|
||||
AD_ENTRY1s("touche.dat", "1caa20bb4d4fc2ce8eb867b6610082b3", 26558232),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{ // retail version - tracker item #2912
|
||||
"touche",
|
||||
"",
|
||||
AD_ENTRY1s("touche.dat", "be2ae6454b3325e410946f2322547cd4", 26625537),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{ // retail version - tracker item #3121
|
||||
"touche",
|
||||
"",
|
||||
AD_ENTRY1s("touche.dat", "64e95ba1decf5a5a60f8fa1840f40c62", 26529523),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{ // fan-made translation (http://www.iagtg.net/) - tracker item #2927
|
||||
"touche",
|
||||
"",
|
||||
AD_ENTRY1s("touche.dat", "1f442331d4b327c3488a9f6ffe9bdd25", 26367792),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{ // retail version - tracker item #3409
|
||||
"touche",
|
||||
"",
|
||||
AD_ENTRY1s("touche.dat", "42d19a0bef65465109020440a9caa228", 26487370),
|
||||
Common::PL_POL,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{ // Fanmade translation by Old-Games.ru
|
||||
"touche",
|
||||
"v1.0.2",
|
||||
AD_ENTRY1s("touche.dat", "44c1a7a619d583d458f0c24e881a0b68", 51362582),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
{ // demo version
|
||||
"touche",
|
||||
"Demo",
|
||||
AD_ENTRY1s("touche.dat", "ddaed436445b2e77294ed19e8ae4aa2c", 8720683),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO0()
|
||||
},
|
||||
AD_TABLE_END_MARKER
|
||||
};
|
||||
|
||||
static const ADFileBasedFallback fileBasedFallback[] = {
|
||||
{ &gameDescriptions[0], { "touche.dat", 0 } }, // default to english version
|
||||
{ 0, { 0 } }
|
||||
};
|
||||
|
||||
} // End of namespace Touche
|
||||
|
||||
static const char *const directoryGlobs[] = {
|
||||
"database",
|
||||
0
|
||||
};
|
||||
|
||||
class ToucheMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
|
||||
public:
|
||||
ToucheMetaEngineDetection() : AdvancedMetaEngineDetection(Touche::gameDescriptions, toucheGames) {
|
||||
_md5Bytes = 4096;
|
||||
_maxScanDepth = 2;
|
||||
_directoryGlobs = directoryGlobs;
|
||||
}
|
||||
|
||||
ADDetectedGame fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist, ADDetectedGameExtraInfo **extra) const override {
|
||||
return detectGameFilebased(allFiles, Touche::fileBasedFallback);
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "touche";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Touch\303\251: The Adventures of the Fifth Musketeer";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "Touch\303\251: The Adventures of the Fifth Musketeer (C) Clipper Software";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN_STATIC(TOUCHE_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, ToucheMetaEngineDetection);
|
||||
209
engines/touche/graphics.cpp
Normal file
209
engines/touche/graphics.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/* 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/endian.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "touche/graphics.h"
|
||||
|
||||
namespace Touche {
|
||||
|
||||
void Graphics::setupFont(Common::Language language) {
|
||||
switch (language) {
|
||||
case Common::FR_FRA:
|
||||
case Common::DE_DEU:
|
||||
_fontOffs = _freGerFontOffs;
|
||||
_fontSize = _freGerFontSize;
|
||||
_fontData = _freGerFontData;
|
||||
break;
|
||||
case Common::ES_ESP:
|
||||
_fontOffs = _spaFontOffs;
|
||||
_fontSize = _spaFontSize;
|
||||
_fontData = _spaFontData;
|
||||
break;
|
||||
case Common::PL_POL:
|
||||
_fontOffs = _polFontOffs;
|
||||
_fontSize = _polFontSize;
|
||||
_fontData = _polFontData;
|
||||
break;
|
||||
case Common::RU_RUS:
|
||||
_fontOffs = _rusFontOffs;
|
||||
_fontSize = _rusFontSize;
|
||||
_fontData = _rusFontData;
|
||||
break;
|
||||
case Common::IT_ITA:
|
||||
case Common::EN_ANY:
|
||||
default:
|
||||
_fontOffs = _engFontOffs;
|
||||
_fontSize = _engFontSize;
|
||||
_fontData = _engFontData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int Graphics::getStringWidth16(const char *str) {
|
||||
int w = 0;
|
||||
while (*str) {
|
||||
char chr = *str++;
|
||||
w += getCharWidth16((uint8)chr);
|
||||
if (*str == '\\') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
int Graphics::getCharWidth16(uint8 chr) {
|
||||
assert(chr >= 32 && chr < 32 + _fontSize);
|
||||
const uint8 *chrData = _fontData + _fontOffs[chr - 32];
|
||||
return chrData[2];
|
||||
}
|
||||
|
||||
void Graphics::drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str, int xmax) {
|
||||
while (*str) {
|
||||
uint8 chr = (uint8)*str++;
|
||||
x += drawChar16(dst, dstPitch, chr, x, y, color);
|
||||
if (xmax != 0 && x > xmax) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Graphics::drawChar16(uint8 *dst, int dstPitch, uint8 chr, int x, int y, uint16 color) {
|
||||
dst += y * dstPitch + x;
|
||||
uint8 color1 = color & 0xFF;
|
||||
uint8 color2 = color >> 8;
|
||||
assert(chr >= 32 && chr < 32 + _fontSize);
|
||||
const uint8 *chrData = _fontData + _fontOffs[chr - 32];
|
||||
int chrHeight = chrData[1];
|
||||
int chrWidth = chrData[2];
|
||||
chrData += 3;
|
||||
while (chrHeight--) {
|
||||
int shiftCount = 0;
|
||||
int mask = 0;
|
||||
for (int i = 0; i < chrWidth; ++i) {
|
||||
if (shiftCount == 0) {
|
||||
mask = READ_BE_UINT16(chrData); chrData += 2;
|
||||
shiftCount = 8;
|
||||
}
|
||||
int b = (mask & 0xC000) >> 14;
|
||||
mask <<= 2;
|
||||
--shiftCount;
|
||||
if (b) {
|
||||
if (b & 2) {
|
||||
dst[i] = color2;
|
||||
} else {
|
||||
dst[i] = color1;
|
||||
}
|
||||
}
|
||||
}
|
||||
dst += dstPitch;
|
||||
}
|
||||
return chrWidth;
|
||||
}
|
||||
|
||||
void Graphics::fillRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color) {
|
||||
dst += y * dstPitch + x;
|
||||
while (h--) {
|
||||
memset(dst, color, w);
|
||||
dst += dstPitch;
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::drawRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color1, uint8 color2) {
|
||||
::Graphics::Surface s;
|
||||
s.init(x+w, y+h, dstPitch, dst, ::Graphics::PixelFormat::createFormatCLUT8());
|
||||
const int x1 = x;
|
||||
const int y1 = y;
|
||||
const int x2 = x + w - 1;
|
||||
const int y2 = y + h - 1;
|
||||
s.hLine(x1, y1, x2, color1);
|
||||
s.vLine(x1, y1, y2, color1);
|
||||
s.vLine(x2, y1 + 1, y2, color2);
|
||||
s.hLine(x1 + 1, y2, x2, color2);
|
||||
}
|
||||
|
||||
void Graphics::drawLine(uint8 *dst, int dstPitch, int x1, int y1, int x2, int y2, uint8 color) {
|
||||
assert(x1 >= 0 && y1 >= 0 && x2 >= 0 && y2 >= 0);
|
||||
|
||||
::Graphics::Surface s;
|
||||
s.init(MAX(x1, x2) + 1, MAX(y1, y2) + 1, dstPitch, dst, ::Graphics::PixelFormat::createFormatCLUT8());
|
||||
|
||||
s.drawLine(x1, y1, x2, y2, color);
|
||||
}
|
||||
|
||||
void Graphics::copyRect(uint8 *dst, int dstPitch, int dstX, int dstY, const uint8 *src, int srcPitch, int srcX, int srcY, int w, int h, int flags) {
|
||||
if (dstX < 0) {
|
||||
w += dstX;
|
||||
dstX = 0;
|
||||
}
|
||||
if (w <= 0) {
|
||||
return;
|
||||
}
|
||||
if (dstY < 0) {
|
||||
h += dstY;
|
||||
dstY = 0;
|
||||
}
|
||||
if (h <= 0) {
|
||||
return;
|
||||
}
|
||||
dst += dstY * dstPitch + dstX;
|
||||
src += srcY * srcPitch + srcX;
|
||||
while (h--) {
|
||||
for (int i = 0; i < w; ++i) {
|
||||
if ((flags & kTransparent) == 0 || src[i] != 0) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
dst += dstPitch;
|
||||
src += srcPitch;
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::copyMask(uint8 *dst, int dstPitch, int dstX, int dstY, const uint8 *src, int srcPitch, int srcX, int srcY, int w, int h, uint8 fillColor) {
|
||||
if (dstX < 0) {
|
||||
w += dstX;
|
||||
dstX = 0;
|
||||
}
|
||||
if (w <= 0) {
|
||||
return;
|
||||
}
|
||||
if (dstY < 0) {
|
||||
h += dstY;
|
||||
dstY = 0;
|
||||
}
|
||||
if (h <= 0) {
|
||||
return;
|
||||
}
|
||||
dst += dstY * dstPitch + dstX;
|
||||
src += srcY * srcPitch + srcX;
|
||||
while (h--) {
|
||||
for (int i = 0; i < w; ++i) {
|
||||
if (src[i] != 0) {
|
||||
dst[i] = fillColor;
|
||||
}
|
||||
}
|
||||
dst += dstPitch;
|
||||
src += srcPitch;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Touche
|
||||
81
engines/touche/graphics.h
Normal file
81
engines/touche/graphics.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/* 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 TOUCHE_GRAPHICS_H
|
||||
#define TOUCHE_GRAPHICS_H
|
||||
|
||||
#include "common/language.h"
|
||||
|
||||
namespace Touche {
|
||||
|
||||
class Graphics {
|
||||
public:
|
||||
|
||||
enum {
|
||||
kTransparent = 1 << 0
|
||||
};
|
||||
|
||||
static void setupFont(Common::Language language);
|
||||
static int getStringWidth16(const char *str);
|
||||
static int getCharWidth16(uint8 chr);
|
||||
static void drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str, int xmax = 0);
|
||||
static int drawChar16(uint8 *dst, int dstPitch, uint8 chr, int x, int y, uint16 color);
|
||||
static void fillRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color);
|
||||
static void drawRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color1, uint8 color2);
|
||||
static void drawLine(uint8 *dst, int dstPitch, int x1, int y1, int x2, int y2, uint8 color);
|
||||
static void copyRect(uint8 *dst, int dstPitch, int dstX, int dstY, const uint8 *src, int srcPitch, int srcX, int srcY, int w, int h, int flags = 0);
|
||||
static void copyMask(uint8 *dst, int dstPitch, int dstX, int dstY, const uint8 *src, int srcPitch, int srcX, int srcY, int w, int h, uint8 fillColor);
|
||||
|
||||
private:
|
||||
|
||||
/* font data for english version */
|
||||
static const uint16 _engFontOffs[];
|
||||
static const int _engFontSize;
|
||||
static const uint8 _engFontData[];
|
||||
|
||||
/* font data for french and german versions */
|
||||
static const uint16 _freGerFontOffs[];
|
||||
static const int _freGerFontSize;
|
||||
static const uint8 _freGerFontData[];
|
||||
|
||||
/* font data for spanish version */
|
||||
static const uint16 _spaFontOffs[];
|
||||
static const int _spaFontSize;
|
||||
static const uint8 _spaFontData[];
|
||||
|
||||
/* font data for polish version */
|
||||
static const uint16 _polFontOffs[];
|
||||
static const int _polFontSize;
|
||||
static const uint8 _polFontData[];
|
||||
|
||||
/* font data for russian version */
|
||||
static const uint16 _rusFontOffs[];
|
||||
static const int _rusFontSize;
|
||||
static const uint8 _rusFontData[];
|
||||
|
||||
static const uint16 *_fontOffs;
|
||||
static int _fontSize;
|
||||
static const uint8 *_fontData;
|
||||
};
|
||||
|
||||
} // namespace Touche
|
||||
|
||||
#endif
|
||||
517
engines/touche/menu.cpp
Normal file
517
engines/touche/menu.cpp
Normal file
@@ -0,0 +1,517 @@
|
||||
/* 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/events.h"
|
||||
#include "common/system.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
|
||||
#include "touche/graphics.h"
|
||||
#include "touche/midi.h"
|
||||
#include "touche/touche.h"
|
||||
|
||||
namespace Touche {
|
||||
|
||||
static void drawArrow(uint8 *dst, int dstPitch, int x, int y, int delta, uint8 color) {
|
||||
static const int8 arrowCoordsTable[7][4] = {
|
||||
{ 5, 0, 9, 0 },
|
||||
{ 5, 0, 5, 4 },
|
||||
{ -5, 4, 5, 4 },
|
||||
{ -5, 0, -5, 4 },
|
||||
{ -9, 0, -5, 0 },
|
||||
{ -9, 0, 0, -9 },
|
||||
{ 0, -9, 9, 0 }
|
||||
};
|
||||
for (uint i = 0; i < 7; ++i) {
|
||||
const int x1 = x + arrowCoordsTable[i][0];
|
||||
const int y1 = y + arrowCoordsTable[i][1] * delta;
|
||||
const int x2 = x + arrowCoordsTable[i][2];
|
||||
const int y2 = y + arrowCoordsTable[i][3] * delta;
|
||||
Graphics::drawLine(dst, dstPitch, x1, y1, x2, y2, color);
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::drawButton(Button *button) {
|
||||
if (button->flags & kButtonBorder) {
|
||||
Graphics::drawRect(_offscreenBuffer, kScreenWidth, button->x, button->y, button->w, button->h, 0xF7, 0xF9);
|
||||
}
|
||||
if (button->flags & kButtonText) {
|
||||
if (button->data != 0) {
|
||||
const char *str = getString(button->data);
|
||||
const int w = getStringWidth(button->data);
|
||||
const int h = kTextHeight;
|
||||
const int x = button->x + (button->w - w) / 2;
|
||||
const int y = button->y + (button->h - h) / 2;
|
||||
Graphics::drawString16(_offscreenBuffer, kScreenWidth, 0xFF, x, y, str);
|
||||
}
|
||||
}
|
||||
if (button->flags & kButtonArrow) {
|
||||
int dx = 0;
|
||||
int dy = 0;
|
||||
switch (button->data) {
|
||||
case 2000: // up arrow
|
||||
dx = 1;
|
||||
dy = 2;
|
||||
break;
|
||||
case 2001: // down arrow
|
||||
dx = -1;
|
||||
dy = -2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const int x = button->x + button->w / 2;
|
||||
const int y = button->y + button->h / 2;
|
||||
drawArrow(_offscreenBuffer, kScreenWidth, x, y + dy + 1, dx, 0xD2);
|
||||
drawArrow(_offscreenBuffer, kScreenWidth, x, y + dy, dx, 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawVolumeSlideBar(uint8 *dst, int dstPitch, int volume) {
|
||||
const int w = volume * 232 / 255;
|
||||
if (w > 0) {
|
||||
Graphics::fillRect(dst, dstPitch, 157, 259, w, 6, 0xF0);
|
||||
}
|
||||
if (w < 232) {
|
||||
Graphics::fillRect(dst, dstPitch, 157 + w, 259, 232 - w, 6, 0xD2);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawSaveGameStateDescriptions(uint8 *dst, int dstPitch, MenuData *menuData, int currentPage, int currentSlot) {
|
||||
for (int i = 0, slot = currentPage * 10; i < 10; ++i, ++slot) {
|
||||
const Button *b = &menuData->buttonsTable[i];
|
||||
const uint8 color = (slot == currentSlot) ? 0xCB : 0xD9;
|
||||
Common::String savegameNameStr = Common::String::format("%d.", slot);
|
||||
Graphics::drawString16(dst, dstPitch, color, b->x, b->y, savegameNameStr.c_str());
|
||||
savegameNameStr = menuData->saveLoadDescriptionsTable[slot];
|
||||
if (slot == currentSlot && menuData->mode == kMenuSaveStateMode) {
|
||||
savegameNameStr += "_";
|
||||
}
|
||||
Graphics::drawString16(dst, dstPitch, color, b->x + 30, b->y, savegameNameStr.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static void setupMenu(MenuMode mode, MenuData *menuData) {
|
||||
static Button settingsButtonsTable[] = {
|
||||
{ 452, 120, 94, 24, kActionLoadMenu, -52, kButtonBorder | kButtonText },
|
||||
{ 452, 152, 94, 24, kActionSaveMenu, -53, kButtonBorder | kButtonText },
|
||||
{ 452, 184, 94, 24, kActionRestartGame, -90, kButtonBorder | kButtonText },
|
||||
{ 452, 216, 94, 24, kActionPlayGame, -54, kButtonBorder | kButtonText },
|
||||
{ 452, 248, 94, 24, kActionQuitGame, -55, kButtonBorder | kButtonText },
|
||||
{ 396, 130, 24, 24, kActionTextOnly, 0, kButtonBorder | kButtonText },
|
||||
{ 396, 160, 24, 24, kActionVoiceOnly, 0, kButtonBorder | kButtonText },
|
||||
{ 396, 190, 24, 24, kActionTextAndVoice, 0, kButtonBorder | kButtonText },
|
||||
{ 126, 130, 254, 24, kActionNone, -92, kButtonBorder | kButtonText },
|
||||
{ 126, 160, 254, 24, kActionNone, -93, kButtonBorder | kButtonText },
|
||||
{ 126, 190, 254, 24, kActionNone, -94, kButtonBorder | kButtonText },
|
||||
{ 126, 222, 294, 20, kActionNone, -91, kButtonBorder | kButtonText },
|
||||
{ 126, 250, 24, 24, kActionLowerVolume, -87, kButtonBorder | kButtonText },
|
||||
{ 396, 250, 24, 24, kActionUpperVolume, -88, kButtonBorder | kButtonText },
|
||||
{ 154, 256, 238, 12, kActionNone, 0, kButtonBorder }
|
||||
};
|
||||
static Button saveLoadButtonsTable[] = {
|
||||
{ 108, 120, 336, 15, kActionGameState1, 0, 0 },
|
||||
{ 108, 136, 336, 15, kActionGameState2, 0, 0 },
|
||||
{ 108, 152, 336, 15, kActionGameState3, 0, 0 },
|
||||
{ 108, 168, 336, 15, kActionGameState4, 0, 0 },
|
||||
{ 108, 184, 336, 15, kActionGameState5, 0, 0 },
|
||||
{ 108, 200, 336, 15, kActionGameState6, 0, 0 },
|
||||
{ 108, 216, 336, 15, kActionGameState7, 0, 0 },
|
||||
{ 108, 232, 336, 15, kActionGameState8, 0, 0 },
|
||||
{ 108, 248, 336, 15, kActionGameState9, 0, 0 },
|
||||
{ 108, 264, 336, 15, kActionGameState10, 0, 0 },
|
||||
{ 452, 120, 94, 24, kActionScrollUpSaves, 2000, kButtonBorder | kButtonArrow },
|
||||
{ 452, 152, 94, 24, kActionCancelSaveLoad, -56, kButtonBorder | kButtonText },
|
||||
{ 452, 216, 94, 24, kActionPerformSaveLoad, 0, kButtonBorder | kButtonText },
|
||||
{ 452, 248, 94, 24, kActionScrollDownSaves, 2001, kButtonBorder | kButtonArrow }
|
||||
};
|
||||
|
||||
switch (mode) {
|
||||
case kMenuSettingsMode:
|
||||
menuData->buttonsTable = settingsButtonsTable;
|
||||
menuData->buttonsCount = ARRAYSIZE(settingsButtonsTable);
|
||||
break;
|
||||
case kMenuLoadStateMode:
|
||||
saveLoadButtonsTable[12].data = -52;
|
||||
menuData->buttonsTable = saveLoadButtonsTable;
|
||||
menuData->buttonsCount = ARRAYSIZE(saveLoadButtonsTable);
|
||||
break;
|
||||
case kMenuSaveStateMode:
|
||||
saveLoadButtonsTable[12].data = -53;
|
||||
menuData->buttonsTable = saveLoadButtonsTable;
|
||||
menuData->buttonsCount = ARRAYSIZE(saveLoadButtonsTable);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::redrawMenu(MenuData *menu) {
|
||||
Graphics::fillRect(_offscreenBuffer, kScreenWidth, 90, 102, 460, 196, 0xF8);
|
||||
Graphics::drawRect(_offscreenBuffer, kScreenWidth, 90, 102, 460, 196, 0xF7, 0xF9);
|
||||
Graphics::drawRect(_offscreenBuffer, kScreenWidth, 106, 118, 340, 164, 0xF9, 0xF7);
|
||||
switch (menu->mode) {
|
||||
case kMenuSettingsMode:
|
||||
drawVolumeSlideBar(_offscreenBuffer, kScreenWidth, getMusicVolume());
|
||||
menu->buttonsTable[5].data = 0;
|
||||
menu->buttonsTable[6].data = 0;
|
||||
menu->buttonsTable[7].data = 0;
|
||||
menu->buttonsTable[5 + _talkTextMode].data = -86;
|
||||
break;
|
||||
case kMenuLoadStateMode:
|
||||
case kMenuSaveStateMode:
|
||||
drawSaveGameStateDescriptions(_offscreenBuffer, kScreenWidth, menu, _saveLoadCurrentPage, _saveLoadCurrentSlot);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for (uint i = 0; i < menu->buttonsCount; ++i) {
|
||||
drawButton(&menu->buttonsTable[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::handleMenuAction(MenuData *menu, int actionId) {
|
||||
switch (actionId) {
|
||||
case kActionLoadMenu:
|
||||
menu->mode = kMenuLoadStateMode;
|
||||
break;
|
||||
case kActionSaveMenu:
|
||||
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
|
||||
menu->mode = kMenuSaveStateMode;
|
||||
break;
|
||||
case kActionRestartGame:
|
||||
restart();
|
||||
menu->quit = true;
|
||||
break;
|
||||
case kActionPlayGame:
|
||||
menu->quit = true;
|
||||
break;
|
||||
case kActionQuitGame:
|
||||
quitGame();
|
||||
menu->quit = true;
|
||||
break;
|
||||
case kActionTextOnly:
|
||||
_talkTextMode = kTalkModeTextOnly;
|
||||
break;
|
||||
case kActionVoiceOnly:
|
||||
_talkTextMode = kTalkModeVoiceOnly;
|
||||
break;
|
||||
case kActionTextAndVoice:
|
||||
_talkTextMode = kTalkModeVoiceAndText;
|
||||
break;
|
||||
case kActionLowerVolume:
|
||||
adjustMusicVolume(-16);
|
||||
break;
|
||||
case kActionUpperVolume:
|
||||
adjustMusicVolume(+16);
|
||||
break;
|
||||
case kActionScrollUpSaves:
|
||||
--_saveLoadCurrentPage;
|
||||
if (_saveLoadCurrentPage < 0) {
|
||||
_saveLoadCurrentPage = 9;
|
||||
}
|
||||
_saveLoadCurrentSlot = _saveLoadCurrentPage * 10 + (_saveLoadCurrentSlot % 10);
|
||||
break;
|
||||
case kActionScrollDownSaves:
|
||||
++_saveLoadCurrentPage;
|
||||
if (_saveLoadCurrentPage > 9) {
|
||||
_saveLoadCurrentPage = 0;
|
||||
}
|
||||
_saveLoadCurrentSlot = _saveLoadCurrentPage * 10 + (_saveLoadCurrentSlot % 10);
|
||||
break;
|
||||
case kActionPerformSaveLoad:
|
||||
if (menu->mode == kMenuLoadStateMode) {
|
||||
if (loadGameState(_saveLoadCurrentSlot).getCode() == Common::kNoError) {
|
||||
menu->quit = true;
|
||||
}
|
||||
} else if (menu->mode == kMenuSaveStateMode) {
|
||||
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
|
||||
const char *description = menu->saveLoadDescriptionsTable[_saveLoadCurrentSlot];
|
||||
if (strlen(description) > 0) {
|
||||
if (saveGameState(_saveLoadCurrentSlot, description).getCode() == Common::kNoError) {
|
||||
menu->quit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kActionCancelSaveLoad:
|
||||
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
|
||||
menu->mode = kMenuSettingsMode;
|
||||
break;
|
||||
default:
|
||||
if (actionId >= kActionGameState1 && actionId <= kActionGameState10) {
|
||||
_saveLoadCurrentSlot = _saveLoadCurrentPage * 10 + (actionId - kActionGameState1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::handleOptions(int forceDisplay) {
|
||||
if (_disabledInputCounter == 0 || forceDisplay != 0) {
|
||||
setDefaultCursor(_currentKeyCharNum);
|
||||
_gameState = kGameStateOptionsDialog;
|
||||
MenuData menuData;
|
||||
memset(&menuData, 0, sizeof(MenuData));
|
||||
menuData.quit = false;
|
||||
menuData.exit = false;
|
||||
menuData.mode = kMenuSettingsMode;
|
||||
int curMode = -1;
|
||||
bool doRedraw = false;
|
||||
while (!menuData.quit) {
|
||||
if (menuData.mode != curMode) {
|
||||
doRedraw = true;
|
||||
setupMenu(menuData.mode, &menuData);
|
||||
curMode = menuData.mode;
|
||||
if (menuData.mode == kMenuLoadStateMode || menuData.mode == kMenuSaveStateMode) {
|
||||
for (int i = 0; i < kMaxSaveStates; ++i) {
|
||||
menuData.saveLoadDescriptionsTable[i][0] = 0;
|
||||
}
|
||||
Common::String gameStateFileName = generateGameStateFileName(_targetName.c_str(), 0, true);
|
||||
Common::StringArray filenames = _saveFileMan->listSavefiles(gameStateFileName);
|
||||
for (Common::StringArray::const_iterator it = filenames.begin(); it != filenames.end(); ++it) {
|
||||
int i = getGameStateFileSlot(it->c_str());
|
||||
if (i >= 0 && i < kMaxSaveStates) {
|
||||
Common::InSaveFile *f = _saveFileMan->openForLoading(*it);
|
||||
if (f) {
|
||||
readGameStateDescription(f, menuData.saveLoadDescriptionsTable[i], 32);
|
||||
delete f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doRedraw) {
|
||||
redrawMenu(&menuData);
|
||||
updateScreenArea(90, 102, 460, 196);
|
||||
doRedraw = false;
|
||||
}
|
||||
|
||||
Common::Keymapper *keymapper = _eventMan->getKeymapper();
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(false);
|
||||
|
||||
Common::Event event;
|
||||
while (_eventMan->pollEvent(event)) {
|
||||
const Button *button = 0;
|
||||
switch (event.type) {
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
case Common::EVENT_QUIT:
|
||||
menuData.quit = true;
|
||||
menuData.exit = true;
|
||||
break;
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
button = menuData.findButtonUnderCursor(event.mouse.x, event.mouse.y);
|
||||
if (button) {
|
||||
handleMenuAction(&menuData, button->action);
|
||||
doRedraw = true;
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_KEYDOWN:
|
||||
if (menuData.mode == kMenuSaveStateMode) {
|
||||
if (event.kbd.keycode == Common::KEYCODE_BACKSPACE) {
|
||||
menuData.removeLastCharFromDescription(_saveLoadCurrentSlot);
|
||||
} else {
|
||||
menuData.addCharToDescription(_saveLoadCurrentSlot, (char)event.kbd.ascii);
|
||||
}
|
||||
doRedraw = true;
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_WHEELUP:
|
||||
handleMenuAction(&menuData, kActionScrollUpSaves);
|
||||
doRedraw = true;
|
||||
break;
|
||||
case Common::EVENT_WHEELDOWN:
|
||||
handleMenuAction(&menuData, kActionScrollDownSaves);
|
||||
doRedraw = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
|
||||
|
||||
_system->updateScreen();
|
||||
_system->delayMillis(10);
|
||||
}
|
||||
_fullRedrawCounter = 2;
|
||||
if (!menuData.exit && shouldQuit()) {
|
||||
if (displayQuitDialog())
|
||||
quitGame();
|
||||
}
|
||||
_gameState = kGameStateGameLoop;
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::drawActionsPanel(int dstX, int dstY, int deltaX, int deltaY) {
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, dstX, dstY,
|
||||
_menuKitData, 42, 0, 0,
|
||||
14, 24,
|
||||
Graphics::kTransparent);
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, deltaX - 14 + dstX, dstY,
|
||||
_menuKitData, 42, 0, 40,
|
||||
14, 24,
|
||||
Graphics::kTransparent);
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, dstX, deltaY - 16 + dstY,
|
||||
_menuKitData, 42, 0, 24,
|
||||
14, 16,
|
||||
Graphics::kTransparent);
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, deltaX - 14 + dstX, deltaY - 16 + dstY,
|
||||
_menuKitData, 42, 0, 64,
|
||||
14, 16,
|
||||
Graphics::kTransparent);
|
||||
int x1 = deltaX - 28;
|
||||
int x2 = dstX + 14;
|
||||
while (x1 > 0) {
|
||||
int w = (x1 > 14) ? 14 : x1;
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, x2, dstY,
|
||||
_menuKitData, 42, 0, 80,
|
||||
w, 24,
|
||||
Graphics::kTransparent);
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, x2, deltaY - 16 + dstY,
|
||||
_menuKitData, 42, 0, 104,
|
||||
w, 16,
|
||||
Graphics::kTransparent);
|
||||
x1 -= 14;
|
||||
x2 += 14;
|
||||
}
|
||||
x1 = deltaY - 40;
|
||||
x2 = dstY + 24;
|
||||
while (x1 > 0) {
|
||||
int w = (x1 > 120) ? 120 : x1;
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, dstX, x2,
|
||||
_menuKitData, 42, 14, 0,
|
||||
14, w,
|
||||
Graphics::kTransparent);
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, deltaX - 14 + dstX, x2,
|
||||
_menuKitData, 42, 28, 0,
|
||||
14, w,
|
||||
Graphics::kTransparent);
|
||||
x1 -= 120;
|
||||
x2 += 120;
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::drawConversationPanelBorder(int dstY, int srcX, int srcY) {
|
||||
int dstX = 24;
|
||||
int w = 48;
|
||||
for (int i = 0; i < 13; ++i) {
|
||||
if (i == 12) {
|
||||
w = 34;
|
||||
}
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, dstX, dstY, _convKitData, 152, srcX, srcY, w, 6);
|
||||
dstX += w;
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::drawConversationPanel() {
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, 0, 320, _convKitData, 152, 0, 0, 72, 80);
|
||||
int dstX = 54;
|
||||
int dstY = 326;
|
||||
int w = 96;
|
||||
for (int i = 0; i < 7; ++i) {
|
||||
if (i == 5) {
|
||||
w = 50;
|
||||
}
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, dstX, dstY, _convKitData, 152, 24, 6, w, 68);
|
||||
dstX += w;
|
||||
}
|
||||
--dstX;
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, dstX, 320, _convKitData, 152, 120, 0, 7, 80);
|
||||
dstX -= 3;
|
||||
if (_scrollConversationChoiceOffset != 0) {
|
||||
drawConversationPanelBorder(320, 72, 0);
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, 0, 320, _convKitData, 152, 128, 0, 24, 21);
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, dstX, 320, _convKitData, 152, 128, 34, 10, 10);
|
||||
} else {
|
||||
drawConversationPanelBorder(320, 24, 0);
|
||||
}
|
||||
if (_conversationChoicesTable[_scrollConversationChoiceOffset + 4].msg != 0) {
|
||||
drawConversationPanelBorder(394, 72, 74);
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, 0, 379, _convKitData, 152, 128, 59, 24, 21);
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, dstX, 394, _convKitData, 152, 128, 46, 10, 6);
|
||||
} else {
|
||||
drawConversationPanelBorder(394, 24, 74);
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::printStatusString(const char *str) {
|
||||
Graphics::fillRect(_offscreenBuffer, kScreenWidth, 0, 0, kScreenWidth, kTextHeight, 0xD7);
|
||||
Graphics::drawRect(_offscreenBuffer, kScreenWidth, 0, 0, kScreenWidth, kTextHeight, 0xD6, 0xD8);
|
||||
Graphics::drawString16(_offscreenBuffer, kScreenWidth, 0xFF, 0, 0, str);
|
||||
updateScreenArea(0, 0, kScreenWidth, kTextHeight);
|
||||
_system->updateScreen();
|
||||
}
|
||||
|
||||
void ToucheEngine::clearStatusString() {
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, 0, 0,
|
||||
_backdropBuffer, _currentBitmapWidth, _flagsTable[614], _flagsTable[615],
|
||||
kScreenWidth, kTextHeight);
|
||||
updateScreenArea(0, 0, kScreenWidth, kTextHeight);
|
||||
}
|
||||
|
||||
int ToucheEngine::displayQuitDialog() {
|
||||
debug(kDebugMenu, "ToucheEngine::displayQuitDialog()");
|
||||
_gameState = kGameStateQuitDialog;
|
||||
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
|
||||
printStatusString(getString(-85));
|
||||
int ret = 0;
|
||||
bool quitLoop = false;
|
||||
while (!quitLoop) {
|
||||
Common::Event event;
|
||||
while (_eventMan->pollEvent(event)) {
|
||||
switch (event.type) {
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
case Common::EVENT_QUIT:
|
||||
quitLoop = true;
|
||||
ret = 1;
|
||||
break;
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
quitLoop = true;
|
||||
if (event.customType == kToucheActionYes) {
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_JOYBUTTON_DOWN:
|
||||
case Common::EVENT_KEYDOWN:
|
||||
quitLoop = true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
_system->delayMillis(10);
|
||||
_system->updateScreen();
|
||||
}
|
||||
clearStatusString();
|
||||
_gameState = kGameStateGameLoop;
|
||||
_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ToucheEngine::displayTextMode(int str) {
|
||||
debug(kDebugMenu, "ToucheEngine::displayTextMode(%d)", str);
|
||||
printStatusString(getString(str));
|
||||
_system->delayMillis(1000);
|
||||
clearStatusString();
|
||||
}
|
||||
|
||||
} // namespace Touche
|
||||
217
engines/touche/metaengine.cpp
Normal file
217
engines/touche/metaengine.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/* 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 "engines/advancedDetector.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
#include "base/plugins.h"
|
||||
|
||||
#include "touche/touche.h"
|
||||
|
||||
class ToucheMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "touche";
|
||||
}
|
||||
|
||||
bool hasFeature(MetaEngineFeature f) const override;
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
|
||||
SaveStateList listSaves(const char *target) const override;
|
||||
int getMaximumSaveSlot() const override;
|
||||
bool removeSaveState(const char *target, int slot) const override;
|
||||
Common::String getSavegameFile(int saveGameIdx, const char *target) const override {
|
||||
if (!target)
|
||||
target = getName();
|
||||
return Touche::generateGameStateFileName(target, saveGameIdx, saveGameIdx == kSavegameFilePattern);
|
||||
}
|
||||
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
};
|
||||
|
||||
bool ToucheMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsListSaves) ||
|
||||
(f == kSupportsLoadingDuringStartup) ||
|
||||
(f == kSupportsDeleteSave);
|
||||
}
|
||||
|
||||
bool Touche::ToucheEngine::hasFeature(EngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsReturnToLauncher) ||
|
||||
(f == kSupportsLoadingDuringRuntime) ||
|
||||
(f == kSupportsSavingDuringRuntime) ||
|
||||
(f == kSupportsSubtitleOptions);
|
||||
}
|
||||
|
||||
Common::Error ToucheMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
|
||||
*engine = new Touche::ToucheEngine(syst, desc->language);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
SaveStateList ToucheMetaEngine::listSaves(const char *target) const {
|
||||
Common::String pattern = Touche::generateGameStateFileName(target, 0, true);
|
||||
Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern);
|
||||
bool slotsTable[Touche::kMaxSaveStates];
|
||||
memset(slotsTable, 0, sizeof(slotsTable));
|
||||
SaveStateList saveList;
|
||||
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
|
||||
int slot = Touche::getGameStateFileSlot(file->c_str());
|
||||
if (slot >= 0 && slot < Touche::kMaxSaveStates) {
|
||||
slotsTable[slot] = true;
|
||||
}
|
||||
}
|
||||
for (int slot = 0; slot < Touche::kMaxSaveStates; ++slot) {
|
||||
if (slotsTable[slot]) {
|
||||
Common::String file = Touche::generateGameStateFileName(target, slot);
|
||||
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(file);
|
||||
if (in) {
|
||||
char description[64];
|
||||
Touche::readGameStateDescription(in, description, sizeof(description) - 1);
|
||||
if (description[0]) {
|
||||
saveList.push_back(SaveStateDescriptor(this, slot, description));
|
||||
}
|
||||
delete in;
|
||||
}
|
||||
}
|
||||
}
|
||||
return saveList;
|
||||
}
|
||||
|
||||
int ToucheMetaEngine::getMaximumSaveSlot() const {
|
||||
return Touche::kMaxSaveStates - 1;
|
||||
}
|
||||
|
||||
bool ToucheMetaEngine::removeSaveState(const char *target, int slot) const {
|
||||
Common::String filename = Touche::generateGameStateFileName(target, slot);
|
||||
return g_system->getSavefileManager()->removeSavefile(filename);
|
||||
}
|
||||
|
||||
Common::KeymapArray ToucheMetaEngine::initKeymaps(const char *target) const {
|
||||
using namespace Common;
|
||||
using namespace Touche;
|
||||
|
||||
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "touche-default", "Default keymappings");
|
||||
Keymap *gameKeyMap = new Keymap(Keymap::kKeymapTypeGame, "game-shortcuts", _("Game keymappings"));
|
||||
Action *act;
|
||||
|
||||
act = new Action(kStandardActionLeftClick, _("Left click"));
|
||||
act->setLeftClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action(kStandardActionRightClick, _("Right click"));
|
||||
act->setRightClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_RIGHT");
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
{
|
||||
act = new Action("SKIPORQUIT", _("Skip sequence / open quit dialog"));
|
||||
act->setCustomEngineActionEvent(kToucheActionSkipOrQuit);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("SKIPDILOG", _("Skip dialog"));
|
||||
act->setCustomEngineActionEvent(kToucheActionSkipDialogue);
|
||||
act->addDefaultInputMapping("SPACE");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("OPTIONS", _("Open options menu"));
|
||||
act->setCustomEngineActionEvent(kToucheActionOpenOptions);
|
||||
act->addDefaultInputMapping("F5");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
// I18N: The actor walking pace is increased
|
||||
act = new Action("ENABLEFASTWALK", _("Enable fast walk"));
|
||||
act->setCustomEngineActionEvent(kToucheActionEnableFastWalk);
|
||||
act->addDefaultInputMapping("F9");
|
||||
act->addDefaultInputMapping("JOY_LEFT");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
// I18N: The actor walking pace is decreased
|
||||
act = new Action("DISABLEFASTWALK", _("Disable fast walk"));
|
||||
act->setCustomEngineActionEvent(kToucheActionDisableFastWalk);
|
||||
act->addDefaultInputMapping("F10");
|
||||
act->addDefaultInputMapping("JOY_LEFT_STICK");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("TGGLFASTMODE", _("Toggle fast mode"));
|
||||
act->setCustomEngineActionEvent(kToucheActionToggleFastMode);
|
||||
act->addDefaultInputMapping("C+f");
|
||||
act->addDefaultInputMapping("JOY_RIGHT_STICK");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("TGGLTALKTEXT", _("Toggle between voice / text / text and voice"));
|
||||
act->setCustomEngineActionEvent(kToucheActionToggleTalkTextMode);
|
||||
act->addDefaultInputMapping("t");
|
||||
act->addDefaultInputMapping("JOY_RIGHT");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
String s = ConfMan.get("language", target);
|
||||
Language l = Common::parseLanguage(s);
|
||||
|
||||
act = new Action("YES", _("Press \"Yes\" Key"));
|
||||
act->setCustomEngineActionEvent(kToucheActionYes);
|
||||
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
|
||||
switch (l) {
|
||||
case FR_FRA:
|
||||
act->addDefaultInputMapping("o");
|
||||
break;
|
||||
case DE_DEU:
|
||||
act->addDefaultInputMapping("j");
|
||||
break;
|
||||
case ES_ESP:
|
||||
act->addDefaultInputMapping("s");
|
||||
break;
|
||||
case PL_POL:
|
||||
act->addDefaultInputMapping("s");
|
||||
act->addDefaultInputMapping("t");
|
||||
break;
|
||||
default:
|
||||
act->addDefaultInputMapping("y");
|
||||
break;
|
||||
}
|
||||
gameKeyMap->addAction(act);
|
||||
}
|
||||
|
||||
KeymapArray keymaps(2);
|
||||
keymaps[0] = engineKeyMap;
|
||||
keymaps[1] = gameKeyMap;
|
||||
|
||||
return keymaps;
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(TOUCHE)
|
||||
REGISTER_PLUGIN_DYNAMIC(TOUCHE, PLUGIN_TYPE_ENGINE, ToucheMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(TOUCHE, PLUGIN_TYPE_ENGINE, ToucheMetaEngine);
|
||||
#endif
|
||||
107
engines/touche/midi.cpp
Normal file
107
engines/touche/midi.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/* 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 "common/stream.h"
|
||||
|
||||
#include "audio/midiparser.h"
|
||||
|
||||
#include "touche/midi.h"
|
||||
|
||||
namespace Touche {
|
||||
|
||||
static const uint8 _gmToRol[128] = {
|
||||
0x01, 0x02, 0x03, 0x08, 0x04, 0x05, 0x11, 0x14, 0x66, 0x66, 0x66, 0x62, 0x69, 0x68, 0x67, 0x26,
|
||||
0x09, 0x0A, 0x0B, 0x0E, 0x0F, 0x10, 0x10, 0x10, 0x3C, 0x3D, 0x3D, 0x3D, 0x3D, 0x3E, 0x3F, 0x3F,
|
||||
0x47, 0x41, 0x42, 0x48, 0x45, 0x46, 0x1D, 0x1E, 0x35, 0x36, 0x37, 0x39, 0x33, 0x34, 0x3A, 0x71,
|
||||
0x31, 0x32, 0x31, 0x32, 0x23, 0x23, 0x23, 0x7B, 0x59, 0x5B, 0x5F, 0x5A, 0x5D, 0x60, 0x19, 0x1A,
|
||||
0x4F, 0x50, 0x51, 0x52, 0x55, 0x56, 0x57, 0x53, 0x4B, 0x49, 0x4D, 0x4E, 0x6F, 0x6C, 0x6D, 0x6E,
|
||||
0x30, 0x19, 0x4E, 0x2B, 0x28, 0x23, 0x19, 0x30, 0x21, 0x25, 0x1C, 0x21, 0x24, 0x22, 0x21, 0x22,
|
||||
0x2A, 0x25, 0x24, 0x26, 0x2E, 0x22, 0x29, 0x21, 0x40, 0x40, 0x6A, 0x6A, 0x68, 0x10, 0x35, 0x10,
|
||||
0x7F, 0x6B, 0x69, 0x75, 0x76, 0x72, 0x74, 0x01, 0x01, 0x70, 0x01, 0x7D, 0x7C, 0x01, 0x01, 0x01
|
||||
};
|
||||
|
||||
|
||||
MidiPlayer::MidiPlayer() {
|
||||
|
||||
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
|
||||
_nativeMT32 = ((MidiDriver::getMusicType(dev) == MT_MT32) || ConfMan.getBool("native_mt32"));
|
||||
_driver = MidiDriver::createMidi(dev);
|
||||
int ret = _driver->open();
|
||||
if (ret == 0) {
|
||||
_driver->setTimerCallback(this, &timerCallback);
|
||||
|
||||
if (_nativeMT32)
|
||||
_driver->sendMT32Reset();
|
||||
else
|
||||
_driver->sendGMReset();
|
||||
}
|
||||
}
|
||||
|
||||
void MidiPlayer::play(Common::ReadStream &stream, int size, bool loop) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
stop();
|
||||
_midiData = (byte *)malloc(size);
|
||||
if (_midiData) {
|
||||
stream.read(_midiData, size);
|
||||
|
||||
_parser = MidiParser::createParser_SMF();
|
||||
_parser->setMidiDriver(this);
|
||||
_parser->setTimerRate(_driver->getBaseTempo());
|
||||
|
||||
_parser->loadMusic(_midiData, size);
|
||||
_parser->setTrack(0);
|
||||
_isLooping = loop;
|
||||
_isPlaying = true;
|
||||
}
|
||||
}
|
||||
|
||||
void MidiPlayer::adjustVolume(int diff) {
|
||||
setVolume(_masterVolume + diff);
|
||||
}
|
||||
|
||||
void MidiPlayer::setVolume(int volume) {
|
||||
// FIXME: This is almost identical to Audio::MidiPlayer::setVolume,
|
||||
// the only difference is that this implementation will always
|
||||
// transmit the volume change, even if the current _masterVolume
|
||||
// equals the new master volume. This *could* make a difference in
|
||||
// some situations.
|
||||
// So, we should determine whether the engine requires this behavioral
|
||||
// difference; and maybe also if other engines could benefit from it
|
||||
// (as hypothetically, it might fix some subtle bugs?)
|
||||
_masterVolume = CLIP(volume, 0, 255);
|
||||
Common::StackLock lock(_mutex);
|
||||
for (int i = 0; i < kNumChannels; ++i) {
|
||||
if (_channelsTable[i]) {
|
||||
_channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MidiPlayer::send(uint32 b) {
|
||||
if ((b & 0xF0) == 0xC0 && _nativeMT32) { // program change
|
||||
b = (b & 0xFFFF00FF) | (_gmToRol[(b >> 8) & 0x7F] << 8);
|
||||
}
|
||||
Audio::MidiPlayer::send(b);
|
||||
}
|
||||
|
||||
} // Touche namespace
|
||||
52
engines/touche/midi.h
Normal file
52
engines/touche/midi.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* 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 TOUCHE_MIDI_H
|
||||
#define TOUCHE_MIDI_H
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/mutex.h"
|
||||
|
||||
#include "audio/midiplayer.h"
|
||||
|
||||
class MidiParser;
|
||||
|
||||
namespace Common {
|
||||
class ReadStream;
|
||||
}
|
||||
|
||||
namespace Touche {
|
||||
|
||||
class MidiPlayer : public Audio::MidiPlayer {
|
||||
public:
|
||||
MidiPlayer();
|
||||
|
||||
void play(Common::ReadStream &stream, int size, bool loop = false);
|
||||
void adjustVolume(int diff);
|
||||
void setVolume(int volume) override;
|
||||
|
||||
// MidiDriver_BASE interface
|
||||
void send(uint32 b) override;
|
||||
};
|
||||
|
||||
} // namespace Touche
|
||||
|
||||
#endif
|
||||
24
engines/touche/module.mk
Normal file
24
engines/touche/module.mk
Normal file
@@ -0,0 +1,24 @@
|
||||
MODULE := engines/touche
|
||||
|
||||
MODULE_OBJS := \
|
||||
console.o \
|
||||
graphics.o \
|
||||
menu.o \
|
||||
metaengine.o \
|
||||
midi.o \
|
||||
opcodes.o \
|
||||
resource.o \
|
||||
saveload.o \
|
||||
staticres.o \
|
||||
touche.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_TOUCHE), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
1057
engines/touche/opcodes.cpp
Normal file
1057
engines/touche/opcodes.cpp
Normal file
File diff suppressed because it is too large
Load Diff
691
engines/touche/resource.cpp
Normal file
691
engines/touche/resource.cpp
Normal file
@@ -0,0 +1,691 @@
|
||||
/* 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 "audio/decoders/flac.h"
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/decoders/mp3.h"
|
||||
#include "audio/decoders/voc.h"
|
||||
#include "audio/decoders/vorbis.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
#include "touche/midi.h"
|
||||
#include "touche/touche.h"
|
||||
#include "touche/graphics.h"
|
||||
|
||||
namespace Touche {
|
||||
|
||||
enum {
|
||||
kCurrentSpeechDataVersion = 1,
|
||||
kSpeechDataFileHeaderSize = 4
|
||||
};
|
||||
|
||||
struct CompressedSpeechFile {
|
||||
const char *filename;
|
||||
Audio::SeekableAudioStream *(*makeStream)(
|
||||
Common::SeekableReadStream *stream,
|
||||
DisposeAfterUse::Flag disposeAfterUse);
|
||||
};
|
||||
|
||||
static const CompressedSpeechFile compressedSpeechFilesTable[] = {
|
||||
#ifdef USE_FLAC
|
||||
{ "TOUCHE.SOF", Audio::makeFLACStream },
|
||||
#endif
|
||||
#ifdef USE_VORBIS
|
||||
{ "TOUCHE.SOG", Audio::makeVorbisStream },
|
||||
#endif
|
||||
#ifdef USE_MAD
|
||||
{ "TOUCHE.SO3", Audio::makeMP3Stream },
|
||||
#endif
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
void ToucheEngine::res_openDataFile() {
|
||||
if (!_fData.open("TOUCHE.DAT")) {
|
||||
error("Unable to open 'TOUCHE.DAT' for reading");
|
||||
}
|
||||
for (int i = 0; compressedSpeechFilesTable[i].filename; ++i) {
|
||||
if (_fSpeech[0].open(compressedSpeechFilesTable[i].filename)) {
|
||||
int version = _fSpeech[0].readUint16LE();
|
||||
if (version == kCurrentSpeechDataVersion) {
|
||||
_compressedSpeechData = i;
|
||||
return;
|
||||
}
|
||||
warning("Unhandled version %d for compressed sound file '%s'", version, compressedSpeechFilesTable[i].filename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// _fSpeech[0] opening/closing is driven by the scripts
|
||||
_fSpeech[1].open("OBJ");
|
||||
_compressedSpeechData = -1;
|
||||
}
|
||||
|
||||
void ToucheEngine::res_closeDataFile() {
|
||||
res_stopSpeech(); // stop any pending speech before closing the underlying streams
|
||||
_fData.close();
|
||||
_fSpeech[0].close();
|
||||
_fSpeech[1].close();
|
||||
}
|
||||
|
||||
void ToucheEngine::res_allocateTables() {
|
||||
_fData.seek(64);
|
||||
uint32 textDataOffs = _fData.readUint32LE();
|
||||
uint32 textDataSize = _fData.readUint32LE();
|
||||
_textData = (uint8 *)malloc(textDataSize);
|
||||
if (!_textData) {
|
||||
error("Unable to allocate memory for text data");
|
||||
}
|
||||
_fData.seek(textDataOffs);
|
||||
_fData.read(_textData, textDataSize);
|
||||
|
||||
_fData.seek(2);
|
||||
const int bw = _fData.readUint16LE();
|
||||
const int bh = _fData.readUint16LE();
|
||||
uint32 size = bw * bh;
|
||||
_backdropBuffer = (uint8 *)malloc(size);
|
||||
if (!_backdropBuffer) {
|
||||
error("Unable to allocate memory for backdrop buffer");
|
||||
}
|
||||
|
||||
_menuKitData = (uint8 *)malloc(42 * 120);
|
||||
if (!_menuKitData) {
|
||||
error("Unable to allocate memory for menu kit data");
|
||||
}
|
||||
|
||||
_convKitData = (uint8 *)malloc(152 * 80);
|
||||
if (!_convKitData) {
|
||||
error("Unable to allocate memory for conv kit data");
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_SEQUENCES; ++i) {
|
||||
_sequenceDataTable[i] = (uint8 *)malloc(16384);
|
||||
if (!_sequenceDataTable[i]) {
|
||||
error("Unable to allocate memory for sequence data %d", i);
|
||||
}
|
||||
}
|
||||
|
||||
_programData = (uint8 *)malloc(kMaxProgramDataSize);
|
||||
if (!_programData) {
|
||||
error("Unable to allocate memory for program data");
|
||||
}
|
||||
|
||||
_mouseData = (uint8 *)malloc(kCursorWidth * kCursorHeight);
|
||||
if (!_mouseData) {
|
||||
error("Unable to allocate memory for mouse data");
|
||||
}
|
||||
|
||||
_iconData = (uint8 *)malloc(kIconWidth * kIconHeight);
|
||||
if (!_iconData) {
|
||||
error("Unable to allocate memory for object data");
|
||||
}
|
||||
|
||||
memset(_spritesTable, 0, sizeof(_spritesTable));
|
||||
|
||||
_offscreenBuffer = (uint8 *)malloc(kScreenWidth * kScreenHeight);
|
||||
if (!_offscreenBuffer) {
|
||||
error("Unable to allocate memory for offscreen buffer");
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::res_deallocateTables() {
|
||||
free(_textData);
|
||||
_textData = nullptr;
|
||||
|
||||
free(_backdropBuffer);
|
||||
_backdropBuffer = nullptr;
|
||||
|
||||
free(_menuKitData);
|
||||
_menuKitData = nullptr;
|
||||
|
||||
free(_convKitData);
|
||||
_convKitData = nullptr;
|
||||
|
||||
for (int i = 0; i < NUM_SEQUENCES; ++i) {
|
||||
free(_sequenceDataTable[i]);
|
||||
_sequenceDataTable[i] = nullptr;
|
||||
}
|
||||
|
||||
free(_programData);
|
||||
_programData = nullptr;
|
||||
|
||||
free(_mouseData);
|
||||
_mouseData = nullptr;
|
||||
|
||||
free(_iconData);
|
||||
_iconData = nullptr;
|
||||
|
||||
for (int i = 0; i < NUM_SPRITES; ++i) {
|
||||
free(_spritesTable[i].ptr);
|
||||
_spritesTable[i].ptr = nullptr;
|
||||
}
|
||||
|
||||
free(_offscreenBuffer);
|
||||
_offscreenBuffer = nullptr;
|
||||
}
|
||||
|
||||
uint32 ToucheEngine::res_getDataOffset(ResourceType type, int num, uint32 *size) {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_getDataOffset() type=%d num=%d", type, num);
|
||||
static const struct ResourceData {
|
||||
int offs;
|
||||
int count;
|
||||
int type;
|
||||
} dataTypesTable[] = {
|
||||
{ 0x048, 100, kResourceTypeRoomImage },
|
||||
{ 0x228, 30, kResourceTypeSequence },
|
||||
{ 0x2A0, 50, kResourceTypeSpriteImage },
|
||||
{ 0x390, 100, kResourceTypeIconImage },
|
||||
{ 0x6B0, 80, kResourceTypeRoomInfo },
|
||||
{ 0x908, 150, kResourceTypeProgram },
|
||||
{ 0xB60, 50, kResourceTypeMusic },
|
||||
{ 0xC28, 120, kResourceTypeSound }
|
||||
};
|
||||
|
||||
const ResourceData *rd = NULL;
|
||||
for (unsigned int i = 0; i < ARRAYSIZE(dataTypesTable); ++i) {
|
||||
if (dataTypesTable[i].type == type) {
|
||||
rd = &dataTypesTable[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rd == NULL) {
|
||||
error("Invalid resource type %d", type);
|
||||
}
|
||||
if (num < 0 || num > rd->count) {
|
||||
error("Invalid resource number %d (type %d)", num, type);
|
||||
}
|
||||
_fData.seek(rd->offs + num * 4);
|
||||
uint32 offs = _fData.readUint32LE();
|
||||
assert(offs != 0);
|
||||
if (size) {
|
||||
uint32 nextOffs = _fData.readUint32LE();
|
||||
*size = nextOffs - offs;
|
||||
}
|
||||
return offs;
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadSpriteImage(int num, uint8 *dst) {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_loadSpriteImage() num=%d", num);
|
||||
const uint32 offs = res_getDataOffset(kResourceTypeSpriteImage, num);
|
||||
_fData.seek(offs);
|
||||
_currentImageWidth = _fData.readUint16LE();
|
||||
_currentImageHeight = _fData.readUint16LE();
|
||||
for (int i = 0; i < _currentImageHeight; ++i) {
|
||||
res_decodeScanLineImageRLE(dst + _currentImageWidth * i, _currentImageWidth);
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadProgram(int num) {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_loadProgram() num=%d", num);
|
||||
const uint32 offs = res_getDataOffset(kResourceTypeProgram, num, &_programDataSize);
|
||||
_fData.seek(offs);
|
||||
assert(_programDataSize <= kMaxProgramDataSize);
|
||||
_fData.read(_programData, _programDataSize);
|
||||
}
|
||||
|
||||
void ToucheEngine::res_decodeProgramData() {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_decodeProgramData()");
|
||||
|
||||
uint8 *p;
|
||||
uint8 *programDataEnd = _programData + _programDataSize;
|
||||
|
||||
p = _programData + READ_LE_UINT32(_programData + 32);
|
||||
_script.init(p);
|
||||
|
||||
p = _programData + READ_LE_UINT32(_programData + 4);
|
||||
_programTextDataPtr = p;
|
||||
|
||||
_programRectsTable.clear();
|
||||
p = _programData + READ_LE_UINT32(_programData + 20);
|
||||
while (p < programDataEnd) {
|
||||
int16 x = READ_LE_UINT16(p); p += 2;
|
||||
int16 y = READ_LE_UINT16(p); p += 2;
|
||||
int16 w = READ_LE_UINT16(p); p += 2;
|
||||
int16 h = READ_LE_UINT16(p); p += 2;
|
||||
_programRectsTable.push_back(Common::Rect(x, y, x + w, y + h));
|
||||
if (x == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_programPointsTable.clear();
|
||||
p = _programData + READ_LE_UINT32(_programData + 24);
|
||||
while (p < programDataEnd) {
|
||||
ProgramPointData ppd;
|
||||
ppd.x = READ_LE_UINT16(p); p += 2;
|
||||
ppd.y = READ_LE_UINT16(p); p += 2;
|
||||
ppd.z = READ_LE_UINT16(p); p += 2;
|
||||
ppd.order = READ_LE_UINT16(p); p += 2;
|
||||
_programPointsTable.push_back(ppd);
|
||||
if (ppd.x == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_programWalkTable.clear();
|
||||
p = _programData + READ_LE_UINT32(_programData + 28);
|
||||
while (p < programDataEnd) {
|
||||
ProgramWalkData pwd;
|
||||
pwd.point1 = READ_LE_UINT16(p); p += 2;
|
||||
if (pwd.point1 == -1) {
|
||||
break;
|
||||
}
|
||||
assert((uint16)pwd.point1 < _programPointsTable.size());
|
||||
pwd.point2 = READ_LE_UINT16(p); p += 2;
|
||||
assert((uint16)pwd.point2 < _programPointsTable.size());
|
||||
pwd.clippingRect = READ_LE_UINT16(p); p += 2;
|
||||
pwd.area1 = READ_LE_UINT16(p); p += 2;
|
||||
pwd.area2 = READ_LE_UINT16(p); p += 2;
|
||||
p += 12; // unused
|
||||
_programWalkTable.push_back(pwd);
|
||||
}
|
||||
|
||||
_programAreaTable.clear();
|
||||
p = _programData + READ_LE_UINT32(_programData + 8);
|
||||
while (p < programDataEnd) {
|
||||
ProgramAreaData pad;
|
||||
int16 x = READ_LE_UINT16(p); p += 2;
|
||||
if (x == -1) {
|
||||
break;
|
||||
}
|
||||
int16 y = READ_LE_UINT16(p); p += 2;
|
||||
int16 w = READ_LE_UINT16(p); p += 2;
|
||||
int16 h = READ_LE_UINT16(p); p += 2;
|
||||
pad.area.r = Common::Rect(x, y, x + w, y + h);
|
||||
pad.area.srcX = READ_LE_UINT16(p); p += 2;
|
||||
pad.area.srcY = READ_LE_UINT16(p); p += 2;
|
||||
pad.id = READ_LE_UINT16(p); p += 2;
|
||||
pad.state = READ_LE_UINT16(p); p += 2;
|
||||
pad.animCount = READ_LE_UINT16(p); p += 2;
|
||||
pad.animNext = READ_LE_UINT16(p); p += 2;
|
||||
_programAreaTable.push_back(pad);
|
||||
}
|
||||
|
||||
_programBackgroundTable.clear();
|
||||
p = _programData + READ_LE_UINT32(_programData + 12);
|
||||
while (p < programDataEnd) {
|
||||
ProgramBackgroundData pbd;
|
||||
int16 x = READ_LE_UINT16(p); p += 2;
|
||||
if (x == -1) {
|
||||
break;
|
||||
}
|
||||
int16 y = READ_LE_UINT16(p); p += 2;
|
||||
int16 w = READ_LE_UINT16(p); p += 2;
|
||||
int16 h = READ_LE_UINT16(p); p += 2;
|
||||
pbd.area.r = Common::Rect(x, y, x + w, y + h);
|
||||
pbd.area.srcX = READ_LE_UINT16(p); p += 2;
|
||||
pbd.area.srcY = READ_LE_UINT16(p); p += 2;
|
||||
pbd.type = READ_LE_UINT16(p); p += 2;
|
||||
pbd.offset = READ_LE_UINT16(p); p += 2;
|
||||
pbd.scaleMul = READ_LE_UINT16(p); p += 2;
|
||||
pbd.scaleDiv = READ_LE_UINT16(p); p += 2;
|
||||
_programBackgroundTable.push_back(pbd);
|
||||
}
|
||||
|
||||
_programHitBoxTable.clear();
|
||||
p = _programData + READ_LE_UINT32(_programData + 16);
|
||||
while (p < programDataEnd) {
|
||||
ProgramHitBoxData phbd;
|
||||
phbd.item = READ_LE_UINT16(p); p += 2;
|
||||
if (phbd.item == 0) {
|
||||
break;
|
||||
}
|
||||
phbd.talk = READ_LE_UINT16(p); p += 2;
|
||||
phbd.state = READ_LE_UINT16(p); p += 2;
|
||||
phbd.str = READ_LE_UINT16(p); p += 2;
|
||||
phbd.defaultStr = READ_LE_UINT16(p); p += 2;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
phbd.actions[i] = READ_LE_UINT16(p); p += 2;
|
||||
}
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
int16 x = READ_LE_UINT16(p); p += 2;
|
||||
int16 y = READ_LE_UINT16(p); p += 2;
|
||||
int16 w = READ_LE_UINT16(p); p += 2;
|
||||
int16 h = READ_LE_UINT16(p); p += 2;
|
||||
phbd.hitBoxes[i].left = x;
|
||||
phbd.hitBoxes[i].top = y;
|
||||
phbd.hitBoxes[i].right = x + w;
|
||||
phbd.hitBoxes[i].bottom = y + h;
|
||||
}
|
||||
p += 8; // unused
|
||||
_programHitBoxTable.push_back(phbd);
|
||||
}
|
||||
|
||||
_programActionScriptOffsetTable.clear();
|
||||
p = _programData + READ_LE_UINT32(_programData + 36);
|
||||
while (p < programDataEnd) {
|
||||
ProgramActionScriptOffsetData pasod;
|
||||
pasod.object1 = READ_LE_UINT16(p); p += 2;
|
||||
if (pasod.object1 == 0) {
|
||||
break;
|
||||
}
|
||||
pasod.action = READ_LE_UINT16(p); p += 2;
|
||||
pasod.object2 = READ_LE_UINT16(p); p += 2;
|
||||
pasod.offset = READ_LE_UINT16(p); p += 2;
|
||||
_programActionScriptOffsetTable.push_back(pasod);
|
||||
}
|
||||
|
||||
_programConversationTable.clear();
|
||||
int count = (READ_LE_UINT32(_programData + 44) - READ_LE_UINT32(_programData + 40)) / 6;
|
||||
assert(count >= 0);
|
||||
p = _programData + READ_LE_UINT32(_programData + 40);
|
||||
while (p < programDataEnd && count != 0) {
|
||||
ProgramConversationData pcd;
|
||||
pcd.num = READ_LE_UINT16(p); p += 2;
|
||||
pcd.offset = READ_LE_UINT16(p); p += 2;
|
||||
pcd.msg = READ_LE_UINT16(p); p += 2;
|
||||
_programConversationTable.push_back(pcd);
|
||||
--count;
|
||||
}
|
||||
|
||||
_programKeyCharScriptOffsetTable.clear();
|
||||
p = _programData + READ_LE_UINT32(_programData + 44);
|
||||
while (p < programDataEnd) {
|
||||
ProgramKeyCharScriptOffsetData pksod;
|
||||
pksod.keyChar = READ_LE_UINT16(p); p += 2;
|
||||
if (pksod.keyChar == 0) {
|
||||
break;
|
||||
}
|
||||
pksod.offset = READ_LE_UINT16(p); p += 2;
|
||||
_programKeyCharScriptOffsetTable.push_back(pksod);
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadRoom(int num) {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_loadRoom() num=%d flag115=%d", num, _flagsTable[115]);
|
||||
|
||||
debug(0, "Setting up room %d", num);
|
||||
|
||||
const uint32 offsInfo = res_getDataOffset(kResourceTypeRoomInfo, num);
|
||||
_fData.seek(offsInfo);
|
||||
_fData.skip(2);
|
||||
const int roomImageNum = _fData.readUint16LE();
|
||||
_fData.skip(2);
|
||||
_fData.read(_paletteBuffer, 3 * 256);
|
||||
|
||||
const uint32 offsImage = res_getDataOffset(kResourceTypeRoomImage, roomImageNum);
|
||||
_fData.seek(offsImage);
|
||||
res_loadBackdrop();
|
||||
|
||||
bool updateScreenPalette = _flagsTable[115] == 0;
|
||||
|
||||
// Workaround to what appears to be a scripting bug. Scripts 27 and 100 triggers
|
||||
// a palette fading just after loading a room. Catch this, so that only *one*
|
||||
// palette refresh occurs.
|
||||
if ((_currentEpisodeNum == 27 && _currentRoomNum == 56 && num == 34) ||
|
||||
(_currentEpisodeNum == 100 && _currentRoomNum == 2 && num == 1)) {
|
||||
updateScreenPalette = false;
|
||||
}
|
||||
|
||||
if (updateScreenPalette) {
|
||||
updatePalette();
|
||||
} else {
|
||||
setPalette(0, 255, 0, 0, 0);
|
||||
}
|
||||
|
||||
_currentRoomNum = num;
|
||||
_updatedRoomAreasTable[0] = 1;
|
||||
|
||||
_fullRedrawCounter = 1;
|
||||
_roomNeedRedraw = true;
|
||||
|
||||
_sequenceEntryTable[5].sprNum = -1;
|
||||
_sequenceEntryTable[5].seqNum = -1;
|
||||
_sequenceEntryTable[6].sprNum = -1;
|
||||
_sequenceEntryTable[6].seqNum = -1;
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadSprite(int num, int index) {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_loadSprite() num=%d index=%d", num, index);
|
||||
assert(index >= 0 && index < NUM_SEQUENCES);
|
||||
_sequenceEntryTable[index].sprNum = num;
|
||||
SpriteData *spr = &_spritesTable[index];
|
||||
const uint32 offs = res_getDataOffset(kResourceTypeSpriteImage, num);
|
||||
_fData.seek(offs);
|
||||
_currentImageWidth = _fData.readUint16LE();
|
||||
_currentImageHeight = _fData.readUint16LE();
|
||||
const uint32 size = _currentImageWidth * _currentImageHeight;
|
||||
if (size > spr->size) {
|
||||
debug(8, "Reallocating memory for sprite %d (index %d), %d bytes needed", num, index, size - spr->size);
|
||||
spr->size = size;
|
||||
|
||||
uint8 *buffer = NULL;
|
||||
if (spr->ptr)
|
||||
buffer = (uint8 *)realloc(spr->ptr, size);
|
||||
|
||||
if (!buffer) {
|
||||
// Free previously allocated sprite (when realloc failed)
|
||||
free(spr->ptr);
|
||||
|
||||
buffer = (uint8 *)malloc(size);
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
error("[ToucheEngine::res_loadSprite] Unable to reallocate memory for sprite %d (%d bytes)", num, size);
|
||||
|
||||
spr->ptr = buffer;
|
||||
}
|
||||
for (int i = 0; i < _currentImageHeight; ++i) {
|
||||
res_decodeScanLineImageRLE(spr->ptr + _currentImageWidth * i, _currentImageWidth);
|
||||
}
|
||||
spr->bitmapWidth = _currentImageWidth;
|
||||
spr->bitmapHeight = _currentImageHeight;
|
||||
if (_flagsTable[268] == 0) {
|
||||
res_loadImageHelper(spr->ptr, _currentImageWidth, _currentImageHeight);
|
||||
}
|
||||
spr->w = _currentImageWidth;
|
||||
spr->h = _currentImageHeight;
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadSequence(int num, int index) {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_loadSequence() num=%d index=%d", num, index);
|
||||
assert(index < NUM_SEQUENCES);
|
||||
_sequenceEntryTable[index].seqNum = num;
|
||||
const uint32 offs = res_getDataOffset(kResourceTypeSequence, num);
|
||||
_fData.seek(offs);
|
||||
_fData.read(_sequenceDataTable[index], 16000);
|
||||
}
|
||||
|
||||
void ToucheEngine::res_decodeScanLineImageRLE(uint8 *dst, int lineWidth) {
|
||||
int w = 0;
|
||||
while (w < lineWidth) {
|
||||
uint8 code = _fData.readByte();
|
||||
if ((code & 0xC0) == 0xC0) {
|
||||
int len = code & 0x3F;
|
||||
uint8 color = _fData.readByte();
|
||||
memset(dst, color, len);
|
||||
dst += len;
|
||||
w += len;
|
||||
} else {
|
||||
*dst = code;
|
||||
++dst;
|
||||
++w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadBackdrop() {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_loadBackdrop()");
|
||||
_currentBitmapWidth = _fData.readUint16LE();
|
||||
_currentBitmapHeight = _fData.readUint16LE();
|
||||
for (int i = 0; i < _currentBitmapHeight; ++i) {
|
||||
res_decodeScanLineImageRLE(_backdropBuffer + _currentBitmapWidth * i, _currentBitmapWidth);
|
||||
}
|
||||
_roomWidth = _currentBitmapWidth;
|
||||
for (int i = 0; i < _currentBitmapWidth; ++i) {
|
||||
if (_backdropBuffer[i] == 255) {
|
||||
_roomWidth = i;
|
||||
_backdropBuffer[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Workaround for bug #3305 (original bitmap has a white pixel in its transparent area).
|
||||
if (_currentRoomNum == 8 && _currentBitmapWidth == 860) {
|
||||
_backdropBuffer[120 * _currentBitmapWidth + 734] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadImage(int num, uint8 *dst) {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_loadImage() num=%d", num);
|
||||
const uint32 offsInfo = res_getDataOffset(kResourceTypeIconImage, num);
|
||||
_fData.seek(offsInfo);
|
||||
_currentImageWidth = _fData.readUint16LE();
|
||||
_currentImageHeight = _fData.readUint16LE();
|
||||
for (int i = 0; i < _currentImageHeight; ++i) {
|
||||
res_decodeScanLineImageRLE(dst + _currentImageWidth * i, _currentImageWidth);
|
||||
}
|
||||
res_loadImageHelper(dst, _currentImageWidth, _currentImageHeight);
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadImageHelper(uint8 *imgData, int imgWidth, int imgHeight) {
|
||||
uint8 *p = imgData;
|
||||
for (_currentImageHeight = 0; _currentImageHeight < imgHeight; ++_currentImageHeight, p += imgWidth) {
|
||||
if (*p == 64 || *p == 255) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
p = imgData;
|
||||
for (_currentImageWidth = 0; _currentImageWidth < imgWidth; ++_currentImageWidth, ++p) {
|
||||
if (*p == 64 || *p == 255) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_flagsTable[267] == 0) {
|
||||
for (int i = 0; i < imgWidth * imgHeight; ++i) {
|
||||
uint8 color = imgData[i];
|
||||
if (color != 0) {
|
||||
if (color < 64) {
|
||||
color += 192;
|
||||
} else {
|
||||
color = 0;
|
||||
}
|
||||
}
|
||||
imgData[i] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadSound(int priority, int num) {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_loadSound() num=%d", num);
|
||||
if (priority >= 0) {
|
||||
uint32 size;
|
||||
const uint32 offs = res_getDataOffset(kResourceTypeSound, num, &size);
|
||||
Common::SeekableReadStream *datastream = SearchMan.createReadStreamForMember("TOUCHE.DAT");
|
||||
if (!datastream) {
|
||||
warning("res_loadSound: Could not open TOUCHE.DAT");
|
||||
return;
|
||||
}
|
||||
|
||||
datastream->seek(offs);
|
||||
Audio::AudioStream *stream = Audio::makeVOCStream(datastream, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
|
||||
if (stream) {
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::res_stopSound() {
|
||||
_mixer->stopHandle(_sfxHandle);
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadMusic(int num) {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_loadMusic() num=%d", num);
|
||||
startMusic(num);
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadSpeech(int num) {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_loadSpeech() num=%d", num);
|
||||
if (num == -1) {
|
||||
res_stopSpeech();
|
||||
} else {
|
||||
if (_compressedSpeechData < 0) { // uncompressed speech data
|
||||
if (_fSpeech[0].isOpen()) {
|
||||
_fSpeech[0].close();
|
||||
}
|
||||
Common::String filenameStr = Common::String::format("V%d", num);
|
||||
_fSpeech[0].open(filenameStr.c_str());
|
||||
}
|
||||
if (_fSpeech[0].isOpen()) {
|
||||
_flagsTable[617] = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::res_loadSpeechSegment(int num) {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_loadSpeechSegment() num=%d", num);
|
||||
if (_talkTextMode != kTalkModeTextOnly && _flagsTable[617] != 0) {
|
||||
Audio::AudioStream *stream = 0;
|
||||
if (_compressedSpeechData < 0) { // uncompressed speech data
|
||||
int i = 0;
|
||||
if (num >= 750) {
|
||||
num -= 750;
|
||||
i = 1;
|
||||
}
|
||||
if (!_fSpeech[i].isOpen()) {
|
||||
return;
|
||||
}
|
||||
_fSpeech[i].seek(num * 8);
|
||||
uint32 offs = _fSpeech[i].readUint32LE();
|
||||
uint32 size = _fSpeech[i].readUint32LE();
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
_fSpeech[i].seek(offs);
|
||||
stream = Audio::makeVOCStream(&_fSpeech[i], Audio::FLAG_UNSIGNED);
|
||||
} else {
|
||||
if (num >= 750) {
|
||||
num -= 750;
|
||||
_fSpeech[0].seek(kSpeechDataFileHeaderSize);
|
||||
} else {
|
||||
assert(_flagsTable[617] > 0 && _flagsTable[617] < 140);
|
||||
_fSpeech[0].seek(kSpeechDataFileHeaderSize + _flagsTable[617] * 4);
|
||||
}
|
||||
uint32 dataOffs = _fSpeech[0].readUint32LE();
|
||||
if (dataOffs == 0) {
|
||||
return;
|
||||
}
|
||||
_fSpeech[0].seek(dataOffs + num * 8);
|
||||
uint32 offs = _fSpeech[0].readUint32LE();
|
||||
uint32 size = _fSpeech[0].readUint32LE();
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
_fSpeech[0].seek(offs);
|
||||
Common::SeekableReadStream *tmp = _fSpeech[0].readStream(size);
|
||||
if (tmp)
|
||||
stream = (compressedSpeechFilesTable[_compressedSpeechData].makeStream)(tmp, DisposeAfterUse::YES);
|
||||
}
|
||||
if (stream) {
|
||||
_speechPlaying = true;
|
||||
_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ToucheEngine::res_stopSpeech() {
|
||||
debugC(9, kDebugResource, "ToucheEngine::res_stopSpeech()");
|
||||
_mixer->stopHandle(_speechHandle);
|
||||
_speechPlaying = false;
|
||||
}
|
||||
|
||||
} // namespace Touche
|
||||
396
engines/touche/saveload.cpp
Normal file
396
engines/touche/saveload.cpp
Normal file
@@ -0,0 +1,396 @@
|
||||
/* 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 "common/savefile.h"
|
||||
|
||||
#include "touche/graphics.h"
|
||||
#include "touche/touche.h"
|
||||
|
||||
namespace Touche {
|
||||
|
||||
enum {
|
||||
kGameStateDescriptionLen = 32,
|
||||
kCurrentGameStateVersion = 6
|
||||
};
|
||||
|
||||
static void saveOrLoad(Common::WriteStream &stream, uint16 &i) {
|
||||
stream.writeUint16LE(i);
|
||||
}
|
||||
|
||||
static void saveOrLoad(Common::ReadStream &stream, uint16 &i) {
|
||||
i = stream.readUint16LE();
|
||||
}
|
||||
|
||||
static void saveOrLoad(Common::WriteStream &stream, int16 &i) {
|
||||
stream.writeSint16LE(i);
|
||||
}
|
||||
|
||||
static void saveOrLoad(Common::ReadStream &stream, int16 &i) {
|
||||
i = stream.readSint16LE();
|
||||
}
|
||||
|
||||
static void saveOrLoadPtr(Common::WriteStream &stream, int16 *&p, int16 *base) {
|
||||
int32 offset = (int32)(p - base);
|
||||
stream.writeSint32LE(offset);
|
||||
}
|
||||
|
||||
static void saveOrLoadPtr(Common::ReadStream &stream, int16 *&p, int16 *base) {
|
||||
int32 offset = stream.readSint32LE();
|
||||
p = base + offset;
|
||||
}
|
||||
|
||||
template<class S>
|
||||
static void saveOrLoad(S &s, Common::Rect &r) {
|
||||
saveOrLoad(s, r.left);
|
||||
saveOrLoad(s, r.top);
|
||||
saveOrLoad(s, r.right);
|
||||
saveOrLoad(s, r.bottom);
|
||||
}
|
||||
|
||||
template<class S>
|
||||
static void saveOrLoad(S &s, SequenceEntry &seq) {
|
||||
saveOrLoad(s, seq.sprNum);
|
||||
saveOrLoad(s, seq.seqNum);
|
||||
}
|
||||
|
||||
template<class S>
|
||||
static void saveOrLoad(S &s, KeyChar &key) {
|
||||
saveOrLoad(s, key.num);
|
||||
saveOrLoad(s, key.flags);
|
||||
saveOrLoad(s, key.currentAnimCounter);
|
||||
saveOrLoad(s, key.strNum);
|
||||
saveOrLoad(s, key.walkDataNum);
|
||||
saveOrLoad(s, key.spriteNum);
|
||||
saveOrLoad(s, key.prevBoundingRect);
|
||||
saveOrLoad(s, key.boundingRect);
|
||||
saveOrLoad(s, key.xPos);
|
||||
saveOrLoad(s, key.yPos);
|
||||
saveOrLoad(s, key.zPos);
|
||||
saveOrLoad(s, key.xPosPrev);
|
||||
saveOrLoad(s, key.yPosPrev);
|
||||
saveOrLoad(s, key.zPosPrev);
|
||||
saveOrLoad(s, key.prevWalkDataNum);
|
||||
saveOrLoad(s, key.textColor);
|
||||
for (uint i = 0; i < 4; ++i) {
|
||||
saveOrLoad(s, key.inventoryItems[i]);
|
||||
}
|
||||
saveOrLoad(s, key.money);
|
||||
saveOrLoad(s, key.pointsDataNum);
|
||||
saveOrLoad(s, key.currentWalkBox);
|
||||
saveOrLoad(s, key.prevPointsDataNum);
|
||||
saveOrLoad(s, key.currentAnim);
|
||||
saveOrLoad(s, key.facingDirection);
|
||||
saveOrLoad(s, key.currentAnimSpeed);
|
||||
for (uint i = 0; i < 16; ++i) {
|
||||
saveOrLoad(s, key.framesList[i]);
|
||||
}
|
||||
saveOrLoad(s, key.framesListCount);
|
||||
saveOrLoad(s, key.currentFrame);
|
||||
saveOrLoad(s, key.anim1Start);
|
||||
saveOrLoad(s, key.anim1Count);
|
||||
saveOrLoad(s, key.anim2Start);
|
||||
saveOrLoad(s, key.anim2Count);
|
||||
saveOrLoad(s, key.anim3Start);
|
||||
saveOrLoad(s, key.anim3Count);
|
||||
saveOrLoad(s, key.followingKeyCharNum);
|
||||
saveOrLoad(s, key.followingKeyCharPos);
|
||||
saveOrLoad(s, key.sequenceDataIndex);
|
||||
saveOrLoad(s, key.sequenceDataOffset);
|
||||
saveOrLoad(s, key.walkPointsListIndex);
|
||||
for (uint i = 0; i < 40; ++i) {
|
||||
saveOrLoad(s, key.walkPointsList[i]);
|
||||
}
|
||||
saveOrLoad(s, key.scriptDataStartOffset);
|
||||
saveOrLoad(s, key.scriptDataOffset);
|
||||
saveOrLoadPtr(s, key.scriptStackPtr, &key.scriptStackTable[39]);
|
||||
saveOrLoad(s, key.delay);
|
||||
saveOrLoad(s, key.waitingKeyChar);
|
||||
for (uint i = 0; i < 3; ++i) {
|
||||
saveOrLoad(s, key.waitingKeyCharPosTable[i]);
|
||||
}
|
||||
for (uint i = 0; i < 40; ++i) {
|
||||
saveOrLoad(s, key.scriptStackTable[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<class S>
|
||||
static void saveOrLoad(S &s, TalkEntry &entry) {
|
||||
saveOrLoad(s, entry.otherKeyChar);
|
||||
saveOrLoad(s, entry.talkingKeyChar);
|
||||
saveOrLoad(s, entry.num);
|
||||
}
|
||||
|
||||
template<class S>
|
||||
static void saveOrLoad(S &s, ProgramHitBoxData &data) {
|
||||
saveOrLoad(s, data.item);
|
||||
saveOrLoad(s, data.talk);
|
||||
saveOrLoad(s, data.state);
|
||||
saveOrLoad(s, data.str);
|
||||
saveOrLoad(s, data.defaultStr);
|
||||
for (uint i = 0; i < 8; ++i) {
|
||||
saveOrLoad(s, data.actions[i]);
|
||||
}
|
||||
for (uint i = 0; i < 2; ++i) {
|
||||
saveOrLoad(s, data.hitBoxes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<class S>
|
||||
static void saveOrLoad(S &s, Area &area) {
|
||||
saveOrLoad(s, area.r);
|
||||
saveOrLoad(s, area.srcX);
|
||||
saveOrLoad(s, area.srcY);
|
||||
}
|
||||
|
||||
template<class S>
|
||||
static void saveOrLoad(S &s, ProgramBackgroundData &data) {
|
||||
saveOrLoad(s, data.area);
|
||||
saveOrLoad(s, data.type);
|
||||
saveOrLoad(s, data.offset);
|
||||
saveOrLoad(s, data.scaleMul);
|
||||
saveOrLoad(s, data.scaleDiv);
|
||||
}
|
||||
|
||||
template<class S>
|
||||
static void saveOrLoad(S &s, ProgramAreaData &data) {
|
||||
saveOrLoad(s, data.area);
|
||||
saveOrLoad(s, data.id);
|
||||
saveOrLoad(s, data.state);
|
||||
saveOrLoad(s, data.animCount);
|
||||
saveOrLoad(s, data.animNext);
|
||||
}
|
||||
|
||||
template<class S>
|
||||
static void saveOrLoad(S &s, ProgramWalkData &data) {
|
||||
saveOrLoad(s, data.point1);
|
||||
saveOrLoad(s, data.point2);
|
||||
saveOrLoad(s, data.clippingRect);
|
||||
saveOrLoad(s, data.area1);
|
||||
saveOrLoad(s, data.area2);
|
||||
}
|
||||
|
||||
template<class S>
|
||||
static void saveOrLoad(S &s, ProgramPointData &data) {
|
||||
saveOrLoad(s, data.x);
|
||||
saveOrLoad(s, data.y);
|
||||
saveOrLoad(s, data.z);
|
||||
saveOrLoad(s, data.order);
|
||||
}
|
||||
|
||||
template<class A>
|
||||
static void saveOrLoadCommonArray(Common::WriteStream &stream, A &array) {
|
||||
uint count = array.size();
|
||||
assert(count < 0xFFFF);
|
||||
stream.writeUint16LE(count);
|
||||
for (uint i = 0; i < count; ++i) {
|
||||
saveOrLoad(stream, array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<class A>
|
||||
static void saveOrLoadCommonArray(Common::ReadStream &stream, A &array) {
|
||||
uint count = stream.readUint16LE();
|
||||
if (count == array.size()) {
|
||||
for (uint i = 0; i < count; ++i) {
|
||||
saveOrLoad(stream, array[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class S, class A>
|
||||
static void saveOrLoadStaticArray(S &s, A &array, uint count) {
|
||||
for (uint i = 0; i < count; ++i) {
|
||||
saveOrLoad(s, array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static const uint32 saveLoadEndMarker = 0x55AA55AA;
|
||||
|
||||
void ToucheEngine::saveGameStateData(Common::WriteStream *stream) {
|
||||
setKeyCharMoney();
|
||||
stream->writeUint16LE(_currentEpisodeNum);
|
||||
stream->writeUint16LE(_currentMusicNum);
|
||||
stream->writeUint16LE(_currentRoomNum);
|
||||
stream->writeUint16LE(_flagsTable[614]);
|
||||
stream->writeUint16LE(_flagsTable[615]);
|
||||
stream->writeUint16LE(_disabledInputCounter);
|
||||
saveOrLoadCommonArray(*stream, _programHitBoxTable);
|
||||
saveOrLoadCommonArray(*stream, _programBackgroundTable);
|
||||
saveOrLoadCommonArray(*stream, _programAreaTable);
|
||||
saveOrLoadCommonArray(*stream, _programWalkTable);
|
||||
saveOrLoadCommonArray(*stream, _programPointsTable);
|
||||
stream->write(_updatedRoomAreasTable, 200);
|
||||
saveOrLoadStaticArray(*stream, _sequenceEntryTable, NUM_SEQUENCES);
|
||||
saveOrLoadStaticArray(*stream, _flagsTable, 1024);
|
||||
saveOrLoadStaticArray(*stream, _inventoryList1, 100);
|
||||
saveOrLoadStaticArray(*stream, _inventoryList2, 100);
|
||||
saveOrLoadStaticArray(*stream, _inventoryList3, 6);
|
||||
saveOrLoadStaticArray(*stream, _keyCharsTable, NUM_KEYCHARS);
|
||||
saveOrLoadStaticArray(*stream, _inventoryItemsInfoTable, NUM_INVENTORY_ITEMS);
|
||||
saveOrLoadStaticArray(*stream, _talkTable, NUM_TALK_ENTRIES);
|
||||
stream->writeUint16LE(_talkListEnd);
|
||||
stream->writeUint16LE(_talkListCurrent);
|
||||
stream->writeUint32LE(saveLoadEndMarker);
|
||||
}
|
||||
|
||||
void ToucheEngine::loadGameStateData(Common::ReadStream *stream) {
|
||||
setKeyCharMoney();
|
||||
clearDirtyRects();
|
||||
_flagsTable[115] = 0;
|
||||
clearRoomArea();
|
||||
_currentEpisodeNum = stream->readUint16LE();
|
||||
_newMusicNum = stream->readUint16LE();
|
||||
_currentRoomNum = stream->readUint16LE();
|
||||
res_loadRoom(_currentRoomNum);
|
||||
int16 roomOffsX = _flagsTable[614] = stream->readUint16LE();
|
||||
int16 roomOffsY = _flagsTable[615] = stream->readUint16LE();
|
||||
_disabledInputCounter = stream->readUint16LE();
|
||||
res_loadProgram(_currentEpisodeNum);
|
||||
setupEpisode(-1);
|
||||
saveOrLoadCommonArray(*stream, _programHitBoxTable);
|
||||
saveOrLoadCommonArray(*stream, _programBackgroundTable);
|
||||
saveOrLoadCommonArray(*stream, _programAreaTable);
|
||||
saveOrLoadCommonArray(*stream, _programWalkTable);
|
||||
saveOrLoadCommonArray(*stream, _programPointsTable);
|
||||
stream->read(_updatedRoomAreasTable, 200);
|
||||
for (uint i = 1; i < _updatedRoomAreasTable[0]; ++i) {
|
||||
updateRoomAreas(_updatedRoomAreasTable[i], -1);
|
||||
}
|
||||
saveOrLoadStaticArray(*stream, _sequenceEntryTable, NUM_SEQUENCES);
|
||||
saveOrLoadStaticArray(*stream, _flagsTable, 1024);
|
||||
saveOrLoadStaticArray(*stream, _inventoryList1, 100);
|
||||
saveOrLoadStaticArray(*stream, _inventoryList2, 100);
|
||||
saveOrLoadStaticArray(*stream, _inventoryList3, 6);
|
||||
saveOrLoadStaticArray(*stream, _keyCharsTable, NUM_KEYCHARS);
|
||||
saveOrLoadStaticArray(*stream, _inventoryItemsInfoTable, NUM_INVENTORY_ITEMS);
|
||||
saveOrLoadStaticArray(*stream, _talkTable, NUM_TALK_ENTRIES);
|
||||
_talkListEnd = stream->readUint16LE();
|
||||
_talkListCurrent = stream->readUint16LE();
|
||||
if (stream->readUint32LE() != saveLoadEndMarker) {
|
||||
warning("Corrupted gamestate data");
|
||||
// if that ever happens, exit the game
|
||||
quitGame();
|
||||
}
|
||||
_flagsTable[614] = roomOffsX;
|
||||
_flagsTable[615] = roomOffsY;
|
||||
for (uint i = 0; i < NUM_SEQUENCES; ++i) {
|
||||
if (_sequenceEntryTable[i].seqNum != -1) {
|
||||
res_loadSequence(_sequenceEntryTable[i].seqNum, i);
|
||||
}
|
||||
if (_sequenceEntryTable[i].sprNum != -1) {
|
||||
res_loadSprite(_sequenceEntryTable[i].sprNum, i);
|
||||
}
|
||||
}
|
||||
_currentKeyCharNum = _flagsTable[104];
|
||||
_inventoryStateTable[0].displayOffset = 0;
|
||||
_inventoryStateTable[1].displayOffset = 0;
|
||||
_inventoryStateTable[2].displayOffset = 0;
|
||||
drawInventory(_currentKeyCharNum, 1);
|
||||
Graphics::copyRect(_offscreenBuffer, kScreenWidth, 0, 0,
|
||||
_backdropBuffer, _currentBitmapWidth, _flagsTable[614], _flagsTable[615],
|
||||
kScreenWidth, kRoomHeight);
|
||||
updateRoomRegions();
|
||||
_fullRedrawCounter = 1;
|
||||
_roomNeedRedraw = false;
|
||||
if (_flagsTable[617] != 0) {
|
||||
res_loadSpeech(_flagsTable[617]);
|
||||
}
|
||||
debug(0, "Loaded state, current episode %d", _currentEpisodeNum);
|
||||
}
|
||||
|
||||
Common::Error ToucheEngine::saveGameState(int num, const Common::String &description, bool isAutosave) {
|
||||
bool saveOk = false;
|
||||
Common::String gameStateFileName = generateGameStateFileName(_targetName.c_str(), num);
|
||||
Common::OutSaveFile *f = _saveFileMan->openForSaving(gameStateFileName);
|
||||
if (f) {
|
||||
f->writeUint16LE(kCurrentGameStateVersion);
|
||||
f->writeUint16LE(0);
|
||||
char headerDescription[kGameStateDescriptionLen];
|
||||
memset(headerDescription, 0, kGameStateDescriptionLen);
|
||||
strncpy(headerDescription, description.c_str(), kGameStateDescriptionLen - 1);
|
||||
f->write(headerDescription, kGameStateDescriptionLen);
|
||||
saveGameStateData(f);
|
||||
f->finalize();
|
||||
if (!f->err()) {
|
||||
saveOk = true;
|
||||
} else {
|
||||
warning("Can't write file '%s'", gameStateFileName.c_str());
|
||||
}
|
||||
delete f;
|
||||
}
|
||||
return saveOk ? Common::kNoError : Common::kUnknownError;
|
||||
}
|
||||
|
||||
Common::Error ToucheEngine::loadGameState(int num) {
|
||||
bool loadOk = false;
|
||||
Common::String gameStateFileName = generateGameStateFileName(_targetName.c_str(), num);
|
||||
Common::InSaveFile *f = _saveFileMan->openForLoading(gameStateFileName);
|
||||
if (f) {
|
||||
uint16 version = f->readUint16LE();
|
||||
if (version < kCurrentGameStateVersion) {
|
||||
warning("Unsupported gamestate version %d (index %d)", version, num);
|
||||
} else {
|
||||
f->skip(2 + kGameStateDescriptionLen);
|
||||
loadGameStateData(f);
|
||||
if (f->err() || f->eos()) {
|
||||
warning("Can't read file '%s'", gameStateFileName.c_str());
|
||||
} else {
|
||||
loadOk = true;
|
||||
}
|
||||
}
|
||||
delete f;
|
||||
}
|
||||
return loadOk ? Common::kNoError : Common::kUnknownError;
|
||||
}
|
||||
|
||||
void readGameStateDescription(Common::ReadStream *f, char *description, int len) {
|
||||
uint16 version = f->readUint16LE();
|
||||
if (version >= kCurrentGameStateVersion) {
|
||||
f->readUint16LE();
|
||||
f->read(description, MIN<int>(len, kGameStateDescriptionLen));
|
||||
description[len] = 0;
|
||||
} else {
|
||||
description[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Common::String generateGameStateFileName(const char *target, int slot, bool prefixOnly) {
|
||||
Common::String name(target);
|
||||
if (prefixOnly) {
|
||||
name += ".*";
|
||||
} else {
|
||||
name += Common::String::format(".%d", slot);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
int getGameStateFileSlot(const char *filename) {
|
||||
int i = -1;
|
||||
const char *slot = strrchr(filename, '.');
|
||||
if (slot) {
|
||||
i = atoi(slot + 1);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
} // namespace Touche
|
||||
2268
engines/touche/staticres.cpp
Normal file
2268
engines/touche/staticres.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3497
engines/touche/touche.cpp
Normal file
3497
engines/touche/touche.cpp
Normal file
File diff suppressed because it is too large
Load Diff
958
engines/touche/touche.h
Normal file
958
engines/touche/touche.h
Normal file
@@ -0,0 +1,958 @@
|
||||
/* 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 TOUCHE_TOUCHE_H
|
||||
#define TOUCHE_TOUCHE_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/file.h"
|
||||
#include "common/random.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
#include "engines/engine.h"
|
||||
|
||||
#include "touche/console.h"
|
||||
|
||||
/**
|
||||
* This is the namespace of the Touche engine.
|
||||
*
|
||||
* Status of this engine: ???
|
||||
*
|
||||
* Games using this engine:
|
||||
* - Touché: The Adventures of the Fifth Musketeer
|
||||
*/
|
||||
namespace Touche {
|
||||
|
||||
enum TOUCHEAction {
|
||||
kToucheActionNone,
|
||||
kToucheActionYes,
|
||||
kToucheActionSkipOrQuit,
|
||||
kToucheActionOpenOptions,
|
||||
kToucheActionEnableFastWalk,
|
||||
kToucheActionDisableFastWalk,
|
||||
kToucheActionToggleFastMode,
|
||||
kToucheActionToggleTalkTextMode,
|
||||
kToucheActionSkipDialogue
|
||||
};
|
||||
|
||||
struct Area {
|
||||
Common::Rect r;
|
||||
int16 srcX, srcY;
|
||||
|
||||
Area() {
|
||||
srcX = srcY = 0;
|
||||
}
|
||||
|
||||
Area(int16 x, int16 y, int16 w, int16 h) {
|
||||
r = Common::Rect(x, y, x + w, y + h);
|
||||
srcX = srcY = 0;
|
||||
}
|
||||
|
||||
bool clip(const Common::Rect &rect) {
|
||||
const int dx = r.left - rect.left;
|
||||
if (dx < 0) {
|
||||
srcX -= dx;
|
||||
}
|
||||
const int dy = r.top - rect.top;
|
||||
if (dy < 0) {
|
||||
srcY -= dy;
|
||||
}
|
||||
if (rect.left > r.left) {
|
||||
r.left = rect.left;
|
||||
}
|
||||
if (rect.top > r.top) {
|
||||
r.top = rect.top;
|
||||
}
|
||||
if (rect.right < r.right) {
|
||||
r.right = rect.right;
|
||||
}
|
||||
if (rect.bottom < r.bottom) {
|
||||
r.bottom = rect.bottom;
|
||||
}
|
||||
return (r.right > r.left && r.bottom > r.top);
|
||||
}
|
||||
};
|
||||
|
||||
struct KeyChar {
|
||||
uint16 num;
|
||||
uint16 flags;
|
||||
int16 currentAnimCounter;
|
||||
int16 strNum;
|
||||
int16 walkDataNum;
|
||||
int16 spriteNum;
|
||||
Common::Rect prevBoundingRect;
|
||||
Common::Rect boundingRect;
|
||||
int16 xPos;
|
||||
int16 yPos;
|
||||
int16 zPos;
|
||||
int16 xPosPrev;
|
||||
int16 yPosPrev;
|
||||
int16 zPosPrev;
|
||||
int16 prevWalkDataNum;
|
||||
uint16 textColor;
|
||||
int16 inventoryItems[4];
|
||||
int16 money;
|
||||
int16 pointsDataNum;
|
||||
int16 currentWalkBox;
|
||||
uint16 prevPointsDataNum;
|
||||
int16 currentAnim;
|
||||
int16 facingDirection;
|
||||
int16 currentAnimSpeed;
|
||||
int16 framesList[16];
|
||||
int16 framesListCount;
|
||||
int16 currentFrame;
|
||||
int16 anim1Start;
|
||||
int16 anim1Count;
|
||||
int16 anim2Start;
|
||||
int16 anim2Count;
|
||||
int16 anim3Start;
|
||||
int16 anim3Count;
|
||||
int16 followingKeyCharNum;
|
||||
int16 followingKeyCharPos;
|
||||
uint16 sequenceDataIndex;
|
||||
uint16 sequenceDataOffset;
|
||||
int16 walkPointsListIndex;
|
||||
int16 walkPointsList[40];
|
||||
uint16 scriptDataStartOffset;
|
||||
uint16 scriptDataOffset;
|
||||
int16 *scriptStackPtr;
|
||||
int16 delay;
|
||||
int16 waitingKeyChar;
|
||||
int16 waitingKeyCharPosTable[3];
|
||||
int16 scriptStackTable[40];
|
||||
};
|
||||
|
||||
struct Script {
|
||||
uint8 opcodeNum;
|
||||
uint32 dataOffset;
|
||||
int16 keyCharNum;
|
||||
uint8 *dataPtr;
|
||||
int16 *stackDataPtr;
|
||||
int16 *stackDataBasePtr;
|
||||
int16 quitFlag;
|
||||
int16 stackDataTable[500];
|
||||
|
||||
void init(uint8 *data) {
|
||||
dataPtr = data;
|
||||
stackDataPtr = stackDataBasePtr = &stackDataTable[499];
|
||||
dataOffset = 0;
|
||||
quitFlag = 0;
|
||||
}
|
||||
|
||||
uint8 readByte(uint32 offs) const {
|
||||
return *(dataPtr + offs);
|
||||
}
|
||||
|
||||
int16 readWord(uint32 offs) const {
|
||||
return READ_LE_UINT16(dataPtr + offs);
|
||||
}
|
||||
|
||||
uint8 readNextByte() {
|
||||
uint8 val = readByte(dataOffset);
|
||||
++dataOffset;
|
||||
return val;
|
||||
}
|
||||
|
||||
int16 readNextWord() {
|
||||
int16 val = readWord(dataOffset);
|
||||
dataOffset += 2;
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
struct TalkEntry {
|
||||
int16 otherKeyChar;
|
||||
int16 talkingKeyChar;
|
||||
int16 num;
|
||||
};
|
||||
|
||||
struct ConversationChoice {
|
||||
int16 num;
|
||||
int16 msg;
|
||||
};
|
||||
|
||||
struct AnimationEntry {
|
||||
int16 num;
|
||||
int16 x;
|
||||
int16 y;
|
||||
int16 dx;
|
||||
int16 dy;
|
||||
int16 posNum;
|
||||
int16 delayCounter;
|
||||
int16 displayCounter;
|
||||
Common::Rect displayRect;
|
||||
|
||||
void clear() {
|
||||
num = 0;
|
||||
x = 0;
|
||||
y = 0;
|
||||
dx = 0;
|
||||
dy = 0;
|
||||
posNum = 0;
|
||||
delayCounter = 0;
|
||||
displayRect.top = 0;
|
||||
displayRect.left = 0;
|
||||
displayRect.bottom = 0;
|
||||
displayRect.right = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct SequenceEntry {
|
||||
int16 sprNum;
|
||||
int16 seqNum;
|
||||
};
|
||||
|
||||
struct SpriteData {
|
||||
uint32 size;
|
||||
uint8 *ptr;
|
||||
uint16 bitmapWidth;
|
||||
uint16 bitmapHeight;
|
||||
uint16 w;
|
||||
uint16 h;
|
||||
};
|
||||
|
||||
struct InventoryState {
|
||||
int16 displayOffset;
|
||||
int16 lastItem;
|
||||
int16 itemsPerLine;
|
||||
int16 *itemsList;
|
||||
};
|
||||
|
||||
struct ProgramPointData {
|
||||
int16 x, y, z;
|
||||
int16 order;
|
||||
};
|
||||
|
||||
struct ProgramWalkData {
|
||||
int16 point1;
|
||||
int16 point2;
|
||||
int16 clippingRect;
|
||||
int16 area1;
|
||||
int16 area2;
|
||||
};
|
||||
|
||||
struct ProgramAreaData {
|
||||
Area area;
|
||||
int16 id;
|
||||
int16 state;
|
||||
int16 animCount;
|
||||
int16 animNext;
|
||||
};
|
||||
|
||||
struct ProgramBackgroundData {
|
||||
Area area;
|
||||
int16 type;
|
||||
int16 offset;
|
||||
int16 scaleMul;
|
||||
int16 scaleDiv;
|
||||
};
|
||||
|
||||
struct ProgramHitBoxData {
|
||||
int16 item;
|
||||
int16 talk;
|
||||
uint16 state;
|
||||
int16 str;
|
||||
int16 defaultStr;
|
||||
int16 actions[8];
|
||||
Common::Rect hitBoxes[2];
|
||||
};
|
||||
|
||||
struct ProgramActionScriptOffsetData {
|
||||
int16 object1;
|
||||
int16 action;
|
||||
int16 object2;
|
||||
uint16 offset;
|
||||
};
|
||||
|
||||
struct ProgramKeyCharScriptOffsetData {
|
||||
int16 keyChar;
|
||||
uint16 offset;
|
||||
};
|
||||
|
||||
struct ProgramConversationData {
|
||||
int16 num;
|
||||
uint16 offset;
|
||||
int16 msg;
|
||||
};
|
||||
|
||||
enum {
|
||||
kDebugEngine = 1,
|
||||
kDebugGraphics,
|
||||
kDebugResource,
|
||||
kDebugOpcodes,
|
||||
kDebugMenu,
|
||||
kDebugCharset,
|
||||
};
|
||||
|
||||
enum ResourceType {
|
||||
kResourceTypeRoomImage = 0,
|
||||
kResourceTypeSequence,
|
||||
kResourceTypeSpriteImage,
|
||||
kResourceTypeIconImage,
|
||||
kResourceTypeRoomInfo,
|
||||
kResourceTypeProgram,
|
||||
kResourceTypeMusic,
|
||||
kResourceTypeSound
|
||||
};
|
||||
|
||||
enum TalkMode {
|
||||
kTalkModeTextOnly = 0,
|
||||
kTalkModeVoiceOnly,
|
||||
kTalkModeVoiceAndText,
|
||||
kTalkModeCount
|
||||
};
|
||||
|
||||
enum ScriptFlag {
|
||||
kScriptStopped = 1 << 0,
|
||||
kScriptPaused = 1 << 1
|
||||
};
|
||||
|
||||
enum SaveLoadMode {
|
||||
kSaveGameState = 0,
|
||||
kLoadGameState
|
||||
};
|
||||
|
||||
enum InventoryArea {
|
||||
kInventoryCharacter = 0,
|
||||
kInventoryMoneyDisplay,
|
||||
kInventoryGoldCoins,
|
||||
kInventorySilverCoins,
|
||||
kInventoryMoney,
|
||||
kInventoryScroller1,
|
||||
kInventoryObject1,
|
||||
kInventoryObject2,
|
||||
kInventoryObject3,
|
||||
kInventoryObject4,
|
||||
kInventoryObject5,
|
||||
kInventoryObject6,
|
||||
kInventoryScroller2
|
||||
};
|
||||
|
||||
enum {
|
||||
kScreenWidth = 640,
|
||||
kScreenHeight = 400,
|
||||
kRoomHeight = 352,
|
||||
kStartupEpisode = 90,
|
||||
// TODO: If the following truncation is intentional (it probably is) it should be clearly marked as such
|
||||
kCycleDelay = 1000 / (1193180 / 32768),
|
||||
kIconWidth = 58,
|
||||
kIconHeight = 42,
|
||||
kCursorWidth = 58,
|
||||
kCursorHeight = 42,
|
||||
kTextHeight = 16,
|
||||
kMaxProgramDataSize = 61440,
|
||||
kMaxSaveStates = 100
|
||||
};
|
||||
|
||||
enum StringType {
|
||||
kStringTypeDefault,
|
||||
kStringTypeConversation
|
||||
};
|
||||
|
||||
enum GameState {
|
||||
kGameStateGameLoop,
|
||||
kGameStateOptionsDialog,
|
||||
kGameStateQuitDialog,
|
||||
kGameStateNone
|
||||
};
|
||||
|
||||
enum ActionId {
|
||||
kActionNone,
|
||||
|
||||
// settings menu
|
||||
kActionLoadMenu,
|
||||
kActionSaveMenu,
|
||||
kActionRestartGame,
|
||||
kActionPlayGame,
|
||||
kActionQuitGame,
|
||||
kActionTextOnly,
|
||||
kActionVoiceOnly,
|
||||
kActionTextAndVoice,
|
||||
kActionLowerVolume,
|
||||
kActionUpperVolume,
|
||||
|
||||
// saveLoad menu
|
||||
kActionGameState1,
|
||||
kActionGameState2,
|
||||
kActionGameState3,
|
||||
kActionGameState4,
|
||||
kActionGameState5,
|
||||
kActionGameState6,
|
||||
kActionGameState7,
|
||||
kActionGameState8,
|
||||
kActionGameState9,
|
||||
kActionGameState10,
|
||||
kActionScrollUpSaves,
|
||||
kActionScrollDownSaves,
|
||||
kActionPerformSaveLoad,
|
||||
kActionCancelSaveLoad
|
||||
};
|
||||
|
||||
enum MenuMode {
|
||||
kMenuSettingsMode = 0,
|
||||
kMenuLoadStateMode,
|
||||
kMenuSaveStateMode
|
||||
};
|
||||
|
||||
enum ButtonFlags {
|
||||
kButtonBorder = 1 << 0,
|
||||
kButtonText = 1 << 1,
|
||||
kButtonArrow = 1 << 2
|
||||
};
|
||||
|
||||
struct Button {
|
||||
int x, y;
|
||||
int w, h;
|
||||
ActionId action;
|
||||
int data;
|
||||
uint8 flags;
|
||||
};
|
||||
|
||||
struct MenuData {
|
||||
MenuMode mode;
|
||||
Button *buttonsTable;
|
||||
uint buttonsCount;
|
||||
bool quit;
|
||||
bool exit;
|
||||
char saveLoadDescriptionsTable[kMaxSaveStates][33];
|
||||
|
||||
void removeLastCharFromDescription(int slot) {
|
||||
char *description = saveLoadDescriptionsTable[slot];
|
||||
int descriptionLen = strlen(description);
|
||||
if (descriptionLen > 0) {
|
||||
--descriptionLen;
|
||||
description[descriptionLen] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void addCharToDescription(int slot, char chr) {
|
||||
char *description = saveLoadDescriptionsTable[slot];
|
||||
int descriptionLen = strlen(description);
|
||||
if (descriptionLen < 32 && Common::isPrint(chr)) {
|
||||
description[descriptionLen] = chr;
|
||||
description[descriptionLen + 1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const Button *findButtonUnderCursor(int cursorX, int cursorY) const {
|
||||
for (uint i = 0; i < buttonsCount; ++i) {
|
||||
const Button *button = &buttonsTable[i];
|
||||
if (cursorX >= button->x && cursorX < button->x + button->w &&
|
||||
cursorY >= button->y && cursorY < button->y + button->h) {
|
||||
return button;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void readGameStateDescription(Common::ReadStream *f, char *description, int len);
|
||||
Common::String generateGameStateFileName(const char *target, int slot, bool prefixOnly = false);
|
||||
int getGameStateFileSlot(const char *filename);
|
||||
|
||||
class MidiPlayer;
|
||||
|
||||
class ToucheEngine: public Engine {
|
||||
public:
|
||||
|
||||
enum {
|
||||
NUM_FLAGS = 2000,
|
||||
NUM_KEYCHARS = 32,
|
||||
NUM_SPRITES = 7,
|
||||
NUM_SEQUENCES = 7,
|
||||
NUM_CONVERSATION_CHOICES = 40,
|
||||
NUM_TALK_ENTRIES = 16,
|
||||
NUM_ANIMATION_ENTRIES = 4,
|
||||
NUM_INVENTORY_ITEMS = 100,
|
||||
NUM_DIRTY_RECTS = 30,
|
||||
NUM_DIRECTIONS = 135
|
||||
};
|
||||
|
||||
typedef void (ToucheEngine::*OpcodeProc)();
|
||||
|
||||
ToucheEngine(OSystem *system, Common::Language language);
|
||||
~ToucheEngine() override;
|
||||
|
||||
// Engine APIs
|
||||
Common::Error run() override;
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
void syncSoundSettings() override;
|
||||
|
||||
protected:
|
||||
|
||||
void restart();
|
||||
void readConfigurationSettings();
|
||||
void writeConfigurationSettings();
|
||||
void mainLoop();
|
||||
void processEvents(bool handleKeyEvents = true);
|
||||
void runCycle();
|
||||
int16 getRandomNumber(int max);
|
||||
void changePaletteRange();
|
||||
void playSoundInRange();
|
||||
void resetSortedKeyCharsTable();
|
||||
void setupEpisode(int num);
|
||||
void setupNewEpisode();
|
||||
void drawKeyChar(KeyChar *key);
|
||||
void sortKeyChars();
|
||||
void runKeyCharScript(KeyChar *key);
|
||||
void runCurrentKeyCharScript(int mode);
|
||||
void executeScriptOpcode(int16 param);
|
||||
void initKeyChars(int keyChar);
|
||||
void setKeyCharTextColor(int keyChar, uint16 color);
|
||||
void waitForKeyCharPosition(int keyChar);
|
||||
void setKeyCharBox(int keyChar, int value);
|
||||
void setKeyCharFrame(int keyChar, int16 type, int16 value1, int16 value2);
|
||||
void setKeyCharFacingDirection(int keyChar, int16 dir);
|
||||
void initKeyCharScript(int keyChar, int16 spriteNum, int16 seqDataIndex, int16 seqDataOffs);
|
||||
uint16 findProgramKeyCharScriptOffset(int keyChar) const;
|
||||
bool scrollRoom(int keyChar);
|
||||
void drawIcon(int x, int y, int num);
|
||||
void centerScreenToKeyChar(int keyChar);
|
||||
void waitForKeyCharsSet();
|
||||
void redrawRoom();
|
||||
void fadePalette(int firstColor, int colorCount, int scale, int scaleInc, int fadingStepsCount);
|
||||
void fadePaletteFromFlags();
|
||||
void moveKeyChar(uint8 *dst, int dstPitch, KeyChar *key);
|
||||
void changeKeyCharFrame(KeyChar *key, int keyChar);
|
||||
void setKeyCharRandomFrame(KeyChar *key);
|
||||
void setKeyCharMoney();
|
||||
const char *getString(int num) const;
|
||||
int getStringWidth(int num) const;
|
||||
void drawString(uint16 color, int x, int y, int16 num, StringType strType = kStringTypeDefault);
|
||||
void drawGameString(uint16 color, int x1, int y, const char *str);
|
||||
int restartKeyCharScriptOnAction(int action, int obj1, int obj2);
|
||||
void buildSpriteScalingTable(int z1, int z2);
|
||||
void drawSpriteOnBackdrop(int num, int x, int y);
|
||||
void updateTalkFrames(int keyChar);
|
||||
void setKeyCharTalkingFrame(int keyChar);
|
||||
void lockUnlockHitBox(int num, int lock);
|
||||
void drawHitBoxes();
|
||||
void showCursor(bool show);
|
||||
void setCursor(int num);
|
||||
void setDefaultCursor(int num);
|
||||
void handleLeftMouseButtonClickOnInventory();
|
||||
void handleRightMouseButtonClickOnInventory();
|
||||
void handleMouseInput(int flag);
|
||||
void handleMouseClickOnRoom(int flag);
|
||||
void handleMouseClickOnInventory(int flag);
|
||||
void scrollScreenToPos(int num);
|
||||
void clearRoomArea();
|
||||
void startNewMusic();
|
||||
void startNewSound();
|
||||
void updateSpeech();
|
||||
int handleActionMenuUnderCursor(const int16 *actions, int offs, int y, int str);
|
||||
|
||||
void redrawBackground();
|
||||
void addRoomArea(int num, int flag);
|
||||
void updateRoomAreas(int num, int flags);
|
||||
void setRoomAreaState(int num, uint16 state);
|
||||
void findAndRedrawRoomRegion(int num);
|
||||
void updateRoomRegions();
|
||||
void redrawRoomRegion(int num, bool markForRedraw);
|
||||
|
||||
void initInventoryObjectsTable();
|
||||
void initInventoryLists();
|
||||
void setupInventoryAreas();
|
||||
void drawInventory(int index, int flag);
|
||||
void drawAmountOfMoneyInInventory();
|
||||
void packInventoryItems(int index);
|
||||
void appendItemToInventoryList(int index);
|
||||
void addItemToInventory(int inventory, int16 item);
|
||||
void removeItemFromInventory(int inventory, int16 item);
|
||||
|
||||
void resetTalkingVars();
|
||||
int updateKeyCharTalk(int pauseFlag);
|
||||
const char *formatTalkText(int *y, int *h, const char *text);
|
||||
void addToTalkTable(int talkingKeyChar, int num, int otherKeyChar);
|
||||
void removeFromTalkTable(int keyChar);
|
||||
void addConversationChoice(int16 num);
|
||||
void removeConversationChoice(int16 num);
|
||||
void runConversationScript(uint16 offset);
|
||||
void findConversationByNum(int16 num);
|
||||
void clearConversationChoices();
|
||||
void scrollDownConversationChoice();
|
||||
void scrollUpConversationChoice();
|
||||
void drawCharacterConversation();
|
||||
void drawConversationString(int num, uint16 color);
|
||||
void clearConversationArea();
|
||||
void setupConversationScript(int num);
|
||||
void handleConversation();
|
||||
|
||||
void buildWalkPointsList(int keyChar);
|
||||
int findWalkDataNum(int pointNum1, int pointNum2);
|
||||
void changeWalkPath(int num1, int num2, int16 val);
|
||||
void adjustKeyCharPosToWalkBox(KeyChar *key, int moveType);
|
||||
void lockWalkPath(int num1, int num2);
|
||||
void unlockWalkPath(int num1, int num2);
|
||||
void resetPointsData(int num);
|
||||
bool sortPointsData(int num1, int num2);
|
||||
void updateKeyCharWalkPath(KeyChar *key, int16 dx, int16 dy, int16 dz);
|
||||
void markWalkPoints(int keyChar);
|
||||
void buildWalkPath(int dstPosX, int dstPosY, int keyChar);
|
||||
|
||||
void addToAnimationTable(int num, int posNum, int keyChar, int delayCounter);
|
||||
void copyAnimationImage(int dstX, int dstY, int w, int h, const uint8 *src, int srcX, int srcY, int fillColor);
|
||||
void drawAnimationImage(AnimationEntry *anim);
|
||||
void processAnimationTable();
|
||||
void clearAnimationTable();
|
||||
|
||||
void addToDirtyRect(const Common::Rect &r);
|
||||
void clearDirtyRects();
|
||||
void setPalette(int firstColor, int colorCount, int redScale, int greenScale, int blueScale);
|
||||
void updateScreenArea(int x, int y, int w, int h);
|
||||
void updateEntireScreen();
|
||||
void updateDirtyScreenAreas();
|
||||
void updatePalette();
|
||||
|
||||
void saveGameStateData(Common::WriteStream *stream);
|
||||
void loadGameStateData(Common::ReadStream *stream);
|
||||
Common::Error saveGameState(int num, const Common::String &description, bool isAutosave = false) override;
|
||||
Common::Error loadGameState(int num) override;
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
Common::String getSaveStateName(int slot) const override {
|
||||
return Common::String::format("%s.%d", _targetName.c_str(), slot);
|
||||
}
|
||||
|
||||
void setupOpcodes();
|
||||
void op_nop();
|
||||
void op_jnz();
|
||||
void op_jz();
|
||||
void op_jmp();
|
||||
void op_true();
|
||||
void op_false();
|
||||
void op_push();
|
||||
void op_not();
|
||||
void op_add();
|
||||
void op_sub();
|
||||
void op_mul();
|
||||
void op_div();
|
||||
void op_mod();
|
||||
void op_and();
|
||||
void op_or();
|
||||
void op_neg();
|
||||
void op_testGreater();
|
||||
void op_testEquals();
|
||||
void op_testLower();
|
||||
void op_fetchScriptWord();
|
||||
void op_testGreaterOrEquals();
|
||||
void op_testLowerOrEquals();
|
||||
void op_testNotEquals();
|
||||
void op_endConversation();
|
||||
void op_stopScript();
|
||||
void op_getFlag();
|
||||
void op_setFlag();
|
||||
void op_fetchScriptByte();
|
||||
void op_getKeyCharWalkBox();
|
||||
void op_startSound();
|
||||
void op_moveKeyCharToPos();
|
||||
void op_loadRoom();
|
||||
void op_updateRoom();
|
||||
void op_startTalk();
|
||||
void op_loadSprite();
|
||||
void op_loadSequence();
|
||||
void op_setKeyCharBox();
|
||||
void op_initKeyCharScript();
|
||||
void op_setKeyCharFrame();
|
||||
void op_setKeyCharDirection();
|
||||
void op_clearConversationChoices();
|
||||
void op_addConversationChoice();
|
||||
void op_removeConversationChoice();
|
||||
void op_getInventoryItem();
|
||||
void op_setInventoryItem();
|
||||
void op_startEpisode();
|
||||
void op_setConversationNum();
|
||||
void op_enableInput();
|
||||
void op_disableInput();
|
||||
void op_faceKeyChar();
|
||||
void op_getKeyCharCurrentAnim();
|
||||
void op_getCurrentKeyChar();
|
||||
void op_isKeyCharActive();
|
||||
void op_setPalette();
|
||||
void op_changeWalkPath();
|
||||
void op_lockWalkPath();
|
||||
void op_initializeKeyChar();
|
||||
void op_setupWaitingKeyChars();
|
||||
void op_updateRoomAreas();
|
||||
void op_unlockWalkPath();
|
||||
void op_addItemToInventoryAndRedraw();
|
||||
void op_giveItemTo();
|
||||
void op_setHitBoxText();
|
||||
void op_fadePalette();
|
||||
void op_getInventoryItemFlags();
|
||||
void op_drawInventory();
|
||||
void op_stopKeyCharScript();
|
||||
void op_restartKeyCharScript();
|
||||
void op_getKeyCharCurrentWalkBox();
|
||||
void op_getKeyCharPointsDataNum();
|
||||
void op_setupFollowingKeyChar();
|
||||
void op_startAnimation();
|
||||
void op_setKeyCharTextColor();
|
||||
void op_startMusic();
|
||||
void op_sleep();
|
||||
void op_setKeyCharDelay();
|
||||
void op_lockHitBox();
|
||||
void op_removeItemFromInventory();
|
||||
void op_unlockHitBox();
|
||||
void op_addRoomArea();
|
||||
void op_setKeyCharFlags();
|
||||
void op_unsetKeyCharFlags();
|
||||
void op_loadSpeechSegment();
|
||||
void op_drawSpriteOnBackdrop();
|
||||
void op_startPaletteFadeIn();
|
||||
void op_startPaletteFadeOut();
|
||||
void op_setRoomAreaState();
|
||||
|
||||
void res_openDataFile();
|
||||
void res_closeDataFile();
|
||||
void res_allocateTables();
|
||||
void res_deallocateTables();
|
||||
uint32 res_getDataOffset(ResourceType type, int num, uint32 *size = NULL);
|
||||
void res_loadSpriteImage(int num, uint8 *dst);
|
||||
void res_loadProgram(int num);
|
||||
void res_decodeProgramData();
|
||||
void res_loadRoom(int num);
|
||||
void res_loadSprite(int num, int index);
|
||||
void res_loadSequence(int num, int index);
|
||||
void res_decodeScanLineImageRLE(uint8 *dst, int lineWidth);
|
||||
void res_loadBackdrop();
|
||||
void res_loadImage(int num, uint8 *dst);
|
||||
void res_loadImageHelper(uint8 *imgData, int imgWidth, int imgHeight);
|
||||
void res_loadSound(int flag, int num);
|
||||
void res_stopSound();
|
||||
void res_loadMusic(int num);
|
||||
void res_loadSpeech(int num);
|
||||
void res_loadSpeechSegment(int num);
|
||||
void res_stopSpeech();
|
||||
|
||||
void drawButton(Button *button);
|
||||
void redrawMenu(MenuData *menu);
|
||||
void handleMenuAction(MenuData *menu, int actionId);
|
||||
void handleOptions(int forceDisplay);
|
||||
void drawActionsPanel(int dstX, int dstY, int deltaX, int deltaY);
|
||||
void drawConversationPanelBorder(int dstY, int srcX, int srcY);
|
||||
void drawConversationPanel();
|
||||
void printStatusString(const char *str);
|
||||
void clearStatusString();
|
||||
int displayQuitDialog();
|
||||
void displayTextMode(int str);
|
||||
|
||||
Common::Point getMousePos() const;
|
||||
|
||||
MidiPlayer *_midiPlayer;
|
||||
|
||||
int _musicVolume;
|
||||
Audio::SoundHandle _musicHandle;
|
||||
|
||||
void initMusic();
|
||||
public: // To allow access from console
|
||||
void startMusic(int num);
|
||||
void stopMusic();
|
||||
protected:
|
||||
int getMusicVolume();
|
||||
void setMusicVolume(int volume);
|
||||
void adjustMusicVolume(int diff);
|
||||
|
||||
Common::Language _language;
|
||||
Common::RandomSource _rnd;
|
||||
|
||||
bool _inp_leftMouseButtonPressed;
|
||||
bool _inp_rightMouseButtonPressed;
|
||||
int _disabledInputCounter;
|
||||
bool _hideInventoryTexts;
|
||||
GameState _gameState;
|
||||
bool _displayQuitDialog;
|
||||
int _saveLoadCurrentPage;
|
||||
int _saveLoadCurrentSlot;
|
||||
|
||||
int _newMusicNum;
|
||||
int _currentMusicNum;
|
||||
int _newSoundNum;
|
||||
int _newSoundDelay;
|
||||
int _newSoundPriority;
|
||||
int _playSoundCounter;
|
||||
bool _speechPlaying;
|
||||
Audio::SoundHandle _sfxHandle;
|
||||
Audio::SoundHandle _speechHandle;
|
||||
|
||||
int16 _inventoryList1[101];
|
||||
int16 _inventoryList2[101];
|
||||
int16 _inventoryList3[7];
|
||||
InventoryState _inventoryStateTable[3];
|
||||
int16 _inventoryItemsInfoTable[NUM_INVENTORY_ITEMS];
|
||||
int16 *_inventoryVar1;
|
||||
int16 *_inventoryVar2;
|
||||
int _currentCursorObject;
|
||||
Common::Rect _inventoryAreasTable[13];
|
||||
|
||||
int _talkTextMode;
|
||||
int _talkListEnd;
|
||||
int _talkListCurrent;
|
||||
bool _talkTextRectDefined;
|
||||
bool _talkTextDisplayed;
|
||||
bool _talkTextInitialized;
|
||||
bool _skipTalkText;
|
||||
int _talkTextSpeed;
|
||||
int _keyCharTalkCounter;
|
||||
int _talkTableLastTalkingKeyChar;
|
||||
int _talkTableLastOtherKeyChar;
|
||||
int _talkTableLastStringNum;
|
||||
int _objectDescriptionNum;
|
||||
TalkEntry _talkTable[NUM_TALK_ENTRIES];
|
||||
|
||||
bool _conversationChoicesUpdated;
|
||||
int _conversationReplyNum;
|
||||
bool _conversationEnded;
|
||||
int _conversationNum;
|
||||
int _scrollConversationChoiceOffset;
|
||||
int _currentConversation;
|
||||
bool _disableConversationScript;
|
||||
bool _conversationAreaCleared;
|
||||
ConversationChoice _conversationChoicesTable[NUM_CONVERSATION_CHOICES];
|
||||
|
||||
int16 _flagsTable[NUM_FLAGS];
|
||||
KeyChar _keyCharsTable[NUM_KEYCHARS];
|
||||
KeyChar *_sortedKeyCharsTable[NUM_KEYCHARS];
|
||||
int _currentKeyCharNum;
|
||||
|
||||
int _newEpisodeNum;
|
||||
int _currentEpisodeNum;
|
||||
|
||||
int _currentAmountOfMoney;
|
||||
int _giveItemToKeyCharNum;
|
||||
int _giveItemToObjectNum;
|
||||
int _giveItemToCounter;
|
||||
int _currentRoomNum;
|
||||
int _waitingSetKeyCharNum1;
|
||||
int _waitingSetKeyCharNum2;
|
||||
int _waitingSetKeyCharNum3;
|
||||
uint8 _updatedRoomAreasTable[200];
|
||||
Common::Rect _moveKeyCharRect;
|
||||
Common::Point _screenOffset;
|
||||
int _currentObjectNum;
|
||||
int _processRandomPaletteCounter;
|
||||
int16 _spriteScalingIndex[1000];
|
||||
int16 _spriteScalingTable[1000];
|
||||
|
||||
bool _fastWalkMode;
|
||||
bool _fastMode;
|
||||
|
||||
AnimationEntry _animationTable[NUM_ANIMATION_ENTRIES];
|
||||
|
||||
Script _script;
|
||||
const OpcodeProc *_opcodesTable;
|
||||
int _numOpcodes;
|
||||
|
||||
Common::File _fData;
|
||||
Common::File _fSpeech[2];
|
||||
int _compressedSpeechData;
|
||||
|
||||
uint8 *_textData;
|
||||
uint8 *_backdropBuffer;
|
||||
uint8 *_menuKitData;
|
||||
uint8 *_convKitData;
|
||||
uint8 *_sequenceDataTable[NUM_SEQUENCES];
|
||||
uint8 *_programData;
|
||||
uint32 _programDataSize;
|
||||
uint8 *_mouseData;
|
||||
uint8 *_iconData;
|
||||
|
||||
SpriteData _spritesTable[NUM_SPRITES];
|
||||
SequenceEntry _sequenceEntryTable[NUM_SEQUENCES];
|
||||
int _currentBitmapWidth;
|
||||
int _currentBitmapHeight;
|
||||
int _currentImageWidth;
|
||||
int _currentImageHeight;
|
||||
int _roomWidth;
|
||||
|
||||
uint8 *_programTextDataPtr;
|
||||
Common::Array<Common::Rect> _programRectsTable;
|
||||
Common::Array<ProgramPointData> _programPointsTable;
|
||||
Common::Array<ProgramWalkData> _programWalkTable;
|
||||
Common::Array<ProgramAreaData> _programAreaTable;
|
||||
Common::Array<ProgramBackgroundData> _programBackgroundTable;
|
||||
Common::Array<ProgramHitBoxData> _programHitBoxTable;
|
||||
Common::Array<ProgramActionScriptOffsetData> _programActionScriptOffsetTable;
|
||||
Common::Array<ProgramKeyCharScriptOffsetData> _programKeyCharScriptOffsetTable;
|
||||
Common::Array<ProgramConversationData> _programConversationTable;
|
||||
Common::Rect _cursorObjectRect;
|
||||
Common::Rect _talkTextRect, _talkTextRect2;
|
||||
Common::Rect _screenRect;
|
||||
Common::Rect _roomAreaRect;
|
||||
|
||||
bool _roomNeedRedraw;
|
||||
int _fullRedrawCounter;
|
||||
int _menuRedrawCounter;
|
||||
uint8 *_offscreenBuffer;
|
||||
uint8 _paletteBuffer[256 * 3];
|
||||
Common::Rect _dirtyRectsTable[NUM_DIRTY_RECTS];
|
||||
int _dirtyRectsTableCount;
|
||||
|
||||
static const uint8 _directionsTable[NUM_DIRECTIONS];
|
||||
};
|
||||
|
||||
/*
|
||||
FLAGS LIST
|
||||
|
||||
115 : don't set backdrop palette on room loading
|
||||
118 : current amount of money
|
||||
119 : current cursor object
|
||||
176 : keychar max direction
|
||||
266 : keychar direction override
|
||||
267 : don't decode picture/sprite images (in load_image_helper)
|
||||
268 : don't decode picture/sprite images
|
||||
269 : disable room background animations
|
||||
270 : play random sound
|
||||
290 : process random palette
|
||||
295 : game cycle counter (incremented)
|
||||
296 : game cycle counter (incremented)
|
||||
297 : game cycle counter (incremented)
|
||||
298 : game cycle counter (decremented)
|
||||
299 : game cycle counter (decremented)
|
||||
600 : last ascii key press
|
||||
603 : fade palette "scale" increment (in vbl handler)
|
||||
605 : fade palette "scale"
|
||||
606 : inventory redraw disabled
|
||||
607 : first palette color to fade
|
||||
608 : last palette color to fade
|
||||
609 : max fade palette "scale"
|
||||
610 : min fade palette "scale"
|
||||
611 : quit game
|
||||
612 : random number modulo
|
||||
613 : last generated random number
|
||||
614 : room scroll x offset
|
||||
615 : room scroll y offset
|
||||
616 : disable room scrolling
|
||||
617 : current speech file number
|
||||
618 : hide mouse cursor
|
||||
621 : enable french version "features"
|
||||
902 : debug/draw walk boxes
|
||||
911 : load scripts/programs from external files
|
||||
*/
|
||||
|
||||
} // namespace Touche
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user