baseline: OpenMU upstream b5a0961 (fresh source)
This commit is contained in:
52
src/GameLogic/PlayerActions/Guild/GuildCreateAction.cs
Normal file
52
src/GameLogic/PlayerActions/Guild/GuildCreateAction.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// <copyright file="GuildCreateAction.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.PlayerActions.Guild;
|
||||
|
||||
using MUnique.OpenMU.GameLogic.Views.Guild;
|
||||
|
||||
/// <summary>
|
||||
/// Action to create a guild.
|
||||
/// </summary>
|
||||
public class GuildCreateAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates the guild.
|
||||
/// </summary>
|
||||
/// <param name="creator">The creator.</param>
|
||||
/// <param name="guildName">Name of the guild.</param>
|
||||
/// <param name="guildEmblem">The guild emblem.</param>
|
||||
public async ValueTask CreateGuildAsync(Player creator, string guildName, byte[] guildEmblem)
|
||||
{
|
||||
using var loggerScope = creator.Logger.BeginScope(this.GetType());
|
||||
if (creator.PlayerState.CurrentState != PlayerState.EnteredWorld)
|
||||
{
|
||||
creator.Logger.LogError($"Account {creator.Account?.LoginName} not in the right state, but {creator.PlayerState.CurrentState}.");
|
||||
return;
|
||||
}
|
||||
|
||||
var guildServer = (creator.GameContext as IGameServerContext)?.GuildServer;
|
||||
if (guildServer is null)
|
||||
{
|
||||
creator.Logger.LogError($"No guild server available");
|
||||
return;
|
||||
}
|
||||
|
||||
if (await guildServer.GuildExistsAsync(guildName).ConfigureAwait(false))
|
||||
{
|
||||
await creator.InvokeViewPlugInAsync<IShowGuildCreateResultPlugIn>(p => p.ShowGuildCreateResultAsync(GuildCreateErrorDetail.GuildAlreadyExist)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (await guildServer.CreateGuildAsync(guildName, creator.SelectedCharacter!.Name, creator.SelectedCharacter.Id, guildEmblem, ((IGameServerContext)creator.GameContext).Id).ConfigureAwait(false))
|
||||
{
|
||||
await creator.InvokeViewPlugInAsync<IShowGuildCreateResultPlugIn>(p => p.ShowGuildCreateResultAsync(GuildCreateErrorDetail.None)).ConfigureAwait(false);
|
||||
creator.Logger.LogInformation("Guild created: [{0}], Master: [{1}]", guildName, creator.SelectedCharacter.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
await creator.InvokeViewPlugInAsync<IShowGuildCreateResultPlugIn>(p => p.ShowGuildCreateResultAsync(GuildCreateErrorDetail.GuildAlreadyExist)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/GameLogic/PlayerActions/Guild/GuildInfoRequestAction.cs
Normal file
23
src/GameLogic/PlayerActions/Guild/GuildInfoRequestAction.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// <copyright file="GuildInfoRequestAction.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.PlayerActions.Guild;
|
||||
|
||||
using MUnique.OpenMU.GameLogic.Views.Guild;
|
||||
|
||||
/// <summary>
|
||||
/// Action to request the information (name, symbol) of a guild.
|
||||
/// </summary>
|
||||
public class GuildInfoRequestAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Requests the guild information.
|
||||
/// </summary>
|
||||
/// <param name="player">The player.</param>
|
||||
/// <param name="guildId">The guild identifier.</param>
|
||||
public async ValueTask RequestGuildInfoAsync(Player player, uint guildId)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IShowGuildInfoPlugIn>(p => p.ShowGuildInfoAsync(guildId)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
71
src/GameLogic/PlayerActions/Guild/GuildKickPlayerAction.cs
Normal file
71
src/GameLogic/PlayerActions/Guild/GuildKickPlayerAction.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
// <copyright file="GuildKickPlayerAction.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.PlayerActions.Guild;
|
||||
|
||||
using MUnique.OpenMU.GameLogic.Views;
|
||||
using MUnique.OpenMU.GameLogic.Views.Guild;
|
||||
using MUnique.OpenMU.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Action to kick a player out of a guild.
|
||||
/// </summary>
|
||||
public class GuildKickPlayerAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Kicks the player out of the guild.
|
||||
/// </summary>
|
||||
/// <param name="player">The player.</param>
|
||||
/// <param name="nickname">The nickname.</param>
|
||||
/// <param name="securityCode">The security code.</param>
|
||||
public async ValueTask KickPlayerAsync(Player player, string nickname, string securityCode)
|
||||
{
|
||||
using var loggerScope = player.Logger.BeginScope(this.GetType());
|
||||
if (player.PlayerState.CurrentState != PlayerState.EnteredWorld)
|
||||
{
|
||||
player.Logger.LogError($"Account {player.Account?.LoginName} not in the right state, but {player.PlayerState.CurrentState}.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.GuildStatus is null)
|
||||
{
|
||||
player.Logger.LogError($"Player {player} not in a guild.");
|
||||
return;
|
||||
}
|
||||
|
||||
var guildServer = (player.GameContext as IGameServerContext)?.GuildServer;
|
||||
if (guildServer is null)
|
||||
{
|
||||
player.Logger.LogWarning("No guild server available");
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.Account!.SecurityCode != null && player.Account.SecurityCode != securityCode)
|
||||
{
|
||||
await player.ShowLocalizedBlueMessageAsync(nameof(PlayerMessage.WrongSecurityCode)).ConfigureAwait(false);
|
||||
player.Logger.LogDebug("Wrong Security Code: [{0}] <> [{1}], Player: {2}", securityCode, player.Account.SecurityCode, player.SelectedCharacter?.Name);
|
||||
|
||||
await player.InvokeViewPlugInAsync<IGuildKickResultPlugIn>(p => p.GuildKickResultAsync(GuildKickSuccess.Failed)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var isKickingHimself = player.SelectedCharacter!.Name == nickname;
|
||||
if (!isKickingHimself && player.GuildStatus?.Position != GuildPosition.GuildMaster)
|
||||
{
|
||||
player.Logger.LogWarning("Suspicious kick request for player with name: {0} (player is not a guild master) to kick {1}, could be hack attempt.", player.Name, nickname);
|
||||
await player.InvokeViewPlugInAsync<IGuildKickResultPlugIn>(p => p.GuildKickResultAsync(GuildKickSuccess.FailedBecausePlayerIsNotGuildMaster)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isKickingHimself && player.GuildStatus?.Position == GuildPosition.GuildMaster)
|
||||
{
|
||||
var guildId = player.GuildStatus.GuildId;
|
||||
await player.InvokeViewPlugInAsync<IGuildKickResultPlugIn>(p => p.GuildKickResultAsync(GuildKickSuccess.GuildDisband)).ConfigureAwait(false);
|
||||
await guildServer.KickMemberAsync(guildId, nickname).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await guildServer.KickMemberAsync(player.GuildStatus!.GuildId, nickname).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
33
src/GameLogic/PlayerActions/Guild/GuildListRequestAction.cs
Normal file
33
src/GameLogic/PlayerActions/Guild/GuildListRequestAction.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
// <copyright file="GuildListRequestAction.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.PlayerActions.Guild;
|
||||
|
||||
using MUnique.OpenMU.GameLogic.Views.Guild;
|
||||
|
||||
/// <summary>
|
||||
/// Action to request the guild list.
|
||||
/// </summary>
|
||||
public class GuildListRequestAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Requests the guild list of the guild the player is currently part of.
|
||||
/// </summary>
|
||||
/// <param name="player">The player.</param>
|
||||
public async ValueTask RequestGuildListAsync(Player player)
|
||||
{
|
||||
if (player.GuildStatus is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: We may want to retrieve guild and guild members in one call, to avoid multiple calls. But for now, we can live with that.
|
||||
if ((player.GameContext as IGameServerContext)?.GuildServer is { } guildServer
|
||||
&& await guildServer.GetGuildAsync(player.GuildStatus.GuildId).ConfigureAwait(false) is { } guild)
|
||||
{
|
||||
var players = await guildServer.GetGuildListAsync(player.GuildStatus.GuildId).ConfigureAwait(false);
|
||||
await player.InvokeViewPlugInAsync<IShowGuildListPlugIn>(p => p.ShowGuildListAsync(players, guild)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/GameLogic/PlayerActions/Guild/GuildMasterAnswerAction.cs
Normal file
50
src/GameLogic/PlayerActions/Guild/GuildMasterAnswerAction.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
// <copyright file="GuildMasterAnswerAction.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.PlayerActions.Guild;
|
||||
|
||||
using MUnique.OpenMU.GameLogic.Views.Guild;
|
||||
|
||||
/// <summary>
|
||||
/// Action to answer the dialog of the guild master npc.
|
||||
/// </summary>
|
||||
public class GuildMasterAnswerAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of the answer.
|
||||
/// </summary>
|
||||
public enum Answer
|
||||
{
|
||||
/// <summary>
|
||||
/// Cancels the guild master npc dialog.
|
||||
/// </summary>
|
||||
Cancel = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The guild master npc dialog should be shown.
|
||||
/// </summary>
|
||||
ShowDialog = 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the answer.
|
||||
/// </summary>
|
||||
/// <param name="player">The player.</param>
|
||||
/// <param name="answer">The answer.</param>
|
||||
public async ValueTask ProcessAnswerAsync(Player player, Answer answer)
|
||||
{
|
||||
if (player.PlayerState.CurrentState == PlayerState.EnteredWorld && answer == Answer.ShowDialog)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IShowGuildCreationDialogPlugIn>(p => p.ShowGuildCreationDialogAsync()).ConfigureAwait(false);
|
||||
}
|
||||
else if (player.OpenedNpc?.Definition.NpcWindow == NpcWindow.GuildMaster && await player.PlayerState.TryAdvanceToAsync(PlayerState.EnteredWorld).ConfigureAwait(false))
|
||||
{
|
||||
player.OpenedNpc = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// nothing to do.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
// <copyright file="GuildRelationshipChangeAction.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.PlayerActions.Guild;
|
||||
|
||||
using MUnique.OpenMU.GameLogic.Attributes;
|
||||
using MUnique.OpenMU.GameLogic.Views;
|
||||
using MUnique.OpenMU.GameLogic.Views.Guild;
|
||||
using MUnique.OpenMU.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Action which handles guild relationship changes (alliance creation/removal and hostility).
|
||||
/// </summary>
|
||||
public class GuildRelationshipChangeAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles an incoming relationship change request from a guild master.
|
||||
/// Validates and forwards the request to the target guild master.
|
||||
/// </summary>
|
||||
/// <param name="player">The player requesting the relationship change.</param>
|
||||
/// <param name="targetPlayerId">The player id of the target guild master.</param>
|
||||
/// <param name="relationshipType">The type of relationship change (Alliance or Hostility).</param>
|
||||
/// <param name="requestType">The type of request (Join or Leave).</param>
|
||||
public async ValueTask RequestAsync(Player player, ushort targetPlayerId, GuildRelationshipType relationshipType, GuildRelationshipRequestType requestType)
|
||||
{
|
||||
var (success, (sourceGuildId, serverContext, sourceGuild)) = await this.CommonChecksAsync(player, targetPlayerId, relationshipType, requestType).ConfigureAwait(false);
|
||||
if (!success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the target player
|
||||
var targetPlayer = await player.GetObservingPlayerWithIdAsync(targetPlayerId).ConfigureAwait(false);
|
||||
if (targetPlayer?.GuildStatus is not { } targetGuildStatus
|
||||
|| await serverContext.GuildServer.GetGuildAsync(targetGuildStatus.GuildId).ConfigureAwait(false) is not { Name: not null } targetGuild)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.Failed, targetPlayerId)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetGuildStatus.Position != GuildPosition.GuildMaster)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.Failed, targetPlayerId)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (relationshipType == GuildRelationshipType.Hostility)
|
||||
{
|
||||
if (requestType == GuildRelationshipRequestType.Join
|
||||
&& (targetGuild.Hostility is not null || sourceGuild.Hostility is not null))
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.AlreadyInHostility, targetPlayerId)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestType == GuildRelationshipRequestType.Leave
|
||||
&& targetGuild.Hostility?.Name != sourceGuild.Name
|
||||
&& sourceGuild.Hostility?.Name != targetGuild.Name)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.HostileGuildDoesNotExist, targetPlayerId)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (relationshipType == GuildRelationshipType.Alliance
|
||||
&& requestType == GuildRelationshipRequestType.Join)
|
||||
{
|
||||
if (targetGuild.AllianceGuild is not null)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.AlreadyInAlliance, targetPlayerId)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceGuild.AllianceGuild is not null && sourceGuild.AllianceGuild != sourceGuild)
|
||||
{
|
||||
// Request is not done by the master of the alliance, but by the master of a sub-guild
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.NoAuthorization, targetPlayerId)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the maximum alliance size configured for this game version.
|
||||
// A value of 0 means no limit is configured (e.g. for game versions that pre-date alliances).
|
||||
var maxAllianceSize = (int)(player.Attributes?[Stats.MaximumAllianceSize] ?? 0);
|
||||
if (maxAllianceSize > 0)
|
||||
{
|
||||
var allianceGuilds = await serverContext.GuildServer.GetAllianceGuildsAsync(sourceGuildId).ConfigureAwait(false);
|
||||
|
||||
// Compute the size of the alliance after the target guild would be added.
|
||||
// When there is no alliance yet (count == 0), the source guild itself is the first
|
||||
// member, so the resulting alliance would have 2 guilds (source + target).
|
||||
var sizeAfterAdding = allianceGuilds.Count == 0 ? 2 : allianceGuilds.Count + 1;
|
||||
if (sizeAfterAdding > maxAllianceSize)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.MaximumNumberOfGuildsInAllianceReached, targetPlayerId)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store the pending request on the target player and ask for consent
|
||||
targetPlayer.PendingAllianceRequest = (player, relationshipType, requestType);
|
||||
await targetPlayer.InvokeViewPlugInAsync<IShowGuildRelationshipRequestPlugIn>(p => p.ShowRequestAsync(
|
||||
player,
|
||||
relationshipType,
|
||||
requestType)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles an incoming relationship leave request from a guild master.
|
||||
/// Validates the request and processes the leave action.
|
||||
/// </summary>
|
||||
/// <param name="player">The player requesting the relationship change.</param>
|
||||
/// <param name="targetGuildName">The name of the guild which should be removed. If <see langword="null"/>, then the own guild should be removed.</param>
|
||||
public async ValueTask RequestLeaveAllianceAsync(Player player, string? targetGuildName = null)
|
||||
{
|
||||
var (success, (sourceGuildId, serverContext, sourceGuild)) = await this.CommonChecksAsync(player, 0, GuildRelationshipType.Alliance, GuildRelationshipRequestType.Leave).ConfigureAwait(false);
|
||||
if (!success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var targetGuildId = sourceGuildId;
|
||||
var leaveWithOwnGuild = string.IsNullOrEmpty(targetGuildName) || sourceGuild.Name == targetGuildName;
|
||||
if (!leaveWithOwnGuild)
|
||||
{
|
||||
if (!await serverContext.GuildServer.IsAllianceMasterAsync(sourceGuildId).ConfigureAwait(false))
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(GuildRelationshipType.Alliance, GuildRelationshipRequestType.Leave, GuildRelationshipChangeResultType.NoAuthorization, null)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
targetGuildId = await serverContext.GuildServer.GetGuildIdByNameAsync(targetGuildName!).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var removeSuccess = await serverContext.GuildServer.RemoveAllianceAsync(targetGuildId).ConfigureAwait(false);
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowRemoveResultAsync(removeSuccess)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the response from the target guild master to an alliance request.
|
||||
/// </summary>
|
||||
/// <param name="player">The target guild master who is responding.</param>
|
||||
/// <param name="relationshipType">The type of relationship change (Alliance or Hostility).</param>
|
||||
/// <param name="requestType">The type of request (Join or Leave).</param>
|
||||
/// <param name="accepted">Whether the relationship change was accepted.</param>
|
||||
public async ValueTask ProcessResponseAsync(Player player, GuildRelationshipType relationshipType, GuildRelationshipRequestType requestType, bool accepted)
|
||||
{
|
||||
var pending = player.PendingAllianceRequest;
|
||||
var (requester, pendingRelationshipType, pendingRequestType) = pending;
|
||||
player.PendingAllianceRequest = default;
|
||||
if (pendingRelationshipType != relationshipType || pendingRequestType != requestType)
|
||||
{
|
||||
// No pending request or mismatch in the request details, ignore the response, leave with default state
|
||||
return;
|
||||
}
|
||||
|
||||
if (requester is null
|
||||
|| requester.GuildStatus is not { } requesterGuildStatus
|
||||
|| player.GuildStatus is not { } responderGuildStatus
|
||||
|| player.GameContext is not IGameServerContext serverContext)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var guildMasterId = player.GetId(requester);
|
||||
if (!accepted)
|
||||
{
|
||||
await requester.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.RequestCancelled, guildMasterId)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var res = pending switch
|
||||
{
|
||||
(_, GuildRelationshipType.Alliance, GuildRelationshipRequestType.Join) =>
|
||||
await serverContext.GuildServer.CreateAllianceAsync(requesterGuildStatus.GuildId, responderGuildStatus.GuildId).ConfigureAwait(false)
|
||||
switch
|
||||
{
|
||||
AllianceCreationResult.Success => GuildRelationshipChangeResultType.Success,
|
||||
AllianceCreationResult.MasterGuildNotFound or AllianceCreationResult.TargetGuildNotFound => GuildRelationshipChangeResultType.GuildNotFound,
|
||||
AllianceCreationResult.TargetGuildAlreadyInAlliance => GuildRelationshipChangeResultType.AlreadyInAlliance,
|
||||
AllianceCreationResult.MaximumAllianceSizeReached => GuildRelationshipChangeResultType.MaximumNumberOfGuildsInAllianceReached,
|
||||
_ => GuildRelationshipChangeResultType.Failed,
|
||||
},
|
||||
(_, GuildRelationshipType.Hostility, _) => await serverContext.GuildServer.SetHostilityAsync(requesterGuildStatus.GuildId, responderGuildStatus.GuildId, pendingRequestType == GuildRelationshipRequestType.Join).ConfigureAwait(false)
|
||||
? GuildRelationshipChangeResultType.Success
|
||||
: GuildRelationshipChangeResultType.Failed,
|
||||
_ => GuildRelationshipChangeResultType.Failed,
|
||||
};
|
||||
|
||||
await requester.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, res, guildMasterId)).ConfigureAwait(false);
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, res, guildMasterId)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async ValueTask<(bool Success, GuildData GuildData)> CommonChecksAsync(Player player, ushort? targetPlayerId, GuildRelationshipType relationshipType, GuildRelationshipRequestType requestType)
|
||||
{
|
||||
if (player.PendingAllianceRequest != default)
|
||||
{
|
||||
// There is already a pending request, so we cannot process another one at the moment. This can happen with multiple requests from different players.
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.RequestCancelled, targetPlayerId)).ConfigureAwait(false);
|
||||
return (false, null!);
|
||||
}
|
||||
|
||||
if (player.GuildStatus is not { } guildStatus
|
||||
|| player.GameContext is not IGameServerContext serverContext)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.Failed, targetPlayerId)).ConfigureAwait(false);
|
||||
return (false, null!);
|
||||
}
|
||||
|
||||
if (guildStatus.Position != GuildPosition.GuildMaster)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.NoAuthorization, targetPlayerId)).ConfigureAwait(false);
|
||||
return (false, null!);
|
||||
}
|
||||
|
||||
var sourceGuild = await serverContext.GuildServer.GetGuildAsync(guildStatus.GuildId).ConfigureAwait(false);
|
||||
if (sourceGuild is null)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildRelationshipChangeResultPlugIn>(p => p.ShowResultAsync(relationshipType, requestType, GuildRelationshipChangeResultType.GuildNotFound, targetPlayerId)).ConfigureAwait(false);
|
||||
return (false, null!);
|
||||
}
|
||||
|
||||
return (true, new(guildStatus.GuildId, serverContext, sourceGuild));
|
||||
}
|
||||
|
||||
private record GuildData(uint GuildId, IGameServerContext Context, Guild Guild);
|
||||
}
|
||||
51
src/GameLogic/PlayerActions/Guild/GuildRequestAction.cs
Normal file
51
src/GameLogic/PlayerActions/Guild/GuildRequestAction.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
// <copyright file="GuildRequestAction.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.PlayerActions.Guild;
|
||||
|
||||
using MUnique.OpenMU.GameLogic.Views.Guild;
|
||||
using MUnique.OpenMU.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Action to request guild membership from a guild master player.
|
||||
/// </summary>
|
||||
public class GuildRequestAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Requests the guild from the guild master player with the specified id.
|
||||
/// </summary>
|
||||
/// <param name="player">The player.</param>
|
||||
/// <param name="guildMasterId">The guild master identifier.</param>
|
||||
public async ValueTask RequestGuildAsync(Player player, ushort guildMasterId)
|
||||
{
|
||||
if (player.Level < 6)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildJoinResponsePlugIn>(p => p.ShowGuildJoinResponseAsync(GuildRequestAnswerResult.MinimumLevel6)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.GuildStatus is not null)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildJoinResponsePlugIn>(p => p.ShowGuildJoinResponseAsync(GuildRequestAnswerResult.AlreadyHaveGuild)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var guildMaster = player.CurrentMap?.GetObject(guildMasterId) as Player;
|
||||
|
||||
if (guildMaster?.GuildStatus?.Position != GuildPosition.GuildMaster)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildJoinResponsePlugIn>(p => p.ShowGuildJoinResponseAsync(GuildRequestAnswerResult.NotTheGuildMaster)).ConfigureAwait(false);
|
||||
return; // targeted player not in a guild or not the guild master
|
||||
}
|
||||
|
||||
if (guildMaster.LastGuildRequester != null || player.PlayerState.CurrentState != PlayerState.EnteredWorld)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildJoinResponsePlugIn>(p => p.ShowGuildJoinResponseAsync(GuildRequestAnswerResult.GuildMasterOrRequesterIsBusy)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
guildMaster.LastGuildRequester = player;
|
||||
await guildMaster.InvokeViewPlugInAsync<IShowGuildJoinRequestPlugIn>(p => p.ShowGuildJoinRequestAsync(player)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// <copyright file="GuildRequestAnswerAction.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.PlayerActions.Guild;
|
||||
|
||||
using MUnique.OpenMU.GameLogic.Views.Guild;
|
||||
using MUnique.OpenMU.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Action for a guild master player to answer the guild membership request.
|
||||
/// </summary>
|
||||
public class GuildRequestAnswerAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Answers the request.
|
||||
/// </summary>
|
||||
/// <param name="player">The player.</param>
|
||||
/// <param name="accept">If set to <c>true</c>, the membership has been accepted. Otherwise, not.</param>
|
||||
public async ValueTask AnswerRequestAsync(Player player, bool accept)
|
||||
{
|
||||
using var loggerScope = player.Logger.BeginScope(this.GetType());
|
||||
var guildServer = (player.GameContext as IGameServerContext)?.GuildServer;
|
||||
if (guildServer is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var lastGuildRequester = player.LastGuildRequester;
|
||||
if (lastGuildRequester?.SelectedCharacter is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastGuildRequester.GuildStatus is not null)
|
||||
{
|
||||
await lastGuildRequester.InvokeViewPlugInAsync<IGuildJoinResponsePlugIn>(p => p.ShowGuildJoinResponseAsync(GuildRequestAnswerResult.AlreadyHaveGuild)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.GuildStatus?.Position != GuildPosition.GuildMaster)
|
||||
{
|
||||
player.Logger.LogWarning("Suspicious request for player with name: {0} (player is not a guild master), could be hack attempt.", player.Name);
|
||||
await lastGuildRequester.InvokeViewPlugInAsync<IGuildJoinResponsePlugIn>(p => p.ShowGuildJoinResponseAsync(GuildRequestAnswerResult.NotTheGuildMaster)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.PlayerState.CurrentState != PlayerState.EnteredWorld
|
||||
|| lastGuildRequester.PlayerState.CurrentState != PlayerState.EnteredWorld)
|
||||
{
|
||||
await lastGuildRequester.InvokeViewPlugInAsync<IGuildJoinResponsePlugIn>(p => p.ShowGuildJoinResponseAsync(GuildRequestAnswerResult.GuildMasterOrRequesterIsBusy)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (accept)
|
||||
{
|
||||
await guildServer.CreateGuildMemberAsync(player.GuildStatus.GuildId, lastGuildRequester.SelectedCharacter.Id, lastGuildRequester.SelectedCharacter.Name, GuildPosition.NormalMember, ((IGameServerContext)player.GameContext).Id).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await lastGuildRequester.InvokeViewPlugInAsync<IGuildJoinResponsePlugIn>(p => p.ShowGuildJoinResponseAsync(accept ? GuildRequestAnswerResult.Accepted : GuildRequestAnswerResult.Refused)).ConfigureAwait(false);
|
||||
player.LastGuildRequester = null;
|
||||
}
|
||||
}
|
||||
208
src/GameLogic/PlayerActions/Guild/GuildWarAnswerAction.cs
Normal file
208
src/GameLogic/PlayerActions/Guild/GuildWarAnswerAction.cs
Normal file
@@ -0,0 +1,208 @@
|
||||
// <copyright file="GuildWarAnswerAction.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.PlayerActions.Guild;
|
||||
|
||||
using System.ComponentModel;
|
||||
using MUnique.OpenMU.GameLogic.GuildWar;
|
||||
using MUnique.OpenMU.GameLogic.Views.Guild;
|
||||
|
||||
/// <summary>
|
||||
/// Action to handle the response of the requested guild master about the guild war.
|
||||
/// </summary>
|
||||
public class GuildWarAnswerAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Processes the answer.
|
||||
/// </summary>
|
||||
/// <param name="player">The player.</param>
|
||||
/// <param name="isWarAccepted">The answer.</param>
|
||||
public async ValueTask ProcessAnswerAsync(Player player, bool isWarAccepted)
|
||||
{
|
||||
if (player.GuildWarContext is not { } guildWarContext
|
||||
|| guildWarContext.Requester is not { } requester)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IShowShowGuildWarRequestResultPlugIn>(p => p.ShowResultAsync(GuildWarRequestResult.GuildNotFound)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
SoccerGameMap? soccerMap = null;
|
||||
if (guildWarContext.WarType == GuildWarType.Soccer
|
||||
&& player.GameContext.Configuration.Maps.FirstOrDefault(m => m.BattleZone?.Type == BattleType.Soccer) is { } definition)
|
||||
{
|
||||
soccerMap = (SoccerGameMap?)await player.GameContext.GetMapAsync(definition.Number.ToUnsigned()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var soccerInitFailed = false;
|
||||
if (guildWarContext.WarType == GuildWarType.Soccer && (soccerMap is null || soccerMap.IsBattleOngoing))
|
||||
{
|
||||
soccerInitFailed = true;
|
||||
await player.InvokeViewPlugInAsync<IShowShowGuildWarRequestResultPlugIn>(p => p.ShowResultAsync(GuildWarRequestResult.Failed)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (!isWarAccepted
|
||||
|| requester.GuildWarContext is not { } requesterGuildWarContext
|
||||
|| soccerInitFailed)
|
||||
{
|
||||
player.GuildWarContext = null;
|
||||
requester.GuildWarContext = null;
|
||||
return;
|
||||
}
|
||||
|
||||
soccerMap?.InitializeBattle();
|
||||
guildWarContext.State = GuildWarState.Started;
|
||||
requesterGuildWarContext.State = GuildWarState.Started;
|
||||
var playerTeam = this.GetTeamPlayers(player);
|
||||
var requesterTeam = this.GetTeamPlayers(requester);
|
||||
var score = guildWarContext.Score;
|
||||
#pragma warning disable VSTHRD101 // Avoid unsupported async delegates
|
||||
score.PropertyChanged += async (_, args) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (args.PropertyName != nameof(score.HasEnded))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
guildWarContext.State = GuildWarState.Ended;
|
||||
requesterGuildWarContext.State = GuildWarState.Ended;
|
||||
if (player.GameContext is IGameServerContext gameContext && score.Winners.HasValue)
|
||||
{
|
||||
var winner = score.Winners == player.GuildWarContext.Team ? player.GuildStatus!.GuildId : requester.GuildStatus!.GuildId;
|
||||
await gameContext.GuildServer.IncreaseGuildScoreAsync(winner).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// must be catched because it's async void.
|
||||
}
|
||||
};
|
||||
#pragma warning restore VSTHRD101 // Avoid unsupported async delegates
|
||||
|
||||
foreach (var guildPlayer in playerTeam)
|
||||
{
|
||||
guildPlayer.GuildWarContext = guildWarContext;
|
||||
await guildPlayer.InvokeViewPlugInAsync<IShowGuildWarDeclaredPlugIn>(p => p.ShowDeclaredAsync()).ConfigureAwait(false);
|
||||
await guildPlayer.InvokeViewPlugInAsync<IGuildWarScoreUpdatePlugIn>(p => p.UpdateScoreAsync()).ConfigureAwait(false);
|
||||
RegisterScoreChangedEventWeakly(guildPlayer, score, soccerMap);
|
||||
}
|
||||
|
||||
foreach (var guildPlayer in requesterTeam)
|
||||
{
|
||||
guildPlayer.GuildWarContext = requesterGuildWarContext;
|
||||
await guildPlayer.InvokeViewPlugInAsync<IShowGuildWarDeclaredPlugIn>(p => p.ShowDeclaredAsync()).ConfigureAwait(false);
|
||||
await guildPlayer.InvokeViewPlugInAsync<IGuildWarScoreUpdatePlugIn>(p => p.UpdateScoreAsync()).ConfigureAwait(false);
|
||||
RegisterScoreChangedEventWeakly(guildPlayer, score, soccerMap);
|
||||
}
|
||||
|
||||
if (guildWarContext.WarType == GuildWarType.Soccer && soccerMap is { })
|
||||
{
|
||||
await this.MovePartyToArenaAsync(player.GuildWarContext.Team, playerTeam, soccerMap).ConfigureAwait(false);
|
||||
await this.MovePartyToArenaAsync(requester.GuildWarContext.Team, requesterTeam, soccerMap).ConfigureAwait(false);
|
||||
await soccerMap.StartBattleAsync(score).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterScoreChangedEventWeakly(Player guildPlayer, GuildWarScore score, SoccerGameMap? soccerMap)
|
||||
{
|
||||
var playerReference = new WeakReference<Player>(guildPlayer);
|
||||
|
||||
#pragma warning disable VSTHRD100 // Avoid async void methods
|
||||
async void OnScorePropertyChanged(object? sender, PropertyChangedEventArgs args)
|
||||
#pragma warning restore VSTHRD100 // Avoid async void methods
|
||||
{
|
||||
try
|
||||
{
|
||||
if (playerReference.TryGetTarget(out var p))
|
||||
{
|
||||
await OnScoreChangedAsync(score, p, soccerMap, args).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
score.PropertyChanged -= OnScorePropertyChanged;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
guildPlayer.Logger.LogError(ex, "Error handling a changed guild war score.");
|
||||
}
|
||||
}
|
||||
|
||||
score.PropertyChanged += OnScorePropertyChanged;
|
||||
}
|
||||
|
||||
private static async ValueTask OnScoreChangedAsync(GuildWarScore score, Player player, SoccerGameMap? soccerMap, PropertyChangedEventArgs args)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (args.PropertyName == nameof(score.HasEnded))
|
||||
{
|
||||
if (player.GuildWarContext is { } context)
|
||||
{
|
||||
var isWinner = context.Team == score.Winners;
|
||||
await player.InvokeViewPlugInAsync<IShowGuildWarResultPlugIn>(p => p.ShowResultAsync(context.EnemyTeamName, isWinner ? GuildWarResult.Won : GuildWarResult.Lost)).ConfigureAwait(false);
|
||||
if (soccerMap is not null)
|
||||
{
|
||||
var spawnGates = soccerMap.Definition.ExitGates.Where(g => g.IsSpawnGate);
|
||||
if (spawnGates.Any())
|
||||
{
|
||||
await player.WarpToAsync(spawnGates.SelectRandom()!).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
player.GuildWarContext = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IGuildWarScoreUpdatePlugIn>(p => p.UpdateScoreAsync()).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
player.Logger.LogError(ex, "Unexpected error when notifying the player about a guild war score update");
|
||||
}
|
||||
}
|
||||
|
||||
private ICollection<Player> GetTeamPlayers(Player guildMaster)
|
||||
{
|
||||
if (guildMaster.Party is { } party)
|
||||
{
|
||||
return party.PartyList.OfType<Player>().Where(p => p.GuildStatus?.GuildId == guildMaster.GuildStatus?.GuildId).ToList();
|
||||
}
|
||||
|
||||
return new List<Player>(1) { guildMaster };
|
||||
}
|
||||
|
||||
private async ValueTask MovePartyToArenaAsync(GuildWarTeam team, ICollection<Player> members, SoccerGameMap soccerMap)
|
||||
{
|
||||
var ground = soccerMap.Definition.BattleZone?.Ground;
|
||||
if (ground is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var increaseX = soccerMap.Definition.BattleZone?.LeftTeamSpawnPointX is not null;
|
||||
|
||||
var exitGate = new ExitGate
|
||||
{
|
||||
X1 = (team == GuildWarTeam.First ? soccerMap.Definition.BattleZone?.LeftTeamSpawnPointX : soccerMap.Definition.BattleZone?.RightTeamSpawnPointX) ?? ground.X1,
|
||||
X2 = (team == GuildWarTeam.First ? soccerMap.Definition.BattleZone?.LeftTeamSpawnPointX : soccerMap.Definition.BattleZone?.RightTeamSpawnPointX) ?? ground.X2,
|
||||
Y1 = (team == GuildWarTeam.First ? soccerMap.Definition.BattleZone?.LeftTeamSpawnPointY : soccerMap.Definition.BattleZone?.RightTeamSpawnPointY) ?? ground.Y1,
|
||||
Y2 = (team == GuildWarTeam.First ? soccerMap.Definition.BattleZone?.LeftTeamSpawnPointY : soccerMap.Definition.BattleZone?.RightTeamSpawnPointY) ?? ground.Y2,
|
||||
Map = soccerMap.Definition,
|
||||
};
|
||||
|
||||
foreach (var member in members)
|
||||
{
|
||||
await member.WarpToAsync(exitGate).ConfigureAwait(false);
|
||||
if (increaseX)
|
||||
{
|
||||
exitGate.X1++;
|
||||
exitGate.X2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
91
src/GameLogic/PlayerActions/Guild/GuildWarRequestAction.cs
Normal file
91
src/GameLogic/PlayerActions/Guild/GuildWarRequestAction.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
// <copyright file="GuildWarRequestAction.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.PlayerActions.Guild;
|
||||
|
||||
using MUnique.OpenMU.GameLogic.GuildWar;
|
||||
using MUnique.OpenMU.GameLogic.Views.Guild;
|
||||
using MUnique.OpenMU.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Action to request a guild war.
|
||||
/// </summary>
|
||||
public class GuildWarRequestAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Requests the a guild war at the guild master of the target guild.
|
||||
/// </summary>
|
||||
/// <param name="player">The player.</param>
|
||||
/// <param name="targetGuildName">Name of the target guild.</param>
|
||||
public ValueTask RequestWarAsync(Player player, string targetGuildName)
|
||||
{
|
||||
return this.TryRequestWarAsync(player, targetGuildName, GuildWarType.Normal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests the a battle soccer at the guild master of the target guild.
|
||||
/// </summary>
|
||||
/// <param name="player">The player.</param>
|
||||
/// <param name="targetGuildName">Name of the target guild.</param>
|
||||
public ValueTask RequestBattleSoccerAsync(Player player, string targetGuildName)
|
||||
{
|
||||
return this.TryRequestWarAsync(player, targetGuildName, GuildWarType.Soccer);
|
||||
}
|
||||
|
||||
private async ValueTask TryRequestWarAsync(Player player, string targetGuildName, GuildWarType guildWarType)
|
||||
{
|
||||
if (player.GuildStatus is not { } guildStatus
|
||||
|| player.GameContext is not IGameServerContext serverContext
|
||||
|| await serverContext.GuildServer.GetGuildAsync(player.GuildStatus.GuildId).ConfigureAwait(false) is not { Name: not null } guild)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IShowShowGuildWarRequestResultPlugIn>(p => p.ShowResultAsync(GuildWarRequestResult.NotInGuild)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (guildStatus.Position != GuildPosition.GuildMaster)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IShowShowGuildWarRequestResultPlugIn>(p => p.ShowResultAsync(GuildWarRequestResult.NotTheGuildMaster)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await serverContext.GuildServer.GuildExistsAsync(targetGuildName).ConfigureAwait(false))
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IShowShowGuildWarRequestResultPlugIn>(p => p.ShowResultAsync(GuildWarRequestResult.GuildNotFound)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var targetGuildId = await serverContext.GuildServer.GetGuildIdByNameAsync(targetGuildName).ConfigureAwait(false);
|
||||
|
||||
Player? targetGuildMaster = null;
|
||||
await serverContext.ForEachGuildPlayerAsync(targetGuildId, p =>
|
||||
{
|
||||
targetGuildMaster = p.GuildStatus?.Position == GuildPosition.GuildMaster ? p : targetGuildMaster;
|
||||
return Task.CompletedTask;
|
||||
}).ConfigureAwait(false);
|
||||
if (targetGuildMaster is null)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IShowShowGuildWarRequestResultPlugIn>(p => p.ShowResultAsync(GuildWarRequestResult.GuildMasterOffline)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetGuildMaster.GuildWarContext is not null || player.GuildWarContext is not null)
|
||||
{
|
||||
await player.InvokeViewPlugInAsync<IShowShowGuildWarRequestResultPlugIn>(p => p.ShowResultAsync(GuildWarRequestResult.AlreadyInWar)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var score = new GuildWarScore
|
||||
{
|
||||
FirstGuildName = targetGuildName,
|
||||
SecondGuildName = guild.Name!,
|
||||
MaximumScore = (byte)(guildWarType == GuildWarType.Soccer ? 100 : 20),
|
||||
};
|
||||
|
||||
targetGuildMaster.GuildWarContext = new GuildWarContext(guildWarType, score, GuildWarTeam.First, player);
|
||||
player.GuildWarContext = new GuildWarContext(guildWarType, score, GuildWarTeam.Second, null);
|
||||
|
||||
await targetGuildMaster.InvokeViewPlugInAsync<IShowGuildWarRequestPlugIn>(p => p.ShowRequestAsync(guild.Name!, guildWarType)).ConfigureAwait(false);
|
||||
await player.InvokeViewPlugInAsync<IShowShowGuildWarRequestResultPlugIn>(p => p.ShowResultAsync(GuildWarRequestResult.RequestSentToGuildMaster)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user