diff options
Diffstat (limited to 'engines/bladerunner/ui/vk.cpp')
-rw-r--r-- | engines/bladerunner/ui/vk.cpp | 917 |
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 |