mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
Fix ambiguous item parsing in bot text (#2356)
## Pull Request Description
This change fixes two cases of broken bot text with respect to inventory
items.
1. Reserved inventory qualifiers such as "mount," "food," "drink," etc.
no longer also trigger generic item name matching. I first noticed this
problem when my resto Shaman who had the "Mounting Vengeance" weapon in
her inventory would repeatedly give error messages of failing to use it
while mounting (because mounting also causes bots to use items that fit
the reserved "mount," which due to this bug, also caused bots to try to
use any item with "mount" in its name).
2. Custom cast output text no longer reports an inferred bag item as the
spell target for normal unit-targeted casts such as "cast chain heal on
Keleborn." There was a bug where the action would first parse the actual
target and then parse the spell text and then try to match the last word
of the string to a bag item (so the bot would say it was casting chain
heal on a healing potion, even though the heal was in fact cast
correctly on a player).
## Feature Evaluation
- Describe the **minimum logic** required to achieve the intended
behavior.
- Add a reserved-qualifier check in InventoryAction::parseItems() so
reserved selectors do not also run through FindNamedItemVisitor.
- In custom cast output text, choose the displayed target based on the
actual target type already resolved for the cast.
- It does not change mount selection behavior itself.
- It does not add new spell-target parsing rules.
- Describe the **processing cost** when this logic executes across many
bots.
- None.
## How to Test the Changes
Reserved qualifiers:
1. Give a bot in your party the "Mounting Vengeance" weapon.
2. Mount up, and the bot should mount too without saying anything
(before the fix, the bot would say it is using the weapon and that the
item was not found).
Spell cast text:
1. Give a bot an inventory item whose name overlaps with part of a spell
name, such as a healing potion.
2. Command a bot to cast some heal on a player.
3. The bot should cast the spell on the intended player (as was the case
previously), and the status text names the player instead of the
inventory item.
## Impact Assessment
- Does this change increase per-bot/per-tick processing or risk scaling
poorly with thousands of bots?
- [x] No, not at all
- [ ] Minimal impact (**explain below**)
- Does this change modify default bot behavior?
- [x] No
- [ ] Yes (**explain why**)
- Does this change add new decision branches or increase maintenance
complexity?
- [ ] No
- [x] Yes (**explain below**)
Very minor changes. InventoryAction gets one explicit reserved-qualifier
guard. Custom cast text selection becomes more explicit about which
target type should be displayed.
## AI Assistance
Was AI assistance used while working on this change?
- [ ] No
- [x] Yes (**explain below**)
GPT-5.4 was used to trace the relevant code paths for the errors and
propose the changes.
## Final Checklist
- [x] Stability is not compromised.
- [x] Performance impact is understood, tested, and acceptable.
- [x] Added logic complexity is justified and explained.
- [x] Any new bot dialogue lines are translated.
- [x] Documentation updated if needed (Conf comments, WiKi commands).
## Notes for Reviewers
---------
Co-authored-by: Keleborn <22352763+Celandriel@users.noreply.github.com>
Co-authored-by: bash <hermensb@gmail.com>
Co-authored-by: Revision <tkn963@gmail.com>
Co-authored-by: kadeshar <kadeshar@gmail.com>
This commit is contained in:
parent
b8ff5996f8
commit
6b0df4ff6c
@ -143,14 +143,17 @@ bool CastCustomSpellAction::Execute(Event event)
|
|||||||
std::ostringstream spellName;
|
std::ostringstream spellName;
|
||||||
spellName << ChatHelper::FormatSpell(spellInfo) << " on ";
|
spellName << ChatHelper::FormatSpell(spellInfo) << " on ";
|
||||||
|
|
||||||
|
bool const hasItemTarget = itemTarget &&
|
||||||
|
(spellInfo->Targets & TARGET_FLAG_ITEM || spellInfo->Targets & TARGET_FLAG_GAMEOBJECT_ITEM);
|
||||||
|
|
||||||
if (bot->GetTrader())
|
if (bot->GetTrader())
|
||||||
spellName << "trade item";
|
spellName << "trade item";
|
||||||
else if (itemTarget)
|
else if (hasItemTarget)
|
||||||
spellName << chat->FormatItem(itemTarget->GetTemplate());
|
spellName << chat->FormatItem(itemTarget->GetTemplate());
|
||||||
else if (target == bot)
|
else if (target != bot)
|
||||||
spellName << "self";
|
|
||||||
else
|
|
||||||
spellName << target->GetName();
|
spellName << target->GetName();
|
||||||
|
else
|
||||||
|
spellName << "self";
|
||||||
|
|
||||||
if (!bot->GetTrader() && !botAI->CanCastSpell(spell, target, true, itemTarget))
|
if (!bot->GetTrader() && !botAI->CanCastSpell(spell, target, true, itemTarget))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -10,6 +10,31 @@
|
|||||||
#include "ItemVisitors.h"
|
#include "ItemVisitors.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool isReservedQualifier(std::string const& text)
|
||||||
|
{
|
||||||
|
static std::array<std::string_view, 13> const exactQualifiers = {
|
||||||
|
"ammo",
|
||||||
|
"conjured drink",
|
||||||
|
"conjured food",
|
||||||
|
"conjured water",
|
||||||
|
"drink",
|
||||||
|
"food",
|
||||||
|
"healing potion",
|
||||||
|
"mount",
|
||||||
|
"mana potion",
|
||||||
|
"pet",
|
||||||
|
"quest",
|
||||||
|
"recipe",
|
||||||
|
"water"
|
||||||
|
};
|
||||||
|
|
||||||
|
return std::find(exactQualifiers.begin(), exactQualifiers.end(), text) != exactQualifiers.end() ||
|
||||||
|
text.rfind("usage ", 0) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InventoryAction::IterateItems(IterateItemsVisitor* visitor, IterateItemsMask mask)
|
void InventoryAction::IterateItems(IterateItemsVisitor* visitor, IterateItemsMask mask)
|
||||||
{
|
{
|
||||||
if (mask & ITERATE_ITEMS_IN_BAGS)
|
if (mask & ITERATE_ITEMS_IN_BAGS)
|
||||||
@ -292,9 +317,12 @@ std::vector<Item*> InventoryAction::parseItems(std::string const text, IterateIt
|
|||||||
found.insert(visitor.GetResult().begin(), visitor.GetResult().end());
|
found.insert(visitor.GetResult().begin(), visitor.GetResult().end());
|
||||||
}
|
}
|
||||||
|
|
||||||
FindNamedItemVisitor visitor(bot, text);
|
if (!isReservedQualifier(text))
|
||||||
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
|
{
|
||||||
found.insert(visitor.GetResult().begin(), visitor.GetResult().end());
|
FindNamedItemVisitor visitor(bot, text);
|
||||||
|
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
|
||||||
|
found.insert(visitor.GetResult().begin(), visitor.GetResult().end());
|
||||||
|
}
|
||||||
|
|
||||||
uint32 quality = chat->parseItemQuality(text);
|
uint32 quality = chat->parseItemQuality(text);
|
||||||
if (quality != MAX_ITEM_QUALITY)
|
if (quality != MAX_ITEM_QUALITY)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user