[Commands] Modify #grid and #wp. (#1399)

- #grid add will no longer let you put in a duplicate grid.
- Grid nodes now spawn with invul/immune to damage.
- Grid nodes now set an entity variable "grid_id" on spawn.
- This allows grid nodes to be specifically despawned by "grid_id" entity variable, meaning you can view multiple grids at once and not despawn them all accidentally.
- #grid hide will despawn your targeted NPC's Grid nodes.
- #grid add, #grid show, #grid delete, and #grid hide send messages to let GM know what's going on.
- #wp add and #wp delete now send messages to let the GM know what's going on.
- #wpadd now send messages to let the GM know what's going on.
This commit is contained in:
Alex 2021-06-13 22:41:38 -04:00 committed by GitHub
parent 22333ee40b
commit 3886636ec7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 202 additions and 107 deletions

View File

@ -439,8 +439,8 @@ int command_init(void)
command_add("weather", "[0/1/2/3] (Off/Rain/Snow/Manual) - Change the weather", 80, command_weather) || command_add("weather", "[0/1/2/3] (Off/Rain/Snow/Manual) - Change the weather", 80, command_weather) ||
command_add("who", "[search]", 20, command_who) || command_add("who", "[search]", 20, command_who) ||
command_add("worldshutdown", "- Shut down world and all zones", 200, command_worldshutdown) || command_add("worldshutdown", "- Shut down world and all zones", 200, command_worldshutdown) ||
command_add("wp", "[add/delete] [grid_num] [pause] [wp_num] [-h] - Add/delete a waypoint to/from a wandering grid", 170, command_wp) || command_add("wp", "[add|delete] [grid_id] [pause] [waypoint_id] [-h] - Add or delete a waypoint by grid ID. (-h to use current heading)", 170, command_wp) ||
command_add("wpadd", "[pause] [-h] - Add your current location as a waypoint to your NPC target's AI path", 170, command_wpadd) || command_add("wpadd", "[pause] [-h] - Add your current location as a waypoint to your NPC target's AI path. (-h to use current heading)", 170, command_wpadd) ||
command_add("wpinfo", "- Show waypoint info about your NPC target", 170, command_wpinfo) || command_add("wpinfo", "- Show waypoint info about your NPC target", 170, command_wpinfo) ||
command_add("worldwide", "Performs world-wide GM functions such as cast (can be extended for other commands). Use caution", 250, command_worldwide) || command_add("worldwide", "Performs world-wide GM functions such as cast (can be extended for other commands). Use caution", 250, command_worldwide) ||
command_add("xtargets", "Show your targets Extended Targets and optionally set how many xtargets they can have.", 250, command_xtargets) || command_add("xtargets", "Show your targets Extended Targets and optionally set how many xtargets they can have.", 250, command_xtargets) ||
@ -2470,28 +2470,58 @@ void command_setlsinfo(Client *c, const Seperator *sep)
void command_grid(Client *c, const Seperator *sep) void command_grid(Client *c, const Seperator *sep)
{ {
if (strcasecmp("max", sep->arg[1]) == 0) { auto command_type = sep->arg[1];
c->Message(Chat::White, "Highest grid ID in this zone: %d", content_db.GetHighestGrid(zone->GetZoneID())); auto zone_id = zone->GetZoneID();
} if (strcasecmp("max", command_type) == 0) {
else if (strcasecmp("add", sep->arg[1]) == 0) { c->Message(
content_db.ModifyGrid(c, false, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), zone->GetZoneID()); Chat::White,
} fmt::format(
else if (strcasecmp("show", sep->arg[1]) == 0) { "Highest grid ID in this zone is {}.",
content_db.GetHighestGrid(zone_id)
Mob *target = c->GetTarget(); ).c_str()
);
if (!target || !target->IsNPC()) { } else if (strcasecmp("add", command_type) == 0) {
c->Message(Chat::White, "You need a NPC target!"); auto grid_id = atoi(sep->arg[2]);
auto wander_type = atoi(sep->arg[3]);
auto pause_type = atoi(sep->arg[4]);
if (!content_db.GridExistsInZone(zone_id, grid_id)) {
content_db.ModifyGrid(c, false, grid_id, wander_type, pause_type, zone_id);
c->Message(
Chat::White,
fmt::format(
"Grid {} added to zone ID {} with wander type {} and pause type {}.",
grid_id,
zone_id,
wander_type,
pause_type
).c_str()
);
} else {
c->Message(
Chat::White,
fmt::format(
"Grid {} already exists in zone ID {}.",
grid_id,
zone_id
).c_str()
);
return; return;
} }
} else if (strcasecmp("show", command_type) == 0) {
std::string query = StringFormat( Mob *target = c->GetTarget();
if (!target || !target->IsNPC()) {
c->Message(Chat::White, "You need to target an NPC!");
return;
}
auto grid_id = target->CastToNPC()->GetGrid();
std::string query = fmt::format(
"SELECT `x`, `y`, `z`, `heading`, `number` " "SELECT `x`, `y`, `z`, `heading`, `number` "
"FROM `grid_entries` " "FROM `grid_entries` "
"WHERE `zoneid` = %u and `gridid` = %i " "WHERE `zoneid` = {} AND `gridid` = {} "
"ORDER BY `number`", "ORDER BY `number`",
zone->GetZoneID(), zone_id,
target->CastToNPC()->GetGrid() grid_id
); );
auto results = content_db.QueryDatabase(query); auto results = content_db.QueryDatabase(query);
@ -2501,33 +2531,21 @@ void command_grid(Client *c, const Seperator *sep)
} }
if (results.RowCount() == 0) { if (results.RowCount() == 0) {
c->Message(Chat::White, "No grid found"); c->Message(Chat::White, "No grid found.");
return; return;
} }
/** // Depop any node npc's already spawned
* Depop any node npc's already spawned entity_list.DespawnGridNodes(grid_id);
*/
auto &mob_list = entity_list.GetMobList();
for (auto itr = mob_list.begin(); itr != mob_list.end(); ++itr) {
Mob *mob = itr->second;
if (mob->IsNPC() && mob->GetRace() == 2254) {
mob->Depop();
}
}
/** // Spawn grid nodes
* Spawn grid nodes
*/
std::map<std::vector<float>, int32> zoffset; std::map<std::vector<float>, int32> zoffset;
for (auto row : results) {
for (auto row = results.begin(); row != results.end(); ++row) {
glm::vec4 node_position = glm::vec4(atof(row[0]), atof(row[1]), atof(row[2]), atof(row[3])); glm::vec4 node_position = glm::vec4(atof(row[0]), atof(row[1]), atof(row[2]), atof(row[3]));
std::vector<float> node_loc { std::vector<float> node_loc {
node_position.x, node_position.x,
node_position.y, node_position.y,
node_position.z node_position.z
}; };
// If we already have a node at this location, set the z offset // If we already have a node at this location, set the z offset
@ -2536,46 +2554,98 @@ void command_grid(Client *c, const Seperator *sep)
auto search = zoffset.find(node_loc); auto search = zoffset.find(node_loc);
if (search != zoffset.end()) { if (search != zoffset.end()) {
search->second = search->second + 3; search->second = search->second + 3;
} } else {
else {
zoffset[node_loc] = 0.0; zoffset[node_loc] = 0.0;
} }
node_position.z += zoffset[node_loc]; node_position.z += zoffset[node_loc];
NPC::SpawnGridNodeNPC(node_position, grid_id, atoi(row[4]), zoffset[node_loc]);
NPC::SpawnGridNodeNPC(node_position,atoi(row[4]),zoffset[node_loc]);
} }
} c->Message(
else if (strcasecmp("delete", sep->arg[1]) == 0) { Chat::White,
content_db.ModifyGrid(c, true, atoi(sep->arg[2]), 0, 0, zone->GetZoneID()); fmt::format(
} "Spawning nodes for grid {}.",
else { grid_id
c->Message(Chat::White, "Usage: #grid add/delete grid_num wandertype pausetype"); ).c_str()
c->Message(Chat::White, "Usage: #grid max - displays the highest grid ID used in this zone (for add)"); );
c->Message(Chat::White, "Usage: #grid show - displays wp nodes as boxes"); } else if (strcasecmp("hide", command_type) == 0) {
Mob* target = c->GetTarget();
if (!target || !target->IsNPC()) {
c->Message(Chat::White, "You need to target an NPC!");
return;
}
auto grid_id = target->CastToNPC()->GetGrid();
entity_list.DespawnGridNodes(grid_id);
c->Message(
Chat::White,
fmt::format(
"Depawning nodes for grid {}.",
grid_id
).c_str()
);
} else if (strcasecmp("delete", command_type) == 0) {
auto grid_id = atoi(sep->arg[2]);
content_db.ModifyGrid(c, true, grid_id, 0, 0, zone_id);
c->Message(
Chat::White,
fmt::format(
"Grid {} deleted from zone ID {}.",
grid_id,
zone_id
).c_str()
);
} else {
c->Message(Chat::White, "Usage: #grid [add|delete] [grid_id] [wander_type] [pause_type]");
c->Message(Chat::White, "Usage: #grid [max] - displays the highest grid ID used in this zone (for add)");
c->Message(Chat::White, "Usage: #grid [show] - displays wp nodes as boxes");
} }
} }
void command_wp(Client *c, const Seperator *sep) void command_wp(Client *c, const Seperator *sep)
{ {
int wp = atoi(sep->arg[4]); auto command_type = sep->arg[1];
auto grid_id = atoi(sep->arg[2]);
if (grid_id != 0) {
auto pause = atoi(sep->arg[3]);
auto waypoint = atoi(sep->arg[4]);
auto zone_id = zone->GetZoneID();
if (strcasecmp("add", command_type) == 0) {
if (waypoint == 0) { // Default to highest if it's left blank, or we enter 0
waypoint = (content_db.GetHighestWaypoint(zone_id, grid_id) + 1);
}
if (strcasecmp("add", sep->arg[1]) == 0) { if (strcasecmp("-h", sep->arg[5]) == 0) {
if (wp == 0) //default to highest if it's left blank, or we enter 0 content_db.AddWP(c, grid_id, waypoint, c->GetPosition(), pause, zone_id);
wp = content_db.GetHighestWaypoint(zone->GetZoneID(), atoi(sep->arg[2])) + 1; } else {
if (strcasecmp("-h", sep->arg[5]) == 0) { auto position = c->GetPosition();
content_db.AddWP(c, atoi(sep->arg[2]),wp, c->GetPosition(), atoi(sep->arg[3]),zone->GetZoneID()); position.w = -1;
} content_db.AddWP(c, grid_id, waypoint, position, pause, zone_id);
else { }
auto position = c->GetPosition(); c->Message(
position.w = -1; Chat::White,
content_db.AddWP(c, atoi(sep->arg[2]),wp, position, atoi(sep->arg[3]),zone->GetZoneID()); fmt::format(
"Waypoint {} added to grid {} with a pause of {} {}.",
waypoint,
grid_id,
pause,
(pause == 1 ? "second" : "seconds")
).c_str()
);
} else if (strcasecmp("delete", command_type) == 0) {
content_db.DeleteWaypoint(c, grid_id, waypoint, zone_id);
c->Message(
Chat::White,
fmt::format(
"Waypoint {} deleted from grid {}.",
waypoint,
grid_id
).c_str()
);
} }
} else {
c->Message(Chat::White,"Usage: #wp [add|delete] [grid_id] [pause] [waypoint_id] [-h]");
} }
else if (strcasecmp("delete", sep->arg[1]) == 0)
content_db.DeleteWaypoint(c, atoi(sep->arg[2]),wp,zone->GetZoneID());
else
c->Message(Chat::White,"Usage: #wp add/delete grid_num pause wp_num [-h]");
} }
void command_iplookup(Client *c, const Seperator *sep) void command_iplookup(Client *c, const Seperator *sep)
@ -7843,20 +7913,14 @@ void command_wpinfo(Client *c, const Seperator *sep)
void command_wpadd(Client *c, const Seperator *sep) void command_wpadd(Client *c, const Seperator *sep)
{ {
int type1 = 0, int type1 = 0, type2 = 0, pause = 0; // Defaults for a new grid
type2 = 0,
pause = 0; // Defaults for a new grid
Mob *target = c->GetTarget(); Mob *target = c->GetTarget();
if (target && target->IsNPC()) { if (target && target->IsNPC()) {
Spawn2 *s2info = target->CastToNPC()->respawn2; Spawn2 *s2info = target->CastToNPC()->respawn2;
if (s2info == nullptr) {
if (s2info ==
nullptr) // Can't figure out where this mob's spawn came from... maybe a dynamic mob created by #spawn
{
c->Message( c->Message(
Chat::White, Chat::White,
"#wpadd FAILED -- Can't determine which spawn record in the database this mob came from!" "#wpadd Failed, you must target a valid spawn."
); );
return; return;
} }
@ -7864,8 +7928,7 @@ void command_wpadd(Client *c, const Seperator *sep)
if (sep->arg[1][0]) { if (sep->arg[1][0]) {
if (atoi(sep->arg[1]) >= 0) { if (atoi(sep->arg[1]) >= 0) {
pause = atoi(sep->arg[1]); pause = atoi(sep->arg[1]);
} } else {
else {
c->Message(Chat::White, "Usage: #wpadd [pause] [-h]"); c->Message(Chat::White, "Usage: #wpadd [pause] [-h]");
return; return;
} }
@ -7875,18 +7938,23 @@ void command_wpadd(Client *c, const Seperator *sep)
position.w = -1; position.w = -1;
} }
uint32 tmp_grid = content_db.AddWPForSpawn(c, s2info->GetID(), position, pause, type1, type2, zone->GetZoneID()); auto zone_id = zone->GetZoneID();
uint32 tmp_grid = content_db.AddWPForSpawn(c, s2info->GetID(), position, pause, type1, type2, zone_id);
if (tmp_grid) { if (tmp_grid) {
target->CastToNPC()->SetGrid(tmp_grid); target->CastToNPC()->SetGrid(tmp_grid);
} }
target->CastToNPC()->AssignWaypoints(target->CastToNPC()->GetGrid()); auto grid_id = target->CastToNPC()->GetGrid();
target->CastToNPC()->AssignWaypoints(grid_id);
c->Message( c->Message(
Chat::White, Chat::White,
"Waypoint added. Use #wpinfo to see waypoints for this NPC (may need to #repop first)." fmt::format(
"Waypoint added to grid {} in zone ID {}. Use #wpinfo to see waypoints for this NPC (may need to #repop first).",
grid_id,
zone_id
).c_str()
); );
} } else {
else {
c->Message(Chat::White, "You must target an NPC to use this."); c->Message(Chat::White, "You must target an NPC to use this.");
} }
} }

View File

@ -5314,3 +5314,12 @@ int EntityList::MovePlayerCorpsesToGraveyard(bool force_move_from_instance)
return moved_count; return moved_count;
} }
void EntityList::DespawnGridNodes(int32 grid_id) {
for (auto mob_iterator : mob_list) {
Mob *mob = mob_iterator.second;
if (mob->IsNPC() && mob->GetRace() == 2254 && mob->EntityVariableExists("grid_id") && atoi(mob->GetEntityVariable("grid_id")) == grid_id) {
mob->Depop();
}
}
}

View File

@ -234,6 +234,7 @@ public:
void RemoveAllCorpsesByCharID(uint32 charid); void RemoveAllCorpsesByCharID(uint32 charid);
void RemoveCorpseByDBID(uint32 dbid); void RemoveCorpseByDBID(uint32 dbid);
int RezzAllCorpsesByCharID(uint32 charid); int RezzAllCorpsesByCharID(uint32 charid);
void DespawnGridNodes(int32 grid_id);
bool IsMobInZone(Mob *who); bool IsMobInZone(Mob *who);
void ClearClientPetitionQueue(); void ClearClientPetitionQueue();
bool CanAddHateForMob(Mob *p); bool CanAddHateForMob(Mob *p);

View File

@ -1099,8 +1099,7 @@ bool NPC::SpawnZoneController()
return true; return true;
} }
void NPC::SpawnGridNodeNPC(const glm::vec4 &position, int32 grid_number, int32 zoffset) { void NPC::SpawnGridNodeNPC(const glm::vec4 &position, int32 grid_id, int32 grid_number, int32 zoffset) {
auto npc_type = new NPCType; auto npc_type = new NPCType;
memset(npc_type, 0, sizeof(NPCType)); memset(npc_type, 0, sizeof(NPCType));
@ -1112,31 +1111,30 @@ void NPC::SpawnGridNodeNPC(const glm::vec4 &position, int32 grid_number, int32 z
strcat(npc_type->name, "(Stacked)"); strcat(npc_type->name, "(Stacked)");
} }
npc_type->current_hp = 4000000; npc_type->current_hp = 4000000;
npc_type->max_hp = 4000000; npc_type->max_hp = 4000000;
npc_type->race = 2254; npc_type->race = 2254;
npc_type->gender = 2; npc_type->gender = 2;
npc_type->class_ = 9; npc_type->class_ = 9;
npc_type->deity = 1; npc_type->deity = 1;
npc_type->level = 200; npc_type->level = 200;
npc_type->npc_id = 0; npc_type->npc_id = 0;
npc_type->loottable_id = 0; npc_type->loottable_id = 0;
npc_type->texture = 1; npc_type->texture = 1;
npc_type->light = 1; npc_type->light = 1;
npc_type->size = 1; npc_type->size = 1;
npc_type->runspeed = 0; npc_type->runspeed = 0;
npc_type->merchanttype = 1; npc_type->merchanttype = 1;
npc_type->bodytype = 1; npc_type->bodytype = 1;
npc_type->show_name = true; npc_type->show_name = true;
npc_type->findable = true; npc_type->findable = true;
strn0cpy(npc_type->special_abilities, "24,1^35,1", 512);
auto node_position = glm::vec4(position.x, position.y, position.z, position.w); auto node_position = glm::vec4(position.x, position.y, position.z, position.w);
auto npc = new NPC(npc_type, nullptr, node_position, GravityBehavior::Flying); auto npc = new NPC(npc_type, nullptr, node_position, GravityBehavior::Flying);
npc->name[strlen(npc->name) - 3] = (char) NULL;
npc->name[strlen(npc->name)-3] = (char) NULL;
npc->GiveNPCTypeData(npc_type); npc->GiveNPCTypeData(npc_type);
npc->SetEntityVariable("grid_id", itoa(grid_id));
entity_list.AddNPC(npc); entity_list.AddNPC(npc);
} }

View File

@ -114,7 +114,7 @@ public:
virtual ~NPC(); virtual ~NPC();
static NPC *SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4 &position); static NPC *SpawnNodeNPC(std::string name, std::string last_name, const glm::vec4 &position);
static void SpawnGridNodeNPC(const glm::vec4 &position, int32 grid_number, int32 zoffset); static void SpawnGridNodeNPC(const glm::vec4 &position, int32 grid_id, int32 grid_number, int32 zoffset);
static void SpawnZonePointNodeNPC(std::string name, const glm::vec4 &position); static void SpawnZonePointNodeNPC(std::string name, const glm::vec4 &position);
//abstract virtual function implementations requird by base abstract class //abstract virtual function implementations requird by base abstract class

View File

@ -1036,6 +1036,24 @@ void ZoneDatabase::ModifyGrid(Client *client, bool remove, uint32 id, uint8 type
results = QueryDatabase(query); results = QueryDatabase(query);
} }
bool ZoneDatabase::GridExistsInZone(uint32 zone_id, uint32 grid_id) {
bool grid_exists = false;
std::string query = fmt::format(
"SELECT * FROM `grid` WHERE `id` = {} AND `zoneid` = {}",
grid_id,
zone_id
);
auto results = QueryDatabase(query);
if (!results.Success()) {
return grid_exists;
}
if (results.RowCount() == 1) {
grid_exists = true;
}
return grid_exists;
}
/************************************** /**************************************
* AddWP - Adds a new waypoint to a specific grid for a specific zone. * AddWP - Adds a new waypoint to a specific grid for a specific zone.
*/ */

View File

@ -448,6 +448,7 @@ public:
void AddWP(Client *c, uint32 gridid, uint32 wpnum, const glm::vec4& position, uint32 pause, uint16 zoneid); void AddWP(Client *c, uint32 gridid, uint32 wpnum, const glm::vec4& position, uint32 pause, uint16 zoneid);
uint32 AddWPForSpawn(Client *c, uint32 spawn2id, const glm::vec4& position, uint32 pause, int type1, int type2, uint16 zoneid); uint32 AddWPForSpawn(Client *c, uint32 spawn2id, const glm::vec4& position, uint32 pause, int type1, int type2, uint16 zoneid);
void ModifyGrid(Client *c, bool remove, uint32 id, uint8 type = 0, uint8 type2 = 0, uint16 zoneid = 0); void ModifyGrid(Client *c, bool remove, uint32 id, uint8 type = 0, uint8 type2 = 0, uint16 zoneid = 0);
bool GridExistsInZone(uint32 zone_id, uint32 grid_id);
void ModifyWP(Client *c, uint32 grid_id, uint32 wp_num, const glm::vec3& location, uint32 script = 0, uint16 zoneid = 0); void ModifyWP(Client *c, uint32 grid_id, uint32 wp_num, const glm::vec3& location, uint32 script = 0, uint16 zoneid = 0);
uint8 GetGridType(uint32 grid, uint32 zoneid); uint8 GetGridType(uint32 grid, uint32 zoneid);
uint8 GetGridType2(uint32 grid, uint16 zoneid); uint8 GetGridType2(uint32 grid, uint16 zoneid);