2014-03-02 20:06:21 -05:00
|
|
|
/* 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 2
|
|
|
|
* 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "common/scummsys.h"
|
|
|
|
#include "mads/mads.h"
|
|
|
|
#include "mads/player.h"
|
|
|
|
|
|
|
|
namespace MADS {
|
|
|
|
|
2014-03-16 14:53:10 -04:00
|
|
|
#define PLAYER_SEQ_INDEX -2
|
|
|
|
|
|
|
|
const int Player::_directionListIndexes[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
|
|
|
|
};
|
|
|
|
|
2014-03-02 20:06:21 -05:00
|
|
|
Player::Player(MADSEngine *vm): _vm(vm) {
|
|
|
|
_action = nullptr;
|
2014-03-26 09:32:33 -04:00
|
|
|
_facing = FACING_NORTH;
|
|
|
|
_turnToFacing = FACING_NORTH;
|
2014-03-25 22:07:33 -04:00
|
|
|
_targetFacing = FACING_NORTH;
|
2014-03-28 23:07:22 -04:00
|
|
|
_prepareWalkFacing = FACING_NONE;
|
2014-03-28 09:19:55 -04:00
|
|
|
_mirror = false;
|
2014-03-02 20:06:21 -05:00
|
|
|
_spritesLoaded = false;
|
2014-03-16 14:53:10 -04:00
|
|
|
_spritesStart = 0;
|
|
|
|
_spritesIdx = 0;
|
|
|
|
_numSprites = 0;
|
2014-03-02 20:06:21 -05:00
|
|
|
_stepEnabled = false;
|
|
|
|
_visible = false;
|
2014-03-16 14:53:10 -04:00
|
|
|
_priorVisible = false;
|
2014-03-28 23:07:22 -04:00
|
|
|
_needToWalk = false;
|
|
|
|
_readyToWalk = false;
|
2014-03-02 20:50:35 -05:00
|
|
|
_visible3 = false;
|
2014-03-27 21:04:27 -04:00
|
|
|
_loadsFirst = false;
|
2014-03-27 22:38:28 -04:00
|
|
|
_loadedFirst = false;
|
2014-03-27 21:04:27 -04:00
|
|
|
_walkAnywhere = false;
|
2014-03-02 20:50:35 -05:00
|
|
|
_special = 0;
|
|
|
|
_ticksAmount = 0;
|
|
|
|
_priorTimer = 0;
|
2014-03-28 22:02:35 -04:00
|
|
|
_trigger = 0;
|
|
|
|
_scalingVelocity = false;
|
2014-03-28 09:19:55 -04:00
|
|
|
_spritesChanged = false;
|
2014-03-04 20:06:48 -05:00
|
|
|
_forceRefresh = false;
|
2014-03-16 14:53:10 -04:00
|
|
|
_highSprites = false;
|
|
|
|
_currentDepth = 0;
|
|
|
|
_currentScale = 0;
|
2014-03-28 09:19:55 -04:00
|
|
|
_frameNumber = 0;
|
|
|
|
_centerOfGravity = 0;
|
2014-03-16 14:53:10 -04:00
|
|
|
_frameCount = 0;
|
2014-03-28 09:19:55 -04:00
|
|
|
_velocity = 0;
|
|
|
|
_upcomingTrigger = 0;
|
|
|
|
_trigger = 0;
|
2014-03-16 14:53:10 -04:00
|
|
|
_frameListIndex = 0;
|
2014-03-28 09:19:55 -04:00
|
|
|
_stopWalkerIndex = 0;
|
2014-03-28 22:02:35 -04:00
|
|
|
_totalDistance = 0;
|
2014-03-16 14:53:10 -04:00
|
|
|
|
2014-03-28 09:19:55 -04:00
|
|
|
Common::fill(&_stopWalkerList[0], &_stopWalkerList[12], 0);
|
|
|
|
Common::fill(&_stopWalkerTrigger[0], &_stopWalkerTrigger[12], 0);
|
2014-03-16 14:53:10 -04:00
|
|
|
Common::fill(&_spriteSetsPresent[0], &_spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT], false);
|
2014-03-02 20:06:21 -05:00
|
|
|
}
|
|
|
|
|
2014-03-27 22:38:28 -04:00
|
|
|
void Player::cancelWalk() {
|
2014-03-02 20:06:21 -05:00
|
|
|
_action = &_vm->_game->_scene._action;
|
2014-03-28 22:02:35 -04:00
|
|
|
_targetPos = _playerPos;
|
2014-03-25 22:07:33 -04:00
|
|
|
_targetFacing = FACING_NONE;
|
2014-03-26 09:32:33 -04:00
|
|
|
_turnToFacing = _facing;
|
2014-03-02 20:06:21 -05:00
|
|
|
_moving = false;
|
2014-03-28 22:02:35 -04:00
|
|
|
_walkOffScreen = _walkOffScreenSceneId = 0;
|
2014-03-02 20:06:21 -05:00
|
|
|
_next = 0;
|
|
|
|
_routeCount = 0;
|
2014-03-27 21:04:27 -04:00
|
|
|
_walkAnywhere = false;
|
2014-03-02 20:06:21 -05:00
|
|
|
|
2014-03-28 23:07:22 -04:00
|
|
|
_needToWalk = false;
|
|
|
|
_readyToWalk = false;
|
2014-03-02 20:06:21 -05:00
|
|
|
}
|
|
|
|
|
2014-03-16 14:53:10 -04:00
|
|
|
bool Player::loadSprites(const Common::String &prefix) {
|
|
|
|
Common::String suffixList = "89632741";
|
|
|
|
|
|
|
|
Common::String newPrefix;
|
|
|
|
if (prefix.empty()) {
|
|
|
|
newPrefix = _spritesPrefix;
|
|
|
|
} else {
|
|
|
|
_spritesPrefix = prefix;
|
|
|
|
newPrefix = prefix;
|
|
|
|
}
|
|
|
|
|
|
|
|
_numSprites = 0;
|
|
|
|
if (!_spritesPrefix.empty()) {
|
|
|
|
for (int fileIndex = 0; fileIndex < PLAYER_SPRITES_FILE_COUNT; ++fileIndex) {
|
|
|
|
Common::String setName = Common::String::format("*%s_%c.SS",
|
|
|
|
newPrefix.c_str(), suffixList[fileIndex]);
|
|
|
|
if (fileIndex >= 5)
|
|
|
|
_highSprites = true;
|
|
|
|
|
|
|
|
_spriteSetsPresent[fileIndex] = true;
|
2014-03-16 15:50:17 -04:00
|
|
|
|
|
|
|
int setIndex = -1;
|
|
|
|
if (Common::File::exists(setName)) {
|
|
|
|
setIndex = _vm->_game->_scene._sprites.addSprites(setName, 4);
|
2014-03-16 14:53:10 -04:00
|
|
|
++_numSprites;
|
2014-03-16 15:50:17 -04:00
|
|
|
} else if (fileIndex < 5) {
|
2014-03-16 14:53:10 -04:00
|
|
|
_highSprites = 0;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
_spriteSetsPresent[fileIndex] = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fileIndex == 0)
|
|
|
|
_spritesStart = setIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
_spritesLoaded = true;
|
|
|
|
_spritesChanged = false;
|
|
|
|
_highSprites = false;
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
Common::fill(&_spriteSetsPresent[0], &_spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT], false);
|
|
|
|
_highSprites = false;
|
|
|
|
return true;
|
|
|
|
}
|
2014-03-02 20:06:21 -05:00
|
|
|
}
|
|
|
|
|
2014-03-27 22:38:28 -04:00
|
|
|
void Player::setFinalFacing() {
|
|
|
|
if (_targetFacing != FACING_NONE)
|
2014-03-26 09:32:33 -04:00
|
|
|
_turnToFacing = _targetFacing;
|
2014-03-02 20:06:21 -05:00
|
|
|
}
|
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
void Player::changeFacing() {
|
2014-03-16 14:53:10 -04:00
|
|
|
int dirIndex = 0, dirIndex2 = 0;
|
|
|
|
int newDir = 0, newDir2 = 0;
|
|
|
|
|
2014-03-26 09:32:33 -04:00
|
|
|
if (_facing != _turnToFacing) {
|
2014-03-16 14:53:10 -04:00
|
|
|
// Find the index for the given direction in the player direction list
|
2014-03-26 09:32:33 -04:00
|
|
|
int tempDir = _facing;
|
2014-03-16 14:53:10 -04:00
|
|
|
do {
|
|
|
|
++dirIndex;
|
|
|
|
newDir += tempDir;
|
|
|
|
tempDir = _directionListIndexes[tempDir + 10];
|
2014-03-26 09:32:33 -04:00
|
|
|
} while (tempDir != _turnToFacing);
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-26 09:32:33 -04:00
|
|
|
if (_facing != _turnToFacing) {
|
2014-03-16 14:53:10 -04:00
|
|
|
// Find the index for the given direction in the player direction list
|
2014-03-26 09:32:33 -04:00
|
|
|
int tempDir = _facing;
|
2014-03-16 14:53:10 -04:00
|
|
|
do {
|
|
|
|
++dirIndex2;
|
|
|
|
newDir2 += tempDir;
|
|
|
|
tempDir = _directionListIndexes[tempDir + 20];
|
2014-03-26 09:32:33 -04:00
|
|
|
} while (tempDir != _turnToFacing);
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int diff = dirIndex - dirIndex2;
|
|
|
|
if (diff == 0)
|
|
|
|
diff = newDir - newDir2;
|
|
|
|
|
2014-03-26 09:32:33 -04:00
|
|
|
_facing = (diff >= 0) ? (Facing)_directionListIndexes[_facing + 20] :
|
|
|
|
(Facing)_directionListIndexes[_facing + 10];
|
2014-03-28 09:19:55 -04:00
|
|
|
selectSeries();
|
|
|
|
|
2014-03-26 09:32:33 -04:00
|
|
|
if ((_facing == _turnToFacing) && !_moving)
|
2014-03-16 14:53:10 -04:00
|
|
|
updateFrame();
|
|
|
|
|
|
|
|
_priorTimer += 1;
|
|
|
|
}
|
|
|
|
|
2014-03-27 22:38:28 -04:00
|
|
|
void Player::cancelCommand() {
|
|
|
|
cancelWalk();
|
2014-03-02 20:06:21 -05:00
|
|
|
_action->_inProgress = false;
|
|
|
|
}
|
|
|
|
|
2014-03-28 09:19:55 -04:00
|
|
|
void Player::selectSeries() {
|
2014-03-16 14:53:10 -04:00
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
|
2014-03-28 09:19:55 -04:00
|
|
|
clearStopList();
|
|
|
|
_mirror = false;
|
|
|
|
|
2014-03-26 09:32:33 -04:00
|
|
|
_spritesIdx = _directionListIndexes[_facing];
|
2014-03-16 14:53:10 -04:00
|
|
|
if (!_spriteSetsPresent[_spritesIdx]) {
|
|
|
|
// Direction isn't present, so use alternate direction, with entries flipped
|
|
|
|
_spritesIdx -= 4;
|
2014-03-28 09:19:55 -04:00
|
|
|
_mirror = true;
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
|
|
|
|
assert(spriteSet._charInfo);
|
2014-03-28 09:19:55 -04:00
|
|
|
_velocity = MAX(spriteSet._charInfo->_velocity, 100);
|
|
|
|
setBaseFrameRate();
|
2014-03-16 14:53:10 -04:00
|
|
|
|
|
|
|
_frameCount = spriteSet._charInfo->_totalFrames;
|
|
|
|
if (_frameCount == 0)
|
|
|
|
_frameCount = spriteSet.getCount();
|
|
|
|
|
2014-03-28 09:19:55 -04:00
|
|
|
_centerOfGravity = spriteSet._charInfo->_centerOfGravity;
|
|
|
|
|
|
|
|
if ((_frameNumber <= 0) || (_frameNumber > _frameCount))
|
|
|
|
_frameNumber = 1;
|
2014-03-16 14:53:10 -04:00
|
|
|
|
|
|
|
_forceRefresh = true;
|
2014-03-02 20:50:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Player::updateFrame() {
|
2014-03-16 14:53:10 -04:00
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
|
|
|
|
assert(spriteSet._charInfo);
|
|
|
|
|
|
|
|
if (!spriteSet._charInfo->_numEntries) {
|
2014-03-28 09:19:55 -04:00
|
|
|
_frameNumber = 1;
|
2014-03-16 14:53:10 -04:00
|
|
|
} else {
|
2014-03-28 09:19:55 -04:00
|
|
|
_frameListIndex = _stopWalkerList[_stopWalkerIndex];
|
2014-03-16 14:53:10 -04:00
|
|
|
|
|
|
|
if (!_visible) {
|
2014-03-28 09:19:55 -04:00
|
|
|
_upcomingTrigger = 0;
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
else {
|
2014-03-28 09:19:55 -04:00
|
|
|
_upcomingTrigger = _stopWalkerTrigger[_stopWalkerIndex];
|
2014-03-16 14:53:10 -04:00
|
|
|
|
2014-03-28 09:19:55 -04:00
|
|
|
if (_stopWalkerIndex > 0)
|
|
|
|
--_stopWalkerIndex;
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set the player frame number
|
2014-03-28 20:23:25 -04:00
|
|
|
int listIndex = ABS(_frameListIndex);
|
|
|
|
_frameNumber = (_frameListIndex >= 0) ? spriteSet._charInfo->_startFrames[listIndex] :
|
|
|
|
spriteSet._charInfo->_stopFrames[listIndex];
|
2014-03-16 14:53:10 -04:00
|
|
|
|
|
|
|
// Set next waiting period in ticks
|
2014-03-28 20:23:25 -04:00
|
|
|
if (listIndex == 0) {
|
2014-03-28 09:19:55 -04:00
|
|
|
setBaseFrameRate();
|
2014-03-16 14:53:10 -04:00
|
|
|
} else {
|
2014-03-28 20:23:25 -04:00
|
|
|
_ticksAmount = spriteSet._charInfo->_ticksList[listIndex];
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
}
|
2014-03-28 09:19:55 -04:00
|
|
|
|
|
|
|
_forceRefresh = true;
|
2014-03-02 20:50:35 -05:00
|
|
|
}
|
|
|
|
|
2014-03-04 20:06:48 -05:00
|
|
|
void Player::update() {
|
2014-03-16 14:53:10 -04:00
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
|
|
|
|
if (_forceRefresh || (_visible != _priorVisible)) {
|
|
|
|
int slotIndex = getSpriteSlot();
|
|
|
|
if (slotIndex >= 0)
|
2014-03-17 21:53:22 -04:00
|
|
|
scene._spriteSlots[slotIndex]._SlotType = ST_EXPIRED;
|
2014-03-16 14:53:10 -04:00
|
|
|
|
|
|
|
int newDepth = 1;
|
|
|
|
int yp = MAX(_playerPos.y, (int16)(MADS_SCENE_HEIGHT - 1));
|
|
|
|
|
|
|
|
for (int idx = 1; idx < 15; ++idx) {
|
|
|
|
if (scene._sceneInfo->_depthList[newDepth] >= yp)
|
|
|
|
newDepth = idx + 1;
|
|
|
|
}
|
|
|
|
_currentDepth = newDepth;
|
|
|
|
|
|
|
|
// Get the scale
|
|
|
|
int newScale = getScale(_playerPos.y);
|
|
|
|
_currentScale = MIN(newScale, 100);
|
|
|
|
|
|
|
|
if (_visible) {
|
|
|
|
// Player sprite needs to be rendered
|
|
|
|
SpriteSlot slot;
|
2014-03-17 21:53:22 -04:00
|
|
|
slot._SlotType = ST_FOREGROUND;
|
2014-03-16 14:53:10 -04:00
|
|
|
slot._seqIndex = PLAYER_SEQ_INDEX;
|
|
|
|
slot._spritesIndex = _spritesStart + _spritesIdx;
|
2014-03-28 09:19:55 -04:00
|
|
|
slot._frameNumber = _mirror ? -_frameNumber : _frameNumber;
|
2014-03-16 14:53:10 -04:00
|
|
|
slot._position.x = _playerPos.x;
|
2014-03-28 09:19:55 -04:00
|
|
|
slot._position.y = _playerPos.y + (_centerOfGravity * newScale) / 100;
|
2014-03-16 14:53:10 -04:00
|
|
|
slot._depth = newDepth;
|
|
|
|
slot._scale = newScale;
|
|
|
|
|
|
|
|
if (slotIndex >= 0) {
|
|
|
|
// Check if the existing player slot has the same details, and can be re-used
|
|
|
|
SpriteSlot &s2 = scene._spriteSlots[slotIndex];
|
|
|
|
bool equal = (s2._seqIndex == slot._seqIndex)
|
|
|
|
&& (s2._spritesIndex == slot._spritesIndex)
|
|
|
|
&& (s2._frameNumber == slot._frameNumber)
|
|
|
|
&& (s2._position == slot._position)
|
|
|
|
&& (s2._depth == slot._depth)
|
|
|
|
&& (s2._scale == slot._scale);
|
|
|
|
|
|
|
|
if (equal)
|
|
|
|
// Undo the prior expiry of the player sprite
|
2014-03-17 21:53:22 -04:00
|
|
|
s2._SlotType = ST_NONE;
|
2014-03-16 14:53:10 -04:00
|
|
|
else
|
|
|
|
slotIndex = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (slotIndex < 0) {
|
|
|
|
// New slot needed, so allocate one and copy the slot data
|
|
|
|
slotIndex = scene._spriteSlots.add();
|
|
|
|
scene._spriteSlots[slotIndex] = slot;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If changing a scene, check to change the scene when the player
|
|
|
|
// has moved off-screen
|
2014-03-28 22:02:35 -04:00
|
|
|
if (_walkOffScreen) {
|
2014-03-16 14:53:10 -04:00
|
|
|
SpriteAsset *asset = scene._sprites[slot._spritesIndex];
|
2014-03-28 09:19:55 -04:00
|
|
|
MSprite *frame = asset->getFrame(_frameNumber - 1);
|
2014-03-16 14:53:10 -04:00
|
|
|
int xScale = frame->w * newScale / 200;
|
|
|
|
int yScale = frame->h * newScale / 100;
|
|
|
|
int playerX = slot._position.x;
|
|
|
|
int playerY = slot._position.y;
|
|
|
|
|
|
|
|
if ((playerX + xScale) < 0 || (playerX + xScale) >= MADS_SCREEN_WIDTH ||
|
|
|
|
playerY < 0 || (playerY + yScale) >= MADS_SCENE_HEIGHT) {
|
2014-03-28 22:02:35 -04:00
|
|
|
scene._nextSceneId = _walkOffScreen;
|
|
|
|
_walkOffScreen = 0;
|
2014-03-27 21:04:27 -04:00
|
|
|
_walkAnywhere = false;
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_visible3 = _visible;
|
|
|
|
_priorVisible = _visible;
|
|
|
|
_forceRefresh = false;
|
2014-03-04 20:06:48 -05:00
|
|
|
}
|
|
|
|
|
2014-03-28 09:19:55 -04:00
|
|
|
void Player::clearStopList() {
|
|
|
|
_stopWalkerList[0] = 0;
|
|
|
|
_stopWalkerTrigger[0] = 0;
|
|
|
|
_stopWalkerIndex = 0;
|
|
|
|
_upcomingTrigger = 0;
|
|
|
|
_trigger = 0;
|
2014-03-02 20:50:35 -05:00
|
|
|
}
|
|
|
|
|
2014-03-28 23:07:22 -04:00
|
|
|
void Player::startWalking(const Common::Point &pt, Facing facing) {
|
2014-03-16 14:53:10 -04:00
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
|
2014-03-28 09:19:55 -04:00
|
|
|
clearStopList();
|
|
|
|
setBaseFrameRate();
|
2014-03-16 14:53:10 -04:00
|
|
|
_moving = true;
|
2014-03-25 22:07:33 -04:00
|
|
|
_targetFacing = facing;
|
2014-03-16 14:53:10 -04:00
|
|
|
|
|
|
|
scene._sceneInfo->setRouteNode(scene._sceneInfo->_nodes.size() - 2,
|
|
|
|
_playerPos, scene._depthSurface);
|
|
|
|
scene._sceneInfo->setRouteNode(scene._sceneInfo->_nodes.size() - 1,
|
|
|
|
pt, scene._depthSurface);
|
|
|
|
|
|
|
|
bool v = scene._depthSurface.getDepthHighBit(pt);
|
|
|
|
setupRoute(v);
|
|
|
|
_next = 0;
|
|
|
|
|
|
|
|
if (_routeCount > 0) {
|
|
|
|
Common::Point srcPos = _playerPos;
|
|
|
|
for (int routeCtr = _routeCount - 1; (routeCtr >= 0) && (_next == 0); --routeCtr) {
|
|
|
|
int idx = _routeIndexes[routeCtr];
|
|
|
|
const Common::Point &pt =scene._sceneInfo->_nodes[idx]._walkPos;
|
|
|
|
|
|
|
|
_next = scanPath(scene._depthSurface, srcPos, pt);
|
|
|
|
srcPos = pt;
|
|
|
|
}
|
|
|
|
}
|
2014-03-03 00:42:41 -05:00
|
|
|
}
|
|
|
|
|
2014-03-28 23:07:22 -04:00
|
|
|
void Player::walk(const Common::Point &pos, Facing facing) {
|
2014-03-17 21:53:22 -04:00
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
|
2014-03-27 22:38:28 -04:00
|
|
|
cancelWalk();
|
2014-03-28 23:07:22 -04:00
|
|
|
_needToWalk = true;
|
|
|
|
_readyToWalk = true;
|
|
|
|
_prepareWalkPos = pos;
|
|
|
|
_prepareWalkFacing = facing;
|
2014-03-17 21:53:22 -04:00
|
|
|
}
|
|
|
|
|
2014-03-03 00:42:41 -05:00
|
|
|
void Player::nextFrame() {
|
2014-03-08 14:05:17 -05:00
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
|
2014-03-16 16:50:53 -04:00
|
|
|
uint32 newTime = _priorTimer + _ticksAmount;
|
|
|
|
if (scene._frameStartTime >= newTime) {
|
2014-03-08 14:05:17 -05:00
|
|
|
_priorTimer = scene._frameStartTime;
|
2014-03-03 00:42:41 -05:00
|
|
|
if (_moving) {
|
|
|
|
move();
|
|
|
|
} else {
|
|
|
|
idle();
|
|
|
|
}
|
|
|
|
|
2014-03-28 23:07:22 -04:00
|
|
|
setFrame();
|
2014-03-03 00:42:41 -05:00
|
|
|
update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::move() {
|
2014-03-16 14:53:10 -04:00
|
|
|
Scene &scene = _vm->_game->_scene;
|
2014-03-28 22:02:35 -04:00
|
|
|
bool newFacing = false;
|
2014-03-16 14:53:10 -04:00
|
|
|
|
|
|
|
if (_moving) {
|
|
|
|
int idx = _routeCount;
|
2014-03-28 22:02:35 -04:00
|
|
|
while (!_walkOffScreen && _playerPos == _targetPos) {
|
2014-03-16 14:53:10 -04:00
|
|
|
if (idx != 0) {
|
|
|
|
--idx;
|
|
|
|
SceneNode &node = scene._sceneInfo->_nodes[_routeIndexes[idx]];
|
2014-03-28 22:02:35 -04:00
|
|
|
_targetPos = node._walkPos;
|
|
|
|
newFacing = true;
|
|
|
|
} else if (_walkOffScreenSceneId == idx) {
|
2014-03-16 14:53:10 -04:00
|
|
|
// End of walking path
|
|
|
|
_routeCount = 0;
|
|
|
|
_moving = false;
|
2014-03-27 22:38:28 -04:00
|
|
|
setFinalFacing();
|
2014-03-28 22:02:35 -04:00
|
|
|
newFacing = true;
|
2014-03-16 14:53:10 -04:00
|
|
|
idx = _routeCount;
|
2014-03-28 22:02:35 -04:00
|
|
|
} else {
|
|
|
|
_walkOffScreen = _walkOffScreenSceneId;
|
|
|
|
_walkAnywhere = true;
|
|
|
|
_walkOffScreenSceneId = 0;
|
2014-03-16 14:53:10 -04:00
|
|
|
_stepEnabled = true;
|
2014-03-28 22:02:35 -04:00
|
|
|
newFacing = false;
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!_moving)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
_routeCount = idx;
|
|
|
|
}
|
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
if (newFacing && _moving)
|
2014-03-16 14:53:10 -04:00
|
|
|
startMovement();
|
|
|
|
|
2014-03-26 09:32:33 -04:00
|
|
|
if (_turnToFacing != _facing)
|
2014-03-28 22:02:35 -04:00
|
|
|
changeFacing();
|
2014-03-16 14:53:10 -04:00
|
|
|
else if (!_moving)
|
|
|
|
updateFrame();
|
|
|
|
|
2014-03-28 09:19:55 -04:00
|
|
|
int velocity = _velocity;
|
2014-03-28 22:02:35 -04:00
|
|
|
if (_scalingVelocity && (_totalDistance > 0)) {
|
|
|
|
int angleRange = 100 - _currentScale;
|
|
|
|
int angleScale = angleRange * (_posDiff.x - 1) / _totalDistance + _currentScale;
|
|
|
|
velocity = MAX(1, 10000 / (angleScale * _currentScale * velocity));
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
|
2014-03-26 09:32:33 -04:00
|
|
|
if (!_moving || (_facing != _turnToFacing))
|
2014-03-16 14:53:10 -04:00
|
|
|
return;
|
|
|
|
|
|
|
|
Common::Point newPos = _playerPos;
|
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
if (_distAccum < velocity) {
|
2014-03-16 14:53:10 -04:00
|
|
|
do {
|
2014-03-28 22:02:35 -04:00
|
|
|
if (_pixelAccum < _posDiff.x)
|
|
|
|
_pixelAccum += _posDiff.y;
|
|
|
|
if (_pixelAccum >= _posDiff.x) {
|
|
|
|
if ((_posChange.y > 0) || (_walkOffScreen != 0))
|
2014-03-16 14:53:10 -04:00
|
|
|
newPos.y += _yDirection;
|
|
|
|
--_posChange.y;
|
2014-03-28 22:02:35 -04:00
|
|
|
_pixelAccum -= _posDiff.x;
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
if (_pixelAccum < _posDiff.x) {
|
|
|
|
if ((_posChange.x > 0) || (_walkOffScreen != 0))
|
2014-03-16 14:53:10 -04:00
|
|
|
newPos.x += _xDirection;
|
|
|
|
--_posChange.x;
|
|
|
|
}
|
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
if (!_walkAnywhere && !_walkOffScreen && (_walkOffScreenSceneId == 0)) {
|
|
|
|
newFacing = scene._depthSurface.getDepthHighBit(newPos);
|
2014-03-16 14:53:10 -04:00
|
|
|
|
|
|
|
if (_special == 0)
|
|
|
|
_special = scene.getDepthHighBits(newPos);
|
|
|
|
}
|
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
_distAccum += _deltaDistance;
|
2014-03-16 14:53:10 -04:00
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
} while ((_distAccum < velocity) && !newFacing && ((_posChange.x > 0) || (_posChange.y > 0) || (_walkOffScreen != 0)));
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
_distAccum -= velocity;
|
2014-03-16 14:53:10 -04:00
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
if (newFacing) {
|
2014-03-27 22:38:28 -04:00
|
|
|
cancelCommand();
|
2014-03-28 22:02:35 -04:00
|
|
|
} else {
|
|
|
|
if (!_walkOffScreen) {
|
2014-03-16 14:53:10 -04:00
|
|
|
// If the move is complete, make sure the position is exactly on the given destination
|
|
|
|
if (_posChange.x == 0)
|
2014-03-28 22:02:35 -04:00
|
|
|
newPos.x = _targetPos.x;
|
2014-03-16 14:53:10 -04:00
|
|
|
if (_posChange.y == 0)
|
2014-03-28 22:02:35 -04:00
|
|
|
newPos.y = _targetPos.y;
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
_playerPos = newPos;
|
|
|
|
}
|
2014-03-03 00:42:41 -05:00
|
|
|
}
|
|
|
|
|
2014-03-02 20:50:35 -05:00
|
|
|
void Player::idle() {
|
2014-03-16 14:53:10 -04:00
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
|
2014-03-26 09:32:33 -04:00
|
|
|
if (_facing != _turnToFacing) {
|
2014-03-16 14:53:10 -04:00
|
|
|
// The direction has changed, so reset for new direction
|
2014-03-28 22:02:35 -04:00
|
|
|
changeFacing();
|
2014-03-16 14:53:10 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
|
|
|
|
assert(spriteSet._charInfo);
|
|
|
|
if (spriteSet._charInfo->_numEntries == 0)
|
|
|
|
// No entries, so exit immediately
|
|
|
|
return;
|
|
|
|
|
|
|
|
int frameIndex = ABS(_frameListIndex);
|
|
|
|
int direction = (_frameListIndex < 0) ? -1 : 1;
|
|
|
|
|
2014-03-28 23:07:22 -04:00
|
|
|
if (frameIndex >= spriteSet._charInfo->_numEntries) {
|
2014-03-16 14:53:10 -04:00
|
|
|
// Reset back to the start of the list
|
|
|
|
_frameListIndex = 0;
|
2014-03-28 23:07:22 -04:00
|
|
|
} else {
|
2014-03-28 09:19:55 -04:00
|
|
|
_frameNumber += direction;
|
2014-03-16 14:53:10 -04:00
|
|
|
_forceRefresh = true;
|
|
|
|
|
2014-03-28 20:23:25 -04:00
|
|
|
if (spriteSet._charInfo->_stopFrames[frameIndex] < _frameNumber) {
|
2014-03-28 09:19:55 -04:00
|
|
|
_trigger = _upcomingTrigger;
|
2014-03-16 14:53:10 -04:00
|
|
|
updateFrame();
|
|
|
|
}
|
2014-03-28 20:23:25 -04:00
|
|
|
if (spriteSet._charInfo->_startFrames[frameIndex] < _frameNumber) {
|
2014-03-28 09:19:55 -04:00
|
|
|
_trigger = _upcomingTrigger;
|
2014-03-16 14:53:10 -04:00
|
|
|
updateFrame();
|
|
|
|
}
|
|
|
|
}
|
2014-03-02 20:50:35 -05:00
|
|
|
}
|
|
|
|
|
2014-03-28 23:07:22 -04:00
|
|
|
void Player::setFrame() {
|
2014-03-16 14:53:10 -04:00
|
|
|
if (_moving) {
|
2014-03-28 09:19:55 -04:00
|
|
|
if (++_frameNumber > _frameCount)
|
|
|
|
_frameNumber = 1;
|
2014-03-16 14:53:10 -04:00
|
|
|
_forceRefresh = true;
|
|
|
|
} else {
|
|
|
|
if (!_forceRefresh)
|
|
|
|
idle();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int Player::getSpriteSlot() {
|
|
|
|
SpriteSlots &spriteSlots = _vm->_game->_scene._spriteSlots;
|
|
|
|
|
|
|
|
for (uint idx = 0; idx < spriteSlots.size(); ++idx) {
|
|
|
|
if (spriteSlots[idx]._seqIndex == PLAYER_SEQ_INDEX &&
|
2014-03-17 21:53:22 -04:00
|
|
|
spriteSlots[idx]._SlotType >= ST_NONE)
|
2014-03-16 14:53:10 -04:00
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
return - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Player::getScale(int yp) {
|
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
|
|
|
|
int scale = (scene._bandsRange == 0) ? scene._sceneInfo->_maxScale :
|
|
|
|
(yp - scene._sceneInfo->_yBandsStart) * scene._scaleRange / scene._bandsRange +
|
|
|
|
scene._sceneInfo->_minScale;
|
|
|
|
|
|
|
|
return MIN(scale, 100);
|
|
|
|
}
|
|
|
|
|
2014-03-28 09:19:55 -04:00
|
|
|
void Player::setBaseFrameRate() {
|
2014-03-16 14:53:10 -04:00
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
|
|
|
|
SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
|
|
|
|
assert(spriteSet._charInfo);
|
|
|
|
|
|
|
|
_ticksAmount = spriteSet._charInfo->_ticksAmount;
|
|
|
|
if (_ticksAmount == 0)
|
|
|
|
_ticksAmount = 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::setupRoute(bool bitFlag) {
|
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
|
|
|
|
// Reset the flag set of nodes in use
|
|
|
|
SceneNodeList &nodes = scene._sceneInfo->_nodes;
|
|
|
|
for (uint i = 0; i < nodes.size(); ++i)
|
|
|
|
nodes[i]._active = false;
|
|
|
|
|
|
|
|
// Start constructing route node list
|
|
|
|
_routeLength = 0x3FFF;
|
|
|
|
_routeCount = 0;
|
|
|
|
|
|
|
|
setupRouteNode(_tempRoute, nodes.size() - 1, bitFlag ? 0xC000 : 0x8000, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::setupRouteNode(int *routeIndexP, int nodeIndex, int flags, int routeLength) {
|
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
SceneNodeList &nodes = scene._sceneInfo->_nodes;
|
|
|
|
SceneNode ¤tNode = nodes[nodeIndex];
|
|
|
|
currentNode._active = true;
|
|
|
|
|
|
|
|
*routeIndexP++ = nodeIndex;
|
|
|
|
|
|
|
|
int subIndex = nodes.size() - 2;
|
|
|
|
int indexVal = nodes[nodeIndex]._indexes[subIndex];
|
|
|
|
if (indexVal & flags) {
|
|
|
|
routeLength += indexVal & 0x3FFF;
|
|
|
|
if (routeLength < _routeLength) {
|
|
|
|
// Found a new shorter route to destination, so set up the route with the found one
|
|
|
|
Common::copy(_tempRoute, routeIndexP, _routeIndexes);
|
|
|
|
_routeCount = routeIndexP - _tempRoute;
|
|
|
|
_routeLength = indexVal & 0x3FFF;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int idx = nodes.size() - 2; idx > 0; --idx) {
|
|
|
|
int nodePos = idx - 1;
|
|
|
|
if (!nodes[nodePos]._active && ((currentNode._indexes[nodePos] & flags) != 0))
|
|
|
|
setupRouteNode(routeIndexP, nodePos, 0x8000, indexVal & 0x3fff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
currentNode._active = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Player::scanPath(MSurface &depthSurface, const Common::Point &srcPos, const Common::Point &destPos) {
|
|
|
|
Scene &scene = _vm->_game->_scene;
|
|
|
|
|
|
|
|
// For compressed depth surfaces, always return 0
|
|
|
|
if (scene._sceneInfo->_depthStyle != 2)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int yDiff = destPos.y - srcPos.y;
|
|
|
|
int yAmount = MADS_SCREEN_WIDTH;
|
|
|
|
|
|
|
|
if (yDiff < 0) {
|
|
|
|
yDiff = -yDiff;
|
|
|
|
yAmount = -yAmount;
|
|
|
|
}
|
|
|
|
|
|
|
|
int xDiff = destPos.x - srcPos.y;
|
|
|
|
int xDirection = 1;
|
|
|
|
int xAmount = 0;
|
|
|
|
if (xDiff < 0) {
|
|
|
|
xDiff = -xDiff;
|
|
|
|
xDirection = -xDirection;
|
|
|
|
xAmount = MIN(yDiff, xDiff);
|
|
|
|
}
|
|
|
|
|
|
|
|
++xDiff;
|
|
|
|
++yDiff;
|
|
|
|
|
|
|
|
const byte *srcP = depthSurface.getBasePtr(srcPos.x, srcPos.y);
|
|
|
|
int index = xAmount;
|
|
|
|
|
|
|
|
// Outer horizontal movement loop
|
|
|
|
for (int yIndex = 0; yIndex < yDiff; ++yIndex) {
|
|
|
|
index += yDiff;
|
|
|
|
int v = (*srcP & 0x7F) >> 4;
|
|
|
|
if (v)
|
|
|
|
return v;
|
|
|
|
|
|
|
|
// Inner loop for handling vertical movement
|
|
|
|
while (index >= xDiff) {
|
|
|
|
index -= xDiff;
|
|
|
|
|
|
|
|
v = (*srcP & 0x7F) >> 4;
|
|
|
|
if (v)
|
|
|
|
return v;
|
|
|
|
|
|
|
|
srcP += yAmount;
|
|
|
|
}
|
|
|
|
|
|
|
|
srcP += xDirection;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Player::startMovement() {
|
2014-03-28 22:02:35 -04:00
|
|
|
int xDiff = _targetPos.x - _playerPos.x;
|
|
|
|
int yDiff = _targetPos.y - _playerPos.y;
|
2014-03-16 14:53:10 -04:00
|
|
|
int srcScale = getScale(_playerPos.y);
|
2014-03-28 22:02:35 -04:00
|
|
|
int destScale = getScale(_targetPos.y);
|
2014-03-16 14:53:10 -04:00
|
|
|
|
|
|
|
// Sets the X direction
|
|
|
|
if (xDiff > 0)
|
|
|
|
_xDirection = 1;
|
|
|
|
else if (xDiff < 0)
|
|
|
|
_xDirection = -1;
|
|
|
|
else
|
|
|
|
_xDirection = 0;
|
|
|
|
|
|
|
|
// Sets the Y direction
|
|
|
|
if (yDiff > 0)
|
|
|
|
_yDirection = 1;
|
|
|
|
else if (yDiff < 0)
|
|
|
|
_yDirection = -1;
|
|
|
|
else
|
|
|
|
_yDirection = 0;
|
|
|
|
|
|
|
|
xDiff = ABS(xDiff);
|
|
|
|
yDiff = ABS(yDiff);
|
|
|
|
int scaleDiff = ABS(srcScale - destScale);
|
|
|
|
|
|
|
|
int xAmt100 = xDiff * 100;
|
|
|
|
int yAmt100 = yDiff * 100;
|
|
|
|
int xAmt33 = xDiff * 33;
|
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
int scaleAmount = (_scalingVelocity ? scaleDiff * 3 : 0) + 100 * yDiff / 100;
|
2014-03-16 14:53:10 -04:00
|
|
|
int scaleAmount100 = scaleAmount * 100;
|
|
|
|
|
|
|
|
// Figure out direction that will need to be moved in
|
|
|
|
int majorDir;
|
|
|
|
if (xDiff == 0)
|
|
|
|
majorDir = 1;
|
|
|
|
else if (yDiff == 0)
|
|
|
|
majorDir = 3;
|
|
|
|
else {
|
|
|
|
if ((scaleAmount < xDiff) && ((xAmt33 / scaleAmount) >= 141))
|
|
|
|
majorDir = 3;
|
|
|
|
else if (yDiff <= xDiff)
|
|
|
|
majorDir = 2;
|
|
|
|
else if ((scaleAmount100 / xDiff) >= 141)
|
|
|
|
majorDir = 1;
|
|
|
|
else
|
|
|
|
majorDir = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (majorDir) {
|
|
|
|
case 1:
|
2014-03-26 09:32:33 -04:00
|
|
|
_turnToFacing = (_yDirection <= 0) ? FACING_NORTH : FACING_SOUTH;
|
2014-03-16 14:53:10 -04:00
|
|
|
break;
|
|
|
|
case 2: {
|
2014-03-26 09:32:33 -04:00
|
|
|
_turnToFacing = (Facing)(((_yDirection <= 0) ? 9 : 3) - ((_xDirection <= 0) ? 2 : 0));
|
2014-03-25 22:07:33 -04:00
|
|
|
break;
|
2014-03-16 14:53:10 -04:00
|
|
|
}
|
|
|
|
case 3:
|
2014-03-26 09:32:33 -04:00
|
|
|
_turnToFacing = (_xDirection <= 0) ? FACING_WEST : FACING_EAST;
|
2014-03-16 14:53:10 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
_totalDistance = sqrt((double)(xAmt100 * xAmt100 + yAmt100 * yAmt100));
|
2014-03-16 14:53:10 -04:00
|
|
|
_posDiff.x = xDiff + 1;
|
|
|
|
_posDiff.y = yDiff + 1;
|
|
|
|
_posChange.x = xDiff;
|
|
|
|
_posChange.y = yDiff;
|
|
|
|
|
|
|
|
int majorChange = MAX(xDiff, yDiff);
|
2014-03-28 22:02:35 -04:00
|
|
|
_deltaDistance = (majorChange == 0) ? 0 : _totalDistance / majorChange;
|
2014-03-16 14:53:10 -04:00
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
if (_playerPos.x > _targetPos.x)
|
|
|
|
_pixelAccum = MAX(_posChange.x, _posChange.y);
|
2014-03-16 14:53:10 -04:00
|
|
|
else
|
2014-03-28 22:02:35 -04:00
|
|
|
_pixelAccum = 0;
|
2014-03-16 14:53:10 -04:00
|
|
|
|
2014-03-28 22:02:35 -04:00
|
|
|
_totalDistance /= 100;
|
|
|
|
_distAccum = -_deltaDistance;
|
2014-03-03 00:42:41 -05:00
|
|
|
}
|
|
|
|
|
2014-03-28 23:07:22 -04:00
|
|
|
void Player::newWalk() {
|
|
|
|
if (_needToWalk && _readyToWalk) {
|
|
|
|
startWalking(_prepareWalkPos, _prepareWalkFacing);
|
|
|
|
_needToWalk = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-29 11:18:07 -04:00
|
|
|
void Player::addWalker(int walker, int trigger) {
|
|
|
|
warning("TODO: Player::addWalker");
|
2014-03-21 09:27:22 -04:00
|
|
|
}
|
|
|
|
|
2014-03-02 20:06:21 -05:00
|
|
|
} // End of namespace MADS
|