Initial commit

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

View File

@@ -0,0 +1,390 @@
/* 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/ui/menu/dialogmenu.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/services/diary.h"
#include "engines/stark/services/gamechapter.h"
#include "engines/stark/services/staticprovider.h"
#include "engines/stark/services/global.h"
#include "engines/stark/gfx/renderentry.h"
#include "engines/stark/resources/location.h"
#include "engines/stark/resources/item.h"
namespace Stark {
DialogScreen::DialogScreen(Gfx::Driver *gfx, Cursor *cursor) :
StaticLocationScreen(gfx, cursor, "DiaryLog", Screen::kScreenDialog),
_startTitleIndex(0), _nextTitleIndex(0),
_startLineIndex(0), _nextLineIndex(0),
_curMaxChapter(0), _curLogIndex(0),
_indexFrame(nullptr),
_logFrame(nullptr),
_chapterTitleTexts(),
_prevTitleIndexStack(),
_prevLineIndexStack() {
}
DialogScreen::~DialogScreen() {
freeResources();
}
void DialogScreen::open() {
StaticLocationScreen::open();
_widgets.push_back(new StaticLocationWidget(
"BGImage",
nullptr,
nullptr));
_widgets.push_back(new StaticLocationWidget(
"Return",
CLICK_HANDLER(DialogScreen, backHandler),
nullptr));
_widgets.push_back(new StaticLocationWidget(
"Back",
CLICK_HANDLER(DialogScreen, backHandler),
nullptr));
_widgets.push_back(new StaticLocationWidget(
"IndexBack",
CLICK_HANDLER(DialogScreen, indexBackHandler),
nullptr));
_widgets.push_back(new StaticLocationWidget(
"IndexNext",
CLICK_HANDLER(DialogScreen, indexNextHandler),
nullptr));
_widgets.push_back(new StaticLocationWidget(
"LogBack",
CLICK_HANDLER(DialogScreen, logBackHandler),
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new StaticLocationWidget(
"Index",
CLICK_HANDLER(DialogScreen, backIndexHandler),
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new StaticLocationWidget(
"LogNext",
CLICK_HANDLER(DialogScreen, logNextHandler),
nullptr));
_widgets.back()->setVisible(false);
for (uint i = 1; i < _widgets.size(); ++i) {
_widgets[i]->setupSounds(0, 1);
}
Resources::Location *location = StarkStaticProvider->getLocation();
_indexFrame = location->getRenderEntryByName("IndexFrame");
_logFrame = location->getRenderEntryByName("LogFrame");
_nextTitleIndex = 0;
loadIndex();
}
void DialogScreen::close() {
freeResources();
StaticLocationScreen::close();
}
void DialogScreen::freeResources() {
freeChapterTitleTexts();
freeDialogLineTexts();
_prevTitleIndexStack.clear();
_prevLineIndexStack.clear();
}
void DialogScreen::onScreenChanged() {
StaticLocationScreen::onScreenChanged();
for (uint i = 0; i < _chapterTitleTexts.size(); ++i) {
_chapterTitleTexts[i]->onScreenChanged();
}
for (uint i = 0; i < _dialogLineTexts.size(); ++i) {
_dialogLineTexts[i]->onScreenChanged();
}
}
void DialogScreen::onDialogClick(uint logIndex) {
freeLogTitleWidgets();
freeChapterTitleTexts();
_widgets[kWidgetIndexBack]->setVisible(false);
_widgets[kWidgetIndexNext]->setVisible(false);
_widgets[kWidgetIndex]->setVisible(true);
_nextLineIndex = 0;
_curLogIndex = logIndex;
loadDialog();
}
void DialogScreen::onRender() {
StaticLocationScreen::onRender();
for (uint i = 0; i < _chapterTitleTexts.size(); ++i) {
_chapterTitleTexts[i]->render();
}
for (uint i = 0; i < _dialogLineTexts.size(); ++i) {
_dialogLineTexts[i]->render();
}
}
void DialogScreen::loadIndex() {
static const int space = 4;
freeLogTitleWidgets();
freeChapterTitleTexts();
_startTitleIndex = _nextTitleIndex;
Common::Point pos = _indexFrame->getPosition();
int bottom = _indexFrame->getText()->getTargetHeight() + pos.y;
int height;
ChapterTitleText *chapterTitleText;
DialogTitleWidget *dialogTitleWidget;
_curMaxChapter = 99;
while (_nextTitleIndex < StarkDiary->countDialog()) {
height = 0;
chapterTitleText = nullptr;
dialogTitleWidget = new DialogTitleWidget(this, _gfx, _nextTitleIndex);
height += dialogTitleWidget->getHeight();
if (dialogTitleWidget->getChapter() != _curMaxChapter) {
_curMaxChapter = dialogTitleWidget->getChapter();
chapterTitleText = new ChapterTitleText(_gfx, _curMaxChapter);
height += chapterTitleText->getHeight() + 2 * space;
}
if (pos.y + height > bottom) {
delete dialogTitleWidget;
delete chapterTitleText;
break;
}
if (chapterTitleText) {
pos.y += space;
chapterTitleText->setPosition(pos);
pos.y += chapterTitleText->getHeight() + space;
}
dialogTitleWidget->setPosition(pos);
pos.y += dialogTitleWidget->getHeight() + space;
_widgets.push_back(dialogTitleWidget);
if (chapterTitleText) {
_chapterTitleTexts.push_back(chapterTitleText);
}
++_nextTitleIndex;
if (pos.y > bottom) {
break;
}
}
_widgets[kWidgetIndexBack]->setVisible(_startTitleIndex > 0);
_widgets[kWidgetIndexNext]->setVisible(_nextTitleIndex < StarkDiary->countDialog());
}
void DialogScreen::loadDialog() {
static const int space = 16;
freeDialogLineTexts();
_startLineIndex = _nextLineIndex;
Common::Point pos = _logFrame->getPosition();
int boxWidth = _logFrame->getText()->getTargetWidth();
int bottom = _logFrame->getText()->getTargetHeight() + pos.y;
int height;
DialogLineText *dialogLineText;
Diary::ConversationLog dialog = StarkDiary->getDialog(_curLogIndex);
while (_nextLineIndex < dialog.lines.size()) {
height = 0;
dialogLineText = new DialogLineText(_gfx, _curLogIndex, _nextLineIndex, boxWidth);
height = dialogLineText->getHeight();
if (pos.y + height + space > bottom) {
delete dialogLineText;
break;
}
dialogLineText->setPosition(pos);
_dialogLineTexts.push_back(dialogLineText);
pos.y += height + space;
++_nextLineIndex;
}
_widgets[kWidgetLogBack]->setVisible(_startLineIndex > 0);
_widgets[kWidgetLogNext]->setVisible(_nextLineIndex < dialog.lines.size());
}
void DialogScreen::backHandler() {
StarkUserInterface->backPrevScreen();
}
void DialogScreen::indexBackHandler() {
_nextTitleIndex = _prevTitleIndexStack.back();
_prevTitleIndexStack.pop_back();
loadIndex();
}
void DialogScreen::indexNextHandler() {
_prevTitleIndexStack.push_back(_startTitleIndex);
loadIndex();
}
void DialogScreen::logBackHandler() {
_nextLineIndex = _prevLineIndexStack.back();
_prevLineIndexStack.pop_back();
loadDialog();
}
void DialogScreen::backIndexHandler() {
freeDialogLineTexts();
_prevLineIndexStack.clear();
_widgets[kWidgetLogBack]->setVisible(false);
_widgets[kWidgetLogNext]->setVisible(false);
_widgets[kWidgetIndex]->setVisible(false);
_nextTitleIndex = _startTitleIndex;
loadIndex();
}
void DialogScreen::logNextHandler() {
_prevLineIndexStack.push_back(_startLineIndex);
loadDialog();
}
void DialogScreen::freeLogTitleWidgets() {
uint size = _widgets.size();
for (uint i = 0; i < size - _dialogTitleWidgetOffset; ++i) {
delete _widgets.back();
_widgets.pop_back();
}
}
void DialogScreen::freeChapterTitleTexts() {
for (uint i = 0; i < _chapterTitleTexts.size(); ++i) {
delete _chapterTitleTexts[i];
}
_chapterTitleTexts.clear();
}
void DialogScreen::freeDialogLineTexts() {
for (uint i = 0; i < _dialogLineTexts.size(); ++i) {
delete _dialogLineTexts[i];
}
_dialogLineTexts.clear();
}
ChapterTitleText::ChapterTitleText(Gfx::Driver *gfx, uint chapter) :
_pos(), _text(gfx) {
Common::String text = Common::String::format(
"%s: %s",
StarkGameChapter->getChapterTitle(chapter).c_str(),
StarkGameChapter->getChapterSubtitle(chapter).c_str());
text.toUppercase();
_text.setText(text);
_text.setColor(_color);
_text.setFont(FontProvider::kCustomFont, 5);
}
DialogLineText::DialogLineText(Gfx::Driver *gfx, uint logIndex, uint lineIndex, uint boxWidth) :
_namePos(), _linePos(), _boxWidth(boxWidth),
_nameText(gfx), _lineText(gfx) {
Diary::ConversationLogLine logLine = StarkDiary->getDialog(logIndex).lines[lineIndex];
Common::String name = StarkGlobal->getCharacterName(logLine.characterId);
name.toUppercase();
Gfx::Color color = logLine.characterId == StarkGlobal->getApril()->getCharacterIndex() ? _textColorApril : _textColorNormal;
_nameText.setText(name);
_nameText.setColor(color);
_nameText.setFont(FontProvider::kCustomFont, 5);
_lineText.setTargetWidth(_boxWidth);
_lineText.setText(logLine.line);
_lineText.setColor(color);
_lineText.setFont(FontProvider::kCustomFont, 3);
Common::Rect rect = _nameText.getRect();
_nameWidth = rect.right - rect.left;
_nameHeight = rect.bottom - rect.top;
rect = _lineText.getRect();
_lineHeight = rect.bottom - rect.top;
}
void DialogLineText::setPosition(const Common::Point &pos) {
static const uint space = 4;
_namePos.x = pos.x + (_boxWidth - _nameWidth) / 2;
_namePos.y = pos.y;
_linePos.x = pos.x;
_linePos.y = pos.y + _nameHeight + space;
}
DialogTitleWidget::DialogTitleWidget(DialogScreen *screen, Gfx::Driver *gfx, uint logIndex) :
StaticLocationWidget(nullptr, nullptr, nullptr),
_logIndex(logIndex), _pos(), _text(gfx),
_screen(screen) {
const Diary::ConversationLog &dialog = StarkDiary->getDialog(_logIndex);
_chapter = dialog.chapter;
_text.setText(dialog.title);
_text.setColor(_textColorDefault);
_text.setFont(FontProvider::kCustomFont, 3);
Common::Rect rect = _text.getRect();
_width = rect.right - rect.left;
_height = rect.bottom - rect.top;
}
bool DialogTitleWidget::isMouseInside(const Common::Point &mousePos) const {
return mousePos.x >= _pos.x && mousePos.x <= _pos.x + _width &&
mousePos.y >= _pos.y && mousePos.y <= _pos.y + _height;
}
void DialogTitleWidget::onClick() {
_screen->onDialogClick(_logIndex);
}
void DialogTitleWidget::onScreenChanged() {
_text.reset();
}
} // End of namespace Stark

View File

@@ -0,0 +1,174 @@
/* 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_UI_MENU_DIALOG_H
#define STARK_UI_MENU_DIALOG_H
#include "engines/stark/ui/menu/locationscreen.h"
#include "engines/stark/visual/text.h"
namespace Stark {
class ChapterTitleText;
class DialogLineText;
/**
* The conversation log menu
*/
class DialogScreen : public StaticLocationScreen {
public:
DialogScreen(Gfx::Driver *gfx, Cursor *cursor);
virtual ~DialogScreen();
// StaticLocationScreen API
void open() override;
void close() override;
void onScreenChanged() override;
void onDialogClick(uint logIndex);
protected:
// Window API
void onRender() override;
private:
static const uint _dialogTitleWidgetOffset = 8;
enum WidgetIndex {
kWidgetIndexBack = 3,
kWidgetIndexNext = 4,
kWidgetLogBack = 5,
kWidgetIndex = 6,
kWidgetLogNext = 7
};
Gfx::RenderEntry *_indexFrame, *_logFrame;
uint _startTitleIndex, _nextTitleIndex, _startLineIndex, _nextLineIndex;
uint _curMaxChapter, _curLogIndex;
Common::Array<ChapterTitleText *> _chapterTitleTexts;
Common::Array<uint> _prevTitleIndexStack;
Common::Array<DialogLineText *> _dialogLineTexts;
Common::Array<uint> _prevLineIndexStack;
void loadIndex();
void loadDialog();
void backHandler();
void indexBackHandler();
void indexNextHandler();
void logBackHandler();
void backIndexHandler();
void logNextHandler();
void freeLogTitleWidgets();
void freeChapterTitleTexts();
void freeDialogLineTexts();
void freeResources();
};
/**
* The chapter title displayed on the menu
*/
class ChapterTitleText {
public:
ChapterTitleText(Gfx::Driver *gfx, uint chapter);
~ChapterTitleText() {}
void setPosition(const Common::Point &pos) { _pos = pos; }
uint getHeight() { return _text.getRect().bottom - _text.getRect().top; }
void render() { _text.render(_pos); }
void onScreenChanged() { _text.reset(); }
private:
const Gfx::Color _color = Gfx::Color(0x68, 0x05, 0x04);
Common::Point _pos;
VisualText _text;
};
/**
* The dialog text displayed
*/
class DialogLineText {
public:
DialogLineText(Gfx::Driver *gfx, uint logIndex, uint lineIndex, uint boxWidth);
~DialogLineText() {}
void setPosition(const Common::Point &pos);
uint getHeight() { return _nameHeight + _lineHeight + 4; }
void render() {
_nameText.render(_namePos);
_lineText.render(_linePos);
}
void onScreenChanged() {
_nameText.reset();
_lineText.reset();
}
private:
const Gfx::Color _textColorApril = Gfx::Color(0x68, 0x05, 0x04);
const Gfx::Color _textColorNormal = Gfx::Color(0x1E, 0x1E, 0x96);
Common::Point _namePos, _linePos;
VisualText _nameText, _lineText;
uint _nameWidth, _nameHeight, _lineHeight, _boxWidth;
};
/**
* The dialog widget
*/
class DialogTitleWidget : public StaticLocationWidget {
public:
DialogTitleWidget(DialogScreen *screen, Gfx::Driver *gfx, uint logIndex);
virtual ~DialogTitleWidget() {}
void setPosition(const Common::Point &pos) { _pos = pos; }
uint getHeight() { return _height; }
uint getChapter() { return _chapter; }
// StaticLocationWidget API
void render() override { _text.render(_pos); }
bool isMouseInside(const Common::Point &mousePos) const override;
void onClick() override;
void onMouseMove(const Common::Point &mousePos) override {
_text.setColor(isMouseInside(mousePos) ? _textColorHovered : _textColorDefault);
}
void onScreenChanged() override;
private:
const Gfx::Color _textColorHovered = Gfx::Color(0x1E, 0x1E, 0x96);
const Gfx::Color _textColorDefault = Gfx::Color(0x00, 0x00, 0x00);
uint _logIndex, _chapter;
int _width, _height;
Common::Point _pos;
VisualText _text;
DialogScreen *_screen;
};
} // End of namespace Stark
#endif // STARK_UI_MENU_DIALOG_H

View File

@@ -0,0 +1,145 @@
/* 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/ui/menu/diaryindex.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/diary.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/services/gamemessage.h"
#include "engines/stark/ui/cursor.h"
#include "engines/engine.h"
#include "gui/message.h"
#include "gui/saveload.h"
namespace Stark {
DiaryIndexScreen::DiaryIndexScreen(Gfx::Driver *gfx, Cursor *cursor) :
StaticLocationScreen(gfx, cursor, "DiaryIndexLocation", Screen::kScreenDiaryIndex) {
}
DiaryIndexScreen::~DiaryIndexScreen() {
}
void DiaryIndexScreen::open() {
StaticLocationScreen::open();
_widgets.push_back(new StaticLocationWidget(
"BGImage",
nullptr,
nullptr));
_widgets.push_back(new StaticLocationWidget(
"SaveGame",
CLICK_HANDLER(DiaryIndexScreen, saveHandler),
MOVE_HANDLER(DiaryIndexScreen, widgetTextColorHandler)));
_widgets.back()->setVisible(g_engine->canSaveGameStateCurrently());
_widgets.push_back(new StaticLocationWidget(
"Continue",
CLICK_HANDLER(DiaryIndexScreen, loadHandler),
MOVE_HANDLER(DiaryIndexScreen, widgetTextColorHandler)));
_widgets.push_back(new StaticLocationWidget(
"Options",
CLICK_HANDLER(DiaryIndexScreen, settingsHandler),
MOVE_HANDLER(DiaryIndexScreen, widgetTextColorHandler)));
_widgets.push_back(new StaticLocationWidget(
"Log",
CLICK_HANDLER(DiaryIndexScreen, dialogHandler),
MOVE_HANDLER(DiaryIndexScreen, widgetTextColorHandler)));
_widgets.push_back(new StaticLocationWidget(
"Fmv",
CLICK_HANDLER(DiaryIndexScreen, fmvHandler),
MOVE_HANDLER(DiaryIndexScreen, widgetTextColorHandler)));
_widgets.push_back(new StaticLocationWidget(
"Diary",
CLICK_HANDLER(DiaryIndexScreen, diaryHandler),
MOVE_HANDLER(DiaryIndexScreen, widgetTextColorHandler)));
_widgets.back()->setVisible(StarkDiary->isEnabled());
_widgets.push_back(new StaticLocationWidget(
"Return",
CLICK_HANDLER(DiaryIndexScreen, backHandler),
nullptr));
_widgets.push_back(new StaticLocationWidget(
"Quit",
CLICK_HANDLER(DiaryIndexScreen, quitHandler),
MOVE_HANDLER(DiaryIndexScreen, widgetTextColorHandler)));
_widgets.push_back(new StaticLocationWidget(
"Back",
CLICK_HANDLER(DiaryIndexScreen, backHandler),
nullptr));
for (uint i = 1; i < _widgets.size(); i++) {
// The background image is intentionally ignored
_widgets[i]->setupSounds(0, 1);
}
}
void DiaryIndexScreen::widgetTextColorHandler(StaticLocationWidget &widget, const Common::Point &mousePos) {
if (widget.isVisible()) {
Gfx::Color textColor = widget.isMouseInside(mousePos) ? _textColorHovered : _textColorDefault;
widget.setTextColor(textColor);
}
}
void DiaryIndexScreen::settingsHandler() {
StarkUserInterface->changeScreen(Screen::kScreenSettingsMenu);
}
void DiaryIndexScreen::fmvHandler() {
StarkUserInterface->changeScreen(Screen::kScreenFMVMenu);
}
void DiaryIndexScreen::backHandler() {
StarkUserInterface->backPrevScreen();
}
void DiaryIndexScreen::quitHandler() {
StarkUserInterface->confirm(GameMessage::kQuitGamePrompt, StarkUserInterface,
&UserInterface::requestQuitToMainMenu);
}
void DiaryIndexScreen::loadHandler() {
StarkUserInterface->changeScreen(Screen::kScreenLoadMenu);
}
void DiaryIndexScreen::saveHandler() {
StarkUserInterface->changeScreen(Screen::kScreenSaveMenu);
}
void DiaryIndexScreen::diaryHandler() {
StarkUserInterface->changeScreen(Screen::kScreenDiaryPages);
}
void DiaryIndexScreen::dialogHandler() {
StarkUserInterface->changeScreen(Screen::kScreenDialog);
}
} // End of namespace Stark

View File

@@ -0,0 +1,57 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STARK_UI_MENU_DIARY_INDEX_H
#define STARK_UI_MENU_DIARY_INDEX_H
#include "engines/stark/ui/menu/locationscreen.h"
namespace Stark {
/**
* The diary index is the in-game menu
*/
class DiaryIndexScreen : public StaticLocationScreen {
public:
DiaryIndexScreen(Gfx::Driver *gfx, Cursor *cursor);
virtual ~DiaryIndexScreen();
// StaticLocationScreen API
void open() override;
private:
void widgetTextColorHandler(StaticLocationWidget &widget, const Common::Point &mousePos);
void backHandler();
void settingsHandler();
void fmvHandler();
void loadHandler();
void saveHandler();
void diaryHandler();
void dialogHandler();
void quitHandler();
const Gfx::Color _textColorHovered = Gfx::Color(0x1E, 0x1E, 0x96);
const Gfx::Color _textColorDefault = Gfx::Color(0x00, 0x00, 0x00);
};
} // End of namespace Stark
#endif // STARK_UI_MENU_DIARY_INDEX_H

View 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/>.
*
*/
#include "engines/stark/ui/menu/diarypages.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/services/diary.h"
#include "engines/stark/services/staticprovider.h"
#include "engines/stark/resources/location.h"
#include "engines/stark/resources/layer.h"
#include "engines/stark/gfx/renderentry.h"
namespace Stark {
DiaryPagesScreen::DiaryPagesScreen(Gfx::Driver *gfx, Cursor *cursor) :
StaticLocationScreen(gfx, cursor, "DiaryPages", Screen::kScreenDiaryPages),
_page(0) {
}
DiaryPagesScreen::~DiaryPagesScreen() {
}
void DiaryPagesScreen::open() {
StaticLocationScreen::open();
_widgets.push_back(new StaticLocationWidget(
"BGImage",
nullptr,
nullptr));
_widgets.push_back(new StaticLocationWidget(
"Return",
CLICK_HANDLER(DiaryPagesScreen, backHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"GoBack",
CLICK_HANDLER(DiaryPagesScreen, backHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"Back",
CLICK_HANDLER(DiaryPagesScreen, prevPageHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"Next",
CLICK_HANDLER(DiaryPagesScreen, nextPageHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
_page = StarkDiary->getPageIndex();
if (StarkDiary->countDiary() > 0) {
_widgets.push_back(new DiaryWidget(_page));
_widgets[kWidgetBack]->setVisible(_page > 0);
_widgets[kWidgetNext]->setVisible(_page < StarkDiary->countDiary() - 1);
} else {
_widgets[kWidgetBack]->setVisible(false);
_widgets[kWidgetNext]->setVisible(false);
}
}
void DiaryPagesScreen::close() {
StarkDiary->setPageIndex(_page);
StarkDiary->setDiaryAllRead();
StaticLocationScreen::close();
}
void DiaryPagesScreen::backHandler() {
StarkUserInterface->backPrevScreen();
}
void DiaryPagesScreen::changePage(uint page) {
assert(page < StarkDiary->countDiary());
delete _widgets.back();
_widgets.pop_back();
_widgets.push_back(new DiaryWidget(page));
_widgets[kWidgetBack]->setVisible(page > 0);
_widgets[kWidgetNext]->setVisible(page < StarkDiary->countDiary() - 1);
_page = page;
}
DiaryWidget::DiaryWidget(uint diaryIndex):
StaticLocationWidget(nullptr, nullptr, nullptr) {
Resources::Location *location = StarkStaticProvider->getLocation();
Resources::Layer *layer = location->getLayerByName(StarkDiary->getDiary(diaryIndex));
if (!layer) {
debug("Unable to retrieve diary in layer %s.", StarkDiary->getDiary(diaryIndex).c_str());
return;
}
// Diary page layer contains only one item, the text
_renderEntry = layer->listRenderEntries()[0];
}
} // End of namespace Stark

View File

@@ -0,0 +1,67 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef STARK_UI_MENU_DIARY_PAGES_H
#define STARK_UI_MENU_DIARY_PAGES_H
#include "engines/stark/ui/menu/locationscreen.h"
namespace Stark {
/**
* The screen where diary pages are shown in the game
*/
class DiaryPagesScreen : public StaticLocationScreen {
public:
DiaryPagesScreen(Gfx::Driver *gfx, Cursor *cursor);
virtual ~DiaryPagesScreen();
// StaticLocationScreen API
void open() override;
void close() override;
private:
enum WidgetIndex {
kWidgetBack = 3,
kWidgetNext = 4
};
uint _page;
void backHandler();
void prevPageHandler() { changePage(_page - 1); }
void nextPageHandler() { changePage(_page + 1); }
void changePage(uint page);
};
/**
* The widget displaying diary text
*/
class DiaryWidget : public StaticLocationWidget {
public:
DiaryWidget(uint diaryIndex);
~DiaryWidget() {}
};
} // End of namespace Stark
#endif // STARK_UI_MENU_DIARY_PAGES_H

View File

@@ -0,0 +1,197 @@
/* 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/ui/menu/fmvmenu.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/services/diary.h"
#include "engines/stark/services/staticprovider.h"
#include "engines/stark/resources/location.h"
#include "engines/stark/visual/text.h"
namespace Stark {
FMVMenuScreen::FMVMenuScreen(Gfx::Driver *gfx, Cursor *cursor) :
StaticLocationScreen(gfx, cursor, "DiaryFMV", Screen::kScreenFMVMenu),
_fmvWidgets(),
_page(0),
_maxPage(0) {
_formatRectPos = Common::Point(202, 61);
_fontHeight = 16;
_fmvPerPage = 18;
}
FMVMenuScreen::~FMVMenuScreen() {
freeFMVWidgets();
}
void FMVMenuScreen::open() {
StaticLocationScreen::open();
_widgets.push_back(new StaticLocationWidget(
"BGImage",
nullptr,
nullptr));
_widgets.push_back(new StaticLocationWidget(
"Return",
CLICK_HANDLER(FMVMenuScreen, backHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"Back",
CLICK_HANDLER(FMVMenuScreen, backHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"PreviousPage",
CLICK_HANDLER(FMVMenuScreen, prevPageHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"NextPage",
CLICK_HANDLER(FMVMenuScreen, nextPageHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
// Acquire data for FMVWidget from the format rectangle
int formatRectHeight = 379;
Resources::Location *location = StarkStaticProvider->getLocation();
Gfx::RenderEntry *formatRect = location->getRenderEntryByName("FormatRectangle");
if (formatRect) {
_formatRectPos = formatRect->getPosition();
formatRectHeight = formatRect->getText()->getTargetHeight();
// The format rectangle contains one line,
// which can be used to retrieve the font's height
Common::Rect textRect = formatRect->getText()->getRect();
_fontHeight = textRect.bottom - textRect.top;
_fmvPerPage = formatRectHeight / (_fontHeight + 4);
}
_maxPage = StarkDiary->countFMV() / _fmvPerPage;
changePage(0);
}
void FMVMenuScreen::close() {
freeFMVWidgets();
StaticLocationScreen::close();
}
void FMVMenuScreen::onScreenChanged() {
StaticLocationScreen::onScreenChanged();
for (uint i = 0; i < _fmvWidgets.size(); ++i) {
_fmvWidgets[i]->onScreenChanged();
}
}
void FMVMenuScreen::onMouseMove(const Common::Point &pos) {
StaticLocationScreen::onMouseMove(pos);
for (uint i = 0; i < _fmvWidgets.size(); ++i) {
_fmvWidgets[i]->onMouseMove(pos);
}
}
void FMVMenuScreen::onClick(const Common::Point &pos) {
StaticLocationScreen::onClick(pos);
for (uint i = 0; i < _fmvWidgets.size(); ++i) {
if (_fmvWidgets[i]->isMouseInside(pos)) {
_fmvWidgets[i]->onClick();
return;
}
}
}
void FMVMenuScreen::onRender() {
StaticLocationScreen::onRender();
for (uint i = 0; i < _fmvWidgets.size(); ++i) {
_fmvWidgets[i]->render();
}
}
void FMVMenuScreen::backHandler() {
StarkUserInterface->backPrevScreen();
}
void FMVMenuScreen::freeFMVWidgets() {
for (uint i = 0; i < _fmvWidgets.size(); ++i) {
delete _fmvWidgets[i];
}
_fmvWidgets.clear();
}
void FMVMenuScreen::loadFMVWidgets(uint page) {
uint start = page * _fmvPerPage;
uint end = start + _fmvPerPage;
end = end < StarkDiary->countFMV() ? end : StarkDiary->countFMV();
for (uint i = start; i < end; ++i) {
_fmvWidgets.push_back(new FMVWidget(_gfx, i));
}
}
void FMVMenuScreen::changePage(uint page) {
assert(page <= _maxPage);
freeFMVWidgets();
loadFMVWidgets(page);
_widgets[kWidgetPrevious]->setVisible(page > 0);
_widgets[kWidgetNext]->setVisible(page < _maxPage);
_page = page;
}
FMVWidget::FMVWidget(Gfx::Driver *gfx, uint fmvIndex) :
_filename(StarkDiary->getFMVFilename(fmvIndex)),
_title(gfx) {
_title.setText(StarkDiary->getFMVTitle(fmvIndex));
_title.setColor(_textColorDefault);
_title.setFont(FontProvider::kCustomFont, 3);
Common::Rect rect = _title.getRect();
_width = rect.right - rect.left;
_formatRectPos = Common::Point(202, 61);
_fontHeight = 16;
_fmvPerPage = 18;
_position.x = _formatRectPos.x;
_position.y = _formatRectPos.y + (fmvIndex % _fmvPerPage) * (_fontHeight + 4);
}
void FMVWidget::onClick() {
StarkUserInterface->requestFMVPlayback(_filename);
}
bool FMVWidget::isMouseInside(const Common::Point &mousePos) const {
return mousePos.x >= _position.x && mousePos.x <= _position.x + _width &&
mousePos.y >= _position.y && mousePos.y <= _position.y + _fontHeight;
}
} // End of namespace Stark

View File

@@ -0,0 +1,116 @@
/* 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_UI_MENU_FMV_MENU_H
#define STARK_UI_MENU_FMV_MENU_H
#include "engines/stark/ui/menu/locationscreen.h"
#include "engines/stark/visual/text.h"
#include "common/path.h"
namespace Stark {
class FMVWidget;
/**
* The video replay menu
*/
class FMVMenuScreen : public StaticLocationScreen {
public:
FMVMenuScreen(Gfx::Driver *gfx, Cursor *cursor);
virtual ~FMVMenuScreen();
// StaticLocationScreen API
void open() override;
void close() override;
void onScreenChanged() override;
protected:
// Window API
void onMouseMove(const Common::Point &pos) override;
void onClick(const Common::Point &pos) override;
void onRender() override;
private:
enum WidgetIndex {
kWidgetPrevious = 3,
kWidgetNext = 4
};
Common::Array<FMVWidget *> _fmvWidgets;
Common::Point _formatRectPos;
int _fontHeight;
uint _fmvPerPage;
// Count from zero
uint _page, _maxPage;
void backHandler();
void prevPageHandler() { changePage(_page - 1); }
void nextPageHandler() { changePage(_page + 1); }
void freeFMVWidgets();
void loadFMVWidgets(uint page);
void changePage(uint page);
};
/**
* The widget for FMV entry, specifically built for FMVMenuScreen
*/
class FMVWidget {
public:
FMVWidget(Gfx::Driver *gfx, uint fmvIndex);
~FMVWidget() {}
void render() { _title.render(_position); }
bool isMouseInside(const Common::Point &mousePos) const;
void onMouseMove(const Common::Point &mousePos) {
setTextColor(isMouseInside(mousePos) ? _textColorHovered : _textColorDefault);
}
void onClick();
void setTextColor(const Gfx::Color &color) { _title.setColor(color); }
void onScreenChanged() { _title.reset(); }
private:
const Gfx::Color _textColorHovered = Gfx::Color(0x1E, 0x1E, 0x96);
const Gfx::Color _textColorDefault = Gfx::Color(0x00, 0x00, 0x00);
Common::Point _formatRectPos;
int _fontHeight;
uint _fmvPerPage;
const Common::Path &_filename;
VisualText _title;
int _width;
Common::Point _position;
};
} // End of namespace Stark
#endif // STARK_UI_MENU_FMV_MENU_H

View File

@@ -0,0 +1,268 @@
/* 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/ui/menu/locationscreen.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/staticprovider.h"
#include "engines/stark/resources/item.h"
#include "engines/stark/resources/location.h"
#include "engines/stark/resources/sound.h"
#include "engines/stark/ui/cursor.h"
#include "engines/stark/visual/text.h"
#include "audio/mixer.h"
#include "common/system.h"
namespace Stark {
StaticLocationScreen::StaticLocationScreen(Gfx::Driver *gfx, Cursor *cursor,
const char *locationName, Screen::Name screenName) :
SingleWindowScreen(screenName, gfx, cursor),
_locationName(locationName),
_location(nullptr),
_hoveredWidgetIndex(-1) {
_position = Common::Rect(Gfx::Driver::kOriginalWidth, Gfx::Driver::kOriginalHeight);
_visible = true;
}
StaticLocationScreen::~StaticLocationScreen() {
freeWidgets();
}
void StaticLocationScreen::open() {
_location = StarkStaticProvider->loadLocation(_locationName);
}
void StaticLocationScreen::close() {
freeWidgets();
StarkStaticProvider->unloadLocation(_location);
_location = nullptr;
}
void StaticLocationScreen::freeWidgets() {
for (uint i = 0; i < _widgets.size(); i++) {
delete _widgets[i];
}
_widgets.clear();
_hoveredWidgetIndex = -1;
}
void StaticLocationScreen::onGameLoop() {
for (uint i = 0; i < _widgets.size(); i++) {
StaticLocationWidget *widget = _widgets[i];
if (widget->isVisible()) {
widget->onGameLoop();
}
}
}
void StaticLocationScreen::onMouseMove(const Common::Point &pos) {
int newHoveredWidget = -1;
for (uint i = 0; i < _widgets.size(); i++) {
StaticLocationWidget *widget = _widgets[i];
widget->onMouseMove(pos);
if (widget->isVisible() && widget->isMouseInside(pos)) {
newHoveredWidget = i;
}
}
// The first widget is always the background. It is ignored below.
if (newHoveredWidget != _hoveredWidgetIndex) {
if (_hoveredWidgetIndex > 0 && uint(_hoveredWidgetIndex) < _widgets.size()) {
_widgets[_hoveredWidgetIndex]->onMouseLeave();
}
if (newHoveredWidget > 0) {
_widgets[newHoveredWidget]->onMouseEnter();
}
_hoveredWidgetIndex = newHoveredWidget;
}
_cursor->setCursorType(_hoveredWidgetIndex > 0 ? Cursor::kActive : Cursor::kDefault);
}
void StaticLocationScreen::onClick(const Common::Point &pos) {
for (uint i = 1; i < _widgets.size(); i++) {
StaticLocationWidget *widget = _widgets[i];
if (widget->isVisible() && widget->isMouseInside(pos)) {
widget->onClick();
break;
}
}
}
void StaticLocationScreen::onRender() {
for (uint i = 0; i < _widgets.size(); i++) {
if (_widgets[i]->isVisible()) {
_widgets[i]->render();
}
}
}
void StaticLocationScreen::onScreenChanged() {
for (uint i = 0; i < _widgets.size(); i++) {
_widgets[i]->onScreenChanged();
}
}
void StaticLocationScreen::waitForSoundsToComplete() {
while (g_system->getMixer()->hasActiveChannelOfType(Audio::Mixer::kSFXSoundType)) {
StarkGfx->clearScreen();
g_system->delayMillis(10);
StarkGfx->flipBuffer();
}
}
StaticLocationWidget::StaticLocationWidget(const char *renderEntryName, WidgetOnClickCallback *onClickCallback,
WidgetOnMouseMoveCallback *onMouseMoveCallback):
_onClick(onClickCallback),
_onMouseMove(onMouseMoveCallback),
_renderEntry(nullptr),
_item(nullptr),
_soundMouseEnter(nullptr),
_soundMouseClick(nullptr),
_visible(true) {
if (renderEntryName) {
Resources::Location *location = StarkStaticProvider->getLocation();
_renderEntry = location->getRenderEntryByName(renderEntryName);
if (_renderEntry == nullptr) {
debug("Widget disabled: unable to find render entry with name '%s' in location '%s'",
renderEntryName, location->getName().c_str());
setVisible(false);
} else {
_item = _renderEntry->getOwner();
}
}
}
void StaticLocationWidget::render() {
if (_renderEntry) {
_renderEntry->render();
}
}
bool StaticLocationWidget::isVisible() const {
return _visible;
}
void StaticLocationWidget::setVisible(bool visible) {
_visible = visible;
}
bool StaticLocationWidget::isMouseInside(const Common::Point &mousePos) const {
if (!_renderEntry) return false;
Common::Point relativePosition;
return _renderEntry->containsPoint(mousePos, relativePosition, Common::Rect());
}
void StaticLocationWidget::onClick() {
onMouseLeave();
if (_soundMouseClick) {
_soundMouseClick->play();
_soundMouseClick->setStopOnDestroy(false);
}
if (_onClick) {
(*_onClick)();
}
}
void StaticLocationWidget::onGameLoop() {
if (_item) {
_item->onGameLoop();
}
}
void StaticLocationWidget::onMouseEnter() {
if (_soundMouseEnter && !_soundMouseEnter->isPlaying()) {
_soundMouseEnter->play();
}
}
void StaticLocationWidget::onMouseLeave() {
if (_soundMouseEnter) {
_soundMouseEnter->stop();
}
}
void StaticLocationWidget::setupSounds(int16 enterSound, int16 clickSound) {
if (enterSound != -1) {
_soundMouseEnter = StarkStaticProvider->getLocationSound(enterSound);
}
if (clickSound != -1) {
_soundMouseClick = StarkStaticProvider->getLocationSound(clickSound);
}
}
void StaticLocationWidget::setTextColor(const Gfx::Color &textColor) {
if (!_renderEntry) return;
VisualText *text = _renderEntry->getText();
assert(text);
text->setColor(textColor);
}
void StaticLocationWidget::onScreenChanged() {
if (!_renderEntry) return;
VisualText *text = _renderEntry->getText();
if (text) {
text->reset();
}
}
void StaticLocationWidget::onMouseMove(const Common::Point &mousePos) {
if (_onMouseMove) {
(*_onMouseMove)(*this, mousePos);
}
}
Common::Point StaticLocationWidget::getPosition() const {
if (_renderEntry) {
return _renderEntry->getPosition();
}
return Common::Point(0, 0);
}
StaticLocationWidget::~StaticLocationWidget() {
delete _onClick;
delete _onMouseMove;
}
} // End of namespace Stark

View File

@@ -0,0 +1,156 @@
/* 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_UI_MENU_LOCATION_SCREEN_H
#define STARK_UI_MENU_LOCATION_SCREEN_H
#include "engines/stark/ui/screen.h"
#include "engines/stark/ui/window.h"
#include "engines/stark/gfx/color.h"
namespace Stark {
namespace Gfx {
class RenderEntry;
}
namespace Resources {
class ItemVisual;
class Location;
class Sound;
}
class StaticLocationWidget;
/**
* Abstract user interface screen using resources from a static Location sub-tree
*/
class StaticLocationScreen : public SingleWindowScreen {
public:
StaticLocationScreen(Gfx::Driver *gfx, Cursor *cursor, const char *locationName, Screen::Name screenName);
~StaticLocationScreen() override;
// Screen API
void open() override;
void close() override;
void onScreenChanged() override;
/**
* Wait for all effect sounds to complete
*
* Used to ensure the button press sounds are no longer
* playing before performing the next action that
* would produce a sound.
*/
void waitForSoundsToComplete();
protected:
// Window API
void onMouseMove(const Common::Point &pos) override;
void onClick(const Common::Point &pos) override;
void onGameLoop() override;
void onRender() override;
Common::Array<StaticLocationWidget *> _widgets;
private:
const char *_locationName;
Resources::Location *_location;
int _hoveredWidgetIndex;
void freeWidgets();
};
typedef Common::Functor0<void> WidgetOnClickCallback;
typedef Common::Functor2<StaticLocationWidget &, const Common::Point &, void> WidgetOnMouseMoveCallback;
#define CLICK_HANDLER(cls, method) new Common::Functor0Mem<void, cls>(this, &cls::method)
#define MOVE_HANDLER(cls, method) new Common::Functor2Mem<StaticLocationWidget &, const Common::Point &, void, cls>(this, &cls::method)
/**
* User interface widget bound to a Location RenderEntry
*
* Also used without bounding the RenderEntry, as a base class
*/
class StaticLocationWidget {
public:
StaticLocationWidget(const char *renderEntryName, WidgetOnClickCallback *onClickCallback,
WidgetOnMouseMoveCallback *onMouseMoveCallback);
virtual ~StaticLocationWidget();
/** Draw the widget */
virtual void render();
/** Is the specified point inside the widget? */
virtual bool isMouseInside(const Common::Point &mousePos) const;
/** Called when the widget is clicked */
virtual void onClick();
/** Called when the mouse hovers the widget */
virtual void onMouseMove(const Common::Point &mousePos);
/** Called when the mouse's left button just gets up */
virtual void onMouseUp() {}
/** Called when the screen's resolution is changed */
virtual void onScreenChanged();
/** Lookup sounds in the static location for use when hovering / clicking the widget */
void setupSounds(int16 enterSound, int16 clickSound);
/**
* Override the text color
*
* Only applies for widget referring to a RenderEntry for a text visual
*/
void setTextColor(const Gfx::Color &textColor);
/** Widgets must be visible to be rendered and interactive */
bool isVisible() const;
void setVisible(bool visible);
/** Per frame widget state update callback */
void onGameLoop();
/** Called when the mouse enters the widget */
void onMouseEnter();
/** Called when the mouse leaves the widget */
void onMouseLeave();
protected:
Common::Point getPosition() const;
Gfx::RenderEntry *_renderEntry;
private:
Resources::ItemVisual *_item;
bool _visible;
Resources::Sound *_soundMouseEnter;
Resources::Sound *_soundMouseClick;
WidgetOnClickCallback *_onClick;
WidgetOnMouseMoveCallback *_onMouseMove;
};
} // End of namespace Stark
#endif // STARK_UI_MENU_LOCATION_SCREEN_H

View File

@@ -0,0 +1,197 @@
/* 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/ui/menu/mainmenu.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/services/resourceprovider.h"
#include "engines/stark/services/global.h"
#include "engines/stark/services/settings.h"
#include "engines/stark/services/gamemessage.h"
#include "engines/stark/gfx/renderentry.h"
#include "engines/stark/visual/text.h"
#include "engines/stark/scene.h"
#include "common/config-manager.h"
namespace Stark {
MainMenuScreen::MainMenuScreen(Gfx::Driver *gfx, Cursor *cursor) :
StaticLocationScreen(gfx, cursor, "MainMenuLocation", Screen::kScreenMainMenu) {
}
MainMenuScreen::~MainMenuScreen() {
}
void MainMenuScreen::open() {
StaticLocationScreen::open();
_widgets.push_back(new StaticLocationWidget(
"BGImage",
nullptr,
nullptr));
_widgets.push_back(new StaticLocationWidget(
"NewGame",
CLICK_HANDLER(MainMenuScreen, newGameHandler),
MOVE_HANDLER(MainMenuScreen, helpTextHandler<kNewGame>)));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"Continue",
CLICK_HANDLER(MainMenuScreen, loadHandler),
MOVE_HANDLER(MainMenuScreen, helpTextHandler<kContinue>)));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"Options",
CLICK_HANDLER(MainMenuScreen, settingsHandler),
MOVE_HANDLER(MainMenuScreen, helpTextHandler<kOption>)));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"Box",
CLICK_HANDLER(MainMenuScreen, boxHandler),
MOVE_HANDLER(MainMenuScreen, helpTextHandler<kBox>)));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"Quit",
CLICK_HANDLER(MainMenuScreen, quitHandler),
MOVE_HANDLER(MainMenuScreen, helpTextHandler<kQuit>)));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"OptionHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new StaticLocationWidget(
"BeginHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new StaticLocationWidget(
"ContinueHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new StaticLocationWidget(
"BoxHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new StaticLocationWidget(
"QuitHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new StaticLocationWidget(
"Credits",
CLICK_HANDLER(MainMenuScreen, creditsHandler),
MOVE_HANDLER(MainMenuScreen, helpTextHandler<kCredits>)));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"CreditHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new VersionInfoText());
}
template<MainMenuScreen::HelpTextIndex N>
void MainMenuScreen::helpTextHandler(StaticLocationWidget &widget, const Common::Point &mousePos) {
if (widget.isVisible()) {
_widgets[N]->setVisible(widget.isMouseInside(mousePos));
}
}
void MainMenuScreen::creditsHandler() {
if (!StarkSettings->isDemo()) {
waitForSoundsToComplete();
StarkUserInterface->requestFMVPlayback("0e02.bbb");
}
}
void MainMenuScreen::newGameHandler() {
waitForSoundsToComplete();
StarkUserInterface->changeScreen(kScreenGame);
StarkResourceProvider->initGlobal();
if (ConfMan.hasKey("startup_chapter")) {
StarkGlobal->setCurrentChapter(ConfMan.getInt("startup_chapter"));
} else {
StarkGlobal->setCurrentChapter(0);
}
if (ConfMan.hasKey("startup_level") && ConfMan.hasKey("startup_location")) {
uint levelIndex = strtol(ConfMan.get("startup_level").c_str(), nullptr, 16);
uint locationIndex = strtol(ConfMan.get("startup_location").c_str(), nullptr, 16);
StarkResourceProvider->requestLocationChange(levelIndex, locationIndex);
} else {
if (StarkSettings->isDemo()) {
StarkResourceProvider->requestLocationChange(0x4f, 0x00);
} else {
// Start us up at the house of all worlds
StarkResourceProvider->requestLocationChange(0x45, 0x00);
}
}
}
void MainMenuScreen::loadHandler() {
StarkUserInterface->changeScreen(Screen::kScreenLoadMenu);
}
void MainMenuScreen::settingsHandler() {
StarkUserInterface->changeScreen(Screen::kScreenSettingsMenu);
}
void MainMenuScreen::boxHandler() {
if (!StarkSettings->isDemo() && StarkSettings->hasBookOfSecrets()) {
StarkUserInterface->changeScreen(kScreenGame);
StarkResourceProvider->initGlobal();
StarkResourceProvider->requestLocationChange(0x7c, 0x00);
}
}
void MainMenuScreen::quitHandler() {
StarkUserInterface->confirm(GameMessage::kQuitGamePrompt, StarkUserInterface,
&UserInterface::notifyShouldExit);
}
VersionInfoText::VersionInfoText() :
StaticLocationWidget("VERSION INFO", nullptr, nullptr) {
Common::String text = _copyrightSymbol + Common::String("1999 Funcom");
_renderEntry->getText()->setText(text);
_renderEntry->setPosition(Common::Point(_posX, _posY));
}
} // End of namespace Stark

View File

@@ -0,0 +1,76 @@
/* 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_UI_MENU_MAIN_MENU_H
#define STARK_UI_MENU_MAIN_MENU_H
#include "engines/stark/ui/menu/locationscreen.h"
namespace Stark {
/**
* The main menu of the game when it is opened
*/
class MainMenuScreen : public StaticLocationScreen {
public:
MainMenuScreen(Gfx::Driver *gfx, Cursor *cursor);
virtual ~MainMenuScreen();
// StaticLocationScreen API
void open() override;
private:
enum HelpTextIndex {
kNewGame = 7,
kContinue = 8,
kOption = 6,
kBox = 9,
kQuit = 10,
kCredits = 12
};
template<HelpTextIndex N>
void helpTextHandler(StaticLocationWidget &widget, const Common::Point &mousePos);
void newGameHandler();
void loadHandler();
void creditsHandler();
void settingsHandler();
void boxHandler();
void quitHandler();
};
/**
* The version info text
*/
class VersionInfoText : public StaticLocationWidget {
public:
VersionInfoText();
virtual ~VersionInfoText() {}
private:
static const char _copyrightSymbol = char(0xA9);
static const int _posX = 16, _posY = 419;
};
} // End of namespace Stark
#endif // STARK_UI_MENU_MAIN_MENU_H

View File

@@ -0,0 +1,360 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/stark/ui/menu/saveloadmenu.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/services/stateprovider.h"
#include "engines/stark/services/global.h"
#include "engines/stark/services/settings.h"
#include "engines/stark/services/gamechapter.h"
#include "engines/stark/services/gamemessage.h"
#include "engines/stark/gfx/driver.h"
#include "engines/stark/gfx/bitmap.h"
#include "engines/stark/gfx/surfacerenderer.h"
#include "engines/stark/stark.h"
#include "engines/stark/savemetadata.h"
#include "engines/engine.h"
#include "common/config-manager.h"
#include "common/savefile.h"
#include "gui/message.h"
namespace Stark {
SaveLoadMenuScreen::SaveLoadMenuScreen(Gfx::Driver *gfx, Cursor *cursor, Screen::Name screenName) :
StaticLocationScreen(gfx, cursor, "LoadSaveLocation", screenName),
_page(0),
_maxPage(10) {
}
SaveLoadMenuScreen::~SaveLoadMenuScreen() {
}
void SaveLoadMenuScreen::open() {
StaticLocationScreen::open();
_maxPage = computeMaxPage();
_page = StarkSettings->getIntSetting(Settings::kSaveLoadPage);
if (_page > _maxPage) {
_page = _maxPage;
}
_widgets.push_back(new StaticLocationWidget(
"loadsavebg",
nullptr,
nullptr));
_widgets.push_back(new StaticLocationWidget(
"back to index",
CLICK_HANDLER(SaveLoadMenuScreen, backHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"Cancel",
CLICK_HANDLER(SaveLoadMenuScreen, backHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
_widgets.push_back(new StaticLocationWidget(
"SaveText",
nullptr,
nullptr));
_widgets.push_back(new StaticLocationWidget(
"LoadText",
nullptr,
nullptr));
_widgets.push_back(new StaticLocationWidget(
"Back",
CLICK_HANDLER(SaveLoadMenuScreen, prevPageHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
_widgets.back()->setTextColor(Gfx::Color(0, 0, 0));
_widgets.back()->setVisible(_page > 0);
_widgets.push_back(new StaticLocationWidget(
"Next",
CLICK_HANDLER(SaveLoadMenuScreen, nextPageHandler),
nullptr));
_widgets.back()->setupSounds(0, 1);
_widgets.back()->setTextColor(Gfx::Color(0, 0, 0));
_widgets.back()->setVisible(_page < _maxPage);
loadSaveData(_page);
}
void SaveLoadMenuScreen::close() {
ConfMan.flushToDisk();
StaticLocationScreen::close();
}
int SaveLoadMenuScreen::computeMaxPage() {
const char *target = ConfMan.getActiveDomainName().c_str();
int maxSlot = 0;
Common::StringArray saves = StarkEngine::listSaveNames(target);
for (Common::StringArray::const_iterator filename = saves.begin(); filename != saves.end(); filename++) {
int slot = StarkEngine::getSaveNameSlot(target, *filename);
if (slot > maxSlot) {
maxSlot = slot;
}
}
// Allow using one more page than the last page with saves
int maxPage = CLIP((maxSlot / _slotPerPage) + 1, 0, 110);
if (maxPage < 10) {
maxPage = 10;
}
return maxPage;
}
void SaveLoadMenuScreen::backHandler() {
StarkUserInterface->backPrevScreen();
}
void SaveLoadMenuScreen::checkError(Common::Error error) {
if (error.getCode() != Common::kNoError) {
GUI::MessageDialog dialog(error.getDesc());
dialog.runModal();
}
}
void SaveLoadMenuScreen::removeSaveDataWidgets() {
assert(_widgets.size() == 7 + _slotPerPage);
for (int i = 0; i < _slotPerPage; ++i) {
delete _widgets.back();
_widgets.pop_back();
}
}
void SaveLoadMenuScreen::loadSaveData(int page) {
for (int i = 0; i < _slotPerPage; ++i) {
_widgets.push_back(new SaveDataWidget(i + page * _slotPerPage, _gfx, this));
}
}
void SaveLoadMenuScreen::changePage(int page) {
assert(page >= 0 && page <= _maxPage);
removeSaveDataWidgets();
loadSaveData(page);
_widgets[kWidgetBack]->setVisible(page > 0);
_widgets[kWidgetNext]->setVisible(page < _maxPage);
StarkSettings->setIntSetting(Settings::kSaveLoadPage, page);
_page = page;
}
void SaveMenuScreen::open() {
SaveLoadMenuScreen::open();
_widgets[kWidgetLoadText]->setVisible(false);
}
void SaveMenuScreen::onWidgetSelected(SaveDataWidget *widget) {
if (widget->hasSave()) {
_slotToSaveAfterConfirm = widget;
Common::String format = StarkGameMessage->getTextByKey(GameMessage::kOverwriteSave);
Common::String prompt = Common::String::format(format.c_str(), widget->getName().c_str());
StarkUserInterface->confirm(prompt, this, &SaveMenuScreen::saveConfirmSlot);
} else {
saveGameToSlot(widget);
}
}
void SaveMenuScreen::saveConfirmSlot() {
assert(_slotToSaveAfterConfirm);
saveGameToSlot(_slotToSaveAfterConfirm);
_slotToSaveAfterConfirm = nullptr;
}
void SaveMenuScreen::saveGameToSlot(SaveDataWidget *widget) {
checkError(g_engine->saveGameState(widget->getSlot(), StarkGameChapter->getCurrentChapterTitle()));
// Freeze the screen for a while to let the user notice the change
widget->loadSaveDataElements();
render();
StarkGfx->flipBuffer();
g_system->delayMillis(100);
render();
StarkGfx->flipBuffer();
StarkUserInterface->backPrevScreen();
}
void LoadMenuScreen::open() {
SaveLoadMenuScreen::open();
_widgets[kWidgetSaveText]->setVisible(false);
}
void LoadMenuScreen::onWidgetSelected(SaveDataWidget *widget) {
if (!StarkGlobal->getCurrent()) {
checkError(g_engine->loadGameState(widget->getSlot()));
} else {
_slotToLoadAfterConfirm = widget->getSlot();
StarkUserInterface->confirm(GameMessage::kEndAndLoad, this, &LoadMenuScreen::loadConfirmSlot);
}
}
void LoadMenuScreen::loadConfirmSlot() {
assert(_slotToLoadAfterConfirm >= 0);
checkError(g_engine->loadGameState(_slotToLoadAfterConfirm));
_slotToLoadAfterConfirm = -1;
}
SaveDataWidget::SaveDataWidget(int slot, Gfx::Driver *gfx, SaveLoadMenuScreen *screen) :
StaticLocationWidget(nullptr, nullptr, nullptr),
_slot(slot),
_screen(screen),
_thumbWidth(kThumbnailWidth),
_thumbHeight(kThumbnailHeight),
_bitmap(gfx->createBitmap()),
_outline(gfx->createBitmap()),
_surfaceRenderer(gfx->createSurfaceRenderer()),
_textDesc(gfx),
_textTime(gfx),
_isMouseHovered(false),
_hasSave(false),
_name() {
// Load from the save data
loadSaveDataElements();
_textDesc.setColor(_textColor);
_textDesc.setFont(FontProvider::kCustomFont, 3);
_textTime.setColor(_textColor);
_textTime.setFont(FontProvider::kCustomFont, 3);
Graphics::PixelFormat pixelFormat = Gfx::Driver::getRGBAPixelFormat();
uint32 outlineColor = pixelFormat.ARGBToColor(
_outlineColor.a, _outlineColor.r, _outlineColor.g, _outlineColor.b
);
// Create the outline bitmap
Graphics::Surface lineSurface;
lineSurface.create(_thumbWidth, _thumbHeight, pixelFormat);
lineSurface.drawThickLine(0, 0, _thumbWidth - 1, 0, 2, 2, outlineColor);
lineSurface.drawThickLine(0, 0, 0, _thumbHeight - 1, 2, 2, outlineColor);
lineSurface.drawThickLine(_thumbWidth - 2, 0, _thumbWidth - 2, _thumbHeight - 2, 2, 2, outlineColor);
lineSurface.drawThickLine(0, _thumbHeight - 2, _thumbWidth - 2, _thumbHeight - 2, 2, 2, outlineColor);
_outline->update(&lineSurface);
lineSurface.free();
// Set the position
_thumbPos.x = 41 + (_slot % SaveLoadMenuScreen::_slotPerRow) * (_thumbWidth + 39);
_thumbPos.y = 61 + (_slot % SaveLoadMenuScreen::_slotPerPage / SaveLoadMenuScreen::_slotPerColumn) * (_thumbHeight + 38);
_textDescPos.x = _thumbPos.x;
_textDescPos.y = _thumbPos.y + _thumbHeight + 2;
_textTimePos.x = _thumbPos.x;
_textTimePos.y = _textDescPos.y + 12;
}
SaveDataWidget::~SaveDataWidget() {
delete _bitmap;
delete _outline;
delete _surfaceRenderer;
}
void SaveDataWidget::render() {
_surfaceRenderer->render(_bitmap, _thumbPos);
_textDesc.render(_textDescPos);
_textTime.render(_textTimePos);
if (_isMouseHovered) {
_surfaceRenderer->render(_outline, _thumbPos);
}
}
bool SaveDataWidget::isMouseInside(const Common::Point &mousePos) const {
return mousePos.x >= _thumbPos.x && mousePos.x <= _thumbPos.x + _thumbWidth &&
mousePos.y >= _thumbPos.y && mousePos.y <= _thumbPos.y + _thumbHeight;
}
void SaveDataWidget::onClick() {
StaticLocationWidget::onClick();
_screen->onWidgetSelected(this);
}
void SaveDataWidget::onMouseMove(const Common::Point &mousePos) {
StaticLocationWidget::onMouseMove(mousePos);
_isMouseHovered = isMouseInside(mousePos);
}
void SaveDataWidget::onScreenChanged() {
StaticLocationWidget::onScreenChanged();
_textDesc.reset();
_textTime.reset();
}
void SaveDataWidget::loadSaveDataElements() {
Common::String filename = StarkEngine::formatSaveName(ConfMan.getActiveDomainName().c_str(), _slot);
Common::InSaveFile *save = g_system->getSavefileManager()->openForLoading(filename);
if (save) {
_hasSave = true;
SaveMetadata metadata;
StateReadStream stream(save);
Common::ErrorCode metadataErrorCode = metadata.read(&stream, filename);
if (metadataErrorCode != Common::kNoError) {
error("Unable to read save metadata with error code %d.", metadataErrorCode);
}
// Obtain the thumbnail
if (metadata.version >= 9) {
Graphics::Surface *thumb = metadata.readGameScreenThumbnail(&stream);
_bitmap->update(thumb);
_bitmap->setSamplingFilter(StarkSettings->getImageSamplingFilter());
thumb->free();
delete thumb;
}
// Obtain the text
Common::String desc = metadata.description;
Common::String time = Common::String::format("%02d:%02d:%02d %02d/%02d/%02d",
metadata.saveHour, metadata.saveMinute, metadata.saveSecond,
metadata.saveMonth, metadata.saveDay, metadata.saveYear % 100);
_textDesc.setText(desc);
_textTime.setText(time);
_name = desc + " " + time;
} else {
_hasSave = false;
setVisible(_screen->isSaveMenu());
}
}
} // End of namespace Stark

View File

@@ -0,0 +1,182 @@
/* 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_UI_MENU_SAVELOAD_MENU_H
#define STARK_UI_MENU_SAVELOAD_MENU_H
#include "engines/stark/ui/menu/locationscreen.h"
#include "engines/stark/visual/text.h"
#include "common/error.h"
namespace Stark {
namespace Gfx {
class Bitmap;
class SurfaceRenderer;
}
class SaveDataWidget;
/**
* The base class of the save and load menu of the game
*/
class SaveLoadMenuScreen : public StaticLocationScreen {
public:
static const int _slotPerRow = 3;
static const int _slotPerColumn = 3;
static const int _slotPerPage = 9;
SaveLoadMenuScreen(Gfx::Driver *gfx, Cursor *cursor, Screen::Name screenName);
virtual ~SaveLoadMenuScreen();
// StaticLocationScreen API
void open() override;
void close() override;
/** Called when a SaveDataWidget is selected */
virtual void onWidgetSelected(SaveDataWidget *widget) = 0;
/** Check whether the menu is used for saving */
virtual bool isSaveMenu() = 0;
protected:
static void checkError(Common::Error error);
enum WidgetIndex {
kWidgetSaveText = 3,
kWidgetLoadText = 4,
kWidgetBack = 5,
kWidgetNext = 6
};
private:
// Start from zero
int _page;
int _maxPage;
void backHandler();
void prevPageHandler() { changePage(_page - 1); }
void nextPageHandler() { changePage(_page + 1); }
void removeSaveDataWidgets();
void loadSaveData(int page);
void changePage(int page);
int computeMaxPage();
};
/**
* The save menu of the game
*/
class SaveMenuScreen : public SaveLoadMenuScreen {
public:
SaveMenuScreen(Gfx::Driver *gfx, Cursor *cursor) :
SaveLoadMenuScreen(gfx, cursor, Screen::kScreenSaveMenu),
_slotToSaveAfterConfirm(nullptr) {}
virtual ~SaveMenuScreen() {}
// SaveLoadMenuScreen API
void open() override;
void onWidgetSelected(SaveDataWidget *widget) override;
bool isSaveMenu() override { return true; }
private:
void saveGameToSlot(SaveDataWidget *widget);
void saveConfirmSlot();
SaveDataWidget *_slotToSaveAfterConfirm;
};
/**
* The load menu of the game
*/
class LoadMenuScreen : public SaveLoadMenuScreen {
public:
LoadMenuScreen(Gfx::Driver *gfx, Cursor *cursor) :
SaveLoadMenuScreen(gfx, cursor, Screen::kScreenLoadMenu),
_slotToLoadAfterConfirm(-1) {}
~LoadMenuScreen() override {}
// SaveLoadMenuScreen API
void open() override;
void onWidgetSelected(SaveDataWidget *widget) override;
bool isSaveMenu() override { return false; }
private:
void loadConfirmSlot();
int _slotToLoadAfterConfirm;
};
/**
* The widget of save data
*/
class SaveDataWidget : public StaticLocationWidget {
public:
SaveDataWidget(int slot, Gfx::Driver *gfx, SaveLoadMenuScreen *screen);
~SaveDataWidget();
// StaticLocationWidget API
void render() override;
bool isMouseInside(const Common::Point &mousePos) const override;
void onClick() override;
void onMouseMove(const Common::Point &mousePos) override;
void onScreenChanged() override;
int getSlot() { return _slot; }
Common::String getName() { return _name; }
/** Load the thumbnail and info from the save data */
void loadSaveDataElements();
/** Check whether the save slot has data */
bool hasSave() { return _hasSave; }
private:
const Gfx::Color _outlineColor = Gfx::Color(0x1E, 0x1E, 0x96);
const Gfx::Color _textColor = Gfx::Color(0x5C, 0x48, 0x3D);
int _slot;
SaveLoadMenuScreen *_screen;
Common::Point _thumbPos, _textDescPos, _textTimePos;
int _thumbWidth, _thumbHeight;
Gfx::Bitmap *_bitmap;
Gfx::Bitmap *_outline;
Gfx::SurfaceRenderer *_surfaceRenderer;
VisualText _textDesc, _textTime;
bool _isMouseHovered;
bool _hasSave;
Common::String _name;
};
} // End of namespace Stark
#endif // STARK_UI_MENU_SETTING_MENU_H

View File

@@ -0,0 +1,399 @@
/* 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/ui/menu/settingsmenu.h"
#include "engines/stark/ui/cursor.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/userinterface.h"
#include "engines/stark/services/staticprovider.h"
#include "engines/stark/visual/image.h"
#include "engines/stark/resources/sound.h"
namespace Stark {
SettingsMenuScreen::SettingsMenuScreen(Gfx::Driver *gfx, Cursor *cursor) :
StaticLocationScreen(gfx, cursor, "OptionLocation", Screen::kScreenSettingsMenu),
_soundManager() {
}
SettingsMenuScreen::~SettingsMenuScreen() {
}
void SettingsMenuScreen::open() {
StaticLocationScreen::open();
_soundManager.load();
_widgets.push_back(new StaticLocationWidget(
// This is the background image
"The Longest Journey",
nullptr,
nullptr));
_widgets.push_back(new StaticLocationWidget(
"Return",
CLICK_HANDLER(SettingsMenuScreen, backHandler),
nullptr));
_widgets.back()->setupSounds(3, 4);
_widgets.push_back(new StaticLocationWidget(
"Back",
CLICK_HANDLER(SettingsMenuScreen, backHandler),
nullptr));
_widgets.back()->setupSounds(3, 4);
_widgets.push_back(new StaticLocationWidget(
"GSettings",
nullptr,
nullptr));
_widgets.push_back(new CheckboxWidget(
"AprilHighRes",
StarkSettings->getBoolSetting(Settings::kHighModel),
CLICK_HANDLER(SettingsMenuScreen, flipSettingHandler<Settings::kHighModel>),
MOVE_HANDLER(SettingsMenuScreen, textHandler<kHighRes>)));
_widgets.back()->setupSounds(3, 4);
_widgets.push_back(new StaticLocationWidget(
"HighResHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new CheckboxWidget(
"Subtitles",
StarkSettings->getBoolSetting(Settings::kSubtitle),
CLICK_HANDLER(SettingsMenuScreen, flipSettingHandler<Settings::kSubtitle>),
MOVE_HANDLER(SettingsMenuScreen, textHandler<kSubtitles>)));
_widgets.back()->setupSounds(3, 4);
_widgets.push_back(new StaticLocationWidget(
"SubtitleHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new CheckboxWidget(
"SpecialFX",
StarkSettings->getBoolSetting(Settings::kSpecialFX),
CLICK_HANDLER(SettingsMenuScreen, flipSettingHandler<Settings::kSpecialFX>),
MOVE_HANDLER(SettingsMenuScreen, textHandler<kSpecialFX>)));
_widgets.back()->setupSounds(3, 4);
_widgets.push_back(new StaticLocationWidget(
"SpecialFXHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new CheckboxWidget(
"Shadows",
StarkSettings->getBoolSetting(Settings::kShadow),
CLICK_HANDLER(SettingsMenuScreen, flipSettingHandler<Settings::kShadow>),
MOVE_HANDLER(SettingsMenuScreen, textHandler<kShadows>)));
_widgets.back()->setupSounds(3, 4);
_widgets.push_back(new StaticLocationWidget(
"ShadowsHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new CheckboxWidget(
"HighResFMV",
StarkSettings->getBoolSetting(Settings::kHighFMV),
CLICK_HANDLER(SettingsMenuScreen, flipSettingHandler<Settings::kHighFMV>),
MOVE_HANDLER(SettingsMenuScreen, textHandler<kHighResFMV>)));
_widgets.back()->setupSounds(3, 4);
_widgets.back()->setVisible(StarkSettings->hasLowResFMV());
_widgets.push_back(new StaticLocationWidget(
"FMVHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new StaticLocationWidget(
"VSettings",
nullptr,
nullptr));
_widgets.push_back(new VolumeWidget(
"Voice",
_cursor,
_soundManager, 0,
Settings::kVoice,
MOVE_HANDLER(SettingsMenuScreen, textHandler<kVoice>)));
_widgets.push_back(new StaticLocationWidget(
"VoiceHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new VolumeWidget(
"Music",
_cursor,
_soundManager, 2,
Settings::kMusic,
MOVE_HANDLER(SettingsMenuScreen, textHandler<kMusic>)));
_widgets.push_back(new StaticLocationWidget(
"MusicHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new VolumeWidget(
"Sfx",
_cursor,
_soundManager, 1,
Settings::kSfx,
MOVE_HANDLER(SettingsMenuScreen, textHandler<kSfx>)));
_widgets.push_back(new StaticLocationWidget(
"SfxHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
_widgets.push_back(new CheckboxWidget(
"AllowFF",
StarkSettings->getBoolSetting(Settings::kTimeSkip),
CLICK_HANDLER(SettingsMenuScreen, flipSettingHandler<Settings::kTimeSkip>),
MOVE_HANDLER(SettingsMenuScreen, textHandler<kAllowFF>)));
_widgets.back()->setupSounds(3, 4);
_widgets.push_back(new StaticLocationWidget(
"AllowFFHelp",
nullptr,
nullptr));
_widgets.back()->setVisible(false);
}
void SettingsMenuScreen::close() {
_soundManager.close();
ConfMan.flushToDisk();
StaticLocationScreen::close();
}
void SettingsMenuScreen::onGameLoop() {
_soundManager.update();
}
void SettingsMenuScreen::handleMouseUp() {
if (!_widgets.empty()) {
_soundManager.endLoop();
_widgets[kWidgetVoice]->onMouseUp();
_widgets[kWidgetMusic]->onMouseUp();
_widgets[kWidgetSfx]->onMouseUp();
}
}
template<SettingsMenuScreen::HelpTextIndex N>
void SettingsMenuScreen::textHandler(StaticLocationWidget &widget, const Common::Point &mousePos) {
if (widget.isVisible()) {
if (widget.isMouseInside(mousePos)) {
widget.setTextColor(_textColorHovered);
_widgets[N]->setVisible(true);
} else {
widget.setTextColor(_textColorDefault);
_widgets[N]->setVisible(false);
}
}
}
template<Settings::BoolSettingIndex N>
void SettingsMenuScreen::flipSettingHandler() {
StarkSettings->flipSetting(N);
}
void SettingsMenuScreen::backHandler() {
StarkUserInterface->backPrevScreen();
}
CheckboxWidget::CheckboxWidget(const char *renderEntryName, bool isChecked,
WidgetOnClickCallback *onClickCallback,
WidgetOnMouseMoveCallback *onMouseMoveCallback) :
StaticLocationWidget(renderEntryName, onClickCallback, onMouseMoveCallback),
_isChecked(isChecked) {
// Load images
_checkBoxImage[0] = StarkStaticProvider->getUIElement(StaticProvider::kCheckMark, 0);
_checkBoxImage[1] = StarkStaticProvider->getUIElement(StaticProvider::kCheckMark, 1);
_checkboxWidth = _checkBoxImage[0]->getWidth();
_checkboxHeight = _checkBoxImage[0]->getHeight();
_currentImage = _checkBoxImage[_isChecked];
// Set positions
Common::Point textPosition = getPosition();
_position.x = textPosition.x - _checkboxWidth - 8;
_position.y = textPosition.y - 4;
}
void CheckboxWidget::render() {
StaticLocationWidget::render();
_currentImage->render(_position, true);
}
bool CheckboxWidget::isMouseInside(const Common::Point &mousePos) const {
return StaticLocationWidget::isMouseInside(mousePos) || isMouseInsideCheckbox(mousePos);
}
void CheckboxWidget::onClick() {
StaticLocationWidget::onClick();
_isChecked = !_isChecked;
_currentImage = _checkBoxImage[_isChecked];
}
bool CheckboxWidget::isMouseInsideCheckbox(const Common::Point &mousePos) const {
return mousePos.x >= _position.x && mousePos.x <= _position.x + _checkboxWidth &&
mousePos.y >= _position.y && mousePos.y <= _position.y + _checkboxHeight;
}
VolumeWidget::VolumeWidget(const char *renderEntryName, Cursor *cursor,
TestSoundManager &soundManager, int soundIndex,
Settings::IntSettingIndex settingIndex,
WidgetOnMouseMoveCallback *onMouseMoveCallback) :
StaticLocationWidget(renderEntryName, nullptr, onMouseMoveCallback),
_cursor(cursor),
_soundManager(soundManager),
_soundIndex(soundIndex),
_settingIndex(settingIndex),
_isDragged(false) {
// Load images
_sliderImage = StarkStaticProvider->getUIElement(StaticProvider::kVolume, 0);
_bgImage = StarkStaticProvider->getUIElement(StaticProvider::kVolume, 1);
_bgWidth = _bgImage->getWidth();
_bgHeight = _bgImage->getHeight();
_sliderWidth = _sliderImage->getWidth();
// Set positions
_bgPosition.x = 313;
_bgPosition.y = 303 + _settingIndex * 51;
_sliderPosition.y = _bgPosition.y;
_minX = _bgPosition.x;
_maxX = _bgPosition.x + _bgWidth - _sliderWidth;
}
void VolumeWidget::render() {
StaticLocationWidget::render();
_sliderPosition.x = volumeToX(StarkSettings->getIntSetting(_settingIndex));
_sliderImage->render(_sliderPosition, false);
_bgImage->render(_bgPosition, false);
}
bool VolumeWidget::isMouseInside(const Common::Point &mousePos) const {
return StaticLocationWidget::isMouseInside(mousePos) || isMouseInsideBg(mousePos);
}
void VolumeWidget::onClick() {
if (isMouseInsideBg(_cursor->getMousePosition())) {
_isDragged = true;
_soundManager.play(_soundIndex);
}
}
void VolumeWidget::onMouseMove(const Common::Point &mousePos) {
if (isMouseInsideBg(mousePos)) {
setTextColor(_textColorBgHovered);
} else {
StaticLocationWidget::onMouseMove(mousePos);
}
if (_isDragged) {
int posX = mousePos.x - _sliderWidth / 2;
if (posX < _minX) {
posX = _minX;
}
if (posX > _maxX) {
posX = _maxX;
}
StarkSettings->setIntSetting(_settingIndex, xToVolume(posX));
}
}
void VolumeWidget::onMouseUp() {
_isDragged = false;
}
bool VolumeWidget::isMouseInsideBg(const Common::Point &mousePos) const {
return mousePos.x >= _bgPosition.x && mousePos.x <= _bgPosition.x + _bgWidth &&
mousePos.y >= _bgPosition.y && mousePos.y <= _bgPosition.y + _bgHeight;
}
TestSoundManager::TestSoundManager() :
_currentSound(nullptr),
_isLopping(false) {
for (int i = 0; i < 3; ++i) {
_sounds[i] = nullptr;
}
}
void TestSoundManager::load() {
for (int i = 0; i < 3; ++i) {
_sounds[i] = StarkStaticProvider->getLocationSound(i);
_sounds[i]->setLooping(false);
}
}
void TestSoundManager::close() {
stop();
for (int i = 0; i < 3; ++i) {
_sounds[i] = nullptr;
}
}
void TestSoundManager::play(int index) {
stop();
_currentSound = _sounds[index];
if (_currentSound) {
_currentSound->play();
_isLopping = true;
}
}
void TestSoundManager::endLoop() {
_isLopping = false;
}
void TestSoundManager::stop() {
if (_currentSound) {
_currentSound->stop();
_currentSound = nullptr;
}
_isLopping = false;
}
void TestSoundManager::update() {
if (_currentSound && !_currentSound->isPlaying()) {
if (_isLopping) {
_currentSound->play();
} else {
_currentSound->stop();
_currentSound = nullptr;
}
}
}
} // End of namespace Stark

View File

@@ -0,0 +1,188 @@
/* 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_UI_MENU_SETTINGS_MENU_H
#define STARK_UI_MENU_SETTINGS_MENU_H
#include "engines/stark/ui/menu/locationscreen.h"
#include "engines/stark/services/services.h"
#include "engines/stark/services/settings.h"
namespace Stark {
class VisualImageXMG;
/**
* Manager of test sound
*/
class TestSoundManager {
public:
TestSoundManager();
~TestSoundManager() {}
/** Load sounds **/
void load();
/** Close the sound manager and reset pointers **/
void close();
/** play a specific sound in a loop */
void play(int index);
/** request to end the playing loop */
void endLoop();
/** stop any currently playing sound */
void stop();
/** update on game frame */
void update();
private:
Resources::Sound *_currentSound;
Resources::Sound *_sounds[3];
bool _isLopping;
};
/**
* The setting menu of the game
*/
class SettingsMenuScreen : public StaticLocationScreen {
public:
SettingsMenuScreen(Gfx::Driver *gfx, Cursor *cursor);
virtual ~SettingsMenuScreen();
// StaticLocationScreen API
void open() override;
void close() override;
void onGameLoop() override;
void handleMouseUp();
private:
enum HelpTextIndex {
kHighRes = 5,
kSubtitles = 7,
kSpecialFX = 9,
kShadows = 11,
kHighResFMV = 13,
kVoice = 16,
kMusic = 18,
kSfx = 20,
kAllowFF = 22
};
enum WidgetIndex {
kWidgetVoice = 15,
kWidgetMusic = 17,
kWidgetSfx = 19
};
template<HelpTextIndex N>
void textHandler(StaticLocationWidget &widget, const Common::Point &mousePos);
template<Settings::BoolSettingIndex N>
void flipSettingHandler();
void backHandler();
private:
const Gfx::Color _textColorHovered = Gfx::Color(0x1E, 0x1E, 0x96);
const Gfx::Color _textColorDefault = Gfx::Color(0x00, 0x00, 0x00);
TestSoundManager _soundManager;
};
/**
* Widget with a checkbox
*/
class CheckboxWidget : public StaticLocationWidget {
public:
CheckboxWidget(const char *renderEntryName, bool isChecked,
WidgetOnClickCallback *onClickCallback,
WidgetOnMouseMoveCallback *onMouseMoveCallback);
virtual ~CheckboxWidget() {};
// StaticLocationWidget API
void render() override;
bool isMouseInside(const Common::Point &mousePos) const override;
void onClick() override;
private:
VisualImageXMG *_currentImage;
VisualImageXMG *_checkBoxImage[2];
Common::Point _position;
int _checkboxWidth, _checkboxHeight;
bool _isChecked;
bool isMouseInsideCheckbox(const Common::Point &mousePos) const;
};
/**
* Widget with a dragged slider for twisting the volume
*/
class VolumeWidget : public StaticLocationWidget {
public:
VolumeWidget(const char *renderEntryName, Cursor *cursor,
TestSoundManager &soundManager, int soundIndex,
Settings::IntSettingIndex settingIndex,
WidgetOnMouseMoveCallback *onMouseMoveCallback);
virtual ~VolumeWidget() {};
// StaticLocationWidget API
void render() override;
bool isMouseInside(const Common::Point &mousePos) const override;
void onClick() override;
void onMouseMove(const Common::Point &mousePos) override;
void onMouseUp() override;
private:
const Gfx::Color _textColorBgHovered = Gfx::Color(0xFF, 0xFF, 0xFF);
static const int _maxVolume = 256;
VisualImageXMG *_sliderImage;
VisualImageXMG *_bgImage;
Cursor *_cursor;
TestSoundManager &_soundManager;
const int _soundIndex;
Common::Point _sliderPosition, _bgPosition;
int _bgWidth, _bgHeight, _sliderWidth, _minX, _maxX;
bool _isDragged;
const Settings::IntSettingIndex _settingIndex;
bool isMouseInsideBg(const Common::Point &mousePos) const;
int volumeToX(int volume) {
return volume * (_maxX - _minX) / _maxVolume + _minX;
}
int xToVolume(int x) {
return (x - _minX) * _maxVolume / (_maxX - _minX);
}
};
} // End of namespace Stark
#endif // STARK_UI_MENU_SETTING_MENU_H