Playerbots : la formation de groupe n'a jamais fonctionne

SIGNALE EN JEU : « les bots restent les uns sur les autres, il n existe
pas des commandes de strategie de placement ? ». Le systeme existait
bien -- il etait casse.

GetPositionFromGroup calcule correctement une place propre a chaque
membre : un angle reparti sur le cercle, a quatre metres du meneur. Mais
son resultat n etait jamais renvoye :

    Position resultPos(distX, distY, distZ, ...);   // calculee
    Position pos;                                    // vide
    pCenterPlayer->GetFirstCollisionPosition(...);   // resultat jete
    return pos;                                      // (0,0,0)

GetFirstCollisionPosition REND une Position ; son retour etait ignore et
l on renvoyait une variable jamais renseignee. La fonction rendait donc
l origine du monde a tous ses appelants -- BotGroupAI comme BotAITool.

Par-dessus, les deux MoveFollow de BotGroupAI employaient la meme
distance et le meme angle pour tout le monde : un metre devant le
meneur, a son orientation. Meme reparee, la formation aurait ete ecrasee
deux lignes plus loin. Chaque bot y prend desormais l angle de son rang
dans le groupe, a trois ou quatre metres selon l effectif.

Le defaut ne touchait pas que le scenario : il vaut pour tous les
playerbots du serveur, champs de bataille et donjons compris.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
BlaMacfly
2026-09-05 09:51:54 +02:00
parent bd22c62631
commit ba0caeece2
2 changed files with 51 additions and 4 deletions
+23 -2
View File
@@ -502,9 +502,30 @@ Position BotUtility::GetPositionFromGroup(Player* pCenterPlayer, ObjectGuid self
float distZ = centerPos.GetPositionZ(); float distZ = centerPos.GetPositionZ();
if (!pCenterPlayer->IsFlying()) if (!pCenterPlayer->IsFlying())
distZ = pCenterPlayer->GetMap()->GetHeight(pCenterPlayer->GetPhaseShift(), distX, distY, distZ); distZ = pCenterPlayer->GetMap()->GetHeight(pCenterPlayer->GetPhaseShift(), distX, distY, distZ);
// =================================================================
// SylvaniaCore : la position calculee etait JETEE.
//
// SIGNALE EN JEU : « les bots restent les uns sur les autres ».
//
// Tout le calcul ci-dessus est juste -- un angle propre a chaque
// membre, reparti sur le cercle, a quatre metres du meneur. Mais le
// resultat n'etait jamais renvoye :
//
// Position resultPos(distX, distY, distZ, ...); // calculee
// Position pos; // vide
// pCenterPlayer->GetFirstCollisionPosition(...); // jete
// return pos; // (0,0,0)
//
// GetFirstCollisionPosition REND une Position ; son resultat etait
// ignore, et l'on renvoyait une variable jamais renseignee. La
// fonction rendait donc l'origine du monde a tous les appelants, et
// la formation n'a jamais fonctionne -- nulle part, pas seulement
// dans ce scenario.
// =================================================================
Position resultPos(distX, distY, distZ, pCenterPlayer->GetOrientation()); Position resultPos(distX, distY, distZ, pCenterPlayer->GetOrientation());
Position pos; Position pos = pCenterPlayer->GetFirstCollisionPosition(
pCenterPlayer->GetFirstCollisionPosition(pCenterPlayer->GetDistance(resultPos), pCenterPlayer->GetRelativeAngle(&resultPos)); pCenterPlayer->GetDistance(resultPos), pCenterPlayer->GetRelativeAngle(&resultPos));
pos.SetOrientation(pCenterPlayer->GetOrientation());
return pos; return pos;
} }
@@ -1528,18 +1528,44 @@ void BotGroupAI::ProcessFollowToMaster()
} }
Position targetPos = BotUtility::GetPositionFromGroup(m_MasterPlayer, me->GetGUID(), me->GetGroup()); Position targetPos = BotUtility::GetPositionFromGroup(m_MasterPlayer, me->GetGUID(), me->GetGroup());
m_Movement->MovementTo(targetPos.GetPositionX(), targetPos.GetPositionY(), targetPos.GetPositionZ(), 0); m_Movement->MovementTo(targetPos.GetPositionX(), targetPos.GetPositionY(), targetPos.GetPositionZ(), 0);
// =================================================================
// ANGLE PROPRE A CHAQUE MEMBRE.
//
// Les deux MoveFollow ci-dessous employaient la MEME distance et le
// MEME angle pour tout le monde -- un metre devant le meneur, a son
// orientation. Tous les bots convergeaient donc vers un point unique
// et se superposaient, quand bien meme GetPositionFromGroup leur
// avait calcule une place distincte deux lignes plus haut.
//
// On reprend l'angle de cette formation : chacun garde son secteur.
float suiviAngle = 0.0f;
float suiviDistance = 3.0f;
{
uint32 index = 0;
uint32 count = 0;
ObjectGuid monGuid = me->GetGUID();
if (me->GetGroup() && me->GetGroup()->GiveAtGroupPos(monGuid, index, count))
{
if (count > 1)
--count;
if (count)
suiviAngle = (float(M_PI) * 2.0f / float(count)) * float(index);
suiviDistance = (count > 3) ? 4.0f : 3.0f;
}
}
float distance = me->GetDistance(m_MasterPlayer->GetPosition()); float distance = me->GetDistance(m_MasterPlayer->GetPosition());
if (distance <= NEEDFLEE_CHECKRANGE && distance > 0.1f) if (distance <= NEEDFLEE_CHECKRANGE && distance > 0.1f)
{ {
me->GetMotionMaster()->Clear(); me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveFollow(m_MasterPlayer, 1.0f, m_MasterPlayer->GetOrientation()); me->GetMotionMaster()->MoveFollow(m_MasterPlayer, suiviDistance, suiviAngle);
return; return;
} }
if (me->IsWithinLOSInMap(m_MasterPlayer)) if (me->IsWithinLOSInMap(m_MasterPlayer))
{ {
me->GetMotionMaster()->Clear(); me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveFollow(m_MasterPlayer, 1.0f, m_MasterPlayer->GetOrientation()); me->GetMotionMaster()->MoveFollow(m_MasterPlayer, suiviDistance, suiviAngle);
} }
else else
m_Movement->MovementTo(m_MasterPlayer->GetPositionX(), m_MasterPlayer->GetPositionY(), m_MasterPlayer->GetPositionZ(), 1); m_Movement->MovementTo(m_MasterPlayer->GetPositionX(), m_MasterPlayer->GetPositionY(), m_MasterPlayer->GetPositionZ(), 1);