scummvm/engines/bladerunner/ui/kia_section_save.cpp
2019-06-28 15:30:44 +03:00

429 lines
12 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/text_resource.h"
#include "bladerunner/time.h"
#include "bladerunner/game_constants.h"
#include "bladerunner/ui/kia.h"
#include "bladerunner/ui/kia_shapes.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 had limit 41 characters
_uiContainer->add(_inputBox);
_inputBox->hide();
_buttons = new UIImagePicker(_vm, 3);
_timeLast = 0;
_timeLeft = 0;
_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 = 800;
}
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->getTextWidth(textChooseSlot);
_vm->_mainFont->drawColor(textChooseSlot, surface, 308 - textChooseSlotWidth / 2, 143, surface.format.RGBToColor(240, 232, 192));
// Original game shows warnings/error here, but we don't have any
const char *textTypeName = _vm->_textOptions->getText(24); // Type a name ...
int textTypeNameWidth = _vm->_mainFont->getTextWidth(textTypeName);
_vm->_mainFont->drawColor(textTypeName, surface, 308 - textTypeNameWidth / 2, 352, 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->getTextWidth(saveName);
_vm->_mainFont->drawColor(saveName, surface, 308 - saveNameWidth / 2, 230, surface.format.RGBToColor(232, 208, 136));
const char *textOverwrite = _vm->_textOptions->getText(35); // Overwrite previously saved game?
int textOverwriteWidth = _vm->_mainFont->getTextWidth(textOverwrite);
_vm->_mainFont->drawColor(textOverwrite, surface, 308 - textOverwriteWidth / 2, 240, 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->getTextWidth(saveName); // Delete this game?
_vm->_mainFont->drawColor(saveName, surface, 308 - saveNameWidth / 2, 230, surface.format.RGBToColor(232, 208, 136));
const char *textDelete = _vm->_textOptions->getText(40);
int textDeleteWidth = _vm->_mainFont->getTextWidth(textDelete);
_vm->_mainFont->drawColor(textDelete, surface, 308 - textDeleteWidth / 2, 240, surface.format.RGBToColor(240, 232, 192));
}
int selectedLineId = _scrollBox->getSelectedLineData();
if (selectedLineId != _hoveredLineId) {
if (selectedLineId >= 0 && selectedLineId < (int)_saveList.size() && _displayingLineId != selectedLineId) {
if (_timeLeft == 0) {
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 = 800;
_displayingLineId = -1;
}
_hoveredLineId = selectedLineId;
}
uint32 now = _vm->_time->currentSystem();
if (selectedLineId >= 0 && selectedLineId < (int)_saveList.size() && _displayingLineId != selectedLineId) {
if (_timeLeft) {
uint32 timeDiff = now - _timeLast;
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 -= 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