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