style: dart format 적용
This commit is contained in:
@@ -142,16 +142,8 @@ class TestCharacterService {
|
|||||||
'Exception Handler',
|
'Exception Handler',
|
||||||
'Null Guard',
|
'Null Guard',
|
||||||
],
|
],
|
||||||
EquipmentSlot.helm => [
|
EquipmentSlot.helm => ['Neural Helm', 'Thought Processor', 'Mind Buffer'],
|
||||||
'Neural Helm',
|
EquipmentSlot.hauberk => ['Matrix Armor', 'Byte Mail', 'Kernel Plate'],
|
||||||
'Thought Processor',
|
|
||||||
'Mind Buffer',
|
|
||||||
],
|
|
||||||
EquipmentSlot.hauberk => [
|
|
||||||
'Matrix Armor',
|
|
||||||
'Byte Mail',
|
|
||||||
'Kernel Plate',
|
|
||||||
],
|
|
||||||
EquipmentSlot.brassairts => [
|
EquipmentSlot.brassairts => [
|
||||||
'Bit Guards',
|
'Bit Guards',
|
||||||
'Stream Bracers',
|
'Stream Bracers',
|
||||||
@@ -167,11 +159,7 @@ class TestCharacterService {
|
|||||||
'Handler Mitts',
|
'Handler Mitts',
|
||||||
'Pointer Grips',
|
'Pointer Grips',
|
||||||
],
|
],
|
||||||
EquipmentSlot.gambeson => [
|
EquipmentSlot.gambeson => ['Layer Vest', 'Cache Coat', 'Buffer Jacket'],
|
||||||
'Layer Vest',
|
|
||||||
'Cache Coat',
|
|
||||||
'Buffer Jacket',
|
|
||||||
],
|
|
||||||
EquipmentSlot.cuisses => [
|
EquipmentSlot.cuisses => [
|
||||||
'Register Guards',
|
'Register Guards',
|
||||||
'Stack Protectors',
|
'Stack Protectors',
|
||||||
|
|||||||
@@ -450,7 +450,9 @@ class GameDataL10n {
|
|||||||
final special = words.last;
|
final special = words.last;
|
||||||
|
|
||||||
// Attrib와 Special이 유효한지 확인
|
// Attrib와 Special이 유효한지 확인
|
||||||
final attribMap = isKo ? itemAttribTranslationsKo : itemAttribTranslationsJa;
|
final attribMap = isKo
|
||||||
|
? itemAttribTranslationsKo
|
||||||
|
: itemAttribTranslationsJa;
|
||||||
final specialMap = isKo ? specialTranslationsKo : specialTranslationsJa;
|
final specialMap = isKo ? specialTranslationsKo : specialTranslationsJa;
|
||||||
if (!attribMap.containsKey(attrib) && !specialMap.containsKey(special)) {
|
if (!attribMap.containsKey(attrib) && !specialMap.containsKey(special)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -472,7 +474,9 @@ class GameDataL10n {
|
|||||||
static String? _tryTranslateMonsterDrop(String itemString, bool isKo) {
|
static String? _tryTranslateMonsterDrop(String itemString, bool isKo) {
|
||||||
// 드롭 아이템 번역 맵 선택 (통합 맵 사용)
|
// 드롭 아이템 번역 맵 선택 (통합 맵 사용)
|
||||||
final dropMap = isKo ? allDropTranslationsKo : allDropTranslationsJa;
|
final dropMap = isKo ? allDropTranslationsKo : allDropTranslationsJa;
|
||||||
final monsterMap = isKo ? allMonsterTranslationsKo : allMonsterTranslationsJa;
|
final monsterMap = isKo
|
||||||
|
? allMonsterTranslationsKo
|
||||||
|
: allMonsterTranslationsJa;
|
||||||
|
|
||||||
// (대소문자 무시, 아이템 문자열 끝에서 매칭)
|
// (대소문자 무시, 아이템 문자열 끝에서 매칭)
|
||||||
for (final entry in dropMap.entries) {
|
for (final entry in dropMap.entries) {
|
||||||
|
|||||||
@@ -181,7 +181,10 @@ class GameSave {
|
|||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
equipment: _equipmentFromJson(equipmentJson, json['version'] as int? ?? 2),
|
equipment: _equipmentFromJson(
|
||||||
|
equipmentJson,
|
||||||
|
json['version'] as int? ?? 2,
|
||||||
|
),
|
||||||
skillBook: SkillBook(
|
skillBook: SkillBook(
|
||||||
skills: skillsJson
|
skills: skillsJson
|
||||||
.map(
|
.map(
|
||||||
@@ -333,10 +336,7 @@ Equipment _equipmentFromJson(Map<String, dynamic> json, int version) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Equipment(
|
return Equipment(items: items, bestIndex: json['bestIndex'] as int? ?? 0);
|
||||||
items: items,
|
|
||||||
bestIndex: json['bestIndex'] as int? ?? 0,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// v2 이하: 레거시 형식 (문자열 기반)
|
// v2 이하: 레거시 형식 (문자열 기반)
|
||||||
|
|||||||
@@ -96,7 +96,8 @@ class _ArenaResultPanelState extends State<ArenaResultPanel>
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// macOS: Downloads 폴더에 저장 (사용자가 쉽게 찾을 수 있도록)
|
// macOS: Downloads 폴더에 저장 (사용자가 쉽게 찾을 수 있도록)
|
||||||
final directory = await getDownloadsDirectory() ??
|
final directory =
|
||||||
|
await getDownloadsDirectory() ??
|
||||||
await getApplicationDocumentsDirectory();
|
await getApplicationDocumentsDirectory();
|
||||||
final timestamp = DateTime.now().toIso8601String().replaceAll(':', '-');
|
final timestamp = DateTime.now().toIso8601String().replaceAll(':', '-');
|
||||||
final challenger = widget.result.match.challenger.characterName;
|
final challenger = widget.result.match.challenger.characterName;
|
||||||
@@ -164,13 +165,15 @@ class _ArenaResultPanelState extends State<ArenaResultPanel>
|
|||||||
'class': entry.klass,
|
'class': entry.klass,
|
||||||
'combatStats': entry.finalStats?.toJson(),
|
'combatStats': entry.finalStats?.toJson(),
|
||||||
'equipment': entry.finalEquipment
|
'equipment': entry.finalEquipment
|
||||||
?.map((EquipmentItem e) => {
|
?.map(
|
||||||
'slot': e.slot.name,
|
(EquipmentItem e) => {
|
||||||
'name': e.name,
|
'slot': e.slot.name,
|
||||||
'level': e.level,
|
'name': e.name,
|
||||||
'rarity': e.rarity.name,
|
'level': e.level,
|
||||||
'stats': e.stats.toJson(),
|
'rarity': e.rarity.name,
|
||||||
})
|
'stats': e.stats.toJson(),
|
||||||
|
},
|
||||||
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
'skills': entry.finalSkills,
|
'skills': entry.finalSkills,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -142,7 +142,8 @@ class _FrontScreenState extends State<FrontScreen> with RouteAware {
|
|||||||
onHallOfFame: widget.onHallOfFame != null
|
onHallOfFame: widget.onHallOfFame != null
|
||||||
? () => widget.onHallOfFame!(context)
|
? () => widget.onHallOfFame!(context)
|
||||||
: null,
|
: null,
|
||||||
onLocalArena: widget.onLocalArena != null &&
|
onLocalArena:
|
||||||
|
widget.onLocalArena != null &&
|
||||||
widget.hallOfFameCount >= 2
|
widget.hallOfFameCount >= 2
|
||||||
? () => widget.onLocalArena!(context)
|
? () => widget.onLocalArena!(context)
|
||||||
: null,
|
: null,
|
||||||
|
|||||||
@@ -206,7 +206,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
|
|
||||||
Widget _buildDebugSection() {
|
Widget _buildDebugSection() {
|
||||||
return Card(
|
return Card(
|
||||||
color: Theme.of(context).colorScheme.errorContainer.withValues(alpha: 0.3),
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.errorContainer.withValues(alpha: 0.3),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@@ -64,7 +64,9 @@ void main() {
|
|||||||
final diagnosis = sim.winRate >= targetWinRate
|
final diagnosis = sim.winRate >= targetWinRate
|
||||||
? '✓ 적정'
|
? '✓ 적정'
|
||||||
: '✗ 조정필요 (목표: ${(targetWinRate * 100).toStringAsFixed(0)}%)';
|
: '✗ 조정필요 (목표: ${(targetWinRate * 100).toStringAsFixed(0)}%)';
|
||||||
print('레벨 $level (${tier.name}): 승률 ${(sim.winRate * 100).toStringAsFixed(0)}% $diagnosis');
|
print(
|
||||||
|
'레벨 $level (${tier.name}): 승률 ${(sim.winRate * 100).toStringAsFixed(0)}% $diagnosis',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
print('\n${'=' * 80}');
|
print('\n${'=' * 80}');
|
||||||
@@ -88,7 +90,9 @@ void main() {
|
|||||||
final minDamage = (monster.atk * 0.8 - player.def * 0.3).round();
|
final minDamage = (monster.atk * 0.8 - player.def * 0.3).round();
|
||||||
final maxDamage = (monster.atk * 1.2 - player.def * 0.3).round();
|
final maxDamage = (monster.atk * 1.2 - player.def * 0.3).round();
|
||||||
print('- 몬스터 데미지: $minDamage ~ $maxDamage');
|
print('- 몬스터 데미지: $minDamage ~ $maxDamage');
|
||||||
print('- 플레이어 생존 히트: ${(player.hp / maxDamage).floor()} ~ ${(player.hp / minDamage).ceil()}');
|
print(
|
||||||
|
'- 플레이어 생존 히트: ${(player.hp / maxDamage).floor()} ~ ${(player.hp / minDamage).ceil()}',
|
||||||
|
);
|
||||||
|
|
||||||
print('\n#### 적용된 밸런스 수정');
|
print('\n#### 적용된 밸런스 수정');
|
||||||
print('1. 플레이어 HP 스케일링 상향:');
|
print('1. 플레이어 HP 스케일링 상향:');
|
||||||
@@ -136,7 +140,8 @@ _PlayerEstimate _estimatePlayerStats(int level) {
|
|||||||
|
|
||||||
// 장비 스탯 추정 (레벨 * 0.8 수준의 common 장비 10개)
|
// 장비 스탯 추정 (레벨 * 0.8 수준의 common 장비 10개)
|
||||||
final equipLevel = (level * 0.8).round().clamp(1, level);
|
final equipLevel = (level * 0.8).round().clamp(1, level);
|
||||||
final equipBaseValue = (equipLevel * 1.2 * ItemRarity.common.multiplier).round();
|
final equipBaseValue = (equipLevel * 1.2 * ItemRarity.common.multiplier)
|
||||||
|
.round();
|
||||||
|
|
||||||
// 무기 ATK (speedMultiplier 1.0 가정)
|
// 무기 ATK (speedMultiplier 1.0 가정)
|
||||||
final weaponAtk = equipBaseValue;
|
final weaponAtk = equipBaseValue;
|
||||||
@@ -182,8 +187,14 @@ _CombatSimulation _simulateCombat(int level) {
|
|||||||
|
|
||||||
// 데미지 계산 (combat_calculator 평균)
|
// 데미지 계산 (combat_calculator 평균)
|
||||||
// damage = ATK * 1.0 - DEF * 0.5 (DEF 감산율 상향)
|
// damage = ATK * 1.0 - DEF * 0.5 (DEF 감산율 상향)
|
||||||
final monsterDamage = (monster.atk * 1.0 - player.def * 0.5).round().clamp(1, 9999);
|
final monsterDamage = (monster.atk * 1.0 - player.def * 0.5).round().clamp(
|
||||||
final playerDamage = (player.atk * 1.0 - monster.def * 0.5).round().clamp(1, 9999);
|
1,
|
||||||
|
9999,
|
||||||
|
);
|
||||||
|
final playerDamage = (player.atk * 1.0 - monster.def * 0.5).round().clamp(
|
||||||
|
1,
|
||||||
|
9999,
|
||||||
|
);
|
||||||
|
|
||||||
// 생존 히트 수
|
// 생존 히트 수
|
||||||
final playerHits = (player.hp / monsterDamage).ceil();
|
final playerHits = (player.hp / monsterDamage).ceil();
|
||||||
@@ -194,8 +205,8 @@ _CombatSimulation _simulateCombat(int level) {
|
|||||||
final winRate = playerHits > monsterHits
|
final winRate = playerHits > monsterHits
|
||||||
? 0.95 // 압도적 유리
|
? 0.95 // 압도적 유리
|
||||||
: playerHits == monsterHits
|
: playerHits == monsterHits
|
||||||
? 0.65 // 동등 (선공 이점)
|
? 0.65 // 동등 (선공 이점)
|
||||||
: (playerHits / monsterHits).clamp(0.2, 0.9);
|
: (playerHits / monsterHits).clamp(0.2, 0.9);
|
||||||
|
|
||||||
return _CombatSimulation(
|
return _CombatSimulation(
|
||||||
monsterDamage: monsterDamage,
|
monsterDamage: monsterDamage,
|
||||||
|
|||||||
@@ -55,8 +55,16 @@ void main() {
|
|||||||
final oldAtk = 10 + level * 12;
|
final oldAtk = 10 + level * 12;
|
||||||
final newAtk = MonsterBaseStats.forLevel(level).atk;
|
final newAtk = MonsterBaseStats.forLevel(level).atk;
|
||||||
final ratio = newAtk / oldAtk;
|
final ratio = newAtk / oldAtk;
|
||||||
expect(ratio, lessThan(0.45), reason: 'Level $level should be < 45% of old');
|
expect(
|
||||||
expect(ratio, greaterThan(0.25), reason: 'Level $level should be > 25% of old');
|
ratio,
|
||||||
|
lessThan(0.45),
|
||||||
|
reason: 'Level $level should be < 45% of old',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
ratio,
|
||||||
|
greaterThan(0.25),
|
||||||
|
reason: 'Level $level should be > 25% of old',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 레벨 1~5는 추가 완화 (기존 대비 더 낮음)
|
// 레벨 1~5는 추가 완화 (기존 대비 더 낮음)
|
||||||
@@ -64,8 +72,16 @@ void main() {
|
|||||||
final oldAtk = 10 + level * 12;
|
final oldAtk = 10 + level * 12;
|
||||||
final newAtk = MonsterBaseStats.forLevel(level).atk;
|
final newAtk = MonsterBaseStats.forLevel(level).atk;
|
||||||
final ratio = newAtk / oldAtk;
|
final ratio = newAtk / oldAtk;
|
||||||
expect(ratio, lessThan(0.35), reason: 'Early level $level should be < 35% of old');
|
expect(
|
||||||
expect(ratio, greaterThan(0.15), reason: 'Early level $level should be > 15% of old');
|
ratio,
|
||||||
|
lessThan(0.35),
|
||||||
|
reason: 'Early level $level should be < 35% of old',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
ratio,
|
||||||
|
greaterThan(0.15),
|
||||||
|
reason: 'Early level $level should be > 15% of old',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user