mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 00:58:33 +00:00
[CRASH FIX] Various crash fixes in regard to defensive checks around unit/targets and finer grained checks on tele ack (#1951)
Some basic defense checks on mainly unit/targets used in public functions, and some minor tweaks with teleport ack. https://github.com/mod-playerbots/mod-playerbots/issues/1934 https://github.com/mod-playerbots/mod-playerbots/issues/1957
This commit is contained in:
@@ -437,7 +437,7 @@ void PlayerbotAI::UpdateAIGroupMaster()
|
|||||||
|
|
||||||
void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal)
|
void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal)
|
||||||
{
|
{
|
||||||
if (bot->IsBeingTeleported() || !bot->IsInWorld())
|
if (!bot || bot->IsBeingTeleported() || !bot->IsInWorld())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string const mapString = WorldPosition(bot).isOverworld() ? std::to_string(bot->GetMapId()) : "I";
|
std::string const mapString = WorldPosition(bot).isOverworld() ? std::to_string(bot->GetMapId()) : "I";
|
||||||
@@ -516,23 +516,37 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal
|
|||||||
void PlayerbotAI::HandleCommands()
|
void PlayerbotAI::HandleCommands()
|
||||||
{
|
{
|
||||||
ExternalEventHelper helper(aiObjectContext);
|
ExternalEventHelper helper(aiObjectContext);
|
||||||
|
|
||||||
for (auto it = chatCommands.begin(); it != chatCommands.end();)
|
for (auto it = chatCommands.begin(); it != chatCommands.end();)
|
||||||
{
|
{
|
||||||
time_t& checkTime = it->GetTime();
|
time_t& checkTime = it->GetTime();
|
||||||
if (checkTime && time(0) < checkTime)
|
if (checkTime && time(nullptr) < checkTime)
|
||||||
{
|
{
|
||||||
++it;
|
++it;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& command = it->GetCommand();
|
|
||||||
Player* owner = it->GetOwner();
|
Player* owner = it->GetOwner();
|
||||||
|
if (!owner)
|
||||||
|
{
|
||||||
|
it = chatCommands.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& command = it->GetCommand();
|
||||||
|
if (command.empty())
|
||||||
|
{
|
||||||
|
it = chatCommands.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!helper.ParseChatCommand(command, owner) && it->GetType() == CHAT_MSG_WHISPER)
|
if (!helper.ParseChatCommand(command, owner) && it->GetType() == CHAT_MSG_WHISPER)
|
||||||
{
|
{
|
||||||
// ostringstream out; out << "Unknown command " << command;
|
// ostringstream out; out << "Unknown command " << command;
|
||||||
// TellPlayer(out);
|
// TellPlayer(out);
|
||||||
// helper.ParseChatCommand("help");
|
// helper.ParseChatCommand("help");
|
||||||
}
|
}
|
||||||
|
|
||||||
it = chatCommands.erase(it);
|
it = chatCommands.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -540,6 +554,9 @@ void PlayerbotAI::HandleCommands()
|
|||||||
std::map<std::string, ChatMsg> chatMap;
|
std::map<std::string, ChatMsg> chatMap;
|
||||||
void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang)
|
void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang)
|
||||||
{
|
{
|
||||||
|
if (!bot)
|
||||||
|
return;
|
||||||
|
|
||||||
std::string filtered = text;
|
std::string filtered = text;
|
||||||
|
|
||||||
if (!IsAllowedCommand(filtered) && !GetSecurity()->CheckLevelFor(PlayerbotSecurityLevel::PLAYERBOT_SECURITY_INVITE,
|
if (!IsAllowedCommand(filtered) && !GetSecurity()->CheckLevelFor(PlayerbotSecurityLevel::PLAYERBOT_SECURITY_INVITE,
|
||||||
@@ -711,65 +728,82 @@ void PlayerbotAI::HandleCommand(uint32 type, const std::string& text, Player& fr
|
|||||||
|
|
||||||
void PlayerbotAI::HandleTeleportAck()
|
void PlayerbotAI::HandleTeleportAck()
|
||||||
{
|
{
|
||||||
|
if (!bot || !bot->GetSession())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// only for bots
|
||||||
if (IsRealPlayer())
|
if (IsRealPlayer())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Clearing motion generators and stopping movement which prevents
|
/*
|
||||||
// conflicts between teleport and any active motion (walk, run, swim, flight, etc.)
|
* FAR TELEPORT (worldport / map change)
|
||||||
bot->GetMotionMaster()->Clear(true);
|
* Player may NOT be in world or grid here.
|
||||||
bot->StopMoving();
|
* Handle this FIRST.
|
||||||
|
*/
|
||||||
// Near teleport (within map/instance)
|
|
||||||
if (bot->IsBeingTeleportedNear())
|
|
||||||
{
|
|
||||||
// Previous versions manually added the bot to the map if it was not in the world.
|
|
||||||
// not needed: HandleMoveTeleportAckOpcode() safely attaches the player to the map
|
|
||||||
// and clears IsBeingTeleportedNear().
|
|
||||||
|
|
||||||
Player* plMover = bot->m_mover->ToPlayer();
|
|
||||||
if (!plMover)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Send the near teleport ACK packet
|
|
||||||
WorldPacket p(MSG_MOVE_TELEPORT_ACK, 20);
|
|
||||||
p << plMover->GetPackGUID();
|
|
||||||
p << uint32(0);
|
|
||||||
p << uint32(0);
|
|
||||||
bot->GetSession()->HandleMoveTeleportAck(p);
|
|
||||||
|
|
||||||
// Simulate teleport latency and prevent AI from running too early (used cmangos delays)
|
|
||||||
SetNextCheckDelay(urand(1000, 2000));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Far teleport (worldport / different map)
|
|
||||||
if (bot->IsBeingTeleportedFar())
|
if (bot->IsBeingTeleportedFar())
|
||||||
{
|
{
|
||||||
// Handle far teleport ACK:
|
|
||||||
// Moves the bot to the new map, clears IsBeingTeleportedFar(), updates session/map references
|
|
||||||
bot->GetSession()->HandleMoveWorldportAck();
|
bot->GetSession()->HandleMoveWorldportAck();
|
||||||
|
|
||||||
// Ensure bot now has a valid map. If this fails, there is a core/session bug?
|
// after worldport ACK the player should be in a valid map
|
||||||
if (!bot->GetMap())
|
if (!bot->GetMap())
|
||||||
{
|
{
|
||||||
LOG_ERROR("playerbot", "Bot {} has no map after worldport ACK", bot->GetGUID().ToString());
|
LOG_ERROR("playerbot", "Bot {} has no map after worldport ACK", bot->GetGUID().ToString());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instance strategies after teleport
|
// apply instance-related strategies after map attach
|
||||||
if (sPlayerbotAIConfig->applyInstanceStrategies)
|
if (sPlayerbotAIConfig->applyInstanceStrategies)
|
||||||
ApplyInstanceStrategies(bot->GetMapId(), true);
|
ApplyInstanceStrategies(bot->GetMapId(), true);
|
||||||
|
|
||||||
// healer DPS strategies if restrictions are enabled
|
|
||||||
if (sPlayerbotAIConfig->restrictHealerDPS)
|
if (sPlayerbotAIConfig->restrictHealerDPS)
|
||||||
EvaluateHealerDpsStrategy();
|
EvaluateHealerDpsStrategy();
|
||||||
|
|
||||||
// Reset AI state to to before teleport conditions
|
// reset AI state after teleport
|
||||||
Reset(true);
|
Reset(true);
|
||||||
|
|
||||||
// Slightly longer delay to simulate far teleport latency (used cmangos delays)
|
// clear movement only AFTER teleport is finalized and bot is in world
|
||||||
|
if (bot->IsInWorld() && bot->GetMotionMaster())
|
||||||
|
{
|
||||||
|
bot->GetMotionMaster()->Clear(true);
|
||||||
|
bot->StopMoving();
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulate far teleport latency (cmangos-style)
|
||||||
SetNextCheckDelay(urand(2000, 5000));
|
SetNextCheckDelay(urand(2000, 5000));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown);
|
/*
|
||||||
|
* NEAR TELEPORT (same map / instance)
|
||||||
|
* Player MUST be in world (and in grid).
|
||||||
|
*/
|
||||||
|
if (bot->IsBeingTeleportedNear())
|
||||||
|
{
|
||||||
|
if (!bot->IsInWorld())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Player* plMover = bot->m_mover ? bot->m_mover->ToPlayer() : nullptr;
|
||||||
|
if (!plMover)
|
||||||
|
return;
|
||||||
|
|
||||||
|
WorldPacket p(MSG_MOVE_TELEPORT_ACK, 20);
|
||||||
|
p << plMover->GetPackGUID();
|
||||||
|
p << uint32(0); // flags
|
||||||
|
p << uint32(0); // time
|
||||||
|
|
||||||
|
bot->GetSession()->HandleMoveTeleportAck(p);
|
||||||
|
|
||||||
|
// clear movement after successful relocation
|
||||||
|
if (bot->GetMotionMaster())
|
||||||
|
{
|
||||||
|
bot->GetMotionMaster()->Clear(true);
|
||||||
|
bot->StopMoving();
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulate near teleport latency
|
||||||
|
SetNextCheckDelay(urand(1000, 2000));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotAI::Reset(bool full)
|
void PlayerbotAI::Reset(bool full)
|
||||||
@@ -1286,7 +1320,12 @@ void PlayerbotAI::SpellInterrupted(uint32 spellid)
|
|||||||
Spell* spell = bot->GetCurrentSpell((CurrentSpellTypes)type);
|
Spell* spell = bot->GetCurrentSpell((CurrentSpellTypes)type);
|
||||||
if (!spell)
|
if (!spell)
|
||||||
continue;
|
continue;
|
||||||
if (spell->GetSpellInfo()->Id == spellid)
|
|
||||||
|
SpellInfo const* spellInfo = spell->GetSpellInfo();
|
||||||
|
if (!spellInfo)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (spellInfo->Id == spellid)
|
||||||
bot->InterruptSpell((CurrentSpellTypes)type);
|
bot->InterruptSpell((CurrentSpellTypes)type);
|
||||||
}
|
}
|
||||||
// LastSpellCast& lastSpell = aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get();
|
// LastSpellCast& lastSpell = aiObjectContext->GetValue<LastSpellCast&>("last spell cast")->Get();
|
||||||
@@ -1728,6 +1767,7 @@ bool PlayerbotAI::IsRanged(Player* player, bool bySpec)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1821,10 +1861,9 @@ bool PlayerbotAI::IsRangedDpsAssistantOfIndex(Player* player, int index)
|
|||||||
|
|
||||||
bool PlayerbotAI::HasAggro(Unit* unit)
|
bool PlayerbotAI::HasAggro(Unit* unit)
|
||||||
{
|
{
|
||||||
if (!unit)
|
if (!IsValidUnit(unit))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
bool isMT = IsMainTank(bot);
|
bool isMT = IsMainTank(bot);
|
||||||
Unit* victim = unit->GetVictim();
|
Unit* victim = unit->GetVictim();
|
||||||
if (victim && (victim->GetGUID() == bot->GetGUID() || (!isMT && victim->ToPlayer() && IsTank(victim->ToPlayer()))))
|
if (victim && (victim->GetGUID() == bot->GetGUID() || (!isMT && victim->ToPlayer() && IsTank(victim->ToPlayer()))))
|
||||||
@@ -2822,6 +2861,9 @@ bool PlayerbotAI::TellMaster(std::string const text, PlayerbotSecurityLevel secu
|
|||||||
|
|
||||||
bool IsRealAura(Player* bot, AuraEffect const* aurEff, Unit const* unit)
|
bool IsRealAura(Player* bot, AuraEffect const* aurEff, Unit const* unit)
|
||||||
{
|
{
|
||||||
|
if (!unit || !unit->IsInWorld() || unit->IsDuringRemoveFromWorld())
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!aurEff)
|
if (!aurEff)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -2829,6 +2871,8 @@ bool IsRealAura(Player* bot, AuraEffect const* aurEff, Unit const* unit)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
|
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
|
||||||
|
if (!spellInfo)
|
||||||
|
return false;
|
||||||
|
|
||||||
uint32 stacks = aurEff->GetBase()->GetStackAmount();
|
uint32 stacks = aurEff->GetBase()->GetStackAmount();
|
||||||
if (stacks >= spellInfo->StackAmount)
|
if (stacks >= spellInfo->StackAmount)
|
||||||
@@ -2844,7 +2888,7 @@ bool IsRealAura(Player* bot, AuraEffect const* aurEff, Unit const* unit)
|
|||||||
bool PlayerbotAI::HasAura(std::string const name, Unit* unit, bool maxStack, bool checkIsOwner, int maxAuraAmount,
|
bool PlayerbotAI::HasAura(std::string const name, Unit* unit, bool maxStack, bool checkIsOwner, int maxAuraAmount,
|
||||||
bool checkDuration)
|
bool checkDuration)
|
||||||
{
|
{
|
||||||
if (!unit)
|
if (!IsValidUnit(unit))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::wstring wnamepart;
|
std::wstring wnamepart;
|
||||||
@@ -2940,7 +2984,7 @@ bool PlayerbotAI::HasAura(uint32 spellId, Unit const* unit)
|
|||||||
|
|
||||||
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 (!IsValidUnit(unit))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
std::wstring wnamepart;
|
std::wstring wnamepart;
|
||||||
@@ -2958,6 +3002,9 @@ 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();
|
||||||
|
if (!spellInfo)
|
||||||
|
continue;
|
||||||
|
|
||||||
std::string const& auraName = spellInfo->SpellName[0];
|
std::string const& auraName = spellInfo->SpellName[0];
|
||||||
|
|
||||||
// Directly skip if name mismatch (both length and content)
|
// Directly skip if name mismatch (both length and content)
|
||||||
@@ -3038,6 +3085,9 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
|
|||||||
if (!target)
|
if (!target)
|
||||||
target = bot;
|
target = bot;
|
||||||
|
|
||||||
|
if (!IsValidUnit(target))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (Pet* pet = bot->GetPet())
|
if (Pet* pet = bot->GetPet())
|
||||||
if (pet->HasSpell(spellid))
|
if (pet->HasSpell(spellid))
|
||||||
return true;
|
return true;
|
||||||
@@ -3299,6 +3349,9 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, float x, float y, float z, bool c
|
|||||||
|
|
||||||
bool PlayerbotAI::CastSpell(std::string const name, Unit* target, Item* itemTarget)
|
bool PlayerbotAI::CastSpell(std::string const name, Unit* target, Item* itemTarget)
|
||||||
{
|
{
|
||||||
|
if (!IsValidUnit(target))
|
||||||
|
return false;
|
||||||
|
|
||||||
bool result = CastSpell(aiObjectContext->GetValue<uint32>("spell id", name)->Get(), target, itemTarget);
|
bool result = CastSpell(aiObjectContext->GetValue<uint32>("spell id", name)->Get(), target, itemTarget);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
@@ -3311,15 +3364,19 @@ bool PlayerbotAI::CastSpell(std::string const name, Unit* target, Item* itemTarg
|
|||||||
bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
||||||
{
|
{
|
||||||
if (!spellId)
|
if (!spellId)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!target)
|
if (!target)
|
||||||
target = bot;
|
target = bot;
|
||||||
|
|
||||||
Pet* pet = bot->GetPet();
|
if (!IsValidUnit(target))
|
||||||
|
return false;
|
||||||
|
|
||||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||||
|
if (!spellInfo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Pet* pet = bot->GetPet();
|
||||||
if (pet && pet->HasSpell(spellId))
|
if (pet && pet->HasSpell(spellId))
|
||||||
{
|
{
|
||||||
// List of spell IDs for which we do NOT want to toggle auto-cast or send message
|
// List of spell IDs for which we do NOT want to toggle auto-cast or send message
|
||||||
@@ -3722,6 +3779,9 @@ bool PlayerbotAI::CanCastVehicleSpell(uint32 spellId, Unit* target)
|
|||||||
if (!spellId)
|
if (!spellId)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!IsValidUnit(target))
|
||||||
|
return false;
|
||||||
|
|
||||||
Vehicle* vehicle = bot->GetVehicle();
|
Vehicle* vehicle = bot->GetVehicle();
|
||||||
if (!vehicle)
|
if (!vehicle)
|
||||||
return false;
|
return false;
|
||||||
@@ -3732,12 +3792,12 @@ bool PlayerbotAI::CanCastVehicleSpell(uint32 spellId, Unit* target)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
Unit* vehicleBase = vehicle->GetBase();
|
Unit* vehicleBase = vehicle->GetBase();
|
||||||
|
|
||||||
Unit* spellTarget = target;
|
Unit* spellTarget = target;
|
||||||
|
|
||||||
if (!spellTarget)
|
if (!spellTarget)
|
||||||
spellTarget = vehicleBase;
|
spellTarget = vehicleBase;
|
||||||
|
|
||||||
if (!spellTarget)
|
if (!IsValidUnit(spellTarget))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (vehicleBase->HasSpellCooldown(spellId))
|
if (vehicleBase->HasSpellCooldown(spellId))
|
||||||
@@ -3804,6 +3864,9 @@ bool PlayerbotAI::CastVehicleSpell(uint32 spellId, Unit* target)
|
|||||||
if (!spellId)
|
if (!spellId)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!IsValidUnit(target))
|
||||||
|
return false;
|
||||||
|
|
||||||
Vehicle* vehicle = bot->GetVehicle();
|
Vehicle* vehicle = bot->GetVehicle();
|
||||||
if (!vehicle)
|
if (!vehicle)
|
||||||
return false;
|
return false;
|
||||||
@@ -3814,12 +3877,12 @@ bool PlayerbotAI::CastVehicleSpell(uint32 spellId, Unit* target)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
Unit* vehicleBase = vehicle->GetBase();
|
Unit* vehicleBase = vehicle->GetBase();
|
||||||
|
|
||||||
Unit* spellTarget = target;
|
Unit* spellTarget = target;
|
||||||
|
|
||||||
if (!spellTarget)
|
if (!spellTarget)
|
||||||
spellTarget = vehicleBase;
|
spellTarget = vehicleBase;
|
||||||
|
|
||||||
if (!spellTarget)
|
if (!IsValidUnit(spellTarget))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||||
@@ -3972,9 +4035,13 @@ bool PlayerbotAI::IsInVehicle(bool canControl, bool canCast, bool canAttack, boo
|
|||||||
|
|
||||||
void PlayerbotAI::WaitForSpellCast(Spell* spell)
|
void PlayerbotAI::WaitForSpellCast(Spell* spell)
|
||||||
{
|
{
|
||||||
|
if (!spell)
|
||||||
|
return;
|
||||||
|
|
||||||
SpellInfo const* spellInfo = spell->GetSpellInfo();
|
SpellInfo const* spellInfo = spell->GetSpellInfo();
|
||||||
uint32 castTime = spell->GetCastTime();
|
uint32 castTime = spell->GetCastTime();
|
||||||
if (spellInfo->IsChanneled())
|
|
||||||
|
if (spellInfo && spellInfo->IsChanneled())
|
||||||
{
|
{
|
||||||
int32 duration = spellInfo->GetDuration();
|
int32 duration = spellInfo->GetDuration();
|
||||||
bot->ApplySpellMod(spellInfo->Id, SPELLMOD_DURATION, duration);
|
bot->ApplySpellMod(spellInfo->Id, SPELLMOD_DURATION, duration);
|
||||||
@@ -4022,6 +4089,9 @@ void PlayerbotAI::RemoveAura(std::string const name)
|
|||||||
|
|
||||||
bool PlayerbotAI::IsInterruptableSpellCasting(Unit* target, std::string const spell)
|
bool PlayerbotAI::IsInterruptableSpellCasting(Unit* target, std::string const spell)
|
||||||
{
|
{
|
||||||
|
if (!IsValidUnit(target))
|
||||||
|
return false;
|
||||||
|
|
||||||
uint32 spellid = aiObjectContext->GetValue<uint32>("spell id", spell)->Get();
|
uint32 spellid = aiObjectContext->GetValue<uint32>("spell id", spell)->Get();
|
||||||
if (!spellid || !target->IsNonMeleeSpellCast(true))
|
if (!spellid || !target->IsNonMeleeSpellCast(true))
|
||||||
return false;
|
return false;
|
||||||
@@ -4050,17 +4120,25 @@ bool PlayerbotAI::IsInterruptableSpellCasting(Unit* target, std::string const sp
|
|||||||
|
|
||||||
bool PlayerbotAI::HasAuraToDispel(Unit* target, uint32 dispelType)
|
bool PlayerbotAI::HasAuraToDispel(Unit* target, uint32 dispelType)
|
||||||
{
|
{
|
||||||
if (!target->IsInWorld())
|
if (!IsValidUnit(target) || !target->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
if (!IsValidPlayer(bot))
|
||||||
|
return false;
|
||||||
|
|
||||||
bool isFriend = bot->IsFriendlyTo(target);
|
bool isFriend = bot->IsFriendlyTo(target);
|
||||||
|
|
||||||
Unit::VisibleAuraMap const* visibleAuras = target->GetVisibleAuras();
|
Unit::VisibleAuraMap const* visibleAuras = target->GetVisibleAuras();
|
||||||
|
if (!visibleAuras)
|
||||||
|
return false;
|
||||||
|
|
||||||
for (Unit::VisibleAuraMap::const_iterator itr = visibleAuras->begin(); itr != visibleAuras->end(); ++itr)
|
for (Unit::VisibleAuraMap::const_iterator itr = visibleAuras->begin(); itr != visibleAuras->end(); ++itr)
|
||||||
{
|
{
|
||||||
Aura* aura = itr->second->GetBase();
|
if (!itr->second)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (aura->IsPassive())
|
Aura* aura = itr->second->GetBase();
|
||||||
|
if (!aura || aura->IsPassive() || aura->IsRemoved())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->dispelAuraDuration && aura->GetDuration() &&
|
if (sPlayerbotAIConfig->dispelAuraDuration && aura->GetDuration() &&
|
||||||
@@ -4068,6 +4146,8 @@ bool PlayerbotAI::HasAuraToDispel(Unit* target, uint32 dispelType)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
SpellInfo const* spellInfo = aura->GetSpellInfo();
|
SpellInfo const* spellInfo = aura->GetSpellInfo();
|
||||||
|
if (!spellInfo)
|
||||||
|
continue;
|
||||||
|
|
||||||
bool isPositiveSpell = spellInfo->IsPositive();
|
bool isPositiveSpell = spellInfo->IsPositive();
|
||||||
if (isPositiveSpell && isFriend)
|
if (isPositiveSpell && isFriend)
|
||||||
@@ -4079,6 +4159,7 @@ bool PlayerbotAI::HasAuraToDispel(Unit* target, uint32 dispelType)
|
|||||||
if (canDispel(spellInfo, dispelType))
|
if (canDispel(spellInfo, dispelType))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5709,7 +5790,7 @@ void PlayerbotAI::ImbueItem(Item* item) { ImbueItem(item, TARGET_FLAG_NONE, Obje
|
|||||||
// item on unit
|
// item on unit
|
||||||
void PlayerbotAI::ImbueItem(Item* item, Unit* target)
|
void PlayerbotAI::ImbueItem(Item* item, Unit* target)
|
||||||
{
|
{
|
||||||
if (!target)
|
if (!IsValidUnit(target))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImbueItem(item, TARGET_FLAG_UNIT, target->GetGUID());
|
ImbueItem(item, TARGET_FLAG_UNIT, target->GetGUID());
|
||||||
|
|||||||
@@ -616,7 +616,15 @@ private:
|
|||||||
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;
|
||||||
|
inline bool IsValidUnit(const Unit* unit) const
|
||||||
|
{
|
||||||
|
return unit && unit->IsInWorld() && !unit->IsDuringRemoveFromWorld();
|
||||||
|
}
|
||||||
|
inline bool IsValidPlayer(const Player* player) const
|
||||||
|
{
|
||||||
|
return player && player->GetSession() && player->IsInWorld() && !player->IsDuringRemoveFromWorld() &&
|
||||||
|
!player->IsBeingTeleported();
|
||||||
|
}
|
||||||
protected:
|
protected:
|
||||||
Player* bot;
|
Player* bot;
|
||||||
Player* master;
|
Player* master;
|
||||||
|
|||||||
Reference in New Issue
Block a user