diff --git a/changelog.txt b/changelog.txt index afef68a37..b62f810be 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,13 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 8/16/2019 == +Akkadius: Simplified the use of roamboxes and improved the AI for roambox pathing https://i.imgur.com/z33u7y9.gif +Akkadius: Implemented command #roambox set [move_delay] +Akkadius: Implemented command #roambox remove +Akkadius: Implemented LUA NPC:SetSimpleRoamBox(box_size, [move_distance], [move_delay]); +Akkadius: Implemented Perl $npc->SetSimpleRoamBox(box_size, [move_distance], [move_delay]); +Akkadius: Spawngroup data now hot reloads on #repop + == 8/11/2019 == Akkadius: Added bulk edit command #npceditmass Akkadius: Modified #findzone to include clickable saylinks to both regular zone (if able) and private gmzone instances diff --git a/zone/aggro.cpp b/zone/aggro.cpp index ca565e0b9..490bf7bbf 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -973,11 +973,13 @@ bool Mob::CombatRange(Mob* other) } //Father Nitwit's LOS code -bool Mob::CheckLosFN(Mob* other) { +bool Mob::CheckLosFN(Mob *other) +{ bool Result = false; - if(other) + if (other) { Result = CheckLosFN(other->GetX(), other->GetY(), other->GetZ(), other->GetSize()); + } SetLastLosState(Result); diff --git a/zone/api_service.cpp b/zone/api_service.cpp index 957d2b012..b8ae1149e 100644 --- a/zone/api_service.cpp +++ b/zone/api_service.cpp @@ -225,7 +225,7 @@ Json::Value ApiGetNpcListDetail(EQ::Net::WebsocketServerConnection *connection, row["sec_skill"] = npc->GetSecSkill(); row["silver"] = npc->GetSilver(); row["slow_mitigation"] = npc->GetSlowMitigation(); - row["sp2"] = npc->GetSp2(); + row["spawn_group_id"] = npc->GetSpawnGroupId(); row["swarm_owner"] = npc->GetSwarmOwner(); row["swarm_target"] = npc->GetSwarmTarget(); row["waypoint_max"] = npc->GetWaypointMax(); diff --git a/zone/attack.cpp b/zone/attack.cpp index 780a8fba4..3dca5f8c3 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -34,6 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "lua_parser.h" #include "fastmath.h" #include "mob.h" +#include "npc.h" #include diff --git a/zone/command.cpp b/zone/command.cpp index 1640994c6..babe3ec24 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -346,6 +346,7 @@ int command_init(void) command_add("resetaa", "- Resets a Player's AA in their profile and refunds spent AA's to unspent, may disconnect player.", 200, command_resetaa) || command_add("resetaa_timer", "Command to reset AA cooldown timers.", 200, command_resetaa_timer) || command_add("revoke", "[charname] [1/0] - Makes charname unable to talk on OOC", 200, command_revoke) || + command_add("roambox", "Manages roambox settings for an NPC", 200, command_roambox) || command_add("rules", "(subcommand) - Manage server rules", 250, command_rules) || command_add("save", "- Force your player or player corpse target to be saved to the database", 50, command_save) || command_add("scale", "- Handles npc scaling", 150, command_scale) || @@ -1820,7 +1821,7 @@ void command_npcstats(Client *c, const Seperator *sep) //c->Message(Chat::White, "Weapon Item Number: %s", target_npc->GetWeapNo()); c->Message(Chat::White, "- Gender: %i Size: %f Bodytype: %d", target_npc->GetGender(), target_npc->GetSize(), target_npc->GetBodyType()); c->Message(Chat::White, "- Runspeed: %.3f Walkspeed: %.3f", static_cast(0.025f * target_npc->GetRunspeed()), static_cast(0.025f * target_npc->GetWalkspeed())); - c->Message(Chat::White, "- Spawn Group: %i Grid: %i", target_npc->GetSp2(), target_npc->GetGrid()); + c->Message(Chat::White, "- Spawn Group: %i Grid: %i", target_npc->GetSpawnGroupId(), target_npc->GetGrid()); if (target_npc->proximity) { c->Message(Chat::White, "- Proximity: Enabled"); c->Message(Chat::White, "-- Cur_X: %1.3f, Cur_Y: %1.3f, Cur_Z: %1.3f", target_npc->GetX(), target_npc->GetY(), target_npc->GetZ()); @@ -7199,6 +7200,96 @@ void command_revoke(Client *c, const Seperator *sep) safe_delete(outapp); } +void command_roambox(Client *c, const Seperator *sep) +{ + std::string arg1 = sep->arg[1]; + + Mob *target = c->GetTarget(); + if (!target || !target->IsNPC()) { + c->Message(Chat::Red, "You need a valid NPC target for this command"); + return; + } + + NPC *npc = dynamic_cast(target); + int spawn_group_id = npc->GetSpawnGroupId(); + if (spawn_group_id <= 0) { + c->Message(Chat::Red, "NPC needs a valid SpawnGroup!"); + return; + } + + if (arg1 == "set") { + int box_size = (sep->arg[2] ? atoi(sep->arg[2]) : 0); + int delay = (sep->arg[3] ? atoi(sep->arg[3]) : 15000); + if (box_size > 0) { + std::string query = fmt::format( + SQL( + UPDATE spawngroup SET + dist = {}, + min_x = {}, + max_x = {}, + min_y = {}, + max_y = {}, + delay = {} + WHERE id = {} + ), + box_size, + npc->GetX() - 100, + npc->GetX() + 100, + npc->GetY() - 100, + npc->GetY() + 100, + delay, + spawn_group_id + ); + + database.QueryDatabase(query); + + c->Message( + Chat::Yellow, + "NPC (%s) Roam Box set to box size of [%i] SpawnGroupId [%i] delay [%i]", + npc->GetCleanName(), + box_size, + spawn_group_id, + delay + ); + + return; + } + + c->Message(Chat::Red, "Box size must be set!"); + } + + if (arg1 == "remove") { + std::string query = fmt::format( + SQL( + UPDATE spawngroup SET + dist = 0, + min_x = 0, + max_x = 0, + min_y = 0, + max_y = 0, + delay = 0 + WHERE id = {} + ), + spawn_group_id + ); + + database.QueryDatabase(query); + + c->Message( + Chat::Yellow, + "NPC (%s) Roam Box has been removed from SpawnGroupID [%i]", + npc->GetCleanName(), + spawn_group_id + ); + + return; + } + + c->Message(Chat::Yellow, "> Command Usage"); + c->Message(Chat::Yellow, "#roambox set box_size [delay = 0]"); + c->Message(Chat::Yellow, "#roambox remove"); +} + void command_oocmute(Client *c, const Seperator *sep) { if(sep->arg[1][0] == 0 || !(sep->arg[1][0] == '1' || sep->arg[1][0] == '0')) @@ -7213,16 +7304,15 @@ void command_oocmute(Client *c, const Seperator *sep) void command_checklos(Client *c, const Seperator *sep) { - if(c->GetTarget()) - { -// if(c->CheckLos(c->GetTarget())) - if(c->CheckLosFN(c->GetTarget())) - c->Message(Chat::White, "You have LOS to %s", c->GetTarget()->GetName()); - else - c->Message(Chat::White, "You do not have LOS to %s", c->GetTarget()->GetName()); + if (c->GetTarget()) { + if (c->CheckLosFN(c->GetTarget())) { + c->Message(Chat::White, "You have LOS to %s", c->GetTarget()->GetName()); + } + else { + c->Message(Chat::White, "You do not have LOS to %s", c->GetTarget()->GetName()); + } } - else - { + else { c->Message(Chat::White, "ERROR: Target required"); } } @@ -8102,8 +8192,10 @@ void command_npcedit(Client *c, const Seperator *sep) return; } - c->Message(Chat::Yellow,"NPCID %u now has the animation set to %i on spawn with spawngroup %i", npcTypeID, animation, c->GetTarget()->CastToNPC()->GetSp2() ); - std::string query = StringFormat("UPDATE spawn2 SET animation = %i " "WHERE spawngroupID = %i", animation, c->GetTarget()->CastToNPC()->GetSp2()); + c->Message(Chat::Yellow,"NPCID %u now has the animation set to %i on spawn with spawngroup %i", npcTypeID, animation, + c->GetTarget()->CastToNPC()->GetSpawnGroupId() ); + std::string query = StringFormat("UPDATE spawn2 SET animation = %i " "WHERE spawngroupID = %i", animation, + c->GetTarget()->CastToNPC()->GetSpawnGroupId()); database.QueryDatabase(query); c->GetTarget()->SetAppearance(EmuAppearance(animation)); @@ -9437,7 +9529,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep) int16 version = atoi(sep->arg[2]); std::string query = StringFormat("UPDATE spawn2 SET version = %i " "WHERE spawngroupID = '%i'", - version, c->GetTarget()->CastToNPC()->GetSp2()); + version, c->GetTarget()->CastToNPC()->GetSpawnGroupId()); auto results = database.QueryDatabase(query); if (!results.Success()) { c->Message(Chat::Red, "Update failed! MySQL gave the following error:"); @@ -9445,7 +9537,8 @@ void command_advnpcspawn(Client *c, const Seperator *sep) return; } - c->Message(Chat::White, "Version change to %i was successful from SpawnGroupID %i", version, c->GetTarget()->CastToNPC()->GetSp2()); + c->Message(Chat::White, "Version change to %i was successful from SpawnGroupID %i", version, + c->GetTarget()->CastToNPC()->GetSpawnGroupId()); c->GetTarget()->Depop(false); return; diff --git a/zone/command.h b/zone/command.h index d6ce90a23..422c61ec0 100644 --- a/zone/command.h +++ b/zone/command.h @@ -248,6 +248,7 @@ void command_repopclose(Client *c, const Seperator *sep); void command_resetaa(Client* c,const Seperator *sep); void command_resetaa_timer(Client *c, const Seperator *sep); void command_revoke(Client *c, const Seperator *sep); +void command_roambox(Client *c, const Seperator *sep); void command_rules(Client *c, const Seperator *sep); void command_save(Client *c, const Seperator *sep); void command_scale(Client *c, const Seperator *sep); diff --git a/zone/entity.cpp b/zone/entity.cpp index be5f249bc..2a1c76101 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -3728,7 +3728,7 @@ void EntityList::LimitAddNPC(NPC *npc) SpawnLimitRecord r; uint16 eid = npc->GetID(); - r.spawngroup_id = npc->GetSp2(); + r.spawngroup_id = npc->GetSpawnGroupId(); r.npc_type = npc->GetNPCTypeID(); npc_limit_list[eid] = r; diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index cb12bce23..4a8bd12a9 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -159,7 +159,7 @@ void Lua_NPC::SetSaveWaypoint(int wp) { void Lua_NPC::SetSp2(int sg2) { Lua_Safe_Call_Void(); - self->SetSp2(sg2); + self->SetSpawnGroupId(sg2); } int Lua_NPC::GetWaypointMax() { @@ -174,7 +174,7 @@ int Lua_NPC::GetGrid() { uint32 Lua_NPC::GetSp2() { Lua_Safe_Call_Int(); - return self->GetSp2(); + return self->GetSpawnGroupId(); } int Lua_NPC::GetNPCFactionID() { @@ -529,6 +529,24 @@ int Lua_NPC::GetAvoidanceRating() return self->GetAvoidanceRating(); } +void Lua_NPC::SetSimpleRoamBox(float box_size) +{ + Lua_Safe_Call_Void(); + self->SetSimpleRoamBox(box_size); +} + +void Lua_NPC::SetSimpleRoamBox(float box_size, float move_distance) +{ + Lua_Safe_Call_Void(); + self->SetSimpleRoamBox(box_size, move_distance); +} + +void Lua_NPC::SetSimpleRoamBox(float box_size, float move_distance, int move_delay) +{ + Lua_Safe_Call_Void(); + self->SetSimpleRoamBox(box_size, move_distance, move_delay); +} + luabind::scope lua_register_npc() { return luabind::class_("NPC") .def(luabind::constructor<>()) @@ -614,6 +632,9 @@ luabind::scope lua_register_npc() { .def("GetGuardPointZ", (float(Lua_NPC::*)(void))&Lua_NPC::GetGuardPointZ) .def("SetPrimSkill", (void(Lua_NPC::*)(int))&Lua_NPC::SetPrimSkill) .def("SetSecSkill", (void(Lua_NPC::*)(int))&Lua_NPC::SetSecSkill) + .def("SetSimpleRoamBox", (void(Lua_NPC::*)(float))&Lua_NPC::SetSimpleRoamBox) + .def("SetSimpleRoamBox", (void(Lua_NPC::*)(float, float))&Lua_NPC::SetSimpleRoamBox) + .def("SetSimpleRoamBox", (void(Lua_NPC::*)(float, float, int))&Lua_NPC::SetSimpleRoamBox) .def("GetPrimSkill", (int(Lua_NPC::*)(void))&Lua_NPC::GetPrimSkill) .def("GetSecSkill", (int(Lua_NPC::*)(void))&Lua_NPC::GetSecSkill) .def("GetSwarmOwner", (int(Lua_NPC::*)(void))&Lua_NPC::GetSwarmOwner) diff --git a/zone/lua_npc.h b/zone/lua_npc.h index 4c407b3fa..92ad73cd7 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -131,6 +131,9 @@ public: void MerchantCloseShop(); int GetRawAC(); int GetAvoidanceRating(); + void SetSimpleRoamBox(float box_size); + void SetSimpleRoamBox(float box_size, float move_distance); + void SetSimpleRoamBox(float box_size, float move_distance, int move_delay); }; #endif diff --git a/zone/mob.cpp b/zone/mob.cpp index b8bedc994..46a5c2fc6 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -2789,10 +2789,10 @@ void Mob::WipeHateList() } } -uint32 Mob::RandomTimer(int min,int max) { +uint32 Mob::RandomTimer(int min, int max) +{ int r = 14000; - if(min != 0 && max != 0 && min < max) - { + if (min != 0 && max != 0 && min < max) { r = zone->random.Int(min, max); } return r; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 31a0fcb40..de7cc68dd 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1579,7 +1579,25 @@ void NPC::AI_DoMovement() { if (GetCWP() == EQEmu::WaypointStatus::RoamBoxPauseInProgress && !IsMoving()) { // We have arrived - time_until_can_move = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay); + + int roambox_move_delay = EQEmu::ClampLower(GetRoamboxDelay(), GetRoamboxMinDelay()); + int move_delay_max = (roambox_move_delay > 0 ? roambox_move_delay : (int) GetRoamboxMinDelay() * 4); + int random_timer = RandomTimer( + GetRoamboxMinDelay(), + move_delay_max + ); + + Log( + Logs::Detail, + Logs::NPCRoamBox, "(%s) Timer calc | random_timer [%i] roambox_move_delay [%i] move_min [%i] move_max [%i]", + this->GetCleanName(), + random_timer, + roambox_move_delay, + (int) GetRoamboxMinDelay(), + move_delay_max + ); + + time_until_can_move = Timer::GetCurrentTime() + random_timer; SetCurrentWP(0); return; } @@ -1636,25 +1654,51 @@ void NPC::AI_DoMovement() { } } - roambox_destination_z = 0; - /* - if (zone->zonemap) { - roambox_destination_z = FindGroundZ(roambox_destination_x, roambox_destination_y, this->GetZOffset()); - } - */ + PathfinderOptions opts; + opts.smooth_path = true; + opts.step_size = RuleR(Pathing, NavmeshStepSize); + opts.offset = GetZOffset(); + opts.flags = PathingNotDisabled ^ PathingZoneLine; - Log(Logs::Detail, + auto partial = false; + auto stuck = false; + auto route = zone->pathing->FindPath( + glm::vec3(GetX(), GetY(), GetZ()), + glm::vec3( + roambox_destination_x, + roambox_destination_y, + GetGroundZ(roambox_destination_x, roambox_destination_y) + ), + partial, + stuck, + opts + ); + + if (route.empty()) { + Log( + Logs::Detail, + Logs::NPCRoamBox, "(%s) We don't have a path route... exiting...", + this->GetCleanName() + ); + return; + } + + roambox_destination_z = 0; + + Log( + Logs::General, Logs::NPCRoamBox, - "Calculate | NPC: %s distance %.3f | min_x %.3f | max_x %.3f | final_x %.3f | min_y %.3f | max_y %.3f | final_y %.3f", + "NPC (%s) distance [%.0f] X (min/max) [%.0f / %.0f] Y (min/max) [%.0f / %.0f] | Dest x/y/z [%.0f / %.0f / %.0f]", this->GetCleanName(), roambox_distance, roambox_min_x, roambox_max_x, - roambox_destination_x, roambox_min_y, roambox_max_y, - roambox_destination_y); - Log(Logs::Detail, Logs::NPCRoamBox, "Dest Z is (%f)", roambox_destination_z); + roambox_destination_x, + roambox_destination_y, + roambox_destination_z + ); SetCurrentWP(EQEmu::WaypointStatus::RoamBoxPauseInProgress); NavigateTo(roambox_destination_x, roambox_destination_y, roambox_destination_z); diff --git a/zone/mob_info.cpp b/zone/mob_info.cpp index 8cf486dea..edac37768 100644 --- a/zone/mob_info.cpp +++ b/zone/mob_info.cpp @@ -278,7 +278,7 @@ inline std::string GetMobAttributeByString(Mob *mob, const std::string &attribut return std::to_string((int)npc->GetWalkspeed()); } if (attribute == "spawngroup") { - return std::to_string(npc->GetSp2()); + return std::to_string(npc->GetSpawnGroupId()); } if (attribute == "grid") { return std::to_string(npc->GetGrid()); diff --git a/zone/npc.cpp b/zone/npc.cpp index ebbf5397f..755664f49 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -146,33 +146,33 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi size = GetRaceGenderDefaultHeight(race, gender); } - taunting = false; - proximity = nullptr; - copper = 0; - silver = 0; - gold = 0; - platinum = 0; - max_dmg = npc_type_data->max_dmg; - min_dmg = npc_type_data->min_dmg; - attack_count = npc_type_data->attack_count; - grid = 0; - wp_m = 0; - max_wp = 0; - save_wp = 0; - spawn_group = 0; - swarmInfoPtr = nullptr; - spellscale = npc_type_data->spellscale; - healscale = npc_type_data->healscale; - pAggroRange = npc_type_data->aggroradius; - pAssistRange = npc_type_data->assistradius; - findable = npc_type_data->findable; - trackable = npc_type_data->trackable; - MR = npc_type_data->MR; - CR = npc_type_data->CR; - DR = npc_type_data->DR; - FR = npc_type_data->FR; - PR = npc_type_data->PR; - Corrup = npc_type_data->Corrup; + taunting = false; + proximity = nullptr; + copper = 0; + silver = 0; + gold = 0; + platinum = 0; + max_dmg = npc_type_data->max_dmg; + min_dmg = npc_type_data->min_dmg; + attack_count = npc_type_data->attack_count; + grid = 0; + wp_m = 0; + max_wp = 0; + save_wp = 0; + spawn_group_id = 0; + swarmInfoPtr = nullptr; + spellscale = npc_type_data->spellscale; + healscale = npc_type_data->healscale; + pAggroRange = npc_type_data->aggroradius; + pAssistRange = npc_type_data->assistradius; + findable = npc_type_data->findable; + trackable = npc_type_data->trackable; + MR = npc_type_data->MR; + CR = npc_type_data->CR; + DR = npc_type_data->DR; + FR = npc_type_data->FR; + PR = npc_type_data->PR; + Corrup = npc_type_data->Corrup; PhR = npc_type_data->PhR; STR = npc_type_data->STR; STA = npc_type_data->STA; @@ -1270,7 +1270,7 @@ uint32 ZoneDatabase::CreateNewNPCCommand(const char *zone, uint32 zone_version, } uint32 spawngroupid = results.LastInsertedID(); - spawn->SetSp2(spawngroupid); + spawn->SetSpawnGroupId(spawngroupid); spawn->SetNPCTypeID(npc_type_id); query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) " @@ -1355,7 +1355,7 @@ uint32 ZoneDatabase::DeleteSpawnLeaveInNPCTypeTable(const char *zone, Client *cl std::string query = StringFormat("SELECT id, spawngroupID FROM spawn2 WHERE " "zone='%s' AND spawngroupID=%i", - zone, spawn->GetSp2()); + zone, spawn->GetSpawnGroupId()); auto results = QueryDatabase(query); if (!results.Success()) return 0; @@ -1396,7 +1396,7 @@ uint32 ZoneDatabase::DeleteSpawnRemoveFromNPCTypeTable(const char *zone, uint32 std::string query = StringFormat("SELECT id, spawngroupID FROM spawn2 WHERE zone = '%s' " "AND (version = %u OR version = -1) AND spawngroupID = %i", - zone, zone_version, spawn->GetSp2()); + zone, zone_version, spawn->GetSpawnGroupId()); auto results = QueryDatabase(query); if (!results.Success()) return 0; @@ -2924,3 +2924,15 @@ bool NPC::IsProximitySet() return false; } + +void NPC::SetSimpleRoamBox(float box_size, float move_distance, int move_delay) +{ + AI_SetRoambox( + (move_distance != 0 ? move_distance : box_size / 2), + GetX() + box_size, + GetX() - box_size, + GetY() + box_size, + GetY() - box_size, + move_delay + ); +} \ No newline at end of file diff --git a/zone/npc.h b/zone/npc.h index 1957b8e63..4c913f70d 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -214,13 +214,13 @@ public: virtual int32 CalcMaxMana(); void SetGrid(int32 grid_){ grid=grid_; } - void SetSp2(uint32 sg2){ spawn_group=sg2; } + void SetSpawnGroupId(uint32 sg2){ spawn_group_id =sg2; } void SetWaypointMax(uint16 wp_){ wp_m=wp_; } void SetSaveWaypoint(uint16 wp_){ save_wp=wp_; } uint16 GetWaypointMax() const { return wp_m; } int32 GetGrid() const { return grid; } - uint32 GetSp2() const { return spawn_group; } + uint32 GetSpawnGroupId() const { return spawn_group_id; } uint32 GetSpawnPointID() const; glm::vec4 const GetSpawnPoint() const { return m_SpawnPoint; } @@ -453,6 +453,8 @@ public: bool IgnoreDespawn() { return ignore_despawn; } + void SetSimpleRoamBox(float box_size, float move_distance = 0, int move_delay = 0); + float GetRoamboxMaxX() const; float GetRoamboxMaxY() const; float GetRoamboxMinX() const; @@ -478,13 +480,13 @@ protected: friend class EntityList; friend class Aura; std::list faction_list; - uint32 copper; - uint32 silver; - uint32 gold; - uint32 platinum; - int32 grid; - uint32 spawn_group; - uint16 wp_m; + uint32 copper; + uint32 silver; + uint32 gold; + uint32 platinum; + int32 grid; + uint32 spawn_group_id; + uint16 wp_m; int32 npc_faction_id; int32 primary_faction; diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index 8c68af734..366aad2ec 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -571,7 +571,7 @@ XS(XS_NPC_SetSp2) { if (THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - THIS->SetSp2(sg2); + THIS->SetSpawnGroupId(sg2); } XSRETURN_EMPTY; } @@ -644,7 +644,7 @@ XS(XS_NPC_GetSp2) { if (THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->GetSp2(); + RETVAL = THIS->GetSpawnGroupId(); XSprePUSH; PUSHu((UV) RETVAL); } @@ -2377,6 +2377,42 @@ XS(XS_NPC_GetCombatState) { XSRETURN(1); } +XS(XS_NPC_SetSimpleRoamBox); /* prototype to pass -Wmissing-prototypes */ +XS(XS_NPC_SetSimpleRoamBox) { + dXSARGS; + if (items < 2) + Perl_croak(aTHX_ "Usage: NPC::SetSimpleRoamBox(THIS, box_size, move_distance, move_delay)"); + { + NPC *THIS; + + auto box_size = (float) SvNV(ST(1)); + float move_distance = 0; + int move_delay = 0; + + if (items >= 3) { + move_distance = (float) SvNV(ST(2)); + } + + if (items >= 4) { + move_delay = (int) SvIV(ST(3)); + } + + if (sv_derived_from(ST(0), "NPC")) { + IV tmp = SvIV((SV *) SvRV(ST(0))); + THIS = INT2PTR(NPC *, tmp); + } + else { + Perl_croak(aTHX_ "THIS is not of type NPC"); + } + if (THIS == nullptr) { + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + } + + THIS->SetSimpleRoamBox(box_size, move_distance, move_delay); + } + XSRETURN_EMPTY; +} + #ifdef __cplusplus extern "C" #endif @@ -2488,6 +2524,7 @@ XS(boot_NPC) { newXSproto(strcpy(buf, "ChangeLastName"), XS_NPC_ChangeLastName, file, "$:$"); newXSproto(strcpy(buf, "ClearLastName"), XS_NPC_ClearLastName, file, "$"); newXSproto(strcpy(buf, "GetCombatState"), XS_NPC_GetCombatState, file, "$"); + newXSproto(strcpy(buf, "SetSimpleRoamBox"), XS_NPC_SetSimpleRoamBox, file, "$$;$$"); XSRETURN_YES; } diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 19c779d87..64e5bd008 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -234,59 +234,48 @@ Mob* QuestManager::unique_spawn(int npc_type, int grid, int unused, const glm::v return nullptr; } -Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id) +Mob *QuestManager::spawn_from_spawn2(uint32 spawn2_id) { - LinkedListIterator iterator(zone->spawn2_list); + LinkedListIterator iterator(zone->spawn2_list); iterator.Reset(); Spawn2 *found_spawn = nullptr; - while(iterator.MoreElements()) - { - Spawn2* cur = iterator.GetData(); + while (iterator.MoreElements()) { + Spawn2 *cur = iterator.GetData(); iterator.Advance(); - if(cur->GetID() == spawn2_id) - { + if (cur->GetID() == spawn2_id) { found_spawn = cur; break; } } - if(found_spawn) - { - SpawnGroup* sg = zone->spawn_group_list.GetSpawnGroup(found_spawn->SpawnGroupID()); - if(!sg) - { - database.LoadSpawnGroupsByID(found_spawn->SpawnGroupID(),&zone->spawn_group_list); - sg = zone->spawn_group_list.GetSpawnGroup(found_spawn->SpawnGroupID()); - if(!sg) - { + if (found_spawn) { + SpawnGroup *spawn_group = zone->spawn_group_list.GetSpawnGroup(found_spawn->SpawnGroupID()); + if (!spawn_group) { + database.LoadSpawnGroupsByID(found_spawn->SpawnGroupID(), &zone->spawn_group_list); + spawn_group = zone->spawn_group_list.GetSpawnGroup(found_spawn->SpawnGroupID()); + if (!spawn_group) { return nullptr; } } - uint32 npcid = sg->GetNPCType(); - if(npcid == 0) - { + uint32 npcid = spawn_group->GetNPCType(); + if (npcid == 0) { return nullptr; } - const NPCType* tmp = database.LoadNPCTypesData(npcid); - if(!tmp) - { + const NPCType *tmp = database.LoadNPCTypesData(npcid); + if (!tmp) { return nullptr; } - if(tmp->unique_spawn_by_name) - { - if(!entity_list.LimitCheckName(tmp->name)) - { + if (tmp->unique_spawn_by_name) { + if (!entity_list.LimitCheckName(tmp->name)) { return nullptr; } } - if(tmp->spawn_limit > 0) - { - if(!entity_list.LimitCheckType(npcid, tmp->spawn_limit)) - { + if (tmp->spawn_limit > 0) { + if (!entity_list.LimitCheckType(npcid, tmp->spawn_limit)) { return nullptr; } } @@ -294,21 +283,35 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id) database.UpdateRespawnTime(spawn2_id, zone->GetInstanceID(), 0); found_spawn->SetCurrentNPCID(npcid); - auto position = glm::vec4(found_spawn->GetX(), found_spawn->GetY(), found_spawn->GetZ(), found_spawn->GetHeading()); + auto position = glm::vec4( + found_spawn->GetX(), + found_spawn->GetY(), + found_spawn->GetZ(), + found_spawn->GetHeading() + ); + auto npc = new NPC(tmp, found_spawn, position, GravityBehavior::Water); found_spawn->SetNPCPointer(npc); npc->AddLootTable(); - if (npc->DropsGlobalLoot()) + if (npc->DropsGlobalLoot()) { npc->CheckGlobalLootTables(); - npc->SetSp2(found_spawn->SpawnGroupID()); + } + npc->SetSpawnGroupId(found_spawn->SpawnGroupID()); entity_list.AddNPC(npc); entity_list.LimitAddNPC(npc); - if (sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay && - sg->min_delay) - npc->AI_SetRoambox(sg->roamdist, sg->roambox[0], sg->roambox[1], sg->roambox[2], sg->roambox[3], - sg->delay, sg->min_delay); + if (spawn_group->roamdist > 0) { + npc->AI_SetRoambox( + spawn_group->roamdist, + spawn_group->roambox[0], + spawn_group->roambox[1], + spawn_group->roambox[2], + spawn_group->roambox[3], + spawn_group->delay, + spawn_group->min_delay + ); + } if (zone->InstantGrids()) { found_spawn->LoadGrid(); } diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index e004faa4a..93c955d4e 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -264,7 +264,7 @@ bool Spawn2::Process() { if (npc->DropsGlobalLoot()) { npc->CheckGlobalLootTables(); } - npc->SetSp2(spawngroup_id_); + npc->SetSpawnGroupId(spawngroup_id_); npc->SaveGuardPointAnim(anim); npc->SetAppearance((EmuAppearance) anim); entity_list.AddNPC(npc); @@ -274,9 +274,7 @@ bool Spawn2::Process() { /** * Roambox init */ - if (spawn_group->roamdist && spawn_group->roambox[0] && spawn_group->roambox[1] && spawn_group->roambox[2] && - spawn_group->roambox[3] && spawn_group->delay && spawn_group->min_delay) { - + if (spawn_group->roamdist > 0) { npc->AI_SetRoambox( spawn_group->roamdist, spawn_group->roambox[0], @@ -298,7 +296,8 @@ bool Spawn2::Process() { npcid, x, y, - z); + z + ); LoadGrid(); } diff --git a/zone/spawngroup.cpp b/zone/spawngroup.cpp index 7cb5cd803..41cd14060 100644 --- a/zone/spawngroup.cpp +++ b/zone/spawngroup.cpp @@ -16,8 +16,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include "../common/global_define.h" -#include "../common/string_util.h" #include "../common/types.h" #include "entity.h" @@ -26,209 +26,352 @@ #include "zonedb.h" extern EntityList entity_list; -extern Zone* zone; +extern Zone *zone; -SpawnEntry::SpawnEntry( uint32 in_NPCType, int in_chance, uint8 in_npc_spawn_limit ) { - NPCType = in_NPCType; - chance = in_chance; +SpawnEntry::SpawnEntry(uint32 in_NPCType, int in_chance, uint8 in_npc_spawn_limit) +{ + NPCType = in_NPCType; + chance = in_chance; npc_spawn_limit = in_npc_spawn_limit; } -SpawnGroup::SpawnGroup( uint32 in_id, char* name, int in_group_spawn_limit, float dist, float maxx, float minx, float maxy, float miny, int delay_in, int despawn_in, uint32 despawn_timer_in, int min_delay_in ) { +SpawnGroup::SpawnGroup( + uint32 in_id, + char *name, + int in_group_spawn_limit, + float dist, + float maxx, + float minx, + float maxy, + float miny, + int delay_in, + int despawn_in, + uint32 despawn_timer_in, + int min_delay_in +) +{ id = in_id; - strn0cpy( name_, name, 120); + strn0cpy(name_, name, 120); group_spawn_limit = in_group_spawn_limit; - roambox[0]=maxx; - roambox[1]=minx; - roambox[2]=maxy; - roambox[3]=miny; - roamdist=dist; - min_delay=min_delay_in; - delay=delay_in; - despawn=despawn_in; - despawn_timer=despawn_timer_in; + roambox[0] = maxx; + roambox[1] = minx; + roambox[2] = maxy; + roambox[3] = miny; + roamdist = dist; + min_delay = min_delay_in; + delay = delay_in; + despawn = despawn_in; + despawn_timer = despawn_timer_in; } -uint32 SpawnGroup::GetNPCType() { +uint32 SpawnGroup::GetNPCType() +{ #if EQDEBUG >= 10 Log(Logs::General, Logs::None, "SpawnGroup[%08x]::GetNPCType()", (uint32) this); #endif - int npcType = 0; + int npcType = 0; int totalchance = 0; - if(!entity_list.LimitCheckGroup(id, group_spawn_limit)) - return(0); + if (!entity_list.LimitCheckGroup(id, group_spawn_limit)) { + return (0); + } - std::list::iterator cur,end; - std::list possible; + std::list::iterator cur, end; + std::list possible; cur = list_.begin(); end = list_.end(); - for(; cur != end; ++cur) { + for (; cur != end; ++cur) { SpawnEntry *se = *cur; - if(!entity_list.LimitCheckType(se->NPCType, se->npc_spawn_limit)) + if (!entity_list.LimitCheckType(se->NPCType, se->npc_spawn_limit)) { continue; + } totalchance += se->chance; possible.push_back(se); } - if(totalchance == 0) + if (totalchance == 0) { return 0; + } int32 roll = 0; - roll = zone->random.Int(0, totalchance-1); + roll = zone->random.Int(0, totalchance - 1); cur = possible.begin(); end = possible.end(); - for(; cur != end; ++cur) { + for (; cur != end; ++cur) { SpawnEntry *se = *cur; if (roll < se->chance) { npcType = se->NPCType; break; - } else { + } + else { roll -= se->chance; } } return npcType; } -void SpawnGroup::AddSpawnEntry( SpawnEntry* newEntry ) { - list_.push_back( newEntry ); +void SpawnGroup::AddSpawnEntry(SpawnEntry *newEntry) +{ + list_.push_back(newEntry); } -SpawnGroup::~SpawnGroup() { - std::list::iterator cur,end; +SpawnGroup::~SpawnGroup() +{ + std::list::iterator cur, end; cur = list_.begin(); end = list_.end(); - for(; cur != end; ++cur) { - SpawnEntry* tmp = *cur; + for (; cur != end; ++cur) { + SpawnEntry *tmp = *cur; safe_delete(tmp); } list_.clear(); } -SpawnGroupList::~SpawnGroupList() { - std::map::iterator cur,end; - cur = groups.begin(); - end = groups.end(); - for(; cur != end; ++cur) { - SpawnGroup* tmp = cur->second; +SpawnGroupList::~SpawnGroupList() +{ + std::map::iterator cur, end; + cur = m_spawn_groups.begin(); + end = m_spawn_groups.end(); + for (; cur != end; ++cur) { + SpawnGroup *tmp = cur->second; safe_delete(tmp); } - groups.clear(); + m_spawn_groups.clear(); } -void SpawnGroupList::AddSpawnGroup(SpawnGroup* newGroup) { - if(newGroup == nullptr) +void SpawnGroupList::AddSpawnGroup(SpawnGroup *new_group) +{ + if (new_group == nullptr) { return; - groups[newGroup->id] = newGroup; + } + + m_spawn_groups[new_group->id] = new_group; } -SpawnGroup* SpawnGroupList::GetSpawnGroup(uint32 in_id) { - if(groups.count(in_id) != 1) +SpawnGroup *SpawnGroupList::GetSpawnGroup(uint32 in_id) +{ + if (m_spawn_groups.count(in_id) != 1) { return nullptr; - return(groups[in_id]); + } + + return (m_spawn_groups[in_id]); } -bool SpawnGroupList::RemoveSpawnGroup(uint32 in_id) { - if(groups.count(in_id) != 1) - return(false); +bool SpawnGroupList::RemoveSpawnGroup(uint32 in_id) +{ + if (m_spawn_groups.count(in_id) != 1) { + return (false); + } - groups.erase(in_id); - return(true); + m_spawn_groups.erase(in_id); + + return (true); +} + +void SpawnGroupList::ReloadSpawnGroups() +{ + ClearSpawnGroups(); + database.LoadSpawnGroups(zone->GetShortName(), zone->GetInstanceVersion(), &zone->spawn_group_list); +} + +void SpawnGroupList::ClearSpawnGroups() +{ + m_spawn_groups.clear(); } bool ZoneDatabase::LoadSpawnGroups(const char *zone_name, uint16 version, SpawnGroupList *spawn_group_list) { - std::string query = StringFormat("SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, " - "spawngroup.dist, spawngroup.max_x, spawngroup.min_x, " - "spawngroup.max_y, spawngroup.min_y, spawngroup.delay, " - "spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay " - "FROM spawn2, spawngroup WHERE spawn2.spawngroupID = spawngroup.ID " - "AND spawn2.version = %u and zone = '%s'", - version, zone_name); + std::string query = fmt::format( + SQL( + SELECT + DISTINCT(spawngroupID), + spawngroup.name, + spawngroup.spawn_limit, + spawngroup.dist, + spawngroup.max_x, + spawngroup.min_x, + spawngroup.max_y, + spawngroup.min_y, + spawngroup.delay, + spawngroup.despawn, + spawngroup.despawn_timer, + spawngroup.mindelay + FROM + spawn2, + spawngroup + WHERE + spawn2.spawngroupID = spawngroup.ID + AND + spawn2.version = {} and zone = '{}' + ), + version, + zone_name + ); + auto results = QueryDatabase(query); if (!results.Success()) { return false; } for (auto row = results.begin(); row != results.end(); ++row) { - auto newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), - atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), - atoi(row[9]), atoi(row[10]), atoi(row[11])); - spawn_group_list->AddSpawnGroup(newSpawnGroup); + auto new_spawn_group = new SpawnGroup( + atoi(row[0]), + row[1], + atoi(row[2]), + atof(row[3]), + atof(row[4]), + atof(row[5]), + atof(row[6]), + atof(row[7]), + atoi(row[8]), + atoi(row[9]), + atoi(row[10]), + atoi(row[11]) + ); + + spawn_group_list->AddSpawnGroup(new_spawn_group); } - query = StringFormat("SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, " - "npc_types.spawn_limit AS sl " - "FROM spawnentry, spawn2, npc_types " - "WHERE spawnentry.npcID=npc_types.id " - "AND spawnentry.spawngroupID = spawn2.spawngroupID " - "AND zone = '%s'", - zone_name); + query = fmt::format( + SQL( + SELECT + DISTINCT + spawnentry.spawngroupID, + npcid, + chance, + npc_types.spawn_limit + AS sl + FROM + spawnentry, + spawn2, + npc_types + WHERE + spawnentry.npcID = npc_types.id + AND + spawnentry.spawngroupID = spawn2.spawngroupID + AND + zone = '{}'), + zone_name + ); + results = QueryDatabase(query); if (!results.Success()) { - Log(Logs::General, Logs::Error, "Error2 in PopulateZoneLists query '%'", query.c_str()); return false; } for (auto row = results.begin(); row != results.end(); ++row) { - auto newSpawnEntry = new SpawnEntry(atoi(row[1]), atoi(row[2]), row[3] ? atoi(row[3]) : 0); - SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0])); + auto new_spawn_entry = new SpawnEntry( + atoi(row[1]), + atoi(row[2]), + (row[3] ? atoi(row[3]) : 0) + ); - if (!sg) { - safe_delete(newSpawnEntry); + SpawnGroup *spawn_group = spawn_group_list->GetSpawnGroup(atoi(row[0])); + + if (!spawn_group) { + safe_delete(new_spawn_entry); continue; } - sg->AddSpawnEntry(newSpawnEntry); + spawn_group->AddSpawnEntry(new_spawn_entry); } return true; } -bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList *spawn_group_list) +/** + * @param spawn_group_id + * @param spawn_group_list + * @return + */ +bool ZoneDatabase::LoadSpawnGroupsByID(int spawn_group_id, SpawnGroupList *spawn_group_list) { - std::string query = StringFormat("SELECT DISTINCT(spawngroup.id), spawngroup.name, spawngroup.spawn_limit, " - "spawngroup.dist, spawngroup.max_x, spawngroup.min_x, " - "spawngroup.max_y, spawngroup.min_y, spawngroup.delay, " - "spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay " - "FROM spawngroup WHERE spawngroup.ID = '%i'", - spawngroupid); + std::string query = fmt::format( + SQL( + SELECT DISTINCT + (spawngroup.id), + spawngroup.name, + spawngroup.spawn_limit, + spawngroup.dist, + spawngroup.max_x, + spawngroup.min_x, + spawngroup.max_y, + spawngroup.min_y, + spawngroup.delay, + spawngroup.despawn, + spawngroup.despawn_timer, + spawngroup.mindelay + FROM + spawngroup + WHERE + spawngroup.ID = '{}' + ), + spawn_group_id + ); + auto results = QueryDatabase(query); if (!results.Success()) { - Log(Logs::General, Logs::Error, "Error2 in PopulateZoneLists query %s", query.c_str()); return false; } for (auto row = results.begin(); row != results.end(); ++row) { - auto newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), - atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), - atoi(row[9]), atoi(row[10]), atoi(row[11])); - spawn_group_list->AddSpawnGroup(newSpawnGroup); + auto new_spawn_group = new SpawnGroup( + atoi(row[0]), + row[1], + atoi(row[2]), + atof(row[3]), + atof(row[4]), + atof(row[5]), + atof(row[6]), + atof(row[7]), + atoi(row[8]), + atoi(row[9]), + atoi(row[10]), + atoi(row[11]) + ); + + spawn_group_list->AddSpawnGroup(new_spawn_group); } - query = StringFormat("SELECT DISTINCT(spawnentry.spawngroupID), spawnentry.npcid, " - "spawnentry.chance, spawngroup.spawn_limit FROM spawnentry, spawngroup " - "WHERE spawnentry.spawngroupID = '%i' AND spawngroup.spawn_limit = '0' " - "ORDER BY chance", - spawngroupid); + query = fmt::format( + SQL( + SELECT DISTINCT + (spawnentry.spawngroupID), + spawnentry.npcid, + spawnentry.chance, + spawngroup.spawn_limit + FROM + spawnentry, + spawngroup + WHERE + spawnentry.spawngroupID = '{}' + AND spawngroup.spawn_limit = '0' + ORDER BY chance), + spawn_group_id + ); + results = QueryDatabase(query); if (!results.Success()) { - Log(Logs::General, Logs::Error, "Error3 in PopulateZoneLists query '%s'", query.c_str()); return false; } for (auto row = results.begin(); row != results.end(); ++row) { - auto newSpawnEntry = new SpawnEntry(atoi(row[1]), atoi(row[2]), row[3] ? atoi(row[3]) : 0); - SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0])); - if (!sg) { - safe_delete(newSpawnEntry); + auto new_spawn_entry = new SpawnEntry( + atoi(row[1]), + atoi(row[2]), + (row[3] ? atoi(row[3]) : 0) + ); + + SpawnGroup *spawn_group = spawn_group_list->GetSpawnGroup(atoi(row[0])); + if (!spawn_group) { + safe_delete(new_spawn_entry); continue; } - sg->AddSpawnEntry(newSpawnEntry); + spawn_group->AddSpawnEntry(new_spawn_entry); } return true; diff --git a/zone/spawngroup.h b/zone/spawngroup.h index b5f6d18cf..4b68a35eb 100644 --- a/zone/spawngroup.h +++ b/zone/spawngroup.h @@ -23,50 +23,63 @@ #include #include -class SpawnEntry -{ +class SpawnEntry { public: - SpawnEntry(uint32 in_NPCType, int in_chance, uint8 in_npc_spawn_limit ); - ~SpawnEntry() { } + SpawnEntry(uint32 in_NPCType, int in_chance, uint8 in_npc_spawn_limit); + ~SpawnEntry() {} uint32 NPCType; - int chance; + int chance; //this is a cached value from npc_types, for speed uint8 npc_spawn_limit; //max # of this entry which can be spawned in this zone }; -class SpawnGroup -{ +class SpawnGroup { public: - SpawnGroup(uint32 in_id, char* name, int in_group_spawn_limit, float dist, float maxx, float minx, float maxy, float miny, int delay_in, int despawn_in, uint32 despawn_timer_in, int min_delay_in ); + SpawnGroup( + uint32 in_id, + char *name, + int in_group_spawn_limit, + float dist, + float maxx, + float minx, + float maxy, + float miny, + int delay_in, + int despawn_in, + uint32 despawn_timer_in, + int min_delay_in + ); + ~SpawnGroup(); uint32 GetNPCType(); - void AddSpawnEntry( SpawnEntry* newEntry ); + void AddSpawnEntry(SpawnEntry *newEntry); uint32 id; - float roamdist; - float roambox[4]; - int min_delay; - int delay; - int despawn; + float roamdist; + float roambox[4]; + int min_delay; + int delay; + int despawn; uint32 despawn_timer; private: char name_[120]; - std::list list_; + std::list list_; uint8 group_spawn_limit; //max # of this entry which can be spawned by this group }; -class SpawnGroupList -{ +class SpawnGroupList { public: - SpawnGroupList() { } + SpawnGroupList() {} ~SpawnGroupList(); - void AddSpawnGroup(SpawnGroup* newGroup); - SpawnGroup* GetSpawnGroup(uint32 id); + void AddSpawnGroup(SpawnGroup *new_group); + SpawnGroup *GetSpawnGroup(uint32 id); bool RemoveSpawnGroup(uint32 in_id); + void ClearSpawnGroups(); + void ReloadSpawnGroups(); private: //LinkedList list_; - std::map groups; + std::map m_spawn_groups; }; #endif diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index bc9e3870d..ebbf5fda5 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -57,7 +57,16 @@ void NPC::AI_SetRoambox(float max_distance, float roam_distance_variance, uint32 ); } -void NPC::AI_SetRoambox(float distance, float max_x, float min_x, float max_y, float min_y, uint32 delay, uint32 min_delay) { +void NPC::AI_SetRoambox( + float distance, + float max_x, + float min_x, + float max_y, + float min_y, + uint32 delay, + uint32 min_delay +) +{ roambox_distance = distance; roambox_max_x = max_x; roambox_min_x = min_x; @@ -71,10 +80,10 @@ void NPC::AI_SetRoambox(float distance, float max_x, float min_x, float max_y, f void NPC::DisplayWaypointInfo(Client *c) { c->Message(Chat::White, "Mob is on grid %d, in spawn group %d, on waypoint %d/%d", - GetGrid(), - GetSp2(), - GetCurWp(), - GetMaxWp()); + GetGrid(), + GetSpawnGroupId(), + GetCurWp(), + GetMaxWp()); std::vector::iterator cur, end; diff --git a/zone/zone.cpp b/zone/zone.cpp index f364ab298..8ca78735f 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1485,6 +1485,8 @@ bool Zone::Depop(bool StartSpawnTimer) { // clear spell cache database.ClearNPCSpells(); + zone->spawn_group_list.ReloadSpawnGroups(); + return true; } diff --git a/zone/zonedb.h b/zone/zonedb.h index f2103715a..e93a40713 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -409,7 +409,7 @@ public: /* Spawns and Spawn Points */ bool LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list); - bool LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list); + bool LoadSpawnGroupsByID(int spawn_group_id, SpawnGroupList* spawn_group_list); bool PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay = 0); bool PopulateZoneSpawnListClose(uint32 zoneid, LinkedList &spawn2_list, int16 version, const glm::vec4& client_position, uint32 repop_distance); Spawn2* LoadSpawn2(LinkedList &spawn2_list, uint32 spawn2id, uint32 timeleft);