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/scummsys.h"
24 #include "access/access.h"
25 #include "access/resources.h"
26 #include "access/screen.h"
27 #include "access/amazon/amazon_game.h"
28 #include "access/amazon/amazon_logic.h"
29 #include "access/amazon/amazon_resources.h"
30 
31 namespace Access {
32 
33 namespace Amazon {
34 
PannedScene(AmazonEngine * vm)35 PannedScene::PannedScene(AmazonEngine *vm) : AmazonManager(vm) {
36 	for (int i = 0; i < PAN_SIZE; ++i) {
37 		_pan[i]._pObject = nullptr;
38 		_pan[i]._pImgNum = 0;
39 		_pan[i]._pObjX = _pan[i]._pObjY = _pan[i]._pObjZ = 0;
40 		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
41 	}
42 
43 	_xCount = 0;
44 	_xTrack = _yTrack = _zTrack = 0;
45 	_xCam = _yCam = _zCam = 0;
46 	_pNumObj = 0;
47 }
48 
pan()49 void PannedScene::pan() {
50 	_zCam += _zTrack;
51 	_xCam += _xTrack;
52 	int tx = (_xTrack << 8) / _zCam;
53 	_yCam += _yTrack;
54 	int ty = (_yTrack << 8) / _zCam;
55 
56 	if (_vm->_timers[24]._flag != 1) {
57 		++_vm->_timers[24]._flag;
58 		for (int i = 0; i < _pNumObj; i++) {
59 			_pan[i]._pObjZ += _zTrack;
60 			_pan[i]._pObjXl += (_pan[i]._pObjZ * tx) & 0xff;
61 			_pan[i]._pObjX += ((_pan[i]._pObjZ * tx) >> 8) + (_pan[i]._pObjXl >> 8);
62 			_pan[i]._pObjXl &= 0xff;
63 
64 			_pan[i]._pObjYl += (_pan[i]._pObjZ * ty) & 0xff;
65 			_pan[i]._pObjY += ((_pan[i]._pObjZ * ty) >> 8) + (_pan[i]._pObjYl >> 8);
66 			_pan[i]._pObjYl &= 0xff;
67 		}
68 	}
69 
70 	for (int i = 0; i < _pNumObj; i++) {
71 		ImageEntry ie;
72 		ie._flags = IMGFLAG_UNSCALED;
73 		ie._position = Common::Point(_pan[i]._pObjX, _pan[i]._pObjY);
74 		ie._offsetY = 255;
75 		ie._spritesPtr = _pan[i]._pObject;
76 		ie._frameNumber = _pan[i]._pImgNum;
77 
78 		_vm->_images.addToList(ie);
79 	}
80 }
81 
82 /*------------------------------------------------------------------------*/
83 
CampScene(AmazonEngine * vm)84 CampScene::CampScene(AmazonEngine *vm) : PannedScene(vm) {
85 	_skipStart = false;
86 }
87 
mWhileDoOpen()88 void CampScene::mWhileDoOpen() {
89 	Screen &screen = *_vm->_screen;
90 	EventsManager &events = *_vm->_events;
91 
92 	screen.setDisplayScan();
93 	events.hideCursor();
94 	screen.forceFadeOut();
95 	_skipStart = false;
96 	if (_vm->_conversation != 2) {
97 		// Cutscene at start of chapter 1
98 		screen.setPanel(3);
99 		_vm->startChapter(1);
100 		_vm->establishCenter(0, 1);
101 	}
102 
103 	Resource *data = _vm->_files->loadFile(1, 0);
104 	_vm->_objectsTable[1] = new SpriteResource(_vm, data);
105 	delete data;
106 
107 	_vm->_files->_setPaletteFlag = false;
108 	_vm->_files->loadScreen(1, 2);
109 	_vm->_buffer2.blitFrom(*_vm->_screen);
110 	_vm->_buffer1.blitFrom(*_vm->_screen);
111 
112 	// Load animation data
113 	_vm->_animation->freeAnimationData();
114 	Resource *animResource = _vm->_files->loadFile(1, 1);
115 	_vm->_animation->loadAnimations(animResource);
116 	delete animResource;
117 
118 	_xTrack = 8;
119 	_yTrack = -3;
120 	_zTrack = 0;
121 	_xCam = _yCam = 0;
122 	_zCam = 270;
123 	_vm->_timers[24]._timer = _vm->_timers[24]._initTm = 1;
124 	++_vm->_timers[24]._flag;
125 	_vm->_timers.updateTimers();
126 
127 	_pNumObj = 10;
128 	for (int i = 0; i < _pNumObj; i++) {
129 		_pan[i]._pObject = _vm->_objectsTable[1];
130 		_pan[i]._pImgNum = OPENING_OBJS[i][0];
131 		_pan[i]._pObjX = OPENING_OBJS[i][1];
132 		_pan[i]._pObjY = OPENING_OBJS[i][2];
133 		_pan[i]._pObjZ = OPENING_OBJS[i][3];
134 		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
135 	}
136 
137 	_vm->_oldRects.clear();
138 	_vm->_newRects.clear();
139 	Animation *anim = _vm->_animation->setAnimation(0);
140 	_vm->_animation->setAnimTimer(anim);
141 	anim = _vm->_animation->setAnimation(1);
142 	_vm->_animation->setAnimTimer(anim);
143 	_vm->_midi->newMusic(10, 0);
144 
145 	bool startFl = false;
146 	while (!_vm->shouldQuit()) {
147 		_vm->_images.clear();
148 		_vm->_animation->animate(0);
149 		_vm->_animation->animate(1);
150 		pan();
151 		_vm->_buffer2.copyFrom(_vm->_buffer1);
152 		_vm->_newRects.clear();
153 		_vm->plotList();
154 		_vm->copyBlocks();
155 		if (!startFl) {
156 			startFl = true;
157 			screen.forceFadeIn();
158 		}
159 
160 		events.pollEventsAndWait();
161 
162 		if (_vm->_events->isKeyMousePressed()) {
163 			_skipStart = true;
164 			_vm->_midi->newMusic(10, 1);
165 			break;
166 		}
167 
168 		if (_xCam > 680) {
169 			events._vbCount = 125;
170 
171 			while (!_vm->shouldQuit() && !events.isKeyMousePressed() && events._vbCount > 0) {
172 				events.pollEventsAndWait();
173 			}
174 			break;
175 		}
176 	}
177 
178 	events.showCursor();
179 	_vm->_buffer2.copyFrom(*_vm->_screen);
180 	_vm->_buffer1.copyFrom(*_vm->_screen);
181 
182 	_vm->freeCells();
183 	_vm->_oldRects.clear();
184 	_vm->_newRects.clear();
185 	_vm->_numAnimTimers = 0;
186 	_vm->_images.clear();
187 
188 	if (_vm->isCD()) {
189 		if (_vm->_conversation == 2) {
190 			// Cutscene at end of Chapter 6
191 			Resource *spriteData = _vm->_files->loadFile(28, 37);
192 			_vm->_objectsTable[28] = new SpriteResource(_vm, spriteData);
193 			delete spriteData;
194 
195 			_vm->_animation->freeAnimationData();
196 			animResource = _vm->_files->loadFile(28, 38);
197 			_vm->_animation->loadAnimations(animResource);
198 			delete animResource;
199 		}
200 	} else {
201 		_vm->freeCells();
202 		_vm->_oldRects.clear();
203 		_vm->_newRects.clear();
204 		_vm->_numAnimTimers = 0;
205 		_vm->_images.clear();
206 	}
207 }
208 
209 /*------------------------------------------------------------------------*/
210 
Opening(AmazonEngine * vm)211 Opening::Opening(AmazonEngine *vm) : CampScene(vm) {
212 	_pCount = 0;
213 }
214 
doIntroduction()215 void Opening::doIntroduction() {
216 	Screen &screen = *_vm->_screen;
217 
218 	screen.setInitialPalettte();
219 	_vm->_events->setCursor(CURSOR_ARROW);
220 	_vm->_events->showCursor();
221 	screen.setPanel(0);
222 	screen.setPalette();
223 
224 	_vm->_events->setCursor(CURSOR_ARROW);
225 	_vm->_events->showCursor();
226 	screen.setPanel(3);
227 	doTitle();
228 
229 	if (_vm->shouldQuit() || _skipStart || _vm->isDemo())
230 		return;
231 
232 	screen.setPanel(3);
233 	mWhileDoOpen();
234 
235 	if (_vm->shouldQuit() || _skipStart)
236 		return;
237 
238 	doTent();
239 }
240 
doCredit()241 void Opening::doCredit() {
242 	if (_pCount < 15)
243 		return;
244 
245 	if (_pCount <= 75)
246 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], _vm->isDemo()? 24 : 0, Common::Point(90, 35));
247 	else if (_pCount <= 210)
248 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 1, Common::Point(65, 35));
249 	else if (_pCount <= 272)
250 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 2, Common::Point(96, 45));
251 	else if (_pCount <= 334)
252 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 3, Common::Point(68, 54));
253 	else if (_pCount <= 396)
254 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 4, Common::Point(103, 54));
255 	else if (_pCount <= 458) {
256 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 5, Common::Point(8, 5));
257 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 12, Common::Point(88, 55));
258 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 6, Common::Point(194, 98));
259 	} else if (_pCount <= 520) {
260 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 7, Common::Point(32, 13));
261 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 8, Common::Point(162, 80));
262 	} else if (_pCount <= 580) {
263 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 9, Common::Point(18, 15));
264 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 10, Common::Point(164, 81));
265 	} else
266 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 11, Common::Point(106, 55));
267 }
268 
doCreditDemo()269 void Opening::doCreditDemo() {
270 	if (_pCount < 15)
271 		return;
272 
273 	if (_pCount <= 75)
274 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], _vm->isDemo()? 24 : 0, Common::Point(90, 35));
275 	else if (_pCount <= 210)
276 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 25, Common::Point(82, 35));
277 	else if (_pCount <= 272) {
278 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 23, Common::Point(77, 20));
279 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 4, Common::Point(50, 35));
280 	} else if (_pCount <= 334) {
281 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 16, Common::Point(200, 70));
282 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 4, Common::Point(170, 85));
283 	} else if (_pCount <= 396) {
284 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 15, Common::Point(65, 15));
285 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 2, Common::Point(30, 30));
286 	} else if (_pCount <= 458) {
287 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 19, Common::Point(123, 40));
288 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 10, Common::Point(115, 55));
289 	} else if (_pCount <= 520) {
290 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 18, Common::Point(50, 15));
291 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 9, Common::Point(40, 30));
292 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 0, Common::Point(40, 55));
293 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 20, Common::Point(198, 95));
294 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 3, Common::Point(160, 110));
295 	} else if (_pCount <= 580) {
296 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 21, Common::Point(40, 10));
297 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 6, Common::Point(20, 25));
298 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 22, Common::Point(145, 50));
299 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 7, Common::Point(125, 65));
300 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 12, Common::Point(207, 90));
301 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 5, Common::Point(200, 105));
302 	} else {
303 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 11, Common::Point(125, 30));
304 		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 4, Common::Point(115, 45));
305 	}
306 }
307 
scrollTitle()308 void Opening::scrollTitle() {
309 	_vm->copyBF1BF2();
310 	_vm->_newRects.clear();
311 	if (_vm->isDemo())
312 		doCreditDemo();
313 	else
314 		doCredit();
315 	_vm->copyRects();
316 	_vm->copyBF2Vid();
317 }
318 
doTitle()319 void Opening::doTitle() {
320 	Screen &screen = *_vm->_screen;
321 
322 	screen.setDisplayScan();
323 
324 	screen.forceFadeOut();
325 	_vm->_events->hideCursor();
326 
327 	if (!_vm->isDemo()) {
328 		_vm->_sound->loadSoundTable(0, 98, 30);
329 		_vm->_sound->loadSoundTable(1, 98, 8);
330 
331 		_vm->_files->_setPaletteFlag = false;
332 		_vm->_files->loadScreen(0, 3);
333 
334 		_vm->_buffer2.copyFrom(*_vm->_screen);
335 		_vm->_buffer1.copyFrom(*_vm->_screen);
336 		screen.forceFadeIn();
337 
338 		_vm->_sound->playSound(1, true);
339 
340 		Resource *spriteData = _vm->_files->loadFile(0, 2);
341 		_vm->_objectsTable[0] = new SpriteResource(_vm, spriteData);
342 		delete spriteData;
343 
344 		_vm->_files->_setPaletteFlag = false;
345 		_vm->_files->loadScreen(0, 4);
346 
347 		_vm->_buffer2.copyFrom(*_vm->_screen);
348 		_vm->_buffer1.copyFrom(*_vm->_screen);
349 
350 		const int COUNTDOWN[6] = { 2, 0x80, 1, 0x7d, 0, 0x87 };
351 		for (_pCount = 0; _pCount < 3 && !_vm->shouldQuit(); ++_pCount) {
352 			_vm->_buffer2.blitFrom(_vm->_buffer1);
353 			int id = COUNTDOWN[_pCount * 2];
354 			int xp = COUNTDOWN[_pCount * 2 + 1];
355 			_vm->_buffer2.plotImage(_vm->_objectsTable[0], id, Common::Point(xp, 71));
356 			_vm->_buffer2.copyTo(_vm->_screen);
357 
358 			_vm->_events->_vbCount = 70;
359 			while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0 && !_skipStart) {
360 				_vm->_events->pollEventsAndWait();
361 				if (_vm->_events->_rightButton)
362 					_skipStart = true;
363 			}
364 		}
365 		if (_vm->shouldQuit())
366 			return;
367 
368 		_vm->_sound->stopSound();
369 		_vm->_sound->checkSoundQueue(); // HACK: Clear sound 1 from the queue
370 		_vm->_sound->playSound(0);
371 		screen.forceFadeOut();
372 		_vm->_events->_vbCount = 100;
373 		while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
374 			_vm->_events->pollEventsAndWait();
375 		if (_vm->shouldQuit())
376 			return;
377 
378 		_vm->_sound->freeSounds();
379 		delete _vm->_objectsTable[0];
380 		_vm->_objectsTable[0] = nullptr;
381 
382 		_vm->_files->_setPaletteFlag = false;
383 		_vm->_files->loadScreen(0, 5);
384 		_vm->_buffer2.blitFrom(*_vm->_screen);
385 		_vm->_buffer1.blitFrom(*_vm->_screen);
386 		screen.forceFadeIn();
387 		_vm->_midi->newMusic(1, 0);
388 		_vm->_events->_vbCount = 950;
389 		while (!_vm->shouldQuit() && (_vm->_events->_vbCount > 0) && !_vm->_events->isKeyMousePressed()) {
390 			_vm->_events->pollEventsAndWait();
391 		}
392 
393 		if (_vm->_events->_rightButton) {
394 			_skipStart = true;
395 			_vm->_room->clearRoom();
396 			_vm->_events->showCursor();
397 			return;
398 		}
399 
400 		_vm->_midi->newMusic(1, 1);
401 		_vm->_midi->setLoop(false);
402 		_vm->_events->zeroKeys();
403 	}
404 
405 	_vm->_buffer1.create(_vm->_screen->w + TILE_WIDTH, _vm->_screen->h);
406 	_vm->_room->loadRoom(0);
407 	screen.clearScreen();
408 	screen.setBufferScan();
409 	_vm->_scrollRow = _vm->_scrollCol = 0;
410 	_vm->_scrollX = _vm->_scrollY = 0;
411 	_vm->_player->_rawPlayer = Common::Point(0, 0);
412 	screen.forceFadeOut();
413 	_vm->_room->buildScreen();
414 	_vm->copyBF2Vid();
415 	screen.forceFadeIn();
416 	_vm->_oldRects.clear();
417 	_vm->_newRects.clear();
418 	_vm->_events->clearEvents();
419 	_vm->_player->_scrollAmount = 1;
420 	_pCount = 0;
421 
422 	while (!_vm->shouldQuit()) {
423 		if (_vm->_events->isKeyMousePressed()) {
424 			if (_vm->_events->_rightButton)
425 				_skipStart = true;
426 			_vm->_room->clearRoom();
427 			_vm->_events->showCursor();
428 			return;
429 		}
430 
431 		_vm->_events->_vbCount = 4;
432 		if (_vm->_scrollCol + screen._vWindowWidth != _vm->_room->_playFieldWidth) {
433 			_vm->_scrollX += _vm->_player->_scrollAmount;
434 
435 			while (_vm->_scrollX >= TILE_WIDTH) {
436 				_vm->_scrollX -= TILE_WIDTH;
437 				++_vm->_scrollCol;
438 
439 				_vm->_buffer1.moveBufferLeft();
440 				_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth, screen._vWindowBytesWide);
441 			}
442 			scrollTitle();
443 			++_pCount;
444 
445 			while (!_vm->shouldQuit() && (_vm->_events->_vbCount > 0)) {
446 				_vm->_events->pollEventsAndWait();
447 			}
448 			continue;
449 		}
450 
451 		_vm->_events->_vbCount = 120;
452 		while (!_vm->shouldQuit() && (_vm->_events->_vbCount > 0))
453 			_vm->_events->pollEventsAndWait();
454 
455 		while (!_vm->shouldQuit()) {
456 			_pCount = 0;
457 			_vm->_events->_vbCount = 3;
458 			if (_vm->_scrollRow + screen._vWindowHeight >= _vm->_room->_playFieldHeight) {
459 				_vm->_room->clearRoom();
460 				_vm->_events->showCursor();
461 				return;
462 			}
463 
464 			_vm->_scrollY = _vm->_scrollY + _vm->_player->_scrollAmount;
465 
466 			while (_vm->_scrollY >= TILE_HEIGHT && !_vm->shouldQuit()) {
467 				_vm->_scrollY -= TILE_HEIGHT;
468 				++_vm->_scrollRow;
469 				_vm->_buffer1.moveBufferUp();
470 
471 				// WORKAROUND: the original was using screen._vWindowBytesWide * screen._vWindowLinesTall
472 				_vm->_room->buildRow(_vm->_scrollRow + screen._vWindowHeight, screen._vWindowLinesTall);
473 
474 				if (_vm->_scrollRow + screen._vWindowHeight >= _vm->_room->_playFieldHeight) {
475 					_vm->_room->clearRoom();
476 					_vm->_events->showCursor();
477 					return;
478 				}
479 			}
480 			scrollTitle();
481 			while (!_vm->shouldQuit() && (_vm->_events->_vbCount > 0))
482 				_vm->_events->pollEventsAndWait();
483 		}
484 	}
485 }
486 
doTent()487 void Opening::doTent() {
488 	int step = 0;
489 	_vm->_screen->setDisplayScan();
490 	_vm->_screen->forceFadeOut();
491 	_vm->_events->hideCursor();
492 	_vm->_sound->loadSoundTable(0, 98, 39);
493 	_vm->_sound->loadSoundTable(1, 98, 14);
494 	_vm->_sound->loadSoundTable(2, 98, 15);
495 	_vm->_sound->loadSoundTable(3, 98, 16);
496 	_vm->_sound->loadSoundTable(4, 98, 31, 2);
497 	_vm->_sound->loadSoundTable(5, 98, 52, 2);
498 	_vm->_sound->playSound(0);
499 
500 	_vm->_files->_setPaletteFlag = false;
501 	_vm->_files->loadScreen(2, 0);
502 	_vm->_buffer2.blitFrom(*_vm->_screen);
503 	_vm->_buffer1.blitFrom(*_vm->_screen);
504 	_vm->_screen->forceFadeIn();
505 
506 	_vm->_video->setVideo(_vm->_screen, Common::Point(126, 73), FileIdent(2, 1), 10);
507 	int previousFrame = -1;
508 	while (!_vm->shouldQuit() && !_vm->_video->_videoEnd) {
509 		_vm->_video->playVideo();
510 		if (previousFrame != _vm->_video->_videoFrame) {
511 			previousFrame = _vm->_video->_videoFrame;
512 
513 			if ((_vm->_video->_videoFrame == 32) || (_vm->_video->_videoFrame == 34))
514 				_vm->_sound->playSound(4);
515 			else if (_vm->_video->_videoFrame == 36) {
516 				if (step != 2) {
517 					_vm->_sound->playSound(2);
518 					step = 2;
519 				}
520 			} else if (_vm->_video->_videoFrame == 18) {
521 				if (step != 1) {
522 					_vm->_midi->newMusic(73, 1);
523 					_vm->_midi->newMusic(11, 0);
524 					step = 1;
525 					_vm->_sound->playSound(1);
526 				}
527 			}
528 		}
529 		_vm->_events->pollEventsAndWait();
530 	}
531 
532 	_vm->_sound->playSound(5);
533 	_vm->_video->setVideo(_vm->_screen, Common::Point(43, 11), FileIdent(2, 2), 10);
534 	previousFrame = -1;
535 	while (!_vm->shouldQuit() && !_vm->_video->_videoEnd) {
536 		_vm->_video->playVideo();
537 		if (previousFrame != _vm->_video->_videoFrame) {
538 			previousFrame = _vm->_video->_videoFrame;
539 			if (_vm->_video->_videoFrame == 26) {
540 				_vm->_sound->playSound(5);
541 			} else if (_vm->_video->_videoFrame == 15) {
542 				if (step !=3) {
543 					_vm->_sound->playSound(3);
544 					step = 3;
545 				}
546 			}
547 		}
548 		_vm->_events->pollEventsAndWait();
549 	}
550 
551 	_vm->_events->_vbCount = 200;
552 	while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
553 		_vm->_events->pollEventsAndWait();
554 
555 	_vm->_events->showCursor();
556 	_vm->_midi->newMusic(11, 1);
557 	_vm->_sound->_soundTable.clear();
558 
559 	_vm->establishCenter(0, 4);
560 }
561 
562 /*------------------------------------------------------------------------*/
563 
Plane(AmazonEngine * vm)564 Plane::Plane(AmazonEngine *vm) : PannedScene(vm) {
565 	_pCount = 0;
566 	_planeCount = 0;
567 	_propCount = 0;
568 }
569 
570 
doFlyCell()571 void Plane::doFlyCell() {
572 	SpriteResource *sprites = _vm->_objectsTable[15];
573 
574 	if (_pCount <= 40) {
575 		_vm->_buffer2.plotImage(sprites, 3, Common::Point(70, 74));
576 	} else if (_pCount <= 80) {
577 		_vm->_buffer2.plotImage(sprites, 6, Common::Point(70, 74));
578 	} else if (_pCount <= 120) {
579 		_vm->_buffer2.plotImage(sprites, 2, Common::Point(50, 76));
580 	} else if (_pCount <= 160) {
581 		_vm->_buffer2.plotImage(sprites, 14, Common::Point(63, 78));
582 	} else if (_pCount <= 200) {
583 		_vm->_buffer2.plotImage(sprites, 5, Common::Point(86, 74));
584 	} else if (_pCount <= 240) {
585 		_vm->_buffer2.plotImage(sprites, 0, Common::Point(103, 76));
586 	} else if (_pCount <= 280) {
587 		_vm->_buffer2.plotImage(sprites, 4, Common::Point(119, 77));
588 	} else {
589 		_vm->_buffer2.plotImage(sprites, 1, Common::Point(111, 77));
590 	}
591 
592 	if (_planeCount == 11 || _planeCount == 12)
593 		++_position.y;
594 	else if (_planeCount >= 28)
595 		--_position.y;
596 
597 	_vm->_buffer2.plotImage(sprites, 7, _position);
598 	_vm->_buffer2.plotImage(sprites, 8 + _propCount, Common::Point(
599 		_position.x + 99, _position.y + 10));
600 	_vm->_buffer2.plotImage(sprites, 11 + _propCount, Common::Point(
601 		_position.x + 104, _position.y + 18));
602 
603 	if (++_planeCount >= 30)
604 		_planeCount = 0;
605 	if (++_propCount >= 3)
606 		_propCount = 0;
607 
608 	++_xCount;
609 	if (_xCount == 1)
610 		++_position.x;
611 	else
612 		_xCount = 0;
613 }
614 
doFallCell()615 void Plane::doFallCell() {
616 	if (_vm->_scaleI <= 20)
617 		return;
618 
619 	SpriteFrame *frame = _vm->_objectsTable[20]->getFrame(_planeCount / 6);
620 	Common::Rect r(115, 11, 115 + _vm->_screen->_scaleTable1[frame->w],
621 		11 + _vm->_screen->_scaleTable1[frame->h]);
622 	_vm->_buffer2.sPlotF(frame, r);
623 
624 	_vm->_scaleI -= 3;
625 	_vm->_scale = _vm->_scaleI;
626 	_vm->_screen->setScaleTable(_vm->_scale);
627 	++_xCount;
628 	if (_xCount == 5)
629 		return;
630 	_xCount = 0;
631 	if (_planeCount == 18)
632 		_planeCount = 0;
633 	else
634 		_planeCount += 6;
635 }
636 
scrollFly()637 void Plane::scrollFly() {
638 	_vm->copyBF1BF2();
639 	_vm->_newRects.clear();
640 	doFlyCell();
641 	_vm->copyRects();
642 	_vm->copyBF2Vid();
643 }
644 
scrollFall()645 void Plane::scrollFall() {
646 	_vm->copyBF1BF2();
647 	_vm->_newRects.clear();
648 	doFallCell();
649 	_vm->copyRects();
650 	_vm->copyBF2Vid();
651 }
652 
mWhileFly()653 void Plane::mWhileFly() {
654 	Screen &screen = *_vm->_screen;
655 	Player &player = *_vm->_player;
656 	EventsManager &events = *_vm->_events;
657 
658 	events.hideCursor();
659 	screen.clearScreen();
660 	screen.setBufferScan();
661 	screen.fadeOut();
662 	_vm->_scrollX = 0;
663 
664 	_vm->_room->buildScreen();
665 	_vm->copyBF2Vid();
666 	screen.fadeIn();
667 	_vm->_oldRects.clear();
668 	_vm->_newRects.clear();
669 	_vm->_events->clearEvents();
670 
671 	_vm->_scrollRow = _vm->_scrollCol = 0;
672 	_vm->_scrollX = _vm->_scrollY = 0;
673 	player._rawPlayer = Common::Point(0, 0);
674 	player._scrollAmount = 1;
675 
676 	_pCount = 0;
677 	_planeCount = 0;
678 	_propCount = 0;
679 	_xCount = 0;
680 	_position = Common::Point(20, 29);
681 
682 	while (!_vm->shouldQuit() && !events.isKeyMousePressed() &&
683 		((_vm->_scrollCol + screen._vWindowWidth) != _vm->_room->_playFieldWidth)) {
684 		events._vbCount = 4;
685 		_vm->_scrollX += player._scrollAmount;
686 
687 		while (_vm->_scrollX >= TILE_WIDTH) {
688 			_vm->_scrollX -= TILE_WIDTH;
689 			++_vm->_scrollCol;
690 
691 			_vm->_buffer1.moveBufferLeft();
692 			_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth, screen._vWindowBytesWide);
693 		}
694 
695 		scrollFly();
696 		++_pCount;
697 
698 		while (!_vm->shouldQuit() && events._vbCount > 0) {
699 			_vm->_sound->playSound(0);
700 			events.pollEventsAndWait();
701 		}
702 	}
703 
704 	events.showCursor();
705 }
706 
mWhileFall()707 void Plane::mWhileFall() {
708 	Screen &screen = *_vm->_screen;
709 	EventsManager &events = *_vm->_events;
710 
711 	events.hideCursor();
712 	screen.clearScreen();
713 	screen.setBufferScan();
714 	screen.fadeOut();
715 	_vm->_scrollX = 0;
716 
717 	_vm->_room->buildScreen();
718 	_vm->copyBF2Vid();
719 	screen.fadeIn();
720 	_vm->_oldRects.clear();
721 	_vm->_newRects.clear();
722 	_vm->_events->clearEvents();
723 
724 	_vm->_scrollRow = _vm->_scrollCol = 0;
725 	_vm->_scrollX = _vm->_scrollY = 0;
726 	_vm->_player->_scrollAmount = 3;
727 	_vm->_scaleI = 255;
728 
729 	_xCount = 0;
730 	_planeCount = 0;
731 
732 	while (!_vm->shouldQuit() && !events.isKeyMousePressed() &&
733 		(_vm->_scrollCol + screen._vWindowWidth != _vm->_room->_playFieldWidth)) {
734 		events._vbCount = 4;
735 		_vm->_scrollX += _vm->_player->_scrollAmount;
736 
737 		while (_vm->_scrollX >= TILE_WIDTH) {
738 			_vm->_scrollX -= TILE_WIDTH;
739 			++_vm->_scrollCol;
740 
741 			_vm->_buffer1.moveBufferLeft();
742 			_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth, screen._vWindowBytesWide);
743 		}
744 
745 		scrollFall();
746 
747 		while (!_vm->shouldQuit() && events._vbCount > 0) {
748 			events.pollEventsAndWait();
749 		}
750 	}
751 
752 	events.showCursor();
753 }
754 
755 /*------------------------------------------------------------------------*/
756 
Jungle(AmazonEngine * vm)757 Jungle::Jungle(AmazonEngine *vm) : CampScene(vm) {
758 	for (int i = 0; i < JUNGLE_SIZE; ++i) {
759 		_jCnt[i] = _jungleX[i] = -1;
760 	}
761 }
762 
jungleMove()763 void Jungle::jungleMove() {
764 	const static int jungleY[3] = { 27, 30, 29 };
765 	int count = 1;
766 	int frameOffset = 0;
767 
768 	if (!_vm->_timers[0]._flag) {
769 		++_vm->_timers[0]._flag;
770 		_vm->_scrollX += _vm->_player->_scrollAmount;
771 
772 		for (int i = 0; i < 3; ++i) {
773 			int newJCnt = (_jCnt[i] + 1) % 8;
774 			_jCnt[i] = newJCnt;
775 			_jungleX[i] += 5;
776 		}
777 
778 		frameOffset = 4;
779 		count = (_vm->_allenFlag != 1) ? 2 : 3;
780 	}
781 
782 	for (int i = 0; i < count; ++i) {
783 		ImageEntry ie;
784 		ie._flags = IMGFLAG_UNSCALED;
785 		ie._spritesPtr = _vm->_objectsTable[24];
786 		ie._frameNumber = _jCnt[i] + frameOffset;
787 		ie._position = Common::Point(_jungleX[i], jungleY[i]);
788 		ie._offsetY = jungleY[i];
789 
790 		_vm->_images.addToList(ie);
791 		frameOffset += 8;
792 	}
793 }
794 
initJWalk2()795 void Jungle::initJWalk2() {
796 	const int JUNGLE1OBJ[7][4] = {
797 		{ 2, 470, 0, 20 },
798 		{ 0, 290, 0, 50 },
799 		{ 1, 210, 0, 40 },
800 		{ 0, 500, 0, 30 },
801 		{ 1, 550, 0, 20 },
802 		{ 0, 580, 0, 60 },
803 		{ 1, 650, 0, 30 }
804 	};
805 
806 	Screen &screen = *_vm->_screen;
807 	screen.fadeOut();
808 	_vm->_events->hideCursor();
809 	screen.clearScreen();
810 	_vm->_buffer2.clearBuffer();
811 	screen.setBufferScan();
812 
813 	_vm->_scrollX = _vm->_scrollY;
814 	_vm->_scrollCol = _vm->_scrollRow;
815 	_vm->_room->buildScreen();
816 	_vm->copyBF2Vid();
817 	screen.fadeIn();
818 	_vm->_events->clearEvents();
819 
820 	_xCount = 2;
821 	_vm->_player->_scrollAmount = 5;
822 	_xTrack = -10;
823 	_yTrack = _zTrack = 0;
824 	_xCam = 480;
825 	_yCam = 0;
826 	_zCam = 80;
827 
828 	_vm->_timers[24]._timer = 1;
829 	_vm->_timers[24]._initTm = 1;
830 	++_vm->_timers[24]._flag;
831 
832 	_pNumObj = 7;
833 	for (int i = 0; i < _pNumObj; i++) {
834 		_pan[i]._pObject = _vm->_objectsTable[24];
835 		_pan[i]._pImgNum = JUNGLE1OBJ[i][0];
836 		_pan[i]._pObjX = JUNGLE1OBJ[i][1];
837 		_pan[i]._pObjY = JUNGLE1OBJ[i][2];
838 		_pan[i]._pObjZ = JUNGLE1OBJ[i][3];
839 		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
840 	}
841 
842 	_jCnt[0] = 0;
843 	_jCnt[1] = 3;
844 	_jCnt[2] = 5;
845 
846 	_jungleX[0] = 50;
847 	_jungleX[1] = 16;
848 	_jungleX[2] = 93;
849 }
850 
mWhileJWalk()851 void Jungle::mWhileJWalk() {
852 	Screen &screen = *_vm->_screen;
853 	EventsManager &events = *_vm->_events;
854 	Player &player = *_vm->_player;
855 
856 	static const int JUNGLE_OBJ[7][4] = {
857 		{ 2, 77, 0, 40 },
858 		{ 0, 290, 0, 50 },
859 		{ 1, 210, 0, 70 },
860 		{ 0, 50, 0, 30 },
861 		{ 1, 70, 0, 20 },
862 		{ 0, -280, 0, 60 },
863 		{ 1, -150, 0, 30 },
864 	};
865 
866 	screen.fadeOut();
867 	events.hideCursor();
868 	screen.clearScreen();
869 	_vm->_buffer2.clearBuffer();
870 	screen.setBufferScan();
871 	_vm->_scrollX = 0;
872 
873 	// Build the initial jungle scene and fade it in
874 	_vm->_room->buildScreen();
875 	_vm->copyBF2Vid();
876 	screen.fadeIn();
877 
878 	// Set up the player to walk horizontally
879 	player._xFlag = 1;
880 	player._yFlag = 0;
881 	player._moveTo.x = 160;
882 	player._playerMove = true;
883 
884 	_xCount = 2;
885 	_xTrack = 10;
886 	_yTrack = _zTrack = 0;
887 	_xCam = 480;
888 	_yCam = 0;
889 	_zCam = 80;
890 
891 	TimerEntry *te = &_vm->_timers[24];
892 	te->_initTm = te->_timer = 1;
893 	te->_flag++;
894 
895 	_pNumObj = 7;
896 	for (int i = 0; i < _pNumObj; i++) {
897 		_pan[i]._pObject = _vm->_objectsTable[24];
898 		_pan[i]._pImgNum = JUNGLE_OBJ[i][0];
899 		_pan[i]._pObjX = JUNGLE_OBJ[i][1];
900 		_pan[i]._pObjY = JUNGLE_OBJ[i][2];
901 		_pan[i]._pObjZ = JUNGLE_OBJ[i][3];
902 		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
903 	}
904 
905 	while (!_vm->shouldQuit() && !events.isKeyMousePressed() && (player._xFlag != 2)) {
906 		_vm->_images.clear();
907 		events._vbCount = 6;
908 
909 		_pan[0]._pImgNum = _xCount;
910 		if (_xCount == 2)
911 			++_xCount;
912 		else
913 			--_xCount;
914 
915 		player.checkMove();
916 		player.checkScroll();
917 		pan();
918 		scrollJWalk();
919 
920 		while (!_vm->shouldQuit() && events._vbCount > 0) {
921 			events.pollEventsAndWait();
922 		}
923 	}
924 
925 	_vm->_images.clear();
926 	events.showCursor();
927 }
928 
mWhileJWalk2()929 void Jungle::mWhileJWalk2() {
930 	Screen &screen = *_vm->_screen;
931 
932 	initJWalk2();
933 
934 	while (!_vm->shouldQuit() && !_vm->_events->isKeyMousePressed() &&
935 		(_vm->_scrollCol + screen._vWindowWidth) != _vm->_room->_playFieldWidth) {
936 		_vm->_images.clear();
937 		_vm->_events->_vbCount = 6;
938 		_pan[0]._pImgNum = _xCount;
939 
940 		jungleMove();
941 		while (_vm->_scrollX >= TILE_WIDTH) {
942 			_vm->_scrollX -= TILE_WIDTH;
943 			++_vm->_scrollCol;
944 			_vm->_buffer1.moveBufferLeft();
945 			_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth, screen._vWindowBytesWide);
946 		}
947 
948 		if (_xCount == 2)
949 			++_xCount;
950 		else
951 			--_xCount;
952 
953 		pan();
954 		scrollJWalk();
955 
956 		while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0) {
957 			_vm->_events->pollEventsAndWait();
958 		}
959 	}
960 
961 	_vm->_events->showCursor();
962 }
963 
scrollJWalk()964 void Jungle::scrollJWalk() {
965 	_vm->copyBF1BF2();
966 	_vm->_newRects.clear();
967 	_vm->plotList();
968 	_vm->copyRects();
969 	_vm->copyBF2Vid();
970 }
971 
972 /*------------------------------------------------------------------------*/
973 
Guard(AmazonEngine * vm)974 Guard::Guard(AmazonEngine *vm) : PannedScene(vm) {
975 	_guardCel = 0;
976 	_gCode1 = _gCode2 = 0;
977 	_xMid = _yMid = 0;
978 }
979 
setVerticalCode()980 void Guard::setVerticalCode() {
981 	Screen &screen = *_vm->_screen;
982 
983 	_gCode1 = 0;
984 	_gCode2 = 0;
985 	if (_topLeft.x < screen._orgX1)
986 		_gCode1 |= 8;
987 	else if (_topLeft.x == screen._orgX1) {
988 		_gCode1 |= 8;
989 		_gCode1 |= 2;
990 	} else
991 		_gCode1 |= 2;
992 
993 	if (_bottomRight.x < screen._orgX1)
994 		_gCode2 |= 8;
995 	else if (_bottomRight.x == screen._orgX1) {
996 		_gCode2 |= 8;
997 		_gCode2 |= 2;
998 	} else
999 		_gCode2 |= 2;
1000 
1001 	if (_topLeft.y < screen._orgY1)
1002 		_gCode1 |= 4;
1003 	else if (_topLeft.y > screen._orgY2)
1004 		_gCode1 |= 1;
1005 
1006 	if (_bottomRight.y < screen._orgY1)
1007 		_gCode2 |= 4;
1008 	else if (_bottomRight.y > screen._orgY2)
1009 		_gCode2 |= 1;
1010 }
1011 
setHorizontalCode()1012 void Guard::setHorizontalCode() {
1013 	Screen &screen = *_vm->_screen;
1014 
1015 	_gCode1 = 0;
1016 	_gCode2 = 0;
1017 
1018 	if (_topLeft.y < screen._orgY1)
1019 		_gCode1 |= 4;
1020 	else if (_topLeft.x == screen._orgX1) {
1021 		_gCode1 |= 4;
1022 		_gCode1 |= 1;
1023 	} else
1024 		_gCode1 |= 1;
1025 
1026 	if (_bottomRight.y < screen._orgY1)
1027 		_gCode2 |= 4;
1028 	else if (_bottomRight.x == screen._orgX1) {
1029 		_gCode2 |= 4;
1030 		_gCode2 |= 1;
1031 	} else
1032 		_gCode2 |= 1;
1033 
1034 	if (_topLeft.x < screen._orgX1)
1035 		_gCode1 |= 8;
1036 	else if (_topLeft.x > screen._orgX2)
1037 		_gCode1 |= 2;
1038 
1039 	if (_bottomRight.x < screen._orgX1)
1040 		_gCode2 |= 8;
1041 	else if (_bottomRight.x > screen._orgX2)
1042 		_gCode2 |= 2;
1043 }
1044 
chkVLine()1045 void Guard::chkVLine() {
1046 	if (_position.x > _vm->_player->_rawPlayer.x) {
1047 		_topLeft = _vm->_player->_rawPlayer;
1048 		_bottomRight = _position;
1049 	} else {
1050 		_topLeft = _position;
1051 		_bottomRight = _vm->_player->_rawPlayer;
1052 	}
1053 
1054 	if (_vm->_screen->_orgY1 > _vm->_screen->_orgY2)
1055 		SWAP(_vm->_screen->_orgY1, _vm->_screen->_orgY2);
1056 
1057 	for (;;) {
1058 		setVerticalCode();
1059 		int code = _gCode1 | _gCode2;
1060 		if (code == 10) {
1061 			_vm->_guardFind = 0;
1062 			return;
1063 		}
1064 
1065 		int code2 = _gCode1 & _gCode2;
1066 		code2 &= 5;
1067 		if (((code & 10) == 8) || ((code & 10) == 2) || (code2 != 0))
1068 			return;
1069 
1070 		int midX = (_topLeft.x + _bottomRight.x) / 2;
1071 		int midY = (_topLeft.y + _bottomRight.y) / 2;
1072 
1073 		if (midX < _vm->_screen->_orgX1) {
1074 			if ((midX == _topLeft.x) && (midY == _topLeft.y))
1075 				return;
1076 
1077 			_topLeft.x = midX;
1078 			_topLeft.y = midY;
1079 		} else {
1080 			if ((midX == _bottomRight.x) && (midY == _bottomRight.y))
1081 				return;
1082 
1083 			_bottomRight.x = midX;
1084 			_bottomRight.y = midY;
1085 		}
1086 	}
1087 }
1088 
chkHLine()1089 void Guard::chkHLine() {
1090 	if (_position.y > _vm->_player->_rawPlayer.y) {
1091 		_topLeft = _vm->_player->_rawPlayer;
1092 		_bottomRight = _position;
1093 	} else {
1094 		_topLeft = _position;
1095 		_bottomRight = _vm->_player->_rawPlayer;
1096 	}
1097 
1098 	if (_vm->_screen->_orgX1 > _vm->_screen->_orgX2)
1099 		SWAP(_vm->_screen->_orgX1, _vm->_screen->_orgX2);
1100 
1101 	while (true) {
1102 		setHorizontalCode();
1103 		int code = _gCode1 | _gCode2;
1104 		if (code == 5) {
1105 			_vm->_guardFind = 0;
1106 			return;
1107 		}
1108 
1109 		int code2 = _gCode1 & _gCode2;
1110 		code2 &= 10;
1111 		if (((code & 5) == 4) || ((code & 5) == 1) || (code2 != 0))
1112 			return;
1113 
1114 		int midX = (_topLeft.x + _bottomRight.x) / 2;
1115 		int midY = (_topLeft.y + _bottomRight.y) / 2;
1116 
1117 		if (midY < _vm->_screen->_orgY1) {
1118 			if ((midX == _topLeft.x) && (midY == _topLeft.y))
1119 				return;
1120 
1121 			_topLeft.x = midX;
1122 			_topLeft.y = midY;
1123 		} else {
1124 			if ((midX == _bottomRight.x) && (midY == _bottomRight.y))
1125 				return;
1126 
1127 			_bottomRight.x = midX;
1128 			_bottomRight.y = midY;
1129 		}
1130 	}
1131 }
1132 
guardSee()1133 void Guard::guardSee() {
1134 	Screen &screen = *_vm->_screen;
1135 	int tmpY = (_vm->_scrollRow << 4) + _vm->_scrollY;
1136 	_vm->_flags[140] = 0;
1137 	if (tmpY > _position.y)
1138 		return;
1139 
1140 	tmpY += screen._vWindowLinesTall;
1141 	tmpY -= 11;
1142 
1143 	if (tmpY < _position.y)
1144 		return;
1145 
1146 	_vm->_guardFind = 1;
1147 	_vm->_flags[140] = 1;
1148 
1149 	for (uint16 idx = 0; idx < _vm->_room->_plotter._walls.size(); idx++) {
1150 		screen._orgX1 = _vm->_room->_plotter._walls[idx].left;
1151 		screen._orgY1 = _vm->_room->_plotter._walls[idx].top;
1152 		screen._orgX2 = _vm->_room->_plotter._walls[idx].right;
1153 		screen._orgY2 = _vm->_room->_plotter._walls[idx].bottom;
1154 		if (screen._orgX1 == screen._orgX2) {
1155 			chkVLine();
1156 			if (_vm->_guardFind == 0)
1157 				return;
1158 		} else if (screen._orgY1 == screen._orgY2) {
1159 			chkHLine();
1160 			if (_vm->_guardFind == 0)
1161 				return;
1162 		}
1163 	}
1164 }
1165 
setGuardFrame()1166 void Guard::setGuardFrame() {
1167 	ImageEntry ie;
1168 	ie._flags = IMGFLAG_UNSCALED;
1169 
1170 	if (_vm->_guardLocation == 4)
1171 		ie._flags |= IMGFLAG_BACKWARDS;
1172 	ie._spritesPtr = _vm->_objectsTable[37];
1173 	ie._frameNumber = _guardCel;
1174 	ie._position = _position;
1175 	ie._offsetY = 10;
1176 	_vm->_images.addToList(ie);
1177 }
1178 
doGuard()1179 void Guard::doGuard() {
1180 	// Skip the code dealing with the guard on the boat (chapter 8)
1181 	// if the cheat mode is activated
1182 	if (_vm->_cheatFl)
1183 		return;
1184 
1185 	if (_vm->_timers[8]._flag) {
1186 		setGuardFrame();
1187 		return;
1188 	}
1189 
1190 	++_vm->_timers[8]._flag;
1191 	++_guardCel;
1192 	int curCel = _guardCel;
1193 
1194 	switch (_vm->_guardLocation) {
1195 	case 1:
1196 		// Guard walking down
1197 		if (curCel <= 8 || curCel > 13)
1198 			_guardCel = curCel = 8;
1199 
1200 		_position.y += _vm->_player->_walkOffDown[curCel - 8];
1201 		guardSee();
1202 		if (_position.y >= 272) {
1203 			_position.y = 272;
1204 			_vm->_guardLocation = 2;
1205 		}
1206 		break;
1207 	case 2:
1208 		// Guard walking left
1209 		if (curCel <= 43 || curCel > 48)
1210 			_guardCel = curCel = 43;
1211 
1212 		_position.x -= _vm->_player->_walkOffLeft[curCel - 43];
1213 		guardSee();
1214 		if (_position.x <= 56) {
1215 			_position.x = 56;
1216 			_vm->_guardLocation = 3;
1217 		}
1218 		break;
1219 	case 3:
1220 		// Guard walking up
1221 		if (curCel <= 0 || curCel > 5)
1222 			_guardCel = curCel = 0;
1223 
1224 		_position.y -= _vm->_player->_walkOffUp[curCel];
1225 		guardSee();
1226 		if (_position.y <= 89) {
1227 			_position.y = 89;
1228 			_vm->_guardLocation = 4;
1229 			if (_vm->_flags[121] == 1)
1230 				_vm->_guardLocation = 5;
1231 		}
1232 		break;
1233 	default:
1234 		// Guard walking right
1235 		if (curCel <= 43 || curCel > 48)
1236 			_guardCel = curCel = 43;
1237 
1238 		_position.x += _vm->_player->_walkOffRight[curCel - 43];
1239 		guardSee();
1240 		if (_position.x >= 127) {
1241 			_position.x = 127;
1242 			_vm->_guardLocation = 1;
1243 		}
1244 		break;
1245 	}
1246 
1247 	setGuardFrame();
1248 }
1249 
setPosition(const Common::Point & pt)1250 void Guard::setPosition(const Common::Point &pt) {
1251 	_position = pt;
1252 }
1253 
1254 /*------------------------------------------------------------------------*/
1255 
Cast(AmazonEngine * vm)1256 Cast::Cast(AmazonEngine *vm) : PannedScene(vm) {
1257 }
1258 
doCast(int param1)1259 void Cast::doCast(int param1) {
1260 	Screen &screen = *_vm->_screen;
1261 
1262 	_vm->_buffer1.create(_vm->_screen->w, _vm->_screen->h);
1263 	_vm->_buffer2.create(_vm->_screen->w, _vm->_screen->h);
1264 
1265 	screen.setDisplayScan();
1266 	_vm->_events->hideCursor();
1267 	screen.forceFadeOut();
1268 	screen._clipHeight = 173;
1269 	screen.clearScreen();
1270 	_vm->_chapter = 16;
1271 	_vm->tileScreen();
1272 	_vm->updateSummary(param1);
1273 	screen.setPanel(3);
1274 	_vm->_chapter = 14;
1275 
1276 	Resource *spriteData = _vm->_files->loadFile(91, 0);
1277 	_vm->_objectsTable[0] = new SpriteResource(_vm, spriteData);
1278 	delete spriteData;
1279 	spriteData = _vm->_files->loadFile(91, 1);
1280 	_vm->_objectsTable[1] = new SpriteResource(_vm, spriteData);
1281 	delete spriteData;
1282 
1283 	_vm->_files->_setPaletteFlag = false;
1284 	_vm->_files->loadScreen(58, 1);
1285 	_vm->_buffer2.blitFrom(*_vm->_screen);
1286 	_vm->_buffer1.blitFrom(*_vm->_screen);
1287 
1288 	_xTrack = 0;
1289 	_yTrack = -6;
1290 	_zTrack = 0;
1291 	_xCam = _yCam = 0;
1292 	_zCam = 60;
1293 
1294 	_vm->_timers[24]._timer = 1;
1295 	_vm->_timers[24]._initTm = 1;
1296 	++_vm->_timers[24]._flag;
1297 
1298 	_pNumObj = 26;
1299 	for (int i = 0; i < _pNumObj; i++) {
1300 		_pan[i]._pObject = _vm->_objectsTable[0];
1301 		_pan[i]._pImgNum = CAST_END_OBJ[i][0];
1302 		_pan[i]._pObjX = CAST_END_OBJ[i][1];
1303 		_pan[i]._pObjY = CAST_END_OBJ[i][2];
1304 		_pan[i]._pObjZ = CAST_END_OBJ[i][3];
1305 		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
1306 	}
1307 
1308 	_pNumObj += 4;
1309 	for (int i = 0; i < 4; i++) {
1310 		_pan[26 + i]._pObject = _vm->_objectsTable[1];
1311 		_pan[26 + i]._pImgNum = CAST_END_OBJ1[i][0];
1312 		_pan[26 + i]._pObjX = CAST_END_OBJ1[i][1];
1313 		_pan[26 + i]._pObjY = CAST_END_OBJ1[i][2];
1314 		_pan[26 + i]._pObjZ = CAST_END_OBJ1[i][3];
1315 		_pan[26 + i]._pObjXl = _pan[26 + i]._pObjYl = 0;
1316 	}
1317 
1318 	_vm->_oldRects.clear();
1319 	_vm->_newRects.clear();
1320 	_vm->_numAnimTimers = 0;
1321 
1322 	_vm->_midi->newMusic(58, 0);
1323 	screen.forceFadeIn();
1324 
1325 	while (!_vm->shouldQuit()) {
1326 		_vm->_images.clear();
1327 		pan();
1328 		_vm->_buffer2.blitFrom(_vm->_buffer1);
1329 		_vm->_newRects.clear();
1330 		_vm->plotList();
1331 		_vm->copyBlocks();
1332 
1333 		for (int idx = 0; idx < 5 && !_vm->shouldQuit() &&
1334 				!_vm->_events->isKeyMousePressed(); ++idx)
1335 			_vm->_events->pollEventsAndWait();
1336 
1337 		if (_vm->_events->isKeyMousePressed())
1338 			break;
1339 
1340 		if (_yCam < -7550) {
1341 			while (!_vm->shouldQuit() && !_vm->_midi->checkMidiDone())
1342 				_vm->_events->pollEventsAndWait();
1343 			break;
1344 		}
1345 	}
1346 
1347 	_vm->_midi->newMusic(58, 1);
1348 	_vm->_events->showCursor();
1349 
1350 	_vm->freeCells();
1351 	_vm->_oldRects.clear();
1352 	_vm->_newRects.clear();
1353 	_vm->_numAnimTimers = 0;
1354 	_vm->_images.clear();
1355 	screen.forceFadeOut();
1356 
1357 	_vm->quitGame();
1358 	_vm->_events->pollEvents();
1359 }
1360 
1361 /*------------------------------------------------------------------------*/
1362 
River(AmazonEngine * vm)1363 River::River(AmazonEngine *vm) : PannedScene(vm) {
1364 	_chickenOutFl = false;
1365 	_rScrollRow = 0;
1366 	_rScrollCol = 0;
1367 	_rScrollX = 0;
1368 	_rScrollY = 0;
1369 	_mapOffset = 0;
1370 	_screenVertX = 0;
1371 	_saveRiver = false;
1372 	_deathFlag = false;
1373 	_deathCount = 0;
1374 	_oldScrollCol = 0;
1375 	_maxHits = 0;
1376 	_mapPtr = nullptr;
1377 	_canoeMoveCount = 0;
1378 	_canoeVXPos = 0;
1379 	_canoeFrame = 0;
1380 	_canoeDir = 0;
1381 	_canoeLane = 0;
1382 	_canoeYPos = 0;
1383 	_hitCount = 0;
1384 	_riverIndex = 0;
1385 	_topList = _botList = nullptr;
1386 	_deathType = 0;
1387 	_hitSafe = 0;
1388 }
1389 
setRiverPan()1390 void River::setRiverPan() {
1391 	int delta = (_vm->_scrollCol * 16) + _vm->_scrollX;
1392 
1393 	_xTrack = 9;
1394 	_yTrack = _zTrack = 0;
1395 	_xCam = 160;
1396 	_yCam = 0;
1397 	_zCam = 80;
1398 
1399 	_vm->_timers[24]._timer = 1;
1400 	_vm->_timers[24]._initTm = 1;
1401 	++_vm->_timers[24]._flag;
1402 
1403 	_pNumObj = 23;
1404 	for (int i = 0; i < _pNumObj; i++) {
1405 		_pan[i]._pObject = _vm->_objectsTable[45];
1406 		_pan[i]._pImgNum = RIVER1OBJ[i][0];
1407 		_pan[i]._pObjX = RIVER1OBJ[i][1] + delta;
1408 		_pan[i]._pObjY = RIVER1OBJ[i][2];
1409 		_pan[i]._pObjZ = RIVER1OBJ[i][3];
1410 		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
1411 	}
1412 }
1413 
initRiver()1414 void River::initRiver() {
1415 	static const int RIVERVXTBL[3] = { 6719, 7039, 8319 };
1416 	Screen &screen = *_vm->_screen;
1417 
1418 	_vm->_events->centerMousePos();
1419 	_vm->_events->restrictMouse();
1420 	screen.setDisplayScan();
1421 	screen.clearScreen();
1422 	screen.savePalette();
1423 	screen.forceFadeOut();
1424 
1425 	_vm->_files->_setPaletteFlag = false;
1426 	_vm->_files->loadScreen(95, 4);
1427 	_vm->_buffer2.blitFrom(*_vm->_screen);
1428 
1429 	screen.restorePalette();
1430 	screen.setBufferScan();
1431 	_vm->_destIn = &_vm->_buffer2;
1432 	_vm->_room->roomMenu();
1433 
1434 	if (_saveRiver) {
1435 		// Restoring a savegame, so set properties from saved fields
1436 		_vm->_scrollRow = _rScrollRow;
1437 		_vm->_scrollCol = _rScrollCol;
1438 		_vm->_scrollX = _rScrollX;
1439 		_vm->_scrollY = _rScrollY;
1440 	} else {
1441 		// Set initial scene state
1442 		_vm->_scrollRow = 0;
1443 		_vm->_scrollCol = 140;
1444 		_vm->_scrollX = 0;
1445 		_vm->_scrollY = 0;
1446 	}
1447 
1448 	_vm->_room->buildScreen();
1449 	_vm->copyBF2Vid();
1450 	screen.forceFadeIn();
1451 
1452 	if (!_saveRiver) {
1453 		// Reset draw rects
1454 		_vm->_oldRects.clear();
1455 		_vm->_newRects.clear();
1456 		_vm->_events->clearEvents();
1457 
1458 	}
1459 
1460 	_vm->_player->_scrollAmount = 2;
1461 	setRiverPan();
1462 	_vm->_timers[3]._timer = 1;
1463 	_vm->_timers[3]._initTm = 1;
1464 	++_vm->_timers[3]._flag;
1465 
1466 	_canoeFrame = 0;
1467 	_mapPtr = (const byte *)MAPTBL[_vm->_riverFlag] + 1;
1468 	if (_saveRiver) {
1469 		_mapPtr--;
1470 		_mapPtr += _mapOffset;
1471 	} else {
1472 		_screenVertX = RIVERVXTBL[_vm->_riverFlag] - 320;
1473 		_canoeLane = 3;
1474 		_hitCount = 0;
1475 		_hitSafe = 0;
1476 		_canoeYPos = 71;
1477 	}
1478 
1479 	_riverIndex = _vm->_riverFlag;
1480 	_topList = RIVER_OBJECTS[_riverIndex][RIVER_START];
1481 	updateObstacles();
1482 	riverSetPhysX();
1483 	_canoeDir = 0;
1484 	_deathFlag = false;
1485 	_deathCount = 0;
1486 
1487 	_vm->_timers[11]._timer = 1200;
1488 	_vm->_timers[11]._initTm = 1200;
1489 	++_vm->_timers[11]._flag;
1490 	_vm->_timers[12]._timer = 1500;
1491 	_vm->_timers[12]._initTm = 1500;
1492 	++_vm->_timers[12]._flag;
1493 
1494 	_maxHits = 2 - _vm->_riverFlag;
1495 	_saveRiver = false;
1496 
1497 	// Set font colors for drawing using font2
1498 	Font::_fontColors[0] = 0;
1499 	Font::_fontColors[1] = 33;
1500 	Font::_fontColors[2] = 34;
1501 	Font::_fontColors[3] = 35;
1502 }
1503 
resetPositions()1504 void River::resetPositions() {
1505 	riverSetPhysX();
1506 	int val = (_vm->_scrollCol + 1 - _oldScrollCol) * 16;
1507 	if (val < 0) {
1508 		val |= 0x80;
1509 	}
1510 
1511 	for (int i = 0; i < _pNumObj; i++)
1512 		_pan[i]._pObjX += val;
1513 }
1514 
checkRiverPan()1515 void River::checkRiverPan() {
1516 	int val = _vm->_scrollCol * 16 + 320;
1517 
1518 	for (int i = 0; i < _pNumObj; i++) {
1519 		if (_pan[i]._pObjX < val)
1520 			return;
1521 	}
1522 
1523 	setRiverPan();
1524 }
1525 
riverJumpTest()1526 bool River::riverJumpTest() {
1527 	if (_vm->_scrollCol == 120 || _vm->_scrollCol == 60 || _vm->_scrollCol == 0) {
1528 		int val = *++_mapPtr;
1529 		if (val == 0xFF)
1530 			return true;
1531 
1532 		_oldScrollCol = _vm->_scrollCol;
1533 
1534 		if (val == 0) {
1535 			_vm->_scrollCol = 139;
1536 			_vm->_scrollX = 14;
1537 			_vm->_room->buildScreen();
1538 			resetPositions();
1539 			return false;
1540 		}
1541 	} else if (_vm->_scrollCol == 105) {
1542 		int val1 = _mapPtr[1];
1543 		int val2 = _mapPtr[2];
1544 		_mapPtr += 3;
1545 		if (_canoeLane < 3) {
1546 			if (val1 != 0) {
1547 				_deathFlag = true;
1548 				_deathCount = 300;
1549 				_deathType = val2;
1550 			}
1551 		} else {
1552 			if (val1 != 1) {
1553 				_deathFlag = true;
1554 				_deathCount = 300;
1555 				_deathType = val2;
1556 			}
1557 			_oldScrollCol = _vm->_scrollCol;
1558 			_vm->_scrollCol = 44;
1559 			_vm->_scrollX = 14;
1560 			_vm->_room->buildScreen();
1561 			resetPositions();
1562 			return false;
1563 		}
1564 	}
1565 
1566 	_vm->_scrollX = 14;
1567 	--_vm->_scrollCol;
1568 	_vm->_buffer1.moveBufferRight();
1569 	_vm->_room->buildColumn(_vm->_scrollCol, 0);
1570 	checkRiverPan();
1571 	return false;
1572 }
1573 
riverSound()1574 void River::riverSound() {
1575 	if (_vm->_timers[11]._flag == 0) {
1576 		++_vm->_timers[11]._flag;
1577 		_vm->_sound->playSound(2);
1578 	}
1579 
1580 	if (_vm->_timers[12]._flag == 0) {
1581 		++_vm->_timers[12]._flag;
1582 		_vm->_sound->playSound(3);
1583 	}
1584 
1585 	if ((_xCam >= 1300) && (_xCam <= 1320))
1586 		_vm->_sound->playSound(1);
1587 }
1588 
moveCanoe()1589 void River::moveCanoe() {
1590 	EventsManager &events = *_vm->_events;
1591 	Common::Point pt = events.calcRawMouse();
1592 	Common::Point mousePos = events.getMousePos();
1593 
1594 	// Do an event polling
1595 	_vm->_canSaveLoad = true;
1596 	events.pollEvents();
1597 	_vm->_canSaveLoad = false;
1598 	if (_vm->_room->_function == FN_CLEAR1)
1599 		return;
1600 
1601 	if (_canoeDir) {
1602 		// Canoe movement in progress
1603 		moveCanoe2();
1604 	} else {
1605 		if (events._leftButton && pt.y >= 140) {
1606 			if (pt.x < _vm->_room->_rMouse[8][0]) {
1607 				// Disk icon wasn't clicked
1608 				_vm->_scripts->printString(AMRES.BAR_MESSAGE);
1609 			} else {
1610 				// Clicked on the Disc icon. Show the ScummVM menu
1611 				_vm->_room->handleCommand(9);
1612 
1613 				if (_vm->_room->_function != FN_CLEAR1) {
1614 					_vm->_room->buildScreen();
1615 					_vm->copyBF2Vid();
1616 				}
1617 			}
1618 		} else if (events._leftButton && mousePos.x < 35 && mousePos.y < 12) {
1619 			// Clicked on the Skip button. So chicken out
1620 			_chickenOutFl = true;
1621 		}  else if ((events._leftButton && pt.y <= _canoeYPos) ||
1622 			(!events._leftButton && _vm->_player->_move == UP)) {
1623 			// Move canoe up
1624 			if (_canoeLane > 0) {
1625 				_canoeDir = -1;
1626 				_canoeMoveCount = 0;
1627 
1628 				moveCanoe2();
1629 			}
1630 		} else if (events._leftButton || _vm->_player->_move == DOWN) {
1631 			// Move canoe down
1632 			if (_canoeLane < 7) {
1633 				_canoeDir = 1;
1634 				_canoeMoveCount = 0;
1635 
1636 				moveCanoe2();
1637 			}
1638 		}
1639 	}
1640 }
1641 
moveCanoe2()1642 void River::moveCanoe2() {
1643 	_canoeYPos += _canoeDir;
1644 
1645 	if (++_canoeMoveCount == 5) {
1646 		_canoeLane += _canoeDir;
1647 		_canoeDir = 0;
1648 	}
1649 }
1650 
updateObstacles()1651 void River::updateObstacles() {
1652 	RiverStruct *cur;
1653 	for (cur = _topList; cur < RIVER_OBJECTS[_riverIndex][RIVER_END]; ++cur) {
1654 		int val = cur->_riverX + cur->_width - 1;
1655 		if (val < _screenVertX)
1656 			// Obstacle is not yet on-screen
1657 			break;
1658 
1659 		if (cur->_riverX < (_screenVertX + 319)) {
1660 			// Object is now on-screen. So set _topList/_botList to the range
1661 			// of river obstacles that are currently visible
1662 			_topList = cur;
1663 			_botList = cur;
1664 
1665 			while (cur < RIVER_OBJECTS[_riverIndex][RIVER_END]) {
1666 				++cur;
1667 				val = cur->_riverX + cur->_width - 1;
1668 				if (val < _screenVertX || (cur->_riverX >= (_screenVertX + 319)))
1669 					break;
1670 
1671 				_botList = cur;
1672 			}
1673 
1674 			return;
1675 		}
1676 	}
1677 
1678 	cur = _topList;
1679 	cur--;
1680 	_botList = cur;
1681 }
1682 
riverSetPhysX()1683 void River::riverSetPhysX() {
1684 	int xAmt = (_vm->_scrollCol * 16) + _vm->_scrollX;
1685 
1686 	for (RiverStruct *cur = _topList; cur <= _botList; ++cur) {
1687 		cur->_xp = xAmt - (_screenVertX - cur->_riverX);
1688 	}
1689 }
1690 
checkRiverCollide()1691 bool River::checkRiverCollide() {
1692 	if (_hitSafe)
1693 		return false;
1694 
1695 	_canoeVXPos = _screenVertX + 170;
1696 
1697 	for (RiverStruct *cur = _topList; cur <= _botList; ++cur) {
1698 		if (cur->_lane < _canoeLane)
1699 			continue;
1700 
1701 		if ((cur->_lane == _canoeLane) || (cur->_lane == _canoeLane + 1)) {
1702 			if ((cur->_riverX + cur->_width - 1) >= _canoeVXPos &&
1703 					cur->_riverX < (_canoeVXPos + 124)) {
1704 				_vm->_sound->playSound(4);
1705 				return true;
1706 			}
1707 		}
1708 	}
1709 
1710 	return false;
1711 }
1712 
plotRiver()1713 void River::plotRiver() {
1714 	// Handle cycling through the canoe rowing frames
1715 	if (_vm->_timers[3]._flag == 0) {
1716 		++_vm->_timers[3]._flag;
1717 
1718 		if (_canoeFrame++ == 12)
1719 			_canoeFrame = 0;
1720 	}
1721 
1722 	// Draw the canoe
1723 	ImageEntry ie;
1724 	ie._flags = IMGFLAG_UNSCALED;
1725 	ie._spritesPtr = _vm->_objectsTable[45];
1726 	ie._frameNumber = _canoeFrame;
1727 	ie._position.x = (_vm->_scrollCol * 16) + _vm->_scrollX + 160;
1728 	ie._position.y = _canoeYPos - 41;
1729 	ie._offsetY = 41;
1730 	_vm->_images.addToList(ie);
1731 
1732 	// Draw any on-screen obstacles
1733 	for (RiverStruct *cur = _topList; cur <= _botList; ++cur) {
1734 		if (cur->_id != -1) {
1735 			ie._flags = IMGFLAG_UNSCALED;
1736 			ie._spritesPtr = _vm->_objectsTable[45];
1737 			ie._frameNumber = cur->_id;
1738 			ie._position.x = cur->_xp;
1739 			ie._position.y = (cur->_lane * 5) + 56 - cur->_offsetY;
1740 			ie._offsetY = cur->_offsetY;
1741 			_vm->_images.addToList(ie);
1742 		}
1743 	}
1744 
1745 	// Draw the text for skipping the river
1746 	Font &font2 = *_vm->_fonts._font2;
1747 	font2.drawString(_vm->_screen, "SKIP", Common::Point(5, 5));
1748 }
1749 
mWhileDownRiver()1750 void River::mWhileDownRiver() {
1751 	Screen &screen = *_vm->_screen;
1752 	_vm->_events->hideCursor();
1753 
1754 	screen.setDisplayScan();
1755 	screen.clearScreen();
1756 	screen.savePalette();
1757 	if (!_vm->isDemo())
1758 		_vm->_files->loadScreen(95, 4);
1759 	_vm->_buffer2.blitFrom(*_vm->_screen);
1760 	screen.restorePalette();
1761 	screen.setPalette();
1762 	screen.setBufferScan();
1763 
1764 	_vm->_scrollX = 0;
1765 	_vm->_room->buildScreen();
1766 	_vm->copyBF2Vid();
1767 
1768 	_vm->_player->_scrollAmount = 2;
1769 	_vm->_destIn = &_vm->_buffer2;
1770 	_xTrack = -7;
1771 	_yTrack = _zTrack = 0;
1772 	_xCam = _yCam = 0;
1773 	_zCam = 80;
1774 
1775 	_vm->_timers[24]._timer = 1;
1776 	_vm->_timers[24]._initTm = 1;
1777 	++_vm->_timers[24]._flag;
1778 
1779 	_pNumObj = 14;
1780 	for (int i = 0; i <_pNumObj; i++) {
1781 		_pan[i]._pObject = _vm->_objectsTable[33];
1782 		_pan[i]._pImgNum = DOWNRIVEROBJ[i][0];
1783 		_pan[i]._pObjX = DOWNRIVEROBJ[i][1];
1784 		_pan[i]._pObjY = DOWNRIVEROBJ[i][2];
1785 		_pan[i]._pObjZ = DOWNRIVEROBJ[i][3];
1786 		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
1787 	}
1788 
1789 	_vm->_timers[3]._timer = 200;
1790 	_vm->_timers[3]._initTm = 200;
1791 	++_vm->_timers[3]._flag;
1792 	_vm->_timers[4]._timer = 350;
1793 	_vm->_timers[4]._initTm = 350;
1794 	++_vm->_timers[4]._flag;
1795 
1796 	while (!_vm->shouldQuit() && !_vm->_events->isKeyMousePressed() &&
1797 		(_vm->_scrollCol + screen._vWindowWidth != _vm->_room->_playFieldWidth)) {
1798 		_vm->_images.clear();
1799 		_vm->_events->_vbCount = 6;
1800 
1801 		_vm->_scrollX += _vm->_player->_scrollAmount;
1802 		while (_vm->_scrollX >= TILE_WIDTH) {
1803 			_vm->_scrollX -= TILE_WIDTH;
1804 			++_vm->_scrollCol;
1805 			_vm->_buffer1.moveBufferLeft();
1806 			_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth, screen._vWindowBytesWide);
1807 		}
1808 
1809 		pan();
1810 		scrollRiver();
1811 
1812 		if (!_vm->_timers[3]._flag) {
1813 			++_vm->_timers[3]._flag;
1814 			_vm->_sound->playSound(1);
1815 		} else if (!_vm->_timers[4]._flag) {
1816 			++_vm->_timers[4]._flag;
1817 			_vm->_sound->playSound(0);
1818 		}
1819 
1820 		while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0) {
1821 			_vm->_events->pollEventsAndWait();
1822 		}
1823 	}
1824 
1825 	_vm->_events->showCursor();
1826 }
1827 
scrollRiver()1828 void River::scrollRiver() {
1829 	_vm->copyBF1BF2();
1830 	_vm->_newRects.clear();
1831 	_vm->_buffer2.plotImage(_vm->_objectsTable[33], 0, Common::Point(66, 30));
1832 	_vm->plotList();
1833 	_vm->copyRects();
1834 	_vm->copyBF2Vid();
1835 }
1836 
scrollRiver1()1837 void River::scrollRiver1() {
1838 	_vm->copyBF1BF2();
1839 	_vm->_newRects.clear();
1840 	plotRiver();
1841 	_vm->plotList();
1842 	_vm->copyRects();
1843 	_vm->copyBF2Vid();
1844 }
1845 
doRiver()1846 void River::doRiver() {
1847 	static const int RIVERDEATH[5] = { 22, 23, 24, 25, 26 };
1848 
1849 	initRiver();
1850 	_vm->_events->showCursor();
1851 
1852 	while (!_vm->shouldQuit()) {
1853 		_vm->_events->_vbCount = 4;
1854 
1855 		// Move the river position
1856 		_screenVertX -= _vm->_player->_scrollAmount;
1857 
1858 		if (_vm->_scrollX == 0) {
1859 			_vm->_midi->midiRepeat();
1860 			if (riverJumpTest()) {
1861 				_chickenOutFl = false;
1862 				return;
1863 			}
1864 		} else {
1865 			_vm->_scrollX -= _vm->_player->_scrollAmount;
1866 		}
1867 
1868 		if (_chickenOutFl) {
1869 			_chickenOutFl = false;
1870 			return;
1871 		}
1872 
1873 		_vm->_images.clear();
1874 		_vm->_animation->animate(0);
1875 
1876 		riverSound();
1877 		pan();
1878 		moveCanoe();
1879 
1880 		if (_vm->_room->_function != FN_CLEAR1) {
1881 			updateObstacles();
1882 			riverSetPhysX();
1883 			bool checkCollide = checkRiverCollide();
1884 			if (_hitSafe != 0)
1885 				_hitSafe -= 2;
1886 
1887 			if (checkCollide) {
1888 				_vm->dead(RIVERDEATH[0]);
1889 				return;
1890 			}
1891 
1892 			if (_deathFlag) {
1893 				if (--_deathCount == 0) {
1894 					_vm->dead(RIVERDEATH[_deathType]);
1895 					return;
1896 				}
1897 			}
1898 
1899 			// Scroll the river
1900 			scrollRiver1();
1901 
1902 			// Allow time for new scrolled river position to be shown
1903 			_vm->_canSaveLoad = true;
1904 			while (!_vm->shouldQuit() && _vm->_room->_function == FN_NONE &&
1905 				_vm->_events->_vbCount > 0) {
1906 				_vm->_events->pollEventsAndWait();
1907 			}
1908 			_vm->_canSaveLoad = false;
1909 		}
1910 
1911 		if (_vm->_room->_function == FN_CLEAR1) {
1912 			_vm->_scripts->_endFlag = true;
1913 			_vm->_scripts->_returnCode = 0;
1914 			_chickenOutFl = false;
1915 			break;
1916 		}
1917 	}
1918 }
1919 
synchronize(Common::Serializer & s)1920 void River::synchronize(Common::Serializer &s) {
1921 	if (_vm->_player->_roomNumber == 45) {
1922 		if (s.isSaving()) {
1923 			// Set river properties to be saved out
1924 			_rScrollRow = _vm->_scrollRow;
1925 			_rScrollCol = _vm->_scrollCol;
1926 			_rScrollX = _vm->_scrollX;
1927 			_rScrollY = _vm->_scrollY;
1928 			_mapOffset = _mapPtr - MAPTBL[_vm->_riverFlag];
1929 		}
1930 
1931 		s.syncAsSint16LE(_canoeLane);
1932 		s.syncAsSint16LE(_canoeYPos);
1933 		s.syncAsSint16LE(_hitCount);
1934 		s.syncAsSint16LE(_riverIndex);
1935 		s.syncAsSint16LE(_hitSafe);
1936 		s.syncAsUint16LE(_rScrollRow);
1937 		s.syncAsUint16LE(_rScrollCol);
1938 		s.syncAsSint16LE(_rScrollX);
1939 		s.syncAsSint16LE(_rScrollY);
1940 		s.syncAsUint16LE(_mapOffset);
1941 		s.syncAsUint16LE(_screenVertX);
1942 
1943 		_saveRiver = s.isLoading();
1944 	}
1945 }
1946 
1947 /*------------------------------------------------------------------------*/
1948 
Ant(AmazonEngine * vm)1949 Ant::Ant(AmazonEngine *vm) : AmazonManager(vm) {
1950 	_antDirection = ANT_RIGHT;
1951 	_pitDirection = ANT_RIGHT;
1952 	_antCel = 0;
1953 	_torchCel = 0;
1954 	_pitCel = 0;
1955 	_stabCel = 0;
1956 	_antPos = Common::Point(0, 0);
1957 	_antDieFl = _antEatFl = false;
1958 	_stabFl = false;
1959 	_pitPos = Common::Point(0, 0);
1960 }
1961 
plotTorchSpear(int indx,const int * & buf)1962 void Ant::plotTorchSpear(int indx, const int *&buf) {
1963 	int idx = indx;
1964 
1965 	ImageEntry ie;
1966 	ie._flags = IMGFLAG_UNSCALED;
1967 	ie._spritesPtr = _vm->_objectsTable[62];
1968 	ie._frameNumber = buf[(idx / 2)];
1969 	ie._position = Common::Point(_pitPos.x + buf[(idx / 2) + 1], _pitPos.y + buf[(idx / 2) + 2]);
1970 	ie._offsetY = 255;
1971 	_vm->_images.addToList(ie);
1972 }
1973 
plotPit(int indx,const int * & buf)1974 void Ant::plotPit(int indx, const int *&buf) {
1975 	int idx = indx;
1976 	ImageEntry ie;
1977 	ie._flags = IMGFLAG_UNSCALED;
1978 	ie._spritesPtr = _vm->_objectsTable[62];
1979 	ie._frameNumber = buf[(idx / 2)];
1980 	ie._position = Common::Point(_pitPos.x, _pitPos.y);
1981 	ie._offsetY = _pitPos.y;
1982 	_vm->_images.addToList(ie);
1983 
1984 	_vm->_player->_rawPlayer = _pitPos;
1985 	if (_vm->_inventory->_inv[INV_TORCH]._value == ITEM_IN_INVENTORY) {
1986 		// Player has torch
1987 		idx = _torchCel;
1988 		buf = Amazon::TORCH;
1989 		_vm->_timers[14]._flag = 1;
1990 		idx += 6;
1991 		if (buf[idx / 2] == -1)
1992 			idx = 0;
1993 		_torchCel = idx;
1994 		plotTorchSpear(idx, buf);
1995 	} else if (!_stabFl && (_vm->_inventory->_inv[INV_KNIFE_SPEAR]._value == ITEM_IN_INVENTORY)) {
1996 		// Player has spear
1997 		idx = 0;
1998 		buf = Amazon::SPEAR;
1999 		plotTorchSpear(idx, buf);
2000 	}
2001 }
2002 
antHandleRight(int indx,const int * & buf)2003 int Ant::antHandleRight(int indx, const int *&buf) {
2004 	int retval = indx;
2005 	if (_pitDirection == ANT_RIGHT) {
2006 		_pitDirection = ANT_LEFT;
2007 		_pitPos.y = 127;
2008 	}
2009 	retval = _pitCel;
2010 	buf = Amazon::PITWALK;
2011 	if (_pitPos.x < 230) {
2012 		if (retval == 0) {
2013 			retval = 48;
2014 			_pitPos.y = 127;
2015 		}
2016 		retval -= 6;
2017 		_pitPos.x -= buf[(retval / 2) + 1];
2018 		_pitPos.y -= buf[(retval / 2) + 2];
2019 		_pitCel = retval;
2020 	}
2021 	return retval;
2022 }
2023 
antHandleLeft(int indx,const int * & buf)2024 int Ant::antHandleLeft(int indx, const int *&buf) {
2025 	int retval = indx;
2026 	if (_pitDirection == ANT_LEFT) {
2027 		_pitDirection = ANT_RIGHT;
2028 		_pitPos.y = 127;
2029 	}
2030 	retval = _pitCel;
2031 	buf = Amazon::PITWALK;
2032 	retval += 6;
2033 	if (buf[retval / 2] == -1) {
2034 		retval = 0;
2035 		_pitPos.y = 127;
2036 	}
2037 	_pitPos.x += buf[(retval / 2) + 1];
2038 	_pitPos.y += buf[(retval / 2) + 2];
2039 	_pitCel = retval;
2040 
2041 	return retval;
2042 }
2043 
antHandleStab(int indx,const int * & buf)2044 int Ant::antHandleStab(int indx, const int *&buf) {
2045 	int retval = indx;
2046 	if (_vm->_inventory->_inv[INV_KNIFE_SPEAR]._value == ITEM_IN_INVENTORY) {
2047 		if (_stabFl) {
2048 			buf = Amazon::PITSTAB;
2049 			retval = _stabCel;
2050 			if (_vm->_timers[13]._flag == 0) {
2051 				_vm->_timers[13]._flag = 1;
2052 				retval += 6;
2053 				_stabCel = retval;
2054 
2055 				if (buf[retval] == -1) {
2056 					_stabFl = false;
2057 					_pitCel = 0;
2058 					_pitPos.y = 127;
2059 					retval = 0;
2060 					buf = Amazon::PITWALK;
2061 				} else {
2062 					_pitPos.x += buf[(retval / 2) + 1];
2063 					_pitPos.y += buf[(retval / 2) + 2];
2064 					_pitCel = retval;
2065 				}
2066 			}
2067 		} else {
2068 			_stabFl = true;
2069 			_pitCel = 0;
2070 			retval = 0;
2071 			_stabCel = 0;
2072 			int dist = _pitPos.x - _antPos.x;
2073 			if (_antEatFl && !_antDieFl && (dist <= 80)) {
2074 				_antDieFl = true;
2075 				_antCel = 0;
2076 				_antPos.y = 123;
2077 				_vm->_sound->playSound(1);
2078 			}
2079 		}
2080 	}
2081 
2082 	return retval;
2083 }
2084 
doAnt()2085 void Ant::doAnt() {
2086 	_antDirection = ANT_RIGHT;
2087 	if (_vm->_aniFlag != 1) {
2088 		_vm->_aniFlag = 1;
2089 		_antCel = 0;
2090 		_torchCel = 0;
2091 		_pitCel = 0;
2092 
2093 		_vm->_timers[15]._timer = 16;
2094 		_vm->_timers[15]._initTm = 16;
2095 		_vm->_timers[15]._flag = 1;
2096 
2097 		_vm->_timers[13]._timer = 5;
2098 		_vm->_timers[13]._initTm = 5;
2099 		_vm->_timers[13]._flag = 1;
2100 
2101 		_vm->_timers[14]._timer = 10;
2102 		_vm->_timers[14]._initTm = 10;
2103 		_vm->_timers[14]._flag = 1;
2104 
2105 		_antPos = Common::Point(-40, 123);
2106 		_antDieFl = _antEatFl = false;
2107 		_stabFl = false;
2108 		_pitPos = Common::Point(_vm->_player->_rawPlayer.x, 127);
2109 	}
2110 
2111 	const int *buf = nullptr;
2112 	if (_antDieFl) {
2113 		buf = Amazon::ANTDIE;
2114 	} else if (_antEatFl) {
2115 		buf = Amazon::ANTEAT;
2116 	} else if (_antPos.x > 120 && _vm->_flags[198] == 1) {
2117 		_antEatFl = true;
2118 		_vm->_flags[235] = 1;
2119 		_antCel = 0;
2120 		buf = Amazon::ANTEAT;
2121 	} else {
2122 		buf = Amazon::ANTWALK;
2123 		if (_vm->_inventory->_inv[INV_TORCH]._value == ITEM_IN_INVENTORY)
2124 			// Player has burning torch, which scares the Ant
2125 			_antDirection = ANT_LEFT;
2126 	}
2127 
2128 	int idx = _antCel;
2129 	if (_vm->_timers[15]._flag == 0) {
2130 		_vm->_timers[15]._flag = 1;
2131 		if (_antDirection == ANT_LEFT) {
2132 			if (_antPos.x > 10) {
2133 				if (idx == 0)
2134 					idx = 36;
2135 				else
2136 					idx -= 6;
2137 
2138 				_antPos -= Common::Point(buf[(idx / 2) + 1], buf[(idx / 2) + 2]);
2139 				_antCel = idx;
2140 			}
2141 		} else {
2142 			idx += 6;
2143 			if (buf[(idx / 2)] != -1) {
2144 				_antPos += Common::Point(buf[(idx / 2) + 1], buf[(idx / 2) + 2]);
2145 				_antCel = idx;
2146 			} else if (!_antDieFl) {
2147 				idx = 0;
2148 				_antPos += Common::Point(buf[(idx / 2) + 1], buf[(idx / 2) + 2]);
2149 				_antCel = idx;
2150 			} else {
2151 				idx -= 6;
2152 				if (_vm->_flags[200] == 0)
2153 					_vm->_flags[200] = 1;
2154 			}
2155 		}
2156 	}
2157 
2158 	ImageEntry ie;
2159 	ie._flags = IMGFLAG_UNSCALED;
2160 	ie._spritesPtr = _vm->_objectsTable[61];
2161 	ie._frameNumber = buf[(idx / 2)];
2162 	ie._position = Common::Point(_antPos.x, _antPos.y);
2163 	ie._offsetY = _antPos.y - 70;
2164 	_vm->_images.addToList(ie);
2165 	_antCel = idx;
2166 
2167 	if (_vm->_flags[196] != 1) {
2168 		idx = _pitCel;
2169 		if (_stabFl) {
2170 			idx = antHandleStab(idx, buf);
2171 		} else {
2172 			buf = Amazon::PITWALK;
2173 			if (_vm->_timers[13]._flag == 0) {
2174 				_vm->_timers[13]._flag = 1;
2175 				_vm->_events->pollEvents();
2176 				if (_vm->_events->_leftButton) {
2177 					// Handle moving the player whilst the mouse button is held down
2178 					Common::Point pt = _vm->_events->calcRawMouse();
2179 					if (pt.x < _pitPos.x)
2180 						idx = antHandleLeft(idx, buf);
2181 					else if (pt.x > _pitPos.x)
2182 						idx = antHandleRight(idx, buf);
2183 				} else {
2184 					// Handle movement based on keyboard keys
2185 					buf = Amazon::PITWALK;
2186 					if (_vm->_player->_move == UP)
2187 						idx = antHandleStab(idx, buf);
2188 					else if (_vm->_player->_move == LEFT)
2189 						idx = antHandleLeft(idx, buf);
2190 					else if (_vm->_player->_move == RIGHT)
2191 						idx = antHandleRight(idx, buf);
2192 				}
2193 			}
2194 		}
2195 		plotPit(idx, buf);
2196 	}
2197 
2198 	if (!_antDieFl) {
2199 		int dist = _pitPos.x - _antPos.x;
2200 		if ((_antEatFl && (dist <= 45)) || (!_antEatFl && (dist <= 80))) {
2201 			_vm->_flags[199] = 1;
2202 			_vm->_aniFlag = 0;
2203 		}
2204 	}
2205 }
2206 
synchronize(Common::Serializer & s)2207 void Ant::synchronize(Common::Serializer &s) {
2208 	if (_vm->_player->_roomNumber == 61) {
2209 		s.syncAsByte(_antDirection);
2210 		s.syncAsByte(_pitDirection);
2211 		s.syncAsSint16LE(_antCel);
2212 		s.syncAsSint16LE(_torchCel);
2213 		s.syncAsSint16LE(_pitCel);
2214 		s.syncAsSint16LE(_stabCel);
2215 		s.syncAsSint16LE(_antPos.x);
2216 		s.syncAsSint16LE(_antPos.y);
2217 		s.syncAsSint16LE(_pitPos.x);
2218 		s.syncAsSint16LE(_pitPos.y);
2219 		s.syncAsByte(_antDieFl);
2220 		s.syncAsByte(_antEatFl);
2221 		s.syncAsByte(_stabFl);
2222 	}
2223 }
2224 
2225 
2226 } // End of namespace Amazon
2227 
2228 } // End of namespace Access
2229