feat(item): Phase 2 아이템 시스템 구현

- ItemStats, ItemRarity 클래스 추가 (아이템 스탯/희귀도)
- EquipmentItem 클래스 추가 (개별 장비 아이템)
- ItemService 추가 (아이템 생성/관리/무게 시스템)
- Equipment 클래스 확장 (EquipmentItem 기반, 기존 API 호환)
- CombatStats에서 장비 스탯 반영
- 레거시 세이브 파일 호환성 유지
This commit is contained in:
JiWoong Sul
2025-12-17 16:57:23 +09:00
parent c62687f7bd
commit 6a696ecd57
6 changed files with 726 additions and 122 deletions

View File

@@ -198,55 +198,71 @@ class CombatStats {
/// Stats와 Equipment에서 CombatStats 생성
///
/// [stats] 캐릭터 기본 스탯
/// [equipment] 장착 장비 (향후 장비 스탯 적용 시 사용)
/// [equipment] 장착 장비 (장비 스탯 적용)
/// [level] 캐릭터 레벨 (스케일링용)
factory CombatStats.fromStats({
required Stats stats,
required Equipment equipment,
required int level,
}) {
// 기본 공격력: STR 기반 + 레벨 보정
final baseAtk = stats.str * 2 + level;
// 장비 총 스탯 가져오기
final equipStats = equipment.totalStats;
// 기본 방어력: CON 기반 + 레벨 보정
final baseDef = stats.con + (level ~/ 2);
// 장비 보너스가 적용된 기본 스탯
final effectiveStr = stats.str + equipStats.strBonus;
final effectiveCon = stats.con + equipStats.conBonus;
final effectiveDex = stats.dex + equipStats.dexBonus;
final effectiveInt = stats.intelligence + equipStats.intBonus;
final effectiveWis = stats.wis + equipStats.wisBonus;
// 마법 공격력: INT 기반
final baseMagAtk = stats.intelligence * 2 + level;
// 기본 공격력: STR 기반 + 레벨 보정 + 장비 ATK
final baseAtk = effectiveStr * 2 + level + equipStats.atk;
// 마법 방어력: WIS 기반
final baseMagDef = stats.wis + (level ~/ 2);
// 기본 방어력: CON 기반 + 레벨 보정 + 장비 DEF
final baseDef = effectiveCon + (level ~/ 2) + equipStats.def;
// 크리티컬 확률: DEX 기반 (0.05 ~ 0.5)
final criRate = (0.05 + stats.dex * 0.005).clamp(0.05, 0.5);
// 마법 공격력: INT 기반 + 장비 MAG_ATK
final baseMagAtk = effectiveInt * 2 + level + equipStats.magAtk;
// 마법 방어력: WIS 기반 + 장비 MAG_DEF
final baseMagDef = effectiveWis + (level ~/ 2) + equipStats.magDef;
// 크리티컬 확률: DEX 기반 + 장비 보너스 (0.05 ~ 0.5)
final criRate = (0.05 + effectiveDex * 0.005 + equipStats.criRate).clamp(0.05, 0.5);
// 크리티컬 데미지: 기본 1.5배, DEX에 따라 증가 (최대 3.0)
final criDamage = (1.5 + stats.dex * 0.01).clamp(1.5, 3.0);
final criDamage = (1.5 + effectiveDex * 0.01).clamp(1.5, 3.0);
// 회피율: DEX 기반 (0.0 ~ 0.5)
final evasion = (stats.dex * 0.005).clamp(0.0, 0.5);
// 회피율: DEX 기반 + 장비 보너스 (0.0 ~ 0.5)
final evasion = (effectiveDex * 0.005 + equipStats.evasion).clamp(0.0, 0.5);
// 명중률: DEX 기반 (0.8 ~ 1.0)
final accuracy = (0.8 + stats.dex * 0.002).clamp(0.8, 1.0);
final accuracy = (0.8 + effectiveDex * 0.002).clamp(0.8, 1.0);
// 방패 방어율: 방패 장착 여부에 따라 (0.0 ~ 0.4)
// 방패 방어율: 방패 장착 시 기본 + CON 보정 + 장비 보너스 (0.0 ~ 0.5)
final hasShield = equipment.shield.isNotEmpty;
final blockRate = hasShield ? (0.1 + stats.con * 0.003).clamp(0.1, 0.4) : 0.0;
final baseBlockRate = hasShield ? (0.1 + effectiveCon * 0.003) : 0.0;
final blockRate = (baseBlockRate + equipStats.blockRate).clamp(0.0, 0.5);
// 무기 쳐내기: DEX + STR 기반 (0.0 ~ 0.3)
final parryRate = ((stats.dex + stats.str) * 0.002).clamp(0.0, 0.3);
// 무기 쳐내기: DEX + STR 기반 + 장비 보너스 (0.0 ~ 0.4)
final baseParryRate = (effectiveDex + effectiveStr) * 0.002;
final parryRate = (baseParryRate + equipStats.parryRate).clamp(0.0, 0.4);
// 공격 속도: DEX 기반 (기본 1000ms, 최소 357ms)
final speedModifier = 1.0 + (stats.dex - 10) * 0.02;
final speedModifier = 1.0 + (effectiveDex - 10) * 0.02;
final attackDelayMs = (1000 / speedModifier).round().clamp(357, 1500);
// HP/MP: 기본 + 장비 보너스
final totalHpMax = stats.hpMax + equipStats.hpBonus;
final totalMpMax = stats.mpMax + equipStats.mpBonus;
return CombatStats(
str: stats.str,
con: stats.con,
dex: stats.dex,
intelligence: stats.intelligence,
wis: stats.wis,
cha: stats.cha,
str: effectiveStr,
con: effectiveCon,
dex: effectiveDex,
intelligence: effectiveInt,
wis: effectiveWis,
cha: stats.cha + equipStats.chaBonus,
atk: baseAtk,
def: baseDef,
magAtk: baseMagAtk,
@@ -258,10 +274,10 @@ class CombatStats {
blockRate: blockRate,
parryRate: parryRate,
attackDelayMs: attackDelayMs,
hpMax: stats.hpMax,
hpCurrent: stats.hp,
mpMax: stats.mpMax,
mpCurrent: stats.mp,
hpMax: totalHpMax,
hpCurrent: stats.hp.clamp(0, totalHpMax),
mpMax: totalMpMax,
mpCurrent: stats.mp.clamp(0, totalMpMax),
);
}