feat(game): 게임 시스템 전면 개편 및 다국어 지원 확장

## 스킬 시스템 개선
- skill_data.dart: 스킬 데이터 구조 전면 개편 (+1176 라인)
- skill_service.dart: 스킬 발동 로직 확장 및 버프 시스템 연동
- skill.dart: 스킬 모델 개선, 쿨다운/효과 타입 추가

## Canvas 애니메이션 리팩토링
- battle_composer.dart 삭제 (레거시 위젯 기반 렌더러)
- monster_colors.dart 삭제 (AsciiCell 색상 시스템으로 통합)
- canvas_battle_composer.dart: z-index 정렬 (몬스터 z=1, 캐릭터 z=2, 이펙트 z=3)
- ascii_cell.dart, ascii_layer.dart: 코드 정리

## UI/UX 개선
- hp_mp_bar.dart: l10n 적용, 몬스터 HP 바 컴팩트화
- death_overlay.dart: 사망 화면 개선
- equipment_stats_panel.dart: 장비 스탯 표시 확장
- active_buff_panel.dart: 버프 패널 개선
- notification_overlay.dart: 알림 시스템 개선

## 다국어 지원 확장
- game_text_l10n.dart: 게임 텍스트 통합 (+758 라인)
- 한국어/일본어/영어/중국어 번역 업데이트
- ARB 파일 동기화

## 게임 로직 개선
- progress_service.dart: 진행 로직 리팩토링
- combat_calculator.dart: 전투 계산 로직 개선
- stat_calculator.dart: 스탯 계산 시스템 개선
- story_service.dart: 스토리 진행 로직 개선

## 기타
- theme_preferences.dart 삭제 (미사용)
- 테스트 파일 업데이트
- class_data.dart: 클래스 데이터 정리
This commit is contained in:
JiWoong Sul
2025-12-22 19:00:58 +09:00
parent f606fca063
commit 99f5b74802
63 changed files with 3403 additions and 2740 deletions

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:askiineverdie/data/game_text_l10n.dart' as l10n;
import 'package:askiineverdie/src/core/l10n/game_data_l10n.dart';
import 'package:askiineverdie/src/core/model/hall_of_fame.dart';
import 'package:askiineverdie/src/core/storage/hall_of_fame_storage.dart';
@@ -36,10 +37,7 @@ class _HallOfFameScreenState extends State<HallOfFameScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Hall of Fame'),
centerTitle: true,
),
appBar: AppBar(title: Text(l10n.uiHallOfFame), centerTitle: true),
body: _isLoading
? const Center(child: CircularProgressIndicator())
: _buildContent(),
@@ -67,19 +65,13 @@ class _HallOfFameScreenState extends State<HallOfFameScreen> {
),
const SizedBox(height: 16),
Text(
'No heroes yet',
style: TextStyle(
fontSize: 20,
color: Colors.grey.shade600,
),
l10n.hofNoHeroes,
style: TextStyle(fontSize: 20, color: Colors.grey.shade600),
),
const SizedBox(height: 8),
Text(
'Defeat the Glitch God to enshrine your legend!',
style: TextStyle(
fontSize: 14,
color: Colors.grey.shade500,
),
l10n.hofDefeatGlitchGod,
style: TextStyle(fontSize: 14, color: Colors.grey.shade500),
textAlign: TextAlign.center,
),
],
@@ -106,22 +98,22 @@ class _HallOfFameScreenState extends State<HallOfFameScreen> {
topRight: Radius.circular(6),
),
),
child: const Row(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.emoji_events, color: Colors.white),
SizedBox(width: 8),
const Icon(Icons.emoji_events, color: Colors.white),
const SizedBox(width: 8),
Text(
'HALL OF FAME',
style: TextStyle(
l10n.uiHallOfFame.toUpperCase(),
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
letterSpacing: 2,
),
),
SizedBox(width: 8),
Icon(Icons.emoji_events, color: Colors.white),
const SizedBox(width: 8),
const Icon(Icons.emoji_events, color: Colors.white),
],
),
),
@@ -132,10 +124,7 @@ class _HallOfFameScreenState extends State<HallOfFameScreen> {
itemCount: hallOfFame.entries.length,
itemBuilder: (context, index) {
final entry = hallOfFame.entries[index];
return _HallOfFameEntryCard(
entry: entry,
rank: index + 1,
);
return _HallOfFameEntryCard(entry: entry, rank: index + 1);
},
),
),
@@ -147,10 +136,7 @@ class _HallOfFameScreenState extends State<HallOfFameScreen> {
/// 명예의 전당 엔트리 카드
class _HallOfFameEntryCard extends StatelessWidget {
const _HallOfFameEntryCard({
required this.entry,
required this.rank,
});
const _HallOfFameEntryCard({required this.entry, required this.rank});
final HallOfFameEntry entry;
final int rank;
@@ -217,7 +203,7 @@ class _HallOfFameEntryCard extends StatelessWidget {
borderRadius: BorderRadius.circular(4),
),
child: Text(
'Lv.${entry.level}',
l10n.uiLevel(entry.level),
style: TextStyle(
color: Colors.blue.shade800,
fontWeight: FontWeight.bold,
@@ -232,10 +218,7 @@ class _HallOfFameEntryCard extends StatelessWidget {
Text(
'${GameDataL10n.getRaceName(context, entry.race)} '
'${GameDataL10n.getKlassName(context, entry.klass)}',
style: TextStyle(
fontSize: 13,
color: Colors.grey.shade700,
),
style: TextStyle(fontSize: 13, color: Colors.grey.shade700),
),
const SizedBox(height: 4),
// 통계
@@ -267,14 +250,15 @@ class _HallOfFameEntryCard extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Icon(Icons.calendar_today, size: 14, color: Colors.grey.shade500),
Icon(
Icons.calendar_today,
size: 14,
color: Colors.grey.shade500,
),
const SizedBox(height: 4),
Text(
entry.formattedClearedDate,
style: TextStyle(
fontSize: 11,
color: Colors.grey.shade600,
),
style: TextStyle(fontSize: 11, color: Colors.grey.shade600),
),
],
),
@@ -362,22 +346,22 @@ class _GameClearDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Row(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.emoji_events, color: Colors.amber, size: 32),
SizedBox(width: 8),
Text('VICTORY!'),
SizedBox(width: 8),
Icon(Icons.emoji_events, color: Colors.amber, size: 32),
const Icon(Icons.emoji_events, color: Colors.amber, size: 32),
const SizedBox(width: 8),
Text(l10n.hofVictory),
const SizedBox(width: 8),
const Icon(Icons.emoji_events, color: Colors.amber, size: 32),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'You have defeated the Glitch God!',
style: TextStyle(fontSize: 16),
Text(
l10n.hofDefeatedGlitchGod,
style: const TextStyle(fontSize: 16),
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
@@ -386,14 +370,11 @@ class _GameClearDialog extends StatelessWidget {
// 캐릭터 정보
Text(
'"${entry.characterName}"',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 4),
Text(
'${entry.race} ${entry.klass}',
'${GameDataL10n.getRaceName(context, entry.race)} ${GameDataL10n.getKlassName(context, entry.klass)}',
style: TextStyle(color: Colors.grey.shade600),
),
const SizedBox(height: 16),
@@ -401,16 +382,16 @@ class _GameClearDialog extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildStat('Level', '${entry.level}'),
_buildStat('Time', entry.formattedPlayTime),
_buildStat('Deaths', '${entry.totalDeaths}'),
_buildStat('Quests', '${entry.questsCompleted}'),
_buildStat(l10n.hofLevel, '${entry.level}'),
_buildStat(l10n.hofTime, entry.formattedPlayTime),
_buildStat(l10n.hofDeaths, '${entry.totalDeaths}'),
_buildStat(l10n.hofQuests, '${entry.questsCompleted}'),
],
),
const SizedBox(height: 16),
const Text(
'Your legend has been enshrined in the Hall of Fame!',
style: TextStyle(
Text(
l10n.hofLegendEnshrined,
style: const TextStyle(
fontStyle: FontStyle.italic,
color: Colors.amber,
),
@@ -424,14 +405,14 @@ class _GameClearDialog extends StatelessWidget {
Navigator.of(context).pop();
onViewHallOfFame();
},
child: const Text('View Hall of Fame'),
child: Text(l10n.hofViewHallOfFame),
),
FilledButton(
onPressed: () {
Navigator.of(context).pop();
onNewGame();
},
child: const Text('New Game'),
child: Text(l10n.hofNewGame),
),
],
);
@@ -442,17 +423,11 @@ class _GameClearDialog extends StatelessWidget {
children: [
Text(
value,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
Text(
label,
style: TextStyle(
fontSize: 11,
color: Colors.grey.shade600,
),
style: TextStyle(fontSize: 11, color: Colors.grey.shade600),
),
],
);