From 1e33b28abecbc6ac24d8fc54749434218f3a0cdd Mon Sep 17 00:00:00 2001 From: kadeshar Date: Sun, 27 Jul 2025 07:51:45 +0200 Subject: [PATCH] - Added raid cheat to configuration to add posibility to turn off (#1465) - Added General Vezax strategy --- conf/playerbots.conf.dist | 3 +- src/PlayerbotAIConfig.cpp | 4 +- src/PlayerbotAIConfig.h | 3 +- src/strategy/actions/CheatAction.cpp | 5 + .../raids/ulduar/RaidUlduarActionContext.h | 6 + .../raids/ulduar/RaidUlduarActions.cpp | 228 +++++++++++------- src/strategy/raids/ulduar/RaidUlduarActions.h | 24 ++ .../raids/ulduar/RaidUlduarStrategy.cpp | 15 ++ .../raids/ulduar/RaidUlduarTriggerContext.h | 6 + .../raids/ulduar/RaidUlduarTriggers.cpp | 62 +++++ .../raids/ulduar/RaidUlduarTriggers.h | 30 +++ 11 files changed, 299 insertions(+), 87 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index b64454ce..b8263ee1 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -501,9 +501,10 @@ AiPlayerbot.AutoGearScoreLimit = 0 # "mana" (bots have infinite mana) # "power" (bots have infinite energy, rage, and runic power) # "taxi" (bots may use all flight paths, though they will not actually learn them) +# "raid" (bots use cheats implemented into raid strategies) # To use multiple cheats, separate them by commas below (e.g., to enable all, use "gold,health,mana,power,taxi") # Default: taxi is enabled -AiPlayerbot.BotCheats = "taxi" +AiPlayerbot.BotCheats = "taxi,raid" # # diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index db1419a4..7899de84 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -448,7 +448,7 @@ bool PlayerbotAIConfig::Initialize() } botCheats.clear(); - LoadListString>(sConfigMgr->GetOption("AiPlayerbot.BotCheats", "taxi"), + LoadListString>(sConfigMgr->GetOption("AiPlayerbot.BotCheats", "taxi,raid"), botCheats); botCheatMask = 0; @@ -463,6 +463,8 @@ bool PlayerbotAIConfig::Initialize() botCheatMask |= (uint32)BotCheatMask::mana; if (std::find(botCheats.begin(), botCheats.end(), "power") != botCheats.end()) botCheatMask |= (uint32)BotCheatMask::power; + if (std::find(botCheats.begin(), botCheats.end(), "raid") != botCheats.end()) + botCheatMask |= (uint32)BotCheatMask::raid; LoadListString>(sConfigMgr->GetOption("AiPlayerbot.AllowedLogFiles", ""), allowedLogFiles); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 65b99c5d..cfdf70ea 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -22,7 +22,8 @@ enum class BotCheatMask : uint32 health = 4, mana = 8, power = 16, - maxMask = 32 + raid = 32, + maxMask = 64 }; enum class HealingManaEfficiency : uint8 diff --git a/src/strategy/actions/CheatAction.cpp b/src/strategy/actions/CheatAction.cpp index 1092ca34..f627105f 100644 --- a/src/strategy/actions/CheatAction.cpp +++ b/src/strategy/actions/CheatAction.cpp @@ -53,6 +53,9 @@ BotCheatMask CheatAction::GetCheatMask(std::string const cheat) if (cheat == "power") return BotCheatMask::power; + if (cheat == "raid") + return BotCheatMask::raid; + return BotCheatMask::none; } @@ -70,6 +73,8 @@ std::string const CheatAction::GetCheatName(BotCheatMask cheatMask) return "mana"; case BotCheatMask::power: return "power"; + case BotCheatMask::raid: + return "raid"; default: return "none"; } diff --git a/src/strategy/raids/ulduar/RaidUlduarActionContext.h b/src/strategy/raids/ulduar/RaidUlduarActionContext.h index da16537a..c27a2580 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActionContext.h +++ b/src/strategy/raids/ulduar/RaidUlduarActionContext.h @@ -62,6 +62,9 @@ public: creators["mimiron rocket strike action"] = &RaidUlduarActionContext::mimiron_rocket_strike_action; creators["mimiron phase 4 mark dps action"] = &RaidUlduarActionContext::mimiron_phase_4_mark_dps_action; creators["mimiron cheat action"] = &RaidUlduarActionContext::mimiron_cheat_action; + creators["vezax cheat action"] = &RaidUlduarActionContext::vezax_cheat_action; + creators["vezax shadow crash action"] = &RaidUlduarActionContext::vezax_shadow_crash_action; + creators["vezax mark of the faceless action"] = &RaidUlduarActionContext::vezax_mark_of_the_faceless_action; } private: @@ -111,6 +114,9 @@ private: static Action* mimiron_rocket_strike_action(PlayerbotAI* ai) { return new MimironRocketStrikeAction(ai); } static Action* mimiron_phase_4_mark_dps_action(PlayerbotAI* ai) { return new MimironPhase4MarkDpsAction(ai); } static Action* mimiron_cheat_action(PlayerbotAI* ai) { return new MimironCheatAction(ai); } + static Action* vezax_cheat_action(PlayerbotAI* ai) { return new VezaxCheatAction(ai); } + static Action* vezax_shadow_crash_action(PlayerbotAI* ai) { return new VezaxShadowCrashAction(ai); } + static Action* vezax_mark_of_the_faceless_action(PlayerbotAI* ai) { return new VezaxMarkOfTheFacelessAction(ai); } }; #endif diff --git a/src/strategy/raids/ulduar/RaidUlduarActions.cpp b/src/strategy/raids/ulduar/RaidUlduarActions.cpp index 901713be..3d180820 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActions.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarActions.cpp @@ -42,7 +42,6 @@ const Position ULDUAR_KOLOGARN_RESTORE_POSITION = Position(1764.3749f, -24.02903 const Position ULDUAR_KOLOGARN_EYEBEAM_LEFT_POSITION = Position(1781.2051f, 9.34402f, 449.0f, 0.00087690353f); const Position ULDUAR_KOLOGARN_EYEBEAM_RIGHT_POSITION = Position(1763.2561f, -24.44305f, 449.0f, 0.00087690353f); const Position ULDUAR_THORIM_JUMP_START_POINT = Position(2137.137f, -291.19025f, 438.24753f, 1.7059844f); -const Position ULDUAR_THORIM_JUMP_END_POINT = Position(2137.8818f, -278.18942f, 419.66653f); bool FlameLeviathanVehicleAction::Execute(Event event) { @@ -484,12 +483,12 @@ bool RazorscaleAvoidDevouringFlameAction::isUseful() float distance = bot->GetDistance2d(unit); if (distance < safeDistance) { - return true; // Bot is within the danger distance + return true; // Bot is within the danger distance } } } - return false; // No nearby flames or bot is at a safe distance + return false; // No nearby flames or bot is at a safe distance } bool RazorscaleAvoidSentinelAction::Execute(Event event) @@ -529,17 +528,17 @@ bool RazorscaleAvoidSentinelAction::Execute(Event event) Unit* mainTankUnit = AI_VALUE(Unit*, "main tank"); Player* mainTank = mainTankUnit ? mainTankUnit->ToPlayer() : nullptr; - if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a real player + if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a real player { // Iterate through the first 3 bot tanks to assign the Skull marker for (int i = 0; i < 3; ++i) { - if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank + if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank { Group* group = bot->GetGroup(); if (group && lowestHealthSentinel) { - int8 skullIndex = 7; // Skull + int8 skullIndex = 7; // Skull ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex); // If there's no skull set yet, or the skull is on a different target, set the sentinel @@ -548,16 +547,16 @@ bool RazorscaleAvoidSentinelAction::Execute(Event event) group->SetTargetIcon(skullIndex, bot->GetGUID(), lowestHealthSentinel->GetGUID()); } } - break; // Stop after finding the first valid bot tank + break; // Stop after finding the first valid bot tank } } } - else if (isMainTank && lowestHealthSentinel) // Bot is the main tank + else if (isMainTank && lowestHealthSentinel) // Bot is the main tank { Group* group = bot->GetGroup(); if (group) { - int8 skullIndex = 7; // Skull + int8 skullIndex = 7; // Skull ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex); // If there's no skull set yet, or the skull is on a different target, set the sentinel @@ -568,8 +567,7 @@ bool RazorscaleAvoidSentinelAction::Execute(Event event) } } - - return movedAway; // Return true if moved + return movedAway; // Return true if moved } bool RazorscaleAvoidSentinelAction::isUseful() @@ -585,13 +583,13 @@ bool RazorscaleAvoidSentinelAction::isUseful() } // If the main tank is a human, check if this bot is one of the first three valid bot tanks - if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a human player + if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a human player { for (int i = 0; i < 3; ++i) { - if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank + if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank { - return true; // This bot should assist with marking + return true; // This bot should assist with marking } } } @@ -654,7 +652,8 @@ bool RazorscaleAvoidWhirlwindAction::isUseful() Unit* unit = botAI->GetUnit(npc); if (unit && unit->GetEntry() == RazorscaleBossHelper::UNIT_DARK_RUNE_SENTINEL) { - if (unit->HasAura(RazorscaleBossHelper::SPELL_SENTINEL_WHIRLWIND) || unit->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + if (unit->HasAura(RazorscaleBossHelper::SPELL_SENTINEL_WHIRLWIND) || + unit->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) { if (bot->GetDistance2d(unit) < radius) { @@ -679,11 +678,11 @@ bool RazorscaleIgnoreBossAction::isUseful() if (boss->GetPositionZ() >= RazorscaleBossHelper::RAZORSCALE_FLYING_Z_THRESHOLD) { // Check if the bot is outside the designated area - if (bot->GetDistance2d( - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y) > RazorscaleBossHelper::RAZORSCALE_ARENA_RADIUS + 25.0f) + if (bot->GetDistance2d(RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, + RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y) > + RazorscaleBossHelper::RAZORSCALE_ARENA_RADIUS + 25.0f) { - return true; // Movement to the center is the top priority for all bots + return true; // Movement to the center is the top priority for all bots } if (!botAI->IsTank(bot)) @@ -698,11 +697,11 @@ bool RazorscaleIgnoreBossAction::isUseful() } // Check if the boss is already set as the moon marker - int8 moonIndex = 4; // Moon marker index + int8 moonIndex = 4; // Moon marker index ObjectGuid currentMoonTarget = group->GetTargetIcon(moonIndex); if (currentMoonTarget == boss->GetGUID()) { - return false; // Moon marker is already correctly set, no further action needed + return false; // Moon marker is already correctly set, no further action needed } // Proceed to tank-specific logic @@ -716,13 +715,13 @@ bool RazorscaleIgnoreBossAction::isUseful() } // If the main tank is a human, check if this bot is the lowest-indexed bot tank - if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a human player + if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a human player { - for (int i = 0; i < 3; ++i) // Only iterate through the first 3 indexes + for (int i = 0; i < 3; ++i) // Only iterate through the first 3 indexes { - if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Valid bot tank + if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Valid bot tank { - return true; // This bot should assign the marker + return true; // This bot should assign the marker } } } @@ -751,18 +750,13 @@ bool RazorscaleIgnoreBossAction::Execute(Event event) } // Check if the bot is outside the designated area and move inside first - if (bot->GetDistance2d( - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y) > RazorscaleBossHelper::RAZORSCALE_ARENA_RADIUS + 25.0f) + if (bot->GetDistance2d(RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, + RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y) > + RazorscaleBossHelper::RAZORSCALE_ARENA_RADIUS + 25.0f) { - return MoveInside( - ULDUAR_MAP_ID, - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y, - bot->GetPositionZ(), - RazorscaleBossHelper::RAZORSCALE_ARENA_RADIUS - 10.0f, - MovementPriority::MOVEMENT_NORMAL - ); + return MoveInside(ULDUAR_MAP_ID, RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, + RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y, bot->GetPositionZ(), + RazorscaleBossHelper::RAZORSCALE_ARENA_RADIUS - 10.0f, MovementPriority::MOVEMENT_NORMAL); } if (!botAI->IsTank(bot)) @@ -775,7 +769,7 @@ bool RazorscaleIgnoreBossAction::Execute(Event event) ObjectGuid currentMoonTarget = group->GetTargetIcon(moonIndex); if (currentMoonTarget == boss->GetGUID()) { - return false; // Moon marker is already correctly set + return false; // Moon marker is already correctly set } // Get the main tank and determine role @@ -783,33 +777,28 @@ bool RazorscaleIgnoreBossAction::Execute(Event event) Player* mainTank = mainTankUnit ? mainTankUnit->ToPlayer() : nullptr; // If the main tank is a human, assign the moon marker using the lowest-indexed bot tank - if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a real player + if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a real player { - for (int i = 0; i < 3; ++i) // Only iterate through the first 3 indexes + for (int i = 0; i < 3; ++i) // Only iterate through the first 3 indexes { - if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank + if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank { group->SetTargetIcon(moonIndex, bot->GetGUID(), boss->GetGUID()); SetNextMovementDelay(1000); - break; // Assign the moon marker and stop + break; // Assign the moon marker and stop } } } - else if (mainTankUnit == bot) // If this bot is the main tank + else if (mainTankUnit == bot) // If this bot is the main tank { group->SetTargetIcon(moonIndex, bot->GetGUID(), boss->GetGUID()); SetNextMovementDelay(1000); } // Tanks move inside the arena - return MoveInside( - ULDUAR_MAP_ID, - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y, - bot->GetPositionZ(), - RazorscaleBossHelper::RAZORSCALE_ARENA_RADIUS - 10.0f, - MovementPriority::MOVEMENT_NORMAL - ); + return MoveInside(ULDUAR_MAP_ID, RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, + RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y, bot->GetPositionZ(), + RazorscaleBossHelper::RAZORSCALE_ARENA_RADIUS - 10.0f, MovementPriority::MOVEMENT_NORMAL); } bool RazorscaleGroundedAction::isUseful() @@ -875,9 +864,8 @@ bool RazorscaleGroundedAction::isUseful() float bossY = boss->GetPositionY(); float bossZ = boss->GetPositionZ(); - bool atInitialLandingPosition = (fabs(bossX - landingX) < 2.0f) && - (fabs(bossY - landingY) < 2.0f) && - (fabs(bossZ - landingZ) < 1.0f); + bool atInitialLandingPosition = + (fabs(bossX - landingX) < 2.0f) && (fabs(bossY - landingY) < 2.0f) && (fabs(bossZ - landingZ) < 1.0f); constexpr float initialLandingRadius = 14.0f; constexpr float normalRadius = 12.0f; @@ -891,7 +879,8 @@ bool RazorscaleGroundedAction::isUseful() return distanceToAdjustedCenter > initialLandingRadius; } - float distanceToCenter = bot->GetDistance2d(RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y); + float distanceToCenter = bot->GetDistance2d(RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, + RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y); return distanceToCenter > normalRadius; } @@ -911,12 +900,12 @@ bool RazorscaleGroundedAction::Execute(Event event) Unit* mainTankUnit = AI_VALUE(Unit*, "main tank"); Player* mainTank = mainTankUnit ? mainTankUnit->ToPlayer() : nullptr; - if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a human player + if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a human player { // Iterate through the first 3 bot tanks to handle the moon marker for (int i = 0; i < 3; ++i) { - if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank + if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank { int8 moonIndex = 4; ObjectGuid currentMoonTarget = group->GetTargetIcon(moonIndex); @@ -931,7 +920,7 @@ bool RazorscaleGroundedAction::Execute(Event event) } } } - else if (botAI->IsMainTank(bot)) // Bot is the main tank + else if (botAI->IsMainTank(bot)) // Bot is the main tank { int8 moonIndex = 4; ObjectGuid currentMoonTarget = group->GetTargetIcon(moonIndex); @@ -961,33 +950,22 @@ bool RazorscaleGroundedAction::Execute(Event event) float bossY = boss->GetPositionY(); float bossZ = boss->GetPositionZ(); - bool atInitialLandingPosition = (fabs(bossX - landingX) < 2.0f) && - (fabs(bossY - landingY) < 2.0f) && - (fabs(bossZ - landingZ) < 1.0f); + bool atInitialLandingPosition = + (fabs(bossX - landingX) < 2.0f) && (fabs(bossY - landingY) < 2.0f) && (fabs(bossZ - landingZ) < 1.0f); if (atInitialLandingPosition) { // If at the initial landing position, use 12-yard radius with a // 20 yard offset on the Y axis so everyone is behind the boss - return MoveInside( - ULDUAR_MAP_ID, - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y - 20.0f, - bot->GetPositionZ(), - RazorscaleBossHelper::RAZORSCALE_ARENA_RADIUS - 12.0f, - MovementPriority::MOVEMENT_COMBAT - ); + return MoveInside(ULDUAR_MAP_ID, RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, + RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y - 20.0f, bot->GetPositionZ(), + RazorscaleBossHelper::RAZORSCALE_ARENA_RADIUS - 12.0f, MovementPriority::MOVEMENT_COMBAT); } // Otherwise, move inside a 12-yard radius around the arena center - return MoveInside( - ULDUAR_MAP_ID, - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, - RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y, - bot->GetPositionZ(), - 12.0f, - MovementPriority::MOVEMENT_COMBAT - ); + return MoveInside(ULDUAR_MAP_ID, RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_X, + RazorscaleBossHelper::RAZORSCALE_ARENA_CENTER_Y, bot->GetPositionZ(), 12.0f, + MovementPriority::MOVEMENT_COMBAT); } return false; } @@ -1064,9 +1042,7 @@ bool RazorscaleHarpoonAction::Execute(Event event) float botDist = bot->GetDistance(closestHarpoon); if (botDist > INTERACTION_DISTANCE - 1.0f) { - return MoveTo(bot->GetMapId(), - closestHarpoon->GetPositionX(), - closestHarpoon->GetPositionY(), + return MoveTo(bot->GetMapId(), closestHarpoon->GetPositionX(), closestHarpoon->GetPositionY(), closestHarpoon->GetPositionZ()); } @@ -1453,7 +1429,12 @@ bool KologarnEyebeamAction::Execute(Event event) bool KologarnEyebeamAction::isUseful() { KologarnEyebeamTrigger kologarnEyebeamTrigger(botAI); - return kologarnEyebeamTrigger.IsActive(); + if (!kologarnEyebeamTrigger.IsActive()) + { + return false; + } + + return botAI->HasCheat(BotCheatMask::raid); } bool KologarnRtiTargetAction::isUseful() @@ -1477,7 +1458,12 @@ bool KologarnRtiTargetAction::Execute(Event event) bool KologarnCrunchArmorAction::isUseful() { KologarnCrunchArmorTrigger kologarnCrunchArmorTrigger(botAI); - return kologarnCrunchArmorTrigger.IsActive(); + if (!kologarnCrunchArmorTrigger.IsActive()) + { + return false; + } + + return botAI->HasCheat(BotCheatMask::raid); } bool KologarnCrunchArmorAction::Execute(Event event) @@ -1576,6 +1562,11 @@ bool HodirBitingColdJumpAction::Execute(Event event) // return true; } +bool HodirBitingColdJumpAction::isUseful() +{ + return botAI->HasCheat(BotCheatMask::raid); +} + bool FreyaMoveAwayNatureBombAction::isUseful() { // Check boss and it is alive @@ -1798,7 +1789,12 @@ bool FreyaMoveToHealingSporeAction::Execute(Event event) bool ThorimUnbalancingStrikeAction::isUseful() { ThorimUnbalancingStrikeTrigger thorimUnbalancingStrikeTrigger(botAI); - return thorimUnbalancingStrikeTrigger.IsActive(); + if (!thorimUnbalancingStrikeTrigger.IsActive()) + { + return false; + } + + return botAI->HasCheat(BotCheatMask::raid); } bool ThorimUnbalancingStrikeAction::Execute(Event event) @@ -2245,7 +2241,7 @@ bool MimironShockBlastAction::Execute(Event event) float dy = bot->GetPositionY() + sin(angle) * distance; float dz = bot->GetPositionZ(); if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), - bot->GetPositionZ(), dx, dy, dz)) + bot->GetPositionZ(), dx, dy, dz)) { bot->TeleportTo(target->GetMapId(), dx, dy, dz, target->GetOrientation()); return true; @@ -2448,7 +2444,7 @@ bool MimironAerialCommandUnitAction::Execute(Event event) { group->SetTargetIcon(crossIndex, bot->GetGUID(), boss->GetGUID()); } - + if (assaultBot) { ObjectGuid skullTarget = group->GetTargetIcon(skullIndex); @@ -2647,3 +2643,67 @@ bool MimironCheatAction::Execute(Event event) return true; } + +bool VezaxCheatAction::Execute(Event event) +{ + // Restore bot's mana to full + uint32 maxMana = bot->GetMaxPower(POWER_MANA); + if (maxMana > 0) + { + bot->SetPower(POWER_MANA, maxMana); + } + + return true; +} + +bool VezaxShadowCrashAction::Execute(Event event) +{ + // Find General Vezax boss + Unit* boss = AI_VALUE2(Unit*, "find target", "general vezax"); + if (!boss || !boss->IsAlive()) + { + return false; + } + + // Get bot's current position relative to boss + float bossX = boss->GetPositionX(); + float bossY = boss->GetPositionY(); + float bossZ = boss->GetPositionZ(); + + float botX = bot->GetPositionX(); + float botY = bot->GetPositionY(); + + // Calculate current angle and distance from boss + float currentAngle = atan2(botY - bossY, botX - bossX); + float currentDistance = bot->GetDistance2d(boss); + + // Set desired distance from boss (stay close enough for melee, far enough for ranged) + float desiredDistance = 15.0f; + + // If too close or too far, adjust distance first + if (currentDistance < desiredDistance - 2.0f || currentDistance > desiredDistance + 2.0f) + { + currentDistance = desiredDistance; + } + + // Calculate movement increment - move in increments around the boss + float angleIncrement = M_PI / 10; + float newAngle = currentAngle + angleIncrement; + + // Calculate new position + float newX = bossX + currentDistance * cos(newAngle); + float newY = bossY + currentDistance * sin(newAngle); + float newZ = bossZ; // Keep same Z level as boss + + // Move to the new position + return MoveTo(boss->GetMapId(), newX, newY, newZ, false, false, false, true, MovementPriority::MOVEMENT_COMBAT, + true); +} + +bool VezaxMarkOfTheFacelessAction::Execute(Event event) +{ + return MoveTo(bot->GetMapId(), ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionX(), + ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionY(), + ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionZ(), false, false, false, true, + MovementPriority::MOVEMENT_FORCED, true, false); +} diff --git a/src/strategy/raids/ulduar/RaidUlduarActions.h b/src/strategy/raids/ulduar/RaidUlduarActions.h index d39c6a1b..6fef3367 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActions.h +++ b/src/strategy/raids/ulduar/RaidUlduarActions.h @@ -198,6 +198,7 @@ class HodirBitingColdJumpAction : public MovementAction public: HodirBitingColdJumpAction(PlayerbotAI* ai) : MovementAction(ai, "hodir biting cold jump") {} bool Execute(Event event) override; + bool isUseful() override; }; class FreyaMoveAwayNatureBombAction : public MovementAction @@ -353,5 +354,28 @@ public: bool Execute(Event event) override; }; +class VezaxCheatAction : public Action +{ +public: + VezaxCheatAction(PlayerbotAI* ai) : Action(ai, "vezax cheat action") {} + + bool Execute(Event event) override; +}; + +class VezaxShadowCrashAction : public MovementAction +{ +public: + VezaxShadowCrashAction(PlayerbotAI* ai) : MovementAction(ai, "vezax shadow crash action") {} + + bool Execute(Event event) override; +}; + +class VezaxMarkOfTheFacelessAction : public MovementAction +{ +public: + VezaxMarkOfTheFacelessAction(PlayerbotAI* ai) : MovementAction(ai, "vezax mark of the faceless action") {} + + bool Execute(Event event) override; +}; #endif diff --git a/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp b/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp index d7e805c0..b7f0ba41 100644 --- a/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp @@ -225,6 +225,21 @@ void RaidUlduarStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode( "mimiron cheat trigger", NextAction::array(0, new NextAction("mimiron cheat action", ACTION_RAID), nullptr))); + + // + // General Vezax + // + triggers.push_back(new TriggerNode( + "vezax cheat trigger", + NextAction::array(0, new NextAction("vezax cheat action", ACTION_RAID), nullptr))); + + triggers.push_back(new TriggerNode( + "vezax shadow crash trigger", + NextAction::array(0, new NextAction("vezax shadow crash action", ACTION_RAID), nullptr))); + + triggers.push_back(new TriggerNode( + "vezax mark of the faceless trigger", + NextAction::array(0, new NextAction("vezax mark of the faceless action", ACTION_RAID), nullptr))); } void RaidUlduarStrategy::InitMultipliers(std::vector& multipliers) diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h b/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h index 84cd1104..a412748b 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h +++ b/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h @@ -64,6 +64,9 @@ public: creators["mimiron rocket strike trigger"] = &RaidUlduarTriggerContext::mimiron_rocket_strike_trigger; creators["mimiron phase 4 mark dps trigger"] = &RaidUlduarTriggerContext::mimiron_phase_4_mark_dps_trigger; creators["mimiron cheat trigger"] = &RaidUlduarTriggerContext::mimiron_cheat_trigger; + creators["vezax cheat trigger"] = &RaidUlduarTriggerContext::vezax_cheat_trigger; + creators["vezax shadow crash trigger"] = &RaidUlduarTriggerContext::vezax_shadow_crash_trigger; + creators["vezax mark of the faceless trigger"] = &RaidUlduarTriggerContext::vezax_mark_of_the_faceless_trigger; } private: @@ -115,6 +118,9 @@ private: static Trigger* mimiron_rocket_strike_trigger(PlayerbotAI* ai) { return new MimironRocketStrikeTrigger(ai); } static Trigger* mimiron_phase_4_mark_dps_trigger(PlayerbotAI* ai) { return new MimironPhase4MarkDpsTrigger(ai); } static Trigger* mimiron_cheat_trigger(PlayerbotAI* ai) { return new MimironCheatTrigger(ai); } + static Trigger* vezax_cheat_trigger(PlayerbotAI* ai) { return new VezaxCheatTrigger(ai); } + static Trigger* vezax_shadow_crash_trigger(PlayerbotAI* ai) { return new VezaxShadowCrashTrigger(ai); } + static Trigger* vezax_mark_of_the_faceless_trigger(PlayerbotAI* ai) { return new VezaxMarkOfTheFacelessTrigger(ai); } }; #endif diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp b/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp index 6deb508c..7e726eef 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp @@ -1533,6 +1533,11 @@ bool MimironPhase4MarkDpsTrigger::IsActive() bool MimironCheatTrigger::IsActive() { + if (!botAI->HasCheat(BotCheatMask::raid)) + { + return false; + } + if (!botAI->IsMainTank(bot)) { return false; @@ -1557,3 +1562,60 @@ bool MimironCheatTrigger::IsActive() return false; } + +bool VezaxCheatTrigger::IsActive() +{ + if (!botAI->HasCheat(BotCheatMask::raid)) + { + return false; + } + + Unit* boss = AI_VALUE2(Unit*, "find target", "general vezax"); + + // Check boss and it is alive + if (!boss || !boss->IsAlive()) + { + return false; + } + + if (!AI_VALUE2(bool, "has mana", "self target")) + { + return false; + } + + return AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->lowMana; +} + +bool VezaxShadowCrashTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "general vezax"); + + // Check boss and it is alive + if (!boss || !boss->IsAlive()) + { + return false; + } + + return botAI->HasAura(SPELL_SHADOW_CRASH, bot); +} + +bool VezaxMarkOfTheFacelessTrigger::IsActive() +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "general vezax"); + + // Check boss and it is alive + if (!boss || !boss->IsAlive()) + { + return false; + } + + if (!botAI->HasAura(SPELL_MARK_OF_THE_FACELESS, bot)) + { + return false; + } + + float distance = bot->GetDistance2d(ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionX(), + ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionY()); + + return distance > 2.0f; +} diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggers.h b/src/strategy/raids/ulduar/RaidUlduarTriggers.h index 987c1ce4..6ebf1a7a 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggers.h +++ b/src/strategy/raids/ulduar/RaidUlduarTriggers.h @@ -77,6 +77,10 @@ enum UlduarIDs SPELL_P3WX2_LASER_BARRAGE_3 = 64042, SPELL_P3WX2_LASER_BARRAGE_AURA_1 = 63274, SPELL_P3WX2_LASER_BARRAGE_AURA_2 = 63300, + + //General Vezax + SPELL_MARK_OF_THE_FACELESS = 63276, + SPELL_SHADOW_CRASH = 63277, // Buffs SPELL_FROST_TRAP = 13809 @@ -106,6 +110,7 @@ const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_5_YARDS_1 = Position(2217.8877f const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_1 = Position(2212.193f, -307.44992f, 412.1348f); const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_2 = Position(2212.1353f, -318.20795f, 412.1348f); const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_3 = Position(2212.1956f, -328.0144f, 412.1348f); +const Position ULDUAR_THORIM_JUMP_END_POINT = Position(2137.8818f, -278.18942f, 419.66653f); const Position ULDUAR_THORIM_PHASE2_TANK_SPOT = Position(2134.8572f, -287.0291f, 419.4935f); const Position ULDUAR_THORIM_PHASE2_RANGE1_SPOT = Position(2112.8752f, -267.69305f, 419.52814f); const Position ULDUAR_THORIM_PHASE2_RANGE2_SPOT = Position(2134.1296f, -257.3316f, 419.8462f); @@ -117,6 +122,7 @@ const Position ULDUAR_MIMIRON_PHASE2_SIDE2MELEE_SPOT = Position(2739.4746f, 2569 const Position ULDUAR_MIMIRON_PHASE2_SIDE3RANGE_SPOT = Position(2754.1294f, 2553.9954f, 364.31357f); const Position ULDUAR_MIMIRON_PHASE2_SIDE3MELEE_SPOT = Position(2746.8513f, 2565.4263f, 364.31357f); const Position ULDUAR_MIMIRON_PHASE4_TANK_SPOT = Position(2744.5754f, 2570.8657f, 364.3138f); +const Position ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT = Position(1913.6501f, 122.93989f, 342.38083f); // // Flame Levi @@ -418,4 +424,28 @@ public: bool IsActive() override; }; +// +// General Vezax +// +class VezaxCheatTrigger : public Trigger +{ +public: + VezaxCheatTrigger(PlayerbotAI* ai) : Trigger(ai, "vezax cheat trigger") {} + bool IsActive() override; +}; + +class VezaxShadowCrashTrigger : public Trigger +{ +public: + VezaxShadowCrashTrigger(PlayerbotAI* ai) : Trigger(ai, "vezax shadow crash trigger") {} + bool IsActive() override; +}; + +class VezaxMarkOfTheFacelessTrigger : public Trigger +{ +public: + VezaxMarkOfTheFacelessTrigger(PlayerbotAI* ai) : Trigger(ai, "vezax mark of the faceless trigger") {} + bool IsActive() override; +}; + #endif