Initial commit

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

View File

@@ -0,0 +1,3 @@
engines/dreamweb/metaengine.cpp
engines/dreamweb/saveload.cpp

View File

@@ -0,0 +1,285 @@
/* 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 "dreamweb/dreamweb.h"
namespace DreamWeb {
void DreamWebEngine::doBlocks() {
uint16 dstOffset = _mapAdY * kScreenwidth + _mapAdX;
uint16 mapOffset = _mapY * kMapWidth + _mapX;
const uint8 *mapData = _mapData + mapOffset;
uint8 *dstBuffer = workspace() + dstOffset;
for (uint i = 0; i < 10; ++i) {
for (uint j = 0; j < 11; ++j) {
uint16 blockType = mapData[j];
if (blockType != 0) {
uint8 *dst = dstBuffer + i * kScreenwidth * 16 + j * 16;
const uint8 *block = _backdropBlocks + blockType * 256;
for (uint k = 0; k < 4; ++k) {
memcpy(dst, block, 16);
block += 16;
dst += kScreenwidth;
}
for (uint k = 0; k < 12; ++k) {
memcpy(dst, block, 16);
memset(dst + 16, 0xdf, 4);
block += 16;
dst += kScreenwidth;
}
dst += 4;
memset(dst, 0xdf, 16);
dst += kScreenwidth;
memset(dst, 0xdf, 16);
dst += kScreenwidth;
memset(dst, 0xdf, 16);
dst += kScreenwidth;
memset(dst, 0xdf, 16);
}
}
mapData += kMapWidth;
}
}
uint8 DreamWebEngine::getXAd(const uint8 *setData, uint8 *result) {
uint8 v0 = setData[0];
uint8 v1 = setData[1];
uint8 v2 = setData[2];
if (v0 != 0)
return 0;
if (v1 < _mapX)
return 0;
v1 -= _mapX;
if (v1 >= 11)
return 0;
*result = (v1 << 4) | v2;
return 1;
}
uint8 DreamWebEngine::getYAd(const uint8 *setData, uint8 *result) {
uint8 v0 = setData[3];
uint8 v1 = setData[4];
if (v0 < _mapY)
return 0;
v0 -= _mapY;
if (v0 >= 10)
return 0;
*result = (v0 << 4) | v1;
return 1;
}
uint8 DreamWebEngine::getMapAd(const uint8 *setData, uint16 *x, uint16 *y) {
uint8 xad, yad;
if (getXAd(setData, &xad) == 0)
return 0;
*x = xad;
if (getYAd(setData, &yad) == 0)
return 0;
*y = yad;
return 1;
}
void DreamWebEngine::calcFrFrame(const Frame &frame, uint8 *width, uint8 *height, uint16 x, uint16 y, ObjPos *objPos) {
*width = frame.width;
*height = frame.height;
objPos->xMin = (x + frame.x) & 0xff;
objPos->yMin = (y + frame.y) & 0xff;
objPos->xMax = objPos->xMin + frame.width;
objPos->yMax = objPos->yMin + frame.height;
}
void DreamWebEngine::makeBackOb(SetObject *objData, uint16 x, uint16 y) {
if (_vars._newObs == 0)
return;
uint8 priority = objData->priority;
uint8 type = objData->type;
Sprite *sprite = makeSprite(x, y, false, &_setFrames);
sprite->_objData = objData;
if (priority == 255)
priority = 0;
sprite->priority = priority;
sprite->type = type;
sprite->delay = 0;
sprite->animFrame = 0;
}
void DreamWebEngine::showAllObs() {
_setList.clear();
const GraphicsFile &frameBase = _setFrames;
for (uint i = 0; i < 128; ++i) {
SetObject *setEntry = &_setDat[i];
uint16 x, y;
if (getMapAd(setEntry->mapad, &x, &y) == 0)
continue;
uint8 currentFrame = setEntry->frames[0];
if (currentFrame == 0xff)
continue;
uint8 width, height;
ObjPos objPos;
calcFrFrame(frameBase._frames[currentFrame], &width, &height, x, y, &objPos);
setEntry->index = setEntry->frames[0];
if ((setEntry->type == 0) && (setEntry->priority != 5) && (setEntry->priority != 6)) {
x += _mapAdX;
y += _mapAdY;
showFrame(frameBase, x, y, currentFrame, 0);
} else
makeBackOb(setEntry, x, y);
objPos.index = i;
_setList.push_back(objPos);
}
}
static bool addAlong(const MapFlag *mapFlags) {
for (uint i = 0; i < 11; ++i) {
if (mapFlags[i]._flag != 0)
return true;
}
return false;
}
static bool addLength(const MapFlag *mapFlags) {
for (uint i = 0; i < 10; ++i) {
if (mapFlags[11 * i]._flag != 0)
return true;
}
return false;
}
void DreamWebEngine::getDimension(uint8 *mapXstart, uint8 *mapYstart, uint8 *mapXsize, uint8 *mapYsize) {
uint8 yStart = 0;
while (! addAlong(_mapFlags + 11 * yStart))
++yStart;
uint8 xStart = 0;
while (! addLength(_mapFlags + xStart))
++xStart;
uint8 yEnd = 10;
while (! addAlong(_mapFlags + 11 * (yEnd - 1)))
--yEnd;
uint8 xEnd = 11;
while (! addLength(_mapFlags + (xEnd - 1)))
--xEnd;
*mapXstart = xStart;
*mapYstart = yStart;
*mapXsize = xEnd - xStart;
*mapYsize = yEnd - yStart;
_mapXStart = xStart << 4;
_mapYStart = yStart << 4;
_mapXSize = *mapXsize << 4;
_mapYSize = *mapYsize << 4;
}
void DreamWebEngine::calcMapAd() {
uint8 mapXstart, mapYstart;
uint8 mapXsize, mapYsize;
getDimension(&mapXstart, &mapYstart, &mapXsize, &mapYsize);
_mapAdX = _mapOffsetX - 8 * (mapXsize + 2 * mapXstart - 11);
_mapAdY = _mapOffsetY - 8 * (mapYsize + 2 * mapYstart - 10);
}
void DreamWebEngine::showAllFree() {
const uint count = 80;
_freeList.clear();
const DynObject *freeObjects = _freeDat;
const GraphicsFile &frameBase = _freeFrames;
for (uint i = 0; i < count; ++i) {
uint16 x, y;
uint8 mapAd = getMapAd(freeObjects[i].mapad, &x, &y);
if (mapAd != 0) {
uint8 width, height;
ObjPos objPos;
uint16 currentFrame = 3 * i;
calcFrFrame(frameBase._frames[currentFrame], &width, &height, x, y, &objPos);
if ((width != 0) || (height != 0)) {
x += _mapAdX;
y += _mapAdY;
assert(currentFrame < 256);
showFrame(frameBase, x, y, currentFrame, 0);
objPos.index = i;
_freeList.push_back(objPos);
}
}
}
}
void DreamWebEngine::drawFlags() {
MapFlag *mapFlag = _mapFlags;
uint16 mapOffset = _mapY * kMapWidth + _mapX;
const uint8 *mapData = _mapData + mapOffset;
for (uint i = 0; i < 10; ++i) {
for (uint j = 0; j < 11; ++j) {
uint8 tile = mapData[i * kMapWidth + j];
mapFlag->_flag = _backdropFlags[tile]._flag;
mapFlag->_flagEx = _backdropFlags[tile]._flagEx;
mapFlag->_type = tile;
mapFlag++;
}
}
}
void DreamWebEngine::showAllEx() {
const uint count = 100;
_exList.clear();
DynObject *objects = _exData;
const GraphicsFile &frameBase = _exFrames;
for (uint i = 0; i < count; ++i) {
DynObject *object = objects + i;
if (object->mapad[0] == 0xff)
continue;
if (object->currentLocation != _realLocation)
continue;
uint16 x, y;
if (getMapAd(object->mapad, &x, &y) == 0)
continue;
uint8 width, height;
ObjPos objPos;
uint16 currentFrame = 3 * i;
calcFrFrame(frameBase._frames[currentFrame], &width, &height, x, y, &objPos);
if ((width != 0) || (height != 0)) {
// FIXME: this was an assert() that failed during normal gameplay.
// Now it's a warning, because it's unclear if the check is valid.
// It could have been a copy/paste mistake from showAllFree,
// where there are fewer iterations. See bugs: #15420, #15436
if (currentFrame >= 256) {
warning("showing extra frame %d >= 256", currentFrame);
}
showFrame(frameBase, x + _mapAdX, y + _mapAdY, currentFrame, 0);
objPos.index = i;
_exList.push_back(objPos);
}
}
}
} // End of namespace DreamWeb

View File

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

View File

@@ -0,0 +1,33 @@
/* 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 "dreamweb/console.h"
namespace DreamWeb {
DreamWebConsole::DreamWebConsole(DreamWebEngine *vm) : GUI::Debugger(), _vm(vm) {
assert(_vm);
}
DreamWebConsole::~DreamWebConsole() {
}
} // End of namespace DreamWeb

View File

@@ -0,0 +1,42 @@
/* 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 DREAMWEB_CONSOLE_H
#define DREAMWEB_CONSOLE_H
#include "gui/debugger.h"
namespace DreamWeb {
class DreamWebEngine;
class DreamWebConsole : public GUI::Debugger {
public:
DreamWebConsole(DreamWebEngine *vm);
~DreamWebConsole(void) override;
private:
DreamWebEngine *_vm;
};
} // End of namespace DreamWeb
#endif

View File

@@ -0,0 +1,7 @@
begin_section("DreamWeb");
add_person("Torbj&ouml;rn Andersson", "eriktorbjorn", "");
add_person("Bertrand Augereau", "Tramb", "");
add_person("Filippos Karapetis", "bluegr", "");
add_person("Vladimir Menshakov", "whoozle", "");
add_person("Willem Jan Palenstijn", "wjp", "");
end_section();

View File

@@ -0,0 +1,71 @@
/* 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/algorithm.h"
#include "common/system.h"
#include "common/text-to-speech.h"
#include "engines/advancedDetector.h"
#include "dreamweb/detection.h"
#include "dreamweb/dreamweb.h"
static const PlainGameDescriptor dreamWebGames[] = {
{ "dreamweb", "DreamWeb" },
{ nullptr, nullptr }
};
static const DebugChannelDef debugFlagList[] = {
{DreamWeb::kDebugAnimation, "Animation", "Animation Debug Flag"},
{DreamWeb::kDebugSaveLoad, "SaveLoad", "Track Save/Load Function"},
DEBUG_CHANNEL_END
};
#include "dreamweb/detection_tables.h"
class DreamWebMetaEngineDetection : public AdvancedMetaEngineDetection<DreamWeb::DreamWebGameDescription> {
public:
DreamWebMetaEngineDetection():
AdvancedMetaEngineDetection(DreamWeb::gameDescriptions,
dreamWebGames) {
_guiOptions = GUIO5(GUIO_NOMIDI, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE, GAMEOPTION_TTS_THINGS, GAMEOPTION_TTS_SPEECH);
}
const char *getName() const override {
return "dreamweb";
}
const char *getEngineName() const override {
return "DreamWeb";
}
const char *getOriginalCopyright() const override {
return "DreamWeb (C) Creative Reality";
}
const DebugChannelDef *getDebugChannels() const override {
return debugFlagList;
}
};
REGISTER_PLUGIN_STATIC(DREAMWEB_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, DreamWebMetaEngineDetection);

View File

@@ -0,0 +1,43 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef DREAMWEB_DETECTION_H
#define DREAMWEB_DETECTION_H
namespace DreamWeb {
struct DreamWebGameDescription {
AD_GAME_DESCRIPTION_HELPERS(desc);
ADGameDescription desc;
};
#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
#define GAMEOPTION_BRIGHTPALETTE GUIO_GAMEOPTIONS2
#define GAMEOPTION_TTS_THINGS GUIO_GAMEOPTIONS3
#define GAMEOPTION_TTS_SPEECH GUIO_GAMEOPTIONS4
#define GAMEOPTION_COPY_PROTECTION GUIO_GAMEOPTIONS5
#define GF_INSTALLER 1
} // End of namespace DreamWeb
#endif // DREAMWEB_DETECTION_H

View File

@@ -0,0 +1,346 @@
/* 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 DREAMWEB_DETECTION_TABLES_H
#define DREAMWEB_DETECTION_TABLES_H
#include "dreamweb/detection.h"
namespace DreamWeb {
static const DreamWebGameDescription gameDescriptions[] = {
// International floppy release
{
{
"dreamweb",
"Installer",
{
{"dreamw_1.rnc", 0, "4b8a92191219cc7e84d50837e1acca93", 1400000},
{"dreamw_2.rnc", 0, "603e053b763c54c13a1e5e28be2ea839", 1457664},
{"dreamw_3.rnc", 0, "1b273aa05a6afb8e7cd3c2defe2e334f", 1457664},
{"dreamw_4.rnc", 0, "f7bc7a8e1147d7379272c6dbfb5e7246", 1457664},
{"dreamw_5.rnc", 0, "0349950d94fee72b8fd57a22f7c465d1", 1457664},
{"dreamw_6.rnc", 0, "c99629c842967e5e41e1c298cb58274f", 662246},
AD_LISTEND
},
Common::EN_ANY,
Common::kPlatformDOS,
GF_INSTALLER,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// International floppy release
{
{
"dreamweb",
"",
{
{"dreamweb.r00", 0, "3b5c87717fc40cc5a5ae19c155662ee3", 152918},
{"dreamweb.r02", 0, "28458718167a040d7e988cf7d2298eae", 210466},
{"dreamweb.exe", 0, "56b1d73aa56e964b45872ff552402341", 64985},
AD_LISTEND
},
Common::EN_ANY,
Common::kPlatformDOS,
0,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// International CD release
{
{
"dreamweb",
"CD",
AD_ENTRY2s("dreamweb.r00", "3b5c87717fc40cc5a5ae19c155662ee3", 152918,
"dreamweb.r02", "d6fe5e3590ec1eea42ff65c10b023e0f", 198681),
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_CD,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// UK-V (Early UK) CD Release - From bug #6035
// Note: r00 and r02 files are identical to international floppy release
// so was misidentified as floppy, resulting in disabled CD speech.
// Added executable to detection to avoid this.
{
{
"dreamweb",
"CD",
{
{"dreamweb.r00", 0, "3b5c87717fc40cc5a5ae19c155662ee3", 152918},
{"dreamweb.r02", 0, "28458718167a040d7e988cf7d2298eae", 210466},
{"dreamweb.exe", 0, "dd1c7793b151489e67b83cd1ecab51cd", AD_NO_SIZE},
AD_LISTEND
},
Common::EN_GRB,
Common::kPlatformDOS,
ADGF_CD,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// US CD release
{
{
"dreamweb",
"CD",
AD_ENTRY2s("dreamweb.r00", "8acafd7f4418d08d0e16b65b8b10bc50", 152983,
"dreamweb.r02", "c0c363715ddf14ab54f2379906a3aa01", 198707),
Common::EN_USA,
Common::kPlatformDOS,
ADGF_CD,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// French CD release
{
{
"dreamweb",
"CD",
AD_ENTRY2s("dreamwfr.r00", "e354582a8564faf5c515df92f207e8d1", 154657,
"dreamwfr.r02", "57f3f08d5aefd04184eac76927eced80", 200575),
Common::FR_FRA,
Common::kPlatformDOS,
ADGF_CD,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// French CD release
// From bug #6030
{
{
"dreamweb",
"CD",
AD_ENTRY2s("dreamwfr.r00", "e354582a8564faf5c515df92f207e8d1", 154657,
"dreamwfr.r02", "cb99f08d5aefd04184eac76927eced80", 200575),
Common::FR_FRA,
Common::kPlatformDOS,
ADGF_CD,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// German floppy release
{
{
"dreamweb",
"",
AD_ENTRY2s("dreamweb.r00", "9960dc3baddabc6ad2a6fd75292b149c", 155886,
"dreamweb.r02", "48e1f42a53402f963ca2d1ed969f4084", 212823),
Common::DE_DEU,
Common::kPlatformDOS,
0,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// German CD release
{
{
"dreamweb",
"CD",
AD_ENTRY2s("dreamweb.r00", "9960dc3baddabc6ad2a6fd75292b149c", 155886,
"dreamweb.r02", "076ca7cd326cb2abfb2091c6cf46ae08", 201038),
Common::DE_DEU,
Common::kPlatformDOS,
ADGF_CD,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// Spanish floppy release
{
{
"dreamweb",
"",
AD_ENTRY2s("dreamweb.r00", "2df07174321de39c4f17c9ff654b268a", 153608,
"dreamweb.r02", "f97d435ad5da08fb1bcf6ea3dd6e0b9e", 199499),
Common::ES_ESP,
Common::kPlatformDOS,
0,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// Spanish CD release
{
{
"dreamweb",
"CD",
AD_ENTRY2s("dreamwsp.r00", "2df07174321de39c4f17c9ff654b268a", 153608,
"dreamwsp.r02", "577d435ad5da08fb1bcf6ea3dd6e0b9e", 199499),
Common::ES_ESP,
Common::kPlatformDOS,
ADGF_CD,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// Spanish CD release
// From bug #6030
{
{
"dreamweb",
"CD",
AD_ENTRY2s("dreamwsp.r00", "2df07174321de39c4f17c9ff654b268a", 153608,
"dreamwsp.r02", "f97d435ad5da08fb1bcf6ea3dd6e0b9e", 199499),
Common::ES_ESP,
Common::kPlatformDOS,
ADGF_CD,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// Italian floppy release
{
{
"dreamweb",
"",
AD_ENTRY2s("dreamweb.r00", "66dcab08354232f423c590156335f819", 155448,
"dreamweb.r02", "87a026e9f80ed4f94169381f871ee305", 199676),
Common::IT_ITA,
Common::kPlatformDOS,
0,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// Italian CD release
{
{
"dreamweb",
"CD",
{
{"dreamweb.exe", 0, "44d1708535cdb863b9cca372ad0b05dd", 65370},
{"dreamweb.r00", 0, "66dcab08354232f423c590156335f819", 155448},
{"dreamweb.r02", 0, "87a026e9f80ed4f94169381f871ee305", 199676},
AD_LISTEND
},
Common::IT_ITA,
Common::kPlatformDOS,
ADGF_CD,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// Czech fan-made translation
// From bug #7078
{
{
"dreamweb",
"CD",
{
{"dreamweb.r00", 0, "3b5c87717fc40cc5a5ae19c155662ee3", 152918},
{"dreamweb.r02", 0, "28458718167a040d7e988cf7d2298eae", 210466},
{"dreamweb.exe", 0, "40cc15bdc8fa3a785b5fd1ecd6194119", 65440},
AD_LISTEND
},
Common::CS_CZE,
Common::kPlatformDOS,
ADGF_CD,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// Russian fan-made translation
{
{
"dreamweb",
"CD",
{
{"dreamweb.r00", 0, "b457b515f1042d345c07e4e58a7ef792", 151975},
{"dreamweb.r02", 0, "eebf681cef5a06ee12a2630512c5eb83", 197091},
{"dreamweb.exe", 0, "9386c192d3bdce2ef4de2135c29fa66d", 65370},
AD_LISTEND
},
Common::RU_RUS,
Common::kPlatformDOS,
ADGF_CD,
GUIO1(GAMEOPTION_COPY_PROTECTION)
},
},
// English floppy demo
{
{
"dreamweb",
"Demo",
{
{"dreamweb.r57", 0, "dba78ab266054ad98151db0a9aa845f6", 102904},
{"dreamweb.r59", 0, "b1635ce312c7273b343eb0c2946361af", 199262},
{"dreamweb.exe", 0, "2362f28683ffe4ae4986c21226e132c9", 63656},
AD_LISTEND
},
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_DEMO,
GUIO0()
},
},
// English CD demo
{
{
"dreamweb",
"CD Demo",
{
{"dreamweb.r60", 0, "45fb1438d165da9f098852cc8e14ad92", 108933},
{"dreamweb.r22", 0, "35537525b55837b91b56f2468500ea43", 190222},
{"dreamweb.exe", 0, "34218e66ffd0e0d65d71282e57ac4fcc", 64445},
AD_LISTEND
},
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_CD|ADGF_DEMO,
GUIO0()
},
},
// English Amiga demo
{
{
"dreamweb",
"Demo",
{
{"dreamweb.r57", 0, "f52b88b8417c7bddc8c63b684c6ad1dd", 117720},
{"dreamweb.r59", 0, "996dfe6d963c27a302952c77a297b0fa", 223764},
{"dreamweb", 0, "093103deb9712340ee34c4bed94aab12", 51496},
AD_LISTEND
},
Common::EN_ANY,
Common::kPlatformAmiga,
ADGF_DEMO,
GUIO0()
},
},
{ AD_TABLE_END_MARKER }
};
} // End of namespace DreamWeb
#endif

View File

@@ -0,0 +1,629 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/config-manager.h"
#include "common/debug-channels.h"
#include "common/events.h"
#include "common/file.h"
#include "common/func.h"
#include "common/system.h"
#include "common/timer.h"
#include "common/util.h"
#include "common/concatstream.h"
#include "engines/advancedDetector.h"
#include "graphics/paletteman.h"
#include "graphics/surface.h"
#include "dreamweb/detection.h"
#include "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
#include "dreamweb/rnca_archive.h"
#include "common/text-to-speech.h"
namespace DreamWeb {
DreamWebEngine::DreamWebEngine(OSystem *syst, const DreamWebGameDescription *gameDesc) :
Engine(syst), _gameDescription(gameDesc), _rnd("dreamweb"),
_exText(kNumExTexts),
_setDesc(kNumSetTexts), _blockDesc(kNumBlockTexts),
_roomDesc(kNumRoomTexts), _freeDesc(kNumFreeTexts),
_personText(kNumPersonTexts) {
_vSyncPrevTick = 0;
_sound = nullptr;
_speed = 1;
_turbo = false;
_oldMouseState = 0;
_ttsMan = g_system->getTextToSpeechManager();
_datafilePrefix = "DREAMWEB.";
_speechDirName = "SPEECH";
// ES and FR CD release use a different data file prefix
// and speech directory naming.
if (isCD()) {
switch(getLanguage()) {
case Common::ES_ESP:
_datafilePrefix = "DREAMWSP.";
_speechDirName = "SPANISH";
break;
case Common::FR_FRA:
_datafilePrefix = "DREAMWFR.";
_speechDirName = "FRENCH";
break;
default:
// Nothing to do
break;
}
}
_openChangeSize = kInventx+(4*kItempicsize);
_quitRequested = false;
_speechLoaded = false;
_backdropBlocks = nullptr;
_reelList = nullptr;
_oldSubject._type = 0;
_oldSubject._index = 0;
// misc variables
_speechCount = 0;
_charShift = 0;
_brightPalette = false;
_roomLoaded = 0;
_didZoom = 0;
_lineSpacing = 10;
_textAddressX = 13;
_textAddressY = 182;
_textLen = 0;
_lastXPos = 0;
_itemFrame = 0;
_withObject = 0;
_withType = 0;
_lookCounter = 0;
_command = 0;
_commandType = 0;
_objectType = 0;
_getBack = 0;
_invOpen = 0;
_mainMode = 0;
_pickUp = 0;
_lastInvPos = 0;
_examAgain = 0;
_newTextLine = 0;
_openedOb = 0;
_openedType = 0;
_mapAdX = 0;
_mapAdY = 0;
_mapOffsetX = 104;
_mapOffsetY = 38;
_mapXStart = 0;
_mapYStart = 0;
_mapXSize = 0;
_mapYSize = 0;
_haveDoneObs = 0;
_manIsOffScreen = 0;
_facing = 0;
_leaveDirection = 0;
_turnToFace = 0;
_turnDirection = 0;
_mainTimer = 0;
_introCount = 0;
_currentKey = 0;
_timerCount = 0;
_mapX = 0;
_mapY = 0;
_ryanX = 0;
_ryanY = 0;
_lastFlag = 0;
_destPos = 0;
_realLocation = 0;
_roomNum = 0;
_nowInNewRoom = 0;
_resetManXY = 0;
_newLocation = 0xFF;
_autoLocation = 0xFF;
_mouseX = 0;
_mouseY = 0;
_mouseButton = 0;
_oldButton = 0;
_oldX = 0;
_oldY = 0;
_oldPointerX = 0;
_oldPointerY = 0;
_delHereX = 0;
_delHereY = 0;
_pointerXS = 32;
_pointerYS = 32;
_delXS = 0;
_delYS = 0;
_pointerFrame = 0;
_pointerPower = 0;
_pointerMode = 0;
_pointerSpeed = 0;
_pointerCount = 0;
_inMapArea = 0;
_talkMode = 0;
_talkPos = 0;
_character = 0;
_watchDump = 0;
_logoNum = 0;
_oldLogoNum = 0;
_pressed = 0;
_pressPointer = 0;
_graphicPress = 0;
_pressCount = 0;
_lightCount = 0;
_folderPage = 0;
_diaryPage = 0;
_menuCount = 0;
_symbolTopX = 0;
_symbolTopNum = 0;
_symbolTopDir = 0;
_symbolBotX = 0;
_symbolBotNum = 0;
_symbolBotDir = 0;
_walkAndExam = 0;
_walkExamType = 0;
_walkExamNum = 0;
_cursLocX = 0;
_cursLocY = 0;
_curPos = 0;
_monAdX = 0;
_monAdY = 0;
_timeCount = 0;
_needToDumpTimed = 0;
_loadingOrSave = 0;
_saveLoadPage = 0;
_currentSlot = 0;
_cursorPos = 0;
_colorPos = 0;
_fadeDirection = 0;
_numToFade = 0;
_fadeCount = 0;
_addToGreen = 0;
_addToRed = 0;
_addToBlue = 0;
_lastSoundReel = 0;
_lastHardKey = Common::KEYCODE_INVALID;
_bufferIn = 0;
_bufferOut = 0;
_blinkFrame = 23;
_blinkCount = 0;
_reAssesChanges = 0;
_pointersPath = 0;
_mansPath = 0;
_pointerFirstPath = 0;
_finalDest = 0;
_destination = 0;
_lineStartX = 0;
_lineStartY = 0;
_lineEndX = 0;
_lineEndY = 0;
_linePointer = 0;
_lineDirection = 0;
_lineLength = 0;
_subtitles = 0;
_foreignRelease = 0;
_wonGame = 0;
_hasSpeech = 0;
_roomsSample = 0;
_copyProtection = 0;
for (uint i = 0; i < 128; i++)
memset(&_setDat[i], 0, sizeof(SetObject));
for (uint i = 0; i < 80; i++)
memset(&_freeDat[i], 0, sizeof(DynObject));
for (uint i = 0; i < kNumExObjects; i++)
memset(&_exData[i], 0, sizeof(DynObject));
memset(&_vars, 0, sizeof(GameVars));
for (uint i = 0; i < 96; i++)
memset(&_backdropFlags[i], 0, sizeof(BackdropMapFlag));
for (uint i = 0; i < kNumReelRoutines+1; i++)
memset(&_reelRoutines[i], 0, sizeof(ReelRoutine));
_personData = nullptr;
for (uint i = 0; i < 16; i++)
memset(&_openInvList[i], 0, sizeof(ObjectRef));
for (uint i = 0; i < 30; i++)
memset(&_ryanInvList[i], 0, sizeof(ObjectRef));
for (uint i = 0; i < 11*10; i++)
memset(&_mapFlags[i], 0, sizeof(MapFlag));
for (uint i = 0; i < kNumChanges; i++)
memset(&_listOfChanges[i], 0, sizeof(Change));
_currentCharset = nullptr;
for (uint i = 0; i < 36; i++)
memset(&_pathData[i], 0, sizeof(RoomPaths));
}
DreamWebEngine::~DreamWebEngine() {
delete _sound;
if (_thumbnail.getPixels())
_thumbnail.free();
}
void DreamWebEngine::pauseEngineIntern(bool pause) {
Engine::pauseEngineIntern(pause);
if (!pause)
_vSyncPrevTick = _system->getMillis();
}
void DreamWebEngine::waitForVSync() {
if (isPaused())
return;
processEvents();
if (!_turbo) {
const uint32 delay = 1000 / 70 / _speed;
uint32 elapsed = _system->getMillis() - _vSyncPrevTick;
if (elapsed < delay)
_system->delayMillis(delay - elapsed);
}
_vSyncPrevTick = _system->getMillis();
doShake();
doFade();
_system->updateScreen();
}
void DreamWebEngine::quit() {
_quitRequested = true;
_lastHardKey = Common::KEYCODE_ESCAPE;
}
void DreamWebEngine::processEvents(bool processSoundEvents) {
if (_eventMan->shouldQuit()) {
quit();
return;
}
if (processSoundEvents)
_sound->soundHandler();
Common::Event event;
int softKey;
while (_eventMan->pollEvent(event)) {
switch(event.type) {
case Common::EVENT_RETURN_TO_LAUNCHER:
quit();
break;
case Common::EVENT_KEYDOWN:
if (event.kbd.flags & Common::KBD_CTRL) {
switch (event.kbd.keycode) {
case Common::KEYCODE_f:
setSpeed(_speed != 4? 4: 1);
break;
case Common::KEYCODE_g:
_turbo = !_turbo;
break;
case Common::KEYCODE_c: //skip statue puzzle
_symbolBotNum = 3;
_symbolTopNum = 5;
break;
default:
break;
}
return; //do not pass ctrl + key to the engine
}
// Some parts of the code uses the hardware key
// code directly.
switch (event.kbd.keycode) {
case Common::KEYCODE_ESCAPE:
_lastHardKey = Common::KEYCODE_ESCAPE;
break;
case Common::KEYCODE_SPACE:
_lastHardKey = Common::KEYCODE_SPACE;
break;
default:
_lastHardKey = Common::KEYCODE_INVALID;
break;
}
// The rest of the keys are converted to ASCII. This
// is fairly restrictive, and eventually we may want
// to let through more keys. I think this is mostly to
// keep weird glyphs out of savegame names.
softKey = 0;
debug(1, "DreamWebEngine::processEvents() KeyDown keycode:%d ascii:0x%02x", event.kbd.keycode, event.kbd.ascii);
if ((event.kbd.ascii >= 'a' && event.kbd.ascii <= 'z') ||
(event.kbd.ascii >= 'A' && event.kbd.ascii <= 'Z')) {
softKey = event.kbd.ascii & ~0x20; // (& ~0x20) forces ascii codes for a-z to map to A-Z
} else if (event.kbd.ascii == '-' ||
event.kbd.ascii == ' ' ||
(event.kbd.ascii >= '0' && event.kbd.ascii <= '9')) {
softKey = event.kbd.ascii;
} else if (event.kbd.keycode >= Common::KEYCODE_KP0 && event.kbd.keycode <= Common::KEYCODE_KP9) {
softKey = event.kbd.keycode - Common::KEYCODE_KP0 + '0';
} else if (event.kbd.keycode == Common::KEYCODE_KP_MINUS) {
softKey = '-';
} else if (event.kbd.keycode == Common::KEYCODE_BACKSPACE ||
event.kbd.keycode == Common::KEYCODE_DELETE) {
softKey = 8;
} else if (event.kbd.keycode == Common::KEYCODE_RETURN
|| event.kbd.keycode == Common::KEYCODE_KP_ENTER) {
softKey = 13;
}
if (softKey)
keyPressed(softKey);
break;
default:
break;
}
}
}
Common::Error DreamWebEngine::run() {
if (_gameDescription->desc.flags & GF_INSTALLER) {
Common::Array<Common::SharedPtr<Common::SeekableReadStream>> volumes;
for (uint i = 0; _gameDescription->desc.filesDescriptions[i].fileName; i++) {
Common::File *dw = new Common::File();
const char *name = _gameDescription->desc.filesDescriptions[i].fileName;
if (!dw->open(name)) {
error("Can't open %s", name);
}
volumes.push_back(Common::SharedPtr<Common::SeekableReadStream>(dw));
}
Common::ConcatReadStream *concat = new Common::ConcatReadStream(volumes);
SearchMan.add("rnca", RNCAArchive::open(concat, DisposeAfterUse::YES));
}
if (_ttsMan != nullptr) {
Common::String languageString = Common::getLanguageCode(getLanguage());
_ttsMan->setLanguage(languageString);
_ttsMan->enable(ConfMan.getBool("tts_enabled_objects") || ConfMan.getBool("tts_enabled_speech"));
switch (getLanguage()) {
case Common::RU_RUS:
_textEncoding = Common::kDos866;
break;
case Common::CS_CZE:
_textEncoding = Common::kWindows1250;
break;
default:
_textEncoding = Common::kDos850;
break;
}
}
syncSoundSettings();
setDebugger(new DreamWebConsole(this));
_sound = new DreamWebSound(this);
_hasSpeech = Common::File::exists(_speechDirName.appendComponent("r01c0000.raw")) && !ConfMan.getBool("speech_mute");
_brightPalette = ConfMan.getBool("bright_palette");
_copyProtection = ConfMan.getBool("copy_protection");
_vSyncPrevTick = _system->getMillis();
dreamweb();
dreamwebFinalize();
_quitRequested = false;
return Common::kNoError;
}
void DreamWebEngine::setSpeed(uint speed) {
debug(0, "setting speed %u", speed);
_speed = speed;
}
Common::String DreamWebEngine::getSavegameFilename(int slot) const {
// TODO: Are saves from all versions of Dreamweb compatible with each other?
// Then we can can consider keeping the filenames as DREAMWEB.Dnn.
// Otherwise, this must be changed to be target dependent.
//Common::String filename = _targetName + Common::String::format(".d%02d", savegameId);
Common::String filename = Common::String::format("DREAMWEB.D%02d", slot);
return filename;
}
void DreamWebEngine::keyPressed(uint16 ascii) {
debug(2, "key pressed = %04x", ascii);
uint16 in = (_bufferIn + 1) % ARRAYSIZE(_keyBuffer);
uint16 out = _bufferOut;
if (in == out) {
warning("keyboard buffer is full");
return;
}
_bufferIn = in;
_keyBuffer[in] = ascii;
}
void DreamWebEngine::getPalette(uint8 *data, uint start, uint count) {
_system->getPaletteManager()->grabPalette(data, start, count);
while (count--)
*data++ >>= 2;
}
void DreamWebEngine::setPalette(const uint8 *data, uint start, uint count) {
assert(start + count <= 256);
uint8 fixed[3*256];
for (uint i = 0; i < count * 3; ++i) {
fixed[i] = data[i] << 2;
}
_system->getPaletteManager()->setPalette(fixed, start, count);
}
void DreamWebEngine::blit(const uint8 *src, int pitch, int x, int y, int w, int h) {
if (y + h > (int)kScreenheight)
h = kScreenheight - y;
if (x + w > (int)kScreenwidth)
w = kScreenwidth - x;
if (h <= 0 || w <= 0)
return;
_system->copyRectToScreen(src, pitch, x, y, w, h);
}
void DreamWebEngine::printUnderMonitor() {
uint8 *dst = workspace() + kScreenwidth * 43 + 76;
Graphics::Surface *s = _system->lockScreen();
if (!s)
error("lockScreen failed");
for (uint y = 0; y < 104; ++y) {
uint8 *src = (uint8 *)s->getBasePtr(76, 43 + 8 + y);
for (uint x = 0; x < 170; ++x) {
if (*src < 231)
*dst++ = *src++;
else {
++dst; ++src;
}
}
dst += kScreenwidth - 170;
}
_system->unlockScreen();
}
void DreamWebEngine::cls() {
_system->fillScreen(0);
}
uint8 DreamWebEngine::modifyChar(uint8 c) const {
switch (getLanguage()) {
case Common::DE_DEU:
switch (c) {
case 129:
return 'Z' + 3;
case 132:
return 'Z' + 1;
case 142:
return 'Z' + 4;
case 154:
return 'Z' + 6;
case 225:
return 'A' - 1;
case 153:
return 'Z' + 5;
case 148:
return 'Z' + 2;
default:
return c;
}
case Common::ES_ESP:
switch(c) {
case 160:
return 'Z' + 1;
case 130:
return 'Z' + 2;
case 161:
return 'Z' + 3;
case 162:
return 'Z' + 4;
case 163:
return 'Z' + 5;
case 164:
return 'Z' + 6;
case 165:
return ',' - 1;
case 168:
return 'A' - 1;
case 173:
return 'A' - 4;
case 129:
return 'A' - 5;
default:
return c;
}
case Common::FR_FRA:
case Common::IT_ITA:
switch(c) {
case 133:
return 'Z' + 1;
case 130:
return 'Z' + 2;
case 138:
return 'Z' + 3;
case 136:
return 'Z' + 4;
case 140:
return 'Z' + 5;
case 135:
return 'Z' + 6;
case 149:
return ',' - 1;
case 131:
return ',' - 2;
case 141:
return ',' - 3;
case 139:
return ',' - 4;
case 151:
return 'A' - 1;
case 147:
return 'A' - 3;
case 150:
return 'A' - 4;
default:
return c;
}
case Common::RU_RUS:
if (c >= 224)
c -= 48;
// fall through
default:
return c;
}
}
Common::Path DreamWebEngine::modifyFileName(const char *name) {
Common::String fileName(name);
// Sanity check
if (!fileName.hasPrefix("DREAMWEB."))
return Common::Path(fileName);
// Make sure we use the correct file name as it differs depending on the game variant
fileName = _datafilePrefix;
fileName += name + 9;
return Common::Path(fileName);
}
bool DreamWebEngine::hasSpeech() {
return isCD() && _hasSpeech;
}
} // End of namespace DreamWeb

1112
engines/dreamweb/dreamweb.h Normal file

File diff suppressed because it is too large Load Diff

867
engines/dreamweb/keypad.cpp Normal file
View File

@@ -0,0 +1,867 @@
/* 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 "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
namespace DreamWeb {
const uint16 kKeypadx = 36+112;
const uint16 kKeypady = 72;
void DreamWebEngine::enterCode(uint8 digit0, uint8 digit1, uint8 digit2, uint8 digit3) {
RectWithCallback keypadList[] = {
{ kKeypadx+9,kKeypadx+30,kKeypady+9,kKeypady+22,&DreamWebEngine::buttonOne },
{ kKeypadx+31,kKeypadx+52,kKeypady+9,kKeypady+22,&DreamWebEngine::buttonTwo },
{ kKeypadx+53,kKeypadx+74,kKeypady+9,kKeypady+22,&DreamWebEngine::buttonThree },
{ kKeypadx+9,kKeypadx+30,kKeypady+23,kKeypady+40,&DreamWebEngine::buttonFour },
{ kKeypadx+31,kKeypadx+52,kKeypady+23,kKeypady+40,&DreamWebEngine::buttonFive },
{ kKeypadx+53,kKeypadx+74,kKeypady+23,kKeypady+40,&DreamWebEngine::buttonSix },
{ kKeypadx+9,kKeypadx+30,kKeypady+41,kKeypady+58,&DreamWebEngine::buttonSeven },
{ kKeypadx+31,kKeypadx+52,kKeypady+41,kKeypady+58,&DreamWebEngine::buttonEight },
{ kKeypadx+53,kKeypadx+74,kKeypady+41,kKeypady+58,&DreamWebEngine::buttonNine },
{ kKeypadx+9,kKeypadx+30,kKeypady+59,kKeypady+73,&DreamWebEngine::buttonNought },
{ kKeypadx+31,kKeypadx+74,kKeypady+59,kKeypady+73,&DreamWebEngine::buttonEnter },
{ kKeypadx+72,kKeypadx+86,kKeypady+80,kKeypady+94,&DreamWebEngine::quitKey },
{ 0,320,0,200,&DreamWebEngine::blank },
{ 0xFFFF,0,0,0,nullptr }
};
getRidOfReels();
loadKeypad();
createPanel();
showIcon();
showOuterPad();
showKeypad();
readMouse();
showPointer();
workToScreen();
delPointer();
_pressPointer = 0;
_getBack = 0;
while (true) {
delPointer();
readMouse();
showKeypad();
showPointer();
waitForVSync();
if (_pressCount == 0) {
_pressed = 255;
_graphicPress = 255;
waitForVSync();
} else
--_pressCount;
dumpPointer();
dumpKeypad();
dumpTextLine();
checkCoords(keypadList);
if (_quitRequested || (_getBack == 1))
break;
if (_lightCount == 1) {
if (_vars._lockStatus == 0)
break;
} else {
if (_pressCount == 40) {
addToPressList();
if (_pressed == 11) {
if (isItRight(digit0, digit1, digit2, digit3))
_vars._lockStatus = 0;
_sound->playChannel1(11);
_lightCount = 120;
_pressPointer = 0;
}
}
}
}
_manIsOffScreen = 0;
_keypadGraphics.clear();
restoreReels();
redrawMainScrn();
workToScreenM();
}
// Note: isItRight comes from use.asm, but is only used by enterCode(),
// so we place it here.
bool DreamWebEngine::isItRight(uint8 digit0, uint8 digit1, uint8 digit2, uint8 digit3) {
return digit0 == _pressList[0] && digit1 == _pressList[1]
&& digit2 == _pressList[2] && digit3 == _pressList[3];
}
void DreamWebEngine::loadKeypad() {
loadGraphicsFile(_keypadGraphics, "G02");
}
void DreamWebEngine::quitKey() {
commandOnlyCond(4, 222);
if (_mouseButton != _oldButton && (_mouseButton & 1))
_getBack = 1;
}
void DreamWebEngine::addToPressList() {
if (_pressPointer == 5)
return;
uint8 pressed = _pressed;
if (pressed == 10)
pressed = 0;
_pressList[_pressPointer] = pressed;
++_pressPointer;
}
void DreamWebEngine::buttonOne() {
buttonPress(1);
}
void DreamWebEngine::buttonTwo() {
buttonPress(2);
}
void DreamWebEngine::buttonThree() {
buttonPress(3);
}
void DreamWebEngine::buttonFour() {
buttonPress(4);
}
void DreamWebEngine::buttonFive() {
buttonPress(5);
}
void DreamWebEngine::buttonSix() {
buttonPress(6);
}
void DreamWebEngine::buttonSeven() {
buttonPress(7);
}
void DreamWebEngine::buttonEight() {
buttonPress(8);
}
void DreamWebEngine::buttonNine() {
buttonPress(9);
}
void DreamWebEngine::buttonNought() {
buttonPress(10);
}
void DreamWebEngine::buttonEnter() {
buttonPress(11);
}
void DreamWebEngine::buttonPress(uint8 buttonId) {
commandOnlyCond(buttonId + 4, buttonId + 100);
if ((_mouseButton & 1) && (_mouseButton != _oldButton)) {
_pressed = buttonId;
_graphicPress = buttonId + 21;
_pressCount = 40;
if (buttonId != 11)
_sound->playChannel1(10);
}
}
void DreamWebEngine::showOuterPad() {
showFrame(_keypadGraphics, kKeypadx-3, kKeypady-4, 1, 0);
showFrame(_keypadGraphics, kKeypadx+74, kKeypady+76, 37, 0);
}
void DreamWebEngine::showKeypad() {
singleKey(22, kKeypadx+9, kKeypady+5);
singleKey(23, kKeypadx+31, kKeypady+5);
singleKey(24, kKeypadx+53, kKeypady+5);
singleKey(25, kKeypadx+9, kKeypady+23);
singleKey(26, kKeypadx+31, kKeypady+23);
singleKey(27, kKeypadx+53, kKeypady+23);
singleKey(28, kKeypadx+9, kKeypady+41);
singleKey(29, kKeypadx+31, kKeypady+41);
singleKey(30, kKeypadx+53, kKeypady+41);
singleKey(31, kKeypadx+9, kKeypady+59);
singleKey(32, kKeypadx+31, kKeypady+59);
if (_lightCount) {
--_lightCount;
uint8 frameIndex;
uint16 y;
if (_vars._lockStatus) {
frameIndex = 36;
y = kKeypady-1+63;
} else {
frameIndex = 41;
y = kKeypady+4+63;
}
if ((_lightCount >= 60) && (_lightCount < 100))
--frameIndex;
showFrame(_keypadGraphics, kKeypadx+60, y, frameIndex, 0);
}
}
void DreamWebEngine::singleKey(uint8 key, uint16 x, uint16 y) {
if (key == _graphicPress) {
key += 11;
if (_pressCount < 8)
key -= 11;
}
key -= 20;
showFrame(_keypadGraphics, x, y, key, 0);
}
void DreamWebEngine::dumpKeypad() {
multiDump(kKeypadx - 3, kKeypady - 4, 120, 90);
}
void DreamWebEngine::useMenu() {
getRidOfReels();
loadMenu();
createPanel();
showPanel();
showIcon();
_vars._newObs = 0;
drawFloor();
printSprites();
showFrame(_menuGraphics2, kMenux-48, kMenuy-4, 4, 0);
getUnderMenu();
showFrame(_menuGraphics2, kMenux+54, kMenuy+72, 5, 0);
workToScreenM();
_getBack = 0;
do {
delPointer();
putUnderMenu();
showMenu();
readMouse();
showPointer();
waitForVSync();
dumpPointer();
dumpMenu();
dumpTextLine();
RectWithCallback menuList[] = {
{ kMenux+54,kMenux+68,kMenuy+72,kMenuy+88,&DreamWebEngine::quitKey },
{ 0,320,0,200,&DreamWebEngine::blank },
{ 0xFFFF,0,0,0,nullptr }
};
checkCoords(menuList);
} while ((_getBack != 1) && !_quitRequested);
_manIsOffScreen = 0;
redrawMainScrn();
_menuGraphics.clear();
_menuGraphics2.clear();
restoreReels();
workToScreenM();
}
void DreamWebEngine::dumpMenu() {
multiDump(kMenux, kMenuy, 48, 48);
}
void DreamWebEngine::getUnderMenu() {
multiGet(_underTimedText, kMenux, kMenuy, 48, 48);
}
void DreamWebEngine::putUnderMenu() {
multiPut(_underTimedText, kMenux, kMenuy, 48, 48);
}
// Note: showoutermenu from the asm version was unused and thus not placed here
void DreamWebEngine::showMenu() {
++_menuCount;
if (_menuCount == 37*2)
_menuCount = 0;
showFrame(_menuGraphics, kMenux, kMenuy, _menuCount / 2, 0);
}
void DreamWebEngine::loadMenu() {
loadGraphicsFile(_menuGraphics, "S02"); // sprite name 3
loadGraphicsFile(_menuGraphics2, "G07"); // mon. graphics 2
}
void DreamWebEngine::viewFolder() {
_manIsOffScreen = 1;
getRidOfAll();
loadFolder();
_folderPage = 0;
showFolder();
workToScreenM();
_getBack = 0;
do {
if (_quitRequested)
break;
delPointer();
readMouse();
showPointer();
waitForVSync();
dumpPointer();
dumpTextLine();
checkFolderCoords();
} while (_getBack == 0);
_manIsOffScreen = 0;
_folderGraphics.clear();
_folderGraphics2.clear();
_folderGraphics3.clear();
_folderCharset.clear();
restoreAll();
redrawMainScrn();
workToScreenM();
}
void DreamWebEngine::nextFolder() {
if (_folderPage == 12) {
blank();
return;
}
commandOnlyCond(16, 201);
if ((_mouseButton == 1) && (_mouseButton != _oldButton)) {
++_folderPage;
folderHints();
delPointer();
showFolder();
_mouseButton = 0;
checkFolderCoords();
workToScreenM();
}
}
void DreamWebEngine::folderHints() {
if (_folderPage == 5) {
if ((_vars._aideDead != 1) && (getLocation(13) != 1)) {
setLocation(13);
showFolder();
const uint8 *string = getTextInFile1(30);
printDirect(string, 0, 86, 141, true);
workToScreenM();
hangOnP(200);
}
} else if (_folderPage == 9) {
if (getLocation(7) != 1) {
setLocation(7);
showFolder();
const uint8 *string = getTextInFile1(31);
printDirect(string, 0, 86, 141, true);
workToScreenM();
hangOnP(200);
}
}
}
void DreamWebEngine::lastFolder() {
if (_folderPage == 0) {
blank();
return;
}
commandOnlyCond(17, 202);
if ((_mouseButton == 1) && (_mouseButton != _oldButton)) {
--_folderPage;
delPointer();
showFolder();
_mouseButton = 0;
checkFolderCoords();
workToScreenM();
}
}
void DreamWebEngine::checkFolderCoords() {
RectWithCallback folderList[] = {
{ 280,320,160,200, &DreamWebEngine::quitKey },
{ 143,300,6,194, &DreamWebEngine::nextFolder },
{ 0,143,6,194, &DreamWebEngine::lastFolder },
{ 0,320,0,200, &DreamWebEngine::blank },
{ 0xFFFF,0,0,0, nullptr }
};
checkCoords(folderList);
}
void DreamWebEngine::loadFolder() {
loadGraphicsFile(_folderGraphics, "G09"); // folder graphics 1
loadGraphicsFile(_folderGraphics2, "G10"); // folder graphics 2
loadGraphicsFile(_folderGraphics3, "G11"); // folder graphics 3
loadGraphicsFile(_folderCharset, "C02"); // character set 3
loadTempText("T50"); // folder text
}
void DreamWebEngine::showFolder() {
_commandType = 255;
if (_folderPage) {
useTempCharset(&_folderCharset);
createPanel2();
showFrame(_folderGraphics, 0, 0, 0, 0);
showFrame(_folderGraphics, 143, 0, 1, 0);
showFrame(_folderGraphics, 0, 92, 2, 0);
showFrame(_folderGraphics, 143, 92, 3, 0);
folderExit();
if (_folderPage != 1)
showLeftPage();
if (_folderPage != 12)
showRightPage();
useCharset1();
underTextLine();
} else {
createPanel2();
showFrame(_folderGraphics3, 143-28, 0, 0, 0);
showFrame(_folderGraphics3, 143-28, 92, 1, 0);
folderExit();
underTextLine();
}
}
void DreamWebEngine::folderExit() {
showFrame(_folderGraphics2, 296, 178, 6, 0);
}
void DreamWebEngine::showLeftPage() {
showFrame(_folderGraphics2, 0, 12, 3, 0);
uint16 y = 12+5;
for (uint i = 0; i < 9; ++i) {
showFrame(_folderGraphics2, 0, y, 4, 0);
y += 16;
}
showFrame(_folderGraphics2, 0, y, 5, 0);
_lineSpacing = 8;
_charShift = 91;
if (getLanguage() == Common::RU_RUS)
_charShift = 182;
uint8 pageIndex = _folderPage - 2;
const uint8 *string = getTextInFile1(pageIndex * 2);
y = 48;
for (uint i = 0; i < 2; ++i) {
uint8 lastChar;
do {
lastChar = printDirect(&string, 2, &y, 140, false, true);
y += _lineSpacing;
} while (lastChar != '\0');
}
_charShift = 0;
_lineSpacing = 10;
uint8 *bufferToSwap = workspace() + (48*kScreenwidth)+2;
for (uint i = 0; i < 120; ++i) {
for (uint j = 0; j < 65; ++j) {
SWAP(bufferToSwap[j], bufferToSwap[130 - j]);
}
bufferToSwap += kScreenwidth;
}
}
void DreamWebEngine::showRightPage() {
showFrame(_folderGraphics2, 143, 12, 0, 0);
uint16 y = 12+37;
for (uint i = 0; i < 7; ++i) {
showFrame(_folderGraphics2, 143, y, 1, 0);
y += 16;
}
showFrame(_folderGraphics2, 143, y, 2, 0);
_lineSpacing = 8;
uint8 pageIndex = _folderPage - 1;
const uint8 *string = getTextInFile1(pageIndex * 2);
y = 48;
for (uint i = 0; i < 2; ++i) {
uint8 lastChar;
do {
lastChar = printDirect(&string, 152, &y, 140, false, true);
y += _lineSpacing;
} while (lastChar != '\0');
}
_lineSpacing = 10;
}
void DreamWebEngine::enterSymbol() {
_manIsOffScreen = 1;
getRidOfReels();
loadGraphicsFile(_symbolGraphics, "G12"); // symbol graphics
_symbolTopX = 24;
_symbolTopDir = 0;
_symbolBotX = 24;
_symbolBotDir = 0;
redrawMainScrn();
showSymbol();
underTextLine();
workToScreenM();
_getBack = 0;
do {
delPointer();
updateSymbolTop();
updateSymbolBot();
showSymbol();
readMouse();
showPointer();
waitForVSync();
dumpPointer();
dumpTextLine();
dumpSymbol();
RectWithCallback symbolList[] = {
{ kSymbolx+40,kSymbolx+64,kSymboly+2,kSymboly+16,&DreamWebEngine::quitSymbol },
{ kSymbolx,kSymbolx+52,kSymboly+20,kSymboly+50,&DreamWebEngine::setTopLeft },
{ kSymbolx+52,kSymbolx+104,kSymboly+20,kSymboly+50,&DreamWebEngine::setTopRight },
{ kSymbolx,kSymbolx+52,kSymboly+50,kSymboly+80,&DreamWebEngine::setBotLeft },
{ kSymbolx+52,kSymbolx+104,kSymboly+50,kSymboly+80,&DreamWebEngine::setBotRight },
{ 0,320,0,200,&DreamWebEngine::blank },
{ 0xFFFF,0,0,0,nullptr }
};
checkCoords(symbolList);
} while ((_getBack == 0) && !_quitRequested);
if ((_symbolBotNum == 3) && (_symbolTopNum == 5)) {
removeSetObject(43);
placeSetObject(46);
turnAnyPathOn(0, _roomNum + 12);
_manIsOffScreen = 0;
redrawMainScrn();
_symbolGraphics.clear();
restoreReels();
workToScreenM();
_sound->playChannel1(13);
} else {
removeSetObject(46);
placeSetObject(43);
turnAnyPathOff(0, _roomNum + 12);
_manIsOffScreen = 0;
redrawMainScrn();
_symbolGraphics.clear();
restoreReels();
workToScreenM();
}
}
void DreamWebEngine::quitSymbol() {
if (_symbolTopX != 24 || _symbolBotX != 24) {
blank();
return;
};
commandOnlyCond(18, 222);
if (_mouseButton == _oldButton)
return; // notqs
if (!(_mouseButton & 1))
return;
_getBack = 1;
}
void DreamWebEngine::setTopLeft() {
if (_symbolTopDir != 0) {
blank();
return;
}
commandOnlyCond(19, 210);
if (_mouseButton != 0)
_symbolTopDir = -1;
}
void DreamWebEngine::setTopRight() {
if (_symbolTopDir != 0) {
blank();
return;
}
commandOnlyCond(20, 211);
if (_mouseButton != 0)
_symbolTopDir = +1;
}
void DreamWebEngine::setBotLeft() {
if (_symbolBotDir != 0) {
blank();
return;
}
commandOnlyCond(21, 212);
if (_mouseButton != 0)
_symbolBotDir = -1;
}
void DreamWebEngine::setBotRight() {
if (_symbolBotDir != 0) {
blank();
return;
}
commandOnlyCond(22, 213);
if (_mouseButton != 0)
_symbolBotDir = +1;
}
void DreamWebEngine::dumpSymbol() {
_newTextLine = 0;
multiDump(kSymbolx, kSymboly + 20, 104, 60);
}
void DreamWebEngine::showSymbol() {
showFrame(_symbolGraphics, kSymbolx, kSymboly, 12, 0);
showFrame(_symbolGraphics, _symbolTopX + kSymbolx-44, kSymboly+20, _symbolTopNum, 32);
uint8 nextTopSymbol = nextSymbol(_symbolTopNum);
showFrame(_symbolGraphics, _symbolTopX + kSymbolx+5, kSymboly+20, nextTopSymbol, 32);
uint8 nextNextTopSymbol = nextSymbol(nextTopSymbol);
showFrame(_symbolGraphics, _symbolTopX + kSymbolx+54, kSymboly+20, nextNextTopSymbol, 32);
showFrame(_symbolGraphics, _symbolBotX + kSymbolx-44, kSymboly+49, 6 + _symbolBotNum, 32);
uint8 nextBotSymbol = nextSymbol(_symbolBotNum);
showFrame(_symbolGraphics, _symbolBotX + kSymbolx+5, kSymboly+49, 6 + nextBotSymbol, 32);
uint8 nextNextBotSymbol = nextSymbol(nextBotSymbol);
showFrame(_symbolGraphics, _symbolBotX + kSymbolx+54, kSymboly+49, 6 + nextNextBotSymbol, 32);
}
uint8 DreamWebEngine::nextSymbol(uint8 symbol) {
uint8 result = symbol + 1;
if (result == 6)
return 0;
if (result == 12)
return 6;
return result;
}
void DreamWebEngine::updateSymbolTop() {
if (!_symbolTopDir)
return; // topfinished
if (_symbolTopDir == -1) {
// Backward
_symbolTopX--;
if (_symbolTopX != (byte)-1) {
// Not wrapping
if (_symbolTopX != 24)
return; // topfinished
_symbolTopDir = 0;
} else {
_symbolTopX = 48;
_symbolTopNum++;
if (_symbolTopNum != 6)
return; // topfinished
_symbolTopNum = 0;
}
} else {
// Forward
_symbolTopX++;
if (_symbolTopX != 49) {
// Not wrapping
if (_symbolTopX != 24)
return; // topfinished
_symbolTopDir = 0;
} else {
_symbolTopX = 0;
_symbolTopNum--;
if (_symbolTopNum != (byte)-1)
return; // topfinished
_symbolTopNum = 5;
}
}
}
void DreamWebEngine::updateSymbolBot() {
if (!_symbolBotDir)
return; // botfinished
if (_symbolBotDir == -1) {
// Backward
_symbolBotX--;
if (_symbolBotX != (byte)-1) {
// Not wrapping
if (_symbolBotX != 24)
return; // botfinished
_symbolBotDir = 0;
} else {
_symbolBotX = 48;
_symbolBotNum++;
if (_symbolBotNum != 6)
return; // botfinished
_symbolBotNum = 0;
}
} else {
// Forward
_symbolBotX++;
if (_symbolBotX != 49) {
// Not wrapping
if (_symbolBotX != 24)
return; // botfinished
_symbolBotDir = 0;
} else {
_symbolBotX = 0;
_symbolBotNum--;
if (_symbolBotNum != (byte)-1)
return; // botfinished
_symbolBotNum = 5;
}
}
}
void DreamWebEngine::useDiary() {
getRidOfReels();
loadGraphicsFile(_diaryGraphics, "G14");
loadTempText("T51");
loadGraphicsFile(_diaryCharset, "C02");
createPanel();
showIcon();
showDiary();
underTextLine();
showDiaryPage();
readMouse();
showPointer();
workToScreen();
delPointer();
_getBack = 0;
RectWithCallback diaryList[] = {
{ kDiaryx+94,kDiaryx+110,kDiaryy+97,kDiaryy+113,&DreamWebEngine::diaryKeyN },
{ kDiaryx+151,kDiaryx+167,kDiaryy+71,kDiaryy+87,&DreamWebEngine::diaryKeyP },
{ kDiaryx+176,kDiaryx+192,kDiaryy+108,kDiaryy+124,&DreamWebEngine::quitKey },
{ 0,320,0,200,&DreamWebEngine::blank },
{ 0xFFFF,0,0,0,nullptr }
};
do {
delPointer();
readMouse();
showDiaryKeys();
showPointer();
waitForVSync();
dumpPointer();
dumpDiaryKeys();
dumpTextLine();
checkCoords(diaryList);
} while (!_getBack && !_quitRequested);
_diaryGraphics.clear();
getRidOfTempText();
_diaryCharset.clear();
restoreReels();
_manIsOffScreen = 0;
redrawMainScrn();
workToScreenM();
}
void DreamWebEngine::showDiary() {
showFrame(_diaryGraphics, kDiaryx, kDiaryy + 37, 1, 0);
showFrame(_diaryGraphics, kDiaryx + 176, kDiaryy + 108, 2, 0);
}
void DreamWebEngine::showDiaryKeys() {
if (!_pressCount)
return; // nokeyatall
_pressCount--;
if (!_pressCount)
return; // nokeyatall
if (_pressed == 'N') {
byte frame = (_pressCount == 1) ? 3 : 4;
showFrame(_diaryGraphics, kDiaryx + 94, kDiaryy + 97, frame, 0);
} else {
byte frame = (_pressCount == 1) ? 5 : 6;
showFrame(_diaryGraphics, kDiaryx + 151, kDiaryy + 71, frame, 0);
}
if (_pressCount == 1)
showDiaryPage();
}
void DreamWebEngine::dumpDiaryKeys() {
if (_pressCount == 1) {
if (_vars._sartainDead != 1 && _diaryPage == 5 && getLocation(6) != 1) {
// Add Sartain Industries note
setLocation(6);
delPointer();
const uint8 *string = getTextInFile1(12);
printDirect(string, 70, 106, 241, 241 & 1);
workToScreenM();
hangOnP(200);
createPanel();
showIcon();
showDiary();
showDiaryPage();
workToScreenM();
showPointer();
return;
} else {
multiDump(kDiaryx + 48, kDiaryy + 15, 200, 16);
}
}
multiDump(kDiaryx + 94, kDiaryy + 97, 16, 16);
multiDump(kDiaryx + 151, kDiaryy + 71, 16, 16);
}
void DreamWebEngine::diaryKeyP() {
commandOnlyCond(23, 214);
if (!_mouseButton ||
_oldButton == _mouseButton ||
_pressCount)
return; // notkeyp
_sound->playChannel1(16);
_pressCount = 12;
_pressed = 'P';
_diaryPage--;
if (_diaryPage == 0xFF)
_diaryPage = 11;
}
void DreamWebEngine::diaryKeyN() {
commandOnlyCond(23, 213);
if (!_mouseButton ||
_oldButton == _mouseButton ||
_pressCount)
return; // notkeyn
_sound->playChannel1(16);
_pressCount = 12;
_pressed = 'N';
_diaryPage++;
if (_diaryPage == 12)
_diaryPage = 0;
}
void DreamWebEngine::showDiaryPage() {
showFrame(_diaryGraphics, kDiaryx, kDiaryy, 0, 0);
useTempCharset(&_diaryCharset);
if (getLanguage() == Common::RU_RUS)
useCharsetTempgraphics();
_charShift = 91+91;
const uint8 *string = getTextInFile1(_diaryPage);
uint16 y = kDiaryy + 16;
printDirect(&string, kDiaryx + 48, &y, 240, 240 & 1, true);
y = kDiaryy + 16;
printDirect(&string, kDiaryx + 129, &y, 240, 240 & 1, true);
y = kDiaryy + 23;
printDirect(&string, kDiaryx + 48, &y, 240, 240 & 1, true);
_charShift = 0;
useCharset1();
}
} // End of namespace DreamWeb

View File

@@ -0,0 +1,274 @@
/* 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/savefile.h"
#include "common/translation.h"
#include "graphics/thumbnail.h"
#include "engines/advancedDetector.h"
#include "dreamweb/dreamweb.h"
#include "dreamweb/detection.h"
static const ADExtraGuiOptionsMap gameGuiOptions[] = {
{
GAMEOPTION_COPY_PROTECTION,
{
_s("Enable copy protection"),
_s("Enable any copy protection that would otherwise be bypassed by default."),
"copy_protection",
false,
0,
0
},
},
{
GAMEOPTION_ORIGINAL_SAVELOAD,
{
_s("Use original save/load screens"),
_s("Use the original save/load screens instead of the ScummVM ones"),
"originalsaveload",
false,
0,
0
}
},
{
GAMEOPTION_BRIGHTPALETTE,
{
_s("Use bright palette mode"),
_s("Display graphics using the game's bright palette"),
"bright_palette",
true,
0,
0
}
},
#ifdef USE_TTS
{
GAMEOPTION_TTS_THINGS,
{
_s("Enable Text to Speech for Objects, Options, and the Bible Quote"),
_s("Use TTS to read the descriptions (if TTS is available)"),
"tts_enabled_objects",
false,
0,
0
}
},
{
GAMEOPTION_TTS_SPEECH,
{
_s("Enable Text to Speech for Subtitles"),
_s("Use TTS to read the subtitles (if TTS is available)"),
"tts_enabled_speech",
false,
0,
0
}
},
#endif
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
class DreamWebMetaEngine : public AdvancedMetaEngine<DreamWeb::DreamWebGameDescription> {
public:
const char *getName() const override {
return "dreamweb";
}
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
return gameGuiOptions;
}
Common::Error createInstance(OSystem *syst, Engine **engine, const DreamWeb::DreamWebGameDescription *desc) const override;
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;
Common::String getSavegameFile(int saveGameIdx, const char *target) const override {
if (saveGameIdx == kSavegameFilePattern)
return Common::String::format("DREAMWEB.D##");
else
return Common::String::format("DREAMWEB.D%02d", saveGameIdx);
}
};
bool DreamWebMetaEngine::hasFeature(MetaEngineFeature f) const {
switch(f) {
case kSupportsListSaves:
case kSupportsLoadingDuringStartup:
case kSupportsDeleteSave:
case kSavesSupportMetaInfo:
case kSavesSupportThumbnail:
case kSavesSupportCreationDate:
case kSavesSupportPlayTime:
return true;
default:
return false;
}
}
bool DreamWeb::DreamWebEngine::hasFeature(EngineFeature f) const {
switch(f) {
case kSupportsReturnToLauncher:
return true;
case kSupportsSubtitleOptions:
return _gameDescription->desc.flags & ADGF_CD;
default:
return false;
}
}
Common::Error DreamWebMetaEngine::createInstance(OSystem *syst, Engine **engine, const DreamWeb::DreamWebGameDescription *desc) const {
*engine = new DreamWeb::DreamWebEngine(syst,desc);
return Common::kNoError;
}
SaveStateList DreamWebMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray files = saveFileMan->listSavefiles("DREAMWEB.D##");
SaveStateList saveList;
for (uint i = 0; i < files.size(); ++i) {
const Common::String &file = files[i];
Common::InSaveFile *stream = saveFileMan->openForLoading(file);
if (!stream)
error("cannot open save file %s", file.c_str());
char name[17] = {};
stream->seek(0x61); // The actual description string starts at desc[1]
stream->read(name, sizeof(name) - 1);
delete stream;
int slotNum = atoi(file.c_str() + file.size() - 2);
SaveStateDescriptor sd(this, slotNum, name);
saveList.push_back(sd);
}
// Sort saves based on slot number.
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
int DreamWebMetaEngine::getMaximumSaveSlot() const { return 99; }
bool DreamWebMetaEngine::removeSaveState(const char *target, int slot) const {
Common::String fileName = Common::String::format("DREAMWEB.D%02d", slot);
return g_system->getSavefileManager()->removeSavefile(fileName);
}
SaveStateDescriptor DreamWebMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::String filename = Common::String::format("DREAMWEB.D%02d", slot);
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
if (in) {
DreamWeb::FileHeader header;
in->read((uint8 *)&header, sizeof(DreamWeb::FileHeader));
char name[17] = {};
in->skip(1); // The actual description string starts at desc[1]
in->read(name, sizeof(name) - 1);
SaveStateDescriptor desc(this, slot, name);
// Check if there is a ScummVM data block
if (header.len(6) == SCUMMVM_BLOCK_MAGIC_SIZE) {
// Skip the game data
for (byte i = 1; i <= 5; i++)
in->skip(header.len(i));
uint32 tag = in->readUint32BE();
if (tag != SCUMMVM_HEADER) {
warning("ScummVM data block found, but the block header is incorrect - skipping");
delete in;
return desc;
}
byte version = in->readByte();
if (version > SAVEGAME_VERSION) {
warning("ScummVM data block found, but it has been saved with a newer version of ScummVM - skipping");
delete in;
return desc;
}
uint32 saveDate = in->readUint32LE();
uint32 saveTime = in->readUint32LE();
uint32 playTime = in->readUint32LE();
Graphics::Surface *thumbnail;
if (!Graphics::loadThumbnail(*in, thumbnail)) {
warning("Missing or broken thumbnail - skipping");
delete in;
return desc;
}
int day = (saveDate >> 24) & 0xFF;
int month = (saveDate >> 16) & 0xFF;
int year = saveDate & 0xFFFF;
int hour = (saveTime >> 16) & 0xFF;
int minutes = (saveTime >> 8) & 0xFF;
desc.setSaveDate(year, month, day);
desc.setSaveTime(hour, minutes);
desc.setPlayTime(playTime * 1000);
desc.setThumbnail(thumbnail);
}
delete in;
return desc;
}
return SaveStateDescriptor();
}
#if PLUGIN_ENABLED_DYNAMIC(DREAMWEB)
REGISTER_PLUGIN_DYNAMIC(DREAMWEB, PLUGIN_TYPE_ENGINE, DreamWebMetaEngine);
#else
REGISTER_PLUGIN_STATIC(DREAMWEB, PLUGIN_TYPE_ENGINE, DreamWebMetaEngine);
#endif
namespace DreamWeb {
Common::Error DreamWebEngine::loadGameState(int slot) {
return Common::kNoError;
}
Common::Error DreamWebEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
return Common::kNoError;
}
Common::Language DreamWebEngine::getLanguage() const {
return _gameDescription->desc.language;
}
bool DreamWebEngine::isCD() {
return _gameDescription->desc.flags & ADGF_CD;
}
} // End of namespace DreamWeb

View File

@@ -0,0 +1,37 @@
MODULE := engines/dreamweb
MODULE_OBJS := \
backdrop.o \
console.o \
dreamweb.o \
keypad.o \
metaengine.o \
monitor.o \
mouse.o \
newplace.o \
object.o \
pathfind.o \
people.o \
print.o \
rain.o \
rnca_archive.o \
saveload.o \
sound.o \
sprite.o \
stubs.o \
talk.o \
titles.o \
use.o \
vgafades.o \
vgagrafx.o
# This module can be built as a plugin
ifeq ($(ENABLE_DREAMWEB), DYNAMIC_PLUGIN)
PLUGIN := 1
endif
# Include common rules
include $(srcdir)/rules.mk
# Detection objects
DETECT_OBJS += $(MODULE)/detection.o

View File

@@ -0,0 +1,783 @@
/* 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 "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
namespace DreamWeb {
struct MonitorKeyEntry {
uint8 keyAssigned;
char username[12];
char password[12];
};
// New monitor key list
static MonitorKeyEntry monitorKeyEntries[4] = {
{ 1, "PUBLIC", "PUBLIC" },
{ 0, "RYAN", "BLACKDRAGON" },
{ 0, "LOUIS", "HENDRIX" },
{ 0, "BECKETT", "SEPTIMUS" }
};
void DreamWebEngine::useMon() {
_vars._lastTrigger = 0;
_currentFile[0] = 34;
memset(_currentFile+1, ' ', 12);
_currentFile[13] = 0;
monitorKeyEntries[0].keyAssigned = 1;
monitorKeyEntries[1].keyAssigned = 0;
monitorKeyEntries[2].keyAssigned = 0;
monitorKeyEntries[3].keyAssigned = 0;
createPanel();
showPanel();
showIcon();
drawFloor();
getRidOfAll();
loadGraphicsFile(_monitorGraphics, "G03"); // mon. graphic name
loadPersonal();
loadNews();
loadCart();
loadGraphicsFile(_monitorCharset, "C01"); // character set 2
printOuterMon();
initialMonCols();
printLogo();
workToScreen();
turnOnPower();
fadeUpYellows();
fadeUpMonFirst();
_monAdX = 76;
_monAdY = 141;
monMessage(1);
hangOnCurs(120);
monMessage(2);
randomAccess(60);
monMessage(3);
hangOnCurs(100);
printLogo();
scrollMonitor();
_bufferIn = 0;
_bufferOut = 0;
bool stop = false;
do {
uint16 oldMonadx = _monAdX;
uint16 oldMonady = _monAdY;
input();
_monAdX = oldMonadx;
_monAdY = oldMonady;
stop = execCommand();
if (_quitRequested) //TODO : Check why it crashes when put before the execcommand
break;
} while (!stop);
_monitorGraphics.clear();
_monitorCharset.clear();
_textFile1.clear();
_textFile2.clear();
_textFile3.clear();
_getBack = 1;
_sound->playChannel1(26);
_manIsOffScreen = 0;
restoreAll();
redrawMainScrn();
workToScreenM();
}
int DreamWebEngine::findCommand(const char *const cmdList[]) {
// Loop over all commands in the list and see if we get a match
int cmd = 0;
while (cmdList[cmd] != nullptr) {
const char *cmdStr = cmdList[cmd];
const char *inputStr = _inputLine;
// Compare the command, char by char, to see if we get a match.
// We only care about the prefix matching, though.
char inputChar, cmdChar;
do {
inputChar = *inputStr; inputStr += 2;
cmdChar = *cmdStr++;
if (cmdChar == 0)
return cmd;
} while (inputChar == cmdChar);
++cmd;
}
return -1;
}
bool DreamWebEngine::execCommand() {
static const char *const comlist[] = {
"EXIT",
"HELP",
"LIST",
"READ",
"LOGON",
"KEYS",
nullptr
};
static const char *const comlistFR[] = {
"SORTIR",
"AIDE",
"LISTE",
"LIRE",
"CONNEXION",
"TOUCHES", // should be CLES but it is translated as TOUCHES in the game...
nullptr
};
static const char *const comlistDE[] = {
"ENDE",
"HILF",
"LISTE",
"LIES",
"ZUGRIFF",
"DATEN",
nullptr
};
static const char *const comlistIT[] = {
"ESCI",
"AIUTO",
"ELENCA",
"LEGGI",
"ACCEDI",
"CHIAVI",
nullptr
};
static const char *const comlistES[] = {
"SALIR",
"AYUDA",
"LISTA",
"LEER",
"ACCESO",
"CLAVES",
nullptr
};
if (_inputLine[0] == 0) {
// No input
scrollMonitor();
return false;
}
int cmd = findCommand(comlist);
if (cmd == -1) {
// This did not match an english command. Try to find a localized one.
switch (getLanguage()) {
case Common::FR_FRA:
cmd = findCommand(comlistFR);
break;
case Common::DE_DEU:
cmd = findCommand(comlistDE);
break;
case Common::IT_ITA:
cmd = findCommand(comlistIT);
break;
case Common::ES_ESP:
cmd = findCommand(comlistES);
break;
default:
break;
}
}
// Execute the selected command
switch (cmd) {
case 0:
return true;
case 1:
monMessage(6);
// An extra addition in ScummVM: available commands.
// Since the reference to the game manual is a form of copy protection,
// this extra text is wrapped around the common copy protection check,
// to keep it faithful to the original, if requested.
if (!_copyProtection) {
switch (getLanguage()) {
case Common::FR_FRA:
monPrint("LES COMMANDES VALIDES SONT SORTIR, AIDE, LISTE, LIRE, CONNEXION, TOUCHES");
break;
case Common::DE_DEU:
monPrint("G\232LTIGE BEFEHLE SIND ENDE, HILFE, LISTE, LIES, ZUGRIFF, DATEN");
break;
case Common::IT_ITA:
monPrint("I COMANDI VALIDI SONO ESCI, AIUTO, ELENCA, LEGGI, ACCEDI, CHIAVI");
break;
case Common::ES_ESP:
default:
monPrint("VALID COMMANDS ARE EXIT, HELP, LIST, READ, LOGON, KEYS");
break;
}
}
break;
case 2:
dirCom();
break;
case 3:
read();
break;
case 4:
signOn();
break;
case 5:
showKeys();
break;
default:
netError();
break;
}
return false;
}
void DreamWebEngine::monitorLogo() {
if (_logoNum != _oldLogoNum) {
_oldLogoNum = _logoNum;
//fadeDownMon(); // FIXME: Commented out in ASM
printLogo();
printUnderMonitor();
workToScreen();
printLogo();
//fadeUpMon(); // FIXME: Commented out in ASM
printLogo();
_sound->playChannel1(26);
randomAccess(20);
} else {
printLogo();
}
}
void DreamWebEngine::printLogo() {
showFrame(_monitorGraphics, 56, 32, 0, 0);
showCurrentFile();
}
void DreamWebEngine::input() {
memset(_inputLine, 0, sizeof(_inputLine));
_curPos = 0;
printChar(_monitorCharset, _monAdX, _monAdY, '>', 0, nullptr, nullptr);
multiDump(_monAdX, _monAdY, 6, 8);
_monAdX += 6;
_cursLocX = _monAdX;
_cursLocY = _monAdY;
while (true) {
printCurs();
waitForVSync();
delCurs();
readKey();
if (_quitRequested)
return;
uint8 currentKey = _currentKey;
if (currentKey == 0)
continue;
if (currentKey == 13)
return;
if (currentKey == 8) {
if (_curPos > 0)
delChar();
continue;
}
if (_curPos == 28)
continue;
if ((currentKey == 32) && (_curPos == 0))
continue;
currentKey = makeCaps(currentKey);
_inputLine[_curPos * 2 + 0] = currentKey;
if (currentKey > 'Z')
continue;
multiGet(_mapStore + _curPos * 256, _monAdX, _monAdY, 8, 8);
uint8 charWidth;
printChar(_monitorCharset, _monAdX, _monAdY, currentKey, 0, &charWidth, nullptr);
_inputLine[_curPos * 2 + 1] = charWidth;
_monAdX += charWidth;
++_curPos;
_cursLocX += charWidth;
}
}
byte DreamWebEngine::makeCaps(byte c) {
// TODO: Replace calls to this by toupper() ?
if (c >= 'a')
c -= 'a' - 'A'; // = 32
return c;
}
void DreamWebEngine::delChar() {
--_curPos;
_inputLine[_curPos * 2] = 0;
uint8 width = _inputLine[_curPos * 2 + 1];
_monAdX -= width;
_cursLocX -= width;
uint16 offset = _curPos;
offset = ((offset & 0x00ff) << 8) | ((offset & 0xff00) >> 8);
multiPut(_mapStore + offset, _monAdX, _monAdY, 8, 8);
multiDump(_monAdX, _monAdY, 8, 8);
}
void DreamWebEngine::printCurs() {
uint16 x = _cursLocX;
uint16 y = _cursLocY;
uint16 height;
if (_foreignRelease) {
y -= 3;
height = 11;
} else
height = 8;
multiGet(_textUnder, x, y, 6, height);
++_mainTimer;
if ((_mainTimer & 16) == 0)
showFrame(_monitorCharset, x, y, '/' - 32, 0);
multiDump(x - (getLanguage() == Common::RU_RUS ? 7 : 6), y, 12, height);
}
void DreamWebEngine::delCurs() {
uint16 x = _cursLocX;
uint16 y = _cursLocY;
uint16 width = 6;
uint16 height;
if (_foreignRelease) {
y -= 3;
height = 11;
} else
height = 8;
multiPut(_textUnder, x, y, width, height);
multiDump(x, y, width, height);
}
void DreamWebEngine::scrollMonitor() {
printLogo();
printUnderMonitor();
workToScreen();
_sound->playChannel1(25);
}
void DreamWebEngine::showCurrentFile() {
uint16 x;
// Monitor Frame position differs between Floppy and CD version
if (isCD())
x = 178;
else
x = 199;
const char *currentFile = _currentFile + 1;
while (*currentFile) {
char c = *currentFile++;
c = modifyChar(c);
printChar(_monitorCharset, &x, 37, c, 0, nullptr, nullptr);
}
}
void DreamWebEngine::accessLightOn() {
showFrame(_monitorGraphics, 74, 182, 8, 0);
multiDump(74, 182, 12, 8);
}
void DreamWebEngine::accessLightOff() {
showFrame(_monitorGraphics, 74, 182, 7, 0);
multiDump(74, 182, 12, 8);
}
void DreamWebEngine::randomAccess(uint16 count) {
for (uint16 i = 0; i < count; ++i) {
waitForVSync();
waitForVSync();
uint16 v = _rnd.getRandomNumber(15);
if (v < 10)
accessLightOff();
else
accessLightOn();
}
accessLightOff();
}
void DreamWebEngine::monMessage(uint8 index) {
assert(index > 0);
const char *string = _textFile1._text;
for (uint8 i = 0; i < index; ++i) {
while (*string++ != '+') {
}
}
monPrint(string);
}
void DreamWebEngine::netError() {
monMessage(5);
scrollMonitor();
}
void DreamWebEngine::powerLightOn() {
showFrame(_monitorGraphics, 257+4, 182, 6, 0);
multiDump(257+4, 182, 12, 8);
}
void DreamWebEngine::powerLightOff() {
showFrame(_monitorGraphics, 257+4, 182, 5, 0);
multiDump(257+4, 182, 12, 8);
}
void DreamWebEngine::lockLightOn() {
showFrame(_monitorGraphics, 56, 182, 10, 0);
multiDump(58, 182, 12, 8);
}
void DreamWebEngine::lockLightOff() {
showFrame(_monitorGraphics, 56, 182, 9, 0);
multiDump(58, 182, 12, 8);
}
void DreamWebEngine::turnOnPower() {
for (uint i = 0; i < 3; ++i) {
powerLightOn();
hangOn(30);
powerLightOff();
hangOn(30);
}
powerLightOn();
}
void DreamWebEngine::printOuterMon() {
showFrame(_monitorGraphics, 40, 32, 1, 0);
showFrame(_monitorGraphics, 264, 32, 2, 0);
showFrame(_monitorGraphics, 40, 12, 3, 0);
showFrame(_monitorGraphics, 40, 164, 4, 0);
}
void DreamWebEngine::loadPersonal() {
if (_vars._location == 0 || _vars._location == 42)
loadTextFile(_textFile1, "T01"); // monitor file 1
else
loadTextFile(_textFile1, "T02"); // monitor file 2
}
void DreamWebEngine::loadNews() {
// textfile2 holds information accessible by anyone
if (_vars._newsItem == 0)
loadTextFile(_textFile2, "T10"); // monitor file 10
else if (_vars._newsItem == 1)
loadTextFile(_textFile2, "T11"); // monitor file 11
else if (_vars._newsItem == 2)
loadTextFile(_textFile2, "T12"); // monitor file 12
else
loadTextFile(_textFile2, "T13"); // monitor file 13
}
void DreamWebEngine::loadCart() {
byte cartridgeId = 0;
uint16 objectIndex = findSetObject("INTF");
uint16 cartridgeIndex = checkInside(objectIndex, 1);
if (cartridgeIndex != kNumexobjects)
cartridgeId = getExAd(cartridgeIndex)->objId[3] + 1;
if (cartridgeId == 0)
loadTextFile(_textFile3, "T20"); // monitor file 20
else if (cartridgeId == 1)
loadTextFile(_textFile3, "T21"); // monitor file 21
else if (cartridgeId == 2)
loadTextFile(_textFile3, "T22"); // monitor file 22
else if (cartridgeId == 3)
loadTextFile(_textFile3, "T23"); // monitor file 23
else
loadTextFile(_textFile3, "T24"); // monitor file 24
}
void DreamWebEngine::showKeys() {
randomAccess(10);
scrollMonitor();
monMessage(18);
for (int i = 0; i < 4; i++) {
if (monitorKeyEntries[i].keyAssigned)
monPrint(monitorKeyEntries[i].username);
}
scrollMonitor();
}
const char *DreamWebEngine::getKeyAndLogo(const char *foundString) {
byte newLogo = foundString[1] - 48;
byte keyNum = foundString[3] - 48;
if (monitorKeyEntries[keyNum].keyAssigned == 1) {
// Key OK
_logoNum = newLogo;
return foundString + 4;
} else {
monMessage(12); // "Access denied, key required -"
monPrint(monitorKeyEntries[keyNum].username);
scrollMonitor();
return nullptr;
}
}
const char *DreamWebEngine::searchForString(const char *topic, const char *text) {
char delim = *topic;
while (true) {
const char *s = topic;
int delimCount = 0;
char c;
do {
c = makeCaps(*text++);
if (c == '*' || (delim == '=' && c == 34))
return nullptr;
if (c == delim) {
delimCount++;
if (delimCount == 2)
return text;
}
} while (c == *s++);
}
}
void DreamWebEngine::dirCom() {
randomAccess(30);
const char *dirname = parser();
if (dirname[1]) {
dirFile(dirname);
return;
}
_logoNum = 0;
memcpy(_currentFile+1, "ROOT ", 12);
monitorLogo();
scrollMonitor();
monMessage(9);
searchForFiles(_textFile1._text);
searchForFiles(_textFile2._text);
searchForFiles(_textFile3._text);
scrollMonitor();
}
void DreamWebEngine::dirFile(const char *dirName) {
char topic[14];
memcpy(topic, dirName, 14);
topic[0] = 34;
const char *text = _textFile1._text;
const char *found = searchForString(topic, text);
if (!found) {
text = _textFile2._text;
found = searchForString(topic, text);
if (!found) {
text = _textFile3._text;
found = searchForString(topic, text);
}
}
if (found) {
found = getKeyAndLogo(found);
if (!found)
return; // not logged in
} else {
monMessage(7);
return;
}
// "keyok2"
memcpy(_currentFile+1, dirName+1, 12);
monitorLogo();
scrollMonitor();
monMessage(10);
while (true) {
byte curChar = *found++;
if (curChar == 34 || curChar == '*') {
// "endofdir2"
scrollMonitor();
return;
}
if (curChar == '=')
found = monPrint(found);
}
}
void DreamWebEngine::read() {
randomAccess(40);
const char *name = parser();
if (name[1] == 0) {
netError();
return;
}
const char *topic = _currentFile;
const char *text = _textFile1._text;
const char *found = searchForString(topic, text);
if (!found) {
text = _textFile2._text;
found = searchForString(topic, text);
if (!found) {
text = _textFile3._text;
found = searchForString(topic, text);
}
}
if (found) {
if (!getKeyAndLogo(found))
return;
} else {
monMessage(7);
return;
}
// "keyok1"
found = searchForString(name, found);
if (!found) {
_logoNum = _oldLogoNum;
monMessage(11);
return;
}
// "findtopictext"
monitorLogo();
scrollMonitor();
found++;
while (true) {
found = monPrint(found);
if (found[0] == 34 || found[0] == '=' || found[0] == '*') {
// "endoftopic"
scrollMonitor();
return;
}
processTrigger();
randomAccess(24);
}
}
void DreamWebEngine::signOn() {
const char *name = parser();
int8 foundIndex = -1;
Common::String inputLine = name + 1;
inputLine.trim();
for (byte i = 0; i < 4; i++) {
if (inputLine.equalsIgnoreCase(monitorKeyEntries[i].username)) {
// Check if the key has already been assigned
if (monitorKeyEntries[i].keyAssigned) {
monMessage(17);
return;
} else {
foundIndex = i;
break;
}
}
}
if (foundIndex == -1) {
monMessage(13);
return;
}
monMessage(15);
uint16 prevX = _monAdX;
uint16 prevY = _monAdY;
input(); // password input
_monAdX = prevX;
_monAdY = prevY;
// The entered line has zeroes in-between each character
uint32 len = strlen(monitorKeyEntries[foundIndex].password);
bool found = true;
for (uint32 i = 0; i < len; i++) {
if (monitorKeyEntries[foundIndex].password[i] != _inputLine[i * 2]) {
found = false;
break;
}
}
if (!found) {
scrollMonitor();
monMessage(16);
} else {
monMessage(14);
monPrint(monitorKeyEntries[foundIndex].username);
scrollMonitor();
monitorKeyEntries[foundIndex].keyAssigned = 1;
}
}
void DreamWebEngine::searchForFiles(const char *filesString) {
byte curChar;
while (true) {
curChar = filesString[0];
filesString++;
if (curChar == '*')
return; // "endofdir"
if (curChar == 34)
filesString = monPrint(filesString);
}
}
const char *DreamWebEngine::parser() {
char *output = _operand1;
memset(output, 0, sizeof(_operand1));
*output++ = '=';
const char *in = _inputLine;
uint8 c;
// skip command
do {
c = *in++;
in++;
if (!c)
return output;
} while (c != 32);
// skip spaces between command and operand
do {
c = *in++;
in++;
} while (c == 32);
// copy first operand
do {
*output++ = c;
c = *in++;
in++;
if (!c)
return _operand1;
} while (c != 32);
return _operand1;
}
} // End of namespace DreamWeb

170
engines/dreamweb/mouse.cpp Normal file
View File

@@ -0,0 +1,170 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/events.h"
#include "dreamweb/dreamweb.h"
namespace DreamWeb {
void DreamWebEngine::mouseCall(uint16 *x, uint16 *y, uint16 *state) {
processEvents();
Common::Point pos = _eventMan->getMousePos();
*x = CLIP<int16>(pos.x, 15, 298);
*y = CLIP<int16>(pos.y, 15, 184);
unsigned newState = _eventMan->getButtonState();
*state = (newState == _oldMouseState ? 0 : newState);
_oldMouseState = newState;
}
void DreamWebEngine::readMouse() {
_oldButton = _mouseButton;
_mouseButton = readMouseState();
}
uint16 DreamWebEngine::readMouseState() {
_oldX = _mouseX;
_oldY = _mouseY;
uint16 x, y, state;
mouseCall(&x, &y, &state);
_mouseX = x;
_mouseY = y;
return state;
}
void DreamWebEngine::dumpPointer() {
dumpBlink();
multiDump(_delHereX, _delHereY, _delXS, _delYS);
if ((_oldPointerX != _delHereX) || (_oldPointerY != _delHereY))
multiDump(_oldPointerX, _oldPointerY, _pointerXS, _pointerYS);
}
void DreamWebEngine::showPointer() {
showBlink();
uint16 x = _mouseX;
_oldPointerX = _mouseX;
uint16 y = _mouseY;
_oldPointerY = _mouseY;
if (_pickUp == 1) {
const GraphicsFile *frames;
if (_objectType != kExObjectType)
frames = &_freeFrames;
else
frames = &_exFrames;
const Frame *frame = &frames->_frames[(3 * _itemFrame + 1)];
uint8 width = MAX<uint8>(frame->width, 12);
uint8 height = MAX<uint8>(frame->height, 12);
_pointerXS = width;
_pointerYS = height;
uint16 xMin = (x >= width / 2) ? x - width / 2 : 0;
uint16 yMin = (y >= height / 2) ? y - height / 2 : 0;
_oldPointerX = xMin;
_oldPointerY = yMin;
multiGet(_pointerBack, xMin, yMin, width, height);
showFrame(*frames, x, y, 3 * _itemFrame + 1, 128);
showFrame(_icons1, x, y, 3, 128);
} else {
const Frame *frame = &_icons1._frames[_pointerFrame + 20];
uint8 width = MAX<uint8>(frame->width, 12);
uint8 height = MAX<uint8>(frame->height, 12);
_pointerXS = width;
_pointerYS = height;
multiGet(_pointerBack, x, y, width, height);
showFrame(_icons1, x, y, _pointerFrame + 20, 0);
}
}
void DreamWebEngine::delPointer() {
if (_oldPointerX == 0xffff)
return;
_delHereX = _oldPointerX;
_delHereY = _oldPointerY;
_delXS = _pointerXS;
_delYS = _pointerYS;
multiPut(_pointerBack, _delHereX, _delHereY, _pointerXS, _pointerYS);
}
void DreamWebEngine::animPointer() {
if (_pointerMode == 2) {
_pointerFrame = 0;
if ((_realLocation == 14) && (_commandType == 211))
_pointerFrame = 5;
return;
} else if (_pointerMode == 3) {
if (_pointerSpeed != 0) {
--_pointerSpeed;
} else {
_pointerSpeed = 5;
++_pointerCount;
if (_pointerCount == 16)
_pointerCount = 0;
}
_pointerFrame = (_pointerCount <= 8) ? 1 : 2;
return;
}
if (_vars._watchingTime != 0) {
_pointerFrame = 11;
return;
}
_pointerFrame = 0;
if (_inMapArea == 0)
return;
if (_pointerFirstPath == 0)
return;
uint8 flag, flagEx;
getFlagUnderP(&flag, &flagEx);
if (flag < 2)
return;
if (flag >= 128)
return;
if (flag & 4) {
_pointerFrame = 3;
return;
}
if (flag & 16) {
_pointerFrame = 4;
return;
}
if (flag & 2) {
_pointerFrame = 5;
return;
}
if (flag & 8) {
_pointerFrame = 6;
return;
}
_pointerFrame = 8;
}
void DreamWebEngine::checkCoords(const RectWithCallback *rectWithCallbacks) {
if (_newLocation != 0xff)
return;
const RectWithCallback *r;
for (r = rectWithCallbacks; r->_xMin != 0xffff; ++r) {
if (r->contains(_mouseX, _mouseY)) {
(this->*(r->_callback))();
return;
}
}
}
} // End of namespace DreamWeb

View File

@@ -0,0 +1,280 @@
/* 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 "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
#include "common/text-to-speech.h"
#include "common/config-manager.h"
namespace DreamWeb {
void DreamWebEngine::newPlace() {
if (_vars._needToTravel == 1) {
_vars._needToTravel = 0;
selectLocation();
} else if (_autoLocation != 0xFF) {
_newLocation = _autoLocation;
_autoLocation = 0xFF;
}
}
void DreamWebEngine::selectLocation() {
_inMapArea = 0;
clearBeforeLoad();
_getBack = 0;
_pointerFrame = 22;
readCityPic();
showCity();
_cityGraphics.clear();
readDestIcon();
loadTravelText();
showPanel();
showMan();
showArrows();
showExit();
locationPic();
underTextLine();
_commandType = 255;
readMouse();
_pointerFrame = 0;
showPointer();
workToScreen();
_sound->playChannel0(9, 255);
_newLocation = 255;
while (_newLocation == 255) {
if (_quitRequested)
break;
delPointer();
readMouse();
showPointer();
waitForVSync();
dumpPointer();
dumpTextLine();
if (_getBack == 1)
break;
RectWithCallback destList[] = {
{ 238,258,4,44,&DreamWebEngine::nextDest },
{ 104,124,4,44,&DreamWebEngine::lastDest },
{ 280,308,4,44,&DreamWebEngine::lookAtPlace },
{ 104,216,138,192,&DreamWebEngine::destSelect },
{ 273,320,157,198,&DreamWebEngine::getBack1 },
{ 0,320,0,200,&DreamWebEngine::blank },
{ 0xFFFF,0,0,0,nullptr }
};
checkCoords(destList);
}
if (_quitRequested || _getBack == 1 || _newLocation == _vars._location) {
_newLocation = _realLocation;
_getBack = 0;
}
_newplaceGraphics.clear();
_newplaceGraphics2.clear();
_newplaceGraphics3.clear();
_travelText.clear();
}
void DreamWebEngine::showCity() {
clearWork();
showFrame(_cityGraphics, 57, 32, 0, 0);
showFrame(_cityGraphics, 120+57, 32, 1, 0);
}
void DreamWebEngine::lookAtPlace() {
commandOnlyCond(27, 224);
if (!(_mouseButton & 1) ||
_mouseButton == _oldButton ||
_destPos >= 15)
return; // noinfo
delPointer();
delTextLine();
getUnderCenter();
showFrame(_newplaceGraphics3, 60, 72, 0, 0);
showFrame(_newplaceGraphics3, 60, 72 + 55, 4, 0);
if (_foreignRelease)
showFrame(_newplaceGraphics3, 60, 72+55+21, 4, 0);
const uint8 *string = (const uint8 *)_travelText.getString(_destPos);
findNextColon(&string);
if (_ttsMan != nullptr && ConfMan.getBool("tts_enabled_objects"))
_ttsMan->say((const char *)string, _textEncoding);
uint16 y = (_foreignRelease) ? 84 + 4 : 84;
printDirect(&string, 63, &y, 191, 191 & 1);
workToScreenM();
hangOnP(500);
_pointerMode = 0;
_pointerFrame = 0;
putUnderCenter();
workToScreenM();
}
void DreamWebEngine::getUnderCenter() {
multiGet(_mapStore, 58, 72, 254, 110);
}
void DreamWebEngine::putUnderCenter() {
multiPut(_mapStore, 58, 72, 254, 110);
}
void DreamWebEngine::locationPic() {
const int roomPics[] = { 5, 0, 3, 2, 4, 1, 10, 9, 8, 6, 11, 4, 7, 7, 0, 0 };
byte picture = roomPics[_destPos];
if (picture >= 6)
showFrame(_newplaceGraphics2, 104, 138 + 14, picture - 6, 0); // Second slot
else
showFrame(_newplaceGraphics, 104, 138 + 14, picture + 4, 0);
if (_destPos == _realLocation)
showFrame(_newplaceGraphics, 104, 140 + 14, 3, 0); // Currently in this location
const uint8 *string = (const uint8 *)_travelText.getString(_destPos);
printDirect(string, 50, 20, 241, 241 & 1);
speakObject((const char *)string);
}
void DreamWebEngine::showArrows() {
showFrame(_newplaceGraphics, 116 - 12, 16, 0, 0);
showFrame(_newplaceGraphics, 226 + 12, 16, 1, 0);
showFrame(_newplaceGraphics, 280, 14, 2, 0);
}
void DreamWebEngine::nextDest() {
commandOnlyCond(28, 218);
if (!(_mouseButton & 1) || _oldButton == 1)
return; // nodu
do {
_destPos++;
if (_destPos == 15)
_destPos = 0; // last destination
} while (!getLocation(_destPos));
_newTextLine = 1;
delTextLine();
delPointer();
showPanel();
showMan();
showArrows();
locationPic();
underTextLine();
readMouse();
showPointer();
workToScreen();
delPointer();
}
void DreamWebEngine::lastDest() {
commandOnlyCond(29, 219);
if (!(_mouseButton & 1) || _oldButton == 1)
return; // nodd
do {
_destPos--;
if (_destPos == 0xFF)
_destPos = 15; // first destination
} while (!getLocation(_destPos));
_newTextLine = 1;
delTextLine();
delPointer();
showPanel();
showMan();
showArrows();
locationPic();
underTextLine();
readMouse();
showPointer();
workToScreen();
delPointer();
}
void DreamWebEngine::destSelect() {
commandOnlyCond(30, 222);
if (!(_mouseButton & 1) || _oldButton == 1)
return; // notrav
_newLocation = _destPos;
}
uint8 DreamWebEngine::getLocation(uint8 index) {
return _roomsCanGo[index];
}
void DreamWebEngine::setLocation(uint8 index) {
_roomsCanGo[index] = 1;
}
void DreamWebEngine::clearLocation(uint8 index) {
_roomsCanGo[index] = 0;
}
void DreamWebEngine::resetLocation(uint8 index) {
if (index == 5) {
// delete hotel
purgeALocation(5);
purgeALocation(21);
purgeALocation(22);
purgeALocation(27);
} else if (index == 8) {
// delete TV studio
purgeALocation(8);
purgeALocation(28);
} else if (index == 6) {
// delete sarters
purgeALocation(6);
purgeALocation(20);
purgeALocation(25);
} else if (index == 13) {
// delete boathouse
purgeALocation(13);
purgeALocation(29);
}
clearLocation(index);
}
void DreamWebEngine::readDestIcon() {
loadGraphicsFile(_newplaceGraphics, "G05");
loadGraphicsFile(_newplaceGraphics2, "G06");
loadGraphicsFile(_newplaceGraphics3, "G08");
}
void DreamWebEngine::readCityPic() {
loadGraphicsFile(_cityGraphics, "G04");
}
} // End of namespace DreamWeb

1260
engines/dreamweb/object.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,349 @@
/* 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 "dreamweb/dreamweb.h"
namespace DreamWeb {
void DreamWebEngine::turnPathOn(uint8 param) {
findOrMake(param, 0xff, _roomNum + 100);
PathNode *roomsPaths = getRoomsPaths()->nodes;
if (param == 0xff)
return;
roomsPaths[param].on = 0xff;
}
void DreamWebEngine::turnPathOff(uint8 param) {
findOrMake(param, 0x00, _roomNum + 100);
PathNode *roomsPaths = getRoomsPaths()->nodes;
if (param == 0xff)
return;
roomsPaths[param].on = 0x00;
}
void DreamWebEngine::turnAnyPathOn(uint8 param, uint8 room) {
findOrMake(param, 0xff, room + 100);
_pathData[room].nodes[param].on = 0xff;
}
void DreamWebEngine::turnAnyPathOff(uint8 param, uint8 room) {
findOrMake(param, 0x00, room + 100);
_pathData[room].nodes[param].on = 0x00;
}
RoomPaths *DreamWebEngine::getRoomsPaths() {
return &_pathData[_roomNum];
}
void DreamWebEngine::faceRightWay() {
PathNode *paths = getRoomsPaths()->nodes;
uint8 dir = paths[_mansPath].dir;
_turnToFace = dir;
_leaveDirection = dir;
}
void DreamWebEngine::setWalk() {
if (_linePointer != 254) {
// Already walking
_finalDest = _pointersPath;
} else if (_pointersPath == _mansPath) {
// Can't walk
faceRightWay();
} else if (_vars._watchMode == 1) {
// Holding reel
_vars._destAfterHold = _pointersPath;
_vars._watchMode = 2;
} else if (_vars._watchMode == 2) {
// Can't walk
} else {
_destination = _pointersPath;
_finalDest = _pointersPath;
if (_mouseButton != 2 || _commandType == 3) {
autoSetWalk();
} else {
_walkAndExam = 1;
_walkExamType = _commandType;
_walkExamNum = _command;
autoSetWalk();
}
}
}
void DreamWebEngine::autoSetWalk() {
if (_finalDest == _mansPath)
return;
const RoomPaths *roomsPaths = getRoomsPaths();
checkDest(roomsPaths);
_lineStartX = roomsPaths->nodes[_mansPath].x - 12;
_lineStartY = roomsPaths->nodes[_mansPath].y - 12;
_lineEndX = roomsPaths->nodes[_destination].x - 12;
_lineEndY = roomsPaths->nodes[_destination].y - 12;
bresenhams();
if (_lineDirection != 0) {
_linePointer = _lineLength - 1;
_lineDirection = 1;
return;
}
_linePointer = 0;
}
void DreamWebEngine::checkDest(const RoomPaths *roomsPaths) {
const PathSegment *segments = roomsPaths->segments;
const uint8 tmp = _mansPath << 4;
uint8 destination = _destination;
for (uint i = 0; i < 24; ++i) {
if ((segments[i].b0 & 0xf0) == tmp &&
(segments[i].b0 & 0x0f) == _destination) {
_destination = segments[i].b1 & 0x0f;
return;
}
if (((segments[i].b0 & 0x0f) << 4) == tmp &&
((segments[i].b0 & 0xf0) >> 4) == _destination) {
destination = segments[i].b1 & 0x0f;
}
}
_destination = destination;
}
void DreamWebEngine::findXYFromPath() {
const PathNode *roomsPaths = getRoomsPaths()->nodes;
_ryanX = roomsPaths[_mansPath].x - 12;
_ryanY = roomsPaths[_mansPath].y - 12;
}
bool DreamWebEngine::checkIfPathIsOn(uint8 index) {
RoomPaths *roomsPaths = getRoomsPaths();
uint8 pathOn = roomsPaths->nodes[index].on;
return pathOn == 0xff;
}
void DreamWebEngine::bresenhams() {
workoutFrames();
Common::Point *lineData = &_lineData[0];
int16 startX = (int16)_lineStartX;
int16 startY = (int16)_lineStartY;
int16 endX = (int16)_lineEndX;
int16 endY = (int16)_lineEndY;
if (endX == startX) {
uint16 deltaY;
int8 y;
if (endY < startY) {
deltaY = startY - endY;
y = (int8)endY;
_lineDirection = 1;
} else {
deltaY = endY - startY;
y = (int8)startY;
_lineDirection = 0;
}
++deltaY;
int8 x = (int8)startX;
_lineLength = deltaY;
for (; deltaY; --deltaY) {
lineData->x = x;
lineData->y = y;
++lineData;
++y;
}
return;
}
uint16 deltaX;
if (endX < startX) {
deltaX = startX - endX;
SWAP(startX, endX);
SWAP(startY, endY);
_lineStartX = (uint16)startX;
_lineStartY = (uint16)startY;
_lineEndX = (uint16)endX;
_lineEndY = (uint16)endY;
_lineDirection = 1;
} else {
deltaX = endX - startX;
_lineDirection = 0;
}
int16 increment;
if (endY == startY) {
int8 x = (int8)startX;
int8 y = (int8)startY;
++deltaX;
_lineLength = deltaX;
for (; deltaX; --deltaX) {
lineData->x = x;
lineData->y = y;
++lineData;
++x;
}
return;
}
uint16 deltaY;
if (startY > endY) {
deltaY = startY - endY;
increment = -1;
} else {
deltaY = endY - startY;
increment = 1;
}
uint16 delta1, delta2;
byte lineRoutine;
if (deltaY > deltaX) {
lineRoutine = 1;
delta1 = deltaY;
delta2 = deltaX;
} else {
lineRoutine = 0;
delta1 = deltaX;
delta2 = deltaY;
}
uint16 increment1 = delta2 * 2;
uint16 increment2 = delta2 * 2 - delta1 * 2;
int16 remainder = delta2 * 2 - delta1;
++delta1;
int8 x = (int8)startX;
int8 y = (int8)startY;
_lineLength = delta1;
if (lineRoutine != 1) {
for (; delta1; --delta1) {
lineData->x = x;
lineData->y = y;
++lineData;
++x;
if (remainder < 0) {
remainder += increment1;
} else {
remainder += increment2;
y += increment;
}
}
} else {
for (; delta1; --delta1) {
lineData->x = x;
lineData->y = y;
++lineData;
y += increment;
if (remainder < 0) {
remainder += increment1;
} else {
remainder += increment2;
++x;
}
}
}
}
void DreamWebEngine::workoutFrames() {
byte tmp;
int diffx, diffy;
// We have to use signed arithmetic here because these values can
// be slightly negative when walking off-screen
int lineStartX = (int16)_lineStartX;
int lineStartY = (int16)_lineStartY;
int lineEndX = (int16)_lineEndX;
int lineEndY = (int16)_lineEndY;
diffx = ABS(lineStartX - lineEndX);
diffy = ABS(lineStartY - lineEndY);
if (diffx < diffy) {
tmp = 2;
if (diffx >= (diffy >> 1))
tmp = 1;
} else {
// tendstohoriz
tmp = 0;
if (diffy >= (diffx >> 1))
tmp = 1;
}
if (lineStartX >= lineEndX) {
// isinleft
if (lineStartY < lineEndY) {
if (tmp != 1)
tmp ^= 2;
tmp += 4;
} else {
// topleft
tmp += 6;
}
} else {
// isinright
if (lineStartY < lineEndY) {
tmp += 2;
} else {
// botright
if (tmp != 1)
tmp ^= 2;
}
}
_turnToFace = tmp & 7;
_turnDirection = 0;
}
byte DreamWebEngine::findFirstPath(byte x, byte y) {
PathNode *paths = _pathData[_roomNum].nodes;
for (uint8 index = 0; index < 12; index++) {
if (paths[index].x1 == 0xff && paths[index].y1 == 0xff)
continue; // "nofirst"
if (x < paths[index].x1 || y < paths[index].y1)
continue; // "nofirst"
if (x >= paths[index].x2 || y >= paths[index].y2)
continue; // "nofirst"
return paths[index].on; // "gotfirst"
}
return 0;
}
byte DreamWebEngine::findPathOfPoint(byte x, byte y) {
PathNode *paths = _pathData[_roomNum].nodes;
for (uint8 index = 0; index < 12; index++) {
if (paths[index].on != 0xff)
continue; // "flunkedit"
if (paths[index].x1 == 0xff && paths[index].y1 == 0xff)
continue; // "flunkedit"
if (x < paths[index].x1 || y < paths[index].y1)
continue; // "flunkedit"
if (x >= paths[index].x2 || y >= paths[index].y2)
continue; // "flunkedit"
return index; // "gotvalidpath"
}
return 0xff;
}
} // End of namespace DreamWeb

1123
engines/dreamweb/people.cpp Normal file

File diff suppressed because it is too large Load Diff

348
engines/dreamweb/print.cpp Normal file
View File

@@ -0,0 +1,348 @@
/* 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 "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
namespace DreamWeb {
void DreamWebEngine::printBoth(const GraphicsFile &charSet, uint16 *x, uint16 y, uint8 c, uint8 nextChar) {
uint16 newX = *x;
uint8 width, height;
printChar(charSet, &newX, y, c, nextChar, &width, &height);
multiDump(*x, y, width, height);
*x = newX;
}
uint8 DreamWebEngine::getNextWord(const GraphicsFile &charSet, const uint8 *string, uint8 *totalWidth, uint8 *charCount) {
*totalWidth = 0;
*charCount = 0;
while (true) {
uint8 firstChar = *string;
++string;
++*charCount;
if ((firstChar == ':') || (firstChar == 0)) { //endall
*totalWidth += 6;
return 1;
}
if (firstChar == 32) { //endword
*totalWidth += 6;
return 0;
}
firstChar = modifyChar(firstChar);
// WORKAROUND: Also filter out invalid characters here (refer to the
// workaround in printChar() below for more info).
if (firstChar >= 32 && firstChar != 255) {
uint8 secondChar = *string;
uint8 width = charSet._frames[firstChar - 32 + _charShift].width;
width = kernChars(firstChar, secondChar, width);
*totalWidth += width;
}
}
}
void DreamWebEngine::printChar(const GraphicsFile &charSet, uint16* x, uint16 y, uint8 c, uint8 nextChar, uint8 *width, uint8 *height, bool kerning) {
// WORKAROUND: Some texts contain leftover tab characters, which will cause
// OOB memory access when showing a character, as all the printable ones are
// from 32 onwards. We compensate for that here by ignoring all the invalid
// characters (0 - 31).
if (c < 32 || c == 255)
return;
uint8 dummyWidth, dummyHeight;
if (width == nullptr)
width = &dummyWidth;
if (height == nullptr)
height = &dummyHeight;
if (_foreignRelease)
y -= 3;
uint16 tmp = c - 32 + _charShift;
showFrame(charSet, *x, y, tmp & 0x1ff, (tmp >> 8) & 0xfe, width, height);
if (!kerning)
*width = kernChars(c, nextChar, *width);
(*x) += *width;
}
void DreamWebEngine::printChar(const GraphicsFile &charSet, uint16 x, uint16 y, uint8 c, uint8 nextChar, uint8 *width, uint8 *height) {
printChar(charSet, &x, y, c, nextChar, width, height);
}
uint8 DreamWebEngine::printSlow(const uint8 *string, uint16 x, uint16 y, uint8 maxWidth, bool centered) {
_pointerFrame = 1;
_pointerMode = 3;
do {
uint16 offset = x;
uint16 charCount = getNumber(_charset1, string, maxWidth, centered, &offset);
do {
uint8 c0 = string[0];
uint8 c1 = string[1];
uint8 c2 = string[2];
c0 = modifyChar(c0);
printBoth(_charset1, &offset, y, c0, c1);
if ((c1 == 0) || (c1 == ':')) {
return 0;
}
if (charCount != 1) {
c1 = modifyChar(c1);
_charShift = getLanguage() == Common::RU_RUS ? 182 : 91;
uint16 offset2 = offset;
printBoth(_charset1, &offset2, y, c1, c2);
_charShift = 0;
for (int i=0; i<2; ++i) {
uint16 mouseState = waitFrames();
if (_quitRequested)
return 0;
if (mouseState == 0)
continue;
if (mouseState != _oldButton) {
return 1;
}
}
}
++string;
--charCount;
} while (charCount);
y += 10;
} while (true);
}
uint8 DreamWebEngine::printDirect(const uint8* string, uint16 x, uint16 y, uint8 maxWidth, bool centered) {
return printDirect(&string, x, &y, maxWidth, centered);
}
uint8 DreamWebEngine::printDirect(const uint8** string, uint16 x, uint16 *y, uint8 maxWidth, bool centered, bool kerning) {
_lastXPos = x;
const GraphicsFile &charSet = *_currentCharset;
while (true) {
uint16 offset = x;
uint8 charCount = getNumber(charSet, *string, maxWidth, centered, &offset);
uint16 i = offset;
do {
uint8 c = (*string)[0];
++(*string);
if ((c == 0) || (c == ':')) {
return c;
}
uint8 nextChar = (*string)[0];
c = modifyChar(c);
uint8 width, height;
printChar(charSet, &i, *y, c, nextChar, &width, &height);
_lastXPos = i;
--charCount;
} while (charCount);
*y += _lineSpacing;
}
}
uint8 DreamWebEngine::getNumber(const GraphicsFile &charSet, const uint8 *string, uint16 maxWidth, bool centered, uint16* offset) {
uint8 totalWidth = 0;
uint8 charCount = 0;
while (true) {
uint8 wordTotalWidth, wordCharCount;
uint8 done = getNextWord(charSet, string, &wordTotalWidth, &wordCharCount);
string += wordCharCount;
uint16 tmp = totalWidth + wordTotalWidth - 10;
if (done == 1) { //endoftext
if (tmp < maxWidth) {
totalWidth += wordTotalWidth;
charCount += wordCharCount;
}
if (centered) {
tmp = (maxWidth & 0xfe) + 2 + 20 - totalWidth;
tmp /= 2;
} else {
tmp = 0;
}
*offset += tmp;
return charCount;
}
if (tmp >= maxWidth) { //gotoverend
if (centered) {
tmp = (maxWidth & 0xfe) - totalWidth + 20;
tmp /= 2;
} else {
tmp = 0;
}
*offset += tmp;
return charCount;
}
totalWidth += wordTotalWidth;
charCount += wordCharCount;
}
}
uint8 DreamWebEngine::kernChars(uint8 firstChar, uint8 secondChar, uint8 width) {
if (getLanguage() == Common::RU_RUS) {
if ((firstChar == 'a') || (firstChar == 'u') || (firstChar == 0xa0)
|| (firstChar == 0xa8) || (firstChar == 0xa9) || (firstChar == 0xe9)) {
if ((secondChar == 0xe2) || (secondChar == 'n') || (secondChar == 't') || (secondChar == 'r') || (secondChar == 'i') || (secondChar == 'l'))
return width-1;
}
return width;
}
if ((firstChar == 'a') || (firstChar == 'u')) {
if ((secondChar == 'n') || (secondChar == 't') || (secondChar == 'r') || (secondChar == 'i') || (secondChar == 'l'))
return width-1;
}
return width;
}
uint16 DreamWebEngine::waitFrames() {
readMouse();
showPointer();
waitForVSync();
dumpPointer();
delPointer();
return _mouseButton;
}
const char *DreamWebEngine::monPrint(const char *string) {
uint16 x = _monAdX;
const char *iterator = string;
bool done = false;
while (!done) {
uint16 count = getNumber(_monitorCharset, (const uint8 *)iterator, 166, false, &x);
do {
char c = *iterator++;
if (c == ':')
break;
if ((c == 0) || (c == '"') || (c == '=')) {
done = true;
break;
}
if (c == '%') {
_vars._lastTrigger = *iterator;
iterator += 2;
done = true;
break;
}
c = modifyChar(c);
printChar(_monitorCharset, &x, _monAdY, c, 0, nullptr, nullptr, true);
_cursLocX = x;
_cursLocY = _monAdY;
_mainTimer = 1;
printCurs();
waitForVSync();
lockMon();
delCurs();
} while (--count);
x = _monAdX;
scrollMonitor();
_cursLocX = _monAdX;
}
return iterator;
}
void DreamWebEngine::rollEndCreditsGameWon() {
_sound->playChannel0(16, 255);
_sound->volumeSet(7);
_sound->volumeChange(0, -1);
multiGet(_mapStore, 75, 20, 160, 160);
const uint8 *string = getTextInFile1(3);
const int linespacing = _lineSpacing;
for (int i = 0; i < 254; ++i) {
// Output the text, initially with an offset of 10 pixels,
// then move it up one pixel until we shifted it by a complete
// line of text.
for (int j = 0; j < linespacing; ++j) {
waitForVSync();
multiPut(_mapStore, 75, 20, 160, 160);
waitForVSync();
// Output up to 18 lines of text
uint16 y = 10 - j;
const uint8 *tmp_str = string;
for (int k = 0; k < 18; ++k) {
printDirect(&tmp_str, 75, &y, 160 + 1, true);
y += linespacing;
}
waitForVSync();
multiDump(75, 20, 160, 160);
}
// Skip to the next text line
byte c;
do {
c = *string++;
} while (c != ':' && c != 0);
}
hangOn(100);
panelToMap();
fadeScreenUpHalf();
}
void DreamWebEngine::rollEndCreditsGameLost() {
multiGet(_mapStore, 25, 20, 160, 160);
const uint8 *string = getTextInFile1(49);
const int linespacing = _lineSpacing;
for (int i = 0; i < 80; ++i) {
// Output the text, initially with an offset of 10 pixels,
// then move it up one pixel until we shifted it by a complete
// line of text.
for (int j = 0; j < linespacing; ++j) {
waitForVSync();
multiPut(_mapStore, 25, 20, 160, 160);
waitForVSync();
// Output up to 18 lines of text
uint16 y = 10 - j;
const uint8 *tmp_str = string;
for (int k = 0; k < 18; ++k) {
printDirect(&tmp_str, 25, &y, 160 + 1, true);
y += linespacing;
}
waitForVSync();
multiDump(25, 20, 160, 160);
if (_lastHardKey == Common::KEYCODE_ESCAPE)
return;
}
// Skip to the next text line
byte c;
do {
c = *string++;
} while (c != ':' && c != 0);
if (_lastHardKey == Common::KEYCODE_ESCAPE)
return;
}
hangOne(120);
}
} // End of namespace DreamWeb

191
engines/dreamweb/rain.cpp Normal file
View File

@@ -0,0 +1,191 @@
/* 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 "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
namespace DreamWeb {
void DreamWebEngine::showRain() {
// Do nothing if there's no rain at all
if (_rainList.empty())
return;
const uint8 *frameData = _mainSprites.getFrameData(58);
for (auto &rain : _rainList) {
uint16 y = rain.y + _mapAdY + _mapYStart;
uint16 x = rain.x + _mapAdX + _mapXStart;
uint16 size = rain.size;
uint16 offset = (rain.w3 - rain.b5) & 511;
rain.w3 = offset;
const uint8 *src = frameData + offset;
uint8 *dst = workspace() + y * kScreenwidth + x;
for (uint16 j = 0; j < size; ++j) {
uint8 v = src[j];
if (v != 0)
*dst = v;
dst += kScreenwidth-1; // advance diagonally
}
}
if (_sound->isChannel1Playing())
return;
if (_realLocation == 2 && _vars._beenMugged != 1)
return;
if (_realLocation == 55)
return;
if (randomNumber() >= 1) // play thunder with 1 in 256 chance
return;
uint8 soundIndex;
if (_sound->getChannel0Playing() != 6)
soundIndex = 4;
else
soundIndex = 7;
_sound->playChannel1(soundIndex);
}
uint8 DreamWebEngine::getBlockOfPixel(uint8 x, uint8 y) {
uint8 flag, flagEx, type, flagX, flagY;
checkOne(x + _mapXStart, y + _mapYStart, &flag, &flagEx, &type, &flagX, &flagY);
if (flag & 1)
return 0;
else
return type;
}
void DreamWebEngine::splitIntoLines(uint8 x, uint8 y) {
do {
Rain rain;
// Look for line start
while (!getBlockOfPixel(x, y)) {
--x;
++y;
if (x == 0 || y >= _mapYSize)
return;
}
rain.x = x;
rain.y = y;
uint8 length = 1;
// Look for line end
while (getBlockOfPixel(x, y)) {
--x;
++y;
if (x == 0 || y >= _mapYSize)
break;
++length;
}
rain.size = length;
rain.w3 = _rnd.getRandomNumber(65535);
rain.b5 = _rnd.getRandomNumberRng(4, 7);
_rainList.push_back(rain);
} while (x > 0 && y < _mapYSize);
}
struct RainLocation {
uint8 location;
uint8 x, y;
uint8 rainSpacing;
};
static const RainLocation rainLocationList[] = {
{ 1,44,10,16 },
{ 4,11,30,14 },
{ 4,22,30,14 },
{ 3,33,10,14 },
{ 10,33,30,14 },
{ 10,22,30,24 },
{ 9,22,10,14 },
{ 2,33,0,14 },
{ 2,22,0,14 },
{ 6,11,30,14 },
{ 7,11,20,18 },
{ 7,0,20,18 },
{ 7,0,30,18 },
{ 55,44,0,14 },
{ 5,22,30,14 },
{ 8,0,10,18 },
{ 8,11,10,18 },
{ 8,22,10,18 },
{ 8,33,10,18 },
{ 8,33,20,18 },
{ 8,33,30,18 },
{ 8,33,40,18 },
{ 8,22,40,18 },
{ 8,11,40,18 },
{ 21,44,20,18 },
{ 255,0,0,0 }
};
void DreamWebEngine::initRain() {
const RainLocation *r = rainLocationList;
_rainList.clear();
uint8 rainSpacing = 0;
// look up location in rainLocationList to determine rainSpacing
for (r = rainLocationList; r->location != 0xff; ++r) {
if (r->location == _realLocation &&
r->x == _mapX && r->y == _mapY) {
rainSpacing = r->rainSpacing;
break;
}
}
if (rainSpacing == 0) {
// location not found in rainLocationList: no rain
return;
}
// start lines of rain from top of screen
uint8 x = 4;
do {
uint8 delta = _rnd.getRandomNumberRng(3, rainSpacing - 1);
x += delta;
if (x >= _mapXSize)
break;
splitIntoLines(x, 0);
} while (true);
// start lines of rain from side of screen
uint8 y = 0;
do {
uint8 delta = _rnd.getRandomNumberRng(3, rainSpacing - 1);
y += delta;
if (y >= _mapYSize)
break;
splitIntoLines(_mapXSize - 1, y);
} while (true);
}
} // End of namespace DreamWeb

View File

@@ -0,0 +1,136 @@
/* 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/array.h"
#include "common/compression/deflate.h"
#include "common/debug.h"
#include "common/ptr.h"
#include "common/substream.h"
#include "common/memstream.h"
#include "common/compression/rnc_deco.h"
#include "common/file.h"
#include "dreamweb/rnca_archive.h"
namespace DreamWeb {
RNCAArchive* RNCAArchive::open(Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose) {
FileMap files;
if (stream->readUint32BE() != 0x524e4341)
return nullptr;
uint16 metadataSize1 = stream->readUint16BE();
stream->readUint16BE(); // No idea
uint16 metadataSize2 = stream->readUint16BE();
stream->readByte(); // Always zero
if (metadataSize1 != metadataSize2 || metadataSize1 < 15)
return nullptr;
int headerlessMetadataSize = metadataSize1 - 11;
byte *metadata = new byte[headerlessMetadataSize];
stream->read(metadata, headerlessMetadataSize);
const byte *eptr = metadata;
while (eptr < metadata + headerlessMetadataSize - 5) {
const byte *ptr = eptr;
while (*ptr)
ptr++;
Common::String fileName((const char *) eptr, ptr - eptr);
ptr++;
uint32 off = READ_BE_UINT32(ptr);
eptr = ptr + 4;
files[Common::Path(fileName, Common::Path::kNoSeparator)] = RNCAFileDescriptor(fileName, off);
}
delete[] metadata;
return new RNCAArchive(files, stream, dispose);
}
bool RNCAArchive::hasFile(const Common::Path &path) const {
return _files.contains(translatePath(path));
}
int RNCAArchive::listMembers(Common::ArchiveMemberList &list) const {
for (const auto &file : _files) {
list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(file._key, *this)));
}
return _files.size();
}
const Common::ArchiveMemberPtr RNCAArchive::getMember(const Common::Path &path) const {
Common::Path translated = translatePath(path);
if (!_files.contains(translated))
return nullptr;
return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(_files.getVal(translated)._fileName, *this));
}
Common::SharedArchiveContents RNCAArchive::readContentsForPath(const Common::Path &translated) const {
if (!_files.contains(translated))
return Common::SharedArchiveContents();
const RNCAFileDescriptor& desc = _files.getVal(translated);
_stream->seek(desc._fileDataOffset);
if (_stream->readUint32BE() != Common::RncDecoder::kRnc1Signature) {
return Common::SharedArchiveContents();
}
// Read unpacked/packed file length
uint32 unpackLen = _stream->readUint32BE();
uint32 packLen = _stream->readUint32BE();
if (unpackLen > 0x7ffff000 || packLen > 0x7ffff000) {
debug("Header error for %s", desc._fileName.c_str());
return Common::SharedArchiveContents();
}
// Rewind back the header
_stream->seek(desc._fileDataOffset);
packLen += 0x12;
byte *compressedBuffer = new byte[packLen];
if (_stream->read(compressedBuffer, packLen) != packLen) {
debug("Read error for %s", desc._fileName.c_str());
return Common::SharedArchiveContents();
}
byte *uncompressedBuffer = new byte[unpackLen];
Common::RncDecoder rnc;
if (rnc.unpackM1(compressedBuffer, packLen, uncompressedBuffer) != (int32) unpackLen) {
debug("Unpacking error for %s", desc._fileName.c_str());
return Common::SharedArchiveContents();
}
byte b = 0;
for (byte *ptr = uncompressedBuffer; ptr < uncompressedBuffer + unpackLen; ptr++) {
b += *ptr;
*ptr = b;
}
return Common::SharedArchiveContents(uncompressedBuffer, unpackLen);
}
} // End of namespace DreamWeb

View File

@@ -0,0 +1,66 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef DREAMWEB_RNCA_ARCHIVE_H
#define DREAMWEB_RNCA_ARCHIVE_H
#include "common/archive.h"
#include "common/ptr.h"
#include "common/stream.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
namespace DreamWeb {
class RNCAArchive : public Common::MemcachingCaseInsensitiveArchive {
public:
bool hasFile(const Common::Path &path) const override;
int listMembers(Common::ArchiveMemberList&) const override;
const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
Common::SharedArchiveContents readContentsForPath(const Common::Path &translated) const override;
static RNCAArchive* open(Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose = DisposeAfterUse::NO);
private:
class RNCAFileDescriptor {
private:
Common::String _fileName;
// Offset of the file contents relative to the beginning of RNCA stream
uint32 _fileDataOffset;
RNCAFileDescriptor(const Common::String& filename, uint32 off) : _fileName(filename), _fileDataOffset(off) {}
friend class RNCAArchive;
public:
// It's public for hashmap
RNCAFileDescriptor() : _fileDataOffset(0) {}
};
typedef Common::HashMap<Common::Path, RNCAFileDescriptor, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo> FileMap;
RNCAArchive(FileMap files, Common::SeekableReadStream *stream, DisposeAfterUse::Flag dispose)
: _files(files), _stream(stream, dispose) {
}
FileMap _files;
Common::DisposablePtr<Common::SeekableReadStream> _stream;
};
}
#endif

View File

@@ -0,0 +1,925 @@
/* 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 "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
#include "engines/metaengine.h"
#include "graphics/thumbnail.h"
#include "gui/saveload.h"
#include "common/config-manager.h"
#include "common/translation.h"
#include "common/savefile.h"
#include "common/serializer.h"
namespace DreamWeb {
// Temporary storage for loading the room from a savegame
Room g_madeUpRoomDat;
void syncReelRoutine(Common::Serializer &s, ReelRoutine *reel) {
s.syncAsByte(reel->reallocation);
s.syncAsByte(reel->mapX);
s.syncAsByte(reel->mapY);
s.syncAsUint16LE(reel->_reelPointer);
s.syncAsByte(reel->period);
s.syncAsByte(reel->counter);
s.syncAsByte(reel->b7);
}
void syncGameVars(Common::Serializer &s, GameVars &vars) {
s.syncAsByte(vars._startVars);
s.syncAsByte(vars._progressPoints);
s.syncAsByte(vars._watchOn);
s.syncAsByte(vars._shadesOn);
s.syncAsByte(vars._secondCount);
s.syncAsByte(vars._minuteCount);
s.syncAsByte(vars._hourCount);
s.syncAsByte(vars._zoomOn);
s.syncAsByte(vars._location);
s.syncAsByte(vars._exPos);
s.syncAsUint16LE(vars._exFramePos);
s.syncAsUint16LE(vars._exTextPos);
s.syncAsUint16LE(vars._card1Money);
s.syncAsUint16LE(vars._listPos);
s.syncAsByte(vars._ryanPage);
s.syncAsUint16LE(vars._watchingTime);
s.syncAsUint16LE(vars._reelToWatch);
s.syncAsUint16LE(vars._endWatchReel);
s.syncAsByte(vars._speedCount);
s.syncAsByte(vars._watchSpeed);
s.syncAsUint16LE(vars._reelToHold);
s.syncAsUint16LE(vars._endOfHoldReel);
s.syncAsByte(vars._watchMode);
s.syncAsByte(vars._destAfterHold);
s.syncAsByte(vars._newsItem);
s.syncAsByte(vars._liftFlag);
s.syncAsByte(vars._liftPath);
s.syncAsByte(vars._lockStatus);
s.syncAsByte(vars._doorPath);
s.syncAsByte(vars._countToOpen);
s.syncAsByte(vars._countToClose);
s.syncAsByte(vars._rockstarDead);
s.syncAsByte(vars._generalDead);
s.syncAsByte(vars._sartainDead);
s.syncAsByte(vars._aideDead);
s.syncAsByte(vars._beenMugged);
s.syncAsByte(vars._gunPassFlag);
s.syncAsByte(vars._canMoveAltar);
s.syncAsByte(vars._talkedToAttendant);
s.syncAsByte(vars._talkedToSparky);
s.syncAsByte(vars._talkedToBoss);
s.syncAsByte(vars._talkedToRecep);
s.syncAsByte(vars._cardPassFlag);
s.syncAsByte(vars._madmanFlag);
s.syncAsByte(vars._keeperFlag);
s.syncAsByte(vars._lastTrigger);
s.syncAsByte(vars._manDead);
s.syncAsByte(vars._seed1);
s.syncAsByte(vars._seed2);
s.syncAsByte(vars._seed3);
s.syncAsByte(vars._needToTravel);
s.syncAsByte(vars._throughDoor);
s.syncAsByte(vars._newObs);
s.syncAsByte(vars._ryanOn);
s.syncAsByte(vars._combatCount);
s.syncAsByte(vars._lastWeapon);
s.syncAsByte(vars._dreamNumber);
s.syncAsByte(vars._roomAfterDream);
s.syncAsByte(vars._shakeCounter);
}
void DreamWebEngine::loadGame() {
commandOnlyCond(41, 246);
if (_mouseButton == _oldButton)
return; // "noload"
if (_mouseButton == 1)
doLoad(-1);
}
// if -1, open menu to ask for slot to load
// if >= 0, directly load from that slot
void DreamWebEngine::doLoad(int savegameId) {
_loadingOrSave = 1;
if (ConfMan.getBool("originalsaveload") && savegameId == -1) {
showOpBox();
showLoadOps();
_currentSlot = 0;
showSlots();
showNames();
_pointerFrame = 0;
workToScreenM();
namesToOld();
_getBack = 0;
while (_getBack == 0) {
if (_quitRequested)
return;
delPointer();
readMouse();
showPointer();
waitForVSync();
dumpPointer();
dumpTextLine();
RectWithCallback loadlist[] = {
{ kOpsx+176,kOpsx+192,kOpsy+60,kOpsy+76,&DreamWebEngine::getBackToOps },
{ kOpsx+128,kOpsx+190,kOpsy+12,kOpsy+100,&DreamWebEngine::actualLoad },
{ kOpsx+2,kOpsx+92,kOpsy+4,kOpsy+81,&DreamWebEngine::selectSlot },
{ kOpsx+158,kOpsx+158+(18*3),kOpsy-17,kOpsy-1,&DreamWebEngine::selectSaveLoadPage },
{ 0,320,0,200,&DreamWebEngine::blank },
{ 0xFFFF,0,0,0,nullptr }
};
checkCoords(loadlist);
if (_getBack == 2)
return; // "quitloaded"
}
} else {
if (savegameId == -1) {
// Wait till both mouse buttons are up. We should wait till the user
// releases the mouse button, otherwise the follow-up mouseup event
// will trigger a load of the save slot under the mouse cursor. Fixes
// bug #6175.
while (_oldMouseState > 0) {
readMouse();
g_system->delayMillis(10);
}
// Open dialog to get savegameId
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
savegameId = dialog->runModalWithCurrentTarget();
delete dialog;
}
if (savegameId < 0) {
_getBack = 0;
return;
}
loadPosition(savegameId);
_getBack = 1;
}
// If we reach this point, loadPosition() has just been called.
// Among other things, it will have filled g_MadeUpRoomDat.
_saveGraphics.clear();
startLoading(g_madeUpRoomDat);
_sound->loadRoomsSample(_roomsSample);
_roomLoaded = 1;
_newLocation = 255;
clearSprites();
initMan();
initRain();
_textAddressX = 13;
_textAddressY = 182;
_textLen = 240;
startup();
workToScreen();
_getBack = 4;
}
void DreamWebEngine::saveGame() {
if (_vars._manDead == 2) {
blank();
return;
}
commandOnlyCond(44, 247);
if (_mouseButton != 1)
return;
_loadingOrSave = 2;
if (ConfMan.getBool("originalsaveload")) {
showOpBox();
showSaveOps();
_currentSlot = 0;
showSlots();
showNames();
workToScreenM();
namesToOld();
_bufferIn = 0;
_bufferOut = 0;
_getBack = 0;
while (_getBack == 0) {
if (_quitRequested)
return;
delPointer();
checkInput();
readMouse();
showPointer();
waitForVSync();
dumpPointer();
dumpTextLine();
RectWithCallback savelist[] = {
{ kOpsx+176,kOpsx+192,kOpsy+60,kOpsy+76,&DreamWebEngine::getBackToOps },
{ kOpsx+128,kOpsx+190,kOpsy+12,kOpsy+100,&DreamWebEngine::actualSave },
{ kOpsx+2,kOpsx+92,kOpsy+4,kOpsy+81,&DreamWebEngine::selectSlot },
{ kOpsx+158,kOpsx+158+(18*3),kOpsy-17,kOpsy-1,&DreamWebEngine::selectSaveLoadPage },
{ 0,320,0,200,&DreamWebEngine::blank },
{ 0xFFFF,0,0,0,nullptr }
};
checkCoords(savelist);
}
return;
} else {
// Wait till both mouse buttons are up. We should wait till the user
// releases the mouse button, otherwise the follow-up mouseup event
// will trigger a save into the save slot under the mouse cursor. Fixes
// bug #6175.
while (_oldMouseState > 0) {
readMouse();
g_system->delayMillis(10);
}
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
int savegameId = dialog->runModalWithCurrentTarget();
Common::String game_description = dialog->getResultString();
if (game_description.empty())
game_description = "Untitled";
delete dialog;
if (savegameId < 0) {
_getBack = 0;
return;
}
char descbuf[17] = { 2, 0 };
Common::strlcpy((char *)descbuf + 1, game_description.c_str(), 16);
unsigned int desclen = game_description.size();
if (desclen > 15)
desclen = 15;
// zero terminate, and pad with ones
descbuf[++desclen] = 0;
while (desclen < 16)
descbuf[++desclen] = 1;
// TODO: The below is copied from actualsave
_saveGraphics.clear();
restoreAll(); // reels
_textAddressX = 13;
_textAddressY = 182;
_textLen = 240;
redrawMainScrn();
workToScreen(); // show the main screen without the mouse pointer
// We need to save after the scene has been redrawn, to capture the
// correct screen thumbnail
savePosition(savegameId, descbuf);
workToScreenM();
_getBack = 4;
}
}
void DreamWebEngine::namesToOld() {
memcpy(_saveNamesOld, _saveNames, 17*21);
}
void DreamWebEngine::oldToNames() {
memcpy(_saveNames, _saveNamesOld, 17*21);
}
void DreamWebEngine::saveLoad() {
if (ConfMan.getBool("originalsaveload"))
createThumbnail(_thumbnail);
if (_vars._watchingTime || (_pointerMode == 2)) {
blank();
return;
}
commandOnlyCond(43, 253);
if ((_mouseButton != _oldButton) && (_mouseButton & 1))
doSaveLoad();
}
void DreamWebEngine::doSaveLoad() {
_pointerFrame = 0;
_textAddressX = 70;
_textAddressY = 182-8;
_textLen = 181;
_manIsOffScreen = 1;
clearWork();
createPanel2();
underTextLine();
getRidOfAll();
loadSaveBox();
showOpBox();
showMainOps();
workToScreen();
RectWithCallback opsList[] = {
{ kOpsx+59,kOpsx+114,kOpsy+30,kOpsy+76,&DreamWebEngine::getBackFromOps },
{ kOpsx+10,kOpsx+77,kOpsy+10,kOpsy+59,&DreamWebEngine::DOSReturn },
{ kOpsx+128,kOpsx+190,kOpsy+16,kOpsy+100,&DreamWebEngine::discOps },
{ 0,320,0,200,&DreamWebEngine::blank },
{ 0xFFFF,0,0,0,nullptr }
};
bool firstOps = true;
do { // restart ops
if (firstOps) {
firstOps = false;
} else {
showOpBox();
showMainOps();
workToScreenM();
}
_getBack = 0;
do { // wait ops
if (_quitRequested) {
_manIsOffScreen = 0;
return;
}
readMouse();
showPointer();
waitForVSync();
dumpPointer();
dumpTextLine();
delPointer();
checkCoords(opsList);
} while (!_getBack);
} while (_getBack == 2);
_textAddressX = 13;
_textAddressY = 182;
_textLen = 240;
if (_getBack != 4) {
_saveGraphics.clear();
restoreAll();
redrawMainScrn();
workToScreenM();
_commandType = 200;
}
_manIsOffScreen = 0;
}
void DreamWebEngine::getBackFromOps() {
if (_vars._manDead == 2)
blank();
else
getBack1();
}
void DreamWebEngine::getBackToOps() {
commandOnlyCond(42, 201);
if (_mouseButton != _oldButton) {
if (_mouseButton & 1) {
oldToNames();
_getBack = 2;
}
}
}
void DreamWebEngine::showMainOps() {
showFrame(_saveGraphics, kOpsx+10, kOpsy+10, 8, 0);
showFrame(_saveGraphics, kOpsx+59, kOpsy+30, 7, 0);
showFrame(_saveGraphics, kOpsx+128+4, kOpsy+12, 1, 0);
}
void DreamWebEngine::showDiscOps() {
showFrame(_saveGraphics, kOpsx+128+4, kOpsy+12, 1, 0);
showFrame(_saveGraphics, kOpsx+10, kOpsy+10, 9, 0);
showFrame(_saveGraphics, kOpsx+59, kOpsy+30, 10, 0);
showFrame(_saveGraphics, kOpsx+176+2, kOpsy+60-4, 5, 0);
}
void DreamWebEngine::discOps() {
commandOnlyCond(43, 249);
if (_mouseButton == _oldButton || !(_mouseButton & 1))
return;
scanForNames();
_loadingOrSave = 2;
showOpBox();
showDiscOps();
_currentSlot = 0;
workToScreenM();
_getBack = 0;
RectWithCallback discOpsList[] = {
{ kOpsx+59,kOpsx+114,kOpsy+30,kOpsy+76,&DreamWebEngine::loadGame },
{ kOpsx+10,kOpsx+79,kOpsy+10,kOpsy+59,&DreamWebEngine::saveGame },
{ kOpsx+176,kOpsx+192,kOpsy+60,kOpsy+76,&DreamWebEngine::getBackToOps },
{ 0,320,0,200,&DreamWebEngine::blank },
{ 0xFFFF,0,0,0,nullptr }
};
do {
if (_quitRequested)
return; // quitdiscops
delPointer();
readMouse();
showPointer();
waitForVSync();
dumpPointer();
dumpTextLine();
checkCoords(discOpsList);
} while (!_getBack);
}
void DreamWebEngine::actualSave() {
commandOnlyCond(44, 222);
if (!(_mouseButton & 1))
return;
unsigned int slot = _currentSlot + 7 * _saveLoadPage;
const char *desc = &_saveNames[17*slot];
if (desc[1] == 0) // The actual description string starts at desc[1]
return;
savePosition(slot, desc);
_saveGraphics.clear();
restoreAll(); // reels
_textAddressX = 13;
_textAddressY = 182;
_textLen = 240;
redrawMainScrn();
workToScreenM();
_getBack = 4;
}
void DreamWebEngine::actualLoad() {
commandOnlyCond(41, 221);
if (_mouseButton == _oldButton || _mouseButton != 1)
return;
unsigned int slot = _currentSlot + 7 * _saveLoadPage;
const char *desc = &_saveNames[17*slot];
if (desc[1] == 0) // The actual description string starts at desc[1]
return;
loadPosition(slot);
_getBack = 1;
}
void DreamWebEngine::savePosition(unsigned int slot, const char *descbuf) {
const Room &currentRoom = g_roomData[_vars._location];
Room madeUpRoom = currentRoom;
madeUpRoom.roomsSample = _roomsSample;
madeUpRoom.mapX = _mapX;
madeUpRoom.mapY = _mapY;
madeUpRoom.liftFlag = _vars._liftFlag;
madeUpRoom.b21 = _mansPath;
madeUpRoom.facing = _facing;
madeUpRoom.b27 = 255;
Common::String filename = getSavegameFilename(slot);
debug(1, "savePosition: slot %d filename %s", slot, filename.c_str());
Common::OutSaveFile *outSaveFile = getSaveFileManager()->openForSaving(filename);
if (!outSaveFile) // TODO: Do proper error handling!
error("save could not be opened for writing");
// Initialize new header
FileHeader header;
// Note: _desc is not zero-terminated
const char *desc = "DREAMWEB DATA FILE COPYRIGHT 1992 CREATIVE REALITY";
assert(strlen(desc) == sizeof(header._desc));
memcpy(header._desc, desc, sizeof(header._desc));
memset(&header._len[0], 0, sizeof(header._len));
memset(&header._padding[0], 0, sizeof(header._padding));
// fill length fields in savegame file header
uint16 len[6] = { 17, kLengthofvars, kLengthofextra,
4*kNumChanges, 48, kNumReelRoutines*8+1 };
for (int i = 0; i < 6; ++i)
header.setLen(i, len[i]);
// Write a new section with data that we need for ScummVM (version,
// thumbnail, played time etc). We don't really care for its size,
// so we just set it to a magic number.
header.setLen(6, SCUMMVM_BLOCK_MAGIC_SIZE);
outSaveFile->write((const uint8 *)&header, sizeof(FileHeader));
outSaveFile->write(descbuf, len[0]);
// TODO: Convert more to serializer?
Common::Serializer s(nullptr, outSaveFile);
syncGameVars(s, _vars);
// the Extras segment:
outSaveFile->write((const uint8 *)_exFrames._frames, kFrameBlocksize);
outSaveFile->write((const uint8 *)_exFrames._data, kExframeslen);
outSaveFile->write((const uint8 *)_exData, sizeof(DynObject)*kNumexobjects);
outSaveFile->write((const uint8 *)_exText._offsetsLE, 2*(kNumExObjects+2));
outSaveFile->write((const uint8 *)_exText._text, kExtextlen);
outSaveFile->write(_listOfChanges, len[3]);
// len[4] == 48, which is sizeof(Room) plus 16 for 'Roomscango'
outSaveFile->write((const uint8 *)&madeUpRoom, sizeof(Room));
outSaveFile->write(_roomsCanGo, 16);
for (unsigned int i = 0; i < kNumReelRoutines; ++i) {
syncReelRoutine(s, &_reelRoutines[i]);
}
// Terminator
s.syncAsByte(_reelRoutines[kNumReelRoutines].reallocation);
// ScummVM data block
outSaveFile->writeUint32BE(SCUMMVM_HEADER);
outSaveFile->writeByte(SAVEGAME_VERSION);
TimeDate curTime;
g_system->getTimeAndDate(curTime);
uint32 saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
uint32 saveTime = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF);
uint32 playTime = g_engine->getTotalPlayTime() / 1000;
outSaveFile->writeUint32LE(saveDate);
outSaveFile->writeUint32LE(saveTime);
outSaveFile->writeUint32LE(playTime);
if (ConfMan.getBool("originalsaveload"))
Graphics::saveThumbnail(*outSaveFile, _thumbnail);
else
Graphics::saveThumbnail(*outSaveFile);
outSaveFile->finalize();
if (outSaveFile->err()) {
// TODO: Do proper error handling
warning("an error occurred while writing the savegame");
}
delete outSaveFile;
}
// Utility struct for a savegame sanity check in loadPosition
struct FrameExtent {
uint16 start;
uint16 length;
bool operator<(const struct FrameExtent& other) const { return start<other.start; }
};
void DreamWebEngine::loadPosition(unsigned int slot) {
_timeCount = 0;
clearChanges();
Common::String filename = getSavegameFilename(slot);
debug(1, "loadPosition: slot %d filename %s", slot, filename.c_str());
Common::InSaveFile *inSaveFile = getSaveFileManager()->openForLoading(filename);
if (!inSaveFile) // TODO: Do proper error handling!
error("save could not be opened for reading");
FileHeader header;
inSaveFile->read((uint8 *)&header, sizeof(FileHeader));
// read segment lengths from savegame file header
int len[6];
for (int i = 0; i < 6; ++i)
len[i] = header.len(i);
if (len[0] != 17)
::error("Error loading save: description buffer isn't 17 bytes");
if (slot < 21) {
inSaveFile->read(&_saveNames[17*slot], len[0]);
} else {
// The savenames buffer only has room for 21 descriptions
uint8 namebuf[17];
inSaveFile->read(namebuf, 17);
}
// TODO: Use serializer for more?
Common::Serializer s(inSaveFile, nullptr);
syncGameVars(s, _vars);
// the Extras segment:
inSaveFile->read((uint8 *)_exFrames._frames, kFrameBlocksize);
inSaveFile->read((uint8 *)_exFrames._data, kExframeslen);
inSaveFile->read((uint8 *)_exData, sizeof(DynObject)*kNumexobjects);
inSaveFile->read((uint8 *)_exText._offsetsLE, 2*(kNumExObjects+2));
inSaveFile->read((uint8 *)_exText._text, kExtextlen);
inSaveFile->read(_listOfChanges, len[3]);
// len[4] == 48, which is sizeof(Room) plus 16 for 'Roomscango'
// Note: the values read into g_madeUpRoomDat are only used in actualLoad,
// which is (almost) immediately called after this function
inSaveFile->read((uint8 *)&g_madeUpRoomDat, sizeof(Room));
inSaveFile->read(_roomsCanGo, 16);
for (unsigned int i = 0; i < kNumReelRoutines; ++i) {
syncReelRoutine(s, &_reelRoutines[i]);
}
// Terminator
s.syncAsByte(_reelRoutines[kNumReelRoutines].reallocation);
// Check if there's a ScummVM data block
if (header.len(6) == SCUMMVM_BLOCK_MAGIC_SIZE) {
uint32 tag = inSaveFile->readUint32BE();
if (tag != SCUMMVM_HEADER) {
warning("ScummVM data block found, but the block header is incorrect - skipping");
delete inSaveFile;
return;
}
byte version = inSaveFile->readByte();
if (version > SAVEGAME_VERSION) {
warning("ScummVM data block found, but it has been saved with a newer version of ScummVM - skipping");
delete inSaveFile;
return;
}
inSaveFile->skip(4); // saveDate
inSaveFile->skip(4); // saveTime
uint32 playTime = inSaveFile->readUint32LE();
g_engine->setTotalPlayTime(playTime * 1000);
// The thumbnail data follows, but we don't need it here
}
delete inSaveFile;
// Do a sanity check on exFrames data to detect exFrames corruption
// caused by a (now fixed) bug in emergencyPurge. See bug #6196.
// Gather the location of frame data of all used ex object frames.
Common::List<FrameExtent> flist;
for (unsigned int i = 0; i < kNumexobjects; ++i) {
if (_exData[i].mapad[0] != 0xff) {
FrameExtent fe;
Frame *frame = &_exFrames._frames[3*i+0];
fe.start = frame->ptr();
fe.length = frame->width * frame->height;
flist.push_back(fe);
frame = &_exFrames._frames[3*i+1];
fe.start = frame->ptr();
fe.length = frame->width * frame->height;
flist.push_back(fe);
}
}
// ...and check if the frames overlap.
Common::sort(flist.begin(), flist.end(), Common::Less<FrameExtent>());
uint16 curEnd = 0;
for (auto &frame : flist) {
if (frame.start < curEnd)
error("exFrames data corruption in savegame");
curEnd = frame.start + frame.length;
}
if (curEnd > _vars._exFramePos) {
if (curEnd > kExframeslen)
error("exFrames data corruption in savegame");
warning("Fixing up exFramePos");
_vars._exFramePos = curEnd;
}
// (end of sanity check)
}
// Count number of save files, and load their descriptions into _saveNames
uint DreamWebEngine::scanForNames() {
// There are 21 save slots, each of which are 17 bytes. The first byte
// doesn't seem to be used. The name starts at the second byte. All the
// slots are initialized to be empty.
for (unsigned int slot = 0; slot < 21; ++slot) {
_saveNames[17 * slot + 0] = 2;
_saveNames[17 * slot + 1] = 0;
for (int i = 2; i < 17; ++i)
_saveNames[17 * slot + i] = 1; // initialize with 1'sdrea
}
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray files = saveFileMan->listSavefiles("DREAMWEB.D??");
Common::sort(files.begin(), files.end());
SaveStateList saveList;
for (uint i = 0; i < files.size(); ++i) {
const Common::String &file = files[i];
Common::InSaveFile *stream = saveFileMan->openForLoading(file);
if (!stream)
error("cannot open save file %s", file.c_str());
char name[17] = {};
stream->seek(0x61);
stream->read(name, sizeof(name) - 1);
delete stream;
int slotNum = atoi(file.c_str() + file.size() - 2);
SaveStateDescriptor sd(getMetaEngine(), slotNum, name);
saveList.push_back(sd);
if (slotNum < 21)
Common::strlcpy(&_saveNames[17 * slotNum + 1], name, 16); // the first character is unused
}
// FIXME: Can the following be safely removed?
// al = saveList.size() <= 7 ? (uint8)saveList.size() : 7;
return saveList.size();
}
void DreamWebEngine::loadOld() {
commandOnlyCond(48, 252);
if (!(_mouseButton & 1))
return;
doLoad(-1);
if (_getBack == 4 || _quitRequested)
return;
showDecisions();
workToScreenM();
_getBack = 0;
}
void DreamWebEngine::showDecisions() {
createPanel2();
showOpBox();
showFrame(_saveGraphics, kOpsx + 17, kOpsy + 13, 6, 0);
underTextLine();
}
void DreamWebEngine::loadSaveBox() {
loadGraphicsFile(_saveGraphics, "G08");
}
// show savegame names (original interface), and set kCursorpos
void DreamWebEngine::showNames() {
unsigned int offset = 7 * _saveLoadPage;
for (int slot = 0; slot < 7; ++slot) {
// The first character of the savegame name is unused
Common::String name(&_saveNames[17 * (slot + offset) + 1]);
if (slot != _currentSlot) {
printDirect((const uint8 *)name.c_str(), kOpsx + 21, kOpsy + 10*slot + 10, 200, false);
continue;
}
if (_loadingOrSave != 2) {
_charShift = 91;
if (getLanguage() == Common::RU_RUS)
_charShift = 182;
printDirect((const uint8 *)name.c_str(), kOpsx + 21, kOpsy + 10*slot + 10, 200, false);
_charShift = 0;
continue;
}
int pos = name.size();
_cursorPos = pos;
name += '/'; // cursor character
printDirect((const uint8 *)name.c_str(), kOpsx + 21, kOpsy + 10*slot + 10, 200, false);
}
}
void DreamWebEngine::checkInput() {
if (_loadingOrSave == 3)
return;
readKey();
unsigned int slot = _currentSlot + 7 * _saveLoadPage;
// The first character of the savegame name is unused
char *name = &_saveNames[17*slot + 1];
if (_currentKey == 0) {
return;
} else if (_currentKey == 13) {
_loadingOrSave = 3;
} else if (_currentKey == 8) {
if (_cursorPos == 0)
return;
--_cursorPos;
name[_cursorPos] = 0;
name[_cursorPos+1] = 1;
} else {
if (_cursorPos == 14)
return;
name[_cursorPos] = _currentKey;
name[_cursorPos+1] = 0;
name[_cursorPos+2] = 1;
++_cursorPos;
}
showOpBox();
showNames();
showSlots();
showSaveOps();
workToScreenM();
}
void DreamWebEngine::selectSaveLoadPage() {
commandOnlyCond(31, 254);
if (_mouseButton != 1 || _mouseButton == _oldButton)
return;
uint saveLoadPage = (_mouseX - (kOpsx + 158)) / 18;
if (saveLoadPage != _saveLoadPage) {
_saveLoadPage = saveLoadPage;
// This will also make the first slot the selected one, based
// on the mouse Y position. I can't decide if this is a feature
// or not.
selectSlot();
}
}
void DreamWebEngine::selectSlot() {
commandOnlyCond(45, 244);
if (_mouseButton != 1 || _mouseButton == _oldButton)
return; // noselslot
if (_loadingOrSave == 3)
_loadingOrSave--;
oldToNames();
int y = _mouseY - (kOpsy + 4);
if (y < 11)
_currentSlot = 0;
else
_currentSlot = y / 11;
delPointer();
showOpBox();
showSlots();
showNames();
if (_loadingOrSave == 1)
showLoadOps();
else
showSaveOps();
readMouse();
showPointer();
workToScreen();
delPointer();
}
void DreamWebEngine::showSlots() {
showFrame(_icons1, kOpsx + 158, kOpsy - 11, 12, 0);
showFrame(_icons1, kOpsx + 158 + 18 * _saveLoadPage, kOpsy - 11, 13 + _saveLoadPage, 0);
showFrame(_saveGraphics, kOpsx + 7, kOpsy + 8, 2, 0);
uint16 y = kOpsy + 11;
for (int slot = 0; slot < 7; slot++) {
if (slot == _currentSlot)
showFrame(_saveGraphics, kOpsx + 10, y, 3, 0);
y += 10;
}
}
void DreamWebEngine::showOpBox() {
showFrame(_saveGraphics, kOpsx, kOpsy, 0, 0);
// This call displays half of the ops dialog in the CD version. It's not
// in the floppy version, and if it's called, a stray red dot is shown in
// the game dialogs. It is included in the early UK CD release, which had
// similar data files as the floppy release (bug #6039).
if (isCD() && getLanguage() != Common::EN_GRB)
showFrame(_saveGraphics, kOpsx, kOpsy + 55, 4, 0);
}
void DreamWebEngine::showLoadOps() {
showFrame(_saveGraphics, kOpsx + 128 + 4, kOpsy + 12, 1, 0);
showFrame(_saveGraphics, kOpsx + 176 + 2, kOpsy + 60 - 4, 5, 0);
printMessage(kOpsx + 104, kOpsy + 14, 55, 101, (101 & 1));
}
void DreamWebEngine::showSaveOps() {
showFrame(_saveGraphics, kOpsx + 128 + 4, kOpsy + 12, 1, 0);
showFrame(_saveGraphics, kOpsx + 176 + 2, kOpsy + 60 - 4, 5, 0);
printMessage(kOpsx + 104, kOpsy + 14, 54, 101, (101 & 1));
}
} // End of namespace DreamWeb

276
engines/dreamweb/sound.cpp Normal file
View 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/>.
*
*/
#include "audio/decoders/raw.h"
#include "common/config-manager.h"
#include "common/debug.h"
#include "common/file.h"
#include "audio/audiostream.h"
#include "dreamweb/dreamweb.h"
#include "dreamweb/sound.h"
namespace DreamWeb {
DreamWebSound::DreamWebSound(DreamWebEngine *vm) : _vm(vm) {
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
_currentSample = 0xff;
_channel0Playing = 255;
_channel0Repeat = 0;
_channel0NewSound = false;
_channel1Playing = 255;
_channel1NewSound = false;
_volume = 0;
_volumeTo = 0;
_volumeDirection = 0;
_volumeCount = 0;
}
DreamWebSound::~DreamWebSound() {
}
bool DreamWebSound::loadSpeech(byte type1, int idx1, byte type2, int idx2) {
cancelCh1();
Common::String name = Common::String::format("%c%02d%c%04d.RAW", type1, idx1, type2, idx2);
debug(2, "loadSpeech() name:%s", name.c_str());
return loadSpeech(name);
}
void DreamWebSound::volumeChange(uint8 value, int8 direction) {
_volumeTo = value;
_volumeDirection = direction;
}
void DreamWebSound::volumeAdjust() {
if (_volumeDirection == 0)
return;
if (_volume != _volumeTo) {
_volumeCount += 64;
// Only modify the volume every 256/64 = 4th time around
if (_volumeCount == 0)
_volume += _volumeDirection;
} else {
_volumeDirection = 0;
}
}
void DreamWebSound::playChannel0(uint8 index, uint8 repeat) {
debug(1, "playChannel0(index:%d, repeat:%d)", index, repeat);
_channel0Playing = index;
_channel0Repeat = repeat;
_channel0NewSound = true;
}
void DreamWebSound::playChannel1(uint8 index) {
debug(1, "playChannel1(index:%d)", index);
if (_channel1Playing == 7)
return;
_channel1Playing = index;
_channel1NewSound = true;
}
void DreamWebSound::cancelCh0() {
debug(1, "cancelCh0()");
_channel0Playing = 255;
_channel0Repeat = 0;
stopSound(0);
}
void DreamWebSound::cancelCh1() {
debug(1, "cancelCh1()");
_channel1Playing = 255;
stopSound(1);
}
void DreamWebSound::loadRoomsSample(uint8 sample) {
debug(1, "loadRoomsSample(sample:%d)", sample);
if (sample == 255 || _currentSample == sample)
return; // loaded already
assert(sample < 100);
Common::String sampleSuffix = Common::String::format("V%02d", sample);
_currentSample = sample;
uint8 ch0 = _channel0Playing;
if (ch0 >= 12 && ch0 != 255)
cancelCh0();
uint8 ch1 = _channel1Playing;
if (ch1 >= 12)
cancelCh1();
loadSounds(1, sampleSuffix.c_str());
}
void DreamWebSound::playSound(uint8 channel, uint8 id, uint8 loops) {
debug(1, "playSound(channel:%u, id:%u, loops:%u)", channel, id, loops);
int bank = 0;
bool speech = false;
Audio::Mixer::SoundType type = channel == 0?
Audio::Mixer::kMusicSoundType: Audio::Mixer::kSFXSoundType;
if (id >= 12) {
id -= 12;
bank = 1;
if (id == 50) {
speech = true;
type = Audio::Mixer::kSpeechSoundType;
}
}
const SoundData &data = _soundData[bank];
Audio::SeekableAudioStream *raw;
if (!speech) {
if (id >= data.samples.size() || data.samples[id].size == 0) {
warning("invalid sample #%u played", id);
return;
}
const Sample &sample = data.samples[id];
uint8 *buffer = (uint8 *)malloc(sample.size);
if (!buffer)
error("out of memory: cannot allocate memory for sound(%u bytes)", sample.size);
memcpy(buffer, data.data.begin() + sample.offset, sample.size);
raw = Audio::makeRawStream(buffer, sample.size, 22050, Audio::FLAG_UNSIGNED);
} else {
uint8 *buffer = (uint8 *)malloc(_speechData.size());
if (!buffer)
error("out of memory: cannot allocate memory for sound(%u bytes)", _speechData.size());
memcpy(buffer, _speechData.begin(), _speechData.size());
raw = Audio::makeRawStream(buffer, _speechData.size(), 22050, Audio::FLAG_UNSIGNED);
}
Audio::AudioStream *stream;
if (loops > 1) {
stream = new Audio::LoopingAudioStream(raw, (loops < 255) ? loops : 0);
} else
stream = raw;
if (_vm->_mixer->isSoundHandleActive(_channelHandle[channel]))
_vm->_mixer->stopHandle(_channelHandle[channel]);
_vm->_mixer->playStream(type, &_channelHandle[channel], stream);
}
void DreamWebSound::stopSound(uint8 channel) {
debug(1, "stopSound(%u)", channel);
assert(channel == 0 || channel == 1);
_vm->_mixer->stopHandle(_channelHandle[channel]);
}
bool DreamWebSound::loadSpeech(const Common::String &filename) {
if (ConfMan.getBool("tts_enabled_speech") || !_vm->hasSpeech())
return false;
Common::File file;
if (!file.open(_vm->getSpeechDirName().appendComponent(filename)))
return false;
debug(1, "loadSpeech(%s)", filename.c_str());
uint size = file.size();
_speechData.resize(size);
file.read(_speechData.begin(), size);
file.close();
return true;
}
void DreamWebSound::soundHandler() {
_vm->_subtitles = ConfMan.getBool("subtitles");
volumeAdjust();
uint volume = _volume;
//.vol file loaded into soundbuf:0x4000
//volume table at (volume * 0x100 + 0x3f00)
//volume value could be from 1 to 7
//1 - 0x10-0xff
//2 - 0x1f-0xdf
//3 - 0x2f-0xd0
//4 - 0x3e-0xc1
//5 - 0x4d-0xb2
//6 - 0x5d-0xa2
//7 - 0x6f-0x91
if (volume >= 8)
volume = 7;
volume = (8 - volume) * Audio::Mixer::kMaxChannelVolume / 8;
_vm->_mixer->setChannelVolume(_channelHandle[0], volume);
if (_channel0NewSound) {
_channel0NewSound = false;
if (_channel0Playing != 255) {
playSound(0, _channel0Playing, _channel0Repeat);
}
}
if (_channel1NewSound) {
_channel1NewSound = false;
if (_channel1Playing != 255) {
playSound(1, _channel1Playing, 1);
}
}
if (!_vm->_mixer->isSoundHandleActive(_channelHandle[0])) {
_channel0Playing = 255;
}
if (!_vm->_mixer->isSoundHandleActive(_channelHandle[1])) {
_channel1Playing = 255;
}
}
void DreamWebSound::loadSounds(uint bank, const Common::String &suffix) {
Common::Path filename(_vm->getDatafilePrefix() + suffix);
debug(1, "loadSounds(%u, %s)", bank, filename.toString(Common::Path::kNativeSeparator).c_str());
Common::File file;
if (!file.open(filename)) {
warning("cannot open %s", filename.toString(Common::Path::kNativeSeparator).c_str());
return;
}
uint8 header[96];
file.read(header, sizeof(header));
uint tablesize = READ_LE_UINT16(header + 50);
debug(1, "table size = %u", tablesize);
SoundData &soundData = _soundData[bank];
soundData.samples.resize(tablesize / 6);
uint total = 0;
for (uint i = 0; i < tablesize / 6; ++i) {
uint8 entry[6];
Sample &sample = soundData.samples[i];
file.read(entry, sizeof(entry));
sample.offset = entry[0] * 16384 + READ_LE_UINT16(entry + 1);
sample.size = READ_LE_UINT16(entry + 3) * 2048;
total += sample.size;
debug(1, "offset: %08x, size: %u", sample.offset, sample.size);
}
soundData.data.resize(total);
file.read(soundData.data.begin(), total);
file.close();
}
} // End of namespace DreamWeb

90
engines/dreamweb/sound.h Normal file
View File

@@ -0,0 +1,90 @@
/* 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 DREAMWEB_SOUND_H
#define DREAMWEB_SOUND_H
#include "common/array.h"
#include "common/str.h"
#include "audio/mixer.h"
namespace DreamWeb {
class DreamWebEngine;
class DreamWebSound {
public:
DreamWebSound(DreamWebEngine *vm);
~DreamWebSound();
bool loadSpeech(byte type1, int idx1, byte type2, int idx2);
void volumeSet(uint8 value) { _volume = value; }
void volumeChange(uint8 value, int8 direction);
void playChannel0(uint8 index, uint8 repeat);
void playChannel1(uint8 index);
uint8 getChannel0Playing() { return _channel0Playing; }
bool isChannel1Playing() { return _channel1Playing != 255; }
void cancelCh0();
void cancelCh1();
void loadRoomsSample(uint8 sample);
void soundHandler();
void loadSounds(uint bank, const Common::String &suffix);
private:
DreamWebEngine *_vm;
struct Sample {
uint offset;
uint size;
Sample(): offset(), size() {}
};
struct SoundData {
Common::Array<Sample> samples;
Common::Array<uint8> data;
};
SoundData _soundData[2];
Common::Array<uint8> _speechData;
Audio::SoundHandle _channelHandle[2];
uint8 _currentSample;
uint8 _channel0Playing;
uint8 _channel0Repeat;
bool _channel0NewSound;
uint8 _channel1Playing;
bool _channel1NewSound;
uint8 _volume;
uint8 _volumeTo;
int8 _volumeDirection;
uint8 _volumeCount;
void volumeAdjust();
void playSound(uint8 channel, uint8 id, uint8 loops);
void stopSound(uint8 channel);
bool loadSpeech(const Common::String &filename);
};
} // End of namespace DreamWeb
#endif

1087
engines/dreamweb/sprite.cpp Normal file

File diff suppressed because it is too large Load Diff

409
engines/dreamweb/structs.h Normal file
View File

@@ -0,0 +1,409 @@
/* 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 DREAMWEB_STRUCTS_H
#define DREAMWEB_STRUCTS_H
#include "common/endian.h"
#include "common/rect.h"
namespace DreamWeb {
struct GraphicsFile;
struct SetObject;
struct Sprite {
bool _mainManCallback;
const GraphicsFile *_frameData;
uint8 x;
uint8 y;
uint8 frameNumber;
uint8 delay;
uint8 animFrame; // index into SetObject::frames
SetObject *_objData;
uint8 speed;
uint8 priority;
uint8 walkFrame;
uint8 type;
uint8 hidden;
};
struct RectWithCallback {
uint16 _xMin, _xMax;
uint16 _yMin, _yMax;
void (DreamWebEngine::*_callback)();
bool contains(uint16 x, uint16 y) const {
return (x >= _xMin) && (x < _xMax) && (y >= _yMin) && (y < _yMax);
}
};
#include "common/pack-start.h" // START STRUCT PACKING
struct SetObject {
uint8 b0;
uint8 b1;
uint8 b2;
uint8 slotSize;
uint8 slotCount;
uint8 priority;
uint8 b6;
uint8 delay;
uint8 type;
uint8 b9;
uint8 b10;
uint8 b11;
uint8 objId[4];
uint8 b16;
uint8 index;
uint8 frames[40]; // Table mapping animFrame to sprite frame number
uint8 mapad[5];
uint8 b63;
} PACKED_STRUCT;
struct DynObject {
uint8 currentLocation;
uint8 index;
uint8 mapad[5];
uint8 slotSize; // the size of an object's slots
uint8 slotCount; // the number of slots of an object
uint8 objectSize; // the size of an object
uint8 turnedOn;
uint8 initialLocation;
uint8 objId[4];
} PACKED_STRUCT;
struct ObjPos {
uint8 xMin;
uint8 yMin;
uint8 xMax;
uint8 yMax;
uint8 index;
bool contains(uint8 x, uint8 y) const {
return (x >= xMin) && (x < xMax) && (y >= yMin) && (y < yMax);
}
} PACKED_STRUCT;
struct Frame {
uint8 width;
uint8 height;
uint16 _ptr;
uint16 ptr() const { return READ_LE_UINT16(&_ptr); }
void setPtr(uint16 v) { WRITE_LE_UINT16(&_ptr, v); }
uint8 x;
uint8 y;
} PACKED_STRUCT;
struct Reel {
uint8 frame_lo;
uint8 frame_hi;
uint16 frame() const { return READ_LE_UINT16(&frame_lo); }
void setFrame(uint16 v) { WRITE_LE_UINT16(&frame_lo, v); }
uint8 x;
uint8 y;
uint8 b4;
} PACKED_STRUCT;
#include "common/pack-end.h" // END STRUCT PACKING
struct ReelRoutine {
uint8 reallocation;
uint8 mapX;
uint8 mapY;
uint16 _reelPointer;
uint16 reelPointer() const { return _reelPointer; }
void setReelPointer(uint16 v) { _reelPointer = v; }
void incReelPointer() { _reelPointer++; }
uint8 period;
uint8 counter;
uint8 b7;
};
struct People {
uint16 _reelPointer;
ReelRoutine *_routinePointer;
uint8 b4;
};
#include "common/pack-start.h" // START STRUCT PACKING
struct Room {
char name[13];
uint8 roomsSample;
uint8 b14;
uint8 mapX;
uint8 mapY;
uint8 b17;
uint8 b18;
uint8 b19;
uint8 liftFlag;
uint8 b21;
uint8 facing;
uint8 countToOpen;
uint8 liftPath;
uint8 doorPath;
uint8 b26;
uint8 b27;
uint8 b28;
uint8 b29;
uint8 b30;
uint8 realLocation;
} PACKED_STRUCT;
extern const Room g_roomData[];
struct Rain {
uint8 x;
uint8 y;
uint8 size;
uint16 w3;
uint8 b5;
} PACKED_STRUCT;
struct Change {
uint8 index;
uint8 location;
uint8 value;
uint8 type;
} PACKED_STRUCT;
struct PathNode {
uint8 x;
uint8 y;
uint8 x1;
uint8 y1;
uint8 x2;
uint8 y2;
uint8 on;
uint8 dir;
} PACKED_STRUCT;
struct PathSegment {
uint8 b0;
uint8 b1;
} PACKED_STRUCT;
struct RoomPaths {
PathNode nodes[12];
PathSegment segments[24];
} PACKED_STRUCT;
struct FileHeader {
char _desc[50];
uint16 _len[20];
uint8 _padding[6];
uint16 len(unsigned int i) const {
assert(i < 20);
return READ_LE_UINT16(&_len[i]);
}
void setLen(unsigned int i, uint16 length) {
assert(i < 20);
WRITE_LE_UINT16(&_len[i], length);
}
} PACKED_STRUCT;
struct Atmosphere {
uint8 _location;
uint8 _mapX;
uint8 _mapY;
uint8 _sound;
uint8 _repeat;
} PACKED_STRUCT;
#include "common/pack-end.h" // END STRUCT PACKING
enum ObjectTypes {
kSetObjectType1 = 1,
kFreeObjectType = 2,
kSetObjectType3 = 3,
kExObjectType = 4
};
struct ObjectRef {
uint8 _index;
uint8 _type; // enum ObjectTypes
bool operator==(const ObjectRef &r) const {
return _index == r._index && _type == r._type;
}
bool operator!=(const ObjectRef &r) const {
return _index != r._index || _type != r._type;
}
};
#include "common/pack-start.h" // START STRUCT PACKING
struct BackdropMapFlag {
uint8 _flag;
uint8 _flagEx;
} PACKED_STRUCT;
struct MapFlag {
uint8 _flag;
uint8 _flagEx;
uint8 _type;
} PACKED_STRUCT;
#include "common/pack-end.h" // END STRUCT PACKING
struct TextFile {
TextFile(unsigned int size = 66) : _size(size), _text(0) { _offsetsLE = new uint16[_size]; }
~TextFile() {
delete[] _offsetsLE;
_offsetsLE = 0;
_size = 0;
clear();
}
uint16 *_offsetsLE;
unsigned int _size;
char *_text;
const char *getString(unsigned int i) const {
assert(i < _size);
return _text + getOffset(i);
}
void setOffset(unsigned int i, uint16 offset) {
WRITE_LE_UINT16(&_offsetsLE[i], offset);
}
uint16 getOffset(unsigned int i) const {
return READ_LE_UINT16(&_offsetsLE[i]);
}
void clear() {
delete[] _text;
_text = 0;
}
};
struct GraphicsFile {
GraphicsFile() : _data(0), _frames(0) { }
Frame *_frames;
uint8 *_data;
const uint8 *getFrameData(unsigned int i) const {
// There is 2080 bytes of Frame data, but that is between 346 and 347
// frames
assert(i < 346);
return _data + _frames[i].ptr();
}
void clear() {
delete[] _frames;
_frames = 0;
delete[] _data;
_data = 0;
}
};
struct GameVars {
uint8 _startVars;
uint8 _progressPoints;
uint8 _watchOn;
uint8 _shadesOn;
uint8 _secondCount;
uint8 _minuteCount;
uint8 _hourCount;
uint8 _zoomOn;
uint8 _location;
uint8 _exPos;
uint16 _exFramePos;
uint16 _exTextPos;
uint16 _card1Money;
uint16 _listPos;
uint8 _ryanPage;
uint16 _watchingTime;
uint16 _reelToWatch; // reel plays from here in mode 0
uint16 _endWatchReel; // and stops here. Mode set to 1
uint8 _speedCount;
uint8 _watchSpeed;
uint16 _reelToHold; // if mode is 1 hold on this reel
uint16 _endOfHoldReel; // if mode is 2 then play to endOfHoldReel and reset mode to -1
uint8 _watchMode;
uint8 _destAfterHold; // set walking destination
uint8 _newsItem;
uint8 _liftFlag;
uint8 _liftPath;
uint8 _lockStatus;
uint8 _doorPath;
uint8 _countToOpen;
uint8 _countToClose;
uint8 _rockstarDead;
uint8 _generalDead;
uint8 _sartainDead;
uint8 _aideDead;
uint8 _beenMugged;
uint8 _gunPassFlag;
uint8 _canMoveAltar;
uint8 _talkedToAttendant;
uint8 _talkedToSparky;
uint8 _talkedToBoss;
uint8 _talkedToRecep;
uint8 _cardPassFlag;
uint8 _madmanFlag;
uint8 _keeperFlag;
uint8 _lastTrigger;
uint8 _manDead;
uint8 _seed1;
uint8 _seed2;
uint8 _seed3;
uint8 _needToTravel;
uint8 _throughDoor;
uint8 _newObs;
uint8 _ryanOn;
uint8 _combatCount;
uint8 _lastWeapon;
uint8 _dreamNumber;
uint8 _roomAfterDream;
uint8 _shakeCounter;
};
struct TimedTemp {
TimedTemp() : _timeCount(0), _string(0) { }
uint8 _x;
uint8 _y;
uint16 _timeCount;
uint16 _countToTimed;
const char *_string;
};
} // End of namespace DreamWeb
#endif

3012
engines/dreamweb/stubs.cpp Normal file

File diff suppressed because it is too large Load Diff

278
engines/dreamweb/talk.cpp Normal file
View File

@@ -0,0 +1,278 @@
/* 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 "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
#include "common/text-to-speech.h"
#include "common/config-manager.h"
namespace DreamWeb {
void DreamWebEngine::talk() {
_talkPos = 0;
_inMapArea = 0;
_character = _command;
createPanel();
showPanel();
showMan();
showExit();
underTextLine();
convIcons();
startTalk();
_commandType = 255;
readMouse();
showPointer();
workToScreen();
RectWithCallback talkList[] = {
{ 273,320,157,198,&DreamWebEngine::getBack1 },
{ 240,290,2,44,&DreamWebEngine::moreTalk },
{ 0,320,0,200,&DreamWebEngine::blank },
{ 0xFFFF,0,0,0,nullptr }
};
do {
delPointer();
readMouse();
animPointer();
showPointer();
waitForVSync();
dumpPointer();
dumpTextLine();
_getBack = 0;
checkCoords(talkList);
if (_quitRequested)
break;
} while (!_getBack);
if (_talkPos >= 4)
_personData->b7 |= 128;
redrawMainScrn();
workToScreenM();
if (_speechLoaded) {
_sound->cancelCh1();
_sound->volumeChange(0, -1);
}
}
void DreamWebEngine::convIcons() {
uint8 index = _character & 127;
uint16 frame = getPersFrame(index);
const GraphicsFile *base = findSource(frame);
showFrame(*base, 234, 2, frame, 0);
}
uint16 DreamWebEngine::getPersFrame(uint8 index) {
return READ_LE_UINT16(&_personFramesLE[index]);
}
void DreamWebEngine::startTalk() {
_talkMode = 0;
const uint8 *str = getPersonText(_character & 0x7F, 0);
uint16 y;
_charShift = 91+91;
if (_ttsMan != nullptr && ConfMan.getBool("tts_enabled_speech")) {
const char *text = (const char *)str;
const char *goodText = strchr(text, ':') + 1;
_ttsMan->say(goodText, _textEncoding);
}
if (getLanguage() == Common::RU_RUS)
useCharsetIcons1();
y = 64;
printDirect(&str, 66, &y, 241, true);
if (getLanguage() == Common::RU_RUS)
resetCharset();
_charShift = 0;
y = 80;
printDirect(&str, 66, &y, 241, true);
if (hasSpeech()) {
_speechLoaded = _sound->loadSpeech('R', _realLocation, 'C', 64*(_character & 0x7F));
if (_speechLoaded) {
_sound->volumeChange(6, 1);
_sound->playChannel1(62);
}
}
}
const uint8 *DreamWebEngine::getPersonText(uint8 index, uint8 talkPos) {
const uint8 *text = (const uint8 *)_personText.getString(index*64 + talkPos);
if (_ttsMan != nullptr && ConfMan.getBool("tts_enabled_speech"))
_ttsMan->say((const char *)text, Common::TextToSpeechManager::INTERRUPT, _textEncoding);
return text;
}
void DreamWebEngine::moreTalk() {
if (_talkMode != 0) {
redes();
return;
}
commandOnlyCond(49, 215);
if (_mouseButton == _oldButton)
return; // nomore
if (!(_mouseButton & 1))
return;
_talkMode = 2;
_talkPos = 4;
if (_character >= 100)
_talkPos = 48; // second part
doSomeTalk();
}
void DreamWebEngine::doSomeTalk() {
// FIXME: This is for the CD version only
while (true) {
const uint8 *str = getPersonText(_character & 0x7F, _talkPos);
if (*str == 0) {
// endheartalk
_pointerMode = 0;
return;
}
createPanel();
showPanel();
showMan();
showExit();
convIcons();
printDirect(str, 164, 64, 144, false);
_speechLoaded = _sound->loadSpeech('R', _realLocation, 'C', (64 * (_character & 0x7F)) + _talkPos);
if (_speechLoaded)
_sound->playChannel1(62);
_pointerMode = 3;
workToScreenM();
if (hangOnPQ())
return;
_talkPos++;
str = getPersonText(_character & 0x7F, _talkPos);
if (*str == 0) {
// endheartalk
_pointerMode = 0;
return;
}
if (*str != ':' && *str != 32) {
createPanel();
showPanel();
showMan();
showExit();
convIcons();
printDirect(str, 48, 128, 144, false);
_speechLoaded = _sound->loadSpeech('R', _realLocation, 'C', (64 * (_character & 0x7F)) + _talkPos);
if (_speechLoaded)
_sound->playChannel1(62);
_pointerMode = 3;
workToScreenM();
if (hangOnPQ())
return;
}
_talkPos++;
}
}
bool DreamWebEngine::hangOnPQ() {
_getBack = 0;
RectWithCallback quitList[] = {
{ 273,320,157,198,&DreamWebEngine::getBack1 },
{ 0,320,0,200,&DreamWebEngine::blank },
{ 0xFFFF,0,0,0,nullptr }
};
uint16 speechFlag = 0;
do {
delPointer();
readMouse();
animPointer();
showPointer();
waitForVSync();
dumpPointer();
dumpTextLine();
checkCoords(quitList);
if (_getBack == 1 || _quitRequested) {
// Quit conversation
delPointer();
_pointerMode = 0;
_sound->cancelCh1();
return true;
}
if (_speechLoaded && !_sound->isChannel1Playing()) {
speechFlag++;
if (speechFlag == 40)
break;
}
} while (!_mouseButton || _oldButton);
delPointer();
_pointerMode = 0;
return false;
}
void DreamWebEngine::redes() {
if (_sound->isChannel1Playing() || _talkMode != 2) {
blank();
return;
}
commandOnlyCond(50, 217);
if (!(_mouseButton & 1))
return;
delPointer();
createPanel();
showPanel();
showMan();
showExit();
convIcons();
startTalk();
readMouse();
showPointer();
workToScreen();
delPointer();
}
} // End of namespace DreamWeb

510
engines/dreamweb/titles.cpp Normal file
View File

@@ -0,0 +1,510 @@
/* 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 "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
#include "engines/util.h"
#include "common/text-to-speech.h"
#include "common/config-manager.h"
namespace DreamWeb {
namespace {
void initTitlesGfx() {
Graphics::ModeWithFormatList modes = {
// First try for a 640x480 mode
Graphics::ModeWithFormat(640, 480, Graphics::PixelFormat::createFormatCLUT8()),
// System doesn't support it, so fall back on 320x240 mode
Graphics::ModeWithFormat(320, 240, Graphics::PixelFormat::createFormatCLUT8()),
};
initGraphicsAny(modes);
}
}
void DreamWebEngine::endGame() {
loadTempText("T83");
monkSpeaking();
if (_quitRequested)
return;
gettingShot();
getRidOfTempText();
_sound->volumeChange(7, 1);
hangOn(200);
}
void DreamWebEngine::monkSpeaking() {
_roomsSample = 35;
_sound->loadRoomsSample(_roomsSample);
GraphicsFile graphics;
loadGraphicsFile(graphics, "G15");
clearWork();
showFrame(graphics, 160, 72, 0, 128); // show monk
workToScreen();
_sound->volumeSet(7);
_sound->volumeChange(hasSpeech() ? 5 : 0, -1);
_sound->playChannel0(12, 255);
fadeScreenUps();
hangOn(300);
// TODO: Subtitles+speech mode
if (hasSpeech()) {
for (int i = 40; i < 48; i++) {
_speechLoaded = _sound->loadSpeech('T', 83, 'T', i);
_sound->playChannel1(62);
do {
waitForVSync();
if (_quitRequested)
return;
} while (_sound->isChannel1Playing());
}
} else {
for (int i = 40; i <= 44; i++) {
uint8 printResult = 0;
const uint8 *string = getTextInFile1(i);
do {
uint16 y = 140;
printResult = printDirect(&string, 36, &y, 239, 239 & 1);
workToScreen();
clearWork();
showFrame(graphics, 160, 72, 0, 128); // show monk
hangOnP(240);
if (_quitRequested)
return;
} while (printResult != 0);
}
}
_sound->volumeChange(7, 1);
fadeScreenDowns();
hangOn(300);
graphics.clear();
}
void DreamWebEngine::gettingShot() {
_newLocation = 55;
clearPalette();
loadIntroRoom();
fadeScreenUps();
_sound->volumeChange(0, -1);
runEndSeq();
clearBeforeLoad();
}
void DreamWebEngine::bibleQuote() {
const char *enStory = "And I heard a great voice out of the temple saying to the seven angels, "
"Go your ways and pour out the vails of the wrath of god upon the earth. "
"Book of revelation Chapter 16 verse 1.";
const char *frStory = "Puis j'entendis une voix forte qui venait du temple et disait aux sept anges: "
"Allez verser sur la terre les sept coupes de la col\xC3\xA8re de Dieu. "
"L'Apocalypse, chapitre 16, verset 1";
const char *esStory = "O\xC3\xAD una gran voz que dec\xC3\xAD""a"" desde el templo a los siete \xC3\xA1ngeles: "
"Id y derramad sobre la tierra las siete copas de la ira de Dios. "
"Apocalipsis, cap\xC3\xADtulo 16, vers\xC3\xAD""culo"" primero.";
const char *deStory = "Dann h\xC3\xB6rte ich, wie eine laute Stimme aus dem Tempel den sieben Engeln zurief: "
"Geht und gie\xC3\x9Ft die sieben Schalen mit dem Zorn Gottes \xC3\xBC""ber"" die Erde. "
"Offenbarung des Johannes. Kapitel 16 Vers 1";
const char *itStory = "Udii poi una gran voce dal tempio che diceva ai sette angeli: "
"Andate e versate sulla terra le sette coppe dell'ira di Dio. "
"Dal libro dell'Apocalisse, capitolo uno, primo versetto";
const char *ruStory = "\xD1\x83\xD1\x81\xD0\xBB\xD1\x8B\xD1\x88\xD0\xB0\xD0\xBB \xD1\x8F \xD0\xB8\xD0\xB7 \xD1\x85\xD1\x80\xD0\xB0\xD0\xBC\xD0\xB0 \xD1\x80\xD1\x8F\xD1\x89\xD0\xB8\xD0\xB9 \xD1\x81\xD0\xB5\xD0\xBC\xD0\xB8 \xD0\x90\xD0\xBD\xD0\xB3\xD0\xB5\xD0\xBB\xD0\xB0\xD0\xBC\x3A: "
"\xD0\xB8\xD0\xB4\xD0\xB8\xD1\x82\xD0\xB5 \xD0\xB8 \xD0\xB2\xD1\x8B\xD0\xBB\xD0\xB5\xD0\xB9\xD1\x82\xD0\xB5 \xD1\x81\xD0\xB5\xD0\xBC\xD1\x8C \xD1\x87\xD0\xB0\xD1\x88 \xD0\xB3\xD0\xBD\xD0\xB5\xD0\xB2\xD0\xB0 \xD0\x91\xD0\xBE\xD0\xB6\xD0\xB8\xD1\x8F \xD0\xBD\xD0\xB0 \xD0\xB7\xD0\xB5\xD0\xBC\xD0\xBB\xD1\x8E\x2E. "
"\xD0\x9E\xD0\xA2\xD0\x9A\xD0\xA0\xD0\x9E\xD0\x92\xD0\x95\xD0\x9D\xD0\x98\xD0\x95 \xD0\x98\xD0\x9E\xD0\x90\xD0\x9D\xD0\x9D\xD0\x90 \xD0\x91\xD0\x9E\xD0\x93\xD0\x9E\xD0\xA1\xD0\x9B\xD0\x9E\xD0\x92\xD0\x90 16:1";
const char *csStory = "Tu jsem usly\xC5\xA1""el"" mocn\xC3\xBD hlas ze svatyn\xC4\x9B, kter\xC3\xBD t\xC4\x9Bm sedmi and\xC4\x9Bl\xC5\xAFm \xC5\x99\xC3\xADkal: "
"Jd\xC4\x9Bte a vylejte t\xC4\x9B""ch"" sedm misek Bo\xC5\xBE\xC3\xADho hn\xC4\x9Bvu na zem. "
"Zjeven\xC3\xAD 16 ver\xC5\xA1 1";
const char *theStory;
switch(getLanguage()) {
case Common::ES_ESP:
theStory = esStory;
break;
case Common::FR_FRA:
theStory = frStory;
break;
case Common::IT_ITA:
theStory = itStory;
break;
case Common::DE_DEU:
theStory = deStory;
break;
case Common::RU_RUS:
theStory = ruStory;
break;
case Common::CS_CZE:
theStory = csStory;
break;
default:
theStory = enStory;
break;
}
initTitlesGfx();
showPCX("I00");
fadeScreenUps();
hangOne(80);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "biblequotearly"
}
if (_ttsMan != nullptr && ConfMan.getBool("tts_enabled_objects")) {
_ttsMan->say(theStory);
while (_ttsMan->isSpeaking() && _lastHardKey != Common::KEYCODE_ESCAPE)
hangOne(1);
_ttsMan->stop();
} else
hangOne(560);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "biblequotearly"
}
fadeScreenDowns();
hangOne(200);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "biblequotearly"
}
_sound->cancelCh0();
_lastHardKey = Common::KEYCODE_INVALID;
}
void DreamWebEngine::hangOne(uint16 delay) {
do {
waitForVSync();
if (_lastHardKey == Common::KEYCODE_ESCAPE)
return; // "hangonearly"
} while (--delay);
}
void DreamWebEngine::intro() {
loadTempText("T82");
loadPalFromIFF();
setMode();
_newLocation = 50;
clearPalette();
loadIntroRoom();
_sound->volumeSet(7);
_sound->volumeChange(hasSpeech() ? 4 : 0, -1);
_sound->playChannel0(12, 255);
fadeScreenUps();
runIntroSeq();
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "introearly"
}
clearBeforeLoad();
_newLocation = 52;
loadIntroRoom();
runIntroSeq();
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "introearly"
}
clearBeforeLoad();
_newLocation = 53;
loadIntroRoom();
runIntroSeq();
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "introearly"
}
clearBeforeLoad();
allPalette();
_newLocation = 54;
loadIntroRoom();
runIntroSeq();
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "introearly"
}
getRidOfTempText();
clearBeforeLoad();
_lastHardKey = Common::KEYCODE_INVALID;
}
void DreamWebEngine::runIntroSeq() {
_getBack = 0;
do {
waitForVSync();
if (_lastHardKey == Common::KEYCODE_ESCAPE)
break;
spriteUpdate();
waitForVSync();
if (_lastHardKey == Common::KEYCODE_ESCAPE)
break;
delEverything();
printSprites();
reelsOnScreen();
afterIntroRoom();
useTimedText();
waitForVSync();
if (_lastHardKey == Common::KEYCODE_ESCAPE)
break;
dumpMap();
dumpTimedText();
waitForVSync();
if (_lastHardKey == Common::KEYCODE_ESCAPE)
break;
} while (_getBack != 1);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
getRidOfTempText();
clearBeforeLoad();
}
// These were not called in this program arc
// in the original code.. Bug?
//getRidOfTempText();
//clearBeforeLoad();
}
void DreamWebEngine::runEndSeq() {
atmospheres();
_getBack = 0;
do {
waitForVSync();
spriteUpdate();
waitForVSync();
delEverything();
printSprites();
reelsOnScreen();
afterIntroRoom();
useTimedText();
waitForVSync();
dumpMap();
dumpTimedText();
waitForVSync();
} while (_getBack != 1 && !_quitRequested);
}
void DreamWebEngine::loadIntroRoom() {
_introCount = 0;
_vars._location = 255;
loadRoom();
_mapOffsetX = 72;
_mapOffsetY = 16;
clearSprites();
_vars._throughDoor = 0;
_currentKey = 0;
_mainMode = 0;
clearWork();
_vars._newObs = 1;
drawFloor();
reelsOnScreen();
spriteUpdate();
printSprites();
workToScreen();
}
void DreamWebEngine::set16ColPalette() {
}
void DreamWebEngine::realCredits() {
_roomsSample = 33;
_sound->loadRoomsSample(_roomsSample);
_sound->volumeSet(0);
initTitlesGfx();
hangOn(35);
showPCX("I01");
_sound->playChannel0(12, 0);
hangOne(2);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
allPalette();
hangOne(80);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
fadeScreenDowns();
hangOne(256);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
showPCX("I02");
_sound->playChannel0(12, 0);
hangOne(2);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
allPalette();
hangOne(80);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
fadeScreenDowns();
hangOne(256);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
showPCX("I03");
_sound->playChannel0(12, 0);
hangOne(2);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
allPalette();
hangOne(80);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
fadeScreenDowns();
hangOne(256);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
showPCX("I04");
_sound->playChannel0(12, 0);
hangOne(2);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
allPalette();
hangOne(80);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
fadeScreenDowns();
hangOne(256);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
showPCX("I05");
_sound->playChannel0(12, 0);
hangOne(2);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
allPalette();
hangOne(80);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
fadeScreenDowns();
hangOne(256);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
showPCX("I06");
fadeScreenUps();
hangOne(60);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
_sound->playChannel0(13, 0);
hangOne(350);
if (_lastHardKey == Common::KEYCODE_ESCAPE) {
_lastHardKey = Common::KEYCODE_INVALID;
return; // "realcreditsearly"
}
fadeScreenDowns();
hangOne(256);
_lastHardKey = Common::KEYCODE_INVALID;
}
} // End of namespace DreamWeb

1611
engines/dreamweb/use.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,284 @@
/* 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 "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
namespace DreamWeb {
void DreamWebEngine::clearStartPal() {
memset(_startPal, 0, 256 * 3);
}
void DreamWebEngine::clearEndPal() {
memset(_endPal, 0, 256 * 3);
}
void DreamWebEngine::palToStartPal() {
memcpy(_startPal, _mainPal, 256 * 3);
}
void DreamWebEngine::endPalToStart() {
memcpy(_startPal, _endPal, 256 * 3);
}
void DreamWebEngine::startPalToEnd() {
memcpy(_endPal, _startPal, 256 * 3);
}
void DreamWebEngine::palToEndPal() {
memcpy(_endPal, _mainPal, 256 * 3);
}
void DreamWebEngine::fadeDOS() {
return; // FIXME later
waitForVSync();
//processEvents will be called from waitForVSync
uint8 *dst = _startPal;
getPalette(dst, 0, 64);
for (uint fade = 0; fade < 64; ++fade) {
for (uint c = 0; c < 768; ++c) { //original sources decrement 768 values -> 256 colors
if (dst[c]) {
--dst[c];
}
}
setPalette(dst, 0, 64);
waitForVSync();
}
}
void DreamWebEngine::doFade() {
if (_fadeDirection == 0)
return;
processEvents();
uint8 *src = _startPal + 3 * _colorPos;
setPalette(src, _colorPos, _numToFade);
_colorPos += _numToFade;
if (_colorPos == 0)
fadeCalculation();
}
void DreamWebEngine::fadeCalculation() {
if (_fadeCount == 0) {
_fadeDirection = 0;
return;
}
uint8 *startPal = _startPal;
const uint8 *endPal = _endPal;
for (uint i = 0; i < 256 * 3; ++i) {
uint8 s = startPal[i];
uint8 e = endPal[i];
if (s == e)
continue;
else if (s > e)
--startPal[i];
else {
if (_fadeCount <= e)
++startPal[i];
}
}
--_fadeCount;
}
void DreamWebEngine::fadeUpYellows() {
palToEndPal();
memset(_endPal + 231 * 3, 0, 8 * 3);
memset(_endPal + 246 * 3, 0, 1 * 3);
_fadeDirection = 1;
_fadeCount = 63;
_colorPos = 0;
_numToFade = 128;
hangOn(128);
}
void DreamWebEngine::fadeUpMonFirst() {
palToStartPal();
palToEndPal();
memset(_startPal + 231 * 3, 0, 8 * 3);
memset(_startPal + 246 * 3, 0, 1 * 3);
_fadeDirection = 1;
_fadeCount = 63;
_colorPos = 0;
_numToFade = 128;
hangOn(64);
_sound->playChannel1(26);
hangOn(64);
}
void DreamWebEngine::fadeDownMon() {
palToStartPal();
palToEndPal();
memset(_endPal + 231 * 3, 0, 8 * 3);
memset(_endPal + 246 * 3, 0, 1 * 3);
_fadeDirection = 1;
_fadeCount = 63;
_colorPos = 0;
_numToFade = 128;
hangOn(64);
}
void DreamWebEngine::fadeUpMon() {
palToStartPal();
palToEndPal();
memset(_startPal + 231 * 3, 0, 8 * 3);
memset(_startPal + 246 * 3, 0, 1 * 3);
_fadeDirection = 1;
_fadeCount = 63;
_colorPos = 0;
_numToFade = 128;
hangOn(128);
}
void DreamWebEngine::initialMonCols() {
palToStartPal();
memset(_startPal + 230 * 3, 0, 9 * 3);
memset(_startPal + 246 * 3, 0, 1 * 3);
processEvents();
setPalette(_startPal + 230 * 3, 230, 18);
}
void DreamWebEngine::fadeScreenUp() {
clearStartPal();
palToEndPal();
_fadeDirection = 1;
_fadeCount = 63;
_colorPos = 0;
_numToFade = 128;
}
void DreamWebEngine::fadeScreenUps() {
clearStartPal();
palToEndPal();
_fadeDirection = 1;
_fadeCount = 63;
_colorPos = 0;
_numToFade = 64;
}
void DreamWebEngine::fadeScreenUpHalf() {
endPalToStart();
palToEndPal();
_fadeDirection = 1;
_fadeCount = 31;
_colorPos = 0;
_numToFade = 32;
}
void DreamWebEngine::fadeScreenDown() {
palToStartPal();
clearEndPal();
_fadeDirection = 1;
_fadeCount = 63;
_colorPos = 0;
_numToFade = 128;
}
void DreamWebEngine::fadeScreenDowns() {
palToStartPal();
clearEndPal();
_fadeDirection = 1;
_fadeCount = 63;
_colorPos = 0;
_numToFade = 64;
}
void DreamWebEngine::fadeScreenDownHalf() {
palToStartPal();
palToEndPal();
const uint8 *startPal = _startPal;
uint8 *endPal = _endPal;
for (uint i = 0; i < 256 * 3; ++i) {
*endPal >>= 1;
endPal++;
}
memcpy(endPal + (56*3), startPal + (56*3), 3*5);
memcpy(endPal + (77*3), startPal + (77*3), 3*2);
_fadeDirection = 1;
_fadeCount = 31;
_colorPos = 0;
_numToFade = 32;
}
void DreamWebEngine::clearPalette() {
_fadeDirection = 0;
clearStartPal();
dumpCurrent();
}
// Converts palette to grey scale, summed using formula
// .20xred + .59xGreen + .11xBlue
void DreamWebEngine::greyscaleSum() {
byte *src = _mainPal;
byte *dst = _endPal;
for (uint i = 0; i < 256; ++i) {
const unsigned int r = 20 * *src++;
const unsigned int g = 59 * *src++;
const unsigned int b = 11 * *src++;
const byte grey = (r + b + g) / 100;
byte tmp;
tmp = grey;
//if (tmp != 0) // FIXME: The assembler code has this check commented out. Bug or feature?
tmp += _addToRed;
*dst++ = tmp;
tmp = grey;
if (tmp != 0)
tmp += _addToGreen;
*dst++ = tmp;
tmp = grey;
if (tmp != 0)
tmp += _addToBlue;
*dst++ = tmp;
}
}
void DreamWebEngine::allPalette() {
memcpy(_startPal, _mainPal, 3 * 256);
dumpCurrent();
}
void DreamWebEngine::dumpCurrent() {
uint8 *pal = _startPal;
waitForVSync();
processEvents();
setPalette(pal, 0, 128);
pal += 128 * 3;
waitForVSync();
processEvents();
setPalette(pal, 128, 128);
}
} // End of namespace DreamWeb

View File

@@ -0,0 +1,440 @@
/* 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 "dreamweb/dreamweb.h"
#include "common/file.h"
#include "engines/util.h"
#include "graphics/surface.h"
#include "graphics/scaler/downscaler.h"
#include "image/pcx.h"
namespace DreamWeb {
const uint16 kZoomx = 8;
const uint16 kZoomy = 132;
void DreamWebEngine::multiGet(uint8 *dst, uint16 x, uint16 y, uint8 w, uint8 h) {
assert(x < kScreenwidth);
assert(y < kScreenheight);
const uint8 *src = workspace() + x + y * kScreenwidth;
if (y + h > kScreenheight)
h = kScreenheight - y;
if (x + w > kScreenwidth)
w = kScreenwidth - x;
for (unsigned l = 0; l < h; ++l) {
const uint8 *src_p = src + kScreenwidth * l;
uint8 *dst_p = dst + w * l;
memcpy(dst_p, src_p, w);
}
}
void DreamWebEngine::multiPut(const uint8 *src, uint16 x, uint16 y, uint8 w, uint8 h) {
assert(x < kScreenwidth);
assert(y < kScreenheight);
uint8 *dst = workspace() + x + y * kScreenwidth;
if (y + h > kScreenheight)
h = kScreenheight - y;
if (x + w > kScreenwidth)
w = kScreenwidth - x;
for (unsigned l = 0; l < h; ++l) {
const uint8 *src_p = src + w * l;
uint8 *dst_p = dst + kScreenwidth * l;
memcpy(dst_p, src_p, w);
}
}
void DreamWebEngine::multiDump(uint16 x, uint16 y, uint8 width, uint8 height) {
unsigned offset = x + y * kScreenwidth;
blit(workspace() + offset, kScreenwidth, x, y, width, height);
}
void DreamWebEngine::workToScreen() {
blit(workspace(), kScreenwidth, 0, 0, kScreenwidth, kScreenheight);
}
void DreamWebEngine::frameOutNm(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y) {
dst += pitch * y + x;
for (uint16 j = 0; j < height; ++j) {
memcpy(dst, src, width);
dst += pitch;
src += width;
}
}
void DreamWebEngine::frameOutBh(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y) {
uint16 stride = pitch - width;
dst += y * pitch + x;
for (uint16 i = 0; i < height; ++i) {
for (uint16 j = 0; j < width; ++j) {
if (*dst == 0xff) {
*dst = *src;
}
++src;
++dst;
}
dst += stride;
}
}
void DreamWebEngine::frameOutFx(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, uint16 x, uint16 y) {
uint16 stride = pitch - width;
dst += y * pitch + x;
dst -= width;
for (uint16 j = 0; j < height; ++j) {
for (uint16 i = 0; i < width; ++i) {
uint8 pixel = src[width - i - 1];
if (pixel)
*dst = pixel;
++dst;
}
src += width;
dst += stride;
}
}
void DreamWebEngine::doShake() {
uint8 &counter = _vars._shakeCounter;
if (counter == 48)
return;
++counter;
static const int shakeTable[] = {
0, -2, 3, -2, 0, 2, 4, -1,
1, -3, 3, 2, 0, -2, 3, -2,
0, 2, 4, -1, 1, -3, 3, 2,
0, -2, 3, -2, 0, 2, 4, -1,
1, -3, 3, 2, 0, -2, 3, -2,
0, 2, 4, -1, 1, -3, 3, 2,
0, -2, 3, -2, 0, 2, 4, -1,
1, -3, 3, 2, 0, -2, 3, -2,
0, 2, 4, -1, 1, -3, 3, 2,
0, -2, 3, -2, 0, 2, 4, -1,
1, -3, 3, 2, 0, -2, 3, -2,
0, 2, 4, -1, 1, -3, 3, 2,
0, -2, 3, -2, 0, 2, 4, -1,
1, -3, 3, 0,
};
assert(counter < ARRAYSIZE(shakeTable));
int offset = shakeTable[counter];
setShakePos(offset >= 0 ? offset : -offset);
}
void DreamWebEngine::setMode() {
waitForVSync();
initGraphics(kScreenwidth, kScreenheight);
}
void DreamWebEngine::showPCX(const Common::String &suffix) {
Common::Path name(getDatafilePrefix() + suffix);
Common::File pcxFile;
if (!pcxFile.open(name)) {
warning("showpcx: Could not open '%s'", name.toString(Common::Path::kNativeSeparator).c_str());
return;
}
Image::PCXDecoder pcx;
if (!pcx.loadStream(pcxFile)) {
warning("showpcx: Could not process '%s'", name.toString(Common::Path::kNativeSeparator).c_str());
return;
}
// Read the 16-color palette into the 'maingamepal' buffer. Note that
// the color components have to be adjusted from 8 to 6 bits.
memset(_mainPal, 0xff, 256 * 3);
memcpy(_mainPal, pcx.getPalette().data(), 48);
for (int i = 0; i < 48; i++) {
_mainPal[i] >>= 2;
}
const Graphics::Surface *pcxSurface = pcx.getSurface();
if (pcxSurface->format.bytesPerPixel != 1)
error("Invalid bytes per pixel in PCX surface (%d)", pcxSurface->format.bytesPerPixel);
g_system->fillScreen(0);
if (pcxSurface->w >= g_system->getWidth() * 2) {
Graphics::Surface *s = g_system->lockScreen();
Graphics::downscaleSurfaceByHalf(s, pcxSurface, _mainPal);
g_system->unlockScreen();
} else {
g_system->copyRectToScreen(pcxSurface->getPixels(), pcxSurface->pitch,
0, 0, pcxSurface->w, pcxSurface->h);
}
}
void DreamWebEngine::frameOutV(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, int16 x, int16 y) {
// NB : These resilience checks were not in the original engine, but did they result in undefined behaviour
// or was something broken during porting to C++?
assert(pitch == kScreenwidth);
if (x < 0) {
assert(width >= -x);
width -= -x;
src += -x;
x = 0;
}
if (y < 0) {
assert(height >= -y);
height -= -y;
src += (-y) * width;
y = 0;
}
if ((uint16)x >= kScreenwidth)
return;
if ((uint16)y >= kScreenheight)
return;
if ((uint16)x + width > kScreenwidth) {
width = kScreenwidth - x;
}
if ((uint16)y + height > kScreenheight) {
height = kScreenheight - y;
}
uint16 stride = pitch - width;
dst += pitch * y + x;
for (uint16 j = 0; j < height; ++j) {
for (uint16 i = 0; i < width; ++i) {
uint8 pixel = *src++;
if (pixel)
*dst = pixel;
++dst;
}
dst += stride;
}
}
void DreamWebEngine::showFrame(const GraphicsFile &frameData, uint16 x, uint16 y, uint16 frameNumber, uint8 effectsFlag) {
uint8 width, height;
showFrame(frameData, x, y, frameNumber, effectsFlag, &width, &height);
}
void DreamWebEngine::showFrameInternal(const uint8 *pSrc, uint16 x, uint16 y, uint8 effectsFlag, uint8 width, uint8 height) {
if (effectsFlag) {
if (effectsFlag & 128) { //centered
x -= width / 2;
y -= height / 2;
}
if (effectsFlag & 64) { // diffDest
error("Unsupported DreamWebEngine::showFrame effectsFlag %d", effectsFlag);
/*
frameOutFx(es.ptr(0, dx * *height), pSrc, dx, *width, *height, x, y);
return;
*/
}
if (effectsFlag & 8) { // printList
//addToPrintList(x - _mapAdX, y - _mapAdY); // NB: Commented in the original asm
}
if (effectsFlag & 4) { // flippedX
frameOutFx(workspace(), pSrc, kScreenwidth, width, height, x, y);
return;
}
if (effectsFlag & 2) { // noMask
frameOutNm(workspace(), pSrc, kScreenwidth, width, height, x, y);
return;
}
if (effectsFlag & 32) {
frameOutBh(workspace(), pSrc, kScreenwidth, width, height, x, y);
return;
}
}
// "noEffects"
frameOutV(workspace(), pSrc, kScreenwidth, width, height, x, y);
}
void DreamWebEngine::showFrame(const GraphicsFile &frameData, uint16 x, uint16 y, uint16 frameNumber, uint8 effectsFlag, uint8 *width, uint8 *height) {
const Frame *frame = &frameData._frames[frameNumber];
if ((frame->width == 0) && (frame->height == 0)) {
*width = 0;
*height = 0;
return;
}
// "notBlankShow"
if ((effectsFlag & 128) == 0) {
x += frame->x;
y += frame->y;
}
// "skipOffsets"
*width = frame->width;
*height = frame->height;
const uint8 *pSrc = frameData.getFrameData(frameNumber);
showFrameInternal(pSrc, x, y, effectsFlag, *width, *height);
}
void DreamWebEngine::clearWork() {
memset(workspace(), 0, kScreenwidth*kScreenheight);
}
void DreamWebEngine::dumpZoom() {
if (_vars._zoomOn == 1)
multiDump(kZoomx + 5, kZoomy + 4, 46, 40);
}
void DreamWebEngine::crosshair() {
uint16 frame;
if ((_commandType != 3) && (_commandType < 10)) {
frame = 9;
} else {
frame = 29;
}
showFrame(_icons1, kZoomx + 24, kZoomy + 19, frame, 0);
}
void DreamWebEngine::getUnderZoom() {
multiGet(_zoomSpace, kZoomx + 5, kZoomy + 4, 46, 40);
}
void DreamWebEngine::putUnderZoom() {
multiPut(_zoomSpace, kZoomx + 5, kZoomy + 4, 46, 40);
}
void DreamWebEngine::zoomIcon() {
if (_vars._zoomOn == 0)
return;
showFrame(_icons1, kZoomx, kZoomy-1, 8, 0);
}
void DreamWebEngine::zoom() {
if (_vars._watchingTime != 0)
return;
if (_vars._zoomOn != 1)
return;
if (_commandType >= 199) {
putUnderZoom();
return;
}
uint16 srcOffset = (_oldPointerY - 9) * kScreenwidth + (_oldPointerX - 11);
uint16 dstOffset = (kZoomy + 4) * kScreenwidth + (kZoomx + 5);
const uint8 *src = workspace() + srcOffset;
uint8 *dst = workspace() + dstOffset;
for (uint i = 0; i < 20; ++i) {
for (uint j = 0; j < 23; ++j) {
uint8 v = src[j];
dst[2*j+0] = v;
dst[2*j+1] = v;
dst[2*j+kScreenwidth] = v;
dst[2*j+kScreenwidth+1] = v;
}
src += kScreenwidth;
dst += kScreenwidth*2;
}
crosshair();
_didZoom = 1;
}
void DreamWebEngine::panelToMap() {
multiGet(_mapStore, _mapXStart + _mapAdX, _mapYStart + _mapAdY, _mapXSize, _mapYSize);
}
void DreamWebEngine::mapToPanel() {
multiPut(_mapStore, _mapXStart + _mapAdX, _mapYStart + _mapAdY, _mapXSize, _mapYSize);
}
void DreamWebEngine::dumpMap() {
multiDump(_mapXStart + _mapAdX, _mapYStart + _mapAdY, _mapXSize, _mapYSize);
}
bool DreamWebEngine::pixelCheckSet(const ObjPos *pos, uint8 x, uint8 y) {
x -= pos->xMin;
y -= pos->yMin;
SetObject *setObject = getSetAd(pos->index);
const Frame &frame = _setFrames._frames[setObject->index];
const uint8 *ptr = _setFrames.getFrameData(setObject->index) + y * frame.width + x;
return *ptr != 0;
}
void DreamWebEngine::loadPalFromIFF() {
Common::File palFile;
uint8* buf = new uint8[2000];
palFile.open(Common::Path(getDatafilePrefix() + "PAL"));
palFile.read(buf, 2000);
palFile.close();
const uint8 *src = buf + 0x30;
uint8 *dst = _mainPal;
for (uint i = 0; i < 256*3; ++i) {
uint8 c = src[i] / 4;
if (_brightPalette) {
if (c) {
c = c + c / 2 + c / 4;
if (c > 63)
c = 63;
}
}
dst[i] = c;
}
delete[] buf;
}
void DreamWebEngine::createPanel() {
showFrame(_icons2, 0, 8, 0, 2);
showFrame(_icons2, 160, 8, 0, 2);
showFrame(_icons2, 0, 104, 0, 2);
showFrame(_icons2, 160, 104, 0, 2);
}
void DreamWebEngine::createPanel2() {
createPanel();
showFrame(_icons2, 0, 0, 5, 2);
showFrame(_icons2, 160, 0, 5, 2);
}
void DreamWebEngine::showPanel() {
showFrame(_icons1, 72, 0, 19, 0);
showFrame(_icons1, 192, 0, 19, 0);
}
void DreamWebEngine::transferFrame(uint8 from, uint8 to, uint8 offset) {
const Frame &freeFrame = _freeFrames._frames[3*from + offset];
Frame &exFrame = _exFrames._frames[3*to + offset];
exFrame.width = freeFrame.width;
exFrame.height = freeFrame.height;
exFrame.x = freeFrame.x;
exFrame.y = freeFrame.y;
uint16 byteCount = freeFrame.width * freeFrame.height;
const uint8 *src = _freeFrames.getFrameData(3*from + offset);
uint8 *dst = _exFrames._data + _vars._exFramePos;
assert(_vars._exFramePos + byteCount <= kExframeslen);
memcpy(dst, src, byteCount);
exFrame.setPtr(_vars._exFramePos);
_vars._exFramePos += byteCount;
}
} // End of namespace DreamWeb