diff --git a/zone/bot.cpp b/zone/bot.cpp index 81981d01d..44f40c692 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -425,11 +425,6 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to cur_end = max_end; - // Safety Check to confirm we have a valid group - if (HasGroup() && !GetGroup()->IsGroupMember(GetBotOwner())) { - Bot::RemoveBotFromGroup(this, GetGroup()); - } - // Safety Check to confirm we have a valid raid if (HasRaid() && !GetRaid()->IsRaidMember(GetBotOwner()->CastToClient())) { Bot::RemoveBotFromRaid(this); @@ -3111,7 +3106,6 @@ Client* Bot::SetLeashOwner(Client* bot_owner, Group* bot_group, Raid* raid, uint raid->GetGroupLeader(r_group)->CastToClient() : bot_owner; } else if (bot_group) { - bot_group->VerifyGroup(); leash_owner = (bot_group->GetLeader() && bot_group->GetLeader()->IsClient() ? bot_group->GetLeader()->CastToClient() : bot_owner); } else { @@ -3321,11 +3315,18 @@ bool Bot::Spawn(Client* botCharacterOwner) { } } - if (Raid* raid = entity_list.GetRaidByBotName(GetName())) - { + Raid* raid = nullptr; + Group* group = nullptr; + + if (raid = entity_list.GetRaidByBotName(GetName())) { raid->VerifyRaid(); SetRaidGrouped(true); } + else if (group = entity_list.GetGroupByMobName(GetName())) { + group->VerifyGroup(); + SetGrouped(true); + } + return true; } @@ -3863,21 +3864,18 @@ bool Bot::RemoveBotFromGroup(Bot* bot, Group* group) { bool Bot::AddBotToGroup(Bot* bot, Group* group) { bool Result = false; - if (bot && group) { - // Add bot to this group - if (group->AddMember(bot)) { - if (group->GetLeader()) { - bot->SetFollowID(group->GetLeader()->GetID()); - // Need to send this only once when a group is formed with a bot so the client knows it is also the group leader - if (group->GroupCount() == 2 && group->GetLeader()->IsClient()) { - group->UpdateGroupAAs(); - Mob *TempLeader = group->GetLeader(); - group->SendUpdate(groupActUpdate, TempLeader); - } + if (bot && group && group->AddMember(bot)) { + if (group->GetLeader()) { + bot->SetFollowID(group->GetLeader()->GetID()); + // Need to send this only once when a group is formed with a bot so the client knows it is also the group leader + if (group->GroupCount() == 2 && group->GetLeader()->IsClient()) { + group->UpdateGroupAAs(); + Mob *TempLeader = group->GetLeader(); + group->SendUpdate(groupActUpdate, TempLeader); } - group->VerifyGroup(); - Result = true; } + group->VerifyGroup(); + Result = true; } return Result; } @@ -6680,7 +6678,11 @@ void Bot::Camp(bool save_to_database) { Save(); } - Depop(); + if (HasGroup() || HasRaid()) { + Zone(); + } else { + Depop(); + } } void Bot::Zone() { @@ -8582,24 +8584,34 @@ void Bot::SpawnBotGroupByName(Client* c, const std::string& botgroup_name, uint3 return; } - if (!leader->Spawn(c)) { - c->Message( - Chat::White, - fmt::format( - "Could not spawn bot-group leader {} for '{}'.", - leader->GetName(), - botgroup_name - ).c_str() - ); - safe_delete(leader); - return; + if (!leader->spawned) { + if (!leader->Spawn(c)) { + c->Message( + Chat::White, + fmt::format( + "Could not spawn bot-group leader {} for '{}'.", + leader->GetName(), + botgroup_name + ).c_str() + ); + safe_delete(leader); + return; + } } - auto* g = new Group(leader); + auto group = leader->GetGroupByLeaderName(); + auto raid = leader->GetRaid(); + + if (!raid && group) { + group->SetLeader(leader); + } + else if (!raid) { + group = new Group(leader); + entity_list.AddGroup(group); + database.SetGroupID(leader->GetCleanName(), group->GetID(), leader->GetBotID()); + database.SetGroupLeaderName(group->GetID(), leader->GetCleanName()); + } - entity_list.AddGroup(g); - database.SetGroupID(leader->GetCleanName(), g->GetID(), leader->GetBotID()); - database.SetGroupLeaderName(g->GetID(), leader->GetCleanName()); leader->SetFollowID(c->GetID()); uint32 botgroup_id = 0; @@ -8686,23 +8698,33 @@ void Bot::SpawnBotGroupByName(Client* c, const std::string& botgroup_name, uint3 continue; } - if (!member->Spawn(c)) { - c->Message( - Chat::White, - fmt::format( - "Could not spawn bot '{}' (ID {}).", - member->GetName(), - member_iter - ).c_str() - ); - safe_delete(member); - return; + if (!member->spawned) { + if (!member->Spawn(c)) { + c->Message( + Chat::White, + fmt::format( + "Could not spawn bot '{}' (ID {}).", + member->GetName(), + member_iter + ).c_str() + ); + safe_delete(member); + return; + } + + spawned_bot_count++; + bot_class_spawned_count[member->GetClass() - 1]++; + + if (group) { + Bot::AddBotToGroup(member, group); + } } + } - spawned_bot_count++; - bot_class_spawned_count[member->GetClass() - 1]++; - - Bot::AddBotToGroup(member, g); + if (group) { + group->VerifyGroup(); + } else if (raid) { + raid->VerifyRaid(); } c->Message( diff --git a/zone/bot.h b/zone/bot.h index f383304ce..b77e0f919 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -141,6 +141,7 @@ public: bool HasGroup() final { return GetGroup() != nullptr; } Raid* GetRaid() final { return entity_list.GetRaidByBot(this); } Group* GetGroup() final { return entity_list.GetGroupByMob(this); } + Group* GetGroupByLeaderName() { return entity_list.GetGroupByLeaderName(GetName()); } // Common, but informal "interfaces" with Client object uint32 CharacterID() const { return GetBotID(); } diff --git a/zone/entity.cpp b/zone/entity.cpp index 49c21a1da..9ded585bf 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -2119,6 +2119,18 @@ Group *EntityList::GetGroupByMob(Mob *mob) return nullptr; } +Group *EntityList::GetGroupByMobName(const char* name) +{ + for (const auto& g : group_list) { + for (const auto& m : g->membername) { + if (strcmp(m, name) == 0) { + return g; + } + } + } + return nullptr; +} + Group *EntityList::GetGroupByLeaderName(const char *leader) { std::list::iterator iterator; diff --git a/zone/entity.h b/zone/entity.h index 5a2939e60..079a33a0a 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -193,6 +193,7 @@ public: NPC* GetRandomNPC(const glm::vec3& location = glm::vec3(0.f), float distance = 0, NPC* exclude_npc = nullptr); Mob* GetRandomMob(const glm::vec3& location = glm::vec3(0.f), float distance = 0, Mob* exclude_mob = nullptr); Group* GetGroupByMob(Mob* mob); + Group* GetGroupByMobName(const char* name); Group* GetGroupByBot(Bot* bot); bool IsInSameGroupOrRaidGroup(Client *client1, Client *client2); Group *GetGroupByClient(Client* client); diff --git a/zone/groups.cpp b/zone/groups.cpp index d803904d6..58db3edf9 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -547,11 +547,13 @@ bool Group::UpdatePlayer(Mob* update) { void Group::MemberZoned(Mob* removemob) { uint32 i; - if (removemob == nullptr) + if (!removemob) { return; + } - if(removemob == GetLeader()) + if (removemob == GetLeader()) { SetLeader(nullptr); + } //should NOT clear the name, it is used for world communication. for (auto & m : members) { @@ -560,17 +562,21 @@ void Group::MemberZoned(Mob* removemob) { } } - if(removemob->IsClient() && HasRole(removemob, RoleAssist)) + if (removemob->IsClient() && HasRole(removemob, RoleAssist)) { SetGroupAssistTarget(0); + } - if(removemob->IsClient() && HasRole(removemob, RoleTank)) + if (removemob->IsClient() && HasRole(removemob, RoleTank)) { SetGroupTankTarget(0); + } - if(removemob->IsClient() && HasRole(removemob, RolePuller)) + if (removemob->IsClient() && HasRole(removemob, RolePuller)) { SetGroupPullerTarget(0); + } - if (removemob->IsClient() && removemob == mentoree) + if (removemob->IsClient() && removemob == mentoree) { mentoree = nullptr; + } if (RuleB(Bots, Enabled)) { Bot::UpdateGroupCastingRoles(this);