mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
10HC until PP (#872)
* 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 * GS fixed bots not returning to their ship for A and H Bots will return back to ship after killing mage * PP gas cloud kiting improved PP gas cloud kiting improved * BPC targeting fixed Bots will mark valid prince with skull RTI now * BQL added melee spread in air pahse BQL added melee spread * VDW healing rotation improved Healers will now use strong heals and hots * Fixed Necrotic Plague Fixed issue with Necrotic where it would get dispelled too soon, or would not get dispelled at all * LK Update Refined defile logic Added 3 points for ranged and melee in winter phase (east, west, south when facing throne) fixed frost spheres targeting (hunter will focus them) Atm bots will reset z axis if they fall underground or if they get teleported by lk Better positioning in 1st phase * 10HC update until PP LK defile improved for 10nm (bots sometimes stood 2 close to defile until it grew few times) Improved rotface for HC PP remade for 10HC. Gas cloud is now properly kited Fixed a rare case of server crash when there were ooze and gas cloud alive at same time. Bots will move around puddles according to its size now. Bots that get unboud plague will simply move away from raid and die thus loosing it from raid. Volatile ooze improved stacking. Fixed ranged sometimes glitching thru walls when spreading out from other members. 10HC PP is now doable but its hard without summoning (summoning break gascloud and ooze targets so its easier to do). You need to watch boss so you dont phase 2 soon otherwise you will get 2x ooze and cloud which is almoust always a wipe. If abo is not played near perfection bots will struggle with oozes and gas clouds if they are not slowed on time. Always save energy to slow gas cloud since it will wipe the group if it reach its target. Bots will sometimes stand in puddle, just command them to move and they will figure out what to do. todo (proper malleable handling) * Up until Sindy 10HC BPC added shadow prison handling, bots stop moving if more than 12 stack, tanks more than 18 Improved spreading logic VDW fixed issue where bots in portal wold move at half speed compared to real player * fixed accidental change
This commit is contained in:
@@ -708,18 +708,20 @@ bool IccRotfaceTankPositionAction::Execute(Event event)
|
||||
if (bot->GetExactDist2d(ICC_ROTFACE_TANK_POSITION) > 7.0f)
|
||||
return MoveTo(bot->GetMapId(), ICC_ROTFACE_TANK_POSITION.GetPositionX(),
|
||||
ICC_ROTFACE_TANK_POSITION.GetPositionY(), ICC_ROTFACE_TANK_POSITION.GetPositionZ(), false,
|
||||
false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
false, false, true, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
bool hasOozeFlood = botAI->HasAura("Ooze Flood", bot);
|
||||
|
||||
// Assist tank positioning for big ooze
|
||||
if (botAI->IsAssistTank(bot))
|
||||
{
|
||||
// If we have the ooze flood aura, move away
|
||||
if (bot->HasAura(71215))
|
||||
if (hasOozeFlood)
|
||||
{
|
||||
return MoveTo(boss->GetMapId(), boss->GetPositionX() + 5.0f * cos(bot->GetAngle(boss)),
|
||||
boss->GetPositionY() + 5.0f * sin(bot->GetAngle(boss)), bot->GetPositionZ(), false,
|
||||
false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
false, false, true, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
Unit* bigOoze = AI_VALUE2(Unit*, "find target", "big ooze");
|
||||
@@ -740,7 +742,7 @@ bool IccRotfaceTankPositionAction::Execute(Event event)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), ICC_ROTFACE_BIG_OOZE_POSITION.GetPositionX(),
|
||||
ICC_ROTFACE_BIG_OOZE_POSITION.GetPositionY(), ICC_ROTFACE_BIG_OOZE_POSITION.GetPositionZ(),
|
||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
false, false, false, true, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
return Attack(bigOoze);
|
||||
}
|
||||
@@ -763,6 +765,7 @@ bool IccRotfaceGroupPositionAction::Execute(Event event)
|
||||
|
||||
// Check for puddles and move away if too close
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
bool hasOozeFlood = botAI->HasAura("Ooze Flood", bot);
|
||||
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
@@ -774,7 +777,7 @@ bool IccRotfaceGroupPositionAction::Execute(Event event)
|
||||
float puddleDistance = bot->GetExactDist2d(unit);
|
||||
|
||||
|
||||
if (puddleDistance < 30.0f && (bot->HasAura(71215) || bot->HasAura(69789)))
|
||||
if (puddleDistance < 30.0f && (hasOozeFlood))
|
||||
{
|
||||
float dx = boss->GetPositionX() - unit->GetPositionX();
|
||||
float dy = boss->GetPositionY() - unit->GetPositionY();
|
||||
@@ -786,7 +789,7 @@ bool IccRotfaceGroupPositionAction::Execute(Event event)
|
||||
float moveY = boss->GetPositionY() + (moveDistance * sin(angle));
|
||||
|
||||
return MoveTo(boss->GetMapId(), moveX, moveY, boss->GetPositionZ(),
|
||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -794,20 +797,22 @@ bool IccRotfaceGroupPositionAction::Execute(Event event)
|
||||
|
||||
// Check if we're targeted by little ooze
|
||||
Unit* smallOoze = AI_VALUE2(Unit*, "find target", "little ooze");
|
||||
if (smallOoze && smallOoze->GetVictim() == bot)
|
||||
bool hasMutatedInfection = botAI->HasAura("Mutated Infection", bot);
|
||||
|
||||
if ((smallOoze && smallOoze->GetVictim() == bot) || hasMutatedInfection)
|
||||
{
|
||||
if (bot->GetExactDist2d(ICC_ROTFACE_BIG_OOZE_POSITION) > 3.0f)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), ICC_ROTFACE_BIG_OOZE_POSITION.GetPositionX(),
|
||||
ICC_ROTFACE_BIG_OOZE_POSITION.GetPositionY(), ICC_ROTFACE_BIG_OOZE_POSITION.GetPositionZ(),
|
||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
false, false, false, true, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
return true; // Stay at position
|
||||
}
|
||||
|
||||
if(botAI->IsRanged(bot) || botAI->IsHeal(bot))
|
||||
{
|
||||
if (!bot->HasAura(71215) && !bot->HasAura(69789)) // ooze flood id
|
||||
if (!hasOozeFlood)
|
||||
{
|
||||
float radius = 10.0f;
|
||||
Unit* closestMember = nullptr;
|
||||
@@ -865,55 +870,140 @@ bool IccRotfaceMoveAwayFromExplosionAction::Execute(Event event)
|
||||
|
||||
// Move to the position
|
||||
return MoveTo(bot->GetMapId(), moveX, moveY, moveZ,
|
||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
false, false, false, false, MovementPriority::MOVEMENT_FORCED);
|
||||
}
|
||||
|
||||
//PP
|
||||
|
||||
bool IccPutricideGrowingOozePuddleAction::Execute(Event event)
|
||||
{
|
||||
const float radius = 12.0f;
|
||||
const float BASE_RADIUS = 2.0f;
|
||||
const float STACK_MULTIPLIER = 0.5f;
|
||||
const float MIN_DISTANCE = 0.1f; // Minimum distance to consider when bot is very close or inside puddle
|
||||
|
||||
// Get the nearest hostile NPCs
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
float closestDistance = FLT_MAX;
|
||||
Unit* closestPuddle = nullptr;
|
||||
float closestSafeDistance = BASE_RADIUS;
|
||||
|
||||
// Find the closest puddle and its safe distance
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (unit && unit->GetEntry() == 37690) //growing ooze puddle ID
|
||||
{
|
||||
float currentDistance = bot->GetDistance2d(unit);
|
||||
// Move away from the puddle if the bot is too close
|
||||
if (currentDistance < radius)
|
||||
// Use GetExactDist instead of GetDistance2d to handle Z-axis
|
||||
float currentDistance = std::max(MIN_DISTANCE, bot->GetExactDist(unit));
|
||||
if (currentDistance < closestDistance)
|
||||
{
|
||||
return MoveAway(unit, radius - currentDistance);
|
||||
closestDistance = currentDistance;
|
||||
closestPuddle = unit;
|
||||
|
||||
// Calculate safe distance for this puddle
|
||||
if (Aura* grow = unit->GetAura(70347))
|
||||
{
|
||||
closestSafeDistance = BASE_RADIUS + (grow->GetStackAmount() * STACK_MULTIPLIER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a puddle that's too close, move away from it
|
||||
if (closestPuddle && closestDistance < closestSafeDistance)
|
||||
{
|
||||
float botX = bot->GetPositionX();
|
||||
float botY = bot->GetPositionY();
|
||||
float botZ = bot->GetPositionZ();
|
||||
|
||||
// Calculate vector from puddle to bot
|
||||
float dx = botX - closestPuddle->GetPositionX();
|
||||
float dy = botY - closestPuddle->GetPositionY();
|
||||
float dist = std::max(MIN_DISTANCE, sqrt(dx * dx + dy * dy));
|
||||
|
||||
// If we're too close or inside, pick a random direction to move
|
||||
if (dist < MIN_DISTANCE * 2)
|
||||
{
|
||||
float randomAngle = float(rand()) / float(RAND_MAX) * 2 * M_PI;
|
||||
dx = cos(randomAngle);
|
||||
dy = sin(randomAngle);
|
||||
}
|
||||
else
|
||||
{
|
||||
dx /= dist;
|
||||
dy /= dist;
|
||||
}
|
||||
|
||||
// Try different angles to find a safe path
|
||||
const int numAngles = 8;
|
||||
float bestMoveX = botX;
|
||||
float bestMoveY = botY;
|
||||
bool foundPath = false;
|
||||
float moveDistance = closestSafeDistance - closestDistance + 2.0f; // Add 2 yards buffer
|
||||
|
||||
for (int i = 0; i < numAngles; i++)
|
||||
{
|
||||
float angle = (2 * M_PI * i) / numAngles;
|
||||
float rotatedDx = dx * cos(angle) - dy * sin(angle);
|
||||
float rotatedDy = dx * sin(angle) + dy * cos(angle);
|
||||
|
||||
float testX = botX + rotatedDx * moveDistance;
|
||||
float testY = botY + rotatedDy * moveDistance;
|
||||
float testZ = botZ;
|
||||
|
||||
// Check if this move would put us too close to any other puddle
|
||||
bool tooCloseToOtherPuddle = false;
|
||||
for (auto& otherNpc : npcs)
|
||||
{
|
||||
Unit* otherUnit = botAI->GetUnit(otherNpc);
|
||||
if (otherUnit && otherUnit->GetEntry() == 37690 && otherUnit != closestPuddle)
|
||||
{
|
||||
float otherSafeDistance = BASE_RADIUS;
|
||||
if (Aura* grow = otherUnit->GetAura(70347))
|
||||
{
|
||||
otherSafeDistance = BASE_RADIUS + (grow->GetStackAmount() * STACK_MULTIPLIER);
|
||||
}
|
||||
|
||||
float newDist = sqrt(pow(testX - otherUnit->GetPositionX(), 2) +
|
||||
pow(testY - otherUnit->GetPositionY(), 2));
|
||||
if (newDist < otherSafeDistance)
|
||||
{
|
||||
tooCloseToOtherPuddle = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tooCloseToOtherPuddle && bot->IsWithinLOS(testX, testY, testZ))
|
||||
{
|
||||
bestMoveX = testX;
|
||||
bestMoveY = testY;
|
||||
foundPath = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundPath)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), bestMoveX, bestMoveY, botZ,
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IccPutricideVolatileOozeAction::Execute(Event event)
|
||||
{
|
||||
const float POSITION_TOLERANCE = 5.0f;
|
||||
const float STACK_DISTANCE = 8.0f;
|
||||
const float SAFE_DISTANCE = 20.0f;
|
||||
|
||||
// 1. Main tank positioning
|
||||
if (botAI->IsMainTank(bot))
|
||||
return MoveTo(bot->GetMapId(), ICC_PUTRICIDE_TANK_OOZE_POSITION.GetPositionX(),
|
||||
ICC_PUTRICIDE_TANK_OOZE_POSITION.GetPositionY(),
|
||||
ICC_PUTRICIDE_TANK_OOZE_POSITION.GetPositionZ(),
|
||||
false, true, false, true, MovementPriority::MOVEMENT_NORMAL);
|
||||
|
||||
// Find the ooze
|
||||
Unit* ooze = AI_VALUE2(Unit*, "find target", "volatile ooze");
|
||||
|
||||
// If bot is melee (and not main tank), always attack ooze if it exists
|
||||
if (botAI->IsMelee(bot) && ooze)
|
||||
{
|
||||
bot->SetTarget(ooze->GetGUID());
|
||||
return Attack(ooze);
|
||||
}
|
||||
bool botHasAura = botAI->HasAura("Volatile Ooze Adhesive", bot);
|
||||
bool botHasAura2 = botAI->HasAura("Gaseous Bloat", bot);
|
||||
bool botHasAura3 = botAI->HasAura("Unbound Plague", bot);
|
||||
|
||||
if (botHasAura2 || botHasAura3)
|
||||
return false;
|
||||
|
||||
// Check for aura on any group member
|
||||
Group* group = bot->GetGroup();
|
||||
@@ -921,60 +1011,80 @@ bool IccPutricideVolatileOozeAction::Execute(Event event)
|
||||
return false;
|
||||
|
||||
Unit* auraTarget = nullptr;
|
||||
Unit* stackTarget = nullptr;
|
||||
bool anyoneHasAura = false;
|
||||
bool botHasAura = bot->HasAura(70447); // Check if this bot has the aura
|
||||
|
||||
// First, try to find someone with the aura
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (!member)
|
||||
if (!member || !member->IsAlive() || member == bot)
|
||||
continue;
|
||||
|
||||
if (member->HasAura(70447)) // Volatile Ooze Adhesive
|
||||
if (botAI->HasAura("Volatile Ooze Adhesive", member))
|
||||
{
|
||||
anyoneHasAura = true;
|
||||
auraTarget = member;
|
||||
stackTarget = member;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no one has aura, find a ranged player to stack with
|
||||
if (!anyoneHasAura && !stackTarget)
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (!member || !member->IsAlive() || member == bot ||
|
||||
botAI->IsTank(member) || botAI->HasAura("Gaseous Bloat", member) ||
|
||||
botAI->HasAura("Unbound Plague", member))
|
||||
continue;
|
||||
|
||||
if (botAI->IsRanged(member))
|
||||
{
|
||||
stackTarget = member;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For melee
|
||||
if (botAI->IsMelee(bot) && !botAI->IsMainTank(bot))
|
||||
{
|
||||
// If ooze exists and someone has aura, attack the ooze
|
||||
if (ooze && anyoneHasAura)
|
||||
{
|
||||
bot->SetTarget(ooze->GetGUID());
|
||||
return Attack(ooze);
|
||||
}
|
||||
// Otherwise stack with ranged
|
||||
else if (stackTarget)
|
||||
{
|
||||
if (bot->GetDistance2d(stackTarget) > STACK_DISTANCE)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), stackTarget->GetPositionX(),
|
||||
stackTarget->GetPositionY(), stackTarget->GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For ranged and healers
|
||||
if (botAI->IsRanged(bot) || botAI->IsHeal(bot))
|
||||
{
|
||||
// If bot has aura or someone else has aura, stack with aura target
|
||||
if (botHasAura || (anyoneHasAura && auraTarget))
|
||||
// Always try to stack
|
||||
if (stackTarget && bot->GetDistance2d(stackTarget) > STACK_DISTANCE)
|
||||
{
|
||||
Position targetPos;
|
||||
targetPos.m_positionX = auraTarget->GetPositionX();
|
||||
targetPos.m_positionY = auraTarget->GetPositionY();
|
||||
targetPos.m_positionZ = auraTarget->GetPositionZ();
|
||||
|
||||
if (bot->GetExactDist2d(targetPos) > STACK_DISTANCE)
|
||||
{
|
||||
bot->AttackStop();
|
||||
return MoveTo(bot->GetMapId(), targetPos.GetPositionX(),
|
||||
targetPos.GetPositionY(), targetPos.GetPositionZ(),
|
||||
false, true, false, true, MovementPriority::MOVEMENT_NORMAL);
|
||||
}
|
||||
}
|
||||
// If no one has aura and ooze exists, maintain safe distance
|
||||
else if (ooze)
|
||||
{
|
||||
float currentDist = bot->GetExactDist2d(ooze);
|
||||
if (abs(currentDist - SAFE_DISTANCE) > POSITION_TOLERANCE)
|
||||
{
|
||||
// Calculate position 20 yards from ooze
|
||||
float angle = ooze->GetAngle(bot);
|
||||
float moveX = ooze->GetPositionX() + (SAFE_DISTANCE * cos(angle));
|
||||
float moveY = ooze->GetPositionY() + (SAFE_DISTANCE * sin(angle));
|
||||
|
||||
return MoveTo(bot->GetMapId(), moveX, moveY, bot->GetPositionZ(),
|
||||
false, true, false, true, MovementPriority::MOVEMENT_NORMAL);
|
||||
}
|
||||
bot->AttackStop();
|
||||
return MoveTo(bot->GetMapId(), stackTarget->GetPositionX(),
|
||||
stackTarget->GetPositionY(), stackTarget->GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
// If in position and ooze exists, attack it (except healers)
|
||||
if (ooze && !botAI->IsHeal(bot))
|
||||
// If stacked and ooze exists, attack it (except healers)
|
||||
if (ooze && !botAI->IsHeal(bot) && stackTarget &&
|
||||
bot->GetDistance2d(stackTarget) <= STACK_DISTANCE)
|
||||
{
|
||||
bot->SetTarget(ooze->GetGUID());
|
||||
return Attack(ooze);
|
||||
@@ -988,106 +1098,98 @@ bool IccPutricideVolatileOozeAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t IccPutricideGasCloudAction::lastKnownPosition = 0;
|
||||
|
||||
bool IccPutricideGasCloudAction::Execute(Event event)
|
||||
{
|
||||
if (botAI->IsMainTank(bot))
|
||||
return false;
|
||||
|
||||
// Find the gas cloud
|
||||
Unit* gasCloud = AI_VALUE2(Unit*, "find target", "gas cloud");
|
||||
if (!gasCloud)
|
||||
return false;
|
||||
|
||||
static ObjectGuid lastGasCloudGuid;
|
||||
// If this is a new gas cloud, reset to position 2
|
||||
if (lastGasCloudGuid != gasCloud->GetGUID())
|
||||
{
|
||||
lastGasCloudGuid = gasCloud->GetGUID();
|
||||
lastKnownPosition = 0; // This will make it go to position 2
|
||||
}
|
||||
|
||||
// Check if this bot has Gaseous Bloat
|
||||
bool botHasAura = botAI->HasAura("Gaseous Bloat", bot);
|
||||
Unit* volatileOoze = AI_VALUE2(Unit*, "find target", "volatile ooze");
|
||||
|
||||
// If bot has aura, handle movement between positions
|
||||
if(!botHasAura && volatileOoze)
|
||||
return false;
|
||||
|
||||
if (botHasAura)
|
||||
{
|
||||
// Get current position
|
||||
float dist1 = bot->GetExactDist2d(ICC_PUTRICIDE_GAS1_POSITION.GetPositionX(), ICC_PUTRICIDE_GAS1_POSITION.GetPositionY());
|
||||
float dist2 = bot->GetExactDist2d(ICC_PUTRICIDE_GAS2_POSITION.GetPositionX(), ICC_PUTRICIDE_GAS2_POSITION.GetPositionY());
|
||||
float dist3 = bot->GetExactDist2d(ICC_PUTRICIDE_GAS3_POSITION.GetPositionX(), ICC_PUTRICIDE_GAS3_POSITION.GetPositionY());
|
||||
float dist4 = bot->GetExactDist2d(ICC_PUTRICIDE_GAS4_POSITION.GetPositionX(), ICC_PUTRICIDE_GAS4_POSITION.GetPositionY());
|
||||
|
||||
uint8_t currentPosition = 0;
|
||||
const Position* nextPos = nullptr;
|
||||
float botX = bot->GetPositionX();
|
||||
float botY = bot->GetPositionY();
|
||||
float botZ = bot->GetPositionZ();
|
||||
|
||||
// Determine current position
|
||||
if (dist1 < 8.0f) currentPosition = 1;
|
||||
else if (dist2 < 8.0f) currentPosition = 2;
|
||||
else if (dist3 < 8.0f) currentPosition = 3;
|
||||
else if (dist4 < 8.0f) currentPosition = 4;
|
||||
|
||||
// If we're at a new position, update last known position
|
||||
if (currentPosition != 0 && currentPosition != lastKnownPosition)
|
||||
float cloudX = gasCloud->GetPositionX();
|
||||
float cloudY = gasCloud->GetPositionY();
|
||||
float cloudDist = gasCloud->GetExactDist2d(botX, botY);
|
||||
|
||||
// Only move if cloud is close enough to be dangerous
|
||||
if (cloudDist < 25.0f)
|
||||
{
|
||||
lastKnownPosition = currentPosition;
|
||||
}
|
||||
|
||||
// Only prevent movement if we're already moving and haven't reached the target yet
|
||||
if (lastKnownPosition != 0 && lastKnownPosition != currentPosition && AI_VALUE(bool, "moving"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine next position to move to
|
||||
if (gasCloud->GetExactDist2d(bot) < 18.0f)
|
||||
{
|
||||
switch(currentPosition)
|
||||
// Calculate vector from cloud to bot
|
||||
float dx = botX - cloudX;
|
||||
float dy = botY - cloudY;
|
||||
float dist = sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (dist > 0)
|
||||
{
|
||||
case 0: // Not at any position
|
||||
case 1:
|
||||
nextPos = &ICC_PUTRICIDE_GAS2_POSITION;
|
||||
lastKnownPosition = 2;
|
||||
break;
|
||||
case 2:
|
||||
nextPos = &ICC_PUTRICIDE_GAS3_POSITION;
|
||||
lastKnownPosition = 3;
|
||||
break;
|
||||
case 3:
|
||||
nextPos = &ICC_PUTRICIDE_GAS4_POSITION;
|
||||
lastKnownPosition = 4;
|
||||
break;
|
||||
case 4:
|
||||
nextPos = &ICC_PUTRICIDE_GAS1_POSITION;
|
||||
lastKnownPosition = 1;
|
||||
break;
|
||||
}
|
||||
dx /= dist;
|
||||
dy /= dist;
|
||||
|
||||
if (nextPos)
|
||||
{
|
||||
// Use PathGenerator to find a safe path to the target
|
||||
PathGenerator path(bot);
|
||||
path.CalculatePath(nextPos->GetPositionX(), nextPos->GetPositionY(), nextPos->GetPositionZ(), false);
|
||||
// Try different angles to find a safe path
|
||||
const int numAngles = 16; // Increased for more precise movement
|
||||
float bestMoveX = botX;
|
||||
float bestMoveY = botY;
|
||||
float bestDist = cloudDist;
|
||||
bool foundPath = false;
|
||||
|
||||
for (int i = 0; i < numAngles; i++)
|
||||
{
|
||||
float angle = (2 * M_PI * i) / numAngles;
|
||||
float rotatedDx = dx * cos(angle) - dy * sin(angle);
|
||||
float rotatedDy = dx * sin(angle) + dy * cos(angle);
|
||||
|
||||
if (path.GetPathType() == PATHFIND_NORMAL || path.GetPathType() == PATHFIND_INCOMPLETE)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), nextPos->GetPositionX(), nextPos->GetPositionY(), nextPos->GetPositionZ(),
|
||||
false, true, false, false, MovementPriority::MOVEMENT_FORCED);
|
||||
// Try different distances
|
||||
for (float testDist = 5.0f; testDist <= 15.0f; testDist += 5.0f)
|
||||
{
|
||||
float testX = botX + rotatedDx * testDist;
|
||||
float testY = botY + rotatedDy * testDist;
|
||||
float testZ = botZ;
|
||||
|
||||
float newCloudDist = gasCloud->GetExactDist2d(testX, testY);
|
||||
|
||||
// Check if this position is better
|
||||
if (newCloudDist > bestDist && bot->IsWithinLOS(testX, testY, testZ))
|
||||
{
|
||||
bestMoveX = testX;
|
||||
bestMoveY = testY;
|
||||
bestDist = newCloudDist;
|
||||
foundPath = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (foundPath)
|
||||
{
|
||||
// If no valid path found, try to move directly (old behavior)
|
||||
return MoveTo(bot->GetMapId(), nextPos->GetPositionX(), nextPos->GetPositionY(), nextPos->GetPositionZ(),
|
||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
return MoveTo(bot->GetMapId(), bestMoveX, bestMoveY, botZ,
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
else if (cloudDist < 8.0f) // Emergency move if very close and no good path found
|
||||
{
|
||||
// Try to move directly away
|
||||
float emergencyX = botX + dx * 10.0f;
|
||||
float emergencyY = botY + dy * 10.0f;
|
||||
|
||||
if (bot->IsWithinLOS(emergencyX, emergencyY, botZ))
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), emergencyX, emergencyY, botZ,
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// If bot doesn't have aura, check if anyone else does
|
||||
|
||||
else
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
@@ -1108,20 +1210,9 @@ bool IccPutricideGasCloudAction::Execute(Event event)
|
||||
}
|
||||
}
|
||||
|
||||
// If someone has aura but not this bot, attack gas cloud (except healers)
|
||||
if (someoneHasAura && !botAI->IsHeal(bot))
|
||||
{
|
||||
lastKnownPosition = 0;
|
||||
return Attack(gasCloud);
|
||||
}
|
||||
// If no one has aura yet, everyone stays at position 2
|
||||
else if (!someoneHasAura)
|
||||
{
|
||||
lastKnownPosition = 0;
|
||||
return MoveTo(bot->GetMapId(), ICC_PUTRICIDE_GAS2_POSITION.GetPositionX(),
|
||||
ICC_PUTRICIDE_GAS2_POSITION.GetPositionY(),
|
||||
ICC_PUTRICIDE_GAS2_POSITION.GetPositionZ(),
|
||||
false, false, false, true, MovementPriority::MOVEMENT_NORMAL);
|
||||
{
|
||||
return Attack(gasCloud);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1130,16 +1221,68 @@ bool IccPutricideGasCloudAction::Execute(Event event)
|
||||
|
||||
bool AvoidMalleableGooAction::Execute(Event event)
|
||||
{
|
||||
|
||||
bool hasUnboundPlague = botAI->HasAura("Unbound Plague", bot);
|
||||
const float UNBOUND_PLAGUE_DISTANCE = 15.0f;
|
||||
|
||||
// If bot has unbound plague, keep away from all other players
|
||||
if (hasUnboundPlague)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
float closestDistance = UNBOUND_PLAGUE_DISTANCE;
|
||||
Unit* closestPlayer = nullptr;
|
||||
|
||||
// Find closest player
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (!member || !member->IsAlive() || member == bot)
|
||||
continue;
|
||||
|
||||
float dist = bot->GetDistance2d(member);
|
||||
if (dist < closestDistance)
|
||||
{
|
||||
closestDistance = dist;
|
||||
closestPlayer = member;
|
||||
}
|
||||
}
|
||||
|
||||
// Move away from closest player if too close
|
||||
if (closestPlayer)
|
||||
{
|
||||
float dx = bot->GetPositionX() - closestPlayer->GetPositionX();
|
||||
float dy = bot->GetPositionY() - closestPlayer->GetPositionY();
|
||||
float dist = sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (dist > 0)
|
||||
{
|
||||
dx /= dist;
|
||||
dy /= dist;
|
||||
float moveDistance = UNBOUND_PLAGUE_DISTANCE - closestDistance + 2.0f;
|
||||
|
||||
float moveX = bot->GetPositionX() + dx * moveDistance;
|
||||
float moveY = bot->GetPositionY() + dy * moveDistance;
|
||||
|
||||
if (bot->IsWithinLOS(moveX, moveY, bot->GetPositionZ()))
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), moveX, moveY, bot->GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (botAI->IsRanged(bot) || botAI->IsHeal(bot))
|
||||
{
|
||||
float radius = 7.0f;
|
||||
float moveIncrement = 3.0f;
|
||||
bool isRanged = botAI->IsRanged(bot);
|
||||
|
||||
GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||
GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||
if (isRanged)
|
||||
{
|
||||
// Ranged: spread from other members
|
||||
for (auto& member : members)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(member);
|
||||
@@ -1149,8 +1292,18 @@ bool AvoidMalleableGooAction::Execute(Event event)
|
||||
float dist = bot->GetExactDist2d(unit);
|
||||
if (dist < radius)
|
||||
{
|
||||
float moveDistance = std::min(moveIncrement, radius - dist + 1.0f);
|
||||
return MoveAway(unit, moveDistance);
|
||||
float moveDistance = radius - dist + 1.0f;
|
||||
|
||||
// Calculate potential new position
|
||||
float angle = bot->GetAngle(unit);
|
||||
float newX = bot->GetPositionX() + cos(angle + M_PI) * moveDistance;
|
||||
float newY = bot->GetPositionY() + sin(angle + M_PI) * moveDistance;
|
||||
|
||||
// Only move if we have line of sight
|
||||
if (bot->IsWithinLOS(newX, newY, bot->GetPositionZ()))
|
||||
{
|
||||
return MoveAway(unit, moveDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1323,7 +1476,7 @@ bool IccBpcMainTankAction::Execute(Event event)
|
||||
bool IccBpcEmpoweredVortexAction::Execute(Event event)
|
||||
{
|
||||
// Double check that we're not a tank
|
||||
if (botAI->IsMainTank(bot) || botAI->IsAssistTank(bot))
|
||||
if (botAI->IsMainTank(bot) || botAI->IsAssistTank(bot) || botAI->IsTank(bot))
|
||||
return false;
|
||||
|
||||
Unit* valanar = AI_VALUE2(Unit*, "find target", "prince valanar");
|
||||
@@ -1331,65 +1484,28 @@ bool IccBpcEmpoweredVortexAction::Execute(Event event)
|
||||
return false;
|
||||
|
||||
float radius = 12.0f;
|
||||
float moveIncrement = 3.0f;
|
||||
bool isRanged = botAI->IsRanged(bot);
|
||||
|
||||
GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||
if (isRanged)
|
||||
|
||||
for (auto& member : members)
|
||||
{
|
||||
// Ranged: spread from other ranged
|
||||
for (auto& member : members)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(member);
|
||||
if (!unit || !unit->IsAlive() || unit == bot ||
|
||||
botAI->IsMainTank(bot) || botAI->IsAssistTank(bot) || !botAI->IsRanged(bot))
|
||||
continue;
|
||||
Unit* unit = botAI->GetUnit(member);
|
||||
if (!unit || !unit->IsAlive() || unit == bot)
|
||||
continue;
|
||||
|
||||
float dist = bot->GetExactDist2d(unit);
|
||||
if (dist < radius)
|
||||
{
|
||||
float moveDistance = std::min(moveIncrement, radius - dist + 1.0f);
|
||||
return MoveAway(unit, moveDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Melee: move opposite to ranged group
|
||||
float avgX = 0, avgY = 0;
|
||||
int rangedCount = 0;
|
||||
|
||||
for (auto& member : members)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(member);
|
||||
if (!unit || !unit->IsAlive() || !botAI->IsRanged(bot))
|
||||
continue;
|
||||
|
||||
avgX += unit->GetPositionX();
|
||||
avgY += unit->GetPositionY();
|
||||
rangedCount++;
|
||||
}
|
||||
|
||||
if (rangedCount > 0)
|
||||
{
|
||||
avgX /= rangedCount;
|
||||
avgY /= rangedCount;
|
||||
|
||||
// Direction from ranged to Valanar
|
||||
float dx = valanar->GetPositionX() - avgX;
|
||||
float dy = valanar->GetPositionY() - avgY;
|
||||
float len = sqrt(dx*dx + dy*dy);
|
||||
float dist = bot->GetExactDist2d(unit);
|
||||
if (dist < radius)
|
||||
{
|
||||
float moveDistance = radius - dist + 1.0f;
|
||||
|
||||
if (len > 0)
|
||||
// Calculate potential new position
|
||||
float angle = bot->GetAngle(unit);
|
||||
float newX = bot->GetPositionX() + cos(angle + M_PI) * moveDistance;
|
||||
float newY = bot->GetPositionY() + sin(angle + M_PI) * moveDistance;
|
||||
|
||||
// Only move if we have line of sight
|
||||
if (bot->IsWithinLOS(newX, newY, bot->GetPositionZ()))
|
||||
{
|
||||
dx /= len;
|
||||
dy /= len;
|
||||
float targetX = valanar->GetPositionX() + dx * 5.0f;
|
||||
float targetY = valanar->GetPositionY() + dy * 5.0f;
|
||||
float targetZ = valanar->GetPositionZ();
|
||||
bot->UpdateAllowedPositionZ(targetX, targetY, targetZ);
|
||||
|
||||
return MoveTo(bot->GetMapId(), targetX, targetY, targetZ);
|
||||
return MoveAway(unit, moveDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1706,10 +1822,15 @@ bool IccValithriaPortalAction::Execute(Event event)
|
||||
if (!portal)
|
||||
return false;
|
||||
|
||||
// Move to the portal if the bot is not at the interact distance
|
||||
if (!portal->IsWithinDistInMap(bot, INTERACTION_DISTANCE))
|
||||
// Move exactly to portal position
|
||||
float portalX = portal->GetPositionX();
|
||||
float portalY = portal->GetPositionY();
|
||||
float portalZ = portal->GetPositionZ();
|
||||
|
||||
// If not at exact portal position, move there
|
||||
if (bot->GetDistance2d(portalX, portalY) > 0.1f)
|
||||
{
|
||||
return MoveTo(portal, INTERACTION_DISTANCE);
|
||||
return MoveTo(portal->GetMapId(), portalX, portalY, portalZ, false, false, false, true, MovementPriority::MOVEMENT_NORMAL);
|
||||
}
|
||||
|
||||
// Remove shapeshift forms
|
||||
@@ -1732,6 +1853,12 @@ bool IccValithriaHealAction::Execute(Event event)
|
||||
if (!botAI->IsHeal(bot))
|
||||
return false;
|
||||
|
||||
if (!bot->HasAura(70766)) //dream state
|
||||
{
|
||||
bot->SetSpeed(MOVE_RUN, 1.0f, true);
|
||||
bot->SetSpeed(MOVE_WALK, 1.0f, true);
|
||||
bot->SetSpeed(MOVE_FLIGHT, 1.0f, true);
|
||||
}
|
||||
// Find Valithria
|
||||
if (Creature* valithria = bot->FindNearestCreature(36789, 100.0f))
|
||||
{
|
||||
@@ -1757,6 +1884,15 @@ bool IccValithriaDreamCloudAction::Execute(Event event)
|
||||
if (!bot->HasAura(70766))
|
||||
return false;
|
||||
|
||||
// Set speed to match players in dream state
|
||||
if (bot->HasAura(70766))
|
||||
{
|
||||
bot->SetSpeed(MOVE_RUN, 2.0f, true);
|
||||
bot->SetSpeed(MOVE_WALK, 2.0f, true);
|
||||
bot->SetSpeed(MOVE_FLIGHT, 2.0f, true);
|
||||
}
|
||||
|
||||
|
||||
// Find nearest cloud of either type that we haven't collected
|
||||
Creature* dreamCloud = bot->FindNearestCreature(37985, 100.0f);
|
||||
Creature* nightmareCloud = bot->FindNearestCreature(38421, 100.0f);
|
||||
@@ -2102,7 +2238,7 @@ bool IccSindragosaFrostBeaconAction::Execute(Event event)
|
||||
// Only move if the change in position is significant
|
||||
if (std::abs(moveX) > MOVE_TOLERANCE || std::abs(moveY) > MOVE_TOLERANCE)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), posX, posY, posZ,
|
||||
return MoveTo(bot->GetMapId(), posX, posY, posZ,
|
||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
}
|
||||
}
|
||||
@@ -2576,7 +2712,7 @@ bool IccLichKingAddsAction::Execute(Event event)
|
||||
if (!defiles.empty())
|
||||
{
|
||||
float baseRadius = 6.0f;
|
||||
float safetyMargin = 1.0f; // Fixed 5-yard safety margin
|
||||
float safetyMargin = 3.0f; // Fixed 3-yard safety margin
|
||||
|
||||
// First, find if we need to move from any defile
|
||||
bool needToMove = false;
|
||||
@@ -2597,7 +2733,7 @@ bool IccLichKingAddsAction::Execute(Event event)
|
||||
if (growAura)
|
||||
{
|
||||
uint8 stacks = growAura->GetStackAmount();
|
||||
currentRadius = baseRadius + (stacks * 1.25f);
|
||||
currentRadius = baseRadius + (stacks * 1.3f);
|
||||
}
|
||||
|
||||
float dx = bot->GetPositionX() - defile->GetPositionX();
|
||||
@@ -2741,14 +2877,14 @@ bool IccLichKingAddsAction::Execute(Event event)
|
||||
if (growAura)
|
||||
{
|
||||
uint8 stacks = growAura->GetStackAmount();
|
||||
currentRadius = 6.0f + (stacks * 1.25f);
|
||||
currentRadius = 6.0f + (stacks * 1.3f);
|
||||
}
|
||||
|
||||
float dx = testX - defile->GetPositionX();
|
||||
float dy = testY - defile->GetPositionY();
|
||||
float distToDefile = sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distToDefile < (currentRadius + 1.0f))
|
||||
if (distToDefile < (currentRadius + 3.0f))
|
||||
{
|
||||
isSafeFromDefiles = false;
|
||||
break;
|
||||
|
||||
@@ -28,12 +28,12 @@ const Position ICC_FESTERGUT_MELEE_SPORE = Position(4269.1772f, 3144.7673f, 360.
|
||||
const Position ICC_ROTFACE_TANK_POSITION = Position(4447.061f, 3150.9758f, 360.38568f);
|
||||
const Position ICC_ROTFACE_BIG_OOZE_POSITION = Position(4432.687f, 3142.3035f, 360.38623f);
|
||||
const Position ICC_ROTFACE_SAFE_POSITION = Position(4446.557f, 3065.6594f, 360.51843f);
|
||||
const Position ICC_PUTRICIDE_TANK_OOZE_POSITION = Position(4362.709f, 3229.1448f, 389.4083f);
|
||||
const Position ICC_PUTRICIDE_TANK_GAS_CLOUD_POSITION = Position(4397.0386f, 3221.385f, 389.3999f);
|
||||
const Position ICC_PUTRICIDE_GAS1_POSITION = Position(4350.772f, 3249.9773f, 389.39508f);
|
||||
const Position ICC_PUTRICIDE_GAS2_POSITION = Position(4390.002f, 3204.8855f, 389.39938f);
|
||||
const Position ICC_PUTRICIDE_GAS3_POSITION = Position(4367.753f, 3177.5894f, 389.39575f);
|
||||
const Position ICC_PUTRICIDE_GAS4_POSITION = Position(4321.8486f, 3206.464f, 389.3982f);
|
||||
//const Position ICC_PUTRICIDE_TANK_OOZE_POSITION = Position(4362.709f, 3229.1448f, 389.4083f);
|
||||
//const Position ICC_PUTRICIDE_TANK_GAS_CLOUD_POSITION = Position(4397.0386f, 3221.385f, 389.3999f);
|
||||
//const Position ICC_PUTRICIDE_GAS1_POSITION = Position(4350.772f, 3249.9773f, 389.39508f);
|
||||
//const Position ICC_PUTRICIDE_GAS2_POSITION = Position(4390.002f, 3204.8855f, 389.39938f);
|
||||
//const Position ICC_PUTRICIDE_GAS3_POSITION = Position(4367.753f, 3177.5894f, 389.39575f);
|
||||
//const Position ICC_PUTRICIDE_GAS4_POSITION = Position(4321.8486f, 3206.464f, 389.3982f);
|
||||
const Position ICC_BPC_OT_POSITION = Position(4649.2236f, 2796.0972f, 361.1815f);
|
||||
const Position ICC_BPC_MT_POSITION = Position(4648.5674f, 2744.847f, 361.18222f);
|
||||
const Position ICC_BQL_CENTER_POSITION = Position(4595.0f, 2769.0f, 400.0f);
|
||||
@@ -58,8 +58,6 @@ const Position ICC_LK_FROST3_POSITION = Position(503.40182f, -2067.3435f, 840.85
|
||||
const Position ICC_LK_FROSTR1_POSITION = Position(481.168f, -2177.8723f, 840.857f);
|
||||
const Position ICC_LK_FROSTR2_POSITION = Position(562.20807f, -2100.2393f, 840.857f);
|
||||
const Position ICC_LK_FROSTR3_POSITION = Position(526.35297f, -2071.0317f, 840.857f);
|
||||
|
||||
|
||||
|
||||
//Lord Marrogwar
|
||||
class IccLmTankPositionAction : public AttackAction
|
||||
@@ -236,14 +234,13 @@ class IccPutricideGasCloudAction : public AttackAction
|
||||
IccPutricideGasCloudAction(PlayerbotAI* botAI, std::string const name = "icc putricide gas cloud")
|
||||
: AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
private:
|
||||
static uint8_t lastKnownPosition; // 0 = none, 1-4 = positions 1-4
|
||||
};
|
||||
|
||||
class AvoidMalleableGooAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
AvoidMalleableGooAction(PlayerbotAI* ai) : MovementAction(ai, "avoid malleable goo") {}
|
||||
AvoidMalleableGooAction(PlayerbotAI* botAI, std::string const name = "avoid malleable goo" )
|
||||
: MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ float IccAddsPutricideMultiplier::GetValue(Action* action)
|
||||
|
||||
if (dynamic_cast<IccPutricideVolatileOozeAction*>(action) || dynamic_cast<IccPutricideGasCloudAction*>(action))
|
||||
{
|
||||
if (dynamic_cast<AvoidMalleableGooAction*>(action))
|
||||
if (dynamic_cast<AvoidMalleableGooAction*>(action) || dynamic_cast<IccPutricideGrowingOozePuddleAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
@@ -307,6 +307,22 @@ float IccBpcAssistMultiplier::GetValue(Action* action)
|
||||
if (!keleseth || !keleseth->IsAlive())
|
||||
return 1.0f;
|
||||
|
||||
Aura* aura = botAI->GetAura("Shadow Prison", bot, false, true);
|
||||
if (aura)
|
||||
{
|
||||
if (aura->GetStackAmount() > 18 && botAI->IsTank(bot))
|
||||
{
|
||||
if (dynamic_cast<MovementAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (aura->GetStackAmount() > 12 && !botAI->IsTank(bot))
|
||||
{
|
||||
if (dynamic_cast<MovementAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// For assist tank during BPC fight
|
||||
if (botAI->IsAssistTank(bot))
|
||||
{
|
||||
|
||||
@@ -76,19 +76,19 @@ void RaidIccStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
//PP
|
||||
triggers.push_back(new TriggerNode("icc putricide volatile ooze",
|
||||
NextAction::array(0, new NextAction("icc putricide volatile ooze", ACTION_EMERGENCY + 4), nullptr)));
|
||||
NextAction::array(0, new NextAction("icc putricide volatile ooze", ACTION_RAID + 4), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc putricide gas cloud",
|
||||
NextAction::array(0, new NextAction("icc putricide gas cloud", ACTION_EMERGENCY + 5), nullptr)));
|
||||
NextAction::array(0, new NextAction("icc putricide gas cloud", ACTION_RAID + 5), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc putricide growing ooze puddle",
|
||||
NextAction::array(0, new NextAction("icc putricide growing ooze puddle", ACTION_EMERGENCY + 3), nullptr)));
|
||||
NextAction::array(0, new NextAction("icc putricide growing ooze puddle", ACTION_RAID + 3), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc putricide main tank mutated plague",
|
||||
NextAction::array(0, new NextAction("taunt spell", ACTION_EMERGENCY + 6), nullptr)));
|
||||
NextAction::array(0, new NextAction("taunt spell", ACTION_RAID + 6), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc putricide malleable goo",
|
||||
NextAction::array(0, new NextAction("avoid malleable goo", ACTION_EMERGENCY + 2), nullptr)));
|
||||
NextAction::array(0, new NextAction("avoid malleable goo", ACTION_RAID + 2), nullptr)));
|
||||
|
||||
//BPC
|
||||
triggers.push_back(new TriggerNode("icc bpc keleseth tank",
|
||||
|
||||
@@ -274,7 +274,8 @@ bool IccFestergutSporeTrigger::IsActive()
|
||||
bool IccRotfaceTankPositionTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "rotface");
|
||||
if (!boss || !(botAI->IsTank(bot) || botAI->IsMainTank(bot) || botAI->IsAssistTank(bot))) { return false; }
|
||||
if (!boss || !(botAI->IsTank(bot) || botAI->IsMainTank(bot) || botAI->IsAssistTank(bot)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -300,18 +301,37 @@ bool IccRotfaceMoveAwayFromExplosionTrigger::IsActive()
|
||||
bool IccPutricideGrowingOozePuddleTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "professor putricide");
|
||||
bool botHasAura = botAI->HasAura("Gaseous Bloat", bot);
|
||||
bool botHasAura = botAI->HasAura("Gaseous Bloat", bot) || botAI->HasAura("Volatile Ooze Adhesive", bot);
|
||||
|
||||
if (!boss || botHasAura)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
// Check for nearby growing ooze puddles (37690) and slime puddles (70341)
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (!unit)
|
||||
continue;
|
||||
|
||||
uint32 entry = unit->GetEntry();
|
||||
if (entry == 37690 || entry == 70341) // Growing Ooze Puddle or Slime Puddle
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IccPutricideVolatileOozeTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "volatile ooze");
|
||||
if (!boss) { return false; }
|
||||
if (!boss)
|
||||
return false;
|
||||
|
||||
if (botAI->HasAura("Gaseous Bloat", bot))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -319,7 +339,8 @@ bool IccPutricideVolatileOozeTrigger::IsActive()
|
||||
bool IccPutricideGasCloudTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "gas cloud");
|
||||
if (!boss) { return false; }
|
||||
if (!boss)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -377,6 +398,11 @@ bool IccBpcKelesethTankTrigger::IsActive()
|
||||
if (!botAI->IsAssistTank(bot))
|
||||
return false;
|
||||
|
||||
Aura* aura = botAI->GetAura("Shadow Prison", bot, false, true);
|
||||
if (aura)
|
||||
if (aura->GetStackAmount() > 18)
|
||||
return false;
|
||||
|
||||
// First priority is to check for nucleuses that need to be picked up
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||
for (auto i = targets.begin(); i != targets.end(); ++i)
|
||||
@@ -401,6 +427,11 @@ bool IccBpcNucleusTrigger::IsActive()
|
||||
if (!botAI->IsAssistTank(bot))
|
||||
return false;
|
||||
|
||||
Aura* aura = botAI->GetAura("Shadow Prison", bot, false, true);
|
||||
if (aura)
|
||||
if (aura->GetStackAmount() > 18)
|
||||
return false;
|
||||
|
||||
// Actively look for any nucleus that isn't targeting us
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||
for (auto i = targets.begin(); i != targets.end(); ++i)
|
||||
@@ -435,6 +466,11 @@ bool IccBpcEmpoweredVortexTrigger::IsActive()
|
||||
if (!valanar || !valanar->IsAlive())
|
||||
return false;
|
||||
|
||||
Aura* aura = botAI->GetAura("Shadow Prison", bot, false, true);
|
||||
if (aura)
|
||||
if (aura->GetStackAmount() > 12)
|
||||
return false;
|
||||
|
||||
// For ranged, spread whenever Valanar is empowered
|
||||
if (botAI->IsRanged(bot))
|
||||
return valanar->HasAura(71596); // Invocation of Blood
|
||||
|
||||
Reference in New Issue
Block a user