using System.Collections;
using UnityEngine;
using Yarn.Unity;
namespace NightclubArcadia.Skills
{
///
/// 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.
///
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] <> called but SkillRuntime is not ready.");
var fallbackRunner = runtime != null ? runtime.DialogueRunner : null;
if (fallbackRunner == null)
{
fallbackRunner = Object.FindFirstObjectByType();
}
WriteFailedResult(fallbackRunner, skillId, difficulty);
yield break;
}
if (!DcBands.TryParse(difficulty, out var dc))
{
Debug.LogError($"[YarnSkillCommands] <>: unknown difficulty; treating as Routine (11).");
dc = (int)DcBand.Routine;
}
if (runtime.Database == null || !runtime.Database.TryGet(skillId, out _))
{
Debug.LogError($"[YarnSkillCommands] <>: 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] <> called but SkillRuntime is not ready.");
return;
}
if (string.IsNullOrEmpty(sourceKey) || string.IsNullOrEmpty(skillId))
{
Debug.LogError("[YarnSkillCommands] <> 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] <> called but SkillRuntime is not ready.");
return;
}
if (string.IsNullOrEmpty(sourceKey))
{
Debug.LogError("[YarnSkillCommands] <> 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",
};
}
}
}