Esempio n. 1
0
void Pathfinding::calculate(BattleUnit *unit, Position endPosition)
{
	Position startPosition = unit->getPosition();
	_movementType = unit->getArmor()->getMovementType();
	_unit = unit;

	Tile *destinationTile = _save->getTile(endPosition);

	// check if destination is not blocked
	if (isBlocked(destinationTile, MapData::O_FLOOR) || isBlocked(destinationTile, MapData::O_OBJECT)) return;

	// the following check avoids that the unit walks behind the stairs if we click behind the stairs to make it go up the stairs.
	// it only works if the unit is on one of the 2 tiles on the stairs, or on the tile right in front of the stairs.
	if (isOnStairs(startPosition, endPosition))
	{
		endPosition.z++;
		destinationTile = _save->getTile(endPosition);
	}

	// check if we have floor, else lower destination (for non flying units only, because otherwise they never reached this place)
	while (canFallDown(destinationTile) && 	_movementType != MT_FLY)
	{
		endPosition.z--;
		destinationTile = _save->getTile(endPosition);
	}

	_path.clear();

	// look for a possible fast and accurate bresenham path and skip A*
	if (startPosition.z == endPosition.z && bresenhamPath(startPosition,endPosition))
	{
		std::reverse(_path.begin(), _path.end()); //paths are stored in reverse order
		return;
	}

	// Now try through A*.
	aStarPath(startPosition, endPosition);
}
Esempio n. 2
0
/**
 * Get's the TU cost to move from 1 tile to the other(ONE STEP ONLY). But also updates the endPosition, because it is possible
 * the unit goes upstairs or falls down while walking.
 * @param startPosition
 * @param direction
 * @param endPosition pointer
 * @param unit
 * @return TU cost - 255 if movement impossible
 */
int Pathfinding::getTUCost(const Position &startPosition, int direction, Position *endPosition, BattleUnit *unit)
{
	_unit = unit;
	directionToVector(direction, endPosition);
	*endPosition += startPosition;
	bool fellDown = false;
	bool triedStairs = false;
	int size = _unit->getArmor()->getSize() - 1;
	int cost = 0;
	int numberOfPartsChangingLevel = 0;


	for (int x = size; x >= 0; x--)
	{
		for (int y = size; y >= 0; y--)
		{

			Tile *startTile = _save->getTile(startPosition + Position(x,y,0));
			Tile *destinationTile = _save->getTile(*endPosition + Position(x,y,0));

			cost = 0;
			// this means the destination is probably outside the map
			if (!destinationTile)
				return 255;

			// check if the destination tile can be walked over
			if (isBlocked(destinationTile, MapData::O_FLOOR) || isBlocked(destinationTile, MapData::O_OBJECT))
				return 255;

			// can't walk on top of other units
			if (_save->getTile(*endPosition + Position(x,y,-1))
				&& _save->getTile(*endPosition + Position(x,y,-1))->getUnit()
				&& _save->getTile(*endPosition + Position(x,y,-1))->getUnit() != _unit
				&& _movementType != MT_FLY)
				return 255;


			if (direction < DIR_UP)
			{
				// check if we can go this way
				if (isBlocked(startTile, destinationTile, direction))
					return 255;
				if (startTile->getTerrainLevel() - destinationTile->getTerrainLevel() > 8 && x==0 && y==0)
					return 255;

			}
			else
			{
				// check if we can go up or down through gravlift or fly
				if (validateUpDown(unit, startPosition, direction))
				{
					cost = 8; // vertical movement by flying suit or grav lift
				}
				else
				{
					return 255;
				}
			}


			// if we are on a stairs try to go up a level
			if (direction < DIR_UP && startTile->getTerrainLevel() < -12 && x==0 && y==0)
			{
				endPosition->z++;
				destinationTile = _save->getTile(*endPosition);
				triedStairs = true;
			}

			// this means the destination is probably outside the map
			if (!destinationTile)
				return 255;

			int wallcost = 0; // walking through rubble walls
			if (direction == 7 || direction == 0 || direction == 1)
				wallcost += startTile->getTUCost(MapData::O_NORTHWALL, _movementType);
			if (direction == 1 || direction == 2 || direction == 3)
				wallcost += destinationTile->getTUCost(MapData::O_WESTWALL, _movementType);
			if (direction == 3 || direction == 4 || direction == 5)
				wallcost += destinationTile->getTUCost(MapData::O_NORTHWALL, _movementType);
			if (direction == 5 || direction == 6 || direction == 7)
				wallcost += startTile->getTUCost(MapData::O_WESTWALL, _movementType);

			// check if we have floor, else fall down
			while (canFallDown(destinationTile) && (_movementType != MT_FLY || triedStairs) && x==0 && y==0)
			{
				endPosition->z--;
				destinationTile = _save->getTile(*endPosition);
				fellDown = true;
				numberOfPartsChangingLevel++;
			}

			// if we don't want to fall down and there is no floor, we can't know the TUs so it's default to 4
			if (direction < DIR_UP && !fellDown && destinationTile->hasNoFloor() && x==0 && y==0)
			{
				cost = 4;
			}

			// check if the destination tile can be walked over
			if ((isBlocked(destinationTile, MapData::O_FLOOR) || isBlocked(destinationTile, MapData::O_OBJECT)) && !fellDown)
			{
				return 255;
			}

			// calculate the cost by adding floor walk cost and object walk cost
			if (direction < DIR_UP)
			{
				cost += destinationTile->getTUCost(MapData::O_FLOOR, _movementType);
				if (!fellDown)
				{
					cost += destinationTile->getTUCost(MapData::O_OBJECT, _movementType);
				}
			}

			// diagonal walking (uneven directions) costs 50% more tu's
			if (direction < DIR_UP && direction & 1)
			{
				wallcost /= 2;
				cost = (int)((double)cost * 1.5);
			}

			cost += wallcost;

			if (startTile->getTerrainLevel() != destinationTile->getTerrainLevel())
			{
				numberOfPartsChangingLevel++;
			}

		}
	}

	// for bigger sized units, check the path between part 1,1 and part 0,0 at end position
	if (size)
	{
			Tile *startTile = _save->getTile(*endPosition + Position(1,1,0));
			Tile *destinationTile = _save->getTile(*endPosition);
			int tmpDirection = 7;
			if (isBlocked(startTile, destinationTile, tmpDirection))
				return 255;

			// also check if we change level, that there are two parts changing level,
			// so a big sized unit can not go up a small sized stairs
			if (numberOfPartsChangingLevel == 1)
				return 255;
	}

	return cost;
}
Esempio n. 3
0
void Pathfinding::calculate(BattleUnit *unit, Position &endPosition)
{
	std::list<PathfindingNode*> openList;
	Position currentPos, nextPos, startPosition = unit->getPosition();
	int tuCost;

	_movementType = MT_WALK; // should be parameter
	_unit = unit;

	Tile *destinationTile = _save->getTile(endPosition);

	// check if destination is not blocked
	if (isBlocked(destinationTile, MapData::O_FLOOR) || isBlocked(destinationTile, MapData::O_OBJECT)) return;

	// the following check avoids that the unit walks behind the stairs if we click behind the stairs to make it go up the stairs.
	// it only works if the unit is on one of the 2 tiles on the stairs, or on the tile right in front of the stairs.
	if (isOnStairs(startPosition, endPosition))
	{
		endPosition.z++;
		destinationTile = _save->getTile(endPosition);
	}

	// check if we have floor, else lower destination (for non flying units only, because otherwise they never reached this place)
	while (canFallDown(destinationTile))
	{
		endPosition.z--;
		destinationTile = _save->getTile(endPosition);
	}


	_path.clear();

	// reset every node, so we have to check them all
	for (int i = 0; i < _size; ++i)
		_nodes[i]->reset();

	// start position is the first one in our "open" list
    openList.push_back(getNode(startPosition));
    openList.front()->check(0, 0, 0, 0);

	// if the open list is empty, we've reached the end
    while(!openList.empty())
	{
		// this algorithm expands in all directions
        for (int direction = 0; direction < 8; direction++)
		{
			currentPos = openList.front()->getPosition();
            tuCost = getTUCost(currentPos, direction, &nextPos, unit);
            if(tuCost < 255)
			{
				if( (!getNode(nextPos)->isChecked() ||
                getNode(nextPos)->getTUCost() > getNode(currentPos)->getTUCost() + tuCost) &&
                (!getNode(endPosition)->isChecked() ||
                getNode(endPosition)->getTUCost() > getNode(currentPos)->getTUCost() + tuCost)
                )
				{
					getNode(nextPos)->check(getNode(currentPos)->getTUCost() + tuCost,
											getNode(currentPos)->getStepsNum() + 1,
											getNode(currentPos),
											direction);
					openList.push_back(getNode(nextPos));
                }
            }
        }
		openList.pop_front();
    }

    if(!getNode(endPosition)->isChecked()) return;

    //Backward tracking of the path
    PathfindingNode* pf = getNode(endPosition);
    for (int i = getNode(endPosition)->getStepsNum(); i > 0; i--)
	{
		_path.push_back(pf->getPrevDir());
        pf=pf->getPrevNode();
    }

}
Esempio n. 4
0
/**
 * Get's the TU cost to move from 1 tile to the other(ONE STEP ONLY). But also updates the endPosition, because it is possible
 * the unit goes upstairs or falls down while walking.
 * @param startPosition
 * @param direction
 * @param endPosition pointer
 * @param unit
 * @return TU cost - 255 if movement impossible
 */
int Pathfinding::getTUCost(const Position &startPosition, int direction, Position *endPosition, BattleUnit *unit)
{
	_unit = unit;
	directionToVector(direction, endPosition);
	*endPosition += startPosition;
	bool fellDown = false;

	Tile *startTile = _save->getTile(startPosition);
	Tile *destinationTile = _save->getTile(*endPosition);

	// this means the destination is probably outside the map
	if (!destinationTile)
		return 255;

	// check if the destination tile can be walked over
	if (isBlocked(destinationTile, MapData::O_FLOOR) || isBlocked(destinationTile, MapData::O_OBJECT))
		return 255;


	// check if we can go this way
	if (isBlocked(startTile, destinationTile, direction))
		return 255;

	// if we are on a stairs try to go up a level
	if (startTile->getTerrainLevel() < -12)
	{
		endPosition->z++;
		destinationTile = _save->getTile(*endPosition);
	}

	// this means the destination is probably outside the map
	if (!destinationTile)
		return 255;

	// check if we have floor, else fall down
	while (canFallDown(destinationTile))
	{
		endPosition->z--;
		destinationTile = _save->getTile(*endPosition);
		fellDown = true;
	}

	// if we don't want to fall down and there is no floor, it ends here
	if (!fellDown && destinationTile->hasNoFloor())
	{
		return 255;
	}

	// check if the destination tile can be walked over
	if ((isBlocked(destinationTile, MapData::O_FLOOR) || isBlocked(destinationTile, MapData::O_OBJECT)) && !fellDown)
	{
		return 255;
	}

	// calculate the cost by adding floor walk cost and object walk cost
	int cost = destinationTile->getTUCost(MapData::O_FLOOR, _movementType);
	if (!fellDown)
	{
		cost += destinationTile->getTUCost(MapData::O_OBJECT, _movementType);
	}

	// diagonal walking (uneven directions) costs 50% more tu's
	if (direction & 1)
	{
		cost = (int)((double)cost * 1.5);
	}

	return cost;
}
Esempio n. 5
0
void Pathfinding::calculate(BattleUnit *unit, Position endPosition)
{
	std::list<PathfindingNode*> openList;
	PathfindingNode *currentNode, *nextNode;
	Position currentPos, nextPos, startPosition = unit->getPosition();
	int tuCost, totalTuCost = 0;

	_movementType = unit->getUnit()->getArmor()->getMovementType();
	_unit = unit;

	Tile *destinationTile = _save->getTile(endPosition);

	// check if destination is not blocked
	if (isBlocked(destinationTile, MapData::O_FLOOR) || isBlocked(destinationTile, MapData::O_OBJECT)) return;

	// the following check avoids that the unit walks behind the stairs if we click behind the stairs to make it go up the stairs.
	// it only works if the unit is on one of the 2 tiles on the stairs, or on the tile right in front of the stairs.
	if (isOnStairs(startPosition, endPosition))
	{
		endPosition.z++;
		destinationTile = _save->getTile(endPosition);
	}

	// check if we have floor, else lower destination (for non flying units only, because otherwise they never reached this place)
	while (canFallDown(destinationTile) && 	_movementType != MT_FLY)
	{
		endPosition.z--;
		destinationTile = _save->getTile(endPosition);
	}

	_path.clear();

	if (startPosition.z == endPosition.z && bresenhamPath(startPosition, endPosition))
		return;

	_path.clear();

	// reset every node, so we have to check them all
	for (int i = 0; i < _size; ++i)
		_nodes[i]->reset();

	// start position is the first one in our "open" list
	openList.push_back(getNode(startPosition));
	openList.front()->check(0, 0, 0, 0);

	// if the open list is empty, we've reached the end
	while(!openList.empty())
	{
		currentPos = openList.front()->getPosition();
		currentNode = getNode(currentPos);
		// this algorithm expands in all directions
		for (int direction = 0; direction < 10; direction++)
		{
			tuCost = getTUCost(currentPos, direction, &nextPos, unit);
			if(tuCost < 255) // check if we can go to this node (ie is not blocked)
			{
				nextNode = getNode(nextPos);
				totalTuCost = currentNode->getTUCost() + tuCost;
				// if we haven't checked this node, or the current cost tu cost is lower than our previous path, push this node in the open list to visit later.
				if( (!nextNode->isChecked() || nextNode->getTUCost() > totalTuCost)
					&& // this will keep pushing back nodes, as long as we did not reach the end position or there are still possible shorter paths
					(!getNode(endPosition)->isChecked() || getNode(endPosition)->getTUCost() > totalTuCost)
				)
				{
					nextNode->check(totalTuCost,
									currentNode->getStepsNum() + 1,
									currentNode,
									direction);
					openList.push_back(nextNode);
				}
			}
		}
		openList.pop_front();
	}

	if(!getNode(endPosition)->isChecked()) return;

	//Backward tracking of the path
	PathfindingNode* pf = getNode(endPosition);
	for (int i = getNode(endPosition)->getStepsNum(); i > 0; i--)
	{
		_path.push_back(pf->getPrevDir());
		pf=pf->getPrevNode();
	}

}
Esempio n. 6
0
/**
 * Get's the TU cost to move from 1 tile to the other(ONE STEP ONLY). But also updates the endPosition, because it is possible
 * the unit goes upstairs or falls down while walking.
 * @param startPosition
 * @param direction
 * @param endPosition pointer
 * @param unit
 * @return TU cost - 255 if movement impossible
 */
int Pathfinding::getTUCost(const Position &startPosition, int direction, Position *endPosition, BattleUnit *unit)
{
	_unit = unit;
	directionToVector(direction, endPosition);
	*endPosition += startPosition;
	bool fellDown = false;
	bool triedStairs = false;
	int size = _unit->getUnit()->getArmor()->getSize() - 1;
	int cost = 0;


	for (int x = size; x >= 0; x--)
	{
		for (int y = size; y >= 0; y--)
		{

			Tile *startTile = _save->getTile(startPosition + Position(x,y,0));
			Tile *destinationTile = _save->getTile(*endPosition + Position(x,y,0));

			cost = 0;
			// this means the destination is probably outside the map
			if (!destinationTile)
				return 255;

			// check if the destination tile can be walked over
			if (isBlocked(destinationTile, MapData::O_FLOOR) || isBlocked(destinationTile, MapData::O_OBJECT))
				return 255;


			if (direction < DIR_UP)
			{
				// check if we can go this way
				if (isBlocked(startTile, destinationTile, direction))
					return 255;
				if (startTile->getTerrainLevel() - destinationTile->getTerrainLevel() > 8 && x==0 && y==0)
					return 255;

			}
			else
			{
				// check if we can go up or down through gravlift or fly
				if (validateUpDown(unit, startPosition, direction))
				{
					cost += 4; // vertical movement
				}
				else
				{
					return 255;
				}
			}


			// if we are on a stairs try to go up a level
			if (startTile->getTerrainLevel() < -12 && x==0 && y==0)
			{
				endPosition->z++;
				destinationTile = _save->getTile(*endPosition);
				triedStairs = true;
			}

			// this means the destination is probably outside the map
			if (!destinationTile)
				return 255;

			// check if we have floor, else fall down
			while (canFallDown(destinationTile) && (_movementType != MT_FLY || triedStairs) && x==0 && y==0)
			{
				endPosition->z--;
				destinationTile = _save->getTile(*endPosition);
				fellDown = true;
			}

			// if we don't want to fall down and there is no floor, it ends here
			if (!fellDown && destinationTile->hasNoFloor() && x==0 && y==0)
			{
				if (_movementType != MT_FLY)
					return 255;
				else
					cost = 4;
			}

			// check if the destination tile can be walked over
			if ((isBlocked(destinationTile, MapData::O_FLOOR) || isBlocked(destinationTile, MapData::O_OBJECT)) && !fellDown)
			{
				return 255;
			}

			// calculate the cost by adding floor walk cost and object walk cost
			cost += destinationTile->getTUCost(MapData::O_FLOOR, _movementType);
			if (!fellDown)
			{
				cost += destinationTile->getTUCost(MapData::O_OBJECT, _movementType);
			}

			// diagonal walking (uneven directions) costs 50% more tu's
			if (direction & 1)
			{
				cost = (int)((double)cost * 1.5);
			}

		}
	}

	// for bigger sized units, check the path between part 1,1 and part 0,0 at end position
	if (size)
	{
			Tile *startTile = _save->getTile(*endPosition + Position(1,1,0));
			Tile *destinationTile = _save->getTile(*endPosition);
			int tmpDirection = 7;
			if (isBlocked(startTile, destinationTile, tmpDirection))
				return 255;
	}

	return cost;
}