From 973abef1b058d5e34400a4c1118259e60fb12dd2 Mon Sep 17 00:00:00 2001 From: KimLS Date: Thu, 18 Oct 2018 20:44:46 -0700 Subject: [PATCH] Water work and work with grids (still not perfect but i think its the ai code) --- zone/attack.cpp | 6 -- zone/mob.h | 1 + zone/mob_ai.cpp | 4 +- zone/mob_movement_manager.cpp | 136 ++++++++++++++++++++++++---------- zone/npc.h | 2 +- zone/waypoints.cpp | 1 - 6 files changed, 100 insertions(+), 50 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index d6cf4227f..f5a126b32 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2667,12 +2667,6 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b } } } - - if (IsNPC() && CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) { - if (!zone->watermap->InLiquid(glm::vec3(other->GetPosition()))) { - return; - } - } // first add self // The damage on the hate list is used to award XP to the killer. This check is to prevent Killstealing. diff --git a/zone/mob.h b/zone/mob.h index 0a56bbd84..d1bd23145 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1061,6 +1061,7 @@ public: void SetCurrentWP(uint16 waypoint) { cur_wp = waypoint; } virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther) { return FACTION_INDIFFERENT; } + virtual const bool IsUnderwaterOnly() const { return false; } inline bool IsTrackable() const { return(trackable); } Timer* GetAIThinkTimer() { return AI_think_timer.get(); } Timer* GetAIMovementTimer() { return AI_movement_timer.get(); } diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index e7cccf320..8e2e3e029 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1710,7 +1710,7 @@ void NPC::AI_DoMovement() { SetWaypointPause(); SetAppearance(eaStanding, false); - if (m_CurrentWayPoint.w >= 0.0) { + if (cur_wp_pause > 0 && m_CurrentWayPoint.w >= 0.0) { RotateTo(m_CurrentWayPoint.w); } @@ -1756,7 +1756,7 @@ void NPC::AI_DoMovement() { } else if (IsGuarding()) { - bool at_gp = IsPositionEqualWithinCertainZ(m_Position, m_GuardPoint, 5.0f); + bool at_gp = IsPositionEqualWithinCertainZ(m_Position, m_GuardPoint, 15.0f); if (at_gp) { diff --git a/zone/mob_movement_manager.cpp b/zone/mob_movement_manager.cpp index 50aad279f..f6b1b6b07 100644 --- a/zone/mob_movement_manager.cpp +++ b/zone/mob_movement_manager.cpp @@ -46,28 +46,29 @@ public: auto rotate_to_speed = m_rotate_to_mode == MovementRunning ? 50.0 : 16.0; //todo: get this from mob + auto from = FixHeading(m->GetHeading()); + auto to = FixHeading(m_rotate_to); + auto diff = to - from; + + while (diff < -256.0) { + diff += 512.0; + } + + while (diff > 256) { + diff -= 512.0; + } + + auto dist = std::abs(diff); + if (!m_started) { m_started = true; m->SetMoving(true); - if (rotate_to_speed > 0.0 && rotate_to_speed <= 25.0) { //send basic rotation + if (dist > 15.0f && rotate_to_speed > 0.0 && rotate_to_speed <= 25.0) { //send basic rotation mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, m_rotate_to_dir * rotate_to_speed, 0, ClientRangeClose); } } - auto from = FixHeading(m->GetHeading()); - auto to = FixHeading(m_rotate_to); - auto diff = to - from; - - while (diff < -256.0) { - diff += 512.0; - } - - while (diff > 256) { - diff -= 512.0; - } - - auto dist = std::abs(diff); auto td = rotate_to_speed * 19.0 * frame_time; if (td >= dist) { @@ -604,51 +605,106 @@ void MobMovementManager::FillCommandStruct(PlayerPositionUpdateServer_Struct *sp void MobMovementManager::UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mode) { + //If who is underwater & xyz is underwater & who can see xyz + //Create a route directly from who to xyz + //else + //Create Route + if (zone->HasMap() && zone->HasWaterMap()) { + if (zone->watermap->InLiquid(who->GetPosition()) && zone->watermap->InLiquid(glm::vec3(x, y, z)) && zone->zonemap->CheckLoS(who->GetPosition(), glm::vec3(x, y, z))) { + auto iter = _impl->Entries.find(who); + auto &ent = (*iter); + + PushMoveTo(ent.second, x, y, z, mode); + return; + } + } + bool partial = false; bool stuck = false; auto route = zone->pathing->FindRoute(glm::vec3(who->GetX(), who->GetY(), who->GetZ()), glm::vec3(x, y, z), partial, stuck); - + + //if route empty then return if (route.empty()) { return; } auto &first = route.front(); + auto &last = route.back(); - //if who is already at the first node, then cull it - if (IsPositionEqualWithinCertainZ(glm::vec3(who->GetX(), who->GetY(), who->GetZ()), first.pos, 5.0f)) { - route.pop_front(); - } - - if (route.empty()) { - return; + if (zone->HasWaterMap()) { + //If who is underwater & who is not at the first node + //Add node at who + if (!IsPositionEqualWithinCertainZ(glm::vec3(who->GetX(), who->GetY(), who->GetZ()), first.pos, 5.0f) + && zone->watermap->InLiquid(who->GetPosition())) + { + IPathfinder::IPathNode node(who->GetPosition()); + route.push_front(node); + } + + //If xyz is underwater & xyz is not at the last node + //Add node at xyz + if (!IsPositionEqualWithinCertainZ(glm::vec3(x, y, z), last.pos, 5.0f) + && zone->watermap->InLiquid(glm::vec3(x, y, z))) + { + IPathfinder::IPathNode node(glm::vec3(x, y, z)); + route.push_back(node); + } } + //adjust route AdjustRoute(route, who->GetFlyMode(), who->GetZOffset()); - auto iter = _impl->Entries.find(who); - auto &ent = (*iter); - - first = route.front(); - //If mode = walking then rotateto first node (if possible, live does this) - if (mode == MovementWalking) { - auto h = who->CalculateHeadingToTarget(first.pos.x, first.pos.y); - PushRotateTo(ent.second, who, h, mode); - } - - //for each node create a moveto/teleport command + auto eiter = _impl->Entries.find(who); + auto &ent = (*eiter); + auto iter = route.begin(); glm::vec3 previous_pos(who->GetX(), who->GetY(), who->GetZ()); - for (auto &node : route) { - if (node.teleport) { - PushTeleportTo(ent.second, node.pos.x, node.pos.y, node.pos.z, - CalculateHeadingAngleBetweenPositions(previous_pos.x, previous_pos.y, node.pos.x, node.pos.y)); + bool first_node = true; + + //for each node + while (iter != route.end()) { + auto ¤t_node = (*iter); + + iter++; + + if (iter == route.end()) { + continue; + } + + previous_pos = current_node.pos; + auto &next_node = (*iter); + + if (first_node) { + + if (mode == MovementWalking) { + auto h = who->CalculateHeadingToTarget(next_node.pos.x, next_node.pos.y); + PushRotateTo(ent.second, who, h, mode); + } + + first_node = false; + } + //yet rotate to node + 1 + //auto h = CalculateHeadingAngleBetweenPositions(current_node.pos.x, current_node.pos.y, next_node.pos.x, next_node.pos.z); + //PushRotateTo(ent.second, who, h, mode); + + //if underwater only mob and node -> node + 1 is moving to land (terminate route, npc will go to the point where it would normally exit the water but no further) + if (who->IsUnderwaterOnly()) { + if (zone->HasWaterMap() && !zone->watermap->InLiquid(next_node.pos)) { + PushStopMoving(ent.second); + return; + } + } + + //move to / teleport to node + 1 + if (next_node.teleport) { + PushTeleportTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z, + CalculateHeadingAngleBetweenPositions(current_node.pos.x, current_node.pos.y, next_node.pos.x, next_node.pos.y)); } else { - PushMoveTo(ent.second, node.pos.x, node.pos.y, node.pos.z, mode); + PushMoveTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z, mode); } - - previous_pos = node.pos; } + //if stuck then handle stuck if (stuck) { PushTeleportTo(ent.second, x, y, z, CalculateHeadingAngleBetweenPositions(previous_pos.x, previous_pos.y, x, y)); diff --git a/zone/npc.h b/zone/npc.h index 2300217a5..5844c1a83 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -381,7 +381,7 @@ public: /* Only allows players that killed corpse to loot */ const bool HasPrivateCorpse() const { return NPCTypedata->private_corpse; } - const bool IsUnderwaterOnly() const { return NPCTypedata->underwater; } + virtual const bool IsUnderwaterOnly() const { return NPCTypedata->underwater; } const char* GetRawNPCTypeName() const { return NPCTypedata->name; } void ChangeLastName(const char* in_lastname); diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index e137b605a..c156914c8 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -392,7 +392,6 @@ void NPC::SetWaypointPause() if (cur_wp_pause == 0) { AI_walking_timer->Start(100); - AI_walking_timer->Trigger(); } else {