158 lines
5.3 KiB
C#
158 lines
5.3 KiB
C#
using BumpCombat.Player;
|
|
using BumpCombat.Core;
|
|
using System;
|
|
using System.Globalization;
|
|
using UnityEngine;
|
|
|
|
namespace BumpCombat.Progression
|
|
{
|
|
[CreateAssetMenu(
|
|
fileName = "ModifierDefinition",
|
|
menuName = "BumpCombat/Progression/Modifier Definition")]
|
|
public sealed class ModifierDefinition : ScriptableObject
|
|
{
|
|
[SerializeField] private string modifierId;
|
|
[SerializeField] private string displayName;
|
|
[SerializeField] private CharacterStat stat;
|
|
[SerializeField] private ModifierOperation operation;
|
|
[SerializeField] private float value;
|
|
[SerializeField, Min(1)] private int maximumStacks = 1;
|
|
[SerializeField, Min(0f)] private float healOnApply;
|
|
|
|
public string ModifierId => modifierId;
|
|
public string DisplayName => displayName;
|
|
public CharacterStat Stat => stat;
|
|
public ModifierOperation Operation => operation;
|
|
public float Value => value;
|
|
public int MaximumStacks => maximumStacks;
|
|
public float HealOnApply => healOnApply;
|
|
|
|
public string GetKoreanDisplayName()
|
|
{
|
|
return $"{GetKoreanStatName(stat)} 강화";
|
|
}
|
|
|
|
public string GetKoreanEffectDescription(float effectMultiplier)
|
|
{
|
|
string statName = GetKoreanStatName(stat);
|
|
string effectValue = operation == ModifierOperation.Flat
|
|
? FormatSignedValue(value * effectMultiplier)
|
|
: $"{FormatSignedValue(value * effectMultiplier * 100f)}%";
|
|
string description = $"{statName} {effectValue}";
|
|
if (healOnApply > 0f)
|
|
{
|
|
description += $"\n즉시 체력 회복 {FormatSignedValue(healOnApply * effectMultiplier)}";
|
|
}
|
|
|
|
return description + "\n선택하면 즉시 적용됩니다.";
|
|
}
|
|
|
|
private static string GetKoreanStatName(CharacterStat targetStat)
|
|
{
|
|
switch (targetStat)
|
|
{
|
|
case CharacterStat.CollisionDamage: return "몸통박치기 피해";
|
|
case CharacterStat.MoveSpeed: return "이동 속도";
|
|
case CharacterStat.MaxHealth: return "최대 체력";
|
|
case CharacterStat.Armor: return "방어력";
|
|
case CharacterStat.LifeSteal: return "생명력 흡수";
|
|
case CharacterStat.ExperienceGain: return "경험치 획득량";
|
|
case CharacterStat.ExperiencePickupRange: return "경험치 획득 범위";
|
|
case CharacterStat.ArtifactGaugeGain: return "유물 게이지 획득량";
|
|
case CharacterStat.IncomingDamage: return "받는 피해";
|
|
case CharacterStat.AttackDamage: return "공격 피해";
|
|
default: return "능력치";
|
|
}
|
|
}
|
|
|
|
private static string FormatSignedValue(float amount)
|
|
{
|
|
if (Mathf.Approximately(amount, 0f))
|
|
{
|
|
return "0";
|
|
}
|
|
|
|
string formatted = amount.ToString("0.##", CultureInfo.InvariantCulture);
|
|
return amount > 0f ? $"+{formatted}" : formatted;
|
|
}
|
|
|
|
public bool CanApply(PlayerStats playerStats)
|
|
{
|
|
return CanApplyToModel(playerStats);
|
|
}
|
|
|
|
public bool CanApplyToModel(CharacterModel model)
|
|
{
|
|
return model != null
|
|
&& model.GetStackCount(modifierId, stat) < maximumStacks;
|
|
}
|
|
|
|
public bool TryApply(
|
|
PlayerStats playerStats,
|
|
PlayerHealth playerHealth)
|
|
{
|
|
Action<float> heal = playerHealth == null
|
|
? null
|
|
: amount => playerHealth.Heal(amount);
|
|
return TryApplyToModel(playerStats, heal);
|
|
}
|
|
|
|
public bool TryApplyToModel(
|
|
CharacterModel model,
|
|
Action<float> heal)
|
|
{
|
|
return TryApplyToModel(model, heal, 1f);
|
|
}
|
|
|
|
public bool TryApplyToModel(
|
|
CharacterModel model,
|
|
Action<float> heal,
|
|
float effectMultiplier)
|
|
{
|
|
if (float.IsNaN(effectMultiplier)
|
|
|| float.IsInfinity(effectMultiplier)
|
|
|| effectMultiplier < 0f)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!CanApplyToModel(model)
|
|
|| !model.AddModifier(new StatModifier(
|
|
modifierId,
|
|
stat,
|
|
operation,
|
|
value * effectMultiplier,
|
|
maximumStacks)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (healOnApply > 0f && heal != null)
|
|
{
|
|
heal(healOnApply * effectMultiplier);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
public void Configure(
|
|
string id,
|
|
string label,
|
|
CharacterStat targetStat,
|
|
ModifierOperation modifierOperation,
|
|
float modifierValue,
|
|
int maxStacks,
|
|
float immediateHeal = 0f)
|
|
{
|
|
modifierId = id;
|
|
displayName = label;
|
|
stat = targetStat;
|
|
operation = modifierOperation;
|
|
value = modifierValue;
|
|
maximumStacks = Mathf.Max(1, maxStacks);
|
|
healOnApply = Mathf.Max(0f, immediateHeal);
|
|
}
|
|
#endif
|
|
}
|
|
}
|