mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Performance: Refactored a bunch of functions in Playerbot ai (#865)
* Update PlayerbotAI.h
* Refactored a number of functions in PlayerbotAI.cpp
* Update PlayerbotAI.cpp
* Update PlayerbotAI.cpp - update for commit done
Take
568592f188
into account.
* Missing check for aurEff
* Update PlayerbotAI.cpp
nvm...
* Update PlayerbotAI.cpp
GetAura
* Update PlayerbotAI.cpp
Simplified/Optimized sPlayerbotAIConfig->dynamicReactDelay logic for in-combat.
* Update PlayerbotAI.cpp
Dubass fix
* Update PlayerbotAI.cpp
Fix bots leaving dungeon group,. again.
* Update PlayerbotAI.cpp
* Update PlayerbotAI.cpp - order correction
...Required for proper pet behavior.
* Update PlayerbotAI.cpp - UpdateAIGroupMembership()
Final refactor of helper function as all now works as required.
* Update PlayerbotAI.cpp
FindItemInInventory
* Update PlayerbotAI.h
Added helper functions, correct public -> private
This commit is contained in:
@@ -225,113 +225,47 @@ PlayerbotAI::~PlayerbotAI()
|
|||||||
|
|
||||||
void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
||||||
{
|
{
|
||||||
|
// Handle the AI check delay
|
||||||
if (nextAICheckDelay > elapsed)
|
if (nextAICheckDelay > elapsed)
|
||||||
nextAICheckDelay -= elapsed;
|
nextAICheckDelay -= elapsed;
|
||||||
else
|
else
|
||||||
nextAICheckDelay = 0;
|
nextAICheckDelay = 0;
|
||||||
|
|
||||||
if (!bot || !bot->IsInWorld())
|
// Early return if bot is in invalid state
|
||||||
{
|
if (!bot || !bot->IsInWorld() || !bot->GetSession() || bot->GetSession()->isLogingOut() || bot->IsDuringRemoveFromWorld())
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (!bot->GetSession() || bot->GetSession()->isLogingOut())
|
// Handle cheat options (set bot health and power if cheats are enabled)
|
||||||
{
|
if (bot->IsAlive() && (static_cast<uint32>(GetCheat()) > 0 || static_cast<uint32>(sPlayerbotAIConfig->botCheatMask) > 0))
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (bot->IsDuringRemoveFromWorld())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// if (!GetMaster() || !GetMaster()->IsInWorld() || !GetMaster()->GetSession() ||
|
|
||||||
// GetMaster()->GetSession()->isLogingOut()) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// if (bot->HasUnitMovementFlag(MOVEMENTFLAG_FALLING)) {
|
|
||||||
// bot->Say("Falling!", LANG_UNIVERSAL);
|
|
||||||
// }
|
|
||||||
// if (!bot->HasUnitMovementFlag(MOVEMENTFLAG_FALLING) && bot->GetPositionZ() - bot->GetFloorZ() > 0.1f) {
|
|
||||||
// bot->AddUnitMovementFlag(MOVEMENTFLAG_FALLING);
|
|
||||||
// // bot->GetMotionMaster()->MoveFall();
|
|
||||||
// }
|
|
||||||
// if (bot->HasUnitMovementFlag(MOVEMENTFLAG_FALLING) && bot->GetPositionZ() - bot->GetFloorZ() <= 0.1f) {
|
|
||||||
// bot->RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// bot->RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// bot->SendMovementFlagUpdate();
|
|
||||||
|
|
||||||
// bot->GetMotionMaster()->MoveFall();
|
|
||||||
// if (bot->HasUnitMovementFlag(MOVEMENTFLAG_FALLING)) {
|
|
||||||
// // bot->GetUnitMovementFlags();
|
|
||||||
// bot->Say("falling... flag: " + std::to_string(bot->GetUnitMovementFlags()), LANG_UNIVERSAL);
|
|
||||||
// }
|
|
||||||
// bot->SendMovementFlagUpdate();
|
|
||||||
// float x, y, z;
|
|
||||||
// bot->GetPosition(x, y, z);
|
|
||||||
// bot->UpdateGroundPositionZ(x, y, z);
|
|
||||||
// if (bot->GetPositionZ() - z > 0.1f) {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// wake up if in combat
|
|
||||||
// if (bot->IsInCombat())
|
|
||||||
// {
|
|
||||||
// if (!inCombat)
|
|
||||||
// nextAICheckDelay = 0;
|
|
||||||
// else if (!AllowActivity())
|
|
||||||
// {
|
|
||||||
// if (AllowActivity(ALL_ACTIVITY, true))
|
|
||||||
// nextAICheckDelay = 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// inCombat = true;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// if (inCombat)
|
|
||||||
// nextAICheckDelay = 0;
|
|
||||||
|
|
||||||
// inCombat = false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// force stop if moving but should not
|
|
||||||
// shouldn't stop charging
|
|
||||||
// if (bot->isMoving() && !CanMove() && !bot->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING))
|
|
||||||
// {
|
|
||||||
// bot->StopMoving();
|
|
||||||
// bot->GetMotionMaster()->Clear();
|
|
||||||
// bot->GetMotionMaster()->MoveIdle();
|
|
||||||
// }
|
|
||||||
// cheat options
|
|
||||||
if (bot->IsAlive() && ((uint32)GetCheat() > 0 || (uint32)sPlayerbotAIConfig->botCheatMask > 0))
|
|
||||||
{
|
{
|
||||||
if (HasCheat(BotCheatMask::health))
|
if (HasCheat(BotCheatMask::health))
|
||||||
bot->SetFullHealth();
|
bot->SetFullHealth();
|
||||||
|
|
||||||
if (HasCheat(BotCheatMask::mana) && bot->getPowerType() == POWER_MANA)
|
if (HasCheat(BotCheatMask::mana) && bot->getPowerType() == POWER_MANA)
|
||||||
bot->SetPower(POWER_MANA, bot->GetMaxPower(POWER_MANA));
|
bot->SetPower(POWER_MANA, bot->GetMaxPower(POWER_MANA));
|
||||||
|
|
||||||
if (HasCheat(BotCheatMask::power) && bot->getPowerType() != POWER_MANA)
|
if (HasCheat(BotCheatMask::power) && bot->getPowerType() != POWER_MANA)
|
||||||
bot->SetPower(bot->getPowerType(), bot->GetMaxPower(bot->getPowerType()));
|
bot->SetPower(bot->getPowerType(), bot->GetMaxPower(bot->getPowerType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
AllowActivity();
|
AllowActivity();
|
||||||
|
|
||||||
|
|
||||||
if (!CanUpdateAI())
|
if (!CanUpdateAI())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Handle the current spell
|
||||||
Spell* currentSpell = bot->GetCurrentSpell(CURRENT_GENERIC_SPELL);
|
Spell* currentSpell = bot->GetCurrentSpell(CURRENT_GENERIC_SPELL);
|
||||||
if (!currentSpell)
|
if (!currentSpell)
|
||||||
currentSpell = bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL);
|
currentSpell = bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL);
|
||||||
if (currentSpell && currentSpell->GetSpellInfo() && currentSpell->getState() == SPELL_STATE_PREPARING)
|
|
||||||
|
if (currentSpell)
|
||||||
{
|
{
|
||||||
const SpellInfo* spellInfo = currentSpell->GetSpellInfo();
|
const SpellInfo* spellInfo = currentSpell->GetSpellInfo();
|
||||||
|
if (spellInfo && currentSpell->getState() == SPELL_STATE_PREPARING)
|
||||||
|
{
|
||||||
Unit* spellTarget = currentSpell->m_targets.GetUnitTarget();
|
Unit* spellTarget = currentSpell->m_targets.GetUnitTarget();
|
||||||
// interrupt if target is dead
|
// Interrupt if target is dead or spell can't target dead units
|
||||||
if (spellTarget && !spellTarget->IsAlive() &&
|
if (spellTarget && !spellTarget->IsAlive() && !spellInfo->IsAllowingDeadTarget())
|
||||||
!spellInfo->IsAllowingDeadTarget())
|
|
||||||
{
|
{
|
||||||
InterruptSpell();
|
InterruptSpell();
|
||||||
YieldThread(GetReactDelay());
|
YieldThread(GetReactDelay());
|
||||||
@@ -346,18 +280,21 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
if (!spellInfo->Effects[i].Effect)
|
if (!spellInfo->Effects[i].Effect)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Check if spell is a heal
|
||||||
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_HEAL ||
|
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_HEAL ||
|
||||||
spellInfo->Effects[i].Effect == SPELL_EFFECT_HEAL_MAX_HEALTH ||
|
spellInfo->Effects[i].Effect == SPELL_EFFECT_HEAL_MAX_HEALTH ||
|
||||||
spellInfo->Effects[i].Effect == SPELL_EFFECT_HEAL_MECHANICAL)
|
spellInfo->Effects[i].Effect == SPELL_EFFECT_HEAL_MECHANICAL)
|
||||||
isHeal = true;
|
isHeal = true;
|
||||||
|
|
||||||
|
// Check if spell is single-target
|
||||||
if ((spellInfo->Effects[i].TargetA.GetTarget() && spellInfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_TARGET_ALLY) ||
|
if ((spellInfo->Effects[i].TargetA.GetTarget() && spellInfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_TARGET_ALLY) ||
|
||||||
(spellInfo->Effects[i].TargetB.GetTarget() && spellInfo->Effects[i].TargetB.GetTarget() != TARGET_UNIT_TARGET_ALLY))
|
(spellInfo->Effects[i].TargetB.GetTarget() && spellInfo->Effects[i].TargetB.GetTarget() != TARGET_UNIT_TARGET_ALLY))
|
||||||
{
|
{
|
||||||
isSingleTarget = false;
|
isSingleTarget = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// interrupt if target ally has full health (heal by other member)
|
|
||||||
|
// Interrupt if target ally has full health (heal by other member)
|
||||||
if (isHeal && isSingleTarget && spellTarget && spellTarget->IsFullHealth())
|
if (isHeal && isSingleTarget && spellTarget && spellTarget->IsFullHealth())
|
||||||
{
|
{
|
||||||
InterruptSpell();
|
InterruptSpell();
|
||||||
@@ -365,16 +302,19 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure bot is facing target if necessary
|
||||||
if (spellTarget && !bot->HasInArc(CAST_ANGLE_IN_FRONT, spellTarget) && (spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT))
|
if (spellTarget && !bot->HasInArc(CAST_ANGLE_IN_FRONT, spellTarget) && (spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT))
|
||||||
{
|
{
|
||||||
sServerFacade->SetFacingTo(bot, spellTarget);
|
sServerFacade->SetFacingTo(bot, spellTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for spell cast
|
// Wait for spell cast
|
||||||
YieldThread(GetReactDelay());
|
YieldThread(GetReactDelay());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle transport check delay
|
||||||
if (nextTransportCheck > elapsed)
|
if (nextTransportCheck > elapsed)
|
||||||
nextTransportCheck -= elapsed;
|
nextTransportCheck -= elapsed;
|
||||||
else
|
else
|
||||||
@@ -385,6 +325,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
nextTransportCheck = 1000;
|
nextTransportCheck = 1000;
|
||||||
Transport* newTransport = bot->GetMap()->GetTransportForPos(bot->GetPhaseMask(), bot->GetPositionX(),
|
Transport* newTransport = bot->GetMap()->GetTransportForPos(bot->GetPhaseMask(), bot->GetPositionX(),
|
||||||
bot->GetPositionY(), bot->GetPositionZ(), bot);
|
bot->GetPositionY(), bot->GetPositionZ(), bot);
|
||||||
|
|
||||||
if (newTransport != bot->GetTransport())
|
if (newTransport != bot->GetTransport())
|
||||||
{
|
{
|
||||||
LOG_DEBUG("playerbots", "Bot {} is on a transport", bot->GetName());
|
LOG_DEBUG("playerbots", "Bot {} is on a transport", bot->GetName());
|
||||||
@@ -399,10 +340,26 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bot->InBattleground() && !bot->inRandomLfgDungeon() && bot->GetGroup() && !bot->GetGroup()->isLFGGroup())
|
// Update the bot's group status (moved to helper function)
|
||||||
|
UpdateAIGroupMembership();
|
||||||
|
|
||||||
|
// Update internal AI
|
||||||
|
UpdateAIInternal(elapsed, minimal);
|
||||||
|
YieldThread(GetReactDelay());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function for UpdateAI to check group membership and handle removal if necessary
|
||||||
|
void PlayerbotAI::UpdateAIGroupMembership()
|
||||||
|
{
|
||||||
|
if (!bot || !bot->GetGroup())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Group* group = bot->GetGroup();
|
||||||
|
|
||||||
|
if (!bot->InBattleground() && !bot->inRandomLfgDungeon() && !group->isLFGGroup())
|
||||||
{
|
{
|
||||||
Player* leader = bot->GetGroup()->GetLeader();
|
Player* leader = group->GetLeader();
|
||||||
if (leader && leader != bot) // Checks if the leader is valid and is not the bot itself
|
if (leader && leader != bot) // Ensure the leader is valid and not the bot itself
|
||||||
{
|
{
|
||||||
PlayerbotAI* leaderAI = GET_PLAYERBOT_AI(leader);
|
PlayerbotAI* leaderAI = GET_PLAYERBOT_AI(leader);
|
||||||
if (leaderAI && !leaderAI->IsRealPlayer())
|
if (leaderAI && !leaderAI->IsRealPlayer())
|
||||||
@@ -412,18 +369,21 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (group->isLFGGroup())
|
||||||
if (bot->GetGroup() && bot->GetGroup()->isLFGGroup())
|
|
||||||
{
|
{
|
||||||
bool hasRealPlayer = false;
|
bool hasRealPlayer = false;
|
||||||
for (GroupReference* ref = bot->GetGroup()->GetFirstMember(); ref; ref = ref->next())
|
|
||||||
|
// Iterate over all group members to check if at least one is a real player
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (!member)
|
if (!member)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
PlayerbotAI* memberAI = GET_PLAYERBOT_AI(member);
|
PlayerbotAI* memberAI = GET_PLAYERBOT_AI(member);
|
||||||
if (memberAI && !memberAI->IsRealPlayer())
|
if (memberAI && !memberAI->IsRealPlayer())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
hasRealPlayer = true;
|
hasRealPlayer = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -433,10 +393,6 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
ResetStrategies();
|
ResetStrategies();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool min = minimal;
|
|
||||||
UpdateAIInternal(elapsed, min);
|
|
||||||
YieldThread(GetReactDelay());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal)
|
void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal)
|
||||||
@@ -1307,8 +1263,9 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// change engine if just died
|
// Change engine if just died
|
||||||
if (currentEngine != engines[BOT_STATE_DEAD] && !bot->IsAlive())
|
bool isBotAlive = bot->IsAlive();
|
||||||
|
if (currentEngine != engines[BOT_STATE_DEAD] && !isBotAlive)
|
||||||
{
|
{
|
||||||
bot->StopMoving();
|
bot->StopMoving();
|
||||||
bot->GetMotionMaster()->Clear();
|
bot->GetMotionMaster()->Clear();
|
||||||
@@ -1331,17 +1288,18 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// change engine if just ressed
|
// Change engine if just ressed
|
||||||
if (currentEngine == engines[BOT_STATE_DEAD] && bot->IsAlive())
|
if (currentEngine == engines[BOT_STATE_DEAD] && isBotAlive)
|
||||||
{
|
{
|
||||||
ChangeEngine(BOT_STATE_NON_COMBAT);
|
ChangeEngine(BOT_STATE_NON_COMBAT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if in combat but stick with old data - clear targets
|
// Clear targets if in combat but sticking with old data
|
||||||
if (currentEngine == engines[BOT_STATE_NON_COMBAT] && bot->IsInCombat())
|
if (currentEngine == engines[BOT_STATE_NON_COMBAT] && bot->IsInCombat())
|
||||||
{
|
{
|
||||||
if (aiObjectContext->GetValue<Unit*>("current target")->Get() != nullptr)
|
Unit* currentTarget = aiObjectContext->GetValue<Unit*>("current target")->Get();
|
||||||
|
if (currentTarget != nullptr)
|
||||||
{
|
{
|
||||||
aiObjectContext->GetValue<Unit*>("current target")->Set(nullptr);
|
aiObjectContext->GetValue<Unit*>("current target")->Set(nullptr);
|
||||||
}
|
}
|
||||||
@@ -1367,7 +1325,7 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
if (master)
|
if (master)
|
||||||
masterBotAI = GET_PLAYERBOT_AI(master);
|
masterBotAI = GET_PLAYERBOT_AI(master);
|
||||||
|
|
||||||
// test BG master set
|
// Test BG master set
|
||||||
if ((!master || (masterBotAI && !masterBotAI->IsRealPlayer())) && group)
|
if ((!master || (masterBotAI && !masterBotAI->IsRealPlayer())) && group)
|
||||||
{
|
{
|
||||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
@@ -1375,6 +1333,7 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ideally we want to have the leader as master.
|
// Ideally we want to have the leader as master.
|
||||||
Player* newMaster = botAI->GetGroupMaster();
|
Player* newMaster = botAI->GetGroupMaster();
|
||||||
Player* playerMaster = nullptr;
|
Player* playerMaster = nullptr;
|
||||||
@@ -1385,20 +1344,7 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||||
{
|
{
|
||||||
Player* member = gref->GetSource();
|
Player* member = gref->GetSource();
|
||||||
|
if (!member || member == bot || member == newMaster || !member->IsInWorld() || !member->IsInSameRaidWith(bot))
|
||||||
if (!member)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (member == bot)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (member == newMaster)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!member->IsInWorld())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!member->IsInSameRaidWith(bot))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
PlayerbotAI* memberBotAI = GET_PLAYERBOT_AI(member);
|
PlayerbotAI* memberBotAI = GET_PLAYERBOT_AI(member);
|
||||||
@@ -1410,37 +1356,19 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// same BG
|
// Same BG checks (optimize checking conditions here)
|
||||||
if (bot->InBattleground() && bot->GetBattleground() &&
|
if (bot->InBattleground() && bot->GetBattleground() &&
|
||||||
bot->GetBattleground()->GetBgTypeID() == BATTLEGROUND_AV && !GET_PLAYERBOT_AI(member) &&
|
bot->GetBattleground()->GetBgTypeID() == BATTLEGROUND_AV && !GET_PLAYERBOT_AI(member) &&
|
||||||
member->InBattleground() && bot->GetMapId() == member->GetMapId())
|
member->InBattleground() && bot->GetMapId() == member->GetMapId())
|
||||||
{
|
{
|
||||||
// TODO disable move to objective if have master in bg
|
// Skip if same BG but same subgroup or lower level
|
||||||
|
if (!group->SameSubGroup(bot, member) || member->GetLevel() < bot->GetLevel())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!group->SameSubGroup(bot, member))
|
// Follow real player only if higher honor points
|
||||||
continue;
|
|
||||||
|
|
||||||
if (member->GetLevel() < bot->GetLevel())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// follow real player only if he has more honor/arena points
|
|
||||||
if (bot->GetBattleground()->isArena())
|
|
||||||
{
|
|
||||||
if (group->IsLeader(member->GetGUID()))
|
|
||||||
{
|
|
||||||
playerMaster = member;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint32 honorpts = member->GetHonorPoints();
|
uint32 honorpts = member->GetHonorPoints();
|
||||||
if (bot->GetHonorPoints() && honorpts < bot->GetHonorPoints())
|
if (bot->GetHonorPoints() && honorpts < bot->GetHonorPoints())
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
playerMaster = member;
|
playerMaster = member;
|
||||||
continue;
|
continue;
|
||||||
@@ -1450,7 +1378,6 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
newMaster = member;
|
newMaster = member;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1474,15 +1401,15 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
|
|
||||||
if (master && master->IsInWorld())
|
if (master && master->IsInWorld())
|
||||||
{
|
{
|
||||||
if (master->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING) &&
|
float distance = sServerFacade->GetDistance2d(bot, master);
|
||||||
sServerFacade->GetDistance2d(bot, master) < 20.0f)
|
if (master->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING) && distance < 20.0f)
|
||||||
bot->m_movementInfo.AddMovementFlag(MOVEMENTFLAG_WALKING);
|
bot->m_movementInfo.AddMovementFlag(MOVEMENTFLAG_WALKING);
|
||||||
else
|
else
|
||||||
bot->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_WALKING);
|
bot->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_WALKING);
|
||||||
|
|
||||||
if (master->IsSitState() && nextAICheckDelay < 1000)
|
if (master->IsSitState() && nextAICheckDelay < 1000)
|
||||||
{
|
{
|
||||||
if (!bot->isMoving() && sServerFacade->GetDistance2d(bot, master) < 10.0f)
|
if (!bot->isMoving() && distance < 10.0f)
|
||||||
bot->SetStandState(UNIT_STAND_STATE_SIT);
|
bot->SetStandState(UNIT_STAND_STATE_SIT);
|
||||||
}
|
}
|
||||||
else if (nextAICheckDelay < 1000)
|
else if (nextAICheckDelay < 1000)
|
||||||
@@ -1500,51 +1427,6 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
bot->RemoveAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED);
|
bot->RemoveAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED);
|
||||||
bot->RemoveAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED);
|
bot->RemoveAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (bot->IsFlying() && !bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) &&
|
|
||||||
// !bot->HasAuraType(SPELL_AURA_FLY))
|
|
||||||
// {
|
|
||||||
// if (bot->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FLYING))
|
|
||||||
// bot->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FLYING);
|
|
||||||
|
|
||||||
// if (bot->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY))
|
|
||||||
// bot->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_CAN_FLY);
|
|
||||||
|
|
||||||
// if (bot->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY))
|
|
||||||
// bot->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/*
|
|
||||||
// land after kncokback/jump
|
|
||||||
if (bot->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING))
|
|
||||||
{
|
|
||||||
// stop movement
|
|
||||||
bot->StopMoving();
|
|
||||||
bot->GetMotionMaster()->Clear();
|
|
||||||
bot->GetMotionMaster()->MoveIdle();
|
|
||||||
|
|
||||||
// remove moveFlags
|
|
||||||
bot->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FALLING);
|
|
||||||
bot->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_PENDING_STOP);
|
|
||||||
|
|
||||||
// set jump destination
|
|
||||||
bot->m_movementInfo.pos = !GetJumpDestination().m_positionZ == 0 ? GetJumpDestination() :
|
|
||||||
bot->GetPosition(); bot->m_movementInfo.jump = MovementInfo::JumpInfo();
|
|
||||||
|
|
||||||
WorldPacket land(MSG_MOVE_FALL_LAND);
|
|
||||||
land << bot->GetGUID().WriteAsPacked();
|
|
||||||
bot->m_mover->BuildMovementPacket(&land);
|
|
||||||
bot->GetSession()->HandleMovementOpcodes(land);
|
|
||||||
|
|
||||||
// move stop
|
|
||||||
WorldPacket stop(MSG_MOVE_STOP);
|
|
||||||
stop << bot->GetGUID().WriteAsPacked();
|
|
||||||
bot->m_mover->BuildMovementPacket(&stop);
|
|
||||||
bot->GetSession()->HandleMovementOpcodes(stop);
|
|
||||||
|
|
||||||
ResetJumpDestination();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotAI::ReInitCurrentEngine()
|
void PlayerbotAI::ReInitCurrentEngine()
|
||||||
@@ -1835,33 +1717,28 @@ bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index)
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Group::MemberSlotList const& slots = group->GetMemberSlots();
|
Group::MemberSlotList const& slots = group->GetMemberSlots();
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (group->IsAssistant(member->GetGUID()) && IsHeal(member))
|
|
||||||
|
if (IsHeal(member)) // Check if the member is a healer
|
||||||
{
|
{
|
||||||
if (index == counter)
|
bool isAssistant = group->IsAssistant(member->GetGUID());
|
||||||
{
|
|
||||||
return player == member;
|
// Check if the index matches for both assistant and non-assistant healers
|
||||||
}
|
if ((isAssistant && index == counter) || (!isAssistant && index == counter))
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// not enough
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (!group->IsAssistant(member->GetGUID()) && IsHeal(member))
|
|
||||||
{
|
|
||||||
if (index == counter)
|
|
||||||
{
|
{
|
||||||
return player == member;
|
return player == member;
|
||||||
}
|
}
|
||||||
|
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1872,33 +1749,28 @@ bool PlayerbotAI::IsRangedDpsAssistantOfIndex(Player* player, int index)
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Group::MemberSlotList const& slots = group->GetMemberSlots();
|
Group::MemberSlotList const& slots = group->GetMemberSlots();
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (group->IsAssistant(member->GetGUID()) && IsRangedDps(member))
|
|
||||||
|
if (IsRangedDps(member)) // Check if the member is a ranged DPS
|
||||||
{
|
{
|
||||||
if (index == counter)
|
bool isAssistant = group->IsAssistant(member->GetGUID());
|
||||||
{
|
|
||||||
return player == member;
|
// Check the index for both assistant and non-assistant ranges
|
||||||
}
|
if ((isAssistant && index == counter) || (!isAssistant && index == counter))
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// not enough
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (!group->IsAssistant(member->GetGUID()) && IsRangedDps(member))
|
|
||||||
{
|
|
||||||
if (index == counter)
|
|
||||||
{
|
{
|
||||||
return player == member;
|
return player == member;
|
||||||
}
|
}
|
||||||
|
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2744,44 +2616,50 @@ bool PlayerbotAI::HasAura(std::string const name, Unit* unit, bool maxStack, boo
|
|||||||
|
|
||||||
std::wstring wnamepart;
|
std::wstring wnamepart;
|
||||||
if (!Utf8toWStr(name, wnamepart))
|
if (!Utf8toWStr(name, wnamepart))
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
wstrToLower(wnamepart);
|
wstrToLower(wnamepart);
|
||||||
|
|
||||||
int auraAmount = 0;
|
int auraAmount = 0;
|
||||||
|
|
||||||
|
// Iterate through all aura types
|
||||||
for (uint32 auraType = SPELL_AURA_BIND_SIGHT; auraType < TOTAL_AURAS; auraType++)
|
for (uint32 auraType = SPELL_AURA_BIND_SIGHT; auraType < TOTAL_AURAS; auraType++)
|
||||||
{
|
{
|
||||||
Unit::AuraEffectList const& auras = unit->GetAuraEffectsByType((AuraType)auraType);
|
Unit::AuraEffectList const& auras = unit->GetAuraEffectsByType((AuraType)auraType);
|
||||||
if (auras.empty())
|
if (auras.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Iterate through each aura effect
|
||||||
for (AuraEffect const* aurEff : auras)
|
for (AuraEffect const* aurEff : auras)
|
||||||
{
|
{
|
||||||
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
|
if (!aurEff)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
|
||||||
|
if (!spellInfo)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Check if the aura name matches
|
||||||
std::string_view const auraName = spellInfo->SpellName[0];
|
std::string_view const auraName = spellInfo->SpellName[0];
|
||||||
if (auraName.empty() || auraName.length() != wnamepart.length() || !Utf8FitTo(auraName, wnamepart))
|
if (auraName.empty() || auraName.length() != wnamepart.length() || !Utf8FitTo(auraName, wnamepart))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Check if this is a valid aura for the bot
|
||||||
if (IsRealAura(bot, aurEff, unit))
|
if (IsRealAura(bot, aurEff, unit))
|
||||||
{
|
{
|
||||||
if (checkIsOwner && aurEff)
|
// Check caster if necessary
|
||||||
{
|
if (checkIsOwner && aurEff->GetCasterGUID() != bot->GetGUID())
|
||||||
if (aurEff->GetCasterGUID() != bot->GetGUID())
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (checkDuration && aurEff)
|
// Check aura duration if necessary
|
||||||
{
|
if (checkDuration && aurEff->GetBase()->GetDuration() == -1)
|
||||||
if (aurEff->GetBase()->GetDuration() == -1)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
// Count stacks and charges
|
||||||
uint32 maxStackAmount = spellInfo->StackAmount;
|
uint32 maxStackAmount = spellInfo->StackAmount;
|
||||||
uint32 maxProcCharges = spellInfo->ProcCharges;
|
uint32 maxProcCharges = spellInfo->ProcCharges;
|
||||||
|
|
||||||
|
// Count the aura based on max stack and proc charges
|
||||||
if (maxStack)
|
if (maxStack)
|
||||||
{
|
{
|
||||||
if (maxStackAmount && aurEff->GetBase()->GetStackAmount() >= maxStackAmount)
|
if (maxStackAmount && aurEff->GetBase()->GetStackAmount() >= maxStackAmount)
|
||||||
@@ -2794,12 +2672,15 @@ bool PlayerbotAI::HasAura(std::string const name, Unit* unit, bool maxStack, boo
|
|||||||
{
|
{
|
||||||
auraAmount++;
|
auraAmount++;
|
||||||
}
|
}
|
||||||
if (maxAuraAmount < 0)
|
|
||||||
return auraAmount > 0;
|
// Early exit if maxAuraAmount is reached
|
||||||
|
if (maxAuraAmount < 0 && auraAmount > 0)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return based on the maximum aura amount conditions
|
||||||
if (maxAuraAmount >= 0)
|
if (maxAuraAmount >= 0)
|
||||||
{
|
{
|
||||||
return auraAmount == maxAuraAmount || (auraAmount > 0 && auraAmount <= maxAuraAmount);
|
return auraAmount == maxAuraAmount || (auraAmount > 0 && auraAmount <= maxAuraAmount);
|
||||||
@@ -2824,6 +2705,8 @@ bool PlayerbotAI::HasAura(uint32 spellId, Unit const* unit)
|
|||||||
// return false;
|
// return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SAW
|
||||||
|
|
||||||
Aura* PlayerbotAI::GetAura(std::string const name, Unit* unit, bool checkIsOwner, bool checkDuration, int checkStack)
|
Aura* PlayerbotAI::GetAura(std::string const name, Unit* unit, bool checkIsOwner, bool checkDuration, int checkStack)
|
||||||
{
|
{
|
||||||
if (!unit)
|
if (!unit)
|
||||||
@@ -2835,7 +2718,7 @@ Aura* PlayerbotAI::GetAura(std::string const name, Unit* unit, bool checkIsOwner
|
|||||||
|
|
||||||
wstrToLower(wnamepart);
|
wstrToLower(wnamepart);
|
||||||
|
|
||||||
for (uint32 auraType = SPELL_AURA_BIND_SIGHT; auraType < TOTAL_AURAS; auraType++)
|
for (uint32 auraType = SPELL_AURA_BIND_SIGHT; auraType < TOTAL_AURAS; ++auraType)
|
||||||
{
|
{
|
||||||
Unit::AuraEffectList const& auras = unit->GetAuraEffectsByType((AuraType)auraType);
|
Unit::AuraEffectList const& auras = unit->GetAuraEffectsByType((AuraType)auraType);
|
||||||
if (auras.empty())
|
if (auras.empty())
|
||||||
@@ -2844,38 +2727,30 @@ Aura* PlayerbotAI::GetAura(std::string const name, Unit* unit, bool checkIsOwner
|
|||||||
for (AuraEffect const* aurEff : auras)
|
for (AuraEffect const* aurEff : auras)
|
||||||
{
|
{
|
||||||
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
|
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
|
||||||
|
std::string const& auraName = spellInfo->SpellName[0];
|
||||||
|
|
||||||
std::string const auraName = spellInfo->SpellName[0];
|
// Directly skip if name mismatch (both length and content)
|
||||||
if (auraName.empty() || auraName.length() != wnamepart.length() || !Utf8FitTo(auraName, wnamepart))
|
if (auraName.empty() || auraName.length() != wnamepart.length() || !Utf8FitTo(auraName, wnamepart))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (IsRealAura(bot, aurEff, unit))
|
if (!IsRealAura(bot, aurEff, unit))
|
||||||
{
|
|
||||||
if (checkIsOwner && aurEff)
|
|
||||||
{
|
|
||||||
if (aurEff->GetCasterGUID() != bot->GetGUID())
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (checkDuration && aurEff)
|
// Check owner if necessary
|
||||||
{
|
if (checkIsOwner && aurEff->GetCasterGUID() != bot->GetGUID())
|
||||||
if (aurEff->GetBase()->GetDuration() == -1)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkStack != -1 && aurEff)
|
// Check duration if necessary
|
||||||
{
|
if (checkDuration && aurEff->GetBase()->GetDuration() == -1)
|
||||||
if (aurEff->GetBase()->GetStackAmount() < checkStack)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
// Check stack if necessary
|
||||||
|
if (checkStack != -1 && aurEff->GetBase()->GetStackAmount() < checkStack)
|
||||||
|
continue;
|
||||||
|
|
||||||
return aurEff->GetBase();
|
return aurEff->GetBase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -2889,15 +2764,14 @@ bool PlayerbotAI::HasAnyAuraOf(Unit* player, ...)
|
|||||||
va_start(vl, player);
|
va_start(vl, player);
|
||||||
|
|
||||||
const char* cur;
|
const char* cur;
|
||||||
do
|
while ((cur = va_arg(vl, const char*)) != nullptr)
|
||||||
{
|
{
|
||||||
cur = va_arg(vl, const char*);
|
if (HasAura(cur, player))
|
||||||
if (cur && HasAura(cur, player))
|
|
||||||
{
|
{
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} while (cur);
|
}
|
||||||
|
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
return false;
|
return false;
|
||||||
@@ -4285,7 +4159,6 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// In bg queue. Speed up bg queue/join.
|
// In bg queue. Speed up bg queue/join.
|
||||||
if (bot->InBattlegroundQueue())
|
if (bot->InBattlegroundQueue())
|
||||||
{
|
{
|
||||||
@@ -4937,124 +4810,62 @@ void PlayerbotAI::Ping(float x, float y)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find Poison ...Natsukawa
|
// Helper function to iterate through items in the inventory and bags
|
||||||
|
Item* PlayerbotAI::FindItemInInventory(std::function<bool(ItemTemplate const*)> checkItem) const
|
||||||
|
{
|
||||||
|
// List out items in the main backpack
|
||||||
|
for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; ++slot)
|
||||||
|
{
|
||||||
|
if (Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
||||||
|
{
|
||||||
|
ItemTemplate const* pItemProto = pItem->GetTemplate();
|
||||||
|
if (pItemProto && bot->CanUseItem(pItemProto) == EQUIP_ERR_OK && checkItem(pItemProto))
|
||||||
|
return pItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List out items in other removable backpacks
|
||||||
|
for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag)
|
||||||
|
{
|
||||||
|
if (Bag const* const pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag))
|
||||||
|
{
|
||||||
|
for (uint8 slot = 0; slot < pBag->GetBagSize(); ++slot)
|
||||||
|
{
|
||||||
|
if (Item* const pItem = bot->GetItemByPos(bag, slot))
|
||||||
|
{
|
||||||
|
ItemTemplate const* pItemProto = pItem->GetTemplate();
|
||||||
|
if (pItemProto && bot->CanUseItem(pItemProto) == EQUIP_ERR_OK && checkItem(pItemProto))
|
||||||
|
return pItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find Poison
|
||||||
Item* PlayerbotAI::FindPoison() const
|
Item* PlayerbotAI::FindPoison() const
|
||||||
{
|
{
|
||||||
// list out items in main backpack
|
return FindItemInInventory([](ItemTemplate const* pItemProto) -> bool {
|
||||||
for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; slot++)
|
return pItemProto->Class == ITEM_CLASS_CONSUMABLE && pItemProto->SubClass == 6;
|
||||||
{
|
});
|
||||||
if (Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
|
||||||
{
|
|
||||||
ItemTemplate const* pItemProto = pItem->GetTemplate();
|
|
||||||
if (!pItemProto || bot->CanUseItem(pItemProto) != EQUIP_ERR_OK)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (pItemProto->Class == ITEM_CLASS_CONSUMABLE && pItemProto->SubClass == 6)
|
|
||||||
return pItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// list out items in other removable backpacks
|
|
||||||
for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag)
|
|
||||||
{
|
|
||||||
if (Bag const* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag))
|
|
||||||
{
|
|
||||||
for (uint8 slot = 0; slot < pBag->GetBagSize(); ++slot)
|
|
||||||
{
|
|
||||||
if (Item* const pItem = bot->GetItemByPos(bag, slot))
|
|
||||||
{
|
|
||||||
ItemTemplate const* pItemProto = pItem->GetTemplate();
|
|
||||||
if (!pItemProto || bot->CanUseItem(pItemProto) != EQUIP_ERR_OK)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (pItemProto->Class == ITEM_CLASS_CONSUMABLE &&
|
|
||||||
pItemProto->SubClass == ITEM_SUBCLASS_ITEM_ENHANCEMENT)
|
|
||||||
return pItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find Consumable
|
||||||
Item* PlayerbotAI::FindConsumable(uint32 displayId) const
|
Item* PlayerbotAI::FindConsumable(uint32 displayId) const
|
||||||
{
|
{
|
||||||
// list out items in main backpack
|
return FindItemInInventory([displayId](ItemTemplate const* pItemProto) -> bool {
|
||||||
for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; slot++)
|
return (pItemProto->Class == ITEM_CLASS_CONSUMABLE || pItemProto->Class == ITEM_CLASS_TRADE_GOODS) && pItemProto->DisplayInfoID == displayId;
|
||||||
{
|
});
|
||||||
if (Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
|
||||||
{
|
|
||||||
ItemTemplate const* pItemProto = pItem->GetTemplate();
|
|
||||||
if (!pItemProto || bot->CanUseItem(pItemProto) != EQUIP_ERR_OK)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((pItemProto->Class == ITEM_CLASS_CONSUMABLE || pItemProto->Class == ITEM_CLASS_TRADE_GOODS) &&
|
|
||||||
pItemProto->DisplayInfoID == displayId)
|
|
||||||
return pItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// list out items in other removable backpacks
|
|
||||||
for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag)
|
|
||||||
{
|
|
||||||
if (Bag const* const pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag))
|
|
||||||
{
|
|
||||||
for (uint8 slot = 0; slot < pBag->GetBagSize(); ++slot)
|
|
||||||
{
|
|
||||||
if (Item* const pItem = bot->GetItemByPos(bag, slot))
|
|
||||||
{
|
|
||||||
ItemTemplate const* pItemProto = pItem->GetTemplate();
|
|
||||||
if (!pItemProto || bot->CanUseItem(pItemProto) != EQUIP_ERR_OK)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((pItemProto->Class == ITEM_CLASS_CONSUMABLE || pItemProto->Class == ITEM_CLASS_TRADE_GOODS) &&
|
|
||||||
pItemProto->DisplayInfoID == displayId)
|
|
||||||
return pItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find Bandage
|
||||||
Item* PlayerbotAI::FindBandage() const
|
Item* PlayerbotAI::FindBandage() const
|
||||||
{
|
{
|
||||||
// list out items in main backpack
|
return FindItemInInventory([](ItemTemplate const* pItemProto) -> bool {
|
||||||
for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; slot++)
|
return pItemProto->Class == ITEM_CLASS_CONSUMABLE && pItemProto->SubClass == ITEM_SUBCLASS_BANDAGE;
|
||||||
{
|
});
|
||||||
if (Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
|
||||||
{
|
|
||||||
ItemTemplate const* pItemProto = pItem->GetTemplate();
|
|
||||||
if (!pItemProto || bot->CanUseItem(pItemProto) != EQUIP_ERR_OK)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (pItemProto->Class == ITEM_CLASS_CONSUMABLE && pItemProto->SubClass == ITEM_SUBCLASS_BANDAGE)
|
|
||||||
return pItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// list out items in other removable backpacks
|
|
||||||
for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag)
|
|
||||||
{
|
|
||||||
if (Bag const* const pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag))
|
|
||||||
{
|
|
||||||
for (uint8 slot = 0; slot < pBag->GetBagSize(); ++slot)
|
|
||||||
{
|
|
||||||
if (Item* const pItem = bot->GetItemByPos(bag, slot))
|
|
||||||
{
|
|
||||||
ItemTemplate const* pItemProto = pItem->GetTemplate();
|
|
||||||
if (!pItemProto || bot->CanUseItem(pItemProto) != EQUIP_ERR_OK)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (pItemProto->Class == ITEM_CLASS_CONSUMABLE && pItemProto->SubClass == ITEM_SUBCLASS_BANDAGE)
|
|
||||||
return pItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint32 uPriorizedSharpStoneIds[8] = {ADAMANTITE_SHARPENING_DISPLAYID, FEL_SHARPENING_DISPLAYID,
|
static const uint32 uPriorizedSharpStoneIds[8] = {ADAMANTITE_SHARPENING_DISPLAYID, FEL_SHARPENING_DISPLAYID,
|
||||||
@@ -6057,53 +5868,66 @@ std::set<uint32> PlayerbotAI::GetCurrentIncompleteQuestIds()
|
|||||||
|
|
||||||
uint32 PlayerbotAI::GetReactDelay()
|
uint32 PlayerbotAI::GetReactDelay()
|
||||||
{
|
{
|
||||||
uint32 base = sPlayerbotAIConfig->reactDelay;
|
uint32 base = sPlayerbotAIConfig->reactDelay; // Default 100(ms)
|
||||||
// old calculate method
|
|
||||||
|
// If dynamic react delay is disabled, use a static calculation
|
||||||
if (!sPlayerbotAIConfig->dynamicReactDelay)
|
if (!sPlayerbotAIConfig->dynamicReactDelay)
|
||||||
{
|
{
|
||||||
inCombat = bot->IsInCombat();
|
if (HasRealPlayerMaster())
|
||||||
bool min = false;
|
return base;
|
||||||
// test fix lags because of BG
|
|
||||||
bool inBG = bot->InBattleground() || bot->InArena();
|
|
||||||
if (bot && !inCombat)
|
|
||||||
min = true;
|
|
||||||
|
|
||||||
if (HasRealPlayerMaster() || (sPlayerbotAIConfig->fastReactInBG && inBG))
|
bool inBG = bot->InBattleground() || bot->InArena();
|
||||||
min = false;
|
if (sPlayerbotAIConfig->fastReactInBG && inBG)
|
||||||
if (min)
|
return base;
|
||||||
return base * 10;
|
|
||||||
|
bool inCombat = bot->IsInCombat();
|
||||||
|
|
||||||
|
if (!inCombat)
|
||||||
|
return base * 10.0f;
|
||||||
|
|
||||||
|
else if (inCombat)
|
||||||
|
return base * 2.5f;
|
||||||
|
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
float multiplier = 1.0f;
|
// Dynamic react delay calculation:
|
||||||
|
|
||||||
if (HasRealPlayerMaster())
|
if (HasRealPlayerMaster())
|
||||||
|
return base;
|
||||||
|
|
||||||
|
float multiplier = 1.0f;
|
||||||
|
bool inBG = bot->InBattleground() || bot->InArena();
|
||||||
|
|
||||||
|
if (inBG)
|
||||||
{
|
{
|
||||||
multiplier = 1.0f;
|
if (bot->IsInCombat() || currentState == BOT_STATE_COMBAT)
|
||||||
|
{
|
||||||
|
multiplier = sPlayerbotAIConfig->fastReactInBG ? 2.5f : 5.0f;
|
||||||
return base * multiplier;
|
return base * multiplier;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
bool inBg = bot->InBattleground() || bot->InArena();
|
|
||||||
if (inBg)
|
|
||||||
{
|
{
|
||||||
multiplier = sPlayerbotAIConfig->fastReactInBG ? 1.0f : 10.0f;
|
multiplier = sPlayerbotAIConfig->fastReactInBG ? 1.0f : 10.0f;
|
||||||
return base * multiplier;
|
return base * multiplier;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When in combat, return 5 times the base
|
||||||
if (bot->IsInCombat() || currentState == BOT_STATE_COMBAT)
|
if (bot->IsInCombat() || currentState == BOT_STATE_COMBAT)
|
||||||
{
|
{
|
||||||
multiplier = 5.0f;
|
multiplier = 5.0f;
|
||||||
return base * multiplier;
|
return base * multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isResting = bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
|
// When not resting, return 10-30 times the base
|
||||||
if (!isResting)
|
if (!bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING))
|
||||||
{
|
{
|
||||||
multiplier = urand(10, 30);
|
multiplier = urand(10, 30);
|
||||||
return base * multiplier;
|
return base * multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In other cases, return 20-200 times the base
|
||||||
multiplier = urand(20, 200);
|
multiplier = urand(20, 200);
|
||||||
return base * multiplier;
|
return base * multiplier;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -579,7 +579,8 @@ private:
|
|||||||
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
|
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
|
||||||
bool mixed = false);
|
bool mixed = false);
|
||||||
bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||||
|
void UpdateAIGroupMembership();
|
||||||
|
Item* FindItemInInventory(std::function<bool(ItemTemplate const*)> checkItem) const;
|
||||||
void HandleCommands();
|
void HandleCommands();
|
||||||
void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL);
|
void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL);
|
||||||
bool _isBotInitializing = false;
|
bool _isBotInitializing = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user