Initial commit
This commit is contained in:
4
engines/sword1/POTFILES
Normal file
4
engines/sword1/POTFILES
Normal file
@@ -0,0 +1,4 @@
|
||||
engines/sword1/animation.cpp
|
||||
engines/sword1/control.cpp
|
||||
engines/sword1/logic.cpp
|
||||
engines/sword1/metaengine.cpp
|
||||
581
engines/sword1/animation.cpp
Normal file
581
engines/sword1/animation.cpp
Normal file
@@ -0,0 +1,581 @@
|
||||
/* 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/file.h"
|
||||
#include "common/events.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/translation.h"
|
||||
#include "sword1/sword1.h"
|
||||
#include "sword1/animation.h"
|
||||
#include "sword1/text.h"
|
||||
#include "sword1/resman.h"
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/system.h"
|
||||
#include "graphics/paletteman.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "gui/message.h"
|
||||
|
||||
#ifdef USE_MPEG2
|
||||
#include "video/avi_decoder.h"
|
||||
#endif
|
||||
|
||||
#include "video/dxa_decoder.h"
|
||||
|
||||
#include "video/psx_decoder.h"
|
||||
#include "video/smk_decoder.h"
|
||||
|
||||
#include "engines/util.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
static const char *const sequenceList[20] = {
|
||||
"ferrari", // 0 CD2 ferrari running down fitz in sc19
|
||||
"ladder", // 1 CD2 george walking down ladder to dig sc24->sc$
|
||||
"steps", // 2 CD2 george walking down steps sc23->sc24
|
||||
"sewer", // 3 CD1 george entering sewer sc2->sc6
|
||||
"intro", // 4 CD1 intro sequence ->sc1
|
||||
"river", // 5 CD1 george being thrown into river by flap & g$
|
||||
"truck", // 6 CD2 truck arriving at bull's head sc45->sc53/4
|
||||
"grave", // 7 BOTH george's grave in scotland, from sc73 + from sc38 $
|
||||
"montfcon", // 8 CD2 monfaucon clue in ireland dig, sc25
|
||||
"tapestry", // 9 CD2 tapestry room beyond spain well, sc61
|
||||
"ireland", // 10 CD2 ireland establishing shot europe_map->sc19
|
||||
"finale", // 11 CD2 grand finale at very end, from sc73
|
||||
"history", // 12 CD1 George's history lesson from Nico, in sc10
|
||||
"spanish", // 13 CD2 establishing shot for 1st visit to Spain, europe_m$
|
||||
"well", // 14 CD2 first time being lowered down well in Spai$
|
||||
"candle", // 15 CD2 Candle burning down in Spain mausoleum sc59
|
||||
"geodrop", // 16 CD2 from sc54, George jumping down onto truck
|
||||
"vulture", // 17 CD2 from sc54, vultures circling George's dead body
|
||||
"enddemo", // 18 --- for end of single CD demo
|
||||
"credits", // 19 CD2 credits, to follow "finale" sequence
|
||||
};
|
||||
|
||||
// This is the list of the names of the PlayStation videos
|
||||
// TODO: fight.str, flashy.str,
|
||||
static const char *const sequenceListPSX[20] = {
|
||||
"e_ferr1",
|
||||
"ladder1",
|
||||
"steps1",
|
||||
"sewer1",
|
||||
"e_intro1",
|
||||
"river1",
|
||||
"truck1",
|
||||
"grave1",
|
||||
"montfcn1",
|
||||
"tapesty1",
|
||||
"ireland1",
|
||||
"e_fin1",
|
||||
"e_hist1",
|
||||
"spanish1",
|
||||
"well1",
|
||||
"candle1",
|
||||
"geodrop1",
|
||||
"vulture1",
|
||||
"", // demo video not present
|
||||
"" // credits are not a video
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Basic movie player
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Sound *sound, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType)
|
||||
: _vm(vm), _textMan(textMan), _resMan(resMan), _sound(sound), _system(system), _textX(0), _textY(0), _textWidth(0), _textHeight(0), _textColor(1), _modeChange(false) {
|
||||
_decoderType = decoderType;
|
||||
_decoder = decoder;
|
||||
|
||||
_c1Color = _c2Color = _c3Color = _c4Color = 255;
|
||||
_black = 0;
|
||||
}
|
||||
|
||||
MoviePlayer::~MoviePlayer() {
|
||||
delete _decoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays an animated cutscene.
|
||||
* @param id the id of the file
|
||||
*/
|
||||
Common::Error MoviePlayer::load(uint32 id) {
|
||||
Common::Path filename;
|
||||
|
||||
if (SwordEngine::_systemVars.showText) {
|
||||
Common::File f;
|
||||
filename = Common::Path(Common::String::format("%s.txt", sequenceList[id]));
|
||||
|
||||
if (f.open(filename)) {
|
||||
Common::String line;
|
||||
int lineNo = 0;
|
||||
int lastEnd = -1;
|
||||
|
||||
_movieTexts.clear();
|
||||
while (!f.eos() && !f.err()) {
|
||||
line = f.readLine();
|
||||
lineNo++;
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *ptr = line.c_str();
|
||||
|
||||
// TODO: Better error handling
|
||||
int startFrame = strtoul(ptr, const_cast<char **>(&ptr), 10);
|
||||
int endFrame = strtoul(ptr, const_cast<char **>(&ptr), 10);
|
||||
|
||||
while (*ptr && Common::isSpace(*ptr))
|
||||
ptr++;
|
||||
|
||||
if (startFrame > endFrame) {
|
||||
warning("%s:%d: startFrame (%d) > endFrame (%d)", filename.toString().c_str(), lineNo, startFrame, endFrame);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startFrame <= lastEnd) {
|
||||
warning("%s:%d startFrame (%d) <= lastEnd (%d)", filename.toString().c_str(), lineNo, startFrame, lastEnd);
|
||||
continue;
|
||||
}
|
||||
|
||||
int color = 0;
|
||||
if (*ptr == '@') {
|
||||
++ptr;
|
||||
color = strtoul(ptr, const_cast<char **>(&ptr), 10);
|
||||
while (*ptr && Common::isSpace(*ptr))
|
||||
ptr++;
|
||||
}
|
||||
|
||||
_movieTexts.push_back(MovieText(startFrame, endFrame, ptr, color));
|
||||
lastEnd = endFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (_decoderType) {
|
||||
case kVideoDecoderDXA:
|
||||
filename = Common::Path(Common::String::format("%s.dxa", sequenceList[id]));
|
||||
break;
|
||||
case kVideoDecoderSMK:
|
||||
filename = Common::Path(Common::String::format("%s.smk", sequenceList[id]));
|
||||
break;
|
||||
case kVideoDecoderPSX:
|
||||
filename = Common::Path(Common::String::format("%s.str", (_vm->_systemVars.isDemo && id == 4) ? "intro" : sequenceListPSX[id]));
|
||||
break;
|
||||
case kVideoDecoderMP2:
|
||||
filename = Common::Path(Common::String::format("%s.mp2", sequenceList[id]));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_decoder->loadFile(filename)) {
|
||||
return Common::Error(Common::kPathDoesNotExist, filename.toString());
|
||||
}
|
||||
|
||||
// Need to switch to true color for PSX/MP2 videos
|
||||
if (!_decoder->getPixelFormat().isCLUT8()) {
|
||||
if (!_decoder->setOutputPixelFormats(g_system->getSupportedFormats()))
|
||||
return Common::kUnsupportedColorMode;
|
||||
|
||||
Graphics::PixelFormat format = _decoder->getPixelFormat();
|
||||
initGraphics(g_system->getWidth(), g_system->getHeight(), &format);
|
||||
|
||||
if (g_system->getScreenFormat() != format) {
|
||||
return Common::kUnsupportedColorMode;
|
||||
} else {
|
||||
_modeChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
// For DXA/MP2, also add the external sound file
|
||||
if (_decoderType == kVideoDecoderDXA || _decoderType == kVideoDecoderMP2)
|
||||
_decoder->addStreamFileTrack(sequenceList[id]);
|
||||
|
||||
_decoder->start();
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void MoviePlayer::play() {
|
||||
_textX = 0;
|
||||
_textY = 0;
|
||||
|
||||
playVideo();
|
||||
|
||||
_textMan->releaseText(2, false);
|
||||
|
||||
_movieTexts.clear();
|
||||
|
||||
// It's tempting to call _screen->fullRefresh() here to restore the old
|
||||
// palette. However, that causes glitches with DXA movies, where the
|
||||
// previous location would be momentarily drawn, before switching to
|
||||
// the new one. Work around this by setting the palette to black.
|
||||
|
||||
byte pal[3 * 256];
|
||||
memset(pal, 0, sizeof(pal));
|
||||
_system->getPaletteManager()->setPalette(pal, 0, 256);
|
||||
}
|
||||
|
||||
void MoviePlayer::performPostProcessing(byte *screen) {
|
||||
// TODO: We don't support displaying these in true color yet,
|
||||
// nor using the PSX fonts to display subtitles.
|
||||
if (_vm->isPsx() || _modeChange)
|
||||
return;
|
||||
|
||||
if (!_movieTexts.empty()) {
|
||||
if (_decoder->getCurFrame() == _movieTexts.front()._startFrame) {
|
||||
_textMan->makeTextSprite(2, (const uint8 *)_movieTexts.front()._text.c_str(), 600, LETTER_COL);
|
||||
|
||||
FrameHeader *frame = _textMan->giveSpriteData(2);
|
||||
_textWidth = _resMan->toUint16(frame->width);
|
||||
_textHeight = _resMan->toUint16(frame->height);
|
||||
_textX = 320 - _textWidth / 2;
|
||||
_textY = 420 - _textHeight;
|
||||
_textColor = _movieTexts.front()._color;
|
||||
}
|
||||
if (_decoder->getCurFrame() == _movieTexts.front()._endFrame) {
|
||||
_textMan->releaseText(2, false);
|
||||
_movieTexts.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
byte *src, *dst;
|
||||
int x, y;
|
||||
|
||||
if (_textMan->giveSpriteData(2)) {
|
||||
src = (byte *)_textMan->giveSpriteData(2) + sizeof(FrameHeader);
|
||||
dst = screen + _textY * SCREEN_WIDTH + _textX * 1;
|
||||
|
||||
for (y = 0; y < _textHeight; y++) {
|
||||
for (x = 0; x < _textWidth; x++) {
|
||||
switch (src[x]) {
|
||||
case BORDER_COL:
|
||||
dst[x] = getBlackColor();
|
||||
break;
|
||||
case LETTER_COL:
|
||||
dst[x] = findTextColor();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
src += _textWidth;
|
||||
dst += SCREEN_WIDTH;
|
||||
}
|
||||
} else if (_textX && _textY) {
|
||||
// If the frame doesn't cover the entire screen, we have to
|
||||
// erase the subtitles manually.
|
||||
|
||||
int frameWidth = _decoder->getWidth();
|
||||
int frameHeight = _decoder->getHeight();
|
||||
int frameX = (_system->getWidth() - frameWidth) / 2;
|
||||
int frameY = (_system->getHeight() - frameHeight) / 2;
|
||||
|
||||
dst = screen + _textY * _system->getWidth();
|
||||
|
||||
for (y = 0; y < _textHeight; y++) {
|
||||
if (_textY + y < frameY || _textY + y >= frameY + frameHeight) {
|
||||
memset(dst + _textX, getBlackColor(), _textWidth);
|
||||
} else {
|
||||
if (frameX > _textX)
|
||||
memset(dst + _textX, getBlackColor(), frameX - _textX);
|
||||
if (frameX + frameWidth < _textX + _textWidth)
|
||||
memset(dst + frameX + frameWidth, getBlackColor(), _textX + _textWidth - (frameX + frameWidth));
|
||||
}
|
||||
|
||||
dst += _system->getWidth();
|
||||
}
|
||||
|
||||
_textX = 0;
|
||||
_textY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool MoviePlayer::playVideo() {
|
||||
bool skipped = false;
|
||||
uint16 x = (g_system->getWidth() - _decoder->getWidth()) / 2;
|
||||
uint16 y = (g_system->getHeight() - _decoder->getHeight()) / 2;
|
||||
|
||||
while (!_vm->shouldQuit() && !_decoder->endOfVideo() && !skipped) {
|
||||
if (_decoder->needsUpdate()) {
|
||||
const Graphics::Surface *frame = _decoder->decodeNextFrame();
|
||||
if (frame) {
|
||||
if (_decoderType == kVideoDecoderPSX)
|
||||
drawFramePSX(frame);
|
||||
else
|
||||
_vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, frame->w, frame->h);
|
||||
}
|
||||
|
||||
_sound->setCrossFadeIncrement();
|
||||
_sound->updateMusicStreaming();
|
||||
|
||||
if (_decoder->hasDirtyPalette()) {
|
||||
_vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256);
|
||||
|
||||
if (!_movieTexts.empty()) {
|
||||
// Look for the best color indexes to use to display the subtitles
|
||||
uint32 minWeight = 0xFFFFFFFF;
|
||||
uint32 weight;
|
||||
float c1Weight = 1e+30f;
|
||||
float c2Weight = 1e+30f;
|
||||
float c3Weight = 1e+30f;
|
||||
float c4Weight = 1e+30f;
|
||||
byte r, g, b;
|
||||
float h, s, v, hd, hsvWeight;
|
||||
|
||||
const byte *palette = _decoder->getPalette();
|
||||
|
||||
// Color comparaison for the subtitles colors is done in HSL
|
||||
// C1 color is used for George and is almost white (R = 248, G = 252, B = 248)
|
||||
const float h1 = 0.333333f, s1 = 0.02f, v1 = 0.99f;
|
||||
|
||||
// C2 color is used for George as a narrator and is grey (R = 184, G = 188, B = 184)
|
||||
const float h2 = 0.333333f, s2 = 0.02f, v2 = 0.74f;
|
||||
|
||||
// C3 color is used for Nicole and is rose (R = 200, G = 120, B = 184)
|
||||
const float h3 = 0.866667f, s3 = 0.4f, v3 = 0.78f;
|
||||
|
||||
// C4 color is used for Maguire and is blue (R = 80, G = 152, B = 184)
|
||||
const float h4 = 0.55f, s4 = 0.57f, v4 = 0.72f;
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
r = *palette++;
|
||||
g = *palette++;
|
||||
b = *palette++;
|
||||
|
||||
weight = 3 * r * r + 6 * g * g + 2 * b * b;
|
||||
|
||||
if (weight <= minWeight) {
|
||||
minWeight = weight;
|
||||
_black = i;
|
||||
}
|
||||
|
||||
convertColor(r, g, b, h, s, v);
|
||||
|
||||
// C1 color
|
||||
// It is almost achromatic (very low saturation) so the hue as litle impact on the color.
|
||||
// Therefore use a low weight on hue and high weight on saturation.
|
||||
hd = h - h1;
|
||||
hd += hd < -0.5f ? 1.0f : hd > 0.5f ? -1.0f : 0.0f;
|
||||
hsvWeight = 1.0f * hd * hd + 4.0f * (s - s1) * (s - s1) + 3.0f * (v - v1) * (v - v1);
|
||||
if (hsvWeight <= c1Weight) {
|
||||
c1Weight = hsvWeight;
|
||||
_c1Color = i;
|
||||
}
|
||||
|
||||
// C2 color
|
||||
// Also an almost achromatic color so use the same weights as for C1 color.
|
||||
hd = h - h2;
|
||||
hd += hd < -0.5f ? 1.0f : hd > 0.5f ? -1.0f : 0.0f;
|
||||
hsvWeight = 1.0f * hd * hd + 4.0f * (s - s2) * (s - s2) + 3.0f * (v - v2) * (v - v2);
|
||||
if (hsvWeight <= c2Weight) {
|
||||
c2Weight = hsvWeight;
|
||||
_c2Color = i;
|
||||
}
|
||||
|
||||
// C3 color
|
||||
// A light rose. Use a high weight on the hue to get a rose.
|
||||
// The color is a bit gray and the saturation has not much impact so use a low weight.
|
||||
hd = h - h3;
|
||||
hd += hd < -0.5f ? 1.0f : hd > 0.5f ? -1.0f : 0.0f;
|
||||
hsvWeight = 4.0f * hd * hd + 1.0f * (s - s3) * (s - s3) + 2.0f * (v - v3) * (v - v3);
|
||||
if (hsvWeight <= c3Weight) {
|
||||
c3Weight = hsvWeight;
|
||||
_c3Color = i;
|
||||
}
|
||||
|
||||
// C4 color
|
||||
// Blue. Use a hight weight on the hue to get a blue.
|
||||
// The color is darker and more saturated than C3 and the saturation has more impact.
|
||||
hd = h - h4;
|
||||
hd += hd < -0.5f ? 1.0f : hd > 0.5f ? -1.0f : 0.0f;
|
||||
hsvWeight = 5.0f * hd * hd + 3.0f * (s - s4) * (s - s4) + 2.0f * (v - v4) * (v - v4);
|
||||
if (hsvWeight <= c4Weight) {
|
||||
c4Weight = hsvWeight;
|
||||
_c4Color = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Graphics::Surface *screen = _vm->_system->lockScreen();
|
||||
performPostProcessing((byte *)screen->getPixels());
|
||||
_vm->_system->unlockScreen();
|
||||
_vm->_system->updateScreen();
|
||||
}
|
||||
|
||||
Common::Event event;
|
||||
while (_vm->_system->getEventManager()->pollEvent(event))
|
||||
if ((event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START && event.customType == kActionEscape) || event.type == Common::EVENT_LBUTTONUP)
|
||||
skipped = true;
|
||||
|
||||
_vm->_system->delayMillis(10);
|
||||
}
|
||||
|
||||
// Need to jump back to paletted color
|
||||
if (_modeChange) {
|
||||
initGraphics(g_system->getWidth(), g_system->getHeight());
|
||||
_modeChange = false;
|
||||
}
|
||||
|
||||
return !_vm->shouldQuit() && !skipped;
|
||||
}
|
||||
|
||||
uint32 MoviePlayer::getBlackColor() {
|
||||
return (_modeChange) ? g_system->getScreenFormat().RGBToColor(0x00, 0x00, 0x00) : _black;
|
||||
}
|
||||
|
||||
uint32 MoviePlayer::findTextColor() {
|
||||
if (_modeChange) {
|
||||
// We're in true color mode, so return the actual colors
|
||||
switch (_textColor) {
|
||||
case 1:
|
||||
return g_system->getScreenFormat().RGBToColor(248, 252, 248);
|
||||
case 2:
|
||||
return g_system->getScreenFormat().RGBToColor(184, 188, 184);
|
||||
case 3:
|
||||
return g_system->getScreenFormat().RGBToColor(200, 120, 184);
|
||||
case 4:
|
||||
return g_system->getScreenFormat().RGBToColor(80, 152, 184);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return g_system->getScreenFormat().RGBToColor(0xFF, 0xFF, 0xFF);
|
||||
}
|
||||
|
||||
switch (_textColor) {
|
||||
case 1:
|
||||
return _c1Color;
|
||||
case 2:
|
||||
return _c2Color;
|
||||
case 3:
|
||||
return _c3Color;
|
||||
case 4:
|
||||
return _c4Color;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return _c1Color;
|
||||
}
|
||||
|
||||
void MoviePlayer::convertColor(byte r, byte g, byte b, float &h, float &s, float &v) {
|
||||
float varR = r / 255.0f;
|
||||
float varG = g / 255.0f;
|
||||
float varB = b / 255.0f;
|
||||
|
||||
float min = MIN(varR, MIN(varG, varB));
|
||||
float max = MAX(varR, MAX(varG, varB));
|
||||
|
||||
v = max;
|
||||
float d = max - min;
|
||||
s = max == 0.0f ? 0.0f : d / max;
|
||||
|
||||
if (min == max) {
|
||||
h = 0.0f; // achromatic
|
||||
} else {
|
||||
if (max == varR)
|
||||
h = (varG - varB) / d + (varG < varB ? 6.0f : 0.0f);
|
||||
else if (max == varG)
|
||||
h = (varB - varR) / d + 2.0f;
|
||||
else
|
||||
h = (varR - varG) / d + 4.0f;
|
||||
h /= 6.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) {
|
||||
// The PSX videos have half resolution
|
||||
|
||||
Graphics::Surface scaledFrame;
|
||||
scaledFrame.create(frame->w, frame->h * 2, frame->format);
|
||||
|
||||
for (int y = 0; y < scaledFrame.h; y++)
|
||||
memcpy(scaledFrame.getBasePtr(0, y), frame->getBasePtr(0, y / 2), scaledFrame.w * scaledFrame.format.bytesPerPixel);
|
||||
|
||||
uint16 x = (g_system->getWidth() - scaledFrame.w) / 2;
|
||||
uint16 y = (g_system->getHeight() - scaledFrame.h) / 2;
|
||||
|
||||
_vm->_system->copyRectToScreen(scaledFrame.getPixels(), scaledFrame.pitch, x, y, scaledFrame.w, scaledFrame.h);
|
||||
|
||||
scaledFrame.free();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Factory function for creating the appropriate cutscene player
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Sound *sound, OSystem *system) {
|
||||
Common::Path filename;
|
||||
|
||||
// For the PSX version, we'll try the PlayStation stream files
|
||||
if (vm->isPsx()) {
|
||||
// The demo uses the normal file names for the intro cutscene
|
||||
filename = ((vm->_systemVars.isDemo && id == 4) ? Common::Path("intro.str") : Common::Path(Common::String(sequenceListPSX[id]) + ".str"));
|
||||
|
||||
if (Common::File::exists(filename)) {
|
||||
// All BS1 PSX videos run the videos at 2x speed
|
||||
Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x);
|
||||
return new MoviePlayer(vm, textMan, resMan, sound, system, psxDecoder, kVideoDecoderPSX);
|
||||
}
|
||||
}
|
||||
|
||||
filename = Common::Path(Common::String::format("%s.smk", sequenceList[id]));
|
||||
|
||||
if (Common::File::exists(filename)) {
|
||||
Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder();
|
||||
return new MoviePlayer(vm, textMan, resMan, sound, system, smkDecoder, kVideoDecoderSMK);
|
||||
}
|
||||
|
||||
filename = Common::Path(Common::String::format("%s.dxa", sequenceList[id]));
|
||||
|
||||
if (Common::File::exists(filename)) {
|
||||
Video::VideoDecoder *dxaDecoder = new Video::DXADecoder();
|
||||
return new MoviePlayer(vm, textMan, resMan, sound, system, dxaDecoder, kVideoDecoderDXA);
|
||||
}
|
||||
|
||||
// Old MPEG2 cutscenes
|
||||
filename = Common::Path(Common::String::format("%s.mp2", sequenceList[id]));
|
||||
|
||||
if (Common::File::exists(filename)) {
|
||||
#ifdef USE_MPEG2
|
||||
// HACK: Old ScummVM builds ignored the AVI frame rate field and forced the video
|
||||
// to be played back at 12fps.
|
||||
Video::VideoDecoder *aviDecoder = new Video::AVIDecoder(12);
|
||||
return new MoviePlayer(vm, textMan, resMan, sound, system, aviDecoder, kVideoDecoderMP2);
|
||||
#else
|
||||
GUI::MessageDialog dialog(_("MPEG-2 cutscenes found but ScummVM has been built without MPEG-2 support"));
|
||||
dialog.runModal();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!vm->isPsx() || scumm_stricmp(sequenceList[id], "enddemo") != 0) {
|
||||
Common::U32String buf = Common::U32String::format(_("Cutscene '%s' not found"), sequenceList[id]);
|
||||
GUI::MessageDialog dialog(buf);
|
||||
dialog.runModal();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End of namespace Sword1
|
||||
97
engines/sword1/animation.h
Normal file
97
engines/sword1/animation.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/* 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 SWORD1_ANIMATION_H
|
||||
#define SWORD1_ANIMATION_H
|
||||
|
||||
#include "common/list.h"
|
||||
|
||||
#include "sword1/screen.h"
|
||||
#include "sword1/sound.h"
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace Video {
|
||||
class VideoDecoder;
|
||||
}
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
enum DecoderType {
|
||||
kVideoDecoderDXA = 0,
|
||||
kVideoDecoderSMK = 1,
|
||||
kVideoDecoderPSX = 2,
|
||||
kVideoDecoderMP2 = 3
|
||||
};
|
||||
|
||||
class MovieText {
|
||||
public:
|
||||
uint16 _startFrame;
|
||||
uint16 _endFrame;
|
||||
uint16 _color;
|
||||
Common::String _text;
|
||||
MovieText(int startFrame, int endFrame, const Common::String &text, int color) {
|
||||
_startFrame = startFrame;
|
||||
_endFrame = endFrame;
|
||||
_text = text;
|
||||
_color = color;
|
||||
}
|
||||
};
|
||||
|
||||
class MoviePlayer {
|
||||
public:
|
||||
MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Sound *sound, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType);
|
||||
virtual ~MoviePlayer();
|
||||
Common::Error load(uint32 id);
|
||||
void play();
|
||||
|
||||
protected:
|
||||
SwordEngine *_vm;
|
||||
Text *_textMan;
|
||||
ResMan *_resMan;
|
||||
Sound *_sound;
|
||||
OSystem *_system;
|
||||
Common::List<MovieText> _movieTexts;
|
||||
int _textX, _textY, _textWidth, _textHeight;
|
||||
int _textColor;
|
||||
uint32 _black;
|
||||
uint32 _c1Color, _c2Color, _c3Color, _c4Color;
|
||||
DecoderType _decoderType;
|
||||
bool _modeChange;
|
||||
|
||||
Video::VideoDecoder *_decoder;
|
||||
|
||||
bool playVideo();
|
||||
void performPostProcessing(byte *screen);
|
||||
void drawFramePSX(const Graphics::Surface *frame);
|
||||
|
||||
uint32 getBlackColor();
|
||||
uint32 findTextColor();
|
||||
void convertColor(byte r, byte g, byte b, float &h, float &s, float &v);
|
||||
};
|
||||
|
||||
MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Sound *sound, OSystem *system);
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif
|
||||
49
engines/sword1/collision.h
Normal file
49
engines/sword1/collision.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD1_COLLISION_H
|
||||
#define SWORD1_COLLISION_H
|
||||
|
||||
/*#include "objectman.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
class Logic;
|
||||
|
||||
class Collision {
|
||||
public:
|
||||
Collision(ObjectMan *pObjMan, Logic *pLogic);
|
||||
~Collision();
|
||||
void checkCollisions();
|
||||
void fnBumpOff();
|
||||
void fnBumpOn();
|
||||
private:
|
||||
int32 getIntersect(int32 x0, int32 y0, int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3);
|
||||
int noCol;
|
||||
ObjectMan *_objMan;
|
||||
Logic *_logic; // for CFN_preset_script
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
*/
|
||||
// maybe it's better to make this part of Router
|
||||
|
||||
#endif // BSCOLLISION_H
|
||||
3
engines/sword1/configure.engine
Normal file
3
engines/sword1/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 sword1 "Broken Sword" yes "" "" "highres" "mpeg2"
|
||||
57
engines/sword1/console.cpp
Normal file
57
engines/sword1/console.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/* 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 "sword1/console.h"
|
||||
#include "sword1/sword1.h"
|
||||
#include "sword1/sound.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
SwordConsole::SwordConsole(SwordEngine *vm) : GUI::Debugger(), _vm(vm) {
|
||||
assert(_vm);
|
||||
if (_vm->isMac())
|
||||
registerCmd("speechEndianness", WRAP_METHOD(SwordConsole, Cmd_SpeechEndianness));
|
||||
}
|
||||
|
||||
SwordConsole::~SwordConsole() {
|
||||
}
|
||||
|
||||
bool SwordConsole::Cmd_SpeechEndianness(int argc, const char **argv) {
|
||||
if (argc == 1) {
|
||||
debugPrintf("Using %s speech\n", _vm->_sound->_bigEndianSpeech ? "be" : "le");
|
||||
return true;
|
||||
}
|
||||
if (argc == 2) {
|
||||
if (scumm_stricmp(argv[1], "le") == 0) {
|
||||
_vm->_sound->_bigEndianSpeech = false;
|
||||
return false;
|
||||
} else if (scumm_stricmp(argv[1], "be") == 0) {
|
||||
_vm->_sound->_bigEndianSpeech = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
debugPrintf("Usage: %s [le | be]\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Sword
|
||||
43
engines/sword1/console.h
Normal file
43
engines/sword1/console.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD1_CONSOLE_H
|
||||
#define SWORD1_CONSOLE_H
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
class SwordEngine;
|
||||
|
||||
class SwordConsole : public GUI::Debugger {
|
||||
public:
|
||||
SwordConsole(SwordEngine *vm);
|
||||
~SwordConsole(void) override;
|
||||
|
||||
private:
|
||||
SwordEngine *_vm;
|
||||
bool Cmd_SpeechEndianness(int argc, const char **argv);
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif
|
||||
3744
engines/sword1/control.cpp
Normal file
3744
engines/sword1/control.cpp
Normal file
File diff suppressed because it is too large
Load Diff
276
engines/sword1/control.h
Normal file
276
engines/sword1/control.h
Normal file
@@ -0,0 +1,276 @@
|
||||
/* 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 SWORD1_CONTROL_H
|
||||
#define SWORD1_CONTROL_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/events.h"
|
||||
#include "common/str-array.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
|
||||
class OSystem;
|
||||
namespace Common {
|
||||
class SaveFileManager;
|
||||
class MemoryWriteStreamDynamic;
|
||||
}
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
enum SNRStatus {
|
||||
SNR_BLANK = 0,
|
||||
SNR_MAINPANEL,
|
||||
SNR_SAVE,
|
||||
SNR_RESTORE,
|
||||
SNR_RESTART,
|
||||
SNR_QUIT,
|
||||
SNR_SPEED,
|
||||
SNR_VOLUME,
|
||||
SNR_SUBTITLES,
|
||||
SNR_DONE,
|
||||
SNR_DRIVEFULL = 99
|
||||
};
|
||||
|
||||
enum SaveGameFlags {
|
||||
SGF_DONE = 0,
|
||||
SGF_SAVE,
|
||||
SGF_RESTORE,
|
||||
SGF_RESTART,
|
||||
SGF_QUIT
|
||||
};
|
||||
|
||||
enum PsxComponents {
|
||||
PSX_PANEL = 0,
|
||||
PSX_DEATHPANEL,
|
||||
PSX_CONFIRM,
|
||||
PSX_BUTTON,
|
||||
PSX_TEXT,
|
||||
PSX_SLAB,
|
||||
PSX_SCROLL
|
||||
};
|
||||
|
||||
class SwordEngine;
|
||||
class ObjectMan;
|
||||
class ResMan;
|
||||
class Mouse;
|
||||
class Sound;
|
||||
class Screen;
|
||||
class Logic;
|
||||
|
||||
#define SAVEGAME_HEADER MKTAG('B','S','_','1')
|
||||
#define SAVEGAME_VERSION 2
|
||||
|
||||
#define FIRSTFONTCHAR ' '
|
||||
#define LASTFONTCHAR (32 + 137)
|
||||
#define CR 13
|
||||
#define LF 10
|
||||
#define ESCAPE 27
|
||||
#define BACKSPACE 8
|
||||
|
||||
#define CONTROL_NOTHING_DONE 0
|
||||
#define CONTROL_GAME_RESTORED 1
|
||||
#define CONTROL_RESTART_GAME 2
|
||||
|
||||
#define VD1X 139
|
||||
#define VD2X 273
|
||||
#define VD3X 404
|
||||
#define VDY 94
|
||||
|
||||
#define SCROLL1X 311
|
||||
#define SCROLL1Y 124
|
||||
#define SCROLL2X 311
|
||||
#define SCROLL2Y 188
|
||||
|
||||
#define SAVEBUTTONS 14
|
||||
#define MAXSAVEGAMES 1000
|
||||
#define OVERLAP 3
|
||||
#define SP_OVERLAP 2
|
||||
#define TEXTBUTTONID 7
|
||||
|
||||
#define PSX_CREDITS_SPACING (-3)
|
||||
#define PSX_CREDITS_MIDDLE 450
|
||||
#define PSX_CREDITS_OFFSET 150
|
||||
#define PSX_NUM_CREDITS 14
|
||||
|
||||
struct Button {
|
||||
int32 x1;
|
||||
int32 y1;
|
||||
int32 x2;
|
||||
int32 y2;
|
||||
};
|
||||
|
||||
class Control {
|
||||
public:
|
||||
Control(SwordEngine *vm, Common::SaveFileManager *saveFileMan, ResMan *pResMan, ObjectMan *pObjMan, OSystem *system, Mouse *pMouse, Sound *pSound, Screen *pScreen, Logic *pLogic);
|
||||
|
||||
void getPlayerOptions();
|
||||
void askForCdMessage(uint32 needCD, bool incorrectCDPhase);
|
||||
void doRestore();
|
||||
bool savegamesExist();
|
||||
void saveGameToFile(uint8 slot);
|
||||
bool restoreGameFromFile(uint8 slot);
|
||||
bool restoreGame();
|
||||
void checkForOldSaveGames();
|
||||
bool isPanelShown();
|
||||
const uint8 *getPauseString();
|
||||
void psxEndCredits();
|
||||
|
||||
void setSaveDescription(int slot, const char *desc) {
|
||||
Common::strcpy_s((char *)_fileDescriptions[slot], sizeof(_fileDescriptions[slot]), desc);
|
||||
}
|
||||
|
||||
private:
|
||||
void saveRestoreScreen();
|
||||
|
||||
void renderSlab(int32 start, int32 i);
|
||||
void renderSlabs();
|
||||
void renderText(const uint8 *str, int32 x, int32 y, bool useSpeechFont = false);
|
||||
void renderRedText(const uint8 *str, int32 x, int32 y);
|
||||
void renderTexts();
|
||||
int32 getTextLength(const uint8 *str, bool useSpeechFont = false);
|
||||
|
||||
void putButton(int32 x, int32 y, int32 index);
|
||||
void putSpriteButton(Sprite *spr, int32 x, int32 y, int32 index);
|
||||
void putTextButton(int32 index);
|
||||
int32 getCurrentButton(const Button b[]);
|
||||
|
||||
void initialiseConfirmation(const uint8 *title);
|
||||
int32 implementConfirmation();
|
||||
void removeConfirmation();
|
||||
|
||||
void volUp(int32 i, int32 j);
|
||||
void volDown(int32 i, int32 j);
|
||||
void renderVolumeLight(int32 i);
|
||||
void renderVolumeDisc(int32 i, int32 j);
|
||||
void initialiseVolume();
|
||||
void implementVolume();
|
||||
void removeVolume();
|
||||
|
||||
void renderScrolls();
|
||||
void initialiseSpeed();
|
||||
void implementSpeed();
|
||||
void removeSpeed();
|
||||
|
||||
int16 readFileDescriptions();
|
||||
void setEditDescription(int32 line);
|
||||
bool driveSpaceAvailable();
|
||||
bool attemptSave();
|
||||
bool saveGame();
|
||||
void editDescription();
|
||||
void restoreSelected();
|
||||
void uneditDescription();
|
||||
void initialiseSave();
|
||||
void implementSave();
|
||||
void removeSave();
|
||||
|
||||
void initialiseRestore();
|
||||
void implementRestore();
|
||||
void removeRestore();
|
||||
|
||||
void initialiseControlPanel();
|
||||
void implementControlPanel();
|
||||
void removeControlPanel();
|
||||
|
||||
void initialiseResources();
|
||||
void releaseResources();
|
||||
|
||||
uint8 *decompressPsxGfx(uint8 *src, FrameHeader *f);
|
||||
void drawPsxComponent(int componentType, uint8 *src, uint8 *dst, FrameHeader *f);
|
||||
|
||||
bool convertSaveGame(uint8 slot, char *desc);
|
||||
|
||||
void delay(uint32 msecs);
|
||||
bool gameVersionIsAkella();
|
||||
bool gameVersionIsMediaHouse();
|
||||
bool loadCustomStrings(const char *filename);
|
||||
|
||||
int displayMessage(MSVC_PRINTF const char *message, ...) GCC_PRINTF(2, 3);
|
||||
|
||||
// PSX Credits functions
|
||||
int32 getCreditsFontHeight(uint8 *font);
|
||||
int32 getCreditsStringLength(uint8 *str, uint8 *font);
|
||||
void renderCreditsTextSprite(uint8 *data, uint8 *dst, int16 x, int16 y, int16 width, int16 height);
|
||||
void createCreditsTextSprite(uint8 *data, int32 pitch, uint8 *str, uint8 *font);
|
||||
|
||||
Common::MemoryWriteStreamDynamic *_tempThumbnail;
|
||||
static const uint8 _languageStrings[8 * 20][43];
|
||||
static const uint8 _akellaLanguageStrings[20][43];
|
||||
static const uint8 _mediaHouseLanguageStrings[20][43];
|
||||
static const uint8 _polishTranslationLanguageStrings[20][43];
|
||||
uint8 _customStrings[20][43];
|
||||
const uint8(*_lStrings)[43];
|
||||
const uint8 _psxPauseStrings[3][7] = { "Paused", "Pause", "Pausa" };
|
||||
SwordEngine *_vm;
|
||||
Common::SaveFileManager *_saveFileMan;
|
||||
ObjectMan *_objMan;
|
||||
ResMan *_resMan;
|
||||
OSystem *_system;
|
||||
Mouse *_mouse;
|
||||
Sound *_sound;
|
||||
Screen *_screen;
|
||||
Logic *_logic;
|
||||
uint8 *_screenBuf;
|
||||
Common::KeyState _keyPressed;
|
||||
Common::CustomEventType _customType;
|
||||
|
||||
Common::Point _mouseCoord;
|
||||
uint16 _mouseState;
|
||||
|
||||
int _oldSnrStatus = SNR_BLANK;
|
||||
bool _newPal = false;
|
||||
Sprite *_slabs[SAVEBUTTONS - 6];
|
||||
int32 _scrollIndex[2] = { 0, 0 };
|
||||
int32 _speedFlag = 0;
|
||||
|
||||
int32 _currentButton = 0;
|
||||
int32 _buttonPressed = 0;
|
||||
int32 _buttonHold = 0;
|
||||
int32 _slabSelected = 0;
|
||||
int32 _firstDescription = 0;
|
||||
byte _fileDescriptions[MAXSAVEGAMES][40];
|
||||
int32 _editingDescription = 0;
|
||||
int32 _gamesSaved = 0;
|
||||
int32 _textCursor;
|
||||
int32 _curCharCount;
|
||||
char _oldString[40];
|
||||
int32 _scroll = 0;
|
||||
int32 _scrollCount = 0;
|
||||
|
||||
uint8 *_restoreBuf = nullptr;
|
||||
uint32 _selectedSavegame = 0;
|
||||
uint8 _numButtons = 0;
|
||||
uint8 _selectedButton = 0;
|
||||
bool _panelShown = false;
|
||||
|
||||
static const Button panelButtons[8];
|
||||
// We want the death screen buttons to have
|
||||
// the same numbers as the panel buttons
|
||||
static const Button deathButtons[8];
|
||||
static const Button confirmButtons[2];
|
||||
static const Button speedButtons[3];
|
||||
static const Button saveButtons[SAVEBUTTONS];
|
||||
static const Button restoreButtons[SAVEBUTTONS];
|
||||
static const Button volumeButtons[25];
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif //BSCONTROL_H
|
||||
6
engines/sword1/credits.pl
Normal file
6
engines/sword1/credits.pl
Normal file
@@ -0,0 +1,6 @@
|
||||
begin_section("Sword1");
|
||||
add_person("Fabio Battaglia", "Hkz", "PSX version support");
|
||||
add_person("Andrea Boscarino", "AndywinXp", "Palette fading, menus, audio");
|
||||
add_person("Thierry Crozat", "criezy", "Mac version support");
|
||||
add_person("Robert Göffringmann", "lavosspawn", "(retired)");
|
||||
end_section();
|
||||
139
engines/sword1/debug.cpp
Normal file
139
engines/sword1/debug.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/util.h"
|
||||
#include "sword1/debug.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
void Debug::interpretScript(uint32 id, uint32 level, uint32 script, uint32 pc) {
|
||||
debug(8, "\nInterpreting %d@%d: script %X from %X", id, level, script, pc);
|
||||
}
|
||||
|
||||
void Debug::callMCode(uint32 mcodeNum, uint32 paramCount, int32 a, int32 b, int32 c, int32 d, int32 e, int32 f) {
|
||||
debug(9, "mcode: %s(%d, %d, %d, %d, %d, %d) [%d]", _mCodeNames[mcodeNum], a, b, c, d, e, f, paramCount);
|
||||
}
|
||||
|
||||
const char Debug::_mCodeNames[100][35] = {
|
||||
"fnBackground",
|
||||
"fnForeground",
|
||||
"fnSort",
|
||||
"fnNoSprite",
|
||||
"fnMegaSet",
|
||||
"fnAnim",
|
||||
"fnSetFrame",
|
||||
"fnFullAnim",
|
||||
"fnFullSetFrame",
|
||||
"fnFadeDown",
|
||||
"fnFadeUp",
|
||||
"fnCheckFade",
|
||||
"fnSetSpritePalette",
|
||||
"fnSetWholePalette",
|
||||
"fnSetFadeTargetPalette",
|
||||
"fnSetPaletteToFade",
|
||||
"fnSetPaletteToCut",
|
||||
"fnPlaySequence",
|
||||
"fnIdle",
|
||||
"fnPause",
|
||||
"fnPauseSeconds",
|
||||
"fnQuit",
|
||||
"fnKillId",
|
||||
"fnSuicide",
|
||||
"fnNewScript",
|
||||
"fnSubScript",
|
||||
"fnRestartScript",
|
||||
"fnSetBookmark",
|
||||
"fnGotoBookmark",
|
||||
"fnSendSync",
|
||||
"fnWaitSync",
|
||||
"cfnClickInteract",
|
||||
"cfnSetScript",
|
||||
"cfnPresetScript",
|
||||
"fnInteract",
|
||||
"fnIssueEvent",
|
||||
"fnCheckForEvent",
|
||||
"fnWipeHands",
|
||||
"fnISpeak",
|
||||
"fnTheyDo",
|
||||
"fnTheyDoWeWait",
|
||||
"fnWeWait",
|
||||
"fnChangeSpeechText",
|
||||
"fnTalkError",
|
||||
"fnStartTalk",
|
||||
"fnCheckForTextLine",
|
||||
"fnAddTalkWaitStatusBit",
|
||||
"fnRemoveTalkWaitStatusBit",
|
||||
"fnNoHuman",
|
||||
"fnAddHuman",
|
||||
"fnBlankMouse",
|
||||
"fnNormalMouse",
|
||||
"fnLockMouse",
|
||||
"fnUnlockMouse",
|
||||
"fnSetMousePointer",
|
||||
"fnSetMouseLuggage",
|
||||
"fnMouseOn",
|
||||
"fnMouseOff",
|
||||
"fnChooser",
|
||||
"fnEndChooser",
|
||||
"fnStartMenu",
|
||||
"fnEndMenu",
|
||||
"cfnReleaseMenu",
|
||||
"fnAddSubject",
|
||||
"fnAddObject",
|
||||
"fnRemoveObject",
|
||||
"fnEnterSection",
|
||||
"fnLeaveSection",
|
||||
"fnChangeFloor",
|
||||
"fnWalk",
|
||||
"fnTurn",
|
||||
"fnStand",
|
||||
"fnStandAt",
|
||||
"fnFace",
|
||||
"fnFaceXy",
|
||||
"fnIsFacing",
|
||||
"fnGetTo",
|
||||
"fnGetToError",
|
||||
"fnGetPos",
|
||||
"fnGetGamepadXy",
|
||||
"fnPlayFx",
|
||||
"fnStopFx",
|
||||
"fnPlayMusic",
|
||||
"fnStopMusic",
|
||||
"fnInnerSpace",
|
||||
"fnRandom",
|
||||
"fnSetScreen",
|
||||
"fnPreload",
|
||||
"fnCheckCD",
|
||||
"fnRestartGame",
|
||||
"fnQuitGame",
|
||||
"fnDeathScreen",
|
||||
"fnSetParallax",
|
||||
"fnTdebug",
|
||||
"fnRedFlash",
|
||||
"fnBlueFlash",
|
||||
"fnYellow",
|
||||
"fnGreen",
|
||||
"fnPurple",
|
||||
"fnBlack"
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
40
engines/sword1/debug.h
Normal file
40
engines/sword1/debug.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* 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 SWORD1_DEBUG_H
|
||||
#define SWORD1_DEBUG_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
class Debug {
|
||||
public:
|
||||
static void interpretScript(uint32 id, uint32 level, uint32 script, uint32 pc);
|
||||
static void callMCode(uint32 mcodeNum, uint32 paramCount, int32 a, int32 b, int32 c, int32 d, int32 e, int32 f);
|
||||
|
||||
private:
|
||||
static const char _mCodeNames[100][35];
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif // BSDEBUG_H
|
||||
75
engines/sword1/detection.cpp
Normal file
75
engines/sword1/detection.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "base/plugins.h"
|
||||
|
||||
#include "common/fs.h"
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "engines/obsolete.h"
|
||||
|
||||
#include "sword1/detection.h"
|
||||
#include "sword1/obsolete.h" // Obsolete ID table.
|
||||
|
||||
static const PlainGameDescriptor swordGames[] = {
|
||||
{"sword1", "Broken Sword: The Shadow of the Templars"},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
#include "sword1/detection_tables.h"
|
||||
|
||||
static const char *const directoryGlobs[] = {
|
||||
"smackshi",
|
||||
"video",
|
||||
nullptr
|
||||
};
|
||||
|
||||
class SwordMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
|
||||
public:
|
||||
SwordMetaEngineDetection() : AdvancedMetaEngineDetection(Sword1::gameDescriptions, swordGames) {
|
||||
_guiOptions = GUIO2(GUIO_NOMIDI, GUIO_NOASPECT);
|
||||
_flags = kADFlagMatchFullPaths;
|
||||
_directoryGlobs = directoryGlobs;
|
||||
}
|
||||
|
||||
PlainGameDescriptor findGame(const char *gameId) const override {
|
||||
return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
|
||||
}
|
||||
|
||||
Common::Error identifyGame(DetectedGame &game, const void **descriptor) override {
|
||||
Engines::upgradeTargetIfNecessary(obsoleteGameIDsTable);
|
||||
return AdvancedMetaEngineDetection::identifyGame(game, descriptor);
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "sword1";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Broken Sword: The Shadow of the Templars";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "Broken Sword: The Shadow of the Templars (C) Revolution";
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN_STATIC(SWORD1_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, SwordMetaEngineDetection);
|
||||
37
engines/sword1/detection.h
Normal file
37
engines/sword1/detection.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* 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.
|
||||
*
|
||||
* Additional copyright for this file:
|
||||
* Copyright (C) 1994-1998 Revolution Software Ltd.
|
||||
*
|
||||
* 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 SWORD1_DETECTION_H
|
||||
#define SWORD1_DETECTION_H
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#define GAMEOPTION_WINDOWS_AUDIO_MODE GUIO_GAMEOPTIONS1
|
||||
#define GAMEOPTION_MULTILANGUAGE GUIO_GAMEOPTIONS2
|
||||
#define GAMEOPTION_MULTILANGUAGE_EXTENDED GUIO_GAMEOPTIONS3
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif // SWORD1_DETECTION_H
|
||||
720
engines/sword1/detection_tables.h
Normal file
720
engines/sword1/detection_tables.h
Normal file
@@ -0,0 +1,720 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
static const ADGameDescription gameDescriptions[] = {
|
||||
{
|
||||
"sword1",
|
||||
"Demo",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "9f6de3bea49a1ef4d8b1b020c41c950e", 1070644,
|
||||
"clusters/swordres.rif", "bc01bc995f23e46bb076f66ba5c516c4", 58388,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 2696228,
|
||||
"smackshi/intro.smk", "f50d773c362d03a52a6a4d541d09449c", 13298480),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Demo",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088232,
|
||||
"clusters/swordres.rif", "3786c6850e51ecbadb65bbedb5395664", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3186195,
|
||||
"smackshi/intro.smk", "95071cd6c12c10c9a30f45a70384cf05", 13448344),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Demo",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "9f6de3bea49a1ef4d8b1b020c41c950e", 1070644,
|
||||
"clusters/swordres.rif", "babe2ab6c352bdeb0fc256a94c934bb8", 58388,
|
||||
"clusters/text.clu", "5d5bf40629364115da603da378e9d4c9", 2685487,
|
||||
"smackshi/intro.smk", "f50d773c362d03a52a6a4d541d09449c", 13298480),
|
||||
Common::PT_BRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Demo",
|
||||
AD_ENTRY4s("clusters/scripts.clm", "6b6d9a32668e6f0285318dbe33f167fe", 1088468,
|
||||
"clusters/swordres.rif", "6b579d7cd94756f5c1e362a9b61f94a3", 59788,
|
||||
"speech/speech.clu", "36919b35067bf56b68ad538732a618c2", 45528200,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_DEMO,
|
||||
GUIO0()
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Demo",
|
||||
AD_ENTRY3s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088372,
|
||||
"swordres.rif", "5bd8928071b91830be6fbcdb7f59786d", 59788,
|
||||
"english/speech.inf", "57f6d6949262cd63fc0378dd2375c819", 1662),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformPSX,
|
||||
ADGF_DEMO,
|
||||
GUIO0()
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Demo",
|
||||
AD_ENTRY3s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088372,
|
||||
"swordres.rif", "5bd8928071b91830be6fbcdb7f59786d", 59788,
|
||||
"italian/speech.inf", "af982fbfd4fdd39ea7108dc8f77cf1b3", 1652),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformPSX,
|
||||
ADGF_DEMO,
|
||||
GUIO0()
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088232,
|
||||
"clusters/swordres.rif", "08d4942cf7c904182a31a1d5333244f3", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3193923,
|
||||
"smackshi/intro.smk", "6689aa8f84cb0387b292481d2a2428b4", 13076700),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"clusters/swordres.rif", "d21d6321ee2dbb2d7d7ca2d2a940c34a", 58916,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 2704592,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::EN_GRB,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{ // 25th Anniversary rerelease / Steam DLC for Director's Cut
|
||||
"sword1",
|
||||
"25th Anniversary",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"swordres.rif", "d21d6321ee2dbb2d7d7ca2d2a940c34a", 58916,
|
||||
"text.clu", "76f93f5feecc8915435105478f3c6615", 2704592,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::EN_GRB,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Rerelease",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088292,
|
||||
"clusters/swordres.rif", "5463362dc77b6efc36e46ac84998bd2f", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3193159,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::EN_GRB,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"GOG.com",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088292,
|
||||
"clusters/swordres.rif", "5463362dc77b6efc36e46ac84998bd2f", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3193159,
|
||||
"video/intro.dxa", "e27cd33593c08b66e8d20fbc40938789", 7420364),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{ // Bundled with ScummVM 0.8
|
||||
// Reported by YetAnotherGuy via IRC
|
||||
"sword1",
|
||||
"SoldOut rerelease",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088292,
|
||||
"clusters/swordres.rif", "5463362dc77b6efc36e46ac84998bd2f", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3193159,
|
||||
"video/intro.mp2", "c3e0ab75e8686c746899a9b6cecceac9", 8739102),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087984,
|
||||
"clusters/swordres.rif", "c7df52094d590b568a4ed35b70390d9e", 58916,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 2705446,
|
||||
"smackshi/intro.smk", "d602a28f5f5c583bf9870a23a94a9bc5", 13525168),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{ // This is apparently one of the frankensten versions floating around
|
||||
// See reports #14865, #15089 and #15376
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087984,
|
||||
"swordres.rif", "c7df52094d590b568a4ed35b70390d9e", 58916,
|
||||
"text.clu", "76f93f5feecc8915435105478f3c6615", 2705446,
|
||||
"smackshi/intro.smk", "d602a28f5f5c583bf9870a23a94a9bc5", 13525168),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_PIRATED,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088372,
|
||||
"clusters/swordres.rif", "665b7ed64c13013ec4a8bcd101a1e862", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3188750,
|
||||
"smackshi/intro.smk", "d602a28f5f5c583bf9870a23a94a9bc5", 13525168),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Steam",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087984,
|
||||
"swordres.rif", "c7df52094d590b568a4ed35b70390d9e", 58916,
|
||||
"text.clu", "76f93f5feecc8915435105478f3c6615", 2705446,
|
||||
"smackshi/intro.smk", "fe087447e0e525e371cf10cfabf589eb", 14524000),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087984,
|
||||
"clusters/swordres.rif", "c7df52094d590b568a4ed35b70390d9e", 58916,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 2705446,
|
||||
"smackshi/intro.smk", "78e3ba96f33be8c2ef8feb46724cfef5", 11537716),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"clusters/swordres.rif", "b0ae5a47aba74dc0acb3442d4c84b225", 58916,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 2705446,
|
||||
"smackshi/intro.smk", "d1d0e958aeef9b1375b55df8f8831f26", 13281776),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Steam",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"swordres.rif", "b0ae5a47aba74dc0acb3442d4c84b225", 58916,
|
||||
"text.clu", "76f93f5feecc8915435105478f3c6615", 2705446,
|
||||
"smackshi/intro.smk", "d1d0e958aeef9b1375b55df8f8831f26", 13281776),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{ // German DVD Trilogy collection
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"clusters/swordres.rif", "b0ae5a47aba74dc0acb3442d4c84b225", 58916,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 2705446,
|
||||
"video/intro.dxa", "e27cd33593c08b66e8d20fbc40938789", 7397543),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{ // GOG.com version + german translation from tickets #14592, #14642, #15763
|
||||
"sword1",
|
||||
"GOG.com",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088292,
|
||||
"clusters/swordres.rif", "5463362dc77b6efc36e46ac84998bd2f", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3193159,
|
||||
"video/intro.dxa", "e27cd33593c08b66e8d20fbc40938789", 7397543),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{ // German version of "Revolution Classic Adventures"
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"clusters/swordres.rif", "b0ae5a47aba74dc0acb3442d4c84b225", 58916,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 2705446,
|
||||
"smackshi/intro.smk", "40a2106393c2a749304de0545ddcb7f6", 11542280),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088232,
|
||||
"clusters/swordres.rif", "08d4942cf7c904182a31a1d5333244f3", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3193923,
|
||||
"smackshi/intro.smk", "95071cd6c12c10c9a30f45a70384cf05", 13448344),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{ // Alternate version
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088232,
|
||||
"clusters/swordres.rif", "08d4942cf7c904182a31a1d5333244f3", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3193923,
|
||||
"smackshi/intro.smk", "a8c6a8770cb4b2669f4263ece8830985", 13293740),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Steam",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088232,
|
||||
"swordres.rif", "08d4942cf7c904182a31a1d5333244f3", 59788,
|
||||
"text.clu", "76f93f5feecc8915435105478f3c6615", 3193923,
|
||||
"smackshi/intro.smk", "a8c6a8770cb4b2669f4263ece8830985", 13293740),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088372,
|
||||
"clusters/swordres.rif", "239bdd76c405bad0f804a8ae5df4adb0", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3188725,
|
||||
"smackshi/intro.smk", "83060041aa155d802e51b7211b62ea2f", 13525252),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088372,
|
||||
"swordres.rif", "239bdd76c405bad0f804a8ae5df4adb0", 59788,
|
||||
"text.clu", "76f93f5feecc8915435105478f3c6615", 3188725,
|
||||
"smackshi/intro.smk", "83060041aa155d802e51b7211b62ea2f", 13525252),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Steam",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088372,
|
||||
"swordres.rif", "239bdd76c405bad0f804a8ae5df4adb0", 59788,
|
||||
"text.clu", "76f93f5feecc8915435105478f3c6615", 3188725,
|
||||
"smackshi/intro.smk", "939643be076c73068f47ce0fd6c27183", 13305080),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"English speech",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088468,
|
||||
"clusters/swordres.rif", "34c111f224e75050a523dc758c71d54e", 60612,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3164478,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::PT_PRT,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE_EXTENDED)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"TecToy",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088468,
|
||||
"clusters/swordres.rif", "34c111f224e75050a523dc758c71d54e", 60612,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3164478,
|
||||
"smackshi/intro.smk", "4a7343c3d59526dcab04be7a6af3943a", 13238300),
|
||||
Common::PT_BRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE_EXTENDED)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"English speech",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088292,
|
||||
"clusters/swordres.rif", "ba6f881c3ace6408880c8e07cd8a1dfe", 59788,
|
||||
"clusters/text.clu", "0c0f9eadf20a497834685ccb3ba53a3f", 397478,
|
||||
"video/intro.smk", "d07ba8a1be7d8a47de50cc4eac2bc243", 13082688),
|
||||
Common::HE_ISR,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"English speech",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"clusters/swordres.rif", "88c0793a4fa908083b00f6677c545f78", 58916,
|
||||
"clusters/text.clu", "7d9e47533fde5333dc310bfd73eaeb5c", 2666944,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::PL_POL,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"English speech and DXA cutscenes",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088292,
|
||||
"clusters/swordres.rif", "04a41fc5783d18a8958d41aa9a3823af", 59788,
|
||||
"clusters/text.clu", "b9e7b3e342569be68738e4681f2adeff", 3164267,
|
||||
"intro.dxa", nullptr, AD_NO_SIZE),
|
||||
Common::PL_POL,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"English speech",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"clusters/swordres.rif", "7188a3ec8d486fd9179f06968369c011", 58916,
|
||||
"clusters/text.clu", "b9e7b3e342569be68738e4681f2adeff", 2675700,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::PL_POL,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"English speech",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"clusters/swordres.rif", "31ea11161d5d2200b6b44a833b7d5aa8", 58916,
|
||||
"clusters/text.clu", "7d9e47533fde5333dc310bfd73eaeb5c", 2666334,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::PL_POL,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"English speech",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088372,
|
||||
"clusters/swordres.rif", "04a41fc5783d18a8958d41aa9a3823af", 59788,
|
||||
"clusters/text.clu", "b9e7b3e342569be68738e4681f2adeff", 3164267,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::PL_POL,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"English speech",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088292,
|
||||
"clusters/swordres.rif", "5463362dc77b6efc36e46ac84998bd2f", 59788,
|
||||
"clusters/text.clu", "cf6a85c2d60386a3c978f0c6fbb377bd", 3193159,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::HU_HUN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"English speech",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088372,
|
||||
"clusters/swordres.rif", "239bdd76c405bad0f804a8ae5df4adb0", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3199652,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::CS_CZE,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE_EXTENDED)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"English speech and DXA cutscenes",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088372,
|
||||
"clusters/swordres.rif", "239bdd76c405bad0f804a8ae5df4adb0", 59788,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3199652,
|
||||
"intro.dxa", nullptr, AD_NO_SIZE),
|
||||
Common::CS_CZE,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GAMEOPTION_WINDOWS_AUDIO_MODE, GAMEOPTION_MULTILANGUAGE_EXTENDED)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Akella",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"clusters/swordres.rif", "e7021abec62dd774010d1f432ef9f03a", 58916,
|
||||
"clusters/text.clu", "524706e42583f6c23a5a7ae3e1784068", 2683625,
|
||||
"smackshi/intro.smk", "ef3ae780668c087fae00ed9c46c2eb35", 13386716),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Mediahauz",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"clusters/swordres.rif", "7a6e896064c8d2ee266e961549487204", 58916,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3198686,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{ // Alternate version, from a DVD collection containing both BS1 and BS2
|
||||
"sword1",
|
||||
"Mediahauz",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"clusters/swordres.rif", "7a6e896064c8d2ee266e961549487204", 58916,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 3198686,
|
||||
"smackshi/intro.smk", "432215e04bb74ad823e033bc774f97d7", 14098520),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"Novy Disk",
|
||||
AD_ENTRY4s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088292,
|
||||
"clusters/swordres.rif", "b5d9ddbe26d453415a43596f86452435", 59788,
|
||||
"clusters/text.clu", "8392ae2af0a8bec1dca511b2fedddc4c", 3178811,
|
||||
"video/intro.dxa", "e27cd33593c08b66e8d20fbc40938789", 7420364),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{ // Korean fan translation
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY6s("clusters/scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1087240,
|
||||
"clusters/swordres.rif", "d21d6321ee2dbb2d7d7ca2d2a940c34a", 58916,
|
||||
"clusters/text.clu", "76f93f5feecc8915435105478f3c6615", 2704592,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268,
|
||||
"bs1k.fnt", NULL, 1222000,
|
||||
"korean.clu", NULL, AD_NO_SIZE),
|
||||
Common::KO_KOR,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_WINDOWS_AUDIO_MODE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clm", "6b6d9a32668e6f0285318dbe33f167fe", 1088468,
|
||||
"clusters/swordres.rif", "6b579d7cd94756f5c1e362a9b61f94a3", 59788,
|
||||
"smackshi/credits.smk", "eacbc81d3ef88628d3710abbbcdc9aa0", 17300736,
|
||||
"smackshi/intro.smk", "6689aa8f84cb0387b292481d2a2428b4", 13076700),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clm", "6b6d9a32668e6f0285318dbe33f167fe", 1088468,
|
||||
"clusters/swordres.rif", "6b579d7cd94756f5c1e362a9b61f94a3", 59788,
|
||||
"smackshi/credits.smk", "9a3fe9cb76bc7ca8a9987c173befb90d", 16315740,
|
||||
"smackshi/intro.smk", "d82a7869ace8fcecaa519c04c4bfc483", 13233268),
|
||||
Common::EN_GRB,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("clusters/scripts.clm", "6b6d9a32668e6f0285318dbe33f167fe", 1088468,
|
||||
"clusters/swordres.rif", "6b579d7cd94756f5c1e362a9b61f94a3", 59788,
|
||||
"smackshi/credits.smk", "0e4eb849d60baab975130efd35f15ace", 17528016,
|
||||
"smackshi/intro.smk", "d602a28f5f5c583bf9870a23a94a9bc5", 13525168),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GAMEOPTION_MULTILANGUAGE)
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088468,
|
||||
"swordres.rif", "a810e6dc5c8e636151a3e1370d41d138", 59788,
|
||||
"credits.dat", "2ec14f1f262cdd2c87dd95acced9e2f6", 3312,
|
||||
"speech.inf", "ed14c2a235cf5388ac3b5f29db129837", 21310),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformPSX,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088468,
|
||||
"swordres.rif", "a810e6dc5c8e636151a3e1370d41d138", 59788,
|
||||
"credits.dat", "69349710eef6b653ed2c02643ed6c4a0", 2799,
|
||||
"speech.inf", "ed14c2a235cf5388ac3b5f29db129837", 21310),
|
||||
Common::EN_GRB,
|
||||
Common::kPlatformPSX,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("scripts.clu" , "72b10193714e8c6e4daca51791c0db0c", 1088468,
|
||||
"swordres.rif", "a810e6dc5c8e636151a3e1370d41d138", 59788,
|
||||
"credits.dat", "0b119d49f27260e6115504c135b9bb19", 2382,
|
||||
"speech.inf", "2ccb9be1a3d8d0e33d6efd6a12a24320", 21450),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformPSX,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088468,
|
||||
"swordres.rif", "a810e6dc5c8e636151a3e1370d41d138", 59788,
|
||||
"credits.dat", "c4f84aaa17f80fb549a5c8a867a9836a", 2382,
|
||||
"speech.inf", "403fb61f9de6ce6cb374edd9985066ae", 21304),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformPSX,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088372,
|
||||
"swordres.rif", "5bd8928071b91830be6fbcdb7f59786d", 59788,
|
||||
"credits.dat", "949806fa3eaa4ff3a6c19ee4b5caa9f5", 2823,
|
||||
"speech.inf", "1165f01823e4d2df72fcc5b592a4960e", 21374),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformPSX,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
|
||||
{
|
||||
"sword1",
|
||||
"",
|
||||
AD_ENTRY4s("scripts.clu", "72b10193714e8c6e4daca51791c0db0c", 1088372,
|
||||
"swordres.rif", "5bd8928071b91830be6fbcdb7f59786d", 59788,
|
||||
"credits.dat", "cd97e8f5006d91914904b3bfdb0ff588", 2412,
|
||||
"speech.inf", "d4558d96ce696a906b086c2b44ffb301", 21342),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformPSX,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO0()
|
||||
},
|
||||
|
||||
AD_TABLE_END_MARKER
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
105
engines/sword1/eventman.cpp
Normal file
105
engines/sword1/eventman.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
/* 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 "sword1/eventman.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/util.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
EventManager::EventManager() {
|
||||
for (uint8 cnt = 0; cnt < TOTAL_EVENT_SLOTS; cnt++)
|
||||
_eventPendingList[cnt].delay = _eventPendingList[cnt].eventNumber = 0;
|
||||
}
|
||||
|
||||
void EventManager::serviceGlobalEventList() {
|
||||
for (uint8 slot = 0; slot < TOTAL_EVENT_SLOTS; slot++)
|
||||
if (_eventPendingList[slot].delay)
|
||||
_eventPendingList[slot].delay--;
|
||||
}
|
||||
|
||||
void EventManager::checkForEvent(Object *compact) {
|
||||
for (uint8 objCnt = 0; objCnt < O_TOTAL_EVENTS; objCnt++) {
|
||||
if (compact->o_event_list[objCnt].o_event)
|
||||
for (uint8 globCnt = 0; globCnt < TOTAL_EVENT_SLOTS; globCnt++) {
|
||||
if (_eventPendingList[globCnt].delay &&
|
||||
(_eventPendingList[globCnt].eventNumber == compact->o_event_list[objCnt].o_event)) {
|
||||
compact->o_logic = LOGIC_script; //force into script mode
|
||||
_eventPendingList[globCnt].delay = 0; //started, so remove from queue
|
||||
compact->o_tree.o_script_level++;
|
||||
compact->o_tree.o_script_id[compact->o_tree.o_script_level] =
|
||||
compact->o_event_list[objCnt].o_event_script;
|
||||
compact->o_tree.o_script_pc[compact->o_tree.o_script_level] =
|
||||
compact->o_event_list[objCnt].o_event_script;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EventManager::eventValid(int32 event) {
|
||||
for (uint8 slot = 0; slot < TOTAL_EVENT_SLOTS; slot++)
|
||||
if ((_eventPendingList[slot].eventNumber == event) &&
|
||||
(_eventPendingList[slot].delay))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int EventManager::fnCheckForEvent(Object *cpt, int32 id, int32 pause) {
|
||||
if (pause) {
|
||||
cpt->o_pause = pause;
|
||||
cpt->o_logic = LOGIC_pause_for_event;
|
||||
return SCRIPT_STOP;
|
||||
}
|
||||
|
||||
for (uint8 objCnt = 0; objCnt < O_TOTAL_EVENTS; objCnt++) {
|
||||
if (cpt->o_event_list[objCnt].o_event)
|
||||
for (uint8 globCnt = 0; globCnt < TOTAL_EVENT_SLOTS; globCnt++) {
|
||||
if (_eventPendingList[globCnt].delay &&
|
||||
(_eventPendingList[globCnt].eventNumber == cpt->o_event_list[objCnt].o_event)) {
|
||||
cpt->o_logic = LOGIC_script; //force into script mode
|
||||
_eventPendingList[globCnt].delay = 0; //started, so remove from queue
|
||||
cpt->o_tree.o_script_level++;
|
||||
cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] =
|
||||
cpt->o_event_list[objCnt].o_event_script;
|
||||
cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] =
|
||||
cpt->o_event_list[objCnt].o_event_script;
|
||||
return SCRIPT_STOP;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SCRIPT_CONT;
|
||||
}
|
||||
|
||||
void EventManager::fnIssueEvent(Object *compact, int32 id, int32 event, int32 delay) {
|
||||
uint8 evSlot = 0;
|
||||
while (_eventPendingList[evSlot].delay)
|
||||
evSlot++;
|
||||
if (evSlot >= TOTAL_EVENT_SLOTS)
|
||||
error("EventManager ran out of event slots");
|
||||
_eventPendingList[evSlot].delay = delay;
|
||||
_eventPendingList[evSlot].eventNumber = event;
|
||||
}
|
||||
|
||||
} // End of namespace Sword1
|
||||
50
engines/sword1/eventman.h
Normal file
50
engines/sword1/eventman.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SWORD1_EVENTMAN_H
|
||||
#define SWORD1_EVENTMAN_H
|
||||
|
||||
#include "sword1/object.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#define TOTAL_EVENT_SLOTS 20
|
||||
|
||||
struct GlobalEvent {
|
||||
int32 eventNumber;
|
||||
int32 delay;
|
||||
};
|
||||
|
||||
class EventManager {
|
||||
public:
|
||||
EventManager();
|
||||
void serviceGlobalEventList();
|
||||
void checkForEvent(Object *compact);
|
||||
int fnCheckForEvent(Object *cpt, int32 id, int32 pause);
|
||||
void fnIssueEvent(Object *compact, int32 id, int32 event, int32 delay);
|
||||
bool eventValid(int32 event);
|
||||
private:
|
||||
GlobalEvent _eventPendingList[TOTAL_EVENT_SLOTS];
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif // BSEVENTMAN_H
|
||||
1987
engines/sword1/logic.cpp
Normal file
1987
engines/sword1/logic.cpp
Normal file
File diff suppressed because it is too large
Load Diff
249
engines/sword1/logic.h
Normal file
249
engines/sword1/logic.h
Normal file
@@ -0,0 +1,249 @@
|
||||
/* 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 SWORD1_LOGIC_H
|
||||
#define SWORD1_LOGIC_H
|
||||
// combination of logic.c and scr_int.c
|
||||
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "sword1/objectman.h"
|
||||
#include "common/util.h"
|
||||
#include "common/random.h"
|
||||
|
||||
class OSystem;
|
||||
|
||||
namespace Audio {
|
||||
class Mixer;
|
||||
}
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#define NON_ZERO_SCRIPT_VARS 95
|
||||
#define NUM_SCRIPT_VARS 1179
|
||||
|
||||
class SwordEngine;
|
||||
class Text;
|
||||
class Sound;
|
||||
class EventManager;
|
||||
class Menu;
|
||||
class Router;
|
||||
class Screen;
|
||||
class Mouse;
|
||||
class Control;
|
||||
|
||||
class Logic;
|
||||
typedef int (Logic::*BSMcodeTable)(Object *, int32, int32, int32, int32, int32, int32, int32);
|
||||
|
||||
class Logic {
|
||||
friend class Control;
|
||||
public:
|
||||
Logic(SwordEngine *vm, ObjectMan *pObjMan, ResMan *resMan, Screen *pScreen, Mouse *pMouse, Sound *pSound, Menu *pMenu, OSystem *system, Audio::Mixer *mixer);
|
||||
~Logic();
|
||||
void initialize();
|
||||
void setControlPanelObject(Control *control);
|
||||
void newScreen(uint32 screen);
|
||||
void engine();
|
||||
void updateScreenParams();
|
||||
void runMouseScript(Object *cpt, int32 scriptId);
|
||||
void startPositions(uint32 pos);
|
||||
bool canShowDebugTextNumber();
|
||||
void plotRouteGrid(Object *megaObject);
|
||||
|
||||
static uint32 _scriptVars[NUM_SCRIPT_VARS];
|
||||
// public for mouse (menu looking)
|
||||
int cfnPresetScript(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
private:
|
||||
SwordEngine *_vm;
|
||||
ObjectMan *_objMan;
|
||||
OSystem *_system;
|
||||
Audio::Mixer *_mixer;
|
||||
ResMan *_resMan;
|
||||
Screen *_screen;
|
||||
Sound *_sound;
|
||||
Mouse *_mouse;
|
||||
Router *_router;
|
||||
Text *_textMan;
|
||||
EventManager *_eventMan;
|
||||
Menu *_menu;
|
||||
Control *_control;
|
||||
uint32 _newScript; // <= ugly, but I can't avoid it.
|
||||
uint8 _speechClickDelay = 0;
|
||||
Common::RandomSource _rnd;
|
||||
bool _psxFudgeRandom = false; // Used within fnIdle() and fnRandom() for the PSX version
|
||||
|
||||
int scriptManager(Object *compact, uint32 id);
|
||||
void processLogic(Object *compact, uint32 id);
|
||||
int interpretScript(Object *compact, int id, Header *scriptModule, int scriptBase, int scriptNum);
|
||||
|
||||
int logicWaitTalk(Object *compact);
|
||||
int logicStartTalk(Object *compact);
|
||||
int logicArAnimate(Object *compact, uint32 id);
|
||||
int speechDriver(Object *compact);
|
||||
int fullAnimDriver(Object *compact);
|
||||
int animDriver(Object *compact);
|
||||
|
||||
void setupMcodeTable();
|
||||
const BSMcodeTable *_mcodeTable;
|
||||
|
||||
//- mcodeTable:
|
||||
int fnBackground(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnForeground(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSort(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnNoSprite(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnMegaSet(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnAnim(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSetFrame(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnFullAnim(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnFullSetFrame(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnFadeDown(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnFadeUp(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnCheckFade(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSetSpritePalette(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSetWholePalette(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSetFadeTargetPalette(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSetPaletteToFade(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSetPaletteToCut(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnPlaySequence(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
|
||||
int fnIdle(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnPause(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnPauseSeconds(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnQuit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnKillId(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSuicide(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnNewScript(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSubScript(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnRestartScript(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSetBookmark(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnGotoBookmark(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSendSync(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnWaitSync(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
|
||||
int cfnClickInteract(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int cfnSetScript(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
|
||||
int fnInteract(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnIssueEvent(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnCheckForEvent(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnWipeHands(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnISpeak(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnTheyDo(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnTheyDoWeWait(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnWeWait(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnChangeSpeechText(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnTalkError(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnStartTalk(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnCheckForTextLine(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnAddTalkWaitStatusBit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnRemoveTalkWaitStatusBit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
|
||||
int fnNoHuman(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnAddHuman(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnBlankMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnNormalMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnLockMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnUnlockMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSetMousePointer(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSetMouseLuggage(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnMouseOn(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnMouseOff(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnChooser(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnEndChooser(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnStartMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnEndMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
|
||||
int cfnReleaseMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
|
||||
int fnAddSubject(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnAddObject(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnRemoveObject(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnEnterSection(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnLeaveSection(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnChangeFloor(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnWalk(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnTurn(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnStand(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnStandAt(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnFace(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnFaceXy(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnIsFacing(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnGetTo(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnGetToError(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnGetPos(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnGetGamepadXy(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnPlayFx(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnStopFx(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnPlayMusic(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnStopMusic(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnInnerSpace(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnRandom(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSetScreen(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnPreload(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnCheckCD(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnRestartGame(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnQuitGame(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnDeathScreen(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnSetParallax(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnTdebug(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
|
||||
int fnRedFlash(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnBlueFlash(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnYellow(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnGreen(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnPurple(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
int fnBlack(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
|
||||
static const uint32 _scriptVarInit[NON_ZERO_SCRIPT_VARS][2];
|
||||
static const uint8 *const _startData[];
|
||||
static const uint8 *const _helperData[];
|
||||
void startPosCallFn(uint8 fnId, uint32 param1, uint32 param2, uint32 param3);
|
||||
void runStartScript(const uint8 *data);
|
||||
};
|
||||
|
||||
enum StartPosOpcodes {
|
||||
opcSeqEnd = 0,
|
||||
opcCallFn,
|
||||
opcCallFnLong,
|
||||
opcSetVar8,
|
||||
opcSetVar16,
|
||||
opcSetVar32,
|
||||
opcGeorge,
|
||||
opcRunStart,
|
||||
opcRunHelper,
|
||||
opcPlaySequence,
|
||||
opcAddObject,
|
||||
opcRemoveObject,
|
||||
opcMegaSet,
|
||||
opcNoSprite
|
||||
};
|
||||
|
||||
enum HelperScripts {
|
||||
HELP_IRELAND = 0,
|
||||
HELP_SYRIA,
|
||||
HELP_SPAIN,
|
||||
HELP_NIGHTTRAIN,
|
||||
HELP_SCOTLAND,
|
||||
HELP_WHITECOAT,
|
||||
HELP_SPAIN2
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif //BSLOGIC_H
|
||||
138
engines/sword1/memman.cpp
Normal file
138
engines/sword1/memman.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "sword1/memman.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/util.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
MemMan::MemMan() {
|
||||
_alloced = 0;
|
||||
_memListFree = _memListFreeEnd = nullptr;
|
||||
}
|
||||
|
||||
MemMan::~MemMan() {
|
||||
flush();
|
||||
if (_alloced)
|
||||
warning("deleting MemMan, still %d bytes alloced", _alloced);
|
||||
}
|
||||
|
||||
void MemMan::alloc(MemHandle *bsMem, uint32 pSize, uint16 pCond) {
|
||||
_alloced += pSize;
|
||||
bsMem->data = (void *)malloc(pSize);
|
||||
if (!bsMem->data)
|
||||
error("MemMan::alloc(): Can't alloc %d bytes of memory.", pSize);
|
||||
bsMem->cond = pCond;
|
||||
bsMem->size = pSize;
|
||||
if (pCond == MEM_CAN_FREE) {
|
||||
warning("%d Bytes alloced as FREEABLE.", pSize); // why should one want to alloc mem if it can be freed?
|
||||
addToFreeList(bsMem);
|
||||
} else if (bsMem->next || bsMem->prev) // it's in our _freeAble list, remove it from there
|
||||
removeFromFreeList(bsMem);
|
||||
checkMemoryUsage();
|
||||
}
|
||||
|
||||
void MemMan::freeNow(MemHandle *bsMem) {
|
||||
if (bsMem->cond != MEM_FREED) {
|
||||
_alloced -= bsMem->size;
|
||||
removeFromFreeList(bsMem);
|
||||
free(bsMem->data);
|
||||
bsMem->cond = MEM_FREED;
|
||||
}
|
||||
}
|
||||
|
||||
void MemMan::setCondition(MemHandle *bsMem, uint16 pCond) {
|
||||
if ((pCond == MEM_FREED) || (pCond > MEM_DONT_FREE))
|
||||
error("MemMan::setCondition: program tried to set illegal memory condition");
|
||||
if (bsMem->cond != pCond) {
|
||||
bsMem->cond = pCond;
|
||||
if (pCond == MEM_DONT_FREE)
|
||||
removeFromFreeList(bsMem);
|
||||
else if (pCond == MEM_CAN_FREE)
|
||||
addToFreeList(bsMem);
|
||||
}
|
||||
}
|
||||
|
||||
void MemMan::flush() {
|
||||
while (_memListFree) {
|
||||
if (_memListFreeEnd == nullptr) {
|
||||
warning("MemMan::flush(): _memListFreeEnd is nullptr");
|
||||
break;
|
||||
}
|
||||
free(_memListFreeEnd->data);
|
||||
_memListFreeEnd->data = nullptr;
|
||||
_memListFreeEnd->cond = MEM_FREED;
|
||||
_alloced -= _memListFreeEnd->size;
|
||||
removeFromFreeList(_memListFreeEnd);
|
||||
}
|
||||
|
||||
if (_alloced)
|
||||
warning("MemMan::flush: Something's wrong: still %d bytes alloced", _alloced);
|
||||
}
|
||||
|
||||
void MemMan::checkMemoryUsage() {
|
||||
while ((_alloced > MAX_ALLOC) && _memListFree) {
|
||||
if (_memListFreeEnd == nullptr) {
|
||||
warning("MemMan::checkMemoryUsage(): _memListFreeEnd is nullptr");
|
||||
break;
|
||||
}
|
||||
free(_memListFreeEnd->data);
|
||||
_memListFreeEnd->data = nullptr;
|
||||
_memListFreeEnd->cond = MEM_FREED;
|
||||
_alloced -= _memListFreeEnd->size;
|
||||
removeFromFreeList(_memListFreeEnd);
|
||||
}
|
||||
}
|
||||
|
||||
void MemMan::addToFreeList(MemHandle *bsMem) {
|
||||
if (bsMem->next || bsMem->prev) {
|
||||
warning("addToFreeList: mem block is already in freeList");
|
||||
return;
|
||||
}
|
||||
bsMem->prev = nullptr;
|
||||
bsMem->next = _memListFree;
|
||||
if (bsMem->next)
|
||||
bsMem->next->prev = bsMem;
|
||||
_memListFree = bsMem;
|
||||
if (!_memListFreeEnd)
|
||||
_memListFreeEnd = _memListFree;
|
||||
}
|
||||
|
||||
void MemMan::removeFromFreeList(MemHandle *bsMem) {
|
||||
if (_memListFree == bsMem)
|
||||
_memListFree = bsMem->next;
|
||||
if (_memListFreeEnd == bsMem)
|
||||
_memListFreeEnd = bsMem->prev;
|
||||
|
||||
if (bsMem->next)
|
||||
bsMem->next->prev = bsMem->prev;
|
||||
if (bsMem->prev)
|
||||
bsMem->prev->next = bsMem->next;
|
||||
bsMem->next = bsMem->prev = nullptr;
|
||||
}
|
||||
|
||||
void MemMan::initHandle(MemHandle *bsMem) {
|
||||
memset(bsMem, 0, sizeof(MemHandle));
|
||||
}
|
||||
|
||||
} // End of namespace Sword1
|
||||
63
engines/sword1/memman.h
Normal file
63
engines/sword1/memman.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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 SWORD1_MEMMAN_H
|
||||
#define SWORD1_MEMMAN_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
struct MemHandle {
|
||||
void *data;
|
||||
uint32 size;
|
||||
uint32 refCount;
|
||||
uint16 cond;
|
||||
MemHandle *next, *prev;
|
||||
};
|
||||
// mem conditions:
|
||||
#define MEM_FREED 0
|
||||
#define MEM_CAN_FREE 1
|
||||
#define MEM_DONT_FREE 2
|
||||
|
||||
#define MAX_ALLOC (6*1024*1024) // max amount of mem we want to alloc().
|
||||
|
||||
class MemMan {
|
||||
public:
|
||||
MemMan();
|
||||
~MemMan();
|
||||
void alloc(MemHandle *bsMem, uint32 pSize, uint16 pCond = MEM_DONT_FREE);
|
||||
void setCondition(MemHandle *bsMem, uint16 pCond);
|
||||
void freeNow(MemHandle *bsMem);
|
||||
void initHandle(MemHandle *bsMem);
|
||||
void flush();
|
||||
private:
|
||||
void addToFreeList(MemHandle *bsMem);
|
||||
void removeFromFreeList(MemHandle *bsMem);
|
||||
void checkMemoryUsage();
|
||||
uint32 _alloced; //currently allocated memory
|
||||
MemHandle *_memListFree;
|
||||
MemHandle *_memListFreeEnd;
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif //MEMMAN_H
|
||||
452
engines/sword1/menu.cpp
Normal file
452
engines/sword1/menu.cpp
Normal file
@@ -0,0 +1,452 @@
|
||||
/* 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 "sword1/menu.h"
|
||||
#include "sword1/resman.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/util.h"
|
||||
#include "common/system.h"
|
||||
#include "sword1/mouse.h"
|
||||
#include "sword1/screen.h"
|
||||
#include "sword1/logic.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
enum {
|
||||
MENU_CLOSED,
|
||||
MENU_CLOSING,
|
||||
MENU_OPENING,
|
||||
MENU_OPEN
|
||||
};
|
||||
|
||||
const byte Menu::_fadeEffectTop[64] = {
|
||||
1, 7, 5, 3, 2, 4, 6, 0,
|
||||
3, 1, 7, 5, 4, 6, 0, 2,
|
||||
5, 3, 1, 7, 6, 0, 2, 4,
|
||||
7, 5, 3, 1, 0, 2, 4, 6,
|
||||
7, 5, 3, 1, 0, 2, 4, 6,
|
||||
5, 3, 1, 7, 6, 0, 2, 4,
|
||||
3, 1, 7, 5, 4, 6, 0, 2,
|
||||
1, 7, 5, 3, 2, 4, 6, 0
|
||||
};
|
||||
|
||||
const byte Menu::_fadeEffectBottom[64] = {
|
||||
7, 6, 5, 4, 3, 2, 1, 0,
|
||||
0, 7, 6, 5, 4, 3, 2, 1,
|
||||
1, 0, 7, 6, 5, 4, 3, 2,
|
||||
2, 1, 0, 7, 6, 5, 4, 3,
|
||||
3, 2, 1, 0, 7, 6, 5, 4,
|
||||
4, 3, 2, 1, 0, 7, 6, 5,
|
||||
5, 4, 3, 2, 1, 0, 7, 6,
|
||||
6, 5, 4, 3, 2, 1, 0, 7
|
||||
};
|
||||
|
||||
MenuIcon::MenuIcon(uint8 menuType, uint8 menuPos, uint32 resId, uint32 frame, Screen *screen) {
|
||||
_menuType = menuType;
|
||||
_menuPos = menuPos;
|
||||
_resId = resId;
|
||||
_frame = frame;
|
||||
_screen = screen;
|
||||
_selected = false;
|
||||
}
|
||||
|
||||
bool MenuIcon::wasClicked(uint16 mouseX, uint16 mouseY) {
|
||||
if (((_menuType == MENU_TOP) && (mouseY >= 40)) || ((_menuType == MENU_BOT) && (mouseY < 440)))
|
||||
return false;
|
||||
if ((mouseX >= _menuPos * 40) && (mouseX < (_menuPos + 1) * 40))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void MenuIcon::setSelect(bool pSel) {
|
||||
_selected = pSel;
|
||||
}
|
||||
|
||||
void MenuIcon::draw(const byte *fadeMask, int8 fadeStatus) {
|
||||
uint16 x = _menuPos * 40;
|
||||
uint16 y = (_menuType == MENU_TOP) ? (0) : (440);
|
||||
_screen->showFrame(x, y, _resId, _frame + (_selected ? 1 : 0), fadeMask, fadeStatus);
|
||||
}
|
||||
|
||||
Menu::Menu(Screen *pScreen, Mouse *pMouse) {
|
||||
uint8 cnt;
|
||||
_screen = pScreen;
|
||||
_mouse = pMouse;
|
||||
_subjectBarStatus = MENU_CLOSED;
|
||||
_objectBarStatus = MENU_CLOSED;
|
||||
_fadeSubject = 0;
|
||||
_fadeObject = 0;
|
||||
for (cnt = 0; cnt < 16; cnt++)
|
||||
_subjects[cnt] = nullptr;
|
||||
for (cnt = 0; cnt < TOTAL_pockets; cnt++)
|
||||
_objects[cnt] = nullptr;
|
||||
_inMenu = 0;
|
||||
}
|
||||
|
||||
Menu::~Menu() {
|
||||
int i;
|
||||
// the menu may be open, so delete the icons
|
||||
for (i = 0; i < TOTAL_pockets; i++) {
|
||||
delete _objects[i];
|
||||
_objects[i] = nullptr;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
delete _subjects[i];
|
||||
_subjects[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::refreshMenus() {
|
||||
if (_objectBarStatus == MENU_OPEN) {
|
||||
buildMenu();
|
||||
for (uint8 cnt = 0; cnt < 16; cnt++) {
|
||||
if (_objects[cnt])
|
||||
_objects[cnt]->draw();
|
||||
else
|
||||
_screen->showFrame(cnt * 40, 0, 0xffffffff, 0);
|
||||
}
|
||||
}
|
||||
if (_subjectBarStatus == MENU_OPEN) {
|
||||
buildSubjects();
|
||||
for (uint8 cnt = 0; cnt < 16; cnt++) {
|
||||
if (_subjects[cnt])
|
||||
_subjects[cnt]->draw();
|
||||
else
|
||||
_screen->showFrame(cnt * 40, 440, 0xffffffff, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 Menu::checkMenuClick(uint8 menuType) {
|
||||
Common::StackLock lock(_menuMutex);
|
||||
uint16 mouseEvent = _mouse->testEvent();
|
||||
if (!mouseEvent)
|
||||
return 0;
|
||||
uint16 x, y;
|
||||
_mouse->giveCoords(&x, &y);
|
||||
if (_subjectBarStatus == MENU_OPEN) {
|
||||
// Conversation mode. Icons are highlighted on mouse-down, but
|
||||
// the actual response is made on mouse-up.
|
||||
if (menuType == MENU_BOT) {
|
||||
if (Logic::_scriptVars[OBJECT_HELD] && (mouseEvent & BS1L_BUTTON_UP)) {
|
||||
for (uint8 cnt = 0; cnt < Logic::_scriptVars[IN_SUBJECT]; cnt++) {
|
||||
if (_subjectBar[cnt] == Logic::_scriptVars[OBJECT_HELD])
|
||||
return cnt + 1;
|
||||
}
|
||||
} else if (mouseEvent & BS1L_BUTTON_DOWN) {
|
||||
for (uint8 cnt = 0; cnt < Logic::_scriptVars[IN_SUBJECT]; cnt++) {
|
||||
if (_subjects[cnt] && _subjects[cnt]->wasClicked(x, y)) {
|
||||
Logic::_scriptVars[OBJECT_HELD] = _subjectBar[cnt];
|
||||
refreshMenus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Logic::_scriptVars[OBJECT_HELD] && (mouseEvent & BS1L_BUTTON_UP)) {
|
||||
for (uint8 cnt = 0; cnt < _inMenu; cnt++) {
|
||||
if (_menuList[cnt] == Logic::_scriptVars[OBJECT_HELD])
|
||||
return cnt + 1;
|
||||
}
|
||||
} else if (mouseEvent & BS1L_BUTTON_DOWN) {
|
||||
for (uint8 cnt = 0; cnt < _inMenu; cnt++) {
|
||||
if (_objects[cnt] && _objects[cnt]->wasClicked(x, y)) {
|
||||
Logic::_scriptVars[OBJECT_HELD] = _menuList[cnt];
|
||||
refreshMenus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Normal use, i.e. inventory. Things happen on mouse-down.
|
||||
if (menuType == MENU_TOP) {
|
||||
for (uint8 cnt = 0; cnt < _inMenu; cnt++) {
|
||||
if (_objects[cnt] && _objects[cnt]->wasClicked(x, y)) {
|
||||
if (mouseEvent & BS1R_BUTTON_DOWN) { // looking at item
|
||||
Logic::_scriptVars[OBJECT_HELD] = _menuList[cnt];
|
||||
Logic::_scriptVars[MENU_LOOKING] = 1;
|
||||
Logic::_scriptVars[DEFAULT_ICON_TEXT] = _objectDefs[_menuList[cnt]].textDesc;
|
||||
} else if (mouseEvent & BS1L_BUTTON_DOWN) {
|
||||
if (Logic::_scriptVars[OBJECT_HELD]) {
|
||||
if (Logic::_scriptVars[OBJECT_HELD] == _menuList[cnt]) {
|
||||
_mouse->setLuggage(0, 0);
|
||||
Logic::_scriptVars[OBJECT_HELD] = 0; // reselected => deselect it
|
||||
} else { // the player is clicking another item on this one.
|
||||
// run its use-script, if there is one
|
||||
Logic::_scriptVars[SECOND_ITEM] = _menuList[cnt];
|
||||
_mouse->setLuggage(0, 0);
|
||||
}
|
||||
} else {
|
||||
Logic::_scriptVars[OBJECT_HELD] = _menuList[cnt];
|
||||
_mouse->setLuggage(_objectDefs[_menuList[cnt]].luggageIconRes, 0);
|
||||
}
|
||||
}
|
||||
refreshMenus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Menu::buildSubjects() {
|
||||
Common::StackLock lock(_menuMutex);
|
||||
uint8 cnt;
|
||||
for (cnt = 0; cnt < 16; cnt++)
|
||||
if (_subjects[cnt]) {
|
||||
delete _subjects[cnt];
|
||||
_subjects[cnt] = nullptr;
|
||||
}
|
||||
for (cnt = 0; cnt < Logic::_scriptVars[IN_SUBJECT]; cnt++) {
|
||||
uint32 res = _subjectList[(_subjectBar[cnt] & 65535) - BASE_SUBJECT].subjectRes;
|
||||
uint32 frame = _subjectList[(_subjectBar[cnt] & 65535) - BASE_SUBJECT].frameNo;
|
||||
_subjects[cnt] = new MenuIcon(MENU_BOT, cnt, res, frame, _screen);
|
||||
if (Logic::_scriptVars[OBJECT_HELD])
|
||||
_subjects[cnt]->setSelect(_subjectBar[cnt] == Logic::_scriptVars[OBJECT_HELD]);
|
||||
else
|
||||
_subjects[cnt]->setSelect(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::refresh(uint8 menuType) {
|
||||
Common::StackLock lock(_menuMutex);
|
||||
uint i;
|
||||
|
||||
if (menuType == MENU_TOP) {
|
||||
if (_objectBarStatus == MENU_OPENING || _objectBarStatus == MENU_CLOSING) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (_objects[i])
|
||||
_objects[i]->draw(_fadeEffectTop, _fadeObject);
|
||||
else
|
||||
_screen->showFrame(i * 40, 0, 0xffffffff, 0, _fadeEffectTop, _fadeObject);
|
||||
}
|
||||
}
|
||||
if (_objectBarStatus == MENU_OPENING) {
|
||||
if (_fadeObject < 8)
|
||||
_fadeObject++;
|
||||
else
|
||||
_objectBarStatus = MENU_OPEN;
|
||||
} else if (_objectBarStatus == MENU_CLOSING) {
|
||||
if (_fadeObject > 0)
|
||||
_fadeObject--;
|
||||
else {
|
||||
for (i = 0; i < _inMenu; i++) {
|
||||
delete _objects[i];
|
||||
_objects[i] = nullptr;
|
||||
}
|
||||
_objectBarStatus = MENU_CLOSED;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_subjectBarStatus == MENU_OPENING || _subjectBarStatus == MENU_CLOSING) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (_subjects[i])
|
||||
_subjects[i]->draw(_fadeEffectBottom, _fadeSubject);
|
||||
else
|
||||
_screen->showFrame(i * 40, 440, 0xffffffff, 0, _fadeEffectBottom, _fadeSubject);
|
||||
}
|
||||
}
|
||||
if (_subjectBarStatus == MENU_OPENING) {
|
||||
if (_fadeSubject < 8)
|
||||
_fadeSubject++;
|
||||
else
|
||||
_subjectBarStatus = MENU_OPEN;
|
||||
} else if (_subjectBarStatus == MENU_CLOSING) {
|
||||
if (_fadeSubject > 0)
|
||||
_fadeSubject--;
|
||||
else {
|
||||
for (i = 0; i < Logic::_scriptVars[IN_SUBJECT]; i++) {
|
||||
delete _subjects[i];
|
||||
_subjects[i] = nullptr;
|
||||
}
|
||||
_subjectBarStatus = MENU_CLOSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::buildMenu() {
|
||||
Common::StackLock lock(_menuMutex);
|
||||
uint32 *pockets = Logic::_scriptVars + POCKET_1;
|
||||
for (uint8 cnt = 0; cnt < _inMenu; cnt++)
|
||||
if (_objects[cnt]) {
|
||||
delete _objects[cnt];
|
||||
_objects[cnt] = nullptr;
|
||||
}
|
||||
_inMenu = 0;
|
||||
for (uint32 pocketNo = 0; pocketNo < TOTAL_pockets; pocketNo++)
|
||||
if (pockets[pocketNo]) {
|
||||
_menuList[_inMenu] = pocketNo + 1;
|
||||
_inMenu++;
|
||||
}
|
||||
for (uint32 menuSlot = 0; menuSlot < _inMenu; menuSlot++) {
|
||||
_objects[menuSlot] = new MenuIcon(MENU_TOP, menuSlot, _objectDefs[_menuList[menuSlot]].bigIconRes, _objectDefs[_menuList[menuSlot]].bigIconFrame, _screen);
|
||||
uint32 objHeld = Logic::_scriptVars[OBJECT_HELD];
|
||||
|
||||
// check highlighting
|
||||
if (Logic::_scriptVars[MENU_LOOKING] || _subjectBarStatus == MENU_OPEN) { // either we're in the chooser or we're doing a 'LOOK AT'
|
||||
if ((!objHeld) || (objHeld == _menuList[menuSlot]))
|
||||
_objects[menuSlot]->setSelect(true);
|
||||
} else if (Logic::_scriptVars[SECOND_ITEM]) { // clicked luggage onto 2nd icon - we need to color-highlight the 2 relevant icons & grey out the rest
|
||||
if ((_menuList[menuSlot] == objHeld) || (_menuList[menuSlot] == Logic::_scriptVars[SECOND_ITEM]))
|
||||
_objects[menuSlot]->setSelect(true);
|
||||
} else { // this object is selected - ie. GREYED OUT
|
||||
if (objHeld != _menuList[menuSlot])
|
||||
_objects[menuSlot]->setSelect(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::showMenu(uint8 menuType) {
|
||||
Common::StackLock lock(_menuMutex);
|
||||
if (menuType == MENU_TOP) {
|
||||
if (_objectBarStatus == MENU_OPEN) {
|
||||
for (uint8 cnt = 0; cnt < 16; cnt++) {
|
||||
if (_objects[cnt])
|
||||
_objects[cnt]->draw();
|
||||
else
|
||||
_screen->showFrame(cnt * 40, 0, 0xffffffff, 0);
|
||||
}
|
||||
} else if (_objectBarStatus == MENU_CLOSED) {
|
||||
_objectBarStatus = MENU_OPENING;
|
||||
_fadeObject = 0;
|
||||
} else if (_objectBarStatus == MENU_CLOSING)
|
||||
_objectBarStatus = MENU_OPENING;
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::fnStartMenu() {
|
||||
Logic::_scriptVars[OBJECT_HELD] = 0; // icon no longer selected
|
||||
Logic::_scriptVars[SECOND_ITEM] = 0; // second icon no longer selected (after using one on another)
|
||||
Logic::_scriptVars[MENU_LOOKING] = 0; // no longer 'looking at' an icon
|
||||
buildMenu();
|
||||
showMenu(MENU_TOP);
|
||||
}
|
||||
|
||||
void Menu::fnEndMenu() {
|
||||
Common::StackLock lock(_menuMutex);
|
||||
if (_objectBarStatus != MENU_CLOSED)
|
||||
_objectBarStatus = MENU_CLOSING;
|
||||
}
|
||||
|
||||
void Menu::fnChooser(Object *compact) {
|
||||
Logic::_scriptVars[OBJECT_HELD] = 0;
|
||||
_mouse->setLuggage(0, 0);
|
||||
buildSubjects();
|
||||
compact->o_logic = LOGIC_choose;
|
||||
_mouse->controlPanel(true); // so the mouse cursor will be shown.
|
||||
|
||||
Common::StackLock lock(_menuMutex);
|
||||
_subjectBarStatus = MENU_OPENING;
|
||||
}
|
||||
|
||||
void Menu::fnEndChooser() {
|
||||
Logic::_scriptVars[OBJECT_HELD] = 0;
|
||||
|
||||
_menuMutex.lock();
|
||||
_subjectBarStatus = MENU_CLOSING;
|
||||
_objectBarStatus = MENU_CLOSING;
|
||||
_menuMutex.unlock();
|
||||
|
||||
_mouse->controlPanel(false);
|
||||
_mouse->setLuggage(0, 0);
|
||||
}
|
||||
|
||||
void Menu::checkTopMenu() {
|
||||
Common::StackLock lock(_menuMutex);
|
||||
if (_objectBarStatus == MENU_OPEN)
|
||||
checkMenuClick(MENU_TOP);
|
||||
}
|
||||
|
||||
void Menu::setToTargetState() {
|
||||
Common::StackLock lock(_menuMutex);
|
||||
// This is an optimization for all the locks introduced
|
||||
// with the fade palette changes: we disable the menu
|
||||
// updates whenever the palette is fading, and we bring
|
||||
// the menu to its target state.
|
||||
// Note that we are only doing this for the top menu:
|
||||
// I haven't seen any instance of a bottom menu (dialog)
|
||||
// being able to immediately open after a palette fade.
|
||||
if (_objectBarStatus == MENU_CLOSING) {
|
||||
_objectBarStatus = MENU_CLOSED;
|
||||
_fadeObject = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (_objects[i])
|
||||
_objects[i]->draw(_fadeEffectTop, _fadeObject);
|
||||
else
|
||||
_screen->showFrame(i * 40, 0, 0xffffffff, 0, _fadeEffectTop, _fadeObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (_objectBarStatus == MENU_OPENING) {
|
||||
_objectBarStatus = MENU_OPEN;
|
||||
_fadeObject = 8;
|
||||
showMenu(MENU_TOP);
|
||||
}
|
||||
|
||||
if (_subjectBarStatus == MENU_CLOSING) {
|
||||
_subjectBarStatus = MENU_CLOSED;
|
||||
_fadeSubject = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (_subjects[i])
|
||||
_subjects[i]->draw(_fadeEffectBottom, _fadeSubject);
|
||||
else
|
||||
_screen->showFrame(i * 40, 440, 0xffffffff, 0, _fadeEffectBottom, _fadeSubject);
|
||||
}
|
||||
}
|
||||
|
||||
if (_subjectBarStatus == MENU_OPENING) {
|
||||
_subjectBarStatus = MENU_OPEN;
|
||||
_fadeSubject = 8;
|
||||
showMenu(MENU_TOP);
|
||||
}
|
||||
}
|
||||
|
||||
int Menu::logicChooser(Object *compact) {
|
||||
Common::StackLock lock(_menuMutex);
|
||||
uint8 objSelected = 0;
|
||||
if (_objectBarStatus == MENU_OPEN)
|
||||
objSelected = checkMenuClick(MENU_TOP);
|
||||
if (!objSelected)
|
||||
objSelected = checkMenuClick(MENU_BOT);
|
||||
if (objSelected) {
|
||||
compact->o_logic = LOGIC_script;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Menu::fnAddSubject(int32 sub) {
|
||||
Common::StackLock lock(_menuMutex);
|
||||
_subjectBar[Logic::_scriptVars[IN_SUBJECT]] = sub;
|
||||
Logic::_scriptVars[IN_SUBJECT]++;
|
||||
}
|
||||
|
||||
void Menu::cfnReleaseMenu() {
|
||||
Common::StackLock lock(_menuMutex);
|
||||
_objectBarStatus = MENU_CLOSING;
|
||||
}
|
||||
|
||||
} // End of namespace Sword1
|
||||
112
engines/sword1/menu.h
Normal file
112
engines/sword1/menu.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/* 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 SWORD1_MENU_H
|
||||
#define SWORD1_MENU_H
|
||||
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "sword1/object.h"
|
||||
#include "common/mutex.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
class Screen;
|
||||
class Mouse;
|
||||
class ResMan;
|
||||
|
||||
#define MENU_TOP 0
|
||||
#define MENU_BOT 1
|
||||
|
||||
struct Subject {
|
||||
uint32 subjectRes;
|
||||
uint32 frameNo;
|
||||
};
|
||||
|
||||
struct MenuObject {
|
||||
int32 textDesc;
|
||||
uint32 bigIconRes;
|
||||
uint32 bigIconFrame;
|
||||
uint32 luggageIconRes;
|
||||
uint32 useScript;
|
||||
};
|
||||
|
||||
class MenuIcon {
|
||||
public:
|
||||
MenuIcon(uint8 menuType, uint8 menuPos, uint32 resId, uint32 frame, Screen *screen);
|
||||
bool wasClicked(uint16 mouseX, uint16 mouseY);
|
||||
void setSelect(bool pSel);
|
||||
void draw(const byte *fadeMask = NULL, int8 fadeStatus = 0);
|
||||
|
||||
private:
|
||||
uint8 _menuType, _menuPos;
|
||||
uint32 _resId, _frame;
|
||||
bool _selected;
|
||||
Screen *_screen;
|
||||
};
|
||||
|
||||
class Menu {
|
||||
public:
|
||||
Menu(Screen *pScreen, Mouse *pMouse);
|
||||
~Menu();
|
||||
void fnChooser(Object *compact);
|
||||
void fnEndChooser();
|
||||
void fnAddSubject(int32 sub);
|
||||
void cfnReleaseMenu();
|
||||
int logicChooser(Object *compact);
|
||||
void engine();
|
||||
void refresh(uint8 menuType);
|
||||
void fnStartMenu();
|
||||
void fnEndMenu();
|
||||
void checkTopMenu();
|
||||
void setToTargetState();
|
||||
static const MenuObject _objectDefs[TOTAL_pockets + 1];
|
||||
|
||||
private:
|
||||
void buildSubjects();
|
||||
void buildMenu();
|
||||
void showMenu(uint8 menuType);
|
||||
byte _subjectBarStatus;
|
||||
byte _objectBarStatus;
|
||||
int8 _fadeSubject;
|
||||
int8 _fadeObject;
|
||||
void refreshMenus();
|
||||
uint8 checkMenuClick(uint8 menuType);
|
||||
//- lower menu, speech subjects:
|
||||
MenuIcon *_subjects[16];
|
||||
uint32 _subjectBar[16];
|
||||
//- top menu, items
|
||||
MenuIcon *_objects[TOTAL_pockets];
|
||||
uint32 _menuList[TOTAL_pockets];
|
||||
uint32 _inMenu;
|
||||
|
||||
Screen *_screen;
|
||||
Mouse *_mouse;
|
||||
static const Subject _subjectList[TOTAL_subjects];
|
||||
|
||||
static const byte _fadeEffectTop[64];
|
||||
static const byte _fadeEffectBottom[64];
|
||||
|
||||
Common::Mutex _menuMutex;
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif //BSMENU_H
|
||||
436
engines/sword1/metaengine.cpp
Normal file
436
engines/sword1/metaengine.cpp
Normal file
@@ -0,0 +1,436 @@
|
||||
/* 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 "sword1/sword1.h"
|
||||
#include "sword1/control.h"
|
||||
#include "sword1/logic.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 "engines/dialogs.h"
|
||||
|
||||
#include "graphics/thumbnail.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "gui/ThemeEval.h"
|
||||
#include "gui/widget.h"
|
||||
#include "gui/widgets/popup.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#define GAMEOPTION_WINDOWS_AUDIO_MODE GUIO_GAMEOPTIONS1
|
||||
#define GAMEOPTION_MULTILANGUAGE GUIO_GAMEOPTIONS2
|
||||
#define GAMEOPTION_MULTILANGUAGE_EXTENDED GUIO_GAMEOPTIONS3
|
||||
|
||||
class Sword1OptionsWidget : public GUI::OptionsContainerWidget {
|
||||
public:
|
||||
explicit Sword1OptionsWidget(GuiObject *boss, const Common::String &name, const Common::String &domain);
|
||||
|
||||
// OptionsContainerWidget API
|
||||
void load() override;
|
||||
bool save() override;
|
||||
|
||||
private:
|
||||
// OptionsContainerWidget API
|
||||
void defineLayout(GUI::ThemeEval &layouts, const Common::String &layoutName, const Common::String &overlayedLayout) const override;
|
||||
Common::StringArray _availableLangCodes = {"en", "de", "fr", "it", "es", "pt", "cs"};
|
||||
Common::StringArray _availableLangs = {_("English"), _("German"), _("French"), _("Italian"), _("Spanish"), _("Brazilian Portuguese"), _("Czech")};
|
||||
uint32 _numAvailableLangs = 0;
|
||||
bool _atLeastOneAdditionalOpt = false;
|
||||
|
||||
GUI::PopUpWidget *_langPopUp;
|
||||
GUI::CheckboxWidget *_windowsAudioMode;
|
||||
};
|
||||
|
||||
Sword1OptionsWidget::Sword1OptionsWidget(GuiObject *boss, const Common::String &name, const Common::String &domain) :
|
||||
OptionsContainerWidget(boss, name, "Sword1GameOptionsDialog", domain) {
|
||||
|
||||
if (Common::checkGameGUIOption(GAMEOPTION_MULTILANGUAGE, ConfMan.get("guioptions", domain))) {
|
||||
_numAvailableLangs = 5;
|
||||
} else if (Common::checkGameGUIOption(GAMEOPTION_MULTILANGUAGE_EXTENDED, ConfMan.get("guioptions", domain))) {
|
||||
_numAvailableLangs = 7;
|
||||
}
|
||||
|
||||
// Language
|
||||
if (Common::checkGameGUIOption(GAMEOPTION_MULTILANGUAGE, ConfMan.get("guioptions", domain)) ||
|
||||
Common::checkGameGUIOption(GAMEOPTION_MULTILANGUAGE_EXTENDED, ConfMan.get("guioptions", domain))) {
|
||||
GUI::StaticTextWidget *textWidget = new GUI::StaticTextWidget(
|
||||
widgetsBoss(),
|
||||
_dialogLayout + ".subtitles_lang_desc",
|
||||
_("Text language:"),
|
||||
_("Set the language for the subtitles. This will not affect voices.")
|
||||
);
|
||||
|
||||
textWidget->setAlign(Graphics::kTextAlignLeft);
|
||||
|
||||
_langPopUp = new GUI::PopUpWidget(
|
||||
widgetsBoss(),
|
||||
_dialogLayout + ".subtitles_lang",
|
||||
_("Set the language for the subtitles. This will not affect voices.")
|
||||
);
|
||||
|
||||
_langPopUp->appendEntry(_("<default>"), (uint32)-1);
|
||||
|
||||
for (uint32 i = 0; i < _numAvailableLangs; i++) {
|
||||
_langPopUp->appendEntry(_availableLangs[i], i);
|
||||
}
|
||||
|
||||
_atLeastOneAdditionalOpt = true;
|
||||
} else {
|
||||
_langPopUp = nullptr;
|
||||
}
|
||||
|
||||
// Windows audio mode
|
||||
if (Common::checkGameGUIOption(GAMEOPTION_WINDOWS_AUDIO_MODE, ConfMan.get("guioptions", domain))) {
|
||||
_windowsAudioMode = new GUI::CheckboxWidget(
|
||||
widgetsBoss(),
|
||||
_dialogLayout + ".windows_audio_mode",
|
||||
_("Simulate the audio engine from the Windows executable"),
|
||||
_("Makes the game use softer (logarithmic) audio curves, but removes fade-in and fade-out for "
|
||||
"sound effects, fade-in for music, and automatic music volume attenuation for when speech is playing"));
|
||||
|
||||
_atLeastOneAdditionalOpt = true;
|
||||
} else {
|
||||
_windowsAudioMode = nullptr;
|
||||
}
|
||||
|
||||
if (_atLeastOneAdditionalOpt) {
|
||||
GUI::StaticTextWidget *additionalOptsWidget = new GUI::StaticTextWidget(
|
||||
widgetsBoss(),
|
||||
_dialogLayout + ".additional_opts_label",
|
||||
_("Additional options:"));
|
||||
|
||||
additionalOptsWidget->setAlign(Graphics::kTextAlignLeft);
|
||||
}
|
||||
}
|
||||
|
||||
void Sword1OptionsWidget::load() {
|
||||
Common::ConfigManager::Domain *gameConfig = ConfMan.getDomain(_domain);
|
||||
if (!gameConfig)
|
||||
return;
|
||||
|
||||
if (_langPopUp) {
|
||||
uint32 curLangIndex = (uint32)-1;
|
||||
Common::String curLang;
|
||||
gameConfig->tryGetVal("subtitles_language_override", curLang);
|
||||
if (!curLang.empty()) {
|
||||
for (uint i = 0; i < _numAvailableLangs; ++i) {
|
||||
if (_availableLangCodes[i].equalsIgnoreCase(curLang)) {
|
||||
curLangIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_langPopUp->setSelectedTag(curLangIndex);
|
||||
}
|
||||
|
||||
if (_windowsAudioMode) {
|
||||
Common::String windowsAudioMode;
|
||||
gameConfig->tryGetVal("windows_audio_mode", windowsAudioMode);
|
||||
if (!windowsAudioMode.empty()) {
|
||||
bool val;
|
||||
if (parseBool(windowsAudioMode, val))
|
||||
_windowsAudioMode->setState(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Sword1OptionsWidget::save() {
|
||||
if (_langPopUp) {
|
||||
uint langIndex = _langPopUp->getSelectedTag();
|
||||
if (langIndex < _numAvailableLangs)
|
||||
ConfMan.set("subtitles_language_override", _availableLangCodes[langIndex], _domain);
|
||||
else
|
||||
ConfMan.removeKey("subtitles_language_override", _domain);
|
||||
}
|
||||
|
||||
if (_windowsAudioMode)
|
||||
ConfMan.setBool("windows_audio_mode", _windowsAudioMode->getState(), _domain);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sword1OptionsWidget::defineLayout(GUI::ThemeEval &layouts, const Common::String &layoutName, const Common::String &overlayedLayout) const {
|
||||
layouts.addDialog(layoutName, overlayedLayout);
|
||||
|
||||
layouts.addLayout(GUI::ThemeLayout::kLayoutVertical).addPadding(16, 0, 0, 0); // Layout 1
|
||||
|
||||
layouts.addWidget("additional_opts_label", "OptionsLabel");
|
||||
layouts.addLayout(GUI::ThemeLayout::kLayoutVertical).addPadding(8, 0, 4, 0); // Layout 2
|
||||
|
||||
layouts.addWidget("subtitles_lang_desc", "OptionsLabel");
|
||||
layouts.addWidget("subtitles_lang", "PopUp");
|
||||
|
||||
// This third layout is added for further separation from the dropdown list
|
||||
layouts.addLayout(GUI::ThemeLayout::kLayoutVertical).addPadding(0, 0, 0, 0); // Layout 3
|
||||
|
||||
if (_langPopUp) // Don't draw padding if there's no lang selection
|
||||
layouts.addPadding(0, 0, 8, 0);
|
||||
|
||||
layouts.addWidget("windows_audio_mode", "Checkbox");
|
||||
|
||||
layouts.closeLayout(); // Close layout 3
|
||||
|
||||
layouts.closeLayout(); // Close layout 2
|
||||
|
||||
layouts.closeLayout().closeDialog(); // Close layout 1
|
||||
}
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
class SwordMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "sword1";
|
||||
}
|
||||
|
||||
bool hasFeature(MetaEngineFeature f) const override;
|
||||
|
||||
SaveStateList listSaves(const char *target) const override;
|
||||
int getMaximumSaveSlot() const override;
|
||||
bool removeSaveState(const char *target, int slot) const override;
|
||||
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
|
||||
|
||||
GUI::OptionsContainerWidget *buildEngineOptionsWidget(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const override;
|
||||
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
|
||||
|
||||
Common::String getSavegameFile(int saveGameIdx, const char *target) const override {
|
||||
if (saveGameIdx == kSavegameFilePattern)
|
||||
return Common::String::format("sword1.###");
|
||||
else
|
||||
return Common::String::format("sword1.%03d", saveGameIdx);
|
||||
}
|
||||
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
};
|
||||
|
||||
bool SwordMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsListSaves) ||
|
||||
(f == kSupportsLoadingDuringStartup) ||
|
||||
(f == kSupportsDeleteSave) ||
|
||||
(f == kSavesSupportMetaInfo) ||
|
||||
(f == kSavesSupportThumbnail) ||
|
||||
(f == kSavesSupportCreationDate) ||
|
||||
(f == kSavesSupportPlayTime);
|
||||
}
|
||||
|
||||
bool Sword1::SwordEngine::hasFeature(EngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsReturnToLauncher) ||
|
||||
(f == kSupportsSavingDuringRuntime) ||
|
||||
(f == kSupportsLoadingDuringRuntime);
|
||||
}
|
||||
|
||||
GUI::OptionsContainerWidget *SwordMetaEngine::buildEngineOptionsWidget(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const {
|
||||
return new Sword1::Sword1OptionsWidget(boss, name, target);
|
||||
}
|
||||
|
||||
Common::Error SwordMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
|
||||
*engine = new Sword1::SwordEngine(syst, desc);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::KeymapArray SwordMetaEngine::initKeymaps(const char *target) const {
|
||||
using namespace Common;
|
||||
using namespace Sword1;
|
||||
|
||||
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "sword1-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("ESCAPE", _("Exit / Skip"));
|
||||
act->setCustomEngineActionEvent(kActionEscape);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_BACK");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("PAUSE", _("Pause game"));
|
||||
act->setCustomEngineActionEvent(kActionPause);
|
||||
act->addDefaultInputMapping("p");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("QUIT", _("Quit game"));
|
||||
act->setCustomEngineActionEvent(kActionQuit);
|
||||
act->addDefaultInputMapping("C+q");
|
||||
act->addDefaultInputMapping("JOY_CENTER");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
act = new Action("MAINPANEL", _("Main menu"));
|
||||
act->setCustomEngineActionEvent(kActionMainPanel);
|
||||
act->addDefaultInputMapping("F5");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
gameKeyMap->addAction(act);
|
||||
|
||||
KeymapArray keymaps(2);
|
||||
keymaps[0] = engineKeyMap;
|
||||
keymaps[1] = gameKeyMap;
|
||||
|
||||
return keymaps;
|
||||
}
|
||||
|
||||
SaveStateList SwordMetaEngine::listSaves(const char *target) const {
|
||||
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
|
||||
SaveStateList saveList;
|
||||
char saveName[40];
|
||||
|
||||
Common::StringArray filenames = saveFileMan->listSavefiles("sword1.###");
|
||||
|
||||
int slotNum = 0;
|
||||
for (const auto &filename : filenames) {
|
||||
// Obtain the last 3 digits of the filename, since they correspond to the save slot
|
||||
slotNum = atoi(filename.c_str() + filename.size() - 3);
|
||||
|
||||
if (slotNum >= 0 && slotNum <= 999) {
|
||||
Common::InSaveFile *in = saveFileMan->openForLoading(filename);
|
||||
if (in) {
|
||||
in->readUint32LE(); // header
|
||||
in->read(saveName, 40);
|
||||
saveList.push_back(SaveStateDescriptor(this, slotNum, saveName));
|
||||
delete in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort saves based on slot number.
|
||||
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
|
||||
return saveList;
|
||||
}
|
||||
|
||||
int SwordMetaEngine::getMaximumSaveSlot() const { return 999; }
|
||||
|
||||
bool SwordMetaEngine::removeSaveState(const char *target, int slot) const {
|
||||
return g_system->getSavefileManager()->removeSavefile(Common::String::format("sword1.%03d", slot));
|
||||
}
|
||||
|
||||
SaveStateDescriptor SwordMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
|
||||
Common::String fileName = Common::String::format("sword1.%03d", slot);
|
||||
char name[40];
|
||||
uint32 playTime = 0;
|
||||
byte versionSave;
|
||||
|
||||
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
|
||||
|
||||
if (in) {
|
||||
in->skip(4); // header
|
||||
in->read(name, sizeof(name));
|
||||
in->read(&versionSave, 1); // version
|
||||
|
||||
SaveStateDescriptor desc(this, slot, name);
|
||||
|
||||
if (versionSave < 2) // These older version of the savegames used a flag to signal presence of thumbnail
|
||||
in->skip(1);
|
||||
|
||||
if (Graphics::checkThumbnailHeader(*in)) {
|
||||
Graphics::Surface *thumbnail;
|
||||
if (!Graphics::loadThumbnail(*in, thumbnail)) {
|
||||
delete in;
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
desc.setThumbnail(thumbnail);
|
||||
}
|
||||
|
||||
uint32 saveDate = in->readUint32BE();
|
||||
uint16 saveTime = in->readUint16BE();
|
||||
if (versionSave > 1) // Previous versions did not have playtime data
|
||||
playTime = in->readUint32BE();
|
||||
|
||||
int day = (saveDate >> 24) & 0xFF;
|
||||
int month = (saveDate >> 16) & 0xFF;
|
||||
int year = saveDate & 0xFFFF;
|
||||
|
||||
desc.setSaveDate(year, month, day);
|
||||
|
||||
int hour = (saveTime >> 8) & 0xFF;
|
||||
int minutes = saveTime & 0xFF;
|
||||
|
||||
desc.setSaveTime(hour, minutes);
|
||||
|
||||
if (versionSave > 1) {
|
||||
desc.setPlayTime(playTime * 1000);
|
||||
} else { //We have no playtime data
|
||||
desc.setPlayTime(0);
|
||||
}
|
||||
|
||||
delete in;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(SWORD1)
|
||||
REGISTER_PLUGIN_DYNAMIC(SWORD1, PLUGIN_TYPE_ENGINE, SwordMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(SWORD1, PLUGIN_TYPE_ENGINE, SwordMetaEngine);
|
||||
#endif
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
Common::Error SwordEngine::loadGameState(int slot) {
|
||||
_systemVars.controlPanelMode = CP_NORMAL;
|
||||
_control->restoreGameFromFile(slot);
|
||||
reinitialize();
|
||||
_control->doRestore();
|
||||
reinitRes();
|
||||
return Common::kNoError; // TODO: return success/failure
|
||||
}
|
||||
|
||||
bool SwordEngine::canLoadGameStateCurrently(Common::U32String *msg) {
|
||||
return (mouseIsActive() && !_control->isPanelShown()); // Disable GMM loading when game panel is shown
|
||||
}
|
||||
|
||||
Common::Error SwordEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
|
||||
_control->setSaveDescription(slot, desc.c_str());
|
||||
_control->saveGameToFile(slot);
|
||||
return Common::kNoError; // TODO: return success/failure
|
||||
}
|
||||
|
||||
bool SwordEngine::canSaveGameStateCurrently(Common::U32String *msg) {
|
||||
return (mouseIsActive() && !_control->isPanelShown() && Logic::_scriptVars[SCREEN] != 91);
|
||||
}
|
||||
|
||||
} // End of namespace Sword1
|
||||
32
engines/sword1/module.mk
Normal file
32
engines/sword1/module.mk
Normal file
@@ -0,0 +1,32 @@
|
||||
MODULE := engines/sword1
|
||||
|
||||
MODULE_OBJS := \
|
||||
animation.o \
|
||||
console.o \
|
||||
control.o \
|
||||
debug.o \
|
||||
eventman.o \
|
||||
logic.o \
|
||||
memman.o \
|
||||
menu.o \
|
||||
metaengine.o \
|
||||
mouse.o \
|
||||
objectman.o \
|
||||
resman.o \
|
||||
router.o \
|
||||
screen.o \
|
||||
sound.o \
|
||||
staticres.o \
|
||||
sword1.o \
|
||||
text.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_SWORD1), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
377
engines/sword1/mouse.cpp
Normal file
377
engines/sword1/mouse.cpp
Normal file
@@ -0,0 +1,377 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
#include "graphics/cursorman.h"
|
||||
|
||||
#include "sword1/mouse.h"
|
||||
#include "sword1/menu.h"
|
||||
#include "sword1/screen.h"
|
||||
#include "sword1/logic.h"
|
||||
#include "sword1/resman.h"
|
||||
#include "sword1/objectman.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "sword1/swordres.h"
|
||||
#include "sword1/sword1.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
Mouse::Mouse(OSystem *system, ResMan *pResMan, ObjectMan *pObjMan) {
|
||||
_resMan = pResMan;
|
||||
_objMan = pObjMan;
|
||||
_system = system;
|
||||
_currentPtr = nullptr;
|
||||
}
|
||||
|
||||
Mouse::~Mouse() {
|
||||
setLuggage(0, 0);
|
||||
setPointer(0, 0);
|
||||
|
||||
for (uint8 cnt = 0; cnt < 17; cnt++) // close mouse cursor resources
|
||||
_resMan->resClose(MSE_POINTER + cnt);
|
||||
}
|
||||
|
||||
void Mouse::initialize() {
|
||||
_numObjs = 0;
|
||||
Logic::_scriptVars[MOUSE_STATUS] = 0; // mouse off and unlocked
|
||||
_getOff = 0;
|
||||
_inTopMenu = false;
|
||||
_lastState = 0;
|
||||
_mouseOverride = false;
|
||||
_currentPtrId = _currentLuggageId = 0;
|
||||
|
||||
for (uint8 cnt = 0; cnt < 17; cnt++) // force res manager to keep mouse
|
||||
_resMan->resOpen(MSE_POINTER + cnt); // cursors in memory all the time
|
||||
|
||||
CursorMan.showMouse(false);
|
||||
createPointer(0, 0);
|
||||
}
|
||||
|
||||
void Mouse::controlPanel(bool on) { // true on entering cpanel, false when leaving
|
||||
static uint32 savedPtrId = 0;
|
||||
if (on) {
|
||||
savedPtrId = _currentPtrId;
|
||||
_mouseOverride = true;
|
||||
setPointer(MSE_POINTER, 0);
|
||||
} else {
|
||||
_currentPtrId = savedPtrId;
|
||||
_mouseOverride = false;
|
||||
setPointer(_currentPtrId, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Mouse::useLogicAndMenu(Logic *pLogic, Menu *pMenu) {
|
||||
_logic = pLogic;
|
||||
_menu = pMenu;
|
||||
}
|
||||
|
||||
void Mouse::useScreenMutex(Common::Mutex *mutex) {
|
||||
_screenAccessMutex = mutex;
|
||||
}
|
||||
|
||||
void Mouse::addToList(int id, Object *compact) {
|
||||
_objList[_numObjs].id = id;
|
||||
_objList[_numObjs].compact = compact;
|
||||
_numObjs++;
|
||||
}
|
||||
|
||||
void Mouse::engine(uint16 x, uint16 y, uint16 eventFlags) {
|
||||
_state = 0; // all mouse events are flushed after one cycle.
|
||||
if (_lastState) { // delay all events by one cycle to notice L_button + R_button clicks correctly.
|
||||
_state = _lastState | eventFlags;
|
||||
_lastState = 0;
|
||||
} else if (eventFlags)
|
||||
_lastState = eventFlags;
|
||||
|
||||
// if we received both, mouse down and mouse up event in this cycle, resort them so that
|
||||
// we'll receive the up event in the next one.
|
||||
if ((_state & MOUSE_DOWN_MASK) && (_state & MOUSE_UP_MASK)) {
|
||||
_lastState = _state & MOUSE_UP_MASK;
|
||||
_state &= MOUSE_DOWN_MASK;
|
||||
}
|
||||
|
||||
_mouse.x = x;
|
||||
_mouse.y = y;
|
||||
if (!(Logic::_scriptVars[MOUSE_STATUS] & 1)) { // no human?
|
||||
_numObjs = 0;
|
||||
return; // no human, so we don't want the mouse engine
|
||||
}
|
||||
|
||||
if (!Logic::_scriptVars[TOP_MENU_DISABLED]) {
|
||||
if (y < 40) { // okay, we are in the top menu.
|
||||
if (!_inTopMenu) { // are we just entering it?
|
||||
if (!Logic::_scriptVars[OBJECT_HELD])
|
||||
_menu->fnStartMenu();
|
||||
setPointer(MSE_POINTER, 0);
|
||||
}
|
||||
_menu->checkTopMenu();
|
||||
_inTopMenu = true;
|
||||
} else if (_inTopMenu) { // we're not in the menu. did we just leave it?
|
||||
if (!Logic::_scriptVars[OBJECT_HELD])
|
||||
_menu->fnEndMenu();
|
||||
_inTopMenu = false;
|
||||
}
|
||||
} else if (_inTopMenu) {
|
||||
_menu->fnEndMenu();
|
||||
_inTopMenu = false;
|
||||
}
|
||||
|
||||
Logic::_scriptVars[MOUSE_X] = Logic::_scriptVars[SCROLL_OFFSET_X] + x + 128;
|
||||
Logic::_scriptVars[MOUSE_Y] = Logic::_scriptVars[SCROLL_OFFSET_Y] + y + 128 - 40;
|
||||
|
||||
//-
|
||||
int32 touchedId = 0;
|
||||
uint16 clicked = 0;
|
||||
if ((y > 40 && _inTopMenu) || !_inTopMenu) {
|
||||
for (uint16 priority = 0; (priority < 10) && (!touchedId); priority++) {
|
||||
for (uint16 cnt = 0; (cnt < _numObjs) && (!touchedId); cnt++) {
|
||||
if ((_objList[cnt].compact->o_priority == priority) &&
|
||||
(Logic::_scriptVars[MOUSE_X] >= (uint32)_objList[cnt].compact->o_mouse_x1) &&
|
||||
(Logic::_scriptVars[MOUSE_X] <= (uint32)_objList[cnt].compact->o_mouse_x2) &&
|
||||
(Logic::_scriptVars[MOUSE_Y] >= (uint32)_objList[cnt].compact->o_mouse_y1) &&
|
||||
(Logic::_scriptVars[MOUSE_Y] <= (uint32)_objList[cnt].compact->o_mouse_y2)) {
|
||||
touchedId = _objList[cnt].id;
|
||||
clicked = cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (touchedId != (int)Logic::_scriptVars[SPECIAL_ITEM]) { //the mouse collision situation has changed in one way or another
|
||||
Logic::_scriptVars[SPECIAL_ITEM] = touchedId;
|
||||
if (_getOff) { // there was something else selected before, run its get-off script
|
||||
_logic->runMouseScript(nullptr, _getOff);
|
||||
_getOff = 0;
|
||||
}
|
||||
if (touchedId) { // there's something new selected, now.
|
||||
if (_objList[clicked].compact->o_mouse_on) //run its get on
|
||||
_logic->runMouseScript(_objList[clicked].compact, _objList[clicked].compact->o_mouse_on);
|
||||
|
||||
_getOff = _objList[clicked].compact->o_mouse_off; //setup get-off for later
|
||||
}
|
||||
}
|
||||
} else
|
||||
Logic::_scriptVars[SPECIAL_ITEM] = 0;
|
||||
if (_state & MOUSE_DOWN_MASK) {
|
||||
if (_inTopMenu) {
|
||||
if (Logic::_scriptVars[SECOND_ITEM]) {
|
||||
if (Logic::_scriptVars[GEORGE_DOING_REST_ANIM] == 1) {
|
||||
Logic::_scriptVars[GEORGE_DOING_REST_ANIM] = 0;
|
||||
} else if (Logic::_scriptVars[GEORGE_WALKING]) {
|
||||
Logic::_scriptVars[GEORGE_WALKING] = 2;
|
||||
}
|
||||
|
||||
_logic->runMouseScript(nullptr, _menu->_objectDefs[Logic::_scriptVars[SECOND_ITEM]].useScript);
|
||||
}
|
||||
|
||||
if (Logic::_scriptVars[MENU_LOOKING]) {
|
||||
if (Logic::_scriptVars[GEORGE_DOING_REST_ANIM] == 1) {
|
||||
Logic::_scriptVars[GEORGE_DOING_REST_ANIM] = 0;
|
||||
} else if (Logic::_scriptVars[GEORGE_WALKING]) {
|
||||
Logic::_scriptVars[GEORGE_WALKING] = 2;
|
||||
}
|
||||
|
||||
_logic->cfnPresetScript(nullptr, -1, PLAYER, SCR_menu_look, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Logic::_scriptVars[MOUSE_BUTTON] = _state & MOUSE_DOWN_MASK;
|
||||
if (Logic::_scriptVars[SPECIAL_ITEM]) {
|
||||
Object *compact = _objMan->fetchObject(Logic::_scriptVars[SPECIAL_ITEM]);
|
||||
_logic->runMouseScript(compact, compact->o_mouse_click);
|
||||
}
|
||||
}
|
||||
_numObjs = 0;
|
||||
}
|
||||
|
||||
uint16 Mouse::testEvent() {
|
||||
return _state;
|
||||
}
|
||||
|
||||
void Mouse::createPointer(uint32 ptrId, uint32 luggageId) {
|
||||
if (_currentPtr) {
|
||||
free(_currentPtr);
|
||||
_currentPtr = nullptr;
|
||||
}
|
||||
|
||||
if (ptrId) {
|
||||
MousePtr *lugg = nullptr;
|
||||
MousePtr *ptr = (MousePtr *)_resMan->openFetchRes(ptrId);
|
||||
uint16 noFrames = _resMan->getLEUint16(ptr->numFrames);
|
||||
uint16 ptrSizeX = _resMan->getLEUint16(ptr->sizeX);
|
||||
uint16 ptrSizeY = _resMan->getLEUint16(ptr->sizeY);
|
||||
uint16 luggSizeX = 0;
|
||||
uint16 luggSizeY = 0;
|
||||
uint16 resSizeX;
|
||||
uint16 resSizeY;
|
||||
|
||||
if (SwordEngine::isPsx()) //PSX pointers are half height
|
||||
ptrSizeY *= 2;
|
||||
|
||||
if (luggageId) {
|
||||
lugg = (MousePtr *)_resMan->openFetchRes(luggageId);
|
||||
luggSizeX = _resMan->getLEUint16(lugg->sizeX);
|
||||
luggSizeY = _resMan->getLEUint16(lugg->sizeY);
|
||||
|
||||
if (SwordEngine::isPsx())
|
||||
luggSizeY *= 2;
|
||||
|
||||
resSizeX = MAX(ptrSizeX, (uint16)((ptrSizeX / 2) + luggSizeX));
|
||||
resSizeY = MAX(ptrSizeY, (uint16)((ptrSizeY / 2) + luggSizeY));
|
||||
} else {
|
||||
resSizeX = ptrSizeX;
|
||||
resSizeY = ptrSizeY;
|
||||
}
|
||||
_currentPtr = (MousePtr *)malloc(sizeof(MousePtr) + resSizeX * resSizeY * noFrames);
|
||||
_currentPtr->hotSpotX = _resMan->getLEUint16(ptr->hotSpotX);
|
||||
_currentPtr->hotSpotY = _resMan->getLEUint16(ptr->hotSpotY);
|
||||
_currentPtr->numFrames = noFrames;
|
||||
_currentPtr->sizeX = resSizeX;
|
||||
_currentPtr->sizeY = resSizeY;
|
||||
uint8 *ptrData = (uint8 *)_currentPtr + sizeof(MousePtr);
|
||||
memset(ptrData, 255, resSizeX * resSizeY * noFrames);
|
||||
if (luggageId) {
|
||||
uint8 *dstData = ptrData + resSizeX - luggSizeX;
|
||||
for (uint32 frameCnt = 0; frameCnt < noFrames; frameCnt++) {
|
||||
uint8 *luggSrc = (uint8 *)lugg + sizeof(MousePtr);
|
||||
dstData += (resSizeY - luggSizeY) * resSizeX;
|
||||
for (uint32 cnty = 0; cnty < (uint32)(SwordEngine::isPsx() ? luggSizeY / 2 : luggSizeY); cnty++) {
|
||||
for (uint32 cntx = 0; cntx < luggSizeX; cntx++)
|
||||
if (luggSrc[cntx])
|
||||
dstData[cntx] = luggSrc[cntx];
|
||||
|
||||
if (SwordEngine::isPsx()) {
|
||||
dstData += resSizeX;
|
||||
for (uint32 cntx = 0; cntx < luggSizeX; cntx++)
|
||||
if (luggSrc[cntx])
|
||||
dstData[cntx] = luggSrc[cntx];
|
||||
}
|
||||
|
||||
dstData += resSizeX;
|
||||
luggSrc += luggSizeX;
|
||||
}
|
||||
}
|
||||
_resMan->resClose(luggageId);
|
||||
}
|
||||
|
||||
uint8 *dstData = ptrData;
|
||||
uint8 *srcData = (uint8 *)ptr + sizeof(MousePtr);
|
||||
for (uint32 frameCnt = 0; frameCnt < noFrames; frameCnt++) {
|
||||
for (uint32 cnty = 0; cnty < (uint32)(SwordEngine::isPsx() ? ptrSizeY / 2 : ptrSizeY); cnty++) {
|
||||
for (uint32 cntx = 0; cntx < ptrSizeX; cntx++)
|
||||
if (srcData[cntx])
|
||||
dstData[cntx] = srcData[cntx];
|
||||
|
||||
if (SwordEngine::isPsx()) {
|
||||
dstData += resSizeX;
|
||||
for (uint32 cntx = 0; cntx < ptrSizeX; cntx++)
|
||||
if (srcData[cntx])
|
||||
dstData[cntx] = srcData[cntx];
|
||||
}
|
||||
|
||||
srcData += ptrSizeX;
|
||||
dstData += resSizeX;
|
||||
}
|
||||
dstData += (resSizeY - ptrSizeY) * resSizeX;
|
||||
}
|
||||
_resMan->resClose(ptrId);
|
||||
}
|
||||
}
|
||||
|
||||
void Mouse::setPointer(uint32 resId, uint32 rate) {
|
||||
_currentPtrId = resId;
|
||||
_frame = 0;
|
||||
_activeFrame = -1;
|
||||
|
||||
createPointer(resId, _currentLuggageId);
|
||||
|
||||
if ((resId == 0) || (!(Logic::_scriptVars[MOUSE_STATUS] & 1) && (!_mouseOverride))) {
|
||||
CursorMan.showMouse(false);
|
||||
} else {
|
||||
animate();
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Mouse::setLuggage(uint32 resId, uint32 rate) {
|
||||
_currentLuggageId = resId;
|
||||
_frame = 0;
|
||||
_activeFrame = -1;
|
||||
|
||||
createPointer(_currentPtrId, resId);
|
||||
}
|
||||
|
||||
void Mouse::animate() {
|
||||
if ((Logic::_scriptVars[MOUSE_STATUS] == 1) || (_mouseOverride && _currentPtr)) {
|
||||
_frame = (_frame + 1) % _currentPtr->numFrames;
|
||||
|
||||
if (_activeFrame == _frame)
|
||||
return;
|
||||
|
||||
uint8 *ptrData = (uint8 *)_currentPtr + sizeof(MousePtr);
|
||||
ptrData += _frame * _currentPtr->sizeX * _currentPtr->sizeY;
|
||||
|
||||
_screenAccessMutex->lock();
|
||||
CursorMan.replaceCursor(ptrData, _currentPtr->sizeX, _currentPtr->sizeY, _currentPtr->hotSpotX, _currentPtr->hotSpotY, 255);
|
||||
_screenAccessMutex->unlock();
|
||||
|
||||
_activeFrame = _frame;
|
||||
}
|
||||
}
|
||||
|
||||
void Mouse::fnNoHuman() {
|
||||
if (Logic::_scriptVars[MOUSE_STATUS] & 2) // locked, can't do anything
|
||||
return;
|
||||
Logic::_scriptVars[MOUSE_STATUS] = 0; // off & unlocked
|
||||
setLuggage(0, 0);
|
||||
setPointer(0, 0);
|
||||
}
|
||||
|
||||
void Mouse::fnAddHuman() {
|
||||
if (Logic::_scriptVars[MOUSE_STATUS] & 2) // locked, can't do anything
|
||||
return;
|
||||
Logic::_scriptVars[MOUSE_STATUS] = 1;
|
||||
Logic::_scriptVars[SPECIAL_ITEM] = 0;
|
||||
_getOff = SCR_std_off;
|
||||
setPointer(MSE_POINTER, 0);
|
||||
}
|
||||
|
||||
void Mouse::fnBlankMouse() {
|
||||
setPointer(0, 0);
|
||||
}
|
||||
|
||||
void Mouse::fnNormalMouse() {
|
||||
setPointer(MSE_POINTER, 0);
|
||||
}
|
||||
|
||||
void Mouse::fnLockMouse() {
|
||||
Logic::_scriptVars[MOUSE_STATUS] |= 2;
|
||||
}
|
||||
|
||||
void Mouse::fnUnlockMouse() {
|
||||
Logic::_scriptVars[MOUSE_STATUS] &= 1;
|
||||
}
|
||||
|
||||
void Mouse::giveCoords(uint16 *x, uint16 *y) {
|
||||
*x = _mouse.x;
|
||||
*y = _mouse.y;
|
||||
}
|
||||
|
||||
} // End of namespace Sword1
|
||||
113
engines/sword1/mouse.h
Normal file
113
engines/sword1/mouse.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* 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 SWORD1_MOUSE_H
|
||||
#define SWORD1_MOUSE_H
|
||||
|
||||
#include "common/mutex.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/rect.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "sword1/object.h"
|
||||
|
||||
class OSystem;
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#define MAX_MOUSE 30
|
||||
|
||||
#define BS1L_BUTTON_DOWN 2
|
||||
#define BS1L_BUTTON_UP 4
|
||||
#define BS1R_BUTTON_DOWN 8
|
||||
#define BS1R_BUTTON_UP 16
|
||||
#define BS1_WHEEL_UP 32
|
||||
#define BS1_WHEEL_DOWN 64
|
||||
#define MOUSE_BOTH_BUTTONS (BS1L_BUTTON_DOWN | BS1R_BUTTON_DOWN)
|
||||
#define MOUSE_DOWN_MASK (BS1L_BUTTON_DOWN | BS1R_BUTTON_DOWN)
|
||||
#define MOUSE_UP_MASK (BS1L_BUTTON_UP | BS1R_BUTTON_UP)
|
||||
|
||||
struct MouseObj {
|
||||
int id;
|
||||
Object *compact;
|
||||
};
|
||||
|
||||
#include "common/pack-start.h" // START STRUCT PACKING
|
||||
|
||||
struct MousePtr {
|
||||
uint16 numFrames;
|
||||
uint16 sizeX;
|
||||
uint16 sizeY;
|
||||
uint16 hotSpotX;
|
||||
uint16 hotSpotY;
|
||||
uint8 dummyData[0x30];
|
||||
} PACKED_STRUCT;
|
||||
|
||||
#include "common/pack-end.h" // END STRUCT PACKING
|
||||
|
||||
class Logic;
|
||||
class Menu;
|
||||
class ResMan;
|
||||
class ObjectMan;
|
||||
|
||||
class Mouse {
|
||||
public:
|
||||
Mouse(OSystem *system, ResMan *pResMan, ObjectMan *pObjMan);
|
||||
~Mouse();
|
||||
void initialize();
|
||||
void addToList(int id, Object *compact);
|
||||
void useLogicAndMenu(Logic *pLogic, Menu *pMenu);
|
||||
void useScreenMutex(Common::Mutex *mutex);
|
||||
void setLuggage(uint32 resID, uint32 rate);
|
||||
void setPointer(uint32 resID, uint32 rate);
|
||||
void animate();
|
||||
void engine(uint16 x, uint16 y, uint16 eventFlags);
|
||||
uint16 testEvent();
|
||||
void giveCoords(uint16 *x, uint16 *y);
|
||||
void fnNoHuman();
|
||||
void fnAddHuman();
|
||||
void fnBlankMouse();
|
||||
void fnNormalMouse();
|
||||
void fnLockMouse();
|
||||
void fnUnlockMouse();
|
||||
void controlPanel(bool on);
|
||||
private:
|
||||
void createPointer(uint32 ptrId, uint32 luggageId);
|
||||
OSystem *_system;
|
||||
Logic *_logic;
|
||||
Menu *_menu;
|
||||
MouseObj _objList[MAX_MOUSE];
|
||||
ResMan *_resMan;
|
||||
ObjectMan *_objMan;
|
||||
Common::Point _mouse;
|
||||
Common::Mutex *_screenAccessMutex;
|
||||
|
||||
uint32 _currentPtrId, _currentLuggageId;
|
||||
MousePtr *_currentPtr;
|
||||
int _frame, _activeFrame;
|
||||
uint16 _numObjs;
|
||||
uint16 _lastState, _state;
|
||||
uint32 _getOff;
|
||||
bool _inTopMenu, _mouseOverride;
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif //BSMOUSE_H
|
||||
124
engines/sword1/object.h
Normal file
124
engines/sword1/object.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/* 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 SWORD1_OBJECT_H
|
||||
#define SWORD1_OBJECT_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#define O_TOTAL_EVENTS 5
|
||||
#define O_WALKANIM_SIZE 600 //max number of nodes in router output
|
||||
#define O_GRID_SIZE 200
|
||||
#define EXTRA_GRID_SIZE 20
|
||||
|
||||
#include "common/pack-start.h" // START STRUCT PACKING
|
||||
|
||||
struct OEventSlot { //receiving event list in the compact -
|
||||
int32 o_event; //array of these with O_TOTAL_EVENTS elements
|
||||
int32 o_event_script;
|
||||
} PACKED_STRUCT; // size = 2*int32 = 8 bytes
|
||||
|
||||
#define TOTAL_script_levels 5
|
||||
|
||||
struct ScriptTree { //this is a logic tree, used by OBJECTs
|
||||
int32 o_script_level; //logic level
|
||||
int32 o_script_id[TOTAL_script_levels]; //script id's (are unique to each level)
|
||||
int32 o_script_pc[TOTAL_script_levels]; //pc of script for each (if script_manager)
|
||||
} PACKED_STRUCT; // size = 11*int32 = 44 bytes
|
||||
|
||||
struct TalkOffset {
|
||||
int32 x;
|
||||
int32 y;
|
||||
} PACKED_STRUCT; // size = 2*int32 = 8 bytes
|
||||
|
||||
struct WalkData {
|
||||
int32 frame;
|
||||
int32 x;
|
||||
int32 y;
|
||||
int32 step;
|
||||
int32 dir;
|
||||
} PACKED_STRUCT; // size = 5*int32 = 20 bytes
|
||||
|
||||
struct Object {
|
||||
int32 o_type; // 0 broad description of type - object, floor, etc.
|
||||
int32 o_status; // 4 bit flags for logic, graphics, mouse, etc.
|
||||
int32 o_logic; // 8 logic type
|
||||
int32 o_place; // 12 where is the mega character
|
||||
int32 o_down_flag; // 16 pass back down with this - with C possibly both are unnecessary?
|
||||
int32 o_target; // 20 target object for the GTM *these are linked to script
|
||||
int32 o_screen; // 24 physical screen/section
|
||||
int32 o_frame; // 28 frame number &
|
||||
int32 o_resource; // 32 id of spr file it comes from
|
||||
int32 o_sync; // 36 receive sync here
|
||||
int32 o_pause; // 40 logic_engine() pauses these cycles
|
||||
int32 o_xcoord; // 44
|
||||
int32 o_ycoord; // 48
|
||||
int32 o_mouse_x1; // 52 top-left of mouse area is (x1,y1)
|
||||
int32 o_mouse_y1; // 56
|
||||
int32 o_mouse_x2; // 60 bottom-right of area is (x2,y2) (these coords are inclusive)
|
||||
int32 o_mouse_y2; // 64
|
||||
int32 o_priority; // 68
|
||||
int32 o_mouse_on; // 72
|
||||
int32 o_mouse_off; // 76
|
||||
int32 o_mouse_click; // 80
|
||||
int32 o_interact; // 84
|
||||
int32 o_get_to_script; // 88
|
||||
int32 o_scale_a; // 92 used by floors
|
||||
int32 o_scale_b; // 96
|
||||
int32 o_anim_x; // 100
|
||||
int32 o_anim_y; // 104
|
||||
|
||||
ScriptTree o_tree; // 108 size = 44 bytes
|
||||
ScriptTree o_bookmark; // 152 size = 44 bytes
|
||||
|
||||
int32 o_dir; // 196
|
||||
int32 o_speech_pen; // 200
|
||||
int32 o_speech_width; // 204
|
||||
int32 o_speech_time; // 208
|
||||
int32 o_text_id; // 212 working back from o_ins1
|
||||
int32 o_tag; // 216
|
||||
int32 o_anim_pc; // 220 position within an animation structure
|
||||
int32 o_anim_resource; // 224 cdt or anim table
|
||||
|
||||
int32 o_walk_pc; // 228
|
||||
|
||||
TalkOffset talk_table[6]; // 232 size = 6*8 bytes = 48
|
||||
|
||||
OEventSlot o_event_list[O_TOTAL_EVENTS]; // 280 size = 5*8 bytes = 40
|
||||
|
||||
int32 o_ins1; // 320
|
||||
int32 o_ins2; // 324
|
||||
int32 o_ins3; // 328
|
||||
|
||||
int32 o_mega_resource; // 332
|
||||
int32 o_walk_resource; // 336
|
||||
|
||||
WalkData o_route[O_WALKANIM_SIZE]; // 340 size = 600*20 bytes = 12000
|
||||
// mega size = 12340 bytes (+ 8 byte offset table + 20 byte header = 12368)
|
||||
} PACKED_STRUCT;
|
||||
|
||||
#include "common/pack-end.h" // END STRUCT PACKING
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif //BSOBJECT_H
|
||||
468
engines/sword1/objectman.cpp
Normal file
468
engines/sword1/objectman.cpp
Normal file
@@ -0,0 +1,468 @@
|
||||
/* 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/util.h"
|
||||
|
||||
#include "sword1/objectman.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "sword1/swordres.h"
|
||||
#include "sword1/sword1.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
ObjectMan::ObjectMan(ResMan *pResourceMan) {
|
||||
_resMan = pResourceMan;
|
||||
}
|
||||
|
||||
void ObjectMan::initialize() {
|
||||
uint16 cnt;
|
||||
for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
|
||||
_liveList[cnt] = 0; // we don't need to close the files here. When this routine is
|
||||
// called, the memory was flushed() anyways, so these resources
|
||||
// already *are* closed.
|
||||
|
||||
_liveList[128] = _liveList[129] = _liveList[130] = _liveList[131] = _liveList[133] =
|
||||
_liveList[134] = _liveList[145] = _liveList[146] = _liveList[TEXT_sect] = 1;
|
||||
|
||||
for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++) {
|
||||
if (_liveList[cnt])
|
||||
_cptData[cnt] = (uint8 *)_resMan->cptResOpen(_objectList[cnt]) + sizeof(Header);
|
||||
else
|
||||
_cptData[cnt] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ObjectMan::~ObjectMan() {
|
||||
for (uint16 cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
|
||||
if (_liveList[cnt])
|
||||
_resMan->resClose(_objectList[cnt]);
|
||||
}
|
||||
|
||||
bool ObjectMan::sectionAlive(uint16 section) {
|
||||
return (_liveList[section] > 0);
|
||||
}
|
||||
|
||||
void ObjectMan::megaEntering(uint16 section) {
|
||||
_liveList[section]++;
|
||||
if (_liveList[section] == 1)
|
||||
_cptData[section] = ((uint8 *)_resMan->cptResOpen(_objectList[section])) + sizeof(Header);
|
||||
}
|
||||
|
||||
void ObjectMan::megaLeaving(uint16 section, int id) {
|
||||
if (_liveList[section] == 0)
|
||||
error("mega %d is leaving empty section %d", id, section);
|
||||
_liveList[section]--;
|
||||
if ((_liveList[section] == 0) && (id != PLAYER)) {
|
||||
_resMan->resClose(_objectList[section]);
|
||||
_cptData[section] = nullptr;
|
||||
}
|
||||
/* if the player is leaving the section then we have to close the resources after
|
||||
mainloop ends, because the screen will still need the resources*/
|
||||
}
|
||||
|
||||
uint8 ObjectMan::fnCheckForTextLine(uint32 textId) {
|
||||
uint8 retVal = 0;
|
||||
if (!_textList[textId / ITM_PER_SEC][0])
|
||||
return 0; // section does not exist
|
||||
|
||||
uint8 lang = SwordEngine::_systemVars.language;
|
||||
uint32 *textData = (uint32 *)((uint8 *)_resMan->openFetchRes(_textList[textId / ITM_PER_SEC][lang]) + sizeof(Header));
|
||||
if ((textId & ITM_ID) < _resMan->readUint32(textData)) {
|
||||
textData++;
|
||||
if (textData[textId & ITM_ID])
|
||||
retVal = 1;
|
||||
}
|
||||
_resMan->resClose(_textList[textId / ITM_PER_SEC][lang]);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
char *ObjectMan::lockText(uint32 textId) {
|
||||
uint8 lang = SwordEngine::_systemVars.language;
|
||||
char *text = lockText(textId, lang);
|
||||
if (text == 0) {
|
||||
if (lang != BS1_ENGLISH) {
|
||||
text = lockText(textId, BS1_ENGLISH);
|
||||
if (text != 0)
|
||||
warning("Missing translation for textId %u (\"%s\")", textId, text);
|
||||
unlockText(textId, BS1_ENGLISH);
|
||||
}
|
||||
|
||||
return _missingSubTitleStr;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
char *ObjectMan::lockText(uint32 textId, uint8 lang) {
|
||||
char *addr = (char *)_resMan->openFetchRes(_textList[textId / ITM_PER_SEC][lang]);
|
||||
if (addr == nullptr)
|
||||
return nullptr;
|
||||
addr += sizeof(Header);
|
||||
if ((textId & ITM_ID) >= _resMan->readUint32(addr)) {
|
||||
// Workaround for missing sentences in some languages in the demo.
|
||||
switch(textId) {
|
||||
case 8455194:
|
||||
return const_cast<char *>(_translationId8455194[lang]);
|
||||
case 8455195:
|
||||
return const_cast<char *>(_translationId8455195[lang]);
|
||||
case 8455196:
|
||||
return const_cast<char *>(_translationId8455196[lang]);
|
||||
case 8455197:
|
||||
return const_cast<char *>(_translationId8455197[lang]);
|
||||
case 8455198:
|
||||
return const_cast<char *>(_translationId8455198[lang]);
|
||||
case 8455199:
|
||||
return const_cast<char *>(_translationId8455199[lang]);
|
||||
case 8455200:
|
||||
return const_cast<char *>(_translationId8455200[lang]);
|
||||
case 8455201:
|
||||
return const_cast<char *>(_translationId8455201[lang]);
|
||||
case 8455202:
|
||||
return const_cast<char *>(_translationId8455202[lang]);
|
||||
case 8455203:
|
||||
return const_cast<char *>(_translationId8455203[lang]);
|
||||
case 8455204:
|
||||
return const_cast<char *>(_translationId8455204[lang]);
|
||||
case 8455205:
|
||||
return const_cast<char *>(_translationId8455205[lang]);
|
||||
case 6488080:
|
||||
return const_cast<char *>(_translationId6488080[lang]);
|
||||
case 6488081:
|
||||
return const_cast<char *>(_translationId6488081[lang]);
|
||||
case 6488082:
|
||||
return const_cast<char *>(_translationId6488082[lang]);
|
||||
case 6488083:
|
||||
return const_cast<char *>(_translationId6488083[lang]);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
warning("ObjectMan::lockText(%d): only %d texts in file", textId & ITM_ID, _resMan->readUint32(addr));
|
||||
return nullptr;
|
||||
}
|
||||
uint32 offset = _resMan->readUint32(addr + ((textId & ITM_ID) + 1) * 4);
|
||||
if (offset == 0) {
|
||||
switch(textId) {
|
||||
// Workaround bug for missing sentence in some languages in Syria (see bug #3753).
|
||||
// We use the hardcoded text in this case.
|
||||
case 2950145:
|
||||
return const_cast<char *>(_translationId2950145[lang]);
|
||||
|
||||
// Workaround for some strings in spanish demo
|
||||
case 6488080:
|
||||
return const_cast<char *>(_translationId6488080[lang]);
|
||||
case 6488081:
|
||||
return const_cast<char *>(_translationId6488081[lang]);
|
||||
case 6488082:
|
||||
return const_cast<char *>(_translationId6488082[lang]);
|
||||
case 6488083:
|
||||
return const_cast<char *>(_translationId6488083[lang]);
|
||||
}
|
||||
warning("ObjectMan::lockText(%d): text number has no text lines", textId);
|
||||
return nullptr;
|
||||
}
|
||||
return addr + offset;
|
||||
}
|
||||
|
||||
void ObjectMan::unlockText(uint32 textId) {
|
||||
unlockText(textId, SwordEngine::_systemVars.language);
|
||||
}
|
||||
|
||||
void ObjectMan::unlockText(uint32 textId, uint8 lang) {
|
||||
_resMan->resClose(_textList[textId / ITM_PER_SEC][lang]);
|
||||
}
|
||||
|
||||
uint32 ObjectMan::lastTextNumber(int section) {
|
||||
uint8 *data = (uint8 *)_resMan->openFetchRes(_textList[section][SwordEngine::_systemVars.language]) + sizeof(Header);
|
||||
uint32 result = _resMan->readUint32(data) - 1;
|
||||
_resMan->resClose(_textList[section][SwordEngine::_systemVars.language]);
|
||||
return result;
|
||||
}
|
||||
|
||||
Object *ObjectMan::fetchObject(uint32 id) {
|
||||
uint8 *addr = _cptData[id / ITM_PER_SEC];
|
||||
if (!addr)
|
||||
addr = _cptData[id / ITM_PER_SEC] = ((uint8 *)_resMan->cptResOpen(_objectList[id / ITM_PER_SEC])) + sizeof(Header);
|
||||
|
||||
id &= ITM_ID;
|
||||
// DON'T do endian conversion here. it's already done.
|
||||
return (Object *)(addr + * (uint32 *)(addr + (id + 1) * 4));
|
||||
}
|
||||
|
||||
uint32 ObjectMan::fetchNoObjects(int section) {
|
||||
if (_cptData[section] == nullptr)
|
||||
error("fetchNoObjects: section %d is not open", section);
|
||||
return *(uint32 *)_cptData[section];
|
||||
}
|
||||
|
||||
void ObjectMan::closeSection(uint32 screen) {
|
||||
if (_liveList[screen] == 0) // close the section that PLAYER has just left, if it's empty now
|
||||
_resMan->resClose(_objectList[screen]);
|
||||
}
|
||||
|
||||
void ObjectMan::loadLiveList(uint16 *src) {
|
||||
for (uint16 cnt = 0; cnt < TOTAL_SECTIONS; cnt++) {
|
||||
if (_liveList[cnt]) {
|
||||
_resMan->resClose(_objectList[cnt]);
|
||||
_cptData[cnt] = nullptr;
|
||||
}
|
||||
_liveList[cnt] = src[cnt];
|
||||
if (_liveList[cnt])
|
||||
_cptData[cnt] = ((uint8 *)_resMan->cptResOpen(_objectList[cnt])) + sizeof(Header);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectMan::mainLoopPatch() {
|
||||
// This patch is available in every executable after the
|
||||
// original UK one. Its purpose is to turn off scripts which
|
||||
// were causing issues by continuing running past their scope.
|
||||
// The patch, as descripted within the original source
|
||||
// code, checks if the game is past the Syria section,
|
||||
// and if so it checks if the Market Stall section is still
|
||||
// alive, and if so it closes both the section (45) and
|
||||
// the Mega object for Duane (134), effectively terminating
|
||||
// their scripts.
|
||||
|
||||
if (_liveList[45] > 0) {
|
||||
_liveList[45] = 0; // Turn off the Syria Market Stall
|
||||
_resMan->resClose(_objectList[45]);
|
||||
|
||||
if (_liveList[134] > 0) {
|
||||
_liveList[134] = 0; // Turn off Duane
|
||||
_resMan->resClose(_objectList[134]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectMan::saveLiveList(uint16 *dest) {
|
||||
memcpy(dest, _liveList, TOTAL_SECTIONS * sizeof(uint16));
|
||||
}
|
||||
|
||||
// String displayed when a subtitle sentence is missing in the cluster file.
|
||||
// It happens with at least one sentence in Syria in some languages (see bug
|
||||
// #3753).
|
||||
// Note: an empty string or a null pointer causes a crash.
|
||||
|
||||
char ObjectMan::_missingSubTitleStr[] = " ";
|
||||
|
||||
// Missing translation for textId 2950145 (see bug #3753).
|
||||
// Currently text is missing for Portuguese languages. (It's possible that it
|
||||
// is not needed. The English version of the game does not include Portuguese
|
||||
// so I cannot check.)
|
||||
|
||||
const char *const ObjectMan::_translationId2950145[7] = {
|
||||
"Oh?", // English (not needed)
|
||||
"Quoi?", // French
|
||||
"Oh?", // German
|
||||
"Eh?", // Italian
|
||||
"\277Eh?", // Spanish
|
||||
"Ano?", // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// The translations for the next texts are missing in the demo but are present
|
||||
// in the full game. The translations were therefore extracted from the full game.
|
||||
|
||||
// Missing translation for textId 8455194 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455194[7] = {
|
||||
nullptr, // "Who was the guy you were supposed to meet?", // English (not needed)
|
||||
"Qui \351tait l'homme que vous deviez rencontrer?", // French
|
||||
"Wer war der Typ, den Du treffen wolltest?", // German
|
||||
"Chi dovevi incontrare?", // Italian
|
||||
"\277Qui\351n era el hombre con el que ten\355as que encontrarte?", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 8455195 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455195[7] = {
|
||||
nullptr, // "His name was Plantard. I didn't know him, but he called me last night.", // English (not needed)
|
||||
"Son nom \351tait Plantard. Je ne le connaissais pas, mais il m'avait t\351l\351phon\351 la veille.", // French
|
||||
"Sein Name war Plantard. Ich kannte ihn nicht, aber er hat mich letzte Nacht angerufen.", // German
|
||||
"Si chiamava Plantard. Mi ha chiamato ieri sera, ma non lo conoscevo.", // Italian
|
||||
"Su nombre era Plantard. Yo no lo conoc\355a pero \351l me llam\363 ayer por la noche.", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 8455196 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455196[7] = {
|
||||
nullptr, // "He said he had a story which would interest me.", // English (not needed)
|
||||
"Il a dit qu'il avait une histoire qui devrait m'int\351resser.", // French
|
||||
"Er sagte, er h\344tte eine Story, die mich interessieren w\374rde.", // German
|
||||
"Mi disse che aveva una storia che mi poteva interessare.", // Italian
|
||||
"Dijo que ten\355a una historia que me interesar\355a.", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 8455197 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455197[7] = {
|
||||
nullptr, // "He asked me to meet him at the caf\351.", // English (not needed)
|
||||
"Il m'a demand\351 de le rencontrer au caf\351.", // French
|
||||
"Er fragte mich, ob wir uns im Caf\351 treffen k\366nnten.", // German
|
||||
"Mi chiese di incontrarci al bar.", // Italian
|
||||
"Me pidi\363 que nos encontr\341ramos en el caf\351.", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 8455198 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455198[7] = {
|
||||
nullptr, // "I guess I'll never know what he wanted to tell me...", // English (not needed)
|
||||
"Je suppose que je ne saurai jamais ce qu'il voulait me dire...", // French
|
||||
"Ich werde wohl nie erfahren, was er mir sagen wollte...", // German
|
||||
"Penso che non sapr\362 mai che cosa voleva dirmi...", // Italian
|
||||
"Supongo que nunca sabr\351 qu\351 me quer\355a contar...", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 8455199 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455199[7] = {
|
||||
nullptr, // "Not unless you have Rosso's gift for psychic interrogation.", // English (not needed)
|
||||
"Non, \340 moins d'avoir les dons de Rosso pour les interrogatoires psychiques.", // French
|
||||
"Es sei denn, Du h\344ttest Rosso's Gabe der parapsychologischen Befragung.", // German
|
||||
"A meno che tu non riesca a fare interrogatori telepatici come Rosso.", // Italian
|
||||
"A no ser que tengas el don de Rosso para la interrogaci\363n ps\355quica.", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 8455200 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455200[7] = {
|
||||
nullptr, // "How did Plantard get your name?", // English (not needed)
|
||||
"Comment Plantard a-t-il obtenu votre nom?", // French
|
||||
"Woher hat Plantard Deinen Namen?", // German
|
||||
"Come ha fatto Plantard a sapere il tuo nome?", // Italian
|
||||
"\277C\363mo consigui\363 Plantard tu nombre?", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 8455201 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455201[7] = {
|
||||
nullptr, // "Through the newspaper - La Libert\351.", // English (not needed)
|
||||
"Par mon journal... La Libert\351.", // French
|
||||
"\334ber die Zeitung - La Libert\351.", // German
|
||||
"Tramite il giornale La Libert\351.", // Italian
|
||||
"Por el peri\363dico - La Libert\351.", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 8455202 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455202[7] = {
|
||||
nullptr, // "I'd written an article linking two unsolved murders, one in Italy, the other in Japan.", // English (not needed)
|
||||
"J'ai \351crit un article o\371 je faisais le lien entre deux meurtres inexpliqu\351s, en Italie et au japon.", // French
|
||||
"Ich habe einen Artikel geschrieben, in dem ich zwei ungel\366ste Morde miteinander in Verbindung bringe, einen in Italien, einen anderen in Japan.", // German
|
||||
"Ho scritto un articolo che metteva in collegamento due omicidi insoluti in Italia e Giappone.", // Italian
|
||||
"Yo hab\355a escrito un art\355culo conectando dos asesinatos sin resolver, uno en Italia, el otro en Jap\363n.", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 8455203 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455203[7] = {
|
||||
nullptr, // "The cases were remarkably similar...", // English (not needed)
|
||||
"Les affaires \351taient quasiment identiques...", // French
|
||||
"Die F\344lle sind sich bemerkenswert \344hnlich...", // German
|
||||
"I casi erano sorprendentemente uguali...", // Italian
|
||||
"Los casos eran incre\355blemente parecidos...", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 8455204 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455204[7] = {
|
||||
nullptr, // "...a wealthy victim, no apparent motive, and a costumed killer.", // English (not needed)
|
||||
"...une victime riche, pas de motif apparent, et un tueur d\351guis\351.", // French
|
||||
"...ein wohlhabendes Opfer, kein offensichtliches Motiv, und ein verkleideter Killer.", // German
|
||||
"...una vittima ricca, nessun motivo apparente e un assassino in costume.", // Italian
|
||||
"...una v\355ctima rica, sin motivo aparente, y un asesino disfrazado.", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 8455205 (in the demo).
|
||||
const char *const ObjectMan::_translationId8455205[7] = {
|
||||
nullptr, // "Plantard said he could supply me with more information.", // English (not needed)
|
||||
"Plantard m'a dit qu'il pourrait me fournir des renseignements.", // French
|
||||
"Plantard sagte, er k\366nne mir weitere Informationen beschaffen.", // German
|
||||
"Plantard mi disse che mi avrebbe fornito ulteriori informazioni.", // Italian
|
||||
"Plantard dijo que \351l me pod\355a proporcionar m\341s informaci\363n.", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 6488080 (in the demo).
|
||||
const char *const ObjectMan::_translationId6488080[7] = {
|
||||
nullptr, // "I wasn't going to head off all over Paris until I'd investigated some more.", // English (not needed)
|
||||
"Je ferais mieux d'enqu\351ter un peu par ici avant d'aller me promener ailleurs.", // French
|
||||
"Ich durchquere nicht ganz Paris, bevor ich etwas mehr herausgefunden habe.", // German
|
||||
"Non mi sarei incamminato per tutta Parigi prima di ulteriori indagini.", // Italian
|
||||
"No iba a empezar a recorrerme todo Par\355s hasta haber investigado algo m\341s.", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// The next three sentences are specific to the demo and only the english text is present.
|
||||
// The translations were provided by:
|
||||
// French: Thierry Crozat
|
||||
// German: Simon Sawatzki
|
||||
// Italian: Matteo Angelino
|
||||
// Spanish: Tomás Maidagan
|
||||
|
||||
// Missing translation for textId 6488081 (in the demo).
|
||||
const char *const ObjectMan::_translationId6488081[7] = {
|
||||
nullptr, // "I wasn't sure what I was going to do when I caught up with that clown...", // English (not needed)
|
||||
"Je ne savais pas ce que je ferais quand je rattraperais le clown...", // French
|
||||
"Ich wu\337te nicht, worauf ich mich einlie\337, als ich dem Clown nachjagte...", // German
|
||||
"Non sapevo cosa avrei fatto una volta raggiunto quel clown...", // Italian
|
||||
"No estaba seguro de qu\351 iba a hacer cuando alcanzara a ese payaso...", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 6488082 (in the demo).
|
||||
const char *const ObjectMan::_translationId6488082[7] = {
|
||||
nullptr, // "...but before I knew it, I was drawn into a desperate race between two ruthless enemies.", // English (not needed)
|
||||
"...mais avant de m'en rendre compte je me retrouvais happ\351 dans une course effr\351n\351e entre deux ennemis impitoyables.", // French
|
||||
"... doch bevor ich mich versah, war ich inmitten eines Wettlaufs von zwei r\374cksichtslosen Feinden.", // German
|
||||
"... ma prima che me ne rendessi conto, fui trascinato in una corsa disperata con due spietati nemici.", // Italian
|
||||
"... pero antes de que me diera tiempo a pensarlo, me encontr\351 metido en una carrera desesperada entre dos enemigos sin piedad.", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
// Missing translation for textId 6488083 (in the demo).
|
||||
const char *const ObjectMan::_translationId6488083[7] = {
|
||||
nullptr, // "The goal: the mysterious power of the Broken Sword.", // English (not needed)
|
||||
"Le but: les pouvoirs myst\351rieux de l'\351p\351e bris\351e.", // French
|
||||
"Das Ziel: die geheimnisvolle Macht des zerbrochenen Schwertes.", // German
|
||||
"Obiettivo: il misterioso potere della Spada spezzata.", // Italian
|
||||
"El objetivo: el misterioso poder de la Espada Rota.", // Spanish
|
||||
nullptr, // Czech
|
||||
nullptr // Portuguese
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
88
engines/sword1/objectman.h
Normal file
88
engines/sword1/objectman.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// this is the object manager. our equivalent to protocol.c and coredata.c
|
||||
|
||||
#ifndef SWORD1_OBJECTMAN_H
|
||||
#define SWORD1_OBJECTMAN_H
|
||||
|
||||
#include "sword1/resman.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "sword1/object.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
class ObjectMan {
|
||||
public:
|
||||
ObjectMan(ResMan *pResourceMan);
|
||||
~ObjectMan();
|
||||
void initialize();
|
||||
|
||||
Object *fetchObject(uint32 id);
|
||||
uint32 fetchNoObjects(int section);
|
||||
bool sectionAlive(uint16 section);
|
||||
void megaEntering(uint16 section);
|
||||
void megaLeaving(uint16 section, int id);
|
||||
|
||||
uint8 fnCheckForTextLine(uint32 textId);
|
||||
char *lockText(uint32 textId);
|
||||
void unlockText(uint32 textId);
|
||||
uint32 lastTextNumber(int section);
|
||||
|
||||
void closeSection(uint32 screen);
|
||||
|
||||
void saveLiveList(uint16 *dest); // for loading/saving
|
||||
void loadLiveList(uint16 *src);
|
||||
|
||||
void mainLoopPatch();
|
||||
|
||||
private:
|
||||
char *lockText(uint32 textId, uint8 language);
|
||||
void unlockText(uint32 textId, uint8 language);
|
||||
|
||||
ResMan *_resMan;
|
||||
static const uint32 _objectList[TOTAL_SECTIONS]; //a table of pointers to object files
|
||||
static const uint32 _textList[TOTAL_SECTIONS][7]; //a table of pointers to text files
|
||||
uint16 _liveList[TOTAL_SECTIONS]; //which sections are active
|
||||
uint8 *_cptData[TOTAL_SECTIONS];
|
||||
static char _missingSubTitleStr[];
|
||||
static const char *const _translationId2950145[7]; //translation for textId 2950145 (missing from cluster file for some languages)
|
||||
static const char *const _translationId8455194[7]; //translation for textId 8455194 (missing in the demo)
|
||||
static const char *const _translationId8455195[7]; //translation for textId 8455195 (missing in the demo)
|
||||
static const char *const _translationId8455196[7]; //translation for textId 8455196 (missing in the demo)
|
||||
static const char *const _translationId8455197[7]; //translation for textId 8455197 (missing in the demo)
|
||||
static const char *const _translationId8455198[7]; //translation for textId 8455198 (missing in the demo)
|
||||
static const char *const _translationId8455199[7]; //translation for textId 8455199 (missing in the demo)
|
||||
static const char *const _translationId8455200[7]; //translation for textId 8455200 (missing in the demo)
|
||||
static const char *const _translationId8455201[7]; //translation for textId 8455201 (missing in the demo)
|
||||
static const char *const _translationId8455202[7]; //translation for textId 8455202 (missing in the demo)
|
||||
static const char *const _translationId8455203[7]; //translation for textId 8455203 (missing in the demo)
|
||||
static const char *const _translationId8455204[7]; //translation for textId 8455204 (missing in the demo)
|
||||
static const char *const _translationId8455205[7]; //translation for textId 8455205 (missing in the demo)
|
||||
static const char *const _translationId6488080[7]; //translation for textId 6488081 (missing in the demo)
|
||||
static const char *const _translationId6488081[7]; //translation for textId 6488081 (missing in the demo)
|
||||
static const char *const _translationId6488082[7]; //translation for textId 6488082 (missing in the demo)
|
||||
static const char *const _translationId6488083[7]; //translation for textId 6488083 (missing in the demo)
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif //OBJECTMAN_H
|
||||
34
engines/sword1/obsolete.h
Normal file
34
engines/sword1/obsolete.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* 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 SWORD1_OBSOLETE_H
|
||||
#define SWORD1_OBSOLETE_H
|
||||
|
||||
static const Engines::ObsoleteGameID obsoleteGameIDsTable[] = {
|
||||
{"sword1demo", "sword1", Common::kPlatformWindows},
|
||||
{"sword1mac", "sword1", Common::kPlatformMacintosh},
|
||||
{"sword1macdemo", "sword1", Common::kPlatformMacintosh},
|
||||
{"sword1psx", "sword1", Common::kPlatformPSX},
|
||||
{"sword1psxdemo", "sword1", Common::kPlatformPSX},
|
||||
{0, 0, Common::kPlatformUnknown}
|
||||
};
|
||||
|
||||
#endif // SWORD1_OBSOLETE_H
|
||||
587
engines/sword1/resman.cpp
Normal file
587
engines/sword1/resman.cpp
Normal file
@@ -0,0 +1,587 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "sword1/memman.h"
|
||||
#include "sword1/resman.h"
|
||||
#include "sword1/sword1.h"
|
||||
#include "sword1/swordres.h"
|
||||
|
||||
#include "gui/message.h"
|
||||
|
||||
namespace Sword1 {
|
||||
void guiFatalError(char *msg) {
|
||||
// Displays a dialog on-screen before terminating the engine.
|
||||
// TODO: We really need to setup a special palette for cases when
|
||||
// the engine is erroring before setting one... otherwise invisible cursor :)
|
||||
|
||||
GUI::MessageDialog dialog(msg);
|
||||
dialog.runModal();
|
||||
error("%s", msg);
|
||||
}
|
||||
|
||||
#define MAX_PATH_LEN 260
|
||||
|
||||
ResMan::ResMan(const char *fileName, bool isMacFile, bool isKorean) {
|
||||
_openCluStart = _openCluEnd = nullptr;
|
||||
_openClus = 0;
|
||||
_isBigEndian = isMacFile;
|
||||
_isKorTrs = isKorean;
|
||||
_memMan = new MemMan();
|
||||
loadCluDescript(fileName);
|
||||
}
|
||||
|
||||
ResMan::~ResMan() {
|
||||
#if 0
|
||||
for (uint32 clusCnt = 0; clusCnt < _prj.noClu; clusCnt++) {
|
||||
Clu *cluster = _prj.clu[clusCnt];
|
||||
if (cluster) {
|
||||
for (uint32 grpCnt = 0; grpCnt < cluster->noGrp; grpCnt++) {
|
||||
Grp *group = cluster->grp[grpCnt];
|
||||
if (group) {
|
||||
for (uint32 resCnt = 0; resCnt < group->noRes; resCnt++) {
|
||||
if (group->resHandle[resCnt].cond == MEM_DONT_FREE) {
|
||||
warning("ResMan::~ResMan: Resource %02X.%04X.%02X is still open",
|
||||
clusCnt + 1, grpCnt, resCnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
debug(0, "ResMan closed\n");
|
||||
#endif
|
||||
flush();
|
||||
freeCluDescript();
|
||||
delete _memMan;
|
||||
}
|
||||
|
||||
void ResMan::loadCluDescript(const char *fileName) {
|
||||
// The cluster description file is always little endian (even on the mac version, whose cluster files are big endian)
|
||||
Common::File file;
|
||||
file.open(fileName);
|
||||
|
||||
if (!file.isOpen()) {
|
||||
char msg[512];
|
||||
Common::sprintf_s(msg, "Couldn't open CLU description '%s'\n\nIf you are running from CD, please ensure you have read the ScummVM documentation regarding multi-cd games.", fileName);
|
||||
guiFatalError(msg);
|
||||
}
|
||||
|
||||
|
||||
_prj.noClu = file.readUint32LE();
|
||||
_prj.clu = new Clu[_prj.noClu]();
|
||||
|
||||
uint32 *cluIndex = (uint32 *)malloc(_prj.noClu * 4);
|
||||
file.read(cluIndex, _prj.noClu * 4);
|
||||
|
||||
for (uint32 clusCnt = 0; clusCnt < _prj.noClu; clusCnt++)
|
||||
if (cluIndex[clusCnt]) {
|
||||
Clu *cluster = _prj.clu + clusCnt;
|
||||
file.read(cluster->label, MAX_LABEL_SIZE);
|
||||
|
||||
cluster->file = nullptr;
|
||||
cluster->noGrp = file.readUint32LE();
|
||||
cluster->grp = new Grp[cluster->noGrp];
|
||||
cluster->nextOpen = nullptr;
|
||||
memset(cluster->grp, 0, cluster->noGrp * sizeof(Grp));
|
||||
cluster->refCount = 0;
|
||||
|
||||
uint32 *grpIndex = (uint32 *)malloc(cluster->noGrp * 4);
|
||||
file.read(grpIndex, cluster->noGrp * 4);
|
||||
|
||||
for (uint32 grpCnt = 0; grpCnt < cluster->noGrp; grpCnt++)
|
||||
if (grpIndex[grpCnt]) {
|
||||
Grp *group = cluster->grp + grpCnt;
|
||||
group->noRes = file.readUint32LE();
|
||||
group->resHandle = new MemHandle[group->noRes];
|
||||
group->offset = new uint32[group->noRes];
|
||||
group->length = new uint32[group->noRes];
|
||||
uint32 *resIdIdx = (uint32 *)malloc(group->noRes * 4);
|
||||
file.read(resIdIdx, group->noRes * 4);
|
||||
|
||||
for (uint32 resCnt = 0; resCnt < group->noRes; resCnt++) {
|
||||
if (resIdIdx[resCnt]) {
|
||||
group->offset[resCnt] = file.readUint32LE();
|
||||
group->length[resCnt] = file.readUint32LE();
|
||||
_memMan->initHandle(group->resHandle + resCnt);
|
||||
} else {
|
||||
group->offset[resCnt] = 0xFFFFFFFF;
|
||||
group->length[resCnt] = 0;
|
||||
_memMan->initHandle(group->resHandle + resCnt);
|
||||
}
|
||||
}
|
||||
free(resIdIdx);
|
||||
}
|
||||
free(grpIndex);
|
||||
}
|
||||
free(cluIndex);
|
||||
|
||||
if (_prj.clu[3].grp[5].noRes == 29)
|
||||
for (uint8 cnt = 0; cnt < 29; cnt++)
|
||||
_srIdList[cnt] = 0x04050000 | cnt;
|
||||
|
||||
if (_isKorTrs) {
|
||||
Common::File cluFile;
|
||||
cluFile.open("korean.clu");
|
||||
if (cluFile.isOpen()) {
|
||||
for (uint32 resCnt = 0, resOffset = 0; resCnt < _prj.clu[2].grp[0].noRes; resCnt++) {
|
||||
Header header;
|
||||
cluFile.read(&header, sizeof(Header));
|
||||
_prj.clu[2].grp[0].offset[resCnt] = resOffset;
|
||||
_prj.clu[2].grp[0].length[resCnt] = header.comp_length;
|
||||
resOffset += header.comp_length;
|
||||
cluFile.seek(header.decomp_length, SEEK_CUR);
|
||||
}
|
||||
Common::strcpy_s(_prj.clu[2].label, "korean");
|
||||
} else {
|
||||
_isKorTrs = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResMan::freeCluDescript() {
|
||||
|
||||
for (uint32 clusCnt = 0; clusCnt < _prj.noClu; clusCnt++) {
|
||||
Clu *cluster = _prj.clu + clusCnt;
|
||||
for (uint32 grpCnt = 0; grpCnt < cluster->noGrp; grpCnt++) {
|
||||
Grp *group = cluster->grp + grpCnt;
|
||||
if (group->resHandle != nullptr) {
|
||||
for (uint32 resCnt = 0; resCnt < group->noRes; resCnt++)
|
||||
_memMan->freeNow(group->resHandle + resCnt);
|
||||
|
||||
delete[] group->resHandle;
|
||||
delete[] group->offset;
|
||||
delete[] group->length;
|
||||
}
|
||||
}
|
||||
delete[] cluster->grp;
|
||||
delete cluster->file;
|
||||
}
|
||||
delete[] _prj.clu;
|
||||
}
|
||||
|
||||
void ResMan::flush() {
|
||||
Common::StackLock lock(_resourceAccessMutex);
|
||||
for (uint32 clusCnt = 0; clusCnt < _prj.noClu; clusCnt++) {
|
||||
Clu *cluster = _prj.clu + clusCnt;
|
||||
for (uint32 grpCnt = 0; grpCnt < cluster->noGrp; grpCnt++) {
|
||||
Grp *group = cluster->grp + grpCnt;
|
||||
for (uint32 resCnt = 0; resCnt < group->noRes; resCnt++)
|
||||
if (group->resHandle[resCnt].cond != MEM_FREED) {
|
||||
_memMan->setCondition(group->resHandle + resCnt, MEM_CAN_FREE);
|
||||
group->resHandle[resCnt].refCount = 0;
|
||||
}
|
||||
}
|
||||
if (cluster->file) {
|
||||
cluster->file->close();
|
||||
delete cluster->file;
|
||||
cluster->file = nullptr;
|
||||
cluster->refCount = 0;
|
||||
}
|
||||
}
|
||||
_openClus = 0;
|
||||
_openCluStart = _openCluEnd = nullptr;
|
||||
// the memory manager cached the blocks we asked it to free, so explicitly make it free them
|
||||
_memMan->flush();
|
||||
}
|
||||
|
||||
void *ResMan::fetchRes(uint32 id) {
|
||||
MemHandle *memHandle = resHandle(id);
|
||||
|
||||
if (!memHandle) {
|
||||
warning("fetchRes:: resource %d out of bounds", id);
|
||||
return nullptr;
|
||||
}
|
||||
if (!memHandle->data)
|
||||
error("fetchRes:: resource %d is not open", id);
|
||||
return memHandle->data;
|
||||
}
|
||||
|
||||
void *ResMan::openFetchRes(uint32 id) {
|
||||
resOpen(id);
|
||||
return fetchRes(id);
|
||||
}
|
||||
|
||||
void ResMan::dumpRes(uint32 id) {
|
||||
char outn[30];
|
||||
Common::sprintf_s(outn, "DUMP%08X.BIN", id);
|
||||
Common::DumpFile outf;
|
||||
if (outf.open(outn)) {
|
||||
resOpen(id);
|
||||
MemHandle *memHandle = resHandle(id);
|
||||
if (memHandle) {
|
||||
outf.write(memHandle->data, memHandle->size);
|
||||
outf.close();
|
||||
}
|
||||
resClose(id);
|
||||
}
|
||||
}
|
||||
|
||||
Header *ResMan::lockScript(uint32 scrID) {
|
||||
if (!_scriptList[scrID / ITM_PER_SEC])
|
||||
error("Script id %d not found", scrID);
|
||||
scrID = _scriptList[scrID / ITM_PER_SEC];
|
||||
#ifdef SCUMM_BIG_ENDIAN
|
||||
openScriptResourceBigEndian(scrID);
|
||||
#else
|
||||
openScriptResourceLittleEndian(scrID);
|
||||
#endif
|
||||
MemHandle *handle = resHandle(scrID);
|
||||
if (!handle)
|
||||
error("Script resource handle %d not found", scrID);
|
||||
return (Header *)handle->data;
|
||||
}
|
||||
|
||||
void ResMan::unlockScript(uint32 scrID) {
|
||||
resClose(_scriptList[scrID / ITM_PER_SEC]);
|
||||
}
|
||||
|
||||
void *ResMan::cptResOpen(uint32 id) {
|
||||
#ifdef SCUMM_BIG_ENDIAN
|
||||
openCptResourceBigEndian(id);
|
||||
#else
|
||||
openCptResourceLittleEndian(id);
|
||||
#endif
|
||||
MemHandle *handle = resHandle(id);
|
||||
return handle != nullptr ? handle->data : nullptr;
|
||||
}
|
||||
|
||||
void ResMan::resOpen(uint32 id) { // load resource ID into memory
|
||||
Common::StackLock lock(_resourceAccessMutex);
|
||||
MemHandle *memHandle = resHandle(id);
|
||||
|
||||
if (!memHandle)
|
||||
return;
|
||||
if (memHandle->cond == MEM_FREED) { // memory has been freed
|
||||
if (id == GAME_FONT && _isKorTrs) {
|
||||
// Load Korean Font
|
||||
uint32 size = resLength(id);
|
||||
uint32 korFontSize = 0;
|
||||
Common::File korFontFile;
|
||||
|
||||
korFontFile.open("bs1k.fnt");
|
||||
if (korFontFile.isOpen()) {
|
||||
korFontSize = korFontFile.size();
|
||||
}
|
||||
_memMan->alloc(memHandle, size + korFontSize);
|
||||
Common::File *clusFile = resFile(id);
|
||||
assert(clusFile);
|
||||
clusFile->seek(resOffset(id));
|
||||
clusFile->read(memHandle->data, size);
|
||||
if (clusFile->err() || clusFile->eos()) {
|
||||
error("Can't read %d bytes from offset %d from cluster file %s\nResource ID: %d (%08X)", size, resOffset(id), _prj.clu[(id >> 24) - 1].label, id, id);
|
||||
}
|
||||
|
||||
if (korFontSize > 0) {
|
||||
korFontFile.read((uint8 *)memHandle->data + size, korFontSize);
|
||||
}
|
||||
} else {
|
||||
uint32 size = resLength(id);
|
||||
_memMan->alloc(memHandle, size);
|
||||
Common::File *clusFile = resFile(id);
|
||||
assert(clusFile);
|
||||
clusFile->seek(resOffset(id));
|
||||
clusFile->read(memHandle->data, size);
|
||||
if (clusFile->err() || clusFile->eos()) {
|
||||
error("Can't read %d bytes from offset %d from cluster file %s\nResource ID: %d (%08X)", size, resOffset(id), _prj.clu[(id >> 24) - 1].label, id, id);
|
||||
}
|
||||
}
|
||||
} else
|
||||
_memMan->setCondition(memHandle, MEM_DONT_FREE);
|
||||
|
||||
memHandle->refCount++;
|
||||
if (memHandle->refCount > 20) {
|
||||
debug(1, "%d references to id %d. Guess there's something wrong.", memHandle->refCount, id);
|
||||
}
|
||||
}
|
||||
|
||||
void ResMan::resClose(uint32 id) {
|
||||
Common::StackLock lock(_resourceAccessMutex);
|
||||
MemHandle *handle = resHandle(id);
|
||||
if (!handle)
|
||||
return;
|
||||
if (!handle->refCount) {
|
||||
warning("Resource Manager fail: unlocking object with refCount 0. Id: %d", id);
|
||||
} else {
|
||||
handle->refCount--;
|
||||
if (!handle->refCount)
|
||||
_memMan->setCondition(handle, MEM_CAN_FREE);
|
||||
}
|
||||
}
|
||||
|
||||
FrameHeader *ResMan::fetchFrame(void *resourceData, uint32 frameNo) {
|
||||
uint8 *frameFile = (uint8 *)resourceData;
|
||||
uint8 *idxData = frameFile + sizeof(Header);
|
||||
if (_isBigEndian) {
|
||||
if (frameNo >= READ_BE_UINT32(idxData))
|
||||
error("fetchFrame:: frame %d doesn't exist in resource.", frameNo);
|
||||
frameFile += READ_BE_UINT32(idxData + (frameNo + 1) * 4);
|
||||
} else {
|
||||
if (frameNo >= READ_LE_UINT32(idxData))
|
||||
error("fetchFrame:: frame %d doesn't exist in resource.", frameNo);
|
||||
frameFile += READ_LE_UINT32(idxData + (frameNo + 1) * 4);
|
||||
}
|
||||
return (FrameHeader *)frameFile;
|
||||
}
|
||||
|
||||
Common::File *ResMan::resFile(uint32 id) {
|
||||
Clu *cluster = _prj.clu + ((id >> 24) - 1);
|
||||
if (cluster->file == nullptr) {
|
||||
_openClus++;
|
||||
if (_openCluEnd == nullptr) {
|
||||
_openCluStart = _openCluEnd = cluster;
|
||||
} else {
|
||||
_openCluEnd->nextOpen = cluster;
|
||||
_openCluEnd = cluster;
|
||||
}
|
||||
cluster->file = new Common::File();
|
||||
char fileName[36];
|
||||
// Supposes that big endian means mac cluster file and little endian means PC cluster file.
|
||||
// This works, but we may want to separate the file name from the endianess or try .CLM extension if opening.clu file fail.
|
||||
if (_isBigEndian)
|
||||
Common::sprintf_s(fileName, "%s.CLM", _prj.clu[(id >> 24) - 1].label);
|
||||
else
|
||||
Common::sprintf_s(fileName, "%s.CLU", _prj.clu[(id >> 24) - 1].label);
|
||||
cluster->file->open(fileName);
|
||||
if (!cluster->file->isOpen()) {
|
||||
char msg[512];
|
||||
Common::sprintf_s(msg, "Couldn't open game cluster file '%s'\n\nIf you are running from CD, please ensure you have read the ScummVM documentation regarding multi-cd games.", fileName);
|
||||
guiFatalError(msg);
|
||||
}
|
||||
while (_openClus > MAX_OPEN_CLUS) {
|
||||
assert(_openCluStart);
|
||||
Clu *closeClu = _openCluStart;
|
||||
_openCluStart = _openCluStart->nextOpen;
|
||||
|
||||
if (closeClu->file)
|
||||
closeClu->file->close();
|
||||
delete closeClu->file;
|
||||
closeClu->file = nullptr;
|
||||
closeClu->nextOpen = nullptr;
|
||||
|
||||
_openClus--;
|
||||
}
|
||||
}
|
||||
return cluster->file;
|
||||
}
|
||||
|
||||
MemHandle *ResMan::resHandle(uint32 id) {
|
||||
if ((id >> 16) == 0x0405)
|
||||
id = _srIdList[id & 0xFFFF];
|
||||
uint8 cluster = (uint8)((id >> 24) - 1);
|
||||
uint8 group = (uint8)(id >> 16);
|
||||
|
||||
// There is a known case of reading beyond array boundaries when trying to use
|
||||
// portuguese subtitles (cluster file 2, group 6) with a version that does not
|
||||
// contain subtitles for this languages (i.e. has only 6 languages and not 7).
|
||||
if (cluster >= _prj.noClu || group >= _prj.clu[cluster].noGrp)
|
||||
return nullptr;
|
||||
|
||||
return &(_prj.clu[cluster].grp[group].resHandle[id & 0xFFFF]);
|
||||
}
|
||||
|
||||
uint32 ResMan::resLength(uint32 id) {
|
||||
if ((id >> 16) == 0x0405)
|
||||
id = _srIdList[id & 0xFFFF];
|
||||
uint8 cluster = (uint8)((id >> 24) - 1);
|
||||
uint8 group = (uint8)(id >> 16);
|
||||
|
||||
if (cluster >= _prj.noClu || group >= _prj.clu[cluster].noGrp)
|
||||
return 0;
|
||||
|
||||
return _prj.clu[cluster].grp[group].length[id & 0xFFFF];
|
||||
}
|
||||
|
||||
uint32 ResMan::resOffset(uint32 id) {
|
||||
if ((id >> 16) == 0x0405)
|
||||
id = _srIdList[id & 0xFFFF];
|
||||
uint8 cluster = (uint8)((id >> 24) - 1);
|
||||
uint8 group = (uint8)(id >> 16);
|
||||
|
||||
if (cluster >= _prj.noClu || group >= _prj.clu[cluster].noGrp)
|
||||
return 0;
|
||||
|
||||
return _prj.clu[cluster].grp[group].offset[id & 0xFFFF];
|
||||
}
|
||||
|
||||
void ResMan::openCptResourceBigEndian(uint32 id) {
|
||||
bool needByteSwap = false;
|
||||
if (!_isBigEndian) {
|
||||
// Cluster files are in little endian fomat.
|
||||
// If the resource are not in memory anymore, and therefore will be read
|
||||
// from disk, they will need to be byte swaped.
|
||||
MemHandle *memHandle = resHandle(id);
|
||||
if (memHandle)
|
||||
needByteSwap = (memHandle->cond == MEM_FREED);
|
||||
}
|
||||
resOpen(id);
|
||||
if (needByteSwap) {
|
||||
MemHandle *handle = resHandle(id);
|
||||
if (!handle)
|
||||
return;
|
||||
uint32 totSize = handle->size;
|
||||
uint32 *data = (uint32 *)((uint8 *)handle->data + sizeof(Header));
|
||||
totSize -= sizeof(Header);
|
||||
if (totSize & 3)
|
||||
error("Illegal compact size for id %d: %d", id, totSize);
|
||||
totSize /= 4;
|
||||
for (uint32 cnt = 0; cnt < totSize; cnt++) {
|
||||
*data = READ_LE_UINT32(data);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResMan::openCptResourceLittleEndian(uint32 id) {
|
||||
bool needByteSwap = false;
|
||||
if (_isBigEndian) {
|
||||
// Cluster files are in big endian fomat.
|
||||
// If the resource are not in memory anymore, and therefore will be read
|
||||
// from disk, they will need to be byte swaped.
|
||||
MemHandle *memHandle = resHandle(id);
|
||||
if (memHandle)
|
||||
needByteSwap = (memHandle->cond == MEM_FREED);
|
||||
}
|
||||
resOpen(id);
|
||||
if (needByteSwap) {
|
||||
MemHandle *handle = resHandle(id);
|
||||
if (!handle)
|
||||
return;
|
||||
uint32 totSize = handle->size;
|
||||
uint32 *data = (uint32 *)((uint8 *)handle->data + sizeof(Header));
|
||||
totSize -= sizeof(Header);
|
||||
if (totSize & 3)
|
||||
error("Illegal compact size for id %d: %d", id, totSize);
|
||||
totSize /= 4;
|
||||
for (uint32 cnt = 0; cnt < totSize; cnt++) {
|
||||
*data = READ_BE_UINT32(data);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResMan::openScriptResourceBigEndian(uint32 id) {
|
||||
bool needByteSwap = false;
|
||||
if (!_isBigEndian) {
|
||||
// Cluster files are in little endian fomat.
|
||||
// If the resource are not in memory anymore, and therefore will be read
|
||||
// from disk, they will need to be byte swaped.
|
||||
MemHandle *memHandle = resHandle(id);
|
||||
if (memHandle)
|
||||
needByteSwap = (memHandle->cond == MEM_FREED);
|
||||
}
|
||||
resOpen(id);
|
||||
if (needByteSwap) {
|
||||
MemHandle *handle = resHandle(id);
|
||||
if (!handle)
|
||||
return;
|
||||
// uint32 totSize = handle->size;
|
||||
Header *head = (Header *)handle->data;
|
||||
head->comp_length = FROM_LE_32(head->comp_length);
|
||||
head->decomp_length = FROM_LE_32(head->decomp_length);
|
||||
head->version = FROM_LE_16(head->version);
|
||||
uint32 *data = (uint32 *)((uint8 *)handle->data + sizeof(Header));
|
||||
uint32 size = handle->size - sizeof(Header);
|
||||
if (size & 3)
|
||||
error("Odd size during script endian conversion. Resource ID =%d, size = %d", id, size);
|
||||
size >>= 2;
|
||||
for (uint32 cnt = 0; cnt < size; cnt++) {
|
||||
*data = READ_LE_UINT32(data);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResMan::openScriptResourceLittleEndian(uint32 id) {
|
||||
bool needByteSwap = false;
|
||||
if (_isBigEndian) {
|
||||
// Cluster files are in big endian fomat.
|
||||
// If the resource are not in memory anymore, and therefore will be read
|
||||
// from disk, they will need to be byte swaped.
|
||||
MemHandle *memHandle = resHandle(id);
|
||||
if (memHandle)
|
||||
needByteSwap = (memHandle->cond == MEM_FREED);
|
||||
}
|
||||
resOpen(id);
|
||||
if (needByteSwap) {
|
||||
MemHandle *handle = resHandle(id);
|
||||
if (!handle)
|
||||
return;
|
||||
// uint32 totSize = handle->size;
|
||||
Header *head = (Header *)handle->data;
|
||||
head->comp_length = FROM_BE_32(head->comp_length);
|
||||
head->decomp_length = FROM_BE_32(head->decomp_length);
|
||||
head->version = FROM_BE_16(head->version);
|
||||
uint32 *data = (uint32 *)((uint8 *)handle->data + sizeof(Header));
|
||||
uint32 size = handle->size - sizeof(Header);
|
||||
if (size & 3)
|
||||
error("Odd size during script endian conversion. Resource ID =%d, size = %d", id, size);
|
||||
size >>= 2;
|
||||
for (uint32 cnt = 0; cnt < size; cnt++) {
|
||||
*data = READ_BE_UINT32(data);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 ResMan::getDeathFontId() {
|
||||
// At some point in the releases (as evidenced by the disasms of all
|
||||
// known executables, and by the source code in our possession), Revolution
|
||||
// changed the resource offsets for some files. I have tried EVERYTHING to
|
||||
// try and discern which file we are dealing with and spectacularly failed.
|
||||
// The only choice which seems to work correctly is to check the file size,
|
||||
// as the newer GENERAL.CLU file is bigger. Sorry.
|
||||
if (SwordEngine::isPsx())
|
||||
return SR_FONT;
|
||||
|
||||
Common::File fp;
|
||||
if (fp.open(SwordEngine::isMac() ? "GENERAL.CLM" : "GENERAL.CLU")) {
|
||||
fp.seek(0, SEEK_END);
|
||||
int64 fileSize = fp.pos();
|
||||
|
||||
if (SwordEngine::_systemVars.realLanguage == Common::RU_RUS) {
|
||||
switch (fileSize) {
|
||||
case 6081261: // Akella
|
||||
return SR_DEATHFONT;
|
||||
case 6354790: // Mediahauz
|
||||
return SR_FONT;
|
||||
case 6350630: // Novy Disk
|
||||
return SR_DEATHFONT_ALT;
|
||||
default:
|
||||
warning("ResMan::getDeathFontId(): Unrecognized version of russian GENERAL.CLU, size %d", (int)fileSize);
|
||||
break;
|
||||
}
|
||||
|
||||
return SR_FONT;
|
||||
} else if (fileSize < 6295679) {
|
||||
return SR_DEATHFONT;
|
||||
} else {
|
||||
return SR_DEATHFONT_ALT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End of namespace Sword1
|
||||
169
engines/sword1/resman.h
Normal file
169
engines/sword1/resman.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/* 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 SWORD1_RESMAN_H
|
||||
#define SWORD1_RESMAN_H
|
||||
|
||||
#include "sword1/memman.h"
|
||||
#include "sword1/swordres.h"
|
||||
#include "common/file.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/mutex.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#define MAX_LABEL_SIZE (31+1)
|
||||
|
||||
#if defined(__PSP__)
|
||||
#define MAX_OPEN_CLUS 4 // the PSP can't have more than 8 files open simultaneously
|
||||
// since we also need filehandles for music and sometimes savegames
|
||||
// set the maximum number of open clusters to 4.
|
||||
#else
|
||||
#define MAX_OPEN_CLUS 8 // don't open more than 8 files at once
|
||||
#endif
|
||||
|
||||
struct Grp {
|
||||
uint32 noRes;
|
||||
MemHandle *resHandle;
|
||||
uint32 *offset;
|
||||
uint32 *length;
|
||||
};
|
||||
|
||||
struct Clu {
|
||||
uint32 refCount;
|
||||
Common::File *file;
|
||||
char label[MAX_LABEL_SIZE];
|
||||
uint32 noGrp;
|
||||
Grp *grp;
|
||||
Clu *nextOpen;
|
||||
};
|
||||
|
||||
struct Prj {
|
||||
uint32 noClu;
|
||||
Clu *clu;
|
||||
};
|
||||
|
||||
class ResMan {
|
||||
public:
|
||||
ResMan(const char *fileName, bool isMacFile, bool isKorean);
|
||||
~ResMan();
|
||||
void flush();
|
||||
void resClose(uint32 id);
|
||||
void resOpen(uint32 id);
|
||||
void *fetchRes(uint32 id);
|
||||
void dumpRes(uint32 id);
|
||||
void *openFetchRes(uint32 id);
|
||||
void *cptResOpen(uint32 id);
|
||||
Header *lockScript(uint32 scrID);
|
||||
void unlockScript(uint32 scrID);
|
||||
FrameHeader *fetchFrame(void *resourceData, uint32 frameNo);
|
||||
|
||||
uint16 getUint16(uint16 value) {
|
||||
return (_isBigEndian) ? FROM_BE_16(value) : FROM_LE_16(value);
|
||||
}
|
||||
uint32 getUint32(uint32 value) {
|
||||
return (_isBigEndian) ? FROM_BE_32(value) : FROM_LE_32(value);
|
||||
}
|
||||
uint16 getLEUint16(uint16 value) {
|
||||
return FROM_LE_16(value);
|
||||
}
|
||||
uint32 getLEUint32(uint32 value) {
|
||||
return FROM_LE_32(value);
|
||||
}
|
||||
uint16 readUint16(const void *ptr) {
|
||||
return (_isBigEndian) ? READ_BE_UINT16(ptr) : READ_LE_UINT16(ptr);
|
||||
}
|
||||
uint32 readUint32(const void *ptr) {
|
||||
return (_isBigEndian) ? READ_BE_UINT32(ptr) : READ_LE_UINT32(ptr);
|
||||
}
|
||||
uint32 readLEUint32(const void *ptr) {
|
||||
return READ_LE_UINT32(ptr);
|
||||
}
|
||||
uint16 toUint16(uint16 value) {
|
||||
return (_isBigEndian) ? TO_BE_16(value) : TO_LE_16(value);
|
||||
}
|
||||
uint32 toUint32(uint32 value) {
|
||||
return (_isBigEndian) ? TO_BE_32(value) : TO_LE_32(value);
|
||||
}
|
||||
|
||||
uint32 getDeathFontId();
|
||||
|
||||
private:
|
||||
uint32 resLength(uint32 id);
|
||||
MemHandle *resHandle(uint32 id);
|
||||
uint32 resOffset(uint32 id);
|
||||
Common::File *resFile(uint32 id);
|
||||
|
||||
void openCptResourceBigEndian(uint32 id);
|
||||
void openScriptResourceBigEndian(uint32 id);
|
||||
void openCptResourceLittleEndian(uint32 id);
|
||||
void openScriptResourceLittleEndian(uint32 id);
|
||||
|
||||
void loadCluDescript(const char *fileName);
|
||||
void freeCluDescript();
|
||||
Prj _prj;
|
||||
MemMan *_memMan;
|
||||
static const uint32 _scriptList[TOTAL_SECTIONS]; //a table of resource tags
|
||||
Clu *_openCluStart, *_openCluEnd;
|
||||
int _openClus;
|
||||
bool _isBigEndian;
|
||||
bool _isKorTrs = false;
|
||||
|
||||
Common::Mutex _resourceAccessMutex;
|
||||
|
||||
uint32 _srIdList[29] = {
|
||||
// the file numbers differ for the control panel file IDs, so we need this array
|
||||
OTHER_SR_FONT, // SR_FONT
|
||||
0x04050000, // SR_BUTTON
|
||||
OTHER_SR_REDFONT, // SR_REDFONT
|
||||
0x04050001, // SR_PALETTE
|
||||
0x04050002, // SR_PANEL_ENGLISH
|
||||
0x04050003, // SR_PANEL_FRENCH
|
||||
0x04050004, // SR_PANEL_GERMAN
|
||||
0x04050005, // SR_PANEL_ITALIAN
|
||||
0x04050006, // SR_PANEL_SPANISH
|
||||
0x04050007, // SR_PANEL_AMERICAN
|
||||
0x04050008, // SR_TEXT_BUTTON
|
||||
0x04050009, // SR_SPEED
|
||||
0x0405000A, // SR_SCROLL1
|
||||
0x0405000B, // SR_SCROLL2
|
||||
0x0405000C, // SR_CONFIRM
|
||||
0x0405000D, // SR_VOLUME
|
||||
0x0405000E, // SR_VLIGHT
|
||||
0x0405000F, // SR_VKNOB
|
||||
0x04050010, // SR_WINDOW
|
||||
0x04050011, // SR_SLAB1
|
||||
0x04050012, // SR_SLAB2
|
||||
0x04050013, // SR_SLAB3
|
||||
0x04050014, // SR_SLAB4
|
||||
0x04050015, // SR_BUTUF
|
||||
0x04050016, // SR_BUTUS
|
||||
0x04050017, // SR_BUTDS
|
||||
0x04050018, // SR_BUTDF
|
||||
0x04050019, // SR_DEATHPANEL
|
||||
SR_DEATHFONT,
|
||||
};
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif //RESMAN_H
|
||||
2135
engines/sword1/router.cpp
Normal file
2135
engines/sword1/router.cpp
Normal file
File diff suppressed because it is too large
Load Diff
161
engines/sword1/router.h
Normal file
161
engines/sword1/router.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/* 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 SWORD1_ROUTER_H
|
||||
#define SWORD1_ROUTER_H
|
||||
|
||||
#include "sword1/object.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#include "common/pack-start.h" // START STRUCT PACKING
|
||||
|
||||
struct BarData {
|
||||
int16 x1;
|
||||
int16 y1;
|
||||
int16 x2;
|
||||
int16 y2;
|
||||
int16 xmin;
|
||||
int16 ymin;
|
||||
int16 xmax;
|
||||
int16 ymax;
|
||||
int16 dx; // x2 - x1
|
||||
int16 dy; // y2 - y1
|
||||
int32 co; // co = (y1*dx) - (x1*dy) from an equation for a line y*dx = x*dy + co
|
||||
} PACKED_STRUCT;
|
||||
|
||||
struct NodeData {
|
||||
int16 x;
|
||||
int16 y;
|
||||
int16 level;
|
||||
int16 prev;
|
||||
int16 dist;
|
||||
} PACKED_STRUCT;
|
||||
|
||||
#include "common/pack-end.h" // END STRUCT PACKING
|
||||
|
||||
struct FloorData {
|
||||
int32 nbars;
|
||||
BarData *bars;
|
||||
int32 nnodes;
|
||||
NodeData *node;
|
||||
};
|
||||
|
||||
struct RouteData {
|
||||
int32 x;
|
||||
int32 y;
|
||||
int32 dirS;
|
||||
int32 dirD;
|
||||
};
|
||||
|
||||
struct PathData {
|
||||
int32 x;
|
||||
int32 y;
|
||||
int32 dir;
|
||||
int32 num;
|
||||
};
|
||||
|
||||
#define MAX_FRAMES_PER_CYCLE 16
|
||||
#define NO_DIRECTIONS 8
|
||||
#define MAX_FRAMES_PER_CHAR (MAX_FRAMES_PER_CYCLE * NO_DIRECTIONS)
|
||||
#define ROUTE_END_FLAG 255
|
||||
|
||||
#define O_GRID_SIZE 200
|
||||
#define O_ROUTE_SIZE 50
|
||||
|
||||
class ObjectMan;
|
||||
class ResMan;
|
||||
class Screen;
|
||||
|
||||
extern int whatTarget(int32 startX, int32 startY, int32 destX, int32 destY);
|
||||
|
||||
class Router {
|
||||
public:
|
||||
Router(ObjectMan *pObjMan, ResMan *pResMan);
|
||||
int32 routeFinder(int32 id, Object *mega, int32 x, int32 y, int32 dir);
|
||||
void setPlayerTarget(int32 x, int32 y, int32 dir, int32 stance);
|
||||
|
||||
// these should be private but are read by Screen for debugging:
|
||||
BarData _bars[O_GRID_SIZE];
|
||||
NodeData _node[O_GRID_SIZE];
|
||||
|
||||
int32 _nBars;
|
||||
int32 _nNodes;
|
||||
|
||||
private:
|
||||
// when the player collides with another mega, we'll receive a ReRouteRequest here.
|
||||
// that's why we need to remember the player's target coordinates
|
||||
int32 _playerTargetX, _playerTargetY, _playerTargetDir, _playerTargetStance;
|
||||
|
||||
ObjectMan *_objMan;
|
||||
ResMan *_resMan;
|
||||
|
||||
int32 _startX, _startY, _startDir;
|
||||
int32 _targetX, _targetY, _targetDir;
|
||||
int32 _scaleA, _scaleB;
|
||||
|
||||
int32 megaId;
|
||||
|
||||
RouteData _route[O_ROUTE_SIZE];
|
||||
PathData _smoothPath[O_ROUTE_SIZE];
|
||||
PathData _modularPath[O_ROUTE_SIZE];
|
||||
int32 _routeLength;
|
||||
|
||||
int32 _framesPerStep, _framesPerChar;
|
||||
uint8 _nWalkFrames, _nTurnFrames;
|
||||
int32 _dx[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
|
||||
int32 _dy[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
|
||||
int32 _modX[NO_DIRECTIONS];
|
||||
int32 _modY[NO_DIRECTIONS];
|
||||
int32 _diagonalx, _diagonaly;
|
||||
int32 standFrames;
|
||||
int32 turnFramesLeft, turnFramesRight;
|
||||
int32 walkFramesLeft, walkFramesRight; // left/right walking turn
|
||||
int32 slowInFrames, slowOutFrames;
|
||||
|
||||
bool _slidyWalkAnimatorState;
|
||||
|
||||
int32 LoadWalkResources(Object *mega, int32 x, int32 y, int32 dir);
|
||||
int32 getRoute();
|
||||
int32 checkTarget(int32 x, int32 y);
|
||||
|
||||
bool scan(int32 level);
|
||||
int32 newCheck(int32 status, int32 x1, int32 x2, int32 y1, int32 y2);
|
||||
bool check(int32 x1, int32 y1, int32 x2, int32 y2);
|
||||
bool horizCheck(int32 x1, int32 y, int32 x2);
|
||||
bool vertCheck(int32 x, int32 y1, int32 y2);
|
||||
bool lineCheck(int32 x1, int32 y1, int32 x2, int32 y2);
|
||||
|
||||
void extractRoute();
|
||||
|
||||
void slidyPath();
|
||||
void slidyWalkAnimator(WalkData *walkAnim);
|
||||
|
||||
int32 smoothestPath();
|
||||
void smoothCheck(int32 &steps, int32 best, int32 p, int32 dirS, int32 dirD);
|
||||
|
||||
void solidPath();
|
||||
int32 solidWalkAnimator(WalkData *walkAnim);
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif //BSROUTER_H
|
||||
1631
engines/sword1/screen.cpp
Normal file
1631
engines/sword1/screen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
198
engines/sword1/screen.h
Normal file
198
engines/sword1/screen.h
Normal file
@@ -0,0 +1,198 @@
|
||||
/* 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 SWORD1_SCREEN_H
|
||||
#define SWORD1_SCREEN_H
|
||||
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "common/mutex.h"
|
||||
|
||||
class OSystem;
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#define MAX_FORE 20
|
||||
#define MAX_BACK 20
|
||||
#define MAX_SORT 20
|
||||
|
||||
struct SortSpr {
|
||||
int32 id, y;
|
||||
};
|
||||
|
||||
struct RoomDef {
|
||||
int totalLayers;
|
||||
int sizeX;
|
||||
int sizeY;
|
||||
int gridWidth; //number of 16*16 grid blocks across - including off screen edges.
|
||||
uint32 layers[4];
|
||||
uint32 grids[3];
|
||||
uint32 palettes[2];
|
||||
uint32 parallax[2];
|
||||
};
|
||||
|
||||
struct PSXDataCache { // Cache for PSX screen, to avoid decompressing background at every screen update
|
||||
uint8 *decodedBackground;
|
||||
uint8 *extPlxCache; // If this screen requires an external parallax, save it here
|
||||
};
|
||||
|
||||
#define SCRNGRID_X 16
|
||||
#define SCRNGRID_Y 8
|
||||
#define SHRINK_BUFFER_SIZE 50000
|
||||
#define RLE_BUFFER_SIZE 50000
|
||||
|
||||
#define FLASH_RED 0
|
||||
#define FLASH_BLUE 1
|
||||
#define BORDER_YELLOW 2
|
||||
#define BORDER_GREEN 3
|
||||
#define BORDER_PURPLE 4
|
||||
#define BORDER_BLACK 5
|
||||
#define TEXT_WHITE 6
|
||||
|
||||
class SwordEngine;
|
||||
class ResMan;
|
||||
class ObjectMan;
|
||||
class Text; // Text objects use sprites that are created internally at run-time
|
||||
// the buffer belongs to Text, so we need a reference here.
|
||||
|
||||
class Screen {
|
||||
friend class Text;
|
||||
public:
|
||||
Screen(OSystem *system, SwordEngine *vm, ResMan *pResMan, ObjectMan *pObjMan);
|
||||
~Screen();
|
||||
void clearScreen();
|
||||
void useTextManager(Text *pTextMan);
|
||||
void draw();
|
||||
void initFadePaletteServer();
|
||||
|
||||
void quitScreen();
|
||||
void newScreen(uint32 screen);
|
||||
|
||||
void setScrolling(int16 offsetX, int16 offsetY);
|
||||
void addToGraphicList(uint8 listId, uint32 objId);
|
||||
|
||||
void startFadePaletteDown(int speed);
|
||||
void startFadePaletteUp(int speed);
|
||||
void fadePalette();
|
||||
void fnSetPalette(uint8 start, uint16 length, uint32 id);
|
||||
void fnSetFadeTargetPalette(uint8 start, uint16 length, uint32 id, int singleColor = -1);
|
||||
int16 stillFading();
|
||||
void fullRefresh(bool soft = false);
|
||||
void setNextFadeOutToBlack();
|
||||
|
||||
bool showScrollFrame();
|
||||
void updateScreen();
|
||||
void showFrame(uint16 x, uint16 y, uint32 resId, uint32 frameNo, const byte *fadeMask = nullptr, int8 fadeStatus = 0);
|
||||
|
||||
void fnSetParallax(uint32 screen, uint32 resId);
|
||||
void fnFlash(uint8 color);
|
||||
|
||||
static void decompressHIF(uint8 *src, uint8 *dest);
|
||||
|
||||
void printDebugLine(uint8 *ascii, uint8 first, int x, int y);
|
||||
|
||||
// Functions used by the router debug visualization routines
|
||||
void plotLine(int32 x1, int32 y1, int32 x2, int32 y2, uint8 color);
|
||||
void plotPoint(int32 x, int32 y, uint8 color);
|
||||
void bresenhamLine(int32 x1, int32 y1, int32 x2, int32 y2, uint8 color);
|
||||
|
||||
Common::Mutex _screenAccessMutex; // To coordinate actions between the main thread and the palette fade thread
|
||||
|
||||
private:
|
||||
// The original values are 6-bit RGB numbers, so they have to be shifted,
|
||||
// except for white, which for some reason has to stay unshifted in order
|
||||
// to work correctly.
|
||||
const uint8 _white[3] = { 63, 63, 63 };
|
||||
const uint8 _red[3] = { 63 << 2, 0 << 2, 0 << 2 };
|
||||
const uint8 _blue[3] = { 0 << 2, 0 << 2, 63 << 2 };
|
||||
const uint8 _yellow[3] = { 63 << 2, 63 << 2, 0 << 2 };
|
||||
const uint8 _green[3] = { 0 << 2, 63 << 2, 0 << 2 };
|
||||
const uint8 _purple[3] = { 32 << 2, 0 << 2, 32 << 2 };
|
||||
const uint8 _black[3] = { 0 << 2, 0 << 2, 0 << 2 };
|
||||
//const uint8 _grey[3] = { 32 << 2, 32 << 2, 32 << 2 };
|
||||
|
||||
struct PaletteFadeInfo {
|
||||
int16 paletteStatus;
|
||||
int16 paletteIndex;
|
||||
int16 paletteCount;
|
||||
int16 fadeCount;
|
||||
uint8 srcPalette[256 * 3];
|
||||
uint8 dstPalette[256 * 3];
|
||||
};
|
||||
|
||||
PaletteFadeInfo _paletteFadeInfo;
|
||||
|
||||
void verticalMask(uint16 x, uint16 y, uint16 bWidth, uint16 bHeight);
|
||||
void blitBlockClear(uint16 x, uint16 y, uint8 *data);
|
||||
void renderParallax(uint8 *data);
|
||||
void processImage(uint32 id);
|
||||
void spriteClipAndSet(uint16 *pSprX, uint16 *pSprY, uint16 *sprWidth, uint16 *sprHeight, uint16 *incr);
|
||||
void drawSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch);
|
||||
void drawPsxHalfShrinkedSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch);
|
||||
void drawPsxFullShrinkedSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch);
|
||||
uint8 *psxBackgroundToIndexed(uint8 *psxBackground, uint32 bakXres, uint32 bakYres);
|
||||
uint8 *psxShrinkedBackgroundToIndexed(uint8 *psxBackground, uint32 bakXres, uint32 bakYres);
|
||||
void fetchPsxParallaxSize(uint8 *psxParallax, uint16 *paraSizeX, uint16 *paraSizeY);
|
||||
void drawPsxParallax(uint8 *psxParallax, uint16 paraScrlX, uint16 scrnScrlX, uint16 scrnWidth);
|
||||
void decompressRLE7(uint8 *src, uint32 compSize, uint8 *dest);
|
||||
void decompressRLE0(uint8 *src, uint32 compSize, uint8 *dest);
|
||||
void decompressTony(uint8 *src, uint32 compSize, uint8 *dest);
|
||||
void fastShrink(uint8 *src, uint32 width, uint32 height, uint32 scale, uint8 *dest);
|
||||
|
||||
void flushPsxCache();
|
||||
|
||||
OSystem *_system;
|
||||
SwordEngine *_vm;
|
||||
ResMan *_resMan;
|
||||
ObjectMan *_objMan;
|
||||
Text *_textMan;
|
||||
|
||||
uint16 _currentScreen;
|
||||
uint8 *_screenBuf;
|
||||
uint8 *_screenGrid;
|
||||
uint16 *_layerGrid[4];
|
||||
uint8 *_layerBlocks[4];
|
||||
uint8 *_parallax[2];
|
||||
uint8 _rleBuffer[RLE_BUFFER_SIZE];
|
||||
uint8 _shrinkBuffer[SHRINK_BUFFER_SIZE];
|
||||
bool _fullRefresh;
|
||||
bool _updatePalette;
|
||||
uint16 _oldScrollX, _oldScrollY; // for drawing additional frames
|
||||
|
||||
PSXDataCache _psxCache; // Cache used for PSX backgrounds
|
||||
|
||||
uint32 _foreList[MAX_FORE];
|
||||
uint32 _backList[MAX_BACK];
|
||||
SortSpr _sortList[MAX_SORT];
|
||||
uint8 _foreLength, _backLength, _sortLength;
|
||||
uint16 _scrnSizeX, _scrnSizeY, _gridSizeX, _gridSizeY;
|
||||
|
||||
static RoomDef _roomDefTable[TOTAL_ROOMS]; // from ROOMS.C (not const, see fnSetParallax)
|
||||
|
||||
uint8 _targetPalette[256 * 3];
|
||||
uint8 _currentPalette[256 * 3]; // for fading
|
||||
uint8 _zeroPalette[256 * 3];
|
||||
|
||||
bool _forceNextFadeOutToBlack = false;
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif //BSSCREEN_H
|
||||
1688
engines/sword1/sound.cpp
Normal file
1688
engines/sword1/sound.cpp
Normal file
File diff suppressed because it is too large
Load Diff
269
engines/sword1/sound.h
Normal file
269
engines/sword1/sound.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/* 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 SWORD1_SOUND_H
|
||||
#define SWORD1_SOUND_H
|
||||
|
||||
#include "sword1/object.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/mutex.h"
|
||||
#include "common/random.h"
|
||||
#include "common/timer.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
namespace Audio {
|
||||
class Mixer;
|
||||
}
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#define TOTAL_FX_PER_ROOM 7 // total loop & random fx per room (see fx_list.c)
|
||||
#define MAX_ROOMS_PER_FX 7 // max no. of rooms in the fx's room,vol list
|
||||
#define MAX_FXQ_LENGTH 32 // max length of sound queue - ie. max number of fx that can be stored up/playing together
|
||||
|
||||
#define FX_SPOT 1
|
||||
#define FX_LOOP 2
|
||||
#define FX_RANDOM 3
|
||||
|
||||
struct QueueElement {
|
||||
uint32 id, delay;
|
||||
Audio::SoundHandle handle;
|
||||
|
||||
void reset() {
|
||||
id = 0, delay = 0;
|
||||
handle = Audio::SoundHandle();
|
||||
}
|
||||
};
|
||||
|
||||
struct RoomVol {
|
||||
int32 roomNo, leftVol, rightVol;
|
||||
};
|
||||
|
||||
struct SampleId {
|
||||
byte cluster;
|
||||
byte idStd;
|
||||
byte idWinDemo;
|
||||
};
|
||||
|
||||
struct FxDef {
|
||||
SampleId sampleId;
|
||||
uint32 type, delay;
|
||||
RoomVol roomVolList[MAX_ROOMS_PER_FX];
|
||||
};
|
||||
|
||||
class ResMan;
|
||||
class SwordEngine;
|
||||
|
||||
#define MUSIC_UNDERSCORE 50
|
||||
#define NEG_MOUTH_THRESHOLD -750
|
||||
#define POS_MOUTH_THRESHOLD 750
|
||||
#define MAX_FX 4
|
||||
#define MAX_MUSIC 2
|
||||
#define S_STATUS_FINISHED 1
|
||||
#define S_STATUS_RUNNING 0
|
||||
#define MUSIC_BUFFER_SIZE 0x2000
|
||||
#define TOTAL_TUNES 270
|
||||
#define DEFAULT_SAMPLE_RATE 11025
|
||||
|
||||
enum CowMode {
|
||||
CowWave = 0,
|
||||
CowFLAC,
|
||||
CowVorbis,
|
||||
CowMP3,
|
||||
CowDemo,
|
||||
CowPSX
|
||||
};
|
||||
|
||||
enum MusCompMode {
|
||||
MusWav = 0,
|
||||
MusAif,
|
||||
MusFLAC,
|
||||
MusVorbis,
|
||||
MusMP3,
|
||||
MusPSX
|
||||
};
|
||||
|
||||
class Sound {
|
||||
friend class SwordConsole;
|
||||
friend class Control;
|
||||
public:
|
||||
Sound(Audio::Mixer *mixer, SwordEngine *vm, ResMan *pResMan);
|
||||
~Sound();
|
||||
|
||||
void newScreen(uint32 screen);
|
||||
void closeCowSystem();
|
||||
|
||||
void engine();
|
||||
|
||||
void checkSpeechFileEndianness();
|
||||
double endiannessHeuristicValue(int16* data, uint32 dataSize, uint32 &maxSamples);
|
||||
|
||||
void installFadeTimer();
|
||||
void uninstallFadeTimer();
|
||||
|
||||
void playSample(int32 fxNo);
|
||||
void stopSample(int32 fxNo);
|
||||
void setFXVolume(byte targetVolume, int handleIdx);
|
||||
void clearAllFx();
|
||||
int addToQueue(uint32 fxNo);
|
||||
void removeFromQueue(uint32 fxNo);
|
||||
|
||||
void startSpeech(uint16 roomNo, uint16 localNo);
|
||||
bool amISpeaking();
|
||||
int32 checkSpeechStatus();
|
||||
void playSpeech();
|
||||
void stopSpeech();
|
||||
|
||||
void streamMusicFile(int32 tuneId, int32 looped);
|
||||
void updateMusicStreaming();
|
||||
void setCrossFadeIncrement();
|
||||
|
||||
void fadeMusicDown(int32 rate);
|
||||
void fadeFxDown(int32 rate);
|
||||
void fadeFxUp(int32 rate);
|
||||
|
||||
void pauseSpeech();
|
||||
void unpauseSpeech();
|
||||
void pauseMusic();
|
||||
void unpauseMusic();
|
||||
void pauseFx();
|
||||
void unpauseFx();
|
||||
|
||||
void getVolumes();
|
||||
void setVolumes();
|
||||
byte clampVolume(int32 volume);
|
||||
|
||||
Common::Mutex _soundMutex;
|
||||
Audio::Mixer *_mixer;
|
||||
|
||||
// Handles for external volume changes (control panel)
|
||||
uint32 _volFX[2] = { 0, 0 };
|
||||
uint32 _volSpeech[2] = { 0, 0 };
|
||||
uint32 _volMusic[2] = { 0, 0 };
|
||||
|
||||
// Volume fading variables
|
||||
int32 _fxCount = 0;
|
||||
int32 _fxFadingFlag = 0;
|
||||
int32 _fxFadingRate = 0;
|
||||
int32 _fxFadeVolume[2] = { 0, 0 };
|
||||
int32 _musicFadeVolume[2] = { 0, 0 };
|
||||
|
||||
// Sound FX information
|
||||
bool _fxSampleBusy[MAX_FX] = { false, false, false, false };
|
||||
|
||||
// Speech data
|
||||
byte *_speechSample = nullptr;
|
||||
|
||||
private:
|
||||
struct WaveHeader {
|
||||
uint32 riffTag;
|
||||
uint32 riffSize;
|
||||
uint32 waveTag;
|
||||
uint32 fmtTag;
|
||||
uint32 fmtSize;
|
||||
|
||||
// Format subchunk
|
||||
uint16 wFormatTag;
|
||||
uint16 wChannels;
|
||||
uint32 dwSamplesPerSec;
|
||||
uint32 dwAvgBytesPerSec;
|
||||
uint16 wBlockAlign;
|
||||
uint16 wBitsPerSample;
|
||||
uint32 dwDataTag;
|
||||
uint32 dwDataSize;
|
||||
};
|
||||
|
||||
void initCowSystem();
|
||||
|
||||
uint32 getSampleId(int32 fxNo);
|
||||
void playFX(int32 fxID, int32 type, uint8 *wavData, uint32 vol[2]);
|
||||
void stopFX(int32 fxID);
|
||||
int32 checkSampleStatus(int32 id);
|
||||
|
||||
bool expandSpeech(byte *src, byte *dst, uint32 dstSize,
|
||||
bool *endiannessCheck = nullptr, uint32 *sizeForEndiannessCheck = nullptr);
|
||||
int32 getSpeechSize(byte *compData, uint32 compSize);
|
||||
|
||||
bool prepareMusicStreaming(const Common::Path &filename, int newHandleId, int32 tuneId,
|
||||
uint32 volume, int8 pan, MusCompMode assignedMode);
|
||||
void serveSample(Common::File *file, int32 i);
|
||||
void reduceMusicVolume();
|
||||
void restoreMusicVolume();
|
||||
|
||||
int8 scalePan(int pan); // From 0,127 to -127,127
|
||||
|
||||
Common::File _cowFile;
|
||||
uint32 *_cowHeader;
|
||||
uint32 _cowHeaderSize;
|
||||
uint8 _currentCowFile;
|
||||
CowMode _cowMode;
|
||||
Common::RandomSource _rnd;
|
||||
|
||||
QueueElement _fxQueue[MAX_FXQ_LENGTH];
|
||||
uint8 _endOfQueue;
|
||||
SwordEngine *_vm;
|
||||
ResMan *_resMan;
|
||||
|
||||
bool _bigEndianSpeech;
|
||||
static const char _musicList[270];
|
||||
static const uint16 _roomsFixedFx[TOTAL_ROOMS][TOTAL_FX_PER_ROOM];
|
||||
static const FxDef _fxList[312];
|
||||
static const char _tuneList[TOTAL_TUNES][8]; // In staticres.cpp
|
||||
|
||||
// Volume fading variables
|
||||
bool _crossFadeIncrement = false;
|
||||
|
||||
// Speech variables
|
||||
int32 _speechLipsyncCounter = 0;
|
||||
int32 _speechSize = 0;
|
||||
bool _speechSampleBusy = false;
|
||||
|
||||
// Sound handles
|
||||
Audio::SoundHandle _hSampleFX[MAX_FX];
|
||||
Audio::SoundHandle _hSampleSpeech;
|
||||
Audio::SoundHandle _hSampleMusic[MAX_MUSIC];
|
||||
|
||||
// Music stream information
|
||||
bool _musicStreamPlaying[MAX_MUSIC] = { false, false };
|
||||
bool _streamLoopingFlag[MAX_MUSIC] = { false, false };
|
||||
int32 _musicStreamFading[MAX_MUSIC] = { 0, 0 };
|
||||
MusCompMode _musicStreamFormat[MAX_MUSIC] = { MusWav, MusWav };
|
||||
Audio::QueuingAudioStream *_musicOutputStream[MAX_MUSIC] = { nullptr, nullptr };
|
||||
Audio::RewindableAudioStream *_compressedMusicStream[MAX_MUSIC] = { nullptr, nullptr };
|
||||
Common::File _musicFile[MAX_MUSIC];
|
||||
|
||||
// Sound FX information
|
||||
int32 _fxSampleId[MAX_FX] = { 0, 0, 0, 0 };
|
||||
|
||||
// Pause variables
|
||||
bool _speechPaused = false;
|
||||
bool _fxPaused[MAX_FX] = { false, false, false, false };
|
||||
bool _musicPaused[MAX_MUSIC] = { false, false };
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif // SOUND_H
|
||||
7150
engines/sword1/staticres.cpp
Normal file
7150
engines/sword1/staticres.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1255
engines/sword1/sword1.cpp
Normal file
1255
engines/sword1/sword1.cpp
Normal file
File diff suppressed because it is too large
Load Diff
204
engines/sword1/sword1.h
Normal file
204
engines/sword1/sword1.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/* 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 SWORD1_SWORD1_H
|
||||
#define SWORD1_SWORD1_H
|
||||
|
||||
#include "engines/engine.h"
|
||||
#include "common/error.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/util.h"
|
||||
#include "common/events.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "sword1/console.h"
|
||||
|
||||
struct ADGameDescription;
|
||||
|
||||
/**
|
||||
* This is the namespace of the Sword1 engine.
|
||||
*
|
||||
* Status of this engine: ???
|
||||
*
|
||||
* Games using this engine:
|
||||
* - Broken Sword: The Shadow of the Templars
|
||||
*/
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
enum SWORD1Action {
|
||||
kActionNone,
|
||||
kActionPause,
|
||||
kActionQuit,
|
||||
kActionMainPanel,
|
||||
kActionEscape
|
||||
};
|
||||
|
||||
enum ControlPanelMode {
|
||||
CP_NORMAL = 0,
|
||||
CP_DEATHSCREEN,
|
||||
CP_THEEND,
|
||||
CP_NEWGAME
|
||||
};
|
||||
|
||||
class Screen;
|
||||
class Sound;
|
||||
class Logic;
|
||||
class Mouse;
|
||||
class ResMan;
|
||||
class ObjectMan;
|
||||
class Menu;
|
||||
class Control;
|
||||
|
||||
struct SystemVars {
|
||||
bool runningFromCd;
|
||||
uint32 currentCD; // starts at zero, then either 1 or 2 depending on section being played
|
||||
uint32 justRestoredGame; // see main() in sword.c & New_screen() in gtm_core.c
|
||||
uint8 controlPanelMode; // 1 death screen version of the control panel, 2 = successful end of game, 3 = force restart
|
||||
uint8 saveGameFlag;
|
||||
int snrStatus;
|
||||
bool wantFade; // when true => fade during scene change, else cut.
|
||||
bool playSpeech;
|
||||
bool textRunning;
|
||||
uint32 speechRunning;
|
||||
bool speechFinished;
|
||||
bool showText;
|
||||
int32 textNumber;
|
||||
uint8 language;
|
||||
bool isDemo;
|
||||
bool isSpanishDemo;
|
||||
Common::Platform platform;
|
||||
Common::Language realLanguage;
|
||||
bool isLangRtl;
|
||||
bool debugMode;
|
||||
bool slowMode;
|
||||
bool fastMode;
|
||||
bool parallaxOn;
|
||||
bool gamePaused;
|
||||
bool displayDebugText;
|
||||
bool displayDebugMouse;
|
||||
bool displayDebugGrid;
|
||||
uint32 framesPerSecondCounter;
|
||||
uint32 gameCycle;
|
||||
bool useWindowsAudioMode; // DOS and Windows use different implementations of the audio driver, each with their own behavior
|
||||
};
|
||||
|
||||
class SwordEngine : public Engine {
|
||||
friend class SwordConsole;
|
||||
friend class Screen;
|
||||
friend class Control;
|
||||
|
||||
public:
|
||||
SwordEngine(OSystem *syst, const ADGameDescription *gameDesc);
|
||||
~SwordEngine() override;
|
||||
static SystemVars _systemVars;
|
||||
void reinitialize();
|
||||
|
||||
uint32 _features;
|
||||
|
||||
int _inTimer = -1; // Is the timer running?
|
||||
int32 _vbl60HzUSecElapsed = 0; // 60 Hz counter for palette fades
|
||||
int _vblCount = 0; // How many vblCallback calls have been made?
|
||||
int _rate = DEFAULT_FRAME_TIME / 10;
|
||||
int _targetFrameTime = DEFAULT_FRAME_TIME;
|
||||
uint32 _mainLoopFrameCount = 0;
|
||||
uint32 _ticker = 0; // For the frame time shown within the debug text
|
||||
|
||||
bool mouseIsActive();
|
||||
|
||||
static bool isMac() { return _systemVars.platform == Common::kPlatformMacintosh; }
|
||||
static bool isPsx() { return _systemVars.platform == Common::kPlatformPSX; }
|
||||
static bool isWindows() { return _systemVars.platform == Common::kPlatformWindows ; }
|
||||
|
||||
// Used by timer
|
||||
void updateTopMenu();
|
||||
void updateBottomMenu();
|
||||
void fadePaletteStep();
|
||||
void startFadePaletteDown(int speed);
|
||||
void startFadePaletteUp(int speed);
|
||||
void waitForFade();
|
||||
bool screenIsFading();
|
||||
bool fadeDirectionIsUp();
|
||||
void setMenuToTargetState();
|
||||
|
||||
void showDebugInfo();
|
||||
|
||||
protected:
|
||||
// Engine APIs
|
||||
Common::Error init();
|
||||
Common::Error go();
|
||||
Common::Error run() override {
|
||||
Common::Error err;
|
||||
err = init();
|
||||
if (err.getCode() != Common::kNoError)
|
||||
return err;
|
||||
return go();
|
||||
}
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
void syncSoundSettings() override;
|
||||
|
||||
Common::Error loadGameState(int slot) override;
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
Common::String getSaveStateName(int slot) const override {
|
||||
return Common::String::format("sword1.%03d", slot);
|
||||
}
|
||||
private:
|
||||
void pollInput(uint32 delay);
|
||||
void checkKeys();
|
||||
|
||||
void checkCdFiles();
|
||||
void checkCd();
|
||||
void askForCd();
|
||||
|
||||
void showFileErrorMsg(uint8 type, bool *fileExists);
|
||||
void flagsToBool(bool *dest, uint8 flags);
|
||||
|
||||
void reinitRes(); //Reinits the resources after a GMM load
|
||||
|
||||
void installTimerRoutines();
|
||||
void uninstallTimerRoutines();
|
||||
|
||||
uint8 mainLoop();
|
||||
|
||||
Common::Point _mouseCoord;
|
||||
uint16 _mouseState;
|
||||
Common::KeyState _keyPressed;
|
||||
Common::CustomEventType _customType;
|
||||
|
||||
ResMan *_resMan;
|
||||
ObjectMan *_objectMan;
|
||||
Screen *_screen;
|
||||
Mouse *_mouse;
|
||||
Logic *_logic;
|
||||
Sound *_sound;
|
||||
Menu *_menu;
|
||||
Control *_control;
|
||||
static const uint8 _cdList[TOTAL_SECTIONS];
|
||||
static const CdFile _pcCdFileList[];
|
||||
static const CdFile _macCdFileList[];
|
||||
static const CdFile _psxCdFileList[];
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif // SWORD1_SWORD1_H
|
||||
1615
engines/sword1/sworddefs.h
Normal file
1615
engines/sword1/sworddefs.h
Normal file
File diff suppressed because it is too large
Load Diff
5224
engines/sword1/swordres.h
Normal file
5224
engines/sword1/swordres.h
Normal file
File diff suppressed because it is too large
Load Diff
360
engines/sword1/text.cpp
Normal file
360
engines/sword1/text.cpp
Normal file
@@ -0,0 +1,360 @@
|
||||
/* 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/str.h"
|
||||
#include "common/unicode-bidi.h"
|
||||
|
||||
#include "sword1/logic.h"
|
||||
#include "sword1/text.h"
|
||||
#include "sword1/resman.h"
|
||||
#include "sword1/objectman.h"
|
||||
#include "sword1/swordres.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
#include "sword1/screen.h"
|
||||
#include "sword1/sword1.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#define OVERLAP 3
|
||||
#define DEMO_OVERLAP 1
|
||||
#define DEBUG_OVERLAP 2
|
||||
#define SPACE ' '
|
||||
#define MAX_LINES 30
|
||||
|
||||
|
||||
Text::Text(SwordEngine *vm, Logic *pLogic, ObjectMan *pObjMan, ResMan *pResMan, Screen *pScreen, bool czechVersion) {
|
||||
_vm = vm;
|
||||
_logic = pLogic;
|
||||
_objMan = pObjMan;
|
||||
_resMan = pResMan;
|
||||
_screen = pScreen;
|
||||
_textCount = 0;
|
||||
_fontId = (czechVersion) ? CZECH_GAME_FONT : GAME_FONT;
|
||||
_font = (uint8 *)_resMan->openFetchRes(_fontId);
|
||||
|
||||
_joinWidth = charWidth(SPACE);
|
||||
|
||||
if (!SwordEngine::_systemVars.isDemo) {
|
||||
_joinWidth -= 2 * OVERLAP;
|
||||
} else {
|
||||
_joinWidth -= 2 * DEMO_OVERLAP;
|
||||
}
|
||||
|
||||
_charHeight = _resMan->getUint16(_resMan->fetchFrame(_font, 0)->height); // all chars have the same height
|
||||
|
||||
if (SwordEngine::isPsx())
|
||||
_charHeight /= 2;
|
||||
|
||||
for (int i = 0; i < MAX_TEXT_OBS; i++)
|
||||
_textBlocks[i] = NULL;
|
||||
}
|
||||
|
||||
Text::~Text() {
|
||||
for (int i = 0; i < MAX_TEXT_OBS; i++)
|
||||
free(_textBlocks[i]);
|
||||
//_resMan->resClose(_fontId); => wiped automatically by _resMan->flush();
|
||||
}
|
||||
|
||||
uint32 Text::lowTextManager(uint8 *ascii, int32 width, uint8 pen) {
|
||||
_textCount++;
|
||||
if (_textCount > MAX_TEXT_OBS)
|
||||
error("Text::lowTextManager: MAX_TEXT_OBS exceeded");
|
||||
uint32 textObjId = (TEXT_sect * ITM_PER_SEC) - 1;
|
||||
do {
|
||||
textObjId++;
|
||||
} while (_objMan->fetchObject(textObjId)->o_status);
|
||||
// okay, found a free text object
|
||||
|
||||
_objMan->fetchObject(textObjId)->o_status = STAT_FORE;
|
||||
makeTextSprite((uint8)textObjId, ascii, (uint16)width, pen);
|
||||
|
||||
return textObjId;
|
||||
}
|
||||
|
||||
void Text::makeTextSprite(uint8 slot, const uint8 *text, uint16 maxWidth, uint8 pen) {
|
||||
LineInfo lines[MAX_LINES];
|
||||
uint16 numLines = analyzeSentence(text, maxWidth, lines);
|
||||
|
||||
uint16 sprWidth = 0;
|
||||
uint16 lineCnt;
|
||||
for (lineCnt = 0; lineCnt < numLines; lineCnt++)
|
||||
if (lines[lineCnt].width > sprWidth)
|
||||
sprWidth = lines[lineCnt].width;
|
||||
|
||||
uint16 sprHeight = _charHeight * numLines;
|
||||
if (SwordEngine::isPsx()) {
|
||||
sprHeight = 2 * _charHeight * numLines - 4 * (numLines - 1);
|
||||
sprWidth = (sprWidth + 1) & 0xFFFE;
|
||||
}
|
||||
|
||||
uint32 sprSize = sprWidth * sprHeight;
|
||||
assert(!_textBlocks[slot]); // if this triggers, the speechDriver failed to call Text::releaseText.
|
||||
_textBlocks[slot] = (FrameHeader *)malloc(sprSize + sizeof(FrameHeader));
|
||||
|
||||
memcpy(_textBlocks[slot]->runTimeComp, "Nu ", 4);
|
||||
_textBlocks[slot]->compSize = 0;
|
||||
_textBlocks[slot]->width = _resMan->toUint16(sprWidth);
|
||||
_textBlocks[slot]->height = _resMan->toUint16(sprHeight);
|
||||
_textBlocks[slot]->offsetX = 0;
|
||||
_textBlocks[slot]->offsetY = 0;
|
||||
|
||||
uint8 *linePtr = ((uint8 *)_textBlocks[slot]) + sizeof(FrameHeader);
|
||||
memset(linePtr, NO_COL, sprSize);
|
||||
for (lineCnt = 0; lineCnt < numLines; lineCnt++) {
|
||||
uint8 *sprPtr = linePtr + (sprWidth - lines[lineCnt].width) / 2; // center the text
|
||||
Common::String textString;
|
||||
const uint8 *curTextLine = text;
|
||||
if (SwordEngine::_systemVars.isLangRtl) {
|
||||
Common::String textLogical = Common::String((const char *)text, (uint32)lines[lineCnt].length);
|
||||
textString = Common::convertBiDiString(textLogical, Common::kWindows1255);
|
||||
curTextLine = (const uint8 *)textString.c_str();
|
||||
}
|
||||
for (uint16 pos = 0; pos < lines[lineCnt].length; pos++) {
|
||||
if (isKoreanChar(*curTextLine, *(curTextLine + 1))) {
|
||||
sprPtr += copyWChar(*curTextLine, *(curTextLine + 1), sprPtr, sprWidth, pen) - OVERLAP;
|
||||
curTextLine += 2;
|
||||
pos++;
|
||||
} else {
|
||||
sprPtr += copyChar(*curTextLine++, sprPtr, sprWidth, pen);
|
||||
|
||||
if (!SwordEngine::_systemVars.isDemo) {
|
||||
sprPtr -= OVERLAP;
|
||||
} else {
|
||||
sprPtr -= DEMO_OVERLAP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
curTextLine++; // skip space at the end of the line
|
||||
text += lines[lineCnt].length + 1;
|
||||
|
||||
if (SwordEngine::isPsx())
|
||||
linePtr += (_charHeight - 4) * sprWidth;
|
||||
else
|
||||
linePtr += _charHeight * sprWidth;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 Text::charWidth(uint8 ch) {
|
||||
if (ch < SPACE)
|
||||
ch = 64;
|
||||
return _resMan->getUint16(_resMan->fetchFrame(_font, ch - SPACE)->width);
|
||||
}
|
||||
|
||||
uint16 Text::analyzeSentence(const uint8 *text, uint16 maxWidth, LineInfo *line) {
|
||||
uint16 lineNo = 0;
|
||||
bool firstWord = true;
|
||||
|
||||
if (SwordEngine::isPsx())
|
||||
maxWidth = 254;
|
||||
|
||||
while (*text) {
|
||||
uint16 wordWidth = 0;
|
||||
uint16 wordLength = 0;
|
||||
|
||||
while ((*text != SPACE) && *text) {
|
||||
if (isKoreanChar(*text, *(text + 1))) {
|
||||
wordWidth += wCharWidth(*text, *(text + 1)) - OVERLAP;
|
||||
wordLength += 2;
|
||||
text += 2;
|
||||
} else {
|
||||
wordWidth += charWidth(*text);
|
||||
|
||||
if (!SwordEngine::_systemVars.isDemo) {
|
||||
wordWidth -= OVERLAP;
|
||||
} else {
|
||||
wordWidth -= DEMO_OVERLAP;
|
||||
}
|
||||
|
||||
wordLength++;
|
||||
text++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*text == SPACE)
|
||||
text++;
|
||||
|
||||
// no overlap on final letter of word!
|
||||
if (!SwordEngine::_systemVars.isDemo) {
|
||||
wordWidth += OVERLAP;
|
||||
} else {
|
||||
wordWidth += DEMO_OVERLAP;
|
||||
}
|
||||
|
||||
if (firstWord) { // first word on first line, so no separating SPACE needed
|
||||
line[0].width = wordWidth;
|
||||
line[0].length = wordLength;
|
||||
firstWord = false;
|
||||
} else {
|
||||
// see how much extra space this word will need to fit on current line
|
||||
// (with a separating space character - also overlapped)
|
||||
uint16 spaceNeeded = _joinWidth + wordWidth;
|
||||
|
||||
if (line[lineNo].width + spaceNeeded <= maxWidth) {
|
||||
line[lineNo].width += spaceNeeded;
|
||||
line[lineNo].length += 1 + wordLength; // NB. space+word characters
|
||||
} else { // put word (without separating SPACE) at start of next line
|
||||
lineNo++;
|
||||
assert(lineNo < MAX_LINES);
|
||||
line[lineNo].width = wordWidth;
|
||||
line[lineNo].length = wordLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lineNo + 1; // return no of lines
|
||||
}
|
||||
|
||||
uint16 Text::copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen) {
|
||||
if (ch < SPACE)
|
||||
ch = 64;
|
||||
FrameHeader *chFrame = _resMan->fetchFrame(_font, ch - SPACE);
|
||||
uint8 *chData = ((uint8 *)chFrame) + sizeof(FrameHeader);
|
||||
uint8 *dest = sprPtr;
|
||||
uint8 *decBuf = NULL;
|
||||
uint8 *decChr;
|
||||
uint16 frameHeight = 0;
|
||||
|
||||
if (SwordEngine::isPsx()) {
|
||||
frameHeight = _resMan->getUint16(chFrame->height) / 2;
|
||||
if (_fontId == CZECH_GAME_FONT) { //Czech game fonts are compressed
|
||||
decBuf = (uint8 *)malloc((_resMan->getUint16(chFrame->width)) * (_resMan->getUint16(chFrame->height) / 2));
|
||||
Screen::decompressHIF(chData, decBuf);
|
||||
decChr = decBuf;
|
||||
} else //Normal game fonts are not compressed
|
||||
decChr = chData;
|
||||
} else {
|
||||
frameHeight = _resMan->getUint16(chFrame->height);
|
||||
decChr = chData;
|
||||
}
|
||||
|
||||
for (uint16 cnty = 0; cnty < frameHeight; cnty++) {
|
||||
for (uint16 cntx = 0; cntx < _resMan->getUint16(chFrame->width); cntx++) {
|
||||
if (*decChr == LETTER_COL)
|
||||
dest[cntx] = pen;
|
||||
else if (((*decChr == BORDER_COL) || (*decChr == BORDER_COL_PSX)) && (!dest[cntx])) // don't do a border if there's already a color underneath (chars can overlap)
|
||||
dest[cntx] = BORDER_COL;
|
||||
decChr++;
|
||||
}
|
||||
dest += sprWidth;
|
||||
}
|
||||
free(decBuf);
|
||||
return _resMan->getUint16(chFrame->width);
|
||||
}
|
||||
|
||||
FrameHeader *Text::giveSpriteData(uint32 textTarget) {
|
||||
// textTarget is the resource ID of the Compact linking the textdata.
|
||||
// that's 0x950000 for slot 0 and 0x950001 for slot 1. easy, huh? :)
|
||||
textTarget &= ITM_ID;
|
||||
assert(textTarget < MAX_TEXT_OBS);
|
||||
|
||||
return _textBlocks[textTarget];
|
||||
}
|
||||
|
||||
void Text::releaseText(uint32 id, bool updateCount) {
|
||||
id &= ITM_ID;
|
||||
assert(id < MAX_TEXT_OBS);
|
||||
if (_textBlocks[id]) {
|
||||
free(_textBlocks[id]);
|
||||
_textBlocks[id] = NULL;
|
||||
if (updateCount)
|
||||
_textCount--;
|
||||
}
|
||||
}
|
||||
|
||||
void Text::printDebugLine(uint8 *ascii, uint8 first, int x, int y) {
|
||||
FrameHeader *head;
|
||||
int chr;
|
||||
|
||||
do {
|
||||
chr = (int)*(ascii);
|
||||
chr -= first;
|
||||
|
||||
head = (FrameHeader *)_resMan->fetchFrame(_font, chr);
|
||||
|
||||
uint8 *sprData = (uint8 *)head + sizeof(FrameHeader);
|
||||
|
||||
// The original drawSprite routine also clipped the sprite, so
|
||||
// let's do that as well in order to produce an accurate result...
|
||||
uint16 newCoordsX = x;
|
||||
uint16 newCoordsY = y;
|
||||
uint16 newWidth = _resMan->getUint16(head->width);
|
||||
uint16 newHeight = SwordEngine::isPsx() ?
|
||||
_resMan->getUint16(head->height) / 2 : _resMan->getUint16(head->height);
|
||||
uint16 incr;
|
||||
_screen->spriteClipAndSet(&newCoordsX, &newCoordsY, &newWidth, &newHeight, &incr);
|
||||
_screen->drawSprite(sprData + incr, newCoordsX, newCoordsY, newWidth, newHeight, newWidth);
|
||||
|
||||
x += _resMan->getUint16(head->width);
|
||||
|
||||
if (SwordEngine::isPsx()) {
|
||||
x -= OVERLAP;
|
||||
} else {
|
||||
// The very first executable version didn't use any overlap (verified on UK disasm)
|
||||
if (SwordEngine::_systemVars.realLanguage != Common::EN_ANY)
|
||||
x -= DEBUG_OVERLAP;
|
||||
}
|
||||
|
||||
ascii++;
|
||||
} while (*ascii);
|
||||
}
|
||||
|
||||
uint16 Text::wCharWidth(uint8 hi, uint8 lo) {
|
||||
if (isKoreanChar(hi, lo)) {
|
||||
return 20; // fixed width : 20
|
||||
}
|
||||
return charWidth(hi) + charWidth(lo);
|
||||
}
|
||||
|
||||
uint16 Text::copyWChar(uint8 hi, uint8 lo, uint8 *sprPtr, uint16 sprWidth, uint8 pen) {
|
||||
if (!isKoreanChar(hi, lo)) {
|
||||
return copyChar(hi, sprPtr, sprWidth, pen) + copyChar(lo, sprPtr, sprWidth, pen);
|
||||
}
|
||||
|
||||
uint16 frameWidth = 20;
|
||||
uint16 frameHeight = 26;
|
||||
FrameHeader *chFrame = _resMan->fetchFrame(_font, 0xFF - SPACE);
|
||||
uint8 *dest = sprPtr;
|
||||
uint8 *decChr = ((uint8 *)chFrame) + sizeof(FrameHeader) + chFrame->width * chFrame->height + ((hi - 0xB0) * 94 + (lo - 0xA1)) * frameWidth * frameHeight;
|
||||
|
||||
for (uint16 cnty = 0; cnty < frameHeight; cnty++) {
|
||||
for (uint16 cntx = 0; cntx < frameWidth; cntx++) {
|
||||
if (*decChr == LETTER_COL)
|
||||
dest[cntx] = pen;
|
||||
else if (((*decChr == BORDER_COL) || (*decChr == BORDER_COL_PSX)) && (!dest[cntx])) // don't do a border if there's already a color underneath (chars can overlap)
|
||||
dest[cntx] = BORDER_COL;
|
||||
decChr++;
|
||||
}
|
||||
dest += sprWidth;
|
||||
}
|
||||
return frameWidth;
|
||||
}
|
||||
|
||||
bool Text::isKoreanChar(uint8 hi, uint8 lo) {
|
||||
if (SwordEngine::_systemVars.realLanguage != Common::KO_KOR)
|
||||
return false;
|
||||
if (hi >= 0xB0 && hi <= 0xC8 && lo >= 0xA1 && lo <= 0xFE)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Sword1
|
||||
80
engines/sword1/text.h
Normal file
80
engines/sword1/text.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* 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 SWORD1_TEXT_H
|
||||
#define SWORD1_TEXT_H
|
||||
|
||||
#include "sword1/object.h"
|
||||
#include "sword1/sworddefs.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
#define MAX_TEXT_OBS 3
|
||||
|
||||
#define BORDER_COL 200
|
||||
#define BORDER_COL_PSX 199
|
||||
#define LETTER_COL 193
|
||||
#define NO_COL 0 // sprite background - 0 for transparency
|
||||
|
||||
class ObjectMan;
|
||||
class ResMan;
|
||||
class Screen;
|
||||
class Logic;
|
||||
class SwordEngine;
|
||||
|
||||
struct LineInfo {
|
||||
uint16 width; // width of line in pixels
|
||||
uint16 length; // length of line in characters
|
||||
};
|
||||
|
||||
class Text {
|
||||
public:
|
||||
Text(SwordEngine *vm, Logic *pLogic, ObjectMan *pObjMan, ResMan *pResMan, Screen *pScreen, bool czechVersion);
|
||||
~Text();
|
||||
FrameHeader *giveSpriteData(uint32 textTarget);
|
||||
uint32 lowTextManager(uint8 *text, int32 width, uint8 pen);
|
||||
void makeTextSprite(uint8 slot, const uint8 *text, uint16 maxWidth, uint8 pen);
|
||||
void releaseText(uint32 id, bool updateCount = true);
|
||||
void printDebugLine(uint8 *ascii, uint8 first, int x, int y);
|
||||
|
||||
private:
|
||||
uint16 analyzeSentence(const uint8 *text, uint16 maxWidth, LineInfo *info);
|
||||
uint16 charWidth(uint8 ch);
|
||||
uint16 wCharWidth(uint8 hi, uint8 lo);
|
||||
uint16 copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen);
|
||||
uint16 copyWChar(uint8 hi, uint8 lo, uint8 *sprPtr, uint16 sprWidth, uint8 pen);
|
||||
bool isKoreanChar(uint8 hi, uint8 lo);
|
||||
|
||||
uint8 *_font;
|
||||
uint8 _textCount;
|
||||
uint16 _charHeight, _joinWidth;
|
||||
SwordEngine *_vm;
|
||||
Logic *_logic;
|
||||
ObjectMan *_objMan;
|
||||
ResMan *_resMan;
|
||||
Screen *_screen;
|
||||
FrameHeader *_textBlocks[MAX_TEXT_OBS];
|
||||
uint32 _fontId;
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif //BSTEXT_H
|
||||
Reference in New Issue
Block a user