mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 23:49:25 +02:00
155 lines
5.0 KiB
C++
155 lines
5.0 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
*/
|
|
|
|
#include "MoveToTravelTargetAction.h"
|
|
|
|
#include "ChooseRpgTargetAction.h"
|
|
#include "LootObjectStack.h"
|
|
#include "Playerbots.h"
|
|
|
|
bool MoveToTravelTargetAction::Execute(Event /*event*/)
|
|
{
|
|
TravelTarget* target = AI_VALUE(TravelTarget*, "travel target");
|
|
|
|
WorldPosition botLocation(bot);
|
|
WorldLocation location = *target->getPosition();
|
|
|
|
Group* group = bot->GetGroup();
|
|
if (group && !urand(0, 1) && bot == botAI->GetGroupLeader() && !bot->IsInCombat())
|
|
{
|
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
{
|
|
Player* member = ref->GetSource();
|
|
if (member == bot)
|
|
continue;
|
|
|
|
if (!member->IsAlive())
|
|
continue;
|
|
|
|
if (!member->isMoving())
|
|
continue;
|
|
|
|
PlayerbotAI* memberBotAI = GET_PLAYERBOT_AI(member);
|
|
if (memberBotAI && !memberBotAI->HasStrategy("follow", BOT_STATE_NON_COMBAT))
|
|
continue;
|
|
|
|
WorldPosition memberPos(member);
|
|
WorldPosition targetPos = *target->getPosition();
|
|
|
|
float memberDistance = botLocation.distance(memberPos);
|
|
|
|
if (memberDistance < 50.0f)
|
|
continue;
|
|
if (memberDistance > sPlayerbotAIConfig.reactDistance * 20)
|
|
continue;
|
|
|
|
// float memberAngle = botLocation.getAngleBetween(targetPos, memberPos);
|
|
|
|
// if (botLocation.getMapId() == targetPos.getMapId() && botLocation.getMapId() == memberPos.getMapId() &&
|
|
// memberAngle < static_cast<float>(M_PI) / 2) //We are heading that direction anyway.
|
|
// continue;
|
|
|
|
if (!urand(0, 5))
|
|
{
|
|
std::ostringstream out;
|
|
if (botAI->GetMaster() && !bot->GetGroup()->IsMember(botAI->GetMaster()->GetGUID()))
|
|
out << "Waiting a bit for ";
|
|
else
|
|
out << "Please hurry up ";
|
|
|
|
out << member->GetName();
|
|
|
|
botAI->TellMasterNoFacing(out);
|
|
}
|
|
|
|
target->setExpireIn(target->getTimeLeft() + sPlayerbotAIConfig.maxWaitForMove);
|
|
|
|
botAI->SetNextCheckDelay(sPlayerbotAIConfig.maxWaitForMove);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
float maxDistance = target->getDestination()->getRadiusMin();
|
|
|
|
// Spread bots around the target but keep the offset stable per
|
|
// (bot, destination) pair. Previously the angle and radius were
|
|
// re-rolled every time the action re-entered (i.e. every tick the
|
|
// bot wasn't already moving), which made bots oscillate between
|
|
// two random points around the same quest POI instead of
|
|
// committing to one approach.
|
|
uint32 botLow = bot->GetGUID().GetCounter();
|
|
int32 destSeed = static_cast<int32>(location.GetPositionX()) * 73856093 ^
|
|
static_cast<int32>(location.GetPositionY()) * 19349663;
|
|
uint32 seed = botLow ^ static_cast<uint32>(destSeed);
|
|
float angle = 2.0f * static_cast<float>(M_PI) * static_cast<float>(seed % 1000) / 1000.0f;
|
|
float mod = 0.5f + static_cast<float>((seed / 1000) % 1000) / 2000.0f; // [0.5, 1.0]
|
|
|
|
if (target->getMaxTravelTime() > target->getTimeLeft()) // The bot is late. Speed it up.
|
|
{
|
|
// distance = sPlayerbotAIConfig.fleeDistance;
|
|
// angle = bot->GetAngle(location.GetPositionX(), location.GetPositionY());
|
|
// location = botLocation.getLocation();
|
|
}
|
|
|
|
float x = location.GetPositionX();
|
|
float y = location.GetPositionY();
|
|
float z = location.GetPositionZ();
|
|
float mapId = location.GetMapId();
|
|
|
|
x += cos(angle) * maxDistance * mod;
|
|
y += sin(angle) * maxDistance * mod;
|
|
|
|
bool canMove = false;
|
|
|
|
if (bot->IsWithinLOS(x, y, z))
|
|
canMove = MoveNear(mapId, x, y, z, 0);
|
|
else
|
|
canMove = MoveTo(mapId, x, y, z, false, false);
|
|
|
|
if (!canMove && !target->isForced())
|
|
{
|
|
target->incRetry(true);
|
|
|
|
if (target->isMaxRetry(true))
|
|
target->setStatus(TRAVEL_STATUS_COOLDOWN);
|
|
}
|
|
else
|
|
target->setRetry(true);
|
|
|
|
return canMove;
|
|
}
|
|
|
|
bool MoveToTravelTargetAction::isUseful()
|
|
{
|
|
if (!botAI->AllowActivity(TRAVEL_ACTIVITY))
|
|
return false;
|
|
|
|
if (!context->GetValue<TravelTarget*>("travel target")->Get()->isTraveling())
|
|
return false;
|
|
|
|
if (bot->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
|
return false;
|
|
|
|
if (bot->IsFlying())
|
|
return false;
|
|
|
|
if (bot->isMoving())
|
|
return false;
|
|
|
|
if (!AI_VALUE(bool, "can move around"))
|
|
return false;
|
|
|
|
LootObject loot = AI_VALUE(LootObject, "loot target");
|
|
if (loot.IsLootPossible(bot))
|
|
return false;
|
|
|
|
if (!ChooseRpgTargetAction::isFollowValid(bot,
|
|
*context->GetValue<TravelTarget*>("travel target")->Get()->getPosition()))
|
|
return false;
|
|
|
|
return true;
|
|
}
|