mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-07 12:41:09 +00:00
New whisper command "pvp stats" that allows players to ask a bot to report its current Arena Points, Honor Points, and Arena Teams (#2071)
# Pull Request
This PR adds a new whisper command "pvp stats" that allows players to
ask a bot to report its current Arena Points, Honor Points, and Arena
Teams (name and team rating).
Reason:
Due to a client limitation in WoW 3.3.5a, the inspection window does not
display another player's Arena or Honor points , only team data.
This command provides an easy in-game way to check a bot’s PvP
currencies without modifying the client or core packets.
---
## Design Philosophy
Uses existing core getters (GetArenaPoints, GetHonorPoints,
GetArenaTeamId, etc.).
Fully integrated into the chat command system (ChatTriggerContext,
ChatActionContext).
Safe, no gameplay changes, purely informational.
No harcoded texts, use database local instead
---
## How to Test the Changes
/w BotName pvp stats
Bot reply:
[PVP] Arena Points: 302 | Honor Points: 11855
[PVP] 2v2: <The Fighters> (rating 2000)
[PVP] 3v3: <The Trio> (rating 573)
## Complexity & Impact
- Does this change add new decision branches?
- [x] No
- [ ] Yes (**explain below**)
- Does this change increase per-bot or per-tick processing?
- [x] No
- [ ] Yes (**describe and justify impact**)
- Could this logic scale poorly under load?
- [x] No
- [ ] Yes (**explain why**)
---
## Defaults & Configuration
- Does this change modify default bot behavior?
- [x] No
- [ ] Yes (**explain why**)
If this introduces more advanced or AI-heavy logic:
- [x] Lightweight mode remains the default
- [ ] More complex behavior is optional and thereby configurable
---
## AI Assistance
- Was AI assistance (e.g. ChatGPT or similar tools) used while working
on this change?
- [x] No
- [ ] Yes (**explain below**)
---
## Final Checklist
- [x] Stability is not compromised
- [x] Performance impact is understood, tested, and acceptable
- [x] Added logic complexity is justified and explained
- [x] Documentation updated if needed
---
Multibot already ready
Here is a sample of multibot when merged:
<img width="706" height="737" alt="image"
src="https://github.com/user-attachments/assets/5bcdd9f8-e2fc-4c29-a497-9fffba5dfd4e"
/>
---
## Notes for Reviewers
Anything that significantly improves realism at the cost of stability or
performance should be carefully discussed
before merging.
---------
Co-authored-by: bashermens <31279994+hermensbas@users.noreply.github.com>
This commit is contained in:
100
src/Ai/Base/Actions/TellPvpStatsAction.cpp
Normal file
100
src/Ai/Base/Actions/TellPvpStatsAction.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "TellPvpStatsAction.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "ArenaTeam.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
#include "Event.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "PlayerbotTextMgr.h"
|
||||
#include "Playerbots.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Language.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
inline char const* BracketName(uint8 slot)
|
||||
{
|
||||
switch (slot)
|
||||
{
|
||||
case ARENA_SLOT_2v2: return "2v2";
|
||||
case ARENA_SLOT_3v3: return "3v3";
|
||||
default: return "5v5"; // ARENA_SLOT_5v5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TellPvpStatsAction::Execute(Event event)
|
||||
{
|
||||
if (!bot)
|
||||
return false;
|
||||
|
||||
// Prefer the actual chat sender (whisper / say / etc.) if available.
|
||||
Player* requester = nullptr;
|
||||
|
||||
if (Unit* owner = event.getOwner())
|
||||
requester = owner->ToPlayer();
|
||||
|
||||
// Fallback to master if event owner is not available.
|
||||
if (!requester)
|
||||
requester = GetMaster();
|
||||
|
||||
// If we still do not have a valid player to answer to, bail out.
|
||||
if (!requester)
|
||||
return false;
|
||||
|
||||
// PVP currencies
|
||||
std::map<std::string, std::string> currencyPlaceholders;
|
||||
currencyPlaceholders["%arena_points"] = std::to_string(bot->GetArenaPoints());
|
||||
currencyPlaceholders["%honor_points"] = std::to_string(bot->GetHonorPoints());
|
||||
|
||||
std::string const currencyText = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"pvp_currency",
|
||||
"[PVP] Arena points: %arena_points | Honor Points: %honor_points",
|
||||
currencyPlaceholders);
|
||||
|
||||
bot->Whisper(currencyText, LANG_UNIVERSAL, requester);
|
||||
|
||||
// Arena Teams by slot
|
||||
bool anyTeam = false;
|
||||
for (uint8 slot = 0; slot < MAX_ARENA_SLOT; ++slot)
|
||||
{
|
||||
uint32 const teamId = bot->GetArenaTeamId(slot);
|
||||
if (!teamId)
|
||||
continue;
|
||||
|
||||
if (ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId))
|
||||
{
|
||||
anyTeam = true;
|
||||
std::map<std::string, std::string> placeholders;
|
||||
placeholders["%bracket"] = BracketName(slot);
|
||||
placeholders["%team_name"] = team->GetName();
|
||||
placeholders["%team_rating"] = std::to_string(team->GetRating());
|
||||
|
||||
std::string const teamText = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"pvp_arena_team",
|
||||
"[PVP] %bracket: <%team_name> (rating %team_rating)",
|
||||
placeholders);
|
||||
|
||||
bot->Whisper(teamText, LANG_UNIVERSAL, requester);
|
||||
}
|
||||
}
|
||||
|
||||
if (!anyTeam)
|
||||
{
|
||||
std::string const noTeamText = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
||||
"pvp_no_arena_team",
|
||||
"[PVP] I have no Arena Team.",
|
||||
std::map<std::string, std::string>());
|
||||
|
||||
bot->Whisper(noTeamText, LANG_UNIVERSAL, requester);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
20
src/Ai/Base/Actions/TellPvpStatsAction.h
Normal file
20
src/Ai/Base/Actions/TellPvpStatsAction.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_TELLPVPSTATSACTION_H
|
||||
#define _PLAYERBOT_TELLPVPSTATSACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class TellPvpStatsAction : public Action
|
||||
{
|
||||
public:
|
||||
TellPvpStatsAction(PlayerbotAI* botAI) : Action(botAI, "tell pvp stats") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
#endif
|
||||
@@ -67,6 +67,7 @@
|
||||
#include "TellItemCountAction.h"
|
||||
#include "TellLosAction.h"
|
||||
#include "TellReputationAction.h"
|
||||
#include "TellPvpStatsAction.h"
|
||||
#include "TellTargetAction.h"
|
||||
#include "TradeAction.h"
|
||||
#include "TrainerAction.h"
|
||||
@@ -97,6 +98,7 @@ public:
|
||||
creators["quests"] = &ChatActionContext::quests;
|
||||
creators["leave"] = &ChatActionContext::leave;
|
||||
creators["reputation"] = &ChatActionContext::reputation;
|
||||
creators["tell pvp stats"] = &ChatActionContext::tell_pvp_stats;
|
||||
creators["log"] = &ChatActionContext::log;
|
||||
creators["los"] = &ChatActionContext::los;
|
||||
creators["rpg status"] = &ChatActionContext::rpg_status;
|
||||
@@ -279,6 +281,7 @@ private:
|
||||
static Action* quests(PlayerbotAI* botAI) { return new ListQuestsAction(botAI); }
|
||||
static Action* leave(PlayerbotAI* botAI) { return new LeaveGroupAction(botAI); }
|
||||
static Action* reputation(PlayerbotAI* botAI) { return new TellReputationAction(botAI); }
|
||||
static Action* tell_pvp_stats(PlayerbotAI* botAI) { return new TellPvpStatsAction(botAI); }
|
||||
static Action* log(PlayerbotAI* botAI) { return new LogLevelAction(botAI); }
|
||||
static Action* los(PlayerbotAI* botAI) { return new TellLosAction(botAI); }
|
||||
static Action* rpg_status(PlayerbotAI* botAI) { return new TellRpgStatusAction(botAI); }
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
creators["leave"] = &ChatTriggerContext::leave;
|
||||
creators["rep"] = &ChatTriggerContext::reputation;
|
||||
creators["reputation"] = &ChatTriggerContext::reputation;
|
||||
creators["pvp stats"] = &ChatTriggerContext::pvp_stats;
|
||||
creators["log"] = &ChatTriggerContext::log;
|
||||
creators["los"] = &ChatTriggerContext::los;
|
||||
creators["rpg status"] = &ChatTriggerContext::rpg_status;
|
||||
@@ -224,6 +225,7 @@ private:
|
||||
static Trigger* stats(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "stats"); }
|
||||
static Trigger* leave(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "leave"); }
|
||||
static Trigger* reputation(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "reputation"); }
|
||||
static Trigger* pvp_stats(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "pvp stats"); }
|
||||
static Trigger* log(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "log"); }
|
||||
static Trigger* los(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "los"); }
|
||||
static Trigger* rpg_status(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "rpg status"); }
|
||||
|
||||
@@ -27,6 +27,7 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
PassTroughStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(new TriggerNode("rep", { NextAction("reputation", relevance) }));
|
||||
triggers.push_back(new TriggerNode("pvp stats", { NextAction("tell pvp stats", relevance) }));
|
||||
triggers.push_back(new TriggerNode("q", { NextAction("query quest", relevance),
|
||||
NextAction("query item usage", relevance) }));
|
||||
triggers.push_back(new TriggerNode("add all loot", { NextAction("add all loot", relevance),
|
||||
@@ -116,6 +117,7 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas
|
||||
supported.push_back("stats");
|
||||
supported.push_back("leave");
|
||||
supported.push_back("reputation");
|
||||
supported.push_back("tell pvp stats");
|
||||
supported.push_back("log");
|
||||
supported.push_back("los");
|
||||
supported.push_back("rpg status");
|
||||
|
||||
@@ -892,6 +892,7 @@ bool PlayerbotAI::IsAllowedCommand(std::string const text)
|
||||
unsecuredCommands.insert("invite");
|
||||
unsecuredCommands.insert("leave");
|
||||
unsecuredCommands.insert("lfg");
|
||||
unsecuredCommands.insert("pvp stats");
|
||||
unsecuredCommands.insert("rpg status");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user