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 #ifdef ENABLE_LOL
24
25 #include "kyra/engine/lol.h"
26 #include "kyra/graphics/screen_lol.h"
27 #include "kyra/resource/resource.h"
28 #include "kyra/engine/timer.h"
29
30 #include "common/endian.h"
31 #include "common/system.h"
32
33 namespace Kyra {
34
loadLevel(int index)35 void LoLEngine::loadLevel(int index) {
36 _flagsTable[73] |= 0x08;
37 setMouseCursorToIcon(0x85);
38 _nextScriptFunc = 0;
39
40 snd_stopMusic();
41
42 stopPortraitSpeechAnim();
43
44 for (int i = 0; i < 400; i++) {
45 delete[] _levelDecorationShapes[i];
46 _levelDecorationShapes[i] = 0;
47 }
48 _emc->unload(&_scriptData);
49
50 resetItems(1);
51 disableMonsters();
52 resetBlockProperties();
53
54 releaseMonsterShapes(0);
55 releaseMonsterShapes(1);
56
57 for (int i = 0x50; i < 0x53; i++)
58 _timer->disable(i);
59
60 _currentLevel = index;
61 _updateFlags = 0;
62
63 setDefaultButtonState();
64
65 loadTalkFile(index);
66
67 loadLevelWallData(index, true);
68 _loadLevelFlag = 1;
69
70 Common::String filename = Common::String::format("LEVEL%d.INI", index);
71
72 int f = _hasTempDataFlags & (1 << (index - 1));
73
74 runInitScript(filename.c_str(), f ? 0 : 1);
75
76 if (f)
77 restoreBlockTempData(index);
78
79 filename = Common::String::format("LEVEL%d.INF", index);
80 runInfScript(filename.c_str());
81
82 addLevelItems();
83 deleteMonstersFromBlock(_currentBlock);
84
85 if (!_flags.use16ColorMode)
86 _screen->generateGrayOverlay(_screen->getPalette(0), _screen->_grayOverlay, 32, 16, 0, 0, 128, true);
87
88 _sceneDefaultUpdate = 0;
89 if (_screen->_fadeFlag == 3)
90 _screen->fadeToBlack(10);
91
92 gui_drawPlayField();
93
94 setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect);
95 setMouseCursorToItemInHand();
96
97 if (_flags.use16ColorMode)
98 _screen->fadeToPalette1(10);
99
100 snd_playTrack(_curMusicTheme);
101 }
102
addLevelItems()103 void LoLEngine::addLevelItems() {
104 for (int i = 0; i < 400; i++) {
105 if (_itemsInPlay[i].level != _currentLevel)
106 continue;
107
108 assignBlockItem(&_levelBlockProperties[_itemsInPlay[i].block], i);
109
110 _levelBlockProperties[_itemsInPlay[i].block].direction = 5;
111 _itemsInPlay[i].nextDrawObject = 0;
112 }
113 }
114
assignBlockItem(LevelBlockProperty * l,uint16 item)115 void LoLEngine::assignBlockItem(LevelBlockProperty *l, uint16 item) {
116 uint16 *index = &l->assignedObjects;
117 LoLObject *tmp = 0;
118
119 while (*index & 0x8000) {
120 tmp = findObject(*index);
121 index = &tmp->nextAssignedObject;
122 }
123
124 tmp = findObject(item);
125 ((LoLItem *)tmp)->level = -1;
126
127 uint16 ix = *index;
128
129 if (ix == item)
130 return;
131
132 *index = item;
133 index = &tmp->nextAssignedObject;
134
135 while (*index) {
136 tmp = findObject(*index);
137 index = &tmp->nextAssignedObject;
138 }
139
140 *index = ix;
141 }
142
loadLevelWallData(int index,bool mapShapes)143 void LoLEngine::loadLevelWallData(int index, bool mapShapes) {
144 Common::String filename = Common::String::format("LEVEL%d.WLL", index);
145
146 uint32 size;
147 uint8 *file = _res->fileData(filename.c_str(), &size);
148
149 uint16 c = READ_LE_UINT16(file);
150 loadLevelShpDat(_levelShpList[c], _levelDatList[c], false);
151
152 uint8 *d = file + 2;
153 size = (size - 2) / 12;
154 for (uint32 i = 0; i < size; i++) {
155 c = READ_LE_UINT16(d);
156 d += 2;
157 _wllVmpMap[c] = *d;
158 d += 2;
159
160 if (mapShapes) {
161 int16 sh = (int16) READ_LE_UINT16(d);
162 if (sh > 0)
163 _wllShapeMap[c] = assignLevelDecorationShapes(sh);
164 else
165 _wllShapeMap[c] = *d;
166 }
167 d += 2;
168 _specialWallTypes[c] = *d;
169 d += 2;
170 _wllWallFlags[c] = *d;
171 d += 2;
172 _wllAutomapData[c] = *d;
173 d += 2;
174 }
175
176 delete[] file;
177
178 delete _lvlShpFileHandle;
179 _lvlShpFileHandle = 0;
180 }
181
assignLevelDecorationShapes(int index)182 int LoLEngine::assignLevelDecorationShapes(int index) {
183 uint16 *p1 = (uint16 *)_tempBuffer5120;
184 uint16 *p2 = (uint16 *)(_tempBuffer5120 + 4000);
185
186 uint16 r = p2[index];
187 if (r)
188 return r;
189
190 uint16 o = _mappedDecorationsCount++;
191
192 memcpy(&_levelDecorationProperties[o], &_levelDecorationData[index], sizeof(LevelDecorationProperty));
193
194 for (int i = 0; i < 10; i++) {
195 uint16 t = _levelDecorationProperties[o].shapeIndex[i];
196 if (t == 0xFFFF)
197 continue;
198
199 uint16 pv = p1[t];
200 if (pv) {
201 _levelDecorationProperties[o].shapeIndex[i] = pv;
202 } else {
203 releaseDecorations(_lvlShapeIndex, 1);
204 _levelDecorationShapes[_lvlShapeIndex] = getLevelDecorationShapes(t);
205 p1[t] = _lvlShapeIndex;
206 _levelDecorationProperties[o].shapeIndex[i] = _lvlShapeIndex++;
207 }
208 }
209
210 p2[index] = o;
211 if (_levelDecorationProperties[o].next)
212 _levelDecorationProperties[o].next = assignLevelDecorationShapes(_levelDecorationProperties[o].next);
213
214 return o;
215 }
216
getLevelDecorationShapes(int shapeIndex)217 uint8 *LoLEngine::getLevelDecorationShapes(int shapeIndex) {
218 if (_decorationCount <= shapeIndex)
219 return 0;
220
221 _lvlShpFileHandle->seek(shapeIndex * 4 + 2, SEEK_SET);
222 uint32 offs = _lvlShpFileHandle->readUint32LE() + 2;
223 _lvlShpFileHandle->seek(offs, SEEK_SET);
224
225 uint8 tmp[16];
226 _lvlShpFileHandle->read(tmp, 16);
227 uint16 size = _screen->getShapeSize(tmp);
228
229 _lvlShpFileHandle->seek(offs, SEEK_SET);
230 uint8 *res = new uint8[size];
231 _lvlShpFileHandle->read(res, size);
232
233 return res;
234 }
235
releaseDecorations(int first,int num)236 void LoLEngine::releaseDecorations(int first, int num) {
237 for (int i = first; i < (first + num); i++) {
238 delete[] _levelDecorationShapes[i];
239 _levelDecorationShapes[i] = 0;
240 }
241 }
242
loadBlockProperties(const char * cmzFile)243 void LoLEngine::loadBlockProperties(const char *cmzFile) {
244 memset(_levelBlockProperties, 0, 1024 * sizeof(LevelBlockProperty));
245 _screen->loadBitmap(cmzFile, 2, 2, 0);
246 const uint8 *h = _screen->getCPagePtr(2);
247 uint16 len = READ_LE_UINT16(&h[4]);
248 const uint8 *p = h + 6;
249
250 for (int i = 0; i < 1024; i++) {
251 for (int ii = 0; ii < 4; ii++)
252 _levelBlockProperties[i].walls[ii] = p[i * len + ii];
253
254 _levelBlockProperties[i].direction = 5;
255
256 if (_wllAutomapData[_levelBlockProperties[i].walls[0]] == 17) {
257 _levelBlockProperties[i].flags &= 0xEF;
258 _levelBlockProperties[i].flags |= 0x20;
259 }
260 }
261 }
262
getBlockFileData(int levelIndex)263 const uint8 *LoLEngine::getBlockFileData(int levelIndex) {
264 _screen->loadBitmap(Common::String::format("LEVEL%d.CMZ", levelIndex).c_str(), 15, 15, 0);
265 return _screen->getCPagePtr(14);
266 }
267
loadLevelShpDat(const char * shpFile,const char * datFile,bool flag)268 void LoLEngine::loadLevelShpDat(const char *shpFile, const char *datFile, bool flag) {
269 memset(_tempBuffer5120, 0, 5120);
270
271 _lvlShpFileHandle = _res->createReadStream(shpFile);
272 _decorationCount = _lvlShpFileHandle->readUint16LE();
273
274 Common::SeekableReadStream *s = _res->createReadStream(datFile);
275
276 _levelDecorationDataSize = s->readUint16LE();
277 delete[] _levelDecorationData;
278 _levelDecorationData = new LevelDecorationProperty[_levelDecorationDataSize];
279 for (int i = 0; i < _levelDecorationDataSize; i++) {
280 LevelDecorationProperty *l = &_levelDecorationData[i];
281 for (int ii = 0; ii < 10; ii++)
282 l->shapeIndex[ii] = s->readUint16LE();
283 for (int ii = 0; ii < 10; ii++)
284 l->scaleFlag[ii] = s->readByte();
285 for (int ii = 0; ii < 10; ii++)
286 l->shapeX[ii] = s->readSint16LE();
287 for (int ii = 0; ii < 10; ii++)
288 l->shapeY[ii] = s->readSint16LE();
289 l->next = s->readByte();
290 l->flags = s->readByte();
291 }
292
293 delete s;
294
295 if (!flag) {
296 _mappedDecorationsCount = 1;
297 _lvlShapeIndex = 1;
298 }
299 }
300
loadLevelGraphics(const char * file,int specialColor,int weight,int vcnLen,int vmpLen,const char * palFile)301 void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight, int vcnLen, int vmpLen, const char *palFile) {
302 if (file) {
303 _lastSpecialColor = specialColor;
304 _lastSpecialColorWeight = weight;
305 strcpy(_lastBlockDataFile, file);
306 if (palFile)
307 _lastOverridePalFile = palFile;
308 else
309 _lastOverridePalFile.clear();
310 }
311
312 if (_flags.use16ColorMode) {
313 if (_lastSpecialColor == 1)
314 _lastSpecialColor = 0x44;
315 else if (_lastSpecialColor == 0x66)
316 _lastSpecialColor = scumm_stricmp(_lastBlockDataFile, "YVEL2") ? 0xCC : 0x44;
317 else if (_lastSpecialColor == 0x6B)
318 _lastSpecialColor = 0xCC;
319 else
320 _lastSpecialColor = 0x44;
321 }
322
323 Common::String fname;
324 const uint8 *v = 0;
325 int tlen = 0;
326
327 if (_flags.use16ColorMode) {
328 fname = Common::String::format("%s.VCF", _lastBlockDataFile);
329 _screen->loadBitmap(fname.c_str(), 3, 3, 0);
330 v = _screen->getCPagePtr(2);
331 tlen = READ_LE_UINT16(v) << 5;
332 v += 2;
333
334 delete[] _vcfBlocks;
335 _vcfBlocks = new uint8[tlen];
336
337 memcpy(_vcfBlocks, v, tlen);
338 }
339
340 fname = Common::String::format("%s.VCN", _lastBlockDataFile);
341 _screen->loadBitmap(fname.c_str(), 3, 3, 0);
342 v = _screen->getCPagePtr(2);
343 tlen = READ_LE_UINT16(v);
344 v += 2;
345
346 if (vcnLen == -1)
347 vcnLen = tlen << 5;
348
349 delete[] _vcnBlocks;
350 _vcnBlocks = new uint8[vcnLen];
351
352 if (!_flags.use16ColorMode) {
353 delete[] _vcnShift;
354 _vcnShift = new uint8[tlen];
355
356 memcpy(_vcnShift, v, tlen);
357 v += tlen;
358
359 memcpy(_vcnColTable, v, 128);
360 v += 128;
361
362 if (!_lastOverridePalFile.empty()) {
363 _res->loadFileToBuf(_lastOverridePalFile.c_str(), _screen->getPalette(0).getData(), 384);
364 } else {
365 _screen->getPalette(0).copy(v, 0, 128);
366 }
367
368 v += 384;
369 }
370
371 if (_currentLevel == 11) {
372 if (_flags.use16ColorMode) {
373 _screen->loadPalette("LOLICE.NOL", _screen->getPalette(2));
374
375 } else {
376 _screen->loadPalette("SWAMPICE.COL", _screen->getPalette(2));
377 _screen->getPalette(2).copy(_screen->getPalette(0), 128);
378 }
379
380 if (_flagsTable[52] & 0x04) {
381 uint8 *pal0 = _screen->getPalette(0).getData();
382 uint8 *pal2 = _screen->getPalette(2).getData();
383 for (int i = 1; i < _screen->getPalette(0).getNumColors() * 3; i++)
384 SWAP(pal0[i], pal2[i]);
385 }
386 }
387
388 memcpy(_vcnBlocks, v, vcnLen);
389 v += vcnLen;
390
391 fname = Common::String::format("%s.VMP", _lastBlockDataFile);
392 _screen->loadBitmap(fname.c_str(), 3, 3, 0);
393 v = _screen->getCPagePtr(2);
394
395 if (vmpLen == -1)
396 vmpLen = READ_LE_UINT16(v);
397 v += 2;
398
399 delete[] _vmpPtr;
400 _vmpPtr = new uint16[vmpLen];
401
402 for (int i = 0; i < vmpLen; i++)
403 _vmpPtr[i] = READ_LE_UINT16(&v[i << 1]);
404
405 Palette tpal(256);
406 if (_flags.use16ColorMode) {
407 uint8 *dst = tpal.getData();
408 _res->loadFileToBuf("LOL.NOL", dst, 48);
409 for (int i = 1; i < 16; i++) {
410 int s = ((i << 4) | i) * 3;
411 SWAP(dst[s], dst[i * 3]);
412 SWAP(dst[s + 1], dst[i * 3 + 1]);
413 SWAP(dst[s + 2], dst[i * 3 + 2]);
414 }
415 } else {
416 tpal.copy(_screen->getPalette(0));
417 }
418
419 for (int i = 0; i < 7; i++) {
420 weight = 100 - (i * _lastSpecialColorWeight);
421 weight = (weight > 0) ? (weight * 255) / 100 : 0;
422 _screen->generateOverlay(tpal, _screen->getLevelOverlay(i), _lastSpecialColor, weight);
423
424 int l = _flags.use16ColorMode ? 256 : 128;
425 uint8 *levelOverlay = _screen->getLevelOverlay(i);
426 for (int ii = 0; ii < l; ii++) {
427 if (levelOverlay[ii] == 255)
428 levelOverlay[ii] = 0;
429 }
430
431 for (int ii = l; ii < 256; ii++)
432 levelOverlay[ii] = ii & 0xFF;
433 }
434
435 uint8 *levelOverlay = _screen->getLevelOverlay(7);
436 for (int i = 0; i < 256; i++)
437 levelOverlay[i] = i & 0xFF;
438
439 if (_flags.use16ColorMode) {
440 _screen->getLevelOverlay(6)[0xEE] = 0xEE;
441 if (_lastSpecialColor == 0x44)
442 _screen->getLevelOverlay(5)[0xEE] = 0xEE;
443
444 for (int i = 0; i < 7; i++)
445 memcpy(_screen->getLevelOverlay(i), _screen->getLevelOverlay(i + 1), 256);
446
447 _screen->loadPalette("LOL.NOL", _screen->getPalette(0));
448
449 for (int i = 0; i < 8; i++) {
450 uint8 *pl = _screen->getLevelOverlay(7 - i);
451 for (int ii = 0; ii < 16; ii++)
452 _vcnColTable[(i << 4) + ii] = pl[(ii << 4) | ii];
453 }
454 }
455
456 _loadSuppFilesFlag = 0;
457 generateBrightnessPalette(_screen->getPalette(0), _screen->getPalette(1), _brightness, _lampEffect);
458
459 if (_flags.isTalkie) {
460 Common::SeekableReadStream *s = _res->createReadStream(Common::String::format("LEVEL%.02d.TLC", _currentLevel));
461 s->read(_transparencyTable1, 256);
462 s->read(_transparencyTable2, 5120);
463 delete s;
464 } else {
465 createTransparencyTables();
466 }
467
468 _loadSuppFilesFlag = 1;
469 }
470
resetItems(int flag)471 void LoLEngine::resetItems(int flag) {
472 for (int i = 0; i < 1024; i++) {
473 _levelBlockProperties[i].direction = 5;
474 uint16 id = _levelBlockProperties[i].assignedObjects;
475 LoLObject *r = 0;
476
477 while (id & 0x8000) {
478 r = findObject(id);
479 id = r->nextAssignedObject;
480 }
481
482 if (!id)
483 continue;
484
485 LoLItem *it = &_itemsInPlay[id];
486 it->level = _currentLevel;
487 it->block = i;
488 if (r)
489 r->nextAssignedObject = 0;
490 }
491
492 if (flag)
493 memset(_flyingObjects, 0, 8 * sizeof(FlyingObject));
494 }
495
disableMonsters()496 void LoLEngine::disableMonsters() {
497 memset(_monsters, 0, 30 * sizeof(LoLMonster));
498 for (int i = 0; i < 30; i++)
499 _monsters[i].mode = 0x10;
500 }
501
resetBlockProperties()502 void LoLEngine::resetBlockProperties() {
503 for (int i = 0; i < 1024; i++) {
504 LevelBlockProperty *l = &_levelBlockProperties[i];
505 if (l->flags & 0x10) {
506 l->flags &= 0xEF;
507 if (testWallInvisibility(i, 0) && testWallInvisibility(i, 1))
508 l->flags |= 0x40;
509 } else {
510 if (l->flags & 0x40)
511 l->flags &= 0xBF;
512 else if (l->flags & 0x80)
513 l->flags &= 0x7F;
514 }
515 }
516 }
517
testWallFlag(int block,int direction,int flag)518 bool LoLEngine::testWallFlag(int block, int direction, int flag) {
519 if (_levelBlockProperties[block].flags & 0x10)
520 return true;
521
522 if (direction != -1)
523 return (_wllWallFlags[_levelBlockProperties[block].walls[direction ^ 2]] & flag) ? true : false;
524
525 for (int i = 0; i < 4; i++) {
526 if (_wllWallFlags[_levelBlockProperties[block].walls[i]] & flag)
527 return true;
528 }
529
530 return false;
531 }
532
testWallInvisibility(int block,int direction)533 bool LoLEngine::testWallInvisibility(int block, int direction) {
534 uint8 w = _levelBlockProperties[block].walls[direction];
535 if (_wllVmpMap[w] || _wllShapeMap[w] || _levelBlockProperties[block].flags & 0x80)
536 return false;
537 return true;
538 }
539
resetLampStatus()540 void LoLEngine::resetLampStatus() {
541 _flagsTable[31] |= 0x04;
542 _lampEffect = -1;
543 updateLampStatus();
544 }
545
setLampMode(bool lampOn)546 void LoLEngine::setLampMode(bool lampOn) {
547 _flagsTable[31] &= 0xFB;
548 if (!(_flagsTable[31] & 0x08) || !lampOn)
549 return;
550
551 _screen->drawShape(0, _gameShapes[_flags.isTalkie ? 43 : 41], 291, 56, 0, 0);
552 _lampEffect = 8;
553 }
554
updateLampStatus()555 void LoLEngine::updateLampStatus() {
556 int8 newLampEffect = 0;
557 uint8 tmpOilStatus = 0;
558
559 if ((_updateFlags & 4) || !(_flagsTable[31] & 0x08))
560 return;
561
562 if (!_brightness || !_lampOilStatus) {
563 newLampEffect = 8;
564 if (newLampEffect != _lampEffect && _screen->_fadeFlag == 0)
565 setPaletteBrightness(_screen->getPalette(0), _brightness, newLampEffect);
566 } else {
567 tmpOilStatus = (_lampOilStatus < 100) ? _lampOilStatus : 100;
568 newLampEffect = (3 - ((tmpOilStatus - 1) / 25)) << 1;
569
570 if (_lampEffect == -1) {
571 if (_screen->_fadeFlag == 0)
572 setPaletteBrightness(_screen->getPalette(0), _brightness, newLampEffect);
573 _lampStatusTimer = _system->getMillis() + (10 + rollDice(1, 30)) * _tickLength;
574 } else {
575 if ((_lampEffect & 0xFE) == (newLampEffect & 0xFE)) {
576 if (_system->getMillis() <= _lampStatusTimer) {
577 newLampEffect = _lampEffect;
578 } else {
579 newLampEffect = _lampEffect ^ 1;
580 _lampStatusTimer = _system->getMillis() + (10 + rollDice(1, 30)) * _tickLength;
581 }
582 } else {
583 if (_screen->_fadeFlag == 0)
584 setPaletteBrightness(_screen->getPalette(0), _brightness, newLampEffect);
585 }
586 }
587 }
588
589 if (newLampEffect == _lampEffect)
590 return;
591
592 _screen->hideMouse();
593
594 _screen->drawShape(_screen->_curPage, _gameShapes[(_flags.isTalkie ? 35 : 33) + newLampEffect], 291, 56, 0, 0);
595 _screen->showMouse();
596
597 _lampEffect = newLampEffect;
598 }
599
updateCompass()600 void LoLEngine::updateCompass() {
601 if (!(_flagsTable[31] & 0x40) || (_updateFlags & 4))
602 return;
603
604 if (_compassDirection == -1) {
605 _compassStep = 0;
606 gui_drawCompass();
607 return;
608 }
609
610 if (_compassTimer >= _system->getMillis())
611 return;
612
613 if ((_currentDirection << 6) == _compassDirection && (!_compassStep))
614 return;
615
616 _compassTimer = _system->getMillis() + 3 * _tickLength;
617 int dir = _compassStep >= 0 ? 1 : -1;
618 if (_compassStep)
619 _compassStep -= (((ABS(_compassStep) >> 4) + 2) * dir);
620
621 int16 diff = _compassBroken ? (int8(_rnd.getRandomNumber(255)) - _compassDirection) : (_currentDirection << 6) - _compassDirection;
622 if (diff <= -128)
623 diff += 256;
624 if (diff >= 128)
625 diff -= 256;
626
627 diff >>= 2;
628 _compassStep += diff;
629 _compassStep = CLIP(_compassStep, -24, 24);
630 _compassDirection += _compassStep;
631
632 if (_compassDirection < 0)
633 _compassDirection += 256;
634 if (_compassDirection > 255)
635 _compassDirection -= 256;
636
637 if (((((_compassDirection + 3) & 0xFD) >> 6) == _currentDirection) && (_compassStep < 2) && (ABS(diff) < 4)) {
638 _compassDirection = _currentDirection << 6;
639 _compassStep = 0;
640 }
641
642 gui_drawCompass();
643 }
644
moveParty(uint16 direction,int unk1,int unk2,int buttonShape)645 void LoLEngine::moveParty(uint16 direction, int unk1, int unk2, int buttonShape) {
646 if (buttonShape)
647 gui_toggleButtonDisplayMode(buttonShape, 1);
648
649 uint16 opos = _currentBlock;
650 uint16 npos = calcNewBlockPosition(_currentBlock, direction);
651
652 if (!checkBlockPassability(npos, direction)) {
653 notifyBlockNotPassable(unk2 ? 0 : 1);
654 gui_toggleButtonDisplayMode(buttonShape, 0);
655 return;
656 }
657
658 _scriptDirection = direction;
659 _currentBlock = npos;
660 _sceneDefaultUpdate = 1;
661
662 calcCoordinates(_partyPosX, _partyPosY, _currentBlock, 0x80, 0x80);
663 _flagsTable[73] &= 0xFD;
664
665 runLevelScript(opos, 4);
666 runLevelScript(npos, 1);
667
668 if (!(_flagsTable[73] & 0x02)) {
669 initTextFading(2, 0);
670
671 if (_sceneDefaultUpdate) {
672 switch (unk2) {
673 case 0:
674 movePartySmoothScrollUp(2);
675 break;
676 case 1:
677 movePartySmoothScrollDown(2);
678 break;
679 case 2:
680 movePartySmoothScrollLeft(1);
681 break;
682 case 3:
683 movePartySmoothScrollRight(1);
684 break;
685 default:
686 break;
687 }
688 } else {
689 gui_drawScene(0);
690 }
691
692 gui_toggleButtonDisplayMode(buttonShape, 0);
693
694 if (npos == _currentBlock) {
695 runLevelScript(opos, 8);
696 runLevelScript(npos, 2);
697
698 if (_levelBlockProperties[npos].walls[0] == 0x1A)
699 memset(_levelBlockProperties[npos].walls, 0, 4);
700 }
701 }
702
703 updateAutoMap(_currentBlock);
704 }
705
calcBlockIndex(uint16 x,uint16 y)706 uint16 LoLEngine::calcBlockIndex(uint16 x, uint16 y) {
707 return (((y & 0xFF00) >> 3) | (x >> 8)) & 0x3FF;
708 }
709
calcCoordinates(uint16 & x,uint16 & y,int block,uint16 xOffs,uint16 yOffs)710 void LoLEngine::calcCoordinates(uint16 &x, uint16 &y, int block, uint16 xOffs, uint16 yOffs) {
711 x = (block & 0x1F) << 8 | xOffs;
712 y = ((block & 0xFFE0) << 3) | yOffs;
713 }
714
calcCoordinatesForSingleCharacter(int charNum,uint16 & x,uint16 & y)715 void LoLEngine::calcCoordinatesForSingleCharacter(int charNum, uint16 &x, uint16 &y) {
716 static const uint8 xOffsets[] = { 0x80, 0x00, 0x00, 0x40, 0xC0, 0x00, 0x40, 0x80, 0xC0 };
717 int c = countActiveCharacters();
718 if (!c)
719 return;
720
721 c = (c - 1) * 3 + charNum;
722
723 x = xOffsets[c];
724 y = 0x80;
725
726 calcCoordinatesAddDirectionOffset(x, y, _currentDirection);
727
728 x |= (_partyPosX & 0xFF00);
729 y |= (_partyPosY & 0xFF00);
730 }
731
calcCoordinatesAddDirectionOffset(uint16 & x,uint16 & y,int direction)732 void LoLEngine::calcCoordinatesAddDirectionOffset(uint16 &x, uint16 &y, int direction) {
733 if (!direction)
734 return;
735
736 int tx = x;
737 int ty = y;
738
739 if (direction & 1)
740 SWAP(tx, ty);
741
742 if (direction != 1)
743 ty = (ty - 256) * -1;
744
745 if (direction != 3) {
746 tx = (tx - 256) * -1;
747 }
748
749 x = tx;
750 y = ty;
751 }
752
checkBlockPassability(uint16 block,uint16 direction)753 bool LoLEngine::checkBlockPassability(uint16 block, uint16 direction) {
754 if (testWallFlag(block, direction, 1))
755 return false;
756
757 uint16 d = _levelBlockProperties[block].assignedObjects;
758
759 while (d) {
760 if (d & 0x8000)
761 return false;
762 d = findObject(d)->nextAssignedObject;
763 }
764
765 return true;
766 }
767
notifyBlockNotPassable(int scrollFlag)768 void LoLEngine::notifyBlockNotPassable(int scrollFlag) {
769 if (scrollFlag)
770 movePartySmoothScrollBlocked(2);
771
772 snd_stopSpeech(true);
773 _txt->printMessage(0x8002, "%s", getLangString(0x403F));
774 snd_playSoundEffect(19, -1);
775 }
776
clickedDoorSwitch(uint16 block,uint16 direction)777 int LoLEngine::clickedDoorSwitch(uint16 block, uint16 direction) {
778 uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
779 if (!clickedShape(v))
780 return 0;
781
782 snd_playSoundEffect(78, -1);
783 _blockDoor = 0;
784 runLevelScript(block, 0x40);
785
786 if (!_blockDoor) {
787 delay(15 * _tickLength);
788 processDoorSwitch(block, 0);
789 }
790
791 return 1;
792 }
793
clickedNiche(uint16 block,uint16 direction)794 int LoLEngine::clickedNiche(uint16 block, uint16 direction) {
795 uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
796 if (!clickedShape(v) || !_itemInHand)
797 return 0;
798
799 uint16 x = 0x80;
800 uint16 y = 0xFF;
801 calcCoordinatesAddDirectionOffset(x, y, _currentDirection);
802 calcCoordinates(x, y, block, x, y);
803 setItemPosition(_itemInHand, x, y, 8, 1);
804 setHandItem(0);
805 return 1;
806 }
807
movePartySmoothScrollBlocked(int speed)808 void LoLEngine::movePartySmoothScrollBlocked(int speed) {
809 if (!_smoothScrollingEnabled || (_smoothScrollingEnabled && _needSceneRestore))
810 return;
811
812 _screen->backupSceneWindow(_sceneDrawPage2 == 2 ? 2 : 6, 6);
813
814 for (int i = 0; i < 2; i++) {
815 uint32 delayTimer = _system->getMillis() + speed * _tickLength;
816 _screen->smoothScrollZoomStepTop(6, 2, _scrollXTop[i], _scrollYTop[i]);
817 _screen->smoothScrollZoomStepBottom(6, 2, _scrollXBottom[i], _scrollYBottom[i]);
818 _screen->restoreSceneWindow(2, 0);
819 _screen->updateScreen();
820 fadeText();
821 delayUntil(delayTimer);
822 if (!_smoothScrollModeNormal)
823 i++;
824 }
825
826 for (int i = 2; i; i--) {
827 uint32 delayTimer = _system->getMillis() + speed * _tickLength;
828 _screen->smoothScrollZoomStepTop(6, 2, _scrollXTop[i], _scrollYTop[i]);
829 _screen->smoothScrollZoomStepBottom(6, 2, _scrollXBottom[i], _scrollYBottom[i]);
830 _screen->restoreSceneWindow(2, 0);
831 _screen->updateScreen();
832 fadeText();
833 delayUntil(delayTimer);
834 if (!_smoothScrollModeNormal)
835 i++;
836 }
837
838 if (_sceneDefaultUpdate != 2) {
839 _screen->restoreSceneWindow(6, 0);
840 _screen->updateScreen();
841 }
842
843 updateDrawPage2();
844 }
845
movePartySmoothScrollUp(int speed)846 void LoLEngine::movePartySmoothScrollUp(int speed) {
847 if (!_smoothScrollingEnabled || (_smoothScrollingEnabled && _needSceneRestore))
848 return;
849
850 int d = 0;
851
852 if (_sceneDrawPage2 == 2) {
853 d = smoothScrollDrawSpecialGuiShape(6);
854 gui_drawScene(6);
855 _screen->backupSceneWindow(6, 12);
856 _screen->backupSceneWindow(2, 6);
857 } else {
858 d = smoothScrollDrawSpecialGuiShape(2);
859 gui_drawScene(2);
860 _screen->backupSceneWindow(2, 12);
861 _screen->backupSceneWindow(6, 6);
862 }
863
864 for (int i = 0; i < 5; i++) {
865 uint32 delayTimer = _system->getMillis() + speed * _tickLength;
866 _screen->smoothScrollZoomStepTop(6, 2, _scrollXTop[i], _scrollYTop[i]);
867 _screen->smoothScrollZoomStepBottom(6, 2, _scrollXBottom[i], _scrollYBottom[i]);
868
869 if (d)
870 _screen->copyGuiShapeToSurface(14, 2);
871
872 _screen->restoreSceneWindow(2, 0);
873 _screen->updateScreen();
874 fadeText();
875 delayUntil(delayTimer);
876 if (!_smoothScrollModeNormal)
877 i++;
878 }
879
880 if (d)
881 _screen->copyGuiShapeToSurface(14, 12);
882
883 if (_sceneDefaultUpdate != 2) {
884 _screen->restoreSceneWindow(12, 0);
885 _screen->updateScreen();
886 }
887
888 updateDrawPage2();
889 }
890
movePartySmoothScrollDown(int speed)891 void LoLEngine::movePartySmoothScrollDown(int speed) {
892 if (!_smoothScrollingEnabled)
893 return;
894
895 int d = smoothScrollDrawSpecialGuiShape(2);
896 gui_drawScene(2);
897 _screen->backupSceneWindow(2, 6);
898
899 for (int i = 4; i >= 0; i--) {
900 uint32 delayTimer = _system->getMillis() + speed * _tickLength;
901 _screen->smoothScrollZoomStepTop(6, 2, _scrollXTop[i], _scrollYTop[i]);
902 _screen->smoothScrollZoomStepBottom(6, 2, _scrollXBottom[i], _scrollYBottom[i]);
903
904 if (d)
905 _screen->copyGuiShapeToSurface(14, 2);
906
907 _screen->restoreSceneWindow(2, 0);
908 _screen->updateScreen();
909 fadeText();
910 delayUntil(delayTimer);
911 if (!_smoothScrollModeNormal)
912 i++;
913 }
914
915 if (d)
916 _screen->copyGuiShapeToSurface(14, 12);
917
918 if (_sceneDefaultUpdate != 2) {
919 _screen->restoreSceneWindow(6, 0);
920 _screen->updateScreen();
921 }
922
923 updateDrawPage2();
924 }
925
movePartySmoothScrollLeft(int speed)926 void LoLEngine::movePartySmoothScrollLeft(int speed) {
927 if (!_smoothScrollingEnabled)
928 return;
929
930 speed <<= 1;
931
932 gui_drawScene(_sceneDrawPage1);
933
934 for (int i = 88, d = 88; i > 22; i -= 22, d += 22) {
935 uint32 delayTimer = _system->getMillis() + speed * _tickLength;
936 _screen->smoothScrollHorizontalStep(_sceneDrawPage2, 66, d, i);
937 _screen->copyRegion(112 + i, 0, 112, 0, d, 120, _sceneDrawPage1, _sceneDrawPage2, Screen::CR_NO_P_CHECK);
938 _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage2, 0, Screen::CR_NO_P_CHECK);
939 _screen->updateScreen();
940 fadeText();
941 delayUntil(delayTimer);
942 }
943
944 if (_sceneDefaultUpdate != 2) {
945 _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK);
946 _screen->updateScreen();
947 }
948
949 SWAP(_sceneDrawPage1, _sceneDrawPage2);
950 }
951
movePartySmoothScrollRight(int speed)952 void LoLEngine::movePartySmoothScrollRight(int speed) {
953 if (!_smoothScrollingEnabled)
954 return;
955
956 speed <<= 1;
957
958 gui_drawScene(_sceneDrawPage1);
959
960 uint32 delayTimer = _system->getMillis() + speed * _tickLength;
961 _screen->copyRegion(112, 0, 222, 0, 66, 120, _sceneDrawPage1, _sceneDrawPage2, Screen::CR_NO_P_CHECK);
962 _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage2, 0, Screen::CR_NO_P_CHECK);
963 _screen->updateScreen();
964 fadeText();
965 delayUntil(delayTimer);
966
967 delayTimer = _system->getMillis() + speed * _tickLength;
968 _screen->smoothScrollHorizontalStep(_sceneDrawPage2, 22, 0, 66);
969 _screen->copyRegion(112, 0, 200, 0, 88, 120, _sceneDrawPage1, _sceneDrawPage2, Screen::CR_NO_P_CHECK);
970 _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage2, 0, Screen::CR_NO_P_CHECK);
971 _screen->updateScreen();
972 fadeText();
973 delayUntil(delayTimer);
974
975 delayTimer = _system->getMillis() + speed * _tickLength;
976 _screen->smoothScrollHorizontalStep(_sceneDrawPage2, 44, 0, 22);
977 _screen->copyRegion(112, 0, 178, 0, 110, 120, _sceneDrawPage1, _sceneDrawPage2, Screen::CR_NO_P_CHECK);
978 _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage2, 0, Screen::CR_NO_P_CHECK);
979 _screen->updateScreen();
980 fadeText();
981 delayUntil(delayTimer);
982
983 if (_sceneDefaultUpdate != 2) {
984 _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK);
985 _screen->updateScreen();
986 }
987
988 SWAP(_sceneDrawPage1, _sceneDrawPage2);
989 }
990
movePartySmoothScrollTurnLeft(int speed)991 void LoLEngine::movePartySmoothScrollTurnLeft(int speed) {
992 if (!_smoothScrollingEnabled)
993 return;
994
995 speed <<= 1;
996
997 int d = smoothScrollDrawSpecialGuiShape(_sceneDrawPage1);
998 gui_drawScene(_sceneDrawPage1);
999 int dp = _sceneDrawPage2 == 2 ? _sceneDrawPage2 : _sceneDrawPage1;
1000
1001 uint32 delayTimer = _system->getMillis() + speed * _tickLength;
1002 _screen->smoothScrollTurnStep1(_sceneDrawPage1, _sceneDrawPage2, dp);
1003 if (d)
1004 _screen->copyGuiShapeToSurface(14, dp);
1005 _screen->restoreSceneWindow(dp, 0);
1006 _screen->updateScreen();
1007 fadeText();
1008 delayUntil(delayTimer);
1009
1010 delayTimer = _system->getMillis() + speed * _tickLength;
1011 _screen->smoothScrollTurnStep2(_sceneDrawPage1, _sceneDrawPage2, dp);
1012 if (d)
1013 _screen->copyGuiShapeToSurface(14, dp);
1014 _screen->restoreSceneWindow(dp, 0);
1015 _screen->updateScreen();
1016 fadeText();
1017 delayUntil(delayTimer);
1018
1019 delayTimer = _system->getMillis() + speed * _tickLength;
1020 _screen->smoothScrollTurnStep3(_sceneDrawPage1, _sceneDrawPage2, dp);
1021 if (d)
1022 _screen->copyGuiShapeToSurface(14, dp);
1023 _screen->restoreSceneWindow(dp, 0);
1024 _screen->updateScreen();
1025 fadeText();
1026 delayUntil(delayTimer);
1027
1028 if (_sceneDefaultUpdate != 2) {
1029 drawSpecialGuiShape(_sceneDrawPage1);
1030 _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK);
1031 _screen->updateScreen();
1032 }
1033 }
1034
movePartySmoothScrollTurnRight(int speed)1035 void LoLEngine::movePartySmoothScrollTurnRight(int speed) {
1036 if (!_smoothScrollingEnabled)
1037 return;
1038
1039 speed <<= 1;
1040
1041 int d = smoothScrollDrawSpecialGuiShape(_sceneDrawPage1);
1042 gui_drawScene(_sceneDrawPage1);
1043 int dp = _sceneDrawPage2 == 2 ? _sceneDrawPage2 : _sceneDrawPage1;
1044
1045 uint32 delayTimer = _system->getMillis() + speed * _tickLength;
1046 _screen->smoothScrollTurnStep3(_sceneDrawPage2, _sceneDrawPage1, dp);
1047 if (d)
1048 _screen->copyGuiShapeToSurface(14, dp);
1049 _screen->restoreSceneWindow(dp, 0);
1050 _screen->updateScreen();
1051 fadeText();
1052 delayUntil(delayTimer);
1053
1054 delayTimer = _system->getMillis() + speed * _tickLength;
1055 _screen->smoothScrollTurnStep2(_sceneDrawPage2, _sceneDrawPage1, dp);
1056 if (d)
1057 _screen->copyGuiShapeToSurface(14, dp);
1058 _screen->restoreSceneWindow(dp, 0);
1059 _screen->updateScreen();
1060 fadeText();
1061 delayUntil(delayTimer);
1062
1063 delayTimer = _system->getMillis() + speed * _tickLength;
1064 _screen->smoothScrollTurnStep1(_sceneDrawPage2, _sceneDrawPage1, dp);
1065 if (d)
1066 _screen->copyGuiShapeToSurface(14, dp);
1067 _screen->restoreSceneWindow(dp, 0);
1068 _screen->updateScreen();
1069 fadeText();
1070 delayUntil(delayTimer);
1071
1072 if (_sceneDefaultUpdate != 2) {
1073 drawSpecialGuiShape(_sceneDrawPage1);
1074 _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK);
1075 _screen->updateScreen();
1076 }
1077 }
1078
pitDropScroll(int numSteps)1079 void LoLEngine::pitDropScroll(int numSteps) {
1080 _screen->copyRegionSpecial(0, 320, 200, 112, 0, 6, 176, 120, 0, 0, 176, 120, 0);
1081 uint32 etime = 0;
1082
1083 for (int i = 0; i < numSteps; i++) {
1084 etime = _system->getMillis() + _tickLength;
1085 int ys = ((30720 / numSteps) * i) >> 8;
1086 _screen->copyRegionSpecial(6, 176, 120, 0, ys, 0, 320, 200, 112, 0, 176, 120 - ys, 0);
1087 _screen->copyRegionSpecial(2, 320, 200, 112, 0, 0, 320, 200, 112, 120 - ys, 176, ys, 0);
1088 _screen->updateScreen();
1089
1090 delayUntil(etime);
1091 }
1092
1093 etime = _system->getMillis() + _tickLength;
1094
1095 _screen->copyRegionSpecial(2, 320, 200, 112, 0, 0, 320, 200, 112, 0, 176, 120, 0);
1096 _screen->updateScreen();
1097
1098 delayUntil(etime);
1099
1100 updateDrawPage2();
1101 }
1102
shakeScene(int duration,int width,int height,int restore)1103 void LoLEngine::shakeScene(int duration, int width, int height, int restore) {
1104 _screen->copyRegion(112, 0, 112, 0, 176, 120, 0, 6, Screen::CR_NO_P_CHECK);
1105 uint32 endTime = _system->getMillis() + duration * _tickLength;
1106
1107 while (endTime > _system->getMillis()) {
1108 uint32 delayTimer = _system->getMillis() + 2 * _tickLength;
1109
1110 int s1 = width ? (_rnd.getRandomNumber(255) % (width << 1)) - width : 0;
1111 int s2 = height ? (_rnd.getRandomNumber(255) % (height << 1)) - height : 0;
1112
1113 int x1, y1, x2, y2, w, h;
1114 if (s1 >= 0) {
1115 x1 = 112;
1116 x2 = 112 + s1;
1117 w = 176 - s1;
1118 } else {
1119 x1 = 112 - s1;
1120 x2 = 112;
1121 w = 176 + s1;
1122 }
1123
1124 if (s2 >= 0) {
1125 y1 = 0;
1126 y2 = s2;
1127 h = 120 - s2;
1128 } else {
1129 y1 = -s2;
1130 y2 = 0;
1131 h = 120 + s2;
1132 }
1133
1134 _screen->copyRegion(x1, y1, x2, y2, w, h, 6, 0, Screen::CR_NO_P_CHECK);
1135 _screen->updateScreen();
1136
1137 delayUntil(delayTimer);
1138 }
1139
1140 if (restore) {
1141 _screen->copyRegion(112, 0, 112, 0, 176, 120, 6, 0, Screen::CR_NO_P_CHECK);
1142 _screen->updateScreen();
1143 updateDrawPage2();
1144 }
1145 }
1146
processGasExplosion(int soundId)1147 void LoLEngine::processGasExplosion(int soundId) {
1148 int cp = _screen->setCurPage(2);
1149 _screen->copyPage(0, 12);
1150
1151 static const uint8 sounds[] = { 0x62, 0xA7, 0xA7, 0xA8 };
1152 snd_playSoundEffect(sounds[soundId], -1);
1153
1154 uint16 targetBlock = 0;
1155 int dist = getSpellTargetBlock(_currentBlock, _currentDirection, 3, targetBlock);
1156
1157 uint8 *p1 = _screen->getPalette(1).getData();
1158 uint8 *p2 = _screen->getPalette(3).getData();
1159
1160 if (dist) {
1161 WSAMovie_v2 *mov = new WSAMovie_v2(this);
1162 Common::String file = Common::String::format("gasexp%0d.wsa", dist);
1163 mov->open(file.c_str(), 1, 0);
1164 if (!mov->opened())
1165 error("Gas: Unable to load gasexp.wsa");
1166
1167 playSpellAnimation(mov, 0, 6, 1, (176 - mov->width()) / 2 + 112, (120 - mov->height()) / 2, 0, 0, 0, 0, false);
1168
1169 mov->close();
1170 delete mov;
1171
1172 } else {
1173 memcpy(p2, p1, 768);
1174
1175 for (int i = 1; i < 128; i++)
1176 p2[i * 3] = 0x3F;
1177
1178 uint32 ctime = _system->getMillis();
1179 while (_screen->timedPaletteFadeStep(_screen->getPalette(0).getData(), p2, _system->getMillis() - ctime, 10))
1180 updateInput();
1181
1182 ctime = _system->getMillis();
1183 while (_screen->timedPaletteFadeStep(p2, _screen->getPalette(0).getData(), _system->getMillis() - ctime, 50))
1184 updateInput();
1185 }
1186
1187 _screen->copyPage(12, 2);
1188 _screen->setCurPage(cp);
1189
1190 updateDrawPage2();
1191 _sceneUpdateRequired = true;
1192 gui_drawScene(0);
1193 }
1194
smoothScrollDrawSpecialGuiShape(int pageNum)1195 int LoLEngine::smoothScrollDrawSpecialGuiShape(int pageNum) {
1196 if (!_specialGuiShape)
1197 return 0;
1198
1199 _screen->clearGuiShapeMemory(pageNum);
1200 _screen->drawShape(pageNum, _specialGuiShape, _specialGuiShapeX, _specialGuiShapeY, 2, 0);
1201 _screen->copyGuiShapeFromSceneBackupBuffer(pageNum, 14);
1202 return 1;
1203 }
1204
drawScene(int pageNum)1205 void LoLEngine::drawScene(int pageNum) {
1206 if (pageNum && pageNum != _sceneDrawPage1) {
1207 SWAP(_sceneDrawPage1, _sceneDrawPage2);
1208 updateDrawPage2();
1209 }
1210
1211 if (pageNum && pageNum != _sceneDrawPage1) {
1212 SWAP(_sceneDrawPage1, _sceneDrawPage2);
1213 updateDrawPage2();
1214 }
1215
1216 generateBlockDrawingBuffer();
1217 drawVcnBlocks();
1218 drawSceneShapes();
1219
1220 if (!pageNum) {
1221 drawSpecialGuiShape(_sceneDrawPage1);
1222 _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, _sceneDrawPage2, Screen::CR_NO_P_CHECK);
1223 _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK);
1224 _screen->updateScreen();
1225 SWAP(_sceneDrawPage1, _sceneDrawPage2);
1226 }
1227
1228 updateEnvironmentalSfx(0);
1229 gui_drawCompass();
1230
1231 _sceneUpdateRequired = false;
1232 }
1233
1234
setWallType(int block,int wall,int val)1235 void LoLEngine::setWallType(int block, int wall, int val) {
1236 if (wall == -1) {
1237 for (int i = 0; i < 4; i++)
1238 _levelBlockProperties[block].walls[i] = val;
1239 if (_wllAutomapData[val] == 17) {
1240 _levelBlockProperties[block].flags &= 0xEF;
1241 _levelBlockProperties[block].flags |= 0x20;
1242 } else {
1243 _levelBlockProperties[block].flags &= 0xDF;
1244 }
1245 } else {
1246 _levelBlockProperties[block].walls[wall] = val;
1247 }
1248
1249 checkSceneUpdateNeed(block);
1250 }
1251
updateDrawPage2()1252 void LoLEngine::updateDrawPage2() {
1253 _screen->copyRegion(112, 0, 112, 0, 176, 120, 0, _sceneDrawPage2, Screen::CR_NO_P_CHECK);
1254 }
1255
prepareSpecialScene(int fieldType,int hasDialogue,int suspendGui,int allowSceneUpdate,int controlMode,int fadeFlag)1256 void LoLEngine::prepareSpecialScene(int fieldType, int hasDialogue, int suspendGui, int allowSceneUpdate, int controlMode, int fadeFlag) {
1257 resetPortraitsAndDisableSysTimer();
1258 if (fieldType) {
1259 if (suspendGui)
1260 gui_specialSceneSuspendControls(1);
1261
1262 if (!allowSceneUpdate)
1263 _sceneDefaultUpdate = 0;
1264
1265 if (hasDialogue)
1266 initDialogueSequence(fieldType, 0);
1267
1268 if (fadeFlag) {
1269 if (_flags.use16ColorMode)
1270 setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect);
1271 else
1272 _screen->fadePalette(_screen->getPalette(3), 10);
1273 _screen->_fadeFlag = 0;
1274 }
1275
1276 setSpecialSceneButtons(0, 0, 320, 130, controlMode);
1277
1278 } else {
1279 if (suspendGui)
1280 gui_specialSceneSuspendControls(0);
1281
1282 if (!allowSceneUpdate)
1283 _sceneDefaultUpdate = 0;
1284
1285 gui_disableControls(controlMode);
1286
1287 if (fadeFlag) {
1288 if (_flags.use16ColorMode) {
1289 setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect);
1290 } else {
1291 _screen->getPalette(3).copy(_screen->getPalette(0), 128);
1292 _screen->loadSpecialColors(_screen->getPalette(3));
1293 _screen->fadePalette(_screen->getPalette(3), 10);
1294 }
1295 _screen->_fadeFlag = 0;
1296 }
1297
1298 if (hasDialogue)
1299 initDialogueSequence(fieldType, 0);
1300
1301 setSpecialSceneButtons(112, 0, 176, 120, controlMode);
1302 }
1303 }
1304
restoreAfterSpecialScene(int fadeFlag,int redrawPlayField,int releaseTimScripts,int sceneUpdateMode)1305 int LoLEngine::restoreAfterSpecialScene(int fadeFlag, int redrawPlayField, int releaseTimScripts, int sceneUpdateMode) {
1306 if (!_needSceneRestore)
1307 return 0;
1308
1309 _needSceneRestore = 0;
1310 enableSysTimer(2);
1311
1312 if (_dialogueField)
1313 restoreAfterDialogueSequence(_currentControlMode);
1314
1315 if (_specialSceneFlag)
1316 gui_specialSceneRestoreControls(_currentControlMode);
1317
1318 int l = _currentControlMode;
1319 _currentControlMode = 0;
1320
1321 gui_specialSceneRestoreButtons();
1322 calcCharPortraitXpos();
1323
1324 _currentControlMode = l;
1325
1326 if (releaseTimScripts) {
1327 for (int i = 0; i < TIM::kWSASlots; i++)
1328 _tim->freeAnimStruct(i);
1329
1330 for (int i = 0; i < 10; i++)
1331 _tim->unload(_activeTim[i]);
1332 }
1333
1334 gui_enableControls();
1335
1336 if (fadeFlag) {
1337 if ((_screen->_fadeFlag != 1 && _screen->_fadeFlag != 2) || (_screen->_fadeFlag == 1 && _currentControlMode)) {
1338 if (_currentControlMode)
1339 _screen->fadeToBlack(10);
1340 else
1341 _screen->fadeClearSceneWindow(10);
1342 }
1343
1344 _currentControlMode = 0;
1345 calcCharPortraitXpos();
1346
1347 if (redrawPlayField)
1348 gui_drawPlayField();
1349
1350 setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect);
1351
1352 } else {
1353 _currentControlMode = 0;
1354 calcCharPortraitXpos();
1355
1356 if (redrawPlayField)
1357 gui_drawPlayField();
1358 }
1359
1360 _sceneDefaultUpdate = sceneUpdateMode;
1361 return 1;
1362 }
1363
setSequenceButtons(int x,int y,int w,int h,int enableFlags)1364 void LoLEngine::setSequenceButtons(int x, int y, int w, int h, int enableFlags) {
1365 gui_enableSequenceButtons(x, y, w, h, enableFlags);
1366 _seqWindowX1 = x;
1367 _seqWindowY1 = y;
1368 _seqWindowX2 = x + w;
1369 _seqWindowY2 = y + h;
1370 int offs = _itemInHand ? 10 : 0;
1371 _screen->setMouseCursor(offs, offs, getItemIconShapePtr(_itemInHand));
1372 _currentFloatingCursor = -1;
1373 if (w == 320) {
1374 setLampMode(0);
1375 _lampStatusSuspended = true;
1376 }
1377 }
1378
setSpecialSceneButtons(int x,int y,int w,int h,int enableFlags)1379 void LoLEngine::setSpecialSceneButtons(int x, int y, int w, int h, int enableFlags) {
1380 gui_enableSequenceButtons(x, y, w, h, enableFlags);
1381 _spsWindowX = x;
1382 _spsWindowY = y;
1383 _spsWindowW = w;
1384 _spsWindowH = h;
1385 }
1386
setDefaultButtonState()1387 void LoLEngine::setDefaultButtonState() {
1388 gui_enableDefaultPlayfieldButtons();
1389 _seqWindowX1 = _seqWindowY1 = _seqWindowX2 = _seqWindowY2 = _seqTrigger = 0;
1390 if (_lampStatusSuspended)
1391 resetLampStatus();
1392 _lampStatusSuspended = false;
1393 }
1394
drawSceneShapes(int)1395 void LoLEngine::drawSceneShapes(int) {
1396 for (int i = 0; i < 18; i++) {
1397 uint8 t = _dscTileIndex[i];
1398 uint8 s = _visibleBlocks[t]->walls[_sceneDrawVarDown];
1399
1400 _shpDmX1 = 0;
1401 _shpDmX2 = 0;
1402
1403 int16 dimY1 = 0;
1404 int16 dimY2 = 0;
1405
1406 setLevelShapesDim(t, _shpDmX1, _shpDmX2, _sceneShpDim);
1407
1408 if (_shpDmX2 <= _shpDmX1)
1409 continue;
1410
1411 drawDecorations(t);
1412
1413 uint16 w = _wllWallFlags[s];
1414
1415 if (t == 16)
1416 w |= 0x80;
1417
1418 drawBlockEffects(t, 0);
1419
1420 if (_visibleBlocks[t]->assignedObjects && (w & 0x80))
1421 drawBlockObjects(t);
1422
1423 drawBlockEffects(t, 1);
1424
1425 if (!(w & 8))
1426 continue;
1427
1428 uint16 v = 20 * (s - (s < 23 ? _dscDoorScaleOffs[s] : 0));
1429 if (v > 80)
1430 v = 80;
1431
1432 setDoorShapeDim(t, dimY1, dimY2, _sceneShpDim);
1433 drawDoor(_doorShapes[(s < 23 ? _dscDoorShpIndex[s] : 0)], 0, t, 10, 0, -v, 2);
1434 setLevelShapesDim(t, dimY1, dimY2, _sceneShpDim);
1435 }
1436 }
1437
drawDecorations(int index)1438 void LoLEngine::drawDecorations(int index) {
1439 for (int i = 1; i >= 0; i--) {
1440 int s = index * 2 + i;
1441 uint16 scaleW = _dscShapeScaleW[s];
1442 uint16 scaleH = _dscShapeScaleH[s];
1443 int8 ix = _dscShapeIndex[s];
1444 uint8 shpIx = ABS(ix);
1445 uint8 ovlIndex = _dscShapeOvlIndex[4 + _dscDimMap[index] * 5] + 2;
1446 if (ovlIndex > 7)
1447 ovlIndex = 7;
1448
1449 if (!scaleW || !scaleH)
1450 continue;
1451
1452 uint8 d = (_currentDirection + _dscWalls[s]) & 3;
1453 int8 l = _wllShapeMap[_visibleBlocks[index]->walls[d]];
1454
1455 uint8 *shapeData = 0;
1456
1457 int x = 0;
1458 int y = 0;
1459 int flags = 0;
1460
1461 while (l > 0) {
1462 if ((_levelDecorationProperties[l].flags & 8) && index != 3 && index != 9 && index != 13) {
1463 l = _levelDecorationProperties[l].next;
1464 continue;
1465 }
1466
1467 if (_dscOvlMap[shpIx] == 1 && ((_levelDecorationProperties[l].flags & 2) || ((_levelDecorationProperties[l].flags & 4) && _wllProcessFlag)))
1468 ix = -ix;
1469
1470 int xOffs = 0;
1471 int yOffs = 0;
1472 uint8 *ovl = 0;
1473
1474 if (_levelDecorationProperties[l].scaleFlag[shpIx] & 1) {
1475 xOffs = _levelDecorationProperties[l].shapeX[shpIx];
1476 yOffs = _levelDecorationProperties[l].shapeY[shpIx];
1477 shpIx = _dscOvlMap[shpIx];
1478 int ov = ovlIndex;
1479 if (_flags.use16ColorMode) {
1480 uint8 bb = _blockBrightness >> 4;
1481 if (ov > bb)
1482 ov -= bb;
1483 else
1484 ov = 0;
1485 }
1486 ovl = _screen->getLevelOverlay(ov);
1487 } else if (_levelDecorationProperties[l].shapeIndex[shpIx] != 0xFFFF) {
1488 scaleW = scaleH = 0x100;
1489 int ov = 7;
1490 if (_flags.use16ColorMode) {
1491 uint8 bb = _blockBrightness >> 4;
1492 if (ov > bb)
1493 ov -= bb;
1494 else
1495 ov = 0;
1496 }
1497 ovl = _screen->getLevelOverlay(ov);
1498 }
1499
1500 if (_levelDecorationProperties[l].shapeIndex[shpIx] != 0xFFFF) {
1501 shapeData = _levelDecorationShapes[_levelDecorationProperties[l].shapeIndex[shpIx]];
1502 if (shapeData) {
1503 if (ix < 0) {
1504 x = _dscShapeX[s] + xOffs + ((_levelDecorationProperties[l].shapeX[shpIx] * scaleW) >> 8);
1505 if (ix == _dscShapeIndex[s]) {
1506 x = _dscShapeX[s] - ((_levelDecorationProperties[l].shapeX[shpIx] * scaleW) >> 8) -
1507 _screen->getShapeScaledWidth(shapeData, scaleW) - xOffs;
1508 }
1509 flags = 0x105;
1510 } else {
1511 x = _dscShapeX[s] + xOffs + ((_levelDecorationProperties[l].shapeX[shpIx] * scaleW) >> 8);
1512 flags = 0x104;
1513 }
1514
1515 y = _dscShapeY[s] + yOffs + ((_levelDecorationProperties[l].shapeY[shpIx] * scaleH) >> 8);
1516 _screen->drawShape(_sceneDrawPage1, shapeData, x + 112, y, _sceneShpDim, flags, ovl, 1, scaleW, scaleH);
1517
1518 if ((_levelDecorationProperties[l].flags & 1) && shpIx < 4) {
1519 //draw shadow
1520 x += (_screen->getShapeScaledWidth(shapeData, scaleW));
1521 flags ^= 1;
1522 _screen->drawShape(_sceneDrawPage1, shapeData, x + 112, y, _sceneShpDim, flags, ovl, 1, scaleW, scaleH);
1523 }
1524 }
1525 }
1526
1527 l = _levelDecorationProperties[l].next;
1528 shpIx = (_dscShapeIndex[s] < 0) ? -_dscShapeIndex[s] : _dscShapeIndex[s];
1529 }
1530 }
1531 }
1532
drawBlockEffects(int index,int type)1533 void LoLEngine::drawBlockEffects(int index, int type) {
1534 static const uint16 yOffs[] = { 0xFF, 0xFF, 0x80, 0x80 };
1535 uint8 flg = _visibleBlocks[index]->flags;
1536 // flags: 0x10 = ice wall, 0x20 = teleporter, 0x40 = blue slime spot, 0x80 = blood spot
1537 if (!(flg & 0xF0))
1538 return;
1539
1540 type = (type == 0) ? 2 : 0;
1541
1542 for (int i = 0; i < 2; i++, type++) {
1543 if (!((0x10 << type) & flg))
1544 continue;
1545
1546 uint16 x = 0x80;
1547 uint16 y = yOffs[type];
1548 uint16 drawFlag = (type == 3) ? 0x80 : 0x20;
1549 uint8 *ovl = (type == 3) ? _screen->_grayOverlay : 0;
1550
1551 if (_flags.use16ColorMode) {
1552 ovl = 0;
1553 drawFlag = (type == 0 || type == 3) ? 0 : 0x20;
1554 }
1555
1556 calcCoordinatesAddDirectionOffset(x, y, _currentDirection);
1557
1558 x |= ((_visibleBlockIndex[index] & 0x1F) << 8);
1559 y |= ((_visibleBlockIndex[index] & 0xFFE0) << 3);
1560
1561 drawItemOrMonster(_effectShapes[type], ovl, x, y, 0, (type == 1) ? -20 : 0, drawFlag, -1, false);
1562 }
1563 }
1564
drawSpecialGuiShape(int pageNum)1565 void LoLEngine::drawSpecialGuiShape(int pageNum) {
1566 if (!_specialGuiShape)
1567 return;
1568
1569 _screen->drawShape(pageNum, _specialGuiShape, _specialGuiShapeX, _specialGuiShapeY, 2, 0);
1570
1571 if (_specialGuiShapeMirrorFlag & 1)
1572 _screen->drawShape(pageNum, _specialGuiShape, _specialGuiShapeX + _specialGuiShape[3], _specialGuiShapeY, 2, 1);
1573 }
1574
1575 } // End of namespace Kyra
1576
1577 #endif // ENABLE_LOL
1578