|
|
|
|
@@ -192,30 +192,23 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool generatePath = !bot->IsFlying() && !bot->isSwimming();
|
|
|
|
|
bool disableMoveSplinePath = sPlayerbotAIConfig->disableMoveSplinePath >= 2 ||
|
|
|
|
|
(sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground());
|
|
|
|
|
bool disableMoveSplinePath =
|
|
|
|
|
sPlayerbotAIConfig->disableMoveSplinePath >= 2 ||
|
|
|
|
|
(sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground());
|
|
|
|
|
if (Vehicle* vehicle = bot->GetVehicle())
|
|
|
|
|
{
|
|
|
|
|
VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(bot);
|
|
|
|
|
Unit* vehicleBase = vehicle->GetBase();
|
|
|
|
|
generatePath = vehicleBase->CanFly();
|
|
|
|
|
generatePath = !vehicleBase || !vehicleBase->CanFly();
|
|
|
|
|
if (!vehicleBase || !seat || !seat->CanControl()) // is passenger and cant move anyway
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
float distance = vehicleBase->GetExactDist(x, y, z); // use vehicle distance, not bot
|
|
|
|
|
if (distance > 0.01f)
|
|
|
|
|
{
|
|
|
|
|
MotionMaster& mm = *vehicleBase->GetMotionMaster(); // need to move vehicle, not bot
|
|
|
|
|
mm.Clear();
|
|
|
|
|
if (!backwards)
|
|
|
|
|
{
|
|
|
|
|
mm.MovePoint(0, x, y, z, generatePath);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mm.MovePointBackwards(0, x, y, z, generatePath);
|
|
|
|
|
}
|
|
|
|
|
DoMovePoint(vehicleBase, x, y, z, generatePath, backwards);
|
|
|
|
|
float speed = backwards ? vehicleBase->GetSpeed(MOVE_RUN_BACK) : vehicleBase->GetSpeed(MOVE_RUN);
|
|
|
|
|
float delay = 1000.0f * (distance / speed);
|
|
|
|
|
if (lessDelay)
|
|
|
|
|
@@ -241,16 +234,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|
|
|
|
// bot->CastStop();
|
|
|
|
|
// botAI->InterruptSpell();
|
|
|
|
|
// }
|
|
|
|
|
MotionMaster& mm = *bot->GetMotionMaster();
|
|
|
|
|
mm.Clear();
|
|
|
|
|
if (!backwards)
|
|
|
|
|
{
|
|
|
|
|
mm.MovePoint(0, x, y, z, generatePath);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mm.MovePointBackwards(0, x, y, z, generatePath);
|
|
|
|
|
}
|
|
|
|
|
DoMovePoint(bot, x, y, z, generatePath, backwards);
|
|
|
|
|
float delay = 1000.0f * MoveDelay(distance, backwards);
|
|
|
|
|
if (lessDelay)
|
|
|
|
|
{
|
|
|
|
|
@@ -268,9 +252,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|
|
|
|
Movement::PointsArray path =
|
|
|
|
|
SearchForBestPath(x, y, z, modifiedZ, sPlayerbotAIConfig->maxMovementSearchTime, normal_only);
|
|
|
|
|
if (modifiedZ == INVALID_HEIGHT)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
float distance = bot->GetExactDist(x, y, modifiedZ);
|
|
|
|
|
if (distance > 0.01f)
|
|
|
|
|
{
|
|
|
|
|
@@ -282,17 +264,8 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|
|
|
|
// bot->CastStop();
|
|
|
|
|
// botAI->InterruptSpell();
|
|
|
|
|
// }
|
|
|
|
|
MotionMaster& mm = *bot->GetMotionMaster();
|
|
|
|
|
G3D::Vector3 endP = path.back();
|
|
|
|
|
mm.Clear();
|
|
|
|
|
if (!backwards)
|
|
|
|
|
{
|
|
|
|
|
mm.MovePoint(0, x, y, z, generatePath);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mm.MovePointBackwards(0, x, y, z, generatePath);
|
|
|
|
|
}
|
|
|
|
|
DoMovePoint(bot, x, y, z, generatePath, backwards);
|
|
|
|
|
float delay = 1000.0f * MoveDelay(distance, backwards);
|
|
|
|
|
if (lessDelay)
|
|
|
|
|
{
|
|
|
|
|
@@ -509,7 +482,8 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|
|
|
|
// {
|
|
|
|
|
// AI_VALUE(LastMovement&, "last area trigger").lastAreaTrigger = entry;
|
|
|
|
|
// }
|
|
|
|
|
// else {
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
// LOG_DEBUG("playerbots", "!entry");
|
|
|
|
|
// return bot->TeleportTo(movePosition.getMapId(), movePosition.getX(), movePosition.getY(),
|
|
|
|
|
// movePosition.getZ(), movePosition.getO(), 0);
|
|
|
|
|
@@ -559,9 +533,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|
|
|
|
// bool goTaxi = bot->ActivateTaxiPathTo({ tEntry->from, tEntry->to }, unit, 1);
|
|
|
|
|
|
|
|
|
|
// if (botAI->HasCheat(BotCheatMask::gold))
|
|
|
|
|
// {
|
|
|
|
|
// bot->SetMoney(botMoney);
|
|
|
|
|
// }
|
|
|
|
|
// LOG_DEBUG("playerbots", "goTaxi");
|
|
|
|
|
// return goTaxi;
|
|
|
|
|
// }
|
|
|
|
|
@@ -988,7 +960,8 @@ bool MovementAction::IsMovingAllowed()
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if (bot->HasUnitMovementFlag(MOVEMENTFLAG_FALLING)) {
|
|
|
|
|
// if (bot->HasUnitMovementFlag(MOVEMENTFLAG_FALLING))
|
|
|
|
|
// {
|
|
|
|
|
// return false;
|
|
|
|
|
// }
|
|
|
|
|
return bot->GetMotionMaster()->GetCurrentMovementGeneratorType() != FLIGHT_MOTION_TYPE;
|
|
|
|
|
@@ -998,54 +971,95 @@ bool MovementAction::Follow(Unit* target, float distance) { return Follow(target
|
|
|
|
|
|
|
|
|
|
void MovementAction::UpdateMovementState()
|
|
|
|
|
{
|
|
|
|
|
int8 botInLiquidState = bot->GetLiquidData().Status;
|
|
|
|
|
const bool isCurrentlyRestricted = // see if the bot is currently slowed, rooted, or otherwise unable to move
|
|
|
|
|
bot->isFrozen() ||
|
|
|
|
|
bot->IsPolymorphed() ||
|
|
|
|
|
bot->HasRootAura() ||
|
|
|
|
|
bot->HasStunAura() ||
|
|
|
|
|
bot->HasConfuseAura() ||
|
|
|
|
|
bot->HasUnitState(UNIT_STATE_LOST_CONTROL);
|
|
|
|
|
|
|
|
|
|
if (botInLiquidState == LIQUID_MAP_IN_WATER || botInLiquidState == LIQUID_MAP_UNDER_WATER)
|
|
|
|
|
// no update movement flags while movement is current restricted.
|
|
|
|
|
if (!isCurrentlyRestricted && bot->IsAlive())
|
|
|
|
|
{
|
|
|
|
|
bot->SetSwim(true);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bot->SetSwim(false);
|
|
|
|
|
// state flags
|
|
|
|
|
const auto master = botAI ? botAI->GetMaster() : nullptr; // real player or not
|
|
|
|
|
const bool masterIsFlying = master ? master->HasUnitMovementFlag(MOVEMENTFLAG_FLYING) : true;
|
|
|
|
|
const bool masterIsSwimming = master ? master->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING) : true;
|
|
|
|
|
const auto liquidState = bot->GetLiquidData().Status; // default LIQUID_MAP_NO_WATER
|
|
|
|
|
const float gZ = bot->GetMapWaterOrGroundLevel(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
|
|
|
|
|
const bool wantsToFly = bot->HasIncreaseMountedFlightSpeedAura() || bot->HasFlyAura();
|
|
|
|
|
const bool isFlying = bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
|
|
|
|
const bool isWaterArea = liquidState != LIQUID_MAP_NO_WATER;
|
|
|
|
|
const bool isUnderWater = liquidState == LIQUID_MAP_UNDER_WATER;
|
|
|
|
|
const bool isInWater = liquidState == LIQUID_MAP_IN_WATER;
|
|
|
|
|
const bool isWaterWalking = bot->HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
|
|
|
|
|
const bool isSwimming = bot->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
|
|
|
|
|
const bool wantsToWaterWalk = bot->HasWaterWalkAura();
|
|
|
|
|
const bool wantsToSwim = isInWater || isUnderWater;
|
|
|
|
|
const bool onGroundZ = (bot->GetPositionZ() < gZ + 1.f) && !isWaterArea;
|
|
|
|
|
bool movementFlagsUpdated = false;
|
|
|
|
|
|
|
|
|
|
// handle water state
|
|
|
|
|
if (isWaterArea && !isFlying)
|
|
|
|
|
{
|
|
|
|
|
// water walking
|
|
|
|
|
if (wantsToWaterWalk && !isWaterWalking && !masterIsSwimming)
|
|
|
|
|
{
|
|
|
|
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
|
|
|
|
|
bot->AddUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
|
|
|
|
|
movementFlagsUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
// swimming
|
|
|
|
|
else if (wantsToSwim && !isSwimming && masterIsSwimming)
|
|
|
|
|
{
|
|
|
|
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
|
|
|
|
|
bot->AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
|
|
|
|
|
movementFlagsUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (isSwimming || isWaterWalking)
|
|
|
|
|
{
|
|
|
|
|
// reset water flags
|
|
|
|
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
|
|
|
|
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
|
|
|
|
|
movementFlagsUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handle flying state
|
|
|
|
|
if (wantsToFly && !isFlying && masterIsFlying)
|
|
|
|
|
{
|
|
|
|
|
bot->AddUnitMovementFlag(MOVEMENTFLAG_CAN_FLY);
|
|
|
|
|
bot->AddUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
|
|
|
|
|
bot->AddUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
|
|
|
|
movementFlagsUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
else if ((!wantsToFly || onGroundZ) && isFlying)
|
|
|
|
|
{
|
|
|
|
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_CAN_FLY);
|
|
|
|
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
|
|
|
|
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
|
|
|
|
movementFlagsUpdated = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// detect if movement restrictions have been lifted, CC just ended.
|
|
|
|
|
if (wasMovementRestricted)
|
|
|
|
|
movementFlagsUpdated = true; // refresh movement state to ensure animations play correctly
|
|
|
|
|
|
|
|
|
|
if (movementFlagsUpdated)
|
|
|
|
|
bot->SendMovementFlagUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool onGround = bot->GetPositionZ() <
|
|
|
|
|
bot->GetMapWaterOrGroundLevel(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()) + 1.0f;
|
|
|
|
|
|
|
|
|
|
// Keep bot->SendMovementFlagUpdate() withing the if statements to not intefere with bot behavior on
|
|
|
|
|
// ground/(shallow) waters
|
|
|
|
|
if (!bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING) &&
|
|
|
|
|
bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !onGround)
|
|
|
|
|
{
|
|
|
|
|
bot->AddUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
|
|
|
|
bot->SendMovementFlagUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING) &&
|
|
|
|
|
(!bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || onGround))
|
|
|
|
|
{
|
|
|
|
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
|
|
|
|
bot->SendMovementFlagUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// See if the bot is currently slowed, rooted, or otherwise unable to move
|
|
|
|
|
bool isCurrentlyRestricted = bot->isFrozen() || bot->IsPolymorphed() || bot->HasRootAura() || bot->HasStunAura() ||
|
|
|
|
|
bot->HasConfuseAura() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL);
|
|
|
|
|
|
|
|
|
|
// Detect if movement restrictions have been lifted
|
|
|
|
|
if (wasMovementRestricted && !isCurrentlyRestricted && bot->IsAlive())
|
|
|
|
|
{
|
|
|
|
|
// CC just ended - refresh movement state to ensure animations play correctly
|
|
|
|
|
bot->SendMovementFlagUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save current state for the next check
|
|
|
|
|
// Save current state for the next check
|
|
|
|
|
wasMovementRestricted = isCurrentlyRestricted;
|
|
|
|
|
|
|
|
|
|
// Temporary speed increase in group
|
|
|
|
|
// if (botAI->HasRealPlayerMaster()) {
|
|
|
|
|
// if (botAI->HasRealPlayerMaster())
|
|
|
|
|
// {
|
|
|
|
|
// bot->SetSpeedRate(MOVE_RUN, 1.1f);
|
|
|
|
|
// } else {
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
// bot->SetSpeedRate(MOVE_RUN, 1.0f);
|
|
|
|
|
// }
|
|
|
|
|
// check if target is not reachable (from Vmangos)
|
|
|
|
|
@@ -1054,7 +1068,7 @@ void MovementAction::UpdateMovementState()
|
|
|
|
|
// {
|
|
|
|
|
// if (Unit* pTarget = sServerFacade->GetChaseTarget(bot))
|
|
|
|
|
// {
|
|
|
|
|
// if (!bot->IsWithinMeleeRange(pTarget) && pTarget->GetTypeId() == TYPEID_UNIT)
|
|
|
|
|
// if (!bot->IsWithinMeleeRange(pTarget) && pTarget->IsCreature())
|
|
|
|
|
// {
|
|
|
|
|
// float angle = bot->GetAngle(pTarget);
|
|
|
|
|
// float distance = 5.0f;
|
|
|
|
|
@@ -1682,7 +1696,8 @@ bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float d
|
|
|
|
|
// float MovementAction::SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range, bool
|
|
|
|
|
// normal_only, float step)
|
|
|
|
|
// {
|
|
|
|
|
// if (!generatePath) {
|
|
|
|
|
// if (!generatePath)
|
|
|
|
|
// {
|
|
|
|
|
// return z;
|
|
|
|
|
// }
|
|
|
|
|
// float min_length = 100000.0f;
|
|
|
|
|
@@ -1693,10 +1708,12 @@ bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float d
|
|
|
|
|
// modified_z = bot->GetMapWaterOrGroundLevel(x, y, z + delta);
|
|
|
|
|
// PathGenerator gen(bot);
|
|
|
|
|
// gen.CalculatePath(x, y, modified_z);
|
|
|
|
|
// if (gen.GetPathType() == PATHFIND_NORMAL && gen.getPathLength() < min_length) {
|
|
|
|
|
// if (gen.GetPathType() == PATHFIND_NORMAL && gen.getPathLength() < min_length)
|
|
|
|
|
// {
|
|
|
|
|
// min_length = gen.getPathLength();
|
|
|
|
|
// current_z = modified_z;
|
|
|
|
|
// if (abs(current_z - z) < 0.5f) {
|
|
|
|
|
// if (abs(current_z - z) < 0.5f)
|
|
|
|
|
// {
|
|
|
|
|
// return current_z;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
@@ -1705,30 +1722,34 @@ bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float d
|
|
|
|
|
// modified_z = bot->GetMapWaterOrGroundLevel(x, y, z + delta);
|
|
|
|
|
// PathGenerator gen(bot);
|
|
|
|
|
// gen.CalculatePath(x, y, modified_z);
|
|
|
|
|
// if (gen.GetPathType() == PATHFIND_NORMAL && gen.getPathLength() < min_length) {
|
|
|
|
|
// if (gen.GetPathType() == PATHFIND_NORMAL && gen.getPathLength() < min_length)
|
|
|
|
|
// {
|
|
|
|
|
// min_length = gen.getPathLength();
|
|
|
|
|
// current_z = modified_z;
|
|
|
|
|
// if (abs(current_z - z) < 0.5f) {
|
|
|
|
|
// if (abs(current_z - z) < 0.5f)
|
|
|
|
|
// return current_z;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// for (delta = range / 2 + step; delta <= range; delta += 2) {
|
|
|
|
|
// modified_z = bot->GetMapWaterOrGroundLevel(x, y, z + delta);
|
|
|
|
|
// PathGenerator gen(bot);
|
|
|
|
|
// gen.CalculatePath(x, y, modified_z);
|
|
|
|
|
// if (gen.GetPathType() == PATHFIND_NORMAL && gen.getPathLength() < min_length) {
|
|
|
|
|
// if (gen.GetPathType() == PATHFIND_NORMAL && gen.getPathLength() < min_length)
|
|
|
|
|
// {
|
|
|
|
|
// min_length = gen.getPathLength();
|
|
|
|
|
// current_z = modified_z;
|
|
|
|
|
// if (abs(current_z - z) < 0.5f) {
|
|
|
|
|
// if (abs(current_z - z) < 0.5f)
|
|
|
|
|
// {
|
|
|
|
|
// return current_z;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// if (current_z == INVALID_HEIGHT && normal_only) {
|
|
|
|
|
// if (current_z == INVALID_HEIGHT && normal_only)
|
|
|
|
|
// {
|
|
|
|
|
// return INVALID_HEIGHT;
|
|
|
|
|
// }
|
|
|
|
|
// if (current_z == INVALID_HEIGHT && !normal_only) {
|
|
|
|
|
// if (current_z == INVALID_HEIGHT && !normal_only)
|
|
|
|
|
// {
|
|
|
|
|
// return z;
|
|
|
|
|
// }
|
|
|
|
|
// return current_z;
|
|
|
|
|
@@ -1803,6 +1824,46 @@ const Movement::PointsArray MovementAction::SearchForBestPath(float x, float y,
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MovementAction::DoMovePoint(Unit* unit, float x, float y, float z, bool generatePath, bool backwards)
|
|
|
|
|
{
|
|
|
|
|
if (!unit)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
MotionMaster* mm = unit->GetMotionMaster();
|
|
|
|
|
if (!mm)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// enable water walking
|
|
|
|
|
if (unit->HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING))
|
|
|
|
|
{
|
|
|
|
|
float gZ = unit->GetMapWaterOrGroundLevel(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ());
|
|
|
|
|
unit->UpdatePosition(unit->GetPositionX(), unit->GetPositionY(), gZ, false);
|
|
|
|
|
// z = gZ; no overwrite Z axe otherwise you cant steer the bots into swimming when water walking.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mm->Clear();
|
|
|
|
|
if (backwards)
|
|
|
|
|
{
|
|
|
|
|
mm->MovePointBackwards(
|
|
|
|
|
/*id*/ 0,
|
|
|
|
|
/*coords*/ x, y, z,
|
|
|
|
|
/*generatePath*/ generatePath,
|
|
|
|
|
/*forceDestination*/ false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mm->MovePoint(
|
|
|
|
|
/*id*/ 0,
|
|
|
|
|
/*coords*/ x, y, z,
|
|
|
|
|
/*forcedMovement*/ FORCED_MOVEMENT_NONE,
|
|
|
|
|
/*speed*/ 0.f,
|
|
|
|
|
/*orientation*/ 0.f,
|
|
|
|
|
/*generatePath*/ generatePath, // true => terrain path (2d mmap); false => straight spline (3d vmap)
|
|
|
|
|
/*forceDestination*/ false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FleeAction::Execute(Event event)
|
|
|
|
|
{
|
|
|
|
|
return MoveAway(AI_VALUE(Unit*, "current target"), sPlayerbotAIConfig->fleeDistance, true);
|
|
|
|
|
@@ -2063,8 +2124,8 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius)
|
|
|
|
|
if (currentTarget)
|
|
|
|
|
{
|
|
|
|
|
// Normally, move to left or right is the best position
|
|
|
|
|
bool isTanking =
|
|
|
|
|
(!currentTarget->isFrozen() && !currentTarget->HasRootAura()) && (currentTarget->GetVictim() == bot);
|
|
|
|
|
bool isTanking = (!currentTarget->isFrozen()
|
|
|
|
|
&& !currentTarget->HasRootAura()) && (currentTarget->GetVictim() == bot);
|
|
|
|
|
float angle = bot->GetAngle(currentTarget);
|
|
|
|
|
float angleLeft = angle + (float)M_PI / 2;
|
|
|
|
|
float angleRight = angle - (float)M_PI / 2;
|
|
|
|
|
@@ -2480,9 +2541,7 @@ bool RearFlankAction::isUseful()
|
|
|
|
|
{
|
|
|
|
|
Unit* target = AI_VALUE(Unit*, "current target");
|
|
|
|
|
if (!target)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Need to double the front angle check to account for mirrored angle.
|
|
|
|
|
bool inFront = target->HasInArc(2.f * minAngle, bot);
|
|
|
|
|
@@ -2497,9 +2556,7 @@ bool RearFlankAction::Execute(Event event)
|
|
|
|
|
{
|
|
|
|
|
Unit* target = AI_VALUE(Unit*, "current target");
|
|
|
|
|
if (!target)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float angle = frand(minAngle, maxAngle);
|
|
|
|
|
float baseDistance = bot->GetMeleeRange(target) * 0.5f;
|
|
|
|
|
@@ -2793,7 +2850,7 @@ bool MoveAwayFromCreatureAction::Execute(Event event)
|
|
|
|
|
|
|
|
|
|
// Find all creatures with the specified Id
|
|
|
|
|
std::vector<Unit*> creatures;
|
|
|
|
|
for (const auto& guid : targets)
|
|
|
|
|
for (auto const& guid : targets)
|
|
|
|
|
{
|
|
|
|
|
Unit* unit = botAI->GetUnit(guid);
|
|
|
|
|
if (unit && (alive && unit->IsAlive()) && unit->GetEntry() == creatureId)
|
|
|
|
|
|