/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "common/scummsys.h"
#include "access/access.h"
#include "access/resources.h"
#include "access/screen.h"
#include "access/amazon/amazon_game.h"
#include "access/amazon/amazon_logic.h"
#include "access/amazon/amazon_resources.h"

namespace Access {

namespace Amazon {

PannedScene::PannedScene(AmazonEngine *vm) : AmazonManager(vm) {
	for (int i = 0; i < PAN_SIZE; ++i) {
		_pan[i]._pObject = nullptr;
		_pan[i]._pImgNum = 0;
		_pan[i]._pObjX = _pan[i]._pObjY = _pan[i]._pObjZ = 0;
		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
	}

	_xCount = 0;
	_xTrack = _yTrack = _zTrack = 0;
	_xCam = _yCam = _zCam = 0;
	_pNumObj = 0;
}

void PannedScene::pan() {
	_zCam += _zTrack;
	_xCam += _xTrack;
	int tx = (_xTrack << 8) / _zCam;
	_yCam += _yTrack;
	int ty = (_yTrack << 8) / _zCam;

	if (_vm->_timers[24]._flag != 1) {
		++_vm->_timers[24]._flag;
		for (int i = 0; i < _pNumObj; i++) {
			_pan[i]._pObjZ += _zTrack;
			_pan[i]._pObjXl += (_pan[i]._pObjZ * tx) & 0xff;
			_pan[i]._pObjX += ((_pan[i]._pObjZ * tx) >> 8) + (_pan[i]._pObjXl >> 8);
			_pan[i]._pObjXl &= 0xff;

			_pan[i]._pObjYl += (_pan[i]._pObjZ * ty) & 0xff;
			_pan[i]._pObjY += ((_pan[i]._pObjZ * ty) >> 8) + (_pan[i]._pObjYl >> 8);
			_pan[i]._pObjYl &= 0xff;
		}
	}

	for (int i = 0; i < _pNumObj; i++) {
		ImageEntry ie;
		ie._flags = IMGFLAG_UNSCALED;
		ie._position = Common::Point(_pan[i]._pObjX, _pan[i]._pObjY);
		ie._offsetY = 255;
		ie._spritesPtr = _pan[i]._pObject;
		ie._frameNumber = _pan[i]._pImgNum;

		_vm->_images.addToList(ie);
	}
}

/*------------------------------------------------------------------------*/

CampScene::CampScene(AmazonEngine *vm) : PannedScene(vm) {
	_skipStart = false;
}

void CampScene::mWhileDoOpen() {
	Screen &screen = *_vm->_screen;
	EventsManager &events = *_vm->_events;

	screen.setDisplayScan();
	events.hideCursor();
	screen.forceFadeOut();
	_skipStart = false;
	if (_vm->_conversation != 2) {
		// Cutscene at start of chapter 1
		screen.setPanel(3);
		_vm->startChapter(1);
		_vm->establishCenter(0, 1);
	}

	Resource *data = _vm->_files->loadFile(1, 0);
	_vm->_objectsTable[1] = new SpriteResource(_vm, data);
	delete data;

	_vm->_files->_setPaletteFlag = false;
	_vm->_files->loadScreen(1, 2);
	_vm->_buffer2.blitFrom(*_vm->_screen);
	_vm->_buffer1.blitFrom(*_vm->_screen);

	// Load animation data
	_vm->_animation->freeAnimationData();
	Resource *animResource = _vm->_files->loadFile(1, 1);
	_vm->_animation->loadAnimations(animResource);
	delete animResource;

	_xTrack = 8;
	_yTrack = -3;
	_zTrack = 0;
	_xCam = _yCam = 0;
	_zCam = 270;
	_vm->_timers[24]._timer = _vm->_timers[24]._initTm = 1;
	++_vm->_timers[24]._flag;
	_vm->_timers.updateTimers();

	_pNumObj = 10;
	for (int i = 0; i < _pNumObj; i++) {
		_pan[i]._pObject = _vm->_objectsTable[1];
		_pan[i]._pImgNum = OPENING_OBJS[i][0];
		_pan[i]._pObjX = OPENING_OBJS[i][1];
		_pan[i]._pObjY = OPENING_OBJS[i][2];
		_pan[i]._pObjZ = OPENING_OBJS[i][3];
		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
	}

	_vm->_oldRects.clear();
	_vm->_newRects.clear();
	Animation *anim = _vm->_animation->setAnimation(0);
	_vm->_animation->setAnimTimer(anim);
	anim = _vm->_animation->setAnimation(1);
	_vm->_animation->setAnimTimer(anim);
	_vm->_midi->newMusic(10, 0);

	bool startFl = false;
	while (!_vm->shouldQuit()) {
		_vm->_images.clear();
		_vm->_animation->animate(0);
		_vm->_animation->animate(1);
		pan();
		_vm->_buffer2.copyFrom(_vm->_buffer1);
		_vm->_newRects.clear();
		_vm->plotList();
		_vm->copyBlocks();
		if (!startFl) {
			startFl = true;
			screen.forceFadeIn();
		}

		events.pollEventsAndWait();

		if (_vm->_events->isKeyMousePressed()) {
			_skipStart = true;
			_vm->_midi->newMusic(10, 1);
			break;
		}

		if (_xCam > 680) {
			events._vbCount = 125;

			while (!_vm->shouldQuit() && !events.isKeyMousePressed() && events._vbCount > 0) {
				events.pollEventsAndWait();
			}
			break;
		}
	}

	events.showCursor();
	_vm->_buffer2.copyFrom(*_vm->_screen);
	_vm->_buffer1.copyFrom(*_vm->_screen);

	_vm->freeCells();
	_vm->_oldRects.clear();
	_vm->_newRects.clear();
	_vm->_numAnimTimers = 0;
	_vm->_images.clear();

	if (_vm->isCD()) {
		if (_vm->_conversation == 2) {
			// Cutscene at end of Chapter 6
			Resource *spriteData = _vm->_files->loadFile(28, 37);
			_vm->_objectsTable[28] = new SpriteResource(_vm, spriteData);
			delete spriteData;

			_vm->_animation->freeAnimationData();
			animResource = _vm->_files->loadFile(28, 38);
			_vm->_animation->loadAnimations(animResource);
			delete animResource;
		}
	} else {
		_vm->freeCells();
		_vm->_oldRects.clear();
		_vm->_newRects.clear();
		_vm->_numAnimTimers = 0;
		_vm->_images.clear();
	}
}

/*------------------------------------------------------------------------*/

Opening::Opening(AmazonEngine *vm) : CampScene(vm) {
	_pCount = 0;
}

void Opening::doIntroduction() {
	Screen &screen = *_vm->_screen;

	screen.setInitialPalettte();
	_vm->_events->setCursor(CURSOR_ARROW);
	_vm->_events->showCursor();
	screen.setPanel(0);
	screen.setPalette();

	_vm->_events->setCursor(CURSOR_ARROW);
	_vm->_events->showCursor();
	screen.setPanel(3);
	doTitle();

	if (_vm->shouldQuit() || _skipStart || _vm->isDemo())
		return;

	screen.setPanel(3);
	mWhileDoOpen();

	if (_vm->shouldQuit() || _skipStart)
		return;

	doTent();
}

void Opening::doCredit() {
	if (_pCount < 15)
		return;

	if (_pCount <= 75)
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], _vm->isDemo()? 24 : 0, Common::Point(90, 35));
	else if (_pCount <= 210)
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 1, Common::Point(65, 35));
	else if (_pCount <= 272)
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 2, Common::Point(96, 45));
	else if (_pCount <= 334)
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 3, Common::Point(68, 54));
	else if (_pCount <= 396)
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 4, Common::Point(103, 54));
	else if (_pCount <= 458) {
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 5, Common::Point(8, 5));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 12, Common::Point(88, 55));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 6, Common::Point(194, 98));
	} else if (_pCount <= 520) {
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 7, Common::Point(32, 13));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 8, Common::Point(162, 80));
	} else if (_pCount <= 580) {
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 9, Common::Point(18, 15));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 10, Common::Point(164, 81));
	} else
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 11, Common::Point(106, 55));
}

void Opening::doCreditDemo() {
	if (_pCount < 15)
		return;

	if (_pCount <= 75)
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], _vm->isDemo()? 24 : 0, Common::Point(90, 35));
	else if (_pCount <= 210)
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 25, Common::Point(82, 35));
	else if (_pCount <= 272) {
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 23, Common::Point(77, 20));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 4, Common::Point(50, 35));
	} else if (_pCount <= 334) {
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 16, Common::Point(200, 70));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 4, Common::Point(170, 85));
	} else if (_pCount <= 396) {
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 15, Common::Point(65, 15));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 2, Common::Point(30, 30));
	} else if (_pCount <= 458) {
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 19, Common::Point(123, 40));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 10, Common::Point(115, 55));
	} else if (_pCount <= 520) {
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 18, Common::Point(50, 15));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 9, Common::Point(40, 30));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 0, Common::Point(40, 55));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 20, Common::Point(198, 95));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 3, Common::Point(160, 110));
	} else if (_pCount <= 580) {
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 21, Common::Point(40, 10));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 6, Common::Point(20, 25));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 22, Common::Point(145, 50));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 7, Common::Point(125, 65));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 12, Common::Point(207, 90));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 5, Common::Point(200, 105));
	} else {
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 11, Common::Point(125, 30));
		_vm->_buffer2.plotImage(_vm->_objectsTable[0], 4, Common::Point(115, 45));
	}
}

void Opening::scrollTitle() {
	_vm->copyBF1BF2();
	_vm->_newRects.clear();
	if (_vm->isDemo())
		doCreditDemo();
	else
		doCredit();
	_vm->copyRects();
	_vm->copyBF2Vid();
}

void Opening::doTitle() {
	Screen &screen = *_vm->_screen;

	screen.setDisplayScan();

	screen.forceFadeOut();
	_vm->_events->hideCursor();

	if (!_vm->isDemo()) {
		_vm->_sound->loadSoundTable(0, 98, 30);
		_vm->_sound->loadSoundTable(1, 98, 8);

		_vm->_files->_setPaletteFlag = false;
		_vm->_files->loadScreen(0, 3);

		_vm->_buffer2.copyFrom(*_vm->_screen);
		_vm->_buffer1.copyFrom(*_vm->_screen);
		screen.forceFadeIn();

		_vm->_sound->playSound(1, true);

		Resource *spriteData = _vm->_files->loadFile(0, 2);
		_vm->_objectsTable[0] = new SpriteResource(_vm, spriteData);
		delete spriteData;

		_vm->_files->_setPaletteFlag = false;
		_vm->_files->loadScreen(0, 4);

		_vm->_buffer2.copyFrom(*_vm->_screen);
		_vm->_buffer1.copyFrom(*_vm->_screen);

		const int COUNTDOWN[6] = { 2, 0x80, 1, 0x7d, 0, 0x87 };
		for (_pCount = 0; _pCount < 3 && !_vm->shouldQuit(); ++_pCount) {
			_vm->_buffer2.blitFrom(_vm->_buffer1);
			int id = COUNTDOWN[_pCount * 2];
			int xp = COUNTDOWN[_pCount * 2 + 1];
			_vm->_buffer2.plotImage(_vm->_objectsTable[0], id, Common::Point(xp, 71));
			_vm->_buffer2.copyTo(_vm->_screen);

			_vm->_events->_vbCount = 70;
			while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0 && !_skipStart) {
				_vm->_events->pollEventsAndWait();
				if (_vm->_events->_rightButton)
					_skipStart = true;
			}
		}
		if (_vm->shouldQuit())
			return;

		_vm->_sound->stopSound();
		_vm->_sound->checkSoundQueue(); // HACK: Clear sound 1 from the queue
		_vm->_sound->playSound(0);
		screen.forceFadeOut();
		_vm->_events->_vbCount = 100;
		while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
			_vm->_events->pollEventsAndWait();
		if (_vm->shouldQuit())
			return;

		_vm->_sound->freeSounds();
		delete _vm->_objectsTable[0];
		_vm->_objectsTable[0] = nullptr;

		_vm->_files->_setPaletteFlag = false;
		_vm->_files->loadScreen(0, 5);
		_vm->_buffer2.blitFrom(*_vm->_screen);
		_vm->_buffer1.blitFrom(*_vm->_screen);
		screen.forceFadeIn();
		_vm->_midi->newMusic(1, 0);
		_vm->_events->_vbCount = 950;
		while (!_vm->shouldQuit() && (_vm->_events->_vbCount > 0) && !_vm->_events->isKeyMousePressed()) {
			_vm->_events->pollEventsAndWait();
		}

		if (_vm->_events->_rightButton) {
			_skipStart = true;
			_vm->_room->clearRoom();
			_vm->_events->showCursor();
			return;
		}

		_vm->_midi->newMusic(1, 1);
		_vm->_midi->setLoop(false);
		_vm->_events->zeroKeys();
	}

	_vm->_buffer1.create(_vm->_screen->w + TILE_WIDTH, _vm->_screen->h);
	_vm->_room->loadRoom(0);
	screen.clearScreen();
	screen.setBufferScan();
	_vm->_scrollRow = _vm->_scrollCol = 0;
	_vm->_scrollX = _vm->_scrollY = 0;
	_vm->_player->_rawPlayer = Common::Point(0, 0);
	screen.forceFadeOut();
	_vm->_room->buildScreen();
	_vm->copyBF2Vid();
	screen.forceFadeIn();
	_vm->_oldRects.clear();
	_vm->_newRects.clear();
	_vm->_events->clearEvents();
	_vm->_player->_scrollAmount = 1;
	_pCount = 0;

	while (!_vm->shouldQuit()) {
		if (_vm->_events->isKeyMousePressed()) {
			if (_vm->_events->_rightButton)
				_skipStart = true;
			_vm->_room->clearRoom();
			_vm->_events->showCursor();
			return;
		}

		_vm->_events->_vbCount = 4;
		if (_vm->_scrollCol + screen._vWindowWidth != _vm->_room->_playFieldWidth) {
			_vm->_scrollX += _vm->_player->_scrollAmount;

			while (_vm->_scrollX >= TILE_WIDTH) {
				_vm->_scrollX -= TILE_WIDTH;
				++_vm->_scrollCol;

				_vm->_buffer1.moveBufferLeft();
				_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth, screen._vWindowBytesWide);
			}
			scrollTitle();
			++_pCount;

			while (!_vm->shouldQuit() && (_vm->_events->_vbCount > 0)) {
				_vm->_events->pollEventsAndWait();
			}
			continue;
		}

		_vm->_events->_vbCount = 120;
		while (!_vm->shouldQuit() && (_vm->_events->_vbCount > 0))
			_vm->_events->pollEventsAndWait();

		while (!_vm->shouldQuit()) {
			_pCount = 0;
			_vm->_events->_vbCount = 3;
			if (_vm->_scrollRow + screen._vWindowHeight >= _vm->_room->_playFieldHeight) {
				_vm->_room->clearRoom();
				_vm->_events->showCursor();
				return;
			}

			_vm->_scrollY = _vm->_scrollY + _vm->_player->_scrollAmount;

			while (_vm->_scrollY >= TILE_HEIGHT && !_vm->shouldQuit()) {
				_vm->_scrollY -= TILE_HEIGHT;
				++_vm->_scrollRow;
				_vm->_buffer1.moveBufferUp();

				// WORKAROUND: the original was using screen._vWindowBytesWide * screen._vWindowLinesTall
				_vm->_room->buildRow(_vm->_scrollRow + screen._vWindowHeight, screen._vWindowLinesTall);

				if (_vm->_scrollRow + screen._vWindowHeight >= _vm->_room->_playFieldHeight) {
					_vm->_room->clearRoom();
					_vm->_events->showCursor();
					return;
				}
			}
			scrollTitle();
			while (!_vm->shouldQuit() && (_vm->_events->_vbCount > 0))
				_vm->_events->pollEventsAndWait();
		}
	}
}

void Opening::doTent() {
	int step = 0;
	_vm->_screen->setDisplayScan();
	_vm->_screen->forceFadeOut();
	_vm->_events->hideCursor();
	_vm->_sound->loadSoundTable(0, 98, 39);
	_vm->_sound->loadSoundTable(1, 98, 14);
	_vm->_sound->loadSoundTable(2, 98, 15);
	_vm->_sound->loadSoundTable(3, 98, 16);
	_vm->_sound->loadSoundTable(4, 98, 31, 2);
	_vm->_sound->loadSoundTable(5, 98, 52, 2);
	_vm->_sound->playSound(0);

	_vm->_files->_setPaletteFlag = false;
	_vm->_files->loadScreen(2, 0);
	_vm->_buffer2.blitFrom(*_vm->_screen);
	_vm->_buffer1.blitFrom(*_vm->_screen);
	_vm->_screen->forceFadeIn();

	_vm->_video->setVideo(_vm->_screen, Common::Point(126, 73), FileIdent(2, 1), 10);
	int previousFrame = -1;
	while (!_vm->shouldQuit() && !_vm->_video->_videoEnd) {
		_vm->_video->playVideo();
		if (previousFrame != _vm->_video->_videoFrame) {
			previousFrame = _vm->_video->_videoFrame;

			if ((_vm->_video->_videoFrame == 32) || (_vm->_video->_videoFrame == 34))
				_vm->_sound->playSound(4);
			else if (_vm->_video->_videoFrame == 36) {
				if (step != 2) {
					_vm->_sound->playSound(2);
					step = 2;
				}
			} else if (_vm->_video->_videoFrame == 18) {
				if (step != 1) {
					_vm->_midi->newMusic(73, 1);
					_vm->_midi->newMusic(11, 0);
					step = 1;
					_vm->_sound->playSound(1);
				}
			}
		}
		_vm->_events->pollEventsAndWait();
	}

	_vm->_sound->playSound(5);
	_vm->_video->setVideo(_vm->_screen, Common::Point(43, 11), FileIdent(2, 2), 10);
	previousFrame = -1;
	while (!_vm->shouldQuit() && !_vm->_video->_videoEnd) {
		_vm->_video->playVideo();
		if (previousFrame != _vm->_video->_videoFrame) {
			previousFrame = _vm->_video->_videoFrame;
			if (_vm->_video->_videoFrame == 26) {
				_vm->_sound->playSound(5);
			} else if (_vm->_video->_videoFrame == 15) {
				if (step !=3) {
					_vm->_sound->playSound(3);
					step = 3;
				}
			}
		}
		_vm->_events->pollEventsAndWait();
	}

	_vm->_events->_vbCount = 200;
	while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
		_vm->_events->pollEventsAndWait();

	_vm->_events->showCursor();
	_vm->_midi->newMusic(11, 1);
	_vm->_sound->_soundTable.clear();

	_vm->establishCenter(0, 4);
}

/*------------------------------------------------------------------------*/

Plane::Plane(AmazonEngine *vm) : PannedScene(vm) {
	_pCount = 0;
	_planeCount = 0;
	_propCount = 0;
}


void Plane::doFlyCell() {
	SpriteResource *sprites = _vm->_objectsTable[15];

	if (_pCount <= 40) {
		_vm->_buffer2.plotImage(sprites, 3, Common::Point(70, 74));
	} else if (_pCount <= 80) {
		_vm->_buffer2.plotImage(sprites, 6, Common::Point(70, 74));
	} else if (_pCount <= 120) {
		_vm->_buffer2.plotImage(sprites, 2, Common::Point(50, 76));
	} else if (_pCount <= 160) {
		_vm->_buffer2.plotImage(sprites, 14, Common::Point(63, 78));
	} else if (_pCount <= 200) {
		_vm->_buffer2.plotImage(sprites, 5, Common::Point(86, 74));
	} else if (_pCount <= 240) {
		_vm->_buffer2.plotImage(sprites, 0, Common::Point(103, 76));
	} else if (_pCount <= 280) {
		_vm->_buffer2.plotImage(sprites, 4, Common::Point(119, 77));
	} else {
		_vm->_buffer2.plotImage(sprites, 1, Common::Point(111, 77));
	}

	if (_planeCount == 11 || _planeCount == 12)
		++_position.y;
	else if (_planeCount >= 28)
		--_position.y;

	_vm->_buffer2.plotImage(sprites, 7, _position);
	_vm->_buffer2.plotImage(sprites, 8 + _propCount, Common::Point(
		_position.x + 99, _position.y + 10));
	_vm->_buffer2.plotImage(sprites, 11 + _propCount, Common::Point(
		_position.x + 104, _position.y + 18));

	if (++_planeCount >= 30)
		_planeCount = 0;
	if (++_propCount >= 3)
		_propCount = 0;

	++_xCount;
	if (_xCount == 1)
		++_position.x;
	else
		_xCount = 0;
}

void Plane::doFallCell() {
	if (_vm->_scaleI <= 20)
		return;

	SpriteFrame *frame = _vm->_objectsTable[20]->getFrame(_planeCount / 6);
	Common::Rect r(115, 11, 115 + _vm->_screen->_scaleTable1[frame->w],
		11 + _vm->_screen->_scaleTable1[frame->h]);
	_vm->_buffer2.sPlotF(frame, r);

	_vm->_scaleI -= 3;
	_vm->_scale = _vm->_scaleI;
	_vm->_screen->setScaleTable(_vm->_scale);
	++_xCount;
	if (_xCount == 5)
		return;
	_xCount = 0;
	if (_planeCount == 18)
		_planeCount = 0;
	else
		_planeCount += 6;
}

void Plane::scrollFly() {
	_vm->copyBF1BF2();
	_vm->_newRects.clear();
	doFlyCell();
	_vm->copyRects();
	_vm->copyBF2Vid();
}

void Plane::scrollFall() {
	_vm->copyBF1BF2();
	_vm->_newRects.clear();
	doFallCell();
	_vm->copyRects();
	_vm->copyBF2Vid();
}

void Plane::mWhileFly() {
	Screen &screen = *_vm->_screen;
	Player &player = *_vm->_player;
	EventsManager &events = *_vm->_events;

	events.hideCursor();
	screen.clearScreen();
	screen.setBufferScan();
	screen.fadeOut();
	_vm->_scrollX = 0;

	_vm->_room->buildScreen();
	_vm->copyBF2Vid();
	screen.fadeIn();
	_vm->_oldRects.clear();
	_vm->_newRects.clear();
	_vm->_events->clearEvents();

	_vm->_scrollRow = _vm->_scrollCol = 0;
	_vm->_scrollX = _vm->_scrollY = 0;
	player._rawPlayer = Common::Point(0, 0);
	player._scrollAmount = 1;

	_pCount = 0;
	_planeCount = 0;
	_propCount = 0;
	_xCount = 0;
	_position = Common::Point(20, 29);

	while (!_vm->shouldQuit() && !events.isKeyMousePressed() &&
		((_vm->_scrollCol + screen._vWindowWidth) != _vm->_room->_playFieldWidth)) {
		events._vbCount = 4;
		_vm->_scrollX += player._scrollAmount;

		while (_vm->_scrollX >= TILE_WIDTH) {
			_vm->_scrollX -= TILE_WIDTH;
			++_vm->_scrollCol;

			_vm->_buffer1.moveBufferLeft();
			_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth, screen._vWindowBytesWide);
		}

		scrollFly();
		++_pCount;

		while (!_vm->shouldQuit() && events._vbCount > 0) {
			_vm->_sound->playSound(0);
			events.pollEventsAndWait();
		}
	}

	events.showCursor();
}

void Plane::mWhileFall() {
	Screen &screen = *_vm->_screen;
	EventsManager &events = *_vm->_events;

	events.hideCursor();
	screen.clearScreen();
	screen.setBufferScan();
	screen.fadeOut();
	_vm->_scrollX = 0;

	_vm->_room->buildScreen();
	_vm->copyBF2Vid();
	screen.fadeIn();
	_vm->_oldRects.clear();
	_vm->_newRects.clear();
	_vm->_events->clearEvents();

	_vm->_scrollRow = _vm->_scrollCol = 0;
	_vm->_scrollX = _vm->_scrollY = 0;
	_vm->_player->_scrollAmount = 3;
	_vm->_scaleI = 255;

	_xCount = 0;
	_planeCount = 0;

	while (!_vm->shouldQuit() && !events.isKeyMousePressed() &&
		(_vm->_scrollCol + screen._vWindowWidth != _vm->_room->_playFieldWidth)) {
		events._vbCount = 4;
		_vm->_scrollX += _vm->_player->_scrollAmount;

		while (_vm->_scrollX >= TILE_WIDTH) {
			_vm->_scrollX -= TILE_WIDTH;
			++_vm->_scrollCol;

			_vm->_buffer1.moveBufferLeft();
			_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth, screen._vWindowBytesWide);
		}

		scrollFall();

		while (!_vm->shouldQuit() && events._vbCount > 0) {
			events.pollEventsAndWait();
		}
	}

	events.showCursor();
}

/*------------------------------------------------------------------------*/

Jungle::Jungle(AmazonEngine *vm) : CampScene(vm) {
	for (int i = 0; i < JUNGLE_SIZE; ++i) {
		_jCnt[i] = _jungleX[i] = -1;
	}
}

void Jungle::jungleMove() {
	const static int jungleY[3] = { 27, 30, 29 };
	int count = 1;
	int frameOffset = 0;

	if (!_vm->_timers[0]._flag) {
		++_vm->_timers[0]._flag;
		_vm->_scrollX += _vm->_player->_scrollAmount;

		for (int i = 0; i < 3; ++i) {
			int newJCnt = (_jCnt[i] + 1) % 8;
			_jCnt[i] = newJCnt;
			_jungleX[i] += 5;
		}

		frameOffset = 4;
		count = (_vm->_allenFlag != 1) ? 2 : 3;
	}

	for (int i = 0; i < count; ++i) {
		ImageEntry ie;
		ie._flags = IMGFLAG_UNSCALED;
		ie._spritesPtr = _vm->_objectsTable[24];
		ie._frameNumber = _jCnt[i] + frameOffset;
		ie._position = Common::Point(_jungleX[i], jungleY[i]);
		ie._offsetY = jungleY[i];

		_vm->_images.addToList(ie);
		frameOffset += 8;
	}
}

void Jungle::initJWalk2() {
	const int JUNGLE1OBJ[7][4] = {
		{ 2, 470, 0, 20 },
		{ 0, 290, 0, 50 },
		{ 1, 210, 0, 40 },
		{ 0, 500, 0, 30 },
		{ 1, 550, 0, 20 },
		{ 0, 580, 0, 60 },
		{ 1, 650, 0, 30 }
	};

	Screen &screen = *_vm->_screen;
	screen.fadeOut();
	_vm->_events->hideCursor();
	screen.clearScreen();
	_vm->_buffer2.clearBuffer();
	screen.setBufferScan();

	_vm->_scrollX = _vm->_scrollY;
	_vm->_scrollCol = _vm->_scrollRow;
	_vm->_room->buildScreen();
	_vm->copyBF2Vid();
	screen.fadeIn();
	_vm->_events->clearEvents();

	_xCount = 2;
	_vm->_player->_scrollAmount = 5;
	_xTrack = -10;
	_yTrack = _zTrack = 0;
	_xCam = 480;
	_yCam = 0;
	_zCam = 80;

	_vm->_timers[24]._timer = 1;
	_vm->_timers[24]._initTm = 1;
	++_vm->_timers[24]._flag;

	_pNumObj = 7;
	for (int i = 0; i < _pNumObj; i++) {
		_pan[i]._pObject = _vm->_objectsTable[24];
		_pan[i]._pImgNum = JUNGLE1OBJ[i][0];
		_pan[i]._pObjX = JUNGLE1OBJ[i][1];
		_pan[i]._pObjY = JUNGLE1OBJ[i][2];
		_pan[i]._pObjZ = JUNGLE1OBJ[i][3];
		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
	}

	_jCnt[0] = 0;
	_jCnt[1] = 3;
	_jCnt[2] = 5;

	_jungleX[0] = 50;
	_jungleX[1] = 16;
	_jungleX[2] = 93;
}

void Jungle::mWhileJWalk() {
	Screen &screen = *_vm->_screen;
	EventsManager &events = *_vm->_events;
	Player &player = *_vm->_player;

	static const int JUNGLE_OBJ[7][4] = {
		{ 2, 77, 0, 40 },
		{ 0, 290, 0, 50 },
		{ 1, 210, 0, 70 },
		{ 0, 50, 0, 30 },
		{ 1, 70, 0, 20 },
		{ 0, -280, 0, 60 },
		{ 1, -150, 0, 30 },
	};

	screen.fadeOut();
	events.hideCursor();
	screen.clearScreen();
	_vm->_buffer2.clearBuffer();
	screen.setBufferScan();
	_vm->_scrollX = 0;

	// Build the initial jungle scene and fade it in
	_vm->_room->buildScreen();
	_vm->copyBF2Vid();
	screen.fadeIn();

	// Set up the player to walk horizontally
	player._xFlag = 1;
	player._yFlag = 0;
	player._moveTo.x = 160;
	player._playerMove = true;

	_xCount = 2;
	_xTrack = 10;
	_yTrack = _zTrack = 0;
	_xCam = 480;
	_yCam = 0;
	_zCam = 80;

	TimerEntry *te = &_vm->_timers[24];
	te->_initTm = te->_timer = 1;
	te->_flag++;

	_pNumObj = 7;
	for (int i = 0; i < _pNumObj; i++) {
		_pan[i]._pObject = _vm->_objectsTable[24];
		_pan[i]._pImgNum = JUNGLE_OBJ[i][0];
		_pan[i]._pObjX = JUNGLE_OBJ[i][1];
		_pan[i]._pObjY = JUNGLE_OBJ[i][2];
		_pan[i]._pObjZ = JUNGLE_OBJ[i][3];
		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
	}

	while (!_vm->shouldQuit() && !events.isKeyMousePressed() && (player._xFlag != 2)) {
		_vm->_images.clear();
		events._vbCount = 6;

		_pan[0]._pImgNum = _xCount;
		if (_xCount == 2)
			++_xCount;
		else
			--_xCount;

		player.checkMove();
		player.checkScroll();
		pan();
		scrollJWalk();

		while (!_vm->shouldQuit() && events._vbCount > 0) {
			events.pollEventsAndWait();
		}
	}

	_vm->_images.clear();
	events.showCursor();
}

void Jungle::mWhileJWalk2() {
	Screen &screen = *_vm->_screen;

	initJWalk2();

	while (!_vm->shouldQuit() && !_vm->_events->isKeyMousePressed() &&
		(_vm->_scrollCol + screen._vWindowWidth) != _vm->_room->_playFieldWidth) {
		_vm->_images.clear();
		_vm->_events->_vbCount = 6;
		_pan[0]._pImgNum = _xCount;

		jungleMove();
		while (_vm->_scrollX >= TILE_WIDTH) {
			_vm->_scrollX -= TILE_WIDTH;
			++_vm->_scrollCol;
			_vm->_buffer1.moveBufferLeft();
			_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth, screen._vWindowBytesWide);
		}

		if (_xCount == 2)
			++_xCount;
		else
			--_xCount;

		pan();
		scrollJWalk();

		while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0) {
			_vm->_events->pollEventsAndWait();
		}
	}

	_vm->_events->showCursor();
}

void Jungle::scrollJWalk() {
	_vm->copyBF1BF2();
	_vm->_newRects.clear();
	_vm->plotList();
	_vm->copyRects();
	_vm->copyBF2Vid();
}

/*------------------------------------------------------------------------*/

Guard::Guard(AmazonEngine *vm) : PannedScene(vm) {
	_guardCel = 0;
	_gCode1 = _gCode2 = 0;
	_xMid = _yMid = 0;
}

void Guard::setVerticalCode() {
	Screen &screen = *_vm->_screen;

	_gCode1 = 0;
	_gCode2 = 0;
	if (_topLeft.x < screen._orgX1)
		_gCode1 |= 8;
	else if (_topLeft.x == screen._orgX1) {
		_gCode1 |= 8;
		_gCode1 |= 2;
	} else
		_gCode1 |= 2;

	if (_bottomRight.x < screen._orgX1)
		_gCode2 |= 8;
	else if (_bottomRight.x == screen._orgX1) {
		_gCode2 |= 8;
		_gCode2 |= 2;
	} else
		_gCode2 |= 2;

	if (_topLeft.y < screen._orgY1)
		_gCode1 |= 4;
	else if (_topLeft.y > screen._orgY2)
		_gCode1 |= 1;

	if (_bottomRight.y < screen._orgY1)
		_gCode2 |= 4;
	else if (_bottomRight.y > screen._orgY2)
		_gCode2 |= 1;
}

void Guard::setHorizontalCode() {
	Screen &screen = *_vm->_screen;

	_gCode1 = 0;
	_gCode2 = 0;

	if (_topLeft.y < screen._orgY1)
		_gCode1 |= 4;
	else if (_topLeft.x == screen._orgX1) {
		_gCode1 |= 4;
		_gCode1 |= 1;
	} else
		_gCode1 |= 1;

	if (_bottomRight.y < screen._orgY1)
		_gCode2 |= 4;
	else if (_bottomRight.x == screen._orgX1) {
		_gCode2 |= 4;
		_gCode2 |= 1;
	} else
		_gCode2 |= 1;

	if (_topLeft.x < screen._orgX1)
		_gCode1 |= 8;
	else if (_topLeft.x > screen._orgX2)
		_gCode1 |= 2;

	if (_bottomRight.x < screen._orgX1)
		_gCode2 |= 8;
	else if (_bottomRight.x > screen._orgX2)
		_gCode2 |= 2;
}

void Guard::chkVLine() {
	if (_position.x > _vm->_player->_rawPlayer.x) {
		_topLeft = _vm->_player->_rawPlayer;
		_bottomRight = _position;
	} else {
		_topLeft = _position;
		_bottomRight = _vm->_player->_rawPlayer;
	}

	if (_vm->_screen->_orgY1 > _vm->_screen->_orgY2)
		SWAP(_vm->_screen->_orgY1, _vm->_screen->_orgY2);

	for (;;) {
		setVerticalCode();
		int code = _gCode1 | _gCode2;
		if (code == 10) {
			_vm->_guardFind = 0;
			return;
		}

		int code2 = _gCode1 & _gCode2;
		code2 &= 5;
		if (((code & 10) == 8) || ((code & 10) == 2) || (code2 != 0))
			return;

		int midX = (_topLeft.x + _bottomRight.x) / 2;
		int midY = (_topLeft.y + _bottomRight.y) / 2;

		if (midX < _vm->_screen->_orgX1) {
			if ((midX == _topLeft.x) && (midY == _topLeft.y))
				return;

			_topLeft.x = midX;
			_topLeft.y = midY;
		} else {
			if ((midX == _bottomRight.x) && (midY == _bottomRight.y))
				return;

			_bottomRight.x = midX;
			_bottomRight.y = midY;
		}
	}
}

void Guard::chkHLine() {
	if (_position.y > _vm->_player->_rawPlayer.y) {
		_topLeft = _vm->_player->_rawPlayer;
		_bottomRight = _position;
	} else {
		_topLeft = _position;
		_bottomRight = _vm->_player->_rawPlayer;
	}

	if (_vm->_screen->_orgX1 > _vm->_screen->_orgX2)
		SWAP(_vm->_screen->_orgX1, _vm->_screen->_orgX2);

	while (true) {
		setHorizontalCode();
		int code = _gCode1 | _gCode2;
		if (code == 5) {
			_vm->_guardFind = 0;
			return;
		}

		int code2 = _gCode1 & _gCode2;
		code2 &= 10;
		if (((code & 5) == 4) || ((code & 5) == 1) || (code2 != 0))
			return;

		int midX = (_topLeft.x + _bottomRight.x) / 2;
		int midY = (_topLeft.y + _bottomRight.y) / 2;

		if (midY < _vm->_screen->_orgY1) {
			if ((midX == _topLeft.x) && (midY == _topLeft.y))
				return;

			_topLeft.x = midX;
			_topLeft.y = midY;
		} else {
			if ((midX == _bottomRight.x) && (midY == _bottomRight.y))
				return;

			_bottomRight.x = midX;
			_bottomRight.y = midY;
		}
	}
}

void Guard::guardSee() {
	Screen &screen = *_vm->_screen;
	int tmpY = (_vm->_scrollRow << 4) + _vm->_scrollY;
	_vm->_flags[140] = 0;
	if (tmpY > _position.y)
		return;

	tmpY += screen._vWindowLinesTall;
	tmpY -= 11;

	if (tmpY < _position.y)
		return;

	_vm->_guardFind = 1;
	_vm->_flags[140] = 1;

	for (uint16 idx = 0; idx < _vm->_room->_plotter._walls.size(); idx++) {
		screen._orgX1 = _vm->_room->_plotter._walls[idx].left;
		screen._orgY1 = _vm->_room->_plotter._walls[idx].top;
		screen._orgX2 = _vm->_room->_plotter._walls[idx].right;
		screen._orgY2 = _vm->_room->_plotter._walls[idx].bottom;
		if (screen._orgX1 == screen._orgX2) {
			chkVLine();
			if (_vm->_guardFind == 0)
				return;
		} else if (screen._orgY1 == screen._orgY2) {
			chkHLine();
			if (_vm->_guardFind == 0)
				return;
		}
	}
}

void Guard::setGuardFrame() {
	ImageEntry ie;
	ie._flags = IMGFLAG_UNSCALED;

	if (_vm->_guardLocation == 4)
		ie._flags |= IMGFLAG_BACKWARDS;
	ie._spritesPtr = _vm->_objectsTable[37];
	ie._frameNumber = _guardCel;
	ie._position = _position;
	ie._offsetY = 10;
	_vm->_images.addToList(ie);
}

void Guard::doGuard() {
	// Skip the code dealing with the guard on the boat (chapter 8)
	// if the cheat mode is activated
	if (_vm->_cheatFl)
		return;

	if (_vm->_timers[8]._flag) {
		setGuardFrame();
		return;
	}

	++_vm->_timers[8]._flag;
	++_guardCel;
	int curCel = _guardCel;

	switch (_vm->_guardLocation) {
	case 1:
		// Guard walking down
		if (curCel <= 8 || curCel > 13)
			_guardCel = curCel = 8;

		_position.y += _vm->_player->_walkOffDown[curCel - 8];
		guardSee();
		if (_position.y >= 272) {
			_position.y = 272;
			_vm->_guardLocation = 2;
		}
		break;
	case 2:
		// Guard walking left
		if (curCel <= 43 || curCel > 48)
			_guardCel = curCel = 43;

		_position.x -= _vm->_player->_walkOffLeft[curCel - 43];
		guardSee();
		if (_position.x <= 56) {
			_position.x = 56;
			_vm->_guardLocation = 3;
		}
		break;
	case 3:
		// Guard walking up
		if (curCel <= 0 || curCel > 5)
			_guardCel = curCel = 0;

		_position.y -= _vm->_player->_walkOffUp[curCel];
		guardSee();
		if (_position.y <= 89) {
			_position.y = 89;
			_vm->_guardLocation = 4;
			if (_vm->_flags[121] == 1)
				_vm->_guardLocation = 5;
		}
		break;
	default:
		// Guard walking right
		if (curCel <= 43 || curCel > 48)
			_guardCel = curCel = 43;

		_position.x += _vm->_player->_walkOffRight[curCel - 43];
		guardSee();
		if (_position.x >= 127) {
			_position.x = 127;
			_vm->_guardLocation = 1;
		}
		break;
	}

	setGuardFrame();
}

void Guard::setPosition(const Common::Point &pt) {
	_position = pt;
}

/*------------------------------------------------------------------------*/

Cast::Cast(AmazonEngine *vm) : PannedScene(vm) {
}

void Cast::doCast(int param1) {
	Screen &screen = *_vm->_screen;

	_vm->_buffer1.create(_vm->_screen->w, _vm->_screen->h);
	_vm->_buffer2.create(_vm->_screen->w, _vm->_screen->h);

	screen.setDisplayScan();
	_vm->_events->hideCursor();
	screen.forceFadeOut();
	screen._clipHeight = 173;
	screen.clearScreen();
	_vm->_chapter = 16;
	_vm->tileScreen();
	_vm->updateSummary(param1);
	screen.setPanel(3);
	_vm->_chapter = 14;

	Resource *spriteData = _vm->_files->loadFile(91, 0);
	_vm->_objectsTable[0] = new SpriteResource(_vm, spriteData);
	delete spriteData;
	spriteData = _vm->_files->loadFile(91, 1);
	_vm->_objectsTable[1] = new SpriteResource(_vm, spriteData);
	delete spriteData;

	_vm->_files->_setPaletteFlag = false;
	_vm->_files->loadScreen(58, 1);
	_vm->_buffer2.blitFrom(*_vm->_screen);
	_vm->_buffer1.blitFrom(*_vm->_screen);

	_xTrack = 0;
	_yTrack = -6;
	_zTrack = 0;
	_xCam = _yCam = 0;
	_zCam = 60;

	_vm->_timers[24]._timer = 1;
	_vm->_timers[24]._initTm = 1;
	++_vm->_timers[24]._flag;

	_pNumObj = 26;
	for (int i = 0; i < _pNumObj; i++) {
		_pan[i]._pObject = _vm->_objectsTable[0];
		_pan[i]._pImgNum = CAST_END_OBJ[i][0];
		_pan[i]._pObjX = CAST_END_OBJ[i][1];
		_pan[i]._pObjY = CAST_END_OBJ[i][2];
		_pan[i]._pObjZ = CAST_END_OBJ[i][3];
		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
	}

	_pNumObj += 4;
	for (int i = 0; i < 4; i++) {
		_pan[26 + i]._pObject = _vm->_objectsTable[1];
		_pan[26 + i]._pImgNum = CAST_END_OBJ1[i][0];
		_pan[26 + i]._pObjX = CAST_END_OBJ1[i][1];
		_pan[26 + i]._pObjY = CAST_END_OBJ1[i][2];
		_pan[26 + i]._pObjZ = CAST_END_OBJ1[i][3];
		_pan[26 + i]._pObjXl = _pan[26 + i]._pObjYl = 0;
	}

	_vm->_oldRects.clear();
	_vm->_newRects.clear();
	_vm->_numAnimTimers = 0;

	_vm->_midi->newMusic(58, 0);
	screen.forceFadeIn();

	while (!_vm->shouldQuit()) {
		_vm->_images.clear();
		pan();
		_vm->_buffer2.blitFrom(_vm->_buffer1);
		_vm->_newRects.clear();
		_vm->plotList();
		_vm->copyBlocks();

		for (int idx = 0; idx < 5 && !_vm->shouldQuit() &&
				!_vm->_events->isKeyMousePressed(); ++idx)
			_vm->_events->pollEventsAndWait();

		if (_vm->_events->isKeyMousePressed())
			break;

		if (_yCam < -7550) {
			while (!_vm->shouldQuit() && !_vm->_midi->checkMidiDone())
				_vm->_events->pollEventsAndWait();
			break;
		}
	}

	_vm->_midi->newMusic(58, 1);
	_vm->_events->showCursor();

	_vm->freeCells();
	_vm->_oldRects.clear();
	_vm->_newRects.clear();
	_vm->_numAnimTimers = 0;
	_vm->_images.clear();
	screen.forceFadeOut();

	_vm->quitGame();
	_vm->_events->pollEvents();
}

/*------------------------------------------------------------------------*/

River::River(AmazonEngine *vm) : PannedScene(vm) {
	_chickenOutFl = false;
	_rScrollRow = 0;
	_rScrollCol = 0;
	_rScrollX = 0;
	_rScrollY = 0;
	_mapOffset = 0;
	_screenVertX = 0;
	_saveRiver = false;
	_deathFlag = false;
	_deathCount = 0;
	_oldScrollCol = 0;
	_maxHits = 0;
	_mapPtr = nullptr;
	_canoeMoveCount = 0;
	_canoeVXPos = 0;
	_canoeFrame = 0;
	_canoeDir = 0;
	_canoeLane = 0;
	_canoeYPos = 0;
	_hitCount = 0;
	_riverIndex = 0;
	_topList = _botList = nullptr;
	_deathType = 0;
	_hitSafe = 0;
}

void River::setRiverPan() {
	int delta = (_vm->_scrollCol * 16) + _vm->_scrollX;

	_xTrack = 9;
	_yTrack = _zTrack = 0;
	_xCam = 160;
	_yCam = 0;
	_zCam = 80;

	_vm->_timers[24]._timer = 1;
	_vm->_timers[24]._initTm = 1;
	++_vm->_timers[24]._flag;

	_pNumObj = 23;
	for (int i = 0; i < _pNumObj; i++) {
		_pan[i]._pObject = _vm->_objectsTable[45];
		_pan[i]._pImgNum = RIVER1OBJ[i][0];
		_pan[i]._pObjX = RIVER1OBJ[i][1] + delta;
		_pan[i]._pObjY = RIVER1OBJ[i][2];
		_pan[i]._pObjZ = RIVER1OBJ[i][3];
		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
	}
}

void River::initRiver() {
	static const int RIVERVXTBL[3] = { 6719, 7039, 8319 };
	Screen &screen = *_vm->_screen;

	_vm->_events->centerMousePos();
	_vm->_events->restrictMouse();
	screen.setDisplayScan();
	screen.clearScreen();
	screen.savePalette();
	screen.forceFadeOut();

	_vm->_files->_setPaletteFlag = false;
	_vm->_files->loadScreen(95, 4);
	_vm->_buffer2.blitFrom(*_vm->_screen);

	screen.restorePalette();
	screen.setBufferScan();
	_vm->_destIn = &_vm->_buffer2;
	_vm->_room->roomMenu();

	if (_saveRiver) {
		// Restoring a savegame, so set properties from saved fields
		_vm->_scrollRow = _rScrollRow;
		_vm->_scrollCol = _rScrollCol;
		_vm->_scrollX = _rScrollX;
		_vm->_scrollY = _rScrollY;
	} else {
		// Set initial scene state
		_vm->_scrollRow = 0;
		_vm->_scrollCol = 140;
		_vm->_scrollX = 0;
		_vm->_scrollY = 0;
	}

	_vm->_room->buildScreen();
	_vm->copyBF2Vid();
	screen.forceFadeIn();

	if (!_saveRiver) {
		// Reset draw rects
		_vm->_oldRects.clear();
		_vm->_newRects.clear();
		_vm->_events->clearEvents();

	}

	_vm->_player->_scrollAmount = 2;
	setRiverPan();
	_vm->_timers[3]._timer = 1;
	_vm->_timers[3]._initTm = 1;
	++_vm->_timers[3]._flag;

	_canoeFrame = 0;
	_mapPtr = (const byte *)MAPTBL[_vm->_riverFlag] + 1;
	if (_saveRiver) {
		_mapPtr--;
		_mapPtr += _mapOffset;
	} else {
		_screenVertX = RIVERVXTBL[_vm->_riverFlag] - 320;
		_canoeLane = 3;
		_hitCount = 0;
		_hitSafe = 0;
		_canoeYPos = 71;
	}

	_riverIndex = _vm->_riverFlag;
	_topList = RIVER_OBJECTS[_riverIndex][RIVER_START];
	updateObstacles();
	riverSetPhysX();
	_canoeDir = 0;
	_deathFlag = false;
	_deathCount = 0;

	_vm->_timers[11]._timer = 1200;
	_vm->_timers[11]._initTm = 1200;
	++_vm->_timers[11]._flag;
	_vm->_timers[12]._timer = 1500;
	_vm->_timers[12]._initTm = 1500;
	++_vm->_timers[12]._flag;

	_maxHits = 2 - _vm->_riverFlag;
	_saveRiver = false;

	// Set font colors for drawing using font2
	Font::_fontColors[0] = 0;
	Font::_fontColors[1] = 33;
	Font::_fontColors[2] = 34;
	Font::_fontColors[3] = 35;
}

void River::resetPositions() {
	riverSetPhysX();
	int val = (_vm->_scrollCol + 1 - _oldScrollCol) * 16;
	if (val < 0) {
		val |= 0x80;
	}

	for (int i = 0; i < _pNumObj; i++)
		_pan[i]._pObjX += val;
}

void River::checkRiverPan() {
	int val = _vm->_scrollCol * 16 + 320;

	for (int i = 0; i < _pNumObj; i++) {
		if (_pan[i]._pObjX < val)
			return;
	}

	setRiverPan();
}

bool River::riverJumpTest() {
	if (_vm->_scrollCol == 120 || _vm->_scrollCol == 60 || _vm->_scrollCol == 0) {
		int val = *++_mapPtr;
		if (val == 0xFF)
			return true;

		_oldScrollCol = _vm->_scrollCol;

		if (val == 0) {
			_vm->_scrollCol = 139;
			_vm->_scrollX = 14;
			_vm->_room->buildScreen();
			resetPositions();
			return false;
		}
	} else if (_vm->_scrollCol == 105) {
		int val1 = _mapPtr[1];
		int val2 = _mapPtr[2];
		_mapPtr += 3;
		if (_canoeLane < 3) {
			if (val1 != 0) {
				_deathFlag = true;
				_deathCount = 300;
				_deathType = val2;
			}
		} else {
			if (val1 != 1) {
				_deathFlag = true;
				_deathCount = 300;
				_deathType = val2;
			}
			_oldScrollCol = _vm->_scrollCol;
			_vm->_scrollCol = 44;
			_vm->_scrollX = 14;
			_vm->_room->buildScreen();
			resetPositions();
			return false;
		}
	}

	_vm->_scrollX = 14;
	--_vm->_scrollCol;
	_vm->_buffer1.moveBufferRight();
	_vm->_room->buildColumn(_vm->_scrollCol, 0);
	checkRiverPan();
	return false;
}

void River::riverSound() {
	if (_vm->_timers[11]._flag == 0) {
		++_vm->_timers[11]._flag;
		_vm->_sound->playSound(2);
	}

	if (_vm->_timers[12]._flag == 0) {
		++_vm->_timers[12]._flag;
		_vm->_sound->playSound(3);
	}

	if ((_xCam >= 1300) && (_xCam <= 1320))
		_vm->_sound->playSound(1);
}

void River::moveCanoe() {
	EventsManager &events = *_vm->_events;
	Common::Point pt = events.calcRawMouse();
	Common::Point mousePos = events.getMousePos();

	// Do an event polling
	_vm->_canSaveLoad = true;
	events.pollEvents();
	_vm->_canSaveLoad = false;
	if (_vm->_room->_function == FN_CLEAR1)
		return;

	if (_canoeDir) {
		// Canoe movement in progress
		moveCanoe2();
	} else {
		if (events._leftButton && pt.y >= 140) {
			if (pt.x < _vm->_room->_rMouse[8][0]) {
				// Disk icon wasn't clicked
				_vm->_scripts->printString(AMRES.BAR_MESSAGE);
			} else {
				// Clicked on the Disc icon. Show the ScummVM menu
				_vm->_room->handleCommand(9);

				if (_vm->_room->_function != FN_CLEAR1) {
					_vm->_room->buildScreen();
					_vm->copyBF2Vid();
				}
			}
		} else if (events._leftButton && mousePos.x < 35 && mousePos.y < 12) {
			// Clicked on the Skip button. So chicken out
			_chickenOutFl = true;
		}  else if ((events._leftButton && pt.y <= _canoeYPos) ||
			(!events._leftButton && _vm->_player->_move == UP)) {
			// Move canoe up
			if (_canoeLane > 0) {
				_canoeDir = -1;
				_canoeMoveCount = 0;

				moveCanoe2();
			}
		} else if (events._leftButton || _vm->_player->_move == DOWN) {
			// Move canoe down
			if (_canoeLane < 7) {
				_canoeDir = 1;
				_canoeMoveCount = 0;

				moveCanoe2();
			}
		}
	}
}

void River::moveCanoe2() {
	_canoeYPos += _canoeDir;

	if (++_canoeMoveCount == 5) {
		_canoeLane += _canoeDir;
		_canoeDir = 0;
	}
}

void River::updateObstacles() {
	RiverStruct *cur;
	for (cur = _topList; cur < RIVER_OBJECTS[_riverIndex][RIVER_END]; ++cur) {
		int val = cur->_riverX + cur->_width - 1;
		if (val < _screenVertX)
			// Obstacle is not yet on-screen
			break;

		if (cur->_riverX < (_screenVertX + 319)) {
			// Object is now on-screen. So set _topList/_botList to the range
			// of river obstacles that are currently visible
			_topList = cur;
			_botList = cur;

			while (cur < RIVER_OBJECTS[_riverIndex][RIVER_END]) {
				++cur;
				val = cur->_riverX + cur->_width - 1;
				if (val < _screenVertX || (cur->_riverX >= (_screenVertX + 319)))
					break;

				_botList = cur;
			}

			return;
		}
	}

	cur = _topList;
	cur--;
	_botList = cur;
}

void River::riverSetPhysX() {
	int xAmt = (_vm->_scrollCol * 16) + _vm->_scrollX;

	for (RiverStruct *cur = _topList; cur <= _botList; ++cur) {
		cur->_xp = xAmt - (_screenVertX - cur->_riverX);
	}
}

bool River::checkRiverCollide() {
	if (_hitSafe)
		return false;

	_canoeVXPos = _screenVertX + 170;

	for (RiverStruct *cur = _topList; cur <= _botList; ++cur) {
		if (cur->_lane < _canoeLane)
			continue;

		if ((cur->_lane == _canoeLane) || (cur->_lane == _canoeLane + 1)) {
			if ((cur->_riverX + cur->_width - 1) >= _canoeVXPos &&
					cur->_riverX < (_canoeVXPos + 124)) {
				_vm->_sound->playSound(4);
				return true;
			}
		}
	}

	return false;
}

void River::plotRiver() {
	// Handle cycling through the canoe rowing frames
	if (_vm->_timers[3]._flag == 0) {
		++_vm->_timers[3]._flag;

		if (_canoeFrame++ == 12)
			_canoeFrame = 0;
	}

	// Draw the canoe
	ImageEntry ie;
	ie._flags = IMGFLAG_UNSCALED;
	ie._spritesPtr = _vm->_objectsTable[45];
	ie._frameNumber = _canoeFrame;
	ie._position.x = (_vm->_scrollCol * 16) + _vm->_scrollX + 160;
	ie._position.y = _canoeYPos - 41;
	ie._offsetY = 41;
	_vm->_images.addToList(ie);

	// Draw any on-screen obstacles
	for (RiverStruct *cur = _topList; cur <= _botList; ++cur) {
		if (cur->_id != -1) {
			ie._flags = IMGFLAG_UNSCALED;
			ie._spritesPtr = _vm->_objectsTable[45];
			ie._frameNumber = cur->_id;
			ie._position.x = cur->_xp;
			ie._position.y = (cur->_lane * 5) + 56 - cur->_offsetY;
			ie._offsetY = cur->_offsetY;
			_vm->_images.addToList(ie);
		}
	}

	// Draw the text for skipping the river
	Font &font2 = *_vm->_fonts._font2;
	font2.drawString(_vm->_screen, "SKIP", Common::Point(5, 5));
}

void River::mWhileDownRiver() {
	Screen &screen = *_vm->_screen;
	_vm->_events->hideCursor();

	screen.setDisplayScan();
	screen.clearScreen();
	screen.savePalette();
	if (!_vm->isDemo())
		_vm->_files->loadScreen(95, 4);
	_vm->_buffer2.blitFrom(*_vm->_screen);
	screen.restorePalette();
	screen.setPalette();
	screen.setBufferScan();

	_vm->_scrollX = 0;
	_vm->_room->buildScreen();
	_vm->copyBF2Vid();

	_vm->_player->_scrollAmount = 2;
	_vm->_destIn = &_vm->_buffer2;
	_xTrack = -7;
	_yTrack = _zTrack = 0;
	_xCam = _yCam = 0;
	_zCam = 80;

	_vm->_timers[24]._timer = 1;
	_vm->_timers[24]._initTm = 1;
	++_vm->_timers[24]._flag;

	_pNumObj = 14;
	for (int i = 0; i <_pNumObj; i++) {
		_pan[i]._pObject = _vm->_objectsTable[33];
		_pan[i]._pImgNum = DOWNRIVEROBJ[i][0];
		_pan[i]._pObjX = DOWNRIVEROBJ[i][1];
		_pan[i]._pObjY = DOWNRIVEROBJ[i][2];
		_pan[i]._pObjZ = DOWNRIVEROBJ[i][3];
		_pan[i]._pObjXl = _pan[i]._pObjYl = 0;
	}

	_vm->_timers[3]._timer = 200;
	_vm->_timers[3]._initTm = 200;
	++_vm->_timers[3]._flag;
	_vm->_timers[4]._timer = 350;
	_vm->_timers[4]._initTm = 350;
	++_vm->_timers[4]._flag;

	while (!_vm->shouldQuit() && !_vm->_events->isKeyMousePressed() &&
		(_vm->_scrollCol + screen._vWindowWidth != _vm->_room->_playFieldWidth)) {
		_vm->_images.clear();
		_vm->_events->_vbCount = 6;

		_vm->_scrollX += _vm->_player->_scrollAmount;
		while (_vm->_scrollX >= TILE_WIDTH) {
			_vm->_scrollX -= TILE_WIDTH;
			++_vm->_scrollCol;
			_vm->_buffer1.moveBufferLeft();
			_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth, screen._vWindowBytesWide);
		}

		pan();
		scrollRiver();

		if (!_vm->_timers[3]._flag) {
			++_vm->_timers[3]._flag;
			_vm->_sound->playSound(1);
		} else if (!_vm->_timers[4]._flag) {
			++_vm->_timers[4]._flag;
			_vm->_sound->playSound(0);
		}

		while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0) {
			_vm->_events->pollEventsAndWait();
		}
	}

	_vm->_events->showCursor();
}

void River::scrollRiver() {
	_vm->copyBF1BF2();
	_vm->_newRects.clear();
	_vm->_buffer2.plotImage(_vm->_objectsTable[33], 0, Common::Point(66, 30));
	_vm->plotList();
	_vm->copyRects();
	_vm->copyBF2Vid();
}

void River::scrollRiver1() {
	_vm->copyBF1BF2();
	_vm->_newRects.clear();
	plotRiver();
	_vm->plotList();
	_vm->copyRects();
	_vm->copyBF2Vid();
}

void River::doRiver() {
	static const int RIVERDEATH[5] = { 22, 23, 24, 25, 26 };

	initRiver();
	_vm->_events->showCursor();

	while (!_vm->shouldQuit()) {
		_vm->_events->_vbCount = 4;

		// Move the river position
		_screenVertX -= _vm->_player->_scrollAmount;

		if (_vm->_scrollX == 0) {
			_vm->_midi->midiRepeat();
			if (riverJumpTest()) {
				_chickenOutFl = false;
				return;
			}
		} else {
			_vm->_scrollX -= _vm->_player->_scrollAmount;
		}

		if (_chickenOutFl) {
			_chickenOutFl = false;
			return;
		}

		_vm->_images.clear();
		_vm->_animation->animate(0);

		riverSound();
		pan();
		moveCanoe();

		if (_vm->_room->_function != FN_CLEAR1) {
			updateObstacles();
			riverSetPhysX();
			bool checkCollide = checkRiverCollide();
			if (_hitSafe != 0)
				_hitSafe -= 2;

			if (checkCollide) {
				_vm->dead(RIVERDEATH[0]);
				return;
			}

			if (_deathFlag) {
				if (--_deathCount == 0) {
					_vm->dead(RIVERDEATH[_deathType]);
					return;
				}
			}

			// Scroll the river
			scrollRiver1();

			// Allow time for new scrolled river position to be shown
			_vm->_canSaveLoad = true;
			while (!_vm->shouldQuit() && _vm->_room->_function == FN_NONE &&
				_vm->_events->_vbCount > 0) {
				_vm->_events->pollEventsAndWait();
			}
			_vm->_canSaveLoad = false;
		}

		if (_vm->_room->_function == FN_CLEAR1) {
			_vm->_scripts->_endFlag = true;
			_vm->_scripts->_returnCode = 0;
			_chickenOutFl = false;
			break;
		}
	}
}

void River::synchronize(Common::Serializer &s) {
	if (_vm->_player->_roomNumber == 45) {
		if (s.isSaving()) {
			// Set river properties to be saved out
			_rScrollRow = _vm->_scrollRow;
			_rScrollCol = _vm->_scrollCol;
			_rScrollX = _vm->_scrollX;
			_rScrollY = _vm->_scrollY;
			_mapOffset = _mapPtr - MAPTBL[_vm->_riverFlag];
		}

		s.syncAsSint16LE(_canoeLane);
		s.syncAsSint16LE(_canoeYPos);
		s.syncAsSint16LE(_hitCount);
		s.syncAsSint16LE(_riverIndex);
		s.syncAsSint16LE(_hitSafe);
		s.syncAsUint16LE(_rScrollRow);
		s.syncAsUint16LE(_rScrollCol);
		s.syncAsSint16LE(_rScrollX);
		s.syncAsSint16LE(_rScrollY);
		s.syncAsUint16LE(_mapOffset);
		s.syncAsUint16LE(_screenVertX);

		_saveRiver = s.isLoading();
	}
}

/*------------------------------------------------------------------------*/

Ant::Ant(AmazonEngine *vm) : AmazonManager(vm) {
	_antDirection = ANT_RIGHT;
	_pitDirection = ANT_RIGHT;
	_antCel = 0;
	_torchCel = 0;
	_pitCel = 0;
	_stabCel = 0;
	_antPos = Common::Point(0, 0);
	_antDieFl = _antEatFl = false;
	_stabFl = false;
	_pitPos = Common::Point(0, 0);
}

void Ant::plotTorchSpear(int indx, const int *&buf) {
	int idx = indx;

	ImageEntry ie;
	ie._flags = IMGFLAG_UNSCALED;
	ie._spritesPtr = _vm->_objectsTable[62];
	ie._frameNumber = buf[(idx / 2)];
	ie._position = Common::Point(_pitPos.x + buf[(idx / 2) + 1], _pitPos.y + buf[(idx / 2) + 2]);
	ie._offsetY = 255;
	_vm->_images.addToList(ie);
}

void Ant::plotPit(int indx, const int *&buf) {
	int idx = indx;
	ImageEntry ie;
	ie._flags = IMGFLAG_UNSCALED;
	ie._spritesPtr = _vm->_objectsTable[62];
	ie._frameNumber = buf[(idx / 2)];
	ie._position = Common::Point(_pitPos.x, _pitPos.y);
	ie._offsetY = _pitPos.y;
	_vm->_images.addToList(ie);

	_vm->_player->_rawPlayer = _pitPos;
	if (_vm->_inventory->_inv[INV_TORCH]._value == ITEM_IN_INVENTORY) {
		// Player has torch
		idx = _torchCel;
		buf = Amazon::TORCH;
		_vm->_timers[14]._flag = 1;
		idx += 6;
		if (buf[idx / 2] == -1)
			idx = 0;
		_torchCel = idx;
		plotTorchSpear(idx, buf);
	} else if (!_stabFl && (_vm->_inventory->_inv[INV_KNIFE_SPEAR]._value == ITEM_IN_INVENTORY)) {
		// Player has spear
		idx = 0;
		buf = Amazon::SPEAR;
		plotTorchSpear(idx, buf);
	}
}

int Ant::antHandleRight(int indx, const int *&buf) {
	int retval = indx;
	if (_pitDirection == ANT_RIGHT) {
		_pitDirection = ANT_LEFT;
		_pitPos.y = 127;
	}
	retval = _pitCel;
	buf = Amazon::PITWALK;
	if (_pitPos.x < 230) {
		if (retval == 0) {
			retval = 48;
			_pitPos.y = 127;
		}
		retval -= 6;
		_pitPos.x -= buf[(retval / 2) + 1];
		_pitPos.y -= buf[(retval / 2) + 2];
		_pitCel = retval;
	}
	return retval;
}

int Ant::antHandleLeft(int indx, const int *&buf) {
	int retval = indx;
	if (_pitDirection == ANT_LEFT) {
		_pitDirection = ANT_RIGHT;
		_pitPos.y = 127;
	}
	retval = _pitCel;
	buf = Amazon::PITWALK;
	retval += 6;
	if (buf[retval / 2] == -1) {
		retval = 0;
		_pitPos.y = 127;
	}
	_pitPos.x += buf[(retval / 2) + 1];
	_pitPos.y += buf[(retval / 2) + 2];
	_pitCel = retval;

	return retval;
}

int Ant::antHandleStab(int indx, const int *&buf) {
	int retval = indx;
	if (_vm->_inventory->_inv[INV_KNIFE_SPEAR]._value == ITEM_IN_INVENTORY) {
		if (_stabFl) {
			buf = Amazon::PITSTAB;
			retval = _stabCel;
			if (_vm->_timers[13]._flag == 0) {
				_vm->_timers[13]._flag = 1;
				retval += 6;
				_stabCel = retval;

				if (buf[retval] == -1) {
					_stabFl = false;
					_pitCel = 0;
					_pitPos.y = 127;
					retval = 0;
					buf = Amazon::PITWALK;
				} else {
					_pitPos.x += buf[(retval / 2) + 1];
					_pitPos.y += buf[(retval / 2) + 2];
					_pitCel = retval;
				}
			}
		} else {
			_stabFl = true;
			_pitCel = 0;
			retval = 0;
			_stabCel = 0;
			int dist = _pitPos.x - _antPos.x;
			if (_antEatFl && !_antDieFl && (dist <= 80)) {
				_antDieFl = true;
				_antCel = 0;
				_antPos.y = 123;
				_vm->_sound->playSound(1);
			}
		}
	}

	return retval;
}

void Ant::doAnt() {
	_antDirection = ANT_RIGHT;
	if (_vm->_aniFlag != 1) {
		_vm->_aniFlag = 1;
		_antCel = 0;
		_torchCel = 0;
		_pitCel = 0;

		_vm->_timers[15]._timer = 16;
		_vm->_timers[15]._initTm = 16;
		_vm->_timers[15]._flag = 1;

		_vm->_timers[13]._timer = 5;
		_vm->_timers[13]._initTm = 5;
		_vm->_timers[13]._flag = 1;

		_vm->_timers[14]._timer = 10;
		_vm->_timers[14]._initTm = 10;
		_vm->_timers[14]._flag = 1;

		_antPos = Common::Point(-40, 123);
		_antDieFl = _antEatFl = false;
		_stabFl = false;
		_pitPos = Common::Point(_vm->_player->_rawPlayer.x, 127);
	}

	const int *buf = nullptr;
	if (_antDieFl) {
		buf = Amazon::ANTDIE;
	} else if (_antEatFl) {
		buf = Amazon::ANTEAT;
	} else if (_antPos.x > 120 && _vm->_flags[198] == 1) {
		_antEatFl = true;
		_vm->_flags[235] = 1;
		_antCel = 0;
		buf = Amazon::ANTEAT;
	} else {
		buf = Amazon::ANTWALK;
		if (_vm->_inventory->_inv[INV_TORCH]._value == ITEM_IN_INVENTORY)
			// Player has burning torch, which scares the Ant
			_antDirection = ANT_LEFT;
	}

	int idx = _antCel;
	if (_vm->_timers[15]._flag == 0) {
		_vm->_timers[15]._flag = 1;
		if (_antDirection == ANT_LEFT) {
			if (_antPos.x > 10) {
				if (idx == 0)
					idx = 36;
				else
					idx -= 6;

				_antPos -= Common::Point(buf[(idx / 2) + 1], buf[(idx / 2) + 2]);
				_antCel = idx;
			}
		} else {
			idx += 6;
			if (buf[(idx / 2)] != -1) {
				_antPos += Common::Point(buf[(idx / 2) + 1], buf[(idx / 2) + 2]);
				_antCel = idx;
			} else if (!_antDieFl) {
				idx = 0;
				_antPos += Common::Point(buf[(idx / 2) + 1], buf[(idx / 2) + 2]);
				_antCel = idx;
			} else {
				idx -= 6;
				if (_vm->_flags[200] == 0)
					_vm->_flags[200] = 1;
			}
		}
	}

	ImageEntry ie;
	ie._flags = IMGFLAG_UNSCALED;
	ie._spritesPtr = _vm->_objectsTable[61];
	ie._frameNumber = buf[(idx / 2)];
	ie._position = Common::Point(_antPos.x, _antPos.y);
	ie._offsetY = _antPos.y - 70;
	_vm->_images.addToList(ie);
	_antCel = idx;

	if (_vm->_flags[196] != 1) {
		idx = _pitCel;
		if (_stabFl) {
			idx = antHandleStab(idx, buf);
		} else {
			buf = Amazon::PITWALK;
			if (_vm->_timers[13]._flag == 0) {
				_vm->_timers[13]._flag = 1;
				_vm->_events->pollEvents();
				if (_vm->_events->_leftButton) {
					// Handle moving the player whilst the mouse button is held down
					Common::Point pt = _vm->_events->calcRawMouse();
					if (pt.x < _pitPos.x)
						idx = antHandleLeft(idx, buf);
					else if (pt.x > _pitPos.x)
						idx = antHandleRight(idx, buf);
				} else {
					// Handle movement based on keyboard keys
					buf = Amazon::PITWALK;
					if (_vm->_player->_move == UP)
						idx = antHandleStab(idx, buf);
					else if (_vm->_player->_move == LEFT)
						idx = antHandleLeft(idx, buf);
					else if (_vm->_player->_move == RIGHT)
						idx = antHandleRight(idx, buf);
				}
			}
		}
		plotPit(idx, buf);
	}

	if (!_antDieFl) {
		int dist = _pitPos.x - _antPos.x;
		if ((_antEatFl && (dist <= 45)) || (!_antEatFl && (dist <= 80))) {
			_vm->_flags[199] = 1;
			_vm->_aniFlag = 0;
		}
	}
}

void Ant::synchronize(Common::Serializer &s) {
	if (_vm->_player->_roomNumber == 61) {
		s.syncAsByte(_antDirection);
		s.syncAsByte(_pitDirection);
		s.syncAsSint16LE(_antCel);
		s.syncAsSint16LE(_torchCel);
		s.syncAsSint16LE(_pitCel);
		s.syncAsSint16LE(_stabCel);
		s.syncAsSint16LE(_antPos.x);
		s.syncAsSint16LE(_antPos.y);
		s.syncAsSint16LE(_pitPos.x);
		s.syncAsSint16LE(_pitPos.y);
		s.syncAsByte(_antDieFl);
		s.syncAsByte(_antEatFl);
		s.syncAsByte(_stabFl);
	}
}


} // End of namespace Amazon

} // End of namespace Access
