From 9917be3094c5684d50e4dd58d83bb3373977741f Mon Sep 17 00:00:00 2001 From: nytmyr <53322305+nytmyr@users.noreply.github.com> Date: Sun, 8 Dec 2024 22:35:36 -0600 Subject: [PATCH] Correct IsValidSpellRange --- zone/bot.cpp | 128 +++++++++++++++++++++++++++++++++++++++---- zone/botspellsai.cpp | 47 +++++++++------- 2 files changed, 146 insertions(+), 29 deletions(-) diff --git a/zone/bot.cpp b/zone/bot.cpp index bdd3a32e5..523f6c918 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -9690,16 +9690,6 @@ bool Bot::CastChecks(uint16 spell_id, Mob* tar, uint16 spellType, bool doPrechec LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to IsImmuneToBotSpell.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme return false; } - - if (!IsCommandedSpell() && !IsTaunting() && GetSpellTypeAggroCheck(spellType) && HasOrMayGetAggro(IsSitting(), spell_id) && !tar->IsFleeing()) { - LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to HasOrMayGetAggro.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme - return false; - } - - if (!DoResistCheckBySpellType(tar, spell_id, spellType)) { - LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to DoResistCheckBySpellType.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme - return false; - } if ( (RequiresStackCheck(spellType) || (!RequiresStackCheck(spellType) && CalcBuffDuration(this, tar, spell_id) != 0)) @@ -9714,6 +9704,20 @@ bool Bot::CastChecks(uint16 spell_id, Mob* tar, uint16 spellType, bool doPrechec return false; } + if (spellType == UINT16_MAX) { //AA cast checks, return here + return true; + } + + if (!IsTaunting() && GetSpellTypeAggroCheck(spellType) && HasOrMayGetAggro(IsSitting(), spell_id) && !tar->IsFleeing()) { + LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to HasOrMayGetAggro.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme + return false; + } + + if (!DoResistCheckBySpellType(tar, spell_id, spellType)) { + LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to DoResistCheckBySpellType.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme + return false; + } + return true; } @@ -11095,6 +11099,81 @@ bool Bot::AttemptAICastSpell(uint16 spellType) { return result; } +bool Bot::AttemptAACastSpell(Mob* tar, uint16 spell_id, AA::Rank* rank) { + if (!tar) { + tar = this; + } + + if (!DoLosChecks(this, tar)) { + return false; + } + + if (CheckSpellRecastTimer(spell_id)) { + if (IsBeneficialSpell(spell_id)) { + if ( + (tar->IsNPC() && !tar->GetOwner()) || + (tar->GetOwner() && tar->GetOwner()->IsOfClientBot() && !GetOwner()->IsInGroupOrRaid(tar->GetOwner())) || + (tar->IsOfClientBot() && !GetOwner()->IsInGroupOrRaid(tar)) + ) { + GetBotOwner()->Message(Chat::Yellow, "[%s] is an invalid target. Only players or their pet in your group or raid are eligible targets.", tar->GetCleanName()); + + return false; + } + } + + if (IsDetrimentalSpell(spell_id) && !IsAttackAllowed(tar)) { + GetBotOwner()->Message(Chat::Yellow, "%s says, 'I cannot attack [%s]'.", GetCleanName(), tar->GetCleanName()); + + return false; + } + + if (!CastChecks(spell_id, tar, UINT16_MAX)) { + GetBotOwner()->Message(Chat::Red, "%s says, 'Ability failed to cast. This could be due to this to any number of things: range, mana, immune, etc.'", GetCleanName()); + + return false; + } + + + if (CastSpell(spell_id, tar->GetID())) { + BotGroupSay( + this, + fmt::format( + "Casting {} on {}.", + GetSpellName(spell_id), + (tar == this ? "myself" : tar->GetCleanName()) + ).c_str() + ); + + int timer_duration = (rank->recast_time - GetAlternateAdvancementCooldownReduction(rank)) * 1000; + + if (timer_duration < 0) { + timer_duration = 0; + } + + SetSpellRecastTimer(spell_id, timer_duration); + } + else { + GetBotOwner()->Message(Chat::Red, "%s says, 'Ability failed to cast. This could be due to this to any number of things: range, mana, immune, etc.'", GetCleanName()); + + return false; + } + } + else { + GetBotOwner()->Message( + Chat::Yellow, + fmt::format( + "{} says, 'Ability recovery time not yet met. {} remaining.'", + GetCleanName(), + Strings::SecondsToTime(GetSpellRecastRemainingTime(spell_id), true) + ).c_str() + ); + + return false; + } + + return true; +} + uint16 Bot::GetSpellListSpellType(uint16 spellType) { switch (spellType) { case BotSpellTypes::AENukes: @@ -11890,3 +11969,32 @@ bool Bot::IsValidSpellTypeSubType(uint16 spellType, uint16 subType, uint16 spell return false; } + +uint16 Bot::GetSpellByAA(int id, AA::Rank*& rank) { + uint16 spell_id = 0; + std::pair aa_ability = std::make_pair(nullptr, nullptr); + AA::Ability* ability = zone->GetAlternateAdvancementAbility(id); + + if (!ability || !ability->first_rank_id) { + return spell_id; + } + + uint32 points = GetAA(ability->first_rank_id); + //if (points) { LogTestDebug("{}: {} says, '{} points for {} [#{} - {}] rank {}'", __LINE__, GetCleanName(), points, zone->GetAAName(aa_ability.first->id), aa_ability.first->id, aa_ability.second->id, points); } //deleteme + if (points > 0) { + aa_ability = zone->GetAlternateAdvancementAbilityAndRank(ability->id, points); + } + + rank = aa_ability.second; + + if (!points || !rank) { + LogTestDebug("{}: {} says, 'No {} found'", __LINE__, GetCleanName(), (!points ? "points" : "rank")); //deleteme + return spell_id; + } + + spell_id = rank->spell; + + LogTestDebug("{}: {} says, 'Found {} [#{}]'", __LINE__, GetCleanName(), spells[spell_id].name, spell_id); //deleteme + + return spell_id; +} diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index 410aa7e69..b4588811d 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -2669,31 +2669,40 @@ bool Bot::HasBotSpellEntry(uint16 spell_id) { } bool Bot::IsValidSpellRange(uint16 spell_id, Mob* tar) { - if (!IsValidSpell(spell_id)) { + if (!IsValidSpell(spell_id) || !tar) { return false; } - if (tar) { - float range = spells[spell_id].range; - - if (tar != this) { - range += GetRangeDistTargetSizeMod(tar); - } + float range = spells[spell_id].range + GetRangeDistTargetSizeMod(tar); - range = GetActSpellRange(spell_id, range); - - if (range >= Distance(m_Position, tar->GetPosition())) { - return true; - } - - range = GetActSpellRange(spell_id, spells[spell_id].aoe_range); - - if (range >= Distance(m_Position, tar->GetPosition())) { - return true; - } + if (IsAnyAESpell(spell_id)) { + range = GetAOERange(spell_id); + } + + if (RuleB(Bots, EnableBotTGB) && IsTGBCompatibleSpell(spell_id) && IsGroupSpell(spell_id)) { + range = spells[spell_id].aoe_range; } - return false; + range = GetActSpellRange(spell_id, range); + + if (IsIllusionSpell(spell_id) && (HasProjectIllusion())) { + range = 100; + } + + float dist2 = DistanceSquared(m_Position, tar->GetPosition()); + float range2 = range * range; + float min_range2 = spells[spell_id].min_range * spells[spell_id].min_range; + + if (dist2 > range2) { + //target is out of range. + return false; + } + else if (dist2 < min_range2) { + //target is too close range. + return false; + } + + return true; } BotSpell Bot::GetBestBotSpellForNukeByBodyType(Bot* botCaster, uint8 bodyType, uint16 spellType, bool AE, Mob* tar) {