mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-14 01:19:08 +00:00
267 lines
6.8 KiB
C++
267 lines
6.8 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 "Stances.h"
|
|
|
|
#include "Arrow.h"
|
|
#include "Event.h"
|
|
#include "Playerbots.h"
|
|
|
|
Unit* Stance::GetTarget()
|
|
{
|
|
Unit* target = AI_VALUE(Unit*, GetTargetName());
|
|
if (target)
|
|
return target;
|
|
|
|
ObjectGuid pullTarget = context->GetValue<ObjectGuid>("pull target")->Get();
|
|
if (pullTarget)
|
|
botAI->GetUnit(pullTarget);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
WorldLocation Stance::GetLocation()
|
|
{
|
|
Unit* target = GetTarget();
|
|
if (!target)
|
|
return Formation::NullLocation;
|
|
|
|
return GetLocationInternal();
|
|
}
|
|
|
|
WorldLocation Stance::GetNearLocation(float angle, float distance)
|
|
{
|
|
Unit* target = GetTarget();
|
|
|
|
float x = target->GetPositionX() + cos(angle) * distance;
|
|
float y = target->GetPositionY() + sin(angle) * distance;
|
|
float z = target->GetPositionZ();
|
|
|
|
if (bot->IsWithinLOS(x, y, z))
|
|
return WorldLocation(bot->GetMapId(), x, y, z);
|
|
|
|
return Formation::NullLocation;
|
|
}
|
|
|
|
WorldLocation MoveStance::GetLocationInternal()
|
|
{
|
|
Unit* target = GetTarget();
|
|
float distance = std::max(sPlayerbotAIConfig->meleeDistance, target->GetCombatReach());
|
|
|
|
float angle = GetAngle();
|
|
return GetNearLocation(angle, distance);
|
|
}
|
|
|
|
std::string const Stance::GetTargetName() { return "current target"; }
|
|
|
|
float Stance::GetMaxDistance() { return sPlayerbotAIConfig->contactDistance; }
|
|
|
|
StanceValue::~StanceValue()
|
|
{
|
|
if (value)
|
|
{
|
|
delete value;
|
|
value = nullptr;
|
|
}
|
|
}
|
|
|
|
class NearStance : public MoveStance
|
|
{
|
|
public:
|
|
NearStance(PlayerbotAI* botAI) : MoveStance(botAI, "near") {}
|
|
|
|
float GetAngle() override
|
|
{
|
|
Unit* target = GetTarget();
|
|
|
|
if (target->GetVictim() && target->GetVictim()->GetGUID() == bot->GetGUID())
|
|
return target->GetOrientation();
|
|
|
|
if (botAI->HasStrategy("behind", BOT_STATE_COMBAT))
|
|
{
|
|
Unit* target = GetTarget();
|
|
Group* group = bot->GetGroup();
|
|
uint32 index = 0;
|
|
uint32 count = 0;
|
|
if (group)
|
|
{
|
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
{
|
|
Player* member = ref->GetSource();
|
|
if (member == bot)
|
|
index = count;
|
|
|
|
if (member && !botAI->IsRanged(member) && !botAI->IsTank(member))
|
|
count++;
|
|
}
|
|
}
|
|
|
|
float angle = target->GetOrientation() + M_PI;
|
|
if (!count)
|
|
return angle;
|
|
|
|
float increment = M_PI / 4 / count;
|
|
return round((angle + index * increment - M_PI / 4) * 10.0f) / 10.0f;
|
|
}
|
|
|
|
float angle = GetFollowAngle() + target->GetOrientation();
|
|
if (Player* master = GetMaster())
|
|
angle -= master->GetOrientation();
|
|
|
|
return angle;
|
|
}
|
|
};
|
|
|
|
class TankStance : public MoveStance
|
|
{
|
|
public:
|
|
TankStance(PlayerbotAI* botAI) : MoveStance(botAI, "tank") {}
|
|
|
|
float GetAngle() override
|
|
{
|
|
Unit* target = GetTarget();
|
|
return target->GetOrientation();
|
|
}
|
|
};
|
|
|
|
class TurnBackStance : public MoveStance
|
|
{
|
|
public:
|
|
TurnBackStance(PlayerbotAI* botAI) : MoveStance(botAI, "turnback") {}
|
|
|
|
float GetAngle() override
|
|
{
|
|
Unit* target = GetTarget();
|
|
|
|
uint32 count = 0;
|
|
float angle = 0.0f;
|
|
if (Group* group = bot->GetGroup())
|
|
{
|
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
{
|
|
if (Player* member = ref->GetSource())
|
|
if (member != bot && botAI->IsRanged(member))
|
|
{
|
|
angle += target->GetAngle(member);
|
|
++count;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!count)
|
|
return target->GetOrientation();
|
|
|
|
return std::round((angle / count) * 10.0f) / 10.0f + M_PI;
|
|
}
|
|
};
|
|
|
|
class BehindStance : public MoveStance
|
|
{
|
|
public:
|
|
BehindStance(PlayerbotAI* botAI) : MoveStance(botAI, "behind") {}
|
|
|
|
float GetAngle() override
|
|
{
|
|
Unit* target = GetTarget();
|
|
|
|
uint32 index = 0;
|
|
uint32 count = 0;
|
|
if (Group* group = bot->GetGroup())
|
|
{
|
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
{
|
|
if (Player* member = ref->GetSource())
|
|
{
|
|
if (member == bot)
|
|
index = count;
|
|
|
|
if (!botAI->IsRanged(member) && !botAI->IsTank(member))
|
|
++count;
|
|
}
|
|
}
|
|
}
|
|
|
|
float angle = target->GetOrientation() + M_PI;
|
|
if (!count)
|
|
return angle;
|
|
|
|
float increment = M_PI / 4 / count;
|
|
return std::round((angle + index * increment - M_PI / 4) * 10.0f) / 10.0f;
|
|
}
|
|
};
|
|
|
|
StanceValue::StanceValue(PlayerbotAI* botAI) : ManualSetValue<Stance*>(botAI, new NearStance(botAI), "stance") {}
|
|
|
|
std::string const StanceValue::Save() { return value ? value->getName() : "?"; }
|
|
|
|
bool StanceValue::Load(std::string const name)
|
|
{
|
|
if (name == "behind")
|
|
{
|
|
if (value)
|
|
delete value;
|
|
value = new BehindStance(botAI);
|
|
}
|
|
else if (name == "near" || name == "default")
|
|
{
|
|
if (value)
|
|
delete value;
|
|
value = new NearStance(botAI);
|
|
}
|
|
else if (name == "tank")
|
|
{
|
|
if (value)
|
|
delete value;
|
|
value = new TankStance(botAI);
|
|
}
|
|
else if (name == "turnback" || name == "turn")
|
|
{
|
|
if (value)
|
|
delete value;
|
|
value = new TurnBackStance(botAI);
|
|
}
|
|
else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SetStanceAction::Execute(Event event)
|
|
{
|
|
std::string const stance = event.getParam();
|
|
|
|
StanceValue* value = (StanceValue*)context->GetValue<Stance*>("stance");
|
|
if (stance == "?" || stance.empty())
|
|
{
|
|
std::ostringstream str;
|
|
str << "Stance: |cff00ff00" << value->Get()->getName();
|
|
botAI->TellMaster(str);
|
|
return true;
|
|
}
|
|
|
|
if (stance == "show")
|
|
{
|
|
WorldLocation loc = value->Get()->GetLocation();
|
|
if (!Formation::IsNullLocation(loc))
|
|
botAI->Ping(loc.GetPositionX(), loc.GetPositionY());
|
|
|
|
return true;
|
|
}
|
|
|
|
if (!value->Load(stance))
|
|
{
|
|
std::ostringstream str;
|
|
str << "Invalid stance: |cffff0000" << stance;
|
|
botAI->TellMaster(str);
|
|
botAI->TellMaster("Please set to any of:|cffffffff near (default), tank, turnback, behind");
|
|
return false;
|
|
}
|
|
|
|
std::ostringstream str;
|
|
str << "Stance set to: " << stance;
|
|
botAI->TellMaster(str);
|
|
return true;
|
|
}
|