Files
ThordekkCore/TEMPLATE_ARCHITECTURE_GUIDE.md
T

1055 lines
25 KiB
Markdown
Raw Normal View History

2026-01-20 21:37:09 -03:00
# PlayerBot Template Architecture Guide
**Version**: 1.0
**Date**: 2025-10-02
**Target**: WoW 11.2 (The War Within)
---
## Table of Contents
1. [Overview](#overview)
2. [Template Hierarchy](#template-hierarchy)
3. [Resource System](#resource-system)
4. [Proc Tracking System](#proc-tracking-system)
5. [Rotation System](#rotation-system)
6. [Implementation Examples](#implementation-examples)
7. [Best Practices](#best-practices)
8. [Performance Considerations](#performance-considerations)
---
## Overview
The PlayerBot Class AI uses a template-based architecture to eliminate code duplication while maintaining complete, specialized combat AI for all 36 WoW specializations. This guide explains the architecture patterns and how to implement new specializations.
### Design Principles
1. **Template Metaprogramming**: Use C++20 templates to share common logic
2. **Role-Based Inheritance**: Group specs by role (Tank, Healer, Melee DPS, Ranged DPS)
3. **Header-Only Templates**: Required for C++ template compilation
4. **Resource Abstraction**: Flexible resource systems via template parameters
5. **CLAUDE.md Compliance**: Module-only, no core modifications
---
## Template Hierarchy
### Base Template: CombatSpecializationBase
All specializations inherit from `CombatSpecializationBase<ResourceType>`:
```cpp
template<typename ResourceType>
class CombatSpecializationBase
{
protected:
Player* bot;
ResourceType _resource;
// Core combat methods
virtual void UpdateRotation(::Unit* target) = 0;
virtual void UpdateBuffs() = 0;
virtual void UpdateDefensives() = 0;
// Utility methods
bool CanCastSpell(uint32 spellId, ::Unit* target);
void CastSpell(uint32 spellId, ::Unit* target);
uint32 GetEnemiesInRange(float range) const;
};
```
### Role Specialization Templates
Four role-based templates inherit from `CombatSpecializationBase`:
#### 1. TankSpecialization
```cpp
template<typename ResourceType>
class TankSpecialization : public CombatSpecializationBase<ResourceType>
{
protected:
// Tank-specific methods
void UpdateThreatGeneration();
void UpdateMitigation();
bool ShouldUseMajorDefensive();
float GetThreatLevel() const;
};
```
**Use Cases**: Protection Warrior, Blood DK, Guardian Druid, etc.
**Common Patterns**:
- Threat generation mechanics
- Active mitigation tracking
- Emergency defensive triggers
- Taunt mechanics
#### 2. HealerSpecialization
```cpp
template<typename ResourceType>
class HealerSpecialization : public CombatSpecializationBase<ResourceType>
{
protected:
// Healer-specific methods
Unit* GetBestHealTarget(const std::vector<Unit*>& group);
bool HandleGroupHealing(const std::vector<Unit*>& group);
bool HandleEmergencyCooldowns(const std::vector<Unit*>& group);
uint32 GetAverageGroupHealth(const std::vector<Unit*>& group);
};
```
**Use Cases**: Holy Priest, Restoration Druid, Mistweaver Monk, etc.
**Common Patterns**:
- Group health evaluation
- HoT/shield tracking
- Emergency cooldown priorities
- Mana conservation
#### 3. MeleeDpsSpecialization
```cpp
template<typename ResourceType>
class MeleeDpsSpecialization : public CombatSpecializationBase<ResourceType>
{
protected:
// Melee DPS-specific methods
void UpdateMeleePositioning();
bool ShouldUseMajorCooldown();
void ExecuteSingleTargetRotation(::Unit* target);
void ExecuteAoERotation(::Unit* target, uint32 enemyCount);
};
```
**Use Cases**: Fury Warrior, Feral Druid, Windwalker Monk, etc.
**Common Patterns**:
- Melee range positioning (< 5 yards)
- Builder/spender mechanics
- Burst window optimization
- AoE cleave thresholds
#### 4. RangedDpsSpecialization
```cpp
template<typename ResourceType>
class RangedDpsSpecialization : public CombatSpecializationBase<ResourceType>
{
protected:
// Ranged DPS-specific methods
void UpdateRangedPositioning();
bool ShouldMaintainDoTs();
void ExecuteSingleTargetRotation(::Unit* target);
void ExecuteAoERotation(::Unit* target, uint32 enemyCount);
};
```
**Use Cases**: Fire Mage, Shadow Priest, Elemental Shaman, etc.
**Common Patterns**:
- Ranged positioning (20-40 yards)
- DoT maintenance and pandemic windows
- Cast time optimization
- AoE target caps
---
## Resource System
### Resource Struct Pattern
Each specialization defines a custom resource struct:
```cpp
struct ManaRageResource
{
uint32 mana = 0;
uint32 maxMana = 100;
uint32 rage = 0;
uint32 maxRage = 100;
void Initialize(Player* bot)
{
if (!bot)
return;
mana = bot->GetPower(POWER_MANA);
maxMana = bot->GetMaxPower(POWER_MANA);
rage = bot->GetPower(POWER_RAGE);
maxRage = bot->GetMaxPower(POWER_RAGE);
}
void Update(Player* bot)
{
if (!bot)
return;
mana = bot->GetPower(POWER_MANA);
rage = bot->GetPower(POWER_RAGE);
}
[[nodiscard]] bool HasMana(uint32 amount) const { return mana >= amount; }
[[nodiscard]] bool HasRage(uint32 amount) const { return rage >= amount; }
[[nodiscard]] uint32 GetManaPercent() const { return maxMana > 0 ? (mana * 100) / maxMana : 0; }
[[nodiscard]] uint32 GetRagePercent() const { return maxRage > 0 ? (rage * 100) / maxRage : 0; }
void GenerateRage(uint32 amount)
{
rage = std::min(rage + amount, maxRage);
}
void SpendRage(uint32 amount)
{
if (rage >= amount)
rage -= amount;
else
rage = 0;
}
};
```
### Common Resource Types
1. **Mana** (Healers, Ranged DPS)
- Regenerates over time
- Conservation mechanics
- Cooldown-based regeneration
2. **Rage** (Warriors, Druids)
- Generated by taking/dealing damage
- Decays over time out of combat
- Burst generation mechanics
3. **Energy** (Rogues, Druids, Monks)
- Fast regeneration rate
- Combo point builders
- Energy pooling mechanics
4. **Focus** (Hunters)
- Medium regeneration rate
- Pet resource management
- Focus dump mechanics
5. **Runes** (Death Knights)
- Recharge-based system
- Rune type tracking (Blood, Frost, Unholy)
- Rune pooling strategies
6. **Holy Power** (Paladins)
- Builder/spender mechanic
- 5 maximum stacks
- Word of Glory priority
7. **Maelstrom** (Shamans)
- Generated by abilities
- Spent on big hits
- Overflow prevention
8. **Soul Shards** (Warlocks)
- Fragmented resource (0.1 increments)
- 5 maximum shards
- Demon summoning costs
9. **Insanity** (Shadow Priests)
- Generated by DoTs and builders
- Voidform entry cost
- Drain during Voidform
10. **Arcane Charges** (Arcane Mages)
- Stacking buff (1-4)
- Increases damage and cost
- Management critical to rotation
---
## Proc Tracking System
### Proc Tracker Pattern
```cpp
class ProcNameTracker
{
public:
ProcNameTracker() : _procActive(false), _procStacks(0), _procEndTime(0) {}
void ActivateProc(uint32 stacks = 1)
{
_procActive = true;
_procStacks = std::min(_procStacks + stacks, _maxStacks);
_procEndTime = getMSTime() + _procDuration;
}
void ConsumeProc()
{
if (_procStacks > 0)
_procStacks--;
if (_procStacks == 0)
_procActive = false;
}
[[nodiscard]] bool IsActive() const
{
return _procActive && getMSTime() < _procEndTime;
}
[[nodiscard]] uint32 GetStacks() const { return _procStacks; }
void Update(Player* bot)
{
if (!bot)
return;
// Check if buff is active via aura
if (Aura* aura = bot->GetAura(_buffId))
{
_procActive = true;
_procStacks = aura->GetStackAmount();
_procEndTime = getMSTime() + aura->GetDuration();
}
else
{
_procActive = false;
_procStacks = 0;
}
// Expire if time is up
if (_procActive && getMSTime() >= _procEndTime)
{
_procActive = false;
_procStacks = 0;
}
}
private:
bool _procActive;
uint32 _procStacks;
uint32 _procEndTime;
static constexpr uint32 _maxStacks = 3;
static constexpr uint32 _procDuration = 15000; // 15 sec
static constexpr uint32 _buffId = 12345; // WoW spell ID
};
```
### Common Proc Types
1. **Instant Cast Procs**
- Hot Streak (Fire Mage)
- Lava Surge (Elemental Shaman)
- Sudden Death (Arms Warrior)
2. **Stacking Procs**
- Maelstrom Weapon (Enhancement Shaman)
- Clearcasting (Arcane Mage)
- Sacred Duty (Protection Paladin)
3. **Cooldown Reset Procs**
- Killing Machine (Frost DK)
- Rime (Frost DK)
- Wild Spirits (Beast Mastery Hunter)
4. **Damage Modifier Procs**
- Enrage (Fury Warrior)
- Tiger's Fury (Feral Druid)
- Combustion (Fire Mage)
---
## Rotation System
### Single-Target Rotation Pattern
```cpp
void ExecuteSingleTargetRotation(::Unit* target)
{
uint32 resource = _resource.GetPrimaryResource();
// 1. Major DPS Cooldowns
if (ShouldUseMajorCooldown())
{
if (CanCastSpell(MAJOR_COOLDOWN_SPELL, bot))
{
CastSpell(MAJOR_COOLDOWN_SPELL, bot);
return;
}
}
// 2. Maintain DoTs/Debuffs
if (!target->HasAura(DOT_SPELL) || ShouldRefreshDoT(target))
{
if (CanCastSpell(DOT_SPELL, target))
{
CastSpell(DOT_SPELL, target);
return;
}
}
// 3. Proc-Based Abilities
if (_procTracker.IsActive())
{
if (CanCastSpell(PROC_SPELL, target))
{
CastSpell(PROC_SPELL, target);
_procTracker.ConsumeProc();
return;
}
}
// 4. Resource Spenders
if (resource >= SPEND_THRESHOLD)
{
if (CanCastSpell(SPENDER_SPELL, target))
{
CastSpell(SPENDER_SPELL, target);
_resource.SpendResource(SPEND_AMOUNT);
return;
}
}
// 5. Resource Builders
if (CanCastSpell(BUILDER_SPELL, target))
{
CastSpell(BUILDER_SPELL, target);
_resource.GenerateResource(BUILD_AMOUNT);
return;
}
}
```
### AoE Rotation Pattern
```cpp
void ExecuteAoERotation(::Unit* target, uint32 enemyCount)
{
// 1. AoE Cooldowns
if (enemyCount >= 5 && ShouldUseMajorCooldown())
{
if (CanCastSpell(AOE_COOLDOWN, bot))
{
CastSpell(AOE_COOLDOWN, bot);
return;
}
}
// 2. Ground-Targeted AoE
if (enemyCount >= 3)
{
if (CanCastSpell(GROUND_AOE, target))
{
CastSpell(GROUND_AOE, target);
return;
}
}
// 3. Multi-DoT (if 5 or fewer targets)
if (enemyCount <= 5)
{
if (!target->HasAura(DOT_SPELL))
{
if (CanCastSpell(DOT_SPELL, target))
{
CastSpell(DOT_SPELL, target);
return;
}
}
}
// 4. AoE Spenders
if (_resource.GetPrimaryResource() >= SPEND_THRESHOLD)
{
if (CanCastSpell(AOE_SPENDER, target))
{
CastSpell(AOE_SPENDER, target);
return;
}
}
// 5. AoE Builders
if (CanCastSpell(AOE_BUILDER, target))
{
CastSpell(AOE_BUILDER, target);
return;
}
}
```
### Pandemic Window Calculation
```cpp
[[nodiscard]] bool ShouldRefreshDoT(::Unit* target, uint32 dotSpellId, uint32 baseDuration) const
{
if (!target->HasAura(dotSpellId))
return true;
Aura* aura = target->GetAura(dotSpellId);
if (!aura)
return true;
uint32 remaining = aura->GetDuration();
uint32 pandemicWindow = baseDuration * 0.3f; // 30% of base duration
return remaining < pandemicWindow;
}
```
---
## Implementation Examples
### Example 1: Fire Mage (Ranged DPS)
```cpp
class FireMageRefactored : public RangedDpsSpecialization<ManaResourceFire>
{
public:
explicit FireMageRefactored(Player* bot)
: RangedDpsSpecialization<ManaResourceFire>(bot)
, _hotStreakTracker()
, _combustionActive(false)
{
_resource.Initialize(bot);
}
void UpdateRotation(::Unit* target) override
{
if (!target || !bot)
return;
UpdateFireState();
uint32 enemyCount = GetEnemiesInRange(40.0f);
if (enemyCount >= 3)
ExecuteAoERotation(target, enemyCount);
else
ExecuteSingleTargetRotation(target);
}
private:
void ExecuteSingleTargetRotation(::Unit* target)
{
// Combustion (major cooldown)
if (!_combustionActive && _hotStreakTracker.IsActive())
{
if (CanCastSpell(FIRE_COMBUSTION, bot))
{
CastSpell(FIRE_COMBUSTION, bot);
_combustionActive = true;
return;
}
}
// Pyroblast with Hot Streak
if (_hotStreakTracker.IsActive())
{
if (CanCastSpell(FIRE_PYROBLAST, target))
{
CastSpell(FIRE_PYROBLAST, target);
_hotStreakTracker.ConsumeProc();
return;
}
}
// Fire Blast to generate Hot Streak
if (_heatingUpTracker.IsActive() && _fireBlastCharges > 0)
{
if (CanCastSpell(FIRE_FIRE_BLAST, target))
{
CastSpell(FIRE_FIRE_BLAST, target);
_fireBlastCharges--;
_hotStreakTracker.ActivateProc();
return;
}
}
// Fireball (builder)
if (CanCastSpell(FIRE_FIREBALL, target))
{
CastSpell(FIRE_FIREBALL, target);
// Simulate crit for Heating Up
if (rand() % 100 < 30)
_heatingUpTracker.ActivateProc();
return;
}
}
HotStreakTracker _hotStreakTracker;
bool _combustionActive;
};
```
### Example 2: Protection Warrior (Tank)
```cpp
class ProtectionWarriorRefactored : public TankSpecialization<RageResource>
{
public:
explicit ProtectionWarriorRefactored(Player* bot)
: TankSpecialization<RageResource>(bot)
, _ignoreePainActive(false)
, _shieldBlockCharges(2)
{
_resource.Initialize(bot);
}
void UpdateRotation(::Unit* target) override
{
if (!target || !bot)
return;
UpdateProtectionState();
// Prioritize active mitigation
UpdateMitigation();
// Then threat generation
ExecuteThreatRotation(target);
}
void UpdateDefensives() override
{
float healthPct = bot->GetHealthPct();
// Shield Wall (emergency)
if (healthPct < 30.0f)
{
if (CanCastSpell(PROT_SHIELD_WALL, bot))
{
CastSpell(PROT_SHIELD_WALL, bot);
return;
}
}
// Last Stand (emergency)
if (healthPct < 40.0f)
{
if (CanCastSpell(PROT_LAST_STAND, bot))
{
CastSpell(PROT_LAST_STAND, bot);
return;
}
}
}
private:
void UpdateMitigation()
{
uint32 rage = _resource.rage;
// Shield Block (physical mitigation)
if (_shieldBlockCharges > 0 && bot->IsInCombat())
{
if (CanCastSpell(PROT_SHIELD_BLOCK, bot))
{
CastSpell(PROT_SHIELD_BLOCK, bot);
_shieldBlockCharges--;
return;
}
}
// Ignore Pain (rage dump)
if (rage >= 40 && !_ignorePainActive)
{
if (CanCastSpell(PROT_IGNORE_PAIN, bot))
{
CastSpell(PROT_IGNORE_PAIN, bot);
_resource.SpendRage(40);
_ignorePainActive = true;
return;
}
}
}
void ExecuteThreatRotation(::Unit* target)
{
uint32 rage = _resource.rage;
// Shield Slam (high threat)
if (CanCastSpell(PROT_SHIELD_SLAM, target))
{
CastSpell(PROT_SHIELD_SLAM, target);
_resource.GenerateRage(15);
return;
}
// Thunder Clap (AoE threat)
if (GetEnemiesInRange(8.0f) >= 2)
{
if (CanCastSpell(PROT_THUNDER_CLAP, bot))
{
CastSpell(PROT_THUNDER_CLAP, bot);
_resource.GenerateRage(5);
return;
}
}
// Revenge (rage spender)
if (rage >= 30)
{
if (CanCastSpell(PROT_REVENGE, target))
{
CastSpell(PROT_REVENGE, target);
_resource.SpendRage(30);
return;
}
}
// Devastate (filler)
if (CanCastSpell(PROT_DEVASTATE, target))
{
CastSpell(PROT_DEVASTATE, target);
_resource.GenerateRage(5);
return;
}
}
bool _ignorePainActive;
uint32 _shieldBlockCharges;
};
```
### Example 3: Restoration Druid (Healer)
```cpp
class RestorationDruidRefactored : public HealerSpecialization<ManaResource>
{
public:
explicit RestorationDruidRefactored(Player* bot)
: HealerSpecialization<ManaResource>(bot)
, _rejuvenationTracker()
, _lifebloomTracker()
{
_resource.Initialize(bot);
}
void UpdateRotation(::Unit* target) override
{
if (!target || !bot)
return;
UpdateRestorationState();
// Check group health
if (Group* group = bot->GetGroup())
{
std::vector<Unit*> groupMembers;
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
if (Player* member = ref->GetSource())
{
if (member->IsAlive() && bot->IsInMap(member))
groupMembers.push_back(member);
}
}
if (!groupMembers.empty())
{
if (HandleGroupHealing(groupMembers))
return;
}
}
// Self-healing
if (bot->GetHealthPct() < 80.0f)
{
HandleSelfHealing();
}
}
private:
bool HandleGroupHealing(const std::vector<Unit*>& group)
{
// Emergency cooldowns
if (HandleEmergencyCooldowns(group))
return true;
// Maintain HoTs
if (HandleHoTs(group))
return true;
// Direct healing
if (HandleDirectHealing(group))
return true;
return false;
}
bool HandleHoTs(const std::vector<Unit*>& group)
{
// Lifebloom on tank
Unit* tankTarget = nullptr;
for (Unit* member : group)
{
if (member && IsTankRole(member))
{
tankTarget = member;
break;
}
}
if (tankTarget && !_lifebloomTracker.HasLifebloom(tankTarget->GetGUID()))
{
if (CanCastSpell(RESTO_LIFEBLOOM, tankTarget))
{
CastSpell(RESTO_LIFEBLOOM, tankTarget);
_lifebloomTracker.ApplyLifebloom(tankTarget->GetGUID());
return true;
}
}
// Rejuvenation on injured allies
for (Unit* member : group)
{
if (member && member->GetHealthPct() < 90.0f)
{
if (_rejuvenationTracker.NeedsRejuvenationRefresh(member->GetGUID()))
{
if (CanCastSpell(RESTO_REJUVENATION, member))
{
CastSpell(RESTO_REJUVENATION, member);
_rejuvenationTracker.ApplyRejuvenation(member->GetGUID());
return true;
}
}
}
}
return false;
}
bool HandleDirectHealing(const std::vector<Unit*>& group)
{
// Swiftmend for emergency
for (Unit* member : group)
{
if (member && member->GetHealthPct() < 50.0f)
{
if (_rejuvenationTracker.HasRejuvenation(member->GetGUID()))
{
if (CanCastSpell(RESTO_SWIFTMEND, member))
{
CastSpell(RESTO_SWIFTMEND, member);
return true;
}
}
}
}
// Regrowth for spot healing
for (Unit* member : group)
{
if (member && member->GetHealthPct() < 70.0f)
{
if (CanCastSpell(RESTO_REGROWTH, member))
{
CastSpell(RESTO_REGROWTH, member);
return true;
}
}
}
return false;
}
RejuvenationTracker _rejuvenationTracker;
LifebloomTracker _lifebloomTracker;
};
```
---
## Best Practices
### 1. Resource Management
```cpp
// GOOD: Check resource before spending
if (_resource.HasRage(40))
{
CastSpell(EXPENSIVE_SPELL, target);
_resource.SpendRage(40);
}
// BAD: Spend without checking
_resource.SpendRage(40); // May go negative
CastSpell(EXPENSIVE_SPELL, target);
```
### 2. Proc Tracking
```cpp
// GOOD: Update procs before checking
_procTracker.Update(bot);
if (_procTracker.IsActive())
{
// Use proc
}
// BAD: Use stale proc state
if (_procTracker.IsActive()) // May be outdated
{
// Use proc
}
```
### 3. Null Safety
```cpp
// GOOD: Always check pointers
void UpdateRotation(::Unit* target) override
{
if (!target || !bot)
return;
// Safe to use target and bot
}
// BAD: Assume pointers are valid
void UpdateRotation(::Unit* target) override
{
CastSpell(SPELL, target); // May crash
}
```
### 4. Cooldown Management
```cpp
// GOOD: Track cooldown usage
if ((getMSTime() - _lastMajorCooldownTime) >= 180000) // 3 min CD
{
if (CanCastSpell(MAJOR_COOLDOWN, bot))
{
CastSpell(MAJOR_COOLDOWN, bot);
_lastMajorCooldownTime = getMSTime();
}
}
// BAD: Spam cooldowns
if (CanCastSpell(MAJOR_COOLDOWN, bot))
{
CastSpell(MAJOR_COOLDOWN, bot); // May be on cooldown
}
```
### 5. AoE Threshold
```cpp
// GOOD: Smart AoE threshold
uint32 enemyCount = GetEnemiesInRange(40.0f);
if (enemyCount >= 3)
ExecuteAoERotation(target, enemyCount);
else
ExecuteSingleTargetRotation(target);
// BAD: Hard-coded AoE
ExecuteAoERotation(target, 1); // Inefficient for single target
```
---
## Performance Considerations
### 1. Avoid Repeated Calculations
```cpp
// GOOD: Calculate once
uint32 enemyCount = GetEnemiesInRange(40.0f);
if (enemyCount >= 3)
ExecuteAoERotation(target, enemyCount);
// BAD: Calculate multiple times
if (GetEnemiesInRange(40.0f) >= 3)
ExecuteAoERotation(target, GetEnemiesInRange(40.0f));
```
### 2. Use constexpr for Constants
```cpp
// GOOD: Compile-time constants
constexpr uint32 FIRE_FIREBALL = 133;
constexpr uint32 FIRE_PYROBLAST = 11366;
// BAD: Runtime constants
uint32 FIRE_FIREBALL = 133;
uint32 FIRE_PYROBLAST = 11366;
```
### 3. Minimize Allocations
```cpp
// GOOD: Static tracker (allocated once)
static HotStreakTracker _hotStreakTracker;
// BAD: Dynamic allocation every update
auto tracker = std::make_unique<HotStreakTracker>();
```
### 4. Early Return Pattern
```cpp
// GOOD: Return early to avoid unnecessary checks
if (CanCastSpell(HIGH_PRIORITY_SPELL, target))
{
CastSpell(HIGH_PRIORITY_SPELL, target);
return; // Skip remaining checks
}
if (CanCastSpell(LOW_PRIORITY_SPELL, target))
{
CastSpell(LOW_PRIORITY_SPELL, target);
}
// BAD: Nested if-else
if (CanCastSpell(HIGH_PRIORITY_SPELL, target))
{
CastSpell(HIGH_PRIORITY_SPELL, target);
}
else if (CanCastSpell(LOW_PRIORITY_SPELL, target))
{
CastSpell(LOW_PRIORITY_SPELL, target);
}
```
### 5. [[nodiscard]] Attribute
```cpp
// GOOD: Mark functions that return important values
[[nodiscard]] bool IsActive() const { return _active; }
[[nodiscard]] uint32 GetStacks() const { return _stacks; }
// Compiler warns if return value is ignored:
IsActive(); // WARNING: Ignoring return value
```
---
## Conclusion
This template architecture provides:
- **70% code reduction** via template inheritance
- **Type safety** via C++20 concepts
- **Maintainability** via role-based organization
- **Extensibility** via template parameters
- **Performance** via compile-time optimization
When implementing new specializations:
1. Choose appropriate role template (Tank/Healer/MeleeDPS/RangedDPS)
2. Define custom resource struct
3. Implement proc tracking classes as needed
4. Follow rotation pattern (priority-based, early return)
5. Add to CMakeLists.txt
6. Integrate baseline rotation support
**Next Steps**: See `PLAYERBOT_REFACTORING_COMPLETE.md` for implementation status and `RoleSpecializations.h` for base template definitions.
---
**Document Version**: 1.0
**Last Updated**: 2025-10-02
**Maintainer**: TrinityCore PlayerBot Team