diff --git a/data/extensions/Events/Startup/VocationConverter.cs b/data/extensions/Events/Startup/VocationConverter.cs index 0cbf6bd3e..9506b0a75 100644 --- a/data/extensions/Events/Startup/VocationConverter.cs +++ b/data/extensions/Events/Startup/VocationConverter.cs @@ -29,8 +29,10 @@ public void Run() foreach (var itemType in _itemTypeStore.All) { var vocationsAttr = itemType.Attributes.GetAttributeArray(ItemAttribute.Vocation); - if (vocationsAttr is not string[] vocations) continue; + if (vocationsAttr is not string[] vocations) continue; + + itemType.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); var vocationsType = new List(vocations.Length); foreach (var vocation in vocations) diff --git a/data/extensions/Items/Doors/LevelDoor.cs b/data/extensions/Items/Doors/LevelDoor.cs index ed43b11b4..0f55d5a84 100644 --- a/data/extensions/Items/Doors/LevelDoor.cs +++ b/data/extensions/Items/Doors/LevelDoor.cs @@ -62,8 +62,8 @@ private void TeleportNorthOrSouth(IPlayer player, Direction directionTo) player.TeleportTo(Location.X, (ushort)(Location.Y + 1), Location.Z); } - public override string GetLookText(IInspectionTextBuilder inspectionTextBuilder, IPlayer player, - bool isClose = false) + public override string GetLookText( + bool isClose = false, bool showInternalDetails = false) { Metadata.Attributes.TryGetAttribute(ItemAttribute.ActionId, out int actionId); diff --git a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs index 2875a354b..9a4df2222 100644 --- a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs +++ b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/IConnection.cs @@ -17,6 +17,7 @@ public interface IConnection string Ip { get; } long TimeStamp { get; } byte RandomNumber { get; } + ushort OtcV8Version { get; set; } event EventHandler OnProcessEvent; event EventHandler OnCloseEvent; diff --git a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs index daa2ddf75..d320563dc 100644 --- a/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs +++ b/src/ApplicationServer/NeoServer.Server.Contracts/Contracts/Network/INetworkMessage.cs @@ -14,7 +14,7 @@ public interface INetworkMessage : IReadOnlyNetworkMessage void AddUInt32(uint value); void WriteUint32(uint value, int position); byte[] AddHeader(bool addChecksum = true); - void AddItem(IItem item); + void AddItem(IItem item, bool showItemDescription = false); void AddLocation(Location location); void AddLength(); } \ No newline at end of file diff --git a/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs index e71c35dae..e46461edf 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Items/ContentModifiedOnContainerEventHandler.cs @@ -5,18 +5,21 @@ using NeoServer.Networking.Packets.Outgoing.Item; using NeoServer.Networking.Packets.Outgoing.Npc; using NeoServer.Server.Common.Contracts; +using NeoServer.Server.Configurations; namespace NeoServer.Server.Events.Items; public class ContentModifiedOnContainerEventHandler { private readonly ICoinTypeStore _coinTypeStore; + private readonly ClientConfiguration _clientConfiguration; private readonly IGameServer game; - public ContentModifiedOnContainerEventHandler(IGameServer game, ICoinTypeStore coinTypeStore) + public ContentModifiedOnContainerEventHandler(IGameServer game, ICoinTypeStore coinTypeStore, ClientConfiguration clientConfiguration) { this.game = game; _coinTypeStore = coinTypeStore; + _clientConfiguration = clientConfiguration; } public void Execute(IPlayer player, ContainerOperation operation, byte containerId, byte slotIndex, IItem item) @@ -30,10 +33,16 @@ public void Execute(IPlayer player, ContainerOperation operation, byte container connection.OutgoingPackets.Enqueue(new RemoveItemContainerPacket(containerId, slotIndex, item)); break; case ContainerOperation.ItemAdded: - connection.OutgoingPackets.Enqueue(new AddItemContainerPacket(containerId, item)); + connection.OutgoingPackets.Enqueue(new AddItemContainerPacket(containerId, item) + { + ShowItemDescription = connection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip + }); break; case ContainerOperation.ItemUpdated: - connection.OutgoingPackets.Enqueue(new UpdateItemContainerPacket(containerId, slotIndex, item)); + connection.OutgoingPackets.Enqueue(new UpdateItemContainerPacket(containerId, slotIndex, item) + { + ShowItemDescription = connection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip + }); break; } diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs index a59bfcfe9..4fae44b87 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/Containers/PlayerOpenedContainerEventHandler.cs @@ -2,16 +2,19 @@ using NeoServer.Game.Common.Contracts.Items.Types.Containers; using NeoServer.Networking.Packets.Outgoing.Player; using NeoServer.Server.Common.Contracts; +using NeoServer.Server.Configurations; namespace NeoServer.Server.Events.Player.Containers; public class PlayerOpenedContainerEventHandler { private readonly IGameServer game; + private readonly ClientConfiguration _clientConfiguration; - public PlayerOpenedContainerEventHandler(IGameServer game) + public PlayerOpenedContainerEventHandler(IGameServer game, ClientConfiguration clientConfiguration) { this.game = game; + _clientConfiguration = clientConfiguration; } public void Execute(IPlayer player, byte containerId, IContainer container) @@ -23,7 +26,10 @@ private void SendContainerPacket(IPlayer player, byte containerId, IContainer co { if (!game.CreatureManager.GetPlayerConnection(player.CreatureId, out var connection)) return; - connection.OutgoingPackets.Enqueue(new OpenContainerPacket(container, containerId)); + connection.OutgoingPackets.Enqueue(new OpenContainerPacket(container, containerId) + { + WithDescription = connection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip + }); connection.Send(); } } \ No newline at end of file diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs index 15cb44398..78460560a 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerChangedInventoryEventHandler.cs @@ -6,18 +6,21 @@ using NeoServer.Networking.Packets.Outgoing.Npc; using NeoServer.Networking.Packets.Outgoing.Player; using NeoServer.Server.Common.Contracts; +using NeoServer.Server.Configurations; namespace NeoServer.Server.Events.Player; public class PlayerChangedInventoryEventHandler { private readonly ICoinTypeStore _coinTypeStore; + private readonly ClientConfiguration _clientConfiguration; private readonly IGameServer game; - public PlayerChangedInventoryEventHandler(IGameServer game, ICoinTypeStore coinTypeStore) + public PlayerChangedInventoryEventHandler(IGameServer game, ICoinTypeStore coinTypeStore, ClientConfiguration clientConfiguration) { this.game = game; _coinTypeStore = coinTypeStore; + _clientConfiguration = clientConfiguration; } public void Execute(IInventory inventory, IItem item, Slot slot, byte amount = 1) @@ -28,7 +31,10 @@ public void Execute(IInventory inventory, IItem item, Slot slot, byte amount = 1 if (!game.CreatureManager.GetPlayerConnection(player.CreatureId, out var connection)) return; - connection.OutgoingPackets.Enqueue(new PlayerInventoryItemPacket(player.Inventory, slot)); + connection.OutgoingPackets.Enqueue(new PlayerInventoryItemPacket(player.Inventory, slot) + { + ShowItemDescription = connection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip + }); if (player.Shopping) connection.OutgoingPackets.Enqueue(new SaleItemListPacket(player, diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerLookedAtEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerLookedAtEventHandler.cs index c9b83eaa5..cea30c5ee 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerLookedAtEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerLookedAtEventHandler.cs @@ -24,7 +24,7 @@ public void Execute(IPlayer player, IThing thing, bool isClose) var inspectionTextBuilder = GetInspectionTextBuilder(thing); - var text = thing.GetLookText(inspectionTextBuilder, player, isClose); + var text = thing.GetLookText( isClose, player.CanSeeInspectionDetails); connection.OutgoingPackets.Enqueue(new TextMessagePacket(text, TextMessageOutgoingType.Description)); connection.Send(); diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs index 38aa4fe24..1f0cec2be 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/PlayerSelfAppearOnMapEventHandler.cs @@ -9,18 +9,21 @@ using NeoServer.Networking.Packets.Outgoing.Player; using NeoServer.Server.Common.Contracts; using NeoServer.Server.Common.Contracts.Network; +using NeoServer.Server.Configurations; namespace NeoServer.Server.Events.Player; public class PlayerSelfAppearOnMapEventHandler : IEventHandler { - private readonly IGameServer game; - private readonly IMap map; + private readonly IGameServer _game; + private readonly ClientConfiguration _clientConfiguration; + private readonly IMap _map; - public PlayerSelfAppearOnMapEventHandler(IMap map, IGameServer game) + public PlayerSelfAppearOnMapEventHandler(IMap map, IGameServer game, ClientConfiguration clientConfiguration) { - this.map = map; - this.game = game; + _map = map; + _game = game; + _clientConfiguration = clientConfiguration; } public void Execute(IWalkableCreature creature) @@ -29,7 +32,7 @@ public void Execute(IWalkableCreature creature) if (creature is not IPlayer player) return; - if (!game.CreatureManager.GetPlayerConnection(creature.CreatureId, out var connection)) return; + if (!_game.CreatureManager.GetPlayerConnection(creature.CreatureId, out var connection)) return; SendPacketsToPlayer(player, connection); } @@ -37,13 +40,17 @@ public void Execute(IWalkableCreature creature) private void SendPacketsToPlayer(IPlayer player, IConnection connection) { connection.OutgoingPackets.Enqueue(new SelfAppearPacket(player)); - connection.OutgoingPackets.Enqueue(new MapDescriptionPacket(player, map)); + connection.OutgoingPackets.Enqueue(new MapDescriptionPacket(player, _map)); connection.OutgoingPackets.Enqueue(new MagicEffectPacket(player.Location, EffectT.BubbleBlue)); - connection.OutgoingPackets.Enqueue(new PlayerInventoryPacket(player.Inventory)); + connection.OutgoingPackets.Enqueue(new PlayerInventoryPacket(player.Inventory) + { + ShowItemDescription = connection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip + }); + connection.OutgoingPackets.Enqueue(new PlayerStatusPacket(player)); connection.OutgoingPackets.Enqueue(new PlayerSkillsPacket(player)); - connection.OutgoingPackets.Enqueue(new WorldLightPacket(game.LightLevel, game.LightColor)); + connection.OutgoingPackets.Enqueue(new WorldLightPacket(_game.LightLevel, _game.LightColor)); connection.OutgoingPackets.Enqueue(new CreatureLightPacket(player)); diff --git a/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs b/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs index 79a767917..17e6a1c9d 100644 --- a/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs +++ b/src/ApplicationServer/NeoServer.Server.Events/Player/Trade/TradeRequestedEventHandler.cs @@ -5,16 +5,19 @@ using NeoServer.Networking.Packets.Outgoing.Trade; using NeoServer.Server.Common.Contracts; using NeoServer.Server.Common.Contracts.Network; +using NeoServer.Server.Configurations; namespace NeoServer.Server.Events.Player.Trade; public class TradeRequestedEventHandler : IEventHandler { private readonly IGameServer _gameServer; + private readonly ClientConfiguration _clientConfiguration; - public TradeRequestedEventHandler(IGameServer gameServer) + public TradeRequestedEventHandler(IGameServer gameServer, ClientConfiguration clientConfiguration) { _gameServer = gameServer; + _clientConfiguration = clientConfiguration; } public void Execute(TradeRequest tradeRequest) @@ -27,7 +30,10 @@ public void Execute(TradeRequest tradeRequest) out var playerRequestedConnection); playerRequestingConnection.OutgoingPackets.Enqueue(new TradeRequestPacket(tradeRequest.PlayerRequesting.Name, - tradeRequest.Items)); + tradeRequest.Items) + { + ShowItemDescription = playerRequestingConnection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip + }); SendTradeMessage(tradeRequest, playerRequestedConnection); @@ -46,7 +52,7 @@ private static void SendTradeMessage(TradeRequest tradeRequest, IConnection play TextMessageOutgoingType.Small)); } - private static void SendAcknowledgeTradeToBothPlayers(TradeRequest tradeRequest, + private void SendAcknowledgeTradeToBothPlayers(TradeRequest tradeRequest, IConnection playerRequestingConnection, IConnection playerRequestedConnection) { @@ -55,9 +61,15 @@ private static void SendAcknowledgeTradeToBothPlayers(TradeRequest tradeRequest, var items = SafeTradeSystem.GetTradedItems(tradeRequest.PlayerRequested); playerRequestingConnection.OutgoingPackets.Enqueue(new TradeRequestPacket(tradeRequest.PlayerRequested.Name, - items, true)); + items, true) + { + ShowItemDescription = playerRequestingConnection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip + }); playerRequestedConnection.OutgoingPackets.Enqueue(new TradeRequestPacket(tradeRequest.PlayerRequesting.Name, - tradeRequest.Items, true)); + tradeRequest.Items, true) + { + ShowItemDescription = playerRequestedConnection.OtcV8Version > 0 && _clientConfiguration.OtcV8.GameItemTooltip + }); } } \ No newline at end of file diff --git a/src/ApplicationServer/NeoServer.Server/Configurations/ServerConfiguration.cs b/src/ApplicationServer/NeoServer.Server/Configurations/ServerConfiguration.cs index 1f32b6762..49fa770c1 100644 --- a/src/ApplicationServer/NeoServer.Server/Configurations/ServerConfiguration.cs +++ b/src/ApplicationServer/NeoServer.Server/Configurations/ServerConfiguration.cs @@ -40,4 +40,13 @@ public record GrayLogConfiguration( string HostnameOverride, string Facility) { +} + +public record ClientConfiguration(ClientConfiguration.OtcV8Configuration OtcV8) +{ + public record OtcV8Configuration( + bool GameExtendedOpcode, + bool GameEnvironmentEffect, + bool GameExtendedClientPing, + bool GameItemTooltip); } \ No newline at end of file diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Inspection/IInspectionTextBuilder.cs b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Inspection/IInspectionTextBuilder.cs index 4d1589394..eedba4b1d 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Inspection/IInspectionTextBuilder.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Inspection/IInspectionTextBuilder.cs @@ -1,19 +1,17 @@ -using System; -using NeoServer.Game.Common.Contracts.Creatures; +using System; using NeoServer.Game.Common.Contracts.Items; namespace NeoServer.Game.Common.Contracts.Inspection; public interface IInspectionTextBuilder -{ - string Build(IThing thing, IPlayer player, bool isClose = false); +{ bool IsApplicable(IThing thing); public static string GetArticle(string name) { if (string.IsNullOrWhiteSpace(name)) return "a"; - Span vowels = stackalloc char[5] { 'a', 'e', 'i', 'o', 'u' }; + Span vowels = ['a', 'e', 'i', 'o', 'u']; return vowels.Contains(name.ToLower()[0]) ? "an" : "a"; } } \ No newline at end of file diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Items/IThing.cs b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Items/IThing.cs index 0e97163bc..7be7d9645 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Items/IThing.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/Contracts/Items/IThing.cs @@ -13,8 +13,7 @@ public interface IThing : IUsable Location.Structs.Location Location { get; } - string GetLookText(IInspectionTextBuilder inspectionTextBuilder, IPlayer player, bool isClose = false); - + string GetLookText(bool isClose = false, bool showInternalDetails = false); public bool IsCloseTo(IThing thing) { if (Location.Type is not LocationType.Ground && diff --git a/src/GameWorldSimulator/NeoServer.Game.Common/Item/ItemAttribute.cs b/src/GameWorldSimulator/NeoServer.Game.Common/Item/ItemAttribute.cs index e7f0148fe..1af5eb0b5 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Common/Item/ItemAttribute.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Common/Item/ItemAttribute.cs @@ -207,5 +207,6 @@ public enum ItemAttribute : byte ManaUse, CooldownTime, UseOn, - DecayElapsed + DecayElapsed, + VocationNames } \ No newline at end of file diff --git a/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/Creature.cs b/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/Creature.cs index fb0e75cf5..46dbae080 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/Creature.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Creatures/Models/Bases/Creature.cs @@ -60,7 +60,7 @@ protected set public uint MaxHealthPoints { get; protected set; } public string Name => CreatureType.Name; - public string GetLookText(IInspectionTextBuilder inspectionTextBuilder, IPlayer player, bool isClose = false) + public string GetLookText(bool isClose = false, bool showInternalDetails = false) { return $"You see {(isClose ? CloseInspectionText : InspectionText)}"; } diff --git a/src/GameWorldSimulator/NeoServer.Game.Items/Bases/BaseItem.cs b/src/GameWorldSimulator/NeoServer.Game.Items/Bases/BaseItem.cs index 736d1ea54..47db1db48 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Items/Bases/BaseItem.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Items/Bases/BaseItem.cs @@ -5,6 +5,7 @@ using NeoServer.Game.Common.Contracts.Items.Types.Containers; using NeoServer.Game.Common.Location.Structs; using NeoServer.Game.Items.Factories.AttributeFactory; +using NeoServer.Game.Items.Inspection; namespace NeoServer.Game.Items.Bases; @@ -63,14 +64,14 @@ public void SetNewLocation(Location location) Location = location; } - public virtual string GetLookText(IInspectionTextBuilder inspectionTextBuilder, IPlayer player, - bool isClose = false) + public virtual string GetLookText( + bool isClose = false, bool showInternalDetails = false) { - return inspectionTextBuilder is null - ? $"You see {Metadata.Article} {Metadata.Name}." - : inspectionTextBuilder.Build(this, player, isClose); + return InspectionTextBuilder.IsApplicable(this) + ? InspectionTextBuilder.Build(this, isClose, showInternalDetails) + : $"You see {Metadata.Article} {Metadata.Name}."; } - + public string FullName => Metadata.FullName; public byte Amount { get; set; } = 1; diff --git a/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/InspectionTextBuilder.cs b/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/InspectionTextBuilder.cs index 674ad6712..a0e24425a 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/InspectionTextBuilder.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/InspectionTextBuilder.cs @@ -1,30 +1,20 @@ using System.Globalization; using System.Text; -using NeoServer.Game.Common.Contracts.Creatures; -using NeoServer.Game.Common.Contracts.DataStores; -using NeoServer.Game.Common.Contracts.Inspection; using NeoServer.Game.Common.Contracts.Items; using NeoServer.Game.Common.Contracts.Items.Types; using NeoServer.Game.Common.Helpers; namespace NeoServer.Game.Items.Inspection; -public class InspectionTextBuilder : IInspectionTextBuilder +public class InspectionTextBuilder { - private readonly IVocationStore _vocationStore; - - public InspectionTextBuilder(IVocationStore vocationStore) - { - _vocationStore = vocationStore; - } - - public string Build(IThing thing, IPlayer player, bool isClose = false) + public static string Build(IThing thing, bool isClose = false, bool showInternalDetails = false) { if (thing is not IItem item) return string.Empty; var inspectionText = new StringBuilder(); - AddItemName(item, player, inspectionText); + AddItemName(item, showInternalDetails, inspectionText); AddEquipmentAttributes(item, inspectionText); inspectionText.AppendNewLine("."); AddRequirement(item, inspectionText); @@ -37,14 +27,14 @@ public string Build(IThing thing, IPlayer player, bool isClose = false) return $"{finalText}"; } - public bool IsApplicable(IThing thing) + public static bool IsApplicable(IThing thing) { return thing is IItem; } - private void AddRequirement(IItem item, StringBuilder inspectionText) + private static void AddRequirement(IItem item, StringBuilder inspectionText) { - var result = RequirementInspectionTextBuilder.Build(item, _vocationStore); + var result = RequirementInspectionTextBuilder.Build(item); if (string.IsNullOrWhiteSpace(result)) return; inspectionText.AppendNewLine(result); } @@ -62,9 +52,9 @@ private static void AddWeight(IItem item, bool isClose, StringBuilder inspection $"{(item is ICumulative ? "They weigh" : "It weighs")} {item.Weight.ToString("F", CultureInfo.InvariantCulture)} oz."); } - private static void AddItemName(IItem item, IPlayer player, StringBuilder inspectionText) + private static void AddItemName(IItem item, bool showInternalDetails, StringBuilder inspectionText) { - if (player.CanSeeInspectionDetails) + if (showInternalDetails) inspectionText.AppendNewLine($"Id: [{item.ServerId}] - Pos: {item.Location}"); inspectionText.Append("You see "); diff --git a/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/RequirementInspectionTextBuilder.cs b/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/RequirementInspectionTextBuilder.cs index e23794911..c666f81a1 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/RequirementInspectionTextBuilder.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Items/Inspection/RequirementInspectionTextBuilder.cs @@ -1,21 +1,21 @@ using System.Text; -using NeoServer.Game.Common.Contracts.DataStores; using NeoServer.Game.Common.Contracts.Items; using NeoServer.Game.Common.Helpers; +using NeoServer.Game.Common.Item; namespace NeoServer.Game.Items.Inspection; public static class RequirementInspectionTextBuilder { - public static string Build(IItem item, IVocationStore vocationStore) + public static string Build(IItem item) { if (item is not IRequirement itemRequirement) return string.Empty; - var vocations = itemRequirement.Vocations; + var vocations = itemRequirement.Metadata.Attributes.GetAttributeArray(ItemAttribute.VocationNames); var minLevel = itemRequirement.MinLevel; if (Guard.IsNullOrEmpty(vocations) && minLevel == 0) return string.Empty; - var vocationsText = FormatVocations(vocations, vocationStore); + var vocationsText = FormatVocations(vocations); var verb = itemRequirement switch { @@ -29,14 +29,15 @@ public static string Build(IItem item, IVocationStore vocationStore) $"It can only be {verb} properly by {vocationsText}{(minLevel > 0 ? $" of level {minLevel} or higher" : string.Empty)}."; } - private static string FormatVocations(byte[] allVocations, IVocationStore vocationStore) + private static string FormatVocations(string[] allVocations) { if (Guard.IsNullOrEmpty(allVocations)) return "players"; var text = new StringBuilder(); for (var i = 0; i < allVocations.Length; i++) { - if (!vocationStore.TryGetValue(allVocations[i], out var vocation)) continue; - text.Append($"{vocation.Name.ToLower()}s"); + var vocation = allVocations[i]; + + text.Append($"{vocation.ToLower()}s"); var lastItem = i == allVocations.Length - 1; var penultimate = i == allVocations.Length - 2; if (lastItem) continue; diff --git a/src/GameWorldSimulator/NeoServer.Game.Items/Items/Sign.cs b/src/GameWorldSimulator/NeoServer.Game.Items/Items/Sign.cs index 5836eddfe..bb3bc5e02 100644 --- a/src/GameWorldSimulator/NeoServer.Game.Items/Items/Sign.cs +++ b/src/GameWorldSimulator/NeoServer.Game.Items/Items/Sign.cs @@ -22,10 +22,10 @@ public Sign(IItemType metadata, Location location, IDictionary string.Empty; public void Use(IPlayer usedBy) { diff --git a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs index f32f19a5b..bbc8cecbe 100644 --- a/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs +++ b/src/NetworkingServer/NeoServer.Networking.Handlers/LogIn/PlayerLogInHandler.cs @@ -20,17 +20,19 @@ public class PlayerLogInHandler : PacketHandler private readonly IGameServer _game; private readonly PlayerLogInCommand _playerLogInCommand; private readonly PlayerLogOutCommand _playerLogOutCommand; + private readonly ClientConfiguration _clientConfiguration; private readonly ServerConfiguration _serverConfiguration; public PlayerLogInHandler(IAccountRepository repositoryNeo, IGameServer game, ServerConfiguration serverConfiguration, PlayerLogInCommand playerLogInCommand, - PlayerLogOutCommand playerLogOutCommand) + PlayerLogOutCommand playerLogOutCommand, ClientConfiguration clientConfiguration) { _accountRepository = repositoryNeo; _game = game; _serverConfiguration = serverConfiguration; _playerLogInCommand = playerLogInCommand; _playerLogOutCommand = playerLogOutCommand; + _clientConfiguration = clientConfiguration; } public override void HandleMessage(IReadOnlyNetworkMessage message, IConnection connection) @@ -75,20 +77,26 @@ private async Task Connect(IConnection connection, PlayerLogInPacket packet) Disconnect(connection, "Your account is banned."); return; } - + + connection.OtcV8Version = packet.OtcV8Version; + if (packet.OtcV8Version > 0 || packet.OperatingSystem >= OperatingSystem.OtcLinux) + { + if (packet.OtcV8Version > 0) connection.Send(new FeaturesPacket + { + GameEnvironmentEffect = _clientConfiguration.OtcV8.GameEnvironmentEffect, + GameExtendedOpcode = _clientConfiguration.OtcV8.GameExtendedOpcode, + GameExtendedClientPing = _clientConfiguration.OtcV8.GameExtendedClientPing, + GameItemTooltip = _clientConfiguration.OtcV8.GameItemTooltip + }); + connection.Send(new OpcodeMessagePacket()); + } + _game.Dispatcher.AddEvent(new Event(() => { var result = _playerLogInCommand.Execute(playerRecord, connection); if (result.Failed) { Disconnect(connection, TextMessageOutgoingParser.Parse(result.Error)); - return; - } - - if (packet.OtcV8Version > 0 || packet.OperatingSystem >= OperatingSystem.OtcLinux) - { - if (packet.OtcV8Version > 0) connection.Send(new FeaturesPacket()); - connection.Send(new OpcodeMessagePacket()); } })); } diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs index 1bea74383..6cc342190 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Connection/Connection.cs @@ -62,6 +62,7 @@ private bool Closed public long LastPingResponse { get; set; } public long TimeStamp { get; } public byte RandomNumber { get; } + public ushort OtcV8Version { get; set; } public event EventHandler OnProcessEvent; public event EventHandler OnCloseEvent; public event EventHandler OnPostProcessEvent; diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs index 9d559efd9..ac085ac9e 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Messages/NetworkMessage.cs @@ -60,13 +60,18 @@ public void AddString(string value) /// Inserts item object into the buffer. /// /// - public void AddItem(IItem item) + public void AddItem(IItem item, bool showItemDescription = false) { if (item == null) //todo log return; AddBytes(item.GetRaw().ToArray()); + + if (showItemDescription) + { + AddString(item.GetLookText(true)); + } } /// diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs index f672c274a..dc5188ca7 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Custom/FeaturesPacket.cs @@ -5,6 +5,10 @@ namespace NeoServer.Networking.Packets.Outgoing.Custom; public class FeaturesPacket : OutgoingPacket { + public required bool GameExtendedOpcode { get; init; } + public required bool GameEnvironmentEffect { get; init; } + public required bool GameExtendedClientPing { get; init; } + public required bool GameItemTooltip { get; init; } public override void WriteToMessage(INetworkMessage message) { message.AddByte(0x43); @@ -12,15 +16,24 @@ public override void WriteToMessage(INetworkMessage message) var features = new Dictionary { - [80] = true, - [13] = false, - [25] = true, - [93] = true + [(byte)Feature.GameExtendedOpcode] = GameExtendedOpcode, + [(byte)Feature.GameEnvironmentEffect] = GameEnvironmentEffect, + [(byte)Feature.GameExtendedClientPing] = GameExtendedClientPing, + [(byte)Feature.GameItemTooltip] = GameItemTooltip }; + foreach (var feature in features) { message.AddByte(feature.Key); message.AddByte((byte)(feature.Value ? 1 : 0)); } } + + private enum Feature : byte + { + GameExtendedOpcode = 80, + GameEnvironmentEffect = 13, + GameExtendedClientPing = 25, + GameItemTooltip = 93 + } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/AddItemContainerPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/AddItemContainerPacket.cs index 34e7ce3d5..9daa77cc1 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/AddItemContainerPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/AddItemContainerPacket.cs @@ -7,6 +7,7 @@ public class AddItemContainerPacket : OutgoingPacket { private readonly byte containerId; private readonly IItem item; + public required bool ShowItemDescription { get; init; } public AddItemContainerPacket(byte containerId, IItem item) { @@ -14,11 +15,12 @@ public AddItemContainerPacket(byte containerId, IItem item) this.item = item; } + public override void WriteToMessage(INetworkMessage message) { message.AddByte((byte)GameOutgoingPacketType.ContainerAddItem); message.AddByte(containerId); - message.AddItem(item); + message.AddItem(item, ShowItemDescription); } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/UpdateItemContainerPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/UpdateItemContainerPacket.cs index f83745add..834b094bc 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/UpdateItemContainerPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Item/UpdateItemContainerPacket.cs @@ -16,12 +16,14 @@ public UpdateItemContainerPacket(byte containerId, byte slot, IItem item) this.slot = slot; } + public required bool ShowItemDescription { get; init; } + public override void WriteToMessage(INetworkMessage message) { message.AddByte((byte)GameOutgoingPacketType.ContainerUpdateItem); message.AddByte(containerId); message.AddByte(slot); - message.AddItem(item); + message.AddItem(item, ShowItemDescription); } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/OpenContainerPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/OpenContainerPacket.cs index db211ef2b..877d5a0c4 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/OpenContainerPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/OpenContainerPacket.cs @@ -8,6 +8,7 @@ public class OpenContainerPacket : OutgoingPacket { private readonly IContainer container; private readonly byte containerId; + public required bool WithDescription { get; init; } public OpenContainerPacket(IContainer container, byte containerId) { @@ -20,7 +21,7 @@ public override void WriteToMessage(INetworkMessage message) message.AddByte((byte)GameOutgoingPacketType.ContainerOpen); message.AddByte(containerId); - message.AddItem(container); + message.AddItem(container, WithDescription); message.AddString(container.Name); message.AddByte(container.Capacity); @@ -28,6 +29,6 @@ public override void WriteToMessage(INetworkMessage message) message.AddByte(Math.Min((byte)0xFF, container.SlotsUsed)); - for (byte i = 0; i < container.SlotsUsed; i++) message.AddItem(container.Items[i]); + for (byte i = 0; i < container.SlotsUsed; i++) message.AddItem(container.Items[i], WithDescription); } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryItemPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryItemPacket.cs index 2cce908d6..472eb176b 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryItemPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryItemPacket.cs @@ -8,6 +8,7 @@ public class PlayerInventoryItemPacket : OutgoingPacket { private readonly IInventory inventory; private readonly Slot slot; + public required bool ShowItemDescription { get; init; } public PlayerInventoryItemPacket(IInventory inventory, Slot slot) { @@ -26,7 +27,7 @@ public override void WriteToMessage(INetworkMessage message) { message.AddByte((byte)GameOutgoingPacketType.InventoryItem); message.AddByte((byte)slot); - message.AddItem(inventory[slot]); + message.AddItem(inventory[slot], ShowItemDescription); } } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs index 9cd2011df..757067742 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Player/PlayerInventoryPacket.cs @@ -8,6 +8,7 @@ namespace NeoServer.Networking.Packets.Outgoing.Player; public class PlayerInventoryPacket : OutgoingPacket { private readonly IInventory inventory; + public required bool ShowItemDescription { get; init; } public PlayerInventoryPacket(IInventory inventory) { @@ -16,7 +17,7 @@ public PlayerInventoryPacket(IInventory inventory) public override void WriteToMessage(INetworkMessage message) { - var addInventoryItem = new Action(slot => + void SendInventoryItem(Slot slot) { if (inventory[slot] == null) { @@ -27,19 +28,19 @@ public override void WriteToMessage(INetworkMessage message) { message.AddByte((byte)GameOutgoingPacketType.InventoryItem); message.AddByte((byte)slot); - message.AddItem(inventory[slot]); + message.AddItem(inventory[slot], ShowItemDescription); } - }); + }; - addInventoryItem(Slot.Head); - addInventoryItem(Slot.Necklace); - addInventoryItem(Slot.Backpack); - addInventoryItem(Slot.Body); - addInventoryItem(Slot.Right); - addInventoryItem(Slot.Left); - addInventoryItem(Slot.Legs); - addInventoryItem(Slot.Feet); - addInventoryItem(Slot.Ring); - addInventoryItem(Slot.Ammo); + SendInventoryItem(Slot.Head); + SendInventoryItem(Slot.Necklace); + SendInventoryItem(Slot.Backpack); + SendInventoryItem(Slot.Body); + SendInventoryItem(Slot.Right); + SendInventoryItem(Slot.Left); + SendInventoryItem(Slot.Legs); + SendInventoryItem(Slot.Feet); + SendInventoryItem(Slot.Ring); + SendInventoryItem(Slot.Ammo); } } \ No newline at end of file diff --git a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Trade/TradeRequestPacket.cs b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Trade/TradeRequestPacket.cs index 15121ff8a..c42eef4c3 100644 --- a/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Trade/TradeRequestPacket.cs +++ b/src/NetworkingServer/NeoServer.Networking.Packets/Outgoing/Trade/TradeRequestPacket.cs @@ -15,7 +15,7 @@ public TradeRequestPacket(string playerName, IItem[] items, bool acknowledged = private string PlayerName { get; } private IItem[] Items { get; } private bool Acknowledged { get; } - + public required bool ShowItemDescription { get; init; } public void WriteToMessage(INetworkMessage message) { message.AddByte(Acknowledged @@ -25,6 +25,6 @@ public void WriteToMessage(INetworkMessage message) message.AddString(PlayerName); message.AddByte((byte)Items.Length); - foreach (var item in Items) message.AddItem(item); + foreach (var item in Items) message.AddItem(item, ShowItemDescription); } } \ No newline at end of file diff --git a/src/Standalone/IoC/Modules/ConfigurationInjection.cs b/src/Standalone/IoC/Modules/ConfigurationInjection.cs index d7d255d1d..1efcb542b 100644 --- a/src/Standalone/IoC/Modules/ConfigurationInjection.cs +++ b/src/Standalone/IoC/Modules/ConfigurationInjection.cs @@ -32,16 +32,19 @@ public static IServiceCollection AddConfigurations(this IServiceCollection build new(0, null, null, null, string.Empty, string.Empty, string.Empty, 7171, 7172,new SaveConfiguration(3600), string.Empty); GameConfiguration gameConfiguration = new(); LogConfiguration logConfiguration = new(null); + ClientConfiguration clientConfiguration = new(null); configuration.GetSection("server").Bind(serverConfiguration); configuration.GetSection("game").Bind(gameConfiguration); configuration.GetSection("log").Bind(logConfiguration); + configuration.GetSection("client").Bind(clientConfiguration); LoadEnvironmentVariables(ref serverConfiguration); builder.AddSingleton(serverConfiguration); builder.AddSingleton(gameConfiguration); builder.AddSingleton(logConfiguration); + builder.AddSingleton(clientConfiguration); return builder; } diff --git a/src/Standalone/appsettings.json b/src/Standalone/appsettings.json index e0e38f850..e5d4b6184 100644 --- a/src/Standalone/appsettings.json +++ b/src/Standalone/appsettings.json @@ -30,6 +30,14 @@ "fishing": 1.5 } }, + "client": { + "otcv8": { + "GameExtendedOpcode": false, + "GameEnvironmentEffect": false, + "GameExtendedClientPing": true, + "GameItemTooltip": true + } + }, "database": { "connections": { "INMEMORY": "neo", diff --git a/tests/NeoServer.Game.Items.Tests/Inspection/InspectionTextBuilderTest.cs b/tests/NeoServer.Game.Items.Tests/Inspection/InspectionTextBuilderTest.cs index 7006aa249..faca9cba8 100644 --- a/tests/NeoServer.Game.Items.Tests/Inspection/InspectionTextBuilderTest.cs +++ b/tests/NeoServer.Game.Items.Tests/Inspection/InspectionTextBuilderTest.cs @@ -14,29 +14,17 @@ public class InspectionTextBuilderTest { [Theory] [InlineData("You see item.")] - [InlineData("You see item.\nIt can only be wielded properly by knights and paladins.", 1, 2)] - [InlineData("You see item.\nIt can only be wielded properly by knights.", 1)] - [InlineData("You see item.\nIt can only be wielded properly by knights, paladins and sorcerers.", 1, 2, 3)] - [InlineData("You see item.\nIt can only be wielded properly by knights, paladins, sorcerers and druids.", 1, 2, 3, - 4)] - public void Add_HasVocations_ReturnText(string expected, params int[] vocations) + [InlineData("You see item.\nIt can only be wielded properly by knights and paladins.", "knight", "paladin")] + [InlineData("You see item.\nIt can only be wielded properly by knights.", "knight")] + [InlineData("You see item.\nIt can only be wielded properly by knights, paladins and sorcerers.", "knight", "paladin", "sorcerer")] + [InlineData("You see item.\nIt can only be wielded properly by knights, paladins, sorcerers and druids.", "knight", "paladin", "sorcerer", "druid")] + public void Add_HasVocations_ReturnText(string expected, params string[] vocations) { - var vocationStore = new VocationStore(); - vocationStore.Add(1, new Vocation { Name = "Knight" }); - vocationStore.Add(2, new Vocation { Name = "Paladin" }); - vocationStore.Add(3, new Vocation { Name = "Sorcerer" }); - vocationStore.Add(4, new Vocation { Name = "Druid" }); - - var input = vocations.Select(x => (byte)x).ToArray(); - var item = ItemTestData.CreateDefenseEquipmentItem(1); - item.Metadata.Attributes.SetAttribute(ItemAttribute.Vocation, input); - - var player = PlayerTestDataBuilder.Build(hp: 200); - var inspectionTextBuilder = new InspectionTextBuilder(vocationStore); - + item.Metadata.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); + //act - var actual = inspectionTextBuilder.Build(item, player); + var actual = InspectionTextBuilder.Build(item); //assert actual.Should().Be(expected); diff --git a/tests/NeoServer.Game.Items.Tests/Inspection/RequirementInspectionTextBuilderTests.cs b/tests/NeoServer.Game.Items.Tests/Inspection/RequirementInspectionTextBuilderTests.cs index 86990b829..de3cb6e10 100644 --- a/tests/NeoServer.Game.Items.Tests/Inspection/RequirementInspectionTextBuilderTests.cs +++ b/tests/NeoServer.Game.Items.Tests/Inspection/RequirementInspectionTextBuilderTests.cs @@ -13,25 +13,17 @@ public class RequirementInspectionTextBuilderTests { [Theory] [InlineData("")] - [InlineData("It can only be wielded properly by knights and paladins.", 1, 2)] - [InlineData("It can only be wielded properly by knights, paladins and sorcerers.", 1, 2, 3)] - [InlineData("It can only be wielded properly by knights, paladins, sorcerers and druids.", 1, 2, 3, 4)] - [InlineData("It can only be wielded properly by knights, sorcerers and druids.", 1, 10, 3, 4)] - public void Add_HasVocations_ReturnText(string expected, params int[] vocations) + [InlineData("It can only be wielded properly by knights and paladins.", "knight", "paladin")] + [InlineData("It can only be wielded properly by knights, paladins and sorcerers.", "knight", "paladin", "sorcerer")] + [InlineData("It can only be wielded properly by knights, paladins, sorcerers and druids.", "knight", "paladin", "sorcerer", "druid")] + [InlineData("It can only be wielded properly by knights, sorcerers and druids.", "knight", "sorcerer", "druid")] + public void Add_HasVocations_ReturnText(string expected, params string[] vocations) { - var vocationStore = new VocationStore(); - vocationStore.Add(1, new Vocation { Name = "Knight" }); - vocationStore.Add(2, new Vocation { Name = "Paladin" }); - vocationStore.Add(3, new Vocation { Name = "Sorcerer" }); - vocationStore.Add(4, new Vocation { Name = "Druid" }); - - var input = vocations.Select(x => (byte)x).ToArray(); - var item = ItemTestData.CreateDefenseEquipmentItem(1); - item.Metadata.Attributes.SetAttribute(ItemAttribute.Vocation, input); + item.Metadata.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); //act - var actual = RequirementInspectionTextBuilder.Build(item, vocationStore); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().Be(expected); @@ -48,34 +40,27 @@ public void Add_HasLevel_ReturnText(string expected, int level) item.Metadata.Attributes.SetAttribute(ItemAttribute.MinimumLevel, level); //act - var actual = RequirementInspectionTextBuilder.Build(item, null); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().Be(expected); } [Theory] - [InlineData("It can only be wielded properly by knights of level 10 or higher.", 10, 1)] - [InlineData("It can only be wielded properly by knights and paladins of level 1 or higher.", 1, 1, 2)] - [InlineData("It can only be wielded properly by knights, paladins and sorcerers of level 200 or higher.", 200, 1, 2, - 3)] + [InlineData("It can only be wielded properly by knights of level 10 or higher.", 10, "knight")] + [InlineData("It can only be wielded properly by knights and paladins of level 1 or higher.", 1, "knight", + "paladin")] + [InlineData("It can only be wielded properly by knights, paladins and sorcerers of level 200 or higher.", 200, + "knight", "paladin", "sorcerer")] [InlineData("", 0)] - public void Add_HasLevelAndVocations_ReturnText(string expected, int level, params int[] vocations) + public void Add_HasLevelAndVocations_ReturnText(string expected, int level, params string[] vocations) { - var vocationStore = new VocationStore(); - vocationStore.Add(1, new Vocation { Name = "Knight" }); - vocationStore.Add(2, new Vocation { Name = "Paladin" }); - vocationStore.Add(3, new Vocation { Name = "Sorcerer" }); - vocationStore.Add(4, new Vocation { Name = "Druid" }); - - var input = vocations.Select(x => (byte)x).ToArray(); - var item = ItemTestData.CreateDefenseEquipmentItem(1); item.Metadata.Attributes.SetAttribute(ItemAttribute.MinimumLevel, level); - item.Metadata.Attributes.SetAttribute(ItemAttribute.Vocation, input); + item.Metadata.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); //act - var actual = RequirementInspectionTextBuilder.Build(item, vocationStore); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().Be(expected); @@ -86,61 +71,43 @@ public void Add_HasNoRequirement_ReturnEmpty() { var item = ItemTestData.CreateCoin(1, 10, 1); //act - var actual = RequirementInspectionTextBuilder.Build(item, null); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().BeEmpty(); } [Theory] - [InlineData("It can only be used properly by knights of level 10 or higher.", 10, 1)] - [InlineData("It can only be used properly by knights and paladins of level 1 or higher.", 1, 1, 2)] - [InlineData("It can only be used properly by knights, paladins and sorcerers of level 200 or higher.", 200, 1, 2, - 3)] + [InlineData("It can only be used properly by knights of level 10 or higher.", 10, "knight")] + [InlineData("It can only be used properly by knights and paladins of level 1 or higher.", 1, "knight", "paladin")] + [InlineData("It can only be used properly by knights, paladins and sorcerers of level 200 or higher.", 200, "knight", "paladin", "sorcerer")] [InlineData("", 0)] - public void Build_UsableHasLevelAndVocations_ReturnText(string expected, int level, params int[] vocations) + public void Build_UsableHasLevelAndVocations_ReturnText(string expected, int level, params string[] vocations) { - var vocationStore = new VocationStore(); - vocationStore.Add(1, new Vocation { Name = "Knight" }); - vocationStore.Add(2, new Vocation { Name = "Paladin" }); - vocationStore.Add(3, new Vocation { Name = "Sorcerer" }); - vocationStore.Add(4, new Vocation { Name = "Druid" }); - - var input = vocations.Select(x => (byte)x).ToArray(); - var item = ItemTestData.CreateAttackRune(1); item.Metadata.Attributes.SetAttribute(ItemAttribute.MinimumLevel, level); - item.Metadata.Attributes.SetAttribute(ItemAttribute.Vocation, input); + item.Metadata.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); //act - var actual = RequirementInspectionTextBuilder.Build(item, vocationStore); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().Be(expected); } [Theory] - [InlineData("It can only be consumed properly by knights of level 10 or higher.", 10, 1)] - [InlineData("It can only be consumed properly by knights and paladins of level 1 or higher.", 1, 1, 2)] - [InlineData("It can only be consumed properly by knights, paladins and sorcerers of level 200 or higher.", 200, 1, - 2, 3)] + [InlineData("It can only be consumed properly by knights of level 10 or higher.", 10, "knight")] + [InlineData("It can only be consumed properly by knights and paladins of level 1 or higher.", 1, "knight", "paladin")] + [InlineData("It can only be consumed properly by knights, paladins and sorcerers of level 200 or higher.", 200, "knight", "paladin", "sorcerer")] [InlineData("", 0)] - public void Build_ConsumableHasLevelAndVocations_ReturnText(string expected, int level, params int[] vocations) + public void Build_ConsumableHasLevelAndVocations_ReturnText(string expected, int level, params string[] vocations) { - var vocationStore = new VocationStore(); - vocationStore.Add(1, new Vocation { Name = "Knight" }); - vocationStore.Add(2, new Vocation { Name = "Paladin" }); - vocationStore.Add(3, new Vocation { Name = "Sorcerer" }); - vocationStore.Add(4, new Vocation { Name = "Druid" }); - - var input = vocations.Select(x => (byte)x).ToArray(); - var item = ItemTestData.CreatePot(1); item.Metadata.Attributes.SetAttribute(ItemAttribute.MinimumLevel, level); - item.Metadata.Attributes.SetAttribute(ItemAttribute.Vocation, input); + item.Metadata.Attributes.SetAttribute(ItemAttribute.VocationNames, vocations); //act - var actual = RequirementInspectionTextBuilder.Build(item, vocationStore); + var actual = RequirementInspectionTextBuilder.Build(item); //assert actual.Should().Be(expected);