From 0da49e5ba94340bc19669ee94f387a8c87c9efa3 Mon Sep 17 00:00:00 2001 From: LP Date: Mon, 8 Dec 2025 13:01:33 +0000 Subject: [PATCH 001/153] Bumped everything to dotnet 10 and C# 14 --- build/pack.bat | 5 +++-- .../OpenRpg.AdviceEngine.Rx.csproj | 4 ++-- .../Extensions/UtilityExtensions.cs | 18 ++++-------------- .../OpenRpg.AdviceEngine.csproj | 4 ++-- src/OpenRpg.Cards/OpenRpg.Cards.csproj | 4 ++-- src/OpenRpg.Combat/OpenRpg.Combat.csproj | 4 ++-- src/OpenRpg.Core/OpenRpg.Core.csproj | 4 ++-- .../OpenRpg.CurveFunctions.csproj | 4 ++-- .../OpenRpg.Data.Database.csproj | 4 ++-- .../OpenRpg.Data.InMemory.csproj | 4 ++-- .../OpenRpg.Data.LiteDB.csproj | 4 ++-- src/OpenRpg.Data/OpenRpg.Data.csproj | 4 ++-- .../OpenRpg.Demos.Infrastructure.csproj | 4 ++-- src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj | 4 ++-- .../OpenRpg.Editor.Core.csproj | 4 ++-- .../OpenRpg.Editor.Infrastructure.csproj | 4 ++-- src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj | 4 ++-- src/OpenRpg.Editor/OpenRpg.Editor.csproj | 4 ++-- src/OpenRpg.Entities/OpenRpg.Entities.csproj | 4 ++-- .../OpenRpg.Genres.Fantasy.csproj | 4 ++-- .../OpenRpg.Genres.Scifi.csproj | 4 ++-- src/OpenRpg.Genres/OpenRpg.Genres.csproj | 4 ++-- .../OpenRpg.Items.TradeSkills.csproj | 4 ++-- src/OpenRpg.Items/OpenRpg.Items.csproj | 4 ++-- .../OpenRpg.Localization.csproj | 4 ++-- src/OpenRpg.Quests/OpenRpg.Quests.csproj | 4 ++-- src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj | 4 ++-- 27 files changed, 57 insertions(+), 66 deletions(-) diff --git a/build/pack.bat b/build/pack.bat index bce98d80..afab125c 100644 --- a/build/pack.bat +++ b/build/pack.bat @@ -1,4 +1,4 @@ -set version=0.29.00 +set version=0.43.00 dotnet pack ../src/OpenRpg.Core -c Release -o ../../_dist /p:version=%version% dotnet pack ../src/OpenRpg.Items -c Release -o ../../_dist /p:version=%version% dotnet pack ../src/OpenRpg.Combat -c Release -o ../../_dist /p:version=%version% @@ -11,4 +11,5 @@ dotnet pack ../src/OpenRpg.Genres.Fantasy -c Release -o ../../_dist /p:version=% dotnet pack ../src/OpenRpg.Cards -c Release -o ../../_dist /p:version=%version% dotnet pack ../src/OpenRpg.CurveFunctions -c Release -o ../../_dist /p:version=%version% dotnet pack ../src/OpenRpg.Tags -c Release -o ../../_dist /p:version=%version% -dotnet pack ../src/OpenRpg.Items.TradeSkills -c Release -o ../../_dist /p:version=%version% \ No newline at end of file +dotnet pack ../src/OpenRpg.Items.TradeSkills -c Release -o ../../_dist /p:version=%version% +dotnet pack ../src/OpenRpg.AdviceEngine.Rx -c Release -o ../../_dist /p:version=%version% \ No newline at end of file diff --git a/src/OpenRpg.AdviceEngine.Rx/OpenRpg.AdviceEngine.Rx.csproj b/src/OpenRpg.AdviceEngine.Rx/OpenRpg.AdviceEngine.Rx.csproj index 2150f822..edd6663f 100644 --- a/src/OpenRpg.AdviceEngine.Rx/OpenRpg.AdviceEngine.Rx.csproj +++ b/src/OpenRpg.AdviceEngine.Rx/OpenRpg.AdviceEngine.Rx.csproj @@ -8,8 +8,8 @@ https://github.com/openrpg/OpenRpg A Utility AI flavoured framework to provide advice about what entities should do rpg game-development xna monogame unity godot rx - netstandard2.1 - 8 + net10.0 + 14 diff --git a/src/OpenRpg.AdviceEngine/Extensions/UtilityExtensions.cs b/src/OpenRpg.AdviceEngine/Extensions/UtilityExtensions.cs index 172f832d..93de8e44 100644 --- a/src/OpenRpg.AdviceEngine/Extensions/UtilityExtensions.cs +++ b/src/OpenRpg.AdviceEngine/Extensions/UtilityExtensions.cs @@ -8,24 +8,14 @@ public static class UtilityExtensions { public static float CalculateScore(this IReadOnlyCollection> variableUtilities) { return CalculateScore(variableUtilities.Select(x => x.Value).ToArray()); } - - public static float CalculateScore(this IReadOnlyCollection utilities) - { - var score = 1.0f; - var compensationFactor = (float)(1.0 - 1.0 / utilities.Count); - foreach (var utility in utilities) - { - var modification = (float)((1.0 - utility) * compensationFactor); - var scaledUtility = utility + (modification * utility); - score *= scaledUtility; - } - return score; - } public static float CalculateScore(params float[] utilities) + { return CalculateScore(utilities as IReadOnlyCollection); } + + public static float CalculateScore(this IReadOnlyCollection utilities) { var score = 1.0f; - var compensationFactor = (float)(1.0 - 1.0 / utilities.Length); + var compensationFactor = (float)(1.0 - 1.0 / utilities.Count); foreach (var utility in utilities) { var modification = (float)((1.0 - utility) * compensationFactor); diff --git a/src/OpenRpg.AdviceEngine/OpenRpg.AdviceEngine.csproj b/src/OpenRpg.AdviceEngine/OpenRpg.AdviceEngine.csproj index 57e5c187..15692de4 100644 --- a/src/OpenRpg.AdviceEngine/OpenRpg.AdviceEngine.csproj +++ b/src/OpenRpg.AdviceEngine/OpenRpg.AdviceEngine.csproj @@ -8,8 +8,8 @@ https://github.com/openrpg/OpenRpg.AdviceEngine A Utility AI flavoured framework to provide advice about what entities should do rpg game-development xna monogame unity godot - netstandard2.1 - 8 + net10.0 + 14 diff --git a/src/OpenRpg.Cards/OpenRpg.Cards.csproj b/src/OpenRpg.Cards/OpenRpg.Cards.csproj index ac6c473b..d542ff47 100644 --- a/src/OpenRpg.Cards/OpenRpg.Cards.csproj +++ b/src/OpenRpg.Cards/OpenRpg.Cards.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Cards Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg Adds a basic starting point for wrapping objects as cards for card game scenarios rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Combat/OpenRpg.Combat.csproj b/src/OpenRpg.Combat/OpenRpg.Combat.csproj index 6bf19d92..b2568cef 100644 --- a/src/OpenRpg.Combat/OpenRpg.Combat.csproj +++ b/src/OpenRpg.Combat/OpenRpg.Combat.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Combat Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg Adds basic combat related types for building off rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Core/OpenRpg.Core.csproj b/src/OpenRpg.Core/OpenRpg.Core.csproj index 0e58b9ed..0eb2263e 100644 --- a/src/OpenRpg.Core/OpenRpg.Core.csproj +++ b/src/OpenRpg.Core/OpenRpg.Core.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Core Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg An open source set of base components to build RPG games rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.CurveFunctions/OpenRpg.CurveFunctions.csproj b/src/OpenRpg.CurveFunctions/OpenRpg.CurveFunctions.csproj index c623a572..dfb9464b 100644 --- a/src/OpenRpg.CurveFunctions/OpenRpg.CurveFunctions.csproj +++ b/src/OpenRpg.CurveFunctions/OpenRpg.CurveFunctions.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.CurveFunctions Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg Adds premade curve functions for scaling values or other use cases rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj b/src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj index b1f32b01..1cb87614 100644 --- a/src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj +++ b/src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Data.Database Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg An SQL database implementation of the OpenRpg data layer using Dapper rpg game-development repository data xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Data.InMemory/OpenRpg.Data.InMemory.csproj b/src/OpenRpg.Data.InMemory/OpenRpg.Data.InMemory.csproj index 2261e073..2a83a29d 100644 --- a/src/OpenRpg.Data.InMemory/OpenRpg.Data.InMemory.csproj +++ b/src/OpenRpg.Data.InMemory/OpenRpg.Data.InMemory.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Data.InMemory Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg An in memory implementation of the OpenRpg data layer rpg game-development repository data xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Data.LiteDB/OpenRpg.Data.LiteDB.csproj b/src/OpenRpg.Data.LiteDB/OpenRpg.Data.LiteDB.csproj index 8f25d9be..6ca3fda3 100644 --- a/src/OpenRpg.Data.LiteDB/OpenRpg.Data.LiteDB.csproj +++ b/src/OpenRpg.Data.LiteDB/OpenRpg.Data.LiteDB.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Data.LiteDB Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg A LiteDB implementation of the OpenRpg data layer rpg game-development repository data xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Data/OpenRpg.Data.csproj b/src/OpenRpg.Data/OpenRpg.Data.csproj index f049cf0e..a333174f 100644 --- a/src/OpenRpg.Data/OpenRpg.Data.csproj +++ b/src/OpenRpg.Data/OpenRpg.Data.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Data Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg A set of data oriented patterns that can simplify managing your game data with OpenRpg rpg game-development repository data xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj b/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj index 43b41259..347b8d50 100644 --- a/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj +++ b/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj @@ -1,8 +1,8 @@  - net9.0 - 13 + net10.0 + 14 false diff --git a/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj b/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj index 88439617..0c974e79 100644 --- a/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj +++ b/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj @@ -1,10 +1,10 @@ - net9.0 + net10.0 enable enable - 13 + 14 false diff --git a/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj b/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj index 9d3ab549..0f3dffa3 100644 --- a/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj +++ b/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj @@ -1,8 +1,8 @@ - net9.0 - 13 + net10.0 + 14 false diff --git a/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj b/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj index d8255283..76d0817d 100644 --- a/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj +++ b/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj @@ -1,8 +1,8 @@ - net9.0 - 13 + net10.0 + 14 false diff --git a/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj b/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj index f6b52eec..346784a9 100644 --- a/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj +++ b/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj @@ -1,8 +1,8 @@ - net9.0 - 13 + net10.0 + 14 false diff --git a/src/OpenRpg.Editor/OpenRpg.Editor.csproj b/src/OpenRpg.Editor/OpenRpg.Editor.csproj index fa915a29..c63b185e 100644 --- a/src/OpenRpg.Editor/OpenRpg.Editor.csproj +++ b/src/OpenRpg.Editor/OpenRpg.Editor.csproj @@ -1,8 +1,8 @@ - net9.0 - 13 + net10.0 + 14 openrpg.ico false false diff --git a/src/OpenRpg.Entities/OpenRpg.Entities.csproj b/src/OpenRpg.Entities/OpenRpg.Entities.csproj index 17e901d7..0b7914f5 100644 --- a/src/OpenRpg.Entities/OpenRpg.Entities.csproj +++ b/src/OpenRpg.Entities/OpenRpg.Entities.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Entities Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg An open source set of base components to build RPG games rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Genres.Fantasy/OpenRpg.Genres.Fantasy.csproj b/src/OpenRpg.Genres.Fantasy/OpenRpg.Genres.Fantasy.csproj index 5b3776c0..9df0b32b 100644 --- a/src/OpenRpg.Genres.Fantasy/OpenRpg.Genres.Fantasy.csproj +++ b/src/OpenRpg.Genres.Fantasy/OpenRpg.Genres.Fantasy.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Genres.Fantasy Grofit (LP) https://github.com/openrpg/OpenRpg.Genres/blob/master/LICENSE https://github.com/openrpg/OpenRpg.Genres Adds common types and classes for fantasy style settings rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Genres.Scifi/OpenRpg.Genres.Scifi.csproj b/src/OpenRpg.Genres.Scifi/OpenRpg.Genres.Scifi.csproj index 40f693b7..f5ae2358 100644 --- a/src/OpenRpg.Genres.Scifi/OpenRpg.Genres.Scifi.csproj +++ b/src/OpenRpg.Genres.Scifi/OpenRpg.Genres.Scifi.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Genres.Scifi Grofit (LP) https://github.com/openrpg/OpenRpg.Genres/blob/master/LICENSE https://github.com/openrpg/OpenRpg.Genres Adds common types and classes for scifi/space ship related game types rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Genres/OpenRpg.Genres.csproj b/src/OpenRpg.Genres/OpenRpg.Genres.csproj index 5fb919f8..30f64379 100644 --- a/src/OpenRpg.Genres/OpenRpg.Genres.csproj +++ b/src/OpenRpg.Genres/OpenRpg.Genres.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Genres Grofit (LP) https://github.com/openrpg/OpenRpg.Genres/blob/master/LICENSE https://github.com/openrpg/OpenRpg.Genres Adds common types and classes for various genres to build off rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Items.TradeSkills/OpenRpg.Items.TradeSkills.csproj b/src/OpenRpg.Items.TradeSkills/OpenRpg.Items.TradeSkills.csproj index 4486a8c5..e9e2fe69 100644 --- a/src/OpenRpg.Items.TradeSkills/OpenRpg.Items.TradeSkills.csproj +++ b/src/OpenRpg.Items.TradeSkills/OpenRpg.Items.TradeSkills.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Items.TradeSkills Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg Adds the notion of trade skills such as gathering or crafting to OpenRpg rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Items/OpenRpg.Items.csproj b/src/OpenRpg.Items/OpenRpg.Items.csproj index beaae259..62e38126 100644 --- a/src/OpenRpg.Items/OpenRpg.Items.csproj +++ b/src/OpenRpg.Items/OpenRpg.Items.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Items Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg Adds the notion of items to OpenRpg rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Localization/OpenRpg.Localization.csproj b/src/OpenRpg.Localization/OpenRpg.Localization.csproj index 5731d96e..0154e137 100644 --- a/src/OpenRpg.Localization/OpenRpg.Localization.csproj +++ b/src/OpenRpg.Localization/OpenRpg.Localization.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Localization Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg Basic classes to assist in management of multi language content rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.Quests/OpenRpg.Quests.csproj b/src/OpenRpg.Quests/OpenRpg.Quests.csproj index a64c3cae..d2034ce9 100644 --- a/src/OpenRpg.Quests/OpenRpg.Quests.csproj +++ b/src/OpenRpg.Quests/OpenRpg.Quests.csproj @@ -2,14 +2,14 @@ 0.0.0 - netstandard2.1 + net10.0 OpenRpg.Quests Grofit (LP) https://github.com/openrpg/OpenRpg/blob/master/LICENSE https://github.com/openrpg/OpenRpg Adds the notion of quests to OpenRpg rpg game-development xna monogame unity godot - 8 + 14 diff --git a/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj b/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj index 1a83aad5..b6c26347 100644 --- a/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj +++ b/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj @@ -1,12 +1,12 @@ - net9.0 + net10.0 enable false - 13 + 14 From 77977e6af791b1f0d793fcd09005c24c21d04bab Mon Sep 17 00:00:00 2001 From: LP Date: Mon, 8 Dec 2025 13:06:13 +0000 Subject: [PATCH 002/153] Updated project extensions --- .../Extensions/LoadedProjectExtensions.cs | 13 ++++++++++--- .../Persistence/CreateProjectExecutor.cs | 6 +++--- .../Persistence/LoadProjectExecutor.cs | 8 ++++---- .../Persistence/SaveProjectExecutor.cs | 10 +++++----- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/OpenRpg.Editor.Core/Extensions/LoadedProjectExtensions.cs b/src/OpenRpg.Editor.Core/Extensions/LoadedProjectExtensions.cs index 6ceafc0d..51125925 100644 --- a/src/OpenRpg.Editor.Core/Extensions/LoadedProjectExtensions.cs +++ b/src/OpenRpg.Editor.Core/Extensions/LoadedProjectExtensions.cs @@ -6,21 +6,28 @@ namespace OpenRpg.Editor.Core.Extensions; public static class LoadedProjectExtensions { - public static string GetTemplatePath(this LoadedProject project) + extension(LoadedProject project) + { + public string TemplatePath => GetTemplatePath(project); + public string LocalePath => GetLocalePath(project); + public string AssetPath => GetAssetPath(project); + } + + public static string GetTemplatePath(LoadedProject project) { var isAbsolutePath = Path.IsPathFullyQualified(project.Project.TemplatesFolder); return isAbsolutePath ? project.Project.TemplatesFolder : $"{project.ProjectPath}/{project.Project.TemplatesFolder}"; } - public static string GetLocalePath(this LoadedProject project) + public static string GetLocalePath(LoadedProject project) { var isAbsolutePath = Path.IsPathFullyQualified(project.Project.LocalesFolder); return isAbsolutePath ? project.Project.LocalesFolder : $"{project.ProjectPath}/{project.Project.LocalesFolder}"; } - public static string GetAssetPath(this LoadedProject project) + public static string GetAssetPath(LoadedProject project) { var isAbsolutePath = Path.IsPathFullyQualified(project.Project.AssetsFolder); return isAbsolutePath ? project.Project.AssetsFolder : diff --git a/src/OpenRpg.Editor.Infrastructure/Persistence/CreateProjectExecutor.cs b/src/OpenRpg.Editor.Infrastructure/Persistence/CreateProjectExecutor.cs index 0ae9b260..ea970831 100644 --- a/src/OpenRpg.Editor.Infrastructure/Persistence/CreateProjectExecutor.cs +++ b/src/OpenRpg.Editor.Infrastructure/Persistence/CreateProjectExecutor.cs @@ -19,9 +19,9 @@ public async Task Execute(string folderPath) var projectContent = JsonConvert.SerializeObject(newProject.Project, Formatting.Indented); await File.WriteAllTextAsync(projectFile, projectContent); - Directory.CreateDirectory(newProject.GetTemplatePath()); - Directory.CreateDirectory(newProject.GetAssetPath()); - Directory.CreateDirectory(newProject.GetLocalePath()); + Directory.CreateDirectory(newProject.TemplatePath); + Directory.CreateDirectory(newProject.AssetPath); + Directory.CreateDirectory(newProject.LocalePath); Directory.CreateDirectory(newProject.GetAssetPath("items")); return newProject; diff --git a/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs b/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs index 053ffc1e..f562dafc 100644 --- a/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs +++ b/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs @@ -65,10 +65,10 @@ public async Task RefreshTemplateData() where T : ITemplate if(string.IsNullOrEmpty(EditorState.CurrentProject?.ProjectPath)) { throw new Exception("Folder path is empty"); } - if(!Directory.Exists(EditorState.CurrentProject.GetTemplatePath())) + if(!Directory.Exists(EditorState.CurrentProject.TemplatePath)) { throw new Exception("Template path does not exist on file system"); } - var dataFile = $"{EditorState.CurrentProject.GetTemplatePath()}/{typeof(T).Name}.json"; + var dataFile = $"{EditorState.CurrentProject.TemplatePath}/{typeof(T).Name}.json"; if(!File.Exists(dataFile)) { await File.WriteAllTextAsync(dataFile, "[]"); } var fileContent = await File.ReadAllTextAsync(dataFile); @@ -95,10 +95,10 @@ public async Task RefreshLocaleData() if(string.IsNullOrEmpty(EditorState.CurrentProject?.ProjectPath)) { throw new Exception("Folder path is empty"); } - if(!Directory.Exists(EditorState.CurrentProject.GetLocalePath())) + if(!Directory.Exists(EditorState.CurrentProject.LocalePath)) { throw new Exception("Locale path does not exist on file system"); } - var localeFiles = Directory.GetFiles(EditorState.CurrentProject.GetLocalePath(), "*.json"); + var localeFiles = Directory.GetFiles(EditorState.CurrentProject.LocalePath, "*.json"); foreach (var localeFile in localeFiles) { var localeData = await File.ReadAllTextAsync(localeFile); diff --git a/src/OpenRpg.Editor.Infrastructure/Persistence/SaveProjectExecutor.cs b/src/OpenRpg.Editor.Infrastructure/Persistence/SaveProjectExecutor.cs index 3cc0763e..3915e2b4 100644 --- a/src/OpenRpg.Editor.Infrastructure/Persistence/SaveProjectExecutor.cs +++ b/src/OpenRpg.Editor.Infrastructure/Persistence/SaveProjectExecutor.cs @@ -36,7 +36,7 @@ public async Task Execute() if(string.IsNullOrEmpty(EditorState.CurrentProject?.ProjectPath)) { throw new Exception("Folder path is empty"); } - if(!Directory.Exists(EditorState.CurrentProject.GetTemplatePath())) + if(!Directory.Exists(EditorState.CurrentProject.TemplatePath)) { throw new Exception("Data path does not exist on file system"); } await SaveTemplateData(); @@ -58,11 +58,11 @@ public async Task SaveTemplateData() where T : ITemplate if(string.IsNullOrEmpty(EditorState.CurrentProject?.ProjectPath)) { throw new Exception("Folder path is empty"); } - if(!Directory.Exists(EditorState.CurrentProject.GetTemplatePath())) + if(!Directory.Exists(EditorState.CurrentProject.TemplatePath)) { throw new Exception("Data path does not exist on file system"); } var data = EditorDatasource.SerializeData(); - var dataFile = $"{EditorState.CurrentProject.GetTemplatePath()}/{typeof(T).Name}.json"; + var dataFile = $"{EditorState.CurrentProject.TemplatePath}/{typeof(T).Name}.json"; await File.WriteAllTextAsync(dataFile, data); } @@ -74,13 +74,13 @@ public async Task SaveLocaleData() if(string.IsNullOrEmpty(EditorState.CurrentProject?.ProjectPath)) { throw new Exception("Folder path is empty"); } - if(!Directory.Exists(EditorState.CurrentProject.GetLocalePath())) + if(!Directory.Exists(EditorState.CurrentProject.LocalePath)) { throw new Exception("Locale path does not exist on file system"); } foreach (var localeData in EditorLocaleDatasource.LocaleDatasets) { var data = localeData.Value.SerializeData(); - var dataFile = $"{EditorState.CurrentProject.GetLocalePath()}/{localeData.Key}.json"; + var dataFile = $"{EditorState.CurrentProject.LocalePath}/{localeData.Key}.json"; await File.WriteAllTextAsync(dataFile, data); } } From b74536e67d1378e954395ff1cdc4ab967b47e1f3 Mon Sep 17 00:00:00 2001 From: LP Date: Mon, 8 Dec 2025 13:40:02 +0000 Subject: [PATCH 003/153] Updated Race/Classes over to newer extension properties --- .../Characters/BasicCharacter.razor | 8 +-- .../Pages/Curves/AdvancedEffects.razor | 12 ++--- .../Entities/BasicEntityComponents.razor | 16 +++--- .../Entities/CharacterStatsComponents.razor | 32 ++++++------ .../Pages/Entities/DefaultEntityClasses.razor | 4 +- .../Effects/Processors/EffectProcessor.cs | 6 +-- .../Extensions/ClassVariableExtensions.cs | 13 +++-- .../Extensions/EffectExtensions.cs | 2 - .../Extensions/EntityVariableExtensions.cs | 52 ++++++++++++------- .../Builders/CharacterBuilder.cs | 6 +-- .../Extensions/EntityExtensions.cs | 14 ++--- .../DefaultCharacterRequirementChecker.cs | 8 +-- .../Core/EntityVariableExtensionTests.cs | 16 +++--- 13 files changed, 103 insertions(+), 86 deletions(-) diff --git a/src/OpenRpg.Demos.Web/Components/Characters/BasicCharacter.razor b/src/OpenRpg.Demos.Web/Components/Characters/BasicCharacter.razor index e8b23e62..d6f6cbba 100644 --- a/src/OpenRpg.Demos.Web/Components/Characters/BasicCharacter.razor +++ b/src/OpenRpg.Demos.Web/Components/Characters/BasicCharacter.razor @@ -9,8 +9,8 @@ @if (Character != null) { + Race="@TemplateAccessor.ToInstance(Character.Variables.Race)" + Class="@TemplateAccessor.ToInstance(Character.Variables.Class)" />

@@ -38,8 +38,8 @@ public ITemplateAccessor TemplateAccessor { get; set; } public IReadOnlyCollection GetRaceEffects() - { return TemplateAccessor.GetRaceTemplate(Character.Variables.Race().TemplateId).Effects.GetStaticEffects(); } + { return TemplateAccessor.GetRaceTemplate(Character.Variables.Race.TemplateId).Effects.GetStaticEffects(); } public IReadOnlyCollection GetClassEffects() - { return TemplateAccessor.GetClassTemplate(Character.Variables.Class().TemplateId).Effects.GetStaticEffects(); ; } + { return TemplateAccessor.GetClassTemplate(Character.Variables.Class.TemplateId).Effects.GetStaticEffects(); ; } } \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor b/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor index 5ff8e6d7..f6d09d9e 100644 --- a/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor +++ b/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor @@ -188,8 +188,8 @@
+ Race="@TemplateAccessor.ToInstance(ExampleCharacter.Variables.Race)" + Class="@TemplateAccessor.ToInstance(ExampleCharacter.Variables.Class)"/>
@@ -211,8 +211,8 @@ public int CharacterLevel { - get => ExampleCharacter.Variables.Class().Variables.Level(); - set => ExampleCharacter.Variables.Class().Variables.Level(value); + get => ExampleCharacter.Variables.Class.Variables.Level(); + set => ExampleCharacter.Variables.Class.Variables.Level(value); } protected override void OnInitialized() @@ -285,8 +285,8 @@ var equipment = new Equipment(); equipment.MainHandSlot(new ItemData() { TemplateId = pretendWeapon.Id }); - ExampleCharacter.Variables.Race(new RaceData() { TemplateId = pretendHumanRace.Id }); - ExampleCharacter.Variables.Class(new ClassData() { TemplateId = pretendFighterClassTemplate.Id }); + ExampleCharacter.Variables.Race = new RaceData() { TemplateId = pretendHumanRace.Id }; + ExampleCharacter.Variables.Class = new ClassData() { TemplateId = pretendFighterClassTemplate.Id }; ExampleCharacter.Variables.Equipment(equipment); TemplateAccessor.AddTemplate(pretendHumanRace); diff --git a/src/OpenRpg.Demos.Web/Pages/Entities/BasicEntityComponents.razor b/src/OpenRpg.Demos.Web/Pages/Entities/BasicEntityComponents.razor index c4e41aa5..58b6085b 100644 --- a/src/OpenRpg.Demos.Web/Pages/Entities/BasicEntityComponents.razor +++ b/src/OpenRpg.Demos.Web/Pages/Entities/BasicEntityComponents.razor @@ -83,8 +83,8 @@
+ Race="@TemplateAccessor.ToInstance(MultiClassEntity.Variables.Race)" + Class="@TemplateAccessor.ToInstance(SimpleEntity.Variables.Class)">
@@ -130,8 +130,8 @@
+ Race="@TemplateAccessor.ToInstance(MultiClassEntity.Variables.Race)" + Classes="@TemplateAccessor.ToInstance(MultiClassEntity.Variables.MultiClass.Classes)">
@@ -157,11 +157,11 @@ TemplateAccessor.AddTemplate(RingBearerClass); SimpleEntity.NameLocaleId = "Frodo Baggins"; - SimpleEntity.Variables.Race(new RaceData { TemplateId = HobbitRace.Id }); - SimpleEntity.Variables.Class(new ClassData { TemplateId = FighterClass.Id }); + SimpleEntity.Variables.Race = new RaceData { TemplateId = HobbitRace.Id }; + SimpleEntity.Variables.Class = new ClassData { TemplateId = FighterClass.Id }; MultiClassEntity.NameLocaleId = "Frodo Baggins"; - MultiClassEntity.Variables.Race(new RaceData { TemplateId = HobbitRace.Id }); + MultiClassEntity.Variables.Race = new RaceData { TemplateId = HobbitRace.Id }; var multiClass = new MultiClasses(); var level2Fighter =new ClassData { TemplateId = FighterClass.Id }; @@ -175,7 +175,7 @@ level3RingBearer.Variables.Level(3); multiClass.AddClass(level3RingBearer); - MultiClassEntity.Variables.MultiClass(multiClass); + MultiClassEntity.Variables.MultiClass = multiClass; base.OnInitialized(); } } \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Pages/Entities/CharacterStatsComponents.razor b/src/OpenRpg.Demos.Web/Pages/Entities/CharacterStatsComponents.razor index 658c4ca7..87c4a57a 100644 --- a/src/OpenRpg.Demos.Web/Pages/Entities/CharacterStatsComponents.razor +++ b/src/OpenRpg.Demos.Web/Pages/Entities/CharacterStatsComponents.razor @@ -61,8 +61,8 @@
+ Race="@ManualStatTemplateAccessor.ToInstance(ManualStatsExample.Variables.Race)" + Class="@ManualStatTemplateAccessor.ToInstance(ManualStatsExample.Variables.Class)" />

@@ -158,8 +158,8 @@
+ Race="@AutoStatTemplateAccessor.ToInstance(AutoStatsExample.Variables.Race)" + Class="@AutoStatTemplateAccessor.ToInstance(AutoStatsExample.Variables.Class)" />

@@ -168,19 +168,19 @@

Race Effects

- +

Class Effects

- +

+ Race="@AutoStatTemplateAccessor.ToInstance(AutoStatsExample2.Variables.Race)" + Class="@AutoStatTemplateAccessor.ToInstance(AutoStatsExample2.Variables.Class)" />

@@ -189,11 +189,11 @@

Race Effects

- +

Class Effects

- +
@@ -222,8 +222,8 @@ ManualStatsExample.NameLocaleId = "Frodo Baggins"; - ManualStatsExample.Variables.Race(new RaceData { TemplateId = hobbitRace.Id }); - ManualStatsExample.Variables.Class(new ClassData { TemplateId = fighterClass.Id }); + ManualStatsExample.Variables.Race = new RaceData { TemplateId = hobbitRace.Id }; + ManualStatsExample.Variables.Class = new ClassData { TemplateId = fighterClass.Id }; ManualStatsExample.Stats = new EntityStatsVariables(); ManualStatsExample.Stats.MaxHealth(100); @@ -278,12 +278,12 @@ AutoStatTemplateAccessor.AddTemplate(fighterClass); AutoStatsExample.NameLocaleId = "Frodo Baggins"; - AutoStatsExample.Variables.Race(new RaceData { TemplateId = hobbitRace.Id }); - AutoStatsExample.Variables.Class(new ClassData{ TemplateId = fighterClass.Id }); + AutoStatsExample.Variables.Race = new RaceData { TemplateId = hobbitRace.Id }; + AutoStatsExample.Variables.Class = new ClassData{ TemplateId = fighterClass.Id }; AutoStatsExample2.NameLocaleId = "Peregrin Took"; - AutoStatsExample2.Variables.Race(new RaceData { TemplateId = hobbitRace.Id }); - AutoStatsExample2.Variables.Class(new ClassData { TemplateId = fighterClass.Id }); + AutoStatsExample2.Variables.Race = new RaceData { TemplateId = hobbitRace.Id }; + AutoStatsExample2.Variables.Class = new ClassData { TemplateId = fighterClass.Id }; var statsCalculator = new FantasyStatsPopulator(); var computedEffects1 = EffectProcessor.ComputeEffects(AutoStatsExample); diff --git a/src/OpenRpg.Demos.Web/Pages/Entities/DefaultEntityClasses.razor b/src/OpenRpg.Demos.Web/Pages/Entities/DefaultEntityClasses.razor index d196981c..d4fd5062 100644 --- a/src/OpenRpg.Demos.Web/Pages/Entities/DefaultEntityClasses.razor +++ b/src/OpenRpg.Demos.Web/Pages/Entities/DefaultEntityClasses.razor @@ -142,8 +142,8 @@ _manualCharacter = new Character(); _manualCharacter.NameLocaleId = "John Doe"; - _manualCharacter.Variables.Race(new RaceData { TemplateId = RaceTypeLookups.Human }); - _manualCharacter.Variables.Class(new ClassData { TemplateId = ClassTypeLookups.Fighter }); + _manualCharacter.Variables.Race = new RaceData { TemplateId = RaceTypeLookups.Human }; + _manualCharacter.Variables.Class = new ClassData { TemplateId = ClassTypeLookups.Fighter }; _manualCharacter.Stats.MaxHealth(100); _manualCharacter.State.Health(50); diff --git a/src/OpenRpg.Entities/Effects/Processors/EffectProcessor.cs b/src/OpenRpg.Entities/Effects/Processors/EffectProcessor.cs index 2d2387b4..14b059ee 100644 --- a/src/OpenRpg.Entities/Effects/Processors/EffectProcessor.cs +++ b/src/OpenRpg.Entities/Effects/Processors/EffectProcessor.cs @@ -51,13 +51,13 @@ public virtual ComputedEffects ComputeEffects(T entity) if (entity.Variables.HasRace()) { - var template = TemplateAccessor.GetRaceTemplate(entity.Variables.Race().TemplateId); + var template = TemplateAccessor.GetRaceTemplate(entity.Variables.Race.TemplateId); ComputeEffects(template, entity, computedEffects); } if (entity.Variables.HasClass()) { - var template = TemplateAccessor.GetClassTemplate(entity.Variables.Class().TemplateId); + var template = TemplateAccessor.GetClassTemplate(entity.Variables.Class.TemplateId); ComputeEffects(template, entity, computedEffects); } @@ -83,7 +83,7 @@ public virtual void ComputeScaledEffect(ScaledEffect effect, IHasEffects context { if (effect.ScalingType == CoreEffectScalingTypes.Level) { - var level = relatedEntity?.Variables.Class()?.Variables.Level() ?? 1; + var level = relatedEntity?.Variables.Class?.Variables.Level() ?? 1; computedEffects.Add(effect.EffectType, effect.PotencyFunction.Plot(level)); return; } diff --git a/src/OpenRpg.Entities/Extensions/ClassVariableExtensions.cs b/src/OpenRpg.Entities/Extensions/ClassVariableExtensions.cs index 79de8ba8..370bb6ea 100644 --- a/src/OpenRpg.Entities/Extensions/ClassVariableExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/ClassVariableExtensions.cs @@ -6,8 +6,15 @@ namespace OpenRpg.Entities.Extensions { public static class ClassVariableExtensions { - public static int Experience(this ClassVariables vars) => vars.GetInt(CoreClassVariableTypes.Experience); - public static void Experience(this ClassVariables vars, int experience) => vars[CoreClassVariableTypes.Experience] = experience; - public static void AddExperience(this ClassVariables state, int change) => state.Experience(state.Experience() + change); + extension(ClassVariables variables) + { + public int Experience + { + get => variables.GetInt(CoreClassVariableTypes.Experience); + set => variables[CoreClassVariableTypes.Experience] = value; + } + } + + public static void AddExperience(this ClassVariables state, int change) => state.Experience += change; } } \ No newline at end of file diff --git a/src/OpenRpg.Entities/Extensions/EffectExtensions.cs b/src/OpenRpg.Entities/Extensions/EffectExtensions.cs index f3b279d9..74d98592 100644 --- a/src/OpenRpg.Entities/Extensions/EffectExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/EffectExtensions.cs @@ -3,8 +3,6 @@ using OpenRpg.Core.Effects; using OpenRpg.Core.Templates; using OpenRpg.Entities.Classes; -using OpenRpg.Entities.Effects; -using OpenRpg.Entities.Modifications; using OpenRpg.Entities.Races; namespace OpenRpg.Entities.Extensions diff --git a/src/OpenRpg.Entities/Extensions/EntityVariableExtensions.cs b/src/OpenRpg.Entities/Extensions/EntityVariableExtensions.cs index 891794e0..03629f58 100644 --- a/src/OpenRpg.Entities/Extensions/EntityVariableExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/EntityVariableExtensions.cs @@ -10,38 +10,50 @@ public static class EntityVariableExtensions { public static bool HasGender(this EntityVariables vars) { return vars.ContainsKey(CoreEntityVariableTypes.Gender); } - - public static byte Gender(this EntityVariables vars) - { return vars.GetByteOrDefault(CoreEntityVariableTypes.Gender, 0); } - public static void Gender(this EntityVariables vars, byte gender) - { vars[CoreEntityVariableTypes.Gender] = gender; } + extension(EntityVariables vars) + { + public byte Gender + { + get => vars.GetByteOrDefault(CoreEntityVariableTypes.Gender, 0); + set => vars[CoreEntityVariableTypes.Gender] = value; + } + } public static bool HasRace(this EntityVariables vars) { return vars.ContainsKey(CoreEntityVariableTypes.Race); } - public static RaceData Race(this EntityVariables vars) - { return vars.GetAs(CoreEntityVariableTypes.Race); } - - public static void Race(this EntityVariables vars, RaceData raceDataData) - { vars[CoreEntityVariableTypes.Race] = raceDataData; } + extension(EntityVariables vars) + { + public RaceData Race + { + get => vars.GetAs(CoreEntityVariableTypes.Race); + set => vars[CoreEntityVariableTypes.Race] = value; + } + } public static bool HasClass(this EntityVariables vars) { return vars.ContainsKey(CoreEntityVariableTypes.Class); } - public static ClassData Class(this EntityVariables vars) - { return vars.GetAs(CoreEntityVariableTypes.Class); } - - public static void Class(this EntityVariables vars, ClassData classDataData) - { vars[CoreEntityVariableTypes.Class] = classDataData; } + extension(EntityVariables vars) + { + public ClassData Class + { + get => vars.GetAs(CoreEntityVariableTypes.Class); + set => vars[CoreEntityVariableTypes.Class] = value; + } + } public static bool HasMultiClass(this EntityVariables vars) { return vars.ContainsKey(CoreEntityVariableTypes.MultiClasses); } - public static MultiClasses MultiClass(this EntityVariables vars) - { return vars.GetAs(CoreEntityVariableTypes.MultiClasses); } - - public static void MultiClass(this EntityVariables vars, MultiClasses multiClasses) - { vars[CoreEntityVariableTypes.MultiClasses] = multiClasses; } + extension(EntityVariables vars) + { + public MultiClasses MultiClass + { + get => vars.GetAs(CoreEntityVariableTypes.MultiClasses); + set => vars[CoreEntityVariableTypes.MultiClasses] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Builders/CharacterBuilder.cs b/src/OpenRpg.Genres/Builders/CharacterBuilder.cs index 61bb7233..89d1472a 100644 --- a/src/OpenRpg.Genres/Builders/CharacterBuilder.cs +++ b/src/OpenRpg.Genres/Builders/CharacterBuilder.cs @@ -162,11 +162,11 @@ protected virtual Character CreateCharacterInstance() public virtual Character CreateCharacter() { - _variables.Class(ProcessClass()); - _variables.Race(ProcessRace()); + _variables.Class = ProcessClass(); + _variables.Race = ProcessRace(); _variables.Equipment(ProcessEquipment()); _variables.Inventory(ProcessInventory()); - _variables.Gender(_genderId); + _variables.Gender = _genderId; var character = CreateCharacterInstance(); character.UniqueId = Guid.NewGuid(); diff --git a/src/OpenRpg.Genres/Extensions/EntityExtensions.cs b/src/OpenRpg.Genres/Extensions/EntityExtensions.cs index 46084d0c..103ea67d 100644 --- a/src/OpenRpg.Genres/Extensions/EntityExtensions.cs +++ b/src/OpenRpg.Genres/Extensions/EntityExtensions.cs @@ -13,16 +13,16 @@ public static IReadOnlyCollection GetEffects(this Entity entity, ITempl { var effects = new List(); - if (entity.Variables.HasRace()) { effects.AddRange(entity.Variables.Race().GetEffects(templateAccessor)); } - if (entity.Variables.HasClass()) { effects.AddRange(entity.Variables.Class().GetEffects(templateAccessor)); } + if (entity.Variables.HasRace()) { effects.AddRange(entity.Variables.Race.GetEffects(templateAccessor)); } + if (entity.Variables.HasClass()) { effects.AddRange(entity.Variables.Class.GetEffects(templateAccessor)); } if (entity.Variables.HasEquipment()) { effects.AddRange(entity.Variables.Equipment().GetEffects(templateAccessor)); } return effects; } - public static float GetHealthPercentage(this Entity entity) - { return (float)entity.State.Health() / entity.Stats.MaxHealth(); } - - public static float GetStaminaPercentage(this Entity entity) - { return (float)entity.State.Stamina() / entity.Stats.MaxStamina(); } + extension(Entity entity) + { + public float HealthPercentage => (float)entity.State.Health() / entity.Stats.MaxHealth(); + public float StaminaPercentage => (float)entity.State.Stamina() / entity.Stats.MaxStamina(); + } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs index a9e57e54..3bd41d86 100644 --- a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs +++ b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs @@ -21,7 +21,7 @@ public virtual bool IsRequirementMet(Character character, Requirement requiremen if (!character.Variables.HasRace()) { return false; } - var race = character.Variables.Race(); + var race = character.Variables.Race; return race.TemplateId == requirement.Association.AssociatedId; } @@ -29,14 +29,14 @@ public virtual bool IsRequirementMet(Character character, Requirement requiremen { if (character.Variables.HasClass()) { - var classDetails = character.Variables.Class(); + var classDetails = character.Variables.Class; if (classDetails.TemplateId == requirement.Association.AssociatedId) { return classDetails.Variables.Level() >= requirement.Association.AssociatedValue; } } if (character.Variables.HasMultiClass()) { - var multiClass = character.Variables.MultiClass(); + var multiClass = character.Variables.MultiClass; var possibleClass = multiClass.GetClass(requirement.Association.AssociatedId); if (possibleClass != null) { return possibleClass.Variables.Level() >= requirement.Association.AssociatedValue; } @@ -50,7 +50,7 @@ public virtual bool IsRequirementMet(Character character, Requirement requiremen if (!character.Variables.HasGender()) { return false; } - return character.Variables.Gender() == requirement.Association.AssociatedId; + return character.Variables.Gender == requirement.Association.AssociatedId; } if (requirement.RequirementType == GenreRequirementTypes.EquipmentItemRequirement) diff --git a/src/OpenRpg.UnitTests/Core/EntityVariableExtensionTests.cs b/src/OpenRpg.UnitTests/Core/EntityVariableExtensionTests.cs index 5ac57acd..10d439fe 100644 --- a/src/OpenRpg.UnitTests/Core/EntityVariableExtensionTests.cs +++ b/src/OpenRpg.UnitTests/Core/EntityVariableExtensionTests.cs @@ -15,9 +15,9 @@ public void should_correctly_handle_gender_on_entity() Assert.False(entityVars.HasGender()); var dummyGender = (byte)1; - entityVars.Gender(dummyGender); + entityVars.Gender = dummyGender; Assert.True(entityVars.HasGender()); - Assert.Equal(entityVars.Gender(), dummyGender); + Assert.Equal(entityVars.Gender, dummyGender); } [Fact] @@ -27,9 +27,9 @@ public void should_correctly_handle_race_on_entity() Assert.False(entityVars.HasRace()); var dummyRace = new RaceData(); - entityVars.Race(dummyRace); + entityVars.Race = dummyRace; Assert.True(entityVars.HasRace()); - Assert.Equal(entityVars.Race(), dummyRace); + Assert.Equal(entityVars.Race, dummyRace); } [Fact] @@ -39,9 +39,9 @@ public void should_correctly_handle_class_on_entity() Assert.False(entityVars.HasClass()); var dummyClass = new ClassData(); - entityVars.Class(dummyClass); + entityVars.Class = dummyClass; Assert.True(entityVars.HasClass()); - Assert.Equal(entityVars.Class(), dummyClass); + Assert.Equal(entityVars.Class, dummyClass); } [Fact] @@ -51,8 +51,8 @@ public void should_correctly_handle_multiclass_on_entity() Assert.False(entityVars.HasMultiClass()); var dummyMultiClass = new MultiClasses(); - entityVars.MultiClass(dummyMultiClass); + entityVars.MultiClass = dummyMultiClass; Assert.True(entityVars.HasMultiClass()); - Assert.Equal(entityVars.MultiClass(), dummyMultiClass); + Assert.Equal(entityVars.MultiClass, dummyMultiClass); } } \ No newline at end of file From f714cc459af20bf96efb20f39acd5757651b5ff1 Mon Sep 17 00:00:00 2001 From: LP Date: Mon, 8 Dec 2025 15:13:13 +0000 Subject: [PATCH 004/153] Moved more extensions over to properties --- .../Characters/CharacterStats.razor | 18 +- .../Characters/CharacterVitals.razor | 4 +- .../Pages/AdviceEngine/ExampleSetup.razor | 6 +- .../Entities/CharacterStatsComponents.razor | 30 +-- .../Pages/Entities/DefaultEntityClasses.razor | 30 +-- .../Combat/FantasyAttackGenerator.cs | 2 +- .../EntityStatVariableExtensions.cs | 241 +++++++++++++----- .../EntityStateVariableExtensions.cs | 19 +- .../FantasyCombatReferencesExtensions.cs | 148 +++++------ .../Extensions/FantasyEntityExtensions.cs | 6 +- ...faultFantasyCharacterRequirementChecker.cs | 14 +- .../State/Populators/FantasyStatePopulator.cs | 6 +- .../Partial/FantasyAttributeStatPopulator.cs | 12 +- .../Partial/FantasyElementalStatPopulator.cs | 26 +- .../Partial/FantasyMeleeStatPopulator.cs | 20 +- .../Partial/FantasyVitalsStatPopulator.cs | 28 +- .../Extensions/EntityExtensions.cs | 4 +- .../EntityStatVariableExtensions.cs | 123 ++++++--- .../EntityStateVariablesExtensions.cs | 61 +++-- .../Entity/State/BasicEntityStatePopulator.cs | 4 +- .../Entity/Stats/AbilityStatPopulator.cs | 15 +- .../Entity/Stats/CriticalStatPopulator.cs | 11 +- .../Entity/Stats/DamageStatPopulator.cs | 5 +- .../Entity/Stats/DefenseStatPopulator.cs | 5 +- .../DefaultCharacterRequirementChecker.cs | 6 +- .../EntityStateVariableExtensionTests.cs | 16 +- 26 files changed, 528 insertions(+), 332 deletions(-) diff --git a/src/OpenRpg.Demos.Web/Components/Characters/CharacterStats.razor b/src/OpenRpg.Demos.Web/Components/Characters/CharacterStats.razor index dd572442..9f981a09 100644 --- a/src/OpenRpg.Demos.Web/Components/Characters/CharacterStats.razor +++ b/src/OpenRpg.Demos.Web/Components/Characters/CharacterStats.razor @@ -7,34 +7,34 @@

Core Stats

- +
- +
- +
- +
- +

Combat Stats

- +
- +
- +
- +
} diff --git a/src/OpenRpg.Demos.Web/Components/Characters/CharacterVitals.razor b/src/OpenRpg.Demos.Web/Components/Characters/CharacterVitals.razor index 6688f457..03b87968 100644 --- a/src/OpenRpg.Demos.Web/Components/Characters/CharacterVitals.razor +++ b/src/OpenRpg.Demos.Web/Components/Characters/CharacterVitals.razor @@ -9,11 +9,11 @@

Health

- +

Mana

- +
} diff --git a/src/OpenRpg.Demos.Web/Pages/AdviceEngine/ExampleSetup.razor b/src/OpenRpg.Demos.Web/Pages/AdviceEngine/ExampleSetup.razor index d6f56f61..4ee24052 100644 --- a/src/OpenRpg.Demos.Web/Pages/AdviceEngine/ExampleSetup.razor +++ b/src/OpenRpg.Demos.Web/Pages/AdviceEngine/ExampleSetup.razor @@ -68,7 +68,7 @@ {

@((agent.OwnerContext as Character).NameLocaleId)

- +
} @@ -345,7 +345,7 @@ public override IConsideration CreateConsideration(IAgent agent) { - var healthValueAccessor = new ManualValueAccessor((context, _) => (context as Character).State.Health()); + var healthValueAccessor = new ManualValueAccessor((context, _) => (context as Character).State.Health); return new ValueBasedConsideration(new UtilityKey(UtilityVariableTypes.LowHealth), healthValueAccessor, PresetClampers.ZeroToHundred, PresetCurves.InverseLinear); } } @@ -500,7 +500,7 @@ void ApplyRandoms(Character character) { character.Variables[PositionVariable] = GetRandomPositionValue(); - character.State.Health(GetRandomHealthValue()); + character.State.Health = GetRandomHealthValue(); } foreach (var agent in Agents) diff --git a/src/OpenRpg.Demos.Web/Pages/Entities/CharacterStatsComponents.razor b/src/OpenRpg.Demos.Web/Pages/Entities/CharacterStatsComponents.razor index 87c4a57a..a1007370 100644 --- a/src/OpenRpg.Demos.Web/Pages/Entities/CharacterStatsComponents.razor +++ b/src/OpenRpg.Demos.Web/Pages/Entities/CharacterStatsComponents.razor @@ -226,21 +226,21 @@ ManualStatsExample.Variables.Class = new ClassData { TemplateId = fighterClass.Id }; ManualStatsExample.Stats = new EntityStatsVariables(); - ManualStatsExample.Stats.MaxHealth(100); - ManualStatsExample.State.Health(50); - ManualStatsExample.Stats.MaxMana(10); - ManualStatsExample.State.Mana(7); - - ManualStatsExample.Stats.Strength(11); - ManualStatsExample.Stats.Dexterity(12); - ManualStatsExample.Stats.Intelligence(12); - ManualStatsExample.Stats.Wisdom(18); - ManualStatsExample.Stats.Charisma(14); - - ManualStatsExample.Stats.Damage(10.0f); - ManualStatsExample.Stats.Defense(8.0f); - ManualStatsExample.Stats.DarkDamage(1); - ManualStatsExample.Stats.DarkDefense(25); + ManualStatsExample.Stats.MaxHealth = 100; + ManualStatsExample.State.Health = 50; + ManualStatsExample.Stats.MaxMana = 10; + ManualStatsExample.State.Mana = 7; + + ManualStatsExample.Stats.Strength = 11; + ManualStatsExample.Stats.Dexterity = 12; + ManualStatsExample.Stats.Intelligence = 12; + ManualStatsExample.Stats.Wisdom = 18; + ManualStatsExample.Stats.Charisma = 14; + + ManualStatsExample.Stats.Damage = 10.0f; + ManualStatsExample.Stats.Defense = 8.0f; + ManualStatsExample.Stats.DarkDamage = 1; + ManualStatsExample.Stats.DarkDefense = 25; } protected void SetupAutoStats1() diff --git a/src/OpenRpg.Demos.Web/Pages/Entities/DefaultEntityClasses.razor b/src/OpenRpg.Demos.Web/Pages/Entities/DefaultEntityClasses.razor index d4fd5062..1cb5ab6a 100644 --- a/src/OpenRpg.Demos.Web/Pages/Entities/DefaultEntityClasses.razor +++ b/src/OpenRpg.Demos.Web/Pages/Entities/DefaultEntityClasses.razor @@ -145,21 +145,21 @@ _manualCharacter.Variables.Race = new RaceData { TemplateId = RaceTypeLookups.Human }; _manualCharacter.Variables.Class = new ClassData { TemplateId = ClassTypeLookups.Fighter }; - _manualCharacter.Stats.MaxHealth(100); - _manualCharacter.State.Health(50); - _manualCharacter.Stats.MaxMana(10); - _manualCharacter.State.Mana(7); - - _manualCharacter.Stats.Strength(11); - _manualCharacter.Stats.Dexterity(12); - _manualCharacter.Stats.Intelligence(12); - _manualCharacter.Stats.Wisdom(18); - _manualCharacter.Stats.Charisma(14); - - _manualCharacter.Stats.Damage(10); - _manualCharacter.Stats.Defense(8); - _manualCharacter.Stats.DarkDamage(1); - _manualCharacter.Stats.DarkDefense(25); + _manualCharacter.Stats.MaxHealth = 100; + _manualCharacter.State.Health = 50; + _manualCharacter.Stats.MaxMana = 10; + _manualCharacter.State.Mana = 7; + + _manualCharacter.Stats.Strength = 11; + _manualCharacter.Stats.Dexterity = 12; + _manualCharacter.Stats.Intelligence = 12; + _manualCharacter.Stats.Wisdom = 18; + _manualCharacter.Stats.Charisma = 14; + + _manualCharacter.Stats.Damage = 10; + _manualCharacter.Stats.Defense = 8; + _manualCharacter.Stats.DarkDamage = 1; + _manualCharacter.Stats.DarkDefense = 25; RandomizeCharacter(); diff --git a/src/OpenRpg.Genres.Fantasy/Combat/FantasyAttackGenerator.cs b/src/OpenRpg.Genres.Fantasy/Combat/FantasyAttackGenerator.cs index d3b81357..f5e16a7b 100644 --- a/src/OpenRpg.Genres.Fantasy/Combat/FantasyAttackGenerator.cs +++ b/src/OpenRpg.Genres.Fantasy/Combat/FantasyAttackGenerator.cs @@ -33,7 +33,7 @@ public Damage ApplyVariance(Damage damage) public virtual (float scaledCritRate, float scaledCritMultiplier) GetScaledCriticalRateAndMultiplier( EntityStatsVariables stats) { - return (stats.CriticalDamageChance(), stats.CriticalDamageMultiplier()); + return (stats.CriticalDamageChance, stats.CriticalDamageMultiplier); } public (bool DidCrit, Damage[] Damages) AttemptToCritical(Damage[] damages, EntityStatsVariables stats) diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/EntityStatVariableExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/EntityStatVariableExtensions.cs index 8aae215b..e9b3f424 100644 --- a/src/OpenRpg.Genres.Fantasy/Extensions/EntityStatVariableExtensions.cs +++ b/src/OpenRpg.Genres.Fantasy/Extensions/EntityStatVariableExtensions.cs @@ -6,67 +6,190 @@ namespace OpenRpg.Genres.Fantasy.Extensions { public static class EntityStatVariableExtensions { - public static int Strength(this EntityStatsVariables stats) => (int)stats.Get(FantasyEntityStatsVariableTypes.Strength); - public static int Dexterity(this EntityStatsVariables stats) => (int)stats.Get(FantasyEntityStatsVariableTypes.Dexterity); - public static int Constitution(this EntityStatsVariables stats) => (int)stats.Get(FantasyEntityStatsVariableTypes.Constitution); - public static int Intelligence(this EntityStatsVariables stats) => (int)stats.Get(FantasyEntityStatsVariableTypes.Intelligence); - public static int Wisdom(this EntityStatsVariables stats) => (int)stats.Get(FantasyEntityStatsVariableTypes.Wisdom); - public static int Charisma(this EntityStatsVariables stats) => (int)stats.Get(FantasyEntityStatsVariableTypes.Charisma); - public static void Strength(this EntityStatsVariables stats, int value) => stats[FantasyEntityStatsVariableTypes.Strength] = value; - public static void Dexterity(this EntityStatsVariables stats, int value) => stats[FantasyEntityStatsVariableTypes.Dexterity] = value; - public static void Constitution(this EntityStatsVariables stats, int value) => stats[FantasyEntityStatsVariableTypes.Constitution] = value; - public static void Intelligence(this EntityStatsVariables stats, int value) => stats[FantasyEntityStatsVariableTypes.Intelligence] = value; - public static void Wisdom(this EntityStatsVariables stats, int value) => stats[FantasyEntityStatsVariableTypes.Wisdom] = value; - public static void Charisma(this EntityStatsVariables stats, int value) => stats[FantasyEntityStatsVariableTypes.Charisma] = value; + extension(EntityStatsVariables stats) + { + public int Strength + { + get => (int)stats.Get(FantasyEntityStatsVariableTypes.Strength); + set => stats[FantasyEntityStatsVariableTypes.Strength] = value; + } + + public int Dexterity + { + get => (int)stats.Get(FantasyEntityStatsVariableTypes.Dexterity); + set => stats[FantasyEntityStatsVariableTypes.Dexterity] = value; + } + + public int Constitution + { + get => (int)stats.Get(FantasyEntityStatsVariableTypes.Constitution); + set => stats[FantasyEntityStatsVariableTypes.Constitution] = value; + } + + public int Intelligence + { + get => (int)stats.Get(FantasyEntityStatsVariableTypes.Intelligence); + set => stats[FantasyEntityStatsVariableTypes.Intelligence] = value; + } + + public int Wisdom + { + get => (int)stats.Get(FantasyEntityStatsVariableTypes.Wisdom); + set => stats[FantasyEntityStatsVariableTypes.Wisdom] = value; + } + + public int Charisma + { + get => (int)stats.Get(FantasyEntityStatsVariableTypes.Charisma); + set => stats[FantasyEntityStatsVariableTypes.Charisma] = value; + } + } - public static void MaxMana(this EntityStatsVariables stats, int value) => stats[FantasyEntityStatsVariableTypes.MaxMana] = value; - public static int MaxMana(this EntityStatsVariables stats) => (int)stats.Get(FantasyEntityStatsVariableTypes.MaxMana); + extension(EntityStatsVariables stats) + { + public float MaxMana + { + get => stats.Get(FantasyEntityStatsVariableTypes.MaxMana); + set => stats[FantasyEntityStatsVariableTypes.MaxMana] = value; + } + + public float ManaRegen + { + get => stats.Get(FantasyEntityStatsVariableTypes.ManaRegen); + set => stats[FantasyEntityStatsVariableTypes.ManaRegen] = value; + } + + public float ManaRegenRate + { + get => stats.Get(FantasyEntityStatsVariableTypes.ManaRegenRate); + set => stats[FantasyEntityStatsVariableTypes.ManaRegenRate] = value; + } + } - public static void ManaRegen(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.ManaRegen] = value; - public static float ManaRegen(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.ManaRegen); - public static float ManaRegenRate(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.ManaRegenRate); - public static void ManaRegenRate(this EntityStatsVariables stats, float regenRate) => stats[FantasyEntityStatsVariableTypes.ManaRegenRate] = regenRate; - - public static float IceDamage(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.IceDamage); - public static float FireDamage(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.FireDamage); - public static float WindDamage(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.WindDamage); - public static float EarthDamage(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.EarthDamage); - public static float LightDamage(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.LightDamage); - public static float DarkDamage(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.DarkDamage); - public static float SlashingDamage(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.SlashingDamage); - public static float BluntDamage(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.BluntDamage); - public static float PiercingDamage(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.PiercingDamage); - public static float UnarmedDamage(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.UnarmedDamage); - public static void IceDamage(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.IceDamage] = value; - public static void FireDamage(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.FireDamage] = value; - public static void WindDamage(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.WindDamage] = value; - public static void EarthDamage(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.EarthDamage] = value; - public static void LightDamage(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.LightDamage] = value; - public static void DarkDamage(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.DarkDamage] = value; - public static void SlashingDamage(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.SlashingDamage] = value; - public static void BluntDamage(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.BluntDamage] = value; - public static void PiercingDamage(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.PiercingDamage] = value; - public static void UnarmedDamage(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.UnarmedDamage] = value; + extension(EntityStatsVariables stats) + { + public float IceDamage + { + get => stats.Get(FantasyEntityStatsVariableTypes.IceDamage); + set => stats[FantasyEntityStatsVariableTypes.IceDamage] = value; + } + + public float FireDamage + { + get => stats.Get(FantasyEntityStatsVariableTypes.FireDamage); + set => stats[FantasyEntityStatsVariableTypes.FireDamage] = value; + } + + public float WindDamage + { + get => stats.Get(FantasyEntityStatsVariableTypes.WindDamage); + set => stats[FantasyEntityStatsVariableTypes.WindDamage] = value; + } + + public float EarthDamage + { + get => stats.Get(FantasyEntityStatsVariableTypes.EarthDamage); + set => stats[FantasyEntityStatsVariableTypes.EarthDamage] = value; + } + + public float LightDamage + { + get => stats.Get(FantasyEntityStatsVariableTypes.LightDamage); + set => stats[FantasyEntityStatsVariableTypes.LightDamage] = value; + } + + public float DarkDamage + { + get => stats.Get(FantasyEntityStatsVariableTypes.DarkDamage); + set => stats[FantasyEntityStatsVariableTypes.DarkDamage] = value; + } + + public float SlashingDamage + { + get => stats.Get(FantasyEntityStatsVariableTypes.SlashingDamage); + set => stats[FantasyEntityStatsVariableTypes.SlashingDamage] = value; + } + + public float BluntDamage + { + get => stats.Get(FantasyEntityStatsVariableTypes.BluntDamage); + set => stats[FantasyEntityStatsVariableTypes.BluntDamage] = value; + } + + public float PiercingDamage + { + get => stats.Get(FantasyEntityStatsVariableTypes.PiercingDamage); + set => stats[FantasyEntityStatsVariableTypes.PiercingDamage] = value; + } + + public float UnarmedDamage + { + get => stats.Get(FantasyEntityStatsVariableTypes.UnarmedDamage); + set => stats[FantasyEntityStatsVariableTypes.UnarmedDamage] = value; + } + } - public static float IceDefense(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.IceDefense); - public static float FireDefense(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.FireDefense); - public static float WindDefense(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.WindDefense); - public static float EarthDefense(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.EarthDefense); - public static float LightDefense(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.LightDefense); - public static float DarkDefense(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.DarkDefense); - public static float SlashingDefense(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.SlashingDefense); - public static float BluntDefense(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.BluntDefense); - public static float PiercingDefense(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.PiercingDefense); - public static float UnarmedDefense(this EntityStatsVariables stats) => stats.Get(FantasyEntityStatsVariableTypes.UnarmedDefense); - public static void IceDefense(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.IceDefense] = value; - public static void FireDefense(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.FireDefense] = value; - public static void WindDefense(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.WindDefense] = value; - public static void EarthDefense(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.EarthDefense] = value; - public static void LightDefense(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.LightDefense] = value; - public static void DarkDefense(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.DarkDefense] = value; - public static void SlashingDefense(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.SlashingDefense] = value; - public static void BluntDefense(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.BluntDefense] = value; - public static void PiercingDefense(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.PiercingDefense] = value; - public static void UnarmedDefense(this EntityStatsVariables stats, float value) => stats[FantasyEntityStatsVariableTypes.UnarmedDefense] = value; + extension(EntityStatsVariables stats) + { + public float IceDefense + { + get => stats.Get(FantasyEntityStatsVariableTypes.IceDefense); + set => stats[FantasyEntityStatsVariableTypes.IceDefense] = value; + } + + public float FireDefense + { + get => stats.Get(FantasyEntityStatsVariableTypes.FireDefense); + set => stats[FantasyEntityStatsVariableTypes.FireDefense] = value; + } + + public float WindDefense + { + get => stats.Get(FantasyEntityStatsVariableTypes.WindDefense); + set => stats[FantasyEntityStatsVariableTypes.WindDefense] = value; + } + + public float EarthDefense + { + get => stats.Get(FantasyEntityStatsVariableTypes.EarthDefense); + set => stats[FantasyEntityStatsVariableTypes.EarthDefense] = value; + } + + public float LightDefense + { + get => stats.Get(FantasyEntityStatsVariableTypes.LightDefense); + set => stats[FantasyEntityStatsVariableTypes.LightDefense] = value; + } + + public float DarkDefense + { + get => stats.Get(FantasyEntityStatsVariableTypes.DarkDefense); + set => stats[FantasyEntityStatsVariableTypes.DarkDefense] = value; + } + + public float SlashingDefense + { + get => stats.Get(FantasyEntityStatsVariableTypes.SlashingDefense); + set => stats[FantasyEntityStatsVariableTypes.SlashingDefense] = value; + } + + public float BluntDefense + { + get => stats.Get(FantasyEntityStatsVariableTypes.BluntDefense); + set => stats[FantasyEntityStatsVariableTypes.BluntDefense] = value; + } + + public float PiercingDefense + { + get => stats.Get(FantasyEntityStatsVariableTypes.PiercingDefense); + set => stats[FantasyEntityStatsVariableTypes.PiercingDefense] = value; + } + + public float UnarmedDefense + { + get => stats.Get(FantasyEntityStatsVariableTypes.UnarmedDefense); + set => stats[FantasyEntityStatsVariableTypes.UnarmedDefense] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/EntityStateVariableExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/EntityStateVariableExtensions.cs index a33025d1..ca802979 100644 --- a/src/OpenRpg.Genres.Fantasy/Extensions/EntityStateVariableExtensions.cs +++ b/src/OpenRpg.Genres.Fantasy/Extensions/EntityStateVariableExtensions.cs @@ -1,4 +1,5 @@ using OpenRpg.Core.Extensions; +using OpenRpg.Entities.Entity; using OpenRpg.Entities.State.Variables; using OpenRpg.Genres.Fantasy.Types; @@ -6,25 +7,31 @@ namespace OpenRpg.Genres.Fantasy.Extensions { public static class EntityStateVariableExtensions { - public static int Mana(this EntityStateVariables state) => (int)state.Get(FantasyEntityStateVariableTypes.Mana); - public static void Mana(this EntityStateVariables state, int value) => state[FantasyEntityStateVariableTypes.Mana] = value; + extension(EntityStateVariables state) + { + public float Mana + { + get => state.Get(FantasyEntityStateVariableTypes.Mana); + set => state[FantasyEntityStateVariableTypes.Mana] = value; + } + } public static void AddMana(this EntityStateVariables state, int change, int? maxMana = null) { - var newValue = state.Mana() + change; + var newValue = state.Mana + change; if (maxMana.HasValue) { state.AddValue(FantasyEntityStateVariableTypes.Mana, newValue, 0, maxMana.Value); } else - { state.Mana(newValue); } + { state.Mana= newValue; } } public static void DeductMana(this EntityStateVariables state, int change, int? maxMana = null) { - var newValue = state.Mana() - change; + var newValue = state.Mana - change; if (maxMana.HasValue) { state.AddValue(FantasyEntityStateVariableTypes.Mana, newValue, 0, maxMana.Value); } else - { state.Mana(newValue); } + { state.Mana = newValue; } } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/FantasyCombatReferencesExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/FantasyCombatReferencesExtensions.cs index 341a49c9..88c358cb 100644 --- a/src/OpenRpg.Genres.Fantasy/Extensions/FantasyCombatReferencesExtensions.cs +++ b/src/OpenRpg.Genres.Fantasy/Extensions/FantasyCombatReferencesExtensions.cs @@ -12,17 +12,17 @@ public static ICollection GetDamageReferences(this EntityStatsVar { return new[] { - new StatReference(FantasyDamageTypes.IceDamage, stats.IceDamage()), - new StatReference(FantasyDamageTypes.FireDamage, stats.FireDamage()), - new StatReference(FantasyDamageTypes.WindDamage, stats.WindDamage()), - new StatReference(FantasyDamageTypes.EarthDamage, stats.EarthDamage()), - new StatReference(FantasyDamageTypes.LightDamage, stats.LightDamage()), - new StatReference(FantasyDamageTypes.DarkDamage, stats.DarkDamage()), - new StatReference(FantasyDamageTypes.SlashingDamage, stats.SlashingDamage()), - new StatReference(FantasyDamageTypes.BluntDamage, stats.BluntDamage()), - new StatReference(FantasyDamageTypes.PiercingDamage, stats.PiercingDamage()), - new StatReference(FantasyDamageTypes.UnarmedDamage, stats.UnarmedDamage()), - new StatReference(FantasyDamageTypes.Damage, stats.Damage()) + new StatReference(FantasyDamageTypes.IceDamage, stats.IceDamage), + new StatReference(FantasyDamageTypes.FireDamage, stats.FireDamage), + new StatReference(FantasyDamageTypes.WindDamage, stats.WindDamage), + new StatReference(FantasyDamageTypes.EarthDamage, stats.EarthDamage), + new StatReference(FantasyDamageTypes.LightDamage, stats.LightDamage), + new StatReference(FantasyDamageTypes.DarkDamage, stats.DarkDamage), + new StatReference(FantasyDamageTypes.SlashingDamage, stats.SlashingDamage), + new StatReference(FantasyDamageTypes.BluntDamage, stats.BluntDamage), + new StatReference(FantasyDamageTypes.PiercingDamage, stats.PiercingDamage), + new StatReference(FantasyDamageTypes.UnarmedDamage, stats.UnarmedDamage), + new StatReference(FantasyDamageTypes.Damage, stats.Damage) }; } @@ -30,111 +30,111 @@ public static ICollection GetDefenseReferences(this EntityStatsVa { return new[] { - new StatReference(FantasyDamageTypes.IceDamage, stats.IceDefense()), - new StatReference(FantasyDamageTypes.FireDamage, stats.FireDefense()), - new StatReference(FantasyDamageTypes.WindDamage, stats.WindDefense()), - new StatReference(FantasyDamageTypes.EarthDamage, stats.EarthDefense()), - new StatReference(FantasyDamageTypes.LightDamage, stats.LightDefense()), - new StatReference(FantasyDamageTypes.DarkDamage, stats.DarkDefense()), - new StatReference(FantasyDamageTypes.SlashingDamage, stats.SlashingDefense()), - new StatReference(FantasyDamageTypes.BluntDamage, stats.BluntDefense()), - new StatReference(FantasyDamageTypes.PiercingDamage, stats.PiercingDefense()), - new StatReference(FantasyDamageTypes.UnarmedDamage, stats.UnarmedDefense()), - new StatReference(FantasyDamageTypes.Damage, stats.Defense()) + new StatReference(FantasyDamageTypes.IceDamage, stats.IceDefense), + new StatReference(FantasyDamageTypes.FireDamage, stats.FireDefense), + new StatReference(FantasyDamageTypes.WindDamage, stats.WindDefense), + new StatReference(FantasyDamageTypes.EarthDamage, stats.EarthDefense), + new StatReference(FantasyDamageTypes.LightDamage, stats.LightDefense), + new StatReference(FantasyDamageTypes.DarkDamage, stats.DarkDefense), + new StatReference(FantasyDamageTypes.SlashingDamage, stats.SlashingDefense), + new StatReference(FantasyDamageTypes.BluntDamage, stats.BluntDefense), + new StatReference(FantasyDamageTypes.PiercingDamage, stats.PiercingDefense), + new StatReference(FantasyDamageTypes.UnarmedDamage, stats.UnarmedDefense), + new StatReference(FantasyDamageTypes.Damage, stats.Defense) }; } public static float GetDefenseFor(this EntityStatsVariables stats, int effectType) { - if (effectType == FantasyEffectTypes.PiercingBonusAmount) { return stats.PiercingDefense(); } - if (effectType == FantasyEffectTypes.SlashingBonusAmount) { return stats.SlashingDefense(); } - if (effectType == FantasyEffectTypes.BluntBonusAmount) { return stats.BluntDefense(); } - if (effectType == FantasyEffectTypes.UnarmedBonusAmount) { return stats.UnarmedDefense(); } - if (effectType == FantasyEffectTypes.FireBonusAmount) { return stats.FireDefense(); } - if (effectType == FantasyEffectTypes.IceBonusAmount) { return stats.IceDefense(); } - if (effectType == FantasyEffectTypes.WindBonusAmount) { return stats.WindDefense(); } - if (effectType == FantasyEffectTypes.EarthBonusAmount) { return stats.EarthDefense(); } - if (effectType == FantasyEffectTypes.LightBonusAmount) { return stats.LightDefense(); } - if (effectType == FantasyEffectTypes.DarkBonusAmount) { return stats.DarkDefense(); } + if (effectType == FantasyEffectTypes.PiercingBonusAmount) { return stats.PiercingDefense; } + if (effectType == FantasyEffectTypes.SlashingBonusAmount) { return stats.SlashingDefense; } + if (effectType == FantasyEffectTypes.BluntBonusAmount) { return stats.BluntDefense; } + if (effectType == FantasyEffectTypes.UnarmedBonusAmount) { return stats.UnarmedDefense; } + if (effectType == FantasyEffectTypes.FireBonusAmount) { return stats.FireDefense; } + if (effectType == FantasyEffectTypes.IceBonusAmount) { return stats.IceDefense; } + if (effectType == FantasyEffectTypes.WindBonusAmount) { return stats.WindDefense; } + if (effectType == FantasyEffectTypes.EarthBonusAmount) { return stats.EarthDefense; } + if (effectType == FantasyEffectTypes.LightBonusAmount) { return stats.LightDefense; } + if (effectType == FantasyEffectTypes.DarkBonusAmount) { return stats.DarkDefense; } if (effectType == FantasyEffectTypes.AllElementDamageBonusAmount) { - return stats.FireDefense() + stats.IceDefense() + stats.WindDefense() + - stats.EarthDefense() + stats.LightDefense() + stats.DarkDefense(); + return stats.FireDefense + stats.IceDefense + stats.WindDefense + + stats.EarthDefense + stats.LightDefense + stats.DarkDefense; } if (effectType == FantasyEffectTypes.AllMeleeDefenseBonusAmount) { - return stats.PiercingDefense() + stats.SlashingDefense() + - stats.BluntDefense() + stats.UnarmedDefense(); + return stats.PiercingDefense + stats.SlashingDefense + + stats.BluntDefense + stats.UnarmedDefense; } if (effectType == FantasyEffectTypes.DamageBonusAmount) - { return stats.Defense(); } + { return stats.Defense; } return 0; } public static float GetDefenseFromDamageType(this EntityStatsVariables stats, int damageType) { - if (damageType == FantasyDamageTypes.PiercingDamage) { return stats.PiercingDefense(); } - if (damageType == FantasyDamageTypes.SlashingDamage) { return stats.SlashingDefense(); } - if (damageType == FantasyDamageTypes.BluntDamage) { return stats.BluntDefense(); } - if (damageType == FantasyDamageTypes.UnarmedDamage) { return stats.UnarmedDefense(); } - if (damageType == FantasyDamageTypes.FireDamage) { return stats.FireDefense(); } - if (damageType == FantasyDamageTypes.IceDamage) { return stats.IceDefense(); } - if (damageType == FantasyDamageTypes.WindDamage) { return stats.WindDefense(); } - if (damageType == FantasyDamageTypes.EarthDamage) { return stats.EarthDefense(); } - if (damageType == FantasyDamageTypes.LightDamage) { return stats.LightDefense(); } - if (damageType == FantasyDamageTypes.DarkDamage) { return stats.DarkDefense(); } - if (damageType == FantasyDamageTypes.Damage) { return stats.Defense(); } + if (damageType == FantasyDamageTypes.PiercingDamage) { return stats.PiercingDefense; } + if (damageType == FantasyDamageTypes.SlashingDamage) { return stats.SlashingDefense; } + if (damageType == FantasyDamageTypes.BluntDamage) { return stats.BluntDefense; } + if (damageType == FantasyDamageTypes.UnarmedDamage) { return stats.UnarmedDefense; } + if (damageType == FantasyDamageTypes.FireDamage) { return stats.FireDefense; } + if (damageType == FantasyDamageTypes.IceDamage) { return stats.IceDefense; } + if (damageType == FantasyDamageTypes.WindDamage) { return stats.WindDefense; } + if (damageType == FantasyDamageTypes.EarthDamage) { return stats.EarthDefense; } + if (damageType == FantasyDamageTypes.LightDamage) { return stats.LightDefense; } + if (damageType == FantasyDamageTypes.DarkDamage) { return stats.DarkDefense; } + if (damageType == FantasyDamageTypes.Damage) { return stats.Defense; } return 0; } public static float GetDamageFor(this EntityStatsVariables stats, int effectType) { - if (effectType == FantasyEffectTypes.PiercingBonusAmount) { return stats.PiercingDamage(); } - if (effectType == FantasyEffectTypes.SlashingBonusAmount) { return stats.SlashingDamage(); } - if (effectType == FantasyEffectTypes.BluntBonusAmount) { return stats.BluntDamage(); } - if (effectType == FantasyEffectTypes.UnarmedBonusAmount) { return stats.UnarmedDamage(); } - if (effectType == FantasyEffectTypes.FireBonusAmount) { return stats.FireDamage(); } - if (effectType == FantasyEffectTypes.IceBonusAmount) { return stats.IceDamage(); } - if (effectType == FantasyEffectTypes.WindBonusAmount) { return stats.WindDamage(); } - if (effectType == FantasyEffectTypes.EarthBonusAmount) { return stats.EarthDamage(); } - if (effectType == FantasyEffectTypes.LightBonusAmount) { return stats.LightDamage(); } - if (effectType == FantasyEffectTypes.DarkBonusAmount) { return stats.DarkDamage(); } + if (effectType == FantasyEffectTypes.PiercingBonusAmount) { return stats.PiercingDamage; } + if (effectType == FantasyEffectTypes.SlashingBonusAmount) { return stats.SlashingDamage; } + if (effectType == FantasyEffectTypes.BluntBonusAmount) { return stats.BluntDamage; } + if (effectType == FantasyEffectTypes.UnarmedBonusAmount) { return stats.UnarmedDamage; } + if (effectType == FantasyEffectTypes.FireBonusAmount) { return stats.FireDamage; } + if (effectType == FantasyEffectTypes.IceBonusAmount) { return stats.IceDamage; } + if (effectType == FantasyEffectTypes.WindBonusAmount) { return stats.WindDamage; } + if (effectType == FantasyEffectTypes.EarthBonusAmount) { return stats.EarthDamage; } + if (effectType == FantasyEffectTypes.LightBonusAmount) { return stats.LightDamage; } + if (effectType == FantasyEffectTypes.DarkBonusAmount) { return stats.DarkDamage; } if (effectType == FantasyEffectTypes.AllElementDamageBonusAmount) { - return stats.FireDamage() + stats.IceDamage() + stats.WindDamage() + - stats.EarthDamage() + stats.LightDamage() + stats.DarkDamage(); + return stats.FireDamage + stats.IceDamage + stats.WindDamage + + stats.EarthDamage + stats.LightDamage + stats.DarkDamage; } if (effectType == FantasyEffectTypes.AllMeleeDefenseBonusAmount) { - return stats.PiercingDamage() + stats.SlashingDamage() + - stats.BluntDamage() + stats.UnarmedDamage(); + return stats.PiercingDamage + stats.SlashingDamage + + stats.BluntDamage + stats.UnarmedDamage; } if (effectType == FantasyEffectTypes.DamageBonusAmount) - { return stats.Damage(); } + { return stats.Damage; } return 0; } public static float GetDamageFromDamageType(this EntityStatsVariables stats, int damageType) { - if (damageType == FantasyDamageTypes.PiercingDamage) { return stats.PiercingDamage(); } - if (damageType == FantasyDamageTypes.SlashingDamage) { return stats.SlashingDamage(); } - if (damageType == FantasyDamageTypes.BluntDamage) { return stats.BluntDamage(); } - if (damageType == FantasyDamageTypes.UnarmedDamage) { return stats.UnarmedDamage(); } - if (damageType == FantasyDamageTypes.FireDamage) { return stats.FireDamage(); } - if (damageType == FantasyDamageTypes.IceDamage) { return stats.IceDamage(); } - if (damageType == FantasyDamageTypes.WindDamage) { return stats.WindDamage(); } - if (damageType == FantasyDamageTypes.EarthDamage) { return stats.EarthDamage(); } - if (damageType == FantasyDamageTypes.LightDamage) { return stats.LightDamage(); } - if (damageType == FantasyDamageTypes.DarkDamage) { return stats.DarkDamage(); } - if (damageType == FantasyDamageTypes.Damage) { return stats.Damage(); } + if (damageType == FantasyDamageTypes.PiercingDamage) { return stats.PiercingDamage; } + if (damageType == FantasyDamageTypes.SlashingDamage) { return stats.SlashingDamage; } + if (damageType == FantasyDamageTypes.BluntDamage) { return stats.BluntDamage; } + if (damageType == FantasyDamageTypes.UnarmedDamage) { return stats.UnarmedDamage; } + if (damageType == FantasyDamageTypes.FireDamage) { return stats.FireDamage; } + if (damageType == FantasyDamageTypes.IceDamage) { return stats.IceDamage; } + if (damageType == FantasyDamageTypes.WindDamage) { return stats.WindDamage; } + if (damageType == FantasyDamageTypes.EarthDamage) { return stats.EarthDamage; } + if (damageType == FantasyDamageTypes.LightDamage) { return stats.LightDamage; } + if (damageType == FantasyDamageTypes.DarkDamage) { return stats.DarkDamage; } + if (damageType == FantasyDamageTypes.Damage) { return stats.Damage; } return 0; } } diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/FantasyEntityExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/FantasyEntityExtensions.cs index b2e282ee..501bf36e 100644 --- a/src/OpenRpg.Genres.Fantasy/Extensions/FantasyEntityExtensions.cs +++ b/src/OpenRpg.Genres.Fantasy/Extensions/FantasyEntityExtensions.cs @@ -4,7 +4,9 @@ namespace OpenRpg.Genres.Fantasy.Extensions { public static class FantasyEntityExtensions { - public static float GetManaPercentage(this Entity entity) - { return (float)entity.State.Mana() / entity.Stats.MaxMana(); } + extension(Entity entity) + { + public float ManaPercentage => entity.State.Mana / entity.Stats.MaxMana; + } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Requirements/DefaultFantasyCharacterRequirementChecker.cs b/src/OpenRpg.Genres.Fantasy/Requirements/DefaultFantasyCharacterRequirementChecker.cs index c9782732..8028e132 100644 --- a/src/OpenRpg.Genres.Fantasy/Requirements/DefaultFantasyCharacterRequirementChecker.cs +++ b/src/OpenRpg.Genres.Fantasy/Requirements/DefaultFantasyCharacterRequirementChecker.cs @@ -12,25 +12,25 @@ public class DefaultFantasyCharacterRequirementChecker : DefaultCharacterRequire public override bool IsRequirementMet(Character character, Requirement requirement) { if(requirement.RequirementType == FantasyRequirementTypes.StrengthRequirement) - { return character.Stats.Strength() >= requirement.Association.AssociatedValue; } + { return character.Stats.Strength >= requirement.Association.AssociatedValue; } if(requirement.RequirementType == FantasyRequirementTypes.DexterityRequirement) - { return character.Stats.Dexterity() >= requirement.Association.AssociatedValue; } + { return character.Stats.Dexterity >= requirement.Association.AssociatedValue; } if(requirement.RequirementType == FantasyRequirementTypes.IntelligenceRequirement) - { return character.Stats.Intelligence() >= requirement.Association.AssociatedValue; } + { return character.Stats.Intelligence >= requirement.Association.AssociatedValue; } if(requirement.RequirementType == FantasyRequirementTypes.ConstitutionRequirement) - { return character.Stats.Constitution() >= requirement.Association.AssociatedValue; } + { return character.Stats.Constitution >= requirement.Association.AssociatedValue; } if(requirement.RequirementType == FantasyRequirementTypes.WisdomRequirement) - { return character.Stats.Wisdom() >= requirement.Association.AssociatedValue; } + { return character.Stats.Wisdom >= requirement.Association.AssociatedValue; } if(requirement.RequirementType == FantasyRequirementTypes.CharismaRequirement) - { return character.Stats.Charisma() >= requirement.Association.AssociatedValue; } + { return character.Stats.Charisma >= requirement.Association.AssociatedValue; } if(requirement.RequirementType == FantasyRequirementTypes.MaxManaRequirement) - { return character.Stats.MaxMana() >= requirement.Association.AssociatedValue; } + { return character.Stats.MaxMana >= requirement.Association.AssociatedValue; } return base.IsRequirementMet(character, requirement); } diff --git a/src/OpenRpg.Genres.Fantasy/State/Populators/FantasyStatePopulator.cs b/src/OpenRpg.Genres.Fantasy/State/Populators/FantasyStatePopulator.cs index f787143d..bd65a62e 100644 --- a/src/OpenRpg.Genres.Fantasy/State/Populators/FantasyStatePopulator.cs +++ b/src/OpenRpg.Genres.Fantasy/State/Populators/FantasyStatePopulator.cs @@ -19,9 +19,9 @@ public void Populate(EntityStateVariables state, ComputedEffects computedEffects if(statsVars == null) { return; } var entityStats = statsVars as EntityStatsVariables; - state.Health(entityStats.MaxHealth()); - state.Stamina(entityStats.MaxStamina()); - state.Mana(entityStats.MaxMana()); + state.Health = entityStats.MaxHealth; + state.Stamina = entityStats.MaxStamina; + state.Mana = entityStats.MaxMana; } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyAttributeStatPopulator.cs b/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyAttributeStatPopulator.cs index bcb356c7..a70155c1 100644 --- a/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyAttributeStatPopulator.cs +++ b/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyAttributeStatPopulator.cs @@ -22,12 +22,12 @@ public int CalculateStateFor(ComputedEffects computedEffects, int amountType, in public void Populate(EntityStatsVariables stats, ComputedEffects computedEffects, IReadOnlyCollection relatedVars) { - stats.Strength(CalculateStateFor(computedEffects, FantasyEffectTypes.StrengthBonusAmount, FantasyEffectTypes.StrengthBonusPercentage)); - stats.Dexterity(CalculateStateFor(computedEffects, FantasyEffectTypes.DexterityBonusAmount, FantasyEffectTypes.DexterityBonusPercentage)); - stats.Constitution(CalculateStateFor(computedEffects, FantasyEffectTypes.ConstitutionBonusAmount, FantasyEffectTypes.ConstitutionBonusPercentage)); - stats.Intelligence(CalculateStateFor(computedEffects, FantasyEffectTypes.IntelligenceBonusAmount, FantasyEffectTypes.IntelligenceBonusPercentage)); - stats.Wisdom(CalculateStateFor(computedEffects, FantasyEffectTypes.WisdomBonusAmount, FantasyEffectTypes.WisdomBonusPercentage)); - stats.Charisma(CalculateStateFor(computedEffects, FantasyEffectTypes.CharismaBonusAmount, FantasyEffectTypes.CharismaBonusPercentage)); + stats.Strength = CalculateStateFor(computedEffects, FantasyEffectTypes.StrengthBonusAmount, FantasyEffectTypes.StrengthBonusPercentage); + stats.Dexterity = CalculateStateFor(computedEffects, FantasyEffectTypes.DexterityBonusAmount, FantasyEffectTypes.DexterityBonusPercentage); + stats.Constitution = CalculateStateFor(computedEffects, FantasyEffectTypes.ConstitutionBonusAmount, FantasyEffectTypes.ConstitutionBonusPercentage); + stats.Intelligence = CalculateStateFor(computedEffects, FantasyEffectTypes.IntelligenceBonusAmount, FantasyEffectTypes.IntelligenceBonusPercentage); + stats.Wisdom = CalculateStateFor(computedEffects, FantasyEffectTypes.WisdomBonusAmount, FantasyEffectTypes.WisdomBonusPercentage); + stats.Charisma = CalculateStateFor(computedEffects, FantasyEffectTypes.CharismaBonusAmount, FantasyEffectTypes.CharismaBonusPercentage); } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyElementalStatPopulator.cs b/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyElementalStatPopulator.cs index 475c5349..e771e977 100644 --- a/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyElementalStatPopulator.cs +++ b/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyElementalStatPopulator.cs @@ -24,20 +24,20 @@ public float CalculateStatsWithModifier(ComputedEffects computedEffects, int eff public void Populate(EntityStatsVariables stats, ComputedEffects computedEffects, IReadOnlyCollection relatedVars) { - var intModifier = stats.Intelligence() / 100.0f; - stats.IceDamage(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.IceDamageRelationship, intModifier)); - stats.FireDamage(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.FireDamageRelationship, intModifier)); - stats.WindDamage(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.WindDamageRelationship, intModifier)); - stats.EarthDamage(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.EarthDamageRelationship, intModifier)); - stats.LightDamage(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.LightDamageRelationship, intModifier)); - stats.DarkDamage(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.DarkDamageRelationship, intModifier)); + var intModifier = stats.Intelligence / 100.0f; + stats.IceDamage = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.IceDamageRelationship, intModifier); + stats.FireDamage = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.FireDamageRelationship, intModifier); + stats.WindDamage = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.WindDamageRelationship, intModifier); + stats.EarthDamage = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.EarthDamageRelationship, intModifier); + stats.LightDamage = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.LightDamageRelationship, intModifier); + stats.DarkDamage = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDamageBonusAmount, FantasyEffectTypes.AllElementDamageBonusPercentage, EffectRelationships.DarkDamageRelationship, intModifier); - stats.IceDefense(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.IceDefenseRelationship, intModifier)); - stats.FireDefense(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.FireDefenseRelationship, intModifier)); - stats.WindDefense(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.WindDefenseRelationship, intModifier)); - stats.EarthDefense(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.EarthDefenseRelationship, intModifier)); - stats.LightDefense(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.LightDefenseRelationship, intModifier)); - stats.DarkDefense(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.DarkDefenseRelationship, intModifier)); + stats.IceDefense = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.IceDefenseRelationship, intModifier); + stats.FireDefense = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.FireDefenseRelationship, intModifier); + stats.WindDefense = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.WindDefenseRelationship, intModifier); + stats.EarthDefense = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.EarthDefenseRelationship, intModifier); + stats.LightDefense = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.LightDefenseRelationship, intModifier); + stats.DarkDefense = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllElementDefenseBonusAmount, FantasyEffectTypes.AllElementDefenseBonusPercentage, EffectRelationships.DarkDefenseRelationship, intModifier); } } } diff --git a/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyMeleeStatPopulator.cs b/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyMeleeStatPopulator.cs index 77f202e1..8dad315a 100644 --- a/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyMeleeStatPopulator.cs +++ b/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyMeleeStatPopulator.cs @@ -26,19 +26,19 @@ public float CalculateStatsWithModifier(ComputedEffects computedEffects, int eff public void Populate(EntityStatsVariables stats, ComputedEffects computedEffects, IReadOnlyCollection relatedVars) { - var bluntModifier = stats.Strength() / 100.0f; - var piercingModifier = stats.Dexterity() / 100.0f; + var bluntModifier = stats.Strength / 100.0f; + var piercingModifier = stats.Dexterity / 100.0f; var slashingOrUnarmedModifier = (bluntModifier + piercingModifier) / 2; - stats.BluntDamage(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeAttackBonusAmount, FantasyEffectTypes.AllMeleeAttackBonusPercentage, EffectRelationships.BluntDamageRelationship, bluntModifier)); - stats.PiercingDamage(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeAttackBonusAmount, FantasyEffectTypes.AllMeleeAttackBonusPercentage, EffectRelationships.PiercingDamageRelationship, piercingModifier)); - stats.SlashingDamage(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeAttackBonusAmount, FantasyEffectTypes.AllMeleeAttackBonusPercentage, EffectRelationships.SlashingDamageRelationship, slashingOrUnarmedModifier)); - stats.UnarmedDamage(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeAttackBonusAmount, FantasyEffectTypes.AllMeleeAttackBonusPercentage, EffectRelationships.UnarmedDamageRelationship, slashingOrUnarmedModifier)); + stats.BluntDamage = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeAttackBonusAmount, FantasyEffectTypes.AllMeleeAttackBonusPercentage, EffectRelationships.BluntDamageRelationship, bluntModifier); + stats.PiercingDamage = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeAttackBonusAmount, FantasyEffectTypes.AllMeleeAttackBonusPercentage, EffectRelationships.PiercingDamageRelationship, piercingModifier); + stats.SlashingDamage = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeAttackBonusAmount, FantasyEffectTypes.AllMeleeAttackBonusPercentage, EffectRelationships.SlashingDamageRelationship, slashingOrUnarmedModifier); + stats.UnarmedDamage = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeAttackBonusAmount, FantasyEffectTypes.AllMeleeAttackBonusPercentage, EffectRelationships.UnarmedDamageRelationship, slashingOrUnarmedModifier); - stats.BluntDefense(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, EffectRelationships.BluntDefenseRelationship, bluntModifier)); - stats.PiercingDefense(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, EffectRelationships.PiercingDefenseRelationship, piercingModifier)); - stats.SlashingDefense(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, EffectRelationships.SlashingDefenseRelationship, slashingOrUnarmedModifier)); - stats.UnarmedDefense(CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, EffectRelationships.UnarmedDefenseRelationship, slashingOrUnarmedModifier)); + stats.BluntDefense = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, EffectRelationships.BluntDefenseRelationship, bluntModifier); + stats.PiercingDefense = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, EffectRelationships.PiercingDefenseRelationship, piercingModifier); + stats.SlashingDefense = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, EffectRelationships.SlashingDefenseRelationship, slashingOrUnarmedModifier); + stats.UnarmedDefense = CalculateStatsWithModifier(computedEffects, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, FantasyEffectTypes.AllMeleeDefenseBonusPercentage, EffectRelationships.UnarmedDefenseRelationship, slashingOrUnarmedModifier); } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyVitalsStatPopulator.cs b/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyVitalsStatPopulator.cs index ed864999..5747d3c3 100644 --- a/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyVitalsStatPopulator.cs +++ b/src/OpenRpg.Genres.Fantasy/Stats/Populators/Partial/FantasyVitalsStatPopulator.cs @@ -16,26 +16,22 @@ public class FantasyVitalsStatPopulator : IEntityPartialStatPopulator public void Populate(EntityStatsVariables stats, ComputedEffects computedEffects, IReadOnlyCollection relatedVars) { - var constitutionBonus = stats.Constitution() * 5; - var maxHealth = (int)computedEffects.CalculateTotalValueFor(FantasyEffectTypes.HealthBonusAmount, FantasyEffectTypes.HealthBonusPercentage, constitutionBonus); - stats.MaxHealth(maxHealth); + var constitutionBonus = stats.Constitution * 5; + stats.MaxHealth = (int)computedEffects.CalculateTotalValueFor(FantasyEffectTypes.HealthBonusAmount, FantasyEffectTypes.HealthBonusPercentage, constitutionBonus); + stats.MaxStamina = (int)computedEffects.CalculateTotalValueFor(FantasyEffectTypes.StaminaBonusAmount, FantasyEffectTypes.StaminaBonusPercentage, constitutionBonus); - var maxStamina = (int)computedEffects.CalculateTotalValueFor(FantasyEffectTypes.StaminaBonusAmount, FantasyEffectTypes.StaminaBonusPercentage, constitutionBonus); - stats.MaxStamina(maxStamina); + var intelligenceBonus = stats.Intelligence * 5; + stats.MaxMana = (int)computedEffects.CalculateTotalValueFor(FantasyEffectTypes.ManaBonusAmount, FantasyEffectTypes.ManaBonusPercentage, intelligenceBonus); - var intelligenceBonus = stats.Intelligence() * 5; - var maxMana = (int)computedEffects.CalculateTotalValueFor(FantasyEffectTypes.ManaBonusAmount, FantasyEffectTypes.ManaBonusPercentage, intelligenceBonus); - stats.MaxMana(maxMana); + stats.HealthRegen = computedEffects.CalculateTotalValueFor(FantasyEffectTypes.HealthRegenBonusAmount, FantasyEffectTypes.HealthRegenBonusPercentage); + stats.ManaRegen = computedEffects.CalculateTotalValueFor(FantasyEffectTypes.ManaRegenBonusAmount, FantasyEffectTypes.ManaRegenBonusPercentage); + stats.StaminaRegen = computedEffects.CalculateTotalValueFor(FantasyEffectTypes.StaminaRegenBonusAmount, FantasyEffectTypes.StaminaRegenBonusPercentage); - stats.HealthRegen(computedEffects.CalculateTotalValueFor(FantasyEffectTypes.HealthRegenBonusAmount, FantasyEffectTypes.HealthRegenBonusPercentage)); - stats.ManaRegen(computedEffects.CalculateTotalValueFor(FantasyEffectTypes.ManaRegenBonusAmount, FantasyEffectTypes.ManaRegenBonusPercentage)); - stats.StaminaRegen(computedEffects.CalculateTotalValueFor(FantasyEffectTypes.StaminaRegenBonusAmount, FantasyEffectTypes.StaminaRegenBonusPercentage)); + stats.HealthRegenRate = computedEffects.CalculateTotalValueFor(FantasyEffectTypes.HealthRegenRateBonusAmount, FantasyEffectTypes.HealthRegenRateBonusPercentage); + stats.ManaRegenRate = computedEffects.CalculateTotalValueFor(FantasyEffectTypes.ManaRegenRateBonusAmount, FantasyEffectTypes.ManaRegenRateBonusPercentage); + stats.StaminaRegenRate = computedEffects.CalculateTotalValueFor(FantasyEffectTypes.StaminaRegenRateBonusAmount, FantasyEffectTypes.StaminaRegenRateBonusPercentage); - stats.HealthRegenRate(computedEffects.CalculateTotalValueFor(FantasyEffectTypes.HealthRegenRateBonusAmount, FantasyEffectTypes.HealthRegenRateBonusPercentage)); - stats.ManaRegenRate(computedEffects.CalculateTotalValueFor(FantasyEffectTypes.ManaRegenRateBonusAmount, FantasyEffectTypes.ManaRegenRateBonusPercentage)); - stats.StaminaRegenRate(computedEffects.CalculateTotalValueFor(FantasyEffectTypes.StaminaRegenRateBonusAmount, FantasyEffectTypes.StaminaRegenRateBonusPercentage)); - - stats.MovementSpeed(computedEffects.CalculateTotalValueFor(FantasyEffectTypes.MovementSpeedBonusAmount, FantasyEffectTypes.MovementSpeedBonusPercentage)); + stats.MovementSpeed = computedEffects.CalculateTotalValueFor(FantasyEffectTypes.MovementSpeedBonusAmount, FantasyEffectTypes.MovementSpeedBonusPercentage); } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Extensions/EntityExtensions.cs b/src/OpenRpg.Genres/Extensions/EntityExtensions.cs index 103ea67d..5414d767 100644 --- a/src/OpenRpg.Genres/Extensions/EntityExtensions.cs +++ b/src/OpenRpg.Genres/Extensions/EntityExtensions.cs @@ -21,8 +21,8 @@ public static IReadOnlyCollection GetEffects(this Entity entity, ITempl extension(Entity entity) { - public float HealthPercentage => (float)entity.State.Health() / entity.Stats.MaxHealth(); - public float StaminaPercentage => (float)entity.State.Stamina() / entity.Stats.MaxStamina(); + public float HealthPercentage => (float)entity.State.Health / entity.Stats.MaxHealth; + public float StaminaPercentage => (float)entity.State.Stamina / entity.Stats.MaxStamina; } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Extensions/EntityStatVariableExtensions.cs b/src/OpenRpg.Genres/Extensions/EntityStatVariableExtensions.cs index 6b75cdbd..af9c3835 100644 --- a/src/OpenRpg.Genres/Extensions/EntityStatVariableExtensions.cs +++ b/src/OpenRpg.Genres/Extensions/EntityStatVariableExtensions.cs @@ -6,42 +6,91 @@ namespace OpenRpg.Genres.Extensions { public static class EntityStatVariableExtensions { - public static int MaxHealth(this EntityStatsVariables stats) => (int)stats.Get(GenreEntityStatsVariableTypes.MaxHealth); - public static void MaxHealth(this EntityStatsVariables stats, int value) => stats[GenreEntityStatsVariableTypes.MaxHealth] = value; - - public static int MaxStamina(this EntityStatsVariables stats) => (int)stats.Get(GenreEntityStatsVariableTypes.MaxStamina); - public static void MaxStamina(this EntityStatsVariables stats, int value) => stats[GenreEntityStatsVariableTypes.MaxStamina] = value; - - public static float Damage(this EntityStatsVariables stats) => stats.Get(GenreEntityStatsVariableTypes.Damage); - public static void Damage(this EntityStatsVariables stats, float value) => stats[GenreEntityStatsVariableTypes.Damage] = value; - public static float Defense(this EntityStatsVariables stats) => stats.Get(GenreEntityStatsVariableTypes.Defense); - public static void Defense(this EntityStatsVariables stats, float value) => stats[GenreEntityStatsVariableTypes.Defense] = value; - - public static float CriticalDamageChance(this EntityStatsVariables stats) => stats.GetValueOrDefault(GenreEntityStatsVariableTypes.CriticalDamageChance, 0); - public static void CriticalDamageChance(this EntityStatsVariables stats, float criticalDamageChance) => stats[GenreEntityStatsVariableTypes.CriticalDamageChance] = criticalDamageChance; - public static float CriticalDamageMultiplier(this EntityStatsVariables stats) => stats.GetValueOrDefault(GenreEntityStatsVariableTypes.CriticalDamageMultiplier, 0); - public static void CriticalDamageMultiplier(this EntityStatsVariables stats, float criticalDamageMultiplier) => stats[GenreEntityStatsVariableTypes.CriticalDamageMultiplier] = criticalDamageMultiplier; - - public static float CooldownReduction(this EntityStatsVariables stats) => stats.GetValueOrDefault(GenreEntityStatsVariableTypes.CooldownReduction, 0); - public static void CooldownReduction(this EntityStatsVariables stats, float cooldownReduction) => stats[GenreEntityStatsVariableTypes.CooldownReduction] = cooldownReduction; - - public static float AttackSize(this EntityStatsVariables stats) => stats.GetValueOrDefault(GenreEntityStatsVariableTypes.AttackSize, 0); - public static void AttackSize(this EntityStatsVariables stats, float attackSize) => stats[GenreEntityStatsVariableTypes.AttackSize] = attackSize; - - public static float AttackRange(this EntityStatsVariables stats) => stats.GetValueOrDefault(GenreEntityStatsVariableTypes.AttackRange, 0); - public static void AttackRange(this EntityStatsVariables stats, float attackSpeed) => stats[GenreEntityStatsVariableTypes.AttackRange] = attackSpeed; - - public static float HealthRegen(this EntityStatsVariables stats) => stats.GetValueOrDefault(GenreEntityStatsVariableTypes.HealthRegen, 0); - public static void HealthRegen(this EntityStatsVariables stats, float staminaRegen) => stats[GenreEntityStatsVariableTypes.HealthRegen] = staminaRegen; - public static float StaminaRegen(this EntityStatsVariables stats) => stats.GetValueOrDefault(GenreEntityStatsVariableTypes.StaminaRegen, 0); - public static void StaminaRegen(this EntityStatsVariables stats, float staminaRegen) => stats[GenreEntityStatsVariableTypes.StaminaRegen] = staminaRegen; - - public static float HealthRegenRate(this EntityStatsVariables stats) => stats.GetValueOrDefault(GenreEntityStatsVariableTypes.HealthRegenRate, 0); - public static void HealthRegenRate(this EntityStatsVariables stats, float regenRate) => stats[GenreEntityStatsVariableTypes.HealthRegenRate] = regenRate; - public static float StaminaRegenRate(this EntityStatsVariables stats) => stats.GetValueOrDefault(GenreEntityStatsVariableTypes.StaminaRegenRate, 0); - public static void StaminaRegenRate(this EntityStatsVariables stats, float regenRate) => stats[GenreEntityStatsVariableTypes.StaminaRegenRate] = regenRate; - - public static float MovementSpeed(this EntityStatsVariables stats) => stats.GetValueOrDefault(GenreEntityStatsVariableTypes.MovementSpeed, 0); - public static void MovementSpeed(this EntityStatsVariables stats, float movementSpeed) => stats[GenreEntityStatsVariableTypes.MovementSpeed] = movementSpeed; + extension(EntityStatsVariables state) + { + public int MaxHealth + { + get => (int)state.Get(GenreEntityStatsVariableTypes.MaxHealth); + set => state[GenreEntityStatsVariableTypes.MaxHealth] = value; + } + + public int MaxStamina + { + get => (int)state.Get(GenreEntityStatsVariableTypes.MaxStamina); + set => state[GenreEntityStatsVariableTypes.MaxStamina] = value; + } + + public float HealthRegen + { + get => state.Get(GenreEntityStatsVariableTypes.HealthRegen); + set => state[GenreEntityStatsVariableTypes.HealthRegen] = value; + } + + public float StaminaRegen + { + get => state.Get(GenreEntityStatsVariableTypes.StaminaRegen); + set => state[GenreEntityStatsVariableTypes.StaminaRegen] = value; + } + + public float HealthRegenRate + { + get => state.Get(GenreEntityStatsVariableTypes.HealthRegenRate); + set => state[GenreEntityStatsVariableTypes.HealthRegenRate] = value; + } + + public float StaminaRegenRate + { + get => state.Get(GenreEntityStatsVariableTypes.StaminaRegenRate); + set => state[GenreEntityStatsVariableTypes.StaminaRegenRate] = value; + } + + public float Damage + { + get => state.Get(GenreEntityStatsVariableTypes.Damage); + set => state[GenreEntityStatsVariableTypes.Damage] = value; + } + + public float Defense + { + get => state.Get(GenreEntityStatsVariableTypes.Defense); + set => state[GenreEntityStatsVariableTypes.Defense] = value; + } + + public float CriticalDamageChance + { + get => state.Get(GenreEntityStatsVariableTypes.CriticalDamageChance); + set => state[GenreEntityStatsVariableTypes.CriticalDamageChance] = value; + } + + public float CriticalDamageMultiplier + { + get => state.Get(GenreEntityStatsVariableTypes.CriticalDamageMultiplier); + set => state[GenreEntityStatsVariableTypes.CriticalDamageMultiplier] = value; + } + + public float CooldownReduction + { + get => state.Get(GenreEntityStatsVariableTypes.CooldownReduction); + set => state[GenreEntityStatsVariableTypes.CooldownReduction] = value; + } + + public float AttackSize + { + get => state.Get(GenreEntityStatsVariableTypes.AttackSize); + set => state[GenreEntityStatsVariableTypes.AttackSize] = value; + } + + public float AttackRange + { + get => state.Get(GenreEntityStatsVariableTypes.AttackRange); + set => state[GenreEntityStatsVariableTypes.AttackRange] = value; + } + + public float MovementSpeed + { + get => state.Get(GenreEntityStatsVariableTypes.MovementSpeed); + set => state[GenreEntityStatsVariableTypes.MovementSpeed] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Extensions/EntityStateVariablesExtensions.cs b/src/OpenRpg.Genres/Extensions/EntityStateVariablesExtensions.cs index d6f1ec4a..2ee5e89f 100644 --- a/src/OpenRpg.Genres/Extensions/EntityStateVariablesExtensions.cs +++ b/src/OpenRpg.Genres/Extensions/EntityStateVariablesExtensions.cs @@ -9,65 +9,76 @@ namespace OpenRpg.Genres.Extensions { public static class EntityStateVariablesExtensions { - public static int Health(this EntityStateVariables state) => (int)state.Get(GenreEntityStateVariableTypes.Health); - public static void Health(this EntityStateVariables state, int value) => state[GenreEntityStateVariableTypes.Health] = value; - - public static int Stamina(this EntityStateVariables state) => (int)state.Get(GenreEntityStateVariableTypes.Stamina); - public static void Stamina(this EntityStateVariables state, int value) => state[GenreEntityStateVariableTypes.Stamina] = value; + extension(EntityStateVariables state) + { + public int Health + { + get => (int)state.Get(GenreEntityStateVariableTypes.Health); + set => state[GenreEntityStateVariableTypes.Health] = value; + } + + public bool IsDead => state.Health <= 0; + } public static void AddHealth(this EntityStateVariables state, int change, int? maxHealth = null) { - var newValue = state.Health() + change; + var newValue = state.Health + change; if(newValue <= 0) { newValue = 0; } if(maxHealth == null) - { state.Health(newValue); } + { state.Health = newValue; } else { state.AddValue(GenreEntityStateVariableTypes.Health, newValue, 0, maxHealth.Value); } } public static void DeductHealth(this EntityStateVariables state, int change, int? maxHealth = null) { - var newValue = state.Health() - change; + var newValue = state.Health - change; if(newValue <= 0) { newValue = 0; } if (maxHealth == null) - { state.Health(newValue); } + { state.Health = newValue; } else { state.AddValue(GenreEntityStateVariableTypes.Health, newValue, 0, maxHealth.Value); } } + public static void ApplyDamageToTarget(this EntityStateVariables state, ProcessedAttack attack) + { + var summedAttack = attack.DamageDone.Sum(x => x.Value); + var totalDamage = (int)Math.Round(summedAttack); + if (totalDamage < 0) { totalDamage = 0; } + state.DeductHealth(totalDamage); + } + + extension(EntityStateVariables state) + { + public int Stamina + { + get => (int)state.Get(GenreEntityStateVariableTypes.Stamina); + set => state[GenreEntityStateVariableTypes.Stamina] = value; + } + } + public static void AddStamina(this EntityStateVariables state, int change, int? maxStamina = null) { - var newValue = state.Health() + change; + var newValue = state.Stamina + change; if(newValue <= 0) { newValue = 0; } if(maxStamina == null) - { state.Stamina(newValue); } + { state.Stamina = newValue; } else { state.AddValue(GenreEntityStateVariableTypes.Stamina, newValue, 0, maxStamina.Value); } } public static void DeductStamina(this EntityStateVariables state, int change, int? maxStamina = null) { - var newValue = state.Health() - change; + var newValue = state.Stamina - change; if(newValue <= 0) { newValue = 0; } if (maxStamina == null) - { state.Stamina(newValue); } + { state.Stamina = newValue; } else - { state.AddValue(GenreEntityStateVariableTypes.Health, newValue, 0, maxStamina.Value); } - } - - public static void ApplyDamageToTarget(this EntityStateVariables state, ProcessedAttack attack) - { - var summedAttack = attack.DamageDone.Sum(x => x.Value); - var totalDamage = (int)Math.Round(summedAttack); - if (totalDamage < 0) { totalDamage = 0; } - state.DeductHealth(totalDamage); + { state.AddValue(GenreEntityStateVariableTypes.Stamina, newValue, 0, maxStamina.Value); } } - - public static bool IsDead(this EntityStateVariables state) - { return state.Health() <= 0; } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Populators/Entity/State/BasicEntityStatePopulator.cs b/src/OpenRpg.Genres/Populators/Entity/State/BasicEntityStatePopulator.cs index 76343798..744ee205 100644 --- a/src/OpenRpg.Genres/Populators/Entity/State/BasicEntityStatePopulator.cs +++ b/src/OpenRpg.Genres/Populators/Entity/State/BasicEntityStatePopulator.cs @@ -18,8 +18,8 @@ public void Populate(EntityStateVariables varsToPopulate, ComputedEffects comput if(statsVars == null) { return; } var entityStats = statsVars as EntityStatsVariables; - varsToPopulate.Health(entityStats.MaxHealth()); - varsToPopulate.Stamina(entityStats.MaxStamina()); + varsToPopulate.Health = entityStats.MaxHealth; + varsToPopulate.Stamina = entityStats.MaxStamina; } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Populators/Entity/Stats/AbilityStatPopulator.cs b/src/OpenRpg.Genres/Populators/Entity/Stats/AbilityStatPopulator.cs index ab66283c..16447273 100644 --- a/src/OpenRpg.Genres/Populators/Entity/Stats/AbilityStatPopulator.cs +++ b/src/OpenRpg.Genres/Populators/Entity/Stats/AbilityStatPopulator.cs @@ -15,14 +15,17 @@ public class AbilityStatPopulator : IEntityPartialStatPopulator public void Populate(EntityStatsVariables stats, ComputedEffects computedEffects, IReadOnlyCollection relatedVars) { - stats.AttackRange(computedEffects.CalculateTotalValueFor(GenreEffectTypes.AttackRangeBonusAmount, - GenreEffectTypes.AttackRangeBonusPercentage)); + stats.AttackRange = computedEffects.CalculateTotalValueFor( + GenreEffectTypes.AttackRangeBonusAmount, + GenreEffectTypes.AttackRangeBonusPercentage); - stats.AttackSize(computedEffects.CalculateTotalValueFor(GenreEffectTypes.AttackRangeBonusAmount, - GenreEffectTypes.AttackRangeBonusPercentage)); + stats.AttackSize = computedEffects.CalculateTotalValueFor( + GenreEffectTypes.AttackRangeBonusAmount, + GenreEffectTypes.AttackRangeBonusPercentage); - stats.CooldownReduction(computedEffects.CalculateTotalValueFor(GenreEffectTypes.AttackRangeBonusAmount, - GenreEffectTypes.AttackRangeBonusPercentage)); + stats.CooldownReduction = computedEffects.CalculateTotalValueFor( + GenreEffectTypes.AttackRangeBonusAmount, + GenreEffectTypes.AttackRangeBonusPercentage); } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Populators/Entity/Stats/CriticalStatPopulator.cs b/src/OpenRpg.Genres/Populators/Entity/Stats/CriticalStatPopulator.cs index 76a77e22..eb7d4525 100644 --- a/src/OpenRpg.Genres/Populators/Entity/Stats/CriticalStatPopulator.cs +++ b/src/OpenRpg.Genres/Populators/Entity/Stats/CriticalStatPopulator.cs @@ -15,10 +15,13 @@ public class CriticalStatPopulator : IEntityPartialStatPopulator public void Populate(EntityStatsVariables stats, ComputedEffects computedEffects, IReadOnlyCollection relatedVars) { - stats.CriticalDamageChance(computedEffects.CalculateTotalValueFor(GenreEffectTypes.CriticalRateBonusAmount, - GenreEffectTypes.CriticalRateBonusPercentage)); - stats.CriticalDamageMultiplier(computedEffects.CalculateTotalValueFor(GenreEffectTypes.CriticalDamageBonusAmount, - GenreEffectTypes.CriticalDamageBonusPercentage)); + stats.CriticalDamageChance = computedEffects.CalculateTotalValueFor( + GenreEffectTypes.CriticalRateBonusAmount, + GenreEffectTypes.CriticalRateBonusPercentage); + + stats.CriticalDamageMultiplier = computedEffects.CalculateTotalValueFor( + GenreEffectTypes.CriticalDamageBonusAmount, + GenreEffectTypes.CriticalDamageBonusPercentage); } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Populators/Entity/Stats/DamageStatPopulator.cs b/src/OpenRpg.Genres/Populators/Entity/Stats/DamageStatPopulator.cs index 0b89826d..2e8e2fba 100644 --- a/src/OpenRpg.Genres/Populators/Entity/Stats/DamageStatPopulator.cs +++ b/src/OpenRpg.Genres/Populators/Entity/Stats/DamageStatPopulator.cs @@ -16,8 +16,9 @@ public class DamageStatPopulator : IEntityPartialStatPopulator public void Populate(EntityStatsVariables stats, ComputedEffects computedEffects, IReadOnlyCollection relatedVars) { - stats.Damage(computedEffects.CalculateTotalValueFor(GenreEffectTypes.DamageBonusAmount, - GenreEffectTypes.DamageBonusPercentage)); + stats.Damage = computedEffects.CalculateTotalValueFor( + GenreEffectTypes.DamageBonusAmount, + GenreEffectTypes.DamageBonusPercentage); } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Populators/Entity/Stats/DefenseStatPopulator.cs b/src/OpenRpg.Genres/Populators/Entity/Stats/DefenseStatPopulator.cs index 9a0b255c..552ab04b 100644 --- a/src/OpenRpg.Genres/Populators/Entity/Stats/DefenseStatPopulator.cs +++ b/src/OpenRpg.Genres/Populators/Entity/Stats/DefenseStatPopulator.cs @@ -15,8 +15,9 @@ public class DefenseStatPopulator : IEntityPartialStatPopulator public void Populate(EntityStatsVariables stats, ComputedEffects computedEffects, IReadOnlyCollection relatedVars) { - stats.Defense(computedEffects.CalculateTotalValueFor(GenreEffectTypes.DefenseBonusAmount, - GenreEffectTypes.DefenseBonusPercentage)); + stats.Defense = computedEffects.CalculateTotalValueFor( + GenreEffectTypes.DefenseBonusAmount, + GenreEffectTypes.DefenseBonusPercentage); } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs index 3bd41d86..34798293 100644 --- a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs +++ b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs @@ -84,13 +84,13 @@ public virtual bool IsRequirementMet(Character character, Requirement requiremen } if(requirement.RequirementType == GenreRequirementTypes.MaxHealthRequirement) - { return character.Stats.MaxHealth() >= requirement.Association.AssociatedValue; } + { return character.Stats.MaxHealth >= requirement.Association.AssociatedValue; } if(requirement.RequirementType == GenreRequirementTypes.MaxStaminaRequirement) - { return character.Stats.MaxStamina() >= requirement.Association.AssociatedValue; } + { return character.Stats.MaxStamina >= requirement.Association.AssociatedValue; } if(requirement.RequirementType == GenreRequirementTypes.MovementSpeedRequirement) - { return character.Stats.MovementSpeed() >= requirement.Association.AssociatedValue; } + { return character.Stats.MovementSpeed >= requirement.Association.AssociatedValue; } if (requirement.RequirementType == GenreRequirementTypes.ActiveEffectRequirement) { diff --git a/src/OpenRpg.UnitTests/Genres/Extensions/EntityStateVariableExtensionTests.cs b/src/OpenRpg.UnitTests/Genres/Extensions/EntityStateVariableExtensionTests.cs index 21aaf510..082b35ab 100644 --- a/src/OpenRpg.UnitTests/Genres/Extensions/EntityStateVariableExtensionTests.cs +++ b/src/OpenRpg.UnitTests/Genres/Extensions/EntityStateVariableExtensionTests.cs @@ -15,9 +15,9 @@ public void should_correctly_apply_health_changes() { var expectedHealth = 123; var entityState = new EntityStateVariables(); - entityState.Health(expectedHealth); + entityState.Health = expectedHealth; - var actualHealth = entityState.Health(); + var actualHealth = entityState.Health; Assert.Equal(expectedHealth, actualHealth); } @@ -26,10 +26,10 @@ public void should_correctly_add_health() { var expectedHealth = 123; var entityState = new EntityStateVariables(); - entityState.Health(100); + entityState.Health = 100; entityState.AddHealth(23); - var actualHealth = entityState.Health(); + var actualHealth = entityState.Health; Assert.Equal(expectedHealth, actualHealth); } @@ -38,10 +38,10 @@ public void should_correctly_deduct_health() { var expectedHealth = 100; var entityState = new EntityStateVariables(); - entityState.Health(123); + entityState.Health = 123; entityState.DeductHealth(23); - var actualHealth = entityState.Health(); + var actualHealth = entityState.Health; Assert.Equal(expectedHealth, actualHealth); } @@ -50,12 +50,12 @@ public void should_correctly_apply_damage() { var expectedHealth = 50; var entityState = new EntityStateVariables(); - entityState.Health(100); + entityState.Health = 100; var processedAttack = new ProcessedAttack(new[] { new Damage(GenreDamageTypes.Damage, 50) }, Array.Empty()); entityState.ApplyDamageToTarget(processedAttack); - var actualHealth = entityState.Health(); + var actualHealth = entityState.Health; Assert.Equal(expectedHealth, actualHealth); } } From 6b030a16b1c2d87389aae306fdab33deae52fa83 Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 9 Dec 2025 08:58:54 +0000 Subject: [PATCH 005/153] Updated more properties --- .../Extensions/IVariableExtensions.cs | 2 +- .../Data/ClassTemplateDataGenerator.cs | 4 +- .../Data/CraftingTemplateDataGenerator.cs | 10 +-- .../Data/GatheringTemplateDataGenerator.cs | 6 +- .../Data/ItemTemplateDataGenerator.cs | 68 +++++++++---------- .../Data/RaceTemplateDataGenerator.cs | 6 +- .../Characters/CharacterDetails.razor | 4 +- .../Components/Items/ItemDetails.razor | 4 +- .../Components/Items/ItemIcon.razor | 6 +- .../Items/ItemTemplateDetails.razor | 4 +- .../Components/Quests/QuestDetails.razor | 2 +- .../TradeSkills/TradeSkillItemIcon.razor | 6 +- .../Pages/Cards/BasicCardComponents.razor | 6 +- .../Pages/Curves/AdvancedEffects.razor | 4 +- .../Entities/BasicEntityComponents.razor | 4 +- .../Inventory/BasicInventoryComponents.razor | 4 +- .../Pages/Items/BasicItemComponents.razor | 12 ++-- .../Pages/Items/ItemsWithModifications.razor | 18 ++--- .../Pages/Items/ItemsWithRequirements.razor | 18 ++--- .../Pages/Procedural/ProceduralItems.razor | 6 +- .../Pages/Quests/BasicQuestComponents.razor | 2 +- .../TradeSkills/CraftingTradeSkills.razor | 4 +- .../Editors/Common/AssetCodeEditor.razor | 6 +- .../List/ItemTemplateDetailsEditor.razor | 12 ++-- .../List/TradeSkillItemEntriesEditor.razor | 6 +- .../Editors/TemplatePageEditor.razor | 12 ++-- .../Templates/ItemTemplateEditor.razor | 5 +- .../Effects/Processors/EffectProcessor.cs | 2 +- .../Extensions/EntityVariableExtensions.cs | 6 +- .../ITemplateDataVariablesExtensions.cs | 30 ++++---- .../Extensions/ITemplateVariableExtensions.cs | 13 ++-- .../Extensions/ObjectVariableExtensions.cs | 25 ++++--- .../Builders/CharacterBuilder.cs | 2 +- .../Effects/CharacterEffectProcessor.cs | 4 +- .../Extensions/RequirementExtensions.cs | 1 - .../DefaultCharacterRequirementChecker.cs | 4 +- .../TradeSkillItemEntryExtensions.cs | 27 +++++--- .../Extensions/EffectExtensions.cs | 4 +- .../Extensions/InventoryExtensions.cs | 42 ++++++------ .../ItemTemplateVariablesExtensions.cs | 42 +++++++++--- .../Extensions/ItemVariablesExtensions.cs | 25 ++++--- .../ProceduralItemTemplateExtensions.cs | 4 +- .../Items/DefaultInventoryAmountTests.cs | 68 +++++++++---------- .../Items/InventoryExtensionTests.cs | 4 +- .../Items/InventoryTransactionTests.cs | 12 ++-- .../TradeSkills/TradeSkillCraftingTests.cs | 30 ++++---- 46 files changed, 321 insertions(+), 265 deletions(-) diff --git a/src/OpenRpg.Core/Extensions/IVariableExtensions.cs b/src/OpenRpg.Core/Extensions/IVariableExtensions.cs index 0dcf4197..e22275be 100644 --- a/src/OpenRpg.Core/Extensions/IVariableExtensions.cs +++ b/src/OpenRpg.Core/Extensions/IVariableExtensions.cs @@ -72,7 +72,7 @@ public static T GetAsOrDefault(this IVariables vars, int variableKey, { if (vars.ContainsKey(variableKey)) { return vars.GetAs(variableKey) ?? defaultValueFactory(); } - return defaultValueFactory(); + return defaultValueFactory(); } } } \ No newline at end of file diff --git a/src/OpenRpg.Demos.Infrastructure/Data/ClassTemplateDataGenerator.cs b/src/OpenRpg.Demos.Infrastructure/Data/ClassTemplateDataGenerator.cs index 58636bed..6652f43f 100644 --- a/src/OpenRpg.Demos.Infrastructure/Data/ClassTemplateDataGenerator.cs +++ b/src/OpenRpg.Demos.Infrastructure/Data/ClassTemplateDataGenerator.cs @@ -38,7 +38,7 @@ public ClassTemplate GenerateFighterClass() DescriptionLocaleId = "Super tough, hits things", Effects = effects }; - classTemplate.Variables.AssetCode("class-fighter"); + classTemplate.Variables.AssetCode = "class-fighter"; return classTemplate; } @@ -59,7 +59,7 @@ public ClassTemplate GenerateMageClass() DescriptionLocaleId = "Powerful magic users", Effects = effects }; - classTemplate.Variables.AssetCode("class-mage"); + classTemplate.Variables.AssetCode = "class-mage"; return classTemplate; } diff --git a/src/OpenRpg.Demos.Infrastructure/Data/CraftingTemplateDataGenerator.cs b/src/OpenRpg.Demos.Infrastructure/Data/CraftingTemplateDataGenerator.cs index d1556b00..2aa23f47 100644 --- a/src/OpenRpg.Demos.Infrastructure/Data/CraftingTemplateDataGenerator.cs +++ b/src/OpenRpg.Demos.Infrastructure/Data/CraftingTemplateDataGenerator.cs @@ -25,10 +25,10 @@ public IEnumerable GenerateData() public ItemCraftingTemplate MakeCopperIngotCraftingTemplate() { var inputItemEntry = new TradeSkillItemEntry() { TemplateId = ItemTemplateLookups.CopperOre }; - inputItemEntry.Variables.Amount(5); + inputItemEntry.Variables.Amount = 5; var outputItemEntry = new TradeSkillItemEntry() { TemplateId = ItemTemplateLookups.CopperIngot }; - outputItemEntry.Variables.Amount(1); + outputItemEntry.Variables.Amount = 1; return new ItemCraftingTemplate() { @@ -44,12 +44,12 @@ public ItemCraftingTemplate MakeCopperIngotCraftingTemplate() public ItemCraftingTemplate MakeCopperSwordCraftingTemplate() { var inputItem1Entry = new TradeSkillItemEntry() { TemplateId = ItemTemplateLookups.CopperIngot }; - inputItem1Entry.Variables.Amount(2); + inputItem1Entry.Variables.Amount = 2; var inputItem2Entry = new TradeSkillItemEntry() { TemplateId = ItemTemplateLookups.OakLog }; - inputItem2Entry.Variables.Amount(1); + inputItem2Entry.Variables.Amount = 1; var outputItemEntry = new TradeSkillItemEntry() { TemplateId = ItemTemplateLookups.CopperSword }; - outputItemEntry.Variables.Amount(1); + outputItemEntry.Variables.Amount = 1; return new ItemCraftingTemplate() { diff --git a/src/OpenRpg.Demos.Infrastructure/Data/GatheringTemplateDataGenerator.cs b/src/OpenRpg.Demos.Infrastructure/Data/GatheringTemplateDataGenerator.cs index d10a33bd..1d6f32d3 100644 --- a/src/OpenRpg.Demos.Infrastructure/Data/GatheringTemplateDataGenerator.cs +++ b/src/OpenRpg.Demos.Infrastructure/Data/GatheringTemplateDataGenerator.cs @@ -26,7 +26,7 @@ public IEnumerable GenerateData() public ItemGatheringTemplate MakeCopperOreGatheringTemplate() { var itemEntry = new TradeSkillItemEntry() { TemplateId = ItemTemplateLookups.CopperOre }; - itemEntry.Variables.Amount(1); + itemEntry.Variables.Amount = 1; return new ItemGatheringTemplate() { @@ -41,7 +41,7 @@ public ItemGatheringTemplate MakeCopperOreGatheringTemplate() public ItemGatheringTemplate MakeIronOreGatheringTemplate() { var itemEntry = new TradeSkillItemEntry() { TemplateId = ItemTemplateLookups.IronOre }; - itemEntry.Variables.Amount(1); + itemEntry.Variables.Amount = 1; return new ItemGatheringTemplate() { @@ -60,7 +60,7 @@ public ItemGatheringTemplate MakeIronOreGatheringTemplate() public ItemGatheringTemplate MakeOakLogGatheringTemplate() { var itemEntry = new TradeSkillItemEntry() { TemplateId = ItemTemplateLookups.OakLog }; - itemEntry.Variables.Amount(1); + itemEntry.Variables.Amount = 1; return new ItemGatheringTemplate() { diff --git a/src/OpenRpg.Demos.Infrastructure/Data/ItemTemplateDataGenerator.cs b/src/OpenRpg.Demos.Infrastructure/Data/ItemTemplateDataGenerator.cs index ed025f64..5f00d313 100644 --- a/src/OpenRpg.Demos.Infrastructure/Data/ItemTemplateDataGenerator.cs +++ b/src/OpenRpg.Demos.Infrastructure/Data/ItemTemplateDataGenerator.cs @@ -47,9 +47,9 @@ public ItemTemplate MakeRubbishSword() new StaticEffect { EffectType = FantasyEffectTypes.DamageBonusAmount, Potency = 30.0f } } }; - template.Variables.QualityType(FantasyItemQualityTypes.JunkQuality); - template.Variables.Value(10); - template.Variables.AssetCode("sword"); + template.Variables.QualityType = FantasyItemQualityTypes.JunkQuality; + template.Variables.Value = 10; + template.Variables.AssetCode = "sword"; return template; } @@ -75,9 +75,9 @@ private ItemTemplate MakeSuperSword() Requirements = Array.Empty(), Effects = swordEffects }; - template.Variables.QualityType(FantasyItemQualityTypes.EpicQuality); - template.Variables.Value(10000); - template.Variables.AssetCode("sword"); + template.Variables.QualityType = FantasyItemQualityTypes.EpicQuality; + template.Variables.Value = 10000; + template.Variables.AssetCode = "sword"; return template; } @@ -97,10 +97,10 @@ public ItemTemplate MakePotion() new StaticEffect { EffectType = FantasyEffectTypes.HealthRestoreAmount, Potency = 30.0f } } }; - template.Variables.QualityType(FantasyItemQualityTypes.UncommonQuality); - template.Variables.Value(20); - template.Variables.MaxStacks(5); - template.Variables.AssetCode("potion"); + template.Variables.QualityType = FantasyItemQualityTypes.UncommonQuality; + template.Variables.Value = 20; + template.Variables.MaxStacks = 5; + template.Variables.AssetCode = "potion"; return template; } @@ -120,10 +120,10 @@ public ItemTemplate MakeJunkPotion() new StaticEffect { EffectType = FantasyEffectTypes.HealthRestoreAmount, Potency = -5.0f } } }; - template.Variables.QualityType(FantasyItemQualityTypes.JunkQuality); - template.Variables.Value(0); - template.Variables.MaxStacks(5); - template.Variables.AssetCode("potion-2"); + template.Variables.QualityType = FantasyItemQualityTypes.JunkQuality; + template.Variables.Value = 0; + template.Variables.MaxStacks = 5; + template.Variables.AssetCode = "potion-2"; return template; } @@ -140,10 +140,10 @@ public ItemTemplate MakeCopperIngot() Requirements = Array.Empty(), Effects = Array.Empty(), }; - template.Variables.QualityType(FantasyItemQualityTypes.CommonQuality); - template.Variables.Value(5); - template.Variables.MaxStacks(20); - template.Variables.AssetCode("copper-ingot"); + template.Variables.QualityType = FantasyItemQualityTypes.CommonQuality; + template.Variables.Value = 5; + template.Variables.MaxStacks = 20; + template.Variables.AssetCode = "copper-ingot"; return template; } @@ -160,10 +160,10 @@ public ItemTemplate MakeCopperOre() Requirements = Array.Empty(), Effects = Array.Empty(), }; - template.Variables.QualityType(FantasyItemQualityTypes.CommonQuality); - template.Variables.Value(1); - template.Variables.MaxStacks(20); - template.Variables.AssetCode("copper-ore"); + template.Variables.QualityType = FantasyItemQualityTypes.CommonQuality; + template.Variables.Value = 1; + template.Variables.MaxStacks = 20; + template.Variables.AssetCode = "copper-ore"; return template; } @@ -180,10 +180,10 @@ public ItemTemplate MakeIronOre() Requirements = Array.Empty(), Effects = Array.Empty(), }; - template.Variables.QualityType(FantasyItemQualityTypes.CommonQuality); - template.Variables.Value(1); - template.Variables.MaxStacks(20); - template.Variables.AssetCode("iron-ore"); + template.Variables.QualityType = FantasyItemQualityTypes.CommonQuality; + template.Variables.Value = 1; + template.Variables.MaxStacks = 20; + template.Variables.AssetCode = "iron-ore"; return template; } @@ -200,10 +200,10 @@ public ItemTemplate MakeOakLog() Requirements = Array.Empty(), Effects = Array.Empty(), }; - template.Variables.QualityType(FantasyItemQualityTypes.CommonQuality); - template.Variables.Value(1); - template.Variables.MaxStacks(20); - template.Variables.AssetCode("oak-log"); + template.Variables.QualityType = FantasyItemQualityTypes.CommonQuality; + template.Variables.Value = 1; + template.Variables.MaxStacks = 20; + template.Variables.AssetCode = "oak-log"; return template; } @@ -223,10 +223,10 @@ public ItemTemplate MakeCopperSword() new StaticEffect { EffectType = FantasyEffectTypes.DamageBonusAmount, Potency = 50 } } }; - template.Variables.QualityType(FantasyItemQualityTypes.CommonQuality); - template.Variables.Value(50); - template.Variables.MaxStacks(1); - template.Variables.AssetCode("copper-sword"); + template.Variables.QualityType = FantasyItemQualityTypes.CommonQuality; + template.Variables.Value = 50; + template.Variables.MaxStacks = 1; + template.Variables.AssetCode = "copper-sword"; return template; } diff --git a/src/OpenRpg.Demos.Infrastructure/Data/RaceTemplateDataGenerator.cs b/src/OpenRpg.Demos.Infrastructure/Data/RaceTemplateDataGenerator.cs index 4e83f17b..d06dd919 100644 --- a/src/OpenRpg.Demos.Infrastructure/Data/RaceTemplateDataGenerator.cs +++ b/src/OpenRpg.Demos.Infrastructure/Data/RaceTemplateDataGenerator.cs @@ -41,7 +41,7 @@ public RaceTemplate GenerateHumanTemplate() DescriptionLocaleId = "Humans are the most common of all races", Effects = effects }; - raceTemplate.Variables.AssetCode("race-human"); + raceTemplate.Variables.AssetCode = "race-human"; return raceTemplate; } @@ -70,7 +70,7 @@ public RaceTemplate GenerateElfTemplate() DescriptionLocaleId = "Elves are pretty common, have pointy ears too", Effects = effects }; - raceTemplate.Variables.AssetCode("race-elf"); + raceTemplate.Variables.AssetCode = "race-elf"; return raceTemplate; } @@ -98,7 +98,7 @@ public RaceTemplate GenerateDwarfTemplate() DescriptionLocaleId = "Dwarves are strong and hardy", Effects = effects }; - raceTemplate.Variables.AssetCode("race-dwarf"); + raceTemplate.Variables.AssetCode = "race-dwarf"; return raceTemplate; } } diff --git a/src/OpenRpg.Demos.Web/Components/Characters/CharacterDetails.razor b/src/OpenRpg.Demos.Web/Components/Characters/CharacterDetails.razor index 109697a5..a43ab9d3 100644 --- a/src/OpenRpg.Demos.Web/Components/Characters/CharacterDetails.razor +++ b/src/OpenRpg.Demos.Web/Components/Characters/CharacterDetails.razor @@ -6,7 +6,7 @@

@(Name ?? "Unnamed Person")

@if(Class != null) { -

@($"Level {Class?.Data.Variables.Level().ToString() ?? "1"} {Race.Template?.NameLocaleId ?? "Unknown Race"} {Class?.Template?.NameLocaleId ?? "Unknown Class"}")

+

@($"Level {Class?.Data.Variables.Level.ToString() ?? "1"} {Race.Template?.NameLocaleId ?? "Unknown Race"} {Class?.Template?.NameLocaleId ?? "Unknown Class"}")

} @if(@Classes != null) { @@ -15,7 +15,7 @@ @foreach (var _class in @Classes) {
- +
} diff --git a/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor b/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor index 1fefb47a..c222c91b 100644 --- a/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor +++ b/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor @@ -27,7 +27,7 @@
- +
@@ -127,7 +127,7 @@ Effects = Item.Data.GetEffects(OverriddenTemplateAccessor != null ? OverriddenTemplateAccessor : TemplateAccessor).ToArray(); if (Item.Template.Variables.ContainsKey(ItemTemplateVariableTypes.QualityType)) - { _itemQualityTypeId = Item.Template.Variables.QualityType(); } + { _itemQualityTypeId = Item.Template.Variables.QualityType; } base.OnParametersSet(); } diff --git a/src/OpenRpg.Demos.Web/Components/Items/ItemIcon.razor b/src/OpenRpg.Demos.Web/Components/Items/ItemIcon.razor index 6ff4968c..38fda023 100644 --- a/src/OpenRpg.Demos.Web/Components/Items/ItemIcon.razor +++ b/src/OpenRpg.Demos.Web/Components/Items/ItemIcon.razor @@ -6,7 +6,7 @@ @using OpenRpg.Genres.Characters
- +
@(_itemAmount > 0 ? $"{_itemAmount}" : "")
@@ -28,12 +28,12 @@ protected override void OnParametersSet() { if (Item.Data.Variables != null && Item.Data.Variables.ContainsKey(ItemVariableTypes.Amount)) - { _itemAmount = Item.Data.Variables.Amount(); } + { _itemAmount = Item.Data.Variables.Amount; } else { _itemAmount = 0;} if (Item.Template.Variables.ContainsKey(ItemTemplateVariableTypes.QualityType)) - { _itemQualityTypeId = Item.Template.Variables.QualityType(); } + { _itemQualityTypeId = Item.Template.Variables.QualityType; } base.OnParametersSet(); } diff --git a/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor b/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor index b90919d6..ed81ceb5 100644 --- a/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor +++ b/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor @@ -26,7 +26,7 @@
- +
@@ -115,7 +115,7 @@ protected override void OnInitialized() { if (ItemTemplate.Variables.ContainsKey(ItemTemplateVariableTypes.QualityType)) - { _itemQualityTypeId = ItemTemplate.Variables.QualityType(); } + { _itemQualityTypeId = ItemTemplate.Variables.QualityType; } } diff --git a/src/OpenRpg.Demos.Web/Components/Quests/QuestDetails.razor b/src/OpenRpg.Demos.Web/Components/Quests/QuestDetails.razor index 971a1dce..e6551f23 100644 --- a/src/OpenRpg.Demos.Web/Components/Quests/QuestDetails.razor +++ b/src/OpenRpg.Demos.Web/Components/Quests/QuestDetails.razor @@ -91,7 +91,7 @@ TemplateId = itemTemplateId, Variables = new ItemVariables() }; - item.Variables.Amount(itemAmount); + item.Variables.Amount = itemAmount; return TemplateAccessor.ToInstance(item); } } \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Components/TradeSkills/TradeSkillItemIcon.razor b/src/OpenRpg.Demos.Web/Components/TradeSkills/TradeSkillItemIcon.razor index 173fb54d..3431300d 100644 --- a/src/OpenRpg.Demos.Web/Components/TradeSkills/TradeSkillItemIcon.razor +++ b/src/OpenRpg.Demos.Web/Components/TradeSkills/TradeSkillItemIcon.razor @@ -8,7 +8,7 @@ @using OpenRpg.Items.TradeSkills.Extensions
- +
@(_itemAmount > 0 ? $"{_itemAmount}" : "")
@@ -34,12 +34,12 @@ protected override void OnParametersSet() { if (Item.Variables != null && Item.Variables.ContainsKey(ItemVariableTypes.Amount)) - { _itemAmount = Item.Variables.Amount(); } + { _itemAmount = Item.Variables.Amount; } else { _itemAmount = 0;} if (ItemTemplate.Variables.ContainsKey(ItemTemplateVariableTypes.QualityType)) - { _itemQualityTypeId = ItemTemplate.Variables.QualityType(); } + { _itemQualityTypeId = ItemTemplate.Variables.QualityType; } base.OnParametersSet(); } diff --git a/src/OpenRpg.Demos.Web/Pages/Cards/BasicCardComponents.razor b/src/OpenRpg.Demos.Web/Pages/Cards/BasicCardComponents.razor index 7a80f88a..39d2dd75 100644 --- a/src/OpenRpg.Demos.Web/Pages/Cards/BasicCardComponents.razor +++ b/src/OpenRpg.Demos.Web/Pages/Cards/BasicCardComponents.razor @@ -115,9 +115,9 @@ new StaticEffect { EffectType = FantasyEffectTypes.DamageBonusAmount, Potency = 30.0f } } }; - template.Variables.QualityType(FantasyItemQualityTypes.JunkQuality); - template.Variables.Value(10); - template.Variables.AssetCode("sword"); + template.Variables.QualityType = FantasyItemQualityTypes.JunkQuality; + template.Variables.Value = 10; + template.Variables.AssetCode = "sword"; var itemData = new ItemData { TemplateId = template.Id }; var item = TemplateAccessor.ToInstance(itemData); diff --git a/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor b/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor index f6d09d9e..acf4db61 100644 --- a/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor +++ b/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor @@ -211,8 +211,8 @@ public int CharacterLevel { - get => ExampleCharacter.Variables.Class.Variables.Level(); - set => ExampleCharacter.Variables.Class.Variables.Level(value); + get => ExampleCharacter.Variables.Class.Variables.Level; + set => ExampleCharacter.Variables.Class.Variables.Level = value; } protected override void OnInitialized() diff --git a/src/OpenRpg.Demos.Web/Pages/Entities/BasicEntityComponents.razor b/src/OpenRpg.Demos.Web/Pages/Entities/BasicEntityComponents.razor index 58b6085b..a761acf0 100644 --- a/src/OpenRpg.Demos.Web/Pages/Entities/BasicEntityComponents.razor +++ b/src/OpenRpg.Demos.Web/Pages/Entities/BasicEntityComponents.razor @@ -165,14 +165,14 @@ var multiClass = new MultiClasses(); var level2Fighter =new ClassData { TemplateId = FighterClass.Id }; - level2Fighter.Variables.Level(2); + level2Fighter.Variables.Level = 2; multiClass.AddClass(level2Fighter); var level1Wraith = new ClassData { TemplateId = WraithClass.Id }; multiClass.AddClass(level1Wraith); var level3RingBearer = new ClassData { TemplateId = RingBearerClass.Id }; - level3RingBearer.Variables.Level(3); + level3RingBearer.Variables.Level = 3; multiClass.AddClass(level3RingBearer); MultiClassEntity.Variables.MultiClass = multiClass; diff --git a/src/OpenRpg.Demos.Web/Pages/Inventory/BasicInventoryComponents.razor b/src/OpenRpg.Demos.Web/Pages/Inventory/BasicInventoryComponents.razor index 485396a6..4f2d0c74 100644 --- a/src/OpenRpg.Demos.Web/Pages/Inventory/BasicInventoryComponents.razor +++ b/src/OpenRpg.Demos.Web/Pages/Inventory/BasicInventoryComponents.razor @@ -144,14 +144,14 @@ private Item MakePotion() { var item = new ItemData { TemplateId = ItemTemplateLookups.HealingPotion }; - item.Variables.Amount(1); + item.Variables.Amount = 1; return TemplateAccessor.ToInstance(item); } private Item MakeJunkPotion() { var item = new ItemData { TemplateId = ItemTemplateLookups.JunkPotion }; - item.Variables.Amount(3); + item.Variables.Amount = 3; return TemplateAccessor.ToInstance(item); } diff --git a/src/OpenRpg.Demos.Web/Pages/Items/BasicItemComponents.razor b/src/OpenRpg.Demos.Web/Pages/Items/BasicItemComponents.razor index 3b48dff6..5417689b 100644 --- a/src/OpenRpg.Demos.Web/Pages/Items/BasicItemComponents.razor +++ b/src/OpenRpg.Demos.Web/Pages/Items/BasicItemComponents.razor @@ -147,9 +147,9 @@ new StaticEffect { EffectType = FantasyEffectTypes.DamageBonusAmount, Potency = 30.0f } } }; - template.Variables.QualityType(FantasyItemQualityTypes.JunkQuality); - template.Variables.Value(10); - template.Variables.AssetCode("sword"); + template.Variables.QualityType = FantasyItemQualityTypes.JunkQuality; + template.Variables.Value = 10; + template.Variables.AssetCode = "sword"; return template; } @@ -173,9 +173,9 @@ ItemType = FantasyItemTypes.GenericWeapon, Effects = swordEffects }; - template.Variables.QualityType(FantasyItemQualityTypes.EpicQuality); - template.Variables.Value(10000); - template.Variables.AssetCode("sword"); + template.Variables.QualityType = FantasyItemQualityTypes.EpicQuality; + template.Variables.Value = 10000; + template.Variables.AssetCode = "sword"; return template; } diff --git a/src/OpenRpg.Demos.Web/Pages/Items/ItemsWithModifications.razor b/src/OpenRpg.Demos.Web/Pages/Items/ItemsWithModifications.razor index d8c735cd..ef551794 100644 --- a/src/OpenRpg.Demos.Web/Pages/Items/ItemsWithModifications.razor +++ b/src/OpenRpg.Demos.Web/Pages/Items/ItemsWithModifications.razor @@ -133,9 +133,9 @@ new StaticEffect { EffectType = FantasyEffectTypes.StrengthBonusAmount, Potency = 3.0f } } }; - template.Variables.QualityType(FantasyItemQualityTypes.UncommonQuality); - template.Variables.Value(150); - template.Variables.AssetCode("staff"); + template.Variables.QualityType = FantasyItemQualityTypes.UncommonQuality; + template.Variables.Value = 150; + template.Variables.AssetCode = "staff"; return template; } @@ -160,9 +160,9 @@ new StaticEffect { EffectType = FantasyEffectTypes.ManaBonusAmount, Potency = 40.0f } } }; - template.Variables.QualityType(FantasyItemQualityTypes.RareQuality); - template.Variables.Value(300); - template.Variables.AssetCode("wand"); + template.Variables.QualityType = FantasyItemQualityTypes.RareQuality; + template.Variables.Value = 300; + template.Variables.AssetCode = "wand"; return template; } @@ -200,9 +200,9 @@ }}, } }; - template.Variables.QualityType(FantasyItemQualityTypes.EpicQuality); - template.Variables.Value(1000); - template.Variables.AssetCode("sword"); + template.Variables.QualityType = FantasyItemQualityTypes.EpicQuality; + template.Variables.Value = 1000; + template.Variables.AssetCode = "sword"; return template; } diff --git a/src/OpenRpg.Demos.Web/Pages/Items/ItemsWithRequirements.razor b/src/OpenRpg.Demos.Web/Pages/Items/ItemsWithRequirements.razor index 4d2753ab..daa4af63 100644 --- a/src/OpenRpg.Demos.Web/Pages/Items/ItemsWithRequirements.razor +++ b/src/OpenRpg.Demos.Web/Pages/Items/ItemsWithRequirements.razor @@ -136,9 +136,9 @@ new StaticEffect { EffectType = FantasyEffectTypes.StrengthBonusAmount, Potency = 3.0f } } }; - template.Variables.QualityType(FantasyItemQualityTypes.UncommonQuality); - template.Variables.Value(150); - template.Variables.AssetCode("staff"); + template.Variables.QualityType = FantasyItemQualityTypes.UncommonQuality; + template.Variables.Value = 150; + template.Variables.AssetCode = "staff"; return template; } @@ -163,9 +163,9 @@ new StaticEffect { EffectType = FantasyEffectTypes.ManaBonusAmount, Potency = 40.0f } } }; - template.Variables.QualityType(FantasyItemQualityTypes.RareQuality); - template.Variables.Value(300); - template.Variables.AssetCode("wand"); + template.Variables.QualityType = FantasyItemQualityTypes.RareQuality; + template.Variables.Value = 300; + template.Variables.AssetCode = "wand"; return template; } @@ -203,9 +203,9 @@ }}, } }; - template.Variables.QualityType(FantasyItemQualityTypes.EpicQuality); - template.Variables.Value(1000); - template.Variables.AssetCode("sword"); + template.Variables.QualityType = FantasyItemQualityTypes.EpicQuality; + template.Variables.Value = 1000; + template.Variables.AssetCode = "sword"; return template; } diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor b/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor index 3819298c..2ff0aecc 100644 --- a/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor @@ -168,9 +168,9 @@ NameLocaleId = "Magical Random Sword", ItemType = FantasyItemTypes.GenericWeapon }; - proceduralItemTemplate.Variables.AssetCode("sword"); - proceduralItemTemplate.Variables.ProceduralEffects(proceduralEffects); - proceduralItemTemplate.Variables.QualityType(FantasyItemQualityTypes.EpicQuality); + proceduralItemTemplate.Variables.AssetCode = "sword"; + proceduralItemTemplate.Variables.ProceduralEffects = proceduralEffects; + proceduralItemTemplate.Variables.QualityType = FantasyItemQualityTypes.EpicQuality; TemplateAccessor.AddTemplate(proceduralItemTemplate); RefreshProceduralItem(); diff --git a/src/OpenRpg.Demos.Web/Pages/Quests/BasicQuestComponents.razor b/src/OpenRpg.Demos.Web/Pages/Quests/BasicQuestComponents.razor index 54400cc4..488515b3 100644 --- a/src/OpenRpg.Demos.Web/Pages/Quests/BasicQuestComponents.razor +++ b/src/OpenRpg.Demos.Web/Pages/Quests/BasicQuestComponents.razor @@ -150,7 +150,7 @@ new() {RewardType = FantasyRewardTypes.CurrencyReward, Association = new Association(0, 50)} } }; - quest.Variables.AssetCode("default-quest"); + quest.Variables.AssetCode = "default-quest"; return quest; } diff --git a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor index bcd25f76..a5ee4c17 100644 --- a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor +++ b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor @@ -189,7 +189,7 @@ public void GiveCopperOre(int amount = 20) { var copperOreItem = TemplateAccessor.ToInstance(new ItemData { TemplateId = ItemTemplateLookups.CopperOre }); - copperOreItem.Data.Variables.Amount(amount); + copperOreItem.Data.Variables.Amount = amount; CraftingInventory.AttemptAddItem(copperOreItem); CraftingInventoryRef?.Refresh(); } @@ -197,7 +197,7 @@ public void GiveOakLog(int amount = 1) { var oakLog = TemplateAccessor.ToInstance(new ItemData { TemplateId = ItemTemplateLookups.OakLog }); - oakLog.Data.Variables.Amount(amount); + oakLog.Data.Variables.Amount = amount; CraftingInventory.AttemptAddItem(oakLog); CraftingInventoryRef.Refresh(); } diff --git a/src/OpenRpg.Editor.UI/Components/Editors/Common/AssetCodeEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/Common/AssetCodeEditor.razor index ac7bbda2..c437b4cd 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/Common/AssetCodeEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/Common/AssetCodeEditor.razor @@ -10,7 +10,7 @@
+ value="@Variables.AssetCode" @onchange="AssetCodeChanged" />
@@ -30,13 +30,13 @@ { base.OnInitialized(); if (!Variables.ContainsKey(CustomVariableTypes.AssetCode)) - { Variables.AssetCode(DefaultAssetCode); } + { Variables.AssetCode = DefaultAssetCode; } } private void AssetCodeChanged(ChangeEventArgs e) { var newAssetCode = e.Value.ToString(); - Variables.AssetCode(newAssetCode); + Variables.AssetCode = newAssetCode; OnAssetCodeChanged.InvokeAsync(newAssetCode); } diff --git a/src/OpenRpg.Editor.UI/Components/Editors/List/ItemTemplateDetailsEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/List/ItemTemplateDetailsEditor.razor index f1673c48..0ad2b816 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/List/ItemTemplateDetailsEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/List/ItemTemplateDetailsEditor.razor @@ -10,8 +10,8 @@
+ value="@Template.Variables.MaxStacks" + @onchange="e => Template.Variables.MaxStacks = int.Parse(e.Value?.ToString())"/>
@@ -24,8 +24,8 @@
+ value="@Template.Variables.Value" + @onchange="e => Template.Variables.Value = int.Parse(e.Value?.ToString())"/>
@@ -53,8 +53,8 @@
- @foreach (var itemType in TypesHelper.GetItemQualityTypes) { diff --git a/src/OpenRpg.Editor.UI/Components/Editors/List/TradeSkillItemEntriesEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/List/TradeSkillItemEntriesEditor.razor index 254c48ba..f4a6b842 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/List/TradeSkillItemEntriesEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/List/TradeSkillItemEntriesEditor.razor @@ -20,7 +20,7 @@
@@ -28,8 +28,8 @@
- +
diff --git a/src/OpenRpg.Editor.UI/Components/Editors/TemplatePageEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/TemplatePageEditor.razor index 1d96d48b..1f75d1fc 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/TemplatePageEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/TemplatePageEditor.razor @@ -82,8 +82,8 @@ var newTemplate = new TTemplate(); newTemplate.SetId(newId); newTemplate.ListifyProperties(); - newTemplate.Variables.AssetCode($"{AssetCodePrefix}-{newTemplate.Id}"); - newTemplate.GenerateLocaleCodes(newTemplate.Variables.AssetCode()); + newTemplate.Variables.AssetCode = $"{AssetCodePrefix}-{newTemplate.Id}"; + newTemplate.GenerateLocaleCodes(newTemplate.Variables.AssetCode); Repository.Create(newTemplate); OnTemplateCreated.InvokeAsync(newTemplate); @@ -102,7 +102,7 @@ { Repository.Delete(CurrentTemplate.Id); OnTemplateRemoved.InvokeAsync(CurrentTemplate); - await Notifier.ShowNotification($"Deleted {FriendlyName} Template {CurrentTemplate.Variables.AssetCode()}"); + await Notifier.ShowNotification($"Deleted {FriendlyName} Template {CurrentTemplate.Variables.AssetCode}"); SelectDefault(); } @@ -111,11 +111,11 @@ var clone = Cloner.Clone(CurrentTemplate); clone.SetId(GetNewId()); clone.ListifyProperties(); - clone.Variables.AssetCode($"{CurrentTemplate.Variables.AssetCode()}-clone"); - clone.GenerateLocaleCodes(clone.Variables.AssetCode()); + clone.Variables.AssetCode = $"{CurrentTemplate.Variables.AssetCode}-clone"; + clone.GenerateLocaleCodes(clone.Variables.AssetCode); Repository.Create(clone); - await Notifier.ShowNotification($"Cloned {FriendlyName} Template {CurrentTemplate.Variables.AssetCode()}"); + await Notifier.ShowNotification($"Cloned {FriendlyName} Template {CurrentTemplate.Variables.AssetCode}"); OnTemplateCreated.InvokeAsync(clone); CurrentTemplate = clone; diff --git a/src/OpenRpg.Editor.UI/Components/Editors/Templates/ItemTemplateEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/Templates/ItemTemplateEditor.razor index e5dc6727..669257b7 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/Templates/ItemTemplateEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/Templates/ItemTemplateEditor.razor @@ -1,4 +1,3 @@ -@using OpenRpg.Editor.Infrastructure.Extensions @using OpenRpg.Entities.Extensions @using OpenRpg.Entities.Modifications @using OpenRpg.Items.Extensions @@ -6,8 +5,8 @@ - + diff --git a/src/OpenRpg.Entities/Effects/Processors/EffectProcessor.cs b/src/OpenRpg.Entities/Effects/Processors/EffectProcessor.cs index 14b059ee..2dfef85d 100644 --- a/src/OpenRpg.Entities/Effects/Processors/EffectProcessor.cs +++ b/src/OpenRpg.Entities/Effects/Processors/EffectProcessor.cs @@ -83,7 +83,7 @@ public virtual void ComputeScaledEffect(ScaledEffect effect, IHasEffects context { if (effect.ScalingType == CoreEffectScalingTypes.Level) { - var level = relatedEntity?.Variables.Class?.Variables.Level() ?? 1; + var level = relatedEntity?.Variables.Class?.Variables.Level ?? 1; computedEffects.Add(effect.EffectType, effect.PotencyFunction.Plot(level)); return; } diff --git a/src/OpenRpg.Entities/Extensions/EntityVariableExtensions.cs b/src/OpenRpg.Entities/Extensions/EntityVariableExtensions.cs index 03629f58..d63482b3 100644 --- a/src/OpenRpg.Entities/Extensions/EntityVariableExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/EntityVariableExtensions.cs @@ -27,7 +27,7 @@ public static bool HasRace(this EntityVariables vars) { public RaceData Race { - get => vars.GetAs(CoreEntityVariableTypes.Race); + get => vars.GetAsOrDefault(CoreEntityVariableTypes.Race, () => new RaceData()); set => vars[CoreEntityVariableTypes.Race] = value; } } @@ -39,7 +39,7 @@ public static bool HasClass(this EntityVariables vars) { public ClassData Class { - get => vars.GetAs(CoreEntityVariableTypes.Class); + get => vars.GetAsOrDefault(CoreEntityVariableTypes.Class, () => new ClassData()); set => vars[CoreEntityVariableTypes.Class] = value; } } @@ -51,7 +51,7 @@ public static bool HasMultiClass(this EntityVariables vars) { public MultiClasses MultiClass { - get => vars.GetAs(CoreEntityVariableTypes.MultiClasses); + get => vars.GetAsOrDefault(CoreEntityVariableTypes.MultiClasses, () => new MultiClasses()); set => vars[CoreEntityVariableTypes.MultiClasses] = value; } } diff --git a/src/OpenRpg.Entities/Extensions/ITemplateDataVariablesExtensions.cs b/src/OpenRpg.Entities/Extensions/ITemplateDataVariablesExtensions.cs index 8248cd0f..19dbebe9 100644 --- a/src/OpenRpg.Entities/Extensions/ITemplateDataVariablesExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/ITemplateDataVariablesExtensions.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using OpenRpg.Core.Associations; using OpenRpg.Core.Extensions; @@ -10,21 +11,26 @@ public static class ITemplateDataVariablesExtensions { public static bool HasLevel(this ITemplateDataVariables vars) => vars.ContainsKey(CoreTemplateDataVariableTypes.Level); - - public static int Level(this ITemplateDataVariables vars) - => vars.GetIntOrDefault(CoreTemplateDataVariableTypes.Level, 1); - - public static void Level(this ITemplateDataVariables vars, int level) - => vars[CoreTemplateDataVariableTypes.Level] = level; + + extension(ITemplateDataVariables vars) + { + public int Level + { + get => vars.GetIntOrDefault(CoreTemplateDataVariableTypes.Level, 1); + set => vars[CoreTemplateDataVariableTypes.Level] = value; + } + } public static bool HasProceduralAssociation(this ITemplateDataVariables vars) => vars.ContainsKey(CoreTemplateDataVariableTypes.ProceduralAssociations); - public static IReadOnlyCollection ProceduralAssociation(this ITemplateDataVariables vars) - => vars.GetAsOrDefault(CoreTemplateDataVariableTypes.ProceduralAssociations, () => new List()); - - public static void ProceduralAssociation(this ITemplateDataVariables vars, IReadOnlyCollection effectAssociations) - => vars[CoreTemplateDataVariableTypes.ProceduralAssociations] = effectAssociations; - + extension(ITemplateDataVariables vars) + { + public IReadOnlyCollection ProceduralAssociation + { + get => vars.GetAsOrDefault(CoreTemplateDataVariableTypes.ProceduralAssociations, Array.Empty); + set => vars[CoreTemplateDataVariableTypes.ProceduralAssociations] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs b/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs index 0fffe5a4..871c8e7a 100644 --- a/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs @@ -10,10 +10,13 @@ public static class ITemplateVariableExtensions public static bool HasProceduralEffects(this ITemplateVariables vars) => vars.ContainsKey(CoreTemplateVariableTypes.ProceduralEffects); - public static ProceduralEffects ProceduralEffects(this ITemplateVariables vars) - => vars.GetAsOrDefault(CoreTemplateVariableTypes.ProceduralEffects, () => new ProceduralEffects()); - - public static void ProceduralEffects(this ITemplateVariables vars, ProceduralEffects proceduralEffects) - => vars[CoreTemplateVariableTypes.ProceduralEffects] = proceduralEffects; + extension(ITemplateVariables vars) + { + public ProceduralEffects ProceduralEffects + { + get => vars.GetAsOrDefault(CoreTemplateVariableTypes.ProceduralEffects, () => new ProceduralEffects()); + set => vars[CoreTemplateVariableTypes.ProceduralEffects] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Entities/Extensions/ObjectVariableExtensions.cs b/src/OpenRpg.Entities/Extensions/ObjectVariableExtensions.cs index d1cfb78c..3c1067cd 100644 --- a/src/OpenRpg.Entities/Extensions/ObjectVariableExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/ObjectVariableExtensions.cs @@ -1,3 +1,4 @@ +using OpenRpg.Core.Extensions; using OpenRpg.Core.Variables; using OpenRpg.Entities.Types; using OpenRpg.Tags; @@ -9,14 +10,22 @@ public static class ObjectVariableExtensions public static bool HasAssetCode(this IVariables vars) => vars.ContainsKey(CoreAnyVariableTypes.AssetCode); - public static string AssetCode(this IVariables vars) - => (string)vars[CoreAnyVariableTypes.AssetCode]; - - public static void AssetCode(this IVariables vars, string assetCode) - => vars[CoreAnyVariableTypes.AssetCode] = assetCode; - - public static string Tags(this IVariables variables) => (string)variables[CoreAnyVariableTypes.Tags]; - public static void Tags(this IVariables variables, TagList tags) => variables[CoreAnyVariableTypes.Tags] = tags; + public static bool HasTags(this IVariables vars) + => vars.ContainsKey(CoreAnyVariableTypes.Tags); + extension(IVariables vars) + { + public string AssetCode + { + get =>(string) vars[CoreAnyVariableTypes.AssetCode]; + set => vars[CoreAnyVariableTypes.AssetCode] = value; + } + + public TagList Tags + { + get => vars.GetAsOrDefault(CoreAnyVariableTypes.Tags, () => new TagList()); + set => vars[CoreAnyVariableTypes.Tags] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Builders/CharacterBuilder.cs b/src/OpenRpg.Genres/Builders/CharacterBuilder.cs index 89d1472a..fb57c319 100644 --- a/src/OpenRpg.Genres/Builders/CharacterBuilder.cs +++ b/src/OpenRpg.Genres/Builders/CharacterBuilder.cs @@ -136,7 +136,7 @@ protected virtual ClassData ProcessClass() if (_classId == 0) { return classData; } classData.TemplateId = _classId; - classData.Variables.Level(_classLevels); + classData.Variables.Level = _classLevels; return classData; } diff --git a/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs b/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs index b78805c8..44649fce 100644 --- a/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs +++ b/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs @@ -29,8 +29,8 @@ public void ComputeEffects(ItemData itemData, Character relatedEntity, ComputedE if (itemTemplate.Variables.HasProceduralEffects()) { - var proceduralEffects = itemTemplate.Variables.ProceduralEffects(); - var associatedEffects = itemData.Variables.ProceduralAssociation(); + var proceduralEffects = itemTemplate.Variables.ProceduralEffects; + var associatedEffects = itemData.Variables.ProceduralAssociation; ComputeProceduralEffects(proceduralEffects, associatedEffects, itemTemplate, computedEffects, relatedEntity); } diff --git a/src/OpenRpg.Genres/Extensions/RequirementExtensions.cs b/src/OpenRpg.Genres/Extensions/RequirementExtensions.cs index 3bbaac4b..4e337c47 100644 --- a/src/OpenRpg.Genres/Extensions/RequirementExtensions.cs +++ b/src/OpenRpg.Genres/Extensions/RequirementExtensions.cs @@ -1,6 +1,5 @@ using System.Linq; using OpenRpg.Core.Requirements; -using OpenRpg.Entities.Requirements; using OpenRpg.Genres.Characters; using OpenRpg.Genres.Requirements; using OpenRpg.Quests.State; diff --git a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs index 34798293..c467e6c1 100644 --- a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs +++ b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs @@ -31,7 +31,7 @@ public virtual bool IsRequirementMet(Character character, Requirement requiremen { var classDetails = character.Variables.Class; if (classDetails.TemplateId == requirement.Association.AssociatedId) - { return classDetails.Variables.Level() >= requirement.Association.AssociatedValue; } + { return classDetails.Variables.Level >= requirement.Association.AssociatedValue; } } if (character.Variables.HasMultiClass()) @@ -39,7 +39,7 @@ public virtual bool IsRequirementMet(Character character, Requirement requiremen var multiClass = character.Variables.MultiClass; var possibleClass = multiClass.GetClass(requirement.Association.AssociatedId); if (possibleClass != null) - { return possibleClass.Variables.Level() >= requirement.Association.AssociatedValue; } + { return possibleClass.Variables.Level >= requirement.Association.AssociatedValue; } } return false; diff --git a/src/OpenRpg.Items.TradeSkills/Extensions/TradeSkillItemEntryExtensions.cs b/src/OpenRpg.Items.TradeSkills/Extensions/TradeSkillItemEntryExtensions.cs index 61d923a0..953c6b16 100644 --- a/src/OpenRpg.Items.TradeSkills/Extensions/TradeSkillItemEntryExtensions.cs +++ b/src/OpenRpg.Items.TradeSkills/Extensions/TradeSkillItemEntryExtensions.cs @@ -21,27 +21,36 @@ public static ItemData AsItem(this TradeSkillItemEntry tradeSkillItemEntry) }; if (tradeSkillItemEntry.Variables.HasAmount()) - { wrapperItem.Variables.Amount(tradeSkillItemEntry.Variables.Amount()); } + { wrapperItem.Variables.Amount = tradeSkillItemEntry.Variables.Amount; } if (wrapperItem.Variables.HasWeight()) - { wrapperItem.Variables.Weight(tradeSkillItemEntry.Variables.Weight()); } + { wrapperItem.Variables.Weight = tradeSkillItemEntry.Variables.Weight; } return wrapperItem; } public static bool HasAmount(this TradeSkillItemEntryVariables variables) { return variables.ContainsKey(TradeSkillItemEntryVariableTypes.Amount); } - - public static int Amount(this TradeSkillItemEntryVariables variables) - { return variables.GetIntOrDefault(TradeSkillItemEntryVariableTypes.Amount, 1); } - public static void Amount(this TradeSkillItemEntryVariables variables, int value) - { variables[TradeSkillItemEntryVariableTypes.Amount] = value; } + extension(TradeSkillItemEntryVariables vars) + { + public int Amount + { + get => vars.GetIntOrDefault(TradeSkillItemEntryVariableTypes.Amount, 1); + set => vars[TradeSkillItemEntryVariableTypes.Amount] = value; + } + } public static bool HasWeight(this TradeSkillItemEntryVariables variables) { return variables.ContainsKey(TradeSkillItemEntryVariableTypes.Weight); } - public static float Weight(this TradeSkillItemEntryVariables variables) => variables.GetFloat(TradeSkillItemEntryVariableTypes.Weight); - public static void Weight(this TradeSkillItemEntryVariables variables, float value) => variables[TradeSkillItemEntryVariableTypes.Weight] = value; + extension(TradeSkillItemEntryVariables vars) + { + public float Weight + { + get => vars.GetFloat(TradeSkillItemEntryVariableTypes.Weight); + set => vars[TradeSkillItemEntryVariableTypes.Weight] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Items/Extensions/EffectExtensions.cs b/src/OpenRpg.Items/Extensions/EffectExtensions.cs index 8179ed47..88489fad 100644 --- a/src/OpenRpg.Items/Extensions/EffectExtensions.cs +++ b/src/OpenRpg.Items/Extensions/EffectExtensions.cs @@ -18,8 +18,8 @@ public static IEnumerable GetEffects(this ItemData itemData, ITemplateA var effects = new List(template.Effects); if (itemData.Variables.HasProceduralAssociation()) { - var proceduralEffects = template.Variables.ProceduralEffects(); - foreach (var proceduralEffect in itemData.Variables.ProceduralAssociation()) + var proceduralEffects = template.Variables.ProceduralEffects; + foreach (var proceduralEffect in itemData.Variables.ProceduralAssociation) { var effect = proceduralEffects.Effects[proceduralEffect.AssociatedId]; if (effect.ScalingType == CoreEffectScalingTypes.Value) diff --git a/src/OpenRpg.Items/Extensions/InventoryExtensions.cs b/src/OpenRpg.Items/Extensions/InventoryExtensions.cs index 332d5aff..73043f03 100644 --- a/src/OpenRpg.Items/Extensions/InventoryExtensions.cs +++ b/src/OpenRpg.Items/Extensions/InventoryExtensions.cs @@ -32,7 +32,7 @@ public static bool HasItem(this Inventory inventory, int itemTemplateId, int amo { var itemAmounts= inventory.Items .Where(x => x.TemplateId == itemTemplateId) - .Sum(x => x.Variables.Amount()); + .Sum(x => x.Variables.Amount); return itemAmounts >= amount; } @@ -50,8 +50,8 @@ public static bool HasItem(this Inventory inventory, int itemTemplateId, float w var itemWeights= inventory.Items .Where(x => x.TemplateId == itemTemplateId) .Sum(x => x.Variables.HasAmount() - ? x.Variables.Weight() * x.Variables.Amount() - : x.Variables.Weight()); + ? x.Variables.Weight * x.Variables.Amount + : x.Variables.Weight); return itemWeights >= weight; } @@ -65,10 +65,10 @@ public static bool HasItem(this Inventory inventory, int itemTemplateId, float w public static bool HasItem(this Inventory inventory, ItemData itemData) { if (itemData.Variables.HasAmount()) - { return inventory.HasItem(itemData.TemplateId, itemData.Variables.Amount()); } + { return inventory.HasItem(itemData.TemplateId, itemData.Variables.Amount); } if (itemData.Variables.HasWeight()) - { return inventory.HasItem(itemData.TemplateId, itemData.Variables.Weight()); } + { return inventory.HasItem(itemData.TemplateId, itemData.Variables.Weight); } return inventory.HasItem(itemData.TemplateId); } @@ -95,7 +95,7 @@ public static bool HasWeightCapacity(this Inventory inventory, float weightToAdd if (!inventory.Variables.ContainsKey(InventoryVariableTypes.MaxWeight)) { return true; } - var proposedWeight = inventory.Items.Sum(x => x.Variables.Weight()) + weightToAdd; + var proposedWeight = inventory.Items.Sum(x => x.Variables.Weight) + weightToAdd; return proposedWeight < inventory.Variables.MaxWeight(); } @@ -129,7 +129,7 @@ public static bool AttemptAddItem(this Inventory inventory, Item item) { return AttemptAddAmountItem(inventory, item); } if (item.Data.Variables.HasWeight()) - { return HasWeightCapacity(inventory, item.Template.Variables.Weight()) && AttemptAddWeightedItem(inventory, item); } + { return HasWeightCapacity(inventory, item.Template.Variables.Weight) && AttemptAddWeightedItem(inventory, item); } if (!HasSlotCapacity(inventory)) { return false; } @@ -140,12 +140,12 @@ public static bool AttemptAddItem(this Inventory inventory, Item item) public static bool AttemptAddAmountItem(Inventory inventory, Item item) { - var requiredAmount = item.Data.Variables.Amount(); - var stackSize = item.Template.Variables.MaxStacks(); + var requiredAmount = item.Data.Variables.Amount; + var stackSize = item.Template.Variables.MaxStacks; var existingItemsWithSpace = inventory.Items - .Where(x => x.TemplateId == item.Data.TemplateId && (stackSize == 0 || x.Variables.Amount() <= stackSize)) - .OrderByDescending(x => x.Variables.Amount()) + .Where(x => x.TemplateId == item.Data.TemplateId && (stackSize == 0 || x.Variables.Amount <= stackSize)) + .OrderByDescending(x => x.Variables.Amount) .ToArray(); var maxSlots = inventory.Variables.MaxSlots(); @@ -155,7 +155,7 @@ public static bool AttemptAddAmountItem(Inventory inventory, Item item) if (stackSize > 0) { - var availableSpace = existingItemsWithSpace.Sum(x => stackSize - x.Variables.Amount()); + var availableSpace = existingItemsWithSpace.Sum(x => stackSize - x.Variables.Amount); var overflowAmount = requiredAmount - availableSpace; var stacksRequired = (int)Math.Ceiling((float)overflowAmount / stackSize); if(currentSlots + stacksRequired > maxSlots) @@ -182,7 +182,7 @@ public static bool AttemptAddAmountItem(Inventory inventory, Item item) } var existingAmount = itemDataHasWithSpace.Variables.HasAmount() - ? itemDataHasWithSpace.Variables.Amount() + ? itemDataHasWithSpace.Variables.Amount : 0; if (stackSize > 0) @@ -190,18 +190,18 @@ public static bool AttemptAddAmountItem(Inventory inventory, Item item) var spaceLeft = stackSize - existingAmount; if (amountLeft < spaceLeft) { - itemDataHasWithSpace.Variables.Amount(existingAmount + amountLeft); + itemDataHasWithSpace.Variables.Amount = existingAmount + amountLeft; amountLeft = 0; } else { - itemDataHasWithSpace.Variables.Amount(existingAmount + spaceLeft); + itemDataHasWithSpace.Variables.Amount = existingAmount + spaceLeft; amountLeft -= spaceLeft; } } else { - itemDataHasWithSpace.Variables.Amount(existingAmount + amountLeft); + itemDataHasWithSpace.Variables.Amount = existingAmount + amountLeft; amountLeft = 0; } @@ -242,13 +242,13 @@ private static bool AttemptRemoveAmountItem(Inventory inventory, ItemData itemDa return true; } - var amountToTake = itemData.Variables.Amount(); + var amountToTake = itemData.Variables.Amount; var applicableItems = inventory.Items .Where(x => x.TemplateId == itemData.TemplateId) - .OrderByDescending(x => x.Variables.Amount()) + .OrderByDescending(x => x.Variables.Amount) .ToArray(); - var maxAvailable = applicableItems.Sum(x => x.Variables.Amount()); + var maxAvailable = applicableItems.Sum(x => x.Variables.Amount); if (maxAvailable < amountToTake) { return false; } @@ -256,7 +256,7 @@ private static bool AttemptRemoveAmountItem(Inventory inventory, ItemData itemDa while (amountToTake > 0) { var currentItem = applicableItems[index]; - var itemAmount = currentItem.Variables.Amount(); + var itemAmount = currentItem.Variables.Amount; if (amountToTake >= itemAmount) { inventory.Items.Remove(currentItem); @@ -264,7 +264,7 @@ private static bool AttemptRemoveAmountItem(Inventory inventory, ItemData itemDa } else { - currentItem.Variables.Amount(itemAmount - amountToTake); + currentItem.Variables.Amount = itemAmount - amountToTake; amountToTake -= itemAmount; } index++; diff --git a/src/OpenRpg.Items/Extensions/ItemTemplateVariablesExtensions.cs b/src/OpenRpg.Items/Extensions/ItemTemplateVariablesExtensions.cs index 4f28a39a..bbf2d85f 100644 --- a/src/OpenRpg.Items/Extensions/ItemTemplateVariablesExtensions.cs +++ b/src/OpenRpg.Items/Extensions/ItemTemplateVariablesExtensions.cs @@ -6,15 +6,37 @@ namespace OpenRpg.Items.Extensions { public static class ItemTemplateVariablesExtensions { - public static int QualityType(this ItemTemplateVariables variables) => variables.GetInt(ItemTemplateVariableTypes.QualityType); - public static void QualityType(this ItemTemplateVariables variables, int value) => variables[ItemTemplateVariableTypes.QualityType] = value; - public static int Value(this ItemTemplateVariables variables) => variables.GetInt(ItemTemplateVariableTypes.Value); - public static void Value(this ItemTemplateVariables variables, int value) => variables[ItemTemplateVariableTypes.Value] = value; - public static int MaxStacks(this ItemTemplateVariables variables) => variables.GetInt(ItemTemplateVariableTypes.MaxStacks); - public static void MaxStacks(this ItemTemplateVariables variables, int value) => variables[ItemTemplateVariableTypes.MaxStacks] = value; - public static float Weight(this ItemTemplateVariables variables) => variables.GetFloat(ItemTemplateVariableTypes.Weight); - public static void Weight(this ItemTemplateVariables variables, float value) => variables[ItemTemplateVariableTypes.Weight] = value; - public static int SlotType(this ItemTemplateVariables variables) => variables.GetInt(ItemTemplateVariableTypes.SlotType); - public static void SlotType(this ItemTemplateVariables variables, int value) => variables[ItemTemplateVariableTypes.SlotType] = value; + extension(ItemTemplateVariables vars) + { + public int QualityType + { + get => vars.GetInt(ItemTemplateVariableTypes.QualityType); + set => vars[ItemTemplateVariableTypes.QualityType] = value; + } + + public int Value + { + get => vars.GetInt(ItemTemplateVariableTypes.Value); + set => vars[ItemTemplateVariableTypes.Value] = value; + } + + public int MaxStacks + { + get => vars.GetInt(ItemTemplateVariableTypes.MaxStacks); + set => vars[ItemTemplateVariableTypes.MaxStacks] = value; + } + + public int Weight + { + get => vars.GetInt(ItemTemplateVariableTypes.Weight); + set => vars[ItemTemplateVariableTypes.Weight] = value; + } + + public int SlotType + { + get => vars.GetInt(ItemTemplateVariableTypes.SlotType); + set => vars[ItemTemplateVariableTypes.SlotType] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Items/Extensions/ItemVariablesExtensions.cs b/src/OpenRpg.Items/Extensions/ItemVariablesExtensions.cs index b3ee6b9e..da653e65 100644 --- a/src/OpenRpg.Items/Extensions/ItemVariablesExtensions.cs +++ b/src/OpenRpg.Items/Extensions/ItemVariablesExtensions.cs @@ -20,16 +20,25 @@ public static ItemVariables Clone(this ItemVariables itemVariables) public static bool HasAmount(this ItemVariables variables) { return variables.ContainsKey(ItemVariableTypes.Amount); } - public static int Amount(this ItemVariables variables) - { return variables.GetIntOrDefault(ItemVariableTypes.Amount, 1); } - - public static void Amount(this ItemVariables variables, int value) - { variables[ItemVariableTypes.Amount] = value; } - + extension(ItemVariables vars) + { + public int Amount + { + get => vars.GetIntOrDefault(ItemVariableTypes.Amount, 1); + set => vars[ItemVariableTypes.Amount] = value; + } + } + public static bool HasWeight(this ItemVariables variables) { return variables.ContainsKey(ItemVariableTypes.Weight); } - public static float Weight(this ItemVariables variables) => variables.GetFloat(ItemVariableTypes.Weight); - public static void Weight(this ItemVariables variables, float value) => variables[ItemVariableTypes.Weight] = value; + extension(ItemVariables vars) + { + public float Weight + { + get => vars.GetFloat(ItemVariableTypes.Weight); + set => vars[ItemVariableTypes.Weight] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Items/Extensions/ProceduralItemTemplateExtensions.cs b/src/OpenRpg.Items/Extensions/ProceduralItemTemplateExtensions.cs index 739ccdff..51ce12a7 100644 --- a/src/OpenRpg.Items/Extensions/ProceduralItemTemplateExtensions.cs +++ b/src/OpenRpg.Items/Extensions/ProceduralItemTemplateExtensions.cs @@ -11,9 +11,9 @@ public static ItemData GenerateProceduralInstance(this ItemTemplate template, IR if (!template.Variables.HasProceduralEffects()) { return new ItemData() { TemplateId = template.Id }; } - var takenEffects = template.Variables.ProceduralEffects().GenerateProceduralEffectAssociations(randomizer); + var takenEffects = template.Variables.ProceduralEffects.GenerateProceduralEffectAssociations(randomizer); var itemData = new ItemData { TemplateId = template.Id }; - itemData.Variables.ProceduralAssociation(takenEffects); + itemData.Variables.ProceduralAssociation = takenEffects; return itemData; } } diff --git a/src/OpenRpg.UnitTests/Items/DefaultInventoryAmountTests.cs b/src/OpenRpg.UnitTests/Items/DefaultInventoryAmountTests.cs index d1a1c6b0..af61694f 100644 --- a/src/OpenRpg.UnitTests/Items/DefaultInventoryAmountTests.cs +++ b/src/OpenRpg.UnitTests/Items/DefaultInventoryAmountTests.cs @@ -20,14 +20,14 @@ public void should_add_item_amount_when_not_existing() var inventory = new Inventory(); var itemToAdd = new ItemData() { TemplateId = existingItemTemplate.Id }; - itemToAdd.Variables.Amount(25); + itemToAdd.Variables.Amount = 25; var item = new Item { Data = itemToAdd, Template = existingItemTemplate }; var isItemAdded = inventory.AttemptAddItem(item); Assert.True(isItemAdded); Assert.Contains(inventory.Items, x => x.TemplateId == existingItemTemplate.Id); - Assert.Equal(expectedAmount, inventory.Items.First().Variables.Amount()); + Assert.Equal(expectedAmount, inventory.Items.First().Variables.Amount); } [Fact] @@ -36,86 +36,86 @@ public void should_add_item_amount_when_existing() var expectedAmount = 35; var existingItemTemplate = new ItemTemplate { Id = 1 }; var existingItem = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem.Variables.Amount(10); + existingItem.Variables.Amount = 10; var inventory = new Inventory(); inventory.Items.Add(existingItem); var itemToAdd = new ItemData() { TemplateId = existingItemTemplate.Id }; - itemToAdd.Variables.Amount(25); + itemToAdd.Variables.Amount = 25; var item = new Item { Data = itemToAdd, Template = existingItemTemplate }; var isItemAdded = inventory.AttemptAddItem(item); Assert.True(isItemAdded); Assert.Contains(inventory.Items, x => x.TemplateId == existingItem.TemplateId); - Assert.Equal(expectedAmount, inventory.Items.First().Variables.Amount()); + Assert.Equal(expectedAmount, inventory.Items.First().Variables.Amount); } [Fact] public void should_add_item_amount_as_new_item_when_stack_limit_met() { var existingItemTemplate = new ItemTemplate { Id = 1 }; - existingItemTemplate.Variables.MaxStacks(12); + existingItemTemplate.Variables.MaxStacks = 12; var existingItem = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem.Variables.Amount(10); + existingItem.Variables.Amount = 10; var inventory = new Inventory(); inventory.Items.Add(existingItem); var itemToAdd = new ItemData() { TemplateId = existingItemTemplate.Id }; - itemToAdd.Variables.Amount(5); + itemToAdd.Variables.Amount = 5; var item = new Item { Data = itemToAdd, Template = existingItemTemplate }; var isItemAdded = inventory.AttemptAddItem(item); Assert.True(isItemAdded); Assert.Equal(2, inventory.Items.Count); - Assert.Equal(12, existingItem.Variables.Amount()); - Assert.Equal(3, inventory.Items.First(x => x != existingItem).Variables.Amount()); + Assert.Equal(12, existingItem.Variables.Amount); + Assert.Equal(3, inventory.Items.First(x => x != existingItem).Variables.Amount); } [Fact] public void should_add_item_amount_when_existing_across_multiple_existing_stacks() { var existingItemTemplate = new ItemTemplate { Id = 1 }; - existingItemTemplate.Variables.MaxStacks(10); + existingItemTemplate.Variables.MaxStacks = 10; var existingItem1 = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem1.Variables.Amount(8); + existingItem1.Variables.Amount = 8; var existingItem2 = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem2.Variables.Amount(8); + existingItem2.Variables.Amount = 8; var inventory = new Inventory(); inventory.Items.Add(existingItem1); inventory.Items.Add(existingItem2); var itemToAdd = new ItemData() { TemplateId = existingItemTemplate.Id }; - itemToAdd.Variables.Amount(5); + itemToAdd.Variables.Amount = 5; var item = new Item { Data = itemToAdd, Template = existingItemTemplate }; var isItemAdded = inventory.AttemptAddItem(item); Assert.True(isItemAdded); Assert.Equal(3, inventory.Items.Count); - Assert.Equal(10, existingItem1.Variables.Amount()); - Assert.Equal(10, existingItem2.Variables.Amount()); - Assert.Equal(1, inventory.Items.First(x => x != existingItem1 && x != existingItem2).Variables.Amount()); + Assert.Equal(10, existingItem1.Variables.Amount); + Assert.Equal(10, existingItem2.Variables.Amount); + Assert.Equal(1, inventory.Items.First(x => x != existingItem1 && x != existingItem2).Variables.Amount); } [Fact] public void should_not_add_item_amount_when_existing_across_multiple_existing_stacks_if_slots_constrained() { var existingItemTemplate = new ItemTemplate { Id = 1 }; - existingItemTemplate.Variables.MaxStacks(10); + existingItemTemplate.Variables.MaxStacks = 10; var existingItem1 = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem1.Variables.Amount(8); + existingItem1.Variables.Amount = 8; var existingItem2 = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem2.Variables.Amount(8); + existingItem2.Variables.Amount = 8; var inventory = new Inventory(); inventory.Variables.MaxSlots(2); @@ -123,15 +123,15 @@ public void should_not_add_item_amount_when_existing_across_multiple_existing_st inventory.Items.Add(existingItem2); var itemToAdd = new ItemData() { TemplateId = existingItemTemplate.Id }; - itemToAdd.Variables.Amount(5); + itemToAdd.Variables.Amount = 5; var item = new Item { Data = itemToAdd, Template = existingItemTemplate }; var isItemAdded = inventory.AttemptAddItem(item); Assert.False(isItemAdded); Assert.Equal(2, inventory.Items.Count); - Assert.Equal(8, existingItem1.Variables.Amount()); - Assert.Equal(8, existingItem2.Variables.Amount()); + Assert.Equal(8, existingItem1.Variables.Amount); + Assert.Equal(8, existingItem2.Variables.Amount); } [Fact] @@ -140,18 +140,18 @@ public void should_remove_item_amount_when_existing() var expectedAmount = 75; var existingItemTemplate = new ItemTemplate { Id = 1 }; var existingItem = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem.Variables.Amount(100); + existingItem.Variables.Amount = 100; var inventory = new Inventory(); inventory.Items.Add(existingItem); var itemToRemove = new ItemData() { TemplateId = existingItemTemplate.Id }; - itemToRemove.Variables.Amount(25); + itemToRemove.Variables.Amount = 25; var isItemRemoved = inventory.AttemptRemoveItem(itemToRemove); Assert.True(isItemRemoved); Assert.Contains(inventory.Items, x => x.TemplateId == existingItem.TemplateId); - Assert.Equal(expectedAmount, inventory.Items.First().Variables.Amount()); + Assert.Equal(expectedAmount, inventory.Items.First().Variables.Amount); } [Fact] @@ -159,7 +159,7 @@ public void should_remove_item_when_existing_amount_matched() { var existingItemTemplate = new ItemTemplate { Id = 1 }; var existingItem = new ItemData() {TemplateId = existingItemTemplate.Id }; - existingItem.Variables.Amount(100); + existingItem.Variables.Amount = 100; var inventory = new Inventory(); inventory.Items.Add(existingItem); @@ -175,17 +175,17 @@ public void should_remove_multiple_when_existing_amount_exceeds_single_stack() { var existingItemTemplate = new ItemTemplate { Id = 1 }; var existingItem1 = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem1.Variables.Amount(5); + existingItem1.Variables.Amount = 5; var existingItem2 = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem2.Variables.Amount(5); + existingItem2.Variables.Amount = 5; var inventory = new Inventory(); inventory.Items.Add(existingItem1); inventory.Items.Add(existingItem2); var itemToRemove = new ItemData() { TemplateId = existingItemTemplate.Id }; - itemToRemove.Variables.Amount(10); + itemToRemove.Variables.Amount = 10; var isItemRemoved = inventory.AttemptRemoveItem(itemToRemove); Assert.True(isItemRemoved); @@ -197,22 +197,22 @@ public void should_remove_and_alter_multiple_when_existing_amount_exceeds_single { var existingItemTemplate = new ItemTemplate { Id = 1 }; var existingItem1 = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem1.Variables.Amount(5); + existingItem1.Variables.Amount = 5; var existingItem2 = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem2.Variables.Amount(7); + existingItem2.Variables.Amount = 7; var inventory = new Inventory(); inventory.Items.Add(existingItem1); inventory.Items.Add(existingItem2); var itemToRemove = new ItemData() { TemplateId = existingItemTemplate.Id }; - itemToRemove.Variables.Amount(10); + itemToRemove.Variables.Amount = 10; var isItemRemoved = inventory.AttemptRemoveItem(itemToRemove); Assert.True(isItemRemoved); Assert.Equal(1, inventory.Items.Count); - Assert.Equal(2, inventory.Items.First().Variables.Amount()); + Assert.Equal(2, inventory.Items.First().Variables.Amount); } } \ No newline at end of file diff --git a/src/OpenRpg.UnitTests/Items/InventoryExtensionTests.cs b/src/OpenRpg.UnitTests/Items/InventoryExtensionTests.cs index dfb84ae0..c6f6b923 100644 --- a/src/OpenRpg.UnitTests/Items/InventoryExtensionTests.cs +++ b/src/OpenRpg.UnitTests/Items/InventoryExtensionTests.cs @@ -34,13 +34,13 @@ public void should_correctly_return_if_it_has_items_with_amounts(int startingAmo { var existingItemTemplate = new ItemTemplate { Id = 1 }; var existingItem = new ItemData() { TemplateId = existingItemTemplate.Id }; - existingItem.Variables.Amount(startingAmount); + existingItem.Variables.Amount = startingAmount; var inventory = new Inventory(); inventory.Items.Add(existingItem); var itemToCheck = new ItemData() { TemplateId = existingItemTemplate.Id }; - itemToCheck.Variables.Amount(requestAmount); + itemToCheck.Variables.Amount = requestAmount; var actualThroughAgnosticMethod = inventory.HasItem(itemToCheck); var actualFromDirectMethod = inventory.HasItem(existingItemTemplate.Id, requestAmount); diff --git a/src/OpenRpg.UnitTests/Items/InventoryTransactionTests.cs b/src/OpenRpg.UnitTests/Items/InventoryTransactionTests.cs index 49f0d00c..107dc08b 100644 --- a/src/OpenRpg.UnitTests/Items/InventoryTransactionTests.cs +++ b/src/OpenRpg.UnitTests/Items/InventoryTransactionTests.cs @@ -21,16 +21,16 @@ public void should_carry_out_transaction_successfully() var dummyItemTemplate4 = new ItemTemplate() { Id = 789 }; var itemToRemove1 = new ItemData() { TemplateId = dummyItemTemplate1.Id }; - itemToRemove1.Variables.Amount(5); + itemToRemove1.Variables.Amount = 5; var itemToRemove2 = new ItemData() { TemplateId = dummyItemTemplate2.Id }; - itemToRemove2.Variables.Amount(2); + itemToRemove2.Variables.Amount = 2; var itemToAdd1 = new ItemData() { TemplateId = dummyItemTemplate3.Id }; - itemToAdd1.Variables.Amount(1); + itemToAdd1.Variables.Amount = 1; var itemToAdd2 = new ItemData() { TemplateId = dummyItemTemplate4.Id }; - itemToAdd2.Variables.Amount(10); + itemToAdd2.Variables.Amount = 10; var inventory = new Inventory() { @@ -66,10 +66,10 @@ public void should_carry_out_transaction_successfully() Assert.True(inventory.HasItem((dummyItemTemplate3.Id))); var item1 = inventory.Items.Single(x => x.TemplateId == itemToAdd1.TemplateId); - Assert.Equal(itemToAdd1.Variables.Amount(), item1.Variables.Amount()); + Assert.Equal(itemToAdd1.Variables.Amount, item1.Variables.Amount); Assert.True(inventory.HasItem((dummyItemTemplate4.Id))); var item2 = inventory.Items.Single(x => x.TemplateId == itemToAdd2.TemplateId); - Assert.Equal(itemToAdd2.Variables.Amount(), item2.Variables.Amount()); + Assert.Equal(itemToAdd2.Variables.Amount, item2.Variables.Amount); } } \ No newline at end of file diff --git a/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCraftingTests.cs b/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCraftingTests.cs index 8b630a84..004a7f31 100644 --- a/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCraftingTests.cs +++ b/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCraftingTests.cs @@ -23,20 +23,20 @@ public void should_return_true_when_inventory_has_items_for_crafting() var dummyItemTemplate2 = new ItemTemplate() { Id = 345 }; var inputItem1 = new TradeSkillItemEntry() { TemplateId = dummyItemTemplate1.Id }; - inputItem1.Variables.Amount(5); + inputItem1.Variables.Amount = 5; var inputItem2 = new TradeSkillItemEntry() { TemplateId = dummyItemTemplate2.Id }; - inputItem2.Variables.Amount(2); + inputItem2.Variables.Amount = 2; var inputItems = new List() { inputItem1, inputItem2 }; var craftingTemplate = new ItemCraftingTemplate() { Id = 1, InputItems = inputItems, OutputItems = new List() }; var itemInInventory1 = new ItemData() { TemplateId = dummyItemTemplate1.Id }; - itemInInventory1.Variables.Amount(5); + itemInInventory1.Variables.Amount = 5; var itemInInventory2 = new ItemData() { TemplateId = dummyItemTemplate2.Id }; - itemInInventory2.Variables.Amount(2); + itemInInventory2.Variables.Amount = 2; var inventory = new Inventory() { @@ -54,17 +54,17 @@ public void should_return_false_when_inventory_missing_items_for_crafting() var dummyItemTemplate2 = new ItemTemplate() { Id = 345 }; var inputItem1 = new TradeSkillItemEntry() { TemplateId = dummyItemTemplate1.Id }; - inputItem1.Variables.Amount(5); + inputItem1.Variables.Amount = 5; var inputItem2 = new TradeSkillItemEntry() { TemplateId = dummyItemTemplate2.Id }; - inputItem2.Variables.Amount(2); + inputItem2.Variables.Amount = 2; var inputItems = new List() { inputItem1, inputItem2 }; var craftingTemplate = new ItemCraftingTemplate() { Id = 1, InputItems = inputItems, OutputItems = new List() }; var itemInInventory1 = new ItemData() { TemplateId = dummyItemTemplate1.Id }; - itemInInventory1.Variables.Amount(5); + itemInInventory1.Variables.Amount = 5; var inventory = new Inventory() { @@ -84,28 +84,28 @@ public void should_craft_item() var dummyItemTemplate4 = new ItemTemplate() { Id = 789 }; var inputItem1 = new TradeSkillItemEntry() { TemplateId = dummyItemTemplate1.Id }; - inputItem1.Variables.Amount(5); + inputItem1.Variables.Amount = 5; var inputItem2 = new TradeSkillItemEntry() { TemplateId = dummyItemTemplate2.Id }; - inputItem2.Variables.Amount(2); + inputItem2.Variables.Amount = 2; var inputItems = new List() { inputItem1, inputItem2 }; var outputItem1 = new TradeSkillItemEntry() { TemplateId = dummyItemTemplate3.Id }; - outputItem1.Variables.Amount(1); + outputItem1.Variables.Amount = 1; var outputItem2 = new TradeSkillItemEntry() { TemplateId = dummyItemTemplate4.Id }; - outputItem2.Variables.Amount(10); + outputItem2.Variables.Amount = 10; var outputItems = new List() { outputItem1, outputItem2 }; var craftingTemplate = new ItemCraftingTemplate() { Id = 1, InputItems = inputItems, OutputItems = outputItems }; var itemInInventory1 = new ItemData() { TemplateId = dummyItemTemplate1.Id }; - itemInInventory1.Variables.Amount(5); + itemInInventory1.Variables.Amount = 5; var itemInInventory2 = new ItemData() { TemplateId = dummyItemTemplate2.Id }; - itemInInventory2.Variables.Amount(2); + itemInInventory2.Variables.Amount = 2; var inventory = new Inventory() { @@ -140,10 +140,10 @@ public void should_craft_item() Assert.True(inventory.HasItem((dummyItemTemplate3.Id))); var craftedItem1 = inventory.Items.Single(x => x.TemplateId == dummyItemTemplate3.Id); - Assert.Equal(outputItem1.Variables.Amount(), craftedItem1.Variables.Amount()); + Assert.Equal(outputItem1.Variables.Amount, craftedItem1.Variables.Amount); Assert.True(inventory.HasItem((dummyItemTemplate4.Id))); var craftedItem2 = inventory.Items.Single(x => x.TemplateId == dummyItemTemplate4.Id); - Assert.Equal(outputItem2.Variables.Amount(), craftedItem2.Variables.Amount()); + Assert.Equal(outputItem2.Variables.Amount, craftedItem2.Variables.Amount); } } \ No newline at end of file From 7de1f1fdbad1709b934c31f32daa6d2b4f028824 Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 9 Dec 2025 11:06:03 +0000 Subject: [PATCH 006/153] Updated more extensions to properties --- .../Inventories/BasicInventory.razor | 4 +- .../Pages/Curves/AdvancedEffects.razor | 2 +- .../Inventory/BasicInventoryComponents.razor | 2 +- .../TradeSkills/CraftingTradeSkills.razor | 2 +- .../TradeSkills/GatheringTradeSkills.razor | 4 +- .../Builders/CharacterBuilder.cs | 4 +- .../Effects/CharacterEffectProcessor.cs | 2 +- .../Extensions/EntityExtensions.cs | 2 +- .../Extensions/RequirementExtensions.cs | 4 +- .../DefaultCharacterRequirementChecker.cs | 6 +-- .../ICharacterRequirementChecker.cs | 2 +- .../Extensions/InventoryExtensions.cs | 7 ++-- .../InventoryVariablesExtensions.cs | 31 +++++++++++--- .../ItemEntityVariableExtensions.cs | 41 +++++++++++-------- .../Extensions/ItemExtensions.cs | 4 +- .../LootTableEntryVariablesExtensions.cs | 38 ++++++++--------- src/OpenRpg.Items/Loot/DefaultLootTable.cs | 4 +- .../QuestEntityVariableExtensions.cs | 39 +++++++++++------- ...ggerStateVariables.cs => ITriggerState.cs} | 2 +- src/OpenRpg.Quests/State/TriggerState.cs | 2 +- .../Fantasy/FantasyCharacterBuilderTests.cs | 2 +- .../Items/DefaultInventoryAmountTests.cs | 2 +- .../Items/ItemEntityVariableExtensionTests.cs | 12 +++--- .../Quest/ItemEntityVariableExtensionTests.cs | 12 +++--- 24 files changed, 133 insertions(+), 97 deletions(-) rename src/OpenRpg.Quests/State/{ITriggerStateVariables.cs => ITriggerState.cs} (53%) diff --git a/src/OpenRpg.Demos.Web/Components/Inventories/BasicInventory.razor b/src/OpenRpg.Demos.Web/Components/Inventories/BasicInventory.razor index 7c817d18..43310603 100644 --- a/src/OpenRpg.Demos.Web/Components/Inventories/BasicInventory.razor +++ b/src/OpenRpg.Demos.Web/Components/Inventories/BasicInventory.razor @@ -5,7 +5,7 @@ @using OpenRpg.Items @using OpenRpg.Items.Inventories -@for (var i = 0; i < Inventory.Variables.MaxSlots(); i+=SlotsPerRow) +@for (var i = 0; i < Inventory.Variables.MaxSlots; i+=SlotsPerRow) {
@for (var row = 0; row < SlotsPerRow; row++) @@ -20,7 +20,7 @@
}
- @(Inventory.Items.Count) @(Inventory.Variables.ContainsKey(InventoryVariableTypes.MaxSlots) ? $"/ {Inventory.Variables.MaxSlots()}" : "") Items + @(Inventory.Items.Count) @(Inventory.Variables.ContainsKey(InventoryVariableTypes.MaxSlots) ? $"/ {Inventory.Variables.MaxSlots}" : "") Items
@code { diff --git a/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor b/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor index acf4db61..9a25bc3a 100644 --- a/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor +++ b/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor @@ -287,7 +287,7 @@ ExampleCharacter.Variables.Race = new RaceData() { TemplateId = pretendHumanRace.Id }; ExampleCharacter.Variables.Class = new ClassData() { TemplateId = pretendFighterClassTemplate.Id }; - ExampleCharacter.Variables.Equipment(equipment); + ExampleCharacter.Variables.Equipment = equipment; TemplateAccessor.AddTemplate(pretendHumanRace); TemplateAccessor.AddTemplate(pretendFighterClassTemplate); diff --git a/src/OpenRpg.Demos.Web/Pages/Inventory/BasicInventoryComponents.razor b/src/OpenRpg.Demos.Web/Pages/Inventory/BasicInventoryComponents.razor index 4f2d0c74..4ebac194 100644 --- a/src/OpenRpg.Demos.Web/Pages/Inventory/BasicInventoryComponents.razor +++ b/src/OpenRpg.Demos.Web/Pages/Inventory/BasicInventoryComponents.razor @@ -107,7 +107,7 @@ _potionItem = MakePotion(); _junkPotions = MakeJunkPotion(); _inventory = new Inventory(); - _inventory.Variables.MaxSlots(32); + _inventory.Variables.MaxSlots = 32; base.OnInitialized(); } diff --git a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor index a5ee4c17..45a35b8c 100644 --- a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor +++ b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor @@ -177,7 +177,7 @@ CopperSwordCraftingTemplate = TemplateAccessor.GetItemCraftingTemplate(ItemCraftingTemplateLookups.CopperSword); CopperIngotCraftingTemplate = TemplateAccessor.GetItemCraftingTemplate(ItemCraftingTemplateLookups.CopperIngot); - CraftingInventory.Variables.MaxSlots(50); + CraftingInventory.Variables.MaxSlots = 50; GiveCopperOre(10); DummyCharacter.Variables.TradeSkillState(new TradeSkillState()); diff --git a/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor b/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor index a767873b..d86b66d8 100644 --- a/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor +++ b/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor @@ -201,8 +201,8 @@ { TradeSkillCalculator = new TradeSkillCalculator(Randomizer) { RandomnessVariance = 0.2f }; - Example1Inventory.Variables.MaxSlots(10); - Example2Inventory.Variables.MaxSlots(10); + Example1Inventory.Variables.MaxSlots = 10; + Example2Inventory.Variables.MaxSlots = 10; CopperOreGatheringTemplate = TemplateAccessor.GetItemGatheringTemplate(ItemGatheringTemplateLookups.CopperOre); OakLogGatheringTemplate = TemplateAccessor.GetItemGatheringTemplate(ItemGatheringTemplateLookups.OakLog); IronOreGatheringTemplate = TemplateAccessor.GetItemGatheringTemplate(ItemGatheringTemplateLookups.IronOre); diff --git a/src/OpenRpg.Genres/Builders/CharacterBuilder.cs b/src/OpenRpg.Genres/Builders/CharacterBuilder.cs index fb57c319..3db172b2 100644 --- a/src/OpenRpg.Genres/Builders/CharacterBuilder.cs +++ b/src/OpenRpg.Genres/Builders/CharacterBuilder.cs @@ -164,8 +164,8 @@ public virtual Character CreateCharacter() { _variables.Class = ProcessClass(); _variables.Race = ProcessRace(); - _variables.Equipment(ProcessEquipment()); - _variables.Inventory(ProcessInventory()); + _variables.Equipment = ProcessEquipment(); + _variables.Inventory = ProcessInventory(); _variables.Gender = _genderId; var character = CreateCharacterInstance(); diff --git a/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs b/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs index 44649fce..bcd23b52 100644 --- a/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs +++ b/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs @@ -50,7 +50,7 @@ public override ComputedEffects ComputeEffects(Character entity) if (entity.Variables.HasEquipment()) { - var equipment = entity.Variables.Equipment(); + var equipment = entity.Variables.Equipment; var equippedItems = equipment.Slots.Values .Where(x => x != null); diff --git a/src/OpenRpg.Genres/Extensions/EntityExtensions.cs b/src/OpenRpg.Genres/Extensions/EntityExtensions.cs index 5414d767..36ed7641 100644 --- a/src/OpenRpg.Genres/Extensions/EntityExtensions.cs +++ b/src/OpenRpg.Genres/Extensions/EntityExtensions.cs @@ -15,7 +15,7 @@ public static IReadOnlyCollection GetEffects(this Entity entity, ITempl if (entity.Variables.HasRace()) { effects.AddRange(entity.Variables.Race.GetEffects(templateAccessor)); } if (entity.Variables.HasClass()) { effects.AddRange(entity.Variables.Class.GetEffects(templateAccessor)); } - if (entity.Variables.HasEquipment()) { effects.AddRange(entity.Variables.Equipment().GetEffects(templateAccessor)); } + if (entity.Variables.HasEquipment()) { effects.AddRange(entity.Variables.Equipment.GetEffects(templateAccessor)); } return effects; } diff --git a/src/OpenRpg.Genres/Extensions/RequirementExtensions.cs b/src/OpenRpg.Genres/Extensions/RequirementExtensions.cs index 4e337c47..213a8510 100644 --- a/src/OpenRpg.Genres/Extensions/RequirementExtensions.cs +++ b/src/OpenRpg.Genres/Extensions/RequirementExtensions.cs @@ -14,10 +14,10 @@ public static bool AreRequirementsMet(this ICharacterRequirementChecker characte public static bool AreRequirementsMet(this ICharacterRequirementChecker characterRequirementChecker, IQuestState questState, IHasRequirements hasRequirements) { return hasRequirements.Requirements.All(x => characterRequirementChecker.IsRequirementMet(questState, x)); } - public static bool AreRequirementsMet(this ICharacterRequirementChecker characterRequirementChecker, ITriggerStateVariables triggerState, IHasRequirements hasRequirements) + public static bool AreRequirementsMet(this ICharacterRequirementChecker characterRequirementChecker, ITriggerState triggerState, IHasRequirements hasRequirements) { return hasRequirements.Requirements.All(x => characterRequirementChecker.IsRequirementMet(triggerState, x)); } - public static bool AreRequirementsMet(this ICharacterRequirementChecker characterRequirementChecker, IQuestState questState, ITriggerStateVariables triggerState, + public static bool AreRequirementsMet(this ICharacterRequirementChecker characterRequirementChecker, IQuestState questState, ITriggerState triggerState, Character character, IHasRequirements hasRequirements) { return AreRequirementsMet(characterRequirementChecker, character, hasRequirements) && diff --git a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs index c467e6c1..99711070 100644 --- a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs +++ b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs @@ -58,7 +58,7 @@ public virtual bool IsRequirementMet(Character character, Requirement requiremen if (!character.Variables.HasEquipment()) { return false; } - return character.Variables.Equipment().Slots.Values + return character.Variables.Equipment.Slots.Values .Any(x => x?.TemplateId == requirement.Association.AssociatedId); } @@ -79,7 +79,7 @@ public virtual bool IsRequirementMet(Character character, Requirement requiremen if (!character.Variables.HasInventory()) { return false; } - return character.Variables.Inventory() + return character.Variables.Inventory .HasItem(requirement.Association.AssociatedId, requirement.Association.AssociatedValue); } @@ -112,7 +112,7 @@ public virtual bool IsRequirementMet(IQuestState state, Requirement requirement) return true; } - public virtual bool IsRequirementMet(ITriggerStateVariables state, Requirement requirement) + public virtual bool IsRequirementMet(ITriggerState state, Requirement requirement) { if (requirement.RequirementType == GenreRequirementTypes.TriggerRequirement) { diff --git a/src/OpenRpg.Genres/Requirements/ICharacterRequirementChecker.cs b/src/OpenRpg.Genres/Requirements/ICharacterRequirementChecker.cs index 1fa85a5e..3c2568c9 100644 --- a/src/OpenRpg.Genres/Requirements/ICharacterRequirementChecker.cs +++ b/src/OpenRpg.Genres/Requirements/ICharacterRequirementChecker.cs @@ -8,6 +8,6 @@ namespace OpenRpg.Genres.Requirements public interface ICharacterRequirementChecker : IEntityRequirementChecker { bool IsRequirementMet(IQuestState state, Requirement requirement); - bool IsRequirementMet(ITriggerStateVariables state, Requirement requirement); + bool IsRequirementMet(ITriggerState state, Requirement requirement); } } \ No newline at end of file diff --git a/src/OpenRpg.Items/Extensions/InventoryExtensions.cs b/src/OpenRpg.Items/Extensions/InventoryExtensions.cs index 73043f03..beec74ee 100644 --- a/src/OpenRpg.Items/Extensions/InventoryExtensions.cs +++ b/src/OpenRpg.Items/Extensions/InventoryExtensions.cs @@ -87,7 +87,7 @@ public static bool HasSlotCapacity(this Inventory inventory, int slotsRequired = if (!inventory.Variables.HasMaxSlots()) { return true; } - return inventory.Items.Count + slotsRequired < inventory.Variables.MaxSlots(); + return inventory.Items.Count + slotsRequired < inventory.Variables.MaxSlots; } public static bool HasWeightCapacity(this Inventory inventory, float weightToAdd) @@ -96,7 +96,7 @@ public static bool HasWeightCapacity(this Inventory inventory, float weightToAdd { return true; } var proposedWeight = inventory.Items.Sum(x => x.Variables.Weight) + weightToAdd; - return proposedWeight < inventory.Variables.MaxWeight(); + return proposedWeight < inventory.Variables.MaxWeight; } /// @@ -148,7 +148,7 @@ public static bool AttemptAddAmountItem(Inventory inventory, Item item) .OrderByDescending(x => x.Variables.Amount) .ToArray(); - var maxSlots = inventory.Variables.MaxSlots(); + var maxSlots = inventory.Variables.MaxSlots; if (maxSlots > 0) { var currentSlots = inventory.Items.Count; @@ -204,7 +204,6 @@ public static bool AttemptAddAmountItem(Inventory inventory, Item item) itemDataHasWithSpace.Variables.Amount = existingAmount + amountLeft; amountLeft = 0; } - index++; } diff --git a/src/OpenRpg.Items/Extensions/InventoryVariablesExtensions.cs b/src/OpenRpg.Items/Extensions/InventoryVariablesExtensions.cs index b86c9004..b6abee68 100644 --- a/src/OpenRpg.Items/Extensions/InventoryVariablesExtensions.cs +++ b/src/OpenRpg.Items/Extensions/InventoryVariablesExtensions.cs @@ -8,12 +8,31 @@ namespace OpenRpg.Items.Extensions public static class InventoryVariablesExtensions { public static bool HasMaxWeight(this InventoryVariables variables) => variables.ContainsKey(InventoryVariableTypes.MaxWeight); - public static float MaxWeight(this InventoryVariables variables) => variables.GetFloat(InventoryVariableTypes.MaxWeight); - public static void MaxWeight(this InventoryVariables variables, float value) => variables[InventoryVariableTypes.MaxWeight] = value; - public static float Weight(this InventoryVariables variables) => variables.GetFloat(InventoryVariableTypes.Weight); - public static void Weight(this InventoryVariables variables, float value) => variables[InventoryVariableTypes.Weight] = value; + + extension(InventoryVariables vars) + { + public float MaxWeight + { + get => vars.GetFloat(InventoryVariableTypes.MaxWeight); + set => vars[InventoryVariableTypes.MaxWeight] = value; + } + + public float Weight + { + get => vars.GetFloat(InventoryVariableTypes.Weight); + set => vars[InventoryVariableTypes.Weight] = value; + } + } + public static bool HasMaxSlots(this InventoryVariables variables) => variables.ContainsKey(InventoryVariableTypes.MaxSlots); - public static int MaxSlots(this InventoryVariables variables) => variables.GetInt(InventoryVariableTypes.MaxSlots); - public static void MaxSlots(this InventoryVariables variables, int value) => variables[InventoryVariableTypes.MaxSlots] = value; + + extension(InventoryVariables vars) + { + public int MaxSlots + { + get => vars.GetInt(InventoryVariableTypes.MaxSlots); + set => vars[InventoryVariableTypes.MaxSlots] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Items/Extensions/ItemEntityVariableExtensions.cs b/src/OpenRpg.Items/Extensions/ItemEntityVariableExtensions.cs index 4e2738b6..57be1be6 100644 --- a/src/OpenRpg.Items/Extensions/ItemEntityVariableExtensions.cs +++ b/src/OpenRpg.Items/Extensions/ItemEntityVariableExtensions.cs @@ -14,29 +14,38 @@ public static class ItemEntityVariableExtensions { public static bool HasEquipment(this EntityVariables vars) { return vars.ContainsKey(ItemEntityVariableTypes.Equipment); } - - public static Equipment Equipment(this EntityVariables vars) - { return vars.GetAs(ItemEntityVariableTypes.Equipment); } - public static void Equipment(this EntityVariables vars, Equipment equipment) - { vars[ItemEntityVariableTypes.Equipment] = equipment; } + extension(EntityVariables vars) + { + public Equipment Equipment + { + get => vars.GetAsOrDefault(ItemEntityVariableTypes.Equipment, () => new Equipment()); + set => vars[ItemEntityVariableTypes.Equipment] = value; + } + } public static bool HasInventory(this EntityVariables vars) { return vars.ContainsKey(ItemEntityVariableTypes.Inventory); } - public static Inventory Inventory(this EntityVariables vars) - { return vars.GetAs(ItemEntityVariableTypes.Inventory); } - - public static void Inventory(this EntityVariables vars, Inventory inventory) - { vars[ItemEntityVariableTypes.Inventory] = inventory; } - + extension(EntityVariables vars) + { + public Inventory Inventory + { + get => vars.GetAsOrDefault(ItemEntityVariableTypes.Inventory, () => new Inventory()); + set => vars[ItemEntityVariableTypes.Inventory] = value; + } + } + public static bool HasLootTable(this EntityVariables vars) { return vars.ContainsKey(ItemEntityVariableTypes.LootTable); } - public static ILootTable LootTable(this EntityVariables vars) - { return vars.GetAs(ItemEntityVariableTypes.LootTable); } - - public static void LootTable(this EntityVariables vars, ILootTable lootTable) - { vars[ItemEntityVariableTypes.LootTable] = lootTable; } + extension(EntityVariables vars) + { + public ILootTable LootTable + { + get => vars.GetAsOrDefault(ItemEntityVariableTypes.LootTable, () => new DefaultLootTable()); + set => vars[ItemEntityVariableTypes.LootTable] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Items/Extensions/ItemExtensions.cs b/src/OpenRpg.Items/Extensions/ItemExtensions.cs index 96e28f00..6cb23fb5 100644 --- a/src/OpenRpg.Items/Extensions/ItemExtensions.cs +++ b/src/OpenRpg.Items/Extensions/ItemExtensions.cs @@ -37,8 +37,8 @@ public static Item Clone(this Item item) public static LootTableEntry GenerateLootTableEntry(this ItemData itemData, float dropRate = 1, bool isUnique = false, IReadOnlyCollection requirements = null) { var variables = new LootTableEntryVariables(); - variables.DropRate(dropRate); - variables.IsUnique(isUnique); + variables.DropRate = dropRate; + variables.IsUnique = isUnique; return new LootTableEntry { diff --git a/src/OpenRpg.Items/Extensions/LootTableEntryVariablesExtensions.cs b/src/OpenRpg.Items/Extensions/LootTableEntryVariablesExtensions.cs index 21f4d91a..1b31d426 100644 --- a/src/OpenRpg.Items/Extensions/LootTableEntryVariablesExtensions.cs +++ b/src/OpenRpg.Items/Extensions/LootTableEntryVariablesExtensions.cs @@ -6,24 +6,24 @@ namespace OpenRpg.Items.Extensions { public static class LootTableEntryVariablesExtensions { - public static float DropRate(this LootTableEntryVariables variables) => variables.GetFloat(LootTableEntryVariableTypes.DropRate); - - /// - /// The DropRate should be a value between 0-1 in which 0 is no drop chance, 0.5 is 50% drop chance, 1 is 100% drop chance - /// - /// /// - /// The drop chance between 0-1 - /// The drop chance can be as low as needed i.e a 1 in 1000 can be represented as 0.001 - public static void DropRate(this LootTableEntryVariables variables, float value) => variables[LootTableEntryVariableTypes.DropRate] = value; - - public static bool IsUnique(this LootTableEntryVariables variables) => variables.GetBool(LootTableEntryVariableTypes.IsUnique); - - /// - /// This indicates that the template associated with this item can only be dropped once - /// - /// - /// a true or false - /// This still needs to be rolled on so even though something is unique it may not be looted - public static void IsUnique(this LootTableEntryVariables variables, bool value) => variables[LootTableEntryVariableTypes.IsUnique] = value; + extension(LootTableEntryVariables vars) + { + /// + /// The DropRate should be a value between 0-1 in which 0 is no drop chance, 0.5 is 50% drop chance, 1 is 100% drop chance + /// + /// The drop chance between 0-1 + /// The drop chance can be as low as needed i.e a 1 in 1000 can be represented as 0.001 + public float DropRate + { + get => vars.GetFloat(LootTableEntryVariableTypes.DropRate); + set => vars[LootTableEntryVariableTypes.DropRate] = value; + } + + public bool IsUnique + { + get => vars.GetBool(LootTableEntryVariableTypes.IsUnique); + set => vars[LootTableEntryVariableTypes.IsUnique] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Items/Loot/DefaultLootTable.cs b/src/OpenRpg.Items/Loot/DefaultLootTable.cs index 694a64a6..bdba2a8c 100644 --- a/src/OpenRpg.Items/Loot/DefaultLootTable.cs +++ b/src/OpenRpg.Items/Loot/DefaultLootTable.cs @@ -30,9 +30,9 @@ public IEnumerable GetRandomLootEntries() foreach (var loot in AvailableLoot) { var randomChance = Randomizer.Random(0f, 1f); - if (!(loot.Variables.DropRate() >= randomChance)) { continue; } + if (!(loot.Variables.DropRate >= randomChance)) { continue; } - if (loot.Variables.ContainsKey(LootTableEntryVariableTypes.IsUnique) && loot.Variables.IsUnique()) + if (loot.Variables.ContainsKey(LootTableEntryVariableTypes.IsUnique) && loot.Variables.IsUnique) { if(uniqueItems.Contains(loot.ItemData)) { continue; } diff --git a/src/OpenRpg.Quests/Extensions/QuestEntityVariableExtensions.cs b/src/OpenRpg.Quests/Extensions/QuestEntityVariableExtensions.cs index 529b4a2f..49993a90 100644 --- a/src/OpenRpg.Quests/Extensions/QuestEntityVariableExtensions.cs +++ b/src/OpenRpg.Quests/Extensions/QuestEntityVariableExtensions.cs @@ -10,29 +10,38 @@ public static class QuestEntityVariableExtensions { public static bool HasFactionReputation(this EntityVariables vars) { return vars.ContainsKey(QuestEntityVariableTypes.FactionReputation); } - - public static FactionReputation FactionReputation(this EntityVariables vars) - { return vars.GetAs(QuestEntityVariableTypes.FactionReputation); } - public static void FactionReputation(this EntityVariables vars, FactionReputation factionReputation) - { vars[QuestEntityVariableTypes.FactionReputation] = factionReputation; } + extension(EntityVariables vars) + { + public FactionReputation FactionReputation + { + get => vars.GetAsOrDefault(QuestEntityVariableTypes.FactionReputation, () => new FactionReputation()); + set => vars[QuestEntityVariableTypes.FactionReputation] = value; + } + } public static bool HasQuestState(this EntityVariables vars) { return vars.ContainsKey(QuestEntityVariableTypes.QuestState); } - public static IQuestState QuestState(this EntityVariables vars) - { return vars.GetAs(QuestEntityVariableTypes.QuestState); } - - public static void QuestState(this EntityVariables vars, IQuestState questState) - { vars[QuestEntityVariableTypes.QuestState] = questState; } + extension(EntityVariables vars) + { + public IQuestState QuestState + { + get => vars.GetAsOrDefault(QuestEntityVariableTypes.QuestState, () => new QuestState()); + set => vars[QuestEntityVariableTypes.QuestState] = value; + } + } public static bool HasTriggerState(this EntityVariables vars) { return vars.ContainsKey(QuestEntityVariableTypes.TriggerState); } - public static ITriggerStateVariables TriggerState(this EntityVariables vars) - { return vars.GetAs(QuestEntityVariableTypes.TriggerState); } - - public static void TriggerState(this EntityVariables vars, ITriggerStateVariables triggerState) - { vars[QuestEntityVariableTypes.TriggerState] = triggerState; } + extension(EntityVariables vars) + { + public ITriggerState TriggerState + { + get => vars.GetAsOrDefault(QuestEntityVariableTypes.TriggerState, () => new TriggerState()); + set => vars[QuestEntityVariableTypes.TriggerState] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Quests/State/ITriggerStateVariables.cs b/src/OpenRpg.Quests/State/ITriggerState.cs similarity index 53% rename from src/OpenRpg.Quests/State/ITriggerStateVariables.cs rename to src/OpenRpg.Quests/State/ITriggerState.cs index 58590d79..9aa074b0 100644 --- a/src/OpenRpg.Quests/State/ITriggerStateVariables.cs +++ b/src/OpenRpg.Quests/State/ITriggerState.cs @@ -2,6 +2,6 @@ namespace OpenRpg.Quests.State { - public interface ITriggerStateVariables : IVariables + public interface ITriggerState : IVariables {} } \ No newline at end of file diff --git a/src/OpenRpg.Quests/State/TriggerState.cs b/src/OpenRpg.Quests/State/TriggerState.cs index 2c617057..d8259b3b 100644 --- a/src/OpenRpg.Quests/State/TriggerState.cs +++ b/src/OpenRpg.Quests/State/TriggerState.cs @@ -4,7 +4,7 @@ namespace OpenRpg.Quests.State { - public class TriggerState : Variables, ITriggerStateVariables + public class TriggerState : Variables, ITriggerState { public TriggerState(IDictionary internalVariables = null) : base(QuestVariableTypes.TriggerVariables, internalVariables) { diff --git a/src/OpenRpg.UnitTests/Genres/Fantasy/FantasyCharacterBuilderTests.cs b/src/OpenRpg.UnitTests/Genres/Fantasy/FantasyCharacterBuilderTests.cs index 12af7f53..b26e6823 100644 --- a/src/OpenRpg.UnitTests/Genres/Fantasy/FantasyCharacterBuilderTests.cs +++ b/src/OpenRpg.UnitTests/Genres/Fantasy/FantasyCharacterBuilderTests.cs @@ -22,7 +22,7 @@ public void should_correctly_setup_slots_for_mapping_when_has_equipment() Assert.NotNull(character); Assert.NotNull(character.Variables); - var equipment = character.Variables.Equipment(); + var equipment = character.Variables.Equipment; Assert.NotNull(equipment); var slots = equipment.Slots; diff --git a/src/OpenRpg.UnitTests/Items/DefaultInventoryAmountTests.cs b/src/OpenRpg.UnitTests/Items/DefaultInventoryAmountTests.cs index af61694f..f438a84f 100644 --- a/src/OpenRpg.UnitTests/Items/DefaultInventoryAmountTests.cs +++ b/src/OpenRpg.UnitTests/Items/DefaultInventoryAmountTests.cs @@ -118,7 +118,7 @@ public void should_not_add_item_amount_when_existing_across_multiple_existing_st existingItem2.Variables.Amount = 8; var inventory = new Inventory(); - inventory.Variables.MaxSlots(2); + inventory.Variables.MaxSlots = 2; inventory.Items.Add(existingItem1); inventory.Items.Add(existingItem2); diff --git a/src/OpenRpg.UnitTests/Items/ItemEntityVariableExtensionTests.cs b/src/OpenRpg.UnitTests/Items/ItemEntityVariableExtensionTests.cs index 177c94e2..23d5d007 100644 --- a/src/OpenRpg.UnitTests/Items/ItemEntityVariableExtensionTests.cs +++ b/src/OpenRpg.UnitTests/Items/ItemEntityVariableExtensionTests.cs @@ -16,9 +16,9 @@ public void should_correctly_handle_inventory_on_entity() Assert.False(entityVars.HasInventory()); var dummyInventory = new Inventory(); - entityVars.Inventory(dummyInventory); + entityVars.Inventory = dummyInventory; Assert.True(entityVars.HasInventory()); - Assert.Equal(entityVars.Inventory(), dummyInventory); + Assert.Equal(entityVars.Inventory, dummyInventory); } [Fact] @@ -28,9 +28,9 @@ public void should_correctly_handle_equipment_on_entity() Assert.False(entityVars.HasEquipment()); var dummyEquipment = new Equipment(); - entityVars.Equipment(dummyEquipment); + entityVars.Equipment = dummyEquipment; Assert.True(entityVars.HasEquipment()); - Assert.Equal(entityVars.Equipment(), dummyEquipment); + Assert.Equal(entityVars.Equipment, dummyEquipment); } [Fact] @@ -40,8 +40,8 @@ public void should_correctly_handle_loot_table_on_entity() Assert.False(entityVars.HasLootTable()); var dummyLootTable = new DefaultLootTable(); - entityVars.LootTable(dummyLootTable); + entityVars.LootTable = dummyLootTable; Assert.True(entityVars.HasLootTable()); - Assert.Equal(entityVars.LootTable(), dummyLootTable); + Assert.Equal(entityVars.LootTable, dummyLootTable); } } \ No newline at end of file diff --git a/src/OpenRpg.UnitTests/Quest/ItemEntityVariableExtensionTests.cs b/src/OpenRpg.UnitTests/Quest/ItemEntityVariableExtensionTests.cs index cf67b411..67ee85ef 100644 --- a/src/OpenRpg.UnitTests/Quest/ItemEntityVariableExtensionTests.cs +++ b/src/OpenRpg.UnitTests/Quest/ItemEntityVariableExtensionTests.cs @@ -15,9 +15,9 @@ public void should_correctly_handle_faction_reputation_on_entity() Assert.False(entityVars.HasFactionReputation()); var dummyFactionRep = new FactionReputation(); - entityVars.FactionReputation(dummyFactionRep); + entityVars.FactionReputation = dummyFactionRep; Assert.True(entityVars.HasFactionReputation()); - Assert.Equal(entityVars.FactionReputation(), dummyFactionRep); + Assert.Equal(entityVars.FactionReputation, dummyFactionRep); } [Fact] @@ -27,9 +27,9 @@ public void should_correctly_handle_quest_state_on_entity() Assert.False(entityVars.HasQuestState()); var dummyQuestState = new QuestState(); - entityVars.QuestState(dummyQuestState); + entityVars.QuestState = dummyQuestState; Assert.True(entityVars.HasQuestState()); - Assert.Equal(entityVars.QuestState(), dummyQuestState); + Assert.Equal(entityVars.QuestState, dummyQuestState); } [Fact] @@ -39,8 +39,8 @@ public void should_correctly_handle_trigger_state_on_entity() Assert.False(entityVars.HasTriggerState()); var dummyQuestState = new TriggerState(); - entityVars.TriggerState(dummyQuestState); + entityVars.TriggerState = dummyQuestState; Assert.True(entityVars.HasTriggerState()); - Assert.Equal(entityVars.TriggerState(), dummyQuestState); + Assert.Equal(entityVars.TriggerState, dummyQuestState); } } \ No newline at end of file From 5e9ba75b9581fe556f5f4e0b3d72dc9553f2b039 Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 9 Dec 2025 12:34:50 +0000 Subject: [PATCH 007/153] Updated effect extensions to properties --- .../Effects/DefaultActiveEffects.cs | 2 +- .../Extensions/ActiveEffectsExtensions.cs | 24 ++++++++++--------- .../Pages/Combat/Buffs.razor | 10 ++++---- .../TradeSkills/CraftingTradeSkills.razor | 4 ++-- .../TradeSkills/GatheringTradeSkills.razor | 4 ++-- .../Effects/CharacterEffectProcessor.cs | 2 +- .../DefaultCharacterRequirementChecker.cs | 2 +- .../TradeSkillEntityVariableExtensions.cs | 13 ++++++---- .../Combat/ActiveEffectExtensionTests.cs | 6 ++--- ...TradeSkillsEntityVariableExtensionTests.cs | 4 ++-- 10 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/OpenRpg.Combat/Effects/DefaultActiveEffects.cs b/src/OpenRpg.Combat/Effects/DefaultActiveEffects.cs index 91c1e112..8eadbb76 100644 --- a/src/OpenRpg.Combat/Effects/DefaultActiveEffects.cs +++ b/src/OpenRpg.Combat/Effects/DefaultActiveEffects.cs @@ -20,7 +20,7 @@ public class DefaultActiveEffects : IActiveEffects public IReadOnlyCollection ActiveEffects => InternalActiveEffects.Values; public IReadOnlyCollection Effects => InternalActiveEffects.Values - .Where(x => x.IsPassiveEffect()) + .Where(x => x.IsPassiveEffect) .Select(x => x.ToEffect()) .ToArray(); diff --git a/src/OpenRpg.Combat/Extensions/ActiveEffectsExtensions.cs b/src/OpenRpg.Combat/Extensions/ActiveEffectsExtensions.cs index a2c8e948..5b399e70 100644 --- a/src/OpenRpg.Combat/Extensions/ActiveEffectsExtensions.cs +++ b/src/OpenRpg.Combat/Extensions/ActiveEffectsExtensions.cs @@ -1,32 +1,34 @@ using OpenRpg.Combat.Effects; using OpenRpg.Core.Effects; -using OpenRpg.Entities.Effects; namespace OpenRpg.Combat.Extensions { public static class ActiveEffectsExtensions { - public static bool IsPassiveEffect(this ActiveEffect activeEffect) - { return IsPassiveEffect(activeEffect.StaticEffect); } - - public static bool IsPassiveEffect(this TimedStaticEffect staticEffect) - { return staticEffect.Frequency == 0; } + extension(ActiveEffect effect) + { + public bool IsPassiveEffect => effect.StaticEffect.IsPassiveEffect; + public float StackedPotency => GetStackedPotency(effect); + public int TicksSoFar => (int)(effect.ActiveTime / effect.StaticEffect.Frequency); + } + + extension(TimedStaticEffect effect) + { + public bool IsPassiveEffect => effect.Frequency == 0; + } - public static float GetStackedPotency(this ActiveEffect activeEffect) + public static float GetStackedPotency(ActiveEffect activeEffect) { var stacks = activeEffect.Stacks > 0 ? activeEffect.Stacks : 1; return activeEffect.StaticEffect.Potency * stacks; } - public static int TicksSoFar(this ActiveEffect activeEffect) - { return (int)(activeEffect.ActiveTime / activeEffect.StaticEffect.Frequency); } - public static StaticEffect ToEffect(this ActiveEffect activeEffect) { return new StaticEffect() { EffectType = activeEffect.StaticEffect.EffectType, - Potency = activeEffect.GetStackedPotency(), + Potency = activeEffect.StackedPotency, Requirements = activeEffect.StaticEffect.Requirements }; } diff --git a/src/OpenRpg.Demos.Web/Pages/Combat/Buffs.razor b/src/OpenRpg.Demos.Web/Pages/Combat/Buffs.razor index f7fd86b4..48804241 100644 --- a/src/OpenRpg.Demos.Web/Pages/Combat/Buffs.razor +++ b/src/OpenRpg.Demos.Web/Pages/Combat/Buffs.razor @@ -207,15 +207,15 @@ public void OnEffectTriggered(ActiveEffect activeEffect) { var effectTypeText = activeEffect.IsBeneficialEffect() ? "healing" : "damage"; - var logEntry = new LogEntry(activeEffect.IsBeneficialEffect(), activeEffect.IsPassiveEffect(), - $"Triggered {activeEffect.StaticEffect.NameLocaleId} with {activeEffect.GetStackedPotency()} {effectTypeText}"); + var logEntry = new LogEntry(activeEffect.IsBeneficialEffect(), activeEffect.IsPassiveEffect, + $"Triggered {activeEffect.StaticEffect.NameLocaleId} with {activeEffect.StackedPotency} {effectTypeText}"); LogOutput.Add(logEntry); } public void OnEffectExpired(ActiveEffect activeEffect) { - var logEntry = new LogEntry(activeEffect.IsBeneficialEffect(), activeEffect.IsPassiveEffect(), + var logEntry = new LogEntry(activeEffect.IsBeneficialEffect(), activeEffect.IsPassiveEffect, $"Expired {activeEffect.StaticEffect.NameLocaleId}"); LogOutput.Add(logEntry); @@ -223,7 +223,7 @@ public void OnEffectAdded(ActiveEffect activeEffect) { - var logEntry = new LogEntry(activeEffect.IsBeneficialEffect(), activeEffect.IsPassiveEffect(), + var logEntry = new LogEntry(activeEffect.IsBeneficialEffect(), activeEffect.IsPassiveEffect, $"Added {activeEffect.StaticEffect.NameLocaleId}"); LogOutput.Add(logEntry); @@ -237,7 +237,7 @@ if (alreadyContainsEffect) { - var logEntry = new LogEntry(effectToApply.IsBeneficialEffect(), effectToApply.IsPassiveEffect(), + var logEntry = new LogEntry(effectToApply.IsBeneficialEffect(), effectToApply.IsPassiveEffect, $"Stacked/Reset {effectToApply.NameLocaleId}"); LogOutput.Add(logEntry); diff --git a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor index 45a35b8c..9ffa4b66 100644 --- a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor +++ b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor @@ -168,7 +168,7 @@ public bool HasMatsForCopperSword => CraftingInventory.HasItemsRequiredFor(CopperSwordCraftingTemplate); public bool HasSkillsForCopperSword => RequirementsChecker.AreRequirementsMet(DummyCharacter, CopperSwordCraftingTemplate); - public TradeSkillState TradeSkillState => DummyCharacter.Variables.TradeSkillState(); + public TradeSkillState TradeSkillState => DummyCharacter.Variables.TradeSkillState; protected override void OnInitialized() { @@ -180,7 +180,7 @@ CraftingInventory.Variables.MaxSlots = 50; GiveCopperOre(10); - DummyCharacter.Variables.TradeSkillState(new TradeSkillState()); + DummyCharacter.Variables.TradeSkillState = new TradeSkillState(); TradeSkillState.Smithing(1); base.OnInitialized(); diff --git a/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor b/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor index d86b66d8..c1319011 100644 --- a/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor +++ b/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor @@ -195,7 +195,7 @@ public TradeSkillItemEntry CopperOreTradeSkillItemEntry => CopperOreGatheringTemplate.OutputItems.First(); public TradeSkillItemEntry OakLogTradeSkillItemEntry => OakLogGatheringTemplate.OutputItems.First(); public TradeSkillItemEntry IronOreTradeSkillItemEntry => IronOreGatheringTemplate.OutputItems.First(); - public TradeSkillState TradeSkillState => DummyCharacter.Variables.TradeSkillState(); + public TradeSkillState TradeSkillState => DummyCharacter.Variables.TradeSkillState; protected override void OnInitialized() { @@ -207,7 +207,7 @@ OakLogGatheringTemplate = TemplateAccessor.GetItemGatheringTemplate(ItemGatheringTemplateLookups.OakLog); IronOreGatheringTemplate = TemplateAccessor.GetItemGatheringTemplate(ItemGatheringTemplateLookups.IronOre); - DummyCharacter.Variables.TradeSkillState(new TradeSkillState()); + DummyCharacter.Variables.TradeSkillState = new TradeSkillState(); TradeSkillState.Mining(1); base.OnInitialized(); diff --git a/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs b/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs index bcd23b52..3c5f900a 100644 --- a/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs +++ b/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs @@ -61,7 +61,7 @@ public override ComputedEffects ComputeEffects(Character entity) if (entity.Variables.HasActiveEffects()) { var activeEffects = entity.Variables.ActiveEffects().ActiveEffects - .Where(x => x.IsPassiveEffect()) + .Where(x => x.IsPassiveEffect) .Select(x => x.ToEffect()); foreach(var effect in activeEffects) diff --git a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs index 99711070..b2218d96 100644 --- a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs +++ b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs @@ -67,7 +67,7 @@ public virtual bool IsRequirementMet(Character character, Requirement requiremen if (!character.Variables.HasTradeSkillState()) { return false; } - var tradeSkills = character.Variables.TradeSkillState(); + var tradeSkills = character.Variables.TradeSkillState; if (!tradeSkills.ContainsKey(requirement.Association.AssociatedId)) { return false; } diff --git a/src/OpenRpg.Items.TradeSkills/Extensions/TradeSkillEntityVariableExtensions.cs b/src/OpenRpg.Items.TradeSkills/Extensions/TradeSkillEntityVariableExtensions.cs index 44a42263..bfc102ee 100644 --- a/src/OpenRpg.Items.TradeSkills/Extensions/TradeSkillEntityVariableExtensions.cs +++ b/src/OpenRpg.Items.TradeSkills/Extensions/TradeSkillEntityVariableExtensions.cs @@ -12,11 +12,14 @@ public static class TradeSkillEntityVariableExtensions { public static bool HasTradeSkillState(this EntityVariables vars) { return vars.ContainsKey(TradeSkillEntityVariableTypes.TradeSkillState); } - - public static TradeSkillState TradeSkillState(this EntityVariables vars) - { return vars.GetAs(TradeSkillEntityVariableTypes.TradeSkillState); } - public static void TradeSkillState(this EntityVariables vars, TradeSkillState tradeSkillState) - { vars[TradeSkillEntityVariableTypes.TradeSkillState] = tradeSkillState; } + extension(EntityVariables vars) + { + public TradeSkillState TradeSkillState + { + get => vars.GetAsOrDefault(TradeSkillEntityVariableTypes.TradeSkillState, () => new TradeSkillState()); + set => vars[TradeSkillEntityVariableTypes.TradeSkillState] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.UnitTests/Combat/ActiveEffectExtensionTests.cs b/src/OpenRpg.UnitTests/Combat/ActiveEffectExtensionTests.cs index 18c03356..7062e52f 100644 --- a/src/OpenRpg.UnitTests/Combat/ActiveEffectExtensionTests.cs +++ b/src/OpenRpg.UnitTests/Combat/ActiveEffectExtensionTests.cs @@ -16,7 +16,7 @@ public void should_correctly_indicate_if_effect_is_passive(int effectFrequency, var dummyTimedEffect = new TimedStaticEffect() { Frequency = effectFrequency }; var dummyActiveEffect = new ActiveEffect(dummyTimedEffect); - Assert.Equal(shouldBePassive, dummyActiveEffect.IsPassiveEffect()); + Assert.Equal(shouldBePassive, dummyActiveEffect.IsPassiveEffect); } [Theory] @@ -28,7 +28,7 @@ public void should_correctly_get_stacked_potency(int potency, int stacks, int ex { var dummyTimedEffect = new TimedStaticEffect() { Potency = potency, MaxStack = stacks }; var dummyActiveEffect = new ActiveEffect(dummyTimedEffect) { Stacks = stacks }; - var actualPotency = dummyActiveEffect.GetStackedPotency(); + var actualPotency = dummyActiveEffect.StackedPotency; Assert.Equal(expectedPotency, actualPotency); } @@ -41,7 +41,7 @@ public void should_correctly_get_total_ticks(float frequency, float activeTime, { var dummyTimedEffect = new TimedStaticEffect() { Frequency = frequency}; var dummyActiveEffect = new ActiveEffect(dummyTimedEffect) { ActiveTime = activeTime }; - var actualTicks = dummyActiveEffect.TicksSoFar(); + var actualTicks = dummyActiveEffect.TicksSoFar; Assert.Equal(expectedTicks, actualTicks); } } \ No newline at end of file diff --git a/src/OpenRpg.UnitTests/TradeSkills/TradeSkillsEntityVariableExtensionTests.cs b/src/OpenRpg.UnitTests/TradeSkills/TradeSkillsEntityVariableExtensionTests.cs index 3221313d..beb5402a 100644 --- a/src/OpenRpg.UnitTests/TradeSkills/TradeSkillsEntityVariableExtensionTests.cs +++ b/src/OpenRpg.UnitTests/TradeSkills/TradeSkillsEntityVariableExtensionTests.cs @@ -14,8 +14,8 @@ public void should_correctly_handle_trade_skill_state_on_entity() Assert.False(entityVars.HasTradeSkillState()); var tradeSkillState = new TradeSkillState(); - entityVars.TradeSkillState(tradeSkillState); + entityVars.TradeSkillState = tradeSkillState; Assert.True(entityVars.HasTradeSkillState()); - Assert.Equal(entityVars.TradeSkillState(), tradeSkillState); + Assert.Equal(entityVars.TradeSkillState, tradeSkillState); } } \ No newline at end of file From cc089cf437f522ed3a759500b2a8438362dea259 Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 9 Dec 2025 12:51:15 +0000 Subject: [PATCH 008/153] Added more properties from extensions --- ...ombatAbilityTemplateVariablesExtensions.cs | 46 +++++++++++++------ .../CombatEntityVariableExtensions.cs | 16 ++++--- .../CombatTemplateVariableExtensions.cs | 16 +++++-- .../Combat/FantasyAttackGenerator.cs | 2 +- .../Combat/ShipAttackGenerator.cs | 2 +- .../Effects/CharacterEffectProcessor.cs | 2 +- .../DefaultCharacterRequirementChecker.cs | 2 +- .../CombatEntityVariableExtensionTests.cs | 4 +- 8 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/OpenRpg.Combat/Extensions/CombatAbilityTemplateVariablesExtensions.cs b/src/OpenRpg.Combat/Extensions/CombatAbilityTemplateVariablesExtensions.cs index 3f87d9fa..30652c86 100644 --- a/src/OpenRpg.Combat/Extensions/CombatAbilityTemplateVariablesExtensions.cs +++ b/src/OpenRpg.Combat/Extensions/CombatAbilityTemplateVariablesExtensions.cs @@ -7,19 +7,37 @@ namespace OpenRpg.Combat.Extensions { public static class CombatAbilityTemplateVariablesExtensions { - public static float Cooldown(this AbilityTemplateVariables vars) => vars.GetFloatOrDefault(CombatAbilityTemplateVariableTypes.Cooldown, 0); - public static void Cooldown(this AbilityTemplateVariables vars, float value) => vars[CombatAbilityTemplateVariableTypes.Cooldown] = value; - - public static Damage Damage(this AbilityTemplateVariables vars) => vars.GetAsOrDefault(CombatAbilityTemplateVariableTypes.Damage, () => new Damage(0, 0)); - public static void Damage(this AbilityTemplateVariables vars, Damage damage) => vars[CombatAbilityTemplateVariableTypes.Damage] = damage; - - public static float Range(this AbilityTemplateVariables vars) => vars.GetFloatOrDefault(CombatAbilityTemplateVariableTypes.Range, 0); - public static void Range(this AbilityTemplateVariables vars, float value) => vars[CombatAbilityTemplateVariableTypes.Range] = value; - - public static float AttackSize(this AbilityTemplateVariables vars) => vars.GetFloatOrDefault(CombatAbilityTemplateVariableTypes.AttackSize, 0); - public static void AttackSize(this AbilityTemplateVariables vars, float value) => vars[CombatAbilityTemplateVariableTypes.AttackSize] = value; - - public static int TargetType(this AbilityTemplateVariables vars) => vars.GetIntOrDefault(CombatAbilityTemplateVariableTypes.TargetType, 0); - public static void TargetType(this AbilityTemplateVariables vars, int value) => vars[CombatAbilityTemplateVariableTypes.TargetType] = value; + extension(AbilityTemplateVariables vars) + { + public float Cooldown + { + get => vars.GetFloatOrDefault(CombatAbilityTemplateVariableTypes.Cooldown, 0); + set => vars[CombatAbilityTemplateVariableTypes.Cooldown] = value; + } + + public Damage Damage + { + get => vars.GetAsOrDefault(CombatAbilityTemplateVariableTypes.Damage, () => new Damage(0, 0)); + set => vars[CombatAbilityTemplateVariableTypes.Damage] = value; + } + + public float Range + { + get => vars.GetFloatOrDefault(CombatAbilityTemplateVariableTypes.Range, 0); + set => vars[CombatAbilityTemplateVariableTypes.Range] = value; + } + + public float AttackSize + { + get => vars.GetFloatOrDefault(CombatAbilityTemplateVariableTypes.AttackSize, 0); + set => vars[CombatAbilityTemplateVariableTypes.AttackSize] = value; + } + + public int TargetType + { + get => vars.GetIntOrDefault(CombatAbilityTemplateVariableTypes.TargetType, 0); + set => vars[CombatAbilityTemplateVariableTypes.TargetType] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Combat/Extensions/CombatEntityVariableExtensions.cs b/src/OpenRpg.Combat/Extensions/CombatEntityVariableExtensions.cs index 98771a1f..3ffc095d 100644 --- a/src/OpenRpg.Combat/Extensions/CombatEntityVariableExtensions.cs +++ b/src/OpenRpg.Combat/Extensions/CombatEntityVariableExtensions.cs @@ -1,7 +1,6 @@ -using System.Collections.Generic; -using OpenRpg.Combat.Abilities; using OpenRpg.Combat.Effects; using OpenRpg.Combat.Types; +using OpenRpg.Core.Extensions; using OpenRpg.Entities.Entity.Variables; namespace OpenRpg.Combat.Extensions @@ -13,11 +12,14 @@ public static class CombatEntityVariableExtensions { public static bool HasActiveEffects(this EntityVariables vars) { return vars.ContainsKey(CombatEntityVariableTypes.ActiveEffects); } - - public static IActiveEffects ActiveEffects(this EntityVariables vars) - { return vars[CombatEntityVariableTypes.ActiveEffects] as IActiveEffects; } - public static void ActiveEffects(this EntityVariables vars, IActiveEffects activeEffects) - { vars[CombatEntityVariableTypes.ActiveEffects] = activeEffects; } + extension(EntityVariables vars) + { + public IActiveEffects ActiveEffects + { + get => vars.GetAsOrDefault(CombatEntityVariableTypes.ActiveEffects, () => new DefaultActiveEffects()); + set => vars[CombatEntityVariableTypes.ActiveEffects] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Combat/Extensions/CombatTemplateVariableExtensions.cs b/src/OpenRpg.Combat/Extensions/CombatTemplateVariableExtensions.cs index f2cd4f75..8191dcba 100644 --- a/src/OpenRpg.Combat/Extensions/CombatTemplateVariableExtensions.cs +++ b/src/OpenRpg.Combat/Extensions/CombatTemplateVariableExtensions.cs @@ -11,11 +11,17 @@ public static class CombatTemplateVariableExtensions { public static bool HasAbilities(this ITemplateVariables vars) => vars.ContainsKey(CombatTemplateVariableTypes.Abilities); + + extension(ITemplateVariables vars) + { + public IReadOnlyCollection Abilities + { + get => vars.GetAsOrDefault(CombatTemplateVariableTypes.Abilities, Array.Empty); + set => vars[CombatTemplateVariableTypes.Abilities] = value; + + } + } - public static IReadOnlyCollection Abilities(this ITemplateVariables vars) => - vars.GetAsOrDefault(CombatTemplateVariableTypes.Abilities, Array.Empty); - - public static void Abilities(this ITemplateVariables vars, IReadOnlyCollection abilities) => - vars[CombatTemplateVariableTypes.Abilities] = abilities; + } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Combat/FantasyAttackGenerator.cs b/src/OpenRpg.Genres.Fantasy/Combat/FantasyAttackGenerator.cs index f5e16a7b..a0dc0221 100644 --- a/src/OpenRpg.Genres.Fantasy/Combat/FantasyAttackGenerator.cs +++ b/src/OpenRpg.Genres.Fantasy/Combat/FantasyAttackGenerator.cs @@ -61,7 +61,7 @@ public virtual Attack GenerateAttack(EntityStatsVariables stats) public virtual Attack GenerateAttack(Ability ability, EntityStatsVariables stats) { - var baseDamage = ability.Template.Variables.Damage(); + var baseDamage = ability.Template.Variables.Damage; return GenerateAttack(baseDamage, stats); } diff --git a/src/OpenRpg.Genres.Scifi/Combat/ShipAttackGenerator.cs b/src/OpenRpg.Genres.Scifi/Combat/ShipAttackGenerator.cs index ffefb1b1..045d1105 100644 --- a/src/OpenRpg.Genres.Scifi/Combat/ShipAttackGenerator.cs +++ b/src/OpenRpg.Genres.Scifi/Combat/ShipAttackGenerator.cs @@ -22,7 +22,7 @@ public Attack GenerateAttack(ShipStatsVariables stats) public Attack GenerateAttack(Ability ability, ShipStatsVariables stats) { - var baseDamage = ability.Template.Variables.Damage(); + var baseDamage = ability.Template.Variables.Damage; return GenerateAttack(baseDamage, stats); } diff --git a/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs b/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs index 3c5f900a..13635cfe 100644 --- a/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs +++ b/src/OpenRpg.Genres/Effects/CharacterEffectProcessor.cs @@ -60,7 +60,7 @@ public override ComputedEffects ComputeEffects(Character entity) if (entity.Variables.HasActiveEffects()) { - var activeEffects = entity.Variables.ActiveEffects().ActiveEffects + var activeEffects = entity.Variables.ActiveEffects.ActiveEffects .Where(x => x.IsPassiveEffect) .Select(x => x.ToEffect()); diff --git a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs index b2218d96..2153703d 100644 --- a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs +++ b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs @@ -95,7 +95,7 @@ public virtual bool IsRequirementMet(Character character, Requirement requiremen if (requirement.RequirementType == GenreRequirementTypes.ActiveEffectRequirement) { if(!character.Variables.HasActiveEffects()) { return false; } - return character.Variables.ActiveEffects().HasEffect(requirement.Association.AssociatedId); + return character.Variables.ActiveEffects.HasEffect(requirement.Association.AssociatedId); } return true; diff --git a/src/OpenRpg.UnitTests/Combat/CombatEntityVariableExtensionTests.cs b/src/OpenRpg.UnitTests/Combat/CombatEntityVariableExtensionTests.cs index c40e4dea..e5374182 100644 --- a/src/OpenRpg.UnitTests/Combat/CombatEntityVariableExtensionTests.cs +++ b/src/OpenRpg.UnitTests/Combat/CombatEntityVariableExtensionTests.cs @@ -14,8 +14,8 @@ public void should_correctly_handle_activeeffects_on_entity() Assert.False(entityVars.HasActiveEffects()); var dummyActiveEffects = new DefaultActiveEffects(); - entityVars.ActiveEffects(dummyActiveEffects); + entityVars.ActiveEffects = dummyActiveEffects; Assert.True(entityVars.HasActiveEffects()); - Assert.Equal(entityVars.ActiveEffects(), dummyActiveEffects); + Assert.Equal(entityVars.ActiveEffects, dummyActiveEffects); } } \ No newline at end of file From c3d7a5d098ce151347a260dc8c1b273ff2e8d19e Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 9 Dec 2025 14:14:00 +0000 Subject: [PATCH 009/153] Updated more extensions to properties --- .../Components/Items/ItemDetails.razor | 4 +- .../Pages/Combat/Buffs.razor | 10 +- .../Pages/Curves/AdvancedEffects.razor | 2 +- .../TradeSkills/CraftingTradeSkills.razor | 6 +- .../TradeSkills/GatheringTradeSkills.razor | 6 +- .../Extensions/EffectExtensions.cs | 24 ++-- .../EntityStatVariableExtensions.cs | 1 - .../EntityStateVariableExtensions.cs | 1 - .../Extensions/EquipmentExtensions.cs | 93 ++++++++++---- .../Extensions/TradeSkillStateExtensions.cs | 38 ++++-- .../Extensions/EquipmentExtensions.cs | 19 ++- .../ScifiCombatReferencesExtensions.cs | 51 ++++---- .../Extensions/ShipEquipmentExtensions.cs | 115 +++++++++++++----- .../Extensions/ShipStatVariablesExtensions.cs | 108 +++++++++++----- .../ShipStateVariablesExtensions.cs | 57 +++++---- .../Extensions/ShipVariableExtensions.cs | 28 +++-- .../Extensions/StatExtensions.cs | 83 +++++++++---- 17 files changed, 440 insertions(+), 206 deletions(-) diff --git a/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor b/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor index c222c91b..cc9cca4c 100644 --- a/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor +++ b/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor @@ -97,11 +97,11 @@ } public float TotalDamage => Effects.GetStaticEffects() - .Where(x => x.IsDamagingEffect() || x.EffectType == FantasyEffectTypes.DamageBonusAmount) + .Where(x => x.IsDamagingEffect || x.EffectType == FantasyEffectTypes.DamageBonusAmount) .Sum(x => x.Potency); public float TotalDefense => Effects.GetStaticEffects() - .Where(x => x.IsDefensiveEffect() || x.EffectType == FantasyEffectTypes.DefenseBonusAmount) + .Where(x => x.IsDefensiveEffect || x.EffectType == FantasyEffectTypes.DefenseBonusAmount) .Sum(x => x.Potency); diff --git a/src/OpenRpg.Demos.Web/Pages/Combat/Buffs.razor b/src/OpenRpg.Demos.Web/Pages/Combat/Buffs.razor index 48804241..fb2ae701 100644 --- a/src/OpenRpg.Demos.Web/Pages/Combat/Buffs.razor +++ b/src/OpenRpg.Demos.Web/Pages/Combat/Buffs.razor @@ -206,8 +206,8 @@ public void OnEffectTriggered(ActiveEffect activeEffect) { - var effectTypeText = activeEffect.IsBeneficialEffect() ? "healing" : "damage"; - var logEntry = new LogEntry(activeEffect.IsBeneficialEffect(), activeEffect.IsPassiveEffect, + var effectTypeText = activeEffect.IsBeneficialEffect ? "healing" : "damage"; + var logEntry = new LogEntry(activeEffect.IsBeneficialEffect, activeEffect.IsPassiveEffect, $"Triggered {activeEffect.StaticEffect.NameLocaleId} with {activeEffect.StackedPotency} {effectTypeText}"); LogOutput.Add(logEntry); @@ -215,7 +215,7 @@ public void OnEffectExpired(ActiveEffect activeEffect) { - var logEntry = new LogEntry(activeEffect.IsBeneficialEffect(), activeEffect.IsPassiveEffect, + var logEntry = new LogEntry(activeEffect.IsBeneficialEffect, activeEffect.IsPassiveEffect, $"Expired {activeEffect.StaticEffect.NameLocaleId}"); LogOutput.Add(logEntry); @@ -223,7 +223,7 @@ public void OnEffectAdded(ActiveEffect activeEffect) { - var logEntry = new LogEntry(activeEffect.IsBeneficialEffect(), activeEffect.IsPassiveEffect, + var logEntry = new LogEntry(activeEffect.IsBeneficialEffect, activeEffect.IsPassiveEffect, $"Added {activeEffect.StaticEffect.NameLocaleId}"); LogOutput.Add(logEntry); @@ -237,7 +237,7 @@ if (alreadyContainsEffect) { - var logEntry = new LogEntry(effectToApply.IsBeneficialEffect(), effectToApply.IsPassiveEffect, + var logEntry = new LogEntry(effectToApply.IsBeneficialEffect, effectToApply.IsPassiveEffect, $"Stacked/Reset {effectToApply.NameLocaleId}"); LogOutput.Add(logEntry); diff --git a/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor b/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor index 9a25bc3a..e90b2247 100644 --- a/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor +++ b/src/OpenRpg.Demos.Web/Pages/Curves/AdvancedEffects.razor @@ -283,7 +283,7 @@ }; var equipment = new Equipment(); - equipment.MainHandSlot(new ItemData() { TemplateId = pretendWeapon.Id }); + equipment.MainHandSlot = new ItemData() { TemplateId = pretendWeapon.Id }; ExampleCharacter.Variables.Race = new RaceData() { TemplateId = pretendHumanRace.Id }; ExampleCharacter.Variables.Class = new ClassData() { TemplateId = pretendFighterClassTemplate.Id }; diff --git a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor index 9ffa4b66..7d4b3b3f 100644 --- a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor +++ b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor @@ -123,7 +123,7 @@
- +
@if (IsCrafting) @@ -181,7 +181,7 @@ GiveCopperOre(10); DummyCharacter.Variables.TradeSkillState = new TradeSkillState(); - TradeSkillState.Smithing(1); + TradeSkillState.Smithing = 1; base.OnInitialized(); } @@ -226,7 +226,7 @@ CurrentTemplate.CraftFrom(CraftingInventory, TemplateAccessor); ActionBarRef?.Reset(); - var currentSkill = TradeSkillState.Smithing(); + var currentSkill = TradeSkillState.Smithing; var tradeSkillPoints = TradeSkillCalculator.CalculateSkillUpPointsFor(currentSkill, CurrentTemplate.SkillDifficulty); TradeSkillState.AddSmithing(tradeSkillPoints); diff --git a/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor b/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor index c1319011..28db1213 100644 --- a/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor +++ b/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor @@ -115,7 +115,7 @@ > To make it quicker to test we have disabled the gathering time so you gather immediately unlike previous example
- +
@@ -208,7 +208,7 @@ IronOreGatheringTemplate = TemplateAccessor.GetItemGatheringTemplate(ItemGatheringTemplateLookups.IronOre); DummyCharacter.Variables.TradeSkillState = new TradeSkillState(); - TradeSkillState.Mining(1); + TradeSkillState.Mining = 1; base.OnInitialized(); } @@ -228,7 +228,7 @@ CurrentTemplate.GatherInto(Example2Inventory, TemplateAccessor); Example2InventoryRef.Refresh(); - var currentMiningSkill = TradeSkillState.Mining(); + var currentMiningSkill = TradeSkillState.Mining; var tradeSkillPoints = TradeSkillCalculator.CalculateSkillUpPointsFor(currentMiningSkill, CurrentTemplate.SkillDifficulty); TradeSkillState.AddMining(tradeSkillPoints); diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/EffectExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/EffectExtensions.cs index 783eb76d..7c5d170b 100644 --- a/src/OpenRpg.Genres.Fantasy/Extensions/EffectExtensions.cs +++ b/src/OpenRpg.Genres.Fantasy/Extensions/EffectExtensions.cs @@ -1,7 +1,6 @@ using System.Linq; using OpenRpg.Combat.Effects; using OpenRpg.Core.Effects; -using OpenRpg.Entities.Effects; using OpenRpg.Genres.Fantasy.Effects; using OpenRpg.Genres.Fantasy.Types; @@ -60,20 +59,25 @@ public static int GetBonusDefenseEffectTypeFrom(int damageType) return FantasyDamageTypes.UnknownDamage; } - public static bool IsDamagingEffect(this StaticEffect staticEffect) - { return EffectTypeGroups.DamageEffectTypes.Contains(staticEffect.EffectType); } + extension(StaticEffect effect) + { + public bool IsDamagingEffect => EffectTypeGroups.DamageEffectTypes.Contains(effect.EffectType); + public bool IsDefensiveEffect => EffectTypeGroups.DefenseEffectTypes.Contains(effect.EffectType); + public bool IsBeneficialEffect => IsBeneficialEffect(effect); + } - public static bool IsDefensiveEffect(this StaticEffect staticEffect) - { return EffectTypeGroups.DefenseEffectTypes.Contains(staticEffect.EffectType); } + extension(ActiveEffect effect) + { + public bool IsDamagingEffect => effect.StaticEffect.IsDamagingEffect; + public bool IsDefensiveEffect => effect.StaticEffect.IsDefensiveEffect; + public bool IsBeneficialEffect => effect.StaticEffect.IsBeneficialEffect; + } - public static bool IsBeneficialEffect(this ActiveEffect effect) - { return IsBeneficialEffect(effect.StaticEffect); } - - public static bool IsBeneficialEffect(this StaticEffect staticEffect) + public static bool IsBeneficialEffect(StaticEffect staticEffect) { if(staticEffect.EffectType != FantasyEffectTypes.LightBonusAmount) { - if (staticEffect.IsDamagingEffect()) + if (staticEffect.IsDamagingEffect) { return false; } } diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/EntityStatVariableExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/EntityStatVariableExtensions.cs index e9b3f424..06628eaf 100644 --- a/src/OpenRpg.Genres.Fantasy/Extensions/EntityStatVariableExtensions.cs +++ b/src/OpenRpg.Genres.Fantasy/Extensions/EntityStatVariableExtensions.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using OpenRpg.Entities.Stats.Variables; using OpenRpg.Genres.Fantasy.Types; diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/EntityStateVariableExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/EntityStateVariableExtensions.cs index ca802979..66fdfe11 100644 --- a/src/OpenRpg.Genres.Fantasy/Extensions/EntityStateVariableExtensions.cs +++ b/src/OpenRpg.Genres.Fantasy/Extensions/EntityStateVariableExtensions.cs @@ -1,5 +1,4 @@ using OpenRpg.Core.Extensions; -using OpenRpg.Entities.Entity; using OpenRpg.Entities.State.Variables; using OpenRpg.Genres.Fantasy.Types; diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/EquipmentExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/EquipmentExtensions.cs index 115d8fdf..92ec9037 100644 --- a/src/OpenRpg.Genres.Fantasy/Extensions/EquipmentExtensions.cs +++ b/src/OpenRpg.Genres.Fantasy/Extensions/EquipmentExtensions.cs @@ -1,35 +1,78 @@ using OpenRpg.Genres.Fantasy.Types; -using OpenRpg.Items; using OpenRpg.Items.Equippables; -using OpenRpg.Items.Equippables.Slots; using OpenRpg.Items.Templates; namespace OpenRpg.Genres.Fantasy.Extensions { public static class EquipmentExtensions { - public static ItemData BackSlot(this Equipment equipment) => equipment.Slots.Get(FantasyEquipmentSlotTypes.BackSlot); - public static ItemData FootSlot(this Equipment equipment) => equipment.Slots.Get(FantasyEquipmentSlotTypes.FootSlot); - public static ItemData HeadSlot(this Equipment equipment) => equipment.Slots.Get(FantasyEquipmentSlotTypes.HeadSlot); - public static ItemData NeckSlot(this Equipment equipment) => equipment.Slots.Get(FantasyEquipmentSlotTypes.NeckSlot); - public static ItemData Ring1Slot(this Equipment equipment) => equipment.Slots.Get(FantasyEquipmentSlotTypes.Ring1Slot); - public static ItemData Ring2Slot(this Equipment equipment) => equipment.Slots.Get(FantasyEquipmentSlotTypes.Ring2Slot); - public static ItemData WristSlot(this Equipment equipment) => equipment.Slots.Get(FantasyEquipmentSlotTypes.WristSlot); - public static ItemData OffHandSlot(this Equipment equipment) => equipment.Slots.Get(FantasyEquipmentSlotTypes.OffHandSlot); - public static ItemData MainHandSlot(this Equipment equipment) => equipment.Slots.Get(FantasyEquipmentSlotTypes.MainHandSlot); - public static ItemData LowerBodySlot(this Equipment equipment) => equipment.Slots.Get(FantasyEquipmentSlotTypes.LowerBodySlot); - public static ItemData UpperBodySlot(this Equipment equipment) => equipment.Slots.Get(FantasyEquipmentSlotTypes.UpperBodySlot); - - public static void BackSlot(this Equipment equipment, ItemData itemData) => equipment.Slots[FantasyEquipmentSlotTypes.BackSlot] = itemData; - public static void FootSlot(this Equipment equipment, ItemData itemData) => equipment.Slots[FantasyEquipmentSlotTypes.FootSlot] = itemData; - public static void HeadSlot(this Equipment equipment, ItemData itemData) => equipment.Slots[FantasyEquipmentSlotTypes.HeadSlot] = itemData; - public static void NeckSlot(this Equipment equipment, ItemData itemData) => equipment.Slots[FantasyEquipmentSlotTypes.NeckSlot] = itemData; - public static void Ring1Slot(this Equipment equipment, ItemData itemData) => equipment.Slots[FantasyEquipmentSlotTypes.Ring1Slot] = itemData; - public static void Ring2Slot(this Equipment equipment, ItemData itemData) => equipment.Slots[FantasyEquipmentSlotTypes.Ring2Slot] = itemData; - public static void WristSlot(this Equipment equipment, ItemData itemData) => equipment.Slots[FantasyEquipmentSlotTypes.WristSlot] = itemData; - public static void OffHandSlot(this Equipment equipment, ItemData itemData) => equipment.Slots[FantasyEquipmentSlotTypes.OffHandSlot] = itemData; - public static void MainHandSlot(this Equipment equipment, ItemData itemData) => equipment.Slots[FantasyEquipmentSlotTypes.MainHandSlot] = itemData; - public static void LowerBodySlot(this Equipment equipment, ItemData itemData) => equipment.Slots[FantasyEquipmentSlotTypes.LowerBodySlot] = itemData; - public static void UpperBodySlot(this Equipment equipment, ItemData itemData) => equipment.Slots[FantasyEquipmentSlotTypes.UpperBodySlot] = itemData; + extension(Equipment equipment) + { + public ItemData BackSlot + { + get => equipment.Slots.Get(FantasyEquipmentSlotTypes.BackSlot); + set => equipment.Slots[FantasyEquipmentSlotTypes.BackSlot] = value; + } + + public ItemData FootSlot + { + get => equipment.Slots.Get(FantasyEquipmentSlotTypes.FootSlot); + set => equipment.Slots[FantasyEquipmentSlotTypes.FootSlot] = value; + } + + public ItemData HeadSlot + { + get => equipment.Slots.Get(FantasyEquipmentSlotTypes.HeadSlot); + set => equipment.Slots[FantasyEquipmentSlotTypes.HeadSlot] = value; + } + + public ItemData NeckSlot + { + get => equipment.Slots.Get(FantasyEquipmentSlotTypes.NeckSlot); + set => equipment.Slots[FantasyEquipmentSlotTypes.NeckSlot] = value; + } + + public ItemData Ring1Slot + { + get => equipment.Slots.Get(FantasyEquipmentSlotTypes.Ring1Slot); + set => equipment.Slots[FantasyEquipmentSlotTypes.Ring1Slot] = value; + } + + public ItemData Ring2Slot + { + get => equipment.Slots.Get(FantasyEquipmentSlotTypes.Ring2Slot); + set => equipment.Slots[FantasyEquipmentSlotTypes.Ring2Slot] = value; + } + + public ItemData WristSlot + { + get => equipment.Slots.Get(FantasyEquipmentSlotTypes.WristSlot); + set => equipment.Slots[FantasyEquipmentSlotTypes.WristSlot] = value; + } + + public ItemData OffHandSlot + { + get => equipment.Slots.Get(FantasyEquipmentSlotTypes.OffHandSlot); + set => equipment.Slots[FantasyEquipmentSlotTypes.OffHandSlot] = value; + } + + public ItemData MainHandSlot + { + get => equipment.Slots.Get(FantasyEquipmentSlotTypes.MainHandSlot); + set => equipment.Slots[FantasyEquipmentSlotTypes.MainHandSlot] = value; + } + + public ItemData LowerBodySlot + { + get => equipment.Slots.Get(FantasyEquipmentSlotTypes.LowerBodySlot); + set => equipment.Slots[FantasyEquipmentSlotTypes.LowerBodySlot] = value; + } + + public ItemData UpperBodySlot + { + get => equipment.Slots.Get(FantasyEquipmentSlotTypes.UpperBodySlot); + set => equipment.Slots[FantasyEquipmentSlotTypes.UpperBodySlot] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/TradeSkillStateExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/TradeSkillStateExtensions.cs index 6a1d9d59..c8a6d1b6 100644 --- a/src/OpenRpg.Genres.Fantasy/Extensions/TradeSkillStateExtensions.cs +++ b/src/OpenRpg.Genres.Fantasy/Extensions/TradeSkillStateExtensions.cs @@ -6,20 +6,36 @@ namespace OpenRpg.Genres.Fantasy.Extensions { public static class TradeSkillStateExtensions { - public static int Logging(this TradeSkillState state) => state.Get(FantasyGatheringTradeSkillTypes.Logging); - public static void Logging(this TradeSkillState state, int value) => state[FantasyGatheringTradeSkillTypes.Logging] = value; + extension(TradeSkillState state) + { + public int Logging + { + get => state.Get(FantasyGatheringTradeSkillTypes.Logging); + set => state[FantasyGatheringTradeSkillTypes.Logging] = value; + } + + public int Mining + { + get => state.Get(FantasyGatheringTradeSkillTypes.Mining); + set => state[FantasyGatheringTradeSkillTypes.Mining] = value; + } + + public int Smelting + { + get => state.Get(FantasyCraftingTradeSkillTypes.Smelting); + set => state[FantasyCraftingTradeSkillTypes.Smelting] = value; + } + + public int Smithing + { + get => state.Get(FantasyCraftingTradeSkillTypes.Smithing); + set => state[FantasyCraftingTradeSkillTypes.Smithing] = value; + } + } + public static void AddLogging(this TradeSkillState state, int addition) => state.AddValue(FantasyGatheringTradeSkillTypes.Logging, addition); - - public static int Mining(this TradeSkillState state) => state.Get(FantasyGatheringTradeSkillTypes.Mining); - public static void Mining(this TradeSkillState state, int value) => state[FantasyGatheringTradeSkillTypes.Mining] = value; public static void AddMining(this TradeSkillState state, int addition) => state.AddValue(FantasyGatheringTradeSkillTypes.Mining, addition); - - public static int Smelting(this TradeSkillState state) => state.Get(FantasyCraftingTradeSkillTypes.Smelting); - public static void Smelting(this TradeSkillState state, int value) => state[FantasyCraftingTradeSkillTypes.Smelting] = value; public static void AddSmelting(this TradeSkillState state, int addition) => state.AddValue(FantasyCraftingTradeSkillTypes.Smelting, addition); - - public static int Smithing(this TradeSkillState state) => state.Get(FantasyCraftingTradeSkillTypes.Smithing); - public static void Smithing(this TradeSkillState state, int value) => state[FantasyCraftingTradeSkillTypes.Smithing] = value; public static void AddSmithing(this TradeSkillState state, int addition) => state.AddValue(FantasyCraftingTradeSkillTypes.Smithing, addition); } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Scifi/Extensions/EquipmentExtensions.cs b/src/OpenRpg.Genres.Scifi/Extensions/EquipmentExtensions.cs index cbbeb347..24e7800d 100644 --- a/src/OpenRpg.Genres.Scifi/Extensions/EquipmentExtensions.cs +++ b/src/OpenRpg.Genres.Scifi/Extensions/EquipmentExtensions.cs @@ -6,10 +6,19 @@ namespace OpenRpg.Genres.Scifi.Extensions { public static class EquipmentExtensions { - public static ItemData WeaponSlot(this Equipment equipment) => equipment.Slots.Get(ScifiEntityEquipmentSlotTypes.WeaponSlot); - public static ItemData ArmourSlot(this Equipment equipment) => equipment.Slots.Get(ScifiEntityEquipmentSlotTypes.ArmourSlot); - - public static void WeaponSlot(this Equipment equipment, ItemData itemData) => equipment.Slots[ScifiEntityEquipmentSlotTypes.WeaponSlot] = itemData; - public static void ArmourSlot(this Equipment equipment, ItemData itemData) => equipment.Slots[ScifiEntityEquipmentSlotTypes.ArmourSlot] = itemData; + extension(Equipment equipment) + { + public ItemData WeaponSlot + { + get => equipment.Slots.Get(ScifiEntityEquipmentSlotTypes.WeaponSlot); + set => equipment.Slots[ScifiEntityEquipmentSlotTypes.WeaponSlot] = value; + } + + public ItemData ArmourSlot + { + get => equipment.Slots.Get(ScifiEntityEquipmentSlotTypes.ArmourSlot); + set => equipment.Slots[ScifiEntityEquipmentSlotTypes.ArmourSlot] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Scifi/Extensions/ScifiCombatReferencesExtensions.cs b/src/OpenRpg.Genres.Scifi/Extensions/ScifiCombatReferencesExtensions.cs index 19e449a2..56d85b85 100644 --- a/src/OpenRpg.Genres.Scifi/Extensions/ScifiCombatReferencesExtensions.cs +++ b/src/OpenRpg.Genres.Scifi/Extensions/ScifiCombatReferencesExtensions.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using OpenRpg.Entities.Stats; -using OpenRpg.Entities.Stats.Variables; using OpenRpg.Genres.Scifi.Types; using OpenRpg.Genres.Scifi.Variables; @@ -12,11 +11,11 @@ public static ICollection GetDamageReferences(this ShipStatsVaria { return new[] { - new StatReference(ScifiDamageTypes.Ballistic, stats.BallisticDamage()), - new StatReference(ScifiDamageTypes.Explosive, stats.ExplosiveDamage()), - new StatReference(ScifiDamageTypes.Ion, stats.IonDamage()), - new StatReference(ScifiDamageTypes.Laser, stats.LaserDamage()), - new StatReference(ScifiDamageTypes.Physical, stats.PhysicalDamage()), + new StatReference(ScifiDamageTypes.Ballistic, stats.BallisticDamage), + new StatReference(ScifiDamageTypes.Explosive, stats.ExplosiveDamage), + new StatReference(ScifiDamageTypes.Ion, stats.IonDamage), + new StatReference(ScifiDamageTypes.Laser, stats.LaserDamage), + new StatReference(ScifiDamageTypes.Physical, stats.PhysicalDamage), }; } @@ -24,41 +23,41 @@ public static ICollection GetDefenseReferences(this ShipStatsVari { return new[] { - new StatReference(ScifiDamageTypes.Ballistic, stats.BallisticDefense()), - new StatReference(ScifiDamageTypes.Explosive, stats.ExplosiveDefense()), - new StatReference(ScifiDamageTypes.Ion, stats.IonDefense()), - new StatReference(ScifiDamageTypes.Laser, stats.LaserDefense()), - new StatReference(ScifiDamageTypes.Physical, stats.PhysicalDefense()), + new StatReference(ScifiDamageTypes.Ballistic, stats.BallisticDefense), + new StatReference(ScifiDamageTypes.Explosive, stats.ExplosiveDefense), + new StatReference(ScifiDamageTypes.Ion, stats.IonDefense), + new StatReference(ScifiDamageTypes.Laser, stats.LaserDefense), + new StatReference(ScifiDamageTypes.Physical, stats.PhysicalDefense), }; } public static float GetDefenseFor(this ShipStatsVariables stats, int effectType) { - if (effectType == ScifiEffectTypes.BallisticDamageAmount) { return stats.BallisticDefense(); } - if (effectType == ScifiEffectTypes.ExplosiveDamageAmount) { return stats.ExplosiveDefense(); } - if (effectType == ScifiEffectTypes.IonDamageAmount) { return stats.IonDefense(); } - if (effectType == ScifiEffectTypes.LaserDamageAmount) { return stats.LaserDefense(); } - if (effectType == ScifiEffectTypes.PhysicalDamageAmount) { return stats.PhysicalDefense(); } + if (effectType == ScifiEffectTypes.BallisticDamageAmount) { return stats.BallisticDefense; } + if (effectType == ScifiEffectTypes.ExplosiveDamageAmount) { return stats.ExplosiveDefense; } + if (effectType == ScifiEffectTypes.IonDamageAmount) { return stats.IonDefense; } + if (effectType == ScifiEffectTypes.LaserDamageAmount) { return stats.LaserDefense; } + if (effectType == ScifiEffectTypes.PhysicalDamageAmount) { return stats.PhysicalDefense; } return 0; } public static float GetDefenseFromDamageType(this ShipStatsVariables stats, int damageType) { - if (damageType == ScifiDamageTypes.Ballistic) { return stats.BallisticDamage(); } - if (damageType == ScifiDamageTypes.Explosive) { return stats.ExplosiveDamage(); } - if (damageType == ScifiDamageTypes.Ion) { return stats.IonDamage(); } - if (damageType == ScifiDamageTypes.Laser) { return stats.LaserDamage(); } - if (damageType == ScifiDamageTypes.Physical) { return stats.PhysicalDamage(); } + if (damageType == ScifiDamageTypes.Ballistic) { return stats.BallisticDamage; } + if (damageType == ScifiDamageTypes.Explosive) { return stats.ExplosiveDamage; } + if (damageType == ScifiDamageTypes.Ion) { return stats.IonDamage; } + if (damageType == ScifiDamageTypes.Laser) { return stats.LaserDamage; } + if (damageType == ScifiDamageTypes.Physical) { return stats.PhysicalDamage; } return 0; } public static float GetDamageFor(this ShipStatsVariables stats, int effectType) { - if (effectType == ScifiEffectTypes.BallisticDamageAmount) { return stats.BallisticDamage(); } - if (effectType == ScifiEffectTypes.ExplosiveDamageAmount) { return stats.ExplosiveDamage(); } - if (effectType == ScifiEffectTypes.IonDamageAmount) { return stats.IonDamage(); } - if (effectType == ScifiEffectTypes.LaserDamageAmount) { return stats.LaserDamage(); } - if (effectType == ScifiEffectTypes.PhysicalDamageAmount) { return stats.PhysicalDamage(); } + if (effectType == ScifiEffectTypes.BallisticDamageAmount) { return stats.BallisticDamage; } + if (effectType == ScifiEffectTypes.ExplosiveDamageAmount) { return stats.ExplosiveDamage; } + if (effectType == ScifiEffectTypes.IonDamageAmount) { return stats.IonDamage; } + if (effectType == ScifiEffectTypes.LaserDamageAmount) { return stats.LaserDamage; } + if (effectType == ScifiEffectTypes.PhysicalDamageAmount) { return stats.PhysicalDamage; } return 0; } } diff --git a/src/OpenRpg.Genres.Scifi/Extensions/ShipEquipmentExtensions.cs b/src/OpenRpg.Genres.Scifi/Extensions/ShipEquipmentExtensions.cs index 998ae81c..6204712e 100644 --- a/src/OpenRpg.Genres.Scifi/Extensions/ShipEquipmentExtensions.cs +++ b/src/OpenRpg.Genres.Scifi/Extensions/ShipEquipmentExtensions.cs @@ -6,34 +6,91 @@ namespace OpenRpg.Genres.Scifi.Extensions { public static class ShipEquipmentExtensions { - public static ItemData WingSlot(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.WingsSlot); - public static ItemData EngineSlot(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.EngineSlot); - public static ItemData ShieldSlot(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.ShieldSlot); - public static ItemData HullArmourSlot(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.HullArmourSlot); - public static ItemData MiscSlot1(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.MiscSlot1); - public static ItemData MiscSlot2(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.MiscSlot2); - public static ItemData MiscSlot3(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.MiscSlot3); - public static ItemData MiscSlot4(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.MiscSlot4); - public static ItemData WeaponSlot1(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot1); - public static ItemData WeaponSlot2(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot2); - public static ItemData WeaponSlot3(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot3); - public static ItemData WeaponSlot4(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot4); - public static ItemData WeaponSlot5(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot5); - public static ItemData WeaponSlot6(this ShipEquipment equipment) => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot6); - - public static void WingSlot(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.WingsSlot] = itemData; - public static void EngineSlot(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.EngineSlot] = itemData; - public static void ShieldSlot(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.ShieldSlot] = itemData; - public static void HullArmourSlot(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.HullArmourSlot] = itemData; - public static void MiscSlot1(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.MiscSlot1] = itemData; - public static void MiscSlot2(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.MiscSlot2] = itemData; - public static void MiscSlot3(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.MiscSlot3] = itemData; - public static void MiscSlot4(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.MiscSlot4] = itemData; - public static void WeaponSlot1(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot1] = itemData; - public static void WeaponSlot2(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot2] = itemData; - public static void WeaponSlot3(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot3] = itemData; - public static void WeaponSlot4(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot4] = itemData; - public static void WeaponSlot5(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot5] = itemData; - public static void WeaponSlot6(this ShipEquipment equipment, ItemData itemData) => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot6] = itemData; + extension(ShipEquipment equipment) + { + public ItemData WingsSlot + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.WingsSlot); + set => equipment.Slots[ShipEquipmentSlotTypes.WingsSlot] = value; + } + + public ItemData EngineSlot + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.EngineSlot); + set => equipment.Slots[ShipEquipmentSlotTypes.EngineSlot] = value; + } + + public ItemData ShieldSlot + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.ShieldSlot); + set => equipment.Slots[ShipEquipmentSlotTypes.ShieldSlot] = value; + } + + public ItemData HullArmourSlot + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.HullArmourSlot); + set => equipment.Slots[ShipEquipmentSlotTypes.HullArmourSlot] = value; + } + + public ItemData MiscSlot1 + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.MiscSlot1); + set => equipment.Slots[ShipEquipmentSlotTypes.MiscSlot1] = value; + } + + public ItemData MiscSlot2 + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.MiscSlot2); + set => equipment.Slots[ShipEquipmentSlotTypes.MiscSlot2] = value; + } + + public ItemData MiscSlot3 + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.MiscSlot3); + set => equipment.Slots[ShipEquipmentSlotTypes.MiscSlot3] = value; + } + + public ItemData MiscSlot4 + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.MiscSlot4); + set => equipment.Slots[ShipEquipmentSlotTypes.MiscSlot4] = value; + } + + public ItemData WeaponSlot1 + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot1); + set => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot1] = value; + } + + public ItemData WeaponSlot2 + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot2); + set => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot2] = value; + } + + public ItemData WeaponSlot3 + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot3); + set => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot3] = value; + } + + public ItemData WeaponSlot4 + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot4); + set => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot4] = value; + } + + public ItemData WeaponSlot5 + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot5); + set => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot5] = value; + } + + public ItemData WeaponSlot6 + { + get => equipment.Slots.Get(ShipEquipmentSlotTypes.WeaponSlot6); + set => equipment.Slots[ShipEquipmentSlotTypes.WeaponSlot6] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Scifi/Extensions/ShipStatVariablesExtensions.cs b/src/OpenRpg.Genres.Scifi/Extensions/ShipStatVariablesExtensions.cs index 6542a7b7..c47d0612 100644 --- a/src/OpenRpg.Genres.Scifi/Extensions/ShipStatVariablesExtensions.cs +++ b/src/OpenRpg.Genres.Scifi/Extensions/ShipStatVariablesExtensions.cs @@ -5,33 +5,85 @@ namespace OpenRpg.Genres.Scifi.Extensions { public static class ShipStatVariablesExtensions { - public static float MaxArmour(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.MaxArmour); - public static void MaxArmour(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.MaxArmour] = value; - public static float MaxShield(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.MaxShield); - public static void MaxShield(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.MaxShield] = value; - public static float MaxEnergy(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.MaxEnergy); - public static void MaxEnergy(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.MaxEnergy] = value; - - public static float PhysicalDamage(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.PhysicalDamage); - public static float BallisticDamage(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.BallisticDamage); - public static float ExplosiveDamage(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.ExplosiveDamage); - public static float IonDamage(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.IonDamage); - public static float LaserDamage(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.LaserDamage); - public static void PhysicalDamage(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.PhysicalDamage] = value; - public static void BallisticDamage(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.BallisticDamage] = value; - public static void ExplosiveDamage(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.ExplosiveDamage] = value; - public static void IonDamage(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.IonDamage] = value; - public static void LaserDamage(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.LaserDamage] = value; - - public static float PhysicalDefense(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.PhysicalDefense); - public static float BallisticDefense(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.BallisticDefense); - public static float ExplosiveDefense(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.ExplosiveDefense); - public static float IonDefense(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.IonDefense); - public static float LaserDefense(this ShipStatsVariables stats) => stats.Get(ScifiShipStatsVariableTypes.LaserDefense); - public static void PhysicalDefense(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.PhysicalDefense] = value; - public static void BallisticDefense(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.BallisticDefense] = value; - public static void ExplosiveDefense(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.ExplosiveDefense] = value; - public static void IonDefense(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.IonDefense] = value; - public static void LaserDefense(this ShipStatsVariables stats, float value) => stats[ScifiShipStatsVariableTypes.LaserDefense] = value; + extension(ShipStatsVariables stats) + { + public float MaxArmour + { + get => stats.Get(ScifiShipStatsVariableTypes.MaxArmour); + set => stats[ScifiShipStatsVariableTypes.MaxArmour] = value; + } + + public float MaxShield + { + get => stats.Get(ScifiShipStatsVariableTypes.MaxShield); + set => stats[ScifiShipStatsVariableTypes.MaxShield] = value; + } + + public float MaxEnergy + { + get => stats.Get(ScifiShipStatsVariableTypes.MaxEnergy); + set => stats[ScifiShipStatsVariableTypes.MaxEnergy] = value; + } + + public float PhysicalDamage + { + get => stats.Get(ScifiShipStatsVariableTypes.PhysicalDamage); + set => stats[ScifiShipStatsVariableTypes.PhysicalDamage] = value; + } + + public float BallisticDamage + { + get => stats.Get(ScifiShipStatsVariableTypes.BallisticDamage); + set => stats[ScifiShipStatsVariableTypes.BallisticDamage] = value; + } + + public float ExplosiveDamage + { + get => stats.Get(ScifiShipStatsVariableTypes.ExplosiveDamage); + set => stats[ScifiShipStatsVariableTypes.ExplosiveDamage] = value; + } + + public float IonDamage + { + get => stats.Get(ScifiShipStatsVariableTypes.IonDamage); + set => stats[ScifiShipStatsVariableTypes.IonDamage] = value; + } + + public float LaserDamage + { + get => stats.Get(ScifiShipStatsVariableTypes.LaserDamage); + set => stats[ScifiShipStatsVariableTypes.LaserDamage] = value; + } + + public float PhysicalDefense + { + get => stats.Get(ScifiShipStatsVariableTypes.PhysicalDefense); + set => stats[ScifiShipStatsVariableTypes.PhysicalDefense] = value; + } + + public float BallisticDefense + { + get => stats.Get(ScifiShipStatsVariableTypes.BallisticDefense); + set => stats[ScifiShipStatsVariableTypes.BallisticDefense] = value; + } + + public float ExplosiveDefense + { + get => stats.Get(ScifiShipStatsVariableTypes.ExplosiveDefense); + set => stats[ScifiShipStatsVariableTypes.ExplosiveDefense] = value; + } + + public float IonDefense + { + get => stats.Get(ScifiShipStatsVariableTypes.IonDefense); + set => stats[ScifiShipStatsVariableTypes.IonDefense] = value; + } + + public float LaserDefense + { + get => stats.Get(ScifiShipStatsVariableTypes.LaserDefense); + set => stats[ScifiShipStatsVariableTypes.LaserDefense] = value; + } + } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Scifi/Extensions/ShipStateVariablesExtensions.cs b/src/OpenRpg.Genres.Scifi/Extensions/ShipStateVariablesExtensions.cs index 3f537f28..73855333 100644 --- a/src/OpenRpg.Genres.Scifi/Extensions/ShipStateVariablesExtensions.cs +++ b/src/OpenRpg.Genres.Scifi/Extensions/ShipStateVariablesExtensions.cs @@ -8,27 +8,47 @@ namespace OpenRpg.Genres.Scifi.Extensions { public static class ShipStateVariablesExtensions { - public static int Armour(this ShipStateVariables state) => (int)state.Get(ScifiShipStateVariableTypes.Armour); - public static void Armour(this ShipStateVariables state, int value) => state[ScifiShipStateVariableTypes.Armour] = value; + extension(ShipStateVariables state) + { + public int Armour + { + get => (int)state.Get(ScifiShipStateVariableTypes.Armour); + set => state[ScifiShipStateVariableTypes.Armour] = value; + } + + public int Shield + { + get => (int)state.Get(ScifiShipStateVariableTypes.Shield); + set => state[ScifiShipStateVariableTypes.Shield] = value; + } + + public int Energy + { + get => (int)state.Get(ScifiShipStateVariableTypes.Energy); + set => state[ScifiShipStateVariableTypes.Energy] = value; + } + + public bool IsDead => state.Armour <= 0; + } public static void AddArmour(this ShipStateVariables state, int change, int? max = null) { - var newValue = state.Armour() + change; + var newValue = state.Armour + change; if(newValue <= 0) { newValue = 0; } if(max == null) - { state.Armour(newValue); } + { state.Armour = newValue; } else {state.EnsureArmourInBounds(newValue, max.Value); } } public static void DeductArmour(this ShipStateVariables state, int change, int? max = null) { - var newValue = state.Armour() - change; + var newValue = state.Armour - change; if(newValue <= 0) { newValue = 0; } if(max == null) - { state.Armour(newValue); } + { state.Armour = newValue; } else {state.EnsureArmourInBounds(newValue, max.Value); } } @@ -43,27 +63,24 @@ public static void EnsureArmourInBounds(this ShipStateVariables state, int value { state[ScifiShipStateVariableTypes.Armour] = value; } } - public static int Shield(this ShipStateVariables state) => (int)state.Get(ScifiShipStateVariableTypes.Shield); - public static void Shield(this ShipStateVariables state, int value) => state[ScifiShipStateVariableTypes.Shield] = value; - public static void AddShield(this ShipStateVariables state, int change, int? max = null) { - var newValue = state.Shield() + change; + var newValue = state.Shield + change; if(newValue <= 0) { newValue = 0; } if(max == null) - { state.Shield(newValue); } + { state.Shield = newValue; } else {state.EnsureShieldInBounds(newValue, max.Value); } } public static void DeductShield(this ShipStateVariables state, int change, int? max = null) { - var newValue = state.Shield() - change; + var newValue = state.Shield - change; if(newValue <= 0) { newValue = 0; } if(max == null) - { state.Shield(newValue); } + { state.Shield = newValue; } else {state.EnsureShieldInBounds(newValue, max.Value); } } @@ -78,27 +95,24 @@ public static void EnsureShieldInBounds(this ShipStateVariables state, int value { state[ScifiShipStateVariableTypes.Shield] = value; } } - public static int Energy(this ShipStateVariables state) => (int)state.Get(ScifiShipStateVariableTypes.Shield); - public static void Energy(this ShipStateVariables state, int value) => state[ScifiShipStateVariableTypes.Shield] = value; - public static void AddEnergy(this ShipStateVariables state, int change, int? max = null) { - var newValue = state.Energy() + change; + var newValue = state.Energy + change; if(newValue <= 0) { newValue = 0; } if(max == null) - { state.Energy(newValue); } + { state.Energy = newValue; } else {state.EnsureEnergyInBounds(newValue, max.Value); } } public static void DeductEnergy(this ShipStateVariables state, int change, int? max = null) { - var newValue = state.Energy() - change; + var newValue = state.Energy - change; if(newValue <= 0) { newValue = 0; } if(max == null) - { state.Energy(newValue); } + { state.Energy = newValue; } else {state.EnsureEnergyInBounds(newValue, max.Value); } } @@ -120,8 +134,5 @@ public static void ApplyDamageToTarget(this ShipStateVariables state, ProcessedA if (totalDamage < 0) { totalDamage = 0; } state.DeductArmour(totalDamage); } - - public static bool IsDead(this ShipStateVariables state) - { return state.Armour() <= 0; } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Scifi/Extensions/ShipVariableExtensions.cs b/src/OpenRpg.Genres.Scifi/Extensions/ShipVariableExtensions.cs index 303d202f..42b80ed7 100644 --- a/src/OpenRpg.Genres.Scifi/Extensions/ShipVariableExtensions.cs +++ b/src/OpenRpg.Genres.Scifi/Extensions/ShipVariableExtensions.cs @@ -1,3 +1,4 @@ +using OpenRpg.Core.Extensions; using OpenRpg.Genres.Scifi.Equippables.ShipSlots; using OpenRpg.Genres.Scifi.Types; using OpenRpg.Genres.Scifi.Variables; @@ -10,22 +11,25 @@ namespace OpenRpg.Genres.Scifi.Extensions ///
public static class ShipVariableExtensions { + extension(ShipVariables vars) + { + public ShipEquipment Equipment + { + get => vars.GetAsOrDefault(ShipVariableTypes.Equipment, () => new ShipEquipment()); + set => vars[ShipVariableTypes.Equipment] = value; + } + + public Inventory Inventory + { + get => vars.GetAsOrDefault(ShipVariableTypes.Inventory, () => new Inventory()); + set => vars[ShipVariableTypes.Inventory] = value; + } + } + public static bool HasEquipment(this ShipVariables vars) { return vars.ContainsKey(ShipVariableTypes.Equipment); } - public static ShipEquipment Equipment(this ShipVariables vars) - { return vars[ShipVariableTypes.Equipment] as ShipEquipment; } - - public static void Equipment(this ShipVariables vars, ShipEquipment equipment) - { vars[ShipVariableTypes.Equipment] = equipment; } - public static bool HasInventory(this ShipVariables vars) { return vars.ContainsKey(ShipVariableTypes.Inventory); } - - public static Inventory Inventory(this ShipVariables vars) - { return vars[ShipVariableTypes.Inventory] as Inventory; } - - public static void Inventory(this ShipVariables vars, Inventory inventory) - { vars[ShipVariableTypes.Inventory] = inventory; } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Scifi/Extensions/StatExtensions.cs b/src/OpenRpg.Genres.Scifi/Extensions/StatExtensions.cs index 1b34134d..cbf91ac4 100644 --- a/src/OpenRpg.Genres.Scifi/Extensions/StatExtensions.cs +++ b/src/OpenRpg.Genres.Scifi/Extensions/StatExtensions.cs @@ -5,26 +5,67 @@ namespace OpenRpg.Genres.Scifi.Extensions { public static class EntityStatExtensions { - public static float PhysicalDamage(this EntityStatsVariables stats) => stats.Get(ScifiEntityStatsVariableTypes.PhysicalDamage); - public static float BallisticDamage(this EntityStatsVariables stats) => stats.Get(ScifiEntityStatsVariableTypes.BallisticDamage); - public static float ExplosiveDamage(this EntityStatsVariables stats) => stats.Get(ScifiEntityStatsVariableTypes.ExplosiveDamage); - public static float IonDamage(this EntityStatsVariables stats) => stats.Get(ScifiEntityStatsVariableTypes.IonDamage); - public static float LaserDamage(this EntityStatsVariables stats) => stats.Get(ScifiEntityStatsVariableTypes.LaserDamage); - public static void PhysicalDamage(this EntityStatsVariables stats, float value) => stats[ScifiEntityStatsVariableTypes.PhysicalDamage] = value; - public static void BallisticDamage(this EntityStatsVariables stats, float value) => stats[ScifiEntityStatsVariableTypes.BallisticDamage] = value; - public static void ExplosiveDamage(this EntityStatsVariables stats, float value) => stats[ScifiEntityStatsVariableTypes.ExplosiveDamage] = value; - public static void IonDamage(this EntityStatsVariables stats, float value) => stats[ScifiEntityStatsVariableTypes.IonDamage] = value; - public static void LaserDamage(this EntityStatsVariables stats, float value) => stats[ScifiEntityStatsVariableTypes.LaserDamage] = value; - - public static float PhysicalDefense(this EntityStatsVariables stats) => stats.Get(ScifiEntityStatsVariableTypes.PhysicalDefense); - public static float BallisticDefense(this EntityStatsVariables stats) => stats.Get(ScifiEntityStatsVariableTypes.BallisticDefense); - public static float ExplosiveDefense(this EntityStatsVariables stats) => stats.Get(ScifiEntityStatsVariableTypes.ExplosiveDefense); - public static float IonDefense(this EntityStatsVariables stats) => stats.Get(ScifiEntityStatsVariableTypes.IonDefense); - public static float LaserDefense(this EntityStatsVariables stats) => stats.Get(ScifiEntityStatsVariableTypes.LaserDefense); - public static void PhysicalDefense(this EntityStatsVariables stats, float value) => stats[ScifiEntityStatsVariableTypes.PhysicalDefense] = value; - public static void BallisticDefense(this EntityStatsVariables stats, float value) => stats[ScifiEntityStatsVariableTypes.BallisticDefense] = value; - public static void ExplosiveDefense(this EntityStatsVariables stats, float value) => stats[ScifiEntityStatsVariableTypes.ExplosiveDefense] = value; - public static void IonDefense(this EntityStatsVariables stats, float value) => stats[ScifiEntityStatsVariableTypes.IonDefense] = value; - public static void LaserDefense(this EntityStatsVariables stats, float value) => stats[ScifiEntityStatsVariableTypes.LaserDefense] = value; + extension(EntityStatsVariables stats) + { + public float PhysicalDamage + { + get => stats.Get(ScifiEntityStatsVariableTypes.PhysicalDamage); + set => stats[ScifiEntityStatsVariableTypes.PhysicalDamage] = value; + } + + public float BallisticDamage + { + get => stats.Get(ScifiEntityStatsVariableTypes.BallisticDamage); + set => stats[ScifiEntityStatsVariableTypes.BallisticDamage] = value; + } + + public float ExplosiveDamage + { + get => stats.Get(ScifiEntityStatsVariableTypes.ExplosiveDamage); + set => stats[ScifiEntityStatsVariableTypes.ExplosiveDamage] = value; + } + + public float IonDamage + { + get => stats.Get(ScifiEntityStatsVariableTypes.IonDamage); + set => stats[ScifiEntityStatsVariableTypes.IonDamage] = value; + } + + public float LaserDamage + { + get => stats.Get(ScifiEntityStatsVariableTypes.LaserDamage); + set => stats[ScifiEntityStatsVariableTypes.LaserDamage] = value; + } + + public float PhysicalDefense + { + get => stats.Get(ScifiEntityStatsVariableTypes.PhysicalDefense); + set => stats[ScifiEntityStatsVariableTypes.PhysicalDefense] = value; + } + + public float BallisticDefense + { + get => stats.Get(ScifiEntityStatsVariableTypes.BallisticDefense); + set => stats[ScifiEntityStatsVariableTypes.BallisticDefense] = value; + } + + public float ExplosiveDefense + { + get => stats.Get(ScifiEntityStatsVariableTypes.ExplosiveDefense); + set => stats[ScifiEntityStatsVariableTypes.ExplosiveDefense] = value; + } + + public float IonDefense + { + get => stats.Get(ScifiEntityStatsVariableTypes.IonDefense); + set => stats[ScifiEntityStatsVariableTypes.IonDefense] = value; + } + + public float LaserDefense + { + get => stats.Get(ScifiEntityStatsVariableTypes.LaserDefense); + set => stats[ScifiEntityStatsVariableTypes.LaserDefense] = value; + } + } } } \ No newline at end of file From 8d6d28893d40623b3d6a0fa227e41572030cd5a0 Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 9 Dec 2025 15:21:12 +0000 Subject: [PATCH 010/153] Fixed issue with array.empty casting, also update asp nugets --- .../CombatTemplateVariableExtensions.cs | 3 +-- .../Extensions/CollectionExtensions.cs | 5 +++++ .../OpenRpg.Demos.Infrastructure.csproj | 4 ++-- .../Components/Items/ItemDetails.razor | 2 -- .../OpenRpg.Demos.Web.csproj | 8 +++---- .../Pages/Procedural/ProceduralItems.razor | 22 +++++++++---------- .../OpenRpg.Editor.Core.csproj | 2 +- .../OpenRpg.Editor.Infrastructure.csproj | 4 ++-- .../OpenRpg.Editor.UI.csproj | 4 ++-- .../ITemplateDataVariablesExtensions.cs | 2 +- .../Extensions/EffectExtensions.cs | 3 ++- 11 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/OpenRpg.Combat/Extensions/CombatTemplateVariableExtensions.cs b/src/OpenRpg.Combat/Extensions/CombatTemplateVariableExtensions.cs index 8191dcba..842b3416 100644 --- a/src/OpenRpg.Combat/Extensions/CombatTemplateVariableExtensions.cs +++ b/src/OpenRpg.Combat/Extensions/CombatTemplateVariableExtensions.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using OpenRpg.Combat.Abilities; using OpenRpg.Combat.Types; @@ -16,7 +15,7 @@ public static bool HasAbilities(this ITemplateVariables vars) => { public IReadOnlyCollection Abilities { - get => vars.GetAsOrDefault(CombatTemplateVariableTypes.Abilities, Array.Empty); + get => vars.GetAsOrDefault(CombatTemplateVariableTypes.Abilities, IReadOnlyCollection.Empty); set => vars[CombatTemplateVariableTypes.Abilities] = value; } diff --git a/src/OpenRpg.Core/Extensions/CollectionExtensions.cs b/src/OpenRpg.Core/Extensions/CollectionExtensions.cs index a2ece362..6cf412eb 100644 --- a/src/OpenRpg.Core/Extensions/CollectionExtensions.cs +++ b/src/OpenRpg.Core/Extensions/CollectionExtensions.cs @@ -5,6 +5,11 @@ namespace OpenRpg.Core.Extensions { public static class CollectionExtensions { + extension(IReadOnlyCollection) + { + public static IReadOnlyCollection Empty() => Array.Empty(); + } + public static void ForEach(this IDictionary dictionary, Action action) { foreach(var pair in dictionary) diff --git a/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj b/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj index 347b8d50..d6aa9af3 100644 --- a/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj +++ b/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj @@ -7,7 +7,7 @@ - + @@ -21,7 +21,7 @@ - + diff --git a/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor b/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor index cc9cca4c..d646550e 100644 --- a/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor +++ b/src/OpenRpg.Demos.Web/Components/Items/ItemDetails.razor @@ -2,9 +2,7 @@ @using OpenRpg.Core.Templates @using OpenRpg.Genres.Fantasy.Types @using OpenRpg.Items.Extensions -@using OpenRpg.Items.Templates @using OpenRpg.Items.Types -@using OpenRpg.Demos.Infrastructure.Extensions @using OpenRpg.Entities.Extensions @using OpenRpg.Genres.Characters @using OpenRpg.Genres.Extensions diff --git a/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj b/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj index 0c974e79..32ee0792 100644 --- a/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj +++ b/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj @@ -10,10 +10,10 @@ - - - - + + + + diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor b/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor index 2ff0aecc..c954eada 100644 --- a/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor @@ -39,18 +39,18 @@ ```csharp var possibleEffects = new List<GroupedEffect> { - new() { GroupType = CoreProceduralGroupTypes.Primary, EffectType = FantasyEffectTypes.BluntDamageAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(20, 30), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, - new() { GroupType = CoreProceduralGroupTypes.Primary, EffectType = FantasyEffectTypes.PiercingDamageAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(20, 30), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, - new() { EffectType = FantasyEffectTypes.StrengthBonusAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(1, 3), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, - new() { EffectType = FantasyEffectTypes.DexterityBonusAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(1, 3), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, - new() { EffectType = FantasyEffectTypes.FireDamageAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(1, 5), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, - new() { EffectType = FantasyEffectTypes.WindDamageAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(1, 5), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, + new() { GroupType = CoreProceduralGroupTypes.Primary, EffectType = FantasyEffectTypes.BluntDamageAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(20, 30), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, + new() { GroupType = CoreProceduralGroupTypes.Primary, EffectType = FantasyEffectTypes.PiercingDamageAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(20, 30), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, + new() { EffectType = FantasyEffectTypes.StrengthBonusAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(1, 3), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, + new() { EffectType = FantasyEffectTypes.DexterityBonusAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(1, 3), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, + new() { EffectType = FantasyEffectTypes.FireDamageAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(1, 5), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, + new() { EffectType = FantasyEffectTypes.WindDamageAmount, PotencyFunction = new ScalingFunction(PresetCurves.BellCurve, new RangeF(1, 5), RangeF.ZeroToOneHundred), ScalingType = CoreEffectScalingTypes.Value }, }; var proceduralEffects = new ProceduralEffects() { - EffectAmount = new Range(1, 3), - Effects = possibleEffects, + EffectAmount = new Range(1, 3), + Effects = possibleEffects, }; ``` @@ -66,9 +66,9 @@ ```csharp var proceduralTemplate = new ItemTemplate() { - Id = 1, - NameLocaleId = "Magical Random Sword", - ItemType = FantasyItemTypes.GenericWeapon + Id = 1, + NameLocaleId = "Magical Random Sword", + ItemType = FantasyItemTypes.GenericWeapon }; proceduralTemplate.Variables.ProceduralEffects(proceduralEffects); ``` diff --git a/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj b/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj index 0f3dffa3..ea904105 100644 --- a/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj +++ b/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj b/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj index 76d0817d..de1a2128 100644 --- a/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj +++ b/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj b/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj index 346784a9..bb313949 100644 --- a/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj +++ b/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/src/OpenRpg.Entities/Extensions/ITemplateDataVariablesExtensions.cs b/src/OpenRpg.Entities/Extensions/ITemplateDataVariablesExtensions.cs index 19dbebe9..5b2ab517 100644 --- a/src/OpenRpg.Entities/Extensions/ITemplateDataVariablesExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/ITemplateDataVariablesExtensions.cs @@ -28,7 +28,7 @@ public static bool HasProceduralAssociation(this ITemplateDataVariables vars) { public IReadOnlyCollection ProceduralAssociation { - get => vars.GetAsOrDefault(CoreTemplateDataVariableTypes.ProceduralAssociations, Array.Empty); + get => vars.GetAsOrDefault(CoreTemplateDataVariableTypes.ProceduralAssociations, IReadOnlyCollection.Empty); set => vars[CoreTemplateDataVariableTypes.ProceduralAssociations] = value; } } diff --git a/src/OpenRpg.Items/Extensions/EffectExtensions.cs b/src/OpenRpg.Items/Extensions/EffectExtensions.cs index 88489fad..8ed5991b 100644 --- a/src/OpenRpg.Items/Extensions/EffectExtensions.cs +++ b/src/OpenRpg.Items/Extensions/EffectExtensions.cs @@ -19,7 +19,8 @@ public static IEnumerable GetEffects(this ItemData itemData, ITemplateA if (itemData.Variables.HasProceduralAssociation()) { var proceduralEffects = template.Variables.ProceduralEffects; - foreach (var proceduralEffect in itemData.Variables.ProceduralAssociation) + var proceduralAssociations = itemData.Variables.ProceduralAssociation; + foreach (var proceduralEffect in proceduralAssociations) { var effect = proceduralEffects.Effects[proceduralEffect.AssociatedId]; if (effect.ScalingType == CoreEffectScalingTypes.Value) From 9a8d3c2235ad697562897d4603cc62dab0063908 Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 9 Dec 2025 15:24:20 +0000 Subject: [PATCH 011/153] Updated more nugets --- src/OpenRpg.AdviceEngine.Rx/OpenRpg.AdviceEngine.Rx.csproj | 2 +- src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj | 2 +- .../OpenRpg.Demos.Infrastructure.csproj | 2 +- src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj | 4 ++-- src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj | 2 +- src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj | 4 ++-- src/OpenRpg.Editor/OpenRpg.Editor.csproj | 2 +- src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/OpenRpg.AdviceEngine.Rx/OpenRpg.AdviceEngine.Rx.csproj b/src/OpenRpg.AdviceEngine.Rx/OpenRpg.AdviceEngine.Rx.csproj index edd6663f..4e0c8b55 100644 --- a/src/OpenRpg.AdviceEngine.Rx/OpenRpg.AdviceEngine.Rx.csproj +++ b/src/OpenRpg.AdviceEngine.Rx/OpenRpg.AdviceEngine.Rx.csproj @@ -17,7 +17,7 @@ - + diff --git a/src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj b/src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj index 1cb87614..dea68c9e 100644 --- a/src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj +++ b/src/OpenRpg.Data.Database/OpenRpg.Data.Database.csproj @@ -18,7 +18,7 @@ - + diff --git a/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj b/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj index d6aa9af3..0fb3b93b 100644 --- a/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj +++ b/src/OpenRpg.Demos.Infrastructure/OpenRpg.Demos.Infrastructure.csproj @@ -23,7 +23,7 @@ - + diff --git a/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj b/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj index 32ee0792..432d1b2d 100644 --- a/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj +++ b/src/OpenRpg.Demos.Web/OpenRpg.Demos.Web.csproj @@ -9,7 +9,7 @@ - + @@ -31,7 +31,7 @@ - + diff --git a/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj b/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj index ea904105..b7ed93bd 100644 --- a/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj +++ b/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj b/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj index bb313949..04463dfe 100644 --- a/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj +++ b/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj @@ -7,12 +7,12 @@ - + - + diff --git a/src/OpenRpg.Editor/OpenRpg.Editor.csproj b/src/OpenRpg.Editor/OpenRpg.Editor.csproj index c63b185e..ef2b90d7 100644 --- a/src/OpenRpg.Editor/OpenRpg.Editor.csproj +++ b/src/OpenRpg.Editor/OpenRpg.Editor.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj b/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj index b6c26347..19448885 100644 --- a/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj +++ b/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj @@ -10,14 +10,14 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all From 11e988f83b305568eb95845979b4bb37a92013d2 Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 9 Dec 2025 19:18:27 +0000 Subject: [PATCH 012/153] Bumped testing nugets --- src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj b/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj index 19448885..4fea5cea 100644 --- a/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj +++ b/src/OpenRpg.UnitTests/OpenRpg.UnitTests.csproj @@ -12,8 +12,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all From 754dc83aa7f13a032be3540a870589b860b73f00 Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 9 Dec 2025 19:52:29 +0000 Subject: [PATCH 013/153] Fixed up some typos --- .../Types/ViewVariableTypes.cs | 7 ------- src/OpenRpg.Genres/Types/GenreEffectTypes.cs | 4 ++-- 2 files changed, 2 insertions(+), 9 deletions(-) delete mode 100644 src/OpenRpg.Demos.Infrastructure/Types/ViewVariableTypes.cs diff --git a/src/OpenRpg.Demos.Infrastructure/Types/ViewVariableTypes.cs b/src/OpenRpg.Demos.Infrastructure/Types/ViewVariableTypes.cs deleted file mode 100644 index f2231370..00000000 --- a/src/OpenRpg.Demos.Infrastructure/Types/ViewVariableTypes.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace OpenRpg.Demos.Infrastructure.Types -{ - public class ViewVariableTypes - { - public static int AssetCode = 5000; - } -} \ No newline at end of file diff --git a/src/OpenRpg.Genres/Types/GenreEffectTypes.cs b/src/OpenRpg.Genres/Types/GenreEffectTypes.cs index d4d258cf..b1446594 100644 --- a/src/OpenRpg.Genres/Types/GenreEffectTypes.cs +++ b/src/OpenRpg.Genres/Types/GenreEffectTypes.cs @@ -9,8 +9,8 @@ public interface GenreEffectTypes public static readonly int DamageBonusPercentage = 2; public static readonly int CriticalRateBonusAmount = 3; public static readonly int CriticalRateBonusPercentage = 4; - static readonly int CriticalDamageBonusAmount = 5; - static readonly int CriticalDamageBonusPercentage = 6; + public static readonly int CriticalDamageBonusAmount = 5; + public static readonly int CriticalDamageBonusPercentage = 6; // Pure Defense Types public static readonly int DefenseBonusAmount = 21; From 15dd02ca5799ade1764136de9df769fc8020104e Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 9 Dec 2025 19:53:41 +0000 Subject: [PATCH 014/153] Bumped photino version --- src/OpenRpg.Editor/OpenRpg.Editor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenRpg.Editor/OpenRpg.Editor.csproj b/src/OpenRpg.Editor/OpenRpg.Editor.csproj index ef2b90d7..6ce97269 100644 --- a/src/OpenRpg.Editor/OpenRpg.Editor.csproj +++ b/src/OpenRpg.Editor/OpenRpg.Editor.csproj @@ -25,7 +25,7 @@ - + From ad2040a78d0268f80cebb5a4362f8cf18b6262ae Mon Sep 17 00:00:00 2001 From: LP Date: Thu, 11 Dec 2025 18:29:45 +0000 Subject: [PATCH 015/153] Starting to add Enemy examples --- .../Pages/Enemies/BasicEnemy.razor | 150 ++++++++++++++++++ src/OpenRpg.Demos.Web/Shared/NavMenu.razor | 5 + src/OpenRpg.Entities/Entity/EntityTemplate.cs | 9 -- .../Effects/CharacterEffectProcessor.cs | 6 - 4 files changed, 155 insertions(+), 15 deletions(-) create mode 100644 src/OpenRpg.Demos.Web/Pages/Enemies/BasicEnemy.razor delete mode 100644 src/OpenRpg.Entities/Entity/EntityTemplate.cs diff --git a/src/OpenRpg.Demos.Web/Pages/Enemies/BasicEnemy.razor b/src/OpenRpg.Demos.Web/Pages/Enemies/BasicEnemy.razor new file mode 100644 index 00000000..f3b7c8bb --- /dev/null +++ b/src/OpenRpg.Demos.Web/Pages/Enemies/BasicEnemy.razor @@ -0,0 +1,150 @@ +@page "/enemies/basic-enemy" + +@using OpenRpg.Core.Effects +@using OpenRpg.Core.Extensions +@using OpenRpg.Core.Templates +@using OpenRpg.Entities.Effects.Processors +@using OpenRpg.Entities.Entity +@using OpenRpg.Entities.Entity.Populators.Stats +@using OpenRpg.Entities.Extensions +@using OpenRpg.Entities.Requirements +@using OpenRpg.Genres.Characters +@using OpenRpg.Genres.Effects +@using OpenRpg.Genres.Extensions +@using OpenRpg.Genres.Requirements +@using OpenRpg.Genres.Types + +@inject ITemplateAccessor TemplateAccessor +@inject ICharacterEffectProcessor EffectProcessor +@inject IEntityStatPopulator StatPopulator + + + ## Enemies + So far we have discussed characters, quests and combat etc, and thats all great, but almost all RPGs need some notion of enemies right? + + Thing is out the box we don't have any formal structures for enemies etc, from a data perspective they are just entities/characters with a template for the most part. + + So with that being the case why do we even have a chapter on this? well because there is some differences in most common use cases between enemies and characters, for example: + - Enemies are often not unique are likely based off templates + - Enemies often give rewards when killed, so may have loot tables rather than inventories etc + - Enemies often end up being short lived and are often not player controlled + + There are many other differences, and these may be more/less apparent in different scenarios, but ultimately we can express enemies with the current structures we have. + +
+ + + ## Expressing Enemy Templates + Given what we discuss above lets have a look at a super simple enemy template we could make, again this is mainly up to you to decide what an enemy needs to be. + + ```csharp + public class EnemyTemplate : ITemplate, IHasEffects + { + public int Id { get; set; } + public string NameLocaleId { get; set; } + public string DescriptionLocaleId { get; set; } + + public IReadOnlyCollection<IEffect> Effects { get; set; } = Array.Empty<IEffect>(); + } + ``` + + This seems reasonable as a starting point, we give the template the notion of `Effects` which we can just assign directly and as with all `Templates` it has an Id/Name/Description. + + So using the above we could create a Bat enemy using this template like so: + + ```csharp + var batTemplate = new EnemyTemplate + { + Id = EnemyTypes.Bat, + NameLocaleId = "Bat", + DescriptionLocaleId = "Its a big bat with leathery wings", + Effects = [ + new StaticEffect() { EffectType = GenreEffectTypes.HealthBonusAmount, Potency = 100 }, // Give it 100 hp + new StaticEffect() { EffectType = GenreEffectTypes.DamageBonusAmount, Potency = 10 }, // and 10 damage + new StaticEffect() { EffectType = GenreEffectTypes.ExperienceRestoreAmount, Potency = 5 }, // gives 5 xp when killed + ] + } + ``` + + > We are keeping things SUPER simple here, but maybe you want your enemies to have races/classes/equipment that can be used to provide effects + > there is nothing stopping you adding that, or any other responsibilities an `Enemy` may have, like a loot table or abilities an enemy has etc. + + Ok so that was simple enough, so now we have expressed the template that drives how the enemies stats will be generated how do we actually make instances from the templates? + +
+ + + ## Creating Instances of Enemies + + So at this point we have a template describing what a Bat is, but we need to have some data container to store the runtime instance of a Bat. + + ```csharp + public class EnemyData : UniqueEntity, IHasTemplateLink + { + public int TemplateId { get; set; } + } + ``` + + Wow that was hard... as mentioned before an Enemy is just an `Entity` but they are basically instances of templates, so we have interfaces for that already. + + > We could have used `ITemplateData<T>` but in this example we are not giving the `EnemyTemplate` any `IVariables` of any kind but in the real world you may want to do that. + + So lets make a couple of bats, what would that look like? + + +@code { + + public class EnemyTemplate : ITemplate, IHasEffects + { + public int Id { get; set; } + public string NameLocaleId { get; set; } + public string DescriptionLocaleId { get; set; } + + public IReadOnlyCollection Effects { get; set; } = Array.Empty(); + } + + public class EnemyData : Character, IHasTemplateLink + { + public int TemplateId { get; set; } + } + + public static class EnemyTypes + { + public static int Bat = 1; + } + + private EnemyTemplate BatTemplate; + private EnemyData Bat1, Bat2; + + protected override void OnInitialized() + { + BatTemplate = new EnemyTemplate + { + Id = EnemyTypes.Bat, + NameLocaleId = "Bat", + DescriptionLocaleId = "Its a big bat with leathery wings", + Effects = + [ + new StaticEffect() { EffectType = GenreEffectTypes.HealthBonusAmount, Potency = 100 }, // Give it 100 hp + new StaticEffect() { EffectType = GenreEffectTypes.DamageBonusAmount, Potency = 10 }, // and 10 damage + new StaticEffect() { EffectType = GenreEffectTypes.ExperienceRestoreAmount, Potency = 5 }, // gives 5 xp when killed + ] + }; + + var computedEffects = new ComputedEffects(); + BatTemplate.Effects + .Cast() + .ForEach(x => computedEffects.Add(x.EffectType, x.Potency)); + + Bat1 = new EnemyData() { TemplateId = EnemyTypes.Bat }; + StatPopulator.Populate(Bat1.Stats, computedEffects, []); + Bat1.State.Health = Bat1.Stats.MaxHealth; + + Bat2 = new EnemyData() { TemplateId = EnemyTypes.Bat }; + StatPopulator.Populate(Bat2.Stats, computedEffects, []); + Bat2.State.Health = Bat2.Stats.MaxHealth; + + base.OnInitialized(); + } + +} \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Shared/NavMenu.razor b/src/OpenRpg.Demos.Web/Shared/NavMenu.razor index 9be3b5cd..bfe85ced 100644 --- a/src/OpenRpg.Demos.Web/Shared/NavMenu.razor +++ b/src/OpenRpg.Demos.Web/Shared/NavMenu.razor @@ -47,6 +47,11 @@
  • Buffs/Temporary Effects
  • + + + - - - + + + diff --git a/src/OpenRpg.Demos.Web/wwwroot/css/site.less b/src/OpenRpg.Demos.Web/wwwroot/css/site.less index 5d018651..21909ffd 100644 --- a/src/OpenRpg.Demos.Web/wwwroot/css/site.less +++ b/src/OpenRpg.Demos.Web/wwwroot/css/site.less @@ -79,22 +79,24 @@ ul.menu-list li.has-text-light { .item-quality-1 { border-color: #9d9d9d; } .item-quality-2 { border-color: #000000; } -.item-quality-3 { border-color: #1eff00; } -.item-quality-10 { border-color: #0070dd; } -.item-quality-11 { border-color: #a335ee; } -.item-quality-12 { border-color: #e6cc80; } +.item-quality-3 { border-color: #0070dd; } +.item-quality-10 { border-color: #1eff00; } +.item-quality-11 { border-color: #0070dd; } +.item-quality-12 { border-color: #a335ee; } .item-quality-13 { border-color: #ff8000; } -.item-quality-14 { border-color: #00ccff; } +.item-quality-14 { border-color: #e89eff; } +.item-quality-15 { border-color: #00ccff; } .title.item-quality-1 { color: #000000 !important; } .title.item-quality-2 { color: #000000 !important; } -.title.item-quality-3 { color: #1eff00 !important; } -.title.item-quality-10 { color: #0070dd !important; } -.title.item-quality-11 { color: #a335ee !important; } -.title.item-quality-12 { color: #e6cc80 !important; } +.title.item-quality-3 { color: #0070dd !important; } +.title.item-quality-10 { color: #1eff00 !important; } +.title.item-quality-11 { color: #0070dd !important; } +.title.item-quality-12 { color: #a335ee !important; } .title.item-quality-13 { color: #ff8000 !important; } -.title.item-quality-14 { color: #00ccff !important; } +.title.item-quality-14 { color: #e89eff !important; } +.title.item-quality-15 { color: #00ccff !important; } .item-icon .item-icon-summary { display: none; @@ -303,4 +305,31 @@ ul.menu-list li.has-text-light { .content pre { white-space: pre-wrap; +} + + +.accordion +{ + &.is-collapsed > div + { + display: none; + } + + &.is-expanded { + & > a + { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + } + & > div + { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + } + + & > a > span.tag + { + background-color: rgba(255,255,255,0.5); + } } \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/wwwroot/images/items/boots.png b/src/OpenRpg.Demos.Web/wwwroot/images/items/boots.png new file mode 100644 index 0000000000000000000000000000000000000000..079ab415d173737e1fc86b56347ceb1270c4faf4 GIT binary patch literal 2430 zcmZ8j3pA7e8-KT%JGBu*t|4hIB{uho%H|sLqm+eQlZ7P}nRHvJL_+Qf(Xur^kwr`8 zQpk{&>->;AtCUMFzgPXv`JeOup7XrV=ed2J=RN29p68{xIvTKnibf=LTxr zhKLG-&$5t+0Z>7r+z#vo%G29P#*>*BFb?~l{=cRG7)llaguqP0 z-A0Cx{6DN49pU+ZnC^mj<3K@P=djghZe&RbmFOM z-+t98)XiBN&Be{tCTKg|-xJdD5TCm49vl5SUdG8|nK}quP3Yuc+$LJ8E!&(dSpUn}PY?D4RFgig3cEmIPYQr$I}~-mE+ZHVv@;gO za`~CS^2`9(Y64H3U2IkM9oFYbTKLoAq>tsZx8yN8^p;|+mf3|D2PIy}@=@p9{t_<3 zD_3OP2IeWm@;V#xk6(yaLmEEf`Oq&PG2>iv#A`+=L6kQItNBM={aM8m`05o@IX7a! zC|5MUl(3bzV@VBh0uf6KmPi?a@rp|cB21ZN@P(>?7+5!Qfgkxv8 zYHI|RcFIU$q471J#Az-(zt)cpyRjNipdJOjD&pT37RPNDY{t=d&kowqcO!wYEta$V zG{76;H*^@E84X7P!BUwt@xQOM@F3h_X&bD!peI zCmGiirNPG>xRWs+Au>j)J@WvFY<=i>UiKPrMlxMEq3kGH=4k!%%L~pKr&Cxw+hx)W zuguGD-zd^YY%|W_TsD)}T0WQ|)K3P-@O?MR>Zgzd1S%9)I+A_&t&dP7@K*8ZTfgST zYTa{vuXaMZUCKg95SB?6&L-)!GDFBqsL7L&iz^5vnfU3MB<$tN9y>T+o#+Ye6K;~v zPG#}Puqfd1*)d*aEO!yR{WnKAWTd;LL1Lr~?*w!2k~i1-?JbAVyX@cj<#nxl9oi|n zOL*twz4WOVEe@6wsZXwgF|&rDOcF*tI<2(-lmO@_*zJ|oe&VSReHc10=PirJ zxTbPO@NlJrIJ)_i8A9UQ^qLhrtE$b}u!4ELu7@oe+a-5r>7T;YpRQ|yp`aE624qDF z^*3F@5jsY-hL#e|jCQIVQdN?}xo^p<^ZgpYk6NB|c614rMcva>HLx_*>{=>v%S@fS z>4r{wk4v|z`|t~QVWK_Ra3@;UAv>0Q*X;V60R92aCie+PTX^Rcp?2b^nm~r1-ybxV zdFLUs&$1$U_({blh<U9SK9`-P$zO=z7wFdvt83_`P1r_P za^_=iop5(>Y`bsVp}_aj%_(KS4y)b-()KRT#2CuXSDawx6mG-&#QJS^ic6NyLye5v zr%1;QMMXNJ`RJQY-Yp?irHVs0#KOlLb!$(CP0$ch@9k4I;lF_zvCBAi%Ix{&yNI#)kKD|qE;>MfN3A*&U3sj4?tF0RNQaWz}txdMgj>A<^hF8 zJ`vRFv334rxoi7}Sd$MP85>B;$D2|S3 zY@*%E&wI_rD6O`78hf1WQW>_Jk(?dbqLw?I#H_UrU+7QJT#8vtFag?*Wcr$>kF|^{ zypGdIYojZW+$J2wun<8+G4lLRg4WNWI;>mH2{@M-wx%u6<4!qlgIa82*3Qi~D}_zn zkh#$WUW|yz#E9WZ2GsglBa{rBkoas-VucD)&nnT=&?L$yX0^0>ddy=xuK~SW40=k7 zpYD3~Jg-ZIC5>^@&DmuRg{>N+#NvW`x>WY|cd}>wzu0-7#)P_pCA`lV+#dAz`EB@H zs){UjwhnBo^^40Ts`&0cy|UDr+^qdV)uM)Mo@plU#Mp!N3_zbmI#z1tTb4C?B=@~cVDE(;=W-$j*pdAD@xBg$tDodz$H??`h8LQ< zWz)wa%ljFl*3Zq}Z}%K)&zmEImv&($LRfzPnD&*cNOM9!v`gz4YC61fR)YTia9tC7 zjGX+0uA1#wWW?z8&wk_$=t@~wTinfn=GIm+b&u9QwXgGPFjz`nMP6t=Q0M9w9+K8F zqOrb6>Cw3?!FgOt`SR&!RF8rRVMQTEz3Q)N#g~WYlj89#9*R`Y} zsK3m8UgJ|vk6Y@taZhVZ$b)W+&V#AK3`#mOU-l|jwiC5V)8B0am(Hbv)`Mofhc7j^ zx76zvV$!R9a%@**V)WD69KD>Y^p%j*Ny_35ezleIh0VbqON!Tp2Sl8qWRQpL5`1#p zz$K0pUmCgEj0+&Fnh6q#W}WTdmaf37Nx@|u@K~uuDDzWH9*(4GDe^*W#U!n*kEPrL hZs$L1`ncs9?6}+^`Vaq5>c&q5exI{l`QBp}{{_V)KcD~r literal 0 HcmV?d00001 diff --git a/src/OpenRpg.Demos.Web/wwwroot/images/items/chest.png b/src/OpenRpg.Demos.Web/wwwroot/images/items/chest.png new file mode 100644 index 0000000000000000000000000000000000000000..52b109a54b8437a691e561d33c5283a355c8fe96 GIT binary patch literal 475 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0h2Ka=yMmi{OYH$Ve4wQsG0#eK+L4Lvi|1(@a#S2u+z**oCSmdKI;Vst0LXB3LP#PSkwlAP#vt(;5n~S@*~bWjY?F{BOM}pmP>r#TA-yBUzQ!vQ z85tQGTS(I)Bs)c~^!@d|=X~dU_nhZG&%O7#zx&*K&$E!MEscc*;er4F2%DN1+JIbd zm-t~|U*>yl3S^KF8{-Q=W&hzhaKP)Me^DO*YSQ;^yYqo#fgls75C9Nq-zCU7K3fHF zQYsYV7;1afJ2c!q*bA_B_a%g?SYj^8X{e~GXr_*Q*8+7Ky&O%wO-+>mesI7Cz#)79 z1eDA`lKxlTwdN#*=l47mlvN>6KosQ8Ao(Wq{+{;(<=sXPg8;KU|KtC6C;%>H>;ZT| zO(aSU2`T&sb@xQR!het+fbwpGg1FG%nl@VJK|gBskR7d=^S`#(ssVMc&i-Qae~X{M=+JqI=b`U3Q+EWnbuulK$1hzy)$|Hj z$(D!g1DM3W;|>s+bbDSL-xS1>=j!o$rDYd=%$uiSx0w&3h({n+Q1k|h=JH|81Ob$= zt?nTzX6J>L&n#QW=d@grB=9x$fl#&5n=;Ff?W~eVO(T+%txiY|`e`%28;>=2O7U{m z6mc;(4-XziPD;z6-S9=$HMkO<5~ACQd!^>rhXde)xN4^lsu_#h5?`)M|OTR2P`B;Mf zXwT*4zQme4Bi1XhH#R(7p1pF*VxoHt6~(wkPu;^3e@5U1h%C)od@u-Lc|-fHFx#OX zejo&se=i|U_K2+0!}bYQ&{blJ{jvMD81BjCw9IE*mSi_-O&Bo-h(tXzA~7ErbhvcH z=r(nccw+7t8AM=>n98VT6o8gVqiXhI0sO(?q~LUO4|Vv5t~lLjf&f=;IZTIsm|#5# zxOfmFEVN*)u&;M`(K^x9w2Xy$XUDt!OV`FR=3ZN?f7JAW~XrYnQ=AqiV+}#dYX}?SX}P$r9A1YxK>LO<^2>u+_&kYL!a~+ z^(T`nt|UZQkN^Y__pF*`Feoa*RCaO93OdJYRE!o%`U%8xUqo2UHO)6XPZAbQKP8_5 z{0LhNQiBU0<)06q@{O79?X3z(6EQD26fYNa5-#7`DLk-O$G@>ud8EoWFcx}vtw-MY z+pYaB+pDpiq#8%8^G8Zgj+buUN9^8Y18z?NQr3w#LUc37)dzhR58nI@-}b@F>hR}* z>V=A7n_htT!8^l+vW#-pkS`zQOz@TPo*!G6bm&4Fe(F93FklCW2wzwq99?K&<-VTq znsuYSoWNjdXM3N!ep9{>BClUHy-&w`!kHep`$Cd&ODQ68F`aM2R$A7>qcRQSaso(m z0luY^Ka@#O9&}rhkF)zb>w(-PD^UAs*p_pBAP`cZ^}wV<&}{tqDXrTgq0pdjAH?@Y zk`r5d-=x|ChI_PKg5$$l2?B~@9h2ePLn>~mBRUjQ(4pe;pikN(XG0h;wTePt4P4aC z_%|<%&JV~0U5mcS`=5Y!0I+3~D9Ls;PDTyTOz7SV+F|1ra{?VQi>m=o)_{kza*c?1 zF#$Oe^xnxrLul8xz}7WDx9L9am|1Af#L{)&rbc53>wSQrQ!o-Pys~LvptCa|T0A&l zqwwSqtP?WNHkMXoaDvlTvOnMNPAN-wSopkjg-BK&ui2p* zg{AQFr~oBzKGW+xiGKqZsNGo`1Ui8cbF&z)s9XhI$zIizi#-YV7;_|yC_0p9ye!49 zDK&c}MmL+84qKnrP;wTopd;o|L?9)zdSTi@EO}kZt#=< zzjs4+s3!E>yYXQ{K{8UCBk$Q&{KTP@ZsXC<&8Rj#jLS}0Ek{4R15;u}@BG*`lNH1g ztL4PmhRUTtMf3~l^H*{$F^nR6zXwA~TQ=lGkHi3+S6Iy*=ccI86sXyw1T<}_%Zon# zMOrzD}FAT-7irTV#iq7p7#V24N=4DmAI(G6C}_OaNj!7B}&56hIdQoD<41Q(>_3|z-kTDlSyv@#4K5b)n(-cH%w zFUZpuE!3PnIywF9lvai!^R-g~8DDb}@kifvw(z*`^f|pE6|bjms;iJSEs69qwWq)O z{0hn_3M!11B?!dJRd*sn^aN_73J;{8QMs7>vy*kg0(dcf)>56{zKCj%gE(S!tBRXg zoi&*_d`ZF!4{}ZD-Sn&8&AB*y(LltL8mEJTN=M!~awq@v?N9gWIjGcQxrb?VgTyNx z<4UEOXn-)&g|T>~6yM#y(fvt+Jh&3_Z8?|683?!}6(m_X^A$tf%&yn& z*bmOew4H${Z>Xy=WA4Fecw#VltF?D1n&i)kRC(94iu21#9j&$SP7!D2W?q_G+Ko=G zJLICRF?@e7qM#L-wMB8ou?5*}2SH!3<4!LUQ>$dK=*Gu>8if9XPqb|1sHbekpOZTl z)a9S;$X4apyF@Lwtu9_<0d7_bwum>=8}**RdE{y0HuczFxdl6yVTfiAvPEUUS3WbN zPzM{0p)w;owYHYTS)|ypS_OC%r0Lc><(w#pWNiA74YtVMfBR>jREwp=tfhkO-Z1Ko zk(-_}pe;&4+slih2Hk^0u1rU5pJ~baB>b1tVa?PA=HQon=w^VD52D@wvHwJ=(aSIO z{=^yL>L={AIq?~SyjvMc)djGQyC1gYSMLR=v2NICBD5z1v2B?R(1Do)FNf+~+u(tR zIzCwu3vwMFRj=A`WQwgTgT105Yr2D+-!YPCh`KHtVab?_4!Yj2(&ibxJeS{4mT#tD zdt_|df3Oi^5i20heBCVJGWf?cJiW(Jdyh3V)}5kRyyejb+s&O|VirD^S%8?jH`Z>~ zE0MDspMDfS7R0o8VrZX(&)$LqZ&J!a-1*D^cmZV_rg2!7W!gRg{9>( zEqtX$-@l%-$ZSGb70)-Z`CBU2zA-sqDL_2MeVK-3yd4m)euB($I($f|0M@2SbC|y1 zR9rPNVbjxc$gidU4~owd?HrySo_$x>l@{niME6@OU}ksX)>v4Q)wIZMgsUtE?{Q4U z$hoya@zFahaXxOQA!;MZwaTusoDBW~u)MF3xswm`uQswL$2w{GLVhz za8m3(9gkto+lhQe)g;)Zz4!&tpAF8CDSYhRTGtd~X;^vTa{PY*Qa_We literal 0 HcmV?d00001 diff --git a/src/OpenRpg.Entities/Extensions/IRequirementsCheckerExtensions.cs b/src/OpenRpg.Entities/Extensions/IRequirementsCheckerExtensions.cs new file mode 100644 index 00000000..99d00655 --- /dev/null +++ b/src/OpenRpg.Entities/Extensions/IRequirementsCheckerExtensions.cs @@ -0,0 +1,19 @@ +using OpenRpg.Core.Extensions; +using OpenRpg.Core.Requirements; +using OpenRpg.Core.Templates.Variables; +using OpenRpg.Entities.Entity; + +namespace OpenRpg.Entities.Extensions; + +public static class IRequirementsCheckerExtensions +{ + public static bool AreRequirementsMet(this IRequirementChecker requirementChecker, ITemplateVariables templateVariables, T context) + where T : EntityData + { + if (!templateVariables.HasRequirements()) + { return true; } + + var requirements = templateVariables.Requirements; + return requirementChecker.AreRequirementsMet(context, requirements); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/EquipmentExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/EquipmentExtensions.cs index 92ec9037..d9c0f500 100644 --- a/src/OpenRpg.Genres.Fantasy/Extensions/EquipmentExtensions.cs +++ b/src/OpenRpg.Genres.Fantasy/Extensions/EquipmentExtensions.cs @@ -6,6 +6,22 @@ namespace OpenRpg.Genres.Fantasy.Extensions { public static class EquipmentExtensions { + public static void PopulateFantasySlots(this Equipment equipment) + { + var slots = equipment.Slots; + slots[FantasyEquipmentSlotTypes.HeadSlot] = null; + slots[FantasyEquipmentSlotTypes.BackSlot] = null; + slots[FantasyEquipmentSlotTypes.UpperBodySlot] = null; + slots[FantasyEquipmentSlotTypes.LowerBodySlot] = null; + slots[FantasyEquipmentSlotTypes.FootSlot] = null; + slots[FantasyEquipmentSlotTypes.MainHandSlot] = null; + slots[FantasyEquipmentSlotTypes.OffHandSlot] = null; + slots[FantasyEquipmentSlotTypes.NeckSlot] = null; + slots[FantasyEquipmentSlotTypes.Ring1Slot] = null; + slots[FantasyEquipmentSlotTypes.Ring2Slot] = null; + slots[FantasyEquipmentSlotTypes.WristSlot] = null; + } + extension(Equipment equipment) { public ItemData BackSlot diff --git a/src/OpenRpg.Genres.Fantasy/Types/FantasyItemQualityTypes.cs b/src/OpenRpg.Genres.Fantasy/Types/FantasyItemQualityTypes.cs index 20b1d56e..8d7f5cde 100644 --- a/src/OpenRpg.Genres.Fantasy/Types/FantasyItemQualityTypes.cs +++ b/src/OpenRpg.Genres.Fantasy/Types/FantasyItemQualityTypes.cs @@ -5,6 +5,7 @@ public interface FantasyItemQualityTypes : Genres.Types.GenresItemQualityTypes public static readonly int UncommonQuality = 10; public static readonly int MagicalQuality = 11; public static readonly int EpicQuality = 12; - public static readonly int MythicalQuality = 13; + public static readonly int LegendaryQuality = 13; + public static readonly int MythicalQuality = 14; } } \ No newline at end of file diff --git a/src/OpenRpg.Items/Extensions/EquipmentExtensions.cs b/src/OpenRpg.Items/Extensions/EquipmentExtensions.cs index 9918ed62..8b421937 100644 --- a/src/OpenRpg.Items/Extensions/EquipmentExtensions.cs +++ b/src/OpenRpg.Items/Extensions/EquipmentExtensions.cs @@ -1,3 +1,8 @@ +using OpenRpg.Core.Extensions; +using OpenRpg.Core.Requirements; +using OpenRpg.Entities.Entity; +using OpenRpg.Entities.Extensions; +using OpenRpg.Entities.Requirements; using OpenRpg.Items.Equippables; using OpenRpg.Items.Equippables.Slots; using OpenRpg.Items.Templates; @@ -17,6 +22,9 @@ public static bool HasItemEquipped(this Equipment equipment, int slotType) if(!equipment.Slots.ContainsKey(slotType)) { return false; } return equipment.Slots[slotType] != null; } + + public static ItemData GetItemInSlot(this Equipment equipment, int slotType) + { return equipment.Slots.TryGetValue(slotType, out var itemData) ? itemData : null; } public static bool HasSlot(this Equipment equipment, int slotType) { return equipment.Slots.ContainsKey(slotType); } @@ -39,5 +47,13 @@ public static bool AttemptEquipSlot(this Equipment equipment, IEquipmentSlotVali equipment.Slots[slotType] = itemData; return true; } + + public static bool AttemptEquipSlot(this Equipment equipment, IEquipmentSlotValidator slotValidator, IRequirementChecker requirementChecker, int slotType, ItemData itemData, ItemTemplate itemTemplate, T requirementContext) where T : EntityData + { + if (!AttemptEquipSlot(equipment, slotValidator, slotType, itemData, itemTemplate)) + { return false; } + + return requirementChecker.AreRequirementsMet(itemTemplate.Variables, requirementContext); + } } } \ No newline at end of file From 30ceb38c4792dfc060224e9733857d3a7ed3fce7 Mon Sep 17 00:00:00 2001 From: LP Date: Mon, 12 Jan 2026 09:18:14 +0000 Subject: [PATCH 023/153] Added more ability related classes --- src/OpenRpg.Cards/Genres/AbilityCard.cs | 1 - ...ombatAbilityTemplateVariablesExtensions.cs | 20 ++ .../Extensions/ITemplateAccessorExtensions.cs | 17 ++ .../CombatAbilityTemplateVariableTypes.cs | 2 + .../Pages/Combat/Abilities.razor | 198 ++++++++++++++++++ src/OpenRpg.Demos.Web/Shared/NavMenu.razor | 1 + ...antasyAbilityTemplateVariableExtensions.cs | 19 ++ .../FantasyAbilityTemplateVariableTypes.cs | 8 + .../GenreAbilityTemplateVariableExtensions.cs | 26 +++ .../GenreAbilityTemplateVariableTypes.cs | 2 + 10 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 src/OpenRpg.Combat/Extensions/ITemplateAccessorExtensions.cs create mode 100644 src/OpenRpg.Demos.Web/Pages/Combat/Abilities.razor create mode 100644 src/OpenRpg.Genres.Fantasy/Extensions/FantasyAbilityTemplateVariableExtensions.cs create mode 100644 src/OpenRpg.Genres.Fantasy/Types/FantasyAbilityTemplateVariableTypes.cs create mode 100644 src/OpenRpg.Genres/Extensions/GenreAbilityTemplateVariableExtensions.cs diff --git a/src/OpenRpg.Cards/Genres/AbilityCard.cs b/src/OpenRpg.Cards/Genres/AbilityCard.cs index 48ab32c3..93a16268 100644 --- a/src/OpenRpg.Cards/Genres/AbilityCard.cs +++ b/src/OpenRpg.Cards/Genres/AbilityCard.cs @@ -4,7 +4,6 @@ using OpenRpg.Cards.Types; using OpenRpg.Combat.Abilities; using OpenRpg.Core.Effects; -using OpenRpg.Entities.Effects; namespace OpenRpg.Cards.Genres { diff --git a/src/OpenRpg.Combat/Extensions/CombatAbilityTemplateVariablesExtensions.cs b/src/OpenRpg.Combat/Extensions/CombatAbilityTemplateVariablesExtensions.cs index 30652c86..8ef2ba88 100644 --- a/src/OpenRpg.Combat/Extensions/CombatAbilityTemplateVariablesExtensions.cs +++ b/src/OpenRpg.Combat/Extensions/CombatAbilityTemplateVariablesExtensions.cs @@ -7,6 +7,14 @@ namespace OpenRpg.Combat.Extensions { public static class CombatAbilityTemplateVariablesExtensions { + public static bool HasCooldown(this AbilityTemplateVariables vars) => vars.ContainsKey(CombatAbilityTemplateVariableTypes.Cooldown); + public static bool HasDamage(this AbilityTemplateVariables vars) => vars.ContainsKey(CombatAbilityTemplateVariableTypes.Damage); + public static bool HasRange(this AbilityTemplateVariables vars) => vars.ContainsKey(CombatAbilityTemplateVariableTypes.Range); + public static bool HasAttackSize(this AbilityTemplateVariables vars) => vars.ContainsKey(CombatAbilityTemplateVariableTypes.AttackSize); + public static bool HasTargetType(this AbilityTemplateVariables vars) => vars.ContainsKey(CombatAbilityTemplateVariableTypes.TargetType); + public static bool HasMultiHit(this AbilityTemplateVariables vars) => vars.ContainsKey(CombatAbilityTemplateVariableTypes.MultiHit); + public static bool HasTargetCount(this AbilityTemplateVariables vars) => vars.ContainsKey(CombatAbilityTemplateVariableTypes.TargetCount); + extension(AbilityTemplateVariables vars) { public float Cooldown @@ -38,6 +46,18 @@ public int TargetType get => vars.GetIntOrDefault(CombatAbilityTemplateVariableTypes.TargetType, 0); set => vars[CombatAbilityTemplateVariableTypes.TargetType] = value; } + + public int MultiHit + { + get => vars.GetIntOrDefault(CombatAbilityTemplateVariableTypes.MultiHit, 0); + set => vars[CombatAbilityTemplateVariableTypes.MultiHit] = value; + } + + public int TargetCount + { + get => vars.GetIntOrDefault(CombatAbilityTemplateVariableTypes.TargetCount, 0); + set => vars[CombatAbilityTemplateVariableTypes.TargetCount] = value; + } } } } \ No newline at end of file diff --git a/src/OpenRpg.Combat/Extensions/ITemplateAccessorExtensions.cs b/src/OpenRpg.Combat/Extensions/ITemplateAccessorExtensions.cs new file mode 100644 index 00000000..e17dff45 --- /dev/null +++ b/src/OpenRpg.Combat/Extensions/ITemplateAccessorExtensions.cs @@ -0,0 +1,17 @@ +using OpenRpg.Combat.Abilities; +using OpenRpg.Core.Templates; + +namespace OpenRpg.Combat.Extensions +{ + public static class ITemplateAccessorExtensions + { + public static AbilityTemplate GetAbilityTemplate(this ITemplateAccessor templateAccessor, int abilityTemplateId) + { return templateAccessor.Get(abilityTemplateId); } + + public static Ability ToInstance(this ITemplateAccessor templateAccessor, AbilityData abilityData) + { + var template = templateAccessor.Get(abilityData.TemplateId); + return new Ability() { Data = abilityData, Template = template }; + } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Combat/Types/CombatAbilityTemplateVariableTypes.cs b/src/OpenRpg.Combat/Types/CombatAbilityTemplateVariableTypes.cs index caecd255..e7239d4d 100644 --- a/src/OpenRpg.Combat/Types/CombatAbilityTemplateVariableTypes.cs +++ b/src/OpenRpg.Combat/Types/CombatAbilityTemplateVariableTypes.cs @@ -9,5 +9,7 @@ public interface CombatAbilityTemplateVariableTypes public static readonly int Range = 3; public static readonly int AttackSize = 4; public static readonly int TargetType = 5; + public static readonly int MultiHit = 6; + public static readonly int TargetCount = 7; } } \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Pages/Combat/Abilities.razor b/src/OpenRpg.Demos.Web/Pages/Combat/Abilities.razor new file mode 100644 index 00000000..e33aa26f --- /dev/null +++ b/src/OpenRpg.Demos.Web/Pages/Combat/Abilities.razor @@ -0,0 +1,198 @@ +@page "/combat/abilities" + +@using OpenRpg.Combat.Abilities +@using OpenRpg.Combat.Attacks +@using OpenRpg.Combat.Processors.Attacks.Entity +@using OpenRpg.Combat.Types +@using OpenRpg.Combat.Extensions +@using OpenRpg.Core.Templates +@using OpenRpg.Entities.Extensions +@using OpenRpg.Genres.Characters +@using OpenRpg.Genres.Effects +@using OpenRpg.Genres.Fantasy.Types +@using OpenRpg.Genres.Fantasy.Extensions +@using OpenRpg.Localization.Data.Repositories + +@inject DemoCharacterBuilder CharacterBuilder +@inject IEntityAttackGenerator AttackGenerator +@inject ILocaleRepository LocaleRepository +@inject ITemplateAccessor TemplateAccessor; +@inject ICharacterEffectProcessor EffectProcessor; + + + ## Abilities + + Quite often your game may need to do more than just "attack" you may have special moves like casing a fireball, or backstab. + + `Abilities` attempt to express this notion in a data driven way so you can separate the *description* of the ability from the *logic* of the ability. + + For example lets make an example **Fireball** ability template. + + ```csharp + var abilityTemplate = new AbilityTemplate() + { + Id = AbilityTypes.Fireball, + NameLocaleId = "Fireball", + DescriptionLocaleId = "Shoots fireballs towards nearby enemies", + }; + abilityTemplate.Variables.Cooldown = 1.0f; + abilityTemplate.Variables.Damage = new Damage(FantasyDamageTypes.FireDamage, 30); + abilityTemplate.Variables.Range = 7.0f; + abilityTemplate.Variables.AttackSize = 2.0f; + abilityTemplate.Variables.TargetType = CombatTargetTypes.AreaOfEffect; + abilityTemplate.Variables.ManaCost = 10; + abilityTemplate.Variables.AssetCode = "ability-fireball"; + return abilityTemplate; + ``` + + There is a lot going on there, but we can see it seems to have a quick-ish cooldown, does 30 fire damage, can be fired a long range, does a medium AoE in 2.0f unit area and costs 10 mana. + + > There are other things you can set such as `TargetCount` for abilities that can only hit fixed numbers of targets, or Stamina/Health costs and many more. + + This alone is great and provides a way to describe your `Abilities` but it needs **something** to exist to actually let something use the abilities. + +
    + + ## Thats not quite as easy to do + + Ok so this is one of those parts of the system where there is no "out the box" solution to the problem, this is mainly because there isn't a huge amount of commonality between use cases. + + For example if you were making a 3rd person souls-like and you wanted to use the above `Fireball` ability you would need to spawn an actual fireball in the world and have it move towards the target/position checking to see if it collides with anything along the way, then do effects for the AoE and collision checks in a 2.0f unit radius then generate an attack for the ability and apply it using the normal combat attack processing logic. + + If you were a 2d turn based RPG you may have a simpler job as you can probably just do some flash effect to pretend the fireball hit, but then you need to work out how to turn 2.0f units into adjacent units being hit etc then formulate the attack and process. + + > As you can see almost all scenarios require information related to positions/collision detection and animation systems which are all vastly different per engine/framework so its not really possible to provide useful abstractions within the library, but we can at least express the data and the components needed for these more complex engine/game specific processes. + + So as you can see for all the varying scenarios you have, the only real thing that would happen for all is you creating an `Attack` from the ability like: + + ```csharp + var fireballAbilityData = new AbilityData { TemplateId = AbilityTypes.Fireball }; + var fireballAbility = TemplateAccessor.ToInstance(fireballAbilityData); + + // Generate attack for the character using the ability + var attack = AttackGenerator.GenerateAttack(fireballAbility, Character.Stats); + // process attack on target + ``` + + This seems to do some of the work for us, but what if our ability should only do 50% damage to adjacent/aoe targets and 150% damage to the main target? what if there is a chance of the targets getting the *Burning* debuff? what if we have some other ability that is passive and makes all corpses touched by fire explode? + + As you can see the **execution** of an ability requires too much game/design context and runtime data that are not expressed within OpenRpg, so all we can do is help you express the fundamentals of an ability then write bespoke handlers for each ability that take into account your game/design scenarios/requirements. + + > Some things to keep in mind at a high level is that `Abilities` are often asynchronous things, once they start lots of things may happen before its deemed as **done** so structure your handler in such a way that it can handle this. + +
    + + ## An **almost** real world example + + Here is some code from a real world Unity project (slightly altered) that shows how a fireball is handled: + + ```csharp + public class FireballAbilityExecutor : AbilityExecutor + { + public override int AbilityTemplateId { get; } = AbilityTypeLookups.Fireball; + + public IPooledProjectileLifecycleHandler ProjectileLifecycleHandler { get; } + + public SpriteAnimationsAsset FireballVfx { get; } + public SpriteAnimationsAsset FireballHitVfx { get; } + + public FireballAbilityExecutor(VfxLinkedAnimationAsset vfxLinkedAnimationAsset, IPooledEffectService pooledEffectService, GameAttackGenerator attackGenerator, ITemplateAccessor templateAccessor, IPhysicsChecker physicsChecker, IDistanceChecker distanceChecker, IEntityAttackProcessor entityAttackProcessor, IPooledPopupTextService popupTextService, IEventSystem eventSystem, IEntityComponentAccessor entityComponentAccessor, IPooledProjectileLifecycleHandler projectileLifecycleHandler) : base(vfxLinkedAnimationAsset, pooledEffectService, attackGenerator, templateAccessor, physicsChecker, distanceChecker, entityAttackProcessor, popupTextService, eventSystem, entityComponentAccessor) + { + ProjectileLifecycleHandler = projectileLifecycleHandler; + FireballVfx = VfxLinkedAnimationAsset.GetDataFor(VfxEffectTypes.Fireball).SpriteAnimation; + FireballHitVfx = VfxLinkedAnimationAsset.GetDataFor(VfxEffectTypes.FireballHit).SpriteAnimation; + } + + public override bool AttemptSkill(Entity ownerEntity, TransientAbilityState abilityData, Character character, Transform2D transform, bool isEnemy) + { + var range = AbilityTemplate.Variables.Range() + character.Stats.ScaledAttackRange(); + var allTargets = GetEntitiesWithinRadius(transform.Position, range, isEnemy); + + var targets = allTargets + .Take(AbilityTemplate.Variables.TargetCount()) + .ToArray(); + + if(targets.Length == 0) { return false; } + + foreach (var targetEntityId in targets) + { + var projectileData = new ProjectileSetupConfig() + { + MaxLifetimeInSeconds = 4.0f, + MovementSpeed = 4.0f, + OwnerEntity = ownerEntity, + TargetPlayers = isEnemy, + TargetTransform = EntityComponentAccessor.GetComponent<Transform2DComponent>(targetEntityId).Transform, + ProjectileRadius = 0.1f, + SpawnPosition = transform.Position, + TargetActiveState = EntityComponentAccessor.GetComponent<ActiveComponent>(targetEntityId), + SpriteAnimation = FireballVfx + }; + ProjectileLifecycleHandler.HandleSpawn(projectileData, x => OnProjectileHit(ownerEntity, x)); + } + + return true; + } + + public void OnProjectileHit(Entity ownerEntity, ProjectileFinishedEventArgs args) + { + ProjectileLifecycleHandler.HandleRecycle(args.ProjectileEntity); + if(args.TargetEntity is null) { return; } + + var character = EntityComponentAccessor.GetComponent<CharacterComponent>(ownerEntity).Character; + var attack = AttackGenerator.GenerateAttack(AbilityTemplate.Variables.Damage().Clone(), character.Stats); + PooledEffectService.ShowEffectAt(FireballHitVfx, args.ProjectilePosition.ToUnity(), rotation: args.ProjectileRotation); + TakeDamage(attack, args.TargetEntity.Value, ownerEntity); + } + } + ``` + + Just to be clear this isn't code you can drop into your project and off you go, it is taking into account 2d positions/collisions, async handling of projectiles and vfx etc and lots of other custom logic. + + It does however give a rough high level example showing the sort of things you may need to think about and how you can express them. + + > Unfortunately the base `AbilityExecutor` is too large to show here, but its a custom class that for **that project** wraps up stuff like positional + + +@code { + + public Character Character; + public AbilityTemplate FireballTemplate; + public Ability FireballAbility; + public Attack _randomAttack; + + protected override void OnInitialized() + { + Character = CharacterBuilder.CreateNew().Build(); + FireballTemplate = MakeFireballTemplate(); + var fireballAbilityData = new AbilityData { TemplateId = 1 }; + FireballAbility = new Ability { Data = fireballAbilityData, Template = FireballTemplate }; + GenerateAttack(); + + base.OnInitialized(); + } + + protected void GenerateAttack() + { + _randomAttack = AttackGenerator.GenerateAttack(FireballAbility, Character.Stats); + } + + public AbilityTemplate MakeFireballTemplate() + { + var abilityTemplate = new AbilityTemplate() + { + Id = 1, + NameLocaleId = "Fireball", + DescriptionLocaleId = "Shoots fireballs towards nearby enemies", + }; + abilityTemplate.Variables.Cooldown = 1.0f; + abilityTemplate.Variables.Damage = new Damage(FantasyDamageTypes.FireDamage, 30); + abilityTemplate.Variables.Range = 7.0f; + abilityTemplate.Variables.AttackSize = 2.0f; + abilityTemplate.Variables.TargetType = CombatTargetTypes.AreaOfEffect; + abilityTemplate.Variables.ManaCost = 10; + abilityTemplate.Variables.AssetCode = "ability-fireball"; + return abilityTemplate; + } + +} \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Shared/NavMenu.razor b/src/OpenRpg.Demos.Web/Shared/NavMenu.razor index 829e7cf0..85a182db 100644 --- a/src/OpenRpg.Demos.Web/Shared/NavMenu.razor +++ b/src/OpenRpg.Demos.Web/Shared/NavMenu.razor @@ -46,6 +46,7 @@
  • Attacking
  • Defending
  • Buffs/Temporary Effects
  • +
  • Abilities
  • diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/FantasyAbilityTemplateVariableExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/FantasyAbilityTemplateVariableExtensions.cs new file mode 100644 index 00000000..e85cb6d1 --- /dev/null +++ b/src/OpenRpg.Genres.Fantasy/Extensions/FantasyAbilityTemplateVariableExtensions.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using OpenRpg.Combat.Abilities.Variables; +using OpenRpg.Genres.Fantasy.Types; + +namespace OpenRpg.Genres.Fantasy.Extensions; + +public static class FantasyAbilityTemplateVariableExtensions +{ + public static bool HasManaCost(this AbilityTemplateVariables vars) => vars.ContainsKey(FantasyAbilityTemplateVariableTypes.ManaCost); + + extension(AbilityTemplateVariables vars) + { + public int ManaCost + { + get => (int)vars.GetValueOrDefault(FantasyAbilityTemplateVariableTypes.ManaCost, 0); + set => vars[FantasyAbilityTemplateVariableTypes.ManaCost] = value; + } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Types/FantasyAbilityTemplateVariableTypes.cs b/src/OpenRpg.Genres.Fantasy/Types/FantasyAbilityTemplateVariableTypes.cs new file mode 100644 index 00000000..a574fd86 --- /dev/null +++ b/src/OpenRpg.Genres.Fantasy/Types/FantasyAbilityTemplateVariableTypes.cs @@ -0,0 +1,8 @@ +using OpenRpg.Genres.Types; + +namespace OpenRpg.Genres.Fantasy.Types; + +public interface FantasyAbilityTemplateVariableTypes : GenreAbilityTemplateVariableTypes +{ + public static int ManaCost = 40; +} \ No newline at end of file diff --git a/src/OpenRpg.Genres/Extensions/GenreAbilityTemplateVariableExtensions.cs b/src/OpenRpg.Genres/Extensions/GenreAbilityTemplateVariableExtensions.cs new file mode 100644 index 00000000..dd06deb5 --- /dev/null +++ b/src/OpenRpg.Genres/Extensions/GenreAbilityTemplateVariableExtensions.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using OpenRpg.Combat.Abilities.Variables; +using OpenRpg.Genres.Types; + +namespace OpenRpg.Genres.Extensions; + +public static class GenreAbilityTemplateVariableExtensions +{ + public static bool HasHealthCost(this AbilityTemplateVariables vars) => vars.ContainsKey(GenreAbilityTemplateVariableTypes.HealthCost); + public static bool HasStaminaCost(this AbilityTemplateVariables vars) => vars.ContainsKey(GenreAbilityTemplateVariableTypes.StaminaCost); + + extension(AbilityTemplateVariables vars) + { + public int HealthCost + { + get => (int)vars.GetValueOrDefault(GenreAbilityTemplateVariableTypes.HealthCost, 0); + set => vars[GenreAbilityTemplateVariableTypes.HealthCost] = value; + } + + public int StaminaCost + { + get => (int)vars.GetValueOrDefault(GenreAbilityTemplateVariableTypes.StaminaCost, 0); + set => vars[GenreAbilityTemplateVariableTypes.StaminaCost] = value; + } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Genres/Types/GenreAbilityTemplateVariableTypes.cs b/src/OpenRpg.Genres/Types/GenreAbilityTemplateVariableTypes.cs index 76332d34..ca7b1fd0 100644 --- a/src/OpenRpg.Genres/Types/GenreAbilityTemplateVariableTypes.cs +++ b/src/OpenRpg.Genres/Types/GenreAbilityTemplateVariableTypes.cs @@ -4,5 +4,7 @@ namespace OpenRpg.Genres.Types { public interface GenreAbilityTemplateVariableTypes : CombatAbilityTemplateVariableTypes { + public static int HealthCost = 20; + public static int StaminaCost = 21; } } \ No newline at end of file From cbb4f13a90ced26c8d03662128bbe70fe264b5a8 Mon Sep 17 00:00:00 2001 From: LP Date: Mon, 12 Jan 2026 14:49:07 +0000 Subject: [PATCH 024/153] Added some basic high level genre summaries --- .../Pages/Other/Scenarios.razor | 92 +++++++++++++++++++ src/OpenRpg.Demos.Web/Shared/NavMenu.razor | 5 + 2 files changed, 97 insertions(+) create mode 100644 src/OpenRpg.Demos.Web/Pages/Other/Scenarios.razor diff --git a/src/OpenRpg.Demos.Web/Pages/Other/Scenarios.razor b/src/OpenRpg.Demos.Web/Pages/Other/Scenarios.razor new file mode 100644 index 00000000..43b5e52e --- /dev/null +++ b/src/OpenRpg.Demos.Web/Pages/Other/Scenarios.razor @@ -0,0 +1,92 @@ +@page "/other/scenarios" + + + ## Game/Genre Scenarios + + As mentioned throughout these examples, this framework is meant to provide the building blocks to be able to express almost any kind of RPG game, so with that in mind lets look at some common types of RPG games and the sort of high level view of how we would express those games with this library. + +
    +
    +
    + + ### Action RPG - i.e Diablo, Torchlight + + These sort of games are generally about looting procedural items and fighting somewhat procedural enemies, the combat revolves around damage derived from ability/item synergies based on affixes/powers on powerful items. + + #### Overall Approach + - Games often ignore notion of `Race` + - Unique Player `Class` templates, scaling damage/defense effects off given attributes + - Paragon board is collection of `Effects` with `Requirements` for previous nodes tracked against `Entity` + - `Enemy` templates use `Procedural Effects` for level scaling + - `Classes` has access to various `Abilities` but can only actively use X amount + - `Items` are generally procedural with unique `Effect Types` to provide affix/powers + - `Items` can use `Modifications Allowances` to support adding Gems, which wrap `Effects` + - `Inventory` is slot based with fixed slots with additional `Size` metadata, also added to `Item Templates` + - `Equipment` generally matches that of `Fantasy Genre` equipment slots + - `Quests` can express repeatable dynamic events + - `Attacks` are often `Ability` based with `Cooldowns` + +
    +
    + + ### CRPG - i.e Baldur's Gate, Pillars of Eternity + + These sort of games are generally more about story and characters, the combat often split into melee or spell based abilities with party based mechanics. + + #### Overall Approach + - `Race` should be used and provide unique bonuses + - `Class` templates have fixed `Effects` and can often use `MultiClass` functionality + - Notion of Feats/Perks can be expressed via unique `Effects` tracked against `Entity` + - `Enemy` templates use `Scaled Effects` for level scaling + - `Abilities` are often fixed per `Class` + - `Item Templates` are generally static + - `Inventory` is weight based + - `Quests` are unique and main focus of the narrative drive + - `Factions` are important as part of narrative decisions + - `Attacks` are a mix of base attacks and `Ability` with custom `Usage` counts metadata + +
    +
    +
    +
    + + ### JRPG - i.e Wild Arms, Grandia + + Like CPRGs they are more story based but often have simpler `Character` mechanics often have more of a fixed + + #### Overall Approach + - Games often ignore notion of `Race` + - `Class` templates have fixed `Effects` and can often use `MultiClass` functionality + - Notion of Feats/Perks can be expressed via unique `Effects` tracked against `Entity` + - `Enemy` templates use `Scaled Effects` for level scaling + - `Abilities` are often fixed per `Class` and known as Spells/Skills + - `Item Templates` are generally static + - `Inventory` is unlimited + - Games often ignore notion of `Quests` but likely tracks game trigger/progress via `GameState` + - `Attacks` are a mix of base attacks and `Ability` with Mana Cost + +
    +
    + + ### Souls-like - i.e Dark Souls, Elden Ring + + Like CPRGs they are more story based but often have simpler `Character` mechanics often have more of a fixed + + #### Overall Approach + - Games often ignore notion of `Race` + - Games often ignore notion of `Class` + - Level up attributes are custom `Effects` tracked against `Entity` + - `Enemy` templates are generally static + - `Items` would scale damage/defense `Effects` based on attributes + - Spells would be expressed as `Abilities` + - `Item Templates` are generally static + - `Inventory` has no limit + - Games often ignore notion of `Quests` but likely tracks game trigger/progress via `GameState` + +
    +
    +
    + +@code { + +} \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Shared/NavMenu.razor b/src/OpenRpg.Demos.Web/Shared/NavMenu.razor index 85a182db..64e2a3d4 100644 --- a/src/OpenRpg.Demos.Web/Shared/NavMenu.razor +++ b/src/OpenRpg.Demos.Web/Shared/NavMenu.razor @@ -81,6 +81,11 @@
  • Applicators
  • Example Usecase
  • + + + From 16d7be493716ee0eb9144adfe9781226ca49f1fb Mon Sep 17 00:00:00 2001 From: LP Date: Mon, 19 Jan 2026 13:09:14 +0000 Subject: [PATCH 025/153] Added first stab at it --- .../Extensions/RangeExtensions.cs | 20 +++ .../Items/ItemTemplateDetails.razor | 22 ++- .../Procedural/PatternGeneratedItems.razor | 163 ++++++++++++++++++ src/OpenRpg.Demos.Web/Shared/NavMenu.razor | 1 + src/OpenRpg.Demos.Web/wwwroot/index.html | 2 +- .../Extensions/ProceduralEffectExtensions.cs | 24 +++ 6 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 src/OpenRpg.Core/Extensions/RangeExtensions.cs create mode 100644 src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor diff --git a/src/OpenRpg.Core/Extensions/RangeExtensions.cs b/src/OpenRpg.Core/Extensions/RangeExtensions.cs new file mode 100644 index 00000000..8b8bd742 --- /dev/null +++ b/src/OpenRpg.Core/Extensions/RangeExtensions.cs @@ -0,0 +1,20 @@ +using OpenRpg.Core.Utils; + +namespace OpenRpg.Core.Extensions; + +public static class RangeExtensions +{ + extension(Range range) + { + public bool IsWithinRange(int value) => value >= range.Min && value <= range.Max; + public bool IsOutsideRange(int value) => value > range.Max || value < range.Min; + } + + extension(RangeF range) + { + public bool IsWithinRange(float value) => value >= range.Min && value <= range.Max; + public bool IsOutsideRange(float value) => value > range.Max || value < range.Min; + public bool IsWithinRange(int value) => value >= range.Min && value <= range.Max; + public bool IsOutsideRange(int value) => value > range.Max || value < range.Min; + } +} \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor b/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor index 71693e64..0e1538dd 100644 --- a/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor +++ b/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor @@ -26,18 +26,18 @@
    - + @($
    @if (IsWeapon) { -

    @(ItemTemplate.Variables.Effects.GetStaticEffects().Where(x => x.EffectType == FantasyEffectTypes.DamageBonusAmount).Sum(x => x.Potency))

    +

    @(SumDamage())

    Damage
    } @if (IsArmour) { -

    @(ItemTemplate.Variables.Effects.GetStaticEffects().Where(x => x.EffectType == FantasyEffectTypes.DefenseBonusAmount).Sum(x => x.Potency))

    +

    @(SumDefense())

    Defense
    }
    @@ -75,6 +75,22 @@ private bool IsWeapon => ItemTemplate.ItemType == FantasyItemTypes.GenericWeapon; + public int SumDamage() + { + return (int)ItemTemplate.Variables.Effects + .GetStaticEffects() + .Where(x => x.EffectType == FantasyEffectTypes.DamageBonusAmount) + .Sum(x => x.Potency); + } + + public int SumDefense() + { + return (int)ItemTemplate.Variables.Effects + .GetStaticEffects() + .Where(x => x.EffectType == FantasyEffectTypes.DefenseBonusAmount) + .Sum(x => x.Potency); + } + private bool IsArmour { get diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor new file mode 100644 index 00000000..e6a3825b --- /dev/null +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor @@ -0,0 +1,163 @@ +@page "/procedural/pattern-generated-items" + +@using Newtonsoft.Json +@using OpenRpg.Core.Utils +@using OpenRpg.Core.Variables.General +@using OpenRpg.CurveFunctions +@using OpenRpg.CurveFunctions.Scaling +@using OpenRpg.Demos.Infrastructure.Templates +@using OpenRpg.Entities.Effects +@using OpenRpg.Entities.Extensions +@using OpenRpg.Entities.Procedural +@using OpenRpg.Entities.Procedural.Builders +@using OpenRpg.Entities.Types +@using OpenRpg.Genres.Fantasy.Types +@using OpenRpg.Items +@using OpenRpg.Items.Extensions +@using OpenRpg.Items.Templates + +@inject IRandomizer Randomizer; + + + ## Pattern Generation + You can generate templates with a given pattern like so + + +
    + +

    Ores

    +
    +
    + @foreach (var itemTemplate in _ores) + { +
    + +
    + } +
    +
    + +

    Ingots

    +
    +
    + @foreach (var itemTemplate in _ingots) + { +
    + +
    + } +
    +
    + +

    Swords

    +
    +
    + @foreach (var itemTemplate in _swords) + { +
    + +
    + } +
    +
    + +

    Armour

    +
    +
    + @foreach (var itemTemplate in _armours) + { +
    + +
    + } +
    +
    + +@code { + + private ItemTemplatePatternGenerator _itemTemplatePatternGenerator; + private IReadOnlyCollection _ores, _ingots, _swords, _armours; + + public class PatternGeneratorVariables : ObjectVariables + { + public int StartingId { get; set; } + public string TypeName { get; set; } + public int ItemType { get; set; } + public ProceduralEffects Effects { get; set; } + } + + public class ItemTemplatePatternGenerator + { + public string[] NamePattern { get; set; } + + public IReadOnlyCollection Generate(PatternGeneratorVariables variables) + { + var itemTemplates = new List(); + var id = variables.StartingId; + for (var i = 0; i < NamePattern.Length; i++) + { + var namePattern = NamePattern[i]; + var template = new ItemTemplate(); + template.Id = id++; + template.NameLocaleId = string.Format(namePattern, variables.TypeName); + template.ItemType = variables.ItemType; + template.Variables.AssetCode = string.Format(namePattern.ToLower(), variables.TypeName.ToLower()).Replace(" ", "-"); + template.Variables.QualityType = FantasyItemQualityTypes.CommonQuality; + + if (variables.Effects is not null) + { + var resultingEffects = variables.Effects.GenerateEffectsFrom(i); + template.Variables.Effects = resultingEffects; + } + + itemTemplates.Add(template); + } + + return itemTemplates; + } + } + + protected override void OnInitialized() + { + base.OnInitialized(); + + _itemTemplatePatternGenerator = new ItemTemplatePatternGenerator + { + NamePattern = ["Copper {0}", "Bronze {0}", "Silver {0}", "Gold {0}", "Iron {0}", "Steel {0}", "Mythril {0}"] + }; + + var numberGenerated = _itemTemplatePatternGenerator.NamePattern.Length; + + _ores = _itemTemplatePatternGenerator.Generate(new PatternGeneratorVariables() { TypeName = "Ore", StartingId = 0, ItemType = FantasyItemTypes.GenericItem }); + _ingots = _itemTemplatePatternGenerator.Generate(new PatternGeneratorVariables() { TypeName = "Ingot", StartingId = 10, ItemType = FantasyItemTypes.GenericItem }); + + var swordEffects = ProceduralEffectsBuilder.Create() + .WithPrimaryEffect(new ScaledEffect() + { + EffectType = FantasyEffectTypes.DamageBonusAmount, + PotencyFunction = new ScalingFunction(PresetCurves.Linear, new RangeF(10, 100), new RangeF(0, numberGenerated)), + ScalingType = CoreEffectScalingTypes.Value + }) + .Build(); + + _swords = _itemTemplatePatternGenerator.Generate(new PatternGeneratorVariables() { TypeName = "Sword", StartingId = 20, ItemType = FantasyItemTypes.GenericWeapon, Effects = swordEffects}); + + var armourEffects = ProceduralEffectsBuilder.Create() + .WithPrimaryEffect(new ScaledEffect() + { + EffectType = FantasyEffectTypes.DefenseBonusAmount, + PotencyFunction = new ScalingFunction(PresetCurves.Linear, new RangeF(10, 100), new RangeF(0, numberGenerated)), + ScalingType = CoreEffectScalingTypes.Value + }) + .WithPrimaryEffect(new ScaledEffect() + { + EffectType = FantasyEffectTypes.HealthBonusAmount, + PotencyFunction = new ScalingFunction(PresetCurves.Linear, new RangeF(10, 20), new RangeF(4, numberGenerated)), + ScalingType = CoreEffectScalingTypes.Value + }) + .Build(); + + _armours = _itemTemplatePatternGenerator.Generate(new PatternGeneratorVariables() { TypeName = "Armor", StartingId = 30, ItemType = FantasyItemTypes.UpperBodyArmour, Effects = armourEffects}); + } + +} \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Shared/NavMenu.razor b/src/OpenRpg.Demos.Web/Shared/NavMenu.razor index 64e2a3d4..099488c7 100644 --- a/src/OpenRpg.Demos.Web/Shared/NavMenu.razor +++ b/src/OpenRpg.Demos.Web/Shared/NavMenu.razor @@ -66,6 +66,7 @@ diff --git a/src/OpenRpg.Demos.Web/wwwroot/index.html b/src/OpenRpg.Demos.Web/wwwroot/index.html index 6f8ebe55..0f9b6ea6 100644 --- a/src/OpenRpg.Demos.Web/wwwroot/index.html +++ b/src/OpenRpg.Demos.Web/wwwroot/index.html @@ -6,7 +6,7 @@ OpenRpg.Demos.Web - + diff --git a/src/OpenRpg.Entities/Extensions/ProceduralEffectExtensions.cs b/src/OpenRpg.Entities/Extensions/ProceduralEffectExtensions.cs index e5b95891..894e6c53 100644 --- a/src/OpenRpg.Entities/Extensions/ProceduralEffectExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/ProceduralEffectExtensions.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using OpenRpg.Core.Associations; +using OpenRpg.Core.Effects; using OpenRpg.Core.Extensions; using OpenRpg.Core.Utils; using OpenRpg.Entities.Effects; @@ -44,5 +45,28 @@ public static IReadOnlyCollection GenerateProceduralEffectAssociati takenEffects.AddRange(secondaryEffects); return takenEffects; } + + public static IReadOnlyCollection GenerateEffectsFrom(this ProceduralEffects proceduralEffects, int proceduralValue) + { + var primaryEffects = proceduralEffects.Effects + .Where(x => x.GroupType == CoreProceduralGroupTypes.Primary); + + var resultingEffects = new List(); + foreach (var primaryEffect in primaryEffects) + { + if(primaryEffect.PotencyFunction.InputScale.IsOutsideRange(proceduralValue)) + { continue; } + + var effect = new StaticEffect + { + EffectType = primaryEffect.EffectType, + Potency = primaryEffect.PotencyFunction.Plot(proceduralValue), + Requirements = primaryEffect.Requirements + }; + resultingEffects.Add(effect); + } + + return resultingEffects; + } } } \ No newline at end of file From f18768e49fc010ed7bfe0ae42146c5c67ded13cb Mon Sep 17 00:00:00 2001 From: LP Date: Mon, 19 Jan 2026 16:02:41 +0000 Subject: [PATCH 026/153] improved approach but still needs more streamlining --- .../Extensions/TypeExtensions.cs | 8 +- .../Templates/ManualTemplateAccessor.cs | 6 + .../Procedural/PatternGeneratedItems.razor | 131 ++++++++++++++---- .../Pages/Procedural/ProceduralItems.razor | 2 +- .../Processors/EntityEffectProcessor.cs | 1 + .../Extensions/ITemplateVariableExtensions.cs | 1 + .../Extensions/ProceduralEffectExtensions.cs | 1 + .../Builders/ProceduralEffectsBuilder.cs | 2 +- .../{ => Effects}/ProceduralEffects.cs | 2 +- .../Patterns/ITemplatePatternGenerator.cs | 11 ++ .../Patterns/PatternGeneratorVariables.cs | 9 ++ .../Types/CoreAnyVariableTypes.cs | 9 +- .../Types/CoreTemplateDataVariableTypes.cs | 5 +- .../Types/CoreTemplateVariableTypes.cs | 10 +- 14 files changed, 156 insertions(+), 42 deletions(-) rename src/OpenRpg.Entities/Procedural/{ => Effects}/Builders/ProceduralEffectsBuilder.cs (97%) rename src/OpenRpg.Entities/Procedural/{ => Effects}/ProceduralEffects.cs (87%) create mode 100644 src/OpenRpg.Entities/Procedural/Patterns/ITemplatePatternGenerator.cs create mode 100644 src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs diff --git a/src/OpenRpg.Demos.Infrastructure/Extensions/TypeExtensions.cs b/src/OpenRpg.Demos.Infrastructure/Extensions/TypeExtensions.cs index ab43880f..12ef55b2 100644 --- a/src/OpenRpg.Demos.Infrastructure/Extensions/TypeExtensions.cs +++ b/src/OpenRpg.Demos.Infrastructure/Extensions/TypeExtensions.cs @@ -7,13 +7,17 @@ namespace OpenRpg.Demos.Infrastructure.Extensions; public static class TypeExtensions { - public static IDictionary GetTypeFieldsDictionary(this Type typeObject) + public static Dictionary GetTypeFieldsDictionary(this Type typeObject, bool ignoreZero = true) { var relatedInterfaceTypes = typeObject.GetInterfaces().ToList(); relatedInterfaceTypes.Add(typeObject); - return relatedInterfaceTypes + var results = relatedInterfaceTypes .SelectMany(x => x.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)) .ToDictionary(x => (int)x.GetValue(null), x => x.Name.UnPascalCase()); + + if(ignoreZero) { results.Remove(0); } + + return results; } } \ No newline at end of file diff --git a/src/OpenRpg.Demos.Infrastructure/Templates/ManualTemplateAccessor.cs b/src/OpenRpg.Demos.Infrastructure/Templates/ManualTemplateAccessor.cs index 6cfd2575..267c5efc 100644 --- a/src/OpenRpg.Demos.Infrastructure/Templates/ManualTemplateAccessor.cs +++ b/src/OpenRpg.Demos.Infrastructure/Templates/ManualTemplateAccessor.cs @@ -18,6 +18,12 @@ public void AddTemplate(ITemplate template) TemplateData[templateType].Add(template.Id, template); } + public void AddTemplates(IEnumerable templates) + { + foreach(var template in templates) + { AddTemplate(template); } + } + public void AddTemplate(T template) where T : ITemplate { var templateType = typeof(T); diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor index e6a3825b..2ddda8b4 100644 --- a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor @@ -1,19 +1,25 @@ @page "/procedural/pattern-generated-items" @using Newtonsoft.Json +@using OpenRpg.Core.Templates @using OpenRpg.Core.Utils @using OpenRpg.Core.Variables.General @using OpenRpg.CurveFunctions @using OpenRpg.CurveFunctions.Scaling +@using OpenRpg.Demos.Infrastructure.Extensions @using OpenRpg.Demos.Infrastructure.Templates @using OpenRpg.Entities.Effects @using OpenRpg.Entities.Extensions @using OpenRpg.Entities.Procedural -@using OpenRpg.Entities.Procedural.Builders +@using OpenRpg.Entities.Procedural.Effects +@using OpenRpg.Entities.Procedural.Effects.Builders +@using OpenRpg.Entities.Procedural.Patterns @using OpenRpg.Entities.Types @using OpenRpg.Genres.Fantasy.Types @using OpenRpg.Items @using OpenRpg.Items.Extensions +@using OpenRpg.Items.TradeSkills.Templates +@using OpenRpg.Items.TradeSkills @using OpenRpg.Items.Templates @inject IRandomizer Randomizer; @@ -77,36 +83,101 @@ private ItemTemplatePatternGenerator _itemTemplatePatternGenerator; private IReadOnlyCollection _ores, _ingots, _swords, _armours; + public ManualTemplateAccessor TemplateAccessor = new ManualTemplateAccessor(); + + public interface MetalItemPatternLookups + { + public static int Unknown = 0; + + public static int Copper = 1; + public static int Bronze = 2; + public static int Silver = 3; + public static int Gold = 4; + public static int Iron = 5; + public static int Steel = 6; + public static int Mythril = 7; + } + + public static Dictionary MetalLookups = typeof(MetalItemPatternLookups).GetTypeFieldsDictionary(); - public class PatternGeneratorVariables : ObjectVariables + public class ItemTemplatePatternGeneratorConfig : PatternGeneratorVariables { + public string NamePattern { get; set; } public int StartingId { get; set; } public string TypeName { get; set; } public int ItemType { get; set; } public ProceduralEffects Effects { get; set; } } - - public class ItemTemplatePatternGenerator + + public class ItemCraftingTemplatePatternGeneratorConfig : PatternGeneratorVariables + { + public string NamePattern { get; set; } + public int StartingId { get; set; } + public int SkillType { get; set; } + + } + + public class CraftingTemplatePatternGenerator : ITemplatePatternGenerator { - public string[] NamePattern { get; set; } + public ITemplateAccessor TemplateAccessor { get; } - public IReadOnlyCollection Generate(PatternGeneratorVariables variables) + public CraftingTemplatePatternGenerator(ITemplateAccessor templateAccessor) { - var itemTemplates = new List(); - var id = variables.StartingId; - for (var i = 0; i < NamePattern.Length; i++) + TemplateAccessor = templateAccessor; + } + + public IReadOnlyCollection Generate(ItemCraftingTemplatePatternGeneratorConfig config) + { + var itemCraftingTemplates = new List(); + var id = config.StartingId; + var patternIds = config.PatternIds; + + for (var i = 0; i < patternIds.Length; i++) { - var namePattern = NamePattern[i]; - var template = new ItemTemplate(); + var patternId = patternIds[i]; + + var inputItemTemplates = new List(); + var outputItemTemplates = new List(); + + var template = new ItemCraftingTemplate(); template.Id = id++; - template.NameLocaleId = string.Format(namePattern, variables.TypeName); - template.ItemType = variables.ItemType; - template.Variables.AssetCode = string.Format(namePattern.ToLower(), variables.TypeName.ToLower()).Replace(" ", "-"); + template.SkillType = config.SkillType; + template.InputItems = inputItemTemplates; + template.OutputItems = outputItemTemplates; + template.Variables[CoreTemplateVariableTypes.PatternId] = patternId; + itemCraftingTemplates.Add(template); + } + + return itemCraftingTemplates; + } + } + + public class ItemTemplatePatternGenerator : ITemplatePatternGenerator + { + public IReadOnlyCollection Generate(ItemTemplatePatternGeneratorConfig config) + { + var itemTemplates = new List(); + var id = config.StartingId; + var patternIds = config.PatternIds; + for (var i = 0; i < patternIds.Length; i++) + { + var patternId = patternIds[i]; + var localeNameForId = MetalLookups[patternId]; + var name = string.Format(config.NamePattern, localeNameForId, config.TypeName); + + var template = new ItemTemplate + { + Id = id++, + NameLocaleId = name, + ItemType = config.ItemType + }; + template.Variables.AssetCode = name.ToLower().Replace(" ", "-"); template.Variables.QualityType = FantasyItemQualityTypes.CommonQuality; + template.Variables[CoreTemplateVariableTypes.PatternId] = patternId; - if (variables.Effects is not null) + if (config.Effects is not null) { - var resultingEffects = variables.Effects.GenerateEffectsFrom(i); + var resultingEffects = config.Effects.GenerateEffectsFrom(i); template.Variables.Effects = resultingEffects; } @@ -121,43 +192,45 @@ { base.OnInitialized(); - _itemTemplatePatternGenerator = new ItemTemplatePatternGenerator - { - NamePattern = ["Copper {0}", "Bronze {0}", "Silver {0}", "Gold {0}", "Iron {0}", "Steel {0}", "Mythril {0}"] - }; + var namePattern = "{0} {1}"; + var patternIds = MetalLookups.Keys.ToArray(); - var numberGenerated = _itemTemplatePatternGenerator.NamePattern.Length; - - _ores = _itemTemplatePatternGenerator.Generate(new PatternGeneratorVariables() { TypeName = "Ore", StartingId = 0, ItemType = FantasyItemTypes.GenericItem }); - _ingots = _itemTemplatePatternGenerator.Generate(new PatternGeneratorVariables() { TypeName = "Ingot", StartingId = 10, ItemType = FantasyItemTypes.GenericItem }); + _itemTemplatePatternGenerator = new ItemTemplatePatternGenerator(); + _ores = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, NamePattern = namePattern, TypeName = "Ore", StartingId = 0, ItemType = FantasyItemTypes.GenericItem }); + _ingots = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, NamePattern = namePattern, TypeName = "Ingot", StartingId = 10, ItemType = FantasyItemTypes.GenericItem }); var swordEffects = ProceduralEffectsBuilder.Create() .WithPrimaryEffect(new ScaledEffect() { EffectType = FantasyEffectTypes.DamageBonusAmount, - PotencyFunction = new ScalingFunction(PresetCurves.Linear, new RangeF(10, 100), new RangeF(0, numberGenerated)), + PotencyFunction = new ScalingFunction(PresetCurves.Linear, new RangeF(10, 100), new RangeF(0, patternIds.Length)), ScalingType = CoreEffectScalingTypes.Value }) .Build(); - _swords = _itemTemplatePatternGenerator.Generate(new PatternGeneratorVariables() { TypeName = "Sword", StartingId = 20, ItemType = FantasyItemTypes.GenericWeapon, Effects = swordEffects}); + _swords = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, NamePattern = namePattern, TypeName = "Sword", StartingId = 20, ItemType = FantasyItemTypes.GenericWeapon, Effects = swordEffects}); var armourEffects = ProceduralEffectsBuilder.Create() .WithPrimaryEffect(new ScaledEffect() { EffectType = FantasyEffectTypes.DefenseBonusAmount, - PotencyFunction = new ScalingFunction(PresetCurves.Linear, new RangeF(10, 100), new RangeF(0, numberGenerated)), + PotencyFunction = new ScalingFunction(PresetCurves.Linear, new RangeF(10, 100), new RangeF(0, patternIds.Length)), ScalingType = CoreEffectScalingTypes.Value }) .WithPrimaryEffect(new ScaledEffect() { EffectType = FantasyEffectTypes.HealthBonusAmount, - PotencyFunction = new ScalingFunction(PresetCurves.Linear, new RangeF(10, 20), new RangeF(4, numberGenerated)), + PotencyFunction = new ScalingFunction(PresetCurves.Linear, new RangeF(10, 20), new RangeF(4, patternIds.Length)), ScalingType = CoreEffectScalingTypes.Value }) .Build(); - _armours = _itemTemplatePatternGenerator.Generate(new PatternGeneratorVariables() { TypeName = "Armor", StartingId = 30, ItemType = FantasyItemTypes.UpperBodyArmour, Effects = armourEffects}); + _armours = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, NamePattern = namePattern, TypeName = "Armor", StartingId = 30, ItemType = FantasyItemTypes.UpperBodyArmour, Effects = armourEffects}); + + TemplateAccessor.AddTemplates(_ores); + TemplateAccessor.AddTemplates(_ingots); + TemplateAccessor.AddTemplates(_swords); + TemplateAccessor.AddTemplates(_armours); } } \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor b/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor index c71118c6..84c562df 100644 --- a/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/ProceduralItems.razor @@ -7,7 +7,7 @@ @using OpenRpg.Demos.Infrastructure.Templates @using OpenRpg.Entities.Effects @using OpenRpg.Entities.Extensions -@using OpenRpg.Entities.Procedural.Builders +@using OpenRpg.Entities.Procedural.Effects.Builders @using OpenRpg.Entities.Types @using OpenRpg.Genres.Fantasy.Types @using OpenRpg.Items diff --git a/src/OpenRpg.Entities/Effects/Processors/EntityEffectProcessor.cs b/src/OpenRpg.Entities/Effects/Processors/EntityEffectProcessor.cs index f7042b63..1ca21769 100644 --- a/src/OpenRpg.Entities/Effects/Processors/EntityEffectProcessor.cs +++ b/src/OpenRpg.Entities/Effects/Processors/EntityEffectProcessor.cs @@ -7,6 +7,7 @@ using OpenRpg.Entities.Entity.Templates; using OpenRpg.Entities.Extensions; using OpenRpg.Entities.Procedural; +using OpenRpg.Entities.Procedural.Effects; using OpenRpg.Entities.Requirements; using OpenRpg.Entities.Types; diff --git a/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs b/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs index 4fd10bc2..8e73d488 100644 --- a/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs @@ -4,6 +4,7 @@ using OpenRpg.Core.Requirements; using OpenRpg.Core.Templates.Variables; using OpenRpg.Entities.Procedural; +using OpenRpg.Entities.Procedural.Effects; using OpenRpg.Entities.Types; namespace OpenRpg.Entities.Extensions diff --git a/src/OpenRpg.Entities/Extensions/ProceduralEffectExtensions.cs b/src/OpenRpg.Entities/Extensions/ProceduralEffectExtensions.cs index 894e6c53..880a6d2f 100644 --- a/src/OpenRpg.Entities/Extensions/ProceduralEffectExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/ProceduralEffectExtensions.cs @@ -6,6 +6,7 @@ using OpenRpg.Core.Utils; using OpenRpg.Entities.Effects; using OpenRpg.Entities.Procedural; +using OpenRpg.Entities.Procedural.Effects; using OpenRpg.Entities.Types; namespace OpenRpg.Entities.Extensions diff --git a/src/OpenRpg.Entities/Procedural/Builders/ProceduralEffectsBuilder.cs b/src/OpenRpg.Entities/Procedural/Effects/Builders/ProceduralEffectsBuilder.cs similarity index 97% rename from src/OpenRpg.Entities/Procedural/Builders/ProceduralEffectsBuilder.cs rename to src/OpenRpg.Entities/Procedural/Effects/Builders/ProceduralEffectsBuilder.cs index c4e7405b..002d236c 100644 --- a/src/OpenRpg.Entities/Procedural/Builders/ProceduralEffectsBuilder.cs +++ b/src/OpenRpg.Entities/Procedural/Effects/Builders/ProceduralEffectsBuilder.cs @@ -3,7 +3,7 @@ using OpenRpg.Entities.Effects; using OpenRpg.Entities.Types; -namespace OpenRpg.Entities.Procedural.Builders; +namespace OpenRpg.Entities.Procedural.Effects.Builders; public class ProceduralEffectsBuilder { diff --git a/src/OpenRpg.Entities/Procedural/ProceduralEffects.cs b/src/OpenRpg.Entities/Procedural/Effects/ProceduralEffects.cs similarity index 87% rename from src/OpenRpg.Entities/Procedural/ProceduralEffects.cs rename to src/OpenRpg.Entities/Procedural/Effects/ProceduralEffects.cs index 2541475b..0f8cfb7b 100644 --- a/src/OpenRpg.Entities/Procedural/ProceduralEffects.cs +++ b/src/OpenRpg.Entities/Procedural/Effects/ProceduralEffects.cs @@ -3,7 +3,7 @@ using OpenRpg.Entities.Effects; using Range = OpenRpg.Core.Utils.Range; -namespace OpenRpg.Entities.Procedural +namespace OpenRpg.Entities.Procedural.Effects { public class ProceduralEffects { diff --git a/src/OpenRpg.Entities/Procedural/Patterns/ITemplatePatternGenerator.cs b/src/OpenRpg.Entities/Procedural/Patterns/ITemplatePatternGenerator.cs new file mode 100644 index 00000000..34e31bf9 --- /dev/null +++ b/src/OpenRpg.Entities/Procedural/Patterns/ITemplatePatternGenerator.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using OpenRpg.Core.Templates; + +namespace OpenRpg.Entities.Procedural.Patterns; + +public interface ITemplatePatternGenerator + where TOut : ITemplate + where TConfig : PatternGeneratorVariables +{ + public IReadOnlyCollection Generate(TConfig config); +} \ No newline at end of file diff --git a/src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs b/src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs new file mode 100644 index 00000000..75214c1f --- /dev/null +++ b/src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs @@ -0,0 +1,9 @@ +using OpenRpg.Core.Variables.General; + +namespace OpenRpg.Entities.Procedural.Patterns; + +public class PatternGeneratorVariables : ObjectVariables +{ + public int[] PatternIds { get; set; } + +} \ No newline at end of file diff --git a/src/OpenRpg.Entities/Types/CoreAnyVariableTypes.cs b/src/OpenRpg.Entities/Types/CoreAnyVariableTypes.cs index f31e175c..ca86c8d5 100644 --- a/src/OpenRpg.Entities/Types/CoreAnyVariableTypes.cs +++ b/src/OpenRpg.Entities/Types/CoreAnyVariableTypes.cs @@ -1,13 +1,16 @@ namespace OpenRpg.Entities.Types { + // Can be applied to any 9000 range public interface CoreAnyVariableTypes { public static int Unknown = 0; + // For linking template/data to assets + public static int AssetCode = 9000; + // For adding the notion of tags - public static int Tags = 5002; + public static int Tags = 9001; - // For linking template/data to assets - public static int AssetCode = 5000; + } } \ No newline at end of file diff --git a/src/OpenRpg.Entities/Types/CoreTemplateDataVariableTypes.cs b/src/OpenRpg.Entities/Types/CoreTemplateDataVariableTypes.cs index 4a1478a1..6147c895 100644 --- a/src/OpenRpg.Entities/Types/CoreTemplateDataVariableTypes.cs +++ b/src/OpenRpg.Entities/Types/CoreTemplateDataVariableTypes.cs @@ -1,14 +1,15 @@ namespace OpenRpg.Entities.Types { + // 4000 Range (wont conflict with template) public interface CoreTemplateDataVariableTypes { // Unknown public static int Unknown = 0; /// For adding the notion of levels to the object - public static int Level = 5001; + public static int Level = 4001; // For adding the procedural associations - public static int ProceduralAssociations = 5002; + public static int ProceduralAssociations = 4002; } } \ No newline at end of file diff --git a/src/OpenRpg.Entities/Types/CoreTemplateVariableTypes.cs b/src/OpenRpg.Entities/Types/CoreTemplateVariableTypes.cs index 85219403..d4124430 100644 --- a/src/OpenRpg.Entities/Types/CoreTemplateVariableTypes.cs +++ b/src/OpenRpg.Entities/Types/CoreTemplateVariableTypes.cs @@ -1,15 +1,19 @@ namespace OpenRpg.Entities.Types { + // 4000 range public interface CoreTemplateVariableTypes { // Unknown public static int Unknown = 0; // For adding the notion of procedural effects - public static int ProceduralEffects = 5001; + public static int ProceduralEffects = 4001; // General - public static int Effects = 5002; // replaces IHasEffects - public static int Requirements = 5003; // replaces IHasRequirements + public static int Effects = 4002; // replaces IHasEffects + public static int Requirements = 4003; // replaces IHasRequirements + + // Patterns + public static int PatternId = 4020; } } \ No newline at end of file From b93c8be56a461cb4296db774b65fb0d68a315aff Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 20 Jan 2026 09:58:00 +0000 Subject: [PATCH 027/153] Added component for crafted item stuffs --- .../Data/ItemTemplateDataGenerator.cs | 2 +- .../Items/ItemTemplateDetails.razor | 7 +- .../ItemCraftingTemplateDetails.razor | 87 ++++++++++ .../TradeSkills/TradeSkillItemIcon.razor | 6 +- .../Procedural/PatternGeneratedItems.razor | 151 +++++++++++------- .../TradeSkills/CraftingTradeSkills.razor | 37 +---- .../Extensions/ITemplateVariableExtensions.cs | 31 +++- .../Patterns/PatternGeneratorVariables.cs | 1 + .../Types/CoreTemplateVariableTypes.cs | 3 +- .../ItemTemplateVariablesExtensions.cs | 6 + 10 files changed, 224 insertions(+), 107 deletions(-) create mode 100644 src/OpenRpg.Demos.Web/Components/TradeSkills/ItemCraftingTemplateDetails.razor diff --git a/src/OpenRpg.Demos.Infrastructure/Data/ItemTemplateDataGenerator.cs b/src/OpenRpg.Demos.Infrastructure/Data/ItemTemplateDataGenerator.cs index b9a52c54..74a4f3f1 100644 --- a/src/OpenRpg.Demos.Infrastructure/Data/ItemTemplateDataGenerator.cs +++ b/src/OpenRpg.Demos.Infrastructure/Data/ItemTemplateDataGenerator.cs @@ -273,7 +273,7 @@ public ItemTemplate MakeCopperSword() var template = new ItemTemplate { Id = ItemTemplateLookups.CopperSword, - NameLocaleId = "A crafted copper sword", + NameLocaleId = "Copper Sword", DescriptionLocaleId = "An oak hilt with a copper blade", ItemType = FantasyItemTypes.GenericWeapon, ModificationAllowances = Array.Empty() diff --git a/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor b/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor index 0e1538dd..835100a9 100644 --- a/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor +++ b/src/OpenRpg.Demos.Web/Components/Items/ItemTemplateDetails.razor @@ -1,11 +1,7 @@ @using OpenRpg.Core.Effects -@using OpenRpg.Core.Templates @using OpenRpg.Genres.Fantasy.Types @using OpenRpg.Items.Extensions @using OpenRpg.Items.Templates -@using OpenRpg.Items.Types -@using OpenRpg.Demos.Infrastructure.Extensions -@using OpenRpg.Entities.Effects @using OpenRpg.Entities.Extensions @using OpenRpg.Genres.Characters @using OpenRpg.Genres.Extensions @@ -15,7 +11,6 @@ @inject ILocaleRepository LocaleRepository; @inject ICharacterRequirementChecker RequirementsChecker -@inject ITemplateAccessor TemplateAccessor

    @(ItemTemplate.NameLocaleId ?? "Unnamed Item")

    @@ -130,7 +125,7 @@ protected override void OnInitialized() { - if (ItemTemplate.Variables.ContainsKey(ItemTemplateVariableTypes.QualityType)) + if (ItemTemplate.Variables.HasQualityType()) { _itemQualityTypeId = ItemTemplate.Variables.QualityType; } } diff --git a/src/OpenRpg.Demos.Web/Components/TradeSkills/ItemCraftingTemplateDetails.razor b/src/OpenRpg.Demos.Web/Components/TradeSkills/ItemCraftingTemplateDetails.razor new file mode 100644 index 00000000..ce3184c1 --- /dev/null +++ b/src/OpenRpg.Demos.Web/Components/TradeSkills/ItemCraftingTemplateDetails.razor @@ -0,0 +1,87 @@ +@using OpenRpg.Core.Templates +@using OpenRpg.Items.Extensions +@using OpenRpg.Items.Templates +@using OpenRpg.Genres.Characters +@using OpenRpg.Items.TradeSkills.Templates + + +

    @(Name)

    + @if (!string.IsNullOrEmpty(ItemCraftingTemplate.DescriptionLocaleId)) + { +
    @(ItemCraftingTemplate.DescriptionLocaleId)
    + } +
    +
    + Requires +
    +
    +
    +
    + Makes +
    +
    +
    +
    +
    + @foreach (var itemEntry in ItemCraftingTemplate.InputItems) + { +
    + +
    + } +
    +
    +
    + => +
    +
    +
    + @foreach (var itemEntry in ItemCraftingTemplate.OutputItems) + { +
    + +
    + } +
    +
    +
    +
    + +@code { + + [Parameter] + public ItemCraftingTemplate ItemCraftingTemplate { get; set; } + + [Parameter] + public ITemplateAccessor TemplateAccessor { get; set; } + + [Parameter] + public Character Character { get; set; } + + private string Name { get; set; } + + private Dictionary InputTemplates { get; set; } = new(); + private Dictionary OutputTemplates { get; set; } = new(); + + protected override void OnInitialized() + { + foreach (var inputItem in ItemCraftingTemplate.InputItems) + { + var inputItemTemplate = TemplateAccessor.GetItemTemplate(inputItem.TemplateId); + InputTemplates.Add(inputItemTemplate.Id, inputItemTemplate); + } + + foreach (var outputItem in ItemCraftingTemplate.OutputItems) + { + var outputItemTemplate = TemplateAccessor.GetItemTemplate(outputItem.TemplateId); + OutputTemplates.Add(outputItemTemplate.Id, outputItemTemplate); + } + + if (string.IsNullOrEmpty(ItemCraftingTemplate.NameLocaleId)) + { + var outputItemTemplate = OutputTemplates.Values.First(); + Name = $"Craft {outputItemTemplate.NameLocaleId}"; + } + else { Name = ItemCraftingTemplate.NameLocaleId; } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Components/TradeSkills/TradeSkillItemIcon.razor b/src/OpenRpg.Demos.Web/Components/TradeSkills/TradeSkillItemIcon.razor index 3431300d..db807df1 100644 --- a/src/OpenRpg.Demos.Web/Components/TradeSkills/TradeSkillItemIcon.razor +++ b/src/OpenRpg.Demos.Web/Components/TradeSkills/TradeSkillItemIcon.razor @@ -11,7 +11,7 @@
    @(_itemAmount > 0 ? $"{_itemAmount}" : "")
    - +
    @@ -33,12 +33,12 @@ protected override void OnParametersSet() { - if (Item.Variables != null && Item.Variables.ContainsKey(ItemVariableTypes.Amount)) + if (Item.Variables != null && Item.Variables.HasAmount()) { _itemAmount = Item.Variables.Amount; } else { _itemAmount = 0;} - if (ItemTemplate.Variables.ContainsKey(ItemTemplateVariableTypes.QualityType)) + if (ItemTemplate.Variables.HasQualityType()) { _itemQualityTypeId = ItemTemplate.Variables.QualityType; } base.OnParametersSet(); diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor index 2ddda8b4..12ccfc6f 100644 --- a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor @@ -20,6 +20,7 @@ @using OpenRpg.Items.Extensions @using OpenRpg.Items.TradeSkills.Templates @using OpenRpg.Items.TradeSkills +@using OpenRpg.Items.TradeSkills.Extensions @using OpenRpg.Items.Templates @inject IRandomizer Randomizer; @@ -31,60 +32,78 @@
    -

    Ores

    -
    -
    - @foreach (var itemTemplate in _ores) - { -
    - -
    - } -
    -
    +

    Generated Item Templates

    + +
    +
    + @foreach (var itemTemplate in _ores) + { +
    + +
    + } +
    +
    +
    -

    Ingots

    -
    -
    - @foreach (var itemTemplate in _ingots) - { -
    - -
    - } -
    -
    + +
    +
    + @foreach (var itemTemplate in _ingots) + { +
    + +
    + } +
    +
    +
    -

    Swords

    -
    -
    - @foreach (var itemTemplate in _swords) - { -
    - -
    - } -
    -
    + +
    +
    + @foreach (var itemTemplate in _swords) + { +
    + +
    + } +
    +
    +
    -

    Armour

    -
    -
    - @foreach (var itemTemplate in _armours) - { -
    - -
    - } -
    -
    + +
    +
    + @foreach (var itemTemplate in _armours) + { +
    + +
    + } +
    +
    +
    + +

    Crafting Templates

    @code { private ItemTemplatePatternGenerator _itemTemplatePatternGenerator; private IReadOnlyCollection _ores, _ingots, _swords, _armours; - public ManualTemplateAccessor TemplateAccessor = new ManualTemplateAccessor(); + private IReadOnlyCollection _ingotCrafting, _swordCrafting, _armourCrafting; + public ManualTemplateAccessor TemplateAccessor = new (); + + public interface ItemPatternTypes + { + public static int Unknown = 0; + public static int Ore = 1; + public static int Ingot = 2; + public static int Sword = 3; + public static int Armour = 4; + } + public interface MetalItemPatternLookups { public static int Unknown = 0; @@ -111,10 +130,12 @@ public class ItemCraftingTemplatePatternGeneratorConfig : PatternGeneratorVariables { - public string NamePattern { get; set; } public int StartingId { get; set; } public int SkillType { get; set; } - + public int InputPatternTypeId { get; set; } + public int OutputPatternTypeId { get; set; } + public int AmountRequired { get; set; } + public int AmountOutput { get; set; } } public class CraftingTemplatePatternGenerator : ITemplatePatternGenerator @@ -136,15 +157,28 @@ { var patternId = patternIds[i]; - var inputItemTemplates = new List(); - var outputItemTemplates = new List(); + var relatedPatternItemTemplates = TemplateAccessor + .GetAll() + .Where(x => x.Variables.PatternId == patternId) + .ToArray(); + + var inputTemplate = relatedPatternItemTemplates.First(x => x.Variables.PatternTypeId == config.InputPatternTypeId); + var inputItemEntry = new TradeSkillItemEntry { TemplateId = inputTemplate.Id }; + inputItemEntry.Variables.Amount = config.AmountRequired; + var inputItems = new List { inputItemEntry }; + + var outputTemplate = relatedPatternItemTemplates.First(x => x.Variables.PatternTypeId == config.OutputPatternTypeId); + var outputItemEntry = new TradeSkillItemEntry { TemplateId = outputTemplate.Id }; + outputItemEntry.Variables.Amount = config.AmountOutput; + var outputItems = new List { outputItemEntry }; var template = new ItemCraftingTemplate(); - template.Id = id++; + template.Id = id; template.SkillType = config.SkillType; - template.InputItems = inputItemTemplates; - template.OutputItems = outputItemTemplates; - template.Variables[CoreTemplateVariableTypes.PatternId] = patternId; + template.InputItems = inputItems; + template.OutputItems = outputItems; + template.Variables.PatternId = patternId; + template.Variables.PatternTypeId = config.PatternTypeId; itemCraftingTemplates.Add(template); } @@ -173,7 +207,8 @@ }; template.Variables.AssetCode = name.ToLower().Replace(" ", "-"); template.Variables.QualityType = FantasyItemQualityTypes.CommonQuality; - template.Variables[CoreTemplateVariableTypes.PatternId] = patternId; + template.Variables.PatternTypeId = config.PatternTypeId; + template.Variables.PatternId = patternId; if (config.Effects is not null) { @@ -196,8 +231,8 @@ var patternIds = MetalLookups.Keys.ToArray(); _itemTemplatePatternGenerator = new ItemTemplatePatternGenerator(); - _ores = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, NamePattern = namePattern, TypeName = "Ore", StartingId = 0, ItemType = FantasyItemTypes.GenericItem }); - _ingots = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, NamePattern = namePattern, TypeName = "Ingot", StartingId = 10, ItemType = FantasyItemTypes.GenericItem }); + _ores = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Ore, NamePattern = namePattern, TypeName = "Ore", StartingId = 0, ItemType = FantasyItemTypes.GenericItem }); + _ingots = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Ingot, NamePattern = namePattern, TypeName = "Ingot", StartingId = 10, ItemType = FantasyItemTypes.GenericItem }); var swordEffects = ProceduralEffectsBuilder.Create() .WithPrimaryEffect(new ScaledEffect() @@ -208,7 +243,7 @@ }) .Build(); - _swords = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, NamePattern = namePattern, TypeName = "Sword", StartingId = 20, ItemType = FantasyItemTypes.GenericWeapon, Effects = swordEffects}); + _swords = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Sword, NamePattern = namePattern, TypeName = "Sword", StartingId = 20, ItemType = FantasyItemTypes.GenericWeapon, Effects = swordEffects}); var armourEffects = ProceduralEffectsBuilder.Create() .WithPrimaryEffect(new ScaledEffect() @@ -225,7 +260,7 @@ }) .Build(); - _armours = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, NamePattern = namePattern, TypeName = "Armor", StartingId = 30, ItemType = FantasyItemTypes.UpperBodyArmour, Effects = armourEffects}); + _armours = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Armour, NamePattern = namePattern, TypeName = "Armor", StartingId = 30, ItemType = FantasyItemTypes.UpperBodyArmour, Effects = armourEffects}); TemplateAccessor.AddTemplates(_ores); TemplateAccessor.AddTemplates(_ingots); diff --git a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor index ecb71f9b..73883e04 100644 --- a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor +++ b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor @@ -1,7 +1,6 @@ @page "/trade-skills/crafting" @using OpenRpg.Core.Templates -@using OpenRpg.Items.TradeSkills @using OpenRpg.Demos.Infrastructure.Lookups @using OpenRpg.Items.TradeSkills.Extensions @using OpenRpg.Genres.Characters @@ -48,21 +47,9 @@ In this case we want to craft `Copper Ingots` which require 5x`Copper Ore` per ingot. -
    - @foreach (var inputItem in CopperIngotCraftingTemplate.InputItems) - { -
    - -
    - } -
    Makes
    - @foreach (var outputItem in CopperIngotCraftingTemplate.OutputItems) - { -
    - -
    - } -
    +
    + +
    @@ -80,21 +67,9 @@ so click the buttons below to give yourself some `Copper Ingots` and `Oak Logs` and keep leveling your smithing skill to 10. -
    - @foreach (var inputItem in CopperSwordCraftingTemplate.InputItems) - { -
    - -
    - } -
    Makes
    - @foreach (var outputItem in CopperSwordCraftingTemplate.OutputItems) - { -
    - -
    - } -
    +
    + +
    diff --git a/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs b/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs index 8e73d488..fc48aeb5 100644 --- a/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs +++ b/src/OpenRpg.Entities/Extensions/ITemplateVariableExtensions.cs @@ -3,7 +3,6 @@ using OpenRpg.Core.Extensions; using OpenRpg.Core.Requirements; using OpenRpg.Core.Templates.Variables; -using OpenRpg.Entities.Procedural; using OpenRpg.Entities.Procedural.Effects; using OpenRpg.Entities.Types; @@ -19,15 +18,15 @@ public static bool HasRequirements(this ITemplateVariables vars) public static bool HasProceduralEffects(this ITemplateVariables vars) => vars.ContainsKey(CoreTemplateVariableTypes.ProceduralEffects); + + public static bool HasPatternId(this ITemplateVariables vars) + => vars.ContainsKey(CoreTemplateVariableTypes.PatternId); + + public static bool HasPatternTypeId(this ITemplateVariables vars) + => vars.ContainsKey(CoreTemplateVariableTypes.PatternTypeId); extension(ITemplateVariables vars) { - public ProceduralEffects ProceduralEffects - { - get => vars.GetAsOrDefault(CoreTemplateVariableTypes.ProceduralEffects, () => new ProceduralEffects()); - set => vars[CoreTemplateVariableTypes.ProceduralEffects] = value; - } - public IReadOnlyCollection Effects { get => vars.GetAsOrDefault(CoreTemplateVariableTypes.Effects, IReadOnlyCollection.Empty); @@ -39,6 +38,24 @@ public IReadOnlyCollection Requirements get => vars.GetAsOrDefault(CoreTemplateVariableTypes.Requirements, IReadOnlyCollection.Empty); set => vars[CoreTemplateVariableTypes.Requirements] = value; } + + public ProceduralEffects ProceduralEffects + { + get => vars.GetAsOrDefault(CoreTemplateVariableTypes.ProceduralEffects, () => new ProceduralEffects()); + set => vars[CoreTemplateVariableTypes.ProceduralEffects] = value; + } + + public int PatternId + { + get => vars.GetInt(CoreTemplateVariableTypes.PatternId); + set => vars[CoreTemplateVariableTypes.PatternId] = value; + } + + public int PatternTypeId + { + get => vars.GetInt(CoreTemplateVariableTypes.PatternTypeId); + set => vars[CoreTemplateVariableTypes.PatternTypeId] = value; + } } } } \ No newline at end of file diff --git a/src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs b/src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs index 75214c1f..3401485e 100644 --- a/src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs +++ b/src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs @@ -4,6 +4,7 @@ namespace OpenRpg.Entities.Procedural.Patterns; public class PatternGeneratorVariables : ObjectVariables { + public int PatternTypeId { get; set; } public int[] PatternIds { get; set; } } \ No newline at end of file diff --git a/src/OpenRpg.Entities/Types/CoreTemplateVariableTypes.cs b/src/OpenRpg.Entities/Types/CoreTemplateVariableTypes.cs index d4124430..b53d9d73 100644 --- a/src/OpenRpg.Entities/Types/CoreTemplateVariableTypes.cs +++ b/src/OpenRpg.Entities/Types/CoreTemplateVariableTypes.cs @@ -14,6 +14,7 @@ public interface CoreTemplateVariableTypes public static int Requirements = 4003; // replaces IHasRequirements // Patterns - public static int PatternId = 4020; + public static int PatternTypeId = 4020; + public static int PatternId = 4021; } } \ No newline at end of file diff --git a/src/OpenRpg.Items/Extensions/ItemTemplateVariablesExtensions.cs b/src/OpenRpg.Items/Extensions/ItemTemplateVariablesExtensions.cs index bbf2d85f..2e7dda9e 100644 --- a/src/OpenRpg.Items/Extensions/ItemTemplateVariablesExtensions.cs +++ b/src/OpenRpg.Items/Extensions/ItemTemplateVariablesExtensions.cs @@ -6,6 +6,12 @@ namespace OpenRpg.Items.Extensions { public static class ItemTemplateVariablesExtensions { + public static bool HasQualityType(this ItemTemplateVariables vars) => vars.ContainsKey(ItemTemplateVariableTypes.QualityType); + public static bool HasValue(this ItemTemplateVariables vars) => vars.ContainsKey(ItemTemplateVariableTypes.Value); + public static bool HasMaxStacks(this ItemTemplateVariables vars) => vars.ContainsKey(ItemTemplateVariableTypes.MaxStacks); + public static bool HasWeight(this ItemTemplateVariables vars) => vars.ContainsKey(ItemTemplateVariableTypes.Weight); + public static bool HasSlotType(this ItemTemplateVariables vars) => vars.ContainsKey(ItemTemplateVariableTypes.SlotType); + extension(ItemTemplateVariables vars) { public int QualityType From a85b3f2ffc0815c0b0e1f6e0219dbd0449c63c5d Mon Sep 17 00:00:00 2001 From: LP Date: Tue, 20 Jan 2026 10:33:23 +0000 Subject: [PATCH 028/153] Got crafting template patterns working --- .../Procedural/PatternGeneratedItems.razor | 142 ++++++++++++++++-- 1 file changed, 133 insertions(+), 9 deletions(-) diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor index 12ccfc6f..247dd685 100644 --- a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor @@ -33,7 +33,7 @@

    Generated Item Templates

    - +
    @foreach (var itemTemplate in _ores) @@ -46,7 +46,7 @@
    - +
    @foreach (var itemTemplate in _ingots) @@ -59,7 +59,7 @@
    - +
    @foreach (var itemTemplate in _swords) @@ -72,7 +72,7 @@
    - +
    @foreach (var itemTemplate in _armours) @@ -87,9 +87,49 @@

    Crafting Templates

    + +
    +
    + @foreach (var craftingTemplate in _ingotCrafting) + { +
    + +
    + } +
    +
    +
    + + +
    +
    + @foreach (var craftingTemplate in _swordCrafting) + { +
    + +
    + } +
    +
    +
    + + +
    +
    + @foreach (var craftingTemplate in _armourCrafting) + { +
    + +
    + } +
    +
    +
    + @code { private ItemTemplatePatternGenerator _itemTemplatePatternGenerator; + private CraftingTemplatePatternGenerator _craftingTemplatePatternGenerator; private IReadOnlyCollection _ores, _ingots, _swords, _armours; private IReadOnlyCollection _ingotCrafting, _swordCrafting, _armourCrafting; public ManualTemplateAccessor TemplateAccessor = new (); @@ -227,12 +267,37 @@ { base.OnInitialized(); + _itemTemplatePatternGenerator = new ItemTemplatePatternGenerator(); + _craftingTemplatePatternGenerator = new CraftingTemplatePatternGenerator(TemplateAccessor); + + GenerateItemTemplates(); + GenerateItemCraftingTemplates(); + } + + private void GenerateItemTemplates() + { var namePattern = "{0} {1}"; var patternIds = MetalLookups.Keys.ToArray(); - _itemTemplatePatternGenerator = new ItemTemplatePatternGenerator(); - _ores = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Ore, NamePattern = namePattern, TypeName = "Ore", StartingId = 0, ItemType = FantasyItemTypes.GenericItem }); - _ingots = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Ingot, NamePattern = namePattern, TypeName = "Ingot", StartingId = 10, ItemType = FantasyItemTypes.GenericItem }); + _ores = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() + { + PatternIds = patternIds, + PatternTypeId = ItemPatternTypes.Ore, + NamePattern = namePattern, + TypeName = "Ore", + StartingId = 0, + ItemType = FantasyItemTypes.GenericItem + }); + + _ingots = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() + { + PatternIds = patternIds, + PatternTypeId = ItemPatternTypes.Ingot, + NamePattern = namePattern, + TypeName = "Ingot", + StartingId = 20, + ItemType = FantasyItemTypes.GenericItem + }); var swordEffects = ProceduralEffectsBuilder.Create() .WithPrimaryEffect(new ScaledEffect() @@ -243,7 +308,16 @@ }) .Build(); - _swords = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Sword, NamePattern = namePattern, TypeName = "Sword", StartingId = 20, ItemType = FantasyItemTypes.GenericWeapon, Effects = swordEffects}); + _swords = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() + { + PatternIds = patternIds, + PatternTypeId = ItemPatternTypes.Sword, + NamePattern = namePattern, + TypeName = "Sword", + StartingId = 40, + ItemType = FantasyItemTypes.GenericWeapon, + Effects = swordEffects + }); var armourEffects = ProceduralEffectsBuilder.Create() .WithPrimaryEffect(new ScaledEffect() @@ -260,7 +334,16 @@ }) .Build(); - _armours = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Armour, NamePattern = namePattern, TypeName = "Armor", StartingId = 30, ItemType = FantasyItemTypes.UpperBodyArmour, Effects = armourEffects}); + _armours = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() + { + PatternIds = patternIds, + PatternTypeId = ItemPatternTypes.Armour, + NamePattern = namePattern, + TypeName = "Armor", + StartingId = 60, + ItemType = FantasyItemTypes.UpperBodyArmour, + Effects = armourEffects + }); TemplateAccessor.AddTemplates(_ores); TemplateAccessor.AddTemplates(_ingots); @@ -268,4 +351,45 @@ TemplateAccessor.AddTemplates(_armours); } + private void GenerateItemCraftingTemplates() + { + var patternIds = MetalLookups.Keys.ToArray(); + + _ingotCrafting = _craftingTemplatePatternGenerator.Generate(new ItemCraftingTemplatePatternGeneratorConfig() + { + PatternIds = patternIds, + StartingId = 0, + SkillType = FantasyCraftingTradeSkillTypes.Smelting, + AmountRequired = 5, + InputPatternTypeId = ItemPatternTypes.Ore, + AmountOutput = 1, + OutputPatternTypeId = ItemPatternTypes.Ingot, + PatternTypeId = ItemPatternTypes.Ingot + }); + + _swordCrafting = _craftingTemplatePatternGenerator.Generate(new ItemCraftingTemplatePatternGeneratorConfig() + { + PatternIds = patternIds, + StartingId = 20, + SkillType = FantasyCraftingTradeSkillTypes.Smithing, + AmountRequired = 4, + InputPatternTypeId = ItemPatternTypes.Ingot, + AmountOutput = 1, + OutputPatternTypeId = ItemPatternTypes.Sword, + PatternTypeId = ItemPatternTypes.Sword + }); + + _armourCrafting = _craftingTemplatePatternGenerator.Generate(new ItemCraftingTemplatePatternGeneratorConfig() + { + PatternIds = patternIds, + StartingId = 40, + SkillType = FantasyCraftingTradeSkillTypes.Smithing, + AmountRequired = 4, + InputPatternTypeId = ItemPatternTypes.Ingot, + AmountOutput = 1, + OutputPatternTypeId = ItemPatternTypes.Armour, + PatternTypeId = ItemPatternTypes.Armour + }); + } + } \ No newline at end of file From a99336f268dba76e8c38f0b1d292be4b26da8aab Mon Sep 17 00:00:00 2001 From: LP Date: Wed, 21 Jan 2026 10:26:05 +0000 Subject: [PATCH 029/153] Updating the way trade skills are handled --- .../Types/CombatRequirementTypes.cs | 8 ++++ .../Data/CraftingTemplateDataGenerator.cs | 26 ++++++----- .../Data/GatheringTemplateDataGenerator.cs | 33 +++++++------- .../Procedural/PatternGeneratedItems.razor | 27 ++++++++++-- .../TradeSkills/CraftingTradeSkills.razor | 8 ++-- .../TradeSkills/GatheringTradeSkills.razor | 9 ++-- .../Helpers/TypesHelper.cs | 4 +- .../Common/TradeSkillDetailsEditor.razor | 43 ++++++++++++++++--- .../Templates/CraftingTemplateEditor.razor | 2 +- .../Templates/GatheringTemplateEditor.razor | 2 +- .../Types/CoreRequirementTypes.cs | 10 +++++ .../Extensions/TradeSkillStateExtensions.cs | 24 +++++------ .../Types/FantasyGatheringTradeSkillTypes.cs | 12 ------ ...killTypes.cs => FantasyTradeSkillTypes.cs} | 6 ++- .../DefaultCharacterRequirementChecker.cs | 3 +- .../Types/GenreRequirementTypes.cs | 23 ++++------ .../Calculator/ITradeSkillCalculator.cs | 1 - .../Calculator/TradeSkillCalculator.cs | 11 +---- ...temTradeSkillTemplateVariableExtensions.cs | 29 +++++++++++++ .../Extensions/RequirementExtensions.cs | 37 ++++++++++++++++ .../Templates/ITradeSkillData.cs | 23 ---------- .../Templates/ItemCraftingTemplate.cs | 17 +------- .../Templates/ItemGatheringTemplate.cs | 16 +------ .../Types/CraftingTradeSkillTypes.cs | 7 --- .../ItemTradeSkillTemplateVariableTypes.cs | 7 +++ .../Types/TradeSkillRequirementTypes.cs | 8 ++++ ...gTradeSkillTypes.cs => TradeSkillTypes.cs} | 2 +- .../IItemTradeSkillTemplateVariables.cs | 6 +++ .../ItemCraftingTemplateVariables.cs | 3 +- .../ItemGatheringTemplateVariables.cs | 3 +- .../Types/ItemRequirementTypes.cs | 9 ++++ src/OpenRpg.Quests/Quest.cs | 2 - .../Types/QuestRequirementTypes.cs | 10 +++++ .../TradeSkills/TradeSkillCalculatorTests.cs | 17 -------- 34 files changed, 265 insertions(+), 183 deletions(-) create mode 100644 src/OpenRpg.Combat/Types/CombatRequirementTypes.cs create mode 100644 src/OpenRpg.Entities/Types/CoreRequirementTypes.cs delete mode 100644 src/OpenRpg.Genres.Fantasy/Types/FantasyGatheringTradeSkillTypes.cs rename src/OpenRpg.Genres.Fantasy/Types/{FantasyCraftingTradeSkillTypes.cs => FantasyTradeSkillTypes.cs} (56%) create mode 100644 src/OpenRpg.Items.TradeSkills/Extensions/ItemTradeSkillTemplateVariableExtensions.cs create mode 100644 src/OpenRpg.Items.TradeSkills/Extensions/RequirementExtensions.cs delete mode 100644 src/OpenRpg.Items.TradeSkills/Templates/ITradeSkillData.cs delete mode 100644 src/OpenRpg.Items.TradeSkills/Types/CraftingTradeSkillTypes.cs create mode 100644 src/OpenRpg.Items.TradeSkills/Types/ItemTradeSkillTemplateVariableTypes.cs create mode 100644 src/OpenRpg.Items.TradeSkills/Types/TradeSkillRequirementTypes.cs rename src/OpenRpg.Items.TradeSkills/Types/{GatheringTradeSkillTypes.cs => TradeSkillTypes.cs} (69%) create mode 100644 src/OpenRpg.Items.TradeSkills/Variables/IItemTradeSkillTemplateVariables.cs create mode 100644 src/OpenRpg.Items/Types/ItemRequirementTypes.cs create mode 100644 src/OpenRpg.Quests/Types/QuestRequirementTypes.cs diff --git a/src/OpenRpg.Combat/Types/CombatRequirementTypes.cs b/src/OpenRpg.Combat/Types/CombatRequirementTypes.cs new file mode 100644 index 00000000..b3ddcee1 --- /dev/null +++ b/src/OpenRpg.Combat/Types/CombatRequirementTypes.cs @@ -0,0 +1,8 @@ +using OpenRpg.Entities.Types; + +namespace OpenRpg.Combat.Types; + +public interface CombatRequirementTypes : CoreRequirementTypes +{ + public static int ActiveEffectRequirement = 40; +} \ No newline at end of file diff --git a/src/OpenRpg.Demos.Infrastructure/Data/CraftingTemplateDataGenerator.cs b/src/OpenRpg.Demos.Infrastructure/Data/CraftingTemplateDataGenerator.cs index 6f244a7d..6b312439 100644 --- a/src/OpenRpg.Demos.Infrastructure/Data/CraftingTemplateDataGenerator.cs +++ b/src/OpenRpg.Demos.Infrastructure/Data/CraftingTemplateDataGenerator.cs @@ -1,10 +1,8 @@ using System.Collections.Generic; using OpenRpg.Core.Associations; using OpenRpg.Core.Requirements; -using OpenRpg.Core.Utils; using OpenRpg.Demos.Infrastructure.Lookups; using OpenRpg.Entities.Extensions; -using OpenRpg.Entities.Requirements; using OpenRpg.Genres.Fantasy.Types; using OpenRpg.Items.TradeSkills; using OpenRpg.Items.TradeSkills.Extensions; @@ -31,15 +29,15 @@ public ItemCraftingTemplate MakeCopperIngotCraftingTemplate() var outputItemEntry = new TradeSkillItemEntry() { TemplateId = ItemTemplateLookups.CopperIngot }; outputItemEntry.Variables.Amount = 1; - return new ItemCraftingTemplate() + var template = new ItemCraftingTemplate() { Id = ItemCraftingTemplateLookups.CopperIngot, - SkillType = FantasyCraftingTradeSkillTypes.Smelting, - SkillDifficulty = 0, - TimeToComplete = 2.0f, InputItems = new List() { inputItemEntry }, OutputItems = new List() { outputItemEntry }, }; + template.Variables.SkillType = FantasyTradeSkillTypes.Smelting; + template.Variables.TimeToAction = 2.0f; + return template; } public ItemCraftingTemplate MakeCopperSwordCraftingTemplate() @@ -55,18 +53,26 @@ public ItemCraftingTemplate MakeCopperSwordCraftingTemplate() var craftingTemplate = new ItemCraftingTemplate() { Id = ItemCraftingTemplateLookups.CopperSword, - SkillType = FantasyCraftingTradeSkillTypes.Smithing, - SkillDifficulty = 10, - TimeToComplete = 2.0f, InputItems = new List() { inputItem1Entry, inputItem2Entry }, OutputItems = new List() { outputItemEntry } }; + craftingTemplate.Variables.SkillType = FantasyTradeSkillTypes.Smithing; + craftingTemplate.Variables.TimeToAction = 2.0f; + craftingTemplate.Variables.Requirements = + [ + new Requirement + { + RequirementType = FantasyRequirementTypes.TradeSkillRequirement, + Association = new Association(FantasyTradeSkillTypes.Smithing, 10) + } + ]; + craftingTemplate.Variables.Requirements = new[] { new Requirement { RequirementType = FantasyRequirementTypes.TradeSkillRequirement, - Association = new Association(FantasyCraftingTradeSkillTypes.Smithing, 5) + Association = new Association(FantasyTradeSkillTypes.Smithing, 5) } }; return craftingTemplate; diff --git a/src/OpenRpg.Demos.Infrastructure/Data/GatheringTemplateDataGenerator.cs b/src/OpenRpg.Demos.Infrastructure/Data/GatheringTemplateDataGenerator.cs index 3445b995..fc60df5e 100644 --- a/src/OpenRpg.Demos.Infrastructure/Data/GatheringTemplateDataGenerator.cs +++ b/src/OpenRpg.Demos.Infrastructure/Data/GatheringTemplateDataGenerator.cs @@ -1,10 +1,8 @@ using System.Collections.Generic; using OpenRpg.Core.Associations; using OpenRpg.Core.Requirements; -using OpenRpg.Core.Utils; using OpenRpg.Demos.Infrastructure.Lookups; using OpenRpg.Entities.Extensions; -using OpenRpg.Entities.Requirements; using OpenRpg.Genres.Fantasy.Types; using OpenRpg.Items.TradeSkills; using OpenRpg.Items.TradeSkills.Extensions; @@ -29,14 +27,14 @@ public ItemGatheringTemplate MakeCopperOreGatheringTemplate() var itemEntry = new TradeSkillItemEntry() { TemplateId = ItemTemplateLookups.CopperOre }; itemEntry.Variables.Amount = 1; - return new ItemGatheringTemplate() + var template = new ItemGatheringTemplate() { Id = ItemGatheringTemplateLookups.CopperOre, - SkillType = FantasyGatheringTradeSkillTypes.Mining, - SkillDifficulty = 5, - TimeToComplete = 1.0f, OutputItems = new List() { itemEntry } }; + template.Variables.SkillType = FantasyTradeSkillTypes.Mining; + template.Variables.TimeToAction = 1.0f; + return template; } public ItemGatheringTemplate MakeIronOreGatheringTemplate() @@ -47,19 +45,18 @@ public ItemGatheringTemplate MakeIronOreGatheringTemplate() var template = new ItemGatheringTemplate() { Id = ItemGatheringTemplateLookups.IronOre, - SkillType = FantasyGatheringTradeSkillTypes.Mining, - SkillDifficulty = 15, - TimeToComplete = 1.0f, OutputItems = new List() { itemEntry } }; - template.Variables.Requirements = new[] - { + template.Variables.SkillType = FantasyTradeSkillTypes.Mining; + template.Variables.TimeToAction = 1.0f; + template.Variables.Requirements = + [ new Requirement { RequirementType = FantasyRequirementTypes.TradeSkillRequirement, - Association = new Association(FantasyGatheringTradeSkillTypes.Mining, 10) + Association = new Association(FantasyTradeSkillTypes.Mining, 10) } - }; + ]; return template; } @@ -68,14 +65,16 @@ public ItemGatheringTemplate MakeOakLogGatheringTemplate() var itemEntry = new TradeSkillItemEntry() { TemplateId = ItemTemplateLookups.OakLog }; itemEntry.Variables.Amount = 1; - return new ItemGatheringTemplate() + var template = new ItemGatheringTemplate() { Id = ItemGatheringTemplateLookups.OakLog, - SkillType = FantasyGatheringTradeSkillTypes.Logging, - SkillDifficulty = 0, - TimeToComplete = 1.0f, OutputItems = new List() { itemEntry } }; + + template.Variables.SkillType = FantasyTradeSkillTypes.Logging; + template.Variables.TimeToAction = 1.0f; + + return template; } } diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor index 247dd685..3052f930 100644 --- a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor @@ -1,6 +1,8 @@ @page "/procedural/pattern-generated-items" @using Newtonsoft.Json +@using OpenRpg.Core.Associations +@using OpenRpg.Core.Requirements @using OpenRpg.Core.Templates @using OpenRpg.Core.Utils @using OpenRpg.Core.Variables.General @@ -172,6 +174,7 @@ { public int StartingId { get; set; } public int SkillType { get; set; } + public ScalingFunction SkillScore { get; set; } public int InputPatternTypeId { get; set; } public int OutputPatternTypeId { get; set; } public int AmountRequired { get; set; } @@ -214,11 +217,24 @@ var template = new ItemCraftingTemplate(); template.Id = id; - template.SkillType = config.SkillType; template.InputItems = inputItems; template.OutputItems = outputItems; template.Variables.PatternId = patternId; template.Variables.PatternTypeId = config.PatternTypeId; + template.Variables.SkillType = config.SkillType; + + var skillDifficulty = (int)Math.Round(config.SkillScore.Plot(patternId)); + if(skillDifficulty > 0) + { + template.Variables.Requirements = [ + new Requirement + { + RequirementType = FantasyRequirementTypes.TradeSkillRequirement, + Association = new Association(config.SkillType, skillDifficulty) + } + ]; + } + itemCraftingTemplates.Add(template); } @@ -359,7 +375,8 @@ { PatternIds = patternIds, StartingId = 0, - SkillType = FantasyCraftingTradeSkillTypes.Smelting, + SkillType = FantasyTradeSkillTypes.Smelting, + SkillScore = new ScalingFunction(PresetCurves.Linear, new RangeF(0, 200), new RangeF(0, patternIds.Length)), AmountRequired = 5, InputPatternTypeId = ItemPatternTypes.Ore, AmountOutput = 1, @@ -371,7 +388,8 @@ { PatternIds = patternIds, StartingId = 20, - SkillType = FantasyCraftingTradeSkillTypes.Smithing, + SkillType = FantasyTradeSkillTypes.Smithing, + SkillScore = new ScalingFunction(PresetCurves.Linear, new RangeF(0, 200), new RangeF(0, patternIds.Length)), AmountRequired = 4, InputPatternTypeId = ItemPatternTypes.Ingot, AmountOutput = 1, @@ -383,7 +401,8 @@ { PatternIds = patternIds, StartingId = 40, - SkillType = FantasyCraftingTradeSkillTypes.Smithing, + SkillType = FantasyTradeSkillTypes.Smithing, + SkillScore = new ScalingFunction(PresetCurves.Linear, new RangeF(0, 200), new RangeF(0, patternIds.Length)), AmountRequired = 4, InputPatternTypeId = ItemPatternTypes.Ingot, AmountOutput = 1, diff --git a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor index 73883e04..d24ac0ef 100644 --- a/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor +++ b/src/OpenRpg.Demos.Web/Pages/TradeSkills/CraftingTradeSkills.razor @@ -11,6 +11,7 @@ @using OpenRpg.Core.Utils @using OpenRpg.Entities.Extensions @using OpenRpg.Genres.Fantasy.Extensions +@using OpenRpg.Genres.Fantasy.Types @using OpenRpg.Items.Extensions @using OpenRpg.Items.Templates @using OpenRpg.Items.TradeSkills.State @@ -130,7 +131,7 @@ public bool IsCrafting { get; set; } public ItemCraftingTemplate CurrentTemplate { get; set; } - public float CurrentGatherTime => (CurrentTemplate?.TimeToComplete / 2 ?? 0.0f); + public float CurrentGatherTime => (CurrentTemplate?.Variables.TimeToAction / 2 ?? 0.0f); public string CurrentCraftName { get @@ -202,8 +203,9 @@ CurrentTemplate.CraftFrom(CraftingInventory, TemplateAccessor); ActionBarRef?.Reset(); - var currentSkill = TradeSkillState.Smithing; - var tradeSkillPoints = TradeSkillCalculator.CalculateSkillUpPointsFor(currentSkill, CurrentTemplate.SkillDifficulty); + var currentSkillScore = TradeSkillState.Smithing; + var skillDifficulty = CurrentTemplate.Variables.Requirements.GetTradeSkillRequirementValue(FantasyTradeSkillTypes.Smithing); + var tradeSkillPoints = TradeSkillCalculator.CalculateSkillUpPointsFor(currentSkillScore, skillDifficulty); TradeSkillState.AddSmithing(tradeSkillPoints); CraftingInventoryRef.Refresh(); diff --git a/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor b/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor index 52133ee7..b5c0a1c0 100644 --- a/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor +++ b/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor @@ -12,8 +12,10 @@ @using OpenRpg.Core.Utils @using OpenRpg.Entities.Extensions @using OpenRpg.Genres.Fantasy.Extensions +@using OpenRpg.Genres.Fantasy.Types @using OpenRpg.Items.Extensions @using OpenRpg.Items.TradeSkills.State +@using OpenRpg.Items.TradeSkills.Types @using Inventory = OpenRpg.Items.Inventories.Inventory; @@ -181,7 +183,7 @@ public bool IsGathering { get; set; } public ItemGatheringTemplate CurrentTemplate { get; set; } - public float CurrentGatherTime => (CurrentTemplate?.TimeToComplete ?? 0.0f); + public float CurrentGatherTime => (CurrentTemplate?.Variables.TimeToAction ?? 0.0f); public string CurrentGatherName { get @@ -229,8 +231,9 @@ CurrentTemplate.GatherInto(Example2Inventory, TemplateAccessor); Example2InventoryRef.Refresh(); - var currentMiningSkill = TradeSkillState.Mining; - var tradeSkillPoints = TradeSkillCalculator.CalculateSkillUpPointsFor(currentMiningSkill, CurrentTemplate.SkillDifficulty); + var currentSkillScore = TradeSkillState.Mining; + var skillDifficulty = CurrentTemplate.Variables.Requirements.GetTradeSkillRequirementValue(FantasyTradeSkillTypes.Mining); + var tradeSkillPoints = TradeSkillCalculator.CalculateSkillUpPointsFor(currentSkillScore, skillDifficulty); TradeSkillState.AddMining(tradeSkillPoints); InvokeAsync(StateHasChanged); diff --git a/src/OpenRpg.Editor.Infrastructure/Helpers/TypesHelper.cs b/src/OpenRpg.Editor.Infrastructure/Helpers/TypesHelper.cs index 29f0ec7e..9c736aa5 100644 --- a/src/OpenRpg.Editor.Infrastructure/Helpers/TypesHelper.cs +++ b/src/OpenRpg.Editor.Infrastructure/Helpers/TypesHelper.cs @@ -36,7 +36,7 @@ public static OptionData[] GetTypesFor(Type typesObject) public static readonly OptionData[] GetEffectScalingType = GetTypesFor(typeof(CoreEffectScalingTypes)).OrderBy(x => x.Id).ToArray(); public static readonly OptionData[] GetStatTypes = GetTypesFor(typeof(FantasyEntityStatsVariableTypes)).OrderBy(x => x.Id).ToArray(); public static readonly OptionData[] GetStateTypes = GetTypesFor(typeof(FantasyEntityStateVariableTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetCraftingSkillTypes = GetTypesFor(typeof(FantasyCraftingTradeSkillTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetGatheringSkillTypes = GetTypesFor(typeof(FantasyGatheringTradeSkillTypes)).OrderBy(x => x.Id).ToArray(); + public static readonly OptionData[] GetCraftingSkillTypes = GetTypesFor(typeof(FantasyTradeSkillTypes)).OrderBy(x => x.Id).ToArray(); + public static readonly OptionData[] GetGatheringSkillTypes = GetTypesFor(typeof(FantasyTradeSkillTypes)).OrderBy(x => x.Id).ToArray(); } } \ No newline at end of file diff --git a/src/OpenRpg.Editor.UI/Components/Editors/Common/TradeSkillDetailsEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/Common/TradeSkillDetailsEditor.razor index 54ef4f93..02ad4000 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/Common/TradeSkillDetailsEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/Common/TradeSkillDetailsEditor.razor @@ -1,5 +1,10 @@ +@using OpenRpg.Core.Associations +@using OpenRpg.Core.Requirements @using OpenRpg.Editor.Infrastructure.Helpers -@using OpenRpg.Items.TradeSkills.Templates +@using OpenRpg.Entities.Extensions +@using OpenRpg.Genres.Fantasy.Types +@using OpenRpg.Items.TradeSkills.Extensions +@using OpenRpg.Items.TradeSkills.Variables
    @@ -9,7 +14,7 @@
    - @{ var gatheringTypes = IsGatheringSkill ? TypesHelper.GetGatheringSkillTypes : TypesHelper.GetCraftingSkillTypes; } @foreach (var tradeSkillType in gatheringTypes) { @@ -28,8 +33,7 @@
    - +
    @@ -42,7 +46,7 @@
    + @bind="@TradeSkillTemplateVariables.TimeToAction" />
    @@ -50,8 +54,35 @@ @code { [Parameter] - public ITradeSkillData TradeSkillData { get; set; } + public IItemTradeSkillTemplateVariables TradeSkillTemplateVariables { get; set; } [Parameter] public bool IsGatheringSkill { get; set; } + + public int SkillDifficulty + { + get + { + if(!TradeSkillTemplateVariables.HasRequirements()) { return 0; } + return TradeSkillTemplateVariables.Requirements.GetTradeSkillRequirementValue(TradeSkillTemplateVariables.SkillType); + } + set + { + if(!TradeSkillTemplateVariables.HasRequirements()) + { + TradeSkillTemplateVariables.Requirements = new[] + { + new Requirement + { + RequirementType = FantasyRequirementTypes.TradeSkillRequirement, + Association = new Association(TradeSkillTemplateVariables.SkillType, value) + } + }; + return; + } + + var requirement = TradeSkillTemplateVariables.Requirements.GetTradeSkillRequirement(TradeSkillTemplateVariables.SkillType); + requirement.Association = new Association(TradeSkillTemplateVariables.SkillType, value); + } + } } \ No newline at end of file diff --git a/src/OpenRpg.Editor.UI/Components/Editors/Templates/CraftingTemplateEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/Templates/CraftingTemplateEditor.razor index c1b23e46..df3d7461 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/Templates/CraftingTemplateEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/Templates/CraftingTemplateEditor.razor @@ -3,7 +3,7 @@ - + diff --git a/src/OpenRpg.Editor.UI/Components/Editors/Templates/GatheringTemplateEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/Templates/GatheringTemplateEditor.razor index 85bed161..d1a986ea 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/Templates/GatheringTemplateEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/Templates/GatheringTemplateEditor.razor @@ -3,7 +3,7 @@ - + diff --git a/src/OpenRpg.Entities/Types/CoreRequirementTypes.cs b/src/OpenRpg.Entities/Types/CoreRequirementTypes.cs new file mode 100644 index 00000000..7af056f4 --- /dev/null +++ b/src/OpenRpg.Entities/Types/CoreRequirementTypes.cs @@ -0,0 +1,10 @@ +namespace OpenRpg.Entities.Types; + +public interface CoreRequirementTypes +{ + public static int Unknown = 0; + + public static readonly int RaceRequirement = 1; + public static readonly int ClassRequirement = 2; + public static readonly int GenderRequirement = 3; +} \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Extensions/TradeSkillStateExtensions.cs b/src/OpenRpg.Genres.Fantasy/Extensions/TradeSkillStateExtensions.cs index c8a6d1b6..0e4612c5 100644 --- a/src/OpenRpg.Genres.Fantasy/Extensions/TradeSkillStateExtensions.cs +++ b/src/OpenRpg.Genres.Fantasy/Extensions/TradeSkillStateExtensions.cs @@ -10,32 +10,32 @@ public static class TradeSkillStateExtensions { public int Logging { - get => state.Get(FantasyGatheringTradeSkillTypes.Logging); - set => state[FantasyGatheringTradeSkillTypes.Logging] = value; + get => state.Get(FantasyTradeSkillTypes.Logging); + set => state[FantasyTradeSkillTypes.Logging] = value; } public int Mining { - get => state.Get(FantasyGatheringTradeSkillTypes.Mining); - set => state[FantasyGatheringTradeSkillTypes.Mining] = value; + get => state.Get(FantasyTradeSkillTypes.Mining); + set => state[FantasyTradeSkillTypes.Mining] = value; } public int Smelting { - get => state.Get(FantasyCraftingTradeSkillTypes.Smelting); - set => state[FantasyCraftingTradeSkillTypes.Smelting] = value; + get => state.Get(FantasyTradeSkillTypes.Smelting); + set => state[FantasyTradeSkillTypes.Smelting] = value; } public int Smithing { - get => state.Get(FantasyCraftingTradeSkillTypes.Smithing); - set => state[FantasyCraftingTradeSkillTypes.Smithing] = value; + get => state.Get(FantasyTradeSkillTypes.Smithing); + set => state[FantasyTradeSkillTypes.Smithing] = value; } } - public static void AddLogging(this TradeSkillState state, int addition) => state.AddValue(FantasyGatheringTradeSkillTypes.Logging, addition); - public static void AddMining(this TradeSkillState state, int addition) => state.AddValue(FantasyGatheringTradeSkillTypes.Mining, addition); - public static void AddSmelting(this TradeSkillState state, int addition) => state.AddValue(FantasyCraftingTradeSkillTypes.Smelting, addition); - public static void AddSmithing(this TradeSkillState state, int addition) => state.AddValue(FantasyCraftingTradeSkillTypes.Smithing, addition); + public static void AddLogging(this TradeSkillState state, int addition) => state.AddValue(FantasyTradeSkillTypes.Logging, addition); + public static void AddMining(this TradeSkillState state, int addition) => state.AddValue(FantasyTradeSkillTypes.Mining, addition); + public static void AddSmelting(this TradeSkillState state, int addition) => state.AddValue(FantasyTradeSkillTypes.Smelting, addition); + public static void AddSmithing(this TradeSkillState state, int addition) => state.AddValue(FantasyTradeSkillTypes.Smithing, addition); } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Types/FantasyGatheringTradeSkillTypes.cs b/src/OpenRpg.Genres.Fantasy/Types/FantasyGatheringTradeSkillTypes.cs deleted file mode 100644 index 675be577..00000000 --- a/src/OpenRpg.Genres.Fantasy/Types/FantasyGatheringTradeSkillTypes.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace OpenRpg.Genres.Fantasy.Types -{ - public interface FantasyGatheringTradeSkillTypes - { - public static readonly int Unknown = 0; - - // Gathering - public static readonly int Logging = 1; - public static readonly int Mining = 2; - - } -} \ No newline at end of file diff --git a/src/OpenRpg.Genres.Fantasy/Types/FantasyCraftingTradeSkillTypes.cs b/src/OpenRpg.Genres.Fantasy/Types/FantasyTradeSkillTypes.cs similarity index 56% rename from src/OpenRpg.Genres.Fantasy/Types/FantasyCraftingTradeSkillTypes.cs rename to src/OpenRpg.Genres.Fantasy/Types/FantasyTradeSkillTypes.cs index c23389e8..7b36d7e9 100644 --- a/src/OpenRpg.Genres.Fantasy/Types/FantasyCraftingTradeSkillTypes.cs +++ b/src/OpenRpg.Genres.Fantasy/Types/FantasyTradeSkillTypes.cs @@ -1,11 +1,15 @@ namespace OpenRpg.Genres.Fantasy.Types { - public interface FantasyCraftingTradeSkillTypes + public interface FantasyTradeSkillTypes { public static readonly int Unknown = 0; // Crafting public static readonly int Smelting = 1; public static readonly int Smithing = 2; + + // Gathering + public static readonly int Logging = 30; + public static readonly int Mining = 31; } } \ No newline at end of file diff --git a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs index 2153703d..c4cc8a0b 100644 --- a/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs +++ b/src/OpenRpg.Genres/Requirements/DefaultCharacterRequirementChecker.cs @@ -2,7 +2,6 @@ using OpenRpg.Combat.Extensions; using OpenRpg.Core.Requirements; using OpenRpg.Entities.Extensions; -using OpenRpg.Entities.Requirements; using OpenRpg.Genres.Characters; using OpenRpg.Genres.Extensions; using OpenRpg.Genres.Types; @@ -91,7 +90,7 @@ public virtual bool IsRequirementMet(Character character, Requirement requiremen if(requirement.RequirementType == GenreRequirementTypes.MovementSpeedRequirement) { return character.Stats.MovementSpeed >= requirement.Association.AssociatedValue; } - + if (requirement.RequirementType == GenreRequirementTypes.ActiveEffectRequirement) { if(!character.Variables.HasActiveEffects()) { return false; } diff --git a/src/OpenRpg.Genres/Types/GenreRequirementTypes.cs b/src/OpenRpg.Genres/Types/GenreRequirementTypes.cs index 9be398cc..b2ee06bc 100644 --- a/src/OpenRpg.Genres/Types/GenreRequirementTypes.cs +++ b/src/OpenRpg.Genres/Types/GenreRequirementTypes.cs @@ -1,21 +1,14 @@ +using OpenRpg.Combat.Types; +using OpenRpg.Items.TradeSkills.Types; +using OpenRpg.Quests.Types; + namespace OpenRpg.Genres.Types { - public interface GenreRequirementTypes + public interface GenreRequirementTypes : TradeSkillRequirementTypes, CombatRequirementTypes, QuestRequirementTypes { - public static readonly int UnknownRequirement = 0; - - public static readonly int RaceRequirement = 1; - public static readonly int ClassRequirement = 2; - public static readonly int TriggerRequirement = 4; - public static readonly int QuestStateRequirement = 5; - public static readonly int InventoryItemRequirement = 6; - public static readonly int EquipmentItemRequirement = 7; - public static readonly int GenderRequirement = 8; - public static readonly int ActiveEffectRequirement = 9; - public static readonly int MaxHealthRequirement = 10; - public static readonly int TradeSkillRequirement = 11; - public static readonly int MaxStaminaRequirement = 12; - public static readonly int MovementSpeedRequirement = 13; + public static readonly int MaxHealthRequirement = 100; + public static readonly int MaxStaminaRequirement = 101; + public static readonly int MovementSpeedRequirement = 103; } } \ No newline at end of file diff --git a/src/OpenRpg.Items.TradeSkills/Calculator/ITradeSkillCalculator.cs b/src/OpenRpg.Items.TradeSkills/Calculator/ITradeSkillCalculator.cs index d2a4c46d..95bb1cc2 100644 --- a/src/OpenRpg.Items.TradeSkills/Calculator/ITradeSkillCalculator.cs +++ b/src/OpenRpg.Items.TradeSkills/Calculator/ITradeSkillCalculator.cs @@ -6,7 +6,6 @@ public interface ITradeSkillCalculator float PointMultiplier { get; set; } float MaximumSkillDifference { get; set; } - bool CanUseSkill(int skillScore, int skillDifficulty); int CalculateSkillUpPointsFor(int skillScore, int skillDifficulty); } } \ No newline at end of file diff --git a/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs b/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs index fbc4a19e..908c04fe 100644 --- a/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs +++ b/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs @@ -39,18 +39,11 @@ public class TradeSkillCalculator : ITradeSkillCalculator /// /// The randomizer to use /// The optional curve function to apply, by default uses inverse linear - public TradeSkillCalculator(IRandomizer randomizer, ICurveFunction curveFunction = null) + public TradeSkillCalculator(IRandomizer randomizer) { - SkillPointCurve = new ScalingFunction(curveFunction ?? PresetCurves.InverseLinear, 0, 1, 0, MaximumSkillDifference); + SkillPointCurve = new ScalingFunction(PresetCurves.BellCurve, new RangeF(0, 1), new RangeF(0, MaximumSkillDifference)); Randomizer = randomizer; } - - public bool CanUseSkill(int skillScore, int skillDifficulty) - { - var skillDifference = skillDifficulty - skillScore; - var absoluteScore = Math.Abs(skillDifference); - return absoluteScore <= MaximumSkillDifference; - } public int CalculateSkillUpPointsFor(int skillScore, int skillDifficulty) { diff --git a/src/OpenRpg.Items.TradeSkills/Extensions/ItemTradeSkillTemplateVariableExtensions.cs b/src/OpenRpg.Items.TradeSkills/Extensions/ItemTradeSkillTemplateVariableExtensions.cs new file mode 100644 index 00000000..8523cef1 --- /dev/null +++ b/src/OpenRpg.Items.TradeSkills/Extensions/ItemTradeSkillTemplateVariableExtensions.cs @@ -0,0 +1,29 @@ +using OpenRpg.Core.Extensions; +using OpenRpg.Items.TradeSkills.Types; +using OpenRpg.Items.TradeSkills.Variables; + +namespace OpenRpg.Items.TradeSkills.Extensions; + +public static class ItemTradeSkillTemplateVariableExtensions +{ + public static bool HasSkillType(this IItemTradeSkillTemplateVariables vars) + { return vars.ContainsKey(ItemTradeSkillTemplateVariableTypes.SkillType); } + + public static bool HasTimeToAction(this IItemTradeSkillTemplateVariables vars) + { return vars.ContainsKey(ItemTradeSkillTemplateVariableTypes.TimeToComplete); } + + extension(IItemTradeSkillTemplateVariables vars) + { + public int SkillType + { + get => vars.GetInt(ItemTradeSkillTemplateVariableTypes.SkillType); + set => vars[ItemTradeSkillTemplateVariableTypes.SkillType] = value; + } + + public float TimeToAction + { + get => vars.GetInt(ItemTradeSkillTemplateVariableTypes.TimeToComplete); + set => vars[ItemTradeSkillTemplateVariableTypes.TimeToComplete] = value; + } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Items.TradeSkills/Extensions/RequirementExtensions.cs b/src/OpenRpg.Items.TradeSkills/Extensions/RequirementExtensions.cs new file mode 100644 index 00000000..c65d85d9 --- /dev/null +++ b/src/OpenRpg.Items.TradeSkills/Extensions/RequirementExtensions.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Linq; +using OpenRpg.Core.Associations; +using OpenRpg.Core.Requirements; +using OpenRpg.Items.TradeSkills.Types; + +namespace OpenRpg.Items.TradeSkills.Extensions; + +public static class RequirementExtensions +{ + extension(IReadOnlyCollection requirements) + { + public bool HasTradeSkillRequirement() + { return requirements.Any(x => x.RequirementType == TradeSkillRequirementTypes.TradeSkillRequirement); } + + public bool HasTradeSkillRequirement(int tradeSkillType) + { return requirements.Any(x => x.RequirementType == TradeSkillRequirementTypes.TradeSkillRequirement && x.Association.AssociatedId == tradeSkillType); } + + public IReadOnlyCollection GetTradeSkillRequirements() + { + return requirements + .Where(x => x.RequirementType == TradeSkillRequirementTypes.TradeSkillRequirement) + .ToArray(); + } + + public Requirement GetTradeSkillRequirement(int tradeSkillType) + { + return requirements + .FirstOrDefault(x => + x.RequirementType == TradeSkillRequirementTypes.TradeSkillRequirement && + x.Association.AssociatedId == tradeSkillType); + } + + public int GetTradeSkillRequirementValue(int tradeSkillType) + { return requirements.GetTradeSkillRequirement(tradeSkillType)?.Association.AssociatedValue ?? 0; } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Items.TradeSkills/Templates/ITradeSkillData.cs b/src/OpenRpg.Items.TradeSkills/Templates/ITradeSkillData.cs deleted file mode 100644 index 238979d2..00000000 --- a/src/OpenRpg.Items.TradeSkills/Templates/ITradeSkillData.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace OpenRpg.Items.TradeSkills.Templates -{ - /// - /// The core mechanical information common among most trade skills - /// - public interface ITradeSkillData - { - /// - /// Gathering time in seconds, per unit gathered - /// - public float TimeToComplete { get; set; } - - /// - /// The category of skill type used for Gathering/Crafting - /// - public int SkillType { get; set; } - - /// - /// Indicates how difficult this is to get, effects if you can use the trade skill and skill up rates - /// - public int SkillDifficulty { get; set; } - } -} \ No newline at end of file diff --git a/src/OpenRpg.Items.TradeSkills/Templates/ItemCraftingTemplate.cs b/src/OpenRpg.Items.TradeSkills/Templates/ItemCraftingTemplate.cs index 7d08069a..bed92f2c 100644 --- a/src/OpenRpg.Items.TradeSkills/Templates/ItemCraftingTemplate.cs +++ b/src/OpenRpg.Items.TradeSkills/Templates/ItemCraftingTemplate.cs @@ -4,7 +4,7 @@ namespace OpenRpg.Items.TradeSkills.Templates { - public class ItemCraftingTemplate : ITemplate, ITradeSkillData + public class ItemCraftingTemplate : ITemplate { /// /// The Id for this template @@ -20,21 +20,6 @@ public class ItemCraftingTemplate : ITemplate, IT /// The description locale id /// public string DescriptionLocaleId { get; set; } - - /// - /// Gathering time in seconds, per unit gathered - /// - public float TimeToComplete { get; set; } = 1.0f; - - /// - /// The category of skill type used for Gathering - /// - public int SkillType { get; set; } - - /// - /// Indicates how difficult this is to get, effects if you can use the trade skill and skill up rates - /// - public int SkillDifficulty { get; set; } /// /// Variables for this template diff --git a/src/OpenRpg.Items.TradeSkills/Templates/ItemGatheringTemplate.cs b/src/OpenRpg.Items.TradeSkills/Templates/ItemGatheringTemplate.cs index 98fb17cb..26f670d4 100644 --- a/src/OpenRpg.Items.TradeSkills/Templates/ItemGatheringTemplate.cs +++ b/src/OpenRpg.Items.TradeSkills/Templates/ItemGatheringTemplate.cs @@ -1,13 +1,10 @@ -using System; -using System.Collections.Generic; -using OpenRpg.Core.Requirements; +using System.Collections.Generic; using OpenRpg.Core.Templates; -using OpenRpg.Entities.Requirements; using OpenRpg.Items.TradeSkills.Variables; namespace OpenRpg.Items.TradeSkills.Templates { - public class ItemGatheringTemplate : ITemplate, ITradeSkillData + public class ItemGatheringTemplate : ITemplate { /// public int Id { get; set; } @@ -17,15 +14,6 @@ public class ItemGatheringTemplate : ITemplate, /// public string DescriptionLocaleId { get; set; } - - /// - public float TimeToComplete { get; set; } = 1.0f; - - /// - public int SkillType { get; set; } - - /// - public int SkillDifficulty { get; set; } /// public ItemGatheringTemplateVariables Variables { get; set; } = new ItemGatheringTemplateVariables(); diff --git a/src/OpenRpg.Items.TradeSkills/Types/CraftingTradeSkillTypes.cs b/src/OpenRpg.Items.TradeSkills/Types/CraftingTradeSkillTypes.cs deleted file mode 100644 index 53b5fa21..00000000 --- a/src/OpenRpg.Items.TradeSkills/Types/CraftingTradeSkillTypes.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace OpenRpg.Items.TradeSkills.Types -{ - public interface CraftingTradeSkillTypes - { - public static readonly int Unknown = 0; - } -} \ No newline at end of file diff --git a/src/OpenRpg.Items.TradeSkills/Types/ItemTradeSkillTemplateVariableTypes.cs b/src/OpenRpg.Items.TradeSkills/Types/ItemTradeSkillTemplateVariableTypes.cs new file mode 100644 index 00000000..f535a336 --- /dev/null +++ b/src/OpenRpg.Items.TradeSkills/Types/ItemTradeSkillTemplateVariableTypes.cs @@ -0,0 +1,7 @@ +namespace OpenRpg.Items.TradeSkills.Types; + +public interface ItemTradeSkillTemplateVariableTypes +{ + public static readonly int SkillType = 10; + public static readonly int TimeToComplete = 11; +} \ No newline at end of file diff --git a/src/OpenRpg.Items.TradeSkills/Types/TradeSkillRequirementTypes.cs b/src/OpenRpg.Items.TradeSkills/Types/TradeSkillRequirementTypes.cs new file mode 100644 index 00000000..93b78e11 --- /dev/null +++ b/src/OpenRpg.Items.TradeSkills/Types/TradeSkillRequirementTypes.cs @@ -0,0 +1,8 @@ +using OpenRpg.Items.Types; + +namespace OpenRpg.Items.TradeSkills.Types; + +public interface TradeSkillRequirementTypes : ItemRequirementTypes +{ + public static readonly int TradeSkillRequirement = 80; +} \ No newline at end of file diff --git a/src/OpenRpg.Items.TradeSkills/Types/GatheringTradeSkillTypes.cs b/src/OpenRpg.Items.TradeSkills/Types/TradeSkillTypes.cs similarity index 69% rename from src/OpenRpg.Items.TradeSkills/Types/GatheringTradeSkillTypes.cs rename to src/OpenRpg.Items.TradeSkills/Types/TradeSkillTypes.cs index 1a4c39fd..93fa39ec 100644 --- a/src/OpenRpg.Items.TradeSkills/Types/GatheringTradeSkillTypes.cs +++ b/src/OpenRpg.Items.TradeSkills/Types/TradeSkillTypes.cs @@ -1,6 +1,6 @@ namespace OpenRpg.Items.TradeSkills.Types { - public interface GatheringTradeSkillTypes + public interface TradeSkillTypes { public static readonly int Unknown = 0; } diff --git a/src/OpenRpg.Items.TradeSkills/Variables/IItemTradeSkillTemplateVariables.cs b/src/OpenRpg.Items.TradeSkills/Variables/IItemTradeSkillTemplateVariables.cs new file mode 100644 index 00000000..cb75a340 --- /dev/null +++ b/src/OpenRpg.Items.TradeSkills/Variables/IItemTradeSkillTemplateVariables.cs @@ -0,0 +1,6 @@ +using OpenRpg.Core.Templates.Variables; + +namespace OpenRpg.Items.TradeSkills.Variables; + +public interface IItemTradeSkillTemplateVariables : ITemplateVariables +{} \ No newline at end of file diff --git a/src/OpenRpg.Items.TradeSkills/Variables/ItemCraftingTemplateVariables.cs b/src/OpenRpg.Items.TradeSkills/Variables/ItemCraftingTemplateVariables.cs index 0d66c98b..224d90f5 100644 --- a/src/OpenRpg.Items.TradeSkills/Variables/ItemCraftingTemplateVariables.cs +++ b/src/OpenRpg.Items.TradeSkills/Variables/ItemCraftingTemplateVariables.cs @@ -1,11 +1,10 @@ using System.Collections.Generic; -using OpenRpg.Core.Templates.Variables; using OpenRpg.Core.Variables.General; using OpenRpg.Items.TradeSkills.Types; namespace OpenRpg.Items.TradeSkills.Variables { - public class ItemCraftingTemplateVariables : ObjectVariables, ITemplateVariables + public class ItemCraftingTemplateVariables : ObjectVariables, IItemTradeSkillTemplateVariables { public ItemCraftingTemplateVariables(IDictionary internalVariables = null) : base(TradeSkillCoreVariableTypes.ItemCraftingTemplateVariables, internalVariables) { diff --git a/src/OpenRpg.Items.TradeSkills/Variables/ItemGatheringTemplateVariables.cs b/src/OpenRpg.Items.TradeSkills/Variables/ItemGatheringTemplateVariables.cs index de309270..77ec0b3d 100644 --- a/src/OpenRpg.Items.TradeSkills/Variables/ItemGatheringTemplateVariables.cs +++ b/src/OpenRpg.Items.TradeSkills/Variables/ItemGatheringTemplateVariables.cs @@ -1,11 +1,10 @@ using System.Collections.Generic; -using OpenRpg.Core.Templates.Variables; using OpenRpg.Core.Variables.General; using OpenRpg.Items.TradeSkills.Types; namespace OpenRpg.Items.TradeSkills.Variables { - public class ItemGatheringTemplateVariables : ObjectVariables, ITemplateVariables + public class ItemGatheringTemplateVariables : ObjectVariables, IItemTradeSkillTemplateVariables { public ItemGatheringTemplateVariables(IDictionary internalVariables = null) : base(TradeSkillCoreVariableTypes.ItemGatheringTemplateVariables, internalVariables) { diff --git a/src/OpenRpg.Items/Types/ItemRequirementTypes.cs b/src/OpenRpg.Items/Types/ItemRequirementTypes.cs new file mode 100644 index 00000000..7564e7da --- /dev/null +++ b/src/OpenRpg.Items/Types/ItemRequirementTypes.cs @@ -0,0 +1,9 @@ +using OpenRpg.Entities.Types; + +namespace OpenRpg.Items.Types; + +public interface ItemRequirementTypes : CoreRequirementTypes +{ + public static readonly int InventoryItemRequirement = 20; + public static readonly int EquipmentItemRequirement = 21; +} \ No newline at end of file diff --git a/src/OpenRpg.Quests/Quest.cs b/src/OpenRpg.Quests/Quest.cs index d8d77163..344b6777 100644 --- a/src/OpenRpg.Quests/Quest.cs +++ b/src/OpenRpg.Quests/Quest.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using OpenRpg.Core.Requirements; using OpenRpg.Core.Templates; -using OpenRpg.Entities.Requirements; using OpenRpg.Quests.Variables; namespace OpenRpg.Quests diff --git a/src/OpenRpg.Quests/Types/QuestRequirementTypes.cs b/src/OpenRpg.Quests/Types/QuestRequirementTypes.cs new file mode 100644 index 00000000..b006eecb --- /dev/null +++ b/src/OpenRpg.Quests/Types/QuestRequirementTypes.cs @@ -0,0 +1,10 @@ +using OpenRpg.Entities.Types; + +namespace OpenRpg.Quests.Types; + +public interface QuestRequirementTypes : CoreRequirementTypes +{ + public static readonly int TriggerRequirement = 60; + public static readonly int QuestStateRequirement = 61; + public static readonly int FactionStateRequirement = 62; +} \ No newline at end of file diff --git a/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs b/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs index 87c3b95f..53109972 100644 --- a/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs +++ b/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs @@ -7,23 +7,6 @@ namespace OpenRpg.UnitTests.TradeSkills; public class TradeSkillCalculatorTests { - [Theory] - [InlineData(1, 1, 1, true)] - [InlineData(0, 1, 1, true)] - [InlineData(0, 2, 1, false)] - [InlineData(0, 2, 2, true)] - [InlineData(10, 100, 10, false)] - [InlineData(10, 100, 80, false)] - [InlineData(10, 100, 90, true)] - public void should_correctly_work_out_skill_use(int skillScore, int skillDifficulty, int maxSkillDifference, bool shouldBeAbleToUse) - { - var mockRandomizer = new Mock(); - mockRandomizer.Setup(x => x.Random(It.IsAny(), It.IsAny())).Returns(0.0f); - var tradeSkillCalculator = new TradeSkillCalculator(mockRandomizer.Object) { MaximumSkillDifference = maxSkillDifference }; - var canUse = tradeSkillCalculator.CanUseSkill(skillScore, skillDifficulty); - Assert.Equal(shouldBeAbleToUse, canUse); - } - [Theory] [InlineData(1, 1, 10, 0.5f, 1, 1)] [InlineData(1, 1, 10, 0.5f, 3, 3)] From a811ac632bde8d9b73130eadf99de5210ea3e959 Mon Sep 17 00:00:00 2001 From: LP Date: Wed, 21 Jan 2026 10:37:48 +0000 Subject: [PATCH 030/153] Fixed up logic and tests --- .../Calculator/TradeSkillCalculator.cs | 6 +++--- .../TradeSkills/TradeSkillCalculatorTests.cs | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs b/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs index 908c04fe..6d52f59c 100644 --- a/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs +++ b/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs @@ -13,7 +13,7 @@ public class TradeSkillCalculator : ITradeSkillCalculator /// /// This is the gated minimum threshold of the 0-1 plot check, defaults to 0.5f /// - public float MinimumPointThreshold { get; set; } = 0.5f; + public float MinimumPointThreshold { get; set; } = 0.1f; /// /// This is the multiplier added to the resulting value post randomness calculations, defaults to 1.0f @@ -39,9 +39,9 @@ public class TradeSkillCalculator : ITradeSkillCalculator /// /// The randomizer to use /// The optional curve function to apply, by default uses inverse linear - public TradeSkillCalculator(IRandomizer randomizer) + public TradeSkillCalculator(IRandomizer randomizer, ICurveFunction curveFunction = null) { - SkillPointCurve = new ScalingFunction(PresetCurves.BellCurve, new RangeF(0, 1), new RangeF(0, MaximumSkillDifference)); + SkillPointCurve = new ScalingFunction(curveFunction ?? PresetCurves.InverseLinear, new RangeF(0, 1), new RangeF(0, MaximumSkillDifference)); Randomizer = randomizer; } diff --git a/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs b/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs index 53109972..c798342d 100644 --- a/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs +++ b/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs @@ -8,7 +8,8 @@ namespace OpenRpg.UnitTests.TradeSkills; public class TradeSkillCalculatorTests { [Theory] - [InlineData(1, 1, 10, 0.5f, 1, 1)] + [InlineData(0, 0, 10, 0.1f, 1, 1)] + [InlineData(1, 1, 10, 0.1f, 1, 1)] [InlineData(1, 1, 10, 0.5f, 3, 3)] [InlineData(1, 10, 10, 0.5f, 1, 0)] [InlineData(1, 10, 10, 0.1f, 5, 1)] From 6097fb61e12a27808e8aa5a2678e351d7b0d58f3 Mon Sep 17 00:00:00 2001 From: LP Date: Wed, 21 Jan 2026 11:38:26 +0000 Subject: [PATCH 031/153] Updated trade skill logic some more --- .../Pages/TradeSkills/GatheringTradeSkills.razor | 2 +- .../Calculator/TradeSkillCalculator.cs | 7 ++++--- .../TradeSkills/TradeSkillCalculatorTests.cs | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor b/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor index b5c0a1c0..e47aea3e 100644 --- a/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor +++ b/src/OpenRpg.Demos.Web/Pages/TradeSkills/GatheringTradeSkills.razor @@ -202,7 +202,7 @@ protected override void OnInitialized() { - TradeSkillCalculator = new TradeSkillCalculator(Randomizer) { RandomnessVariance = 0.2f }; + TradeSkillCalculator = new TradeSkillCalculator(Randomizer) { RandomnessVariance = 0.2f, MaximumSkillDifference = 20 }; Example1Inventory.Variables.MaxSlots = 10; Example2Inventory.Variables.MaxSlots = 10; diff --git a/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs b/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs index 6d52f59c..a794a105 100644 --- a/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs +++ b/src/OpenRpg.Items.TradeSkills/Calculator/TradeSkillCalculator.cs @@ -11,7 +11,7 @@ namespace OpenRpg.Items.TradeSkills.Calculator public class TradeSkillCalculator : ITradeSkillCalculator { /// - /// This is the gated minimum threshold of the 0-1 plot check, defaults to 0.5f + /// This is the gated minimum threshold of the 0-1 plot check, defaults to 0.1f /// public float MinimumPointThreshold { get; set; } = 0.1f; @@ -53,8 +53,9 @@ public int CalculateSkillUpPointsFor(int skillScore, int skillDifficulty) var result = SkillPointCurve.Plot(absoluteScore); var randomVariance = Randomizer.Random(-RandomnessVariance, RandomnessVariance); - if (result < MinimumPointThreshold) { return 0; } - return (int)Math.Round((result + randomVariance) * PointMultiplier); + var totalResult = result + randomVariance; + if (totalResult <= MinimumPointThreshold) { return 0; } + return (int)Math.Ceiling(totalResult * PointMultiplier); } } } \ No newline at end of file diff --git a/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs b/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs index c798342d..dede43ff 100644 --- a/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs +++ b/src/OpenRpg.UnitTests/TradeSkills/TradeSkillCalculatorTests.cs @@ -22,7 +22,8 @@ public void should_correctly_work_out_skill_up_points(int skillScore, int skillD { MinimumPointThreshold = minimumPointThreshold, PointMultiplier = pointMultiplier, - MaximumSkillDifference = maxSkillDifference + MaximumSkillDifference = maxSkillDifference, + RandomnessVariance = 0.0f, }; var actualPoints = tradeSkillCalculator.CalculateSkillUpPointsFor(skillScore, skillDifficulty); Assert.Equal(expectedPoints, actualPoints); From 55620acbf283325a6356fc220523bf35b7d239a2 Mon Sep 17 00:00:00 2001 From: LP Date: Thu, 22 Jan 2026 10:09:29 +0000 Subject: [PATCH 032/153] Fixed crafting generation and component --- .../Data/LocaleDataGenerator.cs | 8 ++++++ .../ItemCraftingTemplateDetails.razor | 27 ++++++++++++++----- .../Procedural/PatternGeneratedItems.razor | 2 +- .../Extensions/RequirementExtensions.cs | 14 +++++++++- 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/OpenRpg.Demos.Infrastructure/Data/LocaleDataGenerator.cs b/src/OpenRpg.Demos.Infrastructure/Data/LocaleDataGenerator.cs index 56763aa0..e632baf0 100644 --- a/src/OpenRpg.Demos.Infrastructure/Data/LocaleDataGenerator.cs +++ b/src/OpenRpg.Demos.Infrastructure/Data/LocaleDataGenerator.cs @@ -27,6 +27,7 @@ public class LocaleDataGenerator : IDataGenerator public static readonly string CardTypesTextKey = "types-cards-"; public static readonly string UtilityTypesTextKey = "types-ai-utility-"; public static readonly string AdviceTypesTextKey = "types-ai-advice-"; + public static readonly string TradeSkillTypesTextKey = "types-trade-skill-"; public IEnumerable GenerateData() { @@ -44,6 +45,7 @@ public IEnumerable GenerateData() GenerateCardTypeLocaleText(localeDataset); GenerateUtilityTypeLocaleText(localeDataset); GenerateAdviceTypeLocaleText(localeDataset); + GenerateTradeSkillTypeLocaleText(localeDataset); return new[] { localeDataset }; } @@ -132,5 +134,11 @@ public void GenerateAdviceTypeLocaleText(LocaleDataset localeDataset) GetTypeFieldsDictionary() .ForEach((key, value) => localeDataset.LocaleData.Add(GetKeyFor(AdviceTypesTextKey, key), value)); } + + public void GenerateTradeSkillTypeLocaleText(LocaleDataset localeDataset) + { + GetTypeFieldsDictionary() + .ForEach((key, value) => localeDataset.LocaleData.Add(GetKeyFor(TradeSkillTypesTextKey, key), value)); + } } } \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Components/TradeSkills/ItemCraftingTemplateDetails.razor b/src/OpenRpg.Demos.Web/Components/TradeSkills/ItemCraftingTemplateDetails.razor index ce3184c1..b3988c31 100644 --- a/src/OpenRpg.Demos.Web/Components/TradeSkills/ItemCraftingTemplateDetails.razor +++ b/src/OpenRpg.Demos.Web/Components/TradeSkills/ItemCraftingTemplateDetails.razor @@ -1,8 +1,14 @@ @using OpenRpg.Core.Templates +@using OpenRpg.Entities.Extensions @using OpenRpg.Items.Extensions @using OpenRpg.Items.Templates @using OpenRpg.Genres.Characters +@using OpenRpg.Items.TradeSkills.Extensions @using OpenRpg.Items.TradeSkills.Templates +@using OpenRpg.Localization.Data.Extensions +@using OpenRpg.Localization.Data.Repositories + +@inject ILocaleRepository LocaleRepository;

    @(Name)

    @@ -23,12 +29,12 @@
    - @foreach (var itemEntry in ItemCraftingTemplate.InputItems) - { -
    - -
    - } + @foreach (var itemEntry in ItemCraftingTemplate.InputItems) + { +
    + +
    + }
    @@ -45,6 +51,15 @@
    + @if (ItemCraftingTemplate.Variables.HasTradeSkillRequirements()) + { + @foreach (var requirement in ItemCraftingTemplate.Variables.GetTradeSkillRequirements()) + { +
    + Requires @(LocaleRepository.Get(LocaleDataGenerator.GetKeyFor(LocaleDataGenerator.TradeSkillTypesTextKey, requirement.Association.AssociatedId))) @(requirement.Association.AssociatedValue) +
    + } + } @code { diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor index 3052f930..9b038b02 100644 --- a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor @@ -223,7 +223,7 @@ template.Variables.PatternTypeId = config.PatternTypeId; template.Variables.SkillType = config.SkillType; - var skillDifficulty = (int)Math.Round(config.SkillScore.Plot(patternId)); + var skillDifficulty = (int)Math.Round(config.SkillScore.Plot(i)); if(skillDifficulty > 0) { template.Variables.Requirements = [ diff --git a/src/OpenRpg.Items.TradeSkills/Extensions/RequirementExtensions.cs b/src/OpenRpg.Items.TradeSkills/Extensions/RequirementExtensions.cs index c65d85d9..549687ea 100644 --- a/src/OpenRpg.Items.TradeSkills/Extensions/RequirementExtensions.cs +++ b/src/OpenRpg.Items.TradeSkills/Extensions/RequirementExtensions.cs @@ -1,13 +1,25 @@ using System.Collections.Generic; using System.Linq; -using OpenRpg.Core.Associations; using OpenRpg.Core.Requirements; +using OpenRpg.Entities.Extensions; using OpenRpg.Items.TradeSkills.Types; +using OpenRpg.Items.TradeSkills.Variables; namespace OpenRpg.Items.TradeSkills.Extensions; public static class RequirementExtensions { + public static bool HasTradeSkillRequirements(this IItemTradeSkillTemplateVariables vars) + { return vars.HasRequirements() && vars.Requirements.HasTradeSkillRequirement(); } + + public static IReadOnlyCollection GetTradeSkillRequirements(this IItemTradeSkillTemplateVariables vars) + { + if (!vars.HasTradeSkillRequirements()) + { return []; } + + return vars.Requirements.GetTradeSkillRequirements(); + } + extension(IReadOnlyCollection requirements) { public bool HasTradeSkillRequirement() From 0cfc3928211514a2d0da0b0d5ba8495e21fb787d Mon Sep 17 00:00:00 2001 From: LP Date: Thu, 22 Jan 2026 15:36:51 +0000 Subject: [PATCH 033/153] Separated more pattern stuff out --- .../Procedural/PatternGeneratedItems.razor | 269 ++++++++---------- .../CraftingTemplatePatternGenerator.cs | 73 +++++ .../FixedNamePatternLocaleGenerator.cs | 15 + ...mCraftingTemplatePatternGeneratorConfig.cs | 15 + .../Patterns/ItemTemplatePatternGenerator.cs | 43 +++ .../ItemTemplatePatternGeneratorConfig.cs | 11 + .../Patterns/IPatternLocaleGenerator.cs | 6 + .../Patterns/PatternGeneratorVariables.cs | 3 +- 8 files changed, 287 insertions(+), 148 deletions(-) create mode 100644 src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/CraftingTemplatePatternGenerator.cs create mode 100644 src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/FixedNamePatternLocaleGenerator.cs create mode 100644 src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemCraftingTemplatePatternGeneratorConfig.cs create mode 100644 src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemTemplatePatternGenerator.cs create mode 100644 src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemTemplatePatternGeneratorConfig.cs create mode 100644 src/OpenRpg.Entities/Procedural/Patterns/IPatternLocaleGenerator.cs diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor index 9b038b02..bf83501a 100644 --- a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor @@ -1,28 +1,15 @@ @page "/procedural/pattern-generated-items" - -@using Newtonsoft.Json -@using OpenRpg.Core.Associations -@using OpenRpg.Core.Requirements -@using OpenRpg.Core.Templates @using OpenRpg.Core.Utils -@using OpenRpg.Core.Variables.General @using OpenRpg.CurveFunctions @using OpenRpg.CurveFunctions.Scaling @using OpenRpg.Demos.Infrastructure.Extensions @using OpenRpg.Demos.Infrastructure.Templates +@using OpenRpg.Demos.Web.Pages.Procedural.Patterns @using OpenRpg.Entities.Effects -@using OpenRpg.Entities.Extensions -@using OpenRpg.Entities.Procedural -@using OpenRpg.Entities.Procedural.Effects @using OpenRpg.Entities.Procedural.Effects.Builders -@using OpenRpg.Entities.Procedural.Patterns @using OpenRpg.Entities.Types @using OpenRpg.Genres.Fantasy.Types -@using OpenRpg.Items -@using OpenRpg.Items.Extensions @using OpenRpg.Items.TradeSkills.Templates -@using OpenRpg.Items.TradeSkills -@using OpenRpg.Items.TradeSkills.Extensions @using OpenRpg.Items.Templates @inject IRandomizer Randomizer; @@ -87,6 +74,45 @@
    + +
    +
    + @foreach (var itemTemplate in _logs) + { +
    + +
    + } +
    +
    +
    + + +
    +
    + @foreach (var itemTemplate in _lumber) + { +
    + +
    + } +
    +
    +
    + + +
    +
    + @foreach (var itemTemplate in _bows) + { +
    + +
    + } +
    +
    +
    +

    Crafting Templates

    @@ -132,8 +158,8 @@ private ItemTemplatePatternGenerator _itemTemplatePatternGenerator; private CraftingTemplatePatternGenerator _craftingTemplatePatternGenerator; - private IReadOnlyCollection _ores, _ingots, _swords, _armours; - private IReadOnlyCollection _ingotCrafting, _swordCrafting, _armourCrafting; + private IReadOnlyCollection _ores, _ingots, _swords, _armours, _logs, _lumber, _bows; + private IReadOnlyCollection _ingotCrafting, _swordCrafting, _armourCrafting, _lumberCrafting; public ManualTemplateAccessor TemplateAccessor = new (); public interface ItemPatternTypes @@ -144,6 +170,10 @@ public static int Ingot = 2; public static int Sword = 3; public static int Armour = 4; + public static int Bows = 5; + + public static int Log = 10; + public static int Lumber = 11; } public interface MetalItemPatternLookups @@ -158,127 +188,20 @@ public static int Steel = 6; public static int Mythril = 7; } - - public static Dictionary MetalLookups = typeof(MetalItemPatternLookups).GetTypeFieldsDictionary(); - public class ItemTemplatePatternGeneratorConfig : PatternGeneratorVariables - { - public string NamePattern { get; set; } - public int StartingId { get; set; } - public string TypeName { get; set; } - public int ItemType { get; set; } - public ProceduralEffects Effects { get; set; } - } - - public class ItemCraftingTemplatePatternGeneratorConfig : PatternGeneratorVariables - { - public int StartingId { get; set; } - public int SkillType { get; set; } - public ScalingFunction SkillScore { get; set; } - public int InputPatternTypeId { get; set; } - public int OutputPatternTypeId { get; set; } - public int AmountRequired { get; set; } - public int AmountOutput { get; set; } - } - - public class CraftingTemplatePatternGenerator : ITemplatePatternGenerator + public interface WoodItemPatternLookups { - public ITemplateAccessor TemplateAccessor { get; } - - public CraftingTemplatePatternGenerator(ITemplateAccessor templateAccessor) - { - TemplateAccessor = templateAccessor; - } - - public IReadOnlyCollection Generate(ItemCraftingTemplatePatternGeneratorConfig config) - { - var itemCraftingTemplates = new List(); - var id = config.StartingId; - var patternIds = config.PatternIds; - - for (var i = 0; i < patternIds.Length; i++) - { - var patternId = patternIds[i]; - - var relatedPatternItemTemplates = TemplateAccessor - .GetAll() - .Where(x => x.Variables.PatternId == patternId) - .ToArray(); - - var inputTemplate = relatedPatternItemTemplates.First(x => x.Variables.PatternTypeId == config.InputPatternTypeId); - var inputItemEntry = new TradeSkillItemEntry { TemplateId = inputTemplate.Id }; - inputItemEntry.Variables.Amount = config.AmountRequired; - var inputItems = new List { inputItemEntry }; - - var outputTemplate = relatedPatternItemTemplates.First(x => x.Variables.PatternTypeId == config.OutputPatternTypeId); - var outputItemEntry = new TradeSkillItemEntry { TemplateId = outputTemplate.Id }; - outputItemEntry.Variables.Amount = config.AmountOutput; - var outputItems = new List { outputItemEntry }; - - var template = new ItemCraftingTemplate(); - template.Id = id; - template.InputItems = inputItems; - template.OutputItems = outputItems; - template.Variables.PatternId = patternId; - template.Variables.PatternTypeId = config.PatternTypeId; - template.Variables.SkillType = config.SkillType; - - var skillDifficulty = (int)Math.Round(config.SkillScore.Plot(i)); - if(skillDifficulty > 0) - { - template.Variables.Requirements = [ - new Requirement - { - RequirementType = FantasyRequirementTypes.TradeSkillRequirement, - Association = new Association(config.SkillType, skillDifficulty) - } - ]; - } - - itemCraftingTemplates.Add(template); - } - - return itemCraftingTemplates; - } - } + public static int Unknown = 0; - public class ItemTemplatePatternGenerator : ITemplatePatternGenerator - { - public IReadOnlyCollection Generate(ItemTemplatePatternGeneratorConfig config) - { - var itemTemplates = new List(); - var id = config.StartingId; - var patternIds = config.PatternIds; - for (var i = 0; i < patternIds.Length; i++) - { - var patternId = patternIds[i]; - var localeNameForId = MetalLookups[patternId]; - var name = string.Format(config.NamePattern, localeNameForId, config.TypeName); - - var template = new ItemTemplate - { - Id = id++, - NameLocaleId = name, - ItemType = config.ItemType - }; - template.Variables.AssetCode = name.ToLower().Replace(" ", "-"); - template.Variables.QualityType = FantasyItemQualityTypes.CommonQuality; - template.Variables.PatternTypeId = config.PatternTypeId; - template.Variables.PatternId = patternId; - - if (config.Effects is not null) - { - var resultingEffects = config.Effects.GenerateEffectsFrom(i); - template.Variables.Effects = resultingEffects; - } - - itemTemplates.Add(template); - } - - return itemTemplates; - } + public static int Maple = 1; + public static int Ash = 2; + public static int Elm = 3; + public static int Oak = 4; } + public static Dictionary MetalLookups = typeof(MetalItemPatternLookups).GetTypeFieldsDictionary(); + public static Dictionary WoodLookups = typeof(WoodItemPatternLookups).GetTypeFieldsDictionary(); + protected override void OnInitialized() { base.OnInitialized(); @@ -286,34 +209,38 @@ _itemTemplatePatternGenerator = new ItemTemplatePatternGenerator(); _craftingTemplatePatternGenerator = new CraftingTemplatePatternGenerator(TemplateAccessor); - GenerateItemTemplates(); + GenerateMetalItemTemplates(); + GenerateWoodItemTemplates(); GenerateItemCraftingTemplates(); } - private void GenerateItemTemplates() + private void GenerateMetalItemTemplates() { - var namePattern = "{0} {1}"; var patternIds = MetalLookups.Keys.ToArray(); + var localeGenerator = new FixedNamePatternLocaleGenerator() { PatternNames = MetalLookups }; _ores = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Ore, - NamePattern = namePattern, - TypeName = "Ore", + LocaleGenerator = localeGenerator, + TypeCode = "Ore", StartingId = 0, ItemType = FantasyItemTypes.GenericItem }); + TemplateAccessor.AddTemplates(_ores); _ingots = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Ingot, - NamePattern = namePattern, - TypeName = "Ingot", + LocaleGenerator = localeGenerator, + TypeCode = "Ingot", StartingId = 20, ItemType = FantasyItemTypes.GenericItem }); + TemplateAccessor.AddTemplates(_ingots); + var swordEffects = ProceduralEffectsBuilder.Create() .WithPrimaryEffect(new ScaledEffect() @@ -328,12 +255,13 @@ { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Sword, - NamePattern = namePattern, - TypeName = "Sword", + LocaleGenerator = localeGenerator, + TypeCode = "Sword", StartingId = 40, ItemType = FantasyItemTypes.GenericWeapon, Effects = swordEffects }); + TemplateAccessor.AddTemplates(_swords); var armourEffects = ProceduralEffectsBuilder.Create() .WithPrimaryEffect(new ScaledEffect() @@ -354,18 +282,65 @@ { PatternIds = patternIds, PatternTypeId = ItemPatternTypes.Armour, - NamePattern = namePattern, - TypeName = "Armor", + LocaleGenerator = localeGenerator, + TypeCode = "Armor", StartingId = 60, ItemType = FantasyItemTypes.UpperBodyArmour, Effects = armourEffects }); - - TemplateAccessor.AddTemplates(_ores); - TemplateAccessor.AddTemplates(_ingots); - TemplateAccessor.AddTemplates(_swords); TemplateAccessor.AddTemplates(_armours); } + + private void GenerateWoodItemTemplates() + { + var patternIds = WoodLookups.Keys.ToArray(); + var localeGenerator = new FixedNamePatternLocaleGenerator() { PatternNames = WoodLookups }; + + _logs = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() + { + PatternIds = patternIds, + PatternTypeId = ItemPatternTypes.Log, + LocaleGenerator = localeGenerator, + TypeCode = "Log", + StartingId = 100, + ItemType = FantasyItemTypes.GenericItem + }); + TemplateAccessor.AddTemplates(_logs); + + _lumber = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() + { + PatternIds = patternIds, + PatternTypeId = ItemPatternTypes.Lumber, + LocaleGenerator = localeGenerator, + TypeCode = "Lumber", + StartingId = 120, + ItemType = FantasyItemTypes.GenericItem + }); + TemplateAccessor.AddTemplates(_lumber); + + + var bowEffects = ProceduralEffectsBuilder.Create() + .WithPrimaryEffect(new ScaledEffect() + { + EffectType = FantasyEffectTypes.DamageBonusAmount, + PotencyFunction = new ScalingFunction(PresetCurves.Linear, new RangeF(10, 100), new RangeF(0, patternIds.Length)), + ScalingType = CoreEffectScalingTypes.Value + }) + .Build(); + + _bows = _itemTemplatePatternGenerator.Generate(new ItemTemplatePatternGeneratorConfig() + { + PatternIds = patternIds, + PatternTypeId = ItemPatternTypes.Bows, + LocaleGenerator = localeGenerator, + TypeCode = "Bow", + StartingId = 140, + ItemType = FantasyItemTypes.GenericWeapon, + Effects = bowEffects + }); + TemplateAccessor.AddTemplates(_bows); + + } private void GenerateItemCraftingTemplates() { diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/CraftingTemplatePatternGenerator.cs b/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/CraftingTemplatePatternGenerator.cs new file mode 100644 index 00000000..ae6855f4 --- /dev/null +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/CraftingTemplatePatternGenerator.cs @@ -0,0 +1,73 @@ +using OpenRpg.Core.Associations; +using OpenRpg.Core.Requirements; +using OpenRpg.Core.Templates; +using OpenRpg.Entities.Extensions; +using OpenRpg.Entities.Procedural.Patterns; +using OpenRpg.Genres.Fantasy.Types; +using OpenRpg.Items.Templates; +using OpenRpg.Items.TradeSkills; +using OpenRpg.Items.TradeSkills.Templates; +using OpenRpg.Items.TradeSkills.Extensions; + +namespace OpenRpg.Demos.Web.Pages.Procedural.Patterns; + +public class CraftingTemplatePatternGenerator : ITemplatePatternGenerator +{ + public ITemplateAccessor TemplateAccessor { get; } + + public CraftingTemplatePatternGenerator(ITemplateAccessor templateAccessor) + { + TemplateAccessor = templateAccessor; + } + + public IReadOnlyCollection Generate(ItemCraftingTemplatePatternGeneratorConfig config) + { + var itemCraftingTemplates = new List(); + var id = config.StartingId; + var patternIds = config.PatternIds; + + for (var i = 0; i < patternIds.Length; i++) + { + var patternId = patternIds[i]; + + var relatedPatternItemTemplates = TemplateAccessor + .GetAll() + .Where(x => x.Variables.PatternId == patternId) + .ToArray(); + + var inputTemplate = relatedPatternItemTemplates.First(x => x.Variables.PatternTypeId == config.InputPatternTypeId); + var inputItemEntry = new TradeSkillItemEntry { TemplateId = inputTemplate.Id }; + inputItemEntry.Variables.Amount = config.AmountRequired; + var inputItems = new List { inputItemEntry }; + + var outputTemplate = relatedPatternItemTemplates.First(x => x.Variables.PatternTypeId == config.OutputPatternTypeId); + var outputItemEntry = new TradeSkillItemEntry { TemplateId = outputTemplate.Id }; + outputItemEntry.Variables.Amount = config.AmountOutput; + var outputItems = new List { outputItemEntry }; + + var template = new ItemCraftingTemplate(); + template.Id = id; + template.InputItems = inputItems; + template.OutputItems = outputItems; + template.Variables.PatternId = patternId; + template.Variables.PatternTypeId = config.PatternTypeId; + template.Variables.SkillType = config.SkillType; + + var skillDifficulty = (int)Math.Round(config.SkillScore.Plot(i)); + if(skillDifficulty > 0) + { + template.Variables.Requirements = [ + new Requirement + { + RequirementType = FantasyRequirementTypes.TradeSkillRequirement, + Association = new Association(config.SkillType, skillDifficulty) + } + ]; + } + + itemCraftingTemplates.Add(template); + } + + return itemCraftingTemplates; + } +} \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/FixedNamePatternLocaleGenerator.cs b/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/FixedNamePatternLocaleGenerator.cs new file mode 100644 index 00000000..f3990b58 --- /dev/null +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/FixedNamePatternLocaleGenerator.cs @@ -0,0 +1,15 @@ +using OpenRpg.Entities.Procedural.Patterns; + +namespace OpenRpg.Demos.Web.Pages.Procedural.Patterns; + +public class FixedNamePatternLocaleGenerator : IPatternLocaleGenerator +{ + public string NamePattern { get; set; } = "{0} {1}"; + public Dictionary PatternNames { get; set; } = new(); + + public string GenerateNameLocaleId(int patternId, string typeCode) + { + var patternIdName = PatternNames[patternId]; + return string.Format(NamePattern, patternIdName, typeCode); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemCraftingTemplatePatternGeneratorConfig.cs b/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemCraftingTemplatePatternGeneratorConfig.cs new file mode 100644 index 00000000..54f4a5c3 --- /dev/null +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemCraftingTemplatePatternGeneratorConfig.cs @@ -0,0 +1,15 @@ +using OpenRpg.CurveFunctions.Scaling; +using OpenRpg.Entities.Procedural.Patterns; + +namespace OpenRpg.Demos.Web.Pages.Procedural.Patterns; + +public class ItemCraftingTemplatePatternGeneratorConfig : PatternGeneratorVariables +{ + public int StartingId { get; set; } + public int SkillType { get; set; } + public ScalingFunction SkillScore { get; set; } + public int InputPatternTypeId { get; set; } + public int OutputPatternTypeId { get; set; } + public int AmountRequired { get; set; } + public int AmountOutput { get; set; } +} \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemTemplatePatternGenerator.cs b/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemTemplatePatternGenerator.cs new file mode 100644 index 00000000..64898959 --- /dev/null +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemTemplatePatternGenerator.cs @@ -0,0 +1,43 @@ +using OpenRpg.Entities.Extensions; +using OpenRpg.Entities.Procedural.Patterns; +using OpenRpg.Genres.Fantasy.Types; +using OpenRpg.Items.Templates; +using OpenRpg.Items.Extensions; + +namespace OpenRpg.Demos.Web.Pages.Procedural.Patterns; + +public class ItemTemplatePatternGenerator : ITemplatePatternGenerator +{ + public IReadOnlyCollection Generate(ItemTemplatePatternGeneratorConfig config) + { + var itemTemplates = new List(); + var id = config.StartingId; + var patternIds = config.PatternIds; + for (var i = 0; i < patternIds.Length; i++) + { + var patternId = patternIds[i]; + var nameLocaleId = config.LocaleGenerator.GenerateNameLocaleId(patternId, config.TypeCode); + + var template = new ItemTemplate + { + Id = id++, + NameLocaleId = nameLocaleId, + ItemType = config.ItemType + }; + template.Variables.AssetCode = nameLocaleId.ToLower().Replace(" ", "-"); + template.Variables.QualityType = FantasyItemQualityTypes.CommonQuality; + template.Variables.PatternTypeId = config.PatternTypeId; + template.Variables.PatternId = patternId; + + if (config.Effects is not null) + { + var resultingEffects = config.Effects.GenerateEffectsFrom(i); + template.Variables.Effects = resultingEffects; + } + + itemTemplates.Add(template); + } + + return itemTemplates; + } +} \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemTemplatePatternGeneratorConfig.cs b/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemTemplatePatternGeneratorConfig.cs new file mode 100644 index 00000000..0ac86582 --- /dev/null +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/Patterns/ItemTemplatePatternGeneratorConfig.cs @@ -0,0 +1,11 @@ +using OpenRpg.Entities.Procedural.Effects; +using OpenRpg.Entities.Procedural.Patterns; + +namespace OpenRpg.Demos.Web.Pages.Procedural.Patterns; + +public class ItemTemplatePatternGeneratorConfig : PatternGeneratorVariables +{ + public int StartingId { get; set; } + public int ItemType { get; set; } + public ProceduralEffects Effects { get; set; } +} \ No newline at end of file diff --git a/src/OpenRpg.Entities/Procedural/Patterns/IPatternLocaleGenerator.cs b/src/OpenRpg.Entities/Procedural/Patterns/IPatternLocaleGenerator.cs new file mode 100644 index 00000000..654411e5 --- /dev/null +++ b/src/OpenRpg.Entities/Procedural/Patterns/IPatternLocaleGenerator.cs @@ -0,0 +1,6 @@ +namespace OpenRpg.Entities.Procedural.Patterns; + +public interface IPatternLocaleGenerator +{ + string GenerateNameLocaleId(int patternId, string typeCode); +} \ No newline at end of file diff --git a/src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs b/src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs index 3401485e..6fb1c893 100644 --- a/src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs +++ b/src/OpenRpg.Entities/Procedural/Patterns/PatternGeneratorVariables.cs @@ -6,5 +6,6 @@ public class PatternGeneratorVariables : ObjectVariables { public int PatternTypeId { get; set; } public int[] PatternIds { get; set; } - + public string TypeCode { get; set; } + public IPatternLocaleGenerator LocaleGenerator { get; set; } } \ No newline at end of file From bb4df88bf5d438eefbbf0a80806b4cbf3eb44074 Mon Sep 17 00:00:00 2001 From: LP Date: Fri, 8 May 2026 11:24:57 +0100 Subject: [PATCH 034/153] Updated ship to be more inline with entity --- .../Extensions/IVariableExtensions.cs | 10 ++++++++++ .../Procedural/PatternGeneratedItems.razor | 1 - .../Extensions/ShipVariableExtensions.cs | 10 ++++++++++ src/OpenRpg.Genres.Scifi/Ships/Ship.cs | 18 ------------------ src/OpenRpg.Genres.Scifi/Ships/ShipData.cs | 16 ++++++++++++++++ src/OpenRpg.Genres.Scifi/Ships/ShipTemplate.cs | 6 ------ .../Types/ShipVariableTypes.cs | 4 ++++ .../Variables/ShipVariables.cs | 3 ++- src/OpenRpg.Items/Equippables/Equipment.cs | 4 ++-- 9 files changed, 44 insertions(+), 28 deletions(-) delete mode 100644 src/OpenRpg.Genres.Scifi/Ships/Ship.cs create mode 100644 src/OpenRpg.Genres.Scifi/Ships/ShipData.cs diff --git a/src/OpenRpg.Core/Extensions/IVariableExtensions.cs b/src/OpenRpg.Core/Extensions/IVariableExtensions.cs index e22275be..a690ec88 100644 --- a/src/OpenRpg.Core/Extensions/IVariableExtensions.cs +++ b/src/OpenRpg.Core/Extensions/IVariableExtensions.cs @@ -74,5 +74,15 @@ public static T GetAsOrDefault(this IVariables vars, int variableKey, { return vars.GetAs(variableKey) ?? defaultValueFactory(); } return defaultValueFactory(); } + + public static T GetAsOrDefaultAndSet(this IVariables vars, int variableKey, Func defaultValueFactory) where T : class + { + if (vars.ContainsKey(variableKey)) + { return vars.GetAs(variableKey); } + + var instance = defaultValueFactory(); + vars[variableKey] = instance; + return instance; + } } } \ No newline at end of file diff --git a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor index bf83501a..c09e06a9 100644 --- a/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor +++ b/src/OpenRpg.Demos.Web/Pages/Procedural/PatternGeneratedItems.razor @@ -318,7 +318,6 @@ }); TemplateAccessor.AddTemplates(_lumber); - var bowEffects = ProceduralEffectsBuilder.Create() .WithPrimaryEffect(new ScaledEffect() { diff --git a/src/OpenRpg.Genres.Scifi/Extensions/ShipVariableExtensions.cs b/src/OpenRpg.Genres.Scifi/Extensions/ShipVariableExtensions.cs index 42b80ed7..6a8ff57b 100644 --- a/src/OpenRpg.Genres.Scifi/Extensions/ShipVariableExtensions.cs +++ b/src/OpenRpg.Genres.Scifi/Extensions/ShipVariableExtensions.cs @@ -1,4 +1,5 @@ using OpenRpg.Core.Extensions; +using OpenRpg.Genres.Characters; using OpenRpg.Genres.Scifi.Equippables.ShipSlots; using OpenRpg.Genres.Scifi.Types; using OpenRpg.Genres.Scifi.Variables; @@ -24,6 +25,12 @@ public Inventory Inventory get => vars.GetAsOrDefault(ShipVariableTypes.Inventory, () => new Inventory()); set => vars[ShipVariableTypes.Inventory] = value; } + + public Character Pilot + { + get => vars.GetAsOrDefault(ShipVariableTypes.Pilot, () => new Character()); + set => vars[ShipVariableTypes.Pilot] = value; + } } public static bool HasEquipment(this ShipVariables vars) @@ -31,5 +38,8 @@ public static bool HasEquipment(this ShipVariables vars) public static bool HasInventory(this ShipVariables vars) { return vars.ContainsKey(ShipVariableTypes.Inventory); } + + public static bool HasPilot(this ShipVariables vars) + { return vars.ContainsKey(ShipVariableTypes.Pilot); } } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Scifi/Ships/Ship.cs b/src/OpenRpg.Genres.Scifi/Ships/Ship.cs deleted file mode 100644 index 9dcd5e7e..00000000 --- a/src/OpenRpg.Genres.Scifi/Ships/Ship.cs +++ /dev/null @@ -1,18 +0,0 @@ -using OpenRpg.Core.Templates; -using OpenRpg.Core.Variables.General; -using OpenRpg.Entities.State; -using OpenRpg.Entities.Stats; -using OpenRpg.Genres.Characters; -using OpenRpg.Genres.Scifi.Variables; - -namespace OpenRpg.Genres.Scifi.Ships -{ - public class Ship : IHasTemplate, IHasState, IHasStats, IHasVariables - { - public Character Pilot { get; set; } - public ShipTemplate Template { get; set; } = new ShipTemplate(); - public ShipStatsVariables Stats { get; set; } = new ShipStatsVariables(); - public ShipStateVariables State { get; set; } = new ShipStateVariables(); - public ShipVariables Variables { get; set; } = new ShipVariables(); - } -} \ No newline at end of file diff --git a/src/OpenRpg.Genres.Scifi/Ships/ShipData.cs b/src/OpenRpg.Genres.Scifi/Ships/ShipData.cs new file mode 100644 index 00000000..3979b4a1 --- /dev/null +++ b/src/OpenRpg.Genres.Scifi/Ships/ShipData.cs @@ -0,0 +1,16 @@ +using OpenRpg.Core.Templates; +using OpenRpg.Entities.State; +using OpenRpg.Entities.Stats; +using OpenRpg.Genres.Scifi.Variables; + +namespace OpenRpg.Genres.Scifi.Ships +{ + public class ShipData : ITemplateData, IHasState, IHasStats + { + public int TemplateId { get; set; } + + public ShipStatsVariables Stats { get; set; } = new(); + public ShipStateVariables State { get; set; } = new(); + public ShipVariables Variables { get; set; } = new(); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Genres.Scifi/Ships/ShipTemplate.cs b/src/OpenRpg.Genres.Scifi/Ships/ShipTemplate.cs index 11692f46..694eee5a 100644 --- a/src/OpenRpg.Genres.Scifi/Ships/ShipTemplate.cs +++ b/src/OpenRpg.Genres.Scifi/Ships/ShipTemplate.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using OpenRpg.Core.Effects; -using OpenRpg.Core.Requirements; using OpenRpg.Core.Templates; -using OpenRpg.Entities.Effects; -using OpenRpg.Entities.Requirements; using OpenRpg.Genres.Scifi.Variables; namespace OpenRpg.Genres.Scifi.Ships diff --git a/src/OpenRpg.Genres.Scifi/Types/ShipVariableTypes.cs b/src/OpenRpg.Genres.Scifi/Types/ShipVariableTypes.cs index 8ebad00d..eeb26784 100644 --- a/src/OpenRpg.Genres.Scifi/Types/ShipVariableTypes.cs +++ b/src/OpenRpg.Genres.Scifi/Types/ShipVariableTypes.cs @@ -2,7 +2,11 @@ namespace OpenRpg.Genres.Scifi.Types { public interface ShipVariableTypes { + public static readonly int Unknown = 0; + public static readonly int Equipment = 1; public static readonly int Inventory = 2; + + public static readonly int Pilot = 10; } } \ No newline at end of file diff --git a/src/OpenRpg.Genres.Scifi/Variables/ShipVariables.cs b/src/OpenRpg.Genres.Scifi/Variables/ShipVariables.cs index a104a23e..90d3e3aa 100644 --- a/src/OpenRpg.Genres.Scifi/Variables/ShipVariables.cs +++ b/src/OpenRpg.Genres.Scifi/Variables/ShipVariables.cs @@ -1,10 +1,11 @@ using System.Collections.Generic; +using OpenRpg.Core.Templates.Variables; using OpenRpg.Core.Variables.General; using OpenRpg.Genres.Scifi.Types; namespace OpenRpg.Genres.Scifi.Variables { - public class ShipVariables : ObjectVariables + public class ShipVariables : ObjectVariables, ITemplateDataVariables { public ShipVariables(IDictionary internalVariables = null) : base(ScifiVariableTypes.ShipVariables, internalVariables) { diff --git a/src/OpenRpg.Items/Equippables/Equipment.cs b/src/OpenRpg.Items/Equippables/Equipment.cs index 577f874c..a2b20567 100644 --- a/src/OpenRpg.Items/Equippables/Equipment.cs +++ b/src/OpenRpg.Items/Equippables/Equipment.cs @@ -6,7 +6,7 @@ namespace OpenRpg.Items.Equippables { public class Equipment : IHasVariables { - public EquipmentSlots Slots { get; set; } = new EquipmentSlots(); - public EquipmentVariables Variables { get; set; } = new EquipmentVariables(); + public EquipmentSlots Slots { get; set; } = new(); + public EquipmentVariables Variables { get; set; } = new(); } } \ No newline at end of file From 9644c02e1313fbdd84b09242d7344227379941fd Mon Sep 17 00:00:00 2001 From: LP Date: Fri, 8 May 2026 12:55:12 +0100 Subject: [PATCH 035/153] Minor updates --- src/OpenRpg.Editor.Core/Models/Project.cs | 2 +- .../Components/Editors/Templates/GenericTemplateEditor.razor | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/OpenRpg.Editor.Core/Models/Project.cs b/src/OpenRpg.Editor.Core/Models/Project.cs index 3d5e2dec..a13c774e 100644 --- a/src/OpenRpg.Editor.Core/Models/Project.cs +++ b/src/OpenRpg.Editor.Core/Models/Project.cs @@ -4,7 +4,7 @@ namespace OpenRpg.Editor.Core.Models; public class Project { - public string Version { get; set; } = "1.0.0"; + public string Version { get; set; } = "1.0.1"; public string AssetsFolder { get; set; } = "assets"; public string TemplatesFolder { get; set; } = "templates"; public string LocalesFolder { get; set; } = "locales"; diff --git a/src/OpenRpg.Editor.UI/Components/Editors/Templates/GenericTemplateEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/Templates/GenericTemplateEditor.razor index ee13a3ee..ff5f9429 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/Templates/GenericTemplateEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/Templates/GenericTemplateEditor.razor @@ -1,9 +1,7 @@ @using OpenRpg.Core.Effects @using OpenRpg.Core.Requirements @using OpenRpg.Editor.Infrastructure.Extensions -@using OpenRpg.Entities.Effects @using OpenRpg.Entities.Extensions -@using OpenRpg.Entities.Requirements @using OpenRpg.Localization.Data.Repositories @typeparam TTemplate where TTemplate : class, OpenRpg.Core.Templates.ITemplate, OpenRpg.Core.Variables.General.IHasVariables, new() From 33380bf3a04b656018f10dc9ee408bce1a89c3a7 Mon Sep 17 00:00:00 2001 From: LP Date: Fri, 8 May 2026 17:46:31 +0100 Subject: [PATCH 036/153] First stab at generic project handler --- .../Extensions/LoadedProjectExtensions.cs | 7 +- .../Models/LoadedProject.cs | 4 +- src/OpenRpg.Editor.Core/Models/Project.cs | 11 -- .../OpenRpg.Editor.Core.csproj | 2 + .../Extensions/EditorDatasourceExtensions.cs | 22 ---- .../EditorLocaleDatasourceExtensions.cs | 24 ---- .../OpenRpg.Editor.Infrastructure.csproj | 1 + .../Persistence/LoadProjectExecutor.cs | 107 +++--------------- .../Loaders/EditorJsonTemplateLoader.cs | 11 ++ .../Modules/DataServiceModule.cs | 11 ++ .../Extensions/ProjectExtensions.cs | 28 +++++ .../Loaders/JsonProjectLoader.cs | 27 +++++ .../Locales/JsonLocaleDatastorePopulator.cs | 41 +++++++ .../Loaders/Locales/JsonLocaleLoader.cs | 32 ++++++ .../JsonTemplateDatastorePopulator.cs | 51 +++++++++ .../Loaders/Templates/JsonTemplateLoader.cs | 50 ++++++++ .../OpenRpg.Projects.Json.csproj | 20 ++++ .../Types/ProjectMetadataKeys.cs | 8 ++ .../Loaders/IProjectLoader.cs | 13 +++ .../Locales/ILocaleDatastorePopulator.cs | 9 ++ .../Loaders/Locales/ILocaleLoader.cs | 14 +++ .../Templates/ITemplateDatastorePopulator.cs | 9 ++ .../Loaders/Templates/ITemplateLoader.cs | 15 +++ .../Models/PluginDescriptor.cs | 7 ++ src/OpenRpg.Projects/Models/Project.cs | 10 ++ src/OpenRpg.Projects/OpenRpg.Projects.csproj | 14 +++ .../Services/DefaultFileService.cs | 16 +++ src/OpenRpg.Projects/Services/IFileService.cs | 8 ++ src/OpenRpg.sln | 19 +++- 29 files changed, 436 insertions(+), 155 deletions(-) delete mode 100644 src/OpenRpg.Editor.Core/Models/Project.cs create mode 100644 src/OpenRpg.Editor.Infrastructure/Persistence/Loaders/EditorJsonTemplateLoader.cs create mode 100644 src/OpenRpg.Projects.Json/Extensions/ProjectExtensions.cs create mode 100644 src/OpenRpg.Projects.Json/Loaders/JsonProjectLoader.cs create mode 100644 src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleDatastorePopulator.cs create mode 100644 src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleLoader.cs create mode 100644 src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateDatastorePopulator.cs create mode 100644 src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateLoader.cs create mode 100644 src/OpenRpg.Projects.Json/OpenRpg.Projects.Json.csproj create mode 100644 src/OpenRpg.Projects.Json/Types/ProjectMetadataKeys.cs create mode 100644 src/OpenRpg.Projects/Loaders/IProjectLoader.cs create mode 100644 src/OpenRpg.Projects/Loaders/Locales/ILocaleDatastorePopulator.cs create mode 100644 src/OpenRpg.Projects/Loaders/Locales/ILocaleLoader.cs create mode 100644 src/OpenRpg.Projects/Loaders/Templates/ITemplateDatastorePopulator.cs create mode 100644 src/OpenRpg.Projects/Loaders/Templates/ITemplateLoader.cs create mode 100644 src/OpenRpg.Projects/Models/PluginDescriptor.cs create mode 100644 src/OpenRpg.Projects/Models/Project.cs create mode 100644 src/OpenRpg.Projects/OpenRpg.Projects.csproj create mode 100644 src/OpenRpg.Projects/Services/DefaultFileService.cs create mode 100644 src/OpenRpg.Projects/Services/IFileService.cs diff --git a/src/OpenRpg.Editor.Core/Extensions/LoadedProjectExtensions.cs b/src/OpenRpg.Editor.Core/Extensions/LoadedProjectExtensions.cs index 51125925..90b148b3 100644 --- a/src/OpenRpg.Editor.Core/Extensions/LoadedProjectExtensions.cs +++ b/src/OpenRpg.Editor.Core/Extensions/LoadedProjectExtensions.cs @@ -1,6 +1,7 @@ using System; using System.IO; using OpenRpg.Editor.Core.Models; +using OpenRpg.Projects.Json.Extensions; namespace OpenRpg.Editor.Core.Extensions; @@ -29,9 +30,9 @@ public static string GetLocalePath(LoadedProject project) public static string GetAssetPath(LoadedProject project) { - var isAbsolutePath = Path.IsPathFullyQualified(project.Project.AssetsFolder); - return isAbsolutePath ? project.Project.AssetsFolder : - $"{project.ProjectPath}/{project.Project.AssetsFolder}"; + var isAbsolutePath = Path.IsPathFullyQualified(project.Project.AssetFolder); + return isAbsolutePath ? project.Project.AssetFolder : + $"{project.ProjectPath}/{project.Project.AssetFolder}"; } public static string GetAssetPath(this LoadedProject project, string type) diff --git a/src/OpenRpg.Editor.Core/Models/LoadedProject.cs b/src/OpenRpg.Editor.Core/Models/LoadedProject.cs index f9b2dda1..7b94628e 100644 --- a/src/OpenRpg.Editor.Core/Models/LoadedProject.cs +++ b/src/OpenRpg.Editor.Core/Models/LoadedProject.cs @@ -1,7 +1,9 @@ +using OpenRpg.Projects.Models; + namespace OpenRpg.Editor.Core.Models; public class LoadedProject { - public Project Project { get; set; } = new Project(); + public Project Project { get; set; } = new(); public string ProjectPath { get; set; } } \ No newline at end of file diff --git a/src/OpenRpg.Editor.Core/Models/Project.cs b/src/OpenRpg.Editor.Core/Models/Project.cs deleted file mode 100644 index a13c774e..00000000 --- a/src/OpenRpg.Editor.Core/Models/Project.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace OpenRpg.Editor.Core.Models; - -public class Project -{ - public string Version { get; set; } = "1.0.1"; - public string AssetsFolder { get; set; } = "assets"; - public string TemplatesFolder { get; set; } = "templates"; - public string LocalesFolder { get; set; } = "locales"; -} \ No newline at end of file diff --git a/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj b/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj index b7ed93bd..ace0cd85 100644 --- a/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj +++ b/src/OpenRpg.Editor.Core/OpenRpg.Editor.Core.csproj @@ -17,6 +17,8 @@ + + diff --git a/src/OpenRpg.Editor.Infrastructure/Extensions/EditorDatasourceExtensions.cs b/src/OpenRpg.Editor.Infrastructure/Extensions/EditorDatasourceExtensions.cs index 0ea1780c..48b475c9 100644 --- a/src/OpenRpg.Editor.Infrastructure/Extensions/EditorDatasourceExtensions.cs +++ b/src/OpenRpg.Editor.Infrastructure/Extensions/EditorDatasourceExtensions.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; -using System.Linq; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using OpenRpg.Core.Templates; using OpenRpg.Editor.Infrastructure.Data; @@ -19,23 +16,4 @@ public static string SerializeData(this EditorDatasource datasource) where T var dataForType = datasource.GetAll(); return JsonConvert.SerializeObject(dataForType, new JsonSerializerSettings{ TypeNameHandling = TypeNameHandling.Objects, Formatting = Formatting.Indented }); } - - public static void DeserializeData(this EditorDatasource datasource, JArray jsonData, bool replaceData = false) where T : ITemplate - { - var type = typeof(T); - if (!datasource.Database.ContainsKey(type)) - { datasource.Database[type] = new Dictionary(); } - - var dataForType = jsonData.ToObject(new JsonSerializer(){ TypeNameHandling = TypeNameHandling.Auto }); - - if (replaceData) - { - datasource.Database[type] = dataForType.ToDictionary(x => (object)x.Id, x => (object)x); - return; - } - - var typeDatasource = datasource.Database[type]; - foreach (var dataItem in dataForType) - { typeDatasource.Add(dataItem.Id, dataItem); } - } } \ No newline at end of file diff --git a/src/OpenRpg.Editor.Infrastructure/Extensions/EditorLocaleDatasourceExtensions.cs b/src/OpenRpg.Editor.Infrastructure/Extensions/EditorLocaleDatasourceExtensions.cs index a1973aa4..10331aef 100644 --- a/src/OpenRpg.Editor.Infrastructure/Extensions/EditorLocaleDatasourceExtensions.cs +++ b/src/OpenRpg.Editor.Infrastructure/Extensions/EditorLocaleDatasourceExtensions.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using OpenRpg.Core.Templates; using OpenRpg.Editor.Infrastructure.Data; using OpenRpg.Localization; @@ -21,25 +18,4 @@ public static string SerializeData(this EditorLocaleDatasource datasource, strin public static string SerializeData(this LocaleDataset dataset) { return JsonConvert.SerializeObject(dataset, new JsonSerializerSettings{ TypeNameHandling = TypeNameHandling.Auto, Formatting = Formatting.Indented }); } - - public static void DeserializeData(this EditorLocaleDatasource datasource, JObject jsonData, bool replace = false) - { - var localeData = jsonData.ToObject(new JsonSerializer{ TypeNameHandling = TypeNameHandling.Auto }); - - if (!datasource.LocaleDatasets.ContainsKey(localeData.LocaleCode)) - { - datasource.LocaleDatasets[localeData.LocaleCode] = localeData; - return; - } - - if (replace) - { - datasource.LocaleDatasets[localeData.LocaleCode] = localeData; - return; - } - - var existingLocaleDataset = datasource.LocaleDatasets[localeData.LocaleCode]; - foreach (var dataItem in localeData.LocaleData) - { existingLocaleDataset.LocaleData.Add(dataItem.Key, dataItem.Value); } - } } \ No newline at end of file diff --git a/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj b/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj index de1a2128..5c0ab20f 100644 --- a/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj +++ b/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj @@ -19,6 +19,7 @@ + diff --git a/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs b/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs index f562dafc..a97bd09c 100644 --- a/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs +++ b/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs @@ -1,21 +1,12 @@ -using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using OpenRpg.Core.Templates; -using OpenRpg.Editor.Core.Extensions; using OpenRpg.Editor.Core.Models; using OpenRpg.Editor.Infrastructure.Data; -using OpenRpg.Editor.Infrastructure.Extensions; using OpenRpg.Editor.Infrastructure.Persistence.Migrations; -using OpenRpg.Entities.Classes.Templates; -using OpenRpg.Entities.Races.Templates; -using OpenRpg.Items.Templates; -using OpenRpg.Items.TradeSkills.Templates; -using OpenRpg.Quests; +using OpenRpg.Projects.Loaders; +using OpenRpg.Projects.Loaders.Locales; +using OpenRpg.Projects.Loaders.Templates; namespace OpenRpg.Editor.Infrastructure.Persistence; @@ -25,96 +16,26 @@ public class LoadProjectExecutor public EditorDatasource EditorDatasource { get; } public EditorLocaleDatasource EditorLocaleDatasource { get; } public IEnumerable ProjectMigrations { get; } + public IProjectLoader ProjectLoader { get; } + public ITemplateDatastorePopulator TemplateDatastorePopulator { get; } + public ILocaleDatastorePopulator LocaleDatastorePopulator { get; } - public LoadProjectExecutor(EditorState editorState, EditorDatasource editorDatasource, EditorLocaleDatasource editorLocaleDatasource, IEnumerable projectMigrations) + public LoadProjectExecutor(EditorState editorState, EditorDatasource editorDatasource, EditorLocaleDatasource editorLocaleDatasource, IEnumerable projectMigrations, IProjectLoader projectLoader, ITemplateDatastorePopulator templateDatastorePopulator, ILocaleDatastorePopulator localeDatastorePopulator) { EditorState = editorState; EditorDatasource = editorDatasource; EditorLocaleDatasource = editorLocaleDatasource; ProjectMigrations = projectMigrations; + ProjectLoader = projectLoader; + TemplateDatastorePopulator = templateDatastorePopulator; + LocaleDatastorePopulator = localeDatastorePopulator; } public async Task Execute(string projectFile) { - if(!File.Exists(projectFile)) - { throw new Exception($"Project file cannot be found in path [{projectFile}]"); } - - var projectData = await File.ReadAllTextAsync(projectFile); - var project = JsonConvert.DeserializeObject(projectData); - var loadedProject = new LoadedProject { Project = project, ProjectPath = Path.GetDirectoryName(projectFile) }; - - EditorState.CurrentProject = loadedProject; - - await RefreshTemplateData(); - await RefreshTemplateData(); - await RefreshTemplateData(); - await RefreshTemplateData(); - await RefreshTemplateData(); - await RefreshTemplateData(); - - await RefreshLocaleData(); - - project.Version = ProjectMigrations.OrderBy(x => x.TargetVersion).Last().NewVersion; - } - - public async Task RefreshTemplateData() where T : ITemplate - { - if (EditorState.CurrentProject == null) - { throw new Exception("No project loaded"); } - - if(string.IsNullOrEmpty(EditorState.CurrentProject?.ProjectPath)) - { throw new Exception("Folder path is empty"); } - - if(!Directory.Exists(EditorState.CurrentProject.TemplatePath)) - { throw new Exception("Template path does not exist on file system"); } - - var dataFile = $"{EditorState.CurrentProject.TemplatePath}/{typeof(T).Name}.json"; - if(!File.Exists(dataFile)) { await File.WriteAllTextAsync(dataFile, "[]"); } - - var fileContent = await File.ReadAllTextAsync(dataFile); - var jsonData = JArray.Parse(fileContent); - - var currentVersion = EditorState.CurrentProject.Project.Version; - foreach (var migration in ProjectMigrations.OrderBy(x => x.TargetVersion)) - { - if (migration.TargetVersion == currentVersion) - { - jsonData = migration.MigrateTemplate(jsonData); - currentVersion = migration.NewVersion; - } - } - - EditorDatasource.DeserializeData(jsonData, true); - } - - public async Task RefreshLocaleData() - { - if (EditorState.CurrentProject == null) - { throw new Exception("No project loaded"); } - - if(string.IsNullOrEmpty(EditorState.CurrentProject?.ProjectPath)) - { throw new Exception("Folder path is empty"); } - - if(!Directory.Exists(EditorState.CurrentProject.LocalePath)) - { throw new Exception("Locale path does not exist on file system"); } - - var localeFiles = Directory.GetFiles(EditorState.CurrentProject.LocalePath, "*.json"); - foreach (var localeFile in localeFiles) - { - var localeData = await File.ReadAllTextAsync(localeFile); - var jsonData = JObject.Parse(localeData); - - var currentVersion = EditorState.CurrentProject.Project.Version; - foreach (var migration in ProjectMigrations.OrderBy(x => x.TargetVersion)) - { - if (migration.TargetVersion == currentVersion) - { - jsonData = migration.MigrateLocale(jsonData); - currentVersion = migration.NewVersion; - } - } - - EditorLocaleDatasource.DeserializeData(jsonData, true); - } + var project = await ProjectLoader.LoadProject(projectFile); + EditorState.CurrentProject = new LoadedProject() { Project = project, ProjectPath = Path.GetDirectoryName(projectFile) }; + await TemplateDatastorePopulator.PopulateDatastore(project, projectFile, EditorDatasource); + await LocaleDatastorePopulator.PopulateDatastore(project, projectFile, EditorLocaleDatasource); } } \ No newline at end of file diff --git a/src/OpenRpg.Editor.Infrastructure/Persistence/Loaders/EditorJsonTemplateLoader.cs b/src/OpenRpg.Editor.Infrastructure/Persistence/Loaders/EditorJsonTemplateLoader.cs new file mode 100644 index 00000000..6765ae61 --- /dev/null +++ b/src/OpenRpg.Editor.Infrastructure/Persistence/Loaders/EditorJsonTemplateLoader.cs @@ -0,0 +1,11 @@ +using OpenRpg.Projects.Json.Loaders.Templates; +using OpenRpg.Projects.Services; + +namespace OpenRpg.Editor.Infrastructure.Persistence.Loaders; + +public class EditorJsonTemplateLoader : JsonTemplateLoader +{ + public EditorJsonTemplateLoader(IFileService fileService) : base(fileService) + { + } +} \ No newline at end of file diff --git a/src/OpenRpg.Editor/Modules/DataServiceModule.cs b/src/OpenRpg.Editor/Modules/DataServiceModule.cs index a128a40d..919ecf9c 100644 --- a/src/OpenRpg.Editor/Modules/DataServiceModule.cs +++ b/src/OpenRpg.Editor/Modules/DataServiceModule.cs @@ -14,6 +14,12 @@ using OpenRpg.Editor.Services.FileSystem; using OpenRpg.Localization.Data.DataSources; using OpenRpg.Localization.Data.Repositories; +using OpenRpg.Projects.Json.Loaders; +using OpenRpg.Projects.Json.Loaders.Locales; +using OpenRpg.Projects.Json.Loaders.Templates; +using OpenRpg.Projects.Loaders; +using OpenRpg.Projects.Loaders.Locales; +using OpenRpg.Projects.Loaders.Templates; using Persistity.Core.Serialization; using Persistity.Flow.Builders; using Persistity.Serializers.Json; @@ -46,6 +52,11 @@ public static void Setup(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(x => x.GetService()); diff --git a/src/OpenRpg.Projects.Json/Extensions/ProjectExtensions.cs b/src/OpenRpg.Projects.Json/Extensions/ProjectExtensions.cs new file mode 100644 index 00000000..e346d113 --- /dev/null +++ b/src/OpenRpg.Projects.Json/Extensions/ProjectExtensions.cs @@ -0,0 +1,28 @@ +using OpenRpg.Projects.Json.Types; +using OpenRpg.Projects.Models; + +namespace OpenRpg.Projects.Json.Extensions; + +public static class ProjectExtensions +{ + extension(Project project) + { + public string AssetFolder + { + get => project.Metadata.GetValueOrDefault(ProjectMetadataKeys.AssetFolder, "assets"); + set => project.Metadata[ProjectMetadataKeys.AssetFolder] = value; + } + + public string TemplatesFolder + { + get => project.Metadata.GetValueOrDefault(ProjectMetadataKeys.TemplatesFolder, "templates"); + set => project.Metadata[ProjectMetadataKeys.TemplatesFolder] = value; + } + + public string LocalesFolder + { + get => project.Metadata.GetValueOrDefault(ProjectMetadataKeys.LocalesFolder, "locales"); + set => project.Metadata[ProjectMetadataKeys.LocalesFolder] = value; + } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Projects.Json/Loaders/JsonProjectLoader.cs b/src/OpenRpg.Projects.Json/Loaders/JsonProjectLoader.cs new file mode 100644 index 00000000..1ae5c365 --- /dev/null +++ b/src/OpenRpg.Projects.Json/Loaders/JsonProjectLoader.cs @@ -0,0 +1,27 @@ +using Newtonsoft.Json; +using OpenRpg.Projects.Loaders; +using OpenRpg.Projects.Models; +using OpenRpg.Projects.Services; + +namespace OpenRpg.Projects.Json.Loaders; + +public class JsonProjectLoader : IProjectLoader +{ + public IFileService FileService { get; } + + public JsonProjectLoader(IFileService fileService) + { + FileService = fileService; + } + + public async Task LoadProject(string projectFilePath) + { + var projectExists = await FileService.Exists(projectFilePath); + if(!projectExists) { throw new Exception($"Project file cannot be found in path [{projectFilePath}]"); } + + var projectData = await FileService.GetContents(projectFilePath); + var project = JsonConvert.DeserializeObject(projectData); + + return project ?? throw new Exception("Project data cannot be read"); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleDatastorePopulator.cs b/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleDatastorePopulator.cs new file mode 100644 index 00000000..df31ccf1 --- /dev/null +++ b/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleDatastorePopulator.cs @@ -0,0 +1,41 @@ +using OpenRpg.Core.Extensions; +using OpenRpg.Localization.Data.DataSources; +using OpenRpg.Projects.Json.Extensions; +using OpenRpg.Projects.Loaders.Locales; +using OpenRpg.Projects.Models; +using OpenRpg.Projects.Services; + +namespace OpenRpg.Projects.Json.Loaders.Locales; + +public class JsonLocaleDatastorePopulator : ILocaleDatastorePopulator +{ + public IFileService FileService { get; } + public ILocaleLoader LocaleLoader { get; } + + public JsonLocaleDatastorePopulator(IFileService fileService, ILocaleLoader localeLoader) + { + FileService = fileService; + LocaleLoader = localeLoader; + } + + public virtual async Task> GetAllLocaleFiles(string localePath) + { return await FileService.GetChildContents(localePath, "*.json"); } + + public async Task PopulateDatastore(Project project, string projectPath, ILocaleDataSource dataSource) + { + var localesFolderPath = project.LocalesFolder; + var absoluteLocaleFolderPath = $"{projectPath}/{localesFolderPath}"; + var localePathExists = await FileService.Exists(absoluteLocaleFolderPath); + if(localePathExists) { throw new Exception($"Locale folder [{absoluteLocaleFolderPath}] cannot be found"); } + + var localeFiles = await GetAllLocaleFiles(absoluteLocaleFolderPath); + foreach (var localeFile in localeFiles) + { + var localeDataset = await LocaleLoader.LoadLocales(project, localeFile); + localeDataset.LocaleData.ForEach(x => AddLocale(localeDataset.LocaleCode, x.Key, x.Value, dataSource)); + } + } + + public virtual void AddLocale(string localeCode, string localeKey, string localeText, ILocaleDataSource dataSource) + { dataSource.Update(localeCode, localeKey, localeText); } +} \ No newline at end of file diff --git a/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleLoader.cs b/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleLoader.cs new file mode 100644 index 00000000..05112116 --- /dev/null +++ b/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleLoader.cs @@ -0,0 +1,32 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenRpg.Localization; +using OpenRpg.Localization.Data.DataSources; +using OpenRpg.Projects.Loaders.Locales; +using OpenRpg.Projects.Models; +using OpenRpg.Projects.Services; + +namespace OpenRpg.Projects.Json.Loaders.Locales; + +public class JsonLocaleLoader : ILocaleLoader +{ + public IFileService FileService { get; } + + public async Task LoadLocales(Project project, string localeFilePath) + { + var localePathExists = await FileService.Exists(localeFilePath); + if(!localePathExists) { throw new Exception($"Locale file [{localeFilePath}] does not exist on file system"); } + + var fileContent = await FileService.GetContents(localeFilePath); + var jsonLocaleData = JObject.Parse(fileContent); + + return LoadLocaleDataset(jsonLocaleData); + } + + public virtual LocaleDataset LoadLocaleDataset(JObject jsonData) + { + var localeData = jsonData.ToObject(new JsonSerializer{ TypeNameHandling = TypeNameHandling.Auto }); + if(localeData is null) { throw new Exception($"Failed to deserialize template data of type [{nameof(LocaleDataset)}]"); } + return localeData; + } +} \ No newline at end of file diff --git a/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateDatastorePopulator.cs b/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateDatastorePopulator.cs new file mode 100644 index 00000000..65eca05e --- /dev/null +++ b/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateDatastorePopulator.cs @@ -0,0 +1,51 @@ +using OpenRpg.Core.Extensions; +using OpenRpg.Core.Templates; +using OpenRpg.Data; +using OpenRpg.Entities.Classes.Templates; +using OpenRpg.Entities.Races.Templates; +using OpenRpg.Items.Templates; +using OpenRpg.Items.TradeSkills.Templates; +using OpenRpg.Projects.Json.Extensions; +using OpenRpg.Projects.Loaders.Templates; +using OpenRpg.Projects.Models; +using OpenRpg.Projects.Services; +using OpenRpg.Quests; + +namespace OpenRpg.Projects.Json.Loaders.Templates; + +public class JsonTemplateDatastorePopulator : ITemplateDatastorePopulator +{ + public IFileService FileService { get; } + public ITemplateLoader TemplateLoader { get; } + + public JsonTemplateDatastorePopulator(IFileService fileService, ITemplateLoader templateLoader) + { + FileService = fileService; + TemplateLoader = templateLoader; + } + + public async Task PopulateDatastore(Project project, string projectPath, IDataSource dataSource) + { + var templateFolderPath = project.TemplatesFolder; + var absoluteTemplateFolderPath = $"{projectPath}/{templateFolderPath}"; + var templatePathExists = await FileService.Exists(absoluteTemplateFolderPath); + if(templatePathExists) { throw new Exception($"Template folder [{absoluteTemplateFolderPath}] cannot be found"); } + + await ProcessTemplates(project, absoluteTemplateFolderPath, dataSource); + await ProcessTemplates(project, absoluteTemplateFolderPath, dataSource); + await ProcessTemplates(project, absoluteTemplateFolderPath, dataSource); + await ProcessTemplates(project, absoluteTemplateFolderPath, dataSource); + await ProcessTemplates(project, absoluteTemplateFolderPath, dataSource); + await ProcessTemplates(project, absoluteTemplateFolderPath, dataSource); + } + + protected async Task ProcessTemplates(Project project, string templateFolderPath, IDataSource dataSource) where T : ITemplate + { + var itemTemplatePath = $"{templateFolderPath}/{typeof(T).Name}.json"; + var templatePathExists = await FileService.Exists(itemTemplatePath); + if(!templatePathExists) { throw new Exception($"Template file [{itemTemplatePath}] cannot be found"); } + + var templates = await TemplateLoader.LoadTemplates(project, itemTemplatePath); + templates.ForEach(x => dataSource.Update(x, x.Id)); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateLoader.cs b/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateLoader.cs new file mode 100644 index 00000000..ef5a6de8 --- /dev/null +++ b/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateLoader.cs @@ -0,0 +1,50 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using OpenRpg.Core.Extensions; +using OpenRpg.Core.Templates; +using OpenRpg.Data; +using OpenRpg.Projects.Loaders.Templates; +using OpenRpg.Projects.Models; +using OpenRpg.Projects.Services; + +namespace OpenRpg.Projects.Json.Loaders.Templates; + +public class JsonTemplateLoader : ITemplateLoader +{ + public IFileService FileService { get; } + + public JsonTemplateLoader(IFileService fileService) + { + FileService = fileService; + } + + public async Task> LoadTemplates(Project project, string templateFilePath) where T : ITemplate + { + var templatePathExists = await FileService.Exists(templateFilePath); + if(!templatePathExists) { throw new Exception($"Template file [{templateFilePath}] does not exist on file system"); } + + var fileContent = await FileService.GetContents(templateFilePath); + var jsonTemplateData = JArray.Parse(fileContent); + return await ProcessAllTemplateData(project, jsonTemplateData); + } + + public virtual async Task> ProcessAllTemplateData(Project project, JArray jsonTemplates) + where T : ITemplate + { + var templates = new List(); + foreach (var templateData in jsonTemplates) + { + var template = ProcessTemplateData(templateData); + templates.Add(template); + } + return templates; + } + + public virtual T ProcessTemplateData(JToken templateData) where T : ITemplate + { + var template = templateData.ToObject(new JsonSerializer{ TypeNameHandling = TypeNameHandling.Auto }); + if(template is null) { throw new Exception($"Failed to deserialize template data of type [{typeof(T).Name}] - {templateData}"); } + + return template; + } +} \ No newline at end of file diff --git a/src/OpenRpg.Projects.Json/OpenRpg.Projects.Json.csproj b/src/OpenRpg.Projects.Json/OpenRpg.Projects.Json.csproj new file mode 100644 index 00000000..3abac65d --- /dev/null +++ b/src/OpenRpg.Projects.Json/OpenRpg.Projects.Json.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + diff --git a/src/OpenRpg.Projects.Json/Types/ProjectMetadataKeys.cs b/src/OpenRpg.Projects.Json/Types/ProjectMetadataKeys.cs new file mode 100644 index 00000000..3dbc4af4 --- /dev/null +++ b/src/OpenRpg.Projects.Json/Types/ProjectMetadataKeys.cs @@ -0,0 +1,8 @@ +namespace OpenRpg.Projects.Json.Types; + +public static class ProjectMetadataKeys +{ + public const string AssetFolder = "asset-folder"; + public const string TemplatesFolder = "templates-folder"; + public const string LocalesFolder = "locales-folder"; +} \ No newline at end of file diff --git a/src/OpenRpg.Projects/Loaders/IProjectLoader.cs b/src/OpenRpg.Projects/Loaders/IProjectLoader.cs new file mode 100644 index 00000000..af6eb03f --- /dev/null +++ b/src/OpenRpg.Projects/Loaders/IProjectLoader.cs @@ -0,0 +1,13 @@ +using OpenRpg.Projects.Models; + +namespace OpenRpg.Projects.Loaders; + +public interface IProjectLoader +{ + /// + /// This should load the project from a given reference + /// + /// The reference to the project data, be it a string file path or asset name + /// The project data + Task LoadProject(string projectReference); +} \ No newline at end of file diff --git a/src/OpenRpg.Projects/Loaders/Locales/ILocaleDatastorePopulator.cs b/src/OpenRpg.Projects/Loaders/Locales/ILocaleDatastorePopulator.cs new file mode 100644 index 00000000..bb6364fb --- /dev/null +++ b/src/OpenRpg.Projects/Loaders/Locales/ILocaleDatastorePopulator.cs @@ -0,0 +1,9 @@ +using OpenRpg.Localization.Data.DataSources; +using OpenRpg.Projects.Models; + +namespace OpenRpg.Projects.Loaders.Locales; + +public interface ILocaleDatastorePopulator +{ + Task PopulateDatastore(Project project, string projectReference, ILocaleDataSource dataSource); +} \ No newline at end of file diff --git a/src/OpenRpg.Projects/Loaders/Locales/ILocaleLoader.cs b/src/OpenRpg.Projects/Loaders/Locales/ILocaleLoader.cs new file mode 100644 index 00000000..0c2f2c6a --- /dev/null +++ b/src/OpenRpg.Projects/Loaders/Locales/ILocaleLoader.cs @@ -0,0 +1,14 @@ +using OpenRpg.Localization; +using OpenRpg.Projects.Models; + +namespace OpenRpg.Projects.Loaders.Locales; + +public interface ILocaleLoader +{ + /// + /// Loads the locale data from a given reference + /// + /// The loaded project + /// The reference to the locale data i.e file path, asset name etc + Task LoadLocales(Project project, string localeReference); +} \ No newline at end of file diff --git a/src/OpenRpg.Projects/Loaders/Templates/ITemplateDatastorePopulator.cs b/src/OpenRpg.Projects/Loaders/Templates/ITemplateDatastorePopulator.cs new file mode 100644 index 00000000..bd4445d9 --- /dev/null +++ b/src/OpenRpg.Projects/Loaders/Templates/ITemplateDatastorePopulator.cs @@ -0,0 +1,9 @@ +using OpenRpg.Data; +using OpenRpg.Projects.Models; + +namespace OpenRpg.Projects.Loaders.Templates; + +public interface ITemplateDatastorePopulator +{ + Task PopulateDatastore(Project project, string projectReference, IDataSource dataSource); +} \ No newline at end of file diff --git a/src/OpenRpg.Projects/Loaders/Templates/ITemplateLoader.cs b/src/OpenRpg.Projects/Loaders/Templates/ITemplateLoader.cs new file mode 100644 index 00000000..4a352b5f --- /dev/null +++ b/src/OpenRpg.Projects/Loaders/Templates/ITemplateLoader.cs @@ -0,0 +1,15 @@ +using OpenRpg.Core.Templates; +using OpenRpg.Projects.Models; + +namespace OpenRpg.Projects.Loaders.Templates; + +public interface ITemplateLoader +{ + /// + /// Loads all templates from a given reference + /// + /// The loaded project + /// The reference to the template data i.e file path, asset name etc + /// The template type + Task> LoadTemplates(Project project, string templateReference) where T : ITemplate; +} \ No newline at end of file diff --git a/src/OpenRpg.Projects/Models/PluginDescriptor.cs b/src/OpenRpg.Projects/Models/PluginDescriptor.cs new file mode 100644 index 00000000..b9705342 --- /dev/null +++ b/src/OpenRpg.Projects/Models/PluginDescriptor.cs @@ -0,0 +1,7 @@ +namespace OpenRpg.Projects.Models; + +public class PluginDescriptor +{ + public string Name { get; set; } + public string Version { get; set; } +} \ No newline at end of file diff --git a/src/OpenRpg.Projects/Models/Project.cs b/src/OpenRpg.Projects/Models/Project.cs new file mode 100644 index 00000000..8b92d065 --- /dev/null +++ b/src/OpenRpg.Projects/Models/Project.cs @@ -0,0 +1,10 @@ +namespace OpenRpg.Projects.Models; + +public class Project +{ + public string Version { get; set; } = "1.0.1"; + public string Type { get; set; } = "json"; + + public Dictionary Metadata { get; set; } = new(); + public IReadOnlyCollection Plugins { get; set; } = new List(); +} \ No newline at end of file diff --git a/src/OpenRpg.Projects/OpenRpg.Projects.csproj b/src/OpenRpg.Projects/OpenRpg.Projects.csproj new file mode 100644 index 00000000..639c8138 --- /dev/null +++ b/src/OpenRpg.Projects/OpenRpg.Projects.csproj @@ -0,0 +1,14 @@ + + + + net10.0 + enable + enable + + + + + + + + diff --git a/src/OpenRpg.Projects/Services/DefaultFileService.cs b/src/OpenRpg.Projects/Services/DefaultFileService.cs new file mode 100644 index 00000000..25f48a98 --- /dev/null +++ b/src/OpenRpg.Projects/Services/DefaultFileService.cs @@ -0,0 +1,16 @@ +namespace OpenRpg.Projects.Services; + +public class DefaultFileService : IFileService +{ + public Task GetContents(string file) + { return File.ReadAllTextAsync(file); } + + public async Task> GetChildContents(string fileOrDirectory, string filter) + { return Directory.GetFiles(fileOrDirectory, filter); } + + public async Task Exists(string file) + { + var attriutes = File.GetAttributes(file); + return attriutes.HasFlag(FileAttributes.Directory) ? Directory.Exists(file) : File.Exists(file); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Projects/Services/IFileService.cs b/src/OpenRpg.Projects/Services/IFileService.cs new file mode 100644 index 00000000..b8411ac8 --- /dev/null +++ b/src/OpenRpg.Projects/Services/IFileService.cs @@ -0,0 +1,8 @@ +namespace OpenRpg.Projects.Services; + +public interface IFileService +{ + Task GetContents(string file); + Task> GetChildContents(string fileOrDirectory, string filter); + Task Exists(string fileOrDirectory); +} \ No newline at end of file diff --git a/src/OpenRpg.sln b/src/OpenRpg.sln index cea19911..15df9043 100644 --- a/src/OpenRpg.sln +++ b/src/OpenRpg.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRpg.Core", "OpenRpg.Core\OpenRpg.Core.csproj", "{86FD715B-0B33-40EB-B8AC-25EE62398A66}" EndProject @@ -78,6 +78,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRpg.Entities", "OpenRpg EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRpg.AdviceEngine.Rx", "OpenRpg.AdviceEngine.Rx\OpenRpg.AdviceEngine.Rx.csproj", "{EBA05F43-4988-4B73-9E11-23360C1BF9A1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRpg.Projects", "OpenRpg.Projects\OpenRpg.Projects.csproj", "{174C18F8-D6D4-4CEE-8C00-5990B070D22B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Projects", "Projects", "{CA01AEB4-E0FA-47F9-9AE8-9D29FA76EC3E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRpg.Projects.Json", "OpenRpg.Projects.Json\OpenRpg.Projects.Json.csproj", "{51D63C2C-4366-4F16-AF1A-A21A70B1789C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -188,6 +194,14 @@ Global {EBA05F43-4988-4B73-9E11-23360C1BF9A1}.Debug|Any CPU.Build.0 = Debug|Any CPU {EBA05F43-4988-4B73-9E11-23360C1BF9A1}.Release|Any CPU.ActiveCfg = Release|Any CPU {EBA05F43-4988-4B73-9E11-23360C1BF9A1}.Release|Any CPU.Build.0 = Release|Any CPU + {174C18F8-D6D4-4CEE-8C00-5990B070D22B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {174C18F8-D6D4-4CEE-8C00-5990B070D22B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {174C18F8-D6D4-4CEE-8C00-5990B070D22B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {174C18F8-D6D4-4CEE-8C00-5990B070D22B}.Release|Any CPU.Build.0 = Release|Any CPU + {51D63C2C-4366-4F16-AF1A-A21A70B1789C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {51D63C2C-4366-4F16-AF1A-A21A70B1789C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51D63C2C-4366-4F16-AF1A-A21A70B1789C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {51D63C2C-4366-4F16-AF1A-A21A70B1789C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {86FD715B-0B33-40EB-B8AC-25EE62398A66} = {6BE3D2A4-F53A-4879-868E-A7522A445FE9} @@ -216,5 +230,8 @@ Global {A71DC9D4-43E8-4E3C-B294-29B0C2E87C39} = {8BEAB2AD-426F-41A7-8378-8D29B8C07D26} {776F3D4B-B89F-4407-BAA7-5E367F643B69} = {6BE3D2A4-F53A-4879-868E-A7522A445FE9} {EBA05F43-4988-4B73-9E11-23360C1BF9A1} = {9ABACD9E-828C-48B7-985D-CFC03A05DF8D} + {CA01AEB4-E0FA-47F9-9AE8-9D29FA76EC3E} = {8BEAB2AD-426F-41A7-8378-8D29B8C07D26} + {174C18F8-D6D4-4CEE-8C00-5990B070D22B} = {CA01AEB4-E0FA-47F9-9AE8-9D29FA76EC3E} + {51D63C2C-4366-4F16-AF1A-A21A70B1789C} = {CA01AEB4-E0FA-47F9-9AE8-9D29FA76EC3E} EndGlobalSection EndGlobal From 029e6224a25c551bc6c0848f32232f3f3a5f8ac3 Mon Sep 17 00:00:00 2001 From: LP Date: Sun, 10 May 2026 09:08:38 +0100 Subject: [PATCH 037/153] Fixed loading for effects/requirements --- .../Persistence/LoadProjectExecutor.cs | 7 ++- .../Variables/CustomVariableTypes.cs | 7 --- .../Editors/Common/AssetCodeEditor.razor | 4 +- .../Modules/DataServiceModule.cs | 2 + .../Locales/JsonLocaleDatastorePopulator.cs | 4 +- .../Loaders/Locales/JsonLocaleLoader.cs | 7 ++- .../JsonTemplateDatastorePopulator.cs | 6 +- .../Loaders/Templates/JsonTemplateLoader.cs | 58 ++++++++++++++++++- .../Services/DefaultFileService.cs | 4 +- 9 files changed, 76 insertions(+), 23 deletions(-) delete mode 100644 src/OpenRpg.Editor.Infrastructure/Variables/CustomVariableTypes.cs diff --git a/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs b/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs index a97bd09c..4277cf66 100644 --- a/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs +++ b/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs @@ -34,8 +34,9 @@ public LoadProjectExecutor(EditorState editorState, EditorDatasource editorDatas public async Task Execute(string projectFile) { var project = await ProjectLoader.LoadProject(projectFile); - EditorState.CurrentProject = new LoadedProject() { Project = project, ProjectPath = Path.GetDirectoryName(projectFile) }; - await TemplateDatastorePopulator.PopulateDatastore(project, projectFile, EditorDatasource); - await LocaleDatastorePopulator.PopulateDatastore(project, projectFile, EditorLocaleDatasource); + var projectPath = Path.GetDirectoryName(projectFile); + EditorState.CurrentProject = new LoadedProject() { Project = project, ProjectPath = projectPath }; + await TemplateDatastorePopulator.PopulateDatastore(project, projectPath, EditorDatasource); + await LocaleDatastorePopulator.PopulateDatastore(project, projectPath, EditorLocaleDatasource); } } \ No newline at end of file diff --git a/src/OpenRpg.Editor.Infrastructure/Variables/CustomVariableTypes.cs b/src/OpenRpg.Editor.Infrastructure/Variables/CustomVariableTypes.cs deleted file mode 100644 index 223a6815..00000000 --- a/src/OpenRpg.Editor.Infrastructure/Variables/CustomVariableTypes.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace OpenRpg.Editor.Infrastructure.Variables -{ - public class CustomVariableTypes - { - public static int AssetCode = 500; - } -} \ No newline at end of file diff --git a/src/OpenRpg.Editor.UI/Components/Editors/Common/AssetCodeEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/Common/AssetCodeEditor.razor index c437b4cd..ec5d6342 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/Common/AssetCodeEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/Common/AssetCodeEditor.razor @@ -1,6 +1,6 @@ @using OpenRpg.Core.Templates.Variables -@using OpenRpg.Editor.Infrastructure.Variables @using OpenRpg.Entities.Extensions +@using OpenRpg.Entities.Types
    @@ -29,7 +29,7 @@ protected override void OnInitialized() { base.OnInitialized(); - if (!Variables.ContainsKey(CustomVariableTypes.AssetCode)) + if (!Variables.ContainsKey(CoreAnyVariableTypes.AssetCode)) { Variables.AssetCode = DefaultAssetCode; } } diff --git a/src/OpenRpg.Editor/Modules/DataServiceModule.cs b/src/OpenRpg.Editor/Modules/DataServiceModule.cs index 919ecf9c..6a614346 100644 --- a/src/OpenRpg.Editor/Modules/DataServiceModule.cs +++ b/src/OpenRpg.Editor/Modules/DataServiceModule.cs @@ -20,6 +20,7 @@ using OpenRpg.Projects.Loaders; using OpenRpg.Projects.Loaders.Locales; using OpenRpg.Projects.Loaders.Templates; +using OpenRpg.Projects.Services; using Persistity.Core.Serialization; using Persistity.Flow.Builders; using Persistity.Serializers.Json; @@ -52,6 +53,7 @@ public static void Setup(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleDatastorePopulator.cs b/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleDatastorePopulator.cs index df31ccf1..cef0968d 100644 --- a/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleDatastorePopulator.cs +++ b/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleDatastorePopulator.cs @@ -24,9 +24,9 @@ public virtual async Task> GetAllLocaleFiles(string public async Task PopulateDatastore(Project project, string projectPath, ILocaleDataSource dataSource) { var localesFolderPath = project.LocalesFolder; - var absoluteLocaleFolderPath = $"{projectPath}/{localesFolderPath}"; + var absoluteLocaleFolderPath = Path.Combine(projectPath, localesFolderPath); var localePathExists = await FileService.Exists(absoluteLocaleFolderPath); - if(localePathExists) { throw new Exception($"Locale folder [{absoluteLocaleFolderPath}] cannot be found"); } + if(!localePathExists) { throw new Exception($"Locale folder [{absoluteLocaleFolderPath}] cannot be found"); } var localeFiles = await GetAllLocaleFiles(absoluteLocaleFolderPath); foreach (var localeFile in localeFiles) diff --git a/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleLoader.cs b/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleLoader.cs index 05112116..a996d58a 100644 --- a/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleLoader.cs +++ b/src/OpenRpg.Projects.Json/Loaders/Locales/JsonLocaleLoader.cs @@ -11,7 +11,12 @@ namespace OpenRpg.Projects.Json.Loaders.Locales; public class JsonLocaleLoader : ILocaleLoader { public IFileService FileService { get; } - + + public JsonLocaleLoader(IFileService fileService) + { + FileService = fileService; + } + public async Task LoadLocales(Project project, string localeFilePath) { var localePathExists = await FileService.Exists(localeFilePath); diff --git a/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateDatastorePopulator.cs b/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateDatastorePopulator.cs index 65eca05e..196e85a8 100644 --- a/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateDatastorePopulator.cs +++ b/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateDatastorePopulator.cs @@ -27,9 +27,9 @@ public JsonTemplateDatastorePopulator(IFileService fileService, ITemplateLoader public async Task PopulateDatastore(Project project, string projectPath, IDataSource dataSource) { var templateFolderPath = project.TemplatesFolder; - var absoluteTemplateFolderPath = $"{projectPath}/{templateFolderPath}"; + var absoluteTemplateFolderPath = Path.Combine(projectPath, templateFolderPath); var templatePathExists = await FileService.Exists(absoluteTemplateFolderPath); - if(templatePathExists) { throw new Exception($"Template folder [{absoluteTemplateFolderPath}] cannot be found"); } + if(!templatePathExists) { throw new Exception($"Template folder [{absoluteTemplateFolderPath}] cannot be found"); } await ProcessTemplates(project, absoluteTemplateFolderPath, dataSource); await ProcessTemplates(project, absoluteTemplateFolderPath, dataSource); @@ -41,7 +41,7 @@ public async Task PopulateDatastore(Project project, string projectPath, IDataSo protected async Task ProcessTemplates(Project project, string templateFolderPath, IDataSource dataSource) where T : ITemplate { - var itemTemplatePath = $"{templateFolderPath}/{typeof(T).Name}.json"; + var itemTemplatePath = Path.Combine(templateFolderPath, $"{typeof(T).Name}.json"); var templatePathExists = await FileService.Exists(itemTemplatePath); if(!templatePathExists) { throw new Exception($"Template file [{itemTemplatePath}] cannot be found"); } diff --git a/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateLoader.cs b/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateLoader.cs index ef5a6de8..3185b606 100644 --- a/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateLoader.cs +++ b/src/OpenRpg.Projects.Json/Loaders/Templates/JsonTemplateLoader.cs @@ -1,8 +1,10 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using OpenRpg.Core.Extensions; +using OpenRpg.Core.Effects; +using OpenRpg.Core.Requirements; using OpenRpg.Core.Templates; -using OpenRpg.Data; +using OpenRpg.Core.Variables; +using OpenRpg.Entities.Types; using OpenRpg.Projects.Loaders.Templates; using OpenRpg.Projects.Models; using OpenRpg.Projects.Services; @@ -12,6 +14,7 @@ namespace OpenRpg.Projects.Json.Loaders.Templates; public class JsonTemplateLoader : ITemplateLoader { public IFileService FileService { get; } + public JsonSerializer JsonSerializer { get; } = new() { TypeNameHandling = TypeNameHandling.Auto }; public JsonTemplateLoader(IFileService fileService) { @@ -42,9 +45,58 @@ public virtual async Task> ProcessAllTemplateData(Proj public virtual T ProcessTemplateData(JToken templateData) where T : ITemplate { - var template = templateData.ToObject(new JsonSerializer{ TypeNameHandling = TypeNameHandling.Auto }); + var template = templateData.ToObject(JsonSerializer); if(template is null) { throw new Exception($"Failed to deserialize template data of type [{typeof(T).Name}] - {templateData}"); } + + var dynamicVariables = GetDynamicVariables(template); + if (dynamicVariables is null) { return template; } + ProcessKnownVariables(dynamicVariables); + foreach (var variable in dynamicVariables) + { dynamicVariables[variable.Key] = DynamicConvert(variable.Value)!; } + return template; } + + public virtual void ProcessKnownVariables(IKeyedVariables dynamicVariables) + { + foreach (var variable in dynamicVariables) + { + if (variable.Key == CoreTemplateVariableTypes.Effects) + { + var jsonArray = (variable.Value as JArray); + dynamicVariables[variable.Key] = jsonArray.ToObject>(JsonSerializer); + continue; + } + + if(variable.Key == CoreTemplateVariableTypes.Requirements) + { + var jsonArray = (variable.Value as JArray); + dynamicVariables[variable.Key] = jsonArray.ToObject>(JsonSerializer); + continue; + } + } + } + + public IKeyedVariables? GetDynamicVariables(T template) where T : ITemplate + { + var propertyName = nameof(ITemplate<>.Variables); + var templateType = template.GetType(); + var property = templateType.GetProperty(propertyName); + if(property is null) { return null; } + + var variables = property.GetValue(template) as IKeyedVariables; + return variables; + } + + public object? DynamicConvert(object? value) + { + return value switch + { + JObject obj => obj.ToObject(JsonSerializer), + JArray arr => arr.Select(DynamicConvert).ToArray(), + JValue val => val.Value, + _ => value + }; + } } \ No newline at end of file diff --git a/src/OpenRpg.Projects/Services/DefaultFileService.cs b/src/OpenRpg.Projects/Services/DefaultFileService.cs index 25f48a98..5f1747fa 100644 --- a/src/OpenRpg.Projects/Services/DefaultFileService.cs +++ b/src/OpenRpg.Projects/Services/DefaultFileService.cs @@ -10,7 +10,7 @@ public async Task> GetChildContents(string fileOrDir public async Task Exists(string file) { - var attriutes = File.GetAttributes(file); - return attriutes.HasFlag(FileAttributes.Directory) ? Directory.Exists(file) : File.Exists(file); + var attributes = File.GetAttributes(file); + return attributes.HasFlag(FileAttributes.Directory) ? Directory.Exists(file) : File.Exists(file); } } \ No newline at end of file From 56c8f70963a173e52cd94eaaafb4c64e629163b1 Mon Sep 17 00:00:00 2001 From: LP Date: Sun, 10 May 2026 09:38:11 +0100 Subject: [PATCH 038/153] Updated csproj metadata --- src/OpenRpg.Projects.Json/OpenRpg.Projects.Json.csproj | 7 +++++++ src/OpenRpg.Projects/OpenRpg.Projects.csproj | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/OpenRpg.Projects.Json/OpenRpg.Projects.Json.csproj b/src/OpenRpg.Projects.Json/OpenRpg.Projects.Json.csproj index 3abac65d..fa4da672 100644 --- a/src/OpenRpg.Projects.Json/OpenRpg.Projects.Json.csproj +++ b/src/OpenRpg.Projects.Json/OpenRpg.Projects.Json.csproj @@ -1,9 +1,16 @@  + 0.0.0 net10.0 enable enable + Grofit (LP) + https://github.com/openrpg/OpenRpg/blob/master/LICENSE + https://github.com/openrpg/OpenRpg + An open source set of base components to build RPG games + rpg game-development xna monogame unity godot + 14 diff --git a/src/OpenRpg.Projects/OpenRpg.Projects.csproj b/src/OpenRpg.Projects/OpenRpg.Projects.csproj index 639c8138..0c97c335 100644 --- a/src/OpenRpg.Projects/OpenRpg.Projects.csproj +++ b/src/OpenRpg.Projects/OpenRpg.Projects.csproj @@ -1,9 +1,16 @@  + 0.0.0 net10.0 enable enable + Grofit (LP) + https://github.com/openrpg/OpenRpg/blob/master/LICENSE + https://github.com/openrpg/OpenRpg + An open source set of base components to build RPG games + rpg game-development xna monogame unity godot + 14 From 3dbe45cdc956046d0bae55cbe9f04cb758bd5f68 Mon Sep 17 00:00:00 2001 From: LP Date: Sun, 10 May 2026 10:10:31 +0100 Subject: [PATCH 039/153] Added basic helper high level data loader --- .../Persistence/EditorDataLoader.cs | 36 ++++++++++++++++ .../Persistence/LoadProjectExecutor.cs | 42 ------------------- .../Editors/List/RewardsEditor.razor | 2 +- src/OpenRpg.Editor.UI/Pages/Index.razor | 4 +- .../Modules/DataServiceModule.cs | 3 +- .../Loaders/JsonProjectLoader.cs | 1 + .../Loaders/FileDataLoader.cs | 36 ++++++++++++++++ src/OpenRpg.Projects/Loaders/IDataLoader.cs | 11 +++++ .../Loaders/{ => Projects}/IProjectLoader.cs | 2 +- src/OpenRpg.Quests/Quest.cs | 9 ++-- 10 files changed, 94 insertions(+), 52 deletions(-) create mode 100644 src/OpenRpg.Editor.Infrastructure/Persistence/EditorDataLoader.cs delete mode 100644 src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs create mode 100644 src/OpenRpg.Projects/Loaders/FileDataLoader.cs create mode 100644 src/OpenRpg.Projects/Loaders/IDataLoader.cs rename src/OpenRpg.Projects/Loaders/{ => Projects}/IProjectLoader.cs (89%) diff --git a/src/OpenRpg.Editor.Infrastructure/Persistence/EditorDataLoader.cs b/src/OpenRpg.Editor.Infrastructure/Persistence/EditorDataLoader.cs new file mode 100644 index 00000000..ffafc767 --- /dev/null +++ b/src/OpenRpg.Editor.Infrastructure/Persistence/EditorDataLoader.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using OpenRpg.Data; +using OpenRpg.Editor.Core.Models; +using OpenRpg.Editor.Infrastructure.Persistence.Migrations; +using OpenRpg.Localization.Data.DataSources; +using OpenRpg.Projects.Loaders; +using OpenRpg.Projects.Loaders.Locales; +using OpenRpg.Projects.Loaders.Projects; +using OpenRpg.Projects.Loaders.Templates; +using OpenRpg.Projects.Models; + +namespace OpenRpg.Editor.Infrastructure.Persistence; + +public class EditorDataLoader : FileDataLoader +{ + public EditorState EditorState { get; } + public IEnumerable ProjectMigrations { get; } + + public EditorDataLoader(IDataSource datasource, ILocaleDataSource localeDatasource, IProjectLoader projectLoader, ITemplateDatastorePopulator templateDatastorePopulator, ILocaleDatastorePopulator localeDatastorePopulator, EditorState editorState, IEnumerable projectMigrations) : base(datasource, localeDatasource, projectLoader, templateDatastorePopulator, localeDatastorePopulator) + { + EditorState = editorState; + ProjectMigrations = projectMigrations; + } + + public override async Task Load(string projectFile) + { + var project = await base.Load(projectFile); + + var projectPath = Path.GetDirectoryName(projectFile); + EditorState.CurrentProject = new LoadedProject() { Project = project, ProjectPath = projectPath }; + + return project; + } +} \ No newline at end of file diff --git a/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs b/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs deleted file mode 100644 index 4277cf66..00000000 --- a/src/OpenRpg.Editor.Infrastructure/Persistence/LoadProjectExecutor.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using OpenRpg.Editor.Core.Models; -using OpenRpg.Editor.Infrastructure.Data; -using OpenRpg.Editor.Infrastructure.Persistence.Migrations; -using OpenRpg.Projects.Loaders; -using OpenRpg.Projects.Loaders.Locales; -using OpenRpg.Projects.Loaders.Templates; - -namespace OpenRpg.Editor.Infrastructure.Persistence; - -public class LoadProjectExecutor -{ - public EditorState EditorState { get; } - public EditorDatasource EditorDatasource { get; } - public EditorLocaleDatasource EditorLocaleDatasource { get; } - public IEnumerable ProjectMigrations { get; } - public IProjectLoader ProjectLoader { get; } - public ITemplateDatastorePopulator TemplateDatastorePopulator { get; } - public ILocaleDatastorePopulator LocaleDatastorePopulator { get; } - - public LoadProjectExecutor(EditorState editorState, EditorDatasource editorDatasource, EditorLocaleDatasource editorLocaleDatasource, IEnumerable projectMigrations, IProjectLoader projectLoader, ITemplateDatastorePopulator templateDatastorePopulator, ILocaleDatastorePopulator localeDatastorePopulator) - { - EditorState = editorState; - EditorDatasource = editorDatasource; - EditorLocaleDatasource = editorLocaleDatasource; - ProjectMigrations = projectMigrations; - ProjectLoader = projectLoader; - TemplateDatastorePopulator = templateDatastorePopulator; - LocaleDatastorePopulator = localeDatastorePopulator; - } - - public async Task Execute(string projectFile) - { - var project = await ProjectLoader.LoadProject(projectFile); - var projectPath = Path.GetDirectoryName(projectFile); - EditorState.CurrentProject = new LoadedProject() { Project = project, ProjectPath = projectPath }; - await TemplateDatastorePopulator.PopulateDatastore(project, projectPath, EditorDatasource); - await LocaleDatastorePopulator.PopulateDatastore(project, projectPath, EditorLocaleDatasource); - } -} \ No newline at end of file diff --git a/src/OpenRpg.Editor.UI/Components/Editors/List/RewardsEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/List/RewardsEditor.razor index 61d90bf0..7f82f825 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/List/RewardsEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/List/RewardsEditor.razor @@ -5,7 +5,7 @@ - >Reward Type + Reward Type Reward Chance Associated Id Associated Value diff --git a/src/OpenRpg.Editor.UI/Pages/Index.razor b/src/OpenRpg.Editor.UI/Pages/Index.razor index da893f11..42064e82 100644 --- a/src/OpenRpg.Editor.UI/Pages/Index.razor +++ b/src/OpenRpg.Editor.UI/Pages/Index.razor @@ -11,7 +11,7 @@ @inject IFileBrowser FileBrowser @inject EditorState EditorState @inject CreateProjectExecutor CreateProjectExecutor; -@inject LoadProjectExecutor LoadProjectExecutor; +@inject EditorDataLoader EditorDataLoader; @inject IEventBus EventBus;

    OpenRpg Data Editor

    @@ -58,7 +58,7 @@ var projectFile = FileBrowser.BrowseToOpenFile(filterList: "*.json"); if(string.IsNullOrEmpty(projectFile)) { return; } - await LoadProjectExecutor.Execute(projectFile); + await EditorDataLoader.Load(projectFile); EventBus.PublishAsync(new ProjectChangedEvent()); } } \ No newline at end of file diff --git a/src/OpenRpg.Editor/Modules/DataServiceModule.cs b/src/OpenRpg.Editor/Modules/DataServiceModule.cs index 6a614346..097c7910 100644 --- a/src/OpenRpg.Editor/Modules/DataServiceModule.cs +++ b/src/OpenRpg.Editor/Modules/DataServiceModule.cs @@ -19,6 +19,7 @@ using OpenRpg.Projects.Json.Loaders.Templates; using OpenRpg.Projects.Loaders; using OpenRpg.Projects.Loaders.Locales; +using OpenRpg.Projects.Loaders.Projects; using OpenRpg.Projects.Loaders.Templates; using OpenRpg.Projects.Services; using Persistity.Core.Serialization; @@ -46,7 +47,7 @@ public static void Setup(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(x => x.GetService()); diff --git a/src/OpenRpg.Projects.Json/Loaders/JsonProjectLoader.cs b/src/OpenRpg.Projects.Json/Loaders/JsonProjectLoader.cs index 1ae5c365..10668412 100644 --- a/src/OpenRpg.Projects.Json/Loaders/JsonProjectLoader.cs +++ b/src/OpenRpg.Projects.Json/Loaders/JsonProjectLoader.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using OpenRpg.Projects.Loaders; +using OpenRpg.Projects.Loaders.Projects; using OpenRpg.Projects.Models; using OpenRpg.Projects.Services; diff --git a/src/OpenRpg.Projects/Loaders/FileDataLoader.cs b/src/OpenRpg.Projects/Loaders/FileDataLoader.cs new file mode 100644 index 00000000..886f11e4 --- /dev/null +++ b/src/OpenRpg.Projects/Loaders/FileDataLoader.cs @@ -0,0 +1,36 @@ +using OpenRpg.Data; +using OpenRpg.Localization.Data.DataSources; +using OpenRpg.Projects.Loaders.Locales; +using OpenRpg.Projects.Loaders.Projects; +using OpenRpg.Projects.Loaders.Templates; +using OpenRpg.Projects.Models; + +namespace OpenRpg.Projects.Loaders; + +public class FileDataLoader : IDataLoader +{ + public IDataSource Datasource { get; } + public ILocaleDataSource LocaleDatasource { get; } + + public IProjectLoader ProjectLoader { get; } + public ITemplateDatastorePopulator TemplateDatastorePopulator { get; } + public ILocaleDatastorePopulator LocaleDatastorePopulator { get; } + + public FileDataLoader(IDataSource datasource, ILocaleDataSource localeDatasource, IProjectLoader projectLoader, ITemplateDatastorePopulator templateDatastorePopulator, ILocaleDatastorePopulator localeDatastorePopulator) + { + Datasource = datasource; + LocaleDatasource = localeDatasource; + ProjectLoader = projectLoader; + TemplateDatastorePopulator = templateDatastorePopulator; + LocaleDatastorePopulator = localeDatastorePopulator; + } + + public virtual async Task Load(string projectFile) + { + var project = await ProjectLoader.LoadProject(projectFile); + var projectPath = Path.GetDirectoryName(projectFile); + await TemplateDatastorePopulator.PopulateDatastore(project, projectPath, Datasource); + await LocaleDatastorePopulator.PopulateDatastore(project, projectPath, LocaleDatasource); + return project; + } +} \ No newline at end of file diff --git a/src/OpenRpg.Projects/Loaders/IDataLoader.cs b/src/OpenRpg.Projects/Loaders/IDataLoader.cs new file mode 100644 index 00000000..7178df70 --- /dev/null +++ b/src/OpenRpg.Projects/Loaders/IDataLoader.cs @@ -0,0 +1,11 @@ +using OpenRpg.Projects.Models; + +namespace OpenRpg.Projects.Loaders; + +/// +/// This acts as a high level loader for all data related to a project +/// +public interface IDataLoader +{ + Task Load(string projectFile); +} \ No newline at end of file diff --git a/src/OpenRpg.Projects/Loaders/IProjectLoader.cs b/src/OpenRpg.Projects/Loaders/Projects/IProjectLoader.cs similarity index 89% rename from src/OpenRpg.Projects/Loaders/IProjectLoader.cs rename to src/OpenRpg.Projects/Loaders/Projects/IProjectLoader.cs index af6eb03f..78ff0328 100644 --- a/src/OpenRpg.Projects/Loaders/IProjectLoader.cs +++ b/src/OpenRpg.Projects/Loaders/Projects/IProjectLoader.cs @@ -1,6 +1,6 @@ using OpenRpg.Projects.Models; -namespace OpenRpg.Projects.Loaders; +namespace OpenRpg.Projects.Loaders.Projects; public interface IProjectLoader { diff --git a/src/OpenRpg.Quests/Quest.cs b/src/OpenRpg.Quests/Quest.cs index 344b6777..9ccbd52e 100644 --- a/src/OpenRpg.Quests/Quest.cs +++ b/src/OpenRpg.Quests/Quest.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using OpenRpg.Core.Templates; using OpenRpg.Quests.Variables; @@ -12,9 +11,9 @@ public class Quest : ITemplate public string DescriptionLocaleId { get; set; } public bool IsRepeatable { get; set; } - public IReadOnlyCollection Objectives { get; set; } = Array.Empty(); - public IReadOnlyCollection Rewards { get; set; } = Array.Empty(); - public IReadOnlyCollection Gifts { get; set; } = Array.Empty(); - public QuestVariables Variables { get; set; } = new QuestVariables(); + public IReadOnlyCollection Objectives { get; set; } = []; + public IReadOnlyCollection Rewards { get; set; } = []; + public IReadOnlyCollection Gifts { get; set; } = []; + public QuestVariables Variables { get; set; } = new(); } } \ No newline at end of file From 0667de3bd904bc58d99ce14b18b9f5a35d05d52f Mon Sep 17 00:00:00 2001 From: LP Date: Mon, 11 May 2026 12:23:25 +0100 Subject: [PATCH 040/153] current spike has quirks --- .../Genres/IGenrePlugin.cs | 16 ++ .../Genres/IGenreRuntimeServices.cs | 8 + .../Genres/IGenreTypesProvider.cs | 20 ++ src/OpenRpg.Editor.Core/Genres/OptionData.cs | 13 + src/OpenRpg.Editor.Core/Models/EditorState.cs | 15 +- .../Helpers/TypesHelper.cs | 38 +-- .../OpenRpg.Editor.Infrastructure.csproj | 5 +- .../Persistence/CreateProjectExecutor.cs | 15 +- .../Plugins/DefaultGenreProvider.cs | 153 ++++++++++++ .../Plugins/GenrePluginLoader.cs | 121 ++++++++++ .../Plugins/GenreService.cs | 169 +++++++++++++ .../Editors/Common/ScaledEffectEditor.razor | 21 +- .../Common/TradeSkillDetailsEditor.razor | 14 +- .../Editors/List/EffectsEditor.razor | 19 +- .../List/ItemTemplateDetailsEditor.razor | 9 +- .../List/ModificationAllowancesEditor.razor | 21 +- .../Editors/List/ObjectivesEditor.razor | 11 +- .../Editors/List/RequirementsEditor.razor | 9 +- .../Editors/List/RewardsEditor.razor | 9 +- .../Components/GenreAwareComponent.cs | 10 + .../OpenRpg.Editor.UI.csproj | 1 - .../Pages/GenreManagerPage.razor | 226 ++++++++++++++++++ src/OpenRpg.Editor.UI/Pages/Index.razor | 76 +++++- .../Services/GenreTypesService.cs | 51 ++++ src/OpenRpg.Editor.UI/Shared/TopMenu.razor | 12 + .../Modules/DataServiceModule.cs | 6 + src/OpenRpg.Genres.Fantasy/FantasyPlugin.cs | 80 +++++++ .../OpenRpg.Genres.Fantasy.csproj | 1 + .../Models/PluginDescriptor.cs | 1 + 29 files changed, 1061 insertions(+), 89 deletions(-) create mode 100644 src/OpenRpg.Editor.Core/Genres/IGenrePlugin.cs create mode 100644 src/OpenRpg.Editor.Core/Genres/IGenreRuntimeServices.cs create mode 100644 src/OpenRpg.Editor.Core/Genres/IGenreTypesProvider.cs create mode 100644 src/OpenRpg.Editor.Core/Genres/OptionData.cs create mode 100644 src/OpenRpg.Editor.Infrastructure/Plugins/DefaultGenreProvider.cs create mode 100644 src/OpenRpg.Editor.Infrastructure/Plugins/GenrePluginLoader.cs create mode 100644 src/OpenRpg.Editor.Infrastructure/Plugins/GenreService.cs create mode 100644 src/OpenRpg.Editor.UI/Components/GenreAwareComponent.cs create mode 100644 src/OpenRpg.Editor.UI/Pages/GenreManagerPage.razor create mode 100644 src/OpenRpg.Editor.UI/Services/GenreTypesService.cs create mode 100644 src/OpenRpg.Genres.Fantasy/FantasyPlugin.cs diff --git a/src/OpenRpg.Editor.Core/Genres/IGenrePlugin.cs b/src/OpenRpg.Editor.Core/Genres/IGenrePlugin.cs new file mode 100644 index 00000000..28815e62 --- /dev/null +++ b/src/OpenRpg.Editor.Core/Genres/IGenrePlugin.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace OpenRpg.Editor.Core.Genres; + +public interface IGenrePlugin +{ + string Id { get; } + string Name { get; } + string Version { get; } + string Description { get; } + + IGenreTypesProvider TypesProvider { get; } + IGenreRuntimeServices RuntimeServices { get; } + + void Initialize(IServiceCollection services); +} diff --git a/src/OpenRpg.Editor.Core/Genres/IGenreRuntimeServices.cs b/src/OpenRpg.Editor.Core/Genres/IGenreRuntimeServices.cs new file mode 100644 index 00000000..e0a8763c --- /dev/null +++ b/src/OpenRpg.Editor.Core/Genres/IGenreRuntimeServices.cs @@ -0,0 +1,8 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace OpenRpg.Editor.Core.Genres; + +public interface IGenreRuntimeServices +{ + void RegisterServices(IServiceCollection services); +} diff --git a/src/OpenRpg.Editor.Core/Genres/IGenreTypesProvider.cs b/src/OpenRpg.Editor.Core/Genres/IGenreTypesProvider.cs new file mode 100644 index 00000000..a8a1a81c --- /dev/null +++ b/src/OpenRpg.Editor.Core/Genres/IGenreTypesProvider.cs @@ -0,0 +1,20 @@ +namespace OpenRpg.Editor.Core.Genres; + +public interface IGenreTypesProvider +{ + string GenreId { get; } + string GenreName { get; } + + OptionData[] ItemTypes { get; } + OptionData[] ItemQualityTypes { get; } + OptionData[] RequirementTypes { get; } + OptionData[] EffectTypes { get; } + OptionData[] RewardTypes { get; } + OptionData[] ModificationTypes { get; } + OptionData[] ObjectiveTypes { get; } + OptionData[] EffectScalingType { get; } + OptionData[] StatTypes { get; } + OptionData[] StateTypes { get; } + OptionData[] CraftingSkillTypes { get; } + OptionData[] GatheringSkillTypes { get; } +} diff --git a/src/OpenRpg.Editor.Core/Genres/OptionData.cs b/src/OpenRpg.Editor.Core/Genres/OptionData.cs new file mode 100644 index 00000000..df13a1e0 --- /dev/null +++ b/src/OpenRpg.Editor.Core/Genres/OptionData.cs @@ -0,0 +1,13 @@ +namespace OpenRpg.Editor.Core.Genres; + +public class OptionData +{ + public int Id { get; } + public string Name { get; } + + public OptionData(int id, string name) + { + Id = id; + Name = name; + } +} diff --git a/src/OpenRpg.Editor.Core/Models/EditorState.cs b/src/OpenRpg.Editor.Core/Models/EditorState.cs index aa265ab8..4c25746c 100644 --- a/src/OpenRpg.Editor.Core/Models/EditorState.cs +++ b/src/OpenRpg.Editor.Core/Models/EditorState.cs @@ -1,6 +1,19 @@ +using System.Collections.Generic; +using OpenRpg.Editor.Core.Genres; +using OpenRpg.Projects.Models; + namespace OpenRpg.Editor.Core.Models; public class EditorState { public LoadedProject CurrentProject { get; set; } -} \ No newline at end of file + public IReadOnlyList AvailableGenres { get; set; } = new List(); + public IReadOnlyList EnabledGenres { get; set; } = new List(); + + public bool HasGenresLoaded => AvailableGenres.Count > 0; + public bool HasEnabledGenres => EnabledGenres.Count > 0; + + public IGenreTypesProvider CurrentTypesProvider { get; set; } + + public bool IsProjectLoaded => CurrentProject != null; +} diff --git a/src/OpenRpg.Editor.Infrastructure/Helpers/TypesHelper.cs b/src/OpenRpg.Editor.Infrastructure/Helpers/TypesHelper.cs index 9c736aa5..c9efede2 100644 --- a/src/OpenRpg.Editor.Infrastructure/Helpers/TypesHelper.cs +++ b/src/OpenRpg.Editor.Infrastructure/Helpers/TypesHelper.cs @@ -1,42 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using OpenRpg.CurveFunctions; -using OpenRpg.Editor.Infrastructure.Extensions; -using OpenRpg.Editor.Infrastructure.Models; -using OpenRpg.Entities.Types; -using OpenRpg.Genres.Fantasy.Types; -using OpenRpg.Quests.Types; - namespace OpenRpg.Editor.Infrastructure.Helpers { public static class TypesHelper { - public static OptionData[] GetTypesFor(Type typesObject) - { - var optionData = new List(); - var fields = typesObject.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy); - foreach (var property in fields) - { - var value = (int)property.GetValue(null); - optionData.Add(new OptionData(value, property.Name.MakeReadable())); - } - - return optionData.ToArray(); - } - - public static readonly OptionData[] GetItemTypes = GetTypesFor(typeof(FantasyItemTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetItemQualityTypes = GetTypesFor(typeof(FantasyItemQualityTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetRequirementTypes = GetTypesFor(typeof(FantasyRequirementTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetModificationTypes = GetTypesFor(typeof(FantasyModificationTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetEffectTypes = GetTypesFor(typeof(FantasyEffectTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetRewardTypes = GetTypesFor(typeof(FantasyRewardTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetObjectiveTypes = GetTypesFor(typeof(ObjectiveTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetEffectScalingType = GetTypesFor(typeof(CoreEffectScalingTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetStatTypes = GetTypesFor(typeof(FantasyEntityStatsVariableTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetStateTypes = GetTypesFor(typeof(FantasyEntityStateVariableTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetCraftingSkillTypes = GetTypesFor(typeof(FantasyTradeSkillTypes)).OrderBy(x => x.Id).ToArray(); - public static readonly OptionData[] GetGatheringSkillTypes = GetTypesFor(typeof(FantasyTradeSkillTypes)).OrderBy(x => x.Id).ToArray(); } -} \ No newline at end of file +} diff --git a/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj b/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj index 5c0ab20f..eaf03a45 100644 --- a/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj +++ b/src/OpenRpg.Editor.Infrastructure/OpenRpg.Editor.Infrastructure.csproj @@ -14,10 +14,13 @@
    + + true + + - diff --git a/src/OpenRpg.Editor.Infrastructure/Persistence/CreateProjectExecutor.cs b/src/OpenRpg.Editor.Infrastructure/Persistence/CreateProjectExecutor.cs index ea970831..d98d18e1 100644 --- a/src/OpenRpg.Editor.Infrastructure/Persistence/CreateProjectExecutor.cs +++ b/src/OpenRpg.Editor.Infrastructure/Persistence/CreateProjectExecutor.cs @@ -1,20 +1,33 @@ using System; +using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Newtonsoft.Json; using OpenRpg.Editor.Core.Extensions; using OpenRpg.Editor.Core.Models; +using OpenRpg.Projects.Models; namespace OpenRpg.Editor.Infrastructure.Persistence; public class CreateProjectExecutor(EditorState EditorState) { - public async Task Execute(string folderPath) + public async Task Execute(string folderPath, IEnumerable enabledGenreIds = null) { if(string.IsNullOrEmpty(folderPath)) { throw new ArgumentException("Folder path is empty", nameof(folderPath)); } + var plugins = new List(); + if (enabledGenreIds != null) + { + foreach (var id in enabledGenreIds) + { + plugins.Add(new PluginDescriptor { Id = id }); + } + } + var newProject = new LoadedProject { ProjectPath = folderPath }; + newProject.Project.Plugins = plugins; + var projectFile = $"{folderPath}/project.json"; var projectContent = JsonConvert.SerializeObject(newProject.Project, Formatting.Indented); diff --git a/src/OpenRpg.Editor.Infrastructure/Plugins/DefaultGenreProvider.cs b/src/OpenRpg.Editor.Infrastructure/Plugins/DefaultGenreProvider.cs new file mode 100644 index 00000000..675d643d --- /dev/null +++ b/src/OpenRpg.Editor.Infrastructure/Plugins/DefaultGenreProvider.cs @@ -0,0 +1,153 @@ +using Microsoft.Extensions.DependencyInjection; +using OpenRpg.Editor.Core.Genres; +using OpenRpg.Entities.Types; +using OpenRpg.Genres.Requirements; +using OpenRpg.Genres.Types; +using OpenRpg.Quests.Types; + +namespace OpenRpg.Editor.Infrastructure.Plugins; + +public class DefaultGenreTypesProvider : IGenreTypesProvider +{ + public string GenreId => "default"; + public string GenreName => "Default Types"; + + public OptionData[] ItemTypes => new OptionData[] + { + new(0, "Unknown"), + new(GenresItemTypes.QuestItem, "Quest Item"), + new(GenresItemTypes.GenericWeapon, "Weapon"), + new(GenresItemTypes.GenericItem, "Generic Item") + }; + + public OptionData[] ItemQualityTypes => new OptionData[] + { + new(0, "Unknown"), + new(GenresItemQualityTypes.JunkQuality, "Junk"), + new(GenresItemQualityTypes.CommonQuality, "Common"), + new(GenresItemQualityTypes.RareQuality, "Rare") + }; + + public OptionData[] RequirementTypes => new OptionData[] + { + new(GenreRequirementTypes.MaxHealthRequirement, "Max Health"), + new(GenreRequirementTypes.MaxStaminaRequirement, "Max Stamina"), + new(GenreRequirementTypes.MovementSpeedRequirement, "Movement Speed") + }; + + public OptionData[] EffectTypes => new OptionData[] + { + new(0, "Unknown"), + new(GenreEffectTypes.DamageBonusAmount, "Damage Bonus"), + new(GenreEffectTypes.DamageBonusPercentage, "Damage Bonus %"), + new(GenreEffectTypes.CriticalRateBonusAmount, "Critical Rate"), + new(GenreEffectTypes.CriticalDamageBonusAmount, "Critical Damage"), + new(GenreEffectTypes.DefenseBonusAmount, "Defense Bonus"), + new(GenreEffectTypes.HealthBonusAmount, "Max Health Bonus"), + new(GenreEffectTypes.HealthRestoreAmount, "Heal Amount"), + new(GenreEffectTypes.StaminaBonusAmount, "Max Stamina Bonus"), + new(GenreEffectTypes.StaminaRestoreAmount, "Stamina Restore"), + new(GenreEffectTypes.MovementSpeedBonusAmount, "Movement Speed Bonus"), + new(GenreEffectTypes.ExperienceRestoreAmount, "Experience") + }; + + public OptionData[] RewardTypes => new OptionData[] + { + new(0, "Unknown"), + new(GenreRewardTypes.ItemReward, "Item Reward"), + new(GenreRewardTypes.QuestReward, "Quest Reward"), + new(GenreRewardTypes.TriggerReward, "Trigger"), + new(GenreRewardTypes.CurrencyReward, "Currency") + }; + + public OptionData[] ModificationTypes => new OptionData[] + { + new(0, "Unknown") + }; + + public OptionData[] ObjectiveTypes => new OptionData[] + { + new(Quests.Types.ObjectiveTypes.UnknownObjective, "Unknown"), + new(Quests.Types.ObjectiveTypes.TriggerObjective, "Trigger"), + new(Quests.Types.ObjectiveTypes.ItemObjective, "Collect Item"), + new(Quests.Types.ObjectiveTypes.LevelObjective, "Reach Level"), + new(Quests.Types.ObjectiveTypes.ClassObjective, "Reach Class"), + new(GenresObjectiveTypes.CurrencyObjective, "Currency"), + new(GenresObjectiveTypes.EnemyDefeatedObjective, "Defeat Enemy"), + new(GenresObjectiveTypes.EnemySightedObjective, "See Enemy") + }; + + public OptionData[] EffectScalingType => new OptionData[] + { + new(0, "None"), + new(1, "Linear"), + new(2, "Percentage") + }; + + public OptionData[] StatTypes => new OptionData[] + { + new(0, "Unknown"), + new(1, "Strength"), + new(2, "Dexterity"), + new(3, "Intelligence"), + new(4, "Wisdom"), + new(5, "Endurance"), + new(6, "Charisma"), + new(GenreEntityStatsVariableTypes.MaxHealth, "Max Health"), + new(GenreEntityStatsVariableTypes.HealthRegen, "Health Regen"), + new(GenreEntityStatsVariableTypes.MaxStamina, "Max Stamina"), + new(GenreEntityStatsVariableTypes.StaminaRegen, "Stamina Regen"), + new(GenreEntityStatsVariableTypes.MovementSpeed, "Movement Speed"), + new(GenreEntityStatsVariableTypes.Damage, "Damage"), + new(GenreEntityStatsVariableTypes.CriticalDamageChance, "Critical Chance"), + new(GenreEntityStatsVariableTypes.CriticalDamageMultiplier, "Critical Damage"), + new(GenreEntityStatsVariableTypes.Defense, "Defense") + }; + + public OptionData[] StateTypes => new OptionData[] + { + new(0, "Unknown"), + new(GenreEntityStateVariableTypes.Health, "Health"), + new(GenreEntityStateVariableTypes.Stamina, "Stamina") + }; + + public OptionData[] CraftingSkillTypes => new OptionData[] + { + new(0, "Unknown") + }; + + public OptionData[] GatheringSkillTypes => new OptionData[] + { + new(0, "Unknown") + }; +} + +public class DefaultGenreRuntimeServices : IGenreRuntimeServices +{ + public void RegisterServices(IServiceCollection services) + { + services.AddSingleton(); + } +} + +public class DefaultGenrePlugin : IGenrePlugin +{ + public string Id => "default"; + public string Name => "Default Types"; + public string Version => "1.0.0"; + public string Description => "Built-in default types from OpenRpg.Genres library"; + + public IGenreTypesProvider TypesProvider { get; private set; } + public IGenreRuntimeServices RuntimeServices { get; private set; } + + public DefaultGenrePlugin() + { + TypesProvider = new DefaultGenreTypesProvider(); + RuntimeServices = new DefaultGenreRuntimeServices(); + } + + public void Initialize(IServiceCollection services) + { + RuntimeServices.RegisterServices(services); + } +} \ No newline at end of file diff --git a/src/OpenRpg.Editor.Infrastructure/Plugins/GenrePluginLoader.cs b/src/OpenRpg.Editor.Infrastructure/Plugins/GenrePluginLoader.cs new file mode 100644 index 00000000..9e3edd77 --- /dev/null +++ b/src/OpenRpg.Editor.Infrastructure/Plugins/GenrePluginLoader.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using OpenRpg.Editor.Core.Genres; +using OpenRpg.Editor.Core.Services.Paths; +using OpenRpg.Editor.Core.Services.Notifications; +using OpenRpg.Editor.Core.Events; + +namespace OpenRpg.Editor.Infrastructure.Plugins; + +public class GenrePluginLoader +{ + private readonly INotifier _notifier; + private readonly List _loadedPlugins = new(); + private readonly List _loadedAssemblies = new(); + + public IReadOnlyList LoadedPlugins => _loadedPlugins.AsReadOnly(); + + public GenrePluginLoader(INotifier notifier) + { + _notifier = notifier; + } + + public void LoadPlugins() + { + _loadedPlugins.Clear(); + var pluginPath = PathHelper.PluginPath; + + if (!Directory.Exists(pluginPath)) + { + Directory.CreateDirectory(pluginPath); + return; + } + + var dllFiles = Directory.GetFiles(pluginPath, "OpenRpg.Genres*.dll", SearchOption.TopDirectoryOnly); + + foreach (var dllPath in dllFiles) + { + LoadPluginFromDllSync(dllPath); + } + } + + public void LoadPluginsAsync() + { + LoadPlugins(); + } + + private void LoadPluginFromDllSync(string dllPath) + { + try + { + var assemblyName = AssemblyName.GetAssemblyName(dllPath); + var assembly = Assembly.Load(assemblyName); + _loadedAssemblies.Add(assembly); + + var pluginType = assembly.GetTypes() + .FirstOrDefault(t => typeof(IGenrePlugin).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); + + if (pluginType == null) + { + return; + } + + var plugin = (IGenrePlugin)Activator.CreateInstance(pluginType); + plugin.Initialize(new ServiceCollection()); + _loadedPlugins.Add(plugin); + } + catch (Exception) + { + } + } + + private async Task LoadPluginFromDll(string dllPath) + { + try + { + var assemblyName = AssemblyName.GetAssemblyName(dllPath); + var assembly = Assembly.Load(assemblyName); + + var pluginType = assembly.GetTypes() + .FirstOrDefault(t => typeof(IGenrePlugin).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); + + if (pluginType == null) + { + return; + } + + var plugin = (IGenrePlugin)Activator.CreateInstance(pluginType); + plugin.Initialize(new ServiceCollection()); + _loadedPlugins.Add(plugin); + } + catch (Exception) + { + } + } + + public void UnloadPlugins() + { + _loadedAssemblies.Clear(); + _loadedPlugins.Clear(); + } +} + +public class GenrePluginMetadata +{ + private readonly IGenrePlugin _plugin; + + public GenrePluginMetadata(IGenrePlugin plugin) + { + _plugin = plugin; + } + + public string Id => _plugin.Id; + public string Name => _plugin.Name; + public string Version => _plugin.Version; + public string Description => _plugin.Description; +} diff --git a/src/OpenRpg.Editor.Infrastructure/Plugins/GenreService.cs b/src/OpenRpg.Editor.Infrastructure/Plugins/GenreService.cs new file mode 100644 index 00000000..6f3d4be1 --- /dev/null +++ b/src/OpenRpg.Editor.Infrastructure/Plugins/GenreService.cs @@ -0,0 +1,169 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using OpenRpg.Editor.Core.Genres; + +namespace OpenRpg.Editor.Infrastructure.Plugins; + +public class GenreService +{ + private readonly GenrePluginLoader _pluginLoader; + private readonly List _enabledGenres = new(); + private bool _initialized = false; + + public IReadOnlyList EnabledGenres => _enabledGenres.AsReadOnly(); + public IReadOnlyList AvailablePlugins => _pluginLoader.LoadedPlugins; + public IEnumerable AvailableGenres => _pluginLoader.LoadedPlugins.Select(p => new GenrePluginMetadata(p)); + public bool HasGenresLoaded => _pluginLoader.LoadedPlugins.Count > 0; + public bool HasEnabledGenres => _enabledGenres.Count > 0; + + public GenreService(GenrePluginLoader pluginLoader) + { + _pluginLoader = pluginLoader; + } + + private void EnsureInitialized() + { + if (_initialized) return; + _initialized = true; + + _pluginLoader.LoadPlugins(); + + if (_pluginLoader.LoadedPlugins.Count == 0) + { + var defaultPlugin = new DefaultGenrePlugin(); + _enabledGenres.Add(defaultPlugin); + } + } + + public void RefreshPlugins() + { + _pluginLoader.LoadPlugins(); + } + + public void EnableGenre(IGenrePlugin plugin) + { + EnsureInitialized(); + if (_enabledGenres.Any(g => g.Id == plugin.Id)) + return; + + _enabledGenres.Add(plugin); + } + + public bool EnableGenre(string genreId) + { + EnsureInitialized(); + var plugin = _pluginLoader.LoadedPlugins.FirstOrDefault(p => p.Id == genreId); + if (plugin == null) return false; + + if (_enabledGenres.Any(g => g.Id == plugin.Id)) + return true; + + _enabledGenres.Add(plugin); + return true; + } + + public void DisableGenre(string genreId) + { + EnsureInitialized(); + _enabledGenres.RemoveAll(g => g.Id == genreId); + } + + public void SetEnabledGenres(IEnumerable genres) + { + EnsureInitialized(); + _enabledGenres.Clear(); + _enabledGenres.AddRange(genres); + } + + public IGenreTypesProvider GetCombinedTypesProvider() + { + EnsureInitialized(); + if (_enabledGenres.Count == 0) + { + return new DefaultGenreTypesProvider(); + } + return new CombinedGenreTypesProvider(_enabledGenres); + } + + public IGenreRuntimeServices GetCombinedRuntimeServices() + { + EnsureInitialized(); + return new CombinedGenreRuntimeServices(_enabledGenres); + } + + public (bool IsValid, string ErrorMessage) ValidateGenreCombination(IGenrePlugin newGenre) + { + EnsureInitialized(); + var existingIds = _enabledGenres + .SelectMany(g => g.TypesProvider.ItemTypes.Select(t => t.Id)) + .ToHashSet(); + + var newIds = newGenre.TypesProvider.ItemTypes.Select(t => t.Id); + + foreach (var id in newIds) + { + if (existingIds.Contains(id)) + { + var existingGenre = _enabledGenres.FirstOrDefault(g => + g.TypesProvider.ItemTypes.Any(t => t.Id == id)); + return (false, $"Type ID {id} conflict between {existingGenre?.Name} and {newGenre.Name}"); + } + } + + return (true, string.Empty); + } + + public void RegisterGenreServices(IServiceCollection services) + { + EnsureInitialized(); + foreach (var genre in _enabledGenres) + { + genre.RuntimeServices.RegisterServices(services); + } + } +} + +public class CombinedGenreTypesProvider : IGenreTypesProvider +{ + public string GenreId => "combined"; + public string GenreName => "Combined"; + + private readonly List _providers; + + public CombinedGenreTypesProvider(IEnumerable plugins) + { + _providers = plugins.Select(p => p.TypesProvider).ToList(); + } + + public OptionData[] ItemTypes => _providers.SelectMany(p => p.ItemTypes).ToArray(); + public OptionData[] ItemQualityTypes => _providers.SelectMany(p => p.ItemQualityTypes).ToArray(); + public OptionData[] RequirementTypes => _providers.SelectMany(p => p.RequirementTypes).ToArray(); + public OptionData[] EffectTypes => _providers.SelectMany(p => p.EffectTypes).ToArray(); + public OptionData[] RewardTypes => _providers.SelectMany(p => p.RewardTypes).ToArray(); + public OptionData[] ModificationTypes => _providers.SelectMany(p => p.ModificationTypes).ToArray(); + public OptionData[] ObjectiveTypes => _providers.SelectMany(p => p.ObjectiveTypes).ToArray(); + public OptionData[] EffectScalingType => _providers.SelectMany(p => p.EffectScalingType).ToArray(); + public OptionData[] StatTypes => _providers.SelectMany(p => p.StatTypes).ToArray(); + public OptionData[] StateTypes => _providers.SelectMany(p => p.StateTypes).ToArray(); + public OptionData[] CraftingSkillTypes => _providers.SelectMany(p => p.CraftingSkillTypes).ToArray(); + public OptionData[] GatheringSkillTypes => _providers.SelectMany(p => p.GatheringSkillTypes).ToArray(); +} + +public class CombinedGenreRuntimeServices : IGenreRuntimeServices +{ + private readonly List _plugins; + + public CombinedGenreRuntimeServices(IEnumerable plugins) + { + _plugins = plugins.ToList(); + } + + public void RegisterServices(IServiceCollection services) + { + foreach (var plugin in _plugins) + { + plugin.RuntimeServices.RegisterServices(services); + } + } +} \ No newline at end of file diff --git a/src/OpenRpg.Editor.UI/Components/Editors/Common/ScaledEffectEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/Common/ScaledEffectEditor.razor index 40a66a7c..fa9fa9b9 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/Common/ScaledEffectEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/Common/ScaledEffectEditor.razor @@ -1,5 +1,5 @@ @using OpenRpg.CurveFunctions.Scaling -@using OpenRpg.Editor.Infrastructure.Helpers +@using OpenRpg.Editor.UI.Services @using OpenRpg.Entities.Effects @using OpenRpg.Entities.Types @@ -8,7 +8,7 @@
    - @{ var scalingIndexOptions = ScaledEffect.ScalingType == CoreEffectScalingTypes.StatIndex ? TypesHelper.GetStatTypes : TypesHelper.GetStateTypes; } + @{ var scalingIndexOptions = ScaledEffect.ScalingType == CoreEffectScalingTypes.StatIndex ? GenreTypes.StatTypes : GenreTypes.StateTypes; } @foreach (var scalingIndex in scalingIndexOptions) { @@ -52,13 +52,16 @@ @code { + [Inject] + public GenreTypesService GenreTypes { get; set; } + [Parameter] public ScaledEffect ScaledEffect { get; set; } - - public string ScalingTypeName => TypesHelper.GetEffectScalingType + + public string ScalingTypeName => GenreTypes.EffectScalingType .First(x => x.Id == ScaledEffect.ScalingType) .Name; - + public string YAxisLabel => "Potency"; public string ChartScalingLabel { @@ -68,16 +71,16 @@ { return ScalingTypeName; } if (ScaledEffect.ScalingType == CoreEffectScalingTypes.StatIndex) - { return TypesHelper.GetStatTypes.First(x => x.Id == ScaledEffect.ScalingIndex).Name; } + { return GenreTypes.StatTypes.First(x => x.Id == ScaledEffect.ScalingIndex).Name; } - return TypesHelper.GetStateTypes.First(x => x.Id == ScaledEffect.ScalingIndex).Name; + return GenreTypes.StateTypes.First(x => x.Id == ScaledEffect.ScalingIndex).Name; } } public float TestOutputValue { get; set; } public float TestInputValue { get; set; } - public bool RequiresScalingIndex => ScaledEffect.ScalingType == CoreEffectScalingTypes.StatIndex + public bool RequiresScalingIndex => ScaledEffect.ScalingType == CoreEffectScalingTypes.StatIndex || ScaledEffect.ScalingType == CoreEffectScalingTypes.StateIndex; public async Task OnScalingFunctionUpdated(ScalingFunction scalingFunction) diff --git a/src/OpenRpg.Editor.UI/Components/Editors/Common/TradeSkillDetailsEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/Common/TradeSkillDetailsEditor.razor index 02ad4000..bdd9d7e8 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/Common/TradeSkillDetailsEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/Common/TradeSkillDetailsEditor.razor @@ -1,8 +1,7 @@ @using OpenRpg.Core.Associations @using OpenRpg.Core.Requirements -@using OpenRpg.Editor.Infrastructure.Helpers +@using OpenRpg.Editor.UI.Services @using OpenRpg.Entities.Extensions -@using OpenRpg.Genres.Fantasy.Types @using OpenRpg.Items.TradeSkills.Extensions @using OpenRpg.Items.TradeSkills.Variables @@ -15,7 +14,7 @@
    - @foreach (var effectType in TypesHelper.GetEffectTypes) + @foreach (var effectType in GenreTypes.EffectTypes) { } @@ -73,7 +73,7 @@ @if (CurrentContext != null) { - + } @@ -82,22 +82,25 @@ @if (CurrentContext != null && CurrentContext is ScaledEffect scaledEffect) { - + } -@functions { +@code { + [Inject] + public GenreTypesService GenreTypes { get; set; } + [CascadingParameter] public IModalInteractionService ModalService { get; set; } - + [Parameter] public List Effects { get; set; } - + public IEffect CurrentContext { get; set; } bool IsDropdownActive { get; set; } - + public ModalElementReference EditRequirementModal { get; set; } public ModalElementReference EditScalingModal { get; set; } diff --git a/src/OpenRpg.Editor.UI/Components/Editors/List/ItemTemplateDetailsEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/List/ItemTemplateDetailsEditor.razor index 0ad2b816..188b773b 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/List/ItemTemplateDetailsEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/List/ItemTemplateDetailsEditor.razor @@ -1,4 +1,4 @@ -@using OpenRpg.Editor.Infrastructure.Helpers +@using OpenRpg.Editor.UI.Services @using OpenRpg.Items.Extensions @using OpenRpg.Items.Templates @@ -39,7 +39,7 @@
    - @foreach (var itemType in TypesHelper.GetItemQualityTypes) + @foreach (var itemType in GenreTypes.ItemQualityTypes) { } @@ -67,6 +67,9 @@
    @code { + [Inject] + public GenreTypesService GenreTypes { get; set; } + [Parameter] public ItemTemplate Template { get; set; } } \ No newline at end of file diff --git a/src/OpenRpg.Editor.UI/Components/Editors/List/ModificationAllowancesEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/List/ModificationAllowancesEditor.razor index b8bbe95f..aeab161d 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/List/ModificationAllowancesEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/List/ModificationAllowancesEditor.razor @@ -1,7 +1,7 @@ @using OpenRpg.Core.Requirements @using OpenRpg.Editor.Core.Services.Modal @using OpenRpg.Editor.Infrastructure.Extensions -@using OpenRpg.Editor.Infrastructure.Helpers +@using OpenRpg.Editor.UI.Services @using OpenRpg.Entities.Modifications @using OpenRpg.Entities.Requirements @@ -16,7 +16,7 @@
    - @foreach (var objectiveType in TypesHelper.GetObjectiveTypes) + @foreach (var objectiveType in GenreTypes.ObjectiveTypes) { } @@ -24,7 +24,7 @@
    -
    @@ -37,7 +37,10 @@ -@functions { +@code { + [Inject] + public GenreTypesService GenreTypes { get; set; } + [Parameter] public List Objectives { get; set; } } diff --git a/src/OpenRpg.Editor.UI/Components/Editors/List/RequirementsEditor.razor b/src/OpenRpg.Editor.UI/Components/Editors/List/RequirementsEditor.razor index 8d46d86e..a8279c01 100644 --- a/src/OpenRpg.Editor.UI/Components/Editors/List/RequirementsEditor.razor +++ b/src/OpenRpg.Editor.UI/Components/Editors/List/RequirementsEditor.razor @@ -1,7 +1,7 @@ @using OpenRpg.Core.Associations @using OpenRpg.Core.Requirements @using OpenRpg.Core.Utils -@using OpenRpg.Editor.Infrastructure.Helpers +@using OpenRpg.Editor.UI.Services @using OpenRpg.Entities.Requirements @@ -15,7 +15,7 @@
    - @foreach (var rewardType in TypesHelper.GetRewardTypes) + @foreach (var rewardType in GenreTypes.RewardTypes) { } @@ -43,6 +43,9 @@ -@functions { +@code { + [Inject] + public GenreTypesService GenreTypes { get; set; } + [Parameter] public List Rewards { get; set; } } diff --git a/src/OpenRpg.Editor.UI/Components/GenreAwareComponent.cs b/src/OpenRpg.Editor.UI/Components/GenreAwareComponent.cs new file mode 100644 index 00000000..4573907b --- /dev/null +++ b/src/OpenRpg.Editor.UI/Components/GenreAwareComponent.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Components; +using OpenRpg.Editor.UI.Services; + +namespace OpenRpg.Editor.UI.Components; + +public class GenreAwareComponent : ComponentBase +{ + [Inject] + public GenreTypesService GenreTypes { get; set; } +} diff --git a/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj b/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj index 04463dfe..842fc9bf 100644 --- a/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj +++ b/src/OpenRpg.Editor.UI/OpenRpg.Editor.UI.csproj @@ -18,7 +18,6 @@ - diff --git a/src/OpenRpg.Editor.UI/Pages/GenreManagerPage.razor b/src/OpenRpg.Editor.UI/Pages/GenreManagerPage.razor new file mode 100644 index 00000000..b006bf30 --- /dev/null +++ b/src/OpenRpg.Editor.UI/Pages/GenreManagerPage.razor @@ -0,0 +1,226 @@ +@page "/genres" +@using System.Reactive.Disposables +@using OpenRpg.Editor.Core.Models +@using OpenRpg.Editor.Core.Genres +@using OpenRpg.Editor.Core.Services.Events.Bus +@using OpenRpg.Editor.Infrastructure.Plugins +@using OpenRpg.Editor.Infrastructure.Events +@using OpenRpg.Editor.UI.Services +@using System.Reactive.Linq + +@implements IDisposable + +@inject EditorState EditorState +@inject GenrePluginLoader PluginLoader +@inject GenreService GenreService +@inject GenreTypesService GenreTypes +@inject IEventBus EventBus + +

    Genre Manager

    + +
    +
    +

    Manage the genre plugins available in the editor. Drop genre DLL files into the Plugins/ folder and click "Refresh" to load them.

    +
    + +
    + +
    +
    + +@if (!GenreService.HasGenresLoaded) +{ +
    +
    + + + +

    No Genre Plugins Loaded

    +

    Drop genre plugin DLLs into the Plugins folder to get started.

    +

    + The Plugins folder is located at: @PluginPath +

    +
    +
    +} +else +{ +
    +

    Available Genres

    + + + + + + + + + + + + + @foreach (var plugin in PluginLoader.LoadedPlugins) + { + + + + + + + + + } + +
    NameIDVersionDescriptionStatusActions
    @plugin.Name@plugin.Id@plugin.Version@plugin.Description + @if (IsGenreEnabled(plugin)) + { + Enabled + } + else + { + Disabled + } + +
    + @if (IsGenreEnabled(plugin)) + { + + } + else + { + + } +
    +
    +
    + + @if (GenreService.HasEnabledGenres) + { +
    +

    Enabled Genres

    +
    + @foreach (var genre in GenreService.EnabledGenres) + { + @genre.Name + } +
    +
    +

    Type Summary:

    +
      +
    • Item Types: @GetTotalTypeCount(GenreService.GetCombinedTypesProvider().ItemTypes)
    • +
    • Requirement Types: @GetTotalTypeCount(GenreService.GetCombinedTypesProvider().RequirementTypes)
    • +
    • Effect Types: @GetTotalTypeCount(GenreService.GetCombinedTypesProvider().EffectTypes)
    • +
    +
    +
    + } +} + +@if (!string.IsNullOrEmpty(ErrorMessage)) +{ +
    + + @ErrorMessage +
    +} + +@code { + private IDisposable _subscription; + private List _composites = new(); + + public string PluginPath { get; set; } = ""; + public string ErrorMessage { get; set; } + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + PluginPath = OpenRpg.Editor.Core.Services.Paths.PathHelper.PluginPath; + + var composite = new System.Reactive.Disposables.CompositeDisposable(); + _composites.Add(composite); + _subscription = EventBus.Receive().Subscribe(_ => InvokeAsync(StateHasChanged)); + composite.Add(_subscription); + + RefreshPlugins(); + } + + public void RefreshPlugins() + { + ErrorMessage = null; + PluginLoader.LoadPluginsAsync(); + StateHasChanged(); + } + + public bool IsGenreEnabled(IGenrePlugin plugin) + { + return GenreService.EnabledGenres.Any(g => g.Id == plugin.Id); + } + + public async Task EnableGenre(IGenrePlugin plugin) + { + var validation = GenreService.ValidateGenreCombination(plugin); + if (!validation.IsValid) + { + ErrorMessage = validation.ErrorMessage; + return; + } + + GenreService.EnableGenre(plugin); + UpdateGenreTypes(); + await NotifyChange(); + } + + public async Task DisableGenre(IGenrePlugin plugin) + { + GenreService.DisableGenre(plugin.Id); + UpdateGenreTypes(); + await NotifyChange(); + } + + private void UpdateGenreTypes() + { + if (GenreService.HasEnabledGenres) + { + GenreTypes.SetTypesProvider(GenreService.GetCombinedTypesProvider()); + } + else + { + GenreTypes.SetTypesProvider(new EmptyTypesProvider()); + } + } + + private async Task NotifyChange() + { + EditorState.AvailableGenres = PluginLoader.LoadedPlugins; + EditorState.EnabledGenres = GenreService.EnabledGenres; + EditorState.CurrentTypesProvider = GenreService.HasEnabledGenres + ? GenreService.GetCombinedTypesProvider() + : null; + EventBus.PublishAsync(new ProjectChangedEvent()); + await Task.CompletedTask; + } + + private int GetTotalTypeCount(OptionData[] types) + { + return types?.Length ?? 0; + } + + public void Dispose() + { + foreach (var composite in _composites) + { + composite.Dispose(); + } + _composites.Clear(); + } +} diff --git a/src/OpenRpg.Editor.UI/Pages/Index.razor b/src/OpenRpg.Editor.UI/Pages/Index.razor index 42064e82..a21fad2c 100644 --- a/src/OpenRpg.Editor.UI/Pages/Index.razor +++ b/src/OpenRpg.Editor.UI/Pages/Index.razor @@ -6,13 +6,15 @@ @using OpenRpg.Editor.Core.Services.FileSystem @using OpenRpg.Editor.Infrastructure.Events @using OpenRpg.Editor.Infrastructure.Persistence +@using OpenRpg.Editor.Infrastructure.Plugins @using OpenRpg.Editor.UI.Models @inject IFileBrowser FileBrowser @inject EditorState EditorState @inject CreateProjectExecutor CreateProjectExecutor; @inject EditorDataLoader EditorDataLoader; -@inject IEventBus EventBus; +@inject IEventBus EventBus; +@inject GenreService GenreService;

    OpenRpg Data Editor

    @@ -40,16 +42,75 @@ }
    +@if (showGenreSelection) +{ + +} @code { + private bool showGenreSelection = false; + private Dictionary selectedGenres = new(); + public async Task CreateProject() + { + GenreService.RefreshPlugins(); + selectedGenres = GenreService.AvailableGenres.ToDictionary(g => g.Id, g => false); + showGenreSelection = true; + } + + private async Task ConfirmCreateProject() { var projectFolder = FileBrowser.BrowseToFolder(); - if(string.IsNullOrEmpty(projectFolder)) { return; } + if (string.IsNullOrEmpty(projectFolder)) { return; } - var newProject = await CreateProjectExecutor.Execute(projectFolder); + var enabledGenreIds = selectedGenres.Where(kvp => kvp.Value).Select(kvp => kvp.Key).ToList(); + var newProject = await CreateProjectExecutor.Execute(projectFolder, enabledGenreIds); EditorState.CurrentProject = newProject; + + foreach (var genreId in enabledGenreIds) + { + GenreService.EnableGenre(genreId); + } + + showGenreSelection = false; EventBus.PublishAsync(new ProjectChangedEvent()); } @@ -59,6 +120,15 @@ if(string.IsNullOrEmpty(projectFile)) { return; } await EditorDataLoader.Load(projectFile); + + if (EditorState.CurrentProject?.Project?.Plugins != null) + { + foreach (var plugin in EditorState.CurrentProject.Project.Plugins) + { + GenreService.EnableGenre(plugin.Id); + } + } + EventBus.PublishAsync(new ProjectChangedEvent()); } } \ No newline at end of file diff --git a/src/OpenRpg.Editor.UI/Services/GenreTypesService.cs b/src/OpenRpg.Editor.UI/Services/GenreTypesService.cs new file mode 100644 index 00000000..874728ba --- /dev/null +++ b/src/OpenRpg.Editor.UI/Services/GenreTypesService.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Components; +using OpenRpg.Editor.Core.Genres; + +namespace OpenRpg.Editor.UI.Services; + +public class GenreTypesService +{ + private IGenreTypesProvider _typesProvider; + + public void SetTypesProvider(IGenreTypesProvider typesProvider) + { + _typesProvider = typesProvider; + } + + public IGenreTypesProvider TypesProvider => _typesProvider ?? new EmptyTypesProvider(); + + public OptionData[] ItemTypes => TypesProvider.ItemTypes; + public OptionData[] ItemQualityTypes => TypesProvider.ItemQualityTypes; + public OptionData[] RequirementTypes => TypesProvider.RequirementTypes; + public OptionData[] EffectTypes => TypesProvider.EffectTypes; + public OptionData[] RewardTypes => TypesProvider.RewardTypes; + public OptionData[] ModificationTypes => TypesProvider.ModificationTypes; + public OptionData[] ObjectiveTypes => TypesProvider.ObjectiveTypes; + public OptionData[] EffectScalingType => TypesProvider.EffectScalingType; + public OptionData[] StatTypes => TypesProvider.StatTypes; + public OptionData[] StateTypes => TypesProvider.StateTypes; + public OptionData[] CraftingSkillTypes => TypesProvider.CraftingSkillTypes; + public OptionData[] GatheringSkillTypes => TypesProvider.GatheringSkillTypes; +} + +public class EmptyTypesProvider : IGenreTypesProvider +{ + public string GenreId => "none"; + public string GenreName => "No Genre Loaded"; + + public OptionData[] ItemTypes => Array.Empty(); + public OptionData[] ItemQualityTypes => Array.Empty(); + public OptionData[] RequirementTypes => Array.Empty(); + public OptionData[] EffectTypes => Array.Empty(); + public OptionData[] RewardTypes => Array.Empty(); + public OptionData[] ModificationTypes => Array.Empty(); + public OptionData[] ObjectiveTypes => Array.Empty(); + public OptionData[] EffectScalingType => Array.Empty(); + public OptionData[] StatTypes => Array.Empty(); + public OptionData[] StateTypes => Array.Empty(); + public OptionData[] CraftingSkillTypes => Array.Empty(); + public OptionData[] GatheringSkillTypes => Array.Empty(); +} diff --git a/src/OpenRpg.Editor.UI/Shared/TopMenu.razor b/src/OpenRpg.Editor.UI/Shared/TopMenu.razor index ddb985e1..6f2b2eea 100644 --- a/src/OpenRpg.Editor.UI/Shared/TopMenu.razor +++ b/src/OpenRpg.Editor.UI/Shared/TopMenu.razor @@ -77,6 +77,18 @@
    -@if (!GenreService.HasGenresLoaded) +@if (!GenreService.HasLoadErrors && GenreService.AvailablePlugins.Count == 0) {
    @@ -62,11 +61,11 @@ else - @foreach (var plugin in PluginLoader.LoadedPlugins) + @foreach (var plugin in GenreService.AvailablePlugins) { @plugin.Name - @plugin.Id + @plugin.PluginId @plugin.Version @plugin.Description @@ -103,12 +102,12 @@ else
    - @if (GenreService.HasEnabledGenres) + @if (GenreService.EnabledPlugins.Count > 0) {

    Enabled Genres

    - @foreach (var genre in GenreService.EnabledGenres) + @foreach (var genre in GenreService.EnabledPlugins) { @genre.Name } @@ -125,11 +124,16 @@ else } } -@if (!string.IsNullOrEmpty(ErrorMessage)) +@if (GenreService.HasLoadErrors) {
    - - @ErrorMessage + Plugin Load Errors: +
      + @foreach (var error in GenreService.LoadErrors) + { +
    • @error
    • + } +
    } @@ -138,7 +142,6 @@ else private List _composites = new(); public string PluginPath { get; set; } = ""; - public string ErrorMessage { get; set; } protected override async Task OnInitializedAsync() { @@ -156,40 +159,39 @@ else public void RefreshPlugins() { - ErrorMessage = null; - PluginLoader.LoadPluginsAsync(); + GenreService.RefreshPlugins(); + UpdateGenreTypes(); StateHasChanged(); } - public bool IsGenreEnabled(IGenrePlugin plugin) + public bool IsGenreEnabled(EditorPluginInfo plugin) { - return GenreService.EnabledGenres.Any(g => g.Id == plugin.Id); + return GenreService.EnabledPlugins.Any(g => g.PluginId == plugin.PluginId); } - public async Task EnableGenre(IGenrePlugin plugin) + public async Task EnableGenre(EditorPluginInfo plugin) { - var validation = GenreService.ValidateGenreCombination(plugin); - if (!validation.IsValid) + var (isValid, conflicts) = GenreService.ValidatePluginCombination(plugin); + if (!isValid) { - ErrorMessage = validation.ErrorMessage; return; } - GenreService.EnableGenre(plugin); + GenreService.EnablePlugin(plugin.PluginId); UpdateGenreTypes(); await NotifyChange(); } - public async Task DisableGenre(IGenrePlugin plugin) + public async Task DisableGenre(EditorPluginInfo plugin) { - GenreService.DisableGenre(plugin.Id); + GenreService.DisablePlugin(plugin.PluginId); UpdateGenreTypes(); await NotifyChange(); } private void UpdateGenreTypes() { - if (GenreService.HasEnabledGenres) + if (GenreService.EnabledPlugins.Count > 0) { GenreTypes.SetTypesProvider(GenreService.GetCombinedTypesProvider()); } @@ -201,9 +203,9 @@ else private async Task NotifyChange() { - EditorState.AvailableGenres = PluginLoader.LoadedPlugins; - EditorState.EnabledGenres = GenreService.EnabledGenres; - EditorState.CurrentTypesProvider = GenreService.HasEnabledGenres + EditorState.AvailableGenres = GenreService.AvailablePlugins; + EditorState.EnabledGenres = GenreService.EnabledPlugins; + EditorState.CurrentTypesProvider = GenreService.EnabledPlugins.Count > 0 ? GenreService.GetCombinedTypesProvider() : null; EventBus.PublishAsync(new ProjectChangedEvent()); @@ -223,4 +225,4 @@ else } _composites.Clear(); } -} +} \ No newline at end of file diff --git a/src/OpenRpg.Editor.UI/Pages/Index.razor b/src/OpenRpg.Editor.UI/Pages/Index.razor index a21fad2c..30ae7bab 100644 --- a/src/OpenRpg.Editor.UI/Pages/Index.razor +++ b/src/OpenRpg.Editor.UI/Pages/Index.razor @@ -2,6 +2,7 @@ @using OpenRpg.CurveFunctions @using OpenRpg.Editor.Core.Models +@using OpenRpg.Editor.Core.Plugins @using OpenRpg.Editor.Core.Services.Events.Bus @using OpenRpg.Editor.Core.Services.FileSystem @using OpenRpg.Editor.Infrastructure.Events @@ -11,10 +12,10 @@ @inject IFileBrowser FileBrowser @inject EditorState EditorState -@inject CreateProjectExecutor CreateProjectExecutor; -@inject EditorDataLoader EditorDataLoader; -@inject IEventBus EventBus; -@inject GenreService GenreService; +@inject CreateProjectExecutor CreateProjectExecutor +@inject EditorDataLoader EditorDataLoader +@inject IEventBus EventBus +@inject GenreService GenreService

    OpenRpg Data Editor

    @@ -53,14 +54,14 @@