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 if (!_emc->start(&_scriptClick, 2))
810 error("Could not start script function 2 of scene script");
811
812 _scriptClick.regs[7] = brandonAlive;
813
814 while (_emc->isValid(&_scriptClick))
815 _emc->run(&_scriptClick);
816
817 setTextFadeTimerCountdown(-1);
818
819 if (_currentCharacter->sceneId == 210) {
820 if (_itemInHand != kItemNone)
821 magicOutMouseItem(2, -1);
822
823 _screen->hideMouse();
824 for (int i = 0; i < 10; ++i) {
825 if (_currentCharacter->inventoryItems[i] != kItemNone)
826 magicOutMouseItem(2, i);
827 }
828 _screen->showMouse();
829 }
830 }
831
handleSceneChange(int xpos,int ypos,int unk1,int frameReset)832 int KyraEngine_LoK::handleSceneChange(int xpos, int ypos, int unk1, int frameReset) {
833 if (queryGameFlag(0xEF))
834 unk1 = 0;
835
836 int sceneId = _currentCharacter->sceneId;
837 _pathfinderFlag = 0;
838
839 if (xpos < 12) {
840 if (_roomTable[sceneId].westExit != 0xFFFF) {
841 xpos = 12;
842 ypos = _sceneExits.westYPos;
843 _pathfinderFlag = 7;
844 }
845 } else if (xpos >= 308) {
846 if (_roomTable[sceneId].eastExit != 0xFFFF) {
847 xpos = 307;
848 ypos = _sceneExits.eastYPos;
849 _pathfinderFlag = 13;
850 }
851 }
852
853 if (ypos <= (_northExitHeight & 0xFF) + 2) {
854 if (_roomTable[sceneId].northExit != 0xFFFF) {
855 xpos = _sceneExits.northXPos;
856 ypos = _northExitHeight & 0xFF;
857 _pathfinderFlag = 14;
858 }
859 } else if (ypos >= 136) {
860 if (_roomTable[sceneId].southExit != 0xFFFF) {
861 xpos = _sceneExits.southXPos;
862 ypos = 136;
863 _pathfinderFlag = 11;
864 }
865 }
866
867 int temp = xpos - _currentCharacter->x1;
868 if (ABS(temp) < 4) {
869 temp = ypos - _currentCharacter->y1;
870 if (ABS(temp) < 2)
871 return 0;
872 }
873
874 int x = (int16)(_currentCharacter->x1 & 0xFFFC);
875 int y = (int16)(_currentCharacter->y1 & 0xFFFE);
876 xpos = (int16)(xpos & 0xFFFC);
877 ypos = (int16)(ypos & 0xFFFE);
878
879 int ret = findWay(x, y, xpos, ypos, _movFacingTable, 150);
880 _pathfinderFlag = 0;
881
882 if (ret >= _lastFindWayRet)
883 _lastFindWayRet = ret;
884
885 if (ret == 0x7D00 || ret == 0)
886 return 0;
887
888 return processSceneChange(_movFacingTable, unk1, frameReset);
889 }
890
processSceneChange(int * table,int unk1,int frameReset)891 int KyraEngine_LoK::processSceneChange(int *table, int unk1, int frameReset) {
892 if (queryGameFlag(0xEF))
893 unk1 = 0;
894
895 int *tableStart = table;
896 _sceneChangeState = 0;
897 _loopFlag2 = 0;
898 bool running = true;
899 int returnValue = 0;
900 uint32 nextFrame = 0;
901
902 while (running) {
903 bool forceContinue = false;
904 switch (*table) {
905 case 0: case 1: case 2:
906 case 3: case 4: case 5:
907 case 6: case 7:
908 _currentCharacter->facing = getOppositeFacingDirection(*table);
909 break;
910
911 case 8:
912 forceContinue = true;
913 running = false;
914 break;
915
916 default:
917 ++table;
918 forceContinue = true;
919 }
920
921 returnValue = changeScene(_currentCharacter->facing);
922 if (returnValue)
923 running = false;
924
925 if (unk1) {
926 if (skipFlag()) {
927 resetSkipFlag(false);
928 running = false;
929 _sceneChangeState = 1;
930 }
931 }
932
933 if (forceContinue || !running)
934 continue;
935
936 int temp = 0;
937 if (table == tableStart || table[1] == 8)
938 temp = setCharacterPosition(0, 0);
939 else
940 temp = setCharacterPosition(0, table);
941
942 if (temp)
943 ++table;
944
945 nextFrame = _timer->getDelay(5) * _tickLength + _system->getMillis();
946 while (_system->getMillis() < nextFrame) {
947 _timer->update();
948
949 if (_currentCharacter->sceneId == 210) {
950 updateKyragemFading();
951 if (seq_playEnd() || _beadStateVar == 4 || _beadStateVar == 5) {
952 *table = 8;
953 running = false;
954 break;
955 }
956 }
957
958 if ((nextFrame - _system->getMillis()) >= 10)
959 delay(10, true);
960 }
961 }
962
963 if (frameReset && !(_brandonStatusBit & 2))
964 _currentCharacter->currentAnimFrame = 7;
965
966 _animator->animRefreshNPC(0);
967 _animator->updateAllObjectShapes();
968 return returnValue;
969 }
970
changeScene(int facing)971 int KyraEngine_LoK::changeScene(int facing) {
972 if (queryGameFlag(0xEF)) {
973 if (_currentCharacter->sceneId == 5)
974 return 0;
975 }
976
977 int xpos = _charAddXPosTable[facing] + _currentCharacter->x1;
978 int ypos = _charAddYPosTable[facing] + _currentCharacter->y1;
979
980 if (xpos >= 12 && xpos <= 308) {
981 if (!lineIsPassable(xpos, ypos))
982 return false;
983 }
984
985 if (_exitListPtr) {
986 int16 *ptr = _exitListPtr;
987 // this loop should be only entered one time, seems to be some hack in the original
988 while (true) {
989 if (*ptr == -1)
990 break;
991
992 if (*ptr > _currentCharacter->x1 || _currentCharacter->y1 < ptr[1] || _currentCharacter->x1 > ptr[2] || _currentCharacter->y1 > ptr[3]) {
993 ptr += 10;
994 break;
995 }
996
997 _brandonPosX = ptr[6];
998 _brandonPosY = ptr[7];
999 uint16 sceneId = ptr[5];
1000 facing = ptr[4];
1001 int unk1 = ptr[8];
1002 int unk2 = ptr[9];
1003
1004 if (sceneId == 0xFFFF) {
1005 switch (facing) {
1006 case 0:
1007 sceneId = _roomTable[_currentCharacter->sceneId].northExit;
1008 break;
1009
1010 case 2:
1011 sceneId = _roomTable[_currentCharacter->sceneId].eastExit;
1012 break;
1013
1014 case 4:
1015 sceneId = _roomTable[_currentCharacter->sceneId].southExit;
1016 break;
1017
1018 case 6:
1019 sceneId = _roomTable[_currentCharacter->sceneId].westExit;
1020 break;
1021
1022 default:
1023 break;
1024 }
1025 }
1026
1027 _currentCharacter->facing = facing;
1028 _animator->animRefreshNPC(0);
1029 _animator->updateAllObjectShapes();
1030 enterNewScene(sceneId, facing, unk1, unk2, 0);
1031 resetGameFlag(0xEE);
1032 return 1;
1033 }
1034 }
1035
1036 int returnValue = 0;
1037 facing = 0;
1038
1039 if ((_northExitHeight & 0xFF) + 2 >= ypos || (_northExitHeight & 0xFF) + 2 >= _currentCharacter->y1) {
1040 facing = 0;
1041 returnValue = 1;
1042 }
1043
1044 if (xpos >= 308 || (_currentCharacter->x1 + 4) >= 308) {
1045 facing = 2;
1046 returnValue = 1;
1047 }
1048
1049 if (((_northExitHeight >> 8) & 0xFF) - 2 < ypos || ((_northExitHeight >> 8) & 0xFF) - 2 < _currentCharacter->y1) {
1050 facing = 4;
1051 returnValue = 1;
1052 }
1053
1054 if (xpos <= 12 || _currentCharacter->y1 <= 12) {
1055 facing = 6;
1056 returnValue = 1;
1057 }
1058
1059 if (!returnValue)
1060 return 0;
1061
1062 uint16 sceneId = 0xFFFF;
1063 switch (facing) {
1064 case 0:
1065 sceneId = _roomTable[_currentCharacter->sceneId].northExit;
1066 break;
1067
1068 case 2:
1069 sceneId = _roomTable[_currentCharacter->sceneId].eastExit;
1070 break;
1071
1072 case 4:
1073 sceneId = _roomTable[_currentCharacter->sceneId].southExit;
1074 break;
1075
1076 default:
1077 sceneId = _roomTable[_currentCharacter->sceneId].westExit;
1078 }
1079
1080 if (sceneId == 0xFFFF)
1081 return 0;
1082
1083 enterNewScene(sceneId, facing, 1, 1, 0);
1084 return returnValue;
1085 }
1086
setCharactersInDefaultScene()1087 void KyraEngine_LoK::setCharactersInDefaultScene() {
1088 static const uint32 defaultSceneTable[][4] = {
1089 { 0xFFFF, 0x0004, 0x0003, 0xFFFF },
1090 { 0xFFFF, 0x0022, 0xFFFF, 0x0000 },
1091 { 0xFFFF, 0x001D, 0x0021, 0xFFFF },
1092 { 0xFFFF, 0x0000, 0x0000, 0xFFFF }
1093 };
1094
1095 for (int i = 1; i < 5; ++i) {
1096 Character *cur = &_characterList[i];
1097 //cur->field_20 = 0;
1098
1099 const uint32 *curTable = defaultSceneTable[i - 1];
1100 cur->sceneId = curTable[0];
1101
1102 if (cur->sceneId == _currentCharacter->sceneId)
1103 //++cur->field_20;
1104 cur->sceneId = curTable[1/*cur->field_20*/];
1105
1106 //cur->field_23 = curTable[cur->field_20+1];
1107 }
1108 }
1109
setCharactersPositions(int character)1110 void KyraEngine_LoK::setCharactersPositions(int character) {
1111 static const uint16 initXPosTable[] = {
1112 0x3200, 0x0024, 0x2230, 0x2F00, 0x0020, 0x002B,
1113 0x00CA, 0x00F0, 0x0082, 0x00A2, 0x0042
1114 };
1115 static const uint8 initYPosTable[] = {
1116 0x00, 0xA2, 0x00, 0x42, 0x00,
1117 0x67, 0x67, 0x60, 0x5A, 0x71,
1118 0x76
1119 };
1120
1121 assert(character < ARRAYSIZE(initXPosTable));
1122 Character *edit = &_characterList[character];
1123 edit->x1 = edit->x2 = initXPosTable[character];
1124 edit->y1 = edit->y2 = initYPosTable[character];
1125 }
1126
1127 #pragma mark -
1128 #pragma mark - Pathfinder
1129 #pragma mark -
1130
findWay(int x,int y,int toX,int toY,int * moveTable,int moveTableSize)1131 int KyraEngine_LoK::findWay(int x, int y, int toX, int toY, int *moveTable, int moveTableSize) {
1132 int ret = KyraEngine_v1::findWay(x, y, toX, toY, moveTable, moveTableSize);
1133 if (ret == 0x7D00)
1134 return 0;
1135 return getMoveTableSize(moveTable);
1136 }
1137
lineIsPassable(int x,int y)1138 bool KyraEngine_LoK::lineIsPassable(int x, int y) {
1139 if (queryGameFlag(0xEF)) {
1140 if (_currentCharacter->sceneId == 5)
1141 return true;
1142 }
1143
1144 if (_pathfinderFlag & 2) {
1145 if (x >= 312)
1146 return false;
1147 }
1148
1149 if (_pathfinderFlag & 4) {
1150 if (y >= 136)
1151 return false;
1152 }
1153
1154 if (_pathfinderFlag & 8) {
1155 if (x < 8)
1156 return false;
1157 }
1158
1159 if (_pathfinderFlag2) {
1160 if (x <= 8 || x >= 312)
1161 return true;
1162 if (y < (_northExitHeight & 0xFF) || y > 135)
1163 return true;
1164 }
1165
1166 if (y > 137)
1167 return false;
1168
1169 if (y < 0)
1170 y = 0;
1171
1172 int ypos = 8;
1173 if (_scaleMode) {
1174 ypos = (_scaleTable[y] >> 5) + 1;
1175 if (8 < ypos)
1176 ypos = 8;
1177 }
1178
1179 x -= (ypos >> 1);
1180
1181 int xpos = x;
1182 int xtemp = xpos + ypos - 1;
1183 if (x < 0)
1184 xpos = 0;
1185
1186 if (xtemp > 319)
1187 xtemp = 319;
1188
1189 for (; xpos < xtemp; ++xpos) {
1190 if (!_screen->getShapeFlag1(xpos, y))
1191 return false;
1192 }
1193 return true;
1194 }
1195
1196 #pragma mark -
1197
setupZanthiaPalette(int pal)1198 void KyraEngine_LoK::setupZanthiaPalette(int pal) {
1199 uint8 r, g, b;
1200
1201 switch (pal - 17) {
1202 case 0:
1203 // 0x88F
1204 r = 33;
1205 g = 33;
1206 b = 63;
1207 break;
1208
1209 case 1:
1210 // 0x00F
1211 r = 0;
1212 g = 0;
1213 b = 63;
1214 break;
1215
1216 case 2:
1217 // 0xF88
1218 r = 63;
1219 g = 33;
1220 b = 33;
1221 break;
1222
1223 case 3:
1224 // 0xF00
1225 r = 63;
1226 g = 0;
1227 b = 0;
1228 break;
1229
1230 case 4:
1231 // 0xFF9
1232 r = 63;
1233 g = 63;
1234 b = 37;
1235 break;
1236
1237 case 5:
1238 // 0xFF1
1239 r = 63;
1240 g = 63;
1241 b = 4;
1242 break;
1243
1244 default:
1245 // 0xFFF
1246 r = 63;
1247 g = 63;
1248 b = 63;
1249 }
1250
1251 _screen->getPalette(4)[12 * 3 + 0] = r;
1252 _screen->getPalette(4)[12 * 3 + 1] = g;
1253 _screen->getPalette(4)[12 * 3 + 2] = b;
1254 }
1255
1256 #pragma mark -
1257
setupSceneResource(int sceneId)1258 void KyraEngine_LoK::setupSceneResource(int sceneId) {
1259 if (!_flags.isTalkie)
1260 return;
1261
1262 if (_currentRoom != 0xFFFF) {
1263 assert(_currentRoom < _roomTableSize);
1264 int tableId = _roomTable[_currentRoom].nameIndex;
1265 assert(tableId < _roomFilenameTableSize);
1266
1267 // unload our old room
1268 char file[64];
1269 strcpy(file, _roomFilenameTable[tableId]);
1270 strcat(file, ".VRM");
1271 _res->unloadPakFile(file);
1272
1273 strcpy(file, _roomFilenameTable[tableId]);
1274 strcat(file, ".PAK");
1275 _res->unloadPakFile(file);
1276
1277 strcpy(file, _roomFilenameTable[tableId]);
1278 strcat(file, ".APK");
1279 _res->unloadPakFile(file);
1280 }
1281
1282 assert(sceneId < _roomTableSize);
1283 int tableId = _roomTable[sceneId].nameIndex;
1284 assert(tableId < _roomFilenameTableSize);
1285
1286 // load our new room
1287 char file[64];
1288 strcpy(file, _roomFilenameTable[tableId]);
1289 strcat(file, ".VRM");
1290 if (_res->exists(file))
1291 _res->loadPakFile(file);
1292
1293 strcpy(file, _roomFilenameTable[tableId]);
1294 strcat(file, ".PAK");
1295 if (_res->exists(file))
1296 _res->loadPakFile(file);
1297
1298 strcpy(file, _roomFilenameTable[tableId]);
1299 strcat(file, ".APK");
1300 if (_res->exists(file))
1301 _res->loadPakFile(file);
1302 }
1303
1304 } // End of namespace Kyra
1305