Skip to content

Commit

Permalink
NPCBots: Implement bots participating in non-rated arena matches. All…
Browse files Browse the repository at this point in the history
…ow owned bots to retaliate to non-melee hostile actions if within attack radius
  • Loading branch information
trickerer committed Nov 8, 2024
1 parent 039ae30 commit 392ec0f
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 30 deletions.
49 changes: 35 additions & 14 deletions src/server/game/AI/NpcBots/bot_ai.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5320,15 +5320,17 @@ void bot_ai::_extendAttackRange(float& dist) const
}
bool bot_ai::_canSwitchToTarget(Unit const* from, Unit const* newTarget, int8 byspell) const
{
if (newTarget)
if (newTarget && newTarget != me->GetVictim())
{
if (IAmFree())
{
if (newTarget != me->GetVictim() &&
(!from || me->GetDistance(newTarget) < me->GetDistance(from) - 10.0f || newTarget->GetHealth() < from->GetHealth()) &&
if ((!from || me->GetDistance(newTarget) < me->GetDistance(from) - 10.0f || newTarget->GetHealth() < from->GetHealth()) &&
CanBotAttack(newTarget, byspell))
return true;
}
else if (!from && me->GetDistance(newTarget) < 0.75f * _getAttackDistance(float(master->GetBotMgr()->GetBotFollowDist())) &&
CanBotAttack(newTarget, byspell))
return true;
}

return false;
Expand Down Expand Up @@ -17659,13 +17661,17 @@ bool bot_ai::GlobalUpdate(uint32 diff)
//Faction
//ensure master is not controlled
ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(master->GetRace());
uint32 fac = rEntry ? rEntry->FactionID : 0;
if (me->GetFaction() != master->GetFaction() && master->GetFaction() == fac)
uint32 fac_orig = rEntry ? rEntry->FactionID : 0;
if (master->GetFaction() == fac_orig)
{
//std::ostringstream msg;
//msg << "Something changed my faction (now " << me->GetFaction() << "), changing back to " << fac << "!";
//BotWhisper(msg.str().c_str());
me->SetFaction(fac);
uint32 fac = (!IAmFree() && me->GetMap()->IsBattleArena()) ? FACTION_MONSTER : fac_orig;
if (me->GetFaction() != fac)
{
//std::ostringstream msg;
//msg << "Something changed my faction (now " << me->GetFaction() << "), changing back to " << fac << "!";
//BotWhisper(msg.str().c_str());
me->SetFaction(fac);
}
}
//Visibility
if (!me->IsVisible() && master->IsVisible())
Expand Down Expand Up @@ -18658,6 +18664,16 @@ bool bot_ai::FinishTeleport(bool reset)
}
//me->CastSpell(me, HONORLESS_TARGET, true);

//Arena flags
Battleground const* bg = GetBG();
if (bg && bg->isArena())
{
TeamId teamId = bg->GetBotTeamId(me->GetGUID());
uint32 flag_spell = teamId == TEAM_ALLIANCE ? master->GetTeamId() == TEAM_HORDE ? ARENA_FLAG_TEAM_H_GOLD : ARENA_FLAG_TEAM_A_GOLD :
master->GetTeamId() == TEAM_HORDE ? ARENA_FLAG_TEAM_H_GREEN : ARENA_FLAG_TEAM_A_GREEN;
me->CastSpell(me, flag_spell, true);
}

//update group member online state
if (Group* gr = master->GetGroup())
if (gr->IsMember(me->GetGUID()))
Expand Down Expand Up @@ -19992,18 +20008,23 @@ void bot_ai::OnBotEnterBattleground()
if (bg->GetStatus() != STATUS_IN_PROGRESS && IsWanderer())
{
BotWPFlags myTeamSpawnFlags;
switch (bg->GetBotTeamId(me->GetGUID()))
if (bg->isArena())
myTeamSpawnFlags = BotWPFlags::BOTWP_FLAG_SPAWN;
else
{
case TEAM_ALLIANCE: myTeamSpawnFlags = BotWPFlags::BOTWP_FLAG_ALLIANCE_SPAWN_POINT; break;
case TEAM_HORDE: myTeamSpawnFlags = BotWPFlags::BOTWP_FLAG_HORDE_SPAWN_POINT; break;
default: myTeamSpawnFlags = BotWPFlags::BOTWP_FLAG_SPAWN; break;
switch (bg->GetBotTeamId(me->GetGUID()))
{
case TEAM_ALLIANCE: myTeamSpawnFlags = BotWPFlags::BOTWP_FLAG_ALLIANCE_SPAWN_POINT; break;
case TEAM_HORDE: myTeamSpawnFlags = BotWPFlags::BOTWP_FLAG_HORDE_SPAWN_POINT; break;
default: myTeamSpawnFlags = BotWPFlags::BOTWP_FLAG_SPAWN; break;
}
}

uint32 mapId = bg->GetBgMap()->GetId();
float mindist = 50000.0f;
WanderNode const* startNode = nullptr;
WanderNode::DoForAllMapWPs(mapId, [pos = me->GetPosition(), spawnFlags = myTeamSpawnFlags, &mindist, &startNode](WanderNode const* wp) {
if (wp->HasFlag(spawnFlags))
if (wp->HasAllFlags(spawnFlags))
{
float dist = pos.GetExactDist2d(wp);
if (dist < mindist)
Expand Down
28 changes: 19 additions & 9 deletions src/server/game/AI/NpcBots/botmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1188,9 +1188,8 @@ void BotMgr::Update(uint32 diff)
if (ai->GetReviveTimer() <= diff)
{
if (bot->IsInMap(_owner) && !bot->IsAlive() && !ai->IsDuringTeleport() && _owner->IsAlive() && !_owner->IsInCombat() &&
!_owner->IsBeingTeleported() && !_owner->InArena() && !_owner->IsInFlight() &&
!_owner->HasUnitFlag2(UNIT_FLAG2_FEIGN_DEATH) &&
!_owner->HasInvisibilityAura() && !_owner->HasStealthAura())
!_owner->IsBeingTeleported() && !_owner->GetMap()->IsBattleArena() && !_owner->IsInFlight() &&
!_owner->HasUnitFlag2(UNIT_FLAG2_FEIGN_DEATH) && !_owner->HasInvisibilityAura() && !_owner->HasStealthAura())
{
_reviveBot(bot);
continue;
Expand Down Expand Up @@ -1252,10 +1251,11 @@ bool BotMgr::RestrictBots(Creature const* bot, bool add) const

if (LimitBots(currMap))
{
Group const* gr = _owner->GetGroup();

//if bot is not in instance group - deny (only if trying to teleport to instance)
if (add)
{
Group const* gr = _owner->GetGroup();
if (!gr || !gr->IsMember(bot->GetGUID()))
return true;

Expand Down Expand Up @@ -1292,13 +1292,23 @@ bool BotMgr::RestrictBots(Creature const* bot, bool add) const
uint32 max_players = 0;
if (currMap->IsDungeon())
max_players = currMap->ToInstanceMap()->GetMaxPlayers();
else if (currMap->IsBattleground())
else if (currMap->IsBattleground() || currMap->IsBattleArena())
max_players = _owner->GetBattleground()->GetMaxPlayersPerTeam();
else if (currMap->IsBattleArena())
max_players = _owner->GetBattleground()->GetArenaType();

if (max_players && currMap->GetPlayersCountExceptGMs() + uint32(add) > max_players)
return true;
if (max_players)
{
uint32 curPlayers;
if (gr && currMap->IsBattlegroundOrArena())
{
curPlayers = std::ranges::count_if(GetAllGroupMembers(gr), [this](Unit const* u) {
return u->IsInWorld() && u->IsInMap(_owner) && !(u->IsNPCBot() && u->ToCreature()->IsTempBot());
});
}
else
curPlayers = currMap->GetPlayersCountExceptGMs();
if (curPlayers + uint32(add) > max_players)
return true;
}
}

return false;
Expand Down
4 changes: 4 additions & 0 deletions src/server/game/AI/NpcBots/botspell.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ enum BotSpells : uint32
SUMMONING_STONE_EFFECT = 59782,//Cast time 5s + Channeled 2m
SHOOT_WAND = 5019,
OPEN_FLAG_BG = 21651,
ARENA_FLAG_TEAM_A_GOLD = 32724,
ARENA_FLAG_TEAM_A_GREEN = 32725,
ARENA_FLAG_TEAM_H_GOLD = 35774,
ARENA_FLAG_TEAM_H_GREEN = 35775,
///Portals
PORTAL_STORMWIND = 10059,
PORTAL_IRONFORGE = 11416,
Expand Down
11 changes: 5 additions & 6 deletions src/server/game/AI/NpcBots/bpet_ai.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2436,13 +2436,12 @@ bool bot_pet_ai::GlobalUpdate(uint32 diff)
//Faction
//ensure master is not controlled
ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(petOwner->GetBotOwner()->GetRace());
uint32 fac = rEntry ? rEntry->FactionID : 0;
if (me->GetFaction() != petOwner->GetBotOwner()->GetFaction() && petOwner->GetBotOwner()->GetFaction() == fac)
uint32 fac_orig = rEntry ? rEntry->FactionID : 0;
if (petOwner->GetBotOwner()->GetFaction() == fac_orig)
{
//std::ostringstream msg;
//msg << "Something changed my faction (now " << me->GetFaction() << "), changing back to " << fac << "!";
//BotWhisper(msg.str().c_str());
me->SetFaction(fac);
uint32 fac = (!IAmFree() && me->GetMap()->IsBattleArena()) ? FACTION_MONSTER : fac_orig;
if (me->GetFaction() != fac)
me->SetFaction(fac);
}
//Visibility
if (!me->IsVisible() && petOwner->GetBotOwner()->IsVisible())
Expand Down
86 changes: 86 additions & 0 deletions src/server/game/Battlegrounds/Arena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,25 @@ void Arena::AddPlayer(Player* player)
UpdateArenaWorldState();
}

//npcbot
void Arena::AddBot(Creature* bot)
{
ASSERT(bot->IsNPCBot() && !bot->IsFreeBot());

bool const isInBattleground = IsPlayerInBattleground(bot->GetGUID());
Battleground::AddBot(bot);

uint32 botteam = bot->GetBotOwner()->GetBGTeam();

if (!isInBattleground)
BotScores[bot->GetEntry()] = new ArenaScore(bot->GetGUID(), botteam);

//No flags - handled by AI

UpdateArenaWorldState();
}
//end npcbot

void Arena::RemovePlayer(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*team*/)
{
if (GetStatus() == STATUS_WAIT_LEAVE)
Expand All @@ -105,6 +124,17 @@ void Arena::RemovePlayer(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*team*
CheckWinConditions();
}

//npcbot
void Arena::RemoveBot(ObjectGuid /*guid*/)
{
if (GetStatus() == STATUS_WAIT_LEAVE)
return;

UpdateArenaWorldState();
CheckWinConditions();
}
//end npcbot

void Arena::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
{
packet.Worldstates.emplace_back(ARENA_WORLD_STATE_ALIVE_PLAYERS_GREEN, GetAlivePlayersCountByTeam(HORDE));
Expand All @@ -128,6 +158,33 @@ void Arena::HandleKillPlayer(Player* player, Player* killer)
CheckWinConditions();
}

//npcbot
void Arena::HandleBotKillPlayer(Creature* killer, Player* victim)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
Battleground::HandleBotKillPlayer(killer, victim);
UpdateArenaWorldState();
CheckWinConditions();
}
void Arena::HandleBotKillBot(Creature* killer, Creature* victim)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
Battleground::HandleBotKillBot(killer, victim);
UpdateArenaWorldState();
CheckWinConditions();
}
void Arena::HandlePlayerKillBot(Creature* victim, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
Battleground::HandlePlayerKillBot(victim, killer);
UpdateArenaWorldState();
CheckWinConditions();
}
//end npcbot

void Arena::RemovePlayerAtLeave(ObjectGuid guid, bool transport, bool sendPacket)
{
if (isRated() && GetStatus() == STATUS_IN_PROGRESS)
Expand Down Expand Up @@ -156,6 +213,35 @@ void Arena::RemovePlayerAtLeave(ObjectGuid guid, bool transport, bool sendPacket
Battleground::RemovePlayerAtLeave(guid, transport, sendPacket);
}

//npcbot
void Arena::RemoveBotAtLeave(ObjectGuid guid)
{
//if (isRated() && GetStatus() == STATUS_IN_PROGRESS)
//{
// BattlegroundBotMap::const_iterator itr = m_Bots.find(guid);
// if (itr != m_Bots.end()) // check if the player was a participant of the match, or only entered through gm command (appear)
// {
// // if the player was a match participant, calculate rating
// uint32 team = itr->second.Team;

// ArenaTeam* winnerArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team)));
// ArenaTeam* loserArenaTeam = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(team));

// // left a rated match while the encounter was in progress, consider as loser
// if (winnerArenaTeam && loserArenaTeam && winnerArenaTeam != loserArenaTeam)
// {
// if (Player* player = _GetPlayer(itr->first, itr->second.OfflineRemoveTime != 0, "Arena::RemovePlayerAtLeave"))
// loserArenaTeam->MemberLost(player, GetArenaMatchmakerRating(GetOtherTeam(team)));
// else
// loserArenaTeam->OfflineMemberLost(guid, GetArenaMatchmakerRating(GetOtherTeam(team)));
// }
// }
//}

Battleground::RemoveBotAtLeave(guid);
}
//end npcbot

void Arena::CheckWinConditions()
{
if (!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
Expand Down
9 changes: 9 additions & 0 deletions src/server/game/Battlegrounds/Arena.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ class TC_GAME_API Arena : public Battleground
void AddPlayer(Player* player) override;
void RemovePlayer(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*team*/) override;

//npcbot
void AddBot(Creature* bot) override;
void RemoveBotAtLeave(ObjectGuid guid) override;
void RemoveBot(ObjectGuid /*guid*/) override;
void HandleBotKillPlayer(Creature* killer, Player* victim) override;
void HandleBotKillBot(Creature* killer, Creature* victim) override;
void HandlePlayerKillBot(Creature* victim, Player* killer) override;
//end npcbot

void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
void UpdateArenaWorldState();

Expand Down
2 changes: 1 addition & 1 deletion src/server/game/Battlegrounds/Battleground.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,7 @@ void Battleground::AddPlayer(Player* player)
void Battleground::AddBot(Creature* bot)
{
ObjectGuid guid = bot->GetGUID();
uint32 team = (BotDataMgr::GetTeamIdForFaction(bot->GetFaction()) == TEAM_ALLIANCE) ? ALLIANCE : HORDE;
uint32 team = !bot->IsFreeBot() ? bot->GetBotOwner()->GetBGTeam() : (BotDataMgr::GetTeamIdForFaction(bot->GetFaction()) == TEAM_ALLIANCE) ? ALLIANCE : HORDE;

// Add to list/maps
BattlegroundBot bb;
Expand Down
5 changes: 5 additions & 0 deletions src/server/game/Entities/Creature/Creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,11 @@ void Creature::SetLootRecipient(Unit* unit, bool withGroup)
else
m_lootRecipientGroup = ObjectGuid::Empty;

//npcbot: prevent visual tap on owned bots
if (IsNPCBotOrPet() && !IsFreeBot())
return;
//end npcbot

SetDynamicFlag(UNIT_DYNFLAG_TAPPED);
}

Expand Down
8 changes: 8 additions & 0 deletions src/server/game/Groups/Group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2410,6 +2410,14 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
return ERR_BATTLEGROUND_JOIN_FAILED;
}

//npcbot
for (GroupBotReference* bitr = GetFirstBotMember(); bitr != nullptr; bitr = bitr->next(), ++memberscount)
{
if (!bitr->GetSource())
return ERR_BATTLEGROUND_JOIN_FAILED;
}
//end npcbot

// only check for MinPlayerCount since MinPlayerCount == MaxPlayerCount for arenas...
if (bgOrTemplate->isArena() && memberscount != MinPlayerCount)
return ERR_ARENA_TEAM_PARTY_SIZE;
Expand Down
Loading

0 comments on commit 392ec0f

Please sign in to comment.