From 0fd894176b9429919be7b0c18af33efe4d1ae959 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 30 Nov 2024 23:48:29 +0800 Subject: [PATCH] [New Rpg] New rpg start up (add GO_GRIND and NEAR_RANDOM status) --- conf/playerbots.conf.dist | 5 + src/AiFactory.cpp | 6 +- src/PlayerbotAI.cpp | 22 +- src/PlayerbotAI.h | 4 +- src/PlayerbotAIConfig.cpp | 3 +- src/PlayerbotAIConfig.h | 1 + src/RandomPlayerbotMgr.cpp | 125 ++++++++-- src/RandomPlayerbotMgr.h | 7 +- src/strategy/StrategyContext.h | 3 + src/strategy/actions/ActionContext.h | 9 + src/strategy/actions/ChatActionContext.h | 3 + src/strategy/actions/MovementActions.cpp | 41 +++- src/strategy/actions/MovementActions.h | 2 +- src/strategy/actions/NewRpgAction.cpp | 214 ++++++++++++++++++ src/strategy/actions/NewRpgAction.h | 57 +++++ .../actions/ReviveFromCorpseAction.cpp | 16 +- .../generic/ChatCommandHandlerStrategy.cpp | 1 + src/strategy/generic/GrindingStrategy.cpp | 6 +- src/strategy/generic/NewRpgStrategy.cpp | 29 +++ src/strategy/generic/NewRpgStrategy.h | 72 ++++++ src/strategy/triggers/ChatTriggerContext.h | 2 + src/strategy/triggers/NewRpgTrigger.cpp | 4 + src/strategy/triggers/NewRpgTriggers.h | 20 ++ src/strategy/triggers/TriggerContext.h | 6 + src/strategy/values/DpsTargetValue.cpp | 3 +- src/strategy/values/GrindTargetValue.cpp | 27 ++- .../GenericWarlockNonCombatStrategy.cpp | 2 +- 27 files changed, 625 insertions(+), 65 deletions(-) create mode 100644 src/strategy/actions/NewRpgAction.cpp create mode 100644 src/strategy/actions/NewRpgAction.h create mode 100644 src/strategy/generic/NewRpgStrategy.cpp create mode 100644 src/strategy/generic/NewRpgStrategy.h create mode 100644 src/strategy/triggers/NewRpgTrigger.cpp create mode 100644 src/strategy/triggers/NewRpgTriggers.h diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 537588fa..00fa3a4c 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -588,6 +588,11 @@ 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" diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index d3cd1ef3..8af2e0dd 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -631,7 +631,11 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const // nonCombatEngine->addStrategy("group"); // nonCombatEngine->addStrategy("guild"); - if (sPlayerbotAIConfig->autoDoQuests) + if (sPlayerbotAIConfig->enableNewRpgStrategy) + { + nonCombatEngine->addStrategy("new rpg", false); + } + else if (sPlayerbotAIConfig->autoDoQuests) { // nonCombatEngine->addStrategy("travel"); nonCombatEngine->addStrategy("rpg", false); diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 44e234d5..bbb4ce06 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -29,6 +29,7 @@ #include "MotionMaster.h" #include "MoveSpline.h" #include "MoveSplineInit.h" +#include "NewRpgStrategy.h" #include "ObjectGuid.h" #include "PerformanceMonitor.h" #include "Player.h" @@ -774,7 +775,8 @@ void PlayerbotAI::Reset(bool full) bot->GetMotionMaster()->Clear(); // bot->CleanupAfterTaxiFlight(); InterruptSpell(); - + rpgInfo = NewRpgInfo(); + if (full) { for (uint8 i = 0; i < BOT_STATE_MAX; i++) @@ -4137,16 +4139,16 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) { // only keep updating till initializing time has completed, // which prevents unneeded expensive GameTime calls. - if (_isBotInitializing) - { - _isBotInitializing = GameTime::GetUptime().count() < sPlayerbotAIConfig->maxRandomBots * 0.12; + // if (_isBotInitializing) + // { + // _isBotInitializing = GameTime::GetUptime().count() < sPlayerbotAIConfig->maxRandomBots * 0.12; - // no activity allowed during bot initialization - if (_isBotInitializing) - { - return false; - } - } + // // no activity allowed during bot initialization + // if (_isBotInitializing) + // { + // return false; + // } + // } // General exceptions if (activityType == PACKET_ACTIVITY) diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index 5477685e..603dd851 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -21,6 +21,7 @@ #include "PlayerbotTextMgr.h" #include "SpellAuras.h" #include "WorldPacket.h" +#include "NewRpgStrategy.h" class AiObjectContext; class Creature; @@ -572,6 +573,7 @@ public: std::set GetCurrentIncompleteQuestIds(); void PetFollow(); static float GetItemScoreMultiplier(ItemQualities quality); + NewRpgInfo rpgInfo; private: static void _fillGearScoreData(Player* player, Item* item, std::vector* gearScore, uint32& twoHandScore, @@ -580,7 +582,7 @@ private: void HandleCommands(); void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL); - bool _isBotInitializing = true; + bool _isBotInitializing = false; protected: Player* bot; diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 53a7b720..871a3213 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -497,7 +497,8 @@ bool PlayerbotAIConfig::Initialize() autoLearnTrainerSpells = sConfigMgr->GetOption("AiPlayerbot.AutoLearnTrainerSpells", true); autoLearnQuestSpells = sConfigMgr->GetOption("AiPlayerbot.AutoLearnQuestSpells", false); autoTeleportForLevel = sConfigMgr->GetOption("AiPlayerbot.AutoTeleportForLevel", false); - autoDoQuests = sConfigMgr->GetOption("AiPlayerbot.AutoDoQuests", false); + autoDoQuests = sConfigMgr->GetOption("AiPlayerbot.AutoDoQuests", true); + enableNewRpgStrategy = sConfigMgr->GetOption("AiPlayerbot.EnableNewRpgStrategy", false); syncLevelWithPlayers = sConfigMgr->GetOption("AiPlayerbot.SyncLevelWithPlayers", false); freeFood = sConfigMgr->GetOption("AiPlayerbot.FreeFood", true); randomBotGroupNearby = sConfigMgr->GetOption("AiPlayerbot.RandomBotGroupNearby", true); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 0f34b41e..be31da62 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -280,6 +280,7 @@ public: bool autoUpgradeEquip; bool autoLearnTrainerSpells; bool autoDoQuests; + bool enableNewRpgStrategy; bool syncLevelWithPlayers; bool freeFood; bool autoLearnQuestSpells; diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index cbb4e53e..fe475e08 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -18,6 +18,8 @@ #include "BattlegroundMgr.h" #include "CellImpl.h" #include "ChannelMgr.h" +#include "DBCStores.h" +#include "DBCStructure.h" #include "DatabaseEnv.h" #include "Define.h" #include "FleeManager.h" @@ -29,6 +31,7 @@ #include "LFGMgr.h" #include "MapMgr.h" #include "PerformanceMonitor.h" +#include "Player.h" #include "PlayerbotAI.h" #include "PlayerbotAIConfig.h" #include "PlayerbotCommandServer.h" @@ -1355,17 +1358,17 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector& { continue; } - if (bot->GetLevel() <= 18 && (loc.GetMapId() != pInfo->mapId || dis > 10000.0f)) + if (bot->GetLevel() <= 16 && (loc.GetMapId() != pInfo->mapId || dis > 10000.0f)) { continue; } const LocaleConstant& locale = sWorld->GetDefaultDbcLocale(); LOG_INFO("playerbots", - "Random teleporting bot {} (level {}) to Map: {} ({}) Zone: {} ({}) Area: {} ({}) {},{},{} ({}/{} " + "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], x, y, z, i + 1, tlocs.size()); + zone->area_name[locale], area->ID, area->area_name[locale], zone->area_level, area->area_level, x, y, z, i + 1, tlocs.size()); if (hearth) { @@ -1408,8 +1411,7 @@ void RandomPlayerbotMgr::PrepareTeleportCache() "FROM " "(SELECT " "map, " - "MIN( c.guid ) guid, " - "t.entry " + "MIN( c.guid ) guid " "FROM " "creature c " "INNER JOIN creature_template t ON c.id1 = t.entry " @@ -1424,12 +1426,12 @@ void RandomPlayerbotMgr::PrepareTeleportCache() "AND t.faction != 188 " "GROUP BY " "map, " - "ROUND( position_x / 500 ), " - "ROUND( position_y / 500 ), " - "ROUND( position_z / 50), " - "t.entry " + "ROUND(position_x / 50), " + "ROUND(position_y / 50), " + "ROUND(position_z / 50) " "HAVING " - "count(*) > 7) AS g " + "count(*) >= 2) " + "AS g " "INNER JOIN creature c ON g.guid = c.guid " "INNER JOIN creature_template t on c.id1 = t.entry " "ORDER BY " @@ -1461,6 +1463,89 @@ void RandomPlayerbotMgr::PrepareTeleportCache() } LOG_INFO("playerbots", "{} locations for level collected.", collected_locs); + 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 & 65536 " + "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(); + float x = fields[1].Get(); + float y = fields[2].Get(); + float z = fields[3].Get(); + float orient = fields[4].Get(); + uint32 faction = fields[5].Get(); + uint32 c_entry = fields[6].Get(); + const FactionTemplateEntry* entry = sFactionTemplateStore.LookupEntry(faction); + + WorldLocation loc(mapId, x, y, z, 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 level = area->area_level; + LOG_INFO("playerbots", "Area: {} Level: {} creature_entry: {}", area->ID, level, c_entry); + int range = level <= 10 ? 6 : 8; + for (int32 l = (int32)level; l <= (int32)level + range; l++) + { + if (l < 1 || l > maxLevel) + { + continue; + } + if (!(entry->hostileMask & 4)) + { + hordeInnkeeperPerLevelCache[(uint8)l].push_back(loc); + } + if (!(entry->hostileMask & 2)) + { + allianceInnkeeperPerLevelCache[(uint8)l].push_back(loc); + } + } + } 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 <= 6; l++) + { + if ((1 << (i - 1)) & RACEMASK_ALLIANCE) + allianceInnkeeperPerLevelCache[(uint8)l].push_back(pos); + else + hordeInnkeeperPerLevelCache[(uint8)l].push_back(pos); + } + break; + } + } + LOG_INFO("playerbots", "{} innkeepers locations for level collected.", collected_locs); + results = WorldDatabase.Query( "SELECT " "map, " @@ -1571,15 +1656,20 @@ void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot) uint32 level = bot->GetLevel(); uint8 race = bot->getRace(); + std::vector* locs = nullptr; + if (sPlayerbotAIConfig->enableNewRpgStrategy) + locs = IsAlliance(race) ? &allianceInnkeeperPerLevelCache[level] : &hordeInnkeeperPerLevelCache[level]; + else + locs = &locsPerLevelCache[level]; LOG_DEBUG("playerbots", "Random teleporting bot {} for level {} ({} locations available)", bot->GetName().c_str(), - bot->GetLevel(), locsPerLevelCache[level].size()); - if (level > 10 && urand(0, 100) < sPlayerbotAIConfig->probTeleToBankers * 100) + bot->GetLevel(), locs->size()); + if (level >= 5 && urand(0, 100) < sPlayerbotAIConfig->probTeleToBankers * 100) { RandomTeleport(bot, bankerLocsPerLevelCache[level], true); } else { - RandomTeleport(bot, locsPerLevelCache[level]); + RandomTeleport(bot, *locs); } } @@ -1590,10 +1680,15 @@ void RandomPlayerbotMgr::RandomTeleportGrindForLevel(Player* bot) uint32 level = bot->GetLevel(); uint8 race = bot->getRace(); + std::vector* locs = nullptr; + if (sPlayerbotAIConfig->enableNewRpgStrategy) + locs = IsAlliance(race) ? &allianceInnkeeperPerLevelCache[level] : &hordeInnkeeperPerLevelCache[level]; + else + locs = &locsPerLevelCache[level]; LOG_DEBUG("playerbots", "Random teleporting bot {} for level {} ({} locations available)", bot->GetName().c_str(), - bot->GetLevel(), locsPerLevelCache[level].size()); + bot->GetLevel(), locs->size()); - RandomTeleport(bot, locsPerLevelCache[level]); + RandomTeleport(bot, *locs); } void RandomPlayerbotMgr::RandomTeleport(Player* bot) diff --git a/src/RandomPlayerbotMgr.h b/src/RandomPlayerbotMgr.h index f7ebf9aa..60d8d8d0 100644 --- a/src/RandomPlayerbotMgr.h +++ b/src/RandomPlayerbotMgr.h @@ -171,6 +171,10 @@ public: void PrepareAddclassCache(); std::map> addclassCache; + std::map> locsPerLevelCache; + std::map> allianceInnkeeperPerLevelCache; + std::map> hordeInnkeeperPerLevelCache; + std::map> bankerLocsPerLevelCache; protected: void OnBotLoginInternal(Player* const bot) override; @@ -199,8 +203,7 @@ private: std::vector players; uint32 processTicks; - std::map> locsPerLevelCache; - std::map> bankerLocsPerLevelCache; + // std::map> rpgLocsCache; std::map>> rpgLocsCacheLevel; diff --git a/src/strategy/StrategyContext.h b/src/strategy/StrategyContext.h index da3d8e42..dad46bd8 100644 --- a/src/strategy/StrategyContext.h +++ b/src/strategy/StrategyContext.h @@ -31,6 +31,7 @@ #include "MeleeCombatStrategy.h" #include "MoveFromGroupStrategy.h" #include "NamedObjectContext.h" +#include "NewRpgStrategy.h" #include "NonCombatStrategy.h" #include "PassiveStrategy.h" #include "PullStrategy.h" @@ -82,6 +83,7 @@ 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; @@ -152,6 +154,7 @@ 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); } diff --git a/src/strategy/actions/ActionContext.h b/src/strategy/actions/ActionContext.h index c13f7162..163731bf 100644 --- a/src/strategy/actions/ActionContext.h +++ b/src/strategy/actions/ActionContext.h @@ -62,6 +62,7 @@ #include "VehicleActions.h" #include "WorldBuffAction.h" #include "XpGainAction.h" +#include "NewRpgAction.h" class PlayerbotAI; @@ -240,6 +241,10 @@ 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 move random"] = &ActionContext::new_rpg_move_random; } private: @@ -415,6 +420,10 @@ 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_move_random(PlayerbotAI* ai) { return new NewRpgMoveRandomAction(ai); } }; #endif diff --git a/src/strategy/actions/ChatActionContext.h b/src/strategy/actions/ChatActionContext.h index 254dc919..f4cd9cba 100644 --- a/src/strategy/actions/ChatActionContext.h +++ b/src/strategy/actions/ChatActionContext.h @@ -38,6 +38,7 @@ #include "LootStrategyAction.h" #include "MailAction.h" #include "NamedObjectContext.h" +#include "NewRpgAction.h" #include "PassLeadershipToMasterAction.h" #include "PositionAction.h" #include "QueryItemUsageAction.h" @@ -88,6 +89,7 @@ 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; @@ -258,6 +260,7 @@ 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); } diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 899b91b5..f4e2be24 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -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 exact_waypoint, MovementPriority priority, bool lessDelay) { UpdateMovementState(); if (!IsMovingAllowed(mapId, x, y, z)) @@ -210,6 +210,10 @@ 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); @@ -233,6 +237,10 @@ 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); @@ -264,6 +272,10 @@ 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); @@ -822,7 +834,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; + int typeOk = PATHFIND_NORMAL | PATHFIND_INCOMPLETE | PATHFIND_SHORTCUT; if (!(type & typeOk)) return false; float shortenTo = distance; @@ -838,7 +850,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); + MovementPriority::MOVEMENT_COMBAT, true); } float MovementAction::GetFollowAngle() @@ -2013,8 +2025,15 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius) } bool strict = checkAngle.strict; float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance); - Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, bot->GetPositionY() + sin(angle) * fleeDis, - bot->GetPositionZ()}; + 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}; if (strict && currentTarget && fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->tooCloseDistance && @@ -2069,8 +2088,15 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius) } bool strict = checkAngle.strict; float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance); - Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, bot->GetPositionY() + sin(angle) * fleeDis, - bot->GetPositionZ()}; + 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}; if (strict && currentTarget && fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->spellDistance) { @@ -2082,6 +2108,7 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius) { continue; } + if (pos.GetExactDist(fleePos) > farestDis) { farestDis = pos.GetExactDist(fleePos); diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index 76929427..ce6c64b2 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -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 normal_only = false, bool exact_waypoint = false, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL, bool lessDelay = false); 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(); diff --git a/src/strategy/actions/NewRpgAction.cpp b/src/strategy/actions/NewRpgAction.cpp new file mode 100644 index 00000000..6fe6e488 --- /dev/null +++ b/src/strategy/actions/NewRpgAction.cpp @@ -0,0 +1,214 @@ +#include "NewRpgAction.h" + +#include + +#include "NewRpgStrategy.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: + { + // // IDLE -> NEAR_NPC + // if (!info.lastNearNpc || info.lastNearNpc + setNpcInterval < getMSTime() && urand(1, 100) <= 50) + // { + // info.lastNearNpc = getMSTime(); + // GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets"); + // if (possibleTargets.empty()) + // break; + // info.status = NewRpgStatus::NEAR_NPC; + // } + // IDLE -> GO_GRIND + if (!info.lastGrind || info.lastGrind + setGrindInterval < getMSTime()) + { + info.lastGrind = getMSTime(); + WorldPosition pos = SelectRandomGrindPos(); + if (pos == WorldPosition()) + break; + info.status = NewRpgStatus::GO_GRIND; + info.grindPos = pos; + return true; + } + break; + } + 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.grindPos = WorldPosition(); + return true; + } + // just choose another grindPos + if (!info.lastGrind || info.lastGrind + setGrindInterval < getMSTime()) + { + WorldPosition pos = SelectRandomGrindPos(); + if (pos == WorldPosition()) + break; + info.status = NewRpgStatus::GO_GRIND; + info.lastGrind = getMSTime(); + info.grindPos = pos; + return true; + } + break; + } + case NewRpgStatus::NEAR_RANDOM: + { + // NEAR_RANDOM -> GO_GRIND + if (!info.lastGrind || info.lastGrind + setGrindInterval < getMSTime()) + { + WorldPosition pos = SelectRandomGrindPos(); + if (pos == WorldPosition()) + break; + info.lastGrind = getMSTime(); + botAI->rpgInfo.status = NewRpgStatus::GO_GRIND; + botAI->rpgInfo.grindPos = pos; + return true; + } + break; + } + default: + break; + } + return false; +} + +WorldPosition NewRpgStatusUpdateAction::SelectRandomGrindPos() +{ + const std::vector& locs = sRandomPlayerbotMgr->locsPerLevelCache[bot->GetLevel()]; + std::vector lo_prepared_locs, hi_prepared_locs; + for (auto& loc : locs) + { + if (bot->GetMapId() != loc.GetMapId()) + continue; + + if (bot->GetExactDist(loc) < 500.0f) + { + hi_prepared_locs.push_back(loc); + } + + if (bot->GetExactDist(loc) < 1500.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_INFO("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; +} + +bool NewRpgGoFarAwayPosAction::MoveFarTo(WorldPosition dest) +{ + float dis = bot->GetExactDist(dest); + if (dis < pathFinderDis) + { + return MoveTo(dest.getMapId(), dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ()); + } + + int attempt = 10; + float minDelta = MAXFLOAT; + const float x = bot->GetPositionX(); + const float y = bot->GetPositionY(); + const float z = bot->GetPositionZ(); + float rx, ry, rz; + bool found = false; + while (--attempt) + { + float angle = bot->GetAngle(&dest); + float delta = (rand_norm() - 0.5) * M_PI; + angle += delta; + float dis = rand_norm() * pathFinderDis; + float dx = x + cos(angle) * dis; + float dy = y + sin(angle) * dis; + float dz = z; + PathGenerator path(bot); + path.CalculatePath(dx, dy, dz); + // bool canReach = bot->GetMap()->CanReachPositionAndGetValidCoords(bot, x, y, z, dx, dy, dz, false); + bool canReach = path.GetPathType() & (PATHFIND_NORMAL | PATHFIND_INCOMPLETE); + + if (canReach) + { + G3D::Vector3 endPos = path.GetPath().back(); + if (fabs(delta) < minDelta) + { + found = true; + minDelta = fabs(delta); + rx = endPos.x; + ry = endPos.y; + rz = endPos.z; + } + } + } + if (found) + { + return MoveTo(bot->GetMapId(), rx, ry, rz, false, false, false, true); + } + // fallback to direct move + float angle = bot->GetAngle(&dest); + return MoveTo(bot->GetMapId(), x + cos(angle) * pathFinderDis, y + sin(angle) * pathFinderDis, z); +} + +bool NewRpgGoGrindAction::Execute(Event event) { return MoveFarTo(botAI->rpgInfo.grindPos); } + +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(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; +} \ No newline at end of file diff --git a/src/strategy/actions/NewRpgAction.h b/src/strategy/actions/NewRpgAction.h new file mode 100644 index 00000000..a2ea84a5 --- /dev/null +++ b/src/strategy/actions/NewRpgAction.h @@ -0,0 +1,57 @@ +#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 = 5 * 60 * 1000; + WorldPosition SelectRandomGrindPos(); +}; + +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 NewRpgMoveRandomAction : public MovementAction +{ +public: + NewRpgMoveRandomAction(PlayerbotAI* botAI) : MovementAction(botAI, "new rpg move random") {} + bool Execute(Event event) override; +protected: + const float moveStep = 50.0f; +}; + +#endif \ No newline at end of file diff --git a/src/strategy/actions/ReviveFromCorpseAction.cpp b/src/strategy/actions/ReviveFromCorpseAction.cpp index 4f19a639..1f61df3b 100644 --- a/src/strategy/actions/ReviveFromCorpseAction.cpp +++ b/src/strategy/actions/ReviveFromCorpseAction.cpp @@ -347,16 +347,16 @@ bool SpiritHealerAction::Execute(Event event) if (moved) return true; - if (!botAI->HasActivePlayerMaster()) - { - context->GetValue("death count")->Set(dCount + 1); - return bot->TeleportTo(ClosestGrave->Map, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, 0.f); - } + // if (!botAI->HasActivePlayerMaster()) + // { + context->GetValue("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; } diff --git a/src/strategy/generic/ChatCommandHandlerStrategy.cpp b/src/strategy/generic/ChatCommandHandlerStrategy.cpp index e88ac5bb..132f2423 100644 --- a/src/strategy/generic/ChatCommandHandlerStrategy.cpp +++ b/src/strategy/generic/ChatCommandHandlerStrategy.cpp @@ -106,6 +106,7 @@ 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"); diff --git a/src/strategy/generic/GrindingStrategy.cpp b/src/strategy/generic/GrindingStrategy.cpp index c8638e45..87970637 100644 --- a/src/strategy/generic/GrindingStrategy.cpp +++ b/src/strategy/generic/GrindingStrategy.cpp @@ -11,10 +11,10 @@ NextAction** GrindingStrategy::getDefaultActions() { return nullptr; } void GrindingStrategy::InitTriggers(std::vector& triggers) { - 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("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("no target", NextAction::array(0, new NextAction("attack anything", 4.0f), nullptr))); + new TriggerNode("no target", NextAction::array(0, new NextAction("attack anything", 10.0f), nullptr))); } void MoveRandomStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/generic/NewRpgStrategy.cpp b/src/strategy/generic/NewRpgStrategy.cpp new file mode 100644 index 00000000..a2a38c5c --- /dev/null +++ b/src/strategy/generic/NewRpgStrategy.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016+ AzerothCore , 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& 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("near random status", NextAction::array(0, new NextAction("new rpg move random", 1.0f), nullptr))); +} + +void NewRpgStrategy::InitMultipliers(std::vector& multipliers) +{ + // multipliers.push_back(new RpgActionMultiplier(botAI)); +} diff --git a/src/strategy/generic/NewRpgStrategy.h b/src/strategy/generic/NewRpgStrategy.h new file mode 100644 index 00000000..c23ee9b2 --- /dev/null +++ b/src/strategy/generic/NewRpgStrategy.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016+ AzerothCore , 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 +#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, + // Idling + IDLE +}; + +struct NewRpgInfo +{ + NewRpgStatus status{NewRpgStatus::IDLE}; + WorldPosition grindPos{}; + uint32 lastGrind{0}; + uint32 lastNearNpc{0}; + std::string ToString() + { + std::stringstream out; + out << "Status: "; + switch (status) + { + case NewRpgStatus::GO_GRIND: + out << "GO_GRIND"; + break; + case NewRpgStatus::GO_INNKEEPER: + out << "GO_INNKEEPER"; + break; + case NewRpgStatus::NEAR_NPC: + out << "NEAR_NPC"; + break; + case NewRpgStatus::NEAR_RANDOM: + out << "NEAR_RANDOM"; + break; + case NewRpgStatus::IDLE: + out << "IDLE"; + break; + } + out << "\nGrindPos: " << grindPos.GetMapId() << " " << grindPos.GetPositionX() << " " << grindPos.GetPositionY() << " " << grindPos.GetPositionZ(); + out << "\nLastGrind: " << lastGrind; + 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& triggers) override; + void InitMultipliers(std::vector& multipliers) override; +}; + +#endif diff --git a/src/strategy/triggers/ChatTriggerContext.h b/src/strategy/triggers/ChatTriggerContext.h index af20f3a9..950cacb3 100644 --- a/src/strategy/triggers/ChatTriggerContext.h +++ b/src/strategy/triggers/ChatTriggerContext.h @@ -24,6 +24,7 @@ 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; @@ -211,6 +212,7 @@ 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"); } diff --git a/src/strategy/triggers/NewRpgTrigger.cpp b/src/strategy/triggers/NewRpgTrigger.cpp new file mode 100644 index 00000000..66354092 --- /dev/null +++ b/src/strategy/triggers/NewRpgTrigger.cpp @@ -0,0 +1,4 @@ +#include "NewRpgTriggers.h" +#include "PlayerbotAI.h" + +bool NewRpgStatusTrigger::IsActive() { return status == botAI->rpgInfo.status; } \ No newline at end of file diff --git a/src/strategy/triggers/NewRpgTriggers.h b/src/strategy/triggers/NewRpgTriggers.h new file mode 100644 index 00000000..9827d57e --- /dev/null +++ b/src/strategy/triggers/NewRpgTriggers.h @@ -0,0 +1,20 @@ +#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 diff --git a/src/strategy/triggers/TriggerContext.h b/src/strategy/triggers/TriggerContext.h index cbfeec6f..3bcc44c8 100644 --- a/src/strategy/triggers/TriggerContext.h +++ b/src/strategy/triggers/TriggerContext.h @@ -12,6 +12,8 @@ #include "LfgTriggers.h" #include "LootTriggers.h" #include "NamedObjectContext.h" +#include "NewRpgStrategy.h" +#include "NewRpgTriggers.h" #include "PvpTriggers.h" #include "RaidNaxxTriggers.h" #include "RpgTriggers.h" @@ -213,6 +215,8 @@ 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["near random status"] = &TriggerContext::near_random_status; } private: @@ -402,6 +406,8 @@ 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* near_random_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, NewRpgStatus::NEAR_RANDOM); } }; #endif diff --git a/src/strategy/values/DpsTargetValue.cpp b/src/strategy/values/DpsTargetValue.cpp index 88c52ccf..526f2e42 100644 --- a/src/strategy/values/DpsTargetValue.cpp +++ b/src/strategy/values/DpsTargetValue.cpp @@ -298,8 +298,9 @@ Unit* DpsTargetValue::Calculate() return rti; // FindLeastHpTargetStrategy strategy(botAI); + Group* group = bot->GetGroup(); float dps = AI_VALUE(float, "estimated group dps"); - if (botAI->IsCaster(bot)) + if (group && botAI->IsCaster(bot)) { CasterFindTargetSmartStrategy strategy(botAI, dps); return TargetValue::FindTarget(&strategy); diff --git a/src/strategy/values/GrindTargetValue.cpp b/src/strategy/values/GrindTargetValue.cpp index e6109463..b21f62a9 100644 --- a/src/strategy/values/GrindTargetValue.cpp +++ b/src/strategy/values/GrindTargetValue.cpp @@ -52,7 +52,7 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) float distance = 0; Unit* result = nullptr; - std::unordered_map needForQuestMap; + // std::unordered_map 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(unit); - if ((urand(0, 100) < 60 || (context->GetValue("travel target")->Get()->isWorking() && - context->GetValue("travel target")->Get()->getDestination()->getName() != "GrindTravelDestination"))) - { - continue; - } - } + // if (!needForQuestMap[unit->GetEntry()]) + // { + // Creature* creature = dynamic_cast(unit); + // if ((urand(0, 100) < 60 || (context->GetValue("travel target")->Get()->isWorking() && + // context->GetValue("travel target")->Get()->getDestination()->getName() != "GrindTravelDestination"))) + // { + // continue; + // } + // } if (Creature* creature = unit->ToCreature()) if (CreatureTemplate const* CreatureTemplate = creature->GetCreatureTemplate()) @@ -142,8 +142,7 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) else { float newdistance = bot->GetDistance(unit); - if (!result || (newdistance < distance && - urand(0, abs(distance - newdistance)) > sPlayerbotAIConfig->sightDistance * 0.1)) + if (!result || (newdistance < distance)) { distance = newdistance; result = unit; diff --git a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp index a46346fe..4de01421 100644 --- a/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp +++ b/src/strategy/warlock/GenericWarlockNonCombatStrategy.cpp @@ -48,7 +48,7 @@ private: { return new ActionNode("summon succubus", /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("summon imp"), nullptr), + /*A*/ NextAction::array(0, new NextAction("summon voidwalker"), nullptr), /*C*/ nullptr); } static ActionNode* summon_felhunter([[maybe_unused]] PlayerbotAI* botAI)