#include "RaidIccTriggers.h" #include "RaidIccActions.h" #include "strategy/values/NearestNpcsValue.h" #include "PlayerbotAIConfig.h" #include "ObjectAccessor.h" #include "GenericTriggers.h" #include "DungeonStrategyUtils.h" #include "EventMap.h" #include "Playerbots.h" #include "ScriptedCreature.h" #include "Trigger.h" #include "CellImpl.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "Vehicle.h" //Lord Marrogwar bool IccLmTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "lord marrowgar"); if (!boss) return false; if (bot->HasAura(SPELL_EXPERIENCED)) bot->RemoveAura(SPELL_EXPERIENCED); return true; } //Lady Deathwhisper bool IccDarkReckoningTrigger::IsActive() { if (bot->HasAura(SPELL_DARK_RECKONING)) return true; return false; } bool IccLadyDeathwhisperTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "lady deathwhisper"); if (!boss) return false; if (bot->HasAura(SPELL_EXPERIENCED)) bot->RemoveAura(SPELL_EXPERIENCED); return true; } //Gunship Battle bool IccRottingFrostGiantTankPositionTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "rotting frost giant"); if (!boss) return false; if (bot->HasAura(SPELL_EXPERIENCED)) bot->RemoveAura(SPELL_EXPERIENCED); return true; } bool IccInCannonTrigger::IsActive() { Unit* vehicleBase = bot->GetVehicleBase(); Vehicle* vehicle = bot->GetVehicle(); if (!vehicleBase || !vehicle) return false; uint32 entry = vehicleBase->GetEntry(); return entry == NPC_CANNONA || entry == NPC_CANNONH; } bool IccGunshipCannonNearTrigger::IsActive() { if (bot->GetVehicle()) return false; Unit* mount1 = bot->FindNearestCreature(NPC_CANNONA, 100.0f); Unit* mount2 = bot->FindNearestCreature(NPC_CANNONH, 100.0f); if (!mount1 && !mount2) return false; if (!botAI->IsDps(bot)) return false; // Player* master = botAI->GetMaster(); // if (!master) // return false; // if (!master->GetVehicle()) // return false; return true; } bool IccGunshipTeleportAllyTrigger::IsActive() { Unit* boss = bot->FindNearestCreature(NPC_HIGH_OVERLORD_SAURFANG, 100.0f); if (!boss) return false; if (!boss->IsHostileTo(bot)) return false; return true; } bool IccGunshipTeleportHordeTrigger::IsActive() { Unit* boss = bot->FindNearestCreature(NPC_MURADIN_BRONZEBEARD, 100.0f); if (!boss) return false; if (!boss->IsHostileTo(bot)) return false; return true; } //DBS bool IccDbsTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "deathbringer saurfang"); if (!boss) return false; if (bot->HasAura(SPELL_EXPERIENCED)) bot->RemoveAura(SPELL_EXPERIENCED); return true; } bool IccDbsMainTankRuneOfBloodTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "deathbringer saurfang"); if (!boss) return false; if (!botAI->IsAssistTankOfIndex(bot, 0)) return false; Unit* mt = AI_VALUE(Unit*, "main tank"); if (!mt) return false; Aura* aura = botAI->GetAura("rune of blood", mt); if (!aura) return false; return true; } //DOGS bool IccStinkyPreciousMainTankMortalWoundTrigger::IsActive() { bool bossPresent = false; if (AI_VALUE2(Unit*, "find target", "stinky") || AI_VALUE2(Unit*, "find target", "precious")) bossPresent = true; if (!bossPresent) return false; if (!botAI->IsAssistTankOfIndex(bot, 0)) return false; Unit* mt = AI_VALUE(Unit*, "main tank"); if (!mt) return false; Aura* aura = botAI->GetAura("mortal wound", mt, false, true); if (!aura || aura->GetStackAmount() < 8) return false; return true; } //FESTERGUT bool IccFestergutGroupPositionTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "festergut"); if (!boss) return false; if (bot->HasAura(SPELL_EXPERIENCED)) bot->RemoveAura(SPELL_EXPERIENCED); return true; } bool IccFestergutMainTankGastricBloatTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "festergut"); if (!boss) { return false; } if (!botAI->IsAssistTankOfIndex(bot, 0)) { return false; } Unit* mt = AI_VALUE(Unit*, "main tank"); if (!mt) { return false; } Aura* aura = botAI->GetAura("Gastric Bloat", mt, false, true); if (!aura || aura->GetStackAmount() < 6) { return false; } return true; } bool IccFestergutSporeTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "festergut"); if (!boss || botAI->IsTank(bot)) return false; // Check for spore aura (ID: 69279) on any bot in the group Group* group = bot->GetGroup(); if (!group) return false; for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* member = itr->GetSource(); if (!member) continue; if (member->HasAura(SPELL_GAS_SPORE)) return true; } return false; } //ROTFACE bool IccRotfaceTankPositionTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "rotface"); if (!boss || !(botAI->IsTank(bot) || botAI->IsMelee(bot))) return false; if (bot->HasAura(SPELL_EXPERIENCED)) bot->RemoveAura(SPELL_EXPERIENCED); return true; } bool IccRotfaceGroupPositionTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "rotface"); if (!boss) return false; return true; } bool IccRotfaceMoveAwayFromExplosionTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "big ooze"); if (!boss) return false; return boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_UNSTABLE_OOZE_EXPLOSION); } //PP bool IccPutricideGrowingOozePuddleTrigger::IsActive() { // Early return if boss doesn't exist Unit* boss = AI_VALUE2(Unit*, "find target", "professor putricide"); if (!boss) return false; Difficulty diff = bot->GetRaidDifficulty(); if (sPlayerbotAIConfig->EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) { //-------CHEAT------- if (!bot->HasAura(SPELL_EXPERIENCED)) bot->AddAura(SPELL_EXPERIENCED, bot); if (!bot->HasAura(SPELL_AGEIS_OF_DALARAN)) bot->AddAura(SPELL_AGEIS_OF_DALARAN, bot); if (!bot->HasAura(SPELL_NO_THREAT) && botAI->HasAggro(boss) && !botAI->IsTank(bot)) bot->AddAura(SPELL_NO_THREAT, bot); if (botAI->IsMainTank(bot) && !bot->HasAura(SPELL_SPITEFULL_FURY) && boss->GetVictim() != bot) bot->AddAura(SPELL_SPITEFULL_FURY, bot); //-------CHEAT------- } const GuidVector& npcs = AI_VALUE(GuidVector, "nearest hostile npcs"); for (const auto& npc : npcs) { if (Unit* unit = botAI->GetUnit(npc)) { const uint32 entry = unit->GetEntry(); if (entry == NPC_GROWING_OOZE_PUDDLE) return true; } } return false; } bool IccPutricideVolatileOozeTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "volatile ooze"); if (!boss) return false; if (botAI->HasAura("Gaseous Bloat", bot)) return false; return true; } bool IccPutricideGasCloudTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "gas cloud"); if (!boss) return false; Unit* boss1 = AI_VALUE2(Unit*, "find target", "volatile ooze"); bool hasGaseousBloat = botAI->HasAura("Gaseous Bloat", bot); if (hasGaseousBloat && boss1) return true; if (boss1) return false; return true; } bool IccPutricideMainTankMutatedPlagueTrigger::IsActive() { bool bossPresent = false; if (AI_VALUE2(Unit*, "find target", "professor putricide")) bossPresent = true; if (!bossPresent) return false; if (!botAI->IsAssistTankOfIndex(bot, 0)) { return false; } Unit* mt = AI_VALUE(Unit*, "main tank"); if (!mt) { return false; } Aura* aura = botAI->GetAura("Mutated Plague", mt, false, true); if (!aura || aura->GetStackAmount() < 4) { return false; } return true; } bool IccPutricideMalleableGooTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "professor putricide"); if (!boss) return false; if (botAI->IsTank(bot)) return true; Unit* boss1 = AI_VALUE2(Unit*, "find target", "volatile ooze"); if (boss1) return false; Unit* boss2 = AI_VALUE2(Unit*, "find target", "gas cloud"); if (boss2) return false; return true; } //BPC bool IccBpcKelesethTankTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "prince keleseth"); if (!boss) return false; if (bot->HasAura(SPELL_EXPERIENCED)) bot->RemoveAura(SPELL_EXPERIENCED); if (!botAI->IsAssistTank(bot)) return false; Aura* aura = botAI->GetAura("Shadow Prison", bot, false, true); if (aura) if (aura->GetStackAmount() > 18) return false; return true; } bool IccBpcMainTankTrigger::IsActive() { if (!botAI->IsTank(bot)) return false; Unit* valanar = AI_VALUE2(Unit*, "find target", "prince valanar"); Unit* taldaram = AI_VALUE2(Unit*, "find target", "prince taldaram"); Unit* keleseth = AI_VALUE2(Unit*, "find target", "prince keleseth"); if (!(valanar || taldaram || keleseth)) return false; if (bot->HasAura(SPELL_EXPERIENCED)) bot->RemoveAura(SPELL_EXPERIENCED); return true; } bool IccBpcEmpoweredVortexTrigger::IsActive() { // Tanks should ignore this mechanic if (botAI->IsMainTank(bot) || botAI->IsAssistTank(bot)) return false; Unit* valanar = AI_VALUE2(Unit*, "find target", "prince valanar"); if (!valanar) return false; Aura* aura = botAI->GetAura("Shadow Prison", bot, false, true); if (aura) if (aura->GetStackAmount() > 12) return false; Aura* auraValanar = botAI->GetAura("Invocation of Blood", valanar); if (!auraValanar) return false; return true; } bool IccBpcKineticBombTrigger::IsActive() { Unit* valanar = AI_VALUE2(Unit*, "find target", "prince valanar"); Unit* taldaram = AI_VALUE2(Unit*, "find target", "prince taldaram"); Unit* keleseth = AI_VALUE2(Unit*, "find target", "prince keleseth"); if (!(valanar || taldaram || keleseth)) return false; if (!botAI->IsRanged(bot) || botAI->IsHeal(bot)) return false; // Early exit condition - if Shadow Prison has too many stacks if (Aura* aura = botAI->GetAura("Shadow Prison", bot, false, true)) { if (aura->GetStackAmount() > 12) return false; } static const std::array bombEntries = {NPC_KINETIC_BOMB1, NPC_KINETIC_BOMB2, NPC_KINETIC_BOMB3, NPC_KINETIC_BOMB4}; const GuidVector bombs = AI_VALUE(GuidVector, "possible targets no los"); bool bombFound = false; for (const auto entry : bombEntries) { for (const auto& guid : bombs) { if (Unit* unit = botAI->GetUnit(guid)) { if (unit->GetEntry() == entry) { // Check if bomb is within valid Z-axis range if (unit->GetPositionZ() - bot->GetPositionZ() < 25.0f) { bombFound = true; break; } } } } if (bombFound) break; } return botAI->IsRangedDps(bot) && bombFound; } bool IccBpcBallOfFlameTrigger::IsActive() { Unit* valanar = AI_VALUE2(Unit*, "find target", "prince valanar"); Unit* taldaram = AI_VALUE2(Unit*, "find target", "prince taldaram"); Unit* keleseth = AI_VALUE2(Unit*, "find target", "prince keleseth"); if (!(valanar || taldaram || keleseth)) return false; Aura* auraTaldaram = botAI->GetAura("Invocation of Blood", taldaram); if (!auraTaldaram) return false; return true; } //BQL bool IccBqlGroupPositionTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "blood-queen lana'thel"); if (!boss) return false; if (bot->HasAura(SPELL_EXPERIENCED)) bot->RemoveAura(SPELL_EXPERIENCED); return true; } bool IccBqlPactOfDarkfallenTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "blood-queen lana'thel"); if (!boss) return false; Aura* aura = botAI->GetAura("Pact of the Darkfallen", bot); if (!aura) return false; return true; } bool IccBqlVampiricBiteTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "blood-queen lana'thel"); if (!boss) return false; Aura* aura = botAI->GetAura("Frenzied Bloodthirst", bot); if (!aura) return false; return true; } // Sister Svalna bool IccValkyreSpearTrigger::IsActive() { // Check if there's a spear nearby if (Creature* spear = bot->FindNearestCreature(NPC_SPEAR, 100.0f)) return true; return false; } bool IccSisterSvalnaTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "sister svalna"); if (!boss) return false; if (bot->GetExactDist2d(boss) > 30.0f) return false; return true; } // VDW bool IccValithriaGroupTrigger::IsActive() { Unit* boss = bot->FindNearestCreature(NPC_VALITHRIA_DREAMWALKER, 100.0f); if (!boss) return false; if (bot->HasAura(SPELL_EXPERIENCED)) bot->RemoveAura(SPELL_EXPERIENCED); return true; } bool IccValithriaPortalTrigger::IsActive() { Unit* boss = bot->FindNearestCreature(NPC_VALITHRIA_DREAMWALKER, 100.0f); if (!boss) return false; Aura* aura = botAI->GetAura("Twisted Nightmares", bot, false, true); if (aura && aura->GetStackAmount() >= 25) return false; // Only healers should use portals if (!botAI->IsHeal(bot) || bot->HasAura(SPELL_DREAM_STATE)) return false; Creature* worm = bot->FindNearestCreature(NPC_ROT_WORM, 100.0f); Creature* zombie = bot->FindNearestCreature(NPC_BLISTERING_ZOMBIE, 100.0f); if ((worm && worm->GetVictim() == bot) || (zombie && zombie->GetVictim() == bot)) return false; Group* group = bot->GetGroup(); if (!group) return false; // Collect healer GUIDs and check for druids std::vector healerGuids; std::vector druidGuids; int healerCount = 0; for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* member = itr->GetSource(); if (!member || !member->IsAlive() || botAI->IsRealPlayer()) continue; if (botAI->IsHeal(member) && !botAI->IsRealPlayer()) { healerCount++; healerGuids.push_back(member->GetGUID()); // Check if druid (class 11) if (member->getClass() == CLASS_DRUID) druidGuids.push_back(member->GetGUID()); } } // Sort GUIDs to ensure consistent ordering std::sort(healerGuids.begin(), healerGuids.end()); std::sort(druidGuids.begin(), druidGuids.end()); // Find position of current bot's GUID in the sorted list auto botGuidPos = std::find(healerGuids.begin(), healerGuids.end(), bot->GetGUID()); if (botGuidPos == healerGuids.end()) return false; int healerIndex = std::distance(healerGuids.begin(), botGuidPos); // Find if this bot is a druid bool isDruid = (bot->getClass() == CLASS_DRUID); // Determine raid healer assignment bool shouldHealRaid = false; int druidCount = druidGuids.size(); if (druidCount > 0) { // If we have druids, they should heal raid if (isDruid) { // If there are more druids than raid healers needed, extra druids can heal boss int raidHealersNeeded = healerCount > 3 ? 2 : 1; int druidIndex = std::distance(druidGuids.begin(), std::find(druidGuids.begin(), druidGuids.end(), bot->GetGUID())); if (druidIndex < raidHealersNeeded) shouldHealRaid = true; else shouldHealRaid = false; } else if (healerCount > 3 && druidCount == 1) { // If only 1 druid and need 2 raid healers, pick the last non-druid healer as well if (healerIndex == (healerCount - 1) && !isDruid) shouldHealRaid = true; } } else { // No druids, assign raid healers as before if (healerCount > 3) shouldHealRaid = (healerIndex >= (healerCount - 2)); else shouldHealRaid = (healerIndex == (healerCount - 1)); } // Raid healers should not use portals if (shouldHealRaid) return false; // Find the nearest portal creature Creature* portal1 = bot->FindNearestCreature(NPC_DREAM_PORTAL, 100.0f); if (!portal1) portal1 = bot->FindNearestCreature(NPC_DREAM_PORTAL_PRE_EFFECT, 100.0f); Creature* portal2 = bot->FindNearestCreature(NPC_NIGHTMARE_PORTAL, 100.0f); if (!portal2) portal2 = bot->FindNearestCreature(NPC_NIGHTMARE_PORTAL_PRE_EFFECT, 100.0f); return portal1 || portal2; } bool IccValithriaHealTrigger::IsActive() { Unit* boss = bot->FindNearestCreature(NPC_VALITHRIA_DREAMWALKER, 100.0f); if (!boss) return false; // Only healers should use healing if (!botAI->IsHeal(bot) || bot->HasAura(SPELL_DREAM_STATE) || bot->HealthBelowPct(50)) return false; Creature* worm = bot->FindNearestCreature(NPC_ROT_WORM, 100.0f); Creature* zombie = bot->FindNearestCreature(NPC_BLISTERING_ZOMBIE, 100.0f); if ((worm && worm->GetVictim() == bot) || (zombie && zombie->GetVictim() == bot)) return false; Group* group = bot->GetGroup(); if (!group) return false; // Collect healer GUIDs and check for druids std::vector healerGuids; std::vector druidGuids; int healerCount = 0; for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* member = itr->GetSource(); if (!member || !member->IsAlive() || botAI->IsRealPlayer()) continue; if (botAI->IsHeal(member) && !botAI->IsRealPlayer()) { healerCount++; healerGuids.push_back(member->GetGUID()); // Check if druid (class 11) if (member->getClass() == CLASS_DRUID) druidGuids.push_back(member->GetGUID()); } } // Sort GUIDs to ensure consistent ordering std::sort(healerGuids.begin(), healerGuids.end()); std::sort(druidGuids.begin(), druidGuids.end()); // Find position of current bot's GUID in the sorted list auto botGuidPos = std::find(healerGuids.begin(), healerGuids.end(), bot->GetGUID()); if (botGuidPos == healerGuids.end()) return false; int healerIndex = std::distance(healerGuids.begin(), botGuidPos); // Find if this bot is a druid bool isDruid = (bot->getClass() == CLASS_DRUID); // Determine raid healer assignment bool shouldHealRaid = false; int druidCount = druidGuids.size(); if (druidCount > 0) { // If we have druids, they should heal raid if (isDruid) { // If there are more druids than raid healers needed, extra druids can heal boss int raidHealersNeeded = healerCount > 3 ? 2 : 1; int druidIndex = std::distance(druidGuids.begin(), std::find(druidGuids.begin(), druidGuids.end(), bot->GetGUID())); if (druidIndex < raidHealersNeeded) shouldHealRaid = true; else shouldHealRaid = false; // extra druids can heal boss } else if (healerCount > 3 && druidCount == 1) { // If only 1 druid and need 2 raid healers, pick the last non-druid healer as well if (healerIndex == (healerCount - 1) && !isDruid) shouldHealRaid = true; } } else { // No druids, assign raid healers as before if (healerCount > 3) shouldHealRaid = (healerIndex >= (healerCount - 2)); else shouldHealRaid = (healerIndex == (healerCount - 1)); } // If assigned to raid healing, return false to not heal Valithria if (shouldHealRaid) return false; if (bot->GetHealthPct() < 50.0f) return false; // For Valithria healers, check portal logic // If no portal is found within 100 yards, we should heal if (!bot->FindNearestCreature(NPC_DREAM_PORTAL, 100.0f) && !bot->FindNearestCreature(NPC_NIGHTMARE_PORTAL, 100.0f)) return true; if (bot->FindNearestCreature(NPC_DREAM_PORTAL, 10.0f) || bot->FindNearestCreature(NPC_NIGHTMARE_PORTAL, 10.0f)) return false; // If portal is far but within 100 yards, heal while moving to it return true; } bool IccValithriaDreamCloudTrigger::IsActive() { // Only active if we're in dream state if (!bot->HasAura(SPELL_DREAM_STATE) || bot->HealthBelowPct(50)) return false; // Find nearest cloud of either type Creature* dreamCloud = bot->FindNearestCreature(NPC_DREAM_CLOUD, 100.0f); Creature* nightmareCloud = bot->FindNearestCreature(NPC_NIGHTMARE_CLOUD, 100.0f); return (dreamCloud || nightmareCloud); } //SINDRAGOSA bool IccSindragosaGroupPositionTrigger::IsActive() { Unit* boss = bot->FindNearestCreature(NPC_SINDRAGOSA, 200.0f); // sindra if (!boss) return false; Difficulty diff = bot->GetRaidDifficulty(); if (sPlayerbotAIConfig->EnableICCBuffs && diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC)) { //-------CHEAT------- if (!bot->HasAura(SPELL_EXPERIENCED)) bot->AddAura(SPELL_EXPERIENCED, bot); if (!bot->HasAura(SPELL_AGEIS_OF_DALARAN)) bot->AddAura(SPELL_AGEIS_OF_DALARAN, bot); if (!bot->HasAura(SPELL_NO_THREAT) && botAI->HasAggro(boss) && !botAI->IsTank(bot)) bot->AddAura(SPELL_NO_THREAT, bot); if (botAI->IsMainTank(bot) && !bot->HasAura(SPELL_SPITEFULL_FURY) && boss->GetVictim() != bot) bot->AddAura(SPELL_SPITEFULL_FURY, bot); //-------CHEAT------- } if (!boss || bot->HasAura(SPELL_FROST_BEACON) /*|| bot->HasAura(69762)*/ || boss->GetExactDist2d(ICC_SINDRAGOSA_FLYING_POSITION.GetPositionX(), ICC_SINDRAGOSA_FLYING_POSITION.GetPositionY()) < 50.0f) return false; return true; } bool IccSindragosaFrostBeaconTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa"); if (!boss) return false; Group* group = bot->GetGroup(); if (!group) return false; if (bot->HasAura(SPELL_FROST_BEACON)) return true; Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); ++itr) { Player* member = ObjectAccessor::FindPlayer(itr->guid); if (!member || !member->IsAlive()) continue; if (member->HasAura(SPELL_FROST_BEACON)) // If any player has Frost Beacon, keep trigger active return true; } return false; } bool IccSindragosaBlisteringColdTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa"); if (!boss) return false; if (botAI->IsMainTank(bot)) return false; // Don't move if any bot in group has ice tomb Group* group = bot->GetGroup(); if (!group) return false; float dist = bot->GetExactDist2d(boss->GetPositionX(), boss->GetPositionY()); if (dist >= 33.0f) return false; bool isCasting = false; if (boss && boss->HasUnitState(UNIT_STATE_CASTING)) isCasting = true; bool isBlisteringCold = false; if (boss && (boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD1) || boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD2) || boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD3) || boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD4))) isBlisteringCold = true; return isCasting && isBlisteringCold; } bool IccSindragosaUnchainedMagicTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa"); if (!boss) return false; Aura* aura = botAI->GetAura("unchained magic", bot, false, false); if (!aura) return false; bool isBlisteringCold = false; if (boss && (boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD1) || boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD2) || boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD3) || boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD4))) isBlisteringCold = true; if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && isBlisteringCold) return false; return true; } bool IccSindragosaChilledToTheBoneTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa"); if (!boss) return false; Aura* aura = botAI->GetAura("Chilled to the Bone", bot, false, false); if (!aura) return false; bool isBlisteringCold = false; if (boss && (boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD1) || boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD2) || boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD3) || boss->FindCurrentSpellBySpellId(SPELL_BLISTERING_COLD4))) isBlisteringCold = true; if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && isBlisteringCold) return false; return true; } bool IccSindragosaMysticBuffetTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa"); if (!boss) return false; if (boss->GetVictim() == bot) return false; Aura* aura = botAI->GetAura("mystic buffet", bot, false, true); if (!aura) return false; if (bot->HasAura(SPELL_FROST_BEACON)) return false; if (aura->GetStackAmount() >= 1) return true; return false; } bool IccSindragosaMainTankMysticBuffetTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa"); if (!boss) return false; Aura* aura = botAI->GetAura("mystic buffet", bot, false, false); if (botAI->IsTank(bot) && aura) //main tank will delete mystic buffet until I find a better way to swap tanks, atm it is not great since while swapping they will wipe group 7/10 times. bot->RemoveAura(aura->GetId()); if (botAI->IsTank(bot) && boss->GetVictim() == bot) return false; // Only for assist tank if (!botAI->IsAssistTankOfIndex(bot, 0)) return false; // Don't swap if we have frost beacon if (bot->HasAura(SPELL_FROST_BEACON)) // Frost Beacon return false; Unit* mt = AI_VALUE(Unit*, "main tank"); if (!mt) return false; // Check main tank stacks Aura* mtAura = botAI->GetAura("mystic buffet", mt, false, true); if (!mtAura || mtAura->GetStackAmount() < 6) return false; // Check our own stacks - don't taunt if we have too many Aura* selfAura = botAI->GetAura("mystic buffet", bot, false, true); if (selfAura && selfAura->GetStackAmount() > 6) return false; // Only taunt if we're in position float distToTankPos = bot->GetExactDist2d(ICC_SINDRAGOSA_TANK_POSITION); if (distToTankPos > 3.0f) return false; return true; } bool IccSindragosaTankSwapPositionTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa"); if (!boss) return false; if (boss && boss->GetVictim() == bot) return false; // Only for assist tank if (!botAI->IsAssistTankOfIndex(bot, 0)) return false; // Don't move to position if we have frost beacon if (bot->HasAura(SPELL_FROST_BEACON)) return false; // Check our own stacks - don't try to tank if we have too many Aura* selfAura = botAI->GetAura("mystic buffet", bot, false, true); if (selfAura && selfAura->GetStackAmount() > 6) return false; // Check if main tank has high stacks Unit* mt = AI_VALUE(Unit*, "main tank"); if (!mt) return false; Aura* mtAura = botAI->GetAura("mystic buffet", mt, false, true); if (!mtAura) return false; uint32 mtStacks = mtAura->GetStackAmount(); if (mtStacks < 6) // Only start moving when MT has 5+ stacks return false; // Check if we're already in position float distToTankPos = bot->GetExactDist2d(ICC_SINDRAGOSA_TANK_POSITION); if (distToTankPos <= 3.0f) return false; return true; // Move to position if all conditions are met } bool IccSindragosaFrostBombTrigger::IsActive() { Unit* boss = bot->FindNearestCreature(NPC_SINDRAGOSA, 200.0f); if (!boss) return false; if (!bot->IsAlive() || bot->HasAura(SPELL_ICE_TOMB)) // Skip if dead or in Ice Tomb return false; if (boss->GetExactDist2d(ICC_SINDRAGOSA_FLYING_POSITION.GetPositionX(), ICC_SINDRAGOSA_FLYING_POSITION.GetPositionY()) < 50.0f && !boss->HealthBelowPct(25) && !boss->HealthAbovePct(99)) return true; return false; } //LK bool IccLichKingShadowTrapTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "the lich king"); if (!boss) return false; bool hasPlague = botAI->HasAura("Necrotic Plague", bot); if (hasPlague) return false; if (!botAI->IsMainTank(bot)) return false; if (boss->HealthBelowPct(65)) return false; // search for all nearby traps GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs"); std::vector nearbyTraps; bool needToMove = false; for (auto& npc : npcs) { Unit* unit = botAI->GetUnit(npc); if (!unit || !unit->IsAlive()) continue; if (unit->GetEntry() == NPC_SHADOW_TRAP && bot->GetExactDist2d(unit) < 11.0f) // shadow trap return true; } return false; } bool IccLichKingNecroticPlagueTrigger::IsActive() { bool hasPlague = botAI->HasAura("Necrotic Plague", bot); return hasPlague; } bool IccLichKingWinterTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "the lich king"); if (!boss) return false; // Check for either Remorseless Winter bool hasWinterAura = false; if (boss && (boss->HasAura(SPELL_REMORSELESS_WINTER1) || boss->HasAura(SPELL_REMORSELESS_WINTER2) || boss->HasAura(SPELL_REMORSELESS_WINTER3) || boss->HasAura(SPELL_REMORSELESS_WINTER4))) hasWinterAura = true; bool hasWinter2Aura = false; if (boss && (boss->HasAura(SPELL_REMORSELESS_WINTER5) || boss->HasAura(SPELL_REMORSELESS_WINTER6) || boss->HasAura(SPELL_REMORSELESS_WINTER7) || boss->HasAura(SPELL_REMORSELESS_WINTER8))) hasWinter2Aura = true; bool isCasting = false; if (boss && boss->HasUnitState(UNIT_STATE_CASTING)) isCasting = true; bool isWinter = false; if (boss && boss->FindCurrentSpellBySpellId(SPELL_REMORSELESS_WINTER1) || boss->FindCurrentSpellBySpellId(SPELL_REMORSELESS_WINTER2) || boss->FindCurrentSpellBySpellId(SPELL_REMORSELESS_WINTER5) || boss->FindCurrentSpellBySpellId(SPELL_REMORSELESS_WINTER6) || boss->FindCurrentSpellBySpellId(SPELL_REMORSELESS_WINTER3) || boss->FindCurrentSpellBySpellId(SPELL_REMORSELESS_WINTER4) || boss->FindCurrentSpellBySpellId(SPELL_REMORSELESS_WINTER7) || boss->FindCurrentSpellBySpellId(SPELL_REMORSELESS_WINTER8)) isWinter = true; if (hasWinterAura || hasWinter2Aura) return true; if (isCasting && isWinter) return true; return false; } bool IccLichKingAddsTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "the lich king"); bool hasPlague = botAI->HasAura("Necrotic Plague", bot); if (hasPlague) return false; Unit* terenasMenethilHC = bot->FindNearestCreature(NPC_TERENAS_MENETHIL_HC, 55.0f); Unit* terenasMenethil = bot->FindNearestCreature(NPC_TERENAS_MENETHIL, 55.0f); if (terenasMenethilHC) return true; if (terenasMenethil) return true; if (!boss) return false; return true; }