aboutsummaryrefslogtreecommitdiff
path: root/src/game/WaypointMovementGenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/WaypointMovementGenerator.cpp')
-rw-r--r--src/game/WaypointMovementGenerator.cpp93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp
index 990bfd46084..cba005a78d9 100644
--- a/src/game/WaypointMovementGenerator.cpp
+++ b/src/game/WaypointMovementGenerator.cpp
@@ -28,53 +28,67 @@
#include "CreatureGroups.h"
//Player-specific
#include "Player.h"
+
template<class T>
void
WaypointMovementGenerator<T>::Initialize(T &u){}
+
template<>
void
WaypointMovementGenerator<Creature>::Finalize(Creature &u){}
+
template<>
void
WaypointMovementGenerator<Player>::Finalize(Player &u){}
+
template<class T>
void
WaypointMovementGenerator<T>::MovementInform(T &unit){}
+
template<>
void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
{
unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
}
+
template<>
bool WaypointMovementGenerator<Creature>::GetDestination(float &x, float &y, float &z) const
{
if(i_destinationHolder.HasArrived())
return false;
+
i_destinationHolder.GetDestination(x, y, z);
return true;
}
+
template<>
bool WaypointMovementGenerator<Player>::GetDestination(float &x, float &y, float &z) const
{
return false;
}
+
template<>
void WaypointMovementGenerator<Creature>::Reset(Creature &unit)
{
StopedByPlayer = true;
i_nextMoveTime.Reset(0);
}
+
template<>
void WaypointMovementGenerator<Player>::Reset(Player &unit){}
+
template<>
void WaypointMovementGenerator<Creature>::InitTraveller(Creature &unit, const WaypointData &node)
{
node.run ? unit.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE):
unit.AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+
unit.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
unit.SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
+
unit.addUnitState(UNIT_STAT_ROAMING);
}
+
template<>
void
WaypointMovementGenerator<Creature>::Initialize(Creature &u)
@@ -94,6 +108,7 @@ WaypointMovementGenerator<Creature>::Initialize(Creature &u)
InitTraveller(u, *node);
i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
+
//Call for creature group update
if(u.GetFormation() && u.GetFormation()->getLeader() == &u)
u.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
@@ -101,32 +116,41 @@ WaypointMovementGenerator<Creature>::Initialize(Creature &u)
else
node = NULL;
}
+
template<>
void WaypointMovementGenerator<Player>::InitTraveller(Player &unit, const WaypointData &node){}
+
template<class T>
bool
WaypointMovementGenerator<T>::Update(T &unit, const uint32 &diff)
{
return false;
}
+
template<>
bool
WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff)
{
if(!&unit)
return true;
+
if(!path_id)
return false;
+
// Waypoint movement can be switched on/off
// This is quite handy for escort quests and other stuff
if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
return true;
+
// Clear the generator if the path doesn't exist
if(!waypoints || !waypoints->size())
return false;
+
Traveller<Creature> traveller(unit);
+
i_nextMoveTime.Update(diff);
i_destinationHolder.UpdateTraveller(traveller, diff, true);
+
if(i_nextMoveTime.Passed())
{
if(unit.IsStopped())
@@ -140,6 +164,7 @@ WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff)
StopedByPlayer = false;
return true;
}
+
if(i_currentNode == waypoints->size() - 1) //If that's our last waypoint
{
if(repeating) //If the movement is repeating
@@ -153,10 +178,12 @@ WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff)
}
else
++i_currentNode;
+
node = waypoints->at(i_currentNode);
InitTraveller(unit, *node);
i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z);
i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
+
//Call for creature group update
if(unit.GetFormation() && unit.GetFormation()->getLeader() == &unit)
unit.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
@@ -166,9 +193,11 @@ WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff)
//Determine waittime
if(node->delay)
i_nextMoveTime.Reset(node->delay);
+
//note: disable "start" for mtmap
if(node->event_id && urand(0,99) < node->event_chance)
unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/);
+
MovementInform(unit);
unit.UpdateWaypointID(i_currentNode);
unit.clearUnitState(UNIT_STAT_ROAMING);
@@ -189,26 +218,32 @@ WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff)
}
return true;
}
+
template void WaypointMovementGenerator<Player>::Initialize(Player &);
template bool WaypointMovementGenerator<Player>::Update(Player &, const uint32 &);
template void WaypointMovementGenerator<Player>::MovementInform(Player &);
+
//----------------------------------------------------//
void FlightPathMovementGenerator::LoadPath(Player &)
{
objmgr.GetTaxiPathNodes(i_pathId, i_path,i_mapIds);
}
+
uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
{
if(i_currentNode >= i_mapIds.size())
return i_mapIds.size();
+
uint32 curMapId = i_mapIds[i_currentNode];
for(uint32 i = i_currentNode; i < i_mapIds.size(); ++i)
{
if(i_mapIds[i] != curMapId)
return i;
}
+
return i_mapIds.size();
}
+
void FlightPathMovementGenerator::Initialize(Player &player)
{
player.getHostilRefManager().setOnlineOfflineState(false);
@@ -218,23 +253,31 @@ void FlightPathMovementGenerator::Initialize(Player &player)
Traveller<Player> traveller(player);
// do not send movement, it was sent already
i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false);
+
player.SendMonsterMoveByPath(GetPath(),GetCurrentNode(),GetPathAtMapEnd());
+
// Storage to preload flightmaster grid at end of flight. For multi-stop flights, this will
// be reinitialized for each flightmaster at the end of each spline (or stop) in the flight.
+
uint32 nodeCount = i_mapIds.size(); // Get the number of nodes in the path. i_path and i_mapIds are the
// same size when loaded in ObjectMgr::GetTaxiPathNodes, called from LoadPath()
+
m_endMapId = i_mapIds[nodeCount -1]; // Get the map ID from the last node
m_preloadTargetNode = nodeCount / 2; // Split the number of nodes in half to preload the flightmaster half-way through the flight
m_endGridX = i_path[nodeCount -1].x; // Get the X position from the last node
m_endGridY = i_path[nodeCount -1].y; // Get tye Y position from the last node
+
}
+
void FlightPathMovementGenerator::Finalize(Player & player)
{
player.clearUnitState(UNIT_STAT_IN_FLIGHT);
+
float x, y, z;
i_destinationHolder.GetLocationNow(player.GetBaseMap(), x, y, z);
player.SetPosition(x, y, z, player.GetOrientation());
}
+
bool FlightPathMovementGenerator::Update(Player &player, const uint32 &diff)
{
if( MovementInProgress() )
@@ -255,6 +298,7 @@ bool FlightPathMovementGenerator::Update(Player &player, const uint32 &diff)
// do not send movement, it was sent already
i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false);
}
+
// check if it's time to preload the flightmaster grid
// at path end
if (i_currentNode == m_preloadTargetNode)
@@ -271,13 +315,16 @@ bool FlightPathMovementGenerator::Update(Player &player, const uint32 &diff)
else
return true;
}
+
// we have arrived at the end of the path
return false;
}
+
void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
{
if(i_mapIds.empty())
return;
+
uint32 map0 = i_mapIds[0];
for(size_t i = 1; i < i_mapIds.size(); ++i)
{
@@ -288,10 +335,12 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
}
}
}
+
void FlightPathMovementGenerator::PreloadEndGrid()
{
// used to preload the final grid where the flightmaster is
Map *endMap = MapManager::Instance().FindMap(m_endMapId);
+
// Load the grid
if (endMap)
{
@@ -302,12 +351,17 @@ void FlightPathMovementGenerator::PreloadEndGrid()
{
sLog.outDetail("Unable to determine map to preload flightmaster grid");
}
+
}
+
//
// Unique1's ASTAR Pathfinding Code... For future use & reference...
//
+
#ifdef __PATHFINDING__
+
int GetFCost(int to, int num, int parentNum, float *gcost); // Below...
+
int ShortenASTARRoute(short int *pathlist, int number)
{ // Wrote this to make the routes a little smarter (shorter)... No point looping back to the same places... Unique1
short int temppathlist[MAX_PATHLIST_NODES];
@@ -316,19 +370,24 @@ int ShortenASTARRoute(short int *pathlist, int number)
int temp, temp2;
int link;
int upto = 0;
+
for (temp = number; temp >= 0; temp--)
{
qboolean shortened = qfalse;
+
for (temp2 = 0; temp2 < temp; temp2++)
{
for (link = 0; link < nodes[pathlist[temp]].enodenum; link++)
{
if (nodes[pathlist[temp]].links[link].flags & PATH_BLOCKED)
continue;
+
//if ((bot->client->ps.eFlags & EF_TANK) && nodes[bot->current_node].links[link].flags & PATH_NOTANKS) //if this path is blocked, skip it
// continue;
+
//if (nodes[nodes[pathlist[temp]].links[link].targetNode].origin[2] > nodes[pathlist[temp]].origin[2] + 32)
// continue;
+
if (nodes[pathlist[temp]].links[link].targetNode == pathlist[temp2])
{ // Found a shorter route...
//if (OrgVisible(nodes[pathlist[temp2]].origin, nodes[pathlist[temp]].origin, -1))
@@ -341,21 +400,26 @@ int ShortenASTARRoute(short int *pathlist, int number)
}
}
}
+
if (!shortened)
{
temppathlist[count] = pathlist[temp];
++count;
}
}
+
upto = count;
+
for (temp = 0; temp < count; temp++)
{
pathlist[temp] = temppathlist[upto];
--upto;
}
+
G_Printf("ShortenASTARRoute: Path size reduced from %i to %i nodes...n", number, count);
return count;
}
+
/*
===========================================================================
CreatePathAStar
@@ -376,6 +440,7 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
int fcost[MAX_NODES];
char list[MAX_NODES]; //0 is neither, 1 is open, 2 is closed - char because it's the smallest data type
short int parent[MAX_NODES];
+
short int numOpen = 0;
short int atNode, temp, newnode=-1;
qboolean found = qfalse;
@@ -383,19 +448,23 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
float gc;
int i, u, v, m;
vec3_t vec;
+
//clear out all the arrays
memset(openlist, 0, sizeof(short int)*(MAX_NODES+1));
memset(fcost, 0, sizeof(int)*MAX_NODES);
memset(list, 0, sizeof(char)*MAX_NODES);
memset(parent, 0, sizeof(short int)*MAX_NODES);
memset(gcost, -1, sizeof(float)*MAX_NODES);
+
//make sure we have valid data before calculating everything
if ((from == NODE_INVALID) || (to == NODE_INVALID) || (from >= MAX_NODES) || (to >= MAX_NODES) || (from == to))
return -1;
+
openlist[1] = from; //add the starting node to the open list
++numOpen;
gcost[from] = 0; //its f and g costs are obviously 0
fcost[from] = 0;
+
while (1)
{
if (numOpen != 0) //if there are still items in the open list
@@ -404,8 +473,10 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
atNode = openlist[1];
list[atNode] = 2; //put the node on the closed list so we don't check it again
--numOpen;
+
openlist[1] = openlist[numOpen+1]; //move the last item in the list to the top position
v = 1;
+
//this while loop reorders the list so that the new lowest fcost is at the top again
while (1)
{
@@ -425,6 +496,7 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
v = 2*u;
}
}
+
if (u != v) //if they're out of order, swap this item with its parent
{
temp = openlist[u];
@@ -434,9 +506,11 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
else
break;
}
+
for (i = 0; i < nodes[atNode].enodenum; ++i) //loop through all the links for this node
{
newnode = nodes[atNode].links[i].targetNode;
+
//if this path is blocked, skip it
if (nodes[atNode].links[i].flags & PATH_BLOCKED)
continue;
@@ -448,17 +522,22 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
continue;
if (bot->client && (nodes[newnode].type & NODE_AXIS_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_AXIS))
continue;
+
if (list[newnode] == 2) //if this node is on the closed list, skip it
continue;
+
if (list[newnode] != 1) //if this node is not already on the open list
{
openlist[++numOpen] = newnode; //add the new node to the open list
list[newnode] = 1;
parent[newnode] = atNode; //record the node's parent
+
if (newnode == to) //if we've found the goal, don't keep computing paths!
break; //this will break the 'for' and go all the way to 'if (list[to] == 1)'
+
//store it's f cost value
fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
+
//this loop re-orders the heap so that the lowest fcost is at the top
m = numOpen;
while (m != 1) //while this item isn't at the top of the heap already
@@ -480,16 +559,19 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
gc = gcost[atNode];
VectorSubtract(nodes[newnode].origin, nodes[atNode].origin, vec);
gc += VectorLength(vec); //calculate what the gcost would be if we reached this node along the current path
+
if (gc < gcost[newnode]) //if the new gcost is less (ie, this path is shorter than what we had before)
{
parent[newnode] = atNode; //set the new parent for this node
gcost[newnode] = gc; //and the new g cost
+
for (i = 1; i < numOpen; ++i) //loop through all the items on the open list
{
if (openlist[i] == newnode) //find this node in the list
{
//calculate the new fcost and store it
fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
+
//reorder the list again, with the lowest fcost item on top
m = i;
while (m != 1)
@@ -517,23 +599,28 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
found = qfalse; //there is no path between these nodes
break;
}
+
if (list[to] == 1) //if the destination node is on the open list, we're done
{
found = qtrue;
break;
}
} //while (1)
+
if (found == qtrue) //if we found a path
{
//G_Printf("%s - path found!n", bot->client->pers.netname);
count = 0;
+
temp = to; //start at the end point
while (temp != from) //travel along the path (backwards) until we reach the starting point
{
pathlist[count++] = temp; //add the node to the pathlist and increment the count
temp = parent[temp]; //move to the parent of this node to continue the path
}
+
pathlist[count++] = from; //add the beginning node to the end of the pathlist
+
#ifdef __BOT_SHORTEN_ROUTING__
count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
#endif //__BOT_SHORTEN_ROUTING__
@@ -542,6 +629,7 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
{
//G_Printf("^1*** ^4BOT DEBUG^5: (CreatePathAStar) There is no route between node ^7%i^5 and node ^7%i^5.n", from, to);
count = CreateDumbRoute(from, to, pathlist);
+
if (count > 0)
{
#ifdef __BOT_SHORTEN_ROUTING__
@@ -550,8 +638,10 @@ int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
return count;
}
}
+
return count; //return the number of nodes in the path, -1 if not found
}
+
/*
===========================================================================
GetFCost
@@ -569,6 +659,7 @@ int GetFCost(int to, int num, int parentNum, float *gcost)
float gc = 0;
float hc = 0;
vec3_t v;
+
if (gcost[num] == -1)
{
if (parentNum != -1)
@@ -581,8 +672,10 @@ int GetFCost(int to, int num, int parentNum, float *gcost)
}
else
gc = gcost[num];
+
VectorSubtract(nodes[to].origin, nodes[num].origin, v);
hc = VectorLength(v);
+
return (int)(gc + hc);
}
#endif //__PATHFINDING__