#include "Contents/NavigationManager.h" #include "Contents/MessageTable.h" #include "Utility/Text/FormatString.h" #include "Client/Registry.h" #include "Client/Session.h" #include "Resource/ResourceMgr.h" #include "UI/Window/UIWindow.h" #include "UI/Window/UIWindowMgr.h" #include "Utility/RegistryKey.h" #include #include // OFFSET: 0x00B88800 // FUNCTION: fn_19376 CNaviInfo* CNavigationManager::FindObject(const char* name) const { for (CNaviInfo* info : this->data.destinations) { if (info->HasName(name)) { return info; } } return nullptr; } // OFFSET: 0x00B88840 // FUNCTION: fn_19377 CNavi_Link* CNaviData::FindLink(unsigned int key, bool byId) { if (byId) { for (CNavi_Link* object : this->objects) { if (object->HasId(key)) { return object; } } return nullptr; } if (this->objects.empty() || key >= this->objects.size()) { return nullptr; } return this->objects[key]; } // OFFSET: 0x00B88910 // FUNCTION: fn_19379 int NaviCell::GetY() const { return this->y; } // OFFSET: 0x00B88930 // FUNCTION: fn_19381 void CNaviData::ClearAll() { this->Clear(); for (CNavi_Link*& object : this->objects) { if (object != nullptr) { delete object; } object = nullptr; } this->objects.clear(); for (CNaviInfo*& info : this->destinations) { if (info != nullptr) { delete info; } info = nullptr; } this->destinations.clear(); } // OFFSET: 0x00B8CF70 // FUNCTION: fn_19432 bool CNavi_Object::HasId(const unsigned int& id) const { return static_cast(this->id) == id; } // OFFSET: 0x00B8D0D0 // FUNCTION: fn_19433 bool CNavi_Object::IsNamed(const char* name) const { if (name == nullptr) { return false; } return this->name == std::string(name); } // OFFSET: 0x00B8E8E0 // FUNCTION: fn_19496 int CNaviInfo::GetCellX() const { return this->cellX; } // OFFSET: 0x00B97750 // FUNCTION: fn_19600 bool CNavigationManager::BuildRoute(int startX, int startY, int destX, int destY, bool collectCells) { this->movementRoute.points.clear(); const bool found = this->pathFinder.FindPath(0, startX, startY, 8, 8, destX, destY, 1, this->movementRoute, 15); this->pathFinder.Reset(); if (!collectCells) { return found; } this->cells.clear(); if (!found) { return found; } CNaviInfo* info = this->FindObject(g_session.m_navigationPlayerMap); if (info == nullptr) { const std::string resolved = ResourceMgr::Instance().aliases.ResolveMapName(g_session.m_navigationPlayerMap); info = this->FindObject(resolved.c_str()); if (info == nullptr) { return found; } } const int height = info->GetCellY(); const int width = info->GetCellX(); int offsetX; int offsetY; const float scale = this->FitToSquare(&offsetX, &offsetY, width, height, 126.0f); for (const MovementRoutePoint& point : this->movementRoute.points) { NaviCell cell; cell.x = static_cast(point.x * scale + offsetX); cell.y = static_cast(126.0f - (point.y * scale + offsetY)); bool exists = false; for (const NaviCell& other : this->cells) { if (other.x == cell.x && other.y == cell.y) { exists = true; break; } } if (!exists) { this->cells.push_back(cell); } } if (g_windowMgr.window_4F174 != nullptr) { g_windowMgr.window_4F174->Invalidate(); } return found; } // OFFSET: 0x00B97E90 // FUNCTION: fn_19603 NaviCell* CNavigationManager::MapCellToView(NaviCell* out, const char* mapName, int cellX, int cellY, float size) { CNaviInfo* info = this->FindObject(mapName); if (info == nullptr) { const std::string resolved = ResourceMgr::Instance().aliases.ResolveMapName(mapName); info = this->FindObject(resolved.c_str()); } out->x = -1; out->y = -1; if (info != nullptr) { const int height = info->GetCellY(); const int width = info->GetCellX(); int offsetX; int offsetY; const float scale = this->FitToSquare(&offsetX, &offsetY, width, height, size); out->x = static_cast(cellX * scale + offsetX); out->y = static_cast(static_cast(size) - (cellY * scale + offsetY)); } return out; } // OFFSET: 0x00B98630 // FUNCTION: fn_19608 std::string CNavigationManager::RouteText() { char buffer[0x32]; std::memset(buffer, 0, sizeof(buffer)); CNaviInfo* info = this->data.GetInfo(); if (info != nullptr) { NaviCell cell; if (this->data.GetCell(&cell)->x > 0) { NaviCell cellY; NaviCell cellX; const int y = this->data.GetCell(&cellY)->y; const int x = this->data.GetCell(&cellX)->x; StringFormat(buffer, sizeof(buffer), static_cast(-1), "[%s] -> %s %d %d", LookupMessage(3585), info->GetName(), x, y); } else { StringFormat(buffer, sizeof(buffer), static_cast(-1), "[%s] %s", LookupMessage(3585), info->GetName()); } } this->routeText.assign(buffer, std::strlen(buffer)); return this->routeText; } // OFFSET: 0x00B8D270 // FUNCTION: fn_19434 bool CNaviInfo::HasName(const char* name) const { return std::strcmp(this->name.c_str(), name) == 0; } // OFFSET: 0x00B97FC0 // FUNCTION: fn_19604 std::string CNavigationManager::SelectedNodeText() { char buffer[0x32]; std::memset(buffer, 0, sizeof(buffer)); if (!this->nodes.empty() && this->selectedNode >= 0) { if (this->nodes.size() <= static_cast(this->selectedNode)) { this->selectedNodeText.assign(buffer, std::strlen(buffer)); return this->selectedNodeText; } CNavi_Object* node = this->nodes[this->selectedNode]; NaviCell cellY; NaviCell cellX; const int y = node->GetCell(&cellY)->y; const int x = node->GetCell(&cellX)->x; std::sprintf(buffer, "%s %d %d...", node->GetInfo()->GetName(), x, y); } else if (this->unknown_1258 == 2) { CNaviInfo* info = this->data.GetInfo(); if (info != nullptr) { NaviCell cellY; NaviCell cellX; const int y = this->data.GetCell(&cellY)->y; const int x = this->data.GetCell(&cellX)->x; std::sprintf(buffer, "%s %d %d...", info->GetName(), x, y); } } this->selectedNodeText.assign(buffer, std::strlen(buffer)); return this->selectedNodeText; } // OFFSET: 0x00B981A0 // FUNCTION: fn_19605 std::string CNavigationManager::SubDestinationText() { char buffer[0x32]; std::memset(buffer, 0, sizeof(buffer)); CNaviInfo* info = this->data.GetInfo(); if (info != nullptr) { NaviCell cell; if (this->data.GetCell(&cell)->x > 0) { NaviCell cellY; NaviCell cellX; const int y = this->data.GetCell(&cellY)->y; const int x = this->data.GetCell(&cellX)->x; std::sprintf(buffer, ">.%s %d %d", info->GetName(), x, y); } else { std::sprintf(buffer, ">.%s", info->GetName()); } } this->subDestinationText.assign(buffer, std::strlen(buffer)); return this->subDestinationText; } // OFFSET: 0x00B982D0 // FUNCTION: fn_19606 std::string CNavigationManager::DestinationText() { char buffer[0x32]; std::memset(buffer, 0, sizeof(buffer)); if (!this->nodes.empty() && this->selectedNode >= 0) { if (this->nodes.size() <= static_cast(this->selectedNode)) { this->destinationText.assign(buffer, std::strlen(buffer)); return this->destinationText; } CNavi_Object* node = this->nodes[this->selectedNode]; NaviCell cellY; NaviCell cellX; const int y = node->GetCell(&cellY)->y; const int x = node->GetCell(&cellX)->x; std::sprintf(buffer, "%s %d %d", node->GetInfo()->GetName(), x, y); } else if (this->unknown_1258 == 2) { CNaviInfo* info = this->data.GetInfo(); if (info != nullptr) { NaviCell cellY; NaviCell cellX; const int y = this->data.GetCell(&cellY)->y; const int x = this->data.GetCell(&cellX)->x; std::sprintf(buffer, "%s %d %d", info->GetName(), x, y); } } this->destinationText.assign(buffer, std::strlen(buffer)); return this->destinationText; } // OFFSET: 0x00B984C0 // FUNCTION: fn_19607 std::string CNavigationManager::DestinationTitle() { char buffer[0x32]; std::memset(buffer, 0, sizeof(buffer)); if (!this->nodes.empty() && this->selectedNode >= 0) { if (this->nodes.size() <= static_cast(this->selectedNode)) { this->destinationTitle.assign(buffer, std::strlen(buffer)); return this->destinationTitle; } this->destinationTitle.assign(this->nodes[this->selectedNode]->GetInfo()->GetTitle()); return this->destinationTitle; } if (this->unknown_1258 == 2) { NaviCell cell; this->data.GetCell(&cell); CNaviInfo* info = this->data.GetInfo(); if (info != nullptr) { this->destinationTitle.assign(info->GetTitle()); return this->destinationTitle; } } this->destinationTitle.assign(buffer, std::strlen(buffer)); return this->destinationTitle; } // OFFSET: 0x00B996D0 // FUNCTION: fn_19613 void CNavigationManager::LoadSettings() { RegistryKey key; std::string subKey(g_subKey); subKey += "\Navigation"; if (key.Open(HKEY_LOCAL_MACHINE, subKey.c_str())) { DWORD viewIcon = 0; if (key.Query("ViewIcon", REG_DWORD, reinterpret_cast(&viewIcon), sizeof(viewIcon))) { this->viewIcon = viewIcon; } } } // OFFSET: 0x00B9C020 // FUNCTION: fn_19618 float CNavigationManager::FitToSquare(int* offsetX, int* offsetY, int width, int height, float size) const { float scale; if (width > height) { scale = size / width; *offsetY = static_cast((width - height) * 0.5f * scale); *offsetX = 0; } else if (width < height) { scale = size / height; *offsetX = static_cast((height - width) * 0.5f * scale); *offsetY = 0; } else { *offsetY = 0; scale = size / width; *offsetX = 0; } return scale; } // OFFSET: 0x00B888F0 // FUNCTION: fn_19378 NaviCell* CNaviData::GetCell(NaviCell* out) { out->x = this->cellX; out->y = this->cellY; return out; } // OFFSET: 0x00B88920 // FUNCTION: fn_19380 CNaviInfo* CNaviData::GetInfo() { return this->info; } // OFFSET: 0x00B88A00 // FUNCTION: fn_45449 void CNaviData::Clear() { this->startLinks.clear(); this->info = nullptr; this->cellX = 0; this->cellY = 0; this->range = 50000; this->endLinks.clear(); for (NaviDataEntry& entry : this->entries) { entry.previous = -1; entry.link = nullptr; entry.cost = 0; } this->entries.clear(); } // OFFSET: 0x00B8CD60 // FUNCTION: fn_19430 CNavi_Object::~CNavi_Object() { this->id = -1; this->type = 101; this->index = -1; this->name.clear(); this->title.clear(); this->cellX = 0; this->cellY = 0; this->info = nullptr; this->links.clear(); } // OFFSET: 0x00B98E40 // FUNCTION: fn_19610 bool CNavigationManager::SavedTargetText(char* out, int size) { if (out == nullptr || this->savedTarget.object == nullptr) { return false; } std::memset(out, 0, size); char text[0x104]; std::memset(text, 0, sizeof(text)); switch (this->savedTarget.type) { case 0: { CNaviInfo* info = static_cast(this->savedTarget.object); NaviCell cellY; NaviCell cellX; const int y = this->data.GetCell(&cellY)->y; const int x = this->data.GetCell(&cellX)->x; std::sprintf(text, "%s %d %d", info->GetName(), x, y); break; } case 1: std::sprintf(text, "%s", static_cast(this->savedTarget.object)->GetName()); break; case 2: { CNavi_Object* object = static_cast(this->savedTarget.object); CNaviInfo* info = object->GetInfo(); NaviCell cellY; NaviCell cellX; const int y = object->GetCell(&cellY)->y; const int x = object->GetCell(&cellX)->x; std::sprintf(text, "%s %d %d", info->GetName(), x, y); break; } case 3: std::sprintf(text, "%s", static_cast(this->savedTarget.object)->GetInfo()->GetName()); break; default: return false; } const int length = static_cast(std::strlen(text)); if (size > length) { std::memcpy(out, text, length); } else { char truncated[0x104]; std::memset(truncated, 0, sizeof(truncated)); std::memcpy(truncated, text, size - 4); std::sprintf(out, "%s...", truncated); } return true; }