aboutsummaryrefslogtreecommitdiff
path: root/engines/saga/interface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/saga/interface.cpp')
-rw-r--r--engines/saga/interface.cpp2453
1 files changed, 2453 insertions, 0 deletions
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
new file mode 100644
index 0000000000..1d3b110068
--- /dev/null
+++ b/engines/saga/interface.cpp
@@ -0,0 +1,2453 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004-2006 The ScummVM project
+ *
+ * The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Game interface module
+#include "saga/saga.h"
+
+#include "saga/gfx.h"
+#include "saga/actor.h"
+#include "saga/console.h"
+#include "saga/events.h"
+#include "saga/font.h"
+#include "saga/objectmap.h"
+#include "saga/isomap.h"
+#include "saga/itedata.h"
+#include "saga/music.h"
+#include "saga/puzzle.h"
+#include "saga/render.h"
+#include "saga/scene.h"
+#include "saga/script.h"
+#include "saga/sound.h"
+#include "saga/sprite.h"
+#include "saga/rscfile.h"
+#include "saga/resnames.h"
+
+#include "saga/interface.h"
+
+#include "common/config-manager.h"
+#include "common/system.h"
+#include "common/timer.h"
+
+namespace Saga {
+
+static int verbTypeToTextStringsIdLUT[2][kVerbTypeIdsMax] = {
+ {-1,
+ kTextPickUp,
+ kTextLookAt,
+ kTextWalkTo,
+ kTextTalkTo,
+ kTextOpen,
+ kTextClose,
+ kTextGive,
+ kTextUse,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1},
+ {-1,
+ 3, //TODO:check
+ 2,
+ 1,
+ 5,
+ 6, //TODO:check
+ 8, //TODO:check
+ 7,
+ 4}
+};
+
+Interface::Interface(SagaEngine *vm) : _vm(vm) {
+ byte *resource;
+ size_t resourceLength;
+ int i;
+
+ // Load interface module resource file context
+ _interfaceContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
+ if (_interfaceContext == NULL) {
+ error("Interface::Interface() resource context not found");
+ }
+
+ _mainPanel.buttons = _vm->getDisplayInfo().mainPanelButtons;
+ _mainPanel.buttonsCount = _vm->getDisplayInfo().mainPanelButtonsCount;
+
+ for (i = 0; i < kVerbTypeIdsMax; i++) {
+ _verbTypeToPanelButton[i] = NULL;
+ }
+
+ for (i = 0; i < _mainPanel.buttonsCount; i++) {
+ if (_mainPanel.buttons[i].type == kPanelButtonVerb) {
+ _verbTypeToPanelButton[_mainPanel.buttons[i].id] = &_mainPanel.buttons[i];
+ }
+ }
+
+ _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->mainPanelResourceId, resource, resourceLength);
+ _vm->decodeBGImage(resource, resourceLength, &_mainPanel.image,
+ &_mainPanel.imageLength, &_mainPanel.imageWidth, &_mainPanel.imageHeight);
+
+ free(resource);
+
+ _conversePanel.buttons = _vm->getDisplayInfo().conversePanelButtons;
+ _conversePanel.buttonsCount = _vm->getDisplayInfo().conversePanelButtonsCount;
+
+ _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->conversePanelResourceId, resource, resourceLength);
+ _vm->decodeBGImage(resource, resourceLength, &_conversePanel.image,
+ &_conversePanel.imageLength, &_conversePanel.imageWidth, &_conversePanel.imageHeight);
+ free(resource);
+
+ _optionPanel.buttons = _vm->getDisplayInfo().optionPanelButtons;
+ _optionPanel.buttonsCount = _vm->getDisplayInfo().optionPanelButtonsCount;
+
+ _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->optionPanelResourceId, resource, resourceLength);
+ _vm->decodeBGImage(resource, resourceLength, &_optionPanel.image,
+ &_optionPanel.imageLength, &_optionPanel.imageWidth, &_optionPanel.imageHeight);
+ free(resource);
+
+ _vm->_sprite->loadList(_vm->getResourceDescription()->mainPanelSpritesResourceId, _mainPanel.sprites);
+
+ if (_vm->getGameType() == GType_ITE) {
+ _vm->_sprite->loadList(_vm->getResourceDescription()->defaultPortraitsResourceId, _defPortraits);
+ }
+
+ setPortraitBgColor(0, 0, 0);
+
+ _mainPanel.x = _vm->getDisplayInfo().mainPanelXOffset;
+ _mainPanel.y = _vm->getDisplayInfo().mainPanelYOffset;
+ _mainPanel.currentButton = NULL;
+ _inventoryUpButton = _mainPanel.getButton(_vm->getDisplayInfo().inventoryUpButtonIndex);
+ _inventoryDownButton = _mainPanel.getButton(_vm->getDisplayInfo().inventoryDownButtonIndex);
+
+ _conversePanel.x = _vm->getDisplayInfo().conversePanelXOffset;
+ _conversePanel.y = _vm->getDisplayInfo().conversePanelYOffset;
+ _conversePanel.currentButton = NULL;
+ _converseUpButton = _conversePanel.getButton(_vm->getDisplayInfo().converseUpButtonIndex);
+ _converseDownButton = _conversePanel.getButton(_vm->getDisplayInfo().converseDownButtonIndex);
+
+ _leftPortrait = 0;
+ _rightPortrait = 0;
+
+ _optionPanel.x = _vm->getDisplayInfo().optionPanelXOffset;
+ _optionPanel.y = _vm->getDisplayInfo().optionPanelYOffset;
+ _optionPanel.currentButton = NULL;
+ _optionSaveFileSlider = _optionPanel.getButton(_vm->getDisplayInfo().optionSaveFileSliderIndex);
+ _optionSaveFilePanel = _optionPanel.getButton(_vm->getDisplayInfo().optionSaveFilePanelIndex);
+
+ _quitPanel.x = _vm->getDisplayInfo().quitPanelXOffset;
+ _quitPanel.y = _vm->getDisplayInfo().quitPanelYOffset;
+ _quitPanel.imageWidth = _vm->getDisplayInfo().quitPanelWidth;
+ _quitPanel.imageHeight = _vm->getDisplayInfo().quitPanelHeight;
+ _quitPanel.buttons = _vm->getDisplayInfo().quitPanelButtons;
+ _quitPanel.buttonsCount = _vm->getDisplayInfo().quitPanelButtonsCount;
+ _quitPanel.currentButton = NULL;
+
+ _loadPanel.x = _vm->getDisplayInfo().loadPanelXOffset;
+ _loadPanel.y = _vm->getDisplayInfo().loadPanelYOffset;
+ _loadPanel.imageWidth = _vm->getDisplayInfo().loadPanelWidth;
+ _loadPanel.imageHeight = _vm->getDisplayInfo().loadPanelHeight;
+ _loadPanel.buttons = _vm->getDisplayInfo().loadPanelButtons;
+ _loadPanel.buttonsCount = _vm->getDisplayInfo().loadPanelButtonsCount;
+ _loadPanel.currentButton = NULL;
+
+ _savePanel.x = _vm->getDisplayInfo().savePanelXOffset;
+ _savePanel.y = _vm->getDisplayInfo().savePanelYOffset;
+ _savePanel.imageWidth = _vm->getDisplayInfo().savePanelWidth;
+ _savePanel.imageHeight = _vm->getDisplayInfo().savePanelHeight;
+ _savePanel.buttons = _vm->getDisplayInfo().savePanelButtons;
+ _savePanel.buttonsCount = _vm->getDisplayInfo().savePanelButtonsCount;
+ _saveEdit = _savePanel.getButton(_vm->getDisplayInfo().saveEditIndex);
+ _savePanel.currentButton = NULL;
+
+ _protectPanel.x = _vm->getDisplayInfo().protectPanelXOffset;
+ _protectPanel.y = _vm->getDisplayInfo().protectPanelYOffset;
+ _protectPanel.imageWidth = _vm->getDisplayInfo().protectPanelWidth;
+ _protectPanel.imageHeight = _vm->getDisplayInfo().protectPanelHeight;
+ _protectPanel.buttons = _vm->getDisplayInfo().protectPanelButtons;
+ _protectPanel.buttonsCount = _vm->getDisplayInfo().protectPanelButtonsCount;
+ _protectEdit = _protectPanel.getButton(_vm->getDisplayInfo().protectEditIndex);
+ _protectPanel.currentButton = NULL;
+
+ _active = true;
+ _panelMode = _lockedMode = kPanelNull;
+ _savedMode = -1;
+ _bossMode = -1;
+ _fadeMode = kNoFade;
+ _inMainMode = false;
+ *_statusText = 0;
+ _statusOnceColor = -1;
+
+ _inventoryCount = 0;
+ _inventoryPos = 0;
+ _inventoryStart = 0;
+ _inventoryEnd = 0;
+ _inventoryBox = 0;
+ _inventorySize = ITE_INVENTORY_SIZE;
+ _saveReminderState = 0;
+
+ _optionSaveFileTop = 0;
+ _optionSaveFileTitleNumber = 0;
+
+ _inventory = (uint16 *)calloc(_inventorySize, sizeof(uint16));
+ if (_inventory == NULL) {
+ error("Interface::Interface(): not enough memory");
+ }
+
+ _textInputRepeatPhase = 0;
+ _textInput = false;
+ _statusTextInput = false;
+ _statusTextInputState = kStatusTextInputFirstRun;
+
+ _disableAbortSpeeches = false;
+}
+
+Interface::~Interface(void) {
+ free(_inventory);
+
+ _mainPanel.sprites.freeMem();
+ _defPortraits.freeMem();
+ _scenePortraits.freeMem();
+}
+
+int Interface::activate() {
+ if (!_active) {
+ _active = true;
+ _vm->_script->_skipSpeeches = false;
+ _vm->_actor->_protagonist->_targetObject = ID_NOTHING;
+ unlockMode();
+ if (_panelMode == kPanelMain){
+ _saveReminderState = 1;
+ }
+ draw();
+ }
+ _vm->_gfx->showCursor(true);
+
+ return SUCCESS;
+}
+
+int Interface::deactivate() {
+ if (_active) {
+ _active = false;
+ lockMode();
+ setMode(kPanelNull);
+ }
+ _vm->_gfx->showCursor(false);
+
+ return SUCCESS;
+}
+
+void Interface::rememberMode() {
+ assert (_savedMode == -1);
+
+ _savedMode = _panelMode;
+}
+
+void Interface::restoreMode() {
+ assert (_savedMode != -1);
+
+ _panelMode = _savedMode;
+ _savedMode = -1;
+
+ draw();
+}
+
+void Interface::setMode(int mode) {
+ debug(1, "Interface::setMode %i", mode);
+
+ if (mode == kPanelMain) {
+ _inMainMode = true;
+ _saveReminderState = 1; //TODO: blinking timeout
+ } else {
+ if (mode == kPanelConverse) {
+ _inMainMode = false;
+ }
+ _saveReminderState = 0;
+ }
+
+ _panelMode = mode;
+
+ switch (_panelMode) {
+ case kPanelMain:
+ if (_vm->getGameType() == GType_IHNM)
+ warning("FIXME: Implement IHNM differences from ExecuteInventoryPanel");
+
+ _mainPanel.currentButton = NULL;
+ break;
+ case kPanelConverse:
+ _conversePanel.currentButton = NULL;
+ converseDisplayText();
+ break;
+ case kPanelOption:
+ _optionPanel.currentButton = NULL;
+ _vm->fillSaveList();
+ calcOptionSaveSlider();
+ if (_optionSaveFileTitleNumber >= _vm->getDisplayInfo().optionSaveFileVisible) {
+ _optionSaveFileTitleNumber = _vm->getDisplayInfo().optionSaveFileVisible - 1;
+ }
+ break;
+ case kPanelLoad:
+ _loadPanel.currentButton = NULL;
+ break;
+ case kPanelQuit:
+ _quitPanel.currentButton = NULL;
+ break;
+ case kPanelSave:
+ _savePanel.currentButton = NULL;
+ _textInputMaxWidth = _saveEdit->width - 10;
+ _textInput = true;
+ _textInputStringLength = strlen(_textInputString);
+ _textInputPos = _textInputStringLength + 1;
+ _textInputRepeatPhase = 0;
+ break;
+ case kPanelMap:
+ mapPanelShow();
+ break;
+ case kPanelSceneSubstitute:
+ _vm->_render->setFlag(RF_DEMO_SUBST);
+ _vm->_gfx->getCurrentPal(_mapSavedPal);
+ break;
+ case kPanelChapterSelection:
+ break;
+ case kPanelBoss:
+ _vm->_render->setFlag(RF_DEMO_SUBST);
+ break;
+ case kPanelProtect:
+ _protectPanel.currentButton = NULL;
+ _textInputMaxWidth = _protectEdit->width - 10;
+ _textInput = true;
+ _textInputString[0] = 0;
+ _textInputStringLength = 0;
+ _textInputPos = _textInputStringLength + 1;
+ _textInputRepeatPhase = 0;
+ break;
+ }
+
+ draw();
+}
+
+bool Interface::processAscii(uint16 ascii, bool synthetic) {
+ // TODO: Checking for Esc and Enter below is a bit hackish, and
+ // and probably only works with the English version. Maybe we should
+ // add a flag to the button so it can indicate if it's the default or
+ // cancel button?
+
+ int i;
+ PanelButton *panelButton;
+ if (!synthetic)
+ _textInputRepeatPhase = 0;
+ if (_statusTextInput) {
+ processStatusTextInput(ascii);
+ return true;
+ }
+
+ switch (_panelMode) {
+ case kPanelNull:
+ if (ascii == 27) { // Esc
+ if (_vm->_scene->isInIntro()) {
+ _vm->_scene->skipScene();
+ } else {
+ if (!_disableAbortSpeeches)
+ _vm->_actor->abortAllSpeeches();
+ }
+ return true;
+ }
+ break;
+ case kPanelCutaway:
+ if (ascii == 27) { // Esc
+ if (!_disableAbortSpeeches)
+ _vm->_actor->abortAllSpeeches();
+ _vm->_scene->cutawaySkip();
+ return true;
+ }
+ break;
+ case kPanelVideo:
+ if (ascii == 27) { // Esc
+ if (_vm->_scene->isInIntro()) {
+ _vm->_scene->skipScene();
+ } else {
+ if (!_disableAbortSpeeches)
+ _vm->_actor->abortAllSpeeches();
+ }
+ _vm->_scene->cutawaySkip();
+ }
+ break;
+ case kPanelOption:
+ // TODO: check input dialog keys
+ if (ascii == 27 || ascii == 13) { // Esc or Enter
+ ascii = 'c'; //continue
+ }
+
+ for (i = 0; i < _optionPanel.buttonsCount; i++) {
+ panelButton = &_optionPanel.buttons[i];
+ if (panelButton->type == kPanelButtonOption) {
+ if (panelButton->ascii == ascii) {
+ setOption(panelButton);
+ return true;
+ }
+ }
+ }
+ break;
+ case kPanelSave:
+ if (_textInput && processTextInput(ascii)) {
+ return true;
+ }
+
+ if (ascii == 27) { // Esc
+ ascii = 'c'; // cancel
+ } else if (ascii == 13) { // Enter
+ ascii = 's'; // save
+ }
+
+ for (i = 0; i < _savePanel.buttonsCount; i++) {
+ panelButton = &_savePanel.buttons[i];
+ if (panelButton->type == kPanelButtonSave) {
+ if (panelButton->ascii == ascii) {
+ setSave(panelButton);
+ return true;
+ }
+ }
+ }
+ break;
+ case kPanelQuit:
+ if (ascii == 27) { // Esc
+ ascii = 'c'; // cancel
+ } else if (ascii == 13) { // Enter
+ ascii = 'q'; // quit
+ }
+
+ for (i = 0; i < _quitPanel.buttonsCount; i++) {
+ panelButton = &_quitPanel.buttons[i];
+ if (panelButton->type == kPanelButtonQuit) {
+ if (panelButton->ascii == ascii) {
+ setQuit(panelButton);
+ return true;
+ }
+ }
+ }
+ break;
+ case kPanelLoad:
+ for (i = 0; i < _loadPanel.buttonsCount; i++) {
+ panelButton = &_loadPanel.buttons[i];
+ if (panelButton->type == kPanelButtonLoad) {
+ if (panelButton->ascii == ascii) {
+ setLoad(panelButton);
+ return true;
+ }
+ }
+ }
+ break;
+ case kPanelMain:
+ for (i = 0; i < _mainPanel.buttonsCount; i++) {
+ panelButton = &_mainPanel.buttons[i];
+ if (panelButton->ascii == ascii) {
+ if (panelButton->type == kPanelButtonVerb) {
+ _vm->_script->setVerb(panelButton->id);
+ }
+ if (panelButton->type == kPanelButtonArrow) {
+ inventoryChangePos(panelButton->id);
+ }
+ return true;
+ }
+ }
+ if (ascii == 15) // ctrl-o
+ {
+ if (_saveReminderState > 0) {
+ setMode(kPanelOption);
+ return true;
+ }
+ }
+ break;
+ case kPanelConverse:
+ switch (ascii) {
+ case 'x':
+ setMode(kPanelMain);
+ if (_vm->_puzzle->isActive())
+ _vm->_puzzle->exitPuzzle();
+ break;
+
+ case 'u':
+ converseChangePos(-1);
+ break;
+
+ case 'd':
+ converseChangePos(1);
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ converseSetPos(ascii);
+ break;
+ }
+ break;
+ case kPanelMap:
+ mapPanelClean();
+ break;
+ case kPanelSceneSubstitute:
+ if (ascii == 13) {
+ _vm->_render->clearFlag(RF_DEMO_SUBST);
+ _vm->_gfx->setPalette(_mapSavedPal);
+ setMode(kPanelMain);
+ _vm->_script->setNoPendingVerb();
+ } else if (ascii == 'q' || ascii == 'Q') {
+ _vm->shutDown();
+ }
+ break;
+ case kPanelBoss:
+ _vm->_render->clearFlag(RF_DEMO_SUBST);
+ keyBossExit();
+ break;
+ case kPanelProtect:
+ if (_textInput && processTextInput(ascii)) {
+ return true;
+ }
+
+ if (ascii == 27 || ascii == 13) { // Esc or Enter
+ _vm->_script->wakeUpThreads(kWaitTypeRequest);
+ _vm->_interface->setMode(kPanelMain);
+
+ _protectHash = 0;
+
+ for (char *p = _textInputString; *p; p++)
+ _protectHash = (_protectHash << 1) + toupper(*p);
+ }
+ break;
+ }
+ return false;
+}
+
+#define KEYBOARD_REPEAT_DELAY1 300000L
+#define KEYBOARD_REPEAT_DELAY2 50000L
+
+void Interface::textInputRepeatCallback(void *refCon) {
+ ((Interface *)refCon)->textInputRepeat();
+}
+
+void Interface::textInputStartRepeat(uint16 ascii) {
+ if (!_textInputRepeatPhase) {
+ _textInputRepeatPhase = 1;
+ Common::g_timer->removeTimerProc(&textInputRepeatCallback);
+ Common::g_timer->installTimerProc(&textInputRepeatCallback, KEYBOARD_REPEAT_DELAY1, this);
+ }
+
+ _textInputRepeatChar = ascii;
+}
+
+void Interface::textInputRepeat() {
+ if (_textInputRepeatPhase == 1) {
+ _textInputRepeatPhase = 2;
+ Common::g_timer->removeTimerProc(&textInputRepeatCallback);
+ Common::g_timer->installTimerProc(&textInputRepeatCallback, KEYBOARD_REPEAT_DELAY2, this);
+ } else if (_textInputRepeatPhase == 2) {
+ processAscii(_textInputRepeatChar, true);
+ }
+}
+
+void Interface::processKeyUp(uint16 ascii) {
+ if (_textInputRepeatPhase) {
+ Common::g_timer->removeTimerProc(&textInputRepeatCallback);
+ _textInputRepeatPhase = 0;
+ }
+}
+
+void Interface::setStatusText(const char *text, int statusColor) {
+ assert(text != NULL);
+ assert(strlen(text) < STATUS_TEXT_LEN);
+
+ if (_vm->_render->getFlags() & (RF_PLACARD | RF_MAP))
+ return;
+
+ strncpy(_statusText, text, STATUS_TEXT_LEN);
+ _statusOnceColor = statusColor;
+ drawStatusBar();
+}
+
+void Interface::loadScenePortraits(int resourceId) {
+ _scenePortraits.freeMem();
+
+ _vm->_sprite->loadList(resourceId, _scenePortraits);
+}
+
+void Interface::drawVerbPanel(Surface *backBuffer, PanelButton* panelButton) {
+ PanelButton * rightButtonVerbPanelButton;
+ PanelButton * currentVerbPanelButton;
+ KnownColor textColor;
+ int spriteNumber;
+ Point point;
+
+ rightButtonVerbPanelButton = getPanelButtonByVerbType(_vm->_script->getRightButtonVerb());
+ currentVerbPanelButton = getPanelButtonByVerbType(_vm->_script->getCurrentVerb());
+
+ if (panelButton->state) {
+ textColor = kKnownColorVerbTextActive;
+ } else if (panelButton == rightButtonVerbPanelButton) {
+ textColor = kKnownColorVerbTextActive;
+ } else {
+ textColor = kKnownColorVerbText;
+ }
+
+ if (panelButton == currentVerbPanelButton) {
+ spriteNumber = panelButton->downSpriteNumber;
+ } else {
+ spriteNumber = panelButton->upSpriteNumber;
+ }
+ point.x = _mainPanel.x + panelButton->xOffset;
+ point.y = _mainPanel.y + panelButton->yOffset;
+
+ _vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _mainPanel.sprites, spriteNumber, point, 256);
+
+ drawVerbPanelText(backBuffer, panelButton, textColor, kKnownColorVerbTextShadow);
+}
+
+void Interface::draw() {
+ Surface *backBuffer;
+ int i;
+
+ Point leftPortraitPoint;
+ Point rightPortraitPoint;
+ Rect rect;
+
+ backBuffer = _vm->_gfx->getBackBuffer();
+
+ if (_vm->_scene->isInIntro() || _fadeMode == kFadeOut)
+ return;
+
+ drawStatusBar();
+
+ if (_panelMode == kPanelMain || _panelMode == kPanelMap) {
+ _mainPanel.getRect(rect);
+ backBuffer->blit(rect, _mainPanel.image);
+
+ for (i = 0; i < kVerbTypeIdsMax; i++) {
+ if (_verbTypeToPanelButton[i] != NULL) {
+ drawVerbPanel(backBuffer, _verbTypeToPanelButton[i]);
+ }
+ }
+ } else if (_panelMode == kPanelConverse) {
+ _conversePanel.getRect(rect);
+ backBuffer->blit(rect, _conversePanel.image);
+ converseDisplayTextLines(backBuffer);
+ }
+
+ if (_vm->getGameType() == GType_IHNM) {
+ if (_vm->_spiritualBarometer > 255)
+ _vm->_gfx->setPaletteColor(kIHNMColorPortrait, 0xff, 0xff, 0xff);
+ else
+ _vm->_gfx->setPaletteColor(kIHNMColorPortrait,
+ _vm->_spiritualBarometer * _portraitBgColor.red / 256,
+ _vm->_spiritualBarometer * _portraitBgColor.green / 256,
+ _vm->_spiritualBarometer * _portraitBgColor.blue / 256);
+ }
+
+ if (_panelMode == kPanelMain || _panelMode == kPanelConverse ||
+ _lockedMode == kPanelMain || _lockedMode == kPanelConverse) {
+ leftPortraitPoint.x = _mainPanel.x + _vm->getDisplayInfo().leftPortraitXOffset;
+ leftPortraitPoint.y = _mainPanel.y + _vm->getDisplayInfo().leftPortraitYOffset;
+ _vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _defPortraits, _leftPortrait, leftPortraitPoint, 256);
+ }
+
+ if (!_inMainMode && _vm->getDisplayInfo().rightPortraitXOffset >= 0) { //FIXME: should we change !_inMainMode to _panelMode == kPanelConverse ?
+ rightPortraitPoint.x = _mainPanel.x + _vm->getDisplayInfo().rightPortraitXOffset;
+ rightPortraitPoint.y = _mainPanel.y + _vm->getDisplayInfo().rightPortraitYOffset;
+
+ // This looks like hack - particularly since it's only done for
+ // the right-side portrait - and perhaps it is! But as far as I
+ // can tell this is what the original engine does. And it keeps
+ // ITE from crashing when entering the Elk King's court.
+
+ if (_rightPortrait >= _scenePortraits.spriteCount)
+ _rightPortrait = 0;
+
+ _vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _scenePortraits, _rightPortrait, rightPortraitPoint, 256);
+ }
+
+ drawInventory(backBuffer);
+}
+
+void Interface::calcOptionSaveSlider() {
+ int totalFiles = _vm->getSaveFilesCount();
+ int visibleFiles = _vm->getDisplayInfo().optionSaveFileVisible;
+ if (_optionSaveFileSlider == NULL) return; //TODO:REMOVE
+ int height = _optionSaveFileSlider->height;
+ int sliderHeight;
+ int pos;
+
+ if (totalFiles < visibleFiles) {
+ totalFiles = visibleFiles;
+ }
+
+ sliderHeight = visibleFiles * height / totalFiles;
+ if (sliderHeight < 7) {
+ sliderHeight = 7;
+ }
+
+ if (totalFiles - visibleFiles <= 0) {
+ pos = 0;
+ } else {
+ pos = _optionSaveFileTop * (height - sliderHeight) / (totalFiles - visibleFiles);
+ }
+ _optionPanel.calcPanelButtonRect(_optionSaveFileSlider, _optionSaveRectTop);
+ _optionSaveRectBottom = _optionSaveRectSlider = _optionSaveRectTop;
+
+ _optionSaveRectTop.bottom = _optionSaveRectTop.top + pos;
+ _optionSaveRectTop.top++;
+ _optionSaveRectTop.right--;
+
+ _optionSaveRectSlider.top = _optionSaveRectTop.bottom;
+ _optionSaveRectSlider.bottom = _optionSaveRectSlider.top + sliderHeight;
+
+ _optionSaveRectBottom.top = _optionSaveRectSlider.bottom;
+ _optionSaveRectBottom.right--;
+}
+
+void Interface::drawPanelText(Surface *ds, InterfacePanel *panel, PanelButton *panelButton) {
+ const char *text;
+ int textWidth;
+ Rect rect;
+ Point textPoint;
+
+ // Button differs for CD version
+ if (panelButton->id == kTextReadingSpeed && _vm->getFeatures() & GF_CD_FX)
+ return;
+ if (panelButton->id == kTextShowDialog && !(_vm->getFeatures() & GF_CD_FX))
+ return;
+
+ text = _vm->getTextString(panelButton->id);
+ panel->calcPanelButtonRect(panelButton, rect);
+ if (panelButton->xOffset < 0) {
+ textWidth = _vm->_font->getStringWidth(kKnownFontMedium, text, 0, kFontNormal);
+ rect.left += 2 + (panel->imageWidth - 1 - textWidth) / 2;
+ }
+
+ textPoint.x = rect.left;
+ textPoint.y = rect.top + 1;
+
+ _vm->_font->textDraw(kKnownFontMedium, ds, text, textPoint, _vm->KnownColor2ColorId(kKnownColorVerbText), _vm->KnownColor2ColorId(kKnownColorVerbTextShadow), kFontShadow);
+}
+
+void Interface::drawOption() {
+ const char *text;
+ Surface *backBuffer;
+ int i;
+ int fontHeight;
+ uint j, idx;
+ int fgColor;
+ int bgColor;
+ Rect rect;
+ Rect rect2;
+ PanelButton *panelButton;
+ Point textPoint;
+ if (_optionSaveFileSlider == NULL) return;//TODO:REMOVE
+
+ backBuffer = _vm->_gfx->getBackBuffer();
+
+ _optionPanel.getRect(rect);
+ backBuffer->blit(rect, _optionPanel.image);
+
+ for (i = 0; i < _optionPanel.buttonsCount; i++) {
+ panelButton = &_optionPanel.buttons[i];
+ if (panelButton->type == kPanelButtonOption) {
+ drawPanelButtonText(backBuffer, &_optionPanel, panelButton);
+ }
+ if (panelButton->type == kPanelButtonOptionText) {
+ drawPanelText(backBuffer, &_optionPanel, panelButton);
+ }
+ }
+
+ if (_optionSaveRectTop.height() > 0) {
+ backBuffer->drawRect(_optionSaveRectTop, kITEColorDarkGrey);
+ }
+
+ drawButtonBox(backBuffer, _optionSaveRectSlider, kSlider, _optionSaveFileSlider->state > 0);
+
+ if (_optionSaveRectBottom.height() > 0) {
+ backBuffer->drawRect(_optionSaveRectBottom, kITEColorDarkGrey);
+ }
+
+ _optionPanel.calcPanelButtonRect(_optionSaveFilePanel, rect);
+ rect.top++;
+ rect2 = rect;
+ fontHeight = _vm->_font->getHeight(kKnownFontSmall);
+ for (j = 0; j < _vm->getDisplayInfo().optionSaveFileVisible; j++) {
+ bgColor = kITEColorDarkGrey0C;
+ fgColor = kITEColorBrightWhite;
+
+ idx = j + _optionSaveFileTop;
+ if (idx == _optionSaveFileTitleNumber) {
+ SWAP(bgColor, fgColor);
+ }
+ if (idx < _vm->getSaveFilesCount()) {
+ rect2.top = rect.top + j * (fontHeight + 1);
+ rect2.bottom = rect2.top + fontHeight;
+ backBuffer->fillRect(rect2, bgColor);
+ text = _vm->getSaveFile(idx)->name;
+ textPoint.x = rect.left + 1;
+ textPoint.y = rect2.top;
+ _vm->_font->textDraw(kKnownFontSmall, backBuffer, text, textPoint, fgColor, 0, kFontNormal);
+ }
+ }
+
+}
+
+void Interface::drawQuit() {
+ Surface *backBuffer;
+ Rect rect;
+ int i;
+ PanelButton *panelButton;
+
+ backBuffer = _vm->_gfx->getBackBuffer();
+
+ _quitPanel.getRect(rect);
+ drawButtonBox(backBuffer, rect, kButton, false);
+ for (i = 0; i < _quitPanel.buttonsCount; i++) {
+ panelButton = &_quitPanel.buttons[i];
+ if (panelButton->type == kPanelButtonQuit) {
+ drawPanelButtonText(backBuffer, &_quitPanel, panelButton);
+ }
+ if (panelButton->type == kPanelButtonQuitText) {
+ drawPanelText(backBuffer, &_quitPanel, panelButton);
+ }
+ }
+}
+
+void Interface::handleQuitUpdate(const Point& mousePoint) {
+ bool releasedButton;
+
+ _quitPanel.currentButton = quitHitTest(mousePoint);
+ releasedButton = (_quitPanel.currentButton != NULL) && (_quitPanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
+
+ if (!_vm->mouseButtonPressed()) {
+ _quitPanel.zeroAllButtonState();
+ }
+
+ if (releasedButton) {
+ setQuit(_quitPanel.currentButton);
+ }
+}
+
+void Interface::handleQuitClick(const Point& mousePoint) {
+ _quitPanel.currentButton = quitHitTest(mousePoint);
+
+ _quitPanel.zeroAllButtonState();
+
+ if (_quitPanel.currentButton == NULL) {
+ return;
+ }
+
+ _quitPanel.currentButton->state = 1;
+}
+
+void Interface::setQuit(PanelButton *panelButton) {
+ _quitPanel.currentButton = NULL;
+ switch (panelButton->id) {
+ case kTextCancel:
+ setMode(kPanelOption);
+ break;
+ case kTextQuit:
+ _vm->shutDown();
+ break;
+ }
+}
+
+void Interface::drawLoad() {
+ Surface *backBuffer;
+ Rect rect;
+ int i;
+ PanelButton *panelButton;
+
+ backBuffer = _vm->_gfx->getBackBuffer();
+
+ _loadPanel.getRect(rect);
+ drawButtonBox(backBuffer, rect, kButton, false);
+ for (i = 0; i < _loadPanel.buttonsCount; i++) {
+ panelButton = &_loadPanel.buttons[i];
+ if (panelButton->type == kPanelButtonLoad) {
+ drawPanelButtonText(backBuffer, &_loadPanel, panelButton);
+ }
+ if (panelButton->type == kPanelButtonLoadText) {
+ drawPanelText(backBuffer, &_loadPanel, panelButton);
+ }
+ }
+}
+
+void Interface::handleLoadUpdate(const Point& mousePoint) {
+ bool releasedButton;
+
+ _loadPanel.currentButton = loadHitTest(mousePoint);
+ releasedButton = (_loadPanel.currentButton != NULL) && (_loadPanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
+
+ if (!_vm->mouseButtonPressed()) {
+ _loadPanel.zeroAllButtonState();
+ }
+
+ if (releasedButton) {
+ setLoad(_loadPanel.currentButton);
+ }
+}
+
+void Interface::handleLoadClick(const Point& mousePoint) {
+ _loadPanel.currentButton = loadHitTest(mousePoint);
+
+ _loadPanel.zeroAllButtonState();
+
+ if (_loadPanel.currentButton == NULL) {
+ return;
+ }
+
+ _loadPanel.currentButton->state = 1;
+}
+
+void Interface::setLoad(PanelButton *panelButton) {
+ _loadPanel.currentButton = NULL;
+ switch (panelButton->id) {
+ case kTextOK:
+ setMode(kPanelMain);
+ break;
+ }
+}
+
+void Interface::processStatusTextInput(uint16 ascii) {
+
+ textInputStartRepeat(ascii);
+ switch (ascii) {
+ case 27: // esc
+ _statusTextInputState = kStatusTextInputAborted;
+ _statusTextInput = false;
+ _vm->_script->wakeUpThreads(kWaitTypeStatusTextInput);
+ break;
+ case 13: // return
+ _statusTextInputState = kStatusTextInputEntered;
+ _statusTextInput = false;
+ _vm->_script->wakeUpThreads(kWaitTypeStatusTextInput);
+ break;
+ case 8: // backspace
+ if (_statusTextInputPos == 0) {
+ break;
+ }
+ _statusTextInputPos--;
+ _statusTextInputString[_statusTextInputPos] = 0;
+ default:
+ if (_statusTextInputPos >= STATUS_TEXT_INPUT_MAX) {
+ break;
+ }
+ if (((ascii >= 'a') && (ascii <='z')) ||
+ ((ascii >= '0') && (ascii <='9')) ||
+ ((ascii >= 'A') && (ascii <='Z')) ||
+ (ascii == ' ')) {
+ _statusTextInputString[_statusTextInputPos++] = ascii;
+ _statusTextInputString[_statusTextInputPos] = 0;
+ }
+ }
+ setStatusText(_statusTextInputString);
+}
+
+bool Interface::processTextInput(uint16 ascii) {
+ char ch[2];
+ char tempString[SAVE_TITLE_SIZE];
+ uint tempWidth;
+ memset(tempString, 0, SAVE_TITLE_SIZE);
+ ch[1] = 0;
+
+ textInputStartRepeat(ascii);
+
+ switch (ascii) {
+ case 13:
+ return false;
+ case 27: // esc
+ _textInput = false;
+ break;
+ case 8: // backspace
+ if (_textInputPos <= 1) {
+ break;
+ }
+ _textInputPos--;
+ case 127: // del
+ if (_textInputPos <= _textInputStringLength) {
+ if (_textInputPos != 1) {
+ strncpy(tempString, _textInputString, _textInputPos - 1);
+ }
+ if (_textInputPos != _textInputStringLength) {
+ strncat(tempString, &_textInputString[_textInputPos], _textInputStringLength - _textInputPos);
+ }
+ strcpy(_textInputString, tempString);
+ _textInputStringLength = strlen(_textInputString);
+ }
+ break;
+ case 276: // left
+ if (_textInputPos > 1) {
+ _textInputPos--;
+ }
+ break;
+ case 275: // right
+ if (_textInputPos <= _textInputStringLength) {
+ _textInputPos++;
+ }
+ break;
+ default:
+ if (((ascii >= 'a') && (ascii <='z')) ||
+ ((ascii >= '0') && (ascii <='9')) ||
+ ((ascii >= 'A') && (ascii <='Z')) ||
+ (ascii == ' ')) {
+ if (_textInputStringLength < SAVE_TITLE_SIZE - 1) {
+ ch[0] = ascii;
+ tempWidth = _vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal);
+ tempWidth += _vm->_font->getStringWidth(kKnownFontSmall, _textInputString, 0, kFontNormal);
+ if (tempWidth > _textInputMaxWidth) {
+ break;
+ }
+ if (_textInputPos != 1) {
+ strncpy(tempString, _textInputString, _textInputPos - 1);
+ strcat(tempString, ch);
+ }
+ if ((_textInputStringLength == 0) || (_textInputPos == 1)) {
+ strcpy(tempString, ch);
+ }
+ if ((_textInputStringLength != 0) && (_textInputPos != _textInputStringLength)) {
+ strncat(tempString, &_textInputString[_textInputPos - 1], _textInputStringLength - _textInputPos + 1);
+ }
+
+ strcpy(_textInputString, tempString);
+ _textInputStringLength = strlen(_textInputString);
+ _textInputPos++;
+ }
+ }
+ break;
+ }
+ return true;
+}
+
+void Interface::drawTextInput(Surface *ds, InterfacePanel *panel, PanelButton *panelButton) {
+ Point textPoint;
+ Rect rect;
+ char ch[2];
+ int fgColor;
+ uint i;
+
+ ch[1] = 0;
+ panel->calcPanelButtonRect(panelButton, rect);
+ drawButtonBox(ds, rect, kEdit, _textInput);
+ rect.left += 4;
+ rect.top += 4;
+ rect.setHeight(_vm->_font->getHeight(kKnownFontSmall));
+
+ i = 0;
+ while ((ch[0] = _textInputString[i++]) != 0) {
+ rect.setWidth(_vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal));
+ if ((i == _textInputPos) && _textInput) {
+ fgColor = kITEColorBlack;
+ ds->fillRect(rect, kITEColorWhite);
+ } else {
+ fgColor = kITEColorWhite;
+ }
+ textPoint.x = rect.left;
+ textPoint.y = rect.top + 1;
+
+ _vm->_font->textDraw(kKnownFontSmall, ds, ch, textPoint, fgColor, 0, kFontNormal);
+ rect.left += rect.width();
+ }
+ if (_textInput && (_textInputPos >= i)) {
+ ch[0] = ' ';
+ rect.setWidth(_vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal));
+ ds->fillRect(rect, kITEColorWhite);
+ }
+}
+
+void Interface::drawSave() {
+ Surface *backBuffer;
+ Rect rect;
+ int i;
+ PanelButton *panelButton;
+
+ backBuffer = _vm->_gfx->getBackBuffer();
+
+ _savePanel.getRect(rect);
+ drawButtonBox(backBuffer, rect, kButton, false);
+ for (i = 0; i < _savePanel.buttonsCount; i++) {
+ panelButton = &_savePanel.buttons[i];
+ if (panelButton->type == kPanelButtonSave) {
+ drawPanelButtonText(backBuffer, &_savePanel, panelButton);
+ }
+ if (panelButton->type == kPanelButtonSaveText) {
+ drawPanelText(backBuffer, &_savePanel, panelButton);
+ }
+ }
+
+ drawTextInput(backBuffer, &_savePanel, _saveEdit);
+}
+
+void Interface::drawProtect() {
+ Surface *backBuffer;
+ Rect rect;
+ int i;
+ PanelButton *panelButton;
+
+ backBuffer = _vm->_gfx->getBackBuffer();
+
+ _protectPanel.getRect(rect);
+ drawButtonBox(backBuffer, rect, kButton, false);
+
+ for (i = 0; i < _protectPanel.buttonsCount; i++) {
+ panelButton = &_protectPanel.buttons[i];
+ if (panelButton->type == kPanelButtonProtectText) {
+ drawPanelText(backBuffer, &_protectPanel, panelButton);
+ }
+ }
+ drawTextInput(backBuffer, &_protectPanel, _protectEdit);
+}
+
+void Interface::handleSaveUpdate(const Point& mousePoint) {
+ bool releasedButton;
+
+ _savePanel.currentButton = saveHitTest(mousePoint);
+
+ validateSaveButtons();
+
+ releasedButton = (_savePanel.currentButton != NULL) &&
+ (_savePanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
+
+ if (!_vm->mouseButtonPressed()) {
+ _savePanel.zeroAllButtonState();
+ }
+
+ if (releasedButton) {
+ setSave(_savePanel.currentButton);
+ }
+}
+
+void Interface::handleSaveClick(const Point& mousePoint) {
+ _savePanel.currentButton = saveHitTest(mousePoint);
+
+ validateSaveButtons();
+
+ _savePanel.zeroAllButtonState();
+
+ if (_savePanel.currentButton == NULL) {
+ _textInput = false;
+ return;
+ }
+
+ _savePanel.currentButton->state = 1;
+ if (_savePanel.currentButton == _saveEdit) {
+ _textInput = true;
+ }
+}
+
+void Interface::setSave(PanelButton *panelButton) {
+ _savePanel.currentButton = NULL;
+ uint titleNumber;
+ char *fileName;
+ switch (panelButton->id) {
+ case kTextSave:
+ if (_textInputStringLength == 0 ) {
+ break;
+ }
+ if (!_vm->isSaveListFull() && (_optionSaveFileTitleNumber == 0)) {
+ if (_vm->locateSaveFile(_textInputString, titleNumber)) {
+ fileName = _vm->calcSaveFileName(_vm->getSaveFile(titleNumber)->slotNumber);
+ _vm->save(fileName, _textInputString);
+ _optionSaveFileTitleNumber = titleNumber;
+ } else {
+ fileName = _vm->calcSaveFileName(_vm->getNewSaveSlotNumber());
+ _vm->save(fileName, _textInputString);
+ _vm->fillSaveList();
+ calcOptionSaveSlider();
+ }
+ } else {
+ fileName = _vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
+ _vm->save(fileName, _textInputString);
+ }
+ _textInput = false;
+ setMode(kPanelOption);
+ break;
+ case kTextCancel:
+ _textInput = false;
+ setMode(kPanelOption);
+ break;
+ }
+}
+
+void Interface::handleOptionUpdate(const Point& mousePoint) {
+ int16 mouseY;
+ Rect rect;
+ int totalFiles = _vm->getSaveFilesCount();
+ int visibleFiles = _vm->getDisplayInfo().optionSaveFileVisible;
+ bool releasedButton;
+
+ if (_vm->mouseButtonPressed()) {
+ if (_optionSaveFileSlider != NULL) //TODO:REMOVE
+ if (_optionSaveFileSlider->state > 0) {
+ _optionPanel.calcPanelButtonRect(_optionSaveFileSlider, rect);
+
+ mouseY = mousePoint.y - rect.top -_optionSaveFileMouseOff;
+
+ if (totalFiles - visibleFiles <= 0) {
+ _optionSaveFileTop = 0;
+ } else {
+ _optionSaveFileTop = mouseY * (totalFiles - visibleFiles) /
+ (_optionSaveFileSlider->height - _optionSaveRectSlider.height());
+ }
+
+ _optionSaveFileTop = clamp(0, _optionSaveFileTop, _vm->getSaveFilesCount() - _vm->getDisplayInfo().optionSaveFileVisible);
+ calcOptionSaveSlider();
+ }
+ }
+
+ _optionPanel.currentButton = optionHitTest(mousePoint);
+
+ validateOptionButtons();
+
+ releasedButton = (_optionPanel.currentButton != NULL) && (_optionPanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
+
+ if (!_vm->mouseButtonPressed()) {
+ _optionPanel.zeroAllButtonState();
+ }
+
+ if (releasedButton) {
+ setOption(_optionPanel.currentButton);
+ }
+}
+
+
+void Interface::handleOptionClick(const Point& mousePoint) {
+ Rect rect;
+ _optionPanel.currentButton = optionHitTest(mousePoint);
+
+ validateOptionButtons();
+
+ _optionPanel.zeroAllButtonState();
+
+ if (_optionPanel.currentButton == NULL) {
+ return;
+ }
+
+ if (_optionPanel.currentButton == _optionSaveFileSlider) {
+ if ((_optionSaveRectTop.height() > 0) && (mousePoint.y < _optionSaveRectTop.bottom)) {
+ _optionSaveFileTop -= _vm->getDisplayInfo().optionSaveFileVisible;
+ } else {
+ if ((_optionSaveRectBottom.height() > 0) && (mousePoint.y >= _optionSaveRectBottom.top)) {
+ _optionSaveFileTop += _vm->getDisplayInfo().optionSaveFileVisible;
+ } else {
+ if (_vm->getDisplayInfo().optionSaveFileVisible < _vm->getSaveFilesCount()) {
+ _optionSaveFileMouseOff = mousePoint.y - _optionSaveRectSlider.top;
+ _optionPanel.currentButton->state = 1;
+ }
+ }
+ }
+
+ _optionSaveFileTop = clamp(0, _optionSaveFileTop, _vm->getSaveFilesCount() - _vm->getDisplayInfo().optionSaveFileVisible);
+ calcOptionSaveSlider();
+ } else {
+ if (_optionPanel.currentButton == _optionSaveFilePanel) {
+ _optionPanel.calcPanelButtonRect(_optionSaveFilePanel, rect);
+ _optionSaveFileTitleNumber = (mousePoint.y - rect.top) / (_vm->_font->getHeight(kKnownFontSmall) + 1);
+
+ if (_optionSaveFileTitleNumber >= _vm->getDisplayInfo().optionSaveFileVisible) {
+ _optionSaveFileTitleNumber = _vm->getDisplayInfo().optionSaveFileVisible - 1;
+ }
+ _optionSaveFileTitleNumber += _optionSaveFileTop;
+ if (_optionSaveFileTitleNumber >= _vm->getSaveFilesCount()) {
+ _optionSaveFileTitleNumber = _vm->getSaveFilesCount() - 1;
+ }
+ } else {
+ _optionPanel.currentButton->state = 1;
+ }
+ }
+}
+
+void Interface::handleChapterSelectionUpdate(const Point& mousePoint) {
+ uint16 objectId;
+
+ // FIXME: Original handled more object types here.
+
+ objectId = _vm->_actor->hitTest(mousePoint, true);
+
+ if (objectId != _vm->_script->_pointerObject) {
+ _vm->_script->_pointerObject = objectId;
+ }
+}
+
+void Interface::handleChapterSelectionClick(const Point& mousePoint) {
+ int obj = _vm->_script->_pointerObject;
+
+ _vm->_actor->abortSpeech();
+
+ if (obj) {
+ int script = 0;
+ HitZone *hitZone;
+ ActorData *a;
+ ObjectData *o;
+ Event event;
+
+ switch (objectTypeId(obj)) {
+ case kGameObjectHitZone:
+ hitZone = _vm->_scene->_actionMap->getHitZone(objectIdToIndex(obj));
+ if (hitZone->getFlags() & kHitZoneExit)
+ script = hitZone->getScriptNumber();
+ break;
+
+ case kGameObjectActor:
+ a = _vm->_actor->getActor(obj);
+ script = a->_scriptEntrypointNumber;
+ break;
+
+ case kGameObjectObject:
+ o = _vm->_actor->getObj(obj);
+ script = o->_scriptEntrypointNumber;
+ break;
+ }
+
+ if (script > 0) {
+ event.type = kEvTOneshot;
+ event.code = kScriptEvent;
+ event.op = kEventExecNonBlocking;
+ event.time = 0;
+ event.param = _vm->_scene->getScriptModuleNumber();
+ event.param2 = script;
+ event.param3 = _vm->_script->getVerbType(kVerbUse); // Action
+ event.param4 = obj; // Object
+ event.param5 = 0; // With Object
+ event.param6 = obj; // Actor
+
+ _vm->_events->queue(&event);
+ }
+ }
+}
+
+void Interface::setOption(PanelButton *panelButton) {
+ char * fileName;
+ _optionPanel.currentButton = NULL;
+ switch (panelButton->id) {
+ case kTextContinuePlaying:
+ ConfMan.flushToDisk();
+ setMode(kPanelMain);
+ break;
+ case kTextQuitGame:
+ setMode(kPanelQuit);
+ break;
+ case kTextLoad:
+ if (_vm->getSaveFilesCount() > 0) {
+ if (_vm->isSaveListFull() || (_optionSaveFileTitleNumber > 0)) {
+ fileName = _vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
+ setMode(kPanelMain);
+ _vm->load(fileName);
+ }
+ }
+ break;
+ case kTextSave:
+ if (!_vm->isSaveListFull() && (_optionSaveFileTitleNumber == 0)) {
+ _textInputString[0] = 0;
+ } else {
+ strcpy(_textInputString, _vm->getSaveFile(_optionSaveFileTitleNumber)->name);
+ }
+ setMode(kPanelSave);
+ break;
+ case kTextReadingSpeed:
+ if (_vm->getFeatures() & GF_CD_FX) {
+ _vm->_subtitlesEnabled = !_vm->_subtitlesEnabled;
+ ConfMan.set("subtitles", _vm->_subtitlesEnabled);
+ } else {
+ _vm->_readingSpeed = (_vm->_readingSpeed + 1) % 4;
+ ConfMan.set("talkspeed", _vm->_readingSpeed);
+ }
+ break;
+ case kTextMusic:
+ _vm->_musicVolume = (_vm->_musicVolume + 1) % 11;
+ _vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
+ ConfMan.set("music_volume", _vm->_musicVolume * 25);
+ break;
+ case kTextSound:
+ _vm->_soundVolume = (_vm->_soundVolume + 1) % 11;
+ _vm->_sound->setVolume(_vm->_soundVolume == 10 ? 255 : _vm->_soundVolume * 25);
+ ConfMan.set("sfx_volume", _vm->_soundVolume * 25);
+ break;
+ }
+}
+
+void Interface::update(const Point& mousePoint, int updateFlag) {
+
+ if (!_active && _panelMode == kPanelNull && (updateFlag & UPDATE_MOUSECLICK))
+ _vm->_actor->abortSpeech();
+
+ if (_vm->_scene->isInIntro() || _fadeMode == kFadeOut || !_active) {
+ return;
+ }
+
+ if (_statusTextInput) {
+ return;
+ }
+
+ switch (_panelMode) {
+ case kPanelMain:
+ if (updateFlag & UPDATE_MOUSEMOVE) {
+ bool lastWasPlayfield = _lastMousePoint.y < _vm->_scene->getHeight();
+ if (mousePoint.y < _vm->_scene->getHeight()) {
+ if (!lastWasPlayfield) {
+ handleMainUpdate(mousePoint);
+ }
+ _vm->_script->whichObject(mousePoint);
+ } else {
+ if (lastWasPlayfield) {
+ _vm->_script->setNonPlayfieldVerb();
+ }
+ handleMainUpdate(mousePoint);
+ }
+
+ } else {
+
+ if (updateFlag & UPDATE_MOUSECLICK) {
+ if (mousePoint.y < _vm->_scene->getHeight()) {
+ _vm->_script->playfieldClick(mousePoint, (updateFlag & UPDATE_LEFTBUTTONCLICK) != 0);
+ } else {
+ handleMainClick(mousePoint);
+ }
+ }
+ }
+ break;
+
+ case kPanelConverse:
+ if (updateFlag & UPDATE_MOUSEMOVE) {
+ handleConverseUpdate(mousePoint);
+ } else {
+ if (updateFlag & UPDATE_MOUSECLICK) {
+ handleConverseClick(mousePoint);
+ }
+ if (updateFlag & UPDATE_WHEELUP) {
+ converseChangePos(-1);
+ }
+ if (updateFlag & UPDATE_WHEELDOWN) {
+ converseChangePos(1);
+ }
+
+ if (_vm->_puzzle->isActive()) {
+ _vm->_puzzle->handleClick(mousePoint);
+ }
+ }
+ break;
+
+ case kPanelOption:
+ if (updateFlag & UPDATE_MOUSEMOVE) {
+ handleOptionUpdate(mousePoint);
+ } else {
+ if (updateFlag & UPDATE_MOUSECLICK) {
+ handleOptionClick(mousePoint);
+ }
+ if (updateFlag & UPDATE_WHEELUP) {
+ if (_optionSaveFileTop)
+ _optionSaveFileTop--;
+ calcOptionSaveSlider();
+ }
+ if (updateFlag & UPDATE_WHEELDOWN) {
+ if (_optionSaveFileTop < _vm->getSaveFilesCount() - _vm->getDisplayInfo().optionSaveFileVisible)
+ _optionSaveFileTop++;
+ calcOptionSaveSlider();
+ }
+ }
+ break;
+
+ case kPanelQuit:
+ if (updateFlag & UPDATE_MOUSEMOVE) {
+ handleQuitUpdate(mousePoint);
+ } else {
+ if (updateFlag & UPDATE_MOUSECLICK) {
+ handleQuitClick(mousePoint);
+ }
+ }
+ break;
+
+ case kPanelLoad:
+ if (updateFlag & UPDATE_MOUSEMOVE) {
+
+ handleLoadUpdate(mousePoint);
+
+ } else {
+ if (updateFlag & UPDATE_MOUSECLICK) {
+ handleLoadClick(mousePoint);
+ }
+ }
+ break;
+
+ case kPanelSave:
+ if (updateFlag & UPDATE_MOUSEMOVE) {
+
+ handleSaveUpdate(mousePoint);
+
+ } else {
+ if (updateFlag & UPDATE_MOUSECLICK) {
+ handleSaveClick(mousePoint);
+ }
+ }
+ break;
+
+ case kPanelMap:
+ if (updateFlag & UPDATE_MOUSECLICK)
+ mapPanelClean();
+ break;
+
+ case kPanelSceneSubstitute:
+ if (updateFlag & UPDATE_MOUSECLICK) {
+ _vm->_render->clearFlag(RF_DEMO_SUBST);
+ _vm->_gfx->setPalette(_mapSavedPal);
+ setMode(kPanelMain);
+ _vm->_script->setNoPendingVerb();
+ }
+ break;
+
+ case kPanelChapterSelection:
+ // TODO: panel has silent button
+ if (updateFlag & UPDATE_MOUSEMOVE) {
+ handleChapterSelectionUpdate(mousePoint);
+ } else {
+ if (updateFlag & UPDATE_MOUSECLICK)
+ handleChapterSelectionClick(mousePoint);
+ }
+ break;
+
+ case kPanelProtect:
+ // No mouse interaction
+ break;
+
+ }
+
+ _lastMousePoint = mousePoint;
+}
+
+void Interface::drawStatusBar() {
+ Surface *backBuffer;
+ Rect rect;
+ Point textPoint;
+ int stringWidth;
+ int color;
+
+ if (_panelMode == kPanelChapterSelection)
+ return;
+
+ backBuffer = _vm->_gfx->getBackBuffer();
+
+ // Disable this for IHNM for now, since that game uses the full screen
+ // in some cases.
+
+ // Erase background of status bar
+ rect.left = _vm->getDisplayInfo().statusXOffset;
+ rect.top = _vm->getDisplayInfo().statusYOffset;
+ rect.right = rect.left + _vm->getDisplayWidth();
+ rect.bottom = rect.top + _vm->getDisplayInfo().statusHeight;
+
+ backBuffer->drawRect(rect, _vm->getDisplayInfo().statusBGColor);
+
+ stringWidth = _vm->_font->getStringWidth(kKnownFontSmall, _statusText, 0, kFontNormal);
+
+ if (_statusOnceColor == -1)
+ color = _vm->getDisplayInfo().statusTextColor;
+ else
+ color = _statusOnceColor;
+
+ textPoint.x = _vm->getDisplayInfo().statusXOffset + (_vm->getDisplayInfo().statusWidth - stringWidth) / 2;
+ textPoint.y = _vm->getDisplayInfo().statusYOffset + _vm->getDisplayInfo().statusTextY;
+ _vm->_font->textDraw(kKnownFontSmall, backBuffer, _statusText, textPoint, color, 0, kFontNormal);
+
+ if (_saveReminderState > 0) {
+ rect.left = _vm->getDisplayInfo().saveReminderXOffset;
+ rect.top = _vm->getDisplayInfo().saveReminderYOffset;
+
+ rect.right = rect.left + _vm->getDisplayInfo().saveReminderWidth;
+ rect.bottom = rect.top + _vm->getDisplayInfo().saveReminderHeight;
+ _vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _vm->_sprite->_saveReminderSprites,
+ _saveReminderState == 1 ? _vm->getDisplayInfo().saveReminderFirstSpriteNumber : _vm->getDisplayInfo().saveReminderSecondSpriteNumber,
+ rect, 256);
+
+ }
+}
+
+void Interface::handleMainClick(const Point& mousePoint) {
+
+ PanelButton *panelButton;
+
+ panelButton = verbHitTest(mousePoint);
+ if (panelButton) {
+ _vm->_script->setVerb(panelButton->id);
+ return;
+ }
+
+ panelButton = _mainPanel.hitTest(mousePoint, kPanelAllButtons);
+
+ if (panelButton != NULL) {
+ if (panelButton->type == kPanelButtonArrow) {
+ panelButton->state = 1;
+ converseChangePos(panelButton->id);
+ }
+
+ if (panelButton->type == kPanelButtonInventory) {
+ if (_vm->_script->_pointerObject != ID_NOTHING) {
+ _vm->_script->hitObject(_vm->leftMouseButtonPressed());
+ }
+ if (_vm->_script->_pendingVerb) {
+ _vm->_actor->_protagonist->_currentAction = kActionWait;
+ _vm->_script->doVerb();
+ }
+ }
+ } else {
+ if (_saveReminderState > 0) {
+ Rect rect;
+ rect.left = _vm->getDisplayInfo().saveReminderXOffset;
+ rect.top = _vm->getDisplayInfo().saveReminderYOffset;
+
+ rect.right = rect.left + _vm->getDisplayInfo().saveReminderWidth;
+ rect.bottom = rect.top + _vm->getDisplayInfo().saveReminderHeight;
+ if (rect.contains(mousePoint)) {
+ setMode(kPanelOption);
+ }
+ }
+ }
+}
+
+void Interface::handleMainUpdate(const Point& mousePoint) {
+ PanelButton *panelButton;
+
+ panelButton = verbHitTest(mousePoint);
+ if (_mainPanel.currentButton != panelButton) {
+ if (_mainPanel.currentButton) {
+ if (_mainPanel.currentButton->type == kPanelButtonVerb) {
+ setVerbState(_mainPanel.currentButton->id, 0);
+ }
+ }
+ if (panelButton) {
+ setVerbState(panelButton->id, 1);
+ }
+ }
+
+ if (panelButton) {
+ _mainPanel.currentButton = panelButton;
+ return;
+ }
+
+
+ if (!_vm->mouseButtonPressed()) { // remove pressed flag
+ if (_inventoryUpButton) {
+ _inventoryUpButton->state = 0;
+ _inventoryDownButton->state = 0;
+ }
+ }
+
+ panelButton = _mainPanel.hitTest(mousePoint, kPanelAllButtons);
+
+ bool changed = false;
+
+ if ((panelButton != NULL) && (panelButton->type == kPanelButtonArrow)) {
+ if (panelButton->state == 1) {
+ //TODO: insert timeout catchup
+ inventoryChangePos(panelButton->id);
+ }
+ changed = true;
+ } else {
+ _vm->_script->whichObject(mousePoint);
+ }
+
+ changed = changed || (panelButton != _mainPanel.currentButton);
+ _mainPanel.currentButton = panelButton;
+ if (changed) {
+ draw();
+ }
+}
+
+//inventory stuff
+void Interface::inventoryChangePos(int chg) {
+ if ((chg < 0 && _inventoryStart + chg >= 0) ||
+ (chg > 0 && _inventoryStart < _inventoryEnd)) {
+ _inventoryStart += chg;
+ draw();
+ }
+}
+
+void Interface::inventorySetPos(int key) {
+ _inventoryBox = key - '1';
+ _inventoryPos = _inventoryStart + _inventoryBox;
+ if (_inventoryPos >= _inventoryCount)
+ _inventoryPos = -1;
+}
+
+void Interface::updateInventory(int pos) {
+ int cols = _vm->getDisplayInfo().inventoryColumns;
+ if (pos >= _inventoryCount) {
+ pos = _inventoryCount - 1;
+ }
+ if (pos < 0) {
+ pos = 0;
+ }
+ _inventoryStart = (pos - cols) / cols * cols;
+ if (_inventoryStart < 0) {
+ _inventoryStart = 0;
+ }
+
+ _inventoryEnd = (_inventoryCount - 1 - cols) / cols * cols;
+ if (_inventoryEnd < 0) {
+ _inventoryEnd = 0;
+ }
+}
+
+void Interface::addToInventory(int objectId) {
+ if (_inventoryCount >= _inventorySize) {
+ return;
+ }
+
+ for (int i = _inventoryCount; i > 0; i--) {
+ _inventory[i] = _inventory[i - 1];
+ }
+
+ _inventory[0] = objectId;
+ _inventoryCount++;
+
+ _inventoryPos = 0;
+ updateInventory(0);
+ draw();
+}
+
+void Interface::removeFromInventory(int objectId) {
+ int j = inventoryItemPosition(objectId);
+ if (j == -1) {
+ return;
+ }
+
+ int i;
+
+ for (i = j; i < _inventoryCount - 1; i++) {
+ _inventory[i] = _inventory[i + 1];
+ }
+
+ --_inventoryCount;
+ _inventory[_inventoryCount] = 0;
+ updateInventory(j);
+ draw();
+}
+
+void Interface::clearInventory() {
+ for (int i = 0; i < _inventoryCount; i++)
+ _inventory[i] = 0;
+
+ _inventoryCount = 0;
+ updateInventory(0);
+}
+
+int Interface::inventoryItemPosition(int objectId) {
+ for (int i = 0; i < _inventoryCount; i++)
+ if (_inventory[i] == objectId)
+ return i;
+
+ return -1;
+}
+
+void Interface::drawInventory(Surface *backBuffer) {
+ if (!isInMainMode())
+ return;
+
+ int i;
+ Rect rect;
+ int ci;
+ ObjectData *obj;
+ ci = _inventoryStart;
+ if (_inventoryStart != 0) {
+ drawPanelButtonArrow(backBuffer, &_mainPanel, _inventoryUpButton);
+ }
+ if (_inventoryStart != _inventoryEnd) {
+ drawPanelButtonArrow(backBuffer, &_mainPanel, _inventoryDownButton);
+ }
+
+ for (i = 0; i < _mainPanel.buttonsCount; i++) {
+ if (_mainPanel.buttons[i].type != kPanelButtonInventory) {
+ continue;
+ }
+ _mainPanel.calcPanelButtonRect(&_mainPanel.buttons[i], rect);
+
+ // TODO: Different colour for IHNM, probably.
+ backBuffer->drawRect(rect, kITEColorDarkGrey);
+
+ if (ci < _inventoryCount) {
+ obj = _vm->_actor->getObj(_inventory[ci]);
+ _vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _vm->_sprite->_inventorySprites, obj->_spriteListResourceId, rect, 256);
+ }
+
+ ci++;
+ }
+}
+
+void Interface::setVerbState(int verb, int state) {
+ PanelButton * panelButton = getPanelButtonByVerbType(verb);
+ if (panelButton == NULL) return;
+ if (state == 2) {
+ state = (_mainPanel.currentButton == panelButton) ? 1 : 0;
+ }
+ panelButton->state = state;
+ draw();
+}
+
+void Interface::drawButtonBox(Surface *ds, const Rect& rect, ButtonKind kind, bool down) {
+ byte cornerColor;
+ byte frameColor;
+ byte fillColor;
+ byte solidColor;
+ byte odl, our, idl, iur;
+
+ switch (kind ) {
+ case kSlider:
+ cornerColor = 0x8b;
+ frameColor = kITEColorBlack;
+ fillColor = kITEColorLightBlue96;
+ odl = kITEColorDarkBlue8a;
+ our = kITEColorLightBlue92;
+ idl = 0x89;
+ iur = 0x94;
+ solidColor = down ? kITEColorLightBlue94 : kITEColorLightBlue96;
+ break;
+ case kEdit:
+ cornerColor = kITEColorLightBlue96;
+ frameColor = kITEColorLightBlue96;
+ fillColor = kITEColorLightBlue96;
+ our = kITEColorDarkBlue8a;
+ odl = kITEColorLightBlue94;
+ iur = 0x97;
+ idl = 0x95;
+ if (down) {
+ solidColor = kITEColorBlue;
+ } else {
+ solidColor = kITEColorDarkGrey0C;
+ }
+ break;
+ default:
+ cornerColor = 0x8b;
+ frameColor = kITEColorBlack;
+ solidColor = fillColor = kITEColorLightBlue96;
+ odl = kITEColorDarkBlue8a;
+ our = kITEColorLightBlue94;
+ idl = 0x97;
+ iur = 0x95;
+ if (down) {
+ SWAP(odl, our);
+ SWAP(idl, iur);
+ }
+ break;
+ }
+
+ int x = rect.left;
+ int y = rect.top;
+ int w = rect.width();
+ int h = rect.height();
+ int xe = rect.right - 1;
+ int ye = rect.bottom - 1;
+
+ ((byte *)ds->getBasePtr(x, y))[0] = cornerColor;
+ ((byte *)ds->getBasePtr(x, ye))[0] = cornerColor;
+ ((byte *)ds->getBasePtr(xe, y))[0] = cornerColor;
+ ((byte *)ds->getBasePtr(xe, ye))[0] = cornerColor;
+ ds->hLine(x + 1, y, x + 1 + w - 2, frameColor);
+ ds->hLine(x + 1, ye, x + 1 + w - 2, frameColor);
+ ds->vLine(x, y + 1, y + 1 + h - 2, frameColor);
+ ds->vLine(xe, y + 1, y + 1 + h - 2, frameColor);
+
+ x++;
+ y++;
+ xe--;
+ ye--;
+ w -= 2;
+ h -= 2;
+ ds->vLine(x, y, y + h - 1, odl);
+ ds->hLine(x, ye, x + w - 1, odl);
+ ds->vLine(xe, y, y + h - 1, our);
+ ds->hLine(x + 1, y, x + 1 + w - 2, our);
+
+ x++;
+ y++;
+ xe--;
+ ye--;
+ w -= 2;
+ h -= 2;
+ ((byte *)ds->getBasePtr(x, y))[0] = fillColor;
+ ((byte *)ds->getBasePtr(xe, ye))[0] = fillColor;
+ ds->vLine(x, y + 1, y + 1 + h - 2, idl);
+ ds->hLine(x + 1, ye, x + 1 + w - 2, idl);
+ ds->vLine(xe, y, y + h - 1, iur);
+ ds->hLine(x + 1, y, x + 1 + w - 2, iur);
+
+ x++; y++;
+ w -= 2; h -= 2;
+
+ Common::Rect fill(x, y, x + w, y + h);
+ ds->fillRect(fill, solidColor);
+}
+
+static const int readingSpeeds[] = { kTextFast, kTextMid, kTextSlow, kTextClick };
+
+void Interface::drawPanelButtonText(Surface *ds, InterfacePanel *panel, PanelButton *panelButton) {
+ const char *text;
+ int textId;
+ int textWidth;
+ int textHeight;
+ Point point;
+ KnownColor textColor;
+ Rect rect;
+
+ textId = panelButton->id;
+ switch(panelButton->id) {
+ case kTextReadingSpeed:
+ if (_vm->getFeatures() & GF_CD_FX) {
+ if (_vm->_subtitlesEnabled)
+ textId = kTextOn;
+ else
+ textId = kTextOff;
+ } else {
+ textId = readingSpeeds[_vm->_readingSpeed];
+ }
+ break;
+ case kTextMusic:
+ if (_vm->_musicVolume)
+ textId = kText10Percent + _vm->_musicVolume - 1;
+ else
+ textId = kTextOff;
+ break;
+ case kTextSound:
+ if (_vm->_soundVolume)
+ textId = kText10Percent + _vm->_soundVolume - 1;
+ else
+ textId = kTextOff;
+ break;
+ }
+ text = _vm->getTextString(textId);
+
+ textWidth = _vm->_font->getStringWidth(kKnownFontMedium, text, 0, kFontNormal);
+ textHeight = _vm->_font->getHeight(kKnownFontMedium);
+
+ point.x = panel->x + panelButton->xOffset + (panelButton->width / 2) - (textWidth / 2);
+ point.y = panel->y + panelButton->yOffset + (panelButton->height / 2) - (textHeight / 2);
+
+ if (panelButton == panel->currentButton) {
+ textColor = kKnownColorVerbTextActive;
+ } else {
+ textColor = kKnownColorVerbText;
+ }
+
+ panel->calcPanelButtonRect(panelButton, rect);
+ drawButtonBox(ds, rect, kButton, panelButton->state > 0);
+
+ _vm->_font->textDraw(kKnownFontMedium, ds, text, point,
+ _vm->KnownColor2ColorId(textColor), _vm->KnownColor2ColorId(kKnownColorVerbTextShadow), kFontShadow);
+}
+
+void Interface::drawPanelButtonArrow(Surface *ds, InterfacePanel *panel, PanelButton *panelButton) {
+ Point point;
+ int spriteNumber;
+
+ if (panel->currentButton == panelButton) {
+ if (panelButton->state != 0) {
+ spriteNumber = panelButton->downSpriteNumber;
+ } else {
+ spriteNumber = panelButton->overSpriteNumber;
+ }
+ } else {
+ spriteNumber = panelButton->upSpriteNumber;
+ }
+
+ point.x = panel->x + panelButton->xOffset;
+ point.y = panel->y + panelButton->yOffset;
+
+ _vm->_sprite->draw(ds, _vm->getDisplayClip(), _vm->_sprite->_mainSprites, spriteNumber, point, 256);
+}
+
+void Interface::drawVerbPanelText(Surface *ds, PanelButton *panelButton, KnownColor textKnownColor, KnownColor textShadowKnownColor) {
+ const char *text;
+ int textWidth;
+ Point point;
+ int textId;
+
+ if (_vm->getGameType() == GType_ITE) {
+ textId = verbTypeToTextStringsIdLUT[0][panelButton->id];
+ text = _vm->getTextString(textId);
+ } else {
+ textId = verbTypeToTextStringsIdLUT[1][panelButton->id];
+ text = _vm->_script->_mainStrings.getString(textId + 1);
+ textShadowKnownColor = kKnownColorTransparent;
+ }
+
+ textWidth = _vm->_font->getStringWidth(kKnownFontVerb, text, 0, kFontNormal);
+
+ if (_vm->getGameType() == GType_ITE) {
+ point.x = _mainPanel.x + panelButton->xOffset + 1 + (panelButton->width - 1 - textWidth) / 2;
+ point.y = _mainPanel.y + panelButton->yOffset + 1;
+ } else {
+ point.x = _mainPanel.x + panelButton->xOffset + 1 + (panelButton->width - textWidth) / 2;
+ point.y = _mainPanel.y + panelButton->yOffset + 12;
+ }
+
+ _vm->_font->textDraw(kKnownFontVerb, ds, text, point, _vm->KnownColor2ColorId(textKnownColor),_vm->KnownColor2ColorId(textShadowKnownColor), (textShadowKnownColor != kKnownColorTransparent) ? kFontShadow : kFontNormal);
+}
+
+
+// Converse stuff
+void Interface::converseInit(void) {
+ for (int i = 0; i < CONVERSE_MAX_TEXTS; i++)
+ _converseText[i].text = NULL;
+ converseClear();
+}
+
+void Interface::converseClear(void) {
+ for (int i = 0; i < CONVERSE_MAX_TEXTS; i++) {
+ if (_converseText[i].text != NULL) {
+ free(_converseText[i].text);
+ _converseText[i].text = NULL;
+ }
+ _converseText[i].stringNum = -1;
+ _converseText[i].replyId = 0;
+ _converseText[i].replyFlags = 0;
+ _converseText[i].replyBit = 0;
+ }
+
+ _converseTextCount = 0;
+ _converseStrCount = 0;
+ _converseStartPos = 0;
+ _converseEndPos = 0;
+ _conversePos = -1;
+}
+
+bool Interface::converseAddText(const char *text, int replyId, byte replyFlags, int replyBit) {
+ int count = 0; // count how many pieces of text per string
+ int i;
+ int len;
+ byte c;
+
+ assert(strlen(text) < CONVERSE_MAX_WORK_STRING);
+
+ strncpy(_converseWorkString, text, CONVERSE_MAX_WORK_STRING);
+
+ while (1) {
+ len = strlen(_converseWorkString);
+
+ for (i = len; i >= 0; i--) {
+ c = _converseWorkString[i];
+
+ if ((c == ' ' || c == '\0') && (_vm->_font->getStringWidth(kKnownFontSmall, _converseWorkString, i, kFontNormal) <= _vm->getDisplayInfo().converseMaxTextWidth)) {
+ break;
+ }
+ }
+ if (i < 0) {
+ return true;
+ }
+
+ if (_converseTextCount == CONVERSE_MAX_TEXTS) {
+ return true;
+ }
+
+ _converseText[_converseTextCount].text = (char *)malloc(i + 1);
+ strncpy(_converseText[_converseTextCount].text, _converseWorkString, i);
+
+ _converseText[_converseTextCount].text[i] = 0;
+ _converseText[_converseTextCount].textNum = count;
+ _converseText[_converseTextCount].stringNum = _converseStrCount;
+ _converseText[_converseTextCount].replyId = replyId;
+ _converseText[_converseTextCount].replyFlags = replyFlags;
+ _converseText[_converseTextCount].replyBit = replyBit;
+
+ _converseTextCount++;
+ count++;
+
+ if (len == i)
+ break;
+
+ strncpy(_converseWorkString, &_converseWorkString[i + 1], len - i);
+ }
+
+ _converseStrCount++;
+
+ return false;
+}
+
+void Interface::converseDisplayText() {
+ int end;
+
+ _converseStartPos = 0;
+
+ end = _converseTextCount - _vm->getDisplayInfo().converseTextLines;
+
+ if (end < 0)
+ end = 0;
+
+ _converseEndPos = end;
+ draw();
+}
+
+
+void Interface::converseSetTextLines(int row) {
+ int pos = row + _converseStartPos;
+ if (pos >= _converseTextCount)
+ pos = -1;
+ if (pos != _conversePos) {
+ _conversePos = pos;
+ draw();
+ }
+}
+
+void Interface::converseDisplayTextLines(Surface *ds) {
+ int relPos;
+ byte foregnd;
+ byte backgnd;
+ byte bulletForegnd;
+ byte bulletBackgnd;
+ const char *str;
+ char bullet[2] = {
+ (char)0xb7, 0
+ };
+ Rect rect(8, _vm->getDisplayInfo().converseTextLines * _vm->getDisplayInfo().converseTextHeight);
+ Point textPoint;
+
+ assert(_conversePanel.buttonsCount >= 6);
+
+ bulletForegnd = kITEColorGreen;
+ bulletBackgnd = kITEColorBlack;
+
+ rect.moveTo(_conversePanel.x + _conversePanel.buttons[0].xOffset,
+ _conversePanel.y + _conversePanel.buttons[0].yOffset);
+
+ ds->drawRect(rect, kITEColorDarkGrey); //fill bullet place
+
+ for (int i = 0; i < _vm->getDisplayInfo().converseTextLines; i++) {
+ relPos = _converseStartPos + i;
+
+ if (_converseTextCount <= relPos) {
+ break;
+ }
+
+ if (_conversePos >= 0 && _converseText[_conversePos].stringNum == _converseText[relPos].stringNum) {
+ foregnd = kITEColorBrightWhite;
+ backgnd = (!_vm->leftMouseButtonPressed()) ? kITEColorDarkGrey : kITEColorGrey;
+ } else {
+ foregnd = kITEColorBlue;
+ backgnd = kITEColorDarkGrey;
+ }
+
+ _conversePanel.calcPanelButtonRect(&_conversePanel.buttons[i], rect);
+ rect.left += 8;
+ ds->drawRect(rect, backgnd);
+
+ str = _converseText[relPos].text;
+
+ if (_converseText[relPos].textNum == 0) { // first entry
+ textPoint.x = rect.left - 6;
+ textPoint.y = rect.top;
+
+ _vm->_font->textDraw(kKnownFontSmall, ds, bullet, textPoint, bulletForegnd, bulletBackgnd, (FontEffectFlags)(kFontShadow | kFontDontmap));
+ }
+ textPoint.x = rect.left + 1;
+ textPoint.y = rect.top;
+ _vm->_font->textDraw(kKnownFontSmall, ds, str, textPoint, foregnd, kITEColorBlack, kFontShadow);
+ }
+
+ if (_converseStartPos != 0) {
+ drawPanelButtonArrow(ds, &_conversePanel, _converseUpButton);
+ }
+
+ if (_converseStartPos != _converseEndPos) {
+ drawPanelButtonArrow(ds, &_conversePanel, _converseDownButton);
+ }
+}
+
+void Interface::converseChangePos(int chg) {
+ if ((chg < 0 && _converseStartPos + chg >= 0) ||
+ (chg > 0 && _converseStartPos < _converseEndPos)) {
+ _converseStartPos += chg;
+ draw();
+ }
+}
+
+void Interface::converseSetPos(int key) {
+ Converse *ct;
+ int selection = key - '1';
+
+ if (selection >= _converseTextCount)
+ return;
+
+ converseSetTextLines(selection);
+
+ ct = &_converseText[_conversePos];
+
+ _vm->_script->finishDialog(ct->replyId, ct->replyFlags, ct->replyBit);
+
+ if (_vm->_puzzle->isActive())
+ _vm->_puzzle->handleReply(ct->replyId);
+
+ _conversePos = -1;
+}
+
+
+void Interface::handleConverseUpdate(const Point& mousePoint) {
+ bool changed;
+
+ PanelButton *last = _conversePanel.currentButton;
+
+ if (!_vm->mouseButtonPressed()) { // remove pressed flag
+ if (_converseUpButton) {
+ _converseUpButton->state = 0;
+ _converseDownButton->state = 0;
+ }
+ }
+
+ _conversePanel.currentButton = converseHitTest(mousePoint);
+ changed = last != _conversePanel.currentButton;
+
+
+ if (_conversePanel.currentButton == NULL) {
+ _conversePos = -1;
+ if (changed) {
+ draw();
+ }
+ return;
+ }
+
+ if (_conversePanel.currentButton->type == kPanelButtonConverseText) {
+ converseSetTextLines(_conversePanel.currentButton->id);
+ }
+
+ if (_conversePanel.currentButton->type == kPanelButtonArrow) {
+ if (_conversePanel.currentButton->state == 1) {
+ //TODO: insert timeout catchup
+ converseChangePos(_conversePanel.currentButton->id);
+ }
+ draw();
+ }
+}
+
+
+void Interface::handleConverseClick(const Point& mousePoint) {
+ _conversePanel.currentButton = converseHitTest(mousePoint);
+
+ if (_conversePanel.currentButton == NULL) {
+ return;
+ }
+
+ if (_conversePanel.currentButton->type == kPanelButtonConverseText) {
+ converseSetPos(_conversePanel.currentButton->ascii);
+ }
+
+ if (_conversePanel.currentButton->type == kPanelButtonArrow) {
+ _conversePanel.currentButton->state = 1;
+ converseChangePos(_conversePanel.currentButton->id);
+ }
+
+}
+
+void Interface::saveState(Common::OutSaveFile *out) {
+ out->writeUint16LE(_inventoryCount);
+
+ for (int i = 0; i < _inventoryCount; i++) {
+ out->writeUint16LE(_inventory[i]);
+ }
+}
+
+void Interface::loadState(Common::InSaveFile *in) {
+ _inventoryCount = in->readUint16LE();
+
+ for (int i = 0; i < _inventoryCount; i++) {
+ _inventory[i] = in->readUint16LE();
+ }
+
+ updateInventory(0);
+}
+
+void Interface::mapPanelShow() {
+ int i;
+ byte *resource;
+ size_t resourceLength, imageLength;
+ Surface *backBuffer;
+ Rect rect;
+ byte *image;
+ int imageWidth, imageHeight;
+ const byte *pal;
+ PalEntry cPal[PAL_ENTRIES];
+
+ _vm->_gfx->showCursor(false);
+
+ backBuffer = _vm->_gfx->getBackBuffer();
+
+ rect.left = rect.top = 0;
+
+ _vm->_resource->loadResource(_interfaceContext,
+ _vm->_resource->convertResourceId(RID_ITE_TYCHO_MAP), resource, resourceLength);
+ if (resourceLength == 0) {
+ error("Interface::mapPanelShow() unable to load Tycho map resource");
+ }
+
+ _vm->_gfx->getCurrentPal(_mapSavedPal);
+
+ for (i = 0; i < 6 ; i++) {
+ _vm->_gfx->palToBlack(_mapSavedPal, 0.2 * i);
+ _vm->_render->drawScene();
+ _vm->_system->delayMillis(5);
+ }
+
+ _vm->_render->setFlag(RF_MAP);
+
+ _vm->decodeBGImage(resource, resourceLength, &image, &imageLength, &imageWidth, &imageHeight);
+ pal = _vm->getImagePal(resource, resourceLength);
+
+ for (i = 0; i < PAL_ENTRIES; i++) {
+ cPal[i].red = *pal++;
+ cPal[i].green = *pal++;
+ cPal[i].blue = *pal++;
+ }
+
+ rect.setWidth(imageWidth);
+ rect.setHeight(imageHeight);
+
+ backBuffer->blit(rect, image);
+
+ // Evil Evil
+ for (i = 0; i < 6 ; i++) {
+ _vm->_gfx->blackToPal(cPal, 0.2 * i);
+ _vm->_render->drawScene();
+ _vm->_system->delayMillis(5);
+ }
+
+ free(resource);
+ free(image);
+
+ setSaveReminderState(false);
+
+ _mapPanelCrossHairState = true;
+}
+
+void Interface::mapPanelClean() {
+ PalEntry pal[PAL_ENTRIES];
+ int i;
+
+ _vm->_gfx->getCurrentPal(pal);
+
+ for (i = 0; i < 6 ; i++) {
+ _vm->_gfx->palToBlack(pal, 0.2 * i);
+ _vm->_render->drawScene();
+ _vm->_system->delayMillis(5);
+ }
+
+ _vm->_render->clearFlag(RF_MAP);
+ setMode(kPanelMain);
+
+ _vm->_gfx->showCursor(true);
+ _vm->_render->drawScene();
+
+ for (i = 0; i < 6 ; i++) {
+ _vm->_gfx->blackToPal(_mapSavedPal, 0.2 * i);
+ _vm->_render->drawScene();
+ _vm->_system->delayMillis(5);
+ }
+}
+
+void Interface::mapPanelDrawCrossHair() {
+ Surface *backBuffer;
+
+ backBuffer = _vm->_gfx->getBackBuffer();
+ _mapPanelCrossHairState = !_mapPanelCrossHairState;
+
+ Point mapPosition = _vm->_isoMap->getMapPosition();
+ Rect screen(_vm->getDisplayWidth(), _vm->_scene->getHeight());
+
+ if (screen.contains(mapPosition)) {
+ _vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _vm->_sprite->_mainSprites,
+ _mapPanelCrossHairState? RID_ITE_SPR_XHAIR1 : RID_ITE_SPR_XHAIR2,
+ mapPosition, 256);
+ }
+}
+
+void Interface::keyBoss() {
+ if (_vm->getGameType() != GType_IHNM)
+ return;
+
+ if (_bossMode != -1 || _fadeMode != kNoFade)
+ return;
+
+ _vm->_sound->pauseVoice();
+ _vm->_sound->pauseSound();
+ _vm->_music->pause();
+
+ int i;
+ byte *resource;
+ size_t resourceLength, imageLength;
+ Surface *backBuffer;
+ Rect rect;
+ byte *image;
+ int imageWidth, imageHeight;
+ const byte *pal;
+ PalEntry cPal[PAL_ENTRIES];
+
+ _vm->_gfx->showCursor(false);
+
+ backBuffer = _vm->_gfx->getBackBuffer();
+
+ rect.left = rect.top = 0;
+
+ _vm->_resource->loadResource(_interfaceContext, RID_IHNM_BOSS_SCREEN, resource, resourceLength);
+ if (resourceLength == 0) {
+ error("Interface::bossKey() unable to load Boss image resource");
+ }
+
+ _bossMode = _panelMode;
+ setMode(kPanelBoss);
+
+ _vm->decodeBGImage(resource, resourceLength, &image, &imageLength, &imageWidth, &imageHeight);
+ rect.setWidth(imageWidth);
+ rect.setHeight(imageHeight);
+
+ _vm->_gfx->getCurrentPal(_mapSavedPal);
+ pal = _vm->getImagePal(resource, resourceLength);
+
+ for (i = 0; i < PAL_ENTRIES; i++) {
+ cPal[i].red = *pal++;
+ cPal[i].green = *pal++;
+ cPal[i].blue = *pal++;
+ }
+
+ backBuffer->blit(rect, image);
+
+ _vm->_gfx->setPalette(cPal);
+
+ free(resource);
+ free(image);
+}
+
+
+void Interface::keyBossExit() {
+ PalEntry pal[PAL_ENTRIES];
+
+ _vm->_sound->resumeVoice();
+ _vm->_sound->resumeSound();
+ _vm->_music->resume();
+
+ _vm->_gfx->getCurrentPal(pal);
+
+ _vm->_gfx->palToBlack(pal, 1);
+ setMode(_bossMode);
+
+ _vm->_render->drawScene();
+
+ _vm->_gfx->blackToPal(_mapSavedPal, 1);
+
+ _vm->_gfx->showCursor(true);
+
+ _bossMode = -1;
+}
+
+
+} // End of namespace Saga