diff --git a/common/ruletypes.h b/common/ruletypes.h index 9a7b3acbd..4d57b4f82 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -824,6 +824,9 @@ RULE_INT(Bots, MinTargetsForAESpell, 3, "Minimum number of targets in valid rang RULE_INT(Bots, MinTargetsForGroupSpell, 3, "Minimum number of targets in valid range that are required for an group spell to cast. Default 3.") RULE_BOOL(Bots, AllowBuffingHealingFamiliars, false, "Determines if bots are allowed to buff and heal familiars. Default false.") RULE_BOOL(Bots, RunSpellTypeChecksOnSpawn, false, "This will run a serious of checks on spell types and output errors to LogBotSpellTypeChecks") +RULE_BOOL(Bots, UseParentSpellTypeForChecks, true, "This will check only the parent instead of AE/Group/Pet types (ex: AENukes/AERains/PBAENukes fall under Nukes or PetBuffs fall under buffs) when RunSpellTypeChecksOnSpawn fires") +RULE_BOOL(Bots, AllowForcedCastsBySpellID, true, "If enabled, players can use ^cast spellid # to cast a specific spell by ID that is in their spell list") +RULE_BOOL(Bots, AllowCastAAs, true, "If enabled, players can use ^cast aa to cast a clickable AA") RULE_BOOL(Bots, AllowMagicianEpicPet, false, "If enabled, magician bots can summon their epic pets following the rules AllowMagicianEpicPetLevel") RULE_INT(Bots, AllowMagicianEpicPetLevel, 50, "If AllowMagicianEpicPet is enabled, bots can start using their epic pets at this level") RULE_INT(Bots, RequiredMagicianEpicPetItemID, 28034, "If AllowMagicianEpicPet is enabled and this is set, bots will be required to have this item ID equipped to cast their epic. Takes in to account AllowMagicianEpicPetLevel as well. Set to 0 to disable requirement") diff --git a/common/spdat.cpp b/common/spdat.cpp index c91255394..cbff31731 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -1582,11 +1582,11 @@ bool IsRegularPetHealSpell(uint16 spell_id) if (spell_id) { if ( - spells[spell_id].target_type == ST_Pet && + (spells[spell_id].target_type == ST_Pet || spells[spell_id].target_type == ST_Undead) && !IsCompleteHealSpell(spell_id) && !IsHealOverTimeSpell(spell_id) && !IsGroupSpell(spell_id) - ) { + ) { for (int i = 0; i < EFFECT_COUNT; i++) { if ( spells[spell_id].base_value[i] > 0 && @@ -1594,8 +1594,8 @@ bool IsRegularPetHealSpell(uint16 spell_id) ( spells[spell_id].effect_id[i] == SE_CurrentHP || spells[spell_id].effect_id[i] == SE_CurrentHPOnce - ) - ) { + ) + ) { return true; } } @@ -3229,6 +3229,17 @@ bool IsDamageShieldOnlySpell(uint16 spell_id) { return true; } +bool IsHateSpell(uint16 spell_id) { + if ( + (IsEffectInSpell(spell_id, SE_Hate) && spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_Hate)] > 0) || + (IsEffectInSpell(spell_id, SE_InstantHate) && spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_InstantHate)] > 0) + ) { + return true; + } + + return false; +} + bool IsCommandedSpellType(uint16 spellType) { switch (spellType) { case BotSpellTypes::Charm: @@ -3281,3 +3292,234 @@ bool IsPullingSpellType(uint16 spellType) { return false; } + +uint16 GetCorrectSpellType(uint16 spellType, uint16 spell_id) { + uint16 correctType = UINT16_MAX; + SPDat_Spell_Struct spell = spells[spell_id]; + std::string teleportZone = spell.teleport_zone; + + if (IsCharmSpell(spell_id)) { + correctType = BotSpellTypes::Charm; + } + else if (IsFearSpell(spell_id)) { + correctType = BotSpellTypes::Fear; + } + else if (IsEffectInSpell(spell_id, SE_Revive)) { + correctType = BotSpellTypes::Resurrect; + } + else if (IsHarmonySpell(spell_id)) { + correctType = BotSpellTypes::Lull; + } + else if (teleportZone.compare("") && !IsEffectInSpell(spell_id, SE_GateToHomeCity) && IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))) { + correctType = BotSpellTypes::Teleport; + } + else if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_Succor)) { + correctType = BotSpellTypes::Succor; + } + else if (IsEffectInSpell(spell_id, SE_BindAffinity)) { + correctType = BotSpellTypes::BindAffinity; + } + else if (IsEffectInSpell(spell_id, SE_Identify)) { + correctType = BotSpellTypes::Identify; + } + else if (spellType == BotSpellTypes::Levitate && IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_Levitate))) { + correctType = BotSpellTypes::Levitate; + } + else if (spellType == BotSpellTypes::Rune && IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_AbsorbMagicAtt) || IsEffectInSpell(spell_id, SE_Rune))) { + correctType = BotSpellTypes::Rune; + } + else if (spellType == BotSpellTypes::WaterBreathing && IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_WaterBreathing)) { + correctType = BotSpellTypes::WaterBreathing; + } + else if (spellType == BotSpellTypes::Size && IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_ModelSize) || IsEffectInSpell(spell_id, SE_ChangeHeight))) { + correctType = BotSpellTypes::Size; + } + else if (spellType == BotSpellTypes::Invisibility && IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_SeeInvis) || IsInvisibleSpell(spell_id))) { + correctType = BotSpellTypes::Invisibility; + } + else if (spellType == BotSpellTypes::MovementSpeed && IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_MovementSpeed)) { + correctType = BotSpellTypes::MovementSpeed; + } + else if (!teleportZone.compare("") && IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_Translocate) || IsEffectInSpell(spell_id, SE_GateToHomeCity))) { + correctType = BotSpellTypes::SendHome; + } + else if (IsEffectInSpell(spell_id, SE_SummonCorpse)) { + correctType = BotSpellTypes::SummonCorpse; + } + + if (correctType == UINT16_MAX) { + if (IsSummonPetSpell(spell_id) || IsEffectInSpell(spell_id, SE_TemporaryPets)) { + correctType = BotSpellTypes::Pet; + } + else if (IsMesmerizeSpell(spell_id)) { + correctType = BotSpellTypes::Mez; + } + else if (IsEscapeSpell(spell_id)) { + correctType = BotSpellTypes::Escape; + } + else if (IsDetrimentalSpell(spell_id) && IsEffectInSpell(spell_id, SE_Root)) { + if (IsAnyAESpell(spell_id)) { + correctType = BotSpellTypes::AERoot; + } + else { + correctType = BotSpellTypes::Root; + } + } + else if (IsDetrimentalSpell(spell_id) && IsLifetapSpell(spell_id)) { + correctType = BotSpellTypes::Lifetap; + } + else if (IsDetrimentalSpell(spell_id) && IsEffectInSpell(spell_id, SE_MovementSpeed)) { + correctType = BotSpellTypes::Snare; + } + else if (IsDetrimentalSpell(spell_id) && (IsStackableDOT(spell_id) || IsDamageOverTimeSpell(spell_id))) { + correctType = BotSpellTypes::DOT; + } + else if (IsDispelSpell(spell_id)) { + correctType = BotSpellTypes::Dispel; + } + else if (IsDetrimentalSpell(spell_id) && IsSlowSpell(spell_id)) { + correctType = BotSpellTypes::Slow; + } + else if (IsDebuffSpell(spell_id) && !IsHateReduxSpell(spell_id) && !IsHateSpell(spell_id)) { + correctType = BotSpellTypes::Debuff; + } + else if (IsHateReduxSpell(spell_id)) { + correctType = BotSpellTypes::HateRedux; + } + else if (IsDetrimentalSpell(spell_id) && IsHateSpell(spell_id)) { + correctType = BotSpellTypes::HateLine; + } + else if ( + IsBuffSpell(spell_id) && + IsBeneficialSpell(spell_id) && + IsBardSong(spell_id) + ) { + if ( + spellType == BotSpellTypes::InCombatBuffSong || + spellType == BotSpellTypes::OutOfCombatBuffSong || + spellType == BotSpellTypes::PreCombatBuffSong + ) { + correctType = spellType; + } + else { + correctType = BotSpellTypes::OutOfCombatBuffSong; + } + } + else if ( + !IsBardSong(spell_id) && + ( + (IsSelfConversionSpell(spell_id) && spell.buff_duration < 1) || + (spellType == BotSpellTypes::InCombatBuff && IsAnyBuffSpell(spell_id)) + ) + ) { + correctType = BotSpellTypes::InCombatBuff; + } + else if ( + spellType == BotSpellTypes::PreCombatBuff && + IsAnyBuffSpell(spell_id) && + !IsBardSong(spell_id) + ) { + correctType = BotSpellTypes::PreCombatBuff; + } + else if ( + (IsCureSpell(spell_id) && spellType == BotSpellTypes::Cure) || + (IsCureSpell(spell_id) && !IsAnyHealSpell(spell_id)) + ) { + correctType = BotSpellTypes::Cure; + } + else if (IsAnyNukeOrStunSpell(spell_id)) { + if (IsAnyAESpell(spell_id)) { + if (IsAERainSpell(spell_id)) { + correctType = BotSpellTypes::AERains; + } + else if (IsPBAENukeSpell(spell_id)) { + correctType = BotSpellTypes::PBAENuke; + } + else if (IsStunSpell(spell_id)) { + correctType = BotSpellTypes::AEStun; + } + else { + correctType = BotSpellTypes::AENukes; + } + } + else if (IsStunSpell(spell_id)) { + correctType = BotSpellTypes::Stun; + } + else { + correctType = BotSpellTypes::Nuke; + } + } + else if (IsAnyHealSpell(spell_id)) { + if (IsGroupSpell(spell_id)) { + if (IsGroupCompleteHealSpell(spell_id)) { + correctType = BotSpellTypes::GroupCompleteHeals; + } + else if (IsGroupHealOverTimeSpell(spell_id)) { + correctType = BotSpellTypes::GroupHoTHeals; + } + else if (IsRegularGroupHealSpell(spell_id)) { + correctType = BotSpellTypes::GroupHeals; + } + } + else { + if (IsVeryFastHealSpell(spell_id)) { + correctType = BotSpellTypes::VeryFastHeals; + } + else if (IsFastHealSpell(spell_id)) { + correctType = BotSpellTypes::FastHeals; + } + else if (IsCompleteHealSpell(spell_id)) { + correctType = BotSpellTypes::CompleteHeal; + } + else if (IsHealOverTimeSpell(spell_id)) { + correctType = BotSpellTypes::HoTHeals; + } + else if (IsRegularSingleTargetHealSpell(spell_id)) { + correctType = BotSpellTypes::RegularHeal; + } + else if (IsRegularPetHealSpell(spell_id)) { + correctType = BotSpellTypes::RegularHeal; + } + } + } + else if (IsAnyBuffSpell(spell_id)) { + if (IsResistanceOnlySpell(spell_id)) { + correctType = BotSpellTypes::ResistBuffs; + } + else if (IsDamageShieldOnlySpell(spell_id)) { + correctType = BotSpellTypes::DamageShields; + } + else { + correctType = BotSpellTypes::Buff; + } + } + } + + + return correctType; +} + +uint16 GetPetSpellType(uint16 spellType) { + switch (spellType) { + case BotSpellTypes::Buff: + return BotSpellTypes::PetBuffs; + case BotSpellTypes::RegularHeal: + return BotSpellTypes::PetRegularHeals; + case BotSpellTypes::CompleteHeal: + return BotSpellTypes::PetCompleteHeals; + case BotSpellTypes::FastHeals: + return BotSpellTypes::PetFastHeals; + case BotSpellTypes::VeryFastHeals: + return BotSpellTypes::PetVeryFastHeals; + case BotSpellTypes::HoTHeals: + return BotSpellTypes::PetHoTHeals; + case BotSpellTypes::DamageShields: + return BotSpellTypes::PetDamageShields; + case BotSpellTypes::ResistBuffs: + return BotSpellTypes::PetResistBuffs; + default: + return spellType; + } + + return spellType; +} diff --git a/common/spdat.h b/common/spdat.h index e030143c7..ffe3525ad 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -752,6 +752,8 @@ bool SpellTypeRequiresTarget(uint16 spellType, uint16 cls = 0); bool SpellTypeRequiresAEChecks(uint16 spellType); bool IsCommandedSpellType(uint16 spellType); bool IsPullingSpellType(uint16 spellType); +uint16 GetCorrectSpellType(uint16 spellType, uint16 spell_id); +uint16 GetPetSpellType(uint16 spellType); // These should not be used to determine spell category.. // They are a graphical affects (effects?) index only @@ -1748,5 +1750,6 @@ bool IsResurrectSpell(uint16 spell_id); bool RequiresStackCheck(uint16 spellType); bool IsResistanceOnlySpell(uint16 spell_id); bool IsDamageShieldOnlySpell(uint16 spell_id); +bool IsHateSpell(uint16 spell_id); #endif diff --git a/zone/bot.cpp b/zone/bot.cpp index 747a30d9c..86ea16881 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -3560,7 +3560,7 @@ bool Bot::Spawn(Client* botCharacterOwner) { } if (RuleB(Bots, RunSpellTypeChecksOnSpawn)) { - OwnerMessage("Running SpellType checks. There may be some spells that are flagged as incorrect but actually are correct. Use this as a guideline."); + OwnerMessage("Running SpellType checks. There may be some spells that are mislabeled as incorrect. Use this as a loose guideline."); CheckBotSpells(); //This runs through a serious of checks and outputs any spells that are set to the wrong spell type in the database } diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index c6ac70397..835e99040 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -2753,10 +2753,11 @@ BotSpell Bot::GetBestBotSpellForNukeByBodyType(Bot* botCaster, uint8 bodyType, u } void Bot::CheckBotSpells() { - bool valid = false; - uint16 correctType; auto spellList = BotSpellsEntriesRepository::All(content_db); uint16 spell_id; + SPDat_Spell_Struct spell; + uint16 correctType; + uint16 parentType; for (const auto& s : spellList) { if (!IsValidSpell(s.spell_id)) { @@ -2764,64 +2765,65 @@ void Bot::CheckBotSpells() { continue; } - spell_id = s.spell_id; + spell = spells[s.spell_id]; + spell_id = spell.id; - if (spells[spell_id].classes[s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX] >= 255) { + if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] >= 255) { LogBotSpellTypeChecks("{} [#{}] is not usable by a {} [#{}].", GetSpellName(spell_id), spell_id, GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX), s.npc_spells_id); //deleteme } else { - if (spells[spell_id].classes[s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX] > s.minlevel) { + if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] > s.minlevel) { LogBotSpellTypeChecks("{} [#{}] is not usable until level {} for a {} [#{}] and the min level is currently set to {}." , GetSpellName(spell_id) , spell_id - , spells[spell_id].classes[s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX] + , spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] , GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX) , s.npc_spells_id , s.minlevel ); //deleteme LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `minlevel` = {} WHERE `spellid` = {} AND `npc_spells_id` = {}; -- {} [#{}] from minlevel {} to {} for {} [#{}]" - , spells[spell_id].classes[s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX] + , spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] , spell_id , s.npc_spells_id , GetSpellName(spell_id) , spell_id , s.minlevel - , spells[spell_id].classes[s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX] + , spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] , GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX) , s.npc_spells_id ); //deleteme } - if (spells[spell_id].classes[s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX] < s.minlevel) { + if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] < s.minlevel) { LogBotSpellTypeChecks("{} [#{}] could be used starting at level {} for a {} [#{}] instead of the current min level of {}." , GetSpellName(spell_id) , spell_id - , spells[spell_id].classes[s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX] + , spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] , GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX) , s.npc_spells_id , s.minlevel ); //deleteme LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `minlevel` = {} WHERE `spellid` = {} AND `npc_spells_id` = {}; -- {} [#{}] from minlevel {} to {} for {} [#{}]" - , spells[spell_id].classes[s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX] + , spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] , spell_id , s.npc_spells_id , GetSpellName(spell_id) , spell_id , s.minlevel - , spells[spell_id].classes[s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX] + , spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] , GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX) , s.npc_spells_id ); //deleteme } - if (spells[spell_id].classes[s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX] > s.maxlevel) { + if (spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] > s.maxlevel) { LogBotSpellTypeChecks("{} [#{}] is not usable until level {} for a {} [#{}] and the max level is currently set to {}." , GetSpellName(spell_id) , spell_id - , spells[spell_id].classes[s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX] + , spell.classes[s.npc_spells_id - (BOT_CLASS_BASE_ID_PREFIX + 1)] , GetClassIDName(s.npc_spells_id - BOT_CLASS_BASE_ID_PREFIX) , s.npc_spells_id , s.maxlevel @@ -2829,380 +2831,33 @@ void Bot::CheckBotSpells() { } } - correctType = UINT16_MAX; - valid = false; + correctType = GetCorrectSpellType(s.type, spell_id); + parentType = GetSpellListSpellType(correctType); - - switch (s.type) { - case BotSpellTypes::Nuke: - if (IsAnyNukeOrStunSpell(spell_id) && !IsEffectInSpell(spell_id, SE_Root) && !IsDebuffSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::RegularHeal: - if (IsAnyHealSpell(spell_id) && !IsEscapeSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::Root: - if (IsEffectInSpell(spell_id, SE_Root)) { - valid = true; - break; - } - break; - case BotSpellTypes::Buff: - if (IsAnyBuffSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::Pet: - if (IsSummonPetSpell(spell_id) || IsEffectInSpell(spell_id, SE_TemporaryPets)) { - valid = true; - break; - } - break; - case BotSpellTypes::Lifetap: - if (IsLifetapSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::Snare: - if (IsEffectInSpell(spell_id, SE_MovementSpeed) && IsDetrimentalSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::DOT: - if (IsStackableDOT(spell_id) || IsDamageOverTimeSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::Dispel: - if (IsDispelSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::InCombatBuff: - if ( - IsSelfConversionSpell(spell_id) || - IsAnyBuffSpell(spell_id) - ) { - valid = true; - break; - } - break; - case BotSpellTypes::HateLine: - if ( - (IsEffectInSpell(spell_id, SE_Hate) && spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_Hate)] > 0) || - (IsEffectInSpell(spell_id, SE_InstantHate) && spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_InstantHate)] > 0) - ) { - valid = true; - break; - } - break; - case BotSpellTypes::Mez: - if (IsMesmerizeSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::Charm: - if (IsCharmSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::Slow: - if (IsSlowSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::Debuff: - if (IsDebuffSpell(spell_id) && !IsEscapeSpell(spell_id) && !IsHateReduxSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::Cure: - if (IsCureSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::PreCombatBuff: - if ( - IsBuffSpell(spell_id) && - IsBeneficialSpell(spell_id) && - !IsBardSong(spell_id) && - !IsEscapeSpell(spell_id) && - (!IsSummonPetSpell(spell_id) && !IsEffectInSpell(spell_id, SE_TemporaryPets)) - ) { - valid = true; - break; - } - break; - case BotSpellTypes::InCombatBuffSong: - case BotSpellTypes::OutOfCombatBuffSong: - case BotSpellTypes::PreCombatBuffSong: - if ( - IsBuffSpell(spell_id) && - IsBeneficialSpell(spell_id) && - IsBardSong(spell_id) && - !IsEscapeSpell(spell_id) && - (!IsSummonPetSpell(spell_id) && !IsEffectInSpell(spell_id, SE_TemporaryPets)) - ) { - valid = true; - break; - } - break; - case BotSpellTypes::Fear: - if (IsFearSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::Escape: - if (IsEscapeSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::HateRedux: - if (IsHateReduxSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::Resurrect: - if (IsEffectInSpell(spell_id, SE_Revive)) { - valid = true; - break; - } - break; - case BotSpellTypes::Lull: - if (IsHarmonySpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::Teleport: - if (IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))) { - valid = true; - break; - } - break; - case BotSpellTypes::Succor: - if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_Succor)) { - valid = true; - break; - } - break; - case BotSpellTypes::BindAffinity: - if (IsEffectInSpell(spell_id, SE_BindAffinity)) { - valid = true; - break; - } - break; - case BotSpellTypes::Identify: - if (IsEffectInSpell(spell_id, SE_Identify)) { - valid = true; - break; - } - break; - case BotSpellTypes::Levitate: - if (IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_Levitate))) { - valid = true; - break; - } - break; - case BotSpellTypes::Rune: - if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_AbsorbMagicAtt) || IsEffectInSpell(spell_id, SE_Rune)) { - valid = true; - break; - } - break; - case BotSpellTypes::WaterBreathing: - if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_WaterBreathing)) { - valid = true; - break; - } - break; - case BotSpellTypes::Size: - if (IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_ModelSize) || IsEffectInSpell(spell_id, SE_ChangeHeight))) { - valid = true; - break; - } - break; - case BotSpellTypes::Invisibility: - if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_SeeInvis) || IsInvisibleSpell(spell_id)) { - valid = true; - break; - } - break; - case BotSpellTypes::MovementSpeed: - if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_MovementSpeed)) { - valid = true; - break; - } - break; - case BotSpellTypes::SendHome: - if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_GateToHomeCity)) { - valid = true; - break; - } - break; - case BotSpellTypes::SummonCorpse: - if (IsEffectInSpell(spell_id, SE_SummonCorpse)) { - valid = true; - break; - } - break; - default: - break; - - } - - if (IsAnyNukeOrStunSpell(spell_id) && !IsEffectInSpell(spell_id, SE_Root) && !IsDebuffSpell(spell_id)) { - correctType = BotSpellTypes::Nuke; - } - else if (IsAnyHealSpell(spell_id) && !IsEscapeSpell(spell_id)) { - correctType = BotSpellTypes::RegularHeal; - } - else if (IsEffectInSpell(spell_id, SE_Root)) { - correctType = BotSpellTypes::Root; - } - else if (IsAnyBuffSpell(spell_id)) { - correctType = BotSpellTypes::Buff; - } - else if (IsSummonPetSpell(spell_id) || IsEffectInSpell(spell_id, SE_TemporaryPets)) { - correctType = BotSpellTypes::Pet; - } - else if (IsLifetapSpell(spell_id)) { - correctType = BotSpellTypes::Lifetap; - } - else if (IsEffectInSpell(spell_id, SE_MovementSpeed) && IsDetrimentalSpell(spell_id)) { - correctType = BotSpellTypes::Snare; - } - else if (IsStackableDOT(spell_id) || IsDamageOverTimeSpell(spell_id)) { - correctType = BotSpellTypes::DOT; - } - else if (IsDispelSpell(spell_id)) { - correctType = BotSpellTypes::Dispel; - } - else if ( - IsSelfConversionSpell(spell_id) || - IsAnyBuffSpell(spell_id) - ) { - correctType = BotSpellTypes::InCombatBuff; - } - else if ( - (IsEffectInSpell(spell_id, SE_Hate) && spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_Hate)] > 0) || - (IsEffectInSpell(spell_id, SE_InstantHate) && spells[spell_id].base_value[GetSpellEffectIndex(spell_id, SE_InstantHate)] > 0) - ) { - correctType = BotSpellTypes::HateLine; - } - else if (IsMesmerizeSpell(spell_id)) { - correctType = BotSpellTypes::Mez; - } - else if (IsCharmSpell(spell_id)) { - correctType = BotSpellTypes::Charm; - } - else if (IsSlowSpell(spell_id)) { - correctType = BotSpellTypes::Slow; - } - else if (IsDebuffSpell(spell_id) && !IsEscapeSpell(spell_id) && !IsHateReduxSpell(spell_id)) { - correctType = BotSpellTypes::Debuff; - } - else if (IsCureSpell(spell_id)) { - correctType = BotSpellTypes::Cure; - } - else if ( - IsBuffSpell(spell_id) && - IsBeneficialSpell(spell_id) && - IsBardSong(spell_id) && - !IsEscapeSpell(spell_id) && - (!IsSummonPetSpell(spell_id) && !IsEffectInSpell(spell_id, SE_TemporaryPets)) - ) { - if ( - s.type == BotSpellTypes::InCombatBuffSong || - s.type == BotSpellTypes::OutOfCombatBuffSong || - s.type == BotSpellTypes::PreCombatBuffSong - ) { - correctType = s.type; - } - else { - correctType = BotSpellTypes::OutOfCombatBuffSong; + if (RuleB(Bots, UseParentSpellTypeForChecks)) { + if (s.type == parentType || s.type == correctType) { + continue; } } - else if ( - IsBuffSpell(spell_id) && - IsBeneficialSpell(spell_id) && - !IsBardSong(spell_id) && - !IsEscapeSpell(spell_id) && - (!IsSummonPetSpell(spell_id) && !IsEffectInSpell(spell_id, SE_TemporaryPets)) - ) { - correctType = BotSpellTypes::PreCombatBuff; - } - else if (IsFearSpell(spell_id)) { - correctType = BotSpellTypes::Fear; - } - else if (IsEscapeSpell(spell_id)) { - correctType = BotSpellTypes::Escape; - } - else if (IsHateReduxSpell(spell_id)) { - correctType = BotSpellTypes::HateRedux; - } - else if (IsEffectInSpell(spell_id, SE_Revive)) { - correctType = BotSpellTypes::Resurrect; - } - else if (IsHarmonySpell(spell_id)) { - correctType = BotSpellTypes::Lull; - } - else if (IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))) { - correctType = BotSpellTypes::Teleport; - } - else if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_Succor)) { - correctType = BotSpellTypes::Succor; - } - else if (IsEffectInSpell(spell_id, SE_BindAffinity)) { - correctType = BotSpellTypes::BindAffinity; - } - else if (IsEffectInSpell(spell_id, SE_Identify)) { - correctType = BotSpellTypes::Identify; - } - else if (IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_Levitate))) { - correctType = BotSpellTypes::Levitate; - } - else if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_AbsorbMagicAtt) || IsEffectInSpell(spell_id, SE_Rune)) { - correctType = BotSpellTypes::Rune; - } - else if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_WaterBreathing)) { - correctType = BotSpellTypes::WaterBreathing; - } - else if (IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_ModelSize) || IsEffectInSpell(spell_id, SE_ChangeHeight))) { - correctType = BotSpellTypes::Size; - } - else if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_SeeInvis) || IsInvisibleSpell(spell_id)) { - correctType = BotSpellTypes::Invisibility; - } - else if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_MovementSpeed)) { - correctType = BotSpellTypes::MovementSpeed; - } - else if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_GateToHomeCity)) { - correctType = BotSpellTypes::SendHome; - } - else if (IsEffectInSpell(spell_id, SE_SummonCorpse)) { - correctType = BotSpellTypes::SummonCorpse; + else { + if (IsPetBotSpellType(s.type)) { + correctType = GetPetSpellType(correctType); + } } - if (!valid || (correctType == UINT16_MAX) || (s.type != correctType)) { + if (correctType == s.type) { + continue; + } + + if (correctType == UINT16_MAX) { + LogBotSpellTypeChecks("{} [#{}] is incorrect. It is currently set as {} [#{}] but the correct type is unknown." + , GetSpellName(spell_id) + , spell_id + , GetSpellTypeNameByID(s.type) + , s.type + ); //deleteme + } + else { LogBotSpellTypeChecks("{} [#{}] is incorrect. It is currently set as {} [#{}] and should be {} [#{}]" , GetSpellName(spell_id) , spell_id @@ -3211,7 +2866,7 @@ void Bot::CheckBotSpells() { , GetSpellTypeNameByID(correctType) , correctType ); //deleteme - LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `type` = {} WHERE `spellid` = {}; -- {} [#{}] from {} [#{}] to {} [#{}]" + LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `type` = {} WHERE `spell_id` = {}; -- {} [#{}] from {} [#{}] to {} [#{}]" , correctType , spell_id , GetSpellName(spell_id)