mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
[Bots] Fix IsValidSpellTypeBySpellID to account for all types (#4764)
* [Bots] Fix IsValidSpellTypeBySpellID to account for all types * Formatting
This commit is contained in:
parent
ef945e6e99
commit
1af29bd7b1
@ -835,7 +835,7 @@ RULE_INT(Bots, MinGroupCureTargets, 3, "Minimum number of targets in valid range
|
||||
RULE_INT(Bots, MinTargetsForAESpell, 3, "Minimum number of targets in valid range that are required for an AE spell to cast. Default 3.")
|
||||
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, RunSpellTypeChecksOnBoot, false, "This will run a series of checks to find potential errors in your bot_spells_entries table on boot and output 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")
|
||||
|
||||
@ -1456,41 +1456,42 @@ bool IsCompleteHealSpell(uint16 spell_id)
|
||||
}
|
||||
|
||||
bool IsFastHealSpell(uint16 spell_id) {
|
||||
spell_id = (
|
||||
IsEffectInSpell(spell_id, SE_CurrentHP) ?
|
||||
spell_id :
|
||||
GetSpellTriggerSpellID(spell_id, SE_CurrentHP)
|
||||
);
|
||||
spell_id = (
|
||||
IsEffectInSpell(spell_id, SE_CurrentHP) ?
|
||||
spell_id :
|
||||
GetSpellTriggerSpellID(spell_id, SE_CurrentHP)
|
||||
);
|
||||
|
||||
if (!spell_id) {
|
||||
spell_id = (
|
||||
IsEffectInSpell(spell_id, SE_CurrentHPOnce) ?
|
||||
spell_id :
|
||||
GetSpellTriggerSpellID(spell_id, SE_CurrentHPOnce)
|
||||
);
|
||||
}
|
||||
if (!spell_id) {
|
||||
spell_id = (
|
||||
IsEffectInSpell(spell_id, SE_CurrentHPOnce) ?
|
||||
spell_id :
|
||||
GetSpellTriggerSpellID(spell_id, SE_CurrentHPOnce)
|
||||
);
|
||||
}
|
||||
|
||||
if (spell_id && IsValidSpell(spell_id)) {
|
||||
if (
|
||||
spells[spell_id].cast_time <= MAX_FAST_HEAL_CASTING_TIME &&
|
||||
spells[spell_id].good_effect &&
|
||||
!IsGroupSpell(spell_id)
|
||||
) {
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
if (
|
||||
spells[spell_id].base_value[i] > 0 &&
|
||||
(
|
||||
spells[spell_id].effect_id[i] == SE_CurrentHP ||
|
||||
spells[spell_id].effect_id[i] == SE_CurrentHPOnce
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IsValidSpell(spell_id)) {
|
||||
if (
|
||||
spell_id != SPELL_MINOR_HEALING &&
|
||||
(spells[spell_id].cast_time > MAX_VERY_FAST_HEAL_CASTING_TIME && spells[spell_id].cast_time <= MAX_FAST_HEAL_CASTING_TIME) &&
|
||||
spells[spell_id].good_effect &&
|
||||
!IsGroupSpell(spell_id)
|
||||
) {
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
if (
|
||||
spells[spell_id].base_value[i] > 0 &&
|
||||
(
|
||||
spells[spell_id].effect_id[i] == SE_CurrentHP ||
|
||||
spells[spell_id].effect_id[i] == SE_CurrentHPOnce
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsVeryFastHealSpell(uint16 spell_id)
|
||||
@ -1509,8 +1510,9 @@ bool IsVeryFastHealSpell(uint16 spell_id)
|
||||
);
|
||||
}
|
||||
|
||||
if (spell_id) {
|
||||
if (IsValidSpell(spell_id)) {
|
||||
if (
|
||||
spell_id != SPELL_MINOR_HEALING &&
|
||||
spells[spell_id].cast_time <= MAX_VERY_FAST_HEAL_CASTING_TIME &&
|
||||
spells[spell_id].good_effect &&
|
||||
!IsGroupSpell(spell_id)
|
||||
@ -1548,8 +1550,13 @@ bool IsRegularSingleTargetHealSpell(uint16 spell_id)
|
||||
);
|
||||
}
|
||||
|
||||
if (spell_id) {
|
||||
if (IsValidSpell(spell_id)) {
|
||||
if (spell_id == SPELL_MINOR_HEALING) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
spells[spell_id].cast_time > MAX_FAST_HEAL_CASTING_TIME &&
|
||||
spells[spell_id].target_type == ST_Target &&
|
||||
!IsCompleteHealSpell(spell_id) &&
|
||||
!IsHealOverTimeSpell(spell_id) &&
|
||||
@ -1589,9 +1596,14 @@ bool IsRegularPetHealSpell(uint16 spell_id)
|
||||
);
|
||||
}
|
||||
|
||||
if (spell_id && IsValidSpell(spell_id)) {
|
||||
if (IsValidSpell(spell_id)) {
|
||||
if (spell_id == SPELL_MINOR_HEALING) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
(spells[spell_id].target_type == ST_Pet || spells[spell_id].target_type == ST_Undead) &&
|
||||
spells[spell_id].cast_time > MAX_FAST_HEAL_CASTING_TIME &&
|
||||
(spells[spell_id].target_type == ST_Pet || spells[spell_id].target_type == ST_SummonedPet) &&
|
||||
!IsCompleteHealSpell(spell_id) &&
|
||||
!IsHealOverTimeSpell(spell_id) &&
|
||||
!IsGroupSpell(spell_id)
|
||||
@ -1630,7 +1642,7 @@ bool IsRegularGroupHealSpell(uint16 spell_id)
|
||||
);
|
||||
}
|
||||
|
||||
if (spell_id) {
|
||||
if (IsValidSpell(spell_id)) {
|
||||
if (
|
||||
IsGroupSpell(spell_id) &&
|
||||
!IsCompleteHealSpell(spell_id) &&
|
||||
|
||||
@ -215,6 +215,7 @@
|
||||
#define SPELL_AMPLIFICATION 2603
|
||||
#define SPELL_DIVINE_REZ 2738
|
||||
#define SPELL_NATURES_RECOVERY 2520
|
||||
#define SPELL_MINOR_HEALING 200
|
||||
#define SPELL_ADRENALINE_SWELL 14445
|
||||
#define SPELL_ADRENALINE_SWELL_RK2 14446
|
||||
#define SPELL_ADRENALINE_SWELL_RK3 14447
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include "spdat.h"
|
||||
#include "../zone/bot.h"
|
||||
|
||||
bool IsBotSpellTypeDetrimental(uint16 spell_type) {
|
||||
switch (spell_type) {
|
||||
@ -417,264 +418,23 @@ uint16 GetCorrectBotSpellType(uint16 spell_type, uint16 spell_id) {
|
||||
return UINT16_MAX;
|
||||
}
|
||||
|
||||
uint16 correct_type = UINT16_MAX;
|
||||
SPDat_Spell_Struct spell = spells[spell_id];
|
||||
std::string teleport_zone = spell.teleport_zone;
|
||||
uint16 correct_type = spell_type;
|
||||
|
||||
if (IsCharmSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Charm;
|
||||
}
|
||||
else if (IsFearSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Fear;
|
||||
}
|
||||
else if (IsEffectInSpell(spell_id, SE_Revive)) {
|
||||
correct_type = BotSpellTypes::Resurrect;
|
||||
}
|
||||
else if (IsHarmonySpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Lull;
|
||||
}
|
||||
else if (
|
||||
teleport_zone.compare("") &&
|
||||
!IsEffectInSpell(spell_id, SE_GateToHomeCity) &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))
|
||||
) {
|
||||
correct_type = BotSpellTypes::Teleport;
|
||||
}
|
||||
else if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_Succor)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Succor;
|
||||
}
|
||||
else if (IsEffectInSpell(spell_id, SE_BindAffinity)) {
|
||||
correct_type = BotSpellTypes::BindAffinity;
|
||||
}
|
||||
else if (IsEffectInSpell(spell_id, SE_Identify)) {
|
||||
correct_type = BotSpellTypes::Identify;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::Levitate &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_Levitate)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Levitate;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::Rune &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_AbsorbMagicAtt) || IsEffectInSpell(spell_id, SE_Rune))
|
||||
) {
|
||||
correct_type = BotSpellTypes::Rune;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::WaterBreathing &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_WaterBreathing)
|
||||
) {
|
||||
correct_type = BotSpellTypes::WaterBreathing;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::Size &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_ModelSize) || IsEffectInSpell(spell_id, SE_ChangeHeight))
|
||||
) {
|
||||
correct_type = BotSpellTypes::Size;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::Invisibility &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_SeeInvis) || IsInvisibleSpell(spell_id))
|
||||
) {
|
||||
correct_type = BotSpellTypes::Invisibility;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::MovementSpeed &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_MovementSpeed)
|
||||
) {
|
||||
correct_type = BotSpellTypes::MovementSpeed;
|
||||
}
|
||||
else if (
|
||||
!teleport_zone.compare("") &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_Translocate) || IsEffectInSpell(spell_id, SE_GateToHomeCity))
|
||||
) {
|
||||
correct_type = BotSpellTypes::SendHome;
|
||||
}
|
||||
else if (IsEffectInSpell(spell_id, SE_SummonCorpse)) {
|
||||
correct_type = BotSpellTypes::SummonCorpse;
|
||||
}
|
||||
if (!Bot::IsValidSpellTypeBySpellID(spell_type, spell_id)) {
|
||||
correct_type = UINT16_MAX;
|
||||
|
||||
if (correct_type == UINT16_MAX) {
|
||||
if (
|
||||
IsSummonPetSpell(spell_id) ||
|
||||
IsEffectInSpell(spell_id, SE_TemporaryPets)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Pet;
|
||||
}
|
||||
else if (IsMesmerizeSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Mez;
|
||||
}
|
||||
else if (IsEscapeSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Escape;
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_Root)
|
||||
) {
|
||||
if (IsAnyAESpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::AERoot;
|
||||
}
|
||||
else {
|
||||
correct_type = BotSpellTypes::Root;
|
||||
}
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
IsLifetapSpell(spell_id)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Lifetap;
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_MovementSpeed)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Snare;
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
(IsStackableDOT(spell_id) || IsDamageOverTimeSpell(spell_id))
|
||||
) {
|
||||
correct_type = BotSpellTypes::DOT;
|
||||
}
|
||||
else if (IsDispelSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Dispel;
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
IsSlowSpell(spell_id)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Slow;
|
||||
}
|
||||
else if (
|
||||
IsDebuffSpell(spell_id) &&
|
||||
!IsHateReduxSpell(spell_id) &&
|
||||
!IsHateSpell(spell_id)
|
||||
) {
|
||||
correct_type = BotSpellTypes::Debuff;
|
||||
}
|
||||
else if (IsHateReduxSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::HateRedux;
|
||||
}
|
||||
else if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
IsHateSpell(spell_id)
|
||||
) {
|
||||
correct_type = BotSpellTypes::HateLine;
|
||||
}
|
||||
else if (
|
||||
IsBuffSpell(spell_id) &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsBardSong(spell_id)
|
||||
) {
|
||||
if (
|
||||
spell_type == BotSpellTypes::InCombatBuffSong ||
|
||||
spell_type == BotSpellTypes::OutOfCombatBuffSong ||
|
||||
spell_type == BotSpellTypes::PreCombatBuffSong
|
||||
) {
|
||||
correct_type = spell_type;
|
||||
}
|
||||
else {
|
||||
correct_type = BotSpellTypes::OutOfCombatBuffSong;
|
||||
}
|
||||
}
|
||||
else if (
|
||||
!IsBardSong(spell_id) &&
|
||||
(
|
||||
(IsSelfConversionSpell(spell_id) && spell.buff_duration < 1) ||
|
||||
(spell_type == BotSpellTypes::InCombatBuff && IsAnyBuffSpell(spell_id))
|
||||
)
|
||||
) {
|
||||
correct_type = BotSpellTypes::InCombatBuff;
|
||||
}
|
||||
else if (
|
||||
spell_type == BotSpellTypes::PreCombatBuff &&
|
||||
IsAnyBuffSpell(spell_id) &&
|
||||
!IsBardSong(spell_id)
|
||||
) {
|
||||
correct_type = BotSpellTypes::PreCombatBuff;
|
||||
}
|
||||
else if (
|
||||
(IsCureSpell(spell_id) && spell_type == BotSpellTypes::Cure) ||
|
||||
(IsCureSpell(spell_id) && !IsAnyHealSpell(spell_id))
|
||||
) {
|
||||
correct_type = BotSpellTypes::Cure;
|
||||
}
|
||||
else if (IsAnyNukeOrStunSpell(spell_id)) {
|
||||
if (IsAnyAESpell(spell_id)) {
|
||||
if (IsAERainSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::AERains;
|
||||
}
|
||||
else if (IsPBAENukeSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::PBAENuke;
|
||||
}
|
||||
else if (IsStunSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::AEStun;
|
||||
}
|
||||
else {
|
||||
correct_type = BotSpellTypes::AENukes;
|
||||
}
|
||||
}
|
||||
else if (IsStunSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Stun;
|
||||
}
|
||||
else {
|
||||
correct_type = BotSpellTypes::Nuke;
|
||||
}
|
||||
}
|
||||
else if (IsAnyHealSpell(spell_id)) {
|
||||
if (IsGroupSpell(spell_id)) {
|
||||
if (IsGroupCompleteHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::GroupCompleteHeals;
|
||||
}
|
||||
else if (IsGroupHealOverTimeSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::GroupHoTHeals;
|
||||
}
|
||||
else if (IsRegularGroupHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::GroupHeals;
|
||||
}
|
||||
auto start = std::min({ BotSpellTypes::START, BotSpellTypes::COMMANDED_START, BotSpellTypes::DISCIPLINE_START });
|
||||
auto end = std::max({ BotSpellTypes::END, BotSpellTypes::COMMANDED_END, BotSpellTypes::DISCIPLINE_END });
|
||||
|
||||
return correct_type;
|
||||
for (int i = end; i >= start; --i) {
|
||||
if (!Bot::IsValidBotSpellType(i) || i == BotSpellTypes::InCombatBuff) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsVeryFastHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::VeryFastHeals;
|
||||
}
|
||||
else if (IsFastHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::FastHeals;
|
||||
}
|
||||
else if (IsCompleteHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::CompleteHeal;
|
||||
}
|
||||
else if (IsHealOverTimeSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::HoTHeals;
|
||||
}
|
||||
else if (IsRegularSingleTargetHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::RegularHeal;
|
||||
}
|
||||
else if (IsRegularPetHealSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::RegularHeal;
|
||||
}
|
||||
}
|
||||
else if (IsAnyBuffSpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::Buff;
|
||||
if (Bot::IsValidSpellTypeBySpellID(i, spell_id)) {
|
||||
correct_type = i;
|
||||
|
||||
if (IsResistanceOnlySpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::ResistBuffs;
|
||||
}
|
||||
else if (IsDamageShieldOnlySpell(spell_id)) {
|
||||
correct_type = BotSpellTypes::DamageShields;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
360
zone/bot.cpp
360
zone/bot.cpp
@ -3710,11 +3710,6 @@ bool Bot::Spawn(Client* botCharacterOwner) {
|
||||
}
|
||||
}
|
||||
|
||||
if (RuleB(Bots, RunSpellTypeChecksOnSpawn)) {
|
||||
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 series of checks and outputs any spells that are set to the wrong spell type in the database
|
||||
}
|
||||
|
||||
if (IsBotRanged()) {
|
||||
ChangeBotRangedWeapons(true);
|
||||
}
|
||||
@ -9798,6 +9793,7 @@ bool Bot::CanCastSpellType(uint16 spell_type, uint16 spell_id, Mob* tar) {
|
||||
}
|
||||
|
||||
uint8 bot_class = GetClass();
|
||||
auto spell = spells[spell_id];
|
||||
|
||||
switch (spell_type) {
|
||||
case BotSpellTypes::Buff:
|
||||
@ -9821,7 +9817,7 @@ bool Bot::CanCastSpellType(uint16 spell_type, uint16 spell_id, Mob* tar) {
|
||||
case BotSpellTypes::SendHome:
|
||||
if (
|
||||
tar == this &&
|
||||
spells[spell_id].target_type == ST_TargetsTarget
|
||||
spell.target_type == ST_TargetsTarget
|
||||
) {
|
||||
LogBotSpellChecksDetail("{} says, 'Cancelling cast of {} on {} due to target_type checks. Using {}'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName(), GetSpellTargetType(spell_id));
|
||||
return false;
|
||||
@ -9851,7 +9847,7 @@ bool Bot::CanCastSpellType(uint16 spell_type, uint16 spell_id, Mob* tar) {
|
||||
}
|
||||
|
||||
if (
|
||||
spells[spell_id].target_type == ST_Pet &&
|
||||
(spell.target_type == ST_Pet || spell.target_type == ST_SummonedPet) &&
|
||||
(
|
||||
!tar->IsPet() ||
|
||||
(
|
||||
@ -11574,18 +11570,265 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsBotSpellTypeDetrimental(spell_type) && !IsDetrimentalSpell(spell_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsBotSpellTypeBeneficial(spell_type) && !IsBeneficialSpell(spell_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto spell = spells[spell_id];
|
||||
std::string teleport_zone = spell.teleport_zone;
|
||||
|
||||
switch (spell_type) {
|
||||
case BotSpellTypes::Buff:
|
||||
case BotSpellTypes::PetBuffs:
|
||||
if (
|
||||
IsResistanceOnlySpell(spell_id) ||
|
||||
IsDamageShieldOnlySpell(spell_id) ||
|
||||
IsDamageShieldAndResistSpell(spell_id)
|
||||
) {
|
||||
return false;
|
||||
case BotSpellTypes::Nuke:
|
||||
if (IsAnyNukeOrStunSpell(spell_id) && !IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
case BotSpellTypes::RegularHeal:
|
||||
case BotSpellTypes::PetRegularHeals:
|
||||
if (
|
||||
IsAnyHealSpell(spell_id) &&
|
||||
!IsVeryFastHealSpell(spell_id) &&
|
||||
!IsFastHealSpell(spell_id) &&
|
||||
!IsCompleteHealSpell(spell_id) &&
|
||||
!IsHealOverTimeSpell(spell_id) &&
|
||||
!IsBuffSpell(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Root:
|
||||
case BotSpellTypes::AERoot:
|
||||
if (IsDetrimentalSpell(spell_id) && IsEffectInSpell(spell_id, SE_Root)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Buff:
|
||||
case BotSpellTypes::PreCombatBuff:
|
||||
case BotSpellTypes::PetBuffs:
|
||||
if (
|
||||
IsBuffSpell(spell_id) &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
!IsBardSong(spell_id) &&
|
||||
!IsResistanceOnlySpell(spell_id) &&
|
||||
!IsDamageShieldOnlySpell(spell_id) &&
|
||||
!IsDamageShieldAndResistSpell(spell_id)
|
||||
) {
|
||||
if (
|
||||
spell_type != BotSpellTypes::PetBuffs &&
|
||||
(spell.target_type == ST_Pet || spell.target_type == ST_SummonedPet)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Escape:
|
||||
if (IsEscapeSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Pet:
|
||||
if (IsSummonPetSpell(spell_id) || IsEffectInSpell(spell_id, SE_TemporaryPets)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Lifetap:
|
||||
case BotSpellTypes::AELifetap:
|
||||
if (IsDetrimentalSpell(spell_id) && IsLifetapSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Snare:
|
||||
case BotSpellTypes::AESnare:
|
||||
if (IsDetrimentalSpell(spell_id) && IsEffectInSpell(spell_id, SE_MovementSpeed)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::DOT:
|
||||
case BotSpellTypes::AEDoT:
|
||||
if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
(IsStackableDOT(spell_id) || IsDamageOverTimeSpell(spell_id))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Dispel:
|
||||
case BotSpellTypes::AEDispel:
|
||||
if (IsDispelSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::InCombatBuff:
|
||||
if (
|
||||
!IsBardSong(spell_id) &&
|
||||
(
|
||||
(IsSelfConversionSpell(spell_id) && spell.buff_duration < 1) ||
|
||||
(spell_type == BotSpellTypes::InCombatBuff && IsAnyBuffSpell(spell_id))
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Mez:
|
||||
case BotSpellTypes::AEMez:
|
||||
if (IsMesmerizeSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Charm:
|
||||
if (IsCharmSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Slow:
|
||||
case BotSpellTypes::AESlow:
|
||||
if (IsDetrimentalSpell(spell_id) && IsSlowSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Debuff:
|
||||
case BotSpellTypes::AEDebuff:
|
||||
if (
|
||||
IsDebuffSpell(spell_id) &&
|
||||
!IsHateReduxSpell(spell_id) &&
|
||||
!IsHateSpell(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Cure:
|
||||
case BotSpellTypes::GroupCures:
|
||||
case BotSpellTypes::PetCures:
|
||||
if (IsCureSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Resurrect:
|
||||
if (IsEffectInSpell(spell_id, SE_Revive)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::HateRedux:
|
||||
if (IsHateReduxSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::InCombatBuffSong:
|
||||
case BotSpellTypes::OutOfCombatBuffSong:
|
||||
case BotSpellTypes::PreCombatBuffSong:
|
||||
if (
|
||||
IsBuffSpell(spell_id) &&
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsBardSong(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Fear:
|
||||
case BotSpellTypes::AEFear:
|
||||
if (IsFearSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Stun:
|
||||
case BotSpellTypes::AEStun:
|
||||
if (IsDetrimentalSpell(spell_id) && IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::HateLine:
|
||||
case BotSpellTypes::AEHateLine:
|
||||
if (IsDetrimentalSpell(spell_id) && IsHateSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::CompleteHeal:
|
||||
case BotSpellTypes::GroupCompleteHeals:
|
||||
case BotSpellTypes::PetCompleteHeals:
|
||||
if (IsCompleteHealSpell(spell_id) || IsGroupCompleteHealSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::FastHeals:
|
||||
case BotSpellTypes::PetFastHeals:
|
||||
if (IsFastHealSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::VeryFastHeals:
|
||||
case BotSpellTypes::PetVeryFastHeals:
|
||||
if (IsVeryFastHealSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::GroupHeals:
|
||||
if (IsRegularGroupHealSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::HoTHeals:
|
||||
case BotSpellTypes::GroupHoTHeals:
|
||||
case BotSpellTypes::PetHoTHeals:
|
||||
if (IsHealOverTimeSpell(spell_id) || IsGroupHealOverTimeSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::AENukes:
|
||||
if (
|
||||
IsDetrimentalSpell(spell_id) &&
|
||||
!IsAERainSpell(spell_id) &&
|
||||
!IsPBAENukeSpell(spell_id) &&
|
||||
!IsStunSpell(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::AERains:
|
||||
if (IsAERainNukeSpell(spell_id) && !IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::PBAENuke:
|
||||
if (IsPBAENukeSpell(spell_id) && !IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::ResistBuffs:
|
||||
case BotSpellTypes::PetResistBuffs:
|
||||
if (IsResistanceBuffSpell(spell_id)) {
|
||||
@ -11595,44 +11838,7 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
return false;
|
||||
case BotSpellTypes::DamageShields:
|
||||
case BotSpellTypes::PetDamageShields:
|
||||
if (IsEffectInSpell(spell_id, SE_DamageShield)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::PBAENuke:
|
||||
if (
|
||||
IsPBAENukeSpell(spell_id) &&
|
||||
!IsStunSpell(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::AERains:
|
||||
if (
|
||||
IsAERainNukeSpell(spell_id) &&
|
||||
!IsStunSpell(spell_id)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case BotSpellTypes::AEStun:
|
||||
case BotSpellTypes::Stun:
|
||||
if (IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::AENukes:
|
||||
case BotSpellTypes::Nuke:
|
||||
if (!IsStunSpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Lull:
|
||||
if (IsHarmonySpell(spell_id)) {
|
||||
if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_DamageShield)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -11640,13 +11846,18 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
case BotSpellTypes::Teleport:
|
||||
if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(
|
||||
IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate)
|
||||
)
|
||||
(IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Lull:
|
||||
case BotSpellTypes::AELull:
|
||||
if (IsHarmonySpell(spell_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Succor:
|
||||
if (
|
||||
@ -11670,25 +11881,21 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Levitate:
|
||||
if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_Levitate)
|
||||
) {
|
||||
if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_Levitate)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Rune:
|
||||
if (
|
||||
IsEffectInSpell(spell_id, SE_AbsorbMagicAtt) ||
|
||||
IsEffectInSpell(spell_id, SE_Rune)
|
||||
if (IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_AbsorbMagicAtt) || IsEffectInSpell(spell_id, SE_Rune))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::WaterBreathing:
|
||||
if (IsEffectInSpell(spell_id, SE_WaterBreathing)) {
|
||||
if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_WaterBreathing)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -11696,29 +11903,22 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
case BotSpellTypes::Size:
|
||||
if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
(
|
||||
IsEffectInSpell(spell_id, SE_ModelSize) ||
|
||||
IsEffectInSpell(spell_id, SE_ChangeHeight)
|
||||
)
|
||||
(IsEffectInSpell(spell_id, SE_ModelSize) || IsEffectInSpell(spell_id, SE_ChangeHeight))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::Invisibility:
|
||||
if (
|
||||
IsEffectInSpell(spell_id, SE_SeeInvis) ||
|
||||
IsInvisibleSpell(spell_id)
|
||||
if (IsBeneficialSpell(spell_id) &&
|
||||
(IsEffectInSpell(spell_id, SE_SeeInvis) ||IsInvisibleSpell(spell_id))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
case BotSpellTypes::MovementSpeed:
|
||||
if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_MovementSpeed)
|
||||
) {
|
||||
if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_MovementSpeed)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -11726,7 +11926,13 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id) {
|
||||
case BotSpellTypes::SendHome:
|
||||
if (
|
||||
IsBeneficialSpell(spell_id) &&
|
||||
IsEffectInSpell(spell_id, SE_GateToHomeCity)
|
||||
(
|
||||
IsEffectInSpell(spell_id, SE_GateToHomeCity) ||
|
||||
(
|
||||
teleport_zone.compare("") &&
|
||||
(IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))
|
||||
)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -683,7 +683,6 @@ public:
|
||||
void SetSitManaPct(uint8 value) { _SitManaPct = value; }
|
||||
|
||||
// Spell lists
|
||||
void CheckBotSpells();
|
||||
std::list<BotSpellTypeOrder> GetSpellTypesPrioritized(uint8 priority_type);
|
||||
static uint16 GetParentSpellType(uint16 spell_type);
|
||||
static bool IsValidSpellTypeBySpellID(uint16 spell_type, uint16 spell_id);
|
||||
|
||||
@ -220,6 +220,11 @@ int bot_command_init(void)
|
||||
std::vector<std::pair<std::string, uint8>> injected_bot_command_settings;
|
||||
std::vector<std::string> orphaned_bot_command_settings;
|
||||
|
||||
if (RuleB(Bots, RunSpellTypeChecksOnBoot)) {
|
||||
LogBotSpellTypeChecks("Running SpellType checks. There may be some spells that are mislabeled as incorrect. Use this as a loose guideline.");
|
||||
database.botdb.CheckBotSpells();
|
||||
}
|
||||
|
||||
database.botdb.MapCommandedSpellTypeMinLevels();
|
||||
|
||||
for (auto bcs_iter : bot_command_settings) {
|
||||
@ -813,7 +818,7 @@ void helper_send_usage_required_bots(Client *bot_owner, uint16 spell_type)
|
||||
auto spell_type_itr = spell_map.find(spell_type);
|
||||
auto class_itr = spell_type_itr->second.find(i);
|
||||
const auto& spell_info = class_itr->second;
|
||||
|
||||
|
||||
if (spell_info.min_level < UINT8_MAX) {
|
||||
found = true;
|
||||
|
||||
|
||||
@ -2523,6 +2523,142 @@ bool BotDatabase::DeleteBotBlockedBuffs(const uint32 bot_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
void BotDatabase::CheckBotSpells() {
|
||||
auto spell_list = BotSpellsEntriesRepository::All(content_db);
|
||||
uint16 spell_id;
|
||||
SPDat_Spell_Struct spell;
|
||||
|
||||
for (const auto& s : spell_list) {
|
||||
if (!IsValidSpell(s.spell_id)) {
|
||||
LogBotSpellTypeChecks("{} is an invalid spell", s.spell_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
spell = spells[s.spell_id];
|
||||
spell_id = spell.id;
|
||||
|
||||
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);
|
||||
}
|
||||
else {
|
||||
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,
|
||||
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
|
||||
);
|
||||
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `minlevel` = {} WHERE `spellid` = {} AND `npc_spells_id` = {}; -- {} [#{}] from minlevel {} to {} for {} [#{}]",
|
||||
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,
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
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
|
||||
);
|
||||
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `minlevel` = {} WHERE `spellid` = {} AND `npc_spells_id` = {}; -- {} [#{}] from minlevel {} to {} for {} [#{}]",
|
||||
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,
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
uint16 correct_type = GetCorrectBotSpellType(s.type, spell_id);
|
||||
|
||||
if (RuleB(Bots, UseParentSpellTypeForChecks)) {
|
||||
uint16 parent_type = Bot::GetParentSpellType(correct_type);
|
||||
|
||||
if (s.type == parent_type || s.type == correct_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (correct_type != parent_type) {
|
||||
correct_type = parent_type;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (IsPetBotSpellType(s.type)) {
|
||||
correct_type = GetPetBotSpellType(correct_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsPetBotSpellType(correct_type) && (spell.target_type != ST_Pet && spell.target_type != ST_SummonedPet)) {
|
||||
correct_type = Bot::GetParentSpellType(correct_type);
|
||||
}
|
||||
|
||||
if (correct_type == s.type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (correct_type == UINT16_MAX) {
|
||||
LogBotSpellTypeChecks(
|
||||
"{} [#{}] is incorrect. It is currently set as {} [#{}] but the correct type is unknown.",
|
||||
GetSpellName(spell_id),
|
||||
spell_id,
|
||||
Bot::GetSpellTypeNameByID(s.type),
|
||||
s.type
|
||||
);
|
||||
}
|
||||
else {
|
||||
LogBotSpellTypeChecks("{} [#{}] is incorrect. It is currently set as {} [#{}] and should be {} [#{}]",
|
||||
GetSpellName(spell_id),
|
||||
spell_id,
|
||||
Bot::GetSpellTypeNameByID(s.type),
|
||||
s.type,
|
||||
Bot::GetSpellTypeNameByID(correct_type),
|
||||
correct_type
|
||||
);
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `type` = {} WHERE `spell_id` = {}; -- {} [#{}] from {} [#{}] to {} [#{}]",
|
||||
correct_type,
|
||||
spell_id,
|
||||
GetSpellName(spell_id),
|
||||
spell_id,
|
||||
Bot::GetSpellTypeNameByID(s.type),
|
||||
s.type,
|
||||
Bot::GetSpellTypeNameByID(correct_type),
|
||||
correct_type
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BotDatabase::MapCommandedSpellTypeMinLevels() {
|
||||
commanded_spell_type_min_levels.clear();
|
||||
|
||||
|
||||
@ -130,6 +130,7 @@ public:
|
||||
bool SaveBotSettings(Mob* m);
|
||||
bool DeleteBotSettings(const uint32 bot_id);
|
||||
|
||||
void CheckBotSpells();
|
||||
void MapCommandedSpellTypeMinLevels();
|
||||
std::map<int32_t, std::map<int32_t, BotSpellTypesByClass>> GetCommandedSpellTypesMinLevels() { return commanded_spell_type_min_levels; }
|
||||
|
||||
|
||||
@ -2865,132 +2865,3 @@ BotSpell Bot::GetBestBotSpellForCharm(Bot* caster, Mob* target, uint16 spell_typ
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void Bot::CheckBotSpells() {
|
||||
auto spell_list = BotSpellsEntriesRepository::All(content_db);
|
||||
uint16 spell_id;
|
||||
SPDat_Spell_Struct spell;
|
||||
uint16 correct_type;
|
||||
uint16 parent_type;
|
||||
|
||||
for (const auto& s : spell_list) {
|
||||
if (!IsValidSpell(s.spell_id)) {
|
||||
LogBotSpellTypeChecks("{} is an invalid spell", s.spell_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
spell = spells[s.spell_id];
|
||||
spell_id = spell.id;
|
||||
|
||||
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);
|
||||
}
|
||||
else {
|
||||
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
|
||||
, 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
|
||||
);
|
||||
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `minlevel` = {} WHERE `spellid` = {} AND `npc_spells_id` = {}; -- {} [#{}] from minlevel {} to {} for {} [#{}]"
|
||||
, 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
|
||||
, 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
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
, 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
|
||||
);
|
||||
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `minlevel` = {} WHERE `spellid` = {} AND `npc_spells_id` = {}; -- {} [#{}] from minlevel {} to {} for {} [#{}]"
|
||||
, 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
|
||||
, 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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
, 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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
correct_type = GetCorrectBotSpellType(s.type, spell_id);
|
||||
parent_type = GetParentSpellType(correct_type);
|
||||
|
||||
if (RuleB(Bots, UseParentSpellTypeForChecks)) {
|
||||
if (s.type == parent_type || s.type == correct_type) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (IsPetBotSpellType(s.type)) {
|
||||
correct_type = GetPetBotSpellType(correct_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (correct_type == s.type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (correct_type == 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
|
||||
);
|
||||
}
|
||||
else {
|
||||
LogBotSpellTypeChecks("{} [#{}] is incorrect. It is currently set as {} [#{}] and should be {} [#{}]"
|
||||
, GetSpellName(spell_id)
|
||||
, spell_id
|
||||
, GetSpellTypeNameByID(s.type)
|
||||
, s.type
|
||||
, GetSpellTypeNameByID(correct_type)
|
||||
, correct_type
|
||||
);
|
||||
LogBotSpellTypeChecksDetail("UPDATE bot_spells_entries SET `type` = {} WHERE `spell_id` = {}; -- {} [#{}] from {} [#{}] to {} [#{}]"
|
||||
, correct_type
|
||||
, spell_id
|
||||
, GetSpellName(spell_id)
|
||||
, spell_id
|
||||
, GetSpellTypeNameByID(s.type)
|
||||
, s.type
|
||||
, GetSpellTypeNameByID(correct_type)
|
||||
, correct_type
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user