- 빌드 입력, 룰셋, 회전 정책, 결과/리포트 모델을 포함한 데미지 계산 시뮬레이터 기반을 추가 - 단일 실행 창과 배치 전수 조사 창, 플레이어 데미지 스윕 메뉴를 추가 - DamageEffect 계산값 접근자를 열어 기존 전투 공식을 시뮬레이터에서 재사용하도록 정리
153 lines
6.1 KiB
C#
153 lines
6.1 KiB
C#
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
using UnityEngine;
|
|
|
|
namespace Colosseum.Combat.Simulation
|
|
{
|
|
/// <summary>
|
|
/// 스킬별 기여도 요약입니다.
|
|
/// </summary>
|
|
[System.Serializable]
|
|
public sealed class SimulationSkillBreakdown
|
|
{
|
|
[SerializeField] private string skillName;
|
|
[Min(0)] [SerializeField] private int castCount;
|
|
[Min(0f)] [SerializeField] private float totalDamage;
|
|
|
|
public string SkillName => skillName;
|
|
public int CastCount => castCount;
|
|
public float TotalDamage => totalDamage;
|
|
|
|
public SimulationSkillBreakdown(string skillName, int castCount, float totalDamage)
|
|
{
|
|
this.skillName = skillName ?? "Unknown";
|
|
this.castCount = Mathf.Max(0, castCount);
|
|
this.totalDamage = Mathf.Max(0f, totalDamage);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 허수아비 계산 시뮬레이터 결과입니다.
|
|
/// </summary>
|
|
[System.Serializable]
|
|
public sealed class SimulationResult
|
|
{
|
|
[SerializeField] private string summaryLine = string.Empty;
|
|
[TextArea(8, 30)]
|
|
[SerializeField] private string detailText = string.Empty;
|
|
[SerializeField] private string buildLabel = string.Empty;
|
|
[SerializeField] private string ruleName = string.Empty;
|
|
[SerializeField] private string rotationName = string.Empty;
|
|
[Min(0f)] [SerializeField] private float durationSeconds;
|
|
[Min(0f)] [SerializeField] private float totalDamage;
|
|
[Min(0f)] [SerializeField] private float averageDps;
|
|
[Min(0f)] [SerializeField] private float totalManaUsed;
|
|
[Min(0f)] [SerializeField] private float averageManaPerSecond;
|
|
[SerializeField] private float firstCycleEndTime = -1f;
|
|
[SerializeField] private List<SimulationSkillBreakdown> skillBreakdowns = new List<SimulationSkillBreakdown>();
|
|
[SerializeField] private List<string> warnings = new List<string>();
|
|
|
|
public string SummaryLine => summaryLine;
|
|
public string DetailText => detailText;
|
|
public string BuildLabel => buildLabel;
|
|
public string RuleName => ruleName;
|
|
public string RotationName => rotationName;
|
|
public float DurationSeconds => durationSeconds;
|
|
public float TotalDamage => totalDamage;
|
|
public float AverageDps => averageDps;
|
|
public float TotalManaUsed => totalManaUsed;
|
|
public float AverageManaPerSecond => averageManaPerSecond;
|
|
public float FirstCycleEndTime => firstCycleEndTime;
|
|
public IReadOnlyList<SimulationSkillBreakdown> SkillBreakdowns => skillBreakdowns;
|
|
public IReadOnlyList<string> Warnings => warnings;
|
|
|
|
public void FinalizeResult(
|
|
string buildLabel,
|
|
string ruleName,
|
|
string rotationName,
|
|
float durationSeconds,
|
|
float totalDamage,
|
|
float totalManaUsed,
|
|
float firstCycleEndTime,
|
|
List<SimulationSkillBreakdown> breakdowns,
|
|
List<string> warnings)
|
|
{
|
|
this.buildLabel = buildLabel ?? string.Empty;
|
|
this.ruleName = ruleName ?? string.Empty;
|
|
this.rotationName = rotationName ?? string.Empty;
|
|
this.durationSeconds = Mathf.Max(0f, durationSeconds);
|
|
this.totalDamage = Mathf.Max(0f, totalDamage);
|
|
averageDps = this.durationSeconds > 0f ? this.totalDamage / this.durationSeconds : 0f;
|
|
this.totalManaUsed = Mathf.Max(0f, totalManaUsed);
|
|
averageManaPerSecond = this.durationSeconds > 0f ? this.totalManaUsed / this.durationSeconds : 0f;
|
|
this.firstCycleEndTime = firstCycleEndTime;
|
|
|
|
skillBreakdowns = breakdowns ?? new List<SimulationSkillBreakdown>();
|
|
this.warnings = warnings ?? new List<string>();
|
|
summaryLine = BuildSummaryLine();
|
|
detailText = BuildDetailText();
|
|
}
|
|
|
|
private string BuildSummaryLine()
|
|
{
|
|
StringBuilder builder = new StringBuilder();
|
|
builder.Append("[BuildSimulation] ");
|
|
builder.Append(buildLabel);
|
|
builder.Append(" | Rule=");
|
|
builder.Append(ruleName);
|
|
builder.Append(" | Rotation=");
|
|
builder.Append(rotationName);
|
|
builder.Append(" | Dmg=");
|
|
builder.Append(totalDamage.ToString("0.##"));
|
|
builder.Append(" | DPS=");
|
|
builder.Append(averageDps.ToString("0.##"));
|
|
builder.Append(" | Mana=");
|
|
builder.Append(totalManaUsed.ToString("0.##"));
|
|
builder.Append(" | Cycle=");
|
|
builder.Append(firstCycleEndTime >= 0f ? firstCycleEndTime.ToString("0.##") + "s" : "미완료");
|
|
return builder.ToString();
|
|
}
|
|
|
|
private string BuildDetailText()
|
|
{
|
|
StringBuilder builder = new StringBuilder();
|
|
builder.AppendLine(summaryLine);
|
|
builder.Append("Duration=");
|
|
builder.Append(durationSeconds.ToString("0.##"));
|
|
builder.Append("s | ManaPerSec=");
|
|
builder.Append(averageManaPerSecond.ToString("0.##"));
|
|
builder.AppendLine();
|
|
|
|
if (skillBreakdowns.Count > 0)
|
|
{
|
|
builder.AppendLine("Skill Breakdown");
|
|
for (int i = 0; i < skillBreakdowns.Count; i++)
|
|
{
|
|
SimulationSkillBreakdown entry = skillBreakdowns[i];
|
|
builder.Append("- ");
|
|
builder.Append(entry.SkillName);
|
|
builder.Append(" | Cast=");
|
|
builder.Append(entry.CastCount);
|
|
builder.Append(" | Dmg=");
|
|
builder.Append(entry.TotalDamage.ToString("0.##"));
|
|
builder.AppendLine();
|
|
}
|
|
}
|
|
|
|
if (warnings.Count > 0)
|
|
{
|
|
builder.AppendLine("Warnings");
|
|
for (int i = 0; i < warnings.Count; i++)
|
|
{
|
|
builder.Append("- ");
|
|
builder.Append(warnings[i]);
|
|
builder.AppendLine();
|
|
}
|
|
}
|
|
|
|
return builder.ToString().TrimEnd();
|
|
}
|
|
}
|
|
}
|