mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-16 18:30:27 +00:00
Big update.
This commit is contained in:
469
src/strategy/triggers/GenericTriggers.cpp
Normal file
469
src/strategy/triggers/GenericTriggers.cpp
Normal file
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* 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 "Playerbots.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 !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()
|
||||
{
|
||||
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, true);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
return AI_VALUE2(bool, "combat", "self target") && AI_VALUE(uint8, "aoe count") >= amount && AI_VALUE(uint8, "attacker count") >= amount;
|
||||
}
|
||||
|
||||
bool NoFoodTrigger::IsActive()
|
||||
{
|
||||
return AI_VALUE2(std::vector<Item*>, "inventory items", "conjured food").empty();
|
||||
}
|
||||
|
||||
bool NoDrinkTrigger::IsActive()
|
||||
{
|
||||
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()) > 15;
|
||||
}
|
||||
|
||||
bool SpellTrigger::IsActive()
|
||||
{
|
||||
return GetTarget();
|
||||
}
|
||||
|
||||
bool SpellCanBeCastTrigger::IsActive()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
return target && botAI->CanCastSpell(spell, target);
|
||||
}
|
||||
|
||||
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->IsActive() && rs->IsActive();
|
||||
}
|
||||
|
||||
std::string const AndTrigger::getName()
|
||||
{
|
||||
std::string name(ls->getName());
|
||||
name = name + " and ";
|
||||
name = name + rs->getName();
|
||||
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());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user