implemented skill system according to designdocuments

This commit is contained in:
2026-08-15 08:09:29 +02:00
parent f8def361fa
commit 063e94f6eb
95 changed files with 2924 additions and 4 deletions
@@ -0,0 +1,43 @@
using System;
using System.Globalization;
namespace NightclubArcadia.Skills
{
public enum DcBand
{
Trivial = 5,
Easy = 8,
Standard = 11,
Hard = 14,
Formidable = 17,
Legendary = 20,
}
public static class DcBands
{
public static bool TryParse(string input, out int dc)
{
dc = 0;
if (string.IsNullOrWhiteSpace(input))
{
return false;
}
input = input.Trim();
if (int.TryParse(input, NumberStyles.Integer, CultureInfo.InvariantCulture, out var numeric))
{
dc = numeric;
return true;
}
if (Enum.TryParse<DcBand>(input, ignoreCase: true, out var band))
{
dc = (int)band;
return true;
}
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 04013b352063419eb6f0c8932a3cb116
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,10 @@
namespace NightclubArcadia.Skills
{
public enum SkillCheckDegree
{
CriticalFailure,
Failure,
Success,
CriticalSuccess,
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a099dc0cf50346e98ea9795411a21f99
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,40 @@
namespace NightclubArcadia.Skills
{
public readonly struct SkillCheckResult
{
public SkillCheckResult(
string skillId,
string skillDisplayName,
int roll,
int rankMod,
int situationalMod,
int stateMod,
int total,
int dc,
bool success,
SkillCheckDegree degree)
{
SkillId = skillId;
SkillDisplayName = skillDisplayName;
Roll = roll;
RankMod = rankMod;
SituationalMod = situationalMod;
StateMod = stateMod;
Total = total;
DC = dc;
Success = success;
Degree = degree;
}
public string SkillId { get; }
public string SkillDisplayName { get; }
public int Roll { get; }
public int RankMod { get; }
public int SituationalMod { get; }
public int StateMod { get; }
public int Total { get; }
public int DC { get; }
public bool Success { get; }
public SkillCheckDegree Degree { get; }
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2ee1160f9fa3439280ca256e5f23193f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace NightclubArcadia.Skills
{
[CreateAssetMenu(menuName = "Nightclub Arcadia/Skill Database", fileName = "SkillDatabase")]
public sealed class SkillDatabase : ScriptableObject
{
[SerializeField] List<SkillDefinition> skills = new List<SkillDefinition>();
Dictionary<string, SkillDefinition> _lookup;
public IReadOnlyList<SkillDefinition> All => skills;
public bool TryGet(string skillId, out SkillDefinition def)
{
EnsureLookup();
if (string.IsNullOrEmpty(skillId))
{
def = null;
return false;
}
return _lookup.TryGetValue(skillId, out def);
}
void EnsureLookup()
{
if (_lookup != null)
{
return;
}
_lookup = new Dictionary<string, SkillDefinition>(StringComparer.OrdinalIgnoreCase);
if (skills == null)
{
return;
}
foreach (var skill in skills)
{
if (skill == null || string.IsNullOrEmpty(skill.Id))
{
continue;
}
_lookup[skill.Id] = skill;
}
}
void OnValidate()
{
_lookup = null;
if (skills == null)
{
return;
}
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var skill in skills)
{
if (skill == null)
{
Debug.LogError($"[{nameof(SkillDatabase)}] Null skill entry in {name}.", this);
continue;
}
if (string.IsNullOrEmpty(skill.Id))
{
Debug.LogError($"[{nameof(SkillDatabase)}] Skill '{skill.name}' has an empty Id.", this);
continue;
}
if (!seen.Add(skill.Id))
{
Debug.LogError($"[{nameof(SkillDatabase)}] Duplicate skill Id '{skill.Id}'.", this);
}
}
}
#if UNITY_EDITOR
public void EditorSetSkills(List<SkillDefinition> newSkills)
{
skills = newSkills ?? new List<SkillDefinition>();
_lookup = null;
}
#endif
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 73f6e7831a60457b918d303c16fc6cec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,40 @@
using UnityEngine;
namespace NightclubArcadia.Skills
{
[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] int startingRank;
[SerializeField] Color accentColor = Color.white;
public string Id => id;
public string DisplayName => displayName;
public SkillDomain Domain => domain;
public string Description => description;
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)
{
id = newId;
displayName = newDisplayName;
domain = newDomain;
description = newDescription;
startingRank = newStartingRank;
accentColor = newAccentColor;
}
#endif
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9a26230b6f20436891aa772e8f858f3f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,10 @@
namespace NightclubArcadia.Skills
{
public enum SkillDomain
{
Reason,
Instinct,
Presence,
Body,
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0bdf9a02be4b42a4a48a099fe924980e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: