diff --git a/zone/bot.cpp b/zone/bot.cpp index 5da128aa6..cb5f89ed2 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -176,6 +176,9 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to if (GetClass() == ROGUE) evade_timer.Start(); + m_CastingRoles.GroupHealer = false; + m_CastingRoles.GroupSlower = false; + GenerateBaseStats(); if (!botdb.LoadTimers(this) && bot_owner) @@ -6835,66 +6838,116 @@ bool Bot::IsBotCasterCombatRange(Mob *target) { return result; } -bool Bot::IsGroupPrimaryHealer() { - bool result = false; - uint8 botclass = GetClass(); - if(HasGroup()) { - Group *g = GetGroup(); - switch(botclass) { - case CLERIC: { - result = true; - break; - } - case DRUID: { - result = GroupHasClericClass(g) ? false : true; - break; - } - case SHAMAN: { - result = (GroupHasClericClass(g) || GroupHasDruidClass(g)) ? false : true; - break; - } - case PALADIN: - case RANGER: - case BEASTLORD: { - result = GroupHasPriestClass(g) ? false : true; - break; - } - default: { - result = false; - break; - } +void Bot::UpdateGroupCastingRoles(const Group* group, bool disband) +{ + if (!group) + return; + + for (auto iter : group->members) { + if (!iter) + continue; + + if (iter->IsBot()) { + iter->CastToBot()->SetGroupHealer(false); + iter->CastToBot()->SetGroupSlower(false); } } - return result; -} + if (disband) + return; -bool Bot::IsGroupPrimarySlower() { - bool result = false; - uint8 botclass = GetClass(); - if(HasGroup()) { - Group *g = GetGroup(); - switch(botclass) { - case SHAMAN: { - result = true; - break; - } - case ENCHANTER: { - result = GroupHasShamanClass(g) ? false : true; - break; - } - case BEASTLORD: { - result = (GroupHasShamanClass(g) || GroupHasEnchanterClass(g)) ? false : true; - break; - } - default: { - result = false; - break; - } + Mob* healer = nullptr; + Mob* slower = nullptr; + + for (auto iter : group->members) { + if (!iter) + continue; + + switch (iter->GetClass()) { + case CLERIC: + if (!healer) + healer = iter; + else + switch (healer->GetClass()) { + case CLERIC: + break; + default: + healer = iter; + } + + break; + case DRUID: + if (!healer) + healer = iter; + else + switch (healer->GetClass()) { + case CLERIC: + case DRUID: + break; + default: + healer = iter; + } + break; + case SHAMAN: + if (!healer) + healer = iter; + else + switch (healer->GetClass()) { + case CLERIC: + case DRUID: + case SHAMAN: + break; + default: + healer = iter; + } + break; + case PALADIN: + case RANGER: + case BEASTLORD: + if (!healer) + healer = iter; + break; + default: + break; + } + + switch (iter->GetClass()) { + case SHAMAN: + if (!slower) + slower = iter; + else + switch (slower->GetClass()) { + case SHAMAN: + break; + default: + slower = iter; + } + break; + case ENCHANTER: + if (!slower) + slower = iter; + else + switch (slower->GetClass()) { + case SHAMAN: + case ENCHANTER: + break; + default: + slower = iter; + } + break; + case BEASTLORD: + if (!slower) + slower = iter; + break; + default: + break; } } - return result; + if (healer && healer->IsBot()) + healer->CastToBot()->SetGroupHealer(); + if (slower && slower->IsBot()) + slower->CastToBot()->SetGroupSlower(); } bool Bot::CanHeal() { diff --git a/zone/bot.h b/zone/bot.h index 17855ad38..dd22f1498 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -132,7 +132,8 @@ enum SpellTypeIndex { MaxSpellTypes }; -enum BotCastingChanceConditional : uint8 { nHS = 0, pH, pS, pHS, cntHS }; // negative Healer/Slower, positive Healer, postive Slower, positive Healer/Slower +// negative Healer/Slower, positive Healer, postive Slower, positive Healer/Slower +enum BotCastingChanceConditional : uint8 { nHS = 0, pH, pS, pHS, cntHS = 4 }; class Bot : public NPC { @@ -475,8 +476,11 @@ public: BotRoleType GetBotRole() { return _botRole; } BotStanceType GetBotStance() { return _botStance; } uint8 GetChanceToCastBySpellType(uint32 spellType); - bool IsGroupPrimaryHealer(); - bool IsGroupPrimarySlower(); + + bool IsGroupHealer() { return m_CastingRoles.GroupHealer; } + bool IsGroupSlower() { return m_CastingRoles.GroupSlower; } + static void UpdateGroupCastingRoles(const Group* group, bool disband = false); + bool IsBotCaster() { return IsCasterClass(GetClass()); } bool IsBotINTCaster() { return IsINTCasterClass(GetClass()); } bool IsBotWISCaster() { return IsWISCasterClass(GetClass()); } @@ -640,6 +644,10 @@ protected: virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0); virtual float GetMaxMeleeRangeToTarget(Mob* target); + BotCastingRoles& GetCastingRoles() { return m_CastingRoles; } + void SetGroupHealer(bool flag = true) { m_CastingRoles.GroupHealer = flag; } + void SetGroupSlower(bool flag = true) { m_CastingRoles.GroupSlower = flag; } + private: // Class Members uint32 _botID; @@ -679,6 +687,8 @@ private: Timer evade_timer; + BotCastingRoles m_CastingRoles; + std::shared_ptr m_member_of_heal_rotation; std::map botAAs; diff --git a/zone/bot_structs.h b/zone/bot_structs.h index a774bad70..8200c9933 100644 --- a/zone/bot_structs.h +++ b/zone/bot_structs.h @@ -60,6 +60,11 @@ struct BotSpell_wPriority : public BotSpell { uint8 Priority; }; +struct BotCastingRoles { + bool GroupHealer; + bool GroupSlower; +}; + struct BotAA { uint32 aa_id; uint8 req_level; diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index 783b735b7..51546eb2a 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -108,7 +108,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) { bool isPrimaryHealer = false; if(HasGroup()) { - isPrimaryHealer = IsGroupPrimaryHealer(); + isPrimaryHealer = IsGroupHealer(); } if(hpr < 95 || (tar->IsClient() && (hpr < 95)) || (botClass == BARD)) { @@ -2590,9 +2590,9 @@ uint8 Bot::GetChanceToCastBySpellType(uint32 spellType) uint8 type_index = nHS; if (HasGroup()) { - if (IsGroupPrimaryHealer()) + if (IsGroupHealer()) type_index |= pH; - if (IsGroupPrimarySlower()) + if (IsGroupSlower()) type_index |= pS; } diff --git a/zone/groups.cpp b/zone/groups.cpp index 94a2b0032..6eff2cee6 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -347,6 +347,10 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte safe_delete(outapp); +#ifdef BOTS + Bot::UpdateGroupCastingRoles(this); +#endif + return true; } @@ -481,6 +485,10 @@ bool Group::UpdatePlayer(Mob* update){ if (update->IsClient() && !mentoree && mentoree_name.length() && !mentoree_name.compare(update->GetName())) mentoree = update->CastToClient(); +#ifdef BOTS + Bot::UpdateGroupCastingRoles(this); +#endif + return updateSuccess; } @@ -513,6 +521,10 @@ void Group::MemberZoned(Mob* removemob) { if (removemob->IsClient() && removemob == mentoree) mentoree = nullptr; + +#ifdef BOTS + Bot::UpdateGroupCastingRoles(this); +#endif } void Group::SendGroupJoinOOZ(Mob* NewMember) { @@ -721,6 +733,10 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender) ClearAllNPCMarks(); } +#ifdef BOTS + Bot::UpdateGroupCastingRoles(this); +#endif + return true; } @@ -864,6 +880,10 @@ uint32 Group::GetTotalGroupDamage(Mob* other) { } void Group::DisbandGroup(bool joinraid) { +#ifdef BOTS + Bot::UpdateGroupCastingRoles(this, true); +#endif + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate_Struct)); GroupUpdate_Struct* gu = (GroupUpdate_Struct*) outapp->pBuffer;