diff --git a/lib/data/game_text_l10n.dart b/lib/data/game_text_l10n.dart index 55d90e1..1a480ac 100644 --- a/lib/data/game_text_l10n.dart +++ b/lib/data/game_text_l10n.dart @@ -103,6 +103,12 @@ String taskDebugging(String monsterName) { return 'Debugging $monsterName'; } +String taskFinalBoss(String bossName) { + if (isKoreanLocale) return '최종 보스와 대결: $bossName'; + if (isJapaneseLocale) return '最終ボスと対決: $bossName'; + return 'Final Battle: $bossName'; +} + String taskSelling(String itemDescription) { if (isKoreanLocale) return '$itemDescription 판매 중'; if (isJapaneseLocale) return '$itemDescription を販売中'; diff --git a/lib/src/core/engine/progress_service.dart b/lib/src/core/engine/progress_service.dart index 4b2bce0..daec89b 100644 --- a/lib/src/core/engine/progress_service.dart +++ b/lib/src/core/engine/progress_service.dart @@ -302,6 +302,27 @@ class ProgressService { progress: progress, potionInventory: resetPotionInventory, ); + + // 최종 보스 처치 체크 + if (progress.finalBossState == FinalBossState.fighting) { + // 글리치 갓 처치 완료 - 게임 클리어 + progress = progress.copyWith( + finalBossState: FinalBossState.defeated, + ); + nextState = nextState.copyWith(progress: progress); + + // completeAct를 호출하여 게임 완료 처리 + final actResult = completeAct(nextState); + nextState = actResult.state; + + return ProgressTickResult( + state: nextState, + leveledUp: false, + completedQuest: false, + completedAct: true, + gameComplete: true, + ); + } } // 시장/판매/구매 태스크 완료 시 처리 (원본 Main.pas:631-649) @@ -494,7 +515,13 @@ class ProgressService { return (progress: progress, queue: queue); } - // 3. MonsterTask 실행 (원본 678-684줄) + // 3. 최종 보스 전투 체크 + // finalBossState == fighting이면 Glitch God 스폰 + if (state.progress.finalBossState == FinalBossState.fighting) { + return _startFinalBossFight(state, progress, queue); + } + + // 4. MonsterTask 실행 (원본 678-684줄) final level = state.traits.level; // 원본 Main.pas:548-551: 25% 확률로 Quest Monster 사용 @@ -567,6 +594,61 @@ class ProgressService { return (progress: progress, queue: queue); } + /// 최종 보스(Glitch God) 전투 시작 + /// + /// Act V 플롯 완료 후 호출되며, 글리치 갓과의 전투를 설정합니다. + ({ProgressState progress, QueueState queue}) _startFinalBossFight( + GameState state, + ProgressState progress, + QueueState queue, + ) { + final level = state.traits.level; + + // 플레이어 전투 스탯 생성 + final playerCombatStats = CombatStats.fromStats( + stats: state.stats, + equipment: state.equipment, + level: level, + ); + + // Glitch God 생성 (레벨 100 최종 보스) + final glitchGod = MonsterCombatStats.glitchGod(); + + // 전투 상태 초기화 + final combatState = CombatState.start( + playerStats: playerCombatStats, + monsterStats: glitchGod, + ); + + // 전투 시간 추정 (보스 전투는 더 길게) + final combatCalculator = CombatCalculator(rng: state.rng); + final baseDuration = combatCalculator.estimateCombatDurationMs( + player: playerCombatStats, + monster: glitchGod, + ); + // 최종 보스는 최소 10초, 최대 60초 + final durationMillis = baseDuration.clamp(10000, 60000); + + final taskResult = pq_logic.startTask( + progress, + l10n.taskFinalBoss(glitchGod.name), + durationMillis, + ); + + final updatedProgress = taskResult.progress.copyWith( + currentTask: TaskInfo( + caption: taskResult.caption, + type: TaskType.kill, + monsterBaseName: 'Glitch God', + monsterPart: '*', // 특수 전리품 + monsterLevel: glitchGod.level, + ), + currentCombat: combatState, + ); + + return (progress: updatedProgress, queue: queue); + } + /// Advances quest completion, applies reward, and enqueues next quest task. GameState completeQuest(GameState state) { final result = pq_logic.completeQuest( @@ -625,28 +707,45 @@ class ProgressService { } /// Advances plot to next act and applies any act-level rewards. - /// Returns gameComplete=true if Act V was completed (game ends). + /// Returns gameComplete=true if Final Boss was defeated (game ends). ({GameState state, bool gameComplete}) completeAct(GameState state) { - // Act V 완료 시 (plotStageCount == 6) 게임 클리어 + // Act V 완료 시 (plotStageCount == 6) → 최종 보스 전투 시작 // plotStageCount: 1=Prologue, 2=Act I, 3=Act II, 4=Act III, 5=Act IV, 6=Act V if (state.progress.plotStageCount >= 6) { - // Act V 완료 - 게임 클리어! - // 히스토리만 업데이트하고 새 Act는 생성하지 않음 - final updatedPlotHistory = [ - ...state.progress.plotHistory.map( - (e) => e.isComplete ? e : e.copyWith(isComplete: true), - ), - const HistoryEntry(caption: '*** THE END ***', isComplete: true), - ]; + // 이미 최종 보스가 처치되었으면 게임 클리어 + if (state.progress.finalBossState == FinalBossState.defeated) { + final updatedPlotHistory = [ + ...state.progress.plotHistory.map( + (e) => e.isComplete ? e : e.copyWith(isComplete: true), + ), + const HistoryEntry(caption: '*** THE END ***', isComplete: true), + ]; - final updatedProgress = state.progress.copyWith( - plotHistory: updatedPlotHistory, - ); + final updatedProgress = state.progress.copyWith( + plotHistory: updatedPlotHistory, + ); - return ( - state: state.copyWith(progress: updatedProgress), - gameComplete: true, - ); + return ( + state: state.copyWith(progress: updatedProgress), + gameComplete: true, + ); + } + + // 최종 보스가 아직 등장하지 않았으면 보스 전투 시작 + if (state.progress.finalBossState == FinalBossState.notSpawned) { + final updatedProgress = state.progress.copyWith( + finalBossState: FinalBossState.fighting, + ); + + // 게임은 아직 끝나지 않음 - 보스 전투 진행 + return ( + state: state.copyWith(progress: updatedProgress), + gameComplete: false, + ); + } + + // 보스 전투 중이면 계속 진행 (게임 종료 안 함) + return (state: state, gameComplete: false); } final actResult = pq_logic.completeAct(state.progress.plotStageCount); diff --git a/lib/src/core/model/game_state.dart b/lib/src/core/model/game_state.dart index 09ee8ff..bc3c754 100644 --- a/lib/src/core/model/game_state.dart +++ b/lib/src/core/model/game_state.dart @@ -727,6 +727,18 @@ class QuestMonsterInfo { static const empty = QuestMonsterInfo(monsterData: '', monsterIndex: -1); } +/// 최종 보스 상태 (Final Boss State) +enum FinalBossState { + /// 최종 보스 등장 전 + notSpawned, + + /// 최종 보스 전투 중 + fighting, + + /// 최종 보스 처치 완료 + defeated, +} + class ProgressState { const ProgressState({ required this.task, @@ -743,6 +755,7 @@ class ProgressState { this.currentCombat, this.monstersKilled = 0, this.deathCount = 0, + this.finalBossState = FinalBossState.notSpawned, }); final ProgressBarState task; @@ -772,6 +785,9 @@ class ProgressState { /// 사망 횟수 final int deathCount; + /// 최종 보스 상태 (Act V) + final FinalBossState finalBossState; + factory ProgressState.empty() => ProgressState( task: ProgressBarState.empty(), quest: ProgressBarState.empty(), @@ -802,6 +818,7 @@ class ProgressState { CombatState? currentCombat, int? monstersKilled, int? deathCount, + FinalBossState? finalBossState, }) { return ProgressState( task: task ?? this.task, @@ -818,6 +835,7 @@ class ProgressState { currentCombat: currentCombat ?? this.currentCombat, monstersKilled: monstersKilled ?? this.monstersKilled, deathCount: deathCount ?? this.deathCount, + finalBossState: finalBossState ?? this.finalBossState, ); } } diff --git a/lib/src/core/model/monster_combat_stats.dart b/lib/src/core/model/monster_combat_stats.dart index 4dc606d..8eef0d6 100644 --- a/lib/src/core/model/monster_combat_stats.dart +++ b/lib/src/core/model/monster_combat_stats.dart @@ -174,6 +174,30 @@ class MonsterCombatStats { ); } + /// 최종 보스 (Glitch God) 생성 + /// + /// Act V 완료 시 등장하는 최종 보스. + /// balance_constants.dart의 BossStats.glitchGod 기반. + factory MonsterCombatStats.glitchGod() { + const bossLevel = 100; + final bossStats = BossStats.glitchGod(bossLevel); + + return MonsterCombatStats( + name: 'The Primordial Glitch', + level: bossLevel, + atk: bossStats.atk, + def: bossStats.def, + hpMax: bossStats.hp, + hpCurrent: bossStats.hp, + criRate: 0.25, // 보스 크리티컬 확률 25% + criDamage: 2.0, // 보스 크리티컬 데미지 200% + evasion: 0.15, // 보스 회피율 15% + accuracy: 0.95, // 보스 명중률 95% + attackDelayMs: 800, // 보스 공격 속도 (빠름) + expReward: bossStats.exp, + ); + } + /// 몬스터 이름에서 속도 타입 추론 /// /// 특정 키워드 기반으로 속도 결정 (향후 확장 가능)