diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp index 3622130b45d9..a3ac82df0ece 100644 --- a/engines/bladerunner/bladerunner.cpp +++ b/engines/bladerunner/bladerunner.cpp @@ -31,6 +31,7 @@ #include "bladerunner/combat.h" #include "bladerunner/crimes_database.h" #include "bladerunner/dialogue_menu.h" +#include "bladerunner/elevator.h" #include "bladerunner/font.h" #include "bladerunner/gameflags.h" #include "bladerunner/gameinfo.h" @@ -292,7 +293,7 @@ bool BladeRunnerEngine::startup(bool hasSavegames) { // TODO: Spinner Interface _spinner = new Spinner(this); - // TODO: Elevators + _elevator = new Elevator(this); // TODO: Scores @@ -598,7 +599,13 @@ void BladeRunnerEngine::gameTick() { // TODO: Esper // TODO: VK - // TODO: Elevators + + if (_elevator->isOpen()) { + _elevator->tick(); + _ambientSounds->tick(); + return; + } + // TODO: Scores _adq->tick(); @@ -845,6 +852,15 @@ void BladeRunnerEngine::handleMouseAction(int x, int y, bool buttonLeft, bool bu return; } + if (_elevator->isOpen()) { + if (buttonDown) { + _elevator->handleMouseDown(x, y); + } else { + _elevator->handleMouseUp(x, y); + } + return; + } + if (_dialogueMenu->waitingForInput()) { if (buttonLeft && !buttonDown) { _dialogueMenu->mouseUp(); diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h index 405952595a48..d58f9a560115 100644 --- a/engines/bladerunner/bladerunner.h +++ b/engines/bladerunner/bladerunner.h @@ -55,6 +55,7 @@ class Chapters; class CrimesDatabase; class Combat; class DialogueMenu; +class Elevator; class Font; class GameFlags; class GameInfo; @@ -94,6 +95,7 @@ class BladeRunnerEngine : public Engine { CrimesDatabase *_crimesDatabase; Combat *_combat; DialogueMenu *_dialogueMenu; + Elevator *_elevator; GameFlags *_gameFlags; GameInfo *_gameInfo; ItemPickup *_itemPickup; diff --git a/engines/bladerunner/elevator.cpp b/engines/bladerunner/elevator.cpp new file mode 100644 index 000000000000..b1268f770b2c --- /dev/null +++ b/engines/bladerunner/elevator.cpp @@ -0,0 +1,317 @@ +/* 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/elevator.h" + +#include "bladerunner/bladerunner.h" + +#include "bladerunner/actor.h" +#include "bladerunner/audio_player.h" +#include "bladerunner/gameinfo.h" +#include "bladerunner/mouse.h" +#include "bladerunner/shape.h" +#include "bladerunner/ui_image_picker.h" +#include "bladerunner/vqa_player.h" + +#include "common/rect.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->_surfaceInterface); + if (!_vqaPlayer->open(vqaName)) { + return 0; + } + + _vqaPlayer->setLoop(1, -1, 0, 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, + 220, 298, 308, 392, + nullptr, + _shapes[11], + _shapes[14], + nullptr); + _imagePicker->defineImage( + 1, + 259, 259, 302, 292, + nullptr, + _shapes[10], + _shapes[13], + nullptr); + _imagePicker->defineImage( + 2, + 227, 398, 301, 434, + nullptr, + _shapes[12], + _shapes[15], + nullptr); + } else { + _imagePicker->defineImage( + 4, + 395, 131, 448, 164, + nullptr, + _shapes[0], + _shapes[5], + nullptr + ); + _imagePicker->defineImage( + 3, + 395, 165, 448, 198, + nullptr, + _shapes[1], + _shapes[6], + nullptr + ); + _imagePicker->defineImage( + 5, + 395, 199, 448, 232, + nullptr, + _shapes[2], + _shapes[7], + nullptr + ); + _imagePicker->defineImage( + 6, + 395, 233, 448, 264, + nullptr, + _shapes[3], + _shapes[8], + nullptr + ); + _imagePicker->defineImage( + 7, + 395, 265, 448, 295, + nullptr, + _shapes[4], + _shapes[9], + nullptr + ); + } + + _imagePicker->setCallbacks( + elevator_mouseInCallback, + elevator_mouseOutCallback, + elevator_mouseDownCallback, + elevator_mouseUpCallback, + this + ); + + open(); + + // TODO: time->lock(); + + _buttonClicked = -1; + do { + _vm->gameTick(); + } while (_buttonClicked == -1); + + _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, 0); + return false; +} + +int Elevator::handleMouseDown(int x, int y) { + _imagePicker->handleMouseAction(x, y, true, false, 0); + return false; +} + +void Elevator::tick() { + if (!_vm->_gameIsRunning) + return; + + int frame = _vqaPlayer->update(); + assert(frame >= -1); + + // vqaPlayer renders to _surfaceInterface + blit(_vm->_surfaceInterface, _vm->_surfaceGame); + + 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->_surfaceGame); + _vm->_mouse->draw(_vm->_surfaceGame, p.x, p.y); + + _vm->blitToScreen(_vm->_surfaceGame); + tickDescription(); + _vm->_system->delayMillis(10); +} + +void Elevator::buttonClick(int buttonId) { + _buttonClicked = buttonId; +} + +void Elevator::reset() { + _isOpen = false; + _vqaPlayer = 0; + _imagePicker = 0; + _actorId = -1; + _sentenceId = -1; + _timeSpeakDescription = 0; +} + +void Elevator::buttonFocus(int buttonId) { + switch (buttonId) { + case 7: + setupDescription(39, 140); + break; + case 6: + setupDescription(39, 130); + break; + case 5: + setupDescription(39, 120); + break; + case 4: + setupDescription(39, 100); + break; + case 3: + setupDescription(39, 110); + break; + case 2: + setupDescription(39, 130); + break; + case 1: + setupDescription(39, 100); + break; + case 0: + setupDescription(39, 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/elevator.h b/engines/bladerunner/elevator.h new file mode 100644 index 000000000000..0a5940a3b3bd --- /dev/null +++ b/engines/bladerunner/elevator.h @@ -0,0 +1,72 @@ +/* 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 _shapes; + UIImagePicker *_imagePicker; + int _actorId; + int _sentenceId; + int _timeSpeakDescription; + + friend void elevator_mouseInCallback(int, void*); + friend void elevator_mouseOutCallback(int, void*); + friend void elevator_mouseDownCallback(int, void*); + friend void elevator_mouseUpCallback(int, void*); + +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(); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk index 3e496ff3b56b..5c995984ded7 100644 --- a/engines/bladerunner/module.mk +++ b/engines/bladerunner/module.mk @@ -21,6 +21,7 @@ MODULE_OBJS = \ decompress_lzo.o \ detection.o \ dialogue_menu.o \ + elevator.o \ fog.o \ font.o \ gameflags.o \ diff --git a/engines/bladerunner/script/scene/ps05.cpp b/engines/bladerunner/script/scene/ps05.cpp index 59e8bbcbbb0d..656550e86402 100644 --- a/engines/bladerunner/script/scene/ps05.cpp +++ b/engines/bladerunner/script/scene/ps05.cpp @@ -91,16 +91,6 @@ bool SceneScriptPS05::ClickedOnActor(int actorId) { } bool SceneScriptPS05::ClickedOnItem(int itemId, bool a2) { - if (Game_Flag_Query(23)) { - Actor_Set_At_XYZ(kActorMcCoy, 718.72f, 0.37f, -461.26f, 600); - } else if (Game_Flag_Query(22)) { - sub_401B34(); - sub_401C30(); - } - Game_Flag_Reset(22); - Game_Flag_Reset(23); - Game_Flag_Reset(21); - Game_Flag_Reset(204); return false; } @@ -152,6 +142,16 @@ void SceneScriptPS05::ActorChangedGoal(int actorId, int newGoal, int oldGoal, bo } void SceneScriptPS05::PlayerWalkedIn() { + if (Game_Flag_Query(23)) { + Actor_Set_At_XYZ(kActorMcCoy, 718.72f, 0.37f, -461.26f, 600); + } else if (Game_Flag_Query(22)) { + sub_401B34(); + sub_401C30(); + } + Game_Flag_Reset(22); + Game_Flag_Reset(23); + Game_Flag_Reset(21); + Game_Flag_Reset(204); } void SceneScriptPS05::PlayerWalkedOut() { diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp index 32528c9728a2..c4352706f501 100644 --- a/engines/bladerunner/script/script.cpp +++ b/engines/bladerunner/script/script.cpp @@ -33,6 +33,7 @@ #include "bladerunner/crimes_database.h" #include "bladerunner/combat.h" #include "bladerunner/dialogue_menu.h" +#include "bladerunner/elevator.h" #include "bladerunner/gameflags.h" #include "bladerunner/gameinfo.h" #include "bladerunner/items.h" @@ -1087,10 +1088,8 @@ bool ScriptBase::Voight_Kampff_Activate(int a1, int a2){ return false; } -int ScriptBase::Elevator_Activate(int elevator) { - //TODO - warning("Elevator_Activate(%d)", elevator); - return 0; +int ScriptBase::Elevator_Activate(int elevatorId) { + return _vm->_elevator->activate(elevatorId); } void ScriptBase::View_Score_Board() { diff --git a/engines/bladerunner/script/script.h b/engines/bladerunner/script/script.h index 93c955dedd57..61cee3aa9bd1 100644 --- a/engines/bladerunner/script/script.h +++ b/engines/bladerunner/script/script.h @@ -630,7 +630,7 @@ class ScriptBase { int Spinner_Interface_Choose_Dest(int a1, int a2); void ESPER_Flag_To_Activate(); bool Voight_Kampff_Activate(int a1, int a2); - int Elevator_Activate(int elevator); + int Elevator_Activate(int elevatorId); void View_Score_Board(); // Query_Score void Set_Score(int a0, int a1); diff --git a/engines/bladerunner/spinner.cpp b/engines/bladerunner/spinner.cpp index bc447e17e284..40650cbc221f 100644 --- a/engines/bladerunner/spinner.cpp +++ b/engines/bladerunner/spinner.cpp @@ -249,7 +249,7 @@ void Spinner::tick() { // vqaPlayer renders to _surfaceInterface blit(_vm->_surfaceInterface, _vm->_surfaceGame); - _imagePicker->draw(_vm->_surfaceInterface); + _imagePicker->draw(_vm->_surfaceGame); Common::Point p = _vm->getMousePos(); _imagePicker->handleMouseAction(p.x, p.y, false, false, false); diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp index 129bb77b0e90..f6eecc85ed65 100644 --- a/engines/bladerunner/vqa_player.cpp +++ b/engines/bladerunner/vqa_player.cpp @@ -57,6 +57,7 @@ bool VQAPlayer::open(const Common::String &name) { if (_loopInitial >= 0) { setLoop(_loopInitial, _repeatsCountInitial, kLoopSetModeImmediate, nullptr, nullptr); } else { + _frameNext = 0; setBeginAndEndFrame(0, _frameEnd, 0, kLoopSetModeJustStart, nullptr, nullptr); }