2025-03-18 19:19:03 -04:00

176 lines
5.1 KiB
C++

/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
* and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "Arrow.h"
#include "Map.h"
#include "Playerbots.h"
WorldLocation ArrowFormation::GetLocationInternal()
{
if (!bot->GetGroup())
return Formation::NullLocation;
Build();
uint32 tankLines = 1 + tanks.Size() / 6;
uint32 meleeLines = 1 + melee.Size() / 6;
uint32 rangedLines = 1 + ranged.Size() / 6;
uint32 healerLines = 1 + healers.Size() / 6;
float offset = 0.f;
Player* master = botAI->GetMaster();
if (!botAI->IsSafe(master))
return Formation::NullLocation;
float orientation = master->GetOrientation();
MultiLineUnitPlacer placer(orientation);
tanks.PlaceUnits(&placer);
tanks.Move(-cos(orientation) * offset, -sin(orientation) * offset);
offset += tankLines * sPlayerbotAIConfig->followDistance + sPlayerbotAIConfig->tooCloseDistance / 2;
melee.PlaceUnits(&placer);
melee.Move(-cos(orientation) * offset, -sin(orientation) * offset);
offset += meleeLines * sPlayerbotAIConfig->followDistance + sPlayerbotAIConfig->tooCloseDistance / 2;
ranged.PlaceUnits(&placer);
ranged.Move(-cos(orientation) * offset, -sin(orientation) * offset);
offset += rangedLines * sPlayerbotAIConfig->followDistance;
healers.PlaceUnits(&placer);
healers.Move(-cos(orientation) * offset, -sin(orientation) * offset);
if (!masterUnit || !botUnit)
return Formation::NullLocation;
float x = master->GetPositionX() - masterUnit->GetX() + botUnit->GetX();
float y = master->GetPositionY() - masterUnit->GetY() + botUnit->GetY();
float z = master->GetPositionZ() + master->GetHoverHeight();
if (!master->GetMap()->CheckCollisionAndGetValidCoords(master, master->GetPositionX(), master->GetPositionY(),
master->GetPositionZ(), x, y, z))
{
x = master->GetPositionX() - masterUnit->GetX() + botUnit->GetX();
y = master->GetPositionY() - masterUnit->GetY() + botUnit->GetY();
z = master->GetPositionZ() + master->GetHoverHeight();
master->UpdateAllowedPositionZ(x, y, z);
}
return WorldLocation(master->GetMapId(), x, y, z);
}
void ArrowFormation::Build()
{
if (built)
return;
FillSlotsExceptMaster();
AddMasterToSlot();
built = true;
}
FormationSlot* ArrowFormation::FindSlot(Player* member)
{
if (botAI->IsTank(member))
return &tanks;
else if (botAI->IsHeal(member))
return &healers;
else if (botAI->IsRanged(member))
return &ranged;
else
return &melee;
}
void ArrowFormation::FillSlotsExceptMaster()
{
Group* group = bot->GetGroup();
GroupReference* gref = group->GetFirstMember();
uint32 index = 0;
while (gref)
{
Player* member = gref->GetSource();
if (botAI->IsSafe(member))
{
if (member == bot)
FindSlot(member)->AddLast(botUnit = new FormationUnit(index, false));
else if (member != botAI->GetMaster())
FindSlot(member)->AddLast(new FormationUnit(index, false));
++index;
}
gref = gref->next();
}
}
void ArrowFormation::AddMasterToSlot()
{
Group* group = bot->GetGroup();
GroupReference* gref = group->GetFirstMember();
uint32 index = 0;
while (gref)
{
Player* member = gref->GetSource();
if (member == botAI->GetMaster())
{
FindSlot(member)->InsertAtCenter(masterUnit = new FormationUnit(index, true));
break;
}
gref = gref->next();
++index;
}
}
void FormationSlot::PlaceUnits(UnitPlacer* placer)
{
uint32 index = 0;
uint32 count = units.size();
for (FormationUnit* unit : units)
{
unit->SetLocation(placer->Place(unit, index, count));
++index;
}
}
UnitPosition MultiLineUnitPlacer::Place(FormationUnit* unit, uint32 index, uint32 count)
{
SingleLineUnitPlacer placer(orientation);
if (count <= 6)
return placer.Place(unit, index, count);
uint32 lineNo = index / 6;
uint32 indexInLine = index % 6;
uint32 lineSize = std::max(count - lineNo * 6, uint32(6));
float x = cos(orientation) * sPlayerbotAIConfig->followDistance * lineNo;
float y = sin(orientation) * sPlayerbotAIConfig->followDistance * lineNo;
return placer.Place(unit, indexInLine, lineSize);
}
UnitPosition SingleLineUnitPlacer::Place(FormationUnit* unit, uint32 index, uint32 count)
{
float angle = orientation - M_PI / 2.0f;
float x = cos(angle) * sPlayerbotAIConfig->followDistance * ((float)index - (float)count / 2);
float y = sin(angle) * sPlayerbotAIConfig->followDistance * ((float)index - (float)count / 2);
return UnitPosition(x, y);
}
void FormationSlot::Move(float dx, float dy)
{
for (FormationUnit* unit : units)
{
unit->SetLocation(unit->GetX() + dx, unit->GetY() + dy);
}
}
FormationSlot::~FormationSlot()
{
for (FormationUnit* unit : units)
{
delete unit;
}
units.clear();
}