bots: accept party invitations regardless of level gap

The reset-aware level gate in BotPartyHandler rejected nearly every party
invitation on servers with resets, because it folded reset count into the level
scale (one reset ~= 400 points against a 500 cap). A veteran player inviting a
freshly generated bot was always over the limit, so the invitation was silently
declined. Remove the gate so a bot accepts any inviter who is alive and in the
world, matching OpenMU's own party action; the situational safeguards (shopping,
revenge, mini game, pending invite, human companion) stay in place.
This commit is contained in:
nolt
2026-07-28 16:34:17 +02:00
committed by Acentech Dev
parent 0ff0707212
commit ebf6958068
3 changed files with 22 additions and 32 deletions

View File

@@ -11,22 +11,13 @@ using MUnique.OpenMU.GameLogic.Offline;
/// <see cref="BotMuHelperSettings.AutoAcceptAnyone"/>): the invitation is accepted after a short
/// human-like delay, and the bot then follows the leader like any party member (see the follow logic
/// in <see cref="BotNavigator"/>) until it gets bored and politely leaves. Safeguards keep it
/// believable and abuse-free: no grouping across an absurd level gap, no acceptance while the bot is
/// on an errand (shopping trip) or has unfinished business (revenge), and the invitation is
/// re-validated when the delay has passed - the inviter may have joined another party or left.
/// believable and abuse-free: no acceptance while the bot is on an errand (shopping trip) or has
/// unfinished business (revenge), and the invitation is re-validated when the delay has passed - the
/// inviter may have joined another party or left. There is no level gate, matching OpenMU's own party
/// action: it is the player who invites, and the bot leaves again once it gets bored.
/// </summary>
internal static class BotPartyHandler
{
/// <summary>
/// The maximum difference of the reset-aware effective level (see
/// <see cref="BotResetHandler.GetEffectiveLevel"/>) between the bot and the inviter. Within one
/// reset worth of levels plus some slack, hunting together still makes sense for both; grouping a
/// fresh character with a 15-resets veteran would only be a power-leveling service. On servers
/// without the reset feature the plain levels always lie within this bound, matching OpenMU's own
/// party action, which has no level gate at all.
/// </summary>
private const int MaxEffectiveLevelGap = 500;
/// <summary>Lower bound of the human-like delay before the bot answers an invitation.</summary>
private static readonly TimeSpan MinAcceptDelay = TimeSpan.FromSeconds(2);
@@ -67,7 +58,7 @@ internal static class BotPartyHandler
return false;
}
if (!IsRequesterEligible(bot, requester))
if (!IsRequesterEligible(requester))
{
return false;
}
@@ -141,7 +132,7 @@ internal static class BotPartyHandler
{
// Re-validate: between the invitation and this answer, the bot may have joined a human's party
// and the inviter may have died, left the game or joined another party.
if (HasHumanCompanion(bot) || !IsRequesterEligible(bot, requester))
if (HasHumanCompanion(bot) || !IsRequesterEligible(requester))
{
bot.Logger.LogInformation("Bot '{Name}' dropped the party invitation of '{Requester}' - the situation changed.", bot.Name, requester.Name);
return;
@@ -209,14 +200,8 @@ internal static class BotPartyHandler
await party.KickMySelfAsync(bot).ConfigureAwait(false);
}
private static bool IsRequesterEligible(OfflinePlayer bot, Player requester)
private static bool IsRequesterEligible(Player requester)
{
if (!requester.IsAlive || requester.PlayerState.CurrentState != PlayerState.EnteredWorld)
{
return false;
}
var levelGap = Math.Abs(BotResetHandler.GetEffectiveLevel(bot) - BotResetHandler.GetEffectiveLevel(requester));
return levelGap <= MaxEffectiveLevelGap;
return requester.IsAlive && requester.PlayerState.CurrentState == PlayerState.EnteredWorld;
}
}