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 #include "common/textconsole.h"
24
25 #include "queen/cutaway.h"
26
27 #include "queen/bankman.h"
28 #include "queen/display.h"
29 #include "queen/graphics.h"
30 #include "queen/grid.h"
31 #include "queen/input.h"
32 #include "queen/logic.h"
33 #include "queen/queen.h"
34 #include "queen/resource.h"
35 #include "queen/sound.h"
36 #include "queen/talk.h"
37 #include "queen/walk.h"
38
39 namespace Queen {
40
run(const char * filename,char * nextFilename,QueenEngine * vm)41 void Cutaway::run(
42 const char *filename,
43 char *nextFilename,
44 QueenEngine *vm) {
45 Cutaway *cutaway = new Cutaway(filename, vm);
46 cutaway->run(nextFilename);
47 delete cutaway;
48 }
49
Cutaway(const char * filename,QueenEngine * vm)50 Cutaway::Cutaway(
51 const char *filename,
52 QueenEngine *vm)
53 : _vm(vm), _personDataCount(0), _personFaceCount(0), _lastSong(0), _songBeforeComic(0) {
54 memset(&_bankNames, 0, sizeof(_bankNames));
55 _vm->input()->cutawayQuitReset();
56 load(filename);
57 }
58
~Cutaway()59 Cutaway::~Cutaway() {
60 delete[] _fileData;
61 }
62
load(const char * filename)63 void Cutaway::load(const char *filename) {
64 byte *ptr;
65
66 debug(6, "----- Cutaway::load(\"%s\") -----", filename);
67
68 ptr = _fileData = _vm->resource()->loadFile(filename, 20);
69
70 if (0 == scumm_stricmp(filename, "COMIC.CUT"))
71 _songBeforeComic = _vm->sound()->lastOverride();
72
73 strcpy(_basename, filename);
74 _basename[strlen(_basename)-4] = '\0';
75
76 _comPanel = READ_BE_UINT16(ptr);
77 ptr += 2;
78 debug(6, "_comPanel = %i", _comPanel);
79 _cutawayObjectCount = (int16)READ_BE_INT16(ptr);
80 ptr += 2;
81
82 debug(6, "_cutawayObjectCount = %i", _cutawayObjectCount);
83
84 if (_cutawayObjectCount < 0) {
85 _cutawayObjectCount = -_cutawayObjectCount;
86 _vm->input()->canQuit(false);
87 } else
88 _vm->input()->canQuit(true);
89
90 int16 flags1 = (int16)READ_BE_INT16(ptr);
91 ptr += 2;
92 debug(6, "flags1 = %i", flags1);
93
94 if (flags1 < 0) {
95 _vm->logic()->entryObj(0);
96 _finalRoom = -flags1;
97 } else
98 _finalRoom = PREVIOUS_ROOM;
99
100 _anotherCutaway = (flags1 == 1);
101
102 debug(6, "[Cutaway::load] _finalRoom = %i", _finalRoom);
103 debug(6, "[Cutaway::load] _anotherCutaway = %i", _anotherCutaway);
104
105 /*
106 Pointers to other places in the cutaway data
107 */
108
109 _gameStatePtr = _fileData + READ_BE_UINT16(ptr);
110 ptr += 2;
111
112 _nextSentenceOff = READ_BE_UINT16(ptr);
113 ptr += 2;
114
115 uint16 bankNamesOff = READ_BE_UINT16(ptr);
116 ptr += 2;
117
118 _objectData = ptr;
119
120 loadStrings(bankNamesOff);
121
122 if (_bankNames[0][0]) {
123 debug(6, "Loading bank '%s'", _bankNames[0]);
124 _vm->bankMan()->load(_bankNames[0], CUTAWAY_BANK);
125 }
126
127 char entryString[MAX_STRING_SIZE];
128 Talk::getString(_fileData, _nextSentenceOff, entryString, MAX_STRING_LENGTH);
129 debug(6, "Entry string = '%s'", entryString);
130
131 _vm->logic()->joeCutFacing(_vm->logic()->joeFacing());
132 _vm->logic()->joeFace();
133
134 if (entryString[0] == '*' &&
135 entryString[1] == 'F' &&
136 entryString[3] == '\0') {
137 switch (entryString[2]) {
138 case 'L':
139 _vm->logic()->joeCutFacing(DIR_LEFT);
140 break;
141 case 'R':
142 _vm->logic()->joeCutFacing(DIR_RIGHT);
143 break;
144 case 'F':
145 _vm->logic()->joeCutFacing(DIR_FRONT);
146 break;
147 case 'B':
148 _vm->logic()->joeCutFacing(DIR_BACK);
149 break;
150 }
151 }
152
153 }
154
loadStrings(uint16 offset)155 void Cutaway::loadStrings(uint16 offset) {
156 int bankNameCount = READ_BE_UINT16(_fileData + offset);
157 offset += 2;
158
159 debug(6, "Bank name count = %i", bankNameCount);
160
161 /*
162 The _bankNames zero-based array is the one-based BANK_NAMEstr array in
163 the original source code.
164 */
165
166 for (int i = 0, j = 0; i < bankNameCount; i++) {
167 Talk::getString(_fileData, offset, _bankNames[j], MAX_FILENAME_LENGTH);
168 if (_bankNames[j][0]) {
169 debug(6, "Bank name %i = '%s'", j, _bankNames[j]);
170 j++;
171 }
172 }
173
174 debug(6, "Getting talk file");
175 Talk::getString(_fileData, offset, _talkFile, MAX_FILENAME_LENGTH);
176 debug(6, "Talk file = '%s'", _talkFile);
177
178 _talkTo = (int16)READ_BE_INT16(_fileData + offset);
179 debug(6, "_talkTo = %i", _talkTo);
180 }
181
getCutawayObject(const byte * ptr,CutawayObject & object)182 const byte *Cutaway::getCutawayObject(const byte *ptr, CutawayObject &object) {
183 const byte *oldPtr = ptr;
184
185 object.objectNumber = (int16)READ_BE_INT16(ptr); ptr += 2;
186 object.moveToX = (int16)READ_BE_INT16(ptr); ptr += 2;
187 object.moveToY = (int16)READ_BE_INT16(ptr); ptr += 2;
188 object.bank = (int16)READ_BE_INT16(ptr); ptr += 2;
189 object.animList = (int16)READ_BE_INT16(ptr); ptr += 2;
190 object.execute = (int16)READ_BE_INT16(ptr); ptr += 2;
191 object.limitBobX1 = (int16)READ_BE_INT16(ptr); ptr += 2;
192 object.limitBobY1 = (int16)READ_BE_INT16(ptr); ptr += 2;
193 object.limitBobX2 = (int16)READ_BE_INT16(ptr); ptr += 2;
194 object.limitBobY2 = (int16)READ_BE_INT16(ptr); ptr += 2;
195 object.specialMove = (int16)READ_BE_INT16(ptr); ptr += 2;
196 object.animType = (int16)READ_BE_INT16(ptr); ptr += 2;
197 object.fromObject = (int16)READ_BE_INT16(ptr); ptr += 2;
198 object.bobStartX = (int16)READ_BE_INT16(ptr); ptr += 2;
199 object.bobStartY = (int16)READ_BE_INT16(ptr); ptr += 2;
200 object.room = (int16)READ_BE_INT16(ptr); ptr += 2;
201 object.scale = (int16)READ_BE_INT16(ptr); ptr += 2;
202
203 if ((ptr - oldPtr) != 17*sizeof(int16))
204 error("Wrong number of values read");
205
206 // Make ugly reuse of data less ugly
207 if (object.limitBobX1 < 0) {
208 object.song = -object.limitBobX1;
209 object.limitBobX1 = 0;
210 } else
211 object.song = 0;
212
213 return ptr;
214 }
215
dumpCutawayObject(int index,CutawayObject & object)216 void Cutaway::dumpCutawayObject(int index, CutawayObject &object) {
217 debug(6, "----- CutawayObject[%i] -----", index);
218
219 const char *objectNumberStr;
220
221 switch (object.objectNumber) {
222 case -1:
223 objectNumberStr = "MESSAGE";
224 break;
225 case 0:
226 objectNumberStr = "Joe";
227 break;
228 default:
229 if (object.objectNumber > 0)
230 objectNumberStr = _vm->logic()->objectName(ABS(_vm->logic()->objectData(object.objectNumber)->name));
231 else
232 objectNumberStr = "Unknown!";
233 break;
234 }
235
236 debug(6, "objectNumber = %i (%s)", object.objectNumber, objectNumberStr);
237
238 if (object.moveToX) debug(6, "moveToX = %i", object.moveToX);
239 if (object.moveToY) debug(6, "moveToY = %i", object.moveToY);
240 if (object.bank) debug(6, "bank = %i", object.bank);
241 if (object.animList) debug(6, "animList = %i", object.animList);
242 if (object.execute) debug(6, "execute = %i", object.execute);
243 if (object.limitBobX1) debug(6, "limitBobX1 = %i", object.limitBobX1);
244 if (object.limitBobY1) debug(6, "limitBobY1 = %i", object.limitBobY1);
245 if (object.limitBobX2) debug(6, "limitBobX2 = %i", object.limitBobX2);
246 if (object.limitBobY2) debug(6, "limitBobY2 = %i", object.limitBobY2);
247 if (object.specialMove) debug(6, "specialMove = %i", object.specialMove);
248 if (object.animType) debug(6, "animType = %i", object.animType);
249 if (object.fromObject) debug(6, "fromObject = %i", object.fromObject);
250 if (object.bobStartX) debug(6, "bobStartX = %i", object.bobStartX);
251 if (object.bobStartY) debug(6, "bobStartY = %i", object.bobStartY);
252 if (object.room) debug(6, "room = %i", object.room);
253 if (object.scale) debug(6, "scale = %i", object.scale);
254
255 }
256
257
turnOnPeople(const byte * ptr,CutawayObject & object)258 const byte *Cutaway::turnOnPeople(const byte *ptr, CutawayObject &object) {
259 // Lines 1248-1259 in cutaway.c
260 object.personCount = (int16)READ_BE_INT16(ptr);
261 ptr += 2;
262
263 if (object.personCount > MAX_PERSON_COUNT)
264 error("[Cutaway::turnOnPeople] object.personCount > MAX_PERSON_COUNT");
265
266 for (int i = 0; i < object.personCount; i++) {
267 object.person[i] = (int16)READ_BE_INT16(ptr);
268 ptr += 2;
269 debug(7, "[%i] Turn on person %i", i, object.person[i]);
270 }
271
272 return ptr;
273 }
274
limitBob(CutawayObject & object)275 void Cutaway::limitBob(CutawayObject &object) {
276 if (object.limitBobX1) {
277
278 if (object.objectNumber < 0) {
279 warning("QueenCutaway::limitBob called with objectNumber = %i", object.objectNumber);
280 return;
281 }
282
283 BobSlot *bob =
284 _vm->graphics()->bob(_vm->logic()->findBob(object.objectNumber));
285
286 if (!bob) {
287 warning("Failed to find bob");
288 return;
289 }
290
291 bob->box.x1 = object.limitBobX1;
292 bob->box.y1 = object.limitBobY1;
293 bob->box.x2 = object.limitBobX2;
294 bob->box.y2 = object.limitBobY2;
295 }
296 }
297
restorePersonData()298 void Cutaway::restorePersonData() {
299 for (int i = 0; i < _personDataCount; i++) {
300 int index = _personData[i].index;
301 ObjectData *objectData = _vm->logic()->objectData(index);
302 objectData->name = _personData[i].name;
303 objectData->image = _personData[i].image;
304 }
305 }
306
changeRooms(CutawayObject & object)307 void Cutaway::changeRooms(CutawayObject &object) {
308 // Lines 1291-1385 in cutaway.c
309
310 debug(6, "Changing from room %i to room %i",
311 _temporaryRoom,
312 object.room);
313
314 restorePersonData();
315 _personDataCount = 0;
316
317 if (_finalRoom != object.room) {
318 int firstObjectInRoom = _vm->logic()->roomData(object.room) + 1;
319 int lastObjectInRoom = _vm->logic()->roomData(object.room) + _vm->grid()->objMax(object.room);
320
321 for (int i = firstObjectInRoom; i <= lastObjectInRoom; i++) {
322 ObjectData *objectData = _vm->logic()->objectData(i);
323
324 if (objectData->image == -3 || objectData->image == -4) {
325
326 assert(_personDataCount < MAX_PERSON_COUNT);
327 // The object is a person! So record the details...
328 _personData[_personDataCount].index = i;
329 _personData[_personDataCount].name = objectData->name;
330 _personData[_personDataCount].image = objectData->image;
331 _personDataCount++;
332
333 // Now, check to see if we need to keep the person on
334 bool on = false;
335 for (int j = 0; j < object.personCount; j++) {
336 if (object.person[j] == i) {
337 on = true;
338 break;
339 }
340 }
341
342 if (on) {
343 // It is needed, so ensure it's ON
344 objectData->name = ABS(objectData->name);
345 } else {
346 // Not needed, so switch off!
347 objectData->name = -ABS(objectData->name);
348 }
349
350 }
351 } // for ()
352 }
353
354 // set coordinates for Joe if he is on screen
355
356 _vm->logic()->joePos(0, 0);
357
358 for (int i = 0; i < object.personCount; i++) {
359 if (PERSON_JOE == object.person[i]) {
360 _vm->logic()->joePos(object.bobStartX, object.bobStartY);
361 }
362 }
363
364 _vm->logic()->oldRoom(_initialRoom);
365
366 // FIXME: Cutaway c41f is played at the end of the command 0x178. This command
367 // setups some persons and associates bob slots to them. They should be hidden as
368 // their y coordinate is > 150, but they aren't ! As a workaround, we display the room
369 // with the panel area enabled. We do the same problem for cutaway c62c.
370 int16 comPanel = _comPanel;
371 if ((strcmp(_basename, "c41f") == 0 && _temporaryRoom == 106 && object.room == 41) ||
372 (strcmp(_basename, "c62c") == 0 && _temporaryRoom == 105 && object.room == 41)) {
373 comPanel = 1;
374 }
375
376 // Hide panel before displaying the 'head room' (ie. before palette fading). This doesn't
377 // match the original engine, but looks better to me.
378 if (object.room == FAYE_HEAD || object.room == AZURA_HEAD || object.room == FRANK_HEAD) {
379 comPanel = 2;
380 }
381
382 RoomDisplayMode mode;
383
384 if (!_vm->logic()->joeX() && !_vm->logic()->joeY()) {
385 mode = RDM_FADE_NOJOE;
386 } else {
387 // We need to display Joe on screen
388 if (_roomFade)
389 mode = RDM_NOFADE_JOE;
390 else
391 mode = RDM_FADE_JOE_XY;
392 }
393
394 _vm->logic()->displayRoom(_vm->logic()->currentRoom(), mode, object.scale, comPanel, true);
395
396 _currentImage = _vm->graphics()->numFrames();
397
398 _temporaryRoom = _vm->logic()->currentRoom();
399
400 restorePersonData();
401 }
402
getObjectType(CutawayObject & object)403 Cutaway::ObjectType Cutaway::getObjectType(CutawayObject &object) {
404 // Lines 1387-1449 in cutaway.c
405
406 ObjectType objectType = OBJECT_TYPE_ANIMATION;
407
408 if (object.objectNumber > 0) {
409 if (!object.animList) {
410 // No anim frames, so treat as a PERSON, ie. allow to speak/walk
411 ObjectData *objectData = _vm->logic()->objectData(object.objectNumber);
412 if (objectData->image == -3 || objectData->image == -4)
413 objectType = OBJECT_TYPE_PERSON;
414 }
415 } else if (object.objectNumber == OBJECT_JOE) {
416 // It's Joe. See if he's to be treated as a person.
417 if (!object.animList) {
418 // There's no animation list, so Joe must be talking.
419 objectType = OBJECT_TYPE_PERSON;
420 }
421 }
422
423 if (object.fromObject > 0) {
424 /* Copy FROM_OBJECT into OBJECT */
425
426 if (object.objectNumber != object.fromObject) {
427 _vm->logic()->objectCopy(object.fromObject, object.objectNumber);
428 } else {
429 // Same object, so just turn it on!
430 ObjectData *objectData = _vm->logic()->objectData(object.objectNumber);
431 objectData->name = ABS(objectData->name);
432 }
433
434 _vm->graphics()->refreshObject(object.objectNumber);
435
436 // Skip doing any anim stuff
437 objectType = OBJECT_TYPE_NO_ANIMATION;
438 }
439
440 switch (object.objectNumber) {
441 case -2:
442 // Text to be spoken
443 objectType = OBJECT_TYPE_TEXT_SPEAK;
444 break;
445 case -3:
446 // Text to be displayed AND spoken
447 objectType = OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK;
448 break;
449 case -4:
450 // Text to be displayed only (not spoken)
451 objectType = OBJECT_TYPE_TEXT_DISPLAY;
452 break;
453 }
454
455 if (OBJECT_TYPE_ANIMATION == objectType && !object.execute) {
456 // Execute is not on, and it's an object, so ignore any Anims
457 objectType = OBJECT_TYPE_NO_ANIMATION;
458 }
459
460 return objectType;
461 }
462
getCutawayAnim(const byte * ptr,int header,CutawayAnim & anim)463 const byte *Cutaway::getCutawayAnim(const byte *ptr, int header, CutawayAnim &anim) {
464 // lines 1531-1607 in cutaway.c
465 debug(6, "[Cutaway::getCutawayAnim] header=%i", header);
466
467 anim.currentFrame = 0;
468 anim.originalFrame = 0;
469
470 if (-1 == header)
471 header = 0;
472
473 if (0 == header) {
474 anim.object = 0;
475 anim.originalFrame = 31;
476 } else {
477 anim.object = _vm->logic()->findBob(header);
478 anim.originalFrame = _vm->logic()->findFrame(header);
479 }
480
481 anim.unpackFrame = (int16)READ_BE_INT16(ptr);
482 ptr += 2;
483
484 anim.speed = ((int16)READ_BE_INT16(ptr)) / 3 + 1;
485 ptr += 2;
486
487 anim.bank = (int16)READ_BE_INT16(ptr);
488 ptr += 2;
489
490 if (anim.bank == 0) {
491 anim.bank = 15;
492 } else {
493 if (anim.bank != 13) {
494 assert(anim.bank - 1 < MAX_BANK_NAME_COUNT);
495 _vm->bankMan()->load(_bankNames[anim.bank-1], CUTAWAY_BANK);
496 anim.bank = 8;
497 } else {
498 // Make sure we ref correct JOE bank (7)
499 anim.bank = 7;
500 }
501 }
502
503 anim.mx = (int16)READ_BE_INT16(ptr);
504 ptr += 2;
505
506 anim.my = (int16)READ_BE_INT16(ptr);
507 ptr += 2;
508
509 anim.cx = (int16)READ_BE_INT16(ptr);
510 ptr += 2;
511
512 anim.cy = (int16)READ_BE_INT16(ptr);
513 ptr += 2;
514
515 anim.scale = (int16)READ_BE_INT16(ptr);
516 ptr += 2;
517
518 if ((_vm->resource()->isDemo() && _vm->resource()->getPlatform() == Common::kPlatformDOS) ||
519 (_vm->resource()->isInterview() && _vm->resource()->getPlatform() == Common::kPlatformAmiga)) {
520 anim.song = 0;
521 } else {
522 anim.song = (int16)READ_BE_INT16(ptr);
523 ptr += 2;
524 }
525
526 // Extract information that depend on the signedness of values
527 if (anim.unpackFrame < 0) {
528 anim.flip = true;
529 anim.unpackFrame = -anim.unpackFrame;
530 } else
531 anim.flip = false;
532
533 return ptr;
534 }
535
dumpCutawayAnim(CutawayAnim & anim)536 void Cutaway::dumpCutawayAnim(CutawayAnim &anim) {
537 debug(6, "----- CutawayAnim -----");
538 if (anim.object) debug(6, "object = %i", anim.object);
539 if (anim.unpackFrame) debug(6, "unpackFrame = %i", anim.unpackFrame);
540 if (anim.speed) debug(6, "speed = %i", anim.speed);
541 if (anim.bank) debug(6, "bank = %i", anim.bank);
542 if (anim.mx) debug(6, "mx = %i", anim.mx);
543 if (anim.my) debug(6, "my = %i", anim.my);
544 if (anim.cx) debug(6, "cx = %i", anim.cx);
545 if (anim.cy) debug(6, "cy = %i", anim.cy);
546 if (anim.scale) debug(6, "scale = %i", anim.scale);
547 if (anim.currentFrame) debug(6, "currentFrame = %i", anim.currentFrame);
548 if (anim.originalFrame) debug(6, "originalFrame = %i", anim.originalFrame);
549 if (anim.song) debug(6, "song = %i", anim.song);
550 }
551
handleAnimation(const byte * ptr,CutawayObject & object)552 const byte *Cutaway::handleAnimation(const byte *ptr, CutawayObject &object) {
553 // lines 1517-1770 in cutaway.c
554 int frameCount = 0;
555 int i;
556
557 CutawayAnim objAnim[56];
558
559 // Read animation frames
560 for (;;) {
561
562 int header = (int16)READ_BE_INT16(ptr);
563 ptr += 2;
564
565 if (-2 == header)
566 break;
567
568 //debug(6, "Animation frame %i, header = %i", frameCount, header);
569
570 if (header > 1000)
571 error("Header too large");
572
573 ptr = getCutawayAnim(ptr, header, objAnim[frameCount]);
574 //dumpCutawayAnim(objAnim[frameCount]);
575
576 frameCount++;
577
578 if (_vm->input()->cutawayQuit())
579 return NULL;
580 }
581
582 if (object.animType == 1) {
583 // lines 1615-1636 in cutaway.c
584
585 debug(6, "----- Complex cutaway animation (animType = %i) -----", object.animType);
586
587 if ((_vm->logic()->currentRoom() == 47 || _vm->logic()->currentRoom() == 63) &&
588 objAnim[0].object == 1) {
589 //CR 2 - 3/3/95, Special harcoded section to make Oracle work...
590 makeComplexAnimation(_vm->graphics()->personFrames(1) - 1, objAnim, frameCount);
591 } else {
592 _currentImage = makeComplexAnimation(_currentImage, objAnim, frameCount);
593 }
594
595 if (object.bobStartX || object.bobStartY) {
596 BobSlot *bob = _vm->graphics()->bob(objAnim[0].object);
597 bob->x = object.bobStartX;
598 bob->y = object.bobStartY;
599 }
600 }
601
602 // Setup the SYNCHRO bob channels
603
604 for (i = 0; i < frameCount; i++) {
605 if (objAnim[i].mx || objAnim[i].my) {
606 BobSlot *bob = _vm->graphics()->bob(objAnim[i].object);
607 bob->frameNum = objAnim[i].originalFrame;
608 bob->move(objAnim[i].mx, objAnim[i].my, (object.specialMove > 0) ? object.specialMove : 4);
609 // Boat room hard coded
610 if (_vm->logic()->currentRoom() == ROOM_TEMPLE_OUTSIDE) {
611 BobSlot *bobJoe = _vm->graphics()->bob(0);
612 if (bobJoe->x < 320) {
613 bobJoe->move(bobJoe->x + 346, bobJoe->y, 4);
614 }
615 }
616 }
617 }
618
619 // Normal cutaway
620
621 if (object.animType != 1) {
622 // lines 1657-1761 in cutaway.c
623
624 debug(6, "----- Normal cutaway animation (animType = %i) -----", object.animType);
625
626 for (i = 0; i < frameCount; i++) {
627 //debug(6, "===== Animating frame %i =====", i);
628 //dumpCutawayAnim(objAnim[i]);
629
630 BobSlot *bob = _vm->graphics()->bob(objAnim[i].object);
631 bob->active = true;
632 if (bob->animating) {
633 bob->animating = false;
634 bob->frameNum = objAnim[i].originalFrame;
635 }
636
637 if (objAnim[i].object < 4)
638 bob->frameNum = 31 + objAnim[i].object;
639
640 if (objAnim[i].unpackFrame == 0) {
641 // Turn off the bob
642 bob->active = false;
643 } else {
644 if (object.animType == 2 || object.animType == 0) {
645 // Unpack animation, but do not unpack moving people
646
647 if (!((objAnim[i].mx > 0 || objAnim[i].my > 0) && inRange(objAnim[i].object, 1, 3))) {
648 _vm->bankMan()->unpack(
649 objAnim[i].unpackFrame,
650 objAnim[i].originalFrame,
651 objAnim[i].bank);
652 }
653
654 if (0 == objAnim[i].object) {
655 // Scale Joe
656 bob->scale = scale(object);
657 }
658 }
659
660 if (objAnim[i].cx || objAnim[i].cy) {
661 bob->x = objAnim[i].cx;
662 bob->y = objAnim[i].cy;
663 }
664
665 // Only flip if we are not moving or it is not a person object
666 if (!(objAnim[i].object > 0 && objAnim[i].object < 4) ||
667 !(objAnim[i].mx || objAnim[i].my))
668 bob->xflip = objAnim[i].flip;
669
670 // Add frame alteration
671 if (!(objAnim[i].object > 0 && objAnim[i].object < 4)) {
672 bob->frameNum = objAnim[i].originalFrame;
673 }
674
675 int j;
676 for (j = 0; j < objAnim[i].speed; j++)
677 _vm->update();
678 }
679
680 if (_vm->input()->cutawayQuit())
681 return NULL;
682
683 if (objAnim[i].song > 0)
684 _vm->sound()->playSong(objAnim[i].song);
685
686 } // for ()
687 }
688
689 bool moving = true;
690
691 while (moving) {
692 moving = false;
693 _vm->update();
694
695 for (i = 0; i < frameCount; i++) {
696 BobSlot *bob = _vm->graphics()->bob(objAnim[i].object);
697 if (bob->moving) {
698 moving = true;
699 break;
700 }
701 }
702
703 if (_vm->input()->cutawayQuit())
704 return NULL;
705 }
706
707 return ptr;
708 }
709
findCdCut(const char * basename,int index,char * result)710 static void findCdCut(const char *basename, int index, char *result) {
711 strcpy(result, basename);
712 for (int i = strlen(basename); i < 5; i++)
713 result[i] = '_';
714 snprintf(result + 5, 3, "%02i", index);
715 }
716
handlePersonRecord(int index,CutawayObject & object,const char * sentence)717 void Cutaway::handlePersonRecord(
718 int index,
719 CutawayObject &object,
720 const char *sentence) {
721 // Lines 1455-1516 in cutaway.c
722
723 Person p;
724
725 if (object.objectNumber == OBJECT_JOE) {
726 if (object.moveToX || object.moveToY) {
727 _vm->walk()->moveJoe(0, object.moveToX, object.moveToY, true);
728 }
729 } else {
730 _vm->logic()->initPerson(
731 object.objectNumber - _vm->logic()->currentRoomData(),
732 "", true, &p);
733
734 if (object.bobStartX || object.bobStartY) {
735 BobSlot *bob = _vm->graphics()->bob(p.actor->bobNum);
736 bob->scale = scale(object);
737 bob->x = object.bobStartX;
738 bob->y = object.bobStartY;
739 }
740
741 if (object.moveToX || object.moveToY)
742 _vm->walk()->movePerson(
743 &p,
744 object.moveToX, object.moveToY,
745 _currentImage + 1,
746 _vm->logic()->objectData(object.objectNumber)->image
747 );
748 }
749
750 if (_vm->input()->cutawayQuit())
751 return;
752
753 if (0 != strcmp(sentence, "*")) {
754 if (sentence[0] == '#') {
755 debug(4, "Starting credits '%s'", sentence + 1);
756 _vm->logic()->startCredits(sentence + 1);
757 } else {
758 if (object.objectNumber > 0) {
759 bool foundPerson = false;
760
761 for (int i = 1; i <= _personFaceCount; i++) {
762 if (_personFace[i].index == object.objectNumber) {
763 foundPerson = true;
764 break;
765 }
766 }
767
768 if (!foundPerson) {
769 _personFaceCount++;
770 assert(_personFaceCount < MAX_PERSON_FACE_COUNT);
771 _personFace[_personFaceCount].index = object.objectNumber;
772 _personFace[_personFaceCount].image = _vm->logic()->objectData(object.objectNumber)->image;
773 }
774 }
775
776 char voiceFilePrefix[MAX_STRING_SIZE];
777 findCdCut(_basename, index, voiceFilePrefix);
778 _vm->logic()->makePersonSpeak(sentence, (object.objectNumber == OBJECT_JOE) ? NULL : &p, voiceFilePrefix);
779 }
780
781 }
782
783 if (_vm->input()->cutawayQuit())
784 return;
785 }
786
run(char * nextFilename)787 void Cutaway::run(char *nextFilename) {
788 int i;
789 nextFilename[0] = '\0';
790
791 _currentImage = _vm->graphics()->numFrames();
792
793 BobSlot *joeBob = _vm->graphics()->bob(0);
794 int initialJoeX = joeBob->x;
795 int initialJoeY = joeBob->y;
796 debug(6, "[Cutaway::run] Joe started at (%i, %i)", initialJoeX, initialJoeY);
797
798 _vm->input()->cutawayRunning(true);
799
800 _initialRoom = _temporaryRoom = _vm->logic()->currentRoom();
801
802 _vm->display()->screenMode(_comPanel, true);
803
804 if (_comPanel == 0 || _comPanel == 2) {
805 _vm->logic()->sceneStart();
806 }
807
808 memset(_personFace, 0, sizeof(_personFace));
809 _personFaceCount = 0;
810
811 const byte *ptr = _objectData;
812
813 for (i = 0; i < _cutawayObjectCount; i++) {
814 CutawayObject object;
815 ptr = getCutawayObject(ptr, object);
816 //dumpCutawayObject(i, object);
817
818 if (!object.moveToX &&
819 !object.moveToY &&
820 object.specialMove > 0 &&
821 object.objectNumber >= 0) {
822 _vm->logic()->executeSpecialMove(object.specialMove);
823 object.specialMove = 0;
824 }
825
826 if (CURRENT_ROOM == object.room) {
827 // Get current room
828 object.room = _vm->logic()->currentRoom();
829 } else {
830 // Change current room
831 _vm->logic()->currentRoom(object.room);
832 }
833
834 ptr = turnOnPeople(ptr, object);
835
836 limitBob(object);
837
838 char sentence[MAX_STRING_SIZE];
839 Talk::getString(_fileData, _nextSentenceOff, sentence, MAX_STRING_LENGTH);
840
841 if (OBJECT_ROOMFADE == object.objectNumber) {
842 _roomFade = true;
843 object.objectNumber = OBJECT_JOE;
844 } else {
845 _roomFade = false;
846 }
847
848 if (object.room != _temporaryRoom)
849 changeRooms(object);
850
851 ObjectType objectType = getObjectType(object);
852
853 if (object.song)
854 _vm->sound()->playSong(object.song);
855
856 switch (objectType) {
857 case OBJECT_TYPE_ANIMATION:
858 ptr = handleAnimation(ptr, object);
859 break;
860 case OBJECT_TYPE_PERSON:
861 handlePersonRecord(i + 1, object, sentence);
862 break;
863 case OBJECT_TYPE_NO_ANIMATION:
864 // Do nothing?
865 break;
866 case OBJECT_TYPE_TEXT_SPEAK:
867 case OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK:
868 case OBJECT_TYPE_TEXT_DISPLAY:
869 handleText(i + 1, objectType, object, sentence);
870 break;
871 default:
872 warning("Unhandled object type: %i", objectType);
873 break;
874 }
875
876 if (_vm->input()->cutawayQuit())
877 break;
878
879 if (_roomFade) {
880 _vm->update();
881 BobSlot *j = _vm->graphics()->bob(0);
882 _vm->display()->palFadeIn(_vm->logic()->currentRoom(), j->active, j->x, j->y);
883 _roomFade = false;
884 }
885
886 } // for ()
887
888 _vm->display()->clearTexts(0, 198);
889 // XXX lines 1887-1895 in cutaway.c
890
891 stop();
892
893 updateGameState();
894
895 _vm->bankMan()->close(CUTAWAY_BANK);
896
897 talk(nextFilename);
898
899 if (_comPanel == 0 || (_comPanel == 2 && !_anotherCutaway)) {
900 _vm->logic()->sceneStop();
901 _comPanel = 0;
902 }
903
904 if (nextFilename[0] == '\0' && !_anotherCutaway && _vm->logic()->currentRoom() != ROOM_ENDING_CREDITS) {
905 _vm->display()->fullscreen(false);
906
907 // Lines 2138-2182 in cutaway.c
908 if (_finalRoom) {
909 _vm->logic()->newRoom(0);
910 _vm->logic()->entryObj(0);
911 } else {
912 /// No need to stay in current room, so return to previous room
913 // if one exists. Reset Joe's X,Y coords to those when first entered
914
915 restorePersonData();
916
917 debug(6, "_vm->logic()->entryObj() = %i", _vm->logic()->entryObj());
918 if (_vm->logic()->entryObj() > 0) {
919 _initialRoom = _vm->logic()->objectData(_vm->logic()->entryObj())->room;
920 } else {
921 // We're not returning to new room, so return to old Joe X,Y coords
922 debug(6, "[Cutaway::run] Moving joe to (%i, %i)", initialJoeX, initialJoeY);
923 _vm->logic()->joePos(initialJoeX, initialJoeY);
924 }
925
926 if (_vm->logic()->currentRoom() != _initialRoom) {
927 _vm->logic()->currentRoom(_initialRoom);
928 _vm->logic()->changeRoom();
929 if (_vm->logic()->currentRoom() == _vm->logic()->newRoom()) {
930 _vm->logic()->newRoom(0);
931 }
932 }
933 _vm->logic()->joePos(0, 0);
934 }
935
936 _vm->logic()->joeCutFacing(0);
937 _comPanel = 0;
938
939 int k = 0;
940 for (i = _vm->logic()->roomData(_vm->logic()->currentRoom());
941 i <= _vm->logic()->roomData(_vm->logic()->currentRoom() + 1); i++) {
942
943 ObjectData *object = _vm->logic()->objectData(i);
944 if (object->image == -3 || object->image == -4) {
945 k++;
946 if (object->name > 0) {
947 _vm->graphics()->resetPersonAnim(k);
948 }
949 }
950 }
951
952 _vm->logic()->removeHotelItemsFromInventory();
953 }
954
955 joeBob->animating = 0;
956 joeBob->moving = 0;
957
958 // if the cutaway has been cancelled, we must stop the speech and the sfx as well
959 if (_vm->input()->cutawayQuit()) {
960 if (_vm->sound()->isSpeechActive())
961 _vm->sound()->stopSpeech();
962 _vm->sound()->stopSfx();
963 }
964
965 _vm->input()->cutawayRunning(false);
966 _vm->input()->cutawayQuitReset();
967 _vm->input()->quickSaveReset();
968 _vm->input()->quickLoadReset();
969
970 if (_songBeforeComic > 0)
971 _vm->sound()->playSong(_songBeforeComic);
972 else if (_lastSong > 0)
973 _vm->sound()->playSong(_lastSong);
974 }
975
stop()976 void Cutaway::stop() {
977 // Lines 1901-2032 in cutaway.c
978 byte *ptr = _gameStatePtr;
979
980 // Skipping GAMESTATE data
981 int gameStateCount = (int16)READ_BE_INT16(ptr); ptr += 2;
982 if (gameStateCount > 0)
983 ptr += (gameStateCount * 12);
984
985 // Get the final room and Joe's final position
986
987 int16 joeRoom = READ_BE_UINT16(ptr); ptr += 2;
988 int16 joeX = READ_BE_UINT16(ptr); ptr += 2;
989 int16 joeY = READ_BE_UINT16(ptr); ptr += 2;
990
991 debug(6, "[Cutaway::stop] Final position is room %i and coordinates (%i, %i)",
992 joeRoom, joeX, joeY);
993
994 if ((!_vm->input()->cutawayQuit() || (!_anotherCutaway && joeRoom == _finalRoom)) &&
995 joeRoom != _temporaryRoom &&
996 joeRoom != 0) {
997
998 debug(6, "[Cutaway::stop] Changing rooms and moving Joe");
999
1000 _vm->logic()->joePos(joeX, joeY);
1001 _vm->logic()->currentRoom(joeRoom);
1002 _vm->logic()->oldRoom(_initialRoom);
1003 _vm->logic()->displayRoom(_vm->logic()->currentRoom(), RDM_FADE_JOE_XY, 0, _comPanel, true);
1004 }
1005
1006 if (_vm->input()->cutawayQuit()) {
1007 // Lines 1927-2032 in cutaway.c
1008 int i;
1009
1010 // Stop the credits from running
1011 _vm->logic()->stopCredits();
1012
1013 _vm->graphics()->stopBobs();
1014
1015 for (i = 1; i <= _personFaceCount; i++) {
1016 int index = _personFace[i].index;
1017 if (index > 0) {
1018 _vm->logic()->objectData(_personFace[i].index)->image = _personFace[i].image;
1019
1020 _vm->graphics()->bob(_vm->logic()->findBob(index))->xflip =
1021 (_personFace[i].image != -4);
1022 }
1023 }
1024
1025 int quitObjectCount = (int16)READ_BE_INT16(ptr); ptr += 2;
1026
1027 for (i = 0; i < quitObjectCount; i++) {
1028 int16 objectIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
1029 int16 fromIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
1030 int16 x = (int16)READ_BE_INT16(ptr); ptr += 2;
1031 int16 y = (int16)READ_BE_INT16(ptr); ptr += 2;
1032 int16 room = (int16)READ_BE_INT16(ptr); ptr += 2;
1033 int16 frame = (int16)READ_BE_INT16(ptr); ptr += 2;
1034 int16 bank = (int16)READ_BE_INT16(ptr); ptr += 2;
1035
1036 int bobIndex = _vm->logic()->findBob(objectIndex);
1037 ObjectData *object = _vm->logic()->objectData(objectIndex);
1038
1039 if (fromIndex > 0) {
1040 if (fromIndex == objectIndex) {
1041 // Enable object
1042 object->name = ABS(object->name);
1043 } else {
1044 _vm->logic()->objectCopy(fromIndex, objectIndex);
1045
1046 ObjectData *from = _vm->logic()->objectData(fromIndex);
1047 if (object->image && !from->image && bobIndex && _vm->logic()->currentRoom() == object->room)
1048 _vm->graphics()->clearBob(bobIndex);
1049 }
1050
1051 if (_vm->logic()->currentRoom() == room)
1052 _vm->graphics()->refreshObject(objectIndex);
1053 }
1054
1055 if (_vm->logic()->currentRoom() == object->room) {
1056 BobSlot *pbs = _vm->graphics()->bob(bobIndex);
1057
1058 if (x || y) {
1059 pbs->x = x;
1060 pbs->y = y;
1061 if (inRange(object->image, -4, -3))
1062 pbs->scale = _vm->grid()->findScale(x, y);
1063 }
1064
1065 if (frame) {
1066 if (0 == bank)
1067 bank = 15;
1068 else if (bank != 13) {
1069 _vm->bankMan()->load(_bankNames[bank-1], CUTAWAY_BANK);
1070 bank = 8;
1071 }
1072
1073 int objectFrame = _vm->logic()->findFrame(objectIndex);
1074
1075 if (objectFrame == 1000) {
1076 _vm->graphics()->clearBob(bobIndex);
1077 } else if (objectFrame) {
1078 _vm->bankMan()->unpack(ABS(frame), objectFrame, bank);
1079 pbs->frameNum = objectFrame;
1080 if (frame < 0)
1081 pbs->xflip = true;
1082
1083 }
1084 }
1085 }
1086 } // for ()
1087
1088 int16 specialMove = (int16)READ_BE_INT16(ptr); ptr += 2;
1089 if (specialMove > 0)
1090 _vm->logic()->executeSpecialMove(specialMove);
1091
1092 _lastSong = (int16)READ_BE_INT16(ptr); ptr += 2;
1093 }
1094
1095 if (joeRoom == _temporaryRoom &&
1096 joeRoom != 37 && joeRoom != 105 && joeRoom != 106 &&
1097 (joeX || joeY)) {
1098 BobSlot *joeBob = _vm->graphics()->bob(0);
1099
1100 debug(6, "[Cutaway::stop] Moving Joe");
1101
1102 joeBob->x = joeX;
1103 joeBob->y = joeY;
1104 _vm->logic()->joeScale(_vm->grid()->findScale(joeX, joeY));
1105 _vm->logic()->joeFace();
1106 }
1107 }
1108
updateGameState()1109 void Cutaway::updateGameState() {
1110 // Lines 2047-2115 in cutaway.c
1111 byte *ptr = _gameStatePtr;
1112
1113 int gameStateCount = (int16)READ_BE_INT16(ptr); ptr += 2;
1114
1115 for (int i = 0; i < gameStateCount; i++) {
1116 int16 stateIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
1117 int16 stateValue = (int16)READ_BE_INT16(ptr); ptr += 2;
1118 int16 objectIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
1119 int16 areaIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
1120 int16 areaSubIndex = (int16)READ_BE_INT16(ptr); ptr += 2;
1121 int16 fromObject = (int16)READ_BE_INT16(ptr); ptr += 2;
1122
1123 bool update = false;
1124
1125 if (stateIndex > 0) {
1126 if (_vm->logic()->gameState(stateIndex) == stateValue)
1127 update = true;
1128 } else {
1129 _vm->logic()->gameState(ABS(stateIndex), stateValue);
1130 update = true;
1131 }
1132
1133 if (update) {
1134
1135 if (objectIndex > 0) { // Show the object
1136 ObjectData *objectData = _vm->logic()->objectData(objectIndex);
1137 objectData->name = ABS(objectData->name);
1138 if (fromObject > 0)
1139 _vm->logic()->objectCopy(fromObject, objectIndex);
1140 _vm->graphics()->refreshObject(objectIndex);
1141 } else if (objectIndex < 0) { // Hide the object
1142 objectIndex = -objectIndex;
1143 ObjectData *objectData = _vm->logic()->objectData(objectIndex);
1144 objectData->name = -ABS(objectData->name);
1145 _vm->graphics()->refreshObject(objectIndex);
1146 }
1147
1148 if (areaIndex > 0) {
1149
1150 // Turn area on or off
1151
1152 if (areaSubIndex > 0) {
1153 Area *area = _vm->grid()->area(areaIndex, areaSubIndex);
1154 area->mapNeighbors = ABS(area->mapNeighbors);
1155 } else {
1156 Area *area = _vm->grid()->area(areaIndex, ABS(areaSubIndex));
1157 area->mapNeighbors = -ABS(area->mapNeighbors);
1158 }
1159 }
1160
1161 }
1162 } // for ()
1163 }
1164
talk(char * nextFilename)1165 void Cutaway::talk(char *nextFilename) {
1166 const char *p = strrchr(_talkFile, '.');
1167 if (p && 0 == scumm_stricmp(p, ".DOG")) {
1168 nextFilename[0] = '\0';
1169 assert(_talkTo > 0);
1170 int personInRoom = _talkTo - _vm->logic()->roomData(_vm->logic()->currentRoom());
1171 _vm->logic()->startDialogue(_talkFile, personInRoom, nextFilename);
1172 }
1173 }
1174
makeComplexAnimation(int16 currentImage,Cutaway::CutawayAnim * objAnim,int frameCount)1175 int Cutaway::makeComplexAnimation(int16 currentImage, Cutaway::CutawayAnim *objAnim, int frameCount) {
1176 int frameIndex[256];
1177 int i;
1178 assert(frameCount < 30);
1179 AnimFrame cutAnim[30];
1180
1181 memset(frameIndex, 0, sizeof(frameIndex));
1182 debug(6, "[Cutaway::makeComplexAnimation] currentImage = %i", currentImage);
1183
1184 for (i = 0; i < frameCount; i++) {
1185 cutAnim[i].frame = objAnim[i].unpackFrame;
1186 cutAnim[i].speed = objAnim[i].speed;
1187 frameIndex[objAnim[i].unpackFrame] = 1;
1188 }
1189
1190 cutAnim[frameCount].frame = 0;
1191 cutAnim[frameCount].speed = 0;
1192
1193 int nextFrameIndex = 1;
1194
1195 for (i = 1; i < 256; i++)
1196 if (frameIndex[i])
1197 frameIndex[i] = nextFrameIndex++;
1198
1199 for (i = 0; i < frameCount; i++) {
1200 cutAnim[i].frame = currentImage + frameIndex[objAnim[i].unpackFrame];
1201 }
1202
1203 for (i = 1; i < 256; i++) {
1204 if (frameIndex[i]) {
1205 currentImage++;
1206 _vm->bankMan()->unpack(i, currentImage, objAnim[0].bank);
1207 }
1208 }
1209
1210 _vm->graphics()->setBobCutawayAnim(objAnim[0].object, objAnim[0].flip, cutAnim, frameCount + 1);
1211 return currentImage;
1212 }
1213
handleText(int index,ObjectType type,CutawayObject & object,const char * sentence)1214 void Cutaway::handleText(
1215 int index,
1216 ObjectType type,
1217 CutawayObject &object,
1218 const char *sentence) {
1219 // lines 1776-1863 in cutaway.c
1220
1221 int spaces = countSpaces(type, sentence);
1222
1223 int x;
1224 int flags;
1225
1226 if (OBJECT_TYPE_TEXT_DISPLAY == type) {
1227 x = _vm->display()->textCenterX(sentence);
1228 flags = 2;
1229 } else {
1230 x = object.bobStartX;
1231 flags = 1;
1232 }
1233
1234 BobSlot *bob =
1235 _vm->graphics()->bob(_vm->logic()->findBob(ABS(object.objectNumber)));
1236
1237 _vm->graphics()->setBobText(bob, sentence, x, object.bobStartY, object.specialMove, flags);
1238
1239 if (OBJECT_TYPE_TEXT_SPEAK == type || OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK == type) {
1240 if (_vm->sound()->speechOn()) {
1241 char voiceFileName[MAX_STRING_SIZE];
1242 findCdCut(_basename, index, voiceFileName);
1243 strcat(voiceFileName, "1");
1244 _vm->sound()->playSpeech(voiceFileName);
1245 }
1246
1247 if (OBJECT_TYPE_TEXT_SPEAK == type && _vm->sound()->speechOn() && !_vm->subtitles())
1248 _vm->display()->clearTexts(0, 150);
1249 }
1250
1251 while (1) {
1252 _vm->update();
1253
1254 if (_vm->input()->cutawayQuit())
1255 return;
1256
1257 if (_vm->input()->keyVerb() == VERB_SKIP_TEXT) {
1258 _vm->input()->clearKeyVerb();
1259 break;
1260 }
1261
1262 if ((OBJECT_TYPE_TEXT_SPEAK == type || OBJECT_TYPE_TEXT_DISPLAY_AND_SPEAK == type) && _vm->sound()->speechOn() && _vm->sound()->speechSfxExists()) {
1263 if (!_vm->sound()->isSpeechActive()) {
1264 break;
1265 }
1266 } else {
1267 --spaces;
1268 if (spaces <= 0) {
1269 break;
1270 }
1271 }
1272 }
1273
1274 _vm->display()->clearTexts(0, 198);
1275 _vm->update();
1276 }
1277
countSpaces(ObjectType type,const char * segment)1278 int Cutaway::countSpaces(ObjectType type, const char *segment) {
1279 int tmp = 0;
1280
1281 while (*segment++)
1282 tmp++;
1283
1284 if (tmp < 50)
1285 tmp = 50;
1286
1287 if (OBJECT_TYPE_TEXT_DISPLAY == type)
1288 tmp *= 3;
1289
1290 return (tmp * 2) / (_vm->talkSpeed() / 3);
1291
1292 }
1293
scale(CutawayObject & object)1294 int Cutaway::scale(CutawayObject &object) {
1295 int scaling = 100;
1296
1297 if (object.scale > 0)
1298 scaling = object.scale;
1299 else if (!object.objectNumber) {
1300 // Only scale Joe
1301 int x, y;
1302
1303 if (object.bobStartX > 0 || object.bobStartY > 0) {
1304 x = object.bobStartX;
1305 y = object.bobStartY;
1306 } else {
1307 BobSlot *bob = _vm->graphics()->bob(0);
1308 x = bob->x;
1309 y = bob->y;
1310 }
1311
1312 int zone = _vm->grid()->findAreaForPos(GS_ROOM, x, y);
1313 if (zone > 0) {
1314 Area *area = _vm->grid()->area(_vm->logic()->currentRoom(), zone);
1315 scaling = area->calcScale(y);
1316 }
1317 }
1318
1319 return scaling;
1320 }
1321
1322 } // End of namespace Queen
1323