mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
General improvement on init and strats (#1064)
* Potions strats and potions init * Druid and shaman spell in low level * Ammo init improvement * Rogue low level * Fix melee attack action (for caster with no mana) * Disable pet spells that reduce dps * Talents improvement * Remove CanFreeMove check * Reduce penalty for non-dagger weapon for rogue
This commit is contained in:
@@ -963,8 +963,8 @@ AiPlayerbot.PremadeSpecLink.2.2.80 = 050501-05-05232051203331302133231331
|
|||||||
|
|
||||||
AiPlayerbot.PremadeSpecName.3.0 = bm pve
|
AiPlayerbot.PremadeSpecName.3.0 = bm pve
|
||||||
AiPlayerbot.PremadeSpecGlyph.3.0 = 42912,43350,42902,43351,43338,45732
|
AiPlayerbot.PremadeSpecGlyph.3.0 = 42912,43350,42902,43351,43338,45732
|
||||||
AiPlayerbot.PremadeSpecLink.3.0.60 = 51200201505112243100511351
|
AiPlayerbot.PremadeSpecLink.3.0.60 = 51200201505112243110531051
|
||||||
AiPlayerbot.PremadeSpecLink.3.0.80 = 51200201505112253100531351-015305021
|
AiPlayerbot.PremadeSpecLink.3.0.80 = 51200201505112243120531251-025305101
|
||||||
AiPlayerbot.PremadeSpecName.3.1 = mm pve
|
AiPlayerbot.PremadeSpecName.3.1 = mm pve
|
||||||
AiPlayerbot.PremadeSpecGlyph.3.1 = 42912,43350,42914,43351,43338,45732
|
AiPlayerbot.PremadeSpecGlyph.3.1 = 42912,43350,42914,43351,43338,45732
|
||||||
AiPlayerbot.PremadeSpecLink.3.1.60 = -025315101030013233125031051
|
AiPlayerbot.PremadeSpecLink.3.1.60 = -025315101030013233125031051
|
||||||
@@ -998,16 +998,16 @@ AiPlayerbot.PremadeHunterPetLink.2.20 = 21000203300002110221
|
|||||||
|
|
||||||
AiPlayerbot.PremadeSpecName.4.0 = as pve
|
AiPlayerbot.PremadeSpecName.4.0 = as pve
|
||||||
AiPlayerbot.PremadeSpecGlyph.4.0 = 45768,43379,45761,43380,43378,45766
|
AiPlayerbot.PremadeSpecGlyph.4.0 = 45768,43379,45761,43380,43378,45766
|
||||||
AiPlayerbot.PremadeSpecLink.4.0.60 = 005323005350100520103331051
|
AiPlayerbot.PremadeSpecLink.4.0.60 = 005303104352100520103331051
|
||||||
AiPlayerbot.PremadeSpecLink.4.0.80 = 005323005350100520103331051-005005005003-2
|
AiPlayerbot.PremadeSpecLink.4.0.80 = 005303104352100520103331051-005005005003-2
|
||||||
AiPlayerbot.PremadeSpecName.4.1 = combat pve
|
AiPlayerbot.PremadeSpecName.4.1 = combat pve
|
||||||
AiPlayerbot.PremadeSpecGlyph.4.1 = 42962,43379,45762,43380,43378,42969
|
AiPlayerbot.PremadeSpecGlyph.4.1 = 42962,43379,45762,43380,43378,42969
|
||||||
AiPlayerbot.PremadeSpecLink.4.1.60 = -0252051000035015223100501251
|
AiPlayerbot.PremadeSpecLink.4.1.60 = -0252051000035015223100501251
|
||||||
AiPlayerbot.PremadeSpecLink.4.1.80 = 00532000523-0252051000035015223100501251
|
AiPlayerbot.PremadeSpecLink.4.1.80 = 00532000523-0252051000035015223100501251
|
||||||
AiPlayerbot.PremadeSpecName.4.2 = subtlety pve
|
AiPlayerbot.PremadeSpecName.4.2 = subtlety pve
|
||||||
AiPlayerbot.PremadeSpecGlyph.4.2 = 42967,43379,45764,43380,43378,45767
|
AiPlayerbot.PremadeSpecGlyph.4.2 = 42967,43379,45764,43380,43378,45767
|
||||||
AiPlayerbot.PremadeSpecLink.4.2.60 = --5120122030321121050135031241
|
AiPlayerbot.PremadeSpecLink.4.2.60 = --5022012030321121350115031151
|
||||||
AiPlayerbot.PremadeSpecLink.4.2.80 = 0053231-2-5120222030321121050135231251
|
AiPlayerbot.PremadeSpecLink.4.2.80 = 30532010114--5022012030321121350115031151
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
|
|
||||||
if (!player->InBattleground())
|
if (!player->InBattleground())
|
||||||
{
|
{
|
||||||
engine->addStrategiesNoInit("racials", "chat", "default", "cast time", "duel", "boost", nullptr);
|
engine->addStrategiesNoInit("racials", "chat", "default", "cast time", "potions", "duel", "boost", nullptr);
|
||||||
}
|
}
|
||||||
if (sPlayerbotAIConfig->autoAvoidAoe && facade->HasRealPlayerMaster())
|
if (sPlayerbotAIConfig->autoAvoidAoe && facade->HasRealPlayerMaster())
|
||||||
{
|
{
|
||||||
@@ -375,13 +375,13 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
// }
|
// }
|
||||||
break;
|
break;
|
||||||
case CLASS_ROGUE:
|
case CLASS_ROGUE:
|
||||||
if (tab == ROGUE_TAB_ASSASSINATION)
|
if (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY)
|
||||||
{
|
{
|
||||||
engine->addStrategiesNoInit("melee", "dps assist", "aoe", /*"behind",*/ nullptr);
|
engine->addStrategiesNoInit("melee", "dps assist", "aoe", nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
engine->addStrategiesNoInit("dps", "dps assist", "aoe", /*"behind",*/ nullptr);
|
engine->addStrategiesNoInit("dps", "dps assist", "aoe", nullptr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLASS_WARLOCK:
|
case CLASS_WARLOCK:
|
||||||
|
|||||||
@@ -2313,8 +2313,9 @@ void RandomItemMgr::BuildAmmoCache()
|
|||||||
for (uint32 subClass = ITEM_SUBCLASS_ARROW; subClass <= ITEM_SUBCLASS_BULLET; subClass++)
|
for (uint32 subClass = ITEM_SUBCLASS_ARROW; subClass <= ITEM_SUBCLASS_BULLET; subClass++)
|
||||||
{
|
{
|
||||||
QueryResult results = WorldDatabase.Query(
|
QueryResult results = WorldDatabase.Query(
|
||||||
"SELECT entry, Flags FROM item_template WHERE class = {} AND subclass = {} AND RequiredLevel <= {} and duration = 0 "
|
"SELECT entry FROM item_template WHERE class = {} AND subclass = {} AND RequiredLevel <= {} AND duration = 0 "
|
||||||
"ORDER BY stackable DESC, RequiredLevel DESC",
|
"AND (Flags & 16) = 0 AND dmg_min1 != 0 AND RequiredLevel != 0 "
|
||||||
|
"ORDER BY stackable DESC, ItemLevel DESC",
|
||||||
ITEM_CLASS_PROJECTILE, subClass, level);
|
ITEM_CLASS_PROJECTILE, subClass, level);
|
||||||
if (!results)
|
if (!results)
|
||||||
continue;
|
continue;
|
||||||
@@ -2322,35 +2323,27 @@ void RandomItemMgr::BuildAmmoCache()
|
|||||||
{
|
{
|
||||||
Field* fields = results->Fetch();
|
Field* fields = results->Fetch();
|
||||||
uint32 entry = fields[0].Get<uint32>();
|
uint32 entry = fields[0].Get<uint32>();
|
||||||
uint32 flags = fields[1].Get<uint32>();
|
ammoCache[level][subClass].push_back(entry);
|
||||||
if (flags & ITEM_FLAG_DEPRECATED)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ammoCache[level][subClass] = entry;
|
|
||||||
++counter;
|
++counter;
|
||||||
break;
|
|
||||||
} while (results->NextRow());
|
} while (results->NextRow());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO("server.loading", "Cached {} types of ammo", counter); // TEST
|
LOG_INFO("server.loading", "Cached {} ammo", counter); // TEST
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 RandomItemMgr::GetAmmo(uint32 level, uint32 subClass) { return ammoCache[level][subClass]; }
|
std::vector<uint32> RandomItemMgr::GetAmmo(uint32 level, uint32 subClass) { return ammoCache[level][subClass]; }
|
||||||
|
|
||||||
void RandomItemMgr::BuildPotionCache()
|
void RandomItemMgr::BuildPotionCache()
|
||||||
{
|
{
|
||||||
uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
||||||
// if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
|
||||||
// maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
|
||||||
|
|
||||||
LOG_INFO("server.loading", "Building potion cache for {} levels", maxLevel);
|
LOG_INFO("playerbots", "Building potion cache for {} levels", maxLevel);
|
||||||
|
|
||||||
ItemTemplateContainer const* itemTemplates = sObjectMgr->GetItemTemplateStore();
|
ItemTemplateContainer const* itemTemplates = sObjectMgr->GetItemTemplateStore();
|
||||||
|
|
||||||
uint32 counter = 0;
|
uint32 counter = 0;
|
||||||
for (uint32 level = 1; level <= maxLevel + 1; level += 10)
|
for (uint32 level = 1; level <= maxLevel; level++)
|
||||||
{
|
{
|
||||||
uint32 effects[] = {SPELL_EFFECT_HEAL, SPELL_EFFECT_ENERGIZE};
|
uint32 effects[] = {SPELL_EFFECT_HEAL, SPELL_EFFECT_ENERGIZE};
|
||||||
for (uint8 i = 0; i < 2; ++i)
|
for (uint8 i = 0; i < 2; ++i)
|
||||||
@@ -2368,7 +2361,8 @@ void RandomItemMgr::BuildPotionCache()
|
|||||||
proto->Bonding != NO_BIND)
|
proto->Bonding != NO_BIND)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (proto->RequiredLevel && (proto->RequiredLevel > level || proto->RequiredLevel < level - 10))
|
uint32 requiredLevel = proto->RequiredLevel;
|
||||||
|
if (requiredLevel > level || (level > 15 && requiredLevel < level - 15))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (proto->RequiredSkill)
|
if (proto->RequiredSkill)
|
||||||
@@ -2380,39 +2374,44 @@ void RandomItemMgr::BuildPotionCache()
|
|||||||
if (proto->Duration & 0x80000000)
|
if (proto->Duration & 0x80000000)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (uint8 j = 0; j < MAX_ITEM_PROTO_SPELLS; j++)
|
|
||||||
{
|
if (proto->AllowableClass != -1)
|
||||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[j].SpellId);
|
|
||||||
if (!spellInfo)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (uint8 i = 0; i < 3; i++)
|
bool hybrid = false;
|
||||||
|
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Spells[0].SpellId);
|
||||||
|
if (!spellInfo)
|
||||||
|
continue;
|
||||||
|
// do not accept hybrid potion
|
||||||
|
for (uint8 i = 1; i < 3; i++)
|
||||||
{
|
{
|
||||||
if (spellInfo->Effects[i].Effect == effect)
|
if (spellInfo->Effects[i].Effect != 0)
|
||||||
{
|
{
|
||||||
potionCache[level / 10][effect].push_back(itr.first);
|
hybrid = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (hybrid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (spellInfo->Effects[0].Effect == effect)
|
||||||
|
potionCache[level][effect].push_back(itr.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32 level = 1; level <= maxLevel + 1; level += 10)
|
for (uint32 level = 1; level <= maxLevel; level++)
|
||||||
{
|
{
|
||||||
uint32 effects[] = {SPELL_EFFECT_HEAL, SPELL_EFFECT_ENERGIZE};
|
uint32 effects[] = {SPELL_EFFECT_HEAL, SPELL_EFFECT_ENERGIZE};
|
||||||
for (uint8 i = 0; i < 2; ++i)
|
for (uint8 i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
uint32 effect = effects[i];
|
uint32 effect = effects[i];
|
||||||
uint32 size = potionCache[level / 10][effect].size();
|
uint32 size = potionCache[level][effect].size();
|
||||||
++counter;
|
counter += size;
|
||||||
|
|
||||||
LOG_DEBUG("server.loading", "Potion cache for level={}, effect={}: {} items", level, effect, size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO("server.loading", "Cached {} types of potions", counter); // TEST
|
LOG_INFO("playerbots", "Cached {} potions", counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RandomItemMgr::BuildFoodCache()
|
void RandomItemMgr::BuildFoodCache()
|
||||||
@@ -2478,7 +2477,7 @@ void RandomItemMgr::BuildFoodCache()
|
|||||||
|
|
||||||
uint32 RandomItemMgr::GetRandomPotion(uint32 level, uint32 effect)
|
uint32 RandomItemMgr::GetRandomPotion(uint32 level, uint32 effect)
|
||||||
{
|
{
|
||||||
std::vector<uint32> potions = potionCache[(level - 1) / 10][effect];
|
const std::vector<uint32> &potions = potionCache[level][effect];
|
||||||
if (potions.empty())
|
if (potions.empty())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ public:
|
|||||||
uint32 GetStatWeight(Player* player, uint32 itemId);
|
uint32 GetStatWeight(Player* player, uint32 itemId);
|
||||||
uint32 GetLiveStatWeight(Player* player, uint32 itemId);
|
uint32 GetLiveStatWeight(Player* player, uint32 itemId);
|
||||||
uint32 GetRandomItem(uint32 level, RandomItemType type, RandomItemPredicate* predicate = nullptr);
|
uint32 GetRandomItem(uint32 level, RandomItemType type, RandomItemPredicate* predicate = nullptr);
|
||||||
uint32 GetAmmo(uint32 level, uint32 subClass);
|
std::vector<uint32> GetAmmo(uint32 level, uint32 subClass);
|
||||||
uint32 GetRandomPotion(uint32 level, uint32 effect);
|
uint32 GetRandomPotion(uint32 level, uint32 effect);
|
||||||
uint32 GetRandomFood(uint32 level, uint32 category);
|
uint32 GetRandomFood(uint32 level, uint32 category);
|
||||||
uint32 GetFood(uint32 level, uint32 category);
|
uint32 GetFood(uint32 level, uint32 category);
|
||||||
@@ -195,7 +195,7 @@ private:
|
|||||||
std::map<RandomItemType, RandomItemPredicate*> predicates;
|
std::map<RandomItemType, RandomItemPredicate*> predicates;
|
||||||
BotEquipCache equipCache;
|
BotEquipCache equipCache;
|
||||||
std::map<EquipmentSlots, std::set<InventoryType>> viableSlots;
|
std::map<EquipmentSlots, std::set<InventoryType>> viableSlots;
|
||||||
std::map<uint32, std::map<uint32, uint32>> ammoCache;
|
std::map<uint32, std::map<uint32, std::vector<uint32>>> ammoCache;
|
||||||
std::map<uint32, std::map<uint32, std::vector<uint32>>> potionCache;
|
std::map<uint32, std::map<uint32, std::vector<uint32>>> potionCache;
|
||||||
std::map<uint32, std::map<uint32, std::vector<uint32>>> foodCache;
|
std::map<uint32, std::map<uint32, std::vector<uint32>>> foodCache;
|
||||||
std::map<uint32, std::vector<uint32>> tradeCache;
|
std::map<uint32, std::vector<uint32>> tradeCache;
|
||||||
|
|||||||
@@ -652,6 +652,9 @@ void PlayerbotFactory::AddConsumables()
|
|||||||
|
|
||||||
void PlayerbotFactory::InitPetTalents()
|
void PlayerbotFactory::InitPetTalents()
|
||||||
{
|
{
|
||||||
|
if (bot->GetLevel() <= 70 && sPlayerbotAIConfig->limitTalentsExpansion)
|
||||||
|
return;
|
||||||
|
|
||||||
Pet* pet = bot->GetPet();
|
Pet* pet = bot->GetPet();
|
||||||
if (!pet)
|
if (!pet)
|
||||||
{
|
{
|
||||||
@@ -1670,9 +1673,6 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
|
|
||||||
if (proto->Quality != desiredQuality)
|
if (proto->Quality != desiredQuality)
|
||||||
continue;
|
continue;
|
||||||
// delay heavy check
|
|
||||||
// if (!CanEquipItem(proto))
|
|
||||||
// continue;
|
|
||||||
|
|
||||||
if (proto->Class == ITEM_CLASS_ARMOR &&
|
if (proto->Class == ITEM_CLASS_ARMOR &&
|
||||||
(slot == EQUIPMENT_SLOT_HEAD || slot == EQUIPMENT_SLOT_SHOULDERS ||
|
(slot == EQUIPMENT_SLOT_HEAD || slot == EQUIPMENT_SLOT_SHOULDERS ||
|
||||||
@@ -1688,9 +1688,6 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
if (slot == EQUIPMENT_SLOT_OFFHAND && bot->getClass() == CLASS_ROGUE &&
|
if (slot == EQUIPMENT_SLOT_OFFHAND && bot->getClass() == CLASS_ROGUE &&
|
||||||
proto->Class != ITEM_CLASS_WEAPON)
|
proto->Class != ITEM_CLASS_WEAPON)
|
||||||
continue;
|
continue;
|
||||||
// delay heavy check
|
|
||||||
// uint16 dest = 0;
|
|
||||||
// if (CanEquipUnseenItem(slot, dest, itemId))
|
|
||||||
items[slot].push_back(itemId);
|
items[slot].push_back(itemId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2830,7 +2827,28 @@ void PlayerbotFactory::InitAmmo()
|
|||||||
if (!subClass)
|
if (!subClass)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32 entry = sRandomItemMgr->GetAmmo(level, subClass);
|
std::vector<uint32> ammoEntryList = sRandomItemMgr->GetAmmo(level, subClass);
|
||||||
|
uint32 entry = 0;
|
||||||
|
for (uint32 tEntry : ammoEntryList)
|
||||||
|
{
|
||||||
|
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(tEntry);
|
||||||
|
if (!proto)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// disable next expansion ammo
|
||||||
|
if (sPlayerbotAIConfig->limitGearExpansion && bot->GetLevel() <= 60 && tEntry >= 23728)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (sPlayerbotAIConfig->limitGearExpansion && bot->GetLevel() <= 70 && tEntry >= 35570)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
entry = tEntry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry)
|
||||||
|
return;
|
||||||
|
|
||||||
uint32 count = bot->GetItemCount(entry);
|
uint32 count = bot->GetItemCount(entry);
|
||||||
uint32 maxCount = bot->getClass() == CLASS_HUNTER ? 6000 : 1000;
|
uint32 maxCount = bot->getClass() == CLASS_HUNTER ? 6000 : 1000;
|
||||||
|
|
||||||
@@ -2984,6 +3002,10 @@ void PlayerbotFactory::InitPotions()
|
|||||||
for (uint8 i = 0; i < 2; ++i)
|
for (uint8 i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
uint32 effect = effects[i];
|
uint32 effect = effects[i];
|
||||||
|
|
||||||
|
if (effect == SPELL_EFFECT_ENERGIZE && !bot->GetPower(POWER_MANA))
|
||||||
|
continue;
|
||||||
|
|
||||||
FindPotionVisitor visitor(bot, effect);
|
FindPotionVisitor visitor(bot, effect);
|
||||||
IterateItems(&visitor);
|
IterateItems(&visitor);
|
||||||
if (!visitor.GetResult().empty())
|
if (!visitor.GetResult().empty())
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ void StatsWeightCalculator::GenerateWeights(Player* player)
|
|||||||
void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
||||||
{
|
{
|
||||||
// Basic weights
|
// Basic weights
|
||||||
stats_weights_[STATS_TYPE_STAMINA] += 0.01f;
|
stats_weights_[STATS_TYPE_STAMINA] += 0.1f;
|
||||||
stats_weights_[STATS_TYPE_ARMOR] += 0.001f;
|
stats_weights_[STATS_TYPE_ARMOR] += 0.001f;
|
||||||
stats_weights_[STATS_TYPE_BONUS] += 1.0f;
|
stats_weights_[STATS_TYPE_BONUS] += 1.0f;
|
||||||
|
|
||||||
@@ -508,9 +508,10 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
|||||||
{
|
{
|
||||||
weight_ *= 0.1;
|
weight_ *= 0.1;
|
||||||
}
|
}
|
||||||
if (cls == CLASS_ROGUE && tab == ROGUE_TAB_ASSASSINATION && proto->SubClass != ITEM_SUBCLASS_WEAPON_DAGGER)
|
if (cls == CLASS_ROGUE && (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY) &&
|
||||||
|
proto->SubClass != ITEM_SUBCLASS_WEAPON_DAGGER)
|
||||||
{
|
{
|
||||||
weight_ *= 0.1;
|
weight_ *= 0.5;
|
||||||
}
|
}
|
||||||
if (cls == CLASS_ROGUE && player_->HasAura(13964) &&
|
if (cls == CLASS_ROGUE && player_->HasAura(13964) &&
|
||||||
(proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE))
|
(proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE))
|
||||||
|
|||||||
@@ -53,6 +53,16 @@ bool AttackMyTargetAction::Execute(Event event)
|
|||||||
|
|
||||||
bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||||
{
|
{
|
||||||
|
Unit* oldTarget = context->GetValue<Unit*>("current target")->Get();
|
||||||
|
bool shouldMelee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot);
|
||||||
|
|
||||||
|
bool sameTarget = oldTarget == target && bot->GetVictim() == target;
|
||||||
|
bool inCombat = botAI->GetState() == BOT_STATE_COMBAT;
|
||||||
|
bool sameAttackMode = bot->HasUnitState(UNIT_STATE_MELEE_ATTACKING) == shouldMelee;
|
||||||
|
// there's no reason to do attack again
|
||||||
|
if (sameTarget && inCombat && sameAttackMode)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE ||
|
if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE ||
|
||||||
bot->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
bot->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
||||||
{
|
{
|
||||||
@@ -131,11 +141,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
|||||||
ObjectGuid guid = target->GetGUID();
|
ObjectGuid guid = target->GetGUID();
|
||||||
bot->SetSelection(target->GetGUID());
|
bot->SetSelection(target->GetGUID());
|
||||||
|
|
||||||
Unit* oldTarget = context->GetValue<Unit*>("current target")->Get();
|
|
||||||
bool melee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot);
|
|
||||||
|
|
||||||
if (oldTarget == target && botAI->GetState() == BOT_STATE_COMBAT && bot->GetVictim() == target && (bot->HasUnitState(UNIT_STATE_MELEE_ATTACKING) == melee))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
context->GetValue<Unit*>("old target")->Set(oldTarget);
|
context->GetValue<Unit*>("old target")->Set(oldTarget);
|
||||||
|
|
||||||
@@ -158,7 +164,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
|||||||
}
|
}
|
||||||
botAI->ChangeEngine(BOT_STATE_COMBAT);
|
botAI->ChangeEngine(BOT_STATE_COMBAT);
|
||||||
|
|
||||||
bot->Attack(target, melee);
|
bot->Attack(target, shouldMelee);
|
||||||
/* prevent pet dead immediately in group */
|
/* prevent pet dead immediately in group */
|
||||||
// if (bot->GetMap()->IsDungeon() && bot->GetGroup() && !target->IsInCombat()) {
|
// if (bot->GetMap()->IsDungeon() && bot->GetGroup() && !target->IsInCombat()) {
|
||||||
// with_pet = false;
|
// with_pet = false;
|
||||||
|
|||||||
@@ -51,11 +51,10 @@ bool TogglePetSpellAutoCastAction::Execute(Event event)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool shouldApply = true;
|
bool shouldApply = true;
|
||||||
// spellId == 4511 || spellId == 54424 || spellId == 57564 || spellId == 57565 ||
|
if (spellId == 1742 /*cower*/ || spellId == 24450 /*Prowl*/ ||
|
||||||
// spellId == 57566 || spellId == 57567 ||
|
spellId == 47482 /*Leap*/ /* || spellId == 47481 Gnaw*/)
|
||||||
// cat stealth, prowl
|
|
||||||
if (spellId == 1742 || spellId == 24450)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
shouldApply = false;
|
shouldApply = false;
|
||||||
}
|
}
|
||||||
bool isAutoCast = false;
|
bool isAutoCast = false;
|
||||||
|
|||||||
@@ -2017,7 +2017,7 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius)
|
|||||||
if (currentTarget)
|
if (currentTarget)
|
||||||
{
|
{
|
||||||
// Normally, move to left or right is the best position
|
// Normally, move to left or right is the best position
|
||||||
bool isTanking = (currentTarget->CanFreeMove()) && (currentTarget->GetVictim() == bot);
|
bool isTanking = (!currentTarget->isFrozen() && !currentTarget->HasRootAura()) && (currentTarget->GetVictim() == bot);
|
||||||
float angle = bot->GetAngle(currentTarget);
|
float angle = bot->GetAngle(currentTarget);
|
||||||
float angleLeft = angle + (float)M_PI / 2;
|
float angleLeft = angle + (float)M_PI / 2;
|
||||||
float angleRight = angle - (float)M_PI / 2;
|
float angleRight = angle - (float)M_PI / 2;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni
|
|||||||
if (bot->CanUseItem(item) != EQUIP_ERR_OK)
|
if (bot->CanUseItem(item) != EQUIP_ERR_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (bot->IsNonMeleeSpellCast(true))
|
if (bot->IsNonMeleeSpellCast(false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint8 bagIndex = item->GetBagSlot();
|
uint8 bagIndex = item->GetBagSlot();
|
||||||
|
|||||||
@@ -143,7 +143,8 @@ void CasterDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(new TriggerNode("eclipse (lunar)",
|
triggers.push_back(new TriggerNode("eclipse (lunar)",
|
||||||
NextAction::array(0, new NextAction("starfire", ACTION_NORMAL + 6), nullptr)));
|
NextAction::array(0, new NextAction("starfire", ACTION_NORMAL + 6), nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("medium mana", NextAction::array(0, new NextAction("innervate", ACTION_HIGH + 9), NULL)));
|
new TriggerNode("medium mana", NextAction::array(0, new NextAction("innervate", ACTION_HIGH + 9), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("enemy too close for spell",
|
triggers.push_back(new TriggerNode("enemy too close for spell",
|
||||||
NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr)));
|
NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,10 +113,10 @@ public:
|
|||||||
SavageRoarTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "savage roar") {}
|
SavageRoarTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "savage roar") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class NaturesGraspTrigger : public BoostTrigger
|
class NaturesGraspTrigger : public BuffTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NaturesGraspTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "nature's grasp") {}
|
NaturesGraspTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "nature's grasp") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class EntanglingRootsTrigger : public HasCcTargetTrigger
|
class EntanglingRootsTrigger : public HasCcTargetTrigger
|
||||||
|
|||||||
@@ -169,4 +169,6 @@ void GenericDruidBuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
NextAction::array(0, new NextAction("mark of the wild on party", 13.0f), nullptr)));
|
NextAction::array(0, new NextAction("mark of the wild on party", 13.0f), nullptr)));
|
||||||
triggers.push_back(new TriggerNode("thorns on main tank",
|
triggers.push_back(new TriggerNode("thorns on main tank",
|
||||||
NextAction::array(0, new NextAction("thorns on main tank", 11.0f), nullptr)));
|
NextAction::array(0, new NextAction("thorns on main tank", 11.0f), nullptr)));
|
||||||
|
triggers.push_back(new TriggerNode("thorns",
|
||||||
|
NextAction::array(0, new NextAction("thorns", 10.0f), nullptr)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,8 @@ void GenericDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
// NextAction::array(0, new NextAction("innervate", ACTION_EMERGENCY + 5), nullptr)));
|
// NextAction::array(0, new NextAction("innervate", ACTION_EMERGENCY + 5), nullptr)));
|
||||||
triggers.push_back(new TriggerNode("combat party member dead",
|
triggers.push_back(new TriggerNode("combat party member dead",
|
||||||
NextAction::array(0, new NextAction("rebirth", ACTION_HIGH + 9), NULL)));
|
NextAction::array(0, new NextAction("rebirth", ACTION_HIGH + 9), NULL)));
|
||||||
|
triggers.push_back(new TriggerNode("being attacked",
|
||||||
|
NextAction::array(0, new NextAction("nature's grasp", ACTION_HIGH + 1), nullptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DruidCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void DruidCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
void DpsAssistStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
NextAction** DpsAssistStrategy::getDefaultActions()
|
||||||
{
|
{
|
||||||
triggers.push_back(
|
return NextAction::array(
|
||||||
new TriggerNode("not dps target active", NextAction::array(0, new NextAction("dps assist", 50.0f), nullptr)));
|
0, new NextAction("dps assist", 50.0f),
|
||||||
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DpsAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void DpsAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ public:
|
|||||||
DpsAssistStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {}
|
DpsAssistStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {}
|
||||||
|
|
||||||
std::string const getName() override { return "dps assist"; }
|
std::string const getName() override { return "dps assist"; }
|
||||||
// uint32 GetType() const override { return STRATEGY_TYPE_DPS; }
|
NextAction** getDefaultActions() override;
|
||||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DpsAoeStrategy : public NonCombatStrategy
|
class DpsAoeStrategy : public NonCombatStrategy
|
||||||
|
|||||||
@@ -7,8 +7,15 @@
|
|||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
void TankAssistStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
NextAction** TankAssistStrategy::getDefaultActions()
|
||||||
{
|
{
|
||||||
triggers.push_back(
|
return NextAction::array(
|
||||||
new TriggerNode("tank assist", NextAction::array(0, new NextAction("tank assist", 50.0f), nullptr)));
|
0, new NextAction("tank assist", 50.0f),
|
||||||
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void TankAssistStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
|
// {
|
||||||
|
// triggers.push_back(
|
||||||
|
// new TriggerNode("tank assist", NextAction::array(0, new NextAction("tank assist", 50.0f), nullptr)));
|
||||||
|
// }
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ public:
|
|||||||
|
|
||||||
std::string const getName() override { return "tank assist"; }
|
std::string const getName() override { return "tank assist"; }
|
||||||
uint32 GetType() const override { return STRATEGY_TYPE_TANK; }
|
uint32 GetType() const override { return STRATEGY_TYPE_TANK; }
|
||||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
NextAction** getDefaultActions() override;
|
||||||
|
// void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -146,9 +146,4 @@ void HunterTrapWeaveStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"immolation trap no cd", NextAction::array(0, new NextAction("reach melee", ACTION_HIGH + 3), nullptr)));
|
"immolation trap no cd", NextAction::array(0, new NextAction("reach melee", ACTION_HIGH + 3), nullptr)));
|
||||||
|
|
||||||
// triggers.push_back(new TriggerNode(
|
|
||||||
// "scare beast", NextAction::array(0, new NextAction("scare beast on cc", ACTION_HIGH + 3), nullptr)));
|
|
||||||
// triggers.push_back(new TriggerNode(
|
|
||||||
// "freezing trap", NextAction::array(0, new NextAction("freezing trap on cc", ACTION_HIGH + 3), nullptr)));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ void ShadowPriestAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
void ShadowPriestDebuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void ShadowPriestDebuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"devouring plague", NextAction::array(0, new NextAction("devouring plague", ACTION_HIGH + 3), nullptr)));
|
"vampiric touch", NextAction::array(0, new NextAction("vampiric touch", ACTION_HIGH + 3), nullptr)));
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"vampiric touch", NextAction::array(0, new NextAction("vampiric touch", ACTION_HIGH + 2), nullptr)));
|
"devouring plague", NextAction::array(0, new NextAction("devouring plague", ACTION_HIGH + 2), nullptr)));
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"shadow word: pain", NextAction::array(0, new NextAction("shadow word: pain", ACTION_HIGH + 1), nullptr)));
|
"shadow word: pain", NextAction::array(0, new NextAction("shadow word: pain", ACTION_HIGH + 1), nullptr)));
|
||||||
// triggers.push_back(new TriggerNode("feedback", NextAction::array(0, new NextAction("feedback", 80.0f),
|
// triggers.push_back(new TriggerNode("feedback", NextAction::array(0, new NextAction("feedback", 80.0f),
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ public:
|
|||||||
{
|
{
|
||||||
creators["mutilate"] = &mutilate;
|
creators["mutilate"] = &mutilate;
|
||||||
creators["envenom"] = &envenom;
|
creators["envenom"] = &envenom;
|
||||||
|
creators["backstab"] = &backstab;
|
||||||
|
creators["rupture"] = &rupture;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -17,16 +19,30 @@ private:
|
|||||||
{
|
{
|
||||||
return new ActionNode("mutilate",
|
return new ActionNode("mutilate",
|
||||||
/*P*/ NULL,
|
/*P*/ NULL,
|
||||||
/*A*/ NextAction::array(0, new NextAction("sinister strike"), NULL),
|
/*A*/ NextAction::array(0, new NextAction("backstab"), nullptr),
|
||||||
/*C*/ NULL);
|
/*C*/ NULL);
|
||||||
}
|
}
|
||||||
static ActionNode* envenom(PlayerbotAI* ai)
|
static ActionNode* envenom(PlayerbotAI* ai)
|
||||||
{
|
{
|
||||||
return new ActionNode("envenom",
|
return new ActionNode("envenom",
|
||||||
/*P*/ NULL,
|
/*P*/ NULL,
|
||||||
/*A*/ NextAction::array(0, new NextAction("eviscerate"), NULL),
|
/*A*/ NextAction::array(0, new NextAction("rupture"), nullptr),
|
||||||
/*C*/ NULL);
|
/*C*/ NULL);
|
||||||
}
|
}
|
||||||
|
static ActionNode* backstab(PlayerbotAI* ai)
|
||||||
|
{
|
||||||
|
return new ActionNode("backstab",
|
||||||
|
/*P*/ NULL,
|
||||||
|
/*A*/ NextAction::array(0, new NextAction("sinister strike"), nullptr),
|
||||||
|
/*C*/ NULL);
|
||||||
|
}
|
||||||
|
static ActionNode* rupture(PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode("rupture",
|
||||||
|
/*P*/ nullptr,
|
||||||
|
/*A*/ NextAction::array(0, new NextAction("eviscerate"), nullptr),
|
||||||
|
/*C*/ nullptr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AssassinationRogueStrategy::AssassinationRogueStrategy(PlayerbotAI* ai) : MeleeCombatStrategy(ai)
|
AssassinationRogueStrategy::AssassinationRogueStrategy(PlayerbotAI* ai) : MeleeCombatStrategy(ai)
|
||||||
@@ -48,7 +64,7 @@ void AssassinationRogueStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
|||||||
new NextAction("ambush", ACTION_HIGH + 6), nullptr)));
|
new NextAction("ambush", ACTION_HIGH + 6), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("high energy available",
|
triggers.push_back(new TriggerNode("high energy available",
|
||||||
NextAction::array(0, new NextAction("mutilate", ACTION_NORMAL + 3), NULL)));
|
NextAction::array(0, new NextAction("mutilate", ACTION_NORMAL + 3), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"hunger for blood", NextAction::array(0, new NextAction("hunger for blood", ACTION_HIGH + 6), NULL)));
|
"hunger for blood", NextAction::array(0, new NextAction("hunger for blood", ACTION_HIGH + 6), NULL)));
|
||||||
@@ -57,7 +73,12 @@ void AssassinationRogueStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
|||||||
NextAction::array(0, new NextAction("slice and dice", ACTION_HIGH + 5), NULL)));
|
NextAction::array(0, new NextAction("slice and dice", ACTION_HIGH + 5), NULL)));
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("combo points 3 available",
|
triggers.push_back(new TriggerNode("combo points 3 available",
|
||||||
NextAction::array(0, new NextAction("envenom", ACTION_HIGH + 4), NULL)));
|
NextAction::array(0, new NextAction("envenom", ACTION_HIGH + 5),
|
||||||
|
new NextAction("eviscerate", ACTION_HIGH + 3), nullptr)));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("target with combo points almost dead",
|
||||||
|
NextAction::array(0, new NextAction("envenom", ACTION_HIGH + 4),
|
||||||
|
new NextAction("eviscerate", ACTION_HIGH + 2), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("expose armor", NextAction::array(0, new NextAction("expose armor", ACTION_HIGH + 3), NULL)));
|
new TriggerNode("expose armor", NextAction::array(0, new NextAction("expose armor", ACTION_HIGH + 3), NULL)));
|
||||||
@@ -69,8 +90,8 @@ void AssassinationRogueStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
|||||||
new TriggerNode("low health", NextAction::array(0, new NextAction("evasion", ACTION_HIGH + 9),
|
new TriggerNode("low health", NextAction::array(0, new NextAction("evasion", ACTION_HIGH + 9),
|
||||||
new NextAction("feint", ACTION_HIGH + 8), nullptr)));
|
new NextAction("feint", ACTION_HIGH + 8), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(new TriggerNode(
|
||||||
new TriggerNode("critical health", NextAction::array(0, new NextAction("cloak of shadows", ACTION_HIGH + 7), nullptr)));
|
"critical health", NextAction::array(0, new NextAction("cloak of shadows", ACTION_HIGH + 7), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("kick", NextAction::array(0, new NextAction("kick", ACTION_INTERRUPT + 2), NULL)));
|
new TriggerNode("kick", NextAction::array(0, new NextAction("kick", ACTION_INTERRUPT + 2), NULL)));
|
||||||
|
|||||||
@@ -44,6 +44,17 @@ bool CastVanishAction::isUseful()
|
|||||||
return !botAI->HasAura(23333, bot) && !botAI->HasAura(23335, bot) && !botAI->HasAura(34976, bot);
|
return !botAI->HasAura(23333, bot) && !botAI->HasAura(23335, bot) && !botAI->HasAura(34976, bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CastEnvenomAction::isUseful()
|
||||||
|
{
|
||||||
|
return AI_VALUE2(uint8, "energy", "self target") >= 35;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CastEnvenomAction::isPossible()
|
||||||
|
{
|
||||||
|
// alternate to eviscerate if talents unlearned
|
||||||
|
return botAI->HasAura(58410, bot) /* Master Poisoner */;
|
||||||
|
}
|
||||||
|
|
||||||
bool CastTricksOfTheTradeOnMainTankAction::isUseful()
|
bool CastTricksOfTheTradeOnMainTankAction::isUseful()
|
||||||
{
|
{
|
||||||
return CastSpellAction::isUseful() && AI_VALUE2(float, "distance", GetTargetName()) < 20.0f;
|
return CastSpellAction::isUseful() && AI_VALUE2(float, "distance", GetTargetName()) < 20.0f;
|
||||||
|
|||||||
@@ -127,10 +127,12 @@ public:
|
|||||||
CastKickOnEnemyHealerAction(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, "kick") {}
|
CastKickOnEnemyHealerAction(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, "kick") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class EnvenomAction : public CastMeleeSpellAction
|
class CastEnvenomAction : public CastMeleeSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EnvenomAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "envenom") {}
|
CastEnvenomAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "envenom") {}
|
||||||
|
bool isUseful() override;
|
||||||
|
bool isPossible() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastTricksOfTheTradeOnMainTankAction : public BuffOnMainTankAction
|
class CastTricksOfTheTradeOnMainTankAction : public BuffOnMainTankAction
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ private:
|
|||||||
static Action* check_stealth(PlayerbotAI* botAI) { return new CheckStealthAction(botAI); }
|
static Action* check_stealth(PlayerbotAI* botAI) { return new CheckStealthAction(botAI); }
|
||||||
static Action* sap(PlayerbotAI* botAI) { return new CastSapAction(botAI); }
|
static Action* sap(PlayerbotAI* botAI) { return new CastSapAction(botAI); }
|
||||||
static Action* unstealth(PlayerbotAI* botAI) { return new UnstealthAction(botAI); }
|
static Action* unstealth(PlayerbotAI* botAI) { return new UnstealthAction(botAI); }
|
||||||
static Action* envenom(PlayerbotAI* ai) { return new EnvenomAction(ai); }
|
static Action* envenom(PlayerbotAI* ai) { return new CastEnvenomAction(ai); }
|
||||||
static Action* tricks_of_the_trade_on_main_tank(PlayerbotAI* ai)
|
static Action* tricks_of_the_trade_on_main_tank(PlayerbotAI* ai)
|
||||||
{
|
{
|
||||||
return new CastTricksOfTheTradeOnMainTankAction(ai);
|
return new CastTricksOfTheTradeOnMainTankAction(ai);
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ private:
|
|||||||
static ActionNode* totem_of_wrath(PlayerbotAI* botAI)
|
static ActionNode* totem_of_wrath(PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("totem of wrath",
|
return new ActionNode("totem of wrath",
|
||||||
/*P*/ NULL,
|
/*P*/ nullptr,
|
||||||
/*A*/ NextAction::array(0, new NextAction("flametongue totem"), NULL),
|
/*A*/ NextAction::array(0, new NextAction("flametongue totem"), nullptr),
|
||||||
/*C*/ NULL);
|
/*C*/ nullptr);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -67,7 +67,11 @@ void CasterShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
// triggers.push_back(new TriggerNode("frost shock snare", NextAction::array(0, new NextAction("frost
|
// triggers.push_back(new TriggerNode("frost shock snare", NextAction::array(0, new NextAction("frost
|
||||||
// shock", 21.0f), nullptr)));
|
// shock", 21.0f), nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("no fire totem", NextAction::array(0, new NextAction("totem of wrath", 15.0f), NULL)));
|
new TriggerNode("no fire totem", NextAction::array(0,
|
||||||
|
new NextAction("totem of wrath", 15.0f),
|
||||||
|
new NextAction("searing totem", 6.0f),
|
||||||
|
nullptr)));
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("fire elemental totem",
|
triggers.push_back(new TriggerNode("fire elemental totem",
|
||||||
NextAction::array(0, new NextAction("fire elemental totem", 32.0f), nullptr)));
|
NextAction::array(0, new NextAction("fire elemental totem", 32.0f), nullptr)));
|
||||||
|
|
||||||
@@ -86,4 +90,7 @@ void CasterAoeShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
{
|
{
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("light aoe", NextAction::array(0, new NextAction("chain lightning", 25.0f), nullptr)));
|
new TriggerNode("light aoe", NextAction::array(0, new NextAction("chain lightning", 25.0f), nullptr)));
|
||||||
|
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("fire nova", 24.0f), nullptr)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public:
|
|||||||
creators["riptide"] = &riptide;
|
creators["riptide"] = &riptide;
|
||||||
creators["riptide on party"] = &riptide_on_party;
|
creators["riptide on party"] = &riptide_on_party;
|
||||||
creators["earth shock"] = &earth_shock;
|
creators["earth shock"] = &earth_shock;
|
||||||
|
creators["water shield"] = &water_shield;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -97,6 +98,15 @@ private:
|
|||||||
/*A*/ nullptr,
|
/*A*/ nullptr,
|
||||||
/*C*/ nullptr);
|
/*C*/ nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ActionNode* water_shield([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode("water shield",
|
||||||
|
/*P*/ nullptr,
|
||||||
|
/*A*/ NextAction::array(0, new NextAction("lightning shield"), nullptr),
|
||||||
|
/*C*/ nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GenericShamanStrategy::GenericShamanStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
GenericShamanStrategy::GenericShamanStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
||||||
|
|||||||
@@ -198,6 +198,13 @@ bool MyAttackerCountTrigger::IsActive()
|
|||||||
return AI_VALUE2(bool, "combat", "self target") && AI_VALUE(uint8, "my attacker count") >= amount;
|
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()
|
bool LowTankThreatTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* mt = AI_VALUE(Unit*, "main tank");
|
Unit* mt = AI_VALUE(Unit*, "main tank");
|
||||||
|
|||||||
@@ -243,10 +243,18 @@ public:
|
|||||||
std::string const getName() override { return "my attacker count"; }
|
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
|
class MediumThreatTrigger : public MyAttackerCountTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MediumThreatTrigger(PlayerbotAI* botAI) : MyAttackerCountTrigger(botAI, 2) {}
|
MediumThreatTrigger(PlayerbotAI* botAI) : MyAttackerCountTrigger(botAI, 2) {}
|
||||||
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LowTankThreatTrigger : public Trigger
|
class LowTankThreatTrigger : public Trigger
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ static float GetSpeedInMotion(Unit* target)
|
|||||||
bool EnemyTooCloseForSpellTrigger::IsActive()
|
bool EnemyTooCloseForSpellTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
return target && (target->GetVictim() != bot || target->isFrozen() || !target->CanFreeMove()) &&
|
return target && (target->GetVictim() != bot || target->isFrozen() || target->HasRootAura()) &&
|
||||||
target->GetObjectSize() <= 10.0f && target->IsWithinCombatRange(bot, MIN_MELEE_REACH);
|
target->GetObjectSize() <= 10.0f && target->IsWithinCombatRange(bot, MIN_MELEE_REACH);
|
||||||
// Unit* target = AI_VALUE(Unit*, "current target");
|
// Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
// if (!target) {
|
// if (!target) {
|
||||||
@@ -69,7 +69,7 @@ bool EnemyTooCloseForAutoShotTrigger::IsActive()
|
|||||||
if (spellId && bot->HasSpellCooldown(spellId))
|
if (spellId && bot->HasSpellCooldown(spellId))
|
||||||
trapToCast = false;
|
trapToCast = false;
|
||||||
|
|
||||||
return !trapToCast && (target->GetVictim() != bot || target->isFrozen() || !target->CanFreeMove()) &&
|
return !trapToCast && (target->GetVictim() != bot || target->isFrozen() || target->HasRootAura()) &&
|
||||||
bot->IsWithinMeleeRange(target);
|
bot->IsWithinMeleeRange(target);
|
||||||
|
|
||||||
// if (target->GetTarget() == bot->GetGUID() && !bot->GetGroup() && !target->HasUnitState(UNIT_STATE_ROOT) &&
|
// if (target->GetTarget() == bot->GetGUID() && !bot->GetGroup() && !target->HasUnitState(UNIT_STATE_ROOT) &&
|
||||||
@@ -100,7 +100,7 @@ bool EnemyTooCloseForShootTrigger::IsActive()
|
|||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
// target->IsWithinCombatRange()
|
// target->IsWithinCombatRange()
|
||||||
|
|
||||||
return target && (target->GetVictim() != bot || target->isFrozen() || !target->CanFreeMove()) &&
|
return target && (target->GetVictim() != bot || target->isFrozen() || target->HasRootAura()) &&
|
||||||
target->IsWithinCombatRange(bot, MIN_MELEE_REACH);
|
target->IsWithinCombatRange(bot, MIN_MELEE_REACH);
|
||||||
|
|
||||||
// Unit* target = AI_VALUE(Unit*, "current target");
|
// Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ public:
|
|||||||
creators["combo points not full"] = &TriggerContext::ComboPointsNotFull;
|
creators["combo points not full"] = &TriggerContext::ComboPointsNotFull;
|
||||||
creators["combo points not full and high energy"] = &TriggerContext::ComboPointsNotFullAndHighEnergy;
|
creators["combo points not full and high energy"] = &TriggerContext::ComboPointsNotFullAndHighEnergy;
|
||||||
|
|
||||||
|
creators["being attacked"] = &TriggerContext::BeingAttacked;
|
||||||
creators["medium threat"] = &TriggerContext::MediumThreat;
|
creators["medium threat"] = &TriggerContext::MediumThreat;
|
||||||
creators["low tank threat"] = &TriggerContext::low_tank_threat;
|
creators["low tank threat"] = &TriggerContext::low_tank_threat;
|
||||||
|
|
||||||
@@ -333,6 +334,7 @@ private:
|
|||||||
}
|
}
|
||||||
static Trigger* ComboPointsNotFull(PlayerbotAI* botAI) { return new ComboPointsNotFullTrigger(botAI); }
|
static Trigger* ComboPointsNotFull(PlayerbotAI* botAI) { return new ComboPointsNotFullTrigger(botAI); }
|
||||||
static Trigger* ComboPointsNotFullAndHighEnergy(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "combo points not full", "high energy available"); }
|
static Trigger* ComboPointsNotFullAndHighEnergy(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "combo points not full", "high energy available"); }
|
||||||
|
static Trigger* BeingAttacked(PlayerbotAI* botAI) { return new BeingAttackedTrigger(botAI); }
|
||||||
static Trigger* MediumThreat(PlayerbotAI* botAI) { return new MediumThreatTrigger(botAI); }
|
static Trigger* MediumThreat(PlayerbotAI* botAI) { return new MediumThreatTrigger(botAI); }
|
||||||
static Trigger* low_tank_threat(PlayerbotAI* botAI) { return new LowTankThreatTrigger(botAI); }
|
static Trigger* low_tank_threat(PlayerbotAI* botAI) { return new LowTankThreatTrigger(botAI); }
|
||||||
// static Trigger* MediumThreat(PlayerbotAI* botAI) { return new MediumThreatTrigger(botAI); }
|
// static Trigger* MediumThreat(PlayerbotAI* botAI) { return new MediumThreatTrigger(botAI); }
|
||||||
|
|||||||
Reference in New Issue
Block a user