Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/game/WorldHandlers/Transports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,32 @@ void GlobalTransport::TeleportTransport(uint32 newMapid, float x, float y, float
SetMap(newMap);
Relocate(x, y, z);

#ifdef ENABLE_PLAYERBOTS
if (oldMap != newMap)
{
// delete playerbots from player range on their client -- otherwise watch client crash
for (UnitSet::const_iterator itr = m_passengers.begin(); itr != m_passengers.end(); ++itr)
{
Player* receiver = (*itr) ? (*itr)->ToPlayer() : nullptr;
if (!receiver || receiver->GetPlayerbotAI())
continue;

for (UnitSet::const_iterator itr2 = m_passengers.begin(); itr2 != m_passengers.end(); ++itr2)
{
Player* other = (*itr2) ? (*itr2)->ToPlayer() : nullptr;
if (!other || other == receiver || !other->GetPlayerbotAI())
continue;

UpdateData updateData;
other->BuildOutOfRangeUpdateBlock(&updateData);
WorldPacket packet;
updateData.BuildPacket(&packet);
receiver->SendDirectMessage(&packet);
}
}
}
#endif

for (UnitSet::iterator itr = m_passengers.begin(); itr != m_passengers.end();)
{
UnitSet::iterator it2 = itr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace ai
virtual bool isUseful()
{
return AI_VALUE2(float, "distance", "master target") > sPlayerbotAIConfig.followDistance &&
!AI_VALUE(bool, "can loot");
!AI_VALUE(bool, "can loot") || transportBoardingDelayTime > 0;
}

};
Expand Down
116 changes: 115 additions & 1 deletion src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include "../../FleeManager.h"
#include "../../LootObjectStack.h"
#include "../../PlayerbotAIConfig.h"
#include "WorldHandlers/Transports.h"
#include "movement/MoveSplineInit.h"
#include "movement/MoveSpline.h"

using namespace ai;

Expand Down Expand Up @@ -180,6 +183,7 @@ bool MovementAction::IsMovingAllowed()
if (bot->IsFrozen() || bot->IsPolymorphed() ||
(bot->IsDead() && !bot->GetCorpse()) ||
bot->IsBeingTeleported() ||
bot->GetTransport() ||
bot->IsInRoots() ||
bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || bot->IsCharmed() ||
bot->HasAuraType(SPELL_AURA_MOD_STUN) || bot->IsTaxiFlying())
Expand All @@ -189,6 +193,105 @@ bool MovementAction::IsMovingAllowed()
return mm.GetCurrentMovementGeneratorType() != FLIGHT_MOTION_TYPE;
}

bool MovementAction::FollowOnTransport(Unit* target, Player* master)
{
float distanceToMaster = bot->GetDistance(master);
bool outOfRange = distanceToMaster > sPlayerbotAIConfig.sightDistance;
uint32 currentTime = time(0);
if (outOfRange)
{
bot->m_movementInfo.RemoveMovementFlag(MOVEFLAG_ONTRANSPORT);
transportBoardingDelayTime = 0;
return false;
}

bool isApproaching = transportBoardingDelayTime > 0;
bool approachTimedOut = isApproaching && (currentTime - transportBoardingDelayTime) > 1;
// Determine if we should complete boarding now
if (isApproaching && approachTimedOut)
{
Transport* transport = master->GetTransport();
MotionMaster &mm = *bot->GetMotionMaster();
// Complete boarding - snap to master and attach to transport
transportBoardingDelayTime = 0;
bot->clearUnitState(UNIT_STAT_IGNORE_PATHFINDING);
mm.Clear();
bot->movespline->_Interrupt();
bot->NearTeleportTo(master->GetPositionX(),
master->GetPositionY(),
master->GetPositionZ(), bot->GetOrientation());
bot->SetTransport(transport);
transport->AddPassenger(bot);
bot->m_movementInfo.SetTransportData(
transport->GetObjectGuid(),
master->m_movementInfo.GetTransportPos()->x,
master->m_movementInfo.GetTransportPos()->y,
master->m_movementInfo.GetTransportPos()->z,
bot->GetOrientation(),
getMSTime()
);
bot->m_movementInfo.AddMovementFlag(MOVEFLAG_ONTRANSPORT);

WorldPacket data(MSG_MOVE_HEARTBEAT, 64);
data << bot->GetPackGUID();
bot->m_movementInfo.Write(data);
bot->SendMessageToSet(&data, false);
AI_VALUE(LastMovement&, "last movement").Set(target);
return true;

}

if (distanceToMaster <= sPlayerbotAIConfig.sightDistance)
{
bot->m_movementInfo.AddMovementFlag(MOVEFLAG_ONTRANSPORT);
// Walk toward master in a straight line, ignoring map geometry
if(!isApproaching) // set the timeout
{
transportBoardingDelayTime = currentTime;
}
Movement::MoveSplineInit init(*bot);
init.MoveTo(master->GetPositionX(), master->GetPositionY(), master->GetPositionZ());
init.SetWalk(false);
init.Launch();
AI_VALUE(LastMovement&, "last movement").Set(target);
return true;
}
}

bool MovementAction::FollowOffTransport(Unit* target, Player* master)
{
Transport* transport = master->GetTransport();
Transport* botTransport = bot->GetTransport();
if(!transport || transport != botTransport) // master has left the transport
{
ObjectGuid botGuid = bot->GetObjectGuid();
uint32 currentTime = time(0);
// Delay elapsed or master too far - disembark now
transportBoardingDelayTime = 0;
bot->TradeCancel(false);
botTransport->RemovePassenger(bot);
bot->m_movementInfo.ClearTransportData();
bot->m_movementInfo.RemoveMovementFlag(MOVEFLAG_ONTRANSPORT);
bot->TeleportTo(master->GetMapId(),
master->GetPositionX(),
master->GetPositionY(),
master->GetPositionZ(),
bot->GetOrientation(),
TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET);
WorldPacket data(MSG_MOVE_HEARTBEAT, 64);
data << bot->GetPackGUID();
bot->m_movementInfo.Write(data);
bot->SendMessageToSet(&data, false);
AI_VALUE(LastMovement&, "last movement").Set(target);
}
else
{
// Bot and master on same transport - clear any stale delay
transportBoardingDelayTime = 0;
}
return true;
}

bool MovementAction::Follow(Unit* target, float distance)
{
return Follow(target, distance, GetFollowAngle());
Expand All @@ -198,11 +301,22 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
{
MotionMaster &mm = *bot->GetMotionMaster();

if (!target)
if (!target || bot->IsBeingTeleported())
{
return false;
}

Player* master = target->ToPlayer();
if (master && bot->GetTransport() != master->GetTransport())
{
if(bot->GetTransport())
return FollowOffTransport(target, master);
else
if (master->GetTransport()) // master on transport
return FollowOnTransport(target, master);
}


if (bot->GetDistance2d(target->GetPositionX(), target->GetPositionY()) <= sPlayerbotAIConfig.sightDistance &&
abs(bot->GetPositionZ() - target->GetPositionZ()) >= sPlayerbotAIConfig.spellDistance)
{
Expand Down
4 changes: 4 additions & 0 deletions src/modules/Bots/playerbot/strategy/actions/MovementActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace ai
MovementAction(PlayerbotAI* ai, string name) : Action(ai, name)
{
bot = ai->GetBot();
transportBoardingDelayTime = 0;
}

protected:
Expand All @@ -20,6 +21,8 @@ namespace ai
float GetFollowAngle();
bool Follow(Unit* target, float distance = sPlayerbotAIConfig.followDistance);
bool Follow(Unit* target, float distance, float angle);
bool FollowOnTransport(Unit* target, Player* master);
bool FollowOffTransport(Unit* target, Player* master);
void WaitForReach(float distance);
bool IsMovingAllowed(Unit* target);
bool IsMovingAllowed(uint32 mapId, float x, float y, float z);
Expand All @@ -28,6 +31,7 @@ namespace ai

protected:
Player* bot;
uint32 transportBoardingDelayTime;
};

class FleeAction : public MovementAction
Expand Down