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