From 44dcb2fd58b6a4a4393765d4558008bb082b903a Mon Sep 17 00:00:00 2001 From: Acentech Dev Date: Tue, 14 Jul 2026 23:11:35 +0300 Subject: [PATCH] feat(CS-P2): Guardsman (NPC 224) talk handler -> register guild during registration phase --- .../CastleSiegeGuardsmanTalkPlugIn.cs | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/GameLogic/CastleSiege/CastleSiegeGuardsmanTalkPlugIn.cs diff --git a/src/GameLogic/CastleSiege/CastleSiegeGuardsmanTalkPlugIn.cs b/src/GameLogic/CastleSiege/CastleSiegeGuardsmanTalkPlugIn.cs new file mode 100644 index 0000000..6a00304 --- /dev/null +++ b/src/GameLogic/CastleSiege/CastleSiegeGuardsmanTalkPlugIn.cs @@ -0,0 +1,74 @@ +// +// Licensed under the MIT License. See LICENSE file in the project root for full license information. +// + +namespace MUnique.OpenMU.GameLogic.CastleSiege; + +using System.Runtime.InteropServices; +using MUnique.OpenMU.GameLogic.NPC; +using MUnique.OpenMU.GameLogic.PlugIns; +using MUnique.OpenMU.GameLogic.PlugIns.PeriodicTasks; +using MUnique.OpenMU.GameLogic.Views; +using MUnique.OpenMU.Interfaces; +using MUnique.OpenMU.PlugIns; + +/// +/// Handles talking to the Castle Siege 'Guardsman' NPC (number 224): registers the talking +/// player's guild for the current siege while the state machine is in the registration phase. +/// P2 first increment — guild marks, entrance fee and minimum-guild requirements come later. +/// +[Guid("CA5710A0-7A1B-4C2D-8E3F-000000000224")] +[PlugIn] +[Display(Name = "Castle Siege Guardsman", Description = "Registers a guild for the Castle Siege when talking to the Guardsman (NPC 224).")] +public class CastleSiegeGuardsmanTalkPlugIn : IPlayerTalkToNpcPlugIn +{ + /// Gets the NPC number of the Castle Siege 'Guardsman'. + public static short GuardsmanNpcNumber => 224; + + /// + public async ValueTask PlayerTalksToNpcAsync(Player player, NonPlayerCharacter npc, NpcTalkEventArgs eventArgs) + { + if (npc.Definition.Number != GuardsmanNpcNumber) + { + return; + } + + // We handle the dialog ourselves (no client-side window), so suppress the default "not implemented" message. + eventArgs.HasBeenHandled = true; + + var context = CastleSiegeEventPlugIn.TryGetContext(player.GameContext); + if (context is null) + { + await ShowAsync(player, "Castle Siege is not active on this server.").ConfigureAwait(false); + return; + } + + if (context.Phase != CastleSiegePhase.Registration) + { + await ShowAsync(player, "Castle Siege registration is not open right now.").ConfigureAwait(false); + return; + } + + if (player.GuildStatus is not { } guildStatus || guildStatus.Position != GuildPosition.GuildMaster) + { + await ShowAsync(player, "Only a guild master can register for the Castle Siege.").ConfigureAwait(false); + return; + } + + var guildName = guildStatus.GuildId.ToString(); + if (player.GameContext is IGameServerContext serverContext) + { + var guild = await serverContext.GuildServer.GetGuildAsync(guildStatus.GuildId).ConfigureAwait(false); + if (guild?.Name is { Length: > 0 } name) + { + guildName = name; + } + } + + context.RegisterGuild(guildName); + await ShowAsync(player, $"Your guild '{guildName}' is registered for the Castle Siege.").ConfigureAwait(false); + } + + private static ValueTask ShowAsync(Player player, string text) + => player.InvokeViewPlugInAsync(p => p.ShowMessageAsync(text, MessageType.BlueNormal)); +}