~ubuntu-branches/debian/jessie/scummvm/jessie

« back to all changes in this revision

Viewing changes to engines/mads/player.cpp

  • Committer: Package Import Robot
  • Author(s): Dmitry Smirnov
  • Date: 2014-08-10 00:50:36 UTC
  • mfrom: (1.2.22)
  • Revision ID: package-import@ubuntu.com-20140810005036-wls6i0dsxqfxu70g
Tags: 1.7.0+dfsg-1
* New upstream release [July 2014].
  - remove old/obsolete patches.
  + added new "drop1test.patch" to disable problematic test.
  + build with "--disable-eventrecorder" to avoid FTBFS in tests.
  + added "libjpeg-dev" and "libfaad-dev" to Build-Depends.
* Install all arch-independent files (themes, game data, etc.).
* Build-time re-compression of "classic" theme.
* Added "debian/gbp.conf".
* Standards-Version to 3.9.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ScummVM - Graphic Adventure Engine
 
2
 *
 
3
 * ScummVM is the legal property of its developers, whose names
 
4
 * are too numerous to list here. Please refer to the COPYRIGHT
 
5
 * file distributed with this source distribution.
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU General Public License
 
9
 * as published by the Free Software Foundation; either version 2
 
10
 * of the License, or (at your option) any later version.
 
11
 
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
20
 *
 
21
 */
 
22
 
 
23
#include "common/scummsys.h"
 
24
#include "mads/mads.h"
 
25
#include "mads/player.h"
 
26
 
 
27
namespace MADS {
 
28
 
 
29
#define PLAYER_SEQ_INDEX -2
 
30
 
 
31
const int Player::_directionListIndexes[32] = {
 
32
        0, 7, 4, 3, 6, 0, 2, 5, 0, 1, 9, 4, 1, 2, 7, 9, 3, 8, 9, 6, 7, 2, 3, 6, 1, 7, 9, 4, 7, 8, 0, 0
 
33
};
 
34
 
 
35
Player::Player(MADSEngine *vm)
 
36
        : _vm(vm) {
 
37
        _action = nullptr;
 
38
        _facing = FACING_NORTH;
 
39
        _turnToFacing = FACING_NORTH;
 
40
        _targetFacing = FACING_NORTH;
 
41
        _prepareWalkFacing = FACING_NONE;
 
42
        _mirror = false;
 
43
        _spritesLoaded = false;
 
44
        _spritesStart = 0;
 
45
        _spritesIdx = 0;
 
46
        _numSprites = 0;
 
47
        _stepEnabled = false;
 
48
        _visible = false;
 
49
        _priorVisible = false;
 
50
        _needToWalk = false;
 
51
        _readyToWalk = false;
 
52
        _beenVisible = false;
 
53
        _loadsFirst = false;
 
54
        _loadedFirst = false;
 
55
        _walkAnywhere = false;
 
56
        _special = 0;
 
57
        _ticksAmount = 0;
 
58
        _priorTimer = 0;
 
59
        _trigger = 0;
 
60
        _scalingVelocity = false;
 
61
        _spritesChanged = false;
 
62
        _forceRefresh = false;
 
63
        _highSprites = false;
 
64
        _currentDepth = 0;
 
65
        _currentScale = 0;
 
66
        _frameNumber = 0;
 
67
        _centerOfGravity = 0;
 
68
        _frameCount = 0;
 
69
        _velocity = 0;
 
70
        _upcomingTrigger = 0;
 
71
        _trigger = 0;
 
72
        _frameListIndex = 0;
 
73
        _stopWalkerIndex = 0;
 
74
        _totalDistance = 0;
 
75
        _distAccum = 0;
 
76
        _pixelAccum = 0;
 
77
        _deltaDistance = 0;
 
78
        _xDirection = 0;
 
79
        _yDirection = 0;
 
80
        _moving = false;
 
81
        _walkOffScreen = 0;
 
82
        _walkOffScreenSceneId = -1;
 
83
 
 
84
        Common::fill(&_stopWalkerList[0], &_stopWalkerList[12], 0);
 
85
        Common::fill(&_stopWalkerTrigger[0], &_stopWalkerTrigger[12], 0);
 
86
        Common::fill(&_spriteSetsPresent[0], &_spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT], false);
 
87
}
 
88
 
 
89
void Player::cancelWalk() {
 
90
        Scene &scene = _vm->_game->_scene;
 
91
        _action = &scene._action;
 
92
        _targetPos = _playerPos;
 
93
        _targetFacing = FACING_NONE;
 
94
        _turnToFacing = _facing;
 
95
        _moving = false;
 
96
        _walkOffScreen = _walkOffScreenSceneId = 0;
 
97
        scene._rails.resetRoute();
 
98
        _walkAnywhere = false;
 
99
 
 
100
        _needToWalk = false;
 
101
        _readyToWalk = false;
 
102
}
 
103
 
 
104
bool Player::loadSprites(const Common::String &prefix) {
 
105
        Common::String suffixList = "89632741";
 
106
 
 
107
        Common::String newPrefix;
 
108
        if (prefix.empty()) {
 
109
                newPrefix = _spritesPrefix;
 
110
        } else {
 
111
                _spritesPrefix = prefix;
 
112
                newPrefix = prefix;
 
113
        }
 
114
 
 
115
        _numSprites = 0;
 
116
        if (!_spritesPrefix.empty()) {
 
117
                for (int fileIndex = 0; fileIndex < PLAYER_SPRITES_FILE_COUNT; ++fileIndex) {
 
118
                        Common::String setName = Common::String::format("*%s_%c.SS",
 
119
                                newPrefix.c_str(), suffixList[fileIndex]);
 
120
                        if (fileIndex >= 5)
 
121
                                _highSprites = true;
 
122
 
 
123
                        _spriteSetsPresent[fileIndex] = true;
 
124
 
 
125
                        int setIndex = -1;
 
126
                        if (Common::File::exists(setName)) {
 
127
                                setIndex = _vm->_game->_scene._sprites.addSprites(setName, 4);
 
128
                                ++_numSprites;
 
129
                        }  else if (fileIndex < 5) {
 
130
                                _highSprites = false;
 
131
                                return true;
 
132
                        } else {
 
133
                                _spriteSetsPresent[fileIndex] = false;
 
134
                        }
 
135
 
 
136
                        if (fileIndex == 0)
 
137
                                _spritesStart = setIndex;
 
138
                }
 
139
 
 
140
                _spritesLoaded = true;
 
141
                _spritesChanged = false;
 
142
        } else {
 
143
                Common::fill(&_spriteSetsPresent[0], &_spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT], false);
 
144
                _visible = false;
 
145
        }
 
146
 
 
147
        _highSprites = false;
 
148
        return false;
 
149
}
 
150
 
 
151
void Player::setFinalFacing() {
 
152
        if (_targetFacing != FACING_NONE)
 
153
                _turnToFacing = _targetFacing;
 
154
}
 
155
 
 
156
void Player::changeFacing() {
 
157
        int dirIndex = 0, dirIndex2 = 0;
 
158
        int newDir = 0, newDir2 = 0;
 
159
 
 
160
        if (_facing != _turnToFacing) {
 
161
                // Find the index for the given direction in the player direction list
 
162
                int tempDir = _facing;
 
163
                do {
 
164
                        ++dirIndex;
 
165
                        newDir += tempDir;
 
166
                        tempDir = _directionListIndexes[tempDir + 10];
 
167
                } while (tempDir != _turnToFacing);
 
168
        }
 
169
 
 
170
 
 
171
        if (_facing != _turnToFacing) {
 
172
                // Find the index for the given direction in the player direction list
 
173
                int tempDir = _facing;
 
174
                do {
 
175
                        ++dirIndex2;
 
176
                        newDir2 += tempDir;
 
177
                        tempDir = _directionListIndexes[tempDir + 20];
 
178
                } while (tempDir != _turnToFacing);
 
179
        }
 
180
 
 
181
        int diff = dirIndex - dirIndex2;
 
182
        if (diff == 0)
 
183
                diff = newDir - newDir2;
 
184
 
 
185
        _facing = (diff >= 0) ? (Facing)_directionListIndexes[_facing + 20] :
 
186
                (Facing)_directionListIndexes[_facing + 10];
 
187
        selectSeries();
 
188
 
 
189
        if ((_facing == _turnToFacing) && !_moving)
 
190
                updateFrame();
 
191
 
 
192
        _priorTimer += 1;
 
193
}
 
194
 
 
195
void Player::cancelCommand() {
 
196
        cancelWalk();
 
197
        _action->_inProgress = false;
 
198
}
 
199
 
 
200
void Player::selectSeries() {
 
201
        Scene &scene = _vm->_game->_scene;
 
202
 
 
203
        clearStopList();
 
204
        _mirror = false;
 
205
 
 
206
        _spritesIdx = _directionListIndexes[_facing];
 
207
        if (!_spriteSetsPresent[_spritesIdx]) {
 
208
                // Direction isn't present, so use alternate direction, with entries flipped
 
209
                _spritesIdx -= 4;
 
210
                _mirror = true;
 
211
        }
 
212
 
 
213
        // If the user isn't to be present (such as for a cutscene), exit immediately
 
214
        // WORKAROUND: Original didn't do a secondary check for the sprite set being
 
215
        // present, but it's needed to prevent invalid reads during cutscenes
 
216
        if ((_spritesStart + _spritesIdx) < 0 || !_spriteSetsPresent[_spritesIdx])
 
217
                return;
 
218
 
 
219
        SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
 
220
        assert(spriteSet._charInfo);
 
221
        _velocity = MAX(spriteSet._charInfo->_velocity, 100);
 
222
        setBaseFrameRate();
 
223
 
 
224
        _frameCount = spriteSet._charInfo->_totalFrames;
 
225
        if (_frameCount == 0)
 
226
                _frameCount = spriteSet.getCount();
 
227
 
 
228
        _centerOfGravity = spriteSet._charInfo->_centerOfGravity;
 
229
 
 
230
        if ((_frameNumber <= 0) || (_frameNumber > _frameCount))
 
231
                _frameNumber = 1;
 
232
 
 
233
        _forceRefresh = true;
 
234
}
 
235
 
 
236
void Player::updateFrame() {
 
237
        // WORKAROUND: Prevent character info being referenced when not present
 
238
        if ((_spritesStart + _spritesIdx) < 0 || !_spriteSetsPresent[_spritesStart + _spritesIdx])
 
239
                return;
 
240
 
 
241
        Scene &scene = _vm->_game->_scene;
 
242
        SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
 
243
        assert(spriteSet._charInfo);
 
244
 
 
245
        if (!spriteSet._charInfo->_numEntries) {
 
246
                _frameNumber = 1;
 
247
        } else {
 
248
                _frameListIndex = _stopWalkerList[_stopWalkerIndex];
 
249
 
 
250
                if (!_visible) {
 
251
                        _upcomingTrigger = 0;
 
252
                } else {
 
253
                        _upcomingTrigger = _stopWalkerTrigger[_stopWalkerIndex];
 
254
 
 
255
                        if (_stopWalkerIndex > 0)
 
256
                                --_stopWalkerIndex;
 
257
                }
 
258
 
 
259
                // Set the player frame number
 
260
                int listIndex = ABS(_frameListIndex);
 
261
                _frameNumber = (_frameListIndex >= 0) ? spriteSet._charInfo->_startFrames[listIndex] :
 
262
                        spriteSet._charInfo->_stopFrames[listIndex];
 
263
 
 
264
                // Set next waiting period in ticks
 
265
                if (listIndex == 0) {
 
266
                        setBaseFrameRate();
 
267
                } else {
 
268
                        _ticksAmount = spriteSet._charInfo->_ticksList[listIndex];
 
269
                }
 
270
        }
 
271
 
 
272
        _forceRefresh = true;
 
273
}
 
274
 
 
275
void Player::update() {
 
276
        Scene &scene = _vm->_game->_scene;
 
277
 
 
278
        if (_forceRefresh || (_visible != _priorVisible)) {
 
279
                int slotIndex = getSpriteSlot();
 
280
                if (slotIndex >= 0)
 
281
                        scene._spriteSlots[slotIndex]._flags = IMG_ERASE;
 
282
 
 
283
                int newDepth = 1;
 
284
                int yp = MIN(_playerPos.y, (int16)(MADS_SCENE_HEIGHT - 1));
 
285
 
 
286
                for (int idx = 1; idx < 15; ++idx) {
 
287
                        if (scene._sceneInfo->_depthList[newDepth] >= yp)
 
288
                                newDepth = idx + 1;
 
289
                }
 
290
                _currentDepth = newDepth;
 
291
 
 
292
                // Get the scale
 
293
                int newScale = getScale(_playerPos.y);
 
294
                _currentScale = MIN(newScale, 100);
 
295
 
 
296
                if (_visible) {
 
297
                        // Player sprite needs to be rendered
 
298
                        SpriteSlot slot;
 
299
                        slot._flags = IMG_UPDATE;
 
300
                        slot._seqIndex = PLAYER_SEQ_INDEX;
 
301
                        slot._spritesIndex = _spritesStart + _spritesIdx;
 
302
                        slot._frameNumber = _mirror ? -_frameNumber : _frameNumber;
 
303
                        slot._position.x = _playerPos.x;
 
304
                        slot._position.y = _playerPos.y + (_centerOfGravity * newScale) / 100;
 
305
                        slot._depth = newDepth;
 
306
                        slot._scale = newScale;
 
307
 
 
308
                        if (slotIndex >= 0) {
 
309
                                // Check if the existing player slot has the same details, and can be re-used
 
310
                                SpriteSlot &s2 = scene._spriteSlots[slotIndex];
 
311
                                bool equal = (s2._seqIndex == slot._seqIndex)
 
312
                                        && (s2._spritesIndex == slot._spritesIndex)
 
313
                                        && (s2._frameNumber == slot._frameNumber)
 
314
                                        && (s2._position == slot._position)
 
315
                                        && (s2._depth == slot._depth)
 
316
                                        && (s2._scale == slot._scale);
 
317
 
 
318
                                if (equal)
 
319
                                        // Undo the prior expiry of the player sprite
 
320
                                        s2._flags = IMG_STATIC;
 
321
                                else
 
322
                                        slotIndex = -1;
 
323
                        }
 
324
 
 
325
                        if (slotIndex < 0) {
 
326
                                // New slot needed, so allocate one and copy the slot data
 
327
                                slotIndex = scene._spriteSlots.add();
 
328
                                scene._spriteSlots[slotIndex] = slot;
 
329
                        }
 
330
 
 
331
                        // If changing a scene, check to change the scene when the player
 
332
                        // has moved off-screen
 
333
                        if (_walkOffScreen) {
 
334
                                SpriteAsset *asset = scene._sprites[slot._spritesIndex];
 
335
                                MSprite *frame = asset->getFrame(_frameNumber - 1);
 
336
                                int xScale = frame->w * newScale / 200;
 
337
                                int yScale = frame->h * newScale / 100;
 
338
                                int playerX = slot._position.x;
 
339
                                int playerY = slot._position.y;
 
340
 
 
341
                                if ((playerX + xScale) < 0 || (playerX + xScale) >= MADS_SCREEN_WIDTH ||
 
342
                                                playerY < 0 || (playerY + yScale) >= MADS_SCENE_HEIGHT) {
 
343
                                        scene._nextSceneId = _walkOffScreen;
 
344
                                        _walkOffScreen = 0;
 
345
                                        _walkAnywhere = false;
 
346
                                }
 
347
                        }
 
348
 
 
349
                }
 
350
        }
 
351
 
 
352
        _beenVisible |= _visible;
 
353
        _priorVisible = _visible;
 
354
        _forceRefresh = false;
 
355
}
 
356
 
 
357
void Player::clearStopList() {
 
358
        _stopWalkerList[0] = 0;
 
359
        _stopWalkerTrigger[0] = 0;
 
360
        _stopWalkerIndex = 0;
 
361
        _upcomingTrigger = 0;
 
362
        _trigger = 0;
 
363
}
 
364
 
 
365
void Player::startWalking(const Common::Point &pt, Facing facing) {
 
366
        Scene &scene = _vm->_game->_scene;
 
367
 
 
368
        clearStopList();
 
369
        setBaseFrameRate();
 
370
        _moving = true;
 
371
        _targetFacing = facing;
 
372
 
 
373
        bool v = scene._depthSurface.getDepthHighBit(pt);
 
374
 
 
375
        scene._rails.setupRoute(v, _playerPos, pt);
 
376
}
 
377
 
 
378
void Player::walk(const Common::Point &pos, Facing facing) {
 
379
        cancelWalk();
 
380
        _needToWalk = true;
 
381
        _readyToWalk = true;
 
382
        _prepareWalkPos = pos;
 
383
        _prepareWalkFacing = facing;
 
384
}
 
385
 
 
386
void Player::nextFrame() {
 
387
        Scene &scene = _vm->_game->_scene;
 
388
 
 
389
        uint32 newTime = _priorTimer + _ticksAmount;
 
390
        if (scene._frameStartTime >= newTime) {
 
391
                _priorTimer = scene._frameStartTime;
 
392
                if (_moving) {
 
393
                        move();
 
394
                } else {
 
395
                        idle();
 
396
                }
 
397
 
 
398
                setFrame();
 
399
                update();
 
400
        }
 
401
}
 
402
 
 
403
void Player::move() {
 
404
        Scene &scene = _vm->_game->_scene;
 
405
        Rails &rails = scene._rails;
 
406
        bool newFacing = false;
 
407
 
 
408
        if (_moving) {
 
409
                while (!_walkOffScreen && _playerPos == _targetPos) {
 
410
                        bool isRouteEmpty = rails.empty();
 
411
                        if (!isRouteEmpty) {
 
412
                                const WalkNode &node = rails.popNode();
 
413
 
 
414
                                _targetPos = node._walkPos;
 
415
                                newFacing = true;
 
416
                        } else if (!_walkOffScreenSceneId) {
 
417
                                // End of walking path
 
418
                                rails.resetRoute();
 
419
                                _moving = false;
 
420
                                setFinalFacing();
 
421
                                newFacing = true;
 
422
                        } else {
 
423
                                _walkOffScreen = _walkOffScreenSceneId;
 
424
                                _walkAnywhere = true;
 
425
                                _walkOffScreenSceneId = 0;
 
426
                                _stepEnabled = false;
 
427
                                newFacing = false;
 
428
                        }
 
429
 
 
430
                        if (!_moving)
 
431
                                break;
 
432
                }
 
433
        }
 
434
 
 
435
        if (newFacing && _moving)
 
436
                startMovement();
 
437
 
 
438
        if (_turnToFacing != _facing)
 
439
                changeFacing();
 
440
        else if (!_moving)
 
441
                updateFrame();
 
442
 
 
443
        int velocity = _velocity;
 
444
        if (_scalingVelocity && (_totalDistance > 0)) {
 
445
                int angleRange = 100 - _currentScale;
 
446
                int angleScale = angleRange * (_posDiff.x - 1) / _totalDistance + _currentScale;
 
447
                velocity = MAX(1L, (angleScale * _currentScale * velocity) / 10000L);
 
448
        }
 
449
 
 
450
        if (!_moving || (_facing != _turnToFacing))
 
451
                return;
 
452
 
 
453
        Common::Point newPos = _playerPos;
 
454
        newFacing = false;
 
455
        _special = 0;
 
456
 
 
457
        if (_distAccum < velocity) {
 
458
                do {
 
459
                        if (_pixelAccum < _posDiff.x)
 
460
                                _pixelAccum += _posDiff.y;
 
461
                        if (_pixelAccum >= _posDiff.x) {
 
462
                                if ((_posChange.y > 0) || _walkOffScreen)
 
463
                                        newPos.y += _yDirection;
 
464
                                --_posChange.y;
 
465
                                _pixelAccum -= _posDiff.x;
 
466
                        }
 
467
 
 
468
                        if (_pixelAccum < _posDiff.x) {
 
469
                                if ((_posChange.x > 0) || _walkOffScreen)
 
470
                                        newPos.x += _xDirection;
 
471
                                --_posChange.x;
 
472
                        }
 
473
 
 
474
                        if (!_walkAnywhere && !_walkOffScreen && (_walkOffScreenSceneId == 0)) {
 
475
                                newFacing = scene._depthSurface.getDepthHighBit(newPos);
 
476
 
 
477
                                if (_special == 0)
 
478
                                        _special = scene.getDepthHighBits(newPos);
 
479
                        }
 
480
 
 
481
                        _distAccum += _deltaDistance;
 
482
 
 
483
                } while ((_distAccum < velocity) && !newFacing && ((_posChange.x > 0) || (_posChange.y > 0) || (_walkOffScreen != 0)));
 
484
        }
 
485
 
 
486
        _distAccum -= velocity;
 
487
 
 
488
        if (newFacing) {
 
489
                cancelCommand();
 
490
        } else {
 
491
                if (!_walkOffScreen) {
 
492
                        // If the move is complete, make sure the position is exactly on the given destination
 
493
                        if (_posChange.x == 0)
 
494
                                newPos.x = _targetPos.x;
 
495
                        if (_posChange.y == 0)
 
496
                                newPos.y = _targetPos.y;
 
497
                }
 
498
 
 
499
                _playerPos = newPos;
 
500
        }
 
501
}
 
502
 
 
503
void Player::idle() {
 
504
        Scene &scene = _vm->_game->_scene;
 
505
 
 
506
        if (_facing != _turnToFacing) {
 
507
                // The direction has changed, so reset for new direction
 
508
                changeFacing();
 
509
                return;
 
510
        }
 
511
 
 
512
        if ((_spritesStart + _spritesIdx) < 0 || !_spriteSetsPresent[_spritesStart + _spritesIdx])
 
513
                return;
 
514
 
 
515
        SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
 
516
        assert(spriteSet._charInfo);
 
517
        if (spriteSet._charInfo->_numEntries == 0)
 
518
                // No entries, so exit immediately
 
519
                return;
 
520
 
 
521
        int frameIndex = ABS(_frameListIndex);
 
522
        int direction = (_frameListIndex < 0) ? -1 : 1;
 
523
 
 
524
        if (frameIndex >= spriteSet._charInfo->_numEntries) {
 
525
                // Reset back to the start of the list
 
526
                _frameListIndex = 0;
 
527
        }  else {
 
528
                _frameNumber += direction;
 
529
                _forceRefresh = true;
 
530
 
 
531
                if (spriteSet._charInfo->_stopFrames[frameIndex] < _frameNumber) {
 
532
                        _trigger = _upcomingTrigger;
 
533
                        updateFrame();
 
534
                }
 
535
                if (spriteSet._charInfo->_startFrames[frameIndex] < _frameNumber) {
 
536
                        _trigger = _upcomingTrigger;
 
537
                        updateFrame();
 
538
                }
 
539
        }
 
540
}
 
541
 
 
542
void Player::setFrame() {
 
543
        if (_moving) {
 
544
                if (++_frameNumber > _frameCount)
 
545
                        _frameNumber = 1;
 
546
                _forceRefresh = true;
 
547
        } else {
 
548
                if (!_forceRefresh)
 
549
                        idle();
 
550
        }
 
551
}
 
552
 
 
553
int Player::getSpriteSlot() {
 
554
        SpriteSlots &spriteSlots = _vm->_game->_scene._spriteSlots;
 
555
 
 
556
        for (uint idx = 0; idx < spriteSlots.size(); ++idx) {
 
557
                if (spriteSlots[idx]._seqIndex == PLAYER_SEQ_INDEX &&
 
558
                                spriteSlots[idx]._flags >= IMG_STATIC)
 
559
                        return idx;
 
560
        }
 
561
 
 
562
        return - 1;
 
563
}
 
564
 
 
565
int Player::getScale(int yp) {
 
566
        Scene &scene = _vm->_game->_scene;
 
567
 
 
568
        int scale = (scene._bandsRange == 0) ? scene._sceneInfo->_maxScale :
 
569
                (yp - scene._sceneInfo->_yBandsStart) * scene._scaleRange / scene._bandsRange +
 
570
                scene._sceneInfo->_minScale;
 
571
 
 
572
        return MIN(scale, 100);
 
573
}
 
574
 
 
575
void Player::setBaseFrameRate() {
 
576
        Scene &scene = _vm->_game->_scene;
 
577
 
 
578
        SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
 
579
        assert(spriteSet._charInfo);
 
580
 
 
581
        _ticksAmount = spriteSet._charInfo->_ticksAmount;
 
582
        if (_ticksAmount == 0)
 
583
                _ticksAmount = 6;
 
584
}
 
585
 
 
586
void Player::startMovement() {
 
587
        int xDiff = _targetPos.x - _playerPos.x;
 
588
        int yDiff = _targetPos.y - _playerPos.y;
 
589
        int srcScale = getScale(_playerPos.y);
 
590
        int destScale = getScale(_targetPos.y);
 
591
 
 
592
        // Sets the X direction
 
593
        if (xDiff > 0)
 
594
                _xDirection = 1;
 
595
        else if (xDiff < 0)
 
596
                _xDirection = -1;
 
597
        else
 
598
                _xDirection = 0;
 
599
 
 
600
        // Sets the Y direction
 
601
        if (yDiff > 0)
 
602
                _yDirection = 1;
 
603
        else if (yDiff < 0)
 
604
                _yDirection = -1;
 
605
        else
 
606
                _yDirection = 0;
 
607
 
 
608
        xDiff = ABS(xDiff);
 
609
        yDiff = ABS(yDiff);
 
610
        int scaleDiff = ABS(srcScale - destScale);
 
611
 
 
612
        int xAmt100 = xDiff * 100;
 
613
        int yAmt100 = yDiff * 100;
 
614
        int xAmt33 = xDiff * 33;
 
615
 
 
616
        int scaleAmount = (_scalingVelocity ? scaleDiff * 3 : 0) + 100 * yDiff / 100;
 
617
        int scaleAmount100 = scaleAmount * 100;
 
618
 
 
619
        // Figure out direction that will need to be moved in
 
620
        int majorDir;
 
621
        if (xDiff == 0) {
 
622
                majorDir = 1;
 
623
        } else if (yDiff == 0) {
 
624
                majorDir = 3;
 
625
        } else {
 
626
                if ((scaleAmount < xDiff) && ((xAmt33 / scaleAmount) >= 141))
 
627
                        majorDir = 3;
 
628
                else if (yDiff <= xDiff)
 
629
                        majorDir = 2;
 
630
                else if ((scaleAmount100 / xDiff) >= 141)
 
631
                        majorDir = 1;
 
632
                else
 
633
                        majorDir = 2;
 
634
        }
 
635
 
 
636
        switch (majorDir) {
 
637
        case 1:
 
638
                _turnToFacing = (_yDirection <= 0) ? FACING_NORTH : FACING_SOUTH;
 
639
                break;
 
640
        case 2: {
 
641
                _turnToFacing = (Facing)(((_yDirection <= 0) ? 9 : 3) - ((_xDirection <= 0) ? 2 : 0));
 
642
                break;
 
643
        }
 
644
        case 3:
 
645
                _turnToFacing = (_xDirection <= 0) ? FACING_WEST : FACING_EAST;
 
646
                break;
 
647
        default:
 
648
                break;
 
649
        }
 
650
 
 
651
        _totalDistance = (int)sqrt((double)(xAmt100 * xAmt100 + yAmt100 * yAmt100));
 
652
        _posDiff.x = xDiff + 1;
 
653
        _posDiff.y = yDiff + 1;
 
654
        _posChange.x = xDiff;
 
655
        _posChange.y = yDiff;
 
656
 
 
657
        int majorChange = MAX(xDiff, yDiff);
 
658
        _deltaDistance = (majorChange == 0) ? 0 : _totalDistance / majorChange;
 
659
 
 
660
        if (_playerPos.x > _targetPos.x)
 
661
                _pixelAccum = MAX(_posChange.x, _posChange.y);
 
662
        else
 
663
                _pixelAccum = 0;
 
664
 
 
665
        _totalDistance /= 100;
 
666
        _distAccum = -_deltaDistance;
 
667
}
 
668
 
 
669
void Player::newWalk() {
 
670
        if (_needToWalk && _readyToWalk) {
 
671
                startWalking(_prepareWalkPos, _prepareWalkFacing);
 
672
                _needToWalk = false;
 
673
        }
 
674
}
 
675
 
 
676
void Player::addWalker(int walker, int trigger) {
 
677
        Scene &scene = _vm->_game->_scene;
 
678
        SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
 
679
        assert(spriteSet._charInfo);
 
680
 
 
681
        if (walker < spriteSet._charInfo->_numEntries && _stopWalkerIndex < 11) {
 
682
                ++_stopWalkerIndex;
 
683
                _stopWalkerList[_stopWalkerIndex] = walker;
 
684
                _stopWalkerTrigger[_stopWalkerIndex] = trigger;
 
685
        }
 
686
}
 
687
 
 
688
 
 
689
/**
 
690
* Releases any sprites used by the player
 
691
*/
 
692
void Player::releasePlayerSprites() {
 
693
        Scene &scene = _vm->_game->_scene;
 
694
 
 
695
        if (_spritesLoaded && _numSprites > 0) {
 
696
                int spriteEnd = _spritesStart + _numSprites - 1;
 
697
                do {
 
698
                        scene._sprites.remove(spriteEnd);
 
699
                } while (--spriteEnd >= _spritesStart);
 
700
        }
 
701
 
 
702
        _numSprites = 0;
 
703
        _spritesLoaded = false;
 
704
        _spritesChanged = true;
 
705
 
 
706
        if (scene._sprites._assetCount > 0) {
 
707
                warning("Player::releasePlayerSprites(): leftover sprites remain, clearing list");
 
708
                scene._sprites.clear();
 
709
        }
 
710
}
 
711
 
 
712
void Player::synchronize(Common::Serializer &s) {
 
713
        s.syncAsByte(_moving);
 
714
        s.syncAsSint16LE(_playerPos.x);
 
715
        s.syncAsSint16LE(_playerPos.y);
 
716
        s.syncAsSint16LE(_targetPos.x);
 
717
        s.syncAsSint16LE(_targetPos.y);
 
718
        s.syncAsSint16LE(_xDirection);
 
719
        s.syncAsSint16LE(_yDirection);
 
720
        s.syncAsSint16LE(_posDiff.x);
 
721
        s.syncAsSint16LE(_posDiff.y);
 
722
        s.syncAsSint16LE(_posChange.x);
 
723
        s.syncAsSint16LE(_posChange.y);
 
724
        s.syncAsUint16LE(_targetFacing);
 
725
        s.syncAsSint16LE(_special);
 
726
        s.syncAsByte(_forceRefresh);
 
727
        s.syncAsSint16LE(_ticksAmount);
 
728
        s.syncAsByte(_walkAnywhere);
 
729
        s.syncAsUint16LE(_walkOffScreenSceneId);
 
730
        s.syncAsByte(_walkOffScreen);
 
731
        s.syncAsByte(_needToWalk);
 
732
        s.syncAsByte(_readyToWalk);
 
733
        s.syncAsUint16LE(_prepareWalkFacing);
 
734
        s.syncAsSint16LE(_prepareWalkPos.x);
 
735
        s.syncAsSint16LE(_prepareWalkPos.y);
 
736
        s.syncAsByte(_stepEnabled);
 
737
        s.syncAsByte(_visible);
 
738
        s.syncAsByte(_priorVisible);
 
739
 
 
740
        for (int i = 0; i < 8; ++i)
 
741
                s.syncAsByte(_spriteSetsPresent[i]);
 
742
 
 
743
        s.syncAsByte(_facing);
 
744
        s.syncAsByte(_turnToFacing);
 
745
        s.syncAsSint16LE(_spritesIdx);
 
746
        s.syncAsSint16LE(_frameNumber);
 
747
        s.syncAsSint16LE(_currentDepth);
 
748
        s.syncAsSint16LE(_currentScale);
 
749
        s.syncAsSint16LE(_frameListIndex);
 
750
 
 
751
        for (int i = 0; i < 12; ++i) {
 
752
                s.syncAsSint16LE(_stopWalkerList[i]);
 
753
                s.syncAsSint16LE(_stopWalkerTrigger[i]);
 
754
        }
 
755
 
 
756
        s.syncAsSint16LE(_stopWalkerIndex);
 
757
        s.syncAsSint16LE(_upcomingTrigger);
 
758
        s.syncAsSint16LE(_trigger);
 
759
        s.syncAsSint16LE(_scalingVelocity);
 
760
        s.syncAsSint16LE(_pixelAccum);
 
761
        s.syncAsSint16LE(_distAccum);
 
762
        s.syncAsSint16LE(_deltaDistance);
 
763
        s.syncAsSint16LE(_totalDistance);
 
764
        s.syncAsSint16LE(_velocity);
 
765
        s.syncAsUint16LE(_frameCount);
 
766
        s.syncString(_spritesPrefix);
 
767
        s.syncAsUint32LE(_priorTimer);
 
768
        s.syncAsByte(_loadsFirst);
 
769
        s.syncAsByte(_loadedFirst);
 
770
        s.syncAsByte(_spritesLoaded);
 
771
        s.syncAsByte(_spritesChanged);
 
772
        s.syncAsByte(_beenVisible);
 
773
        s.syncAsSint16LE(_centerOfGravity);
 
774
        s.syncAsByte(_mirror);
 
775
}
 
776
 
 
777
void Player::removePlayerSprites() {
 
778
        Scene &scene = _vm->_game->_scene;
 
779
        int heroSpriteId = _spritesStart;
 
780
        for (int i = 0; i < 8; i++) {
 
781
                if (_spriteSetsPresent[i]) {
 
782
                        scene._sprites.remove(heroSpriteId++);
 
783
                        _spriteSetsPresent[i] = false;
 
784
                }
 
785
        }
 
786
 
 
787
        if (scene._activeAnimation != nullptr)
 
788
                scene._activeAnimation->resetSpriteSetsCount();
 
789
 
 
790
        scene._spriteSlots.fullRefresh();
 
791
        _visible = false;
 
792
}
 
793
 
 
794
} // End of namespace MADS