mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-16 16:46:10 +00:00
# Pull Request
This is the first in a series of PRs intended to eliminate warnings in
the module. The design intent is to eliminate the calling event when not
needed in the body of the function. Based off of SmashingQuasars work.
---
## How to Test the Changes
- Step-by-step instructions to test the change
- Any required setup (e.g. multiple players, bots, specific
configuration)
- Expected behavior and how to verify it
## Complexity & Impact
- Does this change add new decision branches?
- [x] No
- [ ] Yes (**explain below**)
- Does this change increase per-bot or per-tick processing?
- [x] No
- [ ] Yes (**describe and justify impact**)
- Could this logic scale poorly under load?
- [x] No
- [ ] Yes (**explain why**)
---
## Defaults & Configuration
- Does this change modify default bot behavior?
- [x] No
- [ ] Yes (**explain why**)
If this introduces more advanced or AI-heavy logic:
- [ ] Lightweight mode remains the default
- [ ] More complex behavior is optional and thereby configurable
---
## AI Assistance
- Was AI assistance (e.g. ChatGPT or similar tools) used while working
on this change?
- [x] No
- [ ] Yes (**explain below**)
---
## Final Checklist
- [x] Stability is not compromised
- [x] Performance impact is understood, tested, and acceptable
- [x] Added logic complexity is justified and explained
- [x] Documentation updated if needed
---
## Notes for Reviewers
Anything that significantly improves realism at the cost of stability or
performance should be carefully discussed
before merging.
---------
Co-authored-by: bashermens <31279994+hermensbas@users.noreply.github.com>
353 lines
10 KiB
C++
353 lines
10 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
*/
|
|
|
|
#include "LfgActions.h"
|
|
|
|
#include "AiFactory.h"
|
|
#include "ItemVisitors.h"
|
|
#include "LFGMgr.h"
|
|
#include "Opcodes.h"
|
|
#include "Playerbots.h"
|
|
#include "World.h"
|
|
#include "WorldPacket.h"
|
|
#include "RandomPlayerbotMgr.h"
|
|
|
|
using namespace lfg;
|
|
|
|
bool LfgJoinAction::Execute(Event event) { return JoinLFG(); }
|
|
|
|
uint32 LfgJoinAction::GetRoles()
|
|
{
|
|
if (!RandomPlayerbotMgr::instance().IsRandomBot(bot))
|
|
{
|
|
if (botAI->IsTank(bot))
|
|
return PLAYER_ROLE_TANK;
|
|
if (botAI->IsHeal(bot))
|
|
return PLAYER_ROLE_HEALER;
|
|
else
|
|
return PLAYER_ROLE_DAMAGE;
|
|
}
|
|
|
|
uint8 spec = AiFactory::GetPlayerSpecTab(bot);
|
|
switch (bot->getClass())
|
|
{
|
|
case CLASS_DRUID:
|
|
if (spec == 2)
|
|
return PLAYER_ROLE_HEALER;
|
|
else if (spec == 1 && bot->HasAura(16931) /* thick hide */)
|
|
return PLAYER_ROLE_TANK;
|
|
else
|
|
return PLAYER_ROLE_DAMAGE;
|
|
break;
|
|
case CLASS_PALADIN:
|
|
if (spec == 1)
|
|
return PLAYER_ROLE_TANK;
|
|
else if (!spec)
|
|
return PLAYER_ROLE_HEALER;
|
|
else
|
|
return PLAYER_ROLE_DAMAGE;
|
|
break;
|
|
case CLASS_PRIEST:
|
|
if (spec != 2)
|
|
return PLAYER_ROLE_HEALER;
|
|
else
|
|
return PLAYER_ROLE_DAMAGE;
|
|
break;
|
|
case CLASS_SHAMAN:
|
|
if (spec == 2)
|
|
return PLAYER_ROLE_HEALER;
|
|
else
|
|
return PLAYER_ROLE_DAMAGE;
|
|
break;
|
|
case CLASS_WARRIOR:
|
|
if (spec == 2)
|
|
return PLAYER_ROLE_TANK;
|
|
else
|
|
return PLAYER_ROLE_DAMAGE;
|
|
break;
|
|
case CLASS_DEATH_KNIGHT:
|
|
if (spec == 0)
|
|
return PLAYER_ROLE_TANK;
|
|
else
|
|
return PLAYER_ROLE_DAMAGE;
|
|
break;
|
|
|
|
default:
|
|
return PLAYER_ROLE_DAMAGE;
|
|
break;
|
|
}
|
|
|
|
return PLAYER_ROLE_DAMAGE;
|
|
}
|
|
|
|
bool LfgJoinAction::JoinLFG()
|
|
{
|
|
// check if already in lfg
|
|
LfgState state = sLFGMgr->GetState(bot->GetGUID());
|
|
if (state != LFG_STATE_NONE)
|
|
return false;
|
|
|
|
/*ItemCountByQuality visitor;
|
|
IterateItems(&visitor, ITERATE_ITEMS_IN_EQUIP);
|
|
bool random = urand(0, 100) < 20;
|
|
bool heroic = urand(0, 100) < 50 &&
|
|
(visitor.count[ITEM_QUALITY_EPIC] >= 3 || visitor.count[ITEM_QUALITY_RARE] >= 10) &&
|
|
bot->GetLevel() >= 70;
|
|
bool rbotAId = !heroic && (urand(0, 100) < 50 && visitor.count[ITEM_QUALITY_EPIC] >= 5 &&
|
|
(bot->GetLevel() == 60 || bot->GetLevel() == 70 || bot->GetLevel() == 80));*/
|
|
|
|
LfgDungeonSet list;
|
|
std::vector<uint32> selected;
|
|
|
|
std::vector<uint32> dungeons = RandomPlayerbotMgr::instance().LfgDungeons[bot->GetTeamId()];
|
|
if (!dungeons.size())
|
|
return false;
|
|
|
|
for (std::vector<uint32>::iterator i = dungeons.begin(); i != dungeons.end(); ++i)
|
|
{
|
|
LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*i);
|
|
if (!dungeon || (dungeon->TypeID != LFG_TYPE_RANDOM && dungeon->TypeID != LFG_TYPE_DUNGEON &&
|
|
dungeon->TypeID != LFG_TYPE_HEROIC && dungeon->TypeID != LFG_TYPE_RAID))
|
|
continue;
|
|
|
|
auto const& botLevel = bot->GetLevel();
|
|
|
|
/*LFG_TYPE_RANDOM on classic is 15-58 so bot over level 25 will never queue*/
|
|
if (dungeon->MinLevel && (botLevel < dungeon->MinLevel || botLevel > dungeon->MaxLevel) ||
|
|
(botLevel > dungeon->MinLevel + 10 && dungeon->TypeID == LFG_TYPE_DUNGEON))
|
|
continue;
|
|
|
|
selected.push_back(dungeon->ID);
|
|
list.insert(dungeon->ID);
|
|
}
|
|
|
|
if (!selected.size())
|
|
return false;
|
|
|
|
if (list.empty())
|
|
return false;
|
|
|
|
bool many = list.size() > 1;
|
|
LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(*list.begin());
|
|
|
|
// check role for console msg
|
|
std::string _roles = "multiple roles";
|
|
uint32 roleMask = GetRoles();
|
|
if (roleMask & PLAYER_ROLE_TANK)
|
|
_roles = "TANK";
|
|
|
|
if (roleMask & PLAYER_ROLE_HEALER)
|
|
_roles = "HEAL";
|
|
|
|
if (roleMask & PLAYER_ROLE_DAMAGE)
|
|
_roles = "DPS";
|
|
|
|
LOG_INFO("playerbots", "Bot {} {}:{} <{}>: queues LFG, Dungeon as {} ({})", bot->GetGUID().ToString().c_str(),
|
|
bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName().c_str(), _roles,
|
|
many ? "several dungeons" : dungeon->Name[0]);
|
|
|
|
// Set RbotAId Browser comment
|
|
std::string const _gs = std::to_string(botAI->GetEquipGearScore(bot/*, false, false*/));
|
|
|
|
// JoinLfg is not threadsafe, so make packet and queue into session
|
|
// sLFGMgr->JoinLfg(bot, roleMask, list, _gs);
|
|
|
|
WorldPacket* data = new WorldPacket(CMSG_LFG_JOIN);
|
|
*data << (uint32)roleMask;
|
|
*data << (bool)false;
|
|
*data << (bool)false;
|
|
// Slots
|
|
*data << (uint8)(list.size());
|
|
for (uint32 dungeon : list)
|
|
*data << (uint32)dungeon;
|
|
// Needs
|
|
*data << (uint8)3 << (uint8)0 << (uint8)0 << (uint8)0;
|
|
*data << _gs;
|
|
bot->GetSession()->QueuePacket(data);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool LfgRoleCheckAction::Execute(Event /*event*/)
|
|
{
|
|
if (Group* group = bot->GetGroup())
|
|
{
|
|
uint32 currentRoles = sLFGMgr->GetRoles(bot->GetGUID());
|
|
uint32 newRoles = GetRoles();
|
|
// if (currentRoles == newRoles)
|
|
// return false;
|
|
|
|
WorldPacket* packet = new WorldPacket(CMSG_LFG_SET_ROLES);
|
|
*packet << (uint8)newRoles;
|
|
bot->GetSession()->QueuePacket(packet);
|
|
// sLFGMgr->SetRoles(bot->GetGUID(), newRoles);
|
|
// sLFGMgr->UpdateRoleCheck(group->GetGUID(), bot->GetGUID(), newRoles);
|
|
|
|
LOG_INFO("playerbots", "Bot {} {}:{} <{}>: LFG roles checked", bot->GetGUID().ToString().c_str(),
|
|
bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->GetLevel(), bot->GetName().c_str());
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool LfgAcceptAction::Execute(Event event)
|
|
{
|
|
uint32 id = AI_VALUE(uint32, "lfg proposal");
|
|
|
|
// Try accept if already stored
|
|
if (id)
|
|
{
|
|
if (bot->IsInCombat() || bot->isDead())
|
|
{
|
|
WorldPacket* packet = new WorldPacket(CMSG_LFG_PROPOSAL_RESULT);
|
|
*packet << id << false;
|
|
bot->GetSession()->QueuePacket(packet);
|
|
return true;
|
|
}
|
|
|
|
botAI->GetAiObjectContext()->GetValue<uint32>("lfg proposal")->Set(0);
|
|
bot->ClearUnitState(UNIT_STATE_ALL_STATE);
|
|
|
|
WorldPacket* packet = new WorldPacket(CMSG_LFG_PROPOSAL_RESULT);
|
|
*packet << id << true;
|
|
bot->GetSession()->QueuePacket(packet);
|
|
|
|
if (RandomPlayerbotMgr::instance().IsRandomBot(bot) && !bot->GetGroup())
|
|
{
|
|
RandomPlayerbotMgr::instance().Refresh(bot);
|
|
botAI->ResetStrategies();
|
|
}
|
|
|
|
botAI->Reset();
|
|
return true;
|
|
}
|
|
|
|
// If we get the proposal packet, accept immediately
|
|
if (!event.getPacket().empty())
|
|
{
|
|
WorldPacket p(event.getPacket());
|
|
uint32 dungeonId;
|
|
uint8 state;
|
|
p >> dungeonId >> state >> id;
|
|
|
|
if (id)
|
|
{
|
|
if (bot->IsInCombat() || bot->isDead())
|
|
{
|
|
WorldPacket* packet = new WorldPacket(CMSG_LFG_PROPOSAL_RESULT);
|
|
*packet << id << false;
|
|
bot->GetSession()->QueuePacket(packet);
|
|
return true;
|
|
}
|
|
|
|
botAI->GetAiObjectContext()->GetValue<uint32>("lfg proposal")->Set(0);
|
|
bot->ClearUnitState(UNIT_STATE_ALL_STATE);
|
|
|
|
WorldPacket* packet = new WorldPacket(CMSG_LFG_PROPOSAL_RESULT);
|
|
*packet << id << true;
|
|
bot->GetSession()->QueuePacket(packet);
|
|
|
|
if (RandomPlayerbotMgr::instance().IsRandomBot(bot) && !bot->GetGroup())
|
|
{
|
|
RandomPlayerbotMgr::instance().Refresh(bot);
|
|
botAI->ResetStrategies();
|
|
}
|
|
|
|
botAI->Reset();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool LfgLeaveAction::Execute(Event /*event*/)
|
|
{
|
|
// Don't leave if lfg strategy enabled
|
|
// if (botAI->HasStrategy("lfg", BOT_STATE_NON_COMBAT))
|
|
// return false;
|
|
|
|
// Don't leave if already invited / in dungeon
|
|
if (sLFGMgr->GetState(bot->GetGUID()) > LFG_STATE_QUEUED)
|
|
return false;
|
|
|
|
WorldPacket* packet = new WorldPacket(CMSG_LFG_LEAVE);
|
|
bot->GetSession()->QueuePacket(packet);
|
|
// sLFGMgr->LeaveLfg(bot->GetGUID());
|
|
return true;
|
|
}
|
|
|
|
bool LfgLeaveAction::isUseful() { return true; }
|
|
|
|
bool LfgTeleportAction::Execute(Event event)
|
|
{
|
|
bool out = false;
|
|
|
|
WorldPacket p(event.getPacket());
|
|
if (!p.empty())
|
|
{
|
|
p.rpos(0);
|
|
p >> out;
|
|
}
|
|
|
|
bot->ClearUnitState(UNIT_STATE_ALL_STATE);
|
|
|
|
WorldPacket* packet = new WorldPacket(CMSG_LFG_TELEPORT);
|
|
*packet << out;
|
|
bot->GetSession()->QueuePacket(packet);
|
|
// sLFGMgr->TeleportPlayer(bot, out);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool LfgJoinAction::isUseful()
|
|
{
|
|
if (!sPlayerbotAIConfig.randomBotJoinLfg)
|
|
{
|
|
// botAI->ChangeStrategy("-lfg", BOT_STATE_NON_COMBAT);
|
|
return false;
|
|
}
|
|
|
|
if (bot->GetLevel() < 15)
|
|
return false;
|
|
|
|
// don't use if active player master
|
|
if (GET_PLAYERBOT_AI(bot)->IsRealPlayer())
|
|
return false;
|
|
|
|
if (bot->GetGroup() && bot->GetGroup()->GetLeaderGUID() != bot->GetGUID())
|
|
{
|
|
// botAI->ChangeStrategy("-lfg", BOT_STATE_NON_COMBAT);
|
|
return false;
|
|
}
|
|
|
|
if (bot->IsBeingTeleported())
|
|
return false;
|
|
|
|
if (bot->InBattleground())
|
|
return false;
|
|
|
|
if (bot->InBattlegroundQueue())
|
|
return false;
|
|
|
|
if (bot->isDead())
|
|
return false;
|
|
|
|
if (!RandomPlayerbotMgr::instance().IsRandomBot(bot))
|
|
return false;
|
|
|
|
Map* map = bot->GetMap();
|
|
if (map && map->Instanceable())
|
|
return false;
|
|
|
|
LfgState state = sLFGMgr->GetState(bot->GetGUID());
|
|
if (state != LFG_STATE_NONE)
|
|
return false;
|
|
|
|
return true;
|
|
}
|