176 lines
5.1 KiB
C++
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();
|
|
}
|