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 
24 #include "common/system.h"
25 #include "scumm/actor.h"
26 #include "scumm/boxes.h"
27 #ifdef ENABLE_HE
28 #include "scumm/he/intern_he.h"
29 #endif
30 #include "scumm/object.h"
31 #include "scumm/resource.h"
32 #include "scumm/scumm_v3.h"
33 #include "scumm/sound.h"
34 #include "scumm/util.h"
35 
36 namespace Scumm {
37 
38 /**
39  * Start a 'scene' by loading the specified room with the given main actor.
40  * The actor is placed next to the object indicated by objectNr.
41  */
startScene(int room,Actor * a,int objectNr)42 void ScummEngine::startScene(int room, Actor *a, int objectNr) {
43 	int i, where;
44 
45 	debugC(DEBUG_GENERAL, "Loading room %d", room);
46 
47 	stopTalk();
48 
49 	fadeOut(_switchRoomEffect2);
50 	_newEffect = _switchRoomEffect;
51 
52 	ScriptSlot *ss = &vm.slot[_currentScript];
53 
54 	if (_currentScript != 0xFF) {
55 		if (ss->where == WIO_ROOM || ss->where == WIO_FLOBJECT) {
56 			if (ss->cutsceneOverride && _game.version >= 5)
57 				error("Object %d stopped with active cutscene/override in exit", ss->number);
58 
59 			nukeArrays(_currentScript);
60 			_currentScript = 0xFF;
61 		} else if (ss->where == WIO_LOCAL) {
62 			if (ss->cutsceneOverride && _game.version >= 5)
63 				error("Script %d stopped with active cutscene/override in exit", ss->number);
64 
65 			nukeArrays(_currentScript);
66 			_currentScript = 0xFF;
67 		}
68 	}
69 
70 	if (VAR_NEW_ROOM != 0xFF)
71 		VAR(VAR_NEW_ROOM) = room;
72 
73 	runExitScript();
74 
75 	killScriptsAndResources();
76 	if (_game.version >= 4 && _game.heversion <= 62)
77 		stopCycle(0);
78 
79 	if (_game.id == GID_SAMNMAX) {
80 		// WORKAROUND bug #1132 SAM: Overlapping music at Bigfoot convention
81 		// Added sound queue processing between execution of exit
82 		// script and entry script. In the case of this bug, the
83 		// entry script required that the iMuse state be fully up
84 		// to date, including last-moment changes from the previous
85 		// exit script.
86 		_sound->processSound();
87 	}
88 
89 	clearDrawQueues();
90 
91 	// For HE80+ games
92 	for (i = 0; i < _numRoomVariables; i++)
93 		_roomVars[i] = 0;
94 	nukeArrays(0xFF);
95 
96 	for (i = 1; i < _numActors; i++) {
97 		_actors[i]->hideActor();
98 	}
99 
100 	if (_game.version >= 7) {
101 		// Set the shadow palette(s) to all black. This fixes
102 		// bug #1196, and actually makes some sense (after all,
103 		// shadows tend to be rather black, don't they? ;-)
104 		memset(_shadowPalette, 0, NUM_SHADOW_PALETTE * 256);
105 	} else {
106 		for (i = 0; i < 256; i++) {
107 			_roomPalette[i] = i;
108 			if (_shadowPalette)
109 				_shadowPalette[i] = i;
110 		}
111 		if (_game.features & GF_SMALL_HEADER)
112 			setDirtyColors(0, 255);
113 	}
114 
115 	VAR(VAR_ROOM) = room;
116 	_fullRedraw = true;
117 
118 	_res->increaseResourceCounters();
119 
120 	_currentRoom = room;
121 	VAR(VAR_ROOM) = room;
122 
123 	if (room >= 0x80 && _game.version < 7 && _game.heversion <= 71)
124 		_roomResource = _resourceMapper[room & 0x7F];
125 	else
126 		_roomResource = room;
127 
128 	if (VAR_ROOM_RESOURCE != 0xFF)
129 		VAR(VAR_ROOM_RESOURCE) = _roomResource;
130 
131 	if (room != 0)
132 		ensureResourceLoaded(rtRoom, room);
133 
134 	clearRoomObjects();
135 
136 	if (_currentRoom == 0) {
137 		_ENCD_offs = _EXCD_offs = 0;
138 		_numObjectsInRoom = 0;
139 		return;
140 	}
141 
142 	setupRoomSubBlocks();
143 	resetRoomSubBlocks();
144 
145 	initBGBuffers(_roomHeight);
146 
147 	resetRoomObjects();
148 
149 	if (VAR_ROOM_WIDTH != 0xFF && VAR_ROOM_HEIGHT != 0xFF) {
150 		VAR(VAR_ROOM_WIDTH) = _roomWidth;
151 		VAR(VAR_ROOM_HEIGHT) = _roomHeight;
152 	}
153 
154 	if (VAR_CAMERA_MIN_X != 0xFF)
155 		VAR(VAR_CAMERA_MIN_X) = _screenWidth / 2;
156 	if (VAR_CAMERA_MAX_X != 0xFF)
157 		VAR(VAR_CAMERA_MAX_X) = _roomWidth - (_screenWidth / 2);
158 
159 	if (_game.version >= 7) {
160 		VAR(VAR_CAMERA_MIN_Y) = _screenHeight / 2;
161 		VAR(VAR_CAMERA_MAX_Y) = _roomHeight - (_screenHeight / 2);
162 		setCameraAt(_screenWidth / 2, _screenHeight / 2);
163 	} else {
164 		camera._mode = kNormalCameraMode;
165 		if (_game.version > 2)
166 			camera._cur.x = camera._dest.x = _screenWidth / 2;
167 		camera._cur.y = camera._dest.y = _screenHeight / 2;
168 	}
169 
170 	if (_roomResource == 0)
171 		return;
172 
173 	memset(gfxUsageBits, 0, sizeof(gfxUsageBits));
174 
175 	if (_game.version >= 5 && a) {
176 		where = whereIsObject(objectNr);
177 		if (where != WIO_ROOM && where != WIO_FLOBJECT)
178 			error("startScene: Object %d is not in room %d", objectNr,
179 					_currentRoom);
180 		int x, y, dir;
181 		getObjectXYPos(objectNr, x, y, dir);
182 		a->putActor(x, y, _currentRoom);
183 		a->setDirection(dir + 180);
184 		a->stopActorMoving();
185 		if (_game.id == GID_SAMNMAX) {
186 			camera._cur.x = camera._dest.x = a->getPos().x;
187 			setCameraAt(a->getPos().x, a->getPos().y);
188 		}
189 	}
190 
191 	showActors();
192 
193 	_egoPositioned = false;
194 
195 #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE
196 	towns_resetPalCycleFields();
197 #endif
198 
199 	runEntryScript();
200 	if (_game.version >= 1 && _game.version <= 2) {
201 		runScript(5, 0, 0, 0);
202 	} else if (_game.version >= 5 && _game.version <= 6) {
203 		if (a && !_egoPositioned) {
204 			int x, y;
205 			getObjectXYPos(objectNr, x, y);
206 			a->putActor(x, y, _currentRoom);
207 			a->_moving = 0;
208 		}
209 	} else if (_game.version >= 7) {
210 		if (camera._follows) {
211 			a = derefActor(camera._follows, "startScene: follows");
212 			setCameraAt(a->getPos().x, a->getPos().y);
213 		}
214 	}
215 
216 	_doEffect = true;
217 
218 	// Hint the backend about the virtual keyboard during copy protection screens
219 	if (_game.id == GID_MONKEY2) {
220 		if (_system->getFeatureState(OSystem::kFeatureVirtualKeyboard)) {
221 			if (room != 108)
222 				_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
223 		} else if (room == 108)
224 			_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
225 	} else if (_game.id == GID_MONKEY_EGA) {	// this is my estimation that the room code is 90 (untested)
226 		if (_system->getFeatureState(OSystem::kFeatureVirtualKeyboard)) {
227 			if (room != 90)
228 				_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
229 		} else if (room == 90)
230 			_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
231 	}
232 
233 }
234 
235 /**
236  * Init some static room data after a room has been loaded.
237  * E.g. the room dimension, the offset to the graphics data, the room scripts,
238  * the offset to the room palette and other things which won't be changed
239  * late on.
240  * So it is possible to call this after loading a savegame.
241  */
setupRoomSubBlocks()242 void ScummEngine::setupRoomSubBlocks() {
243 	int i;
244 	const byte *ptr;
245 	byte *roomptr, *searchptr, *roomResPtr = 0;
246 	const RoomHeader *rmhd;
247 
248 	_ENCD_offs = 0;
249 	_EXCD_offs = 0;
250 	_EPAL_offs = 0;
251 	_CLUT_offs = 0;
252 	_PALS_offs = 0;
253 
254 	// Determine the room and room script base address
255 	roomResPtr = roomptr = getResourceAddress(rtRoom, _roomResource);
256 	if (_game.version == 8)
257 		roomResPtr = getResourceAddress(rtRoomScripts, _roomResource);
258 	if (!roomptr || !roomResPtr)
259 		error("Room %d: data not found (" __FILE__  ":%d)", _roomResource, __LINE__);
260 
261 	//
262 	// Determine the room dimensions (width/height)
263 	//
264 	rmhd = (const RoomHeader *)findResourceData(MKTAG('R','M','H','D'), roomptr);
265 
266 	if (_game.version == 8) {
267 		_roomWidth = READ_LE_UINT32(&(rmhd->v8.width));
268 		_roomHeight = READ_LE_UINT32(&(rmhd->v8.height));
269 		_numObjectsInRoom = (byte)READ_LE_UINT32(&(rmhd->v8.numObjects));
270 	} else if (_game.version == 7) {
271 		_roomWidth = READ_LE_UINT16(&(rmhd->v7.width));
272 		_roomHeight = READ_LE_UINT16(&(rmhd->v7.height));
273 		_numObjectsInRoom = (byte)READ_LE_UINT16(&(rmhd->v7.numObjects));
274 	} else {
275 		_roomWidth = READ_LE_UINT16(&(rmhd->old.width));
276 		_roomHeight = READ_LE_UINT16(&(rmhd->old.height));
277 		_numObjectsInRoom = (byte)READ_LE_UINT16(&(rmhd->old.numObjects));
278 	}
279 
280 	//
281 	// Find the room image data
282 	//
283 	if (_game.version == 8) {
284 		_IM00_offs = getObjectImage(roomptr, 1) - roomptr;
285 	} else if (_game.features & GF_SMALL_HEADER) {
286 		_IM00_offs = findResourceData(MKTAG('I','M','0','0'), roomptr) - roomptr;
287 	} else if (_game.heversion >= 70) {
288 		byte *roomImagePtr = getResourceAddress(rtRoomImage, _roomResource);
289 		_IM00_offs = findResource(MKTAG('I','M','0','0'), roomImagePtr) - roomImagePtr;
290 	} else {
291 		_IM00_offs = findResource(MKTAG('I','M','0','0'), findResource(MKTAG('R','M','I','M'), roomptr)) - roomptr;
292 	}
293 
294 	//
295 	// Look for an exit script
296 	//
297 	ptr = findResourceData(MKTAG('E','X','C','D'), roomResPtr);
298 	if (ptr)
299 		_EXCD_offs = ptr - roomResPtr;
300 	if (_dumpScripts && _EXCD_offs)
301 		dumpResource("exit-", _roomResource, roomResPtr + _EXCD_offs - _resourceHeaderSize, -1);
302 
303 	//
304 	// Look for an entry script
305 	//
306 	ptr = findResourceData(MKTAG('E','N','C','D'), roomResPtr);
307 	if (ptr)
308 		_ENCD_offs = ptr - roomResPtr;
309 	if (_dumpScripts && _ENCD_offs)
310 		dumpResource("entry-", _roomResource, roomResPtr + _ENCD_offs - _resourceHeaderSize, -1);
311 
312 	//
313 	// Setup local scripts
314 	//
315 
316 	// Determine the room script base address
317 	roomResPtr = roomptr = getResourceAddress(rtRoom, _roomResource);
318 	if (_game.version == 8)
319 		roomResPtr = getResourceAddress(rtRoomScripts, _roomResource);
320 	searchptr = roomResPtr;
321 
322 	memset(_localScriptOffsets, 0, sizeof(_localScriptOffsets));
323 
324 	if (_game.features & GF_SMALL_HEADER) {
325 		ResourceIterator localScriptIterator(searchptr, true);
326 		while ((ptr = localScriptIterator.findNext(MKTAG('L','S','C','R'))) != NULL) {
327 			int id = 0;
328 			ptr += _resourceHeaderSize;	/* skip tag & size */
329 			id = ptr[0];
330 
331 			if (_dumpScripts) {
332 				char buf[32];
333 				sprintf(buf, "room-%d-", _roomResource);
334 				dumpResource(buf, id, ptr - _resourceHeaderSize);
335 			}
336 
337 			_localScriptOffsets[id - _numGlobalScripts] = ptr + 1 - roomptr;
338 		}
339 	} else if (_game.heversion >= 90) {
340 		ResourceIterator localScriptIterator2(searchptr, false);
341 		while ((ptr = localScriptIterator2.findNext(MKTAG('L','S','C','2'))) != NULL) {
342 			int id = 0;
343 
344 			ptr += _resourceHeaderSize;	/* skip tag & size */
345 
346 			id = READ_LE_UINT32(ptr);
347 
348 			assertRange(_numGlobalScripts, id, _numLocalScripts + _numGlobalScripts, "local script");
349 			_localScriptOffsets[id - _numGlobalScripts] = ptr + 4 - roomResPtr;
350 
351 			if (_dumpScripts) {
352 				char buf[32];
353 				sprintf(buf, "room-%d-", _roomResource);
354 				dumpResource(buf, id, ptr - _resourceHeaderSize);
355 			}
356 		}
357 
358 		ResourceIterator localScriptIterator(searchptr, false);
359 		while ((ptr = localScriptIterator.findNext(MKTAG('L','S','C','R'))) != NULL) {
360 			int id = 0;
361 
362 			ptr += _resourceHeaderSize;	/* skip tag & size */
363 
364 			id = ptr[0];
365 			_localScriptOffsets[id - _numGlobalScripts] = ptr + 1 - roomResPtr;
366 
367 			if (_dumpScripts) {
368 				char buf[32];
369 				sprintf(buf, "room-%d-", _roomResource);
370 				dumpResource(buf, id, ptr - _resourceHeaderSize);
371 			}
372 		}
373 
374 	} else {
375 		ResourceIterator localScriptIterator(searchptr, false);
376 		while ((ptr = localScriptIterator.findNext(MKTAG('L','S','C','R'))) != NULL) {
377 			int id = 0;
378 
379 			ptr += _resourceHeaderSize;	/* skip tag & size */
380 
381 			if (_game.version == 8) {
382 				id = READ_LE_UINT32(ptr);
383 				assertRange(_numGlobalScripts, id, _numLocalScripts + _numGlobalScripts, "local script");
384 				_localScriptOffsets[id - _numGlobalScripts] = ptr + 4 - roomResPtr;
385 			} else if (_game.version == 7) {
386 				id = READ_LE_UINT16(ptr);
387 				assertRange(_numGlobalScripts, id, _numLocalScripts + _numGlobalScripts, "local script");
388 				_localScriptOffsets[id - _numGlobalScripts] = ptr + 2 - roomResPtr;
389 			} else {
390 				id = ptr[0];
391 				_localScriptOffsets[id - _numGlobalScripts] = ptr + 1 - roomResPtr;
392 			}
393 
394 			if (_dumpScripts) {
395 				char buf[32];
396 				sprintf(buf, "room-%d-", _roomResource);
397 				dumpResource(buf, id, ptr - _resourceHeaderSize);
398 			}
399 		}
400 	}
401 
402 	// Locate the EGA palette (currently unused).
403 	ptr = findResourceData(MKTAG('E','P','A','L'), roomptr);
404 	if (ptr)
405 		_EPAL_offs = ptr - roomptr;
406 
407 	// Locate the standard room palette (for V3-V5 games).
408 	ptr = findResourceData(MKTAG('C','L','U','T'), roomptr);
409 	if (ptr)
410 		_CLUT_offs = ptr - roomptr;
411 
412 	// Locate the standard room palettes (for V6+ games).
413 	if (_game.version >= 6) {
414 		ptr = findResource(MKTAG('P','A','L','S'), roomptr);
415 		if (ptr) {
416 			_PALS_offs = ptr - roomptr;
417 		}
418 	}
419 
420 	// Transparent color
421 	byte trans;
422 	if (_game.version == 8)
423 		trans = (byte)READ_LE_UINT32(&(rmhd->v8.transparency));
424 	else {
425 		ptr = findResourceData(MKTAG('T','R','N','S'), roomptr);
426 		if (ptr)
427 			trans = ptr[0];
428 		else
429 			trans = 255;
430 	}
431 
432 	// Actor Palette in HE 70 games
433 	if (_game.heversion == 70) {
434 		ptr = findResourceData(MKTAG('R','E','M','P'), roomptr);
435 		if (ptr) {
436 			for (i = 0; i < 256; i++)
437 				_HEV7ActorPalette[i] = *ptr++;
438 		} else {
439 			for (i = 0; i < 256; i++)
440 				_HEV7ActorPalette[i] = i;
441 		}
442 	}
443 
444 
445 	// WORKAROUND bug #1831: The dreaded DOTT "Can't get teeth" bug
446 	// makes it impossible to go on playing w/o cheating in some way.
447 	// It's not quite clear what causes it, but the effect is that object
448 	// 182, the teeth, are still in class 32 (kObjectClassUntouchable),
449 	// when they shouldn't be. Luckily, bitvar69 is set to 1 if and only if
450 	// the teeth are trapped and have not yet been taken by the player. So
451 	// we can make use of that fact to fix the object class of obj 182.
452 	if (_game.id == GID_TENTACLE && _roomResource == 26 && readVar(0x8000 + 69)
453 			&& getClass(182, kObjectClassUntouchable)) {
454 		putClass(182, kObjectClassUntouchable, 0);
455 	}
456 
457 	_gdi->roomChanged(roomptr);
458 	_gdi->setTransparentColor(trans);
459 }
460 
461 /**
462  * Init some dynamic room data after a room has been loaded.
463  * E.g. the initial box data is loaded, the initial palette is set etc.
464  * All of the things setup in here can be modified later on by scripts.
465  * So it is not appropriate to call it after loading a savegame.
466  */
resetRoomSubBlocks()467 void ScummEngine::resetRoomSubBlocks() {
468 	ResId i;
469 	const byte *ptr;
470 	byte *roomptr;
471 
472 	// Determine the room and room script base address
473 	roomptr = getResourceAddress(rtRoom, _roomResource);
474 	if (!roomptr)
475 		error("Room %d: data not found (" __FILE__  ":%d)", _roomResource, __LINE__);
476 
477 	//
478 	// Load box data
479 	//
480 	memset(_extraBoxFlags, 0, sizeof(_extraBoxFlags));
481 
482 	_res->nukeResource(rtMatrix, 1);
483 	_res->nukeResource(rtMatrix, 2);
484 	if (_game.features & GF_SMALL_HEADER) {
485 		ptr = findResourceData(MKTAG('B','O','X','D'), roomptr);
486 		if (ptr) {
487 			byte numOfBoxes = *ptr;
488 			int size;
489 			if (_game.version == 3)
490 				size = numOfBoxes * SIZEOF_BOX_V3 + 1;
491 			else
492 				size = numOfBoxes * SIZEOF_BOX + 1;
493 
494 			_res->createResource(rtMatrix, 2, size);
495 			memcpy(getResourceAddress(rtMatrix, 2), ptr, size);
496 			ptr += size;
497 
498 			size = getResourceDataSize(ptr - size - _resourceHeaderSize) - size;
499 			if (size > 0) {					// do this :)
500 				_res->createResource(rtMatrix, 1, size);
501 				memcpy(getResourceAddress(rtMatrix, 1), ptr, size);
502 			}
503 
504 		}
505 	} else {
506 		ptr = findResourceData(MKTAG('B','O','X','D'), roomptr);
507 		if (ptr) {
508 			int size = getResourceDataSize(ptr);
509 			_res->createResource(rtMatrix, 2, size);
510 			roomptr = getResourceAddress(rtRoom, _roomResource);
511 			ptr = findResourceData(MKTAG('B','O','X','D'), roomptr);
512 			memcpy(getResourceAddress(rtMatrix, 2), ptr, size);
513 		}
514 
515 		ptr = findResourceData(MKTAG('B','O','X','M'), roomptr);
516 		if (ptr) {
517 			int size = getResourceDataSize(ptr);
518 			_res->createResource(rtMatrix, 1, size);
519 			roomptr = getResourceAddress(rtRoom, _roomResource);
520 			ptr = findResourceData(MKTAG('B','O','X','M'), roomptr);
521 			memcpy(getResourceAddress(rtMatrix, 1), ptr, size);
522 		}
523 	}
524 
525 	//
526 	// Load scale data
527 	//
528 	for (i = 1; i < _res->_types[rtScaleTable].size(); i++)
529 		_res->nukeResource(rtScaleTable, i);
530 
531 	ptr = findResourceData(MKTAG('S','C','A','L'), roomptr);
532 	if (ptr) {
533 		int s1, s2, y1, y2;
534 		if (_game.version == 8) {
535 			for (i = 1; i < _res->_types[rtScaleTable].size(); i++, ptr += 16) {
536 				s1 = READ_LE_UINT32(ptr);
537 				y1 = READ_LE_UINT32(ptr + 4);
538 				s2 = READ_LE_UINT32(ptr + 8);
539 				y2 = READ_LE_UINT32(ptr + 12);
540 				setScaleSlot(i, 0, y1, s1, 0, y2, s2);
541 			}
542 		} else {
543 			for (i = 1; i < _res->_types[rtScaleTable].size(); i++, ptr += 8) {
544 				s1 = READ_LE_UINT16(ptr);
545 				y1 = READ_LE_UINT16(ptr + 2);
546 				s2 = READ_LE_UINT16(ptr + 4);
547 				y2 = READ_LE_UINT16(ptr + 6);
548 				if (s1 || y1 || s2 || y2) {
549 					setScaleSlot(i, 0, y1, s1, 0, y2, s2);
550 				}
551 			}
552 		}
553 	}
554 
555 	// We need to setup the current palette before initCycl for Indy4 Amiga.
556 	if (_PALS_offs || _CLUT_offs)
557 		setCurrentPalette(0);
558 
559 	// Color cycling
560 	// HE 7.0 games load resources but don't use them.
561 	if (_game.version >= 4 && _game.heversion <= 62) {
562 		ptr = findResourceData(MKTAG('C','Y','C','L'), roomptr);
563 		if (ptr) {
564 			initCycl(ptr);
565 		}
566 	}
567 
568 #ifdef ENABLE_HE
569 	// Polygons in HE 80+ games
570 	if (_game.heversion >= 80) {
571 		ptr = findResourceData(MKTAG('P','O','L','D'), roomptr);
572 		if (ptr) {
573 			((ScummEngine_v71he *)this)->_wiz->polygonLoad(ptr);
574 		}
575 	}
576 #endif
577 }
578 
579 
setupRoomSubBlocks()580 void ScummEngine_v3old::setupRoomSubBlocks() {
581 	const byte *ptr;
582 	byte *roomptr;
583 	const RoomHeader *rmhd;
584 
585 	_ENCD_offs = 0;
586 	_EXCD_offs = 0;
587 	_EPAL_offs = 0;
588 	_CLUT_offs = 0;
589 	_PALS_offs = 0;
590 
591 	// Determine the room and room script base address
592 	roomptr = getResourceAddress(rtRoom, _roomResource);
593 	if (!roomptr)
594 		error("Room %d: data not found (" __FILE__  ":%d)", _roomResource, __LINE__);
595 
596 	//
597 	// Determine the room dimensions (width/height)
598 	//
599 	rmhd = (const RoomHeader *)(roomptr + 4);
600 
601 	if (_game.version <= 1) {
602 		if (_game.platform == Common::kPlatformNES) {
603 			_roomWidth = READ_LE_UINT16(&(rmhd->old.width)) * 8;
604 			_roomHeight = READ_LE_UINT16(&(rmhd->old.height)) * 8;
605 
606 			// HACK: To let our code work normal with narrow rooms we
607 			// adjust width. It will render garbage on right edge but we do
608 			// not render it anyway
609 			if (_roomWidth < 32 * 8)
610 				_roomWidth = 32 * 8;
611 		} else {
612 			_roomWidth = roomptr[4] * 8;
613 			_roomHeight = roomptr[5] * 8;
614 		}
615 	} else {
616 		_roomWidth = READ_LE_UINT16(&(rmhd->old.width));
617 
618 		// WORKAROUND: Fix bad width value for room 64 (book of maps) in
619 		// Indy3. A specific version of this game (DOS/EGA v1.0, according to
620 		// scumm-md5.txt) has a wrong width of 1793 stored in the data files,
621 		// which causes a strange situation in which the book view may scroll
622 		// towards the right depending on Indy's position from the previous room.
623 		// Fixes bug #6679.
624 		if (_game.id == GID_INDY3 && _roomResource == 64 && _roomWidth == 1793)
625 			_roomWidth = 320;
626 		_roomHeight = READ_LE_UINT16(&(rmhd->old.height));
627 	}
628 	_numObjectsInRoom = roomptr[20];
629 
630 	//
631 	// Find the room image data
632 	//
633 	if (_game.version <= 1) {
634 		_IM00_offs = 0;
635 	} else {
636 		_IM00_offs = READ_LE_UINT16(roomptr + 0x0A);
637 	}
638 
639 	//
640 	// Look for an exit script
641 	//
642 	int EXCD_len = -1;
643 	if (_game.version <= 2) {
644 		_EXCD_offs = READ_LE_UINT16(roomptr + 0x18);
645 		EXCD_len = READ_LE_UINT16(roomptr + 0x1A) - _EXCD_offs + _resourceHeaderSize;	// HACK
646 	} else {
647 		_EXCD_offs = READ_LE_UINT16(roomptr + 0x19);
648 		EXCD_len = READ_LE_UINT16(roomptr + 0x1B) - _EXCD_offs + _resourceHeaderSize;	// HACK
649 	}
650 	if (_dumpScripts && _EXCD_offs)
651 		dumpResource("exit-", _roomResource, roomptr + _EXCD_offs - _resourceHeaderSize, EXCD_len);
652 
653 	//
654 	// Look for an entry script
655 	//
656 	int ENCD_len = -1;
657 	if (_game.version <= 2) {
658 		_ENCD_offs = READ_LE_UINT16(roomptr + 0x1A);
659 		ENCD_len = READ_LE_UINT16(roomptr) - _ENCD_offs + _resourceHeaderSize; // HACK
660 	} else {
661 		_ENCD_offs = READ_LE_UINT16(roomptr + 0x1B);
662 		// FIXME - the following is a hack which assumes that immediately after
663 		// the entry script the first local script follows.
664 		int num_objects = *(roomptr + 20);
665 		int num_sounds = *(roomptr + 23);
666 		int num_scripts = *(roomptr + 24);
667 		ptr = roomptr + 29 + num_objects * 4 + num_sounds + num_scripts;
668 		ENCD_len = READ_LE_UINT16(ptr + 1) - _ENCD_offs + _resourceHeaderSize; // HACK
669 	}
670 	if (_dumpScripts && _ENCD_offs)
671 		dumpResource("entry-", _roomResource, roomptr + _ENCD_offs - _resourceHeaderSize, ENCD_len);
672 
673 	//
674 	// Setup local scripts
675 	//
676 
677 	// Determine the room script base address
678 	roomptr = getResourceAddress(rtRoom, _roomResource);
679 
680 	memset(_localScriptOffsets, 0, sizeof(_localScriptOffsets));
681 
682 	int num_objects = *(roomptr + 20);
683 	int num_sounds;
684 	int num_scripts;
685 
686 	if (_game.version <= 2) {
687 		num_sounds = *(roomptr + 22);
688 		num_scripts = *(roomptr + 23);
689 		ptr = roomptr + 28 + num_objects * 4;
690 		while (num_sounds--)
691 			loadResource(rtSound, *ptr++);
692 		while (num_scripts--)
693 			loadResource(rtScript, *ptr++);
694 	} else /* if (_game.version == 3) */ {
695 		num_sounds = *(roomptr + 23);
696 		num_scripts = *(roomptr + 24);
697 		ptr = roomptr + 29 + num_objects * 4 + num_sounds + num_scripts;
698 		while (*ptr) {
699 			int id = *ptr;
700 
701 			_localScriptOffsets[id - _numGlobalScripts] = READ_LE_UINT16(ptr + 1);
702 			ptr += 3;
703 
704 			if (_dumpScripts) {
705 				char buf[32];
706 				sprintf(buf, "room-%d-", _roomResource);
707 
708 				// HACK: to determine the sizes of the local scripts, we assume that
709 				// a) their order in the data file is the same as in the index
710 				// b) the last script at the same time is the last item in the room "header"
711 				int len = - (int)_localScriptOffsets[id - _numGlobalScripts] + _resourceHeaderSize;
712 				if (*ptr)
713 					len += READ_LE_UINT16(ptr + 1);
714 				else
715 					len += READ_LE_UINT16(roomptr);
716 				dumpResource(buf, id, roomptr + _localScriptOffsets[id - _numGlobalScripts] - _resourceHeaderSize, len);
717 			}
718 		}
719 	}
720 
721 	_gdi->roomChanged(roomptr);
722 }
723 
resetRoomSubBlocks()724 void ScummEngine_v3old::resetRoomSubBlocks() {
725 	const byte *ptr;
726 	byte *roomptr;
727 
728 	// Determine the room and room script base address
729 	roomptr = getResourceAddress(rtRoom, _roomResource);
730 	if (!roomptr)
731 		error("Room %d: data not found (" __FILE__  ":%d)", _roomResource, __LINE__);
732 
733 	// Reset room color for V1 zak
734 	if (_game.version <= 1)
735 		_roomPalette[0] = 0;
736 
737 	//
738 	// Load box data
739 	//
740 	_res->nukeResource(rtMatrix, 1);
741 	_res->nukeResource(rtMatrix, 2);
742 
743 	if (_game.version <= 2)
744 		ptr = roomptr + *(roomptr + 0x15);
745 	else
746 		ptr = roomptr + READ_LE_UINT16(roomptr + 0x15);
747 	if (ptr) {
748 		byte numOfBoxes = 0;
749 		int size;
750 
751 		if (_game.version == 0) {
752 			// Count number of boxes
753 			while (*ptr != 0xFF) {
754 				numOfBoxes++;
755 				ptr += 5;
756 			}
757 
758 			ptr = roomptr + *(roomptr + 0x15);
759 			size = numOfBoxes * SIZEOF_BOX_V0 + 1;
760 
761 			_res->createResource(rtMatrix, 2, size + 1);
762 			getResourceAddress(rtMatrix, 2)[0] = numOfBoxes;
763 			memcpy(getResourceAddress(rtMatrix, 2) + 1, ptr, size);
764 		} else {
765 			numOfBoxes = *ptr;
766 			if (_game.version <= 2)
767 				size = numOfBoxes * SIZEOF_BOX_V2 + 1;
768 			else
769 				size = numOfBoxes * SIZEOF_BOX_V3 + 1;
770 
771 			_res->createResource(rtMatrix, 2, size);
772 			memcpy(getResourceAddress(rtMatrix, 2), ptr, size);
773 		}
774 
775 		ptr += size;
776 		if (_game.version == 0) {
777 			const byte *tmp = ptr;
778 			size = 0;
779 
780 			// Compute matrix size
781 			for (int i = 0; i < numOfBoxes; i++) {
782 				while (*tmp != 0xFF) {
783 					size++;
784 					tmp++;
785 				}
786 				size++;
787 				tmp++;
788 			}
789 		} else if (_game.version <= 2) {
790 			size = numOfBoxes * (numOfBoxes + 1);
791 		} else {
792 			// FIXME. This is an evil HACK!!!
793 			size = (READ_LE_UINT16(roomptr + 0x0A) - READ_LE_UINT16(roomptr + 0x15)) - size;
794 		}
795 
796 		if (size > 0) {					// do this :)
797 			_res->createResource(rtMatrix, 1, size);
798 			memcpy(getResourceAddress(rtMatrix, 1), ptr, size);
799 		}
800 
801 	}
802 
803 	//
804 	// No scale data in old bundle games
805 	//
806 	for (ResId id = 1; id < _res->_types[rtScaleTable].size(); id++)
807 		_res->nukeResource(rtScaleTable, id);
808 
809 }
810 
811 } // End of namespace Scumm
812