Files
mod-playerbots/src/strategy/triggers/GenericTriggers.cpp
2023-06-11 21:15:02 +08:00

558 lines
14 KiB
C++

/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
*/
#include "GenericTriggers.h"
#include "BattlegroundWS.h"
#include "ObjectGuid.h"
#include "Playerbots.h"
#include "SharedDefines.h"
#include "TemporarySummon.h"
#include <string>
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 HighManaTrigger::IsActive()
{
return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") < 65;
}
bool AlmostFullManaTrigger::IsActive()
{
return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > 85;
}
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 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();
return SpellTrigger::IsActive() && !botAI->HasAura(spell, target, false, checkIsOwner);
}
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);
}
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 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->GetExactDist2d(current_target) <= range) {
attackers_count++;
}
}
return attackers_count >= amount;
}
bool NoFoodTrigger::IsActive()
{
bool isRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot);
if (isRandomBot && sPlayerbotAIConfig->freeFood)
return false;
return AI_VALUE2(std::vector<Item*>, "inventory items", "conjured food").empty();
}
bool NoDrinkTrigger::IsActive()
{
bool isRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot);
if (isRandomBot && sPlayerbotAIConfig->freeFood)
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()
{
return BuffTrigger::IsActive() && AI_VALUE2(uint8, "health", GetTargetName()) > life_bound;
}
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);
}
RandomTrigger::RandomTrigger(PlayerbotAI* botAI, std::string const name, int32 probability) : Trigger(botAI, name), probability(probability), lastCheck(time(nullptr))
{
}
bool RandomTrigger::IsActive()
{
if (time(nullptr) - lastCheck < sPlayerbotAIConfig->repeatDelay / 1000)
return false;
lastCheck = time(nullptr);
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()
{
return BuffTrigger::IsActive() && AI_VALUE(uint8, "balance") <= balance;
}
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 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 currentTarget->GetVictim() == AI_VALUE(Unit*, "self target");
}
bool IsBehindTargetTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
return target && AI_VALUE2(bool, "behind", "current target");
}
bool IsNotBehindTargetTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
return target && !AI_VALUE2(bool, "behind", "current target");
}
bool IsNotFacingTargetTrigger::IsActive()
{
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* dps = AI_VALUE(Unit*, "dps 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 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 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);
}