mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
Per-bot ring buffer of last 3 path attempts on RpgInfo. When 3 mmap or 3 nodetravel attempts to the same dest fail, force the alternative routing strategy on the next tick. When both strategies have failed 3 times each (bothExhausted), fall through to MoveFar:spline rather than flip-flopping forever. Also drops the 10%-per-tick opportunistic combat engage during do-quest travel — the multiplier (0.20x) is the right knob; the random yield was overriding it and producing the 'still grinding too much while traveling' symptom.
161 lines
4.7 KiB
C++
161 lines
4.7 KiB
C++
#ifndef _PLAYERBOT_NEWRPGINFO_H
|
|
#define _PLAYERBOT_NEWRPGINFO_H
|
|
|
|
#include <deque>
|
|
|
|
#include "Define.h"
|
|
#include "ObjectGuid.h"
|
|
#include "ObjectMgr.h"
|
|
#include "QuestDef.h"
|
|
#include "Strategy.h"
|
|
#include "Timer.h"
|
|
#include "TravelMgr.h"
|
|
#include "TravelNode.h"
|
|
|
|
using NewRpgStatusTransitionProb = std::vector<std::vector<int>>;
|
|
|
|
struct NewRpgInfo
|
|
{
|
|
NewRpgInfo() : data(Idle{}) {}
|
|
~NewRpgInfo() = default;
|
|
|
|
// RPG_GO_GRIND
|
|
struct GoGrind
|
|
{
|
|
WorldPosition pos{};
|
|
};
|
|
// RPG_GO_CAMP
|
|
struct GoCamp
|
|
{
|
|
WorldPosition pos{};
|
|
};
|
|
// RPG_WANDER_NPC
|
|
struct WanderNpc
|
|
{
|
|
ObjectGuid npcOrGo{};
|
|
uint32 lastReach{0};
|
|
};
|
|
// RPG_WANDER_RANDOM
|
|
struct WanderRandom
|
|
{
|
|
WanderRandom() = default;
|
|
};
|
|
// RPG_DO_QUEST
|
|
struct DoQuest
|
|
{
|
|
const Quest* quest{nullptr};
|
|
uint32 questId{0};
|
|
int32 objectiveIdx{0};
|
|
WorldPosition pos{};
|
|
uint32 lastReachPOI{0};
|
|
// committed target per objective type. stops zig-zagging in
|
|
// dense spawn clusters when "nearest" would flip each tick.
|
|
ObjectGuid pursuedLootGO{}; // GOs we loot (lilies, eggs)
|
|
ObjectGuid pursuedUseGO{}; // GOs we click or focus on
|
|
ObjectGuid pursuedUseTarget{}; // creature we apply an item to
|
|
};
|
|
// RPG_TRAVEL_FLIGHT
|
|
struct TravelFlight
|
|
{
|
|
uint32 flightMasterEntry{0};
|
|
WorldPosition flightMasterPos{};
|
|
std::vector<uint32> path;
|
|
bool inFlight{false};
|
|
};
|
|
// RPG_REST
|
|
struct Rest
|
|
{
|
|
Rest() = default;
|
|
};
|
|
// RPG_OUTDOOR_PVP
|
|
struct OutdoorPvP
|
|
{
|
|
ObjectGuid::LowType capturePointSpawnId{0};
|
|
};
|
|
struct Idle
|
|
{
|
|
};
|
|
|
|
uint32 startT{0}; // start timestamp of the current status
|
|
|
|
// Travel Node System
|
|
TravelPlan travelPlan;
|
|
bool HasActiveTravelPlan() const { return travelPlan.IsActive(); }
|
|
void ClearTravel() { travelPlan.Reset(); }
|
|
|
|
// MoveFar attempt history. Records the last 3 path commits (node
|
|
// plan or mmap) so MoveFarTo can detect when the same dest +
|
|
// strategy has failed repeatedly and force the alternative
|
|
// routing this tick. Breaks deterministic-loop scenarios where
|
|
// the chained probe (or node graph) keeps returning the same
|
|
// dead-end path. Cmangos doesn't do this — they wait 5+ minutes
|
|
// for UnstuckAction. We're more aggressive here for UX.
|
|
struct MoveFarAttempt
|
|
{
|
|
WorldPosition dest; // requested destination
|
|
bool wasNodeTravel{false}; // true=node plan, false=mmap/spline
|
|
uint32 timestamp{0};
|
|
};
|
|
std::deque<MoveFarAttempt> recentMoveFarAttempts;
|
|
void RecordMoveFarAttempt(WorldPosition const& dest, bool wasNodeTravel);
|
|
int CountRecentAttempts(WorldPosition const& dest, bool wasNodeTravel) const;
|
|
|
|
using RpgData = std::variant<
|
|
Idle,
|
|
GoGrind,
|
|
GoCamp,
|
|
WanderNpc,
|
|
WanderRandom,
|
|
DoQuest,
|
|
Rest,
|
|
TravelFlight,
|
|
OutdoorPvP
|
|
>;
|
|
RpgData data;
|
|
|
|
NewRpgStatus GetStatus();
|
|
bool HasStatusPersisted(uint32 maxDuration) { return GetMSTimeDiffToNow(startT) > maxDuration; }
|
|
void ChangeToGoGrind(WorldPosition pos);
|
|
void ChangeToGoCamp(WorldPosition pos);
|
|
void ChangeToWanderNpc();
|
|
void ChangeToWanderRandom();
|
|
void ChangeToDoQuest(uint32 questId, const Quest* quest);
|
|
void ChangeToTravelFlight(uint32 flightMasterEntry, WorldPosition flightMasterPos, std::vector<uint32> path);
|
|
void ChangeToOutdoorPvp(ObjectGuid::LowType capturePointSpawnId = 0);
|
|
void ChangeToRest();
|
|
void ChangeToIdle();
|
|
bool CanChangeTo(NewRpgStatus status);
|
|
void Reset();
|
|
std::string ToString();
|
|
};
|
|
|
|
struct NewRpgStatistic
|
|
{
|
|
uint32 questAccepted{0};
|
|
uint32 questCompleted{0};
|
|
uint32 questAbandoned{0};
|
|
uint32 questRewarded{0};
|
|
uint32 questDropped{0};
|
|
NewRpgStatistic operator+(const NewRpgStatistic& other) const
|
|
{
|
|
NewRpgStatistic result;
|
|
result.questAccepted = this->questAccepted + other.questAccepted;
|
|
result.questCompleted = this->questCompleted + other.questCompleted;
|
|
result.questAbandoned = this->questAbandoned + other.questAbandoned;
|
|
result.questRewarded = this->questRewarded + other.questRewarded;
|
|
result.questDropped = this->questDropped + other.questDropped;
|
|
return result;
|
|
}
|
|
NewRpgStatistic& operator+=(const NewRpgStatistic& other)
|
|
{
|
|
this->questAccepted += other.questAccepted;
|
|
this->questCompleted += other.questCompleted;
|
|
this->questAbandoned += other.questAbandoned;
|
|
this->questRewarded += other.questRewarded;
|
|
this->questDropped += other.questDropped;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
#endif
|