mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Merge pull request #1467 from ThePenguinMan96/Warlock-Pet-Re-Summon-on-Strategy-Change
Warlock Pet Re-Summon on Strategy Change
This commit is contained in:
@@ -88,6 +88,9 @@ uint8 AiFactory::GetPlayerSpecTab(Player* bot)
|
|||||||
case CLASS_PRIEST:
|
case CLASS_PRIEST:
|
||||||
tab = PRIEST_TAB_HOLY;
|
tab = PRIEST_TAB_HOLY;
|
||||||
break;
|
break;
|
||||||
|
case CLASS_WARLOCK:
|
||||||
|
tab = WARLOCK_TAB_DEMONOLOGY;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tab;
|
return tab;
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ SummonImpStrategy::SummonImpStrategy(PlayerbotAI* ai) : NonCombatStrategy(ai) {}
|
|||||||
void SummonImpStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void SummonImpStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon imp", 29.0f), NULL)));
|
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon imp", 29.0f), NULL)));
|
||||||
|
triggers.push_back(new TriggerNode("wrong pet", NextAction::array(0, new NextAction("summon imp", 29.0f), NULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-combat strategy for summoning a Voidwalker
|
// Non-combat strategy for summoning a Voidwalker
|
||||||
@@ -109,6 +110,7 @@ SummonVoidwalkerStrategy::SummonVoidwalkerStrategy(PlayerbotAI* ai) : NonCombatS
|
|||||||
void SummonVoidwalkerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void SummonVoidwalkerStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon voidwalker", 29.0f), NULL)));
|
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon voidwalker", 29.0f), NULL)));
|
||||||
|
triggers.push_back(new TriggerNode("wrong pet", NextAction::array(0, new NextAction("summon voidwalker", 29.0f), NULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-combat strategy for summoning a Succubus
|
// Non-combat strategy for summoning a Succubus
|
||||||
@@ -120,6 +122,7 @@ SummonSuccubusStrategy::SummonSuccubusStrategy(PlayerbotAI* ai) : NonCombatStrat
|
|||||||
void SummonSuccubusStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void SummonSuccubusStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon succubus", 29.0f), NULL)));
|
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon succubus", 29.0f), NULL)));
|
||||||
|
triggers.push_back(new TriggerNode("wrong pet", NextAction::array(0, new NextAction("summon succubus", 29.0f), NULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-combat strategy for summoning a Felhunter
|
// Non-combat strategy for summoning a Felhunter
|
||||||
@@ -131,6 +134,7 @@ SummonFelhunterStrategy::SummonFelhunterStrategy(PlayerbotAI* ai) : NonCombatStr
|
|||||||
void SummonFelhunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void SummonFelhunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felhunter", 29.0f), NULL)));
|
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felhunter", 29.0f), NULL)));
|
||||||
|
triggers.push_back(new TriggerNode("wrong pet", NextAction::array(0, new NextAction("summon felhunter", 29.0f), NULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-combat strategy for summoning a Felguard
|
// Non-combat strategy for summoning a Felguard
|
||||||
@@ -142,6 +146,7 @@ SummonFelguardStrategy::SummonFelguardStrategy(PlayerbotAI* ai) : NonCombatStrat
|
|||||||
void SummonFelguardStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void SummonFelguardStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 29.0f), NULL)));
|
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon felguard", 29.0f), NULL)));
|
||||||
|
triggers.push_back(new TriggerNode("wrong pet", NextAction::array(0, new NextAction("summon felguard", 29.0f), NULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-combat strategy for selecting themselves to receive soulstone
|
// Non-combat strategy for selecting themselves to receive soulstone
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ public:
|
|||||||
creators["curse of exhaustion"] = &WarlockTriggerFactoryInternal::curse_of_exhaustion;
|
creators["curse of exhaustion"] = &WarlockTriggerFactoryInternal::curse_of_exhaustion;
|
||||||
creators["curse of tongues"] = &WarlockTriggerFactoryInternal::curse_of_tongues;
|
creators["curse of tongues"] = &WarlockTriggerFactoryInternal::curse_of_tongues;
|
||||||
creators["curse of weakness"] = &WarlockTriggerFactoryInternal::curse_of_weakness;
|
creators["curse of weakness"] = &WarlockTriggerFactoryInternal::curse_of_weakness;
|
||||||
|
creators["wrong pet"] = &WarlockTriggerFactoryInternal::wrong_pet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -197,10 +198,7 @@ private:
|
|||||||
static Trigger* immolate(PlayerbotAI* botAI) { return new ImmolateTrigger(botAI); }
|
static Trigger* immolate(PlayerbotAI* botAI) { return new ImmolateTrigger(botAI); }
|
||||||
static Trigger* immolate_on_attacker(PlayerbotAI* ai) { return new ImmolateOnAttackerTrigger(ai); }
|
static Trigger* immolate_on_attacker(PlayerbotAI* ai) { return new ImmolateOnAttackerTrigger(ai); }
|
||||||
static Trigger* unstable_affliction(PlayerbotAI* ai) { return new UnstableAfflictionTrigger(ai); }
|
static Trigger* unstable_affliction(PlayerbotAI* ai) { return new UnstableAfflictionTrigger(ai); }
|
||||||
static Trigger* unstable_affliction_on_attacker(PlayerbotAI* ai)
|
static Trigger* unstable_affliction_on_attacker(PlayerbotAI* ai) { return new UnstableAfflictionOnAttackerTrigger(ai); }
|
||||||
{
|
|
||||||
return new UnstableAfflictionOnAttackerTrigger(ai);
|
|
||||||
}
|
|
||||||
static Trigger* haunt(PlayerbotAI* ai) { return new HauntTrigger(ai); }
|
static Trigger* haunt(PlayerbotAI* ai) { return new HauntTrigger(ai); }
|
||||||
static Trigger* decimation(PlayerbotAI* ai) { return new DecimationTrigger(ai); }
|
static Trigger* decimation(PlayerbotAI* ai) { return new DecimationTrigger(ai); }
|
||||||
static Trigger* life_tap(PlayerbotAI* ai) { return new LifeTapTrigger(ai); }
|
static Trigger* life_tap(PlayerbotAI* ai) { return new LifeTapTrigger(ai); }
|
||||||
@@ -218,6 +216,7 @@ private:
|
|||||||
static Trigger* curse_of_exhaustion(PlayerbotAI* ai) { return new CurseOfExhaustionTrigger(ai); }
|
static Trigger* curse_of_exhaustion(PlayerbotAI* ai) { return new CurseOfExhaustionTrigger(ai); }
|
||||||
static Trigger* curse_of_tongues(PlayerbotAI* ai) { return new CurseOfTonguesTrigger(ai); }
|
static Trigger* curse_of_tongues(PlayerbotAI* ai) { return new CurseOfTonguesTrigger(ai); }
|
||||||
static Trigger* curse_of_weakness(PlayerbotAI* ai) { return new CurseOfWeaknessTrigger(ai); }
|
static Trigger* curse_of_weakness(PlayerbotAI* ai) { return new CurseOfWeaknessTrigger(ai); }
|
||||||
|
static Trigger* wrong_pet(PlayerbotAI* ai) { return new WrongPetTrigger(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class WarlockAiObjectContextInternal : public NamedObjectContext<Action>
|
class WarlockAiObjectContextInternal : public NamedObjectContext<Action>
|
||||||
@@ -413,4 +412,4 @@ void WarlockAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContext
|
|||||||
void WarlockAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList<UntypedValue>& valueContexts)
|
void WarlockAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList<UntypedValue>& valueContexts)
|
||||||
{
|
{
|
||||||
AiObjectContext::BuildSharedValueContexts(valueContexts);
|
AiObjectContext::BuildSharedValueContexts(valueContexts);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,3 +165,66 @@ bool CurseOfWeaknessTrigger::IsActive()
|
|||||||
// Use default BuffTrigger logic for the rest (only trigger if debuff is missing or expiring)
|
// Use default BuffTrigger logic for the rest (only trigger if debuff is missing or expiring)
|
||||||
return BuffTrigger::IsActive();
|
return BuffTrigger::IsActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct WarlockPetDef
|
||||||
|
{
|
||||||
|
const char* strategy; // The strategy string as recognized by the AI (e.g., "imp", "voidwalker", etc.)
|
||||||
|
uint32 spellId; // The spell ID required to summon this pet
|
||||||
|
uint32 npcEntry; // The NPC entry ID for the summoned pet creature
|
||||||
|
};
|
||||||
|
|
||||||
|
// Static array with all relevant Warlock pets and their data
|
||||||
|
static const WarlockPetDef pets[] = {{"imp", 688, 416},
|
||||||
|
{"voidwalker", 697, 1860},
|
||||||
|
{"succubus", 712, 1863},
|
||||||
|
{"felhunter", 691, 417},
|
||||||
|
{"felguard", 30146, 17252}};
|
||||||
|
|
||||||
|
bool WrongPetTrigger::IsActive()
|
||||||
|
{
|
||||||
|
// Retrieve the bot player and its current pet (if any)
|
||||||
|
Player* bot = botAI->GetBot();
|
||||||
|
Pet* pet = bot->GetPet();
|
||||||
|
|
||||||
|
// Step 1: Count how many pet strategies are currently enabled for this bot.
|
||||||
|
// While doing so, also remember which pet strategy is the only enabled one (if that's the case).
|
||||||
|
int enabledCount = 0;
|
||||||
|
const WarlockPetDef* enabledPet =
|
||||||
|
nullptr; // Pointer to the pet definition of the enabled strategy, if only one is enabled
|
||||||
|
for (const WarlockPetDef& pd : pets)
|
||||||
|
{
|
||||||
|
if (botAI->HasStrategy(pd.strategy, BOT_STATE_NON_COMBAT))
|
||||||
|
{
|
||||||
|
enabledCount++;
|
||||||
|
enabledPet = &pd; // Save the pointer to last enabled pet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: If not exactly one pet strategy is enabled, we should not trigger.
|
||||||
|
// This prevents ambiguous or conflicting situations.
|
||||||
|
if (enabledCount != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 3: At this point, we know only one pet strategy is enabled.
|
||||||
|
// We check if the currently summoned pet matches the enabled strategy.
|
||||||
|
bool correctPet = false;
|
||||||
|
if (pet)
|
||||||
|
{
|
||||||
|
CreatureTemplate const* ct = pet->GetCreatureTemplate();
|
||||||
|
// Check if the pet's NPC entry matches the expected one for the enabled strategy
|
||||||
|
if (ct && ct->Entry == enabledPet->npcEntry)
|
||||||
|
correctPet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: If the correct pet is already summoned, the trigger should not activate.
|
||||||
|
if (correctPet)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Step 5: Finally, check if the bot actually knows the spell to summon the desired pet.
|
||||||
|
// If so, the trigger is active (bot should summon the correct pet).
|
||||||
|
if (bot->HasSpell(enabledPet->spellId))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Step 6: If we get here, the bot doesn't know the spell required to support the active pet strategy
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -112,6 +112,14 @@ public:
|
|||||||
HasHealthstoneTrigger(PlayerbotAI* botAI) : WarlockConjuredItemTrigger(botAI, "healthstone") {}
|
HasHealthstoneTrigger(PlayerbotAI* botAI) : WarlockConjuredItemTrigger(botAI, "healthstone") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WrongPetTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WrongPetTrigger(PlayerbotAI* botAI) : Trigger(botAI, "wrong pet") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// CC and Pet Triggers
|
// CC and Pet Triggers
|
||||||
|
|
||||||
class BanishTrigger : public HasCcTargetTrigger
|
class BanishTrigger : public HasCcTargetTrigger
|
||||||
|
|||||||
Reference in New Issue
Block a user