diff --git a/src/strategy/actions/AreaTriggerAction.cpp b/src/strategy/actions/AreaTriggerAction.cpp index 298bc686..f4802778 100644 --- a/src/strategy/actions/AreaTriggerAction.cpp +++ b/src/strategy/actions/AreaTriggerAction.cpp @@ -40,7 +40,14 @@ bool ReachAreaTriggerAction::Execute(Event event) 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 delay = 1000.0f * distance / bot->GetSpeed(MOVE_RUN) + sPlayerbotAIConfig->reactDelay; diff --git a/src/strategy/actions/CheckMountStateAction.cpp b/src/strategy/actions/CheckMountStateAction.cpp index 0366c56d..bf7a3a16 100644 --- a/src/strategy/actions/CheckMountStateAction.cpp +++ b/src/strategy/actions/CheckMountStateAction.cpp @@ -81,7 +81,7 @@ bool CheckMountStateAction::isUseful() // to mostly be an issue in tunnels of WSG and AV) float posZ = bot->GetPositionZ(); float groundLevel = bot->GetMapWaterOrGroundLevel(bot->GetPositionX(), bot->GetPositionY(), posZ); - if (!bot->IsMounted() && posZ < groundLevel) + if (!bot->IsMounted() && !bot->HasWaterWalkAura() && posZ < groundLevel) return false; // Not useful when bot does not have mount strat and is not currently mounted diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 04a89fa1..15e098a5 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -10,6 +10,7 @@ #include #include +#include "Corpse.h" #include "Event.h" #include "FleeManager.h" #include "G3D/Vector3.h" @@ -41,7 +42,6 @@ #include "Unit.h" #include "Vehicle.h" #include "WaypointMovementGenerator.h" -#include "Corpse.h" 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; } + 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(); - // If the mover (vehicle) can fly, we DO NOT want an mmaps path (2D ground) => disable pathfinding generatePath = !vehicleBase || !vehicleBase->CanFly(); if (!vehicleBase || !seat || !seat->CanControl()) // is passenger and cant move anyway 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 if (distance > 0.01f) { - MotionMaster& mm = *vehicleBase->GetMotionMaster(); // need to move vehicle, not bot - // 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); - } + 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) @@ -248,23 +234,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // bot->CastStop(); // botAI->InterruptSpell(); // } - - 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); - } + DoMovePoint(bot, x, y, z, generatePath, backwards); float delay = 1000.0f * MoveDelay(distance, backwards); if (lessDelay) { @@ -282,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) { @@ -296,24 +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(); - // 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); - } + DoMovePoint(bot, x, y, z, generatePath, backwards); float delay = 1000.0f * MoveDelay(distance, backwards); 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); // if (botAI->HasCheat(BotCheatMask::gold)) - // { // bot->SetMoney(botMoney); - // } // LOG_DEBUG("playerbots", "goTaxi"); // return goTaxi; // } @@ -874,7 +824,7 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance) float deltaAngle = Position::NormalizeOrientation(targetOrientation - target->GetAngle(bot)); 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 bool behind = fabs(deltaAngle) > M_PI_2; 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); tx += cos(target->GetOrientation()) * predictDis; ty += sin(target->GetOrientation()) * predictDis; - if (!target->GetMap()->CheckCollisionAndGetValidCoords(target, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), - tx, ty, tz)) + if (!target->GetMap()->CheckCollisionAndGetValidCoords(target, target->GetPositionX(), target->GetPositionY(), + target->GetPositionZ(), tx, ty, tz)) { tx = target->GetPositionX(); ty = target->GetPositionY(); @@ -1001,9 +951,8 @@ bool MovementAction::IsMovingAllowed() return false; if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) || - bot->IsBeingTeleported() || bot->HasRootAura() || bot->HasSpiritOfRedemptionAura() || - bot->HasConfuseAura() || bot->IsCharmed() || bot->HasStunAura() || - bot->IsInFlight() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) + bot->IsBeingTeleported() || bot->HasRootAura() || bot->HasSpiritOfRedemptionAura() || bot->HasConfuseAura() || + bot->IsCharmed() || bot->HasStunAura() || bot->IsInFlight() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) return false; 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() { - 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 { - 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() < - 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 - - bool hasFlightAura = bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || bot->HasAuraType(SPELL_AURA_FLY); - if (hasFlightAura) + // handle flying state + if (wantsToFly && !isFlying && masterIsFlying) { - bool changed = false; - if (!bot->HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY)) - { - 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(); + bot->AddUnitMovementFlag(MOVEMENTFLAG_FLYING); + bot->SendMovementFlagUpdate(); } - else if (!hasFlightAura) + else if ((!wantsToFly || onGround) && isFlying) { - bool changed = false; - if (bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING)) - { - 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(); + bot->RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING); + bot->SendMovementFlagUpdate(); } // 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) return false; + if (!bot->InBattleground() && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target), + sPlayerbotAIConfig->followDistance)) + { + // botAI->TellError("No need to follow"); + return false; + } + /* if (!bot->InBattleground() && 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); } + 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()) distance += angle; - // Do not cancel follow if the 2D distance is short but the Z still differs (e.g., master above). - float dz1 = fabs(bot->GetPositionZ() - target->GetPositionZ()); - if (!bot->InBattleground() - && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target), sPlayerbotAIConfig->followDistance) - && dz1 < sPlayerbotAIConfig->contactDistance) + if (!bot->InBattleground() && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, target), + sPlayerbotAIConfig->followDistance)) { // botAI->TellError("No need to follow"); - return false; // truly in range (2D and Z) => no need to move + return false; } bot->HandleEmoteCommand(0); @@ -1388,7 +1343,7 @@ float MovementAction::MoveDelay(float distance, bool backwards) } 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; return delay; @@ -1418,8 +1373,7 @@ void MovementAction::SetNextMovementDelay(float delayMillis) { AI_VALUE(LastMovement&, "last movement") .Set(bot->GetMapId(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetOrientation(), - delayMillis, - MovementPriority::MOVEMENT_FORCED); + delayMillis, MovementPriority::MOVEMENT_FORCED); } bool MovementAction::Flee(Unit* target) @@ -1633,7 +1587,8 @@ bool MovementAction::MoveAway(Unit* target, float distance, bool backwards) dz = bot->GetPositionZ(); 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; } @@ -1655,7 +1610,8 @@ bool MovementAction::MoveAway(Unit* target, float distance, bool backwards) dz = bot->GetPositionZ(); 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; } @@ -1704,7 +1660,7 @@ bool MovementAction::Move(float angle, float distance) float x = bot->GetPositionX() + cos(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()); if (z == -100000.0f || z == -200000.0f) z = bot->GetPositionZ(); @@ -1758,9 +1714,7 @@ bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float d // min_length = gen.getPathLength(); // current_z = modified_z; // if (abs(current_z - z) < 0.5f) -// { // return current_z; -// } // } // } // for (delta = range / 2 + step; delta <= range; delta += 2) { @@ -1857,6 +1811,59 @@ 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 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) { return MoveAway(AI_VALUE(Unit*, "current target"), sPlayerbotAIConfig->fleeDistance, true); @@ -1937,7 +1944,8 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj() { return false; } - if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellInfo->Id) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end()) + if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellInfo->Id) != + sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end()) return false; DynamicObject* dynOwner = aura->GetDynobjOwner(); @@ -2002,7 +2010,8 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage() continue; } - if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellId) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end()) + if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(spellId) != + sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end()) continue; const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId); @@ -2028,7 +2037,8 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage() lastTellTimer = time(NULL); lastMoveTimer = getMSTime(); 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); } return true; @@ -2071,7 +2081,8 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura() sSpellMgr->GetSpellInfo(spellInfo->Effects[aurEff->GetEffIndex()].TriggerSpell); if (!triggerSpellInfo) continue; - if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(triggerSpellInfo->Id) != sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end()) + if (sPlayerbotAIConfig->aoeAvoidSpellWhitelist.find(triggerSpellInfo->Id) != + sPlayerbotAIConfig->aoeAvoidSpellWhitelist.end()) return false; for (int j = 0; j < MAX_SPELL_EFFECTS; j++) { @@ -2093,7 +2104,8 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura() lastTellTimer = time(NULL); lastMoveTimer = getMSTime(); 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); } } @@ -2112,7 +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; @@ -2327,8 +2340,7 @@ bool CombatFormationMoveAction::isUseful() bool CombatFormationMoveAction::Execute(Event event) { float dis = AI_VALUE(float, "disperse distance"); - if (dis <= 0.0f || - (!bot->IsInCombat() && botAI->HasStrategy("stay", BotState::BOT_STATE_NON_COMBAT)) || + if (dis <= 0.0f || (!bot->IsInCombat() && botAI->HasStrategy("stay", BotState::BOT_STATE_NON_COMBAT)) || (bot->IsInCombat() && botAI->HasStrategy("stay", BotState::BOT_STATE_COMBAT))) return false; Player* playerToLeave = NearestGroupMember(dis); @@ -2478,7 +2490,7 @@ bool TankFaceAction::Execute(Event event) float deltaAngle = Position::NormalizeOrientation(averageAngle - target->GetAngle(bot)); if (deltaAngle > M_PI) - deltaAngle -= 2.0f * M_PI; // -PI..PI + deltaAngle -= 2.0f * M_PI; // -PI..PI float tolerable = M_PI_2; @@ -2489,12 +2501,13 @@ bool TankFaceAction::Execute(Event event) float goodAngle2 = Position::NormalizeOrientation(averageAngle - M_PI * 3 / 5); // 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 availablePos; float x, y, z; target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle1); - if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), - x, y, z)) + if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), + bot->GetPositionZ(), x, y, z)) { /// @todo: movement control now is a mess, prepare to rewrite std::list& infoList = AI_VALUE(std::list&, "recently flee info"); @@ -2506,8 +2519,8 @@ bool TankFaceAction::Execute(Event event) } } target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle2); - if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), - x, y, z)) + if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), + bot->GetPositionZ(), x, y, z)) { std::list& infoList = AI_VALUE(std::list&, "recently flee info"); Position pos(x, y, z); @@ -2520,13 +2533,15 @@ bool TankFaceAction::Execute(Event event) if (availablePos.empty()) return false; 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() { 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. bool inFront = target->HasInArc(2.f * minAngle, bot); @@ -2540,7 +2555,8 @@ bool RearFlankAction::isUseful() bool RearFlankAction::Execute(Event event) { Unit* target = AI_VALUE(Unit*, "current target"); - if (!target) { return false; } + if (!target) + return false; float angle = frand(minAngle, maxAngle); float baseDistance = bot->GetMeleeRange(target) * 0.5f; @@ -2559,8 +2575,8 @@ bool RearFlankAction::Execute(Event event) destination = &rightFlank; } - return MoveTo(bot->GetMapId(), destination->GetPositionX(), destination->GetPositionY(), destination->GetPositionZ(), - false, false, false, true, MovementPriority::MOVEMENT_COMBAT); + return MoveTo(bot->GetMapId(), destination->GetPositionX(), destination->GetPositionY(), + destination->GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT); } bool DisperseSetAction::Execute(Event event) @@ -2688,9 +2704,8 @@ bool SetFacingTargetAction::isUseful() { return !AI_VALUE2(bool, "facing", "curr bool SetFacingTargetAction::isPossible() { if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) || - bot->IsBeingTeleported() || bot->HasConfuseAura() || bot->IsCharmed() || - bot->HasStunAura() || bot->IsInFlight() || - bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) + bot->IsBeingTeleported() || bot->HasConfuseAura() || bot->IsCharmed() || bot->HasStunAura() || + bot->IsInFlight() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL)) return false; return true; @@ -2710,7 +2725,7 @@ bool SetBehindTargetAction::Execute(Event event) float deltaAngle = Position::NormalizeOrientation(target->GetOrientation() - target->GetAngle(bot)); if (deltaAngle > M_PI) - deltaAngle -= 2.0f * M_PI; // -PI..PI + deltaAngle -= 2.0f * M_PI; // -PI..PI 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 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 availablePos; float x, y, z; target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle1); - if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), - x, y, z)) + if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), + bot->GetPositionZ(), x, y, z)) { /// @todo: movement control now is a mess, prepare to rewrite std::list& infoList = AI_VALUE(std::list&, "recently flee info"); @@ -2737,8 +2753,8 @@ bool SetBehindTargetAction::Execute(Event event) } } target->GetNearPoint(bot, x, y, z, 0.0f, dist, goodAngle2); - if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), - x, y, z)) + if (bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), + bot->GetPositionZ(), x, y, z)) { std::list& infoList = AI_VALUE(std::list&, "recently flee info"); Position pos(x, y, z); @@ -2751,7 +2767,8 @@ bool SetBehindTargetAction::Execute(Event event) if (availablePos.empty()) return false; 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) @@ -2822,7 +2839,7 @@ bool MoveFromGroupAction::Execute(Event event) { float distance = atoi(event.getParam().c_str()); 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); } @@ -2905,10 +2922,7 @@ bool MoveAwayFromCreatureAction::Execute(Event event) return false; } -bool MoveAwayFromCreatureAction::isPossible() -{ - return bot->CanFreeMove(); -} +bool MoveAwayFromCreatureAction::isPossible() { return bot->CanFreeMove(); } bool MoveAwayFromPlayerWithDebuffAction::Execute(Event event) { @@ -2995,7 +3009,4 @@ bool MoveAwayFromPlayerWithDebuffAction::Execute(Event event) return false; } -bool MoveAwayFromPlayerWithDebuffAction::isPossible() -{ - return bot->CanFreeMove(); -} +bool MoveAwayFromPlayerWithDebuffAction::isPossible() { return bot->CanFreeMove(); } diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index f50e4b95..d12bcd55 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -29,12 +29,17 @@ public: protected: 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 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 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); + bool normal_only = false, bool exact_waypoint = false, + MovementPriority priority = MovementPriority::MOVEMENT_NORMAL, bool lessDelay = false, + 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(); bool Follow(Unit* target, float distance = sPlayerbotAIConfig->followDistance); bool Follow(Unit* target, float distance, float angle); @@ -51,10 +56,11 @@ protected: bool Flee(Unit* target); void ClearIdleState(); 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 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); Position BestPositionForMeleeToFlee(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, bool normal_only = false, float step = 8.0f); bool wasMovementRestricted = false; + void DoMovePoint(Unit* unit, float x, float y, float z, bool generatePath, bool backwards); }; class FleeAction : public MovementAction @@ -149,17 +156,18 @@ public: class RearFlankAction : public MovementAction { -// 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. -// Some dragons or mobs may have different danger zone angles, override if needed. + // 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. Some dragons or mobs may have different danger zone angles, override if needed. 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") - { - this->distance = distance; - this->minAngle = minAngle; - this->maxAngle = maxAngle; - } + { + this->distance = distance; + this->minAngle = minAngle; + this->maxAngle = maxAngle; + } bool Execute(Event event) override; bool isUseful() override; @@ -297,7 +305,9 @@ class MoveAwayFromCreatureAction : public MovementAction { public: 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 isPossible() override; @@ -312,7 +322,9 @@ class MoveAwayFromPlayerWithDebuffAction : public MovementAction { public: 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 isPossible() override;