mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-22 01:39:57 +00:00
fd804eb44b
svn-id: r51461
793 lines
19 KiB
C++
793 lines
19 KiB
C++
/* 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.
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
#include "m4/m4.h"
|
|
#include "m4/mads_player.h"
|
|
#include "m4/mads_scene.h"
|
|
|
|
namespace M4 {
|
|
|
|
const int MadsPlayer::_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
|
|
};
|
|
|
|
MadsPlayer::MadsPlayer() {
|
|
_playerPos = Common::Point(160, 78);
|
|
_ticksAmount = 3;
|
|
_forceRefresh = true;
|
|
_stepEnabled = true;
|
|
_visible = true;
|
|
_yScale = 0;
|
|
_moving = false;
|
|
|
|
_spriteListStart = 0;
|
|
//TODO:unknown vars
|
|
_special = 0;
|
|
_next = 0;
|
|
_unk4 = false;
|
|
|
|
_spritesChanged = true;
|
|
|
|
_direction = 0;
|
|
_newDirection = 0;
|
|
_priorTimer = 0;
|
|
_priorVisible = false;
|
|
_visible3 = false;
|
|
_spriteListIdx = 0;
|
|
_currentScale = 0;
|
|
strcpy(_spritesPrefix, "");
|
|
for (int idx = 0; idx < 8; ++idx)
|
|
_spriteSetsPresent[idx] = false;
|
|
_frameNum = 0;
|
|
_frameOffset = 0;
|
|
_unk1 = 0;
|
|
_frameCount = 0;
|
|
_frameListIndex = 0;
|
|
_actionIndex = 0;
|
|
_routeCount = 0;
|
|
|
|
resetActionList();
|
|
}
|
|
|
|
/**
|
|
* Loads the sprite set for the player
|
|
*/
|
|
bool MadsPlayer::loadSprites(const char *prefix) {
|
|
const char suffixList[8] = { '8', '9', '6', '3', '2', '7', '4', '1' };
|
|
char setName[80];
|
|
bool result = true;
|
|
|
|
if (prefix)
|
|
strcpy(_spritesPrefix, prefix);
|
|
|
|
_spriteSetCount = 0;
|
|
int prefixLen = strlen(_spritesPrefix);
|
|
|
|
if (prefixLen == 0) {
|
|
// No player sprites at at all
|
|
for (int idx = 0; idx < 8; ++idx)
|
|
_spriteSetsPresent[idx] = false;
|
|
} else {
|
|
strcpy(setName, "*");
|
|
strcat(setName, _spritesPrefix);
|
|
strcat(setName, "_0.SS");
|
|
|
|
char *digitP = strchr(setName, '_') + 1;
|
|
|
|
for (int idx = 0; idx < 8; ++idx) {
|
|
*digitP = suffixList[idx];
|
|
_spriteSetsPresent[idx] = true;
|
|
|
|
int setIndex = _madsVm->scene()->_spriteSlots.addSprites(setName, true, SPRITE_SET_CHAR_INFO);
|
|
if (setIndex < 0) {
|
|
if (idx < 5)
|
|
break;
|
|
_spriteSetsPresent[idx] = false;
|
|
} else {
|
|
++_spriteSetCount;
|
|
}
|
|
|
|
if (idx == 0)
|
|
_spriteListStart = setIndex;
|
|
}
|
|
|
|
result = 0;
|
|
// TODO: Unknown flag
|
|
_spritesChanged = false;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Called each frame to update the display of the player
|
|
*/
|
|
void MadsPlayer::update() {
|
|
if (_forceRefresh || (_visible != _priorVisible)) {
|
|
// If there's an existing player sprite visible, flag it for expiry
|
|
int slotIndex = getSpriteSlot();
|
|
if (slotIndex >= 0)
|
|
_madsVm->scene()->_spriteSlots[slotIndex].spriteType = EXPIRED_SPRITE;
|
|
|
|
// Figure out the depth for the sprite
|
|
int newDepth = 1;
|
|
int yp = MIN(_playerPos.y, (int16)155);
|
|
|
|
for (int idx = 1; idx < 15; ++idx) {
|
|
if (_madsVm->scene()->getSceneResources()._depthBands[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
|
|
MadsSpriteSlot slot;
|
|
slot.spriteType = FOREGROUND_SPRITE;
|
|
slot.seqIndex = PLAYER_SEQ_INDEX;
|
|
slot.spriteListIndex = _spriteListStart + _spriteListIdx;
|
|
slot.frameNumber = _frameOffset + _frameNum;
|
|
slot.xp = _playerPos.x;
|
|
slot.yp = _playerPos.y + (_yScale * newScale) / 100;
|
|
slot.depth = newDepth;
|
|
slot.scale = newScale;
|
|
|
|
if (slotIndex >= 0) {
|
|
// Check if the existing player slot has the same details, and can be re-used
|
|
MadsSpriteSlot &s2 = _madsVm->scene()->_spriteSlots[slotIndex];
|
|
bool equal = (s2.seqIndex == slot.seqIndex) && (s2.spriteListIndex == slot.spriteListIndex)
|
|
&& (s2.frameNumber == slot.frameNumber) && (s2.xp == slot.xp) && (s2.yp == slot.yp)
|
|
&& (s2.depth == slot.depth) && (s2.scale == slot.scale);
|
|
|
|
if (equal)
|
|
// Undo the prior expiry of the player sprite
|
|
s2.spriteType = SPRITE_ZERO;
|
|
else
|
|
slotIndex = -1;
|
|
}
|
|
|
|
if (slotIndex < 0) {
|
|
// New slot needed, so allocate one and copy the slot data
|
|
slotIndex = _madsVm->scene()->_spriteSlots.getIndex();
|
|
_madsVm->scene()->_spriteSlots[slotIndex] = slot;
|
|
}
|
|
|
|
// TODO: Meaning of _v844c0 block
|
|
|
|
}
|
|
}
|
|
|
|
_visible3 = _priorVisible = _visible;
|
|
_forceRefresh = false;
|
|
}
|
|
|
|
/**
|
|
* Updates the animation frame for the player
|
|
*/
|
|
void MadsPlayer::updateFrame() {
|
|
SpriteAsset &spriteSet = _madsVm->scene()->_spriteSlots.getSprite(_spriteListStart + _spriteListIdx);
|
|
assert(spriteSet._charInfo);
|
|
|
|
if (!spriteSet._charInfo->_numEntries) {
|
|
_frameNum = 1;
|
|
} else {
|
|
_frameListIndex = _actionList[_actionIndex];
|
|
|
|
if (!_visible) {
|
|
_unk2 = 0;
|
|
} else {
|
|
_unk2 = _actionList2[_actionIndex];
|
|
|
|
if (_actionIndex > 0)
|
|
--_actionIndex;
|
|
}
|
|
|
|
// Set the player frame number
|
|
int frameIndex = ABS(_frameListIndex);
|
|
_frameNum = (_frameListIndex <= 0) ? spriteSet._charInfo->_frameList[frameIndex] :
|
|
spriteSet._charInfo->_frameList2[frameIndex];
|
|
|
|
// Set next waiting period in ticks
|
|
if (frameIndex == 0)
|
|
setTicksAmount();
|
|
else
|
|
_madsVm->_player._ticksAmount = spriteSet._charInfo->_ticksList[frameIndex];
|
|
}
|
|
}
|
|
|
|
void MadsPlayer::setupFrame() {
|
|
resetActionList();
|
|
_frameOffset = 0;
|
|
_spriteListIdx = _directionListIndexes[_direction];
|
|
if (!_spriteSetsPresent[_spriteListIdx]) {
|
|
// Direction isn't present, so use alternate direction, with entries flipped
|
|
_spriteListIdx -= 4;
|
|
_frameOffset = 0x8000;
|
|
}
|
|
|
|
SpriteAsset &spriteSet = _madsVm->scene()->_spriteSlots.getSprite(_spriteListStart + _spriteListIdx);
|
|
assert(spriteSet._charInfo);
|
|
_unk1 = MAX(spriteSet._charInfo->_unk1, 100);
|
|
setTicksAmount();
|
|
|
|
_frameCount = spriteSet._charInfo->_totalFrames;
|
|
if (_frameCount == 0)
|
|
_frameCount = spriteSet.getCount();
|
|
|
|
_yScale = spriteSet._charInfo->_yScale;
|
|
|
|
if ((_frameNum <= 0) || (_frameNum > _frameCount))
|
|
_frameNum = 1;
|
|
_forceRefresh = true;
|
|
}
|
|
|
|
void MadsPlayer::step() {
|
|
if (_visible && _stepEnabled && !_moving && (_direction == _newDirection) && (_madsVm->_currentTimer >= GET_GLOBAL32(2))) {
|
|
if (_actionIndex == 0) {
|
|
int randVal = _vm->_random->getRandomNumber(29999);
|
|
|
|
if (GET_GLOBAL(0) == SEX_MALE) {
|
|
switch (_direction) {
|
|
case 1:
|
|
case 3:
|
|
case 7:
|
|
case 9:
|
|
if (randVal < 200) {
|
|
queueAction(-1, 0);
|
|
queueAction(1, 0);
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
if (randVal < 500) {
|
|
for (int i = 0; i < 10; ++i)
|
|
queueAction((randVal < 250) ? 1 : 2, 0);
|
|
} else if (randVal < 750) {
|
|
for (int i = 0; i < 5; ++i)
|
|
queueAction(1, 0);
|
|
queueAction(0, 0);
|
|
for (int i = 0; i < 5; ++i)
|
|
queueAction(2, 0);
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
case 6:
|
|
if (randVal < 500) {
|
|
for (int i = 0; i < 10; ++i)
|
|
queueAction(1, 0);
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
case 8:
|
|
if (randVal < 200) {
|
|
queueAction(-1, 0);
|
|
queueAction(1, 0);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SET_GLOBAL32(2, GET_GLOBAL32(2) + 6);
|
|
}
|
|
|
|
if (GET_GLOBAL(138) == 1) {
|
|
uint32 diff = _madsVm->_currentTimer - GET_GLOBAL32(142);
|
|
if (diff > 60) {
|
|
SET_GLOBAL32(144, GET_GLOBAL32(144) + 1);
|
|
} else {
|
|
SET_GLOBAL32(144, GET_GLOBAL32(144) + diff);
|
|
}
|
|
|
|
SET_GLOBAL32(142, _madsVm->_currentTimer);
|
|
}
|
|
}
|
|
|
|
void MadsPlayer::nextFrame() {
|
|
if (_madsVm->_currentTimer >= (_priorTimer + _ticksAmount)) {
|
|
_priorTimer = _madsVm->_currentTimer;
|
|
|
|
if (_moving)
|
|
move();
|
|
else
|
|
idle();
|
|
|
|
// Post update logic
|
|
if (_moving) {
|
|
++_frameNum;
|
|
if (_frameNum > _frameCount)
|
|
_frameNum = 1;
|
|
_forceRefresh = true;
|
|
} else if (!_forceRefresh) {
|
|
idle();
|
|
}
|
|
|
|
// Final update
|
|
update();
|
|
}
|
|
}
|
|
|
|
void MadsPlayer::setDest(int destX, int destY, int facing) {
|
|
resetActionList();
|
|
setTicksAmount();
|
|
_moving = true;
|
|
_destFacing = facing;
|
|
|
|
_madsVm->scene()->getSceneResources().setRouteNode(_madsVm->scene()->getSceneResources()._nodes.size() - 2,
|
|
_playerPos, _madsVm->scene()->_depthSurface);
|
|
_madsVm->scene()->getSceneResources().setRouteNode(_madsVm->scene()->getSceneResources()._nodes.size() - 1,
|
|
Common::Point(destX, destY), _madsVm->scene()->_depthSurface);
|
|
|
|
bool v = _madsVm->scene()->getDepthHighBit(Common::Point(destX, destY));
|
|
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 = _madsVm->scene()->getSceneResources()._nodes[idx].pt;
|
|
|
|
_next = scanPath(_madsVm->scene()->_depthSurface, srcPos, pt);
|
|
srcPos = pt;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int MadsPlayer::getScale(int yp) {
|
|
MadsSceneResources &r = _madsVm->scene()->getSceneResources();
|
|
|
|
int scale = (r.bandsRange() == 0) ? r._maxScale : (yp - r._yBandsStart) * r.scaleRange() / r.bandsRange()
|
|
+ r._minScale;
|
|
|
|
return MIN(scale, 100);
|
|
}
|
|
|
|
/**
|
|
* Scans through the scene's sprite slot list to find any sprite displaying the player
|
|
*/
|
|
int MadsPlayer::getSpriteSlot() {
|
|
MadsSpriteSlots &slots = _madsVm->scene()->_spriteSlots;
|
|
for (int i = 0; i < slots.startIndex; ++i) {
|
|
if ((slots[i].seqIndex == PLAYER_SEQ_INDEX) && (slots[i].spriteType >= SPRITE_ZERO))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void MadsPlayer::setTicksAmount() {
|
|
SpriteAsset &spriteSet = _madsVm->scene()->_spriteSlots.getSprite(_spriteListStart + _spriteListIdx);
|
|
assert(spriteSet._charInfo);
|
|
_madsVm->_player._ticksAmount = spriteSet._charInfo->_ticksAmount;
|
|
if (_madsVm->_player._ticksAmount == 0)
|
|
_madsVm->_player._ticksAmount = 6;
|
|
}
|
|
|
|
void MadsPlayer::resetActionList() {
|
|
_actionList[0] = 0;
|
|
_actionList2[0] = 0;
|
|
_actionIndex = 0;
|
|
_unk2 = 0;
|
|
_unk3 = 0;
|
|
}
|
|
|
|
int MadsPlayer::queueAction(int action1, int action2) {
|
|
SpriteAsset &spriteSet = _madsVm->scene()->_spriteSlots.getSprite(_spriteListStart + _spriteListIdx);
|
|
assert(spriteSet._charInfo);
|
|
|
|
if ((action1 < spriteSet._charInfo->_numEntries) && (_actionIndex < 11)) {
|
|
++_actionIndex;
|
|
_actionList[_actionIndex] = action1;
|
|
_actionList2[_actionIndex] = action2;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void MadsPlayer::idle() {
|
|
if (_direction != _newDirection) {
|
|
// The direction has changed, so reset for new direction
|
|
dirChanged();
|
|
return;
|
|
}
|
|
|
|
SpriteAsset &spriteSet = _madsVm->scene()->_spriteSlots.getSprite(_spriteListStart + _spriteListIdx);
|
|
assert(spriteSet._charInfo);
|
|
if (spriteSet._charInfo->_numEntries == 0)
|
|
// No entries, so exit immediately
|
|
return;
|
|
|
|
int frameIndex = ABS(_frameListIndex);
|
|
int direction = (_frameListIndex < 0) ? -1 : 1;
|
|
|
|
if (frameIndex >= spriteSet._charInfo->_numEntries)
|
|
// Reset back to the start of the list
|
|
_frameListIndex = 0;
|
|
else {
|
|
_frameNum += direction;
|
|
_forceRefresh = true;
|
|
|
|
if (spriteSet._charInfo->_frameList2[frameIndex] < _frameNum) {
|
|
_unk3 = _unk2;
|
|
updateFrame();
|
|
}
|
|
if (spriteSet._charInfo->_frameList[frameIndex] < _frameNum) {
|
|
_unk3 = _unk2;
|
|
updateFrame();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MadsPlayer::move() {
|
|
bool routeFlag = false;
|
|
|
|
if (_moving) {
|
|
int idx = _routeCount;
|
|
while (!_v844C0 && (_destPos.x == _playerPos.x) && (_destPos.y == _playerPos.y)) {
|
|
if (idx != 0) {
|
|
--idx;
|
|
SceneNode &node = _madsVm->scene()->getSceneResources()._nodes[_routeIndexes[idx]];
|
|
_destPos = node.pt;
|
|
routeFlag = true;
|
|
} else if (_v844BE == idx) {
|
|
// End of walking path
|
|
_routeCount = 0;
|
|
_moving = false;
|
|
turnToDestFacing();
|
|
routeFlag = true;
|
|
idx = _routeCount;
|
|
} else {
|
|
_v844C0 = _v844BE;
|
|
_v844BC = true;
|
|
_v844BE = 0;
|
|
_stepEnabled = true;
|
|
routeFlag = false;
|
|
}
|
|
|
|
if (!_moving)
|
|
break;
|
|
}
|
|
_routeCount = idx;
|
|
}
|
|
|
|
if (routeFlag && _moving)
|
|
startMovement();
|
|
|
|
if (_newDirection != _direction)
|
|
dirChanged();
|
|
else if (!_moving)
|
|
updateFrame();
|
|
|
|
int var1 = _unk1;
|
|
if (_unk4 && (_hypotenuse > 0)) {
|
|
int v1 = -(_currentScale - 100) * (_posDiff.x - 1) / _hypotenuse + _currentScale;
|
|
var1 = MAX(1, 10000 / (v1 * _currentScale * var1));
|
|
}
|
|
|
|
if (!_moving || (_direction != _newDirection))
|
|
return;
|
|
|
|
Common::Point newPos = _playerPos;
|
|
|
|
if (_v8452E < var1) {
|
|
do {
|
|
if (_v8452C < _posDiff.x)
|
|
_v8452C += _posDiff.y;
|
|
if (_v8452C >= _posDiff.x) {
|
|
if ((_posChange.y > 0) || (_v844C0 != 0))
|
|
newPos.y += _yDirection;
|
|
--_posChange.y;
|
|
_v8452C -= _posDiff.x;
|
|
}
|
|
|
|
if (_v8452C < _posDiff.x) {
|
|
if ((_posChange.x > 0) || (_v844C0 != 0))
|
|
newPos.x += _xDirection;
|
|
--_posChange.x;
|
|
}
|
|
|
|
if ((_v844BC == 0) && (_v844C0 == 0) && (_v844BE == 0)) {
|
|
routeFlag = _madsVm->scene()->getDepthHighBit(newPos);
|
|
|
|
if (_special == 0)
|
|
_special = _madsVm->scene()->getDepthHighBits(newPos);
|
|
}
|
|
|
|
_v8452E += _v84530;
|
|
|
|
} while ((_v8452E < var1) && !routeFlag && ((_posChange.x > 0) || (_posChange.y > 0) || (_v844C0 != 0)));
|
|
}
|
|
|
|
_v8452E -= var1;
|
|
|
|
if (routeFlag)
|
|
moveComplete();
|
|
else {
|
|
if (!_v844C0) {
|
|
// If the move is complete, make sure the position is exactly on the given destination
|
|
if (_posChange.x == 0)
|
|
newPos.x = _destPos.x;
|
|
if (_posChange.y == 0)
|
|
newPos.y = _destPos.y;
|
|
}
|
|
|
|
_playerPos = newPos;
|
|
}
|
|
}
|
|
|
|
void MadsPlayer::dirChanged() {
|
|
int dirIndex = 0, dirIndex2 = 0;
|
|
int newDir = 0, newDir2 = 0;
|
|
|
|
if (_direction != _newDirection) {
|
|
// Find the index for the given direction in the player direction list
|
|
int tempDir = _direction;
|
|
do {
|
|
++dirIndex;
|
|
newDir += tempDir;
|
|
tempDir = _directionListIndexes[tempDir + 10];
|
|
} while (tempDir != _newDirection);
|
|
}
|
|
|
|
|
|
if (_direction != _newDirection) {
|
|
// Find the index for the given direction in the player direction list
|
|
int tempDir = _direction;
|
|
do {
|
|
++dirIndex2;
|
|
newDir2 += tempDir;
|
|
tempDir = _directionListIndexes[tempDir + 20];
|
|
} while (tempDir != _newDirection);
|
|
}
|
|
|
|
int diff = dirIndex - dirIndex2;
|
|
if (diff == 0)
|
|
diff = newDir - newDir2;
|
|
|
|
_direction = (diff >= 0) ? _directionListIndexes[_direction + 20] : _directionListIndexes[_direction + 10];
|
|
setupFrame();
|
|
if ((_direction == _newDirection) && !_moving)
|
|
updateFrame();
|
|
|
|
_priorTimer += 1;
|
|
}
|
|
|
|
void MadsPlayer::moveComplete() {
|
|
reset();
|
|
//todo: Unknown flag
|
|
}
|
|
|
|
void MadsPlayer::reset() {
|
|
_destPos = _playerPos;
|
|
_destFacing = 5;
|
|
_newDirection = _direction;
|
|
|
|
_madsVm->scene()->_action._startWalkFlag = false;
|
|
_madsVm->scene()->_action._walkFlag = false;
|
|
_moving = false;
|
|
_v844BC = false;
|
|
_v844C0 = false;
|
|
_v844BE = 0;
|
|
_next = 0;
|
|
_routeCount = 0;
|
|
}
|
|
|
|
/**
|
|
* Scans along an edge connecting two points within the depths/walk surface, and returns the information of the first
|
|
* pixel high nibble encountered with a non-zero value
|
|
*/
|
|
int MadsPlayer::scanPath(M4Surface *depthSurface, const Common::Point &srcPos, const Common::Point &destPos) {
|
|
// For compressed depth surfaces, always return 0
|
|
if (_madsVm->scene()->getSceneResources()._depthStyle != 2)
|
|
return 0;
|
|
|
|
int yDiff = destPos.y - srcPos.y;
|
|
int yAmount = MADS_SURFACE_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;
|
|
}
|
|
|
|
/**
|
|
* Starts a player moving to a given destination
|
|
*/
|
|
void MadsPlayer::startMovement() {
|
|
int xDiff = _destPos.x - _playerPos.x;
|
|
int yDiff = _destPos.y - _playerPos.y;
|
|
int srcScale = getScale(_playerPos.y);
|
|
int destScale = getScale(_destPos.y);
|
|
|
|
// 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;
|
|
|
|
int scaleAmount = (_unk4 ? scaleDiff * 3 : 0) + 100 * yDiff / 100;
|
|
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:
|
|
_newDirection = (_yDirection <= 0) ? 8 : 2;
|
|
break;
|
|
case 2: {
|
|
_newDirection = ((_yDirection <= 0) ? 9 : 3) - ((_xDirection <= 0) ? 2 : 0);
|
|
break;
|
|
}
|
|
case 3:
|
|
_newDirection = (_xDirection <= 0) ? 4 : 6;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
_hypotenuse = SqrtF16(xAmt100 * xAmt100 + yAmt100 * yAmt100);
|
|
_posDiff.x = xDiff + 1;
|
|
_posDiff.y = yDiff + 1;
|
|
_posChange.x = xDiff;
|
|
_posChange.y = yDiff;
|
|
|
|
int majorChange = MAX(xDiff, yDiff);
|
|
_v84530 = (majorChange == 0) ? 0 : _hypotenuse / majorChange;
|
|
|
|
if (_playerPos.x > _destPos.x)
|
|
_v8452C = MAX(_posChange.x, _posChange.y);
|
|
else
|
|
_v8452C = 0;
|
|
|
|
_hypotenuse /= 100;
|
|
_v8452E = -_v84530;
|
|
}
|
|
|
|
void MadsPlayer::turnToDestFacing() {
|
|
if (_destFacing != 5)
|
|
_newDirection = _destFacing;
|
|
}
|
|
|
|
void MadsPlayer::setupRoute(bool bitFlag) {
|
|
// Reset the flag set of nodes in use
|
|
SceneNodeList &nodes = _madsVm->scene()->getSceneResources()._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 MadsPlayer::setupRouteNode(int *routeIndexP, int nodeIndex, int flags, int routeLength) {
|
|
SceneNodeList &nodes = _madsVm->scene()->getSceneResources()._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;
|
|
}
|
|
|
|
} // End of namespace M4
|