mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-16 10:20:27 +00:00
ICC Strategy (doable 10/25NM) (#789)
* ICC PP WIP WIP * added mutated plague for PP * BPC added (kinetic and boss targeting need to be done by player) OT collects dark nucles, bots spread on vortex and other stuff they do ok on their own. Tested only on 10NM, should work on 25NM * Tank pos. correction * BQL, ranged spread, link, flame, bite, tanking tested 10NM to do (better fire spread, hc tacti, melee spread when in air) * LDW improved improved shadow logic, ranged spread for easier shadow handling * dbs update, fixed teleporting Bots should only go and teleport to the mage that is actually below zero now * DBS ranged fix Ranged should spread more quickly and freak out less * Festergut && DBS fixed ranged spread (both) fixed spore logic (fester) * Rotface fix Improved big ooze tanking (static pos, todo kiting) ooze explosion spread mechanic fix ooze pool fix Player needs to mark rotface with skull icon, oterwise bots try to attack oozes * BQL fixed for 25nm todo: better melee logic in air phase, better melee flame spread * VDW, Sister Svalna, Sindy update Sister Svalna, bots can pickup spears and throw at svalna when she has shield up VDW added healer strats to use portal and heal boss (atm druids are for raid healing only, so use druide + any other healer, ideally player should be healer) todo (focus on supressers, add healer rotations, atm they use quickest spell they can) Sindragosa Added tank boss manipulation (boss orientation and position) bots detect (buffet, unchained magic and chilled to the bone and act accordingly) bots detect frost beacon move to safe spot and los frost bombs around them, while dpsing tombs (todo stop dps if only one tomb is left, if we have frost bombs around, not a big deal atm since in nm they dont one shot) Last phase bots los behind tomb to loose buffet, tanks swap when they have hi buffet count. Player should tell bots with skull rti if they should kill tomb or focus boss. todo (dynamic tomb los in last phase so that healers can see tank but also hide behind tomb to break los from boss) Removed some debug messages, improved LM spike action (nearest bots also try to help kill it) Improved Lady Deathwshiper shade action (only targeted bots will run away instead of every bot that is near it) dbs improved tank switch I recommend to use 3 healers (just to be safe) and 2 paladin tanks (warr seems to struggle with agro) in 10 man 25 man 6-7 healers (just to be safe) Since most of the bosses are about survival and not dps * LK Update (doable) LK added Improved tank switching for all bosses Fixed PP gas cloud kiting Malleable goo todo (dont know how to detect it since its not object or npc) just summon ranged bots to safe position to bypass BPC fixed OT sometimes not tanking kele kinectic bombs todo (for now player should take care of them) Sindragosa fixed rare case when she is in air phase but tombs went to last phase position LK Bots can handle necrotic Bots can handle adds Bots should focus valkyre that actually grabbed someone (if unlucky and player just use attack command and summon bots to you if they are far away from you) if they grab bots you can either summon to make them useless or let bots cc them and do it legit way. Defile should be watched by player and once it was cast just summon bots to you Vile spirits for some reason go to the ground and get nuked by bots aoe spells so there is not much to be done **Player needs to be alive the whole LK fight since you will have to watch out for frost spehers (sometimes bots ignore them), summon bots when defile is up and summon ranged bots if they get stuck near shambling or raging spirits since their aoe will wipe you) all in all LK is doable both 10 and 25nm, player needs to have knowledge of lk fight and needs to know how to use multibot addon and make macros for eg summoning or commanding groups of bots or individual bots) Dont forget frost/shadow/nature resist auras in whole ICC since it will help alot I have done whole icc 10 and 25 with 2 pala tanks, 2/5 heals and rest dps, if you use +1 or +2 heals it should be easier (since I was testing I did close to 0 dmg in fights same with heals) * fixed changes made by mistake fix * Malleable fix (simple spread mechanic) Malleable mechanic added (simple spread for now) Gas cloud fixed (Bots sometimes got stuck between puddle and kite location) * Defile Update Bots detect and avoid defile (they struggle to find a way back to the boss around it tho, use summon to help them) Melee bots should be able to stand behind/to the flank of shambling/spirits
This commit is contained in:
632
src/strategy/raids/icecrown/RaidIccMultipliers.cpp
Normal file
632
src/strategy/raids/icecrown/RaidIccMultipliers.cpp
Normal file
@@ -0,0 +1,632 @@
|
||||
#include "RaidIccMultipliers.h"
|
||||
|
||||
#include "ChooseTargetActions.h"
|
||||
#include "DKActions.h"
|
||||
#include "DruidActions.h"
|
||||
#include "DruidBearActions.h"
|
||||
#include "FollowActions.h"
|
||||
#include "GenericActions.h"
|
||||
#include "GenericSpellActions.h"
|
||||
#include "HunterActions.h"
|
||||
#include "MageActions.h"
|
||||
#include "MovementActions.h"
|
||||
#include "PaladinActions.h"
|
||||
#include "PriestActions.h"
|
||||
#include "RaidIccActions.h"
|
||||
#include "ReachTargetActions.h"
|
||||
#include "RogueActions.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ShamanActions.h"
|
||||
#include "UseMeetingStoneAction.h"
|
||||
#include "WarriorActions.h"
|
||||
#include "PlayerbotAI.h"
|
||||
|
||||
float IccLadyDeathwhisperMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "lady deathwhisper");
|
||||
if (!boss)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action) || dynamic_cast<FollowAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IccAddsDbsMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "deathbringer saurfang");
|
||||
if (!boss)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action) || dynamic_cast<FollowAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
{
|
||||
Aura* aura = botAI->GetAura("rune of blood", bot);
|
||||
if (aura)
|
||||
{
|
||||
if (dynamic_cast<CastTauntAction*>(action) || dynamic_cast<CastDarkCommandAction*>(action) ||
|
||||
dynamic_cast<CastHandOfReckoningAction*>(action) || dynamic_cast<CastGrowlAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (botAI->IsDps(bot))
|
||||
{
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||
bool hasAdds = false;
|
||||
for (auto& guid : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (unit && unit->IsAlive() && (
|
||||
unit->GetEntry() == 38508 || //blood beast
|
||||
unit->GetEntry() == 38596 ||
|
||||
unit->GetEntry() == 38597 ||
|
||||
unit->GetEntry() == 38598))
|
||||
{
|
||||
hasAdds = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasAdds && !botAI->IsMainTank(bot))
|
||||
{
|
||||
if (dynamic_cast<IccAddsDbsAction*>(action))
|
||||
return 2.0f;
|
||||
else if (dynamic_cast<DpsAssistAction*>(action) || dynamic_cast<TankAssistAction*>(action) ||
|
||||
dynamic_cast<CombatFormationMoveAction*>(action) || dynamic_cast<FollowAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IccDogsMultiplier::GetValue(Action* action)
|
||||
{
|
||||
bool bossPresent = false;
|
||||
if (AI_VALUE2(Unit*, "find target", "stinky") || AI_VALUE2(Unit*, "find target", "precious"))
|
||||
bossPresent = true;
|
||||
|
||||
if (!bossPresent)
|
||||
return 1.0f;
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
{
|
||||
Aura* aura = botAI->GetAura("mortal wound", bot, false, true);
|
||||
if (aura && aura->GetStackAmount() >= 8)
|
||||
{
|
||||
if (dynamic_cast<CastTauntAction*>(action) || dynamic_cast<CastDarkCommandAction*>(action) ||
|
||||
dynamic_cast<CastHandOfReckoningAction*>(action) || dynamic_cast<CastGrowlAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IccFestergutMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "festergut");
|
||||
if (!boss)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action) || dynamic_cast<FollowAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
{
|
||||
Aura* aura = botAI->GetAura("gastric bloat", bot, false, true);
|
||||
if (aura && aura->GetStackAmount() >= 6)
|
||||
{
|
||||
if (dynamic_cast<CastTauntAction*>(action) || dynamic_cast<CastDarkCommandAction*>(action) ||
|
||||
dynamic_cast<CastHandOfReckoningAction*>(action) || dynamic_cast<CastGrowlAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bot->HasAura(69279) && (bot->getClass() == CLASS_HUNTER))
|
||||
{
|
||||
if (dynamic_cast<DpsAssistAction*>(action) || dynamic_cast<TankAssistAction*>(action) ||
|
||||
dynamic_cast<CastDebuffSpellOnAttackerAction*>(action) || dynamic_cast<CombatFormationMoveAction*>(action) ||
|
||||
dynamic_cast<FleeAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IccRotfaceMultiplier::GetValue(Action* action)
|
||||
{
|
||||
// If we're already executing the escape movement, don't interrupt it
|
||||
if (dynamic_cast<IccRotfaceMoveAwayFromExplosionAction*>(action))
|
||||
return 1.0f;
|
||||
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "big ooze");
|
||||
if (!boss) { return 1.0f; }
|
||||
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action) || dynamic_cast<FollowAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<FleeAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
static std::map<ObjectGuid, uint32> lastExplosionTimes;
|
||||
static std::map<ObjectGuid, bool> hasMoved;
|
||||
|
||||
ObjectGuid botGuid = bot->GetGUID();
|
||||
|
||||
// When cast starts, record the time
|
||||
if (boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(69839))
|
||||
{
|
||||
if (lastExplosionTimes[botGuid] == 0) // Only set if not already set
|
||||
{
|
||||
lastExplosionTimes[botGuid] = time(nullptr);
|
||||
hasMoved[botGuid] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If explosion cast is no longer active, reset the timers
|
||||
if (!boss->HasUnitState(UNIT_STATE_CASTING) || !boss->FindCurrentSpellBySpellId(69839))
|
||||
{
|
||||
if (lastExplosionTimes[botGuid] > 0 && time(nullptr) - lastExplosionTimes[botGuid] >= 16)
|
||||
{
|
||||
lastExplosionTimes[botGuid] = 0;
|
||||
hasMoved[botGuid] = false;
|
||||
return 1.0f; // Allow normal actions to resume
|
||||
}
|
||||
}
|
||||
|
||||
// If 9 seconds have passed since cast start and we haven't moved yet
|
||||
if (lastExplosionTimes[botGuid] > 0 && !hasMoved[botGuid] && time(nullptr) - lastExplosionTimes[botGuid] >= 9)
|
||||
{
|
||||
if (dynamic_cast<MovementAction*>(action)
|
||||
&& !dynamic_cast<IccRotfaceMoveAwayFromExplosionAction*>(action))
|
||||
{
|
||||
return 0.0f; // Block other movement actions
|
||||
}
|
||||
hasMoved[botGuid] = true; // Mark that we've initiated movement
|
||||
}
|
||||
|
||||
// Continue blocking other movements for 7 seconds after moving
|
||||
if (hasMoved[botGuid] && time(nullptr) - lastExplosionTimes[botGuid] < 16 // 9 seconds wait + 7 seconds stay
|
||||
&& dynamic_cast<MovementAction*>(action)
|
||||
&& !dynamic_cast<IccRotfaceMoveAwayFromExplosionAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
/*float IccRotfaceGroupPositionMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (dynamic_cast<IccRotfaceGroupPositionAction*>(action))
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f;
|
||||
}*/
|
||||
|
||||
float IccAddsPutricideMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "professor putricide");
|
||||
if (!boss)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
{
|
||||
Aura* aura = botAI->GetAura("mutated plague", bot, false, true);
|
||||
if (aura && aura->GetStackAmount() >= 4)
|
||||
{
|
||||
if (dynamic_cast<CastTauntAction*>(action) || dynamic_cast<CastDarkCommandAction*>(action) ||
|
||||
dynamic_cast<CastHandOfReckoningAction*>(action) || dynamic_cast<CastGrowlAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamic_cast<IccPutricideVolatileOozeAction*>(action) || dynamic_cast<IccPutricideGasCloudAction*>(action))
|
||||
{
|
||||
if (dynamic_cast<AvoidMalleableGooAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsDps(bot))
|
||||
{
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||
bool hasAdds = false;
|
||||
for (auto& guid : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (unit && (unit->GetEntry() == 37697 || unit->GetEntry() == 38604 || unit->GetEntry() == 38758 || unit->GetEntry() == 38759 ||//volatile ooze
|
||||
unit->GetEntry() == 37562 || unit->GetEntry() == 38602 || unit->GetEntry() == 38760 || unit->GetEntry() == 38761)) //gas cloud
|
||||
{
|
||||
hasAdds = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasAdds)
|
||||
{
|
||||
if (dynamic_cast<IccPutricideVolatileOozeAction*>(action) || dynamic_cast<IccPutricideGasCloudAction*>(action))
|
||||
return 2.0f;
|
||||
else if (dynamic_cast<DpsAssistAction*>(action) || dynamic_cast<TankAssistAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
//bpc
|
||||
float IccBpcAssistMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (!action)
|
||||
return 1.0f;
|
||||
|
||||
Unit* keleseth = AI_VALUE2(Unit*, "find target", "prince keleseth");
|
||||
if (!keleseth || !keleseth->IsAlive())
|
||||
return 1.0f;
|
||||
|
||||
// For assist tank during BPC fight
|
||||
if (botAI->IsAssistTank(bot))
|
||||
{
|
||||
// Allow BPC-specific actions
|
||||
if (dynamic_cast<IccBpcKelesethTankAction*>(action) ||
|
||||
dynamic_cast<IccBpcNucleusAction*>(action))
|
||||
return 1.0f;
|
||||
|
||||
// Disable normal assist behavior
|
||||
if (dynamic_cast<TankAssistAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
// Disable following
|
||||
if (dynamic_cast<FollowAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
//BQL
|
||||
float IccBqlPactOfDarkfallenMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (!action)
|
||||
return 1.0f;
|
||||
|
||||
if (action->getName() == "icc bql pact of darkfallen")
|
||||
return 1.0f;
|
||||
|
||||
// If bot has Pact of Darkfallen aura, return 0 for all other actions
|
||||
if (bot->HasAura(71340))
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IccBqlVampiricBiteMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "blood-queen lana'thel");
|
||||
if (!boss)
|
||||
return 1.0f;
|
||||
|
||||
if (bot->HasAura(70877) || bot->HasAura(71474)) // If bot has frenzied bloodthirst
|
||||
{
|
||||
if (dynamic_cast<IccBqlVampiricBiteAction*>(action))
|
||||
return 5.0f; // Highest priority for bite action
|
||||
else if (dynamic_cast<DpsAssistAction*>(action) ||
|
||||
dynamic_cast<TankAssistAction*>(action) ||
|
||||
dynamic_cast<CastDebuffSpellOnAttackerAction*>(action) ||
|
||||
dynamic_cast<CombatFormationMoveAction*>(action))
|
||||
return 0.0f; // Disable all formation/movement actions
|
||||
else
|
||||
return 0.0f; // Disable all other actions
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
//VDW
|
||||
float IccValithriaDreamCloudMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (!bot->HasAura(70766))
|
||||
return 1.0f;
|
||||
|
||||
// If bot is in dream state, prioritize cloud collection over other actions
|
||||
if (bot->HasAura(70766) && dynamic_cast<IccValithriaDreamCloudAction*>(action))
|
||||
return 2.0f;
|
||||
else if (dynamic_cast<FollowAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
//SINDRAGOSA
|
||||
float IccSindragosaTankPositionMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa");
|
||||
if (!boss)
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<IccSindragosaTankPositionAction*>(action))
|
||||
return 1.0f;
|
||||
else if (dynamic_cast<CombatFormationMoveAction*>(action))
|
||||
return 0.0f;
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IccSindragosaFrostBeaconMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa");
|
||||
if (!boss)
|
||||
return 1.0f;
|
||||
|
||||
if (!dynamic_cast<IccSindragosaFrostBeaconAction*>(action))
|
||||
return 1.0f;
|
||||
|
||||
// Highest priority if we have beacon
|
||||
if (bot->HasAura(70126))
|
||||
return 2.0f;
|
||||
|
||||
// Lower priority for non-beaconed players
|
||||
float const MIN_SAFE_DISTANCE = 11.0f;
|
||||
GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||
|
||||
for (auto& member : members)
|
||||
{
|
||||
Unit* player = botAI->GetUnit(member);
|
||||
if (!player || player->GetGUID() == bot->GetGUID())
|
||||
continue;
|
||||
|
||||
if (player->HasAura(70126)) // Frost Beacon
|
||||
{
|
||||
float dist = bot->GetExactDist2d(player);
|
||||
if (dist < MIN_SAFE_DISTANCE)
|
||||
return 1.5f; // Medium priority if too close to beaconed player
|
||||
}
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IccSindragosaBlisteringColdPriorityMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa");
|
||||
if (!boss)
|
||||
return 1.0f;
|
||||
|
||||
// Check if boss is casting blistering cold (using both normal and heroic spell IDs)
|
||||
if (boss->HasUnitState(UNIT_STATE_CASTING) &&
|
||||
(boss->FindCurrentSpellBySpellId(70123) || boss->FindCurrentSpellBySpellId(71047) ||
|
||||
boss->FindCurrentSpellBySpellId(71048) || boss->FindCurrentSpellBySpellId(71049)))
|
||||
{
|
||||
// If this is the blistering cold action, give it highest priority
|
||||
if (dynamic_cast<IccSindragosaBlisteringColdAction*>(action) ||
|
||||
dynamic_cast<IccSindragosaTankSwapPositionAction*>(action))
|
||||
return 5.0f;
|
||||
|
||||
// Disable all other actions while blistering cold is casting
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IccSindragosaMysticBuffetMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa");
|
||||
if (!boss)
|
||||
return 1.0f;
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
{
|
||||
Aura* aura = botAI->GetAura("mystic buffet", bot, false, true);
|
||||
if (aura && aura->GetStackAmount() >= 8)
|
||||
{
|
||||
if (dynamic_cast<CastTauntAction*>(action) || dynamic_cast<CastDarkCommandAction*>(action) ||
|
||||
dynamic_cast<CastHandOfReckoningAction*>(action) || dynamic_cast<CastGrowlAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (boss->GetVictim() == bot)
|
||||
return 1.0f;
|
||||
|
||||
// Only modify actions if we have buffet stacks
|
||||
Aura* aura = bot->GetAura(70127);
|
||||
Aura* aura2 = bot->GetAura(72528);
|
||||
|
||||
// Return normal priority if no auras or not enough stacks
|
||||
if (!aura && !aura2)
|
||||
return 1.0f;
|
||||
|
||||
bool hasEnoughStacks = (aura && aura->GetStackAmount() >= 3) || (aura2 && aura2->GetStackAmount() >= 3);
|
||||
if (!hasEnoughStacks)
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<IccSindragosaMysticBuffetAction*>(action) ||
|
||||
dynamic_cast<IccSindragosaTankSwapPositionAction*>(action))
|
||||
return 5.0f;
|
||||
else if (dynamic_cast<CombatFormationMoveAction*>(action) ||
|
||||
dynamic_cast<IccSindragosaTankPositionAction*>(action)
|
||||
|| dynamic_cast<FollowAction*>(action) || dynamic_cast<TankAssistAction*>(action))
|
||||
return 0.0f;
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IccSindragosaFrostBombMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (!action || !bot || !bot->IsAlive())
|
||||
return 1.0f;
|
||||
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa");
|
||||
if (!boss)
|
||||
return 1.0f;
|
||||
|
||||
float const MAX_REACTION_RANGE = 200.0f;
|
||||
|
||||
// Check if there's an active frost bomb marker within range
|
||||
bool hasMarkerInRange = false;
|
||||
float closestDist = std::numeric_limits<float>::max();
|
||||
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (!unit || !unit->IsAlive())
|
||||
continue;
|
||||
|
||||
if (unit->HasAura(70022)) // Frost bomb visual
|
||||
{
|
||||
float dist = bot->GetDistance(unit);
|
||||
if (dist <= MAX_REACTION_RANGE && dist < closestDist)
|
||||
{
|
||||
hasMarkerInRange = true;
|
||||
closestDist = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasMarkerInRange)
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<IccSindragosaFrostBombAction*>(action))
|
||||
return 5.0f;
|
||||
else if (dynamic_cast<CombatFormationMoveAction*>(action) ||
|
||||
dynamic_cast<IccSindragosaTankPositionAction*>(action)
|
||||
|| dynamic_cast<IccSindragosaBlisteringColdAction*>(action)
|
||||
|| dynamic_cast<FollowAction*>(action))
|
||||
return 0.0f;
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IccLichKingNecroticPlagueMultiplier::GetValue(Action* action)
|
||||
{
|
||||
// Allow plague movement action to proceed
|
||||
if (dynamic_cast<IccLichKingNecroticPlagueAction*>(action))
|
||||
return 1.0f;
|
||||
// Block combat formation and cure actions by default
|
||||
else if (dynamic_cast<CombatFormationMoveAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
// Handle cure actions
|
||||
if (dynamic_cast<CurePartyMemberAction*>(action))
|
||||
{
|
||||
static std::map<ObjectGuid, uint32> plagueTimes;
|
||||
static std::map<ObjectGuid, bool> allowCure;
|
||||
|
||||
Unit* target = action->GetTarget();
|
||||
if (!target || !target->IsPlayer())
|
||||
return 0.0f;
|
||||
|
||||
ObjectGuid targetGuid = target->GetGUID();
|
||||
uint32 currentTime = getMSTime();
|
||||
|
||||
// Check if target has plague
|
||||
bool hasPlague = target->HasAura(70338) || target->HasAura(73785) ||
|
||||
target->HasAura(73786) || target->HasAura(73787) ||
|
||||
target->HasAura(70337) || target->HasAura(73912) ||
|
||||
target->HasAura(73913) || target->HasAura(73914);
|
||||
|
||||
// If no plague, reset timers and block cure
|
||||
if (!hasPlague)
|
||||
{
|
||||
plagueTimes.erase(targetGuid);
|
||||
allowCure.erase(targetGuid);
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// If we haven't seen this plague yet, start the timer
|
||||
if (plagueTimes.find(targetGuid) == plagueTimes.end())
|
||||
{
|
||||
plagueTimes[targetGuid] = currentTime;
|
||||
allowCure[targetGuid] = false;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// If we've already allowed cure for this plague instance, keep allowing it
|
||||
if (allowCure[targetGuid])
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// Check if enough time has passed
|
||||
uint32 timeSincePlague = currentTime - plagueTimes[targetGuid];
|
||||
if (timeSincePlague >= 3000)
|
||||
{
|
||||
allowCure[targetGuid] = true;
|
||||
return 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IccLichKingAddsMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "the lich king");
|
||||
if (!boss)
|
||||
return 1.0f;
|
||||
|
||||
if (botAI->IsMainTank(bot) && dynamic_cast<IccLichKingWinterAction*>(action))
|
||||
{
|
||||
if (dynamic_cast<TankAssistAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsAssistTank(bot))
|
||||
{
|
||||
// Allow BPC-specific actions
|
||||
if (dynamic_cast<IccLichKingAddsAction*>(action))
|
||||
return 1.0f;
|
||||
|
||||
// Disable normal assist behavior
|
||||
if (dynamic_cast<TankAssistAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
if (dynamic_cast<CurePartyMemberAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
// Disable following
|
||||
if (dynamic_cast<FollowAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
//raging spirit, Ice sphere, valkyere shadowguard, sphere 36633 39305 39306 39307
|
||||
Reference in New Issue
Block a user