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/algorithm.h"
24 #include "common/textconsole.h"
25 #include "access/player.h"
26 #include "access/access.h"
27 #include "access/resources.h"
28 #include "access/amazon/amazon_player.h"
29 #include "access/martian/martian_player.h"
30 
31 namespace Access {
32 
init(AccessEngine * vm)33 Player *Player::init(AccessEngine *vm) {
34 	switch (vm->getGameID()) {
35 	case GType_Amazon:
36 		vm->_playerDataCount = 8;
37 		return new Amazon::AmazonPlayer(vm);
38 	case GType_MartianMemorandum:
39 		vm->_playerDataCount = 10;
40 		return new Martian::MartianPlayer(vm);
41 	default:
42 		vm->_playerDataCount = 8;
43 		return new Player(vm);
44 	}
45 }
46 
Player(AccessEngine * vm)47 Player::Player(AccessEngine *vm) : Manager(vm), ImageEntry() {
48 	_playerSprites = nullptr;
49 	_playerSprites1 = nullptr;
50 	_manPal1 = nullptr;
51 	_frameNumber = 0;
52 	_rawTempL = 0;
53 	_rawXTemp = 0;
54 	_rawYTempL = 0;
55 	_rawYTemp = 0;
56 	_playerXLow = 0;
57 	_playerX = 0;
58 	_playerYLow = 0;
59 	_playerY = 0;
60 	_frame = 0;
61 	_playerOff = false;
62 	_playerMove = false;
63 	_leftDelta = _rightDelta = 0;
64 	_upDelta = _downDelta = 0;
65 	_scrollConst = 0;
66 	_scrollFlag = false;
67 	_scrollThreshold = 0;
68 	_scrollAmount = 0;
69 	_scrollEnd = 0;
70 	_roomNumber = 0;
71 	_collideFlag = false;
72 	_move = NONE;
73 	_playerDirection = NONE;
74 	_xFlag = _yFlag = 0;
75 	_inactiveYOff = 0;
76 
77 	_sideWalkMin = _sideWalkMax = 0;
78 	_upWalkMin = _upWalkMax = 0;
79 	_downWalkMin = _downWalkMax = 0;
80 	_diagUpWalkMin = _diagUpWalkMax = 0;
81 	_diagDownWalkMin = _diagDownWalkMax = 0;
82 	_walkOffRight = _walkOffLeft = nullptr;
83 	_walkOffUp = _walkOffDown = nullptr;
84 	_walkOffUR = _walkOffDR = nullptr;
85 	_walkOffUL = _walkOffDL = nullptr;
86 }
87 
~Player()88 Player::~Player() {
89 	delete _playerSprites;
90 	delete[] _manPal1;
91 	delete[] _walkOffRight;
92 	delete[] _walkOffLeft;
93 	delete[] _walkOffUp;
94 	delete[] _walkOffDown;
95 	delete[] _walkOffUR;
96 	delete[] _walkOffDR;
97 	delete[] _walkOffUL;
98 	delete[] _walkOffDL;
99 }
100 
load()101 void Player::load() {
102 	int dataCount = _vm->_playerDataCount;
103 	_walkOffRight = new int[dataCount];
104 	_walkOffLeft = new int[dataCount];
105 	_walkOffUp = new int[dataCount];
106 	_walkOffDown = new int[dataCount];
107 	_walkOffUR = new Common::Point[dataCount];
108 	_walkOffDR = new Common::Point[dataCount];
109 	_walkOffUL = new Common::Point[dataCount];
110 	_walkOffDL = new Common::Point[dataCount];
111 
112 	_playerOffset.x = _vm->_screen->_scaleTable1[25];
113 	_playerOffset.y = _vm->_screen->_scaleTable1[67];
114 	_leftDelta = -3;
115 	_rightDelta = 33;
116 	_upDelta = 5;
117 	_downDelta = -10;
118 	_scrollConst = 5;
119 
120 	_sideWalkMin = 0;
121 	_sideWalkMax = 7;
122 	_upWalkMin = 16;
123 	_upWalkMax = 23;
124 	_downWalkMin = 8;
125 	_downWalkMax = 15;
126 	_diagUpWalkMin = 0;
127 	_diagUpWalkMax = 7;
128 	_diagDownWalkMin = 0;
129 	_diagDownWalkMax = 7;
130 
131 	_playerSprites = _playerSprites1;
132 	if (_manPal1) {
133 		// Those values are from MM as Amazon doesn't use it
134 		Common::copy(_manPal1 + 0x2A0, _manPal1 + 0x2A0 + 0x42, _vm->_screen->_manPal);
135 	} else {
136 		Common::fill(_vm->_screen->_manPal, _vm->_screen->_manPal + 0x60, 0);
137 	}
138 }
139 
loadTexPalette()140 void Player::loadTexPalette() {
141 	Resource *texPal = _vm->_files->loadFile("TEXPAL.COL");
142 	int size = texPal->_size;
143 	assert(size == 768);
144 	_manPal1 = new byte[size];
145 	memcpy(_manPal1, texPal->data(), size);
146 }
147 
loadSprites(const Common::String & name)148 void Player::loadSprites(const Common::String &name) {
149 	freeSprites();
150 
151 	Resource *data = _vm->_files->loadFile(name);
152 
153 #if 0
154 	Common::DumpFile *outFile = new Common::DumpFile();
155 	Common::String outName = name + ".dump";
156 	outFile->open(outName);
157 	outFile->write(data->data(), data->_size);
158 	outFile->finalize();
159 	outFile->close();
160 #endif
161 
162 	_playerSprites1 = new SpriteResource(_vm, data);
163 	delete data;
164 }
165 
freeSprites()166 void Player::freeSprites() {
167 	delete _playerSprites;
168 	_playerSprites1 = nullptr;
169 	_playerSprites = nullptr;
170 }
171 
removeSprite1()172 void Player::removeSprite1() {
173 	if (_playerSprites1) {
174 		delete _playerSprites1;
175 		_playerSprites1 = nullptr;
176 	}
177 }
178 
calcManScale()179 void Player::calcManScale() {
180 	if (!_vm->_manScaleOff) {
181 		_vm->_scale = ((((_rawPlayer.y - _vm->_scaleMaxY + _vm->_scaleN1) *
182 			_vm->_scaleT1 + (_vm->_scaleH2 << 8)) & 0xff00) / _vm->_scaleH1 * _vm->_scaleI) >> 8;
183 		_vm->_screen->setScaleTable(_vm->_scale);
184 
185 		_playerOffset.x = _vm->_screen->_scaleTable1[20];
186 		_playerOffset.y = _vm->_screen->_scaleTable1[67];
187 		_inactiveYOff = _playerOffset.y;
188 	}
189 }
190 
walk()191 void Player::walk() {
192 	_collideFlag = false;
193 	_playerDirection = NONE;
194 
195 	if (_playerOff)
196 		return;
197 	else if (_vm->_timers[0]._flag) {
198 		plotCom3();
199 		return;
200 	}
201 
202 	++_vm->_timers[0]._flag;
203 	switch (_move) {
204 	case UP:
205 		_playerMove = false;
206 		walkUp();
207 		break;
208 	case DOWN:
209 		_playerMove = false;
210 		walkDown();
211 		break;
212 	case LEFT:
213 		_playerMove = false;
214 		walkLeft();
215 		break;
216 	case RIGHT:
217 		_playerMove = false;
218 		walkRight();
219 		break;
220 	case UPLEFT:
221 		_playerMove = false;
222 		walkUpLeft();
223 		break;
224 	case DOWNLEFT:
225 		_playerMove = false;
226 		walkDownLeft();
227 		break;
228 	case UPRIGHT:
229 		_playerMove = false;
230 		walkUpRight();
231 		break;
232 	case DOWNRIGHT:
233 		_playerMove = false;
234 		walkDownRight();
235 		break;
236 	default:
237 		checkMove();
238 		break;
239 	}
240 }
241 
calcPlayer()242 void Player::calcPlayer() {
243 	Screen &scr = *_vm->_screen;
244 	scr._bufferStart.x = (_vm->_scrollCol << 4) + _vm->_scrollX;
245 	scr._bufferStart.y = (_vm->_scrollRow << 4) + _vm->_scrollY;
246 	_playerX = _rawPlayer.x - scr._bufferStart.x;
247 	_playerY = _rawPlayer.y - scr._bufferStart.y;
248 }
249 
walkUp()250 void Player::walkUp() {
251 	if (_frame > _upWalkMax || _frame < _upWalkMin)
252 		_frame = _upWalkMin;
253 
254 	_playerDirection = UP;
255 	int walkOff = _walkOffUp[_frame - _upWalkMin];
256 	int tempL = _rawPlayerLow.y - _vm->_screen->_scaleTable2[walkOff];
257 	_rawYTempL = (byte)tempL;
258 	int yTemp = _rawPlayer.y - _vm->_screen->_scaleTable1[walkOff] -
259 		(tempL < 0 ? 1 : 0);
260 	_rawYTemp = yTemp;
261 	_rawXTemp = _rawPlayer.x;
262 
263 	if (_vm->_room->codeWalls()) {
264 		plotCom2();
265 	} else {
266 		_rawPlayer.y = _rawYTemp;
267 		_rawPlayerLow.y = _rawYTempL;
268 
269 		calcManScale();
270 
271 		// This code looks totally useless as 'si' is unconditionally set in plotCom
272 		//if (_vm->_currentMan != 3 && (_frame == 17 || _frame == 21))
273 		//	warning("TODO: walkUp - si = 0?");
274 
275 		if (++_frame > _upWalkMax)
276 			_frame = _upWalkMin;
277 
278 		plotCom(0);
279 	}
280 }
281 
walkDown()282 void Player::walkDown() {
283 	if (_frame > _downWalkMax || _frame < _downWalkMin)
284 		_frame = _downWalkMin;
285 
286 	_playerDirection = DOWN;
287 	int walkOff = _walkOffDown[_frame - _downWalkMin];
288 	int tempL = _vm->_screen->_scaleTable2[walkOff] + _rawPlayerLow.y;
289 	_rawYTempL = (byte)tempL;
290 	_rawYTemp = _vm->_screen->_scaleTable1[walkOff] + _rawPlayer.y + (tempL >= 0x100 ? 1 : 0);
291 	_rawXTemp = _rawPlayer.x;
292 
293 	if (_vm->_room->codeWalls()) {
294 		plotCom2();
295 	} else {
296 		_rawPlayer.y = _rawYTemp;
297 		_rawPlayerLow.y = _rawYTempL;
298 
299 		calcManScale();
300 
301 		// This code looks totally useless as 'si' is unconditionally set in plotCom
302 		//if (_vm->_currentMan != 3 && (_frame == 10 || _frame == 14))
303 		//	warning("TODO: walkDown - si = 0?");
304 
305 		if (++_frame > _downWalkMax)
306 			_frame = _downWalkMin;
307 
308 		plotCom(0);
309 	}
310 }
311 
walkLeft()312 void Player::walkLeft() {
313 	if (_frame > _sideWalkMax || _frame < _sideWalkMin)
314 		_frame = _sideWalkMin;
315 
316 	_playerDirection = LEFT;
317 
318 	bool flag = _scrollEnd == 1;
319 	if (!flag) {
320 		calcPlayer();
321 		flag = (_playerX - _vm->_screen->_scaleTable1[_scrollConst] -
322 			_vm->_player->_scrollThreshold) > 0;
323 	}
324 	if (flag) {
325 		int walkOffset = _walkOffLeft[_frame - _sideWalkMin];
326 		int tempL = _rawPlayerLow.x - _vm->_screen->_scaleTable2[walkOffset];
327 		_rawTempL = (byte)tempL;
328 		_rawXTemp = _rawPlayer.x - _vm->_screen->_scaleTable1[walkOffset] -
329 			(tempL < 0 ? 1 : 0);
330 	} else {
331 		_rawXTemp = _rawPlayer.x - _vm->_screen->_scaleTable1[_scrollConst];
332 	}
333 	_rawYTemp = _rawPlayer.y;
334 
335 	if (_vm->_room->codeWalls()) {
336 		plotCom2();
337 	} else {
338 		_rawPlayer.x = _rawXTemp;
339 		_rawPlayerLow.x = _rawTempL;
340 		++_frame;
341 
342 		// This code looks totally useless as 'si' is unconditionally set in plotCom1
343 		//if (_vm->_currentMan != 3 && (_frame == 1 || _frame == 5))
344 		//	warning("TODO: walkLeft - si = 0?");
345 
346 		if (_frame > _sideWalkMax)
347 			_frame = _sideWalkMin;
348 
349 		plotCom1();
350 	}
351 }
352 
walkRight()353 void Player::walkRight() {
354 	if (_frame > _sideWalkMax || _frame < _sideWalkMin)
355 		_frame = _sideWalkMin;
356 
357 	_playerDirection = RIGHT;
358 
359 	bool flag = _scrollEnd == 2;
360 	if (!flag) {
361 		calcPlayer();
362 		flag = (_vm->_screen->_clipWidth - _playerX - _vm->_screen->_scaleTable1[_scrollConst] -
363 			_vm->_player->_scrollThreshold) > 0;
364 	}
365 	if (flag) {
366 		int walkOffset = _walkOffRight[_frame - _sideWalkMin];
367 		int tempL = _rawPlayerLow.x + _vm->_screen->_scaleTable2[walkOffset];
368 		_rawTempL = (byte)tempL;
369 		_rawXTemp = _rawPlayer.x + _vm->_screen->_scaleTable1[walkOffset] +
370 			(tempL >= 0x100 ? 1 : 0);
371 	} else {
372 		_rawXTemp = _rawPlayer.x + _vm->_screen->_scaleTable1[_scrollConst];
373 	}
374 	_rawYTemp = _rawPlayer.y;
375 
376 	if (_vm->_room->codeWalls()) {
377 		plotCom2();
378 	} else {
379 		_rawPlayer.x = _rawXTemp;
380 		_rawPlayerLow.x = _rawTempL;
381 		++_frame;
382 
383 		// Useless check removed
384 		if (_frame > _sideWalkMax)
385 			_frame = _sideWalkMin;
386 
387 		plotCom0();
388 	}
389 }
390 
walkUpLeft()391 void Player::walkUpLeft() {
392 	if (_frame > _diagUpWalkMax || _frame < _diagUpWalkMin)
393 		_frame = _diagUpWalkMin;
394 
395 	_playerDirection = UPLEFT;
396 
397 	int walkOffset, tempL;
398 	bool flag = _scrollEnd == 1;
399 	if (!flag) {
400 		calcPlayer();
401 		flag = (_playerX - _vm->_screen->_scaleTable1[_scrollConst] -
402 			_vm->_player->_scrollThreshold) > 0;
403 	}
404 	if (flag) {
405 		walkOffset = _walkOffUL[_frame - _diagUpWalkMin].x;
406 		tempL = _rawPlayerLow.x - _vm->_screen->_scaleTable2[walkOffset];
407 		_rawTempL = (byte)tempL;
408 		_rawXTemp = _rawPlayer.x - _vm->_screen->_scaleTable1[walkOffset] -
409 			(tempL < 0 ? 1 : 0);
410 	} else {
411 		_rawXTemp = _rawPlayer.x - _vm->_screen->_scaleTable1[_scrollConst];
412 	}
413 
414 	walkOffset = _walkOffUL[_frame - _diagUpWalkMin].y;
415 	tempL = _rawPlayerLow.y - _vm->_screen->_scaleTable2[walkOffset];
416 	_rawYTempL = (byte)tempL;
417 	_rawYTemp = _rawPlayer.y - _vm->_screen->_scaleTable1[walkOffset] -
418 		(tempL < 0 ? 1 : 0);
419 
420 	if (_vm->_room->codeWalls()) {
421 		plotCom2();
422 	} else {
423 		_rawPlayer.x = _rawXTemp;
424 		_rawPlayer.y = _rawYTemp;
425 		_rawPlayerLow.x = _rawTempL;
426 		_rawPlayerLow.y = _rawYTempL;
427 
428 		++_frame;
429 		calcManScale();
430 
431 		// This code looks totally useless as 'si' is unconditionally set in plotCom1
432 		//if (_vm->_currentMan != 3 && (_frame == 1 || _frame == 5))
433 		//	warning("TODO: walkUpLeft - si = 0?");
434 
435 		if (_frame > _diagUpWalkMax)
436 			_frame = _diagUpWalkMin;
437 
438 		plotCom1();
439 	}
440 }
441 
walkDownLeft()442 void Player::walkDownLeft() {
443 	if (_frame > _diagDownWalkMax || _frame < _diagDownWalkMin)
444 		_frame = _diagDownWalkMin;
445 
446 	_playerDirection = DOWNLEFT;
447 
448 	int walkOffset, tempL;
449 	bool flag = _scrollEnd == 1;
450 	if (!flag) {
451 		calcPlayer();
452 		flag = (_playerX - _vm->_screen->_scaleTable1[_scrollConst] -
453 			_vm->_player->_scrollThreshold) > 0;
454 	}
455 	if (flag) {
456 		walkOffset = _walkOffDL[_frame - _sideWalkMin].x;
457 		tempL = _rawPlayerLow.x - _vm->_screen->_scaleTable2[walkOffset];
458 		_rawTempL = (byte)tempL;
459 		_rawXTemp = _rawPlayer.x - _vm->_screen->_scaleTable1[walkOffset] -
460 			(tempL < 0 ? 1 : 0);
461 	} else {
462 		_rawXTemp = _rawPlayer.x - _vm->_screen->_scaleTable1[_scrollConst];
463 	}
464 
465 	walkOffset = _walkOffDL[_frame - _diagDownWalkMin].y;
466 	tempL = _rawPlayerLow.y + _vm->_screen->_scaleTable2[walkOffset];
467 	_rawYTempL = (byte)tempL;
468 	_rawYTemp = _rawPlayer.y + _vm->_screen->_scaleTable1[walkOffset] +
469 		(tempL >= 0x100 ? 1 : 0);
470 
471 	if (_vm->_room->codeWalls()) {
472 		plotCom2();
473 	} else {
474 		_rawPlayer.x = _rawXTemp;
475 		_rawPlayer.y = _rawYTemp;
476 		_rawPlayerLow.x = _rawTempL;
477 		_rawPlayerLow.y = _rawYTempL;
478 
479 		++_frame;
480 		calcManScale();
481 
482 		// This code looks totally useless as 'si' is unconditionally set in plotCom1
483 		//if (_vm->_currentMan != 3 && (_frame == 1 || _frame == 5))
484 		//	warning("TODO: walkDownLeft - si = 0?");
485 
486 		if (_frame > _diagDownWalkMax)
487 			_frame = _diagDownWalkMin;
488 
489 		plotCom1();
490 	}
491 }
492 
walkUpRight()493 void Player::walkUpRight() {
494 	if (_frame > _diagUpWalkMax || _frame < _diagUpWalkMin)
495 		_frame = _diagUpWalkMin;
496 
497 	_playerDirection = UPRIGHT;
498 
499 	int walkOffset, tempL;
500 	bool flag = _scrollEnd == 1;
501 	if (!flag) {
502 		calcPlayer();
503 		flag = (_vm->_screen->_clipWidth - _playerX - _vm->_screen->_scaleTable1[_scrollConst] -
504 			_vm->_player->_scrollThreshold) > 0;
505 	}
506 	if (flag) {
507 		walkOffset = _walkOffUR[_frame - _diagUpWalkMin].x;
508 		tempL = _rawPlayerLow.x + _vm->_screen->_scaleTable2[walkOffset];
509 		_rawTempL = (byte)tempL;
510 		_rawXTemp = _rawPlayer.x + _vm->_screen->_scaleTable1[walkOffset] +
511 			(tempL >= 0x100 ? 1 : 0);
512 	} else {
513 		_rawXTemp = _rawPlayer.x + _vm->_screen->_scaleTable1[_scrollConst];
514 	}
515 
516 	walkOffset = _walkOffUL[_frame - _diagUpWalkMin].y;
517 	tempL = _rawPlayerLow.y - _vm->_screen->_scaleTable2[walkOffset];
518 	_rawYTempL = (byte)tempL;
519 	_rawYTemp = _rawPlayer.y - _vm->_screen->_scaleTable1[walkOffset] -
520 		(tempL < 0 ? 1 : 0);
521 
522 	if (_vm->_room->codeWalls()) {
523 		plotCom2();
524 	} else {
525 		_rawPlayer.x = _rawXTemp;
526 		_rawPlayer.y = _rawYTemp;
527 		_rawPlayerLow.x = _rawTempL;
528 		_rawPlayerLow.y = _rawYTempL;
529 
530 		++_frame;
531 		calcManScale();
532 
533 		// This code looks totally useless as 'si' is unconditionally set in plotCom
534 		//if (_vm->_currentMan != 3 && (_frame == 1 || _frame == 5))
535 		//	warning("TODO: walkUpRight - si = 0?");
536 
537 		if (_frame > _diagUpWalkMax)
538 			_frame = _diagUpWalkMin;
539 
540 		plotCom(0);
541 	}
542 }
543 
walkDownRight()544 void Player::walkDownRight() {
545 	if (_frame > _diagDownWalkMax || _frame < _diagDownWalkMin)
546 		_frame = _diagDownWalkMin;
547 
548 	_playerDirection = DOWNRIGHT;
549 
550 	int walkOffset, tempL;
551 	bool flag = _scrollEnd == 2;
552 	if (!flag) {
553 		calcPlayer();
554 		flag = (_vm->_screen->_clipWidth - _playerX - _vm->_screen->_scaleTable1[_scrollConst] -
555 			_vm->_player->_scrollThreshold) > 0;
556 	}
557 	if (flag) {
558 		walkOffset = _walkOffUR[_frame - _diagDownWalkMin].x;
559 		tempL = _rawPlayerLow.x + _vm->_screen->_scaleTable2[walkOffset];
560 		_rawTempL = (byte)tempL;
561 		_rawXTemp = _rawPlayer.x + _vm->_screen->_scaleTable1[walkOffset] +
562 			(tempL >= 0x100 ? 1 : 0);
563 	} else {
564 		_rawXTemp = _rawPlayer.x + _vm->_screen->_scaleTable1[_scrollConst];
565 	}
566 
567 	walkOffset = _walkOffDR[_frame - _diagDownWalkMin].y;
568 	tempL = _rawPlayerLow.y + _vm->_screen->_scaleTable2[walkOffset];
569 	_rawYTempL = (byte)tempL;
570 	_rawYTemp = _rawPlayer.y + _vm->_screen->_scaleTable1[walkOffset] +
571 		(tempL >= 0x100 ? 1 : 0);
572 
573 	if (_vm->_room->codeWalls()) {
574 		plotCom2();
575 	} else {
576 		_rawPlayer.x = _rawXTemp;
577 		_rawPlayer.y = _rawYTemp;
578 		_rawPlayerLow.x = _rawTempL;
579 		_rawPlayerLow.y = _rawYTempL;
580 
581 		calcManScale();
582 
583 		// This code looks totally useless as 'si' is unconditionally set in plotCom1
584 		//if (_vm->_currentMan != 3 && (_frame == 1 || _frame == 5))
585 		//	warning("TODO: walkDownRight - si = 0?");
586 
587 		++_frame;
588 		if (_frame > _diagDownWalkMax)
589 			_frame = _diagDownWalkMin;
590 
591 		plotCom(0);
592 	}
593 }
594 
checkMove()595 void Player::checkMove() {
596 	if (_playerMove) {
597 		if (_xFlag == 0 && _yFlag == 0) {
598 			int xp = (_playerOffset.x / 2) + _rawPlayer.x - _moveTo.x;
599 			if (xp < 0)
600 				xp = -xp;
601 			int yp = _rawPlayer.y - _moveTo.y;
602 			if (yp < 0)
603 				yp = -yp;
604 
605 			if (xp >= yp)
606 				_xFlag = 1;
607 			else
608 				_yFlag = 1;
609 		}
610 
611 		if (_yFlag == 1) {
612 			int yd = _rawPlayer.y - _moveTo.y;
613 			if ((yd >= 0 && yd <= _upDelta) || (yd < 0 && -yd <= _upDelta)) {
614 				++_yFlag;
615 				if (_xFlag) {
616 					_playerMove = false;
617 					_xFlag = _yFlag = 0;
618 				} else {
619 					++_xFlag;
620 				}
621 			} else {
622 				if (yd >= 0)
623 					walkUp();
624 				else
625 					walkDown();
626 
627 				if (_collideFlag) {
628 					_playerMove = false;
629 					_xFlag = _yFlag = 0;
630 				}
631 			}
632 		} else if (_xFlag == 1) {
633 			int xd = (_playerOffset.x / 2) + _rawPlayer.x - _moveTo.x;
634 			if ((xd >= 0 && xd <= -_leftDelta) || (xd < 0 && -xd <= -_leftDelta)) {
635 				++_xFlag;
636 
637 				if (_yFlag) {
638 					_playerMove = false;
639 					_xFlag = _yFlag = 0;
640 				}
641 			} else {
642 				if (xd >= 0)
643 					walkLeft();
644 				else
645 					walkRight();
646 
647 				if (_collideFlag) {
648 					_playerMove = false;
649 					_xFlag = _yFlag = 0;
650 				}
651 			}
652 		} else if (!_yFlag) {
653 			++_yFlag;
654 		} else {
655 			_playerMove = false;
656 			_xFlag = _yFlag = 0;
657 		}
658 	}
659 
660 	plotCom3();
661 }
662 
plotCom(int flags)663 void Player::plotCom(int flags) {
664 	_flags &= ~IMGFLAG_BACKWARDS;
665 	_flags &= ~IMGFLAG_UNSCALED;
666 	_flags |= flags;
667 
668 	plotCom3();
669 }
670 
plotCom0()671 void Player::plotCom0() {
672 	plotCom(_vm->getGameID() == GType_Amazon ? 0 : IMGFLAG_BACKWARDS);
673 }
674 
plotCom1()675 void Player::plotCom1() {
676 	plotCom(_vm->getGameID() == GType_Amazon ? IMGFLAG_BACKWARDS : 0);
677 }
678 
plotCom2()679 void Player::plotCom2() {
680 	// WORKAROUND: Amazon has at least one cutscene with the player not properly turned off
681 	if (!_playerOff && _spritesPtr != nullptr)
682 		_vm->_images.addToList(*this);
683 }
684 
plotCom3()685 void Player::plotCom3() {
686 	// Update the base ImageEntry fields for the player
687 	_position.x = _rawPlayer.x;
688 	_position.y = _rawPlayer.y - _playerOffset.y;
689 	_offsetY = _playerOffset.y;
690 	_spritesPtr = _playerSprites;
691 	_frameNumber = _frame;
692 
693 	plotCom2();
694 }
695 
checkScrollUp()696 void Player::checkScrollUp() {
697 	if ((_playerDirection == DOWNRIGHT || _playerDirection == DOWNLEFT ||
698 		_playerDirection == DOWN) && (_vm->_screen->_clipHeight -
699 		_playerY - _scrollThreshold) <= 0) {
700 			// Scroll up
701 			if (scrollUp()) {
702 				_scrollEnd = 4;
703 				_vm->_scrollY &= TILE_HEIGHT;
704 				_scrollFlag = true;
705 			}
706 	}
707 }
708 
checkScroll()709 void Player::checkScroll() {
710 	_scrollFlag = false;
711 	if (_playerDirection == NONE)
712 		return;
713 
714 	if ((_playerDirection == UPLEFT || _playerDirection == DOWNLEFT ||
715 			_playerDirection == LEFT) && _playerX <= _scrollThreshold) {
716 		// Scroll right
717 		if (!scrollRight()) {
718 			if (_playerDirection == DOWNLEFT)
719 				checkScrollUp();
720 
721 			return;
722 		}
723 	} else if ((_playerDirection == UPRIGHT || _playerDirection == DOWNRIGHT ||
724 			_playerDirection == RIGHT) && (_vm->_screen->_clipWidth -
725 			_playerX - _scrollThreshold) <= 0) {
726 		// Scroll left
727 		if (!scrollLeft()) {
728 			if (_playerDirection == DOWNRIGHT)
729 				checkScrollUp();
730 
731 			return;
732 		}
733 	}
734 
735 	if ((_playerDirection == UPRIGHT || _playerDirection == UPLEFT ||
736 			_playerDirection == UP) && _playerY <= _scrollThreshold) {
737 		scrollDown();
738 	} else {
739 		checkScrollUp();
740 	}
741 }
742 
scrollUp(int forcedAmount)743 bool Player::scrollUp(int forcedAmount) {
744 	if (forcedAmount == -1)
745 		_scrollAmount = -(_vm->_screen->_clipHeight - _playerY - _scrollThreshold);
746 	else
747 		_scrollAmount = forcedAmount;
748 
749 	if ((_vm->_scrollRow + _vm->_screen->_vWindowHeight) >=
750 			_vm->_room->_playFieldHeight)
751 		return true;
752 
753 	_scrollFlag = true;
754 	_vm->_scrollY = _vm->_scrollY + _scrollAmount;
755 
756 	while (_vm->_scrollY >= TILE_HEIGHT && !_vm->shouldQuit()) {
757 			_vm->_scrollY -= TILE_HEIGHT;
758 		++_vm->_scrollRow;
759 		_vm->_buffer1.moveBufferUp();
760 
761 		_vm->_room->buildRow(_vm->_scrollRow + _vm->_screen->_vWindowHeight,
762 			_vm->_screen->_vWindowLinesTall);
763 
764 		if ((_vm->_scrollRow + _vm->_screen->_vWindowHeight) >=
765 			_vm->_room->_playFieldHeight)
766 			return true;
767 
768 		if (_vm->_scrollY <= TILE_HEIGHT)
769 			return false;
770 	}
771 
772 	return false;
773 }
774 
scrollDown(int forcedAmount)775 bool Player::scrollDown(int forcedAmount) {
776 	if (forcedAmount == -1)
777 		_scrollAmount = -(_playerY - _scrollThreshold);
778 	else
779 		_scrollAmount = forcedAmount;
780 
781 	_scrollFlag = true;
782 	_vm->_scrollY -= _scrollAmount;
783 	if (_vm->_scrollY >= 0)
784 		return true;
785 
786 	do {
787 		_vm->_scrollY += TILE_HEIGHT;
788 		if (--_vm->_scrollRow < 0)
789 			break;
790 
791 		_vm->_buffer1.moveBufferDown();
792 		_vm->_room->buildRow(_vm->_scrollRow, 0);
793 
794 		if (_vm->_scrollY >= 0)
795 			return false;
796 	} while (!_vm->shouldQuit());
797 
798 	_scrollEnd = 3;
799 	_vm->_scrollY = 0;
800 	_vm->_scrollRow = 0;
801 	return true;
802 }
803 
scrollLeft(int forcedAmount)804 bool Player::scrollLeft(int forcedAmount) {
805 	Screen &screen = *_vm->_screen;
806 	if (forcedAmount == -1)
807 		_scrollAmount = -(_vm->_screen->_clipWidth - _playerX - _scrollThreshold);
808 	else
809 		_scrollAmount = forcedAmount;
810 
811 	if ((_vm->_scrollCol + screen._vWindowWidth) == _vm->_room->_playFieldWidth) {
812 		_scrollEnd = 2;
813 		_vm->_scrollX = 0;
814 		_scrollFlag = true;
815 		return true;
816 	} else {
817 		_scrollFlag = true;
818 		_vm->_scrollX = _vm->_scrollX + _scrollAmount;
819 
820 		do {
821 			if (_vm->_scrollX < TILE_WIDTH)
822 				return true;
823 
824 			_vm->_scrollX -= TILE_WIDTH;
825 			++_vm->_scrollCol;
826 			_vm->_buffer1.moveBufferLeft();
827 			_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth,
828 				screen._vWindowBytesWide);
829 		} while (!_vm->shouldQuit() && (_vm->_scrollX >= TILE_WIDTH));
830 
831 		return (_playerDirection == UPRIGHT);
832 	}
833 }
834 
scrollRight(int forcedAmount)835 bool Player::scrollRight(int forcedAmount) {
836 	if (forcedAmount == -1)
837 		_scrollAmount = -(_playerX - _scrollThreshold);
838 	else
839 		_scrollAmount = forcedAmount;
840 
841 	_scrollFlag = true;
842 	_vm->_scrollX -= _scrollAmount;
843 
844 	if (_vm->_scrollX < 0) {
845 		do {
846 			_vm->_scrollX += TILE_WIDTH;
847 			if (--_vm->_scrollCol < 0) {
848 				_scrollEnd = true;
849 				_vm->_scrollX = 0;
850 				_vm->_scrollCol = 0;
851 				return true;
852 			}
853 
854 			_vm->_buffer1.moveBufferRight();
855 			_vm->_room->buildColumn(_vm->_scrollCol, 0);
856 		} while (!_vm->shouldQuit() && (_vm->_scrollX < 0));
857 
858 		return false;
859 	}
860 
861 	return true;
862 }
863 
synchronize(Common::Serializer & s)864 void Player::synchronize(Common::Serializer &s) {
865 	s.syncAsUint16LE(_roomNumber);
866 	s.syncAsSint16LE(_rawPlayerLow.x);
867 	s.syncAsSint16LE(_rawPlayer.x);
868 	s.syncAsSint16LE(_rawPlayerLow.y);
869 	s.syncAsSint16LE(_rawPlayer.y);
870 }
871 
872 } // End of namespace Access
873