feat(hall-of-fame): 명예의 전당 상세 보기 및 스펠북 기록 추가
- HallOfFameEntry에 finalSpells 필드 추가 (스펠 이름 + 랭크) - 명예의 전당 카드 클릭 시 상세 정보 다이얼로그 표시 - 디버그 모드에서 샘플 엔트리 자동 생성 (테스트용) - pq_logic 및 progress 관련 minor 수정
This commit is contained in:
@@ -65,14 +65,14 @@ class ProgressLoop {
|
||||
Stream<GameState> get stream => _stateController.stream;
|
||||
GameState _state;
|
||||
|
||||
/// 현재 배속 (1x, 2x, 5x)
|
||||
/// 현재 배속 (1x, 3x, 10x)
|
||||
int get speedMultiplier => _speedMultiplier;
|
||||
|
||||
/// 배속 순환: 1 -> 2 -> 5 -> 1
|
||||
/// 배속 순환: 1 -> 3 -> 10 -> 1
|
||||
void cycleSpeed() {
|
||||
_speedMultiplier = switch (_speedMultiplier) {
|
||||
1 => 2,
|
||||
2 => 5,
|
||||
1 => 3,
|
||||
3 => 10,
|
||||
_ => 1,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -100,8 +100,8 @@ class ProgressService {
|
||||
// ExpBar 초기화 (원본 743-746줄)
|
||||
final expBar = ProgressBarState(position: 0, max: pq_logic.levelUpTime(1));
|
||||
|
||||
// PlotBar 초기화 (원본 759줄)
|
||||
final plotBar = const ProgressBarState(position: 0, max: 26 * 1000);
|
||||
// PlotBar 초기화 - Prologue 5분 (300초)
|
||||
final plotBar = const ProgressBarState(position: 0, max: 300);
|
||||
|
||||
final progress = taskResult.progress.copyWith(
|
||||
exp: expBar,
|
||||
|
||||
@@ -18,6 +18,7 @@ class HallOfFameEntry {
|
||||
required this.clearedAt,
|
||||
this.finalStats,
|
||||
this.finalEquipment,
|
||||
this.finalSpells,
|
||||
});
|
||||
|
||||
/// 고유 ID (UUID)
|
||||
@@ -56,6 +57,9 @@ class HallOfFameEntry {
|
||||
/// 최종 장비 목록 (향후 아스키 아레나용)
|
||||
final Map<String, String>? finalEquipment;
|
||||
|
||||
/// 최종 스펠북 (스펠 이름 + 랭크)
|
||||
final List<Map<String, String>>? finalSpells;
|
||||
|
||||
/// 플레이 시간을 Duration으로 변환
|
||||
Duration get totalPlayTime => Duration(milliseconds: totalPlayTimeMs);
|
||||
|
||||
@@ -107,6 +111,9 @@ class HallOfFameEntry {
|
||||
'greaves': state.equipment.greaves,
|
||||
'sollerets': state.equipment.sollerets,
|
||||
},
|
||||
finalSpells: state.spellBook.spells
|
||||
.map((s) => {'name': s.name, 'rank': s.rank})
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -124,6 +131,7 @@ class HallOfFameEntry {
|
||||
'questsCompleted': questsCompleted,
|
||||
'clearedAt': clearedAt.toIso8601String(),
|
||||
'finalEquipment': finalEquipment,
|
||||
'finalSpells': finalSpells,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -143,6 +151,11 @@ class HallOfFameEntry {
|
||||
finalEquipment: json['finalEquipment'] != null
|
||||
? Map<String, String>.from(json['finalEquipment'] as Map)
|
||||
: null,
|
||||
finalSpells: json['finalSpells'] != null
|
||||
? (json['finalSpells'] as List<dynamic>)
|
||||
.map((s) => Map<String, String>.from(s as Map))
|
||||
.toList()
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,9 +70,10 @@ class ItemResult {
|
||||
}
|
||||
|
||||
int levelUpTimeSeconds(int level) {
|
||||
// ~20 minutes for level 1, then exponential growth (same as LevelUpTime in Main.pas).
|
||||
final seconds = (20.0 + math.pow(1.15, level)) * 60.0;
|
||||
return seconds.round();
|
||||
// 10시간 내 레벨 100 도달 목표 (선형 성장)
|
||||
// 레벨 1: ~2분, 레벨 100: ~7분
|
||||
final seconds = 120 + (level * 3);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
/// 초 단위 시간을 사람이 읽기 쉬운 형태로 변환 (원본 Main.pas:1265-1271)
|
||||
@@ -736,10 +737,22 @@ class ActResult {
|
||||
final List<RewardKind> rewards;
|
||||
}
|
||||
|
||||
/// Act별 Plot Bar 최대값 (초) - 10시간 완주 목표
|
||||
const _actPlotBarSeconds = [
|
||||
300, // Prologue: 5분
|
||||
7200, // Act I: 2시간
|
||||
10800, // Act II: 3시간
|
||||
10800, // Act III: 3시간
|
||||
5400, // Act IV: 1.5시간
|
||||
1800, // Act V: 30분
|
||||
];
|
||||
|
||||
ActResult completeAct(int existingActCount) {
|
||||
final nextActIndex = existingActCount;
|
||||
final title = l10n.actTitle(intToRoman(nextActIndex));
|
||||
final plotBarMax = 60 * 60 * (1 + 5 * existingActCount);
|
||||
final plotBarMax = existingActCount < _actPlotBarSeconds.length
|
||||
? _actPlotBarSeconds[existingActCount]
|
||||
: 3600;
|
||||
|
||||
final rewards = <RewardKind>[];
|
||||
if (existingActCount > 1) {
|
||||
|
||||
Reference in New Issue
Block a user