mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 10:31:29 +00:00
Merge pull request #956 from regneq/master
New pathgrid types. fixed an issue where npc would face north when pause and heading were set at -1.
This commit is contained in:
commit
f73f72b2b2
@ -400,6 +400,7 @@
|
||||
9144|2019_11_09_logsys_description_update.sql|SELECT * FROM db_version WHERE version >= 9143|empty|
|
||||
9145|2019_12_24_banned_ips_update.sql|SHOW TABLES LIKE 'Banned_IPs'|not_empty|
|
||||
9146|2020_01_10_character_soft_deletes.sql|SHOW COLUMNS FROM `character_data` LIKE 'deleted_at'|empty|
|
||||
9147|2020_01_24_grid_centerpoint_wp.sql|SHOW COLUMNS FROM `grid_entries` LIKE 'centerpoint'|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
alter table grid_entries add column `centerpoint` tinyint(4) not null default 0;
|
||||
alter table spawngroup add column `wp_spawns` tinyint(1) unsigned not null default 0;
|
||||
@ -647,6 +647,19 @@ enum {
|
||||
SKILLUP_FAILURE = 2
|
||||
};
|
||||
|
||||
enum {
|
||||
GridCircular,
|
||||
GridRandom10,
|
||||
GridRandom,
|
||||
GridPatrol,
|
||||
GridOneWayRepop,
|
||||
GridRand5LoS,
|
||||
GridOneWayDepop,
|
||||
GridCenterPoint,
|
||||
GridRandomCenterPoint,
|
||||
GridRandomPath
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
petFamiliar, //only listens to /pet get lost
|
||||
petAnimation, //does not listen to any commands
|
||||
|
||||
@ -1693,12 +1693,32 @@ void NPC::AI_DoMovement() {
|
||||
GetZ(),
|
||||
GetGrid());
|
||||
|
||||
if (wandertype == GridRandomPath)
|
||||
{
|
||||
if (cur_wp == patrol)
|
||||
{
|
||||
// reached our randomly selected destination; force a pause
|
||||
if (cur_wp_pause == 0)
|
||||
{
|
||||
if (Waypoints.size() > 0 && Waypoints[0].pause)
|
||||
cur_wp_pause = Waypoints[0].pause;
|
||||
else
|
||||
cur_wp_pause = 38;
|
||||
}
|
||||
Log(Logs::Detail, Logs::AI, "NPC using wander type GridRandomPath on grid %d at waypoint %d has reached its random destination; pause time is %d", GetGrid(), cur_wp, cur_wp_pause);
|
||||
}
|
||||
else
|
||||
cur_wp_pause = 0; // skipping pauses until destination
|
||||
}
|
||||
|
||||
SetWaypointPause();
|
||||
SetAppearance(eaStanding, false);
|
||||
if (cur_wp_pause > 0) {
|
||||
if (GetAppearance() != eaStanding) {
|
||||
SetAppearance(eaStanding, false);
|
||||
}
|
||||
if (cur_wp_pause > 0 && m_CurrentWayPoint.w >= 0.0) {
|
||||
RotateTo(m_CurrentWayPoint.w);
|
||||
}
|
||||
|
||||
|
||||
//kick off event_waypoint arrive
|
||||
char temp[16];
|
||||
sprintf(temp, "%d", cur_wp);
|
||||
@ -1789,12 +1809,12 @@ void NPC::AI_SetupNextWaypoint() {
|
||||
}
|
||||
}
|
||||
|
||||
if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||
if (wandertype == GridOneWayRepop && 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()) {
|
||||
else if (wandertype == GridOneWayDepop && cur_wp == CastToNPC()->GetMaxWp()) {
|
||||
CastToNPC()->Depop(false);//depop without spawn timer
|
||||
if (found_spawn)
|
||||
found_spawn->SetNPCPointerNull();
|
||||
|
||||
@ -303,7 +303,7 @@ public:
|
||||
int GetMaxWp() const { return max_wp; }
|
||||
void DisplayWaypointInfo(Client *to);
|
||||
void CalculateNewWaypoint();
|
||||
void AssignWaypoints(int32 grid);
|
||||
void AssignWaypoints(int32 grid, int start_wp = 0);
|
||||
void SetWaypointPause();
|
||||
void UpdateWaypoint(int wp_index);
|
||||
|
||||
@ -312,7 +312,8 @@ public:
|
||||
void ResumeWandering();
|
||||
void PauseWandering(int pausetime);
|
||||
void MoveTo(const glm::vec4& position, bool saveguardspot);
|
||||
void GetClosestWaypoint(std::list<wplist> &wp_list, int count, const glm::vec3& location);
|
||||
void GetClosestWaypoints(std::list<wplist> &wp_list, int count, const glm::vec3& location);
|
||||
int GetClosestWaypoint(const glm::vec3& location);
|
||||
|
||||
uint32 GetEquippedItemFromTextureSlot(uint8 material_slot) const; // returns item id
|
||||
int32 GetEquipmentMaterial(uint8 material_slot) const;
|
||||
|
||||
@ -233,6 +233,20 @@ bool Spawn2::Process() {
|
||||
}
|
||||
|
||||
currentnpcid = npcid;
|
||||
|
||||
glm::vec4 loc(x, y, z, heading);
|
||||
int starting_wp = 0;
|
||||
if (spawn_group->wp_spawns && grid_ > 0)
|
||||
{
|
||||
glm::vec4 wploc;
|
||||
starting_wp = database.GetRandomWaypointLocFromGrid(wploc, zone->GetZoneID(), grid_);
|
||||
if (wploc.x != 0.0f || wploc.y != 0.0f || wploc.z != 0.0f)
|
||||
{
|
||||
loc = wploc;
|
||||
Log(Logs::General, Logs::Spawns, "spawning at random waypoint #%i loc: (%.3f, %.3f, %.3f).", starting_wp , loc.x, loc.y, loc.z);
|
||||
}
|
||||
}
|
||||
|
||||
NPC *npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), GravityBehavior::Water);
|
||||
|
||||
npc->mod_prespawn(this);
|
||||
@ -275,7 +289,7 @@ bool Spawn2::Process() {
|
||||
z
|
||||
);
|
||||
|
||||
LoadGrid();
|
||||
LoadGrid(starting_wp);
|
||||
}
|
||||
else {
|
||||
LogSpawns("Spawn2 [{}]: Group [{}] spawned [{}] ([{}]) at ([{}], [{}], [{}]). Grid loading delayed",
|
||||
@ -302,7 +316,7 @@ void Spawn2::Disable()
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
void Spawn2::LoadGrid() {
|
||||
void Spawn2::LoadGrid(int start_wp) {
|
||||
if (!npcthis)
|
||||
return;
|
||||
if (grid_ < 1)
|
||||
@ -311,8 +325,8 @@ void Spawn2::LoadGrid() {
|
||||
return;
|
||||
//dont set an NPC's grid until its loaded for them.
|
||||
npcthis->SetGrid(grid_);
|
||||
npcthis->AssignWaypoints(grid_);
|
||||
LogSpawns("Spawn2 [{}]: Loading grid [{}] for [{}]", spawn2_id, grid_, npcthis->GetName());
|
||||
npcthis->AssignWaypoints(grid_, start_wp);
|
||||
LogSpawns("Spawn2 [{}]: Loading grid [{}] for [{}]; starting wp is [{}]", spawn2_id, grid_, npcthis->GetName(), start_wp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -36,7 +36,7 @@ public:
|
||||
uint16 cond_id = SC_AlwaysEnabled, int16 min_value = 0, bool in_enabled = true, EmuAppearance anim = eaStanding);
|
||||
~Spawn2();
|
||||
|
||||
void LoadGrid();
|
||||
void LoadGrid(int start_wp = 0);
|
||||
void Enable() { enabled = true; }
|
||||
void Disable();
|
||||
bool Enabled() { return enabled; }
|
||||
|
||||
@ -48,7 +48,8 @@ SpawnGroup::SpawnGroup(
|
||||
int delay_in,
|
||||
int despawn_in,
|
||||
uint32 despawn_timer_in,
|
||||
int min_delay_in
|
||||
int min_delay_in,
|
||||
bool wp_spawns_in
|
||||
)
|
||||
{
|
||||
id = in_id;
|
||||
@ -63,6 +64,7 @@ SpawnGroup::SpawnGroup(
|
||||
delay = delay_in;
|
||||
despawn = despawn_in;
|
||||
despawn_timer = despawn_timer_in;
|
||||
wp_spawns = wp_spawns_in;
|
||||
}
|
||||
|
||||
uint32 SpawnGroup::GetNPCType(uint16 in_filter)
|
||||
@ -198,7 +200,8 @@ bool ZoneDatabase::LoadSpawnGroups(const char *zone_name, uint16 version, SpawnG
|
||||
spawngroup.delay,
|
||||
spawngroup.despawn,
|
||||
spawngroup.despawn_timer,
|
||||
spawngroup.mindelay
|
||||
spawngroup.mindelay,
|
||||
spawngroup.wp_spawns
|
||||
FROM
|
||||
spawn2,
|
||||
spawngroup
|
||||
@ -229,7 +232,8 @@ bool ZoneDatabase::LoadSpawnGroups(const char *zone_name, uint16 version, SpawnG
|
||||
atoi(row[8]),
|
||||
atoi(row[9]),
|
||||
atoi(row[10]),
|
||||
atoi(row[11])
|
||||
atoi(row[11]),
|
||||
atoi(row[12])
|
||||
);
|
||||
|
||||
spawn_group_list->AddSpawnGroup(new_spawn_group);
|
||||
@ -305,7 +309,8 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawn_group_id, SpawnGroupList *spawn
|
||||
spawngroup.delay,
|
||||
spawngroup.despawn,
|
||||
spawngroup.despawn_timer,
|
||||
spawngroup.mindelay
|
||||
spawngroup.mindelay,
|
||||
spawngroup.wp_spawns
|
||||
FROM
|
||||
spawngroup
|
||||
WHERE
|
||||
@ -332,7 +337,8 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawn_group_id, SpawnGroupList *spawn
|
||||
atoi(row[8]),
|
||||
atoi(row[9]),
|
||||
atoi(row[10]),
|
||||
atoi(row[11])
|
||||
atoi(row[11]),
|
||||
atoi(row[12])
|
||||
);
|
||||
|
||||
spawn_group_list->AddSpawnGroup(new_spawn_group);
|
||||
|
||||
@ -49,13 +49,15 @@ public:
|
||||
int delay_in,
|
||||
int despawn_in,
|
||||
uint32 despawn_timer_in,
|
||||
int min_delay_in
|
||||
int min_delay_in,
|
||||
bool wp_spawns_in
|
||||
);
|
||||
|
||||
~SpawnGroup();
|
||||
uint32 GetNPCType(uint16 condition_value_filter=1);
|
||||
void AddSpawnEntry(SpawnEntry *newEntry);
|
||||
uint32 id;
|
||||
bool wp_spawns; // if true, spawn NPCs at a random waypoint location (if spawnpoint has a grid) instead of the spawnpoint's loc
|
||||
float roamdist;
|
||||
float roambox[4];
|
||||
int min_delay;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -47,6 +47,7 @@ struct wplist {
|
||||
float z;
|
||||
int pause;
|
||||
float heading;
|
||||
bool centerpoint;
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
@ -434,6 +435,7 @@ public:
|
||||
void AssignGrid(Client *client, int grid, int spawn2id);
|
||||
int GetHighestGrid(uint32 zoneid);
|
||||
int GetHighestWaypoint(uint32 zoneid, uint32 gridid);
|
||||
int GetRandomWaypointLocFromGrid(glm::vec4 &loc, uint16 zoneid, int grid);
|
||||
|
||||
/* NPCs */
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user