* Calculates the shortest path using a simple A-Star algorithm. * The unit information and movement type must have already been set. * The path information is set only if a valid path is found. * @param startPosition The position to start from. * @param endPosition The position we want to reach. * @param target Target of the path. * @param sneak Is the unit sneaking? * @param maxTUCost Maxi
| 182 | * @return True if a path exists, false otherwise. |
| 183 | */ |
| 184 | bool Pathfinding::aStarPath(const Position &startPosition, const Position &endPosition, BattleUnit *target, bool sneak, int maxTUCost) |
| 185 | { |
| 186 | // reset every node, so we have to check them all |
| 187 | for (std::vector<PathfindingNode>::iterator it = _nodes.begin(); it != _nodes.end(); ++it) |
| 188 | it->reset(); |
| 189 | |
| 190 | // start position is the first one in our "open" list |
| 191 | PathfindingNode *start = getNode(startPosition); |
| 192 | start->connect(0, 0, 0, endPosition); |
| 193 | PathfindingOpenSet openList; |
| 194 | openList.push(start); |
| 195 | bool missile = (target && maxTUCost == -1); |
| 196 | // if the open list is empty, we've reached the end |
| 197 | while(!openList.empty()) |
| 198 | { |
| 199 | PathfindingNode *currentNode = openList.pop(); |
| 200 | Position const ¤tPos = currentNode->getPosition(); |
| 201 | currentNode->setChecked(); |
| 202 | if (currentPos == endPosition) // We found our target. |
| 203 | { |
| 204 | _path.clear(); |
| 205 | PathfindingNode *pf = currentNode; |
| 206 | while (pf->getPrevNode()) |
| 207 | { |
| 208 | _path.push_back(pf->getPrevDir()); |
| 209 | pf = pf->getPrevNode(); |
| 210 | } |
| 211 | return true; |
| 212 | } |
| 213 | |
| 214 | // Try all reachable neighbours. |
| 215 | for (int direction = 0; direction < 10; direction++) |
| 216 | { |
| 217 | Position nextPos; |
| 218 | int tuCost = getTUCost(currentPos, direction, &nextPos, _unit, target, missile); |
| 219 | if (tuCost >= 255) // Skip unreachable / blocked |
| 220 | continue; |
| 221 | if (sneak && _save->getTile(nextPos)->getVisible()) tuCost *= 2; // avoid being seen |
| 222 | PathfindingNode *nextNode = getNode(nextPos); |
| 223 | if (nextNode->isChecked()) // Our algorithm means this node is already at minimum cost. |
| 224 | continue; |
| 225 | _totalTUCost = currentNode->getTUCost(missile) + tuCost; |
| 226 | // If this node is unvisited or has only been visited from inferior paths... |
| 227 | if ((!nextNode->inOpenSet() || nextNode->getTUCost(missile) > _totalTUCost) && _totalTUCost <= maxTUCost) |
| 228 | { |
| 229 | nextNode->connect(_totalTUCost, currentNode, direction, endPosition); |
| 230 | openList.push(nextNode); |
| 231 | } |
| 232 | } |
| 233 | } |
| 234 | // Unble to reach the target |
| 235 | return false; |
| 236 | } |
| 237 | |
| 238 | /** |
| 239 | * Gets the TU cost to move from 1 tile to the other (ONE STEP ONLY). |
nothing calls this directly
no test coverage detected