From ef14de98ea0c870f3a4ab349144e1bd836ac535f Mon Sep 17 00:00:00 2001 From: BlaMacfly <165155133+BlaMacfly@users.noreply.github.com> Date: Mon, 7 Sep 2026 23:48:18 +0200 Subject: [PATCH] Mercenaires : verifier l arrivee du mercenaire, et insister Signale en jeu : sur une escorte de quatre, un compagnon restait a l autre bout de la carte pour toute la duree du contrat. L ordre de rappel -- ProcessBotCommand("!summon"), ou TeleportToPoint quand un portail est connu -- partait une seule fois, et le contrat le tenait aussitot pour honore : summonPending passait a false sans que rien ne verifie que le mercenaire avait bouge. Un ordre perdu, et le bot restait a la position ou il s etait connecte. Le contrat retient maintenant ses tentatives et verifie l arrivee au point de rendez-vous -- le portail s il y en a un, l employeur sinon. Tant que le mercenaire n y est pas, l ordre est renouvele, jusqu a quatre fois, avec trois secondes entre deux verifications : un teleport de bot se joue en trois echanges et conclure au tick suivant reviendrait a le declarer perdu alors qu il est en route. Passe ce delai, on cesse d insister et on le dit au joueur, plutot que de le laisser croire son groupe au complet. Repare aussi le message de journal du recrutement offert, dont le format avait ete abime lors de sa pose. Co-Authored-By: Claude Opus 5 --- src/server/game/Mercenary/MercenaryMgr.cpp | 44 +++++++++++++++++++--- src/server/game/Mercenary/MercenaryMgr.h | 21 ++++++++++- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/server/game/Mercenary/MercenaryMgr.cpp b/src/server/game/Mercenary/MercenaryMgr.cpp index 63c616a..5075e4f 100644 --- a/src/server/game/Mercenary/MercenaryMgr.cpp +++ b/src/server/game/Mercenary/MercenaryMgr.cpp @@ -460,8 +460,9 @@ MercenaryResult MercenaryMgr::Summon(Player* owner, uint8 role, Creature* portal } m_contracts.push_back(contract); - TC_LOG_INFO("server.worldserver", freeOfCharge ? "Mercenaires: %s recoit gratuitement un %3 (compte bot %4), cout %2 po non preleve." : "Mercenaires: %s a paye %u po pour un %s (compte bot %u).", - owner->GetName().c_str(), GetCostGold(), GetRoleName(role), accountId); + TC_LOG_INFO("server.worldserver", "Mercenaires: %s engage un %s (compte bot %u) -- %s.", + owner->GetName().c_str(), GetRoleName(role), accountId, + freeOfCharge ? "recrutement offert" : "100 po preleves"); return MERC_OK; } @@ -657,7 +658,34 @@ void MercenaryMgr::Update(uint32 diff) // le mercenaire a son ancienne place aux yeux de tout le monde. if (it->summonPending) { - if (BotGroupAI* groupAI = dynamic_cast(bot->GetAI())) + // Est-il arrive ? Le point de rendez-vous est le portail quand + // il y en a un, l employeur sinon. + bool arrive = false; + if (it->hasPortal) + arrive = bot->GetMapId() == it->portalMap + && bot->GetExactDist2d(it->portalPos.GetPositionX(), + it->portalPos.GetPositionY()) < MERCENARY_ARRIVAL_RANGE; + else + arrive = bot->GetMapId() == owner->GetMapId() + && bot->GetExactDist2d(owner) < MERCENARY_ARRIVAL_RANGE; + + if (arrive) + it->summonPending = false; + else if (it->summonCheckTimer > 0) + --it->summonCheckTimer; + else if (it->summonAttempts >= MERCENARY_SUMMON_RETRIES) + { + // On cesse d insister : mieux vaut un mercenaire annonce + // perdu qu un mercenaire qu on croit present. + it->summonPending = false; + ChatHandler(owner->GetSession()).PSendSysMessage( + "|cffff4444[Portail]|r %s n'a pas pu vous rejoindre.", bot->GetName().c_str()); + TC_LOG_ERROR("server.worldserver", + "Mercenaires: %s n'a pas rejoint %s apres %u rappels (carte %u).", + bot->GetName().c_str(), owner->GetName().c_str(), + uint32(it->summonAttempts), bot->GetMapId()); + } + else if (BotGroupAI* groupAI = dynamic_cast(bot->GetAI())) { // Repli : sans portail connu, ou si l armement immediat a // echoue, le mercenaire rejoint simplement son employeur. @@ -665,7 +693,9 @@ void MercenaryMgr::Update(uint32 diff) groupAI->TeleportToPoint(it->portalMap, BuildPortalExit(it->portalPos, bot)); else groupAI->ProcessBotCommand(owner, "!summon"); - it->summonPending = false; + + ++it->summonAttempts; + it->summonCheckTimer = MERCENARY_SUMMON_RECHECK; } } @@ -748,7 +778,11 @@ void MercenaryMgr::Update(uint32 diff) if (BotGroupAI* groupAI = dynamic_cast(bot->GetAI())) { groupAI->TeleportToPoint(it->portalMap, BuildPortalExit(it->portalPos, bot)); - it->summonPending = false; + // L ordre est parti, mais rien ne dit encore qu il aboutira : + // on le compte comme une premiere tentative et la verification + // d arrivee prend le relais au tick suivant. + it->summonAttempts = 1; + it->summonCheckTimer = MERCENARY_SUMMON_RECHECK; } } diff --git a/src/server/game/Mercenary/MercenaryMgr.h b/src/server/game/Mercenary/MercenaryMgr.h index e33b3a2..e942517 100644 --- a/src/server/game/Mercenary/MercenaryMgr.h +++ b/src/server/game/Mercenary/MercenaryMgr.h @@ -40,6 +40,18 @@ class Player; #define MERCENARY_GROUP_SIZE 5 #define MERCENARY_HARD_CAP (MERCENARY_GROUP_SIZE - 1) #define MERCENARY_SUMMON_TIMEOUT 60 // secondes avant abandon + remboursement + +// SIGNALE EN JEU : « Semid n est meme pas vers moi, elle est a l autre bout de +// la map ». L ordre de rappel partait une seule fois et le contrat le tenait +// aussitot pour honore. Quand il se perdait -- IA pas encore prete, teleport +// deja en cours, changement de carte -- le mercenaire restait a sa derniere +// position enregistree pour toute la duree du contrat. +// +// On verifie desormais l arrivee, et on renouvelle l ordre tant qu elle ne +// vient pas. +#define MERCENARY_ARRIVAL_RANGE 80.0f // distance au-dela de laquelle il n est pas arrive +#define MERCENARY_SUMMON_RETRIES 4 // ordres de rappel au maximum +#define MERCENARY_SUMMON_RECHECK 3 // secondes entre deux verifications #define MERCENARY_COPPER_PER_GOLD 10000 enum MercenaryStage @@ -66,7 +78,8 @@ enum MercenaryResult struct MercenaryContract { MercenaryContract() : accountId(0), role(0), stage(MERC_STAGE_SUMMONING), waitSeconds(0), - pendingRelease(false), summonPending(false), hasPortal(false), portalMap(0) { } + pendingRelease(false), summonPending(false), summonAttempts(0), + summonCheckTimer(0), hasPortal(false), portalMap(0) { } uint32 accountId; // compte bot reserve ObjectGuid ownerGuid; // joueur qui a paye @@ -84,6 +97,12 @@ struct MercenaryContract // groupe aura reconnu son maitre. bool summonPending; + // Ordres de rappel deja emis, et delai avant de reverifier l arrivee. Un + // teleport de bot se joue en trois echanges : reverifier au tick suivant + // conclurait a un echec alors qu il est simplement en cours de route. + uint8 summonAttempts; + uint32 summonCheckTimer; + // Le portail d ou part l invocation : le mercenaire doit en sortir, pas // se materialiser aux pieds de son employeur reste en retrait. bool hasPortal;