1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/endian.h"
24 #include "common/stream.h"
25 
26 #include "gob/gob.h"
27 #include "gob/scenery.h"
28 #include "gob/global.h"
29 #include "gob/draw.h"
30 #include "gob/game.h"
31 #include "gob/script.h"
32 #include "gob/resources.h"
33 #include "gob/inter.h"
34 #include "gob/map.h"
35 #include "gob/videoplayer.h"
36 
37 namespace Gob {
38 
Scenery(GobEngine * vm)39 Scenery::Scenery(GobEngine *vm) : _vm(vm) {
40 	for (int i = 0; i < 20; i++) {
41 		_spriteRefs[i]  = 0;
42 		_spriteResId[i] = 0;
43 	}
44 
45 	for (int i = 0; i < 10; i++) {
46 		_staticPictCount[i] = 0;
47 		_staticResId[i]     = 0;
48 		_animPictCount[i]   = 0;
49 		_animResId[i]       = 0;
50 	}
51 
52 	_curStatic      = 0;
53 	_curStaticLayer = 0;
54 
55 	_toRedrawLeft   = 0;
56 	_toRedrawRight  = 0;
57 	_toRedrawTop    = 0;
58 	_toRedrawBottom = 0;
59 
60 	_animTop  = 0;
61 	_animLeft = 0;
62 
63 	_pCaptureCounter = 0;
64 
65 	for (int i = 0; i < 70; i++) {
66 		_staticPictToSprite[i] = 0;
67 		_animPictToSprite[i]   = 0;
68 	}
69 }
70 
~Scenery()71 Scenery::~Scenery() {
72 	for (int i = 0; i < 10; i++) {
73 		freeStatic(i);
74 		freeAnim(i);
75 	}
76 }
77 
init()78 void Scenery::init() {
79 	for (int i = 0; i < 10; i++) {
80 		if (_vm->getGameType() == kGameTypeFascination) {
81 			freeAnim(i);
82 			freeStatic(i);
83 		}
84 		_animPictCount[i]   =  0;
85 		_staticPictCount[i] = -1;
86 	}
87 
88 	for (int i = 0; i < 20; i++) {
89 		_spriteRefs[i]  =  0;
90 		_spriteResId[i] = -1;
91 	}
92 
93 	_curStaticLayer = -1;
94 	_curStatic      = -1;
95 }
96 
loadStatic(char search)97 int16 Scenery::loadStatic(char search) {
98 	int16 size;
99 	byte *backsPtr;
100 	int16 picsCount;
101 	int16 resId;
102 	int16 sceneryIndex;
103 	Static *ptr;
104 	int16 width;
105 	int16 height;
106 	int16 sprResId;
107 	int16 sprIndex;
108 
109 	_vm->_game->_script->evalExpr(&sceneryIndex);
110 
111 	size      = _vm->_game->_script->readInt16();
112 	backsPtr  = _vm->_game->_script->getData() + _vm->_game->_script->pos();
113 	_vm->_game->_script->skip(size * 2);
114 	picsCount = _vm->_game->_script->readInt16();
115 	resId     = _vm->_game->_script->readInt16();
116 
117 	if (search) {
118 		int i;
119 
120 		for (i = 0; i < 10; i++) {
121 			if ((_staticPictCount[i] != -1) && (_staticResId[i] == resId)) {
122 				_vm->_game->_script->skip(8 * _staticPictCount[i]);
123 				return i;
124 			}
125 
126 			if (_staticPictCount[i] == -1 && i < sceneryIndex)
127 				sceneryIndex = i;
128 		}
129 	}
130 
131 	_staticPictCount[sceneryIndex] = picsCount;
132 	_staticResId[sceneryIndex]     = resId;
133 
134 	Resource *resource = _vm->_game->_resources->getResource((uint16) resId);
135 	if (!resource)
136 		return 0;
137 
138 	ptr = &_statics[sceneryIndex];
139 
140 	ptr->layersCount = resource->stream()->readSint16LE();
141 
142 	ptr->layers = new StaticLayer[ptr->layersCount];
143 
144 	for (int i = 0; i < ptr->layersCount; i++) {
145 		Common::SeekableReadStream &layerData = *resource->stream();
146 
147 		layerData.seek(2 + i * 2);
148 		layerData.seek(layerData.readUint16LE());
149 
150 		ptr->layers[i].backResId  = layerData.readSint16LE();
151 		ptr->layers[i].planeCount = layerData.readSint16LE();
152 		if (ptr->layers[i].planeCount > 0) {
153 			ptr->layers[i].planes = new StaticPlane[ptr->layers[i].planeCount];
154 			for (int j = 0; j < ptr->layers[i].planeCount; j++) {
155 				ptr->layers[i].planes[j].pictIndex  = layerData.readByte();
156 				ptr->layers[i].planes[j].pieceIndex = layerData.readByte();
157 				ptr->layers[i].planes[j].drawOrder  = layerData.readByte();
158 				ptr->layers[i].planes[j].destX      = layerData.readSint16LE();
159 				ptr->layers[i].planes[j].destY      = layerData.readSint16LE();
160 				ptr->layers[i].planes[j].transp     = layerData.readSByte();
161 			}
162 		} else
163 			ptr->layers[i].planes = 0;
164 
165 		ptr->layers[i].backResId = (int16) READ_LE_UINT16(backsPtr);
166 		backsPtr += 2;
167 	}
168 
169 	ptr->pieces      = new PieceDesc*[picsCount];
170 	ptr->piecesCount = new uint32[picsCount];
171 
172 	for (int i = 0; i < picsCount; i++) {
173 		int16 pictDescId = _vm->_game->_script->readInt16();
174 
175 		loadPieces(pictDescId, ptr->pieces[i], ptr->piecesCount[i]);
176 
177 		width    = _vm->_game->_script->readInt16();
178 		height   = _vm->_game->_script->readInt16();
179 		sprResId = _vm->_game->_script->readInt16();
180 		for (sprIndex = 0; sprIndex < 20; sprIndex++) {
181 			if (_spriteResId[sprIndex] == sprResId)
182 				break;
183 		}
184 
185 		if (sprIndex < 20) {
186 			_staticPictToSprite[7 * sceneryIndex + i] = sprIndex;
187 			_spriteRefs[sprIndex]++;
188 		} else {
189 			for (sprIndex = 19; _vm->_draw->_spritesArray[sprIndex] != 0; sprIndex--) { }
190 
191 			_staticPictToSprite[7 * sceneryIndex + i] = sprIndex;
192 			_spriteRefs[sprIndex] = 1;
193 			_spriteResId[sprIndex] = sprResId;
194 			_vm->_draw->initSpriteSurf(sprIndex, width, height, 2);
195 
196 			_vm->_draw->_spritesArray[sprIndex]->clear();
197 			_vm->_draw->_destSurface  = sprIndex;
198 			_vm->_draw->_spriteLeft   = sprResId;
199 			_vm->_draw->_transparency = 0;
200 			_vm->_draw->_destSpriteX  = 0;
201 			_vm->_draw->_destSpriteY  = 0;
202 			_vm->_draw->spriteOperation(DRAW_LOADSPRITE);
203 		}
204 	}
205 
206 	delete resource;
207 	return sceneryIndex + 100;
208 }
209 
freeStatic(int16 index)210 void Scenery::freeStatic(int16 index) {
211 	int16 spr;
212 
213 	if (index == -1)
214 		_vm->_game->_script->evalExpr(&index);
215 
216 	if (_staticPictCount[index] == -1)
217 		return;
218 
219 	for (int i = 0; i < _staticPictCount[index]; i++) {
220 		delete[] _statics[index].pieces[i];
221 
222 		spr = _staticPictToSprite[index * 7 + i];
223 		_spriteRefs[spr]--;
224 		if (_spriteRefs[spr] == 0) {
225 			_vm->_draw->freeSprite(spr);
226 			_spriteResId[spr] = -1;
227 		}
228 	}
229 
230 	for (int i = 0; i < _statics[index].layersCount; i++)
231 		delete[] _statics[index].layers[i].planes;
232 
233 	delete[] _statics[index].layers;
234 	delete[] _statics[index].pieces;
235 	delete[] _statics[index].piecesCount;
236 
237 	_statics[index].layersCount = 0;
238 	_staticPictCount[index]     = -1;
239 }
240 
renderStatic(int16 scenery,int16 layer)241 void Scenery::renderStatic(int16 scenery, int16 layer) {
242 	Static *ptr;
243 	StaticLayer *layerPtr;
244 	StaticPlane *planePtr;
245 	int16 planeCount;
246 	int16 order;
247 	int16 plane;
248 
249 	uint16 pieceIndex;
250 	uint16 pictIndex;
251 
252 	int16 left;
253 	int16 right;
254 	int16 top;
255 	int16 bottom;
256 
257 	ptr = &_statics[scenery];
258 	if (layer >= ptr->layersCount)
259 		return;
260 
261 	layerPtr = &ptr->layers[layer];
262 
263 	_vm->_draw->_spriteLeft = layerPtr->backResId;
264 	if (_vm->_draw->_spriteLeft != -1) {
265 		_vm->_draw->_destSpriteX  = 0;
266 		_vm->_draw->_destSpriteY  = 0;
267 		_vm->_draw->_destSurface  = Draw::kBackSurface;
268 		_vm->_draw->_transparency = 0;
269 		_vm->_draw->spriteOperation(DRAW_LOADSPRITE);
270 	}
271 
272 	planeCount = layerPtr->planeCount;
273 	for (order = 0; order < 100; order++) {
274 		for (plane = 0, planePtr = layerPtr->planes; plane < planeCount; plane++, planePtr++) {
275 			if (planePtr->drawOrder != order)
276 				continue;
277 
278 			pieceIndex = planePtr->pieceIndex;
279 			pictIndex  = planePtr->pictIndex - 1;
280 
281 			if (pictIndex >= _staticPictCount[scenery])
282 				continue;
283 
284 			if (!ptr->pieces || !ptr->pieces[pictIndex])
285 				continue;
286 
287 			if (pieceIndex >= ptr->piecesCount[pictIndex])
288 				continue;
289 
290 			_vm->_draw->_destSpriteX = planePtr->destX;
291 			_vm->_draw->_destSpriteY = planePtr->destY;
292 			left   = ptr->pieces[pictIndex][pieceIndex].left;
293 			right  = ptr->pieces[pictIndex][pieceIndex].right;
294 			top    = ptr->pieces[pictIndex][pieceIndex].top;
295 			bottom = ptr->pieces[pictIndex][pieceIndex].bottom;
296 
297 			_vm->_draw->_sourceSurface =
298 			    _staticPictToSprite[scenery * 7 + pictIndex];
299 			_vm->_draw->_destSurface   = Draw::kBackSurface;
300 			_vm->_draw->_spriteLeft    = left;
301 			_vm->_draw->_spriteTop     = top;
302 			_vm->_draw->_spriteRight   = right - left + 1;
303 			_vm->_draw->_spriteBottom  = bottom - top + 1;
304 			_vm->_draw->_transparency  = planePtr->transp ? 3 : 0;
305 			_vm->_draw->spriteOperation(DRAW_BLITSURF);
306 		}
307 	}
308 }
309 
updateStatic(int16 orderFrom,byte index,byte layer)310 void Scenery::updateStatic(int16 orderFrom, byte index, byte layer) {
311 	StaticLayer *layerPtr;
312 	PieceDesc **pictPtr;
313 	StaticPlane *planePtr;
314 	int16 planeCount;
315 	int16 order;
316 	int16 plane;
317 	uint16 pieceIndex;
318 	uint16 pictIndex;
319 
320 	int16 left;
321 	int16 right;
322 	int16 top;
323 	int16 bottom;
324 
325 	if ((index >= 10) || layer >= _statics[index].layersCount)
326 		return;
327 
328 	layerPtr = &_statics[index].layers[layer];
329 	pictPtr = _statics[index].pieces;
330 
331 	planeCount = layerPtr->planeCount;
332 
333 	for (order = orderFrom; order < 100; order++) {
334 		for (planePtr = layerPtr->planes, plane = 0;
335 		    plane < planeCount; plane++, planePtr++) {
336 			if (planePtr->drawOrder != order)
337 				continue;
338 
339 			pieceIndex = planePtr->pieceIndex;
340 			pictIndex  = planePtr->pictIndex - 1;
341 
342 			if (pictIndex >= _staticPictCount[index])
343 				continue;
344 
345 			if (!pictPtr || !pictPtr[pictIndex])
346 				continue;
347 
348 			if (pieceIndex >= _statics[index].piecesCount[pictIndex])
349 				continue;
350 
351 			_vm->_draw->_destSpriteX = planePtr->destX;
352 			_vm->_draw->_destSpriteY = planePtr->destY;
353 
354 			left   = pictPtr[pictIndex][pieceIndex].left;
355 			right  = pictPtr[pictIndex][pieceIndex].right;
356 			top    = pictPtr[pictIndex][pieceIndex].top;
357 			bottom = pictPtr[pictIndex][pieceIndex].bottom;
358 
359 			if (_vm->_draw->_destSpriteX > _toRedrawRight)
360 				continue;
361 
362 			if (_vm->_draw->_destSpriteY > _toRedrawBottom)
363 				continue;
364 
365 			if (_vm->_draw->_destSpriteX < _toRedrawLeft) {
366 				left += _toRedrawLeft - _vm->_draw->_destSpriteX;
367 				_vm->_draw->_destSpriteX = _toRedrawLeft;
368 			}
369 
370 			if (_vm->_draw->_destSpriteY < _toRedrawTop) {
371 				top += _toRedrawTop - _vm->_draw->_destSpriteY;
372 				_vm->_draw->_destSpriteY = _toRedrawTop;
373 			}
374 
375 			_vm->_draw->_spriteLeft   = left;
376 			_vm->_draw->_spriteTop    = top;
377 			_vm->_draw->_spriteRight  = right  - left + 1;
378 			_vm->_draw->_spriteBottom = bottom - top  + 1;
379 
380 			if ((_vm->_draw->_spriteRight <= 0) ||
381 			    (_vm->_draw->_spriteBottom <= 0))
382 				continue;
383 
384 			if ((_vm->_draw->_destSpriteX + _vm->_draw->_spriteRight - 1) >
385 			    _toRedrawRight)
386 				_vm->_draw->_spriteRight =
387 				    _toRedrawRight - _vm->_draw->_destSpriteX + 1;
388 
389 			if ((_vm->_draw->_destSpriteY + _vm->_draw->_spriteBottom - 1) >
390 			    _toRedrawBottom)
391 				_vm->_draw->_spriteBottom =
392 				    _toRedrawBottom - _vm->_draw->_destSpriteY + 1;
393 
394 			_vm->_draw->_sourceSurface =
395 			    _staticPictToSprite[index * 7 + pictIndex];
396 			_vm->_draw->_destSurface   = Draw::kBackSurface;
397 			_vm->_draw->_transparency  = planePtr->transp ? 3 : 0;
398 			_vm->_draw->spriteOperation(DRAW_BLITSURF);
399 		}
400 	}
401 }
402 
updateStatic(int16 orderFrom)403 void Scenery::updateStatic(int16 orderFrom) {
404 	if (_curStatic == -1)
405 		return;
406 
407 	if (_curStatic < 10000) {
408 		updateStatic(orderFrom, _curStatic & 0xFF, _curStaticLayer & 0xFF);
409 
410 		if (_curStatic & 0xFF00)
411 			updateStatic(orderFrom, ((_curStatic >> 8) & 0xFF) - 1,
412 					(_curStaticLayer >> 8) & 0xFF);
413 	} else
414 		for (int i = 0; i < (_curStatic - 10000); i++)
415 			updateStatic(orderFrom, i, 0);
416 }
417 
loadAnim(char search)418 int16 Scenery::loadAnim(char search) {
419 	int16 picsCount;
420 	int16 resId;
421 	int16 i;
422 	int16 j;
423 	int16 sceneryIndex;
424 	int16 framesCount;
425 	Animation *ptr;
426 	int16 width;
427 	int16 height;
428 	int16 sprResId;
429 	int16 sprIndex;
430 	uint32 layerPos;
431 
432 	_vm->_game->_script->evalExpr(&sceneryIndex);
433 	picsCount = _vm->_game->_script->readInt16();
434 	resId = _vm->_game->_script->readInt16();
435 
436 	if (search) {
437 		for (i = 0; i < 10; i++) {
438 			if ((_animPictCount[i] != 0) && (_animResId[i] == resId)) {
439 				_vm->_game->_script->skip(8 * _animPictCount[i]);
440 				return i;
441 			}
442 
443 			if ((_animPictCount[i] == 0) && (i < sceneryIndex))
444 				sceneryIndex = i;
445 		}
446 	}
447 
448 	_animPictCount[sceneryIndex] = picsCount;
449 	_animResId[sceneryIndex] = resId;
450 
451 	Resource *resource = _vm->_game->_resources->getResource((uint16) resId);
452 	if (!resource)
453 		return 0;
454 
455 	ptr = &_animations[sceneryIndex];
456 
457 	ptr->layersCount = resource->stream()->readSint16LE();
458 
459 	ptr->layers = new AnimLayer[ptr->layersCount];
460 
461 	for (i = 0; i < ptr->layersCount; i++) {
462 		Common::SeekableReadStream &layerData = *resource->stream();
463 
464 		layerData.seek(2 + i * 2);
465 		layerData.seek(layerData.readUint16LE());
466 
467 		ptr->layers[i].unknown0    = layerData.readSint16LE();
468 		ptr->layers[i].posX        = layerData.readSint16LE();
469 		ptr->layers[i].posY        = layerData.readSint16LE();
470 		ptr->layers[i].animDeltaX  = layerData.readSint16LE();
471 		ptr->layers[i].animDeltaY  = layerData.readSint16LE();
472 		ptr->layers[i].transp      = layerData.readSByte();
473 		ptr->layers[i].framesCount = layerData.readSint16LE();
474 
475 		// Going through the AnimFramePiece, finding the end for each
476 		layerPos = layerData.pos();
477 		framesCount = 0;
478 		for (j = 0; j < ptr->layers[i].framesCount; j++) {
479 			layerData.skip(4); // pictIndex, pieceIndex, destX, destY
480 			while (layerData.readByte() == 1) {
481 				framesCount++;
482 				layerData.skip(4); // pictIndex, pieceIndex, destX, destY
483 			}
484 			framesCount++;
485 		}
486 		layerData.seek(layerPos);
487 
488 		ptr->layers[i].frames = new AnimFramePiece[framesCount];
489 		for (j = 0; j < framesCount; j++) {
490 			ptr->layers[i].frames[j].pictIndex  = layerData.readByte();
491 			ptr->layers[i].frames[j].pieceIndex = layerData.readByte();
492 			ptr->layers[i].frames[j].destX      = layerData.readSByte();
493 			ptr->layers[i].frames[j].destY      = layerData.readSByte();
494 			ptr->layers[i].frames[j].notFinal   = layerData.readSByte();
495 		}
496 	}
497 
498 	ptr->pieces = new PieceDesc*[picsCount];
499 	ptr->piecesCount = new uint32[picsCount];
500 
501 	for (i = 0; i < picsCount; i++) {
502 		int16 pictDescId = _vm->_game->_script->readInt16();
503 
504 		loadPieces(pictDescId, ptr->pieces[i], ptr->piecesCount[i]);
505 
506 		width    = _vm->_game->_script->readInt16();
507 		height   = _vm->_game->_script->readInt16();
508 		sprResId = _vm->_game->_script->readInt16();
509 		for (sprIndex = 0; sprIndex < 20; sprIndex++)
510 			if (_spriteResId[sprIndex] == sprResId)
511 				break;
512 
513 		if (sprIndex < 20) {
514 			_animPictToSprite[7 * sceneryIndex + i] = sprIndex;
515 			_spriteRefs[sprIndex]++;
516 		} else {
517 			for (sprIndex = 19; _vm->_draw->_spritesArray[sprIndex];
518 				sprIndex--)
519 				;
520 
521 			_animPictToSprite[7 * sceneryIndex + i] = sprIndex;
522 			_spriteRefs[sprIndex]  = 1;
523 			_spriteResId[sprIndex] = sprResId;
524 			_vm->_draw->initSpriteSurf(sprIndex, width, height, 2);
525 
526 			_vm->_draw->_spritesArray[sprIndex]->clear();
527 			_vm->_draw->_destSurface  = sprIndex;
528 			_vm->_draw->_spriteLeft   = sprResId;
529 			_vm->_draw->_transparency = 0;
530 			_vm->_draw->_destSpriteX  = 0;
531 			_vm->_draw->_destSpriteY  = 0;
532 			_vm->_draw->spriteOperation(DRAW_LOADSPRITE);
533 		}
534 	}
535 
536 	delete resource;
537 	return sceneryIndex + 100;
538 }
539 
freeAnim(int16 index)540 void Scenery::freeAnim(int16 index) {
541 	int16 spr;
542 
543 	if (index == -1)
544 		_vm->_game->_script->evalExpr(&index);
545 
546 	if (_animPictCount[index] == 0)
547 		return;
548 
549 	for (int i = 0; i < _animPictCount[index]; i++) {
550 		delete[] _animations[index].pieces[i];
551 
552 		spr = _animPictToSprite[index * 7 + i];
553 		_spriteRefs[spr]--;
554 		if (_spriteRefs[spr] == 0) {
555 			_vm->_draw->freeSprite(spr);
556 			_spriteResId[spr] = -1;
557 		}
558 	}
559 
560 	for (int i = 0; i < _animations[index].layersCount; i++)
561 		delete[] _animations[index].layers[i].frames;
562 
563 	delete[] _animations[index].layers;
564 	delete[] _animations[index].pieces;
565 	delete[] _animations[index].piecesCount;
566 
567 	_animPictCount[index] = 0;
568 }
569 
570 // flags & 1 - do capture all area animation is occupying
571 // flags & 4 == 0 - calculate animation final size
572 // flags & 2 != 0 - don't check with "toRedraw"'s
573 // flags & 4 != 0 - checkk view toRedraw
updateAnim(int16 layer,int16 frame,int16 animation,int16 flags,int16 drawDeltaX,int16 drawDeltaY,char doDraw)574 void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags,
575 	    int16 drawDeltaX, int16 drawDeltaY, char doDraw) {
576 	AnimLayer *layerPtr;
577 	PieceDesc **pictPtr;
578 	AnimFramePiece *framePtr;
579 
580 	uint16 pieceIndex;
581 	uint16 pictIndex;
582 
583 	int16 left;
584 	int16 right;
585 	int16 top;
586 	int16 bottom;
587 
588 	byte highX;
589 	byte highY;
590 
591 	int16 i;
592 	int16 transp;
593 
594 	int16 destX;
595 	int16 destY;
596 
597 	if ((animation < 0) &&
598 	    ((_vm->getGameType() == kGameTypeWoodruff) ||
599 	     (_vm->getGameType() == kGameTypeAdibou2))) {
600 		// Object video
601 
602 		if (flags & 1) { // Do capture
603 			updateAnim(layer, frame, animation, 0, drawDeltaX, drawDeltaY, 0);
604 
605 			if (_toRedrawLeft == -12345)
606 				return;
607 
608 			_vm->_game->capturePush(_toRedrawLeft, _toRedrawTop,
609 					_toRedrawRight  - _toRedrawLeft + 1,
610 					_toRedrawBottom - _toRedrawTop  + 1);
611 
612 			*_pCaptureCounter = *_pCaptureCounter + 1;
613 		}
614 
615 		Mult::Mult_Object &obj = _vm->_mult->_objects[-animation - 1];
616 
617 		if ((obj.videoSlot == 0) || !_vm->_vidPlayer->slotIsOpen(obj.videoSlot - 1)) {
618 			_toRedrawLeft = -12345;
619 			return;
620 		}
621 
622 		if (frame >= (int32)_vm->_vidPlayer->getFrameCount(obj.videoSlot - 1))
623 			frame = _vm->_vidPlayer->getFrameCount(obj.videoSlot - 1) - 1;
624 
625 		if ((int32)_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) >= 255) {
626 			// Allow for object videos with more than 255 frames, although the
627 			// object frame counter is just a byte.
628 
629 			uint32 curFrame  = _vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) + 1;
630 			uint16 frameWrap = curFrame / 256;
631 
632 			frame = ((frame + 1) % 256) + frameWrap * 256;
633 		}
634 
635 		if (frame != (int32)_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1)) {
636 			// Seek to frame
637 
638 			VideoPlayer::Properties props;
639 
640 			props.forceSeek    = true;
641 			props.waitEndFrame = false;
642 			props.lastFrame    = frame;
643 
644 			if ((int32)_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) < frame)
645 				props.startFrame = _vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) + 1;
646 			else
647 				props.startFrame = frame;
648 
649 			_vm->_vidPlayer->play(obj.videoSlot - 1, props);
650 		}
651 
652 		int32 subtitle = _vm->_vidPlayer->getSubtitleIndex(obj.videoSlot - 1);
653 		if (subtitle != -1)
654 			_vm->_draw->printTotText(subtitle);
655 
656 		destX  = 0;
657 		destY  = 0;
658 		left   = *(obj.pPosX);
659 		top    = *(obj.pPosY);
660 		right  = left + _vm->_vidPlayer->getWidth(obj.videoSlot  - 1) - 1;
661 		bottom = top  + _vm->_vidPlayer->getHeight(obj.videoSlot - 1) - 1;
662 
663 		if (flags & 2) {
664 			if (left < _vm->_mult->_animLeft) {
665 				destX += _vm->_mult->_animLeft - left;
666 				left   = _vm->_mult->_animLeft;
667 			}
668 
669 			if ((_vm->_mult->_animLeft + _vm->_mult->_animWidth) <= right)
670 				right = _vm->_mult->_animLeft + _vm->_mult->_animWidth - 1;
671 
672 			if (top < _vm->_mult->_animTop) {
673 				destY += _vm->_mult->_animTop - top;
674 				top    = _vm->_mult->_animTop;
675 			}
676 
677 			if ((_vm->_mult->_animTop + _vm->_mult->_animHeight) <= bottom)
678 				bottom = _vm->_mult->_animTop + _vm->_mult->_animHeight - 1;
679 
680 		} else if (flags & 4) {
681 			if (left < _toRedrawLeft) {
682 				destX += _toRedrawLeft - left;
683 				left   = _toRedrawLeft;
684 			}
685 
686 			if (right > _toRedrawRight)
687 				right = _toRedrawRight;
688 
689 			if (top < _toRedrawTop) {
690 				destY += _toRedrawTop - top;
691 				top    = _toRedrawTop;
692 			}
693 
694 			if (bottom > _toRedrawBottom)
695 				bottom = _toRedrawBottom;
696 
697 		} else {
698 			_toRedrawTop    = top;
699 			_toRedrawLeft   = left;
700 			_toRedrawRight  = right;
701 			_toRedrawBottom = bottom;
702 		}
703 
704 		if (doDraw) {
705 			if ((left > right) || (top > bottom))
706 				return;
707 
708 			if (left < _vm->_mult->_animLeft) {
709 				destX += _vm->_mult->_animLeft - left;
710 				left   = _vm->_mult->_animLeft;
711 			}
712 
713 			if ((_vm->_mult->_animLeft + _vm->_mult->_animWidth) <= right)
714 				right = _vm->_mult->_animLeft + _vm->_mult->_animWidth - 1;
715 
716 			if (top < _vm->_mult->_animTop) {
717 				destY += _vm->_mult->_animTop - top;
718 				top    = _vm->_mult->_animTop;
719 			}
720 
721 			if ((_vm->_mult->_animTop + _vm->_mult->_animHeight) <= bottom)
722 				bottom = _vm->_mult->_animTop + _vm->_mult->_animHeight - 1;
723 
724 			_vm->_draw->_spriteLeft   = destX;
725 			_vm->_draw->_spriteTop    = destY;
726 			_vm->_draw->_spriteRight  = right  - left + 1;
727 			_vm->_draw->_spriteBottom = bottom - top  + 1;
728 			_vm->_draw->_destSpriteX  = left;
729 			_vm->_draw->_destSpriteY  = top;
730 			_vm->_draw->_transparency = layer;
731 			if (layer & 0x80)
732 				_vm->_draw->_spriteLeft = _vm->_vidPlayer->getWidth(obj.videoSlot - 1)  -
733 					(destX + _vm->_draw->_spriteRight);
734 
735 			_vm->_vidPlayer->copyFrame(obj.videoSlot - 1, *_vm->_draw->_backSurface,
736 					_vm->_draw->_spriteLeft,  _vm->_draw->_spriteTop,
737 					_vm->_draw->_spriteRight, _vm->_draw->_spriteBottom,
738 					_vm->_draw->_destSpriteX, _vm->_draw->_destSpriteY,
739 					(_vm->_draw->_transparency != 0) ? 0 : -1);
740 
741 			_vm->_draw->invalidateRect(_vm->_draw->_destSpriteX, _vm->_draw->_destSpriteY,
742 					_vm->_draw->_destSpriteX + _vm->_draw->_spriteRight  - 1,
743 					_vm->_draw->_destSpriteY + _vm->_draw->_spriteBottom - 1);
744 		}
745 
746 		if (!(flags & 4)) {
747 			_animLeft   = _toRedrawLeft   = left;
748 			_animTop    = _toRedrawTop    = top;
749 			_animRight  = _toRedrawRight  = right;
750 			_animBottom = _toRedrawBottom = bottom;
751 		}
752 
753 		return;
754 	}
755 
756 	if ((animation < 0) || (animation >= 10))
757 		return;
758 	if ((_animPictCount[animation] == 0) || (layer < 0))
759 		return;
760 	if (layer >= _animations[animation].layersCount)
761 		return;
762 
763 	layerPtr = &_animations[animation].layers[layer];
764 
765 	if (frame >= layerPtr->framesCount)
766 		return;
767 
768 	if (flags & 1) { // Do capture
769 		updateAnim(layer, frame, animation, 0, drawDeltaX, drawDeltaY, 0);
770 
771 		if (_toRedrawLeft == -12345)
772 			return;
773 
774 		_vm->_game->capturePush(_toRedrawLeft, _toRedrawTop,
775 		    _toRedrawRight  - _toRedrawLeft + 1,
776 		    _toRedrawBottom - _toRedrawTop  + 1);
777 
778 		*_pCaptureCounter = *_pCaptureCounter + 1;
779 	}
780 
781 	pictPtr  = _animations[animation].pieces;
782 	framePtr = layerPtr->frames;
783 
784 	for (i = 0; i < frame; i++, framePtr++)
785 		while (framePtr->notFinal == 1)
786 			framePtr++;
787 
788 	if (flags & 4) {
789 		_toRedrawLeft   = MAX(_toRedrawLeft, _vm->_mult->_animLeft);
790 		_toRedrawTop    = MAX(_toRedrawTop, _vm->_mult->_animTop);
791 		_toRedrawRight  = MIN(_toRedrawRight,
792 		    (int16)(_vm->_mult->_animLeft + _vm->_mult->_animWidth - 1));
793 		_toRedrawBottom = MIN(_toRedrawBottom,
794 		    (int16)(_vm->_mult->_animTop + _vm->_mult->_animHeight - 1));
795 	} else
796 		_toRedrawLeft = -12345;
797 
798 	transp = layerPtr->transp ? 3 : 0;
799 
800 	framePtr--;
801 	do {
802 		framePtr++;
803 
804 		pieceIndex = framePtr->pieceIndex;
805 		pictIndex = framePtr->pictIndex;
806 
807 		destX = framePtr->destX;
808 		destY = framePtr->destY;
809 
810 		highX = pictIndex & 0xC0;
811 		highY = pictIndex & 0x30;
812 		highX >>= 6;
813 		highY >>= 4;
814 		if (destX >= 0)
815 			destX += ((uint16)highX) << 7;
816 		else
817 			destX -= ((uint16)highX) << 7;
818 
819 		if (destY >= 0)
820 			destY += ((uint16)highY) << 7;
821 		else
822 			destY -= ((uint16)highY) << 7;
823 
824 		if (drawDeltaX == 1000)
825 			destX += layerPtr->posX;
826 		else
827 			destX += drawDeltaX;
828 
829 		if (drawDeltaY == 1000)
830 			destY += layerPtr->posY;
831 		else
832 			destY += drawDeltaY;
833 
834 		pictIndex = (pictIndex & 15) - 1;
835 
836 		if (pictIndex >= _animPictCount[animation])
837 			continue;
838 
839 		if (!pictPtr[pictIndex])
840 			continue;
841 
842 		if (pieceIndex >= _animations[animation].piecesCount[pictIndex])
843 			continue;
844 
845 		left = pictPtr[pictIndex][pieceIndex].left;
846 		right = pictPtr[pictIndex][pieceIndex].right;
847 		top = pictPtr[pictIndex][pieceIndex].top;
848 		bottom = pictPtr[pictIndex][pieceIndex].bottom;
849 
850 		if (flags & 2) {
851 			if (destX < _vm->_mult->_animLeft) {
852 				left += _vm->_mult->_animLeft - destX;
853 				destX = _vm->_mult->_animLeft;
854 			}
855 
856 			if ((left <= right) && ((destX + right - left) >=
857 			    (_vm->_mult->_animLeft + _vm->_mult->_animWidth)))
858 				right -= (destX + right - left) -
859 					(_vm->_mult->_animLeft + _vm->_mult->_animWidth) + 1;
860 
861 			if (destY < _vm->_mult->_animTop) {
862 				top  += _vm->_mult->_animTop - destY;
863 				destY = _vm->_mult->_animTop;
864 			}
865 
866 			if ((top <= bottom) && ((destY + bottom - top) >=
867 						(_vm->_mult->_animTop + _vm->_mult->_animHeight)))
868 				bottom -= (destY + bottom - top) -
869 					(_vm->_mult->_animTop + _vm->_mult->_animHeight) + 1;
870 
871 		} else if (flags & 4) {
872 			if (destX < _toRedrawLeft) {
873 				left += _toRedrawLeft - destX;
874 				destX = _toRedrawLeft;
875 			}
876 
877 			if ((left <= right) && ((destX + right - left) > _toRedrawRight))
878 				right -= destX + right - left - _toRedrawRight;
879 
880 			if (destY < _toRedrawTop) {
881 				top  += _toRedrawTop - destY;
882 				destY = _toRedrawTop;
883 			}
884 
885 			if ((top <= bottom) && ((destY + bottom - top) > _toRedrawBottom))
886 				bottom -= destY + bottom - top - _toRedrawBottom;
887 		}
888 
889 		if ((left > right) || (top > bottom))
890 			continue;
891 
892 		if (doDraw) {
893 			_vm->_draw->_sourceSurface =
894 			    _animPictToSprite[animation * 7 + pictIndex];
895 			_vm->_draw->_destSurface   = Draw::kBackSurface;
896 
897 			_vm->_draw->_spriteLeft   = left;
898 			_vm->_draw->_spriteTop    = top;
899 			_vm->_draw->_spriteRight  = right - left + 1;
900 			_vm->_draw->_spriteBottom = bottom - top + 1;
901 			_vm->_draw->_destSpriteX  = destX;
902 			_vm->_draw->_destSpriteY  = destY;
903 			_vm->_draw->_transparency = transp;
904 			_vm->_draw->spriteOperation(DRAW_BLITSURF);
905 		}
906 
907 		if (!(flags & 4)) {
908 			if (_toRedrawLeft == -12345) {
909 				_toRedrawLeft   = destX;
910 				_animLeft       = destX;
911 				_toRedrawTop    = destY;
912 				_animTop        = destY;
913 				_toRedrawRight  = destX + right  - left;
914 				_animRight      = destX + right  - left;
915 				_toRedrawBottom = destY + bottom - top;
916 				_animBottom     = destY + bottom - top;
917 			} else {
918 				_toRedrawLeft   = MIN(_toRedrawLeft, destX);
919 				_toRedrawTop    = MIN(_toRedrawTop, destY);
920 				_toRedrawRight  =
921 					MAX(_toRedrawRight,  (int16)(destX + right - left));
922 				_toRedrawBottom =
923 					MAX(_toRedrawBottom, (int16)(destY + bottom - top));
924 			}
925 		}
926 
927 	} while (framePtr->notFinal == 1);
928 }
929 
writeAnimLayerInfo(uint16 index,uint16 layer,int16 varDX,int16 varDY,int16 varUnk0,int16 varFrames)930 void Scenery::writeAnimLayerInfo(uint16 index, uint16 layer,
931 		int16 varDX, int16 varDY, int16 varUnk0, int16 varFrames) {
932 
933 	assert(index < 10);
934 
935 // WORKAROUND - Fascination Hebrew is using scripts from the CD versions, but of course
936 // no CD track, so the anim syncing failed, and the anims were suppressed. But they
937 // didn't updated the scripts. Skipping the wrong anims is a solution.
938 	if ((_vm->getGameType() == kGameTypeFascination) && (layer >= _animations[index].layersCount)) {
939 		WRITE_VAR_OFFSET(varDX, 0);
940 		WRITE_VAR_OFFSET(varDY, 0);
941 		WRITE_VAR_OFFSET(varUnk0, 0);
942 		WRITE_VAR_OFFSET(varFrames, 0);
943 	} else {
944 		assert(layer < _animations[index].layersCount);
945 
946 		AnimLayer &animLayer = _animations[index].layers[layer];
947 		WRITE_VAR_OFFSET(varDX, animLayer.animDeltaX);
948 		WRITE_VAR_OFFSET(varDY, animLayer.animDeltaY);
949 		WRITE_VAR_OFFSET(varUnk0, animLayer.unknown0);
950 		WRITE_VAR_OFFSET(varFrames, animLayer.framesCount);
951 	}
952 }
953 
getStaticLayersCount(uint16 index)954 int16 Scenery::getStaticLayersCount(uint16 index) {
955 	assert(index < 10);
956 
957 	return _statics[index].layersCount;
958 }
959 
getAnimLayersCount(uint16 index)960 int16 Scenery::getAnimLayersCount(uint16 index) {
961 	assert(index < 10);
962 
963 	return _animations[index].layersCount;
964 }
965 
getStaticLayer(uint16 index,uint16 layer)966 Scenery::StaticLayer *Scenery::getStaticLayer(uint16 index, uint16 layer) {
967 	assert(index < 10);
968 	assert(layer < _statics[index].layersCount);
969 
970 	return &_statics[index].layers[layer];
971 }
972 
getAnimLayer(uint16 index,uint16 layer)973 Scenery::AnimLayer *Scenery::getAnimLayer(uint16 index, uint16 layer) {
974 	assert(index < 10);
975 	assert(layer < _animations[index].layersCount);
976 
977 	return &_animations[index].layers[layer];
978 }
979 
loadPieces(int16 pictDescId,PieceDesc * & pieceDesc,uint32 & piecesCount)980 void Scenery::loadPieces(int16 pictDescId, PieceDesc *&pieceDesc, uint32 &piecesCount) {
981 	Resource *resource = _vm->_game->_resources->getResource(pictDescId);
982 	if (!resource) {
983 		warning("Scenery::loadPieces(): Can't load %d", pictDescId);
984 		return;
985 	}
986 
987 	piecesCount = resource->getSize() / 8;
988 	pieceDesc = new PieceDesc[piecesCount];
989 
990 	for (uint32 i = 0; i < piecesCount; i++) {
991 		pieceDesc[i].left   = resource->stream()->readSint16LE();
992 		pieceDesc[i].right  = resource->stream()->readSint16LE();
993 		pieceDesc[i].top    = resource->stream()->readSint16LE();
994 		pieceDesc[i].bottom = resource->stream()->readSint16LE();
995 	}
996 
997 	delete resource;
998 }
999 
1000 } // End of namespace Gob
1001