Movement priority

This commit is contained in:
Yunfan Li
2024-08-14 18:23:24 +08:00
parent 765d0305ef
commit 7b0bb20078
12 changed files with 216 additions and 183 deletions

View File

@@ -405,14 +405,15 @@ public:
} }
}; };
class RecentlyFleeInfo : public ManualSetValue<std::list<FleeInfo>> class RecentlyFleeInfo : public ManualSetValue<std::list<FleeInfo>&>
{ {
public: public:
RecentlyFleeInfo(PlayerbotAI* botAI, std::list<FleeInfo> defaultValue = {}, RecentlyFleeInfo(PlayerbotAI* botAI, std::string const name = "recently flee info")
std::string const name = "recently flee info") : ManualSetValue<std::list<FleeInfo>&>(botAI, data, name)
: ManualSetValue<std::list<FleeInfo>>(botAI, defaultValue, name)
{ {
} }
private:
std::list<FleeInfo> data = {};
}; };
#endif #endif

View File

@@ -7,9 +7,12 @@
#include "CreatureAI.h" #include "CreatureAI.h"
#include "Event.h" #include "Event.h"
#include "LastMovementValue.h"
#include "LootObjectStack.h" #include "LootObjectStack.h"
#include "PlayerbotAI.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "ServerFacade.h" #include "ServerFacade.h"
#include "SharedDefines.h"
#include "Unit.h" #include "Unit.h"
bool AttackAction::Execute(Event event) bool AttackAction::Execute(Event event)
@@ -109,13 +112,24 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
bot->SetSelection(target->GetGUID()); bot->SetSelection(target->GetGUID());
Unit* oldTarget = context->GetValue<Unit*>("current target")->Get(); Unit* oldTarget = context->GetValue<Unit*>("current target")->Get();
if (oldTarget == target && botAI->GetState() == BOT_STATE_COMBAT && bot->GetVictim() == target)
return false;
context->GetValue<Unit*>("old target")->Set(oldTarget); context->GetValue<Unit*>("old target")->Set(oldTarget);
context->GetValue<Unit*>("current target")->Set(target); context->GetValue<Unit*>("current target")->Set(target);
context->GetValue<LootObjectStack*>("available loot")->Get()->Add(guid); context->GetValue<LootObjectStack*>("available loot")->Get()->Add(guid);
LastMovement& lastMovement = AI_VALUE(LastMovement&, "last movement");
if (lastMovement.priority < MovementPriority::MOVEMENT_COMBAT && bot->isMoving())
{
AI_VALUE(LastMovement&, "last movement").clear();
bot->GetMotionMaster()->Clear(false);
bot->StopMoving();
}
bool melee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot); bool melee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot);
bot->Attack(target, melee);
if (IsMovingAllowed() && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target)) if (IsMovingAllowed() && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target))
{ {
@@ -123,10 +137,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
} }
botAI->ChangeEngine(BOT_STATE_COMBAT); botAI->ChangeEngine(BOT_STATE_COMBAT);
if (!bot->GetVictim()) bot->Attack(target, melee);
{
return false;
}
/* prevent pet dead immediately in group */ /* prevent pet dead immediately in group */
// if (bot->GetMap()->IsDungeon() && bot->GetGroup() && !target->IsInCombat()) { // if (bot->GetMap()->IsDungeon() && bot->GetGroup() && !target->IsInCombat()) {
// with_pet = false; // with_pet = false;

View File

@@ -32,7 +32,7 @@ bool FollowChatShortcutAction::Execute(Event event)
if (!master) if (!master)
return false; return false;
botAI->Reset(); // botAI->Reset();
botAI->ChangeStrategy("+follow,-passive,-grind", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("+follow,-passive,-grind", BOT_STATE_NON_COMBAT);
botAI->ChangeStrategy("-follow,-passive,-grind", BOT_STATE_COMBAT); botAI->ChangeStrategy("-follow,-passive,-grind", BOT_STATE_COMBAT);
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({}); botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
@@ -57,7 +57,9 @@ bool FollowChatShortcutAction::Execute(Event event)
if (Formation::IsNullLocation(loc) || loc.GetMapId() == -1) if (Formation::IsNullLocation(loc) || loc.GetMapId() == -1)
return false; return false;
moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ()); MovementPriority priority = botAI->GetState() == BOT_STATE_COMBAT ? MovementPriority::MOVEMENT_COMBAT : MovementPriority::MOVEMENT_NORMAL;
moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), false, false, false,
true, priority);
} }
if (moved) if (moved)

View File

@@ -8,6 +8,7 @@
#include "BattlegroundWS.h" #include "BattlegroundWS.h"
#include "Event.h" #include "Event.h"
#include "PlayerbotAI.h" #include "PlayerbotAI.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "ServerFacade.h" #include "ServerFacade.h"
#include "SpellAuraEffects.h" #include "SpellAuraEffects.h"
@@ -17,35 +18,46 @@ bool CheckMountStateAction::Execute(Event event)
bool noattackers = bool noattackers =
AI_VALUE2(bool, "combat", "self target") ? (AI_VALUE(uint8, "attacker count") > 0 ? false : true) : true; AI_VALUE2(bool, "combat", "self target") ? (AI_VALUE(uint8, "attacker count") > 0 ? false : true) : true;
bool enemy = AI_VALUE(Unit*, "enemy player target"); bool enemy = AI_VALUE(Unit*, "enemy player target");
// ignore grind target in BG or bots will dismount near any creature (eg: the rams in AV)
bool dps = AI_VALUE(Unit*, "dps target"); bool dps = AI_VALUE(Unit*, "dps target");
// bool fartarget = (enemy && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "enemy player bool shouldDismount = false;
// target"), 40.0f)) || bool shouldMount = false;
// (dps && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "dps target"), 50.0f));
bool attackdistance = false;
// bool chasedistance = false; // bool chasedistance = false;
float attack_distance = 35.0f; float attack_distance;
float mount_distance;
if (PlayerbotAI::IsMelee(bot)) if (PlayerbotAI::IsMelee(bot))
{ {
attack_distance = 5.0f; attack_distance = sPlayerbotAIConfig->meleeDistance + 2.0f;
mount_distance = sPlayerbotAIConfig->meleeDistance + 10.0f;
} }
else else
{ {
attack_distance = 30.0f; attack_distance = sPlayerbotAIConfig->spellDistance + 2.0f;
mount_distance = sPlayerbotAIConfig->spellDistance + 10.0f;
} }
// if (enemy)
// attack_distance /= 2;
if (dps || enemy)
{
Unit* currentTarget = AI_VALUE(Unit*, "current target"); Unit* currentTarget = AI_VALUE(Unit*, "current target");
attackdistance =
(enemy || dps) && currentTarget &&
sServerFacade->IsDistanceLessThan(AI_VALUE2(float, "distance", "current target"), attack_distance);
}
if (bot->IsMounted() && attackdistance) if (currentTarget)
{
float combatReach = bot->GetCombatReach() + currentTarget->GetCombatReach();
attack_distance += combatReach;
float disToTarget = bot->GetExactDist(currentTarget);
shouldDismount = disToTarget <= attack_distance;
}
else
shouldDismount = false;
if (currentTarget)
{
float combatReach = bot->GetCombatReach() + currentTarget->GetCombatReach();
mount_distance += combatReach;
float disToTarget = bot->GetExactDist(currentTarget);
shouldMount = disToTarget > mount_distance;
}
else
shouldMount = true;
if (bot->IsMounted() && shouldDismount)
{ {
WorldPacket emptyPacket; WorldPacket emptyPacket;
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket); bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
@@ -59,7 +71,7 @@ bool CheckMountStateAction::Execute(Event event)
return false; return false;
// bool farFromMaster = sServerFacade->GetDistance2d(bot, master) > sPlayerbotAIConfig->sightDistance; // bool farFromMaster = sServerFacade->GetDistance2d(bot, master) > sPlayerbotAIConfig->sightDistance;
if (master->IsMounted() && !bot->IsMounted() && noattackers && !attackdistance && !bot->IsInCombat() && if (master->IsMounted() && !bot->IsMounted() && noattackers && shouldMount && !bot->IsInCombat() &&
botAI->GetState() != BOT_STATE_COMBAT) botAI->GetState() != BOT_STATE_COMBAT)
{ {
return Mount(); return Mount();
@@ -71,16 +83,6 @@ bool CheckMountStateAction::Execute(Event event)
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket); bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
return true; return true;
} }
// if (!bot->IsMounted() && (chasedistance || (farFromMaster && botAI->HasStrategy("follow",
// BOT_STATE_NON_COMBAT))) && !bot->IsInCombat() && !dps)
// return Mount();
// if (!bot->IsFlying() && ((!farFromMaster && !master->IsMounted()) || attackdistance) && bot->IsMounted())
// {
// WorldPacket emptyPacket;
// bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
// return true;
// }
return false; return false;
} }
@@ -88,13 +90,13 @@ bool CheckMountStateAction::Execute(Event event)
// For random bots // For random bots
if (!bot->InBattleground() && !master) if (!bot->InBattleground() && !master)
{ {
if (!bot->IsMounted() && noattackers && !attackdistance && !bot->IsInCombat()) if (!bot->IsMounted() && noattackers && shouldMount && !bot->IsInCombat())
{ {
return Mount(); return Mount();
} }
} }
if (bot->InBattleground() && !attackdistance && noattackers && !bot->IsInCombat() && !bot->IsMounted()) if (bot->InBattleground() && shouldMount && noattackers && !bot->IsInCombat() && !bot->IsMounted())
{ {
if (bot->GetBattlegroundTypeId() == BATTLEGROUND_WS) if (bot->GetBattlegroundTypeId() == BATTLEGROUND_WS)
{ {
@@ -108,24 +110,7 @@ bool CheckMountStateAction::Execute(Event event)
return Mount(); return Mount();
} }
// if (!bot->InBattleground()) if (!bot->IsFlying() && shouldDismount && bot->IsMounted() && (enemy || dps || (!noattackers && bot->IsInCombat())))
// {
// if (AI_VALUE(GuidPosition, "rpg target"))
// {
// if (sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "rpg target"),
// sPlayerbotAIConfig->farDistance) && noattackers && !dps && !enemy)
// return Mount();
// }
// if (((!AI_VALUE(GuidVector, "possible rpg targets").empty()) && noattackers && !dps && !enemy) && urand(0,
// 100) > 50)
// return Mount();
// }
// if (!bot->IsMounted() && !attackdistance && (fartarget || chasedistance))
// return Mount();
if (!bot->IsFlying() && attackdistance && bot->IsMounted() && (enemy || dps || (!noattackers && bot->IsInCombat())))
{ {
WorldPacket emptyPacket; WorldPacket emptyPacket;
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket); bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);

View File

@@ -9,6 +9,8 @@
#include "Event.h" #include "Event.h"
#include "Formations.h" #include "Formations.h"
#include "LastMovementValue.h"
#include "PlayerbotAI.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "ServerFacade.h" #include "ServerFacade.h"
#include "SharedDefines.h" #include "SharedDefines.h"
@@ -29,24 +31,14 @@ bool FollowAction::Execute(Event event)
if (Formation::IsNullLocation(loc) || loc.GetMapId() == -1) if (Formation::IsNullLocation(loc) || loc.GetMapId() == -1)
return false; return false;
MovementPriority priority = botAI->GetState() == BOT_STATE_COMBAT ? MovementPriority::MOVEMENT_COMBAT : MovementPriority::MOVEMENT_NORMAL;
moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), false, false, false, moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), false, false, false,
true); true, priority);
} }
if (Pet* pet = bot->GetPet()) if (Pet* pet = bot->GetPet())
{ {
if (CreatureAI* creatureAI = ((Creature*)pet)->AI()) botAI->PetFollow();
{
pet->SetReactState(REACT_PASSIVE);
pet->GetCharmInfo()->SetIsCommandFollow(true);
pet->GetCharmInfo()->IsReturning();
pet->GetMotionMaster()->MoveFollow(bot, PET_FOLLOW_DIST, pet->GetFollowAngle());
// pet->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
// pet->GetCharmInfo()->SetIsFollowing(true);
// pet->AttackStop();
// pet->GetCharmInfo()->IsReturning();
// pet->GetMotionMaster()->MoveFollow(bot, PET_FOLLOW_DIST, pet->GetFollowAngle());
}
} }
// if (moved) // if (moved)
// botAI->SetNextCheckDelay(sPlayerbotAIConfig->reactDelay); // botAI->SetNextCheckDelay(sPlayerbotAIConfig->reactDelay);

View File

@@ -94,12 +94,14 @@ bool MoveToRpgTargetAction::Execute(Event event)
x += cos(angle) * INTERACTION_DISTANCE * distance; x += cos(angle) * INTERACTION_DISTANCE * distance;
y += sin(angle) * INTERACTION_DISTANCE * distance; y += sin(angle) * INTERACTION_DISTANCE * distance;
bool exact = true;
if (!wo->GetMap()->CheckCollisionAndGetValidCoords(wo, wo->GetPositionX(), wo->GetPositionY(), wo->GetPositionZ(), if (!wo->GetMap()->CheckCollisionAndGetValidCoords(wo, wo->GetPositionX(), wo->GetPositionY(), wo->GetPositionZ(),
x, y, z)) x, y, z))
{ {
x = wo->GetPositionX(); x = wo->GetPositionX();
y = wo->GetPositionY(); y = wo->GetPositionY();
z = wo->GetPositionZ(); z = wo->GetPositionZ();
exact = false;
} }
// WaitForReach(distance); // WaitForReach(distance);
@@ -108,7 +110,7 @@ bool MoveToRpgTargetAction::Execute(Event event)
// if (bot->IsWithinLOS(x, y, z)) // if (bot->IsWithinLOS(x, y, z))
// couldMove = MoveNear(mapId, x, y, z, 0); // couldMove = MoveNear(mapId, x, y, z, 0);
// else // else
couldMove = MoveTo(mapId, x, y, z, false, false, false, true); couldMove = MoveTo(mapId, x, y, z, false, false, false, exact);
if (!couldMove && WorldPosition(mapId, x, y, z).distance(bot) > INTERACTION_DISTANCE) if (!couldMove && WorldPosition(mapId, x, y, z).distance(bot) > INTERACTION_DISTANCE)
{ {

View File

@@ -61,23 +61,37 @@ void MovementAction::CreateWp(Player* wpOwner, float x, float y, float z, float
wpCreature->SetObjectScale(0.5f); wpCreature->SetObjectScale(0.5f);
} }
void MovementAction::JumpTo(uint32 mapId, float x, float y, float z) bool MovementAction::JumpTo(uint32 mapId, float x, float y, float z, MovementPriority priority)
{ {
UpdateMovementState();
if (!IsMovingAllowed(mapId, x, y, z))
{
return false;
}
if (IsDuplicateMove(mapId, x, y, z))
{
return false;
}
if (IsWaitingForLastMove(priority))
{
return false;
}
float botZ = bot->GetPositionZ(); float botZ = bot->GetPositionZ();
float speed = bot->GetSpeed(MOVE_RUN); float speed = bot->GetSpeed(MOVE_RUN);
MotionMaster& mm = *bot->GetMotionMaster(); MotionMaster& mm = *bot->GetMotionMaster();
mm.Clear(); mm.Clear();
mm.MoveJump(x, y, z, speed, speed, 1); mm.MoveJump(x, y, z, speed, speed, 1);
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), 1000); AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), 1000, priority);
return true;
} }
bool MovementAction::MoveNear(uint32 mapId, float x, float y, float z, float distance) bool MovementAction::MoveNear(uint32 mapId, float x, float y, float z, float distance, MovementPriority priority)
{ {
float angle = GetFollowAngle(); float angle = GetFollowAngle();
return MoveTo(mapId, x + cos(angle) * distance, y + sin(angle) * distance, z); return MoveTo(mapId, x + cos(angle) * distance, y + sin(angle) * distance, z, false, false, false, false, priority);
} }
bool MovementAction::MoveNear(WorldObject* target, float distance) bool MovementAction::MoveNear(WorldObject* target, float distance, MovementPriority priority)
{ {
if (!target) if (!target)
return false; return false;
@@ -99,7 +113,7 @@ bool MovementAction::MoveNear(WorldObject* target, float distance)
if (!bot->IsWithinLOS(x, y, z)) if (!bot->IsWithinLOS(x, y, z))
continue; continue;
bool moved = MoveTo(target->GetMapId(), x, y, z); bool moved = MoveTo(target->GetMapId(), x, y, z, false, false, false, false, priority);
if (moved) if (moved)
return true; return true;
} }
@@ -161,7 +175,7 @@ bool MovementAction::MoveToLOS(WorldObject* target, bool ranged)
} }
bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, bool react, bool normal_only, bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, bool react, bool normal_only,
bool exact_waypoint) bool exact_waypoint, MovementPriority priority)
{ {
UpdateMovementState(); UpdateMovementState();
if (!IsMovingAllowed(mapId, x, y, z)) if (!IsMovingAllowed(mapId, x, y, z))
@@ -172,21 +186,10 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
{ {
return false; return false;
} }
if (IsWaitingForLastMove()) if (IsWaitingForLastMove(priority))
{ {
return false; return false;
} }
// if (bot->Unit::IsFalling()) {
// bot->Say("I'm falling!, flag:" + std::to_string(bot->m_movementInfo.GetMovementFlags()), LANG_UNIVERSAL);
// return false;
// }
// if (bot->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_SWIMMING)) {
// bot->Say("I'm swimming", LANG_UNIVERSAL);
// }
// if (bot->Unit::IsFalling()) {
// bot->Say("I'm falling", LANG_UNIVERSAL);
// }
bool generatePath = !bot->IsFlying() && !bot->isSwimming(); bool generatePath = !bot->IsFlying() && !bot->isSwimming();
bool disableMoveSplinePath = sPlayerbotAIConfig->disableMoveSplinePath >= 2 || bool disableMoveSplinePath = sPlayerbotAIConfig->disableMoveSplinePath >= 2 ||
(sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground()); (sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground());
@@ -202,11 +205,11 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
{ {
MotionMaster& mm = *vehicleBase->GetMotionMaster(); // need to move vehicle, not bot MotionMaster& mm = *vehicleBase->GetMotionMaster(); // need to move vehicle, not bot
mm.Clear(); mm.Clear();
mm.MovePoint(mapId, x, y, z, generatePath); mm.MovePoint(0, x, y, z, generatePath);
float delay = 1000.0f * (distance / vehicleBase->GetSpeed(MOVE_RUN)) - sPlayerbotAIConfig->reactDelay; float delay = 1000.0f * (distance / vehicleBase->GetSpeed(MOVE_RUN));
delay = std::max(.0f, delay); delay = std::max(.0f, delay);
delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay); delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay);
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay); AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority);
return true; return true;
} }
} }
@@ -225,11 +228,11 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
} }
MotionMaster& mm = *bot->GetMotionMaster(); MotionMaster& mm = *bot->GetMotionMaster();
mm.Clear(); mm.Clear();
mm.MovePoint(mapId, x, y, z, generatePath); mm.MovePoint(0, x, y, z, generatePath);
float delay = 1000.0f * MoveDelay(distance) - sPlayerbotAIConfig->reactDelay; float delay = 1000.0f * MoveDelay(distance);
delay = std::max(.0f, delay); delay = std::max(.0f, delay);
delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay); delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay);
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay); AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority);
return true; return true;
} }
} }
@@ -254,14 +257,13 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
botAI->InterruptSpell(); botAI->InterruptSpell();
} }
MotionMaster& mm = *bot->GetMotionMaster(); MotionMaster& mm = *bot->GetMotionMaster();
G3D::Vector3 endP = path.back();
mm.Clear(); mm.Clear();
mm.MoveSplinePath(&path); mm.MovePoint(0, endP.x, endP.y, endP.z, generatePath);
// mm.MoveSplinePath(&path); float delay = 1000.0f * MoveDelay(distance);
float delay = 1000.0f * MoveDelay(distance) - sPlayerbotAIConfig->reactDelay;
delay = std::max(.0f, delay); delay = std::max(.0f, delay);
delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay); delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay);
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay); AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority);
return true; return true;
} }
} }
@@ -759,7 +761,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
// return true; // return true;
} }
bool MovementAction::MoveTo(Unit* target, float distance) bool MovementAction::MoveTo(Unit* target, float distance, MovementPriority priority)
{ {
if (!IsMovingAllowed(target)) if (!IsMovingAllowed(target))
return false; return false;
@@ -793,7 +795,7 @@ bool MovementAction::MoveTo(Unit* target, float distance)
{ {
dz = tz; dz = tz;
} }
return MoveTo(target->GetMapId(), dx, dy, dz); return MoveTo(target->GetMapId(), dx, dy, dz, false, false, false, false, priority);
} }
bool MovementAction::ReachCombatTo(Unit* target, float distance) bool MovementAction::ReachCombatTo(Unit* target, float distance)
@@ -813,6 +815,7 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
if (target->HasUnitMovementFlag(MOVEMENTFLAG_FORWARD)) // target is moving forward, predict the position if (target->HasUnitMovementFlag(MOVEMENTFLAG_FORWARD)) // target is moving forward, predict the position
{ {
float needToGo = bot->GetExactDist(target) - distance; float needToGo = bot->GetExactDist(target) - distance;
float timeToGo = MoveDelay(abs(needToGo)) + sPlayerbotAIConfig->reactDelay / 1000.0f; float timeToGo = MoveDelay(abs(needToGo)) + sPlayerbotAIConfig->reactDelay / 1000.0f;
float targetMoveDist = timeToGo * target->GetSpeed(MOVE_RUN); float targetMoveDist = timeToGo * target->GetSpeed(MOVE_RUN);
@@ -845,7 +848,7 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
return false; return false;
path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), distance); path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), distance);
G3D::Vector3 endPos = path.GetPath().back(); G3D::Vector3 endPos = path.GetPath().back();
return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z); return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
float MovementAction::GetFollowAngle() float MovementAction::GetFollowAngle()
@@ -909,10 +912,13 @@ bool MovementAction::IsDuplicateMove(uint32 mapId, float x, float y, float z)
return true; return true;
} }
bool MovementAction::IsWaitingForLastMove() bool MovementAction::IsWaitingForLastMove(MovementPriority priority)
{ {
LastMovement& lastMove = *context->GetValue<LastMovement&>("last movement"); LastMovement& lastMove = *context->GetValue<LastMovement&>("last movement");
if (priority > lastMove.priority)
return false;
// heuristic 5s // heuristic 5s
if (lastMove.lastdelayTime + lastMove.msTime > getMSTime()) if (lastMove.lastdelayTime + lastMove.msTime > getMSTime())
return true; return true;
@@ -1216,7 +1222,7 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
botAI->InterruptSpell(); botAI->InterruptSpell();
} }
AI_VALUE(LastMovement&, "last movement").Set(target); // AI_VALUE(LastMovement&, "last movement").Set(target);
ClearIdleState(); ClearIdleState();
if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FOLLOW_MOTION_TYPE) if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FOLLOW_MOTION_TYPE)
@@ -1506,7 +1512,17 @@ bool MovementAction::MoveAway(Unit* target)
float dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance; float dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance;
float dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance; float dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance;
float dz = bot->GetPositionZ(); float dz = bot->GetPositionZ();
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true)) bool exact = true;
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
bot->GetPositionZ(), dx, dy, dz))
{
// disable prediction if position is invalid
dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance;
dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance;
dz = bot->GetPositionZ();
exact = false;
}
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true, exact, MovementPriority::MOVEMENT_COMBAT))
{ {
return true; return true;
} }
@@ -1514,11 +1530,21 @@ bool MovementAction::MoveAway(Unit* target)
{ {
continue; continue;
} }
exact = true;
angle = init_angle - delta; angle = init_angle - delta;
dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance; dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance;
dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance; dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance;
dz = bot->GetPositionZ(); dz = bot->GetPositionZ();
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true)) if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
bot->GetPositionZ(), dx, dy, dz))
{
// disable prediction if position is invalid
dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance;
dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance;
dz = bot->GetPositionZ();
exact = false;
}
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true, exact, MovementPriority::MOVEMENT_COMBAT))
{ {
return true; return true;
} }
@@ -1526,13 +1552,13 @@ bool MovementAction::MoveAway(Unit* target)
return false; return false;
} }
bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float distance) bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float distance, MovementPriority priority)
{ {
if (bot->GetDistance2d(x, y) <= distance) if (bot->GetDistance2d(x, y) <= distance)
{ {
return false; return false;
} }
return MoveNear(mapId, x, y, z, distance); return MoveNear(mapId, x, y, z, distance, priority);
} }
// float MovementAction::SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range, bool // float MovementAction::SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range, bool
@@ -1678,13 +1704,7 @@ bool FleeWithPetAction::Execute(Event event)
{ {
if (Pet* pet = bot->GetPet()) if (Pet* pet = bot->GetPet())
{ {
if (CreatureAI* creatureAI = ((Creature*)pet)->AI()) botAI->PetFollow();
{
pet->SetReactState(REACT_PASSIVE);
pet->GetCharmInfo()->SetIsCommandFollow(true);
pet->GetCharmInfo()->IsReturning();
pet->GetMotionMaster()->MoveFollow(bot, PET_FOLLOW_DIST, pet->GetFollowAngle());
}
} }
return Flee(AI_VALUE(Unit*, "current target")); return Flee(AI_VALUE(Unit*, "current target"));
@@ -1929,7 +1949,7 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius)
for (CheckAngle& checkAngle : possibleAngles) for (CheckAngle& checkAngle : possibleAngles)
{ {
float angle = checkAngle.angle; float angle = checkAngle.angle;
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info"); std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
if (!CheckLastFlee(angle, infoList)) if (!CheckLastFlee(angle, infoList))
{ {
continue; continue;
@@ -1985,7 +2005,7 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius)
for (CheckAngle& checkAngle : possibleAngles) for (CheckAngle& checkAngle : possibleAngles)
{ {
float angle = checkAngle.angle; float angle = checkAngle.angle;
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info"); std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
if (!CheckLastFlee(angle, infoList)) if (!CheckLastFlee(angle, infoList))
{ {
continue; continue;
@@ -2032,9 +2052,9 @@ bool MovementAction::FleePosition(Position pos, float radius)
if (bestPos != Position()) if (bestPos != Position())
{ {
if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false,
false, true)) false, true, false, MovementPriority::MOVEMENT_COMBAT))
{ {
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info"); std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
uint32 curTS = getMSTime(); uint32 curTS = getMSTime();
while (!infoList.empty()) while (!infoList.empty())
{ {
@@ -2346,10 +2366,10 @@ bool MoveOutOfCollisionAction::isUseful()
bool MoveRandomAction::Execute(Event event) bool MoveRandomAction::Execute(Event event)
{ {
float distance = sPlayerbotAIConfig->tooCloseDistance + sPlayerbotAIConfig->grindDistance * urand(3, 10) / 10.0f; float distance = sPlayerbotAIConfig->tooCloseDistance + urand(10, 30);
Map* map = bot->GetMap(); Map* map = bot->GetMap();
for (int i = 0; i < 10; ++i) for (int i = 0; i < 3; ++i)
{ {
float x = bot->GetPositionX(); float x = bot->GetPositionX();
float y = bot->GetPositionY(); float y = bot->GetPositionY();
@@ -2362,11 +2382,7 @@ bool MoveRandomAction::Execute(Event event)
float oz = z; float oz = z;
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
bot->GetPositionZ(), x, y, z)) bot->GetPositionZ(), x, y, z))
{ continue;
x = ox;
y = oy;
z = oz;
}
if (map->IsInWater(bot->GetPhaseMask(), x, y, z, bot->GetCollisionHeight())) if (map->IsInWater(bot->GetPhaseMask(), x, y, z, bot->GetCollisionHeight()))
continue; continue;
@@ -2385,7 +2401,7 @@ bool MoveInsideAction::Execute(Event event) { return MoveInside(bot->GetMapId(),
bool RotateAroundTheCenterPointAction::Execute(Event event) bool RotateAroundTheCenterPointAction::Execute(Event event)
{ {
uint32 next_point = GetCurrWaypoint(); uint32 next_point = GetCurrWaypoint();
if (MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ())) if (MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT))
{ {
call_counters += 1; call_counters += 1;
return true; return true;

View File

@@ -9,6 +9,7 @@
#include <cmath> #include <cmath>
#include "Action.h" #include "Action.h"
#include "LastMovementValue.h"
#include "PlayerbotAIConfig.h" #include "PlayerbotAIConfig.h"
class Player; class Player;
@@ -17,19 +18,20 @@ class Unit;
class WorldObject; class WorldObject;
class Position; class Position;
class MovementAction : public Action class MovementAction : public Action
{ {
public: public:
MovementAction(PlayerbotAI* botAI, std::string const name); MovementAction(PlayerbotAI* botAI, std::string const name);
protected: protected:
void JumpTo(uint32 mapId, float x, float y, float z); bool JumpTo(uint32 mapId, float x, float y, float z, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->contactDistance); bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->contactDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
bool MoveToLOS(WorldObject* target, bool ranged = false); 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 exact_waypoint = false); bool normal_only = false, bool exact_waypoint = false, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
bool MoveTo(Unit* target, float distance = 0.0f); bool MoveTo(Unit* target, float distance = 0.0f, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig->contactDistance); bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig->contactDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
float GetFollowAngle(); float GetFollowAngle();
bool Follow(Unit* target, float distance = sPlayerbotAIConfig->followDistance); bool Follow(Unit* target, float distance = sPlayerbotAIConfig->followDistance);
bool Follow(Unit* target, float distance, float angle); bool Follow(Unit* target, float distance, float angle);
@@ -40,13 +42,13 @@ protected:
bool IsMovingAllowed(Unit* target); bool IsMovingAllowed(Unit* target);
bool IsMovingAllowed(uint32 mapId, float x, float y, float z); bool IsMovingAllowed(uint32 mapId, float x, float y, float z);
bool IsDuplicateMove(uint32 mapId, float x, float y, float z); bool IsDuplicateMove(uint32 mapId, float x, float y, float z);
bool IsWaitingForLastMove(); bool IsWaitingForLastMove(MovementPriority priority);
bool IsMovingAllowed(); bool IsMovingAllowed();
bool Flee(Unit* target); bool Flee(Unit* target);
void ClearIdleState(); void ClearIdleState();
void UpdateMovementState(); void UpdateMovementState();
bool MoveAway(Unit* target); bool MoveAway(Unit* target);
bool MoveInside(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->followDistance); bool MoveInside(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->followDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
void CreateWp(Player* wpOwner, float x, float y, float z, float o, uint32 entry, bool important = false); void CreateWp(Player* wpOwner, float x, float y, float z, float o, uint32 entry, bool important = false);
Position BestPositionForMeleeToFlee(Position pos, float radius); Position BestPositionForMeleeToFlee(Position pos, float radius);
Position BestPositionForRangedToFlee(Position pos, float radius); Position BestPositionForRangedToFlee(Position pos, float radius);
@@ -94,7 +96,7 @@ class AvoidAoeAction : public MovementAction
{ {
public: public:
AvoidAoeAction(PlayerbotAI* botAI, int moveInterval = 1000) AvoidAoeAction(PlayerbotAI* botAI, int moveInterval = 1000)
: MovementAction(botAI, "avoid aoe"), moveInterval(moveInterval) : MovementAction(botAI, "aaoe"), moveInterval(moveInterval)
{ {
} }

View File

@@ -87,7 +87,7 @@ bool SummonAction::Execute(Event event)
if (master->GetSession()->GetSecurity() >= SEC_PLAYER) if (master->GetSession()->GetSecurity() >= SEC_PLAYER)
{ {
// botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({}); // botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
SET_AI_VALUE(std::list<FleeInfo>, "recently flee info", {}); AI_VALUE(std::list<FleeInfo>&, "recently flee info").clear();
return Teleport(master, bot); return Teleport(master, bot);
} }
@@ -215,10 +215,12 @@ bool SummonAction::Teleport(Player* summoner, Player* player)
bool revive = bool revive =
sPlayerbotAIConfig->reviveBotWhenSummoned == 2 || sPlayerbotAIConfig->reviveBotWhenSummoned == 2 ||
(sPlayerbotAIConfig->reviveBotWhenSummoned == 1 && !master->IsInCombat() && master->IsAlive()); (sPlayerbotAIConfig->reviveBotWhenSummoned == 1 && !master->IsInCombat() && master->IsAlive());
if (bot->isDead() && revive) if (bot->isDead() && revive)
{ {
bot->ResurrectPlayer(1.0f, false); bot->ResurrectPlayer(1.0f, false);
botAI->TellMasterNoFacing("I live, again!"); botAI->TellMasterNoFacing("I live, again!");
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
} }
player->GetMotionMaster()->Clear(); player->GetMotionMaster()->Clear();

View File

@@ -1,6 +1,7 @@
#include "RaidNaxxActions.h" #include "RaidNaxxActions.h"
#include "LastMovementValue.h"
#include "ObjectGuid.h" #include "ObjectGuid.h"
#include "PlayerbotAIConfig.h" #include "PlayerbotAIConfig.h"
#include "Playerbots.h" #include "Playerbots.h"
@@ -23,7 +24,7 @@ bool GrobbulusGoBehindAction::Execute(Event event)
float z = boss->GetPositionZ(); float z = boss->GetPositionZ();
float rx = x + cos(orientation) * distance; float rx = x + cos(orientation) * distance;
float ry = y + sin(orientation) * distance; float ry = y + sin(orientation) * distance;
return MoveTo(bot->GetMapId(), rx, ry, z); return MoveTo(bot->GetMapId(), rx, ry, z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
uint32 RotateAroundTheCenterPointAction::FindNearestWaypoint() uint32 RotateAroundTheCenterPointAction::FindNearestWaypoint()
@@ -91,7 +92,7 @@ bool HeiganDanceMeleeAction::Execute(Event event)
} }
assert(curr_safe >= 0 && curr_safe <= 3); assert(curr_safe >= 0 && curr_safe <= 3);
return MoveInside(bot->GetMapId(), waypoints[curr_safe].first, waypoints[curr_safe].second, bot->GetPositionZ(), return MoveInside(bot->GetMapId(), waypoints[curr_safe].first, waypoints[curr_safe].second, bot->GetPositionZ(),
botAI->IsMainTank(bot) ? 0 : 0); botAI->IsMainTank(bot) ? 0 : 0, MovementPriority::MOVEMENT_COMBAT);
} }
bool HeiganDanceRangedAction::Execute(Event event) bool HeiganDanceRangedAction::Execute(Event event)
@@ -99,10 +100,10 @@ bool HeiganDanceRangedAction::Execute(Event event)
CalculateSafe(); CalculateSafe();
if (prev_phase != 1) if (prev_phase != 1)
{ {
return MoveTo(bot->GetMapId(), platform.first, platform.second, 276.54f); return MoveTo(bot->GetMapId(), platform.first, platform.second, 276.54f, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
botAI->InterruptSpell(); botAI->InterruptSpell();
return MoveInside(bot->GetMapId(), waypoints[curr_safe].first, waypoints[curr_safe].second, bot->GetPositionZ(), 0); return MoveInside(bot->GetMapId(), waypoints[curr_safe].first, waypoints[curr_safe].second, bot->GetPositionZ(), 0, MovementPriority::MOVEMENT_COMBAT);
} }
bool ThaddiusAttackNearestPetAction::isUseful() bool ThaddiusAttackNearestPetAction::isUseful()
@@ -128,7 +129,7 @@ bool ThaddiusAttackNearestPetAction::Execute(Event event)
Unit* target = helper.GetNearestPet(); Unit* target = helper.GetNearestPet();
if (!bot->IsWithinLOSInMap(target)) if (!bot->IsWithinLOSInMap(target))
{ {
return MoveTo(target); return MoveTo(target, 0, MovementPriority::MOVEMENT_COMBAT);
} }
if (AI_VALUE(Unit*, "current target") != target) if (AI_VALUE(Unit*, "current target") != target)
{ {
@@ -137,12 +138,12 @@ bool ThaddiusAttackNearestPetAction::Execute(Event event)
if (botAI->IsTank(bot) && AI_VALUE2(bool, "has aggro", "current target")) if (botAI->IsTank(bot) && AI_VALUE2(bool, "has aggro", "current target"))
{ {
std::pair<float, float> posForTank = helper.PetPhaseGetPosForTank(); std::pair<float, float> posForTank = helper.PetPhaseGetPosForTank();
return MoveTo(533, posForTank.first, posForTank.second, helper.tankPosZ); return MoveTo(533, posForTank.first, posForTank.second, helper.tankPosZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
if (botAI->IsRanged(bot)) if (botAI->IsRanged(bot))
{ {
std::pair<float, float> posForRanged = helper.PetPhaseGetPosForRanged(); std::pair<float, float> posForRanged = helper.PetPhaseGetPosForRanged();
return MoveTo(533, posForRanged.first, posForRanged.second, helper.tankPosZ); return MoveTo(533, posForRanged.first, posForRanged.second, helper.tankPosZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
return false; return false;
} }
@@ -170,22 +171,28 @@ bool ThaddiusMoveToPlatformAction::Execute(Event event)
{ {
if (is_left) if (is_left)
{ {
if (!MoveTo(bot->GetMapId(), position[0].first, position[0].second, high_z)) if (!MoveTo(bot->GetMapId(), position[0].first, position[0].second, high_z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT))
{ {
bot->TeleportTo(bot->GetMapId(), position[2].first, position[2].second, low_z, bot->GetOrientation()); float distance = bot->GetExactDist2d(position[0].first, position[0].second);
if (distance < sPlayerbotAIConfig->contactDistance)
JumpTo(bot->GetMapId(), position[2].first, position[2].second, low_z, MovementPriority::MOVEMENT_COMBAT);
// bot->TeleportTo(bot->GetMapId(), position[2].first, position[2].second, low_z, bot->GetOrientation());
} }
} }
else else
{ {
if (!MoveTo(bot->GetMapId(), position[1].first, position[1].second, high_z)) if (!MoveTo(bot->GetMapId(), position[1].first, position[1].second, high_z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT))
{ {
bot->TeleportTo(bot->GetMapId(), position[3].first, position[3].second, low_z, bot->GetOrientation()); float distance = bot->GetExactDist2d(position[1].first, position[1].second);
if (distance < sPlayerbotAIConfig->contactDistance)
JumpTo(bot->GetMapId(), position[3].first, position[3].second, low_z, MovementPriority::MOVEMENT_COMBAT);
// bot->TeleportTo(bot->GetMapId(), position[3].first, position[3].second, low_z, bot->GetOrientation());
} }
} }
} }
else else
{ {
return MoveTo(bot->GetMapId(), position[4].first, position[4].second, low_z); return MoveTo(bot->GetMapId(), position[4].first, position[4].second, low_z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
return true; return true;
} }
@@ -225,7 +232,7 @@ bool ThaddiusMovePolarityAction::Execute(Event event)
idx = 2; idx = 2;
} }
idx = idx * 2 + botAI->IsRanged(bot); idx = idx * 2 + botAI->IsRanged(bot);
return MoveTo(bot->GetMapId(), position[idx].first, position[idx].second, bot->GetPositionZ()); return MoveTo(bot->GetMapId(), position[idx].first, position[idx].second, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
bool RazuviousUseObedienceCrystalAction::Execute(Event event) bool RazuviousUseObedienceCrystalAction::Execute(Event event)
@@ -322,7 +329,7 @@ bool RazuviousUseObedienceCrystalAction::Execute(Event event)
{ {
continue; continue;
} }
if (MoveTo(unit)) if (MoveTo(unit, 0.0f, MovementPriority::MOVEMENT_COMBAT))
{ {
return true; return true;
} }
@@ -352,7 +359,7 @@ bool RazuviousUseObedienceCrystalAction::Execute(Event event)
{ {
if (bot->GetDistance2d(target) > sPlayerbotAIConfig->spellDistance) if (bot->GetDistance2d(target) > sPlayerbotAIConfig->spellDistance)
{ {
return MoveNear(target, sPlayerbotAIConfig->spellDistance); return MoveNear(target, sPlayerbotAIConfig->spellDistance, MovementPriority::MOVEMENT_COMBAT);
} }
else else
{ {
@@ -396,7 +403,7 @@ bool HorsemanAttractAlternativelyAction::Execute(Event event)
} }
helper.CalculatePosToGo(bot); helper.CalculatePosToGo(bot);
auto [posX, posY] = helper.CurrentAttractPos(); auto [posX, posY] = helper.CurrentAttractPos();
if (MoveTo(bot->GetMapId(), posX, posY, helper.posZ)) if (MoveTo(bot->GetMapId(), posX, posY, helper.posZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT))
{ {
return true; return true;
} }
@@ -444,7 +451,7 @@ bool HorsemanAttactInOrderAction::Execute(Event event)
} }
if (!bot->IsWithinLOSInMap(target)) if (!bot->IsWithinLOSInMap(target))
{ {
return MoveNear(target, 22.0f); return MoveNear(target, 22.0f, MovementPriority::MOVEMENT_COMBAT);
} }
return Attack(target); return Attack(target);
} }
@@ -461,7 +468,7 @@ bool SapphironGroundPositionAction::Execute(Event event)
{ {
if (AI_VALUE2(bool, "has aggro", "current target")) if (AI_VALUE2(bool, "has aggro", "current target"))
{ {
return MoveTo(NAXX_MAP_ID, helper.mainTankPos.first, helper.mainTankPos.second, helper.GENERIC_HEIGHT); return MoveTo(NAXX_MAP_ID, helper.mainTankPos.first, helper.mainTankPos.second, helper.GENERIC_HEIGHT, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
return false; return false;
} }
@@ -485,14 +492,14 @@ bool SapphironGroundPositionAction::Execute(Event event)
distance = 5.0f; distance = 5.0f;
} }
return MoveTo(NAXX_MAP_ID, helper.center.first + cos(angle) * distance, return MoveTo(NAXX_MAP_ID, helper.center.first + cos(angle) * distance,
helper.center.second + sin(angle) * distance, helper.GENERIC_HEIGHT); helper.center.second + sin(angle) * distance, helper.GENERIC_HEIGHT, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
else else
{ {
std::vector<float> dest; std::vector<float> dest;
if (helper.FindPosToAvoidChill(dest)) if (helper.FindPosToAvoidChill(dest))
{ {
return MoveTo(NAXX_MAP_ID, dest[0], dest[1], dest[2]); return MoveTo(NAXX_MAP_ID, dest[0], dest[1], dest[2], false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
} }
return false; return false;
@@ -513,7 +520,7 @@ bool SapphironFlightPositionAction::Execute(Event event)
std::vector<float> dest; std::vector<float> dest;
if (helper.FindPosToAvoidChill(dest)) if (helper.FindPosToAvoidChill(dest))
{ {
return MoveTo(NAXX_MAP_ID, dest[0], dest[1], dest[2]); return MoveTo(NAXX_MAP_ID, dest[0], dest[1], dest[2], false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
} }
return false; return false;
@@ -548,7 +555,7 @@ bool SapphironFlightPositionAction::MoveToNearestIcebolt()
{ {
float angle = boss->GetAngle(playerWithIcebolt); float angle = boss->GetAngle(playerWithIcebolt);
return MoveTo(NAXX_MAP_ID, playerWithIcebolt->GetPositionX() + cos(angle) * 3.0f, return MoveTo(NAXX_MAP_ID, playerWithIcebolt->GetPositionX() + cos(angle) * 3.0f,
playerWithIcebolt->GetPositionY() + sin(angle) * 3.0f, helper.GENERIC_HEIGHT); playerWithIcebolt->GetPositionY() + sin(angle) * 3.0f, helper.GENERIC_HEIGHT, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
} }
return false; return false;
@@ -679,7 +686,7 @@ bool KelthuzadPositionAction::Execute(Event event)
{ {
if (AI_VALUE(Unit*, "current target") == nullptr) if (AI_VALUE(Unit*, "current target") == nullptr)
{ {
return MoveInside(NAXX_MAP_ID, helper.center.first, helper.center.second, bot->GetPositionZ(), 3.0f); return MoveInside(NAXX_MAP_ID, helper.center.first, helper.center.second, bot->GetPositionZ(), 3.0f, MovementPriority::MOVEMENT_COMBAT);
} }
} }
else if (helper.IsPhaseTwo()) else if (helper.IsPhaseTwo())
@@ -692,7 +699,7 @@ bool KelthuzadPositionAction::Execute(Event event)
{ {
if (AI_VALUE2(bool, "has aggro", "current target")) if (AI_VALUE2(bool, "has aggro", "current target"))
{ {
return MoveTo(NAXX_MAP_ID, helper.tank_pos.first, helper.tank_pos.second, bot->GetPositionZ()); return MoveTo(NAXX_MAP_ID, helper.tank_pos.first, helper.tank_pos.second, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
else else
{ {
@@ -715,7 +722,7 @@ bool KelthuzadPositionAction::Execute(Event event)
float dx, dy; float dx, dy;
dx = helper.center.first + cos(angle) * distance; dx = helper.center.first + cos(angle) * distance;
dy = helper.center.second + sin(angle) * distance; dy = helper.center.second + sin(angle) * distance;
return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ()); return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
else if (botAI->IsTank(bot)) else if (botAI->IsTank(bot))
{ {
@@ -725,7 +732,7 @@ bool KelthuzadPositionAction::Execute(Event event)
botAI->IsAssistTank(cur_tar->GetVictim()->ToPlayer())) botAI->IsAssistTank(cur_tar->GetVictim()->ToPlayer()))
{ {
return MoveTo(NAXX_MAP_ID, helper.assist_tank_pos.first, helper.assist_tank_pos.second, return MoveTo(NAXX_MAP_ID, helper.assist_tank_pos.first, helper.assist_tank_pos.second,
bot->GetPositionZ()); bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
else else
{ {
@@ -747,7 +754,7 @@ bool KelthuzadPositionAction::Execute(Event event)
} }
dx = shadow_fissure->GetPositionX() + cos(angle) * 10.0f; dx = shadow_fissure->GetPositionX() + cos(angle) * 10.0f;
dy = shadow_fissure->GetPositionY() + sin(angle) * 10.0f; dy = shadow_fissure->GetPositionY() + sin(angle) * 10.0f;
return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ()); return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
} }
return false; return false;
@@ -846,11 +853,11 @@ bool AnubrekhanPositionAction::Execute(Event event)
next_point = nearest; next_point = nearest;
} }
return MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, return MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second,
bot->GetPositionZ()); bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
else else
{ {
return MoveInside(533, 3272.49f, -3476.27f, bot->GetPositionZ(), 3.0f); return MoveInside(533, 3272.49f, -3476.27f, bot->GetPositionZ(), 3.0f, MovementPriority::MOVEMENT_COMBAT);
} }
} }
return false; return false;
@@ -964,12 +971,12 @@ bool GluthPositionAction::Execute(Event event)
if (raid25) if (raid25)
{ {
return MoveTo(NAXX_MAP_ID, helper.mainTankPos25.first, helper.mainTankPos25.second, return MoveTo(NAXX_MAP_ID, helper.mainTankPos25.first, helper.mainTankPos25.second,
bot->GetPositionZ()); bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
else else
{ {
return MoveTo(NAXX_MAP_ID, helper.mainTankPos10.first, helper.mainTankPos10.second, return MoveTo(NAXX_MAP_ID, helper.mainTankPos10.first, helper.mainTankPos10.second,
bot->GetPositionZ()); bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
} }
} }
@@ -978,7 +985,7 @@ bool GluthPositionAction::Execute(Event event)
if (helper.BeforeDecimate()) if (helper.BeforeDecimate())
{ {
return MoveTo(bot->GetMapId(), helper.beforeDecimatePos.first, helper.beforeDecimatePos.second, return MoveTo(bot->GetMapId(), helper.beforeDecimatePos.first, helper.beforeDecimatePos.second,
bot->GetPositionZ()); bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
else else
{ {
@@ -987,7 +994,7 @@ bool GluthPositionAction::Execute(Event event)
uint32 nearest = FindNearestWaypoint(); uint32 nearest = FindNearestWaypoint();
uint32 next_point = (nearest + 1) % intervals; uint32 next_point = (nearest + 1) % intervals;
return MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, return MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second,
bot->GetPositionZ()); bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
} }
} }
@@ -998,19 +1005,19 @@ bool GluthPositionAction::Execute(Event event)
if (botAI->GetClassIndex(bot, CLASS_HUNTER) == 0) if (botAI->GetClassIndex(bot, CLASS_HUNTER) == 0)
{ {
return MoveInside(NAXX_MAP_ID, helper.leftSlowDownPos.first, helper.leftSlowDownPos.second, return MoveInside(NAXX_MAP_ID, helper.leftSlowDownPos.first, helper.leftSlowDownPos.second,
bot->GetPositionZ(), 0.0f); bot->GetPositionZ(), 0.0f, MovementPriority::MOVEMENT_COMBAT);
} }
if (botAI->GetClassIndex(bot, CLASS_HUNTER) == 1) if (botAI->GetClassIndex(bot, CLASS_HUNTER) == 1)
{ {
return MoveInside(NAXX_MAP_ID, helper.rightSlowDownPos.first, helper.rightSlowDownPos.second, return MoveInside(NAXX_MAP_ID, helper.rightSlowDownPos.first, helper.rightSlowDownPos.second,
bot->GetPositionZ(), 0.0f); bot->GetPositionZ(), 0.0f, MovementPriority::MOVEMENT_COMBAT);
} }
} }
return MoveInside(NAXX_MAP_ID, helper.rangedPos.first, helper.rangedPos.second, bot->GetPositionZ(), 3.0f); return MoveInside(NAXX_MAP_ID, helper.rangedPos.first, helper.rangedPos.second, bot->GetPositionZ(), 3.0f, MovementPriority::MOVEMENT_COMBAT);
} }
else if (botAI->IsHeal(bot)) else if (botAI->IsHeal(bot))
{ {
return MoveInside(NAXX_MAP_ID, helper.healPos.first, helper.healPos.second, bot->GetPositionZ(), 0.0f); return MoveInside(NAXX_MAP_ID, helper.healPos.first, helper.healPos.second, bot->GetPositionZ(), 0.0f, MovementPriority::MOVEMENT_COMBAT);
} }
return false; return false;
} }
@@ -1051,12 +1058,12 @@ bool LoathebPositionAction::Execute(Event event)
{ {
if (AI_VALUE2(bool, "has aggro", "boss target")) if (AI_VALUE2(bool, "has aggro", "boss target"))
{ {
return MoveTo(533, helper.mainTankPos.first, helper.mainTankPos.second, bot->GetPositionZ()); return MoveTo(533, helper.mainTankPos.first, helper.mainTankPos.second, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
} }
} }
else if (botAI->IsRanged(bot)) else if (botAI->IsRanged(bot))
{ {
return MoveInside(533, helper.rangePos.first, helper.rangePos.second, bot->GetPositionZ(), 1.0f); return MoveInside(533, helper.rangePos.first, helper.rangePos.second, bot->GetPositionZ(), 1.0f, MovementPriority::MOVEMENT_COMBAT);
} }
return false; return false;
} }

View File

@@ -24,6 +24,7 @@ LastMovement::LastMovement(LastMovement& other)
lastMoveShort = other.lastMoveShort; lastMoveShort = other.lastMoveShort;
nextTeleport = other.nextTeleport; nextTeleport = other.nextTeleport;
lastPath = other.lastPath; lastPath = other.lastPath;
priority = other.priority;
} }
void LastMovement::clear() void LastMovement::clear()
@@ -41,6 +42,7 @@ void LastMovement::clear()
nextTeleport = 0; nextTeleport = 0;
msTime = 0; msTime = 0;
lastdelayTime = 0; lastdelayTime = 0;
priority = MovementPriority::MOVEMENT_NORMAL;
} }
void LastMovement::Set(Unit* follow) void LastMovement::Set(Unit* follow)
@@ -51,7 +53,7 @@ void LastMovement::Set(Unit* follow)
lastFollow = follow; lastFollow = follow;
} }
void LastMovement::Set(uint32 mapId, float x, float y, float z, float ori, float delayTime) void LastMovement::Set(uint32 mapId, float x, float y, float z, float ori, float delayTime, MovementPriority pri)
{ {
lastMoveToMapId = mapId; lastMoveToMapId = mapId;
lastMoveToX = x; lastMoveToX = x;
@@ -62,6 +64,7 @@ void LastMovement::Set(uint32 mapId, float x, float y, float z, float ori, float
lastMoveShort = WorldPosition(mapId, x, y, z, ori); lastMoveShort = WorldPosition(mapId, x, y, z, ori);
msTime = getMSTime(); msTime = getMSTime();
lastdelayTime = delayTime; lastdelayTime = delayTime;
priority = pri;
} }
void LastMovement::setShort(WorldPosition point) void LastMovement::setShort(WorldPosition point)

View File

@@ -13,6 +13,15 @@
class PlayerbotAI; class PlayerbotAI;
class Unit; class Unit;
// High priority movement can override the previous low priority one
enum class MovementPriority
{
MOVEMENT_IDLE,
MOVEMENT_NORMAL,
MOVEMENT_COMBAT,
MOVEMENT_FORCED
};
class LastMovement class LastMovement
{ {
public: public:
@@ -28,14 +37,14 @@ public:
lastMoveShort = other.lastMoveShort; lastMoveShort = other.lastMoveShort;
lastPath = other.lastPath; lastPath = other.lastPath;
nextTeleport = other.nextTeleport; nextTeleport = other.nextTeleport;
priority = other.priority;
return *this; return *this;
}; };
void clear(); void clear();
void Set(Unit* follow); void Set(Unit* follow);
void Set(uint32 mapId, float x, float y, float z, float ori, float delayTime); void Set(uint32 mapId, float x, float y, float z, float ori, float delayTime, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
void setShort(WorldPosition point); void setShort(WorldPosition point);
void setPath(TravelPath path); void setPath(TravelPath path);
@@ -53,6 +62,7 @@ public:
float lastdelayTime; float lastdelayTime;
WorldPosition lastMoveShort; WorldPosition lastMoveShort;
uint32 msTime; uint32 msTime;
MovementPriority priority;
TravelPath lastPath; TravelPath lastPath;
time_t nextTeleport; time_t nextTeleport;
std::future<TravelPath> future; std::future<TravelPath> future;