mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-03 19:03:49 +00:00
[HOT FIX] MS build issues regarding folder / command lenght usage or rc.exe (#2038)
This commit is contained in:
228
src/Ai/Base/Trigger/BossAuraTriggers.cpp
Normal file
228
src/Ai/Base/Trigger/BossAuraTriggers.cpp
Normal 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;
|
||||
}
|
||||
88
src/Ai/Base/Trigger/BossAuraTriggers.h
Normal file
88
src/Ai/Base/Trigger/BossAuraTriggers.h
Normal 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
|
||||
30
src/Ai/Base/Trigger/ChatCommandTrigger.cpp
Normal file
30
src/Ai/Base/Trigger/ChatCommandTrigger.cpp
Normal 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; }
|
||||
30
src/Ai/Base/Trigger/ChatCommandTrigger.h
Normal file
30
src/Ai/Base/Trigger/ChatCommandTrigger.h
Normal 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
|
||||
28
src/Ai/Base/Trigger/CureTriggers.cpp
Normal file
28
src/Ai/Base/Trigger/CureTriggers.cpp
Normal 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(); }
|
||||
60
src/Ai/Base/Trigger/CureTriggers.h
Normal file
60
src/Ai/Base/Trigger/CureTriggers.h
Normal 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
|
||||
11
src/Ai/Base/Trigger/FishingTriggers.cpp
Normal file
11
src/Ai/Base/Trigger/FishingTriggers.cpp
Normal 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");}
|
||||
25
src/Ai/Base/Trigger/FishingTriggers.h
Normal file
25
src/Ai/Base/Trigger/FishingTriggers.h
Normal 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
|
||||
732
src/Ai/Base/Trigger/GenericTriggers.cpp
Normal file
732
src/Ai/Base/Trigger/GenericTriggers.cpp
Normal 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;
|
||||
}
|
||||
958
src/Ai/Base/Trigger/GenericTriggers.h
Normal file
958
src/Ai/Base/Trigger/GenericTriggers.h
Normal 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
|
||||
57
src/Ai/Base/Trigger/GuildTriggers.cpp
Normal file
57
src/Ai/Base/Trigger/GuildTriggers.cpp
Normal 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;
|
||||
}
|
||||
37
src/Ai/Base/Trigger/GuildTriggers.h
Normal file
37
src/Ai/Base/Trigger/GuildTriggers.h
Normal 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
|
||||
41
src/Ai/Base/Trigger/HealthTriggers.cpp
Normal file
41
src/Ai/Base/Trigger/HealthTriggers.cpp
Normal 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;
|
||||
}
|
||||
199
src/Ai/Base/Trigger/HealthTriggers.h
Normal file
199
src/Ai/Base/Trigger/HealthTriggers.h
Normal 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
|
||||
16
src/Ai/Base/Trigger/LfgTriggers.cpp
Normal file
16
src/Ai/Base/Trigger/LfgTriggers.cpp
Normal 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();
|
||||
}
|
||||
29
src/Ai/Base/Trigger/LfgTriggers.h
Normal file
29
src/Ai/Base/Trigger/LfgTriggers.h
Normal 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
|
||||
40
src/Ai/Base/Trigger/LootTriggers.cpp
Normal file
40
src/Ai/Base/Trigger/LootTriggers.cpp
Normal 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"); }
|
||||
37
src/Ai/Base/Trigger/LootTriggers.h
Normal file
37
src/Ai/Base/Trigger/LootTriggers.h
Normal 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
|
||||
337
src/Ai/Base/Trigger/PvpTriggers.cpp
Normal file
337
src/Ai/Base/Trigger/PvpTriggers.cpp
Normal 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;
|
||||
}
|
||||
151
src/Ai/Base/Trigger/PvpTriggers.h
Normal file
151
src/Ai/Base/Trigger/PvpTriggers.h
Normal 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
|
||||
298
src/Ai/Base/Trigger/RangeTriggers.cpp
Normal file
298
src/Ai/Base/Trigger/RangeTriggers.cpp
Normal 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;
|
||||
}
|
||||
148
src/Ai/Base/Trigger/RangeTriggers.h
Normal file
148
src/Ai/Base/Trigger/RangeTriggers.h
Normal 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
|
||||
431
src/Ai/Base/Trigger/RpgTriggers.cpp
Normal file
431
src/Ai/Base/Trigger/RpgTriggers.cpp
Normal 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;
|
||||
}
|
||||
214
src/Ai/Base/Trigger/RpgTriggers.h
Normal file
214
src/Ai/Base/Trigger/RpgTriggers.h
Normal 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
|
||||
20
src/Ai/Base/Trigger/RtiTriggers.cpp
Normal file
20
src/Ai/Base/Trigger/RtiTriggers.cpp
Normal 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;
|
||||
}
|
||||
21
src/Ai/Base/Trigger/RtiTriggers.h
Normal file
21
src/Ai/Base/Trigger/RtiTriggers.h
Normal 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
|
||||
199
src/Ai/Base/Trigger/StuckTriggers.cpp
Normal file
199
src/Ai/Base/Trigger/StuckTriggers.cpp
Normal 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;
|
||||
}
|
||||
43
src/Ai/Base/Trigger/StuckTriggers.h
Normal file
43
src/Ai/Base/Trigger/StuckTriggers.h
Normal 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
|
||||
44
src/Ai/Base/Trigger/TravelTriggers.cpp
Normal file
44
src/Ai/Base/Trigger/TravelTriggers.cpp
Normal 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;
|
||||
}
|
||||
53
src/Ai/Base/Trigger/TravelTriggers.h
Normal file
53
src/Ai/Base/Trigger/TravelTriggers.h
Normal 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
|
||||
72
src/Ai/Base/Trigger/WithinAreaTrigger.cpp
Normal file
72
src/Ai/Base/Trigger/WithinAreaTrigger.cpp
Normal 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;
|
||||
}
|
||||
26
src/Ai/Base/Trigger/WithinAreaTrigger.h
Normal file
26
src/Ai/Base/Trigger/WithinAreaTrigger.h
Normal 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
|
||||
25
src/Ai/Base/Trigger/WorldPacketTrigger.cpp
Normal file
25
src/Ai/Base/Trigger/WorldPacketTrigger.cpp
Normal 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; }
|
||||
31
src/Ai/Base/Trigger/WorldPacketTrigger.h
Normal file
31
src/Ai/Base/Trigger/WorldPacketTrigger.h
Normal 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
|
||||
Reference in New Issue
Block a user