aboutsummaryrefslogtreecommitdiff
path: root/engines/bladerunner/ui/vk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/bladerunner/ui/vk.cpp')
-rw-r--r--engines/bladerunner/ui/vk.cpp917
1 files changed, 917 insertions, 0 deletions
diff --git a/engines/bladerunner/ui/vk.cpp b/engines/bladerunner/ui/vk.cpp
new file mode 100644
index 0000000000..fab58e994f
--- /dev/null
+++ b/engines/bladerunner/ui/vk.cpp
@@ -0,0 +1,917 @@
+/* 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/vk.h"
+
+#include "bladerunner/actor.h"
+#include "bladerunner/ambient_sounds.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/music.h"
+#include "bladerunner/scene.h"
+#include "bladerunner/shape.h"
+#include "bladerunner/script/vk_script.h"
+#include "bladerunner/slice_renderer.h"
+#include "bladerunner/text_resource.h"
+#include "bladerunner/ui/ui_image_picker.h"
+#include "bladerunner/vqa_player.h"
+
+#include "common/str.h"
+#include "common/keyboard.h"
+
+namespace BladeRunner {
+
+VK::VK(BladeRunnerEngine *vm) {
+ _vm = vm;
+
+ reset();
+}
+
+VK::~VK() {
+ reset();
+}
+
+void VK::open(int actorId, int calibrationRatio) {
+ if (!_vm->openArchive("MODE.MIX")) {
+ return;
+ }
+
+ reset();
+
+ _questions.resize(3);
+ for (int i = 0; i < (int)_questions.size(); ++i) {
+ _questions[i].resize(18);
+ for (int j = 0; j < (int)_questions[i].size(); ++j) {
+ _questions[i][j].isPresent = false;
+ _questions[i][j].wasAsked = false;
+ }
+ }
+
+ _volumeAmbient = _vm->_ambientSounds->getVolume();
+ _volumeMusic = _vm->_music->getVolume();
+
+ _actorId = actorId;
+ _calibrationRatio = calibrationRatio;
+ _calibration = 0;
+
+ _buttons = new UIImagePicker(_vm, 8);
+
+ _shapes.resize(15);
+ for (int i = 0; i < (int)_shapes.size(); ++i) {
+ _shapes[i] = new Shape(_vm);
+ _shapes[i]->open("VK.SHP", i);
+ }
+
+ _vqaPlayerMain = new VQAPlayer(_vm, &_vm->_surfaceBack);
+ if (!_vqaPlayerMain->open("VK.VQA")) {
+ return;
+ }
+
+ Common::String eyeVqa;
+ switch (actorId) {
+ case kActorDektora:
+ eyeVqa = "VKDEKT.VQA";
+ break;
+ case kActorLucy:
+ eyeVqa = "VKLUCY.VQA";
+ break;
+ case kActorGrigorian:
+ eyeVqa = "VKKASH.VQA";
+ break;
+ case kActorBulletBob:
+ eyeVqa = "VKBOB.VQA";
+ break;
+ case kActorRunciter:
+ eyeVqa = "VKRUNC.VQA";
+ break;
+ default:
+ return;
+ }
+
+ _surfaceEye.create(172, 116, createRGB555());
+ _vqaPlayerEye = new VQAPlayer(_vm, &_surfaceEye);
+ if (!_vqaPlayerEye->open(eyeVqa)) {
+ return;
+ }
+ if (!_vqaPlayerEye->setLoop(0, -1, kLoopSetModeEnqueue, nullptr, nullptr)) {
+ return;
+ }
+
+ _isOpen = true;
+
+ _script = new VKScript(_vm);
+
+ //TODO: time->lock()
+
+ init();
+}
+
+bool VK::isOpen() const {
+ return _isOpen;
+}
+
+void VK::close() {
+ if (_vm->_audioPlayer->isActive(_soundTrackId1)) {
+ _vm->_audioPlayer->stop(_soundTrackId1, false);
+ }
+
+ if (_vm->_audioPlayer->isActive(_soundTrackId3)) {
+ _vm->_audioPlayer->stop(_soundTrackId3, false);
+ }
+
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(458), 33, 0, 0, 50, 0);
+
+ _script->shutdown(_actorId, _humanProbability, _replicantProbability, _anxiety);
+
+ delete _script;
+ _script = nullptr;
+
+
+ if (_buttons) {
+ _buttons->deactivate();
+ _buttons->resetImages();
+ delete _buttons;
+ _buttons = nullptr;
+ }
+
+ if (_vqaPlayerEye) {
+ _vqaPlayerEye->close();
+ delete _vqaPlayerEye;
+ _vqaPlayerEye = nullptr;
+ }
+
+ if (_vqaPlayerMain) {
+ _vqaPlayerMain->close();
+ delete _vqaPlayerMain;
+ _vqaPlayerMain = nullptr;
+ }
+
+ _questions.clear();
+
+ for (int i = 0; i < (int)_shapes.size(); ++i) {
+ delete _shapes[i];
+ }
+ _shapes.clear();
+
+ _vm->closeArchive("MODE.MIX");
+ _vm->_music->setVolume(_volumeMusic);
+ _vm->_ambientSounds->setVolume(_volumeAmbient);
+
+ // TODO: time->unlock();
+ // _vm->_scene->resume(false);
+}
+
+void VK::tick() {
+ int mouseX, mouseY;
+ _vm->_mouse->getXY(&mouseX, &mouseY);
+ if (!_vm->_mouse->isDisabled()) {
+ _buttons->handleMouseAction(mouseX, mouseY, false, false, false);
+ }
+
+ draw();
+
+ _vm->blitToScreen(_vm->_surfaceFront);
+ _vm->_system->delayMillis(10);
+
+ if (_isClosing && (int)_vm->getTotalPlayTime() >= _timeClose && !_script->isInsideScript()) {
+ close();
+ _vm->_mouse->enable();
+ reset();
+ }
+}
+
+void VK::handleMouseDown(int mouseX, int mouseY, bool mainButton) {
+ if (!_vm->_mouse->isDisabled()) {
+ if (!_buttons->handleMouseAction(mouseX, mouseY, true, false, false)) {
+ tick();
+ }
+ }
+}
+
+void VK::handleMouseUp(int mouseX, int mouseY, bool mainButton) {
+ if (!_vm->_mouse->isDisabled()) {
+ _buttons->handleMouseAction(mouseX, mouseY, false, true, false);
+ }
+}
+
+void VK::addQuestion(int intensity, int sentenceId, int relatedSentenceId) {
+ for (int i = 0; i < (int)_questions[intensity].size(); ++i) {
+ if (!_questions[intensity][i].isPresent) {
+ _questions[intensity][i].isPresent = true;
+ _questions[intensity][i].sentenceId = sentenceId;
+ _questions[intensity][i].relatedSentenceId = relatedSentenceId;
+ return;
+ }
+ }
+}
+
+void VK::playSpeechLine(int actorId, int sentenceId, float duration) {
+ _vm->gameWaitForActive();
+
+ _vm->_mouse->disable();
+
+ Actor *actor = _vm->_actors[actorId];
+ actor->speechPlay(sentenceId, true);
+
+ while (_vm->_gameIsRunning) {
+ // ActorSpeaking = 1;
+ _vm->_speechSkipped = false;
+ _vm->gameTick();
+ // ActorSpeaking = 0;
+ if (_vm->_speechSkipped || !actor->isSpeeching()) {
+ actor->speechStop();
+ break;
+ }
+ }
+
+ if (duration > 0.0f && !_vm->_speechSkipped) {
+ int timeEnd = duration * 1000.0f + _vm->getTotalPlayTime();
+ while (timeEnd > (int)_vm->getTotalPlayTime() && _vm->_gameIsRunning) {
+ _vm->gameTick();
+ }
+ }
+
+ _vm->_speechSkipped = false;
+
+ _vm->_mouse->enable();
+}
+
+void VK::subjectReacts(int intensity, int humanResponse, int replicantResponse, int anxiety) {
+ humanResponse = CLIP(humanResponse, -20, 20);
+ replicantResponse = CLIP(replicantResponse, -20, 20);
+
+ int timeNow = _vm->getTotalPlayTime();
+
+ if (intensity > 0) {
+ _needleValueTarget = 78 * intensity / 100;
+ _needleValueDelta = (_needleValueTarget - _needleValue) / 10;
+ _timeNextNeedleStep = timeNow + 66;
+ }
+
+ if (humanResponse != 0) {
+ _humanProbability = CLIP(_humanProbability + humanResponse + _calibration, 0, 100);
+ if (_humanProbability >= 80 && !_isClosing) {
+ _isClosing = true;
+ _timeClose = timeNow + 3000;
+ _vm->_mouse->disable();
+ }
+ _humanGaugeTarget = humanResponse;
+ _humanGaugeDelta = humanResponse / 10;
+ if (_humanGaugeDelta == 0) {
+ _humanGaugeDelta = humanResponse / abs(humanResponse);
+ }
+ }
+
+ if (replicantResponse != 0) {
+ _replicantProbability = CLIP(_replicantProbability + replicantResponse - _calibration, 0, 100);
+ if (_replicantProbability >= 80 && !_isClosing) {
+ _isClosing = true;
+ _timeClose = timeNow + 3000;
+ _vm->_mouse->disable();
+ }
+ _replicantGaugeTarget = replicantResponse;
+ _replicantGauge = replicantResponse / 10;
+ if (_replicantGaugeDelta == 0) {
+ _replicantGaugeDelta = replicantResponse / abs(replicantResponse);
+ }
+ }
+
+ _anxiety = CLIP(_anxiety + anxiety, 0, 100);
+ if (_anxiety == 100 && !_isClosing) {
+ _isClosing = true;
+ _timeClose = timeNow + 3000;
+ _vm->_mouse->disable();
+ }
+}
+
+void VK::eyeAnimates(int loopId) {
+ _vqaPlayerEye->setLoop(loopId, -1, kLoopSetModeImmediate, nullptr, nullptr);
+ _vqaPlayerEye->setLoop(0, -1, kLoopSetModeEnqueue, nullptr, nullptr);
+}
+
+void VK::mouseDownCallback(int buttonId, void *callbackData) {
+ VK *self = (VK *)callbackData;
+
+ switch (buttonId) {
+ case 1:
+ self->startAdjustement();
+ break;
+ case 2:
+ case 3:
+ case 4:
+ if (self->_calibrationStarted) {
+ self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(457), 100, 0, 0, 50, 0);
+ }
+ break;
+ case 5:
+ self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(457), 100, 0, 0, 50, 0);
+ break;
+ default:
+ return;
+ }
+}
+
+void VK::mouseUpCallback(int buttonId, void *callbackData) {
+ VK *self = (VK *)callbackData;
+
+ switch (buttonId) {
+ case 0:
+ self->calibrate();
+ break;
+ case 1:
+ self->stopAdjustement();
+ break;
+ case 2:
+ self->askQuestion(0);
+ break;
+ case 3:
+ self->askQuestion(1);
+ break;
+ case 4:
+ self->askQuestion(2);
+ break;
+ case 5:
+ self->_isClosing = true;
+ break;
+ default:
+ return;
+ }
+}
+
+void VK::loopEnded(void *callbackData, int frame, int loopId) {
+ VK *self = (VK *)callbackData;
+
+ self->_vqaLoopEnded = true;
+ self->_vqaPlayerMain->setLoop(2, -1, kLoopSetModeJustStart, nullptr, nullptr);
+}
+
+void VK::reset() {
+ _buttons = nullptr;
+ _vqaPlayerMain = nullptr;
+ _vqaPlayerEye = nullptr;
+
+ _script = nullptr;
+
+ _isOpen = false;
+
+ _shapes.clear();
+
+ _calibrationCounter = 0;
+ _calibrationStarted = false;
+ _calibration = 0;
+
+ _testStarted = false;
+
+ _needleValue = 0;
+ _needleValueTarget = 0;
+ _needleValueDelta = 0;
+ _timeNextNeedleStep = 0;
+ _timeNeedleReturn = 0;
+ _timeNextNeedleOscillate = 0;
+
+ _humanProbability = 0;
+ _humanGauge = 0;
+ _humanGaugeTarget = 0;
+ _humanGaugeDelta = 0;
+ _timeNextHumanGaugeStep = 0;
+
+ _replicantProbability = 0;
+ _replicantGauge = 0;
+ _replicantGaugeTarget = 0;
+ _replicantGaugeDelta = 0;
+ _timeNextReplicantGaugeStep = 0;
+
+ _anxiety = 0;
+
+ _blinkState = 0;
+ _timeNextBlink = 0;
+ _timeNextGaugesBlink = 0;
+
+ _isClosing = false;
+ _timeClose = 0;
+
+ _isAdjusting = false;
+ _adjustment = 154;
+ _adjustmentTarget = 154;
+ _adjustmentDelta = 0;
+
+ _eyeLineSelected = 1;
+ _eyeLineX = 315;
+ _eyeLineXLast = 315;
+ _eyeLineY = 281;
+ _eyeLineYLast = 281;
+ _eyeLineXDelta = 8;
+ _eyeLineYDelta = 8;
+ _timeNextEyeLineStep = 0;
+ _timeNextEyeLineStart = 0;
+
+ _soundTrackId1 = -1;
+ _soundTrackId2 = -1;
+ _soundTrackId3 = -1;
+ _vqaLoopEnded = false;
+
+ _surfaceEye.free();
+}
+
+void VK::init() {
+ _vm->_mouse->disable();
+
+ _buttons->activate(nullptr, nullptr, mouseDownCallback, mouseUpCallback, this);
+ _buttons->defineImage(0, Common::Rect(191, 364, 218, 373), nullptr, _shapes[2], _shapes[3], _vm->_textVK->getText(1));
+ _buttons->defineImage(1, Common::Rect(154, 258, 161, 265), _shapes[4], _shapes[4], _shapes[5], _vm->_textVK->getText(2));
+ _buttons->defineImage(2, Common::Rect(515, 368, 538, 398), nullptr, _shapes[6], _shapes[7], nullptr);
+ _buttons->defineImage(3, Common::Rect(548, 368, 571, 398), nullptr, _shapes[8], _shapes[9], nullptr);
+ _buttons->defineImage(4, Common::Rect(581, 368, 604, 398), nullptr, _shapes[10], _shapes[11], nullptr);
+ _buttons->defineImage(5, Common::Rect( 31, 363, 65, 392), nullptr, _shapes[0], _shapes[1], _vm->_textVK->getText(0));
+ _buttons->defineImage(6, Common::Rect( 59, 262, 87, 277), nullptr, nullptr, nullptr, _vm->_textVK->getText(6));
+ _buttons->defineImage(7, Common::Rect( 59, 306, 87, 322), nullptr, nullptr, nullptr, _vm->_textVK->getText(7));
+
+ _script->initialize(_actorId);
+
+ _vqaPlayerMain->setLoop(0, -1, kLoopSetModeJustStart, nullptr, nullptr);
+ tick();
+ _vqaPlayerMain->setLoop(1, -1, kLoopSetModeEnqueue, loopEnded, this);
+}
+
+void VK::draw() {
+ if (!_isOpen || !_vm->_gameIsRunning) {
+ return;
+ }
+
+ int frame = _vqaPlayerMain->update();
+ if (frame >= 0) {
+ _vqaFrameMain = frame;
+ }
+
+ if (frame == 0) {
+ _soundTrackId2 = _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(426), 33, 0, 0, 50, 0);
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(431), 50, 0, 0, 50, 0);
+ } else if (frame == 26) {
+ _vm->_audioPlayer->stop(_soundTrackId2, false);
+ _soundTrackId1 = _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(429), 50, 30, 30, 50, kAudioPlayerLoop);
+ } else if (frame == 40) {
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(428), 33, 0, 0, 50, 0);
+ eyeAnimates(1);
+ } else if (frame == 59) {
+ _vm->_mouse->enable();
+ _buttons->setImageShapeHovered(2, nullptr);
+ _buttons->setImageShapeDown(2, nullptr);
+ _buttons->setImageShapeHovered(3, nullptr);
+ _buttons->setImageShapeDown(3, nullptr);
+ _buttons->setImageShapeHovered(4, nullptr);
+ _buttons->setImageShapeDown(4, nullptr);
+ } else if (frame == 100) {
+ if (_vm->_rnd.getRandomNumberRng(0, 100) > 60) {
+ eyeAnimates(1);
+ }
+ } else if (frame == 140) {
+ if (_vm->_rnd.getRandomNumberRng(0, 10) > 6) {
+ _soundTrackId3 = _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(459), 83, 0, 0, 50, 0);
+ }
+ }
+
+ blit(_vm->_surfaceBack, _vm->_surfaceFront);
+
+ Graphics::Surface &surface = _vm->_surfaceFront;
+
+ int timeNow = _vm->getTotalPlayTime();
+
+ if (_isAdjusting && !_testStarted && !_vm->isMouseButtonDown()) {
+ _isAdjusting = false;
+ }
+
+ if (_vqaFrameMain >= 26) {
+ if (_isClosing && timeNow >= _timeNextGaugesBlink) {
+ if (_blinkState) {
+ _buttons->setImageShapeUp(6, nullptr);
+ _buttons->setImageShapeUp(7, nullptr);
+ _blinkState = 0;
+ } else {
+ if (_humanProbability >= 80) {
+ _buttons->setImageShapeUp(6, _shapes[13]);
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(0), 100, 0, 0, 50, 0);
+ }
+ if (_replicantProbability >= 80) {
+ _buttons->setImageShapeUp(7, _shapes[14]);
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(0), 100, 0, 0, 50, 0);
+ }
+ _blinkState = 1;
+ }
+ _timeNextGaugesBlink = timeNow + 600;
+ }
+
+ _buttons->draw(surface);
+
+ if (_humanGaugeDelta != 0 && timeNow >= _timeNextHumanGaugeStep) {
+ _humanGauge += _humanGaugeDelta;
+
+ if ((_humanGaugeDelta > 0 && _humanGauge >= _humanGaugeTarget)
+ || (_humanGaugeDelta < 0 && _humanGauge <= _humanGaugeTarget)) {
+ _humanGauge = _humanGaugeTarget;
+ }
+
+ if (_humanGauge == _humanGaugeTarget) {
+ if (_humanGaugeTarget != 0) {
+ _humanGaugeTarget = 0;
+ _humanGaugeDelta = -_humanGaugeDelta;
+ _timeNextHumanGaugeStep = timeNow + 500;
+ } else {
+ _humanGaugeDelta = 0;
+ }
+ } else {
+ _timeNextHumanGaugeStep = timeNow + 66;
+ }
+ }
+ drawHumanGauge(surface);
+
+ if (_replicantGaugeDelta != 0 && timeNow >= _timeNextReplicantGaugeStep) {
+ _replicantGauge += _replicantGaugeDelta;
+
+ if ((_replicantGaugeDelta > 0 && _replicantGauge >= _replicantGaugeTarget)
+ || (_replicantGaugeDelta < 0 && _replicantGauge <= _replicantGaugeTarget)) {
+ _replicantGauge = _replicantGaugeTarget;
+ }
+
+ if (_replicantGauge == _replicantGaugeTarget) {
+ if (_replicantGaugeTarget != 0) {
+ _replicantGaugeTarget = 0;
+ _replicantGaugeDelta = -_replicantGaugeDelta;
+ _timeNextReplicantGaugeStep = timeNow + 500;
+ } else {
+ _replicantGaugeDelta = 0;
+ }
+ } else {
+ _timeNextReplicantGaugeStep = timeNow + 66;
+ }
+ }
+ drawReplicantGauge(surface);
+
+ if (!_calibrationStarted && _vqaFrameMain >= 59 && timeNow >= _timeNextBlink) {
+ if (_blinkState) {
+ _buttons->setImageShapeUp(0, nullptr);
+ _blinkState = false;
+ } else {
+ _buttons->setImageShapeUp(0, _shapes[2]);
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(461), 50, 0, 0, 50, 0);
+ _blinkState = true;
+ }
+ _timeNextBlink = timeNow + 600;
+ }
+
+ if (_adjustmentDelta != 0 && timeNow >= _timeNextAdjustementStep) {
+ if (_adjustmentDelta > 0) {
+ _adjustment += 3;
+ if (_adjustment >= _adjustmentTarget) {
+ _adjustment = _adjustmentTarget;
+ _adjustmentDelta = 0;
+ }
+ } else {
+ _adjustment -= 3;
+ if (_adjustment <= _adjustmentTarget) {
+ _adjustment = _adjustmentTarget;
+ _adjustmentDelta = 0;
+ }
+ }
+ setAdjustment(_adjustment + 4);
+ }
+ setAdjustmentFromMouse();
+
+ if (_calibrationStarted && !_testStarted && timeNow >= _timeNextBlink) {
+ if (_blinkState) {
+ _buttons->setImageShapeUp(2, nullptr);
+ _buttons->setImageShapeUp(3, nullptr);
+ _buttons->setImageShapeUp(4, nullptr);
+ _blinkState = 0;
+ } else {
+ _buttons->setImageShapeUp(2, _shapes[7]);
+ _buttons->setImageShapeUp(3, _shapes[9]);
+ _buttons->setImageShapeUp(4, _shapes[11]);
+ _blinkState = 1;
+
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(462), 33, 0, 0, 50, 0);
+ }
+ _timeNextBlink = timeNow + 600;
+ }
+
+ if (_needleValueDelta != 0 && timeNow >= _timeNextNeedleStep) {
+ if (_needleValueDelta > 0) {
+ _needleValue += 4;
+ if (_needleValue >= _needleValueTarget) {
+ _needleValue = _needleValueTarget;
+ _needleValueMax = _needleValueTarget;
+ _needleValueDelta = -_needleValueDelta;
+ _needleValueTarget = 0;
+
+ _timeNeedleReturn = timeNow + 1800;
+
+ if (!_testStarted) {
+ animateAdjustment(_needleValueMax + 165);
+ }
+ }
+ } else if (timeNow >= _timeNeedleReturn) {
+ _needleValue -= 4;
+ if (_needleValue <= _needleValueTarget) {
+ _needleValue = _needleValueTarget;
+ _needleValueDelta = 0;
+ }
+ }
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(455), 20, 0, 0, 50, 0);
+ _timeNextNeedleStep = timeNow + 66;
+ }
+
+ drawNeedle(surface);
+ drawEye(surface);
+ drawEyeCrosshair(surface, timeNow);
+ if (timeNow >= _timeNextNeedleOscillate) {
+ _timeNextNeedleOscillate = timeNow + 66;
+ }
+ int mouseX, mouseY;
+ _vm->_mouse->getXY(&mouseX, &mouseY);
+ _buttons->drawTooltip(surface, mouseX, mouseY);
+ }
+
+ drawMouse(surface);
+}
+
+void VK::drawNeedle(Graphics::Surface &surface) {
+ int x = _needleValue + 165;
+ if ((int)_vm->getTotalPlayTime() >= _timeNextNeedleOscillate && x > 165) {
+ x = CLIP(x + (int)_vm->_rnd.getRandomNumberRng(0, 4) - 2, 165, 245);
+ }
+
+ float needleOffset = abs(38.0f - _needleValue);
+ float y = 345 - sqrt(72.0f * 72.0f - needleOffset * needleOffset);
+
+ float colorIntensity = MIN(78.0f, _needleValue + 39.0f) / 78.0f;
+
+ int r = 6 * colorIntensity;
+ int g = 8 * colorIntensity;
+ int b = 12 * colorIntensity;
+
+ surface.drawLine(203, 324, x - 2, y, ((7 - r ) << 10) | ((18 - g ) << 5) | (23 - b ));
+ surface.drawLine(203, 324, x + 2, y, ((7 - r ) << 10) | ((18 - g ) << 5) | (23 - b ));
+ surface.drawLine(203, 324, x - 1, y, ((7 - r / 2) << 10) | ((18 - g / 2) << 5) | (23 - b / 2));
+ surface.drawLine(203, 324, x + 1, y, ((7 - r / 2) << 10) | ((18 - g / 2) << 5) | (23 - b / 2));
+ surface.drawLine(203, 324, x, y - 1, ((7 - r / 2) << 10) | ((18 - g / 2) << 5) | (23 - b / 2));
+ surface.drawLine(203, 324, x, y, 0x1E57);
+}
+
+void VK::drawEye(Graphics::Surface &surface) {
+ _vqaPlayerEye->update(true);
+ surface.copyRectToSurface(_surfaceEye, 315, 281, Common::Rect(0, 0, _surfaceEye.w, _surfaceEye.h));
+}
+
+void VK::drawEyeCrosshair(Graphics::Surface &surface, int timeNow) {
+ surface.drawLine(315, _eyeLineY, 486, _eyeLineY, 0x848u);
+ surface.drawLine(315, _eyeLineY - 1, 486, _eyeLineY - 1, 0x848u);
+ surface.drawLine(315, _eyeLineY, _vm->_rnd.getRandomNumberRng(10, 20) + 315, _eyeLineY, 0x84Au);
+ surface.drawLine(486 - _vm->_rnd.getRandomNumberRng(10, 20), _eyeLineY, 486, _eyeLineY, 0x84Au);
+ surface.drawLine(486 - _vm->_rnd.getRandomNumberRng(10, 20), _eyeLineY - 1, 486, _eyeLineY - 1, 0x846u);
+ surface.drawLine(315, _eyeLineY - 1, _vm->_rnd.getRandomNumberRng(10, 20) + 315, _eyeLineY - 1, 0x846u);
+
+ surface.drawLine(_eyeLineX, 281, _eyeLineX, 396, 0x848u);
+ surface.drawLine(_eyeLineX - 1, 281, _eyeLineX - 1, 396, 0x848u);
+ surface.drawLine(_eyeLineX, 281, _eyeLineX, _vm->_rnd.getRandomNumberRng(10, 20) + 281, 0x846u);
+ surface.drawLine(_eyeLineX, 396 - _vm->_rnd.getRandomNumberRng(10, 20), _eyeLineX, 396, 0x846u);
+ surface.drawLine(_eyeLineX - 1, 396 - _vm->_rnd.getRandomNumberRng(10, 20), _eyeLineX - 1, 396, 0x84Au);
+ surface.drawLine(_eyeLineX - 1, 281, _eyeLineX - 1, _vm->_rnd.getRandomNumberRng(10, 20) + 281, 0x84Au);
+
+ if (timeNow >= _timeNextEyeLineStart) {
+ if (_eyeLineSelected) {
+ if (_eyeLineYLast != _eyeLineY) {
+ surface.drawLine(315, _eyeLineYLast, 486, _eyeLineYLast, 0x844u);
+ }
+ _eyeLineYLast = _eyeLineY;
+ if (timeNow >= _timeNextEyeLineStep) {
+ _eyeLineY += _eyeLineYDelta;
+ if (_eyeLineYDelta > 0) {
+ if (_eyeLineY >= 396) {
+ _eyeLineY = 396;
+ _eyeLineYDelta = -_eyeLineYDelta;
+ }
+ } else if (_eyeLineY <= 281) {
+ _eyeLineY = 281;
+ _eyeLineYDelta = -_eyeLineYDelta;
+ _eyeLineSelected = 0;
+ _timeNextEyeLineStart = timeNow + 1000;
+ }
+ _timeNextEyeLineStep = timeNow + 50;
+ }
+ } else {
+ if (_eyeLineXLast != _eyeLineX) {
+ surface.drawLine(_eyeLineXLast, 281, _eyeLineXLast, 396, 0x844u);
+ }
+ _eyeLineXLast = _eyeLineX;
+ if (timeNow >= _timeNextEyeLineStep) {
+ _eyeLineX += _eyeLineXDelta;
+ if ( _eyeLineXDelta > 0) {
+ if (_eyeLineX >= 486) {
+ _eyeLineX = 486;
+ _eyeLineXDelta = -_eyeLineXDelta;
+ }
+ } else if (_eyeLineX <= 315) {
+ _eyeLineX = 315;
+ _eyeLineXDelta = -_eyeLineXDelta;
+ _eyeLineSelected = 1;
+ _timeNextEyeLineStart = timeNow + 1000;
+ }
+ _timeNextEyeLineStep = timeNow + 50;
+ }
+ }
+ }
+}
+
+void VK::drawMouse(Graphics::Surface &surface) {
+ if (_vm->_mouse->isDisabled()) {
+ return;
+ }
+
+ Common::Point p = _vm->getMousePos();
+
+ if (_buttons->hasHoveredImage()) {
+ _vm->_mouse->setCursor(1);
+ } else {
+ _vm->_mouse->setCursor(0);
+ }
+
+ _vm->_mouse->draw(surface, p.x, p.y);
+}
+
+void VK::drawGauge(Graphics::Surface &surface, int value, int x, int y, int width) {
+ _shapes[12]->draw(surface, x + (width / 2) * value / 20 , y);
+}
+
+void VK::drawHumanGauge(Graphics::Surface &surface) {
+ drawGauge(surface, _humanGauge, 72, 271, 87);
+}
+
+void VK::drawReplicantGauge(Graphics::Surface &surface) {
+ drawGauge(surface, _replicantGauge, 72, 293, 87);
+}
+
+void VK::calibrate() {
+ if (_calibrationCounter >= 3 || _testStarted) {
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(460), 100, 0, 0, 50, 0);
+ } else {
+ _vm->_mouse->disable();
+ _script->calibrate(_actorId);
+ _vm->_mouse->enable();
+ ++_calibrationCounter;
+ if (_calibrationCounter == 3) {
+ _buttons->setImageShapeHovered(0, nullptr);
+ _buttons->setImageShapeDown(0, nullptr);
+ _buttons->setImageTooltip(0, nullptr);
+ }
+ }
+ _calibrationStarted = true;
+ _buttons->setImageShapeUp(0, nullptr);
+
+ _buttons->setImageShapeHovered(2, _shapes[6]);
+ _buttons->setImageShapeDown(2, _shapes[7]);
+ _buttons->setImageTooltip(2, _vm->_textVK->getText(3));
+
+ _buttons->setImageShapeHovered(3, _shapes[8]);
+ _buttons->setImageShapeDown(3, _shapes[9]);
+ _buttons->setImageTooltip(3, _vm->_textVK->getText(4));
+
+ _buttons->setImageShapeHovered(4, _shapes[10]);
+ _buttons->setImageShapeDown(4, _shapes[11]);
+ _buttons->setImageTooltip(4, _vm->_textVK->getText(5));
+}
+
+void VK::beginTest() {
+ if (_calibrationStarted && !_testStarted) {
+ _vm->_mouse->disable();
+ _calibration = ((100.0f / (100.0f - 4.0f) * (_adjustment - 154.0f)) - _calibrationRatio) / 5.0f;
+ _script->beginTest(_actorId);
+ _testStarted = true;
+ _buttons->setImageShapeHovered(0, nullptr);
+ _buttons->setImageShapeDown(0, nullptr);
+ _buttons->setImageTooltip(0, nullptr);
+ _buttons->setImageShapeDown(1, _shapes[4]);
+ _buttons->setImageTooltip(1, nullptr);
+ _buttons->setImageShapeUp(2, nullptr);
+ _buttons->setImageShapeUp(3, nullptr);
+ _buttons->setImageShapeUp(4, nullptr);
+ _vm->_mouse->enable();
+ } else {
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(460), 100, 0, 0, 50, 0);
+ }
+}
+
+void VK::startAdjustement() {
+ if (_testStarted) {
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(460), 100, 0, 0, 50, 0);
+ } else {
+ _isAdjusting = true;
+ }
+}
+
+void VK::stopAdjustement() {
+ if (_testStarted) {
+ _isAdjusting = false;
+ }
+}
+
+void VK::animateAdjustment(int target) {
+ _adjustmentTarget = MAX(target - 4, 154);
+ _adjustmentDelta = (_adjustmentTarget - _adjustment) / 5;
+ _timeNextAdjustementStep = _vm->getTotalPlayTime() + 50;
+}
+
+void VK::setAdjustment(int x) {
+ _adjustment = CLIP(x - 4, 154, 246);
+ float offset = abs(199.0f - _adjustment);
+ int y = sqrt(88.0f * 88.0f - offset * offset);
+ _buttons->setImageLeft(1, _adjustment);
+ _buttons->setImageTop(1, 345 - y);
+}
+
+void VK::setAdjustmentFromMouse() {
+ if (_isAdjusting && !_testStarted) {
+ int mouseX, mouseY;
+ _vm->_mouse->getXY(&mouseX, &mouseY);
+ setAdjustment(mouseX);
+ if (_adjustmentTarget != _adjustment) {
+ _vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(456), 100, 0, 0, 50, 0);
+ }
+ _adjustmentTarget = _adjustment;
+ _adjustmentDelta = 0;
+ }
+}
+
+void VK::askQuestion(int intensity) {
+ assert(intensity < (int)_questions.size());
+
+ if (!_testStarted) {
+ beginTest();
+ }
+
+ if (!_testStarted) {
+ return;
+ }
+
+ int foundQuestionIndex = -1;
+ int foundQuestionIndexLast = -1;
+
+ for (int i = 0; i < (int)_questions[intensity].size(); ++i) {
+ if (_questions[intensity][i].isPresent && !_questions[intensity][i].wasAsked) {
+ int relatedQuestion = -1;
+ if (_questions[intensity][i].relatedSentenceId >= 0) {
+ // TODO: but not used in game
+ // relatedQuestion = vk::findQuestionById(this, questions, relatedQuestionId);
+ }
+
+ if (relatedQuestion < 0 || _questions[intensity][relatedQuestion].wasAsked) {
+ foundQuestionIndexLast = i;
+ if (_vm->_rnd.getRandomNumberRng(0, 100) < 20) {
+ foundQuestionIndex = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (foundQuestionIndex < 0) {
+ foundQuestionIndex = foundQuestionIndexLast;
+ }
+
+ if (foundQuestionIndex >= 0) {
+ _vm->_mouse->disable();
+ _questions[intensity][foundQuestionIndex].wasAsked = true;
+ _script->mcCoyAsksQuestion(_actorId, _questions[intensity][foundQuestionIndex].sentenceId);
+ _script->questionAsked(_actorId, _questions[intensity][foundQuestionIndex].sentenceId);
+ _vm->_mouse->enable();
+ } else if (!_isClosing && !_script->isInsideScript()) {
+ _isClosing = true;
+ _vm->_mouse->disable();
+ _timeClose = _vm->getTotalPlayTime() + 3000;
+ }
+}
+
+} // End of namespace BladeRunner