[Combat formation] Avoid flee repeatly

This commit is contained in:
Yunfan Li
2024-07-09 16:39:50 +08:00
parent b55c9b14d1
commit fe64d9ce00
6 changed files with 79 additions and 19 deletions

View File

@@ -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()

View File

@@ -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

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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);
} }

View File

@@ -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