From b55c9b14d1280d34d6b6cad40fd1ce564ede2da2 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 9 Jul 2024 00:08:20 +0800 Subject: [PATCH] [Combat formation] Last flee angle check --- src/strategy/Value.h | 17 +++++++++- src/strategy/actions/MovementActions.cpp | 42 ++++++++++++++++++++---- src/strategy/actions/MovementActions.h | 1 + src/strategy/values/ValueContext.h | 4 +++ 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/strategy/Value.h b/src/strategy/Value.h index e27600ad..1a7e05ef 100644 --- a/src/strategy/Value.h +++ b/src/strategy/Value.h @@ -329,7 +329,22 @@ class UnitManualSetValue : public ManualSetValue class DisperseDistanceValue : public ManualSetValue { public: - DisperseDistanceValue(PlayerbotAI* botAI, float defaultValue = -1.0f, std::string const name = "disperse value") : + DisperseDistanceValue(PlayerbotAI* botAI, float defaultValue = -1.0f, std::string const name = "disperse distance") : ManualSetValue(botAI, defaultValue, name) { } }; + +class LastFleeAngleValue : public ManualSetValue +{ + public: + LastFleeAngleValue(PlayerbotAI* botAI, float defaultValue = 0.0f, std::string const name = "last flee angle") : + ManualSetValue(botAI, defaultValue, name) { } +}; + +class LastFleeTimestampValue : public ManualSetValue +{ + public: + LastFleeTimestampValue(PlayerbotAI* botAI, uint32 defaultValue = 0, std::string const name = "last flee timestamp") : + ManualSetValue(botAI, defaultValue, name) { } +}; + #endif diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index d9ab66fc..06bc7d74 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -4,6 +4,7 @@ #include "MovementActions.h" #include "GameObject.h" +#include "Geometry.h" #include "Map.h" #include "MotionMaster.h" #include "MoveSplineInitArgs.h" @@ -31,6 +32,8 @@ #include "Unit.h" #include "Vehicle.h" #include "WaypointMovementGenerator.h" +#include +#include #include #include @@ -1511,17 +1514,14 @@ bool AvoidAoeAction::Execute(Event event) { // Case #1: Aura with dynamic object (e.g. rain of fire) if (AvoidAuraWithDynamicObj()) { - lastMoveTimer = getMSTime(); return true; } // Case #2: Trap game object with spell (e.g. lava bomb) if (AvoidGameObjectWithDamage()) { - lastMoveTimer = getMSTime(); return true; } // Case #3: Trigger npc (e.g. Lesser shadow fissure) if (AvoidUnitWithDamageAura()) { - lastMoveTimer = getMSTime(); return true; } return false; @@ -1550,10 +1550,11 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj() return false; } std::ostringstream name; - name << spellInfo->SpellName[0]; // << "] (aura)"; + name << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; // << "] (aura)"; if (FleePosition(dynOwner->GetPosition(), radius)) { if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); + lastMoveTimer = getMSTime(); std::ostringstream out; out << "I'm avoiding " << name.str() << "..."; bot->Say(out.str(), LANG_UNIVERSAL); @@ -1607,10 +1608,11 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage() continue; } std::ostringstream name; - name << spellInfo->SpellName[0]; // << "] (object)"; + name << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; // << "] (object)"; if (FleePosition(go->GetPosition(), radius)) { if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); + lastMoveTimer = getMSTime(); std::ostringstream out; out << "I'm avoiding " << name.str() << "..."; bot->Say(out.str(), LANG_UNIVERSAL); @@ -1655,10 +1657,11 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura() break; } std::ostringstream name; - name << triggerSpellInfo->SpellName[0]; //<< "] (unit)"; + name << triggerSpellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; //<< "] (unit)"; if (FleePosition(unit->GetPosition(), radius)) { if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); + lastMoveTimer = getMSTime(); std::ostringstream out; out << "I'm avoiding " << name.str() << "..."; bot->Say(out.str(), LANG_UNIVERSAL); @@ -1697,6 +1700,11 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius) Position bestPos; for (CheckAngle &checkAngle : possibleAngles) { float angle = checkAngle.angle; + float lastFleeAngle = AI_VALUE(float, "last flee angle"); + uint32 lastFleeTimestamp = AI_VALUE(uint32, "last flee timestamp"); + if (!CheckLastFlee(angle, lastFleeAngle, lastFleeTimestamp)) { + continue; + } bool strict = checkAngle.strict; float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance); Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, @@ -1740,6 +1748,11 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius) Position bestPos; for (CheckAngle &checkAngle : possibleAngles) { float angle = checkAngle.angle; + float lastFleeAngle = AI_VALUE(float, "last flee angle"); + uint32 lastFleeTimestamp = AI_VALUE(uint32, "last flee timestamp"); + if (!CheckLastFlee(angle, lastFleeAngle, lastFleeTimestamp)) { + continue; + } bool strict = checkAngle.strict; float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance); Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, @@ -1774,12 +1787,29 @@ bool MovementAction::FleePosition(Position pos, float radius) } if (bestPos != Position()) { if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) { + SET_AI_VALUE(float, "last flee angle", bot->GetAngle(&bestPos)); + SET_AI_VALUE(uint32, "last flee timestamp", getMSTime()); return true; } } return false; } +bool MovementAction::CheckLastFlee(float curAngle, float lastAngle, uint32 lastTS) +{ + // more than 5 sec + if (lastTS + 5000 < getMSTime()) { + return true; + } + float revAngle = fmod(lastAngle + M_PI, 2 * M_PI); + curAngle = fmod(curAngle, 2 * M_PI); + // angle too close + if (fabs(revAngle - curAngle) < M_PI / 8) { + return false; + } + return true; +} + bool CombatFormationMoveAction::isUseful() { if (getMSTime() - moveInterval < lastMoveTimer) { diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index ed9527af..0db8e7cd 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -44,6 +44,7 @@ class MovementAction : public Action Position BestPositionForMeleeToFlee(Position pos, float radius); Position BestPositionForRangedToFlee(Position pos, float radius); bool FleePosition(Position pos, float radius); + bool CheckLastFlee(float curAngle, float lastAngle, uint32 lastTS); protected: struct CheckAngle { float angle; diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index fe08de8b..e202ff8d 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -302,6 +302,8 @@ class ValueContext : public NamedObjectContext creators["area debuff"] = &ValueContext::area_debuff; creators["nearest trap with damage"] = &ValueContext::nearest_trap_with_damange; creators["disperse distance"] = &ValueContext::disperse_distance; + creators["last flee angle"] = &ValueContext::last_flee_angle; + creators["last flee timestamp"] = &ValueContext::last_flee_timestamp; } private: @@ -507,6 +509,8 @@ class ValueContext : public NamedObjectContext static UntypedValue* area_debuff(PlayerbotAI* ai) { return new AreaDebuffValue(ai); } static UntypedValue* nearest_trap_with_damange(PlayerbotAI* ai) { return new NearestTrapWithDamageValue(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_timestamp(PlayerbotAI* ai) { return new LastFleeTimestampValue(ai); } }; #endif