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/config-manager.h"
25 #include "common/textconsole.h"
26
27 #include "queen/logic.h"
28
29 #include "queen/bankman.h"
30 #include "queen/command.h"
31 #include "queen/credits.h"
32 #include "queen/cutaway.h"
33 #include "queen/debug.h"
34 #include "queen/defs.h"
35 #include "queen/display.h"
36 #include "queen/graphics.h"
37 #include "queen/grid.h"
38 #include "queen/input.h"
39 #include "queen/journal.h"
40 #include "queen/queen.h"
41 #include "queen/resource.h"
42 #include "queen/sound.h"
43 #include "queen/state.h"
44 #include "queen/talk.h"
45 #include "queen/walk.h"
46
47 namespace Queen {
48
Logic(QueenEngine * vm)49 Logic::Logic(QueenEngine *vm)
50 : _credits(NULL), _objectData(NULL), _roomData(NULL), _sfxName(NULL),
51 _itemData(NULL), _graphicData(NULL), _walkOffData(NULL), _objectDescription(NULL),
52 _furnitureData(NULL), _actorData(NULL), _graphicAnim(NULL), _vm(vm) {
53 _joe.x = _joe.y = 0;
54 _joe.scale = 100;
55 _joe.walk = JWM_NORMAL;
56 memset(_gameState, 0, sizeof(_gameState));
57 memset(_talkSelected, 0, sizeof(_talkSelected));
58 _puzzleAttemptCount = 0;
59 _journal = new Journal(vm);
60 _scene = 0;
61 memset(_specialMoves, 0, sizeof(_specialMoves));
62 readQueenJas();
63 }
64
~Logic()65 Logic::~Logic() {
66 delete _journal;
67 delete _credits;
68 delete[] _objectData;
69 delete[] _roomData;
70 delete[] _sfxName;
71 delete[] _itemData;
72 delete[] _graphicData;
73 delete[] _walkOffData;
74 delete[] _objectDescription;
75 delete[] _furnitureData;
76 delete[] _actorData;
77 delete[] _graphicAnim;
78 }
79
readQueenJas()80 void Logic::readQueenJas() {
81 int16 i;
82
83 uint8 *jas = _vm->resource()->loadFile("QUEEN.JAS", 20);
84 uint8 *ptr = jas;
85
86 _numRooms = READ_BE_UINT16(ptr); ptr += 2;
87 _numNames = READ_BE_UINT16(ptr); ptr += 2;
88 _numObjects = READ_BE_UINT16(ptr); ptr += 2;
89 _numDescriptions = READ_BE_UINT16(ptr); ptr += 2;
90
91 _objectData = new ObjectData[_numObjects + 1];
92 memset(&_objectData[0], 0, sizeof(ObjectData));
93 for (i = 1; i <= _numObjects; i++) {
94 _objectData[i].readFromBE(ptr);
95 }
96
97 _roomData = new uint16[_numRooms + 2];
98 _roomData[0] = 0;
99 for (i = 1; i <= (_numRooms + 1); i++) {
100 _roomData[i] = READ_BE_UINT16(ptr); ptr += 2;
101 }
102 _roomData[_numRooms + 1] = _numObjects;
103
104 if ((_vm->resource()->isDemo() && _vm->resource()->getPlatform() == Common::kPlatformDOS) ||
105 (_vm->resource()->isInterview() && _vm->resource()->getPlatform() == Common::kPlatformAmiga)) {
106 _sfxName = NULL;
107 } else {
108 _sfxName = new uint16[_numRooms + 1];
109 _sfxName[0] = 0;
110 for (i = 1; i <= _numRooms; i++) {
111 _sfxName[i] = READ_BE_UINT16(ptr); ptr += 2;
112 }
113 }
114
115 _numItems = READ_BE_UINT16(ptr); ptr += 2;
116 _itemData = new ItemData[_numItems + 1];
117 memset(&_itemData[0], 0, sizeof(ItemData));
118 for (i = 1; i <= _numItems; i++) {
119 _itemData[i].readFromBE(ptr);
120 }
121
122 _numGraphics = READ_BE_UINT16(ptr); ptr += 2;
123 _graphicData = new GraphicData[_numGraphics + 1];
124 memset(&_graphicData[0], 0, sizeof(GraphicData));
125 for (i = 1; i <= _numGraphics; i++) {
126 _graphicData[i].readFromBE(ptr);
127 }
128
129 _vm->grid()->readDataFrom(_numObjects, _numRooms, ptr);
130
131 _numWalkOffs = READ_BE_UINT16(ptr); ptr += 2;
132 _walkOffData = new WalkOffData[_numWalkOffs + 1];
133 memset(&_walkOffData[0], 0, sizeof(WalkOffData));
134 for (i = 1; i <= _numWalkOffs; i++) {
135 _walkOffData[i].readFromBE(ptr);
136 }
137
138 _numObjDesc = READ_BE_UINT16(ptr); ptr += 2;
139 _objectDescription = new ObjectDescription[_numObjDesc + 1];
140 memset(&_objectDescription[0], 0, sizeof(ObjectDescription));
141 for (i = 1; i <= _numObjDesc; i++) {
142 _objectDescription[i].readFromBE(ptr);
143 }
144
145 _vm->command()->readCommandsFrom(ptr);
146
147 _entryObj = READ_BE_UINT16(ptr); ptr += 2;
148
149 _numFurniture = READ_BE_UINT16(ptr); ptr += 2;
150 _furnitureData = new FurnitureData[_numFurniture + 1];
151 memset(&_furnitureData[0], 0, sizeof(FurnitureData));
152 for (i = 1; i <= _numFurniture; i++) {
153 _furnitureData[i].readFromBE(ptr);
154 }
155
156 // Actors
157 _numActors = READ_BE_UINT16(ptr); ptr += 2;
158 _numAAnim = READ_BE_UINT16(ptr); ptr += 2;
159 _numAName = READ_BE_UINT16(ptr); ptr += 2;
160 _numAFile = READ_BE_UINT16(ptr); ptr += 2;
161
162 _actorData = new ActorData[_numActors + 1];
163 memset(&_actorData[0], 0, sizeof(ActorData));
164 for (i = 1; i <= _numActors; i++) {
165 _actorData[i].readFromBE(ptr);
166 }
167
168 _numGraphicAnim = READ_BE_UINT16(ptr); ptr += 2;
169
170 _graphicAnim = new GraphicAnim[_numGraphicAnim + 1];
171 if (_numGraphicAnim == 0) {
172 _graphicAnim[0].readFromBE(ptr);
173 } else {
174 memset(&_graphicAnim[0], 0, sizeof(GraphicAnim));
175 for (i = 1; i <= _numGraphicAnim; i++) {
176 _graphicAnim[i].readFromBE(ptr);
177 }
178 }
179
180 _currentRoom = _objectData[_entryObj].room;
181 _entryObj = 0;
182
183 if (memcmp(ptr, _vm->resource()->getJASVersion(), 5) != 0) {
184 warning("Unexpected queen.jas file format");
185 }
186 delete[] jas;
187
188 _vm->resource()->loadTextFile("QUEEN2.JAS", _jasStringList);
189 _jasStringOffset[0] = 0;
190 _jasStringOffset[1] = _jasStringOffset[0] + _numDescriptions;
191 _jasStringOffset[2] = _jasStringOffset[1] + _numNames;
192 _jasStringOffset[3] = _jasStringOffset[2] + _numRooms;
193 _jasStringOffset[4] = _jasStringOffset[3] + 12;
194 _jasStringOffset[5] = _jasStringOffset[4] + JOE_RESPONSE_MAX;
195 _jasStringOffset[6] = _jasStringOffset[5] + _numAAnim;
196 _jasStringOffset[7] = _jasStringOffset[6] + _numAName;
197
198 // Patch for German text bug
199 if (_vm->resource()->getLanguage() == Common::DE_DEU) {
200 _jasStringList[_jasStringOffset[JSO_OBJECT_DESCRIPTION] + 296 - 1] = "Es bringt nicht viel, das festzubinden.";
201 }
202 }
203
start()204 void Logic::start() {
205 setupSpecialMoveTable();
206 _vm->command()->clear(false);
207 _vm->display()->setupPanel();
208 _vm->graphics()->unpackControlBank();
209 _vm->graphics()->setupMouseCursor();
210 setupJoe();
211 _vm->grid()->setupPanel();
212 inventorySetup();
213
214 _oldRoom = 0;
215 _newRoom = _currentRoom;
216 }
217
findBob(uint16 obj) const218 uint16 Logic::findBob(uint16 obj) const {
219 assert(obj <= _numObjects);
220
221 uint16 room = _objectData[obj].room;
222 assert(room <= _numRooms);
223
224 uint16 bobnum = 0;
225 int16 img = _objectData[obj].image;
226 if (img != 0) {
227 if (img == -3 || img == -4) {
228 // a person object
229 bobnum = findPersonNumber(obj, room);
230 } else {
231 uint16 bobtype = 0; // 1 for animated, 0 for static
232
233 if (img <= -10) {
234 // object has been turned off, but the image order hasn't been updated
235 if (_graphicData[-(img + 10)].lastFrame != 0) {
236 bobtype = 1;
237 }
238 } else if (img == -2) {
239 // -1 static, -2 animated
240 bobtype = 1;
241 } else if (img > 0) {
242 if (_graphicData[img].lastFrame != 0) {
243 bobtype = 1;
244 }
245 }
246
247 uint16 idxAnimated = 0;
248 uint16 idxStatic = 0;
249 for (uint16 i = _roomData[room] + 1; i <= obj; ++i) {
250 img = _objectData[i].image;
251 if (img <= -10) {
252 if (_graphicData[-(img + 10)].lastFrame != 0) {
253 ++idxAnimated;
254 } else {
255 ++idxStatic;
256 }
257 } else if (img > 0) {
258 if (img > 5000) {
259 img -= 5000;
260 }
261
262 assert (img <= _numGraphics);
263
264 if (_graphicData[img].lastFrame != 0) {
265 ++idxAnimated;
266 } else {
267 ++idxStatic;
268 }
269 } else if (img == -1) {
270 ++idxStatic;
271 } else if (img == -2) {
272 ++idxAnimated;
273 }
274 }
275 if (bobtype == 0) {
276 // static bob
277 if (idxStatic > 0) {
278 bobnum = 19 + _vm->graphics()->numStaticFurniture() + idxStatic;
279 }
280 } else {
281 // animated bob
282 if (idxAnimated > 0) {
283 bobnum = 4 + _vm->graphics()->numAnimatedFurniture() + idxAnimated;
284 }
285 }
286 }
287 }
288 return bobnum;
289 }
290
findFrame(uint16 obj) const291 uint16 Logic::findFrame(uint16 obj) const {
292 uint16 framenum = 0;
293 uint16 room = _objectData[obj].room;
294 int16 img = _objectData[obj].image;
295 if (img == -3 || img == -4) {
296 uint16 bobnum = findPersonNumber(obj, room);
297 if (bobnum <= 3) {
298 framenum = 31 + bobnum;
299 }
300 } else {
301 uint16 idx = 0;
302 for (uint16 i = _roomData[room] + 1; i < obj; ++i) {
303 img = _objectData[i].image;
304 if (img <= -10) {
305 const GraphicData* pgd = &_graphicData[-(img + 10)];
306 if (pgd->lastFrame != 0) {
307 // skip all the frames of the animation
308 idx += ABS(pgd->lastFrame) - pgd->firstFrame + 1;
309 } else {
310 // static bob, skip one frame
311 ++idx;
312 }
313 } else if (img == -1) {
314 ++idx;
315 } else if (img > 0) {
316 if (img > 5000) {
317 img -= 5000;
318 }
319 const GraphicData* pgd = &_graphicData[img];
320 uint16 lastFrame = ABS(pgd->lastFrame);
321 if (pgd->firstFrame < 0) {
322 idx += lastFrame;
323 } else if (lastFrame != 0) {
324 idx += (lastFrame - pgd->firstFrame) + 1;
325 } else {
326 ++idx;
327 }
328 }
329 }
330
331 img = _objectData[obj].image;
332 if (img <= -10) {
333 const GraphicData* pgd = &_graphicData[-(img + 10)];
334 if (pgd->lastFrame != 0) {
335 idx += ABS(pgd->lastFrame) - pgd->firstFrame + 1;
336 } else {
337 ++idx;
338 }
339 } else if (img == -1 || img > 0) {
340 ++idx;
341 }
342
343 // calculate only if there are person frames
344 if (idx > 0) {
345 framenum = FRAMES_JOE + _vm->graphics()->numFurnitureFrames() + idx;
346 }
347 }
348 return framenum;
349 }
350
objectForPerson(uint16 bobNum) const351 uint16 Logic::objectForPerson(uint16 bobNum) const {
352 uint16 bobcur = 0;
353 // first object number in the room
354 uint16 cur = currentRoomData() + 1;
355 // last object number in the room
356 uint16 last = _roomData[_currentRoom + 1];
357 for (; cur <= last; ++cur) {
358 int16 image = _objectData[cur].image;
359 if (image == -3 || image == -4) {
360 // the object is a bob
361 ++bobcur;
362 }
363 if (bobcur == bobNum) {
364 return cur;
365 }
366 }
367 return 0;
368 }
369
walkOffPointForObject(int16 obj) const370 WalkOffData *Logic::walkOffPointForObject(int16 obj) const {
371 for (uint16 i = 1; i <= _numWalkOffs; ++i) {
372 if (_walkOffData[i].entryObj == obj) {
373 return &_walkOffData[i];
374 }
375 }
376 return NULL;
377 }
378
joeWalk(JoeWalkMode walking)379 void Logic::joeWalk(JoeWalkMode walking) {
380 _joe.walk = walking;
381 // Do this so that Input doesn't need to know the walk value
382 _vm->input()->dialogueRunning(JWM_SPEAK == walking);
383 }
384
gameState(int index) const385 int16 Logic::gameState(int index) const {
386 assert(index >= 0 && index < GAME_STATE_COUNT);
387 return _gameState[index];
388 }
389
gameState(int index,int16 newValue)390 void Logic::gameState(int index, int16 newValue) {
391 assert(index >= 0 && index < GAME_STATE_COUNT);
392 debug(8, "Logic::gameState() [%d] = %d", index, newValue);
393 _gameState[index] = newValue;
394 }
395
roomName(uint16 roomNum) const396 const char *Logic::roomName(uint16 roomNum) const {
397 assert(roomNum >= 1 && roomNum <= _numRooms);
398 return _jasStringList[_jasStringOffset[JSO_ROOM_NAME] + roomNum - 1].c_str();
399 }
400
objectName(uint16 objNum) const401 const char *Logic::objectName(uint16 objNum) const {
402 assert(objNum >= 1 && objNum <= _numNames);
403 return _jasStringList[_jasStringOffset[JSO_OBJECT_NAME] + objNum - 1].c_str();
404 }
405
objectTextualDescription(uint16 objNum) const406 const char *Logic::objectTextualDescription(uint16 objNum) const {
407 assert(objNum >= 1 && objNum <= _numDescriptions);
408 return _jasStringList[_jasStringOffset[JSO_OBJECT_DESCRIPTION] + objNum - 1].c_str();
409 }
410
joeResponse(int i) const411 const char *Logic::joeResponse(int i) const {
412 assert(i >= 1 && i <= JOE_RESPONSE_MAX);
413 return _jasStringList[_jasStringOffset[JSO_JOE_RESPONSE] + i - 1].c_str();
414 }
415
verbName(Verb v) const416 const char *Logic::verbName(Verb v) const {
417 assert(v >= 0 && v <= 12);
418 if (v == 0) {
419 return "";
420 }
421 return _jasStringList[_jasStringOffset[JSO_VERB_NAME] + v - 1].c_str();
422 }
423
actorAnim(int num) const424 const char *Logic::actorAnim(int num) const {
425 assert(num >= 1 && num <= _numAAnim);
426 return _jasStringList[_jasStringOffset[JSO_ACTOR_ANIM] + num - 1].c_str();
427 }
428
actorName(int num) const429 const char *Logic::actorName(int num) const {
430 assert(num >= 1 && num <= _numAName);
431 return _jasStringList[_jasStringOffset[JSO_ACTOR_NAME] + num - 1].c_str();
432 }
433
actorFile(int num) const434 const char *Logic::actorFile(int num) const {
435 assert(num >= 1 && num <= _numAFile);
436 return _jasStringList[_jasStringOffset[JSO_ACTOR_FILE] + num - 1].c_str();
437 }
438
eraseRoom()439 void Logic::eraseRoom() {
440 _vm->bankMan()->eraseFrames(false);
441 _vm->bankMan()->close(15);
442 _vm->bankMan()->close(11);
443 _vm->bankMan()->close(10);
444 _vm->bankMan()->close(12);
445
446 _vm->display()->palFadeOut(_currentRoom);
447
448 // invalidates all persons animations
449 _vm->graphics()->clearPersonFrames();
450 _vm->graphics()->eraseAllAnims();
451
452 uint16 cur = _roomData[_oldRoom] + 1;
453 uint16 last = _roomData[_oldRoom + 1];
454 for (; cur <= last; ++cur) {
455 ObjectData *pod = &_objectData[cur];
456 if (pod->name == 0) {
457 // object has been deleted, invalidate image
458 pod->image = 0;
459 } else if (pod->image > -4000 && pod->image <= -10) {
460 if (_graphicData[ABS(pod->image + 10)].lastFrame == 0) {
461 // static Bob
462 pod->image = -1;
463 } else {
464 // animated Bob
465 pod->image = -2;
466 }
467 }
468 }
469 }
470
setupRoom(const char * room,int comPanel,bool inCutaway)471 void Logic::setupRoom(const char *room, int comPanel, bool inCutaway) {
472 // load backdrop image, init dynalum, setup colors
473 _vm->display()->setupNewRoom(room, _currentRoom);
474
475 // setup graphics to enter fullscreen/panel mode
476 _vm->display()->screenMode(comPanel, inCutaway);
477
478 _vm->grid()->setupNewRoom(_currentRoom, _roomData[_currentRoom]);
479
480 int16 furn[9];
481 uint16 furnTot = 0;
482 for (uint16 i = 1; i <= _numFurniture; ++i) {
483 if (_furnitureData[i].room == _currentRoom) {
484 ++furnTot;
485 furn[furnTot] = _furnitureData[i].objNum;
486 }
487 }
488 _vm->graphics()->setupNewRoom(room, _currentRoom, furn, furnTot);
489
490 _vm->display()->forceFullRefresh();
491 }
492
displayRoom(uint16 room,RoomDisplayMode mode,uint16 scale,int comPanel,bool inCutaway)493 void Logic::displayRoom(uint16 room, RoomDisplayMode mode, uint16 scale, int comPanel, bool inCutaway) {
494 debug(6, "Logic::displayRoom(%d, %d, %d, %d, %d)", room, mode, scale, comPanel, inCutaway);
495
496 eraseRoom();
497
498 if (_credits)
499 _credits->nextRoom();
500
501 setupRoom(roomName(room), comPanel, inCutaway);
502 if (mode != RDM_FADE_NOJOE) {
503 setupJoeInRoom(mode != RDM_FADE_JOE_XY, scale);
504 }
505 if (mode != RDM_NOFADE_JOE) {
506 _vm->update();
507 BobSlot *joe = _vm->graphics()->bob(0);
508 _vm->display()->palFadeIn(_currentRoom, joe->active, joe->x, joe->y);
509 }
510 if (mode != RDM_FADE_NOJOE && joeX() != 0 && joeY() != 0) {
511 int16 jx = joeX();
512 int16 jy = joeY();
513 joePos(0, 0);
514 _vm->walk()->moveJoe(0, jx, jy, inCutaway);
515 }
516 }
517
findActor(uint16 noun,const char * name) const518 ActorData *Logic::findActor(uint16 noun, const char *name) const {
519 uint16 obj = currentRoomData() + noun;
520 int16 img = objectData(obj)->image;
521 if (img != -3 && img != -4) {
522 warning("Logic::findActor() - Object %d is not a person", obj);
523 return NULL;
524 }
525
526 // search Bob number for the person
527 uint16 bobNum = findPersonNumber(obj, _currentRoom);
528
529 // search for a matching actor
530 if (bobNum > 0) {
531 for (uint16 i = 1; i <= _numActors; ++i) {
532 ActorData *pad = &_actorData[i];
533 if (pad->room == _currentRoom && gameState(pad->gsSlot) == pad->gsValue) {
534 if (bobNum == pad->bobNum || (name && strcmp(actorName(pad->name), name) == 0)) {
535 return pad;
536 }
537 }
538 }
539 }
540 return NULL;
541 }
542
initPerson(uint16 noun,const char * name,bool loadBank,Person * pp)543 bool Logic::initPerson(uint16 noun, const char *name, bool loadBank, Person *pp) {
544 const ActorData *pad = findActor(noun, name);
545 if (pad != NULL) {
546 pp->actor = pad;
547 pp->name = actorName(pad->name);
548 if (pad->anim != 0) {
549 pp->anim = actorAnim(pad->anim);
550 } else {
551 pp->anim = NULL;
552 }
553 if (loadBank && pad->file != 0) {
554 _vm->bankMan()->load(actorFile(pad->file), pad->bankNum);
555 // if there is no valid actor file (ie pad->file is 0), the person
556 // data is already loaded as it is included in objects room bank (.bbk)
557 }
558 pp->bobFrame = 31 + pp->actor->bobNum;
559 }
560 return pad != NULL;
561 }
562
findPersonNumber(uint16 obj,uint16 room) const563 uint16 Logic::findPersonNumber(uint16 obj, uint16 room) const {
564 uint16 num = 0;
565 for (uint16 i = _roomData[room] + 1; i <= obj; ++i) {
566 int16 img = _objectData[i].image;
567 if (img == -3 || img == -4) {
568 ++num;
569 }
570 }
571 return num;
572 }
573
loadJoeBanks(const char * animBank,const char * standBank)574 void Logic::loadJoeBanks(const char *animBank, const char *standBank) {
575 _vm->bankMan()->load(animBank, 13);
576 for (int i = 11; i < 31; ++i) {
577 _vm->bankMan()->unpack(i - 10, i, 13);
578 }
579 _vm->bankMan()->close(13);
580
581 _vm->bankMan()->load(standBank, 7);
582 _vm->bankMan()->unpack(1, 35, 7);
583 _vm->bankMan()->unpack(3, 36, 7);
584 _vm->bankMan()->unpack(5, 37, 7);
585 }
586
setupJoe()587 void Logic::setupJoe() {
588 loadJoeBanks("JOE_A.BBK", "JOE_B.BBK");
589 joePrevFacing(DIR_FRONT);
590 joeFacing(DIR_FRONT);
591 }
592
setupJoeInRoom(bool autoPosition,uint16 scale)593 void Logic::setupJoeInRoom(bool autoPosition, uint16 scale) {
594 debug(9, "Logic::setupJoeInRoom(%d, %d) joe.x=%d joe.y=%d", autoPosition, scale, _joe.x, _joe.y);
595
596 int16 oldx, oldy;
597 if (!autoPosition || joeX() != 0 || joeY() != 0) {
598 oldx = joeX();
599 oldy = joeY();
600 joePos(0, 0);
601 } else {
602 const ObjectData *pod = objectData(_entryObj);
603 // find the walk off point for the entry object and make
604 // Joe walking to that point
605 const WalkOffData *pwo = walkOffPointForObject(_entryObj);
606 if (pwo != NULL) {
607 oldx = pwo->x;
608 oldy = pwo->y;
609 // entryObj has a walk off point, then walk from there to object x,y
610 joePos(pod->x, pod->y);
611 } else {
612 // no walk off point, use object position
613 oldx = pod->x;
614 oldy = pod->y;
615 joePos(0, 0);
616 }
617 }
618
619 debug(6, "Logic::setupJoeInRoom() - oldx=%d, oldy=%d scale=%d", oldx, oldy, scale);
620
621 if (scale > 0 && scale < 100) {
622 joeScale(scale);
623 } else {
624 uint16 a = _vm->grid()->findAreaForPos(GS_ROOM, oldx, oldy);
625 if (a > 0) {
626 joeScale(_vm->grid()->area(_currentRoom, a)->calcScale(oldy));
627 } else {
628 joeScale(100);
629 }
630 }
631
632 if (joeCutFacing() > 0) {
633 joeFacing(joeCutFacing());
634 joeCutFacing(0);
635 } else {
636 // check to see which way Joe entered room
637 const ObjectData *pod = objectData(_entryObj);
638 switch (State::findDirection(pod->state)) {
639 case DIR_BACK:
640 joeFacing(DIR_FRONT);
641 break;
642 case DIR_FRONT:
643 joeFacing(DIR_BACK);
644 break;
645 case DIR_LEFT:
646 joeFacing(DIR_RIGHT);
647 break;
648 case DIR_RIGHT:
649 joeFacing(DIR_LEFT);
650 break;
651 default:
652 break;
653 }
654 }
655 joePrevFacing(joeFacing());
656
657 BobSlot *pbs = _vm->graphics()->bob(0);
658 pbs->scale = joeScale();
659
660 if (_currentRoom == 108) {
661 _vm->graphics()->putCameraOnBob(-1);
662 _vm->bankMan()->load("JOE_E.ACT", 7);
663 _vm->bankMan()->unpack(2, 31, 7);
664
665 _vm->display()->horizontalScroll(320);
666
667 joeFacing(DIR_RIGHT);
668 joeCutFacing(DIR_RIGHT);
669 joePrevFacing(DIR_RIGHT);
670 }
671
672 joeFace();
673 pbs->curPos(oldx, oldy);
674 pbs->frameNum = 31;
675 }
676
joeFace()677 uint16 Logic::joeFace() {
678 debug(9, "Logic::joeFace() - curFace = %d, prevFace = %d", _joe.facing, _joe.prevFacing);
679 BobSlot *pbs = _vm->graphics()->bob(0);
680 uint16 frame;
681 if (_currentRoom == 108) {
682 frame = 1;
683 } else {
684 frame = 35;
685 if (joeFacing() == DIR_FRONT) {
686 if (joePrevFacing() == DIR_BACK) {
687 pbs->frameNum = 35;
688 _vm->update();
689 }
690 frame = 36;
691 } else if (joeFacing() == DIR_BACK) {
692 if (joePrevFacing() == DIR_FRONT) {
693 pbs->frameNum = 35;
694 _vm->update();
695 }
696 frame = 37;
697 } else if ((joeFacing() == DIR_LEFT && joePrevFacing() == DIR_RIGHT)
698 || (joeFacing() == DIR_RIGHT && joePrevFacing() == DIR_LEFT)) {
699 pbs->frameNum = 36;
700 _vm->update();
701 }
702 pbs->frameNum = frame;
703 pbs->scale = joeScale();
704 pbs->xflip = (joeFacing() == DIR_LEFT);
705 _vm->update();
706 joePrevFacing(joeFacing());
707 switch (frame) {
708 case 35:
709 frame = 1;
710 break;
711 case 36:
712 frame = 3;
713 break;
714 case 37:
715 frame = 5;
716 break;
717 default:
718 break;
719 }
720 }
721 pbs->frameNum = 31;
722 _vm->bankMan()->unpack(frame, pbs->frameNum, 7);
723 return frame;
724 }
725
joeGrab(int16 grabState)726 void Logic::joeGrab(int16 grabState) {
727 uint16 frame = 0;
728 BobSlot *bobJoe = _vm->graphics()->bob(0);
729
730 switch (grabState) {
731 case STATE_GRAB_NONE:
732 break;
733 case STATE_GRAB_MID:
734 if (joeFacing() == DIR_BACK) {
735 frame = 6;
736 } else if (joeFacing() == DIR_FRONT) {
737 frame = 4;
738 } else {
739 frame = 2;
740 }
741 break;
742 case STATE_GRAB_DOWN:
743 if (joeFacing() == DIR_BACK) {
744 frame = 9;
745 } else {
746 frame = 8;
747 }
748 break;
749 case STATE_GRAB_UP:
750 // turn back
751 _vm->bankMan()->unpack(5, 31, 7);
752 bobJoe->xflip = (joeFacing() == DIR_LEFT);
753 bobJoe->scale = joeScale();
754 _vm->update();
755 // grab up
756 _vm->bankMan()->unpack(7, 31, 7);
757 bobJoe->xflip = (joeFacing() == DIR_LEFT);
758 bobJoe->scale = joeScale();
759 _vm->update();
760 // turn back
761 frame = 7;
762 break;
763 default:
764 break;
765 }
766
767 if (frame != 0) {
768 _vm->bankMan()->unpack(frame, 31, 7);
769 bobJoe->xflip = (joeFacing() == DIR_LEFT);
770 bobJoe->scale = joeScale();
771 _vm->update();
772
773 // extra delay for grab down
774 if (grabState == STATE_GRAB_DOWN) {
775 _vm->update();
776 _vm->update();
777 }
778 }
779 }
780
joeUseDress(bool showCut)781 void Logic::joeUseDress(bool showCut) {
782 if (showCut) {
783 joeFacing(DIR_FRONT);
784 joeFace();
785 if (gameState(VAR_JOE_DRESSING_MODE) == 0) {
786 playCutaway("CDRES.CUT");
787 inventoryInsertItem(ITEM_CLOTHES);
788 } else {
789 playCutaway("CUDRS.CUT");
790 }
791 }
792 _vm->display()->palSetJoeDress();
793 loadJoeBanks("JOED_A.BBK", "JOED_B.BBK");
794 inventoryDeleteItem(ITEM_DRESS);
795 gameState(VAR_JOE_DRESSING_MODE, 2);
796 }
797
joeUseClothes(bool showCut)798 void Logic::joeUseClothes(bool showCut) {
799 if (showCut) {
800 joeFacing(DIR_FRONT);
801 joeFace();
802 playCutaway("CDCLO.CUT");
803 inventoryInsertItem(ITEM_DRESS);
804 }
805 _vm->display()->palSetJoeNormal();
806 loadJoeBanks("JOE_A.BBK", "JOE_B.BBK");
807 inventoryDeleteItem(ITEM_CLOTHES);
808 gameState(VAR_JOE_DRESSING_MODE, 0);
809 }
810
joeUseUnderwear()811 void Logic::joeUseUnderwear() {
812 _vm->display()->palSetJoeNormal();
813 loadJoeBanks("JOEU_A.BBK", "JOEU_B.BBK");
814 gameState(VAR_JOE_DRESSING_MODE, 1);
815 }
816
makePersonSpeak(const char * sentence,Person * person,const char * voiceFilePrefix)817 void Logic::makePersonSpeak(const char *sentence, Person *person, const char *voiceFilePrefix) {
818 _vm->command()->clear(false);
819 Talk::speak(sentence, person, voiceFilePrefix, _vm);
820 }
821
startDialogue(const char * dlgFile,int personInRoom,char * cutaway)822 void Logic::startDialogue(const char *dlgFile, int personInRoom, char *cutaway) {
823 ObjectData *data = objectData(_roomData[_currentRoom] + personInRoom);
824 if (data->name > 0 && data->entryObj <= 0) {
825 if (State::findTalk(data->state) == STATE_TALK_MUTE) {
826 // 'I can't talk to that'
827 makeJoeSpeak(24 + _vm->randomizer.getRandomNumber(2));
828 } else {
829 char cutawayFile[20];
830 if (cutaway == NULL) {
831 cutaway = cutawayFile;
832 }
833 _vm->display()->fullscreen(true);
834 Talk::talk(dlgFile, personInRoom, cutaway, _vm);
835 if (!cutaway[0]) {
836 _vm->display()->fullscreen(false);
837 }
838 }
839 }
840 }
841
playCutaway(const char * cutFile,char * next)842 void Logic::playCutaway(const char *cutFile, char *next) {
843 char nextFile[20];
844 if (next == NULL) {
845 next = nextFile;
846 }
847 _vm->display()->clearTexts(CmdText::COMMAND_Y_POS, CmdText::COMMAND_Y_POS);
848 Cutaway::run(cutFile, next, _vm);
849 }
850
makeJoeSpeak(uint16 descNum,bool objectType)851 void Logic::makeJoeSpeak(uint16 descNum, bool objectType) {
852 const char *text = objectType ? objectTextualDescription(descNum) : joeResponse(descNum);
853 if (objectType) {
854 descNum += JOE_RESPONSE_MAX;
855 }
856 char descFilePrefix[10];
857 sprintf(descFilePrefix, "JOE%04i", descNum);
858 makePersonSpeak(text, NULL, descFilePrefix);
859 }
860
findInventoryItem(int invSlot) const861 uint16 Logic::findInventoryItem(int invSlot) const {
862 // queen.c l.3894-3898
863 if (invSlot >= 0 && invSlot < 4) {
864 return _inventoryItem[invSlot];
865 }
866 return 0;
867 }
868
inventorySetup()869 void Logic::inventorySetup() {
870 _vm->bankMan()->load("OBJECTS.BBK", 14);
871 if (_vm->resource()->isInterview()) {
872 _inventoryItem[0] = 1;
873 _inventoryItem[1] = 2;
874 _inventoryItem[2] = 3;
875 _inventoryItem[3] = 4;
876 } else {
877 _inventoryItem[0] = ITEM_BAT;
878 _inventoryItem[1] = ITEM_JOURNAL;
879 _inventoryItem[2] = ITEM_NONE;
880 _inventoryItem[3] = ITEM_NONE;
881 }
882 }
883
inventoryRefresh()884 void Logic::inventoryRefresh() {
885 uint16 x = 182;
886 for (int i = 0; i < 4; ++i) {
887 uint16 itemNum = _inventoryItem[i];
888 if (itemNum != 0) {
889 uint16 dstFrame = (i == 0) ? 8 : 9;
890 // unpack frame for object and draw it
891 _vm->bankMan()->unpack(_itemData[itemNum].frame, dstFrame, 14);
892 _vm->graphics()->drawInventoryItem(dstFrame, x, 14);
893 } else {
894 // no object, clear the panel
895 _vm->graphics()->drawInventoryItem(0, x, 14);
896 }
897 x += 35;
898 }
899 }
900
previousInventoryItem(int16 first) const901 int16 Logic::previousInventoryItem(int16 first) const {
902 int i;
903 for (i = first - 1; i >= 1; i--)
904 if (_itemData[i].name > 0)
905 return i;
906 for (i = _numItems; i > first; i--)
907 if (_itemData[i].name > 0)
908 return i;
909
910 return 0; //nothing found
911 }
912
nextInventoryItem(int16 first) const913 int16 Logic::nextInventoryItem(int16 first) const {
914 int i;
915 for (i = first + 1; i < _numItems; i++)
916 if (_itemData[i].name > 0)
917 return i;
918 for (i = 1; i < first; i++)
919 if (_itemData[i].name > 0)
920 return i;
921
922 return 0; //nothing found
923 }
924
removeDuplicateItems()925 void Logic::removeDuplicateItems() {
926 for (int i = 0; i < 4; i++)
927 for (int j = i + 1; j < 4; j++)
928 if (_inventoryItem[i] == _inventoryItem[j])
929 _inventoryItem[j] = ITEM_NONE;
930 }
931
numItemsInventory() const932 uint16 Logic::numItemsInventory() const {
933 uint16 count = 0;
934 for (int i = 1; i < _numItems; i++)
935 if (_itemData[i].name > 0)
936 count++;
937
938 return count;
939 }
940
inventoryInsertItem(uint16 itemNum,bool refresh)941 void Logic::inventoryInsertItem(uint16 itemNum, bool refresh) {
942 int16 item = _inventoryItem[0] = (int16)itemNum;
943 _itemData[itemNum].name = ABS(_itemData[itemNum].name); //set visible
944 for (int i = 1; i < 4; i++) {
945 item = nextInventoryItem(item);
946 _inventoryItem[i] = item;
947 removeDuplicateItems();
948 }
949
950 if (refresh)
951 inventoryRefresh();
952 }
953
inventoryDeleteItem(uint16 itemNum,bool refresh)954 void Logic::inventoryDeleteItem(uint16 itemNum, bool refresh) {
955 int16 item = (int16)itemNum;
956 _itemData[itemNum].name = -ABS(_itemData[itemNum].name); //set invisible
957 for (int i = 0; i < 4; i++) {
958 item = nextInventoryItem(item);
959 _inventoryItem[i] = item;
960 removeDuplicateItems();
961 }
962
963 if (refresh)
964 inventoryRefresh();
965 }
966
inventoryScroll(uint16 count,bool up)967 void Logic::inventoryScroll(uint16 count, bool up) {
968 if (!(numItemsInventory() > 4))
969 return;
970 while (count--) {
971 if (up) {
972 for (int i = 3; i > 0; i--)
973 _inventoryItem[i] = _inventoryItem[i - 1];
974 _inventoryItem[0] = previousInventoryItem(_inventoryItem[0]);
975 } else {
976 for (int i = 0; i < 3; i++)
977 _inventoryItem[i] = _inventoryItem[i + 1];
978 _inventoryItem[3] = nextInventoryItem(_inventoryItem[3]);
979 }
980 }
981
982 inventoryRefresh();
983 }
984
removeHotelItemsFromInventory()985 void Logic::removeHotelItemsFromInventory() {
986 if (currentRoom() == 1 && gameState(VAR_HOTEL_ITEMS_REMOVED) == 0) {
987 inventoryDeleteItem(ITEM_CROWBAR, false);
988 inventoryDeleteItem(ITEM_DRESS, false);
989 inventoryDeleteItem(ITEM_CLOTHES, false);
990 inventoryDeleteItem(ITEM_HAY, false);
991 inventoryDeleteItem(ITEM_OIL, false);
992 inventoryDeleteItem(ITEM_CHICKEN, false);
993 gameState(VAR_HOTEL_ITEMS_REMOVED, 1);
994 inventoryRefresh();
995 }
996 }
997
objectCopy(int dummyObjectIndex,int realObjectIndex)998 void Logic::objectCopy(int dummyObjectIndex, int realObjectIndex) {
999 // copy data from dummy object to real object, if COPY_FROM object
1000 // images are greater than COPY_TO Object images then swap the objects around.
1001
1002 ObjectData *dummyObject = objectData(dummyObjectIndex);
1003 ObjectData *realObject = objectData(realObjectIndex);
1004
1005 int fromState = (dummyObject->name < 0) ? -1 : 0;
1006
1007 int frameCountReal = 1;
1008 int frameCountDummy = 1;
1009
1010 int graphic = realObject->image;
1011 if (graphic > 0) {
1012 if (graphic > 5000)
1013 graphic -= 5000;
1014
1015 GraphicData *data = graphicData(graphic);
1016
1017 if (data->lastFrame > 0)
1018 frameCountReal = data->lastFrame - data->firstFrame + 1;
1019
1020 graphic = dummyObject->image;
1021 if (graphic > 0) {
1022 if (graphic > 5000)
1023 graphic -= 5000;
1024
1025 data = graphicData(graphic);
1026
1027 if (data->lastFrame > 0)
1028 frameCountDummy = data->lastFrame - data->firstFrame + 1;
1029 }
1030 }
1031
1032 ObjectData temp = *realObject;
1033 *realObject = *dummyObject;
1034
1035 if (frameCountDummy > frameCountReal)
1036 *dummyObject = temp;
1037
1038 realObject->name = ABS(realObject->name);
1039
1040 if (fromState == -1)
1041 dummyObject->name = -ABS(dummyObject->name);
1042
1043 for (int i = 1; i <= _numWalkOffs; i++) {
1044 WalkOffData *walkOff = &_walkOffData[i];
1045 if (walkOff->entryObj == (int16)dummyObjectIndex) {
1046 walkOff->entryObj = (int16)realObjectIndex;
1047 break;
1048 }
1049 }
1050 }
1051
handleSpecialArea(Direction facing,uint16 areaNum,uint16 walkDataNum)1052 void Logic::handleSpecialArea(Direction facing, uint16 areaNum, uint16 walkDataNum) {
1053 // queen.c l.2838-2911
1054 debug(9, "handleSpecialArea(%d, %d, %d)\n", facing, areaNum, walkDataNum);
1055
1056 // Stop animating Joe
1057 _vm->graphics()->bob(0)->animating = false;
1058
1059 // Make Joe face the right direction
1060 joeFacing(facing);
1061 joeFace();
1062
1063 _newRoom = 0;
1064 _entryObj = 0;
1065
1066 char nextCut[20];
1067 memset(nextCut, 0, sizeof(nextCut));
1068
1069 switch (_currentRoom) {
1070 case ROOM_JUNGLE_BRIDGE:
1071 makeJoeSpeak(16);
1072 break;
1073 case ROOM_JUNGLE_GORILLA_1:
1074 playCutaway("C6C.CUT", nextCut);
1075 break;
1076 case ROOM_JUNGLE_GORILLA_2:
1077 playCutaway("C14B.CUT", nextCut);
1078 break;
1079 case ROOM_AMAZON_ENTRANCE:
1080 if (areaNum == 3) {
1081 playCutaway("C16A.CUT", nextCut);
1082 }
1083 break;
1084 case ROOM_AMAZON_HIDEOUT:
1085 if (walkDataNum == 4) {
1086 playCutaway("C17A.CUT", nextCut);
1087 } else if (walkDataNum == 2) {
1088 playCutaway("C17B.CUT", nextCut);
1089 }
1090 break;
1091 case ROOM_FLODA_OUTSIDE:
1092 playCutaway("C22A.CUT", nextCut);
1093 break;
1094 case ROOM_FLODA_KITCHEN:
1095 playCutaway("C26B.CUT", nextCut);
1096 break;
1097 case ROOM_FLODA_KLUNK:
1098 playCutaway("C30A.CUT", nextCut);
1099 break;
1100 case ROOM_FLODA_HENRY:
1101 playCutaway("C32C.CUT", nextCut);
1102 break;
1103 case ROOM_TEMPLE_ZOMBIES:
1104 if (areaNum == 6) {
1105 switch (gameState(VAR_BYPASS_ZOMBIES)) {
1106 case 0:
1107 playCutaway("C50D.CUT", nextCut);
1108 while (nextCut[0] != '\0') {
1109 playCutaway(nextCut, nextCut);
1110 }
1111 gameState(VAR_BYPASS_ZOMBIES, 1);
1112 break;
1113 case 1:
1114 playCutaway("C50H.CUT", nextCut);
1115 break;
1116 default:
1117 break;
1118 }
1119 }
1120 break;
1121 case ROOM_TEMPLE_SNAKE:
1122 playCutaway("C53B.CUT", nextCut);
1123 break;
1124 case ROOM_TEMPLE_LIZARD_LASER:
1125 makeJoeSpeak(19);
1126 break;
1127 case ROOM_HOTEL_DOWNSTAIRS:
1128 makeJoeSpeak(21);
1129 break;
1130 case ROOM_HOTEL_LOBBY:
1131 switch (gameState(VAR_HOTEL_ESCAPE_STATE)) {
1132 case 0:
1133 playCutaway("C73A.CUT");
1134 joeUseUnderwear();
1135 joeFace();
1136 gameState(VAR_HOTEL_ESCAPE_STATE, 1);
1137 break;
1138 case 1:
1139 playCutaway("C73B.CUT");
1140 gameState(VAR_HOTEL_ESCAPE_STATE, 2);
1141 break;
1142 case 2:
1143 playCutaway("C73C.CUT");
1144 break;
1145 default:
1146 break;
1147 }
1148 break;
1149 case ROOM_TEMPLE_MAZE_5:
1150 if (areaNum == 7) {
1151 makeJoeSpeak(17);
1152 }
1153 break;
1154 case ROOM_TEMPLE_MAZE_6:
1155 if (areaNum == 5 && gameState(187) == 0) {
1156 playCutaway("C101B.CUT", nextCut);
1157 }
1158 break;
1159 case ROOM_FLODA_FRONTDESK:
1160 if (areaNum == 3) {
1161 switch (gameState(VAR_BYPASS_FLODA_RECEPTIONIST)) {
1162 case 0:
1163 playCutaway("C103B.CUT", nextCut);
1164 gameState(VAR_BYPASS_FLODA_RECEPTIONIST, 1);
1165 break;
1166 case 1:
1167 playCutaway("C103E.CUT", nextCut);
1168 break;
1169 default:
1170 break;
1171 }
1172 }
1173 break;
1174 default:
1175 break;
1176 }
1177
1178 while (strlen(nextCut) > 4 &&
1179 scumm_stricmp(nextCut + strlen(nextCut) - 4, ".CUT") == 0) {
1180 playCutaway(nextCut, nextCut);
1181 }
1182 }
1183
handlePinnacleRoom()1184 void Logic::handlePinnacleRoom() {
1185 // camera does not follow Joe anymore
1186 _vm->graphics()->putCameraOnBob(-1);
1187 displayRoom(ROOM_JUNGLE_PINNACLE, RDM_NOFADE_JOE, 100, 2, true);
1188
1189 BobSlot *joe = _vm->graphics()->bob(6);
1190 BobSlot *piton = _vm->graphics()->bob(7);
1191
1192 // set scrolling value to mouse position to avoid glitch
1193 Common::Point mouse = _vm->input()->getMousePos();
1194 _vm->display()->horizontalScroll(mouse.x);
1195
1196 joe->x = piton->x = 3 * mouse.x / 4 + 200;
1197 joe->frameNum = mouse.x / 36 + 45;
1198
1199 // bobs have been unpacked from animating objects, we don't need them
1200 // to animate anymore ; so turn animation off
1201 joe->animating = piton->animating = false;
1202
1203 _vm->update();
1204 _vm->display()->palFadeIn(ROOM_JUNGLE_PINNACLE, joe->active, joe->x, joe->y);
1205
1206 _entryObj = 0;
1207 uint16 prevObj = 0;
1208 CmdText *cmdText = CmdText::makeCmdTextInstance(5, _vm);
1209 cmdText->setVerb(VERB_WALK_TO);
1210 while (!_vm->shouldQuit() && (_vm->input()->mouseButton() == 0 || _entryObj == 0)) {
1211
1212 _vm->update();
1213 mouse = _vm->input()->getMousePos();
1214
1215 // update bobs position / frame
1216 joe->x = piton->x = 3 * mouse.x / 4 + 200;
1217 joe->frameNum = mouse.x / 36 + 45;
1218
1219 _vm->display()->clearTexts(5, 5);
1220
1221 uint16 curObj = _vm->grid()->findObjectUnderCursor(mouse.x, mouse.y);
1222 if (curObj != 0 && curObj != prevObj) {
1223 _entryObj = 0;
1224 curObj += currentRoomData(); // global object number
1225 ObjectData *objData = objectData(curObj);
1226 if (objData->name > 0) {
1227 _entryObj = objData->entryObj;
1228 cmdText->displayTemp(INK_PINNACLE_ROOM, objectName(objData->name), true);
1229 }
1230 prevObj = curObj;
1231 }
1232
1233 // update screen scrolling
1234 _vm->display()->horizontalScroll(mouse.x);
1235 }
1236 delete cmdText;
1237 _vm->input()->clearMouseButton();
1238
1239 _newRoom = objectData(_entryObj)->room;
1240
1241 // Only a few commands can be triggered from this room :
1242 // piton -> crash : 0x216 (obj1=0x2a, song=3)
1243 // piton -> floda : 0x217 (obj1=0x29, song=16)
1244 // piton -> bob : 0x219 (obj1=0x2f, song=6)
1245 // piton -> embark : 0x218 (obj1=0x2c, song=7)
1246 // piton -> jungle : 0x20B (obj1=0x2b, song=3)
1247 // piton -> amazon : 0x21A (obj1=0x30, song=3)
1248 //
1249 // Because none of these update objects/areas/gamestate, the EXECUTE_ACTION()
1250 // call, as the original does, is useless. All we have to do is the playsong
1251 // call (all songs have the PLAY_BEFORE type). This way we could get rid of
1252 // the hack described in execute.c l.334-339.
1253 struct {
1254 uint16 obj;
1255 int16 song;
1256 } cmds[] = {
1257 { 0x2A, 3 },
1258 { 0x29, 16 },
1259 { 0x2F, 6 },
1260 { 0x2C, 7 },
1261 { 0x2B, 3 },
1262 { 0x30, 3 }
1263 };
1264 for (int i = 0; i < ARRAYSIZE(cmds); ++i) {
1265 if (cmds[i].obj == prevObj) {
1266 _vm->sound()->playSong(cmds[i].song);
1267 break;
1268 }
1269 }
1270
1271 joe->active = piton->active = false;
1272 _vm->display()->clearTexts(5, 5);
1273
1274 // camera follows Joe again
1275 _vm->graphics()->putCameraOnBob(0);
1276
1277 _vm->display()->palFadeOut(ROOM_JUNGLE_PINNACLE);
1278 }
1279
update()1280 void Logic::update() {
1281 if (_credits)
1282 _credits->update();
1283
1284 if (_vm->debugger()->flags() & Debugger::DF_DRAW_AREAS) {
1285 _vm->grid()->drawZones();
1286 }
1287 }
1288
saveState(byte * & ptr)1289 void Logic::saveState(byte *&ptr) {
1290 uint16 i;
1291 for (i = 0; i < 4; i++) {
1292 WRITE_BE_UINT16(ptr, _inventoryItem[i]); ptr += 2;
1293 }
1294
1295 WRITE_BE_UINT16(ptr, _vm->graphics()->bob(0)->x); ptr += 2;
1296 WRITE_BE_UINT16(ptr, _vm->graphics()->bob(0)->y); ptr += 2;
1297
1298 WRITE_BE_UINT16(ptr, _currentRoom); ptr += 2;
1299
1300 for (i = 1; i <= _numObjects; i++)
1301 _objectData[i].writeToBE(ptr);
1302
1303 for (i = 1; i <= _numItems; i++)
1304 _itemData[i].writeToBE(ptr);
1305
1306 for (i = 0; i < GAME_STATE_COUNT; i++) {
1307 WRITE_BE_UINT16(ptr, _gameState[i]); ptr += 2;
1308 }
1309
1310 for (i = 0; i < TALK_SELECTED_COUNT; i++)
1311 _talkSelected[i].writeToBE(ptr);
1312
1313 for (i = 1; i <= _numWalkOffs; i++)
1314 _walkOffData[i].writeToBE(ptr);
1315
1316 WRITE_BE_UINT16(ptr, _joe.facing); ptr += 2;
1317
1318 // V1
1319 WRITE_BE_UINT16(ptr, _puzzleAttemptCount); ptr += 2;
1320 for (i = 1; i <= _numObjDesc; i++)
1321 _objectDescription[i].writeToBE(ptr);
1322 }
1323
loadState(uint32 ver,byte * & ptr)1324 void Logic::loadState(uint32 ver, byte *&ptr) {
1325 uint16 i;
1326 for (i = 0; i < 4; i++) {
1327 _inventoryItem[i] = (int16)READ_BE_INT16(ptr); ptr += 2;
1328 }
1329
1330 _joe.x = (int16)READ_BE_INT16(ptr); ptr += 2;
1331 _joe.y = (int16)READ_BE_INT16(ptr); ptr += 2;
1332
1333 _currentRoom = READ_BE_UINT16(ptr); ptr += 2;
1334
1335 for (i = 1; i <= _numObjects; i++)
1336 _objectData[i].readFromBE(ptr);
1337
1338 for (i = 1; i <= _numItems; i++)
1339 _itemData[i].readFromBE(ptr);
1340
1341 for (i = 0; i < GAME_STATE_COUNT; i++) {
1342 _gameState[i] = (int16)READ_BE_INT16(ptr); ptr += 2;
1343 }
1344
1345 for (i = 0; i < TALK_SELECTED_COUNT; i++)
1346 _talkSelected[i].readFromBE(ptr);
1347
1348 for (i = 1; i <= _numWalkOffs; i++)
1349 _walkOffData[i].readFromBE(ptr);
1350
1351 _joe.facing = READ_BE_UINT16(ptr); ptr += 2;
1352
1353 if (ver >= 1) {
1354 _puzzleAttemptCount = READ_BE_UINT16(ptr); ptr += 2;
1355
1356 for (i = 1; i <= _numObjDesc; i++)
1357 _objectDescription[i].readFromBE(ptr);
1358 }
1359 }
1360
setupRestoredGame()1361 void Logic::setupRestoredGame() {
1362 _vm->sound()->playLastSong();
1363
1364 switch (gameState(VAR_JOE_DRESSING_MODE)) {
1365 case 0:
1366 _vm->display()->palSetJoeNormal();
1367 loadJoeBanks("JOE_A.BBK", "JOE_B.BBK");
1368 break;
1369 case 1:
1370 _vm->display()->palSetJoeNormal();
1371 loadJoeBanks("JOEU_A.BBK", "JOEU_B.BBK");
1372 break;
1373 case 2:
1374 _vm->display()->palSetJoeDress();
1375 loadJoeBanks("JOED_A.BBK", "JOED_B.BBK");
1376 break;
1377 default:
1378 break;
1379 }
1380
1381 BobSlot *pbs = _vm->graphics()->bob(0);
1382 pbs->xflip = (joeFacing() == DIR_LEFT);
1383 joePrevFacing(joeFacing());
1384 joeCutFacing(joeFacing());
1385 switch (joeFacing()) {
1386 case DIR_FRONT:
1387 pbs->frameNum = 36;
1388 _vm->bankMan()->unpack(3, 31, 7);
1389 break;
1390 case DIR_BACK:
1391 pbs->frameNum = 37;
1392 _vm->bankMan()->unpack(5, 31, 7);
1393 break;
1394 default:
1395 pbs->frameNum = 35;
1396 _vm->bankMan()->unpack(1, 31, 7);
1397 break;
1398 }
1399
1400 _oldRoom = 0;
1401 _newRoom = _currentRoom;
1402 _entryObj = 0;
1403
1404 if (_vm->bam()->_flag != BamScene::F_STOP) {
1405 _vm->bam()->prepareAnimation();
1406 }
1407
1408 inventoryRefresh();
1409 }
1410
sceneStart()1411 void Logic::sceneStart() {
1412 debug(6, "[Logic::sceneStart] _scene = %i", _scene);
1413 _scene++;
1414
1415 _vm->display()->showMouseCursor(false);
1416
1417 if (1 == _scene) {
1418 _vm->display()->palGreyPanel();
1419 }
1420
1421 _vm->update();
1422 }
1423
sceneStop()1424 void Logic::sceneStop() {
1425 debug(6, "[Logic::sceneStop] _scene = %i", _scene);
1426 _scene--;
1427
1428 if (_scene > 0)
1429 return;
1430
1431 _vm->display()->palSetAllDirty();
1432 _vm->display()->showMouseCursor(true);
1433 _vm->grid()->setupPanel();
1434 }
1435
changeRoom()1436 void Logic::changeRoom() {
1437 if (!changeToSpecialRoom())
1438 displayRoom(currentRoom(), RDM_FADE_JOE, 100, 1, false);
1439 _vm->display()->showMouseCursor(true);
1440 }
1441
executeSpecialMove(uint16 sm)1442 void Logic::executeSpecialMove(uint16 sm) {
1443 debug(6, "Special move: %d", sm);
1444 if (sm < ARRAYSIZE(_specialMoves) && _specialMoves[sm] != 0) {
1445 (this->*_specialMoves[sm])();
1446 }
1447 }
1448
asmMakeJoeUseDress()1449 void Logic::asmMakeJoeUseDress() {
1450 joeUseDress(false);
1451 }
1452
asmMakeJoeUseNormalClothes()1453 void Logic::asmMakeJoeUseNormalClothes() {
1454 joeUseClothes(false);
1455 }
1456
asmMakeJoeUseUnderwear()1457 void Logic::asmMakeJoeUseUnderwear() {
1458 joeUseUnderwear();
1459 }
1460
asmSwitchToDressPalette()1461 void Logic::asmSwitchToDressPalette() {
1462 _vm->display()->palSetJoeDress();
1463 }
1464
asmSwitchToNormalPalette()1465 void Logic::asmSwitchToNormalPalette() {
1466 _vm->display()->palSetJoeNormal();
1467 }
1468
asmStartCarAnimation()1469 void Logic::asmStartCarAnimation() {
1470 _vm->bam()->_flag = BamScene::F_PLAY;
1471 _vm->bam()->prepareAnimation();
1472 }
1473
asmStopCarAnimation()1474 void Logic::asmStopCarAnimation() {
1475 _vm->bam()->_flag = BamScene::F_STOP;
1476 _vm->graphics()->bob(findBob(594))->active = false; // oil object
1477 _vm->graphics()->bob(7)->active = false; // gun shots
1478 }
1479
asmStartFightAnimation()1480 void Logic::asmStartFightAnimation() {
1481 _vm->bam()->_flag = BamScene::F_PLAY;
1482 _vm->bam()->prepareAnimation();
1483 gameState(148, 1);
1484 }
1485
asmWaitForFrankPosition()1486 void Logic::asmWaitForFrankPosition() {
1487 _vm->bam()->_flag = BamScene::F_REQ_STOP;
1488 while (_vm->bam()->_flag != BamScene::F_STOP) {
1489 _vm->update();
1490 }
1491 }
1492
asmMakeFrankGrowing()1493 void Logic::asmMakeFrankGrowing() {
1494 _vm->bankMan()->unpack(1, 38, 15);
1495 BobSlot *bobFrank = _vm->graphics()->bob(5);
1496 bobFrank->frameNum = 38;
1497 if (_vm->resource()->getPlatform() == Common::kPlatformAmiga) {
1498 bobFrank->active = true;
1499 bobFrank->x = 160;
1500 bobFrank->scale = 100;
1501 for (int i = 350; i >= 200; i -= 5) {
1502 bobFrank->y = i;
1503 _vm->update();
1504 }
1505 } else {
1506 bobFrank->curPos(160, 200);
1507 for (int i = 10; i <= 100; i += 4) {
1508 bobFrank->scale = i;
1509 _vm->update();
1510 }
1511 }
1512 for (int i = 0; i <= 20; ++i) {
1513 _vm->update();
1514 }
1515
1516 objectData(521)->name = ABS(objectData(521)->name); // Dinoray
1517 objectData(526)->name = ABS(objectData(526)->name); // Frank obj
1518 objectData(522)->name = -ABS(objectData(522)->name); // TMPD object off
1519 objectData(525)->name = -ABS(objectData(525)->name); // Floda guards off
1520 objectData(523)->name = -ABS(objectData(523)->name); // Sparky object off
1521 gameState(157, 1); // No more Ironstein
1522 }
1523
asmMakeRobotGrowing()1524 void Logic::asmMakeRobotGrowing() {
1525 _vm->bankMan()->unpack(1, 38, 15);
1526 BobSlot *bobRobot = _vm->graphics()->bob(5);
1527 bobRobot->frameNum = 38;
1528 if (_vm->resource()->getPlatform() == Common::kPlatformAmiga) {
1529 bobRobot->active = true;
1530 bobRobot->x = 160;
1531 bobRobot->scale = 100;
1532 for (int i = 350; i >= 200; i -= 5) {
1533 bobRobot->y = i;
1534 _vm->update();
1535 }
1536 } else {
1537 bobRobot->curPos(160, 200);
1538 for (int i = 10; i <= 100; i += 4) {
1539 bobRobot->scale = i;
1540 _vm->update();
1541 }
1542 }
1543 for (int i = 0; i <= 20; ++i) {
1544 _vm->update();
1545 }
1546
1547 objectData(524)->name = -ABS(objectData(524)->name); // Azura object off
1548 objectData(526)->name = -ABS(objectData(526)->name); // Frank object off
1549 }
1550
asmShrinkRobot()1551 void Logic::asmShrinkRobot() {
1552 int i;
1553 BobSlot *robot = _vm->graphics()->bob(6);
1554 for (i = 100; i >= 35; i -= 5) {
1555 robot->scale = i;
1556 _vm->update();
1557 }
1558 }
1559
asmEndGame()1560 void Logic::asmEndGame() {
1561 int n = 40;
1562 while (n--) {
1563 _vm->update();
1564 }
1565 // debug("Game completed.");
1566 _vm->quitGame();
1567 }
1568
asmPutCameraOnDino()1569 void Logic::asmPutCameraOnDino() {
1570 _vm->graphics()->putCameraOnBob(-1);
1571 int16 scrollx = _vm->display()->horizontalScroll();
1572 while (scrollx < 320) {
1573 scrollx += 16;
1574 if (scrollx > 320) {
1575 scrollx = 320;
1576 }
1577 _vm->display()->horizontalScroll(scrollx);
1578 _vm->update();
1579 }
1580 _vm->graphics()->putCameraOnBob(1);
1581 }
1582
asmPutCameraOnJoe()1583 void Logic::asmPutCameraOnJoe() {
1584 _vm->graphics()->putCameraOnBob(0);
1585 }
1586
asmAltIntroPanRight()1587 void Logic::asmAltIntroPanRight() {
1588 _vm->graphics()->putCameraOnBob(-1);
1589 _vm->input()->fastMode(true);
1590 _vm->update();
1591 int16 scrollx = _vm->display()->horizontalScroll();
1592 while (scrollx < 285 && !_vm->input()->cutawayQuit()) {
1593 ++scrollx;
1594 if (scrollx > 285) {
1595 scrollx = 285;
1596 }
1597 _vm->display()->horizontalScroll(scrollx);
1598 _vm->update();
1599 }
1600 _vm->input()->fastMode(false);
1601 }
1602
asmAltIntroPanLeft()1603 void Logic::asmAltIntroPanLeft() {
1604 _vm->graphics()->putCameraOnBob(-1);
1605 _vm->input()->fastMode(true);
1606 int16 scrollx = _vm->display()->horizontalScroll();
1607 while (scrollx > 0 && !_vm->input()->cutawayQuit()) {
1608 scrollx -= 4;
1609 if (scrollx < 0) {
1610 scrollx = 0;
1611 }
1612 _vm->display()->horizontalScroll(scrollx);
1613 _vm->update();
1614 }
1615 _vm->input()->fastMode(false);
1616 }
1617
asmSetAzuraInLove()1618 void Logic::asmSetAzuraInLove() {
1619 gameState(VAR_AZURA_IN_LOVE, 1);
1620 }
1621
asmPanRightFromJoe()1622 void Logic::asmPanRightFromJoe() {
1623 _vm->graphics()->putCameraOnBob(-1);
1624 int16 scrollx = _vm->display()->horizontalScroll();
1625 while (scrollx < 320) {
1626 scrollx += 16;
1627 if (scrollx > 320) {
1628 scrollx = 320;
1629 }
1630 _vm->display()->horizontalScroll(scrollx);
1631 _vm->update();
1632 }
1633 }
1634
asmSetLightsOff()1635 void Logic::asmSetLightsOff() {
1636 _vm->display()->palCustomLightsOff(currentRoom());
1637 }
1638
asmSetLightsOn()1639 void Logic::asmSetLightsOn() {
1640 _vm->display()->palCustomLightsOn(currentRoom());
1641 }
1642
asmSetManequinAreaOn()1643 void Logic::asmSetManequinAreaOn() {
1644 Area *a = _vm->grid()->area(ROOM_FLODA_FRONTDESK, 7);
1645 a->mapNeighbors = ABS(a->mapNeighbors);
1646 }
1647
asmPanToJoe()1648 void Logic::asmPanToJoe() {
1649 int i = _vm->graphics()->bob(0)->x - 160;
1650 if (i < 0) {
1651 i = 0;
1652 } else if (i > 320) {
1653 i = 320;
1654 }
1655 _vm->graphics()->putCameraOnBob(-1);
1656 int16 scrollx = _vm->display()->horizontalScroll();
1657 if (i < scrollx) {
1658 while (scrollx > i) {
1659 scrollx -= 16;
1660 if (scrollx < i) {
1661 scrollx = i;
1662 }
1663 _vm->display()->horizontalScroll(scrollx);
1664 _vm->update();
1665 }
1666 } else {
1667 while (scrollx < i) {
1668 scrollx += 16;
1669 if (scrollx > i) {
1670 scrollx = i;
1671 }
1672 _vm->display()->horizontalScroll(scrollx);
1673 _vm->update();
1674 }
1675 _vm->update();
1676 }
1677 _vm->graphics()->putCameraOnBob(0);
1678 }
1679
asmTurnGuardOn()1680 void Logic::asmTurnGuardOn() {
1681 gameState(VAR_GUARDS_TURNED_ON, 1);
1682 }
1683
asmPanLeft320To144()1684 void Logic::asmPanLeft320To144() {
1685 _vm->graphics()->putCameraOnBob(-1);
1686 int16 scrollx = _vm->display()->horizontalScroll();
1687 while (scrollx > 144) {
1688 scrollx -= 8;
1689 if (scrollx < 144) {
1690 scrollx = 144;
1691 }
1692 _vm->display()->horizontalScroll(scrollx);
1693 _vm->update();
1694 }
1695 }
1696
asmSmooch()1697 void Logic::asmSmooch() {
1698 _vm->graphics()->putCameraOnBob(-1);
1699 BobSlot *bobAzura = _vm->graphics()->bob(5);
1700 BobSlot *bobJoe = _vm->graphics()->bob(6);
1701 int16 scrollx = _vm->display()->horizontalScroll();
1702 while (scrollx < 320) {
1703 scrollx += 8;
1704 _vm->display()->horizontalScroll(scrollx);
1705 if (bobJoe->x - bobAzura->x > 128) {
1706 bobAzura->x += 10;
1707 bobJoe->x += 6;
1708 } else {
1709 bobAzura->x += 8;
1710 bobJoe->x += 8;
1711 }
1712 _vm->update();
1713 }
1714 }
1715
asmSmoochNoScroll()1716 void Logic::asmSmoochNoScroll() {
1717 _vm->graphics()->putCameraOnBob(-1);
1718 BobSlot *bobAzura = _vm->graphics()->bob(5);
1719 BobSlot *bobJoe = _vm->graphics()->bob(6);
1720 for (int i = 0; i < 320; i += 8) {
1721 if (bobJoe->x - bobAzura->x > 128) {
1722 bobAzura->x += 2;
1723 bobJoe->x -= 2;
1724 }
1725 _vm->update();
1726 }
1727 }
1728
asmMakeLightningHitPlane()1729 void Logic::asmMakeLightningHitPlane() {
1730 _vm->graphics()->putCameraOnBob(-1);
1731 short iy = 0, x, ydir = -1, j, k;
1732
1733 BobSlot *planeBob = _vm->graphics()->bob(5);
1734 BobSlot *lightningBob = _vm->graphics()->bob(20);
1735
1736 planeBob->y = 135;
1737
1738 if (_vm->resource()->getPlatform() == Common::kPlatformAmiga) {
1739 planeBob->scale = 100;
1740 } else {
1741 planeBob->scale = 20;
1742 }
1743
1744 for (x = 660; x > 163; x -= 6) {
1745 planeBob->x = x;
1746 planeBob->y = 135 + iy;
1747
1748 iy -= ydir;
1749 if (iy < -9 || iy > 9)
1750 ydir = -ydir;
1751
1752 planeBob->scale++;
1753 if (planeBob->scale > 100)
1754 planeBob->scale = 100;
1755
1756 int scrollX = x - 163;
1757 if (scrollX > 320)
1758 scrollX = 320;
1759 _vm->display()->horizontalScroll(scrollX);
1760 _vm->update();
1761 }
1762
1763 planeBob->scale = 100;
1764 _vm->display()->horizontalScroll(0);
1765
1766 planeBob->x += 8;
1767 planeBob->y += 6;
1768
1769 lightningBob->x = 160;
1770 lightningBob->y = 0;
1771
1772 _vm->sound()->playSfx(currentRoomSfx());
1773
1774 _vm->bankMan()->unpack(18, lightningBob->frameNum, 15);
1775 _vm->bankMan()->unpack(4, planeBob ->frameNum, 15);
1776
1777 // Plane plunges into the jungle!
1778 BobSlot *fireBob = _vm->graphics()->bob(6);
1779
1780 fireBob->animating = true;
1781 fireBob->x = planeBob->x;
1782 fireBob->y = planeBob->y + 10;
1783
1784 _vm->bankMan()->unpack(19, fireBob->frameNum, 15);
1785 _vm->update();
1786
1787 k = 20;
1788 j = 1;
1789
1790 for (x = 163; x > -30; x -= 10) {
1791 planeBob->y += 4;
1792 fireBob->y += 4;
1793 planeBob->x = fireBob->x = x;
1794
1795 if (k < 40) {
1796 _vm->bankMan()->unpack(j, planeBob->frameNum, 15);
1797 _vm->bankMan()->unpack(k, fireBob ->frameNum, 15);
1798 k++;
1799 j++;
1800
1801 if (j == 4)
1802 j = 1;
1803 }
1804
1805 _vm->update();
1806 }
1807
1808 _vm->graphics()->putCameraOnBob(0);
1809 }
1810
asmScaleBlimp()1811 void Logic::asmScaleBlimp() {
1812 int16 z = 256;
1813 BobSlot *bob = _vm->graphics()->bob(7);
1814 int16 x = bob->x;
1815 int16 y = bob->y;
1816 bob->scale = 100;
1817 while (bob->x > 150 && !_vm->shouldQuit()) {
1818 bob->x = x * 256 / z + 150;
1819 bob->y = y * 256 / z + 112;
1820 if (_vm->resource()->getPlatform() != Common::kPlatformAmiga) {
1821 bob->scale = 100 * 256 / z;
1822 }
1823 ++z;
1824 if (z % 6 == 0) {
1825 --x;
1826 }
1827
1828 _vm->update();
1829 }
1830 }
1831
asmScaleEnding()1832 void Logic::asmScaleEnding() {
1833 _vm->graphics()->bob(7)->active = false; // Turn off blimp
1834 BobSlot *b = _vm->graphics()->bob(20);
1835 b->curPos(160, 100);
1836 if (_vm->resource()->getPlatform() != Common::kPlatformAmiga) {
1837 for (int i = 5; i <= 100; i += 5) {
1838 b->scale = i;
1839 _vm->update();
1840 }
1841 }
1842 for (int i = 0; i < 50; ++i) {
1843 _vm->update();
1844 }
1845 _vm->display()->palFadeOut(_currentRoom);
1846 }
1847
asmWaitForCarPosition()1848 void Logic::asmWaitForCarPosition() {
1849 // Wait for car to reach correct position before pouring oil
1850 while (_vm->bam()->_index != 60) {
1851 _vm->update();
1852 }
1853 }
1854
asmShakeScreen()1855 void Logic::asmShakeScreen() {
1856 _vm->display()->shake(false);
1857 _vm->update();
1858 _vm->display()->shake(true);
1859 _vm->update();
1860 }
1861
asmAttemptPuzzle()1862 void Logic::asmAttemptPuzzle() {
1863 ++_puzzleAttemptCount;
1864 if (_puzzleAttemptCount == 4) {
1865 makeJoeSpeak(226, true);
1866 _puzzleAttemptCount = 0;
1867 }
1868 }
1869
asmScaleTitle()1870 void Logic::asmScaleTitle() {
1871 BobSlot *bob = _vm->graphics()->bob(5);
1872 bob->animating = false;
1873 bob->x = 161;
1874 bob->y = 200;
1875 bob->scale = 100;
1876
1877 int i;
1878 for (i = 5; i <= 100; i +=5) {
1879 bob->scale = i;
1880 bob->y -= 4;
1881 _vm->update();
1882 }
1883 }
1884
asmScrollTitle()1885 void Logic::asmScrollTitle() {
1886 BobSlot *bob = _vm->graphics()->bob(5);
1887 bob->animating = false;
1888 bob->x = 161;
1889 bob->y = 300;
1890 bob->scale = 100;
1891 while (bob->y >= 120) {
1892 _vm->update();
1893 bob->y -= 4;
1894 }
1895 }
1896
asmPanRightToHugh()1897 void Logic::asmPanRightToHugh() {
1898 BobSlot *bob_thugA1 = _vm->graphics()->bob(20);
1899 BobSlot *bob_thugA2 = _vm->graphics()->bob(21);
1900 BobSlot *bob_thugA3 = _vm->graphics()->bob(22);
1901 BobSlot *bob_hugh1 = _vm->graphics()->bob(1);
1902 BobSlot *bob_hugh2 = _vm->graphics()->bob(23);
1903 BobSlot *bob_hugh3 = _vm->graphics()->bob(24);
1904 BobSlot *bob_thugB1 = _vm->graphics()->bob(25);
1905 BobSlot *bob_thugB2 = _vm->graphics()->bob(26);
1906
1907 _vm->graphics()->putCameraOnBob(-1);
1908 _vm->input()->fastMode(true);
1909 _vm->update();
1910
1911 // Adjust thug1 gun so it matches rest of body
1912 bob_thugA1->x += 160 - 45;
1913 bob_thugA2->x += 160;
1914 bob_thugA3->x += 160;
1915
1916 bob_hugh1->x += 160 * 2;
1917 bob_hugh2->x += 160 * 2;
1918 bob_hugh3->x += 160 * 2;
1919
1920 bob_thugB1->x += 160 * 3;
1921 bob_thugB2->x += 160 * 3;
1922
1923 int horizontalScroll = 0;
1924 while (horizontalScroll < 160 && !_vm->input()->cutawayQuit()) {
1925
1926 horizontalScroll += 8;
1927 if (horizontalScroll > 160)
1928 horizontalScroll = 160;
1929
1930 _vm->display()->horizontalScroll(horizontalScroll);
1931
1932 bob_thugA1->x -= 16;
1933 bob_thugA2->x -= 16;
1934 bob_thugA3->x -= 16;
1935
1936 bob_hugh1->x -= 24;
1937 bob_hugh2->x -= 24;
1938 bob_hugh3->x -= 24;
1939
1940 bob_thugB1->x -= 32;
1941 bob_thugB2->x -= 32;
1942
1943 _vm->update();
1944 }
1945
1946 _vm->input()->fastMode(false);
1947 }
1948
asmMakeWhiteFlash()1949 void Logic::asmMakeWhiteFlash() {
1950 _vm->display()->palCustomFlash();
1951 }
1952
asmPanRightToJoeAndRita()1953 void Logic::asmPanRightToJoeAndRita() { // cdint.cut
1954 BobSlot *bob_box = _vm->graphics()->bob(20);
1955 BobSlot *bob_beam = _vm->graphics()->bob(21);
1956 BobSlot *bob_crate = _vm->graphics()->bob(22);
1957 BobSlot *bob_clock = _vm->graphics()->bob(23);
1958 BobSlot *bob_hands = _vm->graphics()->bob(24);
1959
1960 _vm->graphics()->putCameraOnBob(-1);
1961 _vm->input()->fastMode(true);
1962
1963 _vm->update();
1964
1965 bob_box ->x += 280 * 2;
1966 bob_beam ->x += 30;
1967 bob_crate->x += 180 * 3;
1968
1969 int horizontalScroll = _vm->display()->horizontalScroll();
1970
1971 while (horizontalScroll < 290 && !_vm->input()->cutawayQuit()) {
1972
1973 ++horizontalScroll;
1974 if (horizontalScroll > 290)
1975 horizontalScroll = 290;
1976
1977 _vm->display()->horizontalScroll(horizontalScroll);
1978
1979 bob_box ->x -= 2;
1980 bob_beam ->x -= 1;
1981 bob_crate->x -= 3;
1982 bob_clock->x -= 2;
1983 bob_hands->x -= 2;
1984
1985 _vm->update();
1986 }
1987 _vm->input()->fastMode(false);
1988 }
1989
asmPanLeftToBomb()1990 void Logic::asmPanLeftToBomb() {
1991 BobSlot *bob21 = _vm->graphics()->bob(21);
1992 BobSlot *bob22 = _vm->graphics()->bob(22);
1993
1994 _vm->graphics()->putCameraOnBob(-1);
1995 _vm->input()->fastMode(true);
1996
1997 int horizontalScroll = _vm->display()->horizontalScroll();
1998
1999 while ((horizontalScroll > 0 || bob21->x < 136) && !_vm->input()->cutawayQuit()) {
2000
2001 horizontalScroll -= 5;
2002 if (horizontalScroll < 0)
2003 horizontalScroll = 0;
2004
2005 _vm->display()->horizontalScroll(horizontalScroll);
2006
2007 if (horizontalScroll < 272 && bob21->x < 136)
2008 bob21->x += 2;
2009
2010 bob22->x += 5;
2011
2012 _vm->update();
2013 }
2014
2015 _vm->input()->fastMode(false);
2016 }
2017
asmEndDemo()2018 void Logic::asmEndDemo() {
2019 // debug("Flight of the Amazon Queen, released January 95.");
2020 _vm->quitGame();
2021 }
2022
asmInterviewIntro()2023 void Logic::asmInterviewIntro() {
2024 // put camera on airship
2025 _vm->graphics()->putCameraOnBob(5);
2026 BobSlot *bas = _vm->graphics()->bob(5);
2027
2028 bas->curPos(-30, 40);
2029
2030 bas->move(700, 10, 3);
2031 int scale = 450;
2032 while (bas->moving && !_vm->input()->cutawayQuit()) {
2033 bas->scale = 256 * 100 / scale;
2034 --scale;
2035 if (scale < 256) {
2036 scale = 256;
2037 }
2038 _vm->update();
2039 }
2040
2041 bas->scale = 90;
2042 bas->xflip = true;
2043
2044 bas->move(560, 25, 4);
2045 while (bas->moving && !_vm->input()->cutawayQuit()) {
2046 _vm->update();
2047 }
2048
2049 bas->move(545, 65, 2);
2050 while (bas->moving && !_vm->input()->cutawayQuit()) {
2051 _vm->update();
2052 }
2053
2054 bas->move(540, 75, 2);
2055 while (bas->moving && !_vm->input()->cutawayQuit()) {
2056 _vm->update();
2057 }
2058
2059 // put camera on Joe
2060 _vm->graphics()->putCameraOnBob(0);
2061 }
2062
asmEndInterview()2063 void Logic::asmEndInterview() {
2064 // debug("Interactive Interview copyright (c) 1995, IBI.");
2065 _vm->quitGame();
2066 }
2067
startCredits(const char * filename)2068 void Logic::startCredits(const char *filename) {
2069 stopCredits();
2070 _credits = new Credits(_vm, filename);
2071 }
2072
stopCredits()2073 void Logic::stopCredits() {
2074 if (_credits) {
2075 _vm->display()->clearTexts(0, 199);
2076 delete _credits;
2077 _credits = NULL;
2078 }
2079 }
2080
useJournal()2081 void LogicDemo::useJournal() {
2082 makePersonSpeak("This is a demo, so I can't load or save games*14", NULL, "");
2083 }
2084
changeToSpecialRoom()2085 bool LogicDemo::changeToSpecialRoom() {
2086 if (currentRoom() == FOTAQ_LOGO && gameState(VAR_INTRO_PLAYED) == 0) {
2087 currentRoom(79);
2088 displayRoom(currentRoom(), RDM_FADE_NOJOE, 100, 2, true);
2089 playCutaway("CLOGO.CUT");
2090 sceneReset();
2091 if (_vm->shouldQuit())
2092 return true;
2093 currentRoom(ROOM_HOTEL_LOBBY);
2094 entryObj(584);
2095 displayRoom(currentRoom(), RDM_FADE_JOE, 100, 2, true);
2096 playCutaway("C70D.CUT");
2097 gameState(VAR_INTRO_PLAYED, 1);
2098 inventoryRefresh();
2099 return true;
2100 }
2101 return false;
2102 }
2103
setupSpecialMoveTable()2104 void LogicDemo::setupSpecialMoveTable() {
2105 _specialMoves[4] = &LogicDemo::asmMakeJoeUseUnderwear;
2106 _specialMoves[14] = &LogicDemo::asmEndDemo;
2107 if (_vm->resource()->getPlatform() == Common::kPlatformDOS) {
2108 _specialMoves[5] = &LogicDemo::asmSwitchToDressPalette;
2109 }
2110 }
2111
useJournal()2112 void LogicInterview::useJournal() {
2113 // no-op
2114 }
2115
changeToSpecialRoom()2116 bool LogicInterview::changeToSpecialRoom() {
2117 if (currentRoom() == 2 && gameState(2) == 0) {
2118 currentRoom(6);
2119 displayRoom(currentRoom(), RDM_FADE_NOJOE, 100, 2, true);
2120 playCutaway("START.CUT");
2121 gameState(2, 1);
2122 inventoryRefresh();
2123 return true;
2124 }
2125 return false;
2126 }
2127
setupSpecialMoveTable()2128 void LogicInterview::setupSpecialMoveTable() {
2129 _specialMoves[1] = &LogicInterview::asmInterviewIntro;
2130 _specialMoves[2] = &LogicInterview::asmEndInterview;
2131 }
2132
useJournal()2133 void LogicGame::useJournal() {
2134 _vm->input()->clearKeyVerb();
2135 _vm->input()->clearMouseButton();
2136
2137 _vm->command()->clear(false);
2138 _journal->use();
2139 _vm->walk()->stopJoe();
2140
2141 _vm->input()->clearKeyVerb();
2142 _vm->input()->clearMouseButton();
2143 }
2144
changeToSpecialRoom()2145 bool LogicGame::changeToSpecialRoom() {
2146 if (currentRoom() == ROOM_JUNGLE_PINNACLE) {
2147 handlePinnacleRoom();
2148 return true;
2149 } else if (currentRoom() == FOTAQ_LOGO && gameState(VAR_INTRO_PLAYED) == 0) {
2150 displayRoom(currentRoom(), RDM_FADE_NOJOE, 100, 2, true);
2151 playCutaway("COPY.CUT");
2152 if (_vm->shouldQuit())
2153 return true;
2154 playCutaway("CLOGO.CUT");
2155 if (_vm->shouldQuit())
2156 return true;
2157 if (_vm->resource()->getPlatform() != Common::kPlatformAmiga) {
2158 if (ConfMan.getBool("alt_intro") && _vm->resource()->isCD()) {
2159 playCutaway("CINTR.CUT");
2160 } else {
2161 playCutaway("CDINT.CUT");
2162 }
2163 }
2164 if (_vm->shouldQuit())
2165 return true;
2166 playCutaway("CRED.CUT");
2167 if (_vm->shouldQuit())
2168 return true;
2169 _vm->display()->palSetPanel();
2170 sceneReset();
2171 currentRoom(ROOM_HOTEL_LOBBY);
2172 entryObj(584);
2173 displayRoom(currentRoom(), RDM_FADE_JOE, 100, 2, true);
2174 playCutaway("C70D.CUT");
2175 gameState(VAR_INTRO_PLAYED, 1);
2176 inventoryRefresh();
2177 return true;
2178 }
2179 return false;
2180 }
2181
setupSpecialMoveTable()2182 void LogicGame::setupSpecialMoveTable() {
2183 _specialMoves[2] = &LogicGame::asmMakeJoeUseDress;
2184 _specialMoves[3] = &LogicGame::asmMakeJoeUseNormalClothes;
2185 _specialMoves[4] = &LogicGame::asmMakeJoeUseUnderwear;
2186 _specialMoves[7] = &LogicGame::asmStartCarAnimation; // room 74
2187 _specialMoves[8] = &LogicGame::asmStopCarAnimation; // room 74
2188 _specialMoves[9] = &LogicGame::asmStartFightAnimation; // room 69
2189 _specialMoves[10] = &LogicGame::asmWaitForFrankPosition; // c69e.cut
2190 _specialMoves[11] = &LogicGame::asmMakeFrankGrowing; // c69z.cut
2191 _specialMoves[12] = &LogicGame::asmMakeRobotGrowing; // c69z.cut
2192 _specialMoves[14] = &LogicGame::asmEndGame;
2193 _specialMoves[15] = &LogicGame::asmPutCameraOnDino;
2194 _specialMoves[16] = &LogicGame::asmPutCameraOnJoe;
2195 _specialMoves[19] = &LogicGame::asmSetAzuraInLove;
2196 _specialMoves[20] = &LogicGame::asmPanRightFromJoe;
2197 _specialMoves[21] = &LogicGame::asmSetLightsOff;
2198 _specialMoves[22] = &LogicGame::asmSetLightsOn;
2199 _specialMoves[23] = &LogicGame::asmSetManequinAreaOn;
2200 _specialMoves[24] = &LogicGame::asmPanToJoe;
2201 _specialMoves[25] = &LogicGame::asmTurnGuardOn;
2202 _specialMoves[26] = &LogicGame::asmPanLeft320To144;
2203 _specialMoves[27] = &LogicGame::asmSmoochNoScroll;
2204 _specialMoves[28] = &LogicGame::asmMakeLightningHitPlane;
2205 _specialMoves[29] = &LogicGame::asmScaleBlimp;
2206 _specialMoves[30] = &LogicGame::asmScaleEnding;
2207 _specialMoves[31] = &LogicGame::asmWaitForCarPosition;
2208 _specialMoves[33] = &LogicGame::asmAttemptPuzzle;
2209 _specialMoves[34] = &LogicGame::asmScrollTitle;
2210 if (_vm->resource()->getPlatform() == Common::kPlatformDOS) {
2211 _specialMoves[5] = &LogicGame::asmSwitchToDressPalette;
2212 _specialMoves[6] = &LogicGame::asmSwitchToNormalPalette;
2213 _specialMoves[13] = &LogicGame::asmShrinkRobot;
2214 _specialMoves[17] = &LogicGame::asmAltIntroPanRight; // cintr.cut
2215 _specialMoves[18] = &LogicGame::asmAltIntroPanLeft; // cintr.cut
2216 _specialMoves[27] = &LogicGame::asmSmooch;
2217 _specialMoves[32] = &LogicGame::asmShakeScreen;
2218 _specialMoves[34] = &LogicGame::asmScaleTitle;
2219 _specialMoves[36] = &LogicGame::asmPanRightToHugh;
2220 _specialMoves[37] = &LogicGame::asmMakeWhiteFlash;
2221 _specialMoves[38] = &LogicGame::asmPanRightToJoeAndRita;
2222 _specialMoves[39] = &LogicGame::asmPanLeftToBomb; // cdint.cut
2223 }
2224 }
2225
2226 } // End of namespace Queen
2227