feat(hall-of-fame): 명예의 전당 상세 UI 및 전투 스탯 저장 추가

- CombatStats에 toJson/fromJson 직렬화 메서드 추가
- HallOfFameEntry에 finalStats(CombatStats) 필드 추가
- 명예의 전당 상세 다이얼로그에서 전투 스탯, 장비, 스펠 표시
- GameState에 combatStats 접근자 추가
- game_text_l10n에 명예의 전당 관련 텍스트 추가
This commit is contained in:
JiWoong Sul
2025-12-24 17:20:52 +09:00
parent c1db1fd5d3
commit df5fdbaac2
8 changed files with 296 additions and 35 deletions

View File

@@ -287,8 +287,11 @@ class ProgressService {
progress = progress.copyWith(currentCombat: combatForReset);
}
// 전투 상태 초기화 및 물약 사용 기록 초기화
progress = progress.copyWith(currentCombat: null);
// 전투 상태 초기화, 몬스터 처치 수 증가 및 물약 사용 기록 초기화
progress = progress.copyWith(
currentCombat: null,
monstersKilled: progress.monstersKilled + 1,
);
final resetPotionInventory = nextState.potionInventory.resetBattleUsage();
nextState = nextState.copyWith(
progress: progress,
@@ -1331,8 +1334,11 @@ class ProgressService {
lastCombatEvents: lastCombatEvents,
);
// 전투 상태 초기화
final progress = state.progress.copyWith(currentCombat: null);
// 전투 상태 초기화 및 사망 횟수 증가
final progress = state.progress.copyWith(
currentCombat: null,
deathCount: state.progress.deathCount + 1,
);
return state.copyWith(
equipment: emptyEquipment,

View File

@@ -391,6 +391,60 @@ class CombatStats {
);
}
/// JSON으로 직렬화
Map<String, dynamic> toJson() {
return {
'str': str,
'con': con,
'dex': dex,
'intelligence': intelligence,
'wis': wis,
'cha': cha,
'atk': atk,
'def': def,
'magAtk': magAtk,
'magDef': magDef,
'criRate': criRate,
'criDamage': criDamage,
'evasion': evasion,
'accuracy': accuracy,
'blockRate': blockRate,
'parryRate': parryRate,
'attackDelayMs': attackDelayMs,
'hpMax': hpMax,
'hpCurrent': hpCurrent,
'mpMax': mpMax,
'mpCurrent': mpCurrent,
};
}
/// JSON에서 역직렬화
factory CombatStats.fromJson(Map<String, dynamic> json) {
return CombatStats(
str: json['str'] as int,
con: json['con'] as int,
dex: json['dex'] as int,
intelligence: json['intelligence'] as int,
wis: json['wis'] as int,
cha: json['cha'] as int,
atk: json['atk'] as int,
def: json['def'] as int,
magAtk: json['magAtk'] as int,
magDef: json['magDef'] as int,
criRate: (json['criRate'] as num).toDouble(),
criDamage: (json['criDamage'] as num).toDouble(),
evasion: (json['evasion'] as num).toDouble(),
accuracy: (json['accuracy'] as num).toDouble(),
blockRate: (json['blockRate'] as num).toDouble(),
parryRate: (json['parryRate'] as num).toDouble(),
attackDelayMs: json['attackDelayMs'] as int,
hpMax: json['hpMax'] as int,
hpCurrent: json['hpCurrent'] as int,
mpMax: json['mpMax'] as int,
mpCurrent: json['mpCurrent'] as int,
);
}
/// 테스트/디버그용 기본값
factory CombatStats.empty() => const CombatStats(
str: 10,

View File

@@ -741,6 +741,8 @@ class ProgressState {
this.questHistory = const [],
this.currentQuestMonster,
this.currentCombat,
this.monstersKilled = 0,
this.deathCount = 0,
});
final ProgressBarState task;
@@ -764,6 +766,12 @@ class ProgressState {
/// 현재 전투 상태 (킬 태스크 진행 중)
final CombatState? currentCombat;
/// 처치한 몬스터 수
final int monstersKilled;
/// 사망 횟수
final int deathCount;
factory ProgressState.empty() => ProgressState(
task: ProgressBarState.empty(),
quest: ProgressBarState.empty(),
@@ -792,6 +800,8 @@ class ProgressState {
List<HistoryEntry>? questHistory,
QuestMonsterInfo? currentQuestMonster,
CombatState? currentCombat,
int? monstersKilled,
int? deathCount,
}) {
return ProgressState(
task: task ?? this.task,
@@ -806,6 +816,8 @@ class ProgressState {
questHistory: questHistory ?? this.questHistory,
currentQuestMonster: currentQuestMonster ?? this.currentQuestMonster,
currentCombat: currentCombat ?? this.currentCombat,
monstersKilled: monstersKilled ?? this.monstersKilled,
deathCount: deathCount ?? this.deathCount,
);
}
}

View File

@@ -130,6 +130,7 @@ class HallOfFameEntry {
'monstersKilled': monstersKilled,
'questsCompleted': questsCompleted,
'clearedAt': clearedAt.toIso8601String(),
'finalStats': finalStats?.toJson(),
'finalEquipment': finalEquipment,
'finalSpells': finalSpells,
};
@@ -148,6 +149,9 @@ class HallOfFameEntry {
monstersKilled: json['monstersKilled'] as int? ?? 0,
questsCompleted: json['questsCompleted'] as int? ?? 0,
clearedAt: DateTime.parse(json['clearedAt'] as String),
finalStats: json['finalStats'] != null
? CombatStats.fromJson(json['finalStats'] as Map<String, dynamic>)
: null,
finalEquipment: json['finalEquipment'] != null
? Map<String, String>.from(json['finalEquipment'] as Map)
: null,

View File

@@ -117,6 +117,8 @@ class GameSave {
'index': progress.currentQuestMonster!.monsterIndex,
}
: null,
'monstersKilled': progress.monstersKilled,
'deathCount': progress.deathCount,
},
'queue': queue.entries
.map(
@@ -225,6 +227,8 @@ class GameSave {
currentQuestMonster: _questMonsterFromJson(
progressJson['questMonster'] as Map<String, dynamic>?,
),
monstersKilled: progressJson['monstersKilled'] as int? ?? 0,
deathCount: progressJson['deathCount'] as int? ?? 0,
),
queue: QueueState(
entries: Queue<QueueEntry>.from(