119 lines
4.3 KiB
C#
119 lines
4.3 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace TKS
|
||
{
|
||
/// <summary>
|
||
/// 밸런스·스테이지 데이터의 단일 출처(SOT). 코드에는 수치를 두지 않고 이 자산만 읽는다.
|
||
/// 기본값은 에디터 셋업(ProjectSetup)이 최초 1회 시드한다.
|
||
/// </summary>
|
||
[CreateAssetMenu(menuName = "TKS/Balance Config", fileName = "BalanceConfig")]
|
||
public class BalanceConfig : ScriptableObject
|
||
{
|
||
[Serializable]
|
||
public class UnitStats
|
||
{
|
||
public UnitType type;
|
||
public int maxHp;
|
||
public int atk;
|
||
public int def;
|
||
[Tooltip("슬링샷으로 지정할 수 있는 최대 거리(월드 단위)")]
|
||
public float slingMaxDistance;
|
||
[Tooltip("궁병 사거리 · 창병 대기(견제) 반경")]
|
||
public float attackRange;
|
||
public float radius;
|
||
}
|
||
|
||
[Serializable]
|
||
public class HeroDef
|
||
{
|
||
public string name;
|
||
public UnitType type;
|
||
public float hpMult = 1f;
|
||
public float atkMult = 1f;
|
||
}
|
||
|
||
[Serializable]
|
||
public class EnemySpawn
|
||
{
|
||
public string name;
|
||
public UnitType type;
|
||
public Vector2 position;
|
||
public float hpMult = 1f;
|
||
public float atkMult = 1f;
|
||
public bool isBoss;
|
||
}
|
||
|
||
[Serializable]
|
||
public class StageDef
|
||
{
|
||
public string title;
|
||
public string subtitle;
|
||
[Range(0f, 1f)] public float aiAccuracy = 0.6f;
|
||
public List<EnemySpawn> enemies = new List<EnemySpawn>();
|
||
}
|
||
|
||
[Header("병종 기본 능력치")]
|
||
public UnitStats[] unitStats = new UnitStats[0];
|
||
|
||
[Header("상성 배율 (행 = 공격자, 열 = 피격자 · 순서 보병·기병·궁병·창병)")]
|
||
public float[] matchup = new float[UnitTypeInfo.Count * UnitTypeInfo.Count];
|
||
|
||
[Header("전투 공식")]
|
||
[Tooltip("피해 = 공격 × 상성 × (크리 배율) − 방어 × defenseFactor")]
|
||
public float defenseFactor = 0.5f;
|
||
[Tooltip("근접 공격을 받은 쪽이 되돌려주는 반격 피해 비율")]
|
||
public float counterRatio = 0.5f;
|
||
public float critMultiplier = 2f;
|
||
[Tooltip("피해 난수 폭 (0.1 = ±10 %)")]
|
||
public float damageVariance = 0.1f;
|
||
[Tooltip("창병 대기 상태에서 움직이는 적에게 주는 피해 비율")]
|
||
public float overwatchDamageRatio = 1f;
|
||
public float bossHpMult = 1.5f;
|
||
public float bossRadiusMult = 1.25f;
|
||
[Tooltip("기병 관통 시 적을 옆으로 밀어내는 거리")]
|
||
public float cavalryKnockback = 0.35f;
|
||
|
||
[Header("조작")]
|
||
[Tooltip("이보다 짧게 당기면 취소")]
|
||
public float minDragDistance = 0.35f;
|
||
[Tooltip("슬링샷 최종 목표점이 적 원 안에 들어왔다고 보는 여유")]
|
||
public float finalHitTolerance = 0.15f;
|
||
public float moveSpeed = 9f;
|
||
|
||
[Header("전장")]
|
||
public Vector2 boardSize = new Vector2(12f, 16f);
|
||
public Vector2[] playerSpawnPoints = new Vector2[0];
|
||
|
||
[Header("아군 영웅 (최대 5)")]
|
||
public HeroDef[] heroes = new HeroDef[0];
|
||
|
||
[Header("스테이지")]
|
||
public StageDef[] stages = new StageDef[0];
|
||
|
||
public UnitStats GetStats(UnitType t)
|
||
{
|
||
for (int i = 0; i < unitStats.Length; i++)
|
||
{
|
||
if (unitStats[i].type == t) return unitStats[i];
|
||
}
|
||
throw new InvalidOperationException("BalanceConfig 에 " + t + " 능력치가 없습니다.");
|
||
}
|
||
|
||
public float Matchup(UnitType attacker, UnitType defender)
|
||
{
|
||
int idx = (int)attacker * UnitTypeInfo.Count + (int)defender;
|
||
if (matchup == null || idx >= matchup.Length) return 1f;
|
||
return matchup[idx];
|
||
}
|
||
|
||
public void SetMatchup(UnitType attacker, UnitType defender, float value)
|
||
{
|
||
if (matchup == null || matchup.Length != UnitTypeInfo.Count * UnitTypeInfo.Count)
|
||
matchup = new float[UnitTypeInfo.Count * UnitTypeInfo.Count];
|
||
matchup[(int)attacker * UnitTypeInfo.Count + (int)defender] = value;
|
||
}
|
||
}
|
||
}
|