diff --git a/src/GameLogic/CastleSiege/CastleSiegeHuntingPortalTalkPlugIn.cs b/src/GameLogic/CastleSiege/CastleSiegeHuntingPortalTalkPlugIn.cs new file mode 100644 index 0000000..f736f80 --- /dev/null +++ b/src/GameLogic/CastleSiege/CastleSiegeHuntingPortalTalkPlugIn.cs @@ -0,0 +1,59 @@ +// +// 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.Views; +using MUnique.OpenMU.Interfaces; +using MUnique.OpenMU.PlugIns; + +/// +/// ADAMU-CUSTOM (Castle Siege P4 — ownership reward): the castle Guard (NPC 220) on Valley of Loren is the +/// portal into the castle-exclusive hunting ground (Land of Trials, map 31). It warps a player there only +/// when their guild owns the castle (or they are a game master); otherwise it explains why they can't enter. +/// +[Guid("CA5710A0-7A1B-4C2D-8E3F-000000000220")] +[PlugIn] +[Display(Name = "Castle Siege Hunting Portal (Guard)", Description = "Guard NPC 220 on Valley of Loren warps the castle-owning guild into Land of Trials (map 31).")] +public class CastleSiegeHuntingPortalTalkPlugIn : IPlayerTalkToNpcPlugIn +{ + private const short GuardNpcNumber = 220; + private const short ValleyOfLorenMapNumber = 30; + + /// + public async ValueTask PlayerTalksToNpcAsync(Player player, NonPlayerCharacter npc, NpcTalkEventArgs eventArgs) + { + // Only the castle Guard on Valley of Loren acts as the hunting-ground portal. + if (npc.Definition.Number != GuardNpcNumber + || player.CurrentMap?.Definition.Number != ValleyOfLorenMapNumber) + { + return; + } + + eventArgs.HasBeenHandled = true; + + var (allowed, error) = await CastleSiegeMapAccess + .CanEnterMapAsync(player, CastleSiegeMapAccess.CastleHuntingMapNumber).ConfigureAwait(false); + if (!allowed) + { + await ShowAsync(player, error!).ConfigureAwait(false); + return; + } + + var map = await player.GameContext.GetMapAsync((ushort)CastleSiegeMapAccess.CastleHuntingMapNumber).ConfigureAwait(false); + if (map?.SafeZoneSpawnGate is not { } gate) + { + await ShowAsync(player, "The castle hunting ground is not available right now.").ConfigureAwait(false); + return; + } + + await player.WarpToAsync(gate).ConfigureAwait(false); + } + + private static ValueTask ShowAsync(Player player, string text) + => player.InvokeViewPlugInAsync(p => p.ShowMessageAsync(text, MessageType.BlueNormal)); +}