Implement more commanded types properly, move shadownight hate to hateline type...

Add incapacitated checks to casting logic and checks.
Add candocombat zone check, summon other's corpse for bot, in/out combat spell checks, mute checks, level restriction
This commit is contained in:
nytmyr
2024-11-27 13:51:37 -06:00
parent ee9651b4f1
commit b2590b5056
9 changed files with 587 additions and 247 deletions
+177 -111
View File
@@ -5664,9 +5664,7 @@ bool Bot::CastSpell(
casting_spell_id ||
delaytimer ||
spellend_timer.Enabled() ||
IsStunned() ||
IsFeared() ||
IsMezzed() ||
((IsStunned() || IsMezzed() || DivineAura()) && !IsCastNotStandingSpell(spell_id)) ||
(IsSilenced() && !IsDiscipline(spell_id)) ||
(IsAmnesiad() && IsDiscipline(spell_id))
) {
@@ -9403,7 +9401,12 @@ bool Bot::CastChecks(uint16 spell_id, Mob* tar, uint16 spellType, bool doPrechec
if (doPrechecks) {
if (spells[spell_id].target_type == ST_Self && tar != this) {
tar = this;
if (IsEffectInSpell(spell_id, SE_SummonCorpse) && RuleB(Bots, AllowCommandedSummonCorpse)) {
//tar = this;
}
else {
tar = this;
}
}
if (!PrecastChecks(tar, spellType)) {
@@ -9419,11 +9422,30 @@ bool Bot::CastChecks(uint16 spell_id, Mob* tar, uint16 spellType, bool doPrechec
return false;
}
if (spells[spell_id].target_type == ST_Self && tar != this) {
if (IsFeared() || IsSilenced() || IsAmnesiad()) {
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to Incapacitated.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme
return false;
}
if ((IsStunned() || IsMezzed() || DivineAura()) && !IsCastNotStandingSpell(spell_id)) {
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to !IsCastNotStandingSpell.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme
return false;
}
if (
spells[spell_id].target_type == ST_Self
&& tar != this &&
(spellType != BotSpellTypes::SummonCorpse || RuleB(Bots, AllowCommandedSummonCorpse))
) {
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to ST_Self.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme
return false;
}
if (IsDetrimentalSpell(spell_id) && !zone->CanDoCombat()) {
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to !CanDoCombat.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme
return false;
}
if (!CheckSpellRecastTimer(spell_id)) {
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} due to !CheckSpellRecastTimer.'", GetCleanName(), GetSpellName(spell_id)); //deleteme
return false;
@@ -9439,6 +9461,42 @@ bool Bot::CastChecks(uint16 spell_id, Mob* tar, uint16 spellType, bool doPrechec
return false;
}
if (this == tar && IsSacrificeSpell(spell_id)) {
LogBotPreChecks("{} says, 'Cancelling cast of {} due to IsSacrificeSpell.'", GetCleanName(), GetSpellName(spell_id)); //deleteme
return false;
}
if (spells[spell_id].caster_requirement_id && !PassCastRestriction(spells[spell_id].caster_requirement_id)) {
LogBotPreChecks("{} says, 'Cancelling cast of {} due to !PassCastRestriction.'", GetCleanName(), GetSpellName(spell_id)); //deleteme
return false;
}
if (!spells[spell_id].can_cast_in_combat && spells[spell_id].can_cast_out_of_combat) {
if (IsBeneficialSpell(spell_id)) {
if (IsEngaged()) {
LogBotPreChecks("{} says, 'Cancelling cast of {} due to !can_cast_in_combat.'", GetCleanName(), GetSpellName(spell_id)); //deleteme
return false;
}
}
}
else if (spells[spell_id].can_cast_in_combat && !spells[spell_id].can_cast_out_of_combat) {
if (IsBeneficialSpell(spell_id)) {
if (!IsEngaged()) {
LogBotPreChecks("{} says, 'Cancelling cast of {} due to !can_cast_out_of_combat.'", GetCleanName(), GetSpellName(spell_id)); //deleteme
return false;
}
}
}
if (!IsDiscipline(spell_id)) {
int chance = GetFocusEffect(focusFcMute, spell_id);
if (chance && zone->random.Roll(chance)) {
LogBotPreChecks("{} says, 'Cancelling cast of {} due to focusFcMute.'", GetCleanName(), GetSpellName(spell_id)); //deleteme
return(false);
}
}
if (!zone->CanLevitate() && IsEffectInSpell(spell_id, SE_Levitate)) {
LogBotPreChecks("{} says, 'Cancelling cast of {} due to !CanLevitate.'", GetCleanName(), GetSpellName(spell_id)); //deleteme
return false;
@@ -9523,6 +9581,7 @@ bool Bot::CanCastSpellType(uint16 spellType, uint16 spell_id, Mob* tar) {
case BotSpellTypes::Buff:
case BotSpellTypes::PetBuffs:
case BotSpellTypes::PreCombatBuff:
case BotSpellTypes::InCombatBuff:
case BotSpellTypes::DamageShields:
case BotSpellTypes::PetDamageShields:
case BotSpellTypes::ResistBuffs:
@@ -9556,6 +9615,11 @@ bool Bot::CanCastSpellType(uint16 spellType, uint16 spell_id, Mob* tar) {
return false;
}
if (!tar->CheckSpellLevelRestriction(this, spell_id)) {
LogBotPreChecks("{} says, 'Cancelling cast of {} on {} due to CheckSpellLevelRestriction.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme
return false;
}
if ((spellType != BotSpellTypes::Teleport && spellType != BotSpellTypes::Succor) && (IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Succor))) {
LogBotPreChecks("{} says, 'Cancelling cast of {} on {} due to Teleport.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme
return false;
@@ -9668,6 +9732,13 @@ bool Bot::CanCastSpellType(uint16 spellType, uint16 spell_id, Mob* tar) {
}
}
break;
case BotSpellTypes::Lull:
if (IsHarmonySpell(spell_id) && !HarmonySpellLevelCheck(spell_id, tar)) {
LogBotPreChecksDetail("{} says, 'Cancelling cast of {} on {} due to HarmonySpellLevelCheck.'", GetCleanName(), GetSpellName(spell_id), tar->GetCleanName()); //deleteme
return false;
}
break;
default:
break;
@@ -10494,50 +10565,48 @@ uint16 Bot::GetDefaultSpellTypeEngagedPriority(uint16 spellType, uint8 botClass,
return 20;
case BotSpellTypes::Mez:
return 21;
case BotSpellTypes::AEDispel:
case BotSpellTypes::HateLine:
return 22;
case BotSpellTypes::Dispel:
case BotSpellTypes::AEDispel:
return 23;
case BotSpellTypes::AEDebuff:
case BotSpellTypes::Dispel:
return 24;
case BotSpellTypes::Debuff:
case BotSpellTypes::AEDebuff:
return 25;
case BotSpellTypes::AESnare:
case BotSpellTypes::Debuff:
return 26;
case BotSpellTypes::Snare:
case BotSpellTypes::AESnare:
return 27;
case BotSpellTypes::AEFear:
case BotSpellTypes::Snare:
return 28;
case BotSpellTypes::Fear:
return 29;
case BotSpellTypes::AESlow:
return 30;
return 29;
case BotSpellTypes::Slow:
return 31;
return 30;
case BotSpellTypes::AERoot:
return 32;
return 31;
case BotSpellTypes::Root:
return 33;
return 32;
case BotSpellTypes::AEDoT:
return 34;
return 33;
case BotSpellTypes::DOT:
return 35;
return 34;
case BotSpellTypes::AEStun:
return 36;
return 35;
case BotSpellTypes::PBAENuke:
return 37;
return 36;
case BotSpellTypes::AENukes:
return 38;
return 37;
case BotSpellTypes::AERains:
return 39;
return 38;
case BotSpellTypes::Stun:
return 40;
return 39;
case BotSpellTypes::Nuke:
return 41;
return 40;
case BotSpellTypes::InCombatBuff:
return 42;
return 41;
case BotSpellTypes::InCombatBuffSong:
return 43;
return 42;
default:
return 0;
}
@@ -10904,8 +10973,6 @@ uint16 Bot::GetSpellListSpellType(uint16 spellType) {
case BotSpellTypes::PetDamageShields:
case BotSpellTypes::ResistBuffs:
case BotSpellTypes::PetResistBuffs:
case BotSpellTypes::Teleport:
case BotSpellTypes::Succor:
case BotSpellTypes::BindAffinity:
case BotSpellTypes::Identify:
case BotSpellTypes::Levitate:
@@ -10914,8 +10981,6 @@ uint16 Bot::GetSpellListSpellType(uint16 spellType) {
case BotSpellTypes::Size:
case BotSpellTypes::Invisibility:
case BotSpellTypes::MovementSpeed:
case BotSpellTypes::SendHome:
case BotSpellTypes::SummonCorpse:
return BotSpellTypes::Buff;
case BotSpellTypes::AEMez:
case BotSpellTypes::Mez:
@@ -10950,6 +11015,7 @@ uint16 Bot::GetSpellListSpellType(uint16 spellType) {
case BotSpellTypes::Charm:
case BotSpellTypes::Escape:
case BotSpellTypes::HateRedux:
case BotSpellTypes::HateLine:
case BotSpellTypes::InCombatBuff:
case BotSpellTypes::InCombatBuffSong:
case BotSpellTypes::OutOfCombatBuffSong:
@@ -11021,84 +11087,84 @@ bool Bot::IsValidSpellTypeBySpellID(uint16 spellType, uint16 spell_id) {
}
return false;
case BotSpellTypes::Lull:
if (!IsHarmonySpell(spell_id)) {
return true;
}
return false;
case BotSpellTypes::Teleport:
if (IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))) {
return true;
}
return false;
case BotSpellTypes::Succor:
if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_Succor)) {
return true;
}
return false;
case BotSpellTypes::BindAffinity:
if (IsEffectInSpell(spell_id, SE_BindAffinity)) {
return true;
}
return false;
case BotSpellTypes::Identify:
if (IsEffectInSpell(spell_id, SE_Identify)) {
return true;
}
return false;
case BotSpellTypes::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)) {
return true;
}
return false;
case BotSpellTypes::WaterBreathing:
if (IsEffectInSpell(spell_id, SE_WaterBreathing)) {
return true;
}
return false;
case BotSpellTypes::Size:
if (IsBeneficialSpell(spell_id) && (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)) {
return true;
}
return false;
case BotSpellTypes::MovementSpeed:
if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_MovementSpeed)) {
return true;
}
return false;
case BotSpellTypes::SendHome:
if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_GateToHomeCity)) {
return true;
}
return false;
case BotSpellTypes::SummonCorpse:
if (IsEffectInSpell(spell_id, SE_SummonCorpse)) {
return true;
}
return false;
//case BotSpellTypes::Lull:
// if (IsHarmonySpell(spell_id)) {
// return true;
// }
//
// return false;
//case BotSpellTypes::Teleport:
// if (IsBeneficialSpell(spell_id) && (IsEffectInSpell(spell_id, SE_Teleport) || IsEffectInSpell(spell_id, SE_Translocate))) {
// return true;
// }
//
// return false;
//case BotSpellTypes::Succor:
// if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_Succor)) {
// return true;
// }
//
// return false;
//case BotSpellTypes::BindAffinity:
// if (IsEffectInSpell(spell_id, SE_BindAffinity)) {
// return true;
// }
//
// return false;
//case BotSpellTypes::Identify:
// if (IsEffectInSpell(spell_id, SE_Identify)) {
// return true;
// }
//
// return false;
//case BotSpellTypes::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)) {
// return true;
// }
//
// return false;
//case BotSpellTypes::WaterBreathing:
// if (IsEffectInSpell(spell_id, SE_WaterBreathing)) {
// return true;
// }
//
// return false;
//case BotSpellTypes::Size:
// if (IsBeneficialSpell(spell_id) && (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)) {
// return true;
// }
//
// return false;
//case BotSpellTypes::MovementSpeed:
// if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_MovementSpeed)) {
// return true;
// }
//
// return false;
//case BotSpellTypes::SendHome:
// if (IsBeneficialSpell(spell_id) && IsEffectInSpell(spell_id, SE_GateToHomeCity)) {
// return true;
// }
//
// return false;
//case BotSpellTypes::SummonCorpse:
// if (IsEffectInSpell(spell_id, SE_SummonCorpse)) {
// return true;
// }
//
// return false;
default:
return true;
}
@@ -11331,7 +11397,7 @@ bool Bot::HasValidAETarget(Bot* botCaster, uint16 spell_id, uint16 spellType, Mo
break;
}
if (!m->IsNPC() || !m->CastToNPC()->IsOnHatelist(botCaster->GetOwner())) {
if (!m->IsNPC() || (!IsCommandedSpell() && !m->CastToNPC()->IsOnHatelist(botCaster->GetOwner()))) {
continue;
}
+17 -9
View File
@@ -308,7 +308,7 @@ void bot_command_cast(Client* c, const Seperator* sep)
}
Mob* tar = c->GetTarget();
LogTestDebug("{}: 'Attempting {} [{}] on {}'", __LINE__, c->GetSpellTypeNameByID(spellType), (subType != UINT16_MAX ? c->GetSubTypeNameByID(subType) : "Standard"), (tar ? tar->GetCleanName() : "NOBODY")); //deleteme
//LogTestDebug("{}: 'Attempting {} [{}-{}] on {}'", __LINE__, c->GetSpellTypeNameByID(spellType), (subType != UINT16_MAX ? c->GetSubTypeNameByID(subType) : "Standard"), (subTargetType != UINT16_MAX ? c->GetSubTypeNameByID(subTargetType) : "Standard"), (tar ? tar->GetCleanName() : "NOBODY")); //deleteme
if (!tar) {
if (spellType != BotSpellTypes::Escape && spellType != BotSpellTypes::Pet) {
@@ -338,7 +338,17 @@ void bot_command_cast(Client* c, const Seperator* sep)
break;
default:
if (BOT_SPELL_TYPES_DETRIMENTAL(spellType) && !c->IsAttackAllowed(tar)) {
if (
(BOT_SPELL_TYPES_DETRIMENTAL(spellType) && !c->IsAttackAllowed(tar)) ||
(
spellType == BotSpellTypes::Charm &&
(
tar->IsClient() ||
tar->IsCorpse() ||
tar->GetOwner()
)
)
) {
c->Message(Chat::Yellow, "You cannot attack [%s].", tar->GetCleanName());
return;
@@ -395,18 +405,16 @@ void bot_command_cast(Client* c, const Seperator* sep)
/*
TODO bot rewrite -
FIX: Depart, SummonCorpse, Lull,
Group Cures, Precombat, Fear/AE Fear
ICB (SK) casting hate on friendly but not hostile?
FIX: Depart
Group Cures, Precombat
NEED TO CHECK: precombat, AE Dispel, AE Lifetap
DO I NEED A PBAE CHECK???
*/
if (bot_iter->GetBotStance() == Stance::Passive || bot_iter->GetHoldFlag() || bot_iter->GetAppearance() == eaDead || bot_iter->IsFeared() || bot_iter->IsStunned() || bot_iter->IsMezzed() || bot_iter->DivineAura() || bot_iter->GetHP() < 0) {
if (bot_iter->GetBotStance() == Stance::Passive || bot_iter->GetHoldFlag() || bot_iter->GetAppearance() == eaDead || bot_iter->IsFeared() || bot_iter->IsSilenced() || bot_iter->IsAmnesiad() || bot_iter->GetHP() < 0) {
continue;
}
Mob* newTar = tar;
LogTestDebug("{}: {} says, 'Attempting {} [{}] on {}'", __LINE__, bot_iter->GetCleanName(), c->GetSpellTypeNameByID(spellType), (subType != UINT16_MAX ? c->GetSubTypeNameByID(subType) : "Standard"), (newTar ? newTar->GetCleanName() : "NOBODY")); //deleteme
//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
if (!SpellTypeRequiresTarget(spellType, bot_iter->GetClass())) {
newTar = bot_iter;
}
@@ -435,7 +443,7 @@ void bot_command_cast(Client* c, const Seperator* sep)
continue;
}
LogTestDebug("{}: {} says, 'Attempting {} [{}] on {}'", __LINE__, bot_iter->GetCleanName(), c->GetSpellTypeNameByID(spellType), (subType != UINT16_MAX ? c->GetSubTypeNameByID(subType) : "Standard"), (newTar ? newTar->GetCleanName() : "NOBODY")); //deleteme
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);
+174 -67
View File
@@ -116,11 +116,13 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 spellType, uint16 subTarge
break;
case BotSpellTypes::InCombatBuff:
if (GetClass() == Class::ShadowKnight && (tar->IsOfClientBot() || (tar->IsPet() && tar->GetOwner() && tar->GetOwner()->IsOfClientBot()))) {
if (!IsCommandedSpell() && GetClass() != Class::Shaman && spellType == BotSpellTypes::InCombatBuff && IsCasterClass(GetClass()) && GetLevel() >= GetStopMeleeLevel()) {
return false;
}
if (!IsCommandedSpell() && GetClass() != Class::Shaman && spellType == BotSpellTypes::InCombatBuff && IsCasterClass(GetClass()) && GetLevel() >= GetStopMeleeLevel()) {
break;
case BotSpellTypes::HateLine:
if (!tar->IsNPC()) {
return false;
}
@@ -198,7 +200,6 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 spellType, uint16 subTarge
return BotCastPet(tar, botClass, botSpell, spellType);
case BotSpellTypes::Resurrect:
case BotSpellTypes::SummonCorpse:
if (!tar->IsCorpse() || !tar->CastToCorpse()->IsPlayerCorpse()) {
return false;
}
@@ -267,6 +268,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 spellType, uint16 subTarge
return true;
}
else { LogTestDebug("{} says, '{} [#{}] - [{}] FAILED AIDoSpellCast on {}.'", GetCleanName(), spells[s.SpellId].name, s.SpellId, GetSpellTypeNameByID(spellType), tar->GetCleanName()); } //deleteme
}
return false;
@@ -631,7 +633,7 @@ bool Bot::AIDoSpellCast(int32 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
}
bool Bot::AI_PursueCastCheck() {
if (GetAppearance() == eaDead || IsFeared() || IsStunned() || IsMezzed() || DivineAura() || GetHP() < 0) {
if (GetAppearance() == eaDead || IsFeared() || IsSilenced() || IsAmnesiad() || GetHP() < 0) {
return false;
}
@@ -656,11 +658,11 @@ bool Bot::AI_PursueCastCheck() {
continue;
}
if (RuleB(Bots, AllowAIMez) && (currentCast.spellType == BotSpellTypes::AEMez || currentCast.spellType == BotSpellTypes::Mez)) {
if (!RuleB(Bots, AllowAIMez) && (currentCast.spellType == BotSpellTypes::AEMez || currentCast.spellType == BotSpellTypes::Mez)) {
continue;
}
if (IsCommandedSpellType(currentCast.spellType) || currentCast.spellType == BotSpellTypes::Resurrect || currentCast.spellType == BotSpellTypes::Charm) { // Unsupported by AI currently.
if (IsCommandedSpellType(currentCast.spellType)) { // Unsupported by AI currently.
continue;
}
@@ -680,7 +682,7 @@ bool Bot::AI_PursueCastCheck() {
}
bool Bot::AI_IdleCastCheck() {
if (GetAppearance() == eaDead || IsFeared() || IsStunned() || IsMezzed() || DivineAura() || GetHP() < 0) {
if (GetAppearance() == eaDead || IsFeared() || IsSilenced() || IsAmnesiad() || GetHP() < 0) {
return false;
}
@@ -719,11 +721,11 @@ bool Bot::AI_IdleCastCheck() {
continue;
}
if (RuleB(Bots, AllowAIMez) && (currentCast.spellType == BotSpellTypes::AEMez || currentCast.spellType == BotSpellTypes::Mez)) {
if (!RuleB(Bots, AllowAIMez) && (currentCast.spellType == BotSpellTypes::AEMez || currentCast.spellType == BotSpellTypes::Mez)) {
continue;
}
if (IsCommandedSpellType(currentCast.spellType) || currentCast.spellType == BotSpellTypes::Resurrect || currentCast.spellType == BotSpellTypes::Charm) { // Unsupported by AI currently.
if (IsCommandedSpellType(currentCast.spellType)) { // Unsupported by AI currently.
continue;
}
@@ -743,7 +745,7 @@ bool Bot::AI_IdleCastCheck() {
}
bool Bot::AI_EngagedCastCheck() {
if (GetAppearance() == eaDead || IsFeared() || IsStunned() || IsMezzed() || DivineAura() || GetHP() < 0) {
if (GetAppearance() == eaDead || IsFeared() || IsSilenced() || IsAmnesiad() || GetHP() < 0) {
return false;
}
@@ -769,11 +771,11 @@ bool Bot::AI_EngagedCastCheck() {
continue;
}
if (RuleB(Bots, AllowAIMez) && (currentCast.spellType == BotSpellTypes::AEMez || currentCast.spellType == BotSpellTypes::Mez)) {
if (!RuleB(Bots, AllowAIMez) && (currentCast.spellType == BotSpellTypes::AEMez || currentCast.spellType == BotSpellTypes::Mez)) {
continue;
}
if (IsCommandedSpellType(currentCast.spellType) || currentCast.spellType == BotSpellTypes::Resurrect || currentCast.spellType == BotSpellTypes::Charm) { // Unsupported by AI currently.
if (IsCommandedSpellType(currentCast.spellType)) { // Unsupported by AI currently.
continue;
}
@@ -1045,28 +1047,19 @@ std::list<BotSpell_wPriority> Bot::GetPrioritizedBotSpellsBySpellType(Bot* botCa
}
if (
(
!botCaster->IsCommandedSpell() ||
(
botCaster->IsCommandedSpell() &&
(spellType != BotSpellTypes::Mez && spellType != BotSpellTypes::AEMez)
)
)
&&
(
!IsPBAESpell(botSpellList[i].spellid) &&
!botCaster->CastChecks(botSpellList[i].spellid, tar, spellType, false, IsAEBotSpellType(spellType))
)
(!botCaster->IsCommandedSpell() || (botCaster->IsCommandedSpell() && SpellTypeRequiresCastChecks(spellType))) &&
(!IsPBAESpell(botSpellList[i].spellid) && !botCaster->CastChecks(botSpellList[i].spellid, tar, spellType, false, IsAEBotSpellType(spellType)))
) {
continue;
}
if (
botCaster->IsCommandedSpell() ||
botCaster->IsCommandedSpell() ||
!AE ||
(spellType == BotSpellTypes::GroupCures) ||
(spellType == BotSpellTypes::AEMez) ||
(AE && botCaster->HasValidAETarget(botCaster, botSpellList[i].spellid, spellType, tar))
(
SpellTypeRequiresAEChecks(spellType) &&
botCaster->HasValidAETarget(botCaster, botSpellList[i].spellid, spellType, tar)
)
) {
BotSpell_wPriority botSpell;
botSpell.SpellId = botSpellList[i].spellid;
@@ -2099,18 +2092,6 @@ uint8 Bot::GetChanceToCastBySpellType(uint16 spellType)
case BotSpellTypes::PetResistBuffs:
case BotSpellTypes::DamageShields:
case BotSpellTypes::PetDamageShields:
case BotSpellTypes::Teleport:
case BotSpellTypes::Succor:
case BotSpellTypes::BindAffinity:
case BotSpellTypes::Identify:
case BotSpellTypes::Levitate:
case BotSpellTypes::Rune:
case BotSpellTypes::WaterBreathing:
case BotSpellTypes::Size:
case BotSpellTypes::Invisibility:
case BotSpellTypes::MovementSpeed:
case BotSpellTypes::SendHome:
case BotSpellTypes::SummonCorpse:
return RuleI(Bots, PercentChanceToCastBuff);
case BotSpellTypes::Escape:
return RuleI(Bots, PercentChanceToCastEscape);
@@ -2124,6 +2105,8 @@ uint8 Bot::GetChanceToCastBySpellType(uint16 spellType)
return RuleI(Bots, PercentChanceToCastDispel);
case BotSpellTypes::InCombatBuff:
return RuleI(Bots, PercentChanceToCastInCombatBuff);
case BotSpellTypes::HateLine:
return RuleI(Bots, PercentChanceToCastHateLine);
case BotSpellTypes::Mez:
return RuleI(Bots, PercentChanceToCastMez);
case BotSpellTypes::Slow:
@@ -2842,65 +2825,71 @@ void Bot::CheckBotSpells() {
switch (s.type) {
case BotSpellTypes::Nuke: //DONE
case BotSpellTypes::Nuke:
if (IsAnyNukeOrStunSpell(spell_id) && !IsEffectInSpell(spell_id, SE_Root) && !IsDebuffSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::RegularHeal: //DONE
//if (IsAnyHealSpell(spell_id) && !IsEscapeSpell(spell_id) && (IsRegularPetHealSpell(spell_id) || !IsCureSpell(spell_id))) {
case BotSpellTypes::RegularHeal:
if (IsAnyHealSpell(spell_id) && !IsEscapeSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::Root: //DONE
case BotSpellTypes::Root:
if (IsEffectInSpell(spell_id, SE_Root)) {
valid = true;
break;
}
break;
case BotSpellTypes::Buff: //DONE
case BotSpellTypes::Buff:
if (IsAnyBuffSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::Pet: //DONE
case BotSpellTypes::Pet:
if (IsSummonPetSpell(spell_id) || IsEffectInSpell(spell_id, SE_TemporaryPets)) {
valid = true;
break;
}
break;
case BotSpellTypes::Lifetap: //DONE
case BotSpellTypes::Lifetap:
if (IsLifetapSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::Snare: //DONE
case BotSpellTypes::Snare:
if (IsEffectInSpell(spell_id, SE_MovementSpeed) && IsDetrimentalSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::DOT: //DONE
case BotSpellTypes::DOT:
if (IsStackableDOT(spell_id) || IsDamageOverTimeSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::Dispel: //DONE
case BotSpellTypes::Dispel:
if (IsDispelSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::InCombatBuff: //DONE
case BotSpellTypes::InCombatBuff:
if (
IsSelfConversionSpell(spell_id) ||
IsAnyBuffSpell(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)
) {
@@ -2908,37 +2897,37 @@ void Bot::CheckBotSpells() {
break;
}
break;
case BotSpellTypes::Mez: //DONE
case BotSpellTypes::Mez:
if (IsMesmerizeSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::Charm: //DONE
case BotSpellTypes::Charm:
if (IsCharmSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::Slow: //DONE
case BotSpellTypes::Slow:
if (IsSlowSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::Debuff: //DONE
case BotSpellTypes::Debuff:
if (IsDebuffSpell(spell_id) && !IsEscapeSpell(spell_id) && !IsHateReduxSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::Cure: //DONE
case BotSpellTypes::Cure:
if (IsCureSpell(spell_id)) {
valid = true;
break;
}
break;
case BotSpellTypes::PreCombatBuff: //DONE
case BotSpellTypes::PreCombatBuff:
if (
IsBuffSpell(spell_id) &&
IsBeneficialSpell(spell_id) &&
@@ -2950,9 +2939,9 @@ void Bot::CheckBotSpells() {
break;
}
break;
case BotSpellTypes::InCombatBuffSong: //DONE
case BotSpellTypes::OutOfCombatBuffSong: //DONE
case BotSpellTypes::PreCombatBuffSong: //DONE
case BotSpellTypes::InCombatBuffSong:
case BotSpellTypes::OutOfCombatBuffSong:
case BotSpellTypes::PreCombatBuffSong:
if (
IsBuffSpell(spell_id) &&
IsBeneficialSpell(spell_id) &&
@@ -2964,7 +2953,7 @@ void Bot::CheckBotSpells() {
break;
}
break;
case BotSpellTypes::Fear: //DONE
case BotSpellTypes::Fear:
if (IsFearSpell(spell_id)) {
valid = true;
break;
@@ -2988,7 +2977,84 @@ void Bot::CheckBotSpells() {
break;
}
break;
//TODO bot rewrite - add commanded types
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;
@@ -2997,7 +3063,6 @@ void Bot::CheckBotSpells() {
if (IsAnyNukeOrStunSpell(spell_id) && !IsEffectInSpell(spell_id, SE_Root) && !IsDebuffSpell(spell_id)) {
correctType = BotSpellTypes::Nuke;
}
//else if (IsAnyHealSpell(spell_id) && !IsEscapeSpell(spell_id) && (IsRegularPetHealSpell(spell_id) || !IsCureSpell(spell_id))) {
else if (IsAnyHealSpell(spell_id) && !IsEscapeSpell(spell_id)) {
correctType = BotSpellTypes::RegularHeal;
}
@@ -3024,11 +3089,15 @@ void Bot::CheckBotSpells() {
}
else if (
IsSelfConversionSpell(spell_id) ||
IsAnyBuffSpell(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::InCombatBuff;
correctType = BotSpellTypes::HateLine;
}
else if (IsMesmerizeSpell(spell_id)) {
correctType = BotSpellTypes::Mez;
@@ -3084,7 +3153,45 @@ void Bot::CheckBotSpells() {
else if (IsEffectInSpell(spell_id, SE_Revive)) {
correctType = BotSpellTypes::Resurrect;
}
//TODO bot rewrite - add commanded types
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;
}
if (!valid || (correctType == UINT16_MAX) || (s.type != correctType)) {
LogBotSpellTypeChecks("{} [#{}] is incorrect. It is currently set as {} [#{}] and should be {} [#{}]"
+60 -6
View File
@@ -8881,6 +8881,9 @@ std::string Mob::GetSpellTypeNameByID(uint16 spellType) {
case BotSpellTypes::PetResistBuffs:
spellTypeName = "Pet Resist Buff";
break;
case BotSpellTypes::HateLine:
spellTypeName = "Hate Line";
break;
case BotSpellTypes::Lull:
spellTypeName = "Lull";
break;
@@ -9096,6 +9099,9 @@ std::string Mob::GetSpellTypeShortNameByID(uint16 spellType) {
case BotSpellTypes::PetResistBuffs:
spellTypeName = "petresistbuffs";
break;
case BotSpellTypes::HateLine:
spellTypeName = "hateline";
break;
case BotSpellTypes::Lull:
spellTypeName = "lull";
break;
@@ -9214,8 +9220,11 @@ bool Mob::GetDefaultSpellHold(uint16 spellType, uint8 stance) {
case BotSpellTypes::AEFear:
case BotSpellTypes::Fear:
return true;
case BotSpellTypes::Mez:
case BotSpellTypes::AEMez:
case BotSpellTypes::Debuff:
case BotSpellTypes::AEDebuff:
case BotSpellTypes::Slow:
case BotSpellTypes::AESlow:
case BotSpellTypes::HateRedux:
switch (stance) {
@@ -9232,12 +9241,7 @@ bool Mob::GetDefaultSpellHold(uint16 spellType, uint8 stance) {
case Stance::Assist:
return true;
default:
if (GetClass() == Class::Wizard) {
return true;
}
else {
return false;
}
return false;
}
case BotSpellTypes::InCombatBuffSong:
case BotSpellTypes::OutOfCombatBuffSong:
@@ -9248,6 +9252,55 @@ bool Mob::GetDefaultSpellHold(uint16 spellType, uint8 stance) {
else {
return true;
}
case BotSpellTypes::HateLine:
if (GetClass() == Class::ShadowKnight || GetClass() == Class::Paladin) {
switch (stance) {
case Stance::Aggressive:
return false;
default:
return true;
}
}
else {
return true;
}
case BotSpellTypes::Cure:
case BotSpellTypes::GroupCures:
switch (stance) {
case Stance::Aggressive:
case Stance::AEBurn:
case Stance::Burn:
return true;
default:
return false;
}
case BotSpellTypes::GroupCompleteHeals:
case BotSpellTypes::GroupHeals:
case BotSpellTypes::GroupHoTHeals:
case BotSpellTypes::HoTHeals:
case BotSpellTypes::CompleteHeal:
case BotSpellTypes::PetCompleteHeals:
case BotSpellTypes::PetFastHeals:
case BotSpellTypes::PetHoTHeals:
case BotSpellTypes::PetRegularHeals:
case BotSpellTypes::PetVeryFastHeals:
case BotSpellTypes::RegularHeal:
switch (stance) {
case Stance::Aggressive:
case Stance::AEBurn:
case Stance::Burn:
return true;
default:
return false;
}
case BotSpellTypes::FastHeals:
case BotSpellTypes::VeryFastHeals:
case BotSpellTypes::Pet:
case BotSpellTypes::Escape:
case BotSpellTypes::Lifetap:
case BotSpellTypes::Buff:
case BotSpellTypes::InCombatBuff:
case BotSpellTypes::PreCombatBuff:
default:
return false;
}
@@ -9470,6 +9523,7 @@ uint8 Mob::GetDefaultSpellMaxThreshold(uint16 spellType, uint8 stance) {
case BotSpellTypes::PetResistBuffs:
case BotSpellTypes::ResistBuffs:
case BotSpellTypes::Resurrect:
case BotSpellTypes::HateLine:
return 100;
case BotSpellTypes::GroupHoTHeals:
case BotSpellTypes::HoTHeals:
+13 -2
View File
@@ -796,7 +796,12 @@ bool Mob::DoCastingChecksOnTarget(bool check_on_casting, int32 spell_id, Mob *sp
if (IsGroupSpell(spell_id)) {
return true;
} else if (spells[spell_id].target_type == ST_Self) {
spell_target = this;
if (IsBot() && (IsEffectInSpell(spell_id, SE_SummonCorpse) && RuleB(Bots, AllowCommandedSummonCorpse))) {
//spell_target = this;
}
else {
spell_target = this;
}
}
} else {
if (IsGroupSpell(spell_id) && spell_target != this) {
@@ -1937,7 +1942,13 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
// single target spells
case ST_Self:
{
spell_target = this;
if (IsBot() && (IsEffectInSpell(spell_id, SE_SummonCorpse) && RuleB(Bots, AllowCommandedSummonCorpse))) {
//spell_target = this;
}
else {
spell_target = this;
}
CastAction = SingleTarget;
break;
}