From b98bd7ff700a4cdc00e2d22b2635b7dcf1e4ea5f Mon Sep 17 00:00:00 2001 From: acore-crap <174030747+acore-crap@users.noreply.github.com> Date: Tue, 5 Nov 2024 08:09:26 -0700 Subject: [PATCH 1/5] aq40 test: crude but functional --- src/strategy/AiObjectContext.cpp | 6 +- src/strategy/raids/RaidStrategyContext.h | 3 + .../raids/aq40/RaidAq40ActionContext.h | 44 ++ src/strategy/raids/aq40/RaidAq40Actions.cpp | 722 ++++++++++++++++++ src/strategy/raids/aq40/RaidAq40Actions.h | 178 +++++ src/strategy/raids/aq40/RaidAq40Strategy.cpp | 42 + src/strategy/raids/aq40/RaidAq40Strategy.h | 17 + .../raids/aq40/RaidAq40TriggerContext.h | 44 ++ src/strategy/raids/aq40/RaidAq40Triggers.cpp | 438 +++++++++++ src/strategy/raids/aq40/RaidAq40Triggers.h | 135 ++++ 10 files changed, 1627 insertions(+), 2 deletions(-) create mode 100644 src/strategy/raids/aq40/RaidAq40ActionContext.h create mode 100644 src/strategy/raids/aq40/RaidAq40Actions.cpp create mode 100644 src/strategy/raids/aq40/RaidAq40Actions.h create mode 100644 src/strategy/raids/aq40/RaidAq40Strategy.cpp create mode 100644 src/strategy/raids/aq40/RaidAq40Strategy.h create mode 100644 src/strategy/raids/aq40/RaidAq40TriggerContext.h create mode 100644 src/strategy/raids/aq40/RaidAq40Triggers.cpp create mode 100644 src/strategy/raids/aq40/RaidAq40Triggers.h diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index b2ede465d5..b42d637afc 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -28,6 +28,8 @@ #include "raids/moltencore/RaidMcTriggerContext.h" #include "raids/aq20/RaidAq20ActionContext.h" #include "raids/aq20/RaidAq20TriggerContext.h" +#include "raids/aq40/RaidAq40ActionContext.h" +#include "raids/aq40/RaidAq40TriggerContext.h" #include "dungeons/DungeonStrategyContext.h" #include "dungeons/wotlk/WotlkDungeonActionContext.h" #include "dungeons/wotlk/WotlkDungeonTriggerContext.h" @@ -47,6 +49,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) actionContexts.Add(new RaidMcActionContext()); actionContexts.Add(new RaidBwlActionContext()); actionContexts.Add(new RaidAq20ActionContext()); + actionContexts.Add(new RaidAq40ActionContext()); actionContexts.Add(new RaidNaxxActionContext()); actionContexts.Add(new RaidUlduarActionContext()); actionContexts.Add(new RaidIccActionContext()); @@ -59,7 +62,6 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) actionContexts.Add(new WotlkDungeonGDActionContext()); actionContexts.Add(new WotlkDungeonHoSActionContext()); actionContexts.Add(new WotlkDungeonHoLActionContext()); - actionContexts.Add(new WotlkDungeonOccActionContext()); actionContexts.Add(new WotlkDungeonUPActionContext()); actionContexts.Add(new WotlkDungeonCoSActionContext()); @@ -69,6 +71,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) triggerContexts.Add(new RaidMcTriggerContext()); triggerContexts.Add(new RaidBwlTriggerContext()); triggerContexts.Add(new RaidAq20TriggerContext()); + triggerContexts.Add(new RaidAq40TriggerContext()); triggerContexts.Add(new RaidNaxxTriggerContext()); triggerContexts.Add(new RaidUlduarTriggerContext()); triggerContexts.Add(new RaidIccTriggerContext()); @@ -81,7 +84,6 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) triggerContexts.Add(new WotlkDungeonGDTriggerContext()); triggerContexts.Add(new WotlkDungeonHoSTriggerContext()); triggerContexts.Add(new WotlkDungeonHoLTriggerContext()); - triggerContexts.Add(new WotlkDungeonOccTriggerContext()); triggerContexts.Add(new WotlkDungeonUPTriggerContext()); triggerContexts.Add(new WotlkDungeonCoSTriggerContext()); diff --git a/src/strategy/raids/RaidStrategyContext.h b/src/strategy/raids/RaidStrategyContext.h index af30ff1462..04003700f9 100644 --- a/src/strategy/raids/RaidStrategyContext.h +++ b/src/strategy/raids/RaidStrategyContext.h @@ -7,6 +7,7 @@ #include "RaidNaxxStrategy.h" #include "RaidMcStrategy.h" #include "RaidAq20Strategy.h" +#include "RaidAq40Strategy.h" #include "RaidIccStrategy.h" class RaidStrategyContext : public NamedObjectContext @@ -20,6 +21,7 @@ class RaidStrategyContext : public NamedObjectContext creators["mc"] = &RaidStrategyContext::mc; creators["bwl"] = &RaidStrategyContext::bwl; creators["aq20"] = &RaidStrategyContext::aq20; + creators["aq40"] = &RaidStrategyContext::aq40; creators["naxx"] = &RaidStrategyContext::naxx; creators["uld"] = &RaidStrategyContext::uld; creators["icc"] = &RaidStrategyContext::icc; @@ -29,6 +31,7 @@ class RaidStrategyContext : public NamedObjectContext static Strategy* mc(PlayerbotAI* botAI) { return new RaidMcStrategy(botAI); } static Strategy* bwl(PlayerbotAI* botAI) { return new RaidBwlStrategy(botAI); } static Strategy* aq20(PlayerbotAI* botAI) { return new RaidAq20Strategy(botAI); } + static Strategy* aq40(PlayerbotAI* botAI) { return new RaidAq40Strategy(botAI); } static Strategy* naxx(PlayerbotAI* botAI) { return new RaidNaxxStrategy(botAI); } static Strategy* uld(PlayerbotAI* botAI) { return new RaidUlduarStrategy(botAI); } static Strategy* icc(PlayerbotAI* botAI) { return new RaidIccStrategy(botAI); } diff --git a/src/strategy/raids/aq40/RaidAq40ActionContext.h b/src/strategy/raids/aq40/RaidAq40ActionContext.h new file mode 100644 index 0000000000..f235820aa8 --- /dev/null +++ b/src/strategy/raids/aq40/RaidAq40ActionContext.h @@ -0,0 +1,44 @@ +#ifndef _PLAYERBOT_RAIDAQ40ACTIONCONTEXT_H +#define _PLAYERBOT_RAIDAQ40ACTIONCONTEXT_H + +#include "Action.h" +#include "NamedObjectContext.h" +#include "RaidAq40Actions.h" + +class RaidAq40ActionContext : public NamedObjectContext +{ +public: + RaidAq40ActionContext() + { + creators["aq40 use resistance buffs"] = &RaidAq40ActionContext::use_resistance_buffs; + creators["aq40 move from other emperor"] = &RaidAq40ActionContext::move_from_other_emperor; + creators["aq40 attack emperor vek'lor"] = &RaidAq40ActionContext::attack_emperor_veklor; + creators["aq40 attack emperor vek'nilash"] = &RaidAq40ActionContext::attack_emperor_veknilash; + creators["aq40 attack emperor pests"] = &RaidAq40ActionContext::attack_emperor_pests; + creators["aq40 move towards emperor vek'lor"] = &RaidAq40ActionContext::move_towards_emperor_veklor; + creators["aq40 move towards emperor vek'nilash"] = &RaidAq40ActionContext::move_towards_emperor_veknilash; + creators["searing pain"] = &RaidAq40ActionContext::warlock_searing_pain; + creators["frostbolt"] = &RaidAq40ActionContext::mage_cast_frostbolt; + creators["aq40 melee viscidus"] = &RaidAq40ActionContext::melee_viscidus; + creators["aq40 ouro burrowed flee"] = &RaidAq40ActionContext::ouro_burrowed_flee; + creators["aq40 cthun1 get positioned"] = &RaidAq40ActionContext::cthun1_get_positioned; + creators["aq40 cthun2 get positioned"] = &RaidAq40ActionContext::cthun2_get_positioned; + } + +private: + static Action* use_resistance_buffs(PlayerbotAI *ai) { return new Aq40UseResistanceBuffsAction(ai); } + static Action* move_from_other_emperor(PlayerbotAI* ai) { return new Aq40MoveFromOtherEmperorAction(ai); } + static Action* attack_emperor_veklor(PlayerbotAI* ai) { return new Aq40AttackEmperorVekLorAction(ai); } + static Action* attack_emperor_veknilash(PlayerbotAI* ai) { return new Aq40AttackEmperorVekNilashAction(ai); } + static Action* attack_emperor_pests(PlayerbotAI* ai) { return new Aq40AttackEmperorPestsAction(ai); } + static Action* move_towards_emperor_veklor(PlayerbotAI* ai) { return (Action *)(new Aq40MoveTowardsEmperorVekLorAction(ai)); } + static Action* move_towards_emperor_veknilash(PlayerbotAI* ai) { return (Action *)(new Aq40MoveTowardsEmperorVekNilashAction(ai)); } + static Action* warlock_searing_pain(PlayerbotAI* ai) { return new Aq40WarlockCastSearingPainAction(ai); } + static Action* mage_cast_frostbolt(PlayerbotAI* ai) { return new Aq40MageCastFrostboltAction(ai); } + static Action* melee_viscidus(PlayerbotAI* ai) { return new Aq40MeleeViscidusAction(ai); } + static Action* ouro_burrowed_flee(PlayerbotAI* ai) { return new Aq40OuroBurrowedFleeAction(ai); } + static Action* cthun1_get_positioned(PlayerbotAI* ai) { return new Aq40Cthun1PositionAction(ai); } + static Action* cthun2_get_positioned(PlayerbotAI* ai) { return new Aq40Cthun2PositionAction(ai); } +}; + +#endif diff --git a/src/strategy/raids/aq40/RaidAq40Actions.cpp b/src/strategy/raids/aq40/RaidAq40Actions.cpp new file mode 100644 index 0000000000..ef035771a8 --- /dev/null +++ b/src/strategy/raids/aq40/RaidAq40Actions.cpp @@ -0,0 +1,722 @@ +#include "RaidAq40Actions.h" + +#include "Playerbots.h" +#include "AttackAction.h" + +bool Aq40UseResistanceBuffsAction::Execute(Event event) +{ + switch(bot->getClass()) + { + case CLASS_HUNTER: + { + bool isnatureboss = false; + + Unit* boss; + + if ((boss = AI_VALUE2(Unit*, "find target", "viscidus")) && boss->IsInCombat()) + { + isnatureboss = true; + } + else if ((boss = AI_VALUE2(Unit*, "find target", "princess huhuran")) && boss->IsInCombat()) + { + isnatureboss = true; + } + + if (isnatureboss) + { + if (!botAI->HasStrategy("rnature", BotState::BOT_STATE_COMBAT)) + { + botAI->ChangeStrategy("+rnature", BOT_STATE_NON_COMBAT); + botAI->ChangeStrategy("+rnature", BOT_STATE_COMBAT); + return true; + } + } + else if (botAI->HasStrategy("rnature", BotState::BOT_STATE_COMBAT)) + { + botAI->ChangeStrategy("-rnature", BOT_STATE_NON_COMBAT); + botAI->ChangeStrategy("-rnature", BOT_STATE_COMBAT); + return true; + } + } + break; + case CLASS_PRIEST: + { + // paladin aura seems like a waste when priests have buffs that don't have a radius limitation + if (!botAI->HasStrategy("rshadow", BotState::BOT_STATE_NON_COMBAT)) + { + botAI->ChangeStrategy("+rshadow", BOT_STATE_NON_COMBAT); + botAI->ChangeStrategy("+rshadow", BOT_STATE_COMBAT); + return true; + } + } + break; + } + + + return false; +} + + + +// 88072: The Master's Eye for positioning maybe + +bool Aq40MoveFromOtherEmperorAction::Execute(Event event) +{ + const float radius = 120.0f; // emperors' heal range is 60 + + if (Unit* boss1 = AI_VALUE2(Unit*, "find target", "emperor vek'lor")) + if (Unit* boss2 = AI_VALUE2(Unit*, "find target", "emperor vek'nilash")) + { + ObjectGuid botguid = bot->GetGUID(); + ObjectGuid petguid = (ObjectGuid)0UL; + if (Pet* pet = bot->GetPet()) + { + petguid = pet->GetGUID(); + } + Unit* moveAwayFrom = NULL; + + if (boss1->GetTarget() == botguid || boss1->GetTarget() == petguid) + { + moveAwayFrom = boss2; + if (petguid) + { + botAI->PetFollow(); + } + } + else if (boss2->GetTarget() == botguid || boss2->GetTarget() == petguid) + { + moveAwayFrom = boss1; + if (petguid) + { + botAI->PetFollow(); + } + } + + if (moveAwayFrom != NULL) + { + long distToTravel = radius - bot->GetDistance(moveAwayFrom); + + if (distToTravel > 0) + { + return MoveAway(moveAwayFrom, distToTravel); + } + } + } + + return false; +} + +bool Aq40MeleeViscidusAction::Execute(Event event) +{ + if (Unit* boss = AI_VALUE2(Unit*, "find target", "viscidus")) + { + if (!bot->HasUnitState(UNIT_STATE_MELEE_ATTACKING)) + { + // this might not work properly, didn't have problems with boss anyway + ObjectGuid guid = boss->GetGUID(); + + botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({guid}); + bool result = Attack(boss); + if (result) + { + bot->AddUnitState(UNIT_STATE_MELEE_ATTACKING); + context->GetValue("pull target")->Set(guid); + } + + return result; + } + } + + return false; +} + +bool Aq40AttackTargetByNameAction::Execute(Event event) +{ + if (Unit* boss = AI_VALUE2(Unit*, "find target", WhichEmperor())) + { + if (bot->GetTarget() != boss->GetGUID()) + { + ObjectGuid guid = boss->GetGUID(); + + botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({guid}); + bool result = Attack(boss); + if (result) + context->GetValue("pull target")->Set(guid); + + return result; + } + } + else + { + return false; + } +} + +bool Aq40AttackEmperorPestsAction::Execute(Event event) +{ + Unit* current = AI_VALUE(Unit*, "current target"); + + if (current && (current->GetName() == "qiraji scarab" || current->GetName() == "qiraji scorpion")) + { + return false; + } + + Unit* pest1 = AI_VALUE2(Unit*, "find target", "qiraji scarab"); + Unit* pest2 = AI_VALUE2(Unit*, "find target", "qiraji scorpion"); + Unit* pest; + + if (pest1 && pest2) + { + if (pest1->GetDistance(bot) < pest2->GetDistance(bot)) + { + pest = pest1; + } + else + { + pest = pest2; + } + } + else if (pest1) + { + pest = pest1; + } + else if (pest2) + { + pest = pest2; + } + else + { + return false; + } + + ObjectGuid guid = pest->GetGUID(); + botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({guid}); + bool result = Attack(pest); + if (result) + context->GetValue("pull target")->Set(guid); + + return result; +} + +bool Aq40MoveTowardsEmperorAction::Execute(Event event) +{ + const float radius = 20.0f; // assume general healing range of 40, try to keep healers near the tanks/victims + + if (Unit* boss = AI_VALUE2(Unit*, "find target", WhichEmperor())) + { + if (ObjectGuid bosstarget = boss->GetTarget()) + { + Unit* target = botAI->GetUnit(bosstarget); + + long traveltarget = -1;//radius - bot->GetDistance(target); + long travelboss = radius - bot->GetDistance(boss); + + if (traveltarget > travelboss) + { + return MoveTo(target, traveltarget); + } + else + { + return MoveTo(boss, travelboss); + } + } + } + + return false; +} + +bool Aq40OuroBurrowedFleeAction::Execute(Event event) +{ + bool doflee = false; + + if (Unit* boss = AI_VALUE2(Unit*, "find target", "ouro")) + { + if (boss->IsInCombat() && (boss->GetUnitFlags() & UNIT_FLAG_NOT_SELECTABLE) == UNIT_FLAG_NOT_SELECTABLE) + { + doflee = true; + + // todo: if ankle-biter scarab is near, doflee = false + } + + } + /* + else if (Unit* boss = AI_VALUE2(Unit*, "find target", "eye of c'thun")) + { + if (boss->IsInCombat()) + { + float dist = bot->GetDistance(boss); + + //printf("eyedist %f\n",dist); + + doflee = dist < 13.0; + + if (bot->GetName() == "Snusnu") + { + printf("eyedist %f doflee %d\n",dist,doflee); + } + } + } + */ + + + if (doflee) + { + if (!botAI->HasStrategy("move from group", BotState::BOT_STATE_COMBAT)) + { + // add/remove from both for now as it will make it more obvious to + // player if this strat remains on after fight somehow + // (which it will in this case, todo: remove after relevant, or just issue 'follow' command to bots) + botAI->ChangeStrategy("+move from group", BOT_STATE_NON_COMBAT); + botAI->ChangeStrategy("+move from group", BOT_STATE_COMBAT); + } + } + else if (botAI->HasStrategy("move from group", BotState::BOT_STATE_COMBAT)) + { + // add/remove from both for now as it will make it more obvious to + // player if this strat remains on after fight somehow + // (which it will in this case, todo: remove after relevant, or just issue 'follow' command to bots) + botAI->ChangeStrategy("-move from group", BOT_STATE_NON_COMBAT); + botAI->ChangeStrategy("-move from group", BOT_STATE_COMBAT); + } + + return true; +} + +int Aq40Cthun1PositionAction::wrappingdistancebetween(int first, int second, int scope) +{ + int retval = first - second; + if (abs(retval) > scope / 2) + { + if (retval > scope / 2) + { + retval = retval - scope; + } + else + { + retval = scope + retval; + } + } + return retval; +} + +int Aq40Cthun1PositionAction::getnearestpoint(int excludeouter, bool doinner) +{ + int retval = -1; + float retvaldist = 0.0F; + + for (int n = 0; n < outerpointscount; n++) + { + float dist = bot->GetDistance(outerpoints[n]->GetPositionX(), outerpoints[n]->GetPositionY(), outerpoints[n]->GetPositionZ()); + + if (retval < 0 || retvaldist > dist) + { + if (excludeouter != n) + { + retval = n; + retvaldist = dist; + } + } + } + + if (doinner) + { + for (int n = 0; n < innerpointscount; n++) + { + float dist = bot->GetDistance(innerpoints[n]->GetPositionX(), innerpoints[n]->GetPositionY(), innerpoints[n]->GetPositionZ()); + + if (retval < 0 || retvaldist > dist) + { + retval = n + outerpointscount; + retvaldist = dist; + } + } + } + + return retval; +} + +bool Aq40Cthun1PositionAction::Execute(Event event) +{ + // boss_cthun.cpp + const int SPELL_GREEN_BEAM = 26134; + const int SPELL_RED_COLORATION = 22518; //Probably not the right spell but looks similar + + + ObjectGuid botguid = bot->GetGUID(); + + if (Unit* boss = AI_VALUE2(Unit*, "find target", "eye of c'thun")) + { + Position* point = NULL; + + ObjectGuid bosstargetguid = boss->GetTarget(); + if (boss->HasAura(SPELL_RED_COLORATION)) + { + int bossd = (int)(boss->GetOrientation() * outerpointscount / (M_PI * 2.0)); + if (bossd < 0) + { + bossd = bossd + outerpointscount * ((-bossd) / outerpointscount + 1); + } + bossd %= outerpointscount; + + int nearest = getnearestpoint(bossd, false); + int dist = wrappingdistancebetween(bossd, nearest, outerpointscount); + + if (abs(dist) <= outerpointscount / 6) + { + nearest = (nearest + outerpointscount - dist * (outerpointscount / 6) / abs(dist)) % outerpointscount; + } + + point = outerpoints[nearest]; + + if (bot->GetDistance(*point) < 0.5) + { + return false; + } + } + else + { + if (bosstargetguid == botguid) + { + bot->StopMoving(); + return true; + } + else + { + Spell* spell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); + + if (spell and spell->m_spellInfo->Id == SPELL_GREEN_BEAM) + { + Unit* bosstarget = botAI->GetUnit(bosstargetguid); + float bdist = bot->GetDistance(bosstarget); + + if (bdist < 20.0) + { + if (bdist <= 10.0) + { + bot->AttackStop(); + //printf("%s: still %f away from %s\n",bot->GetName().c_str(),bdist,bosstarget->GetName().c_str()); + } + + return MoveAway(bosstarget, 20.0); + } + } + } + } + + if (!point) + { + Group* group = bot->GetGroup(); + if (bot->GetDistance(boss) < 60.0F && group) + { + Player* closest = NULL; + float closestdist = 0.0F; + + for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + { + Player* member = itr->GetSource(); + + if (member->GetGUID() != botguid && member->IsAlive()) + { + float dist = bot->GetDistance(member); + + if (dist < 10.0 && (closest == NULL || closestdist < dist)) + { + closest = member; + closestdist = dist; + } + } + } + + if (closest) + { + return MoveAway(closest, 10.0); + } + } + + int nearest = getnearestpoint(); + + if (nearest >= outerpointscount) + { + point = innerpoints[nearest - outerpointscount]; + } + else + { + point = outerpoints[nearest]; + } + + if (bot->GetDistance(*point) < 0.5) + { + return false; + } + } + + if (point) + { + return MoveTo(bot->GetMapId(), point->GetPositionX(), point->GetPositionY(), point->GetPositionZ(), + false, false, false, true, MovementPriority::MOVEMENT_COMBAT); + } + } + + return false; +} + +bool Aq40Cthun2PositionAction::Execute(Event event) +{ + // boss_cthun.cpp + const int NPC_TRIGGER = 15384; + const int NPC_EXIT_TRIGGER = 15800; + + const int SPELL_DIGESTIVE_ACID = 26476; + + // Areatriggers + const int SPELL_SPIT_OUT = 25383; + const int SPELL_EXIT_STOMACH = 26221; + const int SPELL_RUBBLE_ROCKY = 26271; + + const int SPELL_CARAPACE_CTHUN = 26156; // Server-side + + + // temple_of_ahn_quiraj.h + const int NPC_CLAW_TENTACLE = 15725; + const int NPC_EYE_TENTACLE = 15726; + const int NPC_GIANT_CLAW_TENTACLE = 15728; + const int NPC_GIANT_EYE_TENTACLE = 15334; + const int NPC_FLESH_TENTACLE = 15802; + + ObjectGuid botguid = bot->GetGUID(); + + if (Unit* boss = AI_VALUE2(Unit*, "find target", "c'thun")) + { + Position* point = NULL; + + if (bot->GetPositionZ() > 0.0) + { + Creature* tentacle1 = bot->FindNearestCreature(NPC_GIANT_EYE_TENTACLE, 100.0f, true); + + if (tentacle1) + { + Group* group = bot->GetGroup(); + if (group) + { + Player* closest = NULL; + float closestdist = 0.0F; + + for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + { + Player* member = itr->GetSource(); + + if (member->GetGUID() != botguid && member->IsAlive()) + { + float dist = bot->GetDistance(member); + + if (dist < 11.0 && (closest == NULL || closestdist < dist)) + { + closest = member; + closestdist = dist; + } + } + } + + if (closest) + { + return MoveAway(closest, 11.0); + } + } + } + + Unit* attacktarget = NULL; + + if (!boss->HasAura(SPELL_CARAPACE_CTHUN)) + { + attacktarget = boss; + } + else if (tentacle1) + { + attacktarget = tentacle1; + } + else if (Creature* tentacle3 = bot->FindNearestCreature(NPC_EYE_TENTACLE, 100.0f, true)) + { + attacktarget = tentacle3; + } + else if (Creature* tentacle2 = bot->FindNearestCreature(NPC_GIANT_CLAW_TENTACLE, 100.0f, true)) + { + attacktarget = tentacle2; + } + else if (Creature* tentacle4 = bot->FindNearestCreature(NPC_CLAW_TENTACLE, 100.0f, true)) + { + attacktarget = tentacle4; + } + + if (attacktarget) + { + ObjectGuid guid = attacktarget->GetGUID(); + + botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({guid}); + bot->Attack(attacktarget, botAI->IsMelee(bot)); + + return false; + } + + outtriggered = false; + attackpositioned = false; + } + else + { + if (bot->GetPositionZ() > -50.0) + { + // flying around out of bounds where they shouldn't be... + // teleport them to splashdown at -8562.1 2037.0 -99.58 + bot->TeleportTo(bot->GetMapId(), -8562.1, 2037.0, -99.58, 5.03); + } + + bool dogetout = false; + + if (!attackpositioned) + { + point = insideattack; + + if (bot->GetDistance(*point) < 1.0) + { + attackpositioned = true; + } + } + else + { + int astack = bot->GetAuraCount(SPELL_DIGESTIVE_ACID); + int adamage = (astack + (astack + 1) + (astack + 2)) * 150; // 150 per stack, 5 second tick + + if (adamage >= bot->GetHealth()) + { + point = getout; + dogetout = true; + //printf("%s: low health, get out\n",bot->GetName().c_str()); + } + else if (astack < 1) // bugged state check + { + // immediately leave + point = getout; + dogetout = true; + //printf("%s: bugged state, get out\n",bot->GetName().c_str()); + } + else if (botAI->IsTank(bot, true)) + { + // immediately leave + point = getout; + dogetout = true; + //printf("%s: tank, get out\n",bot->GetName().c_str()); + } + else if (botAI->IsHeal(bot, true)) + { + // stack to 5 and leave, lower tolerance for healers + if (bot->GetAuraCount(SPELL_DIGESTIVE_ACID) >= 5 || bot->GetHealthPct() <= 50.0) + { + point = getout; + dogetout = true; + } + } + else + { + // search completely failed with AI_VALUE2 here, but the above AI_VALUE2 started + // working after the below statement was used here instead? + if (Creature* tboss = bot->FindNearestCreature(NPC_FLESH_TENTACLE, 100.0f, true)) + { + bool hastarget = false; + + ObjectGuid targetguid = bot->GetTarget(); + if (Unit* target = botAI->GetUnit(targetguid)) + { + if (target->GetEntry() == NPC_FLESH_TENTACLE) + { + hastarget = true; + } + } + + if (!hastarget) + { + ObjectGuid guid = tboss->GetGUID(); + + botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({guid}); + bot->SetTarget(guid); + + //printf("%s: attack flesh tentacle\n",bot->GetName().c_str()); + + if (botAI->IsMelee(bot)) + { + // bots not picking up on these tentacles very effectively + return MoveTo(tboss, -1.0); + } + + return false; + } + else + { + //printf("%s: tentacle already target\n",bot->GetName().c_str()); + } + } + else + { + //printf("%s: no flesh tentacle, get out\n",bot->GetName().c_str()); + point = getout; + dogetout = true; + } + } + } + + if (dogetout && !outtriggered) + { + if (bot->GetDistance(*point) < 10.0) + { + // at_cthun_stomach_exit::OnTrigger from boss_cthun.cpp + Player* player = bot; + Unit* cthun = boss; + + if (Creature* trigger = player->FindNearestCreature(NPC_TRIGGER, 15.0f)) + { + if (!trigger->GetCurrentSpell(CurrentSpellTypes::CURRENT_GENERIC_SPELL)) + { + trigger->CastSpell(player, SPELL_EXIT_STOMACH, true); + + if (Creature* exittrigger = player->FindNearestCreature(NPC_EXIT_TRIGGER, 15.0f)) + { + exittrigger->CastSpell(player, SPELL_RUBBLE_ROCKY, true); + } + + outtriggered = true; + } + } + + if (outtriggered) + { + player->m_Events.AddEventAtOffset([player, cthun]() + { + if (player->FindNearestCreature(NPC_EXIT_TRIGGER, 10.0f)) + { + player->JumpTo(0.0f, 80.0f, false); + + player->m_Events.AddEventAtOffset([player, cthun]() + { + if (cthun) + player->NearTeleportTo(cthun->GetPositionX(), cthun->GetPositionY(), cthun->GetPositionZ() + 10, float(rand32() % 6)); + + player->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); + }, 1s); + } + else + { + player->m_Events.KillAllEvents(false); + } + }, 3s); + } + } + } + } + + if (point) + { + return MoveTo(bot->GetMapId(), point->GetPositionX(), point->GetPositionY(), point->GetPositionZ(), + false, false, false, true, MovementPriority::MOVEMENT_COMBAT); + } + } + + return false; +} diff --git a/src/strategy/raids/aq40/RaidAq40Actions.h b/src/strategy/raids/aq40/RaidAq40Actions.h new file mode 100644 index 0000000000..da905140ee --- /dev/null +++ b/src/strategy/raids/aq40/RaidAq40Actions.h @@ -0,0 +1,178 @@ +#ifndef _PLAYERBOT_RAIDAQ40ACTIONS_H +#define _PLAYERBOT_RAIDAQ40ACTIONS_H + +#include "MovementActions.h" +#include "GenericSpellActions.h" +#include "AttackAction.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" + +class Aq40UseResistanceBuffsAction : public Action +{ +public: + Aq40UseResistanceBuffsAction(PlayerbotAI* botAI, std::string const name = "aq40 use resistance buffs") + : Action(botAI, name) {} + bool Execute(Event event) override; +}; + +class Aq40MoveFromOtherEmperorAction : public MovementAction +{ +public: + Aq40MoveFromOtherEmperorAction(PlayerbotAI* botAI, std::string const name = "aq40 move from other emperor") + : MovementAction(botAI, name) {} + bool Execute(Event event) override; +protected: + const Position* torch_left = new Position(-8894.3, 1285.5, -112.25); + const Position* torch_right = new Position(-9029.1, 1261.8, -112.25); + float lastdist = 0.0F; +}; + +BEGIN_RANGED_SPELL_ACTION(Aq40WarlockCastSearingPainAction, "searing pain") +END_SPELL_ACTION() + +BEGIN_RANGED_SPELL_ACTION(Aq40MageCastFrostboltAction, "frostbolt") +END_SPELL_ACTION() + +class Aq40MeleeViscidusAction : public AttackAction +{ +public: + Aq40MeleeViscidusAction(PlayerbotAI* botAI) : AttackAction(botAI, "aq40 melee viscidus") {} + bool Execute(Event event) override; +}; + +class Aq40AttackTargetByNameAction : public AttackAction +{ +public: + Aq40AttackTargetByNameAction(PlayerbotAI* botAI, std::string const name) : AttackAction(botAI, name) {} + bool Execute(Event event) override; + + virtual std::string const WhichEmperor() { return NULL; } +}; + +class Aq40AttackEmperorVekLorAction : public Aq40AttackTargetByNameAction +{ +public: + Aq40AttackEmperorVekLorAction(PlayerbotAI* botAI) : Aq40AttackTargetByNameAction(botAI, "aq40 attack emperor vek'lor") {} + + std::string const WhichEmperor() override { return "emperor vek'lor"; } +}; + +class Aq40AttackEmperorVekNilashAction : public Aq40AttackTargetByNameAction +{ +public: + Aq40AttackEmperorVekNilashAction(PlayerbotAI* botAI) : Aq40AttackTargetByNameAction(botAI, "aq40 attack emperor vek'nilash") {} + + std::string const WhichEmperor() override { return "emperor vek'nilash"; } +}; + +class Aq40AttackEmperorPestsAction : public AttackAction +{ +public: + Aq40AttackEmperorPestsAction(PlayerbotAI* botAI) : AttackAction(botAI, "aq40 attack emperor pests") {} + bool Execute(Event event) override; +}; + +class Aq40MoveTowardsEmperorAction : public MovementAction +{ +public: + Aq40MoveTowardsEmperorAction(PlayerbotAI* botAI, std::string const name) + : MovementAction(botAI, name) {} + bool Execute(Event event) override; + + virtual std::string const WhichEmperor() { return NULL; } +}; + +class Aq40MoveTowardsEmperorVekLorAction : Aq40MoveTowardsEmperorAction +{ +public: + Aq40MoveTowardsEmperorVekLorAction(PlayerbotAI* botAI) + : Aq40MoveTowardsEmperorAction(botAI, "aq40 move towards emperor vek'lor") {} + + std::string const WhichEmperor() override { return "emperor vek'lor"; } +}; + +class Aq40MoveTowardsEmperorVekNilashAction : Aq40MoveTowardsEmperorAction +{ +public: + Aq40MoveTowardsEmperorVekNilashAction(PlayerbotAI* botAI) + : Aq40MoveTowardsEmperorAction(botAI, "aq40 move towards emperor vek'nilash") {} + + std::string const WhichEmperor() override { return "emperor vek'nilash"; } +}; + +class Aq40OuroBurrowedFleeAction : public Action +{ +public: + Aq40OuroBurrowedFleeAction(PlayerbotAI* botAI, std::string const name = "aq40 ouro burrowed flee") + : Action(botAI, name) {} + bool Execute(Event event) override; +}; + +class Aq40Cthun1PositionAction : public MovementAction +{ +public: + Aq40Cthun1PositionAction(PlayerbotAI* botAI, std::string const name = "aq40 cthun1 get positioned") + : MovementAction(botAI, name) + { + /* + x=[-8620.924,-8534.281] + y=[1943.8806,2029.8264] + + -8578.6025,1986.8535 radius 43 = circumference 270, or room for about 20 bots spread 13.5 units apart + so.. two circles, one at radius 50, one at radius 36? + center at -8579.0,1987.0 + rings 14 units apart + outer ring 23 bots about 13.7 units apart + inner ring 17 bots about 13.3 units apart + */ + for (int n = 0; n < outerpointscount; n++) + { + Position* what = new Position(-8579.0F, 1987.0F, 101.0F); + // 45.0: outside of 25 yard range, inside of 30 yard range + what->RelocatePolarOffset(n * M_PI * 2.0 / outerpointscount, 43.0); + outerpoints[n] = what; + //printf("build outerpoint %d: x=%f y=%f z=%f\n",n,what->GetPositionX(),what->GetPositionY(),what->GetPositionZ()); + } + + for (int n = 0; n < innerpointscount; n++) + { + Position* what = new Position(-8579.0F, 1987.0F, 101.0F); + // 45.0: outside of 25 yard range, inside of 30 yard range + what->RelocatePolarOffset(n * M_PI * 2.0 / outerpointscount, 31.0); + innerpoints[n] = what; + //printf("build innerpoint %d: x=%f y=%f z=%f\n",n,what->GetPositionX(),what->GetPositionY(),what->GetPositionZ()); + } + } + bool Execute(Event event) override; + +protected: + static int wrappingdistancebetween(int src, int dst, int scope); + int getnearestpoint(int excludeouter = -1, bool doinner = true); + + static const int outerpointscount = 23; + static const int innerpointscount = 17; + + Position* outerpoints[outerpointscount]; + Position* innerpoints[innerpointscount]; +}; + +class Aq40Cthun2PositionAction : public Aq40Cthun1PositionAction +{ +public: + Aq40Cthun2PositionAction(PlayerbotAI* botAI, std::string const name = "aq40 cthun2 get positioned") + : Aq40Cthun1PositionAction(botAI, name) + { + // oldworld trigger 87646 entry 15384 + getout = new Position(-8546.2, 1987.2, -96.52); + insideattack = new Position(-8550.7, 2000.4, -97.495); + } + bool Execute(Event event) override; + +protected: + Position* getout; + Position* insideattack; + bool outtriggered = false; + bool attackpositioned = false; +}; + +#endif diff --git a/src/strategy/raids/aq40/RaidAq40Strategy.cpp b/src/strategy/raids/aq40/RaidAq40Strategy.cpp new file mode 100644 index 0000000000..a1d28e297c --- /dev/null +++ b/src/strategy/raids/aq40/RaidAq40Strategy.cpp @@ -0,0 +1,42 @@ +#include "RaidAq40Strategy.h" + +#include "Strategy.h" + +void RaidAq40Strategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back( + new TriggerNode("aq40 should use resistance buffs", + NextAction::array(0, new NextAction("aq40 use resistance buffs", ACTION_RAID), nullptr))); + + triggers.push_back( + new TriggerNode("aq40 has emperor aggro", + NextAction::array(0, new NextAction("aq40 move from other emperor", ACTION_EMERGENCY), nullptr))); + + triggers.push_back( + new TriggerNode("aq40 warlock tank emperor", + NextAction::array(0, new NextAction("searing pain", ACTION_RAID), nullptr))); + + triggers.push_back( + new TriggerNode("aq40 mage frostbolt viscidus", // would be rank 1, ideally.. supplying "frostbolt(rank 1)" seems to not work + NextAction::array(0, new NextAction("frostbolt", ACTION_RAID), nullptr))); + + triggers.push_back( + new TriggerNode("aq40 melee viscidus", + NextAction::array(0, new NextAction("aq40 melee viscidus", ACTION_RAID + 1), nullptr))); + + triggers.push_back( + new TriggerNode("aq40 emperor fight", + NextAction::array(0, new NextAction("aq40 decide emperor action", ACTION_RAID), nullptr))); + + triggers.push_back( + new TriggerNode("aq40 ouro burrowed", + NextAction::array(0, new NextAction("aq40 ouro burrowed flee", ACTION_RAID), nullptr))); + + triggers.push_back( + new TriggerNode("aq40 cthun1 started", + NextAction::array(0, new NextAction("aq40 cthun1 get positioned", ACTION_RAID), nullptr))); + + triggers.push_back( + new TriggerNode("aq40 cthun2 started", + NextAction::array(0, new NextAction("aq40 cthun2 get positioned", ACTION_RAID), nullptr))); +} diff --git a/src/strategy/raids/aq40/RaidAq40Strategy.h b/src/strategy/raids/aq40/RaidAq40Strategy.h new file mode 100644 index 0000000000..939cf730d5 --- /dev/null +++ b/src/strategy/raids/aq40/RaidAq40Strategy.h @@ -0,0 +1,17 @@ +#ifndef _PLAYERBOT_RAIDAQ40STRATEGY_H +#define _PLAYERBOT_RAIDAQ40STRATEGY_H + +#include "AiObjectContext.h" +#include "Multiplier.h" +#include "Strategy.h" + +class RaidAq40Strategy : public Strategy +{ +public: + RaidAq40Strategy(PlayerbotAI* ai) : Strategy(ai) {} + virtual std::string const getName() override { return "aq40"; } + virtual void InitTriggers(std::vector& triggers) override; + // virtual void InitMultipliers(std::vector &multipliers) override; +}; + +#endif diff --git a/src/strategy/raids/aq40/RaidAq40TriggerContext.h b/src/strategy/raids/aq40/RaidAq40TriggerContext.h new file mode 100644 index 0000000000..e0e3721ada --- /dev/null +++ b/src/strategy/raids/aq40/RaidAq40TriggerContext.h @@ -0,0 +1,44 @@ +#ifndef _PLAYERBOT_RAIDAQ40TRIGGERCONTEXT_H +#define _PLAYERBOT_RAIDAQ40TRIGGERCONTEXT_H + +#include "AiObjectContext.h" +#include "NamedObjectContext.h" +#include "RaidAq40Triggers.h" + +class RaidAq40TriggerContext : public NamedObjectContext +{ +public: + RaidAq40TriggerContext() + { + creators["aq40 should use resistance buffs"] = &RaidAq40TriggerContext::should_use_resistance_buffs; + creators["aq40 has emperor aggro"] = &RaidAq40TriggerContext::has_emperor_aggro; + creators["aq40 warlock tank emperor"] = &RaidAq40TriggerContext::warlock_tank_emperor; + creators["aq40 mage frostbolt viscidus"] = &RaidAq40TriggerContext::mage_frostbolt_viscidus; + creators["aq40 melee viscidus"] = &RaidAq40TriggerContext::melee_viscidus; + creators["aq40 target emperor vek'lor"] = &RaidAq40TriggerContext::target_emperor_veklor; + creators["aq40 target emperor vek'nilash"] = &RaidAq40TriggerContext::target_emperor_veknilash; + creators["aq40 target emperor pests"] = &RaidAq40TriggerContext::target_emperor_pests; + creators["aq40 approach emperor vek'lor"] = &RaidAq40TriggerContext::approach_emperor_veklor; + creators["aq40 approach emperor vek'nilash"] = &RaidAq40TriggerContext::approach_emperor_veknilash; + creators["aq40 ouro burrowed"] = &RaidAq40TriggerContext::ouro_burrowed; + creators["aq40 cthun1 started"] = &RaidAq40TriggerContext::cthun1_started; + creators["aq40 cthun2 started"] = &RaidAq40TriggerContext::cthun2_started; + } + +private: + static Trigger* should_use_resistance_buffs(PlayerbotAI* ai) { return new Aq40ShouldUseResistanceBuffsTrigger(ai); } + static Trigger* has_emperor_aggro(PlayerbotAI* ai) { return new Aq40HasEmperorAggroTrigger(ai); } + static Trigger* warlock_tank_emperor(PlayerbotAI* ai) { return new Aq40WarlockTankEmperorTrigger(ai); } + static Trigger* mage_frostbolt_viscidus(PlayerbotAI* ai) { return new Aq40MageFrostboltViscidusTrigger(ai); } + static Trigger* melee_viscidus(PlayerbotAI* ai) { return new Aq40MeleeViscidusTrigger(ai); } + static Trigger* target_emperor_veklor(PlayerbotAI* ai) { return new Aq40TargetEmperorVekLorTrigger(ai); } + static Trigger* target_emperor_veknilash(PlayerbotAI* ai) { return new Aq40TargetEmperorVekNilashTrigger(ai); } + static Trigger* target_emperor_pests(PlayerbotAI* ai) { return new Aq40TargetEmperorPestsTrigger(ai); } + static Trigger* approach_emperor_veklor(PlayerbotAI* ai) { return new Aq40ApproachEmperorVekLorTrigger(ai); } + static Trigger* approach_emperor_veknilash(PlayerbotAI* ai) { return new Aq40ApproachEmperorVekNilashTrigger(ai); } + static Trigger* ouro_burrowed(PlayerbotAI* ai) { return new Aq40OuroBurrowedTrigger(ai); } + static Trigger* cthun1_started(PlayerbotAI* ai) { return new Aq40Cthun1StartedTrigger(ai); } + static Trigger* cthun2_started(PlayerbotAI* ai) { return new Aq40Cthun2StartedTrigger(ai); } +}; + +#endif diff --git a/src/strategy/raids/aq40/RaidAq40Triggers.cpp b/src/strategy/raids/aq40/RaidAq40Triggers.cpp new file mode 100644 index 0000000000..c7d4b5e901 --- /dev/null +++ b/src/strategy/raids/aq40/RaidAq40Triggers.cpp @@ -0,0 +1,438 @@ +#include "RaidAq40Triggers.h" + +#include "SharedDefines.h" + +bool Aq40HasEmperorAggroTrigger::IsActive() +{ + // temple_of_ahnquiraj.h + const int NPC_VEKLOR = 15276; + const int NPC_VEKNILASH = 15275; + + ObjectGuid botguid = bot->GetGUID(); + ObjectGuid petguid = (ObjectGuid)0UL; + if (Unit* pet = bot->GetPet()) + { + petguid = pet->GetGUID(); + } + + if (Creature* boss1 = bot->FindNearestCreature(NPC_VEKLOR, 200.0f)) + if (Creature* boss2 = bot->FindNearestCreature(NPC_VEKNILASH, 200.0f)) + { + ObjectGuid boss1target = boss1->GetTarget(); + + if (boss1target && (boss1target == botguid || (petguid && boss1target == petguid))) + { + return true; + } + + ObjectGuid boss2target = boss2->GetTarget(); + + if (boss2target && (boss2target == botguid || (petguid && boss2target == petguid))) + { + return true; + } + } + return false; +} + +bool Aq40WarlockTankEmperorTrigger::IsActive() +{ + if (bot->getClass() == CLASS_WARLOCK) + { + if (Unit* boss1 = AI_VALUE2(Unit*, "find target", "emperor vek'lor")) + { + ObjectGuid bottarget = bot->GetTarget(); + ObjectGuid bossguid = boss1->GetGUID(); + ObjectGuid bosstargetguid = boss1->GetTarget(); + if (bosstargetguid) + { + Player* bosstarget = botAI->GetPlayer(bosstargetguid); + + if (!bosstarget || bosstarget->getClass() != CLASS_WARLOCK || !botAI->IsTank(bosstarget, true)) + { + //std::ostringstream out; + //out << "want tank? target="<GetTarget(); + ObjectGuid bossguid = boss1->GetGUID(); + + //std::ostringstream out; + //out << "want tank? target="<HasAura(SPELL_VISCIDUS_FREEZE)) + { + return true; + } + } + + return false; +} + +bool Aq40EmperorTrigger::IsActive() +{ + Unit* boss1 = AI_VALUE2(Unit*, "find target", "emperor vek'lor"); + Unit* boss2 = AI_VALUE2(Unit*, "find target", "emperor vek'nilash"); + + if (boss1 && boss2 && (boss1->IsInCombat() || boss2->IsInCombat())) + { + Group* group = bot->GetGroup(); + if (!group) + { + return false; + } + + ObjectGuid self = bot->GetGUID(); + ObjectGuid masterguid = botAI->GetMaster()->GetGUID(); + + std::vector memberlists[4]; + for (int n = 0; n < 4; n++) + { + memberlists[n].reserve(group->GetMembersCount()); + } + + int selftype = -1; + + std::vector members; + members.reserve(group->GetMembersCount()); + + for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) + { + Player* member = itr->GetSource(); + auto memberAI = GET_PLAYERBOT_AI(member); + if (memberAI) + { + Player* submaster = memberAI->GetMaster(); + if (submaster && submaster->GetGUID() == masterguid) + { + int assignedtype; + if (member->getClass() == CLASS_WARLOCK) + { + // lol warlock tanks + assignedtype = 0; + } + else if (memberAI->IsTank(member)) + { + assignedtype = 1; + } + else if (memberAI->IsHeal(member)) + { + assignedtype = 2; + } + else + { + assignedtype = 3; + } + + memberlists[assignedtype].push_back(member); + if (member->GetGUID() == self) + { + selftype = assignedtype; + } + } + } + } + + if (selftype < 0 || (IsForHealers() != (selftype == 2))) + { + return false; + } + + + int sametypecount = memberlists[selftype].size(); + + float dist1[sametypecount]; + ObjectGuid dist1who[sametypecount]; + Unit* dist1unit[sametypecount]; + + float dist2[sametypecount]; + ObjectGuid dist2who[sametypecount]; + Unit* dist2unit[sametypecount]; + + for (int n = 0; n < sametypecount; n++) + { + auto member = memberlists[selftype][n]; + + dist1[n] = boss1->GetDistance(member); + dist2[n] = boss2->GetDistance(member); + dist1who[n] = member->GetGUID(); + dist2who[n] = member->GetGUID(); + dist1unit[n] = member; + dist2unit[n] = member; + } + + for (int n = 0; n < sametypecount; n++) + { + for (int subn = n + 1; subn < sametypecount; subn++) + { + if (dist1[n] > dist1[subn]) + { + float fswap = dist1[n]; + dist1[n] = dist1[subn]; + dist1[subn] = fswap; + + ObjectGuid gswap = dist1who[n]; + dist1who[n] = dist1who[subn]; + dist1who[subn] = gswap; + + Unit* uswap = dist1unit[n]; + dist1unit[n] = dist1unit[subn]; + dist1unit[subn] = uswap; + } + + if (dist2[n] > dist2[subn]) + { + float fswap = dist2[n]; + dist2[n] = dist2[subn]; + dist2[subn] = fswap; + + ObjectGuid gswap = dist2who[n]; + dist2who[n] = dist2who[subn]; + dist2who[subn] = gswap; + + Unit* uswap = dist2unit[n]; + dist2unit[n] = dist2unit[subn]; + dist2unit[subn] = uswap; + } + } + } + + ObjectGuid boss1assigned[sametypecount]; + int boss1assignedindex=0; + ObjectGuid boss2assigned[sametypecount]; + int boss2assignedindex=0; + + if (selftype == 3) + { + sametypecount -= 4; + } + else if (selftype == 1) + { + if (sametypecount > 3) + { + sametypecount -= 2; + } + else if (sametypecount > 2) + { + sametypecount--; + } + } + else if (selftype == 2) + { + if (sametypecount > 4) + { + sametypecount = 4; + } + } + + int lastcount = 0; + while (boss1assignedindex + boss2assignedindex < sametypecount) + { + for (int n = 0; n < sametypecount; n++) + { + if (dist1who[n] && boss1assignedindex <= boss2assignedindex) + { + if (selftype != 3 || (dist1unit[n]->getClass() != CLASS_ROGUE && dist1unit[n]->getClass() != CLASS_WARRIOR && dist1unit[n]->getClass() != CLASS_HUNTER)) + { + boss1assigned[boss1assignedindex] = dist1who[n]; + boss1assignedindex++; + + for (int subn = 0; subn < sametypecount; subn++) + { + if (dist2who[subn] == dist1who[n]) + { + dist2who[subn] = (ObjectGuid)0UL; + break; + } + } + dist1who[n] = (ObjectGuid)0UL; + } + } + + if (boss1assignedindex + boss2assignedindex >= sametypecount) + { + break; + } + + if (dist2who[n] && boss2assignedindex <= boss1assignedindex) + { + if (selftype != 3 || (dist2unit[n]->getClass() != CLASS_WARLOCK && dist2unit[n]->getClass() != CLASS_MAGE && dist2unit[n]->getClass() != CLASS_PRIEST)) + { + boss2assigned[boss2assignedindex] = dist2who[n]; + boss2assignedindex++; + + for (int subn = 0; subn < sametypecount; subn++) + { + if (dist1who[subn] == dist2who[n]) + { + dist1who[subn] = (ObjectGuid)0UL; + break; + } + } + dist2who[n] = (ObjectGuid)0UL; + } + } + } + + if (lastcount == boss1assignedindex + boss2assignedindex) + { + // failure to keep filling slots, abort + break; + } + + lastcount = boss1assignedindex + boss2assignedindex; + } + + for (int n = 0; n < boss1assignedindex; n++) + { + if (boss1assigned[n] == self) + { + if (IsVekLor()) + { + std::ostringstream out; + out << "attack vek'lor"; + botAI->TellError(out.str()); + + return true; + } + + return false; + } + } + + for (int n = 0; n < boss2assignedindex; n++) + { + if (boss2assigned[n] == self) + { + if (IsVekNilash()) + { + std::ostringstream out; + out << "attack vek'nilash"; + botAI->TellError(out.str()); + + return true; + } + + return false; + } + } + + if (IsPestControl()) + { + std::ostringstream out; + out << "attack pests"; + botAI->TellError(out.str()); + + return true; + } + } + + return false; +} + +bool Aq40OuroBurrowedTrigger::IsActive() +{ + if (Unit* boss = AI_VALUE2(Unit*, "find target", "ouro")) + { + if (boss->IsInCombat() && (boss->GetUnitFlags() & UNIT_FLAG_NOT_SELECTABLE) == UNIT_FLAG_NOT_SELECTABLE) + { + return true; + } + } + /* + else if (Unit* boss = AI_VALUE2(Unit*, "find target", "eye of c'thun")) + { + if (boss->IsInCombat()) + { + return true; + } + } + */ + + return botAI->HasStrategy("move from group", BotState::BOT_STATE_COMBAT); +} + +bool Aq40Cthun1StartedTrigger::IsActive() +{ + if (Unit* boss = AI_VALUE2(Unit*, "find target", "c'thun")) + { + if (boss->IsAlive() && boss->IsInCombat() && (boss->GetUnitFlags() & UNIT_FLAG_NOT_SELECTABLE) == 0) + { + return false; + } + } + if (Unit* boss = AI_VALUE2(Unit*, "find target", "eye of c'thun")) + { + if (boss->IsAlive() && boss->IsInCombat()) + { + if (!wasactive) + { + //printf("start cthun 1\n"); + wasactive = true; + } + return true; + } + } + + if (wasactive) + { + //printf("end cthun 1\n"); + wasactive = false; + return true; + } + return false; +} + +bool Aq40Cthun2StartedTrigger::IsActive() +{ + if (Unit* boss = AI_VALUE2(Unit*, "find target", "c'thun")) + { + if (boss->IsAlive() && boss->IsInCombat() && (boss->GetUnitFlags() & UNIT_FLAG_NOT_SELECTABLE) == 0) + { + if (!wasactive) + { + //printf("start cthun 2\n"); + wasactive = true; + } + return true; + } + } + + if (wasactive) + { + //printf("end cthun 2\n"); + wasactive = false; + return true; + } + return false; +} diff --git a/src/strategy/raids/aq40/RaidAq40Triggers.h b/src/strategy/raids/aq40/RaidAq40Triggers.h new file mode 100644 index 0000000000..1188eb200b --- /dev/null +++ b/src/strategy/raids/aq40/RaidAq40Triggers.h @@ -0,0 +1,135 @@ +#ifndef _PLAYERBOT_RAIDAQ40TRIGGERS_H +#define _PLAYERBOT_RAIDAQ40TRIGGERS_H + +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "Trigger.h" + +class Aq40ShouldUseResistanceBuffsTrigger : public Trigger +{ +public: + Aq40ShouldUseResistanceBuffsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "aq40 should use resistance buffs") {} + bool IsActive() override { return true; } +}; + +class Aq40HasEmperorAggroTrigger : public Trigger +{ +public: + Aq40HasEmperorAggroTrigger(PlayerbotAI* botAI) : Trigger(botAI, "aq40 has emperor aggro") {} + bool IsActive() override; +}; + +class Aq40WarlockTankEmperorTrigger : public Trigger +{ +public: + Aq40WarlockTankEmperorTrigger(PlayerbotAI* botAI) : Trigger(botAI, "aq40 warlock tank emperor") {} + bool IsActive() override; +}; + +class Aq40MageFrostboltViscidusTrigger : public Trigger +{ +public: + Aq40MageFrostboltViscidusTrigger(PlayerbotAI* botAI) : Trigger(botAI, "aq40 mage frostbolt viscidus") {} + bool IsActive() override; +}; + +class Aq40MeleeViscidusTrigger : public Trigger +{ +public: + Aq40MeleeViscidusTrigger(PlayerbotAI* botAI) : Trigger(botAI, "aq40 melee viscidus") {} + bool IsActive() override; +}; + +class Aq40EmperorTrigger : public Trigger +{ +public: + Aq40EmperorTrigger(PlayerbotAI* botAI, std::string const name) : Trigger(botAI, name) {} + bool IsActive() override; +protected: + virtual bool IsVekLor() { return false; } + virtual bool IsVekNilash() { return false; } + virtual bool IsForHealers() { return false; } + virtual bool IsPestControl() { return false; } +}; + +class Aq40TargetEmperorVekLorTrigger : public Aq40EmperorTrigger +{ +public: + Aq40TargetEmperorVekLorTrigger(PlayerbotAI* botAI) : Aq40EmperorTrigger(botAI, "aq40 target emperor vek'lor") {} +protected: + bool IsVekLor() override { return true; } + bool IsVekNilash() override { return false; } + bool IsForHealers() override { return false; } + bool IsPestControl() override { return false; } +}; + +class Aq40TargetEmperorVekNilashTrigger : public Aq40EmperorTrigger +{ +public: + Aq40TargetEmperorVekNilashTrigger(PlayerbotAI* botAI) : Aq40EmperorTrigger(botAI, "aq40 target emperor vek'nilash") {} +protected: + bool IsVekLor() override { return false; } + bool IsVekNilash() override { return true; } + bool IsForHealers() override { return false; } + bool IsPestControl() override { return false; } +}; + +class Aq40TargetEmperorPestsTrigger : public Aq40EmperorTrigger +{ +public: + Aq40TargetEmperorPestsTrigger(PlayerbotAI* botAI) : Aq40EmperorTrigger(botAI, "aq40 target emperor pests") {} +protected: + bool IsVekLor() override { return false; } + bool IsVekNilash() override { return false; } + bool IsForHealers() override { return false; } + bool IsPestControl() override { return true; } +}; + +class Aq40ApproachEmperorVekLorTrigger : public Aq40EmperorTrigger +{ +public: + Aq40ApproachEmperorVekLorTrigger(PlayerbotAI* botAI) : Aq40EmperorTrigger(botAI, "aq40 approach emperor vek'lor") {} +protected: + bool IsVekLor() override { return true; } + bool IsVekNilash() override { return false; } + bool IsForHealers() override { return true; } + bool IsPestControl() override { return false; } +}; + +class Aq40ApproachEmperorVekNilashTrigger : public Aq40EmperorTrigger +{ +public: + Aq40ApproachEmperorVekNilashTrigger(PlayerbotAI* botAI) : Aq40EmperorTrigger(botAI, "aq40 approach emperor vek'nilash") {} +protected: + bool IsVekLor() override { return false; } + bool IsVekNilash() override { return true; } + bool IsForHealers() override { return true; } + bool IsPestControl() override { return false; } +}; + +class Aq40OuroBurrowedTrigger : public Trigger +{ +public: + Aq40OuroBurrowedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "aq40 ouro burrowed") {} + bool IsActive() override; +}; + +class Aq40Cthun1StartedTrigger : public Trigger +{ +public: + Aq40Cthun1StartedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "aq40 cthun1 started") {} + bool IsActive() override; +private: + bool wasactive = false; +}; + +class Aq40Cthun2StartedTrigger : public Trigger +{ +public: + Aq40Cthun2StartedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "aq40 cthun2 started") {} + bool IsActive() override; +private: + bool wasactive = false; +}; + +#endif From bb6c33ff22b76095271aca9e556d408429f9d451 Mon Sep 17 00:00:00 2001 From: valsan-azerty-boi <52854501+valsan-azerty-boi@users.noreply.github.com> Date: Wed, 5 Mar 2025 20:40:17 +0100 Subject: [PATCH 2/5] auto apply aq40 strat --- src/PlayerbotAI.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 87ef92a2b5..a1f19226fb 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -1481,6 +1481,9 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster) case 509: strategyName = "aq20"; break; + case 531: + strategyName = "aq40"; + break; case 533: strategyName = "naxx"; break; From 39de97fd4ebebe1f2694818fb0fd41af63274bc6 Mon Sep 17 00:00:00 2001 From: valsan-azerty-boi <52854501+valsan-azerty-boi@users.noreply.github.com> Date: Sat, 10 May 2025 19:38:52 +0200 Subject: [PATCH 3/5] Update AiObjectContext.cpp --- src/strategy/AiObjectContext.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index 62d0afd2bf..fc90df990f 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -74,6 +74,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) actionContexts.Add(new WotlkDungeonGDActionContext()); actionContexts.Add(new WotlkDungeonHoSActionContext()); actionContexts.Add(new WotlkDungeonHoLActionContext()); + actionContexts.Add(new WotlkDungeonOccActionContext()); actionContexts.Add(new WotlkDungeonUPActionContext()); actionContexts.Add(new WotlkDungeonCoSActionContext()); actionContexts.Add(new WotlkDungeonFoSActionContext()); @@ -102,6 +103,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI) triggerContexts.Add(new WotlkDungeonGDTriggerContext()); triggerContexts.Add(new WotlkDungeonHoSTriggerContext()); triggerContexts.Add(new WotlkDungeonHoLTriggerContext()); + triggerContexts.Add(new WotlkDungeonOccTriggerContext()); triggerContexts.Add(new WotlkDungeonUPTriggerContext()); triggerContexts.Add(new WotlkDungeonCoSTriggerContext()); triggerContexts.Add(new WotlkDungeonFosTriggerContext()); From 2032fab1595900f16679e3e87df305928d52b0e2 Mon Sep 17 00:00:00 2001 From: Keleborn <22352763+Celandriel@users.noreply.github.com> Date: Tue, 4 Nov 2025 23:11:58 -0800 Subject: [PATCH 4/5] fix merge error. --- src/strategy/AiObjectContext.cpp | 2 -- src/strategy/raids/RaidStrategyContext.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/strategy/AiObjectContext.cpp b/src/strategy/AiObjectContext.cpp index 43540d17e7..d2cf149cb1 100644 --- a/src/strategy/AiObjectContext.cpp +++ b/src/strategy/AiObjectContext.cpp @@ -130,7 +130,6 @@ void AiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList public: RaidStrategyContext() : NamedObjectContext(false, true) { - creators["aq20"] = &RaidStrategyContext::aq20; creators["mc"] = &RaidStrategyContext::mc; creators["bwl"] = &RaidStrategyContext::bwl; creators["karazhan"] = &RaidStrategyContext::karazhan; @@ -41,7 +40,6 @@ class RaidStrategyContext : public NamedObjectContext } private: - static Strategy* aq20(PlayerbotAI* botAI) { return new RaidAq20Strategy(botAI); } static Strategy* mc(PlayerbotAI* botAI) { return new RaidMcStrategy(botAI); } static Strategy* bwl(PlayerbotAI* botAI) { return new RaidBwlStrategy(botAI); } static Strategy* karazhan(PlayerbotAI* botAI) { return new RaidKarazhanStrategy(botAI); } From 063d7c54f89a6fc3c3985598760b71e4c67d72f2 Mon Sep 17 00:00:00 2001 From: Keleborn <22352763+Celandriel@users.noreply.github.com> Date: Wed, 5 Nov 2025 12:20:22 -0800 Subject: [PATCH 5/5] Formatting updates --- src/strategy/raids/aq40/RaidAq40Actions.cpp | 318 +++++++++----------- src/strategy/raids/aq40/RaidAq40Actions.h | 24 +- 2 files changed, 158 insertions(+), 184 deletions(-) diff --git a/src/strategy/raids/aq40/RaidAq40Actions.cpp b/src/strategy/raids/aq40/RaidAq40Actions.cpp index ef035771a8..bce8230a76 100644 --- a/src/strategy/raids/aq40/RaidAq40Actions.cpp +++ b/src/strategy/raids/aq40/RaidAq40Actions.cpp @@ -8,50 +8,47 @@ bool Aq40UseResistanceBuffsAction::Execute(Event event) switch(bot->getClass()) { case CLASS_HUNTER: - { - bool isnatureboss = false; - - Unit* boss; + { + bool isNatureBoss = false; + Unit* boss; - if ((boss = AI_VALUE2(Unit*, "find target", "viscidus")) && boss->IsInCombat()) - { - isnatureboss = true; - } - else if ((boss = AI_VALUE2(Unit*, "find target", "princess huhuran")) && boss->IsInCombat()) - { - isnatureboss = true; - } + if ((boss = AI_VALUE2(Unit*, "find target", "viscidus")) && boss->IsInCombat()) + isNatureBoss = true; - if (isnatureboss) - { - if (!botAI->HasStrategy("rnature", BotState::BOT_STATE_COMBAT)) - { - botAI->ChangeStrategy("+rnature", BOT_STATE_NON_COMBAT); - botAI->ChangeStrategy("+rnature", BOT_STATE_COMBAT); - return true; - } - } - else if (botAI->HasStrategy("rnature", BotState::BOT_STATE_COMBAT)) + else if ((boss = AI_VALUE2(Unit*, "find target", "princess huhuran")) && boss->IsInCombat()) + isNatureBoss = true; + + if (isNatureBoss) + { + if (!botAI->HasStrategy("rnature", BotState::BOT_STATE_COMBAT)) { - botAI->ChangeStrategy("-rnature", BOT_STATE_NON_COMBAT); - botAI->ChangeStrategy("-rnature", BOT_STATE_COMBAT); + botAI->ChangeStrategy("+rnature", BOT_STATE_NON_COMBAT); + botAI->ChangeStrategy("+rnature", BOT_STATE_COMBAT); return true; } } - break; + else if (botAI->HasStrategy("rnature", BotState::BOT_STATE_COMBAT)) + { + botAI->ChangeStrategy("-rnature", BOT_STATE_NON_COMBAT); + botAI->ChangeStrategy("-rnature", BOT_STATE_COMBAT); + return true; + } + } + break; case CLASS_PRIEST: + { + // paladin aura seems like a waste when priests have buffs that don't have a radius limitation + if (!botAI->HasStrategy("rshadow", BotState::BOT_STATE_NON_COMBAT)) { - // paladin aura seems like a waste when priests have buffs that don't have a radius limitation - if (!botAI->HasStrategy("rshadow", BotState::BOT_STATE_NON_COMBAT)) - { - botAI->ChangeStrategy("+rshadow", BOT_STATE_NON_COMBAT); - botAI->ChangeStrategy("+rshadow", BOT_STATE_COMBAT); - return true; - } + botAI->ChangeStrategy("+rshadow", BOT_STATE_NON_COMBAT); + botAI->ChangeStrategy("+rshadow", BOT_STATE_COMBAT); + return true; } - break; + } + break; + case default; + break; } - return false; } @@ -67,29 +64,24 @@ bool Aq40MoveFromOtherEmperorAction::Execute(Event event) if (Unit* boss1 = AI_VALUE2(Unit*, "find target", "emperor vek'lor")) if (Unit* boss2 = AI_VALUE2(Unit*, "find target", "emperor vek'nilash")) { - ObjectGuid botguid = bot->GetGUID(); - ObjectGuid petguid = (ObjectGuid)0UL; + ObjectGuid botGuid = bot->GetGUID(); + ObjectGuid petGuid = (ObjectGuid)0UL; if (Pet* pet = bot->GetPet()) - { - petguid = pet->GetGUID(); - } + petGuid = pet->GetGUID(); + Unit* moveAwayFrom = NULL; - if (boss1->GetTarget() == botguid || boss1->GetTarget() == petguid) + if (boss1->GetTarget() == botGuid || boss1->GetTarget() == petGuid) { moveAwayFrom = boss2; - if (petguid) - { + if (petGuid) botAI->PetFollow(); - } } - else if (boss2->GetTarget() == botguid || boss2->GetTarget() == petguid) + else if (boss2->GetTarget() == botGuid || boss2->GetTarget() == petGuid) { moveAwayFrom = boss1; - if (petguid) - { + if (petGuid) botAI->PetFollow(); - } } if (moveAwayFrom != NULL) @@ -97,9 +89,7 @@ bool Aq40MoveFromOtherEmperorAction::Execute(Event event) long distToTravel = radius - bot->GetDistance(moveAwayFrom); if (distToTravel > 0) - { - return MoveAway(moveAwayFrom, distToTravel); - } + return MoveAway(moveAwayFrom, distToTravel); } } @@ -146,10 +136,7 @@ bool Aq40AttackTargetByNameAction::Execute(Event event) return result; } } - else - { - return false; - } + return false; } bool Aq40AttackEmperorPestsAction::Execute(Event event) @@ -157,9 +144,8 @@ bool Aq40AttackEmperorPestsAction::Execute(Event event) Unit* current = AI_VALUE(Unit*, "current target"); if (current && (current->GetName() == "qiraji scarab" || current->GetName() == "qiraji scorpion")) - { return false; - } + Unit* pest1 = AI_VALUE2(Unit*, "find target", "qiraji scarab"); Unit* pest2 = AI_VALUE2(Unit*, "find target", "qiraji scorpion"); @@ -168,26 +154,20 @@ bool Aq40AttackEmperorPestsAction::Execute(Event event) if (pest1 && pest2) { if (pest1->GetDistance(bot) < pest2->GetDistance(bot)) - { pest = pest1; - } + else - { pest = pest2; - } } else if (pest1) - { pest = pest1; - } + else if (pest2) - { pest = pest2; - } + else - { return false; - } + ObjectGuid guid = pest->GetGUID(); botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({guid}); @@ -204,21 +184,18 @@ bool Aq40MoveTowardsEmperorAction::Execute(Event event) if (Unit* boss = AI_VALUE2(Unit*, "find target", WhichEmperor())) { - if (ObjectGuid bosstarget = boss->GetTarget()) + if (ObjectGuid bossTarget = boss->GetTarget()) { - Unit* target = botAI->GetUnit(bosstarget); + Unit* target = botAI->GetUnit(bossTarget); - long traveltarget = -1;//radius - bot->GetDistance(target); - long travelboss = radius - bot->GetDistance(boss); + long travelTarger = -1;//radius - bot->GetDistance(target); + long travelBoss = radius - bot->GetDistance(boss); + + if (travelTarger > travelBoss) + return MoveTo(target, travelTarger); - if (traveltarget > travelboss) - { - return MoveTo(target, traveltarget); - } else - { - return MoveTo(boss, travelboss); - } + return MoveTo(boss, travelBoss); } } @@ -227,15 +204,15 @@ bool Aq40MoveTowardsEmperorAction::Execute(Event event) bool Aq40OuroBurrowedFleeAction::Execute(Event event) { - bool doflee = false; + bool doFlee = false; if (Unit* boss = AI_VALUE2(Unit*, "find target", "ouro")) { if (boss->IsInCombat() && (boss->GetUnitFlags() & UNIT_FLAG_NOT_SELECTABLE) == UNIT_FLAG_NOT_SELECTABLE) { - doflee = true; + doFlee = true; - // todo: if ankle-biter scarab is near, doflee = false + // todo: if ankle-biter scarab is near, doFlee = false } } @@ -248,18 +225,18 @@ bool Aq40OuroBurrowedFleeAction::Execute(Event event) //printf("eyedist %f\n",dist); - doflee = dist < 13.0; + doFlee = dist < 13.0; if (bot->GetName() == "Snusnu") { - printf("eyedist %f doflee %d\n",dist,doflee); + printf("eyedist %f doFlee %d\n",dist,doFlee); } } } */ - if (doflee) + if (doFlee) { if (!botAI->HasStrategy("move from group", BotState::BOT_STATE_COMBAT)) { @@ -282,57 +259,54 @@ bool Aq40OuroBurrowedFleeAction::Execute(Event event) return true; } -int Aq40Cthun1PositionAction::wrappingdistancebetween(int first, int second, int scope) +int Aq40Cthun1PositionAction::WrappingDistanceBetween(int first, int second, int scope) { - int retval = first - second; - if (abs(retval) > scope / 2) + int retVal = first - second; + if (abs(retVal) > scope / 2) { - if (retval > scope / 2) - { - retval = retval - scope; - } + if (retVal > scope / 2) + retVal = retVal - scope; + else - { - retval = scope + retval; - } + retVal = scope + retVal; } - return retval; + return retVal; } -int Aq40Cthun1PositionAction::getnearestpoint(int excludeouter, bool doinner) +int Aq40Cthun1PositionAction::GetNearestPoint(int excludeouter, bool doinner) { - int retval = -1; - float retvaldist = 0.0F; + int retVal = -1; + float retValDist = 0.0F; - for (int n = 0; n < outerpointscount; n++) + for (int n = 0; n < outerPointsCount; n++) { - float dist = bot->GetDistance(outerpoints[n]->GetPositionX(), outerpoints[n]->GetPositionY(), outerpoints[n]->GetPositionZ()); + float dist = bot->GetDistance(outerPoints[n]->GetPositionX(), outerPoints[n]->GetPositionY(), outerPoints[n]->GetPositionZ()); - if (retval < 0 || retvaldist > dist) + if (retVal < 0 || retValDist > dist) { if (excludeouter != n) { - retval = n; - retvaldist = dist; + retVal = n; + retValDist = dist; } } } if (doinner) { - for (int n = 0; n < innerpointscount; n++) + for (int n = 0; n < innerPointsCount; n++) { - float dist = bot->GetDistance(innerpoints[n]->GetPositionX(), innerpoints[n]->GetPositionY(), innerpoints[n]->GetPositionZ()); + float dist = bot->GetDistance(innerPoints[n]->GetPositionX(), innerPoints[n]->GetPositionY(), innerPoints[n]->GetPositionZ()); - if (retval < 0 || retvaldist > dist) + if (retVal < 0 || retValDist > dist) { - retval = n + outerpointscount; - retvaldist = dist; + retVal = n + outerPointsCount; + retValDist = dist; } } } - return retval; + return retVal; } bool Aq40Cthun1PositionAction::Execute(Event event) @@ -342,31 +316,31 @@ bool Aq40Cthun1PositionAction::Execute(Event event) const int SPELL_RED_COLORATION = 22518; //Probably not the right spell but looks similar - ObjectGuid botguid = bot->GetGUID(); + ObjectGuid botGuid = bot->GetGUID(); if (Unit* boss = AI_VALUE2(Unit*, "find target", "eye of c'thun")) { Position* point = NULL; - ObjectGuid bosstargetguid = boss->GetTarget(); + ObjectGuid bossTargetguid = boss->GetTarget(); if (boss->HasAura(SPELL_RED_COLORATION)) { - int bossd = (int)(boss->GetOrientation() * outerpointscount / (M_PI * 2.0)); + int bossd = (int)(boss->GetOrientation() * outerPointsCount / (M_PI * 2.0)); if (bossd < 0) { - bossd = bossd + outerpointscount * ((-bossd) / outerpointscount + 1); + bossd = bossd + outerPointsCount * ((-bossd) / outerPointsCount + 1); } - bossd %= outerpointscount; + bossd %= outerPointsCount; - int nearest = getnearestpoint(bossd, false); - int dist = wrappingdistancebetween(bossd, nearest, outerpointscount); + int nearest = GetNearestPoint(bossd, false); + int dist = WrappingDistanceBetween(bossd, nearest, outerPointsCount); - if (abs(dist) <= outerpointscount / 6) + if (abs(dist) <= outerPointsCount / 6) { - nearest = (nearest + outerpointscount - dist * (outerpointscount / 6) / abs(dist)) % outerpointscount; + nearest = (nearest + outerPointsCount - dist * (outerPointsCount / 6) / abs(dist)) % outerPointsCount; } - point = outerpoints[nearest]; + point = outerPoints[nearest]; if (bot->GetDistance(*point) < 0.5) { @@ -375,7 +349,7 @@ bool Aq40Cthun1PositionAction::Execute(Event event) } else { - if (bosstargetguid == botguid) + if (bossTargetguid == botGuid) { bot->StopMoving(); return true; @@ -386,18 +360,18 @@ bool Aq40Cthun1PositionAction::Execute(Event event) if (spell and spell->m_spellInfo->Id == SPELL_GREEN_BEAM) { - Unit* bosstarget = botAI->GetUnit(bosstargetguid); - float bdist = bot->GetDistance(bosstarget); + Unit* bossTarget = botAI->GetUnit(bossTargetguid); + float bdist = bot->GetDistance(bossTarget); if (bdist < 20.0) { if (bdist <= 10.0) { bot->AttackStop(); - //printf("%s: still %f away from %s\n",bot->GetName().c_str(),bdist,bosstarget->GetName().c_str()); + //printf("%s: still %f away from %s\n",bot->GetName().c_str(),bdist,bossTarget->GetName().c_str()); } - return MoveAway(bosstarget, 20.0); + return MoveAway(bossTarget, 20.0); } } } @@ -409,20 +383,20 @@ bool Aq40Cthun1PositionAction::Execute(Event event) if (bot->GetDistance(boss) < 60.0F && group) { Player* closest = NULL; - float closestdist = 0.0F; + float closestDist = 0.0F; for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* member = itr->GetSource(); - if (member->GetGUID() != botguid && member->IsAlive()) + if (member->GetGUID() != botGuid && member->IsAlive()) { float dist = bot->GetDistance(member); - if (dist < 10.0 && (closest == NULL || closestdist < dist)) + if (dist < 10.0 && (closest == NULL || closestDist < dist)) { closest = member; - closestdist = dist; + closestDist = dist; } } } @@ -433,15 +407,15 @@ bool Aq40Cthun1PositionAction::Execute(Event event) } } - int nearest = getnearestpoint(); + int nearest = GetNearestPoint(); - if (nearest >= outerpointscount) + if (nearest >= outerPointsCount) { - point = innerpoints[nearest - outerpointscount]; + point = innerPoints[nearest - outerPointsCount]; } else { - point = outerpoints[nearest]; + point = outerPoints[nearest]; } if (bot->GetDistance(*point) < 0.5) @@ -456,7 +430,7 @@ bool Aq40Cthun1PositionAction::Execute(Event event) false, false, false, true, MovementPriority::MOVEMENT_COMBAT); } } - + return false; } @@ -483,7 +457,7 @@ bool Aq40Cthun2PositionAction::Execute(Event event) const int NPC_GIANT_EYE_TENTACLE = 15334; const int NPC_FLESH_TENTACLE = 15802; - ObjectGuid botguid = bot->GetGUID(); + ObjectGuid botGuid = bot->GetGUID(); if (Unit* boss = AI_VALUE2(Unit*, "find target", "c'thun")) { @@ -499,20 +473,20 @@ bool Aq40Cthun2PositionAction::Execute(Event event) if (group) { Player* closest = NULL; - float closestdist = 0.0F; + float closestDist = 0.0F; for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) { Player* member = itr->GetSource(); - if (member->GetGUID() != botguid && member->IsAlive()) + if (member->GetGUID() != botGuid && member->IsAlive()) { float dist = bot->GetDistance(member); - if (dist < 11.0 && (closest == NULL || closestdist < dist)) + if (dist < 11.0 && (closest == NULL || closestDist < dist)) { closest = member; - closestdist = dist; + closestDist = dist; } } } @@ -524,41 +498,41 @@ bool Aq40Cthun2PositionAction::Execute(Event event) } } - Unit* attacktarget = NULL; + Unit* attackTarget = NULL; if (!boss->HasAura(SPELL_CARAPACE_CTHUN)) { - attacktarget = boss; + attackTarget = boss; } else if (tentacle1) { - attacktarget = tentacle1; + attackTarget = tentacle1; } else if (Creature* tentacle3 = bot->FindNearestCreature(NPC_EYE_TENTACLE, 100.0f, true)) { - attacktarget = tentacle3; + attackTarget = tentacle3; } else if (Creature* tentacle2 = bot->FindNearestCreature(NPC_GIANT_CLAW_TENTACLE, 100.0f, true)) { - attacktarget = tentacle2; + attackTarget = tentacle2; } else if (Creature* tentacle4 = bot->FindNearestCreature(NPC_CLAW_TENTACLE, 100.0f, true)) { - attacktarget = tentacle4; + attackTarget = tentacle4; } - if (attacktarget) + if (attackTarget) { - ObjectGuid guid = attacktarget->GetGUID(); + ObjectGuid guid = attackTarget->GetGUID(); botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({guid}); - bot->Attack(attacktarget, botAI->IsMelee(bot)); + bot->Attack(attackTarget, botAI->IsMelee(bot)); return false; } - outtriggered = false; - attackpositioned = false; + outTriggered = false; + attackPositioned = false; } else { @@ -569,40 +543,40 @@ bool Aq40Cthun2PositionAction::Execute(Event event) bot->TeleportTo(bot->GetMapId(), -8562.1, 2037.0, -99.58, 5.03); } - bool dogetout = false; + bool doGetOut = false; - if (!attackpositioned) + if (!attackPositioned) { point = insideattack; if (bot->GetDistance(*point) < 1.0) { - attackpositioned = true; + attackPositioned = true; } } else { - int astack = bot->GetAuraCount(SPELL_DIGESTIVE_ACID); - int adamage = (astack + (astack + 1) + (astack + 2)) * 150; // 150 per stack, 5 second tick + int auraStack = bot->GetAuraCount(SPELL_DIGESTIVE_ACID); + int auraDamage = (auraStack + (auraStack + 1) + (auraStack + 2)) * 150; // 150 per stack, 5 second tick - if (adamage >= bot->GetHealth()) + if (auraDamage >= bot->GetHealth()) { - point = getout; - dogetout = true; + point = getOut; + doGetOut = true; //printf("%s: low health, get out\n",bot->GetName().c_str()); } - else if (astack < 1) // bugged state check + else if (auraStack < 1) // bugged state check { // immediately leave - point = getout; - dogetout = true; + point = getOut; + doGetOut = true; //printf("%s: bugged state, get out\n",bot->GetName().c_str()); } else if (botAI->IsTank(bot, true)) { // immediately leave - point = getout; - dogetout = true; + point = getOut; + doGetOut = true; //printf("%s: tank, get out\n",bot->GetName().c_str()); } else if (botAI->IsHeal(bot, true)) @@ -610,8 +584,8 @@ bool Aq40Cthun2PositionAction::Execute(Event event) // stack to 5 and leave, lower tolerance for healers if (bot->GetAuraCount(SPELL_DIGESTIVE_ACID) >= 5 || bot->GetHealthPct() <= 50.0) { - point = getout; - dogetout = true; + point = getOut; + doGetOut = true; } } else @@ -620,18 +594,18 @@ bool Aq40Cthun2PositionAction::Execute(Event event) // working after the below statement was used here instead? if (Creature* tboss = bot->FindNearestCreature(NPC_FLESH_TENTACLE, 100.0f, true)) { - bool hastarget = false; + bool hasTarget = false; ObjectGuid targetguid = bot->GetTarget(); if (Unit* target = botAI->GetUnit(targetguid)) { if (target->GetEntry() == NPC_FLESH_TENTACLE) { - hastarget = true; + hasTarget = true; } } - if (!hastarget) + if (!hasTarget) { ObjectGuid guid = tboss->GetGUID(); @@ -656,13 +630,13 @@ bool Aq40Cthun2PositionAction::Execute(Event event) else { //printf("%s: no flesh tentacle, get out\n",bot->GetName().c_str()); - point = getout; - dogetout = true; + point = getOut; + doGetOut = true; } } } - if (dogetout && !outtriggered) + if (doGetOut && !outTriggered) { if (bot->GetDistance(*point) < 10.0) { @@ -681,11 +655,11 @@ bool Aq40Cthun2PositionAction::Execute(Event event) exittrigger->CastSpell(player, SPELL_RUBBLE_ROCKY, true); } - outtriggered = true; + outTriggered = true; } } - if (outtriggered) + if (outTriggered) { player->m_Events.AddEventAtOffset([player, cthun]() { @@ -717,6 +691,6 @@ bool Aq40Cthun2PositionAction::Execute(Event event) false, false, false, true, MovementPriority::MOVEMENT_COMBAT); } } - + return false; } diff --git a/src/strategy/raids/aq40/RaidAq40Actions.h b/src/strategy/raids/aq40/RaidAq40Actions.h index da905140ee..31adcef2f1 100644 --- a/src/strategy/raids/aq40/RaidAq40Actions.h +++ b/src/strategy/raids/aq40/RaidAq40Actions.h @@ -146,14 +146,14 @@ class Aq40Cthun1PositionAction : public MovementAction bool Execute(Event event) override; protected: - static int wrappingdistancebetween(int src, int dst, int scope); - int getnearestpoint(int excludeouter = -1, bool doinner = true); + static int WrappingDistanceBetween(int src, int dst, int scope); + int GetNearestPoint(int excludeouter = -1, bool doinner = true); - static const int outerpointscount = 23; - static const int innerpointscount = 17; + static const int outerPointsCount = 23; + static const int innerPointsCount = 17; - Position* outerpoints[outerpointscount]; - Position* innerpoints[innerpointscount]; + Position* outerPoints[outerPointsCount]; + Position* innerPoints[innerPointsCount]; }; class Aq40Cthun2PositionAction : public Aq40Cthun1PositionAction @@ -163,16 +163,16 @@ class Aq40Cthun2PositionAction : public Aq40Cthun1PositionAction : Aq40Cthun1PositionAction(botAI, name) { // oldworld trigger 87646 entry 15384 - getout = new Position(-8546.2, 1987.2, -96.52); - insideattack = new Position(-8550.7, 2000.4, -97.495); + getOut = new Position(-8546.2, 1987.2, -96.52); + insideAttack = new Position(-8550.7, 2000.4, -97.495); } bool Execute(Event event) override; protected: - Position* getout; - Position* insideattack; - bool outtriggered = false; - bool attackpositioned = false; + Position* getOut; + Position* insideAttack; + bool outTriggered = false; + bool attackPositioned = false; }; #endif