diff --git a/src/Ai/Base/ActionContext.h b/src/Ai/Base/ActionContext.h index 93bba4af..6431ee87 100644 --- a/src/Ai/Base/ActionContext.h +++ b/src/Ai/Base/ActionContext.h @@ -125,6 +125,7 @@ public: creators["runaway"] = &ActionContext::runaway; creators["stay"] = &ActionContext::stay; creators["sit"] = &ActionContext::sit; + creators["aggressive target"] = &ActionContext::aggressive_target; creators["attack anything"] = &ActionContext::attack_anything; creators["attack least hp target"] = &ActionContext::attack_least_hp_target; creators["attack enemy player"] = &ActionContext::attack_enemy_player; @@ -315,6 +316,7 @@ private: static Action* suggest_what_to_do(PlayerbotAI* botAI) { return new SuggestWhatToDoAction(botAI); } static Action* suggest_trade(PlayerbotAI* botAI) { return new SuggestTradeAction(botAI); } static Action* suggest_dungeon(PlayerbotAI* botAI) { return new SuggestDungeonAction(botAI); } + static Action* aggressive_target(PlayerbotAI* botAI) { return new AggressiveTargetAction(botAI); } static Action* attack_anything(PlayerbotAI* botAI) { return new AttackAnythingAction(botAI); } static Action* attack_least_hp_target(PlayerbotAI* botAI) { return new AttackLeastHpTargetAction(botAI); } static Action* attack_enemy_player(PlayerbotAI* botAI) { return new AttackEnemyPlayerAction(botAI); } diff --git a/src/Ai/Base/Actions/ChooseTargetActions.cpp b/src/Ai/Base/Actions/ChooseTargetActions.cpp index f7538c03..debcfac0 100644 --- a/src/Ai/Base/Actions/ChooseTargetActions.cpp +++ b/src/Ai/Base/Actions/ChooseTargetActions.cpp @@ -30,6 +30,14 @@ bool AttackEnemyFlagCarrierAction::isUseful() PlayerHasFlag::IsCapturingFlag(bot); } +bool AggressiveTargetAction::isUseful() +{ + if (bot->IsInCombat()) + return false; + + return true; +} + bool DropTargetAction::Execute(Event /*event*/) { Unit* target = context->GetValue("current target")->Get(); diff --git a/src/Ai/Base/Actions/ChooseTargetActions.h b/src/Ai/Base/Actions/ChooseTargetActions.h index 5f905019..5822543e 100644 --- a/src/Ai/Base/Actions/ChooseTargetActions.h +++ b/src/Ai/Base/Actions/ChooseTargetActions.h @@ -35,6 +35,15 @@ public: std::string const GetTargetName() override { return "tank target"; } }; +class AggressiveTargetAction : public AttackAction +{ +public: + AggressiveTargetAction(PlayerbotAI* botAI) : AttackAction(botAI, "aggressive target") {} + + std::string const GetTargetName() override { return "aggressive target"; } + bool isUseful() override; +}; + class AttackAnythingAction : public AttackAction { public: diff --git a/src/Ai/Base/Strategy/AggressiveStrategy.cpp b/src/Ai/Base/Strategy/AggressiveStrategy.cpp new file mode 100644 index 00000000..385e9408 --- /dev/null +++ b/src/Ai/Base/Strategy/AggressiveStrategy.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it + * and/or modify it under version 3 of the License, or (at your option), any later version. + */ + +#include "AggressiveStrategy.h" + +#include "Playerbots.h" + +void AggressiveStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back( + new TriggerNode( + "no target", + { + NextAction("aggressive target", 4.0f) + } + ) + ); +} diff --git a/src/Ai/Base/Strategy/AggressiveStrategy.h b/src/Ai/Base/Strategy/AggressiveStrategy.h new file mode 100644 index 00000000..8a81192e --- /dev/null +++ b/src/Ai/Base/Strategy/AggressiveStrategy.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it + * and/or modify it under version 3 of the License, or (at your option), any later version. + */ + +#ifndef _PLAYERBOT_AGGRESSIVESTRATEGY_H +#define _PLAYERBOT_AGGRESSIVESTRATEGY_H + +#include "NonCombatStrategy.h" + +class PlayerbotAI; + +class AggressiveStrategy : public NonCombatStrategy +{ +public: + AggressiveStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {} + + std::string const getName() override { return "aggressive"; } + void InitTriggers(std::vector& triggers) override; +}; + +#endif diff --git a/src/Ai/Base/StrategyContext.h b/src/Ai/Base/StrategyContext.h index 0cc6855f..60e6808c 100644 --- a/src/Ai/Base/StrategyContext.h +++ b/src/Ai/Base/StrategyContext.h @@ -6,6 +6,7 @@ #ifndef _PLAYERBOT_STRATEGYCONTEXT_H #define _PLAYERBOT_STRATEGYCONTEXT_H +#include "AggressiveStrategy.h" #include "AttackEnemyPlayersStrategy.h" #include "BattlegroundStrategy.h" #include "CastTimeStrategy.h" @@ -61,6 +62,7 @@ public: creators["gather"] = &StrategyContext::gather; creators["emote"] = &StrategyContext::emote; creators["passive"] = &StrategyContext::passive; + creators["aggressive"] = &StrategyContext::aggressive; creators["save mana"] = &StrategyContext::auto_save_mana; creators["food"] = &StrategyContext::food; creators["chat"] = &StrategyContext::chat; @@ -144,6 +146,7 @@ private: static Strategy* gather(PlayerbotAI* botAI) { return new GatherStrategy(botAI); } static Strategy* emote(PlayerbotAI* botAI) { return new EmoteStrategy(botAI); } static Strategy* passive(PlayerbotAI* botAI) { return new PassiveStrategy(botAI); } + static Strategy* aggressive(PlayerbotAI* botAI) { return new AggressiveStrategy(botAI); } // static Strategy* conserve_mana(PlayerbotAI* botAI) { return new ConserveManaStrategy(botAI); } static Strategy* auto_save_mana(PlayerbotAI* botAI) { return new HealerAutoSaveManaStrategy(botAI); } static Strategy* food(PlayerbotAI* botAI) { return new UseFoodStrategy(botAI); } diff --git a/src/Ai/Base/Value/AggressiveTargetValue.cpp b/src/Ai/Base/Value/AggressiveTargetValue.cpp new file mode 100644 index 00000000..bbf39348 --- /dev/null +++ b/src/Ai/Base/Value/AggressiveTargetValue.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it + * and/or modify it under version 3 of the License, or (at your option), any later version. + */ + +#include "AggressiveTargetValue.h" + +#include "Playerbots.h" +#include "ServerFacade.h" +#include "SharedDefines.h" + +Unit* AggressiveTargetValue::Calculate() +{ + Player* master = GetMaster(); + + if (master && (master == bot || master->GetMapId() != bot->GetMapId() || master->IsBeingTeleported() || + !GET_PLAYERBOT_AI(master))) + master = nullptr; + + GuidVector targets = AI_VALUE(GuidVector, "possible targets"); + if (targets.empty()) + return nullptr; + + float aggroRange = sPlayerbotAIConfig.aggroDistance; + float distance = 0; + Unit* result = nullptr; + + for (ObjectGuid const guid : targets) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit || !unit->IsAlive()) + continue; + + if (!unit->IsInWorld() || unit->IsDuringRemoveFromWorld()) + continue; + + if (unit->ToCreature() && !unit->ToCreature()->GetCreatureTemplate()->lootid && + bot->GetReactionTo(unit) >= REP_NEUTRAL) + continue; + + if (!bot->IsHostileTo(unit) && unit->GetNpcFlags() != UNIT_NPC_FLAG_NONE) + continue; + + if (abs(bot->GetPositionZ() - unit->GetPositionZ()) > INTERACTION_DISTANCE) + continue; + + if (!bot->InBattleground() && master && botAI->HasStrategy("follow", BotState::BOT_STATE_NON_COMBAT) && + ServerFacade::instance().GetDistance2d(master, unit) > aggroRange) + continue; + + if (!bot->IsWithinLOSInMap(unit)) + continue; + + if (bot->GetDistance(unit) > aggroRange) + continue; + + float newdistance = bot->GetDistance(unit); + if (!result || (newdistance < distance)) + { + distance = newdistance; + result = unit; + } + } + + return result; +} diff --git a/src/Ai/Base/Value/AggressiveTargetValue.h b/src/Ai/Base/Value/AggressiveTargetValue.h new file mode 100644 index 00000000..61b4d695 --- /dev/null +++ b/src/Ai/Base/Value/AggressiveTargetValue.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license, you may redistribute it + * and/or modify it under version 3 of the License, or (at your option), any later version. + */ + +#ifndef _PLAYERBOT_AGGRESSIVETARGETVALUE_H +#define _PLAYERBOT_AGGRESSIVETARGETVALUE_H + +#include "TargetValue.h" + +class PlayerbotAI; +class Unit; + +class AggressiveTargetValue : public TargetValue +{ +public: + AggressiveTargetValue(PlayerbotAI* botAI, std::string const name = "aggressive target") : TargetValue(botAI, name) {} + + Unit* Calculate() override; +}; + +#endif diff --git a/src/Ai/Base/ValueContext.h b/src/Ai/Base/ValueContext.h index 115294bd..6038db3b 100644 --- a/src/Ai/Base/ValueContext.h +++ b/src/Ai/Base/ValueContext.h @@ -7,6 +7,7 @@ #define _PLAYERBOT_VALUECONTEXT_H #include "ActiveSpellValue.h" +#include "AggressiveTargetValue.h" #include "AlwaysLootListValue.h" #include "AoeHealValues.h" #include "AoeValues.h" @@ -144,6 +145,7 @@ public: creators["pet target"] = &ValueContext::pet_target; creators["old target"] = &ValueContext::old_target; creators["grind target"] = &ValueContext::grind_target; + creators["aggressive target"] = &ValueContext::aggressive_target; creators["rti target"] = &ValueContext::rti_target; creators["rti cc target"] = &ValueContext::rti_cc_target; creators["duel target"] = &ValueContext::duel_target; @@ -459,6 +461,7 @@ private: static UntypedValue* current_cc_target(PlayerbotAI* botAI) { return new CurrentCcTargetValue(botAI); } static UntypedValue* pet_target(PlayerbotAI* botAI) { return new PetTargetValue(botAI); } static UntypedValue* grind_target(PlayerbotAI* botAI) { return new GrindTargetValue(botAI); } + static UntypedValue* aggressive_target(PlayerbotAI* botAI) { return new AggressiveTargetValue(botAI); } static UntypedValue* rti_target(PlayerbotAI* botAI) { return new RtiTargetValue(botAI); } static UntypedValue* rti_cc_target(PlayerbotAI* botAI) { return new RtiCcTargetValue(botAI); } static UntypedValue* duel_target(PlayerbotAI* botAI) { return new DuelTargetValue(botAI); }