From b2590b50566f11fd4e40e5f85c8f618808335cfd Mon Sep 17 00:00:00 2001 From: nytmyr <53322305+nytmyr@users.noreply.github.com> Date: Wed, 27 Nov 2024 13:51:37 -0600 Subject: [PATCH] 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 --- .../database_update_manifest_bots.cpp | 125 ++++++-- common/ruletypes.h | 1 + common/spdat.cpp | 67 ++-- common/spdat.h | 5 +- zone/bot.cpp | 288 +++++++++++------- zone/bot_commands/cast.cpp | 26 +- zone/botspellsai.cpp | 241 +++++++++++---- zone/mob.cpp | 66 +++- zone/spells.cpp | 15 +- 9 files changed, 587 insertions(+), 247 deletions(-) diff --git a/common/database/database_update_manifest_bots.cpp b/common/database/database_update_manifest_bots.cpp index 96627d814..72e26142c 100644 --- a/common/database/database_update_manifest_bots.cpp +++ b/common/database/database_update_manifest_bots.cpp @@ -513,7 +513,7 @@ UPDATE bot_spells_entries SET `type` = 4 WHERE `spell_id` = 10436; .match = "", .sql = R"( INSERT INTO `bot_spells_entries` (`npc_spells_id`, `spell_id`, `type`, `minlevel`, `maxlevel`) -VALUES +VALUES (3006, 9957, 100, 20, 254), (3006, 9956, 100, 20, 254), (3006, 552, 100, 25, 254), @@ -764,31 +764,6 @@ VALUES (3006, 34863, 101, 96, 254), (3006, 34864, 101, 96, 254), (3006, 34862, 101, 96, 254), -(3007, 4614, 101, 35, 49), -(3007, 4683, 101, 50, 56), -(3007, 4684, 101, 57, 63), -(3007, 4698, 101, 64, 64), -(3007, 5019, 101, 65, 254), -(3007, 5020, 101, 65, 254), -(3007, 6175, 101, 69, 70), -(3007, 10949, 101, 71, 75), -(3007, 10947, 101, 71, 75), -(3007, 10948, 101, 71, 75), -(3007, 14800, 101, 76, 80), -(3007, 14801, 101, 76, 80), -(3007, 14799, 101, 76, 80), -(3007, 18905, 101, 81, 85), -(3007, 18906, 101, 81, 85), -(3007, 18904, 101, 81, 85), -(3007, 25912, 101, 86, 90), -(3007, 25913, 101, 86, 90), -(3007, 25911, 101, 86, 90), -(3007, 29006, 101, 91, 95), -(3007, 29007, 101, 91, 95), -(3007, 29008, 101, 91, 95), -(3007, 35047, 101, 96, 254), -(3007, 35048, 101, 96, 254), -(3007, 35049, 101, 96, 254), (3008, 728, 101, 8, 60), (3008, 3361, 101, 61, 254), (3008, 5370, 101, 66, 70), @@ -1090,6 +1065,104 @@ VALUES (3011, 25555, 112, 86, 90), (3011, 28632, 112, 91, 95), (3011, 34662, 112, 96, 254); +)" + }, + ManifestEntry{ + .version = 9051, + .description = "2024_11_26_remove_sk_icb.sql", + .check = "SELECT * FROM `bot_spells_entries` where `type` = 55", + .condition = "empty", + .match = "", + .sql = R"( +DELETE +FROM bot_spells_entries +WHERE `npc_spells_id` = 3005 +AND `type` = 10; + +INSERT INTO `bot_spells_entries` (`npc_spells_id`, `spell_id`, `type`, `minlevel`, `maxlevel`) +VALUES +(3003, 10175, 55, 72, 76), +(3003, 10173, 55, 72, 76), +(3003, 10174, 55, 72, 76), +(3003, 14956, 55, 77, 81), +(3003, 14954, 55, 77, 81), +(3003, 14955, 55, 77, 81), +(3003, 19070, 55, 82, 86), +(3003, 19068, 55, 82, 86), +(3003, 19069, 55, 82, 86), +(3003, 25298, 55, 87, 91), +(3003, 25299, 55, 87, 91), +(3003, 25297, 55, 87, 91), +(3003, 28348, 55, 92, 96), +(3003, 28349, 55, 92, 96), +(3003, 28347, 55, 92, 96), +(3003, 34351, 55, 97, 254), +(3003, 34352, 55, 97, 254), +(3003, 34350, 55, 97, 254), +(3003, 40078, 55, 98, 254), +(3003, 40079, 55, 98, 254), +(3003, 40080, 55, 98, 254), +(3005, 1221, 55, 33, 41), +(3005, 1222, 55, 42, 52), +(3005, 1223, 55, 53, 58), +(3005, 1224, 55, 59, 62), +(3005, 3405, 55, 63, 66), +(3005, 5329, 55, 67, 70), +(3005, 5336, 55, 69, 73), +(3005, 10258, 55, 71, 71), +(3005, 10259, 55, 71, 71), +(3005, 10257, 55, 71, 71), +(3005, 10261, 55, 72, 76), +(3005, 10262, 55, 72, 76), +(3005, 10260, 55, 72, 76), +(3005, 10291, 55, 74, 78), +(3005, 10292, 55, 74, 78), +(3005, 10293, 55, 74, 78), +(3005, 15160, 55, 76, 76), +(3005, 15161, 55, 76, 76), +(3005, 15162, 55, 76, 76), +(3005, 15165, 55, 77, 81), +(3005, 15163, 55, 77, 81), +(3005, 15164, 55, 77, 81), +(3005, 15186, 55, 79, 83), +(3005, 15184, 55, 79, 83), +(3005, 15185, 55, 79, 83), +(3005, 19315, 55, 81, 81), +(3005, 19313, 55, 81, 81), +(3005, 19314, 55, 81, 81), +(3005, 19317, 55, 82, 86), +(3005, 19318, 55, 82, 86), +(3005, 19316, 55, 82, 86), +(3005, 19338, 55, 84, 88), +(3005, 19339, 55, 84, 88), +(3005, 19337, 55, 84, 88), +(3005, 25581, 55, 86, 86), +(3005, 25582, 55, 86, 86), +(3005, 25580, 55, 86, 86), +(3005, 25586, 55, 87, 91), +(3005, 25587, 55, 87, 91), +(3005, 25588, 55, 87, 91), +(3005, 25641, 55, 89, 93), +(3005, 25642, 55, 89, 93), +(3005, 25643, 55, 89, 93), +(3005, 28659, 55, 91, 91), +(3005, 28657, 55, 91, 91), +(3005, 28658, 55, 91, 91), +(3005, 28665, 55, 92, 96), +(3005, 28663, 55, 92, 96), +(3005, 28664, 55, 92, 96), +(3005, 28735, 55, 94, 98), +(3005, 28733, 55, 94, 98), +(3005, 28734, 55, 94, 98), +(3005, 34688, 55, 96, 96), +(3005, 34689, 55, 96, 96), +(3005, 34687, 55, 96, 96), +(3005, 34694, 55, 97, 254), +(3005, 34695, 55, 97, 254), +(3005, 34693, 55, 97, 254), +(3005, 34752, 55, 99, 254), +(3005, 34753, 55, 99, 254), +(3005, 34751, 55, 99, 254); )" } // -- template; copy/paste this when you need to create a new entry diff --git a/common/ruletypes.h b/common/ruletypes.h index da5a5f35d..574b34800 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -806,6 +806,7 @@ RULE_INT(Bots, PercentChanceToCastSnare, 75, "The chance for a bot to attempt to RULE_INT(Bots, PercentChanceToCastDOT, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.") RULE_INT(Bots, PercentChanceToCastDispel, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.") RULE_INT(Bots, PercentChanceToCastInCombatBuff, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.") +RULE_INT(Bots, PercentChanceToCastHateLine, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.") RULE_INT(Bots, PercentChanceToCastMez, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.") RULE_INT(Bots, PercentChanceToCastSlow, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.") RULE_INT(Bots, PercentChanceToCastDebuff, 75, "The chance for a bot to attempt to cast the given spell type in combat. Default 75%.") diff --git a/common/spdat.cpp b/common/spdat.cpp index a691d5197..c4086c0ac 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -2843,13 +2843,8 @@ bool BOT_SPELL_TYPES_DETRIMENTAL(uint16 spellType, uint8 cls) { case BotSpellTypes::AELifetap: case BotSpellTypes::PBAENuke: case BotSpellTypes::Lull: + case BotSpellTypes::HateLine: return true; - case BotSpellTypes::InCombatBuff: - if (cls == Class::ShadowKnight) { - return true; - } - - return false; default: return false; } @@ -2898,12 +2893,6 @@ bool BOT_SPELL_TYPES_BENEFICIAL(uint16 spellType, uint8 cls) { case BotSpellTypes::MovementSpeed: case BotSpellTypes::SendHome: case BotSpellTypes::SummonCorpse: - return true; - case BotSpellTypes::InCombatBuff: - if (cls == Class::ShadowKnight) { - return false; - } - return true; default: return false; @@ -3134,12 +3123,7 @@ bool SpellTypeRequiresLoS(uint16 spellType, uint16 cls) { case BotSpellTypes::PetFastHeals: case BotSpellTypes::PetVeryFastHeals: case BotSpellTypes::PetHoTHeals: - return false; case BotSpellTypes::InCombatBuff: - if (cls && cls == Class::ShadowKnight) { - return true; - } - return false; default: return true; @@ -3150,13 +3134,44 @@ bool SpellTypeRequiresLoS(uint16 spellType, uint16 cls) { bool SpellTypeRequiresTarget(uint16 spellType, uint16 cls) { switch (spellType) { - case BotSpellTypes::Escape: - if (cls == Class::ShadowKnight) { - return false; - } - - return true; case BotSpellTypes::Pet: + case BotSpellTypes::Succor: + return false; + default: + return true; + } + + return true; +} + +bool SpellTypeRequiresCastChecks(uint16 spellType) { + switch (spellType) { + case BotSpellTypes::AEDebuff: + case BotSpellTypes::AEDispel: + case BotSpellTypes::AEDoT: + case BotSpellTypes::AEFear: + case BotSpellTypes::AELifetap: + case BotSpellTypes::AEMez: + case BotSpellTypes::AENukes: + case BotSpellTypes::AERains: + case BotSpellTypes::AERoot: + case BotSpellTypes::AESlow: + case BotSpellTypes::AESnare: + case BotSpellTypes::AEStun: + case BotSpellTypes::PBAENuke: + case BotSpellTypes::Mez: + case BotSpellTypes::SummonCorpse: + return false; + default: + return true; + } + + return true; +} + +bool SpellTypeRequiresAEChecks(uint16 spellType) { + switch (spellType) { + case BotSpellTypes::AEMez: return false; default: return true; @@ -3263,6 +3278,10 @@ bool IsDamageShieldOnlySpell(uint16 spell_id) { bool IsCommandedSpellType(uint16 spellType) { switch (spellType) { + case BotSpellTypes::Charm: + case BotSpellTypes::AEFear: + case BotSpellTypes::Fear: + case BotSpellTypes::Resurrect: case BotSpellTypes::Lull: case BotSpellTypes::Teleport: case BotSpellTypes::Succor: @@ -3276,8 +3295,6 @@ bool IsCommandedSpellType(uint16 spellType) { case BotSpellTypes::MovementSpeed: case BotSpellTypes::SendHome: case BotSpellTypes::SummonCorpse: - //case BotSpellTypes::Charm: - //case BotSpellTypes::Resurrect: //case BotSpellTypes::Cure: //case BotSpellTypes::GroupCures: //case BotSpellTypes::DamageShields: diff --git a/common/spdat.h b/common/spdat.h index cefac6784..1c3bcf52c 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -708,6 +708,7 @@ namespace BotSpellTypes constexpr uint16 ResistBuffs = 52; constexpr uint16 PetDamageShields = 53; constexpr uint16 PetResistBuffs = 54; + constexpr uint16 HateLine = 55; // Command Spell Types constexpr uint16 Teleport = 100; // this is handled by ^depart so uses other logic @@ -725,7 +726,7 @@ namespace BotSpellTypes constexpr uint16 SummonCorpse = 112; constexpr uint16 START = BotSpellTypes::Nuke; // Do not remove or change this - constexpr uint16 END = BotSpellTypes::PetResistBuffs; // Do not remove this, increment as needed + constexpr uint16 END = BotSpellTypes::HateLine; // Do not remove this, increment as needed constexpr uint16 COMMANDED_START = BotSpellTypes::Lull; // Do not remove or change this constexpr uint16 COMMANDED_END = BotSpellTypes::SummonCorpse; // Do not remove this, increment as needed } @@ -747,6 +748,8 @@ bool IsClientBotSpellType(uint16 spellType); bool IsHealBotSpellType(uint16 spellType); bool SpellTypeRequiresLoS(uint16 spellType, uint16 cls = 0); bool SpellTypeRequiresTarget(uint16 spellType, uint16 cls = 0); +bool SpellTypeRequiresCastChecks(uint16 spellType); +bool SpellTypeRequiresAEChecks(uint16 spellType); bool IsCommandedSpellType(uint16 spellType); // These should not be used to determine spell category.. diff --git a/zone/bot.cpp b/zone/bot.cpp index 32a70ceb3..b3158ac35 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -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; } diff --git a/zone/bot_commands/cast.cpp b/zone/bot_commands/cast.cpp index 49112b869..10238aac2 100644 --- a/zone/bot_commands/cast.cpp +++ b/zone/bot_commands/cast.cpp @@ -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); diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index 241854dfa..d3123bf86 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -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 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 {} [#{}]" diff --git a/zone/mob.cpp b/zone/mob.cpp index ac435fdb0..ec1e18efc 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -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: diff --git a/zone/spells.cpp b/zone/spells.cpp index a57093ee2..4eb7a9fc5 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -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; }