diff --git a/zone/bot.cpp b/zone/bot.cpp index 01e3db6c3..a18ba699c 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -109,6 +109,9 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm GenerateBaseStats(); bot_timers.clear(); bot_blocked_buffs.clear(); + _spellTargetList.clear(); + _groupSpellTargetList.clear(); + _storedRaid = nullptr; // Calculate HitPoints Last As It Uses Base Stats current_hp = GenerateBaseHitPoints(); @@ -258,6 +261,9 @@ Bot::Bot( database.botdb.LoadBotBlockedBuffs(this); } + _spellTargetList.clear(); + _groupSpellTargetList.clear(); + _storedRaid = nullptr; LoadAAs(); if (database.botdb.LoadBuffs(this)) { @@ -2095,7 +2101,7 @@ void Bot::AI_Process() else { follow_mob = entity_list.GetMob(GetFollowID()); - if (!follow_mob || !IsInGroupOrRaid(follow_mob, raid)) { + if (!follow_mob || !IsInGroupOrRaid(follow_mob)) { follow_mob = leash_owner; } } @@ -2126,6 +2132,12 @@ void Bot::AI_Process() return; } + SetStoredRaid(raid); + std::vector spellTargetList = GatherSpellTargets(RuleB(Bots, CrossRaidBuffingAndHealing)); + SetSpellTargetList(spellTargetList); + std::vector groupSpellTargetList = GatherSpellTargets(); + SetGroupSpellTargetList(groupSpellTargetList); + // HEAL ROTATION CASTING CHECKS HealRotationChecks(); @@ -2369,7 +2381,7 @@ void Bot::AI_Process() // AUTO DEFEND - if (TryAutoDefend(bot_owner, leash_distance, raid) ) { + if (TryAutoDefend(bot_owner, leash_distance) ) { return; } @@ -2468,7 +2480,7 @@ bool Bot::TryIdleChecks(float fm_distance) { // This is as close as I could get without modifying the aggro mechanics and making it an expensive process... // 'class Client' doesn't make use of hate_list -bool Bot::TryAutoDefend(Client* bot_owner, float leash_distance, Raid* raid) { +bool Bot::TryAutoDefend(Client* bot_owner, float leash_distance) { if (RuleB(Bots, AllowOwnerOptionAutoDefend) && bot_owner->GetBotOption(Client::booAutoDefend)) { @@ -2505,6 +2517,7 @@ bool Bot::TryAutoDefend(Client* bot_owner, float leash_distance, Raid* raid) { bool assisteeFound = false; if (IsRaidGrouped()) { + Raid* raid = GetStoredRaid(); if (raid) { for (const auto& m : raid->members) { if ( @@ -2555,7 +2568,7 @@ bool Bot::TryAutoDefend(Client* bot_owner, float leash_distance, Raid* raid) { if (bot_owner->GetAssistee()) { Client* c = entity_list.GetClientByCharID(bot_owner->GetAssistee()); - if (bot_owner->IsInGroupOrRaid(c, raid) && c->GetAggroCount()) { + if (bot_owner->IsInGroupOrRaid(c) && c->GetAggroCount()) { tempHaters = bot_owner->GetXTargetAutoMgr(); if (tempHaters && !tempHaters->empty()) { @@ -5976,7 +5989,7 @@ bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQ::spe if ( spellTarget && GetClass() != Class::Bard && - (IsGrouped() || (IsRaidGrouped() && GetRaid()->GetGroup(GetCleanName()) != RAID_GROUPLESS)) && + (IsGrouped() || (IsRaidGrouped() && GetStoredRaid()->GetGroup(GetCleanName()) != RAID_GROUPLESS)) && (spellTarget->IsBot() || spellTarget->IsClient()) && (RuleB(Bots, GroupBuffing) || RuleB(Bots, RaidBuffing)) ) { @@ -6008,7 +6021,12 @@ bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQ::spe if (!noGroupSpell) { std::vector v; - v = GatherSpellTargets(RuleB(Bots, RaidBuffing)); + if (RuleB(Bots, RaidBuffing)) { + v = GetSpellTargetList(); + } + else { + v = GatherSpellTargets(false, spellTarget); + } for (Mob* m : v) { if (IsEffectInSpell(thespell, SE_AbsorbMagicAtt) || IsEffectInSpell(thespell, SE_Rune)) { @@ -6043,7 +6061,7 @@ bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQ::spe bool Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQ::spells::CastingSlot slot, bool& stopLogic) { bool isMainGroupMGB = false; - Raid* raid = entity_list.GetRaidByBot(this); + Raid* raid = GetStoredRaid(); if (isMainGroupMGB && (GetClass() != Class::Bard)) { BotGroupSay( @@ -6065,7 +6083,7 @@ bool Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQ::spel std::vector v; if (RuleB(Bots, RaidBuffing)) { - v = GatherSpellTargets(true); + v = GetSpellTargetList(); } else { v = GatherSpellTargets(false, spellTarget); @@ -7206,11 +7224,11 @@ bool Bot::CheckLoreConflict(const EQ::ItemData* item) { return (m_inv.HasItemByLoreGroup(item->LoreGroup, invWhereWorn) != INVALID_INDEX); } -bool Bot::AttemptCloseBeneficialSpells(uint16 spellType, Raid* raid, std::vector targetList) { +bool Bot::AttemptCloseBeneficialSpells(uint16 spellType) { bool result = false; Mob* tar = nullptr; - for (Mob* m : targetList) { + for (Mob* m : GetSpellTargetList()) { tar = m; if (!tar) { @@ -7218,12 +7236,13 @@ bool Bot::AttemptCloseBeneficialSpells(uint16 spellType, Raid* raid, std::vector } if (IsGroupTargetOnlyBotSpellType(spellType)) { + Raid* raid = GetStoredRaid(); if (raid && (raid->GetGroup(GetName()) == raid->GetGroup(tar->GetName()))) { continue; } } - result = AttemptAICastSpell(spellType, tar, raid); + result = AttemptAICastSpell(spellType, tar); if (!result) { if (tar->HasPet() && (!m->GetPet()->IsFamiliar() || RuleB(Bots, AllowBuffingHealingFamiliars))) { @@ -7237,7 +7256,7 @@ bool Bot::AttemptCloseBeneficialSpells(uint16 spellType, Raid* raid, std::vector continue; } - result = AttemptAICastSpell(spellType, tar, raid); + result = AttemptAICastSpell(spellType, tar); } } @@ -7752,7 +7771,7 @@ void Bot::BotGroupSay(Mob* speaker, const char* msg, ...) { va_end(ap); if (speaker->IsRaidGrouped()) { - Raid* r = entity_list.GetRaidByBot(speaker->CastToBot()); + Raid* r = speaker->CastToBot()->GetStoredRaid(); if (r) { for (const auto& m : r->members) { if (m.member && !m.is_bot) { @@ -9699,16 +9718,21 @@ bool Bot::BotHasEnoughMana(uint16 spell_id) { return true; } -bool Bot::IsTargetAlreadyReceivingSpell(Mob* tar, uint16 spell_id) { +bool Bot::IsTargetAlreadyReceivingSpell(Mob* tar, uint16 spell_id) { //TODO bot rewrite - add raid and spell targets if (!tar || !spell_id) { return true; } std::vector v; uint16 targetID = tar->GetID(); - - v = GatherSpellTargets(RuleB(Bots, CrossRaidBuffingAndHealing)); - + + if (RuleB(Bots, CrossRaidBuffingAndHealing)) { + v = GetSpellTargetList(); + } + else { + v = GetGroupSpellTargetList(); + } + for (Mob* m : v) { if ( m->IsBot() && @@ -9716,7 +9740,7 @@ bool Bot::IsTargetAlreadyReceivingSpell(Mob* tar, uint16 spell_id) { m->CastToBot()->casting_spell_targetid && m->CastingSpellID() == spell_id ) { - if (IsGroupSpell(spell_id)) { + if (RuleB(Bots, CrossRaidBuffingAndHealing) && IsGroupSpell(spell_id)) { std::vector t = GatherSpellTargets(false, tar); for (Mob* x : t) { @@ -9849,9 +9873,7 @@ bool Bot::IsMobEngagedByAnyone(Mob* tar) { return false; } - const std::vector v = GatherSpellTargets(true); - - for (Mob* m : v) { + for (Mob* m : GetSpellTargetList()) { if (m->GetTarget() == tar) { if ( m->IsBot() && @@ -10763,7 +10785,7 @@ std::list Bot::GetSpellTypesPrioritized(uint8 priorityType) { return castOrder; } -bool Bot::AttemptAICastSpell(uint16 spellType, Mob* tar, Raid* raid) { +bool Bot::AttemptAICastSpell(uint16 spellType, Mob* tar) { bool result = false; if (!tar) { @@ -10787,12 +10809,12 @@ bool Bot::AttemptAICastSpell(uint16 spellType, Mob* tar, Raid* raid) { tar = this; } - if (!PrecastChecks(tar, spellType) || !AICastSpell(tar, GetChanceToCastBySpellType(spellType), spellType, raid)) { + if (!PrecastChecks(tar, spellType) || !AICastSpell(tar, GetChanceToCastBySpellType(spellType), spellType)) { return result; } } else { - if (!PrecastChecks(tar, spellType) || !AICastSpell(tar, GetChanceToCastBySpellType(spellType), spellType, raid)) { + if (!PrecastChecks(tar, spellType) || !AICastSpell(tar, GetChanceToCastBySpellType(spellType), spellType)) { return result; } } @@ -10948,7 +10970,7 @@ bool Bot::AttemptForcedCastSpell(Mob* tar, uint16 spell_id) { !RuleB(Bots, EnableBotTGB) && IsGroupSpell(forcedSpellID) && !IsTGBCompatibleSpell(forcedSpellID) && - !IsInGroupOrRaid(tar, nullptr, true) + !IsInGroupOrRaid(tar, true) ) { LogTestDebug("{} failed TGB for {} [#{}].", GetCleanName(), spell.name, forcedSpellID); //deleteme return false; diff --git a/zone/bot.h b/zone/bot.h index 381b4de54..7edb42517 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -397,11 +397,11 @@ public: void AI_Bot_Event_SpellCastFinished(bool iCastSucceeded, uint16 slot); // AI Methods - bool AICastSpell(Mob* tar, uint8 iChance, uint16 spellType, Raid* raid = nullptr, uint16 subTargetType = UINT16_MAX, uint16 subType = UINT16_MAX); - bool AttemptAICastSpell(uint16 spellType, Mob* tar = nullptr, Raid* raid = nullptr); + bool AICastSpell(Mob* tar, uint8 iChance, uint16 spellType, uint16 subTargetType = UINT16_MAX, uint16 subType = UINT16_MAX); + bool AttemptAICastSpell(uint16 spellType, Mob* tar = nullptr); bool AttemptAACastSpell(Mob* tar, uint16 spell_id, AA::Rank* rank); bool AttemptForcedCastSpell(Mob* tar, uint16 spell_id); - bool AttemptCloseBeneficialSpells(uint16 spellType, Raid* raid, std::vector targetList); + bool AttemptCloseBeneficialSpells(uint16 spellType); bool AI_EngagedCastCheck() override; bool AI_PursueCastCheck() override; bool AI_IdleCastCheck() override; @@ -460,6 +460,12 @@ public: bool CastChecks(uint16 spell_id, Mob* tar, uint16 spellType, bool doPrechecks = false, bool AECheck = false); bool CanCastSpellType(uint16 spellType, uint16 spell_id, Mob* tar); bool BotHasEnoughMana(uint16 spell_id); + std::vector GetSpellTargetList() { return _spellTargetList; } + void SetSpellTargetList(std::vector spellTargetList) { _spellTargetList = spellTargetList; } + std::vector GetGroupSpellTargetList() { return _groupSpellTargetList; } + void SetGroupSpellTargetList(std::vector spellTargetList) { _groupSpellTargetList = spellTargetList; } + Raid* GetStoredRaid() { return _storedRaid; } + void SetStoredRaid(Raid* storedRaid) { _storedRaid = storedRaid; } bool IsTargetAlreadyReceivingSpell(Mob* tar, uint16 spell_id); bool DoResistCheck(Mob* target, uint16 spell_id, int32 resist_limit); bool DoResistCheckBySpellType(Mob* tar, uint16 spell_id, uint16 spellType); @@ -476,7 +482,6 @@ public: void SetBotBaseSetting(uint16 botSetting, int settingValue); void LoadDefaultBotSettings(); void SetBotSpellRecastTimer(uint16 spellType, Mob* spelltar, bool preCast = false); - BotSpell GetSpellByHealType(uint16 spellType, Mob* tar); uint16 GetSpellByAA(int id, AA::Rank* &rank); void CleanBotBlockedBuffs(); void ClearBotBlockedBuffs() { bot_blocked_buffs.clear(); } @@ -598,6 +603,7 @@ public: static std::vector GetPrioritizedBotSpellsBySpellType(Bot* botCaster, uint16 spellType, Mob* tar, bool AE = false, uint16 subTargetType = UINT16_MAX, uint16 subType = UINT16_MAX); static BotSpell GetFirstBotSpellBySpellType(Bot* botCaster, uint16 spellType); + BotSpell GetSpellByHealType(uint16 spellType, Mob* tar); static BotSpell GetBestBotSpellForVeryFastHeal(Bot* botCaster, Mob* tar, uint16 spellType = BotSpellTypes::RegularHeal); static BotSpell GetBestBotSpellForFastHeal(Bot* botCaster, Mob* tar, uint16 spellType = BotSpellTypes::RegularHeal); static BotSpell GetBestBotSpellForHealOverTime(Bot* botCaster, Mob* tar, uint16 spellType = BotSpellTypes::RegularHeal); @@ -608,7 +614,7 @@ public: static BotSpell GetBestBotSpellForGroupCompleteHeal(Bot* botCaster, Mob* tar, uint16 spellType = BotSpellTypes::RegularHeal); static BotSpell GetBestBotSpellForGroupHeal(Bot* botCaster, Mob* tar, uint16 spellType = BotSpellTypes::RegularHeal); - static Mob* GetFirstIncomingMobToMez(Bot* botCaster, int16 spell_id, uint16 spellType, bool AE = false); + static Mob* GetFirstIncomingMobToMez(Bot* botCaster, int16 spell_id, uint16 spellType, bool AE); bool IsValidMezTarget(Mob* owner, Mob* npc, uint16 spell_id); static BotSpell GetBestBotSpellForMez(Bot* botCaster, uint16 spellType = BotSpellTypes::Mez); static BotSpell GetBestBotMagicianPetSpell(Bot* botCaster, uint16 spellType = BotSpellTypes::Pet); @@ -988,7 +994,7 @@ public: bool TryFacingTarget(Mob* tar); bool TryPursueTarget(float leash_distance, glm::vec3& Goal); bool TryMeditate(); - bool TryAutoDefend(Client* bot_owner, float leash_distance, Raid* raid = nullptr); + bool TryAutoDefend(Client* bot_owner, float leash_distance); bool TryIdleChecks(float fm_distance); bool TryNonCombatMovementChecks(Client* bot_owner, const Mob* follow_mob, glm::vec3& Goal); bool TryBardMovementCasts(); @@ -1093,6 +1099,10 @@ private: bool _commandedSpell; bool _pullingSpell; + std::vector _spellTargetList; // TODO bot rewrite - implement this and raid + std::vector _groupSpellTargetList; + Raid* _storedRaid; + // Private "base stats" Members int32 _baseMR; int32 _baseCR; diff --git a/zone/bot_commands/cast.cpp b/zone/bot_commands/cast.cpp index b62162e75..709e91956 100644 --- a/zone/bot_commands/cast.cpp +++ b/zone/bot_commands/cast.cpp @@ -588,7 +588,7 @@ void bot_command_cast(Client* c, const Seperator* sep) LogTestDebug("{}: {} says, 'Attempting {} [{}-{}] on [{}]'", __LINE__, bot_iter->GetCleanName(), c->GetSpellTypeNameByID(spellType), (subType != UINT16_MAX ? c->GetSubTypeNameByID(subType) : "Standard"), (subTargetType != UINT16_MAX ? c->GetSubTypeNameByID(subTargetType) : "Standard"), (newTar ? newTar->GetCleanName() : "NOBODY")); //deleteme bot_iter->SetCommandedSpell(true); - if (bot_iter->AICastSpell(newTar, 100, spellType, nullptr, subTargetType, subType)) { + if (bot_iter->AICastSpell(newTar, 100, spellType, subTargetType, subType)) { if (!firstFound) { firstFound = bot_iter; } diff --git a/zone/mob.cpp b/zone/mob.cpp index f1b6a1738..bed534071 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -9954,7 +9954,7 @@ void Mob::ClearDataBucketCache() } } -bool Mob::IsInGroupOrRaid(Mob *other, Raid* raid, bool sameRaidGroup) { +bool Mob::IsInGroupOrRaid(Mob *other, bool sameRaidGroup) { if (!other || !IsOfClientBotMerc() || !other->IsOfClientBotMerc()) { return false; } @@ -9963,9 +9963,18 @@ bool Mob::IsInGroupOrRaid(Mob *other, Raid* raid, bool sameRaidGroup) { return true; } - if (IsRaidGrouped() && !raid) { - raid = GetRaid(); + Raid* raid = nullptr; + if (IsBot) { + CastToBot()->GetStoredRaid(); + } + else { + if (IsRaidGrouped()) { + raid = GetRaid(); + } + } + + if (IsRaidGrouped()) { if (!raid) { return false; } @@ -9975,8 +9984,22 @@ bool Mob::IsInGroupOrRaid(Mob *other, Raid* raid, bool sameRaidGroup) { if (!other->IsRaidGrouped()) { return false; } + + Raid* otherRaid = nullptr; + + if (other->IsBot()) { + otherRaid = other->CastToBot()->GetStoredRaid(); + } + else { + otherRaid = other->GetRaid(); + } + + if (!otherRaid) { + return false; + } + auto rGroup = raid->GetGroup(GetCleanName()); - auto rOGroup = raid->GetGroup(other->GetCleanName()); + auto rOGroup = otherRaid->GetGroup(other->GetCleanName()); if (rGroup == RAID_GROUPLESS || rOGroup == RAID_GROUPLESS || (sameRaidGroup && rGroup != rOGroup)) { return false;