#include "PlayerbotAI.h" #include "Group.h" #include "Player.h" #include #include #include #include // Minimal Blessing Type enum enum GreaterBlessingType { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_KINGS, GREATER_BLESSING_OF_SANCTUARY }; // A simple structure to hold which blessings each class should get, // depending on how many Paladins are in the group. static std::map>> BlessingTemplates = { // 1 Paladin: everyone just gets Kings { 1, { { CLASS_WARRIOR, { GREATER_BLESSING_OF_KINGS } }, { CLASS_PALADIN, { GREATER_BLESSING_OF_KINGS } }, { CLASS_HUNTER, { GREATER_BLESSING_OF_KINGS } }, { CLASS_ROGUE, { GREATER_BLESSING_OF_KINGS } }, { CLASS_PRIEST, { GREATER_BLESSING_OF_KINGS } }, { CLASS_DEATH_KNIGHT, { GREATER_BLESSING_OF_KINGS } }, { CLASS_SHAMAN, { GREATER_BLESSING_OF_KINGS } }, { CLASS_MAGE, { GREATER_BLESSING_OF_KINGS } }, { CLASS_WARLOCK, { GREATER_BLESSING_OF_KINGS } }, { CLASS_DRUID, { GREATER_BLESSING_OF_KINGS } } } }, // 2 Paladins: physical classes prefer Might, casters prefer Wisdom, all get Kings { 2, { { CLASS_WARRIOR, { GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_KINGS } }, { CLASS_PALADIN, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_KINGS } }, { CLASS_HUNTER, { GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_KINGS } }, { CLASS_ROGUE, { GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_KINGS } }, { CLASS_PRIEST, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_KINGS } }, { CLASS_DEATH_KNIGHT, { GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_KINGS } }, { CLASS_SHAMAN, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_KINGS } }, { CLASS_MAGE, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_KINGS } }, { CLASS_WARLOCK, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_KINGS } }, { CLASS_DRUID, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_KINGS } }, } }, // 3 Paladins: might see some Sanctuary usage as well { 3, { { CLASS_WARRIOR, { GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_PALADIN, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_KINGS } }, { CLASS_HUNTER, { GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_KINGS } }, { CLASS_ROGUE, { GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_PRIEST, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_DEATH_KNIGHT, { GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_SHAMAN, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_KINGS } }, { CLASS_MAGE, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_WARLOCK, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_DRUID, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_KINGS } }, } }, // 4 Paladins: basically everything is on the table { 4, { { CLASS_WARRIOR, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_PALADIN, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_HUNTER, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_ROGUE, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_PRIEST, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_DEATH_KNIGHT, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_SHAMAN, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_MAGE, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_WARLOCK, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } }, { CLASS_DRUID, { GREATER_BLESSING_OF_WISDOM, GREATER_BLESSING_OF_MIGHT, GREATER_BLESSING_OF_SANCTUARY, GREATER_BLESSING_OF_KINGS } } } } }; // ------------------------------------------------------------------------- // Simple helper to check if a Paladin has the required talent for the blessing // (In your environment, replace HasTalent(SpellID, Spec) with the actual logic.) // ------------------------------------------------------------------------- static bool PaladinHasTalentForBlessing(Player* paladin, GreaterBlessingType blessing) { switch (blessing) { case GREATER_BLESSING_OF_WISDOM: // Improved Blessing of Wisdom (e.g., talent ID 20245) return paladin->HasTalent(20245, paladin->GetActiveSpec()); case GREATER_BLESSING_OF_MIGHT: // Improved Blessing of Might (e.g., talent ID 20045) return paladin->HasTalent(20045, paladin->GetActiveSpec()); case GREATER_BLESSING_OF_SANCTUARY: // Must have the Sanctuary talent (e.g., talent ID 20911) return paladin->HasTalent(20911, paladin->GetActiveSpec()); case GREATER_BLESSING_OF_KINGS: // No talent required return true; default: return false; } } // ------------------------------------------------------------------------- // Gather all Paladins in the group/raid // ------------------------------------------------------------------------- static std::vector GetPaladinsInGroup(PlayerbotAI* botAI) { std::vector paladins; Player* bot = botAI->GetBot(); if (!bot) return paladins; Group* group = bot->GetGroup(); if (!group) return paladins; for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { Player* member = ref->GetSource(); if (member && member->IsInWorld() && member->getClass() == CLASS_PALADIN) paladins.push_back(member); } return paladins; } // ------------------------------------------------------------------------- // Core function: AssignBlessingsForGroup // Returns a map from (Paladin Player*) -> (set of (classId -> assigned blessing)). // The logic is “one greater blessing per class per paladin,” assigned in order // of talent preference. // ------------------------------------------------------------------------- std::map> AssignBlessingsForGroup(PlayerbotAI* botAI) { std::map> results; // Get relevant Paladins std::vector paladins = GetPaladinsInGroup(botAI); int numPaladins = std::min(static_cast(paladins.size()), 4); if (numPaladins == 0) { // No paladins -> empty map return results; } // Find which template we’ll use auto templIt = BlessingTemplates.find(numPaladins); if (templIt == BlessingTemplates.end()) { // If no valid template, return empty return results; } auto& classToBlessings = templIt->second; // Categorize Paladins by which improved blessings they can cast std::vector paladinsWithSanctuary; std::vector paladinsWithMight; std::vector paladinsWithWisdom; std::vector paladinsWithoutImprovements; // can only cast Kings or unimproved Might/Wisdom for (Player* pal : paladins) { bool canSanctuary = PaladinHasTalentForBlessing(pal, GREATER_BLESSING_OF_SANCTUARY); bool canMight = PaladinHasTalentForBlessing(pal, GREATER_BLESSING_OF_MIGHT); bool canWisdom = PaladinHasTalentForBlessing(pal, GREATER_BLESSING_OF_WISDOM); if (canSanctuary) paladinsWithSanctuary.push_back(pal); if (canMight) paladinsWithMight.push_back(pal); if (canWisdom) paladinsWithWisdom.push_back(pal); if (!canSanctuary && !canMight && !canWisdom) paladinsWithoutImprovements.push_back(pal); } // Keep track of which class each Paladin has already assigned // so we don't assign multiple blessings from the same Paladin to the same class. std::map> paladinAssignedClasses; // Go through each class in the template, then each desired blessing, in order for (auto& [classId, blessingsVec] : classToBlessings) { for (GreaterBlessingType b : blessingsVec) { Player* assignedPaladin = nullptr; // Attempt assignment depending on talent priority switch (b) { case GREATER_BLESSING_OF_SANCTUARY: { // Try paladins with the Sanctuary talent for (Player* pal : paladinsWithSanctuary) { if (!paladinAssignedClasses[pal].count(classId)) { assignedPaladin = pal; paladinAssignedClasses[pal].insert(classId); break; } } break; } case GREATER_BLESSING_OF_MIGHT: { // First try paladins with Improved Might for (Player* pal : paladinsWithMight) { if (!paladinAssignedClasses[pal].count(classId)) { assignedPaladin = pal; paladinAssignedClasses[pal].insert(classId); break; } } // Otherwise, try “no improvement” paladins if (!assignedPaladin) { for (Player* pal : paladinsWithoutImprovements) { if (!paladinAssignedClasses[pal].count(classId)) { assignedPaladin = pal; paladinAssignedClasses[pal].insert(classId); break; } } } // Lastly, if still unassigned, pick any Paladin if (!assignedPaladin) { for (Player* pal : paladins) { if (!paladinAssignedClasses[pal].count(classId)) { assignedPaladin = pal; paladinAssignedClasses[pal].insert(classId); break; } } } break; } case GREATER_BLESSING_OF_WISDOM: { // First try paladins with Improved Wisdom for (Player* pal : paladinsWithWisdom) { if (!paladinAssignedClasses[pal].count(classId)) { assignedPaladin = pal; paladinAssignedClasses[pal].insert(classId); break; } } // Otherwise, try “no improvement” paladins if (!assignedPaladin) { for (Player* pal : paladinsWithoutImprovements) { if (!paladinAssignedClasses[pal].count(classId)) { assignedPaladin = pal; paladinAssignedClasses[pal].insert(classId); break; } } } // Lastly, if still unassigned, pick any Paladin if (!assignedPaladin) { for (Player* pal : paladins) { if (!paladinAssignedClasses[pal].count(classId)) { assignedPaladin = pal; paladinAssignedClasses[pal].insert(classId); break; } } } break; } case GREATER_BLESSING_OF_KINGS: { // Anyone can cast Kings, so pick a paladin who hasn’t assigned that class yet // Try “no improvement” paladins first if you want them to focus on Kings for (Player* pal : paladinsWithoutImprovements) { if (!paladinAssignedClasses[pal].count(classId)) { assignedPaladin = pal; paladinAssignedClasses[pal].insert(classId); break; } } // If not found, pick any paladin if (!assignedPaladin) { for (Player* pal : paladins) { if (!paladinAssignedClasses[pal].count(classId)) { assignedPaladin = pal; paladinAssignedClasses[pal].insert(classId); break; } } } break; } } // If we found a Paladin, record it in the results if (assignedPaladin) results[assignedPaladin][classId] = b; } } return results; // (Paladin -> (classId -> Blessing)) for the entire group }