From 6d07d6febedd79a4c0ed5566a1417fa4c9faded0 Mon Sep 17 00:00:00 2001 From: ThePenguinMan96 Date: Sat, 12 Jul 2025 11:45:33 -0700 Subject: [PATCH] Firestone Error Fix/Excess Soul Shard Fix Hello everyone, This PR addresses two errors that players have been getting with the new warlock changes: Firestone - Fel Firestone, which is rank 6 of create firestone, learned at level 74, is creating an error in the worldserver that is quite annoying. That is because the database has an incorrect enchant effect of a chance on hit for that rank. This PR changes the CreateFirestoneAction to skip that spell rank entirely, thus never having that error. Note: You might need to wait a little while after the new change for the errors to go away - that is because there still be pre-existing fel firestones on the warlocks, as well as enchanted on their weapons. Once those disappear, the error will not be there anymore. Excess soul shards - There is an error that currently exists where if a Warlock uses Drain Soul while they have 32 soul shards, it will spam in the chat log "I can't carry anymore of those". This PR will automatically delete soul shards if they have 6 or more. This PR also will reduce the number of soul shards the warlock receives from maintenance to 5. I figured 5 is a good maximum so their inventory doesn't get clogged with 32 shards. Between "DestroySoulShard" and "CreateSoulShard" actions, they will always have between 1-5 soul shards. --- src/factory/PlayerbotFactory.cpp | 2 +- .../GenericWarlockNonCombatStrategy.cpp | 3 +- .../warlock/GenericWarlockStrategy.cpp | 1 + src/strategy/warlock/WarlockActions.cpp | 71 +++++++++++++++++++ src/strategy/warlock/WarlockActions.h | 16 ++++- .../warlock/WarlockAiObjectContext.cpp | 4 ++ src/strategy/warlock/WarlockTriggers.h | 7 ++ 7 files changed, 101 insertions(+), 3 deletions(-) diff --git a/src/factory/PlayerbotFactory.cpp b/src/factory/PlayerbotFactory.cpp index 2fe6cdfa..02e47b21 100644 --- a/src/factory/PlayerbotFactory.cpp +++ b/src/factory/PlayerbotFactory.cpp @@ -3255,7 +3255,7 @@ void PlayerbotFactory::InitReagents() items.push_back({17030, 40}); // Ankh break; case CLASS_WARLOCK: - items.push_back({6265, 20}); // shard + items.push_back({6265, 5}); // shard break; case CLASS_PRIEST: if (level >= 48 && level < 60) diff --git a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp index 88423d90..1e2b89af 100644 --- a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp +++ b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp @@ -80,7 +80,8 @@ void GenericWarlockNonCombatStrategy::InitTriggers(std::vector& tr NonCombatStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", 60.0f), nullptr))); triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("fel domination", 30.0f), nullptr))); - triggers.push_back(new TriggerNode("no soul shard", NextAction::array(0, new NextAction("create soul shard", 29.5f), nullptr))); + triggers.push_back(new TriggerNode("no soul shard", NextAction::array(0, new NextAction("create soul shard", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("too many soul shards", NextAction::array(0, new NextAction("destroy soul shard", 60.0f), nullptr))); triggers.push_back(new TriggerNode("soul link", NextAction::array(0, new NextAction("soul link", 28.0f), nullptr))); triggers.push_back(new TriggerNode("demon armor", NextAction::array(0, new NextAction("fel armor", 27.0f), nullptr))); triggers.push_back(new TriggerNode("no healthstone", NextAction::array(0, new NextAction("create healthstone", 26.0f), nullptr))); diff --git a/src/strategy/warlock/GenericWarlockStrategy.cpp b/src/strategy/warlock/GenericWarlockStrategy.cpp index 1eb5bdbb..9ad266d4 100644 --- a/src/strategy/warlock/GenericWarlockStrategy.cpp +++ b/src/strategy/warlock/GenericWarlockStrategy.cpp @@ -42,6 +42,7 @@ void GenericWarlockStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("medium threat", NextAction::array(0, new NextAction("soulshatter", 55.0f), nullptr))); triggers.push_back(new TriggerNode("spell lock", NextAction::array(0, new NextAction("spell lock", 40.0f), nullptr))); triggers.push_back(new TriggerNode("no soul shard", NextAction::array(0, new NextAction("create soul shard", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("too many soul shards", NextAction::array(0, new NextAction("destroy soul shard", 60.0f), nullptr))); triggers.push_back(new TriggerNode("devour magic purge", NextAction::array(0, new NextAction("devour magic purge", 50.0f), nullptr))); triggers.push_back(new TriggerNode("devour magic cleanse", NextAction::array(0, new NextAction("devour magic cleanse", 50.0f), nullptr))); } diff --git a/src/strategy/warlock/WarlockActions.cpp b/src/strategy/warlock/WarlockActions.cpp index 50cb9e83..433adfed 100644 --- a/src/strategy/warlock/WarlockActions.cpp +++ b/src/strategy/warlock/WarlockActions.cpp @@ -135,6 +135,43 @@ bool CreateSoulShardAction::Execute(Event event) return false; } + +bool DestroySoulShardAction::Execute(Event event) +{ + static const uint32 SOUL_SHARD_ID = 6265; + // Look for the first soul shard in any bag and destroy it + for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + if (Bag* pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + for (uint32 j = 0; j < pBag->GetBagSize(); ++j) + { + if (Item* pItem = pBag->GetItemByPos(j)) + { + if (pItem->GetTemplate()->ItemId == SOUL_SHARD_ID) + { + bot->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); + return true; // Only destroy one! + } + } + } + } + } + // Also check main inventory slots (not in bags) + for (int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) + { + if (Item* pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + if (pItem->GetTemplate()->ItemId == SOUL_SHARD_ID) + { + bot->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); + return true; + } + } + } + return false; +} + // Checks if the target has a soulstone aura static bool HasSoulstoneAura(Unit* unit) { @@ -322,3 +359,37 @@ bool UseSoulstoneHealerAction::Execute(Event event) bot->SetSelection(healer->GetGUID()); return UseItem(items[0], ObjectGuid::Empty, nullptr, healer); } + +const std::vector CastCreateFirestoneAction::firestoneSpellIds = { + 60220, // Create Firestone (Rank 7) + 27250, // Rank 5 + 17953, // Rank 4 + 17952, // Rank 3 + 17951, // Rank 2 + 6366 // Rank 1 +}; + +CastCreateFirestoneAction::CastCreateFirestoneAction(PlayerbotAI* botAI) + : CastBuffSpellAction(botAI, "create firestone") +{ +} + +bool CastCreateFirestoneAction::Execute(Event event) +{ + for (uint32 spellId : firestoneSpellIds) + { + if (bot->HasSpell(spellId)) + return botAI->CastSpell(spellId, bot); + } + return false; +} + +bool CastCreateFirestoneAction::isUseful() +{ + for (uint32 spellId : firestoneSpellIds) + { + if (bot->HasSpell(spellId)) + return true; + } + return false; +} diff --git a/src/strategy/warlock/WarlockActions.h b/src/strategy/warlock/WarlockActions.h index d87358f7..dbf069a8 100644 --- a/src/strategy/warlock/WarlockActions.h +++ b/src/strategy/warlock/WarlockActions.h @@ -8,6 +8,7 @@ #include "GenericSpellActions.h" #include "UseItemAction.h" +#include "InventoryAction.h" #include "Action.h" class PlayerbotAI; @@ -47,6 +48,14 @@ public: bool Execute(Event event) override; }; +class DestroySoulShardAction : public InventoryAction +{ +public: + DestroySoulShardAction(PlayerbotAI* botAI) : InventoryAction(botAI, "destroy soul shard") {} + + bool Execute(Event event) override; +}; + class CastCreateHealthstoneAction : public CastBuffSpellAction { public: @@ -56,7 +65,12 @@ public: class CastCreateFirestoneAction : public CastBuffSpellAction { public: - CastCreateFirestoneAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "create firestone") {} + CastCreateFirestoneAction(PlayerbotAI* botAI); + bool Execute(Event event) override; + bool isUseful() override; + +private: + static const std::vector firestoneSpellIds; }; class CastCreateSpellstoneAction : public CastBuffSpellAction diff --git a/src/strategy/warlock/WarlockAiObjectContext.cpp b/src/strategy/warlock/WarlockAiObjectContext.cpp index 1fe4bf1e..fa1e895d 100644 --- a/src/strategy/warlock/WarlockAiObjectContext.cpp +++ b/src/strategy/warlock/WarlockAiObjectContext.cpp @@ -138,6 +138,7 @@ public: creators["demon armor"] = &WarlockTriggerFactoryInternal::demon_armor; creators["soul link"] = &WarlockTriggerFactoryInternal::soul_link; creators["no soul shard"] = &WarlockTriggerFactoryInternal::no_soul_shard; + creators["too many soul shards"] = &WarlockTriggerFactoryInternal::too_many_soul_shards; creators["no healthstone"] = &WarlockTriggerFactoryInternal::HasHealthstone; creators["no firestone"] = &WarlockTriggerFactoryInternal::HasFirestone; creators["no spellstone"] = &WarlockTriggerFactoryInternal::HasSpellstone; @@ -181,6 +182,7 @@ private: static Trigger* demon_armor(PlayerbotAI* botAI) { return new DemonArmorTrigger(botAI); } static Trigger* soul_link(PlayerbotAI* botAI) { return new SoulLinkTrigger(botAI); } static Trigger* no_soul_shard(PlayerbotAI* botAI) { return new OutOfSoulShardsTrigger(botAI); } + static Trigger* too_many_soul_shards(PlayerbotAI* botAI) { return new TooManySoulShardsTrigger(botAI); } static Trigger* HasHealthstone(PlayerbotAI* botAI) { return new HasHealthstoneTrigger(botAI); } static Trigger* HasFirestone(PlayerbotAI* botAI) { return new HasFirestoneTrigger(botAI); } static Trigger* HasSpellstone(PlayerbotAI* botAI) { return new HasSpellstoneTrigger(botAI); } @@ -229,6 +231,7 @@ public: creators["demon skin"] = &WarlockAiObjectContextInternal::demon_skin; creators["soul link"] = &WarlockAiObjectContextInternal::soul_link; creators["create soul shard"] = &WarlockAiObjectContextInternal::create_soul_shard; + creators["destroy soul shard"] = &WarlockAiObjectContextInternal::destroy_soul_shard; creators["create healthstone"] = &WarlockAiObjectContextInternal::create_healthstone; creators["create firestone"] = &WarlockAiObjectContextInternal::create_firestone; creators["create spellstone"] = &WarlockAiObjectContextInternal::create_spellstone; @@ -301,6 +304,7 @@ private: static Action* demon_skin(PlayerbotAI* botAI) { return new CastDemonSkinAction(botAI); } static Action* soul_link(PlayerbotAI* botAI) { return new CastSoulLinkAction(botAI); } static Action* create_soul_shard(PlayerbotAI* botAI) { return new CreateSoulShardAction(botAI); } + static Action* destroy_soul_shard(PlayerbotAI* botAI) { return new DestroySoulShardAction(botAI); } static Action* create_healthstone(PlayerbotAI* botAI) { return new CastCreateHealthstoneAction(botAI); } static Action* create_firestone(PlayerbotAI* botAI) { return new CastCreateFirestoneAction(botAI); } static Action* create_spellstone(PlayerbotAI* botAI) { return new CastCreateSpellstoneAction(botAI); } diff --git a/src/strategy/warlock/WarlockTriggers.h b/src/strategy/warlock/WarlockTriggers.h index 04de574a..4dedc218 100644 --- a/src/strategy/warlock/WarlockTriggers.h +++ b/src/strategy/warlock/WarlockTriggers.h @@ -37,6 +37,13 @@ public: bool IsActive() override { return AI_VALUE2(uint32, "item count", "soul shard") == 0; } }; +class TooManySoulShardsTrigger : public Trigger +{ +public: + TooManySoulShardsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "too many soul shards") {} + bool IsActive() override { return AI_VALUE2(uint32, "item count", "soul shard") >= 6; } +}; + class FirestoneTrigger : public BuffTrigger { public: