diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index 35c2bed0..9ef20498 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -9,8 +9,6 @@ #include "ChatActionContext.h" #include "ChatTriggerContext.h" #include "Playerbots.h" -#include "RaidIccActionContext.h" -#include "RaidIccTriggerContext.h" #include "RaidUlduarTriggerContext.h" #include "RaidUlduarActionContext.h" #include "SharedValueContext.h" @@ -24,6 +22,8 @@ #include "raids/blackwinglair/RaidBwlTriggerContext.h" #include "raids/naxxramas/RaidNaxxActionContext.h" #include "raids/naxxramas/RaidNaxxTriggerContext.h" +#include "raids/icecrown/RaidIccActionContext.h" +#include "raids/icecrown/RaidIccTriggerContext.h" #include "raids/obsidiansanctum/RaidOsActionContext.h" #include "raids/obsidiansanctum/RaidOsTriggerContext.h" #include "raids/eyeofeternity/RaidEoEActionContext.h" @@ -75,6 +75,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) actionContexts.Add(new WotlkDungeonUPActionContext()); actionContexts.Add(new WotlkDungeonCoSActionContext()); actionContexts.Add(new WotlkDungeonFoSActionContext()); + actionContexts.Add(new WotlkDungeonToCActionContext()); triggerContexts.Add(new TriggerContext()); triggerContexts.Add(new ChatTriggerContext()); @@ -102,6 +103,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) triggerContexts.Add(new WotlkDungeonUPTriggerContext()); triggerContexts.Add(new WotlkDungeonCoSTriggerContext()); triggerContexts.Add(new WotlkDungeonFosTriggerContext()); + triggerContexts.Add(new WotlkDungeonToCTriggerContext()); valueContexts.Add(new ValueContext()); diff --git a/src/strategy/dungeons/DungeonStrategyContext.h b/src/strategy/dungeons/DungeonStrategyContext.h index aa266f66..0a6bae84 100644 --- a/src/strategy/dungeons/DungeonStrategyContext.h +++ b/src/strategy/dungeons/DungeonStrategyContext.h @@ -15,6 +15,7 @@ #include "wotlk/utgardepinnacle/UtgardePinnacleStrategy.h" #include "wotlk/cullingofstratholme/CullingOfStratholmeStrategy.h" #include "wotlk/forgeofsouls/ForgeOfSoulsStrategy.h" +#include "wotlk/trialofthechampion/TrialOfTheChampionStrategy.h" /* Full list/TODO: @@ -78,8 +79,8 @@ class DungeonStrategyContext : public NamedObjectContext static Strategy* wotlk_up(PlayerbotAI* botAI) { return new WotlkDungeonUPStrategy(botAI); } static Strategy* wotlk_cos(PlayerbotAI* botAI) { return new WotlkDungeonCoSStrategy(botAI); } static Strategy* wotlk_fos(PlayerbotAI* botAI) { return new WotlkDungeonFoSStrategy(botAI); } + static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonToCStrategy(botAI); } // NYI from here down - static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } static Strategy* wotlk_hor(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } static Strategy* wotlk_pos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h index 75769739..54cb995c 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h @@ -14,7 +14,7 @@ #include "utgardepinnacle/UtgardePinnacleActionContext.h" #include "cullingofstratholme/CullingOfStratholmeActionContext.h" #include "forgeofsouls/ForgeOfSoulsActionContext.h" -// #include "trialofthechampion/TrialOfTheChampionActionContext.h" +#include "trialofthechampion/TrialOfTheChampionActionContext.h" // #include "hallsofreflection/HallsOfReflectionActionContext.h" // #include "pitofsaron/PitOfSaronActionContext.h" diff --git a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h index 8b4e979e..913dd941 100644 --- a/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h +++ b/src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h @@ -14,7 +14,7 @@ #include "utgardepinnacle/UtgardePinnacleTriggerContext.h" #include "cullingofstratholme/CullingOfStratholmeTriggerContext.h" #include "forgeofsouls/ForgeOfSoulsTriggerContext.h" -// #include "trialofthechampion/TrialOfTheChampionTriggerContext.h" +#include "trialofthechampion/TrialOfTheChampionTriggerContext.h" // #include "hallsofreflection/HallsOfReflectionTriggerContext.h" // #include "pitofsaron/PitOfSaronTriggerContext.h" diff --git a/src/strategy/dungeons/wotlk/trialofthechampion/TODO b/src/strategy/dungeons/wotlk/trialofthechampion/TODO deleted file mode 100644 index e69de29b..00000000 diff --git a/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionActionContext.h b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionActionContext.h new file mode 100644 index 00000000..21f877f2 --- /dev/null +++ b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionActionContext.h @@ -0,0 +1,26 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONTOCACTIONCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONTOCACTIONCONTEXT_H + +#include "Action.h" +#include "NamedObjectContext.h" +#include "TrialOfTheChampionActions.h" + +class WotlkDungeonToCActionContext : public NamedObjectContext +{ + public: + WotlkDungeonToCActionContext() { + creators["toc lance"] = &WotlkDungeonToCActionContext::toc_lance; + creators["toc ue lance"] = &WotlkDungeonToCActionContext::toc_ue_lance; + creators["toc mount"] = &WotlkDungeonToCActionContext::toc_mount; + creators["toc mounted"] = &WotlkDungeonToCActionContext::toc_mounted; + creators["toc eadric"] = &WotlkDungeonToCActionContext::toc_eadric; + } + private: + static Action* toc_lance(PlayerbotAI* ai) { return new ToCLanceAction(ai); } + static Action* toc_ue_lance(PlayerbotAI* ai) { return new ToCUELanceAction(ai); } + static Action* toc_mount(PlayerbotAI* ai) { return new ToCMountAction(ai); } + static Action* toc_mounted(PlayerbotAI* ai) { return new ToCMountedAction(ai); } + static Action* toc_eadric(PlayerbotAI* ai) { return new ToCEadricAction(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionActions.cpp b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionActions.cpp new file mode 100644 index 00000000..95ff8a76 --- /dev/null +++ b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionActions.cpp @@ -0,0 +1,267 @@ +#include "Playerbots.h" +#include "TrialOfTheChampionActions.h" +#include "TrialOfTheChampionStrategy.h" +#include "strategy/values/NearestNpcsValue.h" +#include "ObjectAccessor.h" +#include "Timer.h" +#include "Vehicle.h" +#include "GenericSpellActions.h" +#include "GenericActions.h" +#include + + +bool ToCLanceAction::Execute(Event event) +{ + // If already has lance equipped, do nothing + if (bot->HasItemOrGemWithIdEquipped(ITEM_LANCE, 1)) + return false; + + // Store current mainhand item + Item* oldWeapon = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + + // Search inventory for the lance item + Item* lanceItem = nullptr; + + // Check main inventory + for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; slot++) + { + Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); + if (item && item->GetEntry() == ITEM_LANCE) + { + lanceItem = item; + break; + } + } + + // Check bags if not found in main inventory + if (!lanceItem) + { + for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; bag++) + { + Bag* pBag = bot->GetBagByPos(bag); + if (pBag) + { + for (uint8 slot = 0; slot < pBag->GetBagSize(); slot++) + { + Item* item = bot->GetItemByPos(bag, slot); + if (item && item->GetEntry() == ITEM_LANCE) + { + lanceItem = item; + break; + } + } + } + if (lanceItem) + break; + } + } + + // If we found the lance, equip it + if (lanceItem) + { + // Store the lance's current position + uint8 srcBag = lanceItem->GetBagSlot(); + uint8 srcSlot = lanceItem->GetSlot(); + + // First unequip current weapon if it exists + if (oldWeapon) + { + bot->SwapItem(oldWeapon->GetPos(), lanceItem->GetPos()); + } + else + { + bot->EquipItem(EQUIPMENT_SLOT_MAINHAND, lanceItem, true); + } + return true; + } + + if (bot->HasItemCount(ITEM_LANCE, 1)) + return false; + + GameObject* lanceRack = bot->FindNearestGameObject(OBJECT_LANCE_RACK, 100.0f); + if (!lanceRack) + return false; + + if (!lanceRack->IsWithinDistInMap(bot, INTERACTION_DISTANCE)) + return MoveTo(lanceRack, INTERACTION_DISTANCE); + + botAI->RemoveShapeshift(); + bot->GetMotionMaster()->Clear(); + bot->StopMoving(); + lanceRack->Use(bot); + + return false; +} + +bool ToCUELanceAction::Execute(Event event) +{ + if (!bot->HasItemOrGemWithIdEquipped(ITEM_LANCE, 1)) + return false; + + // Call EquipUpgradeAction + EquipUpgradeAction equipUpgradeAction(botAI); + if (!equipUpgradeAction.Execute(event)) + return false; + + return false; +} + +bool ToCMountedAction::Execute(Event event) +{ + Unit* vehicleBase = bot->GetVehicleBase(); + Vehicle* vehicle = bot->GetVehicle(); + if (!vehicleBase || !vehicle) + return false; + + GuidVector attackers = AI_VALUE(GuidVector, "possible targets no los"); + + Unit* target = nullptr; + for (auto i = attackers.begin(); i != attackers.end(); ++i) + { + Unit* unit = botAI->GetUnit(*i); + if (!unit) + continue; + for (uint32 entry : availableTargets) + { + if (unit->GetEntry() == entry) + { + target = unit; + break; + } + } + if (target) + break; + } + + Aura* defendBot = botAI->GetAura("defend", bot, false, true); + if (!defendBot || defendBot->GetStackAmount() < 3) + { + uint32 spellId = AI_VALUE2(uint32, "vehicle spell id", "Defend"); + if (botAI->CanCastVehicleSpell(spellId, target) && botAI->CastVehicleSpell(spellId, target)) + { + vehicleBase->AddSpellCooldown(spellId, 0, 1000); + return true; + } + } + + if (!target) + return false; + + if (target->GetDistance2d(bot) > 5.0f) + { + uint32 spellId = AI_VALUE2(uint32, "vehicle spell id", "Charge"); + if (botAI->CanCastVehicleSpell(spellId, target) && botAI->CastVehicleSpell(spellId, target)) + { + vehicleBase->AddSpellCooldown(spellId, 0, 1000); + return true; + } + } + + Aura* defendTarget = botAI->GetAura("defend", target, false, false); + if (!defendTarget) + {} + else + { + uint32 spellId = AI_VALUE2(uint32, "vehicle spell id", "Shield-Breaker"); + if (botAI->CanCastVehicleSpell(spellId, target) && botAI->CastVehicleSpell(spellId, target)) + { + vehicleBase->AddSpellCooldown(spellId, 0, 1000); + return true; + } + } + + uint32 spellId = AI_VALUE2(uint32, "vehicle spell id", "Thrust"); + if (botAI->CanCastVehicleSpell(spellId, target) && botAI->CastVehicleSpell(spellId, target)) + { + vehicleBase->AddSpellCooldown(spellId, 0, 1000); + return true; + } + + return false; +} + +bool ToCMountAction::Execute(Event event) +{ + // do not switch vehicles yet + if (bot->GetVehicle()) + return false; + + Unit* vehicleToEnter = nullptr; + GuidVector npcs = AI_VALUE(GuidVector, "nearest vehicles"); + for (GuidVector::iterator i = npcs.begin(); i != npcs.end(); i++) + { + Unit* vehicleBase = botAI->GetUnit(*i); + if (!vehicleBase) + continue; + + if (vehicleBase->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + continue; + + if (!vehicleBase->IsFriendlyTo(bot)) + continue; + + if (!vehicleBase->GetVehicleKit() || !vehicleBase->GetVehicleKit()->GetAvailableSeatCount()) + continue; + + uint32 entry = vehicleBase->GetEntry(); + if (entry != NPC_ARGENT_BATTLEWORG && entry != NPC_ARGENT_WARHORSE) + continue; + + if (!vehicleToEnter || bot->GetExactDist(vehicleToEnter) > bot->GetExactDist(vehicleBase)) + vehicleToEnter = vehicleBase; + } + + if (!vehicleToEnter) + return false; + + if (EnterVehicle(vehicleToEnter, true)) + return true; + + return false; +} + +bool ToCMountAction::EnterVehicle(Unit* vehicleBase, bool moveIfFar) +{ + float dist = bot->GetDistance(vehicleBase); + + if (dist > INTERACTION_DISTANCE && !moveIfFar) + return false; + + if (dist > INTERACTION_DISTANCE) + return MoveTo(vehicleBase); + + botAI->RemoveShapeshift(); + + bot->GetMotionMaster()->Clear(); + bot->StopMoving(); + vehicleBase->HandleSpellClick(bot); + + if (!bot->IsOnVehicle(vehicleBase)) + return false; + + // dismount because bots can enter vehicle on mount + WorldPacket emptyPacket; + bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket); + return true; +} + +bool ToCEadricAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "eadric the pure"); + if (!boss) + return false; + + // If Eadric is casting Radiance, face the opposite direction + if (boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_RADIANCE)) + { + // Calculate the opposite direction + float angle = bot->GetAngle(boss); + float newAngle = Position::NormalizeOrientation(angle + M_PI); // Add 180 degrees (PI radians) + + // Set the bot's orientation to face away from Eadric + bot->SetFacingTo(newAngle); + return true; + } + + return false; +} diff --git a/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionActions.h b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionActions.h new file mode 100644 index 00000000..ab2c18ae --- /dev/null +++ b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionActions.h @@ -0,0 +1,59 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONTOCACTIONS_H +#define _PLAYERBOT_WOTLKDUNGEONTOCACTIONS_H + +#include "Action.h" +#include "AttackAction.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "TrialOfTheChampionTriggers.h" +#include "MovementActions.h" +#include "LastMovementValue.h" +#include "ObjectGuid.h" +#include "PlayerbotAIConfig.h" +#include "ScriptedCreature.h" +#include "SharedDefines.h" +#include "EquipAction.h" +#include "Event.h" +#include "ItemCountValue.h" +#include "ItemUsageValue.h" +#include "StatsWeightCalculator.h" + +class ToCLanceAction : public AttackAction +{ +public: + ToCLanceAction(PlayerbotAI* ai) : AttackAction(ai, "toc lance") {} + bool Execute(Event event) override; +}; + +class ToCUELanceAction : public AttackAction +{ +public: + ToCUELanceAction(PlayerbotAI* ai) : AttackAction(ai, "toc ue lance") {} + bool Execute(Event event) override; +}; + +class ToCMountedAction : public Action +{ +public: + ToCMountedAction(PlayerbotAI* botAI, std::string const name = "toc mounted") + : Action(botAI, name) {} + bool Execute(Event event) override; +}; + +class ToCMountAction : public MovementAction +{ +public: + ToCMountAction(PlayerbotAI* botAI, std::string const name = "toc mount") + : MovementAction(botAI, name) {} + bool Execute(Event event) override; + bool EnterVehicle(Unit* vehicleBase, bool moveIfFar); +}; + +class ToCEadricAction : public MovementAction +{ +public: + ToCEadricAction(PlayerbotAI* botAI, std::string const name = "toc eadric") + : MovementAction(botAI, name) {} + bool Execute(Event event) override; +}; +#endif diff --git a/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionMultipliers.cpp b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionMultipliers.cpp new file mode 100644 index 00000000..c090ef68 --- /dev/null +++ b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionMultipliers.cpp @@ -0,0 +1,9 @@ +#include "TrialOfTheChampionMultipliers.h" +#include "TrialOfTheChampionActions.h" +#include "GenericSpellActions.h" +#include "ChooseTargetActions.h" +#include "MovementActions.h" +#include "TrialOfTheChampionTriggers.h" +#include "Action.h" + +//float tocMultiplier::GetValue(Action* action) { return 1.0f; } diff --git a/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionMultipliers.h b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionMultipliers.h new file mode 100644 index 00000000..bf941263 --- /dev/null +++ b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionMultipliers.h @@ -0,0 +1,15 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONTOCMULTIPLIERS_H +#define _PLAYERBOT_WOTLKDUNGEONTOCMULTIPLIERS_H + +#include "Multiplier.h" + +/* class tocMultiplier : public Multiplier +{ + public: + tocMultiplier(PlayerbotAI* ai) : Multiplier(ai, "toc") {} + + public: + virtual float GetValue(Action* action); +}; +*/ +#endif diff --git a/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionStrategy.cpp b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionStrategy.cpp new file mode 100644 index 00000000..4c439e18 --- /dev/null +++ b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionStrategy.cpp @@ -0,0 +1,23 @@ +#include "TrialOfTheChampionStrategy.h" +#include "TrialOfTheChampionMultipliers.h" + + +void WotlkDungeonToCStrategy::InitTriggers(std::vector &triggers) +{ + triggers.push_back(new TriggerNode("toc lance", + NextAction::array(0, new NextAction("toc lance", ACTION_RAID + 5), nullptr))); + triggers.push_back(new TriggerNode("toc ue lance", + NextAction::array(0, new NextAction("toc ue lance", ACTION_RAID + 2), nullptr))); + triggers.push_back(new TriggerNode("toc mount near", + NextAction::array(0, new NextAction("toc mount", ACTION_RAID + 4), nullptr))); + triggers.push_back(new TriggerNode("toc mounted", + NextAction::array(0, new NextAction("toc mounted", ACTION_RAID + 6), nullptr))); + triggers.push_back(new TriggerNode("toc eadric", + NextAction::array(0, new NextAction("toc eadric", ACTION_RAID + 3), nullptr))); + +} + +void WotlkDungeonToCStrategy::InitMultipliers(std::vector &multipliers) +{ + //multipliers.push_back(new toc...); if needed in the future +} diff --git a/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionStrategy.h b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionStrategy.h new file mode 100644 index 00000000..12416d5a --- /dev/null +++ b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionStrategy.h @@ -0,0 +1,18 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONTOCSTRATEGY_H +#define _PLAYERBOT_WOTLKDUNGEONTOCSTRATEGY_H + +#include "AiObjectContext.h" +#include "Multiplier.h" +#include "Strategy.h" +#include "TrialOfTheChampionMultipliers.h" + +class WotlkDungeonToCStrategy : public Strategy +{ +public: + WotlkDungeonToCStrategy(PlayerbotAI* ai) : Strategy(ai) {} + virtual std::string const getName() override { return "trial of the champion"; } + virtual void InitTriggers(std::vector &triggers) override; + virtual void InitMultipliers(std::vector &multipliers) override; +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionTriggerContext.h b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionTriggerContext.h new file mode 100644 index 00000000..fe4f7883 --- /dev/null +++ b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionTriggerContext.h @@ -0,0 +1,27 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONTOCTRIGGERCONTEXT_H +#define _PLAYERBOT_WOTLKDUNGEONTOCTRIGGERCONTEXT_H + +#include "NamedObjectContext.h" +#include "AiObjectContext.h" +#include "TrialOfTheChampionTriggers.h" + +class WotlkDungeonToCTriggerContext : public NamedObjectContext +{ + public: + WotlkDungeonToCTriggerContext() + { + creators["toc lance"] = &WotlkDungeonToCTriggerContext::toc_lance; + creators["toc ue lance"] = &WotlkDungeonToCTriggerContext::toc_ue_lance; + creators["toc mount near"] = &WotlkDungeonToCTriggerContext::toc_mount_near; + creators["toc mounted"] = &WotlkDungeonToCTriggerContext::toc_mounted; + creators["toc eadric"] = &WotlkDungeonToCTriggerContext::toc_eadric; + } + private: + static Trigger* toc_lance(PlayerbotAI* ai) { return new ToCLanceTrigger(ai); } + static Trigger* toc_ue_lance(PlayerbotAI* ai) { return new ToCUELanceTrigger(ai); } + static Trigger* toc_mount_near(PlayerbotAI* ai) { return new ToCMountNearTrigger(ai); } + static Trigger* toc_mounted(PlayerbotAI* ai) { return new ToCMountedTrigger(ai); } + static Trigger* toc_eadric(PlayerbotAI* ai) { return new ToCEadricTrigger(ai); } +}; + +#endif diff --git a/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionTriggers.cpp b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionTriggers.cpp new file mode 100644 index 00000000..81cfefec --- /dev/null +++ b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionTriggers.cpp @@ -0,0 +1,85 @@ +#include "Playerbots.h" +#include "TrialOfTheChampionTriggers.h" +#include "AiObject.h" +#include "AiObjectContext.h" + + +bool ToCLanceTrigger::IsActive() +{ + if (bot->GetVehicle()) + return false; + + Unit* mount1 = bot->FindNearestCreature(NPC_ARGENT_WARHORSE, 100.0f); + if (!mount1) + return false; + + Unit* mount2 = bot->FindNearestCreature(NPC_ARGENT_BATTLEWORG, 100.0f); + if (!mount2) + return false; + + if (!bot->HasItemOrGemWithIdEquipped(ITEM_LANCE, 1)) + return true; + + if (bot->HasItemCount(ITEM_LANCE, 1)) + return false; + + // Find the nearest spear + GameObject* lanceRack = bot->FindNearestGameObject(OBJECT_LANCE_RACK, 100.0f); + if (!lanceRack) + return false; + + return true; +} + +bool ToCUELanceTrigger::IsActive() +{ + if (bot->GetVehicle()) + return false; + + Unit* mount1 = bot->FindNearestCreature(NPC_ARGENT_WARHORSE, 100.0f); + if (!mount1 && bot->HasItemOrGemWithIdEquipped(ITEM_LANCE, 1)) + return true; + + Unit* mount2 = bot->FindNearestCreature(NPC_ARGENT_BATTLEWORG, 100.0f); + if (!mount2 && bot->HasItemOrGemWithIdEquipped(ITEM_LANCE, 1)) + return true; + + return false; +} + +bool ToCMountedTrigger::IsActive() +{ + Unit* vehicleBase = bot->GetVehicleBase(); + Vehicle* vehicle = bot->GetVehicle(); + if (!vehicleBase || !vehicle) + return false; + + uint32 entry = vehicleBase->GetEntry(); + return entry == NPC_ARGENT_BATTLEWORG || entry == NPC_ARGENT_WARHORSE; +} + +bool ToCMountNearTrigger::IsActive() +{ + if (bot->GetVehicle()) + return false; + + Unit* mount1 = bot->FindNearestCreature(NPC_ARGENT_WARHORSE, 100.0f); + if (!mount1) + return false; + + Unit* mount2 = bot->FindNearestCreature(NPC_ARGENT_BATTLEWORG, 100.0f); + if (!mount2) + return false; + + return true; +} + +bool ToCEadricTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "eadric the pure"); + if (!boss) + return false; + + return true; +} + diff --git a/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionTriggers.h b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionTriggers.h new file mode 100644 index 00000000..c92cd878 --- /dev/null +++ b/src/strategy/dungeons/wotlk/trialofthechampion/TrialOfTheChampionTriggers.h @@ -0,0 +1,125 @@ +#ifndef _PLAYERBOT_WOTLKDUNGEONTOCTRIGGERS_H +#define _PLAYERBOT_WOTLKDUNGEONTOCTRIGGERS_H + +#include "Trigger.h" +#include "PlayerbotAIConfig.h" +#include "GenericTriggers.h" +#include "DungeonStrategyUtils.h" + +enum TocC_IDs +{ + // Spells + + // Horse + SPELL_DEFEND = 66482, + + //Eadric + SPELL_RADIANCE = 66935, + + + // Objects + OBJECT_LANCE_RACK = 196398, + + + // Items + ITEM_LANCE = 46106, + + + // Vehicles + NPC_ARGENT_WARHORSE = 35644, + NPC_ARGENT_BATTLEWORG = 36558, + + + // Horde Champions + NPC_MOKRA = 35572, + NPC_ERESSEA = 35569, + NPC_RUNOK = 35571, + NPC_ZULTORE = 35570, + NPC_VISCERI = 35617, + + + // Alliance Champions + NPC_JACOB = 34705, + NPC_AMBROSE = 34702, + NPC_COLOSOS = 34701, + NPC_JAELYNE = 34657, + NPC_LANA = 34703, + + + // Grand Champion Minions + NPC_IRONFORGE_MINION = 35329, + NPC_STORMWIND_MINION = 35328, + NPC_GNOMEREGAN_MINION = 35331, + NPC_EXODAR_MINION = 35330, + NPC_DARNASSUS_MINION = 35332, + NPC_ORGRIMMAR_MINION = 35314, + NPC_SILVERMOON_MINION = 35326, + NPC_THUNDER_BLUFF_MINION = 35325, + NPC_SENJIN_MINION = 35323, + NPC_UNDERCITY_MINION = 35327, + + + // Rest of the bosses and npcs + NPC_EADRIC = 35119, + NPC_EADRIC_H = 35518, + NPC_PALETRESS = 34928, + NPC_PALETRESS_H = 35517, + + NPC_ARGENT_LIGHTWIELDER = 35309, + NPC_ARGENT_MONK = 35305, + NPC_PRIESTESS = 35307, + + NPC_BLACK_KNIGHT = 35451, + + NPC_JAEREN = 35004, // Horde + NPC_ARELAS = 35005, // Alliance + NPC_RISEN_JAEREN = 35545, + NPC_RISEN_ARELAS = 35564, + NPC_TIRION = 33628, // Possibly wrong npc here, 34996 had already populated creature_text (from ToC25) that + // matches. Needs a sniff to confirm. + +}; + +const std::vector availableTargets = { + NPC_MOKRA, NPC_ERESSEA, NPC_RUNOK, NPC_ZULTORE, NPC_VISCERI, + NPC_AMBROSE, NPC_COLOSOS, NPC_JAELYNE, NPC_LANA, NPC_JACOB, + NPC_STORMWIND_MINION, NPC_GNOMEREGAN_MINION, NPC_EXODAR_MINION, NPC_DARNASSUS_MINION, NPC_IRONFORGE_MINION, + NPC_ORGRIMMAR_MINION, NPC_SILVERMOON_MINION, NPC_THUNDER_BLUFF_MINION, NPC_SENJIN_MINION, NPC_UNDERCITY_MINION, +}; + +class ToCLanceTrigger : public Trigger +{ +public: + ToCLanceTrigger(PlayerbotAI* ai) : Trigger(ai, "toc lance") {} + bool IsActive() override; +}; + +class ToCUELanceTrigger : public Trigger +{ +public: + ToCUELanceTrigger(PlayerbotAI* ai) : Trigger(ai, "toc ue lance") {} + bool IsActive() override; +}; + +class ToCMountedTrigger : public Trigger +{ +public: + ToCMountedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "toc mounted") {} + bool IsActive() override; +}; + +class ToCMountNearTrigger : public Trigger +{ +public: + ToCMountNearTrigger(PlayerbotAI* botAI) : Trigger(botAI, "toc mount near") {} + bool IsActive() override; +}; + +class ToCEadricTrigger : public Trigger +{ +public: + ToCEadricTrigger(PlayerbotAI* botAI) : Trigger(botAI, "toc eadric") {} + bool IsActive() override; +}; + +#endif diff --git a/src/strategy/raids/icecrown/RaidIccActions.cpp b/src/strategy/raids/icecrown/RaidIccActions.cpp index ec3f6c54..a37bbb52 100644 --- a/src/strategy/raids/icecrown/RaidIccActions.cpp +++ b/src/strategy/raids/icecrown/RaidIccActions.cpp @@ -66,8 +66,26 @@ bool IccSpikeAction::Execute(Event event) Aura* bossaura = botAI->GetAura("Bone Storm", boss); if (boss->isInFront(bot) && !botAI->IsTank(bot) && !bossaura) - return MoveTo(bot->GetMapId(), -390.6757f, 2230.5283f, 41.99232f, false, false, false, true, - MovementPriority::MOVEMENT_FORCED); + { + float distance = bot->GetExactDist2d(-390.6757f, 2230.5283f); + if (distance > 3.0f) + { + // Calculate direction vector + float dirX = -390.6757f - bot->GetPositionX(); + float dirY = 2230.5283f - bot->GetPositionY(); + float length = sqrt(dirX * dirX + dirY * dirY); + dirX /= length; + dirY /= length; + + // Move in increments of 3.0f + float moveX = bot->GetPositionX() + dirX * 3.0f; + float moveY = bot->GetPositionY() + dirY * 3.0f; + + return MoveTo(bot->GetMapId(), moveX, moveY, bot->GetPositionZ(), false, false, false, false, + MovementPriority::MOVEMENT_COMBAT); + } + return false; + } if (!botAI->IsTank(bot)) return false; @@ -3563,7 +3581,9 @@ bool IccLichKingAddsAction::Execute(Event event) ICC_LICH_KING_ADDS_POSITION.GetPositionY(), ICC_LICH_KING_ADDS_POSITION.GetPositionZ(), bot->GetOrientation()); } - if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(72262) && bot->GetExactDist2d(boss) > 20.0f) //quake + if (!boss) + {} + else if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(72262) && bot->GetExactDist2d(boss) > 20.0f) //quake { float angle = bot->GetAngle(boss); float posX = bot->GetPositionX() + cos(angle) * 10.0f; @@ -3602,8 +3622,9 @@ bool IccLichKingAddsAction::Execute(Event event) if (bot->getClass() == CLASS_HUNTER && closestHorror && botAI->HasAura("Enrage", closestHorror)) return botAI->CastSpell("Tranquilizing Shot", closestHorror); - // Handle assist tanks - keep them at adds position - if (botAI->IsAssistTank(bot) && !boss->HealthBelowPct(71)) + if (!boss) + {} + else if (botAI->IsAssistTank(bot) && !boss->HealthBelowPct(71)) { // Actively look for any shambling/spirit/ghoul that isn't targeting us GuidVector targets = AI_VALUE(GuidVector, "possible targets"); @@ -3637,7 +3658,9 @@ bool IccLichKingAddsAction::Execute(Event event) return false; // Stay in position and keep facing current target } - if (botAI->IsMelee(bot) && !botAI->IsAssistTank(bot) && !boss->HealthBelowPct(71) && !hasPlague) + if (!boss) + {} + else if (botAI->IsMelee(bot) && !botAI->IsAssistTank(bot) && !boss->HealthBelowPct(71) && !hasPlague) { float currentDist = bot->GetDistance(ICC_LICH_KING_MELEE_POSITION); if (currentDist > 2.0f) @@ -3648,7 +3671,9 @@ bool IccLichKingAddsAction::Execute(Event event) } } - if (botAI->IsRanged(bot) && !boss->HealthBelowPct(71) && !hasPlague && !(diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) + if (!boss) + {} + else if (botAI->IsRanged(bot) && !boss->HealthBelowPct(71) && !hasPlague && !(diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) { float currentDist = bot->GetDistance(ICC_LICH_KING_RANGED_POSITION); if (currentDist > 2.0f) @@ -3658,7 +3683,7 @@ bool IccLichKingAddsAction::Execute(Event event) false, false, false, true, MovementPriority::MOVEMENT_FORCED, true, false); } } - + std::vector defiles; Unit* closestDefile = nullptr; float closestDistance = std::numeric_limits::max(); @@ -3727,7 +3752,9 @@ bool IccLichKingAddsAction::Execute(Event event) } // If we need to move, find the safest direction - if (needToMove) + if (!boss) + {} + else if (needToMove) { // Try 16 different angles for more precise movement for (int i = 0; i < 16; i++) @@ -3792,7 +3819,9 @@ bool IccLichKingAddsAction::Execute(Event event) } // Check if LK is casting Defile - make bots spread - if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(72762)) + if (!boss) + {} + else if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(72762)) { uint32 playerCount = 0; uint32 botIndex = 0; diff --git a/src/strategy/raids/icecrown/RaidIccTriggers.cpp b/src/strategy/raids/icecrown/RaidIccTriggers.cpp index 6a72d892..510ea1ec 100644 --- a/src/strategy/raids/icecrown/RaidIccTriggers.cpp +++ b/src/strategy/raids/icecrown/RaidIccTriggers.cpp @@ -102,7 +102,14 @@ bool IccGunshipCannonNearTrigger::IsActive() { if (bot->GetVehicle()) return false; - + + Unit* mount1 = bot->FindNearestCreature(36838, 100.0f); + + Unit* mount2 = bot->FindNearestCreature(36839, 100.0f); + + if (!mount1 && !mount2) + return false; + if (!botAI->IsDps(bot)) return false; // Player* master = botAI->GetMaster();