diff options
| -rw-r--r-- | engines/mads/game.cpp | 9 | ||||
| -rw-r--r-- | engines/mads/msurface.cpp | 14 | ||||
| -rw-r--r-- | engines/mads/msurface.h | 4 | ||||
| -rw-r--r-- | engines/mads/nebular/game_nebular.cpp | 2 | ||||
| -rw-r--r-- | engines/mads/player.cpp | 637 | ||||
| -rw-r--r-- | engines/mads/player.h | 75 | ||||
| -rw-r--r-- | engines/mads/scene_data.cpp | 81 | ||||
| -rw-r--r-- | engines/mads/scene_data.h | 8 | ||||
| -rw-r--r-- | engines/mads/user_interface.cpp | 4 | 
9 files changed, 814 insertions, 20 deletions
| diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp index 5c034bf8bf..af23998b74 100644 --- a/engines/mads/game.cpp +++ b/engines/mads/game.cpp @@ -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;  		} diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp index 62807e5543..65858f520e 100644 --- a/engines/mads/msurface.cpp +++ b/engines/mads/msurface.cpp @@ -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 diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h index 37ab305fb0..7cf2bbe15b 100644 --- a/engines/mads/msurface.h +++ b/engines/mads/msurface.h @@ -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 diff --git a/engines/mads/nebular/game_nebular.cpp b/engines/mads/nebular/game_nebular.cpp index 1476620f9d..91c10a50ee 100644 --- a/engines/mads/nebular/game_nebular.cpp +++ b/engines/mads/nebular/game_nebular.cpp @@ -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;  } diff --git a/engines/mads/player.cpp b/engines/mads/player.cpp index 73b8ce06ba..fe1065cbed 100644 --- a/engines/mads/player.cpp +++ b/engines/mads/player.cpp @@ -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 diff --git a/engines/mads/player.h b/engines/mads/player.h index 92e28896c4..9a615e544f 100644 --- a/engines/mads/player.h +++ b/engines/mads/player.h @@ -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(); diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp index aa3670ee41..04dfc4be44 100644 --- a/engines/mads/scene_data.cpp +++ b/engines/mads/scene_data.cpp @@ -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) { diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h index ffea369166..00edefbf91 100644 --- a/engines/mads/scene_data.h +++ b/engines/mads/scene_data.h @@ -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 diff --git a/engines/mads/user_interface.cpp b/engines/mads/user_interface.cpp index cbd4573eb4..3b3fc9379a 100644 --- a/engines/mads/user_interface.cpp +++ b/engines/mads/user_interface.cpp @@ -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 | 
