diff options
Diffstat (limited to 'src/game/WaypointMovementGenerator.cpp')
-rw-r--r-- | src/game/WaypointMovementGenerator.cpp | 93 |
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__ |