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