Initial commit
This commit is contained in:
214
engines/stark/services/archiveloader.cpp
Normal file
214
engines/stark/services/archiveloader.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/archiveloader.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
#include "engines/stark/resources/level.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
ArchiveLoader::LoadedArchive::LoadedArchive(const Common::Path& archiveName) :
|
||||
_filename(archiveName),
|
||||
_root(nullptr),
|
||||
_useCount(0) {
|
||||
if (!_xarc.open(archiveName)) {
|
||||
error("Unable to open archive '%s'", archiveName.toString(Common::Path::kNativeSeparator).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ArchiveLoader::LoadedArchive::~LoadedArchive() {
|
||||
// Resource lifecycle update
|
||||
_root->onPreDestroy();
|
||||
|
||||
delete _root;
|
||||
}
|
||||
|
||||
void ArchiveLoader::LoadedArchive::importResources() {
|
||||
// Import the resource tree
|
||||
_root = Formats::XRCReader::importTree(&_xarc);
|
||||
}
|
||||
|
||||
ArchiveLoader::~ArchiveLoader() {
|
||||
for (LoadedArchiveList::iterator it = _archives.begin(); it != _archives.end(); it++) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
bool ArchiveLoader::load(const Common::Path &archiveName) {
|
||||
if (hasArchive(archiveName)) {
|
||||
// Already loaded
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadedArchive *archive = new LoadedArchive(archiveName);
|
||||
_archives.push_back(archive);
|
||||
|
||||
archive->importResources();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ArchiveLoader::unloadUnused() {
|
||||
for (LoadedArchiveList::iterator it = _archives.begin(); it != _archives.end(); it++) {
|
||||
if (!(*it)->isInUse()) {
|
||||
delete *it;
|
||||
it = _archives.erase(it);
|
||||
it--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArchiveReadStream *ArchiveLoader::getFile(const Common::Path &fileName, const Common::Path &archiveName) {
|
||||
LoadedArchive *archive = findArchive(archiveName);
|
||||
const Formats::XARCArchive &xarc = archive->getXArc();
|
||||
|
||||
Common::SeekableReadStream *stream = xarc.createReadStreamForMember(fileName);
|
||||
if (!stream) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new ArchiveReadStream(stream);
|
||||
}
|
||||
|
||||
bool ArchiveLoader::returnRoot(const Common::Path &archiveName) {
|
||||
LoadedArchive *archive = findArchive(archiveName);
|
||||
archive->decUsage();
|
||||
|
||||
return !archive->isInUse();
|
||||
}
|
||||
|
||||
bool ArchiveLoader::hasArchive(const Common::Path &archiveName) const {
|
||||
for (LoadedArchiveList::const_iterator it = _archives.begin(); it != _archives.end(); it++) {
|
||||
if ((*it)->getFilename() == archiveName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ArchiveLoader::LoadedArchive *ArchiveLoader::findArchive(const Common::Path &archiveName) const {
|
||||
for (LoadedArchiveList::const_iterator it = _archives.begin(); it != _archives.end(); it++) {
|
||||
if ((*it)->getFilename() == archiveName) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
error("The archive with name '%s' is not loaded.", archiveName.toString(Common::Path::kNativeSeparator).c_str());
|
||||
}
|
||||
|
||||
Common::Path ArchiveLoader::buildArchiveName(Resources::Level *level, Resources::Location *location) const {
|
||||
Common::String archive;
|
||||
|
||||
if (!location) {
|
||||
switch (level->getSubType()) {
|
||||
case 1:
|
||||
archive = Common::String::format("%s/%s.xarc", level->getName().c_str(), level->getName().c_str());
|
||||
break;
|
||||
case 2:
|
||||
archive = Common::String::format("%02x/%02x.xarc", level->getIndex(), level->getIndex());
|
||||
break;
|
||||
default:
|
||||
error("Unknown level type %d", level->getSubType());
|
||||
}
|
||||
} else {
|
||||
archive = Common::String::format("%02x/%02x/%02x.xarc", level->getIndex(), location->getIndex(), location->getIndex());
|
||||
}
|
||||
|
||||
return Common::Path(archive, '/');
|
||||
}
|
||||
|
||||
Common::Path ArchiveLoader::getExternalFilePath(const Common::Path &fileName, const Common::Path &archiveName) const {
|
||||
// Build a path of the type 45/00/
|
||||
Common::Path filePath = archiveName;
|
||||
if (!filePath.isSeparatorTerminated()) {
|
||||
filePath = filePath.getParent();
|
||||
}
|
||||
filePath.joinInPlace("xarc");
|
||||
filePath.joinInPlace(fileName);
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *ArchiveLoader::getExternalFile(const Common::Path &fileName, const Common::Path &archiveName) const {
|
||||
Common::Path filePath = getExternalFilePath(fileName, archiveName);
|
||||
return SearchMan.createReadStreamForMember(filePath);
|
||||
}
|
||||
|
||||
ArchiveReadStream::ArchiveReadStream(
|
||||
Common::SeekableReadStream *parentStream, DisposeAfterUse::Flag disposeParentStream) :
|
||||
SeekableSubReadStream(parentStream, 0, parentStream->size(), disposeParentStream) {
|
||||
}
|
||||
|
||||
ArchiveReadStream::~ArchiveReadStream() {
|
||||
}
|
||||
|
||||
Common::String ArchiveReadStream::readString() {
|
||||
// Read the string length
|
||||
uint32 length = readUint32LE();
|
||||
|
||||
// Read the string
|
||||
char *data = new char[length + 1];
|
||||
read(data, length);
|
||||
data[length] = '\0';
|
||||
|
||||
Common::String string(data);
|
||||
delete[] data;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
Common::String ArchiveReadStream::readString16() {
|
||||
// Read the string length
|
||||
uint16 length = readUint16LE();
|
||||
|
||||
// Read the string
|
||||
char *data = new char[length + 1];
|
||||
read(data, length);
|
||||
data[length] = '\0';
|
||||
|
||||
Common::String string(data);
|
||||
delete[] data;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
Math::Vector3d ArchiveReadStream::readVector3() {
|
||||
Math::Vector3d v;
|
||||
v.readFromStream(this);
|
||||
return v;
|
||||
}
|
||||
|
||||
Math::Quaternion ArchiveReadStream::readQuaternion() {
|
||||
Math::Quaternion q;
|
||||
q.readFromStream(this);
|
||||
return q;
|
||||
}
|
||||
|
||||
float ArchiveReadStream::readFloat() {
|
||||
float f;
|
||||
read(&f, sizeof(float));
|
||||
return f;
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
132
engines/stark/services/archiveloader.h
Normal file
132
engines/stark/services/archiveloader.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_SERVICES_ARCHIVE_LOADER_H
|
||||
#define STARK_SERVICES_ARCHIVE_LOADER_H
|
||||
|
||||
#include "common/list.h"
|
||||
#include "common/str.h"
|
||||
#include "common/substream.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "math/quat.h"
|
||||
#include "math/vector3d.h"
|
||||
|
||||
#include "engines/stark/formats/xarc.h"
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Resources {
|
||||
class Level;
|
||||
class Location;
|
||||
}
|
||||
|
||||
/**
|
||||
* A read stream with helper functions to read usual data types
|
||||
*/
|
||||
class ArchiveReadStream : public Common::SeekableSubReadStream {
|
||||
public:
|
||||
ArchiveReadStream(Common::SeekableReadStream *parentStream, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::YES);
|
||||
virtual ~ArchiveReadStream();
|
||||
|
||||
Common::String readString();
|
||||
Common::String readString16();
|
||||
Math::Vector3d readVector3();
|
||||
Math::Quaternion readQuaternion();
|
||||
float readFloat();
|
||||
};
|
||||
|
||||
/**
|
||||
* XARC Archive loader.
|
||||
*
|
||||
* Maintains a list of opened archive files.
|
||||
* Loads the resources from the XRC tree.
|
||||
*/
|
||||
class ArchiveLoader {
|
||||
|
||||
public:
|
||||
~ArchiveLoader();
|
||||
|
||||
/** Load a Xarc archive, and add it to the managed archives list */
|
||||
bool load(const Common::Path &archiveName);
|
||||
|
||||
/** Unload all the unused Xarc archives */
|
||||
void unloadUnused();
|
||||
|
||||
/** Retrieve a file from a specified archive */
|
||||
ArchiveReadStream *getFile(const Common::Path &fileName, const Common::Path &archiveName);
|
||||
|
||||
/** Get the resource tree root for an archive, and increment the archive use count */
|
||||
template <class T>
|
||||
T *useRoot(const Common::Path &archiveName);
|
||||
|
||||
/** Decrement the root's archive use count */
|
||||
bool returnRoot(const Common::Path &archiveName);
|
||||
|
||||
/** Build the archive filename for a level or a location */
|
||||
Common::Path buildArchiveName(Resources::Level *level, Resources::Location *location = nullptr) const;
|
||||
|
||||
/** Retrieve a file relative to a specified archive */
|
||||
Common::SeekableReadStream *getExternalFile(const Common::Path &fileName, const Common::Path &archiveName) const;
|
||||
Common::Path getExternalFilePath(const Common::Path &fileName, const Common::Path &archiveName) const;
|
||||
|
||||
private:
|
||||
class LoadedArchive {
|
||||
public:
|
||||
explicit LoadedArchive(const Common::Path &archiveName);
|
||||
~LoadedArchive();
|
||||
|
||||
const Common::Path &getFilename() const { return _filename; }
|
||||
const Formats::XARCArchive &getXArc() const { return _xarc; }
|
||||
Resources::Object *getRoot() const { return _root; }
|
||||
|
||||
void importResources();
|
||||
|
||||
bool isInUse() const { return _useCount > 0; }
|
||||
void incUsage() { _useCount++; }
|
||||
void decUsage() { _useCount = MAX<int>(_useCount - 1, 0); }
|
||||
|
||||
private:
|
||||
uint _useCount;
|
||||
Common::Path _filename;
|
||||
Formats::XARCArchive _xarc;
|
||||
Resources::Object *_root;
|
||||
};
|
||||
|
||||
typedef Common::List<LoadedArchive *> LoadedArchiveList;
|
||||
|
||||
bool hasArchive(const Common::Path &archiveName) const;
|
||||
LoadedArchive *findArchive(const Common::Path &archiveName) const;
|
||||
|
||||
LoadedArchiveList _archives;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T *ArchiveLoader::useRoot(const Common::Path &archiveName) {
|
||||
LoadedArchive *archive = findArchive(archiveName);
|
||||
archive->incUsage();
|
||||
return Resources::Object::cast<T>(archive->getRoot());
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_ARCHIVE_LOADER_H
|
||||
263
engines/stark/services/dialogplayer.cpp
Normal file
263
engines/stark/services/dialogplayer.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/dialogplayer.h"
|
||||
#include "engines/stark/services/diary.h"
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/userinterface.h"
|
||||
|
||||
#include "engines/stark/resources/script.h"
|
||||
#include "engines/stark/resources/speech.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
DialogPlayer::DialogPlayer() :
|
||||
_currentDialog(nullptr),
|
||||
_currentReply(nullptr),
|
||||
_interruptedDialog(nullptr),
|
||||
_interruptedReply(nullptr),
|
||||
_speechReady(false),
|
||||
_singleSpeech(nullptr),
|
||||
_optionsAvailable(false) {
|
||||
}
|
||||
|
||||
DialogPlayer::~DialogPlayer() {}
|
||||
|
||||
void DialogPlayer::run(Resources::Dialog *dialog) {
|
||||
reset();
|
||||
|
||||
StarkUserInterface->setInteractive(false);
|
||||
|
||||
if (!_currentDialog) {
|
||||
Common::String dialogTitle = dialog->getDiaryTitle();
|
||||
int32 characterId = dialog->getCharacter();
|
||||
Common::String characterName = StarkGlobal->getCharacterName(characterId);
|
||||
|
||||
StarkDiary->openDialog(dialogTitle, characterName, characterId);
|
||||
}
|
||||
|
||||
_currentDialog = dialog;
|
||||
buildOptions();
|
||||
}
|
||||
|
||||
void DialogPlayer::playSingle(Resources::Speech *speech) {
|
||||
reset();
|
||||
|
||||
_singleSpeech = speech;
|
||||
_speechReady = true;
|
||||
}
|
||||
|
||||
bool DialogPlayer::isRunning() const {
|
||||
return _currentDialog != nullptr || _interruptedDialog != nullptr;
|
||||
}
|
||||
|
||||
bool DialogPlayer::isSpeechReady() const {
|
||||
return _speechReady;
|
||||
}
|
||||
|
||||
bool DialogPlayer::isSpeechReady(Resources::Speech *speech) const {
|
||||
return _speechReady && _singleSpeech == speech;
|
||||
}
|
||||
|
||||
Resources::Speech *DialogPlayer::acquireReadySpeech() {
|
||||
assert(_speechReady);
|
||||
_speechReady = false;
|
||||
|
||||
if (_singleSpeech) {
|
||||
return _singleSpeech;
|
||||
} else {
|
||||
return _currentReply->getCurrentSpeech();
|
||||
}
|
||||
}
|
||||
|
||||
bool DialogPlayer::areOptionsAvailable() const {
|
||||
return _optionsAvailable;
|
||||
}
|
||||
|
||||
Common::Array<DialogPlayer::Option> DialogPlayer::listOptions() const {
|
||||
return _options;
|
||||
}
|
||||
|
||||
void DialogPlayer::removeLastOnlyOption() {
|
||||
int32 lastOnlyOptionIndex = -1;
|
||||
|
||||
for (uint i = 0; i < _options.size(); i++) {
|
||||
Resources::Dialog::Topic *topic = _options[i]._topic;
|
||||
Resources::Dialog::Reply *reply = topic->getReply(_options[i]._replyIndex);
|
||||
if (reply->isLastOnly()) {
|
||||
lastOnlyOptionIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastOnlyOptionIndex >= 0) {
|
||||
_options.remove_at(lastOnlyOptionIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void DialogPlayer::buildOptions() {
|
||||
Resources::Dialog::TopicArray availableTopics = _currentDialog->listAvailableTopics();
|
||||
|
||||
for (uint i = 0; i < availableTopics.size(); i++) {
|
||||
Option option;
|
||||
|
||||
option._type = kOptionTypeAsk;
|
||||
option._topic = availableTopics[i];
|
||||
option._caption = availableTopics[i]->getCaption();
|
||||
option._replyIndex = availableTopics[i]->getNextReplyIndex();
|
||||
|
||||
Resources::Dialog::Reply *reply = availableTopics[i]->getReply(option._replyIndex);
|
||||
if (reply->checkCondition()) {
|
||||
_options.push_back(option);
|
||||
}
|
||||
}
|
||||
|
||||
if (_options.size() > 1) {
|
||||
removeLastOnlyOption();
|
||||
}
|
||||
|
||||
if (_options.size() == 1) {
|
||||
// Only one option, just run it
|
||||
selectOption(0);
|
||||
} else {
|
||||
_optionsAvailable = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DialogPlayer::selectOption(uint32 index) {
|
||||
_optionsAvailable = false;
|
||||
|
||||
Option &option = _options[index];
|
||||
|
||||
//TODO: Complete
|
||||
|
||||
switch (option._type) {
|
||||
case kOptionTypeAsk: {
|
||||
Resources::Dialog::Topic *topic = option._topic;
|
||||
|
||||
// Set the current reply
|
||||
_currentReply = topic->startReply(option._replyIndex);
|
||||
|
||||
Resources::Speech *speech = _currentReply->getCurrentSpeech();
|
||||
if (speech) {
|
||||
StarkDiary->logSpeech(speech->getPhrase(), speech->getCharacterId());
|
||||
|
||||
_speechReady = true;
|
||||
} else {
|
||||
onReplyEnd();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error("Unhandled option type %d", option._type);
|
||||
}
|
||||
}
|
||||
|
||||
void DialogPlayer::onReplyEnd() {
|
||||
Resources::Script *nextScript = _currentDialog->getNextScript(_currentReply);
|
||||
Resources::Dialog *nextDialog = _currentDialog->getNextDialog(_currentReply);
|
||||
|
||||
if (nextScript) {
|
||||
// Save the dialog player's state before running the script,
|
||||
// so that we can restore it when the script ends.
|
||||
// The script might run another dialog.
|
||||
saveToInterruptionSlot();
|
||||
|
||||
nextScript->addReturnObject(_currentDialog);
|
||||
nextScript->execute(Resources::Script::kCallModeDialogCreateSelections);
|
||||
} else if (nextDialog) {
|
||||
run(nextDialog);
|
||||
} else {
|
||||
// Quit the dialog
|
||||
reset();
|
||||
StarkUserInterface->setInteractive(true);
|
||||
}
|
||||
}
|
||||
|
||||
void DialogPlayer::reset() {
|
||||
if (_currentDialog) {
|
||||
StarkDiary->closeDialog();
|
||||
}
|
||||
|
||||
_currentDialog = nullptr;
|
||||
_currentReply = nullptr;
|
||||
_singleSpeech = nullptr;
|
||||
_speechReady = false;
|
||||
_optionsAvailable = false;
|
||||
_options.clear();
|
||||
}
|
||||
|
||||
void DialogPlayer::update() {
|
||||
if (_singleSpeech || !_currentDialog || !_currentReply) {
|
||||
return; // Nothing to do
|
||||
}
|
||||
|
||||
//TODO: Complete
|
||||
|
||||
Resources::Speech *speech = _currentReply->getCurrentSpeech();
|
||||
if (speech && _speechReady) {
|
||||
// A new line is already ready, no need to prepare another one
|
||||
return;
|
||||
}
|
||||
|
||||
if (!speech || !speech->isPlaying()) {
|
||||
// A line has ended, play the next one
|
||||
_currentReply->goToNextLine();
|
||||
speech = _currentReply->getCurrentSpeech();
|
||||
if (speech) {
|
||||
StarkDiary->logSpeech(speech->getPhrase(), speech->getCharacterId());
|
||||
|
||||
_speechReady = true;
|
||||
} else {
|
||||
onReplyEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DialogPlayer::resume(Resources::Dialog *dialog) {
|
||||
assert(_interruptedDialog == dialog);
|
||||
|
||||
// Restore our state from before running the script
|
||||
restoreFromInterruptionSlot();
|
||||
|
||||
Resources::Dialog *nextDialog = _currentDialog->getNextDialog(_currentReply);
|
||||
if (nextDialog) {
|
||||
run(nextDialog);
|
||||
} else {
|
||||
// Quit the dialog
|
||||
reset();
|
||||
StarkUserInterface->setInteractive(true);
|
||||
}
|
||||
}
|
||||
|
||||
void DialogPlayer::saveToInterruptionSlot() {
|
||||
_interruptedDialog = _currentDialog;
|
||||
_interruptedReply = _currentReply;
|
||||
}
|
||||
|
||||
void DialogPlayer::restoreFromInterruptionSlot() {
|
||||
_currentDialog = _interruptedDialog;
|
||||
_currentReply = _interruptedReply;
|
||||
_interruptedDialog = nullptr;
|
||||
_interruptedReply = nullptr;
|
||||
}
|
||||
} // End of namespace Stark
|
||||
119
engines/stark/services/dialogplayer.h
Normal file
119
engines/stark/services/dialogplayer.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/* 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 STARK_SERVICES_DIALOG_PLAYER_H
|
||||
#define STARK_SERVICES_DIALOG_PLAYER_H
|
||||
|
||||
#include "common/array.h"
|
||||
|
||||
#include "engines/stark/resources/dialog.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Resources {
|
||||
class Speech;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialog player
|
||||
*
|
||||
* Handles the state of the currently running dialog, and implements the
|
||||
* associated logic.
|
||||
*/
|
||||
class DialogPlayer {
|
||||
public:
|
||||
DialogPlayer();
|
||||
virtual ~DialogPlayer();
|
||||
|
||||
enum OptionType {
|
||||
kOptionTypeAsk = 0
|
||||
};
|
||||
|
||||
struct Option {
|
||||
uint32 _type;
|
||||
Common::String _caption;
|
||||
Resources::Dialog::Topic *_topic;
|
||||
int32 _replyIndex;
|
||||
};
|
||||
|
||||
/** Enter a dialog */
|
||||
void run(Resources::Dialog *dialog);
|
||||
|
||||
/** Play a one-shot sentence */
|
||||
void playSingle(Resources::Speech *speech);
|
||||
|
||||
/** Check if a dialog is running */
|
||||
bool isRunning() const;
|
||||
|
||||
/** Update the currently running dialog */
|
||||
void update();
|
||||
|
||||
/** Select a dialog option */
|
||||
void selectOption(uint32 index);
|
||||
|
||||
/** Can a speech be played? */
|
||||
bool isSpeechReady() const;
|
||||
bool isSpeechReady(Resources::Speech *speech) const;
|
||||
|
||||
/** Return the speech to be played */
|
||||
Resources::Speech *acquireReadySpeech();
|
||||
|
||||
/** Does the player need to choose between options? */
|
||||
bool areOptionsAvailable() const;
|
||||
|
||||
/** List the currently available dialog options */
|
||||
Common::Array<DialogPlayer::Option> listOptions() const;
|
||||
|
||||
/** Resume the dialog after it was interrupted to run a script */
|
||||
void resume(Resources::Dialog *dialog);
|
||||
|
||||
/** Clear the currently running dialog */
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
/** Build a list of available dialog options */
|
||||
void buildOptions();
|
||||
|
||||
/** Removes the last only option from the options list */
|
||||
void removeLastOnlyOption();
|
||||
|
||||
/** Initiate the next action after the end of a reply */
|
||||
void onReplyEnd();
|
||||
|
||||
void saveToInterruptionSlot();
|
||||
void restoreFromInterruptionSlot();
|
||||
|
||||
Resources::Dialog *_currentDialog;
|
||||
Resources::Dialog::Reply *_currentReply;
|
||||
|
||||
Resources::Dialog *_interruptedDialog;
|
||||
Resources::Dialog::Reply *_interruptedReply;
|
||||
|
||||
Resources::Speech *_singleSpeech;
|
||||
|
||||
bool _speechReady;
|
||||
bool _optionsAvailable;
|
||||
Common::Array<Option> _options;
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_DIALOG_PLAYER_H
|
||||
180
engines/stark/services/diary.cpp
Normal file
180
engines/stark/services/diary.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/diary.h"
|
||||
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
#include "engines/stark/services/userinterface.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
Diary::Diary() {
|
||||
clear();
|
||||
}
|
||||
|
||||
Diary::~Diary() {}
|
||||
|
||||
void Diary::clear() {
|
||||
_diaryEntries.clear();
|
||||
_fmvEntries.clear();
|
||||
_conversationEntries.clear();
|
||||
_hasUnreadEntries = false;
|
||||
_pageIndex = 0;
|
||||
}
|
||||
|
||||
void Diary::addDiaryEntry(const Common::String &name) {
|
||||
_diaryEntries.push_back(name);
|
||||
_hasUnreadEntries = true;
|
||||
StarkUserInterface->notifyDiaryEntryEnabled();
|
||||
}
|
||||
|
||||
void Diary::addFMVEntry(const Common::Path &filename, const Common::String &title, int gameDisc) {
|
||||
if (!hasFMVEntry(filename)) {
|
||||
FMVEntry entry;
|
||||
entry.filename = filename;
|
||||
entry.title = title;
|
||||
entry.gameDisc = gameDisc;
|
||||
_fmvEntries.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
bool Diary::hasFMVEntry(const Common::Path &filename) const {
|
||||
for (uint i = 0; i < _fmvEntries.size(); i++) {
|
||||
if (_fmvEntries[i].filename == filename) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Diary::readStateFromStream(Common::SeekableReadStream *stream, uint32 version) {
|
||||
clear();
|
||||
|
||||
if (version <= 6) {
|
||||
return; //Early save versions did not persist the diary
|
||||
}
|
||||
|
||||
ResourceSerializer serializer(stream, nullptr, version);
|
||||
saveLoad(&serializer);
|
||||
}
|
||||
|
||||
void Diary::writeStateToStream(Common::WriteStream *stream) {
|
||||
ResourceSerializer serializer(nullptr, stream, StateProvider::kSaveVersion);
|
||||
saveLoad(&serializer);
|
||||
}
|
||||
|
||||
void Diary::saveLoad(ResourceSerializer *serializer) {
|
||||
// Diary entries
|
||||
serializer->syncArraySize(_diaryEntries);
|
||||
for (uint i = 0; i < _diaryEntries.size(); i++) {
|
||||
serializer->syncAsString32(_diaryEntries[i]);
|
||||
}
|
||||
|
||||
// FMV entries
|
||||
serializer->syncArraySize(_fmvEntries);
|
||||
for (uint i = 0; i < _fmvEntries.size(); i++) {
|
||||
if (serializer->isSaving()) {
|
||||
Common::String filename(_fmvEntries[i].filename.toString('/'));
|
||||
serializer->syncAsString32(filename);
|
||||
} else {
|
||||
Common::String filename;
|
||||
serializer->syncAsString32(filename);
|
||||
_fmvEntries[i].filename = Common::Path(filename, '/');
|
||||
}
|
||||
serializer->syncAsString32(_fmvEntries[i].title);
|
||||
serializer->syncAsUint32LE(_fmvEntries[i].gameDisc);
|
||||
}
|
||||
|
||||
// Conversations
|
||||
serializer->syncArraySize(_conversationEntries, 8);
|
||||
for (uint i = 0; i < _conversationEntries.size(); i++) {
|
||||
ConversationLog &entry = _conversationEntries[i];
|
||||
serializer->syncAsSint32LE(entry.chapter);
|
||||
serializer->syncAsSint32LE(entry.characterId);
|
||||
serializer->syncAsString32(entry.characterName);
|
||||
serializer->syncAsString32(entry.title);
|
||||
|
||||
serializer->syncArraySize(entry.lines);
|
||||
for (uint j = 0; j < entry.lines.size(); j++) {
|
||||
ConversationLogLine &logLine = entry.lines[j];
|
||||
serializer->syncAsString32(logLine.line);
|
||||
serializer->syncAsSint32LE(logLine.characterId);
|
||||
}
|
||||
}
|
||||
|
||||
// Misc
|
||||
serializer->syncAsByte(_hasUnreadEntries);
|
||||
serializer->syncAsUint32LE(_pageIndex);
|
||||
}
|
||||
|
||||
void Diary::openDialog(const Common::String &title, const Common::String &characterName, int32 characterId) {
|
||||
// Reuse the previous dialog if it has the same title
|
||||
if (_conversationEntries.empty() || _conversationEntries.back().title != title) {
|
||||
ConversationLog conversation;
|
||||
conversation.title = title;
|
||||
conversation.characterName = characterName;
|
||||
conversation.characterId = characterId;
|
||||
conversation.chapter = StarkGlobal->getCurrentChapter();
|
||||
_conversationEntries.push_back(conversation);
|
||||
}
|
||||
|
||||
_conversationEntries.back().dialogActive = true;
|
||||
}
|
||||
|
||||
void Diary::closeDialog() {
|
||||
if (!_conversationEntries.empty()) {
|
||||
_conversationEntries.back().dialogActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Diary::logSpeech(const Common::String &line, int32 characterId) {
|
||||
ConversationLog &conversationLog = _conversationEntries.back();
|
||||
if (conversationLog.dialogActive) {
|
||||
ConversationLogLine logLine;
|
||||
logLine.line = line;
|
||||
logLine.characterId = characterId;
|
||||
|
||||
conversationLog.lines.push_back(logLine);
|
||||
}
|
||||
}
|
||||
|
||||
bool Diary::isEnabled() const {
|
||||
return StarkGlobal->getInventory() && StarkGlobal->hasInventoryItem("Diary");
|
||||
}
|
||||
|
||||
bool Diary::hasUnreadEntries() const {
|
||||
return _hasUnreadEntries;
|
||||
}
|
||||
|
||||
Diary::ConversationLog::ConversationLog() :
|
||||
dialogActive(false),
|
||||
chapter(0),
|
||||
characterId(0) {
|
||||
}
|
||||
|
||||
Diary::ConversationLogLine::ConversationLogLine() :
|
||||
characterId(0) {
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
136
engines/stark/services/diary.h
Normal file
136
engines/stark/services/diary.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_SERVICES_DIARY_H
|
||||
#define STARK_SERVICES_DIARY_H
|
||||
|
||||
#include "common/path.h"
|
||||
#include "common/str.h"
|
||||
#include "common/str-array.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace Stark {
|
||||
|
||||
class ResourceSerializer;
|
||||
|
||||
/**
|
||||
* Diary state storage
|
||||
*
|
||||
* Stores references to all the unlocked data available from the diary menu
|
||||
*/
|
||||
class Diary {
|
||||
public:
|
||||
struct ConversationLogLine {
|
||||
Common::String line;
|
||||
int32 characterId;
|
||||
|
||||
ConversationLogLine();
|
||||
};
|
||||
|
||||
struct ConversationLog {
|
||||
Common::String title;
|
||||
Common::String characterName;
|
||||
int32 characterId;
|
||||
int32 chapter;
|
||||
bool dialogActive;
|
||||
Common::Array<ConversationLogLine> lines;
|
||||
|
||||
ConversationLog();
|
||||
};
|
||||
|
||||
Diary();
|
||||
virtual ~Diary();
|
||||
|
||||
/** Does the player have the diary in their inventory? */
|
||||
bool isEnabled() const;
|
||||
|
||||
/** Does the diary contain entries that have not been read yet? */
|
||||
bool hasUnreadEntries() const;
|
||||
|
||||
/** Mark all the diary entries read */
|
||||
void setDiaryAllRead() { _hasUnreadEntries = false; }
|
||||
|
||||
/** Add an entry to the list of available diary pages */
|
||||
void addDiaryEntry(const Common::String &name);
|
||||
|
||||
/** Get and set the current diary page index */
|
||||
uint32 getPageIndex() const { return _pageIndex; };
|
||||
void setPageIndex(uint32 pageIndex) { _pageIndex = pageIndex; }
|
||||
|
||||
/** Add a FMV entry to the list of movies available to play from the diary */
|
||||
void addFMVEntry(const Common::Path &filename, const Common::String &title, int gameDisc);
|
||||
|
||||
/** Get info of added FMV entries */
|
||||
uint countFMV() const { return _fmvEntries.size(); }
|
||||
const Common::Path &getFMVFilename(uint index) const { return _fmvEntries[index].filename; }
|
||||
const Common::String &getFMVTitle(uint index) const { return _fmvEntries[index].title; }
|
||||
|
||||
/** Get info of added Diary entries */
|
||||
uint countDiary() const { return _diaryEntries.size(); }
|
||||
const Common::String &getDiary(uint index) const { return _diaryEntries[index]; }
|
||||
|
||||
/** Get added Dialog entries */
|
||||
uint countDialog() const { return _conversationEntries.size(); }
|
||||
const ConversationLog &getDialog(uint index) const { return _conversationEntries[index]; }
|
||||
|
||||
/** Start recording speech lines for a dialog */
|
||||
void openDialog(const Common::String &title, const Common::String &characterName, int32 characterId);
|
||||
|
||||
/** Record a speech line for the previously opened dialog */
|
||||
void logSpeech(const Common::String &line, int32 characterId);
|
||||
|
||||
/** Close the currently active dialog */
|
||||
void closeDialog();
|
||||
|
||||
/** Reset all the game state data */
|
||||
void clear();
|
||||
|
||||
/** Replace the current state by that read from the stream */
|
||||
void readStateFromStream(Common::SeekableReadStream *stream, uint32 version);
|
||||
|
||||
/** Write the state to a stream */
|
||||
void writeStateToStream(Common::WriteStream *stream);
|
||||
|
||||
private:
|
||||
struct FMVEntry {
|
||||
Common::Path filename;
|
||||
Common::String title;
|
||||
int gameDisc;
|
||||
};
|
||||
|
||||
bool hasFMVEntry(const Common::Path &filename) const;
|
||||
void saveLoad(ResourceSerializer *serializer);
|
||||
|
||||
Common::Array<Common::String> _diaryEntries;
|
||||
Common::Array<FMVEntry> _fmvEntries;
|
||||
Common::Array<ConversationLog> _conversationEntries;
|
||||
|
||||
bool _hasUnreadEntries;
|
||||
uint32 _pageIndex;
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_DIARY_H
|
||||
176
engines/stark/services/fontprovider.cpp
Normal file
176
engines/stark/services/fontprovider.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/fontprovider.h"
|
||||
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/settings.h"
|
||||
#include "engines/stark/gfx/driver.h"
|
||||
|
||||
#include "common/archive.h"
|
||||
#include "common/formats/ini-file.h"
|
||||
|
||||
#include "graphics/font.h"
|
||||
#include "graphics/fontman.h"
|
||||
#include "graphics/fonts/ttf.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
FontProvider::FontProvider() {
|
||||
}
|
||||
|
||||
FontProvider::~FontProvider() {
|
||||
}
|
||||
|
||||
void FontProvider::initFonts() {
|
||||
// TODO: Use SystemFontMan instead when it gets merged
|
||||
_ttfFileMap["Garamond"] = "Gara.ttf";
|
||||
_ttfFileMap["Florentine Script"] = "flornt.TTF";
|
||||
_ttfFileMap["Folkard"] = "folkard.ttf";
|
||||
_ttfFileMap["Folkard\231"] = "folkard.ttf";
|
||||
_ttfFileMap["Arial"] = "ARIAL.TTF";
|
||||
_ttfFileMap["Bradley Hand ITC"] = "bradhitc.ttf";
|
||||
_ttfFileMap["Slurry"] = "SLURRY.TTF";
|
||||
_ttfFileMap["President Cyr"] = "President Cyr Regular.Ttf";
|
||||
_ttfFileMap["VictorianCyr"] = "Victorian Cyr.ttf";
|
||||
_ttfFileMap["Zapf Chance Italic"] = "Zapf Chance Italic.Ttf";
|
||||
_ttfFileMap["Arial_tlj"] = "arial_tlj.ttf";
|
||||
|
||||
// Clear any previously used fonts
|
||||
_smallFont = FontHolder();
|
||||
_bigFont = FontHolder();
|
||||
for (uint i = 0; i < ARRAYSIZE(_customFonts); i++) {
|
||||
_customFonts[i] = FontHolder();
|
||||
}
|
||||
|
||||
// Load the font settings from gui.ini when possible
|
||||
if (!StarkSettings->shouldIgnoreFontSettings()) {
|
||||
Common::INIFile gui;
|
||||
if (gui.loadFromFile("gui.ini")) {
|
||||
readFontEntry(&gui, _smallFont, "smallfont", "smallheight");
|
||||
readFontEntry(&gui, _bigFont, "bigfont", "bigheight");
|
||||
readFontEntry(&gui, _customFonts[0], "font0", "fontsize0");
|
||||
readFontEntry(&gui, _customFonts[1], "font1", "fontsize1");
|
||||
readFontEntry(&gui, _customFonts[2], "font2", "fontsize2");
|
||||
readFontEntry(&gui, _customFonts[3], "font3", "fontsize3");
|
||||
readFontEntry(&gui, _customFonts[4], "font4", "fontsize4");
|
||||
readFontEntry(&gui, _customFonts[5], "font5", "fontsize5");
|
||||
readFontEntry(&gui, _customFonts[6], "font6", "fontsize6");
|
||||
readFontEntry(&gui, _customFonts[7], "font7", "fontsize7");
|
||||
} else {
|
||||
warning("Unable to open 'gui.ini' to read the font settings");
|
||||
}
|
||||
}
|
||||
|
||||
// Default fonts
|
||||
if (!_smallFont._font) _smallFont = FontHolder(this, "Garamond", 12);
|
||||
if (!_bigFont._font) _bigFont = FontHolder(this, "Florentine Script", 19);
|
||||
if (!_customFonts[0]._font) _customFonts[0] = FontHolder(this, "Folkard", 20);
|
||||
if (!_customFonts[1]._font) _customFonts[1] = FontHolder(this, "Folkard", 12);
|
||||
if (!_customFonts[2]._font) _customFonts[2] = FontHolder(this, "Arial", 14);
|
||||
if (!_customFonts[3]._font) _customFonts[3] = FontHolder(this, "Bradley Hand ITC", 16);
|
||||
if (!_customFonts[4]._font) _customFonts[4] = FontHolder(this, "Bradley Hand ITC", 20);
|
||||
if (!_customFonts[5]._font) _customFonts[5] = FontHolder(this, "Bradley Hand ITC", 16);
|
||||
if (!_customFonts[6]._font) _customFonts[6] = FontHolder(this, "Bradley Hand ITC", 15);
|
||||
if (!_customFonts[7]._font) _customFonts[7] = FontHolder(this, "Florentine Script", 13);
|
||||
}
|
||||
|
||||
void FontProvider::readFontEntry(const Common::INIFile *gui, FontHolder &holder, const char *nameKey, const char *sizeKey) {
|
||||
Common::String section = "TEXT95";
|
||||
if (gui->hasSection("Western")) {
|
||||
section = "Western";
|
||||
}
|
||||
|
||||
Common::String name, sizeStr;
|
||||
bool gotName = gui->getKey(nameKey, section, name);
|
||||
bool gotSize = gui->getKey(sizeKey, section, sizeStr);
|
||||
|
||||
long size = strtol(sizeStr.c_str(), nullptr, 10);
|
||||
|
||||
// WORKAROUND: In the GOG.com release the computer font (location 36 00)
|
||||
// is too small, preventing the "White Cardinal" label from being clickable.
|
||||
if (strcmp(nameKey, "font2") == 0 && name.equalsIgnoreCase("Arial") && size < 14) {
|
||||
size = 14;
|
||||
}
|
||||
|
||||
if (gotName && gotSize && size > 0) {
|
||||
holder = FontHolder(this, name, size);
|
||||
} else {
|
||||
warning("Unable to read font entry '%s' from 'gui.ini'", nameKey);
|
||||
}
|
||||
}
|
||||
|
||||
FontProvider::FontHolder::FontHolder(FontProvider *fontProvider, const Common::String &name, uint32 height) {
|
||||
_name = name;
|
||||
_originalHeight = height;
|
||||
_scaledHeight = StarkGfx->scaleHeightOriginalToCurrent(_originalHeight);
|
||||
|
||||
// Fetch the font file name
|
||||
Common::Path ttfFileName("fonts");
|
||||
ttfFileName.joinInPlace(fontProvider->_ttfFileMap[_name]);
|
||||
|
||||
// Initialize the font
|
||||
Common::SeekableReadStream *s = SearchMan.createReadStreamForMember(ttfFileName);
|
||||
if (s) {
|
||||
Graphics::TTFRenderMode renderMode = StarkSettings->isFontAntialiasingEnabled() ?
|
||||
Graphics::kTTFRenderModeLight : Graphics::kTTFRenderModeMonochrome;
|
||||
bool stemDarkening = StarkSettings->isFontAntialiasingEnabled();
|
||||
|
||||
_font = Common::SharedPtr<Graphics::Font>(
|
||||
Graphics::loadTTFFont(s, DisposeAfterUse::YES, _scaledHeight, Graphics::kTTFSizeModeCell, 0, 0, renderMode, nullptr, stemDarkening)
|
||||
);
|
||||
} else {
|
||||
warning("Unable to load the font '%s'", ttfFileName.toString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
FontProvider::FontHolder *FontProvider::getFontHolder(FontProvider::FontType type, int32 customFontIndex) {
|
||||
if (type == kSmallFont) {
|
||||
return &_smallFont;
|
||||
} else if (type == kBigFont) {
|
||||
return &_bigFont;
|
||||
} else {
|
||||
assert(customFontIndex >= 0 && customFontIndex < 8);
|
||||
return &_customFonts[customFontIndex];
|
||||
}
|
||||
}
|
||||
|
||||
const Graphics::Font *FontProvider::getScaledFont(FontProvider::FontType type, int32 customFontIndex) {
|
||||
FontHolder *holder = getFontHolder(type, customFontIndex);
|
||||
if (holder->_font) {
|
||||
return holder->_font.get();
|
||||
} else {
|
||||
// Fallback to a default font
|
||||
return FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
|
||||
}
|
||||
}
|
||||
|
||||
uint FontProvider::getScaledFontHeight(FontProvider::FontType type, int32 customFontIndex) {
|
||||
FontHolder *holder = getFontHolder(type, customFontIndex);
|
||||
return holder->_scaledHeight;
|
||||
}
|
||||
|
||||
uint FontProvider::getOriginalFontHeight(FontProvider::FontType type, int32 customFontIndex) {
|
||||
FontHolder *holder = getFontHolder(type, customFontIndex);
|
||||
return holder->_originalHeight;
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
92
engines/stark/services/fontprovider.h
Normal file
92
engines/stark/services/fontprovider.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/* 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 STARK_SERVICES_FONT_PROVIDER_H
|
||||
#define STARK_SERVICES_FONT_PROVIDER_H
|
||||
|
||||
#include "common/hash-str.h"
|
||||
#include "common/ptr.h"
|
||||
|
||||
namespace Common {
|
||||
class INIFile;
|
||||
}
|
||||
|
||||
namespace Graphics {
|
||||
class Font;
|
||||
}
|
||||
|
||||
namespace Stark {
|
||||
|
||||
/**
|
||||
* The font provider offers a set of predefined fonts for the game to use
|
||||
*/
|
||||
class FontProvider {
|
||||
public:
|
||||
FontProvider();
|
||||
~FontProvider();
|
||||
|
||||
enum FontType {
|
||||
kSmallFont,
|
||||
kBigFont,
|
||||
kCustomFont
|
||||
};
|
||||
|
||||
/**
|
||||
* Request a font matching the specified parameters
|
||||
*/
|
||||
const Graphics::Font *getScaledFont(FontType type, int32 customFontIndex);
|
||||
|
||||
/**
|
||||
* Get the height of the font matching the specified parameters
|
||||
*/
|
||||
uint getScaledFontHeight(FontType type, int32 customFontIndex);
|
||||
uint getOriginalFontHeight(FontType type, int32 customFontIndex);
|
||||
|
||||
/** Load all the fonts to memory */
|
||||
void initFonts();
|
||||
|
||||
private:
|
||||
struct FontHolder {
|
||||
Common::String _name;
|
||||
|
||||
uint32 _originalHeight;
|
||||
uint32 _scaledHeight;
|
||||
|
||||
Common::SharedPtr<Graphics::Font> _font;
|
||||
|
||||
FontHolder() : _originalHeight(0), _scaledHeight(0) {}
|
||||
FontHolder(FontProvider *fontProvider, const Common::String &name, uint32 height);
|
||||
|
||||
};
|
||||
|
||||
void readFontEntry(const Common::INIFile *gui, FontHolder &holder, const char *nameKey, const char *sizeKey);
|
||||
FontHolder *getFontHolder(FontType type, int32 customFontIndex);
|
||||
|
||||
FontHolder _smallFont;
|
||||
FontHolder _bigFont;
|
||||
FontHolder _customFonts[8];
|
||||
|
||||
Common::StringMap _ttfFileMap;
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_FONT_PROVIDER_H
|
||||
72
engines/stark/services/gamechapter.cpp
Normal file
72
engines/stark/services/gamechapter.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/gamechapter.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/global.h"
|
||||
|
||||
#include "common/path.h"
|
||||
#include "common/tokenizer.h"
|
||||
#include "common/formats/ini-file.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
GameChapter::GameChapter() : _errorText("Unknown Chapter") {
|
||||
Common::INIFile file;
|
||||
if (!file.loadFromFile("chapters.ini")) {
|
||||
error("Opening file 'chapters.ini' failed");
|
||||
return;
|
||||
}
|
||||
|
||||
Common::String section = file.getSections().front().name;
|
||||
|
||||
int index = 0;
|
||||
Common::String key = Common::String::format("%02d", index);
|
||||
Common::String value;
|
||||
|
||||
while (file.hasKey(key, section)) {
|
||||
file.getKey(key, section, value);
|
||||
_chapterEntries.push_back(ChapterEntry());
|
||||
|
||||
Common::StringTokenizer tokens(value, ":");
|
||||
_chapterEntries.back().title = tokens.nextToken();
|
||||
_chapterEntries.back().title.trim();
|
||||
_chapterEntries.back().subtitle = tokens.nextToken();
|
||||
_chapterEntries.back().subtitle.trim();
|
||||
|
||||
++index;
|
||||
key = Common::String::format("%02d", index);
|
||||
}
|
||||
|
||||
if (index < _numChapter) {
|
||||
error("File 'chapters.ini' is incomplete");
|
||||
}
|
||||
}
|
||||
|
||||
const Common::String &GameChapter::getCurrentChapterTitle() const {
|
||||
return getChapterTitle(StarkGlobal->getCurrentChapter());
|
||||
}
|
||||
|
||||
const Common::String &GameChapter::getCurrentChapterSubtitle() const {
|
||||
return getChapterSubtitle(StarkGlobal->getCurrentChapter());
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
74
engines/stark/services/gamechapter.h
Normal file
74
engines/stark/services/gamechapter.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* 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 STARK_SERVICES_GAME_CHAPTER_H
|
||||
#define STARK_SERVICES_GAME_CHAPTER_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/array.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
/**
|
||||
* Game chapter services
|
||||
*
|
||||
* Provide the game chapter's title and subtitle
|
||||
*/
|
||||
class GameChapter {
|
||||
public:
|
||||
GameChapter();
|
||||
~GameChapter() {}
|
||||
|
||||
const Common::String &getChapterTitle(uint chapter) const {
|
||||
if (chapter >= _numChapter * 10) {
|
||||
return _errorText;
|
||||
} else {
|
||||
return _chapterEntries[chapter / 10].title;
|
||||
}
|
||||
}
|
||||
|
||||
const Common::String &getCurrentChapterTitle() const;
|
||||
|
||||
const Common::String &getChapterSubtitle(uint chapter) const {
|
||||
if (chapter >= _numChapter * 10) {
|
||||
return _errorText;
|
||||
} else {
|
||||
return _chapterEntries[chapter / 10].subtitle;
|
||||
}
|
||||
}
|
||||
|
||||
const Common::String &getCurrentChapterSubtitle() const;
|
||||
|
||||
private:
|
||||
static const int _numChapter = 15;
|
||||
|
||||
struct ChapterEntry {
|
||||
Common::String title;
|
||||
Common::String subtitle;
|
||||
};
|
||||
|
||||
Common::Array<ChapterEntry> _chapterEntries;
|
||||
Common::String _errorText;
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_GAME_CHAPTER_H
|
||||
275
engines/stark/services/gameinterface.cpp
Normal file
275
engines/stark/services/gameinterface.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/gameinterface.h"
|
||||
|
||||
#include "engines/stark/movement/walk.h"
|
||||
|
||||
#include "engines/stark/resources/knowledgeset.h"
|
||||
#include "engines/stark/resources/level.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/resources/speech.h"
|
||||
|
||||
#include "engines/stark/resources/floor.h"
|
||||
#include "engines/stark/resources/floorface.h"
|
||||
#include "engines/stark/resources/script.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
|
||||
#include "engines/stark/visual/image.h"
|
||||
|
||||
#include "engines/stark/scene.h"
|
||||
#include "engines/stark/services/userinterface.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
GameInterface::GameInterface() {
|
||||
}
|
||||
|
||||
GameInterface::~GameInterface() {
|
||||
}
|
||||
|
||||
bool GameInterface::skipCurrentSpeeches() {
|
||||
Current *current = StarkGlobal->getCurrent();
|
||||
|
||||
if (!current) {
|
||||
return false; // No current location, nothing to do
|
||||
}
|
||||
|
||||
// Get all speeches
|
||||
Common::Array<Resources::Speech *> speeches;
|
||||
speeches.push_back(StarkGlobal->getLevel()->listChildrenRecursive<Resources::Speech>());
|
||||
speeches.push_back(current->getLevel()->listChildrenRecursive<Resources::Speech>());
|
||||
speeches.push_back(current->getLocation()->listChildrenRecursive<Resources::Speech>());
|
||||
|
||||
// Stop them
|
||||
bool skippedSpeeches = false;
|
||||
for (uint i = 0; i < speeches.size(); i++) {
|
||||
Resources::Speech *speech = speeches[i];
|
||||
if (speech->isPlaying()) {
|
||||
speech->stop();
|
||||
skippedSpeeches = true;
|
||||
}
|
||||
}
|
||||
|
||||
return skippedSpeeches;
|
||||
}
|
||||
|
||||
void GameInterface::walkTo(const Common::Point &mouse) {
|
||||
Resources::Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||
Resources::ModelItem *april = StarkGlobal->getCurrent()->getInteractive();
|
||||
if (!floor || !april) {
|
||||
return;
|
||||
}
|
||||
|
||||
Math::Ray mouseRay = StarkScene->makeRayFromMouse(mouse);
|
||||
|
||||
// First look for a direct intersection with the floor
|
||||
Math::Vector3d destinationPosition;
|
||||
int32 destinationFloorFaceIndex = floor->findFaceHitByRay(mouseRay, destinationPosition);
|
||||
|
||||
// Otherwise fall back to the floor face center closest to the ray
|
||||
if (destinationFloorFaceIndex < 0) {
|
||||
destinationFloorFaceIndex = floor->findFaceClosestToRay(mouseRay, destinationPosition);
|
||||
}
|
||||
|
||||
if (destinationFloorFaceIndex < 0) {
|
||||
// No destination was found
|
||||
return;
|
||||
}
|
||||
|
||||
Walk *walk = new Walk(april);
|
||||
walk->setDestination(destinationPosition);
|
||||
walk->start();
|
||||
|
||||
april->setMovement(walk);
|
||||
}
|
||||
|
||||
VisualImageXMG *GameInterface::getActionImage(uint32 itemIndex, bool active) {
|
||||
// Lookup the action's item in the inventory
|
||||
Resources::KnowledgeSet *inventory = StarkGlobal->getLevel()->findChildWithSubtype<Resources::KnowledgeSet>(Resources::KnowledgeSet::kInventory, true);
|
||||
|
||||
// Get the visual for the action
|
||||
Resources::InventoryItem *action = inventory->findChildWithIndex<Resources::InventoryItem>(itemIndex);
|
||||
Visual *visual = action->getActionVisual(active);
|
||||
|
||||
return visual->get<VisualImageXMG>();
|
||||
}
|
||||
|
||||
VisualImageXMG *GameInterface::getCursorImage(uint32 itemIndex) {
|
||||
// Lookup the item's item in the inventory
|
||||
Resources::KnowledgeSet *inventory = StarkGlobal->getLevel()->findChildWithSubtype<Resources::KnowledgeSet>(Resources::KnowledgeSet::kInventory, true);
|
||||
|
||||
// Get the visual for the item
|
||||
Resources::InventoryItem *item = inventory->findChildWithIndex<Resources::InventoryItem>(itemIndex);
|
||||
Visual *visual = item->getCursorVisual();
|
||||
|
||||
return visual->get<VisualImageXMG>();
|
||||
}
|
||||
|
||||
bool GameInterface::itemHasAction(Resources::ItemVisual *item, int32 action) {
|
||||
if (action != -1) {
|
||||
return item->canPerformAction(action, 0);
|
||||
} else {
|
||||
Resources::ActionArray actions = listActionsPossibleForObject(item);
|
||||
return !actions.empty();
|
||||
}
|
||||
}
|
||||
|
||||
bool GameInterface::itemHasActionAt(Resources::ItemVisual *item, const Common::Point &position, int32 action) {
|
||||
int32 hotspotIndex = item->getHotspotIndexForPoint(position);
|
||||
if (action != -1) {
|
||||
return item->canPerformAction(action, hotspotIndex);
|
||||
} else {
|
||||
Resources::ActionArray actions = listActionsPossibleForObjectAt(item, position);
|
||||
return !actions.empty();
|
||||
}
|
||||
}
|
||||
|
||||
int32 GameInterface::itemGetDefaultActionAt(Resources::ItemVisual *item, const Common::Point &position) {
|
||||
int32 hotspotIndex = item->getHotspotIndexForPoint(position);
|
||||
Resources::PATTable *table = item->findChildWithOrder<Resources::PATTable>(hotspotIndex);
|
||||
if (table) {
|
||||
return table->getDefaultAction();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void GameInterface::itemDoAction(Resources::ItemVisual *item, uint32 action) {
|
||||
item->doAction(action, 0);
|
||||
}
|
||||
|
||||
void GameInterface::itemDoActionAt(Resources::ItemVisual *item, uint32 action, const Common::Point &position) {
|
||||
int32 hotspotIndex = item->getHotspotIndexForPoint(position);
|
||||
item->doAction(action, hotspotIndex);
|
||||
}
|
||||
|
||||
Common::String GameInterface::getItemTitle(Resources::ItemVisual *item) {
|
||||
return item->getHotspotTitle(0);
|
||||
}
|
||||
|
||||
Common::String GameInterface::getItemTitleAt(Resources::ItemVisual *item, const Common::Point &pos) {
|
||||
int32 hotspotIndex = item->getHotspotIndexForPoint(pos);
|
||||
return item->getHotspotTitle(hotspotIndex);
|
||||
}
|
||||
|
||||
Resources::ActionArray GameInterface::listActionsPossibleForObject(Resources::ItemVisual *item) {
|
||||
if (item == nullptr) {
|
||||
return Resources::ActionArray();
|
||||
}
|
||||
|
||||
Resources::PATTable *table = item->findChildWithOrder<Resources::PATTable>(0);
|
||||
if (table) {
|
||||
return table->listPossibleActions();
|
||||
} else {
|
||||
return Resources::ActionArray();
|
||||
}
|
||||
}
|
||||
|
||||
Resources::ActionArray GameInterface::listActionsPossibleForObjectAt(Resources::ItemVisual *item,
|
||||
const Common::Point &pos) {
|
||||
if (item == nullptr) {
|
||||
return Resources::ActionArray();
|
||||
}
|
||||
|
||||
int index = item->getHotspotIndexForPoint(pos);
|
||||
if (index < 0) {
|
||||
return Resources::ActionArray();
|
||||
}
|
||||
|
||||
Resources::PATTable *table = item->findChildWithOrder<Resources::PATTable>(index);
|
||||
if (table) {
|
||||
return table->listPossibleActions();
|
||||
} else {
|
||||
return Resources::ActionArray();
|
||||
}
|
||||
}
|
||||
|
||||
Resources::ActionArray GameInterface::listStockActionsPossibleForObject(Resources::ItemVisual *item) {
|
||||
Resources::ActionArray actions = listActionsPossibleForObject(item);
|
||||
|
||||
Resources::ActionArray stockActions;
|
||||
for (uint i = 0; i < actions.size(); i++) {
|
||||
if (actions[i] < 4) {
|
||||
stockActions.push_back(actions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return stockActions;
|
||||
}
|
||||
|
||||
Resources::ActionArray GameInterface::listStockActionsPossibleForObjectAt(Resources::ItemVisual *item,
|
||||
const Common::Point &pos) {
|
||||
Resources::ActionArray actions = listActionsPossibleForObjectAt(item, pos);
|
||||
|
||||
Resources::ActionArray stockActions;
|
||||
for (uint i = 0; i < actions.size(); i++) {
|
||||
if (actions[i] < 4) {
|
||||
stockActions.push_back(actions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return stockActions;
|
||||
}
|
||||
|
||||
|
||||
bool GameInterface::isAprilWalking() const {
|
||||
Current *current = StarkGlobal->getCurrent();
|
||||
if (!current) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Resources::ModelItem *april = current->getInteractive();
|
||||
if (!april) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Movement *movement = april->getMovement();
|
||||
if (!movement) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Walk *walk = dynamic_cast<Walk *>(movement);
|
||||
if (!walk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !walk->hasEnded();
|
||||
}
|
||||
|
||||
void GameInterface::setAprilRunning() {
|
||||
Current *current = StarkGlobal->getCurrent();
|
||||
Resources::ModelItem *april = current->getInteractive();
|
||||
Movement *movement = april->getMovement();
|
||||
Walk *walk = dynamic_cast<Walk *>(movement);
|
||||
|
||||
assert(walk);
|
||||
walk->setRunning();
|
||||
}
|
||||
|
||||
Common::Array<Common::Point> GameInterface::listExitPositions() {
|
||||
return StarkGlobal->getCurrent()->getLocation()->listExitPositions();
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
94
engines/stark/services/gameinterface.h
Normal file
94
engines/stark/services/gameinterface.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/* 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 STARK_SERVICES_GAME_INTERFACE_H
|
||||
#define STARK_SERVICES_GAME_INTERFACE_H
|
||||
|
||||
#include "engines/stark/resources/pattable.h"
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
class VisualImageXMG;
|
||||
|
||||
namespace Resources {
|
||||
class ItemVisual;
|
||||
}
|
||||
|
||||
/**
|
||||
* Facade object for the user interface to interact with the game world
|
||||
*/
|
||||
class GameInterface {
|
||||
public:
|
||||
GameInterface();
|
||||
~GameInterface();
|
||||
|
||||
/**
|
||||
* Skip currently playing speeches
|
||||
*
|
||||
* @return true if at least one speech was skipped
|
||||
*/
|
||||
bool skipCurrentSpeeches();
|
||||
|
||||
/** Make April try to go to the location under the cursor */
|
||||
void walkTo(const Common::Point &mouse);
|
||||
|
||||
VisualImageXMG *getActionImage(uint32 itemIndex, bool active);
|
||||
VisualImageXMG *getCursorImage(uint32 itemIndex);
|
||||
|
||||
/** Can the item be used for an action. -1 for all actions */
|
||||
bool itemHasAction(Resources::ItemVisual *item, int32 action);
|
||||
bool itemHasActionAt(Resources::ItemVisual *item, const Common::Point &position, int32 action);
|
||||
|
||||
/** Get the item's default action */
|
||||
int32 itemGetDefaultActionAt(Resources::ItemVisual *item, const Common::Point &position);
|
||||
|
||||
/** Do an action on the item */
|
||||
void itemDoAction(Resources::ItemVisual *item, uint32 action);
|
||||
void itemDoActionAt(Resources::ItemVisual *item, uint32 action, const Common::Point &position);
|
||||
|
||||
/** Get the item's name */
|
||||
Common::String getItemTitle(Resources::ItemVisual *object);
|
||||
Common::String getItemTitleAt(Resources::ItemVisual *object, const Common::Point &pos);
|
||||
|
||||
/** List the actions available for an item in the current game state */
|
||||
Resources::ActionArray listActionsPossibleForObject(Resources::ItemVisual *item);
|
||||
Resources::ActionArray listActionsPossibleForObjectAt(Resources::ItemVisual *item, const Common::Point &pos);
|
||||
|
||||
/** List the stock actions available for an item in the current game state (hand, mouth, eye) */
|
||||
Resources::ActionArray listStockActionsPossibleForObject(Resources::ItemVisual *item);
|
||||
Resources::ActionArray listStockActionsPossibleForObjectAt(Resources::ItemVisual *item, const Common::Point &pos);
|
||||
|
||||
/** Check if April is doing a walk movement */
|
||||
bool isAprilWalking() const;
|
||||
|
||||
/** Make April run if she is walking */
|
||||
void setAprilRunning();
|
||||
|
||||
/** List all the exit positions */
|
||||
Common::Array<Common::Point> listExitPositions();
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_GAME_INTERFACE_H
|
||||
99
engines/stark/services/gamemessage.cpp
Normal file
99
engines/stark/services/gamemessage.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/gamemessage.h"
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/formats/ini-file.h"
|
||||
|
||||
#include "gui/message.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
GameMessage::GameMessage() :
|
||||
_texts() {
|
||||
Common::File tmp;
|
||||
if (!tmp.open("language.ini")) {
|
||||
warning("Unable to open 'language.ini'");
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip the head of the language.ini that is in an unsupported format
|
||||
Common::String line;
|
||||
while (!tmp.eos() && !tmp.err()) {
|
||||
line = tmp.readLine();
|
||||
if (line.size() > 2 && line[0] == '-' && line[1] == '-') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Common::INIFile file;
|
||||
if(file.loadFromStream(tmp)) {
|
||||
Common::String section = "Language";
|
||||
Common::String key, text;
|
||||
|
||||
for (uint i = 2; i <= 400; ++i) {
|
||||
key = Common::String::format("%03d", i);
|
||||
if (file.hasKey(key, section)) {
|
||||
file.getKey(key, section, text);
|
||||
_texts[i] = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pre-process some of the texts
|
||||
if (_texts.contains(kYes)) {
|
||||
Common::replace(_texts[kYes], "&", "");
|
||||
}
|
||||
if (_texts.contains(kNo)) {
|
||||
Common::replace(_texts[kNo], "&", "");
|
||||
}
|
||||
if (_texts.contains(kOverwriteSave)) {
|
||||
Common::replace(_texts[kOverwriteSave], "\\n", "\n");
|
||||
}
|
||||
}
|
||||
|
||||
Common::String GameMessage::getDefaultText(TextKey key) {
|
||||
switch(key) {
|
||||
case kOverwriteSave:
|
||||
return "Are you sure you want to overwrite the savegame:\n'%s' ?";
|
||||
case kEndAndLoad:
|
||||
return "Are you sure you want to end your current game and load a new one ?";
|
||||
case kInventory:
|
||||
return "Inventory";
|
||||
case kOptions:
|
||||
return "Options";
|
||||
case kQuit:
|
||||
return "Quit";
|
||||
case kQuitGamePrompt:
|
||||
return "Are you sure you want to quit this game ?";
|
||||
case kQuitPrompt:
|
||||
return "Are you sure you want to quit ?";
|
||||
case kYes:
|
||||
return "Yes";
|
||||
case kNo:
|
||||
return "No";
|
||||
default:
|
||||
return "Unimplemented message text";
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
67
engines/stark/services/gamemessage.h
Normal file
67
engines/stark/services/gamemessage.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_SERVICES_GAME_MESSAGE_H
|
||||
#define STARK_SERVICES_GAME_MESSAGE_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/hashmap.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
/**
|
||||
* Game message service
|
||||
*
|
||||
* Provide message texts and dialogs used in various points
|
||||
*/
|
||||
class GameMessage {
|
||||
public:
|
||||
GameMessage();
|
||||
~GameMessage() {}
|
||||
|
||||
enum TextKey {
|
||||
kOverwriteSave = 10,
|
||||
kEndAndLoad = 13,
|
||||
kInventory = 353,
|
||||
kOptions = 354,
|
||||
kQuit = 355,
|
||||
kQuitGamePrompt = 356,
|
||||
kQuitPrompt = 357,
|
||||
kYes = 358,
|
||||
kNo = 359
|
||||
};
|
||||
|
||||
/** Acquire a message text by a given key */
|
||||
Common::String getTextByKey(TextKey key) {
|
||||
if (_texts.contains(key)) return _texts[key];
|
||||
|
||||
return getDefaultText(key);
|
||||
}
|
||||
|
||||
private:
|
||||
Common::HashMap<uint, Common::String> _texts;
|
||||
|
||||
Common::String getDefaultText(TextKey key);
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_GAME_MESSAGE_H
|
||||
71
engines/stark/services/global.cpp
Normal file
71
engines/stark/services/global.cpp
Normal 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 "engines/stark/services/global.h"
|
||||
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/level.h"
|
||||
#include "engines/stark/resources/knowledge.h"
|
||||
#include "engines/stark/resources/knowledgeset.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
Global::Global() :
|
||||
_millisecondsPerGameloop(10),
|
||||
_april(nullptr),
|
||||
_root(nullptr),
|
||||
_level(nullptr),
|
||||
_current(nullptr),
|
||||
_fastForward(false),
|
||||
_inventory(nullptr) {
|
||||
}
|
||||
|
||||
int32 Global::getCurrentChapter() {
|
||||
Resources::KnowledgeSet *globalState = _level->findChildWithSubtype<Resources::KnowledgeSet>(Resources::KnowledgeSet::kState);
|
||||
Resources::Knowledge *chapter = globalState->findChildWithIndex<Resources::Knowledge>(0);
|
||||
return chapter->getIntegerValue();
|
||||
}
|
||||
|
||||
void Global::setCurrentChapter(int32 value) {
|
||||
Resources::KnowledgeSet *globalState = _level->findChildWithSubtype<Resources::KnowledgeSet>(Resources::KnowledgeSet::kState);
|
||||
Resources::Knowledge *chapter = globalState->findChildWithIndex<Resources::Knowledge>(0);
|
||||
chapter->setIntegerValue(value);
|
||||
}
|
||||
|
||||
Common::String Global::getCharacterName(int32 id) {
|
||||
Resources::KnowledgeSet *characters = _level->findChildWithSubtype<Resources::KnowledgeSet>(Resources::KnowledgeSet::kPersons);
|
||||
Resources::Knowledge *character = characters->findChildWithIndex<Resources::Knowledge>(id);
|
||||
return character->getName();
|
||||
}
|
||||
|
||||
bool Global::hasInventoryItem(const Common::String &itemName) const {
|
||||
Common::Array<Resources::Item*> inventoryItems = _inventory->listChildren<Resources::Item>(Resources::Item::kItemInventory);
|
||||
|
||||
for (uint i = 0; i < inventoryItems.size(); i++) {
|
||||
if (inventoryItems[i]->getName() == itemName && inventoryItems[i]->isEnabled()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
122
engines/stark/services/global.h
Normal file
122
engines/stark/services/global.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/* 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 STARK_SERVICES_GLOBAL_H
|
||||
#define STARK_SERVICES_GLOBAL_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Resources {
|
||||
class Camera;
|
||||
class Floor;
|
||||
class GlobalItemTemplate;
|
||||
class ModelItem;
|
||||
class KnowledgeSet;
|
||||
class Level;
|
||||
class Location;
|
||||
class Root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current level / location holder object
|
||||
*/
|
||||
class Current {
|
||||
public:
|
||||
Current() :
|
||||
_level(nullptr),
|
||||
_location(nullptr),
|
||||
_floor(nullptr),
|
||||
_camera(nullptr),
|
||||
_interactive(nullptr) {
|
||||
}
|
||||
|
||||
Resources::Level *getLevel() const { return _level; }
|
||||
Resources::Location *getLocation() const { return _location; }
|
||||
Resources::Floor *getFloor() const { return _floor; }
|
||||
Resources::Camera *getCamera() const { return _camera; }
|
||||
Resources::ModelItem *getInteractive() const { return _interactive; }
|
||||
|
||||
void setLevel(Resources::Level *level) { _level = level; }
|
||||
void setLocation(Resources::Location *location) { _location = location; }
|
||||
void setFloor(Resources::Floor *floor) { _floor = floor; }
|
||||
void setCamera(Resources::Camera *camera) { _camera = camera; }
|
||||
void setInteractive(Resources::ModelItem *interactive) { _interactive = interactive; }
|
||||
|
||||
private:
|
||||
Resources::Level *_level;
|
||||
Resources::Location *_location;
|
||||
Resources::ModelItem *_interactive;
|
||||
Resources::Floor *_floor;
|
||||
Resources::Camera *_camera;
|
||||
};
|
||||
|
||||
/**
|
||||
* Global resources holder object
|
||||
*/
|
||||
class Global {
|
||||
public:
|
||||
Global();
|
||||
|
||||
Resources::Root *getRoot() const { return _root; }
|
||||
Resources::Level *getLevel() const { return _level; }
|
||||
Current *getCurrent() const { return _current; }
|
||||
bool isFastForward() const { return _fastForward; }
|
||||
uint getMillisecondsPerGameloop() const { return _millisecondsPerGameloop; }
|
||||
Resources::GlobalItemTemplate *getApril() const { return _april; }
|
||||
Resources::KnowledgeSet *getInventory() const { return _inventory; }
|
||||
|
||||
void setRoot(Resources::Root *root) { _root = root; }
|
||||
void setLevel(Resources::Level *level) { _level = level; }
|
||||
void setCurrent(Current *current) { _current = current; }
|
||||
void setFastForward() { _fastForward = true; }
|
||||
void setNormalSpeed() { _fastForward = false; }
|
||||
void setMillisecondsPerGameloop(uint millisecondsPerGameloop) { _millisecondsPerGameloop = millisecondsPerGameloop; }
|
||||
void setApril(Resources::GlobalItemTemplate *april) { _april = april; }
|
||||
void setInventory(Resources::KnowledgeSet *inventory) { _inventory = inventory; }
|
||||
|
||||
/** Retrieve the current chapter number from the global resource tree */
|
||||
int32 getCurrentChapter();
|
||||
|
||||
/** Check if the player has an inventory item using its name */
|
||||
bool hasInventoryItem(const Common::String &itemName) const;
|
||||
|
||||
/** Change the current chapter */
|
||||
void setCurrentChapter(int32 value);
|
||||
|
||||
/** Get the name of a character by its id */
|
||||
Common::String getCharacterName(int32 id);
|
||||
|
||||
private:
|
||||
uint _millisecondsPerGameloop;
|
||||
Resources::Root *_root;
|
||||
Resources::Level *_level;
|
||||
Resources::KnowledgeSet *_inventory;
|
||||
Resources::GlobalItemTemplate *_april;
|
||||
Current *_current;
|
||||
bool _fastForward;
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_GLOBAL_H
|
||||
416
engines/stark/services/resourceprovider.cpp
Normal file
416
engines/stark/services/resourceprovider.cpp
Normal file
@@ -0,0 +1,416 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/resourceprovider.h"
|
||||
|
||||
#include "engines/stark/resources/bookmark.h"
|
||||
#include "engines/stark/resources/camera.h"
|
||||
#include "engines/stark/resources/floor.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/knowledgeset.h"
|
||||
#include "engines/stark/resources/layer.h"
|
||||
#include "engines/stark/resources/level.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/resources/root.h"
|
||||
#include "engines/stark/resources/script.h"
|
||||
#include "engines/stark/resources/sound.h"
|
||||
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/archiveloader.h"
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
#include "engines/stark/services/userinterface.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
ResourceProvider::ResourceProvider(ArchiveLoader *archiveLoader, StateProvider *stateProvider, Global *global) :
|
||||
_archiveLoader(archiveLoader),
|
||||
_stateProvider(stateProvider),
|
||||
_global(global),
|
||||
_locationChangeRequest(false),
|
||||
_restoreCurrentState(false),
|
||||
_nextDirection(0) {
|
||||
}
|
||||
|
||||
void ResourceProvider::initGlobal() {
|
||||
// Load the root archive
|
||||
_archiveLoader->load("x.xarc");
|
||||
|
||||
// Set the root tree
|
||||
Resources::Root *root = _archiveLoader->useRoot<Resources::Root>("x.xarc");
|
||||
_global->setRoot(root);
|
||||
|
||||
// Resources lifecycle update
|
||||
root->onAllLoaded();
|
||||
|
||||
// Find the global level node
|
||||
Resources::Level *global = root->findChildWithSubtype<Resources::Level>(Resources::Level::kGlobal);
|
||||
|
||||
// Load the global archive
|
||||
Common::Path globalArchiveName = _archiveLoader->buildArchiveName(global);
|
||||
_archiveLoader->load(globalArchiveName);
|
||||
|
||||
// Set the global tree
|
||||
global = _archiveLoader->useRoot<Resources::Level>(globalArchiveName);
|
||||
_global->setLevel(global);
|
||||
|
||||
// Resources lifecycle update
|
||||
global->onAllLoaded();
|
||||
|
||||
// Load the state
|
||||
_stateProvider->restoreLevelState(global);
|
||||
|
||||
_global->setInventory(global->findChildWithSubtype<Resources::KnowledgeSet>(Resources::KnowledgeSet::kInventory));
|
||||
_global->setApril(global->findChildWithSubtype<Resources::GlobalItemTemplate>(Resources::Item::kItemGlobalTemplate));
|
||||
}
|
||||
|
||||
Current *ResourceProvider::findLevel(uint16 level) const {
|
||||
for (CurrentList::const_iterator it = _locations.begin(); it != _locations.end(); it++) {
|
||||
if ((*it)->getLevel()->getIndex() == level) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Current *ResourceProvider::findLocation(uint16 level, uint16 location) const {
|
||||
for (CurrentList::const_iterator it = _locations.begin(); it != _locations.end(); it++) {
|
||||
if ((*it)->getLevel()->getIndex() == level
|
||||
&& (*it)->getLocation()->getIndex() == location) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Resources::Level *ResourceProvider::getLevel(uint16 level) const {
|
||||
Current *current = findLevel(level);
|
||||
|
||||
if (current) {
|
||||
return current->getLevel();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Resources::Location *ResourceProvider::getLocation(uint16 level, uint16 location) const {
|
||||
Current *current = findLocation(level, location);
|
||||
|
||||
if (current) {
|
||||
return current->getLocation();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ResourceProvider::pushAndChangeLocation(int16 level, int16 location) {
|
||||
pushCurrentLocation();
|
||||
requestLocationChange(level, location);
|
||||
}
|
||||
|
||||
void ResourceProvider::returnToPushedLocation() {
|
||||
popCurrentLocation();
|
||||
}
|
||||
|
||||
void ResourceProvider::pushCurrentLocation() {
|
||||
PreviousLocation current;
|
||||
current.level = _global->getCurrent()->getLevel()->getIndex();
|
||||
current.location = _global->getCurrent()->getLocation()->getIndex();
|
||||
current.inventoryOpen = StarkUserInterface->isInventoryOpen();
|
||||
|
||||
_locationStack.push_back(current);
|
||||
|
||||
StarkUserInterface->inventoryOpen(false);
|
||||
}
|
||||
|
||||
void ResourceProvider::popCurrentLocation() {
|
||||
if (_locationStack.empty()) {
|
||||
error("Empty location stack");
|
||||
} else {
|
||||
PreviousLocation previous = _locationStack.back();
|
||||
_locationStack.pop_back();
|
||||
|
||||
requestLocationChange(previous.level, previous.location);
|
||||
StarkUserInterface->inventoryOpen(previous.inventoryOpen);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceProvider::requestLocationChange(uint16 level, uint16 location) {
|
||||
Current *currentLocation = new Current();
|
||||
_locations.push_back(currentLocation);
|
||||
|
||||
// Retrieve the level archive name
|
||||
Resources::Root *root = _global->getRoot();
|
||||
Resources::Level *rootLevelResource = root->findChildWithIndex<Resources::Level>(level);
|
||||
Common::Path levelArchive = _archiveLoader->buildArchiveName(rootLevelResource);
|
||||
|
||||
// Load the archive, and get the resource sub-tree root
|
||||
bool newlyLoaded = _archiveLoader->load(levelArchive);
|
||||
currentLocation->setLevel(_archiveLoader->useRoot<Resources::Level>(levelArchive));
|
||||
|
||||
// If we just loaded a resource tree, restore its state
|
||||
if (newlyLoaded) {
|
||||
currentLocation->getLevel()->onAllLoaded();
|
||||
_stateProvider->restoreLevelState(currentLocation->getLevel());
|
||||
}
|
||||
|
||||
// Retrieve the location archive name
|
||||
Resources::Level *levelResource = currentLocation->getLevel();
|
||||
Resources::Location *levelLocationResource = levelResource->findChildWithIndex<Resources::Location>(location);
|
||||
Common::Path locationArchive = _archiveLoader->buildArchiveName(levelResource, levelLocationResource);
|
||||
|
||||
// Load the archive, and get the resource sub-tree root
|
||||
newlyLoaded = _archiveLoader->load(locationArchive);
|
||||
currentLocation->setLocation(_archiveLoader->useRoot<Resources::Location>(locationArchive));
|
||||
|
||||
if (currentLocation->getLocation()->has3DLayer()) {
|
||||
Resources::Layer3D *layer = currentLocation->getLocation()->findChildWithSubtype<Resources::Layer3D>(Resources::Layer::kLayer3D);
|
||||
currentLocation->setFloor(layer->findChild<Resources::Floor>());
|
||||
currentLocation->setCamera(layer->findChild<Resources::Camera>());
|
||||
} else {
|
||||
currentLocation->setFloor(nullptr);
|
||||
currentLocation->setCamera(nullptr);
|
||||
}
|
||||
|
||||
// If we just loaded a resource tree, restore its state
|
||||
if (newlyLoaded) {
|
||||
currentLocation->getLocation()->onAllLoaded();
|
||||
_stateProvider->restoreLocationState(currentLocation->getLevel(), currentLocation->getLocation());
|
||||
}
|
||||
|
||||
_locationChangeRequest = true;
|
||||
}
|
||||
|
||||
void ResourceProvider::performLocationChange() {
|
||||
Current *current = _locations.back();
|
||||
Current *previous = _global->getCurrent();
|
||||
bool levelChanged = !previous || previous->getLevel() != current->getLevel();
|
||||
|
||||
// Exit the previous location
|
||||
if (previous) {
|
||||
// Trigger location change scripts
|
||||
if (levelChanged) {
|
||||
runLocationChangeScripts(previous->getLevel(), Resources::Script::kCallModeExitLocation);
|
||||
}
|
||||
runLocationChangeScripts(previous->getLocation(), Resources::Script::kCallModeExitLocation);
|
||||
|
||||
// Resources lifecycle update
|
||||
previous->getLocation()->onExitLocation();
|
||||
previous->getLevel()->onExitLocation();
|
||||
_global->getLevel()->onExitLocation();
|
||||
}
|
||||
|
||||
// Clear all pointers to location objects in the UI instances
|
||||
StarkUserInterface->clearLocationDependentState();
|
||||
|
||||
// Set the new current location
|
||||
_global->setCurrent(current);
|
||||
|
||||
// Resources lifecycle update
|
||||
_global->getLevel()->onEnterLocation();
|
||||
current->getLevel()->onEnterLocation();
|
||||
current->getLocation()->onEnterLocation();
|
||||
|
||||
if (current->getLocation()->has3DLayer()) {
|
||||
// Fetch the scene item for April
|
||||
current->setInteractive(Resources::Object::cast<Resources::ModelItem>(_global->getApril()->getSceneInstance()));
|
||||
}
|
||||
|
||||
if (_restoreCurrentState) {
|
||||
_stateProvider->restoreGlobalState(_global->getLevel());
|
||||
_stateProvider->restoreCurrentLevelState(current->getLevel());
|
||||
_stateProvider->restoreCurrentLocationState(current->getLevel(), current->getLocation());
|
||||
_restoreCurrentState = false;
|
||||
} else {
|
||||
setAprilInitialPosition();
|
||||
setScrollInitialPosition();
|
||||
|
||||
// Trigger location change scripts
|
||||
if (levelChanged) {
|
||||
runLocationChangeScripts(current->getLevel(), Resources::Script::kCallModeEnterLocation);
|
||||
}
|
||||
runLocationChangeScripts(current->getLocation(), Resources::Script::kCallModeEnterLocation);
|
||||
}
|
||||
|
||||
current->getLocation()->resetAnimationBlending();
|
||||
purgeOldLocations();
|
||||
|
||||
_locationChangeRequest = false;
|
||||
}
|
||||
|
||||
void ResourceProvider::runLocationChangeScripts(Resources::Object *resource, uint32 scriptCallMode) {
|
||||
Common::Array<Resources::Script *> scripts = resource->listChildrenRecursive<Resources::Script>();
|
||||
|
||||
if (scriptCallMode == Resources::Script::kCallModeEnterLocation) {
|
||||
for (uint i = 0; i < scripts.size(); i++) {
|
||||
scripts[i]->reset();
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i = 0; i < scripts.size(); i++) {
|
||||
scripts[i]->execute(scriptCallMode);
|
||||
}
|
||||
|
||||
if (scriptCallMode == Resources::Script::kCallModeExitLocation) {
|
||||
Common::Array<Resources::Sound *> sounds = resource->listChildrenRecursive<Resources::Sound>();
|
||||
for (uint i = 0; i < sounds.size(); i++) {
|
||||
sounds[i]->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceProvider::setNextLocationPosition(const ResourceReference &bookmark, int32 direction) {
|
||||
_nextPositionBookmarkReference = bookmark;
|
||||
_nextDirection = direction;
|
||||
}
|
||||
|
||||
void ResourceProvider::setAprilInitialPosition() {
|
||||
Current *current = _global->getCurrent();
|
||||
Resources::ModelItem *april = current->getInteractive();
|
||||
if (!april) {
|
||||
return; // No character
|
||||
}
|
||||
|
||||
// Set the initial position for April
|
||||
if (!_nextPositionBookmarkReference.empty()) {
|
||||
Resources::Bookmark *position = _nextPositionBookmarkReference.resolve<Resources::Bookmark>();
|
||||
april->placeOnBookmark(position);
|
||||
|
||||
Resources::Camera *camera = current->getCamera();
|
||||
Math::Angle cameraAngle = camera->getHorizontalAngle();
|
||||
april->setDirection(_nextDirection + cameraAngle);
|
||||
} else if (april->getFloorFaceIndex() <= 0) {
|
||||
// No target location provided, place April on the first floor face
|
||||
april->placeDefaultPosition();
|
||||
}
|
||||
|
||||
_nextPositionBookmarkReference = ResourceReference();
|
||||
_nextDirection = 0;
|
||||
}
|
||||
|
||||
void ResourceProvider::setScrollInitialPosition() {
|
||||
Current *current = _global->getCurrent();
|
||||
Resources::Location *location = current->getLocation();
|
||||
location->scrollToCharacterImmediate();
|
||||
}
|
||||
|
||||
void ResourceProvider::purgeOldLocations() {
|
||||
while (_locations.size() > 2) {
|
||||
Current *location = _locations.front();
|
||||
|
||||
_stateProvider->saveLocationState(location->getLevel(), location->getLocation());
|
||||
_stateProvider->saveLevelState(location->getLevel());
|
||||
|
||||
_archiveLoader->returnRoot(_archiveLoader->buildArchiveName(location->getLevel(), location->getLocation()));
|
||||
_archiveLoader->returnRoot(_archiveLoader->buildArchiveName(location->getLevel()));
|
||||
|
||||
delete location;
|
||||
|
||||
_locations.pop_front();
|
||||
}
|
||||
|
||||
_archiveLoader->unloadUnused();
|
||||
}
|
||||
|
||||
void ResourceProvider::commitActiveLocationsState() {
|
||||
// Save active location states
|
||||
for (CurrentList::const_iterator it = _locations.begin(); it != _locations.end(); it++) {
|
||||
_stateProvider->saveLocationState((*it)->getLevel(), (*it)->getLocation());
|
||||
_stateProvider->saveLevelState((*it)->getLevel());
|
||||
}
|
||||
|
||||
_stateProvider->saveLevelState(_global->getLevel());
|
||||
|
||||
// Save the current location "extended" state, to be able to restore them to the exact same state.
|
||||
Current *location = _global->getCurrent();
|
||||
_stateProvider->saveCurrentLocationState(location->getLevel(), location->getLocation());
|
||||
_stateProvider->saveCurrentLevelState(location->getLevel());
|
||||
|
||||
_stateProvider->saveGlobalState(_global->getLevel());
|
||||
}
|
||||
|
||||
void ResourceProvider::shutdown() {
|
||||
_stateProvider->clear();
|
||||
|
||||
_locationStack.clear();
|
||||
|
||||
// Flush the locations list
|
||||
for (CurrentList::const_iterator it = _locations.begin(); it != _locations.end(); it++) {
|
||||
Current *location = *it;
|
||||
|
||||
_archiveLoader->returnRoot(_archiveLoader->buildArchiveName(location->getLevel(), location->getLocation()));
|
||||
_archiveLoader->returnRoot(_archiveLoader->buildArchiveName(location->getLevel()));
|
||||
|
||||
delete location;
|
||||
}
|
||||
_locations.clear();
|
||||
|
||||
// Return the global resources
|
||||
if (_global->getLevel()) {
|
||||
_archiveLoader->returnRoot(_archiveLoader->buildArchiveName(_global->getLevel()));
|
||||
_global->setLevel(nullptr);
|
||||
}
|
||||
|
||||
if (_global->getRoot()) {
|
||||
_archiveLoader->returnRoot("x.xarc");
|
||||
_global->setRoot(nullptr);
|
||||
}
|
||||
|
||||
_global->setCurrent(nullptr);
|
||||
_global->setInventory(nullptr);
|
||||
_global->setApril(nullptr);
|
||||
|
||||
_archiveLoader->unloadUnused();
|
||||
}
|
||||
|
||||
Resources::Level *ResourceProvider::getLevelFromLocation(Resources::Location *location) const {
|
||||
for (CurrentList::const_iterator it = _locations.begin(); it != _locations.end(); it++) {
|
||||
if ((*it)->getLocation() == location) {
|
||||
return (*it)->getLevel();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ResourceProvider::readLocationStack(Common::SeekableReadStream *stream, uint32 version) {
|
||||
ResourceSerializer serializer(stream, nullptr, version);
|
||||
saveLoadLocationStack(serializer);
|
||||
}
|
||||
|
||||
void ResourceProvider::writeLocationStack(Common::WriteStream *stream) {
|
||||
ResourceSerializer serializer(nullptr, stream, StateProvider::kSaveVersion);
|
||||
saveLoadLocationStack(serializer);
|
||||
}
|
||||
|
||||
void ResourceProvider::saveLoadLocationStack(ResourceSerializer &serializer) {
|
||||
serializer.syncArraySize(_locationStack, 12);
|
||||
|
||||
for (uint i = 0; i < _locationStack.size(); i++) {
|
||||
serializer.syncAsUint16LE(_locationStack[i].level);
|
||||
serializer.syncAsUint16LE(_locationStack[i].location);
|
||||
serializer.syncAsUint32LE(_locationStack[i].inventoryOpen);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
134
engines/stark/services/resourceprovider.h
Normal file
134
engines/stark/services/resourceprovider.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/* 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 STARK_SERVICES_RESOURCE_PROVIDER_H
|
||||
#define STARK_SERVICES_RESOURCE_PROVIDER_H
|
||||
|
||||
#include "common/list.h"
|
||||
|
||||
#include "engines/stark/resourcereference.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Resources {
|
||||
class Level;
|
||||
class Location;
|
||||
class Object;
|
||||
}
|
||||
|
||||
class ArchiveLoader;
|
||||
class Current;
|
||||
class Global;
|
||||
class StateProvider;
|
||||
|
||||
/**
|
||||
* Game Resource provider.
|
||||
*
|
||||
* Maintains a list of resource trees.
|
||||
* Maintained trees are the global and the current ones.
|
||||
*/
|
||||
class ResourceProvider {
|
||||
public:
|
||||
ResourceProvider(ArchiveLoader *archiveLoader, StateProvider *stateProvider, Global *global);
|
||||
|
||||
/** Load the global archives and fill the global object */
|
||||
void initGlobal();
|
||||
|
||||
/** Load the resources for the specified location */
|
||||
void requestLocationChange(uint16 level, uint16 location);
|
||||
|
||||
/** Is a location change pending? */
|
||||
bool hasLocationChangeRequest() const { return _locationChangeRequest; }
|
||||
|
||||
void setShouldRestoreCurrentState() { _restoreCurrentState = true; }
|
||||
|
||||
void pushAndChangeLocation(int16 level, int16 location);
|
||||
void returnToPushedLocation();
|
||||
|
||||
/** Save and restore the previous location stack */
|
||||
void readLocationStack(Common::SeekableReadStream *stream, uint32 version);
|
||||
void writeLocationStack(Common::WriteStream *stream);
|
||||
|
||||
/**
|
||||
* Apply a location change request.
|
||||
*
|
||||
* Update the global object with the new location.
|
||||
* Perform the necessary resource lifecycle updates
|
||||
*/
|
||||
void performLocationChange();
|
||||
|
||||
/** Set the initial position and direction for the next location change */
|
||||
void setNextLocationPosition(const ResourceReference &bookmark, int32 direction);
|
||||
|
||||
/** Save the current location state to the state store. */
|
||||
void commitActiveLocationsState();
|
||||
|
||||
/** Release the global and current resources */
|
||||
void shutdown();
|
||||
|
||||
/** Obtain the root resource for a loaded level */
|
||||
Resources::Level *getLevel(uint16 level) const;
|
||||
|
||||
/** Obtain the root resource for a loaded location */
|
||||
Resources::Location *getLocation(uint16 level, uint16 location) const;
|
||||
|
||||
/** Get the parent level from a currently loaded location */
|
||||
Resources::Level *getLevelFromLocation(Resources::Location *location) const;
|
||||
|
||||
private:
|
||||
struct PreviousLocation {
|
||||
uint16 location;
|
||||
uint16 level;
|
||||
bool inventoryOpen;
|
||||
};
|
||||
|
||||
void pushCurrentLocation();
|
||||
void popCurrentLocation();
|
||||
void saveLoadLocationStack(ResourceSerializer &serializer);
|
||||
Common::Array<PreviousLocation> _locationStack;
|
||||
|
||||
typedef Common::List<Current *> CurrentList;
|
||||
|
||||
Current *findLevel(uint16 level) const;
|
||||
Current *findLocation(uint16 level, uint16 location) const;
|
||||
|
||||
void purgeOldLocations();
|
||||
|
||||
void runLocationChangeScripts(Resources::Object *resource, uint32 scriptCallMode);
|
||||
void setAprilInitialPosition();
|
||||
void setScrollInitialPosition();
|
||||
|
||||
Global *_global;
|
||||
ArchiveLoader *_archiveLoader;
|
||||
StateProvider *_stateProvider;
|
||||
|
||||
bool _locationChangeRequest;
|
||||
bool _restoreCurrentState;
|
||||
|
||||
CurrentList _locations;
|
||||
|
||||
ResourceReference _nextPositionBookmarkReference;
|
||||
int32 _nextDirection;
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_RESOURCE_PROVIDER_H
|
||||
30
engines/stark/services/services.cpp
Normal file
30
engines/stark/services/services.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/services.h"
|
||||
|
||||
namespace Common {
|
||||
DECLARE_SINGLETON(Stark::StarkServices);
|
||||
}
|
||||
|
||||
namespace Stark {
|
||||
|
||||
} // End of namespace Stark
|
||||
115
engines/stark/services/services.h
Normal file
115
engines/stark/services/services.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/* 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 STARK_SERVICES_SERVICES_H
|
||||
#define STARK_SERVICES_SERVICES_H
|
||||
|
||||
#include "common/singleton.h"
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Common {
|
||||
class RandomSource;
|
||||
}
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Gfx {
|
||||
class Driver;
|
||||
}
|
||||
|
||||
class ArchiveLoader;
|
||||
class DialogPlayer;
|
||||
class Diary;
|
||||
class FontProvider;
|
||||
class GameInterface;
|
||||
class Global;
|
||||
class ResourceProvider;
|
||||
class StaticProvider;
|
||||
class Scene;
|
||||
class UserInterface;
|
||||
class Settings;
|
||||
class StateProvider;
|
||||
class GameChapter;
|
||||
class GameMessage;
|
||||
|
||||
/**
|
||||
* Public services available as a singleton
|
||||
*/
|
||||
class StarkServices : public Common::Singleton<StarkServices> {
|
||||
public:
|
||||
StarkServices() {
|
||||
archiveLoader = nullptr;
|
||||
dialogPlayer = nullptr;
|
||||
diary = nullptr;
|
||||
gfx = nullptr;
|
||||
global = nullptr;
|
||||
resourceProvider = nullptr;
|
||||
randomSource = nullptr;
|
||||
scene = nullptr;
|
||||
staticProvider = nullptr;
|
||||
gameInterface = nullptr;
|
||||
userInterface = nullptr;
|
||||
fontProvider = nullptr;
|
||||
settings = nullptr;
|
||||
gameChapter = nullptr;
|
||||
gameMessage = nullptr;
|
||||
stateProvider = nullptr;
|
||||
}
|
||||
|
||||
ArchiveLoader *archiveLoader;
|
||||
DialogPlayer *dialogPlayer;
|
||||
Diary *diary;
|
||||
Gfx::Driver *gfx;
|
||||
Global *global;
|
||||
ResourceProvider *resourceProvider;
|
||||
Common::RandomSource *randomSource;
|
||||
Scene *scene;
|
||||
StaticProvider *staticProvider;
|
||||
GameInterface *gameInterface;
|
||||
UserInterface *userInterface;
|
||||
FontProvider *fontProvider;
|
||||
Settings *settings;
|
||||
GameChapter *gameChapter;
|
||||
GameMessage *gameMessage;
|
||||
StateProvider *stateProvider;
|
||||
};
|
||||
|
||||
/** Shortcuts for accessing the services. */
|
||||
#define StarkArchiveLoader StarkServices::instance().archiveLoader
|
||||
#define StarkDialogPlayer StarkServices::instance().dialogPlayer
|
||||
#define StarkDiary StarkServices::instance().diary
|
||||
#define StarkGfx StarkServices::instance().gfx
|
||||
#define StarkGlobal StarkServices::instance().global
|
||||
#define StarkResourceProvider StarkServices::instance().resourceProvider
|
||||
#define StarkRandomSource StarkServices::instance().randomSource
|
||||
#define StarkScene StarkServices::instance().scene
|
||||
#define StarkStaticProvider StarkServices::instance().staticProvider
|
||||
#define StarkGameInterface StarkServices::instance().gameInterface
|
||||
#define StarkUserInterface StarkServices::instance().userInterface
|
||||
#define StarkFontProvider StarkServices::instance().fontProvider
|
||||
#define StarkSettings StarkServices::instance().settings
|
||||
#define StarkGameChapter StarkServices::instance().gameChapter
|
||||
#define StarkGameMessage StarkServices::instance().gameMessage
|
||||
#define StarkStateProvider StarkServices::instance().stateProvider
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_SERVICES_H
|
||||
126
engines/stark/services/settings.cpp
Normal file
126
engines/stark/services/settings.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/settings.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/archiveloader.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
Settings::Settings(Audio::Mixer *mixer, const ADGameDescription *gd) :
|
||||
_mixer(mixer),
|
||||
_isDemo(gd->flags & ADGF_DEMO),
|
||||
_language(gd->language) {
|
||||
// Initialize keys
|
||||
_boolKey[kHighModel] = "enable_high_resolution_models";
|
||||
_boolKey[kSubtitle] = "subtitles";
|
||||
_boolKey[kSpecialFX] = "enable_special_effects";
|
||||
_boolKey[kShadow] = "enable_shadows";
|
||||
_boolKey[kHighFMV] = "play_high_resolution_videos";
|
||||
_boolKey[kTimeSkip] = "enable_time_skip";
|
||||
_intKey[kVoice] = "speech_volume";
|
||||
_intKey[kMusic] = "music_volume";
|
||||
_intKey[kSfx] = "sfx_volume";
|
||||
_intKey[kSaveLoadPage] = "saveload_lastpage";
|
||||
|
||||
// Register default settings
|
||||
ConfMan.registerDefault(_boolKey[kHighModel], true);
|
||||
ConfMan.registerDefault(_boolKey[kSubtitle], true);
|
||||
ConfMan.registerDefault(_boolKey[kSpecialFX], true);
|
||||
ConfMan.registerDefault(_boolKey[kShadow], true);
|
||||
ConfMan.registerDefault(_boolKey[kHighFMV], true);
|
||||
ConfMan.registerDefault(_boolKey[kTimeSkip], false);
|
||||
ConfMan.registerDefault(_intKey[kSaveLoadPage], 0);
|
||||
ConfMan.registerDefault("replacement_png_premultiply_alpha", false);
|
||||
ConfMan.registerDefault("ignore_font_settings", true);
|
||||
|
||||
// Use the FunCom logo video to check low-resolution fmv
|
||||
Common::SeekableReadStream *lowResFMV = StarkArchiveLoader->getExternalFile("1402_lo_res.bbb", "Global/");
|
||||
_hasLowRes = lowResFMV;
|
||||
delete lowResFMV;
|
||||
}
|
||||
|
||||
void Settings::setIntSetting(IntSettingIndex index, int value) {
|
||||
ConfMan.setInt(_intKey[index], value);
|
||||
|
||||
Audio::Mixer::SoundType type;
|
||||
switch (index) {
|
||||
case kVoice:
|
||||
type = Audio::Mixer::kSpeechSoundType;
|
||||
break;
|
||||
case kMusic:
|
||||
type = Audio::Mixer::kMusicSoundType;
|
||||
break;
|
||||
case kSfx:
|
||||
type = Audio::Mixer::kSFXSoundType;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
_mixer->setVolumeForSoundType(type, value);
|
||||
}
|
||||
|
||||
bool Settings::isAssetsModEnabled() const {
|
||||
return ConfMan.getBool("enable_assets_mod");
|
||||
}
|
||||
|
||||
bool Settings::shouldPreMultiplyReplacementPNGs() const {
|
||||
return ConfMan.getBool("replacement_png_premultiply_alpha");
|
||||
}
|
||||
|
||||
Gfx::Bitmap::SamplingFilter Settings::getImageSamplingFilter() const {
|
||||
return ConfMan.getBool("use_linear_filtering") ? Gfx::Bitmap::kLinear : Gfx::Bitmap::kNearest;
|
||||
}
|
||||
|
||||
bool Settings::isFontAntialiasingEnabled() const {
|
||||
return ConfMan.getBool("enable_font_antialiasing");
|
||||
}
|
||||
|
||||
Common::CodePage Settings::getTextCodePage() const {
|
||||
switch (_language) {
|
||||
case Common::PL_POL:
|
||||
return Common::kWindows1250;
|
||||
case Common::RU_RUS:
|
||||
return Common::kWindows1251;
|
||||
case Common::HE_ISR:
|
||||
return Common::kWindows1255;
|
||||
default:
|
||||
return Common::kWindows1252;
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::shouldIgnoreFontSettings() const {
|
||||
return ConfMan.getBool("ignore_font_settings") && _language == Common::EN_ANY;
|
||||
}
|
||||
|
||||
Common::Language Settings::getLanguage() const {
|
||||
return _language;
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
148
engines/stark/services/settings.h
Normal file
148
engines/stark/services/settings.h
Normal file
@@ -0,0 +1,148 @@
|
||||
/* 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 STARK_SERVICES_SETTINGS_H
|
||||
#define STARK_SERVICES_SETTINGS_H
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/language.h"
|
||||
#include "common/ustr.h"
|
||||
|
||||
#include "engines/stark/gfx/bitmap.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
|
||||
struct ADGameDescription;
|
||||
|
||||
namespace Audio {
|
||||
class Mixer;
|
||||
}
|
||||
|
||||
namespace Stark {
|
||||
|
||||
/**
|
||||
* Settings services.
|
||||
*
|
||||
* Maintains the settings of the game.
|
||||
*/
|
||||
class Settings {
|
||||
public:
|
||||
enum BoolSettingIndex {
|
||||
kHighModel,
|
||||
kSubtitle,
|
||||
kSpecialFX,
|
||||
kShadow,
|
||||
kHighFMV,
|
||||
kTimeSkip
|
||||
};
|
||||
|
||||
enum IntSettingIndex {
|
||||
kVoice,
|
||||
kMusic,
|
||||
kSfx,
|
||||
kSaveLoadPage
|
||||
};
|
||||
|
||||
Settings(Audio::Mixer *mixer, const ADGameDescription *gd);
|
||||
~Settings() {}
|
||||
|
||||
/**
|
||||
* Is this a demo version of the game?
|
||||
*
|
||||
* This is true either for 4-CD or 2-CD style demos
|
||||
*/
|
||||
bool isDemo() const {
|
||||
return _isDemo;
|
||||
}
|
||||
|
||||
/** Get the settings value */
|
||||
bool getBoolSetting(BoolSettingIndex index) { return ConfMan.getBool(_boolKey[index]); }
|
||||
int getIntSetting(IntSettingIndex index) { return ConfMan.getInt(_intKey[index]); }
|
||||
|
||||
/** Flip the boolean settings */
|
||||
void flipSetting(BoolSettingIndex index) {
|
||||
ConfMan.setBool(_boolKey[index], !getBoolSetting(index));
|
||||
}
|
||||
|
||||
/** Set the integer settings */
|
||||
void setIntSetting(IntSettingIndex index, int value);
|
||||
|
||||
/** Check whether low-resolution fmv is available */
|
||||
bool hasLowResFMV() { return _hasLowRes; }
|
||||
|
||||
/** Enable the book of secrets */
|
||||
void enableBookOfSecrets() {
|
||||
ConfMan.setBool("xoBfOsterceS", true);
|
||||
ConfMan.flushToDisk();
|
||||
}
|
||||
|
||||
/** Check whether the book of secrets is enabled */
|
||||
bool hasBookOfSecrets() { return ConfMan.hasKey("xoBfOsterceS"); }
|
||||
|
||||
/** Should the game try to load external replacement assets? */
|
||||
bool isAssetsModEnabled() const;
|
||||
|
||||
/**
|
||||
* Should the engine apply alpha pre-multiplication when loading replacement PNGs
|
||||
*
|
||||
* When rendering, bitmaps are expected to be in pre-multiplied alpha format.
|
||||
* It's best to have the PNGs in that format on file to speed up loading by removing
|
||||
* the need to convert them. However this option enables the conversion when loading
|
||||
* the files to they can be stored with regular alpha transparency for convenience
|
||||
* when testing.
|
||||
*/
|
||||
bool shouldPreMultiplyReplacementPNGs() const;
|
||||
|
||||
/** Should linear filtering be used when sampling the background image bitmaps? */
|
||||
Gfx::Bitmap::SamplingFilter getImageSamplingFilter() const;
|
||||
|
||||
/** The codepage text is encoded in or this version of the game */
|
||||
Common::CodePage getTextCodePage() const;
|
||||
|
||||
/** Should TrueType fonts be rendered with anti-aliasing? */
|
||||
bool isFontAntialiasingEnabled() const;
|
||||
|
||||
/**
|
||||
* Should the font settings from 'gui.ini' be ignored.
|
||||
*
|
||||
* Some versions of the game, especially the GOG.com version have a version of 'gui.ini'
|
||||
* that causes poor visuals. We just ignore the settings from the game and use the
|
||||
* default values from ScummVM.
|
||||
*/
|
||||
bool shouldIgnoreFontSettings() const;
|
||||
|
||||
/**
|
||||
* Return the game language (which is currently initialized with the Advanced Detector description language field value)
|
||||
*/
|
||||
Common::Language getLanguage() const;
|
||||
|
||||
private:
|
||||
Audio::Mixer *_mixer;
|
||||
bool _hasLowRes;
|
||||
const bool _isDemo;
|
||||
const Common::Language _language;
|
||||
|
||||
const char *_boolKey[6];
|
||||
const char *_intKey[4];
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_SETTINGS_H
|
||||
283
engines/stark/services/stateprovider.cpp
Normal file
283
engines/stark/services/stateprovider.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
#include "common/memstream.h"
|
||||
|
||||
#include "engines/stark/resources/level.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
StateReadStream::StateReadStream(Common::SeekableReadStream *parentStream, DisposeAfterUse::Flag disposeParentStream) :
|
||||
SeekableSubReadStream(parentStream, 0, parentStream->size(), disposeParentStream) {
|
||||
}
|
||||
|
||||
StateReadStream::~StateReadStream() {
|
||||
}
|
||||
|
||||
Common::String StateReadStream::readString() {
|
||||
// Read the string length
|
||||
uint32 length = readUint32LE();
|
||||
|
||||
// Read the string
|
||||
char *data = new char[length];
|
||||
read(data, length);
|
||||
Common::String string(data, length);
|
||||
delete[] data;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
StateProvider::ResourceTreeState::ResourceTreeState(uint32 size, byte *data, uint32 version) :
|
||||
_size(size),
|
||||
_data(data),
|
||||
_version(version) {
|
||||
}
|
||||
|
||||
StateProvider::ResourceTreeState::~ResourceTreeState() {
|
||||
free(_data);
|
||||
}
|
||||
|
||||
StateProvider::~StateProvider() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void StateProvider::clear() {
|
||||
for (ResourceTreeStateMap::iterator it = _stateStore.begin(); it != _stateStore.end(); it++) {
|
||||
delete it->_value;
|
||||
}
|
||||
_stateStore.clear();
|
||||
}
|
||||
|
||||
void StateProvider::restoreLevelState(Resources::Level *level) {
|
||||
Common::String storeKey = level->getName();
|
||||
|
||||
restoreResourceTreeState(storeKey, level, false);
|
||||
}
|
||||
|
||||
void StateProvider::restoreCurrentLevelState(Resources::Level *level) {
|
||||
restoreResourceTreeState("Current", level, true);
|
||||
}
|
||||
|
||||
void StateProvider::restoreLocationState(Resources::Level *level, Resources::Location *location) {
|
||||
Common::String storeKey = level->getName() + location->getName();
|
||||
|
||||
restoreResourceTreeState(storeKey, location, false);
|
||||
}
|
||||
|
||||
void StateProvider::restoreCurrentLocationState(Resources::Level *level, Resources::Location *location) {
|
||||
restoreResourceTreeState("CurrentCurrent", location, true);
|
||||
}
|
||||
|
||||
void StateProvider::restoreGlobalState(Resources::Level *level) {
|
||||
restoreResourceTreeState("CurrentGlobal", level, true);
|
||||
}
|
||||
|
||||
void StateProvider::restoreResourceTreeState(const Common::String &storeKey, Resources::Object *root, bool current) {
|
||||
if (_stateStore.contains(storeKey)) {
|
||||
ResourceTreeState *state = _stateStore[storeKey];
|
||||
|
||||
Common::MemoryReadStream stream(state->getData(), state->getSize(), DisposeAfterUse::NO);
|
||||
readResourceTree(root, &stream, current, state->getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
void StateProvider::readResourceTree(Resources::Object *resource, Common::SeekableReadStream *stream, bool current, uint32 version) {
|
||||
// Read the resource to the source stream
|
||||
/* byte type = */ stream->readByte();
|
||||
/* byte subType = */ stream->readByte();
|
||||
uint32 size = stream->readUint32LE();
|
||||
|
||||
if (size > 0) {
|
||||
Common::SeekableReadStream *resourceStream = stream->readStream(size);
|
||||
ResourceSerializer serializer(resourceStream, nullptr, version);
|
||||
|
||||
// Deserialize the resource state from stream
|
||||
if (current) {
|
||||
resource->saveLoadCurrent(&serializer);
|
||||
} else {
|
||||
resource->saveLoad(&serializer);
|
||||
}
|
||||
|
||||
delete resourceStream;
|
||||
}
|
||||
|
||||
// Deserialize the resource children
|
||||
Common::Array<Resources::Object *> children = resource->listChildren<Resources::Object>();
|
||||
for (uint i = 0; i < children.size(); i++) {
|
||||
readResourceTree(children[i], stream, current, version);
|
||||
}
|
||||
}
|
||||
|
||||
void StateProvider::saveLevelState(Resources::Level *level) {
|
||||
Common::String storeKey = level->getName();
|
||||
|
||||
saveResourceTreeState(storeKey, level, false);
|
||||
}
|
||||
|
||||
void StateProvider::saveCurrentLevelState(Resources::Level *level) {
|
||||
saveResourceTreeState("Current", level, true);
|
||||
}
|
||||
|
||||
void StateProvider::saveLocationState(Resources::Level *level, Resources::Location *location) {
|
||||
Common::String storeKey = level->getName() + location->getName();
|
||||
|
||||
saveResourceTreeState(storeKey, location, false);
|
||||
}
|
||||
|
||||
void StateProvider::saveCurrentLocationState(Resources::Level *level, Resources::Location *location) {
|
||||
saveResourceTreeState("CurrentCurrent", location, true);
|
||||
}
|
||||
|
||||
void StateProvider::saveGlobalState(Resources::Level *level) {
|
||||
saveResourceTreeState("CurrentGlobal", level, true);
|
||||
}
|
||||
|
||||
void StateProvider::saveResourceTreeState(const Common::String &storeKey, Resources::Object *root, bool current) {
|
||||
// Delete any previous data
|
||||
if (_stateStore.contains(storeKey)) {
|
||||
delete _stateStore[storeKey];
|
||||
_stateStore.erase(storeKey);
|
||||
}
|
||||
|
||||
// Write the tree state to memory
|
||||
Common::MemoryWriteStreamDynamic stream(DisposeAfterUse::NO);
|
||||
writeResourceTree(root, &stream, current);
|
||||
|
||||
// Add the state to the store
|
||||
_stateStore[storeKey] = new ResourceTreeState(stream.size(), stream.getData(), kSaveVersion);
|
||||
}
|
||||
|
||||
void StateProvider::writeResourceTree(Resources::Object *resource, Common::WriteStream *stream, bool current) {
|
||||
// Explicit scope to control the lifespan of the memory stream
|
||||
{
|
||||
Common::MemoryWriteStreamDynamic resourceStream(DisposeAfterUse::YES);
|
||||
ResourceSerializer serializer(nullptr, &resourceStream, kSaveVersion);
|
||||
|
||||
// Serialize the resource to a memory stream
|
||||
if (current) {
|
||||
resource->saveLoadCurrent(&serializer);
|
||||
} else {
|
||||
resource->saveLoad(&serializer);
|
||||
}
|
||||
|
||||
// Write the resource to the target stream
|
||||
stream->writeByte(resource->getType().get());
|
||||
stream->writeByte(resource->getSubType());
|
||||
stream->writeUint32LE(resourceStream.size());
|
||||
stream->write(resourceStream.getData(), resourceStream.size());
|
||||
}
|
||||
|
||||
// Serialize the resource children
|
||||
Common::Array<Resources::Object *> children = resource->listChildren<Resources::Object>();
|
||||
for (uint i = 0; i < children.size(); i++) {
|
||||
writeResourceTree(children[i], stream, current);
|
||||
}
|
||||
}
|
||||
|
||||
void StateProvider::readStateFromStream(StateReadStream *stream, uint saveVersion) {
|
||||
clear();
|
||||
|
||||
uint32 treeCount = stream->readUint32LE();
|
||||
for (uint i = 0; i < treeCount; i++) {
|
||||
// Read the store key
|
||||
Common::String key = stream->readString();
|
||||
|
||||
// Each resource tree state needs to have its own version because
|
||||
// some may never be made active again and serialized in the latest version.
|
||||
// In that case they stay in a previous version.
|
||||
uint treeVersion = 6;
|
||||
if (saveVersion > 6) {
|
||||
treeVersion = stream->readUint32LE();
|
||||
}
|
||||
|
||||
// Read the data size
|
||||
uint32 dataSize = stream->readUint32LE();
|
||||
|
||||
// Read the data
|
||||
byte *data = (byte *) malloc(dataSize);
|
||||
stream->read(data, dataSize);
|
||||
|
||||
_stateStore[key] = new ResourceTreeState(dataSize, data, treeVersion);
|
||||
}
|
||||
}
|
||||
|
||||
void StateProvider::writeStateToStream(Common::WriteStream *stream) {
|
||||
stream->writeUint32LE(_stateStore.size());
|
||||
|
||||
for (ResourceTreeStateMap::iterator it = _stateStore.begin(); it != _stateStore.end(); it++) {
|
||||
stream->writeUint32LE(it->_key.size());
|
||||
stream->writeString(it->_key);
|
||||
stream->writeUint32LE(it->_value->getVersion());
|
||||
stream->writeUint32LE(it->_value->getSize());
|
||||
stream->write(it->_value->getData(), it->_value->getSize());
|
||||
}
|
||||
}
|
||||
|
||||
ResourceSerializer::ResourceSerializer(Common::SeekableReadStream *in, Common::WriteStream *out, uint32 version) :
|
||||
Common::Serializer(in, out) {
|
||||
_version = version;
|
||||
}
|
||||
|
||||
void ResourceSerializer::syncAsFloat(float &value) {
|
||||
if (isLoading()) {
|
||||
value = _loadStream->readFloatLE();
|
||||
} else {
|
||||
_saveStream->writeFloatLE(value);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceSerializer::syncAsVector3d(Math::Vector3d &value) {
|
||||
syncAsFloat(value.x());
|
||||
syncAsFloat(value.y());
|
||||
syncAsFloat(value.z());
|
||||
}
|
||||
|
||||
void ResourceSerializer::syncAsResourceReference(ResourceReference &reference) {
|
||||
if (isLoading()) {
|
||||
reference.loadFromStream(_loadStream);
|
||||
} else {
|
||||
reference.saveToStream(_saveStream);
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceSerializer::syncAsString32(Common::String &string) {
|
||||
if (isLoading()) {
|
||||
string.clear();
|
||||
|
||||
uint32 length = _loadStream->readUint32LE();
|
||||
for (uint i = 0; i < length; i++) {
|
||||
char c = _loadStream->readByte();
|
||||
string += c;
|
||||
}
|
||||
|
||||
_bytesSynced += 4 + length;
|
||||
} else {
|
||||
_saveStream->writeUint32LE(string.size());
|
||||
_saveStream->writeString(string);
|
||||
_bytesSynced += 4 + string.size();
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
160
engines/stark/services/stateprovider.h
Normal file
160
engines/stark/services/stateprovider.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/* 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 STARK_SERVICES_STATE_PROVIDER_H
|
||||
#define STARK_SERVICES_STATE_PROVIDER_H
|
||||
|
||||
#include "common/hashmap.h"
|
||||
#include "common/serializer.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/substream.h"
|
||||
|
||||
#include "math/mathfwd.h"
|
||||
|
||||
#include "engines/stark/resourcereference.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Resources {
|
||||
class Object;
|
||||
class Level;
|
||||
class Location;
|
||||
}
|
||||
|
||||
class StateReadStream : public Common::SeekableSubReadStream {
|
||||
public:
|
||||
explicit StateReadStream(Common::SeekableReadStream *parentStream, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::YES);
|
||||
virtual ~StateReadStream();
|
||||
|
||||
Common::String readString();
|
||||
};
|
||||
|
||||
class ResourceSerializer : public Common::Serializer {
|
||||
public:
|
||||
ResourceSerializer(Common::SeekableReadStream *in, Common::WriteStream *out, uint32 version);
|
||||
|
||||
void syncAsFloat(float &value);
|
||||
void syncAsVector3d(Math::Vector3d &value);
|
||||
void syncAsResourceReference(ResourceReference &reference);
|
||||
void syncAsString32(Common::String &string);
|
||||
|
||||
template<typename T>
|
||||
void syncAsResourceReference(T **object, Version minVersion = 0, Version maxVersion = kLastVersion);
|
||||
|
||||
template<typename T>
|
||||
void syncArraySize(Common::Array<T> &array, Version minVersion = 0, Version maxVersion = kLastVersion);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void ResourceSerializer::syncAsResourceReference(T **object, Version minVersion, Version maxVersion) {
|
||||
assert(object);
|
||||
|
||||
if (_version < minVersion || _version > maxVersion)
|
||||
return; // Ignore anything which is not supposed to be present in this save game version
|
||||
|
||||
if (isLoading()) {
|
||||
ResourceReference reference;
|
||||
reference.loadFromStream(_loadStream);
|
||||
*object = reference.resolve<T>();
|
||||
} else {
|
||||
ResourceReference reference;
|
||||
reference.buildFromResource(*object);
|
||||
reference.saveToStream(_saveStream);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ResourceSerializer::syncArraySize(Common::Array<T> &array, Version minVersion, Version maxVersion) {
|
||||
if (_version < minVersion || _version > maxVersion)
|
||||
return; // Ignore anything which is not supposed to be present in this save game version
|
||||
|
||||
uint32 size = array.size();
|
||||
syncAsUint32LE(size);
|
||||
|
||||
if (isLoading()) {
|
||||
array.resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource state provider.
|
||||
*
|
||||
* Maintains a serialized version of the state of the resource trees.
|
||||
*/
|
||||
class StateProvider {
|
||||
public:
|
||||
~StateProvider();
|
||||
|
||||
void restoreLevelState(Resources::Level *level);
|
||||
void restoreCurrentLevelState(Resources::Level *level);
|
||||
void restoreLocationState(Resources::Level *level, Resources::Location *location);
|
||||
void restoreCurrentLocationState(Resources::Level *level, Resources::Location *location);
|
||||
void restoreGlobalState(Resources::Level *level);
|
||||
|
||||
void saveLevelState(Resources::Level *level);
|
||||
void saveCurrentLevelState(Resources::Level *level);
|
||||
void saveLocationState(Resources::Level *level, Resources::Location *location);
|
||||
void saveCurrentLocationState(Resources::Level *level, Resources::Location *location);
|
||||
void saveGlobalState(Resources::Level *level);
|
||||
|
||||
/** Replace the current states by those read from the stream */
|
||||
void readStateFromStream(StateReadStream *stream, uint saveVersion);
|
||||
|
||||
/** Write the states in the store to a stream */
|
||||
void writeStateToStream(Common::WriteStream *stream);
|
||||
|
||||
/** Clear all the state, effectively preparing to start a new game */
|
||||
void clear();
|
||||
|
||||
static const uint kMinSaveVersion = 6;
|
||||
static const uint kSaveVersion = 13;
|
||||
|
||||
private:
|
||||
class ResourceTreeState {
|
||||
public:
|
||||
ResourceTreeState(uint32 size, byte *data, uint32 version);
|
||||
~ResourceTreeState();
|
||||
|
||||
uint32 getVersion() const { return _version; }
|
||||
uint32 getSize() const { return _size; }
|
||||
byte *getData() const { return _data; }
|
||||
|
||||
private:
|
||||
uint32 _version;
|
||||
uint32 _size;
|
||||
byte *_data;
|
||||
};
|
||||
|
||||
typedef Common::HashMap<Common::String, ResourceTreeState *> ResourceTreeStateMap;
|
||||
|
||||
void restoreResourceTreeState(const Common::String &storeKey, Resources::Object *root, bool current);
|
||||
void saveResourceTreeState(const Common::String &storeKey, Resources::Object *root, bool current);
|
||||
|
||||
void readResourceTree(Resources::Object *resource, Common::SeekableReadStream *stream, bool current, uint32 version);
|
||||
void writeResourceTree(Resources::Object *resource, Common::WriteStream *stream, bool current);
|
||||
|
||||
ResourceTreeStateMap _stateStore;
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_STATE_PROVIDER_H
|
||||
170
engines/stark/services/staticprovider.cpp
Normal file
170
engines/stark/services/staticprovider.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/services/staticprovider.h"
|
||||
|
||||
#include "engines/stark/resources/anim.h"
|
||||
#include "engines/stark/resources/animscript.h"
|
||||
#include "engines/stark/resources/container.h"
|
||||
#include "engines/stark/resources/image.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/level.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/resources/sound.h"
|
||||
#include "engines/stark/services/archiveloader.h"
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/visual/image.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
StaticProvider::StaticProvider(ArchiveLoader *archiveLoader) :
|
||||
_archiveLoader(archiveLoader),
|
||||
_level(nullptr),
|
||||
_location(nullptr) {
|
||||
}
|
||||
|
||||
void StaticProvider::init() {
|
||||
// Load the static archive
|
||||
_archiveLoader->load("static/static.xarc");
|
||||
|
||||
// Set the root tree
|
||||
_level = _archiveLoader->useRoot<Resources::Level>("static/static.xarc");
|
||||
|
||||
// Resources lifecycle update
|
||||
_level->onAllLoaded();
|
||||
|
||||
Resources::Item *staticItem = _level->findChild<Resources::Item>();
|
||||
_stockAnims = staticItem->listChildren<Resources::Anim>();
|
||||
|
||||
for (uint i = 0; i< _stockAnims.size(); i++) {
|
||||
_stockAnims[i]->applyToItem(nullptr);
|
||||
}
|
||||
|
||||
Resources::Anim *imagesAnim = _stockAnims[kImages];
|
||||
_stockImages = imagesAnim->listChildrenRecursive<Resources::Image>();
|
||||
}
|
||||
|
||||
void StaticProvider::onGameLoop() {
|
||||
_level->onGameLoop();
|
||||
}
|
||||
|
||||
void StaticProvider::shutdown() {
|
||||
if (_location) {
|
||||
unloadLocation(_location);
|
||||
}
|
||||
|
||||
_level = nullptr;
|
||||
|
||||
_archiveLoader->returnRoot("static/static.xarc");
|
||||
_archiveLoader->unloadUnused();
|
||||
}
|
||||
|
||||
VisualImageXMG *StaticProvider::getCursorImage(uint32 cursor) const {
|
||||
Resources::Anim *anim = _stockAnims[cursor];
|
||||
return anim->getVisual()->get<VisualImageXMG>();
|
||||
}
|
||||
|
||||
VisualImageXMG *StaticProvider::getUIElement(UIElement element) const {
|
||||
return getCursorImage(element);
|
||||
}
|
||||
|
||||
VisualImageXMG *StaticProvider::getUIElement(UIElement element, uint32 index) const {
|
||||
Resources::Anim *anim = _stockAnims[element];
|
||||
|
||||
uint32 prevIndex = anim->getCurrentFrame();
|
||||
anim->selectFrame(index);
|
||||
VisualImageXMG *visualImage = anim->getVisual()->get<VisualImageXMG>();
|
||||
anim->selectFrame(prevIndex);
|
||||
|
||||
return visualImage;
|
||||
}
|
||||
|
||||
VisualImageXMG *StaticProvider::getUIImage(UIImage image) const {
|
||||
Resources::Image *anim = _stockImages[image];
|
||||
return anim->getVisual()->get<VisualImageXMG>();
|
||||
}
|
||||
|
||||
void StaticProvider::goToAnimScriptStatement(StaticProvider::UIElement stockUIElement, int animScriptItemIndex) {
|
||||
Resources::Anim *anim = _stockAnims[stockUIElement];
|
||||
Resources::AnimScript *animScript = anim->findChild<Resources::AnimScript>();
|
||||
Resources::AnimScriptItem *animScriptItem = animScript->findChildWithIndex<Resources::AnimScriptItem>(animScriptItemIndex);
|
||||
animScript->goToScriptItem(animScriptItem);
|
||||
}
|
||||
|
||||
Resources::Sound *StaticProvider::getUISound(UISound sound) const {
|
||||
Resources::Item *staticLevelItem = _level->findChild<Resources::Item>();
|
||||
Resources::Anim *anim = staticLevelItem->findChildWithOrder<Resources::Anim>(4);
|
||||
Resources::Container *sounds = anim->findChildWithSubtype<Resources::Container>(Resources::Container::kSounds);
|
||||
return sounds->findChildWithOrder<Resources::Sound>(sound);
|
||||
}
|
||||
|
||||
Common::Path StaticProvider::buildLocationArchiveName(const char *locationName) const {
|
||||
return Common::Path(Common::String::format("static/%s/%s.xarc", locationName, locationName));
|
||||
}
|
||||
|
||||
Resources::Location *StaticProvider::loadLocation(const char *locationName) {
|
||||
assert(!_location);
|
||||
|
||||
Common::Path archiveName = buildLocationArchiveName(locationName);
|
||||
|
||||
_archiveLoader->load(archiveName);
|
||||
_location = _archiveLoader->useRoot<Resources::Location>(archiveName);
|
||||
|
||||
_location->onAllLoaded();
|
||||
_location->onEnterLocation();
|
||||
|
||||
// Start background music
|
||||
Common::Array<Resources::Sound *> sounds = _location->listChildren<Resources::Sound>(Resources::Sound::kSoundBackground);
|
||||
for (uint i = 0; i < sounds.size(); i++) {
|
||||
sounds[i]->play();
|
||||
}
|
||||
|
||||
return _location;
|
||||
}
|
||||
|
||||
void StaticProvider::unloadLocation(Resources::Location *location) {
|
||||
assert(_location == location);
|
||||
|
||||
location->onExitLocation();
|
||||
|
||||
Common::Path archiveName = buildLocationArchiveName(location->getName().c_str());
|
||||
_archiveLoader->returnRoot(archiveName);
|
||||
_archiveLoader->unloadUnused();
|
||||
|
||||
_location = nullptr;
|
||||
}
|
||||
|
||||
bool StaticProvider::isStaticLocation() const {
|
||||
return _location != nullptr;
|
||||
}
|
||||
|
||||
Resources::Location *StaticProvider::getLocation() const {
|
||||
return _location;
|
||||
}
|
||||
|
||||
Resources::Sound *StaticProvider::getLocationSound(uint16 index) const {
|
||||
assert(_location);
|
||||
|
||||
Resources::Container *sounds = _location->findChildWithSubtype<Resources::Container>(Resources::Container::kSounds);
|
||||
return sounds->findChildWithIndex<Resources::Sound>(index);
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
140
engines/stark/services/staticprovider.h
Normal file
140
engines/stark/services/staticprovider.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_SERVICES_STATIC_PROVIDER_H
|
||||
#define STARK_SERVICES_STATIC_PROVIDER_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/path.h"
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Resources {
|
||||
class Anim;
|
||||
class Image;
|
||||
class Level;
|
||||
class Location;
|
||||
class Sound;
|
||||
}
|
||||
|
||||
class ArchiveLoader;
|
||||
class Global;
|
||||
class VisualImageXMG;
|
||||
|
||||
/**
|
||||
* Static Resource provider.
|
||||
*
|
||||
* Maintains the static resource trees.
|
||||
* Maintained trees are the level and the location ones.
|
||||
*/
|
||||
class StaticProvider {
|
||||
public:
|
||||
explicit StaticProvider(ArchiveLoader *archiveLoader);
|
||||
|
||||
enum UIElement {
|
||||
kInventoryScrollUpArrow = 1,
|
||||
kInventoryScrollDownArrow = 2,
|
||||
kImages = 4,
|
||||
kActionMenuBg = 5,
|
||||
kTextScrollUpArrow = 6,
|
||||
kTextScrollDownArrow = 7,
|
||||
kQuit = 8,
|
||||
kCheckMark = 13,
|
||||
kVolume = 14,
|
||||
kDiaryNormal = 15,
|
||||
kInventory = 16,
|
||||
kExitArrow = 17,
|
||||
kExitArrowLeft = 18,
|
||||
kExitArrowRight = 19,
|
||||
kTextBackgroundActive = 20,
|
||||
kTextBackgroundPassive = 21,
|
||||
kDiaryTabbed = 22
|
||||
};
|
||||
|
||||
enum UIImage {
|
||||
kInventoryBg = 0,
|
||||
kDialogOptionBullet = 4
|
||||
};
|
||||
|
||||
enum UISound {
|
||||
kActionMouthHover = 0,
|
||||
kActionHover = 1,
|
||||
kInventoryNewItem = 2
|
||||
};
|
||||
|
||||
/** Load the static level archive */
|
||||
void init();
|
||||
|
||||
/** State update loop */
|
||||
void onGameLoop();
|
||||
|
||||
/** Release the static resources */
|
||||
void shutdown();
|
||||
|
||||
/** Obtain the static level */
|
||||
Resources::Level *getLevel() const { return _level; }
|
||||
|
||||
/** Get an image for a static cursor */
|
||||
VisualImageXMG *getCursorImage(uint32 cursor) const;
|
||||
|
||||
/** Get an image for a static UI element */
|
||||
VisualImageXMG *getUIElement(UIElement element) const;
|
||||
VisualImageXMG *getUIElement(UIElement element, uint32 index) const;
|
||||
|
||||
/** Get an image for a static UI element */
|
||||
VisualImageXMG *getUIImage(UIImage image) const;
|
||||
|
||||
/** Get a static UI sound resource */
|
||||
Resources::Sound *getUISound(UISound sound) const;
|
||||
|
||||
/** Move execution of a static UI element anim script to the specified item */
|
||||
void goToAnimScriptStatement(UIElement stockUIElement, int animScriptItemIndex);
|
||||
|
||||
/** Load a static location and set it as current */
|
||||
Resources::Location *loadLocation(const char *locationName);
|
||||
|
||||
/** Is a static location currently loaded? */
|
||||
bool isStaticLocation() const;
|
||||
|
||||
/** Obtain the currently loaded static location, if any */
|
||||
Resources::Location *getLocation() const;
|
||||
|
||||
/** Look up a sound resource in the current static location by its index */
|
||||
Resources::Sound *getLocationSound(uint16 index) const;
|
||||
|
||||
/** Unload the current static location */
|
||||
void unloadLocation(Resources::Location *location);
|
||||
|
||||
private:
|
||||
ArchiveLoader *_archiveLoader;
|
||||
|
||||
Resources::Level *_level;
|
||||
Resources::Location *_location;
|
||||
Common::Array<Resources::Anim *> _stockAnims;
|
||||
Common::Array<Resources::Image *> _stockImages;
|
||||
|
||||
Common::Path buildLocationArchiveName(const char *locationName) const;
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_STATIC_PROVIDER_H
|
||||
572
engines/stark/services/userinterface.cpp
Normal file
572
engines/stark/services/userinterface.cpp
Normal file
@@ -0,0 +1,572 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/events.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "engines/engine.h"
|
||||
|
||||
#include "engines/stark/services/userinterface.h"
|
||||
|
||||
#include "engines/stark/gfx/driver.h"
|
||||
|
||||
#include "engines/stark/services/diary.h"
|
||||
#include "engines/stark/services/gameinterface.h"
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/staticprovider.h"
|
||||
#include "engines/stark/services/resourceprovider.h"
|
||||
#include "engines/stark/services/settings.h"
|
||||
|
||||
#include "engines/stark/ui/cursor.h"
|
||||
#include "engines/stark/ui/dialogbox.h"
|
||||
#include "engines/stark/ui/menu/diaryindex.h"
|
||||
#include "engines/stark/ui/menu/mainmenu.h"
|
||||
#include "engines/stark/ui/menu/settingsmenu.h"
|
||||
#include "engines/stark/ui/menu/saveloadmenu.h"
|
||||
#include "engines/stark/ui/menu/fmvmenu.h"
|
||||
#include "engines/stark/ui/menu/diarypages.h"
|
||||
#include "engines/stark/ui/menu/dialogmenu.h"
|
||||
#include "engines/stark/ui/world/inventorywindow.h"
|
||||
#include "engines/stark/ui/world/fmvscreen.h"
|
||||
#include "engines/stark/ui/world/gamescreen.h"
|
||||
#include "engines/stark/ui/world/gamewindow.h"
|
||||
#include "engines/stark/ui/world/dialogpanel.h"
|
||||
|
||||
#include "engines/stark/resources/knowledgeset.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
|
||||
#include "gui/message.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
UserInterface::UserInterface(StarkEngine *vm, Gfx::Driver *gfx) :
|
||||
_gfx(gfx),
|
||||
_cursor(nullptr),
|
||||
_diaryIndexScreen(nullptr),
|
||||
_mainMenuScreen(nullptr),
|
||||
_settingsMenuScreen(nullptr),
|
||||
_saveMenuScreen(nullptr),
|
||||
_loadMenuScreen(nullptr),
|
||||
_fmvMenuScreen(nullptr),
|
||||
_diaryPagesScreen(nullptr),
|
||||
_dialogScreen(nullptr),
|
||||
_exitGame(false),
|
||||
_quitToMainMenu(false),
|
||||
_shouldToggleSubtitle(false),
|
||||
_shouldGoBackToPreviousScreen(false),
|
||||
_fmvScreen(nullptr),
|
||||
_gameScreen(nullptr),
|
||||
_interactive(true),
|
||||
_interactionAttemptDenied(false),
|
||||
_currentScreen(nullptr),
|
||||
_gameWindowThumbnail(nullptr),
|
||||
_modalDialog(nullptr) {
|
||||
_vm = vm;
|
||||
}
|
||||
|
||||
UserInterface::~UserInterface() {
|
||||
freeGameScreenThumbnail();
|
||||
|
||||
delete _modalDialog;
|
||||
delete _gameScreen;
|
||||
delete _fmvScreen;
|
||||
delete _diaryIndexScreen;
|
||||
delete _cursor;
|
||||
delete _mainMenuScreen;
|
||||
delete _settingsMenuScreen;
|
||||
delete _saveMenuScreen;
|
||||
delete _loadMenuScreen;
|
||||
delete _fmvMenuScreen;
|
||||
delete _diaryPagesScreen;
|
||||
delete _dialogScreen;
|
||||
}
|
||||
|
||||
void UserInterface::init() {
|
||||
_cursor = new Cursor(_gfx);
|
||||
|
||||
_mainMenuScreen = new MainMenuScreen(_gfx, _cursor);
|
||||
_gameScreen = new GameScreen(_gfx, _cursor);
|
||||
_diaryIndexScreen = new DiaryIndexScreen(_gfx, _cursor);
|
||||
_settingsMenuScreen = new SettingsMenuScreen(_gfx, _cursor);
|
||||
_saveMenuScreen = new SaveMenuScreen(_gfx, _cursor);
|
||||
_loadMenuScreen = new LoadMenuScreen(_gfx, _cursor);
|
||||
_fmvMenuScreen = new FMVMenuScreen(_gfx, _cursor);
|
||||
_diaryPagesScreen = new DiaryPagesScreen(_gfx, _cursor);
|
||||
_dialogScreen = new DialogScreen(_gfx, _cursor);
|
||||
_fmvScreen = new FMVScreen(_gfx, _cursor);
|
||||
_modalDialog = new DialogBox(_vm, _gfx, _cursor);
|
||||
|
||||
_prevScreenNameStack.push(Screen::kScreenMainMenu);
|
||||
_currentScreen = _fmvScreen;
|
||||
|
||||
// Play the FunCom logo video
|
||||
_fmvScreen->play("1402.bbb");
|
||||
}
|
||||
|
||||
void UserInterface::onGameLoop() {
|
||||
StarkStaticProvider->onGameLoop();
|
||||
|
||||
if (_modalDialog->isVisible()) {
|
||||
_modalDialog->handleGameLoop();
|
||||
_modalDialog->handleMouseMove();
|
||||
} else {
|
||||
_currentScreen->handleGameLoop();
|
||||
|
||||
// Check for UI mouse overs
|
||||
// TODO: Call mouse move only if the mouse position actually changed
|
||||
// probably some code will need to be moved to gameloop handling to
|
||||
// account for the case where hotspots move and the mouse cursor needs
|
||||
// to be updated regardless of the mouse actually moved.
|
||||
_currentScreen->handleMouseMove();
|
||||
}
|
||||
}
|
||||
|
||||
void UserInterface::handleMouseMove(const Common::Point &pos) {
|
||||
_cursor->setMousePosition(pos);
|
||||
}
|
||||
|
||||
void UserInterface::handleMouseUp() {
|
||||
// Only the settings menu needs to handle this event
|
||||
// TODO: Clean this up
|
||||
_settingsMenuScreen->handleMouseUp();
|
||||
}
|
||||
|
||||
void UserInterface::handleClick() {
|
||||
if (_modalDialog->isVisible()) {
|
||||
_modalDialog->handleClick();
|
||||
} else {
|
||||
_currentScreen->handleClick();
|
||||
}
|
||||
}
|
||||
|
||||
void UserInterface::handleRightClick() {
|
||||
if (_modalDialog->isVisible()) {
|
||||
_modalDialog->handleRightClick();
|
||||
} else {
|
||||
_currentScreen->handleRightClick();
|
||||
}
|
||||
}
|
||||
|
||||
void UserInterface::handleDoubleClick() {
|
||||
if (_modalDialog->isVisible()) {
|
||||
_modalDialog->handleDoubleClick();
|
||||
} else {
|
||||
_currentScreen->handleDoubleClick();
|
||||
}
|
||||
}
|
||||
|
||||
void UserInterface::handleEscape() {
|
||||
if (StarkGameInterface->skipCurrentSpeeches()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (skipFMV()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Screen::Name curScreenName = _currentScreen->getName();
|
||||
if (curScreenName != Screen::kScreenGame && curScreenName != Screen::kScreenMainMenu) {
|
||||
backPrevScreen();
|
||||
} else if (StarkSettings->getBoolSetting(Settings::kTimeSkip)) {
|
||||
StarkGlobal->setFastForward();
|
||||
}
|
||||
}
|
||||
|
||||
void UserInterface::inventoryOpen(bool open) {
|
||||
// Make the inventory update its contents.
|
||||
if (open) {
|
||||
_gameScreen->getInventoryWindow()->open();
|
||||
} else {
|
||||
_gameScreen->getInventoryWindow()->close();
|
||||
}
|
||||
}
|
||||
|
||||
int16 UserInterface::getSelectedInventoryItem() const {
|
||||
if (_gameScreen) {
|
||||
return _gameScreen->getInventoryWindow()->getSelectedInventoryItem();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void UserInterface::selectInventoryItem(int16 itemIndex) {
|
||||
_gameScreen->getInventoryWindow()->setSelectedInventoryItem(itemIndex);
|
||||
}
|
||||
|
||||
void UserInterface::requestFMVPlayback(const Common::Path &name) {
|
||||
_shouldPlayFmv = name;
|
||||
}
|
||||
|
||||
void UserInterface::onFMVStopped() {
|
||||
_shouldGoBackToPreviousScreen = true;
|
||||
}
|
||||
|
||||
void UserInterface::changeScreen(Screen::Name screenName) {
|
||||
if (screenName == _currentScreen->getName()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_prevScreenNameStack.push(_currentScreen->getName());
|
||||
_currentScreen->close();
|
||||
_currentScreen = getScreenByName(screenName);
|
||||
_currentScreen->open();
|
||||
}
|
||||
|
||||
void UserInterface::backPrevScreen() {
|
||||
// No need to check the stack since at least there will be a MainMenuScreen in it
|
||||
// and MainMenuScreen will not request to go back
|
||||
changeScreen(_prevScreenNameStack.pop());
|
||||
|
||||
// No need to push for going back
|
||||
_prevScreenNameStack.pop();
|
||||
}
|
||||
|
||||
void UserInterface::restoreScreenHistory() {
|
||||
_shouldGoBackToPreviousScreen = false;
|
||||
_prevScreenNameStack.clear();
|
||||
_prevScreenNameStack.push(Screen::kScreenMainMenu);
|
||||
}
|
||||
|
||||
Screen *UserInterface::getScreenByName(Screen::Name screenName) const {
|
||||
switch (screenName) {
|
||||
case Screen::kScreenFMV:
|
||||
return _fmvScreen;
|
||||
case Screen::kScreenDiaryIndex:
|
||||
return _diaryIndexScreen;
|
||||
case Screen::kScreenGame:
|
||||
return _gameScreen;
|
||||
case Screen::kScreenMainMenu:
|
||||
return _mainMenuScreen;
|
||||
case Screen::kScreenSettingsMenu:
|
||||
return _settingsMenuScreen;
|
||||
case Screen::kScreenSaveMenu:
|
||||
return _saveMenuScreen;
|
||||
case Screen::kScreenLoadMenu:
|
||||
return _loadMenuScreen;
|
||||
case Screen::kScreenFMVMenu:
|
||||
return _fmvMenuScreen;
|
||||
case Screen::kScreenDiaryPages:
|
||||
return _diaryPagesScreen;
|
||||
case Screen::kScreenDialog:
|
||||
return _dialogScreen;
|
||||
default:
|
||||
error("Unhandled screen name '%d'", screenName);
|
||||
}
|
||||
}
|
||||
|
||||
bool UserInterface::isInGameScreen() const {
|
||||
return _currentScreen && (_currentScreen->getName() == Screen::kScreenGame);
|
||||
}
|
||||
|
||||
bool UserInterface::isInSaveLoadMenuScreen() const {
|
||||
Screen::Name name = _currentScreen->getName();
|
||||
return name == Screen::kScreenSaveMenu || name == Screen::kScreenLoadMenu;
|
||||
}
|
||||
|
||||
bool UserInterface::isInDiaryIndexScreen() const {
|
||||
return _currentScreen->getName() == Screen::kScreenDiaryIndex;
|
||||
}
|
||||
|
||||
bool UserInterface::isInventoryOpen() const {
|
||||
return _gameScreen->getInventoryWindow()->isVisible();
|
||||
}
|
||||
|
||||
bool UserInterface::skipFMV() {
|
||||
if (_currentScreen->getName() == Screen::kScreenFMV) {
|
||||
_fmvScreen->stop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UserInterface::render() {
|
||||
_currentScreen->render();
|
||||
|
||||
if (_modalDialog->isVisible()) {
|
||||
_modalDialog->render();
|
||||
}
|
||||
|
||||
// The cursor depends on the UI being done.
|
||||
if (_currentScreen->getName() != Screen::kScreenFMV) {
|
||||
_cursor->render();
|
||||
}
|
||||
}
|
||||
|
||||
bool UserInterface::isInteractive() const {
|
||||
return _interactive;
|
||||
}
|
||||
|
||||
void UserInterface::setInteractive(bool interactive) {
|
||||
if (interactive && !_interactive) {
|
||||
StarkGlobal->setNormalSpeed();
|
||||
} else if (!interactive && _interactive) {
|
||||
_interactionAttemptDenied = false;
|
||||
}
|
||||
|
||||
_interactive = interactive;
|
||||
}
|
||||
|
||||
void UserInterface::markInteractionDenied() {
|
||||
if (!_interactive) {
|
||||
_interactionAttemptDenied = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool UserInterface::wasInteractionDenied() const {
|
||||
return !_interactive && _interactionAttemptDenied;
|
||||
}
|
||||
|
||||
void UserInterface::clearLocationDependentState() {
|
||||
_gameScreen->reset();
|
||||
}
|
||||
|
||||
void UserInterface::optionsOpen() {
|
||||
changeScreen(Screen::kScreenDiaryIndex);
|
||||
}
|
||||
|
||||
void UserInterface::saveGameScreenThumbnail() {
|
||||
freeGameScreenThumbnail();
|
||||
|
||||
if (StarkGlobal->getLevel() && StarkGlobal->getCurrent()) {
|
||||
// Re-render the screen to exclude the cursor
|
||||
StarkGfx->clearScreen();
|
||||
_gameScreen->render();
|
||||
}
|
||||
|
||||
Graphics::Surface *big = _gameScreen->getGameWindow()->getScreenshot();
|
||||
assert(big->format.bytesPerPixel == 4);
|
||||
|
||||
_gameWindowThumbnail = new Graphics::Surface();
|
||||
_gameWindowThumbnail->create(kThumbnailWidth, kThumbnailHeight, big->format);
|
||||
|
||||
uint32 *dst = (uint32 *)_gameWindowThumbnail->getPixels();
|
||||
for (int i = 0; i < _gameWindowThumbnail->h; i++) {
|
||||
for (int j = 0; j < _gameWindowThumbnail->w; j++) {
|
||||
uint32 srcX = big->w * j / _gameWindowThumbnail->w;
|
||||
uint32 srcY = big->h * i / _gameWindowThumbnail->h;
|
||||
uint32 *src = (uint32 *)big->getBasePtr(srcX, srcY);
|
||||
|
||||
// Copy RGBA pixel
|
||||
*dst++ = *src;
|
||||
}
|
||||
}
|
||||
|
||||
big->free();
|
||||
delete big;
|
||||
}
|
||||
|
||||
void UserInterface::freeGameScreenThumbnail() {
|
||||
if (_gameWindowThumbnail) {
|
||||
_gameWindowThumbnail->free();
|
||||
delete _gameWindowThumbnail;
|
||||
_gameWindowThumbnail = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const Graphics::Surface *UserInterface::getGameWindowThumbnail() const {
|
||||
return _gameWindowThumbnail;
|
||||
}
|
||||
|
||||
void UserInterface::onScreenChanged() {
|
||||
_gameScreen->onScreenChanged();
|
||||
|
||||
if (_modalDialog->isVisible()) {
|
||||
_modalDialog->onScreenChanged();
|
||||
}
|
||||
|
||||
if (!isInGameScreen()) {
|
||||
_currentScreen->onScreenChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void UserInterface::notifyInventoryItemEnabled(uint16 itemIndex) {
|
||||
_gameScreen->notifyInventoryItemEnabled(itemIndex);
|
||||
}
|
||||
|
||||
void UserInterface::notifyDiaryEntryEnabled() {
|
||||
_gameScreen->notifyDiaryEntryEnabled();
|
||||
}
|
||||
|
||||
void UserInterface::toggleScreen(Screen::Name screenName) {
|
||||
Screen::Name currentName = _currentScreen->getName();
|
||||
|
||||
if (currentName == screenName
|
||||
|| (currentName == Screen::kScreenSaveMenu && screenName == Screen::kScreenLoadMenu)
|
||||
|| (currentName == Screen::kScreenLoadMenu && screenName == Screen::kScreenSaveMenu)) {
|
||||
backPrevScreen();
|
||||
} else if (currentName == Screen::kScreenGame
|
||||
|| currentName == Screen::kScreenDiaryIndex
|
||||
|| (currentName == Screen::kScreenMainMenu && screenName == Screen::kScreenLoadMenu)
|
||||
|| (currentName == Screen::kScreenMainMenu && screenName == Screen::kScreenSettingsMenu)) {
|
||||
changeScreen(screenName);
|
||||
}
|
||||
}
|
||||
|
||||
void UserInterface::performToggleSubtitle() {
|
||||
StarkSettings->flipSetting(Settings::kSubtitle);
|
||||
_shouldToggleSubtitle = false;
|
||||
}
|
||||
|
||||
void UserInterface::cycleInventory(bool forward) {
|
||||
int16 curItem = getSelectedInventoryItem();
|
||||
int16 nextItem = StarkGlobal->getInventory()->getNeighborInventoryItem(curItem, forward);
|
||||
selectInventoryItem(nextItem);
|
||||
}
|
||||
|
||||
void UserInterface::doQueuedScreenChange() {
|
||||
if (_quitToMainMenu) {
|
||||
clearLocationDependentState();
|
||||
changeScreen(Screen::kScreenGame);
|
||||
StarkResourceProvider->shutdown();
|
||||
changeScreen(Screen::kScreenMainMenu);
|
||||
_prevScreenNameStack.clear();
|
||||
_quitToMainMenu = false;
|
||||
}
|
||||
|
||||
if (_shouldGoBackToPreviousScreen) {
|
||||
backPrevScreen();
|
||||
_shouldGoBackToPreviousScreen = false;
|
||||
}
|
||||
|
||||
if (!_shouldPlayFmv.empty()) {
|
||||
changeScreen(Screen::kScreenFMV);
|
||||
_fmvScreen->play(_shouldPlayFmv);
|
||||
_shouldPlayFmv.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void UserInterface::handleActions(Common::CustomEventType customType) {
|
||||
if (_modalDialog->isVisible()) {
|
||||
_modalDialog->onKeyPress(customType);
|
||||
return;
|
||||
}
|
||||
|
||||
if (customType == kActionSkip) {
|
||||
handleEscape();
|
||||
} else if (customType == kActionSelectDialogue) {
|
||||
if (isInGameScreen()) {
|
||||
_gameScreen->getDialogPanel()->selectFocusedOption();
|
||||
}
|
||||
} else if (customType == kActionDiaryMenu) {
|
||||
toggleScreen(Screen::kScreenDiaryIndex);
|
||||
} else if (customType == kActionSaveGame) {
|
||||
if (isInSaveLoadMenuScreen() || g_engine->canSaveGameStateCurrently()) {
|
||||
toggleScreen(Screen::kScreenSaveMenu);
|
||||
}
|
||||
} else if (customType == kActionLoadGame) {
|
||||
toggleScreen(Screen::kScreenLoadMenu);
|
||||
} else if (customType == kActionConversationLog) {
|
||||
toggleScreen(Screen::kScreenDialog);
|
||||
} else if (customType == kActionAprilsDiary) {
|
||||
if (StarkDiary->isEnabled()) {
|
||||
toggleScreen(Screen::kScreenDiaryPages);
|
||||
}
|
||||
} else if (customType == kActionVideoReplay) {
|
||||
toggleScreen(Screen::kScreenFMVMenu);
|
||||
} else if (customType == kActionGameSettings) {
|
||||
toggleScreen(Screen::kScreenSettingsMenu);
|
||||
} else if (customType == kActionSaveScreenshot) {
|
||||
g_system->saveScreenshot();
|
||||
} else if (customType == kActionToggleSubtitles) {
|
||||
if (isInGameScreen()) {
|
||||
_shouldToggleSubtitle = !_shouldToggleSubtitle;
|
||||
}
|
||||
} else if (customType == kActionQuitToMenu) {
|
||||
if (isInGameScreen() || isInDiaryIndexScreen()) {
|
||||
confirm(GameMessage::kQuitGamePrompt, this, &UserInterface::requestQuitToMainMenu);
|
||||
}
|
||||
} else if (customType == kActionCycleForwardInventory) {
|
||||
if (isInGameScreen() && isInteractive()) {
|
||||
cycleInventory(false);
|
||||
}
|
||||
} else if (customType == kActionCycleBackInventory) {
|
||||
if (isInGameScreen() && isInteractive()) {
|
||||
cycleInventory(true);
|
||||
}
|
||||
} else if (customType == kActionInventory) {
|
||||
if (isInGameScreen() && isInteractive()) {
|
||||
inventoryOpen(!isInventoryOpen());
|
||||
}
|
||||
} else if (customType == kActionDisplayExits) {
|
||||
if (isInGameScreen() && isInteractive()) {
|
||||
_gameScreen->getGameWindow()->toggleExitDisplay();
|
||||
}
|
||||
} else if (customType == kActionExitGame) {
|
||||
confirm(GameMessage::kQuitPrompt, this, &UserInterface::notifyShouldExit);
|
||||
} else if (customType == kActionPause) {
|
||||
if (isInGameScreen()) {
|
||||
if (g_engine->isPaused()) {
|
||||
_gamePauseToken.clear();
|
||||
} else {
|
||||
_gamePauseToken = g_engine->pauseEngine();
|
||||
debug("The game is paused");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isInGameScreen()) {
|
||||
if (isInventoryOpen()) {
|
||||
if (customType == kActionInventoryScrollUp) {
|
||||
_gameScreen->getInventoryWindow()->scrollUp();
|
||||
} else if (customType == kActionInventoryScrollDown) {
|
||||
_gameScreen->getInventoryWindow()->scrollDown();
|
||||
}
|
||||
} else {
|
||||
if (customType == kActionDialogueScrollUp) {
|
||||
_gameScreen->getDialogPanel()->scrollUp();
|
||||
} else if (customType == kActionDialogueScrollDown) {
|
||||
_gameScreen->getDialogPanel()->scrollDown();
|
||||
} else if (customType == kActionNextDialogue) {
|
||||
_gameScreen->getDialogPanel()->focusNextOption();
|
||||
} else if (customType == kActionPrevDialogue) {
|
||||
_gameScreen->getDialogPanel()->focusPrevOption();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UserInterface::handleKeyPress(const Common::KeyState &keyState) {
|
||||
|
||||
// TODO: Delegate keypress handling to the screens
|
||||
if (keyState.keycode >= Common::KEYCODE_1 && keyState.keycode <= Common::KEYCODE_9) {
|
||||
if (isInGameScreen()) {
|
||||
uint index = keyState.keycode - Common::KEYCODE_1;
|
||||
_gameScreen->getDialogPanel()->selectOption(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UserInterface::confirm(const Common::String &message, Common::Functor0<void> *confirmCallBack) {
|
||||
Common::String textYes = StarkGameMessage->getTextByKey(GameMessage::kYes);
|
||||
Common::String textNo = StarkGameMessage->getTextByKey(GameMessage::kNo);
|
||||
|
||||
_modalDialog->open(message, confirmCallBack, textYes, textNo);
|
||||
}
|
||||
|
||||
void UserInterface::confirm(GameMessage::TextKey key, Common::Functor0<void> *confirmCallBack) {
|
||||
Common::String message = StarkGameMessage->getTextByKey(key);
|
||||
|
||||
confirm(message, confirmCallBack);
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
250
engines/stark/services/userinterface.h
Normal file
250
engines/stark/services/userinterface.h
Normal file
@@ -0,0 +1,250 @@
|
||||
/* 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 STARK_SERVICES_USER_INTERFACE_H
|
||||
#define STARK_SERVICES_USER_INTERFACE_H
|
||||
|
||||
#include "engines/stark/stark.h"
|
||||
#include "engines/stark/ui/screen.h"
|
||||
|
||||
#include "engines/stark/services/gamemessage.h"
|
||||
|
||||
#include "engines/engine.h"
|
||||
|
||||
#include "common/keyboard.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str-array.h"
|
||||
#include "common/stack.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Gfx {
|
||||
class Driver;
|
||||
}
|
||||
|
||||
class DialogBox;
|
||||
class DiaryIndexScreen;
|
||||
class GameScreen;
|
||||
class MainMenuScreen;
|
||||
class SettingsMenuScreen;
|
||||
class SaveMenuScreen;
|
||||
class LoadMenuScreen;
|
||||
class FMVMenuScreen;
|
||||
class DiaryPagesScreen;
|
||||
class DialogScreen;
|
||||
class Cursor;
|
||||
class FMVScreen;
|
||||
|
||||
enum {
|
||||
kThumbnailWidth = 160,
|
||||
kThumbnailHeight = 92,
|
||||
kThumbnailSize = kThumbnailWidth * kThumbnailHeight * 4
|
||||
};
|
||||
|
||||
/**
|
||||
* Facade object for interacting with the user interface from the rest of the engine
|
||||
*/
|
||||
class UserInterface {
|
||||
public:
|
||||
explicit UserInterface(StarkEngine *vm, Gfx::Driver *gfx);
|
||||
virtual ~UserInterface();
|
||||
|
||||
void init();
|
||||
|
||||
/** Called once per game loop. */
|
||||
void onGameLoop();
|
||||
|
||||
void render();
|
||||
void handleMouseMove(const Common::Point &pos);
|
||||
void handleMouseUp();
|
||||
void handleClick();
|
||||
void handleRightClick();
|
||||
void handleDoubleClick();
|
||||
void handleEscape();
|
||||
void notifyShouldExit() { _exitGame = true; }
|
||||
void inventoryOpen(bool open);
|
||||
bool shouldExit() { return _exitGame; }
|
||||
|
||||
/** Start playing a FMV */
|
||||
void requestFMVPlayback(const Common::Path &name);
|
||||
|
||||
/** FMV playback has just ended */
|
||||
void onFMVStopped();
|
||||
|
||||
/**
|
||||
* Abort the currently playing FMV, if any
|
||||
*
|
||||
* @return true if a FMV was skipped
|
||||
*/
|
||||
bool skipFMV();
|
||||
|
||||
/** Set the currently displayed screen */
|
||||
void changeScreen(Screen::Name screenName);
|
||||
|
||||
/** Back to the previous displayed screen */
|
||||
void backPrevScreen();
|
||||
|
||||
/** Apply the scheduled screen change if any */
|
||||
void doQueuedScreenChange();
|
||||
|
||||
/** Back to the main menu screen and rest resources */
|
||||
void requestQuitToMainMenu() { _quitToMainMenu = true; }
|
||||
|
||||
/** Restore the screen travelling history to the initial state*/
|
||||
void restoreScreenHistory();
|
||||
|
||||
/** Is the game screen currently displayed? */
|
||||
bool isInGameScreen() const;
|
||||
|
||||
/** Is the save & load menu screen currently displayed? */
|
||||
bool isInSaveLoadMenuScreen() const;
|
||||
|
||||
/** Is the diary index screen currently displayed? */
|
||||
bool isInDiaryIndexScreen() const;
|
||||
|
||||
/** Is the inventory panel being displayed? */
|
||||
bool isInventoryOpen() const;
|
||||
|
||||
/** Can the player interact with the game world? */
|
||||
bool isInteractive() const;
|
||||
|
||||
/** Allow or forbid interaction with the game world */
|
||||
void setInteractive(bool interactive);
|
||||
|
||||
/** A new item has been added to the player's inventory */
|
||||
void notifyInventoryItemEnabled(uint16 itemIndex);
|
||||
|
||||
/** A new entry has been added to the player's diary */
|
||||
void notifyDiaryEntryEnabled();
|
||||
|
||||
/** Access the selected inventory item */
|
||||
int16 getSelectedInventoryItem() const;
|
||||
void selectInventoryItem(int16 itemIndex);
|
||||
|
||||
/** Clears all the pointers to data that may be location dependent */
|
||||
void clearLocationDependentState();
|
||||
|
||||
/** Open the in game options menu */
|
||||
void optionsOpen();
|
||||
|
||||
/** Signal a denied interaction that occurred during a non interactive period */
|
||||
void markInteractionDenied();
|
||||
|
||||
/** Was a player interaction with the world denied during this non interactive period? */
|
||||
bool wasInteractionDenied() const;
|
||||
|
||||
/** The screen resolution just changed, rebuild resolution dependent data */
|
||||
void onScreenChanged();
|
||||
|
||||
/** Grab a screenshot of the game screen and store it in the class context as a thumbnail */
|
||||
void saveGameScreenThumbnail();
|
||||
|
||||
/** Clear the currently stored game screen thumbnail, if any */
|
||||
void freeGameScreenThumbnail();
|
||||
|
||||
/** Get the currently stored game screen thumbnail, returns nullptr if there is not thumbnail stored */
|
||||
const Graphics::Surface *getGameWindowThumbnail() const;
|
||||
|
||||
/**
|
||||
* Display a confirmation dialog
|
||||
*
|
||||
* Close the dialog when the cancel button is pressed,
|
||||
* call a callback when the confirm button is pressed.
|
||||
*/
|
||||
template<class T>
|
||||
void confirm(const Common::String &message, T *instance, void (T::*confirmCallBack)());
|
||||
template<class T>
|
||||
void confirm(GameMessage::TextKey key, T *instance, void (T::*confirmCallBack)());
|
||||
void confirm(const Common::String &message, Common::Functor0<void> *confirmCallBack);
|
||||
void confirm(GameMessage::TextKey key, Common::Functor0<void> *confirmCallBack);
|
||||
|
||||
/** Directly open or close a screen */
|
||||
void toggleScreen(Screen::Name screenName);
|
||||
|
||||
/** Toggle subtitles on and off */
|
||||
bool hasToggleSubtitleRequest() { return _shouldToggleSubtitle; }
|
||||
void performToggleSubtitle();
|
||||
|
||||
/** Perform an action after a keypress */
|
||||
void handleActions(Common::CustomEventType customType);
|
||||
void handleKeyPress(const Common::KeyState &keyState);
|
||||
|
||||
private:
|
||||
Screen *getScreenByName(Screen::Name screenName) const;
|
||||
|
||||
void cycleInventory(bool forward);
|
||||
|
||||
StarkEngine *_vm;
|
||||
GameScreen *_gameScreen;
|
||||
FMVScreen *_fmvScreen;
|
||||
DiaryIndexScreen *_diaryIndexScreen;
|
||||
MainMenuScreen *_mainMenuScreen;
|
||||
SettingsMenuScreen *_settingsMenuScreen;
|
||||
SaveMenuScreen *_saveMenuScreen;
|
||||
LoadMenuScreen *_loadMenuScreen;
|
||||
FMVMenuScreen *_fmvMenuScreen;
|
||||
DiaryPagesScreen *_diaryPagesScreen;
|
||||
DialogScreen *_dialogScreen;
|
||||
Screen *_currentScreen;
|
||||
Common::Stack<Screen::Name> _prevScreenNameStack;
|
||||
|
||||
DialogBox *_modalDialog;
|
||||
Cursor *_cursor;
|
||||
|
||||
Gfx::Driver *_gfx;
|
||||
bool _exitGame;
|
||||
bool _quitToMainMenu;
|
||||
PauseToken _gamePauseToken;
|
||||
|
||||
bool _interactive;
|
||||
bool _interactionAttemptDenied;
|
||||
|
||||
bool _shouldToggleSubtitle;
|
||||
|
||||
// TODO: Generalize to all screen changes
|
||||
bool _shouldGoBackToPreviousScreen;
|
||||
Common::Path _shouldPlayFmv;
|
||||
|
||||
Graphics::Surface *_gameWindowThumbnail;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
void UserInterface::confirm(GameMessage::TextKey key, T *instance, void (T::*confirmCallBack)()) {
|
||||
confirm(key, new Common::Functor0Mem<void, T>(instance, confirmCallBack));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void UserInterface::confirm(const Common::String &message, T *instance, void (T::*confirmCallBack)()) {
|
||||
confirm(message, new Common::Functor0Mem<void, T>(instance, confirmCallBack));
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_SERVICES_USER_INTERFACE_H
|
||||
Reference in New Issue
Block a user