165 lines
6.2 KiB
C#
165 lines
6.2 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using Yarn.Unity;
|
|
|
|
namespace NightclubArcadia.Skills
|
|
{
|
|
/// <summary>
|
|
/// Static Yarn adapter. No MonoBehaviour, no check math — translation only.
|
|
///
|
|
/// Commands:
|
|
/// <<check skillId band-or-int [situationalMod]>>
|
|
/// <<skill_mod sourceKey skillId delta>> — set a state/situational mod
|
|
/// <<clear_skill_mods sourceKey>> — clear one source key
|
|
/// Function (kept as skill_rank; skeleton's "rank" would collide with future helpers):
|
|
/// skill_rank("skillId")
|
|
///
|
|
/// Modifier convention: source key "scene" is the situational bucket and must be
|
|
/// cleared on scene exit; any other key (drunk, injured, …) is a state bucket.
|
|
/// Both feed SkillStateModifiers — three modifier sources total (rank / check arg /
|
|
/// state), not a fourth dictionary.
|
|
/// </summary>
|
|
public static class YarnSkillCommands
|
|
{
|
|
[YarnCommand("check")]
|
|
public static IEnumerator Check(string skillId, string difficulty, int modifier = 0)
|
|
{
|
|
var runtime = SkillRuntime.Instance;
|
|
if (runtime == null || runtime.Checks == null || runtime.DialogueRunner == null)
|
|
{
|
|
Debug.LogError("[YarnSkillCommands] <<check>> called but SkillRuntime is not ready.");
|
|
var fallbackRunner = runtime != null ? runtime.DialogueRunner : null;
|
|
if (fallbackRunner == null)
|
|
{
|
|
fallbackRunner = Object.FindFirstObjectByType<DialogueRunner>();
|
|
}
|
|
WriteFailedResult(fallbackRunner, skillId, difficulty);
|
|
yield break;
|
|
}
|
|
|
|
if (!DcBands.TryParse(difficulty, out var dc))
|
|
{
|
|
Debug.LogError($"[YarnSkillCommands] <<check {skillId} {difficulty}>>: unknown difficulty; treating as Routine (11).");
|
|
dc = (int)DcBand.Routine;
|
|
}
|
|
|
|
if (runtime.Database == null || !runtime.Database.TryGet(skillId, out _))
|
|
{
|
|
Debug.LogError($"[YarnSkillCommands] <<check>>: no skill '{skillId}'.");
|
|
}
|
|
|
|
var result = runtime.Checks.Resolve(skillId, dc, modifier);
|
|
WriteResult(runtime.DialogueRunner.VariableStorage, result);
|
|
|
|
if (runtime.ResultView == null)
|
|
{
|
|
Debug.LogWarning("[YarnSkillCommands] SkillCheckResultView is not assigned; skipping roll banner.");
|
|
yield break;
|
|
}
|
|
|
|
yield return runtime.StartCoroutine(runtime.ResultView.Show(result));
|
|
}
|
|
|
|
[YarnCommand("skill_mod")]
|
|
public static void SkillMod(string sourceKey, string skillId, int delta)
|
|
{
|
|
var runtime = SkillRuntime.Instance;
|
|
if (runtime == null || runtime.States == null)
|
|
{
|
|
Debug.LogError("[YarnSkillCommands] <<skill_mod>> called but SkillRuntime is not ready.");
|
|
return;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(sourceKey) || string.IsNullOrEmpty(skillId))
|
|
{
|
|
Debug.LogError("[YarnSkillCommands] <<skill_mod>> requires sourceKey and skillId.");
|
|
return;
|
|
}
|
|
|
|
runtime.States.Set(sourceKey, skillId, delta);
|
|
}
|
|
|
|
[YarnCommand("clear_skill_mods")]
|
|
public static void ClearSkillMods(string sourceKey)
|
|
{
|
|
var runtime = SkillRuntime.Instance;
|
|
if (runtime == null || runtime.States == null)
|
|
{
|
|
Debug.LogError("[YarnSkillCommands] <<clear_skill_mods>> called but SkillRuntime is not ready.");
|
|
return;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(sourceKey))
|
|
{
|
|
Debug.LogError("[YarnSkillCommands] <<clear_skill_mods>> requires a sourceKey.");
|
|
return;
|
|
}
|
|
|
|
runtime.States.Clear(sourceKey);
|
|
}
|
|
|
|
[YarnFunction("skill_rank")]
|
|
public static float SkillRank(string skillId)
|
|
{
|
|
var runtime = SkillRuntime.Instance;
|
|
if (runtime == null || runtime.Skills == null)
|
|
{
|
|
return 0f;
|
|
}
|
|
|
|
return runtime.Skills.GetRank(skillId);
|
|
}
|
|
|
|
static void WriteResult(VariableStorageBehaviour storage, SkillCheckResult result)
|
|
{
|
|
if (storage == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
storage.SetValue("$check_result", result.Success);
|
|
storage.SetValue("$check_roll", (float)result.Roll);
|
|
storage.SetValue("$check_total", (float)result.Total);
|
|
storage.SetValue("$check_dc", (float)result.DC);
|
|
storage.SetValue("$check_modifier", (float)(result.RankMod + result.SituationalMod + result.StateMod));
|
|
storage.SetValue("$check_degree", DegreeToString(result.Degree));
|
|
storage.SetValue("$check_skill", result.SkillId ?? string.Empty);
|
|
}
|
|
|
|
static void WriteFailedResult(DialogueRunner runner, string skillId, string difficulty)
|
|
{
|
|
if (runner == null || runner.VariableStorage == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DcBands.TryParse(difficulty, out var dc);
|
|
if (dc == 0)
|
|
{
|
|
dc = (int)DcBand.Routine;
|
|
}
|
|
|
|
var storage = runner.VariableStorage;
|
|
storage.SetValue("$check_result", false);
|
|
storage.SetValue("$check_roll", 0f);
|
|
storage.SetValue("$check_total", 0f);
|
|
storage.SetValue("$check_dc", (float)dc);
|
|
storage.SetValue("$check_modifier", 0f);
|
|
storage.SetValue("$check_degree", "failure");
|
|
storage.SetValue("$check_skill", skillId ?? string.Empty);
|
|
}
|
|
|
|
static string DegreeToString(SkillCheckDegree degree)
|
|
{
|
|
return degree switch
|
|
{
|
|
SkillCheckDegree.CriticalFailure => "critical_failure",
|
|
SkillCheckDegree.Failure => "failure",
|
|
SkillCheckDegree.Success => "success",
|
|
SkillCheckDegree.CriticalSuccess => "critical_success",
|
|
_ => "failure",
|
|
};
|
|
}
|
|
}
|
|
}
|