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 "kyra/engine/kyra_lok.h"
24 #include "kyra/resource/resource.h"
25 #include "kyra/sound/sound.h"
26 #include "kyra/engine/sprites.h"
27 #include "kyra/graphics/animator_lok.h"
28 #include "kyra/engine/timer.h"
29
30 #include "common/system.h"
31
32 namespace Kyra {
33
enterNewScene(int sceneId,int facing,int unk1,int unk2,int brandonAlive)34 void KyraEngine_LoK::enterNewScene(int sceneId, int facing, int unk1, int unk2, int brandonAlive) {
35 int unkVar1 = 1;
36 _screen->hideMouse();
37
38 // TODO: Check how the original handled sfx still playing
39 _sound->stopAllSoundEffects();
40
41 if (_flags.platform == Common::kPlatformFMTowns) {
42 int newSfxFile = -1;
43 if (_currentCharacter->sceneId == 7 && sceneId == 24)
44 newSfxFile = 2;
45 else if (_currentCharacter->sceneId == 25 && sceneId == 109)
46 newSfxFile = 3;
47 else if (_currentCharacter->sceneId == 120 && sceneId == 37)
48 newSfxFile = 4;
49 else if (_currentCharacter->sceneId == 52 && sceneId == 199)
50 newSfxFile = 5;
51 else if (_currentCharacter->sceneId == 37 && sceneId == 120)
52 newSfxFile = 3;
53 else if (_currentCharacter->sceneId == 109 && sceneId == 25)
54 newSfxFile = 2;
55 else if (_currentCharacter->sceneId == 24 && sceneId == 7)
56 newSfxFile = 1;
57
58 if (newSfxFile != -1) {
59 _curSfxFile = newSfxFile;
60 _sound->loadSoundFile(_curSfxFile);
61 }
62 }
63
64 switch (_currentCharacter->sceneId) {
65 case 1:
66 if (sceneId == 0) {
67 moveCharacterToPos(0, 0, _currentCharacter->x1, 84);
68 unkVar1 = 0;
69 }
70 break;
71
72 case 3:
73 if (sceneId == 2) {
74 moveCharacterToPos(0, 6, 155, _currentCharacter->y1);
75 unkVar1 = 0;
76 }
77 break;
78
79 case 26:
80 if (sceneId == 27) {
81 moveCharacterToPos(0, 6, 155, _currentCharacter->y1);
82 unkVar1 = 0;
83 }
84 break;
85
86 case 44:
87 if (sceneId == 45) {
88 moveCharacterToPos(0, 2, 192, _currentCharacter->y1);
89 unkVar1 = 0;
90 }
91 break;
92
93 default:
94 break;
95 }
96
97 if (unkVar1 && unk1) {
98 int xpos = _currentCharacter->x1;
99 int ypos = _currentCharacter->y1;
100 switch (facing) {
101 case 0:
102 ypos = _currentCharacter->y1 - 6;
103 break;
104
105 case 2:
106 xpos = 336;
107 break;
108
109 case 4:
110 ypos = 143;
111 break;
112
113 case 6:
114 xpos = -16;
115 break;
116
117 default:
118 break;
119 }
120
121 moveCharacterToPos(0, facing, xpos, ypos);
122 }
123
124 for (int i = 0; i < ARRAYSIZE(_movieObjects); ++i)
125 _movieObjects[i]->close();
126
127 if (!brandonAlive) {
128 _emc->init(&_scriptClick, &_scriptClickData);
129 _emc->start(&_scriptClick, 5);
130 while (_emc->isValid(&_scriptClick))
131 _emc->run(&_scriptClick);
132 }
133
134 memset(_entranceMouseCursorTracks, 0xFF, sizeof(_entranceMouseCursorTracks));
135 _currentCharacter->sceneId = sceneId;
136
137 assert(sceneId < _roomTableSize);
138 assert(_roomTable[sceneId].nameIndex < _roomFilenameTableSize);
139
140 Room *currentRoom = &_roomTable[sceneId];
141
142 setupSceneResource(sceneId);
143
144 _currentRoom = sceneId;
145
146 int tableId = _roomTable[sceneId].nameIndex;
147 char fileNameBuffer[32];
148 strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
149 strcat(fileNameBuffer, ".DAT");
150 _sprites->loadDat(fileNameBuffer, _sceneExits);
151 _sprites->setupSceneAnims();
152 _emc->unload(&_scriptClickData);
153 loadSceneMsc();
154
155 _walkBlockNorth = currentRoom->northExit;
156 _walkBlockEast = currentRoom->eastExit;
157 _walkBlockSouth = currentRoom->southExit;
158 _walkBlockWest = currentRoom->westExit;
159
160 if (_walkBlockNorth == 0xFFFF)
161 _screen->blockOutRegion(0, 0, 320, (_northExitHeight & 0xFF) + 3);
162 if (_walkBlockEast == 0xFFFF)
163 _screen->blockOutRegion(312, 0, 8, 139);
164 if (_walkBlockSouth == 0xFFFF)
165 _screen->blockOutRegion(0, 135, 320, 8);
166 if (_walkBlockWest == 0xFFFF)
167 _screen->blockOutRegion(0, 0, 8, 139);
168
169 if (!brandonAlive)
170 updatePlayerItemsForScene();
171
172 startSceneScript(brandonAlive);
173 setupSceneItems();
174
175 initSceneData(facing, unk2, brandonAlive);
176
177 setTextFadeTimerCountdown(-1);
178 _scriptClick.regs[3] = 1;
179
180 _loopFlag2 = 0;
181 _screen->showMouse();
182 if (!brandonAlive)
183 seq_poisonDeathNow(0);
184 updateMousePointer(true);
185 _changedScene = true;
186 }
187
transcendScenes(int roomIndex,int roomName)188 void KyraEngine_LoK::transcendScenes(int roomIndex, int roomName) {
189 assert(roomIndex < _roomTableSize);
190
191 if (_flags.isTalkie) {
192 char file[32];
193 assert(roomIndex < _roomTableSize);
194 int tableId = _roomTable[roomIndex].nameIndex;
195 assert(tableId < _roomFilenameTableSize);
196 strcpy(file, _roomFilenameTable[tableId]);
197 strcat(file, ".VRM");
198 _res->unloadPakFile(file);
199 }
200
201 _roomTable[roomIndex].nameIndex = roomName;
202 _unkScreenVar2 = 1;
203 _unkScreenVar3 = 1;
204 _unkScreenVar1 = 0;
205 _brandonPosX = _currentCharacter->x1;
206 _brandonPosY = _currentCharacter->y1;
207 enterNewScene(roomIndex, _currentCharacter->facing, 0, 0, 0);
208 _unkScreenVar1 = 1;
209 _unkScreenVar2 = 0;
210 _unkScreenVar3 = 0;
211 }
212
setSceneFile(int roomIndex,int roomName)213 void KyraEngine_LoK::setSceneFile(int roomIndex, int roomName) {
214 assert(roomIndex < _roomTableSize);
215 _roomTable[roomIndex].nameIndex = roomName;
216 }
217
moveCharacterToPos(int character,int facing,int xpos,int ypos)218 void KyraEngine_LoK::moveCharacterToPos(int character, int facing, int xpos, int ypos) {
219 Character *ch = &_characterList[character];
220 ch->facing = facing;
221 _screen->hideMouse();
222 xpos = (int16)(xpos & 0xFFFC);
223 ypos = (int16)(ypos & 0xFFFE);
224 _timer->disable(19);
225 _timer->disable(14);
226 _timer->disable(18);
227 uint32 nextFrame = 0;
228
229 switch (facing) {
230 case 0:
231 while (ypos < ch->y1) {
232 nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
233 setCharacterPositionWithUpdate(character);
234 delayUntil(nextFrame, true);
235 }
236 break;
237
238 case 2:
239 while (ch->x1 < xpos) {
240 nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
241 setCharacterPositionWithUpdate(character);
242 delayUntil(nextFrame, true);
243 }
244 break;
245
246 case 4:
247 while (ypos > ch->y1) {
248 nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
249 setCharacterPositionWithUpdate(character);
250 delayUntil(nextFrame, true);
251 }
252 break;
253
254 case 6:
255 while (ch->x1 > xpos) {
256 nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
257 setCharacterPositionWithUpdate(character);
258 delayUntil(nextFrame, true);
259 }
260 break;
261
262 default:
263 break;
264 }
265
266 _timer->enable(19);
267 _timer->enable(14);
268 _timer->enable(18);
269 _screen->showMouse();
270 }
271
setCharacterPositionWithUpdate(int character)272 void KyraEngine_LoK::setCharacterPositionWithUpdate(int character) {
273 setCharacterPosition(character, 0);
274 _sprites->updateSceneAnims();
275 _timer->update();
276 _animator->updateAllObjectShapes();
277 updateTextFade();
278
279 if (_currentCharacter->sceneId == 210)
280 updateKyragemFading();
281 }
282
setCharacterPosition(int character,int * facingTable)283 int KyraEngine_LoK::setCharacterPosition(int character, int *facingTable) {
284 if (character == 0) {
285 _currentCharacter->x1 += _charAddXPosTable[_currentCharacter->facing];
286 _currentCharacter->y1 += _charAddYPosTable[_currentCharacter->facing];
287 setCharacterPositionHelper(0, facingTable);
288 return 1;
289 } else {
290 _characterList[character].x1 += _charAddXPosTable[_characterList[character].facing];
291 _characterList[character].y1 += _charAddYPosTable[_characterList[character].facing];
292 if (_characterList[character].sceneId == _currentCharacter->sceneId)
293 setCharacterPositionHelper(character, 0);
294 }
295 return 0;
296 }
297
setCharacterPositionHelper(int character,int * facingTable)298 void KyraEngine_LoK::setCharacterPositionHelper(int character, int *facingTable) {
299 Character *ch = &_characterList[character];
300 ++ch->currentAnimFrame;
301 int facing = ch->facing;
302 if (facingTable) {
303 if (*facingTable != *(facingTable - 1)) {
304 if (*(facingTable - 1) == *(facingTable + 1)) {
305 facing = getOppositeFacingDirection(*(facingTable - 1));
306 *facingTable = *(facingTable - 1);
307 }
308 }
309 }
310
311 if (facing == 0) {
312 ++_characterFacingZeroCount[character];
313 } else {
314 bool resetTables = false;
315 if (facing != 7) {
316 if (facing - 1 != 0) {
317 if (facing != 4) {
318 if (facing == 3 || facing == 5) {
319 if (_characterFacingFourCount[character] > 2)
320 facing = 4;
321 resetTables = true;
322 }
323 } else {
324 ++_characterFacingFourCount[character];
325 }
326 } else {
327 if (_characterFacingZeroCount[character] > 2)
328 facing = 0;
329 resetTables = true;
330 }
331 } else {
332 if (_characterFacingZeroCount[character] > 2)
333 facing = 0;
334 resetTables = true;
335 }
336
337 if (resetTables) {
338 _characterFacingZeroCount[character] = 0;
339 _characterFacingFourCount[character] = 0;
340 }
341 }
342
343 static const uint16 maxAnimationFrame[] = {
344 0x000F, 0x0031, 0x0055, 0x0000, 0x0000, 0x0000,
345 0x0008, 0x002A, 0x004E, 0x0000, 0x0000, 0x0000,
346 0x0022, 0x0046, 0x006A, 0x0000, 0x0000, 0x0000,
347 0x001D, 0x0041, 0x0065, 0x0000, 0x0000, 0x0000,
348 0x001F, 0x0043, 0x0067, 0x0000, 0x0000, 0x0000,
349 0x0028, 0x004C, 0x0070, 0x0000, 0x0000, 0x0000,
350 0x0023, 0x0047, 0x006B, 0x0000, 0x0000, 0x0000
351 };
352
353 if (facing == 0) {
354 if (maxAnimationFrame[36 + character] > ch->currentAnimFrame)
355 ch->currentAnimFrame = maxAnimationFrame[36 + character];
356 if (maxAnimationFrame[30 + character] < ch->currentAnimFrame)
357 ch->currentAnimFrame = maxAnimationFrame[36 + character];
358 } else if (facing == 4) {
359 if (maxAnimationFrame[18 + character] > ch->currentAnimFrame)
360 ch->currentAnimFrame = maxAnimationFrame[18 + character];
361 if (maxAnimationFrame[12 + character] < ch->currentAnimFrame)
362 ch->currentAnimFrame = maxAnimationFrame[18 + character];
363 } else {
364 if (maxAnimationFrame[18 + character] < ch->currentAnimFrame)
365 ch->currentAnimFrame = maxAnimationFrame[30 + character];
366 if (maxAnimationFrame[character] == ch->currentAnimFrame)
367 ch->currentAnimFrame = maxAnimationFrame[6 + character];
368 if (maxAnimationFrame[character] < ch->currentAnimFrame)
369 ch->currentAnimFrame = maxAnimationFrame[6 + character] + 2;
370 }
371
372 if (character == 0 && (_brandonStatusBit & 0x10))
373 ch->currentAnimFrame = 88;
374
375 _animator->animRefreshNPC(character);
376 }
377
loadSceneMsc()378 void KyraEngine_LoK::loadSceneMsc() {
379 assert(_currentCharacter->sceneId < _roomTableSize);
380 int tableId = _roomTable[_currentCharacter->sceneId].nameIndex;
381 assert(tableId < _roomFilenameTableSize);
382 char fileNameBuffer[32];
383 strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
384 strcat(fileNameBuffer, ".MSC");
385 _screen->fillRect(0, 0, 319, 199, 0, 5);
386 _res->exists(fileNameBuffer, true);
387 _screen->loadBitmap(fileNameBuffer, 3, 5, 0);
388 }
389
startSceneScript(int brandonAlive)390 void KyraEngine_LoK::startSceneScript(int brandonAlive) {
391 assert(_currentCharacter->sceneId < _roomTableSize);
392 int tableId = _roomTable[_currentCharacter->sceneId].nameIndex;
393 assert(tableId < _roomFilenameTableSize);
394 char fileNameBuffer[32];
395 strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
396 strcat(fileNameBuffer, ".CPS");
397 _screen->clearPage(3);
398 _res->exists(fileNameBuffer, true);
399 // FIXME: check this hack for amiga version
400 _screen->loadBitmap(fileNameBuffer, 3, 3, (_flags.platform == Common::kPlatformAmiga ? &_screen->getPalette(0) : 0));
401 _sprites->loadSceneShapes();
402 _exitListPtr = 0;
403
404 _scaleMode = 1;
405 for (int i = 0; i < 145; ++i)
406 _scaleTable[i] = 256;
407
408 clearNoDropRects();
409 _emc->init(&_scriptClick, &_scriptClickData);
410 strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
411 strcat(fileNameBuffer, ".EMC");
412 _res->exists(fileNameBuffer, true);
413 _emc->unload(&_scriptClickData);
414 _emc->load(fileNameBuffer, &_scriptClickData, &_opcodes);
415 _emc->start(&_scriptClick, 0);
416 _scriptClick.regs[0] = _currentCharacter->sceneId;
417 _scriptClick.regs[7] = brandonAlive;
418
419 while (_emc->isValid(&_scriptClick))
420 _emc->run(&_scriptClick);
421 }
422
initSceneData(int facing,int unk1,int brandonAlive)423 void KyraEngine_LoK::initSceneData(int facing, int unk1, int brandonAlive) {
424 int16 xpos2 = 0;
425 int setFacing = 1;
426
427 int16 xpos = 0, ypos = 0;
428
429 if (_brandonPosX == -1 && _brandonPosY == -1) {
430 switch (facing + 1) {
431 case 0:
432 xpos = ypos = -1;
433 break;
434
435 case 1: case 2: case 8:
436 xpos = _sceneExits.southXPos;
437 ypos = _sceneExits.southYPos;
438 break;
439
440 case 3:
441 xpos = _sceneExits.westXPos;
442 ypos = _sceneExits.westYPos;
443 break;
444
445 case 4: case 5: case 6:
446 xpos = _sceneExits.northXPos;
447 ypos = _sceneExits.northYPos;
448 break;
449
450 case 7:
451 xpos = _sceneExits.eastXPos;
452 ypos = _sceneExits.eastYPos;
453 break;
454
455 default:
456 break;
457 }
458
459 if ((uint8)(_northExitHeight & 0xFF) + 2 >= ypos)
460 ypos = (_northExitHeight & 0xFF) + 4;
461 if (xpos >= 308)
462 xpos = 304;
463 if ((uint8)(_northExitHeight >> 8) - 2 <= ypos)
464 ypos = (_northExitHeight >> 8) - 4;
465 if (xpos <= 12)
466 xpos = 16;
467 }
468
469 if (_brandonPosX > -1)
470 xpos = _brandonPosX;
471 if (_brandonPosY > -1)
472 ypos = _brandonPosY;
473
474 int16 ypos2 = 0;
475 if (_brandonPosX > -1 && _brandonPosY > -1) {
476 switch (_currentCharacter->sceneId) {
477 case 1:
478 _currentCharacter->x1 = xpos;
479 _currentCharacter->x2 = xpos;
480 _currentCharacter->y1 = ypos;
481 _currentCharacter->y2 = ypos;
482 facing = 4;
483 xpos2 = 192;
484 ypos2 = 104;
485 setFacing = 0;
486 unk1 = 1;
487 break;
488
489 case 3:
490 _currentCharacter->x1 = xpos;
491 _currentCharacter->x2 = xpos;
492 _currentCharacter->y1 = ypos;
493 _currentCharacter->y2 = ypos;
494 facing = 2;
495 xpos2 = 204;
496 ypos2 = 94;
497 setFacing = 0;
498 unk1 = 1;
499 break;
500
501 case 26:
502 _currentCharacter->x1 = xpos;
503 _currentCharacter->x2 = xpos;
504 _currentCharacter->y1 = ypos;
505 _currentCharacter->y2 = ypos;
506 facing = 2;
507 xpos2 = 192;
508 ypos2 = 128;
509 setFacing = 0;
510 unk1 = 1;
511 break;
512
513 case 44:
514 _currentCharacter->x1 = xpos;
515 _currentCharacter->x2 = xpos;
516 _currentCharacter->y1 = ypos;
517 _currentCharacter->y2 = ypos;
518 facing = 6;
519 xpos2 = 156;
520 ypos2 = 96;
521 setFacing = 0;
522 unk1 = 1;
523 break;
524
525 case 37:
526 _currentCharacter->x1 = xpos;
527 _currentCharacter->x2 = xpos;
528 _currentCharacter->y1 = ypos;
529 _currentCharacter->y2 = ypos;
530 facing = 2;
531 xpos2 = 148;
532 ypos2 = 114;
533 setFacing = 0;
534 unk1 = 1;
535 break;
536
537 default:
538 break;
539 }
540 }
541
542 _brandonPosX = _brandonPosY = -1;
543
544 if (unk1 && setFacing) {
545 ypos2 = ypos;
546 xpos2 = xpos;
547 switch (facing) {
548 case 0:
549 ypos = 142;
550 break;
551
552 case 2:
553 xpos = -16;
554 break;
555
556 case 4:
557 ypos = (uint8)(_northExitHeight & 0xFF) - 4;
558 break;
559
560 case 6:
561 xpos = 336;
562 break;
563
564 default:
565 break;
566 }
567 }
568
569 xpos2 = (int16)(xpos2 & 0xFFFC);
570 ypos2 = (int16)(ypos2 & 0xFFFE);
571 xpos = (int16)(xpos & 0xFFFC);
572 ypos = (int16)(ypos & 0xFFFE);
573 _currentCharacter->facing = facing;
574 _currentCharacter->x1 = xpos;
575 _currentCharacter->x2 = xpos;
576 _currentCharacter->y1 = ypos;
577 _currentCharacter->y2 = ypos;
578
579 initSceneObjectList(brandonAlive);
580
581 if (unk1 && brandonAlive == 0)
582 moveCharacterToPos(0, facing, xpos2, ypos2);
583
584 _scriptClick.regs[4] = _itemInHand;
585 _scriptClick.regs[7] = brandonAlive;
586 _emc->start(&_scriptClick, 3);
587 while (_emc->isValid(&_scriptClick))
588 _emc->run(&_scriptClick);
589 }
590
initSceneObjectList(int brandonAlive)591 void KyraEngine_LoK::initSceneObjectList(int brandonAlive) {
592 for (int i = 0; i < 28; ++i)
593 _animator->actors()[i].active = 0;
594
595 int startAnimFrame = 0;
596
597 Animator_LoK::AnimObject *curAnimState = _animator->actors();
598 curAnimState->active = 1;
599 curAnimState->drawY = _currentCharacter->y1;
600 curAnimState->sceneAnimPtr = _shapes[_currentCharacter->currentAnimFrame];
601 curAnimState->animFrameNumber = _currentCharacter->currentAnimFrame;
602 startAnimFrame = _currentCharacter->currentAnimFrame - 7;
603 int xOffset = _defaultShapeTable[startAnimFrame].xOffset;
604 int yOffset = _defaultShapeTable[startAnimFrame].yOffset;
605
606 if (_scaleMode) {
607 curAnimState->x1 = _currentCharacter->x1;
608 curAnimState->y1 = _currentCharacter->y1;
609
610 _animator->_brandonScaleX = _scaleTable[_currentCharacter->y1];
611 _animator->_brandonScaleY = _scaleTable[_currentCharacter->y1];
612
613 curAnimState->x1 += (_animator->_brandonScaleX * xOffset) >> 8;
614 curAnimState->y1 += (_animator->_brandonScaleY * yOffset) >> 8;
615 } else {
616 curAnimState->x1 = _currentCharacter->x1 + xOffset;
617 curAnimState->y1 = _currentCharacter->y1 + yOffset;
618 }
619
620 curAnimState->x2 = curAnimState->x1;
621 curAnimState->y2 = curAnimState->y1;
622 curAnimState->refreshFlag = 1;
623 curAnimState->bkgdChangeFlag = 1;
624 _animator->clearQueue();
625 _animator->addObjectToQueue(curAnimState);
626
627 int listAdded = 0;
628 int addedObjects = 1;
629
630 for (int i = 1; i < 5; ++i) {
631 Character *ch = &_characterList[i];
632 curAnimState = &_animator->actors()[addedObjects];
633 if (ch->sceneId != _currentCharacter->sceneId) {
634 curAnimState->active = 0;
635 curAnimState->refreshFlag = 0;
636 curAnimState->bkgdChangeFlag = 0;
637 ++addedObjects;
638 continue;
639 }
640
641 curAnimState->drawY = ch->y1;
642 curAnimState->sceneAnimPtr = _shapes[ch->currentAnimFrame];
643 curAnimState->animFrameNumber = ch->currentAnimFrame;
644 startAnimFrame = ch->currentAnimFrame - 7;
645 xOffset = _defaultShapeTable[startAnimFrame].xOffset;
646 yOffset = _defaultShapeTable[startAnimFrame].yOffset;
647 if (_scaleMode) {
648 curAnimState->x1 = ch->x1;
649 curAnimState->y1 = ch->y1;
650
651 _animator->_brandonScaleX = _scaleTable[ch->y1];
652 _animator->_brandonScaleY = _scaleTable[ch->y1];
653
654 curAnimState->x1 += (_animator->_brandonScaleX * xOffset) >> 8;
655 curAnimState->y1 += (_animator->_brandonScaleY * yOffset) >> 8;
656 } else {
657 curAnimState->x1 = ch->x1 + xOffset;
658 curAnimState->y1 = ch->y1 + yOffset;
659 }
660 curAnimState->x2 = curAnimState->x1;
661 curAnimState->y2 = curAnimState->y1;
662 curAnimState->active = 1;
663 curAnimState->refreshFlag = 1;
664 curAnimState->bkgdChangeFlag = 1;
665
666 if (ch->facing >= 1 && ch->facing <= 3)
667 curAnimState->flags |= 1;
668 else if (ch->facing >= 5 && ch->facing <= 7)
669 curAnimState->flags &= 0xFFFFFFFE;
670
671 _animator->addObjectToQueue(curAnimState);
672
673 ++addedObjects;
674 ++listAdded;
675 if (listAdded < 2)
676 i = 5;
677 }
678
679 for (int i = 0; i < 11; ++i) {
680 curAnimState = &_animator->sprites()[i];
681
682 if (_sprites->_anims[i].play) {
683 curAnimState->active = 1;
684 curAnimState->refreshFlag = 1;
685 curAnimState->bkgdChangeFlag = 1;
686 } else {
687 curAnimState->active = 0;
688 curAnimState->refreshFlag = 0;
689 curAnimState->bkgdChangeFlag = 0;
690 }
691 curAnimState->height = _sprites->_anims[i].height;
692 curAnimState->height2 = _sprites->_anims[i].height2;
693 curAnimState->width = _sprites->_anims[i].width + 1;
694 curAnimState->width2 = _sprites->_anims[i].width2;
695 curAnimState->drawY = _sprites->_anims[i].drawY;
696 curAnimState->x1 = curAnimState->x2 = _sprites->_anims[i].x;
697 curAnimState->y1 = curAnimState->y2 = _sprites->_anims[i].y;
698 curAnimState->background = _sprites->_anims[i].background;
699 curAnimState->sceneAnimPtr = _sprites->_sceneShapes[_sprites->_anims[i].sprite];
700
701 curAnimState->disable = _sprites->_anims[i].disable;
702
703 if (_sprites->_anims[i].unk2)
704 curAnimState->flags = 0x800;
705 else
706 curAnimState->flags = 0;
707
708 if (_sprites->_anims[i].flipX)
709 curAnimState->flags |= 0x1;
710
711 _animator->addObjectToQueue(curAnimState);
712 }
713
714 for (int i = 0; i < 12; ++i) {
715 curAnimState = &_animator->items()[i];
716 Room *curRoom = &_roomTable[_currentCharacter->sceneId];
717 byte curItem = curRoom->itemsTable[i];
718 if (curItem != 0xFF) {
719 curAnimState->drawY = curRoom->itemsYPos[i];
720 curAnimState->sceneAnimPtr = _shapes[216 + curItem];
721 curAnimState->animFrameNumber = (int16)0xFFFF;
722 curAnimState->y1 = curRoom->itemsYPos[i];
723 curAnimState->x1 = curRoom->itemsXPos[i];
724
725 curAnimState->x1 -= (_animator->fetchAnimWidth(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY])) >> 1;
726 curAnimState->y1 -= _animator->fetchAnimHeight(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY]);
727
728 curAnimState->x2 = curAnimState->x1;
729 curAnimState->y2 = curAnimState->y1;
730
731 curAnimState->active = 1;
732 curAnimState->refreshFlag = 1;
733 curAnimState->bkgdChangeFlag = 1;
734
735 _animator->addObjectToQueue(curAnimState);
736 } else {
737 curAnimState->active = 0;
738 curAnimState->refreshFlag = 0;
739 curAnimState->bkgdChangeFlag = 0;
740 }
741 }
742
743 _animator->preserveAnyChangedBackgrounds();
744 curAnimState = _animator->actors();
745 curAnimState->bkgdChangeFlag = 1;
746 curAnimState->refreshFlag = 1;
747 for (int i = 1; i < 28; ++i) {
748 curAnimState = &_animator->objects()[i];
749 if (curAnimState->active) {
750 curAnimState->bkgdChangeFlag = 1;
751 curAnimState->refreshFlag = 1;
752 }
753 }
754 _animator->restoreAllObjectBackgrounds();
755 _animator->preserveAnyChangedBackgrounds();
756 _animator->prepDrawAllObjects();
757 initSceneScreen(brandonAlive);
758 _animator->copyChangedObjectsForward(0);
759 }
760
initSceneScreen(int brandonAlive)761 void KyraEngine_LoK::initSceneScreen(int brandonAlive) {
762 if (_flags.platform == Common::kPlatformAmiga) {
763 if (_unkScreenVar1 && !queryGameFlag(0xF0)) {
764 _screen->getPalette(2).clear();
765 if (_currentCharacter->sceneId != 117 || !queryGameFlag(0xB3))
766 _screen->setScreenPalette(_screen->getPalette(2));
767 }
768
769 if (_unkScreenVar2 == 1)
770 _screen->shuffleScreen(8, 8, 304, 128, 2, 0, _unkScreenVar3, false);
771 else
772 _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0, Screen::CR_NO_P_CHECK);
773
774 if (_unkScreenVar1 && !queryGameFlag(0xA0)) {
775 if (_currentCharacter->sceneId == 45 && _cauldronState)
776 _screen->getPalette(0).copy(_screen->getPalette(4), 12, 1);
777
778 if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245 && (_brandonStatusBit & 1))
779 _screen->copyPalette(0, 10);
780
781 _screen->setScreenPalette(_screen->getPalette(0));
782 }
783 } else {
784 if (_unkScreenVar1 && !queryGameFlag(0xA0)) {
785 for (int i = 0; i < 60; ++i) {
786 uint16 col = _screen->getPalette(0)[684 + i];
787 col += _screen->getPalette(1)[684 + i] << 1;
788 col >>= 2;
789 _screen->getPalette(0)[684 + i] = col;
790 }
791 _screen->setScreenPalette(_screen->getPalette(0));
792 }
793
794 if (_unkScreenVar2 == 1)
795 _screen->shuffleScreen(8, 8, 304, 128, 2, 0, _unkScreenVar3, false);
796 else
797 _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0);
798
799 if (_unkScreenVar1 && _paletteChanged) {
800 if (!queryGameFlag(0xA0)) {
801 _screen->getPalette(0).copy(_screen->getPalette(1), 228, 20);
802 _screen->setScreenPalette(_screen->getPalette(0));
803 } else {
804 _screen->getPalette(0).clear();
805 }
806 }
807 }
808
809 // WORKAROUND for bug #12635 ("KYRA: Missing subtitle(also in original game)")
810 // This is a script bug that seems to be present in early English talkie versions, but
811 // not in later versions (e. g. German talkie). Unfortunately it seems to have made its
812 // way into several fan translations (e.g. Hebrew, Spanish), since these were based on
813 // the bugged English version. The opcodes have to be rearranged a bit...
814 if (_flags.isTalkie && !scumm_strnicmp("POTION.EMC", _scriptClick.dataPtr->filename, 12)) {
815 assert(_scriptClick.dataPtr->dataSize >= 0x99E);
816 uint16 *loc = &_scriptClick.dataPtr->data[0x4CA];
817 if (*loc == 0x4e35) {
818 for (int i = 0; i < 4; ++i)
819 SWAP(loc[i], loc[i + 1]);
820 }
821 }
822
823 if (!_emc->start(&_scriptClick, 2))
824 error("Could not start script function 2 of scene script");
825
826 _scriptClick.regs[7] = brandonAlive;
827
828 while (_emc->isValid(&_scriptClick))
829 _emc->run(&_scriptClick);
830
831 setTextFadeTimerCountdown(-1);
832
833 if (_currentCharacter->sceneId == 210) {
834 if (_itemInHand != kItemNone)
835 magicOutMouseItem(2, -1);
836
837 _screen->hideMouse();
838 for (int i = 0; i < 10; ++i) {
839 if (_currentCharacter->inventoryItems[i] != kItemNone)
840 magicOutMouseItem(2, i);
841 }
842 _screen->showMouse();
843 }
844 }
845
handleSceneChange(int xpos,int ypos,int unk1,int frameReset)846 int KyraEngine_LoK::handleSceneChange(int xpos, int ypos, int unk1, int frameReset) {
847 if (queryGameFlag(0xEF))
848 unk1 = 0;
849
850 int sceneId = _currentCharacter->sceneId;
851 _pathfinderFlag = 0;
852
853 if (xpos < 12) {
854 if (_roomTable[sceneId].westExit != 0xFFFF) {
855 xpos = 12;
856 ypos = _sceneExits.westYPos;
857 _pathfinderFlag = 7;
858 }
859 } else if (xpos >= 308) {
860 if (_roomTable[sceneId].eastExit != 0xFFFF) {
861 xpos = 307;
862 ypos = _sceneExits.eastYPos;
863 _pathfinderFlag = 13;
864 }
865 }
866
867 if (ypos <= (_northExitHeight & 0xFF) + 2) {
868 if (_roomTable[sceneId].northExit != 0xFFFF) {
869 xpos = _sceneExits.northXPos;
870 ypos = _northExitHeight & 0xFF;
871 _pathfinderFlag = 14;
872 }
873 } else if (ypos >= 136) {
874 if (_roomTable[sceneId].southExit != 0xFFFF) {
875 xpos = _sceneExits.southXPos;
876 ypos = 136;
877 _pathfinderFlag = 11;
878 }
879 }
880
881 int temp = xpos - _currentCharacter->x1;
882 if (ABS(temp) < 4) {
883 temp = ypos - _currentCharacter->y1;
884 if (ABS(temp) < 2)
885 return 0;
886 }
887
888 int x = (int16)(_currentCharacter->x1 & 0xFFFC);
889 int y = (int16)(_currentCharacter->y1 & 0xFFFE);
890 xpos = (int16)(xpos & 0xFFFC);
891 ypos = (int16)(ypos & 0xFFFE);
892
893 int ret = findWay(x, y, xpos, ypos, _movFacingTable, 150);
894 _pathfinderFlag = 0;
895
896 if (ret >= _lastFindWayRet)
897 _lastFindWayRet = ret;
898
899 if (ret == 0x7D00 || ret == 0)
900 return 0;
901
902 return processSceneChange(_movFacingTable, unk1, frameReset);
903 }
904
processSceneChange(int * table,int unk1,int frameReset)905 int KyraEngine_LoK::processSceneChange(int *table, int unk1, int frameReset) {
906 if (queryGameFlag(0xEF))
907 unk1 = 0;
908
909 int *tableStart = table;
910 _sceneChangeState = 0;
911 _loopFlag2 = 0;
912 bool running = true;
913 int returnValue = 0;
914 uint32 nextFrame = 0;
915
916 while (running) {
917 bool forceContinue = false;
918 switch (*table) {
919 case 0: case 1: case 2:
920 case 3: case 4: case 5:
921 case 6: case 7:
922 _currentCharacter->facing = getOppositeFacingDirection(*table);
923 break;
924
925 case 8:
926 forceContinue = true;
927 running = false;
928 break;
929
930 default:
931 ++table;
932 forceContinue = true;
933 }
934
935 returnValue = changeScene(_currentCharacter->facing);
936 if (returnValue)
937 running = false;
938
939 if (unk1) {
940 if (skipFlag()) {
941 resetSkipFlag(false);
942 running = false;
943 _sceneChangeState = 1;
944 }
945 }
946
947 if (forceContinue || !running)
948 continue;
949
950 int temp = 0;
951 if (table == tableStart || table[1] == 8)
952 temp = setCharacterPosition(0, 0);
953 else
954 temp = setCharacterPosition(0, table);
955
956 if (temp)
957 ++table;
958
959 nextFrame = _timer->getDelay(5) * _tickLength + _system->getMillis();
960 while (_system->getMillis() < nextFrame) {
961 _timer->update();
962
963 if (_currentCharacter->sceneId == 210) {
964 updateKyragemFading();
965 if (seq_playEnd() || _beadStateVar == 4 || _beadStateVar == 5) {
966 *table = 8;
967 running = false;
968 break;
969 }
970 }
971
972 if ((nextFrame - _system->getMillis()) >= 10)
973 delay(10, true);
974 }
975 }
976
977 if (frameReset && !(_brandonStatusBit & 2))
978 _currentCharacter->currentAnimFrame = 7;
979
980 _animator->animRefreshNPC(0);
981 _animator->updateAllObjectShapes();
982 return returnValue;
983 }
984
changeScene(int facing)985 int KyraEngine_LoK::changeScene(int facing) {
986 if (queryGameFlag(0xEF)) {
987 if (_currentCharacter->sceneId == 5)
988 return 0;
989 }
990
991 int xpos = _charAddXPosTable[facing] + _currentCharacter->x1;
992 int ypos = _charAddYPosTable[facing] + _currentCharacter->y1;
993
994 if (xpos >= 12 && xpos <= 308) {
995 if (!lineIsPassable(xpos, ypos))
996 return false;
997 }
998
999 if (_exitListPtr) {
1000 int16 *ptr = _exitListPtr;
1001 // this loop should be only entered one time, seems to be some hack in the original
1002 while (true) {
1003 if (*ptr == -1)
1004 break;
1005
1006 if (*ptr > _currentCharacter->x1 || _currentCharacter->y1 < ptr[1] || _currentCharacter->x1 > ptr[2] || _currentCharacter->y1 > ptr[3]) {
1007 ptr += 10;
1008 break;
1009 }
1010
1011 _brandonPosX = ptr[6];
1012 _brandonPosY = ptr[7];
1013 uint16 sceneId = ptr[5];
1014 facing = ptr[4];
1015 int unk1 = ptr[8];
1016 int unk2 = ptr[9];
1017
1018 if (sceneId == 0xFFFF) {
1019 switch (facing) {
1020 case 0:
1021 sceneId = _roomTable[_currentCharacter->sceneId].northExit;
1022 break;
1023
1024 case 2:
1025 sceneId = _roomTable[_currentCharacter->sceneId].eastExit;
1026 break;
1027
1028 case 4:
1029 sceneId = _roomTable[_currentCharacter->sceneId].southExit;
1030 break;
1031
1032 case 6:
1033 sceneId = _roomTable[_currentCharacter->sceneId].westExit;
1034 break;
1035
1036 default:
1037 break;
1038 }
1039 }
1040
1041 _currentCharacter->facing = facing;
1042 _animator->animRefreshNPC(0);
1043 _animator->updateAllObjectShapes();
1044 enterNewScene(sceneId, facing, unk1, unk2, 0);
1045 resetGameFlag(0xEE);
1046 return 1;
1047 }
1048 }
1049
1050 int returnValue = 0;
1051 facing = 0;
1052
1053 if ((_northExitHeight & 0xFF) + 2 >= ypos || (_northExitHeight & 0xFF) + 2 >= _currentCharacter->y1) {
1054 facing = 0;
1055 returnValue = 1;
1056 }
1057
1058 if (xpos >= 308 || (_currentCharacter->x1 + 4) >= 308) {
1059 facing = 2;
1060 returnValue = 1;
1061 }
1062
1063 if (((_northExitHeight >> 8) & 0xFF) - 2 < ypos || ((_northExitHeight >> 8) & 0xFF) - 2 < _currentCharacter->y1) {
1064 facing = 4;
1065 returnValue = 1;
1066 }
1067
1068 if (xpos <= 12 || _currentCharacter->y1 <= 12) {
1069 facing = 6;
1070 returnValue = 1;
1071 }
1072
1073 if (!returnValue)
1074 return 0;
1075
1076 uint16 sceneId = 0xFFFF;
1077 switch (facing) {
1078 case 0:
1079 sceneId = _roomTable[_currentCharacter->sceneId].northExit;
1080 break;
1081
1082 case 2:
1083 sceneId = _roomTable[_currentCharacter->sceneId].eastExit;
1084 break;
1085
1086 case 4:
1087 sceneId = _roomTable[_currentCharacter->sceneId].southExit;
1088 break;
1089
1090 default:
1091 sceneId = _roomTable[_currentCharacter->sceneId].westExit;
1092 }
1093
1094 if (sceneId == 0xFFFF)
1095 return 0;
1096
1097 enterNewScene(sceneId, facing, 1, 1, 0);
1098 return returnValue;
1099 }
1100
setCharactersInDefaultScene()1101 void KyraEngine_LoK::setCharactersInDefaultScene() {
1102 static const uint32 defaultSceneTable[][4] = {
1103 { 0xFFFF, 0x0004, 0x0003, 0xFFFF },
1104 { 0xFFFF, 0x0022, 0xFFFF, 0x0000 },
1105 { 0xFFFF, 0x001D, 0x0021, 0xFFFF },
1106 { 0xFFFF, 0x0000, 0x0000, 0xFFFF }
1107 };
1108
1109 for (int i = 1; i < 5; ++i) {
1110 Character *cur = &_characterList[i];
1111 //cur->field_20 = 0;
1112
1113 const uint32 *curTable = defaultSceneTable[i - 1];
1114 cur->sceneId = curTable[0];
1115
1116 if (cur->sceneId == _currentCharacter->sceneId)
1117 //++cur->field_20;
1118 cur->sceneId = curTable[1/*cur->field_20*/];
1119
1120 //cur->field_23 = curTable[cur->field_20+1];
1121 }
1122 }
1123
setCharactersPositions(int character)1124 void KyraEngine_LoK::setCharactersPositions(int character) {
1125 static const uint16 initXPosTable[] = {
1126 0x3200, 0x0024, 0x2230, 0x2F00, 0x0020, 0x002B,
1127 0x00CA, 0x00F0, 0x0082, 0x00A2, 0x0042
1128 };
1129 static const uint8 initYPosTable[] = {
1130 0x00, 0xA2, 0x00, 0x42, 0x00,
1131 0x67, 0x67, 0x60, 0x5A, 0x71,
1132 0x76
1133 };
1134
1135 assert(character < ARRAYSIZE(initXPosTable));
1136 Character *edit = &_characterList[character];
1137 edit->x1 = edit->x2 = initXPosTable[character];
1138 edit->y1 = edit->y2 = initYPosTable[character];
1139 }
1140
1141 #pragma mark -
1142 #pragma mark - Pathfinder
1143 #pragma mark -
1144
findWay(int x,int y,int toX,int toY,int * moveTable,int moveTableSize)1145 int KyraEngine_LoK::findWay(int x, int y, int toX, int toY, int *moveTable, int moveTableSize) {
1146 int ret = KyraEngine_v1::findWay(x, y, toX, toY, moveTable, moveTableSize);
1147 if (ret == 0x7D00)
1148 return 0;
1149 return getMoveTableSize(moveTable);
1150 }
1151
lineIsPassable(int x,int y)1152 bool KyraEngine_LoK::lineIsPassable(int x, int y) {
1153 if (queryGameFlag(0xEF)) {
1154 if (_currentCharacter->sceneId == 5)
1155 return true;
1156 }
1157
1158 if (_pathfinderFlag & 2) {
1159 if (x >= 312)
1160 return false;
1161 }
1162
1163 if (_pathfinderFlag & 4) {
1164 if (y >= 136)
1165 return false;
1166 }
1167
1168 if (_pathfinderFlag & 8) {
1169 if (x < 8)
1170 return false;
1171 }
1172
1173 if (_pathfinderFlag2) {
1174 if (x <= 8 || x >= 312)
1175 return true;
1176 if (y < (_northExitHeight & 0xFF) || y > 135)
1177 return true;
1178 }
1179
1180 if (y > 137)
1181 return false;
1182
1183 if (y < 0)
1184 y = 0;
1185
1186 int ypos = 8;
1187 if (_scaleMode) {
1188 ypos = (_scaleTable[y] >> 5) + 1;
1189 if (8 < ypos)
1190 ypos = 8;
1191 }
1192
1193 x -= (ypos >> 1);
1194
1195 int xpos = x;
1196 int xtemp = xpos + ypos - 1;
1197 if (x < 0)
1198 xpos = 0;
1199
1200 if (xtemp > 319)
1201 xtemp = 319;
1202
1203 for (; xpos < xtemp; ++xpos) {
1204 if (!_screen->getShapeFlag1(xpos, y))
1205 return false;
1206 }
1207 return true;
1208 }
1209
1210 #pragma mark -
1211
setupZanthiaPalette(int pal)1212 void KyraEngine_LoK::setupZanthiaPalette(int pal) {
1213 uint8 r, g, b;
1214
1215 switch (pal - 17) {
1216 case 0:
1217 // 0x88F
1218 r = 33;
1219 g = 33;
1220 b = 63;
1221 break;
1222
1223 case 1:
1224 // 0x00F
1225 r = 0;
1226 g = 0;
1227 b = 63;
1228 break;
1229
1230 case 2:
1231 // 0xF88
1232 r = 63;
1233 g = 33;
1234 b = 33;
1235 break;
1236
1237 case 3:
1238 // 0xF00
1239 r = 63;
1240 g = 0;
1241 b = 0;
1242 break;
1243
1244 case 4:
1245 // 0xFF9
1246 r = 63;
1247 g = 63;
1248 b = 37;
1249 break;
1250
1251 case 5:
1252 // 0xFF1
1253 r = 63;
1254 g = 63;
1255 b = 4;
1256 break;
1257
1258 default:
1259 // 0xFFF
1260 r = 63;
1261 g = 63;
1262 b = 63;
1263 }
1264
1265 _screen->getPalette(4)[12 * 3 + 0] = r;
1266 _screen->getPalette(4)[12 * 3 + 1] = g;
1267 _screen->getPalette(4)[12 * 3 + 2] = b;
1268 }
1269
1270 #pragma mark -
1271
setupSceneResource(int sceneId)1272 void KyraEngine_LoK::setupSceneResource(int sceneId) {
1273 if (!_flags.isTalkie)
1274 return;
1275
1276 if (_currentRoom != 0xFFFF) {
1277 assert(_currentRoom < _roomTableSize);
1278 int tableId = _roomTable[_currentRoom].nameIndex;
1279 assert(tableId < _roomFilenameTableSize);
1280
1281 // unload our old room
1282 char file[64];
1283 strcpy(file, _roomFilenameTable[tableId]);
1284 strcat(file, ".VRM");
1285 _res->unloadPakFile(file);
1286
1287 strcpy(file, _roomFilenameTable[tableId]);
1288 strcat(file, ".PAK");
1289 _res->unloadPakFile(file);
1290
1291 strcpy(file, _roomFilenameTable[tableId]);
1292 strcat(file, ".APK");
1293 _res->unloadPakFile(file);
1294 }
1295
1296 assert(sceneId < _roomTableSize);
1297 int tableId = _roomTable[sceneId].nameIndex;
1298 assert(tableId < _roomFilenameTableSize);
1299
1300 // load our new room
1301 char file[64];
1302 strcpy(file, _roomFilenameTable[tableId]);
1303 strcat(file, ".VRM");
1304 if (_res->exists(file))
1305 _res->loadPakFile(file);
1306
1307 strcpy(file, _roomFilenameTable[tableId]);
1308 strcat(file, ".PAK");
1309 if (_res->exists(file))
1310 _res->loadPakFile(file);
1311
1312 strcpy(file, _roomFilenameTable[tableId]);
1313 strcat(file, ".APK");
1314 if (_res->exists(file))
1315 _res->loadPakFile(file);
1316 }
1317
1318 } // End of namespace Kyra
1319