feat(race-class): Phase 5 종족/클래스 특화 시스템 구현
- RaceTraits: 7종족 (Byte Human, Null Elf, Buffer Dwarf 등) - ClassTraits: 6클래스 (Bug Hunter, Compiler Mage 등) - StatCalculator: 종족/클래스 보정 계산 - CombatStats.fromStats: 종족/클래스 패시브 효과 통합 - 종족별 스탯 보정 및 패시브 (경험치, HP/MP, 크리티컬 등) - 클래스별 스탯 보정 및 패시브 (공격력, 방어력, 회피 등)
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import 'package:askiineverdie/src/core/model/class_traits.dart';
|
||||
import 'package:askiineverdie/src/core/model/game_state.dart';
|
||||
import 'package:askiineverdie/src/core/model/race_traits.dart';
|
||||
|
||||
/// 전투용 파생 스탯
|
||||
///
|
||||
@@ -200,41 +202,61 @@ class CombatStats {
|
||||
/// [stats] 캐릭터 기본 스탯
|
||||
/// [equipment] 장착 장비 (장비 스탯 적용)
|
||||
/// [level] 캐릭터 레벨 (스케일링용)
|
||||
/// [race] 종족 특성 (선택사항, Phase 5)
|
||||
/// [klass] 클래스 특성 (선택사항, Phase 5)
|
||||
factory CombatStats.fromStats({
|
||||
required Stats stats,
|
||||
required Equipment equipment,
|
||||
required int level,
|
||||
RaceTraits? race,
|
||||
ClassTraits? klass,
|
||||
}) {
|
||||
// 장비 총 스탯 가져오기
|
||||
final equipStats = equipment.totalStats;
|
||||
|
||||
// 장비 보너스가 적용된 기본 스탯
|
||||
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;
|
||||
// 종족/클래스 스탯 보정 적용
|
||||
final raceStr = race?.getModifier(StatType.str) ?? 0;
|
||||
final raceCon = race?.getModifier(StatType.con) ?? 0;
|
||||
final raceDex = race?.getModifier(StatType.dex) ?? 0;
|
||||
final raceInt = race?.getModifier(StatType.intelligence) ?? 0;
|
||||
final raceWis = race?.getModifier(StatType.wis) ?? 0;
|
||||
final raceCha = race?.getModifier(StatType.cha) ?? 0;
|
||||
|
||||
final classStr = klass?.getModifier(StatType.str) ?? 0;
|
||||
final classCon = klass?.getModifier(StatType.con) ?? 0;
|
||||
final classDex = klass?.getModifier(StatType.dex) ?? 0;
|
||||
final classInt = klass?.getModifier(StatType.intelligence) ?? 0;
|
||||
final classWis = klass?.getModifier(StatType.wis) ?? 0;
|
||||
final classCha = klass?.getModifier(StatType.cha) ?? 0;
|
||||
|
||||
// 장비 보너스 + 종족/클래스 보정이 적용된 기본 스탯
|
||||
final effectiveStr = stats.str + equipStats.strBonus + raceStr + classStr;
|
||||
final effectiveCon = stats.con + equipStats.conBonus + raceCon + classCon;
|
||||
final effectiveDex = stats.dex + equipStats.dexBonus + raceDex + classDex;
|
||||
final effectiveInt = stats.intelligence + equipStats.intBonus + raceInt + classInt;
|
||||
final effectiveWis = stats.wis + equipStats.wisBonus + raceWis + classWis;
|
||||
final effectiveCha = stats.cha + equipStats.chaBonus + raceCha + classCha;
|
||||
|
||||
// 기본 공격력: STR 기반 + 레벨 보정 + 장비 ATK
|
||||
final baseAtk = effectiveStr * 2 + level + equipStats.atk;
|
||||
var baseAtk = effectiveStr * 2 + level + equipStats.atk;
|
||||
|
||||
// 기본 방어력: CON 기반 + 레벨 보정 + 장비 DEF
|
||||
final baseDef = effectiveCon + (level ~/ 2) + equipStats.def;
|
||||
var baseDef = effectiveCon + (level ~/ 2) + equipStats.def;
|
||||
|
||||
// 마법 공격력: INT 기반 + 장비 MAG_ATK
|
||||
final baseMagAtk = effectiveInt * 2 + level + equipStats.magAtk;
|
||||
var 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);
|
||||
// 크리티컬 확률: DEX 기반 + 장비 보너스 (0.05 ~ 0.8)
|
||||
var criRate = 0.05 + effectiveDex * 0.005 + equipStats.criRate;
|
||||
|
||||
// 크리티컬 데미지: 기본 1.5배, DEX에 따라 증가 (최대 3.0)
|
||||
final criDamage = (1.5 + effectiveDex * 0.01).clamp(1.5, 3.0);
|
||||
|
||||
// 회피율: DEX 기반 + 장비 보너스 (0.0 ~ 0.5)
|
||||
final evasion = (effectiveDex * 0.005 + equipStats.evasion).clamp(0.0, 0.5);
|
||||
// 회피율: DEX 기반 + 장비 보너스 (0.0 ~ 0.6)
|
||||
var evasion = effectiveDex * 0.005 + equipStats.evasion;
|
||||
|
||||
// 명중률: DEX 기반 (0.8 ~ 1.0)
|
||||
final accuracy = (0.8 + effectiveDex * 0.002).clamp(0.8, 1.0);
|
||||
@@ -253,8 +275,80 @@ class CombatStats {
|
||||
final attackDelayMs = (1000 / speedModifier).round().clamp(357, 1500);
|
||||
|
||||
// HP/MP: 기본 + 장비 보너스
|
||||
final totalHpMax = stats.hpMax + equipStats.hpBonus;
|
||||
final totalMpMax = stats.mpMax + equipStats.mpBonus;
|
||||
var totalHpMax = stats.hpMax + equipStats.hpBonus;
|
||||
var totalMpMax = stats.mpMax + equipStats.mpBonus;
|
||||
|
||||
// ========================================================================
|
||||
// 종족 패시브 적용 (Phase 5)
|
||||
// ========================================================================
|
||||
|
||||
// HP 보너스 (Heap Troll: +20%)
|
||||
final raceHpBonus = race?.getPassiveValue(PassiveType.hpBonus) ?? 0.0;
|
||||
if (raceHpBonus > 0) {
|
||||
totalHpMax = (totalHpMax * (1 + raceHpBonus)).round();
|
||||
}
|
||||
|
||||
// MP 보너스 (Pointer Fairy: +20%)
|
||||
final raceMpBonus = race?.getPassiveValue(PassiveType.mpBonus) ?? 0.0;
|
||||
if (raceMpBonus > 0) {
|
||||
totalMpMax = (totalMpMax * (1 + raceMpBonus)).round();
|
||||
}
|
||||
|
||||
// 마법 데미지 보너스 (Null Elf: +15%)
|
||||
final raceMagicBonus = race?.getPassiveValue(PassiveType.magicDamageBonus) ?? 0.0;
|
||||
if (raceMagicBonus > 0) {
|
||||
baseMagAtk = (baseMagAtk * (1 + raceMagicBonus)).round();
|
||||
}
|
||||
|
||||
// 방어력 보너스 (Buffer Dwarf: +10%)
|
||||
final raceDefBonus = race?.getPassiveValue(PassiveType.defenseBonus) ?? 0.0;
|
||||
if (raceDefBonus > 0) {
|
||||
baseDef = (baseDef * (1 + raceDefBonus)).round();
|
||||
}
|
||||
|
||||
// 크리티컬 보너스 (Stack Goblin: +5%)
|
||||
final raceCritBonus = race?.getPassiveValue(PassiveType.criticalBonus) ?? 0.0;
|
||||
criRate += raceCritBonus;
|
||||
|
||||
// ========================================================================
|
||||
// 클래스 패시브 적용 (Phase 5)
|
||||
// ========================================================================
|
||||
|
||||
// HP 보너스 (Garbage Collector: +30%)
|
||||
final classHpBonus = klass?.getPassiveValue(ClassPassiveType.hpBonus) ?? 0.0;
|
||||
if (classHpBonus > 0) {
|
||||
totalHpMax = (totalHpMax * (1 + classHpBonus)).round();
|
||||
}
|
||||
|
||||
// 물리 공격력 보너스 (Bug Hunter: +20%)
|
||||
final classPhysBonus = klass?.getPassiveValue(ClassPassiveType.physicalDamageBonus) ?? 0.0;
|
||||
if (classPhysBonus > 0) {
|
||||
baseAtk = (baseAtk * (1 + classPhysBonus)).round();
|
||||
}
|
||||
|
||||
// 방어력 보너스 (Debugger Paladin: +15%)
|
||||
final classDefBonus = klass?.getPassiveValue(ClassPassiveType.defenseBonus) ?? 0.0;
|
||||
if (classDefBonus > 0) {
|
||||
baseDef = (baseDef * (1 + classDefBonus)).round();
|
||||
}
|
||||
|
||||
// 마법 데미지 보너스 (Compiler Mage: +25%)
|
||||
final classMagBonus = klass?.getPassiveValue(ClassPassiveType.magicDamageBonus) ?? 0.0;
|
||||
if (classMagBonus > 0) {
|
||||
baseMagAtk = (baseMagAtk * (1 + classMagBonus)).round();
|
||||
}
|
||||
|
||||
// 회피율 보너스 (Refactor Monk: +15%)
|
||||
final classEvasionBonus = klass?.getPassiveValue(ClassPassiveType.evasionBonus) ?? 0.0;
|
||||
evasion += classEvasionBonus;
|
||||
|
||||
// 크리티컬 보너스 (Pointer Assassin: +20%)
|
||||
final classCritBonus = klass?.getPassiveValue(ClassPassiveType.criticalBonus) ?? 0.0;
|
||||
criRate += classCritBonus;
|
||||
|
||||
// 최종 클램핑
|
||||
criRate = criRate.clamp(0.05, 0.8);
|
||||
evasion = evasion.clamp(0.0, 0.6);
|
||||
|
||||
return CombatStats(
|
||||
str: effectiveStr,
|
||||
@@ -262,7 +356,7 @@ class CombatStats {
|
||||
dex: effectiveDex,
|
||||
intelligence: effectiveInt,
|
||||
wis: effectiveWis,
|
||||
cha: stats.cha + equipStats.chaBonus,
|
||||
cha: effectiveCha,
|
||||
atk: baseAtk,
|
||||
def: baseDef,
|
||||
magAtk: baseMagAtk,
|
||||
|
||||
Reference in New Issue
Block a user