diff --git a/.github/workflows/macos_build.yml b/.github/workflows/macos_build.yml index 3fd3ec97..5ea55963 100644 --- a/.github/workflows/macos_build.yml +++ b/.github/workflows/macos_build.yml @@ -20,17 +20,17 @@ jobs: name: ${{ matrix.os }} steps: - name: Checkout AzerothCore - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: 'liyunfan1223/azerothcore-wotlk' ref: 'Playerbot' - name: Checkout Playerbot Module - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: 'liyunfan1223/mod-playerbots' path: 'modules/mod-playerbots' - name: Cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/Library/Caches/ccache key: ccache:${{ matrix.os }}:${{ github.ref }}:${{ github.sha }} diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index cdfdf522..68ce2c2c 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -697,6 +697,9 @@ AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392 # PvP Restricted Areas (bots don't pvp) AiPlayerbot.PvpProhibitedAreaIds = "976,35,392" +# Improve react speed in battleground and arena (may cause lag) +AiPlayerbot.FastReactInBG = 1 + # # # diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index f94ea4a1..af64014e 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -30,6 +30,7 @@ #include "ObjectGuid.h" #include "PerformanceMonitor.h" #include "Player.h" +#include "PlayerbotAIConfig.h" #include "PlayerbotDbStore.h" #include "PlayerbotMgr.h" #include "Playerbots.h" @@ -342,10 +343,11 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal) UpdateAIInternal(elapsed, min); inCombat = bot->IsInCombat(); // test fix lags because of BG + bool inBG = bot->InBattleground() || bot->InArena(); if (bot && !inCombat) min = true; - if (HasRealPlayerMaster()) + if (HasRealPlayerMaster() || (sPlayerbotAIConfig->fastReactInBG && inBG)) min = false; YieldThread(min); @@ -1629,7 +1631,7 @@ bool PlayerbotAI::IsCaster(Player* player) { return IsRanged(player) && player-> bool PlayerbotAI::IsCombo(Player* player) { - int tab = AiFactory::GetPlayerSpecTab(player); + // int tab = AiFactory::GetPlayerSpecTab(player); return player->getClass() == CLASS_ROGUE || (player->getClass() == CLASS_DRUID && player->HasAura(768)); // cat druid } @@ -3020,8 +3022,8 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget) return true; } - aiObjectContext->GetValue("last movement")->Get().Set(nullptr); - aiObjectContext->GetValue("stay time")->Set(0); + // aiObjectContext->GetValue("last movement")->Get().Set(nullptr); + // aiObjectContext->GetValue("stay time")->Set(0); if (bot->IsFlying() || bot->HasUnitState(UNIT_STATE_IN_FLIGHT)) { @@ -3206,8 +3208,8 @@ bool PlayerbotAI::CastSpell(uint32 spellId, float x, float y, float z, Item* ite return true; } - aiObjectContext->GetValue("last movement")->Get().Set(nullptr); - aiObjectContext->GetValue("stay time")->Set(0); + // aiObjectContext->GetValue("last movement")->Get().Set(nullptr); + // aiObjectContext->GetValue("stay time")->Set(0); MotionMaster& mm = *bot->GetMotionMaster(); diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index aa01fcb4..4edcf6df 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -128,7 +128,7 @@ bool PlayerbotAIConfig::Initialize() pvpProhibitedZoneIds); LoadList>(sConfigMgr->GetOption("AiPlayerbot.PvpProhibitedAreaIds", "976,35"), pvpProhibitedAreaIds); - + fastReactInBG = sConfigMgr->GetOption("AiPlayerbot.FastReactInBG", true); LoadList>( sConfigMgr->GetOption("AiPlayerbot.RandomBotQuestIds", "7848,3802,5505,6502,7761"), randomBotQuestIds); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 5920d7d6..11d45965 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -207,6 +207,7 @@ public: std::vector randomBotGuilds; std::vector pvpProhibitedZoneIds; std::vector pvpProhibitedAreaIds; + bool fastReactInBG; bool randombotsWalkingRPG; bool randombotsWalkingRPGInDoors; diff --git a/src/strategy/actions/CheckMountStateAction.cpp b/src/strategy/actions/CheckMountStateAction.cpp index 17660836..6a51fd92 100644 --- a/src/strategy/actions/CheckMountStateAction.cpp +++ b/src/strategy/actions/CheckMountStateAction.cpp @@ -18,31 +18,31 @@ bool CheckMountStateAction::Execute(Event event) AI_VALUE2(bool, "combat", "self target") ? (AI_VALUE(uint8, "attacker count") > 0 ? false : true) : true; bool enemy = AI_VALUE(Unit*, "enemy player target"); // ignore grind target in BG or bots will dismount near any creature (eg: the rams in AV) - bool dps = (AI_VALUE(Unit*, "dps target") || (!bot->InBattleground() && AI_VALUE(Unit*, "grind target"))); - bool fartarget = - (enemy && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "enemy player target"), 40.0f)) || - (dps && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "dps target"), 50.0f)); + bool dps = AI_VALUE(Unit*, "dps target"); + // bool fartarget = (enemy && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "enemy player + // target"), 40.0f)) || + // (dps && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "dps target"), 50.0f)); bool attackdistance = false; - bool chasedistance = false; + // bool chasedistance = false; float attack_distance = 35.0f; if (PlayerbotAI::IsMelee(bot)) { - attack_distance = 10.0f; + attack_distance = 5.0f; } else { - attack_distance = 40.0f; + attack_distance = 30.0f; } - if (enemy) - attack_distance /= 2; + + // if (enemy) + // attack_distance /= 2; if (dps || enemy) { - attackdistance = (enemy || dps) && sServerFacade->IsDistanceLessThan( - AI_VALUE2(float, "distance", "current target"), attack_distance); - chasedistance = - enemy && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "enemy player target"), 45.0f) && - AI_VALUE2(bool, "moving", "enemy player target"); + Unit* currentTarget = AI_VALUE(Unit*, "current target"); + attackdistance = + (enemy || dps) && currentTarget && + sServerFacade->IsDistanceLessThan(AI_VALUE2(float, "distance", "current target"), attack_distance); } if (bot->IsMounted() && attackdistance) @@ -94,8 +94,7 @@ bool CheckMountStateAction::Execute(Event event) } } - if (bot->InBattleground() && !attackdistance && (noattackers || fartarget) && !bot->IsInCombat() && - !bot->IsMounted()) + if (bot->InBattleground() && !attackdistance && noattackers && !bot->IsInCombat() && !bot->IsMounted()) { if (bot->GetBattlegroundTypeId() == BATTLEGROUND_WS) { diff --git a/src/strategy/actions/FollowActions.cpp b/src/strategy/actions/FollowActions.cpp index 7a4a4bdb..81be99a6 100644 --- a/src/strategy/actions/FollowActions.cpp +++ b/src/strategy/actions/FollowActions.cpp @@ -29,7 +29,8 @@ bool FollowAction::Execute(Event event) if (Formation::IsNullLocation(loc) || loc.GetMapId() == -1) return false; - moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ()); + moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), false, false, false, + true); } if (Pet* pet = bot->GetPet()) diff --git a/src/strategy/actions/MoveToRpgTargetAction.cpp b/src/strategy/actions/MoveToRpgTargetAction.cpp index d13b5669..9640fc5c 100644 --- a/src/strategy/actions/MoveToRpgTargetAction.cpp +++ b/src/strategy/actions/MoveToRpgTargetAction.cpp @@ -94,15 +94,21 @@ bool MoveToRpgTargetAction::Execute(Event event) x += cos(angle) * INTERACTION_DISTANCE * distance; y += sin(angle) * INTERACTION_DISTANCE * distance; - + if (!wo->GetMap()->CheckCollisionAndGetValidCoords(wo, wo->GetPositionX(), wo->GetPositionY(), wo->GetPositionZ(), + x, y, z)) + { + x = wo->GetPositionX(); + y = wo->GetPositionY(); + z = wo->GetPositionZ(); + } // WaitForReach(distance); bool couldMove = false; - if (bot->IsWithinLOS(x, y, z)) - couldMove = MoveNear(mapId, x, y, z, 0); - else - couldMove = MoveTo(mapId, x, y, z); + // if (bot->IsWithinLOS(x, y, z)) + // couldMove = MoveNear(mapId, x, y, z, 0); + // else + couldMove = MoveTo(mapId, x, y, z, false, false, false, true); if (!couldMove && WorldPosition(mapId, x, y, z).distance(bot) > INTERACTION_DISTANCE) { diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 670735e4..fc999005 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -12,6 +12,7 @@ #include "Event.h" #include "FleeManager.h" +#include "G3D/Vector3.h" #include "GameObject.h" #include "Geometry.h" #include "LastMovementValue.h" @@ -68,7 +69,7 @@ void MovementAction::JumpTo(uint32 mapId, float x, float y, float z) 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()); + AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), 1000); } bool MovementAction::MoveNear(uint32 mapId, float x, float y, float z, float distance) @@ -160,13 +161,22 @@ bool MovementAction::MoveToLOS(WorldObject* target, bool ranged) return false; } -bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, bool react, bool normal_only) +bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, bool react, bool normal_only, + bool exact_waypoint) { UpdateMovementState(); if (!IsMovingAllowed(mapId, x, y, z)) { return false; } + if (IsDuplicateMove(mapId, x, y, z)) + { + return false; + } + if (IsWaitingForLastMove()) + { + return false; + } // if (bot->Unit::IsFalling()) { // bot->Say("I'm falling!, flag:" + std::to_string(bot->m_movementInfo.GetMovementFlags()), LANG_UNIVERSAL); // return false; @@ -177,17 +187,16 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, // if (bot->Unit::IsFalling()) { // bot->Say("I'm falling", LANG_UNIVERSAL); // } - bool generatePath = !bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !bot->IsFlying() && - !bot->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING) && !bot->IsInWater(); + // !bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && + + bool generatePath = !bot->IsFlying() && !bot->isSwimming(); bool disableMoveSplinePath = sPlayerbotAIConfig->disableMoveSplinePath >= 2 || (sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground()); - if (disableMoveSplinePath || !generatePath) + if (exact_waypoint || disableMoveSplinePath || !generatePath) { float distance = bot->GetExactDist(x, y, z); if (distance > sPlayerbotAIConfig->contactDistance) { - WaitForReach(distance); - if (bot->IsSitState()) bot->SetStandState(UNIT_STAND_STATE_STAND); @@ -199,7 +208,8 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, MotionMaster& mm = *bot->GetMotionMaster(); mm.Clear(); mm.MovePoint(mapId, x, y, z, generatePath); - AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation()); + float delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, 1000.0f * MoveDelay(distance)); + AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay); return true; } } @@ -215,8 +225,6 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, float distance = bot->GetExactDist(x, y, modifiedZ); if (distance > sPlayerbotAIConfig->contactDistance) { - WaitForReach(distance); - if (bot->IsSitState()) bot->SetStandState(UNIT_STAND_STATE_STAND); @@ -229,7 +237,9 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, mm.Clear(); mm.MoveSplinePath(&path); - AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation()); + // mm.MoveSplinePath(&path); + float delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, 1000.0f * MoveDelay(distance)); + AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay); return true; } } @@ -777,28 +787,34 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance) float ty = target->GetPositionY(); float tz = target->GetPositionZ(); float combatDistance = bot->GetCombatReach() + target->GetCombatReach(); - float distanceToTarget = bot->GetExactDist(target) - combatDistance; - float angle = bot->GetAngle(target); - float needToGo = distanceToTarget - distance; + distance += combatDistance; - float maxDistance = sPlayerbotAIConfig->spellDistance; - if (needToGo > 0 && needToGo > maxDistance) - needToGo = maxDistance; - else if (needToGo < 0 && needToGo < -maxDistance) - needToGo = -maxDistance; + if (target->HasUnitMovementFlag(MOVEMENTFLAG_FORWARD)) // target is moving forward, predict the position + { + float needToGo = bot->GetExactDist(target) - distance; + float timeToGo = MoveDelay(abs(needToGo)) + sPlayerbotAIConfig->reactDelay; + float targetMoveDist = timeToGo * target->GetSpeed(MOVE_RUN); + targetMoveDist = std::min(5.0f, targetMoveDist); + tx += targetMoveDist * cos(target->GetOrientation()); + ty += targetMoveDist * sin(target->GetOrientation()); + if (!target->GetMap()->CheckCollisionAndGetValidCoords(target, target->GetPositionX(), target->GetPositionY(), + target->GetPositionZ(), tx, ty, tz)) + { + // disable prediction if position is invalid + tx = target->GetPositionX(); + ty = target->GetPositionY(); + tz = target->GetPositionZ(); + } + } - float dx = cos(angle) * needToGo + bx; - float dy = sin(angle) * needToGo + by; - float dz; // = std::max(bz, tz); // calc accurate z position to avoid stuck - if (distanceToTarget > CONTACT_DISTANCE) - { - dz = bz + (tz - bz) * (needToGo / distanceToTarget); - } - else - { - dz = tz; - } - return MoveTo(target->GetMapId(), dx, dy, dz); + PathGenerator path(bot); + path.CalculatePath(tx, ty, tz, false); + PathType type = path.GetPathType(); + if (type != PATHFIND_NORMAL && type != PATHFIND_INCOMPLETE) + return false; + path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), distance); + G3D::Vector3 endPos = path.GetPath().back(); + return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z); } float MovementAction::GetFollowAngle() @@ -847,6 +863,29 @@ bool MovementAction::IsMovingAllowed(uint32 mapId, float x, float y, float z) return IsMovingAllowed(); } +bool MovementAction::IsDuplicateMove(uint32 mapId, float x, float y, float z) +{ + LastMovement& lastMove = *context->GetValue("last movement"); + + // heuristic 5s + if (lastMove.msTime + sPlayerbotAIConfig->maxWaitForMove < getMSTime() || + lastMove.lastMoveShort.GetExactDist(x, y, z) > 0.01f) + return false; + + return true; +} + +bool MovementAction::IsWaitingForLastMove() +{ + LastMovement& lastMove = *context->GetValue("last movement"); + + // heuristic 5s + if (lastMove.lastdelayTime + lastMove.msTime > getMSTime()) + return true; + + return false; +} + bool MovementAction::IsMovingAllowed() { // do not allow if not vehicle driver @@ -878,7 +917,7 @@ void MovementAction::UpdateMovementState() { bot->SetSwim(true); } - else + else if (!bot->Unit::IsInWater()) { bot->SetSwim(false); } @@ -1529,13 +1568,14 @@ const Movement::PointsArray MovementAction::SearchForBestPath(float x, float y, gen.CalculatePath(x, y, tempZ); Movement::PointsArray result = gen.GetPath(); float min_length = gen.getPathLength(); - if ((gen.GetPathType() & PATHFIND_NORMAL) && abs(tempZ - z) < 0.5f) + int typeOk = PATHFIND_NORMAL | PATHFIND_INCOMPLETE; + if ((gen.GetPathType() & typeOk) && abs(tempZ - z) < 0.5f) { modified_z = tempZ; return result; } // Start searching - if (gen.GetPathType() & PATHFIND_NORMAL) + if (gen.GetPathType() & typeOk) { modified_z = tempZ; found = true; @@ -1550,7 +1590,7 @@ const Movement::PointsArray MovementAction::SearchForBestPath(float x, float y, } PathGenerator gen(bot); gen.CalculatePath(x, y, tempZ); - if ((gen.GetPathType() & PATHFIND_NORMAL) && gen.getPathLength() < min_length) + if ((gen.GetPathType() & typeOk) && gen.getPathLength() < min_length) { found = true; min_length = gen.getPathLength(); @@ -1567,7 +1607,7 @@ const Movement::PointsArray MovementAction::SearchForBestPath(float x, float y, } PathGenerator gen(bot); gen.CalculatePath(x, y, tempZ); - if ((gen.GetPathType() & PATHFIND_NORMAL) && gen.getPathLength() < min_length) + if ((gen.GetPathType() & typeOk) && gen.getPathLength() < min_length) { found = true; min_length = gen.getPathLength(); @@ -2285,12 +2325,15 @@ bool MoveRandomAction::Execute(Event event) float angle = (float)rand_norm() * static_cast(M_PI); x += urand(0, distance) * cos(angle); y += urand(0, distance) * sin(angle); - bot->UpdateGroundPositionZ(x, y, z); - + if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), + bot->GetPositionZ(), x, y, z)) + { + continue; + } if (map->IsInWater(bot->GetPhaseMask(), x, y, z, bot->GetCollisionHeight())) continue; - bool moved = MoveTo(bot->GetMapId(), x, y, z); + bool moved = MoveTo(bot->GetMapId(), x, y, z, false, false, false, true); if (moved) return true; } diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index c0a5b888..2b8a82fe 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -27,7 +27,7 @@ protected: bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->contactDistance); 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 normal_only = false, bool exact_waypoint = false); bool MoveTo(Unit* target, float distance = 0.0f); bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig->contactDistance); float GetFollowAngle(); @@ -39,6 +39,8 @@ protected: void WaitForReach(float distance); bool IsMovingAllowed(Unit* target); bool IsMovingAllowed(uint32 mapId, float x, float y, float z); + bool IsDuplicateMove(uint32 mapId, float x, float y, float z); + bool IsWaitingForLastMove(); bool IsMovingAllowed(); bool Flee(Unit* target); void ClearIdleState(); diff --git a/src/strategy/triggers/TriggerContext.h b/src/strategy/triggers/TriggerContext.h index e0b7ce99..a10d9ca7 100644 --- a/src/strategy/triggers/TriggerContext.h +++ b/src/strategy/triggers/TriggerContext.h @@ -239,7 +239,7 @@ private: } static Trigger* medium_group_heal_occasion(PlayerbotAI* ai) { - return new AoeInGroupTrigger(ai, "group heal occasion", "medium", 0.4); + return new AoeInGroupTrigger(ai, "group heal occasion", "medium", 0.6); } static Trigger* target_changed(PlayerbotAI* botAI) { return new TargetChangedTrigger(botAI); } static Trigger* swimming(PlayerbotAI* botAI) { return new IsSwimmingTrigger(botAI); } diff --git a/src/strategy/values/Arrow.cpp b/src/strategy/values/Arrow.cpp index adcfcde4..a981eade 100644 --- a/src/strategy/values/Arrow.cpp +++ b/src/strategy/values/Arrow.cpp @@ -48,8 +48,8 @@ WorldLocation ArrowFormation::GetLocationInternal() float y = master->GetPositionY() - masterUnit->GetY() + botUnit->GetY(); float z = master->GetPositionZ(); - float ground = master->GetMapHeight(x, y, z + 30.0f); - if (ground <= INVALID_HEIGHT) + if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(), + master->GetPositionZ(), x, y, z)) return Formation::NullLocation; // master->UpdateGroundPositionZ(x, y, z); return WorldLocation(master->GetMapId(), x, y, z); diff --git a/src/strategy/values/Formations.cpp b/src/strategy/values/Formations.cpp index 7036609f..9418b441 100644 --- a/src/strategy/values/Formations.cpp +++ b/src/strategy/values/Formations.cpp @@ -89,12 +89,9 @@ public: float y = master->GetPositionY() + sin(angle) * range; float z = master->GetPositionZ(); - float ground = master->GetMapHeight(x, y, z + 30.0f); - if (ground <= INVALID_HEIGHT) + if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(), + master->GetPositionZ(), x, y, z)) return Formation::NullLocation; - - // z += CONTACT_DISTANCE; - // bot->UpdateAllowedPositionZ(x, y, z); return WorldLocation(master->GetMapId(), x, y, z); } @@ -118,21 +115,39 @@ public: time_t now = time(nullptr); if (!lastChangeTime || now - lastChangeTime >= 3) { - lastChangeTime = now; - dx = (urand(0, 10) / 10.0 - 0.5) * sPlayerbotAIConfig->tooCloseDistance; - dy = (urand(0, 10) / 10.0 - 0.5) * sPlayerbotAIConfig->tooCloseDistance; - dr = sqrt(dx * dx + dy * dy); + Player* master = botAI->GetGroupMaster(); + if (!master) + return WorldLocation(); + + float range = sPlayerbotAIConfig->followDistance; + float angle = GetFollowAngle(); + + time_t now = time(nullptr); + if (!lastChangeTime || now - lastChangeTime >= 3) + { + lastChangeTime = now; + dx = (urand(0, 10) / 10.0 - 0.5) * sPlayerbotAIConfig->tooCloseDistance; + dy = (urand(0, 10) / 10.0 - 0.5) * sPlayerbotAIConfig->tooCloseDistance; + dr = sqrt(dx * dx + dy * dy); + } + + float x = master->GetPositionX() + cos(angle) * range + dx; + float y = master->GetPositionY() + sin(angle) * range + dy; + float z = master->GetPositionZ(); + if (!master->GetMap()->CheckCollisionAndGetValidCoords( + master, master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), x, y, z)) + return Formation::NullLocation; + // bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), + // bot->GetPositionZ(), x, y, z); + return WorldLocation(master->GetMapId(), x, y, z); } float x = master->GetPositionX() + cos(angle) * range + dx; float y = master->GetPositionY() + sin(angle) * range + dy; float z = master->GetPositionZ(); - float ground = master->GetMapHeight(x, y, z + 30.0f); - if (ground <= INVALID_HEIGHT) + if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(), + master->GetPositionZ(), x, y, z)) return Formation::NullLocation; - - z += CONTACT_DISTANCE; - bot->UpdateAllowedPositionZ(x, y, z); return WorldLocation(master->GetMapId(), x, y, z); } @@ -184,13 +199,10 @@ public: float x = target->GetPositionX() + cos(angle) * range; float y = target->GetPositionY() + sin(angle) * range; float z = target->GetPositionZ(); - float ground = target->GetMapHeight(x, y, z + 30.0f); - if (ground <= INVALID_HEIGHT) + if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(), + master->GetPositionZ(), x, y, z)) return Formation::NullLocation; - z += CONTACT_DISTANCE; - bot->UpdateAllowedPositionZ(x, y, z); - return WorldLocation(bot->GetMapId(), x, y, z); } }; @@ -350,16 +362,18 @@ public: if (minDist) { - z += CONTACT_DISTANCE; - bot->UpdateAllowedPositionZ(minX, minY, z); + if (!master->GetMap()->CheckCollisionAndGetValidCoords( + master, master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), x, y, z)) + return Formation::NullLocation; return WorldLocation(bot->GetMapId(), minX, minY, z); } return Formation::NullLocation; } - z += CONTACT_DISTANCE; - bot->UpdateAllowedPositionZ(x, y, z); + if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(), + master->GetPositionZ(), x, y, z)) + return Formation::NullLocation; return WorldLocation(bot->GetMapId(), x, y, z); } }; @@ -618,12 +632,12 @@ WorldLocation MoveFormation::MoveSingleLine(std::vector line, float dif float lx = x + cos(angle) * radius; float ly = y + sin(angle) * radius; float lz = cz; - float ground = bot->GetMapHeight(lx, ly, lz + 30.0f); - if (ground <= INVALID_HEIGHT) + + Player* master = botAI->GetMaster(); + if (!master->GetMap()->CheckCollisionAndGetValidCoords( + master, master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), lx, ly, lz)) return Formation::NullLocation; - lz += CONTACT_DISTANCE; - bot->UpdateAllowedPositionZ(lx, ly, lz); return WorldLocation(bot->GetMapId(), lx, ly, lz); } diff --git a/src/strategy/values/LastMovementValue.cpp b/src/strategy/values/LastMovementValue.cpp index 767bc89e..f7b5488e 100644 --- a/src/strategy/values/LastMovementValue.cpp +++ b/src/strategy/values/LastMovementValue.cpp @@ -6,6 +6,7 @@ #include "LastMovementValue.h" #include "Playerbots.h" +#include "Timer.h" LastMovement::LastMovement() { clear(); } @@ -38,17 +39,19 @@ void LastMovement::clear() lastAreaTrigger = 0; lastFlee = 0; nextTeleport = 0; + msTime = 0; + lastdelayTime = 0; } void LastMovement::Set(Unit* follow) { - Set(0, 0.0f, 0.0f, 0.0f, 0.0f); + Set(0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); setShort(WorldPosition()); setPath(TravelPath()); lastFollow = follow; } -void LastMovement::Set(uint32 mapId, float x, float y, float z, float ori) +void LastMovement::Set(uint32 mapId, float x, float y, float z, float ori, float delayTime) { lastMoveToMapId = mapId; lastMoveToX = x; @@ -57,6 +60,8 @@ void LastMovement::Set(uint32 mapId, float x, float y, float z, float ori) lastMoveToOri = ori; lastFollow = nullptr; lastMoveShort = WorldPosition(mapId, x, y, z, ori); + msTime = getMSTime(); + lastdelayTime = delayTime; } void LastMovement::setShort(WorldPosition point) diff --git a/src/strategy/values/LastMovementValue.h b/src/strategy/values/LastMovementValue.h index 89277014..fc073a2a 100644 --- a/src/strategy/values/LastMovementValue.h +++ b/src/strategy/values/LastMovementValue.h @@ -35,7 +35,7 @@ public: void clear(); void Set(Unit* follow); - void Set(uint32 mapId, float x, float y, float z, float ori); + void Set(uint32 mapId, float x, float y, float z, float ori, float delayTime); void setShort(WorldPosition point); void setPath(TravelPath path); @@ -50,7 +50,9 @@ public: float lastMoveToY; float lastMoveToZ; float lastMoveToOri; + float lastdelayTime; WorldPosition lastMoveShort; + uint32 msTime; TravelPath lastPath; time_t nextTeleport; std::future future; diff --git a/src/strategy/values/PartyMemberToHeal.cpp b/src/strategy/values/PartyMemberToHeal.cpp index 31a8f00a..5c158428 100644 --- a/src/strategy/values/PartyMemberToHeal.cpp +++ b/src/strategy/values/PartyMemberToHeal.cpp @@ -82,8 +82,7 @@ bool PartyMemberToHeal::Check(Unit* player) // sServerFacade->GetDistance2d(bot, player) < (player->IsPlayer() && botAI->IsTank((Player*)player) ? 50.0f // : 40.0f); return player->GetMapId() == bot->GetMapId() && !player->IsCharmed() && - bot->GetDistance2d(player) < sPlayerbotAIConfig->healDistance * 2 && - bot->IsWithinLOS(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); + bot->GetDistance2d(player) < sPlayerbotAIConfig->healDistance * 2 && bot->IsWithinLOSInMap(player); } Unit* PartyMemberToProtect::Calculate()