mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
41 is the original's name size and resolves truncated autosave names in localized versions Fixes bug #11340 Saves version is increased to "3" (in savefile.h) now, so only new versions of the engine will be able to open the save files with the larger field for the saved game's name
430 lines
13 KiB
C++
430 lines
13 KiB
C++
/* 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 2
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "bladerunner/ui/kia_section_save.h"
|
|
|
|
#include "bladerunner/audio_player.h"
|
|
#include "bladerunner/bladerunner.h"
|
|
#include "bladerunner/font.h"
|
|
#include "bladerunner/game_info.h"
|
|
#include "bladerunner/savefile.h"
|
|
#include "bladerunner/shape.h"
|
|
#include "bladerunner/text_resource.h"
|
|
#include "bladerunner/time.h"
|
|
#include "bladerunner/game_constants.h"
|
|
#include "bladerunner/ui/kia.h"
|
|
#include "bladerunner/ui/ui_container.h"
|
|
#include "bladerunner/ui/ui_image_picker.h"
|
|
#include "bladerunner/ui/ui_input_box.h"
|
|
#include "bladerunner/ui/ui_scroll_box.h"
|
|
|
|
#include "common/error.h"
|
|
#include "common/keyboard.h"
|
|
#include "common/system.h"
|
|
|
|
namespace BladeRunner {
|
|
|
|
KIASectionSave::KIASectionSave(BladeRunnerEngine *vm) : KIASectionBase(vm) {
|
|
_uiContainer = new UIContainer(_vm);
|
|
|
|
_scrollBox = new UIScrollBox(_vm, scrollBoxCallback, this, 1024, 0, true, Common::Rect(155, 158, 461, 346), Common::Rect(506, 160, 506, 350));
|
|
_uiContainer->add(_scrollBox);
|
|
|
|
_inputBox = new UIInputBox(_vm, inputBoxCallback, this, Common::Rect(155, 367, 461, 376), SaveFileManager::kNameLength, ""); // original game has limit 41 characters
|
|
_uiContainer->add(_inputBox);
|
|
_inputBox->hide();
|
|
|
|
_buttons = new UIImagePicker(_vm, 3);
|
|
|
|
_timeLast = 0u;
|
|
_timeLeft = 0u;
|
|
|
|
_state = kStateNormal;
|
|
|
|
_mouseX = 0;
|
|
_mouseY = 0;
|
|
|
|
_hoveredLineId = -1;
|
|
_displayingLineId = -1;
|
|
_selectedLineId = -1;
|
|
_newSaveLineId = -1;
|
|
}
|
|
|
|
KIASectionSave::~KIASectionSave() {
|
|
delete _buttons;
|
|
|
|
_uiContainer->clear();
|
|
delete _inputBox;
|
|
delete _scrollBox;
|
|
delete _uiContainer;
|
|
}
|
|
|
|
void KIASectionSave::open() {
|
|
_scheduledSwitch = false;
|
|
_state = kStateNormal;
|
|
|
|
_buttons->resetImages();
|
|
_buttons->defineImage(
|
|
0,
|
|
Common::Rect(460, 366, 497, 402),
|
|
_vm->_kia->_shapes->get(82),
|
|
_vm->_kia->_shapes->get(83),
|
|
_vm->_kia->_shapes->get(84),
|
|
_vm->_textOptions->getText(22) // Save
|
|
);
|
|
|
|
_scrollBox->show();
|
|
|
|
_saveList = SaveFileManager::list(_vm->getTargetName());
|
|
|
|
bool ableToSaveGame = true;
|
|
|
|
_newSaveLineId = _saveList.size();
|
|
|
|
if (!_saveList.empty() || ableToSaveGame) {
|
|
|
|
_buttons->activate(nullptr, nullptr, nullptr, onButtonPressed, this);
|
|
_inputBox->show();
|
|
|
|
_scrollBox->clearLines();
|
|
|
|
if (ableToSaveGame) {
|
|
_scrollBox->addLine(_vm->_textOptions->getText(23), _newSaveLineId, 0);
|
|
}
|
|
|
|
for (uint i = 0; i < _saveList.size(); ++i) {
|
|
_scrollBox->addLine(_saveList[i].getDescription(), i, 0);
|
|
}
|
|
|
|
if (ableToSaveGame) {
|
|
// New save
|
|
_selectedLineId = _newSaveLineId;
|
|
_inputBox->setText("");
|
|
} else {
|
|
// Overwrite first save
|
|
_selectedLineId = 0;
|
|
_inputBox->setText(_saveList[_selectedLineId].getDescription());
|
|
}
|
|
|
|
_scrollBox->setFlags(_selectedLineId, 8);
|
|
}
|
|
|
|
_hoveredLineId = -1;
|
|
_timeLast = _vm->_time->currentSystem();
|
|
_timeLeft = 800u;
|
|
}
|
|
|
|
void KIASectionSave::close() {
|
|
_inputBox->hide();
|
|
_scrollBox->hide();
|
|
_buttons->deactivate();
|
|
|
|
_vm->_kia->playerReset();
|
|
|
|
_saveList.clear();
|
|
}
|
|
|
|
void KIASectionSave::draw(Graphics::Surface &surface) {
|
|
_vm->_kia->_shapes->get(69)->draw(surface, 501, 123);
|
|
_buttons->draw(surface);
|
|
|
|
if (_state == kStateNormal) {
|
|
const char *textChooseSlot = _vm->_textOptions->getText(24); // Choose a slot ...
|
|
int textChooseSlotWidth = _vm->_mainFont->getStringWidth(textChooseSlot);
|
|
_vm->_mainFont->drawString(&surface, textChooseSlot, 308 - textChooseSlotWidth / 2, 143, surface.w, surface.format.RGBToColor(240, 232, 192));
|
|
|
|
// Original game shows warnings/error here, but we don't have any
|
|
|
|
const char *textTypeName = _vm->_textOptions->getText(25); // Type a name ...
|
|
int textTypeNameWidth = _vm->_mainFont->getStringWidth(textTypeName);
|
|
_vm->_mainFont->drawString(&surface, textTypeName, 308 - textTypeNameWidth / 2, 352, surface.w, surface.format.RGBToColor(240, 232, 192));
|
|
|
|
_uiContainer->draw(surface);
|
|
} else if (_state == kStateOverwrite) {
|
|
surface.fillRect(Common::Rect(155, 230, 462, 239), surface.format.RGBToColor(80, 56, 32));
|
|
|
|
const Common::String &saveName = _saveList[_selectedLineId].getDescription();
|
|
int saveNameWidth = _vm->_mainFont->getStringWidth(saveName);
|
|
_vm->_mainFont->drawString(&surface, saveName, 308 - saveNameWidth / 2, 230, surface.w, surface.format.RGBToColor(232, 208, 136));
|
|
|
|
const char *textOverwrite = _vm->_textOptions->getText(35); // Overwrite previously saved game?
|
|
int textOverwriteWidth = _vm->_mainFont->getStringWidth(textOverwrite);
|
|
_vm->_mainFont->drawString(&surface, textOverwrite, 308 - textOverwriteWidth / 2, 240, surface.w, surface.format.RGBToColor(240, 232, 192));
|
|
} else if (_state == kStateDelete) {
|
|
surface.fillRect(Common::Rect(155, 230, 462, 239), surface.format.RGBToColor(80, 56, 32));
|
|
|
|
const Common::String &saveName = _saveList[_selectedLineId].getDescription();
|
|
int saveNameWidth = _vm->_mainFont->getStringWidth(saveName); // Delete this game?
|
|
_vm->_mainFont->drawString(&surface, saveName, 308 - saveNameWidth / 2, 230, surface.w, surface.format.RGBToColor(232, 208, 136));
|
|
|
|
const char *textDelete = _vm->_textOptions->getText(40);
|
|
int textDeleteWidth = _vm->_mainFont->getStringWidth(textDelete);
|
|
_vm->_mainFont->drawString(&surface, textDelete, 308 - textDeleteWidth / 2, 240, surface.w, surface.format.RGBToColor(240, 232, 192));
|
|
}
|
|
|
|
int selectedLineId = _scrollBox->getSelectedLineData();
|
|
|
|
if (selectedLineId != _hoveredLineId) {
|
|
if (selectedLineId >= 0 && selectedLineId < (int)_saveList.size() && _displayingLineId != selectedLineId) {
|
|
if (_timeLeft == 0u) {
|
|
SaveStateDescriptor desc = SaveFileManager::queryMetaInfos(_vm->getTargetName(), selectedLineId);
|
|
const Graphics::Surface *thumbnail = desc.getThumbnail();
|
|
if (thumbnail != nullptr) {
|
|
_vm->_kia->playImage(*thumbnail);
|
|
_displayingLineId = selectedLineId;
|
|
}
|
|
}
|
|
} else {
|
|
_vm->_kia->playerReset();
|
|
_timeLeft = 800u;
|
|
_displayingLineId = -1;
|
|
}
|
|
_hoveredLineId = selectedLineId;
|
|
}
|
|
|
|
uint32 now = _vm->_time->currentSystem();
|
|
if (selectedLineId >= 0 && selectedLineId < (int)_saveList.size() && _displayingLineId != selectedLineId) {
|
|
if (_timeLeft) {
|
|
uint32 timeDiff = now - _timeLast; // unsigned difference is intentional
|
|
if (timeDiff >= _timeLeft) {
|
|
SaveStateDescriptor desc = SaveFileManager::queryMetaInfos(_vm->getTargetName(), _saveList[selectedLineId].getSaveSlot());
|
|
const Graphics::Surface *thumbnail = desc.getThumbnail();
|
|
if (thumbnail != nullptr) {
|
|
_vm->_kia->playImage(*thumbnail);
|
|
_displayingLineId = selectedLineId;
|
|
}
|
|
} else {
|
|
_timeLeft = (_timeLeft < timeDiff) ? 0u : (_timeLeft - timeDiff);
|
|
}
|
|
}
|
|
}
|
|
|
|
_timeLast = now;
|
|
_buttons->drawTooltip(surface, _mouseX, _mouseY);
|
|
}
|
|
|
|
void KIASectionSave::handleKeyUp(const Common::KeyState &kbd) {
|
|
if (_state == kStateNormal) {
|
|
_uiContainer->handleKeyUp(kbd);
|
|
}
|
|
}
|
|
|
|
void KIASectionSave::handleKeyDown(const Common::KeyState &kbd) {
|
|
if (_state == kStateNormal) {
|
|
if (kbd.keycode == Common::KEYCODE_DELETE && _selectedLineId != _newSaveLineId) {
|
|
changeState(kStateDelete);
|
|
}
|
|
_uiContainer->handleKeyDown(kbd);
|
|
} else if (_state == kStateOverwrite) {
|
|
if (kbd.keycode == Common::KEYCODE_RETURN) {
|
|
save();
|
|
changeState(kStateNormal);
|
|
}
|
|
} else if (_state == kStateDelete) {
|
|
if (kbd.keycode == Common::KEYCODE_RETURN) {
|
|
deleteSave();
|
|
changeState(kStateNormal);
|
|
}
|
|
}
|
|
}
|
|
|
|
void KIASectionSave::handleMouseMove(int mouseX, int mouseY) {
|
|
_mouseX = mouseX;
|
|
_mouseY = mouseY;
|
|
|
|
_buttons->handleMouseAction(_mouseX, _mouseY, false, false, false);
|
|
|
|
if (_state == kStateNormal) {
|
|
_uiContainer->handleMouseMove(_mouseX, _mouseY);
|
|
}
|
|
}
|
|
|
|
void KIASectionSave::handleMouseDown(bool mainButton) {
|
|
if (mainButton) {
|
|
if (_state == kStateNormal) {
|
|
_uiContainer->handleMouseDown(false);
|
|
}
|
|
|
|
_buttons->handleMouseAction(_mouseX, _mouseY, true, false, false);
|
|
}
|
|
}
|
|
|
|
void KIASectionSave::handleMouseUp(bool mainButton) {
|
|
if (mainButton) {
|
|
_buttons->handleMouseAction(_mouseX, _mouseY, false, true, false);
|
|
|
|
if (_state == kStateNormal) {
|
|
_uiContainer->handleMouseUp(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void KIASectionSave::handleMouseScroll(int direction) {
|
|
if (_state == kStateNormal) {
|
|
_uiContainer->handleMouseScroll(direction);
|
|
}
|
|
}
|
|
|
|
|
|
void KIASectionSave::scrollBoxCallback(void *callbackData, void *source, int lineData, int mouseButton) {
|
|
KIASectionSave *self = (KIASectionSave *)callbackData;
|
|
|
|
if (mouseButton == 0 && source == self->_scrollBox && lineData >= 0 && lineData <= (int)self->_saveList.size()) {
|
|
self->_scrollBox->resetFlags(self->_selectedLineId, 8);
|
|
self->_selectedLineId = lineData;
|
|
self->_scrollBox->setFlags(self->_selectedLineId, 8);
|
|
|
|
if (self->_selectedLineId == self->_newSaveLineId) {
|
|
self->_inputBox->setText("");
|
|
} else {
|
|
self->_inputBox->setText(self->_saveList[self->_selectedLineId].getDescription());
|
|
}
|
|
|
|
self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(kSfxSPNBEEP3), 40, 0, 0, 50, 0);
|
|
self->_vm->_kia->resume();
|
|
}
|
|
}
|
|
|
|
void KIASectionSave::inputBoxCallback(void *callbackData, void *source) {
|
|
KIASectionSave *self = (KIASectionSave *)callbackData;
|
|
if (source == self->_inputBox) {
|
|
if (self->_selectedLineId == self->_newSaveLineId) {
|
|
self->save();
|
|
} else {
|
|
self->changeState(kStateOverwrite);
|
|
}
|
|
}
|
|
}
|
|
|
|
void KIASectionSave::onButtonPressed(int buttonId, void *callbackData) {
|
|
KIASectionSave *self = (KIASectionSave *)callbackData;
|
|
|
|
if (buttonId == 0) {
|
|
if (self->_selectedLineId == self->_newSaveLineId)
|
|
{
|
|
self->save();
|
|
}
|
|
else
|
|
{
|
|
self->changeState(kStateOverwrite);
|
|
}
|
|
} else if (buttonId == 1) {
|
|
self->changeState(kStateNormal);
|
|
self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(kSfxSPNBEEP6), 90, -50, -50, 50, 0);
|
|
} else if (buttonId == 2) {
|
|
if (self->_state == kStateOverwrite)
|
|
{
|
|
self->save();
|
|
}
|
|
else if (self->_state == kStateDelete)
|
|
{
|
|
self->deleteSave();
|
|
}
|
|
}
|
|
}
|
|
|
|
void KIASectionSave::changeState(State state) {
|
|
_state = state;
|
|
if (state == kStateNormal) {
|
|
_buttons->resetImages();
|
|
_buttons->defineImage(
|
|
0,
|
|
Common::Rect(460, 366, 497, 402),
|
|
_vm->_kia->_shapes->get(82),
|
|
_vm->_kia->_shapes->get(83),
|
|
_vm->_kia->_shapes->get(84),
|
|
_vm->_textOptions->getText(22) // Save
|
|
);
|
|
} else {
|
|
_buttons->resetImages();
|
|
_buttons->defineImage(
|
|
1,
|
|
Common::Rect(318, 260, 357, 299),
|
|
_vm->_kia->_shapes->get(126),
|
|
_vm->_kia->_shapes->get(127),
|
|
_vm->_kia->_shapes->get(128),
|
|
_vm->_textOptions->getText(38) // No
|
|
);
|
|
_buttons->defineImage(
|
|
2,
|
|
Common::Rect(258, 260, 297, 299),
|
|
_vm->_kia->_shapes->get(129),
|
|
_vm->_kia->_shapes->get(130),
|
|
_vm->_kia->_shapes->get(131),
|
|
_vm->_textOptions->getText(39) // Yes
|
|
);
|
|
_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxSPNBEEP7), 90, 0, 0, 50, 0);
|
|
}
|
|
}
|
|
|
|
void KIASectionSave::save() {
|
|
int slot = -1;
|
|
|
|
if (_selectedLineId < (int)_saveList.size()) {
|
|
slot = _saveList[_selectedLineId].getSaveSlot();
|
|
} else {
|
|
// Find first available save slot
|
|
int maxSlot = -1;
|
|
for (int i = 0; i < (int)_saveList.size(); ++i) {
|
|
maxSlot = MAX(maxSlot, _saveList[i].getSaveSlot());
|
|
if (_saveList[i].getSaveSlot() != i) {
|
|
slot = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (slot == -1) {
|
|
slot = maxSlot + 1;
|
|
}
|
|
}
|
|
|
|
Common::OutSaveFile *saveFile = BladeRunner::SaveFileManager::openForSaving(_vm->getTargetName(), slot);
|
|
if (saveFile == nullptr || saveFile->err()) {
|
|
delete saveFile;
|
|
warning("KIASectionSave::save(): Can not open savegame file for writing");
|
|
return;
|
|
}
|
|
|
|
BladeRunner::SaveFileHeader header;
|
|
header._name = _inputBox->getText();
|
|
header._playTime = _vm->getTotalPlayTime();
|
|
|
|
BladeRunner::SaveFileManager::writeHeader(*saveFile, header);
|
|
|
|
_vm->saveGame(*saveFile, _vm->_kia->_thumbnail);
|
|
|
|
saveFile->finalize();
|
|
|
|
delete saveFile;
|
|
|
|
_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(kSfxELECBP1), 90, 0, 0, 50, 0);
|
|
|
|
_scheduledSwitch = true;
|
|
}
|
|
void KIASectionSave::deleteSave() {
|
|
BladeRunner::SaveFileManager::remove(_vm->getTargetName(), _saveList[_selectedLineId].getSaveSlot());
|
|
close();
|
|
open();
|
|
}
|
|
|
|
} // End of namespace BladeRunner
|