refactor the skill system to adhere to the lore handbook

This commit is contained in:
2026-08-15 11:13:15 +02:00
parent 063e94f6eb
commit 9e5c3277bf
70 changed files with 2271 additions and 445 deletions
@@ -1,39 +1,77 @@
using System;
using UnityEngine;
namespace NightclubArcadia.Skills
{
// Generated from Assets/Skills/skill_bible.json by SkillSystemSetup.
// Hand-edits to .asset files are overwritten on script reload — edit the JSON.
[CreateAssetMenu(menuName = "Nightclub Arcadia/Skill Definition", fileName = "NewSkill")]
public sealed class SkillDefinition : ScriptableObject
{
[SerializeField] string id;
[SerializeField] string displayName;
[SerializeField] SkillDomain domain;
[TextArea] [SerializeField] string description;
[SerializeField] SkillAxis axis;
[SerializeField] string domain;
[TextArea(8, 24)] [SerializeField] string notes;
[SerializeField] float targetFiringsPerHour = 5f;
[SerializeField] string opposedTo;
[SerializeField] string[] alliedWith;
[SerializeField] TraceChannel primaryChannel;
[SerializeField] TraceChannel secondaryChannel;
[SerializeField] ClueYield clueYield;
[SerializeField] int startingRank;
[SerializeField] Color accentColor = Color.white;
public string Id => id;
public string DisplayName => displayName;
public SkillDomain Domain => domain;
public string Description => description;
public SkillAxis Axis => axis;
public string Domain => domain;
public string Notes => notes;
public float TargetFiringsPerHour => targetFiringsPerHour;
public string OpposedTo => opposedTo;
public string[] AlliedWith => alliedWith;
public TraceChannel PrimaryChannel => primaryChannel;
public TraceChannel SecondaryChannel => secondaryChannel;
public ClueYield ClueYield => clueYield;
public int StartingRank => startingRank;
public Color AccentColor => accentColor;
#if UNITY_EDITOR
public void EditorSet(
string newId,
string newDisplayName,
SkillDomain newDomain,
string newDescription,
int newStartingRank,
Color newAccentColor)
public void EditorSet(SkillBibleEntry entry)
{
id = newId;
displayName = newDisplayName;
domain = newDomain;
description = newDescription;
startingRank = newStartingRank;
accentColor = newAccentColor;
if (entry == null)
{
throw new ArgumentNullException(nameof(entry));
}
id = entry.id;
displayName = entry.displayName;
axis = ParseEnumRequired<SkillAxis>(entry.axis, nameof(entry.axis), entry.id);
domain = entry.domain ?? string.Empty;
notes = entry.notes ?? string.Empty;
targetFiringsPerHour = entry.targetFiringsPerHour;
opposedTo = entry.opposedTo ?? string.Empty;
alliedWith = entry.alliedWith ?? Array.Empty<string>();
primaryChannel = ParseEnumRequired<TraceChannel>(entry.primaryChannel, nameof(entry.primaryChannel), entry.id);
secondaryChannel = ParseEnumRequired<TraceChannel>(
string.IsNullOrEmpty(entry.secondaryChannel) ? "None" : entry.secondaryChannel,
nameof(entry.secondaryChannel),
entry.id);
clueYield = ParseEnumRequired<ClueYield>(entry.clueYield, nameof(entry.clueYield), entry.id);
startingRank = entry.startingRank;
accentColor = entry.accentColor;
}
static TEnum ParseEnumRequired<TEnum>(string value, string fieldName, string skillId)
where TEnum : struct
{
if (!Enum.TryParse(value, ignoreCase: true, out TEnum parsed))
{
throw new ArgumentException(
$"Skill '{skillId}': invalid {fieldName} '{value}' for {typeof(TEnum).Name}.");
}
return parsed;
}
#endif
}