From a4c799238841e4e9ae63985b503a669449521cd6 Mon Sep 17 00:00:00 2001 From: Thomas Fach-Pedersen Date: Tue, 22 Aug 2017 18:57:50 +0200 Subject: BLADERUNNER: Add Dialogue Menu --- engines/bladerunner/dialogue_menu.cpp | 359 ++++++++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) create mode 100644 engines/bladerunner/dialogue_menu.cpp (limited to 'engines/bladerunner/dialogue_menu.cpp') diff --git a/engines/bladerunner/dialogue_menu.cpp b/engines/bladerunner/dialogue_menu.cpp new file mode 100644 index 0000000000..2ef137f9d4 --- /dev/null +++ b/engines/bladerunner/dialogue_menu.cpp @@ -0,0 +1,359 @@ +/* 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/dialogue_menu.h" + +#include "bladerunner/bladerunner.h" + +#include "bladerunner/font.h" +#include "bladerunner/mouse.h" +#include "bladerunner/shape.h" +#include "bladerunner/text_resource.h" + +#include "common/debug.h" +#include "common/util.h" + +#define LINE_HEIGHT 9 +#define BORDER_SIZE 10 + +namespace BladeRunner { + +DialogueMenu::DialogueMenu(BladeRunnerEngine *vm) + : _vm(vm) +{ + reset(); + _textResource = new TextResource(_vm); + _shapes.reserve(8); + for (int i = 0; i != 8; ++i) { + _shapes.push_back(Shape(_vm)); + bool r = _shapes[i].readFromContainer("DIALOG.SHP", i); + assert(r); + (void)r; + } +} + +DialogueMenu::~DialogueMenu() { + delete _textResource; +} + +bool DialogueMenu::loadText(const char *name) { + bool r = _textResource->open(name); + if (!r) { + error("Failed to load dialogue menu text"); + } + return r; +} + +bool DialogueMenu::show() { + int x, y; + + _vm->_mouse->getXY(&x, &y); + + return showAt(x, y); +} + +bool DialogueMenu::showAt(int x, int y) { + debug("DialogueMenu::showAt %d %d %d", _isVisible, x, y); + if (_isVisible) { + return false; + } + + _isVisible = true; + _selectedItemIndex = 0; + _centerX = x; + _centerY = y; + calculatePosition(x, y); + + return true; +} + +bool DialogueMenu::hide() { + _waitingForInput = 0; + if (!_isVisible) { + return false; + } + + _isVisible = false; + return true; +} + +bool DialogueMenu::clearList() { + _selectedItemIndex = -1; + _listSize = 0; + return true; +} + +bool DialogueMenu::addToList(int answer, int a3, int a4, int a5, int a6) { + if (_listSize >= 10) + return false; + if (getAnswerIndex(answer) != -1) + return false; + + const char *text = _textResource->getText(answer); + if (!text || strlen(text) >= 50) + return false; + + int index = _listSize++; + strcpy(_items[index].text, text); + _items[index].answerValue = answer; + _items[index].field_36 = 0; + _items[index].field_46 = a3; + _items[index].field_3A = a4; + _items[index].field_3E = a5; + _items[index].field_42 = a6; + + // CHECK(madmoose): BLADE.EXE calls this needlessly + // calculatePosition(); + + return true; +} + +bool DialogueMenu::addToListNeverRepeatOnceSelected(int answer, int a3, int a4, int a5) { + for (int i = 0; i != _neverRepeatListSize; ++i) { + if (answer == _neverRepeatValues[i] && _neverRepeatWasSelected[i]) { + return true; + } + } + + _neverRepeatValues[_neverRepeatListSize] = answer; + _neverRepeatWasSelected[_neverRepeatListSize] = false; + ++_neverRepeatListSize; + return addToList(answer, 0, a3, a4, a5); +} + +int DialogueMenu::queryInput() { + if (!_isVisible || _listSize == 0) + return -1; + + int answer = -1; + if (_listSize == 1) { + _selectedItemIndex = 0; + answer = _items[0].answerValue; + } else if (_listSize == 2) { + if (_items[0].field_46) { + _selectedItemIndex = 1; + answer = _items[0].answerValue; + } else if (_items[0].field_46) { + _selectedItemIndex = 0; + answer = _items[1].answerValue; + } + } + + if (answer == -1) { + int agenda = 4; //_vm->_settings.getPlayerAgenda(); + if (agenda == 4) { + _waitingForInput = true; + do { + // if (!_vm->_gameRunning) + // break; + + while (!_vm->playerHasControl()) { + _vm->playerGainsControl(); + } + + while (_vm->_mouse->isDisabled()) { + _vm->_mouse->enable(); + } + + _vm->gameTick(); + } while (_waitingForInput); + + } else if (agenda == 3) { + int tries = 0; + bool searching = true; + int i; + do { + i = _vm->_rnd.getRandomNumber(_listSize - 1); + if (!_items[i].field_46) { + searching = false; + } else if (++tries > 1000) { + searching = false; + i = 0; + } + } while (searching); + _selectedItemIndex = i; + } else { + error("unimplemented..."); + } + } + + answer = _items[_selectedItemIndex].answerValue; + for (int i = 0; i != _neverRepeatListSize; ++i) { + if (answer == _neverRepeatValues[i]) { + _neverRepeatWasSelected[i] = true; + break; + } + } + + if (_selectedItemIndex >= 0) { + debug("DM Query Input: %d %s", answer, _items[_selectedItemIndex].text); + } + + return answer; +} + +int DialogueMenu::listSize() { + return _listSize; +} + +bool DialogueMenu::isVisible() { + return _isVisible; +} + +bool DialogueMenu::isOpen() { + return _isVisible || _waitingForInput; +} + +void DialogueMenu::tick(int x, int y) { + if (!_isVisible || _listSize == 0) { + return; + } + + int line = (y - (_screenY + BORDER_SIZE)) / LINE_HEIGHT; + line = CLIP(line, 0, _listSize - 1); + + _selectedItemIndex = line; +} + +void DialogueMenu::draw() { + if (!_isVisible || _listSize == 0) + return; + + for (int i = 0; i != _listSize; ++i) { + if (i == _selectedItemIndex) { + _items[i].field_36 = 31; + } else { + _items[i].field_36 = 16; + } + + // TODO(madmoose): There's more logic here + } + + const int x1 = _screenX; + const int y1 = _screenY; + const int x2 = _screenX + BORDER_SIZE + _maxItemWidth; + const int y2 = _screenY + BORDER_SIZE + _listSize * LINE_HEIGHT; + + Graphics::Surface &s = _vm->_surfaceGame; + + darkenRect(s, x1 + 8, y1 + 8, x2 + 2, y2 + 2); + + _shapes[0].draw(s, x1, y1); + _shapes[3].draw(s, x2, y1); + _shapes[2].draw(s, x1, y2); + _shapes[5].draw(s, x2, y2); + + int x = x1 + BORDER_SIZE; + int y = y1 + BORDER_SIZE; + for (int i = 0; i != _listSize; ++i) { + _shapes[1].draw(s, x1, y); + _shapes[4].draw(s, x2, y); + uint16 color = ((_items[i].field_36 >> 1) << 10) | ((_items[i].field_36 >> 1) << 6) | _items[i].field_36; + _vm->_mainFont->drawColor(_items[i].text, s, x, y, color); + y += LINE_HEIGHT; + } + for (; x != x2; ++x) { + _shapes[6].draw(s, x, y1); + _shapes[7].draw(s, x, y2); + } +} + +int DialogueMenu::getAnswerIndex(int answer) { + for (int i = 0; i != _listSize; ++i) { + if (_items[i].answerValue == answer) { + return i; + } + } + + return -1; +} + +const char *DialogueMenu::getText(int id) { + return _textResource->getText((uint32)id); +} + +void DialogueMenu::calculatePosition(int unusedX, int unusedY) { + _maxItemWidth = 0; + for (int i = 0; i != _listSize; ++i) { + _maxItemWidth = MAX(_maxItemWidth, _vm->_mainFont->getTextWidth(_items[i].text)); + } + _maxItemWidth += 2; + + int w = BORDER_SIZE + _shapes[4].getWidth() + _maxItemWidth; + int h = BORDER_SIZE + _shapes[7].getHeight() + LINE_HEIGHT * _listSize; + + _screenX = _centerX - w / 2; + _screenY = _centerY - h / 2; + + _screenX = CLIP(_screenX, 0, 640 - w); + _screenY = CLIP(_screenY, 0, 480 - h); + + debug("calculatePosition: %d %d %d %d %d", _screenX, _screenY, _centerX, _centerY, _maxItemWidth); +} + +void DialogueMenu::mouseUp() { + _waitingForInput = false; +} + +bool DialogueMenu::waitingForInput() { + return _waitingForInput; +} + +void DialogueMenu::clear() { + _isVisible = false; + _waitingForInput = false; + _selectedItemIndex = 0; + _listSize = 0; + for (int i = 0; i != 10; ++i) { + _items[0].text[0] = '\0'; + _items[0].answerValue = -1; + _items[0].field_36 = 0; + _items[0].field_42 = -1; + _items[0].field_3A = -1; + _items[0].field_3E = -1; + _items[0].field_46 = 0; + } + _neverRepeatListSize = 0; + for (int i = 0; i != 100; ++i) { + _neverRepeatValues[i] = -1; + _neverRepeatWasSelected[i] = false; + } + _centerX = 0; + _centerY = 0; +} + +void DialogueMenu::reset() { + clear(); + _textResource = nullptr; +} + +void DialogueMenu::darkenRect(Graphics::Surface &s, int x1, int y1, int x2, int y2) { + for (int y = y1; y != y2; ++y) { + for (int x = x1; x != x2; ++x) { + // TODO(madmoose) + uint16 *p = (uint16*)s.getBasePtr(x, y); + *p = 0; + } + } +} + +} // End of namespace BladeRunner -- cgit v1.2.3