mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 09:07:19 +00:00
[Combat formation] Avoid flee repeatly
This commit is contained in:
@@ -34,6 +34,8 @@ int strcmpi(char const* s1, char const* s2);
|
|||||||
#define AI_VALUE_LAZY(type, name) context->GetValue<type>(name)->LazyGet()
|
#define AI_VALUE_LAZY(type, name) context->GetValue<type>(name)->LazyGet()
|
||||||
#define AI_VALUE2_LAZY(type, name, param) context->GetValue<type>(name, param)->LazyGet()
|
#define AI_VALUE2_LAZY(type, name, param) context->GetValue<type>(name, param)->LazyGet()
|
||||||
|
|
||||||
|
#define AI_VALUE_REF(type, name) context->GetValue<type>(name)->RefGet()
|
||||||
|
|
||||||
#define SET_AI_VALUE(type, name, value) context->GetValue<type>(name)->Set(value)
|
#define SET_AI_VALUE(type, name, value) context->GetValue<type>(name)->Set(value)
|
||||||
#define SET_AI_VALUE2(type, name, param, value) context->GetValue<type>(name, param)->Set(value)
|
#define SET_AI_VALUE2(type, name, param, value) context->GetValue<type>(name, param)->Set(value)
|
||||||
#define RESET_AI_VALUE(type, name) context->GetValue<type>(name)->Reset()
|
#define RESET_AI_VALUE(type, name) context->GetValue<type>(name)->Reset()
|
||||||
|
|||||||
@@ -16,6 +16,16 @@
|
|||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
class Unit;
|
class Unit;
|
||||||
|
|
||||||
|
class FleeInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Position fromPos;
|
||||||
|
float radius;
|
||||||
|
float angle;
|
||||||
|
uint32 timestamp;
|
||||||
|
int GetAngleRangeIndex() { return (angle + 2 * M_PI) / (M_PI / 2); } // [0, 7)
|
||||||
|
};
|
||||||
|
|
||||||
struct CreatureData;
|
struct CreatureData;
|
||||||
|
|
||||||
class UntypedValue : public AiNamedObject
|
class UntypedValue : public AiNamedObject
|
||||||
@@ -37,6 +47,7 @@ class Value
|
|||||||
virtual ~Value() { }
|
virtual ~Value() { }
|
||||||
virtual T Get() = 0;
|
virtual T Get() = 0;
|
||||||
virtual T LazyGet() = 0;
|
virtual T LazyGet() = 0;
|
||||||
|
virtual T& RefGet() = 0;
|
||||||
virtual void Reset() { }
|
virtual void Reset() { }
|
||||||
virtual void Set(T value) = 0;
|
virtual void Set(T value) = 0;
|
||||||
operator T() { return Get(); }
|
operator T() { return Get(); }
|
||||||
@@ -79,7 +90,26 @@ class CalculatedValue : public UntypedValue, public Value<T>
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
T& RefGet() override
|
||||||
|
{
|
||||||
|
if (checkInterval < 2) {
|
||||||
|
// PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr);
|
||||||
|
value = Calculate();
|
||||||
|
// if (pmo)
|
||||||
|
// pmo->finish();
|
||||||
|
} else {
|
||||||
|
time_t now = getMSTime();
|
||||||
|
if (!lastCheckTime || now - lastCheckTime >= checkInterval)
|
||||||
|
{
|
||||||
|
lastCheckTime = now;
|
||||||
|
// PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr);
|
||||||
|
value = Calculate();
|
||||||
|
// if (pmo)
|
||||||
|
// pmo->finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
void Set(T val) override { value = val; }
|
void Set(T val) override { value = val; }
|
||||||
void Update() override {}
|
void Update() override {}
|
||||||
void Reset() override { lastCheckTime = 0; }
|
void Reset() override { lastCheckTime = 0; }
|
||||||
@@ -304,6 +334,7 @@ class ManualSetValue : public UntypedValue, public Value<T>
|
|||||||
|
|
||||||
T Get() override { return value; }
|
T Get() override { return value; }
|
||||||
T LazyGet() override { return value; }
|
T LazyGet() override { return value; }
|
||||||
|
T& RefGet() override { return value; }
|
||||||
void Set(T val) override { value = val; }
|
void Set(T val) override { value = val; }
|
||||||
void Update() override {}
|
void Update() override {}
|
||||||
void Reset() override
|
void Reset() override
|
||||||
@@ -347,4 +378,11 @@ class LastFleeTimestampValue : public ManualSetValue<uint32>
|
|||||||
ManualSetValue<uint32>(botAI, defaultValue, name) { }
|
ManualSetValue<uint32>(botAI, defaultValue, name) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RecentlyFleeInfo : public ManualSetValue<std::list<FleeInfo>>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RecentlyFleeInfo(PlayerbotAI* botAI, std::list<FleeInfo> defaultValue = {}, std::string const name = "recently flee info") :
|
||||||
|
ManualSetValue<std::list<FleeInfo>>(botAI, defaultValue, name) { }
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1700,9 +1700,8 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius)
|
|||||||
Position bestPos;
|
Position bestPos;
|
||||||
for (CheckAngle &checkAngle : possibleAngles) {
|
for (CheckAngle &checkAngle : possibleAngles) {
|
||||||
float angle = checkAngle.angle;
|
float angle = checkAngle.angle;
|
||||||
float lastFleeAngle = AI_VALUE(float, "last flee angle");
|
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info");
|
||||||
uint32 lastFleeTimestamp = AI_VALUE(uint32, "last flee timestamp");
|
if (!CheckLastFlee(angle, infoList)) {
|
||||||
if (!CheckLastFlee(angle, lastFleeAngle, lastFleeTimestamp)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bool strict = checkAngle.strict;
|
bool strict = checkAngle.strict;
|
||||||
@@ -1748,9 +1747,8 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius)
|
|||||||
Position bestPos;
|
Position bestPos;
|
||||||
for (CheckAngle &checkAngle : possibleAngles) {
|
for (CheckAngle &checkAngle : possibleAngles) {
|
||||||
float angle = checkAngle.angle;
|
float angle = checkAngle.angle;
|
||||||
float lastFleeAngle = AI_VALUE(float, "last flee angle");
|
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info");
|
||||||
uint32 lastFleeTimestamp = AI_VALUE(uint32, "last flee timestamp");
|
if (!CheckLastFlee(angle, infoList)) {
|
||||||
if (!CheckLastFlee(angle, lastFleeAngle, lastFleeTimestamp)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bool strict = checkAngle.strict;
|
bool strict = checkAngle.strict;
|
||||||
@@ -1787,25 +1785,43 @@ bool MovementAction::FleePosition(Position pos, float radius)
|
|||||||
}
|
}
|
||||||
if (bestPos != Position()) {
|
if (bestPos != Position()) {
|
||||||
if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) {
|
if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) {
|
||||||
SET_AI_VALUE(float, "last flee angle", bot->GetAngle(&bestPos));
|
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info");
|
||||||
SET_AI_VALUE(uint32, "last flee timestamp", getMSTime());
|
uint32 curTS = getMSTime();
|
||||||
|
while (!infoList.empty()) {
|
||||||
|
if (infoList.size() > 10 || infoList.front().timestamp + 5000 < curTS) {
|
||||||
|
infoList.pop_front();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
infoList.push_back({pos, radius, bot->GetAngle(&bestPos), curTS});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MovementAction::CheckLastFlee(float curAngle, float lastAngle, uint32 lastTS)
|
bool MovementAction::CheckLastFlee(float curAngle, std::list<FleeInfo>& infoList)
|
||||||
{
|
{
|
||||||
// more than 5 sec
|
uint32 curTS = getMSTime();
|
||||||
if (lastTS + 5000 < getMSTime()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
float revAngle = fmod(lastAngle + M_PI, 2 * M_PI);
|
|
||||||
curAngle = fmod(curAngle, 2 * M_PI);
|
curAngle = fmod(curAngle, 2 * M_PI);
|
||||||
// angle too close
|
while (!infoList.empty()) {
|
||||||
if (fabs(revAngle - curAngle) < M_PI / 8) {
|
if (infoList.size() > 10 || infoList.front().timestamp + 5000 < curTS) {
|
||||||
return false;
|
infoList.pop_front();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (FleeInfo& info : infoList) {
|
||||||
|
// more than 5 sec
|
||||||
|
if (info.timestamp + 5000 < curTS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
float revAngle = fmod(info.angle + M_PI, 2 * M_PI);
|
||||||
|
// angle too close
|
||||||
|
if (fabs(revAngle - curAngle) < M_PI / 8) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class Player;
|
|||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
class Unit;
|
class Unit;
|
||||||
class WorldObject;
|
class WorldObject;
|
||||||
|
class Position;
|
||||||
|
|
||||||
class MovementAction : public Action
|
class MovementAction : public Action
|
||||||
{
|
{
|
||||||
@@ -44,7 +45,7 @@ class MovementAction : public Action
|
|||||||
Position BestPositionForMeleeToFlee(Position pos, float radius);
|
Position BestPositionForMeleeToFlee(Position pos, float radius);
|
||||||
Position BestPositionForRangedToFlee(Position pos, float radius);
|
Position BestPositionForRangedToFlee(Position pos, float radius);
|
||||||
bool FleePosition(Position pos, float radius);
|
bool FleePosition(Position pos, float radius);
|
||||||
bool CheckLastFlee(float curAngle, float lastAngle, uint32 lastTS);
|
bool CheckLastFlee(float curAngle, std::list<FleeInfo>& infoList);
|
||||||
protected:
|
protected:
|
||||||
struct CheckAngle {
|
struct CheckAngle {
|
||||||
float angle;
|
float angle;
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ bool SummonAction::Execute(Event event)
|
|||||||
|
|
||||||
if (master->GetSession()->GetSecurity() >= SEC_PLAYER) {
|
if (master->GetSession()->GetSecurity() >= SEC_PLAYER) {
|
||||||
// botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
|
// botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
|
||||||
|
SET_AI_VALUE(std::list<FleeInfo>, "recently flee info", {});
|
||||||
return Teleport(master, bot);
|
return Teleport(master, bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -304,6 +304,7 @@ class ValueContext : public NamedObjectContext<UntypedValue>
|
|||||||
creators["disperse distance"] = &ValueContext::disperse_distance;
|
creators["disperse distance"] = &ValueContext::disperse_distance;
|
||||||
creators["last flee angle"] = &ValueContext::last_flee_angle;
|
creators["last flee angle"] = &ValueContext::last_flee_angle;
|
||||||
creators["last flee timestamp"] = &ValueContext::last_flee_timestamp;
|
creators["last flee timestamp"] = &ValueContext::last_flee_timestamp;
|
||||||
|
creators["recently flee info"] = &ValueContext::recently_flee_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -511,6 +512,7 @@ class ValueContext : public NamedObjectContext<UntypedValue>
|
|||||||
static UntypedValue* disperse_distance(PlayerbotAI* ai) { return new DisperseDistanceValue(ai); }
|
static UntypedValue* disperse_distance(PlayerbotAI* ai) { return new DisperseDistanceValue(ai); }
|
||||||
static UntypedValue* last_flee_angle(PlayerbotAI* ai) { return new LastFleeAngleValue(ai); }
|
static UntypedValue* last_flee_angle(PlayerbotAI* ai) { return new LastFleeAngleValue(ai); }
|
||||||
static UntypedValue* last_flee_timestamp(PlayerbotAI* ai) { return new LastFleeTimestampValue(ai); }
|
static UntypedValue* last_flee_timestamp(PlayerbotAI* ai) { return new LastFleeTimestampValue(ai); }
|
||||||
|
static UntypedValue* recently_flee_info(PlayerbotAI* ai) { return new RecentlyFleeInfo(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user