Merge branch 'liyunfan1223:master' into master

This commit is contained in:
fuzzdeveloper
2024-07-05 00:06:24 +10:00
committed by GitHub
25 changed files with 215 additions and 72 deletions

View File

@@ -6,6 +6,8 @@ Welcome to the Playerbots Module for AzerothCore, a work in progress project bas
If you encounter any errors or experience crashes, we kindly request that you report them as GitHub issues. Your valuable feedback will help us improve and enhance this project collaboratively.
You can also get more information in our [discord](https://discord.gg/NQm5QShwf9).
## Installation
Please note that this module requires specific custom changes to AzerothCore. To ensure compatibility, you must compile it with a custom branch from my fork, which can be found here: [liyunfan1223/azerothcore-wotlk/tree/Playerbot](https://github.com/liyunfan1223/azerothcore-wotlk/tree/Playerbot).
@@ -48,7 +50,9 @@ It's essential to note that there is still a significant amount of work to be do
## Addon
For enhanced control over the bots and to simplify command usage, you can also make use of our addon: [Unbot Addon](https://github.com/liyunfan1223/unbot-addon). Currently, this addon offers better support only for Simplified Chinese client.
For enhanced control over the bots and to simplify command usage, you can also make use of our addon:
- Chinese version: [Unbot Addon (zh)](https://github.com/liyunfan1223/unbot-addon).
- English version (maintained by @Revision): [Unbot Addon (en)](https://github.com/noisiver/unbot-addon/tree/english).
## Frequently Asked Questions

View File

@@ -97,6 +97,10 @@ AiPlayerbot.SummonWhenGroup = 1
AiPlayerbot.RandomBotShowHelmet = 1
AiPlayerbot.RandomBotShowCloak = 1
# Fix the level of random bot (won't level up by grinding)
# Default: 0 (disable)
AiPlayerbot.RandomBotFixedLevel = 0
# Disable random levels for randombots
# Every bots started on the specified level and level up by killing mobs.
AiPlayerbot.DisableRandomLevels = 0
@@ -125,7 +129,7 @@ AiPlayerbot.MinEnchantingBotLevel = 60
AiPlayerbot.LimitEnchantExpansion = 1
# Randombots checking players gear score level and deny the group invite if it's too low
# Default: 1 (enabled)
# Default: 0 (disabled)
AiPlayerbot.GearScoreCheck = 0
# Quest that will be completed and rewarded to all random bots
@@ -338,8 +342,8 @@ AiPlayerbot.AutoSaveMana = 1
AiPlayerbot.SaveManaThreshold = 60
# Enable auto avoid aoe (experimental)
# Default: 0 (disable)
AiPlayerbot.AutoAvoidAoe = 0
# Default: 1 (enable)
AiPlayerbot.AutoAvoidAoe = 1
# Tell which spell is avoiding (experimental)
# Default: 1 (enable)

View File

@@ -91,7 +91,7 @@ bool PlayerbotAIConfig::Initialize()
mediumMana = sConfigMgr->GetOption<int32>("AiPlayerbot.MediumMana", 40);
autoSaveMana = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoSaveMana", true);
saveManaThreshold = sConfigMgr->GetOption<int32>("AiPlayerbot.SaveManaThreshold", 60);
autoAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoAvoidAoe", false);
autoAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoAvoidAoe", true);
tellWhenAvoidAoe = sConfigMgr->GetOption<bool>("AiPlayerbot.TellWhenAvoidAoe", true);
randomGearLoweringChance = sConfigMgr->GetOption<float>("AiPlayerbot.RandomGearLoweringChance", 0.15f);
@@ -265,6 +265,7 @@ bool PlayerbotAIConfig::Initialize()
// SPP switches
enableGreet = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableGreet", true);
summonWhenGroup = sConfigMgr->GetOption<bool>("AiPlayerbot.SummonWhenGroup", true);
randomBotFixedLevel = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotFixedLevel", false);
disableRandomLevels = sConfigMgr->GetOption<bool>("AiPlayerbot.DisableRandomLevels", false);
randomBotRandomPassword = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotRandomPassword", true);
downgradeMaxLevelBot = sConfigMgr->GetOption<bool>("AiPlayerbot.DowngradeMaxLevelBot", true);

View File

@@ -174,6 +174,7 @@ class PlayerbotAIConfig
bool summonWhenGroup;
bool randomBotShowHelmet;
bool randomBotShowCloak;
bool randomBotFixedLevel;
bool disableRandomLevels;
uint32 playerbotsXPrate;
bool disableDeathKnightLogin;

View File

@@ -2502,8 +2502,7 @@ void PlayerbotFactory::InitAmmo()
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
subClass = ITEM_SUBCLASS_ARROW;
break;
case ITEM_SUBCLASS_WEAPON_THROWN:
subClass = ITEM_SUBCLASS_THROWN;
default:
break;
}
@@ -2512,7 +2511,7 @@ void PlayerbotFactory::InitAmmo()
uint32 entry = sRandomItemMgr->GetAmmo(level, subClass);
uint32 count = bot->GetItemCount(entry);
uint32 maxCount = 5000;
uint32 maxCount = 6000;
if (count < maxCount / 2)
{
@@ -3879,10 +3878,9 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot)
score *= 0.1;
}
// spec with double hand
// fury with titan's grip, fury without duel wield, arms, bear, retribution, blood dk
// fury without duel wield, arms, bear, retribution, blood dk
if (isDoubleHand &&
((cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && bot->CanTitanGrip()) ||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !bot->CanDualWield()) ||
((cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !bot->CanDualWield()) ||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) ||
(cls == CLASS_DRUID && tab == 1) ||
(cls == CLASS_PALADIN && tab == 2) ||
@@ -3890,6 +3888,11 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot)
(cls == CLASS_SHAMAN && tab == 1 && !bot->CanDualWield()))) {
score *= 10;
}
// fury with titan's grip
if (isDoubleHand && proto->SubClass != ITEM_SUBCLASS_WEAPON_POLEARM &&
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && bot->CanTitanGrip())) {
score *= 10;
}
}
if (proto->Class == ITEM_CLASS_WEAPON) {
if (cls == CLASS_HUNTER && proto->SubClass == ITEM_SUBCLASS_WEAPON_THROWN) {

View File

@@ -448,6 +448,12 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
uint32 accountId = bot->GetSession()->GetAccountId();
bool isRandomAccount = sPlayerbotAIConfig->IsInRandomAccountList(accountId);
if (isRandomAccount && sPlayerbotAIConfig->randomBotFixedLevel) {
bot->SetPlayerFlag(PLAYER_FLAGS_NO_XP_GAIN);
} else if (isRandomAccount && !sPlayerbotAIConfig->randomBotFixedLevel) {
bot->RemovePlayerFlag(PLAYER_FLAGS_NO_XP_GAIN);
}
bot->SaveToDB(false, false);
if (master && isRandomAccount && master->GetLevel() < bot->GetLevel()) {
// PlayerbotFactory factory(bot, master->getLevel());

View File

@@ -2159,6 +2159,9 @@ void RandomItemMgr::BuildEquipCacheNew()
if (IsTestItem(itemId)) {
continue;
}
if (itemId == 22784) { // Sunwell Orb
continue;
}
equipCacheNew[proto->RequiredLevel][proto->InventoryType].push_back(itemId);
}
}
@@ -2199,9 +2202,7 @@ RandomItemList RandomItemMgr::Query(uint32 level, uint8 clazz, uint8 slot, uint3
void RandomItemMgr::BuildAmmoCache()
{
uint32 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel;
if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
LOG_INFO("server.loading", "Building ammo cache for {} levels", maxLevel);
@@ -2238,9 +2239,9 @@ uint32 RandomItemMgr::GetAmmo(uint32 level, uint32 subClass)
void RandomItemMgr::BuildPotionCache()
{
uint32 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel;
if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
// if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
// maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
LOG_INFO("server.loading", "Building potion cache for {} levels", maxLevel);

View File

@@ -1191,6 +1191,10 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
if (!zone)
continue;
AreaTableEntry const* area = sAreaTableStore.LookupEntry(map->GetAreaId(bot->GetPhaseMask(), x, y, z));
if (!area)
continue;
// Do not teleport to enemy zones if level is low
if (zone->team == 4 && bot->GetTeamId() == TEAM_ALLIANCE)
continue;
@@ -1218,9 +1222,14 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
if (bot->GetLevel() <= 18 && (loc.GetMapId() != pInfo->mapId || dis > 10000.0f)) {
continue;
}
LocaleConstant locale = sWorld->GetDefaultDbcLocale();
LOG_INFO("playerbots", "Random teleporting bot {} (level {}) to {} {},{},{} ({}/{} locations)",
bot->GetName().c_str(), bot->GetLevel(), zone->area_name[0], x, y, z, i + 1, tlocs.size());
LOG_INFO("playerbots", "Random teleporting bot {} (level {}) to Map: {} ({}) Zone: {} ({}) Area: {} ({}) {},{},{} ({}/{} locations)",
bot->GetName().c_str(), bot->GetLevel(),
map->GetId(), map->GetMapName(),
zone->ID, zone->area_name[locale],
area->ID, area->area_name[locale],
x, y, z, i + 1, tlocs.size());
if (hearth)
{
@@ -1248,9 +1257,7 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
void RandomPlayerbotMgr::PrepareTeleportCache()
{
uint8 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel;
if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
LOG_INFO("playerbots", "Preparing random teleport caches for {} levels...", maxLevel);

View File

@@ -1495,6 +1495,8 @@ void TravelTarget::setStatus(TravelStatus status)
break;
case TRAVEL_STATUS_COOLDOWN:
statusTime = tDestination->getCooldownDelay();
default:
break;
}
}
@@ -3687,7 +3689,7 @@ void TravelMgr::LoadQuestTravelTable()
}
}
else
"all";
out << "all";
out << "\n";
}

View File

@@ -144,7 +144,7 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal)
ActionBasket* basket = nullptr;
time_t currentTime = time(nullptr);
aiObjectContext->Update();
// aiObjectContext->Update();
ProcessTriggers(minimal);
PushDefaultActions();
@@ -469,7 +469,7 @@ bool Engine::HasStrategy(std::string const name)
void Engine::ProcessTriggers(bool minimal)
{
std::unordered_map<Trigger*, Event> fires;
// std::unordered_map<Trigger*, Event> fires;
for (std::vector<TriggerNode*>::iterator i = triggers.begin(); i != triggers.end(); i++)
{
TriggerNode* node = *i;
@@ -499,21 +499,22 @@ void Engine::ProcessTriggers(bool minimal)
if (!event)
continue;
fires[trigger] = event;
// fires[trigger] = event;
LogAction("T:%s", trigger->getName().c_str());
}
}
for (std::vector<TriggerNode*>::iterator i = triggers.begin(); i != triggers.end(); i++)
{
TriggerNode* node = *i;
Trigger* trigger = node->getTrigger();
Event event = fires[trigger];
if (!event)
continue;
MultiplyAndPush(node->getHandlers(), 0.0f, false, event, "trigger");
}
}
// for (std::vector<TriggerNode*>::iterator i = triggers.begin(); i != triggers.end(); i++)
// {
// TriggerNode* node = *i;
// Trigger* trigger = node->getTrigger();
// if (fires.find(trigger) == fires.end())
// continue;
// Event event = fires[trigger];
// }
for (std::vector<TriggerNode*>::iterator i = triggers.begin(); i != triggers.end(); i++)
{

View File

@@ -23,10 +23,15 @@ bool ChangeTalentsAction::Execute(Event event)
if (param.find("help") != std::string::npos) {
out << TalentsHelp();
} else if (param.find("switch") != std::string::npos) {
if (param.find("switch 1")) {
if (param.find("switch 1") != std::string::npos) {
bot->ActivateSpec(0);
out << "Active first talent";
} else if (param.find("switch 2")) {
} else if (param.find("switch 2") != std::string::npos) {
if (bot->GetSpecsCount() == 1 && bot->GetLevel() >= sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL))
{
bot->CastSpell(bot, 63680, true, nullptr, nullptr, bot->GetGUID());
bot->CastSpell(bot, 63624, true, nullptr, nullptr, bot->GetGUID());
}
bot->ActivateSpec(1);
out << "Active second talent";
}

View File

@@ -115,6 +115,7 @@ class ChatActionContext : public NamedObjectContext<Action>
creators["de"] = &ChatActionContext::dead;
creators["trainer"] = &ChatActionContext::trainer;
creators["maintenance"] = &ChatActionContext::maintenance;
creators["remove glyph"] = &ChatActionContext::remove_glyph;
creators["autogear"] = &ChatActionContext::autogear;
creators["equip upgrade"] = &ChatActionContext::equip_upgrade;
creators["attack my target"] = &ChatActionContext::attack_my_target;
@@ -215,6 +216,7 @@ class ChatActionContext : public NamedObjectContext<Action>
static Action* attack_my_target(PlayerbotAI* botAI) { return new AttackMyTargetAction(botAI); }
static Action* trainer(PlayerbotAI* botAI) { return new TrainerAction(botAI); }
static Action* maintenance(PlayerbotAI* botAI) { return new MaintenanceAction(botAI); }
static Action* remove_glyph(PlayerbotAI* botAI) { return new RemoveGlyphAction(botAI); }
static Action* autogear(PlayerbotAI* botAI) { return new AutoGearAction(botAI); }
static Action* equip_upgrade(PlayerbotAI* botAI) { return new EquipUpgradeAction(botAI); }
static Action* co(PlayerbotAI* botAI) { return new ChangeCombatStrategyAction(botAI); }

View File

@@ -33,6 +33,7 @@ bool FollowChatShortcutAction::Execute(Event event)
botAI->Reset();
botAI->ChangeStrategy("+follow,-passive,-grind", BOT_STATE_NON_COMBAT);
botAI->ChangeStrategy("-follow,-passive,-grind", BOT_STATE_COMBAT);
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
PositionInfo pos = posMap["return"];

View File

@@ -1645,34 +1645,107 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
return false;
}
bool AvoidAoeAction::FleePosition(Position pos, float radius, std::string name)
Position AvoidAoeAction::BestPositionForMelee(Position pos, float radius)
{
Unit* currentTarget = AI_VALUE(Unit*, "current target");
std::vector<float> possibleAngles;
std::vector<CheckAngle> possibleAngles;
if (currentTarget) {
// Normally, move to left or right is the best position
float angleLeft = bot->GetAngle(currentTarget) + M_PI / 2;
float angleRight = bot->GetAngle(currentTarget) - M_PI / 2;
possibleAngles.push_back(angleLeft);
possibleAngles.push_back(angleRight);
bool isTanking = (currentTarget->CanFreeMove()) && (currentTarget->GetVictim() == bot);
float angle = bot->GetAngle(currentTarget);
float angleLeft = angle + (float)M_PI / 2;
float angleRight = angle - (float)M_PI / 2;
possibleAngles.push_back({angleLeft, false});
possibleAngles.push_back({angleRight, false});
possibleAngles.push_back({angle, true});
if (isTanking) {
possibleAngles.push_back({angle + (float)M_PI, false});
possibleAngles.push_back({bot->GetAngle(&pos) - (float)M_PI, false});
}
} else {
float angleTo = bot->GetAngle(&pos) - M_PI;
possibleAngles.push_back(angleTo);
float angleTo = bot->GetAngle(&pos) - (float)M_PI;
possibleAngles.push_back({angleTo, false});
}
float farestDis = 0.0f;
Position bestPos;
for (float &angle : possibleAngles) {
for (CheckAngle &checkAngle : possibleAngles) {
float angle = checkAngle.angle;
bool strict = checkAngle.strict;
float fleeDis = sPlayerbotAIConfig->fleeDistance;
Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis,
bot->GetPositionY() + sin(angle) * fleeDis,
bot->GetPositionZ()};
// todo (Yunfan): check carefully
if (strict && currentTarget
&& fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->tooCloseDistance) {
continue;
}
if (pos.GetExactDist(fleePos) > farestDis) {
farestDis = pos.GetExactDist(fleePos);
bestPos = fleePos;
}
}
if (farestDis > 0.0f) {
return bestPos;
}
return Position();
}
Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius)
{
Unit* currentTarget = AI_VALUE(Unit*, "current target");
std::vector<CheckAngle> possibleAngles;
float angleToTarget = 0.0f;
float angleFleeFromCenter = bot->GetAngle(&pos) - (float)M_PI;
if (currentTarget) {
// Normally, move to left or right is the best position
angleToTarget = bot->GetAngle(currentTarget);
float angleLeft = angleToTarget + (float)M_PI / 2;
float angleRight = angleToTarget - (float)M_PI / 2;
possibleAngles.push_back({angleLeft, false});
possibleAngles.push_back({angleRight, false});
possibleAngles.push_back({angleToTarget + (float)M_PI, true});
possibleAngles.push_back({angleToTarget, true});
possibleAngles.push_back({angleFleeFromCenter, true});
} else {
possibleAngles.push_back({angleFleeFromCenter, false});
}
float farestDis = 0.0f;
Position bestPos;
for (CheckAngle &checkAngle : possibleAngles) {
float angle = checkAngle.angle;
bool strict = checkAngle.strict;
float fleeDis = sPlayerbotAIConfig->fleeDistance;
Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis,
bot->GetPositionY() + sin(angle) * fleeDis,
bot->GetPositionZ()};
if (strict && currentTarget
&& fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->spellDistance) {
continue;
}
if (strict && currentTarget
&& fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() < (sPlayerbotAIConfig->tooCloseDistance)) {
continue;
}
if (pos.GetExactDist(fleePos) > farestDis) {
farestDis = pos.GetExactDist(fleePos);
bestPos = fleePos;
}
}
if (farestDis > 0.0f) {
return bestPos;
}
return Position();
}
bool AvoidAoeAction::FleePosition(Position pos, float radius, std::string name)
{
Position bestPos;
if (botAI->IsMelee(bot)) {
bestPos = BestPositionForMelee(pos, radius);
} else {
bestPos = BestPositionForRanged(pos, radius);
}
if (bestPos != Position()) {
if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) {
if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) {
lastTellTimer = time(NULL);

View File

@@ -78,11 +78,14 @@ class AvoidAoeAction : public MovementAction
bool AvoidAuraWithDynamicObj();
bool AvoidGameObjectWithDamage();
bool AvoidUnitWithDamageAura();
// Position PositionForTank(Position pos, float radius);
// Position PositionForMelee(Position pos, float radius);
// Position PositionForRanged(Position pos, float radius);
Position BestPositionForMelee(Position pos, float radius);
Position BestPositionForRanged(Position pos, float radius);
bool FleePosition(Position pos, float radius, std::string name);
time_t lastTellTimer = 0;
struct CheckAngle {
float angle;
bool strict;
};
};
class RunAwayAction : public MovementAction

View File

@@ -175,6 +175,15 @@ bool MaintenanceAction::Execute(Event event)
return true;
}
bool RemoveGlyphAction::Execute(Event event)
{
for (uint32 slotIndex = 0; slotIndex < MAX_GLYPH_SLOT_INDEX; ++slotIndex)
{
bot->SetGlyph(slotIndex, 0, true);
}
return true;
}
bool AutoGearAction::Execute(Event event)
{
if (!sPlayerbotAIConfig->autoGearCommand) {

View File

@@ -35,6 +35,13 @@ class MaintenanceAction : public Action
bool Execute(Event event) override;
};
class RemoveGlyphAction : public Action
{
public:
RemoveGlyphAction(PlayerbotAI* botAI) : Action(botAI, "remove glyph") { }
bool Execute(Event event) override;
};
class AutoGearAction : public Action
{
public:

View File

@@ -81,8 +81,10 @@ bool SummonAction::Execute(Event event)
pet->GetCharmInfo()->IsReturning();
}
if (master->GetSession()->GetSecurity() >= SEC_PLAYER)
if (master->GetSession()->GetSecurity() >= SEC_PLAYER) {
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
return Teleport(master, bot);
}
if (SummonUsingGos(master, bot) || SummonUsingNpcs(master, bot))
{

View File

@@ -4,6 +4,7 @@
#include "XpGainAction.h"
#include "Event.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
bool XpGainAction::Execute(Event event)

View File

@@ -89,6 +89,7 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas
supported.push_back("de");
supported.push_back("trainer");
supported.push_back("maintenance");
supported.push_back("remove glyph");
supported.push_back("autogear");
supported.push_back("equip upgrade");
supported.push_back("chat");

View File

@@ -55,6 +55,7 @@ class ChatTriggerContext : public NamedObjectContext<Trigger>
creators["de"] = &ChatTriggerContext::dead;
creators["trainer"] = &ChatTriggerContext::trainer;
creators["maintenance"] = &ChatTriggerContext::maintenance;
creators["remove glyph"] = &ChatTriggerContext::remove_glyph;
creators["autogear"] = &ChatTriggerContext::autogear;
creators["equip upgrade"] = &ChatTriggerContext::equip_upgrade;
creators["attack"] = &ChatTriggerContext::attack;
@@ -168,6 +169,7 @@ class ChatTriggerContext : public NamedObjectContext<Trigger>
static Trigger* attack(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "attack"); }
static Trigger* trainer(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "trainer"); }
static Trigger* maintenance(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "maintenance"); }
static Trigger* remove_glyph(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "remove glyph"); }
static Trigger* autogear(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "autogear"); }
static Trigger* equip_upgrade(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "equip upgrade"); }
static Trigger* co(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "co"); }

View File

@@ -125,7 +125,8 @@ Aura* AreaDebuffValue::Calculate()
Unit::AuraEffectList const& aurasPeriodicDamagePercent = bot->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
Unit::AuraEffectList const& aurasPeriodicTriggerSpell = bot->GetAuraEffectsByType(SPELL_AURA_PERIODIC_TRIGGER_SPELL);
Unit::AuraEffectList const& aurasPeriodicTriggerWithValueSpell = bot->GetAuraEffectsByType(SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE);
for (const Unit::AuraEffectList& list : {aurasPeriodicDamage, aurasPeriodicDamagePercent, aurasPeriodicTriggerSpell, aurasPeriodicTriggerWithValueSpell}) {
Unit::AuraEffectList const& aurasDummy = bot->GetAuraEffectsByType(SPELL_AURA_DUMMY);
for (const Unit::AuraEffectList& list : {aurasPeriodicDamage, aurasPeriodicDamagePercent, aurasPeriodicTriggerSpell, aurasPeriodicTriggerWithValueSpell, aurasDummy}) {
for (auto i = list.begin(); i != list.end(); ++i)
{
AuraEffect* aurEff = *i;

View File

@@ -104,7 +104,7 @@ void AttackersValue::RemoveNonThreating(std::unordered_set<Unit*>& targets)
for(std::unordered_set<Unit *>::iterator tIter = targets.begin(); tIter != targets.end();)
{
Unit* unit = *tIter;
if(bot->GetMapId() != unit->GetMapId() || !hasRealThreat(unit) || !IsValidTarget(unit, bot) || !bot->IsWithinLOSInMap(unit))
if(bot->GetMapId() != unit->GetMapId() || !hasRealThreat(unit) || !IsValidTarget(unit, bot))
{
std::unordered_set<Unit *>::iterator tIter2 = tIter;
++tIter;
@@ -113,15 +113,6 @@ void AttackersValue::RemoveNonThreating(std::unordered_set<Unit*>& targets)
else
++tIter;
}
// Unit* unit = *tIter;
// if (!IsValidTarget(unit, bot) || !bot->IsWithinLOSInMap(unit))
// {
// std::unordered_set<Unit*>::iterator tIter2 = tIter;
// ++tIter;
// targets.erase(tIter2);
// }
// else
// ++tIter;
}
bool AttackersValue::hasRealThreat(Unit *attacker)
@@ -160,7 +151,7 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range)
// bool inCannon = botAI->IsInVehicle(false, true);
// bool enemy = botAI->GetAiObjectContext()->GetValue<Unit*>("enemy player target")->Get();
return attacker &&
return attacker && attacker->IsVisible() &&
attacker->IsInWorld() &&
attacker->GetMapId() == bot->GetMapId() &&
!attacker->isDead() &&
@@ -183,10 +174,9 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range)
bool AttackersValue::IsValidTarget(Unit *attacker, Player *bot)
{
return attacker->IsVisible() &&
IsPossibleTarget(attacker, bot) &&
(attacker->GetThreatMgr().getCurrentVictim() || attacker->GetGuidValue(UNIT_FIELD_TARGET) ||
attacker->GetGUID().IsPlayer() || attacker->GetGUID() == GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue<ObjectGuid>("pull target")->Get());
return IsPossibleTarget(attacker, bot) && bot->IsWithinLOSInMap(attacker);
// (attacker->GetThreatMgr().getCurrentVictim() || attacker->GetGuidValue(UNIT_FIELD_TARGET) ||
// attacker->GetGUID().IsPlayer() || attacker->GetGUID() == GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue<ObjectGuid>("pull target")->Get());
}
bool PossibleAddsValue::Calculate()

View File

@@ -71,6 +71,12 @@ class CasterFindTargetSmartStrategy : public FindTargetStrategy
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
{
if (Group* group = botAI->GetBot()->GetGroup())
{
ObjectGuid guid = group->GetTargetIcon(4);
if (guid && attacker->GetGUID() == guid)
return;
}
if (!attacker->IsAlive()) {
return;
}
@@ -138,6 +144,12 @@ class NonCasterFindTargetSmartStrategy : public FindTargetStrategy
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
{
if (Group* group = botAI->GetBot()->GetGroup())
{
ObjectGuid guid = group->GetTargetIcon(4);
if (guid && attacker->GetGUID() == guid)
return;
}
if (!attacker->IsAlive()) {
return;
}
@@ -193,6 +205,12 @@ class ComboFindTargetSmartStrategy : public FindTargetStrategy
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
{
if (Group* group = botAI->GetBot()->GetGroup())
{
ObjectGuid guid = group->GetTargetIcon(4);
if (guid && attacker->GetGUID() == guid)
return;
}
if (!attacker->IsAlive()) {
return;
}

View File

@@ -27,9 +27,7 @@ bool InvalidTargetValue::Calculate()
target->isFeared() ||
target->HasUnitState(UNIT_STATE_ISOLATED) ||
target->IsFriendlyTo(bot) ||
!AttackersValue::IsValidTarget(target, bot) ||
// !bot->IsWithinDistInMap(target, sPlayerbotAIConfig->sightDistance) ||
!bot->IsWithinLOSInMap(target);
!AttackersValue::IsValidTarget(target, bot);
}
return !target;