mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Add /w botname "glyphs" and "glyph equip" commands
This commit is contained in:
@@ -39,6 +39,7 @@
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "StatsWeightCalculator.h"
|
||||
#include "World.h"
|
||||
#include "AiObjectContext.h"
|
||||
|
||||
const uint64 diveMask = (1LL << 7) | (1LL << 44) | (1LL << 37) | (1LL << 38) | (1LL << 26) | (1LL << 30) | (1LL << 27) |
|
||||
(1LL << 33) | (1LL << 24) | (1LL << 34);
|
||||
@@ -3330,6 +3331,9 @@ void PlayerbotFactory::InitReagents()
|
||||
void PlayerbotFactory::InitGlyphs(bool increment)
|
||||
{
|
||||
bot->InitGlyphsForLevel();
|
||||
if (!increment &&
|
||||
botAI->GetAiObjectContext()->GetValue<bool>("custom_glyphs")->Get())
|
||||
return; // // Added for custom Glyphs - custom glyphs flag test
|
||||
|
||||
if (!increment)
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@ typedef UntypedValue* (*ValueCreator)(PlayerbotAI* botAI);
|
||||
class AiObjectContext : public PlayerbotAIAware
|
||||
{
|
||||
public:
|
||||
static BoolCalculatedValue* custom_glyphs(PlayerbotAI* ai); // Added for cutom glyphs
|
||||
AiObjectContext(PlayerbotAI* botAI,
|
||||
SharedNamedObjectContextList<Strategy>& sharedStrategyContext = sharedStrategyContexts,
|
||||
SharedNamedObjectContextList<Action>& sharedActionContext = sharedActionContexts,
|
||||
|
||||
@@ -11,9 +11,18 @@
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "Playerbots.h"
|
||||
#include "AiObjectContext.h"
|
||||
#include "Log.h"
|
||||
|
||||
bool ChangeTalentsAction::Execute(Event event)
|
||||
{
|
||||
auto* flag = botAI->GetAiObjectContext()->GetValue<bool>("custom_glyphs"); // Added for custom Glyphs
|
||||
|
||||
if (flag->Get()) // Added for custom Glyphs
|
||||
{
|
||||
flag->Set(false);
|
||||
LOG_INFO("playerbots", "Custom Glyph Flag set to OFF");
|
||||
}
|
||||
std::string param = event.getParam();
|
||||
|
||||
std::ostringstream out;
|
||||
|
||||
@@ -79,6 +79,8 @@
|
||||
#include "UnlockItemAction.h"
|
||||
#include "UnlockTradedItemAction.h"
|
||||
#include "PetAction.h"
|
||||
#include "TellGlyphsAction.h"
|
||||
#include "EquipGlyphsAction.h"
|
||||
|
||||
class ChatActionContext : public NamedObjectContext<Action>
|
||||
{
|
||||
@@ -189,6 +191,8 @@ public:
|
||||
creators["calc"] = &ChatActionContext::calc;
|
||||
creators["wipe"] = &ChatActionContext::wipe;
|
||||
creators["pet"] = &ChatActionContext::pet;
|
||||
creators["glyphs"] = &ChatActionContext::glyphs; // Added for custom Glyphs
|
||||
creators["glyph equip"] = &ChatActionContext::glyph_equip; // Added for custom Glyphs
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -296,6 +300,8 @@ private:
|
||||
static Action* calc(PlayerbotAI* ai) { return new TellCalculateItemAction(ai); }
|
||||
static Action* wipe(PlayerbotAI* ai) { return new WipeAction(ai); }
|
||||
static Action* pet(PlayerbotAI* botAI) { return new PetAction(botAI); }
|
||||
static Action* glyphs(PlayerbotAI* botAI) { return new TellGlyphsAction(botAI); } // Added for custom Glyphs
|
||||
static Action* glyph_equip(PlayerbotAI* ai) { return new EquipGlyphsAction(ai); } // Added for custom Glyphs
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
159
src/strategy/actions/EquipGlyphsAction.cpp
Normal file
159
src/strategy/actions/EquipGlyphsAction.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "EquipGlyphsAction.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "DBCStores.h"
|
||||
#include "AiObjectContext.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace
|
||||
{
|
||||
// itemId -> GlyphInfo
|
||||
std::unordered_map<uint32, EquipGlyphsAction::GlyphInfo> s_GlyphCache;
|
||||
}
|
||||
|
||||
void EquipGlyphsAction::BuildGlyphCache()
|
||||
{
|
||||
if (!s_GlyphCache.empty())
|
||||
return;
|
||||
|
||||
ItemTemplateContainer const* store = sObjectMgr->GetItemTemplateStore();
|
||||
|
||||
for (auto const& kv : *store)
|
||||
{
|
||||
uint32 itemId = kv.first;
|
||||
ItemTemplate const* proto = &kv.second;
|
||||
if (!proto || proto->Class != ITEM_CLASS_GLYPH)
|
||||
continue;
|
||||
|
||||
// inspect item spell
|
||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
{
|
||||
uint32 spellId = proto->Spells[i].SpellId;
|
||||
if (!spellId) continue;
|
||||
|
||||
SpellInfo const* si = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!si) continue;
|
||||
|
||||
for (uint8 eff = 0; eff <= EFFECT_2; ++eff)
|
||||
{
|
||||
if (si->Effects[eff].Effect != SPELL_EFFECT_APPLY_GLYPH)
|
||||
continue;
|
||||
|
||||
uint32 glyphId = si->Effects[eff].MiscValue;
|
||||
if (!glyphId) continue;
|
||||
|
||||
if (auto const* gp = sGlyphPropertiesStore.LookupEntry(glyphId))
|
||||
s_GlyphCache[itemId] = {gp, proto};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EquipGlyphsAction::GlyphInfo const* EquipGlyphsAction::GetGlyphInfo(uint32 itemId)
|
||||
{
|
||||
BuildGlyphCache();
|
||||
auto it = s_GlyphCache.find(itemId);
|
||||
return (it == s_GlyphCache.end()) ? nullptr : &it->second;
|
||||
}
|
||||
|
||||
/// -----------------------------------------------------------------
|
||||
/// Validation and collect
|
||||
/// -----------------------------------------------------------------
|
||||
bool EquipGlyphsAction::CollectGlyphs(std::vector<uint32> const& itemIds,
|
||||
std::vector<GlyphInfo const*>& out) const
|
||||
{
|
||||
std::unordered_set<uint32> seen;
|
||||
|
||||
for (uint32 itemId : itemIds)
|
||||
{
|
||||
if (!seen.insert(itemId).second)
|
||||
return false; // double
|
||||
|
||||
auto const* info = GetGlyphInfo(itemId);
|
||||
if (!info) // no good glyph
|
||||
return false;
|
||||
|
||||
// check class by AllowableClass
|
||||
if ((info->proto->AllowableClass & bot->getClassMask()) == 0)
|
||||
return false;
|
||||
|
||||
out.push_back(info);
|
||||
}
|
||||
return out.size() <= 6 && !out.empty();
|
||||
}
|
||||
|
||||
/// -----------------------------------------------------------------
|
||||
/// Action
|
||||
/// -----------------------------------------------------------------
|
||||
bool EquipGlyphsAction::Execute(Event event)
|
||||
{
|
||||
// 1) parse IDs
|
||||
std::vector<uint32> itemIds;
|
||||
std::istringstream iss(event.getParam());
|
||||
for (uint32 id; iss >> id; ) itemIds.push_back(id);
|
||||
|
||||
std::vector<GlyphInfo const*> glyphs;
|
||||
if (!CollectGlyphs(itemIds, glyphs))
|
||||
{
|
||||
botAI->TellMaster("glyph equip : liste invalide (IDs items glyphes de ta classe, max 6).");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2) prepare a empty slots table ?
|
||||
bool used[6] = {false,false,false,false,false,false};
|
||||
|
||||
// 3) for each glyph, find the first available and compatible socket
|
||||
for (auto const* g : glyphs)
|
||||
{
|
||||
bool placed = false;
|
||||
|
||||
for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
|
||||
{
|
||||
if (used[i]) continue;
|
||||
|
||||
uint32 slotId = bot->GetGlyphSlot(i);
|
||||
auto const* gs = sGlyphSlotStore.LookupEntry(slotId);
|
||||
if (!gs || gs->TypeFlags != g->prop->TypeFlags)
|
||||
continue; // major/minor don't match
|
||||
|
||||
// Remove aura if exist
|
||||
uint32 cur = bot->GetGlyph(i);
|
||||
if (cur)
|
||||
if (auto* old = sGlyphPropertiesStore.LookupEntry(cur))
|
||||
bot->RemoveAurasDueToSpell(old->SpellId);
|
||||
|
||||
// Apply new one
|
||||
bot->CastSpell(bot, g->prop->SpellId, true);
|
||||
bot->SetGlyph(i, g->prop->Id, true);
|
||||
|
||||
used[i] = true;
|
||||
placed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!placed)
|
||||
{
|
||||
botAI->TellMaster("Not enought empty sockets for all glyphs.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
botAI->TellMaster("Glyphs updated.");
|
||||
|
||||
// Flag to custom glyphs
|
||||
botAI->GetAiObjectContext()->GetValue<bool>("custom_glyphs")->Set(true);
|
||||
LOG_INFO("playerbots", "Custom Glyph Flag set to ON");
|
||||
|
||||
return true;
|
||||
}
|
||||
37
src/strategy/actions/EquipGlyphsAction.h
Normal file
37
src/strategy/actions/EquipGlyphsAction.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_EQUIPGLYPHSACTION_H
|
||||
#define _PLAYERBOT_EQUIPGLYPHSACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
// 1 = major, 2 = minor dans GlyphProperties.dbc
|
||||
enum class GlyphKind : uint32 { MAJOR = 1, MINOR = 2 };
|
||||
|
||||
class EquipGlyphsAction : public Action
|
||||
{
|
||||
public:
|
||||
EquipGlyphsAction(PlayerbotAI* ai) : Action(ai, "glyph equip") {}
|
||||
bool Execute(Event event) override;
|
||||
|
||||
/// ---- Rendu public pour être utilisable par le cache global ----
|
||||
struct GlyphInfo
|
||||
{
|
||||
GlyphPropertiesEntry const* prop; ///< entrée GlyphProperties.dbc
|
||||
ItemTemplate const* proto; ///< template de l’objet glyphe
|
||||
};
|
||||
|
||||
private:
|
||||
/// Construit la cache {itemId -> GlyphInfo}
|
||||
static void BuildGlyphCache();
|
||||
static GlyphInfo const* GetGlyphInfo(uint32 itemId);
|
||||
|
||||
/// Parse & valide la liste d’items glyphes
|
||||
bool CollectGlyphs(std::vector<uint32> const& itemIds,
|
||||
std::vector<GlyphInfo const*>& out) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
113
src/strategy/actions/TellGlyphsAction.cpp
Normal file
113
src/strategy/actions/TellGlyphsAction.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "TellGlyphsAction.h"
|
||||
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "World.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <sstream>
|
||||
|
||||
namespace
|
||||
{
|
||||
// -----------------------------------------------------------------
|
||||
// Cache : GlyphID (MiscValue) -> ItemTemplate*
|
||||
// -----------------------------------------------------------------
|
||||
std::unordered_map<uint32, ItemTemplate const*> s_GlyphItemCache;
|
||||
|
||||
void BuildGlyphItemCache()
|
||||
{
|
||||
if (!s_GlyphItemCache.empty())
|
||||
return;
|
||||
|
||||
ItemTemplateContainer const* store = sObjectMgr->GetItemTemplateStore();
|
||||
|
||||
for (auto const& kv : *store) // C++17 : range-for sur map
|
||||
{
|
||||
ItemTemplate const* proto = &kv.second;
|
||||
|
||||
if (!proto || proto->Class != ITEM_CLASS_GLYPH)
|
||||
continue;
|
||||
|
||||
for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
{
|
||||
uint32 spellId = proto->Spells[i].SpellId;
|
||||
if (!spellId)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spell = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spell)
|
||||
continue;
|
||||
|
||||
for (uint32 eff = 0; eff <= EFFECT_2; ++eff)
|
||||
{
|
||||
if (spell->Effects[eff].Effect != SPELL_EFFECT_APPLY_GLYPH)
|
||||
continue;
|
||||
|
||||
uint32 glyphId = spell->Effects[eff].MiscValue;
|
||||
if (glyphId)
|
||||
s_GlyphItemCache[glyphId] = proto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Action
|
||||
// -----------------------------------------------------------------
|
||||
bool TellGlyphsAction::Execute(Event event)
|
||||
{
|
||||
//-----------------------------------------------------------------
|
||||
// 1. who sended the wisp ? (source of event)
|
||||
//-----------------------------------------------------------------
|
||||
Player* sender = event.getOwner(); // API Event
|
||||
if (!sender)
|
||||
return false;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// 2. Generate glyphId cache -> item
|
||||
//-----------------------------------------------------------------
|
||||
BuildGlyphItemCache();
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// 3. Look at the 6 glyphs sockets
|
||||
//-----------------------------------------------------------------
|
||||
std::ostringstream list;
|
||||
bool first = true;
|
||||
|
||||
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
|
||||
{
|
||||
uint32 glyphId = bot->GetGlyph(slot);
|
||||
if (!glyphId)
|
||||
continue;
|
||||
|
||||
auto it = s_GlyphItemCache.find(glyphId);
|
||||
if (it == s_GlyphItemCache.end())
|
||||
continue; // No glyph found (rare)
|
||||
|
||||
if (!first)
|
||||
list << ", ";
|
||||
|
||||
// chat->FormatItem
|
||||
list << chat->FormatItem(it->second);
|
||||
first = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// 4. Send chat messages
|
||||
//-----------------------------------------------------------------
|
||||
if (first) // no glyphs
|
||||
botAI->TellMaster("No glyphs equipped");
|
||||
else
|
||||
botAI->TellMaster(std::string("Glyphs: ") + list.str());
|
||||
|
||||
return true;
|
||||
}
|
||||
21
src/strategy/actions/TellGlyphsAction.h
Normal file
21
src/strategy/actions/TellGlyphsAction.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_TELLGLYPHSACTION_H
|
||||
#define _PLAYERBOT_TELLGLYPHSACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class TellGlyphsAction : public Action
|
||||
{
|
||||
public:
|
||||
TellGlyphsAction(PlayerbotAI* ai, std::string const name = "glyphs")
|
||||
: Action(ai, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -103,6 +103,8 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
triggers.push_back(
|
||||
new TriggerNode("wipe", NextAction::array(0, new NextAction("wipe", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("pet", NextAction::array(0, new NextAction("pet", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("glyphs", NextAction::array(0, new NextAction("glyphs", relevance), nullptr))); // Added for custom Glyphs
|
||||
triggers.push_back(new TriggerNode("glyph equip", NextAction::array(0, new NextAction("glyph equip", relevance), nullptr))); // Added for custom Glyphs
|
||||
}
|
||||
|
||||
ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
||||
@@ -183,4 +185,6 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas
|
||||
supported.push_back("unlock items");
|
||||
supported.push_back("unlock traded item");
|
||||
supported.push_back("pet");
|
||||
supported.push_back("glyphs"); // Added for custom Glyphs
|
||||
supported.push_back("glyph equip"); // Added for custom Glyphs
|
||||
}
|
||||
|
||||
@@ -134,6 +134,8 @@ public:
|
||||
creators["qi"] = &ChatTriggerContext::qi;
|
||||
creators["wipe"] = &ChatTriggerContext::wipe;
|
||||
creators["pet"] = &ChatTriggerContext::pet;
|
||||
creators["glyphs"] = &ChatTriggerContext::glyphs; // Added for custom Glyphs
|
||||
creators["glyph equip"] = &ChatTriggerContext::glyph_equip; // Added for custom Glyphs
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -247,6 +249,8 @@ private:
|
||||
static Trigger* qi(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "qi"); }
|
||||
static Trigger* wipe(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "wipe"); }
|
||||
static Trigger* pet(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "pet"); }
|
||||
static Trigger* glyphs(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "glyphs"); } // Added for custom Glyphs
|
||||
static Trigger* glyph_equip(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "glyph equip"); } // Added for custom Glyphs
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -160,6 +160,7 @@ public:
|
||||
creators["my attacker count"] = &ValueContext::my_attacker_count;
|
||||
creators["has aggro"] = &ValueContext::has_aggro;
|
||||
creators["mounted"] = &ValueContext::mounted;
|
||||
creators["custom_glyphs"] = &ValueContext::custom_glyphs; // Added for custom glyphs
|
||||
|
||||
creators["can loot"] = &ValueContext::can_loot;
|
||||
creators["loot target"] = &ValueContext::loot_target;
|
||||
@@ -554,6 +555,13 @@ private:
|
||||
static UntypedValue* last_flee_angle(PlayerbotAI* ai) { return new LastFleeAngleValue(ai); }
|
||||
static UntypedValue* last_flee_timestamp(PlayerbotAI* ai) { return new LastFleeTimestampValue(ai); }
|
||||
static UntypedValue* recently_flee_info(PlayerbotAI* ai) { return new RecentlyFleeInfo(ai); }
|
||||
// -------------------------------------------------------
|
||||
// Flag for cutom glyphs : true when /w bot glyph equip <20>
|
||||
// -------------------------------------------------------
|
||||
static UntypedValue* custom_glyphs(PlayerbotAI* ai)
|
||||
{
|
||||
return new ManualSetValue<bool>(ai, false, "custom_glyphs");
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user