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

@@ -16,10 +16,7 @@ class ClassData {
static const bugHunter = ClassTraits(
classId: 'bug_hunter',
name: 'Bug Hunter',
statModifiers: {
StatType.str: 2,
StatType.intelligence: 1,
},
statModifiers: {StatType.str: 2, StatType.intelligence: 1},
startingSkills: ['power_strike'],
classSkills: ['power_strike', 'execute', 'bug_smash'],
passives: [
@@ -36,10 +33,7 @@ class ClassData {
static const overflowWarrior = ClassTraits(
classId: 'overflow_warrior',
name: 'Overflow Warrior',
statModifiers: {
StatType.str: 2,
StatType.con: 1,
},
statModifiers: {StatType.str: 2, StatType.con: 1},
startingSkills: ['power_strike'],
classSkills: ['power_strike', 'overflow_slash', 'buffer_break'],
passives: [
@@ -56,10 +50,7 @@ class ClassData {
static const stackCrusher = ClassTraits(
classId: 'stack_crusher',
name: 'Stack Crusher',
statModifiers: {
StatType.str: 2,
StatType.con: 1,
},
statModifiers: {StatType.str: 2, StatType.con: 1},
startingSkills: ['power_strike'],
classSkills: ['power_strike', 'stack_smash', 'heap_slam'],
passives: [
@@ -81,10 +72,7 @@ class ClassData {
static const assertionKnight = ClassTraits(
classId: 'assertion_knight',
name: 'Assertion Knight',
statModifiers: {
StatType.str: 2,
StatType.wis: 1,
},
statModifiers: {StatType.str: 2, StatType.wis: 1},
startingSkills: ['shield_bash'],
classSkills: ['shield_bash', 'assert_strike', 'validation_guard'],
passives: [
@@ -94,9 +82,7 @@ class ClassData {
description: '방어력 +10%',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.heavy,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.heavy),
);
// ==========================================================================
@@ -107,10 +93,7 @@ class ClassData {
static const debuggerPaladin = ClassTraits(
classId: 'debugger_paladin',
name: 'Debugger Paladin',
statModifiers: {
StatType.wis: 2,
StatType.con: 1,
},
statModifiers: {StatType.wis: 2, StatType.con: 1},
startingSkills: ['shield_bash'],
classSkills: ['shield_bash', 'debug_heal', 'breakpoint_guard'],
passives: [
@@ -125,19 +108,14 @@ class ClassData {
description: '회복력 +10%',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.heavy,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.heavy),
);
/// Loop Breaker: CON + STR (스탯 합계: +3)
static const loopBreaker = ClassTraits(
classId: 'loop_breaker',
name: 'Loop Breaker',
statModifiers: {
StatType.con: 2,
StatType.str: 1,
},
statModifiers: {StatType.con: 2, StatType.str: 1},
startingSkills: ['shield_bash'],
classSkills: ['shield_bash', 'infinite_guard', 'break_stance'],
passives: [
@@ -147,19 +125,14 @@ class ClassData {
description: 'HP +15%',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.heavy,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.heavy),
);
/// Garbage Collector: CON + STR (스탯 합계: +3)
static const garbageCollector = ClassTraits(
classId: 'garbage_collector',
name: 'Garbage Collector',
statModifiers: {
StatType.con: 2,
StatType.str: 1,
},
statModifiers: {StatType.con: 2, StatType.str: 1},
startingSkills: ['absorb'],
classSkills: ['absorb', 'recycle', 'memory_sweep'],
passives: [
@@ -174,9 +147,7 @@ class ClassData {
description: '전투 후 HP 5% 회복',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.heavy,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.heavy),
);
// ==========================================================================
@@ -187,10 +158,7 @@ class ClassData {
static const compilerMage = ClassTraits(
classId: 'compiler_mage',
name: 'Compiler Mage',
statModifiers: {
StatType.intelligence: 2,
StatType.wis: 1,
},
statModifiers: {StatType.intelligence: 2, StatType.wis: 1},
startingSkills: ['fireball'],
classSkills: ['fireball', 'compile_blast', 'syntax_storm'],
passives: [
@@ -200,19 +168,14 @@ class ClassData {
description: '마법 데미지 +15%',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.light,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.light),
);
/// Recursion Master: INT + DEX (스탯 합계: +3)
static const recursionMaster = ClassTraits(
classId: 'recursion_master',
name: 'Recursion Master',
statModifiers: {
StatType.intelligence: 2,
StatType.dex: 1,
},
statModifiers: {StatType.intelligence: 2, StatType.dex: 1},
startingSkills: ['fireball'],
classSkills: ['fireball', 'recursive_bolt', 'stack_overflow'],
passives: [
@@ -222,19 +185,14 @@ class ClassData {
description: '마법 데미지 +20%',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.light,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.light),
);
/// Memory Leaker: INT + WIS (스탯 합계: +3)
static const memoryLeaker = ClassTraits(
classId: 'memory_leaker',
name: 'Memory Leaker',
statModifiers: {
StatType.intelligence: 2,
StatType.wis: 1,
},
statModifiers: {StatType.intelligence: 2, StatType.wis: 1},
startingSkills: ['fireball'],
classSkills: ['fireball', 'leak_drain', 'memory_corrupt'],
passives: [
@@ -244,19 +202,14 @@ class ClassData {
description: '마법 데미지 +10%',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.light,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.light),
);
/// Type Caster: INT + CHA (스탯 합계: +3)
static const typeCaster = ClassTraits(
classId: 'type_caster',
name: 'Type Caster',
statModifiers: {
StatType.intelligence: 2,
StatType.cha: 1,
},
statModifiers: {StatType.intelligence: 2, StatType.cha: 1},
startingSkills: ['fireball'],
classSkills: ['fireball', 'type_coercion', 'cast_spell'],
passives: [
@@ -266,19 +219,14 @@ class ClassData {
description: '마법 데미지 +10%',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.light,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.light),
);
/// DevOps Shaman: CON + INT (스탯 합계: +3)
static const devOpsShaman = ClassTraits(
classId: 'devops_shaman',
name: 'DevOps Shaman',
statModifiers: {
StatType.con: 1,
StatType.intelligence: 2,
},
statModifiers: {StatType.con: 1, StatType.intelligence: 2},
startingSkills: ['fireball'],
classSkills: ['fireball', 'deploy_strike', 'ci_cd_flow'],
passives: [
@@ -293,9 +241,7 @@ class ClassData {
description: 'HP +10%',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.light,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.light),
);
// ==========================================================================
@@ -306,10 +252,7 @@ class ClassData {
static const refactorMonk = ClassTraits(
classId: 'refactor_monk',
name: 'Refactor Monk',
statModifiers: {
StatType.dex: 2,
StatType.con: 1,
},
statModifiers: {StatType.dex: 2, StatType.con: 1},
startingSkills: ['flurry'],
classSkills: ['flurry', 'clean_code_strike', 'refactor_combo'],
passives: [
@@ -324,19 +267,14 @@ class ClassData {
description: '연속 공격',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.light,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.light),
);
/// Pointer Assassin: DEX + STR (스탯 합계: +3)
static const pointerAssassin = ClassTraits(
classId: 'pointer_assassin',
name: 'Pointer Assassin',
statModifiers: {
StatType.dex: 2,
StatType.str: 1,
},
statModifiers: {StatType.dex: 2, StatType.str: 1},
startingSkills: ['backstab'],
classSkills: ['backstab', 'null_strike', 'dereference_kill'],
passives: [
@@ -351,19 +289,14 @@ class ClassData {
description: '첫 공격 1.5배',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.light,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.light),
);
/// Callback Samurai: DEX + STR (스탯 합계: +3)
static const callbackSamurai = ClassTraits(
classId: 'callback_samurai',
name: 'Callback Samurai',
statModifiers: {
StatType.dex: 2,
StatType.str: 1,
},
statModifiers: {StatType.dex: 2, StatType.str: 1},
startingSkills: ['power_strike'],
classSkills: ['power_strike', 'async_slash', 'promise_blade'],
passives: [
@@ -385,10 +318,7 @@ class ClassData {
static const testerJester = ClassTraits(
classId: 'tester_jester',
name: 'Tester Jester',
statModifiers: {
StatType.dex: 2,
StatType.cha: 1,
},
statModifiers: {StatType.dex: 2, StatType.cha: 1},
startingSkills: ['flurry'],
classSkills: ['flurry', 'mock_strike', 'assert_fail'],
passives: [
@@ -403,9 +333,7 @@ class ClassData {
description: '크리티컬 +5%',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.light,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.light),
);
// ==========================================================================
@@ -416,10 +344,7 @@ class ClassData {
static const exceptionHandler = ClassTraits(
classId: 'exception_handler',
name: 'Exception Handler',
statModifiers: {
StatType.wis: 2,
StatType.intelligence: 1,
},
statModifiers: {StatType.wis: 2, StatType.intelligence: 1},
startingSkills: ['heal'],
classSkills: ['heal', 'try_catch', 'finally_heal'],
passives: [
@@ -429,19 +354,14 @@ class ClassData {
description: '회복력 +15%',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.light,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.light),
);
/// Null Checker: WIS + INT (스탯 합계: +3)
static const nullChecker = ClassTraits(
classId: 'null_checker',
name: 'Null Checker',
statModifiers: {
StatType.wis: 2,
StatType.intelligence: 1,
},
statModifiers: {StatType.wis: 2, StatType.intelligence: 1},
startingSkills: ['heal'],
classSkills: ['heal', 'null_guard', 'safe_call'],
passives: [
@@ -456,9 +376,7 @@ class ClassData {
description: '방어력 +5%',
),
],
restriction: EquipmentRestriction(
armorWeight: ArmorWeight.light,
),
restriction: EquipmentRestriction(armorWeight: ArmorWeight.light),
);
/// 모든 클래스 목록 (18개)

View File

@@ -99,6 +99,362 @@ String taskSelling(String itemDescription) {
return 'Selling $itemDescription';
}
// ============================================================================
// 부활 시퀀스 메시지
// ============================================================================
String get taskReturningToTown {
if (isKoreanLocale) return '마을로 귀환 중...';
if (isJapaneseLocale) return '町に戻っている...';
return 'Returning to town...';
}
String get taskRestockingAtShop {
if (isKoreanLocale) return '상점에서 장비 정비 중...';
if (isJapaneseLocale) return 'ショップで装備を整備中...';
return 'Restocking at shop...';
}
String get taskHeadingToHuntingGrounds {
if (isKoreanLocale) return '사냥터로 이동 중...';
if (isJapaneseLocale) return '狩り場へ向かっている...';
return 'Heading to hunting grounds...';
}
// ============================================================================
// 사망 화면 메시지
// ============================================================================
String get deathYouDied {
if (isKoreanLocale) return '사망';
if (isJapaneseLocale) return '死亡';
return 'YOU DIED';
}
String get deathSacrificedToResurrect {
if (isKoreanLocale) return '부활 대가로 희생됨';
if (isJapaneseLocale) return '復活のために犠牲';
return 'Sacrificed to Resurrect';
}
String get deathEquipment {
if (isKoreanLocale) return '장비';
if (isJapaneseLocale) return '装備';
return 'Equipment';
}
String get deathNoSacrificeNeeded {
if (isKoreanLocale) return '희생 없이 부활';
if (isJapaneseLocale) return '犠牲なしで復活';
return 'No sacrifice needed';
}
String get deathGoldRemaining {
if (isKoreanLocale) return '남은 골드';
if (isJapaneseLocale) return '残りゴールド';
return 'Gold Remaining';
}
String get deathResurrect {
if (isKoreanLocale) return '부활';
if (isJapaneseLocale) return '復活';
return 'Resurrect';
}
String get deathCombatLog {
if (isKoreanLocale) return '전투 기록';
if (isJapaneseLocale) return '戦闘ログ';
return 'Combat Log';
}
String deathKilledBy(String killerName) {
if (isKoreanLocale) return '$killerName에게 사망';
if (isJapaneseLocale) return '$killerNameに倒された';
return 'Killed by $killerName';
}
String get deathEnvironmentalHazard {
if (isKoreanLocale) return '환경 피해로 사망';
if (isJapaneseLocale) return '環境ダメージで死亡';
return 'Environmental hazard';
}
// ============================================================================
// UI 일반 메시지
// ============================================================================
String get uiNoPotions {
if (isKoreanLocale) return '포션 없음';
if (isJapaneseLocale) return 'ポーションなし';
return 'No potions';
}
String get uiTapToContinue {
if (isKoreanLocale) return '탭하여 계속';
if (isJapaneseLocale) return 'タップして続行';
return 'Tap to continue';
}
String get uiNoSkills {
if (isKoreanLocale) return '습득한 스킬이 없습니다';
if (isJapaneseLocale) return 'スキルなし';
return 'No skills';
}
String get uiNoBonusStats {
if (isKoreanLocale) return '추가 스탯 없음';
if (isJapaneseLocale) return 'ボーナスステータスなし';
return 'No bonus stats';
}
String get uiNoActiveBuffs {
if (isKoreanLocale) return '활성 버프 없음';
if (isJapaneseLocale) return 'アクティブバフなし';
return 'No active buffs';
}
String get uiReady {
if (isKoreanLocale) return '준비';
if (isJapaneseLocale) return '準備完了';
return 'Ready';
}
String get uiPotions {
if (isKoreanLocale) return '포션';
if (isJapaneseLocale) return 'ポーション';
return 'Potions';
}
String get uiBuffs {
if (isKoreanLocale) return '버프';
if (isJapaneseLocale) return 'バフ';
return 'Buffs';
}
// ============================================================================
// 스탯 약어
// ============================================================================
String get statStr {
if (isKoreanLocale) return '';
if (isJapaneseLocale) return '筋力';
return 'STR';
}
String get statCon {
if (isKoreanLocale) return '체력';
if (isJapaneseLocale) return '耐久';
return 'CON';
}
String get statDex {
if (isKoreanLocale) return '민첩';
if (isJapaneseLocale) return '敏捷';
return 'DEX';
}
String get statInt {
if (isKoreanLocale) return '지능';
if (isJapaneseLocale) return '知力';
return 'INT';
}
String get statWis {
if (isKoreanLocale) return '지혜';
if (isJapaneseLocale) return '精神';
return 'WIS';
}
String get statCha {
if (isKoreanLocale) return '매력';
if (isJapaneseLocale) return '魅力';
return 'CHA';
}
// ============================================================================
// 패시브 능력 설명
// ============================================================================
String passiveHpBonus(int percent) {
if (isKoreanLocale) return 'HP +$percent%';
if (isJapaneseLocale) return 'HP +$percent%';
return 'HP +$percent%';
}
String passiveMpBonus(int percent) {
if (isKoreanLocale) return 'MP +$percent%';
if (isJapaneseLocale) return 'MP +$percent%';
return 'MP +$percent%';
}
String passivePhysicalBonus(int percent) {
if (isKoreanLocale) return '물리 공격 +$percent%';
if (isJapaneseLocale) return '物理攻撃 +$percent%';
return 'Physical +$percent%';
}
String passiveDefenseBonus(int percent) {
if (isKoreanLocale) return '방어력 +$percent%';
if (isJapaneseLocale) return '防御力 +$percent%';
return 'Defense +$percent%';
}
String passiveMagicBonus(int percent) {
if (isKoreanLocale) return '마법 공격 +$percent%';
if (isJapaneseLocale) return '魔法攻撃 +$percent%';
return 'Magic +$percent%';
}
String passiveEvasionBonus(int percent) {
if (isKoreanLocale) return '회피율 +$percent%';
if (isJapaneseLocale) return '回避率 +$percent%';
return 'Evasion +$percent%';
}
String passiveCritBonus(int percent) {
if (isKoreanLocale) return '크리티컬 +$percent%';
if (isJapaneseLocale) return 'クリティカル +$percent%';
return 'Critical +$percent%';
}
String passiveHpRegen(int percent) {
if (isKoreanLocale) return '전투 후 HP $percent% 회복';
if (isJapaneseLocale) return '戦闘後HP $percent%回復';
return 'Recover $percent% HP after combat';
}
String passiveMpRegen(int percent) {
if (isKoreanLocale) return '전투 후 MP $percent% 회복';
if (isJapaneseLocale) return '戦闘後MP $percent%回復';
return 'Recover $percent% MP after combat';
}
// ============================================================================
// 전투 로그 메시지
// ============================================================================
String combatYouHit(String targetName, int damage) {
if (isKoreanLocale) return '$targetName에게 $damage 데미지';
if (isJapaneseLocale) return '$targetNameに$damageダメージ';
return 'You hit $targetName for $damage damage';
}
String combatYouEvaded(String targetName) {
if (isKoreanLocale) return '$targetName의 공격 회피!';
if (isJapaneseLocale) return '$targetNameの攻撃を回避!';
return 'You evaded $targetName\'s attack!';
}
String combatEvadedAttackFrom(String targetName) {
if (isKoreanLocale) return '$targetName의 공격 회피';
if (isJapaneseLocale) return '$targetNameの攻撃を回避';
return 'Evaded attack from $targetName';
}
String combatHealedFor(int amount) {
if (isKoreanLocale) return 'HP $amount 회복';
if (isJapaneseLocale) return 'HP $amount回復';
return 'Healed for $amount HP';
}
String combatCritical(int damage, String targetName) {
if (isKoreanLocale) return '크리티컬! $targetName에게 $damage 데미지!';
if (isJapaneseLocale) return 'クリティカル! $targetNameに$damageダメージ!';
return 'CRITICAL! $damage damage to $targetName!';
}
String combatMonsterHitsYou(String monsterName, int damage) {
if (isKoreanLocale) return '$monsterName이(가) $damage 데미지';
if (isJapaneseLocale) return '$monsterNameが$damageダメージを与えた';
return '$monsterName hits you for $damage damage';
}
String combatMonsterEvaded(String monsterName) {
if (isKoreanLocale) return '$monsterName이(가) 공격 회피!';
if (isJapaneseLocale) return '$monsterNameが攻撃を回避!';
return '$monsterName evaded your attack!';
}
String combatBlocked(int damage) {
if (isKoreanLocale) return '방어! $damage 데미지로 감소';
if (isJapaneseLocale) return 'ブロック! $damageダメージに軽減';
return 'Blocked! Reduced to $damage damage';
}
String combatParried(int damage) {
if (isKoreanLocale) return '패리! $damage 데미지로 감소';
if (isJapaneseLocale) return 'パリィ! $damageダメージに軽減';
return 'Parried! Reduced to $damage damage';
}
// 스킬 관련 전투 메시지
String combatSkillCritical(String skillName, int damage) {
if (isKoreanLocale) return '크리티컬 $skillName! $damage 데미지!';
if (isJapaneseLocale) return 'クリティカル$skillName! $damageダメージ!';
return 'CRITICAL $skillName! $damage damage!';
}
String combatSkillDamage(String skillName, int damage) {
if (isKoreanLocale) return '$skillName: $damage 데미지';
if (isJapaneseLocale) return '$skillName: $damageダメージ';
return '$skillName: $damage damage';
}
String combatSkillHeal(String skillName, int amount) {
if (isKoreanLocale) return '$skillName: +$amount HP';
if (isJapaneseLocale) return '$skillName: +$amount HP';
return '$skillName: +$amount HP';
}
String get uiHeal {
if (isKoreanLocale) return '';
if (isJapaneseLocale) return 'ヒール';
return 'Heal';
}
String combatBuffActivated(String skillName) {
if (isKoreanLocale) return '$skillName 발동!';
if (isJapaneseLocale) return '$skillName 発動!';
return '$skillName activated!';
}
String combatDotTick(String skillName, int damage) {
if (isKoreanLocale) return '$skillName: $damage 지속 데미지';
if (isJapaneseLocale) return '$skillName: $damage 継続ダメージ';
return '$skillName ticks for $damage damage';
}
String combatPotionUsed(String potionName, int amount, String statName) {
if (isKoreanLocale) return '$potionName: +$amount $statName';
if (isJapaneseLocale) return '$potionName: +$amount $statName';
return '$potionName: +$amount $statName';
}
String combatPotionDrop(String potionName) {
if (isKoreanLocale) return '획득: $potionName';
if (isJapaneseLocale) return '獲得: $potionName';
return 'Dropped: $potionName';
}
// 사망 화면 전투 로그 (death overlay)
String combatBlockedAttack(String monsterName, int reducedDamage) {
if (isKoreanLocale) return '$monsterName의 공격 방어 ($reducedDamage 감소)';
if (isJapaneseLocale) return '$monsterNameの攻撃を防御 ($reducedDamage軽減)';
return 'Blocked $monsterName\'s attack ($reducedDamage reduced)';
}
String combatParriedAttack(String monsterName, int reducedDamage) {
if (isKoreanLocale) return '$monsterName의 공격 패리 ($reducedDamage 감소)';
if (isJapaneseLocale) return '$monsterNameの攻撃をパリィ ($reducedDamage軽減)';
return 'Parried $monsterName\'s attack ($reducedDamage reduced)';
}
String get deathSelfInflicted {
if (isKoreanLocale) return '자해 데미지로 사망';
if (isJapaneseLocale) return '自傷ダメージで死亡';
return 'Self-inflicted damage';
}
// ============================================================================
// 퀘스트 캡션
// ============================================================================
@@ -572,7 +928,8 @@ String translateImpressiveTitle(String englishName) {
/// 특수 아이템 이름 번역
String translateSpecial(String englishName) {
if (isKoreanLocale) return specialTranslationsKo[englishName] ?? englishName;
if (isJapaneseLocale) return specialTranslationsJa[englishName] ?? englishName;
if (isJapaneseLocale)
return specialTranslationsJa[englishName] ?? englishName;
return englishName;
}
@@ -627,14 +984,16 @@ String translateBoringItem(String englishName) {
/// 예: "Golden Iterator" → "황금 이터레이터" / "黄金のイテレーター"
String translateInterestingItem(String attrib, String special) {
if (isKoreanLocale) {
final translatedAttrib = itemAttribTranslationsKo[attrib] ??
final translatedAttrib =
itemAttribTranslationsKo[attrib] ??
additionalItemAttribTranslationsKo[attrib] ??
attrib;
final translatedSpecial = specialTranslationsKo[special] ?? special;
return '$translatedAttrib $translatedSpecial';
}
if (isJapaneseLocale) {
final translatedAttrib = itemAttribTranslationsJa[attrib] ??
final translatedAttrib =
itemAttribTranslationsJa[attrib] ??
additionalItemAttribTranslationsJa[attrib] ??
attrib;
final translatedSpecial = specialTranslationsJa[special] ?? special;
@@ -643,48 +1002,419 @@ String translateInterestingItem(String attrib, String special) {
return '$attrib $special';
}
/// 아이템 이름 문자열 전체 번역 (판매, 로그 등에 사용)
/// 예: "Golden Iterator of Compilation" → "컴파일의 황금 이터레이터"
/// 예: "Syntax Error fragment" → "구문 오류 조각"
String translateItemNameL10n(String itemString) {
if (!isKoreanLocale && !isJapaneseLocale) return itemString;
if (itemString.isEmpty) return itemString;
// 1. specialItem 형식: "Attrib Special of ItemOf"
final ofMatch = RegExp(r'^(.+)\s+of\s+(.+)$').firstMatch(itemString);
if (ofMatch != null) {
final beforeOf = ofMatch.group(1)!;
final afterOf = ofMatch.group(2)!;
// afterOf가 itemOfs 목록에 있는지 확인
final itemOfKo =
itemOfsTranslationsKo[afterOf] ??
additionalItemOfsTranslationsKo[afterOf];
final itemOfJa =
itemOfsTranslationsJa[afterOf] ??
additionalItemOfsTranslationsJa[afterOf];
if (itemOfKo != null || itemOfJa != null) {
// beforeOf를 interestingItem으로 분리 (attrib + special)
final beforeWords = beforeOf.split(' ');
if (beforeWords.length >= 2) {
final attrib = beforeWords[0];
final special = beforeWords.sublist(1).join(' ');
final translatedBefore = translateInterestingItem(attrib, special);
if (isKoreanLocale) {
return '$itemOfKo의 $translatedBefore';
} else if (isJapaneseLocale) {
return '$itemOfJaの$translatedBefore';
}
}
}
}
// 2. 몬스터 드롭 형식: "{monster} {drop}" (예: "syntax error fragment")
final words = itemString.split(' ');
if (words.length >= 2) {
// 마지막 단어가 드롭 아이템인지 확인
final lastWord = words.last.toLowerCase();
final dropKo =
dropItemTranslationsKo[lastWord] ??
additionalDropTranslationsKo[lastWord];
final dropJa =
dropItemTranslationsJa[lastWord] ??
additionalDropTranslationsJa[lastWord];
if (dropKo != null || dropJa != null) {
// 앞 부분은 몬스터 이름
final monsterPart = words.sublist(0, words.length - 1).join(' ');
final translatedMonster = translateMonster(monsterPart);
if (isKoreanLocale && dropKo != null) {
return '$translatedMonster $dropKo';
} else if (isJapaneseLocale && dropJa != null) {
return '$translatedMonsterの$dropJa';
}
}
// 3. interestingItem 형식: "Attrib Special" (2단어)
if (words.length == 2) {
return translateInterestingItem(words[0], words[1]);
}
}
// 4. 단일 단어 - boringItem 번역 시도
return translateBoringItem(itemString);
}
// ============================================================================
// 스토리/시네마틱 번역 함수 (Story/Cinematic Translation Functions)
// ============================================================================
/// Act 제목 번역
String translateActTitle(String englishTitle) {
if (isKoreanLocale) return actTitleTranslationsKo[englishTitle] ?? englishTitle;
if (isJapaneseLocale) return actTitleTranslationsJa[englishTitle] ?? englishTitle;
if (isKoreanLocale)
return actTitleTranslationsKo[englishTitle] ?? englishTitle;
if (isJapaneseLocale)
return actTitleTranslationsJa[englishTitle] ?? englishTitle;
return englishTitle;
}
/// Act 보스 이름 번역
String translateActBoss(String englishBoss) {
if (isKoreanLocale) return actBossTranslationsKo[englishBoss] ?? englishBoss;
if (isJapaneseLocale) return actBossTranslationsJa[englishBoss] ?? englishBoss;
if (isJapaneseLocale)
return actBossTranslationsJa[englishBoss] ?? englishBoss;
return englishBoss;
}
/// Act 퀘스트 번역
String translateActQuest(String englishQuest) {
if (isKoreanLocale) return actQuestTranslationsKo[englishQuest] ?? englishQuest;
if (isJapaneseLocale) return actQuestTranslationsJa[englishQuest] ?? englishQuest;
if (isKoreanLocale)
return actQuestTranslationsKo[englishQuest] ?? englishQuest;
if (isJapaneseLocale)
return actQuestTranslationsJa[englishQuest] ?? englishQuest;
return englishQuest;
}
/// 시네마틱 텍스트 번역
String translateCinematic(String englishText) {
if (isKoreanLocale) return cinematicTranslationsKo[englishText] ?? englishText;
if (isJapaneseLocale) return cinematicTranslationsJa[englishText] ?? englishText;
if (isKoreanLocale)
return cinematicTranslationsKo[englishText] ?? englishText;
if (isJapaneseLocale)
return cinematicTranslationsJa[englishText] ?? englishText;
return englishText;
}
/// 지역 이름 번역
String translateLocation(String englishLocation) {
if (isKoreanLocale) return locationTranslationsKo[englishLocation] ?? englishLocation;
if (isJapaneseLocale) return locationTranslationsJa[englishLocation] ?? englishLocation;
if (isKoreanLocale)
return locationTranslationsKo[englishLocation] ?? englishLocation;
if (isJapaneseLocale)
return locationTranslationsJa[englishLocation] ?? englishLocation;
return englishLocation;
}
/// 세력/조직 이름 번역
String translateFaction(String englishFaction) {
if (isKoreanLocale) return factionTranslationsKo[englishFaction] ?? englishFaction;
if (isJapaneseLocale) return factionTranslationsJa[englishFaction] ?? englishFaction;
if (isKoreanLocale)
return factionTranslationsKo[englishFaction] ?? englishFaction;
if (isJapaneseLocale)
return factionTranslationsJa[englishFaction] ?? englishFaction;
return englishFaction;
}
// ============================================================================
// 프론트 화면 텍스트
// ============================================================================
String get uiHallOfFame {
if (isKoreanLocale) return '명예의 전당';
if (isJapaneseLocale) return '栄誉の殿堂';
return 'Hall of Fame';
}
String get frontDescription {
if (isKoreanLocale) return 'Flutter로 재구축된 오프라인 Progress Quest (PQ 6.4)';
if (isJapaneseLocale) return 'Flutterで再構築されたオフラインProgress Quest (PQ 6.4)';
return 'Offline Progress Quest (PQ 6.4) rebuilt with Flutter.';
}
String get frontTodayFocus {
if (isKoreanLocale) return '오늘의 중점';
if (isJapaneseLocale) return '今日のフォーカス';
return "Today's focus";
}
// ============================================================================
// 명예의 전당 화면 텍스트
// ============================================================================
String get hofNoHeroes {
if (isKoreanLocale) return '영웅이 아직 없습니다';
if (isJapaneseLocale) return 'まだ英雄がいません';
return 'No heroes yet';
}
String get hofDefeatGlitchGod {
if (isKoreanLocale) return '글리치 신을 처치하여 전설을 남기세요!';
if (isJapaneseLocale) return 'グリッチゴッドを倒して伝説を刻もう!';
return 'Defeat the Glitch God to enshrine your legend!';
}
String get hofVictory {
if (isKoreanLocale) return '승리!';
if (isJapaneseLocale) return '勝利!';
return 'VICTORY!';
}
String get hofDefeatedGlitchGod {
if (isKoreanLocale) return '글리치 신을 처치했습니다!';
if (isJapaneseLocale) return 'グリッチゴッドを倒しました!';
return 'You have defeated the Glitch God!';
}
String get hofLegendEnshrined {
if (isKoreanLocale) return '당신의 전설이 명예의 전당에 기록되었습니다!';
if (isJapaneseLocale) return 'あなたの伝説が栄誉の殿堂に刻まれました!';
return 'Your legend has been enshrined in the Hall of Fame!';
}
String get hofViewHallOfFame {
if (isKoreanLocale) return '명예의 전당 보기';
if (isJapaneseLocale) return '栄誉の殿堂を見る';
return 'View Hall of Fame';
}
String get hofNewGame {
if (isKoreanLocale) return '새 게임';
if (isJapaneseLocale) return '新しいゲーム';
return 'New Game';
}
String get hofLevel {
if (isKoreanLocale) return '레벨';
if (isJapaneseLocale) return 'レベル';
return 'Level';
}
String get hofTime {
if (isKoreanLocale) return '시간';
if (isJapaneseLocale) return '時間';
return 'Time';
}
String get hofDeaths {
if (isKoreanLocale) return '사망';
if (isJapaneseLocale) return '死亡';
return 'Deaths';
}
String get hofQuests {
if (isKoreanLocale) return '퀘스트';
if (isJapaneseLocale) return 'クエスト';
return 'Quests';
}
String uiLevel(int level) {
if (isKoreanLocale) return 'Lv.$level';
if (isJapaneseLocale) return 'Lv.$level';
return 'Lv.$level';
}
// ============================================================================
// 시네마틱 뷰 텍스트
// ============================================================================
String get uiSkip {
if (isKoreanLocale) return '건너뛰기';
if (isJapaneseLocale) return 'スキップ';
return 'SKIP';
}
// ============================================================================
// 게임 플레이 화면 텍스트
// ============================================================================
String get uiLevelUp {
if (isKoreanLocale) return '레벨 업!';
if (isJapaneseLocale) return 'レベルアップ!';
return 'Level Up!';
}
String uiQuestComplete(String questName) {
if (isKoreanLocale) return '퀘스트 완료: $questName';
if (isJapaneseLocale) return 'クエスト完了: $questName';
return 'Quest Complete: $questName';
}
// ============================================================================
// 장비 패널 텍스트
// ============================================================================
String get uiEquipmentScore {
if (isKoreanLocale) return '장비 점수';
if (isJapaneseLocale) return '装備スコア';
return 'Equipment Score';
}
String get uiEmpty {
if (isKoreanLocale) return '(비어있음)';
if (isJapaneseLocale) return '(空)';
return '(empty)';
}
String uiWeight(int weight) {
if (isKoreanLocale) return '무게 $weight';
if (isJapaneseLocale) return '重量 $weight';
return 'Wt.$weight';
}
// 장비 슬롯 이름
String get slotWeapon {
if (isKoreanLocale) return '무기';
if (isJapaneseLocale) return '武器';
return 'Weapon';
}
String get slotShield {
if (isKoreanLocale) return '방패';
if (isJapaneseLocale) return '';
return 'Shield';
}
String get slotHelm {
if (isKoreanLocale) return '투구';
if (isJapaneseLocale) return '';
return 'Helm';
}
String get slotHauberk {
if (isKoreanLocale) return '갑옷';
if (isJapaneseLocale) return '';
return 'Hauberk';
}
String get slotBrassairts {
if (isKoreanLocale) return '상완갑';
if (isJapaneseLocale) return '上腕甲';
return 'Brassairts';
}
String get slotVambraces {
if (isKoreanLocale) return '전완갑';
if (isJapaneseLocale) return '前腕甲';
return 'Vambraces';
}
String get slotGauntlets {
if (isKoreanLocale) return '건틀릿';
if (isJapaneseLocale) return 'ガントレット';
return 'Gauntlets';
}
String get slotGambeson {
if (isKoreanLocale) return '패딩';
if (isJapaneseLocale) return 'パッデッドアーマー';
return 'Gambeson';
}
String get slotCuisses {
if (isKoreanLocale) return '허벅지갑';
if (isJapaneseLocale) return '腿当て';
return 'Cuisses';
}
String get slotGreaves {
if (isKoreanLocale) return '정강이갑';
if (isJapaneseLocale) return '脛当て';
return 'Greaves';
}
String get slotSollerets {
if (isKoreanLocale) return '철제부츠';
if (isJapaneseLocale) return '鉄靴';
return 'Sollerets';
}
// 스탯 약어 (장비용)
String get statAtk {
if (isKoreanLocale) return '공격';
if (isJapaneseLocale) return '攻撃';
return 'ATK';
}
String get statMAtk {
if (isKoreanLocale) return '마공';
if (isJapaneseLocale) return '魔攻';
return 'MATK';
}
String get statCri {
if (isKoreanLocale) return '치명';
if (isJapaneseLocale) return 'クリ';
return 'CRI';
}
String get statParry {
if (isKoreanLocale) return '패리';
if (isJapaneseLocale) return 'パリィ';
return 'PARRY';
}
String get statDef {
if (isKoreanLocale) return '방어';
if (isJapaneseLocale) return '防御';
return 'DEF';
}
String get statMDef {
if (isKoreanLocale) return '마방';
if (isJapaneseLocale) return '魔防';
return 'MDEF';
}
String get statBlock {
if (isKoreanLocale) return '블록';
if (isJapaneseLocale) return 'ブロック';
return 'BLOCK';
}
String get statEva {
if (isKoreanLocale) return '회피';
if (isJapaneseLocale) return '回避';
return 'EVA';
}
String get statHp {
if (isKoreanLocale) return 'HP';
if (isJapaneseLocale) return 'HP';
return 'HP';
}
String get statMp {
if (isKoreanLocale) return 'MP';
if (isJapaneseLocale) return 'MP';
return 'MP';
}
String get statSpeed {
if (isKoreanLocale) return '속도';
if (isJapaneseLocale) return '速度';
return 'SPEED';
}
// ============================================================================
// 스킬 패널 텍스트
// ============================================================================
String get uiDot {
if (isKoreanLocale) return '지속';
if (isJapaneseLocale) return 'DOT';
return 'DOT';
}

View File

@@ -1175,7 +1175,8 @@ const Map<String, String> cinematicTranslationsJa = {
// Act I: 覚醒
'=== ACT I: AWAKENING ===': '=== 第1幕: 覚醒 ===',
'You have proven yourself against the lesser bugs.': '下級バグとの戦いで実力を証明した。',
'The Debugger Knights take notice of your potential.': 'デバッガー騎士団があなたの可能性に注目する。',
'The Debugger Knights take notice of your potential.':
'デバッガー騎士団があなたの可能性に注目する。',
'But a greater threat lurks in the Bug Nest...': 'しかしより大きな脅威がバグの巣に潜んでいる…',
'The Syntax Error Dragon awaits.': '構文エラードラゴンが待ち構えている。',
@@ -1217,7 +1218,8 @@ const Map<String, String> cinematicTranslationsJa = {
'The Glitch God falls. The corruption fades.': 'グリッチゴッドが倒れた。破損が消えていく。',
'System Reboot initiated...': 'システム再起動開始…',
'Peace returns to the Digital Realm.': 'デジタル世界に平和が戻った。',
'Your legend will be compiled into the eternal logs.': 'あなたの伝説は永遠のログにコンパイルされるだろう。',
'Your legend will be compiled into the eternal logs.':
'あなたの伝説は永遠のログにコンパイルされるだろう。',
'THE END': '',
'...or is it?': '…本当に?',
};
@@ -1485,37 +1487,37 @@ const Map<String, String> additionalItemOfsTranslationsJa = {
/// すべてのモンスター翻訳を統合して返す
Map<String, String> get allMonsterTranslationsJa => {
...monsterTranslationsJa,
...advancedMonsterTranslationsJa,
};
...monsterTranslationsJa,
...advancedMonsterTranslationsJa,
};
/// すべてのアイテム属性翻訳を統合して返す
Map<String, String> get allItemAttribTranslationsJa => {
...itemAttribTranslationsJa,
...additionalItemAttribTranslationsJa,
};
...itemAttribTranslationsJa,
...additionalItemAttribTranslationsJa,
};
/// すべてのアイテム接尾辞(~の)翻訳を統合して返す
Map<String, String> get allItemOfsTranslationsJa => {
...itemOfsTranslationsJa,
...additionalItemOfsTranslationsJa,
};
...itemOfsTranslationsJa,
...additionalItemOfsTranslationsJa,
};
/// すべてのドロップアイテム翻訳を統合して返す
Map<String, String> get allDropTranslationsJa => {
...boringItemTranslationsJa,
...dropItemTranslationsJa,
...additionalDropTranslationsJa,
};
...boringItemTranslationsJa,
...dropItemTranslationsJa,
...additionalDropTranslationsJa,
};
/// すべての鎧翻訳を統合して返す
Map<String, String> get allArmorTranslationsJa => {
...armorTranslationsJa,
...additionalArmorTranslationsJa,
};
...armorTranslationsJa,
...additionalArmorTranslationsJa,
};
/// すべての盾翻訳を統合して返す
Map<String, String> get allShieldTranslationsJa => {
...shieldTranslationsJa,
...additionalShieldTranslationsJa,
};
...shieldTranslationsJa,
...additionalShieldTranslationsJa,
};

View File

@@ -1165,16 +1165,13 @@ const Map<String, String> actQuestTranslationsKo = {
/// 시네마틱 텍스트 한국어 번역
const Map<String, String> cinematicTranslationsKo = {
// 프롤로그
'In the beginning, there was only the Void...':
'태초에, 오직 공허(Void)만이 존재했다...',
'In the beginning, there was only the Void...': '태초에, 오직 공허(Void)만이 존재했다...',
'Then came the First Commit, and Light filled the Codebase.':
'그리고 첫 번째 커밋이 도래하여, 빛이 코드베이스를 가득 채웠다.',
'The Code God spoke: "Let there be Functions."':
'코드의 신이 말씀하셨다: "함수가 있으라."',
'The Code God spoke: "Let there be Functions."': '코드의 신이 말씀하셨다: "함수가 있으라."',
'And so the Digital Realm was born...': '그리하여 디지털 세계가 탄생하였다...',
'But from the shadows emerged the Glitch.': '그러나 어둠 속에서 글리치가 출현했다.',
'Now, a new hero awakens to defend the Code.':
'이제, 코드를 수호할 새로운 영웅이 깨어난다.',
'Now, a new hero awakens to defend the Code.': '이제, 코드를 수호할 새로운 영웅이 깨어난다.',
'Your journey begins...': '당신의 여정이 시작된다...',
// Act I: 각성
@@ -1191,11 +1188,9 @@ const Map<String, String> cinematicTranslationsKo = {
'=== ACT II: GROWTH ===': '=== 제2막: 성장 ===',
'With the Dragon slain, you join the Debugger Knights.':
'드래곤을 처치하고, 당신은 디버거 기사단에 입단한다.',
'The Corrupted Network spreads its infection...':
'손상된 네트워크가 감염을 퍼뜨리고 있다...',
'The Corrupted Network spreads its infection...': '손상된 네트워크가 감염을 퍼뜨리고 있다...',
'A traitor among the Knights is revealed!': '기사단 내 배신자가 드러났다!',
'The Memory Leak Hydra threatens all data.':
'메모리 누수 히드라가 모든 데이터를 위협한다.',
'The Memory Leak Hydra threatens all data.': '메모리 누수 히드라가 모든 데이터를 위협한다.',
'You must stop the corruption before it consumes everything.':
'모든 것을 삼키기 전에 손상을 멈춰야 한다.',
@@ -1206,20 +1201,16 @@ const Map<String, String> cinematicTranslationsKo = {
'고대 컴파일러가 당신에게 시련을 건넨다.',
'A companion falls... their sacrifice not in vain.':
'동료가 쓰러진다... 그들의 희생은 헛되지 않으리.',
'The Buffer Overflow Titan guards the gate.':
'버퍼 오버플로우 타이탄이 문을 지키고 있다.',
'The Buffer Overflow Titan guards the gate.': '버퍼 오버플로우 타이탄이 문을 지키고 있다.',
'Only through great sacrifice can you proceed.':
'오직 큰 희생을 통해서만 앞으로 나아갈 수 있다.',
// Act IV: 결전
'=== ACT IV: CONFRONTATION ===': '=== 제4막: 결전 ===',
"The Glitch God's Citadel looms before you.":
'글리치 신의 성채가 눈앞에 어렴풋이 보인다.',
'Former enemies unite against the common threat.':
'이전의 적들이 공동의 위협에 맞서 연합한다.',
"The Glitch God's Citadel looms before you.": '글리치 신의 성채가 눈앞에 어렴풋이 보인다.',
'Former enemies unite against the common threat.': '이전의 적들이 공동의 위협에 맞서 연합한다.',
'The Final Alliance is forged.': '최후의 동맹이 결성되었다.',
'The Kernel Panic Archon blocks your path.':
'커널 패닉 아르콘이 당신의 길을 막는다.',
'The Kernel Panic Archon blocks your path.': '커널 패닉 아르콘이 당신의 길을 막는다.',
'One final battle before the end...': '종말 전의 마지막 전투...',
// Act V: 종말
@@ -1227,13 +1218,11 @@ const Map<String, String> cinematicTranslationsKo = {
'The Glitch God reveals its true form.': '글리치 신이 진정한 모습을 드러낸다.',
'Reality itself begins to corrupt.': '현실 그 자체가 손상되기 시작한다.',
'All hope rests upon your shoulders.': '모든 희망이 당신의 어깨에 달려 있다.',
'The final battle for the Codebase begins!':
'코드베이스를 위한 최후의 전투가 시작된다!',
'The final battle for the Codebase begins!': '코드베이스를 위한 최후의 전투가 시작된다!',
// 엔딩
'=== THE END ===': '=== 완결 ===',
'The Glitch God falls. The corruption fades.':
'글리치 신이 쓰러진다. 손상이 사라진다.',
'The Glitch God falls. The corruption fades.': '글리치 신이 쓰러진다. 손상이 사라진다.',
'System Reboot initiated...': '시스템 재부팅 시작...',
'Peace returns to the Digital Realm.': '디지털 세계에 평화가 돌아온다.',
'Your legend will be compiled into the eternal logs.':
@@ -1505,37 +1494,37 @@ const Map<String, String> additionalItemOfsTranslationsKo = {
/// 모든 몬스터 번역을 통합하여 반환
Map<String, String> get allMonsterTranslationsKo => {
...monsterTranslationsKo,
...advancedMonsterTranslationsKo,
};
...monsterTranslationsKo,
...advancedMonsterTranslationsKo,
};
/// 모든 아이템 속성 번역을 통합하여 반환
Map<String, String> get allItemAttribTranslationsKo => {
...itemAttribTranslationsKo,
...additionalItemAttribTranslationsKo,
};
...itemAttribTranslationsKo,
...additionalItemAttribTranslationsKo,
};
/// 모든 아이템 접미사("~의") 번역을 통합하여 반환
Map<String, String> get allItemOfsTranslationsKo => {
...itemOfsTranslationsKo,
...additionalItemOfsTranslationsKo,
};
...itemOfsTranslationsKo,
...additionalItemOfsTranslationsKo,
};
/// 모든 드롭 아이템 번역을 통합하여 반환
Map<String, String> get allDropTranslationsKo => {
...boringItemTranslationsKo,
...dropItemTranslationsKo,
...additionalDropTranslationsKo,
};
...boringItemTranslationsKo,
...dropItemTranslationsKo,
...additionalDropTranslationsKo,
};
/// 모든 갑옷 번역을 통합하여 반환
Map<String, String> get allArmorTranslationsKo => {
...armorTranslationsKo,
...additionalArmorTranslationsKo,
};
...armorTranslationsKo,
...additionalArmorTranslationsKo,
};
/// 모든 방패 번역을 통합하여 반환
Map<String, String> get allShieldTranslationsKo => {
...shieldTranslationsKo,
...additionalShieldTranslationsKo,
};
...shieldTranslationsKo,
...additionalShieldTranslationsKo,
};

File diff suppressed because it is too large Load Diff

View File

@@ -80,18 +80,12 @@ const Map<StoryAct, List<CinematicStep>> cinematicData = {
text: 'Now, a new hero awakens to defend the Code.',
durationMs: 3500,
),
CinematicStep(
text: 'Your journey begins...',
durationMs: 2500,
),
CinematicStep(text: 'Your journey begins...', durationMs: 2500),
],
// Act I: 각성 (레벨 1-20)
StoryAct.act1: [
CinematicStep(
text: '=== ACT I: AWAKENING ===',
durationMs: 3000,
),
CinematicStep(text: '=== ACT I: AWAKENING ===', durationMs: 3000),
CinematicStep(
text: 'You have proven yourself against the lesser bugs.',
durationMs: 3000,
@@ -114,10 +108,7 @@ const Map<StoryAct, List<CinematicStep>> cinematicData = {
// Act II: 성장 (레벨 21-40)
StoryAct.act2: [
CinematicStep(
text: '=== ACT II: GROWTH ===',
durationMs: 3000,
),
CinematicStep(text: '=== ACT II: GROWTH ===', durationMs: 3000),
CinematicStep(
text: 'With the Dragon slain, you join the Debugger Knights.',
durationMs: 3500,
@@ -144,10 +135,7 @@ const Map<StoryAct, List<CinematicStep>> cinematicData = {
// Act III: 시련 (레벨 41-60)
StoryAct.act3: [
CinematicStep(
text: '=== ACT III: TRIALS ===',
durationMs: 3000,
),
CinematicStep(text: '=== ACT III: TRIALS ===', durationMs: 3000),
CinematicStep(
text: 'The path leads to the Null Kingdom...',
asciiArt: _asciiNullKingdom,
@@ -174,10 +162,7 @@ const Map<StoryAct, List<CinematicStep>> cinematicData = {
// Act IV: 결전 (레벨 61-80)
StoryAct.act4: [
CinematicStep(
text: '=== ACT IV: CONFRONTATION ===',
durationMs: 3000,
),
CinematicStep(text: '=== ACT IV: CONFRONTATION ===', durationMs: 3000),
CinematicStep(
text: "The Glitch God's Citadel looms before you.",
asciiArt: _asciiCitadel,
@@ -187,36 +172,24 @@ const Map<StoryAct, List<CinematicStep>> cinematicData = {
text: 'Former enemies unite against the common threat.',
durationMs: 3500,
),
CinematicStep(
text: 'The Final Alliance is forged.',
durationMs: 3000,
),
CinematicStep(text: 'The Final Alliance is forged.', durationMs: 3000),
CinematicStep(
text: 'The Kernel Panic Archon blocks your path.',
asciiArt: _asciiArchon,
durationMs: 4000,
),
CinematicStep(
text: 'One final battle before the end...',
durationMs: 3500,
),
CinematicStep(text: 'One final battle before the end...', durationMs: 3500),
],
// Act V: 종말 (레벨 81-100)
StoryAct.act5: [
CinematicStep(
text: '=== ACT V: ENDGAME ===',
durationMs: 3000,
),
CinematicStep(text: '=== ACT V: ENDGAME ===', durationMs: 3000),
CinematicStep(
text: 'The Glitch God reveals its true form.',
asciiArt: _asciiGlitchGod,
durationMs: 4000,
),
CinematicStep(
text: 'Reality itself begins to corrupt.',
durationMs: 3500,
),
CinematicStep(text: 'Reality itself begins to corrupt.', durationMs: 3500),
CinematicStep(
text: 'All hope rests upon your shoulders.',
durationMs: 3000,
@@ -229,19 +202,13 @@ const Map<StoryAct, List<CinematicStep>> cinematicData = {
// 엔딩: 시스템 재부팅, 평화 회복
StoryAct.ending: [
CinematicStep(
text: '=== THE END ===',
durationMs: 3000,
),
CinematicStep(text: '=== THE END ===', durationMs: 3000),
CinematicStep(
text: 'The Glitch God falls. The corruption fades.',
asciiArt: _asciiVictory,
durationMs: 4000,
),
CinematicStep(
text: 'System Reboot initiated...',
durationMs: 3000,
),
CinematicStep(text: 'System Reboot initiated...', durationMs: 3000),
CinematicStep(
text: 'Peace returns to the Digital Realm.',
durationMs: 3500,
@@ -250,15 +217,8 @@ const Map<StoryAct, List<CinematicStep>> cinematicData = {
text: 'Your legend will be compiled into the eternal logs.',
durationMs: 4000,
),
CinematicStep(
text: 'THE END',
asciiArt: _asciiTheEnd,
durationMs: 5000,
),
CinematicStep(
text: '...or is it?',
durationMs: 3000,
),
CinematicStep(text: 'THE END', asciiArt: _asciiTheEnd, durationMs: 5000),
CinematicStep(text: '...or is it?', durationMs: 3000),
],
};