diff --git a/Source/Contents/NavigationRoute.cpp b/Source/Contents/NavigationRoute.cpp index 81b86ad2..5e7f473d 100644 --- a/Source/Contents/NavigationRoute.cpp +++ b/Source/Contents/NavigationRoute.cpp @@ -1560,5 +1560,194 @@ struct NavigationReplayHeader { static_assert(sizeof(NavigationReplayHeader) == 6); // OFFSET: 0x00B9B080 +// FUNCTION: fn_19616 +int CNavigationManager::LoadReplayState(const std::vector& data) { + g_windowMgr.CloseWindow(203); + this->Reset(true); + if (data.empty()) { + return -1; + } + + std::vector buffer; + NavigationReplayHeader header; + unsigned offset = 6; + header.Read(data.data()); + if (header.tag != 8000) { + offset = static_cast(-1); + } else { + while (offset < data.size()) { + header.Read(data.data() + offset); + offset += 6; + if (header.tag == 8001) { + this->ResumeRoute(); + break; + } + + switch (header.tag) { + case 8002: + std::memcpy(&this->unknown_127D, data.data() + offset, header.size); + offset += header.size; + break; + case 8003: + std::memcpy(&this->unknown_127E, data.data() + offset, header.size); + offset += header.size; + break; + case 8004: + std::memcpy(&this->unknown_127C, data.data() + offset, header.size); + offset += header.size; + break; + case 8005: + std::memcpy(&this->unknown_1280, data.data() + offset, header.size); + offset += header.size; + break; + case 8006: { + buffer.resize(header.size + 1); + std::memcpy(buffer.data(), data.data() + offset, header.size); + offset += header.size; + NavigationTarget target = this->ReadTarget(buffer.data(), header.size); + if (target.object != nullptr) { + this->states.push_back(target); + } + break; + } + case 8007: + buffer.resize(header.size + 1); + std::memcpy(buffer.data(), data.data() + offset, header.size); + offset += header.size; + this->currentTarget = this->ReadTarget(buffer.data(), header.size); + break; + case 8008: + buffer.resize(header.size + 1); + std::memcpy(buffer.data(), data.data() + offset, header.size); + offset += header.size; + this->savedTarget = this->ReadTarget(buffer.data(), header.size); + break; + case 8009: + std::memcpy(&this->unknown_124C, data.data() + offset, header.size); + offset += header.size; + break; + case 8010: + std::memcpy(&this->unknown_1250, data.data() + offset, header.size); + offset += header.size; + break; + case 8011: + std::memcpy(&this->unknown_1254, data.data() + offset, header.size); + offset += header.size; + break; + case 8012: + std::memcpy(&this->unknown_1258, data.data() + offset, header.size); + offset += header.size; + break; + case 8013: + std::memcpy(&this->unknown_125C, data.data() + offset, header.size); + offset += header.size; + break; + case 8014: + std::memcpy(&this->unknown_1260, data.data() + offset, header.size); + offset += header.size; + break; + case 8015: + buffer.resize(header.size + 1); + std::memcpy(buffer.data(), data.data() + offset, header.size); + offset += header.size; + this->unknown_1264 = buffer.data(); + break; + case 8016: + std::memcpy(&this->unknown_1284, data.data() + offset, header.size); + offset += header.size; + break; + case 8017: + std::memcpy(&this->unknown_117C, data.data() + offset, header.size); + offset += header.size; + break; + case 8018: + std::memcpy(&this->routeResult, data.data() + offset, header.size); + offset += header.size; + break; + case 8019: + std::memcpy(&this->unknown_115C, data.data() + offset, header.size); + offset += header.size; + break; + case 8020: + std::memcpy(&this->selectedNode, data.data() + offset, header.size); + offset += header.size; + break; + case 8021: { + buffer.resize(header.size + 1); + std::memcpy(buffer.data(), data.data() + offset, header.size); + offset += header.size; + const int* route = reinterpret_cast(buffer.data()); + int x = route[2]; + int y = route[3]; + if (this->savedTarget.object != nullptr) { + const int type = this->savedTarget.type; + CNaviInfo* info; + bool found = true; + if (type == 2) { + CNavi_Object* object = static_cast(this->savedTarget.object); + info = object->GetInfo(); + NaviCell cell; + const NaviCell* position = object->GetCell(&cell); + x = position->x; + y = position->y; + } else if (type == 3) { + info = static_cast(this->savedTarget.object)->GetInfo(); + x = -1; + y = -1; + } else if (type == 1) { + x = -1; + y = -1; + info = static_cast(this->savedTarget.object); + } else if (type == 0) { + info = static_cast(this->savedTarget.object); + } else { + found = false; + } + if (found) { + this->data.SetDestination(info, x, y); + } + } + + CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); + if (mode && mode->scene && mode->scene->terrain) { + this->ground = mode->scene->ground; + this->pathFinder.attr = mode->scene->terrain; + } + break; + } + case 8022: { + buffer.resize(header.size + 1); + std::memcpy(buffer.data(), data.data() + offset, header.size); + offset += header.size; + CNavi_Link* node = this->ReadObject(buffer.data()); + if (node != nullptr) { + this->nodes.push_back(node); + } + break; + } + case 8023: + std::memcpy(&this->unknown_1248, data.data() + offset, header.size); + offset += header.size; + break; + default: + offset += header.size; + break; + } + } + } + return static_cast(offset); +} // OFFSET: 0x00B9BFC0 +// FUNCTION: fn_19617 +void CNavigationManager::ResumeRoute() { + if (this->unknown_1258 == 1) { + this->LoadTargetPreview(); + g_windowMgr.EnsureWindow(203); + } else if (this->unknown_1258 == 2) { + this->ShowRouteResult(this->RouteFromPlayer(), 1, *reinterpret_cast(&g_windowMgr)); + if (!this->unknown_1248) { + g_windowMgr.EnsureWindow(203); + } + } +} diff --git a/Source/Contents/NavigationSource.cpp b/Source/Contents/NavigationSource.cpp index a80f7da3..fa322eef 100644 --- a/Source/Contents/NavigationSource.cpp +++ b/Source/Contents/NavigationSource.cpp @@ -614,6 +614,153 @@ void CNavigationManager::ClearCurrentObject() { } // OFFSET: 0x00B95280 +// FUNCTION: fn_19573 +int CNavigationManager::RouteFromPlayer() { + 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) { + this->unknown_117C = false; + this->unknown_115C = false; + this->unknown_12B4 = false; + return -93; + } + } + + int result = -96; + this->unknown_117C = false; + this->unknown_115C = false; + this->unknown_12B4 = false; + NaviCell player; + player.x = 0; + player.y = 0; + if (CGameMode* mode = static_cast(g_modeMgr.GetGameMode())) { + mode->PlayerCell(&player.x, &player.y); + } + + if (this->data.GetInfo() == info) { + const int type = this->savedTarget.type; + if (type != 2 && type != 0) { + int code = type == 1 ? 6 : -96; + if (type == 3) { + code = 8; + } + this->CancelRoute(); + return code; + } + + NaviCell cell; + if (player.x == this->data.GetCell(&cell)->x && player.y == this->data.GetCell(&cell)->y) { + this->movementRoute.points.clear(); + PathCell point = {player.x, player.y, 0, 0}; + this->movementRoute.points.push_back(point); + this->CancelRoute(); + return 11; + } + + NaviCell destination; + if (this->BuildRoute(player.x, player.y, this->data.GetCell(&destination)->x, this->data.GetCell(&cell)->y, true)) { + this->nodes.clear(); + this->routeResult = std::abs(player.x - this->data.GetCell(&destination)->x) + std::abs(player.y - this->data.GetCell(&cell)->y); + this->selectedNode = -1; + this->currentTarget = this->savedTarget; + this->LoadTargetPreview(); + const int targetType = this->savedTarget.type; + result = targetType == 2 ? 7 : -96; + this->unknown_117C = true; + this->unknown_115C = true; + this->unknown_12B4 = true; + if (targetType == 0) { + result = 9; + this->unknown_1258 = 2; + return result; + } + if (targetType == 2) { + this->unknown_1258 = 2; + return result; + } + } + } + + const NaviCell start = player; + if (this->nodes.empty() || info == nullptr) { + return result; + } + + CGameMode* mode = static_cast(g_modeMgr.GetGameMode()); + if (mode && mode->scene && mode->scene->terrain) { + this->ground = mode->scene->ground; + this->pathFinder.attr = mode->scene->terrain; + } + + { + std::vector candidates; + for (int index = static_cast(this->nodes.size()) - 1; index > 0; --index) { + if (this->nodes[index]->GetInfo() != info) { + continue; + } + + const NaviCell linked = this->nodes[index - 1]->GetLinkedCell(); + if (linked.x == start.x && linked.y == start.y) { + NaviCell cellX; + NaviCell cellY; + if (this->BuildRoute(start.x, start.y, this->nodes[index]->GetCell(&cellX)->x, this->nodes[index]->GetCell(&cellY)->y, true)) { + this->selectedNode = index; + this->SelectTarget(index); + this->unknown_117C = true; + goto selected; + } + } else { + candidates.push_back(index); + } + } + + if (this->nodes[0]->GetInfo() == info) { + this->movementRoute.points.clear(); + NaviCell cellX; + NaviCell cellY; + if (start.x == this->nodes[0]->GetCell(&cellX)->x && start.y == this->nodes[0]->GetCell(&cellY)->y) { + PathCell point = {start.x, start.y, 0, 0}; + this->movementRoute.points.push_back(point); + } else if (!this->BuildRoute(start.x, start.y, this->nodes[0]->GetCell(&cellX)->x, this->nodes[0]->GetCell(&cellY)->y, true)) { + goto search; + } + this->selectedNode = 0; + this->SelectTarget(0); + this->unknown_117C = true; + goto selected; + } + + search: + for (int index = 0; index < static_cast(candidates.size()); ++index) { + NaviCell cellX; + NaviCell cellY; + if (this->BuildRoute(start.x, start.y, this->nodes[candidates[index]]->GetCell(&cellX)->x, this->nodes[candidates[index]]->GetCell(&cellY)->y, true)) { + this->selectedNode = candidates[index]; + this->SelectTarget(candidates[index]); + this->unknown_117C = true; + goto selected; + } + } + + this->unknown_117C = false; + if (this->nodes[0]->GetType() != 400) { + return result; + } + this->selectedNode = 0; + this->SelectTarget(0); + } + +selected: + if (this->selectedNode == 0 && this->nodes[0]->GetType() == 400) { + result = 4; + } else { + result = 5; + } + this->unknown_1258 = 2; + return result; +} // OFFSET: 0x00B95AD0 // FUNCTION: fn_19576