From 37910cf3dc5222adc4f5d171d9f332ed479ac041 Mon Sep 17 00:00:00 2001 From: nytmyr <53322305+nytmyr@users.noreply.github.com> Date: Tue, 21 Jan 2025 12:25:49 -0600 Subject: [PATCH] Move mob functions to mob_bot --- zone/CMakeLists.txt | 1 + zone/mob.cpp | 768 ------------------------------------------- zone/mob.h | 10 +- zone/mob_bot.cpp | 772 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 777 insertions(+), 774 deletions(-) create mode 100644 zone/mob_bot.cpp diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index 798114399..83963f520 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -98,6 +98,7 @@ SET(zone_sources mob.cpp mob_ai.cpp mob_appearance.cpp + mob_bot.cpp mob_movement_manager.cpp mob_info.cpp npc.cpp diff --git a/zone/mob.cpp b/zone/mob.cpp index 0cf06fbbc..e461fe6c7 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -4822,83 +4822,6 @@ bool Mob::PlotPositionAroundTarget(Mob* target, float &x_dest, float &y_dest, fl return Result; } -bool Mob::PlotBotPositionAroundTarget(Mob* target, float& x_dest, float& y_dest, float& z_dest, float min_distance, float max_distance, bool behind_only, bool front_only, bool bypass_los) { - bool Result = false; - - if (target) { - float look_heading = 0; - - min_distance = min_distance; - max_distance = max_distance; - float temp_x = 0; - float temp_y = 0; - float temp_z = target->GetZ(); - float best_z = 0; - auto offset = GetZOffset(); - const float tar_x = target->GetX(); - const float tar_y = target->GetY(); - float tar_distance = 0; - - glm::vec3 temp_z_Position; - glm::vec4 temp_m_Position; - - const uint16 max_iterations_allowed = 50; - uint16 counter = 0; - - while (counter < max_iterations_allowed) { - temp_x = tar_x + zone->random.Real(-max_distance, max_distance); - temp_y = tar_y + zone->random.Real(-max_distance, max_distance); - - temp_z_Position.x = temp_z; - temp_z_Position.y = temp_y; - temp_z_Position.z = temp_z; - best_z = GetFixedZ(temp_z_Position); - - if (best_z != BEST_Z_INVALID) { - temp_z = best_z; - } - else { - counter++; - continue; - } - - temp_m_Position.x = temp_x; - temp_m_Position.y = temp_y; - temp_m_Position.z = temp_z; - - tar_distance = Distance(target->GetPosition(), temp_m_Position); - - if (tar_distance > max_distance || tar_distance < min_distance) { - counter++; - continue; - } - if (front_only && !InFrontMob(target, temp_x, temp_y)) { - counter++; - continue; - } - else if (behind_only && !BehindMob(target, temp_x, temp_y)) { - counter++; - continue; - } - if (!bypass_los && CastToBot()->RequiresLoSForPositioning() && !CheckPositioningLosFN(target, temp_x, temp_y, temp_z)) { - counter++; - continue; - } - - Result = true; - break; - } - - if (Result) { - x_dest = temp_x; - y_dest = temp_y; - z_dest = temp_z; - } - } - - return Result; -} - bool Mob::HateSummon() { // check if mob has ability to summon // 97% is the offical % that summoning starts on live, not 94 @@ -8690,697 +8613,6 @@ void Mob::CheckScanCloseMobsMovingTimer() } } -std::vector Mob::GatherSpellTargets(bool entire_raid, Mob* target, bool no_clients, bool no_bots, bool no_pets) { - std::vector valid_spell_targets; - - auto is_valid_target = [no_clients, no_bots](Mob* member) { - return member && - ((member->IsClient() && !no_clients) || (member->IsBot() && !no_bots)); - }; - - if (IsRaidGrouped()) { - Raid* raid = IsBot() ? CastToBot()->GetStoredRaid() : GetRaid(); - - if (raid) { - if (entire_raid) { - for (const auto& m : raid->members) { - if (is_valid_target(m.member) && m.group_number != RAID_GROUPLESS) { - valid_spell_targets.emplace_back(m.member); - } - } - } - else { - auto group_name = target ? raid->GetGroup(target->GetName()) : raid->GetGroup(GetName()); - auto raid_group = raid->GetRaidGroupMembers(group_name); - - for (const auto& m : raid_group) { - if (is_valid_target(m.member) && m.group_number != RAID_GROUPLESS) { - valid_spell_targets.emplace_back(m.member); - } - } - } - } - } - else if (IsGrouped()) { - Group* group = GetGroup(); - - if (group) { - for (const auto& m : group->members) { - if (is_valid_target(m)) { - valid_spell_targets.emplace_back(m); - } - } - } - } - else { - valid_spell_targets.emplace_back(this); - } - - return valid_spell_targets; -} - -uint16 Mob::GetSpellTypeIDByShortName(std::string spell_type_string) { - - for (int i = BotSpellTypes::START; i <= BotSpellTypes::END; ++i) { - if (!Strings::ToLower(spell_type_string).compare(GetSpellTypeShortNameByID(i))) { - return i; - } - } - - for (int i = BotSpellTypes::COMMANDED_START; i <= BotSpellTypes::COMMANDED_END; ++i) { - if (!Strings::ToLower(spell_type_string).compare(GetSpellTypeShortNameByID(i))) { - return i; - } - } - - return UINT16_MAX; -} - -bool Mob::IsValidBotSpellCategory(uint8 setting_type) { - return EQ::ValueWithin(setting_type, BotSettingCategories::START, BotSettingCategories::END_FULL); -} - -std::string Mob::GetBotSpellCategoryName(uint8 setting_type) { - return IsValidBotBaseSetting(setting_type) ? botSpellCategory_names[setting_type] : "UNKNOWN CATEGORY"; -} - -uint16 Mob::GetBotSpellCategoryIDByShortName(std::string setting_string) { - for (int i = BotSettingCategories::START; i <= BotSettingCategories::END; ++i) { - if (!Strings::ToLower(setting_string).compare(Strings::ToLower(GetBotSpellCategoryName(i)))) { - return i; - } - } - - return UINT16_MAX; -} - -bool Mob::IsValidBotBaseSetting(uint16 setting_type) { - return EQ::ValueWithin(setting_type, BotBaseSettings::START_ALL, BotBaseSettings::END); -} - -std::string Mob::GetBotSettingCategoryName(uint16 setting_type) { - return IsValidBotBaseSetting(setting_type) ? botBaseSettings_names[setting_type] : "UNKNOWN SETTING"; -} - -uint16 Mob::GetBaseSettingIDByShortName(std::string setting_string) { - for (int i = BotSettingCategories::START; i <= BotSettingCategories::END; ++i) { - if (!Strings::ToLower(setting_string).compare(Strings::ToLower(GetBotSettingCategoryName(i)))) { - return i; - } - } - - return UINT16_MAX; -} - -bool Mob::IsValidSpellType(uint16 spell_type) { - return ( - EQ::ValueWithin(spell_type, BotSpellTypes::START, BotSpellTypes::END) || - EQ::ValueWithin(spell_type, BotSpellTypes::COMMANDED_START, BotSpellTypes::COMMANDED_END) - ); -} - -std::string Mob::GetSpellTypeShortNameByID(uint16 spell_type) { - return IsValidSpellType(spell_type) ? spellType_shortNames[spell_type] : "UNKNOWN SPELLTYPE"; -} - -std::string Mob::GetSpellTypeNameByID(uint16 spell_type) { - return IsValidSpellType(spell_type) ? spellType_names[spell_type] : "UNKNOWN SPELLTYPE"; -} - -bool Mob::IsValidSubType(uint16 sub_type) { - return EQ::ValueWithin(sub_type, CommandedSubTypes::START, CommandedSubTypes::END); -} - -std::string Mob::GetSubTypeNameByID(uint16 sub_type) { - return IsValidSpellType(sub_type) ? botSubType_names[sub_type] : "UNKNOWN SUBTYPE"; -} - -bool Mob::GetDefaultSpellHold(uint16 spell_type, uint8 stance) { - uint8 bot_class = GetClass(); - - switch (spell_type) { - case BotSpellTypes::FastHeals: - case BotSpellTypes::VeryFastHeals: - case BotSpellTypes::Pet: - case BotSpellTypes::Escape: - case BotSpellTypes::Lifetap: - case BotSpellTypes::Buff: - case BotSpellTypes::PetBuffs: - case BotSpellTypes::InCombatBuff: - case BotSpellTypes::PreCombatBuff: - case BotSpellTypes::DamageShields: - case BotSpellTypes::ResistBuffs: - return false; - case BotSpellTypes::GroupCompleteHeals: - case BotSpellTypes::GroupHeals: - case BotSpellTypes::GroupHoTHeals: - case BotSpellTypes::HoTHeals: - case BotSpellTypes::CompleteHeal: - case BotSpellTypes::PetFastHeals: - 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::Cure: - case BotSpellTypes::GroupCures: - switch (stance) { - case Stance::Aggressive: - case Stance::AEBurn: - case Stance::Burn: - return true; - default: - return false; - } - case BotSpellTypes::InCombatBuffSong: - case BotSpellTypes::OutOfCombatBuffSong: - case BotSpellTypes::PreCombatBuffSong: - if (bot_class == Class::Bard) { - return false; - } - else { - return true; - } - case BotSpellTypes::Nuke: - case BotSpellTypes::DOT: - case BotSpellTypes::Stun: - switch (stance) { - case Stance::Assist: - return true; - default: - return false; - } - case BotSpellTypes::AENukes: - case BotSpellTypes::AERains: - case BotSpellTypes::AEStun: - case BotSpellTypes::AEDoT: - case BotSpellTypes::AELifetap: - case BotSpellTypes::PBAENuke: - switch (stance) { - case Stance::AEBurn: - return false; - default: - 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) { - case Stance::AEBurn: - case Stance::Burn: - return true; - default: - return false; - } - case BotSpellTypes::Snare: - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - case Stance::Assist: - return true; - default: - return false; - } - case BotSpellTypes::HateLine: - if (bot_class == Class::ShadowKnight || bot_class == Class::Paladin) { - switch (stance) { - case Stance::Aggressive: - return false; - default: - return true; - } - } - else { - return true; - } - case BotSpellTypes::Charm: - case BotSpellTypes::Resurrect: - case BotSpellTypes::AESnare: - case BotSpellTypes::AERoot: - case BotSpellTypes::Root: - case BotSpellTypes::AEDispel: - case BotSpellTypes::Dispel: - case BotSpellTypes::AEFear: - case BotSpellTypes::Fear: - case BotSpellTypes::AEHateLine: - case BotSpellTypes::PetCures: - case BotSpellTypes::PetHoTHeals: - case BotSpellTypes::PetCompleteHeals: - case BotSpellTypes::PetDamageShields: - case BotSpellTypes::PetResistBuffs: - default: - return true; - } -} - -uint16 Mob::GetDefaultSpellDelay(uint16 spell_type, uint8 stance) { - switch (spell_type) { - case BotSpellTypes::VeryFastHeals: - case BotSpellTypes::PetVeryFastHeals: - return 1500; - case BotSpellTypes::FastHeals: - case BotSpellTypes::PetFastHeals: - return 2500; - case BotSpellTypes::GroupHeals: - case BotSpellTypes::RegularHeal: - case BotSpellTypes::PetRegularHeals: - return 4000; - case BotSpellTypes::CompleteHeal: - case BotSpellTypes::GroupCompleteHeals: - case BotSpellTypes::PetCompleteHeals: - return 8000; - case BotSpellTypes::GroupHoTHeals: - case BotSpellTypes::HoTHeals: - case BotSpellTypes::PetHoTHeals: - return 22000; - case BotSpellTypes::AEDoT: - case BotSpellTypes::DOT: - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - return 1; - case Stance::Aggressive: - return 2000; - case Stance::Efficient: - return 8000; - default: - return 4000; - } - case BotSpellTypes::AENukes: - case BotSpellTypes::AERains: - case BotSpellTypes::PBAENuke: - case BotSpellTypes::Nuke: - case BotSpellTypes::AESnare: - case BotSpellTypes::Snare: - case BotSpellTypes::AEDebuff: - case BotSpellTypes::Debuff: - case BotSpellTypes::AESlow: - case BotSpellTypes::Slow: - case BotSpellTypes::AEStun: - case BotSpellTypes::Stun: - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - return 1; - case Stance::Aggressive: - return 3000; - case Stance::Efficient: - return 10000; - default: - return 6000; - } - case BotSpellTypes::AERoot: - case BotSpellTypes::Root: - return 8000; - case BotSpellTypes::Fear: - case BotSpellTypes::AEFear: - return 15000; - default: - return 1; - } -} - -uint8 Mob::GetDefaultSpellMinThreshold(uint16 spell_type, uint8 stance) { - switch (spell_type) { - case BotSpellTypes::AEDebuff: - case BotSpellTypes::Debuff: - case BotSpellTypes::AEDispel: - case BotSpellTypes::Dispel: - case BotSpellTypes::AESlow: - case BotSpellTypes::Slow: - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - case Stance::Aggressive: - return 0; - default: - return 20; - } - case BotSpellTypes::AENukes: - case BotSpellTypes::AERains: - case BotSpellTypes::PBAENuke: - case BotSpellTypes::Nuke: - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - case Stance::Aggressive: - return 0; - default: - return 5; - } - case BotSpellTypes::AEDoT: - case BotSpellTypes::DOT: - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - case Stance::Aggressive: - return 0; - case Stance::Efficient: - return 40; - default: - return 25; - } - case BotSpellTypes::Mez: - case BotSpellTypes::AEMez: - return 85; - default: - return 0; - } -} - -uint8 Mob::GetDefaultSpellMaxThreshold(uint16 spell_type, uint8 stance) { - uint8 bot_class = GetClass(); - - switch (spell_type) { - case BotSpellTypes::Escape: - case BotSpellTypes::VeryFastHeals: - case BotSpellTypes::PetVeryFastHeals: - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - case Stance::Aggressive: - return 40; - case Stance::Efficient: - default: - return 25; - } - case BotSpellTypes::AELifetap: - case BotSpellTypes::Lifetap: - case BotSpellTypes::FastHeals: - case BotSpellTypes::PetFastHeals: - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - case Stance::Aggressive: - return 55; - case Stance::Efficient: - return 35; - default: - return 40; - } - case BotSpellTypes::GroupHeals: - case BotSpellTypes::RegularHeal: - case BotSpellTypes::PetRegularHeals: - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - case Stance::Aggressive: - return 70; - case Stance::Efficient: - return 50; - default: - return 60; - } - case BotSpellTypes::CompleteHeal: - case BotSpellTypes::GroupCompleteHeals: - case BotSpellTypes::PetCompleteHeals: - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - case Stance::Aggressive: - return 90; - case Stance::Efficient: - return 65; - default: - return 80; - } - case BotSpellTypes::AENukes: - case BotSpellTypes::AERains: - case BotSpellTypes::PBAENuke: - case BotSpellTypes::AEStun: - case BotSpellTypes::Nuke: - case BotSpellTypes::AEDoT: - case BotSpellTypes::DOT: - case BotSpellTypes::AERoot: - case BotSpellTypes::Root: - case BotSpellTypes::AESlow: - case BotSpellTypes::Slow: - case BotSpellTypes::AESnare: - case BotSpellTypes::Snare: - case BotSpellTypes::AEFear: - case BotSpellTypes::Fear: - case BotSpellTypes::AEDispel: - case BotSpellTypes::Dispel: - case BotSpellTypes::AEDebuff: - case BotSpellTypes::Debuff: - case BotSpellTypes::Stun: - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - return 100; - case Stance::Aggressive: - return 100; - case Stance::Efficient: - return 90; - default: - return 99; - } - case BotSpellTypes::GroupHoTHeals: - case BotSpellTypes::HoTHeals: - case BotSpellTypes::PetHoTHeals: - if (bot_class == Class::Necromancer || bot_class == Class::Shaman) { - return 60; - } - else { - switch (stance) { - case Stance::AEBurn: - case Stance::Burn: - case Stance::Aggressive: - return 95; - case Stance::Efficient: - return 80; - default: - return 90; - } - } - case BotSpellTypes::Buff: - case BotSpellTypes::Charm: - case BotSpellTypes::Cure: - case BotSpellTypes::GroupCures: - case BotSpellTypes::PetCures: - case BotSpellTypes::DamageShields: - case BotSpellTypes::HateRedux: - case BotSpellTypes::InCombatBuff: - case BotSpellTypes::InCombatBuffSong: - case BotSpellTypes::Mez: - case BotSpellTypes::AEMez: - case BotSpellTypes::OutOfCombatBuffSong: - case BotSpellTypes::Pet: - case BotSpellTypes::PetBuffs: - case BotSpellTypes::PreCombatBuff: - case BotSpellTypes::PreCombatBuffSong: - case BotSpellTypes::PetDamageShields: - case BotSpellTypes::PetResistBuffs: - case BotSpellTypes::ResistBuffs: - case BotSpellTypes::Resurrect: - case BotSpellTypes::HateLine: - case BotSpellTypes::AEHateLine: - default: - return 100; - } -} - -void Mob::SetSpellHold(uint16 spell_type, bool hold_status) { - m_bot_spell_settings[spell_type].hold = hold_status; -} - -void Mob::SetSpellDelay(uint16 spell_type, uint16 delay_value) { - m_bot_spell_settings[spell_type].delay = delay_value; -} - -void Mob::SetSpellMinThreshold(uint16 spell_type, uint8 threshold_value) { - m_bot_spell_settings[spell_type].minThreshold = threshold_value; -} - -void Mob::SetSpellMaxThreshold(uint16 spell_type, uint8 threshold_value) { - m_bot_spell_settings[spell_type].maxThreshold = threshold_value; -} - -void Mob::SetSpellTypeRecastTimer(uint16 spell_type, uint32 recast_time) { - m_bot_spell_settings[spell_type].recastTimer.Start(recast_time); -} - -void Mob::StartBotSpellTimers() { - for (uint16 i = BotSpellTypes::START; i <= BotSpellTypes::END; ++i) { - m_bot_spell_settings[i].recastTimer.Start(); - } -} - -void Mob::DisableBotSpellTimers() { - for (uint16 i = BotSpellTypes::START; i <= BotSpellTypes::END; ++i) { - m_bot_spell_settings[i].recastTimer.Disable(); - } -} - -bool Mob::GetUltimateSpellHold(uint16 spell_type, Mob* tar) { - if (!tar) { - return GetSpellHold(spell_type); - } - - if (tar->IsPet() && tar->GetOwner() && tar->GetOwner()->IsOfClientBot()) { - return tar->GetOwner()->GetSpellHold(GetPetSpellType(spell_type)); - } - - return GetSpellHold(spell_type); -} - -uint16 Mob::GetUltimateSpellDelay(uint16 spell_type, Mob* tar) { - if (!tar) { - return GetSpellDelay(spell_type); - } - - if (tar->IsPet() && tar->GetOwner() && tar->GetOwner()->IsOfClientBot()) { - return tar->GetOwner()->GetSpellDelay(GetPetSpellType(spell_type)); - } - - if (IsBotSpellTypeOtherBeneficial(spell_type) && tar->IsOfClientBot()) { - return tar->GetSpellDelay(spell_type); - } - - return GetSpellDelay(spell_type); -} - -bool Mob::GetUltimateSpellDelayCheck(uint16 spell_type, Mob* tar) { - if (!tar) { - return SpellTypeRecastCheck(spell_type); - } - - if (tar->IsPet() && tar->GetOwner() && tar->GetOwner()->IsOfClientBot()) { - return tar->GetOwner()->SpellTypeRecastCheck(GetPetSpellType(spell_type)); - } - - if (IsBotSpellTypeOtherBeneficial(spell_type) && tar->IsOfClientBot()) { - return tar->SpellTypeRecastCheck(spell_type); - } - - return SpellTypeRecastCheck(spell_type); -} - -uint8 Mob::GetUltimateSpellMinThreshold(uint16 spell_type, Mob* tar) { - if (!tar) { - return GetSpellMinThreshold(spell_type); - } - - if (tar->IsPet() && tar->GetOwner() && tar->GetOwner()->IsOfClientBot()) { - return tar->GetOwner()->GetSpellMinThreshold(GetPetSpellType(spell_type)); - } - - if (IsBotSpellTypeOtherBeneficial(spell_type) && tar->IsOfClientBot()) { - return tar->GetSpellMinThreshold(spell_type); - } - - return GetSpellMinThreshold(spell_type); -} - -uint8 Mob::GetUltimateSpellMaxThreshold(uint16 spell_type, Mob* tar) { - if (!tar) { - return GetSpellMaxThreshold(spell_type); - } - - if (tar->IsPet() && tar->GetOwner() && tar->GetOwner()->IsOfClientBot()) { - return tar->GetOwner()->GetSpellMaxThreshold(GetPetSpellType(spell_type)); - } - - if (IsBotSpellTypeOtherBeneficial(spell_type) && tar->IsOfClientBot()) { - return tar->GetSpellMaxThreshold(spell_type); - } - - return GetSpellMaxThreshold(spell_type); -} - -uint16 Mob::GetPetSpellType(uint16 spell_type) { - switch (spell_type) { - case BotSpellTypes::VeryFastHeals: - return BotSpellTypes::PetVeryFastHeals; - case BotSpellTypes::FastHeals: - return BotSpellTypes::PetFastHeals; - case BotSpellTypes::RegularHeal: - return BotSpellTypes::PetRegularHeals; - case BotSpellTypes::CompleteHeal: - return BotSpellTypes::PetCompleteHeals; - case BotSpellTypes::HoTHeals: - return BotSpellTypes::PetHoTHeals; - case BotSpellTypes::Buff: - return BotSpellTypes::PetBuffs; - case BotSpellTypes::Cure: - return BotSpellTypes::PetCures; - case BotSpellTypes::DamageShields: - return BotSpellTypes::PetDamageShields; - case BotSpellTypes::ResistBuffs: - return BotSpellTypes::PetResistBuffs; - default: - break; - } - - return spell_type; -} - -uint8 Mob::GetHPRatioForSpellType(uint16 spell_type, Mob* tar) { - switch (spell_type) { - case BotSpellTypes::Escape: - case BotSpellTypes::HateRedux: - case BotSpellTypes::InCombatBuff: - case BotSpellTypes::InCombatBuffSong: - case BotSpellTypes::AELifetap: - case BotSpellTypes::Lifetap: - case BotSpellTypes::OutOfCombatBuffSong: - case BotSpellTypes::Pet: - case BotSpellTypes::PreCombatBuff: - case BotSpellTypes::PreCombatBuffSong: - return GetHPRatio(); - default: - return tar->GetHPRatio(); - } - - return tar->GetHPRatio(); -} - -void Mob::SetBotSetting(uint8 setting_type, uint16 bot_setting, int setting_value) { - if (!IsOfClientBot()) { - return; - } - - if (IsClient()) { - CastToClient()->SetBotSetting(setting_type, bot_setting, setting_value); - return; - } - - if (IsBot()) { - CastToBot()->SetBotSetting(setting_type, bot_setting, setting_value); - return; - } - - return; -} - -void Mob::SetBaseSetting(uint16 base_setting, int setting_value) { - switch (base_setting) { - case BotBaseSettings::IllusionBlock: - SetIllusionBlock(setting_value); - break; - default: - break; - } -} - -bool Mob::TargetValidation(Mob* other) { - if (!other || GetAppearance() == eaDead) { - return false; - } - - return true; -} - std::unordered_map& Mob::GetCloseMobList(float distance) { return entity_list.GetCloseMobList(this, distance); diff --git a/zone/mob.h b/zone/mob.h index b092e3f54..ed358e79e 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -428,14 +428,12 @@ public: virtual bool CheckSpellLevelRestriction(Mob *caster, uint16 spell_id); virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster); + // Bot functions + bool PlotBotPositionAroundTarget(Mob* target, float& x_dest, float& y_dest, float& z_dest, float min_distance, float max_distance, bool behind_only = false, bool front_only = false, bool bypass_los = false); virtual bool IsImmuneToBotSpell(uint16 spell_id, Mob* caster); - - inline bool SpellTypeRecastCheck(uint16 spellType) { return (IsClient() ? true : m_bot_spell_settings[spellType].recastTimer.GetRemainingTime() > 0 ? false : true); } - std::vector GatherSpellTargets(bool entireRaid = false, Mob* target = nullptr, bool no_clients = false, bool no_bots = false, bool no_pets = false); - + inline bool SpellTypeRecastCheck(uint16 spellType) { return (IsClient () ? true : m_bot_spell_settings [spellType].recastTimer.GetRemainingTime () > 0 ? false : true); } uint16 GetSpellTypeIDByShortName(std::string spellType_string); - bool IsValidBotSpellCategory(uint8 setting_type); std::string GetBotSpellCategoryName(uint8 setting_type); uint16 GetBotSpellCategoryIDByShortName(std::string setting_string); @@ -940,7 +938,7 @@ public: void ShowStats(Client* client); void ShowBuffs(Client* c); bool PlotPositionAroundTarget(Mob* target, float &x_dest, float &y_dest, float &z_dest, bool lookForAftArc = true); - bool PlotBotPositionAroundTarget(Mob* target, float& x_dest, float& y_dest, float& z_dest, float min_distance, float max_distance, bool behind_only = false, bool front_only = false, bool bypass_los = false); + virtual int GetKillExpMod() const { return 100; } // aura functions diff --git a/zone/mob_bot.cpp b/zone/mob_bot.cpp new file mode 100644 index 000000000..4dafd4935 --- /dev/null +++ b/zone/mob_bot.cpp @@ -0,0 +1,772 @@ +#include "bot.h" +#include "mob.h" + +bool Mob::PlotBotPositionAroundTarget(Mob* target, float& x_dest, float& y_dest, float& z_dest, float min_distance, float max_distance, bool behind_only, bool front_only, bool bypass_los) { + bool Result = false; + + if (target) { + float look_heading = 0; + + min_distance = min_distance; + max_distance = max_distance; + float temp_x = 0; + float temp_y = 0; + float temp_z = target->GetZ(); + float best_z = 0; + auto offset = GetZOffset(); + const float tar_x = target->GetX(); + const float tar_y = target->GetY(); + float tar_distance = 0; + + glm::vec3 temp_z_Position; + glm::vec4 temp_m_Position; + + const uint16 max_iterations_allowed = 50; + uint16 counter = 0; + + while (counter < max_iterations_allowed) { + temp_x = tar_x + zone->random.Real(-max_distance, max_distance); + temp_y = tar_y + zone->random.Real(-max_distance, max_distance); + + temp_z_Position.x = temp_z; + temp_z_Position.y = temp_y; + temp_z_Position.z = temp_z; + best_z = GetFixedZ(temp_z_Position); + + if (best_z != BEST_Z_INVALID) { + temp_z = best_z; + } + else { + counter++; + continue; + } + + temp_m_Position.x = temp_x; + temp_m_Position.y = temp_y; + temp_m_Position.z = temp_z; + + tar_distance = Distance(target->GetPosition(), temp_m_Position); + + if (tar_distance > max_distance || tar_distance < min_distance) { + counter++; + continue; + } + + if (front_only && !InFrontMob(target, temp_x, temp_y)) { + counter++; + continue; + } + else if (behind_only && !BehindMob(target, temp_x, temp_y)) { + counter++; + continue; + } + + if (!bypass_los && CastToBot()->RequiresLoSForPositioning() && !CheckPositioningLosFN(target, temp_x, temp_y, temp_z)) { + counter++; + continue; + } + + Result = true; + break; + } + + if (Result) { + x_dest = temp_x; + y_dest = temp_y; + z_dest = temp_z; + } + } + + return Result; +} + +std::vector Mob::GatherSpellTargets(bool entire_raid, Mob* target, bool no_clients, bool no_bots, bool no_pets) { + std::vector valid_spell_targets; + + auto is_valid_target = [no_clients, no_bots](Mob* member) { + return member && + ((member->IsClient() && !no_clients) || (member->IsBot() && !no_bots)); + }; + + if (IsRaidGrouped()) { + Raid* raid = IsBot() ? CastToBot()->GetStoredRaid() : GetRaid(); + + if (raid) { + if (entire_raid) { + for (const auto& m : raid->members) { + if (is_valid_target(m.member) && m.group_number != RAID_GROUPLESS) { + valid_spell_targets.emplace_back(m.member); + } + } + } + else { + auto group_name = target ? raid->GetGroup(target->GetName()) : raid->GetGroup(GetName()); + auto raid_group = raid->GetRaidGroupMembers(group_name); + + for (const auto& m : raid_group) { + if (is_valid_target(m.member) && m.group_number != RAID_GROUPLESS) { + valid_spell_targets.emplace_back(m.member); + } + } + } + } + } + else if (IsGrouped()) { + Group* group = GetGroup(); + + if (group) { + for (const auto& m : group->members) { + if (is_valid_target(m)) { + valid_spell_targets.emplace_back(m); + } + } + } + } + else { + valid_spell_targets.emplace_back(this); + } + + return valid_spell_targets; +} + +uint16 Mob::GetSpellTypeIDByShortName(std::string spell_type_string) { + + for (int i = BotSpellTypes::START; i <= BotSpellTypes::END; ++i) { + if (!Strings::ToLower(spell_type_string).compare(GetSpellTypeShortNameByID(i))) { + return i; + } + } + + for (int i = BotSpellTypes::COMMANDED_START; i <= BotSpellTypes::COMMANDED_END; ++i) { + if (!Strings::ToLower(spell_type_string).compare(GetSpellTypeShortNameByID(i))) { + return i; + } + } + + return UINT16_MAX; +} + +bool Mob::IsValidBotSpellCategory(uint8 setting_type) { + return EQ::ValueWithin(setting_type, BotSettingCategories::START, BotSettingCategories::END_FULL); +} + +std::string Mob::GetBotSpellCategoryName(uint8 setting_type) { + return IsValidBotBaseSetting(setting_type) ? botSpellCategory_names[setting_type] : "UNKNOWN CATEGORY"; +} + +uint16 Mob::GetBotSpellCategoryIDByShortName(std::string setting_string) { + for (int i = BotSettingCategories::START; i <= BotSettingCategories::END; ++i) { + if (!Strings::ToLower(setting_string).compare(Strings::ToLower(GetBotSpellCategoryName(i)))) { + return i; + } + } + + return UINT16_MAX; +} + +bool Mob::IsValidBotBaseSetting(uint16 setting_type) { + return EQ::ValueWithin(setting_type, BotBaseSettings::START_ALL, BotBaseSettings::END); +} + +std::string Mob::GetBotSettingCategoryName(uint16 setting_type) { + return IsValidBotBaseSetting(setting_type) ? botBaseSettings_names[setting_type] : "UNKNOWN SETTING"; +} + +uint16 Mob::GetBaseSettingIDByShortName(std::string setting_string) { + for (int i = BotSettingCategories::START; i <= BotSettingCategories::END; ++i) { + if (!Strings::ToLower(setting_string).compare(Strings::ToLower(GetBotSettingCategoryName(i)))) { + return i; + } + } + + return UINT16_MAX; +} + +bool Mob::IsValidSpellType(uint16 spell_type) { + return ( + EQ::ValueWithin(spell_type, BotSpellTypes::START, BotSpellTypes::END) || + EQ::ValueWithin(spell_type, BotSpellTypes::COMMANDED_START, BotSpellTypes::COMMANDED_END) + ); +} + +std::string Mob::GetSpellTypeShortNameByID(uint16 spell_type) { + return IsValidSpellType(spell_type) ? spellType_shortNames[spell_type] : "UNKNOWN SPELLTYPE"; +} + +std::string Mob::GetSpellTypeNameByID(uint16 spell_type) { + return IsValidSpellType(spell_type) ? spellType_names[spell_type] : "UNKNOWN SPELLTYPE"; +} + +bool Mob::IsValidSubType(uint16 sub_type) { + return EQ::ValueWithin(sub_type, CommandedSubTypes::START, CommandedSubTypes::END); +} + +std::string Mob::GetSubTypeNameByID(uint16 sub_type) { + return IsValidSpellType(sub_type) ? botSubType_names[sub_type] : "UNKNOWN SUBTYPE"; +} + +bool Mob::GetDefaultSpellHold(uint16 spell_type, uint8 stance) { + uint8 bot_class = GetClass(); + + switch (spell_type) { + case BotSpellTypes::FastHeals: + case BotSpellTypes::VeryFastHeals: + case BotSpellTypes::Pet: + case BotSpellTypes::Escape: + case BotSpellTypes::Lifetap: + case BotSpellTypes::Buff: + case BotSpellTypes::PetBuffs: + case BotSpellTypes::InCombatBuff: + case BotSpellTypes::PreCombatBuff: + case BotSpellTypes::DamageShields: + case BotSpellTypes::ResistBuffs: + return false; + case BotSpellTypes::GroupCompleteHeals: + case BotSpellTypes::GroupHeals: + case BotSpellTypes::GroupHoTHeals: + case BotSpellTypes::HoTHeals: + case BotSpellTypes::CompleteHeal: + case BotSpellTypes::PetFastHeals: + 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::Cure: + case BotSpellTypes::GroupCures: + switch (stance) { + case Stance::Aggressive: + case Stance::AEBurn: + case Stance::Burn: + return true; + default: + return false; + } + case BotSpellTypes::InCombatBuffSong: + case BotSpellTypes::OutOfCombatBuffSong: + case BotSpellTypes::PreCombatBuffSong: + if (bot_class == Class::Bard) { + return false; + } + else { + return true; + } + case BotSpellTypes::Nuke: + case BotSpellTypes::DOT: + case BotSpellTypes::Stun: + switch (stance) { + case Stance::Assist: + return true; + default: + return false; + } + case BotSpellTypes::AENukes: + case BotSpellTypes::AERains: + case BotSpellTypes::AEStun: + case BotSpellTypes::AEDoT: + case BotSpellTypes::AELifetap: + case BotSpellTypes::PBAENuke: + switch (stance) { + case Stance::AEBurn: + return false; + default: + 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) { + case Stance::AEBurn: + case Stance::Burn: + return true; + default: + return false; + } + case BotSpellTypes::Snare: + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + case Stance::Assist: + return true; + default: + return false; + } + case BotSpellTypes::HateLine: + if (bot_class == Class::ShadowKnight || bot_class == Class::Paladin) { + switch (stance) { + case Stance::Aggressive: + return false; + default: + return true; + } + } + else { + return true; + } + case BotSpellTypes::Charm: + case BotSpellTypes::Resurrect: + case BotSpellTypes::AESnare: + case BotSpellTypes::AERoot: + case BotSpellTypes::Root: + case BotSpellTypes::AEDispel: + case BotSpellTypes::Dispel: + case BotSpellTypes::AEFear: + case BotSpellTypes::Fear: + case BotSpellTypes::AEHateLine: + case BotSpellTypes::PetCures: + case BotSpellTypes::PetHoTHeals: + case BotSpellTypes::PetCompleteHeals: + case BotSpellTypes::PetDamageShields: + case BotSpellTypes::PetResistBuffs: + default: + return true; + } +} + +uint16 Mob::GetDefaultSpellDelay(uint16 spell_type, uint8 stance) { + switch (spell_type) { + case BotSpellTypes::VeryFastHeals: + case BotSpellTypes::PetVeryFastHeals: + return 1500; + case BotSpellTypes::FastHeals: + case BotSpellTypes::PetFastHeals: + return 2500; + case BotSpellTypes::GroupHeals: + case BotSpellTypes::RegularHeal: + case BotSpellTypes::PetRegularHeals: + return 4000; + case BotSpellTypes::CompleteHeal: + case BotSpellTypes::GroupCompleteHeals: + case BotSpellTypes::PetCompleteHeals: + return 8000; + case BotSpellTypes::GroupHoTHeals: + case BotSpellTypes::HoTHeals: + case BotSpellTypes::PetHoTHeals: + return 22000; + case BotSpellTypes::AEDoT: + case BotSpellTypes::DOT: + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + return 1; + case Stance::Aggressive: + return 2000; + case Stance::Efficient: + return 8000; + default: + return 4000; + } + case BotSpellTypes::AENukes: + case BotSpellTypes::AERains: + case BotSpellTypes::PBAENuke: + case BotSpellTypes::Nuke: + case BotSpellTypes::AESnare: + case BotSpellTypes::Snare: + case BotSpellTypes::AEDebuff: + case BotSpellTypes::Debuff: + case BotSpellTypes::AESlow: + case BotSpellTypes::Slow: + case BotSpellTypes::AEStun: + case BotSpellTypes::Stun: + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + return 1; + case Stance::Aggressive: + return 3000; + case Stance::Efficient: + return 10000; + default: + return 6000; + } + case BotSpellTypes::AERoot: + case BotSpellTypes::Root: + return 8000; + case BotSpellTypes::Fear: + case BotSpellTypes::AEFear: + return 15000; + default: + return 1; + } +} + +uint8 Mob::GetDefaultSpellMinThreshold(uint16 spell_type, uint8 stance) { + switch (spell_type) { + case BotSpellTypes::AEDebuff: + case BotSpellTypes::Debuff: + case BotSpellTypes::AEDispel: + case BotSpellTypes::Dispel: + case BotSpellTypes::AESlow: + case BotSpellTypes::Slow: + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + case Stance::Aggressive: + return 0; + default: + return 20; + } + case BotSpellTypes::AENukes: + case BotSpellTypes::AERains: + case BotSpellTypes::PBAENuke: + case BotSpellTypes::Nuke: + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + case Stance::Aggressive: + return 0; + default: + return 5; + } + case BotSpellTypes::AEDoT: + case BotSpellTypes::DOT: + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + case Stance::Aggressive: + return 0; + case Stance::Efficient: + return 40; + default: + return 25; + } + case BotSpellTypes::Mez: + case BotSpellTypes::AEMez: + return 85; + default: + return 0; + } +} + +uint8 Mob::GetDefaultSpellMaxThreshold(uint16 spell_type, uint8 stance) { + uint8 bot_class = GetClass(); + + switch (spell_type) { + case BotSpellTypes::Escape: + case BotSpellTypes::VeryFastHeals: + case BotSpellTypes::PetVeryFastHeals: + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + case Stance::Aggressive: + return 40; + case Stance::Efficient: + default: + return 25; + } + case BotSpellTypes::AELifetap: + case BotSpellTypes::Lifetap: + case BotSpellTypes::FastHeals: + case BotSpellTypes::PetFastHeals: + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + case Stance::Aggressive: + return 55; + case Stance::Efficient: + return 35; + default: + return 40; + } + case BotSpellTypes::GroupHeals: + case BotSpellTypes::RegularHeal: + case BotSpellTypes::PetRegularHeals: + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + case Stance::Aggressive: + return 70; + case Stance::Efficient: + return 50; + default: + return 60; + } + case BotSpellTypes::CompleteHeal: + case BotSpellTypes::GroupCompleteHeals: + case BotSpellTypes::PetCompleteHeals: + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + case Stance::Aggressive: + return 90; + case Stance::Efficient: + return 65; + default: + return 80; + } + case BotSpellTypes::AENukes: + case BotSpellTypes::AERains: + case BotSpellTypes::PBAENuke: + case BotSpellTypes::AEStun: + case BotSpellTypes::Nuke: + case BotSpellTypes::AEDoT: + case BotSpellTypes::DOT: + case BotSpellTypes::AERoot: + case BotSpellTypes::Root: + case BotSpellTypes::AESlow: + case BotSpellTypes::Slow: + case BotSpellTypes::AESnare: + case BotSpellTypes::Snare: + case BotSpellTypes::AEFear: + case BotSpellTypes::Fear: + case BotSpellTypes::AEDispel: + case BotSpellTypes::Dispel: + case BotSpellTypes::AEDebuff: + case BotSpellTypes::Debuff: + case BotSpellTypes::Stun: + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + return 100; + case Stance::Aggressive: + return 100; + case Stance::Efficient: + return 90; + default: + return 99; + } + case BotSpellTypes::GroupHoTHeals: + case BotSpellTypes::HoTHeals: + case BotSpellTypes::PetHoTHeals: + if (bot_class == Class::Necromancer || bot_class == Class::Shaman) { + return 60; + } + else { + switch (stance) { + case Stance::AEBurn: + case Stance::Burn: + case Stance::Aggressive: + return 95; + case Stance::Efficient: + return 80; + default: + return 90; + } + } + case BotSpellTypes::Buff: + case BotSpellTypes::Charm: + case BotSpellTypes::Cure: + case BotSpellTypes::GroupCures: + case BotSpellTypes::PetCures: + case BotSpellTypes::DamageShields: + case BotSpellTypes::HateRedux: + case BotSpellTypes::InCombatBuff: + case BotSpellTypes::InCombatBuffSong: + case BotSpellTypes::Mez: + case BotSpellTypes::AEMez: + case BotSpellTypes::OutOfCombatBuffSong: + case BotSpellTypes::Pet: + case BotSpellTypes::PetBuffs: + case BotSpellTypes::PreCombatBuff: + case BotSpellTypes::PreCombatBuffSong: + case BotSpellTypes::PetDamageShields: + case BotSpellTypes::PetResistBuffs: + case BotSpellTypes::ResistBuffs: + case BotSpellTypes::Resurrect: + case BotSpellTypes::HateLine: + case BotSpellTypes::AEHateLine: + default: + return 100; + } +} + +void Mob::SetSpellHold(uint16 spell_type, bool hold_status) { + m_bot_spell_settings[spell_type].hold = hold_status; +} + +void Mob::SetSpellDelay(uint16 spell_type, uint16 delay_value) { + m_bot_spell_settings[spell_type].delay = delay_value; +} + +void Mob::SetSpellMinThreshold(uint16 spell_type, uint8 threshold_value) { + m_bot_spell_settings[spell_type].minThreshold = threshold_value; +} + +void Mob::SetSpellMaxThreshold(uint16 spell_type, uint8 threshold_value) { + m_bot_spell_settings[spell_type].maxThreshold = threshold_value; +} + +void Mob::SetSpellTypeRecastTimer(uint16 spell_type, uint32 recast_time) { + m_bot_spell_settings[spell_type].recastTimer.Start(recast_time); +} + +void Mob::StartBotSpellTimers() { + for (uint16 i = BotSpellTypes::START; i <= BotSpellTypes::END; ++i) { + m_bot_spell_settings[i].recastTimer.Start(); + } +} + +void Mob::DisableBotSpellTimers() { + for (uint16 i = BotSpellTypes::START; i <= BotSpellTypes::END; ++i) { + m_bot_spell_settings[i].recastTimer.Disable(); + } +} + +bool Mob::GetUltimateSpellHold(uint16 spell_type, Mob* tar) { + if (!tar) { + return GetSpellHold(spell_type); + } + + if (tar->IsPet() && tar->GetOwner() && tar->GetOwner()->IsOfClientBot()) { + return tar->GetOwner()->GetSpellHold(GetPetSpellType(spell_type)); + } + + return GetSpellHold(spell_type); +} + +uint16 Mob::GetUltimateSpellDelay(uint16 spell_type, Mob* tar) { + if (!tar) { + return GetSpellDelay(spell_type); + } + + if (tar->IsPet() && tar->GetOwner() && tar->GetOwner()->IsOfClientBot()) { + return tar->GetOwner()->GetSpellDelay(GetPetSpellType(spell_type)); + } + + if (IsBotSpellTypeOtherBeneficial(spell_type) && tar->IsOfClientBot()) { + return tar->GetSpellDelay(spell_type); + } + + return GetSpellDelay(spell_type); +} + +bool Mob::GetUltimateSpellDelayCheck(uint16 spell_type, Mob* tar) { + if (!tar) { + return SpellTypeRecastCheck(spell_type); + } + + if (tar->IsPet() && tar->GetOwner() && tar->GetOwner()->IsOfClientBot()) { + return tar->GetOwner()->SpellTypeRecastCheck(GetPetSpellType(spell_type)); + } + + if (IsBotSpellTypeOtherBeneficial(spell_type) && tar->IsOfClientBot()) { + return tar->SpellTypeRecastCheck(spell_type); + } + + return SpellTypeRecastCheck(spell_type); +} + +uint8 Mob::GetUltimateSpellMinThreshold(uint16 spell_type, Mob* tar) { + if (!tar) { + return GetSpellMinThreshold(spell_type); + } + + if (tar->IsPet() && tar->GetOwner() && tar->GetOwner()->IsOfClientBot()) { + return tar->GetOwner()->GetSpellMinThreshold(GetPetSpellType(spell_type)); + } + + if (IsBotSpellTypeOtherBeneficial(spell_type) && tar->IsOfClientBot()) { + return tar->GetSpellMinThreshold(spell_type); + } + + return GetSpellMinThreshold(spell_type); +} + +uint8 Mob::GetUltimateSpellMaxThreshold(uint16 spell_type, Mob* tar) { + if (!tar) { + return GetSpellMaxThreshold(spell_type); + } + + if (tar->IsPet() && tar->GetOwner() && tar->GetOwner()->IsOfClientBot()) { + return tar->GetOwner()->GetSpellMaxThreshold(GetPetSpellType(spell_type)); + } + + if (IsBotSpellTypeOtherBeneficial(spell_type) && tar->IsOfClientBot()) { + return tar->GetSpellMaxThreshold(spell_type); + } + + return GetSpellMaxThreshold(spell_type); +} + +uint16 Mob::GetPetSpellType(uint16 spell_type) { + switch (spell_type) { + case BotSpellTypes::VeryFastHeals: + return BotSpellTypes::PetVeryFastHeals; + case BotSpellTypes::FastHeals: + return BotSpellTypes::PetFastHeals; + case BotSpellTypes::RegularHeal: + return BotSpellTypes::PetRegularHeals; + case BotSpellTypes::CompleteHeal: + return BotSpellTypes::PetCompleteHeals; + case BotSpellTypes::HoTHeals: + return BotSpellTypes::PetHoTHeals; + case BotSpellTypes::Buff: + return BotSpellTypes::PetBuffs; + case BotSpellTypes::Cure: + return BotSpellTypes::PetCures; + case BotSpellTypes::DamageShields: + return BotSpellTypes::PetDamageShields; + case BotSpellTypes::ResistBuffs: + return BotSpellTypes::PetResistBuffs; + default: + break; + } + + return spell_type; +} + +uint8 Mob::GetHPRatioForSpellType(uint16 spell_type, Mob* tar) { + switch (spell_type) { + case BotSpellTypes::Escape: + case BotSpellTypes::HateRedux: + case BotSpellTypes::InCombatBuff: + case BotSpellTypes::InCombatBuffSong: + case BotSpellTypes::AELifetap: + case BotSpellTypes::Lifetap: + case BotSpellTypes::OutOfCombatBuffSong: + case BotSpellTypes::Pet: + case BotSpellTypes::PreCombatBuff: + case BotSpellTypes::PreCombatBuffSong: + return GetHPRatio(); + default: + return tar->GetHPRatio(); + } + + return tar->GetHPRatio(); +} + +void Mob::SetBotSetting(uint8 setting_type, uint16 bot_setting, int setting_value) { + if (!IsOfClientBot()) { + return; + } + + if (IsClient()) { + CastToClient()->SetBotSetting(setting_type, bot_setting, setting_value); + return; + } + + if (IsBot()) { + CastToBot()->SetBotSetting(setting_type, bot_setting, setting_value); + return; + } + + return; +} + +void Mob::SetBaseSetting(uint16 base_setting, int setting_value) { + switch (base_setting) { + case BotBaseSettings::IllusionBlock: + SetIllusionBlock(setting_value); + break; + default: + break; + } +} + +bool Mob::TargetValidation(Mob* other) { + if (!other || GetAppearance() == eaDead) { + return false; + } + + return true; +}