Added new pathgrid type 7 (GridCenterPoint). This grid causes a NPC to alternate between the first waypoint in their grid (Number 1 in the editor) and a random waypoint. (1 - 7 - 1 - 4 - 1 - 11 - 1 - 5 - 1, etc)

Changed the wandertype IDs to an enum so we know what we're looking at.
Added new pathgrid type 8 (GridRandomCenterPoint).  (SQL required) This new type causes a NPC to alternate between a random waypoint in grid_entries and a random waypoint marked with the new centerpoint column set to true. If no waypoints are marked as a centerpoint, this wandertype will not work. There is no numbering requirement or limit for centerpoints. You can have as many as you need.
New spawngroup field: wp_spawns (SQL required). Added a new spawngroup field, which is a boolean that if true changes the behavior of spawngroups this way: If the spawnpoint in the spawngroup has a grid, the NPC will spawn at a random waypoint location taken from its grid instead of the spawnpoint location.
New randompath behavior: The randompath grid type will now use the closest waypoint as its current waypoint on spawning.  This allows multiple spawn locations to use the same grid without having the undesirable behavior of walking to the first waypoint through walls and ignoring waypoint nodes. NPC::GetClosestWaypoint() was renamed to NPC::GetClosestWaypoints() as it was filling a list of multiple waypoints. a new method NPC::GetClosestWaypoint() returns a single waypoint in the form of an integer.
This commit is contained in:
regneq
2020-01-24 15:11:08 -08:00
parent 453bee511a
commit c2b3e85272
11 changed files with 219 additions and 43 deletions
+140 -25
View File
@@ -244,14 +244,14 @@ void NPC::CalculateNewWaypoint()
int old_wp = cur_wp;
bool reached_end = false;
bool reached_beginning = false;
if (cur_wp == max_wp)
if (cur_wp == max_wp - 1) //cur_wp starts at 0, max_wp starts at 1.
reached_end = true;
if (cur_wp == 0)
reached_beginning = true;
switch (wandertype)
{
case 0: //circle
case GridCircular:
{
if (reached_end)
cur_wp = 0;
@@ -259,10 +259,10 @@ void NPC::CalculateNewWaypoint()
cur_wp = cur_wp + 1;
break;
}
case 1: //10 closest
case GridRandom10:
{
std::list<wplist> closest;
GetClosestWaypoint(closest, 10, glm::vec3(GetPosition()));
GetClosestWaypoints(closest, 10, glm::vec3(GetPosition()));
auto iter = closest.begin();
if (closest.size() != 0)
{
@@ -273,30 +273,64 @@ void NPC::CalculateNewWaypoint()
break;
}
case 2: //random
case GridRandom:
case GridCenterPoint:
{
cur_wp = zone->random.Int(0, Waypoints.size() - 1);
if (cur_wp == old_wp)
if (wandertype == GridCenterPoint && !reached_beginning)
{
if (cur_wp == (Waypoints.size() - 1))
cur_wp = 0;
}
else
{
cur_wp = zone->random.Int(0, Waypoints.size() - 1);
if (cur_wp == old_wp || (wandertype == GridCenterPoint && cur_wp == 0))
{
if (cur_wp > 0)
if (cur_wp == (Waypoints.size() - 1))
{
cur_wp--;
if (cur_wp > 0)
{
cur_wp--;
}
}
}
else if (cur_wp == 0)
{
if ((Waypoints.size() - 1) > 0)
else if (cur_wp == 0)
{
cur_wp++;
if ((Waypoints.size() - 1) > 0)
{
cur_wp++;
}
}
}
}
break;
}
case 3: //patrol
case GridRandomCenterPoint:
{
bool on_center = Waypoints[cur_wp].centerpoint;
std::vector<wplist> random_waypoints;
for (auto &w : Waypoints)
{
wplist wpl = w;
if (wpl.index != cur_wp &&
((on_center && !wpl.centerpoint) || (!on_center && wpl.centerpoint)))
{
random_waypoints.push_back(w);
}
}
if (random_waypoints.size() == 0)
{
cur_wp = 0;
}
else
{
int windex = zone->random.Roll0(random_waypoints.size());
cur_wp = random_waypoints[windex].index;
}
break;
}
case GridPatrol:
{
if (reached_end)
patrol = 1;
@@ -309,16 +343,16 @@ void NPC::CalculateNewWaypoint()
break;
}
case 4: //goto the end and depop with spawn timer
case 6: //goto the end and depop without spawn timer
case GridOneWayRepop:
case GridOneWayDepop:
{
cur_wp = cur_wp + 1;
break;
}
case 5: //pick random closest 5 and pick one that's in sight
case GridRand5LoS:
{
std::list<wplist> closest;
GetClosestWaypoint(closest, 5, glm::vec3(GetPosition()));
GetClosestWaypoints(closest, 5, glm::vec3(GetPosition()));
auto iter = closest.begin();
while (iter != closest.end())
@@ -341,6 +375,25 @@ void NPC::CalculateNewWaypoint()
}
break;
}
case GridRandomPath: // randomly select a waypoint but follow path to it instead of walk directly to it ignoring walls
{
if (Waypoints.size() == 0)
{
cur_wp = 0;
}
else
{
if (cur_wp == patrol) // reutilizing patrol member instead of making new member for this wander type; here we use it to save a random waypoint
{
while (patrol == cur_wp)
patrol = zone->random.Int(0, Waypoints.size() - 1);
}
if (patrol > cur_wp)
cur_wp = cur_wp + 1;
else
cur_wp = cur_wp - 1;
}
}
}
// Preserve waypoint setting for quest controlled NPCs
@@ -357,7 +410,30 @@ bool wp_distance_pred(const wp_distance& left, const wp_distance& right)
return left.dist < right.dist;
}
void NPC::GetClosestWaypoint(std::list<wplist> &wp_list, int count, const glm::vec3& location)
int NPC::GetClosestWaypoint(const glm::vec3& location)
{
if (Waypoints.size() <= 1)
return 0;
int closest = 0;
float closestDist = 9999999.0f;
float dist;
for (int i = 0; i < Waypoints.size(); ++i)
{
dist = DistanceSquared(location, glm::vec3(Waypoints[i].x, Waypoints[i].y, Waypoints[i].z));
if (dist < closestDist)
{
closestDist = dist;
closest = i;
}
}
return closest;
}
// fills wp_list with the closest count number of waypoints
void NPC::GetClosestWaypoints(std::list<wplist> &wp_list, int count, const glm::vec3& location)
{
wp_list.clear();
if (Waypoints.size() <= count)
@@ -485,7 +561,7 @@ void Mob::StopNavigation() {
mMovementManager->StopNavigation(this);
}
void NPC::AssignWaypoints(int32 grid)
void NPC::AssignWaypoints(int32 grid, int start_wp)
{
if (grid == 0)
return; // grid ID 0 not supported
@@ -518,7 +594,7 @@ void NPC::AssignWaypoints(int32 grid)
SetGrid(grid); // Assign grid number
// Retrieve all waypoints for this grid
query = StringFormat("SELECT `x`,`y`,`z`,`pause`,`heading` "
query = StringFormat("SELECT `x`,`y`,`z`,`pause`,`heading`, `centerpoint` "
"FROM grid_entries WHERE `gridid` = %i AND `zoneid` = %i "
"ORDER BY `number`", grid, zone->GetZoneID());
results = database.QueryDatabase(query);
@@ -539,14 +615,22 @@ void NPC::AssignWaypoints(int32 grid)
newwp.pause = atoi(row[3]);
newwp.heading = atof(row[4]);
newwp.centerpoint = atobool(row[5]);
Waypoints.push_back(newwp);
}
UpdateWaypoint(0);
cur_wp = start_wp;
UpdateWaypoint(start_wp);
SetWaypointPause();
if (wandertype == 1 || wandertype == 2 || wandertype == 5)
if (wandertype == GridRandomPath) {
cur_wp = GetClosestWaypoint(glm::vec3(GetPosition()));
patrol = cur_wp;
}
if (wandertype == GridRandom10 || wandertype == GridRandom || wandertype == GridRand5LoS)
CalculateNewWaypoint();
}
void Mob::SendTo(float new_x, float new_y, float new_z) {
@@ -1058,6 +1142,37 @@ int ZoneDatabase::GetHighestWaypoint(uint32 zoneid, uint32 gridid) {
return atoi(row[0]);
}
int ZoneDatabase::GetRandomWaypointLocFromGrid(glm::vec4 &loc, uint16 zoneid, int grid)
{
loc.x = loc.y = loc.z = loc.w = 0.0f;
std::string query = StringFormat("SELECT `x`,`y`,`z`,`heading` "
"FROM grid_entries WHERE `gridid` = %i AND `zoneid` = %u ORDER BY `number`", grid, zone->GetZoneID());
auto results = database.QueryDatabase(query);
if (!results.Success()) {
Log(Logs::General, Logs::Error, "MySQL Error while trying get random waypoint loc from grid %i in zoneid %u; %s", grid, zoneid, results.ErrorMessage().c_str());
return 0;
}
if (results.RowCount() > 0)
{
int roll = zone->random.Int(0, results.RowCount() - 1);
int i = 0;
auto row = results.begin();
while (i < roll)
{
row++;
i++;
}
loc.x = atof(row[0]);
loc.y = atof(row[1]);
loc.z = atof(row[2]);
loc.w = atof(row[3]);
return i;
}
return 0;
}
void NPC::SaveGuardSpotCharm()
{
m_GuardPointSaved = m_GuardPoint;