From f1bfed190c573305e4c4fbf729f2985514e6992e Mon Sep 17 00:00:00 2001 From: Fuzz Date: Thu, 8 Aug 2024 21:18:52 +1000 Subject: [PATCH] [Battlegrounds] fixed bug I introduced in PR#422 where bots alternate mount/unmount near flag indefinately, also fixed other erroneous uses of sqrt on distances --- src/PlayerbotAI.cpp | 20 +---- src/strategy/actions/AreaTriggerAction.cpp | 4 +- src/strategy/actions/BattleGroundTactics.cpp | 80 ++++++++++--------- .../actions/ChooseRpgTargetAction.cpp | 2 +- src/strategy/actions/MovementActions.cpp | 9 ++- 5 files changed, 56 insertions(+), 59 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 0b4db3ef8..feb5c6fd1 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -2566,7 +2566,7 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, float x, float y, float z, uint8 if (!itemTarget) { - if (sqrt(bot->GetDistance(x, y, z)) > sPlayerbotAIConfig->sightDistance) + if (bot->GetDistance(x, y, z) > sPlayerbotAIConfig->sightDistance) return false; } @@ -3096,21 +3096,9 @@ bool PlayerbotAI::CastVehicleSpell(uint32 spellId, Unit* target) targets.SetDst(dest); targets.SetSpeed(30.0f); - float distanceToDest = sqrt(vehicleBase->GetPosition().GetExactDist(dest)); - float elev = 0.01f; - if (distanceToDest < 25.0f) - elev = 0.04f; - else if (distanceToDest < 55.0f) - elev = 0.22f; - else if (distanceToDest < 85.0f) - elev = 0.42f; - else if (distanceToDest < 95.0f) - elev = 0.70f; - else if (distanceToDest < 110.0f) - elev = 0.88f; - else - elev = 1.0f; - + float dist = vehicleBase->GetPosition().GetExactDist(dest); + // very much an approximation of the real projectile arc + float elev = dist >= 110.0f ? 1.0f : pow(((dist + 10.0f) / 120.0f), 2.0f); targets.SetElevation(elev); } diff --git a/src/strategy/actions/AreaTriggerAction.cpp b/src/strategy/actions/AreaTriggerAction.cpp index 4bd64ede4..5937a0f73 100644 --- a/src/strategy/actions/AreaTriggerAction.cpp +++ b/src/strategy/actions/AreaTriggerAction.cpp @@ -34,7 +34,7 @@ bool ReachAreaTriggerAction::Execute(Event event) return true; } - if (bot->GetMapId() != at->map || sqrt(bot->GetDistance(at->x, at->y, at->z)) > sPlayerbotAIConfig->sightDistance) + if (bot->GetMapId() != at->map) { botAI->TellError("I won't follow: too far away"); return true; @@ -42,7 +42,7 @@ bool ReachAreaTriggerAction::Execute(Event event) bot->GetMotionMaster()->MovePoint(at->map, at->x, at->y, at->z); - float distance = sqrt(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; botAI->TellError("Wait for me"); botAI->SetNextCheckDelay(delay); diff --git a/src/strategy/actions/BattleGroundTactics.cpp b/src/strategy/actions/BattleGroundTactics.cpp index e7f90ea91..9ae915242 100644 --- a/src/strategy/actions/BattleGroundTactics.cpp +++ b/src/strategy/actions/BattleGroundTactics.cpp @@ -2617,8 +2617,8 @@ bool BGTactics::selectObjective(bool reset) { if (GameObject* pGO = bg->GetBGObject(AV_HordeAttackObjectives[0].second)) { - float const distance = sqrt(bot->GetDistance(pGO)); - if (distance < 20.0f) + float const distance = bot->GetDistance(pGO); + if (distance < 400.0f) BgObjective = pGO; } } @@ -2638,7 +2638,7 @@ bool BGTactics::selectObjective(bool reset) { if (GameObject* pGO = bg->GetBGObject(objective.second)) { - float const distance = sqrt(bot->GetDistance(pGO)); + float const distance = bot->GetDistance(pGO); if (attackObjectiveDistance > distance) { BgObjective = pGO; @@ -2808,8 +2808,8 @@ bool BGTactics::selectObjective(bool reset) { if (GameObject* pGO = bg->GetBGObject(AV_AllianceAttackObjectives[0].second)) { - float const distance = sqrt(bot->GetDistance(pGO)); - if (distance < 20.0f) + float const distance = bot->GetDistance(pGO); + if (distance < 400.0f) BgObjective = pGO; } } @@ -2829,7 +2829,7 @@ bool BGTactics::selectObjective(bool reset) { if (GameObject* pGO = bg->GetBGObject(objective.second)) { - float const distance = sqrt(bot->GetDistance(pGO)); + float const distance = bot->GetDistance(pGO); if (attackObjectiveDistance > distance) { BgObjective = pGO; @@ -3022,7 +3022,7 @@ bool BGTactics::selectObjective(bool reset) { if (GameObject* pGO = bg->GetBGObject(objective * BG_AB_OBJECTS_PER_NODE)) { - float const distance = sqrt(bot->GetDistance(pGO)); + float const distance = bot->GetDistance(pGO); if (attackObjectiveDistance > distance) { // do not pick if already in list @@ -3071,7 +3071,7 @@ bool BGTactics::selectObjective(bool reset) { if (GameObject* pGO = bg->GetBGObject(objective * BG_AB_OBJECTS_PER_NODE)) { - float const distance = sqrt(bot->GetDistance(pGO)); + float const distance = bot->GetDistance(pGO); if (attackObjectiveDistance > distance) { // do not pick if already in list @@ -3133,14 +3133,15 @@ bool BGTactics::selectObjective(bool reset) uint8 ownership = pointOwner == bot->GetTeamId() ? 2 : pointOwner == TEAM_NEUTRAL ? 1 : 0; if (closestObjectiveOwnership > ownership) continue; - float dist = sqrt(bot->GetDistance(go)); + float dist = bot->GetDistance(go); + + // select objective when ownership is better + // or distance difference is significantly better + // or distance difference is insignificantly better and coinflip + // the reason it doesn't just check if distance is better is to avoid bot going to same point every time if (closestObjectiveOwnership < ownership || - (closestObjectiveDist > dist && - (closestObjectiveDist - dist > 1 || - urand( - 0, - 1)))) // if distance difference is minor (as it will be when they first pick flag up - // from middle) add some randomness so its not going to same point every time + closestObjectiveDist - 30 > dist || + (closestObjectiveDist > dist && urand(0, 1))) { closestObjectiveOwnership = ownership; closestObjectiveDist = dist; @@ -3397,10 +3398,9 @@ bool BGTactics::selectObjective(bool reset) } else // target gate directly at range if other vehicle { - // take a siege position - if (sqrt(bot->GetDistance(IC_GATE_ATTACK_POS_HORDE)) < - 5.0f) // just make bot stay where it is (stops them shifting around to the random - // spots) + // just make bot stay where it is if already close + // (stops them shifting around between the random spots) + if (bot->GetDistance(IC_GATE_ATTACK_POS_HORDE) < 8.0f) pos.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId()); else pos.Set(IC_GATE_ATTACK_POS_HORDE.GetPositionX() + frand(-5.0f, +5.0f), @@ -3486,10 +3486,10 @@ bool BGTactics::selectObjective(bool reset) } } if (!BgObjective) // guard vehicles as they seige - { - if (sqrt(bot->GetDistance(IC_GATE_ATTACK_POS_HORDE)) < - 5.0f) // just make bot stay where it is (stops them shifting around to the random spots) + // just make bot stay where it is if already close + // (stops them shifting around between the random spots) + if (bot->GetDistance(IC_GATE_ATTACK_POS_HORDE) < 8.0f) pos.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId()); else pos.Set(IC_GATE_ATTACK_POS_HORDE.GetPositionX() + frand(-5.0f, +5.0f), @@ -3550,10 +3550,9 @@ bool BGTactics::selectObjective(bool reset) } else // target gate directly at range if other vehicle { - // take a siege position - if (sqrt(bot->GetDistance(IC_GATE_ATTACK_POS_ALLIANCE)) < - 5.0f) // just make bot stay where it is (stops them shifting around to the random - // spots) + // just make bot stay where it is if already close + // (stops them shifting around between the random spots) + if (bot->GetDistance(IC_GATE_ATTACK_POS_ALLIANCE) < 8.0f) pos.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId()); else pos.Set(IC_GATE_ATTACK_POS_ALLIANCE.GetPositionX() + frand(-5.0f, +5.0f), @@ -3640,8 +3639,9 @@ bool BGTactics::selectObjective(bool reset) } if (!BgObjective) // guard vehicles as they seige { - if (sqrt(bot->GetDistance(IC_GATE_ATTACK_POS_ALLIANCE)) < - 5.0f) // just make bot stay where it is (stops them shifting around to the random spots) + // just make bot stay where it is if already close + // (stops them shifting around between the random spots) + if (bot->GetDistance(IC_GATE_ATTACK_POS_ALLIANCE) < 8.0f) pos.Set(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId()); else pos.Set(IC_GATE_ATTACK_POS_ALLIANCE.GetPositionX() + frand(-5.0f, +5.0f), @@ -3700,7 +3700,7 @@ bool BGTactics::moveToObjective() } // don't try to move if already close - if (sqrt(bot->GetDistance(pos.x, pos.y, pos.z)) < 2.0f) + if (bot->GetDistance(pos.x, pos.y, pos.z) < 4.0f) { resetObjective(); @@ -3714,9 +3714,8 @@ bool BGTactics::moveToObjective() if (bgType == BATTLEGROUND_WS) return MoveTo(bot->GetMapId(), pos.x, pos.y, pos.z); else - return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z, - 1.5f); // note - don't make distance too large or horde bots may struggle to get flags in - // alliance AV towers (because they'll be targetting a spot in midair) + // dont increase from 1.5 will cause bugs with horde capping AV towers + return MoveNear(bot->GetMapId(), pos.x, pos.y, pos.z, 1.5f); } return false; } @@ -3745,7 +3744,7 @@ bool BGTactics::selectObjectiveWp(std::vector const& vPaths) // get bots out of cave when they respawn there (otherwise path selection happens while they're deep within cave // and the results arent good) Position const caveSpawn = bot->GetTeamId() == TEAM_ALLIANCE ? AV_CAVE_SPAWN_ALLIANCE : AV_CAVE_SPAWN_HORDE; - if (sqrt(bot->GetDistance(caveSpawn)) < 4.0f) + if (bot->GetDistance(caveSpawn) < 16.0f) { return moveToStart(true); } @@ -3793,6 +3792,12 @@ bool BGTactics::selectObjectiveWp(std::vector const& vPaths) std::find(vPaths_HordeMine.begin(), vPaths_HordeMine.end(), path) != vPaths_HordeMine.end()) continue; + // TODO need to remove sqrt from these two and distToBot but it totally throws path scoring out of + // whack if you do that without changing how its implemented (I'm amazed it works as well as it does + // using sqrt'ed distances) + // In a reworked version maybe compare the differences of path distances to point (ie: against best path) + // or maybe ratio's (where if a path end is twice the difference in distance from destination we basically + // use that to multiply the total score? BattleBotWaypoint& startPoint = ((*path)[0]); float const startPointDistToDestination = sqrt(Position(pos.x, pos.y, pos.z, 0.f).GetExactDist(startPoint.x, startPoint.y, startPoint.z)); @@ -3958,6 +3963,7 @@ bool BGTactics::startNewPathBegin(std::vector const& vPaths) std::find(vPaths_HordeMine.begin(), vPaths_HordeMine.end(), pPath) != vPaths_HordeMine.end()) continue; + // TODO remove sqrt BattleBotWaypoint* pStart = &((*pPath)[0]); if (sqrt(bot->GetDistance(pStart->x, pStart->y, pStart->z)) < INTERACTION_DISTANCE) availablePaths.emplace_back(AvailablePath(pPath, false)); @@ -3967,6 +3973,7 @@ bool BGTactics::startNewPathBegin(std::vector const& vPaths) vPaths_NoReverseAllowed.end()) continue; + // TODO remove sqrt BattleBotWaypoint* pEnd = &((*pPath)[(*pPath).size() - 1]); if (sqrt(bot->GetDistance(pEnd->x, pEnd->y, pEnd->z)) < INTERACTION_DISTANCE) availablePaths.emplace_back(AvailablePath(pPath, true)); @@ -4016,6 +4023,7 @@ bool BGTactics::startNewPathFree(std::vector const& vPaths) for (uint32 i = 0; i < pPath->size(); i++) { BattleBotWaypoint& waypoint = ((*pPath)[i]); + // TODO remove sqrt float const distanceToPoint = sqrt(bot->GetDistance(waypoint.x, waypoint.y, waypoint.z)); if (distanceToPoint < closestDistance) { @@ -4048,7 +4056,7 @@ bool BGTactics::atFlag(std::vector const& vPaths, std::vector const& vPaths, std::vectorCanUseBattlegroundObject(go) && bgType != BATTLEGROUND_WS) continue; - float const dist = sqrt(bot->GetDistance(go)); + float const dist = bot->GetDistance(go); if (flagRange && dist > flagRange) continue; @@ -4422,7 +4430,7 @@ bool BGTactics::IsLockedInsideKeep() // ALLIANCE if (bot->GetTeamId() == TEAM_ALLIANCE) { - if (GameObject* go = bg->GetBGObject(BG_IC_GO_DOODAD_PORTCULLISACTIVE01)) + if (GameObject* go = bg->GetBGObject(BG_IC_GO_DOODAD_PORTCULLISACTIVE02)) { if (go->isSpawned()) { diff --git a/src/strategy/actions/ChooseRpgTargetAction.cpp b/src/strategy/actions/ChooseRpgTargetAction.cpp index e0890c98d..8d6594d35 100644 --- a/src/strategy/actions/ChooseRpgTargetAction.cpp +++ b/src/strategy/actions/ChooseRpgTargetAction.cpp @@ -294,7 +294,7 @@ bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos) if (!botAI->HasStrategy("follow", BOT_STATE_NON_COMBAT)) return true; - if (sqrt(bot->GetDistance(master)) > sPlayerbotAIConfig->rpgDistance * 2) + if (bot->GetDistance(master) > sPlayerbotAIConfig->rpgDistance * 2) return false; Formation* formation = AI_VALUE(Formation*, "formation"); diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 98018f6d9..149773a71 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -66,7 +66,6 @@ void MovementAction::JumpTo(uint32 mapId, float x, float y, float z) float botZ = bot->GetPositionZ(); float speed = bot->GetSpeed(MOVE_RUN); MotionMaster& mm = *bot->GetMotionMaster(); - botAI->SetNextCheckDelay(1000); mm.Clear(); mm.MoveJump(x, y, z, speed, speed, 1); AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), 1000); @@ -141,7 +140,7 @@ bool MovementAction::MoveToLOS(WorldObject* target, bool ranged) if (botAI->HasStrategy("debug move", BOT_STATE_NON_COMBAT)) CreateWp(bot, point.x, point.y, point.z, 0.0, 2334); - float distPoint = sqrt(target->GetDistance(point.x, point.y, point.z)); + float distPoint = target->GetDistance(point.x, point.y, point.z); if (distPoint < dist && target->IsWithinLOS(point.x, point.y, point.z + bot->GetCollisionHeight())) { dist = distPoint; @@ -208,7 +207,6 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, delay = std::max(.0f, delay); delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay); AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay); - // TODO: is botAI->SetNextCheckDelay() meant to go here or is setting "last movement" value enough? (same question goes for below) return true; } } @@ -883,7 +881,10 @@ bool MovementAction::IsMovingAllowed(Unit* target) bool MovementAction::IsMovingAllowed(uint32 mapId, float x, float y, float z) { - float distance = sqrt(bot->GetDistance(x, y, z)); + // removed sqrt as means distance limit was effectively 22500 (ReactDistance²) + // leaving it commented incase we find ReactDistance limit causes problems + // float distance = sqrt(bot->GetDistance(x, y, z)); + float distance = bot->GetDistance(x, y, z); if (!bot->InBattleground() && distance > sPlayerbotAIConfig->reactDistance) return false;