[Scummvm-git-logs] scummvm master -> b7829323038bdd90e7ecadf1cf52ba490afc3f7d
fracturehill
noreply at scummvm.org
Tue Nov 11 10:58:30 UTC 2025
This automated email contains information about 10 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
4afb30b272 NANCY: Add extra graphic state to Button
e5b2b5d84d NANCY: Implement save/load menu for nancy8 and up
0a1ab6cbe8 NANCY: Fix image loading in The Vampire Diaries
fa613690e6 NANCY: Use ScopedPtr in SetupMenu
b7b64dd4ab NANCY: Use ScopedPtr in SaveDialog
9f3140df4c NANCY: Use ScopedPtr in Map
a0809aa698 NANCY: Use ScopedPtr in MainMenu
7a85b93834 NANCY: Use ScopedPtr in Help
5078e6c1a9 NANCY: Use ScopedPtr in InventoryBox
b782932303 NANCY: Use ScopedPtr in SecondaryMovie
Commit: 4afb30b272f067c17346ee9bdb43cf5bfd32ce1e
https://github.com/scummvm/scummvm/commit/4afb30b272f067c17346ee9bdb43cf5bfd32ce1e
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2025-11-11T11:22:47+01:00
Commit Message:
NANCY: Add extra graphic state to Button
Adds a "base" graphic, used when the button is not being
interacted with. This was missing before, because in most
places, that graphic would just be baked into the background.
Changed paths:
engines/nancy/ui/button.cpp
engines/nancy/ui/button.h
diff --git a/engines/nancy/ui/button.cpp b/engines/nancy/ui/button.cpp
index 5b1e5af4b22..deb2a3c74c7 100644
--- a/engines/nancy/ui/button.cpp
+++ b/engines/nancy/ui/button.cpp
@@ -33,15 +33,28 @@
namespace Nancy {
namespace UI {
-Button::Button(uint16 zOrder, Graphics::ManagedSurface &surface, const Common::Rect &clickSrcBounds, const Common::Rect &destBounds, const Common::Rect &hoverSrcBounds, const Common::Rect &disabledSrcBounds) :
+Button::Button(uint16 zOrder,
+ Graphics::ManagedSurface &surface,
+ const Common::Rect &clickSrcBounds,
+ const Common::Rect &destBounds,
+ const Common::Rect &hoverSrcBounds,
+ const Common::Rect &disabledSrcBounds,
+ const Common::Rect &baseSrcBounds) :
RenderObject(zOrder, surface, clickSrcBounds, destBounds),
surf(surface),
_clickSrc(clickSrcBounds),
_hoverSrc(hoverSrcBounds),
_disabledSrc(disabledSrcBounds),
+ _baseSrc(baseSrcBounds),
_isClicked(false),
_isDisabled(false) {
- setVisible(false);
+ if (!_baseSrc.isEmpty()) {
+ _drawSurface.create(surf, _baseSrc);
+ setVisible(true);
+ } else {
+ setVisible(false);
+ }
+
setTransparent(true);
}
@@ -67,7 +80,12 @@ void Button::handleInput(NancyInput &input) {
}
}
} else if (!_isClicked && _isVisible) {
- setVisible(false);
+ if (!_baseSrc.isEmpty()) {
+ _drawSurface.create(surf, _baseSrc);
+ setVisible(true);
+ } else {
+ setVisible(false);
+ }
}
}
@@ -78,10 +96,20 @@ void Button::setDisabled(bool disabled) {
_drawSurface.create(surf, _disabledSrc);
setVisible(true);
} else {
- setVisible(false);
+ if (!_baseSrc.isEmpty()) {
+ _drawSurface.create(surf, _baseSrc);
+ setVisible(true);
+ } else {
+ setVisible(false);
+ }
}
} else {
- setVisible(false);
+ if (!_baseSrc.isEmpty()) {
+ _drawSurface.create(surf, _baseSrc);
+ setVisible(true);
+ } else {
+ setVisible(false);
+ }
_isDisabled = false;
}
}
diff --git a/engines/nancy/ui/button.h b/engines/nancy/ui/button.h
index eef9c464c73..d2d7fcf8ac4 100644
--- a/engines/nancy/ui/button.h
+++ b/engines/nancy/ui/button.h
@@ -36,7 +36,8 @@ public:
const Common::Rect &clickSrcBounds,
const Common::Rect &destBounds,
const Common::Rect &hoverSrcBounds = Common::Rect(),
- const Common::Rect &disabledSrcBounds = Common::Rect());
+ const Common::Rect &disabledSrcBounds = Common::Rect(),
+ const Common::Rect &baseSrcBounds = Common::Rect());
virtual ~Button() = default;
void handleInput(NancyInput &input);
@@ -47,6 +48,7 @@ public:
Common::Rect _clickSrc;
Common::Rect _hoverSrc;
Common::Rect _disabledSrc;
+ Common::Rect _baseSrc;
bool _isClicked;
bool _isDisabled;
Commit: e5b2b5d84d12202b5f4879a3726dbc1edf5c1104
https://github.com/scummvm/scummvm/commit/e5b2b5d84d12202b5f4879a3726dbc1edf5c1104
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2025-11-11T11:50:18+01:00
Commit Message:
NANCY: Implement save/load menu for nancy8 and up
The newer menu has support for infinite saves, with
multiple pages. Thus, the implementation has
to be in a separate class from the existing one, though
common code is mostly not duplicated.
As a drive-by, all owned pointers are made ScopedPtr.
Changed paths:
engines/nancy/detection.cpp
engines/nancy/enginedata.cpp
engines/nancy/enginedata.h
engines/nancy/nancy.cpp
engines/nancy/nancy.h
engines/nancy/state/loadsave.cpp
engines/nancy/state/loadsave.h
engines/nancy/state/scene.cpp
engines/nancy/ui/fullscreenimage.cpp
diff --git a/engines/nancy/detection.cpp b/engines/nancy/detection.cpp
index 50ead210a23..048bbaf496f 100644
--- a/engines/nancy/detection.cpp
+++ b/engines/nancy/detection.cpp
@@ -64,9 +64,7 @@ static const PlainGameDescriptor nancyGames[] = {
#define NANCY2_GUIOPTIONS GUIO5(GAMEOPTION_PLAYER_SPEECH, GAMEOPTION_CHARACTER_SPEECH, GAMEOPTION_FIX_SOFTLOCKS, GAMEOPTION_NANCY2_TIMER, GAMEOPTION_ORIGINAL_SAVELOAD)
#define NANCY5_GUIOPTIONS GUIO4(GAMEOPTION_PLAYER_SPEECH, GAMEOPTION_CHARACTER_SPEECH, GAMEOPTION_FIX_SOFTLOCKS, GAMEOPTION_ORIGINAL_SAVELOAD)
#define NANCY6_7_GUIOPTIONS GUIO3(GAMEOPTION_AUTO_MOVE, GAMEOPTION_FIX_SOFTLOCKS, GAMEOPTION_ORIGINAL_SAVELOAD)
-// TODO: Since the original save/load menus aren't implemented for
-// Nancy 8 and newer games, we always use the ScummVM ones there
-#define NANCY8_GUIOPTIONS GUIO1(GAMEOPTION_AUTO_MOVE)
+#define NANCY8_GUIOPTIONS GUIO2(GAMEOPTION_AUTO_MOVE, GAMEOPTION_ORIGINAL_SAVELOAD)
static const Nancy::NancyGameDescription gameDescriptions[] = {
diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index 8aa89b4420c..4cad392d97e 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -516,7 +516,8 @@ LOAD::LOAD(Common::SeekableReadStream *chunkStream) :
readRectArray(*chunkStream, _disabledButtonSrcs, 5);
readRectArray(*chunkStream, _buttonDests, 5);
- readRectArray(*chunkStream, _textboxBounds, 10);
+ readRectArray(*chunkStream, _textboxBounds, 9);
+ readRect(*chunkStream, _inputTextboxBounds);
chunkStream->skip(25); // prefixes and suffixes for filenames
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index cc6bfcc733f..f88540b8064 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -275,6 +275,7 @@ struct LOAD : public EngineData {
Common::Array<Common::Rect> _saveButtonDests;
Common::Array<Common::Rect> _loadButtonDests;
Common::Array<Common::Rect> _textboxBounds;
+ Common::Rect _inputTextboxBounds;
Common::Rect _doneButtonDest;
Common::Array<Common::Rect> _saveButtonDownSrcs;
Common::Array<Common::Rect> _loadButtonDownSrcs;
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 43de27d0df1..f4ab8e2f4e7 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -108,6 +108,16 @@ NancyEngine *NancyEngine::create(GameType type, OSystem *syst, const NancyGameDe
error("Unknown GameType");
}
+Common::Error NancyEngine::loadGameState(int slot) {
+ auto save = g_nancy->getMetaEngine()->querySaveMetaInfos(ConfMan.getActiveDomainName().c_str(), slot);
+ if (save.isValid() && save.getDescription() != "SECOND CHANCE") {
+ // Ensure the nancy8+ save screen will display the last non-autosave name
+ ConfMan.setInt("display_slot", slot, Common::ConfigManager::kTransientDomain);
+ }
+
+ return Engine::loadGameState(slot);
+}
+
Common::Error NancyEngine::loadGameStream(Common::SeekableReadStream *stream) {
Common::Serializer ser(stream, nullptr);
return synchronize(ser);
@@ -262,12 +272,6 @@ Common::Error NancyEngine::run() {
}
}
- // TODO: Since the original save/load menus aren't implemented for
- // Nancy 8 and newer games, we always use the ScummVM ones there
- if (getGameType() >= kGameTypeNancy8) {
- ConfMan.setBool("originalsaveload", false, ConfMan.getActiveDomainName());
- }
-
if (!ConfMan.getBool("originalsaveload")) {
ConfMan.setInt("nancy_max_saves", 999, ConfMan.getActiveDomainName());
}
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index 7f21c5c5406..5dd080cf913 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -83,6 +83,7 @@ public:
void errorString(const char *buf_input, char *buf_output, int buf_output_size) override;
bool hasFeature(EngineFeature f) const override;
+ Common::Error loadGameState(int slot) override;
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
diff --git a/engines/nancy/state/loadsave.cpp b/engines/nancy/state/loadsave.cpp
index 3556b5e2002..cd68299e3b9 100644
--- a/engines/nancy/state/loadsave.cpp
+++ b/engines/nancy/state/loadsave.cpp
@@ -39,31 +39,22 @@
namespace Common {
DECLARE_SINGLETON(Nancy::State::LoadSaveMenu);
+
+template<>
+Nancy::State::LoadSaveMenu *Singleton<Nancy::State::LoadSaveMenu>::makeInstance() {
+ if (Nancy::g_nancy->getGameType() <= Nancy::kGameTypeNancy7) {
+ return new Nancy::State::LoadSaveMenu_V1();
+ } else {
+ return new Nancy::State::LoadSaveMenu_V2();
+ }
+}
+
}
namespace Nancy {
namespace State {
LoadSaveMenu::~LoadSaveMenu() {
- for (auto *tb : _textboxes) {
- delete tb;
- }
-
- for (auto *button : _loadButtons) {
- delete button;
- }
-
- for (auto *button : _saveButtons) {
- delete button;
- }
-
- for (auto *overlay : _cancelButtonOverlays) {
- delete overlay;
- }
-
- delete _exitButton;
- delete _cancelButton;
-
g_nancy->_input->setVKEnabled(false);
}
@@ -103,6 +94,44 @@ void LoadSaveMenu::process() {
g_nancy->_cursor->setCursorType(CursorManager::kNormalArrow);
}
+void LoadSaveMenu::onStateEnter(const NancyState::NancyState prevState) {
+ if (!ConfMan.getBool("originalsaveload")) {
+ bool saveAndQuit = false;
+ if (ConfMan.hasKey("sdlg_save_and_quit", Common::ConfigManager::kTransientDomain)) {
+ saveAndQuit = ConfMan.getBool("sdlg_save_and_quit", Common::ConfigManager::kTransientDomain);
+ ConfMan.removeKey("sdlg_save_and_quit", Common::ConfigManager::kTransientDomain);
+ }
+
+ // Display the question dialog if we are in a scene, and if we are not
+ // in the middle of quitting the game, and a save has been requested
+ if (Nancy::State::Scene::hasInstance() && !saveAndQuit) {
+ GUI::MessageDialog saveOrLoad(_("Would you like to load or save a game?"), _("Load"), _("Save"));
+
+ int choice = saveOrLoad.runModal();
+ if (choice == GUI::kMessageOK)
+ scummVMLoad();
+ else
+ scummVMSave();
+ } else if (saveAndQuit) {
+ scummVMSave();
+ } else {
+ scummVMLoad();
+ }
+
+ return;
+ }
+
+ if (_state == kEnterFilename) {
+ g_nancy->_input->setVKEnabled(true);
+ }
+ registerGraphics();
+}
+
+bool LoadSaveMenu::onStateExit(const NancyState::NancyState nextState) {
+ g_nancy->_input->setVKEnabled(false);
+ return _destroyOnExit;
+}
+
void LoadSaveMenu::scummVMSave() {
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
int slot = dialog->runModalWithCurrentTarget();
@@ -140,67 +169,143 @@ void LoadSaveMenu::scummVMLoad() {
}
}
-void LoadSaveMenu::onStateEnter(const NancyState::NancyState prevState) {
- if (!ConfMan.getBool("originalsaveload")) {
- bool saveAndQuit = false;
- if (ConfMan.hasKey("sdlg_save_and_quit", Common::ConfigManager::kTransientDomain)) {
- saveAndQuit = ConfMan.getBool("sdlg_save_and_quit", Common::ConfigManager::kTransientDomain);
- ConfMan.removeKey("sdlg_save_and_quit", Common::ConfigManager::kTransientDomain);
+void LoadSaveMenu::enterFilename() {
+ // Handle keyboard input and cursor blinking
+ uint32 gameTime = g_nancy->getTotalPlayTime();
+ if (_loadSaveData->_blinkingTimeDelay != 0 && gameTime > _nextBlink) {
+ _blinkingCursorOverlay.setVisible(!_blinkingCursorOverlay.isVisible());
+ _nextBlink = gameTime + _loadSaveData->_blinkingTimeDelay;
+ }
+
+ NancyInput input = g_nancy->_input->getInput();
+
+ for (uint i = 0; i < input.otherKbdInput.size(); ++i) {
+ Common::KeyState &key = input.otherKbdInput[i];
+ if (key.keycode == Common::KEYCODE_BACKSPACE) {
+ if (_enteredString.size()) {
+ _enteredString.deleteLastChar();
+ }
+ } else if (Common::isAlnum(key.ascii) || Common::isSpace(key.ascii)) {
+ _enteredString += key.ascii;
}
+ }
- // Display the question dialog if we are in a scene, and if we are not
- // in the middle of quitting the game, and a save has been requested
- if (Nancy::State::Scene::hasInstance() && !saveAndQuit) {
- GUI::MessageDialog saveOrLoad(_("Would you like to load or save a game?"), _("Load"), _("Save"));
+ if (_exitButton && !_exitButton->_isDisabled) {
+ _exitButton->handleInput(input);
+ if (_exitButton->_isClicked) {
+ _state = kStop;
+ g_nancy->_sound->playSound("BUOK");
+ g_nancy->_input->setVKEnabled(false);
+ return;
+ }
+ }
+}
- int choice = saveOrLoad.runModal();
- if (choice == GUI::kMessageOK)
- scummVMLoad();
- else
- scummVMSave();
- } else if (saveAndQuit) {
- scummVMSave();
+void LoadSaveMenu::load() {
+ auto *sdlg = GetEngineData(SDLG);
+
+ if (sdlg && sdlg->dialogs.size() > 1 && Nancy::State::Scene::hasInstance() && !g_nancy->_hasJustSaved) {
+ // nancy6 added a "Do you want load without saving" dialog.
+ if (!ConfMan.hasKey("sdlg_return", Common::ConfigManager::kTransientDomain)) {
+ // Request the dialog
+ ConfMan.setInt("sdlg_id", 2, Common::ConfigManager::kTransientDomain);
+ _destroyOnExit = false;
+ g_nancy->setState(NancyState::kSaveDialog);
+ return;
} else {
- scummVMLoad();
+ // Dialog has returned
+ _destroyOnExit = true;
+ g_nancy->_graphics->suppressNextDraw();
+ uint ret = ConfMan.getInt("sdlg_return", Common::ConfigManager::kTransientDomain);
+ ConfMan.removeKey("sdlg_return", Common::ConfigManager::kTransientDomain);
+ switch (ret) {
+ case 1 :
+ // "No" keeps us in the LoadSave state but doesn't load
+ _state = kRun;
+ return;
+ case 2 :
+ // "Cancel" returns to the main menu
+ g_nancy->setState(NancyState::kMainMenu);
+ return;
+ default:
+ // "Yes" actually loads
+ break;
+ }
}
+ }
- return;
+ if (Nancy::State::Scene::hasInstance()) {
+ Nancy::State::Scene::destroy();
}
- if (_state == kEnterFilename) {
- g_nancy->_input->setVKEnabled(true);
+ ConfMan.setInt("save_slot", scummVMSaveSlotToLoad(), Common::ConfigManager::kTransientDomain);
+ ConfMan.setInt("display_slot", scummVMSaveSlotToLoad(), Common::ConfigManager::kTransientDomain); // Used to load the save name
+
+ _state = kStop;
+ _enteringNewState = true;
+}
+
+void LoadSaveMenu::success() {
+ if (_enteringNewState) {
+ _nextBlink = g_nancy->getTotalPlayTime() + 2000; // Hardcoded
+ _successOverlay.setVisible(true);
+ _enteringNewState = false;
+ }
+
+ if (g_nancy->getTotalPlayTime() > _nextBlink) {
+ _state = kStop;
+ _selectedSave = 0;
+
+ _enteringNewState = true;
}
- registerGraphics();
}
-bool LoadSaveMenu::onStateExit(const NancyState::NancyState nextState) {
- g_nancy->_input->setVKEnabled(false);
- return _destroyOnExit;
+void LoadSaveMenu::stop() {
+ if (_selectedSave != -1) {
+ g_nancy->setState(NancyState::kScene);
+ } else {
+ g_nancy->setState(NancyState::kMainMenu);
+ }
}
void LoadSaveMenu::registerGraphics() {
+ for (auto &tb : _textboxes) {
+ tb->registerGraphics();
+ }
+
+ if (_exitButton) {
+ _exitButton->registerGraphics();
+ }
+}
+
+uint16 LoadSaveMenu::writeToTextbox(int textboxID, const Common::String &text, const Font *font) {
+ assert(font);
+
+ _textboxes[textboxID]->_drawSurface.clear(g_nancy->_graphics->getTransColor());
+ Common::Point destPoint(_loadSaveData->_fontXOffset, _loadSaveData->_fontYOffset + _textboxes[textboxID]->_drawSurface.h - font->getFontHeight());
+ font->drawString(&_textboxes[textboxID]->_drawSurface, text, destPoint.x, destPoint.y, _textboxes[textboxID]->_drawSurface.w, 0);
+ _textboxes[textboxID]->setVisible(true);
+
+ return font->getStringWidth(text);
+}
+
+void LoadSaveMenu_V1::registerGraphics() {
+ LoadSaveMenu::registerGraphics();
+
_background.registerGraphics();
- for (auto *button : _loadButtons) {
+ for (auto &button : _loadButtons) {
button->registerGraphics();
}
- for (auto *button : _saveButtons) {
+ for (auto &button : _saveButtons) {
button->registerGraphics();
}
- for (auto *overlay : _cancelButtonOverlays) {
+ for (auto &overlay : _cancelButtonOverlays) {
overlay->registerGraphics();
}
- for (auto *tb : _textboxes) {
- tb->registerGraphics();
- }
-
- if (_exitButton) {
- _exitButton->registerGraphics();
- }
-
if (_cancelButton) {
_cancelButton->registerGraphics();
}
@@ -211,7 +316,7 @@ void LoadSaveMenu::registerGraphics() {
g_nancy->_graphics->redrawAll();
}
-void LoadSaveMenu::init() {
+void LoadSaveMenu_V1::init() {
_loadSaveData = GetEngineData(LOAD);
assert(_loadSaveData);
@@ -232,7 +337,7 @@ void LoadSaveMenu::init() {
for (uint i = 0; i < _textboxes.size(); ++i) {
// Load textbox objects
RenderObject *newTb = new RenderObject(5);
- _textboxes[i] = newTb;
+ _textboxes[i].reset(newTb);
const Common::Rect &bounds = _loadSaveData->_textboxBounds[i];
newTb->_drawSurface.create(bounds.width(), bounds.height(), g_nancy->_graphics->getScreenPixelFormat());
newTb->_drawSurface.clear(g_nancy->_graphics->getTransColor());
@@ -263,18 +368,18 @@ void LoadSaveMenu::init() {
_cancelButtonOverlays.resize(_textboxes.size());
for (uint i = 0; i < _loadButtons.size(); ++i) {
// Load Save and Load buttons, and Cancel overlays
- _loadButtons[i] = new UI::Button(1, _background._drawSurface,
+ _loadButtons[i].reset(new UI::Button(1, _background._drawSurface,
_loadSaveData->_loadButtonDownSrcs[i], _loadSaveData->_loadButtonDests[i],
hasHighlights ? _loadSaveData->_loadButtonHighlightSrcs[i] : Common::Rect(),
- hasHighlights ? _loadSaveData->_loadButtonDisabledSrcs[i] : Common::Rect());
+ hasHighlights ? _loadSaveData->_loadButtonDisabledSrcs[i] : Common::Rect()));
- _saveButtons[i] = new UI::Button(1, _background._drawSurface,
+ _saveButtons[i].reset(new UI::Button(1, _background._drawSurface,
_loadSaveData->_saveButtonDownSrcs[i], _loadSaveData->_saveButtonDests[i],
hasHighlights ? _loadSaveData->_saveButtonHighlightSrcs[i] : Common::Rect(),
- hasHighlights ? _loadSaveData->_saveButtonDisabledSrcs[i] : Common::Rect());
+ hasHighlights ? _loadSaveData->_saveButtonDisabledSrcs[i] : Common::Rect()));
- _cancelButtonOverlays[i] = new RenderObject(2, _background._drawSurface,
- _loadSaveData->_cancelButtonSrcs[i], _loadSaveData->_cancelButtonDests[i]);
+ _cancelButtonOverlays[i].reset(new RenderObject(2, _background._drawSurface,
+ _loadSaveData->_cancelButtonSrcs[i], _loadSaveData->_cancelButtonDests[i]));
_loadButtons[i]->init();
_saveButtons[i]->init();
@@ -282,10 +387,10 @@ void LoadSaveMenu::init() {
}
// Load exit button
- _exitButton = new UI::Button(3, _background._drawSurface,
+ _exitButton.reset(new UI::Button(3, _background._drawSurface,
_loadSaveData->_doneButtonDownSrc, _loadSaveData->_doneButtonDest,
hasHighlights ? _loadSaveData->_doneButtonHighlightSrc : Common::Rect(),
- hasHighlights ? _loadSaveData->_doneButtonDisabledSrc : Common::Rect());
+ hasHighlights ? _loadSaveData->_doneButtonDisabledSrc : Common::Rect()));
// Load Cancel button that activates when typing a filename
// Note: this is only responsible for the hover/mouse down/disabled graphic;
@@ -293,9 +398,9 @@ void LoadSaveMenu::init() {
// We also make sure this has an invalid position until we need it.
Common::Rect pos = _loadSaveData->_cancelButtonDests[0];
pos.moveTo(-500, 0);
- _cancelButton = new UI::Button(3, _background._drawSurface,
+ _cancelButton.reset(new UI::Button(3, _background._drawSurface,
_loadSaveData->_cancelButtonDownSrc, Common::Rect(),
- _loadSaveData->_cancelButtonHighlightSrc, _loadSaveData->_cancelButtonDisabledSrc);
+ _loadSaveData->_cancelButtonHighlightSrc, _loadSaveData->_cancelButtonDisabledSrc));
// Load the blinking cursor graphic that appears while typing a filename
_blinkingCursorOverlay._drawSurface.create(_loadSaveData->_blinkingCursorSrc.width(),
@@ -323,7 +428,7 @@ void LoadSaveMenu::init() {
_enteringNewState = true;
}
-void LoadSaveMenu::run() {
+void LoadSaveMenu_V1::run() {
if (_enteringNewState) {
// State has changed, revert all relevant objects to an appropriate state
for (uint i = 0; i < _textboxes.size(); ++i) {
@@ -447,7 +552,7 @@ void LoadSaveMenu::run() {
}
}
-void LoadSaveMenu::enterFilename() {
+void LoadSaveMenu_V1::enterFilename() {
if (_enteringNewState) {
// State has changed, revert all relevant objects to an appropriate state
if (_cancelButton) {
@@ -479,34 +584,27 @@ void LoadSaveMenu::enterFilename() {
g_nancy->_input->setVKEnabled(true);
}
- // Perform cursor blinking
- uint32 gameTime = g_nancy->getTotalPlayTime();
- if (_loadSaveData->_blinkingTimeDelay != 0 && gameTime > _nextBlink) {
- _blinkingCursorOverlay.setVisible(!_blinkingCursorOverlay.isVisible());
- _nextBlink = gameTime + _loadSaveData->_blinkingTimeDelay;
- }
+ LoadSaveMenu::enterFilename();
// Handle input
NancyInput input = g_nancy->_input->getInput();
- // Improvement: we allow the enter key to sumbit
bool enterKeyPressed = false;
- for (uint i = 0; i < input.otherKbdInput.size(); ++i) {
- Common::KeyState &key = input.otherKbdInput[i];
- if (key.keycode == Common::KEYCODE_BACKSPACE) {
- if (_enteredString.size()) {
- _enteredString.deleteLastChar();
- }
- } else if (key.keycode == Common::KEYCODE_RETURN || key.keycode == Common::KEYCODE_KP_ENTER) {
- enterKeyPressed = true;
- } else if (Common::isAlnum(key.ascii) || Common::isSpace(key.ascii)) {
- _enteredString += key.ascii;
- }
-
+ if (input.otherKbdInput.size()) {
uint16 textWidthInPixels = writeToTextbox(_selectedSave, _enteredString, _highlightFont);
Common::Rect tbPosition = _textboxes[_selectedSave]->getScreenPosition();
+ Common::Rect lastCursorPosition = _blinkingCursorOverlay.getScreenPosition();
_blinkingCursorOverlay.moveTo(Common::Point(tbPosition.left + textWidthInPixels,
- tbPosition.bottom - _blinkingCursorOverlay._drawSurface.h + _loadSaveData->_fontYOffset));
+ lastCursorPosition.top));
+
+ if ( input.otherKbdInput.back().keycode == Common::KEYCODE_RETURN ||
+ input.otherKbdInput.back().keycode == Common::KEYCODE_KP_ENTER) {
+ enterKeyPressed = true;
+ }
+ }
+
+ if (_state != kEnterFilename) {
+ return;
}
_cancelButton->handleInput(input);
@@ -528,7 +626,7 @@ void LoadSaveMenu::enterFilename() {
}
}
-void LoadSaveMenu::save() {
+void LoadSaveMenu_V1::save() {
auto *sdlg = GetEngineData(SDLG);
if (sdlg && sdlg->dialogs.size() > 1) {
@@ -623,80 +721,673 @@ void LoadSaveMenu::save() {
g_nancy->_hasJustSaved = true;
}
-void LoadSaveMenu::load() {
- auto *sdlg = GetEngineData(SDLG);
+int LoadSaveMenu_V1::scummVMSaveSlotToLoad() const {
+ return _selectedSave + 1;
+}
- if (sdlg && sdlg->dialogs.size() > 1 && Nancy::State::Scene::hasInstance() && !g_nancy->_hasJustSaved) {
- // nancy6 added a "Do you want load without saving" dialog.
- if (!ConfMan.hasKey("sdlg_return", Common::ConfigManager::kTransientDomain)) {
- // Request the dialog
- ConfMan.setInt("sdlg_id", 2, Common::ConfigManager::kTransientDomain);
- _destroyOnExit = false;
- g_nancy->setState(NancyState::kSaveDialog);
- return;
- } else {
- // Dialog has returned
- _destroyOnExit = true;
- g_nancy->_graphics->suppressNextDraw();
- uint ret = ConfMan.getInt("sdlg_return", Common::ConfigManager::kTransientDomain);
- ConfMan.removeKey("sdlg_return", Common::ConfigManager::kTransientDomain);
- switch (ret) {
- case 1 :
- // "No" keeps us in the LoadSave state but doesn't load
- _state = kRun;
- return;
- case 2 :
- // "Cancel" returns to the main menu
- g_nancy->setState(NancyState::kMainMenu);
- return;
- default:
- // "Yes" actually loads
- break;
- }
- }
+enum { kInputTextboxIndex = -2 };
+
+void LoadSaveMenu_V2::registerGraphics() {
+ LoadSaveMenu::registerGraphics();
+
+ _background1.registerGraphics();
+ _background2.registerGraphics();
+
+ if (_loadButton) {
+ _loadButton->registerGraphics();
}
- if (Nancy::State::Scene::hasInstance()) {
- Nancy::State::Scene::destroy();
+ if (_saveButton) {
+ _saveButton->registerGraphics();
}
- ConfMan.setInt("save_slot", _selectedSave + 1, Common::ConfigManager::kTransientDomain);
+ if (_exitButton) {
+ _exitButton->registerGraphics();
+ }
- _state = kStop;
- _enteringNewState = true;
-}
+ if (_pageUpButton) {
+ _pageUpButton->registerGraphics();
+ }
-void LoadSaveMenu::success() {
- // The original engine still lets the cursor blink in the background, but implementing that is completely unnecessary
- if (_enteringNewState) {
- _nextBlink = g_nancy->getTotalPlayTime() + 2000; // Hardcoded
- _successOverlay.setVisible(true);
- _enteringNewState = false;
+ if (_pageDownButton) {
+ _pageDownButton->registerGraphics();
}
- if (g_nancy->getTotalPlayTime() > _nextBlink) {
- _state = kRun;
- _enteringNewState = true;
+ if (_inputTextbox) {
+ _inputTextbox->registerGraphics();
}
+
+ _blinkingCursorOverlay.registerGraphics();
+ _successOverlay.registerGraphics();
+
+ g_nancy->_graphics->redrawAll();
}
-void LoadSaveMenu::stop() {
- if (_selectedSave != -1) {
- g_nancy->setState(NancyState::kScene);
+void LoadSaveMenu_V2::init() {
+ _loadSaveData = GetEngineData(LOAD);
+ assert(_loadSaveData);
+
+ _background1.init(_loadSaveData->_image1Name);
+ _background2.init(_loadSaveData->_image2Name);
+
+ _baseFont = g_nancy->_graphics->getFont(_loadSaveData->_mainFontID);
+
+ if (_loadSaveData->_highlightFontID != -1) {
+ _highlightFont = g_nancy->_graphics->getFont(_loadSaveData->_highlightFontID);
} else {
- g_nancy->setState(NancyState::kMainMenu);
+ _highlightFont = _baseFont;
+ }
+
+ if (_loadSaveData->_disabledFontID != -1) {
+ _disabledFont = g_nancy->_graphics->getFont(_loadSaveData->_disabledFontID);
+ } else {
+ _disabledFont = _baseFont;
+ }
+
+ _sortedSavesList = g_nancy->getMetaEngine()->listSaves(ConfMan.getActiveDomainName().c_str());
+ filterAndSortSaveStates();
+
+ _textboxes.resize(_loadSaveData->_textboxBounds.size());
+ for (uint i = 0; i < _textboxes.size(); ++i) {
+ // Load textbox objects
+ RenderObject *newTb = new RenderObject(5);
+ _textboxes[i].reset(newTb);
+ const Common::Rect &bounds = _loadSaveData->_textboxBounds[i];
+ newTb->_drawSurface.create(bounds.width(), bounds.height(), g_nancy->_graphics->getScreenPixelFormat());
+ newTb->_drawSurface.clear(g_nancy->_graphics->getTransColor());
+ newTb->moveTo(bounds);
+ newTb->setTransparent(true);
+ newTb->setVisible(true);
+ newTb->init();
+ }
+
+ if (!_loadSaveData->_inputTextboxBounds.isEmpty()) {
+ _inputTextbox.reset(new RenderObject(5));
+ const Common::Rect &bounds = _loadSaveData->_inputTextboxBounds;
+ _inputTextbox->_drawSurface.create(bounds.width(), bounds.height(), g_nancy->_graphics->getScreenPixelFormat());
+ _inputTextbox->_drawSurface.clear(g_nancy->_graphics->getTransColor());
+ _inputTextbox->moveTo(bounds);
+ _inputTextbox->setTransparent(true);
+ _inputTextbox->setVisible(true);
+ _inputTextbox->init();
+ }
+
+ _filenameStrings.resize(_loadSaveData->_textboxBounds.size());
+ _saveExists.resize(_filenameStrings.size(), false);
+
+ // Five buttons total
+ g_nancy->_resource->loadImage(_loadSaveData->_imageButtonsName, _buttonsImage);
+
+ _saveButton.reset(new UI::Button(1, _buttonsImage,
+ _loadSaveData->_pressedButtonSrcs[0],
+ _loadSaveData->_buttonDests[0],
+ _loadSaveData->_highlightedButtonSrcs[0],
+ _loadSaveData->_disabledButtonSrcs[0],
+ _loadSaveData->_unpressedButtonSrcs[0]));
+ _pageUpButton.reset(new UI::Button(1, _buttonsImage,
+ _loadSaveData->_pressedButtonSrcs[1],
+ _loadSaveData->_buttonDests[1],
+ _loadSaveData->_highlightedButtonSrcs[1],
+ _loadSaveData->_disabledButtonSrcs[1],
+ _loadSaveData->_unpressedButtonSrcs[1]));
+ _pageDownButton.reset(new UI::Button(1, _buttonsImage,
+ _loadSaveData->_pressedButtonSrcs[2],
+ _loadSaveData->_buttonDests[2],
+ _loadSaveData->_highlightedButtonSrcs[2],
+ _loadSaveData->_disabledButtonSrcs[2],
+ _loadSaveData->_unpressedButtonSrcs[2]));
+ _loadButton.reset(new UI::Button(1, _buttonsImage,
+ _loadSaveData->_pressedButtonSrcs[3],
+ _loadSaveData->_buttonDests[3],
+ _loadSaveData->_highlightedButtonSrcs[3],
+ _loadSaveData->_disabledButtonSrcs[3],
+ _loadSaveData->_unpressedButtonSrcs[3]));
+ _exitButton.reset(new UI::Button(1, _buttonsImage,
+ _loadSaveData->_pressedButtonSrcs[4],
+ _loadSaveData->_buttonDests[4],
+ _loadSaveData->_highlightedButtonSrcs[4],
+ _loadSaveData->_disabledButtonSrcs[4],
+ _loadSaveData->_unpressedButtonSrcs[4]));
+
+ // Load the blinking cursor graphic that appears while typing a filename
+ if (!_loadSaveData->_blinkingCursorSrc.isEmpty()) {
+ _blinkingCursorOverlay._drawSurface.create(_loadSaveData->_blinkingCursorSrc.width(),
+ _loadSaveData->_blinkingCursorSrc.height(),
+ g_nancy->_graphics->getScreenPixelFormat());
+ _blinkingCursorOverlay.setTransparent(true);
+ _blinkingCursorOverlay.setVisible(false);
+ _blinkingCursorOverlay._drawSurface.clear(_blinkingCursorOverlay._drawSurface.getTransparentColor());
+ _blinkingCursorOverlay._drawSurface.transBlitFrom(_highlightFont->getImageSurface(), _loadSaveData->_blinkingCursorSrc,
+ Common::Point(), g_nancy->_graphics->getTransColor());
+ } else {
+ Common::Rect bounds = _highlightFont->getBoundingBox('-');
+ _blinkingCursorOverlay._drawSurface.create(bounds.width() + 2, bounds.height(),
+ g_nancy->_graphics->getScreenPixelFormat());
+ _blinkingCursorOverlay.setTransparent(true);
+ _blinkingCursorOverlay.setVisible(false);
+ _blinkingCursorOverlay._drawSurface.clear(_blinkingCursorOverlay._drawSurface.getTransparentColor());
+ _highlightFont->drawChar(_blinkingCursorOverlay._drawSurface.surfacePtr(), '-', 2, 0, 0);
+ }
+
+ // Load the "Your game has been saved" popup graphic
+ if (!_loadSaveData->_gameSavedPopup.empty()) {
+ g_nancy->_resource->loadImage(_loadSaveData->_gameSavedPopup, _successOverlay._drawSurface);
+ Common::Rect destBounds = Common::Rect(0,0, _successOverlay._drawSurface.w, _successOverlay._drawSurface.h);
+ destBounds.moveTo(640 / 2 - destBounds.width() / 2,
+ 480 / 2 - destBounds.height() / 2);
+ _successOverlay.moveTo(destBounds);
+ _successOverlay.setVisible(false);
+ }
+
+ registerGraphics();
+
+ _state = kRun;
+ _enteringNewState = true;
+}
+
+void LoadSaveMenu_V2::run() {
+ if (_enteringNewState) {
+ // State has changed, revert all relevant objects to an appropriate state
+ goToPage(_currentPage);
+ for (uint i = 0; i < _textboxes.size(); ++i) {
+ writeToTextbox(i, _filenameStrings[i], Nancy::State::Scene::hasInstance() ? _baseFont : _disabledFont);
+ }
+
+ if (_currentPage == 0) {
+ _saveButton->setDisabled(!Nancy::State::Scene::hasInstance());
+ _saveButton->_isClicked = false;
+ _inputTextbox->setVisible(true);
+ _textboxes[0]->setVisible(false);
+ } else {
+ _saveButton->setDisabled(true);
+ _saveButton->setVisible(false);
+ _inputTextbox->setVisible(false);
+ _textboxes[0]->setVisible(true);
+ }
+
+ _loadButton->setDisabled(_selectedSave == -1);
+ _loadButton->_isClicked = false;
+
+ _blinkingCursorOverlay.setVisible(false);
+ _exitButton->setDisabled(false);
+ _successOverlay.setVisible(false);
+
+ _hoveredSave = -1;
+ _enteringNewState = false;
+ }
+
+ // Handle input
+ NancyInput input = g_nancy->_input->getInput();
+
+ _loadButton->handleInput(input);
+
+ if (_loadButton->_isClicked) {
+ uint index = _selectedSave;
+ if (_saveExists[index]) {
+ _state = kLoad;
+ _enteringNewState = true;
+ _selectedSave = index;
+ g_nancy->_sound->playSound("BULS");
+ }
+
+ return;
+ }
+
+ _saveButton->handleInput(input);
+
+ if (_saveButton->_isClicked) {
+ if (Nancy::State::Scene::hasInstance()) {
+ _state = kSave;
+ _enteringNewState = true;
+ g_nancy->_sound->playSound("BULS");
+ }
+
+ return;
+ }
+
+ if (_pageUpButton) {
+ _pageUpButton->handleInput(input);
+ if (_pageUpButton->_isClicked) {
+ --_currentPage;
+ g_nancy->_sound->playSound("BUOK");
+ _enteringNewState = true;
+ _pageUpButton->_isClicked = false;
+ return;
+ }
+ }
+
+ if (_pageDownButton) {
+ _pageDownButton->handleInput(input);
+ if (_pageDownButton->_isClicked) {
+ ++_currentPage;
+ g_nancy->_sound->playSound("BUOK");
+ _enteringNewState = true;
+ _pageDownButton->_isClicked = false;
+ return;
+ }
+ }
+
+ // Handle textbox hovering
+ bool hoversOverTextbox = false;
+ for (int i = 0; i < (int)_textboxes.size(); ++i) {
+ uint i2 = (_currentPage == 0 ? i + 1 : i);
+ if (i2 >= _textboxes.size()) {
+ break;
+ }
+
+ if (_textboxes[i2]->getScreenPosition().contains(input.mousePos)) {
+ hoversOverTextbox = true;
+ if (_hoveredSave != i) {
+ if (_hoveredSave != -1 && _hoveredSave != _selectedSave) {
+ if (_hoveredSave == kInputTextboxIndex) {
+ writeToInputTextbox(_baseFont);
+ } else {
+ writeToTextbox(_hoveredSave, _filenameStrings[_hoveredSave], _baseFont);
+ }
+ }
+
+ _hoveredSave = i;
+ writeToTextbox(_hoveredSave, _filenameStrings[_hoveredSave], _highlightFont);
+ }
+
+ if (input.input & NancyInput::kLeftMouseButtonUp && (_filenameStrings[_hoveredSave].size())) {
+ if (_selectedSave != -1) {
+ writeToTextbox(_selectedSave, _filenameStrings[_selectedSave], _baseFont);
+ }
+
+ _loadButton->setDisabled(false);
+
+ _hoveredSave = -1;
+ _selectedSave = i;
+
+ return;
+ }
+
+ break;
+ }
+ }
+
+ if (Nancy::State::Scene::hasInstance() && _currentPage == 0 &&
+ _inputTextbox && _inputTextbox->getScreenPosition().contains(input.mousePos)) {
+ hoversOverTextbox = true;
+
+ if (_hoveredSave != kInputTextboxIndex && _hoveredSave != -1) {
+ writeToTextbox(_hoveredSave, _filenameStrings[_hoveredSave], _baseFont);
+ }
+
+ if (_selectedSave != -1) {
+ writeToTextbox(_selectedSave, _filenameStrings[_selectedSave], _baseFont);
+ }
+
+ _hoveredSave = kInputTextboxIndex;
+ writeToInputTextbox(_highlightFont);
+
+ if (input.input & NancyInput::kLeftMouseButtonUp) {
+ _state = kEnterFilename;
+ _enteringNewState = true;
+
+ return;
+ }
+ }
+
+ if (!hoversOverTextbox && _hoveredSave != -1 && _hoveredSave != _selectedSave) {
+ if (_hoveredSave == kInputTextboxIndex) {
+ writeToInputTextbox(_baseFont);
+ } else {
+ writeToTextbox(_hoveredSave, _filenameStrings[_hoveredSave], _baseFont);
+ }
+ _hoveredSave = -1;
+ }
+
+ // Check Done button
+ if (_exitButton) {
+ _exitButton->handleInput(input);
+
+ if (_exitButton->_isClicked) {
+ _state = kStop;
+ g_nancy->_sound->playSound("BUOK");
+ return;
+ }
+ }
+}
+
+void LoadSaveMenu_V2::enterFilename() {
+ if (_enteringNewState) {
+ // State has changed, revert all relevant objects to an appropriate state
+ _hoveredSave = -1;
+ _loadButton->setDisabled(true);
+
+ Common::Rect tbPosition = _inputTextbox->getScreenPosition();
+ Common::Rect cursorRect = _blinkingCursorOverlay._drawSurface.getBounds();
+ cursorRect.moveTo(tbPosition.left + _highlightFont->getStringWidth(_enteredString),
+ tbPosition.bottom - _blinkingCursorOverlay._drawSurface.h + _loadSaveData->_fontYOffset);
+ cursorRect.translate(0, cursorRect.height() / 2 - 1);
+ _blinkingCursorOverlay.moveTo(cursorRect);
+ _blinkingCursorOverlay.setVisible(true);
+ _nextBlink = g_nancy->getTotalPlayTime() + _loadSaveData->_blinkingTimeDelay;
+ _enteringNewState = false;
+ g_nancy->_input->setVKEnabled(true);
+ }
+
+ LoadSaveMenu::enterFilename();
+
+ // Handle input
+ NancyInput input = g_nancy->_input->getInput();
+
+ bool enterKeyPressed = false;
+ if (input.otherKbdInput.size()) {
+ uint16 textWidthInPixels = writeToInputTextbox(_highlightFont);
+ Common::Rect tbPosition = _inputTextbox->getScreenPosition();
+ Common::Rect lastCursorPosition = _blinkingCursorOverlay.getScreenPosition();
+ _blinkingCursorOverlay.moveTo(Common::Point(tbPosition.left + textWidthInPixels,
+ lastCursorPosition.top));
+
+ if ( input.otherKbdInput.back().keycode == Common::KEYCODE_RETURN ||
+ input.otherKbdInput.back().keycode == Common::KEYCODE_KP_ENTER) {
+ enterKeyPressed = true;
+ }
+ }
+
+ if (_state != kEnterFilename) {
+ return;
+ }
+
+ if (_pageUpButton) {
+ _pageUpButton->handleInput(input);
+ if (_pageUpButton->_isClicked) {
+ --_currentPage;
+ _state = kRun;
+ _enteringNewState = true;
+ _pageUpButton->_isClicked = false;
+ return;
+ }
+ }
+
+ if (_pageDownButton) {
+ _pageDownButton->handleInput(input);
+ if (_pageDownButton->_isClicked) {
+ // Redraw input textbox so it's not highlighted when user goes back up
+ writeToInputTextbox(_baseFont);
+
+ ++_currentPage;
+ _state = kRun;
+ _enteringNewState = true;
+ _pageDownButton->_isClicked = false;
+ return;
+ }
+ }
+
+ _saveButton->handleInput(input);
+ if (_saveButton->_isClicked || enterKeyPressed) {
+ _state = kSave;
+ _enteringNewState = true;
+ g_nancy->_sound->playSound("BULS");
+ g_nancy->_input->setVKEnabled(false);
+ return;
+ }
+
+ // Handle hovering over other saves
+ bool hoversOverTextbox = false;
+ for (int i = 0; i < (int)_textboxes.size(); ++i) {
+ uint i2 = i + 1;
+ if (i2 >= _textboxes.size()) {
+ break;
+ }
+
+ if (_textboxes[i2]->getScreenPosition().contains(input.mousePos)) {
+ hoversOverTextbox = true;
+ if (_hoveredSave != i) {
+ if (_hoveredSave != -1) {
+ writeToTextbox(_hoveredSave, _filenameStrings[_hoveredSave], _baseFont);
+ }
+
+ _hoveredSave = i;
+ writeToTextbox(_hoveredSave, _filenameStrings[_hoveredSave], _highlightFont);
+ }
+
+ if (input.input & NancyInput::kLeftMouseButtonUp) {
+ writeToInputTextbox(_baseFont);
+ _state = kRun;
+ _enteringNewState = true;
+
+ _hoveredSave = -1;
+ _selectedSave = i;
+
+ return;
+ }
+
+ break;
+ }
+ }
+
+ if (!hoversOverTextbox && _hoveredSave != -1 && _hoveredSave != _selectedSave) {
+ writeToTextbox(_hoveredSave, _filenameStrings[_hoveredSave], _baseFont);
+ _hoveredSave = -1;
}
}
-uint16 LoadSaveMenu::writeToTextbox(uint textboxID, const Common::String &text, const Font *font) {
+void LoadSaveMenu_V2::save() {
+ Common::String finalDesc = _enteredString;
+
+ // Look for a state with a matching name and overwrite it
+ bool foundMatch = false;
+ for (auto &save : _sortedSavesList) {
+ if (save.getDescription() == finalDesc) {
+ foundMatch = true;
+ _selectedSave = save.getSaveSlot();
+ break;
+ }
+ }
+
+ if (!foundMatch) {
+ // No match, place in the lowest free slot
+ _selectedSave = 1;
+ bool shouldContinue = false;
+ do {
+ shouldContinue = false;
+ for (auto &save : _sortedSavesList) {
+ if (save.getSaveSlot() == _selectedSave) {
+ ++_selectedSave;
+ shouldContinue = true;
+ break;
+ }
+ }
+ } while (shouldContinue);
+ }
+
+ g_nancy->saveGameState(_selectedSave, finalDesc, false);
+
+ ConfMan.setInt("display_slot", _selectedSave, Common::ConfigManager::kTransientDomain); // Used to load the save name
+
+ if (_successOverlay._drawSurface.empty()) {
+ _state = kRun;
+ _enteringNewState = true;
+ } else {
+ _state = kSuccess;
+ _enteringNewState = true;
+ }
+
+ if ((int)_saveExists.size() < _selectedSave) {
+ _saveExists.resize(_selectedSave + 1, false);
+ }
+
+ _saveExists[_selectedSave] = true;
+ g_nancy->_hasJustSaved = true;
+}
+
+void LoadSaveMenu_V2::success() {
+ LoadSaveMenu::success();
+
+ if (g_nancy->getTotalPlayTime() > _nextBlink) {
+ _selectedSave = 0;
+ }
+}
+
+int LoadSaveMenu_V2::scummVMSaveSlotToLoad() const {
+ uint orderedSaveID = _currentPage * _filenameStrings.size() + _selectedSave;
+ if (_currentPage != 0) {
+ // First page has one save less
+ orderedSaveID -= 1;
+ }
+
+ return _sortedSavesList[orderedSaveID].getSaveSlot();
+}
+
+uint16 LoadSaveMenu_V2::writeToTextbox(int textboxID, const Common::String &text, const Font *font) {
assert(font);
- _textboxes[textboxID]->_drawSurface.clear(g_nancy->_graphics->getTransColor());
- Common::Point destPoint(_loadSaveData->_fontXOffset, _loadSaveData->_fontYOffset + _textboxes[textboxID]->_drawSurface.h - font->getFontHeight());
- font->drawString(&_textboxes[textboxID]->_drawSurface, text, destPoint.x, destPoint.y, _textboxes[textboxID]->_drawSurface.w, 0);
- _textboxes[textboxID]->setVisible(true);
+ if (_currentPage == 0) {
+ // Page one has one textbox less, right at the top.
+ // We simply disable it and adjust the indexing here and in the hovering code
+ ++textboxID;
+ }
- return font->getStringWidth(text);
+ if (textboxID >= (int)_textboxes.size()) {
+ return 0;
+ }
+
+ return LoadSaveMenu::writeToTextbox(textboxID, text, font);
+}
+
+uint16 LoadSaveMenu_V2::writeToInputTextbox(const Font *font) {
+ assert(font);
+
+ _inputTextbox->_drawSurface.clear(g_nancy->_graphics->getTransColor());
+ Common::Point destPoint(_loadSaveData->_fontXOffset, _loadSaveData->_fontYOffset + _inputTextbox->_drawSurface.h - font->getFontHeight());
+ font->drawString(&_inputTextbox->_drawSurface, _enteredString,
+ destPoint.x, destPoint.y, _inputTextbox->_drawSurface.w, 0);
+ _inputTextbox->setVisible(true);
+
+ return font->getStringWidth(_enteredString);
+}
+
+struct SaveStateDescriptorSaveTimeComparator {
+ bool operator()(const SaveStateDescriptor &x, const SaveStateDescriptor &y) const {
+ // Compare the date/time strings. This is valid since they only
+ // contain digits and the - and : characters. The comparison
+ // makes sure that saves are listed from newest to oldest.
+ int dateCompare = x.getSaveDate().compareToIgnoreCase(y.getSaveDate());
+ if (dateCompare) {
+ return dateCompare > 0;
+ } else {
+ return x.getSaveTime().compareToIgnoreCase(y.getSaveTime()) > 0;
+ }
+ }
+};
+
+void LoadSaveMenu_V2::filterAndSortSaveStates() {
+ if (!_sortedSavesList.size()) {
+ return;
+ }
+
+ // Assumes the autosave slot is 0
+ if (_sortedSavesList[0].isAutosave() && _sortedSavesList[0].isValid()) {
+ _sortedSavesList.erase(_sortedSavesList.begin());
+ }
+
+ // Clear second chance saves
+ for (auto *save = _sortedSavesList.begin(); save != _sortedSavesList.end(); ++save) {
+ if (save->getDescription() == "SECOND CHANCE") {
+ save = _sortedSavesList.erase(save) - 1;
+ }
+ }
+
+ Common::sort(_sortedSavesList.begin(), _sortedSavesList.end(), SaveStateDescriptorSaveTimeComparator());
+}
+
+void LoadSaveMenu_V2::extractSaveNames(uint pageID) {
+ if (!_sortedSavesList.size()) {
+ // No saves yet, just load the default name into the input box
+ _enteredString = _loadSaveData->_emptySaveText;
+ writeToInputTextbox(_baseFont);
+
+ return;
+ }
+
+ // First, empty all save names
+ for (uint i = 0; i < _filenameStrings.size(); ++i) {
+ _filenameStrings[i].clear();
+ _saveExists[i] = false;
+ }
+
+ uint firstSaveID, lastSaveID;
+
+ // The first page has one textbox less
+ uint numTextboxes = (_currentPage == 0 ? _filenameStrings.size() - 1 : _filenameStrings.size());
+ firstSaveID = pageID == 0 ? 0 : (_filenameStrings.size() - 1 + (pageID - 1) * _filenameStrings.size());
+ lastSaveID = MIN<uint>(_sortedSavesList.size() - 1, firstSaveID + numTextboxes - 1);
+
+ for (uint i = firstSaveID; i <= lastSaveID; ++i) {
+ int onScreenSaveID = i - firstSaveID;
+ _saveExists[onScreenSaveID] = true;
+ _filenameStrings[onScreenSaveID] = _sortedSavesList[i].getDescription();
+ }
+
+ // Load the top textbox showing the name of the last save made
+ if (_enteredString.empty() && Nancy::State::Scene::hasInstance()) {
+ bool textboxSet = false;
+
+ if (ConfMan.hasKey("display_slot", Common::ConfigManager::kTransientDomain)) {
+ int slot = ConfMan.getInt("display_slot", Common::ConfigManager::kTransientDomain);
+
+ for (uint i = 0; i < _sortedSavesList.size(); ++i) {
+ if (_sortedSavesList[i].getSaveSlot() == slot) {
+ _enteredString = _sortedSavesList[i].getDescription();
+ writeToInputTextbox(_baseFont);
+ textboxSet = true;
+ break;
+ }
+ }
+ }
+
+ if (!textboxSet) {
+ _enteredString = _loadSaveData->_emptySaveText;
+ writeToInputTextbox(_baseFont);
+ }
+ }
+}
+
+void LoadSaveMenu_V2::goToPage(uint pageID) {
+ if (pageID == 0) {
+ _background1.setVisible(true);
+ _background2.setVisible(false);
+ } else {
+ _background1.setVisible(false);
+ _background2.setVisible(true);
+ }
+
+ extractSaveNames(pageID);
+ _currentPage = pageID;
+ _selectedSave = -1;
+
+ int numSaves = _sortedSavesList.size();
+
+ if (!_pageUpButton || !_pageDownButton)
+ return;
+
+ if (numSaves > (int)((_filenameStrings.size() - 1) + pageID * _filenameStrings.size())) {
+ _pageDownButton->setDisabled(false);
+ _pageDownButton->setVisible(true);
+ } else {
+ _pageDownButton->setDisabled(true);
+ _pageDownButton->setVisible(false);
+ }
+
+ if (pageID == 0) {
+ _pageUpButton->setDisabled(true);
+ _pageUpButton->setVisible(false);
+ } else {
+ _pageUpButton->setDisabled(false);
+ _pageUpButton->setVisible(true);
+ }
+
+ _loadButton->setDisabled(true);
+}
+
+void LoadSaveMenu_V2::reloadSaves() {
+ _sortedSavesList = g_nancy->getMetaEngine()->listSaves(ConfMan.getActiveDomainName().c_str());
+ filterAndSortSaveStates();
+ extractSaveNames(0);
}
} // End of namespace State
diff --git a/engines/nancy/state/loadsave.h b/engines/nancy/state/loadsave.h
index 6a46176f1fc..8eaf602c9ff 100644
--- a/engines/nancy/state/loadsave.h
+++ b/engines/nancy/state/loadsave.h
@@ -23,85 +23,144 @@
#define NANCY_STATE_LOADSAVE_H
#include "common/singleton.h"
+#include "common/ptr.h"
#include "engines/nancy/state/state.h"
#include "engines/nancy/ui/fullscreenimage.h"
+#include "engines/nancy/ui/button.h"
#include "engines/nancy/font.h"
namespace Nancy {
struct LOAD;
-namespace UI {
-class Button;
-}
-
namespace State {
class LoadSaveMenu : public State, public Common::Singleton<LoadSaveMenu> {
public:
- LoadSaveMenu() :
- _state(kInit), _selectedSave(-1), _enteringNewState(false), _nextBlink(0),
- _baseFont(nullptr), _highlightFont(nullptr),
- _disabledFont(nullptr), _loadSaveData(nullptr),
- _cancelButton(nullptr), _exitButton(nullptr),
- _blinkingCursorOverlay(6), _successOverlay(8) {}
virtual ~LoadSaveMenu();
+protected:
+ enum State { kInit, kRun, kEnterFilename, kSave, kLoad, kSuccess, kStop };
+
+ LoadSaveMenu() :
+ _blinkingCursorOverlay(6),
+ _successOverlay(8) {};
+
+ virtual void init() = 0;
+ virtual void run() = 0;
+ virtual void enterFilename();
+ virtual void save() = 0;
+ virtual void load();
+ virtual void success();
+ virtual void stop();
+
+ virtual int scummVMSaveSlotToLoad() const = 0;
+
+ virtual void registerGraphics();
+
+ virtual uint16 writeToTextbox(int textboxID, const Common::String &text, const Font *font);
+
+ void scummVMSave();
+ void scummVMLoad();
+
// State API
void process() override;
void onStateEnter(const NancyState::NancyState prevState) override;
bool onStateExit(const NancyState::NancyState nextState) override;
-private:
- void init();
- void run();
- void enterFilename();
- void save();
- void load();
- void success();
- void stop();
+ const Font *_baseFont = nullptr;
+ const Font *_highlightFont = nullptr;
+ const Font *_disabledFont = nullptr;
- void registerGraphics();
+ State _state = kInit;
+ bool _enteringNewState = true;
+ bool _destroyOnExit = true;
+ const LOAD *_loadSaveData = nullptr;
- void scummVMSave();
- void scummVMLoad();
+ int16 _selectedSave = -1;
+ RenderObject *_textboxReceivingInput = nullptr;
- uint16 writeToTextbox(uint textboxID, const Common::String &text, const Font *font);
+ // UI elements common to both menus
+ Common::Array<Common::ScopedPtr<RenderObject>> _textboxes;
+ Common::ScopedPtr<UI::Button> _exitButton;
- enum State { kInit, kRun, kEnterFilename, kSave, kLoad, kSuccess, kStop };
+ RenderObject _blinkingCursorOverlay;
+ RenderObject _successOverlay;
+
+ uint32 _nextBlink = 0;
+ Common::String _enteredString;
+};
- State _state;
+class LoadSaveMenu_V1 : public LoadSaveMenu {
+private:
+ void init() override;
+ void run() override;
+ void enterFilename() override;
+ void save() override;
- UI::FullScreenImage _background;
+ virtual int scummVMSaveSlotToLoad() const override;
- const Font *_baseFont;
- const Font *_highlightFont;
- const Font *_disabledFont;
+ void registerGraphics() override;
+
+ UI::FullScreenImage _background;
Common::Array<Common::String> _filenameStrings;
Common::Array<bool> _saveExists;
- Common::String _enteredString;
+ Common::Array<Common::ScopedPtr<UI::Button>> _loadButtons;
+ Common::Array<Common::ScopedPtr<UI::Button>> _saveButtons;
+ Common::Array<Common::ScopedPtr<RenderObject>> _cancelButtonOverlays;
+ Common::ScopedPtr<UI::Button> _cancelButton;
+};
- Common::Array<RenderObject *> _textboxes;
- Common::Array<UI::Button *> _loadButtons;
- Common::Array<UI::Button *> _saveButtons;
- Common::Array<RenderObject *> _cancelButtonOverlays;
- UI::Button *_exitButton;
- UI::Button *_cancelButton;
- RenderObject _blinkingCursorOverlay;
- RenderObject _successOverlay;
+class LoadSaveMenu_V2 : public LoadSaveMenu {
+private:
+ void init() override;
+ void run() override;
+ void enterFilename() override;
+ void save() override;
+ void success() override;
- int16 _selectedSave;
- bool _enteringNewState;
- uint32 _nextBlink;
+ virtual int scummVMSaveSlotToLoad() const override;
- bool _destroyOnExit = true;
+ void registerGraphics() override;
- const LOAD *_loadSaveData;
+ uint16 writeToTextbox(int textboxID, const Common::String &text, const Font *font) override;
+ uint16 writeToInputTextbox(const Font *font);
+
+ void filterAndSortSaveStates();
+ void extractSaveNames(uint pageID);
+ void goToPage(uint pageID);
+ void reloadSaves();
+ void setConfig();
+
+ UI::FullScreenImage _background1;
+ UI::FullScreenImage _background2;
+ Graphics::ManagedSurface _buttonsImage;
+
+ Common::Array<Common::String> _filenameStrings;
+ Common::Array<bool> _saveExists;
+
+ Common::ScopedPtr<RenderObject> _inputTextbox;
+ Common::ScopedPtr<UI::Button> _loadButton;
+ Common::ScopedPtr<UI::Button> _saveButton;
+ Common::ScopedPtr<UI::Button> _pageUpButton;
+ Common::ScopedPtr<UI::Button> _pageDownButton;
+
+ int16 _hoveredSave = -1;
+ uint _currentPage = 0;
+
+ SaveStateList _sortedSavesList;
};
} // End of namespace State
} // End of namespace Nancy
+namespace Common {
+
+template<>
+Nancy::State::LoadSaveMenu *Singleton<Nancy::State::LoadSaveMenu>::makeInstance();
+
+} // End of namespace Common
+
#endif // NANCY_STATE_LOADSAVE_H
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index 0a17e7fb671..58af4576895 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -835,9 +835,13 @@ void Scene::init() {
// Remove key so clicking on "New Game" in start menu doesn't just reload the save
ConfMan.removeKey("save_slot", Common::ConfigManager::kTransientDomain);
+ // Retain the last slot used so the nancy8+ save menu shows its name on top
+ ConfMan.setInt("display_slot", saveSlot, Common::ConfigManager::kTransientDomain);
} else {
// Normal boot, load default first scene
_state = kLoad;
+ // Make sure the nancy8+ save menu doesn't display a save name on new game
+ ConfMan.removeKey("display_slot", Common::ConfigManager::kTransientDomain);
}
// Set relevant event flag when player has won the game at least once
diff --git a/engines/nancy/ui/fullscreenimage.cpp b/engines/nancy/ui/fullscreenimage.cpp
index c6ab4bffdb7..9f11e8323c6 100644
--- a/engines/nancy/ui/fullscreenimage.cpp
+++ b/engines/nancy/ui/fullscreenimage.cpp
@@ -28,7 +28,9 @@ namespace Nancy {
namespace UI {
void FullScreenImage::init(const Common::Path &imageName) {
- g_nancy->_resource->loadImage(imageName, _drawSurface);
+ if (!g_nancy->_resource->loadImage(imageName, _drawSurface)) {
+ return;
+ }
Common::Rect srcBounds = Common::Rect(0,0, _drawSurface.w, _drawSurface.h);
_screenPosition = srcBounds;
Commit: 0a1ab6cbe81c435e6bdec78f4d12efc6bc904421
https://github.com/scummvm/scummvm/commit/0a1ab6cbe81c435e6bdec78f4d12efc6bc904421
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2025-11-11T11:50:18+01:00
Commit Message:
NANCY: Fix image loading in The Vampire Diaries
loadImage() was erroneously returning false in
TVD, even when the image was, in fact, found and loaded.
As a result, most graphics wouldn't be displayed
on screen at all.
Changed paths:
engines/nancy/resource.cpp
diff --git a/engines/nancy/resource.cpp b/engines/nancy/resource.cpp
index d83c992da78..b99461d7555 100644
--- a/engines/nancy/resource.cpp
+++ b/engines/nancy/resource.cpp
@@ -78,6 +78,7 @@ bool ResourceManager::loadImage(const Common::Path &name, Graphics::ManagedSurfa
bmpDec.loadStream(*stream);
surf.copyFrom(*bmpDec.getSurface());
surf.setPalette(bmpDec.getPalette().data(), 0, MIN<uint>(256, bmpDec.getPalette().size())); // LOGO.BMP reports 257 colors
+ return true;
}
}
Commit: fa613690e691a78078fa2a292b913ee664904a10
https://github.com/scummvm/scummvm/commit/fa613690e691a78078fa2a292b913ee664904a10
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2025-11-11T11:50:18+01:00
Commit Message:
NANCY: Use ScopedPtr in SetupMenu
Changed paths:
engines/nancy/state/setupmenu.cpp
engines/nancy/state/setupmenu.h
diff --git a/engines/nancy/state/setupmenu.cpp b/engines/nancy/state/setupmenu.cpp
index 73d670a0248..a08788e2f6b 100644
--- a/engines/nancy/state/setupmenu.cpp
+++ b/engines/nancy/state/setupmenu.cpp
@@ -39,18 +39,6 @@ DECLARE_SINGLETON(Nancy::State::SetupMenu);
namespace Nancy {
namespace State {
-SetupMenu::~SetupMenu() {
- for (auto *tog : _toggles) {
- delete tog;
- }
-
- for (auto *scroll : _scrollbars) {
- delete scroll;
- }
-
- delete _exitButton;
-}
-
void SetupMenu::process() {
switch (_state) {
case kInit:
@@ -76,11 +64,11 @@ bool SetupMenu::onStateExit(const NancyState::NancyState nextState) {
void SetupMenu::registerGraphics() {
_background.registerGraphics();
- for (auto *tog : _toggles) {
+ for (auto &tog : _toggles) {
tog->registerGraphics();
}
- for (auto *scroll : _scrollbars) {
+ for (auto &scroll : _scrollbars) {
scroll->registerGraphics();
}
@@ -153,11 +141,12 @@ void SetupMenu::init() {
}
}
+ _toggles.resize(_setupData->_buttonDests.size() - 1);
for (uint i = 0; i < _setupData->_buttonDests.size() - 1; ++i) {
- _toggles.push_back(new UI::Toggle(5, _background._drawSurface,
+ _toggles[i].reset(new UI::Toggle(5, _background._drawSurface,
_setupData->_buttonDownSrcs[i], _setupData->_buttonDests[i]));
- _toggles.back()->init();
+ _toggles[i]->init();
}
// Set toggle visibility
@@ -165,12 +154,13 @@ void SetupMenu::init() {
_toggles[i]->setState(ConfMan.getBool(getToggleConfManKey(i), ConfMan.getActiveDomainName()));
}
+ _scrollbars.resize(_setupData->_scrollbarSrcs.size());
for (uint i = 0; i < _setupData->_scrollbarSrcs.size(); ++i) {
- _scrollbars.push_back(new UI::Scrollbar(7, _setupData->_scrollbarSrcs[i],
+ _scrollbars[i].reset(new UI::Scrollbar(7, _setupData->_scrollbarSrcs[i],
_background._drawSurface, Common::Point(_setupData->_scrollbarsCenterXPosL[i] + 1, _setupData->_scrollbarsCenterYPos[i]),
_setupData->_scrollbarsCenterXPosR[i] + 1 - _setupData->_scrollbarsCenterXPosL[i] - 1, false));
- _scrollbars.back()->init();
- _scrollbars.back()->setVisible(true);
+ _scrollbars[i]->init();
+ _scrollbars[i]->setVisible(true);
}
// Set scrollbar positions
@@ -178,9 +168,9 @@ void SetupMenu::init() {
_scrollbars[1]->setPosition(ConfMan.getInt("music_volume") / 255.0);
_scrollbars[2]->setPosition(ConfMan.getInt("sfx_volume") / 255.0);
- _exitButton = new UI::Button(5, _background._drawSurface,
+ _exitButton.reset(new UI::Button(5, _background._drawSurface,
_setupData->_buttonDownSrcs.back(), _setupData->_buttonDests.back(),
- _setupData->_doneButtonHighlightSrc);
+ _setupData->_doneButtonHighlightSrc));
_exitButton->init();
_exitButton->setVisible(false);
@@ -193,7 +183,7 @@ void SetupMenu::run() {
NancyInput input = g_nancy->_input->getInput();
for (uint i = 0; i < _scrollbars.size(); ++i) {
- auto *scroll = _scrollbars[i];
+ auto &scroll = _scrollbars[i];
float startPos = scroll->getPos();
scroll->handleInput(input);
@@ -223,7 +213,7 @@ void SetupMenu::run() {
}
for (uint i = 0; i < _toggles.size(); ++i) {
- auto *tog = _toggles[i];
+ auto &tog = _toggles[i];
tog->handleInput(input);
if (tog->_stateChanged) {
g_nancy->_sound->playSound("BUOK");
diff --git a/engines/nancy/state/setupmenu.h b/engines/nancy/state/setupmenu.h
index cedc0f147e7..bd45c38f270 100644
--- a/engines/nancy/state/setupmenu.h
+++ b/engines/nancy/state/setupmenu.h
@@ -22,29 +22,22 @@
#ifndef NANCY_STATE_SETUPMENU_H
#define NANCY_STATE_SETUPMENU_H
+#include "common/ptr.h"
#include "common/singleton.h"
#include "engines/nancy/state/state.h"
-
#include "engines/nancy/ui/fullscreenimage.h"
+#include "engines/nancy/ui/scrollbar.h"
+#include "engines/nancy/ui/button.h"
namespace Nancy {
struct SET;
-namespace UI {
-class Button;
-class Toggle;
-class Scrollbar;
-}
-
namespace State {
class SetupMenu : public State, public Common::Singleton<SetupMenu> {
public:
- SetupMenu() : _state(kInit), _exitButton(nullptr), _setupData(nullptr) {}
- virtual ~SetupMenu();
-
// State API
void process() override;
void onStateEnter(const NancyState::NancyState prevState) override;
@@ -62,11 +55,11 @@ private:
enum State { kInit, kRun, kStop };
UI::FullScreenImage _background;
- State _state;
+ State _state = kInit;
- Common::Array<UI::Toggle *> _toggles;
- Common::Array<UI::Scrollbar *> _scrollbars;
- UI::Button *_exitButton;
+ Common::Array<Common::ScopedPtr<UI::Toggle>> _toggles;
+ Common::Array<Common::ScopedPtr<UI::Scrollbar>> _scrollbars;
+ Common::ScopedPtr<UI::Button> _exitButton;
const SET *_setupData;
};
Commit: b7b64dd4abef7aef3eb02dcec8b2e0fa93214023
https://github.com/scummvm/scummvm/commit/b7b64dd4abef7aef3eb02dcec8b2e0fa93214023
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2025-11-11T11:50:18+01:00
Commit Message:
NANCY: Use ScopedPtr in SaveDialog
Changed paths:
engines/nancy/state/savedialog.cpp
engines/nancy/state/savedialog.h
diff --git a/engines/nancy/state/savedialog.cpp b/engines/nancy/state/savedialog.cpp
index bb9b41cb508..f58eea0049b 100644
--- a/engines/nancy/state/savedialog.cpp
+++ b/engines/nancy/state/savedialog.cpp
@@ -38,12 +38,6 @@ DECLARE_SINGLETON(Nancy::State::SaveDialog);
namespace Nancy {
namespace State {
-SaveDialog::~SaveDialog() {
- delete _yesButton;
- delete _noButton;
- delete _cancelButton;
-}
-
void SaveDialog::process() {
if (g_nancy->_sound->isSoundPlaying("BUOK")) {
return;
@@ -97,9 +91,9 @@ void SaveDialog::init() {
_background.init(_dialogData->imageName);
- _yesButton = new UI::Button(1, _background._drawSurface, _dialogData->yesDownSrc, _dialogData->yesDest, _dialogData->yesHighlightSrc);
- _noButton = new UI::Button(1, _background._drawSurface, _dialogData->noDownSrc, _dialogData->noDest, _dialogData->noHighlightSrc);
- _cancelButton = new UI::Button(1, _background._drawSurface, _dialogData->cancelDownSrc, _dialogData->cancelDest, _dialogData->cancelHighlightSrc);
+ _yesButton.reset(new UI::Button(1, _background._drawSurface, _dialogData->yesDownSrc, _dialogData->yesDest, _dialogData->yesHighlightSrc));
+ _noButton.reset(new UI::Button(1, _background._drawSurface, _dialogData->noDownSrc, _dialogData->noDest, _dialogData->noHighlightSrc));
+ _cancelButton.reset(new UI::Button(1, _background._drawSurface, _dialogData->cancelDownSrc, _dialogData->cancelDest, _dialogData->cancelHighlightSrc));
registerGraphics();
@@ -138,4 +132,3 @@ void SaveDialog::stop() {
} // End of namespace State
} // End of namespace Nancy
-
diff --git a/engines/nancy/state/savedialog.h b/engines/nancy/state/savedialog.h
index 0a31ccbe082..d4d93918f0b 100644
--- a/engines/nancy/state/savedialog.h
+++ b/engines/nancy/state/savedialog.h
@@ -22,6 +22,7 @@
#ifndef NANCY_STATE_SAVEDIALOG_H
#define NANCY_STATE_SAVEDIALOG_H
+#include "common/ptr.h"
#include "common/singleton.h"
#include "engines/nancy/state/state.h"
@@ -40,8 +41,7 @@ namespace State {
class SaveDialog : public State, public Common::Singleton<SaveDialog> {
public:
- SaveDialog() : _state(kInit), _yesButton(nullptr), _noButton(nullptr), _cancelButton(nullptr), _selected(-1), _dialogData(nullptr) {}
- virtual ~SaveDialog();
+ SaveDialog() : _state(kInit), _selected(-1), _dialogData(nullptr) {}
// State API
void process() override;
@@ -61,9 +61,9 @@ private:
State _state;
int _selected;
- UI::Button *_yesButton;
- UI::Button *_noButton;
- UI::Button *_cancelButton;
+ Common::ScopedPtr<UI::Button> _yesButton;
+ Common::ScopedPtr<UI::Button> _noButton;
+ Common::ScopedPtr<UI::Button> _cancelButton;
const SDLG::Dialog *_dialogData;
};
Commit: 9f3140df4c55f7087a6fc4406fe857343d489d3b
https://github.com/scummvm/scummvm/commit/9f3140df4c55f7087a6fc4406fe857343d489d3b
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2025-11-11T11:50:18+01:00
Commit Message:
NANCY: Use ScopedPtr in Map
Changed paths:
engines/nancy/state/map.cpp
engines/nancy/state/map.h
diff --git a/engines/nancy/state/map.cpp b/engines/nancy/state/map.cpp
index ea58daa7f3d..230cd5f219e 100644
--- a/engines/nancy/state/map.cpp
+++ b/engines/nancy/state/map.cpp
@@ -351,12 +351,6 @@ void TVDMap::MapGlobe::onTrigger() {
}
}
-Nancy1Map::Nancy1Map() : _button(nullptr)/*, _mapButtonClicked(false)*/ {}
-
-Nancy1Map::~Nancy1Map() {
- delete _button;
-}
-
void Nancy1Map::init() {
_viewport.init();
_label.init();
@@ -382,7 +376,7 @@ void Nancy1Map::init() {
_locationLabelDests[i].top = _locationLabelDests[i].bottom - _mapData->locations[i].labelSrc.height() + 1;
}
- _button = new UI::Button(9, g_nancy->_graphics->_object0, _mapData->buttonSrc, _mapData->buttonDest);
+ _button.reset(new UI::Button(9, g_nancy->_graphics->_object0, _mapData->buttonSrc, _mapData->buttonDest));
_button->init();
_button->setVisible(true);
diff --git a/engines/nancy/state/map.h b/engines/nancy/state/map.h
index 62a433eeabd..1a58924fee0 100644
--- a/engines/nancy/state/map.h
+++ b/engines/nancy/state/map.h
@@ -22,6 +22,7 @@
#ifndef NANCY_STATE_MAP_H
#define NANCY_STATE_MAP_H
+#include "common/ptr.h"
#include "common/singleton.h"
#include "engines/nancy/sound.h"
@@ -127,10 +128,6 @@ private:
};
class Nancy1Map : public Map {
-public:
- Nancy1Map();
- virtual ~Nancy1Map();
-
private:
void init() override;
void load() override;
@@ -139,7 +136,7 @@ private:
bool onStateExit(const NancyState::NancyState next) override;
- UI::Button *_button;
+ Common::ScopedPtr<UI::Button> _button;
};
#define NancyMapState Nancy::State::Map::instance()
Commit: a0809aa698b343d7b5d52f2f330e2b90be277735
https://github.com/scummvm/scummvm/commit/a0809aa698b343d7b5d52f2f330e2b90be277735
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2025-11-11T11:50:19+01:00
Commit Message:
NANCY: Use ScopedPtr in MainMenu
Changed paths:
engines/nancy/state/mainmenu.cpp
engines/nancy/state/mainmenu.h
diff --git a/engines/nancy/state/mainmenu.cpp b/engines/nancy/state/mainmenu.cpp
index 0e58e166fac..048cdcb3d64 100644
--- a/engines/nancy/state/mainmenu.cpp
+++ b/engines/nancy/state/mainmenu.cpp
@@ -39,12 +39,6 @@ DECLARE_SINGLETON(Nancy::State::MainMenu);
namespace Nancy {
namespace State {
-MainMenu::~MainMenu() {
- for (auto *button : _buttons) {
- delete button;
- }
-}
-
void MainMenu::process() {
switch (_state) {
case kInit:
@@ -70,7 +64,7 @@ bool MainMenu::onStateExit(const NancyState::NancyState nextState) {
void MainMenu::registerGraphics() {
_background.registerGraphics();
- for (auto *button : _buttons) {
+ for (auto &button : _buttons) {
button->registerGraphics();
}
@@ -78,7 +72,7 @@ void MainMenu::registerGraphics() {
}
void MainMenu::clearButtonState() {
- for (auto *button : _buttons) {
+ for (auto &button : _buttons) {
button->_isClicked = false;
}
}
@@ -97,14 +91,15 @@ void MainMenu::init() {
g_nancy->_sound->playSound("MSND");
}
+ _buttons.resize(_menuData->_buttonDests.size());
for (uint i = 0; i < _menuData->_buttonDests.size(); ++i) {
- _buttons.push_back(new UI::Button(5, _background._drawSurface,
+ _buttons[i].reset(new UI::Button(5, _background._drawSurface,
_menuData->_buttonDownSrcs[i], _menuData->_buttonDests[i],
_menuData->_buttonHighlightSrcs.size() ? _menuData->_buttonHighlightSrcs[i] : Common::Rect(),
_menuData->_buttonDisabledSrcs.size() ? _menuData->_buttonDisabledSrcs[i] : Common::Rect()));
- _buttons.back()->init();
- _buttons.back()->setVisible(false);
+ _buttons[i]->init();
+ _buttons[i]->setVisible(false);
}
registerGraphics();
@@ -139,7 +134,7 @@ void MainMenu::run() {
}
for (uint i = 0; i < _buttons.size(); ++i) {
- auto *button = _buttons[i];
+ auto &button = _buttons[i];
button->handleInput(input);
if (_selected == -1 && button->_isClicked) {
if (button->_isDisabled) {
diff --git a/engines/nancy/state/mainmenu.h b/engines/nancy/state/mainmenu.h
index f92e9b88bf5..48f19eaefd1 100644
--- a/engines/nancy/state/mainmenu.h
+++ b/engines/nancy/state/mainmenu.h
@@ -22,6 +22,7 @@
#ifndef NANCY_STATE_MAINMENU_H
#define NANCY_STATE_MAINMENU_H
+#include "common/ptr.h"
#include "common/singleton.h"
#include "engines/nancy/state/state.h"
@@ -41,7 +42,6 @@ namespace State {
class MainMenu : public State, public Common::Singleton<MainMenu> {
public:
MainMenu() : _state(kInit), _selected(-1), _menuData(nullptr) {}
- virtual ~MainMenu();
// State API
void process() override;
@@ -62,7 +62,7 @@ private:
State _state;
int16 _selected;
- Common::Array<UI::Button *> _buttons;
+ Common::Array<Common::ScopedPtr<UI::Button>> _buttons;
bool _destroyOnExit = true;
Commit: 7a85b93834d702c9af7ca1958a8f951a204afeee
https://github.com/scummvm/scummvm/commit/7a85b93834d702c9af7ca1958a8f951a204afeee
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2025-11-11T11:50:19+01:00
Commit Message:
NANCY: Use ScopedPtr in Help
Changed paths:
engines/nancy/state/help.cpp
engines/nancy/state/help.h
diff --git a/engines/nancy/state/help.cpp b/engines/nancy/state/help.cpp
index 22f46b1f66f..c88bc370ee3 100644
--- a/engines/nancy/state/help.cpp
+++ b/engines/nancy/state/help.cpp
@@ -36,15 +36,6 @@ DECLARE_SINGLETON(Nancy::State::Help);
namespace Nancy {
namespace State {
-Help::Help() :
- _state(kInit),
- _image(),
- _button(nullptr) {}
-
-Help::~Help() {
- delete _button;
-}
-
void Help::process() {
switch (_state) {
case kInit:
@@ -85,7 +76,7 @@ void Help::init() {
_image.init(helpData->imageName);
- _button = new UI::Button(5, _image._drawSurface, helpData->buttonSrc, helpData->buttonDest, helpData->buttonHoverSrc);
+ _button.reset(new UI::Button(5, _image._drawSurface, helpData->buttonSrc, helpData->buttonDest, helpData->buttonHoverSrc));
_button->init();
_state = kBegin;
diff --git a/engines/nancy/state/help.h b/engines/nancy/state/help.h
index b0ad4480c52..a136dd9d0f7 100644
--- a/engines/nancy/state/help.h
+++ b/engines/nancy/state/help.h
@@ -22,6 +22,7 @@
#ifndef NANCY_STATE_HELP_H
#define NANCY_STATE_HELP_H
+#include "common/ptr.h"
#include "common/singleton.h"
#include "engines/nancy/commontypes.h"
@@ -40,8 +41,6 @@ namespace State {
class Help : public State, public Common::Singleton<Help> {
public:
enum State { kInit, kBegin, kRun, kWait };
- Help();
- virtual ~Help();
// State API
void process() override;
@@ -54,9 +53,9 @@ private:
void run();
void wait();
- State _state;
+ State _state = kInit;
UI::FullScreenImage _image;
- UI::Button *_button;
+ Common::ScopedPtr<UI::Button> _button;
Time _buttonPressActivationTime;
};
Commit: 5078e6c1a9d42e1ad156fa436689dbfb21016399
https://github.com/scummvm/scummvm/commit/5078e6c1a9d42e1ad156fa436689dbfb21016399
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2025-11-11T11:50:19+01:00
Commit Message:
NANCY: Use ScopedPtr in InventoryBox
Changed paths:
engines/nancy/ui/inventorybox.cpp
engines/nancy/ui/inventorybox.h
diff --git a/engines/nancy/ui/inventorybox.cpp b/engines/nancy/ui/inventorybox.cpp
index 1ef5e823164..28b8661679b 100644
--- a/engines/nancy/ui/inventorybox.cpp
+++ b/engines/nancy/ui/inventorybox.cpp
@@ -38,16 +38,10 @@ namespace UI {
InventoryBox::InventoryBox() :
RenderObject(6),
- _scrollbar(nullptr),
_scrollbarPos(0),
_highlightedHotspot(-1),
_inventoryData(nullptr) {}
-InventoryBox::~InventoryBox() {
- _fullInventorySurface.free();
- _iconsSurface.free(); delete _scrollbar;
-}
-
void InventoryBox::init() {
auto *bootSummary = GetEngineData(BSUM);
assert(bootSummary);
@@ -75,10 +69,10 @@ void InventoryBox::init() {
RenderObject::init();
- _scrollbar = new Scrollbar( 9,
+ _scrollbar.reset(new Scrollbar( 9,
_inventoryData->scrollbarSrcBounds,
_inventoryData->scrollbarDefaultPos,
- _inventoryData->scrollbarMaxScroll - _inventoryData->scrollbarDefaultPos.y);
+ _inventoryData->scrollbarMaxScroll - _inventoryData->scrollbarDefaultPos.y));
_scrollbar->init();
_curtains.init();
}
diff --git a/engines/nancy/ui/inventorybox.h b/engines/nancy/ui/inventorybox.h
index 43107b2fdbc..9e420d12e5c 100644
--- a/engines/nancy/ui/inventorybox.h
+++ b/engines/nancy/ui/inventorybox.h
@@ -22,9 +22,11 @@
#ifndef NANCY_UI_INVENTORYBOX_H
#define NANCY_UI_INVENTORYBOX_H
-#include "engines/nancy/time.h"
+#include "common/ptr.h"
+#include "engines/nancy/time.h"
#include "engines/nancy/renderobject.h"
+#include "engines/nancy/ui/scrollbar.h"
namespace Nancy {
@@ -37,8 +39,6 @@ class Scene;
namespace UI {
-class Scrollbar;
-
class InventoryBox : public RenderObject {
friend class Nancy::State::Scene;
@@ -50,7 +50,6 @@ public:
};
InventoryBox();
- virtual ~InventoryBox();
void init() override;
void updateGraphics() override;
@@ -96,7 +95,7 @@ private:
Graphics::ManagedSurface _iconsSurface;
Graphics::ManagedSurface _fullInventorySurface;
- Scrollbar *_scrollbar;
+ Common::ScopedPtr<Scrollbar> _scrollbar;
Curtains _curtains;
float _scrollbarPos;
Commit: b7829323038bdd90e7ecadf1cf52ba490afc3f7d
https://github.com/scummvm/scummvm/commit/b7829323038bdd90e7ecadf1cf52ba490afc3f7d
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2025-11-11T11:50:19+01:00
Commit Message:
NANCY: Use ScopedPtr in SecondaryMovie
Changed paths:
engines/nancy/action/secondarymovie.cpp
engines/nancy/action/secondarymovie.h
diff --git a/engines/nancy/action/secondarymovie.cpp b/engines/nancy/action/secondarymovie.cpp
index 90a1c43bfc2..19273fd2431 100644
--- a/engines/nancy/action/secondarymovie.cpp
+++ b/engines/nancy/action/secondarymovie.cpp
@@ -36,8 +36,6 @@ namespace Nancy {
namespace Action {
PlaySecondaryMovie::~PlaySecondaryMovie() {
- delete _decoder;
-
if (NancySceneState.getActiveMovie() == this) {
NancySceneState.setActiveMovie(nullptr);
}
@@ -97,9 +95,9 @@ void PlaySecondaryMovie::readData(Common::SeekableReadStream &stream) {
void PlaySecondaryMovie::init() {
if (!_decoder) {
if (_videoType == kVideoPlaytypeAVF) {
- _decoder = new AVFDecoder();
+ _decoder.reset(new AVFDecoder());
} else {
- _decoder = new Video::BinkDecoder();
+ _decoder.reset(new Video::BinkDecoder());
}
}
@@ -145,7 +143,7 @@ void PlaySecondaryMovie::execute() {
// Sync audio and video. This is mostly relevant for some nancy2 scenes, as the
// devs stopped using the built-in movie sound around nancy4. The 12 ms
// difference is roughly how long it takes for a single execution of the main game loop
- ((AVFDecoder *)_decoder)->addFrameTime(12);
+ ((AVFDecoder *)_decoder.get())->addFrameTime(12);
}
if (_playerCursorAllowed == kNoPlayerCursorAllowed) {
diff --git a/engines/nancy/action/secondarymovie.h b/engines/nancy/action/secondarymovie.h
index 351bcdde1a3..93520580805 100644
--- a/engines/nancy/action/secondarymovie.h
+++ b/engines/nancy/action/secondarymovie.h
@@ -22,6 +22,8 @@
#ifndef NANCY_ACTION_SECONDARYMOVIE_H
#define NANCY_ACTION_SECONDARYMOVIE_H
+#include "common/ptr.h"
+
#include "engines/nancy/action/actionrecord.h"
namespace Video {
@@ -86,7 +88,7 @@ public:
SceneChangeDescription _sceneChange;
Common::Array<SecondaryVideoDescription> _videoDescs;
- Video::VideoDecoder *_decoder = nullptr;
+ Common::ScopedPtr<Video::VideoDecoder> _decoder;
protected:
Common::String getRecordTypeName() const override { return "PlaySecondaryMovie"; }
More information about the Scummvm-git-logs
mailing list