[HOT FIX] MS build issues regarding folder / command lenght usage or rc.exe (#2038)

This commit is contained in:
bashermens
2026-01-19 22:45:28 +01:00
committed by GitHub
parent fd07e02a8a
commit 41c53365ae
1119 changed files with 27 additions and 27 deletions

View File

@@ -0,0 +1,228 @@
/*
* 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 "BossAuraTriggers.h"
#include <HunterBuffStrategies.h>
#include <PaladinBuffStrategies.h>
#include <Unit.h>
#include "Playerbots.h"
bool BossFireResistanceTrigger::IsActive()
{
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", bossName);
if (!boss || !boss->IsAlive() || boss->IsFriendlyTo(bot))
return false;
// Check if bot is paladin
if (bot->getClass() != CLASS_PALADIN)
return false;
// Check if bot have fire resistance aura
if (bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_5) || bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_4) ||
bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_3) || bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_2) ||
bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_1))
return false;
// Check if bot dont have already have fire resistance strategy
PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI);
if (botAI->HasStrategy(paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT))
return false;
// Check that the bot actually knows the spell
if (!bot->HasActiveSpell(SPELL_FIRE_RESISTANCE_AURA_RANK_5) &&
!bot->HasActiveSpell(SPELL_FIRE_RESISTANCE_AURA_RANK_4) &&
!bot->HasActiveSpell(SPELL_FIRE_RESISTANCE_AURA_RANK_3) &&
!bot->HasActiveSpell(SPELL_FIRE_RESISTANCE_AURA_RANK_2) &&
!bot->HasActiveSpell(SPELL_FIRE_RESISTANCE_AURA_RANK_1))
return false;
// Get the group and ensure it's a raid group
Group* group = bot->GetGroup();
if (!group || !group->isRaidGroup())
return false;
// Iterate through group members to find the first alive paladin
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
// Check if the member is a paladin
if (member->getClass() == CLASS_PALADIN)
{
// Return true only if the current bot is the first alive paladin
return member == bot;
}
}
return false;
}
bool BossFrostResistanceTrigger::IsActive()
{
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", bossName);
if (!boss || !boss->IsAlive() || boss->IsFriendlyTo(bot))
return false;
// Check if bot is paladin
if (bot->getClass() != CLASS_PALADIN)
return false;
// Check if bot have frost resistance aura
if (bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_5) || bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_4) ||
bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_3) || bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_2) ||
bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_1))
return false;
// Check if bot dont have already have frost resistance strategy
PaladinFrostResistanceStrategy paladinFrostResistanceStrategy(botAI);
if (botAI->HasStrategy(paladinFrostResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT))
return false;
// Check that the bot actually knows the spell
if (!bot->HasActiveSpell(SPELL_FROST_RESISTANCE_AURA_RANK_5) &&
!bot->HasActiveSpell(SPELL_FROST_RESISTANCE_AURA_RANK_4) &&
!bot->HasActiveSpell(SPELL_FROST_RESISTANCE_AURA_RANK_3) &&
!bot->HasActiveSpell(SPELL_FROST_RESISTANCE_AURA_RANK_2) &&
!bot->HasActiveSpell(SPELL_FROST_RESISTANCE_AURA_RANK_1))
return false;
// Get the group and ensure it's a raid group
Group* group = bot->GetGroup();
if (!group || !group->isRaidGroup())
return false;
// Iterate through group members to find the first alive paladin
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
// Check if the member is a paladin
if (member->getClass() == CLASS_PALADIN)
{
// Return true only if the current bot is the first alive paladin
return member == bot;
}
}
return false;
}
bool BossNatureResistanceTrigger::IsActive()
{
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", bossName);
if (!boss || !boss->IsAlive() || boss->IsFriendlyTo(bot))
return false;
// Check if bot is alive
if (!bot->IsAlive())
return false;
// Check if bot is hunter
if (bot->getClass() != CLASS_HUNTER)
return false;
// Check if bot have nature resistance aura
if (bot->HasAura(SPELL_ASPECT_OF_THE_WILD_RANK_4) || bot->HasAura(SPELL_ASPECT_OF_THE_WILD_RANK_3) ||
bot->HasAura(SPELL_ASPECT_OF_THE_WILD_RANK_2) || bot->HasAura(SPELL_ASPECT_OF_THE_WILD_RANK_1))
return false;
// Check if bot dont have already setted nature resistance aura
HunterNatureResistanceStrategy hunterNatureResistanceStrategy(botAI);
if (botAI->HasStrategy(hunterNatureResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT))
return false;
// Check that the bot actually knows Aspect of the Wild
if (!bot->HasActiveSpell(SPELL_ASPECT_OF_THE_WILD_RANK_4) &&
!bot->HasActiveSpell(SPELL_ASPECT_OF_THE_WILD_RANK_3) &&
!bot->HasActiveSpell(SPELL_ASPECT_OF_THE_WILD_RANK_2) &&
!bot->HasActiveSpell(SPELL_ASPECT_OF_THE_WILD_RANK_1))
return false;
// Get the group and ensure it's a raid group
Group* group = bot->GetGroup();
if (!group || !group->isRaidGroup())
return false;
// Iterate through group members to find the first alive hunter
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
// Check if the member is a hunter
if (member->getClass() == CLASS_HUNTER)
{
// Return true only if the current bot is the first alive hunter
return member == bot;
}
}
return false;
}
bool BossShadowResistanceTrigger::IsActive()
{
// Check boss and it is alive
Unit* boss = AI_VALUE2(Unit*, "find target", bossName);
if (!boss || !boss->IsAlive() || boss->IsFriendlyTo(bot))
return false;
// Check if bot is paladin
if (bot->getClass() != CLASS_PALADIN)
return false;
// Check if bot have shadow resistance aura
if (bot->HasAura(SPELL_SHADOW_RESISTANCE_AURA_RANK_5) ||
bot->HasAura(SPELL_SHADOW_RESISTANCE_AURA_RANK_4) ||
bot->HasAura(SPELL_SHADOW_RESISTANCE_AURA_RANK_3) ||
bot->HasAura(SPELL_SHADOW_RESISTANCE_AURA_RANK_2) ||
bot->HasAura(SPELL_SHADOW_RESISTANCE_AURA_RANK_1))
return false;
// Check if bot dont have already have shadow resistance strategy
PaladinShadowResistanceStrategy paladinShadowResistanceStrategy(botAI);
if (botAI->HasStrategy(paladinShadowResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT))
return false;
// Check that the bot actually knows the spell
if (!bot->HasActiveSpell(SPELL_SHADOW_RESISTANCE_AURA_RANK_5) &&
!bot->HasActiveSpell(SPELL_SHADOW_RESISTANCE_AURA_RANK_4) &&
!bot->HasActiveSpell(SPELL_SHADOW_RESISTANCE_AURA_RANK_3) &&
!bot->HasActiveSpell(SPELL_SHADOW_RESISTANCE_AURA_RANK_2) &&
!bot->HasActiveSpell(SPELL_SHADOW_RESISTANCE_AURA_RANK_1))
return false;
// Get the group and ensure it's a raid group
Group* group = bot->GetGroup();
if (!group || !group->isRaidGroup())
return false;
// Iterate through group members to find the first alive paladin
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* member = gref->GetSource();
if (!member || !member->IsAlive())
continue;
// Check if the member is a paladin
if (member->getClass() == CLASS_PALADIN)
{
// Return true only if the current bot is the first alive paladin
return member == bot;
}
}
return false;
}

View File

@@ -0,0 +1,88 @@
/*
* 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_BOSSAURATRIGGERS_H
#define _PLAYERBOT_BOSSAURATRIGGERS_H
#include "GenericTriggers.h"
class PlayerbotAI;
enum BossAuraIDs
{
SPELL_SHADOW_RESISTANCE_AURA_RANK_1 = 19876,
SPELL_FROST_RESISTANCE_AURA_RANK_1 = 19888,
SPELL_FIRE_RESISTANCE_AURA_RANK_1 = 19891,
SPELL_SHADOW_RESISTANCE_AURA_RANK_2 = 19895,
SPELL_SHADOW_RESISTANCE_AURA_RANK_3 = 19896,
SPELL_FROST_RESISTANCE_AURA_RANK_2 = 19897,
SPELL_FROST_RESISTANCE_AURA_RANK_3 = 19898,
SPELL_FIRE_RESISTANCE_AURA_RANK_2 = 19899,
SPELL_FIRE_RESISTANCE_AURA_RANK_3 = 19900,
SPELL_ASPECT_OF_THE_WILD_RANK_1 = 20043,
SPELL_ASPECT_OF_THE_WILD_RANK_2 = 20190,
SPELL_ASPECT_OF_THE_WILD_RANK_3 = 27045,
SPELL_SHADOW_RESISTANCE_AURA_RANK_4 = 27151,
SPELL_FROST_RESISTANCE_AURA_RANK_4 = 27152,
SPELL_FIRE_RESISTANCE_AURA_RANK_4 = 27153,
SPELL_SHADOW_RESISTANCE_AURA_RANK_5 = 48943,
SPELL_FROST_RESISTANCE_AURA_RANK_5 = 48945,
SPELL_FIRE_RESISTANCE_AURA_RANK_5 = 48947,
SPELL_ASPECT_OF_THE_WILD_RANK_4 = 49071
};
class BossFireResistanceTrigger : public Trigger
{
public:
BossFireResistanceTrigger(PlayerbotAI* ai, std::string const bossName)
: Trigger(ai, bossName + " fire resistance trigger"), bossName(bossName)
{
}
bool IsActive() override;
private:
std::string bossName;
};
class BossFrostResistanceTrigger : public Trigger
{
public:
BossFrostResistanceTrigger(PlayerbotAI* ai, std::string const bossName)
: Trigger(ai, bossName + " frost resistance trigger"), bossName(bossName)
{
}
bool IsActive() override;
private:
std::string bossName;
};
class BossNatureResistanceTrigger : public Trigger
{
public:
BossNatureResistanceTrigger(PlayerbotAI* ai, std::string const bossName)
: Trigger(ai, " nature resistance trigger"), bossName(bossName)
{
}
bool IsActive() override;
private:
std::string bossName;
};
class BossShadowResistanceTrigger : public Trigger
{
public:
BossShadowResistanceTrigger(PlayerbotAI* ai, std::string const bossName)
: Trigger(ai, " shadow resistance trigger"), bossName(bossName)
{
}
bool IsActive() override;
private:
std::string bossName;
};
#endif

View File

@@ -0,0 +1,30 @@
/*
* 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 "ChatCommandTrigger.h"
#include "Playerbots.h"
ChatCommandTrigger::ChatCommandTrigger(PlayerbotAI* botAI, std::string const command)
: Trigger(botAI, command), triggered(false), owner(nullptr)
{
}
void ChatCommandTrigger::ExternalEvent(std::string const paramName, Player* eventPlayer)
{
param = paramName;
owner = eventPlayer;
triggered = true;
}
Event ChatCommandTrigger::Check()
{
if (!triggered)
return Event();
return Event(getName(), param, owner);
}
void ChatCommandTrigger::Reset() { triggered = false; }

View File

@@ -0,0 +1,30 @@
/*
* 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_CHATCOMMANDTRIGGER_H
#define _PLAYERBOT_CHATCOMMANDTRIGGER_H
#include "Trigger.h"
class Event;
class Player;
class PlayerbotAI;
class ChatCommandTrigger : public Trigger
{
public:
ChatCommandTrigger(PlayerbotAI* botAI, std::string const command);
void ExternalEvent(std::string const param, Player* owner = nullptr) override;
Event Check() override;
void Reset() override;
private:
std::string param;
bool triggered;
Player* owner;
};
#endif

View File

@@ -0,0 +1,28 @@
/*
* 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 "CureTriggers.h"
#include "Playerbots.h"
#include "WorldBuffAction.h"
bool NeedCureTrigger::IsActive()
{
Unit* target = GetTarget();
return target && target->IsInWorld() && botAI->HasAuraToDispel(target, dispelType);
}
Value<Unit*>* PartyMemberNeedCureTrigger::GetTargetValue()
{
return context->GetValue<Unit*>("party member to dispel", dispelType);
}
bool PartyMemberNeedCureTrigger::IsActive()
{
Unit* target = GetTarget();
return target && target->IsInWorld();
}
bool NeedWorldBuffTrigger::IsActive() { return !WorldBuffAction::NeedWorldBuffs(bot).empty(); }

View File

@@ -0,0 +1,60 @@
/*
* 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_CURETRIGGERS_H
#define _PLAYERBOT_CURETRIGGERS_H
#include "GenericTriggers.h"
class PlayerbotAI;
class Unit;
class NeedCureTrigger : public SpellTrigger
{
public:
NeedCureTrigger(PlayerbotAI* botAI, std::string const spell, uint32 dispelType)
: SpellTrigger(botAI, spell, 1 * 1000), dispelType(dispelType)
{
}
std::string const GetTargetName() override { return "self target"; }
bool IsActive() override;
protected:
uint32 dispelType;
};
class TargetAuraDispelTrigger : public NeedCureTrigger
{
public:
TargetAuraDispelTrigger(PlayerbotAI* botAI, std::string const spell, uint32 dispelType)
: NeedCureTrigger(botAI, spell, dispelType)
{
}
std::string const GetTargetName() override { return "current target"; }
};
class PartyMemberNeedCureTrigger : public NeedCureTrigger
{
public:
PartyMemberNeedCureTrigger(PlayerbotAI* botAI, std::string const spell, uint32 dispelType)
: NeedCureTrigger(botAI, spell, dispelType)
{
}
Value<Unit*>* GetTargetValue() override;
bool IsActive() override;
};
class NeedWorldBuffTrigger : public Trigger
{
public:
NeedWorldBuffTrigger(PlayerbotAI* botAI) : Trigger(botAI) {}
bool IsActive() override;
};
#endif

View File

@@ -0,0 +1,11 @@
/*
* 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 "FishingTriggers.h"
#include "Playerbots.h"
bool CanFishTrigger::IsActive() { return AI_VALUE(bool, "can fish"); }
bool CanUseFishingBobberTrigger::IsActive() { return AI_VALUE(bool, "can use fishing bobber");}

View File

@@ -0,0 +1,25 @@
/*
* 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_FISHING_TRIGGER_H
#define _PLAYERBOT_FISHING_TRIGGER_H
#include "GenericTriggers.h"
class CanFishTrigger : public Trigger
{
public:
CanFishTrigger(PlayerbotAI* ai) : Trigger(ai, "can fish") {};
bool IsActive() override;
};
class CanUseFishingBobberTrigger : public Trigger
{
public:
CanUseFishingBobberTrigger(PlayerbotAI* ai) : Trigger(ai, "can use fishing bobber") {};
bool IsActive() override;
};
#endif

View File

@@ -0,0 +1,732 @@
/*
* 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 "GenericTriggers.h"
#include <string>
#include "BattlegroundWS.h"
#include "CreatureAI.h"
#include "GameTime.h"
#include "ItemVisitors.h"
#include "LastSpellCastValue.h"
#include "ObjectGuid.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
#include "PositionValue.h"
#include "SharedDefines.h"
#include "TemporarySummon.h"
#include "ThreatMgr.h"
#include "Timer.h"
#include "PlayerbotAI.h"
#include "Player.h"
bool LowManaTrigger::IsActive()
{
return AI_VALUE2(bool, "has mana", "self target") &&
AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->lowMana;
}
bool MediumManaTrigger::IsActive()
{
return AI_VALUE2(bool, "has mana", "self target") &&
AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->mediumMana;
}
bool NoPetTrigger::IsActive()
{
return (bot->GetMinionGUID().IsEmpty()) && (!AI_VALUE(Unit*, "pet target")) && (!bot->GetGuardianPet()) &&
(!bot->GetFirstControlled()) && (!AI_VALUE2(bool, "mounted", "self target"));
}
bool HasPetTrigger::IsActive()
{
return (AI_VALUE(Unit*, "pet target")) && !AI_VALUE2(bool, "mounted", "self target");
;
}
bool PetAttackTrigger::IsActive()
{
Guardian* pet = bot->GetGuardianPet();
if (!pet)
{
return false;
}
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
{
return false;
}
if (pet->GetVictim() == target && pet->GetCharmInfo()->IsCommandAttack())
{
return false;
}
if (bot->GetMap()->IsDungeon() && bot->GetGroup() && !target->IsInCombat())
{
return false;
}
return true;
}
bool HighManaTrigger::IsActive()
{
return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->highMana;
}
bool AlmostFullManaTrigger::IsActive()
{
return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > 85;
}
bool EnoughManaTrigger::IsActive()
{
return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig->highMana;
}
bool RageAvailable::IsActive() { return AI_VALUE2(uint8, "rage", "self target") >= amount; }
bool EnergyAvailable::IsActive() { return AI_VALUE2(uint8, "energy", "self target") >= amount; }
bool ComboPointsAvailableTrigger::IsActive() { return AI_VALUE2(uint8, "combo", "current target") >= amount; }
bool ComboPointsNotFullTrigger::IsActive() { return AI_VALUE2(uint8, "combo", "current target") < amount; }
bool TargetWithComboPointsLowerHealTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target || !target->IsAlive() || !target->IsInWorld())
{
return false;
}
return ComboPointsAvailableTrigger::IsActive() &&
(target->GetHealth() / AI_VALUE(float, "estimated group dps")) <= lifeTime;
}
bool LoseAggroTrigger::IsActive() { return !AI_VALUE2(bool, "has aggro", "current target"); }
bool HasAggroTrigger::IsActive() { return AI_VALUE2(bool, "has aggro", "current target"); }
bool PanicTrigger::IsActive()
{
return AI_VALUE2(uint8, "health", "self target") < sPlayerbotAIConfig->criticalHealth &&
(!AI_VALUE2(bool, "has mana", "self target") ||
AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig->lowMana);
}
bool OutNumberedTrigger::IsActive()
{
if (bot->GetMap() && (bot->GetMap()->IsDungeon() || bot->GetMap()->IsRaid()))
return false;
if (bot->GetGroup() && bot->GetGroup()->isRaidGroup())
return false;
int32 botLevel = bot->GetLevel();
uint32 friendPower = 200;
uint32 foePower = 0;
for (auto& attacker : botAI->GetAiObjectContext()->GetValue<GuidVector>("attackers")->Get())
{
Creature* creature = botAI->GetCreature(attacker);
if (!creature)
continue;
int32 dLevel = creature->GetLevel() - botLevel;
if (dLevel > -10)
foePower = std::max(100 + 10 * dLevel, dLevel * 200);
}
if (!foePower)
return false;
for (auto& helper : botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest friendly players")->Get())
{
Unit* player = botAI->GetUnit(helper);
if (!player || player == bot)
continue;
int32 dLevel = player->GetLevel() - botLevel;
if (dLevel > -10 && bot->GetDistance(player) < 10.0f)
friendPower += std::max(200 + 20 * dLevel, dLevel * 200);
}
return friendPower < foePower;
}
bool BuffTrigger::IsActive()
{
Unit* target = GetTarget();
if (!target)
return false;
if (!SpellTrigger::IsActive())
return false;
Aura* aura = botAI->GetAura(spell, target, checkIsOwner, checkDuration);
if (!aura)
return true;
if (beforeDuration && aura->GetDuration() < beforeDuration)
return true;
return false;
}
Value<Unit*>* BuffOnPartyTrigger::GetTargetValue()
{
return context->GetValue<Unit*>("party member without aura", spell);
}
bool ProtectPartyMemberTrigger::IsActive() { return AI_VALUE(Unit*, "party member to protect"); }
Value<Unit*>* DebuffOnAttackerTrigger::GetTargetValue()
{
return context->GetValue<Unit*>("attacker without aura", spell);
}
Value<Unit*>* DebuffOnMeleeAttackerTrigger::GetTargetValue()
{
return context->GetValue<Unit*>("melee attacker without aura", spell);
}
bool NoAttackersTrigger::IsActive()
{
return !AI_VALUE(Unit*, "current target") && AI_VALUE(uint8, "my attacker count") > 0;
}
bool InvalidTargetTrigger::IsActive() { return AI_VALUE2(bool, "invalid target", "current target"); }
bool NoTargetTrigger::IsActive() { return !AI_VALUE(Unit*, "current target"); }
bool MyAttackerCountTrigger::IsActive()
{
return AI_VALUE2(bool, "combat", "self target") && AI_VALUE(uint8, "my attacker count") >= amount;
}
bool MediumThreatTrigger::IsActive()
{
if (!AI_VALUE(Unit*, "main tank"))
return false;
return MyAttackerCountTrigger::IsActive();
}
bool LowTankThreatTrigger::IsActive()
{
Unit* mt = AI_VALUE(Unit*, "main tank");
if (!mt)
return false;
Unit* current_target = AI_VALUE(Unit*, "current target");
if (!current_target)
return false;
ThreatMgr& mgr = current_target->GetThreatMgr();
float threat = mgr.GetThreat(bot);
float tankThreat = mgr.GetThreat(mt);
return tankThreat == 0.0f || threat > tankThreat * 0.5f;
}
bool AoeTrigger::IsActive()
{
Unit* current_target = AI_VALUE(Unit*, "current target");
if (!current_target)
{
return false;
}
GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get();
int attackers_count = 0;
for (ObjectGuid const guid : attackers)
{
Unit* unit = botAI->GetUnit(guid);
if (!unit || !unit->IsAlive())
continue;
if (unit->GetDistance(current_target->GetPosition()) <= range)
{
attackers_count++;
}
}
return attackers_count >= amount;
}
bool NoFoodTrigger::IsActive()
{
bool isRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot);
if (isRandomBot && botAI->HasCheat(BotCheatMask::food))
return false;
return AI_VALUE2(std::vector<Item*>, "inventory items", "conjured food").empty();
}
bool NoDrinkTrigger::IsActive()
{
bool isRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot);
if (isRandomBot && botAI->HasCheat(BotCheatMask::food))
return false;
return AI_VALUE2(std::vector<Item*>, "inventory items", "conjured water").empty();
}
bool TargetInSightTrigger::IsActive() { return AI_VALUE(Unit*, "grind target"); }
bool DebuffTrigger::IsActive()
{
Unit* target = GetTarget();
if (!target || !target->IsAlive() || !target->IsInWorld())
{
return false;
}
return BuffTrigger::IsActive() && (target->GetHealth() / AI_VALUE(float, "estimated group dps")) >= needLifeTime;
}
bool DebuffOnBossTrigger::IsActive()
{
if (!DebuffTrigger::IsActive())
{
return false;
}
Creature* c = GetTarget()->ToCreature();
return c && ((c->IsDungeonBoss()) || (c->isWorldBoss()));
}
bool SpellTrigger::IsActive() { return GetTarget(); }
bool SpellCanBeCastTrigger::IsActive()
{
Unit* target = GetTarget();
return target && botAI->CanCastSpell(spell, target);
}
bool SpellNoCooldownTrigger::IsActive()
{
uint32 spellId = AI_VALUE2(uint32, "spell id", name);
if (!spellId)
return false;
return !bot->HasSpellCooldown(spellId);
}
bool SpellCooldownTrigger::IsActive()
{
uint32 spellId = AI_VALUE2(uint32, "spell id", name);
if (!spellId)
return false;
return bot->HasSpellCooldown(spellId);
}
RandomTrigger::RandomTrigger(PlayerbotAI* botAI, std::string const name, int32 probability)
: Trigger(botAI, name), probability(probability), lastCheck(getMSTime())
{
}
bool RandomTrigger::IsActive()
{
if (getMSTime() - lastCheck < sPlayerbotAIConfig->repeatDelay)
return false;
lastCheck = getMSTime();
int32 k = (int32)(probability / sPlayerbotAIConfig->randomChangeMultiplier);
if (k < 1)
k = 1;
return (rand() % k) == 0;
}
bool AndTrigger::IsActive() { return ls && rs && ls->IsActive() && rs->IsActive(); }
std::string const AndTrigger::getName()
{
std::string name(ls->getName());
name = name + " and ";
name = name + rs->getName();
return name;
}
bool TwoTriggers::IsActive()
{
if (name1.empty() || name2.empty())
return false;
Trigger* trigger1 = botAI->GetAiObjectContext()->GetTrigger(name1);
Trigger* trigger2 = botAI->GetAiObjectContext()->GetTrigger(name2);
if (!trigger1 || !trigger2)
return false;
return trigger1->IsActive() && trigger2->IsActive();
}
std::string const TwoTriggers::getName()
{
std::string name;
name = name1 + " and " + name2;
return name;
}
bool BoostTrigger::IsActive()
{
if (!BuffTrigger::IsActive())
return false;
Unit* target = AI_VALUE(Unit*, "current target");
if (target && target->ToPlayer())
return true;
return AI_VALUE(uint8, "balance") <= balance;
}
bool GenericBoostTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
if (target && target->ToPlayer())
return true;
return AI_VALUE(uint8, "balance") <= balance;
}
bool HealerShouldAttackTrigger::IsActive()
{
// nobody can help me
if (botAI->GetNearGroupMemberCount(sPlayerbotAIConfig->sightDistance) <= 1)
return true;
if (AI_VALUE2(uint8, "health", "party member to heal") < sPlayerbotAIConfig->almostFullHealth)
return false;
// special check for resto druid (dont remove tree of life frequently)
if (bot->GetAura(33891))
{
LastSpellCast& lastSpell = botAI->GetAiObjectContext()->GetValue<LastSpellCast&>("last spell cast")->Get();
if (lastSpell.timer + 5 > time(nullptr))
return false;
}
int manaThreshold;
int balance = AI_VALUE(uint8, "balance");
// higher threshold in higher pressure
if (balance <= 50)
manaThreshold = 85;
else if (balance <= 100)
manaThreshold = sPlayerbotAIConfig->highMana;
else
manaThreshold = sPlayerbotAIConfig->mediumMana;
if (AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") < manaThreshold)
return false;
return true;
}
bool ItemCountTrigger::IsActive() { return AI_VALUE2(uint32, "item count", item) < count; }
bool InterruptSpellTrigger::IsActive()
{
return SpellTrigger::IsActive() && botAI->IsInterruptableSpellCasting(GetTarget(), getName());
}
bool DeflectSpellTrigger::IsActive()
{
Unit* target = GetTarget();
if (!target)
return false;
if (!target->IsNonMeleeSpellCast(true))
return false;
if (target->GetTarget() != bot->GetGUID())
return false;
uint32 spellid = context->GetValue<uint32>("spell id", spell)->Get();
if (!spellid)
return false;
SpellInfo const* deflectSpell = sSpellMgr->GetSpellInfo(spellid);
if (!deflectSpell)
return false;
// warrior deflects all
if (spell == "spell reflection")
return true;
// human priest feedback
if (spell == "feedback")
return true;
SpellSchoolMask deflectSchool = SpellSchoolMask(deflectSpell->Effects[EFFECT_0].MiscValue);
SpellSchoolMask attackSchool = SPELL_SCHOOL_MASK_NONE;
if (Spell* spell = target->GetCurrentSpell(CURRENT_GENERIC_SPELL))
{
if (SpellInfo const* tarSpellInfo = spell->GetSpellInfo())
{
attackSchool = tarSpellInfo->GetSchoolMask();
if (deflectSchool == attackSchool)
return true;
}
}
return false;
}
bool AttackerCountTrigger::IsActive() { return AI_VALUE(uint8, "attacker count") >= amount; }
bool HasAuraTrigger::IsActive() { return botAI->HasAura(getName(), GetTarget(), false, false, -1, true); }
bool HasAuraStackTrigger::IsActive()
{
Aura* aura = botAI->GetAura(getName(), GetTarget(), false, true, stack);
// sLog->outMessage("playerbot", LOG_LEVEL_DEBUG, "HasAuraStackTrigger::IsActive %s %d", getName(), aura ?
// aura->GetStackAmount() : -1);
return aura;
}
bool TimerTrigger::IsActive()
{
if (time(nullptr) != lastCheck)
{
lastCheck = time(nullptr);
return true;
}
return false;
}
bool TimerBGTrigger::IsActive()
{
time_t now = time(nullptr);
if (now - lastCheck >= 60)
{
lastCheck = now;
return true;
}
return false;
}
bool HasNoAuraTrigger::IsActive() { return !botAI->HasAura(getName(), GetTarget()); }
bool TankAssistTrigger::IsActive()
{
if (!AI_VALUE(uint8, "attacker count"))
return false;
Unit* currentTarget = AI_VALUE(Unit*, "current target");
if (!currentTarget)
return true;
Unit* tankTarget = AI_VALUE(Unit*, "tank target");
if (!tankTarget || currentTarget == tankTarget)
return false;
return AI_VALUE2(bool, "has aggro", "current target");
}
bool IsBehindTargetTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
return target && AI_VALUE2(bool, "behind", "current target");
}
bool IsNotBehindTargetTrigger::IsActive()
{
if (botAI->HasStrategy("stay", botAI->GetState()))
{
return false;
}
Unit* target = AI_VALUE(Unit*, "current target");
return target && !AI_VALUE2(bool, "behind", "current target");
}
bool IsNotFacingTargetTrigger::IsActive()
{
if (botAI->HasStrategy("stay", botAI->GetState()))
{
return false;
}
return !AI_VALUE2(bool, "facing", "current target");
}
bool HasCcTargetTrigger::IsActive()
{
return AI_VALUE2(Unit*, "cc target", getName()) && !AI_VALUE2(Unit*, "current cc target", getName());
}
bool NoMovementTrigger::IsActive() { return !AI_VALUE2(bool, "moving", "self target"); }
bool NoPossibleTargetsTrigger::IsActive()
{
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
return !targets.size();
}
bool PossibleAddsTrigger::IsActive() { return AI_VALUE(bool, "possible adds") && !AI_VALUE(ObjectGuid, "pull target"); }
bool NotDpsTargetActiveTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
// do not switch if enemy target
if (target && target->IsAlive())
{
Unit* enemy = AI_VALUE(Unit*, "enemy player target");
if (target == enemy)
return false;
}
Unit* dps = AI_VALUE(Unit*, "dps target");
return dps && target != dps;
}
bool NotDpsAoeTargetActiveTrigger::IsActive()
{
Unit* dps = AI_VALUE(Unit*, "dps aoe target");
Unit* target = AI_VALUE(Unit*, "current target");
Unit* enemy = AI_VALUE(Unit*, "enemy player target");
// do not switch if enemy target
if (target && target == enemy && target->IsAlive())
return false;
return dps && target != dps;
}
bool IsSwimmingTrigger::IsActive() { return AI_VALUE2(bool, "swimming", "self target"); }
bool HasNearestAddsTrigger::IsActive()
{
GuidVector targets = AI_VALUE(GuidVector, "nearest adds");
return targets.size();
}
bool HasItemForSpellTrigger::IsActive()
{
std::string const spell = getName();
uint32 spellId = AI_VALUE2(uint32, "spell id", spell);
return spellId && AI_VALUE2(Item*, "item for spell", spellId);
}
bool TargetChangedTrigger::IsActive()
{
Unit* oldTarget = context->GetValue<Unit*>("old target")->Get();
Unit* target = context->GetValue<Unit*>("current target")->Get();
return target && oldTarget != target;
}
Value<Unit*>* InterruptEnemyHealerTrigger::GetTargetValue()
{
return context->GetValue<Unit*>("enemy healer target", spell);
}
bool RandomBotUpdateTrigger::IsActive() { return RandomTrigger::IsActive() && AI_VALUE(bool, "random bot update"); }
bool NoNonBotPlayersAroundTrigger::IsActive()
{
return !botAI->HasPlayerNearby();
/*if (!bot->InBattleground())
return AI_VALUE(GuidVector, "nearest non bot players").empty();
return false;
*/
}
bool NewPlayerNearbyTrigger::IsActive() { return AI_VALUE(ObjectGuid, "new player nearby"); }
bool CollisionTrigger::IsActive() { return AI_VALUE2(bool, "collision", "self target"); }
bool ReturnToStayPositionTrigger::IsActive()
{
PositionInfo stayPosition = AI_VALUE(PositionMap&, "position")["stay"];
if (stayPosition.isSet())
{
const float distance = bot->GetDistance(stayPosition.x, stayPosition.y, stayPosition.z);
return distance > sPlayerbotAIConfig->followDistance;
}
return false;
}
bool GiveItemTrigger::IsActive()
{
return AI_VALUE2(Unit*, "party member without item", item) && AI_VALUE2(uint32, "item count", item);
}
bool GiveFoodTrigger::IsActive()
{
return AI_VALUE(Unit*, "party member without food") && AI_VALUE2(uint32, "item count", item);
}
bool GiveWaterTrigger::IsActive()
{
return AI_VALUE(Unit*, "party member without water") && AI_VALUE2(uint32, "item count", item);
}
Value<Unit*>* SnareTargetTrigger::GetTargetValue() { return context->GetValue<Unit*>("snare target", spell); }
bool StayTimeTrigger::IsActive()
{
time_t stayTime = AI_VALUE(time_t, "stay time");
time_t now = time(nullptr);
return delay && stayTime && now > stayTime + 2 * delay / 1000;
}
bool IsMountedTrigger::IsActive() { return AI_VALUE2(bool, "mounted", "self target"); }
bool CorpseNearTrigger::IsActive()
{
return bot->GetCorpse() && bot->GetCorpse()->IsWithinDistInMap(bot, CORPSE_RECLAIM_RADIUS, true);
}
bool IsFallingTrigger::IsActive() { return bot->HasUnitMovementFlag(MOVEMENTFLAG_FALLING); }
bool IsFallingFarTrigger::IsActive() { return bot->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR); }
bool HasAreaDebuffTrigger::IsActive() { return AI_VALUE2(bool, "has area debuff", "self target"); }
Value<Unit*>* BuffOnMainTankTrigger::GetTargetValue() { return context->GetValue<Unit*>("main tank", spell); }
bool AmmoCountTrigger::IsActive()
{
if (bot->GetUInt32Value(PLAYER_AMMO_ID) != 0)
return ItemCountTrigger::IsActive(); // Ammo already equipped
if (botAI->FindAmmo())
return true; // Found ammo in inventory but not equipped
return ItemCountTrigger::IsActive();
}
bool NewPetTrigger::IsActive()
{
// Get the bot player object from the AI
Player* bot = botAI->GetBot();
if (!bot)
return false;
// Try to get the current pet; initialize guardian and GUID to null/empty
Pet* pet = bot->GetPet();
Guardian* guardian = nullptr;
ObjectGuid currentPetGuid = ObjectGuid::Empty;
// If bot has a pet, get its GUID
if (pet)
{
currentPetGuid = pet->GetGUID();
}
else
{
// If no pet, try to get a guardian pet and its GUID
guardian = bot->GetGuardianPet();
if (guardian)
currentPetGuid = guardian->GetGUID();
}
// If the current pet or guardian GUID has changed (including becoming empty), reset the trigger state
if (currentPetGuid != lastPetGuid)
{
triggered = false;
lastPetGuid = currentPetGuid;
}
// If there's a valid current pet/guardian (non-empty GUID) and we haven't triggered yet, activate trigger
if (currentPetGuid != ObjectGuid::Empty && !triggered)
{
triggered = true;
return true;
}
// Otherwise, do not activate
return false;
}

View File

@@ -0,0 +1,958 @@
/*
* 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_GENERICTRIGGERS_H
#define _PLAYERBOT_GENERICTRIGGERS_H
#include <utility>
#include "HealthTriggers.h"
#include "RangeTriggers.h"
#include "Trigger.h"
#include "Player.h"
class PlayerbotAI;
class Unit;
class StatAvailable : public Trigger
{
public:
StatAvailable(PlayerbotAI* botAI, int32 amount, std::string const name = "stat available")
: Trigger(botAI, name), amount(amount)
{
}
protected:
int32 amount;
};
class HighManaTrigger : public Trigger
{
public:
HighManaTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high mana") {}
bool IsActive() override;
};
class EnoughManaTrigger : public Trigger
{
public:
EnoughManaTrigger(PlayerbotAI* botAI) : Trigger(botAI, "enough mana") {}
bool IsActive() override;
};
class AlmostFullManaTrigger : public Trigger
{
public:
AlmostFullManaTrigger(PlayerbotAI* botAI) : Trigger(botAI, "almost full mana") {}
bool IsActive() override;
};
class RageAvailable : public StatAvailable
{
public:
RageAvailable(PlayerbotAI* botAI, int32 amount) : StatAvailable(botAI, amount, "rage available") {}
bool IsActive() override;
};
class LightRageAvailableTrigger : public RageAvailable
{
public:
LightRageAvailableTrigger(PlayerbotAI* botAI) : RageAvailable(botAI, 20) {}
};
class MediumRageAvailableTrigger : public RageAvailable
{
public:
MediumRageAvailableTrigger(PlayerbotAI* botAI) : RageAvailable(botAI, 40) {}
};
class HighRageAvailableTrigger : public RageAvailable
{
public:
HighRageAvailableTrigger(PlayerbotAI* botAI) : RageAvailable(botAI, 60) {}
};
class EnergyAvailable : public StatAvailable
{
public:
EnergyAvailable(PlayerbotAI* botAI, int32 amount) : StatAvailable(botAI, amount, "energy available") {}
bool IsActive() override;
};
class LightEnergyAvailableTrigger : public EnergyAvailable
{
public:
LightEnergyAvailableTrigger(PlayerbotAI* botAI) : EnergyAvailable(botAI, 20) {}
};
class MediumEnergyAvailableTrigger : public EnergyAvailable
{
public:
MediumEnergyAvailableTrigger(PlayerbotAI* botAI) : EnergyAvailable(botAI, 40) {}
};
class HighEnergyAvailableTrigger : public EnergyAvailable
{
public:
HighEnergyAvailableTrigger(PlayerbotAI* botAI) : EnergyAvailable(botAI, 60) {}
};
class ComboPointsAvailableTrigger : public StatAvailable
{
public:
ComboPointsAvailableTrigger(PlayerbotAI* botAI, int32 amount = 5)
: StatAvailable(botAI, amount, "combo points available")
{
}
bool IsActive() override;
};
class TargetWithComboPointsLowerHealTrigger : public ComboPointsAvailableTrigger
{
public:
TargetWithComboPointsLowerHealTrigger(PlayerbotAI* ai, int32 combo_point = 5, float lifeTime = 8.0f)
: ComboPointsAvailableTrigger(ai, combo_point), lifeTime(lifeTime)
{
}
bool IsActive() override;
private:
float lifeTime;
};
class ComboPointsNotFullTrigger : public StatAvailable
{
public:
ComboPointsNotFullTrigger(PlayerbotAI* botAI, int32 amount = 5, std::string const name = "combo points not full")
: StatAvailable(botAI, amount, name)
{
}
bool IsActive() override;
};
class LoseAggroTrigger : public Trigger
{
public:
LoseAggroTrigger(PlayerbotAI* botAI) : Trigger(botAI, "lose aggro") {}
bool IsActive() override;
};
class HasAggroTrigger : public Trigger
{
public:
HasAggroTrigger(PlayerbotAI* botAI) : Trigger(botAI, "have aggro") {}
bool IsActive() override;
};
class SpellTrigger : public Trigger
{
public:
SpellTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1)
: Trigger(botAI, spell, checkInterval), spell(spell)
{
}
std::string const GetTargetName() override { return "current target"; }
std::string const getName() override { return spell; }
bool IsActive() override;
protected:
std::string spell;
};
class SpellCanBeCastTrigger : public SpellTrigger
{
public:
SpellCanBeCastTrigger(PlayerbotAI* botAI, std::string const spell) : SpellTrigger(botAI, spell) {}
bool IsActive() override;
};
class SpellNoCooldownTrigger : public SpellTrigger
{
public:
SpellNoCooldownTrigger(PlayerbotAI* botAI, std::string const spell) : SpellTrigger(botAI, spell) {}
bool IsActive() override;
};
class SpellCooldownTrigger : public SpellTrigger
{
public:
SpellCooldownTrigger(PlayerbotAI* botAI, std::string const spell) : SpellTrigger(botAI, spell) {}
std::string const GetTargetName() override { return "self target"; }
bool IsActive() override;
};
// TODO: check other targets
class InterruptSpellTrigger : public SpellTrigger
{
public:
InterruptSpellTrigger(PlayerbotAI* botAI, std::string const spell) : SpellTrigger(botAI, spell) {}
bool IsActive() override;
};
class DeflectSpellTrigger : public SpellTrigger
{
public:
DeflectSpellTrigger(PlayerbotAI* botAI, std::string const spell) : SpellTrigger(botAI, spell) {}
bool IsActive() override;
};
class AttackerCountTrigger : public Trigger
{
public:
AttackerCountTrigger(PlayerbotAI* botAI, int32 amount, float distance = sPlayerbotAIConfig->sightDistance)
: Trigger(botAI), amount(amount), distance(distance)
{
}
bool IsActive() override;
std::string const getName() override { return "attacker count"; }
protected:
int32 amount;
float distance;
};
class HasAttackersTrigger : public AttackerCountTrigger
{
public:
HasAttackersTrigger(PlayerbotAI* botAI) : AttackerCountTrigger(botAI, 1) {}
};
class MyAttackerCountTrigger : public AttackerCountTrigger
{
public:
MyAttackerCountTrigger(PlayerbotAI* botAI, int32 amount) : AttackerCountTrigger(botAI, amount) {}
bool IsActive() override;
std::string const getName() override { return "my attacker count"; }
};
class BeingAttackedTrigger : public MyAttackerCountTrigger
{
public:
BeingAttackedTrigger(PlayerbotAI* botAI) : MyAttackerCountTrigger(botAI, 1) {}
std::string const getName() override { return "being attacked"; }
};
class MediumThreatTrigger : public MyAttackerCountTrigger
{
public:
MediumThreatTrigger(PlayerbotAI* botAI) : MyAttackerCountTrigger(botAI, 2) {}
bool IsActive() override;
};
class LowTankThreatTrigger : public Trigger
{
public:
LowTankThreatTrigger(PlayerbotAI* botAI) : Trigger(botAI, "low tank threat") {}
bool IsActive() override;
};
class AoeTrigger : public AttackerCountTrigger
{
public:
AoeTrigger(PlayerbotAI* botAI, int32 amount = 3, float range = 15.0f)
: AttackerCountTrigger(botAI, amount), range(range)
{
}
bool IsActive() override;
std::string const getName() override { return "aoe"; }
private:
float range;
};
class NoFoodTrigger : public Trigger
{
public:
NoFoodTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no food trigger") {}
bool IsActive() override;
};
class NoDrinkTrigger : public Trigger
{
public:
NoDrinkTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no drink trigger") {}
bool IsActive() override;
};
class LightAoeTrigger : public AoeTrigger
{
public:
LightAoeTrigger(PlayerbotAI* botAI) : AoeTrigger(botAI, 2, 8.0f) {}
};
class MediumAoeTrigger : public AoeTrigger
{
public:
MediumAoeTrigger(PlayerbotAI* botAI) : AoeTrigger(botAI, 3, 8.0f) {}
};
class HighAoeTrigger : public AoeTrigger
{
public:
HighAoeTrigger(PlayerbotAI* botAI) : AoeTrigger(botAI, 4, 8.0f) {}
};
class BuffTrigger : public SpellTrigger
{
public:
BuffTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1, bool checkIsOwner = false, bool checkDuration = false, uint32 beforeDuration = 0)
: SpellTrigger(botAI, spell, checkInterval)
{
this->checkIsOwner = checkIsOwner;
this->checkDuration = checkDuration;
this->beforeDuration = beforeDuration;
}
public:
std::string const GetTargetName() override { return "self target"; }
bool IsActive() override;
protected:
bool checkIsOwner;
bool checkDuration;
uint32 beforeDuration;
};
class BuffOnPartyTrigger : public BuffTrigger
{
public:
BuffOnPartyTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1)
: BuffTrigger(botAI, spell, checkInterval)
{
}
Value<Unit*>* GetTargetValue() override;
std::string const getName() override { return spell + " on party"; }
};
class ProtectPartyMemberTrigger : public Trigger
{
public:
ProtectPartyMemberTrigger(PlayerbotAI* botAI) : Trigger(botAI, "protect party member") {}
std::string const GetTargetName() override { return "party member to protect"; }
bool IsActive() override;
};
class NoAttackersTrigger : public Trigger
{
public:
NoAttackersTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no attackers") {}
bool IsActive() override;
};
class NoTargetTrigger : public Trigger
{
public:
NoTargetTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no target") {}
bool IsActive() override;
};
class InvalidTargetTrigger : public Trigger
{
public:
InvalidTargetTrigger(PlayerbotAI* botAI) : Trigger(botAI, "invalid target") {}
bool IsActive() override;
};
class TargetInSightTrigger : public Trigger
{
public:
TargetInSightTrigger(PlayerbotAI* botAI) : Trigger(botAI, "target in sight") {}
bool IsActive() override;
};
class DebuffTrigger : public BuffTrigger
{
public:
DebuffTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1, bool checkIsOwner = false,
float needLifeTime = 8.0f, uint32 beforeDuration = 0)
: BuffTrigger(botAI, spell, checkInterval, checkIsOwner, false, beforeDuration), needLifeTime(needLifeTime)
{
}
std::string const GetTargetName() override { return "current target"; }
bool IsActive() override;
protected:
float needLifeTime;
};
class DebuffOnBossTrigger : public DebuffTrigger
{
public:
DebuffOnBossTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1, bool checkIsOwner = false)
: DebuffTrigger(botAI, spell, checkInterval, checkIsOwner)
{
}
bool IsActive() override;
};
class DebuffOnAttackerTrigger : public DebuffTrigger
{
public:
DebuffOnAttackerTrigger(PlayerbotAI* botAI, std::string const spell, bool checkIsOwner = true,
float needLifeTime = 8.0f)
: DebuffTrigger(botAI, spell, 1, checkIsOwner, needLifeTime)
{
}
Value<Unit*>* GetTargetValue() override;
std::string const getName() override { return spell + " on attacker"; }
};
class DebuffOnMeleeAttackerTrigger : public DebuffTrigger
{
public:
DebuffOnMeleeAttackerTrigger(PlayerbotAI* botAI, std::string const spell, bool checkIsOwner = true,
float needLifeTime = 8.0f)
: DebuffTrigger(botAI, spell, 1, checkIsOwner, needLifeTime)
{
}
Value<Unit*>* GetTargetValue() override;
std::string const getName() override { return spell + " on attacker"; }
};
class BoostTrigger : public BuffTrigger
{
public:
BoostTrigger(PlayerbotAI* botAI, std::string const spell, float balance = 50.f)
: BuffTrigger(botAI, spell, 1), balance(balance)
{
}
bool IsActive() override;
protected:
float balance;
};
class GenericBoostTrigger : public Trigger
{
public:
GenericBoostTrigger(PlayerbotAI* botAI, float balance = 50.f)
: Trigger(botAI, "generic boost", 1), balance(balance)
{
}
bool IsActive() override;
protected:
float balance;
};
class HealerShouldAttackTrigger : public Trigger
{
public:
HealerShouldAttackTrigger(PlayerbotAI* botAI)
: Trigger(botAI, "healer should attack", 1)
{
}
bool IsActive() override;
};
class RandomTrigger : public Trigger
{
public:
RandomTrigger(PlayerbotAI* botAI, std::string const name, int32 probability = 7);
bool IsActive() override;
protected:
int32 probability;
uint32 lastCheck;
};
class AndTrigger : public Trigger
{
public:
AndTrigger(PlayerbotAI* botAI, Trigger* ls, Trigger* rs) : Trigger(botAI), ls(ls), rs(rs) {}
virtual ~AndTrigger()
{
delete ls;
delete rs;
}
bool IsActive() override;
std::string const getName() override;
protected:
Trigger* ls;
Trigger* rs;
};
class TwoTriggers : public Trigger
{
public:
explicit TwoTriggers(PlayerbotAI* botAI, std::string name1 = "", std::string name2 = "") : Trigger(botAI)
{
this->name1 = std::move(name1);
this->name2 = std::move(name2);
}
bool IsActive() override;
std::string const getName() override;
protected:
std::string name1;
std::string name2;
};
class SnareTargetTrigger : public DebuffTrigger
{
public:
SnareTargetTrigger(PlayerbotAI* botAI, std::string const spell) : DebuffTrigger(botAI, spell) {}
Value<Unit*>* GetTargetValue() override;
std::string const getName() override { return spell + " on snare target"; }
};
class LowManaTrigger : public Trigger
{
public:
LowManaTrigger(PlayerbotAI* botAI) : Trigger(botAI, "low mana") {}
bool IsActive() override;
};
class MediumManaTrigger : public Trigger
{
public:
MediumManaTrigger(PlayerbotAI* botAI) : Trigger(botAI, "medium mana") {}
bool IsActive() override;
};
BEGIN_TRIGGER(PanicTrigger, Trigger) // cppcheck-suppress unknownMacro
std::string const getName() override { return "panic"; }
END_TRIGGER()
BEGIN_TRIGGER(OutNumberedTrigger, Trigger)
std::string const getName() override { return "outnumbered"; }
END_TRIGGER()
class NoPetTrigger : public Trigger
{
public:
NoPetTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no pet", 5 * 1000) {}
virtual bool IsActive() override;
};
class HasPetTrigger : public Trigger
{
public:
HasPetTrigger(PlayerbotAI* ai) : Trigger(ai, "has pet", 5 * 1000) {}
virtual bool IsActive() override;
};
class PetAttackTrigger : public Trigger
{
public:
PetAttackTrigger(PlayerbotAI* ai) : Trigger(ai, "pet attack") {}
virtual bool IsActive() override;
};
class ItemCountTrigger : public Trigger
{
public:
ItemCountTrigger(PlayerbotAI* botAI, std::string const item, int32 count, int32 interval = 30 * 1000)
: Trigger(botAI, item, interval), item(item), count(count)
{
}
bool IsActive() override;
std::string const getName() override { return "item count"; }
protected:
std::string const item;
int32 count;
};
class AmmoCountTrigger : public ItemCountTrigger
{
public:
AmmoCountTrigger(PlayerbotAI* botAI, std::string const item, uint32 count = 1, int32 interval = 30 * 1000)
: ItemCountTrigger(botAI, item, count, interval)
{
}
bool IsActive() override;
};
class HasAuraTrigger : public Trigger
{
public:
HasAuraTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1)
: Trigger(botAI, spell, checkInterval)
{
}
std::string const GetTargetName() override { return "self target"; }
bool IsActive() override;
};
class HasAuraStackTrigger : public Trigger
{
public:
HasAuraStackTrigger(PlayerbotAI* ai, std::string spell, int stack, int checkInterval = 1)
: Trigger(ai, spell, checkInterval), stack(stack)
{
}
std::string const GetTargetName() override { return "self target"; }
bool IsActive() override;
private:
int stack;
};
class HasNoAuraTrigger : public Trigger
{
public:
HasNoAuraTrigger(PlayerbotAI* botAI, std::string const spell) : Trigger(botAI, spell) {}
std::string const GetTargetName() override { return "self target"; }
bool IsActive() override;
};
class TimerTrigger : public Trigger
{
public:
TimerTrigger(PlayerbotAI* botAI) : Trigger(botAI, "timer"), lastCheck(0) {}
bool IsActive() override;
private:
time_t lastCheck;
};
class TimerBGTrigger : public Trigger
{
public:
TimerBGTrigger(PlayerbotAI* botAI) : Trigger(botAI, "timer bg"), lastCheck(0) {}
bool IsActive() override;
private:
time_t lastCheck;
};
class TankAssistTrigger : public NoAttackersTrigger
{
public:
TankAssistTrigger(PlayerbotAI* botAI) : NoAttackersTrigger(botAI) {}
bool IsActive() override;
};
class IsBehindTargetTrigger : public Trigger
{
public:
IsBehindTargetTrigger(PlayerbotAI* botAI) : Trigger(botAI, "behind target") {}
bool IsActive() override;
};
class IsNotBehindTargetTrigger : public Trigger
{
public:
IsNotBehindTargetTrigger(PlayerbotAI* botAI) : Trigger(botAI, "is not behind target") {}
bool IsActive() override;
};
class IsNotFacingTargetTrigger : public Trigger
{
public:
IsNotFacingTargetTrigger(PlayerbotAI* botAI) : Trigger(botAI, "not facing target") {}
bool IsActive() override;
};
class HasCcTargetTrigger : public Trigger
{
public:
HasCcTargetTrigger(PlayerbotAI* botAI, std::string const name) : Trigger(botAI, name) {}
bool IsActive() override;
};
class NoMovementTrigger : public Trigger
{
public:
NoMovementTrigger(PlayerbotAI* botAI, std::string const name) : Trigger(botAI, name) {}
bool IsActive() override;
};
class NoPossibleTargetsTrigger : public Trigger
{
public:
NoPossibleTargetsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no possible targets") {}
bool IsActive() override;
};
class NotDpsTargetActiveTrigger : public Trigger
{
public:
NotDpsTargetActiveTrigger(PlayerbotAI* botAI) : Trigger(botAI, "not dps target active") {}
bool IsActive() override;
};
class NotDpsAoeTargetActiveTrigger : public Trigger
{
public:
NotDpsAoeTargetActiveTrigger(PlayerbotAI* botAI) : Trigger(botAI, "not dps aoe target active") {}
bool IsActive() override;
};
class PossibleAddsTrigger : public Trigger
{
public:
PossibleAddsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "possible adds") {}
bool IsActive() override;
};
class IsSwimmingTrigger : public Trigger
{
public:
IsSwimmingTrigger(PlayerbotAI* botAI) : Trigger(botAI, "swimming") {}
bool IsActive() override;
};
class HasNearestAddsTrigger : public Trigger
{
public:
HasNearestAddsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "has nearest adds") {}
bool IsActive() override;
};
class HasItemForSpellTrigger : public Trigger
{
public:
HasItemForSpellTrigger(PlayerbotAI* botAI, std::string const spell) : Trigger(botAI, spell) {}
bool IsActive() override;
};
class TargetChangedTrigger : public Trigger
{
public:
TargetChangedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "target changed") {}
bool IsActive() override;
};
class InterruptEnemyHealerTrigger : public SpellTrigger
{
public:
InterruptEnemyHealerTrigger(PlayerbotAI* botAI, std::string const spell) : SpellTrigger(botAI, spell) {}
Value<Unit*>* GetTargetValue() override;
std::string const getName() override { return spell + " on enemy healer"; }
};
class RandomBotUpdateTrigger : public RandomTrigger
{
public:
RandomBotUpdateTrigger(PlayerbotAI* botAI) : RandomTrigger(botAI, "random bot update", 30 * 1000) {}
bool IsActive() override;
};
class NoNonBotPlayersAroundTrigger : public Trigger
{
public:
NoNonBotPlayersAroundTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no non bot players around", 10 * 1000) {}
bool IsActive() override;
};
class NewPlayerNearbyTrigger : public Trigger
{
public:
NewPlayerNearbyTrigger(PlayerbotAI* botAI) : Trigger(botAI, "new player nearby", 10 * 1000) {}
bool IsActive() override;
};
class CollisionTrigger : public Trigger
{
public:
CollisionTrigger(PlayerbotAI* botAI) : Trigger(botAI, "collision", 5 * 1000) {}
bool IsActive() override;
};
class StayTimeTrigger : public Trigger
{
public:
StayTimeTrigger(PlayerbotAI* botAI, uint32 delay, std::string const name)
: Trigger(botAI, name, 5 * 1000), delay(delay)
{
}
bool IsActive() override;
private:
uint32 delay;
};
class SitTrigger : public StayTimeTrigger
{
public:
SitTrigger(PlayerbotAI* botAI) : StayTimeTrigger(botAI, sPlayerbotAIConfig->sitDelay, "sit") {}
};
class ReturnToStayPositionTrigger : public Trigger
{
public:
ReturnToStayPositionTrigger(PlayerbotAI* ai) : Trigger(ai, "return to stay position", 2) {}
virtual bool IsActive() override;
};
class ReturnTrigger : public StayTimeTrigger
{
public:
ReturnTrigger(PlayerbotAI* botAI) : StayTimeTrigger(botAI, sPlayerbotAIConfig->returnDelay, "return") {}
};
class GiveItemTrigger : public Trigger
{
public:
GiveItemTrigger(PlayerbotAI* botAI, std::string const name, std::string const item)
: Trigger(botAI, name, 2 * 1000), item(item)
{
}
bool IsActive() override;
protected:
std::string const item;
};
class GiveFoodTrigger : public GiveItemTrigger
{
public:
GiveFoodTrigger(PlayerbotAI* botAI) : GiveItemTrigger(botAI, "give food", "conjured food") {}
bool IsActive() override;
};
class GiveWaterTrigger : public GiveItemTrigger
{
public:
GiveWaterTrigger(PlayerbotAI* botAI) : GiveItemTrigger(botAI, "give water", "conjured water") {}
bool IsActive() override;
};
class IsMountedTrigger : public Trigger
{
public:
IsMountedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "mounted", 1) {}
bool IsActive() override;
};
class CorpseNearTrigger : public Trigger
{
public:
CorpseNearTrigger(PlayerbotAI* botAI) : Trigger(botAI, "corpse near", 1 * 1000) {}
bool IsActive() override;
};
class IsFallingTrigger : public Trigger
{
public:
IsFallingTrigger(PlayerbotAI* botAI) : Trigger(botAI, "falling", 10 * 1000) {}
bool IsActive() override;
};
class IsFallingFarTrigger : public Trigger
{
public:
IsFallingFarTrigger(PlayerbotAI* botAI) : Trigger(botAI, "falling far", 10 * 1000) {}
bool IsActive() override;
};
class HasAreaDebuffTrigger : public Trigger
{
public:
HasAreaDebuffTrigger(PlayerbotAI* botAI) : Trigger(botAI, "have area debuff") {}
bool IsActive() override;
};
class BuffOnMainTankTrigger : public BuffTrigger
{
public:
BuffOnMainTankTrigger(PlayerbotAI* botAI, std::string spell, bool checkIsOwner = false, int checkInterval = 1)
: BuffTrigger(botAI, spell, checkInterval, checkIsOwner)
{
}
public:
virtual Value<Unit*>* GetTargetValue();
};
class SelfResurrectTrigger : public Trigger
{
public:
SelfResurrectTrigger(PlayerbotAI* ai) : Trigger(ai, "can self resurrect") {}
bool IsActive() override { return !bot->IsAlive() && bot->GetUInt32Value(PLAYER_SELF_RES_SPELL); }
};
class NewPetTrigger : public Trigger
{
public:
NewPetTrigger(PlayerbotAI* ai) : Trigger(ai, "new pet"), lastPetGuid(ObjectGuid::Empty), triggered(false) {}
bool IsActive() override;
private:
ObjectGuid lastPetGuid;
bool triggered;
};
#endif

View File

@@ -0,0 +1,57 @@
/*
* 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 "GuildTriggers.h"
#include "GuildMgr.h"
#include "Playerbots.h"
bool PetitionTurnInTrigger::IsActive()
{
return !bot->GetGuildId() && AI_VALUE2(uint32, "item count", chat->FormatQItem(5863)) &&
AI_VALUE(uint8, "petition signs") >= sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS);
}
bool BuyTabardTrigger::IsActive()
{
return bot->GetGuildId() && !AI_VALUE2(uint32, "item count", chat->FormatQItem(5976));
}
bool LeaveLargeGuildTrigger::IsActive()
{
if (!bot->GetGuildId())
return false;
if (botAI->IsRealPlayer())
return false;
if (botAI->IsAlt())
return false;
if (botAI->IsInRealGuild())
return false;
GuilderType type = botAI->GetGuilderType();
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
Player* leader = ObjectAccessor::FindPlayer(guild->GetLeaderGUID());
// Only leave the guild if we know the leader is not a real player.
if (!leader || !GET_PLAYERBOT_AI(leader) || !GET_PLAYERBOT_AI(leader)->IsRealPlayer())
return false;
PlayerbotAI* leaderBotAI = GET_PLAYERBOT_AI(leader);
if (!leaderBotAI || leaderBotAI->IsRealPlayer())
return false;
if (type == GuilderType::SOLO && guild->GetLeaderGUID() != bot->GetGUID())
return true;
uint32 members = guild->GetMemberSize();
uint32 maxMembers = uint8(type);
return members > maxMembers;
}

View File

@@ -0,0 +1,37 @@
/*
* 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_GUILDTRIGGER_H
#define _PLAYERBOT_GUILDTRIGGER_H
#include "Trigger.h"
class PlayerbotAI;
class PetitionTurnInTrigger : public Trigger
{
public:
PetitionTurnInTrigger(PlayerbotAI* botAI) : Trigger(botAI) {}
bool IsActive() override;
};
class BuyTabardTrigger : public Trigger
{
public:
BuyTabardTrigger(PlayerbotAI* botAI) : Trigger(botAI) {}
bool IsActive() override;
};
class LeaveLargeGuildTrigger : public Trigger
{
public:
LeaveLargeGuildTrigger(PlayerbotAI* botAI) : Trigger(botAI) {}
bool IsActive();
};
#endif

View File

@@ -0,0 +1,41 @@
/*
* 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 "HealthTriggers.h"
#include "Playerbots.h"
bool HealthInRangeTrigger::IsActive()
{
return ValueInRangeTrigger::IsActive() && !AI_VALUE2(bool, "dead", GetTargetName());
}
float HealthInRangeTrigger::GetValue() { return AI_VALUE2(uint8, "health", GetTargetName()); }
bool PartyMemberDeadTrigger::IsActive() { return GetTarget(); }
bool CombatPartyMemberDeadTrigger::IsActive() { return GetTarget(); }
bool DeadTrigger::IsActive() { return AI_VALUE2(bool, "dead", GetTargetName()); }
bool AoeHealTrigger::IsActive() { return AI_VALUE2(uint8, "aoe heal", type) >= count; }
bool AoeInGroupTrigger::IsActive()
{
int32 member = botAI->GetNearGroupMemberCount();
if (member < 5)
return false;
int threshold = member * 0.5;
if (member <= 5)
threshold = 3;
else if (member <= 10)
threshold = std::min(threshold, 5);
else if (member <= 25)
threshold = std::min(threshold, 10);
else
threshold = std::min(threshold, 15);
return AI_VALUE2(uint8, "aoe heal", type) >= threshold;
}

View File

@@ -0,0 +1,199 @@
/*
* 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_HEALTHTRIGGERS_H
#define _PLAYERBOT_HEALTHTRIGGERS_H
#include <stdexcept>
#include "PlayerbotAIConfig.h"
#include "Trigger.h"
class PlayerbotAI;
class ValueInRangeTrigger : public Trigger
{
public:
ValueInRangeTrigger(PlayerbotAI* botAI, std::string const name, float maxValue, float minValue)
: Trigger(botAI, name), maxValue(maxValue), minValue(minValue)
{
}
virtual float GetValue() = 0;
bool IsActive() override
{
float value = GetValue();
return value < maxValue && value >= minValue;
}
protected:
float maxValue, minValue;
};
class HealthInRangeTrigger : public ValueInRangeTrigger
{
public:
HealthInRangeTrigger(PlayerbotAI* botAI, std::string const name, float maxValue, float minValue = 0)
: ValueInRangeTrigger(botAI, name, maxValue, minValue)
{
}
bool IsActive() override;
float GetValue() override;
};
class LowHealthTrigger : public HealthInRangeTrigger
{
public:
LowHealthTrigger(PlayerbotAI* botAI, std::string const name = "low health",
float value = sPlayerbotAIConfig->lowHealth, float minValue = 0)
: HealthInRangeTrigger(botAI, name, value, minValue)
{
}
std::string const GetTargetName() override { return "self target"; }
};
class CriticalHealthTrigger : public LowHealthTrigger
{
public:
CriticalHealthTrigger(PlayerbotAI* botAI)
: LowHealthTrigger(botAI, "critical health", sPlayerbotAIConfig->criticalHealth, 0)
{
}
};
class MediumHealthTrigger : public LowHealthTrigger
{
public:
MediumHealthTrigger(PlayerbotAI* botAI)
: LowHealthTrigger(botAI, "medium health", sPlayerbotAIConfig->mediumHealth, 0)
{
}
};
class AlmostFullHealthTrigger : public LowHealthTrigger
{
public:
AlmostFullHealthTrigger(PlayerbotAI* botAI)
: LowHealthTrigger(botAI, "almost full health", sPlayerbotAIConfig->almostFullHealth,
sPlayerbotAIConfig->mediumHealth)
{
}
};
class PartyMemberLowHealthTrigger : public HealthInRangeTrigger
{
public:
PartyMemberLowHealthTrigger(PlayerbotAI* botAI, std::string const name = "party member low health",
float value = sPlayerbotAIConfig->lowHealth,
float minValue = 0)
: HealthInRangeTrigger(botAI, name, value, minValue)
{
}
std::string const GetTargetName() override { return "party member to heal"; }
};
class PartyMemberCriticalHealthTrigger : public PartyMemberLowHealthTrigger
{
public:
PartyMemberCriticalHealthTrigger(PlayerbotAI* botAI)
: PartyMemberLowHealthTrigger(botAI, "party member critical health", sPlayerbotAIConfig->criticalHealth, 0)
{
}
};
class PartyMemberMediumHealthTrigger : public PartyMemberLowHealthTrigger
{
public:
PartyMemberMediumHealthTrigger(PlayerbotAI* botAI)
: PartyMemberLowHealthTrigger(botAI, "party member medium health", sPlayerbotAIConfig->mediumHealth,
0)
{
}
};
class PartyMemberAlmostFullHealthTrigger : public PartyMemberLowHealthTrigger
{
public:
PartyMemberAlmostFullHealthTrigger(PlayerbotAI* botAI)
: PartyMemberLowHealthTrigger(botAI, "party member almost full health", sPlayerbotAIConfig->almostFullHealth,
0)
{
}
};
class TargetLowHealthTrigger : public HealthInRangeTrigger
{
public:
TargetLowHealthTrigger(PlayerbotAI* botAI, float value, float minValue = 0)
: HealthInRangeTrigger(botAI, "target low health", value, minValue)
{
}
std::string const GetTargetName() override { return "current target"; }
};
class TargetCriticalHealthTrigger : public TargetLowHealthTrigger
{
public:
TargetCriticalHealthTrigger(PlayerbotAI* botAI) : TargetLowHealthTrigger(botAI, 20) {}
};
class PartyMemberDeadTrigger : public Trigger
{
public:
PartyMemberDeadTrigger(PlayerbotAI* botAI) : Trigger(botAI, "resurrect", 1 * 1000) {}
std::string const GetTargetName() override { return "party member to resurrect"; }
bool IsActive() override;
};
class CombatPartyMemberDeadTrigger : public Trigger
{
public:
CombatPartyMemberDeadTrigger(PlayerbotAI* ai) : Trigger(ai, "combat party member to resurrect", 1) {}
std::string const GetTargetName() override { return "party member to resurrect"; }
bool IsActive() override;
};
class DeadTrigger : public Trigger
{
public:
DeadTrigger(PlayerbotAI* botAI) : Trigger(botAI, "dead") {}
std::string const GetTargetName() override { return "self target"; }
bool IsActive() override;
};
class AoeHealTrigger : public Trigger
{
public:
AoeHealTrigger(PlayerbotAI* botAI, std::string const name, std::string const type, int32 count)
: Trigger(botAI, name), count(count), type(type)
{
} // reorder args - whipowill
bool IsActive() override;
protected:
int32 count;
std::string const type;
};
class AoeInGroupTrigger : public Trigger
{
public:
AoeInGroupTrigger(PlayerbotAI* ai, std::string name, std::string type)
: Trigger(ai, name), type(type)
{
}
bool IsActive() override;
protected:
std::string type;
};
#endif

View File

@@ -0,0 +1,16 @@
/*
* 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 "LfgTriggers.h"
#include "Playerbots.h"
bool LfgProposalActiveTrigger::IsActive() { return AI_VALUE(uint32, "lfg proposal"); }
bool UnknownDungeonTrigger::IsActive()
{
return botAI->HasActivePlayerMaster() && botAI->GetMaster() && botAI->GetMaster()->IsInWorld() &&
botAI->GetMaster()->GetMap()->IsDungeon() && bot->GetMapId() == botAI->GetMaster()->GetMapId();
}

View File

@@ -0,0 +1,29 @@
/*
* 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_LFGTRIGGERS_H
#define _PLAYERBOT_LFGTRIGGERS_H
#include "Trigger.h"
class PlayerbotAI;
class LfgProposalActiveTrigger : public Trigger
{
public:
LfgProposalActiveTrigger(PlayerbotAI* botAI) : Trigger(botAI, "lfg proposal active", 20 * 2000) {}
bool IsActive() override;
};
class UnknownDungeonTrigger : public Trigger
{
public:
UnknownDungeonTrigger(PlayerbotAI* botAI) : Trigger(botAI, "unknown dungeon", 20 * 2000) {}
bool IsActive() override;
};
#endif

View File

@@ -0,0 +1,40 @@
/*
* 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 "LootTriggers.h"
#include "LootObjectStack.h"
#include "Playerbots.h"
#include "ServerFacade.h"
bool LootAvailableTrigger::IsActive()
{
bool distanceCheck = false;
if (botAI->HasStrategy("stay", BOT_STATE_NON_COMBAT))
{
distanceCheck =
sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"), CONTACT_DISTANCE);
}
else
{
distanceCheck = sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "loot target"),
INTERACTION_DISTANCE - 2.0f);
}
// if loot target if empty, always pass distance check
return AI_VALUE(bool, "has available loot") &&
(distanceCheck || AI_VALUE(GuidVector, "all targets").empty());
}
bool FarFromCurrentLootTrigger::IsActive()
{
LootObject loot = AI_VALUE(LootObject, "loot target");
if (!loot.IsLootPossible(bot))
return false;
return AI_VALUE2(float, "distance", "loot target") >= INTERACTION_DISTANCE - 2.0f;
}
bool CanLootTrigger::IsActive() { return AI_VALUE(bool, "can loot"); }

View File

@@ -0,0 +1,37 @@
/*
* 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_LOOTTRIGGERS_H
#define _PLAYERBOT_LOOTTRIGGERS_H
#include "Trigger.h"
class PlayerbotAI;
class LootAvailableTrigger : public Trigger
{
public:
LootAvailableTrigger(PlayerbotAI* botAI) : Trigger(botAI, "loot available") {}
bool IsActive() override;
};
class FarFromCurrentLootTrigger : public Trigger
{
public:
FarFromCurrentLootTrigger(PlayerbotAI* botAI) : Trigger(botAI, "far from current loot") {}
bool IsActive() override;
};
class CanLootTrigger : public Trigger
{
public:
CanLootTrigger(PlayerbotAI* botAI) : Trigger(botAI, "can loot") {}
bool IsActive() override;
};
#endif

View File

@@ -0,0 +1,337 @@
/*
* 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 "PvpTriggers.h"
#include "BattleGroundTactics.h"
#include "BattlegroundEY.h"
#include "BattlegroundMgr.h"
#include "BattlegroundWS.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "BattlegroundAV.h"
#include "BattlegroundEY.h"
bool EnemyPlayerNear::IsActive() { return AI_VALUE(Unit*, "enemy player target"); }
bool PlayerHasNoFlag::IsActive()
{
if (botAI->GetBot()->InBattleground())
{
if (botAI->GetBot()->GetBattlegroundTypeId() == BattlegroundTypeId::BATTLEGROUND_WS)
{
BattlegroundWS* bg = (BattlegroundWS*)botAI->GetBot()->GetBattleground();
if (!(bg->GetFlagState(bg->GetOtherTeamId(bot->GetTeamId())) == BG_WS_FLAG_STATE_ON_PLAYER))
return true;
if (bot->GetGUID() == bg->GetFlagPickerGUID(TEAM_ALLIANCE) ||
bot->GetGUID() == bg->GetFlagPickerGUID(TEAM_HORDE))
{
return false;
}
return true;
}
return false;
}
return false;
}
bool PlayerIsInBattleground::IsActive() { return botAI->GetBot()->InBattleground(); }
bool BgWaitingTrigger::IsActive()
{
if (bot->InBattleground())
{
if (bot->GetBattleground() && bot->GetBattleground()->GetStatus() == STATUS_WAIT_JOIN)
return true;
}
return false;
}
bool BgActiveTrigger::IsActive()
{
if (bot->InBattleground())
{
if (bot->GetBattleground() && bot->GetBattleground()->GetStatus() == STATUS_IN_PROGRESS)
return true;
}
return false;
}
bool BgInviteActiveTrigger::IsActive()
{
if (bot->InBattleground() || !bot->InBattlegroundQueue())
{
return false;
}
for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
{
BattlegroundQueueTypeId queueTypeId = bot->GetBattlegroundQueueTypeId(i);
if (queueTypeId == BATTLEGROUND_QUEUE_NONE)
continue;
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(queueTypeId);
GroupQueueInfo ginfo;
if (bgQueue.GetPlayerGroupInfoData(bot->GetGUID(), &ginfo))
{
if (ginfo.IsInvitedToBGInstanceGUID && ginfo.RemoveInviteTime)
{
LOG_INFO("playerbots", "Bot {} <{}> ({} {}) : Invited to BG but not in BG",
bot->GetGUID().ToString().c_str(), bot->GetName(), bot->GetLevel(),
bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H");
return true;
}
}
}
return false;
}
bool InsideBGTrigger::IsActive() { return bot->InBattleground() && bot->GetBattleground(); }
bool PlayerIsInBattlegroundWithoutFlag::IsActive()
{
if (botAI->GetBot()->InBattleground())
{
if (botAI->GetBot()->GetBattlegroundTypeId() == BattlegroundTypeId::BATTLEGROUND_WS)
{
BattlegroundWS* bg = (BattlegroundWS*)botAI->GetBot()->GetBattleground();
if (!(bg->GetFlagState(bg->GetOtherTeamId(bot->GetTeamId())) == BG_WS_FLAG_STATE_ON_PLAYER))
return true;
if (bot->GetGUID() == bg->GetFlagPickerGUID(TEAM_ALLIANCE) ||
bot->GetGUID() == bg->GetFlagPickerGUID(TEAM_ALLIANCE))
{
return false;
}
}
return true;
}
return false;
}
bool PlayerHasFlag::IsActive()
{
return IsCapturingFlag(bot);
}
bool PlayerHasFlag::IsCapturingFlag(Player* bot)
{
if (bot->InBattleground())
{
if (bot->GetBattlegroundTypeId() == BATTLEGROUND_WS)
{
BattlegroundWS* bg = (BattlegroundWS*)bot->GetBattleground();
// bot is horde and has ally flag
if (bot->GetGUID() == bg->GetFlagPickerGUID(TEAM_ALLIANCE))
{
if (bg->GetFlagPickerGUID(TEAM_HORDE)) // enemy has flag too
{
if (GameObject* go = bg->GetBGObject(BG_WS_OBJECT_H_FLAG))
{
// only indicate capturing if signicant distance from own flag
// (otherwise allow bot to defend itself)
return bot->GetDistance(go) > 36.0f;
}
}
return true; // enemy doesnt have flag so we can cap immediately
}
// bot is ally and has horde flag
if (bot->GetGUID() == bg->GetFlagPickerGUID(TEAM_HORDE))
{
if (bg->GetFlagPickerGUID(TEAM_ALLIANCE)) // enemy has flag too
{
if (GameObject* go = bg->GetBGObject(BG_WS_OBJECT_A_FLAG))
{
// only indicate capturing if signicant distance from own flag
// (otherwise allow bot to defend itself)
return bot->GetDistance(go) > 36.0f;
}
}
return true; // enemy doesnt have flag so we can cap immediately
}
return false; // bot doesn't have flag
}
if (bot->GetBattlegroundTypeId() == BATTLEGROUND_EY)
{
BattlegroundEY* bg = (BattlegroundEY*)bot->GetBattleground();
// Check if bot has the flag
if (bot->GetGUID() == bg->GetFlagPickerGUID())
{
// Count how many bases the bot's team owns
uint32 controlledBases = 0;
for (uint8 point = 0; point < EY_POINTS_MAX; ++point)
{
if (bg->GetCapturePointInfo(point)._ownerTeamId == bot->GetTeamId())
controlledBases++;
}
// If no bases are controlled, bot should go aggressive
if (controlledBases == 0)
return false; // bot has flag but no place to take it
// Otherwise, return false and stay defensive / move to base
return bot->GetGUID() == bg->GetFlagPickerGUID();
}
}
return false;
}
return false;
}
bool TeamHasFlag::IsActive()
{
if (!botAI->GetBot()->InBattleground())
return false;
if (botAI->GetBot()->GetBattlegroundTypeId() != BattlegroundTypeId::BATTLEGROUND_WS)
return false;
BattlegroundWS* bg = (BattlegroundWS*)botAI->GetBot()->GetBattleground();
ObjectGuid botGuid = bot->GetGUID();
TeamId teamId = bot->GetTeamId();
TeamId enemyTeamId = bg->GetOtherTeamId(teamId);
// If the bot is carrying any flag, don't activate
if (botGuid == bg->GetFlagPickerGUID(TEAM_ALLIANCE) || botGuid == bg->GetFlagPickerGUID(TEAM_HORDE))
return false;
// Check: Own team has enemy flag, enemy team does NOT have your flag
bool ownTeamHasFlag = bg->GetFlagState(enemyTeamId) == BG_WS_FLAG_STATE_ON_PLAYER;
bool enemyTeamHasFlag = bg->GetFlagState(teamId) == BG_WS_FLAG_STATE_ON_PLAYER;
return ownTeamHasFlag && !enemyTeamHasFlag;
}
bool EnemyTeamHasFlag::IsActive()
{
if (botAI->GetBot()->InBattleground())
{
if (botAI->GetBot()->GetBattlegroundTypeId() == BattlegroundTypeId::BATTLEGROUND_WS)
{
BattlegroundWS* bg = (BattlegroundWS*)botAI->GetBot()->GetBattleground();
if (bot->GetTeamId() == TEAM_HORDE)
{
if (!bg->GetFlagPickerGUID(TEAM_HORDE).IsEmpty())
return true;
}
else
{
if (!bg->GetFlagPickerGUID(TEAM_ALLIANCE).IsEmpty())
return true;
}
}
return false;
}
return false;
}
bool EnemyFlagCarrierNear::IsActive()
{
Unit* carrier = AI_VALUE(Unit*, "enemy flag carrier");
if (!carrier || !sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, carrier), 100.f))
return false;
// Check if there is another enemy player target closer than the FC
Unit* nearbyEnemy = AI_VALUE(Unit*, "enemy player target");
if (nearbyEnemy)
{
float distToFC = sServerFacade->GetDistance2d(bot, carrier);
float distToEnemy = sServerFacade->GetDistance2d(bot, nearbyEnemy);
// If the other enemy is significantly closer, don't pursue FC
if (distToEnemy + 15.0f < distToFC) // Add small buffer
return false;
}
return true;
}
bool TeamFlagCarrierNear::IsActive()
{
if (bot->GetBattlegroundTypeId() == BATTLEGROUND_WS)
{
BattlegroundWS* bg = dynamic_cast<BattlegroundWS*>(bot->GetBattleground());
if (bg)
{
bool bothFlagsNotAtBase =
bg->GetFlagState(TEAM_ALLIANCE) != BG_WS_FLAG_STATE_ON_BASE &&
bg->GetFlagState(TEAM_HORDE) != BG_WS_FLAG_STATE_ON_BASE;
if (bothFlagsNotAtBase)
return false;
}
}
Unit* carrier = AI_VALUE(Unit*, "team flag carrier");
return carrier && sServerFacade->IsDistanceLessOrEqualThan(sServerFacade->GetDistance2d(bot, carrier), 200.f);
}
bool PlayerWantsInBattlegroundTrigger::IsActive()
{
if (bot->InBattleground())
return false;
if (bot->GetBattleground() && bot->GetBattleground()->GetStatus() == STATUS_WAIT_JOIN)
return false;
if (bot->GetBattleground() && bot->GetBattleground()->GetStatus() == STATUS_IN_PROGRESS)
return false;
if (!bot->CanJoinToBattleground())
return false;
return true;
}
bool VehicleNearTrigger::IsActive()
{
GuidVector npcs = AI_VALUE(GuidVector, "nearest vehicles");
return npcs.size();
}
bool InVehicleTrigger::IsActive() { return botAI->IsInVehicle(); }
bool AllianceNoSnowfallGY::IsActive()
{
if (!bot || bot->GetTeamId() != TEAM_ALLIANCE)
return false;
Battleground* bg = bot->GetBattleground();
if (bg && BGTactics::GetBotStrategyForTeam(bg, TEAM_ALLIANCE) != AV_STRATEGY_BALANCED)
return false;
float botX = bot->GetPositionX();
if (botX <= -562.0f)
return false;
if (bot->GetBattlegroundTypeId() != BATTLEGROUND_AV)
return false;
if (BattlegroundAV* av = dynamic_cast<BattlegroundAV*>(bg))
{
const BG_AV_NodeInfo& snowfall = av->GetAVNodeInfo(BG_AV_NODES_SNOWFALL_GRAVE);
return snowfall.OwnerId != TEAM_ALLIANCE; // Active if the Snowfall Graveyard is NOT fully controlled by the Alliance
}
return false;
}

View File

@@ -0,0 +1,151 @@
/*
* 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_PVPTRIGGERS_H
#define _PLAYERBOT_PVPTRIGGERS_H
#include "Trigger.h"
class PlayerbotAI;
class EnemyPlayerNear : public Trigger
{
public:
EnemyPlayerNear(PlayerbotAI* botAI) : Trigger(botAI, "enemy player near", 3) {}
bool IsActive() override;
};
class PlayerHasNoFlag : public Trigger
{
public:
PlayerHasNoFlag(PlayerbotAI* botAI) : Trigger(botAI, "player has no flag") {}
bool IsActive() override;
};
// NOTE this trigger is only active when bot is actively returning flag
// (not when hiding in base because enemy has flag too)
class PlayerHasFlag : public Trigger
{
public:
PlayerHasFlag(PlayerbotAI* botAI) : Trigger(botAI, "player has flag") {}
bool IsActive() override;
static bool IsCapturingFlag(Player* bot);
};
class EnemyFlagCarrierNear : public Trigger
{
public:
EnemyFlagCarrierNear(PlayerbotAI* botAI) : Trigger(botAI, "enemy flagcarrier near") {}
bool IsActive() override;
};
class TeamFlagCarrierNear : public Trigger
{
public:
TeamFlagCarrierNear(PlayerbotAI* botAI) : Trigger(botAI, "team flagcarrier near") {}
bool IsActive() override;
};
class TeamHasFlag : public Trigger
{
public:
TeamHasFlag(PlayerbotAI* botAI) : Trigger(botAI, "team has flag") {}
bool IsActive() override;
};
class EnemyTeamHasFlag : public Trigger
{
public:
EnemyTeamHasFlag(PlayerbotAI* botAI) : Trigger(botAI, "enemy team has flag") {}
bool IsActive() override;
};
class PlayerIsInBattleground : public Trigger
{
public:
PlayerIsInBattleground(PlayerbotAI* botAI) : Trigger(botAI, "in Battleground") {}
bool IsActive() override;
};
class BgWaitingTrigger : public Trigger
{
public:
BgWaitingTrigger(PlayerbotAI* botAI) : Trigger(botAI, "bg waiting", 30) {}
bool IsActive() override;
};
class BgActiveTrigger : public Trigger
{
public:
BgActiveTrigger(PlayerbotAI* botAI) : Trigger(botAI, "bg active", 1) {}
bool IsActive() override;
};
class BgInviteActiveTrigger : public Trigger
{
public:
BgInviteActiveTrigger(PlayerbotAI* botAI) : Trigger(botAI, "bg invite active", 10) {}
bool IsActive() override;
};
class InsideBGTrigger : public Trigger
{
public:
InsideBGTrigger(PlayerbotAI* botAI) : Trigger(botAI, "inside bg", 1) {}
bool IsActive() override;
};
class PlayerIsInBattlegroundWithoutFlag : public Trigger
{
public:
PlayerIsInBattlegroundWithoutFlag(PlayerbotAI* botAI) : Trigger(botAI, "in Battleground without flag") {}
bool IsActive() override;
};
class PlayerWantsInBattlegroundTrigger : public Trigger
{
public:
PlayerWantsInBattlegroundTrigger(PlayerbotAI* botAI) : Trigger(botAI, "wants in bg") {}
bool IsActive() override;
};
class VehicleNearTrigger : public Trigger
{
public:
VehicleNearTrigger(PlayerbotAI* botAI) : Trigger(botAI, "vehicle near", 10) {}
bool IsActive() override;
};
class InVehicleTrigger : public Trigger
{
public:
InVehicleTrigger(PlayerbotAI* botAI) : Trigger(botAI, "in vehicle") {}
bool IsActive() override;
};
class AllianceNoSnowfallGY : public Trigger
{
public:
AllianceNoSnowfallGY(PlayerbotAI* botAI) : Trigger(botAI, "alliance no snowfall gy") {}
bool IsActive() override;
};
#endif

View File

@@ -0,0 +1,298 @@
/*
* 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 "RangeTriggers.h"
#include "MoveSplineInit.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "SharedDefines.h"
static float GetSpeedInMotion(Unit* target)
{
return target->GetSpeed(Movement::SelectSpeedType(target->GetUnitMovementFlags()));
}
bool EnemyTooCloseForSpellTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
return target && (target->GetVictim() != bot || target->isFrozen() || target->HasRootAura()) &&
target->GetObjectSize() <= 10.0f && target->IsWithinCombatRange(bot, MIN_MELEE_REACH);
// Unit* target = AI_VALUE(Unit*, "current target");
// if (!target)
// {
// return false;
// }
// if (target->GetTarget() == bot->GetGUID() && !bot->GetGroup() && !target->HasUnitState(UNIT_STATE_ROOT) &&
// GetSpeedInMotion(target) > GetSpeedInMotion(bot) * 0.65f)
// return false;
// bool isBoss = false;
// bool isRaid = false;
// float combatReach = bot->GetCombatReach() + target->GetCombatReach();
// float targetDistance = sServerFacade->GetDistance2d(bot, target) + combatReach;
// if (target->IsCreature())
// {
// Creature* creature = botAI->GetCreature(target->GetGUID());
// if (creature)
// {
// isBoss = creature->isWorldBoss();
// }
// }
// if (bot->GetMap() && bot->GetMap()->IsRaid())
// isRaid = true;
// // if (isBoss || isRaid)
// // return sServerFacade->IsDistanceLessThan(targetDistance, (sPlayerbotAIConfig->tooCloseDistance +
// combatReach) / 2);
// return sServerFacade->IsDistanceLessOrEqualThan(targetDistance, (sPlayerbotAIConfig->tooCloseDistance +
// combatReach / 2));
}
bool EnemyTooCloseForAutoShotTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target)
return false;
// hunter move away after casting immolation/explosive trap
bool trapToCast = bot->getClass() == CLASS_HUNTER;
uint32 spellId = AI_VALUE2(uint32, "spell id", "immolation trap");
if (!spellId)
trapToCast = false;
if (spellId && bot->HasSpellCooldown(spellId))
trapToCast = false;
return !trapToCast && (target->GetVictim() != bot || target->isFrozen() || target->HasRootAura()) &&
bot->IsWithinMeleeRange(target);
// if (target->GetTarget() == bot->GetGUID() && !bot->GetGroup() && !target->HasUnitState(UNIT_STATE_ROOT) &&
// GetSpeedInMotion(target) > GetSpeedInMotion(bot) * 0.65f)
// return false;
// bool isBoss = false;
// bool isRaid = false;
// float combatReach = bot->GetCombatReach() + target->GetCombatReach();
// float targetDistance = sServerFacade->GetDistance2d(bot, target) + combatReach;
// if (target->IsCreature())
// {
// Creature* creature = botAI->GetCreature(target->GetGUID());
// if (creature)
// {
// isBoss = creature->isWorldBoss();
// }
// }
// if (bot->GetMap() && bot->GetMap()->IsRaid())
// isRaid = true;
// return sServerFacade->IsDistanceLessOrEqualThan(targetDistance, 5.0f);
}
bool EnemyTooCloseForShootTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
// target->IsWithinCombatRange()
return target && (target->GetVictim() != bot || target->isFrozen() || target->HasRootAura()) &&
target->IsWithinCombatRange(bot, MIN_MELEE_REACH);
// Unit* target = AI_VALUE(Unit*, "current target");
// if (!target)
// return false;
// if (target->GetTarget() == bot->GetGUID() && !bot->GetGroup() && !target->HasUnitState(UNIT_STATE_ROOT) &&
// GetSpeedInMotion(target) > GetSpeedInMotion(bot) * 0.65f)
// return false;
// bool isBoss = false;
// bool isRaid = false;
// float combatReach = bot->GetCombatReach() + target->GetCombatReach();
// float targetDistance = sServerFacade->GetDistance2d(bot, target) + combatReach;
// if (target->IsCreature())
// {
// Creature* creature = botAI->GetCreature(target->GetGUID());
// if (creature)
// {
// isBoss = creature->isWorldBoss();
// }
// }
// if (bot->GetMap() && bot->GetMap()->IsRaid())
// isRaid = true;
// // if (isBoss || isRaid)
// // return sServerFacade->IsDistanceLessThan(targetDistance, botAI->GetRange("shoot") + combatReach);
// return sServerFacade->IsDistanceLessOrEqualThan(targetDistance, (botAI->GetRange("shoot") + combatReach /
// 2));
}
bool EnemyTooCloseForMeleeTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
if (target && target->IsPlayer())
return false;
return target && AI_VALUE2(bool, "inside target", "current target");
}
bool EnemyIsCloseTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
return target && sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"),
sPlayerbotAIConfig->tooCloseDistance);
}
bool EnemyWithinMeleeTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
return target && bot->IsWithinMeleeRange(target);
}
bool OutOfRangeTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, GetTargetName());
// increase contact distance to prevent calculation error
float dis = distance + CONTACT_DISTANCE;
return target &&
!bot->IsWithinCombatRange(
target,
dis); // sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", GetTargetName()), distance);
}
EnemyOutOfSpellRangeTrigger::EnemyOutOfSpellRangeTrigger(PlayerbotAI* botAI)
: OutOfRangeTrigger(botAI, "enemy out of spell range", botAI->GetRange("spell"))
{
}
// bool EnemyOutOfSpellRangeTrigger::IsActive()
// {
// Unit* target = AI_VALUE(Unit*, GetTargetName());
// if (!target)
// return false;
// float combatReach = bot->GetCombatReach() + target->GetCombatReach();
// return target && (sServerFacade->GetDistance2d(bot, target) > (distance + combatReach +
// sPlayerbotAIConfig->contactDistance) || !bot->IsWithinLOSInMap(target));
// }
// bool EnemyOutOfMeleeTrigger::IsActive()
// {
// Unit* target = AI_VALUE(Unit*, GetTargetName());
// if (!target)
// return false;
// float targetDistance = sServerFacade->GetDistance2d(bot, target);
// return target && (targetDistance > std::max(5.0f, bot->GetCombatReach() + target->GetCombatReach()) ||
// (!bot->IsWithinLOSInMap(target) && targetDistance > 5.0f));
// }
bool PartyMemberToHealOutOfSpellRangeTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, GetTargetName());
if (!target)
return false;
float combatReach = bot->GetCombatReach() + target->GetCombatReach();
return target && (sServerFacade->GetDistance2d(bot, target) > (distance + sPlayerbotAIConfig->contactDistance) ||
!bot->IsWithinLOSInMap(target));
}
PartyMemberToHealOutOfSpellRangeTrigger::PartyMemberToHealOutOfSpellRangeTrigger(PlayerbotAI* botAI)
: OutOfRangeTrigger(botAI, "party member to heal out of spell range", botAI->GetRange("heal") + 1.0f)
{
}
bool FarFromMasterTrigger::IsActive()
{
return sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "group leader"), distance);
}
bool TooCloseToCreatureTrigger::TooCloseToCreature(uint32 creatureId, float range, bool alive)
{
Creature* nearestCreature = bot->FindNearestCreature(creatureId, range, alive);
return nearestCreature != nullptr;
}
bool TooCloseToPlayerWithDebuffTrigger::TooCloseToPlayerWithDebuff(uint32 spellId, float range)
{
Group* group = bot->GetGroup();
if (!group)
{
return false;
}
std::vector<Player*> debuffedPlayers;
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* player = gref->GetSource();
if (player && player->IsAlive() && player->HasAura(spellId))
{
debuffedPlayers.push_back(player);
}
}
if (debuffedPlayers.empty())
{
return false;
}
for (Unit* debuffedPlayer : debuffedPlayers)
{
float dist = debuffedPlayer->GetExactDist2d(bot->GetPositionX(), bot->GetPositionY());
if (dist < range)
{
return true;
}
}
return false;
}
bool TooFarFromPlayerWithAuraTrigger::TooFarFromPlayerWithAura(uint32 spellId, float range, bool selfInclude)
{
Group* group = bot->GetGroup();
if (!group)
{
return false;
}
std::vector<Player*> debuffedPlayers;
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* player = gref->GetSource();
if (player && player->IsAlive() && player->HasAura(spellId) &&
(selfInclude || (!selfInclude && player->GetGUID() != bot->GetGUID())))
{
debuffedPlayers.push_back(player);
}
}
return !debuffedPlayers.empty();
if (debuffedPlayers.empty())
{
return false;
}
for (Unit* debuffedPlayer : debuffedPlayers)
{
float dist = debuffedPlayer->GetExactDist2d(bot->GetPositionX(), bot->GetPositionY());
if (dist > range)
{
return true;
}
}
return false;
}

View File

@@ -0,0 +1,148 @@
/*
* 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_RANGETRIGGERS_H
#define _PLAYERBOT_RANGETRIGGERS_H
#include "PlayerbotAIConfig.h"
#include "Trigger.h"
class PlayerbotAI;
class EnemyTooCloseForSpellTrigger : public Trigger
{
public:
EnemyTooCloseForSpellTrigger(PlayerbotAI* botAI) : Trigger(botAI, "enemy too close for spell") {}
bool IsActive() override;
};
class EnemyTooCloseForShootTrigger : public Trigger
{
public:
EnemyTooCloseForShootTrigger(PlayerbotAI* botAI) : Trigger(botAI, "enemy too close for shoot") {}
bool IsActive() override;
};
class EnemyTooCloseForAutoShotTrigger : public Trigger
{
public:
EnemyTooCloseForAutoShotTrigger(PlayerbotAI* botAI) : Trigger(botAI, "enemy too close for auto shot") {}
bool IsActive() override;
};
class EnemyTooCloseForMeleeTrigger : public Trigger
{
public:
EnemyTooCloseForMeleeTrigger(PlayerbotAI* botAI) : Trigger(botAI, "enemy too close for melee", 5) {}
bool IsActive() override;
};
class EnemyIsCloseTrigger : public Trigger
{
public:
EnemyIsCloseTrigger(PlayerbotAI* botAI) : Trigger(botAI, "enemy is close") {}
bool IsActive() override;
};
class EnemyWithinMeleeTrigger : public Trigger
{
public:
EnemyWithinMeleeTrigger(PlayerbotAI* botAI) : Trigger(botAI, "enemy within melee") {}
bool IsActive() override;
};
class OutOfRangeTrigger : public Trigger
{
public:
OutOfRangeTrigger(PlayerbotAI* botAI, std::string const name, float distance)
: Trigger(botAI, name), distance(distance)
{
}
bool IsActive() override;
std::string const GetTargetName() override { return "current target"; }
protected:
float distance;
};
class EnemyOutOfMeleeTrigger : public OutOfRangeTrigger
{
public:
EnemyOutOfMeleeTrigger(PlayerbotAI* botAI)
: OutOfRangeTrigger(botAI, "enemy out of melee range", sPlayerbotAIConfig->meleeDistance)
{
}
// bool IsActive() override;
};
class EnemyOutOfSpellRangeTrigger : public OutOfRangeTrigger
{
public:
EnemyOutOfSpellRangeTrigger(PlayerbotAI* botAI);
};
class PartyMemberToHealOutOfSpellRangeTrigger : public OutOfRangeTrigger
{
public:
PartyMemberToHealOutOfSpellRangeTrigger(PlayerbotAI* botAI);
bool IsActive() override;
std::string const GetTargetName() override { return "party member to heal"; }
};
class FarFromMasterTrigger : public Trigger
{
public:
FarFromMasterTrigger(PlayerbotAI* botAI, std::string const name = "far from master", float distance = 12.0f,
int32 checkInterval = 50)
: Trigger(botAI, name, checkInterval), distance(distance)
{
}
bool IsActive() override;
private:
float distance;
};
class OutOfReactRangeTrigger : public FarFromMasterTrigger
{
public:
OutOfReactRangeTrigger(PlayerbotAI* botAI) : FarFromMasterTrigger(botAI, "out of react range", 50.0f, 5) {}
};
class TooCloseToCreatureTrigger : public Trigger
{
public:
TooCloseToCreatureTrigger(PlayerbotAI* ai) : Trigger(ai, "too close to creature trigger") {}
bool TooCloseToCreature(uint32 creatureId, float range, bool alive = true);
};
class TooCloseToPlayerWithDebuffTrigger : public Trigger
{
public:
TooCloseToPlayerWithDebuffTrigger(PlayerbotAI* ai) : Trigger(ai, "too cloose to player with debuff trigger") {}
bool TooCloseToPlayerWithDebuff(uint32 spellId, float range);
};
class TooFarFromPlayerWithAuraTrigger : public Trigger
{
public:
TooFarFromPlayerWithAuraTrigger(PlayerbotAI* ai) : Trigger(ai, "too far from player with aura trigger") {}
bool TooFarFromPlayerWithAura(uint32 spellId, float range, bool selfInclude = false);
};
#endif

View File

@@ -0,0 +1,431 @@
/*
* 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 "RpgTriggers.h"
#include "BudgetValues.h"
#include "GuildCreateActions.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "SocialMgr.h"
bool NoRpgTargetTrigger::IsActive() { return !AI_VALUE(GuidPosition, "rpg target"); }
bool HasRpgTargetTrigger::IsActive() { return !NoRpgTargetTrigger::IsActive(); }
bool FarFromRpgTargetTrigger::IsActive()
{
return !NoRpgTargetTrigger::IsActive() && AI_VALUE2(float, "distance", "rpg target") > INTERACTION_DISTANCE;
}
bool NearRpgTargetTrigger::IsActive()
{
return !NoRpgTargetTrigger::IsActive() && !FarFromRpgTargetTrigger::IsActive();
}
GuidPosition RpgTrigger::getGuidP() { return AI_VALUE(GuidPosition, "rpg target"); }
bool RpgTrigger::IsActive() { return true; }
Event RpgTrigger::Check()
{
if (!NoRpgTargetTrigger::IsActive() && (AI_VALUE(std::string, "next rpg action") == "choose rpg target") ||
!FarFromRpgTargetTrigger::IsActive())
return Trigger::Check();
return Event();
}
bool RpgTaxiTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.HasNpcFlag(UNIT_NPC_FLAG_FLIGHTMASTER))
return false;
uint32 node =
sObjectMgr->GetNearestTaxiNode(guidP.getX(), guidP.getY(), guidP.getZ(), guidP.getMapId(), bot->GetTeamId());
if (!node)
return false;
if (!bot->m_taxi.IsTaximaskNodeKnown(node))
return false;
return true;
}
bool RpgDiscoverTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.HasNpcFlag(UNIT_NPC_FLAG_FLIGHTMASTER))
return false;
if (bot->isTaxiCheater())
return false;
uint32 node =
sObjectMgr->GetNearestTaxiNode(guidP.getX(), guidP.getY(), guidP.getZ(), guidP.getMapId(), bot->GetTeamId());
if (bot->m_taxi.IsTaximaskNodeKnown(node))
return false;
return true;
}
bool RpgStartQuestTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.IsCreature() && !guidP.IsGameObject())
return false;
if (AI_VALUE(bool, "can fight equal"))
{
if (AI_VALUE2(bool, "can accept quest npc", guidP.GetEntry()))
return true;
}
else
{
if (AI_VALUE2(bool, "can accept quest low level npc", guidP.GetEntry()))
return true;
}
return false;
}
bool RpgEndQuestTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.IsCreature() && !guidP.IsGameObject())
return false;
if (AI_VALUE2(bool, "can turn in quest npc", guidP.GetEntry()))
return true;
if (!AI_VALUE2(bool, "can accept quest low level npc", guidP.GetEntry()))
return false;
if (guidP.GetEntry() == AI_VALUE(TravelTarget*, "travel target")->getEntry())
return true;
return false;
}
bool RpgBuyTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.HasNpcFlag(UNIT_NPC_FLAG_VENDOR))
return false;
if (AI_VALUE(uint8, "durability") > 50)
return false;
if (!AI_VALUE(bool, "can sell")) // Need better condition.
return false;
return true;
}
bool RpgSellTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.HasNpcFlag(UNIT_NPC_FLAG_VENDOR))
return false;
if (!AI_VALUE(bool, "can sell"))
return false;
return true;
}
bool RpgRepairTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.HasNpcFlag(UNIT_NPC_FLAG_REPAIR))
return false;
if (AI_VALUE2_LAZY(bool, "group or", "should sell,can sell,following party,near leader"))
return true;
if (AI_VALUE2_LAZY(bool, "group or", "should repair,can repair,following party,near leader"))
return true;
return false;
}
bool RpgTrainTrigger::IsTrainerOf(CreatureTemplate const* cInfo, Player* pPlayer)
{
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(cInfo->Entry);
if (trainer->GetTrainerType() == Trainer::Type::Mount && trainer->GetTrainerRequirement() != pPlayer->getRace())
{
if (FactionTemplateEntry const* faction_template = sFactionTemplateStore.LookupEntry(cInfo->faction))
if (pPlayer->GetReputationRank(faction_template->faction) == REP_EXALTED)
return true;
return false;
}
return trainer->IsTrainerValidForPlayer(pPlayer);
}
bool RpgTrainTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.HasNpcFlag(UNIT_NPC_FLAG_TRAINER))
return false;
CreatureTemplate const* cInfo = guidP.GetCreatureTemplate();
if (!IsTrainerOf(cInfo, bot))
return false;
Trainer::Trainer* trainer = sObjectMgr->GetTrainer(cInfo->Entry);
FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction);
float fDiscountMod = bot->GetReputationPriceDiscount(factionTemplate);
for (auto& spell : trainer->GetSpells())
{
if (!trainer->CanTeachSpell(bot, trainer->GetSpell(spell.SpellId)))
continue;
uint32 cost = uint32(floor(spell.MoneyCost * fDiscountMod));
if (cost > AI_VALUE2(uint32, "free money for", (uint32)NeedMoneyFor::spells))
continue;
return true;
}
return false;
}
bool RpgHealTrigger::IsActive()
{
if (!botAI->HasStrategy("heal", BOT_STATE_COMBAT))
return false;
GuidPosition guidP(getGuidP());
Unit* unit = guidP.GetUnit();
if (!unit)
return false;
if (!unit->IsFriendlyTo(bot))
return false;
if (unit->isDead() || unit->GetHealthPct() >= 100)
return false;
return true;
}
bool RpgHomeBindTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.HasNpcFlag(UNIT_NPC_FLAG_INNKEEPER))
return false;
if (AI_VALUE(WorldPosition, "home bind").distance(bot) < 500.0f)
return false;
return true;
}
bool RpgQueueBGTrigger::IsActive()
{
// skip bots not in continents
if (!WorldPosition(bot).isOverworld()) // bg, raid, dungeon
return false;
GuidPosition guidP(getGuidP());
if (!guidP.IsCreature())
return false;
// if bot is not leader disallow tag bg
if (bot->GetGroup() && !bot->GetGroup()->IsLeader(bot->GetGUID()))
return false;
if (AI_VALUE(BattlegroundTypeId, "rpg bg type") == BATTLEGROUND_TYPE_NONE)
return false;
return true;
}
bool RpgBuyPetitionTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.HasNpcFlag(UNIT_NPC_FLAG_PETITIONER))
return false;
if (!BuyPetitionAction::canBuyPetition(bot))
return false;
return true;
}
bool RpgUseTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.IsGameObject())
return false;
GameObjectTemplate const* goInfo = guidP.GetGameObjectTemplate();
switch (goInfo->type)
{
case GAMEOBJECT_TYPE_BINDER:
case GAMEOBJECT_TYPE_GENERIC:
case GAMEOBJECT_TYPE_TEXT:
case GAMEOBJECT_TYPE_GOOBER:
case GAMEOBJECT_TYPE_TRANSPORT:
case GAMEOBJECT_TYPE_AREADAMAGE:
case GAMEOBJECT_TYPE_CAMERA:
case GAMEOBJECT_TYPE_MAP_OBJECT:
case GAMEOBJECT_TYPE_MO_TRANSPORT:
case GAMEOBJECT_TYPE_DUEL_ARBITER:
case GAMEOBJECT_TYPE_FISHINGNODE:
case GAMEOBJECT_TYPE_GUARDPOST:
case GAMEOBJECT_TYPE_SPELLCASTER:
case GAMEOBJECT_TYPE_FISHINGHOLE:
case GAMEOBJECT_TYPE_AURA_GENERATOR:
return false;
default:
break;
}
return true;
}
bool RpgSpellTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (guidP.IsPlayer())
return false;
if (!guidP.GetWorldObject())
return false;
return true;
}
bool RpgCraftTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (guidP.IsPlayer())
return false;
if (!guidP.GetWorldObject())
return false;
return true;
}
bool RpgTradeUsefulTrigger::IsActive()
{
GuidPosition guidP(getGuidP());
if (!guidP.IsPlayer())
return false;
Player* player = guidP.GetPlayer();
if (!player)
return false;
// More code/botAI-value here to see if bot is friendly enough.
bool isFriend = false;
if (player->GetGuildId() != bot->GetGuildId())
isFriend = true;
if (bot->GetGroup() == player->GetGroup() && !urand(0, 5))
isFriend = true;
if (!urand(0, 20))
isFriend = true;
if (!isFriend)
return false;
if (!player->IsWithinLOSInMap(bot))
return false;
if (player->GetTrader() && player->GetTrader() != bot)
return false;
if (bot->GetTrader() && bot->GetTrader() != player)
return false;
if (AI_VALUE(std::vector<Item*>, "items useful to give").empty())
return false;
return true;
}
bool RpgDuelTrigger::IsActive()
{
if (!botAI->HasStrategy("start duel", BOT_STATE_NON_COMBAT))
return false;
// Less spammy duels
if (bot->GetLevel() < 3)
return false;
if (botAI->HasRealPlayerMaster())
{
// do not auto duel if master is not afk
if (botAI->GetMaster() && !botAI->GetMaster()->isAFK())
return false;
}
// do not auto duel with low hp
if (AI_VALUE2(uint8, "health", "self target") < 90)
return false;
GuidPosition guidP(getGuidP());
if (!guidP.IsPlayer())
return false;
Player* player = guidP.GetPlayer();
if (!player)
return false;
if (player->GetLevel() > bot->GetLevel() + 3)
return false;
if (bot->GetLevel() > player->GetLevel() + 10)
return false;
// caster or target already have requested duel
if (bot->duel || player->duel || !player->GetSocial() || player->GetSocial()->HasIgnore(bot->GetGUID()))
return false;
AreaTableEntry const* targetAreaEntry = sAreaTableStore.LookupEntry(player->GetAreaId());
if (targetAreaEntry && !(targetAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))
{
// Dueling isn't allowed here
return false;
}
if (!AI_VALUE(GuidVector, "all targets").empty())
return false;
return true;
}

View File

@@ -0,0 +1,214 @@
/*
* 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_RPGTRIGGERS_H
#define _PLAYERBOT_RPGTRIGGERS_H
#include "Trigger.h"
class Event;
class GuidPosition;
class PlayerbotAI;
struct CreatureTemplate;
class NoRpgTargetTrigger : public Trigger
{
public:
NoRpgTargetTrigger(PlayerbotAI* botAI, std::string const name = "no rpg target", int checkInterval = 1)
: Trigger(botAI, name, checkInterval)
{
}
bool IsActive() override;
};
class HasRpgTargetTrigger : public NoRpgTargetTrigger
{
public:
HasRpgTargetTrigger(PlayerbotAI* botAI, std::string const name = "has rpg target", int checkInterval = 1)
: NoRpgTargetTrigger(botAI, name, checkInterval)
{
}
bool IsActive() override;
};
class FarFromRpgTargetTrigger : public NoRpgTargetTrigger
{
public:
FarFromRpgTargetTrigger(PlayerbotAI* botAI, std::string const name = "far from rpg target", int checkInterval = 1)
: NoRpgTargetTrigger(botAI, name, checkInterval)
{
}
bool IsActive() override;
};
class NearRpgTargetTrigger : public FarFromRpgTargetTrigger
{
public:
NearRpgTargetTrigger(PlayerbotAI* botAI, std::string const name = "near rpg target", int checkInterval = 1)
: FarFromRpgTargetTrigger(botAI, name, checkInterval)
{
}
bool IsActive() override;
};
// Sub actions:
class RpgTrigger : public FarFromRpgTargetTrigger
{
public:
RpgTrigger(PlayerbotAI* botAI, std::string const name = "sub rpg", int checkInterval = 2)
: FarFromRpgTargetTrigger(botAI, name, checkInterval)
{
}
GuidPosition getGuidP();
bool IsActive() override;
Event Check() override;
};
class RpgTaxiTrigger : public RpgTrigger
{
public:
RpgTaxiTrigger(PlayerbotAI* botAI, std::string const name = "rpg taxi") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgDiscoverTrigger : public RpgTrigger
{
public:
RpgDiscoverTrigger(PlayerbotAI* botAI, std::string const name = "rpg discover") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgStartQuestTrigger : public RpgTrigger
{
public:
RpgStartQuestTrigger(PlayerbotAI* botAI, std::string const name = "rpg start quest") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgEndQuestTrigger : public RpgTrigger
{
public:
RpgEndQuestTrigger(PlayerbotAI* botAI, std::string const name = "rpg end quest") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgBuyTrigger : public RpgTrigger
{
public:
RpgBuyTrigger(PlayerbotAI* botAI, std::string const name = "rpg buy") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgSellTrigger : public RpgTrigger
{
public:
RpgSellTrigger(PlayerbotAI* botAI, std::string const name = "rpg sell") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgRepairTrigger : public RpgTrigger
{
public:
RpgRepairTrigger(PlayerbotAI* botAI, std::string const name = "rpg repair") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgTrainTrigger : public RpgTrigger
{
public:
RpgTrainTrigger(PlayerbotAI* botAI, std::string const name = "rpg train") : RpgTrigger(botAI, name) {}
static bool IsTrainerOf(CreatureTemplate const* cInfo, Player* pPlayer);
bool IsActive() override;
};
class RpgHealTrigger : public RpgTrigger
{
public:
RpgHealTrigger(PlayerbotAI* botAI, std::string const name = "rpg heal") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgHomeBindTrigger : public RpgTrigger
{
public:
RpgHomeBindTrigger(PlayerbotAI* botAI, std::string const name = "rpg home bind") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgQueueBGTrigger : public RpgTrigger
{
public:
RpgQueueBGTrigger(PlayerbotAI* botAI, std::string const name = "rpg queue bg") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgBuyPetitionTrigger : public RpgTrigger
{
public:
RpgBuyPetitionTrigger(PlayerbotAI* botAI, std::string const name = "rpg buy petition") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgUseTrigger : public RpgTrigger
{
public:
RpgUseTrigger(PlayerbotAI* botAI, std::string const name = "rpg use") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgSpellTrigger : public RpgTrigger
{
public:
RpgSpellTrigger(PlayerbotAI* botAI, std::string const name = "rpg spell") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgCraftTrigger : public RpgTrigger
{
public:
RpgCraftTrigger(PlayerbotAI* botAI, std::string const name = "rpg craft") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgTradeUsefulTrigger : public RpgTrigger
{
public:
RpgTradeUsefulTrigger(PlayerbotAI* botAI, std::string const name = "rpg trade useful") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
class RpgDuelTrigger : public RpgTrigger
{
public:
RpgDuelTrigger(PlayerbotAI* botAI, std::string const name = "rpg duel") : RpgTrigger(botAI, name) {}
bool IsActive() override;
};
#endif

View 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.
*/
#include "RtiTriggers.h"
#include "Playerbots.h"
bool NoRtiTrigger::IsActive()
{
// Do not auto-react to raid icons while out of combat.
// Out-of-combat RTI usage (explicit chat commands) is handled by chat triggers,
// not by this generic trigger.
if (!bot->IsInCombat())
return false;
Unit* target = AI_VALUE(Unit*, "rti target");
return target != nullptr;
}

View File

@@ -0,0 +1,21 @@
/*
* 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_RTITRIGGERS_H
#define _PLAYERBOT_RTITRIGGERS_H
#include "Trigger.h"
class PlayerbotAI;
class NoRtiTrigger : public Trigger
{
public:
NoRtiTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no rti target") {}
bool IsActive() override;
};
#endif

View File

@@ -0,0 +1,199 @@
/*
* 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 "StuckTriggers.h"
#include "CellImpl.h"
#include "PathGenerator.h"
#include "Playerbots.h"
#include "MMapFactory.h"
bool MoveStuckTrigger::IsActive()
{
if (botAI->HasActivePlayerMaster())
return false;
if (!botAI->AllowActivity(ALL_ACTIVITY))
return false;
WorldPosition botPos(bot);
LogCalculatedValue<WorldPosition>* posVal =
dynamic_cast<LogCalculatedValue<WorldPosition>*>(context->GetUntypedValue("current position"));
if (posVal->LastChangeDelay() > 5 * MINUTE)
{
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in the same position for {} seconds",
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
// bot->GetName(), posVal->LastChangeDelay());
return true;
}
bool longLog = false;
for (auto tPos : posVal->ValueLog())
{
uint32 timePassed = time(0) - tPos.second;
if (timePassed > 10 * MINUTE)
{
if (botPos.fDist(tPos.first) > 50.0f)
return false;
longLog = true;
}
}
if (longLog)
{
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in the same position for 10mins",
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
// bot->GetName(), posVal->LastChangeDelay());
}
return longLog;
}
bool MoveLongStuckTrigger::IsActive()
{
if (botAI->HasActivePlayerMaster())
return false;
if (!botAI->AllowActivity(ALL_ACTIVITY))
return false;
WorldPosition botPos(bot);
Cell cell(bot->GetPositionX(), bot->GetPositionY());
GridCoord grid = botPos.getGridCoord();
if (grid.x_coord < 0 || grid.x_coord >= MAX_NUMBER_OF_GRIDS)
{
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in grid {},{} on map {}",
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
// bot->GetName(), grid.x_coord, grid.y_coord, botPos.getMapId());
return true;
}
if (grid.y_coord < 0 || grid.y_coord >= MAX_NUMBER_OF_GRIDS)
{
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in grid {},{} on map {}",
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
// bot->GetName(), grid.x_coord, grid.y_coord, botPos.getMapId());
return true;
}
if (cell.GridX() > 0 && cell.GridY() > 0 &&
!MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(botPos.getMapId(), cell.GridX(), cell.GridY()))
{
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in unloaded grid {},{} on map {}",
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
// bot->GetName(), grid.x_coord, grid.y_coord, botPos.getMapId());
return true;
}
LogCalculatedValue<WorldPosition>* posVal =
dynamic_cast<LogCalculatedValue<WorldPosition>*>(context->GetUntypedValue("current position"));
if (posVal->LastChangeDelay() > 10 * MINUTE)
{
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in the same position for {} seconds",
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
// bot->GetName(), posVal->LastChangeDelay());
return true;
}
MemoryCalculatedValue<uint32>* expVal =
dynamic_cast<MemoryCalculatedValue<uint32>*>(context->GetUntypedValue("experience"));
if (expVal->LastChangeDelay() < 15 * MINUTE)
return false;
bool longLog = false;
for (auto tPos : posVal->ValueLog())
{
uint32 timePassed = time(0) - tPos.second;
if (timePassed > 15 * MINUTE)
{
if (botPos.fDist(tPos.first) > 50.0f)
return false;
longLog = true;
}
}
if (longLog)
{
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in the same position for 15mins",
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
// bot->GetName(), posVal->LastChangeDelay());
}
return longLog;
}
bool CombatStuckTrigger::IsActive()
{
if (!bot->IsInCombat())
return false;
if (botAI->HasActivePlayerMaster())
return false;
if (!botAI->AllowActivity(ALL_ACTIVITY))
return false;
WorldPosition botPos(bot);
MemoryCalculatedValue<bool>* combatVal =
dynamic_cast<MemoryCalculatedValue<bool>*>(context->GetUntypedValue("combat::self target"));
if (combatVal->LastChangeDelay() > 5 * MINUTE)
{
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in combat for {} seconds",
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
// bot->GetName(), posVal->LastChangeDelay());
return true;
}
return false;
}
bool CombatLongStuckTrigger::IsActive()
{
if (!bot->IsInCombat())
return false;
if (botAI->HasActivePlayerMaster())
return false;
if (!botAI->AllowActivity(ALL_ACTIVITY))
return false;
WorldPosition botPos(bot);
MemoryCalculatedValue<bool>* combatVal =
dynamic_cast<MemoryCalculatedValue<bool>*>(context->GetUntypedValue("combat::self target"));
if (combatVal->LastChangeDelay() > 15 * MINUTE)
{
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> was in combat for {} seconds",
// bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(),
// bot->GetName(), posVal->LastChangeDelay());
return true;
}
return false;
}

View File

@@ -0,0 +1,43 @@
/*
* 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_STUCKTRIGGERS_H
#define _PLAYERBOT_STUCKTRIGGERS_H
#include "Trigger.h"
class MoveStuckTrigger : public Trigger
{
public:
MoveStuckTrigger(PlayerbotAI* botAI) : Trigger(botAI, "move stuck", 5) {}
bool IsActive() override;
};
class MoveLongStuckTrigger : public Trigger
{
public:
MoveLongStuckTrigger(PlayerbotAI* botAI) : Trigger(botAI, "move long stuck", 5) {}
bool IsActive() override;
};
class CombatStuckTrigger : public Trigger
{
public:
CombatStuckTrigger(PlayerbotAI* botAI) : Trigger(botAI, "combat stuck", 5) {}
bool IsActive() override;
};
class CombatLongStuckTrigger : public Trigger
{
public:
CombatLongStuckTrigger(PlayerbotAI* botAI) : Trigger(botAI, "combat long stuck", 5) {}
bool IsActive() override;
};
#endif

View File

@@ -0,0 +1,44 @@
/*
* 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 "TravelTriggers.h"
#include "Playerbots.h"
#include "ServerFacade.h"
bool NoTravelTargetTrigger::IsActive() { return !context->GetValue<TravelTarget*>("travel target")->Get()->isActive(); }
bool FarFromTravelTargetTrigger::IsActive()
{
return context->GetValue<TravelTarget*>("travel target")->Get()->isTraveling();
}
bool NearDarkPortalTrigger::IsActive() { return bot->GetAreaId() == 72; }
bool AtDarkPortalAzerothTrigger::IsActive()
{
if (bot->GetAreaId() == 72)
{
if (sServerFacade->GetDistance2d(bot, -11906.9f, -3208.53f) < 20.0f)
{
return true;
}
}
return false;
}
bool AtDarkPortalOutlandTrigger::IsActive()
{
if (bot->GetAreaId() == 3539)
{
if (sServerFacade->GetDistance2d(bot, -248.1939f, 921.919f) < 10.0f)
{
return true;
}
}
return false;
}

View File

@@ -0,0 +1,53 @@
/*
* 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_TRAVELTRIGGERS_H
#define _PLAYERBOT_TRAVELTRIGGERS_H
#include "Trigger.h"
class PlayerbotAI;
class NoTravelTargetTrigger : public Trigger
{
public:
NoTravelTargetTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no travel target") {}
bool IsActive() override;
};
class FarFromTravelTargetTrigger : public Trigger
{
public:
FarFromTravelTargetTrigger(PlayerbotAI* botAI) : Trigger(botAI, "far from travel target") {}
bool IsActive() override;
};
class NearDarkPortalTrigger : public Trigger
{
public:
NearDarkPortalTrigger(PlayerbotAI* botAI) : Trigger(botAI, "near dark portal", 10) {}
virtual bool IsActive();
};
class AtDarkPortalAzerothTrigger : public Trigger
{
public:
AtDarkPortalAzerothTrigger(PlayerbotAI* botAI) : Trigger(botAI, "at dark portal azeroth", 10) {}
bool IsActive() override;
};
class AtDarkPortalOutlandTrigger : public Trigger
{
public:
AtDarkPortalOutlandTrigger(PlayerbotAI* botAI) : Trigger(botAI, "at dark portal outland", 10) {}
bool IsActive() override;
};
#endif

View File

@@ -0,0 +1,72 @@
/*
* 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 "WithinAreaTrigger.h"
#include "LastMovementValue.h"
#include "Playerbots.h"
bool WithinAreaTrigger::IsActive()
{
LastMovement& movement = context->GetValue<LastMovement&>("last area trigger")->Get();
if (!movement.lastAreaTrigger)
return false;
AreaTrigger const* at = sObjectMgr->GetAreaTrigger(movement.lastAreaTrigger);
if (!at)
return false;
if (!sObjectMgr->GetAreaTriggerTeleport(movement.lastAreaTrigger))
return false;
return IsPointInAreaTriggerZone(at, bot->GetMapId(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(),
0.5f);
}
bool WithinAreaTrigger::IsPointInAreaTriggerZone(AreaTrigger const* atEntry, uint32 mapid, float x, float y, float z,
float delta)
{
if (mapid != atEntry->map)
return false;
if (atEntry->radius > 0)
{
// if we have radius check it
float dist2 = (x - atEntry->x) * (x - atEntry->x) + (y - atEntry->y) * (y - atEntry->y) +
(z - atEntry->z) * (z - atEntry->z);
if (dist2 > (atEntry->radius + delta) * (atEntry->radius + delta))
return false;
}
else
{
// we have only extent
// rotate the players position instead of rotating the whole cube, that way we can make a simplified
// is-in-cube check and we have to calculate only one point instead of 4
// 2PI = 360, keep in mind that ingame orientation is counter-clockwise
double rotation = 2 * M_PI - atEntry->orientation;
double sinVal = sin(rotation);
double cosVal = cos(rotation);
float playerBoxDistX = x - atEntry->x;
float playerBoxDistY = y - atEntry->y;
float rotPlayerX = float(atEntry->x + playerBoxDistX * cosVal - playerBoxDistY * sinVal);
float rotPlayerY = float(atEntry->y + playerBoxDistY * cosVal + playerBoxDistX * sinVal);
// box edges are parallel to coordiante axis, so we can treat every dimension independently :D
float dz = z - atEntry->z;
float dx = rotPlayerX - atEntry->x;
float dy = rotPlayerY - atEntry->y;
if ((fabs(dx) > atEntry->x / 2 + delta) || (fabs(dy) > atEntry->y / 2 + delta) ||
(fabs(dz) > atEntry->z / 2 + delta))
{
return false;
}
}
return true;
}

View File

@@ -0,0 +1,26 @@
/*
* 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_WITHINAREATRIGGER_H
#define _PLAYERBOT_WITHINAREATRIGGER_H
#include "Trigger.h"
class PlayerbotAI;
struct AreaTrigger;
class WithinAreaTrigger : public Trigger
{
public:
WithinAreaTrigger(PlayerbotAI* botAI) : Trigger(botAI, "within area trigger") {}
bool IsActive() override;
private:
bool IsPointInAreaTriggerZone(AreaTrigger const* atEntry, uint32 mapid, float x, float y, float z, float delta);
};
#endif

View File

@@ -0,0 +1,25 @@
/*
* 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 "WorldPacketTrigger.h"
#include "Playerbots.h"
void WorldPacketTrigger::ExternalEvent(WorldPacket& revData, Player* eventOwner)
{
packet = revData;
owner = eventOwner;
triggered = true;
}
Event WorldPacketTrigger::Check()
{
if (!triggered)
return Event();
return Event(getName(), packet, owner);
}
void WorldPacketTrigger::Reset() { triggered = false; }

View File

@@ -0,0 +1,31 @@
/*
* 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_WORLDPACKETTRIGGER_H
#define _PLAYERBOT_WORLDPACKETTRIGGER_H
#include "Trigger.h"
class Event;
class Player;
class PlayerbotAI;
class WorldPacket;
class WorldPacketTrigger : public Trigger
{
public:
WorldPacketTrigger(PlayerbotAI* botAI, std::string const command) : Trigger(botAI, command), triggered(false) {}
void ExternalEvent(WorldPacket& packet, Player* owner = nullptr) override;
Event Check() override;
void Reset() override;
private:
WorldPacket packet;
bool triggered;
Player* owner;
};
#endif