Merge pull request #53 from liyunfan1223/smart_target

Smart target
This commit is contained in:
Yunfan Li
2023-10-27 19:23:54 +08:00
committed by GitHub
51 changed files with 365 additions and 181 deletions

View File

@@ -292,9 +292,9 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
if (tab == 2)
engine->addStrategies("tank", "tank assist", "aoe", "mark rti", nullptr);
else if (player->getLevel() < 30 || tab == 0)
engine->addStrategies("arms", "aoe", "dps assist", "threat", "behind", nullptr);
engine->addStrategies("arms", "aoe", "dps assist", "threat", /*"behind",*/ nullptr);
else
engine->addStrategies("fury", "aoe", "dps assist", "threat", "behind", nullptr);
engine->addStrategies("fury", "aoe", "dps assist", "threat", /*"behind",*/ nullptr);
break;
case CLASS_SHAMAN:
if (tab == 0)
@@ -302,7 +302,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
else if (tab == 2)
engine->addStrategies("heal", "bmana", nullptr);
else
engine->addStrategies("melee", "melee aoe", "bmana", "threat", nullptr);
engine->addStrategies("melee", "melee aoe", "bdps", "threat", nullptr);
engine->addStrategies("dps assist", "cure", "totems", nullptr);
break;
@@ -335,9 +335,9 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
break;
case CLASS_ROGUE:
if (tab == ROGUE_TAB_ASSASSINATION) {
engine->addStrategies("melee", "threat", "dps assist", "aoe", "behind", nullptr);
engine->addStrategies("melee", "threat", "dps assist", "aoe", /*"behind",*/ nullptr);
} else {
engine->addStrategies("dps", "threat", "dps assist", "aoe", "behind", nullptr);
engine->addStrategies("dps", "threat", "dps assist", "aoe", /*"behind",*/ nullptr);
}
break;
case CLASS_WARLOCK:
@@ -436,10 +436,10 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
engine->addStrategies("caster", "caster aoe", nullptr);
if (player->getClass() == CLASS_DRUID && tab == 1)
engine->addStrategies("behind", "dps", nullptr);
engine->addStrategies(/*"behind",*/ "dps", nullptr);
if (player->getClass() == CLASS_ROGUE)
engine->addStrategies("behind", "stealth", nullptr);
engine->addStrategies(/*"behind",*/ "stealth", nullptr);
}
}
@@ -473,10 +473,10 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
nonCombatEngine->addStrategies("bdps", "dps assist", "pet", nullptr);
break;
case CLASS_SHAMAN:
// if (tab == 0 || tab == 2)
nonCombatEngine->addStrategy("bmana");
// else
// nonCombatEngine->addStrategy("bdps");
if (tab == 0 || tab == 2)
nonCombatEngine->addStrategy("bmana");
else
nonCombatEngine->addStrategy("bdps");
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
break;

View File

@@ -1399,6 +1399,19 @@ bool PlayerbotAI::IsRangedDpsAssistantOfIndex(Player* player, int index)
return false;
}
bool PlayerbotAI::HasAggro(Unit* unit)
{
if (!unit) {
return false;
}
bool isMT = IsMainTank(bot);
Unit* victim = unit->GetVictim();
if (victim && (victim->GetGUID() == bot->GetGUID() || (!isMT && victim->ToPlayer() && IsTank(victim->ToPlayer())))) {
return true;
}
return false;
}
int32 PlayerbotAI::GetGroupSlotIndex(Player* player)
{
Group* group = bot->GetGroup();

View File

@@ -338,6 +338,7 @@ class PlayerbotAI : public PlayerbotAIBase
bool IsAssistTankOfIndex(Player* player, int index);
bool IsHealAssistantOfIndex(Player* player, int index);
bool IsRangedDpsAssistantOfIndex(Player* player, int index);
bool HasAggro(Unit* unit);
int32 GetGroupSlotIndex(Player* player);
int32 GetRangedIndex(Player* player);
int32 GetClassIndex(Player* player, uint8_t cls);

View File

@@ -1335,7 +1335,7 @@ void PlayerbotFactory::InitEquipment(bool incremental)
float bestScoreForSlot = -1;
uint32 bestItemForSlot = 0;
for (int attempts = 0; attempts < std::min((int)ids.size(), 25); attempts++)
for (int attempts = 0; attempts < std::max((int)(ids.size() * 0.75), 1); attempts++)
{
uint32 index = urand(0, ids.size() - 1);
uint32 newItemId = ids[index];

View File

@@ -443,7 +443,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
if (master && isRandomAccount && master->GetLevel() < bot->GetLevel()) {
// PlayerbotFactory factory(bot, master->getLevel());
// factory.Randomize(false);
uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(master, false, false, 12) * sPlayerbotAIConfig->autoInitEquipLevelLimitRatio;
uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(master, true, false, 12) * sPlayerbotAIConfig->autoInitEquipLevelLimitRatio;
PlayerbotFactory factory(bot, master->getLevel(), ITEM_QUALITY_LEGENDARY, mixedGearScore);
factory.Randomize(false);
}
@@ -584,14 +584,13 @@ std::string const PlayerbotHolder::ProcessBotCommand(std::string const cmd, Obje
}
else if (cmd == "init=auto")
{
uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(master, false, false, 12) * sPlayerbotAIConfig->autoInitEquipLevelLimitRatio;
uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(master, true, false, 12) * sPlayerbotAIConfig->autoInitEquipLevelLimitRatio;
PlayerbotFactory factory(bot, master->getLevel(), ITEM_QUALITY_LEGENDARY, mixedGearScore);
factory.Randomize(false);
return "ok, gear score limit: " + std::to_string(mixedGearScore / (ITEM_QUALITY_EPIC + 1)) + "(for epic)";
}
else if (cmd.starts_with("init=") && sscanf(cmd.c_str(), "init=%d", &gs) != -1)
{
// uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(master, false, false, 12) * sPlayerbotAIConfig->autoInitEquipLevelLimitRatio;
PlayerbotFactory factory(bot, master->getLevel(), ITEM_QUALITY_LEGENDARY, gs);
factory.Randomize(false);
return "ok, gear score limit: " + std::to_string(gs / (ITEM_QUALITY_EPIC + 1)) + "(for epic)";

View File

@@ -206,11 +206,11 @@ Player* RandomPlayerbotFactory::CreateRandomBot(WorldSession* session, uint8 cls
player->setCinematic(2);
player->SetAtLoginFlag(AT_LOGIN_NONE);
player->SaveToDB(true, false);
if (player->getClass() == CLASS_DEATH_KNIGHT)
{
player->learnSpell(50977, false);
}
// player->SaveToDB(true, false);
// player->RewardQuest(const Quest *quest, uint32 reward, Object *questGiver)
LOG_DEBUG("playerbots", "Random bot created for account {} - name: \"{}\"; race: {}; class: {}", accountId, name.c_str(), race, cls);
@@ -274,12 +274,14 @@ void RandomPlayerbotFactory::CreateRandomBots()
LOG_INFO("playerbots", "Deleting all random bot characters, {} accounts collected...", botAccounts.size());
QueryResult results = LoginDatabase.Query("SELECT id FROM account WHERE username LIKE '{}%%'", sPlayerbotAIConfig->randomBotAccountPrefix.c_str());
int32 deletion_count = 0;
if (results)
{
do
{
Field* fields = results->Fetch();
uint32 accId = fields[0].Get<uint32>();
LOG_INFO("playerbots", "Deleting account accID: {}({})...", accId, ++deletion_count);
AccountMgr::DeleteAccount(accId);
} while (results->NextRow());
}
@@ -288,8 +290,11 @@ void RandomPlayerbotFactory::CreateRandomBots()
CharacterDatabase.Execute("UPDATE playerbots_names SET in_use=0 WHERE in_use=1");
/* TODO(yunfan): we need to sleep here to wait for async account deleted, or the newly account won't be created correctly
the better way is turning the async db operation to sync db operation */
std::this_thread::sleep_for(10ms * sPlayerbotAIConfig->randomBotAccountCount);
LOG_INFO("playerbots", "Random bot characters deleted");
std::this_thread::sleep_for(100ms * sPlayerbotAIConfig->randomBotAccountCount);
LOG_INFO("playerbots", "Random bot characters deleted.");
LOG_INFO("playerbots", "Please reset the AiPlayerbot.DeleteRandomBotAccounts to 0 and restart the server...");
World::StopNow(SHUTDOWN_EXIT_CODE);
return;
}
uint32 totalAccCount = sPlayerbotAIConfig->randomBotAccountCount;
@@ -330,7 +335,7 @@ void RandomPlayerbotFactory::CreateRandomBots()
if (account_creation) {
/* wait for async accounts create to make character create correctly, same as account delete */
std::this_thread::sleep_for(10ms * sPlayerbotAIConfig->randomBotAccountCount);
std::this_thread::sleep_for(100ms * sPlayerbotAIConfig->randomBotAccountCount);
}
LOG_INFO("playerbots", "Creating random bot characters...");

View File

@@ -146,7 +146,8 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal)
time_t currentTime = time(nullptr);
aiObjectContext->Update();
ProcessTriggers(minimal);
PushDefaultActions();
uint32 iterations = 0;
uint32 iterationsPerTick = queue.Size() * (minimal ? 2 : sPlayerbotAIConfig->iterationsPerTick);
do
@@ -265,15 +266,15 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal)
}
while (basket && ++iterations <= iterationsPerTick);
if (!basket)
{
lastRelevance = 0.0f;
PushDefaultActions();
// if (!basket)
// {
// lastRelevance = 0.0f;
// PushDefaultActions();
// prevent the delay after pushing default actions
if (queue.Peek() && depth < 1 && !minimal)
return DoNextAction(unit, depth + 1, minimal);
}
// // prevent the delay after pushing default actions
// if (queue.Peek() && depth < 1 && !minimal)
// return DoNextAction(unit, depth + 1, minimal);
// }
// MEMORY FIX TEST
/*

View File

@@ -23,20 +23,34 @@ enum StrategyType : uint32
STRATEGY_TYPE_MELEE = 64
};
enum ActionPriority
{
ACTION_IDLE = 0,
ACTION_NORMAL = 10,
ACTION_HIGH = 20,
ACTION_MOVE = 30,
ACTION_INTERRUPT = 40,
ACTION_DISPEL = 50,
ACTION_RAID = 60,
ACTION_LIGHT_HEAL = 10,
ACTION_MEDIUM_HEAL = 20,
ACTION_CRITICAL_HEAL = 30,
ACTION_EMERGENCY = 90
};
// enum ActionPriority
// {
// ACTION_IDLE = 0,
// ACTION_DEFAULT = 5,
// ACTION_NORMAL = 10,
// ACTION_HIGH = 20,
// ACTION_MOVE = 30,
// ACTION_INTERRUPT = 40,
// ACTION_DISPEL = 50,
// ACTION_RAID = 60,
// ACTION_LIGHT_HEAL = 10,
// ACTION_MEDIUM_HEAL = 20,
// ACTION_CRITICAL_HEAL = 30,
// ACTION_EMERGENCY = 90
// };
static float ACTION_IDLE = 0.0f;
static float ACTION_DEFAULT = 5.0f;
static float ACTION_NORMAL = 10.0f;
static float ACTION_HIGH = 20.0f;
static float ACTION_MOVE = 30.0f;
static float ACTION_INTERRUPT = 40.0f;
static float ACTION_DISPEL = 50.0f;
static float ACTION_RAID = 60.0f;
static float ACTION_LIGHT_HEAL = 10.0f;
static float ACTION_MEDIUM_HEAL = 20.0f;
static float ACTION_CRITICAL_HEAL = 30.0f;
static float ACTION_EMERGENCY = 90.0f;
class Strategy : public PlayerbotAIAware
{

View File

@@ -9,6 +9,7 @@
#include "ObjectGuid.h"
#include "PathGenerator.h"
#include "PlayerbotAIConfig.h"
#include "Random.h"
#include "SharedDefines.h"
#include "TargetedMovementGenerator.h"
#include "Event.h"
@@ -132,7 +133,7 @@ bool MovementAction::MoveToLOS(WorldObject* target, bool ranged)
return false;
}
bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, bool react)
bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, bool react, bool normal_only)
{
UpdateMovementState();
if (!IsMovingAllowed(mapId, x, y, z)) {
@@ -166,7 +167,11 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
MotionMaster &mm = *bot->GetMotionMaster();
mm.Clear();
mm.MovePoint(mapId, x, y, SearchBestGroundZForPath(x, y, z, generatePath), generatePath);
float modifiedZ = SearchBestGroundZForPath(x, y, z, generatePath, normal_only);
if (modifiedZ == INVALID_HEIGHT) {
return false;
}
mm.MovePoint(mapId, x, y, modifiedZ, generatePath);
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation());
return true;
}
@@ -1253,11 +1258,27 @@ bool MovementAction::MoveAway(Unit* target)
if (!target) {
return false;
}
float angle = target->GetAngle(bot);
float dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance;
float dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance;
float dz = bot->GetPositionZ();
return MoveTo(target->GetMapId(), dx, dy, dz);
float init_angle = target->GetAngle(bot);
for (float delta = 0; delta <= M_PI / 2; delta += M_PI / 8) {
float angle = init_angle + delta;
float dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance;
float dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance;
float dz = bot->GetPositionZ();
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true)) {
return true;
}
if (delta == 0) {
continue;
}
angle = init_angle - delta;
dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance;
dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance;
dz = bot->GetPositionZ();
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true)) {
return true;
}
}
return false;
}
bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float distance)
@@ -1268,7 +1289,7 @@ bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float d
return MoveNear(mapId, x, y, z, distance);
}
float MovementAction::SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range)
float MovementAction::SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range, bool normal_only)
{
if (!generatePath) {
return z;
@@ -1299,6 +1320,9 @@ float MovementAction::SearchBestGroundZForPath(float x, float y, float z, bool g
return modified_z;
}
}
if (normal_only) {
return INVALID_HEIGHT;
}
return z;
}
@@ -1449,14 +1473,15 @@ bool MoveRandomAction::Execute(Event event)
float x = bot->GetPositionX();
float y = bot->GetPositionY();
float z = bot->GetPositionZ();
x += urand(0, distance) - distance / 2;
y += urand(0, distance) - distance / 2;
float angle = (float)rand_norm() * static_cast<float>(M_PI);
x += urand(0, distance) * cos(angle);
y += urand(0, distance) * sin(angle);
bot->UpdateGroundPositionZ(x, y, z);
if (map->IsInWater(bot->GetPhaseMask(), x, y, z, bot->GetCollisionHeight()))
continue;
bool moved = MoveTo(bot->GetMapId(), x, y, z);
bool moved = MoveTo(bot->GetMapId(), x, y, z, false, false, true);
if (moved)
return true;
}

View File

@@ -22,7 +22,7 @@ class MovementAction : public Action
protected:
bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->contactDistance);
bool MoveToLOS(WorldObject* target, bool ranged = false);
bool MoveTo(uint32 mapId, float x, float y, float z, bool idle = false, bool react = false);
bool MoveTo(uint32 mapId, float x, float y, float z, bool idle = false, bool react = false, bool normal_only = false);
bool MoveTo(Unit* target, float distance = 0.0f);
bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig->contactDistance);
float GetFollowAngle();
@@ -41,7 +41,7 @@ class MovementAction : public Action
bool MoveInside(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->followDistance);
void CreateWp(Player* wpOwner, float x, float y, float z, float o, uint32 entry, bool important = false);
private:
float SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range = 10.0f);
float SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range = 10.0f, bool normal_only = false);
};
class FleeAction : public MovementAction

View File

@@ -80,15 +80,15 @@ BloodDKStrategy::BloodDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
NextAction** BloodDKStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("rune strike", ACTION_NORMAL + 8),
new NextAction("icy touch", ACTION_NORMAL + 7),
new NextAction("heart strike", ACTION_NORMAL + 6),
new NextAction("blood strike", ACTION_NORMAL + 5),
new NextAction("dancing rune weapon", ACTION_NORMAL + 4),
new NextAction("death coil", ACTION_NORMAL + 3),
new NextAction("plague strike", ACTION_NORMAL + 2),
new NextAction("horn of winter", ACTION_NORMAL + 1),
new NextAction("melee", ACTION_NORMAL),
new NextAction("rune strike", ACTION_DEFAULT + 0.8f),
new NextAction("icy touch", ACTION_DEFAULT + 0.7f),
new NextAction("heart strike", ACTION_DEFAULT + 0.6f),
new NextAction("blood strike", ACTION_DEFAULT + 0.5f),
new NextAction("dancing rune weapon", ACTION_DEFAULT + 0.4f),
new NextAction("death coil", ACTION_DEFAULT + 0.3f),
new NextAction("plague strike", ACTION_DEFAULT + 0.2f),
new NextAction("horn of winter", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT),
NULL);
}

View File

@@ -78,12 +78,12 @@ FrostDKStrategy::FrostDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
NextAction** FrostDKStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("obliterate", ACTION_NORMAL + 5),
new NextAction("frost strike", ACTION_NORMAL + 4),
new NextAction("obliterate", ACTION_DEFAULT + 0.5f),
new NextAction("frost strike", ACTION_DEFAULT + 0.4f),
// new NextAction("death strike", ACTION_NORMAL + 3),
new NextAction("empower rune weapon", ACTION_NORMAL + 2),
new NextAction("horn of winter", ACTION_NORMAL),
new NextAction("melee", ACTION_NORMAL),
new NextAction("empower rune weapon", ACTION_DEFAULT + 0.2f),
new NextAction("horn of winter", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT),
NULL
);
}

View File

@@ -72,15 +72,15 @@ UnholyDKStrategy::UnholyDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI
NextAction** UnholyDKStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("scourge strike", ACTION_NORMAL + 7),
new NextAction("blood strike", ACTION_NORMAL + 6),
new NextAction("ghoul frenzy", ACTION_NORMAL + 5),
new NextAction("summon gargoyle", ACTION_NORMAL + 4),
new NextAction("death coil", ACTION_NORMAL + 3),
new NextAction("plague strike", ACTION_NORMAL + 2),
new NextAction("icy touch", ACTION_NORMAL + 1),
new NextAction("horn of winter", ACTION_NORMAL),
new NextAction("melee", ACTION_NORMAL),
new NextAction("scourge strike", ACTION_DEFAULT + 0.8f),
new NextAction("blood strike", ACTION_DEFAULT + 0.7f),
new NextAction("ghoul frenzy", ACTION_DEFAULT + 0.6f),
new NextAction("summon gargoyle", ACTION_DEFAULT + 0.5f),
new NextAction("death coil", ACTION_DEFAULT + 0.4f),
new NextAction("plague strike", ACTION_DEFAULT + 0.3f),
new NextAction("icy touch", ACTION_DEFAULT + 0.2f),
new NextAction("horn of winter", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT),
nullptr);
}

View File

@@ -140,12 +140,12 @@ BearTankDruidStrategy::BearTankDruidStrategy(PlayerbotAI* botAI) : FeralDruidStr
NextAction** BearTankDruidStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("mangle (bear)", ACTION_NORMAL + 5),
new NextAction("faerie fire (feral)", ACTION_NORMAL + 4),
new NextAction("lacerate", ACTION_NORMAL + 3),
new NextAction("maul", ACTION_NORMAL + 2),
new NextAction("enrage", ACTION_NORMAL + 1),
new NextAction("melee", ACTION_NORMAL),
new NextAction("mangle (bear)", ACTION_DEFAULT + 0.5f),
new NextAction("faerie fire (feral)", ACTION_DEFAULT + 0.4f),
new NextAction("lacerate", ACTION_DEFAULT + 0.3f),
new NextAction("maul", ACTION_DEFAULT + 0.2f),
new NextAction("enrage", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT),
nullptr);
}

View File

@@ -105,8 +105,8 @@ CasterDruidStrategy::CasterDruidStrategy(PlayerbotAI* botAI) : GenericDruidStrat
NextAction** CasterDruidStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("starfall", ACTION_NORMAL + 2),
new NextAction("wrath", ACTION_NORMAL + 1),
new NextAction("starfall", ACTION_DEFAULT + 0.2f),
new NextAction("wrath", ACTION_DEFAULT + 0.1f),
// new NextAction("starfire", ACTION_NORMAL),
nullptr);
}

View File

@@ -120,7 +120,7 @@ CatDpsDruidStrategy::CatDpsDruidStrategy(PlayerbotAI* botAI) : FeralDruidStrateg
NextAction** CatDpsDruidStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("mangle (cat)", ACTION_NORMAL + 1), nullptr);
return NextAction::array(0, new NextAction("mangle (cat)", ACTION_DEFAULT + 0.1f), nullptr);
}
void CatDpsDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -12,8 +12,8 @@ MeleeDruidStrategy::MeleeDruidStrategy(PlayerbotAI* botAI) : CombatStrategy(botA
NextAction** MeleeDruidStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("faerie fire", ACTION_NORMAL + 1),
new NextAction("melee", ACTION_NORMAL),
new NextAction("faerie fire", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT),
nullptr);
}

View File

@@ -12,9 +12,9 @@ NextAction** GrindingStrategy::getDefaultActions()
void GrindingStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("drink", 7.0f), nullptr)));
triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("food", 6.0f), nullptr)));
triggers.push_back(new TriggerNode("no target", NextAction::array(0, new NextAction("attack anything", 5.0f), nullptr)));
triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("drink", 4.2f), nullptr)));
triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("food", 4.1f), nullptr)));
triggers.push_back(new TriggerNode("no target", NextAction::array(0, new NextAction("attack anything", 4.0f), nullptr)));
}
void MoveRandomStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -26,32 +26,33 @@ RpgStrategy::RpgStrategy(PlayerbotAI* botAI) : Strategy(botAI)
NextAction** RpgStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("rpg", 1.1f), nullptr);
return NextAction::array(0, new NextAction("rpg", 1.0f), nullptr);
}
void RpgStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("no rpg target", NextAction::array(0, new NextAction("choose rpg target", 5.0f), nullptr)));
triggers.push_back(new TriggerNode("no rpg target", NextAction::array(0, new NextAction("move random", 1.10f), NULL)));
triggers.push_back(new TriggerNode("far from rpg target", NextAction::array(0, new NextAction("move to rpg target", 5.0f), nullptr)));
//Sub actions
triggers.push_back(new TriggerNode("rpg", NextAction::array(0, new NextAction("rpg stay", 1.001f), nullptr)));
triggers.push_back(new TriggerNode("rpg", NextAction::array(0, new NextAction("rpg work", 1.001f), nullptr)));
triggers.push_back(new TriggerNode("rpg", NextAction::array(0, new NextAction("rpg emote", 1.001f), nullptr)));
triggers.push_back(new TriggerNode("has rpg target", NextAction::array(0, new NextAction("rpg cancel", 1.001f), nullptr)));
triggers.push_back(new TriggerNode("rpg", NextAction::array(0, new NextAction("rpg stay", 1.101f), nullptr)));
triggers.push_back(new TriggerNode("rpg", NextAction::array(0, new NextAction("rpg work", 1.101f), nullptr)));
triggers.push_back(new TriggerNode("rpg", NextAction::array(0, new NextAction("rpg emote", 1.101f), nullptr)));
triggers.push_back(new TriggerNode("has rpg target", NextAction::array(0, new NextAction("rpg cancel", 1.101f), nullptr)));
// triggers.push_back(new TriggerNode("rpg taxi", NextAction::array(0, new NextAction("rpg taxi", 1.005f), nullptr)));
triggers.push_back(new TriggerNode("rpg discover", NextAction::array(0, new NextAction("rpg discover", 1.110f), nullptr)));
triggers.push_back(new TriggerNode("rpg start quest", NextAction::array(0, new NextAction("rpg start quest", 1.080f), nullptr)));
triggers.push_back(new TriggerNode("rpg end quest", NextAction::array(0, new NextAction("rpg end quest", 1.090f), nullptr)));
triggers.push_back(new TriggerNode("rpg buy", NextAction::array(0, new NextAction("rpg buy", 1.030f), nullptr)));
triggers.push_back(new TriggerNode("rpg discover", NextAction::array(0, new NextAction("rpg discover", 1.210f), nullptr)));
triggers.push_back(new TriggerNode("rpg start quest", NextAction::array(0, new NextAction("rpg start quest", 1.180f), nullptr)));
triggers.push_back(new TriggerNode("rpg end quest", NextAction::array(0, new NextAction("rpg end quest", 1.190f), nullptr)));
triggers.push_back(new TriggerNode("rpg buy", NextAction::array(0, new NextAction("rpg buy", 1.130f), nullptr)));
// triggers.push_back(new TriggerNode("rpg sell", NextAction::array(0, new NextAction("rpg sell", 1.100f), nullptr)));
triggers.push_back(new TriggerNode("rpg repair", NextAction::array(0, new NextAction("rpg repair", 1.095f), nullptr)));
triggers.push_back(new TriggerNode("rpg repair", NextAction::array(0, new NextAction("rpg repair", 1.195f), nullptr)));
// triggers.push_back(new TriggerNode("rpg train", NextAction::array(0, new NextAction("rpg train", 1.080f), nullptr)));
triggers.push_back(new TriggerNode("rpg heal", NextAction::array(0, new NextAction("rpg heal", 1.025f), nullptr)));
triggers.push_back(new TriggerNode("rpg home bind", NextAction::array(0, new NextAction("rpg home bind", 1.060f), nullptr)));
triggers.push_back(new TriggerNode("rpg heal", NextAction::array(0, new NextAction("rpg heal", 1.125f), nullptr)));
triggers.push_back(new TriggerNode("rpg home bind", NextAction::array(0, new NextAction("rpg home bind", 1.160f), nullptr)));
// triggers.push_back(new TriggerNode("rpg queue bg", NextAction::array(0, new NextAction("rpg queue bg", 1.085f), nullptr)));
triggers.push_back(new TriggerNode("rpg buy petition", NextAction::array(0, new NextAction("rpg buy petition", 1.040f), nullptr)));
triggers.push_back(new TriggerNode("rpg use", NextAction::array(0, new NextAction("rpg use", 1.002f), nullptr)));
triggers.push_back(new TriggerNode("rpg buy petition", NextAction::array(0, new NextAction("rpg buy petition", 1.140f), nullptr)));
triggers.push_back(new TriggerNode("rpg use", NextAction::array(0, new NextAction("rpg use", 1.102f), nullptr)));
//triggers.push_back(new TriggerNode("rpg spell", NextAction::array(0, new NextAction("rpg spell", 1.001f), nullptr)));
//triggers.push_back(new TriggerNode("rpg craft", NextAction::array(0, new NextAction("rpg craft", 1.001f), nullptr)));
// triggers.push_back(new TriggerNode("rpg trade useful", NextAction::array(0, new NextAction("rpg trade useful", 1.030f), nullptr)));

View File

@@ -31,13 +31,13 @@ DpsHunterStrategy::DpsHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy
NextAction** DpsHunterStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("kill shot", 16.0f),
new NextAction("chimera shot", 15.0f),
new NextAction("explosive shot", 15.0f),
new NextAction("aimed shot", 14.0f),
new NextAction("arcane shot", 13.0f),
new NextAction("steady shot", 12.0f),
new NextAction("auto shot", 10.0f),
new NextAction("kill shot", ACTION_DEFAULT + 0.6f),
new NextAction("chimera shot", ACTION_DEFAULT + 0.5f),
new NextAction("explosive shot", ACTION_DEFAULT + 0.4f),
new NextAction("aimed shot", ACTION_DEFAULT + 0.3f),
new NextAction("arcane shot", ACTION_DEFAULT + 0.2f),
new NextAction("steady shot", ACTION_DEFAULT + 0.1f),
new NextAction("auto shot", ACTION_DEFAULT),
nullptr);
// return NextAction::array(0, new NextAction("explosive shot", 11.0f), new NextAction("auto shot", 10.0f), new NextAction("auto attack", 9.0f), nullptr);
}
@@ -48,7 +48,7 @@ void DpsHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode("black arrow", NextAction::array(0, new NextAction("black arrow", 15.0f), nullptr)));
triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("viper sting", 23.0f), nullptr)));
triggers.push_back(new TriggerNode("hunter's mark", NextAction::array(0, new NextAction("hunter's mark", 11.0f), nullptr)));
triggers.push_back(new TriggerNode("hunter's mark", NextAction::array(0, new NextAction("hunter's mark", 31.0f), nullptr)));
triggers.push_back(new TriggerNode("concussive shot on snare target", NextAction::array(0, new NextAction("concussive shot", 20.0f), nullptr)));
// triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("call pet", 21.0f), NULL)));
triggers.push_back(new TriggerNode("hunters pet low health", NextAction::array(0, new NextAction("mend pet", 21.0f), NULL)));

View File

@@ -41,7 +41,7 @@ bool CastAutoShotAction::isUseful()
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
return false;
if (bot->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)) {
if (bot->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) && bot->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_targets.GetUnitTargetGUID() == AI_VALUE(Unit*, "current target")->GetGUID()) {
return false;
}
return AI_VALUE(uint32, "active spell") != AI_VALUE2(uint32, "spell id", getName());

View File

@@ -7,6 +7,7 @@
#include "HunterActions.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "SharedDefines.h"
bool HunterAspectOfTheHawkTrigger::IsActive()
{
@@ -77,3 +78,9 @@ bool SwitchToMeleeTrigger::IsActive()
return botAI->HasStrategy("ranged", BOT_STATE_COMBAT) && target && (target->GetVictim() == bot &&
sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f));
}
bool TargetRemoveEnrageTrigger::IsActive()
{
Unit* target = GetTarget();
return target && (botAI->HasAuraToDispel(target, DISPEL_ENRAGE) || botAI->HasAuraToDispel(target, DISPEL_MAGIC));
}

View File

@@ -160,5 +160,6 @@ class TargetRemoveEnrageTrigger : public TargetAuraDispelTrigger
{
public:
TargetRemoveEnrageTrigger(PlayerbotAI* ai) : TargetAuraDispelTrigger(ai, "tranquilizing shot", DISPEL_ENRAGE) {}
bool IsActive() override;
};
#endif

View File

@@ -57,7 +57,10 @@ ArcaneMageStrategy::ArcaneMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy
NextAction** ArcaneMageStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("arcane blast", 10.0f), NULL);
return NextAction::array(0,
new NextAction("arcane blast", ACTION_DEFAULT + 0.1f),
new NextAction("shoot", ACTION_DEFAULT),
NULL);
}
void ArcaneMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -7,7 +7,10 @@
NextAction** FireMageStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("fireball", ACTION_NORMAL + 1), NULL);
return NextAction::array(0,
new NextAction("fireball", ACTION_DEFAULT + 0.1f),
new NextAction("shoot", ACTION_DEFAULT),
NULL);
}
void FireMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -11,7 +11,11 @@ FrostMageStrategy::FrostMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(b
NextAction** FrostMageStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("frostbolt", 7.0f), nullptr);
return NextAction::array(0,
new NextAction("frostbolt", ACTION_DEFAULT + 0.1f),
new NextAction("shoot", ACTION_DEFAULT),
nullptr);
}
void FrostMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -80,11 +80,11 @@ DpsPaladinStrategy::DpsPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStrat
NextAction** DpsPaladinStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("judgement of wisdom", ACTION_NORMAL + 6),
new NextAction("crusader strike", ACTION_NORMAL + 5),
new NextAction("divine storm", ACTION_NORMAL + 4),
new NextAction("consecration", ACTION_NORMAL + 3),
new NextAction("melee", ACTION_NORMAL),
new NextAction("judgement of wisdom", ACTION_DEFAULT + 0.4f),
new NextAction("crusader strike", ACTION_DEFAULT + 0.3f),
new NextAction("divine storm", ACTION_DEFAULT + 0.2f),
new NextAction("consecration", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT),
NULL);
}

View File

@@ -25,7 +25,7 @@ HealPaladinStrategy::HealPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStr
NextAction** HealPaladinStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("judgement of light", ACTION_NORMAL + 2), nullptr);
return NextAction::array(0, new NextAction("judgement of light", ACTION_DEFAULT + 2), nullptr);
}
void HealPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -59,12 +59,12 @@ TankPaladinStrategy::TankPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStr
NextAction** TankPaladinStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("shield of righteousness", ACTION_NORMAL + 6),
new NextAction("hammer of the righteous", ACTION_NORMAL + 5),
new NextAction("judgement of wisdom", ACTION_NORMAL + 4),
new NextAction("shield of righteousness", ACTION_DEFAULT + 0.6f),
new NextAction("hammer of the righteous", ACTION_DEFAULT + 0.5f),
new NextAction("judgement of wisdom", ACTION_DEFAULT + 0.4f),
// new NextAction("avenger's shield", ACTION_NORMAL + 3),
// new NextAction("consecration", ACTION_NORMAL + 2),
new NextAction("melee", ACTION_NORMAL),
new NextAction("melee", ACTION_DEFAULT),
NULL);
}

View File

@@ -13,7 +13,7 @@ HealPriestStrategy::HealPriestStrategy(PlayerbotAI* botAI) : GenericPriestStrate
NextAction** HealPriestStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("shoot", 10.0f), nullptr);
return NextAction::array(0, new NextAction("shoot", ACTION_DEFAULT), nullptr);
}
void HealPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -30,7 +30,7 @@ HolyPriestStrategy::HolyPriestStrategy(PlayerbotAI* botAI) : HealPriestStrategy(
NextAction** HolyPriestStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("smite", 10.0f), new NextAction("mana burn", 9.0f), new NextAction("starshards", 8.0f), nullptr);
return NextAction::array(0, new NextAction("smite", ACTION_DEFAULT + 0.2f), new NextAction("mana burn", ACTION_DEFAULT + 0.1f), new NextAction("starshards", ACTION_DEFAULT), nullptr);
}
void HolyPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -14,10 +14,10 @@ ShadowPriestStrategy::ShadowPriestStrategy(PlayerbotAI* botAI) : GenericPriestSt
NextAction** ShadowPriestStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("mind blast", 13.0f),
new NextAction("mind blast", ACTION_DEFAULT + 0.2f),
// new NextAction("shadow word: death", 12.0f),
new NextAction("mind flay", 11.0f),
// new NextAction("shoot", 10.0f),
new NextAction("mind flay", ACTION_DEFAULT + 0.1f),
new NextAction("shoot", ACTION_DEFAULT),
NULL);
}
@@ -40,7 +40,7 @@ void ShadowPriestAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(new TriggerNode("shadow word: pain on attacker", NextAction::array(0, new NextAction("shadow word: pain on attacker", ACTION_NORMAL + 5), nullptr)));
triggers.push_back(new TriggerNode("vampiric touch on attacker", NextAction::array(0, new NextAction("vampiric touch on attacker", ACTION_NORMAL + 4), nullptr)));
// triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("mind sear", ACTION_HIGH + 4), nullptr)));
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("mind sear", ACTION_HIGH + 4), nullptr)));
}
void ShadowPriestDebuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -35,7 +35,7 @@ AssassinationRogueStrategy::AssassinationRogueStrategy(PlayerbotAI* ai) : MeleeC
NextAction** AssassinationRogueStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("melee", ACTION_NORMAL),
new NextAction("melee", ACTION_DEFAULT),
NULL);
}

View File

@@ -71,8 +71,8 @@ DpsRogueStrategy::DpsRogueStrategy(PlayerbotAI* botAI) : MeleeCombatStrategy(bot
NextAction** DpsRogueStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("killing spree", ACTION_NORMAL + 1),
new NextAction("melee", ACTION_NORMAL), NULL);
new NextAction("killing spree", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT), NULL);
}
void DpsRogueStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -14,16 +14,6 @@ bool CastStealthAction::isPossible()
return !botAI->HasAura(23333, bot) && !botAI->HasAura(23335, bot) && !botAI->HasAura(34976, bot);
}
bool CastStealthAction::Execute(Event event)
{
if (botAI->CastSpell("stealth", bot))
{
// botAI->ChangeStrategy("-dps,+stealthed", BOT_STATE_COMBAT);
}
return true;
}
bool UnstealthAction::Execute(Event event)
{
botAI->RemoveAura("stealth");

View File

@@ -32,7 +32,6 @@ class CastStealthAction : public CastBuffSpellAction
std::string const GetTargetName() override { return "self target"; }
bool isPossible() override;
bool Execute(Event event) override;
};
class UnstealthAction : public Action

View File

@@ -39,8 +39,8 @@ CasterShamanStrategy::CasterShamanStrategy(PlayerbotAI* botAI) : GenericShamanSt
NextAction** CasterShamanStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("lava burst", 11.0f),
new NextAction("lightning bolt", 10.0f),
new NextAction("lava burst", ACTION_DEFAULT + 0.1f),
new NextAction("lightning bolt", ACTION_DEFAULT),
NULL);
}

View File

@@ -4,6 +4,7 @@
#include "HealShamanStrategy.h"
#include "Playerbots.h"
#include "Strategy.h"
class GenericShamanStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
@@ -116,7 +117,7 @@ void GenericShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode("wind shear", NextAction::array(0, new NextAction("wind shear", 23.0f), nullptr)));
triggers.push_back(new TriggerNode("wind shear on enemy healer", NextAction::array(0, new NextAction("wind shear on enemy healer", 23.0f), nullptr)));
triggers.push_back(new TriggerNode("purge", NextAction::array(0, new NextAction("purge", 10.0f), nullptr)));
triggers.push_back(new TriggerNode("purge", NextAction::array(0, new NextAction("purge", ACTION_DISPEL), nullptr)));
// triggers.push_back(new TriggerNode("party member medium health", NextAction::array(0, new NextAction("lesser healing wave on party", 25.0f), nullptr)));
// triggers.push_back(new TriggerNode("party member low health", NextAction::array(0, new NextAction("riptide on party", 25.0f), nullptr)));
// triggers.push_back(new TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("chain heal", 27.0f), nullptr)));

View File

@@ -50,11 +50,11 @@ MeleeShamanStrategy::MeleeShamanStrategy(PlayerbotAI* botAI) : GenericShamanStra
NextAction** MeleeShamanStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("stormstrike", ACTION_NORMAL + 6),
new NextAction("earth shock", ACTION_NORMAL + 5),
new NextAction("fire nova", ACTION_NORMAL + 4),
new NextAction("lava lash", ACTION_NORMAL + 1),
new NextAction("melee", ACTION_NORMAL),
new NextAction("stormstrike", ACTION_DEFAULT + 0.4f),
new NextAction("earth shock", ACTION_DEFAULT + 0.3f),
new NextAction("fire nova", ACTION_DEFAULT + 0.2f),
new NextAction("lava lash", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT),
NULL);
}

View File

@@ -13,7 +13,7 @@ class Unit;
class NeedCureTrigger : public SpellTrigger
{
public:
NeedCureTrigger(PlayerbotAI* botAI, std::string const spell, uint32 dispelType) : SpellTrigger(botAI, spell, 2 * 1000), dispelType(dispelType) { }
NeedCureTrigger(PlayerbotAI* botAI, std::string const spell, uint32 dispelType) : SpellTrigger(botAI, spell, 1 * 1000), dispelType(dispelType) { }
std::string const GetTargetName() override { return "self target"; }
bool IsActive() override;

View File

@@ -406,7 +406,7 @@ bool TankAssistTrigger::IsActive()
if (!tankTarget || currentTarget == tankTarget)
return false;
return currentTarget->GetVictim() == AI_VALUE(Unit*, "self target");
return AI_VALUE2(bool, "has aggro", "current target");
}
bool IsBehindTargetTrigger::IsActive()

View File

@@ -217,7 +217,7 @@ class TriggerContext : public NamedObjectContext<Trigger>
static Trigger* critical_aoe_heal(PlayerbotAI* botAI) { return new AoeHealTrigger(botAI, "critical aoe heal", "critical", 2); }
static Trigger* low_aoe_heal(PlayerbotAI* botAI) { return new AoeHealTrigger(botAI, "low aoe heal", "low", 2); }
static Trigger* medium_aoe_heal(PlayerbotAI* botAI) { return new AoeHealTrigger(botAI, "medium aoe heal", "medium", 2); }
static Trigger* group_heal_occasion(PlayerbotAI* ai) { return new AoeInGroupTrigger(ai, "group heal occasion", "almost full", 0.4); }
static Trigger* group_heal_occasion(PlayerbotAI* ai) { return new AoeInGroupTrigger(ai, "group heal occasion", "almost full", 0.6); }
static Trigger* medium_group_heal_occasion(PlayerbotAI* ai) { return new AoeInGroupTrigger(ai, "group heal occasion", "medium", 0.4); }
static Trigger* target_changed(PlayerbotAI* botAI) { return new TargetChangedTrigger(botAI); }
static Trigger* swimming(PlayerbotAI* botAI) { return new IsSwimmingTrigger(botAI); }

View File

@@ -21,7 +21,8 @@ bool HasAggroValue::Calculate()
if (!victim) {
return true;
}
if (victim && (victim->GetGUID() == bot->GetGUID() || (victim->ToPlayer() && botAI->IsMainTank(victim->ToPlayer())))) {
bool isMT = botAI->IsMainTank(bot);
if (victim && (victim->GetGUID() == bot->GetGUID() || (!isMT && victim->ToPlayer() && botAI->IsTank(victim->ToPlayer())))) {
return true;
}
return false;

View File

@@ -3,6 +3,7 @@
*/
#include "DpsTargetValue.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
class FindLeastHpTargetStrategy : public FindTargetStrategy
@@ -58,13 +59,79 @@ class FindMaxThreatGapTargetStrategy : public FindTargetStrategy
float minThreat;
};
class FindTargetSmartStrategy : public FindTargetStrategy
{
public:
FindTargetSmartStrategy(PlayerbotAI* botAI, float dps) : FindTargetStrategy(botAI), dps_(dps), targetExpectedLifeTime(1000000) { }
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;
}
float expectedLifeTime = attacker->GetHealth() / dps_;
// Unit* victim = attacker->GetVictim();
if (!result || IsBetter(attacker, result)) {
targetExpectedLifeTime = expectedLifeTime;
result = attacker;
}
}
bool IsBetter(Unit* new_unit, Unit* old_unit) {
float new_time = new_unit->GetHealth() / dps_;
float old_time = old_unit->GetHealth() / dps_;
// [5-20] > (5-0] > (20-inf)
if (GetIntervalLevel(new_unit) > GetIntervalLevel(old_unit)) {
return true;
}
int32_t level = GetIntervalLevel(new_unit);
if (level % 10 == 2 || level % 10 == 0) {
return new_time < old_time;
}
// dont switch targets when all of them with low health
Unit* currentTarget = botAI->GetAiObjectContext()->GetValue<Unit*>("current target")->Get();
if (currentTarget == new_unit) {
return true;
}
if (currentTarget == old_unit) {
return false;
}
return new_time > old_time;
}
int32_t GetIntervalLevel(Unit* unit) {
float time = unit->GetHealth() / dps_;
float dis = unit->GetDistance(botAI->GetBot());
float attackRange = botAI->IsRanged(botAI->GetBot()) ? sPlayerbotAIConfig->spellDistance : sPlayerbotAIConfig->meleeDistance;
attackRange += 5.0f;
int level = dis < attackRange ? 10 : 0;
if (time >= 5 && time <= 20) {
return level + 2;
}
if (time < 5) {
return level + 1;
}
return level;
}
protected:
float dps_;
float targetExpectedLifeTime;
};
Unit* DpsTargetValue::Calculate()
{
Unit* rti = RtiTargetValue::Calculate();
if (rti)
return rti;
FindLeastHpTargetStrategy strategy(botAI);
// FindLeastHpTargetStrategy strategy(botAI);
float dps = AI_VALUE(float, "expected group dps");
FindTargetSmartStrategy strategy(botAI, dps);
// FindMaxThreatGapTargetStrategy strategy(botAI);
return TargetValue::FindTarget(&strategy);
}

View File

@@ -21,11 +21,11 @@ float ExpectedGroupDpsValue::Calculate()
float dps_num;
Group* group = bot->GetGroup();
if (!group) {
dps_num = 1;
dps_num = 0.7;
} else {
dps_num = group->GetMembersCount() * 0.7;
}
uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(bot, false, false, 12);
uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(bot, true, false, 12);
// efficiency record based on rare gear level, is there better calculation method?
// float dps_efficiency = 1;
float basic_dps;
@@ -45,7 +45,7 @@ float ExpectedGroupDpsValue::Calculate()
} else if (level <= 70) {
basic_dps = 350 + (level - 60) * 40;
} else {
basic_dps = 750 + (level - 70) * 100;
basic_dps = 750 + (level - 70) * 125;
}
if (level <= 8) {
@@ -59,10 +59,12 @@ float ExpectedGroupDpsValue::Calculate()
} else if (level <= 80) {
basic_gs = (155 + (level - 70) * 4) * 4;
}
float gap = mixedGearScore - basic_gs;
float gs_modifier = (float)mixedGearScore / basic_gs - 1;
gs_modifier = gs_modifier * 3 + 1;
float gs_modifier = (float)mixedGearScore / basic_gs;
if (gs_modifier < 0.5) gs_modifier = 0.5;
if (gs_modifier > 3) gs_modifier = 3;
if (gs_modifier > 4) gs_modifier = 4;
return dps_num * basic_dps * gs_modifier;
}

View File

@@ -3,6 +3,7 @@
*/
#include "AttackersValue.h"
#include "PlayerbotAIConfig.h"
#include "TankTargetValue.h"
#include "Playerbots.h"
@@ -41,8 +42,53 @@ class FindTargetForTankStrategy : public FindNonCcTargetStrategy
float minThreat;
};
class FindTankTargetSmartStrategy : public FindTargetStrategy
{
public:
FindTankTargetSmartStrategy(PlayerbotAI* botAI) : FindTargetStrategy(botAI) { }
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;
}
if (!result || IsBetter(attacker, result)) {
result = attacker;
}
}
bool IsBetter(Unit* new_unit, Unit* old_unit) {
Player* bot = botAI->GetBot();
float new_threat = new_unit->GetThreatMgr().GetThreat(bot);
float old_threat = old_unit->GetThreatMgr().GetThreat(bot);
float new_dis = bot->GetDistance(new_unit);
float old_dis = bot->GetDistance(old_unit);
// hasAggro? -> withinMelee? -> threat
if (GetIntervalLevel(new_unit) > GetIntervalLevel(old_unit)) {
return true;
}
int32_t interval = GetIntervalLevel(new_unit);
if (interval == 1) {
return new_dis < old_dis;
}
return new_threat < old_threat;
}
int32_t GetIntervalLevel(Unit* unit) {
if (!botAI->HasAggro(unit)) {
return 1;
}
return 0;
}
};
Unit* TankTargetValue::Calculate()
{
FindTargetForTankStrategy strategy(botAI);
// FindTargetForTankStrategy strategy(botAI);
FindTankTargetSmartStrategy strategy(botAI);
return FindTarget(&strategy);
}

View File

@@ -47,9 +47,10 @@ DpsWarlockStrategy::DpsWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStrat
NextAction** DpsWarlockStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("haunt", 14.0f),
new NextAction("demonic empowerment", 13.0f),
new NextAction("shadow bolt", 10.0f),
new NextAction("haunt", ACTION_DEFAULT + 0.3f),
new NextAction("demonic empowerment", ACTION_DEFAULT + 0.2f),
new NextAction("shadow bolt", ACTION_DEFAULT + 0.1f),
new NextAction("shoot", ACTION_DEFAULT),
nullptr);
}

View File

@@ -57,7 +57,7 @@ TankWarlockStrategy::TankWarlockStrategy(PlayerbotAI* botAI) : GenericWarlockStr
NextAction** TankWarlockStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("shoot", 10.0f), nullptr);
return NextAction::array(0, new NextAction("shoot", ACTION_DEFAULT), nullptr);
}
void TankWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -32,7 +32,7 @@ ArmsWarriorStrategy::ArmsWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStr
NextAction** ArmsWarriorStrategy::getDefaultActions()
{
return NextAction::array(0, new NextAction("heroic strike", ACTION_NORMAL), nullptr);
return NextAction::array(0, new NextAction("heroic strike", ACTION_DEFAULT), nullptr);
}
void ArmsWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -35,12 +35,12 @@ FuryWarriorStrategy::FuryWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStr
NextAction** FuryWarriorStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("bloodthirst", ACTION_NORMAL + 5),
new NextAction("whirlwind", ACTION_NORMAL + 4),
new NextAction("sunder armor", ACTION_NORMAL + 3),
new NextAction("execute", ACTION_NORMAL + 2),
new NextAction("overpower", ACTION_NORMAL + 1),
new NextAction("melee", ACTION_NORMAL),
new NextAction("bloodthirst", ACTION_DEFAULT + 0.5f),
new NextAction("whirlwind", ACTION_DEFAULT + 0.4f),
new NextAction("sunder armor", ACTION_DEFAULT + 0.3f),
new NextAction("execute", ACTION_DEFAULT + 0.2f),
new NextAction("overpower", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT),
NULL);
}

View File

@@ -43,9 +43,9 @@ TankWarriorStrategy::TankWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStr
NextAction** TankWarriorStrategy::getDefaultActions()
{
return NextAction::array(0,
new NextAction("devastate", ACTION_NORMAL + 2),
new NextAction("revenge", ACTION_NORMAL + 1),
new NextAction("melee", ACTION_NORMAL),
new NextAction("devastate", ACTION_DEFAULT + 0.2f),
new NextAction("revenge", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT),
NULL);
}