From 8a46e5b08de7c89934062ad146ecf472c0ffad59 Mon Sep 17 00:00:00 2001 From: SylvaniaCore deploy Date: Sun, 16 Aug 2026 13:20:01 +0200 Subject: [PATCH] Bots de groupe : rehabillage a chaque montee de niveau MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seuls les talents et les sorts suivaient la montee de niveau d un bot (OnLevelupToBotAI : ReupdateTalents + LearnSpells). L equipement, lui, n etait pose qu une fois, au re-level initial : un mercenaire embauche au niveau 20 et monte a 25 gardait son stuff de niveau 20 pour tout le contrat et devenait de plus en plus fragile. Nouvelle methode PlayerBotSetting::RefreshEquipment() : reprend le seul bloc equipement du re-level complet -- UnequipFromAll, CheckInventroy, AddEquipFromAll, UpequipFromAll, SupplementOtherItems -- puis UpdateAllStats et SaveToDB. On ne repasse volontairement ni par ResetTalents ni par ActivateSpecialization : la reattribution de specialisation en cours de partie est le chemin des crashs connus dans Unit::GetAPMultiplier. ProcessDelayLevelup renvoie desormais false tant que le bot est en combat : le schedule reste en tete de file et sera retente au tick suivant, plutot que de desarmer le bot en pleine bagarre. RefreshEquipment reverifie de son cote. Ce commit emporte aussi ActivateSpecialization (PlayerBotSetting), ecrit lors d une session precedente, deployé depuis le 15/08 mais jamais commité. Co-Authored-By: Claude Opus 5 --- src/server/game/Entities/Player/Player.cpp | 4 ++ .../game/PlayerBot/PlayerBotSetting.cpp | 64 ++++++++++++++++++- src/server/game/PlayerBot/PlayerBotSetting.h | 2 + src/server/game/Server/PlayerBotSession.cpp | 5 ++ 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 36dc3f8..9ef78ef 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -492,6 +492,10 @@ void Player::OnLevelupToBotAI() { uint32 type = ReupdateTalents(); m_PlayerBotSetting->LearnSpells(); + // Seuls les talents et les sorts suivaient la montee de niveau : le + // bot gardait pour tout le contrat l equipement recu a l embauche et + // devenait de plus en plus fragile. + m_PlayerBotSetting->RefreshEquipment(); pAI->OnLevelUp(type); } } diff --git a/src/server/game/PlayerBot/PlayerBotSetting.cpp b/src/server/game/PlayerBot/PlayerBotSetting.cpp index 59ece1a..5687851 100644 --- a/src/server/game/PlayerBot/PlayerBotSetting.cpp +++ b/src/server/game/PlayerBot/PlayerBotSetting.cpp @@ -1742,7 +1742,7 @@ bool PlayerBotSetting::ResetPlayerToLevel(uint32 level, uint32 talent, bool tena m_Player->GiveLevel(level); m_Player->SetUInt32Value(PLAYER_XP, 0); } - m_ResetStep = 1; + m_ResetStep = 0; m_Finish = false; m_TenacitySetting = tenacity; return true; @@ -1758,6 +1758,32 @@ void PlayerBotSetting::SupplementAmmo() } +// Rehabille le bot a son niveau courant. +// +// C est exactement le bloc equipement du re-level complet -- les etapes 6 a 10 +// de UpdateReset() -- isole pour pouvoir etre rejoue a chaque montee de niveau. +// On ne repasse volontairement NI par ResetTalents NI par ActivateSpecialization : +// la reattribution de specialisation en cours de partie est le chemin des crashs +// connus de PlayerBotSetting, et les talents comme les sorts sont deja tenus a +// jour par OnLevelupToBotAI(). +// +// L ordre compte : AddEquipFromAll() remplit m_NeedEquips, UpequipFromAll() le +// consomme et le vide. +void PlayerBotSetting::RefreshEquipment() +{ + if (!m_Player || !m_Player->IsInWorld() || m_Player->IsInCombat()) + return; + + UnequipFromAll(); + CheckInventroy(); + AddEquipFromAll(); + UpequipFromAll(); + SupplementOtherItems(); + + m_Player->UpdateAllStats(); + m_Player->SaveToDB(); +} + void PlayerBotSetting::UpdateReset() { if (m_Finish) @@ -1767,6 +1793,13 @@ void PlayerBotSetting::UpdateReset() m_Player->CombatStop(true); switch (m_ResetStep) { + case 0: + // Sur son propre tick, avant l effacement des talents : changer de + // specialisation pendant que les stats et les auras sont recalculees + // est precisement ce qui faisait exploser la pile. + ActivateSpecialization(); + ++m_ResetStep; + break; case 1: m_Player->ResetTalents(true); ++m_ResetStep; @@ -1839,6 +1872,35 @@ void PlayerBotSetting::UpdateReset() m_TenacitySetting = false; } +// Bascule le bot sur la specialisation demandee par le re-level, en passant par +// le chemin officiel du core. Une version precedente ecrivait +// PLAYER_FIELD_CURRENT_SPEC_ID a la main en plein re-level et provoquait un +// debordement de pile : ActivateTalentGroup fait le travail complet, y compris +// InitTalentForLevel, les boutons d action, la puissance et les auras de forme. +void PlayerBotSetting::ActivateSpecialization() +{ + if (!m_Player) + return; + + // 3 signifie garder la specialisation du personnage : rien a faire. + if (m_ActiveTalentType > 2) + return; + + uint8 const playerClass = m_Player->getClass(); + for (uint32 i = 0; i < sChrSpecializationStore.GetNumRows(); ++i) + { + ChrSpecializationEntry const* spec = sChrSpecializationStore.LookupEntry(i); + if (!spec || spec->ClassID != int8(playerClass) || spec->IsPetSpecialization()) + continue; + if (uint32(spec->OrderIndex) != m_ActiveTalentType) + continue; + + // ActivateTalentGroup ne fait rien si la specialisation est deja active. + m_Player->ActivateTalentGroup(spec); + return; + } +} + void PlayerBotSetting::LearnTalents() { // SylvaniaCore : cette fonction etait un corps vide alors que l etape diff --git a/src/server/game/PlayerBot/PlayerBotSetting.h b/src/server/game/PlayerBot/PlayerBotSetting.h index e244db0..b1fc255 100644 --- a/src/server/game/PlayerBot/PlayerBotSetting.h +++ b/src/server/game/PlayerBot/PlayerBotSetting.h @@ -120,7 +120,9 @@ public: uint32 SwitchPlayerTalent(uint32 talent); void SupplementAmmo(); void UpdateReset(); + void RefreshEquipment(); void LearnSpells(); + void ActivateSpecialization(); void LearnTalents(); bool EquipItem(Item* pItem); diff --git a/src/server/game/Server/PlayerBotSession.cpp b/src/server/game/Server/PlayerBotSession.cpp index a00b27d..01c21af 100644 --- a/src/server/game/Server/PlayerBotSession.cpp +++ b/src/server/game/Server/PlayerBotSession.cpp @@ -704,6 +704,11 @@ bool PlayerBotSession::ProcessDelayLevelup(BotGlobleSchedule& schedule) ClearAllSchedule(); return false; } + // Le rehabillage retire puis rend tout l equipement : hors de question de + // desarmer le bot en pleine bagarre. Renvoyer false laisse le schedule en + // tete de file, il sera retente au tick suivant. + if (player->IsInCombat()) + return false; player->OnLevelupToBotAI(); return true; }