mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Compare commits
1 Commits
hermensbas
...
hermensbas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad6c9cb1bc |
@@ -67,7 +67,7 @@
|
||||
|
||||
###################################
|
||||
# #
|
||||
# GENERAL SETTINGS #
|
||||
# GENERAL SETTINGS #
|
||||
# #
|
||||
###################################
|
||||
|
||||
@@ -368,10 +368,6 @@ AiPlayerbot.SyncQuestWithPlayer = 1
|
||||
# Default: 0 (disabled)
|
||||
AiPlayerbot.SyncQuestForPlayer = 0
|
||||
|
||||
# Bots will drop obsolete quests
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.DropObsoleteQuests = 1
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
@@ -424,10 +420,6 @@ AiPlayerbot.MaintenanceCommand = 1
|
||||
# default: 1 (enable)
|
||||
AiPlayerbot.AutoGearCommand = 1
|
||||
|
||||
# Enable/Disable autogear command on player alt bots
|
||||
# Default: 1 (enable)
|
||||
AiPlayerbot.AutoGearCommandAltBots = 1
|
||||
|
||||
# Equips quality limitation for auto gear command (1 = normal, 2 = uncommon, 3 = rare, 4 = epic, 5 = legendary)
|
||||
# default: 3 (rare)
|
||||
AiPlayerbot.AutoGearQualityLimit = 3
|
||||
@@ -596,11 +588,6 @@ AiPlayerbot.RandomBotGroupNearby = 0
|
||||
# Default: 1 (enabled)
|
||||
AiPlayerbot.AutoDoQuests = 1
|
||||
|
||||
# Random Bots will behave more like real players (exprimental)
|
||||
# This option will override AutoDoQuests
|
||||
# Default: 0 (disabled)
|
||||
AiPlayerbot.EnableNewRpgStrategy = 0
|
||||
|
||||
# Quest items to leave (do not destroy)
|
||||
AiPlayerbot.RandomBotQuestItems = "6948,5175,5176,5177,5178,16309,12382,13704,11000"
|
||||
|
||||
@@ -722,10 +709,10 @@ AiPlayerbot.RandomBotArenaTeamMinRating = 1000
|
||||
AiPlayerbot.DeleteRandomBotArenaTeams = 0
|
||||
|
||||
# PvP Restricted Zones (bots don't pvp)
|
||||
AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703,4298,139"
|
||||
AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703,4298"
|
||||
|
||||
# PvP Restricted Areas (bots don't pvp)
|
||||
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268"
|
||||
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392"
|
||||
|
||||
# Improve react speed in battleground and arena (may cause lag)
|
||||
AiPlayerbot.FastReactInBG = 1
|
||||
@@ -1035,56 +1022,6 @@ AiPlayerbot.PremadeSpecLink.11.3.80 = -553202032322010053100030310511-205503012
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
###################################
|
||||
# #
|
||||
# WORLD BUFFS #
|
||||
# #
|
||||
###################################
|
||||
|
||||
####################################################################################################
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
# Applies a permanent buff to all bots when not in combat simulating flasks, food, rune etc.
|
||||
# WorldBuff.Faction.Class.Spec.MinLevel.MaxLevel
|
||||
|
||||
AiPlayerbot.WorldBuff.0.1.0.80.80 = 53760,57358 #WARRIOR ARMS
|
||||
AiPlayerbot.WorldBuff.0.1.1.80.80 = 53760,57358 #WARRIOR FURY
|
||||
AiPlayerbot.WorldBuff.0.1.2.80.80 = 53758,57356 #WARRIOR PROTECTION
|
||||
AiPlayerbot.WorldBuff.0.2.0.80.80 = 60347,53749,57332 #PALADIN HOLY
|
||||
AiPlayerbot.WorldBuff.0.2.1.80.80 = 53758,57356 #PALADIN PROTECTION
|
||||
AiPlayerbot.WorldBuff.0.2.2.80.80 = 53760,57371 #PALADIN RETRIBUTION
|
||||
AiPlayerbot.WorldBuff.0.3.0.80.80 = 53760,57325 #HUNTER BEAST
|
||||
AiPlayerbot.WorldBuff.0.3.1.80.80 = 53760,57358 #HUNTER MARKSMANSHIP
|
||||
AiPlayerbot.WorldBuff.0.3.2.80.80 = 53760,57367 #HUNTER SURVIVAL
|
||||
AiPlayerbot.WorldBuff.0.4.0.80.80 = 53760,57325 #ROGUE ASSASINATION
|
||||
AiPlayerbot.WorldBuff.0.4.1.80.80 = 53760,57358 #ROGUE COMBAT
|
||||
AiPlayerbot.WorldBuff.0.4.2.80.80 = 53760,57367 #ROGUE SUBTLETY
|
||||
AiPlayerbot.WorldBuff.0.5.0.80.80 = 53755,57327 #PRIEST DISCIPLINE
|
||||
AiPlayerbot.WorldBuff.0.5.1.80.80 = 53755,57327 #PRIEST HOLY
|
||||
AiPlayerbot.WorldBuff.0.5.2.80.80 = 53755,57327 #PRIEST SHADOW
|
||||
AiPlayerbot.WorldBuff.0.6.0.80.80 = 53758,57356 #DEATH KNIGHT BLOOD
|
||||
AiPlayerbot.WorldBuff.0.6.1.80.80 = 53760,57358 #DEATH KNIGHT FROST
|
||||
AiPlayerbot.WorldBuff.0.6.2.80.80 = 53760,57358 #DEATH KNIGHT UNHOLY
|
||||
AiPlayerbot.WorldBuff.0.7.0.80.80 = 53755,57327 #SHAMAN ELEMENTAL
|
||||
AiPlayerbot.WorldBuff.0.7.1.80.80 = 53760,57325 #SHAMAN ENHANCEMENT
|
||||
AiPlayerbot.WorldBuff.0.7.2.80.80 = 53755,57327 #SHAMAN RESTORATION
|
||||
AiPlayerbot.WorldBuff.0.8.0.80.80 = 53755,57327 #MAGE ARCANE
|
||||
AiPlayerbot.WorldBuff.0.8.1.80.80 = 53755,57327 #MAGE FIRE
|
||||
AiPlayerbot.WorldBuff.0.8.2.80.80 = 53755,57327 #MAGE FROST
|
||||
AiPlayerbot.WorldBuff.0.9.0.80.80 = 53755,57327 #WARLOCK AFFLICTION
|
||||
AiPlayerbot.WorldBuff.0.9.1.80.80 = 53755,57327 #WARLOCK DEMONOLOGY
|
||||
AiPlayerbot.WorldBuff.0.9.2.80.80 = 53755,57327 #WARLOCK DESTRUCTION
|
||||
AiPlayerbot.WorldBuff.0.11.0.80.80 = 53755,57327 #DRUID BALANCE
|
||||
AiPlayerbot.WorldBuff.0.11.1.80.80 = 53749,53763,57367 #DRUID FERAL
|
||||
AiPlayerbot.WorldBuff.0.11.2.80.80 = 54212,57334 #DRUID RESTORATION
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
###################################
|
||||
# #
|
||||
# RANDOM BOT DEFAULT TALENT SPEC #
|
||||
@@ -1474,6 +1411,9 @@ AiPlayerbot.BroadcastChanceGuildManagement = 30000
|
||||
# Example: AiPlayerbot.AllowedLogFiles = travelNodes.csv,travelPaths.csv,TravelNodeStore.h,bot_movement.csv,bot_location.csv
|
||||
AiPlayerbot.AllowedLogFiles = ""
|
||||
|
||||
Appender.Playerbots=2,5,0,Playerbots.log,w
|
||||
Logger.playerbots=5,Console Playerbots
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
@@ -1520,13 +1460,6 @@ AiPlayerbot.RandombotsWalkingRPG.InDoors = 0
|
||||
# enforced to 100%
|
||||
AiPlayerbot.BotActiveAlone = 100
|
||||
|
||||
# Force botActiveAlone when bot is ... of real player
|
||||
AiPlayerbot.BotActiveAloneForceWhenInRadius = 150
|
||||
AiPlayerbot.BotActiveAloneForceWhenInZone = 1
|
||||
AiPlayerbot.BotActiveAloneForceWhenInMap = 0
|
||||
AiPlayerbot.BotActiveAloneForceWhenIsFriend = 1
|
||||
AiPlayerbot.BotActiveAloneForceWhenInGuild = 1
|
||||
|
||||
# Specify smart scaling is enabled or not.
|
||||
# The default is 1. When enabled (smart) scales the 'BotActiveAlone' value.
|
||||
# Only when botLevel is between WhenMinLevel and WhenMaxLevel.
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
UPDATE `updates_include`
|
||||
SET `path` = '$/data/sql/playerbots/updates'
|
||||
WHERE `state` = 'RELEASED';
|
||||
|
||||
UPDATE `updates_include`
|
||||
SET `path` = '$/data/sql/playerbots/custom'
|
||||
WHERE `state` = 'CUSTOM';
|
||||
|
||||
UPDATE `updates_include`
|
||||
SET `path` = '$/data/sql/playerbots/archive'
|
||||
WHERE `state` = 'ARCHIVED';
|
||||
@@ -631,11 +631,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
// nonCombatEngine->addStrategy("group");
|
||||
// nonCombatEngine->addStrategy("guild");
|
||||
|
||||
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
||||
{
|
||||
nonCombatEngine->addStrategy("new rpg", false);
|
||||
}
|
||||
else if (sPlayerbotAIConfig->autoDoQuests)
|
||||
if (sPlayerbotAIConfig->autoDoQuests)
|
||||
{
|
||||
// nonCombatEngine->addStrategy("travel");
|
||||
nonCombatEngine->addStrategy("rpg", false);
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "MotionMaster.h"
|
||||
#include "MoveSpline.h"
|
||||
#include "MoveSplineInit.h"
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "PerformanceMonitor.h"
|
||||
#include "Player.h"
|
||||
@@ -39,7 +38,6 @@
|
||||
#include "Playerbots.h"
|
||||
#include "PointMovementGenerator.h"
|
||||
#include "PositionValue.h"
|
||||
#include "RandomPlayerbotMgr.h"
|
||||
#include "SayAction.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ServerFacade.h"
|
||||
@@ -720,7 +718,7 @@ void PlayerbotAI::HandleTeleportAck()
|
||||
// SetNextCheckDelay(urand(2000, 5000));
|
||||
if (sPlayerbotAIConfig->applyInstanceStrategies)
|
||||
ApplyInstanceStrategies(bot->GetMapId(), true);
|
||||
Reset(true);
|
||||
Reset();
|
||||
}
|
||||
|
||||
SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown);
|
||||
@@ -769,15 +767,14 @@ void PlayerbotAI::Reset(bool full)
|
||||
->setTarget(sTravelMgr->nullTravelDestination, sTravelMgr->nullWorldPosition, true);
|
||||
aiObjectContext->GetValue<TravelTarget*>("travel target")->Get()->setStatus(TRAVEL_STATUS_EXPIRED);
|
||||
aiObjectContext->GetValue<TravelTarget*>("travel target")->Get()->setExpireIn(1000);
|
||||
rpgInfo = NewRpgInfo();
|
||||
}
|
||||
|
||||
aiObjectContext->GetValue<GuidSet&>("ignore rpg target")->Get().clear();
|
||||
|
||||
bot->GetMotionMaster()->Clear();
|
||||
|
||||
// bot->CleanupAfterTaxiFlight();
|
||||
InterruptSpell();
|
||||
|
||||
|
||||
if (full)
|
||||
{
|
||||
for (uint8 i = 0; i < BOT_STATE_MAX; i++)
|
||||
@@ -1606,12 +1603,6 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
||||
case 608:
|
||||
strategyName = "wotlk-vh"; // Violet Hold
|
||||
break;
|
||||
case 615:
|
||||
strategyName = "wotlk-os"; // Obsidian Sanctum
|
||||
break;
|
||||
case 616:
|
||||
strategyName = "wotlk-eoe"; // Eye Of Eternity
|
||||
break;
|
||||
case 619:
|
||||
strategyName = "wotlk-ok"; // Ahn'kahet: The Old Kingdom
|
||||
break;
|
||||
@@ -4114,11 +4105,20 @@ inline bool ZoneHasRealPlayers(Player* bot)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& player : sRandomPlayerbotMgr->GetPlayers())
|
||||
|
||||
Map::PlayerList const& players = bot->GetMap()->GetPlayers();
|
||||
if (players.IsEmpty())
|
||||
{
|
||||
if (player->GetMapId() != bot->GetMapId())
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto const& itr : players)
|
||||
{
|
||||
Player* player = itr.GetSource();
|
||||
if (!player || !player->IsVisible())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player->GetZoneId() == bot->GetZoneId())
|
||||
{
|
||||
@@ -4135,15 +4135,6 @@ inline bool ZoneHasRealPlayers(Player* bot)
|
||||
|
||||
bool PlayerbotAI::AllowActive(ActivityType activityType)
|
||||
{
|
||||
// Is in combat. Always defend yourself.
|
||||
if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY)
|
||||
{
|
||||
if (bot->IsInCombat())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// only keep updating till initializing time has completed,
|
||||
// which prevents unneeded expensive GameTime calls.
|
||||
if (_isBotInitializing)
|
||||
@@ -4163,53 +4154,35 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
|
||||
return true;
|
||||
}
|
||||
|
||||
// when botActiveAlone is 100% and smartScale disabled
|
||||
if (sPlayerbotAIConfig->botActiveAlone >= 100 && !sPlayerbotAIConfig->botActiveAloneSmartScale)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// bg, raid, dungeon
|
||||
if (!WorldPosition(bot).isOverworld())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// bot map has active players.
|
||||
if (sPlayerbotAIConfig->BotActiveAloneForceWhenInMap)
|
||||
|
||||
// Is in combat. Defend yourself.
|
||||
if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY)
|
||||
{
|
||||
if (HasRealPlayers(bot->GetMap()))
|
||||
if (bot->IsInCombat())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// bot zone has active players.
|
||||
if (sPlayerbotAIConfig->BotActiveAloneForceWhenInZone)
|
||||
if (ZoneHasRealPlayers(bot))
|
||||
{
|
||||
if (ZoneHasRealPlayers(bot))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// when in real guild
|
||||
if (sPlayerbotAIConfig->BotActiveAloneForceWhenInGuild)
|
||||
{
|
||||
if (IsInRealGuild())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Player is near. Always active.
|
||||
if (HasPlayerNearby(sPlayerbotAIConfig->BotActiveAloneForceWhenInRadius))
|
||||
if (IsInRealGuild())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Has player master. Always active.
|
||||
if (GetMaster())
|
||||
if (GetMaster())
|
||||
{
|
||||
PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(GetMaster());
|
||||
if (!masterBotAI || masterBotAI->IsRealPlayer())
|
||||
@@ -4277,27 +4250,30 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
|
||||
return true;
|
||||
}
|
||||
|
||||
// HasFriend
|
||||
if (sPlayerbotAIConfig->BotActiveAloneForceWhenIsFriend)
|
||||
// Player is near. Always active.
|
||||
if (HasPlayerNearby(300.f))
|
||||
{
|
||||
for (auto& player : sRandomPlayerbotMgr->GetPlayers())
|
||||
{
|
||||
if (!player || !player->IsInWorld() || !player->GetSocial() || !bot->GetGUID())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player->GetSocial()->HasFriend(bot->GetGUID()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// HasFriend
|
||||
for (auto& player : sRandomPlayerbotMgr->GetPlayers())
|
||||
{
|
||||
if (!player || !player->IsInWorld() || !player->GetSocial() || !bot->GetGUID())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player->GetSocial()->HasFriend(bot->GetGUID()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Force the bots to spread
|
||||
if (activityType == OUT_OF_PARTY_ACTIVITY || activityType == GRIND_ACTIVITY)
|
||||
{
|
||||
if (HasManyPlayersNearby(10, 40))
|
||||
if (HasManyPlayersNearby(10, sPlayerbotAIConfig->sightDistance))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -4313,7 +4289,11 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->botActiveAlone >= 100 && !sPlayerbotAIConfig->botActiveAloneSmartScale)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// #######################################################################################
|
||||
// All mandatory conditations are checked to be active or not, from here the remaining
|
||||
// situations are usable for scaling when enabled.
|
||||
@@ -5492,10 +5472,10 @@ bool PlayerbotAI::CanMove()
|
||||
if (IsInVehicle() && !IsInVehicle(true))
|
||||
return false;
|
||||
|
||||
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) ||
|
||||
bot->IsBeingTeleported() || bot->HasRootAura() || bot->HasSpiritOfRedemptionAura() ||
|
||||
bot->HasConfuseAura() || bot->IsCharmed() || bot->HasStunAura() ||
|
||||
bot->IsInFlight() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) ||
|
||||
bot->IsBeingTeleported() || bot->isInRoots() || bot->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) ||
|
||||
bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || bot->IsCharmed() || bot->HasAuraType(SPELL_AURA_MOD_STUN) ||
|
||||
bot->HasUnitState(UNIT_STATE_IN_FLIGHT) || bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||
return false;
|
||||
|
||||
return bot->GetMotionMaster()->GetCurrentMovementGeneratorType() != FLIGHT_MOTION_TYPE;
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "PlayerbotTextMgr.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "NewRpgStrategy.h"
|
||||
|
||||
class AiObjectContext;
|
||||
class Creature;
|
||||
@@ -433,7 +432,7 @@ public:
|
||||
std::vector<Player*> GetPlayersInGroup();
|
||||
const AreaTableEntry* GetCurrentArea();
|
||||
const AreaTableEntry* GetCurrentZone();
|
||||
static std::string GetLocalizedAreaName(const AreaTableEntry* entry);
|
||||
std::string GetLocalizedAreaName(const AreaTableEntry* entry);
|
||||
|
||||
bool TellMaster(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellMaster(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
@@ -573,7 +572,6 @@ public:
|
||||
std::set<uint32> GetCurrentIncompleteQuestIds();
|
||||
void PetFollow();
|
||||
static float GetItemScoreMultiplier(ItemQualities quality);
|
||||
NewRpgInfo rpgInfo;
|
||||
|
||||
private:
|
||||
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
|
||||
@@ -582,7 +580,7 @@ private:
|
||||
|
||||
void HandleCommands();
|
||||
void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL);
|
||||
bool _isBotInitializing = false;
|
||||
bool _isBotInitializing = true;
|
||||
|
||||
protected:
|
||||
Player* bot;
|
||||
|
||||
@@ -399,19 +399,15 @@ bool PlayerbotAIConfig::Initialize()
|
||||
|
||||
worldBuffs.clear();
|
||||
|
||||
LOG_INFO("playerbots", "Loading Worldbuff...");
|
||||
for (uint32 factionId = 0; factionId < 3; factionId++)
|
||||
{
|
||||
for (uint32 classId = 0; classId < MAX_CLASSES; classId++)
|
||||
{
|
||||
for (uint32 specId = 0; specId < MAX_SPECNO; specId++)
|
||||
for (uint32 minLevel = 0; minLevel < MAX_LEVEL; minLevel++)
|
||||
{
|
||||
for (uint32 minLevel = 0; minLevel < MAX_LEVEL; minLevel++)
|
||||
for (uint32 maxLevel = 0; maxLevel < MAX_LEVEL; maxLevel++)
|
||||
{
|
||||
for (uint32 maxLevel = 0; maxLevel < MAX_LEVEL; maxLevel++)
|
||||
{
|
||||
loadWorldBuf(factionId, classId, specId, minLevel, maxLevel);
|
||||
}
|
||||
loadWorldBuf(factionId, classId, minLevel, maxLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,18 +459,12 @@ bool PlayerbotAIConfig::Initialize()
|
||||
addClassAccountPoolSize = sConfigMgr->GetOption<int32>("AiPlayerbot.AddClassAccountPoolSize", 50);
|
||||
maintenanceCommand = sConfigMgr->GetOption<int32>("AiPlayerbot.MaintenanceCommand", 1);
|
||||
autoGearCommand = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearCommand", 1);
|
||||
autoGearCommandAltBots = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearCommandAltBots", 1);
|
||||
autoGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearQualityLimit", 3);
|
||||
autoGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearScoreLimit", 0);
|
||||
|
||||
playerbotsXPrate = sConfigMgr->GetOption<int32>("AiPlayerbot.KillXPRate", 1);
|
||||
disableDeathKnightLogin = sConfigMgr->GetOption<bool>("AiPlayerbot.DisableDeathKnightLogin", 0);
|
||||
botActiveAlone = sConfigMgr->GetOption<int32>("AiPlayerbot.BotActiveAlone", 100);
|
||||
BotActiveAloneForceWhenInRadius = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotActiveAloneForceWhenInRadius", 150);
|
||||
BotActiveAloneForceWhenInZone = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenInZone", 1);
|
||||
BotActiveAloneForceWhenInMap = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenInMap", 0);
|
||||
BotActiveAloneForceWhenIsFriend = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenIsFriend", 1);
|
||||
BotActiveAloneForceWhenInGuild = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenInGuild", 1);
|
||||
botActiveAloneSmartScale = sConfigMgr->GetOption<bool>("AiPlayerbot.botActiveAloneSmartScale", 1);
|
||||
botActiveAloneSmartScaleWhenMinLevel =
|
||||
sConfigMgr->GetOption<uint32>("AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel", 1);
|
||||
@@ -501,15 +491,13 @@ bool PlayerbotAIConfig::Initialize()
|
||||
twoRoundsGearInit = sConfigMgr->GetOption<bool>("AiPlayerbot.TwoRoundsGearInit", false);
|
||||
syncQuestWithPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestWithPlayer", true);
|
||||
syncQuestForPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncQuestForPlayer", false);
|
||||
dropObsoleteQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.DropObsoleteQuests", true);
|
||||
autoTrainSpells = sConfigMgr->GetOption<std::string>("AiPlayerbot.AutoTrainSpells", "yes");
|
||||
autoPickTalents = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoPickTalents", true);
|
||||
autoUpgradeEquip = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoUpgradeEquip", false);
|
||||
autoLearnTrainerSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnTrainerSpells", true);
|
||||
autoLearnQuestSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnQuestSpells", false);
|
||||
autoTeleportForLevel = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoTeleportForLevel", false);
|
||||
autoDoQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoDoQuests", true);
|
||||
enableNewRpgStrategy = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableNewRpgStrategy", false);
|
||||
autoDoQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoDoQuests", false);
|
||||
syncLevelWithPlayers = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncLevelWithPlayers", false);
|
||||
freeFood = sConfigMgr->GetOption<bool>("AiPlayerbot.FreeFood", true);
|
||||
randomBotGroupNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGroupNearby", true);
|
||||
@@ -571,7 +559,7 @@ bool PlayerbotAIConfig::IsInRandomQuestItemList(uint32 id)
|
||||
|
||||
bool PlayerbotAIConfig::IsPvpProhibited(uint32 zoneId, uint32 areaId)
|
||||
{
|
||||
return IsInPvpProhibitedZone(zoneId) || IsInPvpProhibitedArea(areaId) || IsInPvpProhibitedZone(areaId);
|
||||
return IsInPvpProhibitedZone(zoneId) || IsInPvpProhibitedArea(areaId);
|
||||
}
|
||||
|
||||
bool PlayerbotAIConfig::IsInPvpProhibitedZone(uint32 id)
|
||||
@@ -656,50 +644,36 @@ void PlayerbotAIConfig::log(std::string const fileName, char const* str, ...)
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void PlayerbotAIConfig::loadWorldBuf(uint32 factionId1, uint32 classId1, uint32 specId1, uint32 minLevel1, uint32 maxLevel1)
|
||||
void PlayerbotAIConfig::loadWorldBuf(uint32 factionId1, uint32 classId1, uint32 minLevel1, uint32 maxLevel1)
|
||||
{
|
||||
std::vector<uint32> buffs;
|
||||
|
||||
std::ostringstream os;
|
||||
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << specId1 << "." << minLevel1 << "." << maxLevel1;
|
||||
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << minLevel1 << "." << maxLevel1;
|
||||
|
||||
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
|
||||
|
||||
for (auto buff : buffs)
|
||||
{
|
||||
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||
worldBuff wb = {buff, factionId1, classId1, minLevel1, maxLevel1};
|
||||
worldBuffs.push_back(wb);
|
||||
}
|
||||
|
||||
if (maxLevel1 == 0)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << specId1 << "." << minLevel1;
|
||||
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << classId1 << "." << minLevel1;
|
||||
|
||||
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
|
||||
|
||||
for (auto buff : buffs)
|
||||
{
|
||||
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||
worldBuff wb = {buff, factionId1, classId1, minLevel1, maxLevel1};
|
||||
worldBuffs.push_back(wb);
|
||||
}
|
||||
}
|
||||
|
||||
if (maxLevel1 == 0 && minLevel1 == 0)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << factionId1 << "." << classId1 << "." << specId1;
|
||||
|
||||
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>(os.str().c_str(), "", false), buffs);
|
||||
|
||||
for (auto buff : buffs)
|
||||
{
|
||||
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||
worldBuffs.push_back(wb);
|
||||
}
|
||||
}
|
||||
|
||||
if (maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "AiPlayerbot.WorldBuff." << factionId1 << "." << factionId1 << "." << classId1;
|
||||
@@ -708,12 +682,12 @@ void PlayerbotAIConfig::loadWorldBuf(uint32 factionId1, uint32 classId1, uint32
|
||||
|
||||
for (auto buff : buffs)
|
||||
{
|
||||
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||
worldBuff wb = {buff, factionId1, classId1, minLevel1, maxLevel1};
|
||||
worldBuffs.push_back(wb);
|
||||
}
|
||||
}
|
||||
|
||||
if (classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
|
||||
if (classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "AiPlayerbot.WorldBuff." << factionId1;
|
||||
@@ -722,12 +696,12 @@ void PlayerbotAIConfig::loadWorldBuf(uint32 factionId1, uint32 classId1, uint32
|
||||
|
||||
for (auto buff : buffs)
|
||||
{
|
||||
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||
worldBuff wb = {buff, factionId1, classId1, minLevel1, maxLevel1};
|
||||
worldBuffs.push_back(wb);
|
||||
}
|
||||
}
|
||||
|
||||
if (factionId1 == 0 && classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0 && specId1 == 0)
|
||||
if (factionId1 == 0 && classId1 == 0 && maxLevel1 == 0 && minLevel1 == 0)
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "AiPlayerbot.WorldBuff";
|
||||
@@ -736,7 +710,7 @@ void PlayerbotAIConfig::loadWorldBuf(uint32 factionId1, uint32 classId1, uint32
|
||||
|
||||
for (auto buff : buffs)
|
||||
{
|
||||
worldBuff wb = {buff, factionId1, classId1, specId1, minLevel1, maxLevel1};
|
||||
worldBuff wb = {buff, factionId1, classId1, minLevel1, maxLevel1};
|
||||
worldBuffs.push_back(wb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +247,6 @@ public:
|
||||
uint32 spellId;
|
||||
uint32 factionId = 0;
|
||||
uint32 classId = 0;
|
||||
uint32 specId = 0;
|
||||
uint32 minLevel = 0;
|
||||
uint32 maxLevel = 0;
|
||||
};
|
||||
@@ -264,11 +263,6 @@ public:
|
||||
uint32 playerbotsXPrate;
|
||||
bool disableDeathKnightLogin;
|
||||
uint32 botActiveAlone;
|
||||
uint32 BotActiveAloneForceWhenInRadius;
|
||||
bool BotActiveAloneForceWhenInZone;
|
||||
bool BotActiveAloneForceWhenInMap;
|
||||
bool BotActiveAloneForceWhenIsFriend;
|
||||
bool BotActiveAloneForceWhenInGuild;
|
||||
bool botActiveAloneSmartScale;
|
||||
uint32 botActiveAloneSmartScaleWhenMinLevel;
|
||||
uint32 botActiveAloneSmartScaleWhenMaxLevel;
|
||||
@@ -281,13 +275,11 @@ public:
|
||||
bool twoRoundsGearInit;
|
||||
bool syncQuestWithPlayer;
|
||||
bool syncQuestForPlayer;
|
||||
bool dropObsoleteQuests;
|
||||
std::string autoTrainSpells;
|
||||
bool autoPickTalents;
|
||||
bool autoUpgradeEquip;
|
||||
bool autoLearnTrainerSpells;
|
||||
bool autoDoQuests;
|
||||
bool enableNewRpgStrategy;
|
||||
bool syncLevelWithPlayers;
|
||||
bool freeFood;
|
||||
bool autoLearnQuestSpells;
|
||||
@@ -320,7 +312,7 @@ public:
|
||||
int32 addClassCommand;
|
||||
int32 addClassAccountPoolSize;
|
||||
int32 maintenanceCommand;
|
||||
int32 autoGearCommand, autoGearCommandAltBots, autoGearQualityLimit, autoGearScoreLimit;
|
||||
int32 autoGearCommand, autoGearQualityLimit, autoGearScoreLimit;
|
||||
|
||||
std::string const GetTimestampStr();
|
||||
bool hasLog(std::string const fileName)
|
||||
@@ -335,7 +327,7 @@ public:
|
||||
}
|
||||
void log(std::string const fileName, const char* str, ...);
|
||||
|
||||
void loadWorldBuf(uint32 factionId, uint32 classId, uint32 specId, uint32 minLevel, uint32 maxLevel);
|
||||
void loadWorldBuf(uint32 factionId, uint32 classId, uint32 minLevel, uint32 maxLevel);
|
||||
static std::vector<std::vector<uint32>> ParseTempTalentsOrder(uint32 cls, std::string temp_talents_order);
|
||||
static std::vector<std::vector<uint32>> ParseTempPetTalentsOrder(uint32 spec, std::string temp_talents_order);
|
||||
};
|
||||
|
||||
@@ -958,17 +958,9 @@ std::vector<std::string> PlayerbotHolder::HandlePlayerbotCommand(char const* arg
|
||||
|
||||
if (!strcmp(cmd, "reload"))
|
||||
{
|
||||
if (master->GetSession()->GetSecurity() >= SEC_GAMEMASTER)
|
||||
{
|
||||
sPlayerbotAIConfig->Initialize();
|
||||
messages.push_back("Config reloaded.");
|
||||
return messages;
|
||||
}
|
||||
else
|
||||
{
|
||||
messages.push_back("ERROR: Only GM can use this command.");
|
||||
return messages;
|
||||
}
|
||||
messages.push_back("Reloading config");
|
||||
sPlayerbotAIConfig->Initialize();
|
||||
return messages;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, "tweak"))
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
|
||||
void OnDatabaseSelectIndexLogout(Player* player, uint32& statementIndex, uint32& statementParam) override
|
||||
{
|
||||
statementIndex = CHAR_UPD_CHAR_OFFLINE;
|
||||
statementIndex = CHAR_UPD_CHAR_ONLINE;
|
||||
statementParam = player->GetGUID().GetCounter();
|
||||
}
|
||||
|
||||
|
||||
@@ -556,7 +556,7 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
||||
totalRandomBotChars += AccountMgr::GetCharactersCount(accountId);
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", ">> {} random bot accounts with {} characters available",
|
||||
LOG_INFO("server.loading", "{} random bot accounts with {} characters available",
|
||||
sPlayerbotAIConfig->randomBotAccounts.size(), totalRandomBotChars);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <algorithm>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
|
||||
@@ -19,8 +18,6 @@
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "CellImpl.h"
|
||||
#include "ChannelMgr.h"
|
||||
#include "DBCStores.h"
|
||||
#include "DBCStructure.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Define.h"
|
||||
#include "FleeManager.h"
|
||||
@@ -31,19 +28,15 @@
|
||||
#include "GuildTaskMgr.h"
|
||||
#include "LFGMgr.h"
|
||||
#include "MapMgr.h"
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "PerformanceMonitor.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "PlayerbotCommandServer.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Position.h"
|
||||
#include "Random.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "TravelMgr.h"
|
||||
#include "Unit.h"
|
||||
#include "UpdateTime.h"
|
||||
#include "World.h"
|
||||
@@ -172,13 +165,6 @@ RandomPlayerbotMgr::RandomPlayerbotMgr() : PlayerbotHolder(), processTicks(0)
|
||||
}
|
||||
|
||||
BattlegroundData.clear();
|
||||
for (int bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
|
||||
{
|
||||
for (int queueType = BATTLEGROUND_QUEUE_AV; queueType < MAX_BATTLEGROUND_QUEUE_TYPES; ++queueType)
|
||||
{
|
||||
BattlegroundData[queueType][bracket] = BattlegroundInfo();
|
||||
}
|
||||
}
|
||||
BgCheckTimer = 0;
|
||||
LfgCheckTimer = 0;
|
||||
PlayersCheckTimer = 0;
|
||||
@@ -355,32 +341,21 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
||||
if (sPlayerbotAIConfig->syncLevelWithPlayers && !players.empty())
|
||||
{
|
||||
if (time(nullptr) > (PlayersCheckTimer + 60))
|
||||
sRandomPlayerbotMgr->CheckPlayers();
|
||||
activateCheckPlayersThread();
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotJoinBG /* && !players.empty()*/)
|
||||
{
|
||||
if (time(nullptr) > (BgCheckTimer + 30))
|
||||
sRandomPlayerbotMgr->CheckBgQueue();
|
||||
activateCheckBgQueueThread();
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotJoinLfg /* && !players.empty()*/)
|
||||
{
|
||||
if (time(nullptr) > (LfgCheckTimer + 30))
|
||||
sRandomPlayerbotMgr->CheckLfgQueue();
|
||||
activateCheckLfgQueueThread();
|
||||
}
|
||||
|
||||
if (time(nullptr) > (printStatsTimer + 300))
|
||||
{
|
||||
if (!printStatsTimer)
|
||||
{
|
||||
printStatsTimer = time(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
activatePrintStatsThread();
|
||||
}
|
||||
}
|
||||
uint32 updateBots = sPlayerbotAIConfig->randomBotsPerInterval * onlineBotFocus / 100;
|
||||
uint32 maxNewBots = onlineBotCount < maxAllowedBotCount ? maxAllowedBotCount - onlineBotCount : 0;
|
||||
uint32 loginBots = std::min(sPlayerbotAIConfig->randomBotsPerInterval - updateBots, maxNewBots);
|
||||
@@ -435,25 +410,25 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
||||
}
|
||||
}
|
||||
|
||||
// void RandomPlayerbotMgr::ScaleBotActivity()
|
||||
//void RandomPlayerbotMgr::ScaleBotActivity()
|
||||
//{
|
||||
// float activityPercentage = getActivityPercentage();
|
||||
// float activityPercentage = getActivityPercentage();
|
||||
//
|
||||
// // if (activityPercentage >= 100.0f || activityPercentage <= 0.0f) pid.reset(); //Stop integer buildup during
|
||||
// // max/min activity
|
||||
// // if (activityPercentage >= 100.0f || activityPercentage <= 0.0f) pid.reset(); //Stop integer buildup during
|
||||
// // max/min activity
|
||||
//
|
||||
// // % increase/decrease wanted diff , avg diff
|
||||
// float activityPercentageMod = pid.calculate(
|
||||
// sRandomPlayerbotMgr->GetPlayers().empty() ? sPlayerbotAIConfig->diffEmpty :
|
||||
// sPlayerbotAIConfig->diffWithPlayer, sWorldUpdateTime.GetAverageUpdateTime());
|
||||
// // % increase/decrease wanted diff , avg diff
|
||||
// float activityPercentageMod = pid.calculate(
|
||||
// sRandomPlayerbotMgr->GetPlayers().empty() ? sPlayerbotAIConfig->diffEmpty : sPlayerbotAIConfig->diffWithPlayer,
|
||||
// sWorldUpdateTime.GetAverageUpdateTime());
|
||||
//
|
||||
// activityPercentage = activityPercentageMod + 50;
|
||||
// activityPercentage = activityPercentageMod + 50;
|
||||
//
|
||||
// // Cap the percentage between 0 and 100.
|
||||
// activityPercentage = std::max(0.0f, std::min(100.0f, activityPercentage));
|
||||
// // Cap the percentage between 0 and 100.
|
||||
// activityPercentage = std::max(0.0f, std::min(100.0f, activityPercentage));
|
||||
//
|
||||
// setActivityPercentage(activityPercentage);
|
||||
// }
|
||||
// setActivityPercentage(activityPercentage);
|
||||
//}
|
||||
|
||||
uint32 RandomPlayerbotMgr::AddRandomBots()
|
||||
{
|
||||
@@ -539,9 +514,7 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
||||
}
|
||||
|
||||
if (maxAllowedBotCount)
|
||||
LOG_ERROR("playerbots",
|
||||
"Not enough random bot accounts available. Need {} more, try to increase RandomBotAccountCount "
|
||||
"in your conf file",
|
||||
LOG_ERROR("playerbots", "Not enough random bot accounts available. Need {} more!!",
|
||||
ceil(maxAllowedBotCount / 10));
|
||||
}
|
||||
|
||||
@@ -617,18 +590,10 @@ void RandomPlayerbotMgr::CheckBgQueue()
|
||||
|
||||
BgCheckTimer = time(nullptr);
|
||||
|
||||
LOG_DEBUG("playerbots", "Checking BG Queue...");
|
||||
LOG_INFO("playerbots", "Checking BG Queue...");
|
||||
|
||||
BattlegroundData.clear();
|
||||
|
||||
for (int bracket = BG_BRACKET_ID_FIRST; bracket < MAX_BATTLEGROUND_BRACKETS; ++bracket)
|
||||
{
|
||||
for (int queueType = BATTLEGROUND_QUEUE_AV; queueType < MAX_BATTLEGROUND_QUEUE_TYPES; ++queueType)
|
||||
{
|
||||
BattlegroundData[queueType][bracket] = BattlegroundInfo();
|
||||
}
|
||||
}
|
||||
|
||||
for (Player* player : players)
|
||||
{
|
||||
if (!player->InBattlegroundQueue())
|
||||
@@ -875,8 +840,7 @@ void RandomPlayerbotMgr::LogBattlegroundInfo()
|
||||
for (const auto& bracketIdPair : queueTypePair.second)
|
||||
{
|
||||
auto& bgInfo = bracketIdPair.second;
|
||||
if (bgInfo.minLevel == 0)
|
||||
continue;
|
||||
|
||||
LOG_INFO("playerbots",
|
||||
"ARENA:{} {}: Player (Skirmish:{}, Rated:{}) Bots (Skirmish:{}, Rated:{}) Total (Skirmish:{} "
|
||||
"Rated:{}), Instances (Skirmish:{} Rated:{})",
|
||||
@@ -925,8 +889,6 @@ void RandomPlayerbotMgr::LogBattlegroundInfo()
|
||||
for (const auto& bracketIdPair : queueTypePair.second)
|
||||
{
|
||||
auto& bgInfo = bracketIdPair.second;
|
||||
if (bgInfo.minLevel == 0)
|
||||
continue;
|
||||
|
||||
LOG_INFO("playerbots", "BG:{} {}: Player ({}:{}) Bot ({}:{}) Total (A:{} H:{}), Instances {}", _bgType,
|
||||
std::to_string(bgInfo.minLevel) + "-" + std::to_string(bgInfo.maxLevel),
|
||||
@@ -935,7 +897,7 @@ void RandomPlayerbotMgr::LogBattlegroundInfo()
|
||||
bgInfo.bgHordePlayerCount + bgInfo.bgHordeBotCount, bgInfo.bgInstanceCount);
|
||||
}
|
||||
}
|
||||
LOG_DEBUG("playerbots", "BG Queue check finished");
|
||||
LOG_INFO("playerbots", "BG Queue check finished");
|
||||
}
|
||||
|
||||
void RandomPlayerbotMgr::CheckLfgQueue()
|
||||
@@ -943,7 +905,7 @@ void RandomPlayerbotMgr::CheckLfgQueue()
|
||||
if (!LfgCheckTimer || time(nullptr) > (LfgCheckTimer + 30))
|
||||
LfgCheckTimer = time(nullptr);
|
||||
|
||||
LOG_DEBUG("playerbots", "Checking LFG Queue...");
|
||||
LOG_INFO("playerbots", "Checking LFG Queue...");
|
||||
|
||||
// Clear LFG list
|
||||
LfgDungeons[TEAM_ALLIANCE].clear();
|
||||
@@ -973,7 +935,7 @@ void RandomPlayerbotMgr::CheckLfgQueue()
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG("playerbots", "LFG Queue check finished");
|
||||
LOG_INFO("playerbots", "LFG Queue check finished");
|
||||
}
|
||||
|
||||
void RandomPlayerbotMgr::CheckPlayers()
|
||||
@@ -1003,7 +965,10 @@ void RandomPlayerbotMgr::CheckPlayers()
|
||||
LOG_INFO("playerbots", "Max player level is {}, max bot level set to {}", playersLevel - 3, playersLevel);
|
||||
}
|
||||
|
||||
void RandomPlayerbotMgr::ScheduleRandomize(uint32 bot, uint32 time) { SetEventValue(bot, "randomize", 1, time); }
|
||||
void RandomPlayerbotMgr::ScheduleRandomize(uint32 bot, uint32 time)
|
||||
{
|
||||
SetEventValue(bot, "randomize", 1, time);
|
||||
}
|
||||
|
||||
void RandomPlayerbotMgr::ScheduleTeleport(uint32 bot, uint32 time)
|
||||
{
|
||||
@@ -1119,7 +1084,9 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot)
|
||||
if (update)
|
||||
ProcessBot(player);
|
||||
|
||||
randomTime = urand(sPlayerbotAIConfig->minRandomBotReviveTime, sPlayerbotAIConfig->maxRandomBotReviveTime);
|
||||
randomTime = urand(
|
||||
sPlayerbotAIConfig->minRandomBotReviveTime,
|
||||
sPlayerbotAIConfig->maxRandomBotReviveTime);
|
||||
SetEventValue(bot, "update", 1, randomTime);
|
||||
|
||||
return true;
|
||||
@@ -1132,8 +1099,9 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot)
|
||||
player->GetLevel(), player->GetName().c_str());
|
||||
LogoutPlayerBot(botGUID);
|
||||
currentBots.remove(bot);
|
||||
SetEventValue(bot, "logout", 1,
|
||||
urand(sPlayerbotAIConfig->minRandomBotInWorldTime, sPlayerbotAIConfig->maxRandomBotInWorldTime));
|
||||
SetEventValue(bot, "logout", 1, urand(
|
||||
sPlayerbotAIConfig->minRandomBotInWorldTime,
|
||||
sPlayerbotAIConfig->maxRandomBotInWorldTime));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1155,10 +1123,11 @@ bool RandomPlayerbotMgr::ProcessBot(Player* player)
|
||||
{
|
||||
if (!GetEventValue(bot, "dead"))
|
||||
{
|
||||
uint32 randomTime =
|
||||
urand(sPlayerbotAIConfig->minRandomBotReviveTime, sPlayerbotAIConfig->maxRandomBotReviveTime);
|
||||
LOG_DEBUG("playerbots", "Mark bot {} as dead, will be revived in {}s.", player->GetName().c_str(),
|
||||
randomTime);
|
||||
uint32 randomTime = urand(
|
||||
sPlayerbotAIConfig->minRandomBotReviveTime,
|
||||
sPlayerbotAIConfig->maxRandomBotReviveTime);
|
||||
LOG_INFO("playerbots", "Mark bot {} as dead, will be revived in {}s.",
|
||||
player->GetName().c_str(), randomTime);
|
||||
SetEventValue(bot, "dead", 1, sPlayerbotAIConfig->maxRandomBotInWorldTime);
|
||||
SetEventValue(bot, "revive", 1, randomTime);
|
||||
return false;
|
||||
@@ -1181,10 +1150,11 @@ bool RandomPlayerbotMgr::ProcessBot(Player* player)
|
||||
LOG_INFO("playerbots", "Bot {} remove from group since leader is random bot.", player->GetName().c_str());
|
||||
}
|
||||
|
||||
|
||||
// only randomize and teleport idle bots
|
||||
bool idleBot = false;
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
|
||||
if (botAI)
|
||||
if (botAI)
|
||||
{
|
||||
if (TravelTarget* target = botAI->GetAiObjectContext()->GetValue<TravelTarget*>("travel target")->Get())
|
||||
{
|
||||
@@ -1193,10 +1163,10 @@ bool RandomPlayerbotMgr::ProcessBot(Player* player)
|
||||
idleBot = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
idleBot = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (idleBot)
|
||||
{
|
||||
@@ -1204,7 +1174,7 @@ bool RandomPlayerbotMgr::ProcessBot(Player* player)
|
||||
uint32 randomize = GetEventValue(bot, "randomize");
|
||||
if (!randomize)
|
||||
{
|
||||
// bool randomiser = true;
|
||||
// bool randomiser = true;
|
||||
// if (player->GetGuildId())
|
||||
// {
|
||||
// if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId()))
|
||||
@@ -1226,10 +1196,11 @@ bool RandomPlayerbotMgr::ProcessBot(Player* player)
|
||||
// if (randomiser)
|
||||
// {
|
||||
Randomize(player);
|
||||
LOG_DEBUG("playerbots", "Bot #{} {}:{} <{}>: randomized", bot,
|
||||
player->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", player->GetLevel(), player->GetName());
|
||||
uint32 randomTime =
|
||||
urand(sPlayerbotAIConfig->minRandomBotRandomizeTime, sPlayerbotAIConfig->maxRandomBotRandomizeTime);
|
||||
LOG_INFO("playerbots", "Bot #{} {}:{} <{}>: randomized",
|
||||
bot, player->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", player->GetLevel(), player->GetName());
|
||||
uint32 randomTime = urand(
|
||||
sPlayerbotAIConfig->minRandomBotRandomizeTime,
|
||||
sPlayerbotAIConfig->maxRandomBotRandomizeTime);
|
||||
ScheduleRandomize(bot, randomTime);
|
||||
return true;
|
||||
}
|
||||
@@ -1245,11 +1216,12 @@ bool RandomPlayerbotMgr::ProcessBot(Player* player)
|
||||
uint32 teleport = GetEventValue(bot, "teleport");
|
||||
if (!teleport)
|
||||
{
|
||||
LOG_DEBUG("playerbots", "Bot #{} <{}>: teleport for level and refresh", bot, player->GetName());
|
||||
LOG_INFO("playerbots", "Bot #{} <{}>: teleport for level and refresh", bot, player->GetName());
|
||||
Refresh(player);
|
||||
RandomTeleportForLevel(player);
|
||||
uint32 time = urand(sPlayerbotAIConfig->minRandomBotTeleportInterval,
|
||||
sPlayerbotAIConfig->maxRandomBotTeleportInterval);
|
||||
uint32 time = urand(
|
||||
sPlayerbotAIConfig->minRandomBotTeleportInterval,
|
||||
sPlayerbotAIConfig->maxRandomBotTeleportInterval);
|
||||
ScheduleTeleport(bot, time);
|
||||
return true;
|
||||
}
|
||||
@@ -1274,7 +1246,7 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
||||
{
|
||||
// ignore when alrdy teleported or not in the world yet.
|
||||
if (bot->IsBeingTeleported() || !bot->IsInWorld())
|
||||
return;
|
||||
return;
|
||||
|
||||
// ignore when in queue for battle grounds.
|
||||
if (bot->InBattlegroundQueue())
|
||||
@@ -1290,10 +1262,11 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
if (botAI)
|
||||
{
|
||||
{
|
||||
// ignore when in when taxi with boat/zeppelin and has players nearby
|
||||
if (bot->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && bot->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) &&
|
||||
botAI->HasPlayerNearby())
|
||||
if (bot->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) &&
|
||||
bot->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) &&
|
||||
botAI->HasPlayerNearby())
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1382,19 +1355,17 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (bot->GetLevel() <= 16 && (loc.GetMapId() != pInfo->mapId || dis > 10000.0f))
|
||||
if (bot->GetLevel() <= 18 && (loc.GetMapId() != pInfo->mapId || dis > 10000.0f))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const LocaleConstant& locale = sWorld->GetDefaultDbcLocale();
|
||||
LOG_DEBUG("playerbots",
|
||||
"Random teleporting bot {} (level {}) to Map: {} ({}) Zone: {} ({}) Area: {} ({}) ZoneLevel: {} "
|
||||
"AreaLevel: {} {},{},{} ({}/{} "
|
||||
"locations)",
|
||||
bot->GetName().c_str(), bot->GetLevel(), map->GetId(), map->GetMapName(), zone->ID,
|
||||
zone->area_name[locale], area->ID, area->area_name[locale], zone->area_level, area->area_level, x, y,
|
||||
z, i + 1, tlocs.size());
|
||||
LOG_INFO("playerbots",
|
||||
"Random teleporting bot {} (level {}) to Map: {} ({}) Zone: {} ({}) Area: {} ({}) {},{},{} ({}/{} "
|
||||
"locations)",
|
||||
bot->GetName().c_str(), bot->GetLevel(), map->GetId(), map->GetMapName(), zone->ID,
|
||||
zone->area_name[locale], area->ID, area->area_name[locale], x, y, z, i + 1, tlocs.size());
|
||||
|
||||
if (hearth)
|
||||
{
|
||||
@@ -1433,35 +1404,32 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
||||
"position_x, "
|
||||
"position_y, "
|
||||
"position_z, "
|
||||
"t.minlevel, "
|
||||
"t.maxlevel "
|
||||
"t.minlevel "
|
||||
"FROM "
|
||||
"(SELECT "
|
||||
"map, "
|
||||
"MIN( c.guid ) guid "
|
||||
"MIN( c.guid ) guid, "
|
||||
"t.entry "
|
||||
"FROM "
|
||||
"creature c "
|
||||
"INNER JOIN creature_template t ON c.id1 = t.entry "
|
||||
"WHERE "
|
||||
"t.npcflag = 0 "
|
||||
"AND t.lootid != 0 "
|
||||
"AND t.unit_flags != 768 "
|
||||
"AND t.maxlevel - t.minlevel < 3 "
|
||||
"AND map IN ({}) "
|
||||
"AND t.entry not in (32820, 24196, 30627, 30617) "
|
||||
"AND c.id1 != 32820 "
|
||||
"AND c.spawntimesecs < 1000 "
|
||||
"AND t.faction not in (11, 71, 79, 85, 188, 1575) "
|
||||
"AND (t.unit_flags & 256) = 0 "
|
||||
"AND (t.unit_flags & 4096) = 0 "
|
||||
"AND t.rank = 0 "
|
||||
// "AND (t.flags_extra & 32768) = 0 "
|
||||
"AND t.faction != 188 "
|
||||
"GROUP BY "
|
||||
"map, "
|
||||
"ROUND(position_x / 50), "
|
||||
"ROUND(position_y / 50), "
|
||||
"ROUND(position_z / 50) "
|
||||
"ROUND( position_x / 500 ), "
|
||||
"ROUND( position_y / 500 ), "
|
||||
"ROUND( position_z / 50), "
|
||||
"t.entry "
|
||||
"HAVING "
|
||||
"count(*) >= 2) "
|
||||
"AS g "
|
||||
"count(*) > 7) AS g "
|
||||
"INNER JOIN creature c ON g.guid = c.guid "
|
||||
"INNER JOIN creature_template t on c.id1 = t.entry "
|
||||
"ORDER BY "
|
||||
@@ -1477,9 +1445,7 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
||||
float x = fields[1].Get<float>();
|
||||
float y = fields[2].Get<float>();
|
||||
float z = fields[3].Get<float>();
|
||||
uint32 min_level = fields[4].Get<uint32>();
|
||||
uint32 max_level = fields[5].Get<uint32>();
|
||||
uint32 level = (min_level + max_level + 1) / 2;
|
||||
uint32 level = fields[4].Get<uint32>();
|
||||
WorldLocation loc(mapId, x, y, z, 0);
|
||||
collected_locs++;
|
||||
for (int32 l = (int32)level - (int32)sPlayerbotAIConfig->randomBotTeleHigherLevel;
|
||||
@@ -1493,117 +1459,8 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
||||
}
|
||||
} while (results->NextRow());
|
||||
}
|
||||
LOG_INFO("playerbots", ">> {} locations for level collected.", collected_locs);
|
||||
LOG_INFO("playerbots", "{} locations for level collected.", collected_locs);
|
||||
|
||||
LOG_INFO("playerbots", "Preparing innkeepers locations for level collected...");
|
||||
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
||||
{
|
||||
results = WorldDatabase.Query(
|
||||
"SELECT "
|
||||
"map, "
|
||||
"position_x, "
|
||||
"position_y, "
|
||||
"position_z, "
|
||||
"orientation, "
|
||||
"t.faction, "
|
||||
"t.entry "
|
||||
"FROM "
|
||||
"creature c "
|
||||
"INNER JOIN creature_template t on c.id1 = t.entry "
|
||||
"WHERE "
|
||||
"t.npcflag & 73728 "
|
||||
"AND map IN ({}) "
|
||||
"ORDER BY "
|
||||
"t.minlevel;",
|
||||
sPlayerbotAIConfig->randomBotMapsAsString.c_str());
|
||||
collected_locs = 0;
|
||||
if (results)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = results->Fetch();
|
||||
uint16 mapId = fields[0].Get<uint16>();
|
||||
float x = fields[1].Get<float>();
|
||||
float y = fields[2].Get<float>();
|
||||
float z = fields[3].Get<float>();
|
||||
float orient = fields[4].Get<float>();
|
||||
uint32 faction = fields[5].Get<uint32>();
|
||||
uint32 c_entry = fields[6].Get<uint32>();
|
||||
const FactionTemplateEntry* entry = sFactionTemplateStore.LookupEntry(faction);
|
||||
|
||||
WorldLocation loc(mapId, x + cos(orient) * 5.0f, y + sin(orient) * 5.0f, z + 0.5f, orient + M_PI);
|
||||
collected_locs++;
|
||||
Map* map = sMapMgr->FindMap(loc.GetMapId(), 0);
|
||||
if (!map)
|
||||
continue;
|
||||
const AreaTableEntry* area = sAreaTableStore.LookupEntry(map->GetAreaId(1, x, y, z));
|
||||
uint32 zoneId = area->zone ? area->zone : area->ID;
|
||||
uint32 level = area->area_level;
|
||||
for (int i = 5; i <= maxLevel; i++)
|
||||
{
|
||||
std::vector<WorldLocation>& locs = locsPerLevelCache[i];
|
||||
int counter = 0;
|
||||
WorldLocation levelLoc;
|
||||
for (auto& checkLoc : locs)
|
||||
{
|
||||
if (loc.GetMapId() != checkLoc.GetMapId())
|
||||
continue;
|
||||
|
||||
if (loc.GetExactDist(checkLoc) > 1500.0f)
|
||||
continue;
|
||||
|
||||
if (zoneId !=
|
||||
map->GetZoneId(1, checkLoc.GetPositionX(), checkLoc.GetPositionY(), checkLoc.GetPositionZ()))
|
||||
continue;
|
||||
|
||||
counter++;
|
||||
levelLoc = checkLoc;
|
||||
if (counter >= 15)
|
||||
break;
|
||||
}
|
||||
|
||||
if (counter < 15)
|
||||
continue;
|
||||
|
||||
if (!(entry->hostileMask & 4))
|
||||
{
|
||||
hordeStarterPerLevelCache[i].push_back(loc);
|
||||
}
|
||||
if (!(entry->hostileMask & 2))
|
||||
{
|
||||
allianceStarterPerLevelCache[i].push_back(loc);
|
||||
}
|
||||
LOG_DEBUG("playerbots", "Area: {} Level: {} creature_entry: {} add to: {} {}({},{},{},{})", area->ID,
|
||||
level, c_entry, i, counter, levelLoc.GetPositionX(), levelLoc.GetPositionY(),
|
||||
levelLoc.GetPositionZ(), levelLoc.GetMapId());
|
||||
}
|
||||
} while (results->NextRow());
|
||||
}
|
||||
// add all initial position
|
||||
for (uint32 i = 1; i < MAX_RACES; i++)
|
||||
{
|
||||
for (uint32 j = 1; j < MAX_CLASSES; j++)
|
||||
{
|
||||
PlayerInfo const* info = sObjectMgr->GetPlayerInfo(i, j);
|
||||
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
WorldPosition pos(info->mapId, info->positionX, info->positionY, info->positionZ, info->orientation);
|
||||
|
||||
for (int32 l = 1; l <= 5; l++)
|
||||
{
|
||||
if ((1 << (i - 1)) & RACEMASK_ALLIANCE)
|
||||
allianceStarterPerLevelCache[(uint8)l].push_back(pos);
|
||||
else
|
||||
hordeStarterPerLevelCache[(uint8)l].push_back(pos);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG_INFO("playerbots", ">> {} innkeepers locations for level collected.", collected_locs);
|
||||
}
|
||||
|
||||
results = WorldDatabase.Query(
|
||||
"SELECT "
|
||||
"map, "
|
||||
@@ -1625,7 +1482,6 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
||||
"AND t.faction != 69 "
|
||||
"AND t.entry != 30606 "
|
||||
"AND t.entry != 30608 "
|
||||
"AND t.entry != 29282 "
|
||||
"AND t.faction != 69 "
|
||||
"AND map IN ({}) "
|
||||
"ORDER BY "
|
||||
@@ -1667,15 +1523,15 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
||||
}
|
||||
} while (results->NextRow());
|
||||
}
|
||||
LOG_INFO("playerbots", ">> {} banker locations for level collected.", collected_locs);
|
||||
LOG_INFO("playerbots", "{} banker locations for level collected.", collected_locs);
|
||||
}
|
||||
|
||||
void RandomPlayerbotMgr::PrepareAddclassCache()
|
||||
{
|
||||
int32 maxAccountId = sPlayerbotAIConfig->randomBotAccounts.back();
|
||||
int32 minIdx = sPlayerbotAIConfig->randomBotAccounts.size() - 1 >= sPlayerbotAIConfig->addClassAccountPoolSize
|
||||
? sPlayerbotAIConfig->randomBotAccounts.size() - sPlayerbotAIConfig->addClassAccountPoolSize
|
||||
: 0;
|
||||
int32 minIdx =
|
||||
sPlayerbotAIConfig->randomBotAccounts.size() - 1 >= sPlayerbotAIConfig->addClassAccountPoolSize
|
||||
? sPlayerbotAIConfig->randomBotAccounts.size() - sPlayerbotAIConfig->addClassAccountPoolSize : 0;
|
||||
int32 minAccountId = sPlayerbotAIConfig->randomBotAccounts[minIdx];
|
||||
if (minAccountId < 0)
|
||||
{
|
||||
@@ -1705,7 +1561,7 @@ void RandomPlayerbotMgr::PrepareAddclassCache()
|
||||
} while (results->NextRow());
|
||||
}
|
||||
}
|
||||
LOG_INFO("playerbots", ">> {} characters collected for addclass command.", collected);
|
||||
LOG_INFO("playerbots", "{} characters collected for addclass command.", collected);
|
||||
}
|
||||
|
||||
void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot)
|
||||
@@ -1715,20 +1571,15 @@ void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot)
|
||||
|
||||
uint32 level = bot->GetLevel();
|
||||
uint8 race = bot->getRace();
|
||||
std::vector<WorldLocation>* locs = nullptr;
|
||||
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
||||
locs = IsAlliance(race) ? &allianceStarterPerLevelCache[level] : &hordeStarterPerLevelCache[level];
|
||||
else
|
||||
locs = &locsPerLevelCache[level];
|
||||
LOG_DEBUG("playerbots", "Random teleporting bot {} for level {} ({} locations available)", bot->GetName().c_str(),
|
||||
bot->GetLevel(), locs->size());
|
||||
if (level >= 10 && urand(0, 100) < sPlayerbotAIConfig->probTeleToBankers * 100)
|
||||
bot->GetLevel(), locsPerLevelCache[level].size());
|
||||
if (level > 10 && urand(0, 100) < sPlayerbotAIConfig->probTeleToBankers * 100)
|
||||
{
|
||||
RandomTeleport(bot, bankerLocsPerLevelCache[level], true);
|
||||
}
|
||||
else
|
||||
{
|
||||
RandomTeleport(bot, *locs);
|
||||
RandomTeleport(bot, locsPerLevelCache[level]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1739,15 +1590,10 @@ void RandomPlayerbotMgr::RandomTeleportGrindForLevel(Player* bot)
|
||||
|
||||
uint32 level = bot->GetLevel();
|
||||
uint8 race = bot->getRace();
|
||||
std::vector<WorldLocation>* locs = nullptr;
|
||||
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
||||
locs = IsAlliance(race) ? &allianceStarterPerLevelCache[level] : &hordeStarterPerLevelCache[level];
|
||||
else
|
||||
locs = &locsPerLevelCache[level];
|
||||
LOG_DEBUG("playerbots", "Random teleporting bot {} for level {} ({} locations available)", bot->GetName().c_str(),
|
||||
bot->GetLevel(), locs->size());
|
||||
bot->GetLevel(), locsPerLevelCache[level].size());
|
||||
|
||||
RandomTeleport(bot, *locs);
|
||||
RandomTeleport(bot, locsPerLevelCache[level]);
|
||||
}
|
||||
|
||||
void RandomPlayerbotMgr::RandomTeleport(Player* bot)
|
||||
@@ -2397,7 +2243,7 @@ void RandomPlayerbotMgr::OnBotLoginInternal(Player* const bot)
|
||||
{
|
||||
LOG_INFO("playerbots", "{}/{} Bot {} logged in", playerBots.size(), sRandomPlayerbotMgr->GetMaxAllowedBotCount(),
|
||||
bot->GetName().c_str());
|
||||
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotFixedLevel)
|
||||
{
|
||||
bot->SetPlayerFlag(PLAYER_FLAGS_NO_XP_GAIN);
|
||||
@@ -2515,8 +2361,7 @@ Player* RandomPlayerbotMgr::GetRandomPlayer()
|
||||
|
||||
void RandomPlayerbotMgr::PrintStats()
|
||||
{
|
||||
printStatsTimer = time(nullptr);
|
||||
LOG_INFO("playerbots", "Random Bots Stats: {} online", playerBots.size());
|
||||
LOG_INFO("playerbots", "{} Random Bots online", playerBots.size());
|
||||
|
||||
std::map<uint8, uint32> alliance, horde;
|
||||
for (uint32 i = 0; i < 10; ++i)
|
||||
@@ -2558,17 +2403,13 @@ void RandomPlayerbotMgr::PrintStats()
|
||||
uint32 engine_dead = 0;
|
||||
uint32 stateCount[MAX_TRAVEL_STATE + 1] = {0};
|
||||
std::vector<std::pair<Quest const*, int32>> questCount;
|
||||
std::unordered_map<NewRpgStatus, int> rpgStatusCount;
|
||||
std::unordered_map<uint32, int> zoneCount;
|
||||
uint8 maxBotLevel = 0;
|
||||
for (PlayerBotMap::iterator i = playerBots.begin(); i != playerBots.end(); ++i)
|
||||
{
|
||||
Player* bot = i->second;
|
||||
if (IsAlliance(bot->getRace()))
|
||||
++alliance[bot->GetLevel()];
|
||||
++alliance[bot->GetLevel() / 10];
|
||||
else
|
||||
++horde[bot->GetLevel()];
|
||||
maxBotLevel = std::max(maxBotLevel, bot->GetLevel());
|
||||
++horde[bot->GetLevel() / 10];
|
||||
|
||||
++perRace[bot->getRace()];
|
||||
++perClass[bot->getClass()];
|
||||
@@ -2622,7 +2463,7 @@ void RandomPlayerbotMgr::PrintStats()
|
||||
++engine_combat;
|
||||
else
|
||||
++engine_dead;
|
||||
|
||||
|
||||
if (botAI->IsHeal(bot, true))
|
||||
++heal;
|
||||
else if (botAI->IsTank(bot, true))
|
||||
@@ -2630,11 +2471,6 @@ void RandomPlayerbotMgr::PrintStats()
|
||||
else
|
||||
++dps;
|
||||
|
||||
zoneCount[bot->GetZoneId()]++;
|
||||
|
||||
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
||||
rpgStatusCount[botAI->rpgInfo.status]++;
|
||||
|
||||
if (TravelTarget* target = botAI->GetAiObjectContext()->GetValue<TravelTarget*>("travel target")->Get())
|
||||
{
|
||||
TravelState state = target->getTravelState();
|
||||
@@ -2664,22 +2500,18 @@ void RandomPlayerbotMgr::PrintStats()
|
||||
}
|
||||
|
||||
LOG_INFO("playerbots", "Bots level:");
|
||||
// uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
||||
uint32 currentAlliance = 0, currentHorde = 0;
|
||||
uint32 step = std::max(1, (maxBotLevel + 4) / 8);
|
||||
uint32 from = 1;
|
||||
for (uint8 i = 1; i <= maxBotLevel; ++i)
|
||||
uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
||||
for (uint8 i = 0; i < 10; ++i)
|
||||
{
|
||||
currentAlliance += alliance[i];
|
||||
currentHorde += horde[i];
|
||||
if (!alliance[i] && !horde[i])
|
||||
continue;
|
||||
|
||||
if (((i + 1) % step == 0) || i == maxBotLevel)
|
||||
{
|
||||
LOG_INFO("playerbots", " {}..{}: {} alliance, {} horde", from, i, currentAlliance, currentHorde);
|
||||
currentAlliance = 0;
|
||||
currentHorde = 0;
|
||||
from = i + 1;
|
||||
}
|
||||
uint32 from = i * 10;
|
||||
uint32 to = std::min(from + 9, maxLevel);
|
||||
if (!from)
|
||||
from = 1;
|
||||
|
||||
LOG_INFO("playerbots", " {}..{}: {} alliance, {} horde", from, to, alliance[i], horde[i]);
|
||||
}
|
||||
|
||||
LOG_INFO("playerbots", "Bots race:");
|
||||
@@ -2716,39 +2548,20 @@ void RandomPlayerbotMgr::PrintStats()
|
||||
LOG_INFO("playerbots", " In BG: {}", inBg);
|
||||
LOG_INFO("playerbots", " In Rest: {}", rest);
|
||||
LOG_INFO("playerbots", " Dead: {}", dead);
|
||||
|
||||
// LOG_INFO("playerbots", "Bots zone:");
|
||||
// for (auto &[zond_id, counter] : zoneCount)
|
||||
// {
|
||||
// const AreaTableEntry* entry = sAreaTableStore.LookupEntry(zond_id);
|
||||
// std::string name = PlayerbotAI::GetLocalizedAreaName(entry);
|
||||
// LOG_INFO("playerbots", " {}: {}", name, counter);
|
||||
// }
|
||||
|
||||
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
||||
{
|
||||
LOG_INFO("playerbots", "Bots rpg status:", dead);
|
||||
LOG_INFO("playerbots", " IDLE: {}", rpgStatusCount[NewRpgStatus::IDLE]);
|
||||
LOG_INFO("playerbots", " REST: {}", rpgStatusCount[NewRpgStatus::REST]);
|
||||
LOG_INFO("playerbots", " GO_GRIND: {}", rpgStatusCount[NewRpgStatus::GO_GRIND]);
|
||||
LOG_INFO("playerbots", " GO_INNKEEPER: {}", rpgStatusCount[NewRpgStatus::GO_INNKEEPER]);
|
||||
LOG_INFO("playerbots", " NEAR_RANDOM: {}", rpgStatusCount[NewRpgStatus::NEAR_RANDOM]);
|
||||
LOG_INFO("playerbots", " NEAR_NPC: {}", rpgStatusCount[NewRpgStatus::NEAR_NPC]);
|
||||
}
|
||||
|
||||
LOG_INFO("playerbots", "Bots engine:", dead);
|
||||
LOG_INFO("playerbots", " Non-combat: {}", engine_noncombat);
|
||||
LOG_INFO("playerbots", " Combat: {}", engine_combat);
|
||||
LOG_INFO("playerbots", " Dead: {}", engine_dead);
|
||||
|
||||
// LOG_INFO("playerbots", "Bots questing:");
|
||||
// LOG_INFO("playerbots", " Picking quests: {}",
|
||||
// stateCount[TRAVEL_STATE_TRAVEL_PICK_UP_QUEST] + stateCount[TRAVEL_STATE_WORK_PICK_UP_QUEST]);
|
||||
// LOG_INFO("playerbots", " Doing quests: {}",
|
||||
// stateCount[TRAVEL_STATE_TRAVEL_DO_QUEST] + stateCount[TRAVEL_STATE_WORK_DO_QUEST]);
|
||||
// LOG_INFO("playerbots", " Completing quests: {}",
|
||||
// stateCount[TRAVEL_STATE_TRAVEL_HAND_IN_QUEST] + stateCount[TRAVEL_STATE_WORK_HAND_IN_QUEST]);
|
||||
// LOG_INFO("playerbots", " Idling: {}", stateCount[TRAVEL_STATE_IDLE]);
|
||||
LOG_INFO("playerbots", "Bots questing:");
|
||||
LOG_INFO("playerbots", " Picking quests: {}",
|
||||
stateCount[TRAVEL_STATE_TRAVEL_PICK_UP_QUEST] + stateCount[TRAVEL_STATE_WORK_PICK_UP_QUEST]);
|
||||
LOG_INFO("playerbots", " Doing quests: {}",
|
||||
stateCount[TRAVEL_STATE_TRAVEL_DO_QUEST] + stateCount[TRAVEL_STATE_WORK_DO_QUEST]);
|
||||
LOG_INFO("playerbots", " Completing quests: {}",
|
||||
stateCount[TRAVEL_STATE_TRAVEL_HAND_IN_QUEST] + stateCount[TRAVEL_STATE_WORK_HAND_IN_QUEST]);
|
||||
LOG_INFO("playerbots", " Idling: {}", stateCount[TRAVEL_STATE_IDLE]);
|
||||
|
||||
/*sort(questCount.begin(), questCount.end(), [](std::pair<Quest const*, int32> i, std::pair<Quest const*, int32> j)
|
||||
{return i.second > j.second; });
|
||||
|
||||
@@ -171,10 +171,6 @@ public:
|
||||
|
||||
void PrepareAddclassCache();
|
||||
std::map<uint8, std::vector<ObjectGuid>> addclassCache;
|
||||
std::map<uint8, std::vector<WorldLocation>> locsPerLevelCache;
|
||||
std::map<uint8, std::vector<WorldLocation>> allianceStarterPerLevelCache;
|
||||
std::map<uint8, std::vector<WorldLocation>> hordeStarterPerLevelCache;
|
||||
std::map<uint8, std::vector<WorldLocation>> bankerLocsPerLevelCache;
|
||||
protected:
|
||||
void OnBotLoginInternal(Player* const bot) override;
|
||||
|
||||
@@ -192,7 +188,6 @@ private:
|
||||
time_t BgCheckTimer;
|
||||
time_t LfgCheckTimer;
|
||||
time_t PlayersCheckTimer;
|
||||
time_t printStatsTimer;
|
||||
uint32 AddRandomBots();
|
||||
bool ProcessBot(uint32 bot);
|
||||
void ScheduleRandomize(uint32 bot, uint32 time);
|
||||
@@ -204,7 +199,8 @@ private:
|
||||
|
||||
std::vector<Player*> players;
|
||||
uint32 processTicks;
|
||||
|
||||
std::map<uint8, std::vector<WorldLocation>> locsPerLevelCache;
|
||||
std::map<uint8, std::vector<WorldLocation>> bankerLocsPerLevelCache;
|
||||
|
||||
// std::map<uint32, std::vector<WorldLocation>> rpgLocsCache;
|
||||
std::map<uint32, std::map<uint32, std::vector<WorldLocation>>> rpgLocsCacheLevel;
|
||||
|
||||
@@ -207,10 +207,7 @@ void PlayerbotFactory::Randomize(bool incremental)
|
||||
Prepare();
|
||||
LOG_DEBUG("playerbots", "Resetting player...");
|
||||
PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Reset");
|
||||
if (!sPlayerbotAIConfig->equipmentPersistence || level < sPlayerbotAIConfig->equipmentPersistenceLevel)
|
||||
{
|
||||
bot->resetTalents(true);
|
||||
}
|
||||
bot->resetTalents(true);
|
||||
// bot->SaveToDB(false, false);
|
||||
ClearSkills();
|
||||
// bot->SaveToDB(false, false);
|
||||
@@ -270,7 +267,7 @@ void PlayerbotFactory::Randomize(bool incremental)
|
||||
|
||||
pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Talents");
|
||||
LOG_DEBUG("playerbots", "Initializing talents...");
|
||||
if (!incremental || !sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel)
|
||||
if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel)
|
||||
{
|
||||
InitTalentsTree();
|
||||
}
|
||||
@@ -305,7 +302,7 @@ void PlayerbotFactory::Randomize(bool incremental)
|
||||
|
||||
pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Equip");
|
||||
LOG_DEBUG("playerbots", "Initializing equipmemt...");
|
||||
if (!incremental || !sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel)
|
||||
if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel)
|
||||
{
|
||||
InitEquipment(incremental, incremental ? false : sPlayerbotAIConfig->twoRoundsGearInit);
|
||||
}
|
||||
@@ -427,7 +424,7 @@ void PlayerbotFactory::Randomize(bool incremental)
|
||||
bot->SetHealth(bot->GetMaxHealth());
|
||||
bot->SetPower(POWER_MANA, bot->GetMaxPower(POWER_MANA));
|
||||
bot->SaveToDB(false, false);
|
||||
// LOG_INFO("playerbots", "Initialization Done.");
|
||||
LOG_INFO("playerbots", "Initialization Done.");
|
||||
if (pmo)
|
||||
pmo->finish();
|
||||
}
|
||||
|
||||
@@ -24,10 +24,6 @@
|
||||
#include "raids/blackwinglair/RaidBwlTriggerContext.h"
|
||||
#include "raids/naxxramas/RaidNaxxActionContext.h"
|
||||
#include "raids/naxxramas/RaidNaxxTriggerContext.h"
|
||||
#include "raids/obsidiansanctum/RaidOsActionContext.h"
|
||||
#include "raids/obsidiansanctum/RaidOsTriggerContext.h"
|
||||
#include "raids/eyeofeternity/RaidEoEActionContext.h"
|
||||
#include "raids/eyeofeternity/RaidEoETriggerContext.h"
|
||||
#include "raids/moltencore/RaidMcActionContext.h"
|
||||
#include "raids/moltencore/RaidMcTriggerContext.h"
|
||||
#include "raids/aq20/RaidAq20ActionContext.h"
|
||||
@@ -52,8 +48,6 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
||||
actionContexts.Add(new RaidBwlActionContext());
|
||||
actionContexts.Add(new RaidAq20ActionContext());
|
||||
actionContexts.Add(new RaidNaxxActionContext());
|
||||
actionContexts.Add(new RaidOsActionContext());
|
||||
actionContexts.Add(new RaidEoEActionContext());
|
||||
actionContexts.Add(new RaidUlduarActionContext());
|
||||
actionContexts.Add(new RaidIccActionContext());
|
||||
actionContexts.Add(new WotlkDungeonUKActionContext());
|
||||
@@ -77,8 +71,6 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
||||
triggerContexts.Add(new RaidBwlTriggerContext());
|
||||
triggerContexts.Add(new RaidAq20TriggerContext());
|
||||
triggerContexts.Add(new RaidNaxxTriggerContext());
|
||||
triggerContexts.Add(new RaidOsTriggerContext());
|
||||
triggerContexts.Add(new RaidEoETriggerContext());
|
||||
triggerContexts.Add(new RaidUlduarTriggerContext());
|
||||
triggerContexts.Add(new RaidIccTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonUKTriggerContext());
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "MeleeCombatStrategy.h"
|
||||
#include "MoveFromGroupStrategy.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "NonCombatStrategy.h"
|
||||
#include "PassiveStrategy.h"
|
||||
#include "PullStrategy.h"
|
||||
@@ -83,7 +82,6 @@ public:
|
||||
creators["reveal"] = &StrategyContext::reveal;
|
||||
creators["collision"] = &StrategyContext::collision;
|
||||
creators["rpg"] = &StrategyContext::rpg;
|
||||
creators["new rpg"] = &StrategyContext::new_rpg;
|
||||
creators["travel"] = &StrategyContext::travel;
|
||||
creators["explore"] = &StrategyContext::explore;
|
||||
creators["map"] = &StrategyContext::map;
|
||||
@@ -154,7 +152,6 @@ private:
|
||||
static Strategy* reveal(PlayerbotAI* botAI) { return new RevealStrategy(botAI); }
|
||||
static Strategy* collision(PlayerbotAI* botAI) { return new CollisionStrategy(botAI); }
|
||||
static Strategy* rpg(PlayerbotAI* botAI) { return new RpgStrategy(botAI); }
|
||||
static Strategy* new_rpg(PlayerbotAI* botAI) { return new NewRpgStrategy(botAI); }
|
||||
static Strategy* travel(PlayerbotAI* botAI) { return new TravelStrategy(botAI); }
|
||||
static Strategy* explore(PlayerbotAI* botAI) { return new ExploreStrategy(botAI); }
|
||||
static Strategy* map(PlayerbotAI* botAI) { return new MapStrategy(botAI); }
|
||||
|
||||
@@ -17,8 +17,8 @@ bool AcceptAllQuestsAction::ProcessQuest(Quest const* quest, Object* questGiver)
|
||||
|
||||
if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
LOG_INFO("playerbots", "{} => Quest [{}] accepted", bot->GetName(), quest->GetTitle());
|
||||
bot->Say("Quest [" + text_quest + "] accepted", LANG_UNIVERSAL);
|
||||
LOG_INFO("playerbots", "{} => Quest [ {} ] accepted", bot->GetName(), quest->GetTitle());
|
||||
bot->Say("Quest [ " + text_quest + " ] accepted", LANG_UNIVERSAL);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -86,7 +86,7 @@ bool AcceptQuestAction::Execute(Event event)
|
||||
if (hasAccept)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "AcceptQuestAction [" << qInfo->GetTitle() << "] - [" << std::to_string(qInfo->GetQuestId()) << "]";
|
||||
ss << "AcceptQuestAction {" << qInfo->GetTitle() << "} - {" << std::to_string(qInfo->GetQuestId()) << "}";
|
||||
LOG_INFO("playerbots", "{}", ss.str().c_str());
|
||||
// botAI->TellMaster(ss.str());
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@
|
||||
#include "VehicleActions.h"
|
||||
#include "WorldBuffAction.h"
|
||||
#include "XpGainAction.h"
|
||||
#include "NewRpgAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
@@ -241,12 +240,6 @@ public:
|
||||
|
||||
creators["toggle pet spell"] = &ActionContext::toggle_pet_spell;
|
||||
creators["pet attack"] = &ActionContext::pet_attack;
|
||||
|
||||
creators["new rpg status update"] = &ActionContext::new_rpg_status_update;
|
||||
creators["new rpg go grind"] = &ActionContext::new_rpg_go_grind;
|
||||
creators["new rpg go innkeeper"] = &ActionContext::new_rpg_go_innkeeper;
|
||||
creators["new rpg move random"] = &ActionContext::new_rpg_move_random;
|
||||
creators["new rpg move npc"] = &ActionContext::new_rpg_move_npc;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -422,12 +415,6 @@ private:
|
||||
|
||||
static Action* toggle_pet_spell(PlayerbotAI* ai) { return new TogglePetSpellAutoCastAction(ai); }
|
||||
static Action* pet_attack(PlayerbotAI* ai) { return new PetAttackAction(ai); }
|
||||
|
||||
static Action* new_rpg_status_update(PlayerbotAI* ai) { return new NewRpgStatusUpdateAction(ai); }
|
||||
static Action* new_rpg_go_grind(PlayerbotAI* ai) { return new NewRpgGoGrindAction(ai); }
|
||||
static Action* new_rpg_go_innkeeper(PlayerbotAI* ai) { return new NewRpgGoInnKeeperAction(ai); }
|
||||
static Action* new_rpg_move_random(PlayerbotAI* ai) { return new NewRpgMoveRandomAction(ai); }
|
||||
static Action* new_rpg_move_npc(PlayerbotAI* ai) { return new NewRpgMoveNpcAction(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -74,7 +74,6 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ostringstream msg;
|
||||
msg << target->GetName();
|
||||
|
||||
@@ -89,11 +88,9 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
|
||||
if (!bot->IsWithinLOSInMap(target))
|
||||
{
|
||||
msg << " is not in my sight";
|
||||
msg << " is not on my sight";
|
||||
if (verbose)
|
||||
botAI->TellError(msg.str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target->isDead())
|
||||
@@ -105,15 +102,6 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->IsInPvpProhibitedZone(bot->GetZoneId())
|
||||
&& (target->IsPlayer() || target->IsPet() || !bot->IsValidAttackTarget(target)))
|
||||
{
|
||||
if (verbose)
|
||||
botAI->TellError("I cannot attack others in PvP prohibited zones");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// if (bot->IsMounted() && bot->IsWithinLOSInMap(target))
|
||||
// {
|
||||
// WorldPacket emptyPacket;
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
#include "LootStrategyAction.h"
|
||||
#include "MailAction.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "NewRpgAction.h"
|
||||
#include "PassLeadershipToMasterAction.h"
|
||||
#include "PositionAction.h"
|
||||
#include "QueryItemUsageAction.h"
|
||||
@@ -89,7 +88,6 @@ public:
|
||||
creators["reputation"] = &ChatActionContext::reputation;
|
||||
creators["log"] = &ChatActionContext::log;
|
||||
creators["los"] = &ChatActionContext::los;
|
||||
creators["rpg status"] = &ChatActionContext::rpg_status;
|
||||
creators["aura"] = &ChatActionContext::aura;
|
||||
creators["drop"] = &ChatActionContext::drop;
|
||||
creators["clean quest log"] = &ChatActionContext::clean_quest_log;
|
||||
@@ -260,7 +258,6 @@ private:
|
||||
static Action* reputation(PlayerbotAI* botAI) { return new TellReputationAction(botAI); }
|
||||
static Action* log(PlayerbotAI* botAI) { return new LogLevelAction(botAI); }
|
||||
static Action* los(PlayerbotAI* botAI) { return new TellLosAction(botAI); }
|
||||
static Action* rpg_status(PlayerbotAI* botAI) { return new TellRpgStatusAction(botAI); }
|
||||
static Action* aura(PlayerbotAI* ai) { return new TellAuraAction(ai); }
|
||||
static Action* ll(PlayerbotAI* botAI) { return new LootStrategyAction(botAI); }
|
||||
static Action* ss(PlayerbotAI* botAI) { return new SkipSpellsListAction(botAI); }
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#include "LootObjectStack.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PossibleRpgTargetsValue.h"
|
||||
#include "PvpTriggers.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "PvpTriggers.h"
|
||||
|
||||
bool AttackEnemyPlayerAction::isUseful()
|
||||
{
|
||||
@@ -49,15 +49,8 @@ bool AttackAnythingAction::isUseful()
|
||||
return false;
|
||||
|
||||
std::string const name = std::string(target->GetName());
|
||||
// Check for invalid targets: Dummy, Charge Target, Melee Target, Ranged Target
|
||||
if (!name.empty() &&
|
||||
(name.find("Dummy") != std::string::npos ||
|
||||
name.find("Charge Target") != std::string::npos ||
|
||||
name.find("Melee Target") != std::string::npos ||
|
||||
name.find("Ranged Target") != std::string::npos))
|
||||
{
|
||||
return false; // Target is one of the disallowed types
|
||||
}
|
||||
if (!name.empty() && name.find("Dummy") != std::string::npos) // Target is not a targetdummy
|
||||
return false;
|
||||
|
||||
// if (!ChooseRpgTargetAction::isFollowValid(bot, target)) //Do not grind mobs far
|
||||
// away from master.
|
||||
@@ -136,33 +129,3 @@ bool DpsAssistAction::isUseful()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AttackRtiTargetAction::Execute(Event event)
|
||||
{
|
||||
Unit* rtiTarget = AI_VALUE(Unit*, "rti target");
|
||||
|
||||
if (rtiTarget && rtiTarget->IsInWorld() && rtiTarget->GetMapId() == bot->GetMapId())
|
||||
{
|
||||
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({rtiTarget->GetGUID()});
|
||||
bool result = Attack(botAI->GetUnit(rtiTarget->GetGUID()));
|
||||
if (result)
|
||||
{
|
||||
context->GetValue<ObjectGuid>("pull target")->Set(rtiTarget->GetGUID());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
botAI->TellError("I dont see my rti attack target");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AttackRtiTargetAction::isUseful()
|
||||
{
|
||||
if (botAI->ContainsStrategy(STRATEGY_TYPE_HEAL))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -69,8 +69,6 @@ public:
|
||||
AttackRtiTargetAction(PlayerbotAI* botAI) : AttackAction(botAI, "attack rti target") {}
|
||||
|
||||
std::string const GetTargetName() override { return "rti target"; }
|
||||
bool Execute(Event event) override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class AttackEnemyFlagCarrierAction : public AttackAction
|
||||
|
||||
@@ -68,11 +68,6 @@ bool CleanQuestLogAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sPlayerbotAIConfig->dropObsoleteQuests)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only output this message if "debug rpg" strategy is enabled
|
||||
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
|
||||
@@ -65,210 +65,88 @@ void EquipAction::EquipItem(Item* item)
|
||||
uint8 slot = item->GetSlot();
|
||||
const ItemTemplate* itemProto = item->GetTemplate();
|
||||
uint32 itemId = itemProto->ItemId;
|
||||
uint8 invType = itemProto->InventoryType;
|
||||
|
||||
// Handle ammunition separately
|
||||
if (invType == INVTYPE_AMMO)
|
||||
if (itemProto->InventoryType == INVTYPE_AMMO)
|
||||
{
|
||||
bot->SetAmmo(itemId);
|
||||
std::ostringstream out;
|
||||
out << "equipping " << chat->FormatItem(itemProto);
|
||||
botAI->TellMaster(out);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle bags first
|
||||
bool equippedBag = false;
|
||||
if (itemProto->Class == ITEM_CLASS_CONTAINER)
|
||||
else
|
||||
{
|
||||
// Attempt to equip as a bag
|
||||
Bag* pBag = reinterpret_cast<Bag*>(item);
|
||||
uint8 newBagSlot = GetSmallestBagSlot();
|
||||
if (newBagSlot > 0)
|
||||
bool equippedBag = false;
|
||||
if (itemProto->Class == ITEM_CLASS_CONTAINER)
|
||||
{
|
||||
uint16 src = ((bagIndex << 8) | slot);
|
||||
uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | newBagSlot);
|
||||
bot->SwapItem(src, dst);
|
||||
equippedBag = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't equip as a bag, try to equip as gear
|
||||
if (!equippedBag)
|
||||
{
|
||||
uint8 dstSlot = botAI->FindEquipSlot(itemProto, NULL_SLOT, true);
|
||||
|
||||
// Check if the item is a weapon and whether the bot can dual wield or use Titan Grip
|
||||
bool isWeapon = (itemProto->Class == ITEM_CLASS_WEAPON);
|
||||
bool canTitanGrip = bot->CanTitanGrip();
|
||||
bool canDualWield = bot->CanDualWield();
|
||||
|
||||
bool isTwoHander = (invType == INVTYPE_2HWEAPON);
|
||||
bool isValidTGWeapon = false;
|
||||
if (canTitanGrip && isTwoHander)
|
||||
{
|
||||
// Titan Grip-valid 2H weapon subclasses: Axe2, Mace2, Sword2
|
||||
isValidTGWeapon = (itemProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 ||
|
||||
itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 ||
|
||||
itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2);
|
||||
}
|
||||
|
||||
// Check if the main hand currently has a 2H weapon equipped
|
||||
Item* currentMHItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
|
||||
bool have2HWeaponEquipped = (currentMHItem && currentMHItem->GetTemplate()->InventoryType == INVTYPE_2HWEAPON);
|
||||
|
||||
bool canDualWieldOrTG = (canDualWield || (canTitanGrip && isTwoHander));
|
||||
|
||||
// If this is a weapon and we can dual wield or Titan Grip, check if we can improve main/off-hand setup
|
||||
if (isWeapon && canDualWieldOrTG)
|
||||
{
|
||||
// Fetch current main hand and offhand items
|
||||
Item* mainHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
|
||||
Item* offHandItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
|
||||
|
||||
// Set up the stats calculator once and reuse results for performance
|
||||
StatsWeightCalculator calculator(bot);
|
||||
calculator.SetItemSetBonus(false);
|
||||
calculator.SetOverflowPenalty(false);
|
||||
|
||||
// Calculate item scores once and store them
|
||||
float newItemScore = calculator.CalculateItem(itemId);
|
||||
float mainHandScore = mainHandItem ? calculator.CalculateItem(mainHandItem->GetTemplate()->ItemId) : 0.0f;
|
||||
float offHandScore = offHandItem ? calculator.CalculateItem(offHandItem->GetTemplate()->ItemId) : 0.0f;
|
||||
|
||||
// Determine where this weapon can go
|
||||
bool canGoMain = (invType == INVTYPE_WEAPON ||
|
||||
invType == INVTYPE_WEAPONMAINHAND ||
|
||||
(canTitanGrip && isTwoHander));
|
||||
|
||||
bool canTGOff = false;
|
||||
if (canTitanGrip && isTwoHander && isValidTGWeapon)
|
||||
canTGOff = true;
|
||||
|
||||
bool canGoOff = (invType == INVTYPE_WEAPON ||
|
||||
invType == INVTYPE_WEAPONOFFHAND ||
|
||||
canTGOff);
|
||||
|
||||
// Check if the main hand item can go to offhand if needed
|
||||
bool mainHandCanGoOff = false;
|
||||
if (mainHandItem)
|
||||
Bag* pBag = (Bag*)&item;
|
||||
uint8 newBagSlot = GetSmallestBagSlot();
|
||||
if (newBagSlot > 0)
|
||||
{
|
||||
const ItemTemplate* mhProto = mainHandItem->GetTemplate();
|
||||
bool mhIsValidTG = false;
|
||||
if (canTitanGrip && mhProto->InventoryType == INVTYPE_2HWEAPON)
|
||||
{
|
||||
mhIsValidTG = (mhProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 ||
|
||||
mhProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 ||
|
||||
mhProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2);
|
||||
}
|
||||
|
||||
mainHandCanGoOff = (mhProto->InventoryType == INVTYPE_WEAPON ||
|
||||
mhProto->InventoryType == INVTYPE_WEAPONOFFHAND ||
|
||||
(mhProto->InventoryType == INVTYPE_2HWEAPON && mhIsValidTG));
|
||||
}
|
||||
|
||||
// Priority 1: Replace main hand if the new weapon is strictly better
|
||||
// and if conditions allow (e.g. no conflicting 2H logic)
|
||||
bool betterThanMH = (newItemScore > mainHandScore);
|
||||
bool mhConditionOK = ((invType != INVTYPE_2HWEAPON && !have2HWeaponEquipped) ||
|
||||
(canTitanGrip && isValidTGWeapon));
|
||||
|
||||
if (canGoMain && betterThanMH && mhConditionOK)
|
||||
{
|
||||
// Equip new weapon in main hand
|
||||
{
|
||||
WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2);
|
||||
ObjectGuid newItemGuid = item->GetGUID();
|
||||
eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_MAINHAND);
|
||||
bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket);
|
||||
}
|
||||
|
||||
// Try moving old main hand weapon to offhand if beneficial
|
||||
if (mainHandItem && mainHandCanGoOff && (!offHandItem || mainHandScore > offHandScore))
|
||||
{
|
||||
const ItemTemplate* oldMHProto = mainHandItem->GetTemplate();
|
||||
|
||||
WorldPacket offhandPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2);
|
||||
ObjectGuid oldMHGuid = mainHandItem->GetGUID();
|
||||
offhandPacket << oldMHGuid << uint8(EQUIPMENT_SLOT_OFFHAND);
|
||||
bot->GetSession()->HandleAutoEquipItemSlotOpcode(offhandPacket);
|
||||
|
||||
std::ostringstream moveMsg;
|
||||
moveMsg << "Main hand upgrade found. Moving " << chat->FormatItem(oldMHProto) << " to offhand";
|
||||
botAI->TellMaster(moveMsg);
|
||||
}
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Equipping " << chat->FormatItem(itemProto) << " in main hand";
|
||||
botAI->TellMaster(out);
|
||||
return;
|
||||
}
|
||||
|
||||
// Priority 2: If not better than main hand, check if better than offhand
|
||||
else if (canGoOff && newItemScore > offHandScore)
|
||||
{
|
||||
// Equip in offhand
|
||||
WorldPacket eqPacket(CMSG_AUTOEQUIP_ITEM_SLOT, 2);
|
||||
ObjectGuid newItemGuid = item->GetGUID();
|
||||
eqPacket << newItemGuid << uint8(EQUIPMENT_SLOT_OFFHAND);
|
||||
bot->GetSession()->HandleAutoEquipItemSlotOpcode(eqPacket);
|
||||
|
||||
std::ostringstream out;
|
||||
out << "Equipping " << chat->FormatItem(itemProto) << " in offhand";
|
||||
botAI->TellMaster(out);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No improvement, do nothing
|
||||
return;
|
||||
uint16 src = ((bagIndex << 8) | slot);
|
||||
uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | newBagSlot);
|
||||
bot->SwapItem(src, dst);
|
||||
equippedBag = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If not a special dual-wield/TG scenario or no improvement found, fall back to original logic
|
||||
if (dstSlot == EQUIPMENT_SLOT_FINGER1 ||
|
||||
dstSlot == EQUIPMENT_SLOT_TRINKET1 ||
|
||||
(dstSlot == EQUIPMENT_SLOT_MAINHAND && canDualWield &&
|
||||
((invType != INVTYPE_2HWEAPON && !have2HWeaponEquipped) || (canTitanGrip && isValidTGWeapon))))
|
||||
if (!equippedBag)
|
||||
{
|
||||
// Handle ring/trinket dual-slot logic
|
||||
Item* const equippedItems[2] = {
|
||||
bot->GetItemByPos(INVENTORY_SLOT_BAG_0, dstSlot),
|
||||
bot->GetItemByPos(INVENTORY_SLOT_BAG_0, dstSlot + 1)
|
||||
};
|
||||
|
||||
if (equippedItems[0])
|
||||
uint8 dstSlot = botAI->FindEquipSlot(itemProto, NULL_SLOT, true);
|
||||
bool have2HWeapon = false;
|
||||
bool isValidTGWeapon = false;
|
||||
if (dstSlot == EQUIPMENT_SLOT_MAINHAND)
|
||||
{
|
||||
if (equippedItems[1])
|
||||
Item* currentWeapon = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
|
||||
have2HWeapon = currentWeapon && currentWeapon->GetTemplate()->InventoryType == INVTYPE_2HWEAPON;
|
||||
isValidTGWeapon = itemProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 ||
|
||||
itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 ||
|
||||
itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2;
|
||||
}
|
||||
|
||||
if (dstSlot == EQUIPMENT_SLOT_FINGER1 ||
|
||||
dstSlot == EQUIPMENT_SLOT_TRINKET1 ||
|
||||
(dstSlot == EQUIPMENT_SLOT_MAINHAND && bot->CanDualWield() &&
|
||||
((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) || (bot->CanTitanGrip() && isValidTGWeapon))))
|
||||
{
|
||||
Item* const equippedItems[2] = {
|
||||
bot->GetItemByPos(INVENTORY_SLOT_BAG_0, dstSlot),
|
||||
bot->GetItemByPos(INVENTORY_SLOT_BAG_0, dstSlot + 1)
|
||||
};
|
||||
|
||||
if (equippedItems[0])
|
||||
{
|
||||
// Both slots are full - pick the worst item to replace
|
||||
StatsWeightCalculator calc(bot);
|
||||
calc.SetItemSetBonus(false);
|
||||
calc.SetOverflowPenalty(false);
|
||||
if (equippedItems[1])
|
||||
{
|
||||
// Both slots are full - determine worst item to replace
|
||||
StatsWeightCalculator calculator(bot);
|
||||
calculator.SetItemSetBonus(false);
|
||||
calculator.SetOverflowPenalty(false);
|
||||
|
||||
// float newItemScore = calculator.CalculateItem(itemId);
|
||||
float equippedItemScore[2] = {
|
||||
equippedItemScore[0] = calculator.CalculateItem(equippedItems[0]->GetTemplate()->ItemId),
|
||||
equippedItemScore[1] = calculator.CalculateItem(equippedItems[1]->GetTemplate()->ItemId)
|
||||
};
|
||||
|
||||
float firstItemScore = calc.CalculateItem(equippedItems[0]->GetTemplate()->ItemId);
|
||||
float secondItemScore = calc.CalculateItem(equippedItems[1]->GetTemplate()->ItemId);
|
||||
|
||||
// If the second slot is worse, place the new item there
|
||||
if (firstItemScore > secondItemScore)
|
||||
// Second item is worse than first, equip candidate item in second slot
|
||||
if (equippedItemScore[0] > equippedItemScore[1])
|
||||
{
|
||||
dstSlot++;
|
||||
}
|
||||
}
|
||||
else // No item equipped in slot 2, equip in that slot instead of replacing first item
|
||||
{
|
||||
dstSlot++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Second slot empty, use it
|
||||
dstSlot++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Equip the item in the chosen slot
|
||||
{
|
||||
WorldPacket packet(CMSG_AUTOEQUIP_ITEM_SLOT, 2);
|
||||
ObjectGuid itemguid = item->GetGUID();
|
||||
|
||||
packet << itemguid << dstSlot;
|
||||
bot->GetSession()->HandleAutoEquipItemSlotOpcode(packet);
|
||||
|
||||
// WorldPacket packet(CMSG_AUTOEQUIP_ITEM, 2);
|
||||
// packet << bagIndex << slot;
|
||||
// bot->GetSession()->HandleAutoEquipItemOpcode(packet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +155,6 @@ void EquipAction::EquipItem(Item* item)
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
|
||||
|
||||
bool EquipUpgradesAction::Execute(Event event)
|
||||
{
|
||||
if (!sPlayerbotAIConfig->autoEquipUpgradeLoot && !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
|
||||
@@ -75,7 +75,7 @@ bool InventoryChangeFailureAction::Execute(Event event)
|
||||
messages[EQUIP_ERR_BAG_FULL4] = messages[EQUIP_ERR_BAG_FULL];
|
||||
messages[EQUIP_ERR_ITEM_SOLD_OUT] = messages[EQUIP_ERR_ITEM_IS_CURRENTLY_SOLD_OUT];
|
||||
messages[EQUIP_ERR_OBJECT_IS_BUSY] = "This object is busy";
|
||||
messages[EQUIP_ERR_NOT_IN_COMBAT] = "I am in combat";
|
||||
messages[EQUIP_ERR_NOT_IN_COMBAT] = "I am not in combat";
|
||||
messages[EQUIP_ERR_NOT_WHILE_DISARMED] = "Cannot do while disarmed";
|
||||
messages[EQUIP_ERR_BAG_FULL6] = messages[EQUIP_ERR_BAG_FULL];
|
||||
messages[EQUIP_ERR_CANT_EQUIP_RANK] = "Not enough rank";
|
||||
|
||||
@@ -177,7 +177,7 @@ bool MovementAction::MoveToLOS(WorldObject* target, bool ranged)
|
||||
}
|
||||
|
||||
bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, bool react, bool normal_only,
|
||||
bool exact_waypoint, MovementPriority priority, bool lessDelay)
|
||||
bool exact_waypoint, MovementPriority priority)
|
||||
{
|
||||
UpdateMovementState();
|
||||
if (!IsMovingAllowed(mapId, x, y, z))
|
||||
@@ -210,10 +210,6 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
mm.Clear();
|
||||
mm.MovePoint(0, x, y, z, generatePath);
|
||||
float delay = 1000.0f * (distance / vehicleBase->GetSpeed(MOVE_RUN));
|
||||
if (lessDelay)
|
||||
{
|
||||
delay -= botAI->GetReactDelay();
|
||||
}
|
||||
delay = std::max(.0f, delay);
|
||||
delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority);
|
||||
@@ -237,10 +233,6 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
mm.Clear();
|
||||
mm.MovePoint(0, x, y, z, generatePath);
|
||||
float delay = 1000.0f * MoveDelay(distance);
|
||||
if (lessDelay)
|
||||
{
|
||||
delay -= botAI->GetReactDelay();
|
||||
}
|
||||
delay = std::max(.0f, delay);
|
||||
delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority);
|
||||
@@ -272,10 +264,6 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
mm.Clear();
|
||||
mm.MovePoint(0, endP.x, endP.y, endP.z, generatePath);
|
||||
float delay = 1000.0f * MoveDelay(distance);
|
||||
if (lessDelay)
|
||||
{
|
||||
delay -= botAI->GetReactDelay();
|
||||
}
|
||||
delay = std::max(.0f, delay);
|
||||
delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority);
|
||||
@@ -834,7 +822,7 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
|
||||
PathGenerator path(bot);
|
||||
path.CalculatePath(tx, ty, tz, false);
|
||||
PathType type = path.GetPathType();
|
||||
int typeOk = PATHFIND_NORMAL | PATHFIND_INCOMPLETE | PATHFIND_SHORTCUT;
|
||||
int typeOk = PATHFIND_NORMAL | PATHFIND_INCOMPLETE;
|
||||
if (!(type & typeOk))
|
||||
return false;
|
||||
float shortenTo = distance;
|
||||
@@ -850,7 +838,7 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
|
||||
path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), shortenTo);
|
||||
G3D::Vector3 endPos = path.GetPath().back();
|
||||
return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z, false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true);
|
||||
MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
float MovementAction::GetFollowAngle()
|
||||
@@ -935,10 +923,10 @@ bool MovementAction::IsMovingAllowed()
|
||||
if (botAI->IsInVehicle() && !botAI->IsInVehicle(true))
|
||||
return false;
|
||||
|
||||
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) ||
|
||||
bot->IsBeingTeleported() || bot->HasRootAura() || bot->HasSpiritOfRedemptionAura() ||
|
||||
bot->HasConfuseAura() || bot->IsCharmed() || bot->HasStunAura() ||
|
||||
bot->IsInFlight() || bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) ||
|
||||
bot->IsBeingTeleported() || bot->isInRoots() || bot->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) ||
|
||||
bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || bot->IsCharmed() || bot->HasAuraType(SPELL_AURA_MOD_STUN) ||
|
||||
bot->HasUnitState(UNIT_STATE_IN_FLIGHT) || bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||
return false;
|
||||
|
||||
if (bot->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) != NULL_MOTION_TYPE)
|
||||
@@ -2025,15 +2013,8 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius)
|
||||
}
|
||||
bool strict = checkAngle.strict;
|
||||
float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance);
|
||||
float dx = bot->GetPositionX() + cos(angle) * fleeDis;
|
||||
float dy = bot->GetPositionY() + sin(angle) * fleeDis;
|
||||
float dz = bot->GetPositionZ();
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
bot->GetPositionZ(), dx, dy, dz))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Position fleePos{dx, dy, dz};
|
||||
Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, bot->GetPositionY() + sin(angle) * fleeDis,
|
||||
bot->GetPositionZ()};
|
||||
if (strict && currentTarget &&
|
||||
fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() >
|
||||
sPlayerbotAIConfig->tooCloseDistance &&
|
||||
@@ -2088,15 +2069,8 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius)
|
||||
}
|
||||
bool strict = checkAngle.strict;
|
||||
float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance);
|
||||
float dx = bot->GetPositionX() + cos(angle) * fleeDis;
|
||||
float dy = bot->GetPositionY() + sin(angle) * fleeDis;
|
||||
float dz = bot->GetPositionZ();
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
bot->GetPositionZ(), dx, dy, dz))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Position fleePos{dx, dy, dz};
|
||||
Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, bot->GetPositionY() + sin(angle) * fleeDis,
|
||||
bot->GetPositionZ()};
|
||||
if (strict && currentTarget &&
|
||||
fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->spellDistance)
|
||||
{
|
||||
@@ -2108,7 +2082,6 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pos.GetExactDist(fleePos) > farestDis)
|
||||
{
|
||||
farestDis = pos.GetExactDist(fleePos);
|
||||
@@ -2564,9 +2537,9 @@ bool SetFacingTargetAction::isUseful() { return !AI_VALUE2(bool, "facing", "curr
|
||||
|
||||
bool SetFacingTargetAction::isPossible()
|
||||
{
|
||||
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST)) ||
|
||||
bot->IsBeingTeleported() || bot->HasConfuseAura() || bot->IsCharmed() ||
|
||||
bot->HasStunAura() || bot->IsInFlight() ||
|
||||
if (bot->isFrozen() || bot->IsPolymorphed() || (bot->isDead() && !bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) ||
|
||||
bot->IsBeingTeleported() || bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) || bot->IsCharmed() ||
|
||||
bot->HasAuraType(SPELL_AURA_MOD_STUN) || bot->HasUnitState(UNIT_STATE_IN_FLIGHT) ||
|
||||
bot->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ protected:
|
||||
bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->contactDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
bool MoveToLOS(WorldObject* target, bool ranged = false);
|
||||
bool MoveTo(uint32 mapId, float x, float y, float z, bool idle = false, bool react = false,
|
||||
bool normal_only = false, bool exact_waypoint = false, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL, bool lessDelay = false);
|
||||
bool normal_only = false, bool exact_waypoint = false, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
bool MoveTo(WorldObject* target, float distance = 0.0f, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig->contactDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
float GetFollowAngle();
|
||||
|
||||
@@ -22,7 +22,7 @@ bool ReleaseSpiritAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->GetCorpse() && bot->HasPlayerFlag(PLAYER_FLAGS_GHOST))
|
||||
if (bot->GetCorpse() && bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
|
||||
{
|
||||
botAI->TellMasterNoFacing("I am already a spirit");
|
||||
return false;
|
||||
@@ -149,7 +149,7 @@ bool AutoReleaseSpiritAction::isUseful()
|
||||
if (bot->InBattleground())
|
||||
return true;
|
||||
|
||||
if (bot->HasPlayerFlag(PLAYER_FLAGS_GHOST))
|
||||
if (bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
|
||||
return false;
|
||||
|
||||
if (!bot->GetGroup())
|
||||
|
||||
@@ -188,7 +188,7 @@ bool FindCorpseAction::Execute(Event event)
|
||||
|
||||
if (!moved)
|
||||
{
|
||||
moved = botAI->DoSpecificAction("spirit healer", Event(), true);
|
||||
moved = botAI->DoSpecificAction("spirit healer");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,17 +347,17 @@ bool SpiritHealerAction::Execute(Event event)
|
||||
if (moved)
|
||||
return true;
|
||||
|
||||
// if (!botAI->HasActivePlayerMaster())
|
||||
// {
|
||||
context->GetValue<uint32>("death count")->Set(dCount + 1);
|
||||
return bot->TeleportTo(ClosestGrave->Map, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, 0.f);
|
||||
// }
|
||||
if (!botAI->HasActivePlayerMaster())
|
||||
{
|
||||
context->GetValue<uint32>("death count")->Set(dCount + 1);
|
||||
return bot->TeleportTo(ClosestGrave->Map, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, 0.f);
|
||||
}
|
||||
|
||||
// LOG_INFO("playerbots", "Bot {} {}:{} <{}> can't find a spirit healer", bot->GetGUID().ToString().c_str(),
|
||||
// bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName().c_str());
|
||||
LOG_INFO("playerbots", "Bot {} {}:{} <{}> can't find a spirit healer", bot->GetGUID().ToString().c_str(),
|
||||
bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName().c_str());
|
||||
|
||||
// botAI->TellError("Cannot find any spirit healer nearby");
|
||||
botAI->TellError("Cannot find any spirit healer nearby");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpiritHealerAction::isUseful() { return bot->HasPlayerFlag(PLAYER_FLAGS_GHOST); }
|
||||
bool SpiritHealerAction::isUseful() { return bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST); }
|
||||
|
||||
@@ -80,7 +80,7 @@ bool MarkRtiAction::Execute(Event event)
|
||||
for (uint8 i = 0; i < 8; i++)
|
||||
{
|
||||
ObjectGuid iconGUID = group->GetTargetIcon(i);
|
||||
if (iconGUID == unit->GetGUID())
|
||||
if (guid == unit->GetGUID())
|
||||
{
|
||||
marked = true;
|
||||
break;
|
||||
|
||||
@@ -207,7 +207,7 @@ bool TradeStatusAction::CheckTrade()
|
||||
for (uint32 slot = 0; slot < TRADE_SLOT_TRADED_COUNT; ++slot)
|
||||
{
|
||||
Item* item = bot->GetTradeData()->GetItem((TradeSlots)slot);
|
||||
if (item && !item->GetTemplate()->SellPrice && !item->GetTemplate()->IsConjuredConsumable())
|
||||
if (item && !item->GetTemplate()->SellPrice)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << chat->FormatItem(item->GetTemplate()) << " - This is not for sale";
|
||||
|
||||
@@ -202,16 +202,6 @@ bool AutoGearAction::Execute(Event event)
|
||||
botAI->TellError("autogear command is not allowed, please check the configuration.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!sPlayerbotAIConfig->autoGearCommandAltBots)
|
||||
{
|
||||
if (!sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
{
|
||||
botAI->TellError("You cannot use autogear on alt bots.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
botAI->TellMaster("I'm auto gearing");
|
||||
uint32 gs = sPlayerbotAIConfig->autoGearScoreLimit == 0
|
||||
? 0
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "WorldBuffAction.h"
|
||||
|
||||
#include "AiFactory.h"
|
||||
#include "Event.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
@@ -40,11 +39,6 @@ std::vector<uint32> WorldBuffAction::NeedWorldBuffs(Unit* unit)
|
||||
if (wb.classId != 0 && wb.classId != unit->getClass())
|
||||
continue;
|
||||
|
||||
uint8 tab = AiFactory::GetPlayerSpecTab(unit->ToPlayer());
|
||||
|
||||
if (wb.specId != tab)
|
||||
continue;
|
||||
|
||||
if (wb.minLevel != 0 && wb.minLevel > unit->GetLevel())
|
||||
continue;
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ void FeralDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
// triggers.push_back(new TriggerNode("not facing target", NextAction::array(0, new NextAction("set facing",
|
||||
// ACTION_NORMAL + 7), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_HIGH + 1), nullptr)));
|
||||
"enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("enemy too close for melee", NextAction::array(0, new NextAction("move out of
|
||||
// enemy contact", ACTION_NORMAL + 8), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
|
||||
@@ -21,8 +21,8 @@ class WotlkDungeonOccActionContext : public NamedObjectContext<Action>
|
||||
static Action* avoid_unstable_sphere(PlayerbotAI* ai) { return new AvoidUnstableSphereAction(ai); }
|
||||
static Action* mount_drake(PlayerbotAI* ai) { return new MountDrakeAction(ai); }
|
||||
static Action* dismount_drake(PlayerbotAI* ai) { return new DismountDrakeAction(ai); }
|
||||
static Action* fly_drake(PlayerbotAI* ai) { return new OccFlyDrakeAction(ai); }
|
||||
static Action* drake_attack(PlayerbotAI* ai) { return new OccDrakeAttackAction(ai); }
|
||||
static Action* fly_drake(PlayerbotAI* ai) { return new FlyDrakeAction(ai); }
|
||||
static Action* drake_attack(PlayerbotAI* ai) { return new DrakeAttackAction(ai); }
|
||||
static Action* avoid_arcane_explosion(PlayerbotAI* ai) { return new AvoidArcaneExplosionAction(ai); }
|
||||
static Action* time_bomb_spread(PlayerbotAI* ai) { return new TimeBombSpreadAction(ai); }
|
||||
};
|
||||
|
||||
@@ -111,7 +111,7 @@ bool DismountDrakeAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OccFlyDrakeAction::Execute(Event event)
|
||||
bool FlyDrakeAction::Execute(Event event)
|
||||
{
|
||||
Player* master = botAI->GetMaster();
|
||||
if (!master) { return false; }
|
||||
@@ -152,7 +152,7 @@ bool OccFlyDrakeAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OccDrakeAttackAction::Execute(Event event)
|
||||
bool DrakeAttackAction::Execute(Event event)
|
||||
{
|
||||
vehicleBase = bot->GetVehicleBase();
|
||||
if (!vehicleBase) { return false; }
|
||||
@@ -188,7 +188,7 @@ bool OccDrakeAttackAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OccDrakeAttackAction::CastDrakeSpellAction(Unit* target, uint32 spellId, uint32 cooldown)
|
||||
bool DrakeAttackAction::CastDrakeSpellAction(Unit* target, uint32 spellId, uint32 cooldown)
|
||||
{
|
||||
if (botAI->CanCastVehicleSpell(spellId, target))
|
||||
if (botAI->CastVehicleSpell(spellId, target))
|
||||
@@ -199,7 +199,7 @@ bool OccDrakeAttackAction::CastDrakeSpellAction(Unit* target, uint32 spellId, ui
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OccDrakeAttackAction::AmberDrakeAction(Unit* target)
|
||||
bool DrakeAttackAction::AmberDrakeAction(Unit* target)
|
||||
{
|
||||
Aura* shockCharges = target->GetAura(SPELL_SHOCK_CHARGE, vehicleBase->GetGUID());
|
||||
if (shockCharges && shockCharges->GetStackAmount() > 8)
|
||||
@@ -225,7 +225,7 @@ bool OccDrakeAttackAction::AmberDrakeAction(Unit* target)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OccDrakeAttackAction::EmeraldDrakeAction(Unit* target)
|
||||
bool DrakeAttackAction::EmeraldDrakeAction(Unit* target)
|
||||
{
|
||||
Aura* poisonStacks = target->GetAura(SPELL_LEECHING_POISON, vehicleBase->GetGUID());
|
||||
if (!poisonStacks || (poisonStacks->GetStackAmount() < 3 ||
|
||||
@@ -286,7 +286,7 @@ bool OccDrakeAttackAction::EmeraldDrakeAction(Unit* target)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OccDrakeAttackAction::RubyDrakeAction(Unit* target)
|
||||
bool DrakeAttackAction::RubyDrakeAction(Unit* target)
|
||||
{
|
||||
Aura* evasiveCharges = vehicleBase->GetAura(SPELL_EVASIVE_CHARGES);
|
||||
Aura* evasiveManeuvers = vehicleBase->GetAura(SPELL_EVASIVE_MANEUVERS);
|
||||
|
||||
@@ -38,17 +38,17 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class OccFlyDrakeAction : public MovementAction
|
||||
class FlyDrakeAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
OccFlyDrakeAction(PlayerbotAI* ai) : MovementAction(ai, "occ fly drake") {}
|
||||
FlyDrakeAction(PlayerbotAI* ai) : MovementAction(ai, "fly drake") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class OccDrakeAttackAction : public Action
|
||||
class DrakeAttackAction : public Action
|
||||
{
|
||||
public:
|
||||
OccDrakeAttackAction(PlayerbotAI* botAI) : Action(botAI, "occ drake attack") {}
|
||||
DrakeAttackAction(PlayerbotAI* botAI) : Action(botAI, "drake attack") {}
|
||||
bool Execute(Event event) override;
|
||||
|
||||
protected:
|
||||
@@ -57,6 +57,7 @@ protected:
|
||||
bool AmberDrakeAction(Unit* target);
|
||||
bool EmeraldDrakeAction(Unit* target);
|
||||
bool RubyDrakeAction(Unit* target);
|
||||
|
||||
};
|
||||
|
||||
class AvoidArcaneExplosionAction : public MovementAction
|
||||
|
||||
@@ -26,12 +26,12 @@ float MountingDrakeMultiplier::GetValue(Action* action)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float OccFlyingMultiplier::GetValue(Action* action)
|
||||
float FlyingMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (bot->GetMapId() != OCULUS_MAP_ID || !bot->GetVehicleBase()) { return 1.0f; }
|
||||
|
||||
// Suppresses FollowAction as well as some attack-based movements
|
||||
if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<OccFlyDrakeAction*>(action))
|
||||
if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<FlyDrakeAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -103,7 +103,7 @@ float EregosMultiplier::GetValue(Action* action)
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ley-guardian eregos");
|
||||
if (!boss) { return 1.0f; }
|
||||
|
||||
if (boss->HasAura(SPELL_PLANAR_SHIFT && dynamic_cast<OccDrakeAttackAction*>(action)))
|
||||
if (boss->HasAura(SPELL_PLANAR_SHIFT && dynamic_cast<DrakeAttackAction*>(action)))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ class MountingDrakeMultiplier : public Multiplier
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class OccFlyingMultiplier : public Multiplier
|
||||
class FlyingMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
OccFlyingMultiplier(PlayerbotAI* ai) : Multiplier(ai, "occ flying drake") {}
|
||||
FlyingMultiplier(PlayerbotAI* ai) : Multiplier(ai, "flying drake") {}
|
||||
|
||||
public:
|
||||
virtual float GetValue(Action* action);
|
||||
|
||||
@@ -36,7 +36,7 @@ void WotlkDungeonOccStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
||||
void WotlkDungeonOccStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||
{
|
||||
multipliers.push_back(new MountingDrakeMultiplier(botAI));
|
||||
multipliers.push_back(new OccFlyingMultiplier(botAI));
|
||||
multipliers.push_back(new FlyingMultiplier(botAI));
|
||||
multipliers.push_back(new UromMultiplier(botAI));
|
||||
multipliers.push_back(new EregosMultiplier(botAI));
|
||||
}
|
||||
|
||||
@@ -106,7 +106,6 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas
|
||||
supported.push_back("reputation");
|
||||
supported.push_back("log");
|
||||
supported.push_back("los");
|
||||
supported.push_back("rpg status");
|
||||
supported.push_back("aura");
|
||||
supported.push_back("drop");
|
||||
supported.push_back("share");
|
||||
|
||||
@@ -22,7 +22,7 @@ void CombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(new TriggerNode("not facing target",
|
||||
NextAction::array(0, new NextAction("set facing", ACTION_MOVE + 7), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("pet attack", NextAction::array(0, new NextAction("pet attack", 40.0f), nullptr)));
|
||||
new TriggerNode("pet attack", NextAction::array(0, new NextAction("pet attack", ACTION_NORMAL), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("combat long stuck", NextAction::array(0, new NextAction("hearthstone", 0.9f),
|
||||
// new NextAction("repop", 0.8f), nullptr)));
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ NextAction** GrindingStrategy::getDefaultActions() { return nullptr; }
|
||||
|
||||
void GrindingStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("drink", 10.2f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("food", 10.1f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("drink", 4.2f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("timer", NextAction::array(0, new NextAction("food", 4.1f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("no target", NextAction::array(0, new NextAction("attack anything", 10.0f), nullptr)));
|
||||
new TriggerNode("no target", NextAction::array(0, new NextAction("attack anything", 4.0f), nullptr)));
|
||||
}
|
||||
|
||||
void MoveRandomStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
@@ -14,7 +14,7 @@ void MeleeCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
// triggers.push_back(new TriggerNode("not facing target", NextAction::array(0, new NextAction("set facing",
|
||||
// ACTION_MOVE + 7), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_HIGH + 1), nullptr)));
|
||||
"enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("enemy too close for melee", NextAction::array(0, new NextAction("move out of
|
||||
// enemy contact", ACTION_NORMAL + 8), nullptr)));
|
||||
}
|
||||
|
||||
@@ -59,9 +59,8 @@ FrostMageStrategy::FrostMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(b
|
||||
|
||||
NextAction** FrostMageStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("frostbolt", ACTION_DEFAULT + 0.2f),
|
||||
new NextAction("shoot", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("fireball", ACTION_DEFAULT), nullptr);
|
||||
return NextAction::array(0, new NextAction("frostbolt", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("shoot", ACTION_DEFAULT), nullptr);
|
||||
}
|
||||
|
||||
void FrostMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
@@ -131,5 +131,5 @@ void DpsPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
// NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), NULL)));
|
||||
|
||||
triggers.push_back(new TriggerNode("enemy out of melee",
|
||||
NextAction::array(0, new NextAction("reach melee", ACTION_HIGH + 1), NULL)));
|
||||
NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), NULL)));
|
||||
}
|
||||
|
||||
@@ -113,5 +113,5 @@ void TankPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(new TriggerNode("not facing target",
|
||||
NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_HIGH + 1), nullptr)));
|
||||
"enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), nullptr)));
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include "Strategy.h"
|
||||
#include "RaidBwlStrategy.h"
|
||||
#include "RaidNaxxStrategy.h"
|
||||
#include "RaidOsStrategy.h"
|
||||
#include "RaidEoEStrategy.h"
|
||||
#include "RaidMcStrategy.h"
|
||||
#include "RaidAq20Strategy.h"
|
||||
#include "RaidIccStrategy.h"
|
||||
@@ -23,8 +21,6 @@ public:
|
||||
creators["bwl"] = &RaidStrategyContext::bwl;
|
||||
creators["aq20"] = &RaidStrategyContext::aq20;
|
||||
creators["naxx"] = &RaidStrategyContext::naxx;
|
||||
creators["wotlk-os"] = &RaidStrategyContext::wotlk_os;
|
||||
creators["wotlk-eoe"] = &RaidStrategyContext::wotlk_eoe;
|
||||
creators["uld"] = &RaidStrategyContext::uld;
|
||||
creators["icc"] = &RaidStrategyContext::icc;
|
||||
}
|
||||
@@ -34,8 +30,6 @@ private:
|
||||
static Strategy* bwl(PlayerbotAI* botAI) { return new RaidBwlStrategy(botAI); }
|
||||
static Strategy* aq20(PlayerbotAI* botAI) { return new RaidAq20Strategy(botAI); }
|
||||
static Strategy* naxx(PlayerbotAI* botAI) { return new RaidNaxxStrategy(botAI); }
|
||||
static Strategy* wotlk_os(PlayerbotAI* botAI) { return new RaidOsStrategy(botAI); }
|
||||
static Strategy* wotlk_eoe(PlayerbotAI* botAI) { return new RaidEoEStrategy(botAI); }
|
||||
static Strategy* uld(PlayerbotAI* botAI) { return new RaidUlduarStrategy(botAI); }
|
||||
static Strategy* icc(PlayerbotAI* botAI) { return new RaidIccStrategy(botAI); }
|
||||
};
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef _PLAYERBOT_RAIDEOEACTIONCONTEXT_H
|
||||
#define _PLAYERBOT_RAIDEOEACTIONCONTEXT_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "RaidEoEActions.h"
|
||||
|
||||
class RaidEoEActionContext : public NamedObjectContext<Action>
|
||||
{
|
||||
public:
|
||||
RaidEoEActionContext()
|
||||
{
|
||||
creators["malygos position"] = &RaidEoEActionContext::position;
|
||||
creators["malygos target"] = &RaidEoEActionContext::target;
|
||||
// creators["pull power spark"] = &RaidEoEActionContext::pull_power_spark;
|
||||
// creators["kill power spark"] = &RaidEoEActionContext::kill_power_spark;
|
||||
creators["fly drake"] = &RaidEoEActionContext::fly_drake;
|
||||
creators["drake attack"] = &RaidEoEActionContext::drake_attack;
|
||||
}
|
||||
|
||||
private:
|
||||
static Action* position(PlayerbotAI* ai) { return new MalygosPositionAction(ai); }
|
||||
static Action* target(PlayerbotAI* ai) { return new MalygosTargetAction(ai); }
|
||||
// static Action* pull_power_spark(PlayerbotAI* ai) { return new PullPowerSparkAction(ai); }
|
||||
// static Action* kill_power_spark(PlayerbotAI* ai) { return new KillPowerSparkAction(ai); }
|
||||
static Action* fly_drake(PlayerbotAI* ai) { return new EoEFlyDrakeAction(ai); }
|
||||
static Action* drake_attack(PlayerbotAI* ai) { return new EoEDrakeAttackAction(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,391 +0,0 @@
|
||||
#include "RaidEoEActions.h"
|
||||
#include "RaidEoETriggers.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
|
||||
bool MalygosPositionAction::Execute(Event event)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "malygos");
|
||||
if (!boss) { return false; }
|
||||
|
||||
uint8 phase = MalygosTrigger::getPhase(bot, boss);
|
||||
|
||||
float distance = 5.0f;
|
||||
|
||||
if (phase == 1)
|
||||
{
|
||||
Unit* spark = nullptr;
|
||||
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||
for (auto& target : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(target);
|
||||
if (unit && unit->GetEntry() == NPC_POWER_SPARK)
|
||||
{
|
||||
spark = unit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Position tank
|
||||
if (botAI->IsMainTank(bot))
|
||||
{
|
||||
if (bot->GetDistance2d(MALYGOS_MAINTANK_POSITION.first, MALYGOS_MAINTANK_POSITION.second) > distance)
|
||||
{
|
||||
return MoveTo(EOE_MAP_ID, MALYGOS_MAINTANK_POSITION.first, MALYGOS_MAINTANK_POSITION.second, bot->GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Position DK for spark pull
|
||||
// else if (spark && bot->IsClass(CLASS_DEATH_KNIGHT))
|
||||
// {
|
||||
// if (bot->GetDistance2d(MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second) > distance)
|
||||
// {
|
||||
// bot->Yell("SPARK SPAWNED, MOVING TO STACK", LANG_UNIVERSAL);
|
||||
// return MoveTo(EOE_MAP_ID, MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second, bot->GetPositionZ(),
|
||||
// false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
else if (spark)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!bot->IsClass(CLASS_HUNTER))
|
||||
{
|
||||
if (bot->GetDistance2d(MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second) > (distance * 3.0f))
|
||||
{
|
||||
return MoveTo(EOE_MAP_ID, MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second, bot->GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MalygosTargetAction::Execute(Event event)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "malygos");
|
||||
if (!boss) { return false; }
|
||||
|
||||
uint8 phase = MalygosTrigger::getPhase(bot, boss);
|
||||
|
||||
if (phase == 1)
|
||||
{
|
||||
if (botAI->IsHeal(bot)) { return false; }
|
||||
|
||||
// Init this as boss by default, if no better target is found just fall back to Malygos
|
||||
Unit* newTarget = boss;
|
||||
// Unit* spark = nullptr;
|
||||
|
||||
// GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||
// for (auto& target : targets)
|
||||
// {
|
||||
// Unit* unit = botAI->GetUnit(target);
|
||||
// if (unit && unit->GetEntry() == NPC_POWER_SPARK)
|
||||
// {
|
||||
// spark = unit;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (spark && botAI->IsRangedDps(bot))
|
||||
// {
|
||||
// newTarget = spark;
|
||||
// }
|
||||
|
||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||
|
||||
if (!currentTarget || currentTarget->GetEntry() != newTarget->GetEntry())
|
||||
{
|
||||
return Attack(newTarget);
|
||||
}
|
||||
}
|
||||
else if (phase == 2)
|
||||
{
|
||||
if (botAI->IsHeal(bot)) { return false; }
|
||||
|
||||
Unit* newTarget = nullptr;
|
||||
Unit* nexusLord = nullptr;
|
||||
Unit* scionOfEternity = nullptr;
|
||||
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||
for (auto& target : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(target);
|
||||
if (!unit) { continue; }
|
||||
|
||||
if (unit->GetEntry() == NPC_NEXUS_LORD)
|
||||
{
|
||||
nexusLord = unit;
|
||||
}
|
||||
else if (unit->GetEntry() == NPC_SCION_OF_ETERNITY)
|
||||
{
|
||||
scionOfEternity = unit;
|
||||
}
|
||||
}
|
||||
|
||||
if (botAI->IsRangedDps(bot) && scionOfEternity)
|
||||
{
|
||||
newTarget = scionOfEternity;
|
||||
}
|
||||
else
|
||||
{
|
||||
newTarget = nexusLord;
|
||||
}
|
||||
|
||||
if (!newTarget) { return false; }
|
||||
|
||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||
if (!currentTarget || currentTarget->GetEntry() != newTarget->GetEntry())
|
||||
{
|
||||
return Attack(newTarget);
|
||||
}
|
||||
}
|
||||
|
||||
// else if (phase == 3)
|
||||
// {}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// bool PullPowerSparkAction::Execute(Event event)
|
||||
// {
|
||||
// Unit* spark = nullptr;
|
||||
|
||||
// GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||
// for (auto& target : targets)
|
||||
// {
|
||||
// Unit* unit = botAI->GetUnit(target);
|
||||
// if (unit && unit->GetEntry() == NPC_POWER_SPARK)
|
||||
// {
|
||||
// spark = unit;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (!spark) { return false; }
|
||||
|
||||
// if (spark->GetDistance2d(MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second) > 3.0f)
|
||||
// {
|
||||
// bot->Yell("GRIPPING SPARK", LANG_UNIVERSAL);
|
||||
// return botAI->CastSpell("death grip", spark);
|
||||
// }
|
||||
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// bool PullPowerSparkAction::isPossible()
|
||||
// {
|
||||
// Unit* spark = nullptr;
|
||||
|
||||
// GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||
// for (auto& target : targets)
|
||||
// {
|
||||
// Unit* unit = botAI->GetUnit(target);
|
||||
// if (unit && unit->GetEntry() == NPC_POWER_SPARK)
|
||||
// {
|
||||
// spark = unit;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return botAI->CanCastSpell(spell, spark);
|
||||
// }
|
||||
|
||||
// bool PullPowerSparkAction::isUseful()
|
||||
// {
|
||||
// Unit* spark = nullptr;
|
||||
|
||||
// GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||
// for (auto& target : targets)
|
||||
// {
|
||||
// Unit* unit = botAI->GetUnit(target);
|
||||
// if (unit && unit->GetEntry() == NPC_POWER_SPARK)
|
||||
// {
|
||||
// spark = unit;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (!spark)
|
||||
// return false;
|
||||
|
||||
// if (!spark->IsInWorld() || spark->GetMapId() != bot->GetMapId())
|
||||
// return false;
|
||||
|
||||
// return bot->GetDistance2d(MALYGOS_STACK_POSITION.first, MALYGOS_STACK_POSITION.second) < 3.0f;
|
||||
// }
|
||||
|
||||
// bool KillPowerSparkAction::Execute(Event event)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
bool EoEFlyDrakeAction::isPossible()
|
||||
{
|
||||
Unit* vehicleBase = bot->GetVehicleBase();
|
||||
return (vehicleBase && vehicleBase->GetEntry() == NPC_WYRMREST_SKYTALON);
|
||||
}
|
||||
bool EoEFlyDrakeAction::Execute(Event event)
|
||||
{
|
||||
Player* master = botAI->GetMaster();
|
||||
if (!master) { return false; }
|
||||
Unit* masterVehicle = master->GetVehicleBase();
|
||||
Unit* vehicleBase = bot->GetVehicleBase();
|
||||
if (!vehicleBase || !masterVehicle) { return false; }
|
||||
|
||||
MotionMaster* mm = vehicleBase->GetMotionMaster();
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "malygos");
|
||||
if (boss && false)
|
||||
{
|
||||
// Handle as boss encounter instead of formation flight
|
||||
mm->Clear(false);
|
||||
float distance = vehicleBase->GetExactDist(boss);
|
||||
float range = 55.0f; // Drake range is 60yd
|
||||
if (distance > range)
|
||||
{
|
||||
mm->MoveForwards(boss, range - distance);
|
||||
vehicleBase->SendMovementFlagUpdate();
|
||||
return true;
|
||||
}
|
||||
|
||||
vehicleBase->SetFacingToObject(boss);
|
||||
mm->MoveIdle();
|
||||
vehicleBase->SendMovementFlagUpdate();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vehicleBase->GetExactDist(masterVehicle) > 5.0f)
|
||||
{
|
||||
uint8 numPlayers;
|
||||
bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL ? numPlayers = 25 : numPlayers = 10;
|
||||
// 3/4 of a circle, with frontal cone 90 deg unobstructed
|
||||
float angle = botAI->GetGroupSlotIndex(bot) * (2*M_PI - M_PI_2)/numPlayers + M_PI_2;
|
||||
// float angle = M_PI;
|
||||
vehicleBase->SetCanFly(true);
|
||||
mm->MoveFollow(masterVehicle, 3.0f, angle);
|
||||
vehicleBase->SendMovementFlagUpdate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EoEDrakeAttackAction::isPossible()
|
||||
{
|
||||
Unit* vehicleBase = bot->GetVehicleBase();
|
||||
return (vehicleBase && vehicleBase->GetEntry() == NPC_WYRMREST_SKYTALON);
|
||||
}
|
||||
bool EoEDrakeAttackAction::Execute(Event event)
|
||||
{
|
||||
vehicleBase = bot->GetVehicleBase();
|
||||
if (!vehicleBase) { return false; }
|
||||
|
||||
// Unit* target = AI_VALUE(Unit*, "current target");
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "malygos");
|
||||
// if (!boss) { return false; }
|
||||
|
||||
if (!boss)
|
||||
{
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "possible targets");
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (!unit || unit->GetEntry() != NPC_MALYGOS) { continue; }
|
||||
|
||||
boss = unit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check this again to see if a target was assigned
|
||||
if (!boss) { return false; }
|
||||
|
||||
if (botAI->IsHeal(bot))
|
||||
{
|
||||
return DrakeHealAction();
|
||||
}
|
||||
else
|
||||
{
|
||||
return DrakeDpsAction(boss);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EoEDrakeAttackAction::CastDrakeSpellAction(Unit* target, uint32 spellId, uint32 cooldown)
|
||||
{
|
||||
if (botAI->CanCastVehicleSpell(spellId, target))
|
||||
if (botAI->CastVehicleSpell(spellId, target))
|
||||
{
|
||||
vehicleBase->AddSpellCooldown(spellId, 0, cooldown);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EoEDrakeAttackAction::DrakeDpsAction(Unit* target)
|
||||
{
|
||||
Unit* vehicleBase = bot->GetVehicleBase();
|
||||
if (!vehicleBase) { return false; }
|
||||
|
||||
Vehicle* veh = bot->GetVehicle();
|
||||
|
||||
uint8 comboPoints = vehicleBase->GetComboPoints(target);
|
||||
if (comboPoints >= 2)
|
||||
{
|
||||
return CastDrakeSpellAction(target, SPELL_ENGULF_IN_FLAMES, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CastDrakeSpellAction(target, SPELL_FLAME_SPIKE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool EoEDrakeAttackAction::DrakeHealAction()
|
||||
{
|
||||
Unit* vehicleBase = bot->GetVehicleBase();
|
||||
if (!vehicleBase) { return false; }
|
||||
|
||||
Unit* target = vehicleBase->GetComboTarget();
|
||||
if (!target)
|
||||
{
|
||||
// Unit* newTarget = nullptr;
|
||||
Unit* newTarget = vehicleBase;
|
||||
GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||
for (auto& member : members)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(member);
|
||||
if (!unit)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Unit* drake = unit->GetVehicleBase();
|
||||
if (!drake || drake->IsFullHealth()) { continue; }
|
||||
|
||||
if (!newTarget || drake->GetHealthPct() < newTarget->GetHealthPct() - 5.0f)
|
||||
{
|
||||
newTarget = drake;
|
||||
}
|
||||
}
|
||||
target = newTarget;
|
||||
}
|
||||
|
||||
uint8 comboPoints = vehicleBase->GetComboPoints(target);
|
||||
if (comboPoints >= 5)
|
||||
{
|
||||
return CastDrakeSpellAction(target, SPELL_LIFE_BURST, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// "Revivify" may be bugged server-side:
|
||||
// "botAI->CanCastVehicleSpell()" returns SPELL_FAILED_BAD_TARGETS when targeting drakes.
|
||||
// Forcing the cast attempt seems to succeed, not sure what's going on here.
|
||||
// return CastDrakeSpellAction(target, SPELL_REVIVIFY, 0);
|
||||
return botAI->CastVehicleSpell(SPELL_REVIVIFY, target);
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
#ifndef _PLAYERBOT_RAIDEOEACTIONS_H
|
||||
#define _PLAYERBOT_RAIDEOEACTIONS_H
|
||||
|
||||
#include "MovementActions.h"
|
||||
#include "AttackAction.h"
|
||||
#include "GenericSpellActions.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
const std::pair<float, float> MALYGOS_MAINTANK_POSITION = {757.0f, 1337.0f};
|
||||
const std::pair<float, float> MALYGOS_STACK_POSITION = {755.0f, 1301.0f};
|
||||
|
||||
class MalygosPositionAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
MalygosPositionAction(PlayerbotAI* botAI, std::string const name = "malygos position")
|
||||
: MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class MalygosTargetAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
MalygosTargetAction(PlayerbotAI* botAI, std::string const name = "malygos target")
|
||||
: AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class PullPowerSparkAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
PullPowerSparkAction(PlayerbotAI* botAI, std::string const name = "pull power spark")
|
||||
: CastSpellAction(botAI, "death grip") {}
|
||||
bool Execute(Event event) override;
|
||||
bool isPossible() override;
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class KillPowerSparkAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
KillPowerSparkAction(PlayerbotAI* botAI, std::string const name = "kill power spark")
|
||||
: AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class EoEFlyDrakeAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
EoEFlyDrakeAction(PlayerbotAI* ai) : MovementAction(ai, "eoe fly drake") {}
|
||||
bool Execute(Event event) override;
|
||||
bool isPossible() override;
|
||||
};
|
||||
|
||||
class EoEDrakeAttackAction : public Action
|
||||
{
|
||||
public:
|
||||
EoEDrakeAttackAction(PlayerbotAI* botAI) : Action(botAI, "eoe drake attack") {}
|
||||
bool Execute(Event event) override;
|
||||
bool isPossible() override;
|
||||
|
||||
protected:
|
||||
Unit* vehicleBase;
|
||||
bool CastDrakeSpellAction(Unit* target, uint32 spellId, uint32 cooldown);
|
||||
bool DrakeDpsAction(Unit* target);
|
||||
bool DrakeHealAction();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,81 +0,0 @@
|
||||
#include "RaidEoEMultipliers.h"
|
||||
|
||||
#include "ChooseTargetActions.h"
|
||||
#include "DKActions.h"
|
||||
#include "DruidActions.h"
|
||||
#include "DruidBearActions.h"
|
||||
#include "FollowActions.h"
|
||||
#include "GenericActions.h"
|
||||
#include "GenericSpellActions.h"
|
||||
#include "MovementActions.h"
|
||||
#include "PaladinActions.h"
|
||||
#include "RaidEoEActions.h"
|
||||
#include "RaidEoETriggers.h"
|
||||
#include "ReachTargetActions.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "WarriorActions.h"
|
||||
|
||||
float MalygosMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "malygos");
|
||||
|
||||
uint8 phase = MalygosTrigger::getPhase(bot, boss);
|
||||
if (phase == 0) { return 1.0f; }
|
||||
|
||||
if (phase == 1)
|
||||
{
|
||||
if (dynamic_cast<FollowAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsDps(bot) && dynamic_cast<DpsAssistAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsRangedDps(bot) && dynamic_cast<DropTargetAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (!botAI->IsMainTank(bot) && dynamic_cast<TankAssistAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<MalygosPositionAction*>(action))
|
||||
// {
|
||||
// return 0.0f;
|
||||
// }
|
||||
}
|
||||
else if (phase == 2)
|
||||
{
|
||||
if (botAI->IsDps(bot) && dynamic_cast<DpsAssistAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<FleeAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<TankAssistAction*>(action))
|
||||
{
|
||||
Unit* target = action->GetTarget();
|
||||
if (target && target->GetEntry() == NPC_SCION_OF_ETERNITY)
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
else if (phase == 3)
|
||||
{
|
||||
// Suppresses FollowAction as well as some attack-based movements
|
||||
if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<EoEFlyDrakeAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
#ifndef _PLAYERRBOT_RAIDEOEMULTIPLIERS_H
|
||||
#define _PLAYERRBOT_RAIDEOEMULTIPLIERS_H
|
||||
|
||||
#include "Multiplier.h"
|
||||
|
||||
class MalygosMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
MalygosMultiplier(PlayerbotAI* ai) : Multiplier(ai, "malygos") {}
|
||||
|
||||
public:
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,25 +0,0 @@
|
||||
#include "RaidEoEStrategy.h"
|
||||
#include "RaidEoEMultipliers.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
void RaidEoEStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("malygos",
|
||||
NextAction::array(0, new NextAction("malygos position", ACTION_MOVE), nullptr)));
|
||||
triggers.push_back(new TriggerNode("malygos",
|
||||
NextAction::array(0, new NextAction("malygos target", ACTION_RAID + 1), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("power spark",
|
||||
// NextAction::array(0, new NextAction("pull power spark", ACTION_RAID + 2), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("power spark",
|
||||
// NextAction::array(0, new NextAction("kill power spark", ACTION_RAID + 3), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("group flying",
|
||||
NextAction::array(0, new NextAction("fly drake", ACTION_NORMAL + 1), nullptr)));
|
||||
triggers.push_back(new TriggerNode("drake combat",
|
||||
NextAction::array(0, new NextAction("drake attack", ACTION_NORMAL + 5), nullptr)));
|
||||
}
|
||||
|
||||
void RaidEoEStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||
{
|
||||
multipliers.push_back(new MalygosMultiplier(botAI));
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#ifndef _PLAYERBOT_RAIDEOESTRATEGY_H
|
||||
#define _PLAYERBOT_RAIDEOESTRATEGY_H
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
#include "Multiplier.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
class RaidEoEStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
RaidEoEStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
||||
virtual std::string const getName() override { return "wotlk-eoe"; }
|
||||
virtual void InitTriggers(std::vector<TriggerNode*> &triggers) override;
|
||||
virtual void InitMultipliers(std::vector<Multiplier*> &multipliers) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef _PLAYERBOT_RAIDEOETRIGGERCONTEXT_H
|
||||
#define _PLAYERBOT_RAIDEOETRIGGERCONTEXT_H
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "RaidEoETriggers.h"
|
||||
|
||||
class RaidEoETriggerContext : public NamedObjectContext<Trigger>
|
||||
{
|
||||
public:
|
||||
RaidEoETriggerContext()
|
||||
{
|
||||
creators["malygos"] = &RaidEoETriggerContext::malygos;
|
||||
creators["power spark"] = &RaidEoETriggerContext::power_spark;
|
||||
}
|
||||
|
||||
private:
|
||||
static Trigger* power_spark(PlayerbotAI* ai) { return new PowerSparkTrigger(ai); }
|
||||
static Trigger* malygos(PlayerbotAI* ai) { return new MalygosTrigger(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,53 +0,0 @@
|
||||
#include "RaidEoETriggers.h"
|
||||
|
||||
#include "SharedDefines.h"
|
||||
|
||||
uint8 MalygosTrigger::getPhase(Player* bot, Unit* boss)
|
||||
{
|
||||
uint8 phase = 0;
|
||||
Unit* vehicle = bot->GetVehicleBase();
|
||||
if (bot->GetMapId() != EOE_MAP_ID) { return phase; }
|
||||
|
||||
if (vehicle && vehicle->GetEntry() == NPC_WYRMREST_SKYTALON)
|
||||
{
|
||||
phase = 3;
|
||||
}
|
||||
else if (boss && boss->HealthAbovePct(50))
|
||||
{
|
||||
phase = 1;
|
||||
}
|
||||
else if (boss)
|
||||
{
|
||||
phase = 2;
|
||||
}
|
||||
|
||||
return phase;
|
||||
}
|
||||
|
||||
bool MalygosTrigger::IsActive()
|
||||
{
|
||||
return bool(AI_VALUE2(Unit*, "find target", "malygos"));
|
||||
}
|
||||
|
||||
bool PowerSparkTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "malygos");
|
||||
if (!boss) { return false; }
|
||||
|
||||
if (bot->getClass() != CLASS_DEATH_KNIGHT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||
for (auto& target : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(target);
|
||||
if (unit && unit->GetEntry() == NPC_POWER_SPARK)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
#ifndef _PLAYERBOT_RAIDEOETRIGGERS_H
|
||||
#define _PLAYERBOT_RAIDEOETRIGGERS_H
|
||||
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Trigger.h"
|
||||
|
||||
enum EyeOfEternityIDs
|
||||
{
|
||||
NPC_MALYGOS = 28859,
|
||||
NPC_POWER_SPARK = 30084,
|
||||
NPC_NEXUS_LORD = 30245,
|
||||
NPC_SCION_OF_ETERNITY = 30249,
|
||||
NPC_WYRMREST_SKYTALON = 30161,
|
||||
|
||||
SPELL_POWER_SPARK_VISUAL = 55845,
|
||||
SPELL_POWER_SPARK_GROUND_BUFF = 55852,
|
||||
SPELL_POWER_SPARK_MALYGOS_BUFF = 56152,
|
||||
|
||||
SPELL_TELEPORT_VISUAL = 52096,
|
||||
|
||||
SPELL_SCION_ARCANE_BARRAGE = 56397,
|
||||
SPELL_ARCANE_SHOCK_N = 57058,
|
||||
SPELL_ARCANE_SHOCK_H = 60073,
|
||||
SPELL_HASTE = 57060,
|
||||
|
||||
SPELL_ALEXSTRASZA_GIFT = 61028,
|
||||
|
||||
// Drake Abilities:
|
||||
// DPS
|
||||
SPELL_FLAME_SPIKE = 56091,
|
||||
SPELL_ENGULF_IN_FLAMES = 56092,
|
||||
// Healing
|
||||
SPELL_REVIVIFY = 57090,
|
||||
SPELL_LIFE_BURST = 57143,
|
||||
// Utility
|
||||
SPELL_FLAME_SHIELD = 57108,
|
||||
SPELL_BLAZING_SPEED = 57092,
|
||||
};
|
||||
|
||||
const uint32 EOE_MAP_ID = 616;
|
||||
|
||||
class MalygosTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
MalygosTrigger(PlayerbotAI* botAI) : Trigger(botAI, "malygos") {}
|
||||
bool IsActive() override;
|
||||
uint8 static getPhase(Player* bot, Unit* boss);
|
||||
};
|
||||
|
||||
class PowerSparkTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
PowerSparkTrigger(PlayerbotAI* botAI) : Trigger(botAI, "power spark") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -834,14 +834,17 @@ bool AnubrekhanPositionAction::Execute(Event event)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
EventMap* eventMap = &boss_ai->events;
|
||||
uint32 locust = eventMap->GetNextEventTime(2);
|
||||
uint32 timer = eventMap->GetTimer();
|
||||
bool inPhase = botAI->HasAura("locust swarm", boss) || boss->GetCurrentSpell(CURRENT_GENERIC_SPELL);
|
||||
if (inPhase)
|
||||
if (inPhase || (locust && locust - timer <= 8000))
|
||||
{
|
||||
if (botAI->IsMainTank(bot))
|
||||
{
|
||||
uint32 nearest = FindNearestWaypoint();
|
||||
uint32 next_point;
|
||||
if (inPhase)
|
||||
if (inPhase || (locust && locust - timer <= 3000))
|
||||
{
|
||||
next_point = (nearest + 1) % intervals;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,26 @@ bool BossEventTrigger<T>::IsActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool BossPhaseTrigger<T>::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", boss_name);
|
||||
if (!boss)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (this->phase_mask == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
T* boss_ai = dynamic_cast<T*>(boss->GetAI());
|
||||
EventMap* eventMap = &boss_ai->events;
|
||||
uint8 phase_mask = eventMap->GetPhaseMask();
|
||||
// bot->Yell("phase mask detected: " + to_string(phase_mask) + " compare with " + to_string(this->phase_mask),
|
||||
// LANG_UNIVERSAL);
|
||||
return phase_mask == this->phase_mask;
|
||||
}
|
||||
|
||||
bool GrobbulusCloudTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE(Unit*, "boss target");
|
||||
@@ -142,6 +162,21 @@ bool SapphironFlightTrigger::IsActive()
|
||||
return helper.IsPhaseFlight();
|
||||
}
|
||||
|
||||
// bool SapphironGroundExceptMainTankTrigger::IsActive()
|
||||
// {
|
||||
// return BossPhaseTrigger::IsActive() && !botAI->IsMainTank(bot);
|
||||
// }
|
||||
|
||||
// bool SapphironFlightTrigger::IsActive()
|
||||
// {
|
||||
// return BossPhaseTrigger::IsActive();
|
||||
// }
|
||||
|
||||
// bool SapphironGroundChillTrigger::IsActive()
|
||||
// {
|
||||
// return BossPhaseTrigger::IsActive() && !botAI->IsMainTank(bot) && botAI->HasAura("chill", bot);
|
||||
// }
|
||||
|
||||
bool GluthTrigger::IsActive() { return helper.UpdateBossAI(); }
|
||||
|
||||
bool GluthMainTankMortalWoundTrigger::IsActive()
|
||||
@@ -169,15 +204,6 @@ bool GluthMainTankMortalWoundTrigger::IsActive()
|
||||
|
||||
bool KelthuzadTrigger::IsActive() { return helper.UpdateBossAI(); }
|
||||
|
||||
bool AnubrekhanTrigger::IsActive() {
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "anub'rekhan");
|
||||
if (!boss)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoathebTrigger::IsActive() { return helper.UpdateBossAI(); }
|
||||
|
||||
bool ThaddiusPhasePetTrigger::IsActive()
|
||||
@@ -208,3 +234,4 @@ bool ThaddiusPhaseThaddiusTrigger::IsActive()
|
||||
}
|
||||
|
||||
template bool BossEventTrigger<Grobbulus::boss_grobbulus::boss_grobbulusAI>::IsActive();
|
||||
template bool BossPhaseTrigger<Anubrekhan::boss_anubrekhan::boss_anubrekhanAI>::IsActive();
|
||||
@@ -49,6 +49,23 @@ protected:
|
||||
uint32 boss_entry, event_id, last_event_time;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class BossPhaseTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
BossPhaseTrigger(PlayerbotAI* ai, std::string boss_name, uint32 phase_mask, std::string name = "boss event")
|
||||
: Trigger(ai, name, 1)
|
||||
{
|
||||
this->boss_name = boss_name;
|
||||
this->phase_mask = phase_mask;
|
||||
}
|
||||
virtual bool IsActive();
|
||||
|
||||
protected:
|
||||
std::string boss_name;
|
||||
uint32 phase_mask;
|
||||
};
|
||||
|
||||
class GrobbulusCloudTrigger : public BossEventTrigger<Grobbulus::boss_grobbulus::boss_grobbulusAI>
|
||||
{
|
||||
public:
|
||||
@@ -100,11 +117,10 @@ private:
|
||||
KelthuzadBossHelper helper;
|
||||
};
|
||||
|
||||
class AnubrekhanTrigger : public Trigger
|
||||
class AnubrekhanTrigger : public BossPhaseTrigger<Anubrekhan::boss_anubrekhan::boss_anubrekhanAI>
|
||||
{
|
||||
public:
|
||||
AnubrekhanTrigger(PlayerbotAI* ai) : Trigger(ai, "anub'rekhan") {}
|
||||
bool IsActive() override;
|
||||
AnubrekhanTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "anub'rekhan", 0, "anub'rekhan trigger") {}
|
||||
};
|
||||
|
||||
class ThaddiusPhasePetTrigger : public Trigger
|
||||
@@ -178,6 +194,12 @@ private:
|
||||
SapphironBossHelper helper;
|
||||
};
|
||||
|
||||
// class SapphironGroundExceptMainTankTrigger : public BossPhaseTrigger
|
||||
// {
|
||||
// public:
|
||||
// SapphironGroundExceptMainTankTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "sapphiron", (1 << (2 - 1)),
|
||||
// "sapphiron ground except main tank") {} virtual bool IsActive();
|
||||
// };
|
||||
|
||||
class SapphironFlightTrigger : public Trigger
|
||||
{
|
||||
@@ -189,6 +211,20 @@ private:
|
||||
SapphironBossHelper helper;
|
||||
};
|
||||
|
||||
// class SapphironGroundChillTrigger : public BossPhaseTrigger
|
||||
// {
|
||||
// public:
|
||||
// SapphironGroundChillTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "sapphiron", 0, "sapphiron chill") {}
|
||||
// virtual bool IsActive();
|
||||
// };
|
||||
|
||||
// class KelthuzadPhaseTwoTrigger : public BossPhaseTrigger
|
||||
// {
|
||||
// public:
|
||||
// KelthuzadPhaseTwoTrigger(PlayerbotAI* ai) : BossPhaseTrigger(ai, "kel'thuzad", 1 << (2 - 1), "kel'thuzad
|
||||
// trigger") {}
|
||||
// };
|
||||
|
||||
class GluthTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
@@ -221,4 +257,5 @@ private:
|
||||
LoathebBossHelper helper;
|
||||
};
|
||||
|
||||
// template BossEventTrigger<class boss_grobbulus::boss_grobbulusAI>;
|
||||
#endif
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef _PLAYERBOT_RAIDOSACTIONCONTEXT_H
|
||||
#define _PLAYERBOT_RAIDOSACTIONCONTEXT_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "RaidOsActions.h"
|
||||
|
||||
class RaidOsActionContext : public NamedObjectContext<Action>
|
||||
{
|
||||
public:
|
||||
RaidOsActionContext()
|
||||
{
|
||||
creators["sartharion tank position"] = &RaidOsActionContext::tank_position;
|
||||
creators["avoid twilight fissure"] = &RaidOsActionContext::avoid_twilight_fissure;
|
||||
creators["avoid flame tsunami"] = &RaidOsActionContext::avoid_flame_tsunami;
|
||||
creators["sartharion attack priority"] = &RaidOsActionContext::attack_priority;
|
||||
creators["enter twilight portal"] = &RaidOsActionContext::enter_twilight_portal;
|
||||
creators["exit twilight portal"] = &RaidOsActionContext::exit_twilight_portal;
|
||||
}
|
||||
|
||||
private:
|
||||
static Action* tank_position(PlayerbotAI* ai) { return new SartharionTankPositionAction(ai); }
|
||||
static Action* avoid_twilight_fissure(PlayerbotAI* ai) { return new AvoidTwilightFissureAction(ai); }
|
||||
static Action* avoid_flame_tsunami(PlayerbotAI* ai) { return new AvoidFlameTsunamiAction(ai); }
|
||||
static Action* attack_priority(PlayerbotAI* ai) { return new SartharionAttackPriorityAction(ai); }
|
||||
static Action* enter_twilight_portal(PlayerbotAI* ai) { return new EnterTwilightPortalAction(ai); }
|
||||
static Action* exit_twilight_portal(PlayerbotAI* ai) { return new ExitTwilightPortalAction(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,246 +0,0 @@
|
||||
#include "RaidOsActions.h"
|
||||
#include "RaidOsTriggers.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
bool SartharionTankPositionAction::Execute(Event event)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion");
|
||||
if (!boss) { return false; }
|
||||
|
||||
// Unit* shadron = AI_VALUE2(Unit*, "find target", "shadron");
|
||||
// Unit* tenebron = AI_VALUE2(Unit*, "find target", "tenebron");
|
||||
// Unit* vesperon = AI_VALUE2(Unit*, "find target", "vesperon");
|
||||
Unit* shadron = nullptr;
|
||||
Unit* tenebron = nullptr;
|
||||
Unit* vesperon = nullptr;
|
||||
|
||||
// Detect incoming drakes before they are on aggro table
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||
for (auto& target : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(target);
|
||||
if (!unit) { continue; }
|
||||
|
||||
switch (unit->GetEntry())
|
||||
{
|
||||
case NPC_SHADRON:
|
||||
shadron = unit;
|
||||
continue;
|
||||
case NPC_TENEBRON:
|
||||
tenebron = unit;
|
||||
continue;
|
||||
case NPC_VESPERON:
|
||||
vesperon = unit;
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Position currentPos = bot->GetPosition();
|
||||
// Adjustable, this is the acceptable distance to stack point that will be accepted as "safe"
|
||||
float looseDistance = 12.0f;
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
{
|
||||
if (bot->GetExactDist2d(SARTHARION_MAINTANK_POSITION.first, SARTHARION_MAINTANK_POSITION.second) > looseDistance)
|
||||
{
|
||||
return MoveTo(OS_MAP_ID, SARTHARION_MAINTANK_POSITION.first, SARTHARION_MAINTANK_POSITION.second, currentPos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
// Offtank grab drakes
|
||||
else if (shadron || tenebron || vesperon)
|
||||
{
|
||||
float triggerDistance = 100.0f;
|
||||
// Prioritise threat before positioning
|
||||
if (tenebron && bot->GetExactDist2d(tenebron) < triggerDistance &&
|
||||
tenebron->GetTarget() != bot->GetGUID() && AI_VALUE(Unit*, "current target") != tenebron)
|
||||
{
|
||||
return Attack(tenebron);
|
||||
}
|
||||
if (shadron && bot->GetExactDist2d(shadron) < triggerDistance &&
|
||||
shadron->GetTarget() != bot->GetGUID() && AI_VALUE(Unit*, "current target") != shadron)
|
||||
{
|
||||
return Attack(shadron);
|
||||
}
|
||||
if (vesperon && bot->GetExactDist2d(vesperon) < triggerDistance &&
|
||||
vesperon->GetTarget() != bot->GetGUID() && AI_VALUE(Unit*, "current target") != vesperon)
|
||||
{
|
||||
return Attack(vesperon);
|
||||
}
|
||||
|
||||
bool drakeInCombat = (tenebron && bot->GetExactDist2d(tenebron) < triggerDistance) ||
|
||||
(shadron && bot->GetExactDist2d(shadron) < triggerDistance) ||
|
||||
(vesperon && bot->GetExactDist2d(vesperon) < triggerDistance);
|
||||
// Offtank has threat on drakes, check positioning
|
||||
if (drakeInCombat && bot->GetExactDist2d(SARTHARION_OFFTANK_POSITION.first, SARTHARION_OFFTANK_POSITION.second) > looseDistance)
|
||||
{
|
||||
return MoveTo(OS_MAP_ID, SARTHARION_OFFTANK_POSITION.first, SARTHARION_OFFTANK_POSITION.second, currentPos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AvoidTwilightFissureAction::Execute(Event event)
|
||||
{
|
||||
const float radius = 5.0f;
|
||||
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (unit && unit->GetEntry() == NPC_TWILIGHT_FISSURE)
|
||||
{
|
||||
float currentDistance = bot->GetDistance2d(unit);
|
||||
if (currentDistance < radius)
|
||||
{
|
||||
return MoveAway(unit, radius - currentDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AvoidFlameTsunamiAction::Execute(Event event)
|
||||
{
|
||||
// Adjustable, this is the acceptable distance to stack point that will be accepted as "safe"
|
||||
float looseDistance = 4.0f;
|
||||
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (unit && unit->GetEntry() == NPC_FLAME_TSUNAMI)
|
||||
{
|
||||
Position currentPos = bot->GetPosition();
|
||||
|
||||
// I think these are centrepoints for the wave segments. Either way they uniquely identify the wave
|
||||
// direction as they have different coords for the left and right waves
|
||||
// int casting is not a mistake, need to avoid FP errors somehow.
|
||||
// I always saw these accurate to around 6 decimal places, but if there are issues,
|
||||
// can switch this to abs comparison of floats which would technically be more robust.
|
||||
int posY = (int) unit->GetPositionY();
|
||||
if (posY == 505 || posY == 555) // RIGHT WAVE
|
||||
{
|
||||
bool wavePassed = currentPos.GetPositionX() > unit->GetPositionX();
|
||||
if (wavePassed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_RIGHT_SAFE_ALL) > looseDistance)
|
||||
{
|
||||
return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_RIGHT_SAFE_ALL, currentPos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
else // LEFT WAVE
|
||||
{
|
||||
bool wavePassed = currentPos.GetPositionX() < unit->GetPositionX();
|
||||
if (wavePassed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (botAI->IsMelee(bot))
|
||||
{
|
||||
if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_MELEE) > looseDistance)
|
||||
{
|
||||
return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_MELEE, currentPos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
else // Ranged/healers
|
||||
{
|
||||
if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_RANGED) > looseDistance)
|
||||
{
|
||||
return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_RANGED, currentPos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SartharionAttackPriorityAction::Execute(Event event)
|
||||
{
|
||||
Unit* sartharion = AI_VALUE2(Unit*, "find target", "sartharion");
|
||||
Unit* shadron = AI_VALUE2(Unit*, "find target", "shadron");
|
||||
Unit* tenebron = AI_VALUE2(Unit*, "find target", "tenebron");
|
||||
Unit* vesperon = AI_VALUE2(Unit*, "find target", "vesperon");
|
||||
Unit* acolyte = AI_VALUE2(Unit*, "find target", "acolyte of shadron");
|
||||
|
||||
Unit* target = nullptr;
|
||||
|
||||
if (acolyte)
|
||||
{
|
||||
target = acolyte;
|
||||
}
|
||||
else if (vesperon)
|
||||
{
|
||||
target = vesperon;
|
||||
}
|
||||
else if (tenebron)
|
||||
{
|
||||
target = tenebron;
|
||||
}
|
||||
else if (shadron)
|
||||
{
|
||||
target = shadron;
|
||||
}
|
||||
else if (sartharion)
|
||||
{
|
||||
target = sartharion;
|
||||
}
|
||||
|
||||
if (target && AI_VALUE(Unit*, "current target") != target)
|
||||
{
|
||||
return Attack(target);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EnterTwilightPortalAction::Execute(Event event)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion");
|
||||
if (!boss || !boss->HasAura(SPELL_GIFT_OF_TWILIGHT_FIRE)) { return false; }
|
||||
|
||||
GameObject* portal = bot->FindNearestGameObject(GO_TWILIGHT_PORTAL, 100.0f);
|
||||
if (!portal) { return false; }
|
||||
|
||||
if (!portal->IsAtInteractDistance(bot))
|
||||
{
|
||||
return MoveTo(portal, fmaxf(portal->GetInteractionDistance() - 1.0f, 0.0f));
|
||||
}
|
||||
|
||||
// Go through portal
|
||||
WorldPacket data1(CMSG_GAMEOBJ_USE);
|
||||
data1 << portal->GetGUID();
|
||||
bot->GetSession()->HandleGameObjectUseOpcode(data1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExitTwilightPortalAction::Execute(Event event)
|
||||
{
|
||||
GameObject* portal = bot->FindNearestGameObject(GO_NORMAL_PORTAL, 100.0f);
|
||||
if (!portal) { return false; }
|
||||
|
||||
if (!portal->IsAtInteractDistance(bot))
|
||||
{
|
||||
return MoveTo(portal, fmaxf(portal->GetInteractionDistance() - 1.0f, 0.0f));
|
||||
}
|
||||
|
||||
// Go through portal
|
||||
WorldPacket data1(CMSG_GAMEOBJ_USE);
|
||||
data1 << portal->GetGUID();
|
||||
bot->GetSession()->HandleGameObjectUseOpcode(data1);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
#ifndef _PLAYERBOT_RAIDOSACTIONS_H
|
||||
#define _PLAYERBOT_RAIDOSACTIONS_H
|
||||
|
||||
#include "MovementActions.h"
|
||||
#include "AttackAction.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
const float TSUNAMI_LEFT_SAFE_MELEE = 552.0f;
|
||||
const float TSUNAMI_LEFT_SAFE_RANGED = 504.0f;
|
||||
const float TSUNAMI_RIGHT_SAFE_ALL = 529.0f;
|
||||
const std::pair<float, float> SARTHARION_MAINTANK_POSITION = {3258.5f, 532.5f};
|
||||
const std::pair<float, float> SARTHARION_OFFTANK_POSITION = {3230.0f, 526.0f};
|
||||
const std::pair<float, float> SARTHARION_RANGED_POSITION = {3248.0f, 507.0f};
|
||||
|
||||
class SartharionTankPositionAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
SartharionTankPositionAction(PlayerbotAI* botAI, std::string const name = "sartharion tank position")
|
||||
: AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class AvoidTwilightFissureAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
AvoidTwilightFissureAction(PlayerbotAI* botAI, std::string const name = "avoid twilight fissure")
|
||||
: MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class AvoidFlameTsunamiAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
AvoidFlameTsunamiAction(PlayerbotAI* botAI, std::string const name = "avoid flame tsunami")
|
||||
: MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class SartharionAttackPriorityAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
SartharionAttackPriorityAction(PlayerbotAI* botAI, std::string const name = "sartharion attack priority")
|
||||
: AttackAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class EnterTwilightPortalAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
EnterTwilightPortalAction(PlayerbotAI* botAI, std::string const name = "enter twilight portal")
|
||||
: MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class ExitTwilightPortalAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
ExitTwilightPortalAction(PlayerbotAI* botAI, std::string const name = "exit twilight portal")
|
||||
: MovementAction(botAI, name) {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "RaidOsMultipliers.h"
|
||||
|
||||
#include "ChooseTargetActions.h"
|
||||
#include "DKActions.h"
|
||||
#include "DruidActions.h"
|
||||
#include "DruidBearActions.h"
|
||||
#include "FollowActions.h"
|
||||
#include "GenericActions.h"
|
||||
#include "GenericSpellActions.h"
|
||||
#include "MovementActions.h"
|
||||
#include "PaladinActions.h"
|
||||
#include "RaidOsActions.h"
|
||||
#include "RaidOsTriggers.h"
|
||||
#include "ReachTargetActions.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "WarriorActions.h"
|
||||
|
||||
float SartharionMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion");
|
||||
if (!boss) { return 1.0f; }
|
||||
|
||||
Unit* target = action->GetTarget();
|
||||
|
||||
if (botAI->IsMainTank(bot) && dynamic_cast<TankFaceAction*>(action))
|
||||
{
|
||||
// return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsDps(bot) && dynamic_cast<DpsAssistAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsMainTank(bot) && target && target != boss &&
|
||||
(dynamic_cast<TankAssistAction*>(action) || dynamic_cast<CastTauntAction*>(action) || dynamic_cast<CastDarkCommandAction*>(action) ||
|
||||
dynamic_cast<CastHandOfReckoningAction*>(action) || dynamic_cast<CastGrowlAction*>(action)))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsAssistTank(bot) && target && target == boss &&
|
||||
(dynamic_cast<CastTauntAction*>(action) || dynamic_cast<CastDarkCommandAction*>(action) ||
|
||||
dynamic_cast<CastHandOfReckoningAction*>(action) || dynamic_cast<CastGrowlAction*>(action)))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
#ifndef _PLAYERRBOT_RAIDOSMULTIPLIERS_H
|
||||
#define _PLAYERRBOT_RAIDOSMULTIPLIERS_H
|
||||
|
||||
#include "Multiplier.h"
|
||||
|
||||
class SartharionMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
SartharionMultiplier(PlayerbotAI* ai) : Multiplier(ai, "sartharion") {}
|
||||
|
||||
public:
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,32 +0,0 @@
|
||||
#include "RaidOsStrategy.h"
|
||||
#include "RaidOsMultipliers.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
void RaidOsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("sartharion tank",
|
||||
NextAction::array(0, new NextAction("sartharion tank position", ACTION_MOVE), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("twilight fissure",
|
||||
NextAction::array(0, new NextAction("avoid twilight fissure", ACTION_RAID + 2), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("flame tsunami",
|
||||
NextAction::array(0, new NextAction("avoid flame tsunami", ACTION_RAID + 1), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("sartharion dps",
|
||||
NextAction::array(0, new NextAction("sartharion attack priority", ACTION_RAID), nullptr)));
|
||||
// Flank dragon positioning
|
||||
triggers.push_back(new TriggerNode("sartharion melee positioning",
|
||||
NextAction::array(0, new NextAction("rear flank", ACTION_MOVE + 4), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("twilight portal enter",
|
||||
NextAction::array(0, new NextAction("enter twilight portal", ACTION_RAID + 1), nullptr)));
|
||||
triggers.push_back(new TriggerNode("twilight portal exit",
|
||||
NextAction::array(0, new NextAction("exit twilight portal", ACTION_RAID + 1), nullptr)));
|
||||
}
|
||||
|
||||
void RaidOsStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||
{
|
||||
multipliers.push_back(new SartharionMultiplier(botAI));
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#ifndef _PLAYERBOT_RAIDOSSTRATEGY_H
|
||||
#define _PLAYERBOT_RAIDOSSTRATEGY_H
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
#include "Multiplier.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
class RaidOsStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
RaidOsStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
||||
virtual std::string const getName() override { return "wotlk-os"; }
|
||||
virtual void InitTriggers(std::vector<TriggerNode*> &triggers) override;
|
||||
virtual void InitMultipliers(std::vector<Multiplier*> &multipliers) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef _PLAYERBOT_RAIDOSTRIGGERCONTEXT_H
|
||||
#define _PLAYERBOT_RAIDOSTRIGGERCONTEXT_H
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "RaidOsTriggers.h"
|
||||
|
||||
class RaidOsTriggerContext : public NamedObjectContext<Trigger>
|
||||
{
|
||||
public:
|
||||
RaidOsTriggerContext()
|
||||
{
|
||||
creators["sartharion tank"] = &RaidOsTriggerContext::sartharion_tank;
|
||||
creators["flame tsunami"] = &RaidOsTriggerContext::flame_tsunami;
|
||||
creators["twilight fissure"] = &RaidOsTriggerContext::twilight_fissure;
|
||||
creators["sartharion dps"] = &RaidOsTriggerContext::sartharion_dps;
|
||||
creators["sartharion melee positioning"] = &RaidOsTriggerContext::sartharion_melee;
|
||||
creators["twilight portal enter"] = &RaidOsTriggerContext::twilight_portal_enter;
|
||||
creators["twilight portal exit"] = &RaidOsTriggerContext::twilight_portal_exit;
|
||||
}
|
||||
|
||||
private:
|
||||
static Trigger* sartharion_tank(PlayerbotAI* ai) { return new SartharionTankTrigger(ai); }
|
||||
static Trigger* flame_tsunami(PlayerbotAI* ai) { return new FlameTsunamiTrigger(ai); }
|
||||
static Trigger* twilight_fissure(PlayerbotAI* ai) { return new TwilightFissureTrigger(ai); }
|
||||
static Trigger* sartharion_dps(PlayerbotAI* ai) { return new SartharionDpsTrigger(ai); }
|
||||
static Trigger* sartharion_melee(PlayerbotAI* ai) { return new SartharionMeleePositioningTrigger(ai); }
|
||||
static Trigger* twilight_portal_enter(PlayerbotAI* ai) { return new TwilightPortalEnterTrigger(ai); }
|
||||
static Trigger* twilight_portal_exit(PlayerbotAI* ai) { return new TwilightPortalExitTrigger(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,128 +0,0 @@
|
||||
#include "RaidOsTriggers.h"
|
||||
|
||||
#include "SharedDefines.h"
|
||||
|
||||
bool SartharionTankTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion");
|
||||
if (!boss) { return false; }
|
||||
|
||||
return botAI->IsTank(bot);
|
||||
}
|
||||
|
||||
bool FlameTsunamiTrigger::IsActive()
|
||||
{
|
||||
if (botAI->IsTank(bot)) { return false; }
|
||||
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion");
|
||||
if (!boss) { return false; }
|
||||
|
||||
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (unit)
|
||||
{
|
||||
if (unit->GetEntry() == NPC_FLAME_TSUNAMI)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TwilightFissureTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion");
|
||||
if (!boss) { return false; }
|
||||
|
||||
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (unit)
|
||||
{
|
||||
if (unit->GetEntry() == NPC_TWILIGHT_FISSURE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SartharionDpsTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion");
|
||||
if (!boss) { return false; }
|
||||
|
||||
return botAI->IsDps(bot);
|
||||
}
|
||||
|
||||
bool SartharionMeleePositioningTrigger::IsActive()
|
||||
{
|
||||
if (!botAI->IsMelee(bot) || !botAI->IsDps(bot)) { return false; }
|
||||
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion");
|
||||
if (!boss) { return false; }
|
||||
|
||||
Unit* shadron = AI_VALUE2(Unit*, "find target", "shadron");
|
||||
Unit* tenebron = AI_VALUE2(Unit*, "find target", "tenebron");
|
||||
Unit* vesperon = AI_VALUE2(Unit*, "find target", "vesperon");
|
||||
|
||||
return !(shadron || tenebron || vesperon);
|
||||
}
|
||||
|
||||
bool TwilightPortalEnterTrigger::IsActive()
|
||||
{
|
||||
if (botAI->IsMainTank(bot) || botAI->IsHealAssistantOfIndex(bot, 0)) { return false; }
|
||||
|
||||
// In 25-man, take two healers in. Otherwise just take one
|
||||
// if (bot->GetRaidDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL)
|
||||
// {
|
||||
// if (botAI->IsHealAssistantOfIndex(bot, 0) || botAI->IsHealAssistantOfIndex(bot, 1))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (botAI->IsHealAssistantOfIndex(bot, 0))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// Don't enter portal until drakes are dead
|
||||
if (bot->HasAura(SPELL_POWER_OF_SHADRON) ||
|
||||
bot->HasAura(SPELL_POWER_OF_TENEBRON) ||
|
||||
bot->HasAura(SPELL_POWER_OF_VESPERON))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion");
|
||||
if (!boss) { return false; }
|
||||
|
||||
// GuidVector objects = AI_VALUE(GuidVector, "nearest game objects no los");
|
||||
// for (auto& object : objects)
|
||||
// {
|
||||
// GameObject* go = botAI->GetGameObject(object);
|
||||
// if (go && go->GetEntry() == GO_TWILIGHT_PORTAL)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
return bool(bot->FindNearestGameObject(GO_TWILIGHT_PORTAL, 100.0f));
|
||||
}
|
||||
|
||||
bool TwilightPortalExitTrigger::IsActive()
|
||||
{
|
||||
return bot->HasAura(SPELL_TWILIGHT_SHIFT) && !AI_VALUE2(Unit*, "find target", "acolyte of shadron");
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
#ifndef _PLAYERBOT_RAIDOSTRIGGERS_H
|
||||
#define _PLAYERBOT_RAIDOSTRIGGERS_H
|
||||
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Trigger.h"
|
||||
|
||||
enum ObsidianSanctumIDs
|
||||
{
|
||||
// Bosses
|
||||
NPC_SARTHARION = 28860,
|
||||
NPC_SHADRON = 30451,
|
||||
NPC_TENEBRON = 30452,
|
||||
NPC_VESPERON = 30449,
|
||||
|
||||
// Mini-boss shared
|
||||
SPELL_SHADOW_BREATH = 57570,
|
||||
SPELL_SHADOW_FISSURE = 57579,
|
||||
SPELL_SUMMON_TWILIGHT_WHELP = 58035,
|
||||
SPELL_GIFT_OF_TWILIGHT_SHADOW = 57835,
|
||||
SPELL_TWILIGHT_TORMENT_VESPERON = 57935,
|
||||
|
||||
// Sartharion
|
||||
SPELL_SARTHARION_CLEAVE = 56909,
|
||||
SPELL_SARTHARION_FLAME_BREATH = 56908,
|
||||
SPELL_SARTHARION_TAIL_LASH = 56910,
|
||||
SPELL_CYCLONE_AURA_PERIODIC = 57598,
|
||||
SPELL_LAVA_STRIKE_DUMMY = 57578,
|
||||
SPELL_LAVA_STRIKE_DUMMY_TRIGGER = 57697,
|
||||
SPELL_LAVA_STRIKE_SUMMON = 57572,
|
||||
SPELL_SARTHARION_PYROBUFFET = 56916,
|
||||
SPELL_SARTHARION_BERSERK = 61632,
|
||||
SPELL_SARTHARION_TWILIGHT_REVENGE = 60639,
|
||||
|
||||
// Sartharion with drakes
|
||||
SPELL_WILL_OF_SARTHARION = 61254,
|
||||
SPELL_POWER_OF_TENEBRON = 61248,
|
||||
SPELL_POWER_OF_VESPERON = 61251,
|
||||
SPELL_POWER_OF_SHADRON = 58105,
|
||||
SPELL_GIFT_OF_TWILIGHT_FIRE = 58766,
|
||||
|
||||
// Visuals
|
||||
SPELL_EGG_MARKER_VISUAL = 58547,
|
||||
SPELL_FLAME_TSUNAMI_VISUAL = 57494,
|
||||
|
||||
// Misc
|
||||
SPELL_FADE_ARMOR = 60708,
|
||||
SPELL_FLAME_TSUNAMI_DAMAGE_AURA = 57492,
|
||||
SPELL_FLAME_TSUNAMI_LEAP = 60241,
|
||||
SPELL_SARTHARION_PYROBUFFET_TRIGGER = 57557,
|
||||
|
||||
NPC_TWILIGHT_EGG = 30882,
|
||||
NPC_TWILIGHT_WHELP = 30890,
|
||||
NPC_DISCIPLE_OF_SHADRON = 30688,
|
||||
NPC_DISCIPLE_OF_VESPERON = 30858,
|
||||
NPC_ACOLYTE_OF_SHADRON = 31218,
|
||||
NPC_ACOLYTE_OF_VESPERON = 31219,
|
||||
|
||||
// Sartharion fight
|
||||
NPC_LAVA_BLAZE = 30643,
|
||||
NPC_FLAME_TSUNAMI = 30616,
|
||||
NPC_SAFE_AREA_TRIGGER = 30494,
|
||||
NPC_TWILIGHT_FISSURE = 30641,
|
||||
GO_TWILIGHT_PORTAL = 193988,
|
||||
GO_NORMAL_PORTAL = 193989,
|
||||
SPELL_TWILIGHT_SHIFT = 57874,
|
||||
};
|
||||
|
||||
const uint32 OS_MAP_ID = 615;
|
||||
|
||||
class SartharionTankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
SartharionTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "sartharion tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class FlameTsunamiTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
FlameTsunamiTrigger(PlayerbotAI* botAI) : Trigger(botAI, "flame tsunami") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class TwilightFissureTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
TwilightFissureTrigger(PlayerbotAI* botAI) : Trigger(botAI, "twilight fissure") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class SartharionDpsTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
SartharionDpsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "sartharion dps") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class SartharionMeleePositioningTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
SartharionMeleePositioningTrigger(PlayerbotAI* botAI) : Trigger(botAI, "sartharion melee positioning") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class TwilightPortalEnterTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
TwilightPortalEnterTrigger(PlayerbotAI* botAI) : Trigger(botAI, "twilight portal enter") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class TwilightPortalExitTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
TwilightPortalExitTrigger(PlayerbotAI* botAI) : Trigger(botAI, "twilight portal exit") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -88,6 +88,6 @@ void AssassinationRogueStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"enemy out of melee",
|
||||
NextAction::array(0, new NextAction("stealth", ACTION_HIGH + 3), new NextAction("sprint", ACTION_HIGH + 2),
|
||||
new NextAction("reach melee", ACTION_HIGH + 1), NULL)));
|
||||
NextAction::array(0, new NextAction("stealth", ACTION_NORMAL + 9), new NextAction("sprint", ACTION_NORMAL + 8),
|
||||
new NextAction("reach melee", ACTION_NORMAL + 7), NULL)));
|
||||
}
|
||||
|
||||
@@ -134,8 +134,8 @@ void DpsRogueStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"enemy out of melee",
|
||||
NextAction::array(0, new NextAction("stealth", ACTION_HIGH + 3), new NextAction("sprint", ACTION_HIGH + 2),
|
||||
new NextAction("reach melee", ACTION_HIGH + 1), nullptr)));
|
||||
NextAction::array(0, new NextAction("stealth", ACTION_NORMAL + 9), new NextAction("sprint", ACTION_NORMAL + 8),
|
||||
new NextAction("reach melee", ACTION_NORMAL + 7), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("expose armor",
|
||||
NextAction::array(0, new NextAction("expose armor", ACTION_HIGH + 3), nullptr)));
|
||||
|
||||
@@ -1,380 +0,0 @@
|
||||
#include "NewRpgAction.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "PathGenerator.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Random.h"
|
||||
#include "RandomPlayerbotMgr.h"
|
||||
#include "Timer.h"
|
||||
#include "TravelMgr.h"
|
||||
#include "World.h"
|
||||
|
||||
bool TellRpgStatusAction::Execute(Event event)
|
||||
{
|
||||
std::string out = botAI->rpgInfo.ToString();
|
||||
botAI->TellMasterNoFacing(out);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NewRpgStatusUpdateAction::Execute(Event event)
|
||||
{
|
||||
NewRpgInfo& info = botAI->rpgInfo;
|
||||
switch (info.status)
|
||||
{
|
||||
case NewRpgStatus::IDLE:
|
||||
{
|
||||
uint32 roll = urand(1, 100);
|
||||
// IDLE -> NEAR_NPC
|
||||
// if ((!info.lastNearNpc || info.lastNearNpc + setNpcInterval < getMSTime()) && roll <= 30)
|
||||
if (roll <= 30)
|
||||
{
|
||||
info.lastNearNpc = getMSTime();
|
||||
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets");
|
||||
if (!possibleTargets.empty())
|
||||
{
|
||||
info.status = NewRpgStatus::NEAR_NPC;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// IDLE -> GO_INNKEEPER
|
||||
else if (bot->GetLevel() >= 6 && roll <= 40)
|
||||
{
|
||||
WorldPosition pos = SelectRandomInnKeeperPos();
|
||||
if (pos != WorldPosition() && bot->GetExactDist(pos) > 50.0f)
|
||||
{
|
||||
info.lastGoInnKeeper = getMSTime();
|
||||
info.status = NewRpgStatus::GO_INNKEEPER;
|
||||
info.innKeeperPos = pos;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// IDLE -> GO_GRIND
|
||||
else if (roll <= 90)
|
||||
{
|
||||
WorldPosition pos = SelectRandomGrindPos();
|
||||
if (pos != WorldPosition())
|
||||
{
|
||||
info.lastGoGrind = getMSTime();
|
||||
info.status = NewRpgStatus::GO_GRIND;
|
||||
info.grindPos = pos;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// IDLE -> REST
|
||||
info.status = NewRpgStatus::REST;
|
||||
info.lastRest = getMSTime();
|
||||
bot->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
return true;
|
||||
}
|
||||
case NewRpgStatus::GO_GRIND:
|
||||
{
|
||||
WorldPosition& originalPos = info.grindPos;
|
||||
assert(info.grindPos != WorldPosition());
|
||||
// GO_GRIND -> NEAR_RANDOM
|
||||
if (bot->GetExactDist(originalPos) < 10.0f)
|
||||
{
|
||||
info.status = NewRpgStatus::NEAR_RANDOM;
|
||||
info.lastNearRandom = getMSTime();
|
||||
info.grindPos = WorldPosition();
|
||||
return true;
|
||||
}
|
||||
// // just choose another grindPos
|
||||
// if (!info.lastGoGrind || info.lastGoGrind + setGrindInterval < getMSTime())
|
||||
// {
|
||||
// WorldPosition pos = SelectRandomGrindPos();
|
||||
// if (pos == WorldPosition())
|
||||
// break;
|
||||
// info.status = NewRpgStatus::GO_GRIND;
|
||||
// info.lastGoGrind = getMSTime();
|
||||
// info.grindPos = pos;
|
||||
// return true;
|
||||
// }
|
||||
break;
|
||||
}
|
||||
case NewRpgStatus::GO_INNKEEPER:
|
||||
{
|
||||
WorldPosition& originalPos = info.innKeeperPos;
|
||||
assert(info.innKeeperPos != WorldPosition());
|
||||
// GO_INNKEEPER -> NEAR_NPC
|
||||
if (bot->GetExactDist(originalPos) < 10.0f)
|
||||
{
|
||||
info.lastNearNpc = getMSTime();
|
||||
info.status = NewRpgStatus::NEAR_NPC;
|
||||
info.innKeeperPos = WorldPosition();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NewRpgStatus::NEAR_RANDOM:
|
||||
{
|
||||
// NEAR_RANDOM -> IDLE
|
||||
if (info.lastNearRandom + statusNearRandomDuration < getMSTime())
|
||||
{
|
||||
info.status = NewRpgStatus::IDLE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NewRpgStatus::NEAR_NPC:
|
||||
{
|
||||
if (info.lastNearNpc + statusNearNpcDuration < getMSTime())
|
||||
{
|
||||
info.status = NewRpgStatus::IDLE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NewRpgStatus::REST:
|
||||
{
|
||||
// REST -> IDLE
|
||||
if (info.lastRest + statusRestDuration < getMSTime())
|
||||
{
|
||||
info.status = NewRpgStatus::IDLE;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldPosition NewRpgStatusUpdateAction::SelectRandomGrindPos()
|
||||
{
|
||||
const std::vector<WorldLocation>& locs = sRandomPlayerbotMgr->locsPerLevelCache[bot->GetLevel()];
|
||||
std::vector<WorldLocation> lo_prepared_locs, hi_prepared_locs;
|
||||
for (auto& loc : locs)
|
||||
{
|
||||
if (bot->GetMapId() != loc.GetMapId())
|
||||
continue;
|
||||
|
||||
if (bot->GetMap()->GetZoneId(bot->GetPhaseMask(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ()) !=
|
||||
bot->GetZoneId())
|
||||
continue;
|
||||
|
||||
if (bot->GetExactDist(loc) < 500.0f)
|
||||
{
|
||||
hi_prepared_locs.push_back(loc);
|
||||
}
|
||||
|
||||
if (bot->GetExactDist(loc) < 2500.0f)
|
||||
{
|
||||
lo_prepared_locs.push_back(loc);
|
||||
}
|
||||
}
|
||||
WorldPosition dest;
|
||||
if (urand(1, 100) <= 50 && !hi_prepared_locs.empty())
|
||||
{
|
||||
uint32 idx = urand(0, hi_prepared_locs.size() - 1);
|
||||
dest = hi_prepared_locs[idx];
|
||||
}
|
||||
else if (!lo_prepared_locs.empty())
|
||||
{
|
||||
uint32 idx = urand(0, lo_prepared_locs.size() - 1);
|
||||
dest = lo_prepared_locs[idx];
|
||||
}
|
||||
LOG_DEBUG("playerbots", "[New Rpg] Bot {} select random grind pos Map:{} X:{} Y:{} Z:{} ({}+{} available in {})",
|
||||
bot->GetName(), dest.GetMapId(), dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(),
|
||||
hi_prepared_locs.size(), lo_prepared_locs.size() - hi_prepared_locs.size(), locs.size());
|
||||
return dest;
|
||||
}
|
||||
|
||||
WorldPosition NewRpgStatusUpdateAction::SelectRandomInnKeeperPos()
|
||||
{
|
||||
const std::vector<WorldLocation>& locs = IsAlliance(bot->getRace())
|
||||
? sRandomPlayerbotMgr->allianceStarterPerLevelCache[bot->GetLevel()]
|
||||
: sRandomPlayerbotMgr->hordeStarterPerLevelCache[bot->GetLevel()];
|
||||
std::vector<WorldLocation> prepared_locs;
|
||||
for (auto& loc : locs)
|
||||
{
|
||||
if (bot->GetMapId() != loc.GetMapId())
|
||||
continue;
|
||||
|
||||
float range = bot->GetLevel() <= 5 ? 500.0f : 2500.0f;
|
||||
if (bot->GetExactDist(loc) < range)
|
||||
{
|
||||
prepared_locs.push_back(loc);
|
||||
}
|
||||
}
|
||||
WorldPosition dest;
|
||||
if (!prepared_locs.empty())
|
||||
{
|
||||
uint32 idx = urand(0, prepared_locs.size() - 1);
|
||||
dest = prepared_locs[idx];
|
||||
}
|
||||
LOG_DEBUG("playerbots", "[New Rpg] Bot {} select random inn keeper pos Map:{} X:{} Y:{} Z:{} ({} available in {})",
|
||||
bot->GetName(), dest.GetMapId(), dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(),
|
||||
prepared_locs.size(), locs.size());
|
||||
return dest;
|
||||
}
|
||||
|
||||
bool NewRpgGoFarAwayPosAction::MoveFarTo(WorldPosition dest)
|
||||
{
|
||||
float dis = bot->GetExactDist(dest);
|
||||
if (dis < pathFinderDis)
|
||||
{
|
||||
return MoveTo(dest.getMapId(), dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), false, false,
|
||||
false, true);
|
||||
}
|
||||
|
||||
// performance optimization
|
||||
if (IsWaitingForLastMove(MovementPriority::MOVEMENT_NORMAL))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float minDelta = M_PI;
|
||||
const float x = bot->GetPositionX();
|
||||
const float y = bot->GetPositionY();
|
||||
const float z = bot->GetPositionZ();
|
||||
float rx, ry, rz;
|
||||
bool found = false;
|
||||
int attempt = 10;
|
||||
while (--attempt)
|
||||
{
|
||||
float angle = bot->GetAngle(&dest);
|
||||
float delta = (rand_norm() - 0.5) * M_PI * 2;
|
||||
angle += delta;
|
||||
float dis = rand_norm() * pathFinderDis;
|
||||
float dx = x + cos(angle) * dis;
|
||||
float dy = y + sin(angle) * dis;
|
||||
float dz = z + 5.0f;
|
||||
bot->UpdateAllowedPositionZ(dx, dy, dz);
|
||||
PathGenerator path(bot);
|
||||
path.CalculatePath(dx, dy, dz);
|
||||
PathType type = path.GetPathType();
|
||||
|
||||
bool canReach = type == PATHFIND_INCOMPLETE || type == PATHFIND_NORMAL;
|
||||
|
||||
if (canReach && fabs(delta) <= minDelta)
|
||||
{
|
||||
found = true;
|
||||
const G3D::Vector3& endPos = path.GetActualEndPosition();
|
||||
rx = endPos.x;
|
||||
ry = endPos.y;
|
||||
rz = endPos.z;
|
||||
minDelta = fabs(delta);
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), rx, ry, rz, false, false, false, true);
|
||||
}
|
||||
// don't fallback to direct move
|
||||
// float angle = bot->GetAngle(&dest);
|
||||
// return MoveTo(bot->GetMapId(), x + cos(angle) * pathFinderDis, y + sin(angle) * pathFinderDis, z);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NewRpgGoGrindAction::Execute(Event event) { return MoveFarTo(botAI->rpgInfo.grindPos); }
|
||||
|
||||
bool NewRpgGoInnKeeperAction::Execute(Event event) { return MoveFarTo(botAI->rpgInfo.innKeeperPos); }
|
||||
|
||||
bool NewRpgMoveRandomAction::Execute(Event event)
|
||||
{
|
||||
float distance = rand_norm() * moveStep;
|
||||
Map* map = bot->GetMap();
|
||||
const float x = bot->GetPositionX();
|
||||
const float y = bot->GetPositionY();
|
||||
const float z = bot->GetPositionZ();
|
||||
int attempts = 5;
|
||||
while (--attempts)
|
||||
{
|
||||
float angle = (float)rand_norm() * 2 * static_cast<float>(M_PI);
|
||||
float dx = x + distance * cos(angle);
|
||||
float dy = y + distance * sin(angle);
|
||||
float dz = z;
|
||||
if (!map->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(),
|
||||
dx, dy, dz))
|
||||
continue;
|
||||
|
||||
if (map->IsInWater(bot->GetPhaseMask(), dx, dy, dz, bot->GetCollisionHeight()))
|
||||
continue;
|
||||
|
||||
bool moved = MoveTo(bot->GetMapId(), dx, dy, dz, false, false, false, true);
|
||||
if (moved)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NewRpgMoveNpcAction::Execute(Event event)
|
||||
{
|
||||
NewRpgInfo& info = botAI->rpgInfo;
|
||||
if (!info.npcPos)
|
||||
{
|
||||
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets");
|
||||
if (possibleTargets.empty())
|
||||
return false;
|
||||
int idx = urand(0, possibleTargets.size() - 1);
|
||||
ObjectGuid guid = possibleTargets[idx];
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (unit)
|
||||
{
|
||||
info.npcPos = GuidPosition(unit);
|
||||
info.lastReachNpc = 0;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->GetDistance(info.npcPos) <= INTERACTION_DISTANCE)
|
||||
{
|
||||
if (!info.lastReachNpc)
|
||||
{
|
||||
info.lastReachNpc = getMSTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (info.lastReachNpc && info.lastReachNpc + stayTime > getMSTime())
|
||||
return false;
|
||||
|
||||
info.npcPos = GuidPosition();
|
||||
info.lastReachNpc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(info.npcPos);
|
||||
Unit* unit = botAI->GetUnit(info.npcPos);
|
||||
if (!unit)
|
||||
return false;
|
||||
float x = unit->GetPositionX();
|
||||
float y = unit->GetPositionY();
|
||||
float z = unit->GetPositionZ();
|
||||
float mapId = unit->GetMapId();
|
||||
float angle = 0.f;
|
||||
if (bot->IsWithinLOS(x, y, z))
|
||||
{
|
||||
if (!unit->isMoving())
|
||||
angle = unit->GetAngle(bot) + (M_PI * irand(-25, 25) / 100.0); // Closest 45 degrees towards the target
|
||||
else
|
||||
angle = unit->GetOrientation() +
|
||||
(M_PI * irand(-25, 25) / 100.0); // 45 degrees infront of target (leading it's movement)
|
||||
}
|
||||
else
|
||||
angle = 2 * M_PI * rand_norm(); // A circle around the target.
|
||||
float rnd = rand_norm();
|
||||
x += cos(angle) * INTERACTION_DISTANCE * rnd;
|
||||
y += sin(angle) * INTERACTION_DISTANCE * rnd;
|
||||
// bool exact = true;
|
||||
if (!unit->GetMap()->CheckCollisionAndGetValidCoords(unit, unit->GetPositionX(), unit->GetPositionY(),
|
||||
unit->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = unit->GetPositionX();
|
||||
y = unit->GetPositionY();
|
||||
z = unit->GetPositionZ();
|
||||
// exact = false;
|
||||
}
|
||||
return MoveTo(mapId, x, y, z, false, false, false, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
#ifndef _PLAYERBOT_NEWRPGACTION_H
|
||||
#define _PLAYERBOT_NEWRPGACTION_H
|
||||
|
||||
#include "Duration.h"
|
||||
#include "MovementActions.h"
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "TravelMgr.h"
|
||||
#include "PlayerbotAI.h"
|
||||
|
||||
class TellRpgStatusAction : public Action
|
||||
{
|
||||
public:
|
||||
TellRpgStatusAction(PlayerbotAI* botAI) : Action(botAI, "rpg status") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class NewRpgStatusUpdateAction : public Action
|
||||
{
|
||||
public:
|
||||
NewRpgStatusUpdateAction(PlayerbotAI* botAI) : Action(botAI, "new rpg status update") {}
|
||||
bool Execute(Event event) override;
|
||||
protected:
|
||||
// const int32 setGrindInterval = 5 * 60 * 1000;
|
||||
// const int32 setNpcInterval = 1 * 60 * 1000;
|
||||
const int32 statusNearNpcDuration = 2 * 60 * 1000;
|
||||
const int32 statusNearRandomDuration = 2 * 60 * 1000;
|
||||
const int32 statusRestDuration = 30 * 1000;
|
||||
WorldPosition SelectRandomGrindPos();
|
||||
WorldPosition SelectRandomInnKeeperPos();
|
||||
};
|
||||
|
||||
class NewRpgGoFarAwayPosAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
NewRpgGoFarAwayPosAction(PlayerbotAI* botAI, std::string name) : MovementAction(botAI, name) {}
|
||||
// bool Execute(Event event) override;
|
||||
bool MoveFarTo(WorldPosition dest);
|
||||
|
||||
protected:
|
||||
// WorldPosition dest;
|
||||
float pathFinderDis = 70.0f; // path finder
|
||||
};
|
||||
|
||||
class NewRpgGoGrindAction : public NewRpgGoFarAwayPosAction
|
||||
{
|
||||
public:
|
||||
NewRpgGoGrindAction(PlayerbotAI* botAI) : NewRpgGoFarAwayPosAction(botAI, "new rpg go grind") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class NewRpgGoInnKeeperAction : public NewRpgGoFarAwayPosAction
|
||||
{
|
||||
public:
|
||||
NewRpgGoInnKeeperAction(PlayerbotAI* botAI) : NewRpgGoFarAwayPosAction(botAI, "new rpg go innkeeper") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
|
||||
class NewRpgMoveRandomAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
NewRpgMoveRandomAction(PlayerbotAI* botAI) : MovementAction(botAI, "new rpg move random") {}
|
||||
bool Execute(Event event) override;
|
||||
protected:
|
||||
const float moveStep = 50.0f;
|
||||
};
|
||||
|
||||
class NewRpgMoveNpcAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
NewRpgMoveNpcAction(PlayerbotAI* botAI) : MovementAction(botAI, "new rpg move npcs") {}
|
||||
bool Execute(Event event) override;
|
||||
protected:
|
||||
const uint32 stayTime = 8 * 1000;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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 "NewRpgStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
NewRpgStrategy::NewRpgStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
NextAction** NewRpgStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("new rpg status update", 5.0f), nullptr);
|
||||
}
|
||||
|
||||
void NewRpgStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("go grind status", NextAction::array(0, new NextAction("new rpg go grind", 1.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("go innkeeper status", NextAction::array(0, new NextAction("new rpg go innkeeper", 1.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("near random status", NextAction::array(0, new NextAction("new rpg move random", 1.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("near npc status", NextAction::array(0, new NextAction("new rpg move npc", 1.0f), nullptr)));
|
||||
}
|
||||
|
||||
void NewRpgStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
// multipliers.push_back(new RpgActionMultiplier(botAI));
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_NEWRPGSTRATEGY_H
|
||||
#define _PLAYERBOT_NEWRPGSTRATEGY_H
|
||||
|
||||
#include <cstdint>
|
||||
#include "Strategy.h"
|
||||
#include "TravelMgr.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
enum class NewRpgStatus
|
||||
{
|
||||
// Going to far away place
|
||||
GO_GRIND,
|
||||
GO_INNKEEPER,
|
||||
// Exploring nearby
|
||||
NEAR_RANDOM,
|
||||
NEAR_NPC,
|
||||
// Taking a break
|
||||
REST,
|
||||
// Initial status
|
||||
IDLE
|
||||
};
|
||||
|
||||
struct NewRpgInfo
|
||||
{
|
||||
NewRpgStatus status{NewRpgStatus::IDLE};
|
||||
// NewRpgStatus::GO_GRIND
|
||||
WorldPosition grindPos{};
|
||||
uint32 lastGoGrind{0};
|
||||
// NewRpgStatus::GO_INNKEEPER
|
||||
WorldPosition innKeeperPos{};
|
||||
uint32 lastGoInnKeeper{0};
|
||||
// NewRpgStatus::NEAR_NPC
|
||||
GuidPosition npcPos{};
|
||||
uint32 lastNearNpc{0};
|
||||
uint32 lastReachNpc{0};
|
||||
// NewRpgStatus::NEAR_RANDOM
|
||||
uint32 lastNearRandom{0};
|
||||
// NewRpgStatus::REST
|
||||
uint32 lastRest{0};
|
||||
|
||||
std::string ToString()
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "Status: ";
|
||||
switch (status)
|
||||
{
|
||||
case NewRpgStatus::GO_GRIND:
|
||||
out << "GO_GRIND";
|
||||
out << "\nGrindPos: " << grindPos.GetMapId() << " " << grindPos.GetPositionX() << " " << grindPos.GetPositionY() << " " << grindPos.GetPositionZ();
|
||||
out << "\nlastGoGrind: " << lastGoGrind;
|
||||
break;
|
||||
case NewRpgStatus::GO_INNKEEPER:
|
||||
out << "GO_INNKEEPER";
|
||||
out << "\nInnKeeperPos: " << innKeeperPos.GetMapId() << " " << innKeeperPos.GetPositionX() << " " << innKeeperPos.GetPositionY() << " " << innKeeperPos.GetPositionZ();
|
||||
out << "\nlastGoInnKeeper: " << lastGoInnKeeper;
|
||||
break;
|
||||
case NewRpgStatus::NEAR_NPC:
|
||||
out << "NEAR_NPC";
|
||||
out << "\nNpcPos: " << npcPos.GetMapId() << " " << npcPos.GetPositionX() << " " << npcPos.GetPositionY() << " " << npcPos.GetPositionZ();
|
||||
out << "\nlastNearNpc: " << lastNearNpc;
|
||||
out << "\nlastReachNpc: " << lastReachNpc;
|
||||
break;
|
||||
case NewRpgStatus::NEAR_RANDOM:
|
||||
out << "NEAR_RANDOM";
|
||||
out << "\nlastNearRandom: " << lastNearRandom;
|
||||
break;
|
||||
case NewRpgStatus::IDLE:
|
||||
out << "IDLE";
|
||||
break;
|
||||
case NewRpgStatus::REST:
|
||||
out << "REST";
|
||||
out << "\nlastRest: " << lastRest;
|
||||
break;
|
||||
default:
|
||||
out << "UNKNOWN";
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
};
|
||||
|
||||
class NewRpgStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
NewRpgStrategy(PlayerbotAI* botAI);
|
||||
|
||||
std::string const getName() override { return "new rpg"; }
|
||||
NextAction** getDefaultActions() override;
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,4 +0,0 @@
|
||||
#include "NewRpgTriggers.h"
|
||||
#include "PlayerbotAI.h"
|
||||
|
||||
bool NewRpgStatusTrigger::IsActive() { return status == botAI->rpgInfo.status; }
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef _PLAYERBOT_NEWRPGTRIGGERS_H
|
||||
#define _PLAYERBOT_NEWRPGTRIGGERS_H
|
||||
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "Trigger.h"
|
||||
|
||||
class NewRpgStatusTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NewRpgStatusTrigger(PlayerbotAI* botAI, NewRpgStatus status = NewRpgStatus::IDLE)
|
||||
: Trigger(botAI, "new rpg status"), status(status)
|
||||
{
|
||||
}
|
||||
bool IsActive() override;
|
||||
|
||||
protected:
|
||||
NewRpgStatus status;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -50,7 +50,7 @@ void HealShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
NextAction::array(0, new NextAction("earthliving weapon", 22.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"group heal setting",
|
||||
NextAction::array(0, new NextAction("riptide on party", 27.0f), new NextAction("chain heal on party", 26.0f), NULL)));
|
||||
NextAction::array(0, new NextAction("riptide on party", 23.0f), new NextAction("chain heal on party", 22.0f), NULL)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"party member critical health",
|
||||
|
||||
@@ -77,7 +77,7 @@ void MeleeShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(new TriggerNode(
|
||||
"medium aoe", NextAction::array(0, new NextAction("strength of earth totem", ACTION_LIGHT_HEAL), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_HIGH + 1), nullptr)));
|
||||
"enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"no fire totem",
|
||||
|
||||
@@ -24,7 +24,6 @@ public:
|
||||
creators["reputation"] = &ChatTriggerContext::reputation;
|
||||
creators["log"] = &ChatTriggerContext::log;
|
||||
creators["los"] = &ChatTriggerContext::los;
|
||||
creators["rpg status"] = &ChatTriggerContext::rpg_status;
|
||||
creators["aura"] = &ChatTriggerContext::aura;
|
||||
creators["drop"] = &ChatTriggerContext::drop;
|
||||
creators["share"] = &ChatTriggerContext::share;
|
||||
@@ -212,7 +211,6 @@ private:
|
||||
static Trigger* reputation(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "reputation"); }
|
||||
static Trigger* log(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "log"); }
|
||||
static Trigger* los(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "los"); }
|
||||
static Trigger* rpg_status(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "rpg status"); }
|
||||
static Trigger* aura(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "aura"); }
|
||||
static Trigger* loot_all(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "add all loot"); }
|
||||
static Trigger* release(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "release"); }
|
||||
|
||||
@@ -25,8 +25,4 @@ bool PartyMemberNeedCureTrigger::IsActive()
|
||||
return target && target->IsInWorld();
|
||||
}
|
||||
|
||||
bool NeedWorldBuffTrigger::IsActive()
|
||||
{
|
||||
std::any_of(WorldBuffAction::NeedWorldBuffs(bot).begin(), WorldBuffAction::NeedWorldBuffs(bot).end(),
|
||||
[](const auto& wb) { return true; });
|
||||
}
|
||||
bool NeedWorldBuffTrigger::IsActive() { return !WorldBuffAction::NeedWorldBuffs(bot).empty(); }
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#include "LfgTriggers.h"
|
||||
#include "LootTriggers.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "NewRpgTriggers.h"
|
||||
#include "PvpTriggers.h"
|
||||
#include "RaidNaxxTriggers.h"
|
||||
#include "RpgTriggers.h"
|
||||
@@ -215,10 +213,6 @@ public:
|
||||
creators["rpg craft"] = &TriggerContext::rpg_craft;
|
||||
creators["rpg trade useful"] = &TriggerContext::rpg_trade_useful;
|
||||
creators["rpg duel"] = &TriggerContext::rpg_duel;
|
||||
creators["go grind status"] = &TriggerContext::go_grind_status;
|
||||
creators["go innkeeper status"] = &TriggerContext::go_innkeeper_status;
|
||||
creators["near random status"] = &TriggerContext::near_random_status;
|
||||
creators["near npc status"] = &TriggerContext::near_npc_status;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -408,10 +402,6 @@ private:
|
||||
static Trigger* rpg_craft(PlayerbotAI* botAI) { return new RpgCraftTrigger(botAI); }
|
||||
static Trigger* rpg_trade_useful(PlayerbotAI* botAI) { return new RpgTradeUsefulTrigger(botAI); }
|
||||
static Trigger* rpg_duel(PlayerbotAI* botAI) { return new RpgDuelTrigger(botAI); }
|
||||
static Trigger* go_grind_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, NewRpgStatus::GO_GRIND); }
|
||||
static Trigger* go_innkeeper_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, NewRpgStatus::GO_INNKEEPER); }
|
||||
static Trigger* near_random_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, NewRpgStatus::NEAR_RANDOM); }
|
||||
static Trigger* near_npc_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, NewRpgStatus::NEAR_NPC); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -175,7 +175,7 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range)
|
||||
// !((attacker->IsPolymorphed() || botAI->HasAura("sap", attacker) || /*attacker->IsCharmed() ||*/
|
||||
// attacker->isFeared()) && !rti) &&
|
||||
/*!sServerFacade->IsInRoots(attacker) &&*/
|
||||
!attacker->IsFriendlyTo(bot) && !attacker->HasSpiritOfRedemptionAura() &&
|
||||
!attacker->IsFriendlyTo(bot) && !attacker->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) &&
|
||||
// !(attacker->GetGUID().IsPet() && enemy) &&
|
||||
!(attacker->GetCreatureType() == CREATURE_TYPE_CRITTER && !attacker->IsInCombat()) &&
|
||||
!attacker->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) && !attacker->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE) &&
|
||||
|
||||
@@ -298,9 +298,8 @@ Unit* DpsTargetValue::Calculate()
|
||||
return rti;
|
||||
|
||||
// FindLeastHpTargetStrategy strategy(botAI);
|
||||
Group* group = bot->GetGroup();
|
||||
float dps = AI_VALUE(float, "estimated group dps");
|
||||
if (group && botAI->IsCaster(bot))
|
||||
if (botAI->IsCaster(bot))
|
||||
{
|
||||
CasterFindTargetSmartStrategy strategy(botAI, dps);
|
||||
return TargetValue::FindTarget(&strategy);
|
||||
|
||||
@@ -18,7 +18,7 @@ bool NearestEnemyPlayersValue::AcceptUnit(Unit* unit)
|
||||
!enemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NON_ATTACKABLE_2) &&
|
||||
((inCannon || !enemy->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE))) &&
|
||||
/*!enemy->HasStealthAura() && !enemy->HasInvisibilityAura()*/ enemy->CanSeeOrDetect(bot) &&
|
||||
!(enemy->HasSpiritOfRedemptionAura()))
|
||||
!(enemy->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -52,7 +52,7 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
||||
|
||||
float distance = 0;
|
||||
Unit* result = nullptr;
|
||||
// std::unordered_map<uint32, bool> needForQuestMap;
|
||||
std::unordered_map<uint32, bool> needForQuestMap;
|
||||
|
||||
for (ObjectGuid const guid : targets)
|
||||
{
|
||||
@@ -99,18 +99,18 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
||||
if (!bot->InBattleground() && (int)unit->GetLevel() - (int)bot->GetLevel() > 4 && !unit->GetGUID().IsPlayer())
|
||||
continue;
|
||||
|
||||
// if (needForQuestMap.find(unit->GetEntry()) == needForQuestMap.end())
|
||||
// needForQuestMap[unit->GetEntry()] = needForQuest(unit);
|
||||
if (needForQuestMap.find(unit->GetEntry()) == needForQuestMap.end())
|
||||
needForQuestMap[unit->GetEntry()] = needForQuest(unit);
|
||||
|
||||
// if (!needForQuestMap[unit->GetEntry()])
|
||||
// {
|
||||
// Creature* creature = dynamic_cast<Creature*>(unit);
|
||||
// if ((urand(0, 100) < 60 || (context->GetValue<TravelTarget*>("travel target")->Get()->isWorking() &&
|
||||
// context->GetValue<TravelTarget*>("travel target")->Get()->getDestination()->getName() != "GrindTravelDestination")))
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
if (!needForQuestMap[unit->GetEntry()])
|
||||
{
|
||||
Creature* creature = dynamic_cast<Creature*>(unit);
|
||||
if ((urand(0, 100) < 60 || (context->GetValue<TravelTarget*>("travel target")->Get()->isWorking() &&
|
||||
context->GetValue<TravelTarget*>("travel target")->Get()->getDestination()->getName() != "GrindTravelDestination")))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (Creature* creature = unit->ToCreature())
|
||||
if (CreatureTemplate const* CreatureTemplate = creature->GetCreatureTemplate())
|
||||
@@ -142,7 +142,8 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
||||
else
|
||||
{
|
||||
float newdistance = bot->GetDistance(unit);
|
||||
if (!result || (newdistance < distance))
|
||||
if (!result || (newdistance < distance &&
|
||||
urand(0, abs(distance - newdistance)) > sPlayerbotAIConfig->sightDistance * 0.1))
|
||||
{
|
||||
distance = newdistance;
|
||||
result = unit;
|
||||
|
||||
@@ -21,7 +21,7 @@ bool InvalidTargetValue::Calculate()
|
||||
return target->GetMapId() != bot->GetMapId() || target->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE) ||
|
||||
target->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) || target->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE_2) ||
|
||||
!target->IsVisible() || !target->IsAlive() || target->IsPolymorphed() || target->IsCharmed() ||
|
||||
target->HasFearAura() || target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsFriendlyTo(bot) ||
|
||||
target->isFeared() || target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsFriendlyTo(bot) ||
|
||||
!AttackersValue::IsValidTarget(target, bot);
|
||||
}
|
||||
|
||||
|
||||
@@ -256,42 +256,20 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto)
|
||||
// Check weapon case separately to keep things a bit cleaner
|
||||
bool have2HWeapon = false;
|
||||
bool isValidTGWeapon = false;
|
||||
|
||||
if (dstSlot == EQUIPMENT_SLOT_MAINHAND)
|
||||
{
|
||||
Item* currentWeapon = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
|
||||
have2HWeapon = currentWeapon && currentWeapon->GetTemplate()->InventoryType == INVTYPE_2HWEAPON;
|
||||
|
||||
// Determine if the new weapon is a valid Titan Grip weapon
|
||||
isValidTGWeapon = (itemProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 ||
|
||||
itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 ||
|
||||
itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2);
|
||||
|
||||
// If the bot can Titan Grip, ignore any 2H weapon that isn't a 2H sword, mace, or axe.
|
||||
if (bot->CanTitanGrip())
|
||||
{
|
||||
// If this weapon is 2H but not one of the valid TG weapon types, do not equip it at all.
|
||||
if (itemProto->InventoryType == INVTYPE_2HWEAPON && !isValidTGWeapon)
|
||||
{
|
||||
return ITEM_USAGE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// Now handle the logic for equipping and possible offhand slots
|
||||
// If the bot can Dual Wield and:
|
||||
// - The weapon is not 2H and we currently don't have a 2H weapon equipped
|
||||
// OR
|
||||
// - The bot can Titan Grip and it is a valid TG weapon
|
||||
// Then we can consider the offhand slot as well.
|
||||
if (bot->CanDualWield() &&
|
||||
((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) ||
|
||||
(bot->CanTitanGrip() && isValidTGWeapon)))
|
||||
isValidTGWeapon = itemProto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2 ||
|
||||
itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MACE2 ||
|
||||
itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2;
|
||||
|
||||
if (bot->CanDualWield() && ((itemProto->InventoryType != INVTYPE_2HWEAPON && !have2HWeapon) || (bot->CanTitanGrip() && isValidTGWeapon)))
|
||||
{
|
||||
possibleSlots = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (uint8 i = 0; i < possibleSlots; i++)
|
||||
{
|
||||
bool shouldEquipInSlot = shouldEquip;
|
||||
|
||||
@@ -14,7 +14,7 @@ class PlayerbotAI;
|
||||
class PossibleRpgTargetsValue : public NearestUnitsValue
|
||||
{
|
||||
public:
|
||||
PossibleRpgTargetsValue(PlayerbotAI* botAI, float range = 70.0f);
|
||||
PossibleRpgTargetsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->rpgDistance);
|
||||
|
||||
static std::vector<uint32> allowedNpcFlags;
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ Unit* RtiTargetValue::Calculate()
|
||||
if (!guid)
|
||||
return nullptr;
|
||||
|
||||
if (!bot->IsInCombat())
|
||||
return nullptr;
|
||||
|
||||
//////////////////////////////////////////////////////begin: delete below check
|
||||
// Some units that need to be killed in battle are not on the list of attackers,
|
||||
// such as the Kor'kron Battle-Mage in Icecrown Citadel.
|
||||
@@ -59,7 +62,7 @@ Unit* RtiTargetValue::Calculate()
|
||||
//////////////////////////////////////////////////////end: delete below check
|
||||
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (!unit || unit->isDead() || !bot->IsWithinLOSInMap(unit) || !AttackersValue::IsValidTarget(unit, bot) ||
|
||||
if (!unit || unit->isDead() || !bot->IsWithinLOSInMap(unit) || !AttackersValue::IsValidTarget(unit, bot) ||
|
||||
sServerFacade->IsDistanceGreaterThan(sServerFacade->GetDistance2d(bot, unit),
|
||||
sPlayerbotAIConfig->sightDistance))
|
||||
return nullptr;
|
||||
|
||||
@@ -48,7 +48,7 @@ private:
|
||||
{
|
||||
return new ActionNode("summon succubus",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ NextAction::array(0, new NextAction("summon voidwalker"), nullptr),
|
||||
/*A*/ NextAction::array(0, new NextAction("summon imp"), nullptr),
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
static ActionNode* summon_felhunter([[maybe_unused]] PlayerbotAI* botAI)
|
||||
|
||||
@@ -23,5 +23,3 @@ bool CastFearOnCcAction::isPossible() { return botAI->CanCastSpell("fear", GetTa
|
||||
bool CastFearOnCcAction::isUseful() { return true; }
|
||||
|
||||
bool CastLifeTapAction::isUseful() { return AI_VALUE2(uint8, "health", "self target") > sPlayerbotAIConfig->lowHealth; }
|
||||
|
||||
Unit* UseSoulstoneAction::GetTarget() { return botAI->GetMaster(); }
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#define _PLAYERBOT_WARLOCKACTIONS_H
|
||||
|
||||
#include "GenericSpellActions.h"
|
||||
#include "UseItemAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
class Unit;
|
||||
@@ -303,12 +302,4 @@ class CastIncinerateAction : public CastSpellAction
|
||||
public:
|
||||
CastIncinerateAction(PlayerbotAI* ai) : CastSpellAction(ai, "incinerate") {}
|
||||
};
|
||||
|
||||
class UseSoulstoneAction : public UseSpellItemAction
|
||||
{
|
||||
public:
|
||||
UseSoulstoneAction(PlayerbotAI* ai) : UseSpellItemAction(ai, "soulstone") {}
|
||||
|
||||
Unit* GetTarget() override;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -184,7 +184,6 @@ public:
|
||||
creators["metamorphosis"] = &WarlockAiObjectContextInternal::metamorphosis;
|
||||
creators["soul fire"] = &WarlockAiObjectContextInternal::soul_fire;
|
||||
creators["incinerate"] = &WarlockAiObjectContextInternal::incinerate;
|
||||
creators["soulstone"] = &WarlockAiObjectContextInternal::soulstone;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -240,7 +239,6 @@ private:
|
||||
static Action* metamorphosis(PlayerbotAI* ai) { return new CastMetamorphosisAction(ai); }
|
||||
static Action* soul_fire(PlayerbotAI* ai) { return new CastSoulFireAction(ai); }
|
||||
static Action* incinerate(PlayerbotAI* ai) { return new CastIncinerateAction(ai); }
|
||||
static Action* soulstone(PlayerbotAI* ai) { return new UseSoulstoneAction(ai); }
|
||||
};
|
||||
|
||||
WarlockAiObjectContext::WarlockAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)
|
||||
|
||||
@@ -16,7 +16,7 @@ void GenericWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
CombatStrategy::InitTriggers(triggers);
|
||||
triggers.push_back(new TriggerNode(
|
||||
"enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_HIGH + 1), nullptr)));
|
||||
"enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), nullptr)));
|
||||
/*triggers.push_back(new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 1),
|
||||
nullptr))); triggers.push_back(new TriggerNode("shield bash", NextAction::array(0, new NextAction("shield bash",
|
||||
ACTION_INTERRUPT + 4), nullptr))); triggers.push_back(new TriggerNode("shield bash on enemy healer",
|
||||
|
||||
Reference in New Issue
Block a user