mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 23:01:30 +00:00
smoother NPC pathing. (credit to Haynar from EQMacEmu)
This commit is contained in:
parent
cc2a60feb2
commit
052f343e4d
@ -1129,6 +1129,7 @@ public:
|
|||||||
inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); }
|
inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); }
|
||||||
void DragCorpses();
|
void DragCorpses();
|
||||||
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
|
inline void ClearDraggedCorpses() { DraggedCorpses.clear(); }
|
||||||
|
inline void ResetPositionTimer() { position_timer_counter = 0; }
|
||||||
void SendAltCurrencies();
|
void SendAltCurrencies();
|
||||||
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
|
void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount);
|
||||||
void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0);
|
void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0);
|
||||||
|
|||||||
37
zone/map.cpp
37
zone/map.cpp
@ -64,7 +64,7 @@ Map::~Map() {
|
|||||||
|
|
||||||
float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const {
|
float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const {
|
||||||
if (!imp)
|
if (!imp)
|
||||||
return false;
|
return BEST_Z_INVALID;
|
||||||
|
|
||||||
glm::vec3 tmp;
|
glm::vec3 tmp;
|
||||||
if(!result)
|
if(!result)
|
||||||
@ -93,6 +93,41 @@ float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const {
|
|||||||
return BEST_Z_INVALID;
|
return BEST_Z_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Map::FindClosestZ(glm::vec3 &start, glm::vec3 *result) const {
|
||||||
|
// Unlike FindBestZ, this method finds the closest Z value above or below the specified point.
|
||||||
|
//
|
||||||
|
if (!imp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float ClosestZ = BEST_Z_INVALID;
|
||||||
|
|
||||||
|
glm::vec3 tmp;
|
||||||
|
if (!result)
|
||||||
|
result = &tmp;
|
||||||
|
|
||||||
|
glm::vec3 from(start.x, start.y, start.z);
|
||||||
|
glm::vec3 to(start.x, start.y, BEST_Z_INVALID);
|
||||||
|
float hit_distance;
|
||||||
|
bool hit = false;
|
||||||
|
|
||||||
|
// first check is below us
|
||||||
|
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
|
||||||
|
if (hit) {
|
||||||
|
ClosestZ = result->z;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find nearest Z above us
|
||||||
|
to.z = -BEST_Z_INVALID;
|
||||||
|
hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance);
|
||||||
|
if (hit) {
|
||||||
|
if (abs(from.z - result->z) < abs(ClosestZ - from.z))
|
||||||
|
return result->z;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClosestZ;
|
||||||
|
}
|
||||||
|
|
||||||
bool Map::LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const {
|
bool Map::LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const {
|
||||||
if(!imp)
|
if(!imp)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -34,6 +34,7 @@ public:
|
|||||||
~Map();
|
~Map();
|
||||||
|
|
||||||
float FindBestZ(glm::vec3 &start, glm::vec3 *result) const;
|
float FindBestZ(glm::vec3 &start, glm::vec3 *result) const;
|
||||||
|
float FindClosestZ(glm::vec3 &start, glm::vec3 *result) const;
|
||||||
bool LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const;
|
bool LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const;
|
||||||
bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const;
|
bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const;
|
||||||
bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const;
|
bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const;
|
||||||
|
|||||||
@ -1201,6 +1201,7 @@ void Mob::SendPosition()
|
|||||||
PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)app->pBuffer;
|
PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)app->pBuffer;
|
||||||
MakeSpawnUpdateNoDelta(spu);
|
MakeSpawnUpdateNoDelta(spu);
|
||||||
move_tic_count = 0;
|
move_tic_count = 0;
|
||||||
|
tar_ndx = 20;
|
||||||
entity_list.QueueClients(this, app, true);
|
entity_list.QueueClients(this, app, true);
|
||||||
safe_delete(app);
|
safe_delete(app);
|
||||||
}
|
}
|
||||||
|
|||||||
148
zone/mob_ai.cpp
148
zone/mob_ai.cpp
@ -1666,92 +1666,41 @@ void NPC::AI_DoMovement() {
|
|||||||
|
|
||||||
if (gridno > 0 || cur_wp==-2) {
|
if (gridno > 0 || cur_wp==-2) {
|
||||||
if (movetimercompleted==true) { // time to pause at wp is over
|
if (movetimercompleted==true) { // time to pause at wp is over
|
||||||
|
AI_SetupNextWaypoint();
|
||||||
int32 spawn_id = this->GetSpawnPointID();
|
|
||||||
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
|
||||||
iterator.Reset();
|
|
||||||
Spawn2 *found_spawn = nullptr;
|
|
||||||
|
|
||||||
while(iterator.MoreElements())
|
|
||||||
{
|
|
||||||
Spawn2* cur = iterator.GetData();
|
|
||||||
iterator.Advance();
|
|
||||||
if(cur->GetID() == spawn_id)
|
|
||||||
{
|
|
||||||
found_spawn = cur;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) {
|
|
||||||
CastToNPC()->Depop(true); //depop and resart spawn timer
|
|
||||||
if(found_spawn)
|
|
||||||
found_spawn->SetNPCPointerNull();
|
|
||||||
}
|
|
||||||
else if (wandertype == 6 && cur_wp == CastToNPC()->GetMaxWp()) {
|
|
||||||
CastToNPC()->Depop(false);//depop without spawn timer
|
|
||||||
if(found_spawn)
|
|
||||||
found_spawn->SetNPCPointerNull();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
movetimercompleted=false;
|
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Pathing, "We are departing waypoint %d.", cur_wp);
|
|
||||||
|
|
||||||
//if we were under quest control (with no grid), we are done now..
|
|
||||||
if(cur_wp == -2) {
|
|
||||||
Log.Out(Logs::Detail, Logs::Pathing, "Non-grid quest mob has reached its quest ordered waypoint. Leaving pathing mode.");
|
|
||||||
roamer = false;
|
|
||||||
cur_wp = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(GetAppearance() != eaStanding)
|
|
||||||
SetAppearance(eaStanding, false);
|
|
||||||
|
|
||||||
entity_list.OpenDoorsNear(CastToNPC());
|
|
||||||
|
|
||||||
if(!DistractedFromGrid) {
|
|
||||||
//kick off event_waypoint depart
|
|
||||||
char temp[16];
|
|
||||||
sprintf(temp, "%d", cur_wp);
|
|
||||||
parse->EventNPC(EVENT_WAYPOINT_DEPART, CastToNPC(), nullptr, temp, 0);
|
|
||||||
|
|
||||||
//setup our next waypoint, if we are still on our normal grid
|
|
||||||
//remember that the quest event above could have done anything it wanted with our grid
|
|
||||||
if(gridno > 0) {
|
|
||||||
CastToNPC()->CalculateNewWaypoint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DistractedFromGrid = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // endif (movetimercompleted==true)
|
} // endif (movetimercompleted==true)
|
||||||
else if (!(AIwalking_timer->Enabled()))
|
else if (!(AIwalking_timer->Enabled()))
|
||||||
{ // currently moving
|
{ // currently moving
|
||||||
|
bool doMove = true;
|
||||||
if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY())
|
if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY())
|
||||||
{ // are we there yet? then stop
|
{ // are we there yet? then stop
|
||||||
Log.Out(Logs::Detail, Logs::AI, "We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d", cur_wp, GetX(), GetY(), GetZ(), GetGrid());
|
Log.Out(Logs::Detail, Logs::AI, "We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d", cur_wp, GetX(), GetY(), GetZ(), GetGrid());
|
||||||
SetWaypointPause();
|
if (cur_wp_pause != 0) {
|
||||||
if(GetAppearance() != eaStanding)
|
SetWaypointPause();
|
||||||
SetAppearance(eaStanding, false);
|
if (GetAppearance() != eaStanding)
|
||||||
SetMoving(false);
|
SetAppearance(eaStanding, false);
|
||||||
if (m_CurrentWayPoint.w >= 0.0) {
|
SetMoving(false);
|
||||||
SetHeading(m_CurrentWayPoint.w);
|
if (m_CurrentWayPoint.w >= 0.0) {
|
||||||
|
SetHeading(m_CurrentWayPoint.w);
|
||||||
|
}
|
||||||
|
SendPosition();
|
||||||
}
|
}
|
||||||
SendPosition();
|
|
||||||
|
|
||||||
//kick off event_waypoint arrive
|
//kick off event_waypoint arrive
|
||||||
char temp[16];
|
char temp[16];
|
||||||
sprintf(temp, "%d", cur_wp);
|
sprintf(temp, "%d", cur_wp);
|
||||||
parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0);
|
parse->EventNPC(EVENT_WAYPOINT_ARRIVE, CastToNPC(), nullptr, temp, 0);
|
||||||
|
// start moving directly to next waypoint if we're at a 0 pause waypoint and we didn't get quest halted.
|
||||||
|
if (!AIwalking_timer->Enabled())
|
||||||
|
AI_SetupNextWaypoint();
|
||||||
|
else
|
||||||
|
doMove = false;
|
||||||
|
|
||||||
// wipe feign memory since we reached our first waypoint
|
// wipe feign memory since we reached our first waypoint
|
||||||
if(cur_wp == 1)
|
if(cur_wp == 1)
|
||||||
ClearFeignMemory();
|
ClearFeignMemory();
|
||||||
}
|
}
|
||||||
else
|
if (doMove)
|
||||||
{ // not at waypoint yet, so keep moving
|
{ // not at waypoint yet or at 0 pause WP, so keep moving
|
||||||
if(!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0))
|
if(!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0))
|
||||||
CalculateNewPosition2(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true);
|
CalculateNewPosition2(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true);
|
||||||
else
|
else
|
||||||
@ -1829,6 +1778,67 @@ void NPC::AI_DoMovement() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void NPC::AI_SetupNextWaypoint() {
|
||||||
|
int32 spawn_id = this->GetSpawnPointID();
|
||||||
|
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
||||||
|
iterator.Reset();
|
||||||
|
Spawn2 *found_spawn = nullptr;
|
||||||
|
|
||||||
|
while (iterator.MoreElements())
|
||||||
|
{
|
||||||
|
Spawn2* cur = iterator.GetData();
|
||||||
|
iterator.Advance();
|
||||||
|
if (cur->GetID() == spawn_id)
|
||||||
|
{
|
||||||
|
found_spawn = cur;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||||
|
CastToNPC()->Depop(true); //depop and restart spawn timer
|
||||||
|
if (found_spawn)
|
||||||
|
found_spawn->SetNPCPointerNull();
|
||||||
|
}
|
||||||
|
else if (wandertype == 6 && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||||
|
CastToNPC()->Depop(false);//depop without spawn timer
|
||||||
|
if (found_spawn)
|
||||||
|
found_spawn->SetNPCPointerNull();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
movetimercompleted = false;
|
||||||
|
|
||||||
|
Log.Out(Logs::Detail, Logs::Pathing, "We are departing waypoint %d.", cur_wp);
|
||||||
|
|
||||||
|
//if we were under quest control (with no grid), we are done now..
|
||||||
|
if (cur_wp == -2) {
|
||||||
|
Log.Out(Logs::Detail, Logs::Pathing, "Non-grid quest mob has reached its quest ordered waypoint. Leaving pathing mode.");
|
||||||
|
roamer = false;
|
||||||
|
cur_wp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetAppearance() != eaStanding)
|
||||||
|
SetAppearance(eaStanding, false);
|
||||||
|
|
||||||
|
entity_list.OpenDoorsNear(CastToNPC());
|
||||||
|
|
||||||
|
if (!DistractedFromGrid) {
|
||||||
|
//kick off event_waypoint depart
|
||||||
|
char temp[16];
|
||||||
|
sprintf(temp, "%d", cur_wp);
|
||||||
|
parse->EventNPC(EVENT_WAYPOINT_DEPART, CastToNPC(), nullptr, temp, 0);
|
||||||
|
|
||||||
|
//setup our next waypoint, if we are still on our normal grid
|
||||||
|
//remember that the quest event above could have done anything it wanted with our grid
|
||||||
|
if (GetGrid() > 0) {
|
||||||
|
CastToNPC()->CalculateNewWaypoint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DistractedFromGrid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Note: Mob that caused this may not get added to the hate list until after this function call completes
|
// Note: Mob that caused this may not get added to the hate list until after this function call completes
|
||||||
void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) {
|
void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) {
|
||||||
|
|||||||
@ -119,6 +119,7 @@ public:
|
|||||||
virtual void AI_Start(uint32 iMoveDelay = 0);
|
virtual void AI_Start(uint32 iMoveDelay = 0);
|
||||||
virtual void AI_Stop();
|
virtual void AI_Stop();
|
||||||
void AI_DoMovement();
|
void AI_DoMovement();
|
||||||
|
void AI_SetupNextWaypoint();
|
||||||
bool AI_AddNPCSpells(uint32 iDBSpellsID);
|
bool AI_AddNPCSpells(uint32 iDBSpellsID);
|
||||||
bool AI_AddNPCSpellsEffects(uint32 iDBSpellsEffectsID);
|
bool AI_AddNPCSpellsEffects(uint32 iDBSpellsEffectsID);
|
||||||
virtual bool AI_EngagedCastCheck();
|
virtual bool AI_EngagedCastCheck();
|
||||||
|
|||||||
@ -394,6 +394,7 @@ void NPC::SetWaypointPause()
|
|||||||
|
|
||||||
if (cur_wp_pause == 0) {
|
if (cur_wp_pause == 0) {
|
||||||
AIwalking_timer->Start(100);
|
AIwalking_timer->Start(100);
|
||||||
|
AIwalking_timer->Trigger();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -514,7 +515,9 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool send_update = false;
|
||||||
int compare_steps = IsBoat() ? 1 : 20;
|
int compare_steps = IsBoat() ? 1 : 20;
|
||||||
|
|
||||||
if(tar_ndx < compare_steps && m_TargetLocation.x==x && m_TargetLocation.y==y) {
|
if(tar_ndx < compare_steps && m_TargetLocation.x==x && m_TargetLocation.y==y) {
|
||||||
|
|
||||||
float new_x = m_Position.x + m_TargetV.x*tar_vector;
|
float new_x = m_Position.x + m_TargetV.x*tar_vector;
|
||||||
@ -637,13 +640,14 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
|||||||
m_Position.y = y;
|
m_Position.y = y;
|
||||||
m_Position.z = z;
|
m_Position.z = z;
|
||||||
|
|
||||||
|
tar_ndx = 20;
|
||||||
Log.Out(Logs::Detail, Logs::AI, "Only a single step to get there... jumping.");
|
Log.Out(Logs::Detail, Logs::AI, "Only a single step to get there... jumping.");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
tar_vector/=20;
|
tar_vector/=20.0f;
|
||||||
|
|
||||||
float new_x = m_Position.x + m_TargetV.x*tar_vector;
|
float new_x = m_Position.x + m_TargetV.x*tar_vector;
|
||||||
float new_y = m_Position.y + m_TargetV.y*tar_vector;
|
float new_y = m_Position.y + m_TargetV.y*tar_vector;
|
||||||
@ -699,12 +703,19 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
|
|||||||
m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f);
|
m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f);
|
||||||
|
|
||||||
if (IsClient())
|
if (IsClient())
|
||||||
|
{
|
||||||
SendPosUpdate(1);
|
SendPosUpdate(1);
|
||||||
|
CastToClient()->ResetPositionTimer();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
// force an update now
|
||||||
|
move_tic_count = RuleI(Zone, NPCPositonUpdateTicCount);
|
||||||
SendPosUpdate();
|
SendPosUpdate();
|
||||||
|
SetAppearance(eaStanding, false);
|
||||||
SetAppearance(eaStanding, false);
|
}
|
||||||
pLastChange = Timer::GetCurrentTime();
|
pLastChange = Timer::GetCurrentTime();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user