feat(debug): 모바일 레이아웃에 치트 기능 추가
- MobileCarouselLayout에 치트 버튼 추가 - GameSessionController에 치트 활성화 상태 관리 추가 - ProgressLoop/ProgressService에 치트 메서드 추가
This commit is contained in:
@@ -844,6 +844,11 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
||||
// 통계 및 도움말
|
||||
onShowStatistics: () => _showStatisticsDialog(context),
|
||||
onShowHelp: () => HelpDialog.show(context),
|
||||
// 치트 (디버그 모드)
|
||||
cheatsEnabled: widget.controller.cheatsEnabled,
|
||||
onCheatTask: () => widget.controller.loop?.cheatCompleteTask(),
|
||||
onCheatQuest: () => widget.controller.loop?.cheatCompleteQuest(),
|
||||
onCheatPlot: () => widget.controller.loop?.cheatCompletePlot(),
|
||||
),
|
||||
// 사망 오버레이
|
||||
if (state.isDead && state.deathInfo != null)
|
||||
|
||||
@@ -6,12 +6,13 @@ import 'package:asciineverdie/src/core/engine/resurrection_service.dart';
|
||||
import 'package:asciineverdie/src/core/engine/shop_service.dart';
|
||||
import 'package:asciineverdie/src/core/model/game_state.dart';
|
||||
import 'package:asciineverdie/src/core/model/game_statistics.dart';
|
||||
import 'package:asciineverdie/src/core/model/hall_of_fame.dart';
|
||||
import 'package:asciineverdie/src/core/storage/hall_of_fame_storage.dart';
|
||||
import 'package:asciineverdie/src/core/storage/save_manager.dart';
|
||||
import 'package:asciineverdie/src/core/storage/statistics_storage.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
enum GameSessionStatus { idle, loading, running, error, dead }
|
||||
enum GameSessionStatus { idle, loading, running, error, dead, complete }
|
||||
|
||||
/// Presentation-friendly wrapper that owns ProgressLoop and SaveManager.
|
||||
class GameSessionController extends ChangeNotifier {
|
||||
@@ -104,6 +105,7 @@ class GameSessionController extends ChangeNotifier {
|
||||
now: _now,
|
||||
cheatsEnabled: cheatsEnabled,
|
||||
onPlayerDied: _onPlayerDied,
|
||||
onGameComplete: _onGameComplete,
|
||||
availableSpeeds: availableSpeeds,
|
||||
);
|
||||
|
||||
@@ -272,6 +274,31 @@ class GameSessionController extends ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// 게임 클리어 콜백 (ProgressLoop에서 호출, Act V 완료 시)
|
||||
void _onGameComplete() {
|
||||
_status = GameSessionStatus.complete;
|
||||
notifyListeners();
|
||||
|
||||
// Hall of Fame 등록 (비동기)
|
||||
unawaited(_registerToHallOfFame());
|
||||
}
|
||||
|
||||
/// 명예의 전당 등록
|
||||
Future<void> _registerToHallOfFame() async {
|
||||
if (_state == null) return;
|
||||
|
||||
final entry = HallOfFameEntry.fromGameState(
|
||||
state: _state!,
|
||||
totalDeaths: _sessionStats.deathCount,
|
||||
monstersKilled: _state!.progress.monstersKilled,
|
||||
);
|
||||
|
||||
await _hallOfFameStorage.addEntry(entry);
|
||||
|
||||
// 통계 기록
|
||||
await _statisticsStorage.recordGameComplete();
|
||||
}
|
||||
|
||||
/// 플레이어 부활 처리 (상태만 업데이트, 게임 재개는 별도로)
|
||||
///
|
||||
/// HP/MP 회복, 빈 슬롯에 장비 자동 구매
|
||||
@@ -308,4 +335,7 @@ class GameSessionController extends ChangeNotifier {
|
||||
/// 사망 상태 여부
|
||||
bool get isDead =>
|
||||
_status == GameSessionStatus.dead || (_state?.isDead ?? false);
|
||||
|
||||
/// 게임 클리어 여부
|
||||
bool get isComplete => _status == GameSessionStatus.complete;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,10 @@ class MobileCarouselLayout extends StatefulWidget {
|
||||
this.onSfxVolumeChange,
|
||||
this.onShowStatistics,
|
||||
this.onShowHelp,
|
||||
this.cheatsEnabled = false,
|
||||
this.onCheatTask,
|
||||
this.onCheatQuest,
|
||||
this.onCheatPlot,
|
||||
});
|
||||
|
||||
final GameState state;
|
||||
@@ -81,6 +85,18 @@ class MobileCarouselLayout extends StatefulWidget {
|
||||
/// 도움말 표시 콜백
|
||||
final VoidCallback? onShowHelp;
|
||||
|
||||
/// 치트 모드 활성화 여부
|
||||
final bool cheatsEnabled;
|
||||
|
||||
/// 치트: 태스크 완료
|
||||
final VoidCallback? onCheatTask;
|
||||
|
||||
/// 치트: 퀘스트 완료
|
||||
final VoidCallback? onCheatQuest;
|
||||
|
||||
/// 치트: 액트(플롯) 완료
|
||||
final VoidCallback? onCheatPlot;
|
||||
|
||||
@override
|
||||
State<MobileCarouselLayout> createState() => _MobileCarouselLayoutState();
|
||||
}
|
||||
@@ -547,6 +563,52 @@ class _MobileCarouselLayoutState extends State<MobileCarouselLayout> {
|
||||
},
|
||||
),
|
||||
|
||||
// 치트 섹션 (디버그 모드에서만 표시)
|
||||
if (widget.cheatsEnabled) ...[
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
child: Text(
|
||||
'DEBUG CHEATS',
|
||||
style: TextStyle(
|
||||
fontFamily: 'PressStart2P',
|
||||
fontSize: 8,
|
||||
color: Colors.red.shade300,
|
||||
),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.fast_forward, color: Colors.red),
|
||||
title: const Text('Skip Task (L+1)'),
|
||||
subtitle: const Text('태스크 즉시 완료'),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
widget.onCheatTask?.call();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.skip_next, color: Colors.red),
|
||||
title: const Text('Skip Quest (Q!)'),
|
||||
subtitle: const Text('퀘스트 즉시 완료'),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
widget.onCheatQuest?.call();
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.double_arrow, color: Colors.red),
|
||||
title: const Text('Skip Act (P!)'),
|
||||
subtitle: const Text('액트 즉시 완료 (명예의 전당 테스트용)'),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
widget.onCheatPlot?.call();
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user