PlayerBot : ordres stop et summon operants, rotation des mercenaires
Trois defauts distincts, tous verifies en jeu par sondes temporaires puis par comparaison des positions en base. 1. L ordre « stop » n arretait rien. Le suivi est un generateur MoveFollow pose sur le MotionMaster ; ClearMovement() se contente d appeler StopMoving() et le generateur, toujours en tete de pile, relançait la poursuite au tick suivant. ProcessStopCommand vide desormais la pile de mouvement. 2. Le teleport d un bot aboutissait cote serveur - positions identiques en base apres un « summon » - mais les clients continuaient de l afficher a son ancienne place : l etape finale diffuse un paquet portant un opcode CLIENT (CMSG_MOVE_FALL_LAND) que les clients voisins ne savent pas lire. L objet est maintenant reconstruit chez les joueurs alentour, et le MotionMaster vide a chaque acquittement, comme le fait mod-playerbots dans HandleTeleportAck. 3. Cote module, l invocation posait un TeleportTo direct : meme cause, meme effet, le mercenaire semblait n arriver jamais au portail. Elle passe desormais par l ordre « summon » de l IA de groupe, au tick qui suit l entree dans le groupe - le temps que l IA reconnaisse son maitre. Enfin, FindCandidate retournait le premier compte bot eligible d une carte ordonnee par identifiant : c etait invariablement le meme mercenaire. Tous les candidats sont desormais collectes puis tires au sort, en ligne comme hors ligne, un seul personnage par compte pour ne pas biaiser le tirage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1043,6 +1043,20 @@ void BotAITeleport::Update(uint32 diff, BotBGAIMovement* pMovement)
|
||||
me->SendMessageToSet(&data, me);
|
||||
me->CombatStop(true);
|
||||
me->SetSelection(ObjectGuid::Empty);
|
||||
// SylvaniaCore : le paquet diffuse ci-dessus porte un opcode CLIENT
|
||||
// (CMSG_MOVE_FALL_LAND), que les clients voisins ne savent pas lire.
|
||||
// Resultat : le bot avait bien change de place cote serveur - positions
|
||||
// identiques en base - mais restait affiche a son ancien emplacement,
|
||||
// jusqu au prochain passage hors puis dans le champ de vision. On force
|
||||
// donc la reconstruction de l objet chez les joueurs alentour.
|
||||
me->DestroyForNearbyPlayers();
|
||||
me->UpdateObjectVisibility(true);
|
||||
// mod-playerbots (PlayerbotAI::HandleTeleportAck) vide le MotionMaster
|
||||
// et arrete le mouvement a chaque acquittement de teleport. Sans cela,
|
||||
// le generateur de suivi encore en place fait repartir le bot depuis
|
||||
// l ancienne trajectoire.
|
||||
me->GetMotionMaster()->Clear(true);
|
||||
me->StopMoving();
|
||||
m_TeleportPositon.m_positionX = m_TeleportPositon.m_positionY = m_TeleportPositon.m_positionZ = 0;
|
||||
m_TeleportStep = 0;
|
||||
}
|
||||
|
||||
@@ -285,6 +285,14 @@ void BotGroupAI::ProcessStopCommand()
|
||||
me->SetSelection(ObjectGuid::Empty);
|
||||
m_SeduceTarget = ObjectGuid::Empty;
|
||||
m_StopFollow = true;
|
||||
// SylvaniaCore : sans ces trois lignes, l ordre restait sans effet visible.
|
||||
// Le suivi est un generateur MoveFollow pose sur le MotionMaster ;
|
||||
// ClearMovement() se contente d appeler StopMoving(), et le generateur,
|
||||
// toujours en tete de pile, relance la poursuite au tick suivant. Il faut
|
||||
// vider la pile de mouvement pour que le mercenaire se fige vraiment.
|
||||
m_Movement->ClearMovement();
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->StopMoving();
|
||||
}
|
||||
|
||||
void BotGroupAI::ProcessSetting()
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "MercenaryMgr.h"
|
||||
#include "BotGroupAI.h"
|
||||
#include "CapitalSiegeMgr.h"
|
||||
#include "Chat.h"
|
||||
#include "Config.h"
|
||||
@@ -161,6 +162,8 @@ bool MercenaryMgr::IsAccountHired(uint32 accountId) const
|
||||
bool MercenaryMgr::FindCandidate(Player* owner, uint8 role, uint32& accountId, uint64& charGuid, bool& alreadyOnline) const
|
||||
{
|
||||
SessionMap const& sessions = sWorld->GetAllSessions();
|
||||
std::vector<uint32> onlineCandidates;
|
||||
std::vector<std::pair<uint32, uint64> > offlineCandidates;
|
||||
|
||||
for (SessionMap::const_iterator it = sessions.begin(); it != sessions.end(); ++it)
|
||||
{
|
||||
@@ -194,7 +197,15 @@ bool MercenaryMgr::FindCandidate(Player* owner, uint8 role, uint32& accountId, u
|
||||
if (FindSpecIndexForRole(bot->getClass(), role) < 0)
|
||||
continue;
|
||||
|
||||
accountId = session->GetAccountId();
|
||||
onlineCandidates.push_back(session->GetAccountId());
|
||||
}
|
||||
|
||||
// Tirage au sort parmi TOUS les candidats, et non premier trouve : la carte
|
||||
// des sessions est ordonnee par identifiant de compte, si bien qu un choix
|
||||
// sequentiel ramenait invariablement le meme mercenaire.
|
||||
if (!onlineCandidates.empty())
|
||||
{
|
||||
accountId = onlineCandidates[urand(0, uint32(onlineCandidates.size()) - 1)];
|
||||
charGuid = 0;
|
||||
alreadyOnline = true;
|
||||
return true;
|
||||
@@ -235,13 +246,21 @@ bool MercenaryMgr::FindCandidate(Player* owner, uint8 role, uint32& accountId, u
|
||||
if (FindSpecIndexForRole(uint8(charInfo.profession), role) < 0)
|
||||
continue;
|
||||
|
||||
accountId = session->GetAccountId();
|
||||
charGuid = charInfo.guid;
|
||||
alreadyOnline = false;
|
||||
return true;
|
||||
offlineCandidates.push_back(std::make_pair(session->GetAccountId(), charInfo.guid));
|
||||
break; // un seul personnage retenu par compte
|
||||
}
|
||||
}
|
||||
|
||||
if (!offlineCandidates.empty())
|
||||
{
|
||||
std::pair<uint32, uint64> const& picked =
|
||||
offlineCandidates[urand(0, uint32(offlineCandidates.size()) - 1)];
|
||||
accountId = picked.first;
|
||||
charGuid = picked.second;
|
||||
alreadyOnline = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -518,6 +537,22 @@ void MercenaryMgr::Update(uint32 diff)
|
||||
ReleaseBot(contract);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Materialisation aupres de l employeur, au premier tick qui suit
|
||||
// l entree dans le groupe. On passe par l ordre « summon » de l IA
|
||||
// plutot que par un TeleportTo direct : un bot n a pas de client
|
||||
// pour accuser reception du teleport, c est BotAITeleport qui
|
||||
// simule cet echange en trois etapes. Un TeleportTo pose ici laisse
|
||||
// le mercenaire a son ancienne place aux yeux de tout le monde.
|
||||
if (it->summonPending)
|
||||
{
|
||||
if (BotGroupAI* groupAI = dynamic_cast<BotGroupAI*>(bot->GetAI()))
|
||||
{
|
||||
groupAI->ProcessBotCommand(owner, "summon");
|
||||
it->summonPending = false;
|
||||
}
|
||||
}
|
||||
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
@@ -581,16 +616,13 @@ void MercenaryMgr::Update(uint32 diff)
|
||||
|
||||
it->botGuid = bot->GetGUID();
|
||||
it->stage = MERC_STAGE_ACTIVE;
|
||||
// Le mercenaire doit encore se materialiser aupres de son employeur :
|
||||
// c est fait au tick suivant, une fois que l IA de groupe aura reconnu
|
||||
// son maitre. Voir la branche MERC_STAGE_ACTIVE.
|
||||
it->summonPending = true;
|
||||
|
||||
PlayerBotMgr::SwitchPlayerBotAI(bot, PlayerBotAIType::PBAIT_GROUP, true);
|
||||
|
||||
// Le mercenaire se materialise aupres de son employeur. L ajout au
|
||||
// groupe precede volontairement le teleport : c est ce qui autorise
|
||||
// l entree dans l instance ou se trouve deja le joueur.
|
||||
float x, y, z;
|
||||
owner->GetClosePoint(x, y, z, 2.0f, 3.0f);
|
||||
bot->TeleportTo(owner->GetMapId(), x, y, z, owner->GetOrientation());
|
||||
|
||||
ChatHandler(owner->GetSession()).PSendSysMessage(
|
||||
"|cff00ff00[Portail]|r %s, %s mercenaire, répond à votre appel.",
|
||||
bot->GetName().c_str(), GetRoleName(it->role));
|
||||
|
||||
@@ -64,7 +64,7 @@ enum MercenaryResult
|
||||
struct MercenaryContract
|
||||
{
|
||||
MercenaryContract() : accountId(0), role(0), stage(MERC_STAGE_SUMMONING), waitSeconds(0),
|
||||
pendingRelease(false) { }
|
||||
pendingRelease(false), summonPending(false) { }
|
||||
|
||||
uint32 accountId; // compte bot reserve
|
||||
ObjectGuid ownerGuid; // joueur qui a paye
|
||||
@@ -76,6 +76,11 @@ struct MercenaryContract
|
||||
// Contrat rompu par un hook de groupe du core, mais dont la liberation est
|
||||
// differee au prochain Update() : voir MercenaryMgr::OnPlayerLeftGroup().
|
||||
bool pendingRelease;
|
||||
|
||||
// Le mercenaire est entre dans le groupe mais n a pas encore ete rappele
|
||||
// aupres de son employeur : l ordre part au tick suivant, quand l IA de
|
||||
// groupe aura reconnu son maitre.
|
||||
bool summonPending;
|
||||
};
|
||||
|
||||
class TC_GAME_API MercenaryMgr
|
||||
|
||||
Reference in New Issue
Block a user