From 98e46a3d02a5188ab357b729ed170f240b8fad87 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 6 Jun 2023 00:11:35 +0800 Subject: [PATCH] miscs(raid strategy, distance triggers, etc) --- src/strategy/AiObjectContext.cpp | 3 +- src/strategy/StrategyContext.h | 12 + src/strategy/actions/ActionContext.h | 64 + src/strategy/actions/GenericSpellActions.cpp | 8 +- src/strategy/actions/MovementActions.cpp | 75 +- src/strategy/actions/MovementActions.h | 1 + src/strategy/actions/RaidNaxxAction.cpp | 1135 +++++++++++++++++ src/strategy/actions/RaidNaxxAction.h | 318 +++++ src/strategy/actions/ReachTargetActions.cpp | 2 +- src/strategy/generic/RTSCStrategy.h | 2 +- src/strategy/generic/RaidStrategy.cpp | 427 +++++++ src/strategy/generic/RaidStrategy.h | 108 ++ src/strategy/hunter/GenericHunterStrategy.cpp | 3 + src/strategy/hunter/HunterActions.h | 7 +- src/strategy/hunter/HunterAiObjectContext.cpp | 8 +- src/strategy/hunter/HunterTriggers.h | 12 + .../mage/GenericMageNonCombatStrategy.cpp | 8 +- src/strategy/paladin/HealPaladinStrategy.cpp | 3 +- src/strategy/paladin/TankPaladinStrategy.cpp | 4 +- src/strategy/shaman/ShamanActions.h | 42 +- src/strategy/shaman/ShamanAiObjectContext.cpp | 18 +- src/strategy/triggers/GenericTriggers.h | 2 +- src/strategy/triggers/RaidNaxxTrigger.cpp | 151 +++ src/strategy/triggers/RaidNaxxTrigger.h | 212 +++ src/strategy/triggers/RangeTriggers.cpp | 18 +- src/strategy/triggers/RangeTriggers.h | 2 +- src/strategy/triggers/TriggerContext.h | 58 + src/strategy/values/AttackerCountValues.cpp | 2 +- src/strategy/values/PartyMemberToHeal.cpp | 4 +- src/strategy/values/TargetValue.cpp | 49 + src/strategy/values/TargetValue.h | 25 + src/strategy/values/ValueContext.h | 4 + 32 files changed, 2711 insertions(+), 76 deletions(-) create mode 100644 src/strategy/actions/RaidNaxxAction.cpp create mode 100644 src/strategy/actions/RaidNaxxAction.h create mode 100644 src/strategy/generic/RaidStrategy.cpp create mode 100644 src/strategy/generic/RaidStrategy.h create mode 100644 src/strategy/triggers/RaidNaxxTrigger.cpp create mode 100644 src/strategy/triggers/RaidNaxxTrigger.h diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index 95395279..f148c4b1 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -20,7 +20,8 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) strategyContexts.Add(new MovementStrategyContext()); strategyContexts.Add(new AssistStrategyContext()); strategyContexts.Add(new QuestStrategyContext()); - + strategyContexts.Add(new RaidStrategyContext()); + actionContexts.Add(new ActionContext()); actionContexts.Add(new ChatActionContext()); actionContexts.Add(new WorldPacketActionContext()); diff --git a/src/strategy/StrategyContext.h b/src/strategy/StrategyContext.h index 6d4af223..a2fbd4b8 100644 --- a/src/strategy/StrategyContext.h +++ b/src/strategy/StrategyContext.h @@ -47,6 +47,7 @@ #include "UseFoodStrategy.h" #include "UsePotionsStrategy.h" #include "WorldPacketHandlerStrategy.h" +#include "RaidStrategy.h" class StrategyContext : public NamedObjectContext { @@ -220,4 +221,15 @@ class QuestStrategyContext : public NamedObjectContext static Strategy* accept_all_quests(PlayerbotAI* botAI) { return new AcceptAllQuestsStrategy(botAI); } }; +class RaidStrategyContext : public NamedObjectContext +{ + public: + RaidStrategyContext() : NamedObjectContext(false, true) + { + creators["naxx"] = &RaidStrategyContext::naxx; + } + private: + static Strategy* naxx(PlayerbotAI* botAI) { return new RaidNaxxGenericStrategy(botAI); } +}; + #endif diff --git a/src/strategy/actions/ActionContext.h b/src/strategy/actions/ActionContext.h index 3e07f02e..8d87f607 100644 --- a/src/strategy/actions/ActionContext.h +++ b/src/strategy/actions/ActionContext.h @@ -57,6 +57,7 @@ #include "XpGainAction.h" #include "VehicleActions.h" #include "WorldBuffAction.h" +#include "RaidNaxxAction.h" class PlayerbotAI; @@ -221,6 +222,42 @@ class ActionContext : public NamedObjectContext creators["rpg mount anim"] = &ActionContext::rpg_mount_anim; creators["toggle pet spell"] = &ActionContext::toggle_pet_spell; + + // creators["rotate grobbulus"] = &ActionContext::rotate_grobbulus; + // creators["grobbulus move center"] = &ActionContext::grobbulus_move_center; + + creators["heigan dance melee"] = &ActionContext::heigan_dance_melee; + creators["heigan dance ranged"] = &ActionContext::heigan_dance_ranged; + + // creators["thaddius attack nearest pet"] = &ActionContext::thaddius_attack_nearest_pet; + // creators["thaddius melee to place"] = &ActionContext::thaddius_tank_to_place; + // creators["thaddius ranged to place"] = &ActionContext::thaddius_ranged_to_place; + // creators["thaddius move to platform"] = &ActionContext::thaddius_move_to_platform; + // creators["thaddius move polarity"] = &ActionContext::thaddius_move_polarity; + + // creators["razuvious use obedience crystal"] = &ActionContext::razuvious_use_obedience_crystal; + // creators["razuvious target"] = &ActionContext::razuvious_target; + + // creators["horseman attract alternatively"] = &ActionContext::horseman_attract_alternatively; + // creators["horseman attack in order"] = &ActionContext::horseman_attack_in_order; + + // creators["sapphiron ground main tank position"] = &ActionContext::sapphiron_ground_main_tank_position; + // creators["sapphiron ground position"] = &ActionContext::sapphiron_ground_position; + // creators["sapphiron flight position"] = &ActionContext::sapphiron_flight_position; + // creators["sapphiron avoid chill"] = &ActionContext::sapphiron_avoid_chill; + + // creators["kel'thuzad choose target"] = &ActionContext::kelthuzad_choose_target; + // creators["kel'thuzad position"] = &ActionContext::kelthuzad_position; + + // creators["anub'rekhan choose target"] = &ActionContext::anubrekhan_choose_target; + // creators["anub'rekhan position"] = &ActionContext::anubrekhan_position; + + // creators["gluth choose target"] = &ActionContext::gluth_choose_target; + // creators["gluth position"] = &ActionContext::gluth_position; + // creators["gluth slowdown"] = &ActionContext::gluth_slowdown; + + // creators["loatheb position"] = &ActionContext::loatheb_position; + // creators["loatheb choose target"] = &ActionContext::loatheb_choose_target; } private: @@ -382,6 +419,33 @@ class ActionContext : public NamedObjectContext static Action* rpg_mount_anim(PlayerbotAI* botAI) { return new RpgMountAnimAction(botAI); } static Action* toggle_pet_spell(PlayerbotAI* ai) { return new TogglePetSpellAutoCastAction(ai); } + + // static Action* rotate_grobbulus(PlayerbotAI* ai) { return new RotateGrobbulusAction(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); } + // static Action* thaddius_attack_nearest_pet(PlayerbotAI* ai) { return new ThaddiusAttackNearestPetAction(ai); } + // static Action* thaddius_tank_to_place(PlayerbotAI* ai) { return new ThaddiusMeleeToPlaceAction(ai); } + // static Action* thaddius_ranged_to_place(PlayerbotAI* ai) { return new ThaddiusRangedToPlaceAction(ai); } + // static Action* thaddius_move_to_platform(PlayerbotAI* ai) { return new ThaddiusMoveToPlatformAction(ai); } + // static Action* thaddius_move_polarity(PlayerbotAI* ai) { return new ThaddiusMovePolarityAction(ai); } + // static Action* razuvious_target(PlayerbotAI* ai) { return new RazuviousTargetAction(ai); } + // static Action* razuvious_use_obedience_crystal(PlayerbotAI* ai) { return new RazuviousUseObedienceCrystalAction(ai); } + // static Action* horseman_attract_alternatively(PlayerbotAI* ai) { return new HorsemanAttractAlternativelyAction(ai); } + // static Action* horseman_attack_in_order(PlayerbotAI* ai) { return new HorsemanAttactInOrderAction(ai); } + // static Action* sapphiron_ground_main_tank_position(PlayerbotAI* ai) { return new SapphironGroundMainTankPositionAction(ai); } + // 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* 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); } + // static Action* gluth_position(PlayerbotAI* ai) { return new GluthPositionAction(ai); } + // static Action* gluth_slowdown(PlayerbotAI* ai) { return new GluthSlowdownAction(ai); } + // static Action* loatheb_position(PlayerbotAI* ai) { return new LoathebPositionAction(ai); } + // static Action* loatheb_choose_target(PlayerbotAI* ai) { return new LoathebChooseTargetAction(ai); } }; #endif diff --git a/src/strategy/actions/GenericSpellActions.cpp b/src/strategy/actions/GenericSpellActions.cpp index d01105dd..c3812488 100644 --- a/src/strategy/actions/GenericSpellActions.cpp +++ b/src/strategy/actions/GenericSpellActions.cpp @@ -108,11 +108,11 @@ bool CastSpellAction::isUseful() if (!spellTarget->IsInWorld() || spellTarget->GetMapId() != bot->GetMapId()) return false; - float combatReach = bot->GetCombatReach() + spellTarget->GetCombatReach(); - if (!botAI->IsRanged(bot)) - combatReach += 4.0f / 3.0f; + // float combatReach = bot->GetCombatReach() + spellTarget->GetCombatReach(); + // if (!botAI->IsRanged(bot)) + // combatReach += 4.0f / 3.0f; - return spellTarget && AI_VALUE2(bool, "spell cast useful", spell) && sServerFacade->GetDistance2d(bot, spellTarget) <= (range + combatReach); + return spellTarget && AI_VALUE2(bool, "spell cast useful", spell); // && sServerFacade->GetDistance2d(bot, spellTarget) <= (range + combatReach); } CastMeleeSpellAction::CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 0da2153b..19aeb3e2 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -128,6 +128,43 @@ bool MovementAction::MoveToLOS(WorldObject* target, bool ranged) bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, bool react) { + // if (!IsMovingAllowed(mapId, x, y, z)) + // return false; + // bot->UpdateGroundPositionZ(x, y, z); + + // float distance = bot->GetDistance2d(x, y); + // if (distance > sPlayerbotAIConfig->contactDistance) + // { + // WaitForReach(distance); + + // if (bot->IsSitState()) + // bot->SetStandState(UNIT_STAND_STATE_STAND); + + // if (bot->IsNonMeleeSpellCast(true)) + // { + // bot->CastStop(); + // botAI->InterruptSpell(); + // } + + // bool generatePath = !bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && + // !bot->IsFlying() && !bot->IsUnderWater(); + // MotionMaster &mm = *bot->GetMotionMaster(); + // mm.Clear(); + + // // float botZ = bot->GetPositionZ(); + // // if (!bot->InBattleground() && z - botZ > 0.5f && bot->GetDistance2d(x, y) <= 5.0f) + // // { + // // float speed = bot->GetSpeed(MOVE_RUN); + // // mm.MoveJump(x, y, botZ + 0.5f, speed, speed, 1); + // // } + // // else + // mm.MovePoint(mapId, x, y, z, generatePath); + + // AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation()); + // return true; + // } + + // return false; UpdateMovementState(); // LOG_DEBUG("playerbots", "IsMovingAllowed {}", IsMovingAllowed()); if (!IsMovingAllowed()) @@ -507,20 +544,20 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, */ // Clean movement if not already moving the same way. - if (mover->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) - { - mover->StopMoving(); - mover->GetMotionMaster()->Clear(); - } - else - { - mover->GetMotionMaster()->GetDestination(x, y, z); - if (movePosition.distance(WorldPosition(movePosition.getMapId(), x, y, z, 0)) > minDist) - { - mover->StopMoving(); - mover->GetMotionMaster()->Clear(); - } - } + // if (mover->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) + // { + // mover->StopMoving(); + // mover->GetMotionMaster()->Clear(); + // } + // else + // { + // mover->GetMotionMaster()->GetDestination(x, y, z); + // if (movePosition.distance(WorldPosition(movePosition.getMapId(), x, y, z, 0)) > minDist) + // { + // mover->StopMoving(); + // mover->GetMotionMaster()->Clear(); + // } + // } if (totalDistance > maxDist && !detailedMove && !botAI->HasPlayerNearby(&movePosition)) // Why walk if you can fly? { @@ -549,6 +586,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, { bot->SetWalk(masterWalking); bot->GetMotionMaster()->MovePoint(movePosition.getMapId(), movePosition.getX(), movePosition.getY(), movePosition.getZ(), generatePath); + WaitForReach(startPosition.distance(movePosition)); // LOG_DEBUG("playerbots", "Movepoint to ({}, {})", movePosition.getX(), movePosition.getY()); } else @@ -595,6 +633,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, } bot->GetMotionMaster()->MovePoint(movePosition.getMapId(), Position(movePosition.getX(), movePosition.getY(), movePosition.getZ(), 0.f)); + WaitForReach(startPosition.distance(movePosition)); LOG_DEBUG("playerbots", "Movepoint to ({}, {})", movePosition.getX(), movePosition.getY()); } @@ -1221,6 +1260,14 @@ bool MovementAction::MoveAway(Unit* target) return MoveTo(target->GetMapId(), dx, dy, dz); } +bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float distance) +{ + if (bot->GetDistance2d(x, y) <= distance) { + return false; + } + return MoveNear(mapId, x, y, z, distance); +} + bool FleeAction::Execute(Event event) { // return Flee(AI_VALUE(Unit*, "current target")); diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index 56183d20..d04b37da 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -37,6 +37,7 @@ class MovementAction : public Action void ClearIdleState(); void UpdateMovementState(); bool MoveAway(Unit* target); + bool MoveInside(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->followDistance); void CreateWp(Player* wpOwner, float x, float y, float z, float o, uint32 entry, bool important = false); }; diff --git a/src/strategy/actions/RaidNaxxAction.cpp b/src/strategy/actions/RaidNaxxAction.cpp new file mode 100644 index 00000000..752414df --- /dev/null +++ b/src/strategy/actions/RaidNaxxAction.cpp @@ -0,0 +1,1135 @@ + +#include "Playerbots.h" +#include "RaidNaxxAction.h" +#include "RaidStrategy.h" +#include "ScriptedCreature.h" +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_heigan.h" + +using namespace std; + +// bool TryToGetBossAIAction::Execute(Event event) { +// Unit* boss = AI_VALUE(Unit*, "boss target"); +// if (!boss) { +// return false; +// } +// Creature* creature = boss->ToCreature(); +// BossAI* b_ai = dynamic_cast(boss->GetAI()); +// if (!b_ai) { +// return false; +// } +// bool enabled = boss->IsAIEnabled; +// EventMap *eventMap = b_botAI->GetEvents(); +// uint8 phase_mask = eventMap->GetPhaseMask(); +// uint32 bossID = b_botAI->GetBossID(); +// bool isDungeonBoss = creature->IsDungeonBoss(); +// // bot->Yell("boss ai detected.", LANG_UNIVERSAL); +// uint32 next_event_time_1 = eventMap->GetNextEventTime(1); +// uint32 next_event_time_2 = eventMap->GetNextEventTime(2); +// uint32 next_event_time_3 = eventMap->GetNextEventTime(3); +// uint32 next_event_time_4 = eventMap->GetNextEventTime(4); +// uint32 next_event_time_5 = eventMap->GetNextEventTime(5); +// uint32 curr_timer = eventMap->GetTimer(); +// bot->Yell("boss ai detected. phase mask: " + std::to_string(phase_mask) + " ai enabled: " + std::to_string(enabled) + +// " boss id: " + std::to_string(bossID) + " name: " + boss->GetName() + " entry: " + std::to_string(boss->GetEntry()) + +// " guid: " + std::to_string(boss->GetGUID().GetRawValue()) + " isDungeonBoss: " + std::to_string(isDungeonBoss) + +// " event1: " + std::to_string(next_event_time_1) + " event2: " + std::to_string(next_event_time_2) + +// " event3: " + std::to_string(next_event_time_3) + " event4: " + std::to_string(next_event_time_4) + +// " event5: " + std::to_string(next_event_time_5) + " timer: " + std::to_string(curr_timer), LANG_UNIVERSAL); +// return true; + +// } + +// bool GoBehindTheBossAction::Execute(Event event) +// { +// Unit* boss = AI_VALUE(Unit*, "boss target"); +// if (!boss) { +// return false; +// } +// // Position* pos = boss->GetPosition(); +// float orientation = boss->GetOrientation() + M_PI + delta_angle; +// float x = boss->GetPositionX(); +// float y = boss->GetPositionY(); +// float z = boss->GetPositionZ(); +// float rx = x + cos(orientation) * distance; +// float ry = y + sin(orientation) * distance; +// return MoveTo(bot->GetMapId(), rx, ry, z); +// } + +// bool MoveToPointForceAction::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() +// { +// float minDistance = 0; +// int ret = -1; +// for (int i = 0; i < intervals; i++) { +// float w_x = waypoints[i].first, w_y = waypoints[i].second; +// float dis = bot->GetDistance2d(w_x, w_y); +// if (ret == -1 || dis < minDistance) { +// ret = i; +// minDistance = dis; +// } +// } +// return ret; +// } + +// uint32 RotateGrobbulusAction::GetCurrWaypoint() +// { +// Unit* boss = AI_VALUE(Unit*, "boss target"); +// if (!boss) { +// return false; +// } +// BossAI* boss_ai = dynamic_cast(boss->GetAI()); +// EventMap* eventMap = boss_botAI->GetEvents(); +// const uint32 event_time = eventMap->GetNextEventTime(2); +// return (event_time / 15000) % intervals; +// } + +bool HeiganDanceAction::CalculateSafe() { + Unit* boss = AI_VALUE2(Unit*, "find target", "heigan the unclean"); + if (!boss) { + return false; + } + boss_heigan::boss_heiganAI* boss_ai = dynamic_cast(boss->GetAI()); + EventMap* eventMap = &boss_ai->events; + uint32 curr_phase = boss_ai->currentPhase; + uint32 curr_erupt = eventMap->GetNextEventTime(3); + uint32 curr_dance = eventMap->GetNextEventTime(4); + uint32 curr_timer = eventMap->GetTimer(); + if ((curr_phase == PHASE_SLOW_DANCE && curr_dance - curr_timer >= 80000) || (curr_phase == PHASE_FAST_DANCE && curr_dance - curr_timer >= 40000)) { + ResetSafe(); + } else if (curr_erupt != prev_erupt) { + NextSafe(); + } + prev_phase = curr_phase; + prev_erupt = curr_erupt; + return true; +} + +bool HeiganDanceMeleeAction::Execute(Event event) { + CalculateSafe(); + if (prev_phase == PHASE_SLOW_DANCE && botAI->IsMainTank(bot) && !AI_VALUE2(bool, "has aggro", "boss target")) { + return false; + } + // botAI->TellMaster("Let\'s go " + std::to_string(curr_safe)); + return MoveInside(bot->GetMapId(), waypoints[curr_safe].first, waypoints[curr_safe].second, bot->GetPositionZ(), botAI->IsMainTank(bot) ? 0 : 0.5f); +} + +bool HeiganDanceRangedAction::Execute(Event event) { + CalculateSafe(); + if (prev_phase != PHASE_FAST_DANCE) { + return MoveTo(bot->GetMapId(), platform.first, platform.second, 276.54f); + } + botAI->InterruptSpell(); + return MoveInside(bot->GetMapId(), waypoints[curr_safe].first, waypoints[curr_safe].second, bot->GetPositionZ(), 0.5f); +} + +// bool ThaddiusAttackNearestPetAction::isUseful() +// { +// Unit* feugen = AI_VALUE2(Unit*, "find target", "feugen"); +// Unit* stalagg = AI_VALUE2(Unit*, "find target", "stalagg"); +// if (!feugen || !stalagg) { +// return false; +// } +// Unit* result = feugen; +// if (stalagg && (!result || (bot->GetDistance2d(result) > bot->GetDistance2d(stalagg)))) { +// result = stalagg; +// } +// if (AI_VALUE(Unit*, "current target") == result) { +// return false; +// } +// return true; +// } + +// bool ThaddiusAttackNearestPetAction::Execute(Event event) { +// Unit* feugen = AI_VALUE2(Unit*, "find target", "feugen"); +// Unit* stalagg = AI_VALUE2(Unit*, "find target", "stalagg"); +// Unit* result = feugen; +// if (stalagg && (!result || (bot->GetDistance2d(result) > bot->GetDistance2d(stalagg)))) { +// result = stalagg; +// } +// // if (result) { +// // bot->Yell("Goona attack " + result->GetName(), LANG_UNIVERSAL); +// // } +// return Attack(result); +// } + +// bool ThaddiusMeleeToPlaceAction::isUseful() +// { +// if (botAI->IsTank(bot)) { +// Unit* target = AI_VALUE(Unit*, "current target"); +// return target && target->GetVictim() == bot; +// } else { +// return !botAI->IsRanged(bot); +// } +// } + +// bool ThaddiusMeleeToPlaceAction::Execute(Event event) +// { +// Unit* target = AI_VALUE(Unit*, "current target"); +// Unit* feugen = AI_VALUE2(Unit*, "find target", "feugen"); +// Unit* stalagg = AI_VALUE2(Unit*, "find target", "stalagg"); +// // float high_lx = 3455.14f, high_ly = -2927.48f; +// // float high_rx = 3515.00f, high_ry = -2983.09f; +// float high_lx = 3436.14f, high_ly = -2919.98f; +// float high_rx = 3522.94f, high_ry = -3002.60f; +// float high_z = 312.61f; +// if (target == feugen) { +// return MoveTo(bot->GetMapId(), high_rx, high_ry, high_z); +// } else if (target == stalagg) { +// return MoveTo(bot->GetMapId(), high_lx, high_ly, high_z); +// } +// return false; +// } + +// bool ThaddiusRangedToPlaceAction::isUseful() +// { +// return botAI->IsRanged(bot); +// } + +// bool ThaddiusRangedToPlaceAction::Execute(Event event) +// { +// Unit* target = AI_VALUE(Unit*, "current target"); +// Unit* feugen = AI_VALUE2(Unit*, "find target", "feugen"); +// Unit* stalagg = AI_VALUE2(Unit*, "find target", "stalagg"); +// float high_lx = 3441.01f, high_ly = -2942.04f; +// float high_rx = 3500.45f, high_ry = -2997.92f; +// float high_z = 312.61f; +// if (target == feugen) { +// return MoveTo(bot->GetMapId(), high_rx, high_ry, high_z); +// } else if (target == stalagg) { +// return MoveTo(bot->GetMapId(), high_lx, high_ly, high_z); +// } +// return false; +// } + +// bool ThaddiusMoveToPlatformAction::isUseful() +// { +// // float high_z = 312.0f; +// // if (bot->GetPositionZ() < (high_z - 3.0f)) { +// // return false; +// // } +// return true; +// } + +// bool ThaddiusMoveToPlatformAction::Execute(Event event) { +// std::vector> position = { +// // high left +// {3462.99f, -2918.90f}, +// // high right +// {3520.65f, -2976.51f}, +// // low left +// {3471.36f, -2910.65f}, +// // low right +// {3528.80f, -2967.04f}, +// // center +// {3512.19f, -2928.58f}, +// }; +// // float high_lx = 3462.99f, high_ly = -2918.90f; +// // float high_rx = 3520.65f, high_ly = -2976.51f; +// // float low_lx = 3471.36f, low_ly = -2910.65f; +// // float low_rx = 3528.80f, low_ry = -2967.04f; +// float high_z = 312.00f, low_z = 304.02f; +// bool is_left = bot->GetDistance2d(position[0].first, position[0].second) < bot->GetDistance2d(position[1].first, position[1].second); +// if (bot->GetPositionZ() >= (high_z - 3.0f)) { +// if (is_left) { +// if (!MoveTo(bot->GetMapId(), position[0].first, position[0].second, high_z)) { +// bot->TeleportTo(bot->GetMapId(), position[2].first, position[2].second, low_z, bot->GetOrientation()); +// } +// } else { +// if (!MoveTo(bot->GetMapId(), position[1].first, position[1].second, high_z)) { +// bot->TeleportTo(bot->GetMapId(), position[3].first, position[3].second, low_z, bot->GetOrientation()); +// } +// } +// } else { +// return MoveTo(bot->GetMapId(), position[4].first, position[4].second, low_z); +// } +// return true; +// } + +// bool ThaddiusMovePolarityAction::isUseful() { +// return !botAI->IsMainTank(bot) || AI_VALUE2(bool, "has aggro", "current target"); +// } + +// bool ThaddiusMovePolarityAction::Execute(Event event) { +// std::vector> position = { +// // left melee +// {3508.29f, -2920.12f}, +// // left ranged +// {3501.72f, -2913.36f}, +// // right melee +// {3519.74f, -2931.69f}, +// // right ranged +// {3524.32f, -2936.26f}, +// // center melee +// {3512.19f, -2928.58f}, +// // center ranged +// {3504.68f, -2936.68f}, +// }; +// uint32 idx; +// if (botAI->HasAuraWithDuration("negative charge", bot)) { +// idx = 0; +// } else if (botAI->HasAuraWithDuration("positive charge", bot)) { +// idx = 1; +// } else { +// idx = 2; +// } +// idx = idx * 2 + botAI->IsRanged(bot); +// return MoveTo(bot->GetMapId(), position[idx].first, position[idx].second, bot->GetPositionZ()); +// } + +// bool RazuviousUseObedienceCrystalAction::Execute(Event event) +// { + +// if (Unit* charm = bot->GetCharm()) { +// Unit* target = AI_VALUE2(Unit*, "find target", "instructor razuvious"); +// if (!target) { +// return false; +// } +// charm->GetMotionMaster()->MoveChase(target); +// charm->Attack(target, true); +// charm->SetFacingToObject(target); +// Aura* forceObedience = botAI->GetAura("force obedience", charm); +// uint32 duration_time; +// if (!forceObedience) { +// forceObedience = botAI->GetAura("mind control", charm); +// duration_time = 60000; +// } else { +// duration_time = 90000; +// } +// if (!forceObedience) { +// return false; +// } +// if (charm->GetDistance(target) <= 0.51f) { +// // taunt +// bool tauntUseful = true; +// if (forceObedience->GetDuration() <= (duration_time - 5000)) { +// if (target->GetVictim() && botAI->HasAura(29061, target->GetVictim())) { +// tauntUseful = false; +// } +// if (forceObedience->GetDuration() <= 3000) { +// tauntUseful = false; +// } +// } +// if (forceObedience->GetDuration() >= (duration_time - 500)) { +// tauntUseful = false; +// } +// if ( tauntUseful && !charm->GetSpellHistory()->HasCooldown(29060) ) { +// // shield +// if (!charm->GetSpellHistory()->HasCooldown(29061)) { +// charm->CastSpell(charm, 29061, true); +// charm->GetSpellHistory()->AddCooldown(29061, 0, Seconds(30)); +// } +// charm->CastSpell(target, 29060, true); +// charm->GetSpellHistory()->AddCooldown(29060, 0, Seconds(20)); +// } +// // strike +// if (!charm->GetSpellHistory()->HasCooldown(61696)) { +// charm->CastSpell(target, 61696, true); +// charm->GetSpellHistory()->AddCooldown(61696, 0, Seconds(4)); +// } +// } +// } else { +// Difficulty diff = bot->GetRaidDifficulty(); +// if (diff == RAID_DIFFICULTY_10MAN_NORMAL) { +// list npcs = AI_VALUE(list, "nearest npcs"); +// for (list::iterator i = npcs.begin(); i != npcs.end(); i++) +// { +// Creature* unit = botAI->GetCreature(*i); +// if (!unit) { +// continue; +// } +// if (botAI->IsMainTank(bot) && unit->GetSpawnId() != 128352) { +// continue; +// } +// if (!botAI->IsMainTank(bot) && unit->GetSpawnId() != 128353) { +// continue; +// } +// if (MoveTo(unit)) { +// return true; +// } +// Creature *creature = bot->GetNPCIfCanInteractWith(*i, UNIT_NPC_FLAG_SPELLCLICK); +// if (!creature) +// continue; +// creature->HandleSpellClick(bot); +// return true; +// } +// } else { +// list attackers = context->GetValue >("attackers")->Get(); +// Unit* target = NULL; +// for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) { +// Unit* unit = botAI->GetUnit(*i); +// if (!unit) +// continue; +// if (botAI->EqualLowercaseName(unit->GetName(), "death knight understudy")) { +// target = unit; +// break; +// } +// } +// if (target) { +// if (bot->GetDistance2d(target) > sPlayerbotAIConfig.spellDistance) { +// return MoveNear(target, sPlayerbotAIConfig.spellDistance); +// } else { +// return botAI->CastSpell("mind control", target); +// } +// } +// } +// } +// return false; +// } + +// bool RazuviousTargetAction::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; +// if (botAI->IsTank(bot)) { +// target = understudy; +// } else { +// target = razuvious; +// } +// if (AI_VALUE(Unit*, "current target") == target) { +// return false; +// } +// return Attack(target); +// } + +// bool HorsemanAttractAlternativelyAction::Execute(Event event) +// { +// Unit* sir = AI_VALUE2(Unit*, "find target", "sir zeliek"); +// Unit* lady = AI_VALUE2(Unit*, "find target", "lady blaumeux"); +// bool raid25 = bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL; +// if (!sir) { +// return false; +// } +// std::vector> position = { +// // left (sir zeliek) +// {2502.03f, -2910.90f}, +// // right (lady blaumeux) +// {2484.61f, -2947.07f}, +// }; +// float pos_z = 241.27f; +// BossAI* boss_ai = dynamic_cast(sir->GetAI()); +// EventMap* eventMap = boss_botAI->GetEvents(); +// const uint32 timer = eventMap->GetTimer(); +// if (lady) { +// BossAI* lady_ai = dynamic_cast(lady->GetAI()); +// EventMap* ladyEventMap = lady_botAI->GetEvents(); +// const uint32 voidZone = ladyEventMap->GetNextEventTime(5); +// if (!voidZone) { +// voidzone_counter = 0; +// } +// if (voidZone && last_voidzone != voidZone) { +// voidzone_counter = (voidzone_counter + 1) % 8; +// } +// last_voidzone = voidZone; +// } +// int pos_to_go; +// if (!lady) { +// pos_to_go = 0; +// } else { +// // 24 - 15 - 15 - ... +// if (timer <= 9000 || ((timer - 9000) / 67500) % 2 == 0) { +// pos_to_go = 0; +// } else { +// pos_to_go = 1; +// } +// if (botAI->IsRangedDpsAssistantOfIndex(bot, 0) || (raid25 && botAI->IsHealAssistantOfIndex(bot, 1))) { +// pos_to_go = 1 - pos_to_go; +// } +// } +// // bot->Yell("pos to go: " + std::to_string(pos_to_go), LANG_UNIVERSAL); +// float pos_x = position[pos_to_go].first, pos_y = position[pos_to_go].second; +// if (pos_to_go == 1) { +// float offset_x; +// float offset_y; +// if (voidzone_counter < 4) { +// offset_x = voidzone_counter * (-4.5f); +// offset_y = voidzone_counter * (4.5f); +// } +// if (voidzone_counter >= 4) { +// offset_x = (7 - voidzone_counter) * (-4.5f); +// offset_y = (7 - voidzone_counter) * (4.5f); +// offset_x += 4.5f; +// offset_y += 4.5f; +// } +// pos_x += offset_x; +// pos_y += offset_y; +// } +// if (MoveTo(bot->GetMapId(), pos_x, pos_y, pos_z)) { +// return true; +// } +// Unit* attackTarget; +// if (pos_to_go == 0) { +// attackTarget = sir; +// } else { +// attackTarget = lady; +// } +// if (context->GetValue("current target")->Get() != attackTarget) { +// return Attack(attackTarget); +// } +// return false; +// } + +// bool HorsemanAttactInOrderAction::Execute(Event event) +// { +// Unit* target = NULL; +// 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"); +// Unit* sir = AI_VALUE2(Unit*, "find target", "sir zeliek"); +// vector attack_order; +// if (botAI->IsAssistTank(bot)) { +// attack_order = {baron, thane, lady, sir}; +// } else { +// attack_order = {thane, baron, lady, sir}; +// } +// for (Unit* t : attack_order) { +// if (t) { +// target = t; +// break; +// } +// } +// if (target) { +// if (context->GetValue("current target")->Get() == target && botAI->GetCurrentState() == BOT_STATE_COMBAT) { +// return false; +// } +// if (!bot->IsWithinLOSInMap(target)) { +// return MoveNear(target, 10.0f); +// } +// return Attack(target); +// } +// return false; +// } + +// bool SapphironGroundMainTankPositionAction::Execute(Event event) +// { +// return MoveTo(533, 3512.07f, -5274.06f, 137.29f); +// // return MoveTo(533, 3498.58f, -5245.35f, 137.29f); +// } + +// bool SapphironGroundPositionAction::Execute(Event event) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "sapphiron"); +// if (!boss) { +// return false; +// } +// BossAI* boss_ai = dynamic_cast(boss->GetAI()); +// EventMap* eventMap = boss_botAI->GetEvents(); +// const uint32 flight = eventMap->GetNextEventTime(6); +// const uint32 timer = eventMap->GetTimer(); +// if (timer <= 2000 || (flight && flight != last_flight)) { +// reset = true; +// reset_timer = timer; +// } +// last_flight = flight; +// if (reset) { +// // bot->Yell("Let\'s go!", LANG_UNIVERSAL); +// std::pair center = {3517.31f, -5253.74f}; +// // std::pair center = {3498.58f, -5245.35f}; +// // std::pair center = {boss->GetPositionX(), boss->GetPositionY()}; +// uint32 index = botAI->GetGroupSlotIndex(bot); +// // float start_angle = 1.25 * M_PI; +// // float offset_angle = botAI->IsRanged(bot) ? -M_PI * 0.06 * index : -M_PI * 0.3; +// float start_angle = 0.85 * M_PI; +// float offset_angle = M_PI * 0.02 * index; +// float angle = start_angle + offset_angle; +// float distance = 30.0f; +// if (botAI->IsRangedDps(bot)) { +// distance = rand_norm() * 5 + 40.0f; +// } else if (botAI->IsHeal(bot)) { +// distance = rand_norm() * 5 + 25.0f; +// } else { +// distance = rand_norm() * 10; +// } +// if (MoveTo(533, center.first + cos(angle) * distance, center.second + sin(angle) * distance, 137.29f)) { +// return true; +// } +// if (timer - reset_timer >= 2000) { +// reset = false; +// } +// } +// return false; +// } + +// bool SapphironFlightPositionAction::Execute(Event event) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "sapphiron"); +// if (!boss) { +// return false; +// } +// BossAI* boss_ai = dynamic_cast(boss->GetAI()); +// EventMap* eventMap = boss_botAI->GetEvents(); +// const uint32 explosion = eventMap->GetNextEventTime(10); +// const uint32 land = eventMap->GetNextEventTime(11); +// const uint32 timer = eventMap->GetTimer(); +// if (explosion && explosion != last_explosion) { +// move_ice_bolt = true; +// } +// last_explosion = explosion; +// if (land && land > timer) { +// move_ice_bolt = false; +// } +// // bool newexplosion = explosion && explosion != last_explosion; +// if (move_ice_bolt) { +// return MoveToNearestIcebolt(); +// } + +// // before explosion +// std::pair center = {boss->GetPositionX(), boss->GetPositionY()}; +// const uint32 icebolt = eventMap->GetNextEventTime(8); + +// // uint32 runBeforeIcebolt = botAI->IsRanged(bot) ? 1000 : 3000; +// // if ((icebolt <= timer && timer - icebolt <= 7000) || (icebolt >= timer && icebolt - timer <= runBeforeIcebolt)) { +// // std::pair center = {3517.31f, -5253.74f}; +// // uint32 index = botAI->GetGroupSlotIndex(bot); +// // float start_angle = 0.9 * M_PI; +// // float offset_angle = M_PI * 0.025 * index; +// // float angle = start_angle + offset_angle; +// // float distance = 45.0f; +// // if (MoveTo(533, center.first + cos(angle) * distance, center.second + sin(angle) * distance, 137.29f)) { +// // return true; +// // } +// // } +// return false; +// } + +// bool SapphironFlightPositionAction::MoveToNearestIcebolt() +// { +// Group* group = bot->GetGroup(); +// if (!group) { +// return 0; +// } +// Group::MemberSlotList const& slots = group->GetMemberSlots(); +// int counter = 0; +// Player* playerWithIcebolt = NULL; +// float minDistance; +// for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { +// Player* member = ref->GetSource(); +// if (botAI->HasAuraWithDuration("icebolt", member)) { +// if (!playerWithIcebolt || minDistance > bot->GetDistance(member)) { +// playerWithIcebolt = member; +// minDistance = bot->GetDistance(member); +// } +// } +// } +// if (playerWithIcebolt) { +// Unit* boss = AI_VALUE2(Unit*, "find target", "sapphiron"); +// float angle = boss->GetAngle(playerWithIcebolt); +// // bot->Yell("Find icebolt and let\'s move!", LANG_UNIVERSAL); +// return MoveTo(533, playerWithIcebolt->GetPositionX() + cos(angle) * 3.0f, playerWithIcebolt->GetPositionY() + sin(angle) * 3.0f, 137.29f); +// } +// // bot->Yell("No icebolt!", LANG_UNIVERSAL); +// return false; +// } + +// bool SapphironAvoidChillAction::Execute(Event event) +// { +// Aura* aura = botAI->GetAura("chill", bot); +// if (!aura) return false; +// DynamicObject* dyn_obj = aura->GetDynobjOwner(); +// if (!dyn_obj) return false; +// Unit* currentTarget = AI_VALUE(Unit*, "current target"); +// float angle = 0; +// uint32 index = botAI->GetGroupSlotIndex(bot); +// // prevent seg fault +// if (currentTarget) { +// if (botAI->IsRanged(bot)) { +// if (bot->GetExactDist2d(currentTarget) <= 45.0f) { +// angle = bot->GetAngle(dyn_obj) - M_PI + (rand_norm() - 0.5) * M_PI / 2; +// } else { +// if (index % 2 == 0) { +// angle = bot->GetAngle(currentTarget) + M_PI / 2; +// } else { +// angle = bot->GetAngle(currentTarget) - M_PI / 2; +// } +// } +// } else { +// if (index % 3 == 0) { +// angle = bot->GetAngle(currentTarget); +// } else if (index % 3 == 1) { +// angle = bot->GetAngle(currentTarget) + M_PI / 2; +// } else { +// angle = bot->GetAngle(currentTarget) - M_PI / 2; +// } +// } +// } else { +// angle = bot->GetAngle(dyn_obj) - M_PI + (rand_norm() - 0.5) * M_PI / 2; +// } +// // } +// 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; + +// 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 (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); +// } + +// 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 AnubrekhanChooseTargetAction::Execute(Event event) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "anub'rekhan"); +// if (!boss) { +// return false; +// } +// 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; +// vector target_guards; +// for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) +// { +// Unit* unit = botAI->GetUnit(*i); +// if (!unit) +// continue; +// if (botAI->EqualLowercaseName(unit->GetName(), "crypt guard")) { +// target_guards.push_back(unit); +// // target_guard = unit; +// } +// if (botAI->EqualLowercaseName(unit->GetName(), "anub'rekhan")) { +// target_boss = unit; +// } +// } +// // vector targets; +// if (botAI->IsMainTank(bot)) { +// target = target_boss; +// } else { +// if (target_guards.size() == 0) { +// target = target_boss; +// } else { +// if (botAI->IsAssistTank(bot)) { +// for (Unit* t : target_guards) { +// if (target == NULL || (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()) { +// target = t; +// } +// } +// } +// } +// } +// if (context->GetValue("current target")->Get() == target) { +// return false; +// } +// // if (target) { +// // bot->Yell("Let\'s attack " + target->GetName(), LANG_UNIVERSAL); +// // } +// return Attack(target); +// } + +// bool AnubrekhanPositionAction::Execute(Event event) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "anub'rekhan"); +// 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(); +// uint32 locust = eventMap->GetNextEventTime(2); +// uint32 timer = eventMap->GetTimer(); +// if (phase_mask == 2 || (locust && locust - timer <= 5000)) { +// if (botAI->IsMainTank(bot)) { +// uint32 nearest = FindNearestWaypoint(); +// uint32 next_point; +// if (phase_mask == 2) { +// next_point = (nearest + 1) % intervals; +// } else { +// next_point = nearest; +// } +// return MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ()); +// } else { +// return MoveInside(533, 3272.49f, -3476.27f, bot->GetPositionZ(), 3.0f); +// } +// } +// return false; +// } + +// bool GluthChooseTargetAction::Execute(Event event) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "gluth"); +// if (!boss) { +// return false; +// } +// 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; +// vector target_zombies; +// for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) +// { +// Unit* unit = botAI->GetUnit(*i); +// if (!unit) +// continue; +// if (!unit->IsAlive()) { +// continue; +// } +// if (botAI->EqualLowercaseName(unit->GetName(), "zombie chow")) { +// target_zombies.push_back(unit); +// } +// if (botAI->EqualLowercaseName(unit->GetName(), "gluth")) { +// target_boss = unit; +// } +// } +// if (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0)) { +// target = target_boss; +// } else if (botAI->IsAssistTankOfIndex(bot, 1)) { +// for (Unit* t : target_zombies) { +// if (t->GetHealthPct() > 10.0f && t->GetVictim() != bot && t->GetDistance2d(bot) <= 10.0f) { +// target = t; +// break; +// } +// } +// } 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)) { +// target = t; +// } +// } +// } +// if (target == NULL) { +// target = target_boss; +// } +// } +// if (!target || context->GetValue("current target")->Get() == target) { +// return false; +// } +// return Attack(target); +// } + +// bool GluthPositionAction::Execute(Event event) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "gluth"); +// 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(); +// uint32 timer = eventMap->GetTimer(); +// uint32 decimate = eventMap->GetNextEventTime(3); +// bool raid25 = bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL; +// if (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0)) { +// if (AI_VALUE2(bool, "has aggro", "boss target")) { +// if (raid25) { +// return MoveTo(533, 3331.48f, -3109.06f, bot->GetPositionZ()); +// } else { +// return MoveTo(533, 3278.29f, -3162.06f, bot->GetPositionZ()); +// } +// // return MoveTo(533, 3322.52f, -3117.11f, bot->GetPositionZ()); +// // return MoveTo(533, 3285.15f, -3167.02f, bot->GetPositionZ()); +// } +// } else if (botAI->IsAssistTankOfIndex(bot, 1)) { +// if (decimate && decimate - timer <= 3000) { +// return MoveTo(bot->GetMapId(), 3267.34f, -3175.68f, bot->GetPositionZ()); +// } else { +// if (AI_VALUE2(bool, "has aggro", "current target")) { +// uint32 nearest = FindNearestWaypoint(); +// uint32 next_point = (nearest + 1) % intervals; +// return MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ()); +// } +// } +// } else if (botAI->IsRangedDps(bot)) { +// if (raid25) { +// if (botAI->GetClassIndex(bot, CLASS_HUNTER) == 0) { +// // return MoveInside(533, 3301.14f, -3155.33f, bot->GetPositionZ(), 0.0f); +// return MoveInside(533, 3290.68f, -3141.65f, bot->GetPositionZ(), 0.0f); +// } +// if (botAI->GetClassIndex(bot, CLASS_HUNTER) == 1) { +// // return MoveInside(533, 3286.66f, -3141.42f, bot->GetPositionZ(), 0.0f); +// return MoveInside(533, 3300.78f, -3151.98f, bot->GetPositionZ(), 0.0f); +// } +// } +// // return MoveInside(533, 3293.61f, -3149.01f, bot->GetPositionZ(), 10.0f); +// return MoveInside(533, 3301.45f, -3139.29f, bot->GetPositionZ(), 3.0f); +// } else if (botAI->IsHeal(bot)) { +// return MoveInside(533, 3303.09f, -3135.24f, bot->GetPositionZ(), 0.0f); +// } +// return false; +// } + +// bool GluthSlowdownAction::Execute(Event event) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "gluth"); +// if (!boss) { +// return false; +// } +// bool raid25 = bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL; +// if (!raid25) { +// return false; +// } +// BossAI* b_ai = dynamic_cast(boss->GetAI()); +// if (!b_ai) { +// return false; +// } +// EventMap *eventMap = b_botAI->GetEvents(); +// uint8 phase_mask = eventMap->GetPhaseMask(); +// uint32 timer = eventMap->GetTimer(); +// if (timer < 10000) { +// return false; +// } +// switch (bot->getClass()) +// { +// case CLASS_HUNTER: +// return botAI->CastSpell("frost trap", bot); +// break; +// // case CLASS_MAGE: +// // return botAI->CastSpell("frost nova", bot); +// // break; +// default: +// break; +// } +// return false; +// } + +// bool LoathebPositionAction::Execute(Event event) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "loatheb"); +// if (!boss) { +// return false; +// } +// if (botAI->IsTank(bot)) { +// if (AI_VALUE2(bool, "has aggro", "boss target")) { +// return MoveTo(533, 2877.57, -3967.00, bot->GetPositionZ()); +// } +// } else if (botAI->IsRanged(bot)) { +// return MoveInside(533, 2896.96f, -3980.61f, bot->GetPositionZ(), 1.0f); +// } +// return false; +// } + +// bool LoathebChooseTargetAction::Execute(Event event) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "loatheb"); +// if (!boss) { +// return false; +// } +// 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; +// for (list::iterator i = attackers.begin(); i != attackers.end(); ++i) +// { +// Unit* unit = botAI->GetUnit(*i); +// if (!unit) +// continue; +// if (!unit->IsAlive()) { +// continue; +// } +// if (botAI->EqualLowercaseName(unit->GetName(), "spore")) { +// target_spore = unit; +// } +// if (botAI->EqualLowercaseName(unit->GetName(), "loatheb")) { +// target_boss = unit; +// } +// } +// if (target_spore && bot->GetDistance2d(target_spore) <= 1.0f) { +// target = target_spore; +// } else { +// target = target_boss; +// } +// if (!target || context->GetValue("current target")->Get() == target) { +// return false; +// } +// return Attack(target); +// } \ No newline at end of file diff --git a/src/strategy/actions/RaidNaxxAction.h b/src/strategy/actions/RaidNaxxAction.h new file mode 100644 index 00000000..1e9c1157 --- /dev/null +++ b/src/strategy/actions/RaidNaxxAction.h @@ -0,0 +1,318 @@ +#ifndef _PLAYERBOT_RAIDNAXXACTION_H +#define _PLAYERBOT_RAIDNAXXACTION_H + +#include "Action.h" +#include "MovementActions.h" +#include "AttackAction.h" +#include "GenericActions.h" + +// just for test +// class TryToGetBossAIAction : public Action +// { +// public: +// TryToGetBossAIAction(PlayerbotAI* ai) : Action(ai, "try to get boss ai") {} + +// public: +// virtual bool Execute(Event event); +// }; + +// class GoBehindTheBossAction : public MovementAction +// { +// public: +// GoBehindTheBossAction(PlayerbotAI* ai, float distance = 24.0f, float delta_angle = M_PI / 8) : MovementAction(ai, "grobbulus go behind the boss") { +// this->distance = distance; +// this->delta_angle = delta_angle; +// } +// virtual bool Execute(Event event); +// 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 +// { +// 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, 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* ai): RotateAroundTheCenterPointAction(ai, "rotate grobbulus", 3281.23f, -3310.38f, 35.0f, 8, true, M_PI) {} +// virtual bool isUseful() { +// return RotateAroundTheCenterPointAction::isUseful() && ai->IsMainTank(bot) && AI_VALUE2(bool, "has aggro", "boss target"); +// } +// virtual uint32 GetCurrWaypoint(); +// protected: +// }; + +// class GrobblulusMoveCenterAction : public MoveInsideAction +// { +// public: +// GrobblulusMoveCenterAction(PlayerbotAI* ai) : MoveInsideAction(ai, 3281.23f, -3310.38f, 5.0f) {} +// }; + +class HeiganDanceAction : public MovementAction +{ +public: + HeiganDanceAction(PlayerbotAI* ai) : MovementAction(ai, "heigan dance") { + this->prev_phase = 0; + this->prev_erupt = 0; + this->prev_timer = 0; + waypoints.push_back(std::make_pair(2793.58f, -3665.93f)); + waypoints.push_back(std::make_pair(2775.49f, -3674.43f)); + waypoints.push_back(std::make_pair(2762.30f, -3684.59f)); + waypoints.push_back(std::make_pair(2755.99f, -3703.96f)); + } +protected: + bool CalculateSafe(); + void ResetSafe() { curr_safe = 0; curr_dir = 1; } + void NextSafe() { curr_safe += curr_dir; if (curr_safe == 3 || curr_safe == 0) { curr_dir = -curr_dir; } } + uint32 prev_phase, prev_erupt, prev_timer; + uint32 curr_safe, curr_dir; + std::vector> waypoints; +}; + +class HeiganDanceMeleeAction : public HeiganDanceAction +{ +public: + HeiganDanceMeleeAction(PlayerbotAI* ai) : HeiganDanceAction(ai) {} + virtual bool Execute(Event event); +}; + +class HeiganDanceRangedAction : public HeiganDanceAction +{ +public: + HeiganDanceRangedAction(PlayerbotAI* ai) : HeiganDanceAction(ai) { + platform = std::make_pair(2794.26f, -3706.67f); + } + virtual bool Execute(Event event); +protected: + std::pair platform; +}; + +// class ThaddiusAttackNearestPetAction : public AttackAction +// { +// public: +// ThaddiusAttackNearestPetAction(PlayerbotAI* ai) : AttackAction(ai, "thaddius attack nearest pet") {} +// virtual bool Execute(Event event); +// virtual bool isUseful(); +// }; + +// class ThaddiusMeleeToPlaceAction : public MovementAction +// { +// public: +// ThaddiusMeleeToPlaceAction(PlayerbotAI* ai) : MovementAction(ai, "thaddius melee to place") {} +// virtual bool Execute(Event event); +// virtual bool isUseful(); +// }; + +// class ThaddiusRangedToPlaceAction : public MovementAction +// { +// public: +// ThaddiusRangedToPlaceAction(PlayerbotAI* ai) : MovementAction(ai, "thaddius ranged to place") {} +// virtual bool Execute(Event event); +// virtual bool isUseful(); +// }; + +// class ThaddiusMoveToPlatformAction : public MovementAction +// { +// public: +// ThaddiusMoveToPlatformAction(PlayerbotAI* ai) : MovementAction(ai, "thaddius move to platform") {} +// virtual bool Execute(Event event); +// virtual bool isUseful(); +// }; + +// class ThaddiusMovePolarityAction : public MovementAction +// { +// public: +// ThaddiusMovePolarityAction(PlayerbotAI* ai) : MovementAction(ai, "thaddius move polarity") {} +// virtual bool Execute(Event event); +// virtual bool isUseful(); +// }; + +// class RazuviousUseObedienceCrystalAction : public MovementAction +// { +// public: +// RazuviousUseObedienceCrystalAction(PlayerbotAI* ai) : MovementAction(ai, "razuvious use obedience crystal") {} +// virtual bool Execute(Event event); +// }; + +// class RazuviousTargetAction : public AttackAction +// { +// public: +// RazuviousTargetAction(PlayerbotAI* ai) : AttackAction(ai, "razuvious target") {} +// virtual bool Execute(Event event); +// }; + +// class HorsemanAttractAlternativelyAction : public AttackAction +// { +// public: +// HorsemanAttractAlternativelyAction(PlayerbotAI* ai) : AttackAction(ai, "horseman attract alternatively") { +// this->last_voidzone = 0; +// this->voidzone_counter = 0; +// } +// virtual bool Execute(Event event); +// protected: +// uint32 last_voidzone, voidzone_counter; +// }; + +// class HorsemanAttactInOrderAction : public AttackAction +// { +// public: +// HorsemanAttactInOrderAction(PlayerbotAI* ai) : AttackAction(ai, "horseman attact in order") {} +// virtual bool Execute(Event event); +// }; + +// class SapphironGroundMainTankPositionAction : public MovementAction +// { +// public: +// SapphironGroundMainTankPositionAction(PlayerbotAI* ai) : MovementAction(ai, "sapphiron ground main tank position") {} +// virtual bool Execute(Event event); +// }; + +// class SapphironGroundPositionAction : public MovementAction +// { +// public: +// SapphironGroundPositionAction(PlayerbotAI* ai) : MovementAction(ai, "sapphiron ground position") { +// this->reset = 1; +// this->last_flight = 0; +// this->reset_timer = 0; +// } +// virtual bool Execute(Event event); +// protected: +// bool reset; +// uint32 last_flight, reset_timer; +// }; + +// class SapphironFlightPositionAction : public MovementAction +// { +// public: +// SapphironFlightPositionAction(PlayerbotAI* ai) : MovementAction(ai, "sapphiron flight position") { +// this->last_explosion = 0; +// this->move_ice_bolt = 0; +// } +// virtual bool Execute(Event event); +// protected: +// uint32 last_explosion; +// bool move_ice_bolt; +// bool MoveToNearestIcebolt(); +// }; + +// class SapphironAvoidChillAction : public MovementAction +// { +// public: +// SapphironAvoidChillAction(PlayerbotAI* ai) : MovementAction(ai, "sapphiron avoid chill") {} +// 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 KelthuzadPositionAction : public MovementAction +// { +// public: +// KelthuzadPositionAction(PlayerbotAI* ai) : MovementAction(ai, "kel'thuzad position") {} +// virtual bool Execute(Event event); +// }; + +// class AnubrekhanChooseTargetAction : public AttackAction +// { +// public: +// AnubrekhanChooseTargetAction(PlayerbotAI* ai) : AttackAction(ai, "anub'rekhan choose target") {} +// virtual bool Execute(Event event); +// }; + +// class AnubrekhanPositionAction : public RotateAroundTheCenterPointAction +// { +// public: +// AnubrekhanPositionAction(PlayerbotAI* ai) : RotateAroundTheCenterPointAction(ai, "anub'rekhan position", 3272.49f, -3476.27f, 45.0f, 16) {} +// virtual bool Execute(Event event); +// }; + +// class GluthChooseTargetAction : public AttackAction +// { +// public: +// GluthChooseTargetAction(PlayerbotAI* ai) : AttackAction(ai, "gluth choose target") {} +// virtual bool Execute(Event event); +// }; + +// class GluthPositionAction : public RotateAroundTheCenterPointAction +// { +// public: +// GluthPositionAction(PlayerbotAI* ai) : RotateAroundTheCenterPointAction(ai, "gluth position", 3293.61f, -3149.01f, 12.0f, 12) {} +// virtual bool Execute(Event event); +// }; + +// class GluthSlowdownAction : public Action +// { +// public: +// GluthSlowdownAction(PlayerbotAI* ai) : Action(ai, "slowdown") {} +// virtual bool Execute(Event event); +// }; + +// class LoathebPositionAction : public MovementAction +// { +// public: +// LoathebPositionAction(PlayerbotAI* ai) : MovementAction(ai, "loatheb position") {} +// virtual bool Execute(Event event); +// }; + +// class LoathebChooseTargetAction : public AttackAction +// { +// public: +// LoathebChooseTargetAction(PlayerbotAI* ai) : AttackAction(ai, "loatheb choose target") {} +// virtual bool Execute(Event event); +// }; + + +#endif \ No newline at end of file diff --git a/src/strategy/actions/ReachTargetActions.cpp b/src/strategy/actions/ReachTargetActions.cpp index 146ef379..9fc27e71 100644 --- a/src/strategy/actions/ReachTargetActions.cpp +++ b/src/strategy/actions/ReachTargetActions.cpp @@ -36,7 +36,7 @@ ReachSpellAction::ReachSpellAction(PlayerbotAI* botAI) : ReachTargetAction(botAI { } -ReachPartyMemberToHealAction::ReachPartyMemberToHealAction(PlayerbotAI* botAI) : ReachTargetAction(botAI, "reach party member to heal", botAI->GetRange("spell")) +ReachPartyMemberToHealAction::ReachPartyMemberToHealAction(PlayerbotAI* botAI) : ReachTargetAction(botAI, "reach party member to heal", botAI->GetRange("heal")) { } diff --git a/src/strategy/generic/RTSCStrategy.h b/src/strategy/generic/RTSCStrategy.h index 912442b1..4e5aa6f3 100644 --- a/src/strategy/generic/RTSCStrategy.h +++ b/src/strategy/generic/RTSCStrategy.h @@ -15,7 +15,7 @@ class RTSCStrategy : public Strategy RTSCStrategy(PlayerbotAI* botAI); std::string const getName() override { return "RTSC"; } - void InitTriggers(std::vector& triggers); + void InitTriggers(std::vector& triggers) override; }; #endif diff --git a/src/strategy/generic/RaidStrategy.cpp b/src/strategy/generic/RaidStrategy.cpp new file mode 100644 index 00000000..51fdf547 --- /dev/null +++ b/src/strategy/generic/RaidStrategy.cpp @@ -0,0 +1,427 @@ +#include "RaidStrategy.h" +#include "MovementActions.h" +#include "ScriptedCreature.h" +#include "RaidNaxxAction.h" +#include "GenericSpellActions.h" +#include "ChooseTargetActions.h" +#include "ReachTargetActions.h" +#include "UseMeetingStoneAction.h" +#include "FollowActions.h" +#include "ShamanActions.h" +#include "PriestActions.h" +#include "DKActions.h" +#include "HunterActions.h" +#include "MageActions.h" +#include "RogueActions.h" +#include "DruidActions.h" +#include "PaladinActions.h" +#include "WarriorActions.h" +#include +#include "../../../../src/server/scripts/Northrend/Naxxramas/boss_heigan.h" + +float HeiganDanceMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "heigan the unclean"); + if (!boss) { + return 1.0f; + } + + boss_heigan::boss_heiganAI* boss_ai = dynamic_cast(boss->GetAI()); + EventMap* eventMap = &boss_ai->events; + uint32 curr_phase = boss_ai->currentPhase; + uint32 curr_dance = eventMap->GetNextEventTime(4); + uint32 curr_timer = eventMap->GetTimer(); + uint32 curr_erupt = eventMap->GetNextEventTime(3); + if (dynamic_cast(action)) { + return 0.0f; + } + if (curr_phase != PHASE_FAST_DANCE && (int32)curr_dance - curr_timer >= 3000) { + return 1.0f; + } + if (dynamic_cast(action) || dynamic_cast(action)) { + return 1.0f; + } + if (dynamic_cast(action)) + { + uint32 spellId = AI_VALUE2(uint32, "spell id", action->getName()); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + if (!spellInfo) { + return 0.0f; + } + uint32 castTime = spellInfo->CalcCastTime(); + if (castTime == 0) { + return 1.0f; + } + } + return 0.0f; +} + +// float LoathebGenericMultiplier::GetValue(Action* action) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "loatheb"); +// if (!boss) { +// // bot->Yell("Can\'t find Loatheb...", LANG_UNIVERSAL); +// return 1.0f; +// } +// context->GetValue("neglect threat")->Set(true); +// if (botAI->GetCurrentState() == BOT_STATE_COMBAT && +// (dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action))) { +// return 0.0f; +// } +// if (!dynamic_cast(action)) { +// return 1.0f; +// } +// // bot->Yell("It\'s a healing spell!", LANG_UNIVERSAL); +// Aura* aura = botAI->GetAura("necrotic aura", bot); +// if (!aura || aura->GetDuration() <= 1500) { +// return 1.0f; +// } +// return 0.0f; +// } + +// float ThaddiusGenericMultiplier::GetValue(Action* action) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "thaddius"); +// if (!boss) { +// return 1.0f; +// } +// BossAI* boss_ai = dynamic_cast(boss->GetAI()); +// EventMap* eventMap = boss_botAI->GetEvents(); +// uint32 curr_phase = eventMap->GetPhaseMask(); +// // pet phase +// if (curr_phase == 2 && +// ( dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action) )) { +// return 0.0f; +// } +// // die at the same time +// Unit* target = AI_VALUE(Unit*, "current target"); +// Unit* feugen = AI_VALUE2(Unit*, "find target", "feugen"); +// Unit* stalagg = AI_VALUE2(Unit*, "find target", "stalagg"); +// if (curr_phase == 2 && target && feugen && stalagg && +// target->GetHealthPct() <= 40 && +// (feugen->GetHealthPct() >= target->GetHealthPct() + 3 || stalagg->GetHealthPct() >= target->GetHealthPct() + 3)) { +// if (dynamic_cast(action) && !dynamic_cast(action)) { +// return 0.0f; +// } +// } +// // magnetic pull +// // uint32 curr_timer = eventMap->GetTimer(); +// // // if (curr_phase == 2 && bot->GetPositionZ() > 312.5f && dynamic_cast(action)) { +// // if (curr_phase == 2 && (curr_timer % 20000 >= 18000 || curr_timer % 20000 <= 2000) && dynamic_cast(action)) { +// // // MotionMaster *mm = bot->GetMotionMaster(); +// // // mm->Clear(); +// // return 0.0f; +// // } +// // thaddius phase +// if (curr_phase == 8 && dynamic_cast(action)) { +// return 0.0f; +// } +// return 1.0f; +// } + +// float SapphironGenericMultiplier::GetValue(Action* action) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "sapphiron"); +// if (!boss) { +// return 1.0f; +// } +// if (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(); +// uint32 timer = eventMap->GetTimer(); +// uint32 explosion = eventMap->GetNextEventTime(10); +// if (curr_phase == 4 && explosion > timer && +// (dynamic_cast(action) && +// !dynamic_cast(action) && +// !dynamic_cast(action))) { +// return 0.0f; +// } +// return 1.0f; +// } + +// float InstructorRazuviousGenericMultiplier::GetValue(Action* action) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "instructor razuvious"); +// if (!boss) { +// return 1.0f; +// } +// context->GetValue("neglect threat")->Set(true); +// if (botAI->GetCurrentState() == BOT_STATE_COMBAT && +// (dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action))) { +// return 0.0f; +// } +// 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 AnubrekhanGenericMultiplier::GetValue(Action* action) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "anub'rekhan"); +// if (!boss) { +// return 1.0f; +// } +// if ((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 == 2) { +// if (dynamic_cast(action)) { +// return 0.0f; +// } +// } +// return 1.0f; +// } + +// float FourhorsemanGenericMultiplier::GetValue(Action* action) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "sir zeliek"); +// if (!boss) { +// return 1.0f; +// } +// if ((dynamic_cast(action) || +// dynamic_cast(action))) { +// return 0.0f; +// } +// return 1.0f; +// } + +// float GothikGenericMultiplier::GetValue(Action* action) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "gothik the harvester"); +// if (!boss) { +// return 1.0f; +// } +// BossAI* boss_ai = dynamic_cast(boss->GetAI()); +// EventMap* eventMap = boss_botAI->GetEvents(); +// uint32 curr_phase = eventMap->GetPhaseMask(); +// if (curr_phase == 1 && (dynamic_cast(action))) { +// return 0.0f; +// } +// if (curr_phase == 1 && (dynamic_cast(action))) { +// Unit* target = action->GetTarget(); +// if (target == boss) { +// return 0.0f; +// } +// } +// return 1.0f; +// } + +// float GluthGenericMultiplier::GetValue(Action* action) +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "gluth"); +// if (!boss) { +// return 1.0f; +// } +// if ((dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action))) { +// return 0.0f; +// } + +// if (botAI->IsMainTank(bot)) { +// Aura* aura = botAI->GetAuraWithDuration("mortal wound", bot); +// if (aura && aura->GetStackAmount() >= 5) { +// if (dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action) || +// dynamic_cast(action)) { +// return 0.0f; +// } +// } +// } +// return 1.0f; +// } + +void RaidNaxxGenericStrategy::InitTriggers(std::vector &triggers) +{ + // triggers.push_back(new TriggerNode( + // "often", + // NextAction::array(0, new NextAction("try to get boss ai", ACTION_RAID), NULL))); + + // Grobbulus + // triggers.push_back(new TriggerNode( + // "mutating injection", + // NextAction::array(0, new NextAction("grobbulus go behind the boss", ACTION_RAID + 2), NULL))); + + // triggers.push_back(new TriggerNode( + // "mutating injection removed", + // NextAction::array(0, new NextAction("grobbulus move center", ACTION_RAID + 1), NULL))); + + // triggers.push_back(new TriggerNode( + // "grobbulus cloud", + // NextAction::array(0, new NextAction("rotate grobbulus", ACTION_RAID + 1), NULL))); + + // Heigan the Unclean + triggers.push_back(new TriggerNode( + "heigan melee", + NextAction::array(0, new NextAction("heigan dance melee", ACTION_RAID + 1), NULL))); + + triggers.push_back(new TriggerNode( + "heigan ranged", + NextAction::array(0, new NextAction("heigan dance ranged", ACTION_RAID + 1), NULL))); + + // Thaddius + // triggers.push_back(new TriggerNode( + // "thaddius phase pet", + // NextAction::array(0, + // new NextAction("thaddius attack nearest pet", ACTION_RAID + 1), + // new NextAction("thaddius melee to place", ACTION_RAID), + // new NextAction("thaddius ranged to place", ACTION_RAID), + // NULL))); + + // triggers.push_back(new TriggerNode( + // "thaddius phase pet lose aggro", + // NextAction::array(0, new NextAction("taunt spell", ACTION_RAID + 2), NULL))); + + // triggers.push_back(new TriggerNode( + // "thaddius phase transition", + // NextAction::array(0, new NextAction("thaddius move to platform", ACTION_RAID + 1), NULL))); + + // triggers.push_back(new TriggerNode( + // "thaddius phase thaddius", + // NextAction::array(0, new NextAction("thaddius move polarity", ACTION_RAID + 1), NULL))); + + // // Instructor Razuvious + // triggers.push_back(new TriggerNode( + // "razuvious tank", + // NextAction::array(0, new NextAction("razuvious use obedience crystal", ACTION_RAID + 1), NULL))); + + // triggers.push_back(new TriggerNode( + // "razuvious nontank", + // NextAction::array(0, new NextAction("razuvious target", ACTION_RAID + 1), NULL))); + + // // four horseman + // triggers.push_back(new TriggerNode( + // "horseman attractors", + // NextAction::array(0, new NextAction("horseman attract alternatively", ACTION_RAID + 1), NULL))); + + // triggers.push_back(new TriggerNode( + // "horseman except attractors", + // NextAction::array(0, new NextAction("horseman attack in order", ACTION_RAID + 1), NULL))); + + // // sapphiron + // triggers.push_back(new TriggerNode( + // "sapphiron ground main tank", + // NextAction::array(0, new NextAction("sapphiron ground main tank position", ACTION_RAID + 1), NULL))); + + // triggers.push_back(new TriggerNode( + // "sapphiron ground except main tank", + // NextAction::array(0, new NextAction("sapphiron ground position", ACTION_RAID + 1), NULL))); + + // triggers.push_back(new TriggerNode( + // "sapphiron flight", + // NextAction::array(0, new NextAction("sapphiron flight position", ACTION_RAID + 1), NULL))); + + // triggers.push_back(new TriggerNode( + // "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))); + + // // Anub'Rekhan + // triggers.push_back(new TriggerNode( + // "anub'rekhan", + // NextAction::array(0, + // new NextAction("anub'rekhan choose target", ACTION_RAID + 1), + // new NextAction("anub'rekhan position", ACTION_RAID + 1), + // NULL))); + + // // Gluth + // triggers.push_back(new TriggerNode( + // "gluth", + // NextAction::array(0, + // new NextAction("gluth choose target", ACTION_RAID + 1), + // new NextAction("gluth position", ACTION_RAID + 1), + // new NextAction("gluth slowdown", ACTION_RAID), + // NULL))); + + // triggers.push_back(new TriggerNode( + // "gluth main tank mortal wound", + // NextAction::array(0, + // new NextAction("taunt spell", ACTION_RAID + 1), NULL))); + // // Loatheb + // triggers.push_back(new TriggerNode( + // "loatheb", + // NextAction::array(0, + // new NextAction("loatheb position", ACTION_RAID + 1), + // new NextAction("loatheb choose target", ACTION_RAID + 1), + // NULL))); +} + +void RaidNaxxGenericStrategy::InitMultipliers(std::vector &multipliers) +{ + multipliers.push_back(new HeiganDanceMultiplier(botAI)); + // multipliers.push_back(new LoathebGenericMultiplier(ai)); + // 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 AnubrekhanGenericMultiplier(ai)); + // multipliers.push_back(new FourhorsemanGenericMultiplier(ai)); + // multipliers.push_back(new GothikGenericMultiplier(ai)); + // multipliers.push_back(new GluthGenericMultiplier(ai)); +} diff --git a/src/strategy/generic/RaidStrategy.h b/src/strategy/generic/RaidStrategy.h new file mode 100644 index 00000000..3fff6459 --- /dev/null +++ b/src/strategy/generic/RaidStrategy.h @@ -0,0 +1,108 @@ + +#ifndef _PLAYERBOT_RAIDSTRATEGY_H +#define _PLAYERBOT_RAIDSTRATEGY_H + +#include "Multiplier.h" +#include "Strategy.h" + +class HeiganDanceMultiplier : public Multiplier +{ +public: + HeiganDanceMultiplier(PlayerbotAI* ai) : Multiplier(ai, "helgan dance") {} + +public: + virtual float GetValue(Action* action); +}; + +// class LoathebGenericMultiplier : public Multiplier +// { +// public: +// LoathebGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "loatheb generic") {} + +// public: +// virtual float GetValue(Action* action); +// }; + +// class ThaddiusGenericMultiplier : public Multiplier +// { +// public: +// ThaddiusGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "thaddius generic") {} + +// public: +// virtual float GetValue(Action* action); +// }; + +// class SapphironGenericMultiplier : public Multiplier +// { +// public: +// SapphironGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "sapphiron generic") {} + +// public: +// virtual float GetValue(Action* action); +// }; + +// class InstructorRazuviousGenericMultiplier : public Multiplier +// { +// public: +// InstructorRazuviousGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "instructor razuvious generic") {} + +// 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 AnubrekhanGenericMultiplier : public Multiplier +// { +// public: +// AnubrekhanGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "anubrekhan generic") {} + +// public: +// virtual float GetValue(Action* action); +// }; + +// class FourhorsemanGenericMultiplier : public Multiplier +// { +// public: +// FourhorsemanGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "fourhorseman generic") {} + +// public: +// virtual float GetValue(Action* action); +// }; + +// class GothikGenericMultiplier : public Multiplier +// { +// public: +// GothikGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "gothik generic") {} + +// public: +// virtual float GetValue(Action* action); +// }; + +// class GluthGenericMultiplier : public Multiplier +// { +// public: +// GluthGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "gluth generic") {} + +// public: +// virtual float GetValue(Action* action); +// }; + +class RaidNaxxGenericStrategy : public Strategy +{ +public: + RaidNaxxGenericStrategy(PlayerbotAI* ai) : Strategy(ai) {} + virtual std::string const getName() override { return "naxx"; } + virtual void InitTriggers(std::vector &triggers) override; + virtual void InitMultipliers(std::vector &multipliers) override; +}; + + +#endif \ No newline at end of file diff --git a/src/strategy/hunter/GenericHunterStrategy.cpp b/src/strategy/hunter/GenericHunterStrategy.cpp index 3059d07e..fb9fee00 100644 --- a/src/strategy/hunter/GenericHunterStrategy.cpp +++ b/src/strategy/hunter/GenericHunterStrategy.cpp @@ -76,6 +76,9 @@ void GenericHunterStrategy::InitTriggers(std::vector& triggers) // triggers.push_back(new TriggerNode("no ammo", NextAction::array(0, new NextAction("switch to melee", ACTION_HIGH + 1), new NextAction("say::no ammo", ACTION_HIGH), nullptr))); triggers.push_back(new TriggerNode("aspect of the viper", NextAction::array(0, new NextAction("aspect of the viper", ACTION_HIGH), NULL))); triggers.push_back(new TriggerNode("enemy too close for shoot", NextAction::array(0, new NextAction("flee", ACTION_HIGH + 3), NULL))); + triggers.push_back(new TriggerNode("misdirection on main tank", NextAction::array(0, new NextAction("misdirection on main tank", ACTION_HIGH + 7), NULL))); + triggers.push_back(new TriggerNode("tranquilizing shot", NextAction::array(0, new NextAction("tranquilizing shot", 61.0f), NULL))); + } NextAction** HunterBoostStrategy::getDefaultActions() diff --git a/src/strategy/hunter/HunterActions.h b/src/strategy/hunter/HunterActions.h index 5c82e5e6..af04188d 100644 --- a/src/strategy/hunter/HunterActions.h +++ b/src/strategy/hunter/HunterActions.h @@ -67,7 +67,7 @@ END_SPELL_ACTION() BEGIN_RANGED_SPELL_ACTION(CastKillShotAction, "kill shot") END_SPELL_ACTION() -BEGIN_RANGED_SPELL_ACTION(CastTranquilizingShortAction, "tranquilizing shot") +BEGIN_RANGED_SPELL_ACTION(CastTranquilizingShotAction, "tranquilizing shot") END_SPELL_ACTION() class CastAspectOfTheHawkAction : public CastBuffSpellAction @@ -218,4 +218,9 @@ class CastScareBeastCcAction : public CastSpellAction bool Execute(Event event) override; }; +class CastMisdirectionOnMainTankAction : public BuffOnMainTankAction +{ + public: + CastMisdirectionOnMainTankAction(PlayerbotAI* ai) : BuffOnMainTankAction(ai, "misdirection", true) {} +}; #endif diff --git a/src/strategy/hunter/HunterAiObjectContext.cpp b/src/strategy/hunter/HunterAiObjectContext.cpp index ea7a3f71..d6d65c19 100644 --- a/src/strategy/hunter/HunterAiObjectContext.cpp +++ b/src/strategy/hunter/HunterAiObjectContext.cpp @@ -80,6 +80,8 @@ class HunterTriggerFactoryInternal : public NamedObjectContext creators["has ammo"] = &HunterTriggerFactoryInternal::has_ammo; creators["switch to melee"] = &HunterTriggerFactoryInternal::switch_to_melee; creators["switch to ranged"] = &HunterTriggerFactoryInternal::switch_to_ranged; + creators["misdirection on main tank"] = &HunterTriggerFactoryInternal::misdirection_on_main_tank; + creators["tranquilizing shot"] = &HunterTriggerFactoryInternal::remove_enrage; } private: @@ -105,6 +107,8 @@ class HunterTriggerFactoryInternal : public NamedObjectContext static Trigger* has_ammo(PlayerbotAI* botAI) { return new HunterHasAmmoTrigger(botAI); } static Trigger* switch_to_melee(PlayerbotAI* botAI) { return new SwitchToMeleeTrigger(botAI); } static Trigger* switch_to_ranged(PlayerbotAI* botAI) { return new SwitchToRangedTrigger(botAI); } + static Trigger* misdirection_on_main_tank(PlayerbotAI* ai) { return new MisdirectionOnMainTankTrigger(ai); } + static Trigger* remove_enrage(PlayerbotAI* ai) { return new TargetRemoveEnrageTrigger(ai); } }; class HunterAiObjectContextInternal : public NamedObjectContext @@ -152,6 +156,7 @@ class HunterAiObjectContextInternal : public NamedObjectContext creators["tranquilizing shot"] = &HunterAiObjectContextInternal::tranquilizing_shot; creators["steady shot"] = &HunterAiObjectContextInternal::steady_shot; creators["kill shot"] = &HunterAiObjectContextInternal::kill_shot; + creators["misdirection on main tank"] = &HunterAiObjectContextInternal::misdirection_on_main_tank; } private: @@ -191,9 +196,10 @@ class HunterAiObjectContextInternal : public NamedObjectContext static Action* wing_clip(PlayerbotAI* botAI) { return new CastWingClipAction(botAI); } static Action* raptor_strike(PlayerbotAI* botAI) { return new CastRaptorStrikeAction(botAI); } static Action* aspect_of_the_dragonhawk(PlayerbotAI* ai) { return new CastAspectOfTheDragonhawkAction(ai); } - static Action* tranquilizing_shot(PlayerbotAI* ai) { return new CastTranquilizingShortAction(ai); } + static Action* tranquilizing_shot(PlayerbotAI* ai) { return new CastTranquilizingShotAction(ai); } static Action* steady_shot(PlayerbotAI* ai) { return new CastSteadyShotAction(ai); } static Action* kill_shot(PlayerbotAI* ai) { return new CastKillShotAction(ai); } + static Action* misdirection_on_main_tank(PlayerbotAI* ai) { return new CastMisdirectionOnMainTankAction(ai); } }; HunterAiObjectContext::HunterAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) diff --git a/src/strategy/hunter/HunterTriggers.h b/src/strategy/hunter/HunterTriggers.h index c022a05c..46aab8d9 100644 --- a/src/strategy/hunter/HunterTriggers.h +++ b/src/strategy/hunter/HunterTriggers.h @@ -7,6 +7,7 @@ #include "GenericTriggers.h" #include "Trigger.h" +#include "CureTriggers.h" class PlayerbotAI; @@ -149,4 +150,15 @@ class SwitchToMeleeTrigger : public Trigger bool IsActive() override; }; +class MisdirectionOnMainTankTrigger : public BuffOnMainTankTrigger +{ + public: + MisdirectionOnMainTankTrigger(PlayerbotAI* ai) : BuffOnMainTankTrigger(ai, "misdirection", true) {} +}; + +class TargetRemoveEnrageTrigger : public TargetAuraDispelTrigger +{ + public: + TargetRemoveEnrageTrigger(PlayerbotAI* ai) : TargetAuraDispelTrigger(ai, "tranquilizing shot", DISPEL_ENRAGE) {} +}; #endif diff --git a/src/strategy/mage/GenericMageNonCombatStrategy.cpp b/src/strategy/mage/GenericMageNonCombatStrategy.cpp index 96b20b29..f228b11a 100644 --- a/src/strategy/mage/GenericMageNonCombatStrategy.cpp +++ b/src/strategy/mage/GenericMageNonCombatStrategy.cpp @@ -51,8 +51,8 @@ void GenericMageNonCombatStrategy::InitTriggers(std::vector& trigg NonCombatStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode("arcane intellect", NextAction::array(0, new NextAction("arcane intellect", 21.0f), nullptr))); - triggers.push_back(new TriggerNode("no drink", NextAction::array(0, new NextAction("conjure water", 16.0f), nullptr))); - triggers.push_back(new TriggerNode("no food", NextAction::array(0, new NextAction("conjure food", 15.0f), nullptr))); + // triggers.push_back(new TriggerNode("no drink", NextAction::array(0, new NextAction("conjure water", 16.0f), nullptr))); + // triggers.push_back(new TriggerNode("no food", NextAction::array(0, new NextAction("conjure food", 15.0f), nullptr))); triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("apply oil", 1.0f), nullptr))); } @@ -69,6 +69,6 @@ void MageBuffDpsStrategy::InitTriggers(std::vector& triggers) void MageBuffStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("arcane intellect on party", NextAction::array(0, new NextAction("arcane intellect on party", 20.0f), nullptr))); - triggers.push_back(new TriggerNode("give water", NextAction::array(0, new NextAction("give water", 14.0f), nullptr))); - triggers.push_back(new TriggerNode("give food", NextAction::array(0, new NextAction("give food", 13.0f), nullptr))); + // triggers.push_back(new TriggerNode("give water", NextAction::array(0, new NextAction("give water", 14.0f), nullptr))); + // triggers.push_back(new TriggerNode("give food", NextAction::array(0, new NextAction("give food", 13.0f), nullptr))); } diff --git a/src/strategy/paladin/HealPaladinStrategy.cpp b/src/strategy/paladin/HealPaladinStrategy.cpp index e9d98fe4..ec7eda15 100644 --- a/src/strategy/paladin/HealPaladinStrategy.cpp +++ b/src/strategy/paladin/HealPaladinStrategy.cpp @@ -24,8 +24,7 @@ HealPaladinStrategy::HealPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStr NextAction** HealPaladinStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("judgement of light", ACTION_NORMAL + 2), - new NextAction("reach party member to heal", ACTION_NORMAL + 1), nullptr); + return NextAction::array(0, new NextAction("judgement of light", ACTION_NORMAL + 2), nullptr); } void HealPaladinStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/paladin/TankPaladinStrategy.cpp b/src/strategy/paladin/TankPaladinStrategy.cpp index a24f5070..c1b342eb 100644 --- a/src/strategy/paladin/TankPaladinStrategy.cpp +++ b/src/strategy/paladin/TankPaladinStrategy.cpp @@ -54,9 +54,7 @@ void TankPaladinStrategy::InitTriggers(std::vector& triggers) // triggers.push_back(new TriggerNode("judgement", NextAction::array(0, new NextAction("judgement", ACTION_HIGH + 6), nullptr))); // triggers.push_back(new TriggerNode("judgement", NextAction::array(0, new NextAction("exorcism", ACTION_HIGH + 6), nullptr))); // triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("hammer of the righteous", ACTION_HIGH + 8), new NextAction("avenger's shield", ACTION_HIGH + 7), nullptr))); - triggers.push_back(new TriggerNode( - "medium aoe", - NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 1), new NextAction("avenger's shield", ACTION_HIGH + 3), NULL))); + triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 1), new NextAction("avenger's shield", ACTION_HIGH + 3), NULL))); triggers.push_back(new TriggerNode("avenger's shield", NextAction::array(0, new NextAction("avenger's shield", ACTION_HIGH + 7), nullptr))); triggers.push_back(new TriggerNode("lose aggro", NextAction::array(0, new NextAction("hand of reckoning", ACTION_HIGH + 7), nullptr))); triggers.push_back(new TriggerNode("holy shield", NextAction::array(0, new NextAction("holy shield", ACTION_HIGH + 7), nullptr))); diff --git a/src/strategy/shaman/ShamanActions.h b/src/strategy/shaman/ShamanActions.h index 69f03999..26e0a21e 100644 --- a/src/strategy/shaman/ShamanActions.h +++ b/src/strategy/shaman/ShamanActions.h @@ -342,30 +342,30 @@ class CastWindShearOnEnemyHealerAction : public CastSpellOnEnemyHealerAction CastWindShearOnEnemyHealerAction(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, "wind shear") { } }; -class CastCurePoisonAction : public CastCureSpellAction -{ - public: - CastCurePoisonAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure poison") { } -}; +// class CastCurePoisonAction : public CastCureSpellAction +// { +// public: +// CastCurePoisonAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure poison") { } +// }; -class CastCurePoisonOnPartyAction : public CurePartyMemberAction -{ - public: - CastCurePoisonOnPartyAction(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure poison", DISPEL_POISON) { } -}; +// class CastCurePoisonOnPartyAction : public CurePartyMemberAction +// { +// public: +// CastCurePoisonOnPartyAction(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure poison", DISPEL_POISON) { } +// }; -class CastCureDiseaseAction : public CastCureSpellAction -{ - public: - CastCureDiseaseAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure disease") { } -}; +// class CastCureDiseaseAction : public CastCureSpellAction +// { +// public: +// CastCureDiseaseAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure disease") { } +// }; -class CastCureDiseaseOnPartyAction : public CurePartyMemberAction -{ - public: - CastCureDiseaseOnPartyAction(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure disease", DISPEL_DISEASE) { } +// class CastCureDiseaseOnPartyAction : public CurePartyMemberAction +// { +// public: +// CastCureDiseaseOnPartyAction(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure disease", DISPEL_DISEASE) { } - std::string const getName() override { return "cure disease on party"; } -}; +// std::string const getName() override { return "cure disease on party"; } +// }; #endif diff --git a/src/strategy/shaman/ShamanAiObjectContext.cpp b/src/strategy/shaman/ShamanAiObjectContext.cpp index fd2301dd..0673a32e 100644 --- a/src/strategy/shaman/ShamanAiObjectContext.cpp +++ b/src/strategy/shaman/ShamanAiObjectContext.cpp @@ -99,7 +99,7 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext creators["wind shear on enemy healer"] = &ShamanATriggerFactoryInternal::wind_shear_on_enemy_healer; creators["cure poison"] = &ShamanATriggerFactoryInternal::cure_poison; creators["party member cure poison"] = &ShamanATriggerFactoryInternal::party_member_cure_poison; - creators["cure disease"] = &ShamanATriggerFactoryInternal::cure_disease; + // creators["cure disease"] = &ShamanATriggerFactoryInternal::cure_disease; creators["party member cure disease"] = &ShamanATriggerFactoryInternal::party_member_cure_disease; } @@ -192,10 +192,10 @@ class ShamanAiObjectContextInternal : public NamedObjectContext creators["thunderstorm"] = &ShamanAiObjectContextInternal::thunderstorm; creators["heroism"] = &ShamanAiObjectContextInternal::heroism; creators["bloodlust"] = &ShamanAiObjectContextInternal::bloodlust; - creators["cure disease"] = &ShamanAiObjectContextInternal::cure_disease; - creators["cure disease on party"] = &ShamanAiObjectContextInternal::cure_disease_on_party; - creators["cure poison"] = &ShamanAiObjectContextInternal::cure_poison; - creators["cure poison on party"] = &ShamanAiObjectContextInternal::cure_poison_on_party; + // creators["cure disease"] = &ShamanAiObjectContextInternal::cure_disease; + // creators["cure disease on party"] = &ShamanAiObjectContextInternal::cure_disease_on_party; + // creators["cure poison"] = &ShamanAiObjectContextInternal::cure_poison; + // creators["cure poison on party"] = &ShamanAiObjectContextInternal::cure_poison_on_party; } private: @@ -248,10 +248,10 @@ class ShamanAiObjectContextInternal : public NamedObjectContext static Action* lava_lash(PlayerbotAI* botAI) { return new CastLavaLashAction(botAI); } static Action* ancestral_spirit(PlayerbotAI* botAI) { return new CastAncestralSpiritAction(botAI); } static Action* wind_shear_on_enemy_healer(PlayerbotAI* botAI) { return new CastWindShearOnEnemyHealerAction(botAI); } - static Action* cure_poison(PlayerbotAI* botAI) { return new CastCurePoisonAction(botAI); } - static Action* cure_poison_on_party(PlayerbotAI* botAI) { return new CastCurePoisonOnPartyAction(botAI); } - static Action* cure_disease(PlayerbotAI* botAI) { return new CastCureDiseaseAction(botAI); } - static Action* cure_disease_on_party(PlayerbotAI* botAI) { return new CastCureDiseaseOnPartyAction(botAI); } + // static Action* cure_poison(PlayerbotAI* botAI) { return new CastCurePoisonAction(botAI); } + // static Action* cure_poison_on_party(PlayerbotAI* botAI) { return new CastCurePoisonOnPartyAction(botAI); } + // static Action* cure_disease(PlayerbotAI* botAI) { return new CastCureDiseaseAction(botAI); } + // static Action* cure_disease_on_party(PlayerbotAI* botAI) { return new CastCureDiseaseOnPartyAction(botAI); } }; ShamanAiObjectContext::ShamanAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) diff --git a/src/strategy/triggers/GenericTriggers.h b/src/strategy/triggers/GenericTriggers.h index df8b5c0d..e243ca03 100644 --- a/src/strategy/triggers/GenericTriggers.h +++ b/src/strategy/triggers/GenericTriggers.h @@ -450,7 +450,7 @@ class AmmoCountTrigger : public ItemCountTrigger class HasAuraTrigger : public Trigger { public: - HasAuraTrigger(PlayerbotAI* botAI, std::string const spell) : Trigger(botAI, spell) { } + HasAuraTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1) : Trigger(botAI, spell, checkInterval) { } std::string const GetTargetName() override { return "self target"; } bool IsActive() override; diff --git a/src/strategy/triggers/RaidNaxxTrigger.cpp b/src/strategy/triggers/RaidNaxxTrigger.cpp new file mode 100644 index 00000000..78087b2f --- /dev/null +++ b/src/strategy/triggers/RaidNaxxTrigger.cpp @@ -0,0 +1,151 @@ +#include "Playerbots.h" +#include "RaidNaxxTrigger.h" +#include "ScriptedCreature.h" + +// bool MutatingInjectionRemovedTrigger::IsActive() +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", "grobbulus"); +// if (!boss) { +// return false; +// } +// return HasNotAuraTrigger::IsActive() && botAI->GetCurrentState() == BOT_STATE_COMBAT && botAI->IsRanged(bot); +// } + +// bool BossEventTrigger::IsActive() +// { +// Unit* boss = AI_VALUE(Unit*, "boss target"); +// if (!boss || boss->GetEntry() != boss_entry) { +// return false; +// } +// BossAI* boss_ai = dynamic_cast(boss->GetAI()); +// EventMap* eventMap = boss_botAI->GetEvents(); +// const uint32 event_time = eventMap->GetNextEventTime(event_id); +// if (event_time != last_event_time) { +// last_event_time = event_time; +// return true; +// } +// return false; +// } + +// bool BossPhaseTrigger::IsActive() +// { +// Unit* boss = AI_VALUE2(Unit*, "find target", boss_name); +// if (!boss) { +// return false; +// } +// if (this->phase_mask == 0) { +// return true; +// } +// BossAI* boss_ai = dynamic_cast(boss->GetAI()); +// EventMap* eventMap = boss_botAI->GetEvents(); +// uint8 phase_mask = eventMap->GetPhaseMask(); +// // bot->Yell("phase mask detected: " + to_string(phase_mask) + " compare with " + to_string(this->phase_mask), LANG_UNIVERSAL); +// return phase_mask == this->phase_mask; +// } + +// bool GrobbulusCloudTrigger::IsActive() +// { +// Unit* boss = AI_VALUE(Unit*, "boss target"); +// if (!boss || boss->GetEntry() != boss_entry) { +// return false; +// } +// if (!botAI->IsMainTank(bot)) { +// return false; +// } +// // bot->Yell("has aggro on " + boss->GetName() + " : " + to_string(AI_VALUE2(bool, "has aggro", "boss target")), LANG_UNIVERSAL); +// return AI_VALUE2(bool, "has aggro", "boss target"); +// } + +bool HeiganMeleeTrigger::IsActive() +{ + + Unit* heigan = AI_VALUE2(Unit*, "find target", "heigan the unclean"); + if (!heigan) { + return false; + } + return !botAI->IsRanged(bot); +} + +bool HeiganRangedTrigger::IsActive() +{ + Unit* heigan = AI_VALUE2(Unit*, "find target", "heigan the unclean"); + if (!heigan) { + return false; + } + return botAI->IsRanged(bot); +} + +// bool RazuviousTankTrigger::IsActive() +// { +// Difficulty diff = bot->GetRaidDifficulty(); +// if (diff == RAID_DIFFICULTY_10MAN_NORMAL) { +// return BossPhaseTrigger::IsActive() && botAI->IsTank(bot); +// } +// return BossPhaseTrigger::IsActive() && bot->getClass() == CLASS_PRIEST; +// } + +// bool RazuviousNontankTrigger::IsActive() +// { +// Difficulty diff = bot->GetRaidDifficulty(); +// if (diff == RAID_DIFFICULTY_10MAN_NORMAL) { +// return BossPhaseTrigger::IsActive() && !(botAI->IsTank(bot)); +// } +// return BossPhaseTrigger::IsActive() && !(bot->getClass() == CLASS_PRIEST); +// } + +// bool HorsemanAttractorsTrigger::IsActive() +// { +// Difficulty diff = bot->GetRaidDifficulty(); +// if (diff == RAID_DIFFICULTY_25MAN_NORMAL) { +// return BossPhaseTrigger::IsActive() && (botAI->IsRangedDpsAssistantOfIndex(bot, 0) || botAI->IsHealAssistantOfIndex(bot, 0) || +// botAI->IsHealAssistantOfIndex(bot, 1) || botAI->IsHealAssistantOfIndex(bot, 2)); +// } +// return BossPhaseTrigger::IsActive() && (botAI->IsRangedDpsAssistantOfIndex(bot, 0) || botAI->IsHealAssistantOfIndex(bot, 0)); +// } + +// bool HorsemanExceptAttractorsTrigger::IsActive() +// { +// return BossPhaseTrigger::IsActive() && +// !(botAI->IsRangedDpsAssistantOfIndex(bot, 0) || botAI->IsHealAssistantOfIndex(bot, 0) || +// botAI->IsHealAssistantOfIndex(bot, 1) || botAI->IsHealAssistantOfIndex(bot, 2)); +// } + +// bool SapphironGroundMainTankTrigger::IsActive() +// { +// return BossPhaseTrigger::IsActive() && botAI->IsMainTank(bot) && AI_VALUE2(bool, "has aggro", "boss target"); +// } + +// bool SapphironGroundExceptMainTankTrigger::IsActive() +// { +// return BossPhaseTrigger::IsActive() && !botAI->IsMainTank(bot); +// } + +// bool SapphironFlightTrigger::IsActive() +// { +// return BossPhaseTrigger::IsActive(); +// } + +// bool SapphironGroundChillTrigger::IsActive() +// { +// return BossPhaseTrigger::IsActive() && !botAI->IsMainTank(bot) && botAI->HasAura("chill", bot); +// } + +// bool GluthMainTankMortalWoundTrigger::IsActive() +// { +// if (!BossPhaseTrigger::IsActive()) { +// return false; +// } +// if (!botAI->IsAssistTankOfIndex(bot, 0)) { +// return false; +// } +// Unit* mt = AI_VALUE(Unit*, "main tank"); +// if (!mt) { +// return false; +// } +// Aura* aura = botAI->GetAuraWithDuration("mortal wound", mt); +// if (!aura || aura->GetStackAmount() < 5) { +// return false; +// } +// // bot->Yell("Time to taunt!", LANG_UNIVERSAL); +// return true; +// } \ No newline at end of file diff --git a/src/strategy/triggers/RaidNaxxTrigger.h b/src/strategy/triggers/RaidNaxxTrigger.h new file mode 100644 index 00000000..10fbe5c8 --- /dev/null +++ b/src/strategy/triggers/RaidNaxxTrigger.h @@ -0,0 +1,212 @@ + +#ifndef _PLAYERBOT_RAIDNAXXTRIGGER_H +#define _PLAYERBOT_RAIDNAXXTRIGGER_H + +#include "Trigger.h" +#include "PlayerbotAIConfig.h" +#include "GenericTriggers.h" + +using namespace std; + +// class MutatingInjectionTrigger : public HasAuraTrigger +// { +// public: +// MutatingInjectionTrigger(PlayerbotAI* ai): HasAuraTrigger(ai, "mutating injection", 1) {} +// }; + +// class AuraRemovedTrigger : public Trigger +// { +// public: +// AuraRemovedTrigger(PlayerbotAI* ai, string name): Trigger(ai, name, 1) { +// this->prev_check = false; +// } +// virtual bool IsActive() { +// bool check = ai->HasAuraWithDuration(name, bot); +// bool ret = false; +// // bot->Yell(to_string(prev_check) + to_string(check), LANG_UNIVERSAL); +// if (prev_check && !check) { +// ret = true; +// } +// prev_check = check; +// return ret; +// } +// protected: +// bool prev_check; +// }; + +// class MutatingInjectionRemovedTrigger : public HasNotAuraTrigger +// { +// public: +// MutatingInjectionRemovedTrigger(PlayerbotAI* ai): HasNotAuraTrigger(ai, "mutating injection", 1) {} +// virtual bool IsActive(); +// }; + +class BossEventTrigger : public Trigger +{ +public: + BossEventTrigger(PlayerbotAI* ai, uint32 boss_entry, uint32 event_id, string name = "boss event"): Trigger(ai, name, 1) { + this->boss_entry = boss_entry; + this->event_id = event_id; + this->last_event_time = -1; + } + virtual bool IsActive(); +protected: + uint32 boss_entry, event_id, last_event_time; +}; + +class BossPhaseTrigger : public Trigger +{ +public: + BossPhaseTrigger(PlayerbotAI* ai, string boss_name, uint32 phase_mask, string name = "boss event"): Trigger(ai, name, 1) { + this->boss_name = boss_name; + this->phase_mask = phase_mask; + } + virtual bool IsActive(); +protected: + string boss_name; + uint32 phase_mask; +}; + +// class GrobbulusCloudTrigger : public BossEventTrigger +// { +// public: +// GrobbulusCloudTrigger(PlayerbotAI* ai): BossEventTrigger(ai, 15931, 2, "grobbulus cloud event") {} +// virtual bool IsActive(); +// }; + +class HeiganMeleeTrigger : public Trigger +{ +public: + HeiganMeleeTrigger(PlayerbotAI* ai): Trigger(ai, "heigan melee") {} + virtual bool IsActive(); +}; + +class HeiganRangedTrigger : public Trigger +{ +public: + HeiganRangedTrigger(PlayerbotAI* ai): Trigger(ai, "heigan ranged") {} + virtual bool IsActive(); +}; + +// class ThaddiusPhasePetTrigger : public BossPhaseTrigger +// { +// public: +// ThaddiusPhasePetTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "thaddius", 1 << (2 - 1), "thaddius phase pet") {} +// }; + +// class ThaddiusPhasePetLoseAggroTrigger : public ThaddiusPhasePetTrigger +// { +// public: +// ThaddiusPhasePetLoseAggroTrigger(PlayerbotAI* ai) : ThaddiusPhasePetTrigger(ai) {} +// virtual bool IsActive() { +// Unit* target = AI_VALUE(Unit*, "current target"); +// return ThaddiusPhasePetTrigger::IsActive() && ai->IsTank(bot) && target && target->GetVictim() != bot; +// } +// }; + +// class ThaddiusPhaseTransitionTrigger : public BossPhaseTrigger +// { +// public: +// ThaddiusPhaseTransitionTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "thaddius", 1 << (3 - 1), "thaddius phase transition") {} +// }; + +// class ThaddiusPhaseThaddiusTrigger : public BossPhaseTrigger +// { +// public: +// ThaddiusPhaseThaddiusTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "thaddius", 1 << (4 - 1), "thaddius phase thaddius") {} +// }; + +// class RazuviousTankTrigger : public BossPhaseTrigger +// { +// public: +// RazuviousTankTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "instructor razuvious", 0, "razuvious tank") {} +// virtual bool IsActive(); +// }; + +// class RazuviousNontankTrigger : public BossPhaseTrigger +// { +// public: +// RazuviousNontankTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "instructor razuvious", 0, "razuvious nontank") {} +// virtual bool IsActive(); +// }; + +// class HorsemanAttractorsTrigger : public BossPhaseTrigger +// { +// public: +// HorsemanAttractorsTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "sir zeliek", 0, "horseman attractors") {} +// virtual bool IsActive(); +// }; + +// class HorsemanExceptAttractorsTrigger : public BossPhaseTrigger +// { +// public: +// HorsemanExceptAttractorsTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "sir zeliek", 0, "horseman except attractors") {} +// virtual bool IsActive(); +// }; + +// class SapphironGroundMainTankTrigger : public BossPhaseTrigger +// { +// public: +// SapphironGroundMainTankTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "sapphiron", (1 << (2 - 1)), "sapphiron ground main tank") {} +// virtual bool IsActive(); +// }; + +// class SapphironGroundExceptMainTankTrigger : public BossPhaseTrigger +// { +// public: +// SapphironGroundExceptMainTankTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "sapphiron", (1 << (2 - 1)), "sapphiron ground except main tank") {} +// virtual bool IsActive(); +// }; + +// class SapphironFlightTrigger : public BossPhaseTrigger +// { +// public: +// SapphironFlightTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "sapphiron", (1 << (3 - 1)), "sapphiron flight") {} +// virtual bool IsActive(); +// }; + +// class SapphironGroundChillTrigger : public BossPhaseTrigger +// { +// public: +// SapphironGroundChillTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "sapphiron", 0, "sapphiron chill") {} +// virtual bool IsActive(); +// }; + +// class KelthuzadTrigger : public BossPhaseTrigger +// { +// public: +// KelthuzadTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "kel'thuzad", 0, "kel'thuzad trigger") {} +// }; + +// class AnubrekhanTrigger : public BossPhaseTrigger +// { +// public: +// AnubrekhanTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "anub'rekhan", 0, "anub'rekhan trigger") {} +// }; + +// class KelthuzadPhaseTwoTrigger : public BossPhaseTrigger +// { +// public: +// KelthuzadPhaseTwoTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "kel'thuzad", 1 << (2 - 1), "kel'thuzad trigger") {} +// }; + +// class GluthTrigger : public BossPhaseTrigger +// { +// public: +// GluthTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "gluth", 0, "gluth trigger") {} +// }; + +// class GluthMainTankMortalWoundTrigger : public BossPhaseTrigger +// { +// public: +// GluthMainTankMortalWoundTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "gluth", 0, "gluth main tank mortal wound trigger") {} +// virtual bool IsActive(); +// }; + +// class LoathebTrigger : public BossPhaseTrigger +// { +// public: +// LoathebTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "loatheb", 0, "loatheb trigger") {} +// }; + +#endif \ No newline at end of file diff --git a/src/strategy/triggers/RangeTriggers.cpp b/src/strategy/triggers/RangeTriggers.cpp index 49ea6af9..fe992db6 100644 --- a/src/strategy/triggers/RangeTriggers.cpp +++ b/src/strategy/triggers/RangeTriggers.cpp @@ -145,15 +145,15 @@ bool EnemyOutOfSpellRangeTrigger::IsActive() return target && (sServerFacade->GetDistance2d(bot, target) > (distance + combatReach + sPlayerbotAIConfig->contactDistance) || !bot->IsWithinLOSInMap(target)); } -bool EnemyOutOfMeleeTrigger::IsActive() -{ - Unit* target = AI_VALUE(Unit*, GetTargetName()); - if (!target) - return false; +// bool EnemyOutOfMeleeTrigger::IsActive() +// { +// Unit* target = AI_VALUE(Unit*, GetTargetName()); +// if (!target) +// return false; - float targetDistance = sServerFacade->GetDistance2d(bot, target); - return target && (targetDistance > std::max(5.0f, bot->GetCombatReach() + target->GetCombatReach()) || (!bot->IsWithinLOSInMap(target) && targetDistance > 5.0f)); -} +// float targetDistance = sServerFacade->GetDistance2d(bot, target); +// return target && (targetDistance > std::max(5.0f, bot->GetCombatReach() + target->GetCombatReach()) || (!bot->IsWithinLOSInMap(target) && targetDistance > 5.0f)); +// } bool PartyMemberToHealOutOfSpellRangeTrigger::IsActive() { @@ -166,7 +166,7 @@ bool PartyMemberToHealOutOfSpellRangeTrigger::IsActive() } PartyMemberToHealOutOfSpellRangeTrigger::PartyMemberToHealOutOfSpellRangeTrigger(PlayerbotAI* botAI) : - OutOfRangeTrigger(botAI, "party member to heal out of spell range", botAI->GetRange("spell")) + OutOfRangeTrigger(botAI, "party member to heal out of spell range", botAI->GetRange("heal") + 1.0f) { } diff --git a/src/strategy/triggers/RangeTriggers.h b/src/strategy/triggers/RangeTriggers.h index 1545e197..f61f9b16 100644 --- a/src/strategy/triggers/RangeTriggers.h +++ b/src/strategy/triggers/RangeTriggers.h @@ -67,7 +67,7 @@ class EnemyOutOfMeleeTrigger : public OutOfRangeTrigger public: EnemyOutOfMeleeTrigger(PlayerbotAI* botAI) : OutOfRangeTrigger(botAI, "enemy out of melee range", sPlayerbotAIConfig->meleeDistance) { } - bool IsActive() override; + // bool IsActive() override; }; class EnemyOutOfSpellRangeTrigger : public OutOfRangeTrigger diff --git a/src/strategy/triggers/TriggerContext.h b/src/strategy/triggers/TriggerContext.h index df0bdbc1..888803d0 100644 --- a/src/strategy/triggers/TriggerContext.h +++ b/src/strategy/triggers/TriggerContext.h @@ -16,6 +16,7 @@ #include "StuckTriggers.h" #include "TravelTriggers.h" #include "NamedObjectContext.h" +#include "RaidNaxxTrigger.h" class PlayerbotAI; @@ -191,6 +192,38 @@ class TriggerContext : public NamedObjectContext creators["rpg craft"] = &TriggerContext::rpg_craft; creators["rpg trade useful"] = &TriggerContext::rpg_trade_useful; creators["rpg duel"] = &TriggerContext::rpg_duel; + + // creators["mutating injection"] = &TriggerContext::mutating_injection; + // creators["mutating injection removed"] = &TriggerContext::mutating_injection_removed; + // creators["grobbulus cloud"] = &TriggerContext::grobbulus_cloud; + creators["heigan melee"] = &TriggerContext::heigan_melee; + creators["heigan ranged"] = &TriggerContext::heigan_ranged; + + // creators["thaddius phase pet"] = &TriggerContext::thaddius_phase_pet; + // creators["thaddius phase pet lose aggro"] = &TriggerContext::thaddius_phase_pet_lose_aggro; + // creators["thaddius phase transition"] = &TriggerContext::thaddius_phase_transition; + // creators["thaddius phase thaddius"] = &TriggerContext::thaddius_phase_thaddius; + + // creators["razuvious tank"] = &TriggerContext::razuvious_tank; + // creators["razuvious nontank"] = &TriggerContext::razuvious_nontank; + + // creators["horseman attractors"] = &TriggerContext::horseman_attractors; + // creators["horseman except attractors"] = &TriggerContext::horseman_except_attractors; + + // creators["sapphiron ground main tank"] = &TriggerContext::sapphiron_ground_main_tank; + // creators["sapphiron ground except main tank"] = &TriggerContext::sapphiron_ground_except_main_tank; + // creators["sapphiron flight"] = &TriggerContext::sapphiron_flight; + // creators["sapphiron chill"] = &TriggerContext::sapphiron_ground_chill; + + // creators["kel'thuzad"] = &TriggerContext::kelthuzad; + // creators["kel'thuzad phase two"] = &TriggerContext::kelthuzad_phase_two; + + // creators["anub'rekhan"] = &TriggerContext::anubrekhan; + + // creators["gluth"] = &TriggerContext::gluth; + // creators["gluth main tank mortal wound"] = &TriggerContext::gluth_main_tank_mortal_wound; + + // creators["loatheb"] = &TriggerContext::loatheb; } private: @@ -330,6 +363,31 @@ class TriggerContext : public NamedObjectContext static Trigger* rpg_craft(PlayerbotAI* botAI) { return new RpgCraftTrigger(botAI); } static Trigger* rpg_trade_useful(PlayerbotAI* botAI) { return new RpgTradeUsefulTrigger(botAI); } static Trigger* rpg_duel(PlayerbotAI* botAI) { return new RpgDuelTrigger(botAI); } + + // static Trigger* mutating_injection(PlayerbotAI* ai) { return new MutatingInjectionTrigger(ai); } + // static Trigger* mutating_injection_removed(PlayerbotAI* ai) { return new MutatingInjectionRemovedTrigger(ai); } + // static Trigger* grobbulus_cloud(PlayerbotAI* ai) { return new GrobbulusCloudTrigger(ai); } + static Trigger* heigan_melee(PlayerbotAI* ai) { return new HeiganMeleeTrigger(ai); } + static Trigger* heigan_ranged(PlayerbotAI* ai) { return new HeiganRangedTrigger(ai); } + // static Trigger* thaddius_phase_pet(PlayerbotAI* ai) { return new ThaddiusPhasePetTrigger(ai); } + // static Trigger* thaddius_phase_pet_lose_aggro(PlayerbotAI* ai) { return new ThaddiusPhasePetLoseAggroTrigger(ai); } + // static Trigger* thaddius_phase_transition(PlayerbotAI* ai) { return new ThaddiusPhaseTransitionTrigger(ai); } + // static Trigger* thaddius_phase_thaddius(PlayerbotAI* ai) { return new ThaddiusPhaseThaddiusTrigger(ai); } + // static Trigger* razuvious_tank(PlayerbotAI* ai) { return new RazuviousTankTrigger(ai); } + // static Trigger* razuvious_nontank(PlayerbotAI* ai) { return new RazuviousNontankTrigger(ai); } + + // static Trigger* horseman_attractors(PlayerbotAI* ai) { return new HorsemanAttractorsTrigger(ai); } + // static Trigger* horseman_except_attractors(PlayerbotAI* ai) { return new HorsemanExceptAttractorsTrigger(ai); } + // static Trigger* sapphiron_ground_main_tank(PlayerbotAI* ai) { return new SapphironGroundMainTankTrigger(ai); } + // 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_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); } + // static Trigger* gluth_main_tank_mortal_wound(PlayerbotAI* ai) { return new GluthMainTankMortalWoundTrigger(ai); } + // static Trigger* loatheb(PlayerbotAI* ai) { return new LoathebTrigger(ai); } }; #endif diff --git a/src/strategy/values/AttackerCountValues.cpp b/src/strategy/values/AttackerCountValues.cpp index f022ee26..43e548cd 100644 --- a/src/strategy/values/AttackerCountValues.cpp +++ b/src/strategy/values/AttackerCountValues.cpp @@ -38,7 +38,7 @@ bool HasAggroValue::Calculate() { if (Player* pl = victim->ToPlayer()) { - if (botAI->IsTank(pl)) + if (botAI->IsMainTank(pl)) { return true; } diff --git a/src/strategy/values/PartyMemberToHeal.cpp b/src/strategy/values/PartyMemberToHeal.cpp index a7ac06c6..372bb671 100644 --- a/src/strategy/values/PartyMemberToHeal.cpp +++ b/src/strategy/values/PartyMemberToHeal.cpp @@ -45,7 +45,7 @@ Unit* PartyMemberToHeal::Calculate() if (player && Check(player) && player->IsAlive()) { uint8 health = player->GetHealthPct(); if (isRaid || health < sPlayerbotAIConfig->mediumHealth || !IsTargetOfSpellCast(player, predicate)) { - if (player->GetDistance2d(bot) > sPlayerbotAIConfig->spellDistance) { + if (player->GetDistance2d(bot) > sPlayerbotAIConfig->healDistance) { calc.probe(health + 30, player); } else { calc.probe(health + player->GetDistance2d(bot) / 10, player); @@ -75,7 +75,7 @@ bool PartyMemberToHeal::Check(Unit* player) // return player && player != bot && player->GetMapId() == bot->GetMapId() && player->IsInWorld() && // sServerFacade->GetDistance2d(bot, player) < (player->IsPlayer() && botAI->IsTank((Player*)player) ? 50.0f : 40.0f); return player && player->GetMapId() == bot->GetMapId() && - bot->GetDistance2d(player) < sPlayerbotAIConfig->spellDistance * 2 && + bot->GetDistance2d(player) < sPlayerbotAIConfig->healDistance * 2 && bot->IsWithinLOS(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); } diff --git a/src/strategy/values/TargetValue.cpp b/src/strategy/values/TargetValue.cpp index f56bdc99..762e99ec 100644 --- a/src/strategy/values/TargetValue.cpp +++ b/src/strategy/values/TargetValue.cpp @@ -6,6 +6,8 @@ #include "LastMovementValue.h" #include "RtiTargetValue.h" #include "Playerbots.h" +#include "ScriptedCreature.h" +#include "ThreatMgr.h" Unit* FindTargetStrategy::GetResult() { @@ -111,3 +113,50 @@ WorldPosition HomeBindValue::Calculate() { return WorldPosition(bot->m_homebindMapId, bot->m_homebindX, bot->m_homebindY, bot->m_homebindZ, 0.f); } + +Unit* FindTargetValue::Calculate() +{ + if (qualifier == "") { + return NULL; + } + Group* group = bot->GetGroup(); + if (!group) { + return NULL; + } + for (GroupReference *gref = group->GetFirstMember(); gref; gref = gref->next()) { + Player* member = gref->GetSource(); + if (!member) { + continue; + } + HostileReference *ref = member->getHostileRefMgr().getFirst(); + while (ref) + { + ThreatMgr *threatManager = ref->GetSource(); + Unit *unit = threatManager->GetOwner(); + std::wstring wnamepart; + Utf8toWStr(unit->GetName(), wnamepart); + wstrToLower(wnamepart); + if (!qualifier.empty() && qualifier.length() == wnamepart.length() && Utf8FitTo(qualifier, wnamepart)) { + return unit; + } + assert(ref); + ref = ref->next(); + } + } + return nullptr; +} + +void FindBossTargetStrategy::CheckAttacker(Unit* attacker, ThreatMgr* threatManager) +{ + UnitAI* unitAI = attacker->GetAI(); + BossAI* bossAI = dynamic_cast(unitAI); + if (bossAI) { + result = attacker; + } +} + +Unit* BossTargetValue::Calculate() +{ + FindBossTargetStrategy strategy(botAI); + return FindTarget(&strategy); +} \ No newline at end of file diff --git a/src/strategy/values/TargetValue.h b/src/strategy/values/TargetValue.h index 5273c9cc..e56ffaf3 100644 --- a/src/strategy/values/TargetValue.h +++ b/src/strategy/values/TargetValue.h @@ -7,6 +7,7 @@ #include "TravelMgr.h" #include "Value.h" +#include "NamedObjectContext.h" class PlayerbotAI; class ThreatMgr; @@ -97,4 +98,28 @@ class PullTargetValue : public ManualSetValue PullTargetValue(PlayerbotAI* botAI, std::string const name = "pull target") : ManualSetValue(botAI, ObjectGuid::Empty, name) { } }; +class FindTargetValue : public UnitCalculatedValue, public Qualified +{ +public: + FindTargetValue(PlayerbotAI* ai) : UnitCalculatedValue(ai) {} + +public: + Unit* Calculate(); +}; + +class FindBossTargetStrategy : public FindTargetStrategy + { + public: + FindBossTargetStrategy(PlayerbotAI* ai) : FindTargetStrategy(ai) {} + virtual void CheckAttacker(Unit* attacker, ThreatMgr* threatManager); + }; + +class BossTargetValue : public TargetValue, public Qualified +{ +public: + BossTargetValue(PlayerbotAI* ai) : TargetValue(ai) {} + +public: + Unit* Calculate(); +}; #endif diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index a8bcf4ba..9df608ac 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -287,6 +287,8 @@ class ValueContext : public NamedObjectContext creators["has area debuff"] = &ValueContext::has_area_debuff; creators["main tank"] = &ValueContext::main_tank; + creators["find target"] = &ValueContext::find_target; + creators["boss target"] = &ValueContext::boss_target; } private: @@ -479,6 +481,8 @@ class ValueContext : public NamedObjectContext static UntypedValue* has_area_debuff(PlayerbotAI* botAI) { return new HasAreaDebuffValue(botAI); } 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); } }; #endif