MADS: Implemented lots of Player methods
This commit is contained in:
parent
834cf846f1
commit
f3415b762e
9 changed files with 814 additions and 20 deletions
|
@ -179,11 +179,18 @@ void Game::sectionLoop() {
|
|||
|
||||
_vm->_palette->_paletteUsage.load(3, 0xF0, 0xF1, 0xF2);
|
||||
|
||||
if (!_player._spritesLoaded && _v3) {
|
||||
if (_player.loadSprites(""))
|
||||
_vm->quitGame();
|
||||
_playerSpritesFlag = true;
|
||||
}
|
||||
|
||||
_scene.loadScene(_scene._nextSceneId, _aaName, 0);
|
||||
_vm->_sound->pauseNewCommands();
|
||||
|
||||
if (!_player._spritesLoaded) {
|
||||
_player.loadSprites("");
|
||||
if (_player.loadSprites(""))
|
||||
_vm->quitGame();
|
||||
_playerSpritesFlag = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -521,4 +521,18 @@ int DepthSurface::getDepth(const Common::Point &pt) {
|
|||
}
|
||||
}
|
||||
|
||||
int DepthSurface::getDepthHighBit(const Common::Point &pt) {
|
||||
if (_vm->_game->_scene._sceneInfo->_depthStyle == 2) {
|
||||
int bits = (3 - (pt.x % 4)) * 2;
|
||||
byte v = *getBasePtr(pt.x >> 2, pt.y);
|
||||
return (v >> bits) & 2;
|
||||
} else {
|
||||
if (pt.x < 0 || pt.y < 0 || pt.x >= this->w || pt.y >= this->h)
|
||||
return 0;
|
||||
|
||||
return *getBasePtr(pt.x, pt.y) & 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace MADS
|
||||
|
|
|
@ -223,6 +223,10 @@ public:
|
|||
* Returns the depth at a given position
|
||||
*/
|
||||
int getDepth(const Common::Point &pt);
|
||||
|
||||
/**
|
||||
*/
|
||||
int getDepthHighBit(const Common::Point &pt);
|
||||
};
|
||||
|
||||
} // End of namespace MADS
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace MADS {
|
|||
namespace Nebular {
|
||||
|
||||
GameNebular::GameNebular(MADSEngine *vm): Game(vm) {
|
||||
_surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT - MADS_INTERFACE_HEIGHT);
|
||||
_surface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
|
||||
_storyMode = STORYMODE_NAUGHTY;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,21 +26,47 @@
|
|||
|
||||
namespace MADS {
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
Player::Player(MADSEngine *vm): _vm(vm) {
|
||||
_action = nullptr;
|
||||
_direction = 8;
|
||||
_newDirection = 8;
|
||||
_destFacing = 0;
|
||||
_spritesLoaded = false;
|
||||
_spritesStart = _numSprites = 0;
|
||||
_spritesStart = 0;
|
||||
_spritesIdx = 0;
|
||||
_numSprites = 0;
|
||||
_stepEnabled = false;
|
||||
_visible = false;
|
||||
_priorVisible = false;
|
||||
_visible3 = false;
|
||||
_special = 0;
|
||||
_ticksAmount = 0;
|
||||
_priorTimer = 0;
|
||||
_unk3 = _unk4 = 0;
|
||||
_forceRefresh = false;
|
||||
_highSprites = false;
|
||||
_currentDepth = 0;
|
||||
_currentScale = 0;
|
||||
_frameOffset = 0;
|
||||
_frameNum = 0;
|
||||
_yScale = 0;
|
||||
_frameCount = 0;
|
||||
_unk1 = 0;
|
||||
_unk2 = 0;
|
||||
_unk3 = 0;
|
||||
_frameListIndex = 0;
|
||||
_actionIndex = 0;
|
||||
_hypotenuse = 0;
|
||||
|
||||
Common::fill(&_actionList[0], &_actionList[12], 0);
|
||||
Common::fill(&_actionList2[0], &_actionList2[12], 0);
|
||||
Common::fill(&_spriteSetsPresent[0], &_spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT], false);
|
||||
}
|
||||
|
||||
void Player::reset() {
|
||||
|
@ -49,7 +75,7 @@ void Player::reset() {
|
|||
_destFacing = 5;
|
||||
_newDirection = _direction;
|
||||
_moving = false;
|
||||
_v844C0 = _v844BE = 0;
|
||||
_newSceneId = _v844BE = 0;
|
||||
_next = 0;
|
||||
_routeCount = 0;
|
||||
|
||||
|
@ -58,8 +84,49 @@ void Player::reset() {
|
|||
_action->_walkFlag = false;
|
||||
}
|
||||
|
||||
void Player::loadSprites(const Common::String &prefix) {
|
||||
warning("TODO: Player::loadSprites");
|
||||
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;
|
||||
int setIndex = _vm->_game->_scene._sprites.addSprites(setName, 4);
|
||||
if (setIndex >= 0) {
|
||||
++_numSprites;
|
||||
} else if (fileIndex >= 5) {
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::turnToDestFacing() {
|
||||
|
@ -67,30 +134,227 @@ void Player::turnToDestFacing() {
|
|||
_newDirection = _destFacing;
|
||||
}
|
||||
|
||||
void Player::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 Player::moveComplete() {
|
||||
reset();
|
||||
_action->_inProgress = false;
|
||||
}
|
||||
|
||||
void Player::setupFrame() {
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
|
||||
resetActionList();
|
||||
warning("TODO: Player::setupFrame");
|
||||
_frameOffset = 0;
|
||||
_spritesIdx = _directionListIndexes[_direction];
|
||||
if (!_spriteSetsPresent[_spritesIdx]) {
|
||||
// Direction isn't present, so use alternate direction, with entries flipped
|
||||
_spritesIdx -= 4;
|
||||
_frameOffset = 0x8000;
|
||||
}
|
||||
|
||||
SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
|
||||
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 Player::updateFrame() {
|
||||
warning("TODO: Player::updateFrame");
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
SpriteAsset &spriteSet = *scene._sprites[_spritesStart + _spritesIdx];
|
||||
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 {
|
||||
_ticksAmount = spriteSet._charInfo->_ticksList[frameIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::update() {
|
||||
warning("TODO: Player::update");
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
|
||||
if (_forceRefresh || (_visible != _priorVisible)) {
|
||||
int slotIndex = getSpriteSlot();
|
||||
if (slotIndex >= 0)
|
||||
scene._spriteSlots[slotIndex]._spriteType = ST_EXPIRED;
|
||||
|
||||
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;
|
||||
slot._spriteType = ST_FOREGROUND;
|
||||
slot._seqIndex = PLAYER_SEQ_INDEX;
|
||||
slot._spritesIndex = _spritesStart + _spritesIdx;
|
||||
slot._frameNumber = _frameOffset + _frameNum;
|
||||
slot._position.x = _playerPos.x;
|
||||
slot._position.y = _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
|
||||
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
|
||||
s2._spriteType = ST_NONE;
|
||||
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
|
||||
if (_newSceneId) {
|
||||
SpriteAsset *asset = scene._sprites[slot._spritesIndex];
|
||||
MSprite *frame = asset->getFrame(_frameNum - 1);
|
||||
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) {
|
||||
scene._nextSceneId = _newSceneId;
|
||||
_newSceneId = 0;
|
||||
_vm->_game->_v4 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
_visible3 = _visible;
|
||||
_priorVisible = _visible;
|
||||
_forceRefresh = false;
|
||||
}
|
||||
|
||||
void Player::resetActionList() {
|
||||
warning("TODO: Player::resetActionList");
|
||||
_actionList[0] = 0;
|
||||
_actionList2[0] = 0;
|
||||
_actionIndex = 0;
|
||||
_unk2 = 0;
|
||||
_unk3 = 0;
|
||||
}
|
||||
|
||||
void Player::setDest(const Common::Point &pt, int facing) {
|
||||
warning("TODO: Player::setDest");
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
|
||||
resetActionList();
|
||||
setTicksAmount();
|
||||
_moving = true;
|
||||
_destFacing = facing;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::nextFrame() {
|
||||
|
@ -111,15 +375,364 @@ void Player::nextFrame() {
|
|||
}
|
||||
|
||||
void Player::move() {
|
||||
warning("TODO: Player::move");
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
bool routeFlag = false;
|
||||
|
||||
if (_moving) {
|
||||
int idx = _routeCount;
|
||||
while (!_newSceneId && (_destPos.x == _playerPos.x) && (_destPos.y == _playerPos.y)) {
|
||||
if (idx != 0) {
|
||||
--idx;
|
||||
SceneNode &node = scene._sceneInfo->_nodes[_routeIndexes[idx]];
|
||||
_destPos = node._walkPos;
|
||||
routeFlag = true;
|
||||
}
|
||||
else if (_v844BE == idx) {
|
||||
// End of walking path
|
||||
_routeCount = 0;
|
||||
_moving = false;
|
||||
turnToDestFacing();
|
||||
routeFlag = true;
|
||||
idx = _routeCount;
|
||||
}
|
||||
else {
|
||||
_newSceneId = _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) || (_newSceneId != 0))
|
||||
newPos.y += _yDirection;
|
||||
--_posChange.y;
|
||||
_v8452C -= _posDiff.x;
|
||||
}
|
||||
|
||||
if (_v8452C < _posDiff.x) {
|
||||
if ((_posChange.x > 0) || (_newSceneId != 0))
|
||||
newPos.x += _xDirection;
|
||||
--_posChange.x;
|
||||
}
|
||||
|
||||
if ((_v844BC == 0) && (_newSceneId == 0) && (_v844BE == 0)) {
|
||||
routeFlag = scene._depthSurface.getDepthHighBit(newPos);
|
||||
|
||||
if (_special == 0)
|
||||
_special = scene.getDepthHighBits(newPos);
|
||||
}
|
||||
|
||||
_v8452E += _v84530;
|
||||
|
||||
} while ((_v8452E < var1) && !routeFlag && ((_posChange.x > 0) || (_posChange.y > 0) || (_newSceneId != 0)));
|
||||
}
|
||||
|
||||
_v8452E -= var1;
|
||||
|
||||
if (routeFlag)
|
||||
moveComplete();
|
||||
else {
|
||||
if (!_newSceneId) {
|
||||
// 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 Player::idle() {
|
||||
warning("TODO: Player::idle");
|
||||
Scene &scene = _vm->_game->_scene;
|
||||
|
||||
if (_direction != _newDirection) {
|
||||
// The direction has changed, so reset for new direction
|
||||
dirChanged();
|
||||
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;
|
||||
|
||||
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 Player::postUpdate() {
|
||||
warning("TODO: Player::postUpdate");
|
||||
if (_moving) {
|
||||
if (++_frameNum > _frameCount)
|
||||
_frameNum = 1;
|
||||
_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 &&
|
||||
spriteSlots[idx]._spriteType >= ST_NONE)
|
||||
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);
|
||||
}
|
||||
|
||||
void Player::setTicksAmount() {
|
||||
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() {
|
||||
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 = sqrt((double)(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;
|
||||
}
|
||||
|
||||
} // End of namespace MADS
|
||||
|
|
|
@ -31,10 +31,32 @@ namespace MADS {
|
|||
class MADSEngine;
|
||||
class Action;
|
||||
|
||||
#define PLAYER_SPRITES_FILE_COUNT 8
|
||||
|
||||
class Player {
|
||||
private:
|
||||
static const int _directionListIndexes[32];
|
||||
private:
|
||||
MADSEngine *_vm;
|
||||
MADSAction *_action;
|
||||
bool _highSprites;
|
||||
bool _spriteSetsPresent[PLAYER_SPRITES_FILE_COUNT];
|
||||
int _currentDepth;
|
||||
int _currentScale;
|
||||
int _frameOffset;
|
||||
int _frameNum;
|
||||
int _yScale;
|
||||
int _frameCount;
|
||||
int _frameListIndex;
|
||||
int _actionIndex;
|
||||
bool _v844BC;
|
||||
int _v8452E;
|
||||
int _v8452C;
|
||||
int _v84530;
|
||||
int _routeLength;
|
||||
int _actionList[12];
|
||||
int _actionList2[12];
|
||||
int _hypotenuse;
|
||||
|
||||
void reset();
|
||||
|
||||
|
@ -43,33 +65,78 @@ private:
|
|||
void move();
|
||||
|
||||
void postUpdate();
|
||||
|
||||
/**
|
||||
* Get the sprite slot index for the player
|
||||
*/
|
||||
int getSpriteSlot();
|
||||
|
||||
/**
|
||||
* Get the scale for the player at the given Y position
|
||||
*/
|
||||
int getScale(int yp);
|
||||
|
||||
void setTicksAmount();
|
||||
|
||||
void setupRoute();
|
||||
|
||||
void setupRoute(bool bitFlag);
|
||||
|
||||
void setupRouteNode(int *routeIndexP, int nodeIndex, int flags, int routeLength);
|
||||
|
||||
/**
|
||||
* 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 scanPath(MSurface &depthSurface, const Common::Point &srcPos, const Common::Point &destPos);
|
||||
|
||||
/**
|
||||
* Starts a player moving to a given destination
|
||||
*/
|
||||
void startMovement();
|
||||
|
||||
void dirChanged();
|
||||
public:
|
||||
int _direction;
|
||||
int _newDirection;
|
||||
int _xDirection, _yDirection;
|
||||
int _destFacing;
|
||||
bool _spritesLoaded;
|
||||
int _spritesStart;
|
||||
int _spritesIdx;
|
||||
int _numSprites;
|
||||
bool _stepEnabled;
|
||||
bool _spritesChanged;
|
||||
bool _visible;
|
||||
bool _priorVisible;
|
||||
bool _visible3;
|
||||
Common::Point _playerPos;
|
||||
Common::Point _destPos;
|
||||
Common::Point _posChange;
|
||||
Common::Point _posDiff;
|
||||
bool _moving;
|
||||
int _v844C0, _v844BE;
|
||||
int _newSceneId, _v844BE;
|
||||
int _next;
|
||||
int _routeCount;
|
||||
int _special;
|
||||
int _ticksAmount;
|
||||
uint32 _priorTimer;
|
||||
int _unk3, _unk4;
|
||||
int _unk1;
|
||||
int _unk2;
|
||||
int _unk3;
|
||||
bool _unk4;
|
||||
bool _forceRefresh;
|
||||
Common::String _spritesPrefix;
|
||||
int _routeCount;
|
||||
int _routeOffset;
|
||||
int _tempRoute[MAX_ROUTE_NODES];
|
||||
int _routeIndexes[MAX_ROUTE_NODES];
|
||||
public:
|
||||
Player(MADSEngine *vm);
|
||||
|
||||
void loadSprites(const Common::String &prefix);
|
||||
/**
|
||||
* Load sprites for the player
|
||||
*/
|
||||
bool loadSprites(const Common::String &prefix);
|
||||
|
||||
void turnToDestFacing();
|
||||
|
||||
|
|
|
@ -394,6 +394,87 @@ void SceneInfo::SpriteInfo::load(Common::SeekableReadStream *f) {
|
|||
_scale = f->readByte();
|
||||
}
|
||||
|
||||
void SceneInfo::setRouteNode(int nodeIndex, const Common::Point &pt, MSurface &depthSurface) {
|
||||
int flags, hypotenuse;
|
||||
|
||||
_nodes[nodeIndex]._walkPos = pt;
|
||||
|
||||
// Recalculate inter-node lengths
|
||||
for (uint idx = 0; idx < _nodes.size(); ++idx) {
|
||||
int entry;
|
||||
if (idx == (uint)nodeIndex) {
|
||||
entry = 0x3FFF;
|
||||
}
|
||||
else {
|
||||
// Process the node
|
||||
flags = getRouteFlags(pt, _nodes[idx]._walkPos, depthSurface);
|
||||
|
||||
int xDiff = ABS(_nodes[idx]._walkPos.x - pt.x);
|
||||
int yDiff = ABS(_nodes[idx]._walkPos.y - pt.y);
|
||||
hypotenuse = sqrt((double)(xDiff * xDiff + yDiff * yDiff));
|
||||
|
||||
if (hypotenuse >= 0x3FFF)
|
||||
// Shouldn't ever be this large
|
||||
hypotenuse = 0x3FFF;
|
||||
|
||||
entry = hypotenuse | flags;
|
||||
_nodes[idx]._indexes[nodeIndex] = entry;
|
||||
_nodes[nodeIndex]._indexes[idx] = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SceneInfo::getRouteFlags(const Common::Point &src, const Common::Point &dest,
|
||||
MSurface &depthSurface) {
|
||||
int result = 0x8000;
|
||||
bool flag = false;
|
||||
|
||||
int xDiff = ABS(dest.x - src.x);
|
||||
int yDiff = ABS(dest.y - src.y);
|
||||
int xDirection = dest.x >= src.x ? 1 : -1;
|
||||
int yDirection = dest.y >= src.y ? depthSurface.w : -depthSurface.w;
|
||||
int majorDiff = 0;
|
||||
if (dest.x < src.x)
|
||||
majorDiff = MAX(xDiff, yDiff);
|
||||
++xDiff;
|
||||
++yDiff;
|
||||
|
||||
byte *srcP = depthSurface.getBasePtr(src.x, src.y);
|
||||
|
||||
int totalCtr = majorDiff;
|
||||
for (int xCtr = 0; xCtr < xDiff; ++xCtr, srcP += xDirection) {
|
||||
totalCtr += yDiff;
|
||||
|
||||
if ((*srcP & 0x80) == 0)
|
||||
flag = false;
|
||||
else if (!flag) {
|
||||
flag = true;
|
||||
result -= 0x4000;
|
||||
if (result == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
while (totalCtr >= xDiff) {
|
||||
totalCtr -= xDiff;
|
||||
|
||||
if ((*srcP & 0x80) == 0)
|
||||
flag = false;
|
||||
else if (!flag) {
|
||||
flag = true;
|
||||
result -= 0x4000;
|
||||
if (result == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
srcP += yDirection;
|
||||
}
|
||||
if (result == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
SceneInfo *SceneInfo::init(MADSEngine *vm) {
|
||||
|
|
|
@ -251,6 +251,9 @@ class SceneInfo {
|
|||
|
||||
void load(Common::SeekableReadStream *f);
|
||||
};
|
||||
|
||||
|
||||
int getRouteFlags(const Common::Point &src, const Common::Point &dest, MSurface &depthSurface);
|
||||
protected:
|
||||
MADSEngine *_vm;
|
||||
|
||||
|
@ -301,6 +304,11 @@ public:
|
|||
*/
|
||||
void load(int sceneId, int flags, const Common::String &resName, int v3,
|
||||
MSurface &depthSurface, MSurface &bgSurface);
|
||||
|
||||
/**
|
||||
* Set up a route node
|
||||
*/
|
||||
void setRouteNode(int nodeIndex, const Common::Point &pt, MSurface &depthSurface);
|
||||
};
|
||||
|
||||
} // End of namespace MADS
|
||||
|
|
|
@ -42,7 +42,7 @@ UserInterface::UserInterface(MADSEngine *vm) : _vm(vm) {
|
|||
_inventoryTopIndex = 0;
|
||||
_objectY = 0;
|
||||
|
||||
byte *pData = _vm->_screen.getBasePtr(0, MADS_SCREEN_HEIGHT - MADS_INTERFACE_HEIGHT);
|
||||
byte *pData = _vm->_screen.getBasePtr(0, MADS_SCENE_HEIGHT);
|
||||
setPixels(pData, MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT);
|
||||
}
|
||||
|
||||
|
@ -270,7 +270,7 @@ bool UserInterface::getBounds(ScrCategory category, int v, Common::Rect &bounds)
|
|||
}
|
||||
|
||||
void UserInterface::moveRect(Common::Rect &bounds) {
|
||||
bounds.translate(0, MADS_SCREEN_HEIGHT - MADS_INTERFACE_HEIGHT);
|
||||
bounds.translate(0, MADS_SCENE_HEIGHT);
|
||||
}
|
||||
|
||||
} // End of namespace MADS
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue