using System.Collections.Generic; using TKS.OutGame; using UnityEngine; namespace TKS { public enum SkillTrigger { /// 액티브 · 다음 슬링샷 1회에 붙는다(예약 · 행동 전 다시 탭 = 취소 · 쿨 소모 없음). NextAction, /// 액티브 · 즉시 발동(행동 소모 없음). Instant, /// 패시브 · 상시. Always } /// 스킬 효과 1개(effect_key 1개 + 값). 키가 하나뿐인 행은 p2·p3 = 그 키의 조건·보조값. public class SkillEffect { public string Key; public float P; public float A2; public float A3; public bool HasA2; public bool HasA3; public SkillEffect Scaled(float factor) { SkillKeys.Info info; if (!SkillKeys.All.TryGetValue(Key, out info)) return this; return new SkillEffect { Key = Key, P = SkillKeys.Apply(info.Main, P, factor), A2 = info.ScaleA2 && HasA2 ? A2 * factor : A2, A3 = A3, HasA2 = HasA2, HasA3 = HasA3, }; } } /// skills.csv 1행의 전투용 정의(SkillInfoDb.Skill → effect_key 를 키 규약대로 풀어 둠). public class SkillDef { public string Id; public string HeroId; public string NameKo; public bool IsActive; public SkillTrigger Trigger; public int Cooldown; public int LvMax; public float LvScale; public bool NeedsImpl; public readonly List Effects = new List(); public static SkillDef From(SkillInfoDb.Skill s) { var d = new SkillDef { Id = s.id, HeroId = s.heroId, NameKo = s.nameKo, IsActive = s.kind == "active", Trigger = s.trigger == "next_action" ? SkillTrigger.NextAction : s.trigger == "instant" ? SkillTrigger.Instant : SkillTrigger.Always, Cooldown = s.cooldown, LvMax = Mathf.Max(1, s.lvMax), LvScale = s.lvScale, NeedsImpl = s.needsImpl, }; var keys = s.EffectKeys; for (int i = 0; i < keys.Length; i++) { if (keys.Length > 1) d.Effects.Add(new SkillEffect { Key = keys[i], P = s.P(i) }); else d.Effects.Add(new SkillEffect { Key = keys[i], P = s.p1, A2 = s.p2, A3 = s.p3, HasA2 = s.HasP(1), HasA3 = s.HasP(2) }); } return d; } /// 레벨 계수 = 1 + lv_scale·(lv−1) (lv 는 1~lv_max 로 자름). public float LevelFactor(int lv) { return 1f + LvScale * (Mathf.Clamp(lv, 1, LvMax) - 1); } /// 레벨·★ 배율(패시브 ★5 = evolve.csv passive_x)을 적용한 효과 목록. public List ScaledEffects(int lv, float starMult) { float f = LevelFactor(lv) * (IsActive ? 1f : starMult); var list = new List(); foreach (var e in Effects) list.Add(e.Scaled(f)); return list; } public SkillEffect First(string key) { foreach (var e in Effects) if (e.Key == key) return e; return null; } } /// 스킬·영웅 표 조회(Resources/OutGame 의 SkillInfoDb · HeroDb = 임포트 자산 · 전투 시작마다 다시 읽음). public static class SkillCatalog { static Dictionary defs; static SkillInfoDb source; static int sourceCount; public static void Invalidate() { defs = null; } static void Ensure() { var db = OutGameData.Default; var s = db != null ? db.Skills : null; if (defs != null && s == source && s != null && s.skills.Count == sourceCount) return; defs = new Dictionary(); source = s; sourceCount = s != null ? s.skills.Count : 0; if (s == null) return; foreach (var row in s.skills) { if (string.IsNullOrEmpty(row.id) || defs.ContainsKey(row.id)) continue; defs[row.id] = SkillDef.From(row); } } public static SkillDef Get(string id) { if (string.IsNullOrEmpty(id)) return null; Ensure(); SkillDef d; return defs.TryGetValue(id, out d) ? d : null; } public static IEnumerable All { get { Ensure(); return defs.Values; } } public static HeroDb.Hero Hero(string id) { var db = OutGameData.Default; return db != null && db.Heroes != null ? db.Heroes.Get(id) : null; } /// 적 무장 → heroes.csv 영웅(아트 id 가 같으면 · 없으면 이름이 같은 영웅) · 병사 유닛 제외 · 없으면 null. public static HeroDb.Hero HeroForEnemy(string art, string name) { var db = OutGameData.Default; if (db == null || db.Heroes == null) return null; HeroDb.Hero byName = null; foreach (var h in db.Heroes.heroes) { if (h.isSoldier) continue; if (!string.IsNullOrEmpty(art) && h.art == art) return h; if (byName == null && !string.IsNullOrEmpty(name) && h.nameKo == name) byName = h; } return byName; } } }