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 #if defined(ENABLE_EOB) || defined(ENABLE_LOL)
24
25 #include "kyra/engine/kyra_rpg.h"
26 #include "kyra/resource/resource.h"
27 #include "kyra/engine/timer.h"
28 #include "kyra/sound/sound.h"
29
30 #include "common/system.h"
31
32 namespace Kyra {
33
setLevelShapesDim(int index,int16 & x1,int16 & x2,int dim)34 void KyraRpgEngine::setLevelShapesDim(int index, int16 &x1, int16 &x2, int dim) {
35 if (_lvlShapeLeftRight[index << 1] == -1) {
36 x1 = 0;
37 x2 = 22;
38
39 int16 y1 = 0;
40 int16 y2 = 120;
41
42 int m = index * 18;
43
44 for (int i = 0; i < 18; i++) {
45 uint8 d = _visibleBlocks[i]->walls[_sceneDrawVarDown];
46 uint8 a = _wllWallFlags[d];
47
48 if (a & 8) {
49 int t = _dscDim2[(m + i) << 1];
50
51 if (t > x1) {
52 x1 = t;
53 if (!(a & 0x10))
54 setDoorShapeDim(index, y1, y2, -1);
55 }
56
57 t = _dscDim2[((m + i) << 1) + 1];
58
59 if (t < x2) {
60 x2 = t;
61 if (!(a & 0x10))
62 setDoorShapeDim(index, y1, y2, -1);
63 }
64 } else {
65 int t = _dscDim1[m + i];
66
67 if (!_wllVmpMap[d] || t == -40)
68 continue;
69
70 if (t == -41) {
71 x1 = 22;
72 x2 = 0;
73 break;
74 }
75
76 if (t > 0 && x2 > t)
77 x2 = t;
78
79 if (t < 0 && x1 < -t)
80 x1 = -t;
81 }
82
83 if (x2 < x1)
84 break;
85 }
86
87 x1 += (_sceneXoffset >> 3);
88 x2 += (_sceneXoffset >> 3);
89
90 _lvlShapeTop[index] = y1;
91 _lvlShapeBottom[index] = y2;
92 _lvlShapeLeftRight[index << 1] = x1;
93 _lvlShapeLeftRight[(index << 1) + 1] = x2;
94 } else {
95 x1 = _lvlShapeLeftRight[index << 1];
96 x2 = _lvlShapeLeftRight[(index << 1) + 1];
97 }
98
99 drawLevelModifyScreenDim(dim, x1, 0, x2, 15);
100 }
101
setDoorShapeDim(int index,int16 & y1,int16 & y2,int dim)102 void KyraRpgEngine::setDoorShapeDim(int index, int16 &y1, int16 &y2, int dim) {
103 uint8 a = _dscDimMap[index];
104
105 if (_flags.gameID != GI_EOB1 && dim == -1 && a != 3)
106 a++;
107
108 uint8 b = a;
109 if (_flags.gameID == GI_EOB1) {
110 a += _dscDoorFrameIndex1[_currentLevel - 1];
111 b += _dscDoorFrameIndex2[_currentLevel - 1];
112 }
113
114 y1 = _dscDoorFrameY1[a];
115 y2 = _dscDoorFrameY2[b];
116
117 if (dim == -1)
118 return;
119
120 const ScreenDim *cDim = screen()->getScreenDim(dim);
121
122 screen()->modifyScreenDim(dim, cDim->sx, y1, cDim->w, y2 - y1);
123 }
124
drawLevelModifyScreenDim(int dim,int16 x1,int16 y1,int16 x2,int16 y2)125 void KyraRpgEngine::drawLevelModifyScreenDim(int dim, int16 x1, int16 y1, int16 x2, int16 y2) {
126 screen()->modifyScreenDim(dim, x1, y1 << 3, x2 - x1, (y2 - y1) << 3);
127 }
128
generateBlockDrawingBuffer()129 void KyraRpgEngine::generateBlockDrawingBuffer() {
130 _sceneDrawVarDown = _dscBlockMap[_currentDirection];
131 _sceneDrawVarRight = _dscBlockMap[_currentDirection + 4];
132 _sceneDrawVarLeft = _dscBlockMap[_currentDirection + 8];
133
134 /*******************************************
135 * _visibleBlocks map *
136 * *
137 * | | | | | | *
138 * 00 | 01 | 02 | 03 | 04 | 05 | 06 *
139 * ____|_____|_____|_____|_____|_____|_____ *
140 * | | | | | | *
141 * | 07 | 08 | 09 | 10 | 11 | *
142 * |_____|_____|_____|_____|_____| *
143 * | | | | *
144 * | 12 | 13 | 14 | *
145 * |_____|_____|_____| *
146 * | | *
147 * 15 | 16 | 17 *
148 * | (P) | *
149 ********************************************/
150
151 memset(_blockDrawingBuffer, 0, 660 * sizeof(uint16));
152
153 _wllProcessFlag = ((_currentBlock >> 5) + (_currentBlock & 0x1F) + _currentDirection) & 1;
154
155 if (_wllProcessFlag) // floor and ceiling
156 generateVmpTileDataFlipped(0, 15, 1, -330, 22, 15);
157 else
158 generateVmpTileData(0, 15, 1, -330, 22, 15);
159
160 assignVisibleBlocks(_currentBlock, _currentDirection);
161
162 uint8 t = _visibleBlocks[0]->walls[_sceneDrawVarRight];
163 if (t)
164 generateVmpTileData(-2, 3, t, 102, 3, 5);
165
166 t = _visibleBlocks[6]->walls[_sceneDrawVarLeft];
167 if (t)
168 generateVmpTileDataFlipped(21, 3, t, 102, 3, 5);
169
170 t = _visibleBlocks[1]->walls[_sceneDrawVarRight];
171 uint8 t2 = _visibleBlocks[2]->walls[_sceneDrawVarDown];
172
173 if (hasWall(t) && !(_wllWallFlags[t2] & 8))
174 generateVmpTileData(2, 3, t, 102, 3, 5);
175 else if (t && (_wllWallFlags[t2] & 8))
176 generateVmpTileData(2, 3, t2, 102, 3, 5);
177
178 t = _visibleBlocks[5]->walls[_sceneDrawVarLeft];
179 t2 = _visibleBlocks[4]->walls[_sceneDrawVarDown];
180
181 if (hasWall(t) && !(_wllWallFlags[t2] & 8))
182 generateVmpTileDataFlipped(17, 3, t, 102, 3, 5);
183 else if (t && (_wllWallFlags[t2] & 8))
184 generateVmpTileDataFlipped(17, 3, t2, 102, 3, 5);
185
186 t = _visibleBlocks[2]->walls[_sceneDrawVarRight];
187 if (t)
188 generateVmpTileData(8, 3, t, 97, 1, 5);
189
190 t = _visibleBlocks[4]->walls[_sceneDrawVarLeft];
191 if (t)
192 generateVmpTileDataFlipped(13, 3, t, 97, 1, 5);
193
194 t = _visibleBlocks[1]->walls[_sceneDrawVarDown];
195 if (hasWall(t))
196 generateVmpTileData(-4, 3, t, 129, 6, 5);
197
198 t = _visibleBlocks[5]->walls[_sceneDrawVarDown];
199 if (hasWall(t))
200 generateVmpTileData(20, 3, t, 129, 6, 5);
201
202 t = _visibleBlocks[2]->walls[_sceneDrawVarDown];
203 if (hasWall(t))
204 generateVmpTileData(2, 3, t, 129, 6, 5);
205
206 t = _visibleBlocks[4]->walls[_sceneDrawVarDown];
207 if (hasWall(t))
208 generateVmpTileData(14, 3, t, 129, 6, 5);
209
210 t = _visibleBlocks[3]->walls[_sceneDrawVarDown];
211 if (t)
212 generateVmpTileData(8, 3, t, 129, 6, 5);
213
214 t = _visibleBlocks[7]->walls[_sceneDrawVarRight];
215 if (t)
216 generateVmpTileData(0, 3, t, 117, 2, 6);
217
218 t = _visibleBlocks[11]->walls[_sceneDrawVarLeft];
219 if (t)
220 generateVmpTileDataFlipped(20, 3, t, 117, 2, 6);
221
222 t = _visibleBlocks[8]->walls[_sceneDrawVarRight];
223 if (t)
224 generateVmpTileData(6, 2, t, 81, 2, 8);
225
226 t = _visibleBlocks[10]->walls[_sceneDrawVarLeft];
227 if (t)
228 generateVmpTileDataFlipped(14, 2, t, 81, 2, 8);
229
230 t = _visibleBlocks[8]->walls[_sceneDrawVarDown];
231 if (hasWall(t))
232 generateVmpTileData(-4, 2, t, 159, 10, 8);
233
234 t = _visibleBlocks[10]->walls[_sceneDrawVarDown];
235 if (hasWall(t))
236 generateVmpTileData(16, 2, t, 159, 10, 8);
237
238 t = _visibleBlocks[9]->walls[_sceneDrawVarDown];
239 if (t)
240 generateVmpTileData(6, 2, t, 159, 10, 8);
241
242 t = _visibleBlocks[12]->walls[_sceneDrawVarRight];
243 if (t)
244 generateVmpTileData(3, 1, t, 45, 3, 12);
245
246 t = _visibleBlocks[14]->walls[_sceneDrawVarLeft];
247 if (t)
248 generateVmpTileDataFlipped(16, 1, t, 45, 3, 12);
249
250 t = _visibleBlocks[12]->walls[_sceneDrawVarDown];
251 if (!(_wllWallFlags[t] & 8))
252 generateVmpTileData(-13, 1, t, 239, 16, 12);
253
254 t = _visibleBlocks[14]->walls[_sceneDrawVarDown];
255 if (!(_wllWallFlags[t] & 8))
256 generateVmpTileData(19, 1, t, 239, 16, 12);
257
258 t = _visibleBlocks[13]->walls[_sceneDrawVarDown];
259 if (t)
260 generateVmpTileData(3, 1, t, 239, 16, 12);
261
262 t = _visibleBlocks[15]->walls[_sceneDrawVarRight];
263 t2 = _visibleBlocks[17]->walls[_sceneDrawVarLeft];
264 if (t)
265 generateVmpTileData(0, 0, t, 0, 3, 15);
266 if (t2)
267 generateVmpTileDataFlipped(19, 0, t2, 0, 3, 15);
268 }
269
generateVmpTileData(int16 startBlockX,uint8 startBlockY,uint8 vmpMapIndex,int16 vmpOffset,uint8 numBlocksX,uint8 numBlocksY)270 void KyraRpgEngine::generateVmpTileData(int16 startBlockX, uint8 startBlockY, uint8 vmpMapIndex, int16 vmpOffset, uint8 numBlocksX, uint8 numBlocksY) {
271 if (!_wllVmpMap[vmpMapIndex])
272 return;
273
274 uint16 *vmp = &_vmpPtr[(_wllVmpMap[vmpMapIndex] - 1) * 431 + vmpOffset + 330];
275
276 for (int i = 0; i < numBlocksY; i++) {
277 uint16 *bl = &_blockDrawingBuffer[(startBlockY + i) * 22 + startBlockX];
278 for (int ii = 0; ii < numBlocksX; ii++) {
279 if ((startBlockX + ii >= 0) && (startBlockX + ii < 22) && *vmp)
280 *bl = *vmp;
281 bl++;
282 vmp++;
283 }
284 }
285 }
286
generateVmpTileDataFlipped(int16 startBlockX,uint8 startBlockY,uint8 vmpMapIndex,int16 vmpOffset,uint8 numBlocksX,uint8 numBlocksY)287 void KyraRpgEngine::generateVmpTileDataFlipped(int16 startBlockX, uint8 startBlockY, uint8 vmpMapIndex, int16 vmpOffset, uint8 numBlocksX, uint8 numBlocksY) {
288 if (!_wllVmpMap[vmpMapIndex])
289 return;
290
291 uint16 *vmp = &_vmpPtr[(_wllVmpMap[vmpMapIndex] - 1) * 431 + vmpOffset + 330];
292
293 for (int i = 0; i < numBlocksY; i++) {
294 for (int ii = 0; ii < numBlocksX; ii++) {
295 if ((startBlockX + ii) < 0 || (startBlockX + ii) > 21)
296 continue;
297
298 uint16 v = vmp[i * numBlocksX + (numBlocksX - 1 - ii)];
299 if (!v)
300 continue;
301
302 if (v & 0x4000)
303 v -= 0x4000;
304 else
305 v |= 0x4000;
306
307 _blockDrawingBuffer[(startBlockY + i) * 22 + startBlockX + ii] = v;
308 }
309 }
310 }
311
hasWall(int index)312 bool KyraRpgEngine::hasWall(int index) {
313 if (!index || (_wllWallFlags[index] & 8))
314 return false;
315 return true;
316 }
317
assignVisibleBlocks(int block,int direction)318 void KyraRpgEngine::assignVisibleBlocks(int block, int direction) {
319 for (int i = 0; i < 18; i++) {
320 uint16 t = (block + _dscBlockIndex[direction * 18 + i]) & 0x3FF;
321 _visibleBlockIndex[i] = t;
322
323 _visibleBlocks[i] = &_levelBlockProperties[t];
324 _lvlShapeLeftRight[i] = _lvlShapeLeftRight[18 + i] = -1;
325 }
326 }
327
checkSceneUpdateNeed(int block)328 bool KyraRpgEngine::checkSceneUpdateNeed(int block) {
329 if (_sceneUpdateRequired)
330 return true;
331
332 for (int i = 0; i < 15; i++) {
333 if (_visibleBlockIndex[i] == block) {
334 _sceneUpdateRequired = true;
335 return true;
336 }
337 }
338
339 if (_currentBlock == block) {
340 _sceneUpdateRequired = true;
341 return true;
342 }
343
344 return false;
345 }
346
calcNewBlockPosition(uint16 curBlock,uint16 direction)347 uint16 KyraRpgEngine::calcNewBlockPosition(uint16 curBlock, uint16 direction) {
348 static const int16 blockPosTable[] = { -32, 1, 32, -1 };
349 return (curBlock + blockPosTable[direction]) & 0x3FF;
350 }
351
drawVcnBlocks()352 void KyraRpgEngine::drawVcnBlocks() {
353 uint8 *d = _sceneWindowBuffer;
354 uint16 *bdb = _blockDrawingBuffer;
355
356 for (int y = 0; y < 15; y++) {
357 for (int x = 0; x < 22; x++) {
358 bool horizontalFlip = false;
359 uint16 vcnOffset = *bdb++;
360 uint16 vcnExtraOffsetWll = 0;
361 _wllVcnOffset2 = 0;
362 _wllVcnRmdOffset = 0;
363
364 if (vcnOffset & 0x8000) {
365 // this renders a wall block over the transparent pixels of a floor/ceiling block
366 vcnExtraOffsetWll = vcnOffset - 0x8000;
367 vcnOffset = 0;
368 _wllVcnRmdOffset = _wllVcnOffset;
369 }
370
371 if (vcnOffset & 0x4000) {
372 horizontalFlip = true;
373 vcnOffset &= 0x3FFF;
374 }
375
376 const uint8 *src = 0;
377 if (vcnOffset) {
378 src = &_vcnBlocks[vcnOffset * (_vcnSrcBitsPerPixel << 3)];
379 _wllVcnOffset2 = _wllVcnOffset;
380 } else {
381 // floor/ceiling blocks
382 vcnOffset = bdb[329];
383 if (vcnOffset & 0x4000) {
384 horizontalFlip = true;
385 vcnOffset &= 0x3FFF;
386 }
387
388 src = (_vcfBlocks ? _vcfBlocks : _vcnBlocks) + (vcnOffset * (_vcnSrcBitsPerPixel << 3));
389 }
390
391 _vcnShiftVal = _vcnShift ? _vcnShift[vcnOffset] : _blockBrightness;
392
393 for (int blockY = 0; blockY < 8; blockY++) {
394 if (horizontalFlip)
395 (*_vcnDrawLine->backwards)(d, src);
396 else
397 (*_vcnDrawLine->forward)(d, src);
398 d += 168 * _vcnBpp;
399 }
400 d -= 1400 * _vcnBpp;
401
402 if (vcnExtraOffsetWll) {
403 d -= (8 * _vcnBpp);
404 horizontalFlip = false;
405
406 if (vcnExtraOffsetWll & 0x4000) {
407 vcnExtraOffsetWll &= 0x3FFF;
408 horizontalFlip = true;
409 }
410
411 _vcnShiftVal = _vcnShift ? _vcnShift[vcnExtraOffsetWll] : _blockBrightness;
412 src = &_vcnBlocks[vcnExtraOffsetWll * (_vcnSrcBitsPerPixel << 3)];
413 _vcnMaskTbl = _vcnTransitionMask ? &_vcnTransitionMask[vcnExtraOffsetWll * (_vcnSrcBitsPerPixel << 3)] : 0;
414
415 for (int blockY = 0; blockY < 8; blockY++) {
416 if (horizontalFlip)
417 (*_vcnDrawLine->backwards_trans)(d, src);
418 else
419 (*_vcnDrawLine->forward_trans)(d, src);
420 d += 168 * _vcnBpp;
421 }
422 d -= 1400 * _vcnBpp;
423 }
424 }
425 d += 1232 * _vcnBpp;
426 }
427
428 screen()->copyBlockToPage(_sceneDrawPage1, _sceneXoffset, 0, 176, 120, _sceneWindowBuffer);
429 }
430
vcnDraw_fw_4bit(uint8 * & dst,const uint8 * & src)431 void KyraRpgEngine::vcnDraw_fw_4bit(uint8 *&dst, const uint8 *&src) {
432 for (int blockX = 0; blockX < 4; blockX++) {
433 uint8 bl = *src++;
434 *dst++ = _vcnColTable[((bl >> 4) + _wllVcnOffset2) | _vcnShiftVal];
435 *dst++ = _vcnColTable[((bl & 0x0F) + _wllVcnOffset2) | _vcnShiftVal];
436 }
437 }
438
vcnDraw_bw_4bit(uint8 * & dst,const uint8 * & src)439 void KyraRpgEngine::vcnDraw_bw_4bit(uint8 *&dst, const uint8 *&src) {
440 src += 3;
441 for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) {
442 uint8 bl = *src--;
443 *dst++ = _vcnColTable[((bl & 0x0F) + _wllVcnOffset2) | _vcnShiftVal];
444 *dst++ = _vcnColTable[((bl >> 4) + _wllVcnOffset2) | _vcnShiftVal];
445 }
446 src += 5;
447 }
448
vcnDraw_fw_trans_4bit(uint8 * & dst,const uint8 * & src)449 void KyraRpgEngine::vcnDraw_fw_trans_4bit(uint8 *&dst, const uint8 *&src) {
450 for (int blockX = 0; blockX < _vcnSrcBitsPerPixel; blockX++) {
451 uint8 bl = *src++;
452 uint8 mask = _vcnTransitionMask ? *_vcnMaskTbl++ : 0;
453 uint8 h = _vcnColTable[((bl >> 4) + _wllVcnRmdOffset) | _vcnShiftVal];
454 uint8 l = _vcnColTable[((bl & 0x0F) + _wllVcnRmdOffset) | _vcnShiftVal];
455
456 if (_vcnTransitionMask)
457 *dst = (*dst & (mask >> 4)) | h;
458 else if (h)
459 *dst = h;
460 dst++;
461
462 if (_vcnTransitionMask)
463 *dst = (*dst & (mask & 0x0F)) | l;
464 else if (l)
465 *dst = l;
466 dst++;
467 }
468 }
469
vcnDraw_bw_trans_4bit(uint8 * & dst,const uint8 * & src)470 void KyraRpgEngine::vcnDraw_bw_trans_4bit(uint8 *&dst, const uint8 *&src) {
471 src += 3;
472 _vcnMaskTbl += 3;
473 for (int blockX = 0; blockX < _vcnSrcBitsPerPixel; blockX++) {
474 uint8 bl = *src--;
475 uint8 mask = _vcnTransitionMask ? *_vcnMaskTbl-- : 0;
476 uint8 h = _vcnColTable[((bl & 0x0F) + _wllVcnRmdOffset) | _vcnShiftVal];
477 uint8 l = _vcnColTable[((bl >> 4) + _wllVcnRmdOffset) | _vcnShiftVal];
478
479 if (_vcnTransitionMask)
480 *dst = (*dst & (mask & 0x0F)) | h;
481 else if (h)
482 *dst = h;
483 dst++;
484
485 if (_vcnTransitionMask)
486 *dst = (*dst & (mask >> 4)) | l;
487 else if (l)
488 *dst = l;
489 dst++;
490 }
491 src += 5;
492 _vcnMaskTbl += 5;
493 }
494
vcnDraw_fw_hiCol(uint8 * & dst,const uint8 * & src)495 void KyraRpgEngine::vcnDraw_fw_hiCol(uint8 *&dst, const uint8 *&src) {
496 const uint16 *hiColorPal = screen()->get16bitPalette();
497 for (int blockX = 0; blockX < 8; blockX++) {
498 *(uint16*)dst = hiColorPal[*src++];
499 dst += 2;
500 }
501 }
502
vcnDraw_bw_hiCol(uint8 * & dst,const uint8 * & src)503 void KyraRpgEngine::vcnDraw_bw_hiCol(uint8 *&dst, const uint8 *&src) {
504 src += 7;
505 const uint16 *hiColorPal = screen()->get16bitPalette();
506 for (int blockX = 0; blockX < 4 * _vcnBpp; blockX++) {
507 *(uint16*)dst = hiColorPal[*src--];
508 dst += 2;
509 }
510 src += 9;
511 }
512
vcnDraw_fw_trans_hiCol(uint8 * & dst,const uint8 * & src)513 void KyraRpgEngine::vcnDraw_fw_trans_hiCol(uint8 *&dst, const uint8 *&src) {
514 const uint16 *hiColorPal = screen()->get16bitPalette();
515 for (int blockX = 0; blockX < _vcnSrcBitsPerPixel; blockX++) {
516 uint8 bl = *src++;
517 if (bl)
518 *(uint16*)dst = hiColorPal[bl];
519 dst += 2;
520 }
521 }
522
vcnDraw_bw_trans_hiCol(uint8 * & dst,const uint8 * & src)523 void KyraRpgEngine::vcnDraw_bw_trans_hiCol(uint8 *&dst, const uint8 *&src) {
524 src += 7;
525 const uint16 *hiColorPal = screen()->get16bitPalette();
526 for (int blockX = 0; blockX < _vcnSrcBitsPerPixel; blockX++) {
527 uint8 bl = *src--;
528 if (bl)
529 *(uint16*)dst = hiColorPal[bl];
530 dst += 2;
531 }
532 src += 9;
533 }
534
vcnDraw_fw_Amiga(uint8 * & dst,const uint8 * & src)535 void KyraRpgEngine::vcnDraw_fw_Amiga(uint8 *&dst, const uint8 *&src) {
536 for (int blockX = 0; blockX < 8; blockX++) {
537 uint8 col = 0;
538 for (int i = 0; i < 5; ++i)
539 col |= (((src[i] & (0x80 >> blockX)) >> (7 - blockX)) << i);
540 *dst++ = col;
541 }
542 src += 5;
543 }
544
vcnDraw_bw_Amiga(uint8 * & dst,const uint8 * & src)545 void KyraRpgEngine::vcnDraw_bw_Amiga(uint8 *&dst, const uint8 *&src) {
546 for (int blockX = 7; blockX >= 0; blockX--) {
547 uint8 col = 0;
548 for (int i = 0; i < 5; ++i)
549 col |= (((src[i] & (0x80 >> blockX)) >> (7 - blockX)) << i);
550 *dst++ = col;
551 }
552 src += 5;
553 }
554
vcnDraw_fw_trans_Amiga(uint8 * & dst,const uint8 * & src)555 void KyraRpgEngine::vcnDraw_fw_trans_Amiga(uint8 *&dst, const uint8 *&src) {
556 for (int blockX = 0; blockX < 8; blockX++) {
557 uint8 col = 0;
558 for (int i = 0; i < 5; ++i)
559 col |= (((src[i] & (0x80 >> blockX)) >> (7 - blockX)) << i);
560
561 if (col)
562 *dst = col;
563 dst++;
564 }
565 src += 5;
566 }
567
vcnDraw_bw_trans_Amiga(uint8 * & dst,const uint8 * & src)568 void KyraRpgEngine::vcnDraw_bw_trans_Amiga(uint8 *&dst, const uint8 *&src) {
569 for (int blockX = 7; blockX >= 0; blockX--) {
570 uint8 col = 0;
571 for (int i = 0; i < 5; ++i)
572 col |= (((src[i] & (0x80 >> blockX)) >> (7 - blockX)) << i);
573
574 if (col)
575 *dst = col;
576 dst++;
577 }
578 src += 5;
579 }
580
581
clickedWallShape(uint16 block,uint16 direction)582 int KyraRpgEngine::clickedWallShape(uint16 block, uint16 direction) {
583 uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
584 if (!clickedShape(v))
585 return 0;
586
587 snd_stopSpeech(true);
588 runLevelScript(block, 0x40);
589
590 return 1;
591 }
592
clickedLeverOn(uint16 block,uint16 direction)593 int KyraRpgEngine::clickedLeverOn(uint16 block, uint16 direction) {
594 uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
595 if (!clickedShape(v))
596 return 0;
597
598 _levelBlockProperties[block].walls[direction]++;
599 _sceneUpdateRequired = true;
600
601 if (_flags.gameID == GI_LOL)
602 snd_playSoundEffect(30, -1);
603
604 runLevelScript(block, _clickedSpecialFlag);
605
606 return 1;
607 }
608
clickedLeverOff(uint16 block,uint16 direction)609 int KyraRpgEngine::clickedLeverOff(uint16 block, uint16 direction) {
610 uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
611 if (!clickedShape(v))
612 return 0;
613
614 _levelBlockProperties[block].walls[direction]--;
615 _sceneUpdateRequired = true;
616
617 if (_flags.gameID == GI_LOL)
618 snd_playSoundEffect(29, -1);
619
620 runLevelScript(block, _clickedSpecialFlag);
621 return 1;
622 }
623
clickedWallOnlyScript(uint16 block)624 int KyraRpgEngine::clickedWallOnlyScript(uint16 block) {
625 runLevelScript(block, _clickedSpecialFlag);
626 return 1;
627 }
628
processDoorSwitch(uint16 block,int openClose)629 void KyraRpgEngine::processDoorSwitch(uint16 block, int openClose) {
630 if (block == _currentBlock)
631 return;
632
633 if ((_flags.gameID == GI_LOL && (_levelBlockProperties[block].assignedObjects & 0x8000)) || (_flags.gameID != GI_LOL && (_levelBlockProperties[block].flags & 7)))
634 return;
635
636 if (openClose == 0) {
637 for (int i = 0; i < 3; i++) {
638 if (_openDoorState[i].block != block)
639 continue;
640 openClose = -_openDoorState[i].state;
641 break;
642 }
643 }
644
645 if (openClose == 0) {
646 openClose = (_wllWallFlags[_levelBlockProperties[block].walls[_wllWallFlags[_levelBlockProperties[block].walls[0]] & 8 ? 0 : 1]] & 1) ? 1 : -1;
647 if (_flags.gameID != GI_LOL)
648 openClose *= -1;
649 }
650
651 openCloseDoor(block, openClose);
652 }
653
openCloseDoor(int block,int openClose)654 void KyraRpgEngine::openCloseDoor(int block, int openClose) {
655 int s1 = -1;
656 int s2 = -1;
657
658 int c = (_wllWallFlags[_levelBlockProperties[block].walls[0]] & 8) ? 0 : 1;
659 int v = _levelBlockProperties[block].walls[c];
660 int flg = (_flags.gameID == GI_EOB1) ? 1 : ((openClose == 1) ? 0x10 : (openClose == -1 ? 0x20 : 0));
661
662 if ((_flags.gameID == GI_EOB1 && openClose == -1 && !(_wllWallFlags[v] & flg)) || (!(_flags.gameID == GI_EOB1 && openClose == -1) && (_wllWallFlags[v] & flg)))
663 return;
664
665 for (int i = 0; i < 3; i++) {
666 if (_openDoorState[i].block == block) {
667 s1 = i;
668 break;
669 } else if (_openDoorState[i].block == 0 && s2 == -1) {
670 s2 = i;
671 }
672 }
673
674 if (s1 != -1 || s2 != -1) {
675 if (s1 == -1)
676 s1 = s2;
677
678 _openDoorState[s1].block = block;
679 _openDoorState[s1].state = openClose;
680 _openDoorState[s1].wall = c;
681
682 flg = (-openClose == 1) ? 0x10 : (-openClose == -1 ? 0x20 : 0);
683
684 if (_wllWallFlags[v] & flg) {
685 _levelBlockProperties[block].walls[c] += openClose;
686 _levelBlockProperties[block].walls[c ^ 2] += openClose;
687
688 int snd = (openClose == -1) ? 4 : 3;
689 if (_flags.gameID == GI_LOL) {
690 snd_processEnvironmentalSoundEffect(snd + 28, _currentBlock);
691 if (!checkSceneUpdateNeed(block))
692 updateEnvironmentalSfx(0);
693 } else {
694 updateEnvironmentalSfx(snd);
695 }
696 }
697
698 enableTimer(_flags.gameID == GI_LOL ? 0 : 4);
699
700 } else {
701 while (!(flg & _wllWallFlags[v]))
702 v += openClose;
703
704 _levelBlockProperties[block].walls[c] = _levelBlockProperties[block].walls[c ^ 2] = v;
705 checkSceneUpdateNeed(block);
706 }
707 }
708
completeDoorOperations()709 void KyraRpgEngine::completeDoorOperations() {
710 for (int i = 0; i < 3; i++) {
711 if (!_openDoorState[i].block)
712 continue;
713
714 uint16 b = _openDoorState[i].block;
715
716 do {
717 _levelBlockProperties[b].walls[_openDoorState[i].wall] += _openDoorState[i].state;
718 _levelBlockProperties[b].walls[_openDoorState[i].wall ^ 2] += _openDoorState[i].state;
719 } while (!(_wllWallFlags[_levelBlockProperties[b].walls[_openDoorState[i].wall]] & 0x30));
720
721 _openDoorState[i].block = 0;
722 }
723 }
724
725 } // End of namespace Kyra
726
727 #endif // ENABLE_EOB || ENABLE_LOL
728