1 /* ScummVM - Graphic Adventure Engine
2 *
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.
6 *
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.
11 *
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.
16 *
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.
20 *
21 */
22
23 // Scene management module
24 #include "saga/saga.h"
25
26 #include "saga/gfx.h"
27 #include "saga/animation.h"
28 #include "saga/console.h"
29 #include "saga/interface.h"
30 #include "saga/events.h"
31 #include "saga/isomap.h"
32 #include "saga/objectmap.h"
33 #include "saga/palanim.h"
34 #include "saga/puzzle.h"
35 #include "saga/render.h"
36 #include "saga/script.h"
37 #include "saga/sound.h"
38 #include "saga/music.h"
39
40 #include "saga/scene.h"
41 #include "saga/actor.h"
42 #include "saga/resource.h"
43
44 #include "common/util.h"
45
46 #include "image/iff.h"
47
48 namespace Saga {
49
50 static int initSceneDoors[SCENE_DOORS_MAX] = {
51 0, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
52 };
53
54 static SAGAResourceTypes ITESceneResourceTypes[26] = {
55 SAGA_ACTOR,
56 SAGA_OBJECT,
57 SAGA_BG_IMAGE,
58 SAGA_BG_MASK,
59 SAGA_UNKNOWN,
60 SAGA_STRINGS,
61 SAGA_OBJECT_MAP,
62 SAGA_ACTION_MAP,
63 SAGA_ISO_IMAGES,
64 SAGA_ISO_MAP,
65 SAGA_ISO_PLATFORMS,
66 SAGA_ISO_METATILES,
67 SAGA_ENTRY,
68 SAGA_UNKNOWN,
69 SAGA_ANIM,
70 SAGA_ANIM,
71 SAGA_ANIM,
72 SAGA_ANIM,
73 SAGA_ANIM,
74 SAGA_ANIM,
75 SAGA_ANIM,
76 SAGA_ANIM,
77 SAGA_ISO_MULTI,
78 SAGA_PAL_ANIM,
79 SAGA_FACES,
80 SAGA_PALETTE
81 };
82
83 #ifdef ENABLE_IHNM
84 static SAGAResourceTypes IHNMSceneResourceTypes[28] = {
85 SAGA_ACTOR,
86 SAGA_UNKNOWN,
87 SAGA_BG_IMAGE,
88 SAGA_BG_MASK,
89 SAGA_UNKNOWN,
90 SAGA_STRINGS,
91 SAGA_OBJECT_MAP,
92 SAGA_ACTION_MAP,
93 SAGA_ISO_IMAGES,
94 SAGA_ISO_MAP,
95 SAGA_ISO_PLATFORMS,
96 SAGA_ISO_METATILES,
97 SAGA_ENTRY,
98 SAGA_UNKNOWN,
99 SAGA_ANIM,
100 SAGA_ANIM,
101 SAGA_ANIM,
102 SAGA_ANIM,
103 SAGA_ANIM,
104 SAGA_ANIM,
105 SAGA_ANIM,
106 SAGA_ANIM,
107 SAGA_ANIM,
108 SAGA_ANIM,
109 SAGA_ISO_MULTI,
110 SAGA_PAL_ANIM,
111 SAGA_FACES,
112 SAGA_PALETTE
113 };
114 #endif
115
116 const char *SAGAResourceTypesString[] = {
117 "SAGA_UNKNOWN",
118 "SAGA_ACTOR",
119 "SAGA_OBJECT",
120 "SAGA_BG_IMAGE",
121 "SAGA_BG_MASK",
122 "SAGA_STRINGS",
123 "SAGA_OBJECT_MAP",
124 "SAGA_ACTION_MAP",
125 "SAGA_ISO_IMAGES",
126 "SAGA_ISO_MAP",
127 "SAGA_ISO_PLATFORMS",
128 "SAGA_ISO_METATILES",
129 "SAGA_ENTRY",
130 "SAGA_ANIM",
131 "SAGA_ISO_MULTI",
132 "SAGA_PAL_ANIM",
133 "SAGA_FACES",
134 "SAGA_PALETTE"
135 };
136
Scene(SagaEngine * vm)137 Scene::Scene(SagaEngine *vm) : _vm(vm) {
138 ByteArray sceneLUTData;
139 uint32 resourceId;
140 uint i;
141
142 // Do nothing for SAGA2 games for now
143 if (_vm->isSaga2()) {
144 _inGame = false;
145 _sceneLoaded = false;
146 return;
147 }
148
149 // Load scene module resource context
150 _sceneContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
151 if (_sceneContext == NULL) {
152 error("Scene::Scene() scene context not found");
153 }
154
155 // Load scene lookup table
156 resourceId = _vm->_resource->convertResourceId(_vm->getResourceDescription()->sceneLUTResourceId);
157 debug(3, "Loading scene LUT from resource %i", resourceId);
158 _vm->_resource->loadResource(_sceneContext, resourceId, sceneLUTData);
159 if (sceneLUTData.empty()) {
160 error("Scene::Scene() sceneLUT is empty");
161 }
162 _sceneLUT.resize(sceneLUTData.size() / 2);
163
164 ByteArrayReadStreamEndian readS(sceneLUTData, _sceneContext->isBigEndian());
165
166 for (i = 0; i < _sceneLUT.size(); i++) {
167 _sceneLUT[i] = readS.readUint16();
168 debug(8, "sceneNumber %i has resourceId %i", i, _sceneLUT[i]);
169 }
170
171 #ifdef SAGA_DEBUG
172
173 #define DUMP_SCENES_LEVEL 10
174
175 if (DUMP_SCENES_LEVEL <= gDebugLevel) {
176 int backUpDebugLevel = gDebugLevel;
177 SAGAResourceTypes *types;
178 int typesCount;
179 SAGAResourceTypes resType;
180 SceneResourceDataArray resourceList;
181
182 getResourceTypes(types, typesCount);
183
184 for (i = 0; i < _sceneLUT.size(); i++) {
185 gDebugLevel = -1;
186 loadSceneDescriptor(_sceneLUT[i]);
187 loadSceneResourceList(_sceneDescription.resourceListResourceId, resourceList);
188 gDebugLevel = backUpDebugLevel;
189 debug(DUMP_SCENES_LEVEL, "Dump Scene: number %i, descriptor resourceId %i, resourceList resourceId %i", i, _sceneLUT[i], _sceneDescription.resourceListResourceId);
190 debug(DUMP_SCENES_LEVEL, "\tresourceListCount %i", (int)resourceList.size());
191 for (SceneResourceDataArray::iterator j = resourceList.begin(); j != resourceList.end(); ++j) {
192 if (j->resourceType >= typesCount) {
193 error("wrong resource type %i", j->resourceType);
194 }
195 resType = types[j->resourceType];
196
197 debug(DUMP_SCENES_LEVEL, "\t%s resourceId %i", SAGAResourceTypesString[resType], j->resourceId);
198 }
199 }
200 }
201 #endif
202
203 debug(3, "LUT has %d entries.", _sceneLUT.size());
204
205 _sceneLoaded = false;
206 _sceneNumber = 0;
207 _chapterNumber = 0;
208 _sceneResourceId = 0;
209 _inGame = false;
210 _sceneDescription.reset();
211 _sceneProc = NULL;
212 _objectMap = new ObjectMap(_vm);
213 _actionMap = new ObjectMap(_vm);
214 }
215
~Scene()216 Scene::~Scene() {
217 // Do nothing for SAGA2 games for now
218 if (_vm->isSaga2()) {
219 return;
220 }
221
222 delete _actionMap;
223 delete _objectMap;
224 }
225
getResourceTypes(SAGAResourceTypes * & types,int & typesCount)226 void Scene::getResourceTypes(SAGAResourceTypes *&types, int &typesCount) {
227 if (_vm->getGameId() == GID_ITE) {
228 typesCount = ARRAYSIZE(ITESceneResourceTypes);
229 types = ITESceneResourceTypes;
230 #ifdef ENABLE_IHNM
231 } else if (_vm->getGameId() == GID_IHNM) {
232 typesCount = ARRAYSIZE(IHNMSceneResourceTypes);
233 types = IHNMSceneResourceTypes;
234 #endif
235 }
236 }
237
drawTextList()238 void Scene::drawTextList() {
239 for (TextList::iterator entry = _textList.begin(); entry != _textList.end(); ++entry) {
240
241 if (entry->display) {
242
243 if (entry->useRect) {
244 _vm->_font->textDrawRect(entry->font, entry->text, entry->rect, _vm->KnownColor2ColorId(entry->knownColor), _vm->KnownColor2ColorId(entry->effectKnownColor), entry->flags);
245 } else {
246 _vm->_font->textDraw(entry->font, entry->text, entry->point, _vm->KnownColor2ColorId(entry->knownColor), _vm->KnownColor2ColorId(entry->effectKnownColor), entry->flags);
247 }
248 }
249 }
250 }
251
startScene()252 void Scene::startScene() {
253 SceneQueueList::iterator queueIterator;
254 Event event;
255
256 if (_sceneLoaded) {
257 error("Scene::start(): Error: Can't start game...scene already loaded");
258 }
259
260 if (_inGame) {
261 error("Scene::start(): Error: Can't start game...game already started");
262 }
263
264 // Hide cursor during intro
265 event.type = kEvTOneshot;
266 event.code = kCursorEvent;
267 event.op = kEventHide;
268 _vm->_events->queue(event);
269
270 switch (_vm->getGameId()) {
271 case GID_ITE:
272 ITEStartProc();
273 break;
274 #ifdef ENABLE_IHNM
275 case GID_IHNM:
276 IHNMStartProc();
277 break;
278 #endif
279 #ifdef ENABLE_SAGA2
280 case GID_DINO:
281 DinoStartProc();
282 break;
283 case GID_FTA2:
284 FTA2StartProc();
285 break;
286 #endif
287 default:
288 error("Scene::start(): Error: Can't start game... gametype not supported");
289 break;
290 }
291
292 // Stop the intro music
293 _vm->_music->stop();
294
295 // Load the head in scene queue
296 queueIterator = _sceneQueue.begin();
297 if (queueIterator == _sceneQueue.end()) {
298 return;
299 }
300
301 loadScene(*queueIterator);
302 }
303
304 #ifdef ENABLE_IHNM
305
creditsScene()306 void Scene::creditsScene() {
307 // End the last game ending scene
308 _vm->_scene->endScene();
309 // We're not in the game anymore
310 _inGame = false;
311
312 // Hide cursor during credits
313 _vm->_gfx->showCursor(false);
314
315 switch (_vm->getGameId()) {
316 case GID_ITE:
317 // Not called by ITE
318 break;
319 case GID_IHNM:
320 IHNMCreditsProc();
321 break;
322 default:
323 error("Scene::creditsScene(): Error: Can't start credits scene... gametype not supported");
324 break;
325 }
326
327 _vm->quitGame();
328 return;
329 }
330
331 #endif
332
nextScene()333 void Scene::nextScene() {
334 SceneQueueList::iterator queueIterator;
335
336 if (!_sceneLoaded) {
337 error("Scene::next(): Error: Can't advance scene...no scene loaded");
338 }
339
340 if (_inGame) {
341 error("Scene::next(): Error: Can't advance scene...game already started");
342 }
343
344 endScene();
345
346 // Delete the current head in scene queue
347 queueIterator = _sceneQueue.begin();
348 if (queueIterator == _sceneQueue.end()) {
349 return;
350 }
351
352 queueIterator = _sceneQueue.erase(queueIterator);
353
354 if (queueIterator == _sceneQueue.end()) {
355 return;
356 }
357
358 // Load the head in scene queue
359 loadScene(*queueIterator);
360 }
361
skipScene()362 void Scene::skipScene() {
363 SceneQueueList::iterator queueIterator;
364
365 if (!_sceneLoaded) {
366 error("Scene::skip(): Error: Can't skip scene...no scene loaded");
367 }
368
369 if (_inGame) {
370 error("Scene::skip(): Error: Can't skip scene...game already started");
371 }
372
373 // Walk down scene queue and try to find a skip target
374 queueIterator = _sceneQueue.begin();
375 if (queueIterator == _sceneQueue.end()) {
376 error("Scene::skip(): Error: Can't skip scene...no scenes in queue");
377 }
378
379 ++queueIterator;
380 while (queueIterator != _sceneQueue.end()) {
381 if (queueIterator->sceneSkipTarget) {
382 // If skip target found, remove preceding scenes and load
383 _sceneQueue.erase(_sceneQueue.begin(), queueIterator);
384
385 endScene();
386
387 loadScene(*_sceneQueue.begin());
388 break;
389 }
390 ++queueIterator;
391 }
392
393 }
394
395 static struct SceneSubstitutes {
396 int sceneId;
397 const char *message;
398 const char *title;
399 const char *image;
400 } sceneSubstitutes[] = {
401 {
402 7,
403 "Tycho says he knows much about the northern lands. Can Rif convince "
404 "the Dog to share this knowledge?",
405 "The Home of Tycho Northpaw",
406 "tycho.bbm"
407 },
408
409 {
410 27,
411 "The scene of the crime may hold many clues, but will the servants of "
412 "the Sanctuary trust Rif?",
413 "The Sanctuary of the Orb",
414 "sanctuar.bbm"
415 },
416
417 {
418 5,
419 "The Rats hold many secrets that could guide Rif on his quest -- assuming "
420 "he can get past the doorkeeper.",
421 "The Rat Complex",
422 "ratdoor.bbm"
423 },
424
425 {
426 2,
427 "The Ferrets enjoy making things and have the materials to do so. How can "
428 "that help Rif?",
429 "The Ferret Village",
430 "ferrets.bbm"
431 },
432
433 {
434 67,
435 "What aid can the noble King of the Elks provide to Rif and his companions?",
436 "The Realm of the Forest King",
437 "elkenter.bbm"
438 },
439
440 {
441 3,
442 "The King holds Rif's sweetheart hostage. Will the Boar provide any "
443 "assistance to Rif?",
444 "The Great Hall of the Boar King",
445 "boarhall.bbm"
446 }
447 };
448
changeScene(int16 sceneNumber,int actorsEntrance,SceneTransitionType transitionType,int chapter)449 void Scene::changeScene(int16 sceneNumber, int actorsEntrance, SceneTransitionType transitionType, int chapter) {
450
451 debug(5, "Scene::changeScene(%d, %d, %d, %d)", sceneNumber, actorsEntrance, transitionType, chapter);
452
453 // This is used for latter ITE demos where all places on world map except
454 // Tent Faire are substituted with IFF picture and short description
455 if (_vm->_hasITESceneSubstitutes) {
456 for (int i = 0; i < ARRAYSIZE(sceneSubstitutes); i++) {
457 if (sceneSubstitutes[i].sceneId == sceneNumber) {
458 const byte *pal;
459 Common::File file;
460 Rect rect;
461 PalEntry cPal[PAL_ENTRIES];
462
463 _vm->_interface->setMode(kPanelSceneSubstitute);
464
465 if (file.open(sceneSubstitutes[i].image)) {
466 Image::IFFDecoder decoder;
467 decoder.loadStream(file);
468 pal = decoder.getPalette();
469 rect.setWidth(decoder.getSurface()->w);
470 rect.setHeight(decoder.getSurface()->h);
471 _vm->_gfx->drawRegion(rect, (const byte *)decoder.getSurface()->getPixels());
472 for (int j = 0; j < PAL_ENTRIES; j++) {
473 cPal[j].red = *pal++;
474 cPal[j].green = *pal++;
475 cPal[j].blue = *pal++;
476 }
477 _vm->_gfx->setPalette(cPal);
478
479 }
480
481 _vm->_interface->setStatusText("Click or Press Return to continue. Press Q to quit.", 96);
482 _vm->_font->textDrawRect(kKnownFontMedium, sceneSubstitutes[i].title,
483 Common::Rect(0, 7, _vm->getDisplayInfo().width, 27), _vm->KnownColor2ColorId(kKnownColorBrightWhite), _vm->KnownColor2ColorId(kKnownColorBlack), kFontOutline);
484 _vm->_font->textDrawRect(kKnownFontMedium, sceneSubstitutes[i].message,
485 Common::Rect(24, getHeight() - 33, _vm->getDisplayInfo().width - 11,
486 getHeight()), _vm->KnownColor2ColorId(kKnownColorBrightWhite), _vm->KnownColor2ColorId(kKnownColorBlack), kFontOutline);
487 return;
488 }
489 }
490 }
491
492 LoadSceneParams sceneParams;
493
494 sceneParams.actorsEntrance = actorsEntrance;
495 sceneParams.loadFlag = kLoadBySceneNumber;
496 sceneParams.sceneDescriptor = sceneNumber;
497 sceneParams.transitionType = transitionType;
498 sceneParams.sceneProc = NULL;
499 sceneParams.sceneSkipTarget = false;
500 sceneParams.chapter = chapter;
501
502 if (sceneNumber != -2) {
503 endScene();
504 }
505
506 loadScene(sceneParams);
507 }
508
getSlopes(int & beginSlope,int & endSlope)509 void Scene::getSlopes(int &beginSlope, int &endSlope) {
510 beginSlope = getHeight() - _sceneDescription.beginSlope;
511 endSlope = getHeight() - _sceneDescription.endSlope;
512 }
513
getBGInfo(BGInfo & bgInfo)514 void Scene::getBGInfo(BGInfo &bgInfo) {
515 bgInfo.buffer = _bg.buffer.getBuffer();
516 bgInfo.bounds.left = 0;
517 bgInfo.bounds.top = 0;
518
519 if (_bg.w < _vm->getDisplayInfo().width) {
520 bgInfo.bounds.left = (_vm->getDisplayInfo().width - _bg.w) / 2;
521 }
522
523 if (_bg.h < getHeight()) {
524 bgInfo.bounds.top = (getHeight() - _bg.h) / 2;
525 }
526
527 bgInfo.bounds.setWidth(_bg.w);
528 bgInfo.bounds.setHeight(_bg.h);
529 }
530
canWalk(const Point & testPoint)531 bool Scene::canWalk(const Point &testPoint) {
532 int maskType;
533
534 if (!_bgMask.loaded) {
535 return true;
536 }
537 if (!validBGMaskPoint(testPoint)) {
538 return true;
539 }
540
541 maskType = getBGMaskType(testPoint);
542 return getDoorState(maskType) == 0;
543 }
544
offscreenPath(Point & testPoint)545 bool Scene::offscreenPath(Point &testPoint) {
546 Point point;
547
548 if (!_bgMask.loaded) {
549 return false;
550 }
551
552 point.x = CLIP<int>(testPoint.x, 0, _vm->getDisplayInfo().width - 1);
553 point.y = CLIP<int>(testPoint.y, 0, _bgMask.h - 1);
554 if (point == testPoint) {
555 return false;
556 }
557
558 if (point.y >= _bgMask.h - 1) {
559 point.y = _bgMask.h - 2;
560 }
561 testPoint = point;
562
563 return true;
564 }
565
566
getBGMaskInfo(int & width,int & height,byte * & buffer)567 void Scene::getBGMaskInfo(int &width, int &height, byte *&buffer) {
568 if (!_bgMask.loaded) {
569 error("Scene::getBGMaskInfo _bgMask not loaded");
570 }
571
572 width = _bgMask.w;
573 height = _bgMask.h;
574 buffer = _bgMask.buffer.getBuffer();
575 }
576
initDoorsState()577 void Scene::initDoorsState() {
578 memcpy(_sceneDoors, initSceneDoors, sizeof (_sceneDoors) );
579 }
580
loadScene(LoadSceneParams & loadSceneParams)581 void Scene::loadScene(LoadSceneParams &loadSceneParams) {
582 Event event;
583 EventColumns *eventColumns;
584 static PalEntry current_pal[PAL_ENTRIES];
585
586 if (loadSceneParams.transitionType == kTransitionFade)
587 _vm->_interface->setFadeMode(kFadeOut);
588
589 // Change the cursor to an hourglass in IHNM
590 event.type = kEvTOneshot;
591 event.code = kCursorEvent;
592 event.op = kEventSetBusyCursor;
593 event.time = 0;
594 _vm->_events->queue(event);
595
596 _chapterPointsChanged = false;
597
598 #ifdef ENABLE_IHNM
599 if ((_vm->getGameId() == GID_IHNM) && (loadSceneParams.chapter != NO_CHAPTER_CHANGE)) {
600 if (loadSceneParams.loadFlag != kLoadBySceneNumber) {
601 error("loadScene wrong usage");
602 }
603
604 if (loadSceneParams.chapter == 6 || loadSceneParams.chapter == 8)
605 _vm->_interface->setLeftPortrait(0);
606
607 _vm->_anim->clearCutawayList();
608 _vm->_script->clearModules();
609
610 // deleteAllScenes();
611
612 // installSomeAlarm()
613
614 _vm->_interface->clearInventory();
615 _vm->_resource->loadGlobalResources(loadSceneParams.chapter, loadSceneParams.actorsEntrance);
616 _vm->_interface->addToInventory(IHNM_OBJ_PROFILE);
617 _vm->_interface->activate();
618
619 if (loadSceneParams.chapter == 8 || loadSceneParams.chapter == -1) {
620 if (!_vm->isIHNMDemo())
621 _vm->_interface->setMode(kPanelChapterSelection);
622 else
623 _vm->_interface->setMode(kPanelNull);
624 } else {
625 _vm->_interface->setMode(kPanelMain);
626 }
627
628 _inGame = true;
629
630 _vm->_script->setVerb(_vm->_script->getVerbType(kVerbWalkTo));
631
632 if (loadSceneParams.sceneDescriptor == -2) {
633 _vm->_interface->setFadeMode(kNoFade);
634 return;
635 }
636 }
637 #endif
638
639 if (_sceneLoaded) {
640 error("Scene::loadScene(): Error, a scene is already loaded");
641 }
642
643 #ifdef ENABLE_IHNM
644 if (_vm->getGameId() == GID_IHNM) {
645 if (loadSceneParams.loadFlag == kLoadBySceneNumber) // When will we get rid of it?
646 if (loadSceneParams.sceneDescriptor <= 0)
647 loadSceneParams.sceneDescriptor = _vm->_resource->getMetaResource()->sceneIndex;
648 }
649 #endif
650
651 switch (loadSceneParams.loadFlag) {
652 case kLoadByResourceId:
653 _sceneNumber = 0; // original assign zero for loaded by resource id
654 _sceneResourceId = loadSceneParams.sceneDescriptor;
655 break;
656 case kLoadBySceneNumber:
657 _sceneNumber = loadSceneParams.sceneDescriptor;
658 _sceneResourceId = getSceneResourceId(_sceneNumber);
659 break;
660 }
661
662 debug(3, "Loading scene number %d:", _sceneNumber);
663
664 if (isNonInteractiveIHNMDemoPart()) {
665 // WORKAROUND for the non-interactive part of the IHNM demo: When restarting the
666 // non-interactive demo, opcode sfMainMode is incorrectly called. Therefore, if any
667 // of the scenes of the non-interactive demo are loaded (scenes 144-149), set panel
668 // to null and lock the user interface
669 _vm->_interface->deactivate();
670 _vm->_interface->setMode(kPanelNull);
671 }
672
673 // Load scene descriptor and resource list resources
674 debug(3, "Loading scene resource %i", _sceneResourceId);
675
676 loadSceneDescriptor(_sceneResourceId);
677
678 SceneResourceDataArray resourceList;
679 loadSceneResourceList(_sceneDescription.resourceListResourceId, resourceList);
680
681 // Process resources from scene resource list
682 processSceneResources(resourceList);
683
684 if (_sceneDescription.flags & kSceneFlagISO) {
685 _outsetSceneNumber = _sceneNumber;
686
687 _sceneClip.left = 0;
688 _sceneClip.top = 0;
689 _sceneClip.right = _vm->getDisplayInfo().width;
690 _sceneClip.bottom = getHeight();
691 } else {
692 BGInfo backGroundInfo;
693 getBGInfo(backGroundInfo);
694 _sceneClip = backGroundInfo.bounds;
695 if (!(_bg.w < _vm->getDisplayInfo().width || _bg.h < getHeight()))
696 _outsetSceneNumber = _sceneNumber;
697 }
698
699 _sceneLoaded = true;
700
701 eventColumns = NULL;
702
703 if (loadSceneParams.transitionType == kTransitionFade) {
704
705 _vm->_interface->setFadeMode(kFadeOut);
706
707 // Fade to black out
708 _vm->_gfx->getCurrentPal(current_pal);
709 event.type = kEvTImmediate;
710 event.code = kPalEvent;
711 event.op = kEventPalToBlack;
712 event.time = 0;
713 event.duration = kNormalFadeDuration;
714 event.data = current_pal;
715 eventColumns = _vm->_events->queue(event);
716
717 // set fade mode
718 event.type = kEvTImmediate;
719 event.code = kInterfaceEvent;
720 event.op = kEventSetFadeMode;
721 event.param = kNoFade;
722 event.time = 0;
723 event.duration = 0;
724 _vm->_events->chain(eventColumns, event);
725
726 // Display scene background, but stay with black palette
727 event.type = kEvTImmediate;
728 event.code = kBgEvent;
729 event.op = kEventDisplay;
730 event.param = kEvPNoSetPalette;
731 event.time = 0;
732 event.duration = 0;
733 _vm->_events->chain(eventColumns, event);
734
735 }
736
737 // Start the scene pre script, but stay with black palette
738 if (_sceneDescription.startScriptEntrypointNumber > 0) {
739 event.type = kEvTOneshot;
740 event.code = kScriptEvent;
741 event.op = kEventExecBlocking;
742 event.time = 0;
743 event.param = _sceneDescription.scriptModuleNumber;
744 event.param2 = _sceneDescription.startScriptEntrypointNumber;
745 event.param3 = 0; // Action
746 event.param4 = _sceneNumber; // Object
747 event.param5 = loadSceneParams.actorsEntrance; // With Object
748 event.param6 = 0; // Actor
749 eventColumns = _vm->_events->chain(eventColumns, event);
750 }
751
752 if (loadSceneParams.transitionType == kTransitionFade) {
753
754 // set fade mode
755 event.type = kEvTImmediate;
756 event.code = kInterfaceEvent;
757 event.op = kEventSetFadeMode;
758 event.param = kFadeIn;
759 event.time = 0;
760 event.duration = 0;
761 eventColumns = _vm->_events->chain(eventColumns, event);
762
763 // Fade in from black to the scene background palette
764 event.type = kEvTImmediate;
765 event.code = kPalEvent;
766 event.op = kEventBlackToPal;
767 event.time = 0;
768 event.duration = kNormalFadeDuration;
769 event.data = _bg.pal;
770 _vm->_events->chain(eventColumns, event);
771
772 // set fade mode
773 event.type = kEvTImmediate;
774 event.code = kInterfaceEvent;
775 event.op = kEventSetFadeMode;
776 event.param = kNoFade;
777 event.time = 0;
778 event.duration = 0;
779 _vm->_events->chain(eventColumns, event);
780 }
781
782 if (loadSceneParams.sceneProc == NULL) {
783 if (!_inGame && _vm->getGameId() == GID_ITE) {
784 _inGame = true;
785 _vm->_interface->setMode(kPanelMain);
786 }
787
788 _vm->_sound->stopAll();
789
790 if (_vm->getGameId() == GID_ITE) {
791 if (_sceneDescription.musicResourceId >= 0) {
792 _vm->_events->queueMusic(_sceneDescription.musicResourceId);
793 } else {
794 event.type = kEvTOneshot;
795 event.code = kMusicEvent;
796 event.op = kEventStop;
797 event.time = 0;
798 _vm->_events->queue(event);
799 }
800 }
801
802 // Set scene background
803 event.type = kEvTOneshot;
804 event.code = kBgEvent;
805 event.op = kEventDisplay;
806 event.param = kEvPSetPalette;
807 event.time = 0;
808 _vm->_events->queue(event);
809
810 // Begin palette cycle animation if present
811 event.type = kEvTOneshot;
812 event.code = kPalAnimEvent;
813 event.op = kEventCycleStart;
814 event.time = 0;
815 _vm->_events->queue(event);
816
817 // Start the scene main script
818 if (_sceneDescription.sceneScriptEntrypointNumber > 0) {
819 event.type = kEvTOneshot;
820 event.code = kScriptEvent;
821 event.op = kEventExecNonBlocking;
822 event.time = 0;
823 event.param = _sceneDescription.scriptModuleNumber;
824 event.param2 = _sceneDescription.sceneScriptEntrypointNumber;
825 event.param3 = _vm->_script->getVerbType(kVerbEnter); // Action
826 event.param4 = _sceneNumber; // Object
827 event.param5 = loadSceneParams.actorsEntrance; // With Object
828 event.param6 = 0; // Actor
829 _vm->_events->queue(event);
830 }
831
832 debug(3, "Scene started");
833
834 } else {
835 loadSceneParams.sceneProc(SCENE_BEGIN, this);
836 }
837
838 if (_vm->getGameId() == GID_ITE && _sceneNumber == ITE_SCENE_PUZZLE) {
839 _vm->_puzzle->execute();
840 } else {
841 // We probably don't want "followers" to go into scene -1 , 0. At the very
842 // least we don't want garbage to be drawn that early in the ITE intro.
843 if (_sceneNumber > 0)
844 _vm->_actor->updateActorsScene(loadSceneParams.actorsEntrance);
845 }
846
847 if (getFlags() & kSceneFlagShowCursor) {
848 // Activate user interface
849 event.type = kEvTOneshot;
850 event.code = kInterfaceEvent;
851 event.op = kEventActivate;
852 event.time = 0;
853 _vm->_events->queue(event);
854 }
855
856 // Change the cursor back to a crosshair in IHNM
857 event.type = kEvTOneshot;
858 event.code = kCursorEvent;
859 event.op = kEventSetNormalCursor;
860 event.time = 0;
861 _vm->_events->queue(event);
862 }
863
loadSceneDescriptor(uint32 resourceId)864 void Scene::loadSceneDescriptor(uint32 resourceId) {
865 ByteArray sceneDescriptorData;
866
867 _sceneDescription.reset();
868
869 if (resourceId == 0)
870 return;
871
872 _vm->_resource->loadResource(_sceneContext, resourceId, sceneDescriptorData);
873 ByteArrayReadStreamEndian readS(sceneDescriptorData, _sceneContext->isBigEndian());
874
875 if (sceneDescriptorData.size() == 14 || sceneDescriptorData.size() == 16) {
876 _sceneDescription.flags = readS.readSint16();
877 _sceneDescription.resourceListResourceId = readS.readSint16();
878 _sceneDescription.endSlope = readS.readSint16();
879 _sceneDescription.beginSlope = readS.readSint16();
880 _sceneDescription.scriptModuleNumber = readS.readUint16();
881 _sceneDescription.sceneScriptEntrypointNumber = readS.readUint16();
882 _sceneDescription.startScriptEntrypointNumber = readS.readUint16();
883 if (sceneDescriptorData.size() == 16)
884 _sceneDescription.musicResourceId = readS.readSint16();
885 } else {
886 warning("Scene::loadSceneDescriptor: Unknown scene descriptor data size (%d)", sceneDescriptorData.size());
887 }
888 }
889
loadSceneResourceList(uint32 resourceId,SceneResourceDataArray & resourceList)890 void Scene::loadSceneResourceList(uint32 resourceId, SceneResourceDataArray &resourceList) {
891 ByteArray resourceListData;
892
893 resourceList.clear();
894
895 if (resourceId == 0) {
896 return;
897 }
898
899 // Load the scene resource table
900 _vm->_resource->loadResource(_sceneContext, resourceId, resourceListData);
901
902 if ((resourceListData.size() % SAGA_RESLIST_ENTRY_LEN) == 0) {
903 ByteArrayReadStreamEndian readS(resourceListData, _sceneContext->isBigEndian());
904
905 // Allocate memory for scene resource list
906 resourceList.resize(resourceListData.size() / SAGA_RESLIST_ENTRY_LEN);
907 debug(3, "Scene resource list contains %i entries", (int)resourceList.size());
908
909 // Load scene resource list from raw scene
910 // resource table
911 debug(3, "Loading scene resource list");
912
913 for (SceneResourceDataArray::iterator resource = resourceList.begin(); resource != resourceList.end(); ++resource) {
914 resource->resourceId = readS.readUint16();
915 resource->resourceType = readS.readUint16();
916 // demo version may contain invalid resourceId
917 resource->invalid = !_sceneContext->validResourceId(resource->resourceId);
918 }
919
920 }
921 }
922
processSceneResources(SceneResourceDataArray & resourceList)923 void Scene::processSceneResources(SceneResourceDataArray &resourceList) {
924 ByteArray resourceData;
925 const byte *palPointer;
926 SAGAResourceTypes *types = 0;
927 int typesCount = 0;
928 SAGAResourceTypes resType;
929
930 getResourceTypes(types, typesCount);
931
932 // Process the scene resource list
933 for (SceneResourceDataArray::iterator resource = resourceList.begin(); resource != resourceList.end(); ++resource) {
934 if (resource->invalid) {
935 continue;
936 }
937 _vm->_resource->loadResource(_sceneContext, resource->resourceId, resourceData);
938
939
940 if (resourceData.size() >= 6) {
941 if (!memcmp(resourceData.getBuffer(), "DUMMY!", 6)) {
942 resource->invalid = true;
943 warning("DUMMY resource %i", resource->resourceId);
944 }
945 }
946
947 if (resource->invalid) {
948 continue;
949 }
950
951 if (resource->resourceType >= typesCount) {
952 error("Scene::processSceneResources() wrong resource type %i", resource->resourceType);
953 }
954
955 resType = types[resource->resourceType];
956
957 switch (resType) {
958 case SAGA_UNKNOWN:
959 warning("UNKNOWN resourceType %i", resource->resourceType);
960 break;
961 case SAGA_ACTOR:
962 //for (a = actorsInScene; a; a = a->nextInScene)
963 // if (a->obj.figID == glist->file_id)
964 // if (_vm->getGameId() == GID_ITE ||
965 // ((a->obj.flags & ACTORF_FINAL_FACE) & 0xff))
966 // a->sprites = (xSpriteSet *)glist->offset;
967 warning("STUB: unimplemeted handler of SAGA_ACTOR resource");
968 break;
969 case SAGA_OBJECT:
970 break;
971 case SAGA_BG_IMAGE: // Scene background resource
972 if (_bg.loaded)
973 error("Scene::processSceneResources() Multiple background resources encountered");
974
975 debug(3, "Loading background resource.");
976
977 if (!_vm->decodeBGImage(resourceData,
978 _bg.buffer,
979 &_bg.w,
980 &_bg.h)) {
981 error("Scene::processSceneResources() Error loading background resource %i", resource->resourceId);
982 }
983 _bg.loaded = true;
984
985 palPointer = _vm->getImagePal(resourceData);
986 memcpy(_bg.pal, palPointer, sizeof(_bg.pal));
987 break;
988 case SAGA_BG_MASK: // Scene background mask resource
989 if (_bgMask.loaded)
990 error("Scene::ProcessSceneResources(): Duplicate background mask resource encountered");
991
992 debug(3, "Loading BACKGROUND MASK resource.");
993 _vm->decodeBGImage(resourceData, _bgMask.buffer, &_bgMask.w, &_bgMask.h, true);
994 _bgMask.loaded = true;
995
996 // At least in ITE the mask needs to be clipped.
997
998 _bgMask.w = MIN(_bgMask.w, _vm->getDisplayInfo().width);
999 _bgMask.h = MIN(_bgMask.h, getHeight());
1000
1001 debug(4, "BACKGROUND MASK width=%d height=%d length=%d", _bgMask.w, _bgMask.h, _bgMask.buffer.size());
1002 break;
1003 case SAGA_STRINGS:
1004 debug(3, "Loading scene strings resource...");
1005 _vm->loadStrings(_sceneStrings, resourceData);
1006 break;
1007 case SAGA_OBJECT_MAP:
1008 debug(3, "Loading object map resource...");
1009 _objectMap->load(resourceData);
1010 break;
1011 case SAGA_ACTION_MAP:
1012 debug(3, "Loading action map resource...");
1013 _actionMap->load(resourceData);
1014 break;
1015 case SAGA_ISO_IMAGES:
1016 if (!(_sceneDescription.flags & kSceneFlagISO))
1017 error("Scene::ProcessSceneResources(): not Iso mode");
1018
1019 debug(3, "Loading isometric images resource.");
1020
1021 _vm->_isoMap->loadImages(resourceData);
1022 break;
1023 case SAGA_ISO_MAP:
1024 if (!(_sceneDescription.flags & kSceneFlagISO))
1025 error("Scene::ProcessSceneResources(): not Iso mode");
1026
1027 debug(3, "Loading isometric map resource.");
1028 _vm->_isoMap->loadMap(resourceData);
1029 break;
1030 case SAGA_ISO_PLATFORMS:
1031 if (!(_sceneDescription.flags & kSceneFlagISO))
1032 error("Scene::ProcessSceneResources(): not Iso mode");
1033
1034 debug(3, "Loading isometric platforms resource.");
1035 _vm->_isoMap->loadPlatforms(resourceData);
1036 break;
1037 case SAGA_ISO_METATILES:
1038 if (!(_sceneDescription.flags & kSceneFlagISO))
1039 error("Scene::ProcessSceneResources(): not Iso mode");
1040
1041 debug(3, "Loading isometric metatiles resource.");
1042 _vm->_isoMap->loadMetaTiles(resourceData);
1043 break;
1044 case SAGA_ANIM:
1045 {
1046 uint16 animId = resource->resourceType - 14;
1047 debug(3, "Loading animation resource animId=%i", animId);
1048 _vm->_anim->load(animId, resourceData);
1049 }
1050 break;
1051 case SAGA_ENTRY:
1052 debug(3, "Loading entry list resource...");
1053 loadSceneEntryList(resourceData);
1054 break;
1055 case SAGA_ISO_MULTI:
1056 if (!(_sceneDescription.flags & kSceneFlagISO))
1057 error("Scene::ProcessSceneResources(): not Iso mode");
1058
1059 debug(3, "Loading isometric multi resource.");
1060
1061 _vm->_isoMap->loadMulti(resourceData);
1062 break;
1063 case SAGA_PAL_ANIM:
1064 debug(3, "Loading palette animation resource.");
1065 _vm->_palanim->loadPalAnim(resourceData);
1066 break;
1067 case SAGA_FACES:
1068 if (_vm->getGameId() == GID_ITE)
1069 _vm->_interface->loadScenePortraits(resource->resourceId);
1070 break;
1071 case SAGA_PALETTE:
1072 {
1073 PalEntry pal[PAL_ENTRIES];
1074 byte *palPtr = resourceData.getBuffer();
1075
1076 if (resourceData.size() < 3 * PAL_ENTRIES)
1077 error("Too small scene palette %i", (int)resourceData.size());
1078
1079 for (uint16 c = 0; c < PAL_ENTRIES; c++) {
1080 pal[c].red = *palPtr++;
1081 pal[c].green = *palPtr++;
1082 pal[c].blue = *palPtr++;
1083 }
1084 _vm->_gfx->setPalette(pal);
1085 }
1086 break;
1087 default:
1088 error("Scene::ProcessSceneResources() Encountered unknown resource type %i", resource->resourceType);
1089 break;
1090 }
1091 }
1092 }
1093
draw()1094 void Scene::draw() {
1095 // Do nothing for SAGA2 games for now
1096 if (_vm->isSaga2()) {
1097 return;
1098 }
1099
1100 if (_sceneDescription.flags & kSceneFlagISO) {
1101 _vm->_isoMap->adjustScroll(false);
1102 _vm->_isoMap->draw();
1103 } else {
1104 Rect rect;
1105 _vm->_render->getBackGroundSurface()->getRect(rect);
1106 rect.bottom = (_sceneClip.bottom < rect.bottom) ? getHeight() : rect.bottom;
1107 if (_vm->_render->isFullRefresh())
1108 _vm->_gfx->drawRegion(rect, (const byte *)_vm->_render->getBackGroundSurface()->getPixels());
1109 else
1110 _vm->_gfx->drawBgRegion(rect, (const byte *)_vm->_render->getBackGroundSurface()->getPixels());
1111 }
1112 }
1113
endScene()1114 void Scene::endScene() {
1115 Rect rect;
1116
1117 if (!_sceneLoaded)
1118 return;
1119
1120 debug(3, "Ending scene...");
1121
1122 if (_sceneProc != NULL) {
1123 _sceneProc(SCENE_END, this);
1124 }
1125
1126 // Stop showing actors till the next scene's background is drawn from loadScene
1127 _vm->_render->setFlag(RF_DISABLE_ACTORS);
1128
1129 _vm->_script->abortAllThreads();
1130 _vm->_script->_skipSpeeches = false;
1131
1132 // WORKAROUND: Bug #2886151: "ITE: Mouse stops responding at Boar Castle"
1133 // This is bug in original engine
1134 if (_sceneNumber == 50) {
1135 _vm->_interface->activate();
1136 }
1137
1138 // Copy current screen to render buffer so inset rooms will get proper background
1139 if (!(_sceneDescription.flags & kSceneFlagISO) && !_vm->_scene->isInIntro()) {
1140 BGInfo bgInfo;
1141
1142 _vm->_scene->getBGInfo(bgInfo);
1143 _vm->_render->getBackGroundSurface()->blit(bgInfo.bounds, bgInfo.buffer);
1144 _vm->_render->addDirtyRect(bgInfo.bounds);
1145 } else {
1146 _vm->_gfx->getBackBufferRect(rect);
1147 _vm->_render->getBackGroundSurface()->blit(rect, (const byte *)_vm->_gfx->getBackBufferPixels());
1148 _vm->_render->addDirtyRect(rect);
1149 }
1150
1151 // Free scene background
1152 if (_bg.loaded) {
1153 _bg.buffer.clear();
1154 _bg.loaded = false;
1155 }
1156
1157 // Free scene background mask
1158 if (_bgMask.loaded) {
1159 _bgMask.buffer.clear();
1160 _bgMask.loaded = false;
1161 }
1162
1163 // Free animation info list
1164 _vm->_anim->reset();
1165
1166 _vm->_palanim->clear();
1167
1168 _objectMap->clear();
1169 _actionMap->clear();
1170 _entryList.clear();
1171 _sceneStrings.clear();
1172
1173 if (_vm->getGameId() == GID_ITE)
1174 _vm->_isoMap->clear();
1175
1176 _vm->_events->clearList();
1177 _textList.clear();
1178
1179 _sceneLoaded = false;
1180 }
1181
restoreScene()1182 void Scene::restoreScene() {
1183 // There is no implementation for tiled scenes, since this function is only used
1184 // in IHNM, which has no tiled scenes
1185
1186 Event event;
1187
1188 _vm->_gfx->showCursor(false);
1189 _vm->_gfx->restorePalette();
1190
1191 event.type = kEvTImmediate;
1192 event.code = kBgEvent;
1193 event.op = kEventDisplay;
1194 event.param = kEvPNoSetPalette;
1195 event.time = 0;
1196 event.duration = 0;
1197 _vm->_events->queue(event);
1198
1199 _vm->_gfx->showCursor(true);
1200 }
1201
cmdSceneChange(int argc,const char ** argv)1202 void Scene::cmdSceneChange(int argc, const char **argv) {
1203 int scene_num = 0;
1204
1205 scene_num = atoi(argv[1]);
1206
1207 if ((scene_num < 1) || (uint(scene_num) >= _sceneLUT.size())) {
1208 _vm->_console->debugPrintf("Invalid scene number.\n");
1209 return;
1210 }
1211
1212 clearSceneQueue();
1213
1214 changeScene(scene_num, 0, kTransitionNoFade);
1215 }
1216
cmdActionMapInfo()1217 void Scene::cmdActionMapInfo() {
1218 _actionMap->cmdInfo();
1219 }
1220
cmdObjectMapInfo()1221 void Scene::cmdObjectMapInfo() {
1222 _objectMap->cmdInfo();
1223 }
1224
loadSceneEntryList(const ByteArray & resourceData)1225 void Scene::loadSceneEntryList(const ByteArray &resourceData) {
1226 uint i;
1227
1228 if (!_entryList.empty()) {
1229 error("Scene::loadSceneEntryList entryList not empty");
1230 }
1231
1232 _entryList.resize(resourceData.size() / 8);
1233
1234 ByteArrayReadStreamEndian readS(resourceData, _sceneContext->isBigEndian());
1235
1236 for (i = 0; i < _entryList.size(); i++) {
1237 _entryList[i].location.x = readS.readSint16();
1238 _entryList[i].location.y = readS.readSint16();
1239 _entryList[i].location.z = readS.readSint16();
1240 _entryList[i].facing = readS.readUint16();
1241 }
1242 }
1243
clearPlacard()1244 void Scene::clearPlacard() {
1245 static PalEntry cur_pal[PAL_ENTRIES];
1246 Event event;
1247 EventColumns *eventColumns;
1248
1249 _vm->_interface->setFadeMode(kFadeOut);
1250
1251 // Fade to black out
1252 _vm->_gfx->getCurrentPal(cur_pal);
1253 event.type = kEvTImmediate;
1254 event.code = kPalEvent;
1255 event.op = kEventPalToBlack;
1256 event.time = 0;
1257 event.duration = kNormalFadeDuration;
1258 event.data = cur_pal;
1259 eventColumns = _vm->_events->queue(event);
1260
1261 // set fade mode
1262 event.type = kEvTImmediate;
1263 event.code = kInterfaceEvent;
1264 event.op = kEventSetFadeMode;
1265 event.param = kNoFade;
1266 event.time = 0;
1267 event.duration = 0;
1268 _vm->_events->chain(eventColumns, event);
1269
1270 if (_vm->getGameId() == GID_ITE) {
1271 event.type = kEvTOneshot;
1272 event.code = kTextEvent;
1273 event.op = kEventRemove;
1274 event.data = _vm->_script->getPlacardTextEntry();
1275 _vm->_events->chain(eventColumns, event);
1276 } else {
1277 _vm->_scene->_textList.clear();
1278 }
1279
1280 event.type = kEvTImmediate;
1281 event.code = kInterfaceEvent;
1282 event.op = kEventRestoreMode;
1283 event.time = 0;
1284 event.duration = 0;
1285 _vm->_events->chain(eventColumns, event);
1286
1287 #ifdef ENABLE_IHNM
1288 if (_vm->getGameId() == GID_IHNM) {
1289 // set mode to main
1290 event.type = kEvTImmediate;
1291 event.code = kInterfaceEvent;
1292 event.op = kEventSetMode;
1293 event.param = kPanelMain;
1294 event.time = 0;
1295 event.duration = 0;
1296 _vm->_events->chain(eventColumns, event);
1297 }
1298 #endif
1299
1300 // Display scene background, but stay with black palette
1301 event.type = kEvTImmediate;
1302 event.code = kBgEvent;
1303 event.op = kEventDisplay;
1304 event.param = kEvPNoSetPalette;
1305 event.time = 0;
1306 event.duration = 0;
1307 _vm->_events->chain(eventColumns, event);
1308
1309 // set fade mode
1310 event.type = kEvTImmediate;
1311 event.code = kInterfaceEvent;
1312 event.op = kEventSetFadeMode;
1313 event.param = kFadeIn;
1314 event.time = 0;
1315 event.duration = 0;
1316 _vm->_events->chain(eventColumns, event);
1317
1318 // Fade in from black to the scene background palette
1319 event.type = kEvTImmediate;
1320 event.code = kPalEvent;
1321 event.op = kEventBlackToPal;
1322 event.time = 0;
1323 event.duration = kNormalFadeDuration;
1324 event.data = _bg.pal;
1325 _vm->_events->chain(eventColumns, event);
1326
1327 // set fade mode
1328 event.type = kEvTImmediate;
1329 event.code = kInterfaceEvent;
1330 event.op = kEventSetFadeMode;
1331 event.param = kNoFade;
1332 event.time = 0;
1333 event.duration = 0;
1334 _vm->_events->chain(eventColumns, event);
1335
1336 event.type = kEvTOneshot;
1337 event.code = kCursorEvent;
1338 event.op = kEventShow;
1339 _vm->_events->chain(eventColumns, event);
1340
1341 event.type = kEvTOneshot;
1342 event.code = kScriptEvent;
1343 event.op = kEventThreadWake;
1344 event.param = kWaitTypePlacard;
1345 _vm->_events->chain(eventColumns, event);
1346 }
1347
1348 #ifdef ENABLE_IHNM
1349
showPsychicProfile(const char * text)1350 void Scene::showPsychicProfile(const char *text) {
1351 int textHeight;
1352 static PalEntry cur_pal[PAL_ENTRIES];
1353 PalEntry *pal;
1354 TextListEntry textEntry;
1355 Event event;
1356 EventColumns *eventColumns;
1357
1358 if (_vm->_interface->getMode() == kPanelPlacard)
1359 return;
1360
1361 _vm->_interface->rememberMode();
1362 _vm->_interface->setMode(kPanelPlacard);
1363 _vm->_gfx->savePalette();
1364
1365 _vm->_events->clearList();
1366
1367 event.type = kEvTOneshot;
1368 event.code = kCursorEvent;
1369 event.op = kEventHide;
1370 eventColumns = _vm->_events->queue(event);
1371
1372 _vm->_interface->setFadeMode(kFadeOut);
1373
1374 // Fade to black out
1375 _vm->_gfx->getCurrentPal(cur_pal);
1376 event.type = kEvTImmediate;
1377 event.code = kPalEvent;
1378 event.op = kEventPalToBlack;
1379 event.time = 0;
1380 event.duration = kNormalFadeDuration;
1381 event.data = cur_pal;
1382 _vm->_events->chain(eventColumns, event);
1383
1384 // set fade mode
1385 event.type = kEvTImmediate;
1386 event.code = kInterfaceEvent;
1387 event.op = kEventSetFadeMode;
1388 event.param = kNoFade;
1389 event.time = 0;
1390 event.duration = 0;
1391 _vm->_events->chain(eventColumns, event);
1392
1393 event.type = kEvTOneshot;
1394 event.code = kInterfaceEvent;
1395 event.op = kEventClearStatus;
1396 _vm->_events->chain(eventColumns, event);
1397
1398 // Set the background and palette for the psychic profile
1399 event.type = kEvTOneshot;
1400 event.code = kPsychicProfileBgEvent;
1401 _vm->_events->chain(eventColumns, event);
1402
1403 _vm->_scene->_textList.clear();
1404
1405 if (text != NULL) {
1406 textHeight = _vm->_font->getHeight(kKnownFontVerb, text, 226, kFontCentered);
1407
1408 textEntry.knownColor = kKnownColorBlack;
1409 textEntry.useRect = true;
1410 textEntry.rect.left = 245;
1411 textEntry.rect.setHeight(210 + 76);
1412 textEntry.rect.setWidth(226);
1413 textEntry.rect.top = 210 - textHeight;
1414 textEntry.font = kKnownFontVerb;
1415 textEntry.flags = (FontEffectFlags)(kFontCentered);
1416 textEntry.text = text;
1417
1418 TextListEntry *_psychicProfileTextEntry = _vm->_scene->_textList.addEntry(textEntry);
1419
1420 event.type = kEvTOneshot;
1421 event.code = kTextEvent;
1422 event.op = kEventDisplay;
1423 event.data = _psychicProfileTextEntry;
1424 _vm->_events->chain(eventColumns, event);
1425 }
1426
1427 _vm->_scene->getBGPal(pal);
1428
1429 event.type = kEvTImmediate;
1430 event.code = kPalEvent;
1431 event.op = kEventBlackToPal;
1432 event.time = 0;
1433 event.duration = kNormalFadeDuration;
1434 event.data = pal;
1435 _vm->_events->chain(eventColumns, event);
1436
1437 event.type = kEvTOneshot;
1438 event.code = kScriptEvent;
1439 event.op = kEventThreadWake;
1440 event.param = kWaitTypePlacard;
1441 _vm->_events->chain(eventColumns, event);
1442 }
1443
clearPsychicProfile()1444 void Scene::clearPsychicProfile() {
1445 if (_vm->_interface->getMode() == kPanelPlacard || _vm->isIHNMDemo()) {
1446 _vm->_render->setFlag(RF_DISABLE_ACTORS);
1447 _vm->_scene->clearPlacard();
1448 _vm->_interface->activate();
1449 }
1450 }
1451
showIHNMDemoSpecialScreen()1452 void Scene::showIHNMDemoSpecialScreen() {
1453 _vm->_gfx->showCursor(true);
1454 _vm->_interface->clearInventory();
1455 _vm->_scene->changeScene(150, 0, kTransitionFade);
1456 }
1457
1458 #endif // IHNM
1459
1460 } // End of namespace Saga
1461