From 7c70f42f349e7489a0ac4ff86aa44172354ebb8b Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 18 Jul 2023 17:58:51 +0800 Subject: [PATCH] refactor: naxxramas and kel'thuzad strategy --- src/PlayerbotAI.cpp | 197 +++++++++- src/PlayerbotAI.h | 12 + src/strategy/actions/AttackAction.cpp | 6 +- src/strategy/actions/MovementActions.cpp | 14 + src/strategy/actions/MovementActions.h | 40 ++ src/strategy/druid/HealDruidStrategy.cpp | 6 +- src/strategy/hunter/DpsHunterStrategy.cpp | 6 +- src/strategy/paladin/PaladinActions.cpp | 4 +- .../raids/naxxramas/RaidNaxxActionContext.h | 12 +- .../raids/naxxramas/RaidNaxxActions.cpp | 366 ++++++++---------- .../raids/naxxramas/RaidNaxxActions.h | 94 ++--- .../raids/naxxramas/RaidNaxxBossHelper.h | 72 ++++ .../raids/naxxramas/RaidNaxxMultipliers.cpp | 66 ++-- .../raids/naxxramas/RaidNaxxMultipliers.h | 17 +- .../raids/naxxramas/RaidNaxxScripts.h | 22 +- .../raids/naxxramas/RaidNaxxStrategy.cpp | 16 +- .../raids/naxxramas/RaidNaxxTriggerContext.h | 4 +- .../raids/naxxramas/RaidNaxxTriggers.cpp | 4 + .../raids/naxxramas/RaidNaxxTriggers.h | 14 +- src/strategy/triggers/TriggerContext.h | 2 + src/strategy/values/AttackerCountValues.cpp | 70 +--- src/strategy/values/ItemUsageValue.cpp | 2 +- src/strategy/values/NearestNpcsValue.cpp | 12 + src/strategy/values/NearestNpcsValue.h | 9 + src/strategy/values/TargetValue.h | 2 +- src/strategy/values/ValueContext.h | 3 + 26 files changed, 647 insertions(+), 425 deletions(-) create mode 100644 src/strategy/raids/naxxramas/RaidNaxxBossHelper.h diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 662fa866..19a77269 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -1304,6 +1304,151 @@ bool PlayerbotAI::IsRanged(Player* player) return true; } +bool PlayerbotAI::IsRangedDps(Player* player) +{ + return IsRanged(player) && IsDps(player); +} + +bool PlayerbotAI::IsRangedDpsAssistantOfIndex(Player* player, int index) +{ + Group* group = bot->GetGroup(); + if (!group) { + return false; + } + Group::MemberSlotList const& slots = group->GetMemberSlots(); + int counter = 0; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { + Player* member = ref->GetSource(); + if (group->IsAssistant(member->GetGUID()) && IsRangedDps(member)) { + if (index == counter) { + return player == member; + } + counter++; + } + } + // not enough + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { + Player* member = ref->GetSource(); + if (!group->IsAssistant(member->GetGUID()) && IsRangedDps(member)) { + if (index == counter) { + return player == member; + } + counter++; + } + } + return false; +} + +int32 PlayerbotAI::GetGroupSlotIndex(Player* player) +{ + Group* group = bot->GetGroup(); + if (!group) { + return -1; + } + Group::MemberSlotList const& slots = group->GetMemberSlots(); + int counter = 0; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { + Player* member = ref->GetSource(); + if (player == member) { + return counter; + } + counter++; + } + return 0; +} + +int32 PlayerbotAI::GetRangedIndex(Player* player) +{ + if (!IsRanged(player)) { + return -1; + } + Group* group = bot->GetGroup(); + if (!group) { + return -1; + } + Group::MemberSlotList const& slots = group->GetMemberSlots(); + int counter = 0; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { + Player* member = ref->GetSource(); + if (player == member) { + return counter; + } + if (IsRanged(member)) { + counter++; + } + } + return 0; +} + +int32 PlayerbotAI::GetClassIndex(Player* player, uint8_t cls) +{ + if (player->getClass() != cls) { + return -1; + } + Group* group = bot->GetGroup(); + if (!group) { + return -1; + } + Group::MemberSlotList const& slots = group->GetMemberSlots(); + int counter = 0; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { + Player* member = ref->GetSource(); + if (player == member) { + return counter; + } + if (member->getClass() == cls) { + counter++; + } + } + return 0; +} +int32 PlayerbotAI::GetRangedDpsIndex(Player* player) +{ + if (!IsRangedDps(player)) { + return -1; + } + Group* group = bot->GetGroup(); + if (!group) { + return -1; + } + Group::MemberSlotList const& slots = group->GetMemberSlots(); + int counter = 0; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { + Player* member = ref->GetSource(); + if (player == member) { + return counter; + } + if (IsRangedDps(member)) { + counter++; + } + } + return 0; +} + +int32 PlayerbotAI::GetMeleeIndex(Player* player) +{ + if (IsRanged(player)) { + return -1; + } + Group* group = bot->GetGroup(); + if (!group) { + return -1; + } + Group::MemberSlotList const& slots = group->GetMemberSlots(); + int counter = 0; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { + Player* member = ref->GetSource(); + if (player == member) { + return counter; + } + if (!IsRanged(member)) { + counter++; + } + } + return 0; +} + + bool PlayerbotAI::IsTank(Player* player) { PlayerbotAI* botAi = GET_PLAYERBOT_AI(player); @@ -1370,6 +1515,54 @@ bool PlayerbotAI::IsHeal(Player* player) return false; } +bool PlayerbotAI::IsDps(Player* player) +{ + PlayerbotAI* botAi = GET_PLAYERBOT_AI(player); + if (botAi) + return botAi->ContainsStrategy(STRATEGY_TYPE_DPS); + + int tab = AiFactory::GetPlayerSpecTab(player); + switch (player->getClass()) + { + case CLASS_MAGE: + case CLASS_WARLOCK: + case CLASS_HUNTER: + case CLASS_ROGUE: + return true; + case CLASS_PRIEST: + if (tab == PRIEST_TAB_SHADOW) { + return true; + } + break; + case CLASS_DRUID: + if (tab == DRUID_TAB_BALANCE) { + return true; + } + break; + case CLASS_SHAMAN: + if (tab != SHAMAN_TAB_RESTORATION) { + return true; + } + break; + case CLASS_PALADIN: + if (tab == PALADIN_TAB_RETRIBUTION) { + return true; + } + break; + case CLASS_DEATH_KNIGHT: + if (tab != DEATHKNIGT_TAB_BLOOD) { + return true; + } + break; + case CLASS_WARRIOR: + if (tab != WARRIOR_TAB_PROTECTION) { + return true; + } + break; + } + return false; +} + bool PlayerbotAI::IsMainTank(Player* player) { Group* group = bot->GetGroup(); @@ -1379,8 +1572,10 @@ bool PlayerbotAI::IsMainTank(Player* player) ObjectGuid mainTank = ObjectGuid(); Group::MemberSlotList const& slots = group->GetMemberSlots(); for (Group::member_citerator itr = slots.begin(); itr != slots.end(); ++itr) { - if (itr->flags & MEMBER_FLAG_MAINTANK) + if (itr->flags & MEMBER_FLAG_MAINTANK) { mainTank = itr->guid; + break; + } } if (mainTank != ObjectGuid::Empty) { return player->GetGUID() == mainTank; diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index 4fa499d8..36d4f512 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -330,9 +330,21 @@ class PlayerbotAI : public PlayerbotAIBase void Reset(bool full = false); bool IsTank(Player* player); bool IsHeal(Player* player); + bool IsDps(Player* player); bool IsRanged(Player* player); + bool IsRangedDps(Player* player); bool IsMainTank(Player* player); bool IsAssistTank(Player* player); + + bool IsAssistTankOfIndex(Player* player, int index); + bool IsHealAssistantOfIndex(Player* player, int index); + bool IsRangedDpsAssistantOfIndex(Player* player, int index); + int32 GetGroupSlotIndex(Player* player); + int32 GetRangedIndex(Player* player); + int32 GetClassIndex(Player* player, uint8_t cls); + int32 GetRangedDpsIndex(Player* player); + int32 GetMeleeIndex(Player* player); + Creature* GetCreature(ObjectGuid guid); Unit* GetUnit(ObjectGuid guid); Player* GetPlayer(ObjectGuid guid); diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index 3246dde0..eedd6ea7 100644 --- a/src/strategy/actions/AttackAction.cpp +++ b/src/strategy/actions/AttackAction.cpp @@ -104,18 +104,16 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) if (Pet* pet = bot->GetPet()) { + pet->SetReactState(REACT_PASSIVE); if (with_pet) { pet->SetTarget(target->GetGUID()); - // pet->GetCharmInfo()->SetCommandState(COMMAND_ATTACK); pet->GetCharmInfo()->SetIsCommandAttack(true); pet->AI()->AttackStart(target); - pet->SetReactState(REACT_DEFENSIVE); + // pet->SetReactState(REACT_DEFENSIVE); } else { - // pet->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW); pet->GetCharmInfo()->SetIsCommandFollow(true); pet->GetCharmInfo()->IsReturning(); pet->GetMotionMaster()->MoveFollow(bot, PET_FOLLOW_DIST, pet->GetFollowAngle()); - pet->SetReactState(REACT_PASSIVE); } } diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 1b21ba5a..8c13a979 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1399,3 +1399,17 @@ bool MoveRandomAction::isUseful() return !botAI->HasRealPlayerMaster() && botAI->GetAiObjectContext()->GetValue("nearest friendly players")->Get().size() > urand(25, 100); } +bool MoveInsideAction::Execute(Event event) +{ + return MoveInside(bot->GetMapId(), x, y, bot->GetPositionZ(), distance); +} + +bool RotateAroundTheCenterPointAction::Execute(Event event) +{ + uint32 next_point = GetCurrWaypoint(); + if (MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ())) { + call_counters += 1; + return true; + } + return false; +} \ No newline at end of file diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index d04b37da..49cfc299 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -7,6 +7,7 @@ #include "Action.h" #include "PlayerbotAIConfig.h" +#include class Player; class PlayerbotAI; @@ -123,4 +124,43 @@ class MoveRandomAction : public MovementAction bool isUseful() override; }; +class MoveInsideAction : public MovementAction +{ + public: + MoveInsideAction(PlayerbotAI* ai, float x, float y, float distance = 5.0f) : MovementAction(ai, "move inside") { + this->x = x; + this->y = y; + this->distance = distance; + } + virtual bool Execute(Event event); + protected: + float x, y, distance; +}; + +class RotateAroundTheCenterPointAction : public MovementAction +{ +public: + RotateAroundTheCenterPointAction(PlayerbotAI* ai, std::string name, + float center_x, float center_y, float radius = 40.0f, + uint32 intervals = 16, bool clockwise = true, float start_angle = 0) : MovementAction(ai, name) { + this->center_x = center_x; + this->center_y = center_y; + this->radius = radius; + this->intervals = intervals; + this->clockwise = clockwise; + this->call_counters = 0; + for (int i = 0; i < intervals; i++) { + float angle = start_angle + 2 * M_PI * i / intervals; + waypoints.push_back(std::make_pair(center_x + cos(angle) * radius, center_y + sin(angle) * radius)); + } + } + virtual bool Execute(Event event); +protected: + virtual uint32 GetCurrWaypoint() { return 0; } + uint32 FindNearestWaypoint(); + float center_x, center_y, radius; + uint32 intervals, call_counters; + bool clockwise; + std::vector> waypoints; +}; #endif diff --git a/src/strategy/druid/HealDruidStrategy.cpp b/src/strategy/druid/HealDruidStrategy.cpp index 65e95a6b..36086394 100644 --- a/src/strategy/druid/HealDruidStrategy.cpp +++ b/src/strategy/druid/HealDruidStrategy.cpp @@ -33,7 +33,7 @@ void HealDruidStrategy::InitTriggers(std::vector& triggers) new NextAction("swiftmend on party", ACTION_CRITICAL_HEAL + 3), new NextAction("wild growth", ACTION_CRITICAL_HEAL + 2), new NextAction("nourish on party", ACTION_CRITICAL_HEAL + 1), - // new NextAction("healing touch on party", ACTION_CRITICAL_HEAL + 0), + new NextAction("healing touch on party", ACTION_CRITICAL_HEAL + 0), NULL))); triggers.push_back(new TriggerNode( @@ -41,7 +41,7 @@ void HealDruidStrategy::InitTriggers(std::vector& triggers) NextAction::array(0, new NextAction("nature's swiftness", ACTION_CRITICAL_HEAL + 4), NULL))); triggers.push_back(new TriggerNode( - "group heal occasion", + "medium group heal occasion", NextAction::array(0, new NextAction("tranquility", ACTION_CRITICAL_HEAL + 5), NULL))); // LOW @@ -51,7 +51,7 @@ void HealDruidStrategy::InitTriggers(std::vector& triggers) new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 8), new NextAction("swiftmend on party", ACTION_MEDIUM_HEAL + 7), new NextAction("nourish on party", ACTION_MEDIUM_HEAL + 6), - // new NextAction("healing touch on party", ACTION_MEDIUM_HEAL + 5), + new NextAction("healing touch on party", ACTION_MEDIUM_HEAL + 5), NULL))); // MEDIUM diff --git a/src/strategy/hunter/DpsHunterStrategy.cpp b/src/strategy/hunter/DpsHunterStrategy.cpp index 32c0acb0..07d0f92a 100644 --- a/src/strategy/hunter/DpsHunterStrategy.cpp +++ b/src/strategy/hunter/DpsHunterStrategy.cpp @@ -47,8 +47,8 @@ void DpsHunterStrategy::InitTriggers(std::vector& triggers) GenericHunterStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode("black arrow", NextAction::array(0, new NextAction("black arrow", 15.0f), nullptr))); - triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("viper sting", 23), nullptr))); - triggers.push_back(new TriggerNode("hunter's mark", NextAction::array(0, new NextAction("hunter's mark", 19.0f), nullptr))); + triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("viper sting", 23.0f), nullptr))); + triggers.push_back(new TriggerNode("hunter's mark", NextAction::array(0, new NextAction("hunter's mark", 11.0f), nullptr))); triggers.push_back(new TriggerNode("concussive shot on snare target", NextAction::array(0, new NextAction("concussive shot", 20.0f), nullptr))); triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("call pet", 21.0f), NULL))); triggers.push_back(new TriggerNode("hunters pet low health", NextAction::array(0, new NextAction("mend pet", 21.0f), NULL))); @@ -58,7 +58,7 @@ void DpsHunterStrategy::InitTriggers(std::vector& triggers) void DpsAoeHunterStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("multi-shot", 20.0f), nullptr))); - triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("volley", 20.0f), nullptr))); + triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("volley", 21.0f), nullptr))); triggers.push_back(new TriggerNode("serpent sting on attacker", NextAction::array(0, new NextAction("serpent sting on attacker", 17.0f), nullptr))); } diff --git a/src/strategy/paladin/PaladinActions.cpp b/src/strategy/paladin/PaladinActions.cpp index 7bc25a24..33e3ad55 100644 --- a/src/strategy/paladin/PaladinActions.cpp +++ b/src/strategy/paladin/PaladinActions.cpp @@ -13,7 +13,7 @@ inline std::string const GetActualBlessingOfMight(Unit* target) { if (!target->ToPlayer()) { - return {""}; + return "blessing of might"; } int tab = AiFactory::GetPlayerSpecTab(target->ToPlayer()); switch (target->getClass()) @@ -46,7 +46,7 @@ inline std::string const GetActualBlessingOfMight(Unit* target) inline std::string const GetActualBlessingOfWisdom(Unit* target) { if (!target->ToPlayer()) { - return {""}; + return "blessing of might"; } int tab = AiFactory::GetPlayerSpecTab(target->ToPlayer()); switch (target->getClass()) diff --git a/src/strategy/raids/naxxramas/RaidNaxxActionContext.h b/src/strategy/raids/naxxramas/RaidNaxxActionContext.h index dcf8ba28..f9841dae 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxActionContext.h +++ b/src/strategy/raids/naxxramas/RaidNaxxActionContext.h @@ -36,8 +36,8 @@ class RaidNaxxActionContext : public NamedObjectContext // creators["sapphiron flight position"] = &RaidNaxxActionContext::sapphiron_flight_position; // creators["sapphiron avoid chill"] = &RaidNaxxActionContext::sapphiron_avoid_chill; - // creators["kel'thuzad choose target"] = &RaidNaxxActionContext::kelthuzad_choose_target; - // creators["kel'thuzad position"] = &RaidNaxxActionContext::kelthuzad_position; + creators["kel'thuzad choose target"] = &RaidNaxxActionContext::kelthuzad_choose_target; + creators["kel'thuzad position"] = &RaidNaxxActionContext::kelthuzad_position; creators["anub'rekhan choose target"] = &RaidNaxxActionContext::anubrekhan_choose_target; creators["anub'rekhan position"] = &RaidNaxxActionContext::anubrekhan_position; @@ -50,8 +50,8 @@ class RaidNaxxActionContext : public NamedObjectContext // creators["loatheb choose target"] = &RaidNaxxActionContext::loatheb_choose_target; } private: - static Action* go_behind_the_boss(PlayerbotAI* ai) { return new GoBehindTheBossAction(ai); } - static Action* rotate_grobbulus(PlayerbotAI* ai) { return new RotateGrobbulusAction(ai); } + static Action* go_behind_the_boss(PlayerbotAI* ai) { return new GrobbulusGoBehindAction(ai); } + static Action* rotate_grobbulus(PlayerbotAI* ai) { return new GrobbulusRotateAction(ai); } static Action* grobbulus_move_center(PlayerbotAI* ai) { return new GrobblulusMoveCenterAction(ai); } static Action* heigan_dance_melee(PlayerbotAI* ai) { return new HeiganDanceMeleeAction(ai); } static Action* heigan_dance_ranged(PlayerbotAI* ai) { return new HeiganDanceRangedAction(ai); } @@ -68,8 +68,8 @@ class RaidNaxxActionContext : public NamedObjectContext // static Action* sapphiron_ground_position(PlayerbotAI* ai) { return new SapphironGroundPositionAction(ai); } // static Action* sapphiron_flight_position(PlayerbotAI* ai) { return new SapphironFlightPositionAction(ai); } // static Action* sapphiron_avoid_chill(PlayerbotAI* ai) { return new SapphironAvoidChillAction(ai); } - // static Action* kelthuzad_choose_target(PlayerbotAI* ai) { return new KelthuzadChooseTargetAction(ai); } - // static Action* kelthuzad_position(PlayerbotAI* ai) { return new KelthuzadPositionAction(ai); } + static Action* kelthuzad_choose_target(PlayerbotAI* ai) { return new KelthuzadChooseTargetAction(ai); } + static Action* kelthuzad_position(PlayerbotAI* ai) { return new KelthuzadPositionAction(ai); } static Action* anubrekhan_choose_target(PlayerbotAI* ai) { return new AnubrekhanChooseTargetAction(ai); } static Action* anubrekhan_position(PlayerbotAI* ai) { return new AnubrekhanPositionAction(ai); } // static Action* gluth_choose_target(PlayerbotAI* ai) { return new GluthChooseTargetAction(ai); } diff --git a/src/strategy/raids/naxxramas/RaidNaxxActions.cpp b/src/strategy/raids/naxxramas/RaidNaxxActions.cpp index 7cf3f667..b3d658cf 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxActions.cpp +++ b/src/strategy/raids/naxxramas/RaidNaxxActions.cpp @@ -1,8 +1,12 @@ +#include "ObjectGuid.h" #include "Playerbots.h" #include "RaidNaxxActions.h" #include "RaidNaxxStrategy.h" #include "ScriptedCreature.h" +#include "SharedDefines.h" +#include "raids/naxxramas/RaidNaxxBossHelper.h" +#include using namespace std; @@ -39,7 +43,7 @@ using namespace std; // } -bool GoBehindTheBossAction::Execute(Event event) +bool GrobbulusGoBehindAction::Execute(Event event) { Unit* boss = AI_VALUE(Unit*, "boss target"); if (!boss) { @@ -60,22 +64,9 @@ bool GoBehindTheBossAction::Execute(Event event) // return MoveTo(bot->GetMapId(), x, y, bot->GetPositionZ(), true); // } -bool MoveInsideAction::Execute(Event event) -{ - return MoveInside(bot->GetMapId(), x, y, bot->GetPositionZ(), distance); -} -bool RotateAroundTheCenterPointAction::Execute(Event event) -{ - // uint32 nearest = FindNearestWaypoint(); - // uint32 next_point = (nearest + 1) % intervals; - uint32 next_point = GetCurrWaypoint(); - if (MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ())) { - call_counters += 1; - return true; - } - return false; -} + + uint32 RotateAroundTheCenterPointAction::FindNearestWaypoint() { @@ -92,7 +83,7 @@ uint32 RotateAroundTheCenterPointAction::FindNearestWaypoint() return ret; } -uint32 RotateGrobbulusAction::GetCurrWaypoint() +uint32 GrobbulusRotateAction::GetCurrWaypoint() { Unit* boss = AI_VALUE(Unit*, "boss target"); if (!boss) { @@ -375,7 +366,7 @@ bool HeiganDanceRangedAction::Execute(Event event) { // } // } else { // list attackers = context->GetValue >("attackers")->Get(); -// Unit* target = NULL; +// Unit* target = nullptr; // for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) { // Unit* unit = botAI->GetUnit(*i); // if (!unit) @@ -401,7 +392,7 @@ bool HeiganDanceRangedAction::Execute(Event event) { // { // Unit* razuvious = AI_VALUE2(Unit*, "find target", "instructor razuvious"); // Unit* understudy = AI_VALUE2(Unit*, "find target", "death knight understudy"); -// Unit* target = NULL; +// Unit* target = nullptr; // if (botAI->IsTank(bot)) { // target = understudy; // } else { @@ -492,7 +483,7 @@ bool HeiganDanceRangedAction::Execute(Event event) { // bool HorsemanAttactInOrderAction::Execute(Event event) // { -// Unit* target = NULL; +// Unit* target = nullptr; // Unit* thane = AI_VALUE2(Unit*, "find target", "thane korth'azz"); // Unit* baron = AI_VALUE2(Unit*, "find target", "baron rivendare"); // Unit* lady = AI_VALUE2(Unit*, "find target", "lady blaumeux"); @@ -621,7 +612,7 @@ bool HeiganDanceRangedAction::Execute(Event event) { // } // Group::MemberSlotList const& slots = group->GetMemberSlots(); // int counter = 0; -// Player* playerWithIcebolt = NULL; +// Player* playerWithIcebolt = nullptr; // float minDistance; // for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { // Player* member = ref->GetSource(); @@ -679,188 +670,153 @@ bool HeiganDanceRangedAction::Execute(Event event) { // return MoveTo(bot->GetMapId(), bot->GetPositionX() + cos(angle) * 5.0f, bot->GetPositionY() + sin(angle) * 5.0f, bot->GetPositionZ()); // } -// bool KelthuzadChooseTargetAction::Execute(Event event) -// { -// Unit* boss = AI_VALUE2(Unit*, "find target", "kel'thuzad"); -// if (!boss) { -// return false; -// } -// BossAI* boss_ai = dynamic_cast(boss->GetAI()); -// EventMap* eventMap = boss_botAI->GetEvents(); -// std::pair center = {3716.19f, -5106.58f}; -// list attackers = context->GetValue >("attackers")->Get(); -// Unit* target = NULL; -// Unit *target_soldier = NULL, *target_weaver = NULL, *target_abomination = NULL, *target_kelthuzad = NULL, *target_guardian = NULL; -// for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) -// { -// Unit* unit = botAI->GetUnit(*i); -// if (!unit) -// continue; +bool KelthuzadChooseTargetAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) { + return false; + } + GuidVector attackers = context->GetValue("attackers")->Get(); + Unit* target = nullptr; + Unit *target_soldier = nullptr, *target_weaver = nullptr, *target_abomination = nullptr, *target_kelthuzad = nullptr, *target_guardian = nullptr; + for (auto i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit) + continue; -// if (botAI->EqualLowercaseName(unit->GetName(), "guardian of icecrown")) { -// if (!target_guardian) { -// target_guardian = unit; -// } else if (unit->GetVictim() && target_guardian->GetVictim() && -// unit->GetVictim()->ToPlayer() && target_guardian->GetVictim()->ToPlayer() && -// !botAI->IsAssistTank(unit->GetVictim()->ToPlayer()) && botAI->IsAssistTank(target_guardian->GetVictim()->ToPlayer())) { -// target_guardian = unit; -// } else if (unit->GetVictim() && target_guardian->GetVictim() && -// unit->GetVictim()->ToPlayer() && target_guardian->GetVictim()->ToPlayer() && -// !botAI->IsAssistTank(unit->GetVictim()->ToPlayer()) && !botAI->IsAssistTank(target_guardian->GetVictim()->ToPlayer()) && -// target_guardian->GetDistance2d(center.first, center.second) > bot->GetDistance2d(unit)) { -// target_guardian = unit; -// } -// } + if (botAI->EqualLowercaseName(unit->GetName(), "guardian of icecrown")) { + if (!target_guardian) { + target_guardian = unit; + } else if (unit->GetVictim() && target_guardian->GetVictim() && + unit->GetVictim()->ToPlayer() && target_guardian->GetVictim()->ToPlayer() && + !botAI->IsAssistTank(unit->GetVictim()->ToPlayer()) && botAI->IsAssistTank(target_guardian->GetVictim()->ToPlayer())) { + target_guardian = unit; + } else if (unit->GetVictim() && target_guardian->GetVictim() && + unit->GetVictim()->ToPlayer() && target_guardian->GetVictim()->ToPlayer() && + !botAI->IsAssistTank(unit->GetVictim()->ToPlayer()) && !botAI->IsAssistTank(target_guardian->GetVictim()->ToPlayer()) && + target_guardian->GetDistance2d(helper.center.first, helper.center.second) > bot->GetDistance2d(unit)) { + target_guardian = unit; + } + } -// if (unit->GetDistance2d(center.first, center.second) > 30.0f) { -// continue; -// } -// if (bot->GetDistance2d(unit) > sPlayerbotAIConfig.spellDistance) { -// continue; -// } -// if (botAI->EqualLowercaseName(unit->GetName(), "unstoppable abomination")) { -// if (target_abomination == NULL || -// target_abomination->GetDistance2d(center.first, center.second) > unit->GetDistance2d(center.first, center.second)) { -// target_abomination = unit; -// } -// } -// if (botAI->EqualLowercaseName(unit->GetName(), "soldier of the frozen wastes")) { -// if (target_soldier == NULL || -// target_soldier->GetDistance2d(center.first, center.second) > unit->GetDistance2d(center.first, center.second)) { -// target_soldier = unit; -// } -// } -// if (botAI->EqualLowercaseName(unit->GetName(), "soul weaver")) { -// if (target_weaver == NULL || -// target_weaver->GetDistance2d(center.first, center.second) > unit->GetDistance2d(center.first, center.second)) { -// target_weaver = unit; -// } -// } -// if (botAI->EqualLowercaseName(unit->GetName(), "kel'thuzad")) { -// target_kelthuzad = unit; -// } - -// } -// vector targets; -// if (botAI->IsRanged(bot)) { -// if (botAI->GetRangedDpsIndex(bot) <= 1) { -// targets = {target_soldier, target_weaver, target_abomination, target_kelthuzad}; -// } else { -// targets = {target_weaver, target_soldier, target_abomination, target_kelthuzad}; -// } -// } else if (botAI->IsAssistTank(bot)) { -// targets = {target_abomination, target_guardian, target_kelthuzad}; -// } else { -// targets = {target_abomination, target_kelthuzad}; -// } -// for (Unit* t : targets) { -// if (t) { -// target = t; -// break; -// } -// } -// if (context->GetValue("current target")->Get() == target) { -// return false; -// } -// // if (target) { -// // bot->Yell("Target name: " + target->GetName(), LANG_UNIVERSAL); -// // } -// if (target_kelthuzad && target == target_kelthuzad) { -// return Attack(target, true); -// } -// return Attack(target, false); -// } + if (unit->GetDistance2d(helper.center.first, helper.center.second) > 30.0f) { + continue; + } + if (bot->GetDistance2d(unit) > sPlayerbotAIConfig->spellDistance) { + continue; + } + if (botAI->EqualLowercaseName(unit->GetName(), "unstoppable abomination")) { + if (target_abomination == nullptr || + target_abomination->GetDistance2d(helper.center.first, helper.center.second) > unit->GetDistance2d(helper.center.first, helper.center.second)) { + target_abomination = unit; + } + } + if (botAI->EqualLowercaseName(unit->GetName(), "soldier of the frozen wastes")) { + if (target_soldier == nullptr || + target_soldier->GetDistance2d(helper.center.first, helper.center.second) > unit->GetDistance2d(helper.center.first, helper.center.second)) { + target_soldier = unit; + } + } + if (botAI->EqualLowercaseName(unit->GetName(), "soul weaver")) { + if (target_weaver == nullptr || + target_weaver->GetDistance2d(helper.center.first, helper.center.second) > unit->GetDistance2d(helper.center.first, helper.center.second)) { + target_weaver = unit; + } + } + if (botAI->EqualLowercaseName(unit->GetName(), "kel'thuzad")) { + target_kelthuzad = unit; + } + } + vector targets; + if (botAI->IsRanged(bot)) { + if (botAI->GetRangedDpsIndex(bot) <= 1) { + targets = {target_soldier, target_weaver, target_abomination, target_kelthuzad}; + } else { + targets = {target_weaver, target_soldier, target_abomination, target_kelthuzad}; + } + } else if (botAI->IsAssistTank(bot)) { + targets = {target_abomination, target_guardian, target_kelthuzad}; + } else { + targets = {target_abomination, target_kelthuzad}; + } + for (Unit* t : targets) { + if (t) { + target = t; + break; + } + } + if (context->GetValue("current target")->Get() == target) { + return false; + } + if (target_kelthuzad && target == target_kelthuzad) { + return Attack(target, true); + } + return Attack(target, false); +} -// bool KelthuzadPositionAction::Execute(Event event) -// { -// Unit* boss = AI_VALUE2(Unit*, "find target", "kel'thuzad"); -// if (!boss) { -// return false; -// } -// BossAI* b_ai = dynamic_cast(boss->GetAI()); -// if (!b_ai) { -// return false; -// } -// EventMap *eventMap = b_botAI->GetEvents(); -// uint8 phase_mask = eventMap->GetPhaseMask(); -// if (phase_mask == 1) { -// if (AI_VALUE(Unit*, "current target") == NULL) { -// return MoveInside(533, 3716.19f, -5106.58f, bot->GetPositionZ(), 3.0f); -// } -// } else if (phase_mask == 2) { -// Unit* shadow_fissure = NULL; - -// list units = *context->GetValue >("possible targets"); -// for (list::iterator i = units.begin(); i != units.end(); i++) -// { -// Unit* unit = botAI->GetUnit(*i); -// if (!unit) -// continue; - -// if (botAI->EqualLowercaseName(unit->GetName(), "shadow fissure")) { -// shadow_fissure = unit; -// } -// } - -// if (!shadow_fissure || bot->GetDistance2d(shadow_fissure) > 8.0f) { -// float distance, angle; -// if (botAI->IsMainTank(bot)) { -// if (AI_VALUE2(bool, "has aggro", "current target")) { -// return MoveTo(533, 3709.19f, -5104.86f, bot->GetPositionZ()); -// // return false; -// } -// } else if (botAI->IsRanged(bot)) { -// uint32 index = botAI->GetRangedIndex(bot); -// if (index < 8) { -// distance = 20.0f; -// angle = index * M_PI / 4; -// } else { -// distance = 32.0f; -// angle = (index - 8) * M_PI / 4; -// } -// } else if (botAI->IsTank(bot)) { -// Unit* cur_tar = AI_VALUE(Unit*, "current target"); -// if (cur_tar && cur_tar->GetVictim() && cur_tar->GetVictim()->ToPlayer() && -// botAI->EqualLowercaseName(cur_tar->GetName(), "guardian of icecrown") && -// botAI->IsAssistTank(cur_tar->GetVictim()->ToPlayer()) ) { -// return MoveTo(533, 3746.05f, -5112.74f, bot->GetPositionZ()); -// } else { -// return false; -// } -// } else { -// return false; -// } -// std::pair center = {3716.19f, -5106.58f}; -// float dx, dy; -// dx = center.first + cos(angle) * distance; -// dy = center.second + sin(angle) * distance; -// return MoveTo(533, dx, dy, bot->GetPositionZ()); -// } else { -// float dx, dy; -// float angle; -// if (!botAI->IsRanged(bot)) { -// angle = shadow_fissure->GetAngle(3716.19f, -5106.58f); -// } else { -// angle = bot->GetAngle(shadow_fissure) + M_PI; -// } -// dx = shadow_fissure->GetPositionX() + cos(angle) * 8.0f; -// dy = shadow_fissure->GetPositionY() + sin(angle) * 8.0f; -// return MoveTo(533, dx, dy, bot->GetPositionZ()); -// } -// } -// return false; -// } +bool KelthuzadPositionAction::Execute(Event event) +{ + if (!helper.UpdateBossAI()) { + return false; + } + if (helper.IsPhaseOne()) { + if (AI_VALUE(Unit*, "current target") == nullptr) { + return MoveInside(NAXX_MAP_ID, helper.center.first, helper.center.second, bot->GetPositionZ(), 3.0f); + } + } else if (helper.IsPhaseTwo()) { + Unit* shadow_fissure = helper.GetAnyShadowFissure(); + if (!shadow_fissure || bot->GetDistance2d(shadow_fissure) > 10.0f) { + float distance, angle; + if (botAI->IsMainTank(bot)) { + if (AI_VALUE2(bool, "has aggro", "current target")) { + return MoveTo(NAXX_MAP_ID, helper.tank_pos.first, helper.tank_pos.second, bot->GetPositionZ()); + } else { + return false; + } + } else if (botAI->IsRanged(bot)) { + uint32 index = botAI->GetRangedIndex(bot); + if (index < 8) { + distance = 20.0f; + angle = index * M_PI / 4; + } else { + distance = 32.0f; + angle = (index - 8) * M_PI / 4; + } + float dx, dy; + dx = helper.center.first + cos(angle) * distance; + dy = helper.center.second + sin(angle) * distance; + return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ()); + } else if (botAI->IsTank(bot)) { + Unit* cur_tar = AI_VALUE(Unit*, "current target"); + if (cur_tar && cur_tar->GetVictim() && cur_tar->GetVictim()->ToPlayer() && + botAI->EqualLowercaseName(cur_tar->GetName(), "guardian of icecrown") && + botAI->IsAssistTank(cur_tar->GetVictim()->ToPlayer()) ) { + return MoveTo(NAXX_MAP_ID, helper.assist_tank_pos.first, helper.assist_tank_pos.second, bot->GetPositionZ()); + } else { + return false; + } + } + } else { + float dx, dy; + float angle; + if (!botAI->IsRanged(bot)) { + angle = shadow_fissure->GetAngle(helper.center.first, helper.center.second); + } else { + angle = bot->GetAngle(shadow_fissure) + M_PI; + } + dx = shadow_fissure->GetPositionX() + cos(angle) * 10.0f; + dy = shadow_fissure->GetPositionY() + sin(angle) * 10.0f; + return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ()); + } + } + return false; +} bool AnubrekhanChooseTargetAction::Execute(Event event) { - Unit* boss = AI_VALUE2(Unit*, "find target", "anub'rekhan"); - if (!boss) { - return false; - } - BossAI* boss_ai = dynamic_cast(boss->GetAI()); GuidVector attackers = context->GetValue("attackers")->Get(); - Unit* target = NULL; - Unit *target_boss = NULL; + Unit* target = nullptr; + Unit *target_boss = nullptr; vector target_guards; for (ObjectGuid const guid : attackers) { @@ -882,13 +838,13 @@ bool AnubrekhanChooseTargetAction::Execute(Event event) } else { if (botAI->IsAssistTank(bot)) { for (Unit* t : target_guards) { - if (target == NULL || (target->GetVictim() && target->GetVictim()->ToPlayer() && botAI->IsTank(target->GetVictim()->ToPlayer()))) { + if (target == nullptr || (target->GetVictim() && target->GetVictim()->ToPlayer() && botAI->IsTank(target->GetVictim()->ToPlayer()))) { target = t; } } } else { for (Unit* t : target_guards) { - if (target == NULL || target->GetHealthPct() > t->GetHealthPct()) { + if (target == nullptr || target->GetHealthPct() > t->GetHealthPct()) { target = t; } } @@ -941,8 +897,8 @@ bool AnubrekhanPositionAction::Execute(Event event) // BossAI* boss_ai = dynamic_cast(boss->GetAI()); // EventMap* eventMap = boss_botAI->GetEvents(); // list attackers = context->GetValue >("attackers")->Get(); -// Unit* target = NULL; -// Unit *target_boss = NULL; +// Unit* target = nullptr; +// Unit *target_boss = nullptr; // vector target_zombies; // for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) // { @@ -971,12 +927,12 @@ bool AnubrekhanPositionAction::Execute(Event event) // } else { // for (Unit* t : target_zombies) { // if (t->GetHealthPct() <= 10.0f) { -// if (target == NULL || target->GetDistance2d(3331.48f, -3109.06f) > t->GetDistance2d(3331.48f, -3109.06f)) { +// if (target == nullptr || target->GetDistance2d(3331.48f, -3109.06f) > t->GetDistance2d(3331.48f, -3109.06f)) { // target = t; // } // } // } -// if (target == NULL) { +// if (target == nullptr) { // target = target_boss; // } // } @@ -1099,9 +1055,9 @@ bool AnubrekhanPositionAction::Execute(Event event) // BossAI* boss_ai = dynamic_cast(boss->GetAI()); // EventMap* eventMap = boss_botAI->GetEvents(); // list attackers = context->GetValue >("attackers")->Get(); -// Unit* target = NULL; -// Unit *target_boss = NULL; -// Unit *target_spore = NULL; +// Unit* target = nullptr; +// Unit *target_boss = nullptr; +// Unit *target_spore = nullptr; // for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) // { // Unit* unit = botAI->GetUnit(*i); diff --git a/src/strategy/raids/naxxramas/RaidNaxxActions.h b/src/strategy/raids/naxxramas/RaidNaxxActions.h index d6e3785d..00655254 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxActions.h +++ b/src/strategy/raids/naxxramas/RaidNaxxActions.h @@ -8,6 +8,7 @@ #include "PlayerbotAI.h" #include "Playerbots.h" #include "RaidNaxxScripts.h" +#include "RaidNaxxBossHelper.h" // just for test // class TryToGetBossAIAction : public Action @@ -19,10 +20,10 @@ // virtual bool Execute(Event event); // }; -class GoBehindTheBossAction : public MovementAction +class GrobbulusGoBehindAction : public MovementAction { public: - GoBehindTheBossAction(PlayerbotAI* ai, float distance = 24.0f, float delta_angle = M_PI / 8) : MovementAction(ai, "grobbulus go behind the boss") { + GrobbulusGoBehindAction(PlayerbotAI* ai, float distance = 24.0f, float delta_angle = M_PI / 8) : MovementAction(ai, "grobbulus go behind") { this->distance = distance; this->delta_angle = delta_angle; } @@ -31,67 +32,14 @@ protected: float distance, delta_angle; }; -// class MoveToPointForceAction : public MovementAction -// { -// public: -// MoveToPointForceAction(PlayerbotAI* ai, float x, float y) : MovementAction(ai, "move to point force") { -// this->x = x; -// this->y = y; -// } -// virtual bool Execute(Event event); -// protected: -// float x, y; -// }; - -class MoveInsideAction : public MovementAction +class GrobbulusRotateAction : public RotateAroundTheCenterPointAction { public: - MoveInsideAction(PlayerbotAI* ai, float x, float y, float distance = 5.0f) : MovementAction(ai, "move inside") { - this->x = x; - this->y = y; - this->distance = distance; - } - virtual bool Execute(Event event); -protected: - float x, y, distance; -}; - -class RotateAroundTheCenterPointAction : public MovementAction -{ -public: - RotateAroundTheCenterPointAction(PlayerbotAI* ai, std::string name, - float center_x, float center_y, float radius = 40.0f, - uint32 intervals = 16, bool clockwise = true, float start_angle = 0) : MovementAction(ai, name) { - this->center_x = center_x; - this->center_y = center_y; - this->radius = radius; - this->intervals = intervals; - this->clockwise = clockwise; - this->call_counters = 0; - for (int i = 0; i < intervals; i++) { - float angle = start_angle + 2 * M_PI * i / intervals; - waypoints.push_back(std::make_pair(center_x + cos(angle) * radius, center_y + sin(angle) * radius)); - } - } - virtual bool Execute(Event event); -protected: - virtual uint32 GetCurrWaypoint() { return 0; } - uint32 FindNearestWaypoint(); - float center_x, center_y, radius; - uint32 intervals, call_counters; - bool clockwise; - std::vector> waypoints; -}; - -class RotateGrobbulusAction : public RotateAroundTheCenterPointAction -{ -public: - RotateGrobbulusAction(PlayerbotAI* botAI): RotateAroundTheCenterPointAction(botAI, "rotate grobbulus", 3281.23f, -3310.38f, 35.0f, 8, true, M_PI) {} - virtual bool isUseful() { + GrobbulusRotateAction(PlayerbotAI* botAI): RotateAroundTheCenterPointAction(botAI, "rotate grobbulus", 3281.23f, -3310.38f, 35.0f, 8, true, M_PI) {} + virtual bool isUseful() override { return RotateAroundTheCenterPointAction::isUseful() && botAI->IsMainTank(bot) && AI_VALUE2(bool, "has aggro", "boss target"); } - virtual uint32 GetCurrWaypoint(); -protected: + uint32 GetCurrWaypoint() override; }; class GrobblulusMoveCenterAction : public MoveInsideAction @@ -254,19 +202,23 @@ protected: // virtual bool Execute(Event event); // }; -// class KelthuzadChooseTargetAction : public AttackAction -// { -// public: -// KelthuzadChooseTargetAction(PlayerbotAI* ai) : AttackAction(ai, "kel'thuzad choose target") {} -// virtual bool Execute(Event event); -// }; +class KelthuzadChooseTargetAction : public AttackAction +{ + public: + KelthuzadChooseTargetAction(PlayerbotAI* ai) : AttackAction(ai, "kel'thuzad choose target"), helper(ai) {} + virtual bool Execute(Event event); + private: + KelthuzadBossHelper helper; +}; -// class KelthuzadPositionAction : public MovementAction -// { -// public: -// KelthuzadPositionAction(PlayerbotAI* ai) : MovementAction(ai, "kel'thuzad position") {} -// virtual bool Execute(Event event); -// }; +class KelthuzadPositionAction : public MovementAction +{ + public: + KelthuzadPositionAction(PlayerbotAI* ai) : MovementAction(ai, "kel'thuzad position"), helper(ai) {} + virtual bool Execute(Event event); + private: + KelthuzadBossHelper helper; +}; class AnubrekhanChooseTargetAction : public AttackAction { diff --git a/src/strategy/raids/naxxramas/RaidNaxxBossHelper.h b/src/strategy/raids/naxxramas/RaidNaxxBossHelper.h new file mode 100644 index 00000000..6250c515 --- /dev/null +++ b/src/strategy/raids/naxxramas/RaidNaxxBossHelper.h @@ -0,0 +1,72 @@ +#ifndef _PLAYERBOT_RAIDNAXXBOSSHELPER_H +#define _PLAYERBOT_RAIDNAXXBOSSHELPER_H + +#include "AiObject.h" +#include "AiObjectContext.h" +#include "EventMap.h" +#include "ObjectGuid.h" +#include "Player.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "ScriptedCreature.h" +#include "RaidNaxxScripts.h" +#include "SharedDefines.h" + +#include + +const uint32 NAXX_MAP_ID = 533; + +template +class GenericBossHelper : public AiObject { + +}; + +class KelthuzadBossHelper: public AiObject { + public: + std::pair center = {3716.19f, -5106.58f}; + std::pair tank_pos = {3709.19f, -5104.86f}; + std::pair assist_tank_pos = {3746.05f, -5112.74f}; + KelthuzadBossHelper(PlayerbotAI *botAI): AiObject(botAI) {} + + bool UpdateBossAI() { + Unit* target = AI_VALUE2(Unit*, "find target", "kel'thuzad"); + if (!target) { + return false; + } + ai_ = dynamic_cast(target->GetAI()); + if (!ai_) { + return false; + } + event_map_ = &ai_->events; + if (!event_map_) { + return false; + } + return true; + } + bool IsPhaseOne() { + return event_map_->GetNextEventTime(KELTHUZAD_EVENT_PHASE_2) != 0; + } + bool IsPhaseTwo() { + return !IsPhaseOne(); + } + Unit* GetAnyShadowFissure() { + Unit* shadow_fissure = nullptr; + GuidVector units = *context->GetValue("nearest triggers"); + for (auto i = units.begin(); i != units.end(); i++) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit) + continue; + if (botAI->EqualLowercaseName(unit->GetName(), "shadow fissure")) { + shadow_fissure = unit; + } + } + return shadow_fissure; + } + private: + boss_kelthuzad::boss_kelthuzadAI *ai_; + EventMap* event_map_; +}; + + +#endif \ No newline at end of file diff --git a/src/strategy/raids/naxxramas/RaidNaxxMultipliers.cpp b/src/strategy/raids/naxxramas/RaidNaxxMultipliers.cpp index c9af8f5c..7db6acc1 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxMultipliers.cpp +++ b/src/strategy/raids/naxxramas/RaidNaxxMultipliers.cpp @@ -167,42 +167,36 @@ float HeiganDanceMultiplier::GetValue(Action* action) // return 1.0f; // } -// float KelthuzadGenericMultiplier::GetValue(Action* action) -// { -// Unit* boss = AI_VALUE2(Unit*, "find target", "kel'thuzad"); -// if (!boss) { -// return 1.0f; -// } -// if ((dynamic_cast(action) || -// dynamic_cast(action) || -// dynamic_cast(action) || -// dynamic_cast(action) || -// dynamic_cast(action))) { -// return 0.0f; -// } -// BossAI* boss_ai = dynamic_cast(boss->GetAI()); -// EventMap* eventMap = boss_botAI->GetEvents(); -// uint32 curr_phase = eventMap->GetPhaseMask(); - -// if (curr_phase == 1) { -// if (dynamic_cast(action) || -// dynamic_cast(action) || -// dynamic_cast(action) || -// dynamic_cast(action) || -// dynamic_cast(action) || -// dynamic_cast(action)) { -// return 0.0f; -// } -// } -// if (curr_phase == 2) { -// if (dynamic_cast(action) || -// dynamic_cast(action)) { -// return 0.0f; -// } - -// } -// return 1.0f; -// } +float KelthuzadGenericMultiplier::GetValue(Action* action) +{ + if (!helper.UpdateBossAI()) { + return 1.0f; + } + if ((dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action))) { + return 0.0f; + } + if (helper.IsPhaseOne()) { + if (dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action) || + dynamic_cast(action)) { + return 0.0f; + } + } + if (helper.IsPhaseTwo()) { + if (dynamic_cast(action) || + dynamic_cast(action)) { + return 0.0f; + } + } + return 1.0f; +} float AnubrekhanGenericMultiplier::GetValue(Action* action) { diff --git a/src/strategy/raids/naxxramas/RaidNaxxMultipliers.h b/src/strategy/raids/naxxramas/RaidNaxxMultipliers.h index 1a28944d..1673a0a0 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxMultipliers.h +++ b/src/strategy/raids/naxxramas/RaidNaxxMultipliers.h @@ -3,6 +3,7 @@ #define _PLAYERRBOT_RAIDNAXXMULTIPLIERS_H_ #include "Multiplier.h" +#include "raids/naxxramas/RaidNaxxBossHelper.h" class HeiganDanceMultiplier : public Multiplier { @@ -49,14 +50,14 @@ public: // virtual float GetValue(Action* action); // }; -// class KelthuzadGenericMultiplier : public Multiplier -// { -// public: -// KelthuzadGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "kelthuzad generic") {} - -// public: -// virtual float GetValue(Action* action); -// }; +class KelthuzadGenericMultiplier : public Multiplier +{ + public: + KelthuzadGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "kelthuzad generic"), helper(ai) {} + virtual float GetValue(Action* action); + private: + KelthuzadBossHelper helper; +}; class AnubrekhanGenericMultiplier : public Multiplier { diff --git a/src/strategy/raids/naxxramas/RaidNaxxScripts.h b/src/strategy/raids/naxxramas/RaidNaxxScripts.h index 5fa0d77e..c0edcc67 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxScripts.h +++ b/src/strategy/raids/naxxramas/RaidNaxxScripts.h @@ -1,8 +1,24 @@ #ifndef _PLAYERBOT_RAIDNAXXSCRIPTS_H #define _PLAYERBOT_RAIDNAXXSCRIPTS_H -#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_heigan.h" #include "../../../../src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.h" -#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_grobbulus.h" +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_faerlina.h" +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_maexxna.h" -#endif \ No newline at end of file +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_noth.h" +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_heigan.h" +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_loatheb.h" + +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_patchwerk.h" +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_grobbulus.h" +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_gluth.h" +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_thaddius.h" + +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_razuvious.h" +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_gothik.h" +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.h" + +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_sapphiron.h" +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.h" + +#endif diff --git a/src/strategy/raids/naxxramas/RaidNaxxStrategy.cpp b/src/strategy/raids/naxxramas/RaidNaxxStrategy.cpp index 39e27e79..5080fcf5 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxStrategy.cpp +++ b/src/strategy/raids/naxxramas/RaidNaxxStrategy.cpp @@ -86,13 +86,13 @@ void RaidNaxxStrategy::InitTriggers(std::vector &triggers) // "sapphiron chill", // NextAction::array(0, new NextAction("sapphiron avoid chill", ACTION_RAID + 1), NULL))); - // // Kel'Thuzad - // triggers.push_back(new TriggerNode( - // "kel'thuzad", - // NextAction::array(0, - // new NextAction("kel'thuzad choose target", ACTION_RAID + 1), - // new NextAction("kel'thuzad position", ACTION_RAID + 1), - // NULL))); + // Kel'Thuzad + triggers.push_back(new TriggerNode( + "kel'thuzad", + NextAction::array(0, + new NextAction("kel'thuzad choose target", ACTION_RAID + 1), + new NextAction("kel'thuzad position", ACTION_RAID + 1), + NULL))); // Anub'Rekhan triggers.push_back(new TriggerNode( @@ -131,7 +131,7 @@ void RaidNaxxStrategy::InitMultipliers(std::vector &multipliers) // multipliers.push_back(new ThaddiusGenericMultiplier(ai)); // multipliers.push_back(new SapphironGenericMultiplier(ai)); // multipliers.push_back(new InstructorRazuviousGenericMultiplier(ai)); - // multipliers.push_back(new KelthuzadGenericMultiplier(ai)); + multipliers.push_back(new KelthuzadGenericMultiplier(botAI)); multipliers.push_back(new AnubrekhanGenericMultiplier(botAI)); // multipliers.push_back(new FourhorsemanGenericMultiplier(ai)); // multipliers.push_back(new GothikGenericMultiplier(ai)); diff --git a/src/strategy/raids/naxxramas/RaidNaxxTriggerContext.h b/src/strategy/raids/naxxramas/RaidNaxxTriggerContext.h index 7729432d..5682912e 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxTriggerContext.h +++ b/src/strategy/raids/naxxramas/RaidNaxxTriggerContext.h @@ -36,7 +36,7 @@ class RaidNaxxTriggerContext : public NamedObjectContext // creators["sapphiron flight"] = &RaidNaxxTriggerContext::sapphiron_flight; // creators["sapphiron chill"] = &RaidNaxxTriggerContext::sapphiron_ground_chill; - // creators["kel'thuzad"] = &RaidNaxxTriggerContext::kelthuzad; + creators["kel'thuzad"] = &RaidNaxxTriggerContext::kelthuzad; // creators["kel'thuzad phase two"] = &RaidNaxxTriggerContext::kelthuzad_phase_two; creators["anub'rekhan"] = &RaidNaxxTriggerContext::anubrekhan; @@ -65,7 +65,7 @@ class RaidNaxxTriggerContext : public NamedObjectContext // static Trigger* sapphiron_ground_except_main_tank(PlayerbotAI* ai) { return new SapphironGroundExceptMainTankTrigger(ai); } // static Trigger* sapphiron_flight(PlayerbotAI* ai) { return new SapphironFlightTrigger(ai); } // static Trigger* sapphiron_ground_chill(PlayerbotAI* ai) { return new SapphironGroundChillTrigger(ai); } - // static Trigger* kelthuzad(PlayerbotAI* ai) { return new KelthuzadTrigger(ai); } + static Trigger* kelthuzad(PlayerbotAI* ai) { return new KelthuzadTrigger(ai); } // static Trigger* kelthuzad_phase_two(PlayerbotAI* ai) { return new KelthuzadPhaseTwoTrigger(ai); } static Trigger* anubrekhan(PlayerbotAI* ai) { return new AnubrekhanTrigger(ai); } // static Trigger* gluth(PlayerbotAI* ai) { return new GluthTrigger(ai); } diff --git a/src/strategy/raids/naxxramas/RaidNaxxTriggers.cpp b/src/strategy/raids/naxxramas/RaidNaxxTriggers.cpp index b1f4366c..1d2c7cd9 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxTriggers.cpp +++ b/src/strategy/raids/naxxramas/RaidNaxxTriggers.cpp @@ -166,5 +166,9 @@ bool HeiganRangedTrigger::IsActive() // return true; // } +bool KelthuzadTrigger::IsActive() { + return helper.UpdateBossAI(); +} + template bool BossEventTrigger::IsActive(); template bool BossPhaseTrigger::IsActive(); \ No newline at end of file diff --git a/src/strategy/raids/naxxramas/RaidNaxxTriggers.h b/src/strategy/raids/naxxramas/RaidNaxxTriggers.h index b3048815..b4c6653e 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxTriggers.h +++ b/src/strategy/raids/naxxramas/RaidNaxxTriggers.h @@ -7,6 +7,7 @@ #include "PlayerbotAIConfig.h" #include "GenericTriggers.h" #include "RaidNaxxScripts.h" +#include "raids/naxxramas/RaidNaxxBossHelper.h" using namespace std; @@ -167,11 +168,14 @@ public: // virtual bool IsActive(); // }; -// class KelthuzadTrigger : public BossPhaseTrigger -// { -// public: -// KelthuzadTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "kel'thuzad", 0, "kel'thuzad trigger") {} -// }; +class KelthuzadTrigger : public Trigger +{ + public: + KelthuzadTrigger(PlayerbotAI* ai) : Trigger(ai, "kel'thuzad trigger"), helper(ai) {} + bool IsActive() override; + private: + KelthuzadBossHelper helper; +}; class AnubrekhanTrigger : public BossPhaseTrigger { diff --git a/src/strategy/triggers/TriggerContext.h b/src/strategy/triggers/TriggerContext.h index 3da3ed0b..a1fe2c27 100644 --- a/src/strategy/triggers/TriggerContext.h +++ b/src/strategy/triggers/TriggerContext.h @@ -123,6 +123,7 @@ class TriggerContext : public NamedObjectContext creators["low aoe heal"] = &TriggerContext::low_aoe_heal; creators["medium aoe heal"] = &TriggerContext::medium_aoe_heal; creators["group heal occasion"] = &TriggerContext::group_heal_occasion; + creators["medium group heal occasion"] = &TriggerContext::medium_group_heal_occasion; creators["invalid target"] = &TriggerContext::invalid_target; creators["lfg proposal active"] = &TriggerContext::lfg_proposal_active; @@ -216,6 +217,7 @@ class TriggerContext : public NamedObjectContext static Trigger* low_aoe_heal(PlayerbotAI* botAI) { return new AoeHealTrigger(botAI, "low aoe heal", "low", 2); } static Trigger* medium_aoe_heal(PlayerbotAI* botAI) { return new AoeHealTrigger(botAI, "medium aoe heal", "medium", 2); } static Trigger* group_heal_occasion(PlayerbotAI* ai) { return new AoeInGroupTrigger(ai, "group heal occasion", "almost full", 0.4); } + static Trigger* medium_group_heal_occasion(PlayerbotAI* ai) { return new AoeInGroupTrigger(ai, "group heal occasion", "medium", 0.4); } static Trigger* target_changed(PlayerbotAI* botAI) { return new TargetChangedTrigger(botAI); } static Trigger* swimming(PlayerbotAI* botAI) { return new IsSwimmingTrigger(botAI); } static Trigger* no_possible_targets(PlayerbotAI* botAI) { return new NoPossibleTargetsTrigger(botAI); } diff --git a/src/strategy/values/AttackerCountValues.cpp b/src/strategy/values/AttackerCountValues.cpp index 04fac4e7..9faeeb2a 100644 --- a/src/strategy/values/AttackerCountValues.cpp +++ b/src/strategy/values/AttackerCountValues.cpp @@ -4,6 +4,7 @@ #include "AttackerCountValues.h" #include "Playerbots.h" +#include "SharedDefines.h" uint8 MyAttackerCountValue::Calculate() { @@ -13,80 +14,17 @@ uint8 MyAttackerCountValue::Calculate() bool HasAggroValue::Calculate() { Unit* target = GetTarget(); - if (!target) + if (!target) { return true; - + } Unit* victim = target->GetVictim(); - if (!victim) { return true; } - - if (victim->GetGUID() == bot->GetGUID() || (victim->ToPlayer() && botAI->IsMainTank(victim->ToPlayer()))) { + if (victim && (victim->GetGUID() == bot->GetGUID() || (victim->ToPlayer() && botAI->IsMainTank(victim->ToPlayer())))) { return true; } - - // botAI->TellMaster("target: " + target->GetName() + " victim: " + victim->GetName()); - // if (victim->ToPlayer() ) { - // botAI->TellMaster("victim is mt: " + std::to_string(botAI->IsMainTank(victim->ToPlayer()))); - // } return false; - // HostileReference *ref = bot->getHostileRefMgr().getFirst(); - // if (!ref) - // return true; // simulate as target is not atacking anybody yet - - // while( ref ) - // { - // ThreatMgr *threatManager = ref->GetSource(); - // Unit *attacker = threatManager->GetOwner(); - // if (attacker->GetGUID() != target->GetGUID()) { - // ref = ref->next(); - // continue; - // } - // Unit *victim = attacker->GetVictim(); - // if (!victim) { - // return true; - // } - // if ((victim->GetGUID() == bot->GetGUID() || (victim && victim->ToPlayer() && botAI->IsMainTank(victim->ToPlayer()))) && - // target->GetGUID() == attacker->GetGUID()) - // return true; - // ref = ref->next(); - // } - // Unit* target = GetTarget(); - // if (!target) - // return true; - - // HostileReference *ref = bot->getHostileRefMgr().getFirst(); - // if (!ref) - // return true; // simulate as target is not atacking anybody yet - - // while( ref ) - // { - // ThreatMgr* threatMgr = ref->GetSource(); - // Unit* attacker = threatMgr->GetOwner(); - // Unit* victim = attacker->GetVictim(); - // if (victim == bot && target == attacker) - // return true; - - // ref = ref->next(); - // } - - // ref = target->GetThreatMgr().getCurrentVictim(); - // if (ref) - // { - // if (Unit* victim = ref->getTarget()) - // { - // if (Player* pl = victim->ToPlayer()) - // { - // if (botAI->IsMainTank(pl)) - // { - // return true; - // } - // } - // } - // } - - // return false; } uint8 AttackerCountValue::Calculate() diff --git a/src/strategy/values/ItemUsageValue.cpp b/src/strategy/values/ItemUsageValue.cpp index c569c82f..598d321e 100644 --- a/src/strategy/values/ItemUsageValue.cpp +++ b/src/strategy/values/ItemUsageValue.cpp @@ -208,7 +208,7 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto) float oldScore = PlayerbotFactory::CalculateItemScore(oldItemProto->ItemId, bot); if (itemScore || oldScore) { - shouldEquip = itemScore >= oldScore * 1.2; + shouldEquip = itemScore >= oldScore * 1.5; } } diff --git a/src/strategy/values/NearestNpcsValue.cpp b/src/strategy/values/NearestNpcsValue.cpp index 946260a9..0bae5942 100644 --- a/src/strategy/values/NearestNpcsValue.cpp +++ b/src/strategy/values/NearestNpcsValue.cpp @@ -39,3 +39,15 @@ bool NearestVehiclesValue::AcceptUnit(Unit* unit) return true; } + +void NearestTriggersValue::FindUnits(std::list& targets) +{ + Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(bot, bot, range); + Acore::UnitListSearcher searcher(bot, targets, u_check); + Cell::VisitAllObjects(bot, searcher, range); +} + +bool NearestTriggersValue::AcceptUnit(Unit* unit) +{ + return !unit->IsPlayer(); +} \ No newline at end of file diff --git a/src/strategy/values/NearestNpcsValue.h b/src/strategy/values/NearestNpcsValue.h index 2476c794..4ae4a3af 100644 --- a/src/strategy/values/NearestNpcsValue.h +++ b/src/strategy/values/NearestNpcsValue.h @@ -30,4 +30,13 @@ class NearestVehiclesValue : public NearestUnitsValue bool AcceptUnit(Unit* unit) override; }; +class NearestTriggersValue : public NearestUnitsValue +{ + public: + NearestTriggersValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) : NearestUnitsValue(botAI, "nearest triggers", range) { } + + protected: + void FindUnits(std::list& targets) override; + bool AcceptUnit(Unit* unit) override; +}; #endif diff --git a/src/strategy/values/TargetValue.h b/src/strategy/values/TargetValue.h index e56ffaf3..2bdc2cd2 100644 --- a/src/strategy/values/TargetValue.h +++ b/src/strategy/values/TargetValue.h @@ -19,7 +19,7 @@ class FindTargetStrategy FindTargetStrategy(PlayerbotAI* botAI) : result(nullptr), botAI(botAI) { } Unit* GetResult(); - virtual void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) = 0; + virtual void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) = 0; void GetPlayerCount(Unit* creature, uint32* tankCount, uint32* dpsCount); protected: diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index 9df608ac..54ded1ac 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -85,6 +85,7 @@ #include "TankTargetValue.h" #include "ThreatValues.h" #include "TradeValues.h" +#include "Value.h" class PlayerbotAI; @@ -289,6 +290,7 @@ class ValueContext : public NamedObjectContext creators["main tank"] = &ValueContext::main_tank; creators["find target"] = &ValueContext::find_target; creators["boss target"] = &ValueContext::boss_target; + creators["nearest triggers"] = &ValueContext::nearest_triggers; } private: @@ -483,6 +485,7 @@ class ValueContext : public NamedObjectContext static UntypedValue* main_tank(PlayerbotAI* ai) { return new PartyMemberMainTankValue(ai); } static UntypedValue* find_target(PlayerbotAI* ai) { return new FindTargetValue(ai); } static UntypedValue* boss_target(PlayerbotAI* ai) { return new BossTargetValue(ai); } + static UntypedValue* nearest_triggers(PlayerbotAI* ai) { return new NearestTriggersValue(ai); } }; #endif