diff --git a/Assets/AddressableAssetsData/AssetGroups/Common_Assets.asset b/Assets/AddressableAssetsData/AssetGroups/Common_Assets.asset index fd0bf5c..fde7b5f 100644 --- a/Assets/AddressableAssetsData/AssetGroups/Common_Assets.asset +++ b/Assets/AddressableAssetsData/AssetGroups/Common_Assets.asset @@ -126,7 +126,7 @@ MonoBehaviour: m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 - m_GUID: 9e8339bc69fe33641a8fbc5bffd0ebd5 - m_Address: EntitiesBaseSettings + m_Address: CharacterBaseSettings m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 @@ -201,6 +201,11 @@ MonoBehaviour: m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: f37df040ec9864f4dbafe3f5e6dfe4d9 + m_Address: DefaultPartySettings + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 - m_GUID: fe393ace9b354375a9cb14cdbbc28be4 m_Address: Assets/TextMesh Pro/Shaders/TMP_SDF-Mobile.shader m_ReadOnly: 0 diff --git a/Assets/Code/Core/EntryPoint.cs b/Assets/Code/Core/EntryPoint.cs index 69ea6a4..7d6da2b 100644 --- a/Assets/Code/Core/EntryPoint.cs +++ b/Assets/Code/Core/EntryPoint.cs @@ -99,11 +99,14 @@ namespace Nox.Core { saveSystem = new SaveSystem(saveSerializer, saveStorage, saveSlotManager, saveSettings); var adventureData = new AdventureData(); + var characterBaseSettings = Addressables.LoadAssetAsync("CharacterBaseSettings").WaitForCompletion(); - var perKRegistry = Addressables.LoadAssetAsync("PerkRegistry").WaitForCompletion(); + var perKRegistry = Addressables.LoadAssetAsync("PerksRegistry ").WaitForCompletion(); var characterRegistry = Addressables.LoadAssetAsync("CharacterRegistry").WaitForCompletion(); + var defaultPartySettings = Addressables.LoadAssetAsync("DefaultPartySettings").WaitForCompletion(); + var characterSystems = DefaultCharacterSystemsFactory.Create(characterBaseSettings, perKRegistry, characterRegistry); - var partyCreatorModel = new PartyCreatorModel(characterSystems.CharacterFactory, characterSystems.PartyFactory); + var partyCreatorModel = new PartyCreatorModel(characterSystems.CharacterFactory, characterSystems.PartyFactory, defaultPartySettings); applicationStates = new Dictionary { [GameState.BootState] = new SplashGameState(bootstrapReferences, gameDataState), diff --git a/Assets/Code/GameState/Entities/CharacterBaseSettings.cs b/Assets/Code/GameState/Entities/CharacterBaseSettings.cs index f61e88c..a946b06 100644 --- a/Assets/Code/GameState/Entities/CharacterBaseSettings.cs +++ b/Assets/Code/GameState/Entities/CharacterBaseSettings.cs @@ -2,13 +2,10 @@ using System; using UnityEngine; namespace Nox.Game { - [CreateAssetMenu(fileName = "EntitiesBaseSettings", menuName = "Nox/Database/Entities/EntitiesBaseSettings")] + [CreateAssetMenu(fileName = "CharacterBaseSettings", menuName = "Nox/Database/Entities/CharacterBaseSettings")] public class CharacterBaseSettings: ScriptableObject { - - [Header("Character General Defaults")] - public int startAttributesPool = 12; - [Header("Character Creation Defaults")] + public DistributionPointsPerClass distributionPointsPerClass; public EntityAttributes defaultEntityAttributes; public EntityStats defaultEntityStats; public PerksData defaultPerksData; @@ -25,18 +22,24 @@ namespace Nox.Game { [Serializable] public sealed class RacialBonuses { public CharacterRace race; - public EntityAttributes defaultEntityAttributes; - public EntityStats defaultEntityStats; - public PerksData perksData; - public ModifiersData modifiersData; + public EntityAttributes bonusAttributes; + public EntityStats bonusStats; + public PerksData startingPerks; + public ModifiersData permanentModifiers; } [Serializable] public sealed class ClassBonuses { public CharacterClass @class; - public EntityAttributes defaultEntityAttributes; - public EntityStats defaultEntityStats; - public PerksData perksData; - public ModifiersData modifiersData; + public EntityAttributes bonusAttributes; + public EntityStats bonusStats; + public PerksData startingPerks; + public ModifiersData permanentModifiers; + } + + [Serializable] + public sealed class DistributionPointsPerClass { + public CharacterClass @class; + public int points; } } diff --git a/Assets/Code/GameState/Entities/DefaultCharacterSystemsFactory.cs b/Assets/Code/GameState/Entities/DefaultCharacterSystemsFactory.cs index cfb3317..cb2d7c9 100644 --- a/Assets/Code/GameState/Entities/DefaultCharacterSystemsFactory.cs +++ b/Assets/Code/GameState/Entities/DefaultCharacterSystemsFactory.cs @@ -2,16 +2,12 @@ using System; namespace Nox.Game { public static class DefaultCharacterSystemsFactory { - public static ICharacterSystems Create(CharacterBaseSettings characterBaseSettings, PerkRegistry perkRegistry, CharacterRegistry characterRegistry) { - IPerkFactory perkFactory = new PerkFactory(perkRegistry); + public static ICharacterSystems Create(CharacterBaseSettings characterBaseSettings, PerksRegistry perksRegistry, CharacterRegistry characterRegistry) { + IPerkFactory perkFactory = new PerkFactory(perksRegistry); ICharacterAttributesFactory attributesFactory = new CharacterAttributesFactory(characterRegistry); ICharacterStatsFactory statsFactory = new CharacterStatsFactory(); ICharacterFactory characterFactory = new CharacterFactory(attributesFactory, statsFactory, perkFactory); - IPartyFactory partyFactory = new PartyFactory(new PartyFactoryOptions { - minPartySize = 1, - maxPartySize = characterBaseSettings.maxPartySize, - enforceUniqueCharacterIds = true - }); + IPartyFactory partyFactory = new PartyFactory(characterBaseSettings); return new CharacterSystems(perkFactory, characterFactory, partyFactory); } diff --git a/Assets/Code/GameState/Entities/DefaultPartySettings.cs b/Assets/Code/GameState/Entities/DefaultPartySettings.cs new file mode 100644 index 0000000..2fd8649 --- /dev/null +++ b/Assets/Code/GameState/Entities/DefaultPartySettings.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace Nox.Game { + [CreateAssetMenu(fileName = "DefaultPartySettings", menuName = "Nox/Database/Entities/Default Party Settings")] + public class DefaultPartySettings : ScriptableObject { + [Header("This will be default starting set")] + public string startingSetId; + + [Header("Party Definition Sets")] + public List partyDefinitionSets; + + [Header("Testing Party Definition Sets")] + public CharacterBaseSettings characterBaseSettings; + + private void OnValidate() { + if(String.IsNullOrEmpty(startingSetId)) { + Debug.LogError("DefaultPartySettings: startingSetId cannot be null or empty"); + return; + } + foreach(var partyDefinitionSet in partyDefinitionSets) { + var partyDefinition = partyDefinitionSet.partyDefinition; + if(partyDefinition == null) { + return; + } + + for(var i = 0; i < partyDefinition.maxPartySize; i++) { + if (partyDefinition.members.Count <= i) { + partyDefinition.members.Add(new CharacterDefinition()); + } + } + + if(partyDefinitionSets.FirstOrDefault(pds => pds.id == partyDefinitionSet.id && pds.isTestingSet) != null) { + var testingSet = partyDefinitionSets.FirstOrDefault(pds => pds.id == partyDefinitionSet.id && pds.isTestingSet); + ApplyClassAndRacialBonuses(testingSet); + } + + if(partyDefinition.members.Count <= partyDefinition.maxPartySize) { + continue; + } + Debug.LogError($"Party definition '{partyDefinitionSet.id}' has more members than the maximum allowed size.Removing extra members."); + partyDefinition.members.RemoveRange(partyDefinition.maxPartySize, partyDefinition.members.Count - partyDefinition.maxPartySize); + } + } + private void ApplyClassAndRacialBonuses(PartyDefinitionSet testingSet) { + var partyDefinition = testingSet.partyDefinition; + foreach(var member in partyDefinition.members) { + var baseSettings = characterBaseSettings.defaultEntityAttributes; + var classAttributes = characterBaseSettings.classBonuses.FirstOrDefault(c => c.@class == member.@class)?.bonusAttributes; + var racialAttributes = characterBaseSettings.racialBonuses.FirstOrDefault(rb => rb.race == member.race)?.bonusAttributes; + if (classAttributes != null && racialAttributes != null) { + member.Attributes += baseSettings + classAttributes + racialAttributes; + } + } + } + } + + [Serializable] + public sealed class PartyDefinitionSet { + public string id; + public bool isTestingSet; + public PartyDefinition partyDefinition; + } +} diff --git a/Assets/Code/GameState/Entities/DefaultPartySettings.cs.meta b/Assets/Code/GameState/Entities/DefaultPartySettings.cs.meta new file mode 100644 index 0000000..fea6db5 --- /dev/null +++ b/Assets/Code/GameState/Entities/DefaultPartySettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ff702898b3cd4100b9b8230f04711fa9 +timeCreated: 1774195937 \ No newline at end of file diff --git a/Assets/Code/GameState/Entities/EntitiesDefinitions.cs b/Assets/Code/GameState/Entities/EntitiesDefinitions.cs index 5bbcd86..8e467bd 100644 --- a/Assets/Code/GameState/Entities/EntitiesDefinitions.cs +++ b/Assets/Code/GameState/Entities/EntitiesDefinitions.cs @@ -40,7 +40,14 @@ namespace Nox.Game { public int knowledge; public int perception; - public int Total => might + reflex + knowledge; + public static EntityAttributes operator +(EntityAttributes a, EntityAttributes b) { + return new EntityAttributes { + might = a.might + b.might, + reflex = a.reflex + b.reflex, + knowledge = a.knowledge + b.knowledge, + perception = a.perception + b.perception + }; + } } [Serializable] @@ -118,8 +125,8 @@ namespace Nox.Game { [Serializable] public sealed class PartyDefinition { - public List members = new(); public int maxPartySize; + public List members = new(); [JsonIgnore] public CharacterDefinition Protagonist => members.FirstOrDefault(m => m.role == CharacterRole.Protagonist); diff --git a/Assets/Code/GameState/Entities/PartyCreatorModel.cs b/Assets/Code/GameState/Entities/PartyCreatorModel.cs index 197b790..6478ca7 100644 --- a/Assets/Code/GameState/Entities/PartyCreatorModel.cs +++ b/Assets/Code/GameState/Entities/PartyCreatorModel.cs @@ -4,7 +4,7 @@ namespace Nox.Game { public class PartyCreatorModel { private readonly ICharacterFactory characterFactory; private readonly IPartyFactory partyFactory; - public PartyCreatorModel(ICharacterFactory characterFactory, IPartyFactory partyFactory) { + public PartyCreatorModel(ICharacterFactory characterFactory, IPartyFactory partyFactory, DefaultPartySettings defaultPartySettings) { this.characterFactory = characterFactory; this.partyFactory = partyFactory; } diff --git a/Assets/Code/GameState/Entities/PartyFactory.cs b/Assets/Code/GameState/Entities/PartyFactory.cs index 984cd70..c1af840 100644 --- a/Assets/Code/GameState/Entities/PartyFactory.cs +++ b/Assets/Code/GameState/Entities/PartyFactory.cs @@ -7,17 +7,11 @@ namespace Nox.Game { PartyDefinition Create(CharacterDefinition protagonist, IEnumerable companions = null); } - public sealed class PartyFactoryOptions { - public int minPartySize = 1; - public int maxPartySize = 4; - public bool enforceUniqueCharacterIds = true; - } - public sealed class PartyFactory : IPartyFactory { - private readonly PartyFactoryOptions options; + private readonly CharacterBaseSettings characterBaseSettings; - public PartyFactory(PartyFactoryOptions options = null) { - this.options = options ?? new PartyFactoryOptions(); + public PartyFactory(CharacterBaseSettings characterBaseSettings) { + this.characterBaseSettings = characterBaseSettings; } public PartyDefinition Create(CharacterDefinition protagonist, IEnumerable companions = null) { @@ -25,17 +19,17 @@ namespace Nox.Game { throw new ArgumentNullException(nameof(protagonist)); } - PartyDefinition party = new PartyDefinition { - maxPartySize = options.maxPartySize <= 0 ? int.MaxValue : options.maxPartySize + var party = new PartyDefinition { + maxPartySize = characterBaseSettings.maxPartySize <= 0 ? int.MaxValue : characterBaseSettings.maxPartySize }; - CharacterDefinition protagonistClone = protagonist.Clone(); + var protagonistClone = protagonist.Clone(); protagonistClone.role = CharacterRole.Protagonist; party.members.Add(protagonistClone); if(companions != null) { - foreach(CharacterDefinition companion in companions.Where(c => c != null)) { - CharacterDefinition companionClone = companion.Clone(); + foreach(var companion in companions.Where(c => c != null)) { + var companionClone = companion.Clone(); companionClone.role = CharacterRole.Companion; party.members.Add(companionClone); } @@ -46,10 +40,6 @@ namespace Nox.Game { } private void ValidateParty(PartyDefinition party) { - if(party.members.Count < options.minPartySize) { - throw new ArgumentException($"Party size {party.members.Count} is below minimum {options.minPartySize}."); - } - if(party.members.Count > party.maxPartySize) { throw new ArgumentException($"Party size {party.members.Count} exceeds max {party.maxPartySize}."); } @@ -59,15 +49,13 @@ namespace Nox.Game { throw new ArgumentException($"Party must contain exactly one protagonist, found {protagonistCount}."); } - if(options.enforceUniqueCharacterIds) { - int uniqueIds = party.members - .Where(m => !string.IsNullOrWhiteSpace(m.ID)) - .Select(m => m.ID) - .Distinct() - .Count(); - if(uniqueIds != party.members.Count) { - throw new ArgumentException("Party contains duplicate or missing character ids."); - } + int uniqueIds = party.members + .Where(m => !string.IsNullOrWhiteSpace(m.ID)) + .Select(m => m.ID) + .Distinct() + .Count(); + if(uniqueIds != party.members.Count) { + throw new ArgumentException("Party contains duplicate or missing character ids."); } } } diff --git a/Assets/Code/GameState/Entities/PerkFactory.cs b/Assets/Code/GameState/Entities/PerkFactory.cs index 77a51da..a6fa46a 100644 --- a/Assets/Code/GameState/Entities/PerkFactory.cs +++ b/Assets/Code/GameState/Entities/PerkFactory.cs @@ -14,11 +14,11 @@ namespace Nox.Game { public sealed class PerkFactory : IPerkFactory { private readonly Dictionary perkPool = new (); - public PerkFactory(PerkRegistry perkRegistry) { - if(perkRegistry == null) { - throw new ArgumentNullException(nameof(perkRegistry)); + public PerkFactory(PerksRegistry perksRegistry) { + if(perksRegistry == null) { + throw new ArgumentNullException(nameof(perksRegistry)); } - var allAvailablePerks = perkRegistry.perksData; + var allAvailablePerks = perksRegistry.perksData; foreach(var perk in allAvailablePerks.perks) { perkPool.Add(perk.id, perk); } diff --git a/Assets/Code/GameState/Entities/PerkRegistry.cs b/Assets/Code/GameState/Entities/PerksRegistry.cs similarity index 80% rename from Assets/Code/GameState/Entities/PerkRegistry.cs rename to Assets/Code/GameState/Entities/PerksRegistry.cs index bec3cc1..6fe339b 100644 --- a/Assets/Code/GameState/Entities/PerkRegistry.cs +++ b/Assets/Code/GameState/Entities/PerksRegistry.cs @@ -3,7 +3,7 @@ using UnityEngine; namespace Nox.Game { [CreateAssetMenu(fileName = "PerksRegistry", menuName = "Nox/Database/Entities/Perks Registry")] - public class PerkRegistry : ScriptableObject { + public class PerksRegistry : ScriptableObject { public PerksData perksData; } } diff --git a/Assets/Code/GameState/Entities/PerkRegistry.cs.meta b/Assets/Code/GameState/Entities/PerksRegistry.cs.meta similarity index 100% rename from Assets/Code/GameState/Entities/PerkRegistry.cs.meta rename to Assets/Code/GameState/Entities/PerksRegistry.cs.meta diff --git a/Assets/Database/Entities/EntitiesBaseSettings.asset b/Assets/Database/Entities/CharacterBaseSettings.asset similarity index 95% rename from Assets/Database/Entities/EntitiesBaseSettings.asset rename to Assets/Database/Entities/CharacterBaseSettings.asset index 9578b16..2ffc96b 100644 --- a/Assets/Database/Entities/EntitiesBaseSettings.asset +++ b/Assets/Database/Entities/CharacterBaseSettings.asset @@ -10,7 +10,7 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 1bbecc15c7cd4a7ca90ce17b3d3d75f0, type: 3} - m_Name: EntitiesBaseSettings + m_Name: CharacterBaseSettings m_EditorClassIdentifier: Assembly-CSharp::Nox.Game.CharacterBaseSettings startAttributesPool: 12 defaultEntityAttributes: diff --git a/Assets/Database/Entities/EntitiesBaseSettings.asset.meta b/Assets/Database/Entities/CharacterBaseSettings.asset.meta similarity index 100% rename from Assets/Database/Entities/EntitiesBaseSettings.asset.meta rename to Assets/Database/Entities/CharacterBaseSettings.asset.meta diff --git a/Assets/Database/Entities/DefaultPartySettings.asset b/Assets/Database/Entities/DefaultPartySettings.asset new file mode 100644 index 0000000..e64a6b9 --- /dev/null +++ b/Assets/Database/Entities/DefaultPartySettings.asset @@ -0,0 +1,103 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ff702898b3cd4100b9b8230f04711fa9, type: 3} + m_Name: DefaultPartySettings + m_EditorClassIdentifier: Assembly-CSharp::Nox.Game.DefaultPartySettings + partyDefinitionSets: + - id: startingParty1 + partyDefinition: + maxPartySize: 4 + members: + - id: + displayName: + race: 0 + class: 0 + role: 0 + attributes: + might: 0 + reflex: 0 + knowledge: 0 + perception: 0 + stats: + health: 0 + stamina: 0 + level: 0 + experience: 0 + perksData: + perks: [] + activeModifiers: + modifiers: [] + - id: + displayName: + race: 0 + class: 0 + role: 0 + attributes: + might: 0 + reflex: 0 + knowledge: 0 + perception: 0 + stats: + health: 0 + stamina: 0 + level: 0 + experience: 0 + perksData: + perks: [] + activeModifiers: + modifiers: [] + - id: + displayName: + race: 0 + class: 0 + role: 0 + attributes: + might: 0 + reflex: 0 + knowledge: 0 + perception: 0 + stats: + health: 0 + stamina: 0 + level: 0 + experience: 0 + perksData: + perks: [] + activeModifiers: + modifiers: [] + - id: + displayName: + race: 0 + class: 0 + role: 0 + attributes: + might: 0 + reflex: 0 + knowledge: 0 + perception: 0 + stats: + health: 0 + stamina: 0 + level: 0 + experience: 0 + perksData: + perks: [] + activeModifiers: + modifiers: [] + attributesPointDistribution: + might: 0 + reflex: 0 + knowledge: 0 + perception: 0 + distributionPointsPerClass: + class: 0 + points: 0 diff --git a/Assets/Database/Entities/DefaultPartySettings.asset.meta b/Assets/Database/Entities/DefaultPartySettings.asset.meta new file mode 100644 index 0000000..c1c9a7b --- /dev/null +++ b/Assets/Database/Entities/DefaultPartySettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f37df040ec9864f4dbafe3f5e6dfe4d9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: