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