diff --git a/common/base_packet.h b/common/base_packet.h index 16a527ade..875adf343 100644 --- a/common/base_packet.h +++ b/common/base_packet.h @@ -63,7 +63,7 @@ public: void WriteFloat(float value) { *(float *)(pBuffer + _wpos) = value; _wpos += sizeof(float); } void WriteDouble(double value) { *(double *)(pBuffer + _wpos) = value; _wpos += sizeof(double); } void WriteString(const char * str) { uint32 len = static_cast(strlen(str)) + 1; memcpy(pBuffer + _wpos, str, len); _wpos += len; } - void WriteData(const void *ptr, size_t n) { memcpy(pBuffer + _wpos, ptr, n); _wpos += n; } + void WriteData(const void *ptr, size_t n) { memcpy(pBuffer + _wpos, ptr, n); _wpos += (uint32)n; } uint8 ReadUInt8() { uint8 value = *(uint8 *)(pBuffer + _rpos); _rpos += sizeof(uint8); return value; } uint8 ReadUInt8(uint32 Offset) const { uint8 value = *(uint8 *)(pBuffer + Offset); return value; } diff --git a/common/pathfind.cpp b/common/pathfind.cpp index b544342d4..26c5c7f22 100644 --- a/common/pathfind.cpp +++ b/common/pathfind.cpp @@ -1,13 +1,34 @@ #include "pathfind.h" +#include "random.h" + #include -#include const uint32_t nav_mesh_file_version = 1; const float max_dest_drift = 10.0f; +const float at_waypoint_eps = 1.0f; +EQEmu::Random path_rng; + +float vec_dist(const glm::vec3 &a, const glm::vec3 &b) { + float dist_x = a.x - b.x; + float dist_y = a.y - b.y; + float dist_z = a.z - b.z; + return sqrt((dist_x * dist_x) + (dist_y * dist_y) + (dist_z * dist_z)); +} PathfindingManager::PathfindingManager() { m_nav_mesh = nullptr; + m_nav_query = nullptr; + m_filter.setIncludeFlags(NavigationPolyFlagAll); + m_filter.setAreaCost(NavigationAreaFlagNormal, 1.0f); + m_filter.setAreaCost(NavigationAreaFlagWater, 2.5f); + m_filter.setAreaCost(NavigationAreaFlagLava, 2.5f); + m_filter.setAreaCost(NavigationAreaFlagPvP, 1.0f); + m_filter.setAreaCost(NavigationAreaFlagSlime, 1.0f); + m_filter.setAreaCost(NavigationAreaFlagIce, 1.0f); + m_filter.setAreaCost(NavigationAreaFlagVWater, 2.5f); + m_filter.setAreaCost(NavigationAreaFlagGeneralArea, 1.0f); + m_filter.setAreaCost(NavigationAreaFlagPortal, 1.0f); } PathfindingManager::~PathfindingManager() @@ -17,6 +38,8 @@ PathfindingManager::~PathfindingManager() void PathfindingManager::Load(const std::string &zone_name) { + Clear(); + std::string filename = MAP_DIR + std::string("/") + zone_name + ".nav"; FILE *f = fopen(filename.c_str(), "rb"); if (f) { @@ -109,6 +132,11 @@ void PathfindingManager::Clear() dtFreeNavMesh(m_nav_mesh); m_nav_mesh = nullptr; } + + if (m_nav_query) { + dtFreeNavMeshQuery(m_nav_query); + m_nav_query = nullptr; + } } PathfindingRoute PathfindingManager::FindRoute(const glm::vec3 &src_loc, const glm::vec3 &dest_loc) @@ -117,8 +145,10 @@ PathfindingRoute PathfindingManager::FindRoute(const glm::vec3 &src_loc, const g glm::vec3 dest_location(dest_loc.x, dest_loc.z, dest_loc.y); PathfindingRoute ret; - ret.m_dest = dest_location; + + ret.m_dest = dest_loc; ret.m_current_node = 0; + ret.m_active = true; if (!m_nav_mesh) { PathfindingNode src; @@ -134,30 +164,19 @@ PathfindingRoute PathfindingManager::FindRoute(const glm::vec3 &src_loc, const g return ret; } - glm::vec3 ext(5.0f, 5.0f, 5.0f); - dtQueryFilter filter; - filter.setIncludeFlags(NavigationPolyFlagAll); - filter.setAreaCost(NavigationAreaFlagNormal, 1.0f); - filter.setAreaCost(NavigationAreaFlagWater, 2.5f); - filter.setAreaCost(NavigationAreaFlagLava, 2.5f); - filter.setAreaCost(NavigationAreaFlagPvP, 1.0f); - filter.setAreaCost(NavigationAreaFlagSlime, 1.0f); - filter.setAreaCost(NavigationAreaFlagIce, 1.0f); - filter.setAreaCost(NavigationAreaFlagVWater, 2.5f); - filter.setAreaCost(NavigationAreaFlagGeneralArea, 1.0f); - filter.setAreaCost(NavigationAreaFlagPortal, 1.0f); + if (!m_nav_query) { + m_nav_query = dtAllocNavMeshQuery(); + m_nav_query->init(m_nav_mesh, 4092); + } - dtNavMeshQuery *query = dtAllocNavMeshQuery(); - query->init(m_nav_mesh, 4092); dtPolyRef start_ref; dtPolyRef end_ref; + glm::vec3 ext(10.0f, 10.0f, 10.0f); - query->findNearestPoly(¤t_location[0], &ext[0], &filter, &start_ref, 0); - query->findNearestPoly(&dest_location[0], &ext[0], &filter, &end_ref, 0); + m_nav_query->findNearestPoly(¤t_location[0], &ext[0], &m_filter, &start_ref, 0); + m_nav_query->findNearestPoly(&dest_location[0], &ext[0], &m_filter, &end_ref, 0); if (!start_ref || !end_ref) { - dtFreeNavMeshQuery(query); - PathfindingNode src; src.flag = NavigationPolyFlagNormal; src.position = current_location; @@ -173,23 +192,21 @@ PathfindingRoute PathfindingManager::FindRoute(const glm::vec3 &src_loc, const g int npoly = 0; dtPolyRef path[256] = { 0 }; - query->findPath(start_ref, end_ref, ¤t_location[0], &dest_location[0], &filter, path, &npoly, 256); + m_nav_query->findPath(start_ref, end_ref, ¤t_location[0], &dest_location[0], &m_filter, path, &npoly, 256); if (npoly) { glm::vec3 epos = dest_location; if (path[npoly - 1] != end_ref) - query->closestPointOnPoly(path[npoly - 1], &dest_location[0], &epos[0], 0); + m_nav_query->closestPointOnPoly(path[npoly - 1], &dest_location[0], &epos[0], 0); float straight_path[256 * 3]; unsigned char straight_path_flags[256]; int n_straight_polys; dtPolyRef straight_path_polys[256]; - query->findStraightPath(¤t_location[0], &epos[0], path, npoly, + m_nav_query->findStraightPath(¤t_location[0], &epos[0], path, npoly, straight_path, straight_path_flags, straight_path_polys, &n_straight_polys, 256, DT_STRAIGHTPATH_ALL_CROSSINGS); - dtFreeNavMeshQuery(query); - if (n_straight_polys) { ret.m_nodes.reserve(n_straight_polys); for (int i = 0; i < n_straight_polys; ++i) @@ -222,17 +239,52 @@ PathfindingRoute PathfindingManager::FindRoute(const glm::vec3 &src_loc, const g return ret; } +bool PathfindingManager::GetRandomPoint(const glm::vec3 &start, float radius, glm::vec3 &pos) +{ + if(!m_nav_mesh) + return false; + + if (!m_nav_query) { + m_nav_query = dtAllocNavMeshQuery(); + m_nav_query->init(m_nav_mesh, 4092); + } + + glm::vec3 ext(10.0f, 10.0f, 10.0f); + dtPolyRef start_ref; + m_nav_query->findNearestPoly(&start[0], &ext[0], &m_filter, &start_ref, 0); + if (!start_ref) { + return false; + } + + dtPolyRef random_ref; + glm::vec3 pt; + + dtStatus status = m_nav_query->findRandomPointAroundCircle(start_ref, &start[0], radius, + &m_filter, []() -> float { return (float)path_rng.Real(0.0, 1.0); }, &random_ref, &pt[0]); + + if (dtStatusSucceed(status)) + { + pos.x = pt.x; + pos.z = pt.y; + pos.y = pt.z; + return true; + } + + return false; +} + PathfindingRoute::PathfindingRoute() { + m_active = false; } PathfindingRoute::~PathfindingRoute() { } -bool PathfindingRoute::Valid(const glm::vec3 &dest) +bool PathfindingRoute::DestinationValid(const glm::vec3 &dest) { - auto dist = (dest - m_dest).length(); + auto dist = vec_dist(dest, m_dest); if (dist <= max_dest_drift) { return true; } @@ -240,11 +292,29 @@ bool PathfindingRoute::Valid(const glm::vec3 &dest) return false; } -void PathfindingRoute::CalcCurrentNode() +void PathfindingRoute::CalcCurrentNode(const glm::vec3 ¤t_pos, bool &wp_changed) { - //if we're at last node then we dont need to do anything. + wp_changed = false; + if (m_active) { + //if we're at last node then we dont need to do anything. + if (m_nodes.size() - 1 == m_current_node) { + return; + } - //else need to see if we're at current_node - //if so then we advance to the next node and return it - //else just return the current node + auto ¤t = GetCurrentNode(); + auto dist = vec_dist(current.position, current_pos); + if (dist < at_waypoint_eps) { + m_current_node++; + wp_changed = true; + } + } } + +unsigned short PathfindingRoute::GetPreviousNodeFlag() +{ + if(m_current_node == 0) + return 0; + + return m_nodes[m_current_node - 1].flag; +} + diff --git a/common/pathfind.h b/common/pathfind.h index 1292b94ea..e037b388c 100644 --- a/common/pathfind.h +++ b/common/pathfind.h @@ -3,6 +3,7 @@ #include #include #include +#include #include enum NavigationAreaFlags @@ -48,15 +49,18 @@ public: PathfindingRoute(); ~PathfindingRoute(); - bool Valid(const glm::vec3 &dest); - void CalcCurrentNode(); + bool Active() const { return m_active; } + bool PathfindingRoute::DestinationValid(const glm::vec3 &dest); + void CalcCurrentNode(const glm::vec3 ¤t_pos, bool &wp_changed); const PathfindingNode& GetCurrentNode() { return m_nodes[m_current_node]; } + unsigned short GetPreviousNodeFlag(); const std::vector& GetNodes() const { return m_nodes; } std::vector& GetNodesEdit() { return m_nodes; } private: glm::vec3 m_dest; std::vector m_nodes; int m_current_node; + bool m_active; friend class PathfindingManager; }; @@ -72,6 +76,9 @@ public: //Expects locations in EQEmu internal format eg what #loc returns not what /loc returns. PathfindingRoute FindRoute(const glm::vec3 ¤t_location, const glm::vec3 &dest_location); + bool GetRandomPoint(const glm::vec3 &start, float radius, glm::vec3 &pos); private: dtNavMesh *m_nav_mesh; + dtNavMeshQuery *m_nav_query; + dtQueryFilter m_filter; }; diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index bf510a921..e84931d7a 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -183,7 +183,6 @@ SET(zone_headers npc_ai.h object.h oriented_bounding_box.h - pathing.h perlpacket.h petitions.h pets.h diff --git a/zone/client.h b/zone/client.h index 6a405b802..159f26fdb 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1256,7 +1256,7 @@ public: bool InterrogateInventory(Client* requester, bool log, bool silent, bool allowtrip, bool& error, bool autolog = true); void SetNextInvSnapshot(uint32 interval_in_min) { - m_epp.last_invsnapshot_time = time(nullptr); + m_epp.last_invsnapshot_time = (uint32)time(nullptr); m_epp.next_invsnapshot_time = m_epp.last_invsnapshot_time + (interval_in_min * 60); } uint32 GetLastInvSnapshotTime() { return m_epp.last_invsnapshot_time; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 6ff5d522f..456012360 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -5630,7 +5630,7 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app) } glm::vec3 dest(target->GetX(), target->GetY(), target->GetZ()); - auto route = zone->pathing_new.FindRoute(glm::vec3(GetX(), GetY(), GetZ()), dest); + auto route = zone->pathing.FindRoute(glm::vec3(GetX(), GetY(), GetZ()), dest); CreatePathFromRoute(dest, route); } } diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 5bd61d344..3b973e7b7 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -236,8 +236,8 @@ bool Client::Process() { CheckMercSuspendTimer(); } - //if(IsAIControlled()) - //AI_Process(); + if(IsAIControlled()) + AI_Process(); // Don't reset the bindwound timer so we can check it in BindWound as well. if (bindwound_timer.Check(false) && bindwound_target != 0) { diff --git a/zone/command.cpp b/zone/command.cpp index 09cf9ac59..46a540789 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -58,7 +58,6 @@ #include "command.h" #include "guild_mgr.h" #include "map.h" -#include "pathing.h" #include "qglobals.h" #include "queryserv.h" #include "quest_parser_collection.h" diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index bf43e43a1..3114221db 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -1930,52 +1930,6 @@ XS(XS__repopzone) XSRETURN_EMPTY; } -XS(XS__ConnectNodeToNode); -XS(XS__ConnectNodeToNode) -{ - dXSARGS; - if (items != 4) - Perl_croak(aTHX_ "Usage: ConnectNodeToNode(node1, node2, teleport, doorid)"); - - int node1 = (int)SvIV(ST(0)); - int node2 = (int)SvIV(ST(1)); - int teleport = (int)SvIV(ST(2)); - int doorid = (int)SvIV(ST(3)); - - quest_manager.ConnectNodeToNode(node1, node2, teleport, doorid); - - XSRETURN_EMPTY; -} - -XS(XS__AddNode); -XS(XS__AddNode) -{ - dXSARGS; - //void QuestManager::AddNode(float x, float y, float z, float best_z, int32 requested_id); - if (items < 3 || items > 5) - Perl_croak(aTHX_ "Usage: AddNode(x, y, z, [best_z], [requested_id])"); - - int x = (int)SvIV(ST(0)); - int y = (int)SvIV(ST(1)); - int z = (int)SvIV(ST(2)); - int best_z = 0; - int requested_id = 0; - - if (items == 4) - { - best_z = (int)SvIV(ST(3)); - } - else if (items == 5) - { - best_z = (int)SvIV(ST(3)); - requested_id = (int)SvIV(ST(4)); - } - - quest_manager.AddNode(x, y, z, best_z, requested_id); - - XSRETURN_EMPTY; -} - XS(XS__npcrace); XS(XS__npcrace) { @@ -3818,8 +3772,6 @@ EXTERN_C XS(boot_quest) newXS(strcpy(buf, "reloadzonestaticdata"), XS__reloadzonestaticdata, file); newXS(strcpy(buf, "removetitle"), XS__removetitle, file); newXS(strcpy(buf, "repopzone"), XS__repopzone, file); - newXS(strcpy(buf, "ConnectNodeToNode"), XS__ConnectNodeToNode, file); - newXS(strcpy(buf, "AddNode"), XS__AddNode, file); newXS(strcpy(buf, "resettaskactivity"), XS__resettaskactivity, file); newXS(strcpy(buf, "respawn"), XS__respawn, file); newXS(strcpy(buf, "resume"), XS__resume, file); diff --git a/zone/entity.cpp b/zone/entity.cpp index 92fefb2ec..84682acf5 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2691,26 +2691,6 @@ void EntityList::ListPlayerCorpses(Client *client) client->Message(0, "%d player corpses listed.", x); } -void EntityList::FindPathsToAllNPCs() -{ - if (!zone->pathing) - return; - - auto it = npc_list.begin(); - while (it != npc_list.end()) { - glm::vec3 Node0 = zone->pathing->GetPathNodeCoordinates(0, false); - glm::vec3 Dest(it->second->GetX(), it->second->GetY(), it->second->GetZ()); - std::deque Route = zone->pathing->FindRoute(Node0, Dest); - if (Route.size() == 0) - printf("Unable to find a route to %s\n", it->second->GetName()); - else - printf("Found a route to %s\n", it->second->GetName()); - ++it; - } - - fflush(stdout); -} - // returns the number of corpses deleted. A negative number indicates an error code. int32 EntityList::DeleteNPCCorpses() { diff --git a/zone/entity.h b/zone/entity.h index 0b9521179..8ef0a5d1c 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -350,7 +350,6 @@ public: void ListNPCs(Client* client, const char* arg1 = 0, const char* arg2 = 0, uint8 searchtype = 0); void ListNPCCorpses(Client* client); void ListPlayerCorpses(Client* client); - void FindPathsToAllNPCs(); int32 DeleteNPCCorpses(); int32 DeletePlayerCorpses(); void WriteEntityIDs(); diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index bbcf4d4c6..adaad8ff3 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -19,7 +19,6 @@ #include "../common/rulesys.h" #include "map.h" -#include "pathing.h" #include "zone.h" #ifdef _WINDOWS @@ -46,7 +45,7 @@ void Mob::CheckFlee() { //see if were possibly hurt enough float ratio = GetHPRatio(); - float fleeratio = GetSpecialAbility(FLEE_PERCENT); + float fleeratio = (float)GetSpecialAbility(FLEE_PERCENT); fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio); if(ratio >= fleeratio) @@ -106,7 +105,7 @@ void Mob::ProcessFlee() } //see if we are still dying, if so, do nothing - float fleeratio = GetSpecialAbility(FLEE_PERCENT); + float fleeratio = (float)GetSpecialAbility(FLEE_PERCENT); fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio); if (GetHPRatio() < fleeratio) return; @@ -125,28 +124,11 @@ void Mob::ProcessFlee() void Mob::CalculateNewFearpoint() { - if(RuleB(Pathing, Fear) && zone->pathing) - { - int Node = zone->pathing->GetRandomPathNode(); - - glm::vec3 Loc = zone->pathing->GetPathNodeCoordinates(Node); - - ++Loc.z; - - glm::vec3 CurrentPosition(GetX(), GetY(), GetZ()); - - std::deque Route = zone->pathing->FindRoute(CurrentPosition, Loc); - - if(Route.size() > 0) - { - m_FearWalkTarget = glm::vec3(Loc.x, Loc.y, Loc.z); - currently_fleeing = true; - - Log.Out(Logs::Detail, Logs::None, "Feared to node %i (%8.3f, %8.3f, %8.3f)", Node, Loc.x, Loc.y, Loc.z); - return; - } - - Log.Out(Logs::Detail, Logs::None, "No path found to selected node. Falling through to old fear point selection."); + glm::vec3 pos; + if (zone->pathing.GetRandomPoint(glm::vec3(GetX(), GetY(), GetZ()), 500.0f, pos)) { + currently_fleeing = true; + m_FearWalkTarget = pos; + return; } int loop = 0; @@ -168,6 +150,7 @@ void Mob::CalculateNewFearpoint() break; } } + if (currently_fleeing) m_FearWalkTarget = glm::vec3(ranx, rany, ranz); else //Break fear diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 1e785ce9b..239043add 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -1049,12 +1049,12 @@ void Lua_Client::IncrementAA(int aa) { bool Lua_Client::GrantAlternateAdvancementAbility(int aa_id, int points) { Lua_Safe_Call_Bool(); - self->GrantAlternateAdvancementAbility(aa_id, points); + return self->GrantAlternateAdvancementAbility(aa_id, points); } bool Lua_Client::GrantAlternateAdvancementAbility(int aa_id, int points, bool ignore_cost) { Lua_Safe_Call_Bool(); - self->GrantAlternateAdvancementAbility(aa_id, points, ignore_cost); + return self->GrantAlternateAdvancementAbility(aa_id, points, ignore_cost); } void Lua_Client::MarkSingleCompassLoc(float in_x, float in_y, float in_z) { diff --git a/zone/map.cpp b/zone/map.cpp index 37f394626..1d2b4c7ee 100644 --- a/zone/map.cpp +++ b/zone/map.cpp @@ -873,7 +873,7 @@ bool Map::LoadV2(FILE *f) { } } - uint32 face_count = indices.size() / 3; + uint32 face_count = (uint32)indices.size() / 3; if (imp) { imp->rm->release(); diff --git a/zone/merc.cpp b/zone/merc.cpp index 30bac4703..b4125735e 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -1304,7 +1304,7 @@ bool Merc::Process() return true; // Merc AI - //AI_Process(); + AI_Process(); return true; } diff --git a/zone/mob.cpp b/zone/mob.cpp index e28ccefcc..de15456f1 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -415,15 +415,8 @@ Mob::Mob(const char* in_name, m_TargetRing = glm::vec3(); flymode = FlyMode3; - // Pathing - PathingLOSState = UnknownLOS; - PathingLoopCount = 0; - PathingLastNodeVisited = -1; - PathingLOSCheckTimer = new Timer(RuleI(Pathing, LOSCheckFrequency)); - PathingRouteUpdateTimerShort = new Timer(RuleI(Pathing, RouteUpdateFrequencyShort)); - PathingRouteUpdateTimerLong = new Timer(RuleI(Pathing, RouteUpdateFrequencyLong)); + DistractedFromGrid = false; - PathingTraversedNodes = 0; hate_list.SetHateOwner(this); m_AllowBeneficial = false; @@ -469,9 +462,6 @@ Mob::~Mob() entity_list.DestroyTempPets(this); } entity_list.UnMarkNPC(GetID()); - safe_delete(PathingLOSCheckTimer); - safe_delete(PathingRouteUpdateTimerShort); - safe_delete(PathingRouteUpdateTimerLong); UninitializeBuffSlots(); } @@ -1564,8 +1554,7 @@ void Mob::ShowBuffList(Client* client) { } void Mob::GMMove(float x, float y, float z, float heading, bool SendUpdate) { - - Route.clear(); + m_pathing_route = PathfindingRoute(); if(IsNPC()) { entity_list.ProcessMove(CastToNPC(), x, y, z); diff --git a/zone/mob.h b/zone/mob.h index 334c81e51..f58cc4640 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -18,10 +18,10 @@ #ifndef MOB_H #define MOB_H +#include "../common/pathfind.h" #include "common.h" #include "entity.h" #include "hate_list.h" -#include "pathing.h" #include "position.h" #include "aa_ability.h" #include "aa.h" @@ -473,7 +473,7 @@ public: int GetBaseRunspeed() const { return base_runspeed; } int GetBaseWalkspeed() const { return base_walkspeed; } int GetBaseFearSpeed() const { return base_fearspeed; } - float GetMovespeed() const { return IsRunning() ? GetRunspeed() : GetWalkspeed(); } + float GetMovespeed() const { return IsRunning() ? (float)GetRunspeed() : (float)GetWalkspeed(); } bool IsRunning() const { return m_is_running; } void SetRunning(bool val) { m_is_running = val; } virtual void GMMove(float x, float y, float z, float heading = 0.01, bool SendUpdate = true); @@ -1141,8 +1141,8 @@ protected: virtual int16 GetFocusEffect(focusType type, uint16 spell_id) { return 0; } void CalculateNewFearpoint(); float FindGroundZ(float new_x, float new_y, float z_offset=0.0); - glm::vec3 UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached); - void PrintRoute(); + glm::vec3 UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange); + void TrySnapToMap(); virtual float GetSympatheticProcChances(uint16 spell_id, int16 ProcRateMod, int32 ItemProcRate = 0); int16 GetSympatheticSpellProcRate(uint16 spell_id); @@ -1313,19 +1313,8 @@ protected: glm::vec3 m_FearWalkTarget; bool currently_fleeing; - // Pathing - // - glm::vec3 PathingDestination; - glm::vec3 PathingLastPosition; - int PathingLoopCount; - int PathingLastNodeVisited; - std::deque Route; - LOSType PathingLOSState; - Timer *PathingLOSCheckTimer; - Timer *PathingRouteUpdateTimerShort; - Timer *PathingRouteUpdateTimerLong; + PathfindingRoute m_pathing_route; bool DistractedFromGrid; - int PathingTraversedNodes; uint32 pDontHealMeBefore; uint32 pDontBuffMeBefore; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 79c4493ea..b0173361b 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -586,10 +586,6 @@ void Client::AI_Stop() { // only call this on a zone shutdown event void Mob::AI_ShutDown() { - safe_delete(PathingLOSCheckTimer); - safe_delete(PathingRouteUpdateTimerShort); - safe_delete(PathingRouteUpdateTimerLong); - attack_timer.Disable(); attack_dw_timer.Disable(); ranged_timer.Disable(); @@ -787,20 +783,12 @@ void Client::AI_Process() // Calculate a new point to run to CalculateNewFearpoint(); } - if(!RuleB(Pathing, Fear) || !zone->pathing) - CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, speed, true); - else - { - bool WaypointChanged, NodeReached; - glm::vec3 Goal = UpdatePath(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, - speed, WaypointChanged, NodeReached); + bool WaypointChanged; + glm::vec3 Goal = UpdatePath(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, + speed, WaypointChanged); - if(WaypointChanged) - tar_ndx = 20; - - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed); - } + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed); } return; } @@ -869,19 +857,12 @@ void Client::AI_Process() animation = newspeed; newspeed *= 2; SetCurrentSpeed(newspeed); - if(!RuleB(Pathing, Aggro) || !zone->pathing) - CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), newspeed); - else - { - bool WaypointChanged, NodeReached; - glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), - GetRunspeed(), WaypointChanged, NodeReached); + + bool WaypointChanged; + glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), + GetRunspeed(), WaypointChanged); - if(WaypointChanged) - tar_ndx = 20; - - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, newspeed); - } + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, newspeed); } } else if(IsMoving()) @@ -980,22 +961,13 @@ void Mob::AI_Process() { // Calculate a new point to run to CalculateNewFearpoint(); } - if(!RuleB(Pathing, Fear) || !zone->pathing) - { - CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true); - } - else - { - bool WaypointChanged, NodeReached; + + bool WaypointChanged; - glm::vec3 Goal = UpdatePath(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, - GetFearSpeed(), WaypointChanged, NodeReached); + glm::vec3 Goal = UpdatePath(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, + GetFearSpeed(), WaypointChanged); - if(WaypointChanged) - tar_ndx = 20; - - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetFearSpeed()); - } + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetFearSpeed()); } return; } @@ -1299,20 +1271,13 @@ void Mob::AI_Process() { { if(!IsRooted()) { Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName()); - if(!RuleB(Pathing, Aggro) || !zone->pathing) - CalculateNewPosition2(target->GetX(), target->GetY(), target->GetZ(), GetRunspeed()); - else - { - bool WaypointChanged, NodeReached; - glm::vec3 Goal = UpdatePath(target->GetX(), target->GetY(), target->GetZ(), - GetRunspeed(), WaypointChanged, NodeReached); + bool WaypointChanged; - if(WaypointChanged) - tar_ndx = 20; + glm::vec3 Goal = UpdatePath(target->GetX(), target->GetY(), target->GetZ(), + GetRunspeed(), WaypointChanged); - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed()); - } + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed()); } else if(IsMoving()) { @@ -1588,18 +1553,15 @@ void NPC::AI_DoMovement() { } if (doMove) { // not at waypoint yet or at 0 pause WP, so keep moving - if(!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0)) + if(DistractedFromGrid == 0) CalculateNewPosition2(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true); else { bool WaypointChanged; - bool NodeReached; - glm::vec3 Goal = UpdatePath(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, WaypointChanged, NodeReached); - if(WaypointChanged) - tar_ndx = 20; - - if(NodeReached) + glm::vec3 Goal = UpdatePath(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, WaypointChanged); + if (WaypointChanged) { entity_list.OpenDoorsNear(CastToNPC()); + } CalculateNewPosition2(Goal.x, Goal.y, Goal.z, walksp, true); } @@ -1625,26 +1587,19 @@ void NPC::AI_DoMovement() { else if (IsGuarding()) { bool CP2Moved; - if(!RuleB(Pathing, Guard) || !zone->pathing) - CP2Moved = CalculateNewPosition2(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, walksp); - else + if(!((m_Position.x == m_GuardPoint.x) && (m_Position.y == m_GuardPoint.y) && (m_Position.z == m_GuardPoint.z))) { - if(!((m_Position.x == m_GuardPoint.x) && (m_Position.y == m_GuardPoint.y) && (m_Position.z == m_GuardPoint.z))) - { - bool WaypointChanged, NodeReached; - glm::vec3 Goal = UpdatePath(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, walksp, WaypointChanged, NodeReached); - if(WaypointChanged) - tar_ndx = 20; - - if(NodeReached) - entity_list.OpenDoorsNear(CastToNPC()); - - CP2Moved = CalculateNewPosition2(Goal.x, Goal.y, Goal.z, walksp); + bool WaypointChanged; + glm::vec3 Goal = UpdatePath(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, walksp, WaypointChanged); + if (WaypointChanged) { + entity_list.OpenDoorsNear(CastToNPC()); } - else - CP2Moved = false; + CP2Moved = CalculateNewPosition2(Goal.x, Goal.y, Goal.z, walksp); } + else + CP2Moved = false; + if (!CP2Moved) { if(moved) { diff --git a/zone/npc.cpp b/zone/npc.cpp index c85cc2c0f..22e4b4b0d 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -734,7 +734,7 @@ bool NPC::Process() } } - //AI_Process(); + AI_Process(); return true; } diff --git a/zone/pathing.cpp b/zone/pathing.cpp index 9d642097b..9ba55a57c 100644 --- a/zone/pathing.cpp +++ b/zone/pathing.cpp @@ -2,2250 +2,75 @@ #include "client.h" #include "doors.h" -#include "pathing.h" #include "water_map.h" #include "zone.h" - -#include -#include #include -#include -#include -#ifdef _WINDOWS -#define snprintf _snprintf -#endif - -//#define PATHDEBUG - -extern Zone *zone; - -float VectorDistance(glm::vec3 a, glm::vec3 b) -{ - float xdist = a.x - b.x; - float ydist = a.y - b.y; - float zdist = a.z - b.z; - return sqrtf(xdist * xdist + ydist * ydist + zdist * zdist); -} - -float VectorDistanceNoRoot(glm::vec3 a, glm::vec3 b) -{ - float xdist = a.x - b.x; - float ydist = a.y - b.y; - float zdist = a.z - b.z; - return xdist * xdist + ydist * ydist + zdist * zdist; - -} - -PathManager* PathManager::LoadPathFile(const char* ZoneName) -{ - - FILE *PathFile = nullptr; - - char LowerCaseZoneName[64]; - - char ZonePathFileName[256]; - - PathManager* Ret = nullptr; - - strn0cpy(LowerCaseZoneName, ZoneName, 64); - - strlwr(LowerCaseZoneName); - - snprintf(ZonePathFileName, 250, MAP_DIR "/%s.path", LowerCaseZoneName); - - if((PathFile = fopen(ZonePathFileName, "rb"))) - { - Ret = new PathManager(); - - if(Ret->loadPaths(PathFile)) - { - Log.Out(Logs::General, Logs::Status, "Path File %s loaded.", ZonePathFileName); - - } - else - { - Log.Out(Logs::General, Logs::Error, "Path File %s failed to load.", ZonePathFileName); - safe_delete(Ret); - } - fclose(PathFile); - } - else - { - Log.Out(Logs::General, Logs::Error, "Path File %s not found.", ZonePathFileName); - } - - return Ret; -} - -PathManager::PathManager() -{ - PathNodes = nullptr; - ClosedListFlag = nullptr; - Head.PathNodeCount = 0; - Head.version = 2; - QuickConnectTarget = -1; -} - -PathManager::~PathManager() -{ - safe_delete_array(PathNodes); - safe_delete_array(ClosedListFlag); -} - -bool PathManager::loadPaths(FILE *PathFile) -{ - - char Magic[10]; - - fread(&Magic, 9, 1, PathFile); - - if(strncmp(Magic, "EQEMUPATH", 9)) - { - Log.Out(Logs::General, Logs::Error, "Bad Magic String in .path file."); - return false; - } - - fread(&Head, sizeof(Head), 1, PathFile); - - Log.Out(Logs::General, Logs::Status, "Path File Header: Version %ld, PathNodes %ld", - (long)Head.version, (long)Head.PathNodeCount); - - if(Head.version != 2) - { - Log.Out(Logs::General, Logs::Error, "Unsupported path file version."); - return false; - } - - PathNodes = new PathNode[Head.PathNodeCount]; - - fread(PathNodes, sizeof(PathNode), Head.PathNodeCount, PathFile); - - ClosedListFlag = new int[Head.PathNodeCount]; - -#ifdef PATHDEBUG - PrintPathing(); -#endif - - int MaxNodeID = Head.PathNodeCount - 1; - - bool PathFileValid = true; - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - for(uint32 j = 0; j < PATHNODENEIGHBOURS; ++j) - { - if(PathNodes[i].Neighbours[j].id > MaxNodeID) - { - Log.Out(Logs::General, Logs::Error, "Path Node %i, Neighbour %i (%i) out of range.", i, j, PathNodes[i].Neighbours[j].id); - - PathFileValid = false; - } - } - } - - if(!PathFileValid) - { - safe_delete_array(PathNodes); - } - - return PathFileValid; -} - -void PathManager::PrintPathing() -{ - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - printf("PathNode: %2d id %2d. (%8.3f, %8.3f, %8.3f), BestZ: %8.3f\n", - i, PathNodes[i].id, PathNodes[i].v.x, PathNodes[i].v.y, PathNodes[i].v.z, PathNodes[i].bestz); - - - if(PathNodes[i].Neighbours[0].id == -1) - { - printf(" NO NEIGHBOURS.\n"); - continue; - } - - for(int j=0; j= 0) - printf(" ***** via door %i *****", PathNodes[i].Neighbours[j].DoorID); - - printf("\n"); - } - } -} - -glm::vec3 PathManager::GetPathNodeCoordinates(int NodeNumber, bool BestZ) -{ - glm::vec3 Result; - - if(NodeNumber < Head.PathNodeCount) - { - Result = PathNodes[NodeNumber].v; - - if(!BestZ) - return Result; - - Result.z = PathNodes[NodeNumber].bestz; - } - - return Result; - -} - -std::deque PathManager::FindRoute(int startID, int endID) -{ - Log.Out(Logs::Detail, Logs::None, "FindRoute from node %i to %i", startID, endID); - - memset(ClosedListFlag, 0, sizeof(int) * Head.PathNodeCount); - - std::deque OpenList, ClosedList; - - std::dequeRoute; - - AStarNode AStarEntry, CurrentNode; - - AStarEntry.PathNodeID = startID; - AStarEntry.Parent = -1; - AStarEntry.HCost = 0; - AStarEntry.GCost = 0; - AStarEntry.Teleport = false; - - OpenList.push_back(AStarEntry); - - while(OpenList.size() > 0) - { - // The OpenList is maintained in sorted order, lowest to highest cost. - - CurrentNode = (*OpenList.begin()); - - ClosedList.push_back(CurrentNode); - - ClosedListFlag[CurrentNode.PathNodeID] = true; - - OpenList.pop_front(); - - for(int i = 0; i < PATHNODENEIGHBOURS; ++i) - { - if(PathNodes[CurrentNode.PathNodeID].Neighbours[i].id == -1) - break; - - if(PathNodes[CurrentNode.PathNodeID].Neighbours[i].id == CurrentNode.Parent) - continue; - - if(PathNodes[CurrentNode.PathNodeID].Neighbours[i].id == endID) - { - Route.push_back(CurrentNode.PathNodeID); - - Route.push_back(endID); - - std::deque::iterator RouteIterator; - - while(CurrentNode.PathNodeID != startID) - { - for(RouteIterator = ClosedList.begin(); RouteIterator != ClosedList.end(); ++RouteIterator) - { - if((*RouteIterator).PathNodeID == CurrentNode.Parent) - { - if(CurrentNode.Teleport) - Route.insert(Route.begin(), -1); - - CurrentNode = (*RouteIterator); - - Route.insert(Route.begin(), CurrentNode.PathNodeID); - - break; - } - } - } - - return Route; - } - if(ClosedListFlag[PathNodes[CurrentNode.PathNodeID].Neighbours[i].id]) - continue; - - AStarEntry.PathNodeID = PathNodes[CurrentNode.PathNodeID].Neighbours[i].id; - - AStarEntry.Parent = CurrentNode.PathNodeID; - - AStarEntry.Teleport = PathNodes[CurrentNode.PathNodeID].Neighbours[i].Teleport; - - // HCost is the estimated cost to get from this node to the end. - AStarEntry.HCost = VectorDistance(PathNodes[PathNodes[CurrentNode.PathNodeID].Neighbours[i].id].v, - PathNodes[endID].v); - - AStarEntry.GCost = CurrentNode.GCost + PathNodes[CurrentNode.PathNodeID].Neighbours[i].distance; - - float FCost = AStarEntry.HCost + AStarEntry.GCost; -#ifdef PATHDEBUG - printf("Node: %i, Open Neighbour %i has HCost %8.3f, GCost %8.3f (Total Cost: %8.3f)\n", - CurrentNode.PathNodeID, - PathNodes[CurrentNode.PathNodeID].Neighbours[i].id, - AStarEntry.HCost, - AStarEntry.GCost, - AStarEntry.HCost + AStarEntry.GCost); -#endif - - bool AlreadyInOpenList = false; - - std::deque::iterator OpenListIterator, InsertionPoint = OpenList.end(); - - for(OpenListIterator = OpenList.begin(); OpenListIterator != OpenList.end(); ++OpenListIterator) - { - if((*OpenListIterator).PathNodeID == PathNodes[CurrentNode.PathNodeID].Neighbours[i].id) - { - AlreadyInOpenList = true; - - float GCostToNode = CurrentNode.GCost + PathNodes[CurrentNode.PathNodeID].Neighbours[i].distance; - - if(GCostToNode < (*OpenListIterator).GCost) - { - (*OpenListIterator).Parent = CurrentNode.PathNodeID; - - (*OpenListIterator).GCost = GCostToNode; - - (*OpenListIterator).Teleport = PathNodes[CurrentNode.PathNodeID].Neighbours[i].Teleport; - } - break; - } - else if((InsertionPoint == OpenList.end()) && (((*OpenListIterator).HCost + (*OpenListIterator).GCost) > FCost)) - { - InsertionPoint = OpenListIterator; - } - } - if(!AlreadyInOpenList) - OpenList.insert(InsertionPoint, AStarEntry); - } - - } - Log.Out(Logs::Detail, Logs::None, "Unable to find a route."); - return Route; - -} - -bool CheckLOSBetweenPoints(glm::vec3 start, glm::vec3 end) { - - glm::vec3 hit; - - if((zone->zonemap) && (zone->zonemap->LineIntersectsZone(start, end, 1, &hit))) - return false; - - return true; -} - -auto path_compare = [](const PathNodeSortStruct& a, const PathNodeSortStruct& b) -{ - return a.Distance < b.Distance; -}; - -std::deque PathManager::FindRoute(glm::vec3 Start, glm::vec3 End) -{ - Log.Out(Logs::Detail, Logs::None, "FindRoute(%8.3f, %8.3f, %8.3f, %8.3f, %8.3f, %8.3f)", Start.x, Start.y, Start.z, End.x, End.y, End.z); - - std::deque noderoute; - - float CandidateNodeRangeXY = RuleR(Pathing, CandidateNodeRangeXY); - - float CandidateNodeRangeZ = RuleR(Pathing, CandidateNodeRangeZ); - - // Find the nearest PathNode the Start has LOS to. - // - // - int ClosestPathNodeToStart = -1; - - std::deque SortedByDistance; - - PathNodeSortStruct TempNode; - - for(uint32 i = 0 ; i < Head.PathNodeCount; ++i) - { - if ((std::abs(Start.x - PathNodes[i].v.x) <= CandidateNodeRangeXY) && - (std::abs(Start.y - PathNodes[i].v.y) <= CandidateNodeRangeXY) && - (std::abs(Start.z - PathNodes[i].v.z) <= CandidateNodeRangeZ)) { - TempNode.id = i; - TempNode.Distance = VectorDistanceNoRoot(Start, PathNodes[i].v); - SortedByDistance.push_back(TempNode); - - } - } - - std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare); - - for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) - { - Log.Out(Logs::Detail, Logs::None, "Checking Reachability of Node %i from Start Position.", PathNodes[(*Iterator).id].id); - - if(!zone->zonemap->LineIntersectsZone(Start, PathNodes[(*Iterator).id].v, 1.0f, nullptr)) - { - ClosestPathNodeToStart = (*Iterator).id; - break; - } - } - - if(ClosestPathNodeToStart <0 ) { - Log.Out(Logs::Detail, Logs::None, "No LOS to any starting Path Node within range."); - return noderoute; - } - - Log.Out(Logs::Detail, Logs::None, "Closest Path Node To Start: %2d", ClosestPathNodeToStart); - - // Find the nearest PathNode the end point has LOS to - - int ClosestPathNodeToEnd = -1; - - SortedByDistance.clear(); - - for(uint32 i = 0 ; i < Head.PathNodeCount; ++i) - { - if ((std::abs(End.x - PathNodes[i].v.x) <= CandidateNodeRangeXY) && - (std::abs(End.y - PathNodes[i].v.y) <= CandidateNodeRangeXY) && - (std::abs(End.z - PathNodes[i].v.z) <= CandidateNodeRangeZ)) { - TempNode.id = i; - TempNode.Distance = VectorDistanceNoRoot(End, PathNodes[i].v); - SortedByDistance.push_back(TempNode); - } - } - - std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare); - - for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) - { - Log.Out(Logs::Detail, Logs::None, "Checking Reachability of Node %i from End Position.", PathNodes[(*Iterator).id].id); - Log.Out(Logs::Detail, Logs::None, " (%8.3f, %8.3f, %8.3f) to (%8.3f, %8.3f, %8.3f)", - End.x, End.y, End.z, - PathNodes[(*Iterator).id].v.x, PathNodes[(*Iterator).id].v.y, PathNodes[(*Iterator).id].v.z); - - if(!zone->zonemap->LineIntersectsZone(End, PathNodes[(*Iterator).id].v, 1.0f, nullptr)) - { - ClosestPathNodeToEnd = (*Iterator).id; - break; - } - } - - if(ClosestPathNodeToEnd < 0) { - Log.Out(Logs::Detail, Logs::None, "No LOS to any end Path Node within range."); - return noderoute; - } - - Log.Out(Logs::Detail, Logs::None, "Closest Path Node To End: %2d", ClosestPathNodeToEnd); - - if(ClosestPathNodeToStart == ClosestPathNodeToEnd) - { - noderoute.push_back(ClosestPathNodeToStart); - return noderoute; - } - noderoute = FindRoute(ClosestPathNodeToStart, ClosestPathNodeToEnd); - - int NodesToAttemptToCull = RuleI(Pathing, CullNodesFromStart); - - if(NodesToAttemptToCull > 0) - { - int CulledNodes = 0; - - std::deque::iterator First, Second; - - while((noderoute.size() >= 2) && (CulledNodes < NodesToAttemptToCull)) - { - First = noderoute.begin(); - - Second = First; - - ++Second; - - if((*Second) < 0) - break; - - if(!zone->zonemap->LineIntersectsZone(Start, PathNodes[(*Second)].v, 1.0f, nullptr) - && zone->pathing->NoHazards(Start, PathNodes[(*Second)].v)) - { - noderoute.erase(First); - - ++CulledNodes; - } - else - break; - } - } - - NodesToAttemptToCull = RuleI(Pathing, CullNodesFromEnd); - - if(NodesToAttemptToCull > 0) - { - int CulledNodes = 0; - - std::deque::iterator First, Second; - - while((noderoute.size() >= 2) && (CulledNodes < NodesToAttemptToCull)) - { - First = noderoute.end(); - - --First; - - Second = First; - - --Second; - - if((*Second) < 0) - break; - - if(!zone->zonemap->LineIntersectsZone(End, PathNodes[(*Second)].v, 1.0f, nullptr) - && zone->pathing->NoHazards(End, PathNodes[(*Second)].v)) - { - noderoute.erase(First); - - ++CulledNodes; - } - else - break; - } - } - - return noderoute; -} - -const char* DigitToWord(int i) -{ - switch(i) { - case 0: - return "zero"; - case 1: - return "one"; - case 2: - return "two"; - case 3: - return "three"; - case 4: - return "four"; - case 5: - return "five"; - case 6: - return "six"; - case 7: - return "seven"; - case 8: - return "eight"; - case 9: - return "nine"; - } - return ""; -} - -void PathManager::SpawnPathNodes() -{ - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - NPCType* npc_type = new NPCType; - memset(npc_type, 0, sizeof(NPCType)); - - if(PathNodes[i].id < 10) - sprintf(npc_type->name, "%s", DigitToWord(PathNodes[i].id)); - else if(PathNodes[i].id < 100) - sprintf(npc_type->name, "%s_%s", DigitToWord(PathNodes[i].id/10), DigitToWord(PathNodes[i].id % 10)); - else - sprintf(npc_type->name, "%s_%s_%s", DigitToWord(PathNodes[i].id/100), DigitToWord((PathNodes[i].id % 100)/10), - DigitToWord(((PathNodes[i].id % 100) %10))); - - sprintf(npc_type->lastname, "%i", PathNodes[i].id); - npc_type->cur_hp = 4000000; - npc_type->max_hp = 4000000; - npc_type->race = 151; - npc_type->gender = 2; - npc_type->class_ = 9; - npc_type->deity= 1; - npc_type->level = 75; - npc_type->npc_id = 0; - npc_type->loottable_id = 0; - npc_type->texture = 1; - npc_type->light = 0; - npc_type->runspeed = 0; - npc_type->d_melee_texture1 = 1; - npc_type->d_melee_texture2 = 1; - npc_type->merchanttype = 1; - npc_type->bodytype = 1; - - npc_type->STR = 150; - npc_type->STA = 150; - npc_type->DEX = 150; - npc_type->AGI = 150; - npc_type->INT = 150; - npc_type->WIS = 150; - npc_type->CHA = 150; - - npc_type->findable = 1; - auto position = glm::vec4(PathNodes[i].v.x, PathNodes[i].v.y, PathNodes[i].v.z, 0.0f); - NPC* npc = new NPC(npc_type, nullptr, position, FlyMode1); - npc->GiveNPCTypeData(npc_type); - - entity_list.AddNPC(npc, true, true); - } -} - -void PathManager::MeshTest() -{ - // This will test connectivity between all path nodes - - int TotalTests = 0; - int NoConnections = 0; - - printf("Beginning Pathmanager connectivity tests.\n"); fflush(stdout); - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - for(uint32 j = 0; j < Head.PathNodeCount; ++j) - { - if(j == i) - continue; - - std::deque Route = FindRoute(PathNodes[i].id, PathNodes[j].id); - - if(Route.size() == 0) - { - ++NoConnections; - printf("FindRoute(%i, %i) **** NO ROUTE FOUND ****\n", PathNodes[i].id, PathNodes[j].id); - } - ++TotalTests; - } - } - printf("Executed %i route searches.\n", TotalTests); - printf("Failed to find %i routes.\n", NoConnections); - fflush(stdout); -} - -void PathManager::SimpleMeshTest() -{ - // This will test connectivity between the first path node and all other nodes - - int TotalTests = 0; - int NoConnections = 0; - - printf("Beginning Pathmanager connectivity tests.\n"); - fflush(stdout); - - for(uint32 j = 1; j < Head.PathNodeCount; ++j) - { - std::deque Route = FindRoute(PathNodes[0].id, PathNodes[j].id); - - if(Route.size() == 0) - { - ++NoConnections; - printf("FindRoute(%i, %i) **** NO ROUTE FOUND ****\n", PathNodes[0].id, PathNodes[j].id); - } - ++TotalTests; - } - printf("Executed %i route searches.\n", TotalTests); - printf("Failed to find %i routes.\n", NoConnections); - fflush(stdout); -} - -glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChanged, bool &NodeReached) +glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChanged) { WaypointChanged = false; - NodeReached = false; + glm::vec3 from(GetX(), GetY(), GetZ()); + glm::vec3 to(ToX, ToY, ToZ); - glm::vec3 NodeLoc; + if (Speed <= 0) + return to; - glm::vec3 From(GetX(), GetY(), GetZ()); + if (to == from) + return to; - glm::vec3 HeadPosition(From.x, From.y, From.z + (GetSize() < 6.0 ? 6 : GetSize()) * HEAD_POSITION); + if (DistanceSquaredNoZ(m_Position, glm::vec4(ToX, ToY, ToZ, 0.0f)) < 100.0f) { + return to; + } - glm::vec3 To(ToX, ToY, ToZ); + if (!m_pathing_route.Active() || !m_pathing_route.DestinationValid(to)) { + m_pathing_route = zone->pathing.FindRoute(from, to); - bool SameDestination = (To == PathingDestination); + auto &nodes = m_pathing_route.GetNodesEdit(); + auto &last_node = nodes[nodes.size() - 1]; + if (DistanceSquared(glm::vec4(last_node.position, 1.0f), glm::vec4(ToX, ToY, ToZ, 0.0f)) > 100.0f) { + last_node.flag = NavigationPolyFlagPortal; - if (Speed <= 0) // our speed is 0, we cant move so lets return the dest - return To; // this will also avoid the teleports cleanly - - int NextNode; - - if(To == From) - return To; - - Log.Out(Logs::Detail, Logs::None, "UpdatePath. From(%8.3f, %8.3f, %8.3f) To(%8.3f, %8.3f, %8.3f)", From.x, From.y, From.z, To.x, To.y, To.z); - - if(From == PathingLastPosition) - { - ++PathingLoopCount; - - if((PathingLoopCount > 5) && !IsRooted()) - { - Log.Out(Logs::Detail, Logs::None, "appears to be stuck. Teleporting them to next position.", GetName()); - - if(Route.size() == 0) - { - Teleport(To); - - WaypointChanged = true; - - PathingLoopCount = 0; - - return To; - } - NodeLoc = zone->pathing->GetPathNodeCoordinates(Route.front()); - - Route.pop_front(); - - ++PathingTraversedNodes; - - Teleport(NodeLoc); - - WaypointChanged = true; - - PathingLoopCount = 0; - - return NodeLoc; + PathfindingNode end; + end.position.x = ToX; + end.position.y = ToY; + end.position.z = ToZ; + end.flag = NavigationPolyFlagNormal; + nodes.push_back(end); } } - else - { - PathingLoopCount = 0; - PathingLastPosition = From; - } - - if(Route.size() > 0) - { - - // If we are already pathing, and the destination is the same as before ... - if(SameDestination) - { - Log.Out(Logs::Detail, Logs::None, " Still pathing to the same destination."); - - // Get the coordinates of the first path node we are going to. - NextNode = Route.front(); - - NodeLoc = zone->pathing->GetPathNodeCoordinates(NextNode); - - // May need to refine this as rounding errors may mean we never have equality - // We have reached the path node. - if(NodeLoc == From) - { - Log.Out(Logs::Detail, Logs::None, " Arrived at node %i", NextNode); - - NodeReached = true; - - PathingLastNodeVisited = Route.front(); - // We only check for LOS again after traversing more than 1 node, otherwise we can get into - // a loop where we have a hazard and so run to a path node far enough away from the hazard, and - // then run right back towards the same hazard again. - // - // An exception is when we are about to head for the last node. We always check LOS then. This - // is because we are seeking a path to the node nearest to our target. This node may be behind the - // target, and we may run past the target if we don't check LOS at this point. - int RouteSize = Route.size(); - - Log.Out(Logs::Detail, Logs::None, "Route size is %i", RouteSize); - - if((RouteSize == 2) - || ((PathingTraversedNodes >= RuleI(Pathing, MinNodesTraversedForLOSCheck)) - && (RouteSize <= RuleI(Pathing, MinNodesLeftForLOSCheck)) - && PathingLOSCheckTimer->Check())) - { - Log.Out(Logs::Detail, Logs::None, " Checking distance to target."); - float Distance = VectorDistanceNoRoot(From, To); - - Log.Out(Logs::Detail, Logs::None, " Distance between From and To (NoRoot) is %8.3f", Distance); - - if ((Distance <= RuleR(Pathing, MinDistanceForLOSCheckShort)) && - (std::abs(From.z - To.z) <= RuleR(Pathing, ZDiffThreshold))) { - if(!zone->zonemap->LineIntersectsZone(HeadPosition, To, 1.0f, nullptr)) - PathingLOSState = HaveLOS; - else - PathingLOSState = NoLOS; - Log.Out(Logs::Detail, Logs::None, "NoLOS"); - - if((PathingLOSState == HaveLOS) && zone->pathing->NoHazards(From, To)) - { - Log.Out(Logs::Detail, Logs::None, " No hazards. Running directly to target."); - Route.clear(); - - return To; - } - else - { - Log.Out(Logs::Detail, Logs::None, " Continuing on node path."); - } - } - else - PathingLOSState = UnknownLOS; - } - // We are on the same route, no LOS (or not checking this time, so pop off the node we just reached - // - Route.pop_front(); - - ++PathingTraversedNodes; - - WaypointChanged = true; - - // If there are more nodes on the route, return the coords of the next node - if(Route.size() > 0) - { - NextNode = Route.front(); - - if(NextNode == -1) - { - // -1 indicates a teleport to the next node - Route.pop_front(); - - if(Route.size() == 0) - { - Log.Out(Logs::Detail, Logs::None, "Missing node after teleport."); - return To; - } - - NextNode = Route.front(); - - NodeLoc = zone->pathing->GetPathNodeCoordinates(NextNode); - - Teleport(NodeLoc); - - Log.Out(Logs::Detail, Logs::None, " TELEPORTED to %8.3f, %8.3f, %8.3f\n", NodeLoc.x, NodeLoc.y, NodeLoc.z); - - Route.pop_front(); - - if(Route.size() == 0) - return To; - - NextNode = Route.front(); - } - zone->pathing->OpenDoors(PathingLastNodeVisited, NextNode, this); - - Log.Out(Logs::Detail, Logs::None, " Now moving to node %i", NextNode); - - return zone->pathing->GetPathNodeCoordinates(NextNode); - } - else - { - // we have run all the nodes, all that is left is the direct path from the last node - // to the destination - Log.Out(Logs::Detail, Logs::None, " Reached end of node path, running direct to target."); - - return To; - } - } - // At this point, we are still on the previous path, but not reached a node yet. - // The route shouldn't be empty, but check anyway. - // - int RouteSize = Route.size(); - - if((PathingTraversedNodes >= RuleI(Pathing, MinNodesTraversedForLOSCheck)) - && (RouteSize <= RuleI(Pathing, MinNodesLeftForLOSCheck)) - && PathingLOSCheckTimer->Check()) - { - Log.Out(Logs::Detail, Logs::None, " Checking distance to target."); - - float Distance = VectorDistanceNoRoot(From, To); - - Log.Out(Logs::Detail, Logs::None, " Distance between From and To (NoRoot) is %8.3f", Distance); - - if ((Distance <= RuleR(Pathing, MinDistanceForLOSCheckShort)) && - (std::abs(From.z - To.z) <= RuleR(Pathing, ZDiffThreshold))) { - if(!zone->zonemap->LineIntersectsZone(HeadPosition, To, 1.0f, nullptr)) - PathingLOSState = HaveLOS; - else - PathingLOSState = NoLOS; - Log.Out(Logs::Detail, Logs::None, "NoLOS"); - - if((PathingLOSState == HaveLOS) && zone->pathing->NoHazards(From, To)) - { - Log.Out(Logs::Detail, Logs::None, " No hazards. Running directly to target."); - Route.clear(); - - return To; - } - else - { - Log.Out(Logs::Detail, Logs::None, " Continuing on node path."); - } - } - else - PathingLOSState = UnknownLOS; - } - return NodeLoc; - } - else - { - // We get here if we were already pathing, but our destination has now changed. - // - Log.Out(Logs::Detail, Logs::None, " Target has changed position."); - // Update our record of where we are going to. - PathingDestination = To; - // Check if we now have LOS etc to the new destination. - if(PathingLOSCheckTimer->Check()) - { - float Distance = VectorDistanceNoRoot(From, To); - - if ((Distance <= RuleR(Pathing, MinDistanceForLOSCheckShort)) && - (std::abs(From.z - To.z) <= RuleR(Pathing, ZDiffThreshold))) { - Log.Out(Logs::Detail, Logs::None, " Checking for short LOS at distance %8.3f.", Distance); - if(!zone->zonemap->LineIntersectsZone(HeadPosition, To, 1.0f, nullptr)) - PathingLOSState = HaveLOS; - else - PathingLOSState = NoLOS; - - Log.Out(Logs::Detail, Logs::None, "NoLOS"); - - if((PathingLOSState == HaveLOS) && zone->pathing->NoHazards(From, To)) - { - Log.Out(Logs::Detail, Logs::None, " No hazards. Running directly to target."); - Route.clear(); - return To; - } - else - { - Log.Out(Logs::Detail, Logs::None, " Continuing on node path."); - } - } - } - - // If the player is moving, we don't want to recalculate our route too frequently. - // - if(static_cast(Route.size()) <= RuleI(Pathing, RouteUpdateFrequencyNodeCount)) - { - if(!PathingRouteUpdateTimerShort->Check()) - { - Log.Out(Logs::Detail, Logs::None, "Short route update timer not yet expired."); - return zone->pathing->GetPathNodeCoordinates(Route.front()); - } - Log.Out(Logs::Detail, Logs::None, "Short route update timer expired."); - } - else - { - if(!PathingRouteUpdateTimerLong->Check()) - { - Log.Out(Logs::Detail, Logs::None, "Long route update timer not yet expired."); - return zone->pathing->GetPathNodeCoordinates(Route.front()); - } - Log.Out(Logs::Detail, Logs::None, "Long route update timer expired."); - } - - // We are already pathing, destination changed, no LOS. Find the nearest node to our destination. - int DestinationPathNode= zone->pathing->FindNearestPathNode(To); - - // Destination unreachable via pathing, return direct route. - if(DestinationPathNode == -1) - { - Log.Out(Logs::Detail, Logs::None, " Unable to find path node for new destination. Running straight to target."); - Route.clear(); - return To; - } - // If the nearest path node to our new destination is the same as for the previous - // one, we will carry on on our path. - if(DestinationPathNode == Route.back()) - { - Log.Out(Logs::Detail, Logs::None, " Same destination Node (%i). Continue with current path.", DestinationPathNode); - - NodeLoc = zone->pathing->GetPathNodeCoordinates(Route.front()); - - // May need to refine this as rounding errors may mean we never have equality - // Check if we have reached a path node. - if(NodeLoc == From) - { - Log.Out(Logs::Detail, Logs::None, " Arrived at node %i, moving to next one.\n", Route.front()); - - NodeReached = true; - - PathingLastNodeVisited = Route.front(); - - Route.pop_front(); - - ++PathingTraversedNodes; - - WaypointChanged = true; - - if(Route.size() > 0) - { - NextNode = Route.front(); - - if(NextNode == -1) - { - // -1 indicates a teleport to the next node - Route.pop_front(); - - if(Route.size() == 0) - { - Log.Out(Logs::Detail, Logs::None, "Missing node after teleport."); - return To; - } - - NextNode = Route.front(); - - NodeLoc = zone->pathing->GetPathNodeCoordinates(NextNode); - - Teleport(NodeLoc); - - Log.Out(Logs::Detail, Logs::None, " TELEPORTED to %8.3f, %8.3f, %8.3f\n", NodeLoc.x, NodeLoc.y, NodeLoc.z); - - Route.pop_front(); - - if(Route.size() == 0) - return To; - - NextNode = Route.front(); - } - // Return the coords of our next path node on the route. - Log.Out(Logs::Detail, Logs::None, " Now moving to node %i", NextNode); - - zone->pathing->OpenDoors(PathingLastNodeVisited, NextNode, this); - - return zone->pathing->GetPathNodeCoordinates(NextNode); - } - else - { - Log.Out(Logs::Detail, Logs::None, " Reached end of path grid. Running direct to target."); - return To; - } - } - return NodeLoc; - } - else - { - Log.Out(Logs::Detail, Logs::None, " Target moved. End node is different. Clearing route."); - - Route.clear(); - // We will now fall through to get a new route. - } + m_pathing_route.CalcCurrentNode(from, WaypointChanged); + auto ¤t = m_pathing_route.GetCurrentNode(); + //We reached a wp and rolled over to a new wp dest and it was a portal wp so we portal to the next spot + if (WaypointChanged) { + if (m_pathing_route.GetPreviousNodeFlag() & NavigationPolyFlagPortal) { + Teleport(current.position); } - - } - Log.Out(Logs::Detail, Logs::None, " Our route list is empty."); - - if((SameDestination) && !PathingLOSCheckTimer->Check()) - { - Log.Out(Logs::Detail, Logs::None, " Destination same as before, LOS check timer not reached. Returning To."); - return To; + TrySnapToMap(); } - PathingLOSState = UnknownLOS; - - PathingDestination = To; - - WaypointChanged = true; - - float Distance = VectorDistanceNoRoot(From, To); - - if ((Distance <= RuleR(Pathing, MinDistanceForLOSCheckLong)) && - (std::abs(From.z - To.z) <= RuleR(Pathing, ZDiffThreshold))) { - Log.Out(Logs::Detail, Logs::None, " Checking for long LOS at distance %8.3f.", Distance); - - if(!zone->zonemap->LineIntersectsZone(HeadPosition, To, 1.0f, nullptr)) - PathingLOSState = HaveLOS; - else - PathingLOSState = NoLOS; - - Log.Out(Logs::Detail, Logs::None, "NoLOS"); - - if((PathingLOSState == HaveLOS) && zone->pathing->NoHazards(From, To)) - { - Log.Out(Logs::Detail, Logs::None, "Target is reachable. Running directly there."); - return To; - } - } - Log.Out(Logs::Detail, Logs::None, " Calculating new route to target."); - - Route = zone->pathing->FindRoute(From, To); - - PathingTraversedNodes = 0; - - if(Route.size() == 0) - { - Log.Out(Logs::Detail, Logs::None, " No route available, running direct."); - - return To; - } - - if(SameDestination && (Route.front() == PathingLastNodeVisited)) - { - Log.Out(Logs::Detail, Logs::None, " Probable loop detected. Same destination and Route.front() == PathingLastNodeVisited."); - - Route.clear(); - - return To; - } - NodeLoc = zone->pathing->GetPathNodeCoordinates(Route.front()); - - Log.Out(Logs::Detail, Logs::None, " New route determined, heading for node %i", Route.front()); - - PathingLoopCount = 0; - - return NodeLoc; - + return current.position; } -int PathManager::FindNearestPathNode(glm::vec3 Position) -{ - - // Find the nearest PathNode we have LOS to. - // - // - - float CandidateNodeRangeXY = RuleR(Pathing, CandidateNodeRangeXY); - - float CandidateNodeRangeZ = RuleR(Pathing, CandidateNodeRangeZ); - - int ClosestPathNodeToStart = -1; - - std::deque SortedByDistance; - - PathNodeSortStruct TempNode; - - for(uint32 i = 0 ; i < Head.PathNodeCount; ++i) - { - if ((std::abs(Position.x - PathNodes[i].v.x) <= CandidateNodeRangeXY) && - (std::abs(Position.y - PathNodes[i].v.y) <= CandidateNodeRangeXY) && - (std::abs(Position.z - PathNodes[i].v.z) <= CandidateNodeRangeZ)) { - TempNode.id = i; - TempNode.Distance = VectorDistanceNoRoot(Position, PathNodes[i].v); - SortedByDistance.push_back(TempNode); - +void Mob::TrySnapToMap() { + bool snap = true; + if (IsNPC()) { + auto npc = CastToNPC(); + if (npc->GetFlyMode() == 1 || npc->GetFlyMode() == 2) { + snap = false; } } - - std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare); - - for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator) - { - Log.Out(Logs::Detail, Logs::None, "Checking Reachability of Node %i from Start Position.", PathNodes[(*Iterator).id].id); - - if(!zone->zonemap->LineIntersectsZone(Position, PathNodes[(*Iterator).id].v, 1.0f, nullptr)) - { - ClosestPathNodeToStart = (*Iterator).id; - break; - } - } - - if(ClosestPathNodeToStart <0 ) { - Log.Out(Logs::Detail, Logs::None, "No LOS to any starting Path Node within range."); - return -1; - } - return ClosestPathNodeToStart; -} - -bool PathManager::NoHazards(glm::vec3 From, glm::vec3 To) -{ - // Test the Z coordinate at the mid point. - // - glm::vec3 MidPoint((From.x + To.x) / 2, (From.y + To.y) / 2, From.z); - - float NewZ = zone->zonemap->FindBestZ(MidPoint, nullptr); - - if (std::abs(NewZ - From.z) > RuleR(Pathing, ZDiffThreshold)) { - Log.Out(Logs::Detail, Logs::None, " HAZARD DETECTED moving from %8.3f, %8.3f, %8.3f to %8.3f, %8.3f, %8.3f. Z Change is %8.3f", - From.x, From.y, From.z, MidPoint.x, MidPoint.y, MidPoint.z, NewZ - From.z); - - return false; - } - else - { - Log.Out(Logs::Detail, Logs::None, "No HAZARD DETECTED moving from %8.3f, %8.3f, %8.3f to %8.3f, %8.3f, %8.3f. Z Change is %8.3f", - From.x, From.y, From.z, MidPoint.x, MidPoint.y, MidPoint.z, NewZ - From.z); - } - - return true; -} - -bool PathManager::NoHazardsAccurate(glm::vec3 From, glm::vec3 To) -{ - float stepx, stepy, stepz, curx, cury, curz; - glm::vec3 cur = From; - float last_z = From.z; - float step_size = 1.0; - - curx = From.x; - cury = From.y; - curz = From.z; - - do - { - stepx = (float)To.x - curx; - stepy = (float)To.y - cury; - stepz = (float)To.z - curz; - float factor = sqrt(stepx*stepx + stepy*stepy + stepz*stepz); - stepx = (stepx / factor)*step_size; - stepy = (stepy / factor)*step_size; - stepz = (stepz / factor)*step_size; - - glm::vec3 TestPoint(curx, cury, curz); - float NewZ = zone->zonemap->FindBestZ(TestPoint, nullptr); - if (std::abs(NewZ - last_z) > 5.0f) { - Log.Out(Logs::Detail, Logs::None, " HAZARD DETECTED moving from %8.3f, %8.3f, %8.3f to %8.3f, %8.3f, %8.3f. Best Z %8.3f, Z Change is %8.3f", - From.x, From.y, From.z, TestPoint.x, TestPoint.y, TestPoint.z, NewZ, NewZ - From.z); - return false; - } - last_z = NewZ; - - if (zone->watermap) - { - auto from = glm::vec3(From.x, From.y, From.z); - auto to = glm::vec3(To.x, To.y, To.z); - if (zone->watermap->InLiquid(from) || zone->watermap->InLiquid(to)) - { - break; - } - auto testPointNewZ = glm::vec3(TestPoint.x, TestPoint.y, NewZ); - if (zone->watermap->InLiquid(testPointNewZ)) - { - glm::vec3 TestPointWater(TestPoint.x, TestPoint.y, NewZ - 0.5f); - glm::vec3 TestPointWaterDest = TestPointWater; - glm::vec3 hit; - TestPointWaterDest.z -= 500; - float best_z2 = -999990; - if (zone->zonemap->LineIntersectsZone(TestPointWater, TestPointWaterDest, 1.0f, &hit)) - { - best_z2 = hit.z; - } - if (best_z2 == -999990) - { - Log.Out(Logs::Detail, Logs::None, " HAZARD DETECTED, really deep water/lava!"); - return false; - } - else - { - if (std::abs(NewZ - best_z2) > RuleR(Pathing, ZDiffThreshold)) { - Log.Out(Logs::Detail, Logs::None, - " HAZARD DETECTED, water is fairly deep at %8.3f units deep", - std::abs(NewZ - best_z2)); - return false; - } - else - { - Log.Out(Logs::Detail, Logs::None, - " HAZARD NOT DETECTED, water is shallow at %8.3f units deep", - std::abs(NewZ - best_z2)); - } - } - } - else - { - Log.Out(Logs::Detail, Logs::None, "Hazard point not in water or lava!"); - } - } - else - { - Log.Out(Logs::Detail, Logs::None, "No water map loaded for hazards!"); - } - - curx += stepx; - cury += stepy; - curz += stepz; - - cur.x = curx; - cur.y = cury; - cur.z = curz; - - if (std::abs(curx - To.x) < step_size) - cur.x = To.x; - if (std::abs(cury - To.y) < step_size) - cur.y = To.y; - if (std::abs(curz - To.z) < step_size) - cur.z = To.z; - - } while (cur.x != To.x || cur.y != To.y || cur.z != To.z); - return true; -} - -void Mob::PrintRoute() -{ - - printf("Route is : "); - - for(auto Iterator = Route.begin(); Iterator !=Route.end(); ++Iterator) - { - printf("%i, ", (*Iterator)); - } - - printf("\n"); - -} - -void PathManager::OpenDoors(int Node1, int Node2, Mob *ForWho) -{ - if(!ForWho || (Node1 >= Head.PathNodeCount) || (Node2 >= Head.PathNodeCount) || (Node1 < 0) || (Node2 < 0)) - return; - - for(int i = 0; i < PATHNODENEIGHBOURS; ++i) - { - if(PathNodes[Node1].Neighbours[i].id == -1) - return; - - if(PathNodes[Node1].Neighbours[i].id != Node2) - continue; - - if(PathNodes[Node1].Neighbours[i].DoorID >= 0) - { - Doors *d = entity_list.FindDoor(PathNodes[Node1].Neighbours[i].DoorID); - - if(d && !d->IsDoorOpen() ) - { - Log.Out(Logs::Detail, Logs::None, "Opening door %i for %s", PathNodes[Node1].Neighbours[i].DoorID, ForWho->GetName()); - - d->ForceOpen(ForWho); - } - return; + + if (snap && zone->HasMap()) { + if (!RuleB(Watermap, CheckForWaterWhenMoving) || + !zone->HasWaterMap() || + (zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position)))) { + glm::vec3 dest(m_Position); + float newz = zone->zonemap->FindBestZ(dest, nullptr) + 3.5f; + m_Position.z = newz; } } } - -PathNode* PathManager::FindPathNodeByCoordinates(float x, float y, float z) -{ - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - if((PathNodes[i].v.x == x) && (PathNodes[i].v.y == y) && (PathNodes[i].v.z == z)) - return &PathNodes[i]; - - return nullptr; -} - -int PathManager::GetRandomPathNode() -{ - return zone->random.Int(0, Head.PathNodeCount - 1); - -} - -void PathManager::ShowPathNodeNeighbours(Client *c) -{ - if(!c || !c->GetTarget()) - return; - - - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - - if(!Node) - { - c->Message(0, "Unable to find path node."); - return; - } - c->Message(0, "Path node %4i", Node->id); - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - char Name[64]; - - if(PathNodes[i].id < 10) - sprintf(Name, "%s000", DigitToWord(PathNodes[i].id)); - else if(PathNodes[i].id < 100) - sprintf(Name, "%s_%s000", DigitToWord(PathNodes[i].id / 10), DigitToWord(PathNodes[i].id % 10)); - else - sprintf(Name, "%s_%s_%s000", DigitToWord(PathNodes[i].id/100), DigitToWord((PathNodes[i].id % 100)/10), - DigitToWord(((PathNodes[i].id % 100) %10))); - - Mob *m = entity_list.GetMob(Name); - - if(m) - m->SendIllusionPacket(151); - } - - std::stringstream Neighbours; - - for(int i = 0; i < PATHNODENEIGHBOURS; ++i) - { - if(Node->Neighbours[i].id == -1) - break; - Neighbours << Node->Neighbours[i].id << ", "; - - char Name[64]; - - if(Node->Neighbours[i].id < 10) - sprintf(Name, "%s000", DigitToWord(Node->Neighbours[i].id)); - else if(Node->Neighbours[i].id < 100) - sprintf(Name, "%s_%s000", DigitToWord(Node->Neighbours[i].id / 10), DigitToWord(Node->Neighbours[i].id % 10)); - else - sprintf(Name, "%s_%s_%s000", DigitToWord(Node->Neighbours[i].id/100), DigitToWord((Node->Neighbours[i].id % 100)/10), - DigitToWord(((Node->Neighbours[i].id % 100) %10))); - - Mob *m = entity_list.GetMob(Name); - - if(m) - m->SendIllusionPacket(46); - } - c->Message(0, "Neighbours: %s", Neighbours.str().c_str()); -} - -void PathManager::NodeInfo(Client *c) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - c->Message(0, "Pathing node: %i at (%.2f, %.2f, %.2f) with bestz %.2f", - Node->id, Node->v.x, Node->v.y, Node->v.z, Node->bestz); - - bool neighbour = false; - for(int x = 0; x < 50; ++x) - { - if(Node->Neighbours[x].id != -1) - { - if(!neighbour) - { - c->Message(0, "Neighbours found:"); - neighbour = true; - } - c->Message(0, "id: %i, distance: %.2f, door id: %i, is teleport: %i", - Node->Neighbours[x].id, Node->Neighbours[x].distance, - Node->Neighbours[x].DoorID, Node->Neighbours[x].Teleport); - } - } - - if(!neighbour) - { - c->Message(0, "No neighbours found!"); - } - return; -} - -void PathManager::DumpPath(std::string filename) -{ - std::ofstream o_file; - o_file.open(filename.c_str(), std::ios_base::binary | std::ios_base::trunc | std::ios_base::out); - o_file.write("EQEMUPATH", 9); - o_file.write((const char*)&Head, sizeof(Head)); - o_file.write((const char*)PathNodes, (sizeof(PathNode)*Head.PathNodeCount)); - o_file.close(); -} - -int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 requested_id) -{ - int32 new_id = -1; - if(requested_id != 0) - { - new_id = requested_id; - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - if(PathNodes[i].id == requested_id) - { - new_id = -1; - break; - } - } - } - - if(new_id == -1) - { - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - if(PathNodes[i].id - new_id > 1) { - new_id = PathNodes[i].id - 1; - break; - } - - if(PathNodes[i].id > new_id) - new_id = PathNodes[i].id; - } - new_id++; - } - - PathNode new_node; - new_node.v.x = x; - new_node.v.y = y; - new_node.v.z = z; - new_node.bestz = best_z; - new_node.id = (uint16)new_id; - for(int x = 0; x < PATHNODENEIGHBOURS; ++x) - { - new_node.Neighbours[x].id = -1; - new_node.Neighbours[x].distance = 0.0; - new_node.Neighbours[x].DoorID = -1; - new_node.Neighbours[x].Teleport = 0; - } - - Head.PathNodeCount++; - if(Head.PathNodeCount > 1) - { - PathNode *t_PathNodes = new PathNode[Head.PathNodeCount]; - for(uint32 x = 0; x < (Head.PathNodeCount - 1); ++x) - { - t_PathNodes[x].v.x = PathNodes[x].v.x; - t_PathNodes[x].v.y = PathNodes[x].v.y; - t_PathNodes[x].v.z = PathNodes[x].v.z; - t_PathNodes[x].bestz = PathNodes[x].bestz; - t_PathNodes[x].id = PathNodes[x].id; - for(int n = 0; n < PATHNODENEIGHBOURS; ++n) - { - t_PathNodes[x].Neighbours[n].distance = PathNodes[x].Neighbours[n].distance; - t_PathNodes[x].Neighbours[n].DoorID = PathNodes[x].Neighbours[n].DoorID; - t_PathNodes[x].Neighbours[n].id = PathNodes[x].Neighbours[n].id; - t_PathNodes[x].Neighbours[n].Teleport = PathNodes[x].Neighbours[n].Teleport; - } - - } - - int32 index = (Head.PathNodeCount - 1); - t_PathNodes[index].v.x = new_node.v.x; - t_PathNodes[index].v.y = new_node.v.y; - t_PathNodes[index].v.z = new_node.v.z; - t_PathNodes[index].bestz = new_node.bestz; - t_PathNodes[index].id = new_node.id; - for(int n = 0; n < PATHNODENEIGHBOURS; ++n) - { - t_PathNodes[index].Neighbours[n].distance = new_node.Neighbours[n].distance; - t_PathNodes[index].Neighbours[n].DoorID = new_node.Neighbours[n].DoorID; - t_PathNodes[index].Neighbours[n].id = new_node.Neighbours[n].id; - t_PathNodes[index].Neighbours[n].Teleport = new_node.Neighbours[n].Teleport; - } - - delete[] PathNodes; - PathNodes = t_PathNodes; - - NPCType* npc_type = new NPCType; - memset(npc_type, 0, sizeof(NPCType)); - if(new_id < 10) - sprintf(npc_type->name, "%s", DigitToWord(new_id)); - else if(new_id < 100) - sprintf(npc_type->name, "%s_%s", DigitToWord(new_id/10), DigitToWord(new_id % 10)); - else - sprintf(npc_type->name, "%s_%s_%s", DigitToWord(new_id/100), DigitToWord((new_id % 100)/10), - DigitToWord(((new_id % 100) %10))); - - sprintf(npc_type->lastname, "%i", new_id); - npc_type->cur_hp = 4000000; - npc_type->max_hp = 4000000; - npc_type->race = 151; - npc_type->gender = 2; - npc_type->class_ = 9; - npc_type->deity= 1; - npc_type->level = 75; - npc_type->npc_id = 0; - npc_type->loottable_id = 0; - npc_type->texture = 1; - npc_type->light = 0; - npc_type->runspeed = 0; - npc_type->d_melee_texture1 = 1; - npc_type->d_melee_texture2 = 1; - npc_type->merchanttype = 1; - npc_type->bodytype = 1; - npc_type->STR = 150; - npc_type->STA = 150; - npc_type->DEX = 150; - npc_type->AGI = 150; - npc_type->INT = 150; - npc_type->WIS = 150; - npc_type->CHA = 150; - npc_type->findable = 1; - - auto position = glm::vec4(new_node.v.x, new_node.v.y, new_node.v.z, 0.0f); - NPC* npc = new NPC(npc_type, nullptr, position, FlyMode1); - npc->GiveNPCTypeData(npc_type); - entity_list.AddNPC(npc, true, true); - - safe_delete_array(ClosedListFlag); - ClosedListFlag = new int[Head.PathNodeCount]; - return new_id; - } - else - { - PathNodes = new PathNode[Head.PathNodeCount]; - PathNodes[0].v.x = new_node.v.x; - PathNodes[0].v.y = new_node.v.y; - PathNodes[0].v.z = new_node.v.z; - PathNodes[0].bestz = new_node.bestz; - PathNodes[0].id = new_node.id; - for(int n = 0; n < PATHNODENEIGHBOURS; ++n) - { - PathNodes[0].Neighbours[n].distance = new_node.Neighbours[n].distance; - PathNodes[0].Neighbours[n].DoorID = new_node.Neighbours[n].DoorID; - PathNodes[0].Neighbours[n].id = new_node.Neighbours[n].id; - PathNodes[0].Neighbours[n].Teleport = new_node.Neighbours[n].Teleport; - } - - NPCType* npc_type = new NPCType; - memset(npc_type, 0, sizeof(NPCType)); - if(new_id < 10) - sprintf(npc_type->name, "%s", DigitToWord(new_id)); - else if(new_id < 100) - sprintf(npc_type->name, "%s_%s", DigitToWord(new_id/10), DigitToWord(new_id % 10)); - else - sprintf(npc_type->name, "%s_%s_%s", DigitToWord(new_id/100), DigitToWord((new_id % 100)/10), - DigitToWord(((new_id % 100) %10))); - - sprintf(npc_type->lastname, "%i", new_id); - npc_type->cur_hp = 4000000; - npc_type->max_hp = 4000000; - npc_type->race = 151; - npc_type->gender = 2; - npc_type->class_ = 9; - npc_type->deity= 1; - npc_type->level = 75; - npc_type->npc_id = 0; - npc_type->loottable_id = 0; - npc_type->texture = 1; - npc_type->light = 0; - npc_type->runspeed = 0; - npc_type->d_melee_texture1 = 1; - npc_type->d_melee_texture2 = 1; - npc_type->merchanttype = 1; - npc_type->bodytype = 1; - npc_type->STR = 150; - npc_type->STA = 150; - npc_type->DEX = 150; - npc_type->AGI = 150; - npc_type->INT = 150; - npc_type->WIS = 150; - npc_type->CHA = 150; - npc_type->findable = 1; - - auto position = glm::vec4(new_node.v.x, new_node.v.y, new_node.v.z, 0.0f); - NPC* npc = new NPC(npc_type, nullptr, position, FlyMode1); - npc->GiveNPCTypeData(npc_type); - entity_list.AddNPC(npc, true, true); - - ClosedListFlag = new int[Head.PathNodeCount]; - - return new_id; - } -} - -bool PathManager::DeleteNode(Client *c) -{ - if(!c) - { - return false; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return false; - } - - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return false; - } - - return DeleteNode(Node->id); -} - -bool PathManager::DeleteNode(int32 id) -{ - //if the current list is > 1 in size create a new list of size current size - 1 - //transfer all but the current node to this new list and delete our current list - //set this new list to be our current list - //else if the size is 1 just delete our current list and set it to zero. - //go through and delete all ref in neighbors... - - if(Head.PathNodeCount > 1) - { - PathNode *t_PathNodes = new PathNode[Head.PathNodeCount-1]; - uint32 index = 0; - for(uint32 x = 0; x < Head.PathNodeCount; x++) - { - if(PathNodes[x].id != id) - { - t_PathNodes[index].id = PathNodes[x].id; - t_PathNodes[index].v.x = PathNodes[x].v.x; - t_PathNodes[index].v.y = PathNodes[x].v.y; - t_PathNodes[index].v.z = PathNodes[x].v.z; - t_PathNodes[index].bestz = PathNodes[x].bestz; - for(int n = 0; n < PATHNODENEIGHBOURS; ++n) - { - t_PathNodes[index].Neighbours[n].distance = PathNodes[x].Neighbours[n].distance; - t_PathNodes[index].Neighbours[n].DoorID = PathNodes[x].Neighbours[n].DoorID; - t_PathNodes[index].Neighbours[n].id = PathNodes[x].Neighbours[n].id; - t_PathNodes[index].Neighbours[n].Teleport = PathNodes[x].Neighbours[n].Teleport; - } - index++; - } - } - Head.PathNodeCount--; - delete[] PathNodes; - PathNodes = t_PathNodes; - - for(uint32 y = 0; y < Head.PathNodeCount; ++y) - { - for(int n = 0; n < PATHNODENEIGHBOURS; ++n) - { - if(PathNodes[y].Neighbours[n].id == id) - { - PathNodes[y].Neighbours[n].Teleport = 0; - PathNodes[y].Neighbours[n].DoorID = -1; - PathNodes[y].Neighbours[n].distance = 0.0; - PathNodes[y].Neighbours[n].id = -1; - } - } - } - safe_delete_array(ClosedListFlag); - ClosedListFlag = new int[Head.PathNodeCount]; - } - else - { - delete[] PathNodes; - PathNodes = nullptr; - } - return true; -} - -void PathManager::ConnectNodeToNode(Client *c, int32 Node2, int32 teleport, int32 doorid) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - c->Message(0, "Connecting %i to %i", Node->id, Node2); - - if(doorid == 0) - ConnectNodeToNode(Node->id, Node2, teleport); - else - ConnectNodeToNode(Node->id, Node2, teleport, doorid); -} - -void PathManager::ConnectNodeToNode(int32 Node1, int32 Node2, int32 teleport, int32 doorid) -{ - PathNode *a = nullptr; - PathNode *b = nullptr; - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - if(PathNodes[x].id == Node1) - { - a = &PathNodes[x]; - if(b) - break; - } - else if(PathNodes[x].id == Node2) - { - b = &PathNodes[x]; - if(a) - break; - } - } - - if(a == nullptr || b == nullptr) - return; - - bool connect_a_to_b = true; - if(NodesConnected(a, b)) - connect_a_to_b = false; - - bool connect_b_to_a = true; - if(NodesConnected(b, a)) - connect_b_to_a = false; - - - if(connect_a_to_b) - { - for(int a_i = 0; a_i < PATHNODENEIGHBOURS; ++a_i) - { - if(a->Neighbours[a_i].id == -1) - { - a->Neighbours[a_i].id = b->id; - a->Neighbours[a_i].DoorID = doorid; - a->Neighbours[a_i].Teleport = teleport; - a->Neighbours[a_i].distance = VectorDistance(a->v, b->v); - break; - } - } - } - - if(connect_b_to_a) - { - for(int b_i = 0; b_i < PATHNODENEIGHBOURS; ++b_i) - { - if(b->Neighbours[b_i].id == -1) - { - b->Neighbours[b_i].id = a->id; - b->Neighbours[b_i].DoorID = doorid; - b->Neighbours[b_i].Teleport = teleport; - b->Neighbours[b_i].distance = VectorDistance(a->v, b->v); - break; - } - } - } -} - -void PathManager::ConnectNode(Client *c, int32 Node2, int32 teleport, int32 doorid) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - c->Message(0, "Connecting %i to %i", Node->id, Node2); - - if(doorid == 0) - ConnectNode(Node->id, Node2, teleport); - else - ConnectNode(Node->id, Node2, teleport, doorid); -} - -void PathManager::ConnectNode(int32 Node1, int32 Node2, int32 teleport, int32 doorid) -{ - PathNode *a = nullptr; - PathNode *b = nullptr; - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - if(PathNodes[x].id == Node1) - { - a = &PathNodes[x]; - if(b) - break; - } - else if(PathNodes[x].id == Node2) - { - b = &PathNodes[x]; - if(a) - break; - } - } - - if(a == nullptr || b == nullptr) - return; - - bool connect_a_to_b = true; - if(NodesConnected(a, b)) - connect_a_to_b = false; - - if(connect_a_to_b) - { - for(int a_i = 0; a_i < PATHNODENEIGHBOURS; ++a_i) - { - if(a->Neighbours[a_i].id == -1) - { - a->Neighbours[a_i].id = b->id; - a->Neighbours[a_i].DoorID = doorid; - a->Neighbours[a_i].Teleport = teleport; - a->Neighbours[a_i].distance = VectorDistance(a->v, b->v); - break; - } - } - } -} - -void PathManager::DisconnectNodeToNode(Client *c, int32 Node2) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - DisconnectNodeToNode(Node->id, Node2); -} - -void PathManager::DisconnectNodeToNode(int32 Node1, int32 Node2) -{ - PathNode *a = nullptr; - PathNode *b = nullptr; - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - if(PathNodes[x].id == Node1) - { - a = &PathNodes[x]; - if(b) - break; - } - else if(PathNodes[x].id == Node2) - { - b = &PathNodes[x]; - if(a) - break; - } - } - - if(a == nullptr || b == nullptr) - return; - - bool disconnect_a_from_b = false; - if(NodesConnected(a, b)) - disconnect_a_from_b = true; - - bool disconnect_b_from_a = false; - if(NodesConnected(b, a)) - disconnect_b_from_a = true; - - if(disconnect_a_from_b) - { - for(int a_i = 0; a_i < PATHNODENEIGHBOURS; ++a_i) - { - if(a->Neighbours[a_i].id == b->id) - { - a->Neighbours[a_i].distance = 0.0; - a->Neighbours[a_i].DoorID = -1; - a->Neighbours[a_i].id = -1; - a->Neighbours[a_i].Teleport = 0; - break; - } - } - } - - if(disconnect_b_from_a) - { - for(int b_i = 0; b_i < PATHNODENEIGHBOURS; ++b_i) - { - if(b->Neighbours[b_i].id == a->id) - { - b->Neighbours[b_i].distance = 0.0; - b->Neighbours[b_i].DoorID = -1; - b->Neighbours[b_i].id = -1; - b->Neighbours[b_i].Teleport = 0; - break; - } - } - } -} - -void PathManager::MoveNode(Client *c) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - Node->v.x = c->GetX(); - Node->v.y = c->GetY(); - Node->v.z = c->GetZ(); - - if(zone->zonemap) - { - glm::vec3 loc(c->GetX(), c->GetY(), c->GetZ()); - Node->bestz = zone->zonemap->FindBestZ(loc, nullptr); - } - else - { - Node->bestz = Node->v.z; - } -} - -void PathManager::DisconnectAll(Client *c) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - for(int x = 0; x < PATHNODENEIGHBOURS; ++x) - { - Node->Neighbours[x].distance = 0; - Node->Neighbours[x].Teleport = 0; - Node->Neighbours[x].DoorID = -1; - Node->Neighbours[x].id = -1; - } - - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - if(PathNodes[i].id == Node->id) - continue; - - for(int ix = 0; ix < PATHNODENEIGHBOURS; ++ix) - { - if(PathNodes[i].Neighbours[ix].id == Node->id) - { - PathNodes[i].Neighbours[ix].distance = 0; - PathNodes[i].Neighbours[ix].Teleport = 0; - PathNodes[i].Neighbours[ix].id = -1; - PathNodes[i].Neighbours[ix].DoorID = -1; - } - } - } -} - -//checks if anything in a points to b -bool PathManager::NodesConnected(PathNode *a, PathNode *b) -{ - if(!a) - return false; - - if(!b) - return false; - - for(int x = 0; x < PATHNODENEIGHBOURS; ++x) - { - if(a->Neighbours[x].id == b->id) - return true; - } - return false; -} - -bool PathManager::CheckLosFN(glm::vec3 a, glm::vec3 b) -{ - if(zone->zonemap) - { - glm::vec3 hit; - - glm::vec3 myloc; - glm::vec3 oloc; - - myloc.x = a.x; - myloc.y = a.y; - myloc.z = a.z; - - oloc.x = b.x; - oloc.y = b.y; - oloc.z = b.z; - - - if(zone->zonemap->LineIntersectsZone(myloc, oloc, 1.0f, nullptr)) - { - return false; - } - } - return true; -} - -void PathManager::ProcessNodesAndSave(std::string filename) -{ - if(zone->zonemap) - { - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - for(int in = 0; in < PATHNODENEIGHBOURS; ++in) - { - PathNodes[i].Neighbours[in].distance = 0.0; - PathNodes[i].Neighbours[in].DoorID = -1; - PathNodes[i].Neighbours[in].id = -1; - PathNodes[i].Neighbours[in].Teleport = 0; - } - } - - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - for(uint32 y = 0; y < Head.PathNodeCount; ++y) - { - if(y == x) //can't connect to ourselves. - continue; - - if(!NodesConnected(&PathNodes[x], &PathNodes[y])) - { - if(VectorDistance(PathNodes[x].v, PathNodes[y].v) <= 200) - { - if(CheckLosFN(PathNodes[x].v, PathNodes[y].v)) - { - if(NoHazardsAccurate(PathNodes[x].v, PathNodes[y].v)) - { - ConnectNodeToNode(PathNodes[x].id, PathNodes[y].id, 0, 0); - } - } - } - } - } - } - } - DumpPath(filename); -} - -void PathManager::ResortConnections() -{ - NeighbourNode Neigh[PATHNODENEIGHBOURS]; - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - int index = 0; - for(int y = 0; y < PATHNODENEIGHBOURS; ++y) - { - Neigh[y].distance = 0; - Neigh[y].DoorID = -1; - Neigh[y].id = -1; - Neigh[y].Teleport = 0; - } - - for(int z = 0; z < PATHNODENEIGHBOURS; ++z) - { - if(PathNodes[x].Neighbours[z].id != -1) - { - Neigh[index].id = PathNodes[x].Neighbours[z].id; - Neigh[index].distance = PathNodes[x].Neighbours[z].distance; - Neigh[index].DoorID = PathNodes[x].Neighbours[z].DoorID; - Neigh[index].Teleport = PathNodes[x].Neighbours[z].Teleport; - index++; - } - } - - for(int i = 0; i < PATHNODENEIGHBOURS; ++i) - { - PathNodes[x].Neighbours[i].distance = 0; - PathNodes[x].Neighbours[i].DoorID = -1; - PathNodes[x].Neighbours[i].id = -1; - PathNodes[x].Neighbours[i].Teleport = 0; - } - - for(int z = 0; z < PATHNODENEIGHBOURS; ++z) - { - PathNodes[x].Neighbours[z].distance = Neigh[z].distance; - PathNodes[x].Neighbours[z].DoorID = Neigh[z].DoorID; - PathNodes[x].Neighbours[z].id = Neigh[z].id; - PathNodes[x].Neighbours[z].Teleport = Neigh[z].Teleport; - } - } -} - -void PathManager::QuickConnect(Client *c, bool set) -{ - if(!c) - { - return; - } - - if(!c->GetTarget()) - { - c->Message(0, "You must target a node."); - return; - } - - PathNode *Node = zone->pathing->FindPathNodeByCoordinates(c->GetTarget()->GetX(), c->GetTarget()->GetY(), c->GetTarget()->GetZ()); - if(!Node) - { - return; - } - - if(set) - { - c->Message(0, "Setting %i to the quick connect target", Node->id); - QuickConnectTarget = Node->id; - } - else - { - if(QuickConnectTarget >= 0) - { - ConnectNodeToNode(QuickConnectTarget, Node->id); - } - } -} - -struct InternalPathSort -{ - int16 old_id; - int16 new_id; -}; - -void PathManager::SortNodes() -{ - std::vector sorted_vals; - for(uint32 x = 0; x < Head.PathNodeCount; ++x) - { - InternalPathSort tmp; - tmp.old_id = PathNodes[x].id; - sorted_vals.push_back(tmp); - } - - PathNode *t_PathNodes = new PathNode[Head.PathNodeCount]; - memcpy(t_PathNodes, PathNodes, sizeof(PathNode)*Head.PathNodeCount); - for(uint32 i = 0; i < Head.PathNodeCount; ++i) - { - for(size_t j = 0; j < sorted_vals.size(); ++j) - { - if(sorted_vals[j].old_id == PathNodes[i].id) - { - if(i != PathNodes[i].id) - { - printf("Assigning new id of index %i differs from old id %i\n", i, PathNodes[i].id); - } - sorted_vals[j].new_id = i; - } - } - t_PathNodes[i].id = i; - } - - for(uint32 y = 0; y < Head.PathNodeCount; ++y) - { - for(int z = 0; z < PATHNODENEIGHBOURS; ++z) - { - if(PathNodes[y].Neighbours[z].id != -1) - { - int new_val = -1; - for(size_t c = 0; c < sorted_vals.size(); ++c) - { - if(PathNodes[y].Neighbours[z].id == sorted_vals[c].old_id) - { - new_val = sorted_vals[c].new_id; - break; - } - } - if(new_val != -1) - { - if(t_PathNodes[y].Neighbours[z].id != new_val) - { - printf("changing neighbor value to %i from %i\n", new_val, t_PathNodes[y].Neighbours[z].id); - } - t_PathNodes[y].Neighbours[z].id = new_val; - } - } - } - } - safe_delete_array(PathNodes); - PathNodes = t_PathNodes; -} - diff --git a/zone/pathing.h b/zone/pathing.h index c6cfd9c26..682fb54c6 100644 --- a/zone/pathing.h +++ b/zone/pathing.h @@ -74,10 +74,8 @@ public: void OpenDoors(int Node1, int Node2, Mob* ForWho); PathNode* FindPathNodeByCoordinates(float x, float y, float z); - void ShowPathNodeNeighbours(Client *c); int GetRandomPathNode(); - void NodeInfo(Client *c); int32 AddNode(float x, float y, float z, float best_z, int32 requested_id = 0); //return -1 on failure, else returns the id of this node bool DeleteNode(Client *c); bool DeleteNode(int32 id); //returns true on success, false on failure, tries to delete a node from this map diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 6bd1cfe9d..01c8c17f6 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -670,79 +670,6 @@ void QuestManager::repopzone() { } } -void QuestManager::ConnectNodeToNode(int node1, int node2, int teleport, int doorid) { - if (!node1 || !node2) - { - Log.Out(Logs::General, Logs::Quests, "QuestManager::ConnectNodeToNode called without node1 or node2. Probably syntax error in quest file."); - } - else - { - if (!teleport) - { - teleport = 0; - } - else if (teleport == 1 || teleport == -1) - { - teleport = -1; - } - - if (!doorid) - { - doorid = 0; - } - - if (!zone->pathing) - { - // if no pathing bits available, make them available. - zone->pathing = new PathManager(); - } - - if (zone->pathing) - { - zone->pathing->ConnectNodeToNode(node1, node2, teleport, doorid); - Log.Out(Logs::Moderate, Logs::Quests, "QuestManager::ConnectNodeToNode connecting node %i to node %i.", node1, node2); - } - } -} - -void QuestManager::AddNode(float x, float y, float z, float best_z, int32 requested_id) -{ - if (!x || !y || !z) - { - Log.Out(Logs::General, Logs::Quests, "QuestManager::AddNode called without x, y, z. Probably syntax error in quest file."); - } - - if (!best_z || best_z == 0) - { - if (zone->zonemap) - { - glm::vec3 loc(x, y, z); - best_z = zone->zonemap->FindBestZ(loc, nullptr); - } - else - { - best_z = z; - } - } - - if (!requested_id) - { - requested_id = 0; - } - - if (!zone->pathing) - { - // if no pathing bits available, make them available. - zone->pathing = new PathManager(); - } - - if (zone->pathing) - { - zone->pathing->AddNode(x, y, z, best_z, requested_id); - Log.Out(Logs::Moderate, Logs::Quests, "QuestManager::AddNode adding node at (%i, %i, %i).", x, y, z); - } -} - void QuestManager::settarget(const char *type, int target_id) { QuestManagerCurrentQuestVars(); if (!owner || !owner->IsNPC()) diff --git a/zone/questmgr.h b/zone/questmgr.h index a4cc2a38b..3b2707be9 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -87,8 +87,6 @@ public: void depopall(int npc_type = 0); void depopzone(bool StartSpawnTimer = true); void repopzone(); - void ConnectNodeToNode(int node1, int node2, int teleport, int doorid); - void AddNode(float x, float y, float z, float best_z, int32 requested_id); void settarget(const char *type, int target_id); void follow(int entity_id, int distance); void sfollow(); diff --git a/zone/zone.cpp b/zone/zone.cpp index 44d2078ba..dc24ff603 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -42,7 +42,6 @@ #include "net.h" #include "npc.h" #include "object.h" -#include "pathing.h" #include "petitions.h" #include "quest_parser_collection.h" #include "spawn2.h" @@ -102,8 +101,7 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { } zone->zonemap = Map::LoadMapFile(zone->map_name); zone->watermap = WaterMap::LoadWaterMapfile(zone->map_name); - zone->pathing = PathManager::LoadPathFile(zone->map_name); - zone->pathing_new.Load(zone->map_name); + zone->pathing.Load(zone->map_name); char tmp[10]; if (database.GetVariable("loglevel",tmp, 9)) { @@ -756,7 +754,6 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name) pers_instance = false; zonemap = nullptr; watermap = nullptr; - pathing = nullptr; qGlobals = nullptr; default_ruleset = 0; @@ -845,7 +842,6 @@ Zone::~Zone() { spawn2_list.Clear(); safe_delete(zonemap); safe_delete(watermap); - safe_delete(pathing); if (worldserver.Connected()) { worldserver.SetZoneData(0); } diff --git a/zone/zone.h b/zone/zone.h index 5b7115d82..66ee85244 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -25,6 +25,7 @@ #include "../common/random.h" #include "../common/string_util.h" #include "../common/pathfind.h" +#include "map.h" #include "qglobals.h" #include "spawn2.h" #include "spawngroup.h" @@ -212,8 +213,7 @@ public: Map* zonemap; WaterMap* watermap; - PathManager *pathing; - PathfindingManager pathing_new; + PathfindingManager pathing; NewZone_Struct newzone_data; SpawnConditionManager spawn_conditions;