mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Compare commits
2 Commits
ce2a990495
...
05057ae9b5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05057ae9b5 | ||
|
|
610a032379 |
@@ -40,7 +40,14 @@ bool ReachAreaTriggerAction::Execute(Event event)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bot->GetMotionMaster()->MovePoint(at->map, at->x, at->y, at->z);
|
bot->GetMotionMaster()->MovePoint(
|
||||||
|
/*id*/ at->map,
|
||||||
|
/*coords*/ at->x, at->y, at->z,
|
||||||
|
/*forcedMovement*/ FORCED_MOVEMENT_NONE,
|
||||||
|
/*speed*/ 0.0f, // default speed (not handled here)
|
||||||
|
/*orientation*/ 0.0f, // keep current orientation of bot
|
||||||
|
/*generatePath*/ true, // true => terrain path (2d mmap); false => straight spline (3d vmap)
|
||||||
|
/*forceDestination*/ false);
|
||||||
|
|
||||||
float distance = bot->GetDistance(at->x, at->y, at->z);
|
float distance = bot->GetDistance(at->x, at->y, at->z);
|
||||||
float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig->reactDelay;
|
float delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig->reactDelay;
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ bool CheckMountStateAction::isUseful()
|
|||||||
// to mostly be an issue in tunnels of WSG and AV)
|
// to mostly be an issue in tunnels of WSG and AV)
|
||||||
float posZ = bot->GetPositionZ();
|
float posZ = bot->GetPositionZ();
|
||||||
float groundLevel = bot->GetMapWaterOrGroundLevel(bot->GetPositionX(), bot->GetPositionY(), posZ);
|
float groundLevel = bot->GetMapWaterOrGroundLevel(bot->GetPositionX(), bot->GetPositionY(), posZ);
|
||||||
if (!bot->IsMounted() && posZ < groundLevel)
|
if (!bot->IsMounted() && !bot->HasWaterWalkAura() && posZ < groundLevel)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Not useful when bot does not have mount strat and is not currently mounted
|
// Not useful when bot does not have mount strat and is not currently mounted
|
||||||
@@ -122,18 +122,21 @@ bool CheckMountStateAction::Execute(Event /*event*/)
|
|||||||
bool shouldMount = false;
|
bool shouldMount = false;
|
||||||
|
|
||||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||||
if (currentTarget)
|
bool masterInCombat = master && master->IsInCombat();
|
||||||
|
|
||||||
|
if (currentTarget && (bot->IsInCombat() || masterInCombat))
|
||||||
{
|
{
|
||||||
|
// Use target-based logic if bot is in combat OR master is in combat and needs assistance
|
||||||
float dismountDistance = CalculateDismountDistance();
|
float dismountDistance = CalculateDismountDistance();
|
||||||
float mountDistance = CalculateMountDistance();
|
float mountDistance = CalculateMountDistance();
|
||||||
float combatReach = bot->GetCombatReach() + currentTarget->GetCombatReach();
|
|
||||||
float distanceToTarget = bot->GetExactDist(currentTarget);
|
float distanceToTarget = bot->GetExactDist(currentTarget);
|
||||||
|
|
||||||
shouldDismount = (distanceToTarget <= dismountDistance + combatReach);
|
shouldDismount = (distanceToTarget <= dismountDistance);
|
||||||
shouldMount = (distanceToTarget > mountDistance + combatReach);
|
shouldMount = (distanceToTarget > mountDistance);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// If neither bot nor master is in combat, prioritize master-following
|
||||||
shouldMount = true;
|
shouldMount = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,10 +163,19 @@ bool CheckMountStateAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
else if (ShouldDismountForMaster(master) && bot->IsMounted())
|
else if (ShouldDismountForMaster(master) && bot->IsMounted())
|
||||||
{
|
{
|
||||||
|
// If master dismounted, stay mounted until close enough to assist
|
||||||
|
if (StayMountedToCloseDistance())
|
||||||
|
return false;
|
||||||
|
|
||||||
Dismount();
|
Dismount();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mount up to close distance to master if beneficial - allow mounting even if master is in combat
|
||||||
|
// as long as the bot itself is not in combat and has no attackers
|
||||||
|
else if (!bot->IsMounted() && noAttackers && !bot->IsInCombat() && ShouldMountToCloseDistance())
|
||||||
|
return Mount();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,6 +409,50 @@ bool CheckMountStateAction::TryRandomMountFiltered(const std::map<int32, std::ve
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CheckMountStateAction::StayMountedToCloseDistance() const
|
||||||
|
{
|
||||||
|
// Keep the bot mounted while closing distance to a recently dismounted master.
|
||||||
|
// Rationale: if the master dismounts far away, immediately dismounting slows the bot down
|
||||||
|
// and delays assistance. Instead, remain mounted until within reasonable proximity
|
||||||
|
// of the master, then dismount to help.
|
||||||
|
|
||||||
|
if (!master)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float distToMaster = sServerFacade->GetDistance2d(bot, master);
|
||||||
|
|
||||||
|
// If master is in combat, dismount at combat assist range to help immediately
|
||||||
|
if (master->IsInCombat())
|
||||||
|
{
|
||||||
|
float assistRange = CalculateDismountDistance();
|
||||||
|
return distToMaster > assistRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If master is not in combat, use smaller proximity range for general following
|
||||||
|
float masterProximityRange = 10.0f; // Close enough to be near master but not attack range
|
||||||
|
return distToMaster > masterProximityRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckMountStateAction::ShouldMountToCloseDistance() const
|
||||||
|
{
|
||||||
|
// Mount up to close distance to master if beneficial
|
||||||
|
// Uses the same logic as CalculateMountDistance() which already considers the 2-second mount cast time
|
||||||
|
// This handles cases where master is in combat but bot isn't, and bot needs to mount to reach master
|
||||||
|
|
||||||
|
if (!master)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Only mount to close distance when actively following
|
||||||
|
if (!botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float distToMaster = sServerFacade->GetDistance2d(bot, master);
|
||||||
|
float mountDistance = CalculateMountDistance();
|
||||||
|
|
||||||
|
// Mount if distance is greater than the calculated mount distance threshold
|
||||||
|
return distToMaster > mountDistance;
|
||||||
|
}
|
||||||
|
|
||||||
float CheckMountStateAction::CalculateDismountDistance() const
|
float CheckMountStateAction::CalculateDismountDistance() const
|
||||||
{
|
{
|
||||||
// Warrior bots should dismount far enough to charge (because it's important for generating some initial rage),
|
// Warrior bots should dismount far enough to charge (because it's important for generating some initial rage),
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ private:
|
|||||||
bool TryPreferredMount(Player* master) const;
|
bool TryPreferredMount(Player* master) const;
|
||||||
uint32 GetMountType(Player* master) const;
|
uint32 GetMountType(Player* master) const;
|
||||||
bool TryRandomMountFiltered(const std::map<int32, std::vector<uint32>>& spells, int32 masterSpeed) const;
|
bool TryRandomMountFiltered(const std::map<int32, std::vector<uint32>>& spells, int32 masterSpeed) const;
|
||||||
|
bool StayMountedToCloseDistance() const;
|
||||||
|
bool ShouldMountToCloseDistance() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "Corpse.h"
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include "FleeManager.h"
|
#include "FleeManager.h"
|
||||||
#include "G3D/Vector3.h"
|
#include "G3D/Vector3.h"
|
||||||
@@ -41,7 +42,6 @@
|
|||||||
#include "Unit.h"
|
#include "Unit.h"
|
||||||
#include "Vehicle.h"
|
#include "Vehicle.h"
|
||||||
#include "WaypointMovementGenerator.h"
|
#include "WaypointMovementGenerator.h"
|
||||||
#include "Corpse.h"
|
|
||||||
|
|
||||||
MovementAction::MovementAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name)
|
MovementAction::MovementAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name)
|
||||||
{
|
{
|
||||||
@@ -192,14 +192,15 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool generatePath = !bot->IsFlying() && !bot->isSwimming();
|
bool generatePath = !bot->IsFlying() && !bot->isSwimming();
|
||||||
bool disableMoveSplinePath = sPlayerbotAIConfig->disableMoveSplinePath >= 2 ||
|
bool disableMoveSplinePath =
|
||||||
(sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground());
|
sPlayerbotAIConfig->disableMoveSplinePath >= 2 ||
|
||||||
|
(sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground());
|
||||||
if (Vehicle* vehicle = bot->GetVehicle())
|
if (Vehicle* vehicle = bot->GetVehicle())
|
||||||
{
|
{
|
||||||
VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(bot);
|
VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(bot);
|
||||||
Unit* vehicleBase = vehicle->GetBase();
|
Unit* vehicleBase = vehicle->GetBase();
|
||||||
// If the mover (vehicle) can fly, we DO NOT want an mmaps path (2D ground) => disable pathfinding
|
|
||||||
generatePath = !vehicleBase || !vehicleBase->CanFly();
|
generatePath = !vehicleBase || !vehicleBase->CanFly();
|
||||||
if (!vehicleBase || !seat || !seat->CanControl()) // is passenger and cant move anyway
|
if (!vehicleBase || !seat || !seat->CanControl()) // is passenger and cant move anyway
|
||||||
return false;
|
return false;
|
||||||
@@ -207,22 +208,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|||||||
float distance = vehicleBase->GetExactDist(x, y, z); // use vehicle distance, not bot
|
float distance = vehicleBase->GetExactDist(x, y, z); // use vehicle distance, not bot
|
||||||
if (distance > 0.01f)
|
if (distance > 0.01f)
|
||||||
{
|
{
|
||||||
MotionMaster& mm = *vehicleBase->GetMotionMaster(); // need to move vehicle, not bot
|
DoMovePoint(vehicleBase, x, y, z, generatePath, backwards);
|
||||||
// Disable ground pathing if the bot/master/vehicle are flying
|
|
||||||
auto isFlying = [](Unit* u){ return u && (u->HasUnitMovementFlag(MOVEMENTFLAG_FLYING) || u->IsInFlight()); };
|
|
||||||
bool allowPathVeh = generatePath;
|
|
||||||
Unit* masterVeh = botAI ? botAI->GetMaster() : nullptr;
|
|
||||||
if (isFlying(vehicleBase) || isFlying(bot) || isFlying(masterVeh))
|
|
||||||
allowPathVeh = false;
|
|
||||||
mm.Clear();
|
|
||||||
if (!backwards)
|
|
||||||
{
|
|
||||||
mm.MovePoint(0, x, y, z, FORCED_MOVEMENT_NONE, 0.0f, 0.0f, allowPathVeh);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mm.MovePointBackwards(0, x, y, z, allowPathVeh);
|
|
||||||
}
|
|
||||||
float speed = backwards ? vehicleBase->GetSpeed(MOVE_RUN_BACK) : vehicleBase->GetSpeed(MOVE_RUN);
|
float speed = backwards ? vehicleBase->GetSpeed(MOVE_RUN_BACK) : vehicleBase->GetSpeed(MOVE_RUN);
|
||||||
float delay = 1000.0f * (distance / speed);
|
float delay = 1000.0f * (distance / speed);
|
||||||
if (lessDelay)
|
if (lessDelay)
|
||||||
@@ -248,23 +234,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|||||||
// bot->CastStop();
|
// bot->CastStop();
|
||||||
// botAI->InterruptSpell();
|
// botAI->InterruptSpell();
|
||||||
// }
|
// }
|
||||||
|
DoMovePoint(bot, x, y, z, generatePath, backwards);
|
||||||
MotionMaster& mm = *bot->GetMotionMaster();
|
|
||||||
// No ground pathfinding if the bot/master are flying => allow true 3D (Z) movement
|
|
||||||
auto isFlying = [](Unit* u){ return u && (u->HasUnitMovementFlag(MOVEMENTFLAG_FLYING) || u->IsInFlight()); };
|
|
||||||
bool allowPath = generatePath;
|
|
||||||
Unit* master = botAI ? botAI->GetMaster() : nullptr;
|
|
||||||
if (isFlying(bot) || isFlying(master))
|
|
||||||
allowPath = false;
|
|
||||||
mm.Clear();
|
|
||||||
if (!backwards)
|
|
||||||
{
|
|
||||||
mm.MovePoint(0, x, y, z, FORCED_MOVEMENT_NONE, 0.0f, 0.0f, allowPath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mm.MovePointBackwards(0, x, y, z, allowPath);
|
|
||||||
}
|
|
||||||
float delay = 1000.0f * MoveDelay(distance, backwards);
|
float delay = 1000.0f * MoveDelay(distance, backwards);
|
||||||
if (lessDelay)
|
if (lessDelay)
|
||||||
{
|
{
|
||||||
@@ -282,9 +252,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|||||||
Movement::PointsArray path =
|
Movement::PointsArray path =
|
||||||
SearchForBestPath(x, y, z, modifiedZ, sPlayerbotAIConfig->maxMovementSearchTime, normal_only);
|
SearchForBestPath(x, y, z, modifiedZ, sPlayerbotAIConfig->maxMovementSearchTime, normal_only);
|
||||||
if (modifiedZ == INVALID_HEIGHT)
|
if (modifiedZ == INVALID_HEIGHT)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
float distance = bot->GetExactDist(x, y, modifiedZ);
|
float distance = bot->GetExactDist(x, y, modifiedZ);
|
||||||
if (distance > 0.01f)
|
if (distance > 0.01f)
|
||||||
{
|
{
|
||||||
@@ -296,24 +264,8 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|||||||
// bot->CastStop();
|
// bot->CastStop();
|
||||||
// botAI->InterruptSpell();
|
// botAI->InterruptSpell();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
MotionMaster& mm = *bot->GetMotionMaster();
|
|
||||||
G3D::Vector3 endP = path.back();
|
G3D::Vector3 endP = path.back();
|
||||||
// No ground pathfinding if the bot/master are flying => allow true 3D (Z) movement
|
DoMovePoint(bot, x, y, z, generatePath, backwards);
|
||||||
auto isFlying = [](Unit* u){ return u && (u->HasUnitMovementFlag(MOVEMENTFLAG_FLYING) || u->IsInFlight()); };
|
|
||||||
bool allowPath = generatePath;
|
|
||||||
Unit* master = botAI ? botAI->GetMaster() : nullptr;
|
|
||||||
if (isFlying(bot) || isFlying(master))
|
|
||||||
allowPath = false;
|
|
||||||
mm.Clear();
|
|
||||||
if (!backwards)
|
|
||||||
{
|
|
||||||
mm.MovePoint(0, x, y, z, FORCED_MOVEMENT_NONE, 0.0f, 0.0f, allowPath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mm.MovePointBackwards(0, x, y, z, allowPath);
|
|
||||||
}
|
|
||||||
float delay = 1000.0f * MoveDelay(distance, backwards);
|
float delay = 1000.0f * MoveDelay(distance, backwards);
|
||||||
if (lessDelay)
|
if (lessDelay)
|
||||||
{
|
{
|
||||||
@@ -581,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);
|
// bool goTaxi = bot->ActivateTaxiPathTo({ tEntry->from, tEntry->to }, unit, 1);
|
||||||
|
|
||||||
// if (botAI->HasCheat(BotCheatMask::gold))
|
// if (botAI->HasCheat(BotCheatMask::gold))
|
||||||
// {
|
|
||||||
// bot->SetMoney(botMoney);
|
// bot->SetMoney(botMoney);
|
||||||
// }
|
|
||||||
// LOG_DEBUG("playerbots", "goTaxi");
|
// LOG_DEBUG("playerbots", "goTaxi");
|
||||||
// return goTaxi;
|
// return goTaxi;
|
||||||
// }
|
// }
|
||||||
@@ -874,7 +824,7 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
|
|||||||
|
|
||||||
float deltaAngle = Position::NormalizeOrientation(targetOrientation - target->GetAngle(bot));
|
float deltaAngle = Position::NormalizeOrientation(targetOrientation - target->GetAngle(bot));
|
||||||
if (deltaAngle > M_PI)
|
if (deltaAngle > M_PI)
|
||||||
deltaAngle -= 2.0f * M_PI; // -PI..PI
|
deltaAngle -= 2.0f * M_PI; // -PI..PI
|
||||||
// if target is moving forward and moving far away, predict the position
|
// if target is moving forward and moving far away, predict the position
|
||||||
bool behind = fabs(deltaAngle) > M_PI_2;
|
bool behind = fabs(deltaAngle) > M_PI_2;
|
||||||
if (target->HasUnitMovementFlag(MOVEMENTFLAG_FORWARD) && behind)
|
if (target->HasUnitMovementFlag(MOVEMENTFLAG_FORWARD) && behind)
|
||||||
@@ -882,8 +832,8 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
|
|||||||
float predictDis = std::min(3.0f, target->GetObjectSize() * 2);
|
float predictDis = std::min(3.0f, target->GetObjectSize() * 2);
|
||||||
tx += cos(target->GetOrientation()) * predictDis;
|
tx += cos(target->GetOrientation()) * predictDis;
|
||||||
ty += sin(target->GetOrientation()) * predictDis;
|
ty += sin(target->GetOrientation()) * predictDis;
|
||||||
if (!target->GetMap()->CheckCollisionAndGetValidCoords(target, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(),
|
if (!target->GetMap()->CheckCollisionAndGetValidCoords(target, target->GetPositionX(), target->GetPositionY(),
|
||||||
tx, ty, tz))
|
target->GetPositionZ(), tx, ty, tz))
|
||||||
{
|
{
|
||||||
tx = target->GetPositionX();
|
tx = target->GetPositionX();
|
||||||
ty = target->GetPositionY();
|
ty = target->GetPositionY();
|
||||||
@@ -1001,9 +951,8 @@ bool MovementAction::IsMovingAllowed()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) ||
|
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) ||
|
||||||
bot->IsBeingTeleported() || bot->HasRootAura() || bot->HasSpiritOfRedemptionAura() ||
|
bot->IsBeingTeleported() || bot->HasRootAura() || bot->HasSpiritOfRedemptionAura() || bot->HasConfuseAura() ||
|
||||||
bot->HasConfuseAura() || bot->IsCharmed() || bot->HasStunAura() ||
|
bot->IsCharmed() || bot->HasStunAura() || bot->IsInFlight() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||||
bot->IsInFlight() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (bot->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) != NULL_MOTION_TYPE)
|
if (bot->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) != NULL_MOTION_TYPE)
|
||||||
@@ -1022,64 +971,59 @@ bool MovementAction::Follow(Unit* target, float distance) { return Follow(target
|
|||||||
|
|
||||||
void MovementAction::UpdateMovementState()
|
void MovementAction::UpdateMovementState()
|
||||||
{
|
{
|
||||||
int8 botInLiquidState = bot->GetLiquidData().Status;
|
// state flags
|
||||||
|
const float gLvlZ = bot->GetMapWaterOrGroundLevel(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
|
||||||
|
const bool onGround = bot->GetPositionZ() < gLvlZ + 1.f;
|
||||||
|
const bool wantsToFly = bot->HasIncreaseMountedFlightSpeedAura() || bot->HasFlyAura();
|
||||||
|
const auto master = botAI ? botAI->GetMaster() : nullptr; // real or not
|
||||||
|
const bool masterIsFlying = master && master->HasUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
||||||
|
const bool isFlying = bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
||||||
|
const auto liquidState = bot->GetLiquidData().Status; // default LIQUID_MAP_NO_WATER
|
||||||
|
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;
|
||||||
|
|
||||||
if (botInLiquidState == LIQUID_MAP_IN_WATER || botInLiquidState == LIQUID_MAP_UNDER_WATER)
|
// handle water state
|
||||||
|
if (isWaterArea)
|
||||||
{
|
{
|
||||||
bot->SetSwim(true);
|
// water walking
|
||||||
|
if (wantsToWaterWalk && !isWaterWalking && !isUnderWater && !isFlying)
|
||||||
|
{
|
||||||
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
|
||||||
|
bot->AddUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
|
||||||
|
bot->SendMovementFlagUpdate();
|
||||||
|
}
|
||||||
|
// swimming
|
||||||
|
else if (wantsToSwim && !isSwimming && !wantsToWaterWalk && !isFlying)
|
||||||
|
{
|
||||||
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
|
||||||
|
bot->AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
|
||||||
|
bot->SendMovementFlagUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bot->SetSwim(false);
|
// reset flags, if not will inherit incorrect walk speed here and there
|
||||||
|
// when transistions between land and water.
|
||||||
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
|
||||||
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
|
||||||
|
bot->SendMovementFlagUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool onGround = bot->GetPositionZ() <
|
// handle flying state
|
||||||
bot->GetMapWaterOrGroundLevel(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ()) + 1.0f;
|
if (wantsToFly && !isFlying && masterIsFlying)
|
||||||
|
|
||||||
// Keep bot->SendMovementFlagUpdate() withing the if statements to not intefere with bot behavior on ground/(shallow) waters
|
|
||||||
|
|
||||||
bool hasFlightAura = bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || bot->HasAuraType(SPELL_AURA_FLY);
|
|
||||||
if (hasFlightAura)
|
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bot->AddUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
||||||
if (!bot->HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY))
|
bot->SendMovementFlagUpdate();
|
||||||
{
|
|
||||||
bot->AddUnitMovementFlag(MOVEMENTFLAG_CAN_FLY);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
if (!bot->HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY))
|
|
||||||
{
|
|
||||||
bot->AddUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
if (!bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING))
|
|
||||||
{
|
|
||||||
bot->AddUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
if (changed)
|
|
||||||
bot->SendMovementFlagUpdate();
|
|
||||||
}
|
}
|
||||||
else if (!hasFlightAura)
|
else if ((!wantsToFly || onGround) && isFlying)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
||||||
if (bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING))
|
bot->SendMovementFlagUpdate();
|
||||||
{
|
|
||||||
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
if (bot->HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY))
|
|
||||||
{
|
|
||||||
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
if (bot->HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY))
|
|
||||||
{
|
|
||||||
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_CAN_FLY);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
if (changed)
|
|
||||||
bot->SendMovementFlagUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if the bot is currently slowed, rooted, or otherwise unable to move
|
// See if the bot is currently slowed, rooted, or otherwise unable to move
|
||||||
@@ -1180,6 +1124,13 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
|
|||||||
if (!target)
|
if (!target)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!bot->InBattleground() && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target),
|
||||||
|
sPlayerbotAIConfig->followDistance))
|
||||||
|
{
|
||||||
|
// botAI->TellError("No need to follow");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (!bot->InBattleground()
|
if (!bot->InBattleground()
|
||||||
&& sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target->GetPositionX(),
|
&& sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target->GetPositionX(),
|
||||||
@@ -1297,17 +1248,21 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
|
|||||||
return MoveTo(target, sPlayerbotAIConfig->followDistance);
|
return MoveTo(target, sPlayerbotAIConfig->followDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target),
|
||||||
|
sPlayerbotAIConfig->followDistance))
|
||||||
|
{
|
||||||
|
// botAI->TellError("No need to follow");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (target->IsFriendlyTo(bot) && bot->IsMounted() && AI_VALUE(GuidVector, "all targets").empty())
|
if (target->IsFriendlyTo(bot) && bot->IsMounted() && AI_VALUE(GuidVector, "all targets").empty())
|
||||||
distance += angle;
|
distance += angle;
|
||||||
|
|
||||||
// Do not cancel follow if the 2D distance is short but the Z still differs (e.g., master above).
|
if (!bot->InBattleground() && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target),
|
||||||
float dz1 = fabs(bot->GetPositionZ() - target->GetPositionZ());
|
sPlayerbotAIConfig->followDistance))
|
||||||
if (!bot->InBattleground()
|
|
||||||
&& sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target), sPlayerbotAIConfig->followDistance)
|
|
||||||
&& dz1 < sPlayerbotAIConfig->contactDistance)
|
|
||||||
{
|
{
|
||||||
// botAI->TellError("No need to follow");
|
// botAI->TellError("No need to follow");
|
||||||
return false; // truly in range (2D and Z) => no need to move
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bot->HandleEmoteCommand(0);
|
bot->HandleEmoteCommand(0);
|
||||||
@@ -1388,7 +1343,7 @@ float MovementAction::MoveDelay(float distance, bool backwards)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
speed = backwards ? bot->GetSpeed(MOVE_RUN_BACK) :bot->GetSpeed(MOVE_RUN);
|
speed = backwards ? bot->GetSpeed(MOVE_RUN_BACK) : bot->GetSpeed(MOVE_RUN);
|
||||||
}
|
}
|
||||||
float delay = distance / speed;
|
float delay = distance / speed;
|
||||||
return delay;
|
return delay;
|
||||||
@@ -1418,8 +1373,7 @@ void MovementAction::SetNextMovementDelay(float delayMillis)
|
|||||||
{
|
{
|
||||||
AI_VALUE(LastMovement&, "last movement")
|
AI_VALUE(LastMovement&, "last movement")
|
||||||
.Set(bot->GetMapId(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetOrientation(),
|
.Set(bot->GetMapId(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetOrientation(),
|
||||||
delayMillis,
|
delayMillis, MovementPriority::MOVEMENT_FORCED);
|
||||||
MovementPriority::MOVEMENT_FORCED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MovementAction::Flee(Unit* target)
|
bool MovementAction::Flee(Unit* target)
|
||||||
@@ -1633,7 +1587,8 @@ bool MovementAction::MoveAway(Unit* target, float distance, bool backwards)
|
|||||||
dz = bot->GetPositionZ();
|
dz = bot->GetPositionZ();
|
||||||
exact = false;
|
exact = false;
|
||||||
}
|
}
|
||||||
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true, exact, MovementPriority::MOVEMENT_COMBAT, false, backwards))
|
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true, exact, MovementPriority::MOVEMENT_COMBAT, false,
|
||||||
|
backwards))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1655,7 +1610,8 @@ bool MovementAction::MoveAway(Unit* target, float distance, bool backwards)
|
|||||||
dz = bot->GetPositionZ();
|
dz = bot->GetPositionZ();
|
||||||
exact = false;
|
exact = false;
|
||||||
}
|
}
|
||||||
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true, exact, MovementPriority::MOVEMENT_COMBAT, false, backwards))
|
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true, exact, MovementPriority::MOVEMENT_COMBAT, false,
|
||||||
|
backwards))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1704,7 +1660,7 @@ bool MovementAction::Move(float angle, float distance)
|
|||||||
float x = bot->GetPositionX() + cos(angle) * distance;
|
float x = bot->GetPositionX() + cos(angle) * distance;
|
||||||
float y = bot->GetPositionY() + sin(angle) * distance;
|
float y = bot->GetPositionY() + sin(angle) * distance;
|
||||||
|
|
||||||
//TODO do we need GetMapWaterOrGroundLevel() if we're using CheckCollisionAndGetValidCoords() ?
|
// TODO do we need GetMapWaterOrGroundLevel() if we're using CheckCollisionAndGetValidCoords() ?
|
||||||
float z = bot->GetMapWaterOrGroundLevel(x, y, bot->GetPositionZ());
|
float z = bot->GetMapWaterOrGroundLevel(x, y, bot->GetPositionZ());
|
||||||
if (z == -100000.0f || z == -200000.0f)
|
if (z == -100000.0f || z == -200000.0f)
|
||||||
z = bot->GetPositionZ();
|
z = bot->GetPositionZ();
|
||||||
@@ -1758,9 +1714,7 @@ bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float d
|
|||||||
// min_length = gen.getPathLength();
|
// min_length = gen.getPathLength();
|
||||||
// current_z = modified_z;
|
// current_z = modified_z;
|
||||||
// if (abs(current_z - z) < 0.5f)
|
// if (abs(current_z - z) < 0.5f)
|
||||||
// {
|
|
||||||
// return current_z;
|
// return current_z;
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// for (delta = range / 2 + step; delta <= range; delta += 2) {
|
// for (delta = range / 2 + step; delta <= range; delta += 2) {
|
||||||
@@ -1857,6 +1811,59 @@ const Movement::PointsArray MovementAction::SearchForBestPath(float x, float y,
|
|||||||
return result;
|
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 flying
|
||||||
|
if (unit->HasUnitMovementFlag(MOVEMENTFLAG_FLYING))
|
||||||
|
{
|
||||||
|
unit->AddUnitMovementFlag(MOVEMENTFLAG_CAN_FLY);
|
||||||
|
unit->AddUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unit->RemoveUnitMovementFlag(MOVEMENTFLAG_CAN_FLY);
|
||||||
|
unit->RemoveUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable water walking
|
||||||
|
if (unit->HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING))
|
||||||
|
{
|
||||||
|
float gLvlZ = unit->GetMapWaterOrGroundLevel(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ());
|
||||||
|
unit->UpdatePosition(unit->GetPositionX(), unit->GetPositionY(), gLvlZ, false);
|
||||||
|
// z = gLvlZ; do not overwrite Z axex, otherwise you wont be able to 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)
|
bool FleeAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
return MoveAway(AI_VALUE(Unit*, "current target"), sPlayerbotAIConfig->fleeDistance, true);
|
return MoveAway(AI_VALUE(Unit*, "current target"), sPlayerbotAIConfig->fleeDistance, true);
|
||||||
@@ -1937,7 +1944,8 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj()
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellInfo->Id) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
|
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellInfo->Id) !=
|
||||||
|
sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DynamicObject* dynOwner = aura->GetDynobjOwner();
|
DynamicObject* dynOwner = aura->GetDynobjOwner();
|
||||||
@@ -2002,7 +2010,8 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellId) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
|
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellId) !=
|
||||||
|
sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||||
@@ -2028,7 +2037,8 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage()
|
|||||||
lastTellTimer = time(NULL);
|
lastTellTimer = time(NULL);
|
||||||
lastMoveTimer = getMSTime();
|
lastMoveTimer = getMSTime();
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "I'm avoiding " << name.str() << " (" << spellInfo->Id << ")" << " Radius " << radius << " - [Trap]";
|
out << "I'm avoiding " << name.str() << " (" << spellInfo->Id << ")" << " Radius " << radius
|
||||||
|
<< " - [Trap]";
|
||||||
bot->Say(out.str(), LANG_UNIVERSAL);
|
bot->Say(out.str(), LANG_UNIVERSAL);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -2071,7 +2081,8 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
|
|||||||
sSpellMgr->GetSpellInfo(spellInfo->Effects[aurEff->GetEffIndex()].TriggerSpell);
|
sSpellMgr->GetSpellInfo(spellInfo->Effects[aurEff->GetEffIndex()].TriggerSpell);
|
||||||
if (!triggerSpellInfo)
|
if (!triggerSpellInfo)
|
||||||
continue;
|
continue;
|
||||||
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(triggerSpellInfo->Id) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
|
if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(triggerSpellInfo->Id) !=
|
||||||
|
sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end())
|
||||||
return false;
|
return false;
|
||||||
for (int j = 0; j < MAX_SPELL_EFFECTS; j++)
|
for (int j = 0; j < MAX_SPELL_EFFECTS; j++)
|
||||||
{
|
{
|
||||||
@@ -2093,7 +2104,8 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
|
|||||||
lastTellTimer = time(NULL);
|
lastTellTimer = time(NULL);
|
||||||
lastMoveTimer = getMSTime();
|
lastMoveTimer = getMSTime();
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "I'm avoiding " << name.str() << " (" << triggerSpellInfo->Id << ")" << " Radius " << radius << " - [Unit Trigger]";
|
out << "I'm avoiding " << name.str() << " (" << triggerSpellInfo->Id << ")"
|
||||||
|
<< " Radius " << radius << " - [Unit Trigger]";
|
||||||
bot->Say(out.str(), LANG_UNIVERSAL);
|
bot->Say(out.str(), LANG_UNIVERSAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2112,7 +2124,8 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius)
|
|||||||
if (currentTarget)
|
if (currentTarget)
|
||||||
{
|
{
|
||||||
// Normally, move to left or right is the best position
|
// 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 angle = bot->GetAngle(currentTarget);
|
||||||
float angleLeft = angle + (float)M_PI / 2;
|
float angleLeft = angle + (float)M_PI / 2;
|
||||||
float angleRight = angle - (float)M_PI / 2;
|
float angleRight = angle - (float)M_PI / 2;
|
||||||
@@ -2327,8 +2340,7 @@ bool CombatFormationMoveAction::isUseful()
|
|||||||
bool CombatFormationMoveAction::Execute(Event event)
|
bool CombatFormationMoveAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
float dis = AI_VALUE(float, "disperse distance");
|
float dis = AI_VALUE(float, "disperse distance");
|
||||||
if (dis <= 0.0f ||
|
if (dis <= 0.0f || (!bot->IsInCombat() && botAI->HasStrategy("stay", BotState::BOT_STATE_NON_COMBAT)) ||
|
||||||
(!bot->IsInCombat() && botAI->HasStrategy("stay", BotState::BOT_STATE_NON_COMBAT)) ||
|
|
||||||
(bot->IsInCombat() && botAI->HasStrategy("stay", BotState::BOT_STATE_COMBAT)))
|
(bot->IsInCombat() && botAI->HasStrategy("stay", BotState::BOT_STATE_COMBAT)))
|
||||||
return false;
|
return false;
|
||||||
Player* playerToLeave = NearestGroupMember(dis);
|
Player* playerToLeave = NearestGroupMember(dis);
|
||||||
@@ -2478,7 +2490,7 @@ bool TankFaceAction::Execute(Event event)
|
|||||||
|
|
||||||
float deltaAngle = Position::NormalizeOrientation(averageAngle - target->GetAngle(bot));
|
float deltaAngle = Position::NormalizeOrientation(averageAngle - target->GetAngle(bot));
|
||||||
if (deltaAngle > M_PI)
|
if (deltaAngle > M_PI)
|
||||||
deltaAngle -= 2.0f * M_PI; // -PI..PI
|
deltaAngle -= 2.0f * M_PI; // -PI..PI
|
||||||
|
|
||||||
float tolerable = M_PI_2;
|
float tolerable = M_PI_2;
|
||||||
|
|
||||||
@@ -2489,12 +2501,13 @@ bool TankFaceAction::Execute(Event event)
|
|||||||
float goodAngle2 = Position::NormalizeOrientation(averageAngle - M_PI * 3 / 5);
|
float goodAngle2 = Position::NormalizeOrientation(averageAngle - M_PI * 3 / 5);
|
||||||
|
|
||||||
// if dist < bot->GetMeleeRange(target) / 2, target will move backward
|
// if dist < bot->GetMeleeRange(target) / 2, target will move backward
|
||||||
float dist = std::max(bot->GetExactDist(target), bot->GetMeleeRange(target) / 2) - bot->GetCombatReach() - target->GetCombatReach();
|
float dist = std::max(bot->GetExactDist(target), bot->GetMeleeRange(target) / 2) - bot->GetCombatReach() -
|
||||||
|
target->GetCombatReach();
|
||||||
std::vector<Position> availablePos;
|
std::vector<Position> availablePos;
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle1);
|
target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle1);
|
||||||
if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(),
|
if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||||
x, y, z))
|
bot->GetPositionZ(), x, y, z))
|
||||||
{
|
{
|
||||||
/// @todo: movement control now is a mess, prepare to rewrite
|
/// @todo: movement control now is a mess, prepare to rewrite
|
||||||
std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
|
std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
|
||||||
@@ -2506,8 +2519,8 @@ bool TankFaceAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle2);
|
target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle2);
|
||||||
if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(),
|
if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||||
x, y, z))
|
bot->GetPositionZ(), x, y, z))
|
||||||
{
|
{
|
||||||
std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
|
std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
|
||||||
Position pos(x, y, z);
|
Position pos(x, y, z);
|
||||||
@@ -2520,13 +2533,15 @@ bool TankFaceAction::Execute(Event event)
|
|||||||
if (availablePos.empty())
|
if (availablePos.empty())
|
||||||
return false;
|
return false;
|
||||||
Position nearest = GetNearestPosition(availablePos);
|
Position nearest = GetNearestPosition(availablePos);
|
||||||
return MoveTo(bot->GetMapId(), nearest.GetPositionX(), nearest.GetPositionY(), nearest.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT);
|
return MoveTo(bot->GetMapId(), nearest.GetPositionX(), nearest.GetPositionY(), nearest.GetPositionZ(), false, false,
|
||||||
|
false, true, MovementPriority::MOVEMENT_COMBAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RearFlankAction::isUseful()
|
bool RearFlankAction::isUseful()
|
||||||
{
|
{
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
if (!target) { return false; }
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
// Need to double the front angle check to account for mirrored angle.
|
// Need to double the front angle check to account for mirrored angle.
|
||||||
bool inFront = target->HasInArc(2.f * minAngle, bot);
|
bool inFront = target->HasInArc(2.f * minAngle, bot);
|
||||||
@@ -2540,7 +2555,8 @@ bool RearFlankAction::isUseful()
|
|||||||
bool RearFlankAction::Execute(Event event)
|
bool RearFlankAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
if (!target) { return false; }
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
float angle = frand(minAngle, maxAngle);
|
float angle = frand(minAngle, maxAngle);
|
||||||
float baseDistance = bot->GetMeleeRange(target) * 0.5f;
|
float baseDistance = bot->GetMeleeRange(target) * 0.5f;
|
||||||
@@ -2559,8 +2575,8 @@ bool RearFlankAction::Execute(Event event)
|
|||||||
destination = &rightFlank;
|
destination = &rightFlank;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MoveTo(bot->GetMapId(), destination->GetPositionX(), destination->GetPositionY(), destination->GetPositionZ(),
|
return MoveTo(bot->GetMapId(), destination->GetPositionX(), destination->GetPositionY(),
|
||||||
false, false, false, true, MovementPriority::MOVEMENT_COMBAT);
|
destination->GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DisperseSetAction::Execute(Event event)
|
bool DisperseSetAction::Execute(Event event)
|
||||||
@@ -2688,9 +2704,8 @@ bool SetFacingTargetAction::isUseful() { return !AI_VALUE2(bool, "facing", "curr
|
|||||||
bool SetFacingTargetAction::isPossible()
|
bool SetFacingTargetAction::isPossible()
|
||||||
{
|
{
|
||||||
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) ||
|
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) ||
|
||||||
bot->IsBeingTeleported() || bot->HasConfuseAura() || bot->IsCharmed() ||
|
bot->IsBeingTeleported() || bot->HasConfuseAura() || bot->IsCharmed() || bot->HasStunAura() ||
|
||||||
bot->HasStunAura() || bot->IsInFlight() ||
|
bot->IsInFlight() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||||
bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -2710,7 +2725,7 @@ bool SetBehindTargetAction::Execute(Event event)
|
|||||||
|
|
||||||
float deltaAngle = Position::NormalizeOrientation(target->GetOrientation() - target->GetAngle(bot));
|
float deltaAngle = Position::NormalizeOrientation(target->GetOrientation() - target->GetAngle(bot));
|
||||||
if (deltaAngle > M_PI)
|
if (deltaAngle > M_PI)
|
||||||
deltaAngle -= 2.0f * M_PI; // -PI..PI
|
deltaAngle -= 2.0f * M_PI; // -PI..PI
|
||||||
|
|
||||||
float tolerable = M_PI_2;
|
float tolerable = M_PI_2;
|
||||||
|
|
||||||
@@ -2720,12 +2735,13 @@ bool SetBehindTargetAction::Execute(Event event)
|
|||||||
float goodAngle1 = Position::NormalizeOrientation(target->GetOrientation() + M_PI * 3 / 5);
|
float goodAngle1 = Position::NormalizeOrientation(target->GetOrientation() + M_PI * 3 / 5);
|
||||||
float goodAngle2 = Position::NormalizeOrientation(target->GetOrientation() - M_PI * 3 / 5);
|
float goodAngle2 = Position::NormalizeOrientation(target->GetOrientation() - M_PI * 3 / 5);
|
||||||
|
|
||||||
float dist = std::max(bot->GetExactDist(target), bot->GetMeleeRange(target) / 2) - bot->GetCombatReach() - target->GetCombatReach();
|
float dist = std::max(bot->GetExactDist(target), bot->GetMeleeRange(target) / 2) - bot->GetCombatReach() -
|
||||||
|
target->GetCombatReach();
|
||||||
std::vector<Position> availablePos;
|
std::vector<Position> availablePos;
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle1);
|
target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle1);
|
||||||
if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(),
|
if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||||
x, y, z))
|
bot->GetPositionZ(), x, y, z))
|
||||||
{
|
{
|
||||||
/// @todo: movement control now is a mess, prepare to rewrite
|
/// @todo: movement control now is a mess, prepare to rewrite
|
||||||
std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
|
std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
|
||||||
@@ -2737,8 +2753,8 @@ bool SetBehindTargetAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle2);
|
target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle2);
|
||||||
if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(),
|
if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||||
x, y, z))
|
bot->GetPositionZ(), x, y, z))
|
||||||
{
|
{
|
||||||
std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
|
std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
|
||||||
Position pos(x, y, z);
|
Position pos(x, y, z);
|
||||||
@@ -2751,7 +2767,8 @@ bool SetBehindTargetAction::Execute(Event event)
|
|||||||
if (availablePos.empty())
|
if (availablePos.empty())
|
||||||
return false;
|
return false;
|
||||||
Position nearest = GetNearestPosition(availablePos);
|
Position nearest = GetNearestPosition(availablePos);
|
||||||
return MoveTo(bot->GetMapId(), nearest.GetPositionX(), nearest.GetPositionY(), nearest.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT);
|
return MoveTo(bot->GetMapId(), nearest.GetPositionX(), nearest.GetPositionY(), nearest.GetPositionZ(), false, false,
|
||||||
|
false, true, MovementPriority::MOVEMENT_COMBAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MoveOutOfCollisionAction::Execute(Event event)
|
bool MoveOutOfCollisionAction::Execute(Event event)
|
||||||
@@ -2822,7 +2839,7 @@ bool MoveFromGroupAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
float distance = atoi(event.getParam().c_str());
|
float distance = atoi(event.getParam().c_str());
|
||||||
if (!distance)
|
if (!distance)
|
||||||
distance = 20.0f; // flee distance from config is too small for this
|
distance = 20.0f; // flee distance from config is too small for this
|
||||||
return MoveFromGroup(distance);
|
return MoveFromGroup(distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2905,10 +2922,7 @@ bool MoveAwayFromCreatureAction::Execute(Event event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MoveAwayFromCreatureAction::isPossible()
|
bool MoveAwayFromCreatureAction::isPossible() { return bot->CanFreeMove(); }
|
||||||
{
|
|
||||||
return bot->CanFreeMove();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MoveAwayFromPlayerWithDebuffAction::Execute(Event event)
|
bool MoveAwayFromPlayerWithDebuffAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
@@ -2995,7 +3009,4 @@ bool MoveAwayFromPlayerWithDebuffAction::Execute(Event event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MoveAwayFromPlayerWithDebuffAction::isPossible()
|
bool MoveAwayFromPlayerWithDebuffAction::isPossible() { return bot->CanFreeMove(); }
|
||||||
{
|
|
||||||
return bot->CanFreeMove();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -29,12 +29,17 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool JumpTo(uint32 mapId, float x, float y, float z, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
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, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
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, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL, bool lessDelay = false, bool backwards = false);
|
bool normal_only = false, bool exact_waypoint = false,
|
||||||
bool MoveTo(WorldObject* target, float distance = 0.0f, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
MovementPriority priority = MovementPriority::MOVEMENT_NORMAL, bool lessDelay = false,
|
||||||
bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig->contactDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
bool backwards = false);
|
||||||
|
bool MoveTo(WorldObject* target, float distance = 0.0f,
|
||||||
|
MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||||
|
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);
|
||||||
@@ -51,10 +56,11 @@ protected:
|
|||||||
bool Flee(Unit* target);
|
bool Flee(Unit* target);
|
||||||
void ClearIdleState();
|
void ClearIdleState();
|
||||||
void UpdateMovementState();
|
void UpdateMovementState();
|
||||||
bool MoveAway(Unit* target, float distance = sPlayerbotAIConfig -> fleeDistance, bool backwards = false);
|
bool MoveAway(Unit* target, float distance = sPlayerbotAIConfig->fleeDistance, bool backwards = false);
|
||||||
bool MoveFromGroup(float distance);
|
bool MoveFromGroup(float distance);
|
||||||
bool Move(float angle, float distance);
|
bool Move(float angle, float distance);
|
||||||
bool MoveInside(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->followDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
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);
|
||||||
@@ -74,6 +80,7 @@ private:
|
|||||||
const Movement::PointsArray SearchForBestPath(float x, float y, float z, float& modified_z, int maxSearchCount = 5,
|
const Movement::PointsArray SearchForBestPath(float x, float y, float z, float& modified_z, int maxSearchCount = 5,
|
||||||
bool normal_only = false, float step = 8.0f);
|
bool normal_only = false, float step = 8.0f);
|
||||||
bool wasMovementRestricted = false;
|
bool wasMovementRestricted = false;
|
||||||
|
void DoMovePoint(Unit* unit, float x, float y, float z, bool generatePath, bool backwards);
|
||||||
};
|
};
|
||||||
|
|
||||||
class FleeAction : public MovementAction
|
class FleeAction : public MovementAction
|
||||||
@@ -149,17 +156,18 @@ public:
|
|||||||
|
|
||||||
class RearFlankAction : public MovementAction
|
class RearFlankAction : public MovementAction
|
||||||
{
|
{
|
||||||
// 90 degree minimum angle prevents any frontal cleaves/breaths and avoids parry-hasting the boss.
|
// 90 degree minimum angle prevents any frontal cleaves/breaths and avoids parry-hasting the boss.
|
||||||
// 120 degree maximum angle leaves a 120 degree symmetrical cone at the tail end which is usually enough to avoid tail swipes.
|
// 120 degree maximum angle leaves a 120 degree symmetrical cone at the tail end which is usually enough to avoid
|
||||||
// Some dragons or mobs may have different danger zone angles, override if needed.
|
// tail swipes. Some dragons or mobs may have different danger zone angles, override if needed.
|
||||||
public:
|
public:
|
||||||
RearFlankAction(PlayerbotAI* botAI, float distance = 0.0f, float minAngle = ANGLE_90_DEG, float maxAngle = ANGLE_120_DEG)
|
RearFlankAction(PlayerbotAI* botAI, float distance = 0.0f, float minAngle = ANGLE_90_DEG,
|
||||||
|
float maxAngle = ANGLE_120_DEG)
|
||||||
: MovementAction(botAI, "rear flank")
|
: MovementAction(botAI, "rear flank")
|
||||||
{
|
{
|
||||||
this->distance = distance;
|
this->distance = distance;
|
||||||
this->minAngle = minAngle;
|
this->minAngle = minAngle;
|
||||||
this->maxAngle = maxAngle;
|
this->maxAngle = maxAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
@@ -297,7 +305,9 @@ class MoveAwayFromCreatureAction : public MovementAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MoveAwayFromCreatureAction(PlayerbotAI* botAI, std::string name, uint32 creatureId, float range, bool alive = true)
|
MoveAwayFromCreatureAction(PlayerbotAI* botAI, std::string name, uint32 creatureId, float range, bool alive = true)
|
||||||
: MovementAction(botAI, name), creatureId(creatureId), range(range), alive(alive) {}
|
: MovementAction(botAI, name), creatureId(creatureId), range(range), alive(alive)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
bool isPossible() override;
|
bool isPossible() override;
|
||||||
@@ -312,7 +322,9 @@ class MoveAwayFromPlayerWithDebuffAction : public MovementAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MoveAwayFromPlayerWithDebuffAction(PlayerbotAI* botAI, std::string name, uint32 spellId, float range)
|
MoveAwayFromPlayerWithDebuffAction(PlayerbotAI* botAI, std::string name, uint32 spellId, float range)
|
||||||
: MovementAction(botAI, name), spellId(spellId), range(range) {}
|
: MovementAction(botAI, name), spellId(spellId), range(range)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
bool isPossible() override;
|
bool isPossible() override;
|
||||||
|
|||||||
Reference in New Issue
Block a user