feat: 초기 커밋

- Progress Quest 6.4 Flutter 포팅 프로젝트
- 게임 루프, 상태 관리, UI 구현
- 캐릭터 생성, 인벤토리, 장비, 주문 시스템
- 시장/판매/구매 메커니즘
This commit is contained in:
JiWoong Sul
2025-12-09 17:24:04 +09:00
commit 08054d97c1
168 changed files with 12876 additions and 0 deletions

145
lib/src/app.dart Normal file
View File

@@ -0,0 +1,145 @@
import 'package:flutter/material.dart';
import 'package:askiineverdie/src/core/engine/game_mutations.dart';
import 'package:askiineverdie/src/core/engine/progress_service.dart';
import 'package:askiineverdie/src/core/engine/reward_service.dart';
import 'package:askiineverdie/src/core/model/game_state.dart';
import 'package:askiineverdie/src/core/model/pq_config.dart';
import 'package:askiineverdie/src/core/storage/save_manager.dart';
import 'package:askiineverdie/src/core/storage/save_repository.dart';
import 'package:askiineverdie/src/features/front/front_screen.dart';
import 'package:askiineverdie/src/features/front/save_picker_dialog.dart';
import 'package:askiineverdie/src/features/game/game_play_screen.dart';
import 'package:askiineverdie/src/features/game/game_session_controller.dart';
import 'package:askiineverdie/src/features/new_character/new_character_screen.dart';
class AskiiNeverDieApp extends StatefulWidget {
const AskiiNeverDieApp({super.key});
@override
State<AskiiNeverDieApp> createState() => _AskiiNeverDieAppState();
}
class _AskiiNeverDieAppState extends State<AskiiNeverDieApp> {
late final GameSessionController _controller;
@override
void initState() {
super.initState();
const config = PqConfig();
final mutations = GameMutations(config);
final rewards = RewardService(mutations);
_controller = GameSessionController(
progressService: ProgressService(
config: config,
mutations: mutations,
rewards: rewards,
),
saveManager: SaveManager(SaveRepository()),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Ascii Never Die',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF234361)),
scaffoldBackgroundColor: const Color(0xFFF4F5F7),
useMaterial3: true,
),
home: FrontScreen(
onNewCharacter: _navigateToNewCharacter,
onLoadSave: _loadSave,
),
);
}
void _navigateToNewCharacter(BuildContext context) {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context) => NewCharacterScreen(
onCharacterCreated: (initialState) {
_startGame(context, initialState);
},
),
),
);
}
Future<void> _loadSave(BuildContext context) async {
// 저장 파일 목록 조회
final saves = await _controller.saveManager.listSaves();
if (!context.mounted) return;
String? selectedFileName;
if (saves.isEmpty) {
// 저장 파일이 없으면 안내 메시지
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('저장된 게임이 없습니다.')));
return;
} else if (saves.length == 1) {
// 파일이 하나면 바로 선택
selectedFileName = saves.first.fileName;
} else {
// 여러 개면 다이얼로그 표시
selectedFileName = await SavePickerDialog.show(context, saves);
}
if (selectedFileName == null || !context.mounted) return;
// 선택된 파일 로드
await _controller.loadAndStart(
fileName: selectedFileName,
cheatsEnabled: false,
);
if (_controller.status == GameSessionStatus.running) {
if (context.mounted) {
_navigateToGame(context);
}
} else if (_controller.status == GameSessionStatus.error) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'저장 파일을 불러올 수 없습니다: ${_controller.error ?? "알 수 없는 오류"}',
),
),
);
}
}
}
Future<void> _startGame(BuildContext context, GameState initialState) async {
await _controller.startNew(initialState, cheatsEnabled: false);
if (context.mounted) {
// NewCharacterScreen을 pop하고 GamePlayScreen으로 이동
Navigator.of(context).pushReplacement(
MaterialPageRoute<void>(
builder: (context) => GamePlayScreen(controller: _controller),
),
);
}
}
void _navigateToGame(BuildContext context) {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context) => GamePlayScreen(controller: _controller),
),
);
}
}