baseline: OpenMU upstream b5a0961 (fresh source)

This commit is contained in:
Acentech Dev
2026-07-14 19:00:35 +03:00
parent 450402e47d
commit 36fc125d5c
11968 changed files with 748705 additions and 0 deletions

View File

@@ -0,0 +1,202 @@
// <copyright file="TalkNpcAction.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;
using MUnique.OpenMU.GameLogic.MiniGames;
using MUnique.OpenMU.GameLogic.NPC;
using MUnique.OpenMU.GameLogic.PlayerActions.Quests;
using MUnique.OpenMU.GameLogic.PlugIns;
using MUnique.OpenMU.GameLogic.Views;
using MUnique.OpenMU.GameLogic.Views.Guild;
using MUnique.OpenMU.GameLogic.Views.NPC;
using MUnique.OpenMU.GameLogic.Views.Quest;
using MUnique.OpenMU.GameLogic.Views.Vault;
using MUnique.OpenMU.Interfaces;
/// <summary>
/// Action to talk to a npc.
/// </summary>
public class TalkNpcAction
{
/// <summary>
/// Talks to the specified Monster.
/// </summary>
/// <param name="player">The player.</param>
/// <param name="npc">The Monster.</param>
public async ValueTask TalkToNpcAsync(Player player, NonPlayerCharacter npc)
{
var npcStats = npc.Definition;
if (this.AdvancePlayerState(npc))
{
if (!await player.PlayerState.TryAdvanceToAsync(PlayerState.NpcDialogOpened).ConfigureAwait(false))
{
return;
}
}
else
{
if (player.PlayerState.CurrentState != PlayerState.EnteredWorld)
{
return;
}
}
player.OpenedNpc = npc;
if (npcStats.MerchantStore != null && npcStats.MerchantStore.Items.Count > 0)
{
await Task.Delay(500).ConfigureAwait(false);
await player.InvokeViewPlugInAsync<IOpenNpcWindowPlugIn>(p => p.OpenNpcWindowAsync(npcStats.NpcWindow != NpcWindow.Undefined ? npcStats.NpcWindow : NpcWindow.Merchant)).ConfigureAwait(false);
await player.InvokeViewPlugInAsync<IShowMerchantStoreItemListPlugIn>(p => p.ShowMerchantStoreItemListAsync(npcStats.MerchantStore.Items, StoreKind.Normal)).ConfigureAwait(false);
}
else
{
await this.ShowDialogOfOpenedNpcAsync(player).ConfigureAwait(false);
}
}
/// <summary>
/// Gets a value indicating whether this action advances the player state to <see cref="PlayerState.NpcDialogOpened" />.
/// </summary>
/// <param name="npc">The NPC whose dialog is about to be opened.</param>
/// <returns>A value indicating whether this action advances the player state to <see cref="PlayerState.NpcDialogOpened" />.</returns>
protected virtual bool AdvancePlayerState(NonPlayerCharacter npc) => true;
private async ValueTask ShowDialogOfOpenedNpcAsync(Player player)
{
var npcStats = player.OpenedNpc!.Definition;
switch (npcStats.NpcWindow)
{
case NpcWindow.Undefined:
var eventArgs = new NpcTalkEventArgs();
player.GameContext.PlugInManager.GetPlugInPoint<IPlayerTalkToNpcPlugIn>()?.PlayerTalksToNpcAsync(player, player.OpenedNpc, eventArgs);
if (!eventArgs.HasBeenHandled)
{
if (player.CurrentMiniGame is BloodCastleContext bloodCastle && player.OpenedNpc.Definition.Number == 232)
{
await bloodCastle.TalkToNpcArchangelAsync(player).ConfigureAwait(false);
}
else
{
await player.ShowLocalizedBlueMessageAsync(nameof(PlayerMessage.TalkingNotImplementedFormat), npcStats.Number, npcStats.Designation).ConfigureAwait(false);
}
await player.PlayerState.TryAdvanceToAsync(PlayerState.EnteredWorld).ConfigureAwait(false);
}
else if (!eventArgs.LeavesDialogOpen)
{
player.OpenedNpc = null;
await player.PlayerState.TryAdvanceToAsync(PlayerState.EnteredWorld).ConfigureAwait(false);
}
else
{
// Leaves dialog opened, so leave the state as it is.
}
break;
case NpcWindow.VaultStorage:
player.Account!.Vault ??= player.PersistenceContext.CreateNew<ItemStorage>();
var warehouseSize = player.Account.IsVaultExtended ? InventoryConstants.WarehouseSize * 2 : InventoryConstants.WarehouseSize;
player.Vault = new Storage(warehouseSize, player.Account.Vault);
await player.InvokeViewPlugInAsync<IShowVaultPlugIn>(p => p.ShowVaultAsync()).ConfigureAwait(false);
break;
case NpcWindow.GuildMaster:
if (await this.IsPlayedAllowedToCreateGuildAsync(player).ConfigureAwait(false))
{
await player.InvokeViewPlugInAsync<IShowGuildMasterDialogPlugIn>(p => p.ShowGuildMasterDialogAsync()).ConfigureAwait(false);
}
else
{
player.OpenedNpc = null;
await player.PlayerState.TryAdvanceToAsync(PlayerState.EnteredWorld).ConfigureAwait(false);
}
break;
case NpcWindow.LegacyQuest:
await this.ShowLegacyQuestDialogAsync(player).ConfigureAwait(false);
break;
case NpcWindow.DoorkeeperTitusDuelWatch:
await player.InvokeViewPlugInAsync<IOpenNpcWindowPlugIn>(p => p.OpenNpcWindowAsync(npcStats.NpcWindow)).ConfigureAwait(false);
_ = Task.Run(async () =>
{
while (player.IsActive() && player.OpenedNpc?.Definition.NpcWindow == NpcWindow.DoorkeeperTitusDuelWatch)
{
await player.GameContext.DuelRoomManager.ShowRoomsAsync(player).ConfigureAwait(false);
await Task.Delay(5000).ConfigureAwait(false);
}
});
break;
case NpcWindow.ChaosMachine:
case NpcWindow.RemoveJohOption:
await player.InvokeViewPlugInAsync<IOpenNpcWindowPlugIn>(p => p.OpenNpcWindowAsync(npcStats.NpcWindow)).ConfigureAwait(false);
break;
default:
await player.InvokeViewPlugInAsync<IOpenNpcWindowPlugIn>(p => p.OpenNpcWindowAsync(npcStats.NpcWindow)).ConfigureAwait(false);
break;
}
if (npcStats.ItemCraftings.Any())
{
player.BackupInventory = new BackupItemStorage(player.Inventory!.ItemStorage);
}
}
private async ValueTask ShowLegacyQuestDialogAsync(Player player)
{
var quests = player.OpenedNpc!.Definition.Quests
.Where(q => q.QualifiedCharacter is null || Equals(q.QualifiedCharacter, player.SelectedCharacter!.CharacterClass));
if (!quests.Any())
{
await player.InvokeViewPlugInAsync<IShowMessageOfObjectPlugIn>(p => p.ShowMessageOfObjectAsync("I have no quests for you.", player.OpenedNpc)).ConfigureAwait(false);
player.OpenedNpc = null;
await player.PlayerState.TryAdvanceToAsync(PlayerState.EnteredWorld).ConfigureAwait(false);
return;
}
if (quests.All(quest => quest.MinimumCharacterLevel > player.Level))
{
await player.InvokeViewPlugInAsync<IShowMessageOfObjectPlugIn>(p => p.ShowMessageOfObjectAsync(
"I have nothing to do for you. Come back with more power.",
player.OpenedNpc)).ConfigureAwait(false);
player.OpenedNpc = null;
await player.PlayerState.TryAdvanceToAsync(PlayerState.EnteredWorld).ConfigureAwait(false);
return;
}
var maxQuestNumber = quests.Max(q => q.Number);
var questGroup = quests.FirstOrDefault(q => q.Number == maxQuestNumber)?.Group;
var questState = player.GetQuestState(questGroup ?? 0);
if (questState?.LastFinishedQuest?.Number >= maxQuestNumber)
{
await player.InvokeViewPlugInAsync<IShowMessageOfObjectPlugIn>(p => p.ShowMessageOfObjectAsync(
"I have nothing to do for you. You solved all my quests already.",
player.OpenedNpc)).ConfigureAwait(false);
player.OpenedNpc = null;
await player.PlayerState.TryAdvanceToAsync(PlayerState.EnteredWorld).ConfigureAwait(false);
return;
}
await player.InvokeViewPlugInAsync<ILegacyQuestStateDialogPlugIn>(p => p.ShowAsync()).ConfigureAwait(false);
}
private async ValueTask<bool> IsPlayedAllowedToCreateGuildAsync(Player player)
{
if (player.Level < 100)
{
await player.InvokeViewPlugInAsync<IShowMessageOfObjectPlugIn>(p => p.ShowMessageOfObjectAsync("Your level should be at least level 100", player.OpenedNpc!)).ConfigureAwait(false);
return false;
}
if (player.GuildStatus != null)
{
await player.InvokeViewPlugInAsync<IShowMessageOfObjectPlugIn>(p => p.ShowMessageOfObjectAsync("You already belong to a guild", player.OpenedNpc!)).ConfigureAwait(false);
return false;
}
return true;
}
}