diff options
author | Peter Kohaut | 2018-01-14 12:12:06 +0100 |
---|---|---|
committer | Peter Kohaut | 2018-01-28 10:57:16 +0100 |
commit | 1e5f9d3078f236f306b5d868bcd52f4e47f7b512 (patch) | |
tree | 0d402af27d75064d60e4674ab3bd4c9ad08759f1 /engines/bladerunner/ui | |
parent | 3a937f19c0a5e347c801c62d345475be082f9e41 (diff) | |
download | scummvm-rg350-1e5f9d3078f236f306b5d868bcd52f4e47f7b512.tar.gz scummvm-rg350-1e5f9d3078f236f306b5d868bcd52f4e47f7b512.tar.bz2 scummvm-rg350-1e5f9d3078f236f306b5d868bcd52f4e47f7b512.zip |
BLADERUNNER: Added basic KIA interface
Settings works
Help works
Clue database works
Fixed code for inserting objects into scene
Reorganization of few files
Unification & code formatting of few older files
Diffstat (limited to 'engines/bladerunner/ui')
38 files changed, 5968 insertions, 0 deletions
diff --git a/engines/bladerunner/ui/elevator.cpp b/engines/bladerunner/ui/elevator.cpp new file mode 100644 index 0000000000..f0c8d7d921 --- /dev/null +++ b/engines/bladerunner/ui/elevator.cpp @@ -0,0 +1,325 @@ +/* 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/elevator.h" + +#include "bladerunner/actor.h" +#include "bladerunner/bladerunner.h" +#include "bladerunner/audio_player.h" +#include "bladerunner/game_info.h" +#include "bladerunner/mouse.h" +#include "bladerunner/shape.h" +#include "bladerunner/script/script.h" +#include "bladerunner/ui/ui_image_picker.h" +#include "bladerunner/vqa_player.h" + +#include "common/rect.h" +#include "common/str.h" +#include "common/system.h" + +namespace BladeRunner { + +Elevator::Elevator(BladeRunnerEngine *vm) { + _vm = vm; + reset(); + _imagePicker = new UIImagePicker(vm, 8); +} + +Elevator::~Elevator() { + delete _imagePicker; + reset(); +} + +int Elevator::activate(int elevatorId) { + const char *vqaName; + + if (elevatorId == 1) { + _buttonClicked = 3; + vqaName = "MA06ELEV.VQA"; + } else if (elevatorId == 2) { + _buttonClicked = 1; + vqaName = "PS02ELEV.VQA"; + } else { + error("Invalid elevator id"); + } + + if (!_vm->openArchive("MODE.MIX")) { + return 0; + } + + _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack); + if (!_vqaPlayer->open(vqaName)) { + return 0; + } + + _vqaPlayer->setLoop(1, -1, kLoopSetModeJustStart, nullptr, nullptr); + _vm->_mouse->setCursor(0); + + for (int i = 0; i != 16; ++i) { + _shapes.push_back(new Shape(_vm)); + _shapes[i]->readFromContainer("ELEVATOR.SHP", i); + } + + _imagePicker->resetImages(); + + if (elevatorId == 1) { + _imagePicker->defineImage( + 0, + Common::Rect(220, 298, 308, 392), + nullptr, + _shapes[11], + _shapes[14], + nullptr); + _imagePicker->defineImage( + 1, + Common::Rect(259, 259, 302, 292), + nullptr, + _shapes[10], + _shapes[13], + nullptr); + _imagePicker->defineImage( + 2, + Common::Rect(227, 398, 301, 434), + nullptr, + _shapes[12], + _shapes[15], + nullptr); + } else { + _imagePicker->defineImage( + 4, + Common::Rect(395, 131, 448, 164), + nullptr, + _shapes[0], + _shapes[5], + nullptr + ); + _imagePicker->defineImage( + 3, + Common::Rect(395, 165, 448, 198), + nullptr, + _shapes[1], + _shapes[6], + nullptr + ); + _imagePicker->defineImage( + 5, + Common::Rect(395, 199, 448, 232), + nullptr, + _shapes[2], + _shapes[7], + nullptr + ); + _imagePicker->defineImage( + 6, + Common::Rect(395, 233, 448, 264), + nullptr, + _shapes[3], + _shapes[8], + nullptr + ); + _imagePicker->defineImage( + 7, + Common::Rect(395, 265, 448, 295), + nullptr, + _shapes[4], + _shapes[9], + nullptr + ); + } + + _imagePicker->activate( + mouseInCallback, + mouseOutCallback, + mouseDownCallback, + mouseUpCallback, + this + ); + + open(); + + // TODO: time->lock(); + + _buttonClicked = -1; + do { + _vm->gameTick(); + } while (_buttonClicked == -1); + + _imagePicker->deactivate(); + + _vqaPlayer->close(); + delete _vqaPlayer; + + for (int i = 0; i != (int)_shapes.size(); ++i) { + delete _shapes[i]; + } + _shapes.clear(); + + _vm->closeArchive("MODE.MIX"); + + _isOpen = false; + + // TODO: time->unlock(); + + return _buttonClicked; +} + +void Elevator::open() { + resetDescription(); + _isOpen = true; +} + +bool Elevator::isOpen() const { + return _isOpen; +} + +int Elevator::handleMouseUp(int x, int y) { + _imagePicker->handleMouseAction(x, y, false, true, false); + return false; +} + +int Elevator::handleMouseDown(int x, int y) { + _imagePicker->handleMouseAction(x, y, true, false, false); + return false; +} + +void Elevator::tick() { + if (!_vm->_gameIsRunning) { + return; + } + + int frame = _vqaPlayer->update(); + assert(frame >= -1); + + // vqaPlayer renders to _surfaceBack + blit(_vm->_surfaceBack, _vm->_surfaceFront); + + Common::Point p = _vm->getMousePos(); + + // TODO(madmoose): BLADE.EXE has hasHoveredImage before handleMouseAction? + _imagePicker->handleMouseAction(p.x, p.y, false, false, false); + if (_imagePicker->hasHoveredImage()) { + _vm->_mouse->setCursor(1); + } else { + _vm->_mouse->setCursor(0); + } + + _imagePicker->draw(_vm->_surfaceFront); + _vm->_mouse->draw(_vm->_surfaceFront, p.x, p.y); + + _vm->blitToScreen(_vm->_surfaceFront); + tickDescription(); + _vm->_system->delayMillis(10); +} + +void Elevator::buttonClick(int buttonId) { + _buttonClicked = buttonId; +} + +void Elevator::reset() { + _isOpen = false; + _vqaPlayer = nullptr; + _imagePicker = nullptr; + _actorId = -1; + _sentenceId = -1; + _timeSpeakDescription = 0; +} + +void Elevator::buttonFocus(int buttonId) { + switch (buttonId) { + case 7: + setupDescription(kActorAnsweringMachine, 140); + break; + case 6: + setupDescription(kActorAnsweringMachine, 130); + break; + case 5: + setupDescription(kActorAnsweringMachine, 120); + break; + case 4: + setupDescription(kActorAnsweringMachine, 100); + break; + case 3: + setupDescription(kActorAnsweringMachine, 110); + break; + case 2: + setupDescription(kActorAnsweringMachine, 130); + break; + case 1: + setupDescription(kActorAnsweringMachine, 100); + break; + case 0: + setupDescription(kActorAnsweringMachine, 150); + break; + default: + resetDescription(); + break; + } +} + +void Elevator::setupDescription(int actorId, int sentenceId) { + _actorId = actorId; + _sentenceId = sentenceId; + + // TODO: Use proper timer + _timeSpeakDescription = _vm->getTotalPlayTime() + 600; +} + +void Elevator::resetDescription() { + _actorId = -1; + _sentenceId = -1; + _timeSpeakDescription = 0; +} + +void Elevator::tickDescription() { + int now = _vm->getTotalPlayTime(); + if (_actorId <= 0 || now < _timeSpeakDescription) { + return; + } + + _vm->_actors[_actorId]->speechPlay(_sentenceId, false); + _actorId = -1; + _sentenceId = -1; +} + +void Elevator::resume() { + // TODO +} + +void Elevator::mouseInCallback(int buttonId, void *self) { + ((Elevator *)self)->buttonFocus(buttonId); +} + +void Elevator::mouseOutCallback(int, void *self) { + ((Elevator *)self)->buttonFocus(-1); +} + +void Elevator::mouseDownCallback(int, void *self) { + Elevator *elevator = ((Elevator *)self); + const char *name = elevator->_vm->_gameInfo->getSfxTrack(515); + elevator->_vm->_audioPlayer->playAud(name, 100, 0, 0, 50, 0); +} + +void Elevator::mouseUpCallback(int buttonId, void *self) { + ((Elevator *)self)->buttonClick(buttonId); +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/elevator.h b/engines/bladerunner/ui/elevator.h new file mode 100644 index 0000000000..f2e1443929 --- /dev/null +++ b/engines/bladerunner/ui/elevator.h @@ -0,0 +1,73 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_ELEVATOR_H +#define BLADERUNNER_ELEVATOR_H + +#include "common/array.h" + +namespace BladeRunner { + +class BladeRunnerEngine; +class Shape; +class VQAPlayer; +class UIImagePicker; + +class Elevator { + BladeRunnerEngine *_vm; + bool _isOpen; + VQAPlayer *_vqaPlayer; + int _buttonClicked; + Common::Array<Shape *> _shapes; + UIImagePicker *_imagePicker; + int _actorId; + int _sentenceId; + int _timeSpeakDescription; + +public: + Elevator(BladeRunnerEngine *vm); + ~Elevator(); + + int activate(int elevatorId); + void open(); + bool isOpen() const; + int handleMouseUp(int x, int y); + int handleMouseDown(int x, int y); + void tick(); + void buttonClick(int buttonId); + void reset(); + void buttonFocus(int buttonId); + void setupDescription(int actorId, int sentenceId); + void resetDescription(); + void tickDescription(); + void resume(); + +private: + static void mouseInCallback(int, void *); + static void mouseOutCallback(int, void *); + static void mouseDownCallback(int, void *); + static void mouseUpCallback(int, void *); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/kia.cpp b/engines/bladerunner/ui/kia.cpp new file mode 100644 index 0000000000..09c5918872 --- /dev/null +++ b/engines/bladerunner/ui/kia.cpp @@ -0,0 +1,1229 @@ +/* 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.h" + +#include "bladerunner/actor.h" +#include "bladerunner/audio_player.h" +#include "bladerunner/bladerunner.h" +#include "bladerunner/combat.h" +#include "bladerunner/font.h" +#include "bladerunner/game_constants.h" +#include "bladerunner/game_flags.h" +#include "bladerunner/game_info.h" +#include "bladerunner/mouse.h" +#include "bladerunner/scene.h" +#include "bladerunner/shape.h" +#include "bladerunner/script/kia.h" +#include "bladerunner/settings.h" +#include "bladerunner/slice_renderer.h" +#include "bladerunner/text_resource.h" +#include "bladerunner/ui/kia_log.h" +#include "bladerunner/ui/kia_section_base.h" +#include "bladerunner/ui/kia_section_clues.h" +#include "bladerunner/ui/kia_section_crimes.h" +#include "bladerunner/ui/kia_section_diagnostic.h" +#include "bladerunner/ui/kia_section_help.h" +#include "bladerunner/ui/kia_section_load.h" +#include "bladerunner/ui/kia_section_settings.h" +#include "bladerunner/ui/kia_section_pogo.h" +#include "bladerunner/ui/kia_section_save.h" +#include "bladerunner/ui/kia_section_suspects.h" +#include "bladerunner/ui/kia_shapes.h" +#include "bladerunner/ui/ui_image_picker.h" +#include "bladerunner/vqa_player.h" + +#include "common/str.h" +#include "common/keyboard.h" + +namespace BladeRunner { + +const char *KIA::kPogo = "POGO"; + +enum KIASections { + kKIASectionNone = 0, + kKIASectionCrimes = 1, + kKIASectionSuspects = 2, + kKIASectionClues = 3, + kKIASectionSettings = 4, + kKIASectionHelp = 5, + kKIASectionSave = 6, + kKIASectionLoad = 7, + kKIASectionQuit = 8, + kKIASectionDiagnostic = 9, + kKIASectionPogo = 10 +}; + +KIA::KIA(BladeRunnerEngine *vm) { + _vm = vm; + + _script = new KIAScript(_vm); + _log = new KIALog(_vm); + _shapes = new KIAShapes(_vm); + + _forceOpen = 0; + _currentSectionId = kKIASectionNone; + _lastSectionIdKIA = kKIASectionCrimes; + _lastSectionIdOptions = kKIASectionSettings; + _playerVqaTimeLast = _vm->getTotalPlayTime(); + _playerVqaFrame = 0; + _playerVisualizerState = 0; + _playerPhotographId = -1; + _playerPhotograph = nullptr; + _playerSliceModelId = -1; + _playerSliceModelAngle = 0.0f; + // _playerImage = nullptr; + _timeLast = _vm->getTotalPlayTime(); + _playerActorDialogueQueueCapacity = 31; + _playerActorDialogueQueuePosition = 0; + _playerActorDialogueQueueSize = 0; + _playerActorDialogueQueue = new ActorDialogueQueueEntry[_playerActorDialogueQueueCapacity]; + _playerActorDialogueState = 0; + _currentSection = nullptr; + _mainVqaPlayer = nullptr; + _playerVqaPlayer = nullptr; + // _thumbnail = nullptr; + + _pogoPos = 0; + + _buttons = new UIImagePicker(_vm, 22); + + _crimesSection = new KIASectionCrimes(_vm); // PlayerActor->_clues + _suspectsSection = new KIASectionSuspects(_vm); // PlayerActor->_clues + _cluesSection = new KIASectionClues(_vm, _vm->_playerActor->_clues); + _settingsSection = new KIASectionSettings(_vm); + _helpSection = new KIASectionHelp(_vm); + _saveSection = new KIASectionSave(_vm); + _loadSection = new KIASectionLoad(_vm); + _diagnosticSection = new KIASectionDiagnostic(_vm); + _pogoSection = new KIASectionPogo(_vm); +} + +KIA::~KIA() { + delete _playerPhotograph; + // delete _playerImage; + // delete _thumbnail; + delete _settingsSection; + delete _buttons; + delete _shapes; + delete _log; + delete _script; +} + +void KIA::openLastOpened() { + open(_lastSectionIdKIA); +} + +void KIA::openOptions() { + open(kKIASectionSettings); +} + +void KIA::tick() { + if (!_currentSectionId) { + return; + } + + int timeNow = _vm->getTotalPlayTime(); + int timeDiff = timeNow - _timeLast; + + if (_playerActorDialogueQueueSize == _playerActorDialogueQueuePosition) { + _playerActorDialogueState = 0; + } else if (_playerActorDialogueState == 0) { + if (_playerSliceModelId == -1 && _playerPhotographId == -1) { //&& !this->_playerImage + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(495), 70, 0, 0, 50, 0); + } + _playerActorDialogueState = 1; + } else if (_playerActorDialogueState == 200) { + if (!_vm->_actors[_playerActorDialogueQueue[_playerActorDialogueQueuePosition].actorId]->isSpeeching()) { + if (_playerActorDialogueQueueSize != _playerActorDialogueQueuePosition) { + _playerActorDialogueQueuePosition = (_playerActorDialogueQueuePosition + 1) % _playerActorDialogueQueueCapacity; + } + if (_playerActorDialogueQueueSize != _playerActorDialogueQueuePosition) { + _vm->_actors[_playerActorDialogueQueue[_playerActorDialogueQueuePosition].actorId]->speechPlay(_playerActorDialogueQueue[_playerActorDialogueQueuePosition].sentenceId, true); + } + } + } else { + _playerActorDialogueState += timeDiff; + + if (_playerActorDialogueState >= 200) { + _playerActorDialogueState = 200; + _vm->_actors[_playerActorDialogueQueue[_playerActorDialogueQueuePosition].actorId]->speechPlay(_playerActorDialogueQueue[_playerActorDialogueQueuePosition].sentenceId, true); + } + } + + int timeDiffDiv48 = (timeNow - _playerVqaTimeLast) / 48; + if (timeDiffDiv48 > 0) { + _playerVqaTimeLast = timeNow; + if (_playerActorDialogueQueueSize == _playerActorDialogueQueuePosition || _playerSliceModelId != -1 || _playerPhotographId != -1) { // || this->_viewerImage + if (_playerVisualizerState > 0) { + _playerVisualizerState = MAX(_playerVisualizerState - timeDiffDiv48, 0); + } + } else { + if (_playerVisualizerState < 2) { + _playerVisualizerState = MIN(_playerVisualizerState + timeDiffDiv48, 2); + + } + } + + if ( _playerSliceModelId != -1 || _playerPhotographId != -1 ) { // || _playerImage + if (_playerVqaFrame < 8) { + int newVqaFrame = MIN(timeDiffDiv48 + _playerVqaFrame, 8); + if (_playerVqaFrame <= 0 && newVqaFrame > 0) { + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(497), 100, 70, 70, 50, 0); + } + _playerVqaFrame = newVqaFrame; + } + } else { + if (_playerVqaFrame > 0) { + int newVqaFrame = MAX(_playerVqaFrame - timeDiffDiv48, 0); + if (_playerVqaFrame >= 8 && newVqaFrame < 8) + { + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(496), 100, 70, 70, 50, 0); + } + _playerVqaFrame = newVqaFrame; + } + } + } + + _mainVqaPlayer->update(false); + blit(_vm->_surfaceBack, _vm->_surfaceFront); + + Common::Point mouse = _vm->getMousePos(); + + if (!_transitionId) { + _buttons->handleMouseAction(mouse.x, mouse.y, false, false, false); + if (_buttons->hasHoveredImage()) { + _vm->_mouse->setCursor(1); + } else { + _vm->_mouse->setCursor(0); + } + if (_currentSection) { + _currentSection->handleMouseMove(mouse.x, mouse.y); + } + } + + if (_vm->_gameFlags->query(kFlagKIAPrivacyAddon)) { + _shapes->get(40)->draw(_vm->_surfaceFront, 0, 0); + _shapes->get(41)->draw(_vm->_surfaceFront, 211, 447); + } + if (_currentSectionId != kKIASectionQuit && _transitionId != 14) { + if (_vm->_settings->getDifficulty() > 0) { + _vm->_mainFont->drawColor(Common::String::format("%04d", _vm->_gameVars[2]), _vm->_surfaceFront, 580, 341, 0x2991); + } else { + _shapes->get(39)->draw(_vm->_surfaceFront, 583, 342); + } + } + _playerVqaPlayer->seekToFrame(_playerVqaFrame); + _playerVqaPlayer->update(true); //_vm->_surfaceFront, 3 + + _playerSliceModelAngle += (float)(timeDiff) * 1.0f/400.0f; + while (_playerSliceModelAngle >= 2 * M_PI) { + _playerSliceModelAngle -= (float)(2 * M_PI); + } + + if (_playerVqaFrame == 8) { + if (_playerSliceModelId != -1) { + _vm->_sliceRenderer->drawOnScreen(_playerSliceModelId, 0, 585, 80, _playerSliceModelAngle, 100.0, _vm->_surfaceFront); + } else if (_playerPhotographId != -1) { + int width = _playerPhotograph->getWidth(); + int height = _playerPhotograph->getHeight(); + _playerPhotograph->draw(_vm->_surfaceFront, 590 - width / 2, 80 - height / 2); + } + // else if (_playerImage) { + // ... + // } + } + + if (_playerVisualizerState == 1) { + _shapes->get(51)->draw(_vm->_surfaceFront, 576, 174); + } else if (_playerVisualizerState == 2) { + _shapes->get(50)->draw(_vm->_surfaceFront, 576, 174); + _shapes->get(_vm->_rnd.getRandomNumberRng(90, 105))->draw(_vm->_surfaceFront, 576, 174); + } + if (!_transitionId) { + _buttons->draw(_vm->_surfaceFront); + if (_currentSection) { + _currentSection->draw(_vm->_surfaceFront); + } + } + if (_vm->_settings->getAmmoAmount(0) > 0) { + if (_vm->_settings->getAmmoType() == 0) { + _shapes->get(42)->draw(_vm->_surfaceFront, 147, 405); + } else { + _shapes->get(45)->draw(_vm->_surfaceFront, 140, 446); + } + } + if (_vm->_settings->getAmmoAmount(1) > 0) { + if (_vm->_settings->getAmmoType() == 1) { + _shapes->get(43)->draw(_vm->_surfaceFront, 167, 394); + } else { + _shapes->get(46)->draw(_vm->_surfaceFront, 160, 446); + } + } + if (_vm->_settings->getAmmoAmount(2) > 0) { + if (_vm->_settings->getAmmoType() == 2) { + _shapes->get(44)->draw(_vm->_surfaceFront, 189, 385); + } else { + _shapes->get(47)->draw(_vm->_surfaceFront, 182, 446); + } + } + _vm->_mainFont->drawColor("1.00", _vm->_surfaceFront, 438, 471, 0x1CE7); + if (!_transitionId) { + _buttons->drawTooltip(_vm->_surfaceFront, mouse.x, mouse.y); + } + _vm->_mouse->draw(_vm->_surfaceFront, mouse.x, mouse.y); + _vm->blitToScreen(_vm->_surfaceFront); + + _timeLast = timeNow; +} + +void KIA::handleMouseDown(int mouseX, int mouseY, bool mainButton) { + if (!_currentSectionId) { + return; + } + if (mainButton) { + _buttons->handleMouseAction(mouseX, mouseY, true, false, false); + } + if (_currentSection) { + _currentSection->handleMouseDown(mainButton); + } +} + +void KIA::handleMouseUp(int mouseX, int mouseY, bool mainButton) { + if (!_currentSectionId) { + return; + } + if (mainButton) { + _buttons->handleMouseAction(mouseX, mouseY, false, true, false); + } + if (_currentSection) { + _currentSection->handleMouseUp(mainButton); + } + if (_currentSection && _currentSection->_field0) { + if (_currentSectionId == kKIASectionCrimes) { + open(kKIASectionSuspects); + // kiaSuspects::sub_45290C(_suspectsMenu, _crimesMenu->selectedSuspectId); + _log->next(); + _log->clearFuture(); + } else if (_currentSectionId == kKIASectionSuspects) { + open(kKIASectionCrimes); + // kiaCrimes::updateCrime(_crimesMenu, *&_suspectsMenu->data[8052]); + _log->next(); + _log->clearFuture(); + } else { + open(kKIASectionNone); + } + } +} + +void KIA::handleKeyUp(const Common::KeyState &kbd) { + if (!_currentSectionId) { + return; + } + + if (toupper(kbd.ascii) != kPogo[_pogoPos]) { + _pogoPos = 0; + } + if (_currentSectionId != kKIASectionSave) { + if (toupper(kbd.ascii) == kPogo[_pogoPos]) { + ++_pogoPos; + if (!kPogo[_pogoPos]) { + open(kKIASectionPogo); + _pogoPos = 0; + } + } + } + if (kbd.keycode == Common::KEYCODE_ESCAPE) { + if (!_forceOpen) { + open(kKIASectionNone); + } + } else { + if (_currentSection) { + _currentSection->handleKeyUp(kbd); + } + } + if (_currentSection && _currentSection->_field0) { + open(kKIASectionNone); + } +} + +void KIA::handleKeyDown(const Common::KeyState &kbd) { + if (!_currentSectionId) { + return; + } + switch (kbd.keycode) { + case Common::KEYCODE_F1: + open(kKIASectionHelp); + break; + case Common::KEYCODE_F2: + if (!_forceOpen) { + open(kKIASectionSave); + } + break; + case Common::KEYCODE_F3: + open(kKIASectionLoad); + break; + case Common::KEYCODE_F10: + open(kKIASectionQuit); + break; + case Common::KEYCODE_F4: + if (_currentSectionId != kKIASectionCrimes) { + if (!_forceOpen) { + open(kKIASectionCrimes); + _log->next(); + _log->clearFuture(); + } + } + break; + case Common::KEYCODE_F5: + if (_currentSectionId != kKIASectionSuspects) { + if (_forceOpen) { + open(kKIASectionSuspects); + _log->next(); + _log->clearFuture(); + } + } + break; + case Common::KEYCODE_F6: + if (_currentSectionId != kKIASectionClues) { + if (!_forceOpen) { + open(kKIASectionClues); + _log->next(); + _log->clearFuture(); + } + } + break; + default: + if (_currentSection) { + _currentSection->handleKeyDown(kbd); + } + break; + } + if (_currentSection && _currentSection->_field0) { + open(kKIASectionNone); + } +} + +void KIA::playerReset() { + if (_playerActorDialogueQueueSize != _playerActorDialogueQueuePosition) { + if (_playerActorDialogueQueueSize != _playerActorDialogueQueuePosition) { + int actorId = _playerActorDialogueQueue[_playerActorDialogueQueuePosition].actorId; + if (_vm->_actors[actorId]->isSpeeching()) { + _vm->_actors[actorId]->speechStop(); + } + } + } + _playerActorDialogueQueueSize = _playerActorDialogueQueuePosition; + _playerSliceModelId = -1; + if (_playerPhotographId != -1) { + delete _playerPhotograph; + _playerPhotograph = nullptr; + } + _playerPhotographId = -1; + // delete _playerImage; + // _playerImage = nullptr; + _playerActorDialogueState = 0; +} + +void KIA::playActorDialogue(int actorId, int sentenceId) { + int newQueueSize = (_playerActorDialogueQueueSize + 1) % _playerActorDialogueQueueCapacity; + if (newQueueSize != _playerActorDialogueQueuePosition) { + _playerActorDialogueQueue[_playerActorDialogueQueueSize].actorId = actorId; + _playerActorDialogueQueue[_playerActorDialogueQueueSize].sentenceId = sentenceId; + _playerActorDialogueQueueSize = newQueueSize; + } +} + +void KIA::playSliceModel(int sliceModelId) { + if (_playerVqaFrame == 8) { + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(502), 70, 0, 0, 50, 0); + } + _playerSliceModelId = sliceModelId; +} + +void KIA::playPhotograph(int photographId) { + if (_playerPhotographId != -1) { + delete _playerPhotograph; + _playerPhotograph = nullptr; + } + if (_playerVqaFrame == 8) { + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(502), 70, 0, 0, 50, 0); + } + _playerPhotographId = photographId; + _playerPhotograph = new Shape(_vm); + _playerPhotograph->readFromContainer("photos.shp", photographId); +} + +void KIA::mouseDownCallback(int buttonId, void *callbackData) { + KIA *self = (KIA *)callbackData; + switch (buttonId) { + case 0: + case 6: + self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(503), 100, -65, -65, 50, 0); + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(505), 70, 0, 0, 50, 0); + if (buttonId == 12){ + self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(596), 70, 0, 0, 50, 0); + } + break; + case 15: + self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(503), 70, 0, 0, 50, 0); + break; + } +} + +void KIA::mouseUpCallback(int buttonId, void *callbackData) { + KIA *self = (KIA *)callbackData; + switch (buttonId) { + case 0: + case 6: + self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(504), 100, -65, -65, 50, 0); + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(506), 70, 0, 0, 50, 0); + break; + case 15: + self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(504), 100, 0, 0, 50, 0); + break; + default: + break; + } + self->buttonClicked(buttonId); +} + +void KIA::loopEnded(void *callbackData, int frame, int loopId) { + KIA *self = (KIA *)callbackData; + self->_mainVqaPlayer->setLoop(self->getVqaLoopMain(self->_currentSectionId) + 1, -1, kLoopSetModeJustStart, nullptr, nullptr); + self->_transitionId = 0; +} + +void KIA::open(int sectionId) { + if (_currentSectionId == sectionId) { + return; + } + + if (!sectionId) { + unload(); + return; + } + + if (!_currentSectionId) { + init(); + } + + switch (_currentSectionId) { + case kKIASectionCrimes: + _crimesSection->saveToLog(); + break; + case kKIASectionSuspects: + _suspectsSection->saveToLog(); + break; + case kKIASectionClues: + _cluesSection->saveToLog(); + break; + } + + if (sectionId != kKIASectionCrimes && sectionId != kKIASectionSuspects && sectionId != kKIASectionClues) { + playerReset(); + } + + _transitionId = getTransitionId(_currentSectionId, sectionId); + const char *name = getSectionVqaName(sectionId); + if (getSectionVqaName(_currentSectionId) != name) { + if (_mainVqaPlayer) { + _mainVqaPlayer->close(); + delete _mainVqaPlayer; + _mainVqaPlayer = nullptr; + } + + _mainVqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack); + _mainVqaPlayer->open(name); + } + + if (_transitionId) { + playTransitionSound(_transitionId); + _mainVqaPlayer->setLoop(getVqaLoopTransition(_transitionId), -1, kLoopSetModeImmediate, nullptr, nullptr); + _mainVqaPlayer->setLoop(getVqaLoopMain(sectionId), -1, kLoopSetModeEnqueue, loopEnded, this); + } else { + int loopId = getVqaLoopMain(sectionId); + _mainVqaPlayer->setLoop(loopId, -1, kLoopSetModeImmediate, nullptr, nullptr); + _mainVqaPlayer->setLoop(loopId + 1, -1, kLoopSetModeJustStart, nullptr, nullptr); + } + + _buttons->resetImages(); + createButtons(sectionId); + switchSection(sectionId); + _currentSectionId = sectionId; + + if (sectionId == kKIASectionCrimes || sectionId == kKIASectionSuspects || sectionId == kKIASectionClues) { + _lastSectionIdKIA = _currentSectionId; + } + + if (sectionId == kKIASectionSettings || sectionId == kKIASectionHelp || sectionId == kKIASectionSave || sectionId == kKIASectionLoad) { + _lastSectionIdOptions = _currentSectionId; + } +} + +void KIA::init() { + if (!_vm->openArchive("MODE.MIX")) { + return; + } + + playerReset(); + _playerVqaFrame = 0; + _playerVqaTimeLast = _vm->getTotalPlayTime(); + _timeLast = _vm->getTotalPlayTime(); + + if (_vm->_gameFlags->query(kFlagKIAPrivacyAddon) && !_vm->_gameFlags->query(kFlagKIAPrivacyAddonIntro)) { + _vm->_gameFlags->set(kFlagKIAPrivacyAddonIntro); + playPrivateAddon(); + } + + _shapes->load(); + _buttons->activate(nullptr, nullptr, mouseDownCallback, mouseUpCallback, this); + _vm->_mouse->setCursor(0); + if (_playerVqaPlayer == nullptr) { + + _playerVqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceFront); + _playerVqaPlayer->open("kiaover.vqa"); + _playerVqaPlayer->setLoop(0, -1, kLoopSetModeJustStart, nullptr, nullptr); + } + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(501), 70, 0, 0, 50, 0); + + // TODO: time->lock(); +} + +void KIA::unload() { + if (!_currentSectionId) { + return; + } + + _forceOpen = false; + + if (_currentSection) { + _currentSection->close(); + _currentSection = nullptr; + } + + _buttons->resetImages(); + _buttons->deactivate(); + + _shapes->unload(); + + if (_mainVqaPlayer) { + _mainVqaPlayer->close(); + delete _mainVqaPlayer; + _mainVqaPlayer = nullptr; + } + + if (_playerVqaPlayer) { + _playerVqaPlayer->close(); + delete _playerVqaPlayer; + _playerVqaPlayer = nullptr; + } + + _vm->closeArchive("MODE.MIX"); + + _currentSectionId = 0; + + // TODO: Unfreeze game time + + //if (!_vm->_settings->isLoadingGame(&Settings) && GameRunning) + // if (_vm->_gameIsRunning) { + // _vm->_scene->resume(false); + // } +} + +void KIA::createButtons(int sectionId) { + Common::Rect kiaButton6( 66, 00, 122, 44); + Common::Rect kiaButton7( 191, 29, 233, 70); + Common::Rect kiaButton8( 234, 29, 278, 70); + Common::Rect kiaButton9( 278, 29, 321, 70); + Common::Rect kiaButton10(322, 29, 365, 70); + Common::Rect kiaButton11(366, 29, 410, 70); + Common::Rect kiaButton12(420, 286, 472, 328); + Common::Rect kiaButton13(334, 286, 386, 328); + Common::Rect kiaButton14(411, 29, 453, 70); + Common::Rect kiaButton15(264, 9, 304, 26); + Common::Rect kiaButton16(140, 406, 160, 479); + Common::Rect kiaButton17(161, 406, 180, 479); + Common::Rect kiaButton18(181, 406, 202, 479); + Common::Rect kiaButton19(575, 307, 606, 350); + Common::Rect kiaButton21(211, 443, 291, 479); + + const Shape *shapeUp = nullptr; + const Shape *shapeHovered = nullptr; + const Shape *shapeDown = nullptr; + + switch (sectionId) { + case kKIASectionCrimes: + case kKIASectionSuspects: + case kKIASectionClues: + _buttons->defineImage(0, kiaButton6, nullptr, nullptr, _shapes->get(1), _vm->_textKIA->getText(23)); + + if (sectionId == kKIASectionCrimes) { + shapeUp = _shapes->get(2); + shapeHovered = _shapes->get(2); + shapeDown = _shapes->get(10); + } else { + shapeUp = nullptr; + shapeHovered = nullptr; + shapeDown = _shapes->get(18); + } + _buttons->defineImage(1, kiaButton7, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(24)); + + if (sectionId == kKIASectionSuspects) { + shapeUp = _shapes->get(3); + shapeHovered = _shapes->get(3); + shapeDown = _shapes->get(11); + } else { + shapeUp = nullptr; + shapeHovered = nullptr; + shapeDown = _shapes->get(19); + } + _buttons->defineImage(2, kiaButton8, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(25)); + + if (sectionId == kKIASectionClues) { + shapeUp = _shapes->get(4); + shapeHovered = _shapes->get(4); + shapeDown = _shapes->get(12); + } else { + shapeUp = nullptr; + shapeHovered = nullptr; + shapeDown = _shapes->get(20); + } + _buttons->defineImage(3, kiaButton9, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(26)); + + _buttons->defineImage(4, kiaButton10, nullptr, nullptr, _shapes->get(21), _vm->_textKIA->getText(27)); + + _buttons->defineImage(5, kiaButton11, nullptr, nullptr, _shapes->get(22), _vm->_textKIA->getText(28)); + + _buttons->defineImage(14, kiaButton14, nullptr, nullptr, _shapes->get(23), _vm->_textKIA->getText(29)); + + break; + case kKIASectionSettings: + case kKIASectionHelp: + case kKIASectionSave: + case kKIASectionLoad: + case kKIASectionDiagnostic: + case kKIASectionPogo: + _buttons->defineImage(6, kiaButton6, nullptr, nullptr, _shapes->get(0), _vm->_textKIA->getText(37)); + + if (sectionId == kKIASectionSettings) { + shapeUp = _shapes->get(5); + shapeHovered = _shapes->get(5); + shapeDown = _shapes->get(13); + } else { + shapeUp = nullptr; + shapeHovered = nullptr; + shapeDown = _shapes->get(24); + } + _buttons->defineImage(7, kiaButton7, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(38)); + + if (sectionId == kKIASectionHelp) { + shapeUp = _shapes->get(6); + shapeHovered = _shapes->get(6); + shapeDown = _shapes->get(14); + } else { + shapeUp = nullptr; + shapeHovered = nullptr; + shapeDown = _shapes->get(25); + } + _buttons->defineImage(8, kiaButton8, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(41)); + + if (sectionId == kKIASectionSave) { + shapeUp = _shapes->get(7); + shapeHovered = _shapes->get(7); + shapeDown = _shapes->get(15); + } else { + shapeUp = nullptr; + shapeHovered = nullptr; + shapeDown = _shapes->get(26); + } + _buttons->defineImage(9, kiaButton9, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(39)); + + if (sectionId == kKIASectionLoad) { + shapeUp = _shapes->get(8); + shapeHovered = _shapes->get(8); + shapeDown = _shapes->get(16); + } else { + shapeUp = nullptr; + shapeHovered = nullptr; + shapeDown = _shapes->get(27); + } + _buttons->defineImage(10, kiaButton10, shapeUp, shapeHovered, shapeDown, _vm->_textKIA->getText(40)); + + _buttons->defineImage(11, kiaButton11, nullptr, nullptr, _shapes->get(28), _vm->_textKIA->getText(42)); + + _buttons->defineImage(14, kiaButton14, nullptr, nullptr, _shapes->get(29), _vm->_textKIA->getText(29)); + + break; + case 8: + _buttons->defineImage(12, kiaButton12, _shapes->get(124), _shapes->get(124), _shapes->get(48), _vm->_textKIA->getText(42)); + + _buttons->defineImage(13, kiaButton13, _shapes->get(125), _shapes->get(125), _shapes->get(49), _vm->_textKIA->getText(29)); + break; + } + + if (sectionId != kKIASectionQuit) { + _buttons->defineImage(15, kiaButton15, nullptr, nullptr, _shapes->get(38), _vm->_textKIA->getText(43)); + + _buttons->defineImage(19, kiaButton19, nullptr, nullptr, nullptr, _vm->_textKIA->getText(44)); + + if (_vm->_settings->getAmmoAmount(0) > 0) { + _buttons->defineImage(16, kiaButton16, nullptr, nullptr, nullptr, _vm->_textKIA->getText(50)); + } + Common::String tooltip; + if (_vm->_settings->getAmmoAmount(1) > 0) { + if (_vm->_settings->getDifficulty() > 0) { + tooltip = Common::String::format("%d", _vm->_settings->getAmmoAmount(1)); + } else { + tooltip = _vm->_textKIA->getText(50); + } + _buttons->defineImage(17, kiaButton17, nullptr, nullptr, nullptr, tooltip.c_str()); + } + if (_vm->_settings->getAmmoAmount(2) > 0) { + if (_vm->_settings->getDifficulty() > 0) { + tooltip = Common::String::format("%d", _vm->_settings->getAmmoAmount(2)); + } else { + tooltip = _vm->_textKIA->getText(50); + } + _buttons->defineImage(18, kiaButton18, nullptr, nullptr, nullptr, tooltip.c_str()); + } + if (_vm->_gameFlags->query(kFlagKIAPrivacyAddon)) { + _buttons->defineImage(21, kiaButton21, nullptr, nullptr, nullptr, nullptr); + } + } +} + +void KIA::buttonClicked(int buttonId) { + int soundId = 0; + + if (!_currentSectionId) { + return; + } + switch (buttonId) { + case 0: + open(kKIASectionSettings); + break; + case 1: + if (_currentSectionId != kKIASectionCrimes) { + open(kKIASectionCrimes); + _log->next(); + _log->clearFuture(); + } + break; + case 2: + if (_currentSectionId != kKIASectionSuspects) { + open(kKIASectionSuspects); + _log->next(); + _log->clearFuture(); + } + break; + case 3: + if (_currentSectionId != kKIASectionClues) { + open(kKIASectionClues); + _log->next(); + _log->clearFuture(); + } + break; + case 4: + if (_log->hasPrev()) { + int kiaLogPrevType = _log->getPrevType(); + switch (kiaLogPrevType) { + case 2: + open(kKIASectionCrimes); + _log->prev(); + _crimesSection->loadFromLog(); + break; + case 1: + open(kKIASectionSuspects); + _log->prev(); + _suspectsSection->loadFromLog(); + break; + case 0: + open(kKIASectionClues); + _log->prev(); + _cluesSection->loadFromLog(); + break; + } + } + break; + case 5: + if (_log->hasNext()) { + int kiaLogNextType = _log->getNextType(); + switch (kiaLogNextType) { + case 2: + open(kKIASectionCrimes); + _log->next(); + _crimesSection->loadFromLog(); + break; + case 1: + open(kKIASectionSuspects); + _log->next(); + _suspectsSection->loadFromLog(); + break; + case 0: + open(kKIASectionClues); + _log->next(); + _cluesSection->loadFromLog(); + break; + } + } + break; + case 6: + if (!_forceOpen) { + open(_lastSectionIdKIA); + } + break; + case 7: + open(kKIASectionSettings); + break; + case 8: + open(kKIASectionHelp); + break; + case 9: + if (!_forceOpen) { + open(kKIASectionSave); + } + break; + case 10: + open(kKIASectionLoad); + break; + case 11: + open(kKIASectionQuit); + break; + case 12: + _vm->_gameIsRunning = false; + open(kKIASectionNone); + break; + case 13: + open(_lastSectionIdOptions); + break; + case 14: + if (!_forceOpen) { + open(kKIASectionNone); + } + break; + case 15: + open(kKIASectionDiagnostic); + break; + case 16: + _vm->_settings->setAmmoType(0); + if (_vm->_rnd.getRandomNumber(1)) { + soundId = _vm->_combat->getHitSound(); + } else { + soundId = _vm->_combat->getMissSound(); + } + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(soundId), 70, 0, 0, 50, 0); + break; + case 17: + _vm->_settings->setAmmoType(1); + if (_vm->_rnd.getRandomNumber(1)) { + soundId = _vm->_combat->getHitSound(); + } else { + soundId = _vm->_combat->getMissSound(); + } + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(soundId), 70, 0, 0, 50, 0); + break; + case 18: + _vm->_settings->setAmmoType(2); + if (_vm->_rnd.getRandomNumber(1)) { + soundId = _vm->_combat->getHitSound(); + } else { + soundId = _vm->_combat->getMissSound(); + } + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(soundId), 70, 0, 0, 50, 0); + break; + case 19: + return; + case 20: + playerReset(); + break; + case 21: + playPrivateAddon(); + break; + } +} + +void KIA::switchSection(int sectionId) { + if (_currentSection) { + _currentSection->close(); + } + switch (sectionId) { + case kKIASectionCrimes: + _currentSection = _crimesSection; + break; + case kKIASectionSuspects: + _currentSection = _suspectsSection; + break; + case kKIASectionClues: + _currentSection = _cluesSection; + break; + case kKIASectionSettings: + _currentSection = _settingsSection; + break; + case kKIASectionHelp: + _currentSection = _helpSection; + break; + case kKIASectionSave: + _currentSection = _saveSection; + break; + case kKIASectionLoad: + _currentSection = _loadSection; + break; + case kKIASectionQuit: + _currentSection = nullptr; + break; + case kKIASectionDiagnostic: + _currentSection = _diagnosticSection; + break; + case kKIASectionPogo: + _currentSection = _pogoSection; + break; + default: + _currentSection = nullptr; + break; + } + if (_currentSection) { + _currentSection->open(); + } +} + +const char *KIA::getSectionVqaName(int sectionId) { + switch (sectionId) { + case kKIASectionCrimes: + return "kia_crim.vqa"; + case kKIASectionSuspects: + return "kia_susp.vqa"; + case kKIASectionClues: + return "kia_clue.vqa"; + case kKIASectionSettings: + case kKIASectionHelp: + case kKIASectionSave: + case kKIASectionLoad: + case kKIASectionQuit: + case kKIASectionDiagnostic: + case kKIASectionPogo: + return "kia_ingm.vqa"; + default: + return nullptr; + } +} + +int KIA::getVqaLoopMain(int sectionId) { + switch (sectionId) { + case kKIASectionCrimes: + case kKIASectionSuspects: + case kKIASectionClues: + return 3; + case kKIASectionSettings: + case kKIASectionHelp: + case kKIASectionSave: + case kKIASectionLoad: + case kKIASectionDiagnostic: + case kKIASectionPogo: + return 4; + case kKIASectionQuit: + return 7; + default: + return 0; + } +} + +int KIA::getVqaLoopTransition(int transitionId) { + switch (transitionId) { + case 0: + case 2: + case 7: + case 8: + return 0; + case 1: + case 4: + case 5: + case 9: + return 1; + case 3: + case 10: + case 11: + case 12: + return 2; + case 6: + return 3; + case 13: + return 6; + default: + return 0; + } +} + +int KIA::getTransitionId(int oldSectionId, int newSectionId) { + switch (oldSectionId) { + case kKIASectionNone: + return 0; + case kKIASectionCrimes: + switch (newSectionId) { + case kKIASectionCrimes: + return 0; + case kKIASectionSuspects: + return 1; + case kKIASectionClues: + return 2; + case kKIASectionSettings: + case kKIASectionHelp: + case kKIASectionSave: + case kKIASectionLoad: + case kKIASectionDiagnostic: + case kKIASectionPogo: + return 3; + case kKIASectionQuit: + return 13; + } + return 0; + case kKIASectionSuspects: + switch (newSectionId) { + case kKIASectionCrimes: + return 4; + case kKIASectionSuspects: + return 0; + case kKIASectionClues: + return 5; + case kKIASectionSettings: + case kKIASectionHelp: + case kKIASectionSave: + case kKIASectionLoad: + case kKIASectionDiagnostic: + case kKIASectionPogo: + return 6; + case kKIASectionQuit: + return 13; + } + return 0; + case kKIASectionClues: + switch (newSectionId) { + case kKIASectionCrimes: + return 7; + case kKIASectionSuspects: + return 8; + case kKIASectionClues: + return 0; + case kKIASectionSettings: + case kKIASectionHelp: + case kKIASectionSave: + case kKIASectionLoad: + case kKIASectionDiagnostic: + case kKIASectionPogo: + return 9; + case kKIASectionQuit: + return 13; + } + return 0; + case kKIASectionSettings: + case kKIASectionHelp: + case kKIASectionSave: + case kKIASectionLoad: + case kKIASectionDiagnostic: + case kKIASectionPogo: + switch (newSectionId) { + case kKIASectionCrimes: + return 10; + case kKIASectionSuspects: + return 11; + case kKIASectionClues: + return 12; + case kKIASectionSettings: + case kKIASectionHelp: + case kKIASectionSave: + case kKIASectionLoad: + case kKIASectionDiagnostic: + case kKIASectionPogo: + return 0; + case kKIASectionQuit: + return 13; + } + return 0; + case kKIASectionQuit: + if (newSectionId != kKIASectionQuit) { + return 14; + } + } + return 0; +} + +void KIA::playTransitionSound(int transitionId) { + switch (transitionId) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(498), 100, 0, 0, 50, 0); + break; + case 13: + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(499), 100, 0, 0, 50, 0); + break; + case 14: + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(500), 100, 0, 0, 50, 0); + break; + } +} + +void KIA::playPrivateAddon() { + playerReset(); + playSliceModel(524); + playActorDialogue(14, 2060); + playActorDialogue(14, 2070); +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/kia.h b/engines/bladerunner/ui/kia.h new file mode 100644 index 0000000000..c979f9ff8b --- /dev/null +++ b/engines/bladerunner/ui/kia.h @@ -0,0 +1,155 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_KIA_H +#define BLADERUNNER_KIA_H + +#include "common/str.h" + + +namespace Common { +struct KeyState; +} + +namespace Graphics { +struct Surface; +} + +namespace BladeRunner { + +class BladeRunnerEngine; +class KIALog; +class KIAScript; +class KIASectionBase; +class KIASectionClues; +class KIASectionDiagnostic; +class KIASectionCrimes; +class KIASectionHelp; +class KIASectionLoad; +class KIASectionSettings; +class KIASectionPogo; +class KIASectionSave; +class KIASectionSuspects; +class KIAShapes; +class Shape; +class UIImagePicker; +class VQAPlayer; + +class KIA { + static const char *kPogo; + + struct ActorDialogueQueueEntry { + int actorId; + int sentenceId; + }; + + BladeRunnerEngine *_vm; + + int _forceOpen; + int _transitionId; + + int _lastSectionIdKIA; + int _lastSectionIdOptions; + + int _playerVqaTimeLast; + VQAPlayer *_playerVqaPlayer; + int _playerVqaFrame; + int _playerVisualizerState; + int _playerPhotographId; + Shape *_playerPhotograph; + int _playerSliceModelId; + float _playerSliceModelAngle; + int _timeLast; + + ActorDialogueQueueEntry *_playerActorDialogueQueue; + int _playerActorDialogueQueueCapacity; + int _playerActorDialogueQueuePosition; + int _playerActorDialogueQueueSize; + int _playerActorDialogueState; + + KIASectionBase *_currentSection; + KIASectionClues *_cluesSection; + KIASectionCrimes *_crimesSection; + KIASectionDiagnostic *_diagnosticSection; + KIASectionHelp *_helpSection; + KIASectionLoad *_loadSection; + KIASectionSettings *_settingsSection; + KIASectionPogo *_pogoSection; + KIASectionSave *_saveSection; + KIASectionSuspects *_suspectsSection; + + UIImagePicker *_buttons; + + VQAPlayer *_mainVqaPlayer; + + int _pogoPos; + +public: + int _currentSectionId; + KIALog *_log; + KIAScript *_script; + KIAShapes *_shapes; + +public: + KIA(BladeRunnerEngine *vm); + ~KIA(); + + void openLastOpened(); + void openOptions(); + + void tick(); + + void handleMouseDown(int mouseX, int mouseY, bool mainButton); + void handleMouseUp(int mouseX, int mouseY, bool mainButton); + void handleKeyUp(const Common::KeyState &kbd); + void handleKeyDown(const Common::KeyState &kbd); + + void playerReset(); + void playActorDialogue(int actorId, int sentenceId); + void playSliceModel(int sliceModelId); + void playPhotograph(int photographId); + +private: + static void mouseDownCallback(int buttonId, void *callbackData); + static void mouseUpCallback(int buttonId, void *callbackData); + static void loopEnded(void *callbackData, int frame, int loopId); + + void open(int sectionId); + void init(); + void unload(); + void switchSection(int sectionId); + + void createButtons(int sectionId); + void buttonClicked(int buttonId); + + const char *getSectionVqaName(int sectionId); + int getVqaLoopMain(int sectionId); + int getVqaLoopTransition(int transitionId); + + int getTransitionId(int oldSectionId, int newSectionId); + void playTransitionSound(int transitionId); + + void playPrivateAddon(); +}; + +} // End of namespace BladeRunner +#endif diff --git a/engines/bladerunner/ui/kia_log.cpp b/engines/bladerunner/ui/kia_log.cpp new file mode 100644 index 0000000000..51b922a8f7 --- /dev/null +++ b/engines/bladerunner/ui/kia_log.cpp @@ -0,0 +1,128 @@ +/* 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_log.h" + +#include "bladerunner/bladerunner.h" + +namespace BladeRunner { + +KIALog::KIALog(BladeRunnerEngine *vm) { + _vm = vm; + + _firstIndex = 0; + _lastIndex = 0; + _currentIndex = 0; + for (int i = 0; i < kSize; ++i) { + _entries[i].dataSize = 0; + _entries[i].data = nullptr; + } +} + +KIALog::~KIALog() { + clear(); +} + +void KIALog::add(int type, int dataSize, const void *data) { + if (_currentIndex == _lastIndex) { + _lastIndex = (_lastIndex + 1) % kSize; + } + + if (_entries[_currentIndex].data) { + delete[] _entries[_currentIndex].data; + } + + _entries[_currentIndex].type = type; + _entries[_currentIndex].dataSize = dataSize; + + if (dataSize > 0) { + char *dataCopy = new char[dataSize]; + memcpy(dataCopy, data, dataSize); + _entries[_currentIndex].data = dataCopy; + } else { + _entries[_currentIndex].data = nullptr; + } +} + +void KIALog::clear() { + _firstIndex = 0; + _lastIndex = 0; + _currentIndex = 0; + for (int i = 0; i < kSize; ++i) { + if (_entries[i].data) { + delete[] _entries[i].data; + } + _entries[i].dataSize = 0; + _entries[i].data = nullptr; + } +} + +void KIALog::prev() { + if (_currentIndex != _firstIndex) { + _currentIndex = (_currentIndex - 1) % kSize; + } +} + +void KIALog::next() { + if (_currentIndex != _lastIndex) { + _currentIndex = (_currentIndex + 1) % kSize; + } +} + +void KIALog::clearFuture() { + _lastIndex = _currentIndex; + int currentIndex = _currentIndex; + while (currentIndex != _firstIndex) { + if (_entries[currentIndex].data) { + delete[] _entries[currentIndex].data; + _entries[currentIndex].data = 0; + _entries[currentIndex].dataSize = 0; + } + currentIndex = (currentIndex + 1) % kSize; + } +} + +bool KIALog::hasPrev() const { + return _currentIndex != _firstIndex; +} + +bool KIALog::hasNext() const { + if (_currentIndex == _lastIndex) { + return false; + } + + return (((_currentIndex + 1) % kSize) != _lastIndex); +} + +int KIALog::getPrevType() const { + return _entries[(_currentIndex - 1) % kSize].type; +} + +int KIALog::getNextType() const { + return _entries[(_currentIndex + 1) % kSize].type; +} + +const void *KIALog::getCurrentData() const { + return _entries[_currentIndex].data; +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/kia_log.h b/engines/bladerunner/ui/kia_log.h new file mode 100644 index 0000000000..4a89492817 --- /dev/null +++ b/engines/bladerunner/ui/kia_log.h @@ -0,0 +1,65 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_KIA_LOG_H +#define BLADERUNNER_KIA_LOG_H + +namespace BladeRunner { + +class BladeRunnerEngine; + +class KIALog { + static const int kSize = 16; + + struct Entry { + int type; + int dataSize; + const char *data; + }; + + BladeRunnerEngine *_vm; + + Entry _entries[kSize]; + int _firstIndex; + int _lastIndex; + int _currentIndex; + +public: + KIALog(BladeRunnerEngine *vm); + ~KIALog(); + + void add(int type, int dataSize, const void *data); + void clear(); + + void prev(); + void next(); + void clearFuture(); + bool hasPrev() const; + bool hasNext() const; + int getPrevType() const; + int getNextType() const; + const void *getCurrentData() const; +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/kia_section_base.cpp b/engines/bladerunner/ui/kia_section_base.cpp new file mode 100644 index 0000000000..96571e5a48 --- /dev/null +++ b/engines/bladerunner/ui/kia_section_base.cpp @@ -0,0 +1,35 @@ +/* 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_base.h" + +namespace BladeRunner { + +KIASectionBase::KIASectionBase(BladeRunnerEngine *vm) { + _vm = vm; + _field0 = false; +} + +KIASectionBase::~KIASectionBase() { +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/kia_section_base.h b/engines/bladerunner/ui/kia_section_base.h new file mode 100644 index 0000000000..176e30d4b7 --- /dev/null +++ b/engines/bladerunner/ui/kia_section_base.h @@ -0,0 +1,67 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 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. + * + */ + +#ifndef BLADERUNNER_KIA_SECTION_BASE_H +#define BLADERUNNER_KIA_SECTION_BASE_H + + +namespace Common { +struct KeyState; +} + +namespace Graphics { +struct Surface; +} + +namespace BladeRunner { + +class BladeRunnerEngine; + +class KIASectionBase { +protected: + BladeRunnerEngine *_vm; + +public: + bool _field0; + + KIASectionBase(BladeRunnerEngine *vm); + virtual ~KIASectionBase(); + + virtual void open() {} + virtual void close() {} + + virtual void draw(Graphics::Surface &surface) {} + + virtual void handleKeyUp(const Common::KeyState &kbd) {} + virtual void handleKeyDown(const Common::KeyState &kbd) {} + virtual void handleMouseMove(int mouseX, int mouseY) {} + virtual void handleMouseDown(bool mainButton) {} + virtual void handleMouseUp(bool mainButton) {} + +protected: + virtual void onButtonPressed(int buttonId) {} + +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/kia_section_clues.cpp b/engines/bladerunner/ui/kia_section_clues.cpp new file mode 100644 index 0000000000..1e80b57ed7 --- /dev/null +++ b/engines/bladerunner/ui/kia_section_clues.cpp @@ -0,0 +1,422 @@ +/* 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_clues.h" + +#include "bladerunner/actor_clues.h" +#include "bladerunner/audio_player.h" +#include "bladerunner/bladerunner.h" +#include "bladerunner/crimes_database.h" +#include "bladerunner/game_constants.h" +#include "bladerunner/game_flags.h" +#include "bladerunner/game_info.h" +#include "bladerunner/font.h" +#include "bladerunner/script/kia.h" +#include "bladerunner/text_resource.h" +#include "bladerunner/ui/kia.h" +#include "bladerunner/ui/kia_log.h" +#include "bladerunner/ui/kia_shapes.h" +#include "bladerunner/ui/ui_container.h" +#include "bladerunner/ui/ui_image_picker.h" +#include "bladerunner/ui/ui_scroll_box.h" + +#include "common/rect.h" + +namespace BladeRunner { + +KIASectionClues::KIASectionClues(BladeRunnerEngine *vm, ActorClues *clues) : KIASectionBase(vm) { + _uiContainer = new UIContainer(_vm); + + _isVisible = false; + + _debugIntangible = false; + _debugNop = 0; + + _clues = clues; + + _mouseX = 0; + _mouseY = 0; + + _buttons = new UIImagePicker(_vm, 2); + + _cluesScrollBox = new UIScrollBox(_vm, scrollBoxCallback, this, _vm->_gameInfo->getClueCount(), 1, false, Common::Rect(312, 172, 500, 376), Common::Rect(506, 160, 506, 394)); + _uiContainer->add(_cluesScrollBox); + + _filterScrollBox = new UIScrollBox(_vm, scrollBoxCallback, this, 128, 1, false, Common::Rect(142, 162, 291, 376), Common::Rect(120, 160, 120, 370)); + _uiContainer->add(_filterScrollBox); + + _assetTypeFilterCount = 4 + 1; // we have 4 asset types + _crimeFilterCount = _vm->_gameInfo->getCrimeCount() + 1; + _filterCount = _assetTypeFilterCount + _crimeFilterCount; + _filters.resize(_filterCount); + for (int i = 0; i < _filterCount; ++i) { + _filters[i] = true; + } +} + +KIASectionClues::~KIASectionClues() { + _uiContainer->clear(); + delete _filterScrollBox; + delete _cluesScrollBox; + delete _uiContainer; +} + +void KIASectionClues::open() { + _isVisible = true; + + _buttons->resetImages(); + _buttons->defineImage(0, Common::Rect(142, 380, 191, 395), _vm->_kia->_shapes->get(79), _vm->_kia->_shapes->get(80), _vm->_kia->_shapes->get(81), _vm->_textKIA->getText(30)); + _buttons->defineImage(1, Common::Rect(193, 380, 242, 395), _vm->_kia->_shapes->get(76), _vm->_kia->_shapes->get(77), _vm->_kia->_shapes->get(78), _vm->_textKIA->getText(31)); + + _buttons->activate(nullptr, nullptr, nullptr, mouseUpCallback, this); + _cluesScrollBox->show(); + _filterScrollBox->show(); + + populateFilters(); + populateClues(); +} + +void KIASectionClues::close() { + if (_isVisible) { + _isVisible = false; + + _buttons->deactivate(); + _cluesScrollBox->hide(); + _filterScrollBox->hide(); + } +} + +void KIASectionClues::draw(Graphics::Surface &surface) { + _uiContainer->draw(surface); + + _vm->_mainFont->drawColor(_vm->_textKIA->getText(0), surface, 300, 162, 0x77DF); + _vm->_mainFont->drawColor(_vm->_textKIA->getText(2), surface, 440, 426, 0x2991); + _vm->_mainFont->drawColor(_vm->_textKIA->getText(1), surface, 440, 442, 0x2991); + _vm->_mainFont->drawColor(_vm->_textKIA->getText(4), surface, 440, 458, 0x2991); + + int clueId = _cluesScrollBox->getSelectedLineData(); + if (clueId != -1) { + Common::String text; + + int actorId = _clues->getFromActorId(clueId); + if (actorId != -1) { + text = _vm->_textActorNames->getText(actorId); + } else { + text.clear(); + } + _vm->_mainFont->drawColor(text, surface, 490, 426, 0x46BF); + + int crimeId = _vm->_crimesDatabase->getCrime(clueId); + if (crimeId != -1) { + text = _vm->_textCrimes->getText(crimeId); + } else { + text.clear(); + } + _vm->_mainFont->drawColor(text, surface, 490, 442, 0x46BF); + + int assetType = _vm->_crimesDatabase->getAssetType(clueId); + if (assetType != -1) { + text = _vm->_textClueTypes->getText(assetType); + } else { + text.clear(); + } + _vm->_mainFont->drawColor(text, surface, 490, 458, 0x46BF); + } + + _buttons->draw(surface); + _buttons->drawTooltip(surface, _mouseX, _mouseY); + + if (_debugNop) { + _vm->_mainFont->drawColor(Common::String::format("Debug display: %s", _vm->_textActorNames->getText(_debugNop)), surface, 120, 132, 0x7FE0); + } + if (_debugIntangible) { + _vm->_mainFont->drawColor("Debug Mode: Showing intangible clues.", surface, 220, 105, 0x7FE0); + } +} + +void KIASectionClues::handleMouseMove(int mouseX, int mouseY) { + _mouseX = mouseX; + _mouseY = mouseY; + _buttons->handleMouseAction(mouseX, mouseY, false, false, false); + _uiContainer->handleMouseMove(mouseX, mouseY); +} + +void KIASectionClues::handleMouseDown(bool mainButton) { + _uiContainer->handleMouseDown(!mainButton); + if (mainButton) { + _buttons->handleMouseAction(_mouseX, _mouseY, true, false, false); + } +} + +void KIASectionClues::handleMouseUp(bool mainButton) { + _uiContainer->handleMouseUp(!mainButton); + if (mainButton) { + _buttons->handleMouseAction(_mouseX, _mouseY, false, true, false); + } +} + +void KIASectionClues::saveToLog() { + _vm->_kia->_log->add(0, sizeof(bool) * _filterCount, _filters.data()); +} + +void KIASectionClues::loadFromLog() { + memcpy(_filters.data(), _vm->_kia->_log->getCurrentData(), sizeof(bool) * _filterCount); + populateFilters(); + populateClues(); +} + +void KIASectionClues::scrollBoxCallback(void *callbackData, void *source, int lineData, int mouseButton) { + KIASectionClues *self = (KIASectionClues *)callbackData; + + if (source == self->_filterScrollBox && lineData >= 0) { + self->_filters[lineData] = !self->_filters[lineData]; + self->_filterScrollBox->toggleCheckBox(lineData); + self->populateClues(); + } else if (source == self->_cluesScrollBox && lineData >= 0) { + if (mouseButton) { + if (self->_vm->_gameFlags->query(kFlagKIAPrivacyAddon)) { + self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(511), 70, 0, 0, 50, 0); + + if (self->_clues->isPrivate(lineData)) { + self->_clues->setPrivate(lineData, false); + self->_cluesScrollBox->resetFlags(lineData, 0x08); + } else { + self->_clues->setPrivate(lineData, true); + self->_cluesScrollBox->setFlags(lineData, 0x08); + } + } + } else { + self->_clues->setViewed(lineData, true); + self->_cluesScrollBox->resetHighlight(lineData); + self->_vm->_kia->_script->playClueAssetScript(0, lineData); + } + } +} + +void KIASectionClues::mouseUpCallback(int buttonId, void *callbackData) { + KIASectionClues *self = (KIASectionClues *)callbackData; + + if (buttonId <= 1) { + self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(510), 100, 0, 0, 50, 0); + } + + self->onButtonPressed(buttonId); +} + +void KIASectionClues::onButtonPressed(int buttonId) { + if (buttonId == 1) { + disableAllFilters(); + } + if (buttonId == 0) { + enableAllFilters(); + } +} + +void KIASectionClues::enableAllFilters() { + for (int i = 0; i < _filterCount; ++i) { + if (_filterScrollBox->hasLine(i)) { + _filters[i] = true; + } + } + _filterScrollBox->checkAll(); + populateClues(); +} + +void KIASectionClues::disableAllFilters() { + for (int i = 0; i < _filterCount; ++i) { + if (_filterScrollBox->hasLine(i)) { + _filters[i] = false; + } + } + _filterScrollBox->uncheckAll(); + populateClues(); +} + +void KIASectionClues::populateFilters() { + _filterScrollBox->clearLines(); + + Common::Array<bool> availableFilters(_filterCount); + for (int i = 0; i < _filterCount; ++i) { + availableFilters[i] = false; + } + + Common::String assetTypeNames[] = { + _vm->_textKIA->getText(6), + _vm->_textKIA->getText(7), + _vm->_textKIA->getText(8), + _vm->_textKIA->getText(9) + }; + + for (int i = 0; i < kClueCount; ++i) { + if (_clues->isAcquired(i)) { + int assetType = _vm->_crimesDatabase->getAssetType(i); + int crimeId = _vm->_crimesDatabase->getCrime(i); + if (_debugIntangible || assetType != -1) { + availableFilters[getLineIdForAssetType(assetType)] = true; + availableFilters[getLineIdForCrimeId(crimeId)] = true; + } + } + } + + int assetTypeFiltersAvailable = 0; + for (int i = 0; i < _assetTypeFilterCount; ++i) { + if (availableFilters[i]) { + ++assetTypeFiltersAvailable; + } + } + + int crimeFiltersAvailable = 0; + for (int i = _assetTypeFilterCount; i < _filterCount; ++i) { + if (availableFilters[i]) { + ++crimeFiltersAvailable; + } + } + + if (assetTypeFiltersAvailable > 1) { + _filterScrollBox->addLine(_vm->_textKIA->getText(11), -1, 0x04); + + for (int i = 0; i < _assetTypeFilterCount; ++i) { + if (availableFilters[i]) { + int flags = 0x01; + if (_filters[i]) { + flags |= 0x02; + } + + Common::String text; + int typeTextId = getClueFilterTypeTextId(i); + if (typeTextId == -1) { + text = _vm->_textKIA->getText(10); + } else { + text = assetTypeNames[typeTextId]; + } + + _filterScrollBox->addLine(text, i, flags); + } + } + } + + if (crimeFiltersAvailable > 1) { + if (assetTypeFiltersAvailable > 1) { + _filterScrollBox->addLine(" ", -1, 0); + } + + _filterScrollBox->addLine(_vm->_textKIA->getText(12), -1, 0x04); + + struct Line { + Common::String crimeName; + int lineData; + int flags; + }; + + Common::Array<Line> crimeLines; + crimeLines.reserve(crimeFiltersAvailable); + + for (int i = _assetTypeFilterCount; i < _filterCount; ++i) { + if (availableFilters[i]) { + Line line; + + line.lineData = i; + + line.flags = 0x01; + if (_filters[i]) { + line.flags |= 0x02; + } + + int crimeId = getClueFilterCrimeId(i); + if (crimeId == -1) { + line.crimeName = _vm->_textKIA->getText(5); + } else { + line.crimeName = _vm->_textCrimes->getText(crimeId); + } + + crimeLines.push_back(line); + } + } + + for (int i = 0; i < crimeFiltersAvailable - 1; ++i) { + for (int j = i + 1; j < crimeFiltersAvailable; ++j) { + if (crimeLines[i].lineData != _assetTypeFilterCount) { + if (crimeLines[i].crimeName.compareToIgnoreCase(crimeLines[j].crimeName) <= 0) { + continue; + } + } + SWAP(crimeLines[i], crimeLines[j]); + } + } + + for (uint i = 0; i < crimeLines.size(); ++i) { + _filterScrollBox->addLine(crimeLines[i].crimeName, crimeLines[i].lineData, crimeLines[i].flags); + } + } +} + +void KIASectionClues::populateClues() { + _cluesScrollBox->clearLines(); + for (int i = 0; i < kClueCount; ++i) { + if (_clues->isAcquired(i)) { + int assetType = _vm->_crimesDatabase->getAssetType(i); + int crimeId = _vm->_crimesDatabase->getCrime(i); + if (assetType != -1 || _debugIntangible) { + if(_filters[getLineIdForAssetType(assetType)] && _filters[getLineIdForCrimeId(crimeId)]) { + int flags = 0x30; + if (_clues->isPrivate(i)) { + flags = 0x08; + } else if (_clues->isViewed(i)) { + flags = 0x10; + } + _cluesScrollBox->addLine(_vm->_crimesDatabase->getClueText(i), i, flags); + } + } + } + } + _cluesScrollBox->sortLines(); +} + +int KIASectionClues::getClueFilterTypeTextId(int i) { + if (i) { + return i - 1; + } + return -1; +} + +int KIASectionClues::getClueFilterCrimeId(int filterId) { + if (filterId == _assetTypeFilterCount) { + return -1; + } + return filterId - (_assetTypeFilterCount + 1); +} + +int KIASectionClues::getLineIdForAssetType(int assetType) { + if (assetType == -1) { + return 0; + } + return assetType + 1; +} + +int KIASectionClues::getLineIdForCrimeId(int crimeId) { + if (crimeId == -1) { + return _assetTypeFilterCount; + } + return _assetTypeFilterCount + crimeId + 1; +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/kia_section_clues.h b/engines/bladerunner/ui/kia_section_clues.h new file mode 100644 index 0000000000..28d9077e6c --- /dev/null +++ b/engines/bladerunner/ui/kia_section_clues.h @@ -0,0 +1,95 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_KIA_SECTION_CLUES_H +#define BLADERUNNER_KIA_SECTION_CLUES_H + +#include "bladerunner/ui/kia_section_base.h" + +#include "common/array.h" +#include "common/str.h" + +namespace BladeRunner { + +class ActorClues; +class UIContainer; +class UIImagePicker; +class UIScrollBox; + +class KIASectionClues : public KIASectionBase { + static const int kClueCount = 288; + + UIContainer *_uiContainer; + UIImagePicker *_buttons; + UIScrollBox *_cluesScrollBox; + UIScrollBox *_filterScrollBox; + + bool _isVisible; + bool _debugIntangible; + int _debugNop; + ActorClues *_clues; + + int _assetTypeFilterCount; + int _crimeFilterCount; + int _filterCount; + Common::Array<bool> _filters; + + int _mouseX; + int _mouseY; + +public: + KIASectionClues(BladeRunnerEngine *vm, ActorClues *clues); + ~KIASectionClues(); + + void open(); + void close(); + + void draw(Graphics::Surface &surface); + + void handleMouseMove(int mouseX, int mouseY); + void handleMouseDown(bool mainButton); + void handleMouseUp(bool mainButton); + + void saveToLog(); + void loadFromLog(); + +private: + static void scrollBoxCallback(void *callbackData, void *source, int lineData, int mouseButton); + static void mouseUpCallback(int buttonId, void *callbackData); + + void onButtonPressed(int buttonId); + + void enableAllFilters(); + void disableAllFilters(); + + void populateFilters(); + void populateClues(); + + int getClueFilterTypeTextId(int); + int getClueFilterCrimeId(int); + int getLineIdForAssetType(int assetType); + int getLineIdForCrimeId(int crimeId); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/kia_section_crimes.cpp b/engines/bladerunner/ui/kia_section_crimes.cpp new file mode 100644 index 0000000000..4cfaaedbad --- /dev/null +++ b/engines/bladerunner/ui/kia_section_crimes.cpp @@ -0,0 +1,37 @@ +/* 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_crimes.h" + +#include "bladerunner/bladerunner.h" + +namespace BladeRunner { + +KIASectionCrimes::KIASectionCrimes(BladeRunnerEngine *vm) + : KIASectionBase(vm) + , _shape(vm) { +} + +KIASectionCrimes::~KIASectionCrimes() { +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/kia_section_crimes.h b/engines/bladerunner/ui/kia_section_crimes.h new file mode 100644 index 0000000000..befe5e528c --- /dev/null +++ b/engines/bladerunner/ui/kia_section_crimes.h @@ -0,0 +1,82 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_KIA_SECTION_CRIME_H +#define BLADERUNNER_KIA_SECTION_CRIME_H + +#include "bladerunner/shape.h" +#include "bladerunner/ui/kia_section_base.h" + +namespace BladeRunner { + +class ActorClues; +class BladeRunnerEngine; +class UIContainer; +class UIImagePicker; +class UIScrollBox; + +class KIASectionCrimes : public KIASectionBase { + struct Clue + { + int clueId; + int actorId; + }; + +protected: + + UIContainer *_uiContainer; + // void (__cdecl **scrollboxCallback)(int, UIScrollBoxStruc *, int, int); + int _isOpen; + int *_list; + UIImagePicker *_uiImagePicker; + + UIScrollBox *_cluesScrollbox; + ActorClues *_clues; + int _clueInfoCount; + Clue _clueInfo[1000]; + int _selectedCrimeId; + int _crimesFoundCount; + int *_crimeIsKnown; + int _selectedSuspectId; + int _suspectsFoundCount; + int *_suspectIsKnown; + int *_suspectHasIdentity; + int _mouseX; + int _mouseY; + int _suspectPhotoShapeId; + int _field_15; + Shape _shape; + +public: + KIASectionCrimes(BladeRunnerEngine *vm); + ~KIASectionCrimes(); + + void saveToLog() {} + void loadFromLog() {} + +protected: + +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/kia_section_diagnostic.h b/engines/bladerunner/ui/kia_section_diagnostic.h new file mode 100644 index 0000000000..9a5b74b8af --- /dev/null +++ b/engines/bladerunner/ui/kia_section_diagnostic.h @@ -0,0 +1,39 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_KIA_SECTION_DIAGNOSTIC_H +#define BLADERUNNER_KIA_SECTION_DIAGNOSTIC_H + +#include "bladerunner/ui/kia_section_base.h" + +namespace BladeRunner { + +class KIASectionDiagnostic : public KIASectionBase { + +public: + KIASectionDiagnostic(BladeRunnerEngine *vm) : KIASectionBase(vm){} + +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/kia_section_help.cpp b/engines/bladerunner/ui/kia_section_help.cpp new file mode 100644 index 0000000000..5065382c41 --- /dev/null +++ b/engines/bladerunner/ui/kia_section_help.cpp @@ -0,0 +1,90 @@ +/* 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_help.h" + +#include "bladerunner/bladerunner.h" +#include "bladerunner/text_resource.h" +#include "bladerunner/ui/kia.h" +#include "bladerunner/ui/kia_shapes.h" +#include "bladerunner/ui/ui_container.h" +#include "bladerunner/ui/ui_scroll_box.h" + +namespace BladeRunner { + +KIASectionHelp::KIASectionHelp(BladeRunnerEngine *vm) : KIASectionBase(vm) { + _uiContainer = new UIContainer(_vm); + _scrollBox = new UIScrollBox(_vm, nullptr, this, 1024, 0, false, Common::Rect(135, 145, 461, 385), Common::Rect(506, 160, 506, 350)); + + _uiContainer->add(_scrollBox); +} + +KIASectionHelp::~KIASectionHelp() { + _uiContainer->clear(); + delete _scrollBox; + delete _uiContainer; +} + +void KIASectionHelp::open() { + TextResource textResource(_vm); + textResource.open("HELP"); + + _scrollBox->clearLines(); + + for (int i = 0; i < textResource.getCount(); ++i) { + Common::String textLine = textResource.getText(i); + int flags = 0x04; + if (textLine.firstChar() == ' ') { + flags = 0x00; + } + _scrollBox->addLine(textLine, -1, flags); + } + + _scrollBox->show(); +} + +void KIASectionHelp::close() { + _scrollBox->hide(); +} + +void KIASectionHelp::draw(Graphics::Surface &surface){ + _vm->_kia->_shapes->get(69)->draw(surface, 501, 123); + _uiContainer->draw(surface); +} + +void KIASectionHelp::handleKeyUp(const Common::KeyState &kbd) { + _uiContainer->handleKeyUp(kbd); +} + +void KIASectionHelp::handleMouseMove(int mouseX, int mouseY) { + _uiContainer->handleMouseMove(mouseX, mouseY); +} + +void KIASectionHelp::handleMouseDown(bool mainButton) { + _uiContainer->handleMouseDown(!mainButton); +} + +void KIASectionHelp::handleMouseUp(bool mainButton) { + _uiContainer->handleMouseUp(!mainButton); +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/kia_section_help.h b/engines/bladerunner/ui/kia_section_help.h new file mode 100644 index 0000000000..0bda5d8851 --- /dev/null +++ b/engines/bladerunner/ui/kia_section_help.h @@ -0,0 +1,54 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_KIA_SECTION_HELP_H +#define BLADERUNNER_KIA_SECTION_HELP_H + +#include "bladerunner/ui/kia_section_base.h" + +namespace BladeRunner { + +class BladeRunnerEngine; +class UIContainer; +class UIScrollBox; + +class KIASectionHelp : public KIASectionBase { + UIContainer *_uiContainer; + UIScrollBox *_scrollBox; + +public: + KIASectionHelp(BladeRunnerEngine *vm); + ~KIASectionHelp(); + + void open(); + void close(); + + void draw(Graphics::Surface &surface); + + void handleKeyUp(const Common::KeyState &kbd); + void handleMouseMove(int mouseX, int mouseY); + void handleMouseDown(bool mainButton); + void handleMouseUp(bool mainButton); +}; + +} // End of namespace BladeRunner +#endif diff --git a/engines/bladerunner/ui/kia_section_load.h b/engines/bladerunner/ui/kia_section_load.h new file mode 100644 index 0000000000..4cff04d2c4 --- /dev/null +++ b/engines/bladerunner/ui/kia_section_load.h @@ -0,0 +1,39 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_KIA_SECTION_LOAD_H +#define BLADERUNNER_KIA_SECTION_LOAD_H + +#include "bladerunner/ui/kia_section_base.h" + +namespace BladeRunner { + +class KIASectionLoad : public KIASectionBase { + +public: + KIASectionLoad(BladeRunnerEngine *vm): KIASectionBase(vm){} + +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/kia_section_pogo.h b/engines/bladerunner/ui/kia_section_pogo.h new file mode 100644 index 0000000000..d2a2edd859 --- /dev/null +++ b/engines/bladerunner/ui/kia_section_pogo.h @@ -0,0 +1,39 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_KIA_SECTION_POGO_H +#define BLADERUNNER_KIA_SECTION_POGO_H + +#include "bladerunner/ui/kia_section_base.h" + +namespace BladeRunner { + +class KIASectionPogo : public KIASectionBase { + +public: + KIASectionPogo(BladeRunnerEngine *vm): KIASectionBase(vm){} + +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/kia_section_save.h b/engines/bladerunner/ui/kia_section_save.h new file mode 100644 index 0000000000..5e2f5f26ac --- /dev/null +++ b/engines/bladerunner/ui/kia_section_save.h @@ -0,0 +1,39 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_KIA_SECTION_SAVE_H +#define BLADERUNNER_KIA_SECTION_SAVE_H + +#include "bladerunner/ui/kia_section_base.h" + +namespace BladeRunner { + +class KIASectionSave : public KIASectionBase { + +public: + KIASectionSave(BladeRunnerEngine *vm): KIASectionBase(vm){} + +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/kia_section_settings.cpp b/engines/bladerunner/ui/kia_section_settings.cpp new file mode 100644 index 0000000000..7f2db4ae12 --- /dev/null +++ b/engines/bladerunner/ui/kia_section_settings.cpp @@ -0,0 +1,301 @@ +/* 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_settings.h" + +#include "bladerunner/audio_player.h" +#include "bladerunner/audio_speech.h" +#include "bladerunner/ambient_sounds.h" +#include "bladerunner/bladerunner.h" +#include "bladerunner/font.h" +#include "bladerunner/game_constants.h" +#include "bladerunner/game_flags.h" +#include "bladerunner/game_info.h" +#include "bladerunner/music.h" +#include "bladerunner/settings.h" +#include "bladerunner/text_resource.h" +#include "bladerunner/ui/kia.h" +#include "bladerunner/ui/kia_shapes.h" +#include "bladerunner/ui/ui_check_box.h" +#include "bladerunner/ui/ui_container.h" +#include "bladerunner/ui/ui_image_picker.h" +#include "bladerunner/ui/ui_slider.h" + +#include "common/keyboard.h" + +namespace BladeRunner { + +const char *KIASectionSettings::kLeary = "LEARY"; + +KIASectionSettings::KIASectionSettings(BladeRunnerEngine *vm) + : KIASectionBase(vm) { + + _uiContainer = new UIContainer(_vm); + _musicVolume = new UISlider(_vm, sliderCallback, this, Common::Rect(180, 160, 460, 170), 101, 0); + _soundEffectVolume = new UISlider(_vm, sliderCallback, this, Common::Rect( 180, 185, 460, 195), 101, 0); + _ambientSoundVolume = new UISlider(_vm, sliderCallback, this, Common::Rect(180, 210, 460, 220), 101, 0); + _speechVolume = new UISlider(_vm, sliderCallback, this, Common::Rect(180, 235, 460, 245), 101, 0); + _gammaCorrection = new UISlider(_vm, sliderCallback, this, Common::Rect(180, 260, 460, 270), 101, 0); + _directorsCut = new UICheckBox(_vm, checkBoxCallback, this, Common::Rect(180, 364, 460, 374), 0, false); + _playerAgendaSelector = new UIImagePicker(_vm, 5); + + _uiContainer->add(_musicVolume); + _uiContainer->add(_soundEffectVolume); + _uiContainer->add(_ambientSoundVolume); + _uiContainer->add(_speechVolume); + _uiContainer->add(_gammaCorrection); + _uiContainer->add(_directorsCut); + + _learyPos = 0; +} + +KIASectionSettings::~KIASectionSettings() { + delete _uiContainer; + delete _musicVolume; + delete _soundEffectVolume; + delete _ambientSoundVolume; + delete _speechVolume; + delete _gammaCorrection; + delete _directorsCut; + delete _playerAgendaSelector; +} + +void KIASectionSettings::open() { + _playerAgendaSelector->resetImages(); + + _playerAgendaSelector->defineImage(0, Common::Rect(180, 290, 227, 353), nullptr, nullptr, nullptr, _vm->_textOptions->getText(30)); + _playerAgendaSelector->defineImage(1, Common::Rect(238, 290, 285, 353), nullptr, nullptr, nullptr, _vm->_textOptions->getText(31)); + _playerAgendaSelector->defineImage(2, Common::Rect(296, 290, 343, 353), nullptr, nullptr, nullptr, _vm->_textOptions->getText(32)); + _playerAgendaSelector->defineImage(3, Common::Rect(354, 290, 401, 353), nullptr, nullptr, nullptr, _vm->_textOptions->getText(33)); + _playerAgendaSelector->defineImage(4, Common::Rect(412, 290, 459, 353), nullptr, nullptr, nullptr, _vm->_textOptions->getText(34)); + initConversationChoices(); + _playerAgendaSelector->activate(mouseInCallback, nullptr, nullptr, mouseUpCallback, this); + + _directorsCut->enable(); +} + +void KIASectionSettings::close() { + _playerAgendaSelector->deactivate(); +} + +void KIASectionSettings::draw(Graphics::Surface &surface) { + _musicVolume->setValue(_vm->_music->getVolume()); + _soundEffectVolume->setValue(_vm->_audioPlayer->getVolume()); + _ambientSoundVolume->setValue(_vm->_ambientSounds->getVolume()); + _speechVolume->setValue(_vm->_audioSpeech->getVolume()); + _gammaCorrection->setValue(100.0f); + _directorsCut->setChecked(_vm->_gameFlags->query(kFlagDirectorsCut)); + + const char *textConversationChoices = _vm->_textOptions->getText(0); + const char *textMusic = _vm->_textOptions->getText(2); + const char *textSoundEffects = _vm->_textOptions->getText(3); + const char *textAmbientSound = _vm->_textOptions->getText(4); + const char *textSpeech = _vm->_textOptions->getText(5); + const char *textGammaCorrection = _vm->_textOptions->getText(7); + const char *textSoft = _vm->_textOptions->getText(10); + const char *textLoud = _vm->_textOptions->getText(11); + const char *textDark = _vm->_textOptions->getText(14); + const char *textLight = _vm->_textOptions->getText(15); + const char *textDesignersCut = _vm->_textOptions->getText(18); + + int posConversationChoices = 320 - _vm->_mainFont->getTextWidth(textConversationChoices) / 2; + int posMusic = 320 - _vm->_mainFont->getTextWidth(textMusic) / 2; + int posSoundEffects = 320 - _vm->_mainFont->getTextWidth(textSoundEffects) / 2; + int posAmbientSound = 320 - _vm->_mainFont->getTextWidth(textAmbientSound) / 2; + int posSpeech = 320 - _vm->_mainFont->getTextWidth(textSpeech) / 2; + int posGammaCorrection = 320 - _vm->_mainFont->getTextWidth(textGammaCorrection) / 2; + int posSoft = 178 - _vm->_mainFont->getTextWidth(textSoft); + int posDark = 178 - _vm->_mainFont->getTextWidth(textDark); + + _uiContainer->draw(surface); + _playerAgendaSelector->draw(surface); + + _vm->_mainFont->drawColor(textConversationChoices, surface, posConversationChoices, 280, 0x7751); + + _vm->_mainFont->drawColor(textMusic, surface, posMusic, 150, 0x7751); + _vm->_mainFont->drawColor(textSoft, surface, posSoft, 161, 0x6EEE); + _vm->_mainFont->drawColor(textLoud, surface, 462, 161, 0x6EEE); + + _vm->_mainFont->drawColor(textSoundEffects, surface, posSoundEffects, 175, 0x7751); + _vm->_mainFont->drawColor(textSoft, surface, posSoft, 186, 0x6EEE); + _vm->_mainFont->drawColor(textLoud, surface, 462, 186, 0x6EEE); + + _vm->_mainFont->drawColor(textAmbientSound, surface, posAmbientSound, 200, 0x7751); + _vm->_mainFont->drawColor(textSoft, surface, posSoft, 211, 0x6EEE); + _vm->_mainFont->drawColor(textLoud, surface, 462, 211, 0x6EEE); + + _vm->_mainFont->drawColor(textSpeech, surface, posSpeech, 225, 0x7751); + _vm->_mainFont->drawColor(textSoft, surface, posSoft, 236, 0x6EEE); + _vm->_mainFont->drawColor(textLoud, surface, 462, 236, 0x6EEE); + + _vm->_mainFont->drawColor(textGammaCorrection, surface, posGammaCorrection, 250, 0x7751); + _vm->_mainFont->drawColor(textDark, surface, posDark, 261, 0x6EEE); + _vm->_mainFont->drawColor(textLight, surface, 462, 261, 0x6EEE); + + _vm->_mainFont->drawColor(textDesignersCut, surface, 192, 365, 0x7751); + + _playerAgendaSelector->drawTooltip(surface, _mouseX, _mouseY); +} + +void KIASectionSettings::handleKeyUp(const Common::KeyState &kbd) { + if (toupper(kbd.ascii) != kLeary[_learyPos]) { + _learyPos = 0; + } + + if (toupper(kbd.ascii) == kLeary[_learyPos]) { + ++_learyPos; + if (!kLeary[_learyPos]) { + _vm->_settings->setLearyMode(!_vm->_settings->getLearyMode()); + _learyPos = 0; + initConversationChoices(); + } + } +} + +void KIASectionSettings::handleMouseMove(int mouseX, int mouseY) { + _uiContainer->handleMouseMove(mouseX, mouseY); + _mouseX = mouseX; + _mouseY = mouseY; + _playerAgendaSelector->handleMouseAction(mouseX, mouseY, false, false, false); +} + +void KIASectionSettings::handleMouseDown(bool mainButton) { + if (mainButton) { + _uiContainer->handleMouseDown(false); + _playerAgendaSelector->handleMouseAction(_mouseX, _mouseY, true, false, false); + } +} + +void KIASectionSettings::handleMouseUp(bool mainButton) { + if (mainButton) { + _uiContainer->handleMouseUp(false); + _playerAgendaSelector->handleMouseAction(_mouseX, _mouseY, false, true, false); + } +} + +void KIASectionSettings::sliderCallback(void *callbackData, void *source) { + KIASectionSettings *self = (KIASectionSettings *)callbackData; + + if (source == self->_musicVolume) { + self->_vm->_music->setVolume(self->_musicVolume->_value); + self->_vm->_music->playSample(); + } else if (source == self->_soundEffectVolume) { + self->_vm->_audioPlayer->setVolume(self->_soundEffectVolume->_value); + self->_vm->_audioPlayer->playSample(); + } else if (source == self->_ambientSoundVolume) { + self->_vm->_ambientSounds->setVolume(self->_ambientSoundVolume->_value); + self->_vm->_ambientSounds->playSample(); + } else if (source == self->_speechVolume) { + self->_vm->_audioSpeech->setVolume(self->_speechVolume->_value); + self->_vm->_audioSpeech->playSample(); + } else if (source == self->_gammaCorrection) { + // TODO: gamma, should we support it? + // gamma = self->_gammaCorrection._value / 100.0f; + // settings::setGamma(&Settings, gamma); + // colorFormat = DirectDrawSurfaces_get_colorFormat(); + // Palette_fill(colorFormat); + // Palette_copy(Palette); + // kia::resume(KIA); + } +} + +void KIASectionSettings::checkBoxCallback(void *callbackData, void *source) { + KIASectionSettings *self = (KIASectionSettings *)callbackData; + if (source == self->_directorsCut) { + if (self->_directorsCut->_isChecked) { + self->_vm->_gameFlags->set(kFlagDirectorsCut); + } else { + self->_vm->_gameFlags->reset(kFlagDirectorsCut); + } + } +} + +void KIASectionSettings::mouseInCallback(int buttonId, void *callbackData) { + KIASectionSettings *self = (KIASectionSettings *)callbackData; + self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(508), 100, 0, 0, 50, 0); +} + +void KIASectionSettings::mouseUpCallback(int buttonId, void *callbackData) { + KIASectionSettings *self = (KIASectionSettings *)callbackData; + self->onButtonPressed(buttonId); +} + +void KIASectionSettings::onButtonPressed(int buttonId) { + switch (buttonId) { + case 0: + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(513), 90, -30, -30, 50, 0); + _vm->_settings->setPlayerAgenda(0); + initConversationChoices(); + break; + case 1: + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(513), 90, -15, -15, 50, 0); + _vm->_settings->setPlayerAgenda(1); + initConversationChoices(); + break; + case 2: + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(513), 90, 0, 0, 50, 0); + _vm->_settings->setPlayerAgenda(2); + initConversationChoices(); + break; + case 3: + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(513), 90, 15, 15, 50, 0); + _vm->_settings->setPlayerAgenda(3); + initConversationChoices(); + break; + case 4: + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(513), 90, 30, 30, 50, 0); + _vm->_settings->setPlayerAgenda(4); + initConversationChoices(); + break; + default: + return; + } +} + +void KIASectionSettings::initConversationChoices() { + for (int i = 0; i < 5; ++i) { + const Shape *shape = nullptr; + if (_vm->_settings->getPlayerAgenda() == i) { + if (i == 4) { + shape = _vm->_kia->_shapes->get(122); + } else if (_vm->_settings->getLearyMode()) { + shape = _vm->_kia->_shapes->get(106 + i); + } else { + shape = _vm->_kia->_shapes->get(114 + i); + } + } else { + if (i == 4) { + shape = _vm->_kia->_shapes->get(123); + } else if (_vm->_settings->getLearyMode()) { + shape = _vm->_kia->_shapes->get(110 + i); + } else { + shape = _vm->_kia->_shapes->get(118 + i); + } + } + + _playerAgendaSelector->setImageShapeUp(i, shape); + _playerAgendaSelector->setImageShapeHovered(i, shape); + _playerAgendaSelector->setImageShapeDown(i, shape); + } +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/kia_section_settings.h b/engines/bladerunner/ui/kia_section_settings.h new file mode 100644 index 0000000000..49356266b7 --- /dev/null +++ b/engines/bladerunner/ui/kia_section_settings.h @@ -0,0 +1,80 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_KIA_SECTION_SETTINGS_H +#define BLADERUNNER_KIA_SECTION_SETTINGS_H + +#include "bladerunner/ui/kia_section_base.h" + +namespace BladeRunner { + +class BladeRunnerEngine; +class UIContainer; +class UICheckBox; +class UIImagePicker; +class UISlider; + +class KIASectionSettings : public KIASectionBase { + static const char *kLeary; + + UIContainer *_uiContainer; + UISlider *_musicVolume; + UISlider *_soundEffectVolume; + UISlider *_ambientSoundVolume; + UISlider *_speechVolume; + UISlider *_gammaCorrection; + UICheckBox *_directorsCut; + UIImagePicker *_playerAgendaSelector; + + int _mouseX; + int _mouseY; + + int _learyPos; + +public: + KIASectionSettings(BladeRunnerEngine *vm); + ~KIASectionSettings(); + + void open(); + void close(); + + void draw(Graphics::Surface &surface); + + void handleKeyUp(const Common::KeyState &kbd); + void handleMouseMove(int mouseX, int mouseY); + void handleMouseDown(bool mainButton); + void handleMouseUp(bool mainButton); + +private: + static void sliderCallback(void *callbackData, void *source); + static void checkBoxCallback(void *callbackData, void *source); + static void mouseInCallback(int buttonId, void *callbackData); + static void mouseUpCallback(int buttonId, void *callbackData); + + void onButtonPressed(int buttonId); + + void initConversationChoices(); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/kia_section_suspects.h b/engines/bladerunner/ui/kia_section_suspects.h new file mode 100644 index 0000000000..94cf1bfc06 --- /dev/null +++ b/engines/bladerunner/ui/kia_section_suspects.h @@ -0,0 +1,41 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_KIA_SECTION_SUSPECTS_H +#define BLADERUNNER_KIA_SECTION_SUSPECTS_H + +#include "bladerunner/ui/kia_section_base.h" + +namespace BladeRunner { + +class KIASectionSuspects : public KIASectionBase { + +public: + KIASectionSuspects(BladeRunnerEngine *vm): KIASectionBase(vm) {} + + void saveToLog() {} + void loadFromLog() {} +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/kia_shapes.cpp b/engines/bladerunner/ui/kia_shapes.cpp new file mode 100644 index 0000000000..6835216e26 --- /dev/null +++ b/engines/bladerunner/ui/kia_shapes.cpp @@ -0,0 +1,69 @@ +/* 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_shapes.h" + +#include "bladerunner/bladerunner.h" + +namespace BladeRunner { + +KIAShapes::KIAShapes(BladeRunnerEngine *vm) { + _vm = vm; + _isLoaded = false; +} + +KIAShapes::~KIAShapes() { + unload(); +} + +void KIAShapes::load() { + if (_isLoaded) { + return; + } + + for (uint i = 0; i < kShapeCount; ++i) { + Shape *shape = new Shape(_vm); + shape->readFromContainer("kiaopt.shp", i); + _shapes[i] = shape; + } + + _isLoaded = true; +} + +void KIAShapes::unload() { + if (!_isLoaded) { + return; + } + + for (uint i = 0; i < kShapeCount; ++i) { + delete _shapes[i]; + _shapes[i] = nullptr; + } + + _isLoaded = false; +} + +const Shape *KIAShapes::get(int shapeId) const { + return _shapes[shapeId]; +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/kia_shapes.h b/engines/bladerunner/ui/kia_shapes.h new file mode 100644 index 0000000000..e075547542 --- /dev/null +++ b/engines/bladerunner/ui/kia_shapes.h @@ -0,0 +1,54 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_UI_SHAPES_H +#define BLADERUNNER_UI_SHAPES_H + +#include "bladerunner/shape.h" + +#include "common/array.h" + +namespace BladeRunner { + +class BladeRunnerEngine; + +class KIAShapes +{ +private: + static const int kShapeCount = 132; + + BladeRunnerEngine *_vm; + const Shape *_shapes[kShapeCount]; + bool _isLoaded; + +public: + KIAShapes(BladeRunnerEngine *vm); + ~KIAShapes(); + + void load(); + void unload(); + const Shape *get(int shapeId) const; +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/spinner.cpp b/engines/bladerunner/ui/spinner.cpp new file mode 100644 index 0000000000..9018de15e6 --- /dev/null +++ b/engines/bladerunner/ui/spinner.cpp @@ -0,0 +1,303 @@ +/* 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/spinner.h" + +#include "bladerunner/bladerunner.h" +#include "bladerunner/mouse.h" +#include "bladerunner/scene.h" +#include "bladerunner/shape.h" +#include "bladerunner/text_resource.h" +#include "bladerunner/vqa_player.h" +#include "bladerunner/ui/ui_image_picker.h" + +#include "common/rect.h" +#include "common/system.h" + +namespace BladeRunner { + +Spinner::Spinner(BladeRunnerEngine *vm) { + _vm = vm; + reset(); + _imagePicker = new UIImagePicker(vm, kSpinnerDestinations); + _vqaPlayer = nullptr; +} + +Spinner::~Spinner() { + delete _imagePicker; + + reset(); + + if (_vqaPlayer != nullptr) { + _vqaPlayer->close(); + delete _vqaPlayer; + } +} + +void Spinner::setSelectableDestinationFlag(int destination, bool selectable) { + _isDestinationSelectable[destination] = selectable; +} + +bool Spinner::querySelectableDestinationFlag(int destination) const { + return _isDestinationSelectable[destination]; +} + +const Spinner::Destination Spinner::kSpinnerDestinationsNear[] = { + { 0, Common::Rect(210, 263, 263, 332) }, + { 1, Common::Rect(307, 330, 361, 381) }, + { 2, Common::Rect(338, 137, 362, 169) }, + { 3, Common::Rect(248, 135, 289, 168) }, + { 4, Common::Rect(352, 222, 379, 238) }, + { -1, Common::Rect(-1,-1,-1,-1) } +}; + +const Spinner::Destination Spinner::kSpinnerDestinationsMedium[] = { + { 0, Common::Rect(252, 242, 279, 283) }, + { 1, Common::Rect(301, 273, 328, 304) }, + { 2, Common::Rect(319, 182, 336, 200) }, + { 3, Common::Rect(269, 181, 293, 200) }, + { 4, Common::Rect(325, 227, 345, 240) }, + { 5, Common::Rect(259, 74, 380, 119) }, + { 6, Common::Rect(203, 124, 224, 136) }, + { 7, Common::Rect(200, 147, 222, 170) }, + { -1, Common::Rect(-1,-1,-1,-1) } +}; + +const Spinner::Destination Spinner::kSpinnerDestinationsFar[] = { + { 0, Common::Rect(220, 227, 246, 262) }, + { 1, Common::Rect(260, 252, 286, 279) }, + { 2, Common::Rect(286, 178, 302, 196) }, + { 3, Common::Rect(244, 178, 263, 195) }, + { 4, Common::Rect(288, 216, 306, 228) }, + { 5, Common::Rect(249, 77, 353, 124) }, + { 6, Common::Rect(190, 127, 208, 138) }, + { 7, Common::Rect(185, 149, 206, 170) }, + { 8, Common::Rect(398, 249, 419, 268) }, + { 9, Common::Rect(390, 218, 419, 236) }, + { -1, Common::Rect(-1, -1, -1, -1) } +}; + +int Spinner::chooseDestination(int loopId, bool immediately) { + _selectedDestination = 0; + if (!_vm->openArchive("MODE.MIX")) { + return 0; + } + + if (loopId < 0) { + _isOpen = true; + } else { + _vm->playerLosesControl(); + _vm->_scene->loopStartSpecial(kSceneLoopModeSpinner, loopId, immediately); + while (!_isOpen) { + _vm->gameTick(); + } + _vm->playerGainsControl(); + } + + _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack); + if (!_vqaPlayer->open("SPINNER.VQA")) { + return 0; + } + + _vm->_mouse->setCursor(0); + + // Determine which map we need to show to include the active destinations + uint8 mapmask = 0; + uint8 mapmaskv[kSpinnerDestinations] = { 1, 1, 1, 1, 1, 3, 3, 3, 7, 7 }; + for (int i = 0; i != kSpinnerDestinations; ++i) { + if (_isDestinationSelectable[i]) { + mapmask |= mapmaskv[i]; + } + } + + _destinations = nullptr; + int firstShapeId = 0; + int shapeCount = 0; + int spinnerLoopId = 4; + + mapmask = 1; + + if (mapmask & 4) { + _destinations = kSpinnerDestinationsFar; + firstShapeId = 26; + shapeCount = 20; + spinnerLoopId = 4; + } else if (mapmask & 2) { + _destinations = kSpinnerDestinationsMedium; + firstShapeId = 10; + shapeCount = 16; + spinnerLoopId = 2; + } else if (mapmask & 1) { + _destinations = kSpinnerDestinationsNear; + firstShapeId = 0; + shapeCount = 10; + spinnerLoopId = 0; + } else { + return -1; + } + + _vqaPlayer->setLoop(spinnerLoopId, -1, kLoopSetModeImmediate, nullptr, nullptr); + _vqaPlayer->setLoop(spinnerLoopId + 1, -1, kLoopSetModeJustStart, nullptr, nullptr); + + for (int j = 0; j != shapeCount; ++j) { + _shapes.push_back(new Shape(_vm)); + _shapes[j]->readFromContainer("SPINNER.SHP", firstShapeId + j); + } + + _imagePicker->resetImages(); + + for (const Destination *dest = _destinations; dest->id != -1; ++dest) { + if (!_isDestinationSelectable[dest->id]) { + continue; + } + + const char *tooltip = _vm->_textSpinnerDestinations->getText(dest->id); + + _imagePicker->defineImage( + dest->id, + dest->rect, + _shapes[dest->id], + _shapes[dest->id + _shapes.size() / 2], + _shapes[dest->id + _shapes.size() / 2], + tooltip + ); + } + + _imagePicker->activate( + nullptr, + nullptr, + nullptr, + mouseUpCallback, + this + ); + + // TODO: Freeze game time + _selectedDestination = -1; + do { + _vm->gameTick(); + } while (_selectedDestination == -1); + + _imagePicker->deactivate(); + + for (int i = 0; i != (int)_shapes.size(); ++i) { + delete _shapes[i]; + } + _shapes.clear(); + + if (_vqaPlayer != nullptr) { + _vqaPlayer->close(); + delete _vqaPlayer; + _vqaPlayer = nullptr; + } + + _vm->closeArchive("MODE.MIX"); + + _isOpen = false; + + // TODO: Unfreeze game time + // TODO: _vm->_scene->resume(); + + return _selectedDestination; +} + +void Spinner::mouseUpCallback(int image, void *self) { + if (image >= 0 && image < 10) { + ((Spinner *)self)->setSelectedDestination(image); + } +} + +void Spinner::open() { + _isOpen = true; +} + +bool Spinner::isOpen() const { + return _isOpen; +} + +int Spinner::handleMouseUp(int x, int y) { + _imagePicker->handleMouseAction(x, y, false, true, false); + return false; +} + +int Spinner::handleMouseDown(int x, int y) { + _imagePicker->handleMouseAction(x, y, true, false, false); + return false; +} + +void Spinner::tick() { + if (!_vm->_gameIsRunning) { + return; + } + + int frame = _vqaPlayer->update(); + assert(frame >= -1); + + // vqaPlayer renders to _surfaceBack + blit(_vm->_surfaceBack, _vm->_surfaceFront); + + Common::Point p = _vm->getMousePos(); + _imagePicker->handleMouseAction(p.x, p.y, false, false, false); + if (_imagePicker->hasHoveredImage()) { + _vm->_mouse->setCursor(1); + } else { + _vm->_mouse->setCursor(0); + } + _imagePicker->draw(_vm->_surfaceFront); + _vm->_mouse->draw(_vm->_surfaceFront, p.x, p.y); + _imagePicker->drawTooltip(_vm->_surfaceFront, p.x, p.y); + + _vm->blitToScreen(_vm->_surfaceFront); + _vm->_system->delayMillis(10); +} + +void Spinner::setSelectedDestination(int destination) { + _selectedDestination = destination; +} + +void Spinner::reset() { + for (int i = 0; i != kSpinnerDestinations; ++i) { + _isDestinationSelectable[i] = false; + } + + _isOpen = false; + _destinations = nullptr; + _selectedDestination = -1; + _imagePicker = nullptr; + + for (int i = 0; i != (int)_shapes.size(); ++i) { + delete _shapes[i]; + } + _shapes.clear(); +} + +void Spinner::resume() { + if(_vqaPlayer == nullptr) { + return; + } + + //_vqa->clear(); + _vqaPlayer->setLoop(0, -1, kLoopSetModeImmediate, nullptr, nullptr); + tick(); + _vqaPlayer->setLoop(1, -1, kLoopSetModeJustStart, nullptr, nullptr); +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/spinner.h b/engines/bladerunner/ui/spinner.h new file mode 100644 index 0000000000..ec0f8dbe33 --- /dev/null +++ b/engines/bladerunner/ui/spinner.h @@ -0,0 +1,84 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_SPINNER_H +#define BLADERUNNER_SPINNER_H + +#include "common/array.h" +#include "common/rect.h" + +namespace BladeRunner { + +class BladeRunnerEngine; +class Shape; +class VQAPlayer; +class UIImagePicker; + + +class Spinner { + static const int kSpinnerDestinations = 10; + + struct Destination { + int id; + Common::Rect rect; + }; + + static const Destination kSpinnerDestinationsNear[]; + static const Destination kSpinnerDestinationsMedium[]; + static const Destination kSpinnerDestinationsFar[]; + + BladeRunnerEngine *_vm; + bool _isDestinationSelectable[kSpinnerDestinations]; + bool _isOpen; + VQAPlayer *_vqaPlayer; + const Destination *_destinations; + int _selectedDestination; + Common::Array<Shape *> _shapes; + UIImagePicker *_imagePicker; + +public: + Spinner(BladeRunnerEngine *vm); + ~Spinner(); + + void setSelectableDestinationFlag(int destination, bool selectable); + bool querySelectableDestinationFlag(int destination) const; + + int chooseDestination(int vqaLoopId, bool immediately); + + void open(); + bool isOpen() const; + + int handleMouseUp(int x, int y); + int handleMouseDown(int x, int y); + + void tick(); + void setSelectedDestination(int destination); + void reset(); + void resume(); + +private: + static void mouseUpCallback(int, void *); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/ui_check_box.cpp b/engines/bladerunner/ui/ui_check_box.cpp new file mode 100644 index 0000000000..39e120e883 --- /dev/null +++ b/engines/bladerunner/ui/ui_check_box.cpp @@ -0,0 +1,140 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 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/ui_check_box.h" + +#include "bladerunner/audio_player.h" +#include "bladerunner/bladerunner.h" +#include "bladerunner/game_info.h" +#include "bladerunner/ui/kia.h" +#include "bladerunner/ui/kia_shapes.h" + +namespace BladeRunner { + +UICheckBox::UICheckBox(BladeRunnerEngine *vm, UIComponentCallback *valueChangedCallback, void *callbackData, Common::Rect rect, int style, bool isChecked) + : UIComponent(vm) { + + _valueChangedCallback = valueChangedCallback; + _callbackData = callbackData; + + _isEnabled = true; + _hasFocus = false; + _isPressed = false; + _style = style; + + if (isChecked) { + _frame = 5; + } else { + _frame = 0; + } + + _timeLast = _vm->getTotalPlayTime(); + _rect = rect; + _isChecked = isChecked; +} + + +void UICheckBox::draw(Graphics::Surface &surface) { + int shapeId; + if (_rect.right > _rect.left && _rect.bottom > _rect.top) { + uint timeNow = _vm->getTotalPlayTime(); + if (timeNow - _timeLast > 67) { + int frameDelta = (timeNow - _timeLast) / 67u; + _timeLast = timeNow; + + if (_isChecked) { + _frame = MIN(_frame + frameDelta, 5); + } else { + _frame = MAX(_frame - frameDelta, 0); + } + } + + if (_style) { + if (_frame || (_hasFocus && !_isPressed && _isEnabled)) { + if (_frame != 5 || (_hasFocus && !_isPressed && _isEnabled)) { + shapeId = _frame + 54; + } else { + shapeId = 53; + } + } else { + shapeId = 52; + } + } else { + if (_frame || (_hasFocus && !_isPressed && _isEnabled)) { + if (_frame != 5 || (_hasFocus && !_isPressed && _isEnabled)) { + shapeId = _frame + 62; + } else { + shapeId = 61; + } + } else { + shapeId = 60; + } + } + + _vm->_kia->_shapes->get(shapeId)->draw(surface, _rect.left, _rect.top + 1); + } +} + +void UICheckBox::enable() { + _isEnabled = true; + _isPressed = false; + _hasFocus = false; +} + +void UICheckBox::disable() { + _isEnabled = false; +} + +void UICheckBox::setChecked(bool isChecked) { + _isChecked = isChecked; +} + +void UICheckBox::handleMouseMove(int mouseX, int mouseY) { + if (_rect.contains(mouseX, mouseY)) { + if (!_hasFocus && _isEnabled && !_isPressed ) { + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(508), 100, 0, 0, 50, 0); + } + _hasFocus = true; + } else { + _hasFocus = false; + } +} + +void UICheckBox::handleMouseDown(bool alternateButton) { + if (!alternateButton) { + if (_isEnabled && _hasFocus) { + _isChecked = !_isChecked; + if (_valueChangedCallback) { + _valueChangedCallback(_callbackData, this); + } + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(509), 100, 0, 0, 50, 0); + } else { + _isPressed = true; + } + } +} + +void UICheckBox::handleMouseUp(bool alternateButton) { + _isPressed = false; +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/ui_check_box.h b/engines/bladerunner/ui/ui_check_box.h new file mode 100644 index 0000000000..cfd584b09e --- /dev/null +++ b/engines/bladerunner/ui/ui_check_box.h @@ -0,0 +1,64 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_UI_CHECKBOX_H +#define BLADERUNNER_UI_CHECKBOX_H + +#include "bladerunner/ui/ui_component.h" + +#include "common/rect.h" + +namespace BladeRunner { + +class UICheckBox : public UIComponent +{ +private: + UIComponentCallback *_valueChangedCallback; + void *_callbackData; + + int _style; + int _isEnabled; + Common::Rect _rect; + int _frame; + int _isPressed; + uint _timeLast; + int _hasFocus; + +public: + bool _isChecked; + + UICheckBox(BladeRunnerEngine *vm, UIComponentCallback *valueChangedCallback, void *callbackData, Common::Rect rect, int style, bool isChecked); + + void draw(Graphics::Surface &surface); + + void enable(); + void disable(); + void setChecked(bool isChecked); + + void handleMouseMove(int mouseX, int mouseY); + void handleMouseDown(bool alternateButton); + void handleMouseUp(bool alternateButton); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/ui_component.h b/engines/bladerunner/ui/ui_component.h new file mode 100644 index 0000000000..9c290d9dcb --- /dev/null +++ b/engines/bladerunner/ui/ui_component.h @@ -0,0 +1,62 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_UI_COMPONENT_H +#define BLADERUNNER_UI_COMPONENT_H + +namespace Common{ +struct KeyState; +} + +namespace Graphics { +struct Surface; +} + +namespace BladeRunner { + +class BladeRunnerEngine; + +typedef void UIComponentCallback(void *callbackData, void *source); + +class UIComponent +{ +protected: + BladeRunnerEngine *_vm; + +public: + UIComponent(BladeRunnerEngine *vm) { + _vm = vm; + } + + virtual ~UIComponent() {} + + virtual void draw(Graphics::Surface &surface) {} + + virtual void handleMouseMove(int mouseX, int mouseY) {} + virtual void handleMouseDown(bool alternateButton) {} + virtual void handleMouseUp(bool alternateButton) {} + virtual void handleKeyUp(const Common::KeyState &kbd) {} +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/ui_container.cpp b/engines/bladerunner/ui/ui_container.cpp new file mode 100644 index 0000000000..78097a9d3d --- /dev/null +++ b/engines/bladerunner/ui/ui_container.cpp @@ -0,0 +1,67 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 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/ui_container.h" + +#include "common/keyboard.h" + +namespace BladeRunner { + +void UIContainer::draw(Graphics::Surface &surface) { +for (Common::Array<UIComponent*>::iterator component = _components.begin(); component != _components.end(); component++) { + (*component)->draw(surface); + } +} + +void UIContainer::handleMouseMove(int mouseX, int mouseY) { + for (Common::Array<UIComponent*>::iterator component = _components.begin(); component != _components.end(); component++) { + (*component)->handleMouseMove(mouseX, mouseY); + } +} + +void UIContainer::handleMouseDown(bool alternateButton) { +for (Common::Array<UIComponent*>::iterator component = _components.begin(); component != _components.end(); component++) { + (*component)->handleMouseDown(alternateButton); + } +} + +void UIContainer::handleMouseUp(bool alternateButton) { +for (Common::Array<UIComponent*>::iterator component = _components.begin(); component != _components.end(); component++) { + (*component)->handleMouseUp(alternateButton); + } +} + +void UIContainer::handleKeyUp(const Common::KeyState &kbd) { +for (Common::Array<UIComponent*>::iterator component = _components.begin(); component != _components.end(); component++) { + (*component)->handleKeyUp(kbd); + } +} + +void UIContainer::add(UIComponent *component) { + _components.push_back(component); +} + +void UIContainer::clear() { + _components.clear(); +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/ui_container.h b/engines/bladerunner/ui/ui_container.h new file mode 100644 index 0000000000..9d5bded960 --- /dev/null +++ b/engines/bladerunner/ui/ui_container.h @@ -0,0 +1,56 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_UI_CONTAINER_H +#define BLADERUNNER_UI_CONTAINER_H + +#include "bladerunner/ui/ui_component.h" + +#include "common/array.h" + +namespace BladeRunner { + +class UIComponent; + +class UIContainer : public UIComponent +{ +private: + Common::Array<UIComponent*> _components; + +public: + UIContainer(BladeRunnerEngine *vm) : UIComponent(vm) {} + + void draw(Graphics::Surface &surface); + + void handleMouseMove(int mouseX, int mouseY); + void handleMouseDown(bool alternateButton); + void handleMouseUp(bool alternateButton); + void handleKeyUp(const Common::KeyState &kbd); + + void add(UIComponent *component); + void clear(); +}; + + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/ui_image_picker.cpp b/engines/bladerunner/ui/ui_image_picker.cpp new file mode 100644 index 0000000000..997ff7bc5e --- /dev/null +++ b/engines/bladerunner/ui/ui_image_picker.cpp @@ -0,0 +1,331 @@ +/* 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/ui_image_picker.h" + +#include "bladerunner/bladerunner.h" +#include "bladerunner/font.h" +#include "bladerunner/mouse.h" +#include "bladerunner/shape.h" + +#include "common/rect.h" +#include "common/str.h" +#include "graphics/surface.h" + +namespace BladeRunner { + +UIImagePicker::UIImagePicker(BladeRunnerEngine *vm, int imageCount) { + _vm = vm; + reset(); + _images.resize(imageCount); + _imageCount = imageCount; + resetImages(); +} + +UIImagePicker::~UIImagePicker() { + _images.clear(); + reset(); +} + +void UIImagePicker::resetImages() { + for (int i = 0; i != _imageCount; i++) { + resetImage(i); + } +} + +bool UIImagePicker::defineImage(int i, Common::Rect rect, const Shape *shapeUp, const Shape *shapeHovered, const Shape *shapeDown, const char *tooltip) { + if (i < 0 || i >= _imageCount || _images[i].active) { + return false; + } + + Image &img = _images[i]; + + img.rect = rect; + // for rect to be inclusive + img.rect.right += 1; + img.rect.bottom += 1; + img.shapeUp = shapeUp; + img.shapeHovered = shapeHovered; + img.shapeDown = shapeDown; + img.active = true; + + if (tooltip != nullptr) { + img.tooltip = tooltip; + } else { + img.tooltip.clear(); + } + + return true; +} + +bool UIImagePicker::setImageTop(int i, int top) { + if (i < 0 || i >= _imageCount || !_images[i].active) { + return false; + } + + Image &img = _images[i]; + + img.rect.moveTo(img.rect.left, top); + + return true; +} + +bool UIImagePicker::setImageLeft(int i, int left) { + if (i < 0 || i >= _imageCount || !_images[i].active) { + return false; + } + + Image &img = _images[i]; + + img.rect.moveTo(left, img.rect.top); + + return true; +} + +bool UIImagePicker::setImageShapeUp(int i, const Shape *shapeUp) { + if (i < 0 || i >= _imageCount || !_images[i].active) { + return false; + } + + _images[i].shapeUp = shapeUp; + + return true; +} + +bool UIImagePicker::setImageShapeHovered(int i, const Shape *shapeHovered) { + if (i < 0 || i >= _imageCount || !_images[i].active) { + return false; + } + + _images[i].shapeHovered = shapeHovered; + + return true; +} + +bool UIImagePicker::setImageShapeDown(int i, const Shape *shapeDown) { + if (i < 0 || i >= _imageCount || !_images[i].active) { + return false; + } + + _images[i].shapeDown = shapeDown; + + return true; +} + +bool UIImagePicker::setImageTooltip(int i, const char *tooltip) { + if (i < 0 || i >= _imageCount || !_images[i].active) { + return false; + } + + _images[i].tooltip = tooltip; + + return true; +} + +bool UIImagePicker::resetActiveImage(int i) { + if (i < 0 || i >= _imageCount || !_images[i].active) { + return false; + } + + resetImage(i); + return true; +} + +void UIImagePicker::activate(UIImagePickerCallback *mouseInCallback, + UIImagePickerCallback *mouseOutCallback, + UIImagePickerCallback *mouseDownCallback, + UIImagePickerCallback *mouseUpCallback, + void *callbackData) +{ + _isButtonDown = false; + _mouseInCallback = mouseInCallback; + _mouseOutCallback = mouseOutCallback; + _mouseDownCallback = mouseDownCallback; + _mouseUpCallback = mouseUpCallback; + _callbackData = callbackData; + _hoverStartTimestamp = 0; + _isVisible = true; + _hoveredImageIndex = -1; + _pressedImageIndex = -1; +} + +void UIImagePicker::deactivate() { + _isButtonDown = false; + _mouseInCallback = nullptr; + _mouseOutCallback = nullptr; + _mouseDownCallback = nullptr; + _mouseUpCallback = nullptr; + _callbackData = nullptr; + _hoverStartTimestamp = 0; + _isVisible = false; + _hoveredImageIndex = -1; + _pressedImageIndex = -1; +} + +void UIImagePicker::draw(Graphics::Surface &surface) { + if (!_isVisible) { + return; + } + + for (int i = 0; i != _imageCount; ++i) { + Image &img = _images[i]; + if (!img.active) { + continue; + } + + // TODO: Check interaction with Mouse::isDisabled + if (i == _hoveredImageIndex && i == _pressedImageIndex && _isButtonDown) { + if (img.shapeDown) { + img.shapeDown->draw(surface, img.rect.left, img.rect.top); + } + } else if (i == _hoveredImageIndex && !_isButtonDown) { + if (img.shapeHovered) { + img.shapeHovered->draw(surface, img.rect.left, img.rect.top); + } + } else { + if (img.shapeUp) { + img.shapeUp->draw(surface, img.rect.left, img.rect.top); + } + } +#if BLADERUNNER_DEBUG_RENDERING + surface.frameRect(img.rect, 0x7fff); +#endif + } +} + +void UIImagePicker::drawTooltip(Graphics::Surface &surface, int x, int y) { + if (!_isVisible) { + return; + } + + if (_hoveredImageIndex == -1 || _vm->_mouse->isDisabled() || !_images[_hoveredImageIndex].active || _vm->getTotalPlayTime() < _hoverStartTimestamp + 1000) { + return; + } + + Common::String &tooltip = _images[_hoveredImageIndex].tooltip; + int width = _vm->_mainFont->getTextWidth(tooltip) + 1; + int height = _vm->_mainFont->getTextHeight(tooltip) + 1; + + Common::Rect rect; + rect.left = x - ((width / 2) + 1); + if (rect.left < 0) { + rect.left = 0; + } + + rect.top = y - 10; + if (rect.top < 0) { + rect.top = 0; + } + + rect.right = width + rect.left + 3; + if (rect.right >= 640) { + rect.right = 639; + rect.left = 636 - width; + } + + rect.bottom = height + rect.top + 1; + if (rect.bottom >= 480) { + rect.bottom = 479; + rect.top = 478 - height; + } + + surface.fillRect(rect, 0); + surface.frameRect(rect, 0x7FFF); + _vm->_mainFont->drawColor(tooltip, surface, rect.left + 2, rect.top, 0x7FFF); +} + +void UIImagePicker::handleMouseAction(int x, int y, bool down, bool up, bool ignore) { + if (!_isVisible || ignore) { + return; + } + + int hoveredImageIndex = -1; + for (int i = 0; i != _imageCount; ++i) { + if (_images[i].rect.contains(x, y)) { + hoveredImageIndex = i; + break; + } + } + + // If mouse moved to a new image + if (hoveredImageIndex != _hoveredImageIndex) { + if (!_isButtonDown) { + if (hoveredImageIndex == -1) { + if (_mouseOutCallback) { + _mouseOutCallback(hoveredImageIndex, _callbackData); + } + } else { + if (_mouseInCallback) { + _mouseInCallback(hoveredImageIndex, _callbackData); + } + } + } + _hoverStartTimestamp = _vm->getTotalPlayTime(); + _hoveredImageIndex = hoveredImageIndex; + } + + // If mouse button changed to pressed + if (down && !_isButtonDown) { + _isButtonDown = true; + _pressedImageIndex = _hoveredImageIndex; + if (_hoveredImageIndex != 1) { + if (_mouseDownCallback) { + _mouseDownCallback(_hoveredImageIndex, _callbackData); + } + } + } + + // If mouse button changed to released + if (up) { + if (_isButtonDown) { + if (_hoveredImageIndex == _pressedImageIndex && _pressedImageIndex != -1) { + if (_mouseUpCallback) + _mouseUpCallback(_hoveredImageIndex, _callbackData); + } + } + _isButtonDown = false; + _pressedImageIndex = -1; + } +} + +void UIImagePicker::resetImage(int i) { + assert(i >= 0 && i < _imageCount); + Image &img = _images[i]; + + img.active = false; + img.rect.left = -1; + img.rect.top = -1; + img.rect.right = -1; + img.rect.bottom = -1; + img.shapeUp = nullptr; + img.shapeHovered = nullptr; + img.shapeDown = nullptr; + img.tooltip.clear(); +} + +bool UIImagePicker::hasHoveredImage() { + return _hoveredImageIndex >= 0; +} + +void UIImagePicker::reset() {} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/ui_image_picker.h b/engines/bladerunner/ui/ui_image_picker.h new file mode 100644 index 0000000000..00f2f3dfd9 --- /dev/null +++ b/engines/bladerunner/ui/ui_image_picker.h @@ -0,0 +1,104 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_UI_IMAGE_PICKER_H +#define BLADERUNNER_UI_IMAGE_PICKER_H + +#include "common/array.h" +#include "common/rect.h" +#include "common/str.h" + +namespace Graphics { +struct Surface; +} + +namespace BladeRunner { + +class BladeRunnerEngine; +class Shape; + +typedef void UIImagePickerCallback(int, void *); + +class UIImagePicker { + struct Image { + int active; + Common::Rect rect; + const Shape *shapeUp; + const Shape *shapeHovered; + const Shape *shapeDown; + Common::String tooltip; + }; + + BladeRunnerEngine *_vm; + + int _isVisible; + int _imageCount; + int _hoveredImageIndex; + int _pressedImageIndex; + uint32 _hoverStartTimestamp; + int _isButtonDown; + Common::Array<Image> _images; + + UIImagePickerCallback *_mouseInCallback; + UIImagePickerCallback *_mouseOutCallback; + UIImagePickerCallback *_mouseDownCallback; + UIImagePickerCallback *_mouseUpCallback; + void *_callbackData; + +public: + UIImagePicker(BladeRunnerEngine *vm, int imageCount); + ~UIImagePicker(); + + void resetImages(); + bool defineImage(int i, Common::Rect rect, const Shape *shapeUp, const Shape *shapeHovered, const Shape *shapeDown, const char *tooltip); + + bool setImageTop(int i, int top); + bool setImageLeft(int i, int left); + bool setImageShapeUp(int i, const Shape *shapeUp); + bool setImageShapeHovered(int i, const Shape *shapeHovered); + bool setImageShapeDown(int i, const Shape *shapeDown); + bool setImageTooltip(int i, const char *tooltip); + + bool resetActiveImage(int i); + + void activate(UIImagePickerCallback *mouseInCallback, + UIImagePickerCallback *mouseOutCallback, + UIImagePickerCallback *mouseDownCallback, + UIImagePickerCallback *mouseUpCallback, + void *callbackData); + + void deactivate(); + + void draw(Graphics::Surface &surface); + void drawTooltip(Graphics::Surface &surface, int x, int y); + + void handleMouseAction(int x, int y, bool down, bool up, bool ignore = false); + + void resetImage(int i); + bool hasHoveredImage(); + + void reset(); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/ui_input_box.cpp b/engines/bladerunner/ui/ui_input_box.cpp new file mode 100644 index 0000000000..409563f73e --- /dev/null +++ b/engines/bladerunner/ui/ui_input_box.cpp @@ -0,0 +1,115 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 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/ui_input_box.h" + +#include "bladerunner/bladerunner.h" +#include "bladerunner/font.h" + +#include "common/keyboard.h" + +#include "graphics/surface.h" + +namespace BladeRunner { + +UIInputBox::UIInputBox(BladeRunnerEngine *vm, UIComponentCallback *valueChangedCallback, void *callbackData, Common::Rect rect, int maxLength, const Common::String &text) + : UIComponent(vm) { + _valueChangedCallback = valueChangedCallback; + _callbackData = callbackData; + + _isVisible = true; + _rect = rect; + + _maxLength = maxLength; + _length = 0; + setText(text); + + _cursorIsVisible = false; + _timeLast = _vm->getTotalPlayTime(); +} + +void UIInputBox::draw(Graphics::Surface &surface) { + if (!_isVisible) { + return; + } + + int rectHalfWidth = (_rect.right + _rect.left) / 2; + int textHalfWidth = _vm->_mainFont->getTextWidth(_text) / 2; + + _vm->_mainFont->drawColor(_text, surface, rectHalfWidth - textHalfWidth, _rect.top, 0x4DC7); // 10011 01110 00111 + + if (_cursorIsVisible) { + surface.vLine(textHalfWidth + rectHalfWidth + 2, _rect.top, _rect.bottom - 1, 0x7FDD); // 11111 11110 11101 + } + + if (_vm->getTotalPlayTime() - _timeLast > 500) { + _timeLast = _vm->getTotalPlayTime(); + _cursorIsVisible = !_cursorIsVisible; + } +} + +void UIInputBox::setText(const Common::String &text) { + _text = text; +} + +const Common::String &UIInputBox::getText() { + return _text; +} + +void UIInputBox::show() { + _isVisible = true; +} + +void UIInputBox::hide() { + _isVisible = false; +} + +void UIInputBox::handleKeyUp(const Common::KeyState &kbd) { + if (_isVisible) { + if (charIsValid(kbd)) { + _text += kbd.ascii; + } else if (kbd.keycode == Common::KEYCODE_BACKSPACE) { + _text.deleteLastChar(); + } else if (kbd.keycode == Common::KEYCODE_RETURN && !_text.empty()) { + if (_valueChangedCallback) { + _valueChangedCallback(_callbackData, this); + } + } + } +} + +bool UIInputBox::charIsValid(const Common::KeyState &kbd) +{ + return kbd.ascii >= ' ' + && kbd.ascii != '<' + && kbd.ascii != '>' + && kbd.ascii != ':' + && kbd.ascii != '"' + && kbd.ascii != '/' + && kbd.ascii != '\\' + && kbd.ascii != '|' + && kbd.ascii != '?' + && kbd.ascii != '*' + && (kbd.ascii <= '¿' || kbd.ascii == '¡' || kbd.ascii == 'ß'); +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/ui_input_box.h b/engines/bladerunner/ui/ui_input_box.h new file mode 100644 index 0000000000..473fe175df --- /dev/null +++ b/engines/bladerunner/ui/ui_input_box.h @@ -0,0 +1,69 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_ui_inputbox_H +#define BLADERUNNER_ui_inputbox_H + +#include "bladerunner/ui/ui_component.h" + +#include "common/rect.h" +#include "common/str.h" + +namespace BladeRunner { + +class UIInputBox : public UIComponent +{ +private: + UIComponentCallback *_valueChangedCallback; + void *_callbackData; + + bool _isVisible; + Common::Rect _rect; + + int _maxLength; + int _length; + Common::String _text; + + bool _cursorIsVisible; + + int _timeLast; + +public: + UIInputBox(BladeRunnerEngine *vm, UIComponentCallback *valueChangedCallback, void *callbackData, Common::Rect rect, int maxLength, const Common::String &text); + + void draw(Graphics::Surface &surface); + + void setText(const Common::String &text); + const Common::String &getText(); + + void show(); + void hide(); + + void handleKeyUp(const Common::KeyState &kbd); + +private: + bool charIsValid(const Common::KeyState &kbd); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/ui_scroll_box.cpp b/engines/bladerunner/ui/ui_scroll_box.cpp new file mode 100644 index 0000000000..a0d53a444d --- /dev/null +++ b/engines/bladerunner/ui/ui_scroll_box.cpp @@ -0,0 +1,662 @@ +/* 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/ui_scroll_box.h" + +#include "bladerunner/audio_player.h" +#include "bladerunner/bladerunner.h" +#include "bladerunner/font.h" +#include "bladerunner/game_info.h" +#include "bladerunner/shape.h" +#include "bladerunner/ui/kia.h" +#include "bladerunner/ui/kia_shapes.h" + +namespace BladeRunner { + +const int UIScrollBox::k3DFrameColors[] = { 0x1083, 0x14A5, 0x14A6, 0x2508, 0x5230, 0x5230, 0x0000, 0x0000 }; +const int UIScrollBox::kTextBackgroundColors[] = { 0x14EA, 0x190C, 0x1D2E, 0x2570, 0x4F1F, 0x0000 }; +const int UIScrollBox::kTextColors1[] = { 0x25B3, 0x31F7, 0x3A5B, 0x46BF, 0x4F1F }; +const int UIScrollBox::kTextColors2[] = { 0x677F, 0x6F9F, 0x73BF, 0x77DF, 0x7FFF }; +const int UIScrollBox::kTextColors3[] = { 0x7BB8, 0x7BBA, 0x7BDB, 0x7FDD, 0x7FFF }; +const int UIScrollBox::kTextColors4[] = { 0x4DC7, 0x5E4B, 0x6EEE, 0x7751, 0x7F92 }; + +UIScrollBox::UIScrollBox(BladeRunnerEngine *vm, UIScrollBoxCallback *lineSelectedCallback, void *callbackData, int maxLineCount, int style, bool center, Common::Rect rect, Common::Rect scrollBarRect) : UIComponent(vm) { + _selectedLineState = 0; + _scrollUpButtonState = 0; + _scrollDownButtonState = 0; + _scrollAreaUpState = 0; + _scrollAreaDownState = 0; + _scrollBarState = 0; + + _scrollUpButtonHover = false; + _scrollDownButtonHover = false; + _scrollAreaUpHover = false; + _scrollAreaDownHover = false; + _scrollBarHover = false; + + _hoveredLine = -1; + _selectedLineIndex = -1; + + _lineSelectedCallback = lineSelectedCallback; + _callbackData = callbackData; + + _isVisible = false; + _style = style; + _center = center; + _timeLastScroll = _vm->getTotalPlayTime(); + _timeLastCheckbox = _vm->getTotalPlayTime(); + _timeLastHighlight = _vm->getTotalPlayTime(); + + _highlightFrame = 0; + + _rect = rect; + _scrollBarRect = scrollBarRect; + + _lineCount = 0; + _maxLineCount = maxLineCount; + + _firstLineVisible = 0; + + _maxLinesVisible = _rect.height() / kLineHeight; + _rect.bottom = _rect.top + kLineHeight * _maxLinesVisible - 1; + + _lines.resize(_maxLineCount); + for (int i = 0; i < _maxLineCount; ++i) { + _lines[i] = new Line(); + _lines[i]->lineData = -1; + _lines[i]->flags = 0x00; + _lines[i]->checkboxFrame = 5; + } +} + +UIScrollBox::~UIScrollBox() { + for (int i = 0; i < _maxLineCount; ++i) { + delete _lines[i]; + } +} + +void UIScrollBox::show() { + _selectedLineState = 0; + _scrollUpButtonState = 0; + _scrollDownButtonState = 0; + _scrollAreaUpState = 0; + _scrollAreaDownState = 0; + _scrollBarState = 0; + + _hoveredLine = -1; + _selectedLineIndex = -1; + + _scrollUpButtonHover = false; + _scrollDownButtonHover = false; + _scrollAreaUpHover = false; + _scrollAreaDownHover = false; + _scrollBarHover = false; + + _timeLastScroll = _vm->getTotalPlayTime(); + _timeLastCheckbox = _vm->getTotalPlayTime(); + _timeLastHighlight = _vm->getTotalPlayTime(); + + _highlightFrame = 0; + _isVisible = true; +} + +void UIScrollBox::hide() { + _isVisible = false; +} + +void UIScrollBox::clearLines(){ + _lineCount = 0; + _firstLineVisible = 0; + +} + +void UIScrollBox::addLine(const Common::String &text, int lineData, int flags) { + _lines[_lineCount]->text = text; + _lines[_lineCount]->lineData = lineData; + _lines[_lineCount]->flags = flags; + + ++_lineCount; +} + +void UIScrollBox::addLine(const char *text, int lineData, int flags) { + _lines[_lineCount]->text = text; + _lines[_lineCount]->lineData = lineData; + _lines[_lineCount]->flags = flags; + + ++_lineCount; +} + +void UIScrollBox::sortLines() { + qsort(_lines.data(), _lineCount, sizeof(Line *), &sortFunction); +} + +void UIScrollBox::handleMouseMove(int mouseX, int mouseY) { + if (!_isVisible) { + return; + } + + if (_rect.contains(mouseX, mouseY)) { + int newHoveredLine = (mouseY - _rect.top) / 10 + _firstLineVisible; + if (newHoveredLine >= _lineCount) { + newHoveredLine = -1; + } + + if (newHoveredLine != _hoveredLine && newHoveredLine >= 0 && newHoveredLine < _lineCount) { + if (_lines[newHoveredLine]->lineData >= 0 && _selectedLineState == 0) { + int soundId = 507; + if (_lines[newHoveredLine]->flags & 0x01 ) { + soundId = 508; + } + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(soundId), 100, 0, 0, 50, 0); + } + } + _hoveredLine = newHoveredLine; + } else { + _hoveredLine = -1; + } + + _scrollUpButtonHover = + (mouseX >= _scrollBarRect.left) + && (mouseX < _scrollBarRect.left + 15) + && (mouseY >= _scrollBarRect.top) + && (mouseY < _scrollBarRect.top + 8); + + _scrollDownButtonHover = + (mouseX >= _scrollBarRect.left) + && (mouseX < _scrollBarRect.left + 15) + && (mouseY > _scrollBarRect.bottom - 8) + && (mouseY <= _scrollBarRect.bottom); + + int scrollAreaHeight = _scrollBarRect.bottom - _scrollBarRect.top - 15; + + int scrollBarHeight = scrollAreaHeight; + if (_lineCount > _maxLinesVisible) { + scrollBarHeight = _maxLinesVisible * scrollAreaHeight / _lineCount; + } + if (scrollBarHeight < 16) { + scrollBarHeight = 16; + } + + int scrollAreaEmptySize = scrollAreaHeight - scrollBarHeight; + + int scrollBarY = 0; + if (_lineCount > _maxLinesVisible) { + scrollBarY = scrollAreaEmptySize * _firstLineVisible / (_lineCount - _maxLinesVisible); + } + + if (_scrollBarState == 2) { + int v12 = scrollBarHeight / 2 + 8; + if (mouseY - _scrollBarRect.top > v12 && _lineCount > _maxLinesVisible && scrollAreaEmptySize > 0) { + _firstLineVisible = (_lineCount - _maxLinesVisible) * (mouseY - _scrollBarRect.top - v12) / scrollAreaEmptySize; + if (_firstLineVisible > _lineCount - _maxLinesVisible) { + _firstLineVisible = _lineCount - _maxLinesVisible; + } + } else { + _firstLineVisible = 0; + } + + if (_lineCount <= _maxLinesVisible) { + scrollBarY = 0; + } else { + scrollBarY = scrollAreaEmptySize * _firstLineVisible/ (_lineCount - _maxLinesVisible); + } + } + scrollBarY = scrollBarY + _scrollBarRect.top + 8; + + _scrollBarHover = + (mouseX >= _scrollBarRect.left) + && (mouseX < _scrollBarRect.left + 15) + && (mouseY >= scrollBarY) + && (mouseY < scrollBarY + scrollBarHeight); + + _scrollAreaUpHover = + (mouseX >= _scrollBarRect.left) + && (mouseX < _scrollBarRect.left + 15) + && (mouseY >= _scrollBarRect.top + 8) + && (mouseY < scrollBarY); + + _scrollAreaDownHover = + (mouseX >= _scrollBarRect.left) + && (mouseX < _scrollBarRect.left + 15) + && (mouseY >= scrollBarY + scrollBarHeight) + && (mouseY < _scrollBarRect.bottom - 8); +} + +void UIScrollBox::handleMouseDown(bool alternateButton) { + if (!_isVisible) { + return; + } + + _mouseButton = alternateButton; + if (_hoveredLine == -1) { + _selectedLineState = 1; + } else if (_selectedLineIndex == -1) { + _selectedLineIndex = _hoveredLine; + _selectedLineState = 2; + if (_hoveredLine < _lineCount) { + if (_lineSelectedCallback) { + _lineSelectedCallback(_callbackData, this, _lines[_selectedLineIndex]->lineData, _mouseButton); + } + + if (_lines[_selectedLineIndex]->flags & 0x01) { + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(509), 100, 0, 0, 50, 0); + } + } + } + if (!alternateButton) { + if (_scrollUpButtonHover) { + _scrollUpButtonState = 2; + _timeLastScroll = _vm->getTotalPlayTime() - 160; + } else { + _scrollUpButtonState = 1; + } + if (_scrollDownButtonHover) { + _scrollDownButtonState = 2; + } else { + _scrollDownButtonState = 1; + } + if (_scrollBarHover) { + _scrollBarState = 2; + } else { + _scrollBarState = 1; + } + if (_scrollAreaUpHover) { + _scrollAreaUpState = 2; + _timeLastScroll = _vm->getTotalPlayTime() - 160; + } else { + _scrollAreaUpState = 1; + } + if (_scrollAreaDownHover) { + _scrollAreaDownState = 2; + _timeLastScroll = _vm->getTotalPlayTime() - 160; + } else { + _scrollAreaDownState = 1; + } + } +} + +void UIScrollBox::handleMouseUp(bool alternateButton) { + if (_isVisible) { + if ( alternateButton == _mouseButton) { + _selectedLineState = 0; + _selectedLineIndex = -1; + } + + if (!alternateButton) { + _scrollUpButtonState = 0; + _scrollDownButtonState = 0; + _scrollAreaUpState = 0; + _scrollAreaDownState = 0; + _scrollBarState = 0; + } + } +} + +int UIScrollBox::getSelectedLineData() { + if (_hoveredLine >= 0 && _selectedLineState != 1 && _hoveredLine < _lineCount) { + return _lines[_hoveredLine]->lineData; + } + return -1; +} + +void UIScrollBox::draw(Graphics::Surface &surface) { + int timeNow = _vm->getTotalPlayTime(); + + // update scrolling + if (_scrollUpButtonState == 2 && _scrollUpButtonHover) { + if ((timeNow - _timeLastScroll) > 160) { + scrollUp(); + _timeLastScroll = timeNow; + } + } else if (_scrollDownButtonState == 2 && _scrollDownButtonHover) { + if ((timeNow - _timeLastScroll) > 160) { + scrollDown(); + _timeLastScroll = timeNow; + } + } else if (_scrollAreaUpState == 2 && _scrollAreaUpHover) { + if ((timeNow - _timeLastScroll) > 160) { + _firstLineVisible -= _maxLinesVisible - 1; + _firstLineVisible = CLIP(_firstLineVisible, 0, _lineCount - _maxLinesVisible); + _timeLastScroll = timeNow; + } + } else if (_scrollAreaDownState == 2 && _scrollAreaDownHover) { + if ((timeNow - _timeLastScroll) > 160) { + _firstLineVisible += _maxLinesVisible - 1; + _firstLineVisible = CLIP(_firstLineVisible, 0, _lineCount - _maxLinesVisible); + _timeLastScroll = timeNow; + } + } + + // update checkboxes + int timeDiffCheckBox = timeNow - _timeLastCheckbox; + if (timeDiffCheckBox > 67) { + _timeLastCheckbox = timeNow; + for (int i = 0; i < _lineCount; ++i) { + if (_lines[i]->flags & 0x01) { // has checkbox + if (_lines[i]->flags & 0x02) { // checkbox checked + if (_lines[i]->checkboxFrame < 5) { + _lines[i]->checkboxFrame += timeDiffCheckBox / 67; + } + if (_lines[i]->checkboxFrame > 5) { + _lines[i]->checkboxFrame = 5; + } + } else { // checkbox not checked + if (_lines[i]->checkboxFrame > 0) { + _lines[i]->checkboxFrame -= timeDiffCheckBox / 67; + } + if (_lines[i]->checkboxFrame < 0) { + _lines[i]->checkboxFrame = 0; + } + } + } + } + } + + + // update highlight + if ((timeNow - _timeLastHighlight) > 67) { + _timeLastHighlight = timeNow; + _highlightFrame = (_highlightFrame + 1) % 8; + } + + // draw text lines + int linesVisible = 0; + int lastLineVisible = 0; + + if (_maxLinesVisible < _lineCount - _firstLineVisible) { + linesVisible = _maxLinesVisible; + lastLineVisible = _firstLineVisible + _maxLinesVisible; + } else { + linesVisible = _lineCount - _firstLineVisible; + lastLineVisible = _lineCount; + } + + if (_firstLineVisible < lastLineVisible) { + int y = _rect.top; + int y1 = _rect.top + 8; + int y2 = _rect.top + 2; + int i = _firstLineVisible; + do { + int startingColorIndex = 3; + if (i - _firstLineVisible < 3) { + startingColorIndex = i - _firstLineVisible; + } + + int endingColorIndex = 3; + if (i - _firstLineVisible >= linesVisible - 3) { + endingColorIndex = linesVisible - (i - _firstLineVisible + 1); + } + + int colorIndex = endingColorIndex; + if (startingColorIndex < endingColorIndex) { + colorIndex = startingColorIndex; + } + + bool v35 = false; + int color = 0; + + if ((((_selectedLineState == 0 && i == _hoveredLine) || (_selectedLineState == 2 && i == _selectedLineIndex && _selectedLineIndex == _hoveredLine)) && _lines[i]->lineData != -1) || _lines[i]->flags & 0x04) { + v35 = true; + if (_style) { + color = kTextColors2[colorIndex]; + } else { + color = kTextColors3[colorIndex]; + } + } + else { + if (_style) { + color = kTextColors1[colorIndex]; + } else { + color = kTextColors4[colorIndex]; + } + } + + int x = _rect.left; + + if (_lines[i]->flags & 0x01) { // has checkbox + int checkboxShapeId = 0; + if (_style == 0) { + if (_lines[i]->checkboxFrame || v35) { + if (_lines[i]->checkboxFrame != 5 || v35) { + checkboxShapeId = _lines[i]->checkboxFrame + 62; + } else { + checkboxShapeId = 61; + } + } else { + checkboxShapeId = 60; + } + } else if (_lines[i]->checkboxFrame || v35) { + if (_lines[i]->checkboxFrame != 5 || v35) { + checkboxShapeId = _lines[i]->checkboxFrame + 54; + } else { + checkboxShapeId = 53; + } + } else { + checkboxShapeId = 52; + } + _vm->_kia->_shapes->get(checkboxShapeId)->draw(surface, x - 1, y); + x += 11; + } + + if (_lines[i]->flags & 0x10) { // highlighted line + if (_lines[i]->flags & 0x20) { + int highlightShapeId = _highlightFrame; + if (highlightShapeId > 4) { + highlightShapeId = 8 - highlightShapeId; + } + _vm->_kia->_shapes->get(highlightShapeId + 85)->draw(surface, x, y2); + } + x += 6; + } + + if (_lines[i]->flags & 0x08) { // has background rectangle + int colorBackground = 0; + if (_style) { + colorBackground = kTextBackgroundColors[colorIndex]; + } else { + colorBackground = 0x28E4; + } + surface.fillRect(Common::Rect(x, y, _rect.right + 1, y1 + 1), colorBackground); + } + + if (_center) { + x = (_rect.width() - _vm->_mainFont->getTextWidth(_lines[i]->text)) / 2; + } + + _vm->_mainFont->drawColor(_lines[i]->text, surface, x, y, color); + + y1 += kLineHeight; + y2 += kLineHeight; + y += kLineHeight; + ++i; + } + while (i < lastLineVisible); + } + + // draw scroll up button + int scrollUpButtonShapeId = 0; + if (_scrollUpButtonState) { + if (_scrollUpButtonState == 2) { + if (_scrollUpButtonHover) { + scrollUpButtonShapeId = 72; + } else { + scrollUpButtonShapeId = 71; + } + } else { + scrollUpButtonShapeId = 70; + } + } else if (_scrollUpButtonHover) { + scrollUpButtonShapeId = 71; + } else { + scrollUpButtonShapeId = 70; + } + _vm->_kia->_shapes->get(scrollUpButtonShapeId)->draw(surface, _scrollBarRect.left, _scrollBarRect.top); + + // draw scroll down button + int scrollDownButtonShapeId = 0; + if (_scrollDownButtonState) { + if (_scrollDownButtonState == 2) { + if (_scrollDownButtonHover) { + scrollDownButtonShapeId = 75; + } else { + scrollDownButtonShapeId = 74; + } + } else { + scrollDownButtonShapeId = 73; + } + } else if (_scrollDownButtonHover) { + scrollDownButtonShapeId = 74; + } else { + scrollDownButtonShapeId = 73; + } + _vm->_kia->_shapes->get(scrollDownButtonShapeId)->draw(surface, _scrollBarRect.left, _scrollBarRect.bottom - 7); + + int scrollAreaSize = _scrollBarRect.bottom - (_scrollBarRect.top + 15); + int scrollBarHeight = 0; + if (_lineCount <= _maxLinesVisible) { + scrollBarHeight = _scrollBarRect.bottom - (_scrollBarRect.top + 15); + } else { + scrollBarHeight = _maxLinesVisible * scrollAreaSize / _lineCount; + } + scrollBarHeight = MAX(scrollBarHeight, 16); + + int v56 = 0; + if (_lineCount <= _maxLinesVisible) { + v56 = 0; + } else { + v56 = _firstLineVisible * (scrollAreaSize - scrollBarHeight) / (_lineCount - _maxLinesVisible); + } + + int v58 = v56 + _scrollBarRect.top + 8; + + if (_scrollBarState == 2) { + draw3DFrame(surface, Common::Rect(_scrollBarRect.left, v58, _scrollBarRect.left + 15, v58 + scrollBarHeight), 1, 1); + } else if (!_scrollBarState && _scrollBarHover) { + draw3DFrame(surface, Common::Rect(_scrollBarRect.left, v56 + _scrollBarRect.top + 8, _scrollBarRect.left + 15, v58 + scrollBarHeight), 0, 1); + } else { + draw3DFrame(surface, Common::Rect(_scrollBarRect.left, v58, _scrollBarRect.left + 15, v58 + scrollBarHeight), 0, 0); + } +} + +void UIScrollBox::checkAll() { + for (int i = 0; i < _lineCount; ++i) { + if (_lines[i]->flags & 0x01) { + _lines[i]->flags |= 0x02; + } + } +} + +void UIScrollBox::uncheckAll() { + for (int i = 0; i < _lineCount; ++i) { + if (_lines[i]->flags & 0x01) { + _lines[i]->flags &= ~0x02; + } + } +} + +void UIScrollBox::toggleCheckBox(int lineData) { + int i = findLine(lineData); + if (i != -1) { + if (_lines[i]->flags & 0x02) { + _lines[i]->flags &= ~0x02; + } else { + _lines[i]->flags |= 0x02; + } + } +} + +bool UIScrollBox::hasLine(int lineData) { + return findLine(lineData) != -1; +} + +void UIScrollBox::resetHighlight(int lineData) { + int i = findLine(lineData); + if (i != -1) { + _lines[i]->flags &= ~0x20; + } +} + +void UIScrollBox::setFlags(int lineData, int flags) { + int i = findLine(lineData); + if (i != -1) { + _lines[i]->flags |= flags; + } +} + +void UIScrollBox::resetFlags(int lineData, int flags) { + int i = findLine(lineData); + if (i != -1) { + _lines[i]->flags &= ~flags; + } +} + +int UIScrollBox::sortFunction(const void *item1, const void *item2) { + Line *line1 = *(Line * const *)item1; + Line *line2 = *(Line * const *)item2; + return line1->text.compareToIgnoreCase(line2->text); +} + +void UIScrollBox::draw3DFrame(Graphics::Surface &surface, Common::Rect rect, bool pressed, int style) { + int color1, color2; + + if (pressed) { + color1 = k3DFrameColors[style + 6]; + color2 = k3DFrameColors[style + 4]; + } else { + color1 = k3DFrameColors[style + 4]; + color2 = k3DFrameColors[style + 6]; + } + + int fillColor = k3DFrameColors[style + 2]; + + surface.fillRect(Common::Rect(rect.left + 1, rect.top + 1, rect.right - 1, rect.bottom - 1), fillColor); + + surface.hLine(rect.left + 1, rect.top, rect.right - 2, color1); + surface.hLine(rect.left + 1, rect.bottom - 1, rect.right - 2, color2); + surface.vLine(rect.left, rect.top, rect.bottom - 2, color1); + surface.vLine(rect.right - 1, rect.top + 1, rect.bottom - 1, color2); + surface.hLine(rect.right - 1, rect.top, rect.right - 1, k3DFrameColors[style]); + surface.hLine(rect.left, rect.bottom - 1, rect.left, k3DFrameColors[style]); +} + +void UIScrollBox::scrollUp() { + if (_firstLineVisible > 0) { + --_firstLineVisible; + } +} + +void UIScrollBox::scrollDown() { + if (_lineCount - _firstLineVisible > _maxLinesVisible) { + ++_firstLineVisible; + } +} + +int UIScrollBox::findLine(int lineData) { + for (int i = 0; i < _lineCount; ++i) { + if (_lines[i]->lineData == lineData) { + return i; + } + } + return -1; +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/ui_scroll_box.h b/engines/bladerunner/ui/ui_scroll_box.h new file mode 100644 index 0000000000..1f416baffc --- /dev/null +++ b/engines/bladerunner/ui/ui_scroll_box.h @@ -0,0 +1,137 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_UI_SCROLLBOX_H +#define BLADERUNNER_UI_SCROLLBOX_H + +#include "bladerunner/ui/ui_component.h" + +#include "common/array.h" +#include "common/rect.h" +#include "common/str.h" + +namespace BladeRunner { + +typedef void UIScrollBoxCallback(void *callbackData, void *source, int lineData, int mouseButton); + +class UIScrollBox : public UIComponent +{ +private: + static const int kLineHeight = 10; + static const int k3DFrameColors[]; + static const int kTextBackgroundColors[]; + static const int kTextColors1[]; + static const int kTextColors2[]; + static const int kTextColors3[]; + static const int kTextColors4[]; + + struct Line { + Common::String text; + int lineData; + int flags; + int checkboxFrame; + }; + + int _selectedLineState; + int _scrollUpButtonState; + int _scrollDownButtonState; + int _scrollAreaUpState; + int _scrollAreaDownState; + int _scrollBarState; + + int _hoveredLine; + int _selectedLineIndex; + + bool _scrollUpButtonHover; + bool _scrollDownButtonHover; + bool _scrollAreaUpHover; + bool _scrollAreaDownHover; + bool _scrollBarHover; + + bool _mouseButton; + + UIScrollBoxCallback *_lineSelectedCallback; + void *_callbackData; + + bool _isVisible; + int _style; + bool _center; + + int _timeLastScroll; + int _timeLastCheckbox; + int _timeLastHighlight; + + int _highlightFrame; + + Common::Rect _rect; + Common::Rect _scrollBarRect; + + int _lineCount; + int _maxLineCount; + Common::Array<Line *> _lines; + int _maxLinesVisible; + int _firstLineVisible; + +public: + UIScrollBox(BladeRunnerEngine *vm, UIScrollBoxCallback *lineSelectedCallback, void *callbackData, int maxLineCount, int style, bool center, Common::Rect rect,Common::Rect scrollBarRect); + ~UIScrollBox(); + + void draw(Graphics::Surface &surface); + + void handleMouseMove(int mouseX, int mouseY); + void handleMouseDown(bool alternateButton); + void handleMouseUp(bool alternateButton); + + void show(); + void hide(); + + void clearLines(); + void addLine(const Common::String &text, int lineData, int flags); + void addLine(const char *text, int lineData, int flags); + void sortLines(); + + int getSelectedLineData(); + + void checkAll(); + void uncheckAll(); + void toggleCheckBox(int lineData); + + bool hasLine(int lineData); + + void resetHighlight(int lineData); + void setFlags(int lineData, int flags); + void resetFlags(int lineData, int flags); + +private: + static int sortFunction(const void *line1, const void *line2); + + void draw3DFrame(Graphics::Surface &surface, Common::Rect rect, bool pressed, int style); + + void scrollUp(); + void scrollDown(); + + int findLine(int lineData); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui/ui_slider.cpp b/engines/bladerunner/ui/ui_slider.cpp new file mode 100644 index 0000000000..d25b7fac2c --- /dev/null +++ b/engines/bladerunner/ui/ui_slider.cpp @@ -0,0 +1,153 @@ +/* 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/ui_slider.h" + +#include "bladerunner/audio_player.h" +#include "bladerunner/bladerunner.h" +#include "bladerunner/game_info.h" + +namespace BladeRunner { + +const uint16 UISlider::kColors[] = { 0x0000, 0x0821, 0x1061, 0x1C82, 0x24C2, 0x2CE3, 0x3524, 0x4145, 0x4586, 0x4DC7, 0x5609, 0x5E4B, 0x668C, 0x6EEE, 0x7730, 0x7B92 }; + +UISlider::UISlider(BladeRunnerEngine *vm, UIComponentCallback *valueChangedCallback, void *callbackData, Common::Rect rect, int maxValue, int value) + : UIComponent(vm) { + + _valueChangedCallback = valueChangedCallback; + _callbackData = callbackData; + + _maxValue = MAX(0, maxValue); + _value = CLIP(value, 0, _maxValue - 1); + + _rect = rect; + _isEnabled = true; + _currentFrameColor = 0; + _hasFocus = false; + _pressedStatus = 0; +} + +void UISlider::draw(Graphics::Surface &surface) { + if (_rect.isEmpty()) { + return; + } + + int frameColor; + if (_pressedStatus == 1) { + frameColor = 10; + } else if (_hasFocus && _pressedStatus != 2 && _isEnabled) { + frameColor = 5; + } else { + frameColor = 0; + } + + if (_currentFrameColor < frameColor) { + ++_currentFrameColor; + } + + if (_currentFrameColor > frameColor) { + --_currentFrameColor; + } + + surface.frameRect(_rect, kColors[_currentFrameColor]); + + int sliderX = 0; + if (_maxValue <= 1) { + sliderX = _rect.left; + } else { + sliderX = _rect.left + ((_value * _rect.width()) / (_maxValue - 1)); + } + + if (_pressedStatus == 1) { + int sliderValue = ((_maxValue - 1) * (_mouseX - _rect.left)) / _rect.width(); + sliderX = _rect.left + ((sliderValue * _rect.width()) / (_maxValue - 1)); + sliderX = CLIP(sliderX, (int)_rect.left, (int)_rect.right); + } + + if (_rect.left + 1 < _rect.right - 1) { + int striding = _rect.left + sliderX; + for (int x = _rect.left + 1; x < _rect.right - 1; x++) { + int colorIndex = 15 - (abs(sliderX - x) >> 2); + + if (!_isEnabled) { + colorIndex /= 2; + } + + if (colorIndex < 3) { + colorIndex = 3; + } + + uint16 color = kColors[colorIndex]; + if ((striding + x) & 1 || x == sliderX) { + color = 0; + } + + surface.vLine(x, _rect.top + 1, _rect.bottom - 2, color); + } + } +} + +void UISlider::handleMouseMove(int mouseX, int mouseY) { + _mouseX = mouseX; + if (_rect.contains(mouseX, mouseY)) { + if (!_hasFocus && _isEnabled && _pressedStatus == 0) { + _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(508), 100, 0, 0, 50, 0); + } + _hasFocus = true; + } else { + _hasFocus = false; + } +} + +void UISlider::handleMouseDown(bool alternateButton) { + if (_isEnabled && !alternateButton) { + if (_hasFocus) { + _pressedStatus = 1; + } else { + _pressedStatus = 2; + } + } +} + +void UISlider::handleMouseUp(bool alternateButton) { + if (!alternateButton) { + if (_pressedStatus == 1) { + if (_rect.width() == 0) { + _value = 0; + } else { + _value = ((_maxValue - 1) * (_mouseX - _rect.left)) / _rect.width(); + } + _value = CLIP(_value, 0, _maxValue - 1); + + if (_valueChangedCallback) { + _valueChangedCallback(_callbackData, this); + } + } + _pressedStatus = 0; + } +} + +void UISlider::setValue(int value) { + _value = CLIP(value, 0, _maxValue - 1); +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui/ui_slider.h b/engines/bladerunner/ui/ui_slider.h new file mode 100644 index 0000000000..7cbd5bfda7 --- /dev/null +++ b/engines/bladerunner/ui/ui_slider.h @@ -0,0 +1,63 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_UI_SLIDER_H +#define BLADERUNNER_UI_SLIDER_H + +#include "bladerunner/ui/ui_component.h" + +#include "common/rect.h" + +namespace BladeRunner { + +class UISlider : public UIComponent +{ +private: + static const uint16 kColors[]; + + UIComponentCallback *_valueChangedCallback; + void *_callbackData; + bool _isEnabled; + int _maxValue; + Common::Rect _rect; + int _currentFrameColor; + bool _hasFocus; + int _pressedStatus; + int _mouseX; + +public: + int _value; + + UISlider(BladeRunnerEngine *vm, UIComponentCallback *valueChangedCallback, void *callbackData, Common::Rect rect, int maxValue, int value); + + void draw(Graphics::Surface &surface); + + void handleMouseMove(int mouseX, int mouseY); + void handleMouseDown(bool alternateButton); + void handleMouseUp(bool alternateButton); + + void setValue(int value); +}; + +} // End of namespace BladeRunner + +#endif |