Added a bunch of utilities and modfief the character data structue

This commit is contained in:
Sebastian Bularca
2026-03-29 18:31:03 +02:00
parent 4a9c00212a
commit ee97b2fec3
110 changed files with 6752 additions and 169 deletions

View File

@@ -100,7 +100,7 @@ namespace Nox.Core {
var adventureData = new AdventureData();
var characterBaseSettings = Addressables.LoadAssetAsync<CharacterBaseSettings>("CharacterBaseSettings").WaitForCompletion();
var characterBaseSettings = Addressables.LoadAssetAsync<StarterCharacterSettings>("CharacterBaseSettings").WaitForCompletion();
var perKRegistry = Addressables.LoadAssetAsync<PerksRegistry>("PerksRegistry ").WaitForCompletion();
var characterRegistry = Addressables.LoadAssetAsync<CharacterRegistry>("CharacterRegistry").WaitForCompletion();
var defaultPartySettings = Addressables.LoadAssetAsync<DefaultPartySettings>("DefaultPartySettings").WaitForCompletion();

View File

@@ -1,8 +1,9 @@
using System;
using System.Linq;
namespace Nox.Game {
public interface ICharacterAttributesFactory {
EntityAttributes Create(EntityAttributes attributes);
EntityAttributes Create(EntityAttributes entityAttributes);
}
public sealed class CharacterAttributesFactory : ICharacterAttributesFactory {
@@ -12,12 +13,12 @@ namespace Nox.Game {
this.characterRegistry = characterRegistry;
}
public EntityAttributes Create(EntityAttributes attributes) {
if(attributes.might <= 0 || attributes.reflex <= 0 || attributes.knowledge <= 0 || attributes.perception <= 0) {
public EntityAttributes Create(EntityAttributes entityAttributes) {
if(entityAttributes.attributes.All(a => a.value != 0)) {
throw new ArgumentOutOfRangeException( "attributes cannot be zero or negative.", new ArgumentException() );
}
return attributes;
//TODO: Handle attributes modifiers and perks
return entityAttributes;
}
}
}

View File

@@ -27,6 +27,7 @@ namespace Nox.Game {
public EntityStats stats;
public EntityAttributes attributes;
public PerksData perksData = new();
public ModifiersData modifiersData = new();
}
public sealed class CharacterFactory : ICharacterFactory {
@@ -49,6 +50,7 @@ namespace Nox.Game {
}
var attributes = attributesFactory.Create(request.attributes);
var stats = statsFactory.Create(request.attributes);
var character = new CharacterDefinition {
ID = string.IsNullOrWhiteSpace(request.id) ? Guid.NewGuid().ToString("N") : request.id,
@@ -57,14 +59,9 @@ namespace Nox.Game {
@class = request.characterClass,
role = CharacterRole.Protagonist,
Attributes = attributes,
Stats = {
level = statsFactory.Create(attributes).level,
health = statsFactory.Create(attributes).health,
stamina = statsFactory.Create(attributes).stamina,
experience = statsFactory.Create(attributes).experience
},
perksData = new PerksData(),
activeModifiers = new ModifiersData()
Stats = stats,
perksData = request.perksData ?? new PerksData(),
activeModifiers = request.modifiersData ?? new ModifiersData()
};
AddStartingPerks(character, request.perksData);

View File

@@ -1,31 +1,25 @@
using System;
using System.Linq;
namespace Nox.Game {
public interface ICharacterStatsFactory {
EntityStats Create(EntityAttributes attributes);
}
public sealed class CharacterStatsFactoryOptions {
public EntityStats entityStats = new EntityStats() {
health = 10,
stamina = 10,
level = 1,
experience = 0
};
}
public sealed class CharacterStatsFactory : ICharacterStatsFactory {
private readonly CharacterStatsFactoryOptions options;
private readonly CharacterRegistry characterRegistry;
public CharacterStatsFactory(CharacterStatsFactoryOptions options = null) {
this.options = options ?? new CharacterStatsFactoryOptions();
public CharacterStatsFactory(CharacterRegistry characterRegistry) {
this.characterRegistry = characterRegistry;
}
public EntityStats Create(EntityAttributes attributes) {
if(attributes == null) {
throw new ArgumentNullException(nameof(attributes));
if(attributes.attributes.All(a => a.value != 0)) {
throw new ArgumentOutOfRangeException( "attributes cannot be zero or negative.", new ArgumentException() );
}
//TODO: Create stats based on attributes
// int maxHealth = options.baseHealth + attributes.might * options.mightHealthBonus;
// int maxStamina = options.baseStamina +
// attributes.might * options.mightStaminaBonus +

View File

@@ -3,16 +3,16 @@ using System;
namespace Nox.Game {
public static class DefaultCharacterSystemsFactory {
public static ICharacterSystems Create(
CharacterBaseSettings characterBaseSettings,
StarterCharacterSettings starterCharacterSettings,
PerksRegistry perksRegistry,
CharacterRegistry characterRegistry,
ModifiersRegistry modifiersRegistry) {
IPerkFactory perkFactory = new PerkFactory(perksRegistry);
IModfiersFactory modifiersFactory = new ModifiersFactory(modifiersRegistry);
ICharacterAttributesFactory attributesFactory = new CharacterAttributesFactory(characterRegistry);
ICharacterStatsFactory statsFactory = new CharacterStatsFactory();
ICharacterStatsFactory statsFactory = new CharacterStatsFactory(characterRegistry);
ICharacterFactory characterFactory = new CharacterFactory(attributesFactory, statsFactory, perkFactory);
IPartyFactory partyFactory = new PartyFactory(characterBaseSettings);
IPartyFactory partyFactory = new PartyFactory(starterCharacterSettings);
return new CharacterSystems(perkFactory, modifiersFactory, characterFactory, partyFactory);
}

View File

@@ -13,7 +13,7 @@ namespace Nox.Game {
public List<PartyDefinitionSet> partyDefinitionSets;
[Header("Testing Party Definition Sets")]
public CharacterBaseSettings characterBaseSettings;
public StarterCharacterSettings starterCharacterSettings;
private void OnValidate() {
if(String.IsNullOrEmpty(startingSetId)) {
@@ -47,9 +47,9 @@ namespace Nox.Game {
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;
var baseSettings = starterCharacterSettings.defaultEntityAttributes;
var classAttributes = starterCharacterSettings.classBonuses.FirstOrDefault(c => c.@class == member.@class)?.bonusAttributes;
var racialAttributes = starterCharacterSettings.racialBonuses.FirstOrDefault(rb => rb.race == member.race)?.bonusAttributes;
if (classAttributes != null && racialAttributes != null) {
member.Attributes += baseSettings + classAttributes + racialAttributes;
}

View File

@@ -12,6 +12,22 @@ namespace Nox.Game {
EntityStats Stats { get; }
}
public enum StatType {
None,
Health,
Stamina,
Level,
Experience
}
public enum AttributeType {
None,
Might,
Reflex,
Knowledge,
Perception
}
public enum CharacterRole {
None,
Protagonist,
@@ -33,29 +49,57 @@ namespace Nox.Game {
Tunneler
}
[Serializable]
public sealed class Stat {
private readonly StatType health;
public StatType type;
public int value;
public Stat(StatType health, int value) {
this.health = health;
this.value = value;
}
}
public sealed record Attribute {
private readonly int values;
public AttributeType attribute;
public int value;
public Attribute(AttributeType attributeType, int values) {
this.values = values;
}
}
[Serializable]
public sealed class EntityAttributes {
public int might;
public int reflex;
public int knowledge;
public int perception;
public Attribute[] attributes = {
new(AttributeType.Might, 1),
new(AttributeType.Reflex, 1),
new(AttributeType.Knowledge, 1),
new(AttributeType.Perception, 1)
};
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
attributes = a.attributes
.Select(attr => new Attribute(attr.attribute, attr.value + b.attributes
.First(attr2 => attr2.attribute == attr.attribute).value))
.ToArray()
};
}
}
[Serializable]
public sealed class EntityStats {
public int health;
public int stamina;
public int level;
public int experience;
public Stat[] stats = {
new(StatType.Health, 0),
new(StatType.Stamina, 0),
new(StatType.Level, 1),
new(StatType.Experience, 0)
};
public int GetValue(StatType statType) {
return stats.First(stat => stat.type == statType).value;
}
}
[Serializable]
@@ -65,8 +109,8 @@ namespace Nox.Game {
public CharacterRace race;
public CharacterClass @class;
public CharacterRole role;
[SerializeField] EntityAttributes attributes;
[SerializeField] EntityStats stats;
[SerializeField] private EntityAttributes attributes;
[SerializeField] private EntityStats stats;
public PerksData perksData = new();
public ModifiersData activeModifiers = new();
@@ -77,15 +121,8 @@ namespace Nox.Game {
role = role,
race = race,
@class = @class,
attributes = new EntityAttributes {
might = attributes?.might ?? 1,
reflex = attributes?.reflex ?? 1,
knowledge = attributes?.knowledge ?? 1
},
stats = new EntityStats {
health = stats?.health ?? 1,
stamina = stats?.stamina ?? 1
},
attributes = new EntityAttributes(),
stats = new EntityStats(),
perksData = new PerksData(),
activeModifiers = new ModifiersData()
};
@@ -100,6 +137,7 @@ namespace Nox.Game {
get => displayName;
set => displayName = value;
}
public EntityAttributes Attributes {
get => attributes;
set => attributes = value;

View File

@@ -10,7 +10,7 @@ namespace Nox.Game {
bool TryAddModifier(CharacterDefinition character, string modiferId);
}
public enum ModifierType {
public enum ModifierRole {
None,
Flat,
Addition,
@@ -20,8 +20,11 @@ namespace Nox.Game {
[Serializable]
public sealed class ModifierDefinition {
public ModifierIds id;
public ModifierType type;
[ReadOnlyField]
public System.Guid id = Guid.NewGuid();
public StatType statType;
public AttributeType attributeType;
public ModifierRole role;
public float value;
}

View File

@@ -1,11 +0,0 @@
namespace Nox.Game {
public enum ModifierIds {
generic_mgt_health_multiplier,
warrior_mgt_health_multiplier,
generic_mgt_mana_multiplier,
generic_kno_mana_multiplier
}
public enum PerksIds{
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: fc2631d096794cea9ae7c9cd82a38c53
timeCreated: 1774366047

View File

@@ -19,46 +19,46 @@ namespace Nox.Game {
});
CharacterTemplate[] companionTemplates = {
new() {
id = "companion-bruiser",
displayName = "Rook",
attributes = new EntityAttributes { might = 5, reflex = 2, knowledge = 1 },
perksData = new PerksData(){
perks = new List<PerkDefinition>()
}
},
new() {
id = "companion-scout",
displayName = "Sable",
attributes = new EntityAttributes { might = 2, reflex = 5, knowledge = 1 },
perksData = new PerksData(){
perks = new List<PerkDefinition>()
}
},
new() {
id = "companion-scholar",
displayName = "Quill",
attributes = new EntityAttributes { might = 1, reflex = 2, knowledge = 5 },
perksData = new PerksData(){
perks = new List<PerkDefinition>()
}
},
new() {
id = "companion-vanguard",
displayName = "Brant",
attributes = new EntityAttributes { might = 4, reflex = 3, knowledge = 2 },
perksData = new PerksData(){
perks = new List<PerkDefinition>()
}
},
new() {
id = "companion-tracker",
displayName = "Mira",
attributes = new EntityAttributes { might = 2, reflex = 4, knowledge = 3 },
perksData = new PerksData(){
perks = new List<PerkDefinition>()
}
}
// new() {
// id = "companion-bruiser",
// displayName = "Rook",
// attributes = new EntityAttributes { might = 5, reflex = 2, knowledge = 1 },
// perksData = new PerksData(){
// perks = new List<PerkDefinition>()
// }
// },
// new() {
// id = "companion-scout",
// displayName = "Sable",
// attributes = new EntityAttributes { might = 2, reflex = 5, knowledge = 1 },
// perksData = new PerksData(){
// perks = new List<PerkDefinition>()
// }
// },
// new() {
// id = "companion-scholar",
// displayName = "Quill",
// attributes = new EntityAttributes { might = 1, reflex = 2, knowledge = 5 },
// perksData = new PerksData(){
// perks = new List<PerkDefinition>()
// }
// },
// new() {
// id = "companion-vanguard",
// displayName = "Brant",
// attributes = new EntityAttributes { might = 4, reflex = 3, knowledge = 2 },
// perksData = new PerksData(){
// perks = new List<PerkDefinition>()
// }
// },
// new() {
// id = "companion-tracker",
// displayName = "Mira",
// attributes = new EntityAttributes { might = 2, reflex = 4, knowledge = 3 },
// perksData = new PerksData(){
// perks = new List<PerkDefinition>()
// }
// }
};
var companions = new List<CharacterDefinition>();

View File

@@ -8,10 +8,10 @@ namespace Nox.Game {
}
public sealed class PartyFactory : IPartyFactory {
private readonly CharacterBaseSettings characterBaseSettings;
private readonly StarterCharacterSettings starterCharacterSettings;
public PartyFactory(CharacterBaseSettings characterBaseSettings) {
this.characterBaseSettings = characterBaseSettings;
public PartyFactory(StarterCharacterSettings starterCharacterSettings) {
this.starterCharacterSettings = starterCharacterSettings;
}
public PartyDefinition Create(CharacterDefinition protagonist, IEnumerable<CharacterDefinition> companions = null) {
@@ -20,7 +20,7 @@ namespace Nox.Game {
}
var party = new PartyDefinition {
maxPartySize = characterBaseSettings.maxPartySize <= 0 ? int.MaxValue : characterBaseSettings.maxPartySize
maxPartySize = starterCharacterSettings.maxPartySize <= 0 ? int.MaxValue : starterCharacterSettings.maxPartySize
};
var protagonistClone = protagonist.Clone();

View File

@@ -3,7 +3,7 @@ using UnityEngine;
namespace Nox.Game {
[CreateAssetMenu(fileName = "CharacterBaseSettings", menuName = "Nox/Database/Entities/CharacterBaseSettings")]
public class CharacterBaseSettings: ScriptableObject {
public class StarterCharacterSettings: ScriptableObject {
[Header("Character Creation Defaults")]
public DistributionPointsPerClass[] distributionPointsPerClass;
public EntityAttributes defaultEntityAttributes;

View File

@@ -21,16 +21,16 @@ MonoBehaviour:
points: 10
- class: 4
points: 10
defaultEntityAttributes:
might: 1
reflex: 1
knowledge: 1
perception: 1
defaultEntityStats:
health: 0
stamina: 0
level: 0
experience: 0
stats:
- type: 0
value: 0
- type: 1
value: 0
- type: 2
value: 1
- type: 3
value: 0
defaultPerksData:
perks: []
defaultModifiersData:
@@ -38,9 +38,6 @@ MonoBehaviour:
- id: 0
type: 3
value: 3
- id: 1
type: 3
value: 4
- id: 2
type: 3
value: 1
@@ -49,64 +46,67 @@ MonoBehaviour:
value: 2
racialBonuses:
- race: 1
bonusAttributes:
might: 0
reflex: 0
knowledge: 1
perception: 0
bonusStats:
health: 0
stamina: 0
level: 0
experience: 0
stats:
- type: 0
value: 10
- type: 0
value: 10
- type: 0
value: 1
- type: 0
value: 0
startingPerks:
perks: []
permanentModifiers:
modifiers: []
- race: 2
bonusAttributes:
might: 0
reflex: 1
knowledge: 0
perception: 0
bonusStats:
health: 0
stamina: 0
level: 0
experience: 0
stats:
- type: 0
value: 10
- type: 0
value: 10
- type: 0
value: 1
- type: 0
value: 0
startingPerks:
perks: []
permanentModifiers:
modifiers: []
- race: 2
bonusAttributes:
might: 1
reflex: 0
knowledge: 0
perception: 0
bonusStats:
health: 0
stamina: 0
level: 0
experience: 0
stats:
- type: 0
value: 10
- type: 0
value: 10
- type: 0
value: 1
- type: 0
value: 0
startingPerks:
perks: []
permanentModifiers:
modifiers: []
classBonuses:
- class: 1
bonusAttributes:
might: 0
reflex: 0
knowledge: 0
perception: 0
bonusStats:
health: 0
stamina: 0
level: 0
experience: 0
stats:
- type: 0
value: 10
- type: 0
value: 10
- type: 0
value: 1
- type: 0
value: 0
startingPerks:
perks: []
permanentModifiers:
modifiers: []
modifiers:
- id: 1
type: 3
value: 4
maxPartySize: 4