[10358] A small spoon of changes and cleanup for WaypointMovementGenerator

* Initialization to ensure destination is always set (prevent evade problem)
* Simplify how behavior for node is processed, incl fix MovementInform script call (based on idea/past code from Quriq14)
* Make sure last node is also processed correct (DB script for last node will now work as expected)

As usual if any problems occur, you can call our toll free customer support number.

Signed-off-by: NoFantasy <nofantasy@nf.no>
This commit is contained in:
NoFantasy 2010-08-14 23:38:20 +02:00
parent 9c07bb1314
commit 647f731e3b
3 changed files with 71 additions and 69 deletions

View file

@ -44,55 +44,51 @@ alter table creature_movement add `wpguid` int(11) default '0';
#include <cassert> #include <cassert>
//-----------------------------------------------// //-----------------------------------------------//
void WaypointMovementGenerator<Creature>::LoadPath(Creature &c) void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature)
{ {
DETAIL_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "LoadPath: loading waypoint path for creature %u, %u", c.GetGUIDLow(), c.GetDBTableGUIDLow()); DETAIL_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "LoadPath: loading waypoint path for creature %u, %u", creature.GetGUIDLow(), creature.GetDBTableGUIDLow());
i_path = sWaypointMgr.GetPath(c.GetDBTableGUIDLow()); i_path = sWaypointMgr.GetPath(creature.GetDBTableGUIDLow());
if (!i_path) if (!i_path)
{ {
sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path", sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path",
c.GetName(), c.GetEntry(), c.GetDBTableGUIDLow()); creature.GetName(), creature.GetEntry(), creature.GetDBTableGUIDLow());
return; return;
} }
uint32 node_count = i_path->size(); // We have to set the destination here (for the first point), right after Initialize. Without, we may not have valid xyz for GetResetPosition
i_hasDone.resize(node_count); CreatureTraveller traveller(creature);
for(uint32 i = 0; i < node_count-1; ++i) if (creature.canFly())
i_hasDone[i] = false; creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);
// to prevent a misbehavior inside "update" const WaypointNode &node = i_path->at(i_currentNode);
// update is always called with the next wp - but the wpSys needs the current i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
// so when the routine is called the first time, wpSys gets the last waypoint i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
// and this prevents the system from performing text/emote, etc
i_hasDone[node_count - 1] = true;
} }
void WaypointMovementGenerator<Creature>::Initialize( Creature &u ) void WaypointMovementGenerator<Creature>::Initialize(Creature &creature)
{ {
i_nextMoveTime.Reset(0); // TODO: check the lower bound (0 is probably too small) LoadPath(creature);
u.StopMoving(); creature.addUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
LoadPath(u);
u.addUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
} }
void WaypointMovementGenerator<Creature>::Finalize( Creature &u ) void WaypointMovementGenerator<Creature>::Finalize(Creature &creature)
{ {
u.clearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); creature.clearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
} }
void WaypointMovementGenerator<Creature>::Interrupt( Creature &u ) void WaypointMovementGenerator<Creature>::Interrupt(Creature &creature)
{ {
u.clearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); creature.clearUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
} }
void WaypointMovementGenerator<Creature>::Reset( Creature &u ) void WaypointMovementGenerator<Creature>::Reset(Creature &creature)
{ {
b_StoppedByPlayer = false; SetStoppedByPlayer(false);
i_nextMoveTime.Reset(0); i_nextMoveTime.Reset(0);
u.addUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); creature.addUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE);
} }
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
@ -115,16 +111,16 @@ bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint3
return true; return true;
} }
// i_path was modified by chat commands for example
if (i_path->size() != i_hasDone.size())
i_hasDone.resize(i_path->size());
if (i_currentNode >= i_path->size()) if (i_currentNode >= i_path->size())
{
sLog.outError("WaypointMovement currentNode (%u) is equal or bigger than path size (creature entry %u)", i_currentNode, creature.GetEntry());
i_currentNode = 0; i_currentNode = 0;
}
CreatureTraveller traveller(creature); CreatureTraveller traveller(creature);
i_nextMoveTime.Update(diff); i_nextMoveTime.Update(diff);
if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true)) if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true))
{ {
if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list)
@ -165,20 +161,19 @@ bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint3
if (creature.IsStopped()) if (creature.IsStopped())
{ {
uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; if (!m_isArrivalDone)
if (!i_hasDone[idx])
{ {
if (i_path->at(idx).orientation != 100) if (i_path->at(i_currentNode).orientation != 100)
creature.SetOrientation(i_path->at(idx).orientation); creature.SetOrientation(i_path->at(i_currentNode).orientation);
if (i_path->at(idx).script_id) if (i_path->at(i_currentNode).script_id)
{ {
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for creature %u (entry %u).", i_path->at(idx).script_id, idx, creature.GetDBTableGUIDLow(), creature.GetEntry()); DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for creature %u (entry %u).", i_path->at(i_currentNode).script_id, i_currentNode, creature.GetDBTableGUIDLow(), creature.GetEntry());
creature.GetMap()->ScriptsStart(sCreatureMovementScripts, i_path->at(idx).script_id, &creature, &creature); creature.GetMap()->ScriptsStart(sCreatureMovementScripts, i_path->at(i_currentNode).script_id, &creature, &creature);
} }
if (WaypointBehavior *behavior = i_path->at(idx).behavior) // We have reached the destination and can process behavior
if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior)
{ {
if (behavior->emote != 0) if (behavior->emote != 0)
creature.HandleEmote(behavior->emote); creature.HandleEmote(behavior->emote);
@ -214,7 +209,10 @@ bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint3
} }
} // wpBehaviour found } // wpBehaviour found
i_hasDone[idx] = true; // Can only do this once for the node
m_isArrivalDone = true;
// Inform script
MovementInform(creature); MovementInform(creature);
if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list)
@ -226,10 +224,10 @@ bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint3
creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);
return true; return true;
} }
} // HasDone == false }
} // i_creature.IsStopped() } // i_creature.IsStopped()
// This is at the end of waypoint segment or has been stopped by player // This is at the end of waypoint segment (incl. was previously stopped by player, extending the time)
if (i_nextMoveTime.Passed()) if (i_nextMoveTime.Passed())
{ {
// If stopped then begin a new move segment // If stopped then begin a new move segment
@ -240,48 +238,53 @@ bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint3
if (creature.canFly()) if (creature.canFly())
creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7);
const WaypointNode &node = i_path->at(i_currentNode); if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior)
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;
if (i_path->at(idx).orientation != 100)
creature.SetOrientation(i_path->at(idx).orientation);
if (WaypointBehavior *behavior = i_path->at(idx).behavior)
{ {
i_hasDone[idx] = false;
if (behavior->model2 != 0) if (behavior->model2 != 0)
creature.SetDisplayId(behavior->model2); creature.SetDisplayId(behavior->model2);
creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
} }
// behavior for "departure" of the current node is done
m_isArrivalDone = false;
// Proceed with increment current node and then send to the next destination
++i_currentNode;
// Oops, end of the line so need to start from the beginning
if (i_currentNode >= i_path->size())
i_currentNode = 0;
if (i_path->at(i_currentNode).orientation != 100)
creature.SetOrientation(i_path->at(i_currentNode).orientation);
const WaypointNode &node = i_path->at(i_currentNode);
i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
} }
else else
{ {
// If not stopped then stop it and set the reset of TimeTracker to waittime // If not stopped then stop it
creature.StopMoving(); creature.StopMoving();
SetStoppedByPlayer(false); SetStoppedByPlayer(false);
// Set TimeTracker to waittime for the current node
i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); i_nextMoveTime.Reset(i_path->at(i_currentNode).delay);
++i_currentNode;
if (i_currentNode >= i_path->size())
i_currentNode = 0;
} }
} }
return true; return true;
} }
void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit) void WaypointMovementGenerator<Creature>::MovementInform(Creature &creature)
{ {
if (unit.AI()) if (creature.AI())
unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); creature.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
} }
bool WaypointMovementGenerator<Creature>::GetResetPosition( Creature&, float& x, float& y, float& z ) bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x, float& y, float& z)
{ {
return PathMovementBase<Creature, WaypointPath const*>::GetPosition(x,y,z); return PathMovementBase<Creature, WaypointPath const*>::GetPosition(x,y,z);
} }

View file

@ -74,7 +74,7 @@ class MANGOS_DLL_SPEC WaypointMovementGenerator<Creature>
public PathMovementBase<Creature, WaypointPath const*> public PathMovementBase<Creature, WaypointPath const*>
{ {
public: public:
WaypointMovementGenerator(Creature &) : i_nextMoveTime(0), b_StoppedByPlayer(false) {} WaypointMovementGenerator(Creature &) : i_nextMoveTime(0), m_isArrivalDone(false), m_isStoppedByPlayer(false) {}
~WaypointMovementGenerator() { i_path = NULL; } ~WaypointMovementGenerator() { i_path = NULL; }
void Initialize(Creature &u); void Initialize(Creature &u);
void Interrupt(Creature &); void Interrupt(Creature &);
@ -90,8 +90,8 @@ public PathMovementBase<Creature, WaypointPath const*>
void LoadPath(Creature &c); void LoadPath(Creature &c);
// Player stoping creature // Player stoping creature
bool IsStoppedByPlayer() { return b_StoppedByPlayer; } bool IsStoppedByPlayer() { return m_isStoppedByPlayer; }
void SetStoppedByPlayer(bool val) { b_StoppedByPlayer = val; } void SetStoppedByPlayer(bool val) { m_isStoppedByPlayer = val; }
// allow use for overwrite empty implementation // allow use for overwrite empty implementation
bool GetDestination(float& x, float& y, float& z) const { return PathMovementBase<Creature, WaypointPath const*>::GetDestination(x,y,z); } bool GetDestination(float& x, float& y, float& z) const { return PathMovementBase<Creature, WaypointPath const*>::GetDestination(x,y,z); }
@ -99,10 +99,9 @@ public PathMovementBase<Creature, WaypointPath const*>
bool GetResetPosition(Creature&, float& x, float& y, float& z); bool GetResetPosition(Creature&, float& x, float& y, float& z);
private: private:
TimeTrackerSmall i_nextMoveTime; TimeTrackerSmall i_nextMoveTime;
std::vector<bool> i_hasDone; bool m_isArrivalDone;
bool b_StoppedByPlayer; bool m_isStoppedByPlayer;
}; };
/** FlightPathMovementGenerator generates movement of the player for the paths /** FlightPathMovementGenerator generates movement of the player for the paths

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "10357" #define REVISION_NR "10358"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__