rodecomp/Source/Contents/TerrainPathSearch.cpp
ragnarok-clanker 9541f2ff09 Decompile 4 functions in Source/Contents/TerrainPathSearch.cpp, Source/Contents/TerrainPathSearch.h
Batch #1547 by ragnarok-clanker: 0 byte-identical, 4 confirmed by peer review.

- fn_17868 CPathFinder::FindPath: logic confirmed by peer review
- fn_17875 CPathFinder::FindOrCreateNode: logic confirmed by peer review
- fn_17882 CPathFinder::AddNeighbor: logic confirmed by peer review
- fn_17884 CPathFinder::Clear: logic confirmed by peer review

Reviewed-by: ragnarok-clanker
2026-10-28 18:20:56 +00:00

216 lines
6.6 KiB
C++

#include "Contents/TerrainPathSearch.h"
#include "Resource/World/TerrainResource.h"
#include <algorithm>
#include <cstdlib>
// OFFSET: 0x00AD7E70
// FUNCTION: fn_17860
CPathFinder::CPathFinder() : useNodePool(false) {
}
// OFFSET: 0x00AD88F0
// FUNCTION: fn_17868
bool CPathFinder::FindPath(
int startTick, int startX, int startY, int currentFractionX, int currentFractionY, int destX, int destY, int speed, MovementRouteInterpolation& route,
char flag
) {
this->destinationX = destX;
this->destinationY = destY;
if (startX == destX && startY == destY) {
return false;
}
route.segment = 0;
this->Reset();
this->nodeCount = 0;
MovementPathNode* start = this->FindOrCreateNode(startX, startY);
start->state = 1;
start->parent = nullptr;
start->cost = 0;
start->estimatedCost = 10 * (std::abs(startX - this->destinationX) + std::abs(startY - this->destinationY));
std::vector<MovementPathNode*>& open = this->openList.Nodes();
open.push_back(start);
std::push_heap(open.begin(), open.end(), MovementPathNodeCompare());
while (!open.empty()) {
MovementPathNode* current = open.front();
std::pop_heap(open.begin(), open.end(), MovementPathNodeCompare());
open.pop_back();
if (current->x == destX && current->y == destY) {
float x = static_cast<float>(currentFractionX) * 0.0625f;
if (startX > 0) {
x = static_cast<float>(static_cast<double>(startX) - 0.5 + x);
}
route.startX = x;
float y = static_cast<float>(currentFractionY) * 0.0625f;
if (startY > 0) {
y = static_cast<float>(static_cast<double>(startY) - 0.5 + y);
}
route.startY = y;
BuildMovementRoute(startTick, current, speed, route);
return true;
}
if (this->CanMove(current->x, current->y, current->x + 1, current->y - 1, flag) && !this->AddNeighbor(current, 14, current->x + 1, current->y - 1, 5)) {
return false;
}
if (this->CanMove(current->x, current->y, current->x + 1, current->y, flag) && !this->AddNeighbor(current, 10, current->x + 1, current->y, 6)) {
return false;
}
if (this->CanMove(current->x, current->y, current->x + 1, current->y + 1, flag) && !this->AddNeighbor(current, 14, current->x + 1, current->y + 1, 7)) {
return false;
}
if (this->CanMove(current->x, current->y, current->x, current->y + 1, flag) && !this->AddNeighbor(current, 10, current->x, current->y + 1, 0)) {
return false;
}
if (this->CanMove(current->x, current->y, current->x - 1, current->y + 1, flag) && !this->AddNeighbor(current, 14, current->x - 1, current->y + 1, 1)) {
return false;
}
if (this->CanMove(current->x, current->y, current->x - 1, current->y, flag) && !this->AddNeighbor(current, 10, current->x - 1, current->y, 2)) {
return false;
}
if (this->CanMove(current->x, current->y, current->x - 1, current->y - 1, flag) && !this->AddNeighbor(current, 14, current->x - 1, current->y - 1, 3)) {
return false;
}
if (this->CanMove(current->x, current->y, current->x, current->y - 1, flag) && !this->AddNeighbor(current, 10, current->x, current->y - 1, 4)) {
return false;
}
current->state = 2;
}
return false;
}
// OFFSET: 0x00AD9030
// FUNCTION: fn_17875
MovementPathNode* CPathFinder::FindOrCreateNode(int x, int y) {
const int width = this->attr->width;
const int key = y * width + x;
auto found = this->nodeMap.find(key);
if (found != this->nodeMap.end() && found->second) {
return found->second;
}
MovementPathNode* node;
if (this->useNodePool) {
const int count = static_cast<int>(this->nodePool.size());
if (this->nodeCount >= count - 1) {
this->nodePool.resize(this->attr->height * width + 1);
}
node = &this->nodePool[this->nodeCount++];
} else {
if (this->nodeCount >= 149) {
return nullptr;
}
node = &this->nodes[this->nodeCount++];
}
if (!node) {
return nullptr;
}
node->x = x;
node->y = y;
node->state = 0;
this->nodeMap[key] = node;
return node;
}
// OFFSET: 0x00AD9550
// FUNCTION: fn_17879
bool CPathFinder::CanMove(int startX, int startY, int targetX, int targetY, char flag) const {
if (targetX < 0 || targetY < 0 || targetX >= this->attr->width || targetY >= this->attr->height) {
return false;
}
const TerrainHeightCell* cell = this->attr->Grid().CellAt(targetX, targetY);
if (!cell || cell->type == 1 || (flag != 12 && cell->type == 5)) {
return false;
}
if (startX == targetX || startY == targetY) {
return true;
}
const TerrainHeightCell* side = this->attr->Grid().CellAt(startX, targetY);
if (!side || side->type == 1 || side->type == 5) {
return false;
}
side = this->attr->Grid().CellAt(targetX, startY);
if (!side || side->type == 1 || side->type == 5) {
return false;
}
return true;
}
// OFFSET: 0x00AD9610
// FUNCTION: fn_17882
bool CPathFinder::AddNeighbor(MovementPathNode* current, int cost, int nextX, int nextY, int metadata) {
const int totalCost = current->cost + cost;
MovementPathNode* next = this->FindOrCreateNode(nextX, nextY);
if (!next) {
return false;
}
if (next->state == 0) {
next->parent = current;
next->state = 1;
next->cost = totalCost;
next->estimatedCost = totalCost + 10 * (std::abs(nextX - this->destinationX) + std::abs(nextY - this->destinationY));
next->metadata = metadata;
std::vector<MovementPathNode*>& open = this->openList.Nodes();
open.push_back(next);
std::push_heap(open.begin(), open.end(), MovementPathNodeCompare());
return true;
}
if (next->cost > totalCost) {
next->parent = current;
next->cost = totalCost;
next->estimatedCost = totalCost + 10 * (std::abs(nextX - this->destinationX) + std::abs(nextY - this->destinationY));
next->metadata = metadata;
if (next->state == 1) {
std::vector<MovementPathNode*>& open = this->openList.Nodes();
for (auto it = open.begin(); it != open.end(); ++it) {
if ((*it)->x == next->x && (*it)->y == next->y) {
std::push_heap(open.begin(), it + 1, MovementPathNodeCompare());
return true;
}
}
} else if (next->state == 2) {
next->state = 1;
}
}
return true;
}
// OFFSET: 0x00AD97C0
// FUNCTION: fn_17884
void CPathFinder::Clear() {
for (auto& [name, cached] : this->attrCache) {
delete cached;
}
this->attrCache.clear();
}
// OFFSET: 0x00AD9840
// FUNCTION: fn_17885
void CPathFinder::Reset() {
this->nodePool.erase(this->nodePool.begin(), this->nodePool.end());
this->nodeMap.erase(this->nodeMap.begin(), this->nodeMap.end());
std::vector<MovementPathNode*>& open = this->openList.Nodes();
open.erase(open.begin(), open.end());
}