mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 17:09:08 +00:00
Compare commits
4 Commits
02e8465a3b
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
965d300203 | ||
|
|
dc55ecfd9c | ||
|
|
59d6eb139e | ||
|
|
00171a8c82 |
@@ -21,7 +21,7 @@
|
||||
# THRESHOLDS
|
||||
# QUESTS
|
||||
# COMBAT
|
||||
# PALADIN BUFFS STRATEGIES
|
||||
# GREATER BUFFS STRATEGIES
|
||||
# CHEATS
|
||||
# SPELLS
|
||||
# FLIGHTPATH
|
||||
@@ -91,17 +91,20 @@ AiPlayerbot.MinRandomBots = 500
|
||||
AiPlayerbot.MaxRandomBots = 500
|
||||
|
||||
# Randombot accounts
|
||||
# If you are not using any expansion at all, you may have to set this manually, in which case please ensure that RandomBotAccountCount is at least greater than (MaxRandomBots / 10 + AddClassAccountPoolSize)
|
||||
# If you are not using any expansion at all, you may have to set this manually, in which case please
|
||||
# ensure that RandomBotAccountCount is at least greater than (MaxRandomBots / 10 + AddClassAccountPoolSize)
|
||||
# Default: 0 (automatic)
|
||||
AiPlayerbot.RandomBotAccountCount = 0
|
||||
|
||||
# Delete all randombot accounts
|
||||
# To apply this, set the number to 1 and run the Worldserver. Once deletion is complete, if you would like to recreate randombots, set the number back to 0 and rerun the Worldserver.
|
||||
# To apply this, set the number to 1 and run the Worldserver. Once deletion is complete, if you would
|
||||
# like to recreate randombots, set the number back to 0 and rerun the Worldserver.
|
||||
AiPlayerbot.DeleteRandomBotAccounts = 0
|
||||
|
||||
# Disable randombots when no real players are logged in
|
||||
# Default: 0 (randombots will login when server starts)
|
||||
# If enabled, randombots will only log in 30 seconds (default) after a real player logs in, and will log out 300 seconds (default) after all real players log out
|
||||
# If enabled, randombots will only log in 30 seconds (default) after a real player logs in, and will
|
||||
# log out 300 seconds (default) after all real players log out
|
||||
AiPlayerbot.DisabledWithoutRealPlayer = 0
|
||||
AiPlayerbot.DisabledWithoutRealPlayerLoginDelay = 30
|
||||
AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay = 300
|
||||
@@ -153,7 +156,8 @@ AiPlayerbot.AllowGuildBots = 1
|
||||
AiPlayerbot.AllowTrustedAccountBots = 1
|
||||
|
||||
# Randombots will create guilds with nearby randombots
|
||||
# Note: currently, randombots will not invite more bots after a guild is created (i.e., randombot guilds will have only the 10 initial randombots needed to sign the charter)
|
||||
# Note: currently, randombots will not invite more bots after a guild is created,
|
||||
# meaning randombot guilds will have only the 10 initial randombots needed to sign the charter
|
||||
# Default: 0 (disabled)
|
||||
AiPlayerbot.RandomBotGuildNearby = 0
|
||||
|
||||
@@ -187,7 +191,8 @@ AiPlayerbot.AutoInitOnly = 0
|
||||
# Default: 1.0 (same with the player)
|
||||
AiPlayerbot.AutoInitEquipLevelLimitRatio = 1.0
|
||||
|
||||
# Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells)
|
||||
# Bot automatically trains spells when talking to trainer
|
||||
# yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells
|
||||
AiPlayerbot.AutoTrainSpells = yes
|
||||
|
||||
#
|
||||
@@ -264,7 +269,7 @@ AiPlayerbot.UseFastFlyMountAtMinLevel = 70
|
||||
AiPlayerbot.RandomBotShowHelmet = 1
|
||||
AiPlayerbot.RandomBotShowCloak = 1
|
||||
|
||||
# Randombots and altbots automatically equip upgrades (bots will equip any item obtained from looting or a quest if they are sufficient upgrades)
|
||||
# Randombots and altbots automatically equip any items in their inventory that are sufficient upgrades
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.AutoEquipUpgradeLoot = 1
|
||||
|
||||
@@ -312,7 +317,8 @@ AiPlayerbot.GlobalCooldown = 500
|
||||
# Max wait time when moving
|
||||
AiPlayerbot.MaxWaitForMove = 5000
|
||||
|
||||
# Disable use of MoveSplinePath for bot movement, will result in more erratic bot movement but means stun/snare/root/etc will work on bots (they wont reliably work when MoveSplinePath is enabled, though slowing effects still work ok)
|
||||
# Enable/disable use of MoveSplinePath for bot movement
|
||||
# Disabling will result in more erratic movement but is required for stuns, snares, and roots to work on bots
|
||||
# Default: 0 - MoveSplinePath enabled
|
||||
# 1 - MoveSplinePath disabled in BG/Arena only
|
||||
# 2 - MoveSplinePath disabled everywhere
|
||||
@@ -406,10 +412,11 @@ AiPlayerbot.HighMana = 65
|
||||
#
|
||||
#
|
||||
|
||||
# Bots pick their quest rewards (yes = picks the most useful item, no = list all rewards, ask = pick useful item and lists if multiple)
|
||||
# Bots pick their quest rewards
|
||||
# yes = picks the most useful item, no = list all rewards, ask = pick useful item and lists if multiple
|
||||
AiPlayerbot.AutoPickReward = yes
|
||||
|
||||
# Sync quests with player (Bots will complete quests the moment you hand them in and will not loot quest items.)
|
||||
# Sync quests with player (bots will complete quests the moment you hand them in and will not loot quest items.)
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.SyncQuestWithPlayer = 1
|
||||
|
||||
@@ -434,7 +441,7 @@ AiPlayerbot.DropObsoleteQuests = 1
|
||||
# Auto add dungeon/raid strategies when entering the instance if implemented
|
||||
AiPlayerbot.ApplyInstanceStrategies = 1
|
||||
|
||||
# Enable auto avoid aoe strategy (experimental)
|
||||
# Enable auto avoid aoe strategy
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.AutoAvoidAoe = 1
|
||||
|
||||
@@ -461,7 +468,7 @@ AiPlayerbot.FleeingEnabled = 1
|
||||
####################################################################################################
|
||||
|
||||
####################################################################################################
|
||||
# PALADIN BUFFS STRATEGIES
|
||||
# GREATER BUFFS STRATEGIES
|
||||
#
|
||||
#
|
||||
|
||||
@@ -484,12 +491,13 @@ AiPlayerbot.RPWarningCooldown = 30
|
||||
#
|
||||
|
||||
# Enable/Disable maintenance command
|
||||
# Learn all available spells and skills, refresh consumables, repair, enchant equipment and socket gems if bot's level is above AiPlayerbot.MinEnchantingBotLevel
|
||||
# Learn all available spells and skills, assign talent points, refresh consumables, repair, enchant equipment, socket gems, etc.
|
||||
# Applies if bot's level is above AiPlayerbot.MinEnchantingBotLevel
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.MaintenanceCommand = 1
|
||||
|
||||
# Enable/Disable specific maintenance command functionality for alt bots
|
||||
# Disable to prevent players from giving free bags, spells, skill levels etc to their alt bots
|
||||
# Disable to prevent players from giving free bags, spells, skill levels, etc. to their alt bots
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.AltMaintenanceAmmo = 1
|
||||
AiPlayerbot.AltMaintenanceFood = 1
|
||||
@@ -501,6 +509,7 @@ AiPlayerbot.AltMaintenanceBags = 1
|
||||
AiPlayerbot.AltMaintenanceMounts = 1
|
||||
AiPlayerbot.AltMaintenanceSkills = 1
|
||||
|
||||
# "Special Spells" consist of any spells listed in AiPlayerbot.RandomBotSpellIds and Death Gate for Death Knights
|
||||
AiPlayerbot.AltMaintenanceClassSpells = 1
|
||||
AiPlayerbot.AltMaintenanceAvailableSpells = 1
|
||||
AiPlayerbot.AltMaintenanceSpecialSpells = 1
|
||||
@@ -515,8 +524,8 @@ AiPlayerbot.AltMaintenanceReputation = 1
|
||||
AiPlayerbot.AltMaintenanceAttunementQuests = 1
|
||||
AiPlayerbot.AltMaintenanceKeyring = 1
|
||||
|
||||
|
||||
# Enable/Disable autogear command, which automatically upgrades bots' gear; the quality is limited by AutoGearQualityLimit and AutoGearScoreLimit
|
||||
# Enable/Disable autogear command, which automatically upgrades bots' gear
|
||||
# The quality is limited by AutoGearQualityLimit and AutoGearScoreLimit
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.AutoGearCommand = 1
|
||||
|
||||
@@ -582,15 +591,21 @@ AiPlayerbot.BotTaxiGapJitterMs = 100
|
||||
|
||||
####################################################################################################
|
||||
# PROFESSIONS
|
||||
# Random bots currently do not get professions.
|
||||
# Note: Random bots currently do not get professions
|
||||
#
|
||||
|
||||
# EnableFishingWithMaster automatically adds the 'master fishing' strategy to bots that can fish that can.
|
||||
# Automatically adds the 'master fishing' strategy to bots that have the fishing skill when the bots master fishes.
|
||||
# Default: 1 (Enabled)
|
||||
AiPlayerbot.EnableFishingWithMaster = 1
|
||||
#FishingDistance sets how far a bot without a master will search for water, while FishingDistanceFromMaster limits it to a closer range, and overrides the following distance to the same value. EndFishingWithMaster sets the distance from water a bot needs to have to automatically drop the 'master fishing' strategy.
|
||||
|
||||
# Distance from itself (in yards) that a bot with a master will search for water to fish
|
||||
AiPlayerbot.FishingDistanceFromMaster = 10.0
|
||||
|
||||
# Distance from itself (in yards) that a bot without a master will search for water to fish
|
||||
# Currently not relevant since masterless bots will not fish
|
||||
AiPlayerbot.FishingDistance = 40.0
|
||||
|
||||
# Distance from water (in yards) beyond which a bot will remove the 'master fishing' strategy
|
||||
AiPlayerbot.EndFishingWithMaster = 30.0
|
||||
|
||||
#
|
||||
@@ -719,7 +734,7 @@ AiPlayerbot.RandomGearQualityLimit = 3
|
||||
# Max iLVL Phase 1(MC, Ony, ZG) = 78 | Phase 2(BWL) = 83 | Phase 2.5(AQ40) = 88 | Phase 3(Naxx40) = 92
|
||||
# TBC
|
||||
# Max iLVL Tier 4 = 120 | Tier 5 = 133 | Tier 6 = 164
|
||||
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 1.5(ZA) = 138 | Phase 2(SC, TK) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
||||
# Max iLVL Phase 1(Kara, Gruul, Mag) = 125 | Phase 2(SSC, TK, ZA) = 141 | Phase 3(Hyjal, BT) = 156 | Phase 4(Sunwell) = 164
|
||||
# Wotlk
|
||||
# Max iLVL Tier 7(10/25) = 200/213 | Tier 8(10/25) = 225/232 | Tier 9(10/25) = 232/245 | Tier 10(10/25/HC) = 251/264/290
|
||||
# Max iLVL Phase 1(Naxx) = 224 | Phase 2(Ulduar) = 245 | Phase 3(ToC) = 258 | Phase 4(ICC) = 290
|
||||
@@ -730,7 +745,8 @@ AiPlayerbot.RandomGearScoreLimit = 0
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.IncrementalGearInit = 1
|
||||
|
||||
# Set minimum level of bots that will enchant their equipment (if greater than RandomBotMaxlevel, bots will not enchant equipment)
|
||||
# Set minimum level of bots that will enchant and socket gems into their equipment with maintenance
|
||||
# If greater than RandomBotMaxlevel, bots will not automatically enchant equipment or socket gems
|
||||
# Default: 60
|
||||
AiPlayerbot.MinEnchantingBotLevel = 60
|
||||
|
||||
@@ -882,13 +898,15 @@ AiPlayerbot.OpenGoSpell = 6477
|
||||
#
|
||||
|
||||
# Additional randombot strategies
|
||||
# Strategies added here are applied to all randombots, in addition (or subtraction) to spec/role-based default strategies. These rules are processed after the defaults.
|
||||
# Strategies added here are applied to all randombots, in addition (or subtraction) to spec/role-based default strategies.
|
||||
# These rules are processed after the defaults.
|
||||
# Example: "+threat,-potions"
|
||||
AiPlayerbot.RandomBotCombatStrategies = ""
|
||||
AiPlayerbot.RandomBotNonCombatStrategies = ""
|
||||
|
||||
# Additional altbot strategies
|
||||
# Strategies added here are applied to all altbots, in addition (or subtraction) to spec/role-based default strategies. These rules are processed after the defaults.
|
||||
# Strategies added here are applied to all altbots, in addition (or subtraction) to spec/role-based default strategies.
|
||||
# These rules are processed after the defaults.
|
||||
AiPlayerbot.CombatStrategies = ""
|
||||
AiPlayerbot.NonCombatStrategies = ""
|
||||
|
||||
|
||||
@@ -122,7 +122,11 @@ void PlayerbotFactory::Init()
|
||||
uint32 maxStoreSize = sSpellMgr->GetSpellInfoStoreSize();
|
||||
for (uint32 id = 1; id < maxStoreSize; ++id)
|
||||
{
|
||||
if (id == 47181 || id == 50358 || id == 47242 || id == 52639 || id == 47147 || id == 7218) // Test Enchant
|
||||
if (id == 7218 || id == 19927 || id == 44119 || id == 47147 || id == 47181 ||
|
||||
id == 47242 || id == 50358 || id == 52639) // Test Enchants
|
||||
continue;
|
||||
|
||||
if (id == 35791 || id == 39405) // Grandfathered TBC Enchants
|
||||
continue;
|
||||
|
||||
if (id == 15463 || id == 15490) // Legendary Arcane Amalgamation
|
||||
|
||||
@@ -90,18 +90,25 @@ void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out)
|
||||
//uint32 questId = i->first; //not used, line marked for removal.
|
||||
Quest const* quest = i->second;
|
||||
|
||||
if (!quest->GetRequiredClasses() || quest->IsRepeatable() || quest->GetMinLevel() < 10)
|
||||
// only process class-specific quests to learn class-related spells, cuz
|
||||
// we don't want all these bunch of entries to be handled!
|
||||
if (!quest->GetRequiredClasses())
|
||||
continue;
|
||||
|
||||
if (!bot->SatisfyQuestClass(quest, false) || quest->GetMinLevel() > bot->GetLevel() ||
|
||||
!bot->SatisfyQuestRace(quest, false))
|
||||
// skip quests that are repeatable, too low level, or above bots' level
|
||||
if (quest->IsRepeatable() || quest->GetMinLevel() < 10 || quest->GetMinLevel() > bot->GetLevel())
|
||||
continue;
|
||||
|
||||
if (quest->GetRewSpellCast() > 0)
|
||||
// skip if bot doesnt satisfy class, race, or skill requirements
|
||||
if (!bot->SatisfyQuestClass(quest, false) || !bot->SatisfyQuestRace(quest, false) ||
|
||||
!bot->SatisfyQuestSkill(quest, false))
|
||||
continue;
|
||||
|
||||
if (quest->GetRewSpellCast() > 0) // RewardSpell - expected route
|
||||
{
|
||||
LearnSpell(quest->GetRewSpellCast(), out);
|
||||
}
|
||||
else if (quest->GetRewSpell() > 0)
|
||||
else if (quest->GetRewSpell() > 0) // RewardDisplaySpell - fallback
|
||||
{
|
||||
LearnSpell(quest->GetRewSpell(), out);
|
||||
}
|
||||
@@ -123,35 +130,37 @@ std::string const AutoMaintenanceOnLevelupAction::FormatSpell(SpellInfo const* s
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::LearnSpell(uint32 spellId, std::ostringstream* out)
|
||||
{
|
||||
SpellInfo const* proto = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!proto)
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
return;
|
||||
|
||||
bool learned = false;
|
||||
for (uint8 j = 0; j < 3; ++j)
|
||||
SpellInfo const* triggeredInfo;
|
||||
|
||||
// find effect with learn spell and check if we have this spell
|
||||
bool found = false;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (proto->Effects[j].Effect == SPELL_EFFECT_LEARN_SPELL)
|
||||
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL && spellInfo->Effects[i].TriggerSpell &&
|
||||
!bot->HasSpell(spellInfo->Effects[i].TriggerSpell))
|
||||
{
|
||||
uint32 learnedSpell = proto->Effects[j].TriggerSpell;
|
||||
triggeredInfo = sSpellMgr->GetSpellInfo(spellInfo->Effects[i].TriggerSpell);
|
||||
|
||||
if (!bot->HasSpell(learnedSpell))
|
||||
{
|
||||
bot->learnSpell(learnedSpell);
|
||||
*out << FormatSpell(sSpellMgr->GetSpellInfo(learnedSpell)) << ", ";
|
||||
}
|
||||
// do not learn profession specialties!
|
||||
if (!triggeredInfo || triggeredInfo->Effects[0].Effect == SPELL_EFFECT_TRADE_SKILL)
|
||||
break;
|
||||
|
||||
learned = true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!learned)
|
||||
{
|
||||
if (!bot->HasSpell(spellId))
|
||||
{
|
||||
bot->learnSpell(spellId);
|
||||
*out << FormatSpell(proto) << ", ";
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return;
|
||||
|
||||
// NOTE: When rewarding quests, core casts spells instead of learning them,
|
||||
// but we sacrifice safe cast checks here in favor of performance/speed
|
||||
bot->learnSpell(triggeredInfo->Id);
|
||||
*out << FormatSpell(triggeredInfo) << ", ";
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
|
||||
bool NearestEnemyPlayersValue::AcceptUnit(Unit* unit)
|
||||
{
|
||||
// Apply parent's filtering first (includes level difference checks)
|
||||
if (!PossibleTargetsValue::AcceptUnit(unit))
|
||||
return false;
|
||||
|
||||
bool inCannon = botAI->IsInVehicle(false, true);
|
||||
Player* enemy = dynamic_cast<Player*>(unit);
|
||||
if (enemy && botAI->IsOpposing(enemy) && enemy->IsPvP() &&
|
||||
@@ -23,14 +19,7 @@ bool NearestEnemyPlayersValue::AcceptUnit(Unit* unit)
|
||||
((inCannon || !enemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))) &&
|
||||
/*!enemy->HasStealthAura() && !enemy->HasInvisibilityAura()*/ enemy->CanSeeOrDetect(bot) &&
|
||||
!(enemy->HasSpiritOfRedemptionAura()))
|
||||
{
|
||||
// If with master, only attack if master is PvP flagged
|
||||
Player* master = botAI->GetMaster();
|
||||
if (master && !master->IsPvP() && !master->IsFFAPvP())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -16,32 +16,6 @@
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Unit.h"
|
||||
#include "AreaDefines.h"
|
||||
#include <unordered_map>
|
||||
|
||||
// Level difference thresholds for attack probability
|
||||
constexpr int32 EXTREME_LEVEL_DIFF = 5; // Don't attack if enemy is this much higher
|
||||
constexpr int32 HIGH_LEVEL_DIFF = 4; // 25% chance at +/- this difference
|
||||
constexpr int32 MID_LEVEL_DIFF = 3; // 50% chance at +/- this difference
|
||||
constexpr int32 LOW_LEVEL_DIFF = 2; // 75% chance at +/- this difference
|
||||
|
||||
// Cache duration before reconsidering attack decision, and old cache cleanup interval
|
||||
constexpr uint32 ATTACK_DECISION_CACHE_DURATION = 2 * MINUTE;
|
||||
constexpr uint32 ATTACK_DECISION_CACHE_CLEANUP_INTERVAL = 10 * MINUTE;
|
||||
|
||||
// Custom hash function for (botGUID, targetGUID) pairs
|
||||
struct PairGuidHash
|
||||
{
|
||||
std::size_t operator()(const std::pair<ObjectGuid, ObjectGuid>& pair) const
|
||||
{
|
||||
return std::hash<uint64>()(pair.first.GetRawValue()) ^
|
||||
(std::hash<uint64>()(pair.second.GetRawValue()) << 1);
|
||||
}
|
||||
};
|
||||
|
||||
// Cache for probability-based attack decisions (Per-bot: non-global)
|
||||
// Map: (botGUID, targetGUID) -> (should attack decision, timestamp)
|
||||
static std::unordered_map<std::pair<ObjectGuid, ObjectGuid>, std::pair<bool, time_t>, PairGuidHash> attackDecisionCache;
|
||||
|
||||
void PossibleTargetsValue::FindUnits(std::list<Unit*>& targets)
|
||||
{
|
||||
@@ -50,117 +24,7 @@ void PossibleTargetsValue::FindUnits(std::list<Unit*>& targets)
|
||||
Cell::VisitObjects(bot, searcher, range);
|
||||
}
|
||||
|
||||
static void CleanupAttackDecisionCache()
|
||||
{
|
||||
time_t currentTime = time(nullptr);
|
||||
for (auto it = attackDecisionCache.begin(); it != attackDecisionCache.end();)
|
||||
{
|
||||
if (currentTime - it->second.second >= ATTACK_DECISION_CACHE_DURATION)
|
||||
it = attackDecisionCache.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
bool PossibleTargetsValue::AcceptUnit(Unit* unit)
|
||||
{
|
||||
// attackDecisionCache cleanup
|
||||
static time_t lastCleanup = 0;
|
||||
time_t currentTime = time(nullptr);
|
||||
if (currentTime - lastCleanup > ATTACK_DECISION_CACHE_CLEANUP_INTERVAL)
|
||||
{
|
||||
CleanupAttackDecisionCache();
|
||||
lastCleanup = currentTime;
|
||||
}
|
||||
|
||||
if (!AttackersValue::IsPossibleTarget(unit, bot, range))
|
||||
return false;
|
||||
|
||||
// Level-based PvP restrictions
|
||||
if (unit->IsPlayer())
|
||||
{
|
||||
// Self-defense - always allow fighting back
|
||||
if (bot->IsInCombat() && bot->GetVictim() == unit)
|
||||
return true; // Already fighting
|
||||
|
||||
Unit* botAttacker = bot->getAttackerForHelper();
|
||||
if (botAttacker)
|
||||
{
|
||||
if (botAttacker == unit)
|
||||
return true; // Enemy attacking
|
||||
|
||||
if (botAttacker->IsPet())
|
||||
{
|
||||
Unit* petOwner = botAttacker->GetOwner();
|
||||
if (petOwner && petOwner == unit)
|
||||
return true; // Enemy's pet attacking
|
||||
}
|
||||
}
|
||||
|
||||
// Skip restrictions in BG/Arena
|
||||
if (bot->InBattleground() || bot->InArena())
|
||||
return true;
|
||||
|
||||
// Skip restrictions if in duel with this player
|
||||
if (bot->duel && bot->duel->Opponent == unit)
|
||||
return true;
|
||||
|
||||
// Capital cities - no restrictions
|
||||
uint32 zoneId = bot->GetZoneId();
|
||||
bool inCapitalCity = (zoneId == AREA_STORMWIND_CITY ||
|
||||
zoneId == AREA_IRONFORGE ||
|
||||
zoneId == AREA_DARNASSUS ||
|
||||
zoneId == AREA_THE_EXODAR ||
|
||||
zoneId == AREA_ORGRIMMAR ||
|
||||
zoneId == AREA_THUNDER_BLUFF ||
|
||||
zoneId == AREA_UNDERCITY ||
|
||||
zoneId == AREA_SILVERMOON_CITY);
|
||||
|
||||
if (inCapitalCity)
|
||||
return true;
|
||||
|
||||
// Level difference check
|
||||
int32 levelDifference = unit->GetLevel() - bot->GetLevel();
|
||||
int32 absLevelDifference = std::abs(levelDifference);
|
||||
|
||||
// Extreme difference - do not attack
|
||||
if (levelDifference >= EXTREME_LEVEL_DIFF)
|
||||
return false;
|
||||
|
||||
// Calculate attack chance based on level difference
|
||||
uint32 attackChance = 100; // Default 100%: Bot and target's levels are very close
|
||||
|
||||
// There's a chance a bot might gank on an extremly low target
|
||||
if ((absLevelDifference < EXTREME_LEVEL_DIFF && absLevelDifference >= HIGH_LEVEL_DIFF) ||
|
||||
levelDifference <= -EXTREME_LEVEL_DIFF)
|
||||
attackChance = 25;
|
||||
|
||||
else if (absLevelDifference < HIGH_LEVEL_DIFF && absLevelDifference >= MID_LEVEL_DIFF)
|
||||
attackChance = 50;
|
||||
|
||||
else if (absLevelDifference < MID_LEVEL_DIFF && absLevelDifference >= LOW_LEVEL_DIFF)
|
||||
attackChance = 75;
|
||||
|
||||
// If probability check needed, use cache
|
||||
if (attackChance < 100)
|
||||
{
|
||||
std::pair<ObjectGuid, ObjectGuid> cacheKey = std::make_pair(bot->GetGUID(), unit->GetGUID());
|
||||
|
||||
auto it = attackDecisionCache.find(cacheKey);
|
||||
if (it != attackDecisionCache.end())
|
||||
{
|
||||
if (currentTime - it->second.second < ATTACK_DECISION_CACHE_DURATION)
|
||||
return it->second.first;
|
||||
}
|
||||
|
||||
bool shouldAttack = (urand(1, 100) <= attackChance);
|
||||
attackDecisionCache[cacheKey] = std::make_pair(shouldAttack, currentTime);
|
||||
return shouldAttack;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool PossibleTargetsValue::AcceptUnit(Unit* unit) { return AttackersValue::IsPossibleTarget(unit, bot, range); }
|
||||
|
||||
void PossibleTriggersValue::FindUnits(std::list<Unit*>& targets)
|
||||
{
|
||||
@@ -172,8 +36,9 @@ void PossibleTriggersValue::FindUnits(std::list<Unit*>& targets)
|
||||
bool PossibleTriggersValue::AcceptUnit(Unit* unit)
|
||||
{
|
||||
if (!unit->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
|
||||
{
|
||||
return false;
|
||||
|
||||
}
|
||||
Unit::AuraEffectList const& aurasPeriodicTriggerSpell =
|
||||
unit->GetAuraEffectsByType(SPELL_AURA_PERIODIC_TRIGGER_SPELL);
|
||||
Unit::AuraEffectList const& aurasPeriodicTriggerWithValueSpell =
|
||||
@@ -193,7 +58,9 @@ bool PossibleTriggersValue::AcceptUnit(Unit* unit)
|
||||
for (int j = 0; j < MAX_SPELL_EFFECTS; j++)
|
||||
{
|
||||
if (triggerSpellInfo->Effects[j].Effect == SPELL_EFFECT_SCHOOL_DAMAGE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user