diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index b4df8f9a..19c31aca 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -127,6 +127,10 @@ AiPlayerbot.SyncQuestForPlayer = 0 # Default: 0 (disabled) AiPlayerbot.SyncLevelWithPlayers = 0 +# Give free food to random bots +# Default: 1 (enabled) +AiPlayerbot.FreeFood = 1 + # Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells) AiPlayerbot.AutoTrainSpells = yes @@ -531,7 +535,7 @@ AiPlayerbot.RandomBotQuestItems = "6948,5175,5176,5177,5178,16309,12382,13704,11 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"" # Spells every random bot will learn on randomize (54197 - cold weather flying) -AiPlayerbot.RandomBotSpellIds = "1"" +AiPlayerbot.RandomBotSpellIds = "54197"" # Level diff between random bots and nearby creatures for random teleports AiPlayerbot.RandomBotTeleLevel = 5 diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 396f1228..cd10d1c2 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -698,7 +698,7 @@ void PlayerbotAI::ChangeEngine(BotState type) void PlayerbotAI::DoNextAction(bool min) { - if (bot->IsBeingTeleported() || (GetMaster() && GetMaster()->IsBeingTeleported())) + if (!bot->IsInWorld() || bot->IsBeingTeleported() || (GetMaster() && GetMaster()->IsBeingTeleported())) { SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); return; @@ -814,6 +814,9 @@ void PlayerbotAI::DoNextAction(bool min) // same BG if (bot->InBattleground() && bot->GetBattleground()->GetBgTypeID() == BATTLEGROUND_AV && !GET_PLAYERBOT_AI(member) && member->InBattleground() && bot->GetMapId() == member->GetMapId()) { + // TODO disable move to objective if have master in bg + continue; + if (!group->SameSubGroup(bot, member)) continue; diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index e289addc..ed8db0f5 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -8,7 +8,7 @@ #include "PlayerbotFactory.h" #include "RandomItemMgr.h" #include "RandomPlayerbotFactory.h" -#include "TalentSpec.h" +#include "Talentspec.h" #include @@ -100,7 +100,7 @@ bool PlayerbotAIConfig::Initialize() randomBotMapsAsString = sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotMaps", "0,1,530,571"); LoadList>(randomBotMapsAsString, randomBotMaps); LoadList>(sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotQuestItems", "6948,5175,5176,5177,5178,16309,12382,13704,11000"), randomBotQuestItems); - LoadList>(sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotSpellIds", "1"), randomBotSpellIds); + LoadList>(sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotSpellIds", "54197"), randomBotSpellIds); LoadList>(sConfigMgr->GetStringDefault("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"), pvpProhibitedZoneIds); LoadList>(sConfigMgr->GetStringDefault("AiPlayerbot.RandomBotQuestIds", "7848,3802,5505,6502,7761"), randomBotQuestIds); @@ -291,6 +291,7 @@ bool PlayerbotAIConfig::Initialize() autoLearnQuestSpells = sConfigMgr->GetBoolDefault("AiPlayerbot.AutoLearnQuestSpells", false); autoDoQuests = sConfigMgr->GetBoolDefault("AiPlayerbot.AutoDoQuests", false); syncLevelWithPlayers = sConfigMgr->GetBoolDefault("AiPlayerbot.SyncLevelWithPlayers", false); + freeFood = sConfigMgr->GetBoolDefault("AiPlayerbot.FreeFood", true); randomBotSayWithoutMaster = sConfigMgr->GetBoolDefault("AiPlayerbot.RandomBotSayWithoutMaster", false); randomBotGroupNearby = sConfigMgr->GetBoolDefault("AiPlayerbot.RandomBotGroupNearby", true); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 81d94973..22000c98 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -146,6 +146,7 @@ class PlayerbotAIConfig bool autoLearnTrainerSpells; bool autoDoQuests; bool syncLevelWithPlayers; + bool freeFood; bool autoLearnQuestSpells; bool randomBotSayWithoutMaster; bool randomBotGroupNearby; diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 017aa214..4ee5fc98 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -396,7 +396,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) } else { - botAI->ResetStrategies(!sRandomPlayerbotMgr->IsRandomBot(bot->GetGUID().GetCounter())); + botAI->ResetStrategies(!sRandomPlayerbotMgr->IsRandomBot(bot)); } if (master && !master->HasUnitState(UNIT_STATE_IN_FLIGHT)) diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 7b574a8b..2a484f47 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -563,7 +563,7 @@ void RandomPlayerbotMgr::CheckBgQueue() if (!bot->InBattlegroundQueue()) continue; - if (!IsRandomBot(bot->GetGUID().GetCounter())) + if (!IsRandomBot(bot)) continue; if (bot->InBattleground() && bot->GetBattleground()->GetStatus() == STATUS_WAIT_LEAVE) @@ -816,7 +816,7 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot) if (botAI) { //botAI->GetAiObjectContext()->GetValue("random bot update")->Set(true); - if (!sRandomPlayerbotMgr->IsRandomBot(player->GetGUID().GetCounter())) + if (!sRandomPlayerbotMgr->IsRandomBot(player)) update = false; if (player->GetGroup() && botAI->GetGroupMaster()) @@ -1382,6 +1382,11 @@ void RandomPlayerbotMgr::Refresh(Player* bot) bool RandomPlayerbotMgr::IsRandomBot(Player* bot) { + if (bot && GET_PLAYERBOT_AI(bot)) + { + if (GET_PLAYERBOT_AI(bot)->IsRealPlayer()) + return false; + } if (bot) return IsRandomBot(bot->GetGUID().GetCounter()) || sPlayerbotAIConfig->IsInRandomAccountList(bot->GetSession()->GetAccountId()); diff --git a/src/strategy/actions/AcceptDuelAction.cpp b/src/strategy/actions/AcceptDuelAction.cpp index 159799c3..a48c9d5d 100644 --- a/src/strategy/actions/AcceptDuelAction.cpp +++ b/src/strategy/actions/AcceptDuelAction.cpp @@ -15,6 +15,14 @@ bool AcceptDuelAction::Execute(Event event) ObjectGuid playerGuid; p >> playerGuid; + // do not auto duel with low hp + if ((!botAI->HasRealPlayerMaster() || (botAI->GetMaster() && botAI->GetMaster()->GetGUID() != playerGuid)) && AI_VALUE2(uint8, "health", "self target") < 90) + { + WorldPacket packet(CMSG_DUEL_CANCELLED, 8); + packet << flagGuid; + bot->GetSession()->HandleDuelCancelledOpcode(packet); + } + WorldPacket packet(CMSG_DUEL_ACCEPTED, 8); packet << flagGuid; bot->GetSession()->HandleDuelAcceptedOpcode(packet); diff --git a/src/strategy/actions/ActionContext.h b/src/strategy/actions/ActionContext.h index e4f42bbb..33fcc436 100644 --- a/src/strategy/actions/ActionContext.h +++ b/src/strategy/actions/ActionContext.h @@ -219,6 +219,7 @@ class ActionContext : public NamedObjectContext creators["rpg craft"] = &ActionContext::rpg_craft; creators["rpg trade useful"] = &ActionContext::rpg_trade_useful; creators["rpg duel"] = &ActionContext::rpg_duel; + creators["rpg mount anim"] = &ActionContext::rpg_mount_anim; } private: @@ -377,6 +378,7 @@ class ActionContext : public NamedObjectContext static Action* rpg_craft(PlayerbotAI* botAI) { return new RpgCraftAction(botAI); } static Action* rpg_trade_useful(PlayerbotAI* botAI) { return new RpgTradeUsefulAction(botAI); } static Action* rpg_duel(PlayerbotAI* botAI) { return new RpgDuelAction(botAI); } + static Action* rpg_mount_anim(PlayerbotAI* botAI) { return new RpgMountAnimAction(botAI); } }; #endif diff --git a/src/strategy/actions/BattleGroundJoinAction.cpp b/src/strategy/actions/BattleGroundJoinAction.cpp index 2840f913..6566b5ac 100644 --- a/src/strategy/actions/BattleGroundJoinAction.cpp +++ b/src/strategy/actions/BattleGroundJoinAction.cpp @@ -692,7 +692,7 @@ bool BGLeaveAction::Execute(Event event) uint16 unk = 0x1F90; uint8 unk2 = 0x0; bool isArena = false; - bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot->GetGUID().GetCounter()); + bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot); ArenaType arenaType = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId)); if (arenaType) @@ -801,7 +801,7 @@ bool BGStatusAction::Execute(Event event) break; } - bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot->GetGUID().GetCounter()); + bool IsRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot); BattlegroundQueueTypeId queueTypeId = bot->GetBattlegroundQueueTypeId(QueueSlot); BattlegroundTypeId _bgTypeId = BattlegroundMgr::BGTemplateId(queueTypeId); if (!queueTypeId) diff --git a/src/strategy/actions/GiveItemAction.cpp b/src/strategy/actions/GiveItemAction.cpp index 6ec661f3..cf3a0717 100644 --- a/src/strategy/actions/GiveItemAction.cpp +++ b/src/strategy/actions/GiveItemAction.cpp @@ -72,7 +72,28 @@ Unit* GiveFoodAction::GetTarget() return AI_VALUE(Unit*, "party member without food"); } +bool GiveFoodAction::isUseful() +{ + if (!GetTarget()) + return false; + + bool isRandomBot = GetTarget()->IsPlayer() && sRandomPlayerbotMgr->IsRandomBot((Player*) GetTarget()); + + return !isRandomBot || (isRandomBot && !sPlayerbotAIConfig->freeFood); +} + Unit* GiveWaterAction::GetTarget() { return AI_VALUE(Unit*, "party member without water"); } + + +bool GiveWaterAction::isUseful() +{ + if (!GetTarget()) + return false; + + bool isRandomBot = GetTarget()->IsPlayer() && sRandomPlayerbotMgr->IsRandomBot((Player*)GetTarget()); + + return !isRandomBot || (isRandomBot && !sPlayerbotAIConfig->freeFood); +} diff --git a/src/strategy/actions/GiveItemAction.h b/src/strategy/actions/GiveItemAction.h index 40456eb6..b4aeeea5 100644 --- a/src/strategy/actions/GiveItemAction.h +++ b/src/strategy/actions/GiveItemAction.h @@ -27,7 +27,8 @@ class GiveFoodAction : public GiveItemAction public: GiveFoodAction(PlayerbotAI* botAI) : GiveItemAction(botAI, "give food", "conjured food") { } - Unit* GetTarget() override; + bool isUseful() override; + Unit* GetTarget() override; }; class GiveWaterAction : public GiveItemAction @@ -35,7 +36,8 @@ class GiveWaterAction : public GiveItemAction public: GiveWaterAction(PlayerbotAI* botAI) : GiveItemAction(botAI, "give water", "conjured water") { } - Unit* GetTarget() override; + bool isUseful() override; + Unit* GetTarget() override; }; #endif diff --git a/src/strategy/actions/NonCombatActions.cpp b/src/strategy/actions/NonCombatActions.cpp index a339f345..7dcc11d4 100644 --- a/src/strategy/actions/NonCombatActions.cpp +++ b/src/strategy/actions/NonCombatActions.cpp @@ -11,6 +11,44 @@ bool DrinkAction::Execute(Event event) if (bot->IsInCombat()) return false; + bool hasMana = AI_VALUE2(bool, "has mana", "self target"); + if (!hasMana) + return false; + + if (sPlayerbotAIConfig->freeFood) + { + if (bot->IsNonMeleeSpellCast(true)) + return false; + + bot->ClearUnitState(UNIT_STATE_CHASE); + bot->ClearUnitState(UNIT_STATE_FOLLOW); + + if (bot->isMoving()) + { + bot->StopMoving(); + botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); + return false; + } + + bot->AddUnitState(UNIT_STAND_STATE_SIT); + botAI->InterruptSpell(); + + //float hp = bot->GetHealthPercent(); + float mp = bot->GetPowerPct(POWER_MANA); + float p = mp; + float delay; + + if (!bot->InBattleground()) + delay = 27000.0f * (100 - p) / 100.0f; + else + delay = 20000.0f * (100 - p) / 100.0f; + + botAI->CastSpell(24707, bot); + botAI->SetNextCheckDelay(delay); + + return true; + } + return UseItemAction::Execute(event); } @@ -19,11 +57,50 @@ bool DrinkAction::isUseful() return UseItemAction::isUseful() && AI_VALUE2(uint8, "mana", "self target") < 85; } +bool DrinkAction::isPossible() +{ + return sPlayerbotAIConfig->freeFood || UseItemAction::isPossible(); +} + bool EatAction::Execute(Event event) { if (bot->IsInCombat()) return false; + if (sPlayerbotAIConfig->freeFood) + { + if (bot->IsNonMeleeSpellCast(true)) + return false; + + bot->ClearUnitState(UNIT_STATE_CHASE); + bot->ClearUnitState(UNIT_STATE_FOLLOW); + + if (bot->isMoving()) + { + bot->StopMoving(); + botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); + return false; + } + + bot->AddUnitState(UNIT_STAND_STATE_SIT); + botAI->InterruptSpell(); + + float hp = bot->GetHealthPct(); + //float mp = bot->HasMana() ? bot->GetPowerPercent() : 0.f; + float p = hp; + float delay; + + if (!bot->InBattleground()) + delay = 27000.0f * (100 - p) / 100.0f; + else + delay = 20000.0f * (100 - p) / 100.0f; + + botAI->CastSpell(24707, bot); + botAI->SetNextCheckDelay(delay); + + return true; + } + return UseItemAction::Execute(event); } @@ -31,3 +108,8 @@ bool EatAction::isUseful() { return UseItemAction::isUseful() && AI_VALUE2(uint8, "health", "self target") < sPlayerbotAIConfig->lowHealth; } + +bool EatAction::isPossible() +{ + return sPlayerbotAIConfig->freeFood || UseItemAction::isPossible(); +} diff --git a/src/strategy/actions/NonCombatActions.h b/src/strategy/actions/NonCombatActions.h index 9ac80c3e..8eb8a0e6 100644 --- a/src/strategy/actions/NonCombatActions.h +++ b/src/strategy/actions/NonCombatActions.h @@ -16,6 +16,7 @@ class DrinkAction : public UseItemAction bool Execute(Event event) override; bool isUseful() override; + bool isPossible() override; }; class EatAction : public UseItemAction @@ -25,6 +26,7 @@ class EatAction : public UseItemAction bool Execute(Event event) override; bool isUseful() override; + bool isPossible() override; }; #endif diff --git a/src/strategy/actions/ReachTargetActions.cpp b/src/strategy/actions/ReachTargetActions.cpp index a261e5a0..014ccd37 100644 --- a/src/strategy/actions/ReachTargetActions.cpp +++ b/src/strategy/actions/ReachTargetActions.cpp @@ -26,7 +26,7 @@ bool ReachTargetAction::Execute(Event event) bool inLos = bot->IsWithinLOSInMap(target); bool isFriend = bot->IsFriendlyTo(target); float chaseDist = inLos ? distance : isFriend ? distance / 2 : distance; - return ChaseTo(target, chaseDist + combatReach, bot->GetAngle(target)); + return ChaseTo(target, chaseDist - sPlayerbotAIConfig->contactDistance, bot->GetAngle(target)); } } diff --git a/src/strategy/actions/RpgSubActions.cpp b/src/strategy/actions/RpgSubActions.cpp index dca6a03d..6e56fd4b 100644 --- a/src/strategy/actions/RpgSubActions.cpp +++ b/src/strategy/actions/RpgSubActions.cpp @@ -470,10 +470,6 @@ bool RpgDuelAction::isUseful() return false; } - // Less spammy duels - if (bot->getLevel() == 1) - return false; - return true; } @@ -488,3 +484,17 @@ bool RpgDuelAction::Execute(Event event) return botAI->DoSpecificAction("cast custom spell", Event("rpg action", chat->FormatWorldobject(player) + " 7266"), true); } + + +bool RpgMountAnimAction::isUseful() +{ + return AI_VALUE2(bool, "mounted", "self target") && !AI_VALUE2(bool, "moving", "self target"); +} + +bool RpgMountAnimAction::Execute(Event event) +{ + WorldPacket p; + bot->GetSession()->HandleMountSpecialAnimOpcode(p); + + return true; +} \ No newline at end of file diff --git a/src/strategy/actions/RpgSubActions.h b/src/strategy/actions/RpgSubActions.h index 13739c92..1ea97c2b 100644 --- a/src/strategy/actions/RpgSubActions.h +++ b/src/strategy/actions/RpgSubActions.h @@ -255,4 +255,13 @@ class RpgDuelAction : public RpgSubAction bool Execute(Event event) override; }; +class RpgMountAnimAction : public RpgSubAction +{ + public: + RpgMountAnimAction(PlayerbotAI* botAI, std::string const name = "rpg mount anim") : RpgSubAction(botAI, name) {} + + bool isUseful() override; + bool Execute(Event event) override; +}; + #endif diff --git a/src/strategy/actions/StayActions.cpp b/src/strategy/actions/StayActions.cpp index d3f570b4..1b810dd4 100644 --- a/src/strategy/actions/StayActions.cpp +++ b/src/strategy/actions/StayActions.cpp @@ -14,7 +14,7 @@ bool StayActionBase::Stay() //if (!urand(0, 10)) //botAI->PlaySound(TEXT_EMOTE_YAWN); - if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE || bot->IsFlying()) + if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) return false; uint32 sitDelay = sPlayerbotAIConfig->sitDelay / 1000; diff --git a/src/strategy/generic/EmoteStrategy.cpp b/src/strategy/generic/EmoteStrategy.cpp index 923cab70..a55a979d 100644 --- a/src/strategy/generic/EmoteStrategy.cpp +++ b/src/strategy/generic/EmoteStrategy.cpp @@ -19,4 +19,5 @@ void EmoteStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("seldom", NextAction::array(0, new NextAction("talk", 1.0f), nullptr))); triggers.push_back(new TriggerNode("receive text emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); triggers.push_back(new TriggerNode("receive emote", NextAction::array(0, new NextAction("emote", 10.0f), nullptr))); + triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("rpg mount anim", 1.0f), nullptr))); } diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index 23244d95..0329caa1 100644 --- a/src/strategy/triggers/GenericTriggers.cpp +++ b/src/strategy/triggers/GenericTriggers.cpp @@ -64,6 +64,9 @@ bool PanicTrigger::IsActive() bool OutNumberedTrigger::IsActive() { + if (bot->GetMap() && (bot->GetMap()->IsDungeon() || bot->GetMap()->IsRaid())) + return false; + int32 botLevel = bot->getLevel(); uint32 friendPower = 200; uint32 foePower = 0; @@ -144,11 +147,19 @@ bool AoeTrigger::IsActive() bool NoFoodTrigger::IsActive() { + bool isRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot); + if (isRandomBot && sPlayerbotAIConfig->freeFood) + return false; + return AI_VALUE2(std::vector, "inventory items", "conjured food").empty(); } bool NoDrinkTrigger::IsActive() { + bool isRandomBot = sRandomPlayerbotMgr->IsRandomBot(bot); + if (isRandomBot && sPlayerbotAIConfig->freeFood) + return false; + return AI_VALUE2(std::vector, "inventory items", "conjured water").empty(); } diff --git a/src/strategy/triggers/RangeTriggers.cpp b/src/strategy/triggers/RangeTriggers.cpp index e6b64fc9..fbed0f4d 100644 --- a/src/strategy/triggers/RangeTriggers.cpp +++ b/src/strategy/triggers/RangeTriggers.cpp @@ -22,7 +22,8 @@ bool EnemyTooCloseForSpellTrigger::IsActive() bool isBoss = false; bool isRaid = false; - float targetDistance = sServerFacade->GetDistance2d(bot, target) + bot->GetCombatReach() + target->GetCombatReach(); + float combatReach = bot->GetCombatReach() + target->GetCombatReach(); + float targetDistance = sServerFacade->GetDistance2d(bot, target) + combatReach; if (target->GetTypeId() == TYPEID_UNIT) { Creature* creature = botAI->GetCreature(target->GetGUID()); @@ -35,10 +36,10 @@ bool EnemyTooCloseForSpellTrigger::IsActive() if (bot->GetMap() && bot->GetMap()->IsRaid()) isRaid = true; - if (isBoss || isRaid) - return sServerFacade->IsDistanceLessThan(targetDistance, botAI->GetRange("spell")); +// if (isBoss || isRaid) +// return sServerFacade->IsDistanceLessThan(targetDistance, (botAI->GetRange("spell") + combatReach) / 2); - return sServerFacade->IsDistanceLessOrEqualThan(targetDistance, (botAI->GetRange("spell") / 2)); + return sServerFacade->IsDistanceLessOrEqualThan(targetDistance, (botAI->GetRange("spell") + combatReach / 2)); } return false; } @@ -53,7 +54,9 @@ bool EnemyTooCloseForShootTrigger::IsActive() return false; bool isBoss = false; - float targetDistance = sServerFacade->GetDistance2d(bot, target) + bot->GetCombatReach() + target->GetCombatReach(); + bool isRaid = false; + float combatReach = bot->GetCombatReach() + target->GetCombatReach(); + float targetDistance = sServerFacade->GetDistance2d(bot, target) + combatReach; if (target->GetTypeId() == TYPEID_UNIT) { Creature* creature = botAI->GetCreature(target->GetGUID()); @@ -63,10 +66,13 @@ bool EnemyTooCloseForShootTrigger::IsActive() } } - if (isBoss) - return sServerFacade->IsDistanceLessThan(targetDistance, botAI->GetRange("shoot")); + if (bot->GetMap() && bot->GetMap()->IsRaid()) + isRaid = true; - return sServerFacade->IsDistanceLessOrEqualThan(targetDistance, (botAI->GetRange("shoot") / 2)); +// if (isBoss || isRaid) +// return sServerFacade->IsDistanceLessThan(targetDistance, botAI->GetRange("shoot") + combatReach); + + return sServerFacade->IsDistanceLessOrEqualThan(targetDistance, (botAI->GetRange("shoot") + combatReach / 2)); } bool EnemyTooCloseForMeleeTrigger::IsActive() @@ -97,7 +103,11 @@ EnemyOutOfSpellRangeTrigger::EnemyOutOfSpellRangeTrigger(PlayerbotAI* botAI) : O bool EnemyOutOfSpellRangeTrigger::IsActive() { Unit* target = AI_VALUE(Unit*, GetTargetName()); - return target && (sServerFacade->GetDistance2d(bot, target) > distance || !bot->IsWithinLOSInMap(target)); + if (!target) + return false; + + float combatReach = bot->GetCombatReach() + target->GetCombatReach(); + return target && (sServerFacade->GetDistance2d(bot, target) > (distance + combatReach + sPlayerbotAIConfig->contactDistance) || !bot->IsWithinLOSInMap(target)); } bool EnemyOutOfMeleeTrigger::IsActive() @@ -117,7 +127,7 @@ bool PartyMemberToHealOutOfSpellRangeTrigger::IsActive() return false; float combatReach = bot->GetCombatReach() + target->GetCombatReach(); - return target && (sServerFacade->GetDistance2d(bot, target) > (distance + combatReach) || !bot->IsWithinLOSInMap(target)); + return target && (sServerFacade->GetDistance2d(bot, target) > (distance + sPlayerbotAIConfig->contactDistance) || !bot->IsWithinLOSInMap(target)); } PartyMemberToHealOutOfSpellRangeTrigger::PartyMemberToHealOutOfSpellRangeTrigger(PlayerbotAI* botAI) : diff --git a/src/strategy/triggers/RpgTriggers.cpp b/src/strategy/triggers/RpgTriggers.cpp index a3aa033d..4c2b09e9 100644 --- a/src/strategy/triggers/RpgTriggers.cpp +++ b/src/strategy/triggers/RpgTriggers.cpp @@ -291,6 +291,10 @@ bool RpgHomeBindTrigger::IsActive() bool RpgQueueBGTrigger::IsActive() { + // skip bots not in continents + if (!WorldPosition(bot).isOverworld()) // bg, raid, dungeon + return false; + GuidPosition guidP(getGuidP()); if (!guidP.IsCreature()) @@ -420,6 +424,22 @@ bool RpgDuelTrigger::IsActive() if (!botAI->HasStrategy("start duel", BOT_STATE_NON_COMBAT)) return false; + // Less spammy duels + if (bot->getLevel() < 3) + return false; + + if (botAI->HasRealPlayerMaster()) + { + // do not auto duel if master is not afk + if (botAI->GetMaster() && !botAI->GetMaster()->isAFK()) + return false; + } + + // do not auto duel with low hp + if (AI_VALUE2(uint8, "health", "self target") < 90) + return false; + + GuidPosition guidP(getGuidP()); if (!guidP.IsPlayer()) @@ -433,7 +453,7 @@ bool RpgDuelTrigger::IsActive() if (player->getLevel() > bot->getLevel() + 3) return false; - if (bot->getLevel() > player->getLevel() + 20) + if (bot->getLevel() > player->getLevel() + 10) return false; // caster or target already have requested duel diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index b11c074f..5d788e8d 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -39,7 +39,7 @@ void AttackersValue::AddAttackersOf(Group* group, std::set& targets) for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) { Player *member = ObjectAccessor::FindPlayer(itr->guid); - if (!member || !member->IsAlive() || member == bot || member->GetMapId() != bot->GetMapId()) + if (!member || !member->IsAlive() || member == bot || member->GetMapId() != bot->GetMapId() || sServerFacade->GetDistance2d(bot, member) > sPlayerbotAIConfig->sightDistance) continue; AddAttackersOf(member, targets); diff --git a/src/strategy/warrior/FuryWarriorStrategy.cpp b/src/strategy/warrior/FuryWarriorStrategy.cpp index 29ef29c3..31c488e8 100644 --- a/src/strategy/warrior/FuryWarriorStrategy.cpp +++ b/src/strategy/warrior/FuryWarriorStrategy.cpp @@ -57,6 +57,6 @@ void FuryWarriorStrategy::InitTriggers(std::vector &triggers) triggers.push_back(new TriggerNode("berserker rage", NextAction::array(0, new NextAction("berserker rage", ACTION_HIGH + 2), nullptr))); triggers.push_back(new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 2), nullptr))); triggers.push_back(new TriggerNode("death wish", NextAction::array(0, new NextAction("death wish", ACTION_HIGH + 2), nullptr))); - triggers.push_back(new TriggerNode("rampage", NextAction::array(0, new NextAction("rampage", ACTION_INTERRUPT), nullptr))); + triggers.push_back(new TriggerNode("rampage", NextAction::array(0, new NextAction("rampage", ACTION_INTERRUPT + 1), nullptr))); triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("intimidating shout", ACTION_EMERGENCY), nullptr))); } diff --git a/src/strategy/warrior/WarriorActions.h b/src/strategy/warrior/WarriorActions.h index a933b8a3..c6d2972b 100644 --- a/src/strategy/warrior/WarriorActions.h +++ b/src/strategy/warrior/WarriorActions.h @@ -69,7 +69,7 @@ BUFF_ACTION(CastDeathWishAction, "death wish"); MELEE_ACTION(CastBloodthirstAction, "bloodthirst"); DEBUFF_ACTION_R(CastPiercingHowlAction, "piercing howl", 8.0f); // fury talents 2.4.3 -SPELL_ACTION(CastRampageAction, "rampage"); +BUFF_ACTION(CastRampageAction, "rampage"); // protection MELEE_ACTION_U(CastTauntAction, "taunt", GetTarget() && GetTarget()->GetTarget() != bot->GetGUID()); diff --git a/src/strategy/warrior/WarriorTriggers.h b/src/strategy/warrior/WarriorTriggers.h index 2c6d3195..12afa7fd 100644 --- a/src/strategy/warrior/WarriorTriggers.h +++ b/src/strategy/warrior/WarriorTriggers.h @@ -21,7 +21,7 @@ DEBUFF_TRIGGER(MortalStrikeDebuffTrigger, "mortal strike"); DEBUFF_ENEMY_TRIGGER(RendDebuffOnAttackerTrigger, "rend"); CAN_CAST_TRIGGER(RevengeAvailableTrigger, "revenge"); CAN_CAST_TRIGGER(OverpowerAvailableTrigger, "overpower"); -CAN_CAST_TRIGGER(RampageAvailableTrigger, "rampage"); +BUFF_TRIGGER(RampageAvailableTrigger, "rampage"); BUFF_TRIGGER_A(BloodrageBuffTrigger, "bloodrage"); CAN_CAST_TRIGGER(VictoryRushTrigger, "victory rush"); HAS_AURA_TRIGGER(SwordAndBoardTrigger, "sword and board");