From 94c17f941c78d445a3f48aa86d9cf974b76f2c71 Mon Sep 17 00:00:00 2001 From: Uleat Date: Sat, 6 Oct 2018 23:23:29 -0400 Subject: [PATCH] Fixed a few bot issues... --- changelog.txt | 6 +++++ zone/bot.cpp | 19 +++++++++++--- zone/bot.h | 3 +++ zone/hate_list.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++ zone/hate_list.h | 2 ++ 5 files changed, 89 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7ba6c61c9..da28bf394 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,11 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 10/06/2018 == +Uleat: Fixed a few bot issues.. + - Fix for bot 'stop melee level' not honoring setting level over rule level + - Fix for missing bot combat spell casting when within melee range + - Fix (in-work) for bots 'forgetting' current target when it flees + == 07/10/2018 == Akkadius: Adjusted DataBuckets to use other acceptable time formats Example: quest::set_data('key', 'value', '1d'); diff --git a/zone/bot.cpp b/zone/bot.cpp index a5dd4aa41..b2fac55e4 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -2261,10 +2261,15 @@ void Bot::AI_Process() { } if (find_target) { - if (IsRooted()) + if (IsRooted()) { SetTarget(hate_list.GetClosestEntOnHateList(this)); - else - SetTarget(hate_list.GetEntWithMostHateOnList(this)); + } + else { + // This will keep bots on target for now..but, future updates will allow for rooting/stunning + SetTarget(hate_list.GetEscapingEntOnHateList(leash_owner, BOT_LEASH_DISTANCE)); + if (!GetTarget()) + SetTarget(hate_list.GetEntWithMostHateOnList(this)); + } } TEST_TARGET(); @@ -2471,6 +2476,8 @@ void Bot::AI_Process() { ChangeBotArcherWeapons(IsBotArcher()); } + // all of this needs review... + if (IsBotArcher() && atArcheryRange) atCombatRange = true; else if (caster_distance_max && tar_distance <= caster_distance_max) @@ -2567,6 +2574,10 @@ void Bot::AI_Process() { } } + if (!IsBotNonSpellFighter() && AI_EngagedCastCheck()) { + return; + } + // Up to this point, GetTarget() has been safe to dereference since the initial // TEST_TARGET() call. Due to the chance of the target dying and our pointer // being nullified, we need to test it before dereferencing to avoid crashes @@ -2576,7 +2587,7 @@ void Bot::AI_Process() { if (GetTarget()->GetHPRatio() <= 99.0f) BotRangedAttack(tar); } - else if (!IsBotArcher() && (!(IsBotCaster() && GetLevel() >= RuleI(Bots, CasterStopMeleeLevel)))) { + else if (!IsBotArcher() && (IsBotNonSpellFighter() || GetLevel() < GetStopMeleeLevel())) { // we can't fight if we don't have a target, are stun/mezzed or dead.. // Stop attacking if the target is enraged TEST_TARGET(); diff --git a/zone/bot.h b/zone/bot.h index 0c48b6483..5c3ccdb6a 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -534,6 +534,9 @@ public: bool IsBotCaster() { return IsCasterClass(GetClass()); } bool IsBotINTCaster() { return IsINTCasterClass(GetClass()); } bool IsBotWISCaster() { return IsWISCasterClass(GetClass()); } + bool IsBotSpellFighter() { return IsSpellFighterClass(GetClass()); } + bool IsBotFighter() { return IsFighterClass(GetClass()); } + bool IsBotNonSpellFighter() { return IsNonSpellFighterClass(GetClass()); } bool CanHeal(); int GetRawACNoShield(int &shield_ac); diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index 5649c0da4..3f1fbf892 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -538,6 +538,69 @@ Mob *HateList::GetRandomEntOnHateList() return (*iterator)->entity_on_hatelist; } +Mob *HateList::GetEscapingEntOnHateList() { + // function is still in design stage + + for (auto iter : list) { + if (!iter->entity_on_hatelist) + continue; + + if (!iter->entity_on_hatelist->IsFeared()) + continue; + + if (iter->entity_on_hatelist->IsRooted()) + continue; + if (iter->entity_on_hatelist->IsMezzed()) + continue; + if (iter->entity_on_hatelist->IsStunned()) + continue; + + return iter->entity_on_hatelist; + } + + return nullptr; +} + +Mob *HateList::GetEscapingEntOnHateList(Mob *center, float range, bool first) { + // function is still in design stage + + if (!center) + return nullptr; + + Mob *escaping_mob = nullptr; + float mob_distance = 0.0f; + + for (auto iter : list) { + if (!iter->entity_on_hatelist) + continue; + + if (!iter->entity_on_hatelist->IsFeared()) + continue; + + if (iter->entity_on_hatelist->IsRooted()) + continue; + if (iter->entity_on_hatelist->IsMezzed()) + continue; + if (iter->entity_on_hatelist->IsStunned()) + continue; + + float distance_test = DistanceSquared(center->GetPosition(), iter->entity_on_hatelist->GetPosition()); + + if (range > 0.0f && distance_test > range) + continue; + + if (first) + return iter->entity_on_hatelist; + + if (distance_test > mob_distance) { + escaping_mob = iter->entity_on_hatelist; + mob_distance = distance_test; + } + } + + return escaping_mob; +} + int32 HateList::GetEntHateAmount(Mob *in_entity, bool damage) { struct_HateList *entity; diff --git a/zone/hate_list.h b/zone/hate_list.h index 0ac1840ac..96d8ed067 100644 --- a/zone/hate_list.h +++ b/zone/hate_list.h @@ -46,6 +46,8 @@ public: Mob *GetEntWithMostHateOnList(Mob *center, Mob *skip = nullptr); Mob *GetRandomEntOnHateList(); Mob *GetEntWithMostHateOnList(); + Mob *GetEscapingEntOnHateList(); // returns first eligble entity + Mob *GetEscapingEntOnHateList(Mob *center, float range = 0.0f, bool first = false); bool IsEntOnHateList(Mob *mob); bool IsHateListEmpty();