Hooked up the pathfinder so that it seems to work. Animation opcode 0x12.
[scummvm-innocent.git] / engines / saga / interface.cpp
blobe6755c6dc047a9f2f9567c5a00880e63bbf896d0
1 /* ScummVM - Graphic Adventure Engine
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * $URL$
22 * $Id$
26 // Game interface module
27 #include "saga/saga.h"
29 #include "saga/gfx.h"
30 #include "saga/actor.h"
31 #include "saga/console.h"
32 #include "saga/displayinfo.h"
33 #include "saga/events.h"
34 #include "saga/font.h"
35 #include "saga/objectmap.h"
36 #include "saga/isomap.h"
37 #include "saga/itedata.h"
38 #include "saga/music.h"
39 #include "saga/puzzle.h"
40 #include "saga/render.h"
41 #include "saga/scene.h"
42 #include "saga/script.h"
43 #include "saga/sound.h"
44 #include "saga/sprite.h"
45 #include "saga/resource.h"
47 #include "saga/interface.h"
49 #include "common/config-manager.h"
50 #include "common/system.h"
51 #include "common/timer.h"
53 namespace Saga {
55 static const int verbToTextIdITE[] = {
56 kTextWalkTo, kTextLookAt, kTextPickUp, kTextTalkTo,
57 kTextOpen, kTextClose, kTextUse, kTextGive
60 // This maps the internally used string ITE IDs to the LUT strings loaded in IHNM
61 // i.e. id 12 (quit game button) maps to string 14 (Quit game)
62 // The comments are what the actual IHNM string is
63 // For the text string IDs, refer to saga.h, enum TextStringIds
64 static const int IHNMTextStringIdsLUT[56] = {
65 -1, // (Empty)
66 -1, // (Empty)
67 4, // Take
68 6, // Talk to
69 -1,
70 -1,
71 5, // Use
72 8, // Give
73 10, // Options
74 11, // Test
75 12, // Demo
76 13, // Help
77 14, // Quit Game
78 16, // Fast
79 18, // Slow
80 20, // On
81 21, // Off
82 15, // Continue Playing
83 22, // Load
84 23, // Save
85 24, // Game Options
86 25, // Reading Speed
87 26, // Music
88 27, // Sound
89 32, // Cancel
90 33, // Quit
91 34, // OK
92 17, // Mid
93 19, // Click
94 36, // 10%
95 37, // 20%
96 38, // 30%
97 39, // 40%
98 40, // 50%
99 41, // 60%
100 42, // 70%
101 43, // 80%
102 44, // 90%
103 45, // Max
117 28, // Voices
118 29, // Text
119 30, // Audio
120 31 // Both
123 #define buttonRes0 0x42544E00
124 #define buttonRes1 0x42544E01
126 Interface::Interface(SagaEngine *vm) : _vm(vm) {
127 byte *resource;
128 size_t resourceLength;
129 int i;
131 #if 0
132 // FTA2 related test code
134 // TODO: this will probably have to be moved to a new class
135 // It's left here for now till the code differences are figured out
136 if (_vm->getGameId() == GID_FTA2) {
137 _interfaceContext = _vm->_resource->getContext(GAME_IMAGEFILE);
138 _vm->_resource->loadResource(_interfaceContext, 22, resource, resourceLength); // Julian's portrait
140 _vm->decodeBGImage(resource, resourceLength, &_mainPanel.image,
141 &_mainPanel.imageLength, &_mainPanel.imageWidth, &_mainPanel.imageHeight);
143 free(resource);
144 return;
146 #endif
148 // Load interface module resource file context
149 _interfaceContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
150 if (_interfaceContext == NULL) {
151 error("Interface::Interface() resource context not found");
154 // Do nothing for SAGA2 games for now
155 if (_vm->isSaga2()) {
156 return;
159 // Main panel
160 _mainPanel.buttons = _vm->getDisplayInfo().mainPanelButtons;
161 _mainPanel.buttonsCount = _vm->getDisplayInfo().mainPanelButtonsCount;
163 for (i = 0; i < kVerbTypeIdsMax; i++) {
164 _verbTypeToPanelButton[i] = NULL;
167 for (i = 0; i < _mainPanel.buttonsCount; i++) {
168 if (_mainPanel.buttons[i].type == kPanelButtonVerb) {
169 _verbTypeToPanelButton[_mainPanel.buttons[i].id] = &_mainPanel.buttons[i];
173 _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->mainPanelResourceId, resource, resourceLength);
174 _vm->decodeBGImage(resource, resourceLength, &_mainPanel.image,
175 &_mainPanel.imageLength, &_mainPanel.imageWidth, &_mainPanel.imageHeight);
177 free(resource);
179 // Converse panel
180 _conversePanel.buttons = _vm->getDisplayInfo().conversePanelButtons;
181 _conversePanel.buttonsCount = _vm->getDisplayInfo().conversePanelButtonsCount;
183 _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->conversePanelResourceId, resource, resourceLength);
184 _vm->decodeBGImage(resource, resourceLength, &_conversePanel.image,
185 &_conversePanel.imageLength, &_conversePanel.imageWidth, &_conversePanel.imageHeight);
186 free(resource);
188 // Option panel
189 if (!(_vm->getFeatures() & GF_NON_INTERACTIVE)) {
190 _optionPanel.buttons = _vm->getDisplayInfo().optionPanelButtons;
191 _optionPanel.buttonsCount = _vm->getDisplayInfo().optionPanelButtonsCount;
193 _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->optionPanelResourceId, resource, resourceLength);
194 _vm->decodeBGImage(resource, resourceLength, &_optionPanel.image,
195 &_optionPanel.imageLength, &_optionPanel.imageWidth, &_optionPanel.imageHeight);
196 free(resource);
197 } else {
198 _optionPanel.buttons = NULL;
199 _optionPanel.buttonsCount = 0;
200 _optionPanel.sprites.spriteCount = 0;
203 #ifdef ENABLE_IHNM
204 // Quit panel
205 if (_vm->getGameId() == GID_IHNM) {
206 _quitPanel.buttons = _vm->getDisplayInfo().quitPanelButtons;
207 _quitPanel.buttonsCount = _vm->getDisplayInfo().quitPanelButtonsCount;
209 _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resource, resourceLength);
210 _vm->decodeBGImage(resource, resourceLength, &_quitPanel.image,
211 &_quitPanel.imageLength, &_quitPanel.imageWidth, &_quitPanel.imageHeight);
212 free(resource);
215 // Save panel
216 if (_vm->getGameId() == GID_IHNM) {
217 _savePanel.buttons = _vm->getDisplayInfo().savePanelButtons;
218 _savePanel.buttonsCount = _vm->getDisplayInfo().savePanelButtonsCount;
220 _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resource, resourceLength);
221 _vm->decodeBGImage(resource, resourceLength, &_savePanel.image,
222 &_savePanel.imageLength, &_savePanel.imageWidth, &_savePanel.imageHeight);
223 free(resource);
226 // Load panel
227 if (_vm->getGameId() == GID_IHNM) {
228 _loadPanel.buttons = _vm->getDisplayInfo().loadPanelButtons;
229 _loadPanel.buttonsCount = _vm->getDisplayInfo().loadPanelButtonsCount;
231 _vm->_resource->loadResource(_interfaceContext, _vm->getResourceDescription()->warningPanelResourceId, resource, resourceLength);
232 _vm->decodeBGImage(resource, resourceLength, &_loadPanel.image,
233 &_loadPanel.imageLength, &_loadPanel.imageWidth, &_loadPanel.imageHeight);
234 free(resource);
236 #endif
238 // Main panel sprites
239 _vm->_sprite->loadList(_vm->getResourceDescription()->mainPanelSpritesResourceId, _mainPanel.sprites);
240 if (!(_vm->getFeatures() & GF_NON_INTERACTIVE)) {
241 // Option panel sprites
242 _vm->_sprite->loadList(_vm->getResourceDescription()->optionPanelSpritesResourceId, _optionPanel.sprites);
243 // Save panel sprites
244 _vm->_sprite->loadList(_vm->getResourceDescription()->warningPanelSpritesResourceId, _savePanel.sprites);
245 // Load panel sprites
246 _vm->_sprite->loadList(_vm->getResourceDescription()->warningPanelSpritesResourceId, _loadPanel.sprites);
247 // Quit panel sprites
248 _vm->_sprite->loadList(_vm->getResourceDescription()->warningPanelSpritesResourceId, _quitPanel.sprites);
251 if (_vm->getGameId() == GID_ITE) {
252 _vm->_sprite->loadList(_vm->getResourceDescription()->defaultPortraitsResourceId, _defPortraits);
255 setPortraitBgColor(0, 0, 0);
257 _mainPanel.x = _vm->getDisplayInfo().mainPanelXOffset;
258 _mainPanel.y = _vm->getDisplayInfo().mainPanelYOffset;
259 _mainPanel.currentButton = NULL;
260 _inventoryUpButton = _mainPanel.getButton(_vm->getDisplayInfo().inventoryUpButtonIndex);
261 _inventoryDownButton = _mainPanel.getButton(_vm->getDisplayInfo().inventoryDownButtonIndex);
263 _conversePanel.x = _vm->getDisplayInfo().conversePanelXOffset;
264 _conversePanel.y = _vm->getDisplayInfo().conversePanelYOffset;
265 _conversePanel.currentButton = NULL;
266 _converseUpButton = _conversePanel.getButton(_vm->getDisplayInfo().converseUpButtonIndex);
267 _converseDownButton = _conversePanel.getButton(_vm->getDisplayInfo().converseDownButtonIndex);
269 _leftPortrait = 0;
270 _rightPortrait = 0;
272 _optionPanel.x = _vm->getDisplayInfo().optionPanelXOffset;
273 _optionPanel.y = _vm->getDisplayInfo().optionPanelYOffset;
274 _optionPanel.currentButton = NULL;
275 _optionSaveFileSlider = _optionPanel.getButton(_vm->getDisplayInfo().optionSaveFileSliderIndex);
276 _optionSaveFilePanel = _optionPanel.getButton(_vm->getDisplayInfo().optionSaveFilePanelIndex);
278 _quitPanel.x = _vm->getDisplayInfo().quitPanelXOffset;
279 _quitPanel.y = _vm->getDisplayInfo().quitPanelYOffset;
280 _quitPanel.imageWidth = _vm->getDisplayInfo().quitPanelWidth;
281 _quitPanel.imageHeight = _vm->getDisplayInfo().quitPanelHeight;
282 _quitPanel.buttons = _vm->getDisplayInfo().quitPanelButtons;
283 _quitPanel.buttonsCount = _vm->getDisplayInfo().quitPanelButtonsCount;
284 _quitPanel.currentButton = NULL;
286 _loadPanel.x = _vm->getDisplayInfo().loadPanelXOffset;
287 _loadPanel.y = _vm->getDisplayInfo().loadPanelYOffset;
288 _loadPanel.imageWidth = _vm->getDisplayInfo().loadPanelWidth;
289 _loadPanel.imageHeight = _vm->getDisplayInfo().loadPanelHeight;
290 _loadPanel.buttons = _vm->getDisplayInfo().loadPanelButtons;
291 _loadPanel.buttonsCount = _vm->getDisplayInfo().loadPanelButtonsCount;
292 _loadPanel.currentButton = NULL;
294 _savePanel.x = _vm->getDisplayInfo().savePanelXOffset;
295 _savePanel.y = _vm->getDisplayInfo().savePanelYOffset;
296 _savePanel.imageWidth = _vm->getDisplayInfo().savePanelWidth;
297 _savePanel.imageHeight = _vm->getDisplayInfo().savePanelHeight;
298 _savePanel.buttons = _vm->getDisplayInfo().savePanelButtons;
299 _savePanel.buttonsCount = _vm->getDisplayInfo().savePanelButtonsCount;
300 _saveEdit = _savePanel.getButton(_vm->getDisplayInfo().saveEditIndex);
301 _savePanel.currentButton = NULL;
303 _protectPanel.x = _vm->getDisplayInfo().protectPanelXOffset;
304 _protectPanel.y = _vm->getDisplayInfo().protectPanelYOffset;
305 _protectPanel.imageWidth = _vm->getDisplayInfo().protectPanelWidth;
306 _protectPanel.imageHeight = _vm->getDisplayInfo().protectPanelHeight;
307 _protectPanel.buttons = _vm->getDisplayInfo().protectPanelButtons;
308 _protectPanel.buttonsCount = _vm->getDisplayInfo().protectPanelButtonsCount;
309 _protectEdit = _protectPanel.getButton(_vm->getDisplayInfo().protectEditIndex);
310 _protectPanel.currentButton = NULL;
312 _active = true;
313 _panelMode = _lockedMode = kPanelNull;
314 _savedMode = -1;
315 _bossMode = -1;
316 _fadeMode = kNoFade;
317 _inMainMode = false;
318 *_statusText = 0;
319 _statusOnceColor = -1;
321 _inventoryCount = 0;
322 _inventoryPos = 0;
323 _inventoryStart = 0;
324 _inventoryEnd = 0;
325 _inventoryBox = 0;
326 _inventorySize = ITE_INVENTORY_SIZE;
327 _saveReminderState = 0;
329 _optionSaveFileTop = 0;
330 _optionSaveFileTitleNumber = 0;
332 _inventory = (uint16 *)calloc(_inventorySize, sizeof(uint16));
333 if (_inventory == NULL) {
334 error("Interface::Interface(): not enough memory");
337 _textInput = false;
338 _statusTextInput = false;
339 _statusTextInputState = kStatusTextInputFirstRun;
341 _disableAbortSpeeches = false;
343 // set save game reminder alarm
344 _vm->getTimerManager()->installTimerProc(&saveReminderCallback, TIMETOSAVE, this);
347 Interface::~Interface(void) {
348 free(_inventory);
350 free(_mainPanel.image);
351 free(_conversePanel.image);
352 free(_optionPanel.image);
353 free(_quitPanel.image);
354 free(_loadPanel.image);
355 free(_savePanel.image);
357 _mainPanel.sprites.freeMem();
358 _conversePanel.sprites.freeMem();
359 _optionPanel.sprites.freeMem();
360 _quitPanel.sprites.freeMem();
361 _loadPanel.sprites.freeMem();
362 _savePanel.sprites.freeMem();
363 _protectPanel.sprites.freeMem();
365 _defPortraits.freeMem();
366 _scenePortraits.freeMem();
369 void Interface::saveReminderCallback(void *refCon) {
370 ((Interface *)refCon)->updateSaveReminder();
373 void Interface::updateSaveReminder() {
374 if (_active && _panelMode == kPanelMain) {
375 _saveReminderState = _saveReminderState % _vm->getDisplayInfo().saveReminderNumSprites + 1;
376 drawStatusBar();
377 _vm->getTimerManager()->removeTimerProc(&saveReminderCallback);
378 _vm->getTimerManager()->installTimerProc(&saveReminderCallback, ((_vm->getGameId() == GID_ITE) ? TIMETOBLINK_ITE : TIMETOBLINK_IHNM), this);
382 int Interface::activate() {
383 if (!_active) {
384 _active = true;
385 _vm->_script->_skipSpeeches = false;
386 _vm->_actor->_protagonist->_targetObject = ID_NOTHING;
387 unlockMode();
388 if (_panelMode == kPanelMain || _panelMode == kPanelChapterSelection) {
389 _saveReminderState = 1;
390 } else if (_panelMode == kPanelNull && _vm->getFeatures() & GF_IHNM_DEMO) {
391 _saveReminderState = 1;
393 _vm->_gfx->showCursor(true);
394 draw();
395 _vm->_render->setFullRefresh(true);
398 return SUCCESS;
401 int Interface::deactivate() {
402 if (_active) {
403 _active = false;
404 lockMode();
405 setMode(kPanelNull);
407 _vm->_gfx->showCursor(false);
409 return SUCCESS;
412 void Interface::rememberMode() {
413 debug(1, "rememberMode(%d)", _panelMode);
415 _savedMode = _panelMode;
418 void Interface::restoreMode(bool draw_) {
419 debug(1, "restoreMode(%d)", _savedMode);
421 // If _savedMode is -1 by a race condition, set it to kPanelMain
422 if (_savedMode == -1)
423 _savedMode = kPanelMain;
425 _panelMode = _savedMode;
426 _savedMode = -1;
428 if (draw_)
429 draw();
432 void Interface::setMode(int mode) {
433 debug(1, "Interface::setMode %i", mode);
435 if (mode == kPanelMain) {
436 _inMainMode = true;
437 _saveReminderState = 1;
438 } else if (mode == kPanelChapterSelection) {
439 _saveReminderState = 1;
440 } else if (mode == kPanelNull) {
441 if (_vm->getFeatures() & GF_IHNM_DEMO) {
442 _inMainMode = true;
443 _saveReminderState = 1;
445 } else if (mode == kPanelOption) {
446 // Show the cursor if it's hidden
447 _vm->_gfx->showCursor(true);
448 } else {
449 if (mode == kPanelConverse) {
450 _inMainMode = false;
453 _saveReminderState = 0;
456 _panelMode = mode;
458 switch (_panelMode) {
459 case kPanelMain:
460 // FIXME: Implement IHNM differences from ExecuteInventoryPanel for IHNM (though I believe they're already
461 // implemented)
463 _mainPanel.currentButton = NULL;
464 break;
465 case kPanelConverse:
466 _conversePanel.currentButton = NULL;
467 converseDisplayText();
468 break;
469 case kPanelOption:
470 _optionPanel.currentButton = NULL;
471 _vm->fillSaveList();
472 calcOptionSaveSlider();
473 if (_optionSaveFileTitleNumber >= _vm->getDisplayInfo().optionSaveFileVisible) {
474 _optionSaveFileTitleNumber = _vm->getDisplayInfo().optionSaveFileVisible - 1;
476 break;
477 case kPanelLoad:
478 _loadPanel.currentButton = NULL;
479 break;
480 case kPanelQuit:
481 _quitPanel.currentButton = NULL;
482 break;
483 case kPanelSave:
484 _savePanel.currentButton = NULL;
485 _textInputMaxWidth = _saveEdit->width - 10;
486 _textInput = true;
487 _textInputStringLength = strlen(_textInputString);
488 _textInputPos = _textInputStringLength + 1;
489 break;
490 case kPanelMap:
491 mapPanelShow();
492 break;
493 case kPanelSceneSubstitute:
494 _vm->_render->setFlag(RF_DEMO_SUBST);
495 _vm->_gfx->getCurrentPal(_mapSavedPal);
496 break;
497 case kPanelChapterSelection:
498 break;
499 case kPanelBoss:
500 _vm->_render->setFlag(RF_DEMO_SUBST);
501 break;
502 case kPanelProtect:
503 if (_vm->getGameId() == GID_ITE) {
504 // This is used as the copy protection panel in ITE
505 _protectPanel.currentButton = NULL;
506 _textInputMaxWidth = _protectEdit->width - 10;
507 _textInput = true;
508 _textInputString[0] = 0;
509 _textInputStringLength = 0;
510 _textInputPos = _textInputStringLength + 1;
511 } else {
512 // In the IHNM demo, this panel mode is set by the scripts
513 // to flip through the pages of the help system
515 break;
518 draw();
519 _vm->_render->setFullRefresh(true);
522 bool Interface::processAscii(Common::KeyState keystate) {
523 // TODO: Checking for Esc and Enter below is a bit hackish, and
524 // probably only works with the English version. Maybe we should
525 // add a flag to the button so it can indicate if it's the default
526 // or cancel button?
527 uint16 ascii = keystate.ascii;
528 int i;
529 PanelButton *panelButton;
530 if (_statusTextInput) {
531 processStatusTextInput(keystate);
532 return true;
535 switch (_panelMode) {
536 case kPanelNull:
537 if (keystate.keycode == Common::KEYCODE_ESCAPE) {
538 if (_vm->_scene->isInIntro()) {
539 _vm->_scene->skipScene();
540 } else {
541 if (!_disableAbortSpeeches)
542 _vm->_actor->abortAllSpeeches();
544 return true;
547 if (_vm->_scene->isNonInteractiveIHNMDemoPart())
548 _vm->_scene->showIHNMDemoSpecialScreen();
549 break;
550 case kPanelCutaway:
551 if (keystate.keycode == Common::KEYCODE_ESCAPE) {
552 if (!_disableAbortSpeeches)
553 _vm->_actor->abortAllSpeeches();
554 _vm->_scene->cutawaySkip();
555 return true;
558 if (_vm->_scene->isNonInteractiveIHNMDemoPart())
559 _vm->_scene->showIHNMDemoSpecialScreen();
560 break;
561 case kPanelVideo:
562 if (keystate.keycode == Common::KEYCODE_ESCAPE) {
563 if (_vm->_scene->isInIntro()) {
564 _vm->_scene->skipScene();
565 } else {
566 if (!_disableAbortSpeeches)
567 _vm->_actor->abortAllSpeeches();
569 _vm->_scene->cutawaySkip();
570 return true;
573 if (_vm->_scene->isNonInteractiveIHNMDemoPart())
574 _vm->_scene->showIHNMDemoSpecialScreen();
575 break;
576 case kPanelOption:
577 // TODO: check input dialog keys
578 if (keystate.keycode == Common::KEYCODE_ESCAPE || keystate.keycode == Common::KEYCODE_RETURN) { // Esc or Enter
579 ascii = 'c'; //continue
582 for (i = 0; i < _optionPanel.buttonsCount; i++) {
583 panelButton = &_optionPanel.buttons[i];
584 if (panelButton->type == kPanelButtonOption) {
585 if (panelButton->ascii == ascii) {
586 setOption(panelButton);
587 return true;
591 break;
592 case kPanelSave:
593 if (_textInput && processTextInput(keystate)) {
594 return true;
597 if (keystate.keycode == Common::KEYCODE_ESCAPE) {
598 ascii = 'c'; // cancel
599 } else if (keystate.keycode == Common::KEYCODE_RETURN) { // Enter
600 ascii = 's'; // save
603 for (i = 0; i < _savePanel.buttonsCount; i++) {
604 panelButton = &_savePanel.buttons[i];
605 if (panelButton->type == kPanelButtonSave) {
606 if (panelButton->ascii == ascii) {
607 setSave(panelButton);
608 return true;
612 break;
613 case kPanelQuit:
614 if (keystate.keycode == Common::KEYCODE_ESCAPE) {
615 ascii = 'c'; // cancel
616 } else if (keystate.keycode == Common::KEYCODE_RETURN) { // Enter
617 ascii = 'q'; // quit
620 for (i = 0; i < _quitPanel.buttonsCount; i++) {
621 panelButton = &_quitPanel.buttons[i];
622 if (panelButton->type == kPanelButtonQuit) {
623 if (panelButton->ascii == ascii) {
624 setQuit(panelButton);
625 return true;
629 break;
630 case kPanelLoad:
631 for (i = 0; i < _loadPanel.buttonsCount; i++) {
632 panelButton = &_loadPanel.buttons[i];
633 if (panelButton->type == kPanelButtonLoad) {
634 if (panelButton->ascii == ascii) {
635 setLoad(panelButton);
636 return true;
640 break;
641 case kPanelMain:
642 for (i = 0; i < _mainPanel.buttonsCount; i++) {
643 panelButton = &_mainPanel.buttons[i];
644 if (panelButton->ascii == ascii) {
645 if (panelButton->type == kPanelButtonVerb) {
646 _vm->_script->setVerb(panelButton->id);
648 if (panelButton->type == kPanelButtonArrow) {
649 inventoryChangePos(panelButton->id);
651 return true;
654 if (keystate.keycode == Common::KEYCODE_o && keystate.flags == Common::KBD_CTRL) { // ctrl-o
655 if (_saveReminderState > 0) {
656 setMode(kPanelOption);
657 return true;
660 break;
661 case kPanelConverse:
662 switch (ascii) {
663 case 'x':
664 setMode(kPanelMain);
665 if (_vm->_scene->isITEPuzzleScene())
666 _vm->_puzzle->exitPuzzle();
667 break;
669 case 'u':
670 converseChangePos(-1);
671 break;
673 case 'd':
674 converseChangePos(1);
675 break;
677 case '1':
678 case '2':
679 case '3':
680 case '4':
681 case '5':
682 case '6':
683 case '7':
684 case '8':
685 case '9':
686 converseSetPos(ascii);
687 break;
689 break;
690 case kPanelMap:
691 mapPanelClean();
692 break;
693 case kPanelSceneSubstitute:
694 if (keystate.keycode == Common::KEYCODE_RETURN) {
695 _vm->_render->clearFlag(RF_DEMO_SUBST);
696 _vm->_gfx->setPalette(_mapSavedPal);
697 setMode(kPanelMain);
698 _vm->_script->setNoPendingVerb();
699 } else if (ascii == 'q' || ascii == 'Q') {
700 _vm->quitGame();
702 break;
703 case kPanelBoss:
704 _vm->_render->clearFlag(RF_DEMO_SUBST);
705 keyBossExit();
706 break;
707 case kPanelProtect:
708 if (_vm->getGameId() == GID_ITE) {
709 if (_textInput && processTextInput(keystate)) {
710 return true;
713 if (keystate.keycode == Common::KEYCODE_ESCAPE || keystate.keycode == Common::KEYCODE_RETURN) {
714 _vm->_script->wakeUpThreads(kWaitTypeRequest);
715 _vm->_interface->setMode(kPanelMain);
717 _protectHash = 0;
719 for (char *p = _textInputString; *p; p++)
720 _protectHash = (_protectHash << 1) + toupper(*p);
722 } else {
723 // In the IHNM demo, this panel mode is set by the scripts
724 // to flip through the pages of the help system
726 break;
727 case kPanelPlacard:
728 #ifdef ENABLE_IHNM
729 if (_vm->getGameId() == GID_IHNM) {
730 // Any keypress here returns the user back to the game
731 if (!(_vm->getFeatures() & GF_IHNM_DEMO)) {
732 _vm->_scene->clearPsychicProfile();
733 } else {
734 setMode(kPanelConverse);
735 _vm->_scene->_textList.clear();
736 _vm->_script->wakeUpThreads(kWaitTypeDelay);
739 #endif
740 break;
742 return false;
745 void Interface::setStatusText(const char *text, int statusColor) {
746 if (_vm->getGameId() == GID_IHNM) {
747 // Don't show the status text for the IHNM chapter selection screens (chapter 8), or
748 // scene 0 (IHNM demo introduction)
749 if (_vm->_scene->currentChapterNumber() == 8 || _vm->_scene->currentSceneNumber() == 0)
750 return;
753 assert(text != NULL);
754 assert(strlen(text) < STATUS_TEXT_LEN);
756 if (_vm->_render->getFlags() & RF_MAP || _vm->_interface->getMode() == kPanelPlacard)
757 return;
759 strncpy(_statusText, text, STATUS_TEXT_LEN);
760 _statusOnceColor = statusColor;
761 drawStatusBar();
764 void Interface::loadScenePortraits(int resourceId) {
765 _scenePortraits.freeMem();
767 _vm->_sprite->loadList(resourceId, _scenePortraits);
770 void Interface::drawVerbPanel(PanelButton* panelButton) {
771 PanelButton * rightButtonVerbPanelButton;
772 PanelButton * currentVerbPanelButton;
773 KnownColor textColor;
774 int spriteNumber;
775 Point point;
777 rightButtonVerbPanelButton = getPanelButtonByVerbType(_vm->_script->getRightButtonVerb());
778 currentVerbPanelButton = getPanelButtonByVerbType(_vm->_script->getCurrentVerb());
780 if (panelButton->state) {
781 textColor = kKnownColorVerbTextActive;
782 } else if (panelButton == rightButtonVerbPanelButton) {
783 textColor = kKnownColorVerbTextActive;
784 } else {
785 textColor = kKnownColorVerbText;
788 if (panelButton == currentVerbPanelButton) {
789 spriteNumber = panelButton->downSpriteNumber;
790 } else {
791 spriteNumber = panelButton->upSpriteNumber;
793 point.x = _mainPanel.x + panelButton->xOffset;
794 point.y = _mainPanel.y + panelButton->yOffset;
796 _vm->_sprite->draw(_mainPanel.sprites, spriteNumber, point, 256);
798 drawVerbPanelText(panelButton, textColor, kKnownColorVerbTextShadow);
801 void Interface::draw() {
802 Point leftPortraitPoint;
803 Point rightPortraitPoint;
804 Rect rect;
806 if (_vm->_scene->isInIntro() || _fadeMode == kFadeOut)
807 return;
809 drawStatusBar();
811 if (_panelMode == kPanelMain || _panelMode == kPanelMap ||
812 (_panelMode == kPanelNull && _vm->getFeatures() & GF_IHNM_DEMO)) {
813 _mainPanel.getRect(rect);
814 _vm->_gfx->drawRegion(rect, _mainPanel.image);
816 for (int i = 0; i < kVerbTypeIdsMax; i++) {
817 if (_verbTypeToPanelButton[i] != NULL) {
818 drawVerbPanel(_verbTypeToPanelButton[i]);
821 } else if (_panelMode == kPanelConverse) {
822 _conversePanel.getRect(rect);
823 _vm->_gfx->drawRegion(rect, _conversePanel.image);
824 converseDisplayTextLines();
827 if (_panelMode == kPanelMain || _panelMode == kPanelConverse ||
828 _lockedMode == kPanelMain || _lockedMode == kPanelConverse ||
829 (_panelMode == kPanelNull && _vm->getFeatures() & GF_IHNM_DEMO)) {
830 leftPortraitPoint.x = _mainPanel.x + _vm->getDisplayInfo().leftPortraitXOffset;
831 leftPortraitPoint.y = _mainPanel.y + _vm->getDisplayInfo().leftPortraitYOffset;
832 _vm->_sprite->draw(_defPortraits, _leftPortrait, leftPortraitPoint, 256);
835 if (!_inMainMode && _vm->getDisplayInfo().rightPortraitXOffset >= 0) { //FIXME: should we change !_inMainMode to _panelMode == kPanelConverse ?
836 rightPortraitPoint.x = _mainPanel.x + _vm->getDisplayInfo().rightPortraitXOffset;
837 rightPortraitPoint.y = _mainPanel.y + _vm->getDisplayInfo().rightPortraitYOffset;
839 // This looks like hack - particularly since it's only done for
840 // the right-side portrait - and perhaps it is! But as far as I
841 // can tell this is what the original engine does. And it keeps
842 // ITE from crashing when entering the Elk King's court.
844 if (_rightPortrait >= _scenePortraits.spriteCount)
845 _rightPortrait = 0;
847 _vm->_sprite->draw(_scenePortraits, _rightPortrait, rightPortraitPoint, 256);
850 drawInventory();
853 void Interface::calcOptionSaveSlider() {
854 int totalFiles = _vm->getSaveFilesCount();
855 int visibleFiles = _vm->getDisplayInfo().optionSaveFileVisible;
856 int height = _optionSaveFileSlider->height;
857 int sliderHeight = 13; // IHNM's save file list slider has a fixed height
858 int pos;
860 if (totalFiles < visibleFiles) {
861 totalFiles = visibleFiles;
864 if (_vm->getGameId() == GID_ITE) {
865 // ITE's save file list slider has a dynamically computed height, depending on
866 // the number of save games
867 sliderHeight = visibleFiles * height / totalFiles;
870 if (sliderHeight < 7) {
871 sliderHeight = 7;
874 if (totalFiles - visibleFiles <= 0) {
875 pos = 0;
876 } else {
877 pos = _optionSaveFileTop * (height - sliderHeight) / (totalFiles - visibleFiles);
879 _optionPanel.calcPanelButtonRect(_optionSaveFileSlider, _optionSaveRectTop);
880 _optionSaveRectBottom = _optionSaveRectSlider = _optionSaveRectTop;
882 _optionSaveRectTop.bottom = _optionSaveRectTop.top + pos;
883 _optionSaveRectTop.top++;
884 _optionSaveRectTop.right--;
886 _optionSaveRectSlider.top = _optionSaveRectTop.bottom;
887 _optionSaveRectSlider.bottom = _optionSaveRectSlider.top + sliderHeight;
889 _optionSaveRectBottom.top = _optionSaveRectSlider.bottom;
890 _optionSaveRectBottom.right--;
893 void Interface::drawPanelText(InterfacePanel *panel, PanelButton *panelButton) {
894 const char *text;
895 int textWidth;
896 Rect rect;
897 Point textPoint;
898 KnownColor textShadowKnownColor = kKnownColorVerbTextShadow;
899 KnownFont textFont = kKnownFontMedium;
901 // Button differs for CD version
902 if (panelButton->id == kTextReadingSpeed && _vm->getGameId() == GID_ITE && !(_vm->getFeatures() & GF_ITE_FLOPPY))
903 return;
904 if (panelButton->id == kTextShowDialog && _vm->getFeatures() & GF_ITE_FLOPPY)
905 return;
907 if (_vm->getGameId() == GID_ITE) {
908 text = _vm->getTextString(panelButton->id);
909 textFont = kKnownFontMedium;
910 textShadowKnownColor = kKnownColorVerbTextShadow;
911 } else {
912 if ((panelButton->id < 39 || panelButton->id > 50) && panelButton->id != kTextLoadSavedGame) {
913 // Read non-hardcoded strings from the LUT string table, loaded from the game
914 // data files
915 text = _vm->_script->_mainStrings.getString(IHNMTextStringIdsLUT[panelButton->id]);
916 } else if (panelButton->id == kTextLoadSavedGame) {
917 // a bit of a kludge, but it will do
918 text = _vm->getTextString(52);
919 } else {
920 // Hardcoded strings in IHNM are read from the ITE hardcoded strings
921 text = _vm->getTextString(panelButton->id);
923 textFont = kKnownFontVerb;
924 textShadowKnownColor = kKnownColorTransparent;
927 panel->calcPanelButtonRect(panelButton, rect);
928 if (panelButton->xOffset < 0) {
929 if (_vm->getGameId() == GID_ITE)
930 textWidth = _vm->_font->getStringWidth(kKnownFontMedium, text, 0, kFontNormal);
931 else
932 textWidth = _vm->_font->getStringWidth(kKnownFontVerb, text, 0, kFontNormal);
933 rect.left += 2 + (panel->imageWidth - 1 - textWidth) / 2;
936 textPoint.x = rect.left;
937 textPoint.y = rect.top + 1;
939 _vm->_font->textDraw(textFont, text, textPoint,
940 _vm->KnownColor2ColorId(kKnownColorVerbText), _vm->KnownColor2ColorId(textShadowKnownColor), kFontShadow);
943 void Interface::drawOption() {
944 const char *text;
945 int fontHeight;
946 uint idx;
947 int fgColor;
948 int bgColor;
949 Rect rect;
950 Rect rect2;
951 PanelButton *panelButton;
952 Point textPoint;
953 Point point;
954 Point sliderPoint;
955 int spritenum = 0;
957 _optionPanel.getRect(rect);
958 _vm->_gfx->drawRegion(rect, _optionPanel.image);
960 for (int i = 0; i < _optionPanel.buttonsCount; i++) {
961 panelButton = &_optionPanel.buttons[i];
963 if (panelButton->type == kPanelButtonOption) {
964 if (_vm->getGameId() == GID_ITE) {
965 drawPanelButtonText(&_optionPanel, panelButton);
966 } else {
967 drawPanelButtonText(&_optionPanel, panelButton, spritenum);
968 spritenum += 2; // 2 sprites per button (lit and unlit)
971 if (panelButton->type == kPanelButtonOptionText) {
972 drawPanelText(&_optionPanel, panelButton);
976 if (_optionSaveRectTop.height() > 0) {
977 if (_vm->getGameId() == GID_ITE)
978 _vm->_gfx->drawRect(_optionSaveRectTop, kITEColorDarkGrey);
981 if (_vm->getGameId() == GID_ITE) {
982 drawButtonBox(_optionSaveRectSlider, kSlider, _optionSaveFileSlider->state > 0);
983 } else {
984 panelButton = &_optionPanel.buttons[0];
985 sliderPoint.x = _optionPanel.x + panelButton->xOffset;
986 sliderPoint.y = _optionSaveRectSlider.top;
987 _vm->_sprite->draw(_optionPanel.sprites, 0 + _optionSaveFileSlider->state, sliderPoint, 256);
991 if (_optionSaveRectBottom.height() > 0) {
992 _vm->_gfx->drawRect(_optionSaveRectBottom, kITEColorDarkGrey);
995 _optionPanel.calcPanelButtonRect(_optionSaveFilePanel, rect);
996 rect.top++;
997 rect2 = rect;
998 fontHeight = _vm->_font->getHeight(kKnownFontSmall);
999 for (uint j = 0; j < _vm->getDisplayInfo().optionSaveFileVisible; j++) {
1000 if (_vm->getGameId() == GID_ITE)
1001 bgColor = kITEColorDarkGrey0C;
1002 else
1003 bgColor = _vm->KnownColor2ColorId(kKnownColorBlack);
1004 fgColor = kITEColorBrightWhite;
1006 idx = j + _optionSaveFileTop;
1007 if (idx == _optionSaveFileTitleNumber) {
1008 SWAP(bgColor, fgColor);
1010 if (idx < _vm->getSaveFilesCount()) {
1011 rect2.top = rect.top + j * (fontHeight + 1);
1012 rect2.bottom = rect2.top + fontHeight;
1013 _vm->_gfx->fillRect(rect2, bgColor);
1014 text = _vm->getSaveFile(idx)->name;
1015 textPoint.x = rect.left + 1;
1016 textPoint.y = rect2.top;
1017 if (_vm->getGameId() == GID_ITE)
1018 _vm->_font->textDraw(kKnownFontSmall, text, textPoint, fgColor, 0, kFontNormal);
1019 else
1020 _vm->_font->textDraw(kKnownFontVerb, text, textPoint, fgColor, 0, kFontNormal);
1026 void Interface::drawQuit() {
1027 Rect rect;
1028 int i;
1029 PanelButton *panelButton;
1031 _quitPanel.getRect(rect);
1032 if (_vm->getGameId() == GID_ITE)
1033 drawButtonBox(rect, kButton, false);
1034 else
1035 _vm->_gfx->drawRegion(rect, _quitPanel.image);
1037 for (i = 0; i < _quitPanel.buttonsCount; i++) {
1038 panelButton = &_quitPanel.buttons[i];
1039 if (panelButton->type == kPanelButtonQuit) {
1040 drawPanelButtonText(&_quitPanel, panelButton);
1042 if (panelButton->type == kPanelButtonQuitText) {
1043 drawPanelText(&_quitPanel, panelButton);
1048 void Interface::handleQuitUpdate(const Point& mousePoint) {
1049 bool releasedButton;
1051 _quitPanel.currentButton = quitHitTest(mousePoint);
1052 releasedButton = (_quitPanel.currentButton != NULL) && (_quitPanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
1054 if (!_vm->mouseButtonPressed()) {
1055 _quitPanel.zeroAllButtonState();
1058 if (releasedButton) {
1059 setQuit(_quitPanel.currentButton);
1063 void Interface::handleQuitClick(const Point& mousePoint) {
1064 _quitPanel.currentButton = quitHitTest(mousePoint);
1066 _quitPanel.zeroAllButtonState();
1068 if (_quitPanel.currentButton == NULL) {
1069 return;
1072 _quitPanel.currentButton->state = 1;
1075 void Interface::setQuit(PanelButton *panelButton) {
1076 _quitPanel.currentButton = NULL;
1077 switch (panelButton->id) {
1078 case kTextCancel:
1079 setMode(kPanelOption);
1080 break;
1081 case kTextQuit:
1082 #ifdef ENABLE_IHNM
1083 if (_vm->getFeatures() & GF_IHNM_DEMO)
1084 _vm->_scene->creditsScene(); // display sales info for IHNM demo
1085 else
1086 #endif
1087 _vm->quitGame();
1088 break;
1092 void Interface::drawLoad() {
1093 Rect rect;
1094 int i;
1095 PanelButton *panelButton;
1097 _loadPanel.getRect(rect);
1098 if (_vm->getGameId() == GID_ITE)
1099 drawButtonBox(rect, kButton, false);
1100 else
1101 _vm->_gfx->drawRegion(rect, _loadPanel.image);
1103 for (i = 0; i < _loadPanel.buttonsCount; i++) {
1104 panelButton = &_loadPanel.buttons[i];
1105 if (panelButton->type == kPanelButtonLoad) {
1106 drawPanelButtonText(&_loadPanel, panelButton);
1108 if (panelButton->type == kPanelButtonLoadText) {
1109 drawPanelText(&_loadPanel, panelButton);
1114 void Interface::handleLoadUpdate(const Point& mousePoint) {
1115 bool releasedButton;
1117 _loadPanel.currentButton = loadHitTest(mousePoint);
1118 releasedButton = (_loadPanel.currentButton != NULL) && (_loadPanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
1120 if (!_vm->mouseButtonPressed()) {
1121 _loadPanel.zeroAllButtonState();
1124 if (releasedButton) {
1125 setLoad(_loadPanel.currentButton);
1129 void Interface::handleLoadClick(const Point& mousePoint) {
1130 _loadPanel.currentButton = loadHitTest(mousePoint);
1132 _loadPanel.zeroAllButtonState();
1134 if (_loadPanel.currentButton == NULL) {
1135 return;
1138 _loadPanel.currentButton->state = 1;
1141 void Interface::setLoad(PanelButton *panelButton) {
1142 _loadPanel.currentButton = NULL;
1143 switch (panelButton->id) {
1144 case kTextOK:
1145 if (_vm->getGameId() == GID_ITE) {
1146 setMode(kPanelMain);
1147 } else {
1148 if (_vm->getSaveFilesCount() > 0) {
1149 if (_vm->isSaveListFull() || (_optionSaveFileTitleNumber > 0)) {
1150 debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
1151 setMode(kPanelMain);
1152 _vm->load(_vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber));
1153 _vm->syncSoundSettings();
1157 break;
1158 case kTextCancel:
1159 // IHNM only
1160 setMode(kPanelOption);
1161 break;
1165 void Interface::processStatusTextInput(Common::KeyState keystate) {
1167 switch (keystate.keycode) {
1168 case Common::KEYCODE_ESCAPE:
1169 _statusTextInputState = kStatusTextInputAborted;
1170 _statusTextInput = false;
1171 _vm->_script->wakeUpThreads(kWaitTypeStatusTextInput);
1172 break;
1173 case Common::KEYCODE_RETURN:
1174 _statusTextInputState = kStatusTextInputEntered;
1175 _statusTextInput = false;
1176 _vm->_script->wakeUpThreads(kWaitTypeStatusTextInput);
1177 break;
1178 case Common::KEYCODE_BACKSPACE:
1179 if (_statusTextInputPos == 0) {
1180 break;
1182 _statusTextInputPos--;
1183 _statusTextInputString[_statusTextInputPos] = 0;
1184 default:
1185 if (_statusTextInputPos >= STATUS_TEXT_INPUT_MAX) {
1186 break;
1188 if (isalnum(keystate.ascii) || (keystate.ascii == ' ')) {
1189 _statusTextInputString[_statusTextInputPos++] = keystate.ascii;
1190 _statusTextInputString[_statusTextInputPos] = 0;
1193 setStatusText(_statusTextInputString);
1196 bool Interface::processTextInput(Common::KeyState keystate) {
1197 char ch[2];
1198 char tempString[SAVE_TITLE_SIZE];
1199 uint tempWidth;
1200 memset(tempString, 0, SAVE_TITLE_SIZE);
1201 ch[1] = 0;
1202 // IHNM has a smaller save title size than ITE. We only limit the save title size during text input
1203 // in IHNM, to preserve backwards compatibility with older save games
1204 uint save_title_size = _vm->getGameId() == GID_ITE ? SAVE_TITLE_SIZE : IHNM_SAVE_TITLE_SIZE;
1206 switch (keystate.keycode) {
1207 case Common::KEYCODE_RETURN:
1208 return false;
1209 case Common::KEYCODE_ESCAPE:
1210 _textInput = false;
1211 break;
1212 case Common::KEYCODE_BACKSPACE:
1213 if (_textInputPos <= 1) {
1214 break;
1216 _textInputPos--;
1217 case Common::KEYCODE_DELETE:
1218 if (_textInputPos <= _textInputStringLength) {
1219 if (_textInputPos != 1) {
1220 strncpy(tempString, _textInputString, _textInputPos - 1);
1222 if (_textInputPos != _textInputStringLength) {
1223 strncat(tempString, &_textInputString[_textInputPos], _textInputStringLength - _textInputPos);
1225 strcpy(_textInputString, tempString);
1226 _textInputStringLength = strlen(_textInputString);
1228 break;
1229 case Common::KEYCODE_LEFT:
1230 if (_textInputPos > 1) {
1231 _textInputPos--;
1233 break;
1234 case Common::KEYCODE_RIGHT:
1235 if (_textInputPos <= _textInputStringLength) {
1236 _textInputPos++;
1238 break;
1239 case Common::KEYCODE_HOME:
1240 _textInputPos = 1;
1241 break;
1242 case Common::KEYCODE_END:
1243 _textInputPos = _textInputStringLength + 1;
1244 break;
1245 default:
1246 if (((keystate.ascii <= 255) && (isalnum(keystate.ascii))) || (keystate.ascii == ' ') ||
1247 (keystate.ascii == '-') || (keystate.ascii == '_')) {
1248 if (_textInputStringLength < save_title_size - 1) {
1249 ch[0] = keystate.ascii;
1250 tempWidth = _vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal);
1251 tempWidth += _vm->_font->getStringWidth(kKnownFontSmall, _textInputString, 0, kFontNormal);
1252 if (tempWidth > _textInputMaxWidth) {
1253 break;
1255 if (_textInputPos != 1) {
1256 strncpy(tempString, _textInputString, _textInputPos - 1);
1257 strcat(tempString, ch);
1259 if ((_textInputStringLength == 0) || (_textInputPos == 1)) {
1260 strcpy(tempString, ch);
1262 if ((_textInputStringLength != 0) && (_textInputPos != _textInputStringLength)) {
1263 strncat(tempString, &_textInputString[_textInputPos - 1], _textInputStringLength - _textInputPos + 1);
1266 strcpy(_textInputString, tempString);
1267 _textInputStringLength = strlen(_textInputString);
1268 _textInputPos++;
1271 break;
1273 return true;
1276 void Interface::drawTextInput(InterfacePanel *panel, PanelButton *panelButton) {
1277 Point textPoint;
1278 Rect rect;
1279 char ch[2];
1280 int fgColor;
1281 uint i;
1283 ch[1] = 0;
1284 panel->calcPanelButtonRect(panelButton, rect);
1285 drawButtonBox(rect, kEdit, _textInput);
1286 rect.left += 4;
1287 rect.top += 4;
1288 rect.setHeight(_vm->_font->getHeight(kKnownFontSmall));
1290 i = 0;
1291 while ((ch[0] = _textInputString[i++]) != 0) {
1292 rect.setWidth(_vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal));
1293 if ((i == _textInputPos) && _textInput) {
1294 fgColor = _vm->KnownColor2ColorId(kKnownColorBlack);
1295 _vm->_gfx->fillRect(rect, _vm->KnownColor2ColorId(kKnownColorWhite));
1296 } else {
1297 fgColor = _vm->KnownColor2ColorId(kKnownColorWhite);
1299 textPoint.x = rect.left;
1300 textPoint.y = rect.top + 1;
1302 _vm->_font->textDraw(kKnownFontSmall, ch, textPoint, fgColor, 0, kFontNormal);
1303 rect.left += rect.width();
1305 if (_textInput && (_textInputPos >= i)) {
1306 ch[0] = ' ';
1307 rect.setWidth(_vm->_font->getStringWidth(kKnownFontSmall, ch, 0, kFontNormal));
1308 _vm->_gfx->fillRect(rect, _vm->KnownColor2ColorId(kKnownColorWhite));
1312 void Interface::drawSave() {
1313 Rect rect;
1314 int i;
1315 PanelButton *panelButton;
1317 _savePanel.getRect(rect);
1318 if (_vm->getGameId() == GID_ITE)
1319 drawButtonBox(rect, kButton, false);
1320 else
1321 _vm->_gfx->drawRegion(rect, _savePanel.image);
1323 for (i = 0; i < _savePanel.buttonsCount; i++) {
1324 panelButton = &_savePanel.buttons[i];
1325 if (panelButton->type == kPanelButtonSave) {
1326 drawPanelButtonText(&_savePanel, panelButton);
1328 if (panelButton->type == kPanelButtonSaveText) {
1329 drawPanelText(&_savePanel, panelButton);
1333 drawTextInput(&_savePanel, _saveEdit);
1336 void Interface::drawProtect() {
1337 Rect rect;
1338 int i;
1339 PanelButton *panelButton;
1341 _protectPanel.getRect(rect);
1342 drawButtonBox(rect, kButton, false);
1344 for (i = 0; i < _protectPanel.buttonsCount; i++) {
1345 panelButton = &_protectPanel.buttons[i];
1346 if (panelButton->type == kPanelButtonProtectText) {
1347 drawPanelText(&_protectPanel, panelButton);
1350 drawTextInput(&_protectPanel, _protectEdit);
1353 void Interface::handleSaveUpdate(const Point& mousePoint) {
1354 bool releasedButton;
1356 _savePanel.currentButton = saveHitTest(mousePoint);
1358 validateSaveButtons();
1360 releasedButton = (_savePanel.currentButton != NULL) &&
1361 (_savePanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
1363 if (!_vm->mouseButtonPressed()) {
1364 _savePanel.zeroAllButtonState();
1367 if (releasedButton) {
1368 setSave(_savePanel.currentButton);
1372 void Interface::handleSaveClick(const Point& mousePoint) {
1373 _savePanel.currentButton = saveHitTest(mousePoint);
1375 validateSaveButtons();
1377 _savePanel.zeroAllButtonState();
1379 if (_savePanel.currentButton == NULL) {
1380 _textInput = false;
1381 return;
1384 _savePanel.currentButton->state = 1;
1385 if (_savePanel.currentButton == _saveEdit) {
1386 _textInput = true;
1390 void Interface::setSave(PanelButton *panelButton) {
1391 _savePanel.currentButton = NULL;
1392 uint titleNumber;
1393 char *fileName;
1394 switch (panelButton->id) {
1395 case kTextSave:
1396 if (_textInputStringLength == 0 ) {
1397 break;
1399 if (!_vm->isSaveListFull() && (_optionSaveFileTitleNumber == 0)) {
1400 if (_vm->locateSaveFile(_textInputString, titleNumber)) {
1401 fileName = _vm->calcSaveFileName(_vm->getSaveFile(titleNumber)->slotNumber);
1402 _vm->save(fileName, _textInputString);
1403 _optionSaveFileTitleNumber = titleNumber;
1404 } else {
1405 fileName = _vm->calcSaveFileName(_vm->getNewSaveSlotNumber());
1406 _vm->save(fileName, _textInputString);
1407 _vm->fillSaveList();
1408 calcOptionSaveSlider();
1410 } else {
1411 fileName = _vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
1412 _vm->save(fileName, _textInputString);
1414 _vm->getTimerManager()->removeTimerProc(&saveReminderCallback);
1415 _vm->getTimerManager()->installTimerProc(&saveReminderCallback, TIMETOSAVE, this);
1416 setSaveReminderState(1);
1418 _textInput = false;
1419 setMode(kPanelOption);
1420 break;
1421 case kTextCancel:
1422 _textInput = false;
1423 setMode(kPanelOption);
1424 break;
1428 void Interface::handleOptionUpdate(const Point& mousePoint) {
1429 int16 mouseY;
1430 Rect rect;
1431 int totalFiles = _vm->getSaveFilesCount();
1432 int visibleFiles = _vm->getDisplayInfo().optionSaveFileVisible;
1433 bool releasedButton;
1435 if (_vm->mouseButtonPressed()) {
1436 if (_optionSaveFileSlider->state > 0) {
1437 _optionPanel.calcPanelButtonRect(_optionSaveFileSlider, rect);
1439 mouseY = mousePoint.y - rect.top -_optionSaveFileMouseOff;
1440 if (mouseY < 0)
1441 mouseY = 0;
1443 if (totalFiles - visibleFiles <= 0) {
1444 _optionSaveFileTop = 0;
1445 } else {
1446 _optionSaveFileTop = mouseY * (totalFiles - visibleFiles) /
1447 (_optionSaveFileSlider->height - _optionSaveRectSlider.height());
1450 _optionSaveFileTop = CLIP<uint>(_optionSaveFileTop, 0, totalFiles - visibleFiles);
1451 calcOptionSaveSlider();
1455 _optionPanel.currentButton = optionHitTest(mousePoint);
1457 validateOptionButtons();
1459 releasedButton = (_optionPanel.currentButton != NULL) && (_optionPanel.currentButton->state > 0) && (!_vm->mouseButtonPressed());
1461 if (!_vm->mouseButtonPressed()) {
1462 _optionPanel.zeroAllButtonState();
1465 if (releasedButton) {
1466 setOption(_optionPanel.currentButton);
1471 void Interface::handleOptionClick(const Point& mousePoint) {
1472 Rect rect;
1473 _optionPanel.currentButton = optionHitTest(mousePoint);
1475 validateOptionButtons();
1477 _optionPanel.zeroAllButtonState();
1479 if (_optionPanel.currentButton == NULL) {
1480 return;
1483 if (_optionPanel.currentButton == _optionSaveFileSlider) {
1484 if ((_optionSaveRectTop.height() > 0) && (mousePoint.y < _optionSaveRectTop.bottom)) {
1485 _optionSaveFileTop -= _vm->getDisplayInfo().optionSaveFileVisible;
1486 } else {
1487 if ((_optionSaveRectBottom.height() > 0) && (mousePoint.y >= _optionSaveRectBottom.top)) {
1488 _optionSaveFileTop += _vm->getDisplayInfo().optionSaveFileVisible;
1489 } else {
1490 if (_vm->getDisplayInfo().optionSaveFileVisible < _vm->getSaveFilesCount()) {
1491 _optionSaveFileMouseOff = mousePoint.y - _optionSaveRectSlider.top;
1492 _optionPanel.currentButton->state = 1;
1497 _optionSaveFileTop = CLIP<uint>(_optionSaveFileTop, 0, _vm->getSaveFilesCount() - _vm->getDisplayInfo().optionSaveFileVisible);
1498 calcOptionSaveSlider();
1499 } else {
1500 if (_optionPanel.currentButton == _optionSaveFilePanel) {
1501 _optionPanel.calcPanelButtonRect(_optionSaveFilePanel, rect);
1502 _optionSaveFileTitleNumber = (mousePoint.y - rect.top) / (_vm->_font->getHeight(kKnownFontSmall) + 1);
1504 if (_optionSaveFileTitleNumber >= _vm->getDisplayInfo().optionSaveFileVisible) {
1505 _optionSaveFileTitleNumber = _vm->getDisplayInfo().optionSaveFileVisible - 1;
1507 _optionSaveFileTitleNumber += _optionSaveFileTop;
1508 if (_optionSaveFileTitleNumber >= _vm->getSaveFilesCount()) {
1509 _optionSaveFileTitleNumber = _vm->getSaveFilesCount() - 1;
1511 } else {
1512 _optionPanel.currentButton->state = 1;
1517 void Interface::handleChapterSelectionUpdate(const Point& mousePoint) {
1518 uint16 objectId;
1519 int hitZoneIndex;
1520 const HitZone * hitZone;
1522 // FIXME: Original handled more object types here.
1524 objectId = _vm->_actor->hitTest(mousePoint, true);
1526 if (objectId == ID_NOTHING) {
1527 hitZoneIndex = _vm->_scene->_objectMap->hitTest(mousePoint);
1529 if ((hitZoneIndex != -1)) {
1530 hitZone = _vm->_scene->_objectMap->getHitZone(hitZoneIndex);
1531 objectId = hitZone->getHitZoneId();
1535 if (objectId != _vm->_script->_pointerObject) {
1536 _vm->_script->_pointerObject = objectId;
1540 void Interface::handleChapterSelectionClick(const Point& mousePoint) {
1541 int obj = _vm->_script->_pointerObject;
1543 _vm->_actor->abortSpeech();
1545 if (obj) {
1546 int script = 0;
1547 HitZone *hitZone;
1548 ActorData *a;
1549 ObjectData *o;
1550 Event event;
1552 switch (objectTypeId(obj)) {
1553 case kGameObjectHitZone:
1554 hitZone = _vm->_scene->_objectMap->getHitZone(objectIdToIndex(obj));
1556 if (hitZone == NULL)
1557 return;
1559 if (hitZone->getFlags() & kHitZoneEnabled)
1560 script = hitZone->getScriptNumber();
1561 break;
1563 case kGameObjectActor:
1564 a = _vm->_actor->getActor(obj);
1565 script = a->_scriptEntrypointNumber;
1566 break;
1568 case kGameObjectObject:
1569 o = _vm->_actor->getObj(obj);
1570 script = o->_scriptEntrypointNumber;
1571 break;
1574 if (script > 0) {
1575 event.type = kEvTOneshot;
1576 event.code = kScriptEvent;
1577 event.op = kEventExecNonBlocking;
1578 event.time = 0;
1579 event.param = _vm->_scene->getScriptModuleNumber();
1580 event.param2 = script;
1581 event.param3 = _vm->_script->getVerbType(kVerbUse); // Action
1582 event.param4 = obj; // Object
1583 event.param5 = 0; // With Object
1584 event.param6 = obj; // Actor
1585 _vm->_events->queue(&event);
1590 void Interface::setOption(PanelButton *panelButton) {
1591 _optionPanel.currentButton = NULL;
1592 switch (panelButton->id) {
1593 case kTextContinuePlaying:
1594 ConfMan.flushToDisk();
1595 if (_vm->getGameId() == GID_ITE) {
1596 setMode(kPanelMain);
1597 } else {
1598 if (_vm->_scene->currentChapterNumber() == 8) {
1599 setMode(kPanelChapterSelection);
1600 } else if (_vm->_scene->isNonInteractiveIHNMDemoPart()) {
1601 setMode(kPanelNull);
1602 } else {
1603 setMode(kPanelMain);
1606 break;
1607 case kTextQuitGame:
1608 setMode(kPanelQuit);
1609 break;
1610 case kTextLoad:
1611 if (_vm->getGameId() == GID_ITE) {
1612 if (_vm->getSaveFilesCount() > 0) {
1613 if (_vm->isSaveListFull() || (_optionSaveFileTitleNumber > 0)) {
1614 debug(1, "Loading save game %d", _vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber);
1615 setMode(kPanelMain);
1616 _vm->load(_vm->calcSaveFileName(_vm->getSaveFile(_optionSaveFileTitleNumber)->slotNumber));
1617 _vm->syncSoundSettings();
1620 } else {
1621 setMode(kPanelLoad);
1623 break;
1624 case kTextSave:
1625 // Disallow saving in the non-interactive part of the IHNM demo (original demo didn't support saving at all)
1626 if (_vm->_scene->isNonInteractiveIHNMDemoPart())
1627 return;
1629 if (!_vm->isSaveListFull() && (_optionSaveFileTitleNumber == 0)) {
1630 _textInputString[0] = 0;
1631 } else {
1632 strcpy(_textInputString, _vm->getSaveFile(_optionSaveFileTitleNumber)->name);
1634 setMode(kPanelSave);
1635 break;
1636 case kTextReadingSpeed:
1637 if (_vm->getGameId() == GID_ITE && !(_vm->getFeatures() & GF_ITE_FLOPPY)) {
1638 _vm->_subtitlesEnabled = !_vm->_subtitlesEnabled;
1639 ConfMan.setBool("subtitles", _vm->_subtitlesEnabled);
1640 } else {
1641 _vm->_readingSpeed = (_vm->_readingSpeed + 1) % 4;
1642 _vm->setTalkspeed(_vm->_readingSpeed);
1644 break;
1645 case kTextMusic:
1646 _vm->_musicVolume = _vm->_musicVolume + 25;
1647 if (_vm->_musicVolume > 255) _vm->_musicVolume = 0;
1648 _vm->_music->setVolume(_vm->_musicVolume, 1);
1649 ConfMan.setInt("music_volume", _vm->_musicVolume);
1650 break;
1651 case kTextSound:
1652 _vm->_soundVolume = _vm->_soundVolume + 25;
1653 if (_vm->_soundVolume > 255) _vm->_soundVolume = 0;
1654 ConfMan.setInt("sfx_volume", _vm->_soundVolume);
1655 _vm->_sound->setVolume();
1656 break;
1657 case kTextVoices:
1658 if (_vm->_voiceFilesExist) {
1659 if (_vm->_subtitlesEnabled && _vm->_voicesEnabled) { // Both
1660 _vm->_subtitlesEnabled = false; // Set it to "Audio"
1661 _vm->_voicesEnabled = true; // Not necessary, just for completeness
1662 } else if (!_vm->_subtitlesEnabled && _vm->_voicesEnabled) {
1663 _vm->_subtitlesEnabled = true; // Set it to "Text"
1664 _vm->_voicesEnabled = false;
1665 } else if (_vm->_subtitlesEnabled && !_vm->_voicesEnabled) {
1666 _vm->_subtitlesEnabled = true; // Set it to "Both"
1667 _vm->_voicesEnabled = true;
1669 } else {
1670 _vm->_subtitlesEnabled = true; // Set it to "Text"
1671 _vm->_voicesEnabled = false;
1674 _vm->_speechVolume = _vm->_speechVolume + 25;
1675 if (_vm->_speechVolume > 255) _vm->_speechVolume = 0;
1676 ConfMan.setInt("speech_volume", _vm->_speechVolume);
1677 _vm->_sound->setVolume();
1679 ConfMan.setBool("subtitles", _vm->_subtitlesEnabled);
1680 ConfMan.setBool("voices", _vm->_voicesEnabled);
1681 break;
1685 void Interface::update(const Point& mousePoint, int updateFlag) {
1687 if (!_active && _panelMode == kPanelNull && (updateFlag & UPDATE_MOUSECLICK))
1688 _vm->_actor->abortSpeech();
1690 if (_vm->_scene->isInIntro() || _fadeMode == kFadeOut || !_active) {
1691 // When opening the psychic profile, or the options screen in the non-interactive part of the IHNM demo,
1692 // the interface is locked (_active is false)
1693 // Don't return in those cases, so that mouse actions can be processed
1694 if (_vm->getGameId() == GID_ITE) {
1695 return;
1696 } else {
1697 if (_panelMode == kPanelPlacard && (updateFlag & UPDATE_MOUSECLICK)) {
1698 // the psychic profile or the special screen in IHNM demo is open, don't return
1699 } else if (_panelMode == kPanelOption || _panelMode == kPanelQuit) {
1700 // options/quit panel is open, set interface to active and don't return
1701 _vm->_actor->abortSpeech(); // abort any speech being played
1702 _active = true;
1703 } else {
1704 return;
1709 if (_statusTextInput) {
1710 return;
1713 switch (_panelMode) {
1714 case kPanelMain:
1715 if (updateFlag & UPDATE_MOUSEMOVE) {
1716 bool lastWasPlayfield = _lastMousePoint.y < _vm->_scene->getHeight();
1717 if (mousePoint.y < _vm->_scene->getHeight()) {
1718 if (!lastWasPlayfield) {
1719 handleMainUpdate(mousePoint);
1721 _vm->_script->whichObject(mousePoint);
1722 } else {
1723 if (lastWasPlayfield) {
1724 _vm->_script->setNonPlayfieldVerb();
1726 handleMainUpdate(mousePoint);
1729 } else {
1731 if (updateFlag & UPDATE_MOUSECLICK) {
1732 if (mousePoint.y < _vm->_scene->getHeight()) {
1733 _vm->_script->playfieldClick(mousePoint, (updateFlag & UPDATE_LEFTBUTTONCLICK) != 0);
1734 } else {
1735 handleMainClick(mousePoint);
1739 break;
1741 case kPanelConverse:
1742 if (updateFlag & UPDATE_MOUSEMOVE) {
1743 handleConverseUpdate(mousePoint);
1744 } else {
1745 if (updateFlag & UPDATE_MOUSECLICK) {
1746 handleConverseClick(mousePoint);
1748 if (updateFlag & UPDATE_WHEELUP) {
1749 converseChangePos(-1);
1751 if (updateFlag & UPDATE_WHEELDOWN) {
1752 converseChangePos(1);
1755 if (_vm->_scene->isITEPuzzleScene()) {
1756 _vm->_puzzle->handleClick(mousePoint);
1759 break;
1761 case kPanelOption:
1762 if (updateFlag & UPDATE_MOUSEMOVE) {
1763 handleOptionUpdate(mousePoint);
1764 } else {
1765 if (updateFlag & UPDATE_MOUSECLICK) {
1766 handleOptionClick(mousePoint);
1768 if (updateFlag & UPDATE_WHEELUP) {
1769 if (_optionSaveFileTop)
1770 _optionSaveFileTop--;
1771 calcOptionSaveSlider();
1773 if (updateFlag & UPDATE_WHEELDOWN) {
1774 if (_optionSaveFileTop < _vm->getSaveFilesCount() - _vm->getDisplayInfo().optionSaveFileVisible)
1775 _optionSaveFileTop++;
1776 calcOptionSaveSlider();
1779 break;
1781 case kPanelQuit:
1782 if (updateFlag & UPDATE_MOUSEMOVE) {
1783 handleQuitUpdate(mousePoint);
1784 } else {
1785 if (updateFlag & UPDATE_MOUSECLICK) {
1786 handleQuitClick(mousePoint);
1789 break;
1791 case kPanelLoad:
1792 if (updateFlag & UPDATE_MOUSEMOVE) {
1794 handleLoadUpdate(mousePoint);
1796 } else {
1797 if (updateFlag & UPDATE_MOUSECLICK) {
1798 handleLoadClick(mousePoint);
1801 break;
1803 case kPanelSave:
1804 if (updateFlag & UPDATE_MOUSEMOVE) {
1806 handleSaveUpdate(mousePoint);
1808 } else {
1809 if (updateFlag & UPDATE_MOUSECLICK) {
1810 handleSaveClick(mousePoint);
1813 break;
1815 case kPanelMap:
1816 if (updateFlag & UPDATE_MOUSECLICK)
1817 mapPanelClean();
1818 break;
1820 case kPanelSceneSubstitute:
1821 if (updateFlag & UPDATE_MOUSECLICK) {
1822 _vm->_render->clearFlag(RF_DEMO_SUBST);
1823 _vm->_gfx->setPalette(_mapSavedPal);
1824 setMode(kPanelMain);
1825 _vm->_script->setNoPendingVerb();
1827 break;
1829 case kPanelChapterSelection:
1830 if (updateFlag & UPDATE_MOUSEMOVE) {
1831 handleChapterSelectionUpdate(mousePoint);
1832 } else {
1833 if (updateFlag & UPDATE_MOUSECLICK) {
1834 Rect rect;
1835 rect.left = _vm->getDisplayInfo().saveReminderXOffset;
1836 rect.top = _vm->getDisplayInfo().saveReminderYOffset;
1838 rect.right = rect.left + _vm->getDisplayInfo().saveReminderWidth;
1839 rect.bottom = rect.top + _vm->getDisplayInfo().saveReminderHeight;
1840 if (rect.contains(mousePoint))
1841 setMode(kPanelOption);
1842 else
1843 handleChapterSelectionClick(mousePoint);
1846 break;
1848 case kPanelProtect:
1849 // No mouse interaction
1850 break;
1852 case kPanelPlacard:
1853 #ifdef ENABLE_IHNM
1854 if (_vm->getGameId() == GID_IHNM) {
1855 // Any mouse click here returns the user back to the game
1856 if (updateFlag & UPDATE_MOUSECLICK) {
1857 if (!(_vm->getFeatures() & GF_IHNM_DEMO)) {
1858 _vm->_scene->clearPsychicProfile();
1859 } else {
1860 setMode(kPanelConverse);
1861 _vm->_scene->_textList.clear();
1862 _vm->_script->wakeUpThreads(kWaitTypeDelay);
1866 #endif
1867 break;
1869 case kPanelNull:
1870 if (_vm->_scene->isNonInteractiveIHNMDemoPart() && (updateFlag & UPDATE_MOUSECLICK))
1871 _vm->_scene->showIHNMDemoSpecialScreen();
1872 break;
1875 _lastMousePoint = mousePoint;
1878 void Interface::drawStatusBar() {
1879 Rect rect;
1880 Point textPoint;
1881 int stringWidth;
1882 int color;
1883 // The default colors in the Spanish version of IHNM are shifted by one
1884 // Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)"
1885 int offset = (_vm->getLanguage() == Common::ES_ESP) ? 1 : 0;
1887 // Disable the status text in IHNM when the chapter is 8
1888 if (_vm->getGameId() == GID_IHNM && _vm->_scene->currentChapterNumber() == 8)
1889 return;
1891 // Don't draw the status bar while fading out
1892 if (_fadeMode == kFadeOut)
1893 return;
1895 // Erase background of status bar
1896 rect.left = _vm->getDisplayInfo().statusXOffset;
1897 rect.top = _vm->getDisplayInfo().statusYOffset;
1898 rect.right = rect.left + _vm->getDisplayInfo().width;
1899 rect.bottom = rect.top + _vm->getDisplayInfo().statusHeight;
1901 _vm->_gfx->drawRect(rect, _vm->getDisplayInfo().statusBGColor - offset);
1903 stringWidth = _vm->_font->getStringWidth(kKnownFontSmall, _statusText, 0, kFontNormal);
1905 if (_statusOnceColor == -1)
1906 color = _vm->getDisplayInfo().statusTextColor - offset;
1907 else
1908 color = _statusOnceColor;
1910 textPoint.x = _vm->getDisplayInfo().statusXOffset + (_vm->getDisplayInfo().statusWidth - stringWidth) / 2;
1911 textPoint.y = _vm->getDisplayInfo().statusYOffset + _vm->getDisplayInfo().statusTextY;
1912 if (_vm->getGameId() == GID_ITE)
1913 _vm->_font->textDraw(kKnownFontSmall, _statusText, textPoint, color, 0, kFontNormal);
1914 else
1915 _vm->_font->textDraw(kKnownFontVerb, _statusText, textPoint, color, 0, kFontNormal);
1917 if (_saveReminderState > 0) {
1918 rect.left = _vm->getDisplayInfo().saveReminderXOffset;
1919 rect.top = _vm->getDisplayInfo().saveReminderYOffset;
1921 rect.right = rect.left + _vm->getDisplayInfo().saveReminderWidth;
1922 rect.bottom = rect.top + _vm->getDisplayInfo().saveReminderHeight;
1923 _vm->_sprite->draw(_vm->_sprite->_saveReminderSprites,
1924 _vm->getDisplayInfo().saveReminderFirstSpriteNumber + _saveReminderState - 1,
1925 rect, 256);
1930 void Interface::handleMainClick(const Point& mousePoint) {
1932 PanelButton *panelButton;
1934 panelButton = verbHitTest(mousePoint);
1935 if (panelButton) {
1936 _vm->_script->setVerb(panelButton->id);
1937 return;
1940 panelButton = _mainPanel.hitTest(mousePoint, kPanelAllButtons);
1942 if (panelButton != NULL) {
1943 if (panelButton->type == kPanelButtonArrow) {
1944 panelButton->state = 1;
1945 converseChangePos(panelButton->id);
1948 if (panelButton->type == kPanelButtonInventory) {
1949 if (_vm->_script->_pointerObject != ID_NOTHING) {
1950 _vm->_script->hitObject(_vm->leftMouseButtonPressed());
1952 if (_vm->_script->_pendingVerb) {
1953 _vm->_actor->_protagonist->_currentAction = kActionWait;
1954 _vm->_script->doVerb();
1957 } else {
1958 if (_saveReminderState > 0) {
1959 Rect rect;
1960 rect.left = _vm->getDisplayInfo().saveReminderXOffset;
1961 rect.top = _vm->getDisplayInfo().saveReminderYOffset;
1963 rect.right = rect.left + _vm->getDisplayInfo().saveReminderWidth;
1964 rect.bottom = rect.top + _vm->getDisplayInfo().saveReminderHeight;
1965 if (rect.contains(mousePoint)) {
1966 setMode(kPanelOption);
1972 void Interface::handleMainUpdate(const Point& mousePoint) {
1973 PanelButton *panelButton;
1975 panelButton = verbHitTest(mousePoint);
1976 if (_mainPanel.currentButton != panelButton) {
1977 if (_mainPanel.currentButton) {
1978 if (_mainPanel.currentButton->type == kPanelButtonVerb) {
1979 setVerbState(_mainPanel.currentButton->id, 0);
1982 if (panelButton) {
1983 setVerbState(panelButton->id, 1);
1987 if (panelButton) {
1988 _mainPanel.currentButton = panelButton;
1989 return;
1993 if (!_vm->mouseButtonPressed()) { // remove pressed flag
1994 if (_inventoryUpButton) {
1995 _inventoryUpButton->state = 0;
1996 _inventoryDownButton->state = 0;
2000 panelButton = _mainPanel.hitTest(mousePoint, kPanelAllButtons);
2002 bool changed = false;
2004 if ((panelButton != NULL) && (panelButton->type == kPanelButtonArrow)) {
2005 if (panelButton->state == 1) {
2006 inventoryChangePos(panelButton->id);
2008 changed = true;
2009 } else {
2010 _vm->_script->whichObject(mousePoint);
2013 changed = changed || (panelButton != _mainPanel.currentButton);
2014 _mainPanel.currentButton = panelButton;
2015 if (changed) {
2016 draw();
2020 //inventory stuff
2021 void Interface::inventoryChangePos(int chg) {
2022 // Arrows will scroll the inventory up or down up to 4 items
2023 for (int i = 1; i <= 4; i++) {
2024 if ((chg < 0 && _inventoryStart + chg >= 0) ||
2025 (chg > 0 && _inventoryStart < _inventoryEnd)) {
2026 _inventoryStart += chg;
2029 draw();
2032 void Interface::inventorySetPos(int key) {
2033 _inventoryBox = key - '1';
2034 _inventoryPos = _inventoryStart + _inventoryBox;
2035 if (_inventoryPos >= _inventoryCount)
2036 _inventoryPos = -1;
2039 void Interface::updateInventory(int pos) {
2040 int cols = _vm->getDisplayInfo().inventoryColumns;
2041 if (pos >= _inventoryCount) {
2042 pos = _inventoryCount - 1;
2044 if (pos < 0) {
2045 pos = 0;
2047 _inventoryStart = (pos - cols) / cols * cols;
2048 if (_inventoryStart < 0) {
2049 _inventoryStart = 0;
2052 _inventoryEnd = (_inventoryCount - 1 - cols) / cols * cols;
2053 if (_inventoryEnd < 0) {
2054 _inventoryEnd = 0;
2058 void Interface::addToInventory(int objectId) {
2059 if (_inventoryCount >= _inventorySize) {
2060 return;
2063 for (int i = _inventoryCount; i > 0; i--) {
2064 _inventory[i] = _inventory[i - 1];
2067 _inventory[0] = objectId;
2068 _inventoryCount++;
2070 _inventoryPos = 0;
2071 updateInventory(0);
2072 draw();
2075 void Interface::removeFromInventory(int objectId) {
2076 int j = inventoryItemPosition(objectId);
2077 if (j == -1) {
2078 return;
2081 int i;
2083 for (i = j; i < _inventoryCount - 1; i++) {
2084 _inventory[i] = _inventory[i + 1];
2087 --_inventoryCount;
2088 _inventory[_inventoryCount] = 0;
2089 updateInventory(j);
2090 draw();
2093 void Interface::clearInventory() {
2094 for (int i = 0; i < _inventoryCount; i++)
2095 _inventory[i] = 0;
2097 _inventoryCount = 0;
2098 updateInventory(0);
2101 int Interface::inventoryItemPosition(int objectId) {
2102 for (int i = 0; i < _inventoryCount; i++)
2103 if (_inventory[i] == objectId)
2104 return i;
2106 return -1;
2109 void Interface::drawInventory() {
2110 if (!isInMainMode())
2111 return;
2113 Rect rect;
2114 int ci = _inventoryStart;
2115 ObjectData *obj;
2117 if (_inventoryStart != 0) {
2118 drawPanelButtonArrow(&_mainPanel, _inventoryUpButton);
2120 if (_inventoryStart != _inventoryEnd) {
2121 drawPanelButtonArrow(&_mainPanel, _inventoryDownButton);
2124 for (int i = 0; i < _mainPanel.buttonsCount; i++) {
2125 if (_mainPanel.buttons[i].type != kPanelButtonInventory) {
2126 continue;
2128 _mainPanel.calcPanelButtonRect(&_mainPanel.buttons[i], rect);
2130 if (_vm->getGameId() == GID_ITE)
2131 _vm->_gfx->drawRect(rect, kITEColorDarkGrey);
2132 else
2133 _vm->_gfx->drawRect(rect, _vm->KnownColor2ColorId(kKnownColorBlack));
2135 if (ci < _inventoryCount) {
2136 obj = _vm->_actor->getObj(_inventory[ci]);
2137 _vm->_sprite->draw(_vm->_sprite->_inventorySprites, obj->_spriteListResourceId, rect, 256);
2140 ci++;
2144 void Interface::setVerbState(int verb, int state) {
2145 PanelButton * panelButton = getPanelButtonByVerbType(verb);
2146 if (panelButton == NULL) return;
2147 if (state == 2) {
2148 state = (_mainPanel.currentButton == panelButton) ? 1 : 0;
2150 panelButton->state = state;
2151 draw();
2154 void Interface::drawButtonBox(const Rect& rect, ButtonKind kind, bool down) {
2155 byte cornerColor;
2156 byte frameColor;
2157 byte fillColor;
2158 byte solidColor;
2159 byte odl, our, idl, iur;
2161 switch (kind ) {
2162 case kSlider:
2163 cornerColor = 0x8b;
2164 frameColor = _vm->KnownColor2ColorId(kKnownColorBlack);
2165 fillColor = kITEColorLightBlue96;
2166 odl = kITEColorDarkBlue8a;
2167 our = kITEColorLightBlue92;
2168 idl = 0x89;
2169 iur = 0x94;
2170 solidColor = down ? kITEColorLightBlue94 : kITEColorLightBlue96;
2171 break;
2172 case kEdit:
2173 if (_vm->getGameId() == GID_ITE) {
2174 cornerColor = frameColor = fillColor = kITEColorLightBlue96;
2175 our = kITEColorDarkBlue8a;
2176 odl = kITEColorLightBlue94;
2177 solidColor = down ? kITEColorBlue : kITEColorDarkGrey0C;
2178 } else {
2179 cornerColor = frameColor = fillColor = _vm->KnownColor2ColorId(kKnownColorBlack);
2180 our = odl = solidColor = _vm->KnownColor2ColorId(kKnownColorBlack);
2182 iur = 0x97;
2183 idl = 0x95;
2184 break;
2185 default:
2186 cornerColor = 0x8b;
2187 frameColor = _vm->KnownColor2ColorId(kKnownColorBlack);
2188 solidColor = fillColor = kITEColorLightBlue96;
2189 odl = kITEColorDarkBlue8a;
2190 our = kITEColorLightBlue94;
2191 idl = 0x97;
2192 iur = 0x95;
2193 if (down) {
2194 SWAP(odl, our);
2195 SWAP(idl, iur);
2197 break;
2200 int x = rect.left;
2201 int y = rect.top;
2202 int w = rect.width();
2203 int h = rect.height();
2204 int xe = rect.right - 1;
2205 int ye = rect.bottom - 1;
2207 _vm->_gfx->setPixelColor(x, y, cornerColor);
2208 _vm->_gfx->setPixelColor(x, ye, cornerColor);
2209 _vm->_gfx->setPixelColor(xe, y, cornerColor);
2210 _vm->_gfx->setPixelColor(xe, ye, cornerColor);
2211 _vm->_gfx->hLine(x + 1, y, x + w - 2, frameColor);
2212 _vm->_gfx->hLine(x + 1, ye, x + w - 2, frameColor);
2213 _vm->_gfx->vLine(x, y + 1, y + h - 2, frameColor);
2214 _vm->_gfx->vLine(xe, y + 1, y + h - 2, frameColor);
2216 x++;
2217 y++;
2218 xe--;
2219 ye--;
2220 w -= 2;
2221 h -= 2;
2222 _vm->_gfx->vLine(x, y, y + h - 1, odl);
2223 _vm->_gfx->hLine(x, ye, x + w - 1, odl);
2224 _vm->_gfx->vLine(xe, y, y + h - 2, our);
2225 _vm->_gfx->hLine(x + 1, y, x + 1 + w - 2, our);
2227 x++;
2228 y++;
2229 xe--;
2230 ye--;
2231 w -= 2;
2232 h -= 2;
2233 _vm->_gfx->setPixelColor(x, y, fillColor);
2234 _vm->_gfx->setPixelColor(xe, ye, fillColor);
2235 _vm->_gfx->vLine(x, y + 1, y + 1 + h - 2, idl);
2236 _vm->_gfx->hLine(x + 1, ye, x + 1 + w - 2, idl);
2237 _vm->_gfx->vLine(xe, y, y + h - 2, iur);
2238 _vm->_gfx->hLine(x + 1, y, x + 1 + w - 2, iur);
2240 x++; y++;
2241 w -= 2; h -= 2;
2243 Common::Rect fill(x, y, x + w, y + h);
2244 _vm->_gfx->fillRect(fill, solidColor);
2245 _vm->_render->addDirtyRect(rect);
2248 static const int readingSpeeds[] = { kTextClick, kTextSlow, kTextMid, kTextFast };
2250 void Interface::drawPanelButtonText(InterfacePanel *panel, PanelButton *panelButton, int spritenum) {
2251 const char *text;
2252 int textId;
2253 int textWidth;
2254 int textHeight;
2255 Point point;
2256 Point texturePoint;
2257 KnownColor textColor;
2258 Rect rect;
2259 int litButton = 0;
2260 KnownColor textShadowKnownColor = kKnownColorVerbTextShadow;
2261 KnownFont textFont = kKnownFontMedium;
2263 textId = panelButton->id;
2264 switch (panelButton->id) {
2265 case kTextReadingSpeed:
2266 if (_vm->getGameId() == GID_ITE && !(_vm->getFeatures() & GF_ITE_FLOPPY)) {
2267 if (_vm->_subtitlesEnabled)
2268 textId = kTextOn;
2269 else
2270 textId = kTextOff;
2271 } else {
2272 textId = readingSpeeds[_vm->_readingSpeed];
2274 break;
2275 case kTextMusic:
2276 if (_vm->_musicVolume)
2277 textId = kText10Percent + _vm->_musicVolume / 25 - 1;
2278 else
2279 textId = kTextOff;
2280 break;
2281 case kTextSound:
2282 if (_vm->_soundVolume)
2283 textId = kText10Percent + _vm->_soundVolume / 25 - 1;
2284 else
2285 textId = kTextOff;
2286 break;
2287 case kTextVoices:
2288 if (_vm->_subtitlesEnabled && _vm->_voicesEnabled)
2289 textId = kTextBoth;
2290 else if (_vm->_subtitlesEnabled && !_vm->_voicesEnabled)
2291 textId = kTextText;
2292 else if (!_vm->_subtitlesEnabled && _vm->_voicesEnabled)
2293 textId = kTextAudio;
2294 break;
2296 if (_vm->getGameId() == GID_ITE) {
2297 text = _vm->getTextString(textId);
2298 textFont = kKnownFontMedium;
2299 textShadowKnownColor = kKnownColorVerbTextShadow;
2300 textWidth = _vm->_font->getStringWidth(kKnownFontMedium, text, 0, kFontNormal);
2301 textHeight = _vm->_font->getHeight(kKnownFontMedium);
2302 } else {
2303 if (textId < 39 || textId > 50) {
2304 // Read non-hardcoded strings from the LUT string table, loaded from the game
2305 // data files
2306 text = _vm->_script->_mainStrings.getString(IHNMTextStringIdsLUT[textId]);
2307 } else {
2308 // Hardcoded strings in IHNM are read from the ITE hardcoded strings
2309 text = _vm->getTextString(textId);
2312 textFont = kKnownFontVerb;
2313 textShadowKnownColor = kKnownColorTransparent;
2314 textWidth = _vm->_font->getStringWidth(kKnownFontVerb, text, 0, kFontNormal);
2315 textHeight = _vm->_font->getHeight(kKnownFontVerb);
2318 point.x = panel->x + panelButton->xOffset + (panelButton->width / 2) - (textWidth / 2);
2319 point.y = panel->y + panelButton->yOffset + (panelButton->height / 2) - (textHeight / 2);
2321 if (panelButton == panel->currentButton) {
2322 textColor = kKnownColorVerbTextActive;
2323 } else {
2324 textColor = kKnownColorVerbText;
2327 panel->calcPanelButtonRect(panelButton, rect);
2328 if (_vm->getGameId() == GID_ITE) {
2329 drawButtonBox(rect, kButton, panelButton->state > 0);
2330 } else {
2331 litButton = panelButton->state > 0;
2333 if (panel == &_optionPanel) {
2334 texturePoint.x = _optionPanel.x + panelButton->xOffset - 1;
2335 texturePoint.y = _optionPanel.y + panelButton->yOffset - 1;
2336 _vm->_sprite->draw(_optionPanel.sprites, spritenum + 2 + litButton, texturePoint, 256);
2337 } else if (panel == &_quitPanel) {
2338 texturePoint.x = _quitPanel.x + panelButton->xOffset - 3;
2339 texturePoint.y = _quitPanel.y + panelButton->yOffset - 3;
2340 _vm->_sprite->draw(_quitPanel.sprites, litButton, texturePoint, 256);
2341 } else if (panel == &_savePanel) {
2342 texturePoint.x = _savePanel.x + panelButton->xOffset - 3;
2343 texturePoint.y = _savePanel.y + panelButton->yOffset - 3;
2344 _vm->_sprite->draw(_savePanel.sprites, litButton, texturePoint, 256);
2345 // Input text box sprite
2346 texturePoint.x = _savePanel.x + _saveEdit->xOffset - 2;
2347 texturePoint.y = _savePanel.y + _saveEdit->yOffset - 2;
2348 _vm->_sprite->draw(_savePanel.sprites, 2, texturePoint, 256);
2349 } else if (panel == &_loadPanel) {
2350 texturePoint.x = _loadPanel.x + panelButton->xOffset - 3;
2351 texturePoint.y = _loadPanel.y + panelButton->yOffset - 3;
2352 _vm->_sprite->draw(_loadPanel.sprites, litButton, texturePoint, 256);
2353 } else {
2354 // revert to default behavior
2355 drawButtonBox(rect, kButton, panelButton->state > 0);
2359 _vm->_font->textDraw(textFont, text, point,
2360 _vm->KnownColor2ColorId(textColor), _vm->KnownColor2ColorId(textShadowKnownColor), kFontShadow);
2363 void Interface::drawPanelButtonArrow(InterfacePanel *panel, PanelButton *panelButton) {
2364 Point point;
2365 int spriteNumber;
2367 if (panel->currentButton == panelButton) {
2368 if (panelButton->state != 0) {
2369 spriteNumber = panelButton->downSpriteNumber;
2370 } else {
2371 spriteNumber = panelButton->overSpriteNumber;
2373 } else {
2374 spriteNumber = panelButton->upSpriteNumber;
2377 point.x = panel->x + panelButton->xOffset;
2378 point.y = panel->y + panelButton->yOffset;
2380 if (_vm->getGameId() == GID_ITE)
2381 _vm->_sprite->draw(_vm->_sprite->_mainSprites, spriteNumber, point, 256);
2382 else
2383 _vm->_sprite->draw(_vm->_sprite->_arrowSprites, spriteNumber, point, 256);
2386 void Interface::drawVerbPanelText(PanelButton *panelButton, KnownColor textKnownColor, KnownColor textShadowKnownColor) {
2387 const char *text;
2388 int textWidth;
2389 Point point;
2390 int textId;
2392 if (_vm->getGameId() == GID_ITE) {
2393 textId = verbToTextIdITE[panelButton->id - 1];
2394 text = _vm->getTextString(textId);
2395 } else {
2396 textId = panelButton->id;
2397 text = _vm->_script->_mainStrings.getString(textId + 1);
2398 textShadowKnownColor = kKnownColorTransparent;
2401 textWidth = _vm->_font->getStringWidth(kKnownFontVerb, text, 0, kFontNormal);
2403 if (_vm->getGameId() == GID_ITE) {
2404 point.x = _mainPanel.x + panelButton->xOffset + 1 + (panelButton->width - 1 - textWidth) / 2;
2405 point.y = _mainPanel.y + panelButton->yOffset + 1;
2406 } else {
2407 point.x = _mainPanel.x + panelButton->xOffset + 1 + (panelButton->width - textWidth) / 2;
2408 point.y = _mainPanel.y + panelButton->yOffset + 12;
2411 _vm->_font->textDraw(kKnownFontVerb, text, point,
2412 _vm->KnownColor2ColorId(textKnownColor), _vm->KnownColor2ColorId(textShadowKnownColor),
2413 (textShadowKnownColor != kKnownColorTransparent) ? kFontShadow : kFontNormal);
2417 // Converse stuff
2418 void Interface::converseInit(void) {
2419 for (int i = 0; i < CONVERSE_MAX_TEXTS; i++)
2420 _converseText[i].text = NULL;
2421 converseClear();
2424 void Interface::converseClear(void) {
2425 for (int i = 0; i < CONVERSE_MAX_TEXTS; i++) {
2426 if (_converseText[i].text != NULL) {
2427 free(_converseText[i].text);
2428 _converseText[i].text = NULL;
2430 _converseText[i].stringNum = -1;
2431 _converseText[i].replyId = 0;
2432 _converseText[i].replyFlags = 0;
2433 _converseText[i].replyBit = 0;
2436 _converseTextCount = 0;
2437 _converseStrCount = 0;
2438 _converseStartPos = 0;
2439 _converseEndPos = 0;
2440 _conversePos = -1;
2443 bool Interface::converseAddText(const char *text, int strId, int replyId, byte replyFlags, int replyBit) {
2444 int count = 0; // count how many pieces of text per string
2445 int i;
2446 int len;
2447 byte c;
2449 assert(strlen(text) < CONVERSE_MAX_WORK_STRING);
2451 strncpy(_converseWorkString, text, CONVERSE_MAX_WORK_STRING);
2453 while (1) {
2454 len = strlen(_converseWorkString);
2456 for (i = len; i >= 0; i--) {
2457 c = _converseWorkString[i];
2459 if (_vm->getGameId() == GID_ITE) {
2460 if ((c == ' ' || c == '\0') && (_vm->_font->getStringWidth(kKnownFontSmall, _converseWorkString, i, kFontNormal) <= _vm->getDisplayInfo().converseMaxTextWidth))
2461 break;
2462 } else {
2463 if ((c == ' ' || c == '\0') && (_vm->_font->getStringWidth(kKnownFontVerb, _converseWorkString, i, kFontNormal) <= _vm->getDisplayInfo().converseMaxTextWidth))
2464 break;
2467 if (i < 0) {
2468 return true;
2471 if (_converseTextCount == CONVERSE_MAX_TEXTS) {
2472 return true;
2475 _converseText[_converseTextCount].text = (char *)malloc(i + 1);
2476 strncpy(_converseText[_converseTextCount].text, _converseWorkString, i);
2478 _converseText[_converseTextCount].strId = strId;
2479 _converseText[_converseTextCount].text[i] = 0;
2480 _converseText[_converseTextCount].textNum = count;
2481 _converseText[_converseTextCount].stringNum = _converseStrCount;
2482 _converseText[_converseTextCount].replyId = replyId;
2483 _converseText[_converseTextCount].replyFlags = replyFlags;
2484 _converseText[_converseTextCount].replyBit = replyBit;
2486 _converseTextCount++;
2487 count++;
2489 if (len == i)
2490 break;
2492 strncpy(_converseWorkString, &_converseWorkString[i + 1], len - i);
2495 _converseStrCount++;
2497 return false;
2500 void Interface::converseDisplayText() {
2501 int end;
2503 _converseStartPos = 0;
2505 end = _converseTextCount - _vm->getDisplayInfo().converseTextLines;
2507 if (end < 0)
2508 end = 0;
2510 _converseEndPos = end;
2511 draw();
2515 void Interface::converseSetTextLines(int row) {
2516 int pos = row + _converseStartPos;
2517 if (pos >= _converseTextCount)
2518 pos = -1;
2519 if (pos != _conversePos) {
2520 _conversePos = pos;
2521 draw();
2525 void Interface::converseDisplayTextLines() {
2526 int relPos;
2527 byte foregnd;
2528 byte backgnd;
2529 byte bulletForegnd;
2530 byte bulletBackgnd;
2531 const char *str;
2532 char bullet[2] = {
2533 (char)0xb7, 0
2535 Rect rect(8, _vm->getDisplayInfo().converseTextLines * _vm->getDisplayInfo().converseTextHeight);
2536 Point textPoint;
2538 assert(_conversePanel.buttonsCount >= 6);
2540 if (_vm->getGameId() == GID_ITE) {
2541 bulletForegnd = kITEColorGreen;
2542 bulletBackgnd = kITEColorBlack;
2543 } else {
2544 bulletForegnd = _vm->KnownColor2ColorId(kKnownColorBrightWhite);
2545 bulletBackgnd = _vm->KnownColor2ColorId(kKnownColorBlack);
2546 bullet[0] = '>'; // different bullet in IHNM
2549 rect.moveTo(_conversePanel.x + _conversePanel.buttons[0].xOffset,
2550 _conversePanel.y + _conversePanel.buttons[0].yOffset);
2552 if (_vm->getGameId() == GID_ITE)
2553 _vm->_gfx->drawRect(rect, kITEColorDarkGrey); //fill bullet place
2554 else
2555 _vm->_gfx->drawRect(rect, _vm->KnownColor2ColorId(kKnownColorBlack)); //fill bullet place
2557 for (int i = 0; i < _vm->getDisplayInfo().converseTextLines; i++) {
2558 relPos = _converseStartPos + i;
2560 if (_converseTextCount <= relPos) {
2561 break;
2564 if (_conversePos >= 0 && _converseText[_conversePos].stringNum == _converseText[relPos].stringNum) {
2565 if (_vm->getGameId() == GID_ITE) {
2566 foregnd = kITEColorBrightWhite;
2567 backgnd = (!_vm->leftMouseButtonPressed()) ? kITEColorDarkGrey : kITEColorGrey;
2568 } else {
2569 foregnd = _vm->KnownColor2ColorId(kKnownColorVerbTextActive);
2570 backgnd = _vm->KnownColor2ColorId(kKnownColorVerbTextActive);
2572 } else {
2573 if (_vm->getGameId() == GID_ITE) {
2574 foregnd = kITEColorBlue;
2575 backgnd = kITEColorDarkGrey;
2576 } else {
2577 foregnd = _vm->KnownColor2ColorId(kKnownColorBrightWhite);
2578 backgnd = _vm->KnownColor2ColorId(kKnownColorBlack);
2582 _conversePanel.calcPanelButtonRect(&_conversePanel.buttons[i], rect);
2583 rect.left += 8;
2584 _vm->_gfx->drawRect(rect, backgnd);
2586 str = _converseText[relPos].text;
2588 if (_converseText[relPos].textNum == 0) { // first entry
2589 textPoint.x = rect.left - 6;
2590 textPoint.y = rect.top;
2592 if (_vm->getGameId() == GID_ITE)
2593 _vm->_font->textDraw(kKnownFontSmall, bullet, textPoint, bulletForegnd, bulletBackgnd, (FontEffectFlags)(kFontShadow | kFontDontmap));
2594 else
2595 _vm->_font->textDraw(kKnownFontVerb, bullet, textPoint, bulletForegnd, bulletBackgnd, (FontEffectFlags)(kFontShadow | kFontDontmap));
2597 textPoint.x = rect.left + 1;
2598 textPoint.y = rect.top;
2599 if (_vm->getGameId() == GID_ITE)
2600 _vm->_font->textDraw(kKnownFontSmall, str, textPoint, foregnd, kITEColorBlack, kFontShadow);
2601 else
2602 _vm->_font->textDraw(kKnownFontVerb, str, textPoint, foregnd, _vm->KnownColor2ColorId(kKnownColorBlack), kFontShadow);
2605 if (_converseStartPos != 0) {
2606 drawPanelButtonArrow(&_conversePanel, _converseUpButton);
2609 if (_converseStartPos != _converseEndPos) {
2610 drawPanelButtonArrow(&_conversePanel, _converseDownButton);
2614 void Interface::converseChangePos(int chg) {
2615 // Arrows will scroll the converse panel or down up to 4 conversation options
2616 for (int i = 1; i <= 4; i++) {
2617 if ((chg < 0 && _converseStartPos + chg >= 0) ||
2618 (chg > 0 && _converseStartPos < _converseEndPos)) {
2619 _converseStartPos += chg;
2622 draw();
2625 void Interface::converseSetPos(int key) {
2626 Converse *ct;
2627 int selection = key - '1';
2629 if (selection >= _converseTextCount)
2630 return;
2632 converseSetTextLines(selection);
2634 ct = &_converseText[_conversePos];
2636 _vm->_script->finishDialog(ct->strId, ct->replyId, ct->replyFlags, ct->replyBit);
2638 if (_vm->_scene->isITEPuzzleScene())
2639 _vm->_puzzle->handleReply(ct->replyId);
2641 _conversePos = -1;
2645 void Interface::handleConverseUpdate(const Point& mousePoint) {
2646 bool changed;
2648 PanelButton *last = _conversePanel.currentButton;
2650 if (!_vm->mouseButtonPressed()) { // remove pressed flag
2651 if (_converseUpButton) {
2652 _converseUpButton->state = 0;
2653 _converseDownButton->state = 0;
2657 _conversePanel.currentButton = converseHitTest(mousePoint);
2658 changed = last != _conversePanel.currentButton;
2661 if (_conversePanel.currentButton == NULL) {
2662 _conversePos = -1;
2663 if (changed) {
2664 draw();
2666 return;
2669 if (_conversePanel.currentButton->type == kPanelButtonConverseText) {
2670 converseSetTextLines(_conversePanel.currentButton->id);
2673 if (_conversePanel.currentButton->type == kPanelButtonArrow) {
2674 if (_conversePanel.currentButton->state == 1) {
2675 converseChangePos(_conversePanel.currentButton->id);
2677 draw();
2682 void Interface::handleConverseClick(const Point& mousePoint) {
2683 _conversePanel.currentButton = converseHitTest(mousePoint);
2685 if (_conversePanel.currentButton == NULL) {
2686 return;
2689 if (_conversePanel.currentButton->type == kPanelButtonConverseText) {
2690 converseSetPos(_conversePanel.currentButton->ascii);
2693 if (_conversePanel.currentButton->type == kPanelButtonArrow) {
2694 _conversePanel.currentButton->state = 1;
2695 converseChangePos(_conversePanel.currentButton->id);
2700 void Interface::saveState(Common::OutSaveFile *out) {
2701 out->writeUint16LE(_inventoryCount);
2703 for (int i = 0; i < _inventoryCount; i++) {
2704 out->writeUint16LE(_inventory[i]);
2708 void Interface::loadState(Common::InSaveFile *in) {
2709 _inventoryCount = in->readUint16LE();
2711 for (int i = 0; i < _inventoryCount; i++) {
2712 _inventory[i] = in->readUint16LE();
2715 updateInventory(0);
2718 void Interface::mapPanelShow() {
2719 int i;
2720 byte *resource;
2721 size_t resourceLength, imageLength;
2722 Rect rect;
2723 byte *image;
2724 int imageWidth, imageHeight;
2725 const byte *pal;
2726 PalEntry cPal[PAL_ENTRIES];
2728 _vm->_gfx->showCursor(false);
2730 rect.left = rect.top = 0;
2732 _vm->_resource->loadResource(_interfaceContext,
2733 _vm->_resource->convertResourceId(RID_ITE_TYCHO_MAP), resource, resourceLength);
2734 if (resourceLength == 0) {
2735 error("Interface::mapPanelShow() unable to load Tycho map resource");
2738 _vm->_gfx->getCurrentPal(_mapSavedPal);
2740 for (i = 0; i < 6 ; i++) {
2741 _vm->_gfx->palToBlack(_mapSavedPal, 0.2 * i);
2742 _vm->_render->drawScene();
2743 _vm->_system->delayMillis(5);
2746 _vm->_render->setFlag(RF_MAP);
2748 _vm->decodeBGImage(resource, resourceLength, &image, &imageLength, &imageWidth, &imageHeight);
2749 pal = _vm->getImagePal(resource, resourceLength);
2751 for (i = 0; i < PAL_ENTRIES; i++) {
2752 cPal[i].red = *pal++;
2753 cPal[i].green = *pal++;
2754 cPal[i].blue = *pal++;
2757 rect.setWidth(imageWidth);
2758 rect.setHeight(imageHeight);
2760 _vm->_gfx->drawRegion(rect, image);
2762 // Evil Evil
2763 for (i = 0; i < 6 ; i++) {
2764 _vm->_gfx->blackToPal(cPal, 0.2 * i);
2765 _vm->_render->drawScene();
2766 _vm->_system->delayMillis(5);
2769 free(resource);
2770 free(image);
2772 setSaveReminderState(false);
2774 _mapPanelCrossHairState = true;
2777 void Interface::mapPanelClean() {
2778 PalEntry pal[PAL_ENTRIES];
2779 int i;
2781 _vm->_gfx->getCurrentPal(pal);
2783 for (i = 0; i < 6 ; i++) {
2784 _vm->_gfx->palToBlack(pal, 0.2 * i);
2785 _vm->_render->drawScene();
2786 _vm->_system->delayMillis(5);
2789 _vm->_render->clearFlag(RF_MAP);
2790 setMode(kPanelMain);
2792 _vm->_gfx->showCursor(true);
2793 _vm->_render->drawScene();
2795 for (i = 0; i < 6 ; i++) {
2796 _vm->_gfx->blackToPal(_mapSavedPal, 0.2 * i);
2797 _vm->_render->drawScene();
2798 _vm->_system->delayMillis(5);
2802 void Interface::mapPanelDrawCrossHair() {
2803 _mapPanelCrossHairState = !_mapPanelCrossHairState;
2805 Point mapPosition = _vm->_isoMap->getMapPosition();
2806 Rect screen(_vm->getDisplayInfo().width, _vm->_scene->getHeight());
2808 if (screen.contains(mapPosition)) {
2809 _vm->_sprite->draw(_vm->_sprite->_mainSprites,
2810 _mapPanelCrossHairState? RID_ITE_SPR_CROSSHAIR : RID_ITE_SPR_CROSSHAIR + 1,
2811 mapPosition, 256);
2815 void Interface::keyBoss() {
2816 if (_vm->getGameId() == GID_ITE)
2817 return;
2819 if (_bossMode != -1 || _fadeMode != kNoFade)
2820 return;
2822 _vm->_sound->pauseVoice();
2823 _vm->_sound->pauseSound();
2824 _vm->_music->pause();
2826 int i;
2827 byte *resource;
2828 size_t resourceLength, imageLength;
2829 Rect rect;
2830 byte *image;
2831 int imageWidth, imageHeight;
2832 const byte *pal;
2833 PalEntry cPal[PAL_ENTRIES];
2835 _vm->_gfx->showCursor(false);
2837 rect.left = rect.top = 0;
2839 _vm->_resource->loadResource(_interfaceContext, RID_IHNM_BOSS_SCREEN, resource, resourceLength);
2840 if (resourceLength == 0) {
2841 error("Interface::bossKey() unable to load Boss image resource");
2844 _bossMode = _panelMode;
2845 setMode(kPanelBoss);
2847 _vm->decodeBGImage(resource, resourceLength, &image, &imageLength, &imageWidth, &imageHeight);
2848 rect.setWidth(imageWidth);
2849 rect.setHeight(imageHeight);
2851 _vm->_gfx->getCurrentPal(_mapSavedPal);
2852 pal = _vm->getImagePal(resource, resourceLength);
2854 cPal[0].red = 0;
2855 cPal[0].green = 0;
2856 cPal[0].blue = 0;
2858 for (i = 1; i < PAL_ENTRIES; i++) {
2859 cPal[i].red = 128;
2860 cPal[i].green = 128;
2861 cPal[i].blue = 128;
2864 _vm->_gfx->drawRegion(rect, image);
2866 _vm->_gfx->setPalette(cPal);
2868 free(resource);
2869 free(image);
2873 void Interface::keyBossExit() {
2874 PalEntry pal[PAL_ENTRIES];
2876 _vm->_sound->resumeVoice();
2877 _vm->_sound->resumeSound();
2878 _vm->_music->resume();
2880 _vm->_gfx->getCurrentPal(pal);
2882 _vm->_gfx->palToBlack(pal, 1);
2883 setMode(_bossMode);
2885 _vm->_render->drawScene();
2887 _vm->_gfx->blackToPal(_mapSavedPal, 1);
2889 _vm->_gfx->showCursor(true);
2891 _bossMode = -1;
2895 } // End of namespace Saga