mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
tank target, formation arrow, mount fix, miscs
This commit is contained in:
@@ -489,10 +489,10 @@ AiPlayerbot.HealDistance = 38.5
|
||||
AiPlayerbot.LootDistance = 15.0
|
||||
AiPlayerbot.FleeDistance = 5.0
|
||||
AiPlayerbot.TooCloseDistance = 5.0
|
||||
AiPlayerbot.MeleeDistance = 1.5
|
||||
AiPlayerbot.MeleeDistance = 0.01
|
||||
AiPlayerbot.FollowDistance = 1.5
|
||||
AiPlayerbot.WhisperDistance = 6000.0
|
||||
AiPlayerbot.ContactDistance = 0.5
|
||||
AiPlayerbot.ContactDistance = 0.01
|
||||
AiPlayerbot.AoeRadius = 10
|
||||
AiPlayerbot.RpgDistance = 200
|
||||
AiPlayerbot.AggroDistance = 22
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "ObjectGuid.h"
|
||||
#include "Playerbots.h"
|
||||
#include "AiFactory.h"
|
||||
#include "BudgetValues.h"
|
||||
@@ -1263,55 +1264,124 @@ void PlayerbotAI::ResetStrategies(bool load)
|
||||
|
||||
bool PlayerbotAI::IsRanged(Player* player)
|
||||
{
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
|
||||
if (botAI && !player->InBattleground())
|
||||
return botAI->ContainsStrategy(STRATEGY_TYPE_RANGED);
|
||||
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
|
||||
if (botAi)
|
||||
return botAi->ContainsStrategy(STRATEGY_TYPE_RANGED);
|
||||
|
||||
int tab = AiFactory::GetPlayerSpecTab(player);
|
||||
switch (player->getClass())
|
||||
{
|
||||
case CLASS_PALADIN:
|
||||
case CLASS_WARRIOR:
|
||||
case CLASS_ROGUE:
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
case CLASS_WARRIOR:
|
||||
case CLASS_ROGUE:
|
||||
return false;
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
if (tab == 1) {
|
||||
return false;
|
||||
case CLASS_DRUID:
|
||||
return !HasAnyAuraOf(player, "cat form", "bear form", "dire bear form", nullptr);
|
||||
}
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
if (tab != 0) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case CLASS_SHAMAN:
|
||||
if (tab == 1) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlayerbotAI::IsTank(Player* player)
|
||||
{
|
||||
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player))
|
||||
return botAI->ContainsStrategy(STRATEGY_TYPE_TANK);
|
||||
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
|
||||
if (botAi)
|
||||
return botAi->ContainsStrategy(STRATEGY_TYPE_TANK);
|
||||
|
||||
int tab = AiFactory::GetPlayerSpecTab(player);
|
||||
switch (player->getClass())
|
||||
{
|
||||
case CLASS_PALADIN:
|
||||
case CLASS_WARRIOR:
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
return true;
|
||||
if (tab == 0) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
if (tab == 1) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CLASS_WARRIOR:
|
||||
if (tab == 2) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
return HasAnyAuraOf(player, "bear form", "dire bear form", nullptr);
|
||||
if (tab == 1 && HasAnyAuraOf(player, "bear form", "dire bear form", "thick hide", NULL)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerbotAI::IsHeal(Player* player)
|
||||
{
|
||||
if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player))
|
||||
return botAI->ContainsStrategy(STRATEGY_TYPE_HEAL);
|
||||
PlayerbotAI* botAi = GET_PLAYERBOT_AI(player);
|
||||
if (botAi)
|
||||
return botAi->ContainsStrategy(STRATEGY_TYPE_HEAL);
|
||||
|
||||
int tab = AiFactory::GetPlayerSpecTab(player);
|
||||
switch (player->getClass())
|
||||
{
|
||||
case CLASS_PRIEST:
|
||||
case CLASS_PRIEST:
|
||||
if (tab == PRIEST_TAB_DISIPLINE || tab == PRIEST_TAB_HOLY) {
|
||||
return true;
|
||||
case CLASS_DRUID:
|
||||
return HasAnyAuraOf(player, "tree of life form", nullptr);
|
||||
}
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
if (tab == DRUID_TAB_RESTORATION) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CLASS_SHAMAN:
|
||||
if (tab == SHAMAN_TAB_RESTORATION) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
if (tab == PALADIN_TAB_HOLY) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerbotAI::IsMainTank(Player* player)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group) {
|
||||
return false;
|
||||
}
|
||||
ObjectGuid mainTank = ObjectGuid();
|
||||
Group::MemberSlotList const& slots = group->GetMemberSlots();
|
||||
for (Group::member_citerator itr = slots.begin(); itr != slots.end(); ++itr) {
|
||||
if (itr->flags & MEMBER_FLAG_MAINTANK)
|
||||
mainTank = itr->guid;
|
||||
}
|
||||
if (mainTank != ObjectGuid::Empty) {
|
||||
return player->GetGUID() == mainTank;
|
||||
}
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) {
|
||||
Player* member = ref->GetSource();
|
||||
if (IsTank(member)) {
|
||||
return player == member;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1987,7 +2057,7 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
||||
{
|
||||
// WorldLocation aoe = aiObjectContext->GetValue<WorldLocation>("aoe position")->Get();
|
||||
// targets.SetDst(aoe);
|
||||
targets.SetDst(*bot);
|
||||
targets.SetDst(*target);
|
||||
}
|
||||
else if (spellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION)
|
||||
{
|
||||
|
||||
@@ -208,6 +208,66 @@ enum BotRoles : uint8
|
||||
BOT_ROLE_DPS = 0x04
|
||||
};
|
||||
|
||||
enum HUNTER_TABS {
|
||||
HUNTER_TAB_BEASTMASTER,
|
||||
HUNTER_TAB_MARKSMANSHIP,
|
||||
HUNTER_TAB_SURVIVAL,
|
||||
};
|
||||
|
||||
enum ROGUE_TABS {
|
||||
ROGUE_TAB_ASSASSINATION,
|
||||
ROGUE_TAB_COMBAT,
|
||||
ROGUE_TAB_SUBTLETY
|
||||
};
|
||||
|
||||
enum PRIEST_TABS {
|
||||
PRIEST_TAB_DISIPLINE,
|
||||
PRIEST_TAB_HOLY,
|
||||
PRIEST_TAB_SHADOW,
|
||||
};
|
||||
|
||||
enum DEATHKNIGT_TABS {
|
||||
DEATHKNIGT_TAB_BLOOD,
|
||||
DEATHKNIGT_TAB_FROST,
|
||||
DEATHKNIGT_TAB_UNHOLY,
|
||||
};
|
||||
|
||||
enum DRUID_TABS {
|
||||
DRUID_TAB_BALANCE,
|
||||
DRUID_TAB_FERAL,
|
||||
DRUID_TAB_RESTORATION,
|
||||
};
|
||||
|
||||
enum MAGE_TABS {
|
||||
MAGE_TAB_ARCANE,
|
||||
MAGE_TAB_FIRE,
|
||||
MAGE_TAB_FROST,
|
||||
};
|
||||
|
||||
enum SHAMAN_TABS {
|
||||
SHAMAN_TAB_ELEMENTAL,
|
||||
SHAMAN_TAB_ENHANCEMENT,
|
||||
SHAMAN_TAB_RESTORATION,
|
||||
};
|
||||
|
||||
enum PALADIN_TABS {
|
||||
PALADIN_TAB_HOLY,
|
||||
PALADIN_TAB_PROTECTION,
|
||||
PALADIN_TAB_RETRIBUTION,
|
||||
};
|
||||
|
||||
enum WARLOCK_TABS {
|
||||
WARLOCK_TAB_AFFLICATION,
|
||||
WARLOCK_TAB_DEMONOLOGY,
|
||||
WARLOCK_TAB_DESTRUCTION,
|
||||
};
|
||||
|
||||
enum WARRIOR_TABS {
|
||||
WARRIOR_TAB_ARMS,
|
||||
WARRIOR_TAB_FURY,
|
||||
WARRIOR_TAB_PROTECTION,
|
||||
};
|
||||
|
||||
class PacketHandlingHelper
|
||||
{
|
||||
public:
|
||||
@@ -270,6 +330,7 @@ class PlayerbotAI : public PlayerbotAIBase
|
||||
bool IsTank(Player* player);
|
||||
bool IsHeal(Player* player);
|
||||
bool IsRanged(Player* player);
|
||||
bool IsMainTank(Player* player);
|
||||
Creature* GetCreature(ObjectGuid guid);
|
||||
Unit* GetUnit(ObjectGuid guid);
|
||||
Player* GetPlayer(ObjectGuid guid);
|
||||
|
||||
@@ -427,6 +427,14 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||
master->GetGroup()->AddMember(bot);
|
||||
}
|
||||
|
||||
uint32 accountId = bot->GetSession()->GetAccountId();
|
||||
bool isRandomAccount = sPlayerbotAIConfig->IsInRandomAccountList(accountId);
|
||||
|
||||
if (master && isRandomAccount) {
|
||||
PlayerbotFactory factory(bot, master->getLevel());
|
||||
factory.Randomize(false);
|
||||
}
|
||||
|
||||
// bots join World chat if not solo oriented
|
||||
if (bot->getLevel() >= 10 && sRandomPlayerbotMgr->IsRandomBot(bot) && GET_PLAYERBOT_AI(bot) && GET_PLAYERBOT_AI(bot)->GetGrouperType() != GrouperType::SOLO)
|
||||
{
|
||||
|
||||
@@ -992,14 +992,14 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
||||
std::vector<WorldPosition> tlocs;
|
||||
for (auto& loc : locs)
|
||||
tlocs.push_back(WorldPosition(loc));
|
||||
LOG_INFO("playerbots", "Locs {} collected.", tlocs.size());
|
||||
// LOG_INFO("playerbots", "Locs {} collected.", tlocs.size());
|
||||
//Do not teleport to maps disabled in config
|
||||
tlocs.erase(std::remove_if(tlocs.begin(), tlocs.end(), [bot](WorldPosition l)
|
||||
{
|
||||
std::vector<uint32>::iterator i = find(sPlayerbotAIConfig->randomBotMaps.begin(), sPlayerbotAIConfig->randomBotMaps.end(), l.getMapId());
|
||||
return i == sPlayerbotAIConfig->randomBotMaps.end();
|
||||
}), tlocs.end());
|
||||
LOG_INFO("playerbots", "Locs {} after disabled in config.", tlocs.size());
|
||||
// LOG_INFO("playerbots", "Locs {} after disabled in config.", tlocs.size());
|
||||
// Check locs again in case all possible locations were removed
|
||||
if (tlocs.empty())
|
||||
{
|
||||
|
||||
@@ -52,6 +52,12 @@ bool CheckMountStateAction::Execute(Event event)
|
||||
return Mount();
|
||||
}
|
||||
|
||||
if (!master->IsMounted() && bot->IsMounted())
|
||||
{
|
||||
WorldPacket emptyPacket;
|
||||
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
|
||||
return true;
|
||||
}
|
||||
// if (!bot->IsMounted() && (chasedistance || (farFromMaster && botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT))) && !bot->IsInCombat() && !dps)
|
||||
// return Mount();
|
||||
|
||||
|
||||
@@ -77,18 +77,18 @@ bool DropTargetAction::Execute(Event event)
|
||||
botAI->InterruptSpell();
|
||||
bot->AttackStop();
|
||||
|
||||
if (Pet* pet = bot->GetPet())
|
||||
{
|
||||
if (CreatureAI* creatureAI = ((Creature*)pet)->AI())
|
||||
{
|
||||
pet->SetReactState(REACT_PASSIVE);
|
||||
pet->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
|
||||
pet->GetCharmInfo()->SetIsCommandFollow(true);
|
||||
pet->AttackStop();
|
||||
pet->GetCharmInfo()->IsReturning();
|
||||
pet->GetMotionMaster()->MoveFollow(bot, PET_FOLLOW_DIST, pet->GetFollowAngle());
|
||||
}
|
||||
}
|
||||
// if (Pet* pet = bot->GetPet())
|
||||
// {
|
||||
// if (CreatureAI* creatureAI = ((Creature*)pet)->AI())
|
||||
// {
|
||||
// pet->SetReactState(REACT_PASSIVE);
|
||||
// pet->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
|
||||
// pet->GetCharmInfo()->SetIsCommandFollow(true);
|
||||
// pet->AttackStop();
|
||||
// pet->GetCharmInfo()->IsReturning();
|
||||
// pet->GetMotionMaster()->MoveFollow(bot, PET_FOLLOW_DIST, pet->GetFollowAngle());
|
||||
// }
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
triggers.push_back(new TriggerNode("loot response", NextAction::array(0, new NextAction("store loot", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("item push result", NextAction::array(0, new NextAction("query item usage", relevance), new NextAction("equip upgrades", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("ready check finished", NextAction::array(0, new NextAction("finish ready check", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("security check", relevance), new NextAction("check mail", relevance), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("security check", relevance), new NextAction("check mail", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("guild invite", NextAction::array(0, new NextAction("guild accept", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("petition offer", NextAction::array(0, new NextAction("petition sign", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("lfg proposal", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr)));
|
||||
|
||||
@@ -18,11 +18,11 @@ bool MediumManaTrigger::IsActive()
|
||||
|
||||
bool NoPetTrigger::IsActive()
|
||||
{
|
||||
return !AI_VALUE(Unit*, "pet target") && !bot->GetGuardianPet() && !AI_VALUE2(bool, "mounted", "self target");
|
||||
return (!AI_VALUE(Unit*, "pet target")) && (!bot->GetGuardianPet()) && (!bot->GetFirstControlled()) && (!AI_VALUE2(bool, "mounted", "self target"));
|
||||
}
|
||||
|
||||
bool HasPetTrigger::IsActive() {
|
||||
return (AI_VALUE(Unit*, "pet target") || bot->GetGuardianPet()) && !AI_VALUE2(bool, "mounted", "self target");;
|
||||
return (AI_VALUE(Unit*, "pet target")) && !AI_VALUE2(bool, "mounted", "self target");;
|
||||
}
|
||||
|
||||
bool HighManaTrigger::IsActive()
|
||||
|
||||
@@ -415,13 +415,13 @@ class NoPetTrigger : public Trigger
|
||||
public:
|
||||
NoPetTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no pet", 5) { }
|
||||
|
||||
bool IsActive() override;
|
||||
virtual bool IsActive() override;
|
||||
};
|
||||
|
||||
class HasPetTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HasPetTrigger(PlayerbotAI* ai) : Trigger(ai, "no pet", 5) {}
|
||||
HasPetTrigger(PlayerbotAI* ai) : Trigger(ai, "has pet", 5) {}
|
||||
|
||||
virtual bool IsActive() override;
|
||||
};
|
||||
|
||||
@@ -19,6 +19,9 @@ WorldLocation ArrowFormation::GetLocationInternal()
|
||||
float offset = 0.f;
|
||||
|
||||
Player* master = botAI->GetMaster();
|
||||
if (!master) {
|
||||
return Formation::NullLocation;
|
||||
}
|
||||
float orientation = master->GetOrientation();
|
||||
MultiLineUnitPlacer placer(orientation);
|
||||
|
||||
@@ -29,7 +32,7 @@ WorldLocation ArrowFormation::GetLocationInternal()
|
||||
melee.PlaceUnits(&placer);
|
||||
melee.Move(-cos(orientation) * offset, -sin(orientation) * offset);
|
||||
|
||||
offset += meleeLines * sPlayerbotAIConfig->followDistance;
|
||||
offset += meleeLines * sPlayerbotAIConfig->followDistance + sPlayerbotAIConfig->tooCloseDistance;
|
||||
ranged.PlaceUnits(&placer);
|
||||
ranged.Move(-cos(orientation) * offset, -sin(orientation) * offset);
|
||||
|
||||
|
||||
@@ -14,11 +14,20 @@ class FindTargetForTankStrategy : public FindNonCcTargetStrategy
|
||||
void CheckAttacker(Unit* creature, ThreatMgr* threatMgr) override
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
if (IsCcTarget(creature))
|
||||
return;
|
||||
|
||||
float threat = threatMgr->GetThreat(bot);
|
||||
if (!result || (minThreat - threat) > 0.1f)
|
||||
if (!result) {
|
||||
minThreat = threat;
|
||||
result = creature;
|
||||
}
|
||||
// neglect if victim is main tank, or no victim (for untauntable target)
|
||||
if (threatMgr->getCurrentVictim()) {
|
||||
// float max_threat = threatMgr->GetThreat(threatMgr->getCurrentVictim()->getTarget());
|
||||
Unit* victim = threatMgr->getCurrentVictim()->getTarget();
|
||||
if (victim && victim->ToPlayer() && botAI->IsMainTank(victim->ToPlayer())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (minThreat >= threat)
|
||||
{
|
||||
minThreat = threat;
|
||||
result = creature;
|
||||
|
||||
Reference in New Issue
Block a user