tank target, formation arrow, mount fix, miscs

This commit is contained in:
Yunfan Li
2023-06-02 15:49:49 +08:00
parent ebfd338af0
commit 25da0af70e
12 changed files with 206 additions and 49 deletions

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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())
{

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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)));

View File

@@ -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()

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -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;