mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
feat: add /stopmacro support and low durability warning for equipped items
- /stopmacro [conditions] halts remaining macro commands; supports all existing macro conditionals ([combat], [nocombat], [mod:shift], etc.) via the sentinel action trick on evaluateMacroConditionals - macroStopped_ flag in GameScreen; executeMacroText resets and checks it after each command so /stopmacro mid-macro skips all subsequent lines - Emit a "X is about to break!" UI error + system chat when an equipped item's durability drops below 20% via SMSG_UPDATE_OBJECT field delta; warning fires once per threshold crossing (prevDur >= maxDur/5, newDur < maxDur/5)
This commit is contained in:
parent
d7c377292e
commit
09b0bea981
3 changed files with 52 additions and 0 deletions
|
|
@ -55,6 +55,9 @@ private:
|
|||
std::vector<std::string> chatSentHistory_;
|
||||
int chatHistoryIdx_ = -1; // -1 = not browsing history
|
||||
|
||||
// Set to true by /stopmacro; checked in executeMacroText to halt remaining commands.
|
||||
bool macroStopped_ = false;
|
||||
|
||||
// Tab-completion state for slash commands
|
||||
std::string chatTabPrefix_; // prefix captured on first Tab press
|
||||
std::vector<std::string> chatTabMatches_; // matching command list
|
||||
|
|
|
|||
|
|
@ -12302,8 +12302,30 @@ void GameHandler::applyUpdateObjectBlock(const UpdateBlock& block, bool& newItem
|
|||
}
|
||||
} else if (key == itemDurField && isItemInInventory) {
|
||||
if (it->second.curDurability != val) {
|
||||
const uint32_t prevDur = it->second.curDurability;
|
||||
it->second.curDurability = val;
|
||||
inventoryChanged = true;
|
||||
// Warn once when durability drops below 20% for an equipped item.
|
||||
const uint32_t maxDur = it->second.maxDurability;
|
||||
if (maxDur > 0 && val < maxDur / 5u && prevDur >= maxDur / 5u) {
|
||||
// Check if this item is in an equip slot (not bag inventory).
|
||||
bool isEquipped = false;
|
||||
for (uint64_t slotGuid : equipSlotGuids_) {
|
||||
if (slotGuid == block.guid) { isEquipped = true; break; }
|
||||
}
|
||||
if (isEquipped) {
|
||||
std::string itemName;
|
||||
const auto* info = getItemInfo(it->second.entry);
|
||||
if (info) itemName = info->name;
|
||||
char buf[128];
|
||||
if (!itemName.empty())
|
||||
std::snprintf(buf, sizeof(buf), "%s is about to break!", itemName.c_str());
|
||||
else
|
||||
std::snprintf(buf, sizeof(buf), "An equipped item is about to break!");
|
||||
addUIError(buf);
|
||||
addSystemChatMessage(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (key == itemMaxDurField && isItemInInventory) {
|
||||
if (it->second.maxDurability != val) {
|
||||
|
|
|
|||
|
|
@ -5564,12 +5564,16 @@ static std::string evaluateMacroConditionals(const std::string& rawArg,
|
|||
|
||||
// Execute all non-comment lines of a macro body in sequence.
|
||||
// In WoW, every line executes per click; the server enforces spell-cast limits.
|
||||
// /stopmacro (with optional conditionals) halts the remaining commands early.
|
||||
void GameScreen::executeMacroText(game::GameHandler& gameHandler, const std::string& macroText) {
|
||||
macroStopped_ = false;
|
||||
for (const auto& cmd : allMacroCommands(macroText)) {
|
||||
strncpy(chatInputBuffer, cmd.c_str(), sizeof(chatInputBuffer) - 1);
|
||||
chatInputBuffer[sizeof(chatInputBuffer) - 1] = '\0';
|
||||
sendChatMessage(gameHandler);
|
||||
if (macroStopped_) break;
|
||||
}
|
||||
macroStopped_ = false;
|
||||
}
|
||||
|
||||
// /castsequence persistent state — shared across all macros using the same spell list.
|
||||
|
|
@ -5633,6 +5637,29 @@ void GameScreen::sendChatMessage(game::GameHandler& gameHandler) {
|
|||
return;
|
||||
}
|
||||
|
||||
// /stopmacro [conditions]
|
||||
// Halts execution of the current macro (remaining lines are skipped).
|
||||
// With a condition block, only stops if the conditions evaluate to true.
|
||||
// /stopmacro → always stops
|
||||
// /stopmacro [combat] → stops only while in combat
|
||||
// /stopmacro [nocombat] → stops only when not in combat
|
||||
if (cmdLower == "stopmacro") {
|
||||
bool shouldStop = true;
|
||||
if (spacePos != std::string::npos) {
|
||||
std::string condArg = command.substr(spacePos + 1);
|
||||
while (!condArg.empty() && condArg.front() == ' ') condArg.erase(condArg.begin());
|
||||
if (!condArg.empty() && condArg.front() == '[') {
|
||||
// Append a sentinel action so evaluateMacroConditionals can signal a match.
|
||||
uint64_t tgtOver = static_cast<uint64_t>(-1);
|
||||
std::string hit = evaluateMacroConditionals(condArg + " __stop__", gameHandler, tgtOver);
|
||||
shouldStop = !hit.empty();
|
||||
}
|
||||
}
|
||||
if (shouldStop) macroStopped_ = true;
|
||||
chatInputBuffer[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// /invite command
|
||||
if (cmdLower == "invite" && spacePos != std::string::npos) {
|
||||
std::string targetName = command.substr(spacePos + 1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue