scummvm/engines/saga/interface.cpp

2712 lines
72 KiB
C++
Raw Normal View History

/* 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.
*
* $URL$
* $Id$
*
*/
2004-05-01 09:37:24 +00:00
// Game interface module
2004-08-02 16:20:35 +00:00
#include "saga/saga.h"
2004-08-02 16:20:35 +00:00
#include "saga/gfx.h"
#include "saga/actor.h"
2004-08-10 18:31:33 +00:00
#include "saga/console.h"
#include "saga/displayinfo.h"
#include "saga/events.h"
2004-08-03 00:06:18 +00:00
#include "saga/font.h"
2004-08-02 16:20:35 +00:00
#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"
2004-08-03 01:07:34 +00:00
#include "saga/sprite.h"
#include "saga/rscfile.h"
#include "saga/sagaresnames.h"
2004-08-02 16:20:35 +00:00
#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,
2007-05-01 21:48:18 +00:00
kVerbIHNMWalk,
kVerbIHNMLookAt,
kVerbIHNMTake,
kVerbIHNMUse,
kVerbIHNMTalkTo,
kVerbIHNMSwallow,
kVerbIHNMGive,
kVerbIHNMPush}
};
// This maps the internally used string ITE IDs to the LUT strings loaded in IHNM
// i.e. id 12 (quit game button) maps to string 14 (Quit game)
// The comments are what the actual IHNM string is
// For the text string IDs, refer to saga.h, enum TextStringIds
static int IHNMTextStringIdsLUT[56] = {
-1, // (Empty)
-1, // (Empty)
4, // Take
6, // Talk to
-1,
-1,
5, // Use
8, // Give
10, // Options
11, // Test
12, //
13, // Help
14, // Quit Game
16, // Fast
18, // Slow
20, // On
21, // Off
15, // Continue Playing
22, // Load
23, // Save
24, // Game Options
25, // Reading Speed
26, // Music
27, // Sound
32, // Cancel
33, // Quit
34, // OK
17, // Mid
19, // Click
36, // 10%
37, // 20%
38, // 30%
39, // 40%
40, // 50%
41, // 60%
42, // 70%
43, // 80%
44, // 90%
45, // Max
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
28, // Voices
29, // Text
30, // Audio
31 // Both
};
Interface::Interface(SagaEngine *vm) : _vm(vm) {
byte *resource;
size_t resourceLength;
int i;
2005-07-29 17:58:00 +00:00
2004-05-01 09:37:24 +00:00
// Load interface module resource file context
_interfaceContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
if (_interfaceContext == NULL) {
error("Interface::Interface() resource context not found");
}
2005-07-29 17:58:00 +00:00
// Main panel
_mainPanel.buttons = _vm->getDisplayInfo().mainPanelButtons;
_mainPanel.buttonsCount = _vm->getDisplayInfo().mainPanelButtonsCount;
for (i = 0; i < kVerbTypeIdsMax; i++) {
_verbTypeToPanelButton[i] = NULL;
}
2005-07-29 17:58:00 +00:00
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);
2005-07-29 17:58:00 +00:00
free(resource);
// Converse panel
_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);
// Option panel
_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);
// Quit panel
if (_vm->getGameType() == GType_IHNM) {
_quitPanel.buttons = _vm->getDisplayInfo().quitPanelButtons;
_quitPanel.buttonsCount = _vm->getDisplayInfo().quitPanelButtonsCount;
_vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resource, resourceLength);
_vm->decodeBGImage(resource, resourceLength, &_quitPanel.image,
&_quitPanel.imageLength, &_quitPanel.imageWidth, &_quitPanel.imageHeight);
free(resource);
}
// Save panel
if (_vm->getGameType() == GType_IHNM) {
_savePanel.buttons = _vm->getDisplayInfo().savePanelButtons;
_savePanel.buttonsCount = _vm->getDisplayInfo().savePanelButtonsCount;
_vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resource, resourceLength);
_vm->decodeBGImage(resource, resourceLength, &_savePanel.image,
&_savePanel.imageLength, &_savePanel.imageWidth, &_savePanel.imageHeight);
free(resource);
}
// Load panel
if (_vm->getGameType() == GType_IHNM) {
_loadPanel.buttons = _vm->getDisplayInfo().loadPanelButtons;
_loadPanel.buttonsCount = _vm->getDisplayInfo().loadPanelButtonsCount;
_vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resource, resourceLength);
_vm->decodeBGImage(resource, resourceLength, &_loadPanel.image,
&_loadPanel.imageLength, &_loadPanel.imageWidth, &_loadPanel.imageHeight);
free(resource);
}
// Main panel sprites
_vm->_sprite->loadList(_vm->getResourceDescription()->mainPanelSpritesResourceId, _mainPanel.sprites);
// Option panel sprites
_vm->_sprite->loadList(_vm->getResourceDescription()->optionPanelSpritesResourceId, _optionPanel.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);
2005-07-29 17:58:00 +00:00
_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;
2005-05-28 11:06:55 +00:00
_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;
2005-05-28 11:06:55 +00:00
_optionSaveFileTop = 0;
_optionSaveFileTitleNumber = 0;
2005-05-28 11:06:55 +00:00
_inventory = (uint16 *)calloc(_inventorySize, sizeof(uint16));
if (_inventory == NULL) {
error("Interface::Interface(): not enough memory");
}
_textInput = false;
_statusTextInput = false;
_statusTextInputState = kStatusTextInputFirstRun;
_disableAbortSpeeches = false;
}
Interface::~Interface(void) {
free(_inventory);
2005-07-29 17:58:00 +00:00
_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 || _panelMode == kPanelChapterSelection) {
if (_vm->getGameId() != GID_IHNM_DEMO)
_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);
2005-07-29 17:58:00 +00:00
_savedMode = _panelMode;
debug(1, "rememberMode(%d)", _savedMode);
}
void Interface::restoreMode(bool draw_) {
assert (_savedMode != -1);
debug(1, "restoreMode(%d)", _savedMode);
_panelMode = _savedMode;
_savedMode = -1;
if (draw_)
draw();
}
void Interface::setMode(int mode) {
debug(1, "Interface::setMode %i", mode);
if (mode == kPanelMain) {
_inMainMode = true;
if (_vm->getGameId() != GID_IHNM_DEMO)
_saveReminderState = 1; //TODO: blinking timeout
} else if (mode == kPanelChapterSelection) {
if (_vm->getGameId() != GID_IHNM_DEMO)
_saveReminderState = 1;
} else if (mode == kPanelNull) {
if (_vm->getGameId() == GID_IHNM_DEMO)
_inMainMode = true;
} else {
if (mode == kPanelConverse) {
_inMainMode = false;
2005-07-29 17:58:00 +00:00
}
_saveReminderState = 0;
}
_panelMode = mode;
2005-07-29 17:58:00 +00:00
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;
break;
case kPanelMap:
mapPanelShow();
break;
case kPanelSceneSubstitute:
2005-07-29 17:42:33 +00:00
_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;
break;
}
draw();
}
bool Interface::processAscii(uint16 ascii) {
// 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 (_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
2005-05-28 11:06:55 +00:00
ascii = 'c'; //continue
}
for (i = 0; i < _optionPanel.buttonsCount; i++) {
panelButton = &_optionPanel.buttons[i];
2005-06-10 13:49:43 +00:00
if (panelButton->type == kPanelButtonOption) {
2005-05-28 11:06:55 +00:00
if (panelButton->ascii == ascii) {
setOption(panelButton);
2005-05-23 18:53:36 +00:00
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];
2005-06-10 13:49:43 +00:00
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];
2005-06-10 13:49:43 +00:00
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];
2005-05-28 11:06:55 +00:00
if (panelButton->ascii == ascii) {
if (panelButton->type == kPanelButtonVerb) {
_vm->_script->setVerb(panelButton->id);
2005-07-29 17:58:00 +00:00
}
if (panelButton->type == kPanelButtonArrow) {
inventoryChangePos(panelButton->id);
2005-07-29 17:58:00 +00:00
}
return true;
}
}
2005-05-28 11:06:55 +00:00
if (ascii == 15) // ctrl-o
{
if (_saveReminderState > 0) {
setMode(kPanelOption);
return true;
}
}
break;
case kPanelConverse:
2005-05-28 11:06:55 +00:00
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':
2005-05-28 11:06:55 +00:00
converseSetPos(ascii);
break;
case '5':
case '6':
case '7':
case '8':
case '9':
if (_vm->getGameType() == GType_IHNM)
converseSetPos(ascii);
break;
}
2005-07-06 17:07:58 +00:00
break;
case kPanelMap:
mapPanelClean();
break;
case kPanelSceneSubstitute:
if (ascii == 13) {
2005-07-29 17:42:33 +00:00
_vm->_render->clearFlag(RF_DEMO_SUBST);
_vm->_gfx->setPalette(_mapSavedPal);
setMode(kPanelMain);
2005-07-29 17:42:33 +00:00
_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;
}
void Interface::setStatusText(const char *text, int statusColor) {
// Disable the status text in IHNM when the chapter is 8
if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 8)
return;
// Disable the status text in the IHNM demo
if (_vm->getGameId() == GID_IHNM_DEMO)
return;
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;
2005-07-29 17:58:00 +00:00
drawStatusBar();
}
void Interface::loadScenePortraits(int resourceId) {
_scenePortraits.freeMem();
_vm->_sprite->loadList(resourceId, _scenePortraits);
}
void Interface::drawVerbPanel(Surface *backBuffer, PanelButton* panelButton) {
PanelButton * rightButtonVerbPanelButton;
PanelButton * currentVerbPanelButton;
2005-11-26 12:08:05 +00:00
KnownColor textColor;
int spriteNumber;
Point point;
rightButtonVerbPanelButton = getPanelButtonByVerbType(_vm->_script->getRightButtonVerb());
currentVerbPanelButton = getPanelButtonByVerbType(_vm->_script->getCurrentVerb());
if (panelButton->state) {
2005-11-26 12:08:05 +00:00
textColor = kKnownColorVerbTextActive;
2005-07-17 13:36:38 +00:00
} else if (panelButton == rightButtonVerbPanelButton) {
2005-11-26 12:08:05 +00:00
textColor = kKnownColorVerbTextActive;
} else {
2005-11-26 12:08:05 +00:00
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);
2005-11-26 12:08:05 +00:00
drawVerbPanelText(backBuffer, panelButton, textColor, kKnownColorVerbTextShadow);
}
void Interface::draw() {
Surface *backBuffer;
int i;
Point leftPortraitPoint;
2005-07-29 17:58:00 +00:00
Point rightPortraitPoint;
Rect rect;
backBuffer = _vm->_gfx->getBackBuffer();
if (_vm->_scene->isInIntro() || _fadeMode == kFadeOut)
return;
drawStatusBar();
if (_panelMode == kPanelMain || _panelMode == kPanelMap ||
(_panelMode == kPanelNull && _vm->getGameId() == GID_IHNM_DEMO)) {
2005-07-29 17:58:00 +00:00
_mainPanel.getRect(rect);
backBuffer->blit(rect, _mainPanel.image);
for (i = 0; i < kVerbTypeIdsMax; i++) {
if (_verbTypeToPanelButton[i] != NULL) {
drawVerbPanel(backBuffer, _verbTypeToPanelButton[i]);
}
}
2005-07-29 17:58:00 +00:00
} else if (_panelMode == kPanelConverse) {
2005-07-17 13:36:38 +00:00
_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 ||
(_panelMode == kPanelNull && _vm->getGameId() == GID_IHNM_DEMO)) {
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);
}
2005-05-28 11:06:55 +00:00
void Interface::calcOptionSaveSlider() {
int totalFiles = _vm->getSaveFilesCount();
2005-07-29 17:58:00 +00:00
int visibleFiles = _vm->getDisplayInfo().optionSaveFileVisible;
2005-05-28 11:06:55 +00:00
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;
KnownColor textShadowKnownColor = kKnownColorVerbTextShadow;
KnownFont textFont = kKnownFontMedium;
// 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;
if (_vm->getGameType() == GType_ITE) {
text = _vm->getTextString(panelButton->id);
textFont = kKnownFontMedium;
textShadowKnownColor = kKnownColorVerbTextShadow;
} else {
if (panelButton->id < 39 || panelButton->id > 50) {
// Read non-hardcoded strings from the LUT string table, loaded from the game
// data files
text = _vm->_script->_mainStrings.getString(IHNMTextStringIdsLUT[panelButton->id]);
} else {
// Hardcoded strings in IHNM are read from the ITE hardcoded strings
text = _vm->getTextString(panelButton->id);
}
textFont = kKnownFontVerb;
textShadowKnownColor = kKnownColorTransparent;
}
panel->calcPanelButtonRect(panelButton, rect);
if (panelButton->xOffset < 0) {
if (_vm->getGameType() == GType_ITE)
textWidth = _vm->_font->getStringWidth(kKnownFontMedium, text, 0, kFontNormal);
else
textWidth = _vm->_font->getStringWidth(kKnownFontVerb, text, 0, kFontNormal);
rect.left += 2 + (panel->imageWidth - 1 - textWidth) / 2;
}
textPoint.x = rect.left;
textPoint.y = rect.top + 1;
2005-07-29 17:58:00 +00:00
_vm->_font->textDraw(textFont, ds, text, textPoint, _vm->KnownColor2ColorId(kKnownColorVerbText), _vm->KnownColor2ColorId(textShadowKnownColor), kFontShadow);
}
void Interface::drawOption() {
2005-05-28 11:06:55 +00:00
const char *text;
Surface *backBuffer;
int i;
2005-05-28 11:06:55 +00:00
int fontHeight;
uint j, idx;
int fgColor;
int bgColor;
Rect rect;
Rect rect2;
2005-05-23 18:53:36 +00:00
PanelButton *panelButton;
Point textPoint;
Point point;
int spritenum = 0;
backBuffer = _vm->_gfx->getBackBuffer();
_optionPanel.getRect(rect);
backBuffer->blit(rect, _optionPanel.image);
2005-07-29 17:58:00 +00:00
for (i = 0; i < _optionPanel.buttonsCount; i++) {
2005-05-23 18:53:36 +00:00
panelButton = &_optionPanel.buttons[i];
2005-06-10 13:49:43 +00:00
if (panelButton->type == kPanelButtonOption) {
if (_vm->getGameType() == GType_ITE) {
drawPanelButtonText(backBuffer, &_optionPanel, panelButton);
} else {
drawPanelButtonText(backBuffer, &_optionPanel, panelButton, spritenum);
spritenum += 2; // 2 sprites per button (lit and unlit)
}
2005-07-29 17:58:00 +00:00
}
2005-05-28 11:06:55 +00:00
if (panelButton->type == kPanelButtonOptionText) {
2005-07-29 17:58:00 +00:00
drawPanelText(backBuffer, &_optionPanel, panelButton);
}
}
2005-05-28 11:06:55 +00:00
2005-06-10 13:49:43 +00:00
if (_optionSaveRectTop.height() > 0) {
if (_vm->getGameType() == GType_ITE)
backBuffer->drawRect(_optionSaveRectTop, kITEColorDarkGrey);
}
2005-07-29 17:58:00 +00:00
drawButtonBox(backBuffer, _optionSaveRectSlider, kSlider, _optionSaveFileSlider->state > 0);
2005-05-28 11:06:55 +00:00
2005-06-10 13:49:43 +00:00
if (_optionSaveRectBottom.height() > 0) {
backBuffer->drawRect(_optionSaveRectBottom, kITEColorDarkGrey);
2005-05-28 11:06:55 +00:00
}
_optionPanel.calcPanelButtonRect(_optionSaveFilePanel, rect);
rect.top++;
2005-05-28 11:06:55 +00:00
rect2 = rect;
2005-11-19 12:41:23 +00:00
fontHeight = _vm->_font->getHeight(kKnownFontSmall);
2005-05-28 11:06:55 +00:00
for (j = 0; j < _vm->getDisplayInfo().optionSaveFileVisible; j++) {
bgColor = kITEColorDarkGrey0C;
fgColor = kITEColorBrightWhite;
2005-07-29 17:58:00 +00:00
2005-05-28 11:06:55 +00:00
idx = j + _optionSaveFileTop;
if (idx == _optionSaveFileTitleNumber) {
SWAP(bgColor, fgColor);
}
if (idx < _vm->getSaveFilesCount()) {
2005-05-28 11:06:55 +00:00
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;
if (_vm->getGameType() == GType_ITE)
_vm->_font->textDraw(kKnownFontSmall, backBuffer, text, textPoint, fgColor, 0, kFontNormal);
else
_vm->_font->textDraw(kKnownFontVerb, backBuffer, text, textPoint, fgColor, 0, kFontNormal);
2005-05-28 11:06:55 +00:00
}
}
}
void Interface::drawQuit() {
Surface *backBuffer;
Rect rect;
2005-05-23 18:53:36 +00:00
int i;
PanelButton *panelButton;
backBuffer = _vm->_gfx->getBackBuffer();
_quitPanel.getRect(rect);
if (_vm->getGameType() == GType_ITE)
drawButtonBox(backBuffer, rect, kButton, false);
else
backBuffer->blit(rect, _quitPanel.image);
2005-07-29 17:58:00 +00:00
for (i = 0; i < _quitPanel.buttonsCount; i++) {
panelButton = &_quitPanel.buttons[i];
2005-06-10 13:49:43 +00:00
if (panelButton->type == kPanelButtonQuit) {
drawPanelButtonText(backBuffer, &_quitPanel, panelButton);
2005-07-29 17:58:00 +00:00
}
2005-06-10 13:49:43 +00:00
if (panelButton->type == kPanelButtonQuitText) {
drawPanelText(backBuffer, &_quitPanel, panelButton);
2005-07-29 17:58:00 +00:00
}
}
}
void Interface::handleQuitUpdate(const Point& mousePoint) {
bool releasedButton;
2005-07-29 17:58:00 +00:00
_quitPanel.currentButton = quitHitTest(mousePoint);
releasedButton = (_quitPanel.currentButton != NULL) && (_quitPanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
if (!_vm->mouseButtonPressed()) {
_quitPanel.zeroAllButtonState();
}
if (releasedButton) {
2005-07-29 17:58:00 +00:00
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;
2005-05-28 11:06:55 +00:00
Rect rect;
int i;
PanelButton *panelButton;
backBuffer = _vm->_gfx->getBackBuffer();
_loadPanel.getRect(rect);
if (_vm->getGameType() == GType_ITE)
drawButtonBox(backBuffer, rect, kButton, false);
else
backBuffer->blit(rect, _loadPanel.image);
2005-07-29 17:58:00 +00:00
for (i = 0; i < _loadPanel.buttonsCount; i++) {
panelButton = &_loadPanel.buttons[i];
2005-06-10 13:49:43 +00:00
if (panelButton->type == kPanelButtonLoad) {
drawPanelButtonText(backBuffer, &_loadPanel, panelButton);
2005-07-29 17:58:00 +00:00
}
2005-06-10 13:49:43 +00:00
if (panelButton->type == kPanelButtonLoadText) {
drawPanelText(backBuffer, &_loadPanel, panelButton);
2005-07-29 17:58:00 +00:00
}
}
}
void Interface::handleLoadUpdate(const Point& mousePoint) {
bool releasedButton;
2005-07-29 17:58:00 +00:00
_loadPanel.currentButton = loadHitTest(mousePoint);
releasedButton = (_loadPanel.currentButton != NULL) && (_loadPanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
if (!_vm->mouseButtonPressed()) {
_loadPanel.zeroAllButtonState();
}
if (releasedButton) {
2005-07-29 17:58:00 +00:00
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) {
2005-07-29 17:58:00 +00:00
case kTextOK:
setMode(kPanelMain);
break;
}
}
void Interface::processStatusTextInput(uint16 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;
}
2005-07-29 17:58:00 +00:00
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;
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) {
2005-07-29 17:58:00 +00:00
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:
2005-07-29 17:58:00 +00:00
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);
}
2005-07-29 17:58:00 +00:00
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);
2005-07-29 17:58:00 +00:00
rect.left += 4;
rect.top += 4;
2005-11-19 12:41:23 +00:00
rect.setHeight(_vm->_font->getHeight(kKnownFontSmall));
2005-07-29 17:58:00 +00:00
i = 0;
while ((ch[0] = _textInputString[i++]) != 0) {
rect.setWidth(_vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal));
if ((i == _textInputPos) && _textInput) {
2005-07-29 17:58:00 +00:00
fgColor = kITEColorBlack;
ds->fillRect(rect, kITEColorWhite);
} else {
2005-07-29 17:58:00 +00:00
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);
if (_vm->getGameType() == GType_ITE)
drawButtonBox(backBuffer, rect, kButton, false);
else
backBuffer->blit(rect, _savePanel.image);
2005-07-29 17:58:00 +00:00
for (i = 0; i < _savePanel.buttonsCount; i++) {
panelButton = &_savePanel.buttons[i];
2005-06-10 13:49:43 +00:00
if (panelButton->type == kPanelButtonSave) {
drawPanelButtonText(backBuffer, &_savePanel, panelButton);
2005-07-29 17:58:00 +00:00
}
2005-06-10 13:49:43 +00:00
if (panelButton->type == kPanelButtonSaveText) {
drawPanelText(backBuffer, &_savePanel, panelButton);
2005-07-29 17:58:00 +00:00
}
}
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;
2005-07-29 17:58:00 +00:00
_savePanel.currentButton = saveHitTest(mousePoint);
validateSaveButtons();
2005-07-29 17:58:00 +00:00
releasedButton = (_savePanel.currentButton != NULL) &&
(_savePanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
if (!_vm->mouseButtonPressed()) {
_savePanel.zeroAllButtonState();
}
if (releasedButton) {
2005-07-29 17:58:00 +00:00
setSave(_savePanel.currentButton);
}
}
void Interface::handleSaveClick(const Point& mousePoint) {
_savePanel.currentButton = saveHitTest(mousePoint);
2005-07-29 17:58:00 +00:00
validateSaveButtons();
2005-07-29 17:58:00 +00:00
_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;
2005-07-29 17:58:00 +00:00
Rect rect;
int totalFiles = _vm->getSaveFilesCount();
2005-07-29 17:58:00 +00:00
int visibleFiles = _vm->getDisplayInfo().optionSaveFileVisible;
bool releasedButton;
2005-07-29 17:58:00 +00:00
2005-05-28 11:06:55 +00:00
if (_vm->mouseButtonPressed()) {
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);
2005-05-28 11:06:55 +00:00
calcOptionSaveSlider();
}
}
2005-07-29 17:58:00 +00:00
_optionPanel.currentButton = optionHitTest(mousePoint);
validateOptionButtons();
releasedButton = (_optionPanel.currentButton != NULL) && (_optionPanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
2005-05-23 18:53:36 +00:00
if (!_vm->mouseButtonPressed()) {
_optionPanel.zeroAllButtonState();
2005-05-23 18:53:36 +00:00
}
2005-05-28 11:06:55 +00:00
if (releasedButton) {
2005-07-29 17:58:00 +00:00
setOption(_optionPanel.currentButton);
2005-05-23 18:53:36 +00:00
}
}
void Interface::handleOptionClick(const Point& mousePoint) {
2005-05-28 11:06:55 +00:00
Rect rect;
_optionPanel.currentButton = optionHitTest(mousePoint);
validateOptionButtons();
_optionPanel.zeroAllButtonState();
2005-05-23 18:53:36 +00:00
if (_optionPanel.currentButton == NULL) {
return;
}
2005-07-29 17:58:00 +00:00
if (_optionPanel.currentButton == _optionSaveFileSlider) {
2005-05-28 11:06:55 +00:00
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()) {
2005-05-28 11:06:55 +00:00
_optionSaveFileMouseOff = mousePoint.y - _optionSaveRectSlider.top;
_optionPanel.currentButton->state = 1;
}
}
}
_optionSaveFileTop = clamp(0, _optionSaveFileTop, _vm->getSaveFilesCount() - _vm->getDisplayInfo().optionSaveFileVisible);
2005-05-28 11:06:55 +00:00
calcOptionSaveSlider();
} else {
if (_optionPanel.currentButton == _optionSaveFilePanel) {
_optionPanel.calcPanelButtonRect(_optionSaveFilePanel, rect);
2005-11-19 12:41:23 +00:00
_optionSaveFileTitleNumber = (mousePoint.y - rect.top) / (_vm->_font->getHeight(kKnownFontSmall) + 1);
2005-07-29 17:58:00 +00:00
2005-05-28 11:06:55 +00:00
if (_optionSaveFileTitleNumber >= _vm->getDisplayInfo().optionSaveFileVisible) {
_optionSaveFileTitleNumber = _vm->getDisplayInfo().optionSaveFileVisible - 1;
}
_optionSaveFileTitleNumber += _optionSaveFileTop;
if (_optionSaveFileTitleNumber >= _vm->getSaveFilesCount()) {
_optionSaveFileTitleNumber = _vm->getSaveFilesCount() - 1;
2005-05-28 11:06:55 +00:00
}
} 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;
2005-08-10 14:11:22 +00:00
Event event;
switch (objectTypeId(obj)) {
case kGameObjectHitZone:
hitZone = _vm->_scene->_actionMap->getHitZone(objectIdToIndex(obj));
if (hitZone == NULL)
return;
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;
2005-05-28 11:06:55 +00:00
switch (panelButton->id) {
case kTextContinuePlaying:
ConfMan.flushToDisk();
if (!(_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 8))
setMode(kPanelMain);
else
setMode(kPanelChapterSelection);
break;
case kTextQuitGame:
setMode(kPanelQuit);
break;
case kTextLoad:
if (_vm->getSaveFilesCount() > 0) {
if (_vm->isSaveListFull() || (_optionSaveFileTitleNumber > 0)) {
debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
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.setBool("subtitles", _vm->_subtitlesEnabled);
} else {
_vm->_readingSpeed = (_vm->_readingSpeed + 1) % 4;
_vm->setTalkspeed(_vm->_readingSpeed);
}
break;
case kTextMusic:
_vm->_musicVolume = (_vm->_musicVolume + 1) % 11;
_vm->_music->setVolume(_vm->_musicVolume == 10 ? -1 : _vm->_musicVolume * 25, 1);
ConfMan.setInt("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.setInt("sfx_volume", _vm->_soundVolume * 25);
break;
case kTextVoices:
if (_vm->_subtitlesEnabled && _vm->_voicesEnabled) { // Both
_vm->_subtitlesEnabled = false; // Set it to "Audio"
_vm->_voicesEnabled = true; // Not necessary, just for completeness
} else if (!_vm->_subtitlesEnabled && _vm->_voicesEnabled) {
_vm->_subtitlesEnabled = true; // Set it to "Text"
_vm->_voicesEnabled = false;
} else if (_vm->_subtitlesEnabled && !_vm->_voicesEnabled) {
_vm->_subtitlesEnabled = true; // Set it to "Both"
_vm->_voicesEnabled = true;
}
ConfMan.setBool("subtitles", _vm->_subtitlesEnabled);
ConfMan.setBool("voices", _vm->_voicesEnabled);
break;
}
}
void Interface::update(const Point& mousePoint, int updateFlag) {
2005-07-29 17:58:00 +00:00
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()) {
2005-07-29 17:58:00 +00:00
_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) {
2005-07-29 17:42:33 +00:00
_vm->_render->clearFlag(RF_DEMO_SUBST);
_vm->_gfx->setPalette(_mapSavedPal);
setMode(kPanelMain);
2005-07-29 17:42:33 +00:00
_vm->_script->setNoPendingVerb();
}
break;
case kPanelChapterSelection:
if (updateFlag & UPDATE_MOUSEMOVE) {
handleChapterSelectionUpdate(mousePoint);
} else {
if (updateFlag & UPDATE_MOUSECLICK) {
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);
else
handleChapterSelectionClick(mousePoint);
}
}
break;
case kPanelProtect:
// No mouse interaction
break;
}
_lastMousePoint = mousePoint;
}
void Interface::drawStatusBar() {
Surface *backBuffer;
Rect rect;
Point textPoint;
int stringWidth;
int color;
// Disable the status text in IHNM when the chapter is 8
if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 8)
return;
backBuffer = _vm->_gfx->getBackBuffer();
2004-05-01 09:37:24 +00:00
// 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;
if (_vm->getGameType() == GType_ITE)
_vm->_font->textDraw(kKnownFontSmall, backBuffer, _statusText, textPoint, color, 0, kFontNormal);
else
_vm->_font->textDraw(kKnownFontVerb, backBuffer, _statusText, textPoint, color, 0, kFontNormal);
if (_saveReminderState > 0) {
rect.left = _vm->getDisplayInfo().saveReminderXOffset;
rect.top = _vm->getDisplayInfo().saveReminderYOffset;
2005-07-29 17:58:00 +00:00
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();
}
2005-07-29 17:58:00 +00:00
}
} 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) {
2005-07-29 17:58:00 +00:00
setVerbState(panelButton->id, 1);
}
}
2005-07-29 17:58:00 +00:00
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);
2005-07-29 17:58:00 +00:00
bool changed = false;
if ((panelButton != NULL) && (panelButton->type == kPanelButtonArrow)) {
if (panelButton->state == 1) {
//TODO: insert timeout catchup
inventoryChangePos(panelButton->id);
}
changed = true;
} else {
2005-07-29 17:58:00 +00:00
_vm->_script->whichObject(mousePoint);
}
changed = changed || (panelButton != _mainPanel.currentButton);
_mainPanel.currentButton = panelButton;
if (changed) {
draw();
2005-07-29 17:58:00 +00:00
}
}
//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)
2005-07-29 17:58:00 +00:00
_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;
}
2005-07-29 17:58:00 +00:00
_inventoryEnd = (_inventoryCount - 1 - cols) / cols * cols;
if (_inventoryEnd < 0) {
_inventoryEnd = 0;
2005-07-29 17:58:00 +00:00
}
}
void Interface::addToInventory(int objectId) {
if (_inventoryCount >= _inventorySize) {
return;
}
2005-07-29 17:58:00 +00:00
for (int i = _inventoryCount; i > 0; i--) {
_inventory[i] = _inventory[i - 1];
}
_inventory[0] = objectId;
_inventoryCount++;
_inventoryPos = 0;
updateInventory(0);
2005-07-17 13:36:38 +00:00
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) {
2005-07-29 17:58:00 +00:00
drawPanelButtonArrow(backBuffer, &_mainPanel, _inventoryUpButton);
}
if (_inventoryStart != _inventoryEnd) {
2005-07-29 17:58:00 +00:00
drawPanelButtonArrow(backBuffer, &_mainPanel, _inventoryDownButton);
}
for (i = 0; i < _mainPanel.buttonsCount; i++) {
if (_mainPanel.buttons[i].type != kPanelButtonInventory) {
continue;
}
_mainPanel.calcPanelButtonRect(&_mainPanel.buttons[i], rect);
if (_vm->getGameType() == GType_ITE)
backBuffer->drawRect(rect, kITEColorDarkGrey);
else
backBuffer->drawRect(rect, kIHNMColorBlack);
2005-07-29 17:58:00 +00:00
if (ci < _inventoryCount) {
obj = _vm->_actor->getObj(_inventory[ci]);
_vm->_sprite->draw(backBuffer, _vm->getDisplayClip(), _vm->_sprite->_inventorySprites, obj->_spriteListResourceId, rect, 256);
}
2005-07-29 17:58:00 +00:00
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;
2005-07-29 17:58:00 +00:00
}
panelButton->state = state;
draw();
}
2005-07-29 17:58:00 +00:00
void Interface::drawButtonBox(Surface *ds, const Rect& rect, ButtonKind kind, bool down) {
2005-05-28 11:06:55 +00:00
byte cornerColor;
byte frameColor;
byte fillColor;
byte solidColor;
byte odl, our, idl, iur;
switch (kind ) {
case kSlider:
cornerColor = 0x8b;
frameColor = _vm->KnownColor2ColorId(kKnownColorBlack);
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 = (_vm->getGameType() == GType_ITE) ? kITEColorBlack : kIHNMColorBlack;
solidColor = fillColor = kITEColorLightBlue96;
odl = kITEColorDarkBlue8a;
our = kITEColorLightBlue94;
idl = 0x97;
iur = 0x95;
if (down) {
SWAP(odl, our);
SWAP(idl, iur);
}
break;
2005-05-28 11:06:55 +00:00
}
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 + w - 2, frameColor);
ds->hLine(x + 1, ye, x + w - 2, frameColor);
ds->vLine(x, y + 1, y + h - 2, frameColor);
ds->vLine(xe, y + 1, y + 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 - 2, 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 - 2, 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);
2005-05-28 11:06:55 +00:00
ds->fillRect(fill, solidColor);
2005-05-22 12:21:16 +00:00
}
static const int readingSpeeds[] = { kTextClick, kTextSlow, kTextMid, kTextFast };
void Interface::drawPanelButtonText(Surface *ds, InterfacePanel *panel, PanelButton *panelButton, int spritenum) {
const char *text;
2005-05-28 11:06:55 +00:00
int textId;
int textWidth;
int textHeight;
Point point;
Point texturePoint;
2005-11-26 12:08:05 +00:00
KnownColor textColor;
2005-05-22 12:21:16 +00:00
Rect rect;
int litButton = 0;
KnownColor textShadowKnownColor = kKnownColorVerbTextShadow;
KnownFont textFont = kKnownFontMedium;
2005-05-28 11:06:55 +00:00
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;
case kTextVoices:
if (_vm->_subtitlesEnabled && _vm->_voicesEnabled)
textId = kTextBoth;
else if (_vm->_subtitlesEnabled && !_vm->_voicesEnabled)
textId = kTextText;
else if (!_vm->_subtitlesEnabled && _vm->_voicesEnabled)
textId = kTextAudio;
break;
2005-05-28 11:06:55 +00:00
}
if (_vm->getGameType() == GType_ITE) {
text = _vm->getTextString(textId);
textFont = kKnownFontMedium;
textShadowKnownColor = kKnownColorVerbTextShadow;
textWidth = _vm->_font->getStringWidth(kKnownFontMedium, text, 0, kFontNormal);
textHeight = _vm->_font->getHeight(kKnownFontMedium);
} else {
if (textId < 39 || textId > 50) {
// Read non-hardcoded strings from the LUT string table, loaded from the game
// data files
text = _vm->_script->_mainStrings.getString(IHNMTextStringIdsLUT[textId]);
} else {
// Hardcoded strings in IHNM are read from the ITE hardcoded strings
text = _vm->getTextString(textId);
}
textFont = kKnownFontVerb;
textShadowKnownColor = kKnownColorTransparent;
textWidth = _vm->_font->getStringWidth(kKnownFontVerb, text, 0, kFontNormal);
textHeight = _vm->_font->getHeight(kKnownFontVerb);
}
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) {
2005-11-26 12:08:05 +00:00
textColor = kKnownColorVerbTextActive;
} else {
2005-11-26 12:08:05 +00:00
textColor = kKnownColorVerbText;
}
panel->calcPanelButtonRect(panelButton, rect);
if (_vm->getGameType() == GType_ITE) {
drawButtonBox(ds, rect, kButton, panelButton->state > 0);
} else {
litButton = panelButton->state > 0;
if (panel == &_optionPanel) {
texturePoint.x = _optionPanel.x + panelButton->xOffset;
texturePoint.y = _optionPanel.y + panelButton->yOffset;
_vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, spritenum + 2 + litButton, texturePoint, 256);
} else if (panel == &_quitPanel) {
texturePoint.x = _quitPanel.x + panelButton->xOffset;
texturePoint.y = _quitPanel.y + panelButton->yOffset;
_vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, 14 + litButton, texturePoint, 256);
} else if (panel == &_savePanel) {
texturePoint.x = _savePanel.x + panelButton->xOffset;
texturePoint.y = _savePanel.y + panelButton->yOffset;
_vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, 14 + litButton, texturePoint, 256);
} else if (panel == &_loadPanel) {
texturePoint.x = _loadPanel.x + panelButton->xOffset;
texturePoint.y = _loadPanel.y + panelButton->yOffset;
_vm->_sprite->draw(ds, _vm->getDisplayClip(), _optionPanel.sprites, 14 + litButton, texturePoint, 256);
} else {
// revert to default behavior
drawButtonBox(ds, rect, kButton, panelButton->state > 0);
}
}
2005-05-22 12:21:16 +00:00
_vm->_font->textDraw(textFont, ds, text, point,
_vm->KnownColor2ColorId(textColor), _vm->KnownColor2ColorId(textShadowKnownColor), 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;
}
2005-07-29 17:58:00 +00:00
point.x = panel->x + panelButton->xOffset;
point.y = panel->y + panelButton->yOffset;
if (_vm->getGameType() == GType_ITE)
_vm->_sprite->draw(ds, _vm->getDisplayClip(), _vm->_sprite->_mainSprites, spriteNumber, point, 256);
else
_vm->_sprite->draw(ds, _vm->getDisplayClip(), _vm->_sprite->_arrowSprites, spriteNumber, point, 256);
}
2005-11-26 12:08:05 +00:00
void Interface::drawVerbPanelText(Surface *ds, PanelButton *panelButton, KnownColor textKnownColor, KnownColor textShadowKnownColor) {
const char *text;
int textWidth;
Point point;
int textId;
2005-07-29 17:58:00 +00:00
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);
2005-11-26 12:08:05 +00:00
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;
}
2005-11-26 12:08:05 +00:00
_vm->_font->textDraw(kKnownFontVerb, ds, text, point, _vm->KnownColor2ColorId(textKnownColor),_vm->KnownColor2ColorId(textShadowKnownColor), (textShadowKnownColor != kKnownColorTransparent) ? kFontShadow : kFontNormal);
}
2005-07-29 17:58:00 +00:00
// 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 strId, 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 (_vm->getGameType() == GType_ITE) {
if ((c == ' ' || c == '\0') && (_vm->_font->getStringWidth(kKnownFontSmall, _converseWorkString, i, kFontNormal) <= _vm->getDisplayInfo().converseMaxTextWidth))
break;
} else {
if ((c == ' ' || c == '\0') && (_vm->_font->getStringWidth(kKnownFontVerb, _converseWorkString, i, kFontNormal) <= _vm->getDisplayInfo().converseMaxTextWidth))
break;
2005-07-29 17:58:00 +00:00
}
}
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].strId = strId;
_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++;
2005-07-29 17:58:00 +00:00
if (len == i)
break;
strncpy(_converseWorkString, &_converseWorkString[i + 1], len - i);
}
_converseStrCount++;
return false;
}
void Interface::converseDisplayText() {
2005-07-29 17:58:00 +00:00
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] = {
2005-07-29 17:58:00 +00:00
(char)0xb7, 0
};
Rect rect(8, _vm->getDisplayInfo().converseTextLines * _vm->getDisplayInfo().converseTextHeight);
Point textPoint;
2005-07-29 17:58:00 +00:00
assert(_conversePanel.buttonsCount >= 6);
if (_vm->getGameType() == GType_ITE) {
bulletForegnd = kITEColorGreen;
bulletBackgnd = kITEColorBlack;
} else {
bulletForegnd = kITEColorBrightWhite;
bulletBackgnd = kIHNMColorBlack;
bullet[0] = '>'; // different bullet in IHNM
}
2005-07-29 17:58:00 +00:00
rect.moveTo(_conversePanel.x + _conversePanel.buttons[0].xOffset,
_conversePanel.y + _conversePanel.buttons[0].yOffset);
if (_vm->getGameType() == GType_ITE)
ds->drawRect(rect, kITEColorDarkGrey); //fill bullet place
else
ds->drawRect(rect, kIHNMColorBlack); //fill bullet place
2005-07-29 17:58:00 +00:00
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) {
if (_vm->getGameType() == GType_ITE) {
foregnd = kITEColorBrightWhite;
backgnd = (!_vm->leftMouseButtonPressed()) ? kITEColorDarkGrey : kITEColorGrey;
} else {
foregnd = kIHNMColorRed;
backgnd = (!_vm->leftMouseButtonPressed()) ? kIHNMColorRed : kIHNMColorRed;
}
} else {
if (_vm->getGameType() == GType_ITE) {
foregnd = kITEColorBlue;
backgnd = kITEColorDarkGrey;
} else {
foregnd = kITEColorBrightWhite;
backgnd = kIHNMColorBlack;
}
}
_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;
if (_vm->getGameType() == GType_ITE)
_vm->_font->textDraw(kKnownFontSmall, ds, bullet, textPoint, bulletForegnd, bulletBackgnd, (FontEffectFlags)(kFontShadow | kFontDontmap));
else
_vm->_font->textDraw(kKnownFontVerb, ds, bullet, textPoint, bulletForegnd, bulletBackgnd, (FontEffectFlags)(kFontShadow | kFontDontmap));
}
textPoint.x = rect.left + 1;
textPoint.y = rect.top;
if (_vm->getGameType() == GType_ITE)
_vm->_font->textDraw(kKnownFontSmall, ds, str, textPoint, foregnd, kITEColorBlack, kFontShadow);
else
_vm->_font->textDraw(kKnownFontVerb, ds, str, textPoint, foregnd, kIHNMColorBlack, 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->strId, 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;
2005-07-29 17:58:00 +00:00
if (!_vm->mouseButtonPressed()) { // remove pressed flag
if (_converseUpButton) {
_converseUpButton->state = 0;
_converseDownButton->state = 0;
}
}
_conversePanel.currentButton = converseHitTest(mousePoint);
changed = last != _conversePanel.currentButton;
2005-07-29 17:58:00 +00:00
if (_conversePanel.currentButton == NULL) {
_conversePos = -1;
if (changed) {
draw();
}
return;
}
if (_conversePanel.currentButton->type == kPanelButtonConverseText) {
converseSetTextLines(_conversePanel.currentButton->id);
}
2005-07-29 17:58:00 +00:00
if (_conversePanel.currentButton->type == kPanelButtonArrow) {
if (_conversePanel.currentButton->state == 1) {
//TODO: insert timeout catchup
converseChangePos(_conversePanel.currentButton->id);
}
draw();
2005-07-29 17:58:00 +00:00
}
}
void Interface::handleConverseClick(const Point& mousePoint) {
_conversePanel.currentButton = converseHitTest(mousePoint);
if (_conversePanel.currentButton == NULL) {
return;
}
if (_conversePanel.currentButton->type == kPanelButtonConverseText) {
2005-05-28 11:06:55 +00:00
converseSetPos(_conversePanel.currentButton->ascii);
}
if (_conversePanel.currentButton->type == kPanelButtonArrow) {
_conversePanel.currentButton->state = 1;
converseChangePos(_conversePanel.currentButton->id);
2005-07-29 17:58:00 +00:00
}
}
2005-05-23 18:53:36 +00:00
void Interface::saveState(Common::OutSaveFile *out) {
out->writeUint16LE(_inventoryCount);
for (int i = 0; i < _inventoryCount; i++) {
2005-05-23 18:53:36 +00:00
out->writeUint16LE(_inventory[i]);
}
}
2005-05-23 18:53:36 +00:00
void Interface::loadState(Common::InSaveFile *in) {
_inventoryCount = in->readUint16LE();
for (int i = 0; i < _inventoryCount; i++) {
2005-05-23 18:53:36 +00:00
_inventory[i] = in->readUint16LE();
}
2005-07-29 17:58:00 +00:00
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++;
2005-07-29 17:58:00 +00:00
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