refactor(model): SpellBook을 SkillBook으로 리네이밍

- 게임 컨셉에 맞게 주문서 → 스킬북 용어 통일
- 관련 모든 참조 일괄 변경
This commit is contained in:
JiWoong Sul
2026-01-06 18:45:16 +09:00
parent afc3c18ae4
commit 8d51263b2e
14 changed files with 114 additions and 114 deletions

View File

@@ -29,16 +29,16 @@ class ArenaService {
// 스킬 시스템 헬퍼 // 스킬 시스템 헬퍼
// ============================================================================ // ============================================================================
/// HallOfFameEntry의 finalSpells에서 Skill 목록 추출 /// HallOfFameEntry의 finalSkills에서 Skill 목록 추출
List<Skill> _getSkillsFromEntry(HallOfFameEntry entry) { List<Skill> _getSkillsFromEntry(HallOfFameEntry entry) {
final spells = entry.finalSpells; final skillData = entry.finalSkills;
if (spells == null || spells.isEmpty) return []; if (skillData == null || skillData.isEmpty) return [];
final skills = <Skill>[]; final skills = <Skill>[];
for (final spell in spells) { for (final data in skillData) {
final spellName = spell['name']; final skillName = data['name'];
if (spellName != null) { if (skillName != null) {
final skill = SkillData.getSkillBySpellName(spellName); final skill = SkillData.getSkillBySpellName(skillName);
if (skill != null) { if (skill != null) {
skills.add(skill); skills.add(skill);
} }

View File

@@ -49,17 +49,17 @@ class GameMutations {
final name = parts[0]; final name = parts[0];
final rank = parts.length > 1 ? parts[1] : 'I'; final rank = parts.length > 1 ? parts[1] : 'I';
final spells = [...state.spellBook.spells]; final skills = [...state.skillBook.skills];
final index = spells.indexWhere((s) => s.name == name); final index = skills.indexWhere((s) => s.name == name);
if (index >= 0) { if (index >= 0) {
spells[index] = spells[index].copyWith(rank: rank); skills[index] = skills[index].copyWith(rank: rank);
} else { } else {
spells.add(SpellEntry(name: name, rank: rank)); skills.add(SkillEntry(name: name, rank: rank));
} }
return state.copyWith( return state.copyWith(
rng: state.rng, rng: state.rng,
spellBook: state.spellBook.copyWith(spells: spells), skillBook: state.skillBook.copyWith(skills: skills),
); );
} }

View File

@@ -1240,11 +1240,11 @@ class ProgressService {
// 플레이어 공격 체크 // 플레이어 공격 체크
if (playerAccumulator >= playerStats.attackDelayMs) { if (playerAccumulator >= playerStats.attackDelayMs) {
// SpellBook에서 사용 가능한 스킬 ID 목록 조회 // SkillBook에서 사용 가능한 스킬 ID 목록 조회
var availableSkillIds = skillService.getAvailableSkillIdsFromSpellBook( var availableSkillIds = skillService.getAvailableSkillIdsFromSkillBook(
state.spellBook, state.skillBook,
); );
// SpellBook에 스킬이 없으면 기본 스킬 사용 // SkillBook에 스킬이 없으면 기본 스킬 사용
if (availableSkillIds.isEmpty) { if (availableSkillIds.isEmpty) {
availableSkillIds = SkillData.defaultSkillIds; availableSkillIds = SkillData.defaultSkillIds;
} }
@@ -1259,9 +1259,9 @@ class ProgressService {
); );
if (selectedSkill != null && selectedSkill.isAttack) { if (selectedSkill != null && selectedSkill.isAttack) {
// 스 랭크 조회 (SpellBook 기반) // 스 랭크 조회 (SkillBook 기반)
final spellRank = skillService.getSkillRankFromSpellBook( final skillRank = skillService.getSkillRankFromSkillBook(
state.spellBook, state.skillBook,
selectedSkill.id, selectedSkill.id,
); );
// 랭크 스케일링 적용된 공격 스킬 사용 // 랭크 스케일링 적용된 공격 스킬 사용
@@ -1270,7 +1270,7 @@ class ProgressService {
player: playerStats, player: playerStats,
monster: monsterStats, monster: monsterStats,
skillSystem: updatedSkillSystem, skillSystem: updatedSkillSystem,
rank: spellRank, rank: skillRank,
); );
playerStats = skillResult.updatedPlayer; playerStats = skillResult.updatedPlayer;
monsterStats = skillResult.updatedMonster; monsterStats = skillResult.updatedMonster;

View File

@@ -552,50 +552,50 @@ class SkillService {
} }
// ============================================================================ // ============================================================================
// SpellBook 연동 // SkillBook 연동
// ============================================================================ // ============================================================================
/// SpellBook에서 사용 가능한 스킬 목록 조회 /// SkillBook에서 사용 가능한 스킬 목록 조회
/// ///
/// SpellEntry 이름을 Skill로 매핑하여 반환 /// SkillEntry 이름을 Skill로 매핑하여 반환
List<Skill> getAvailableSkillsFromSpellBook(SpellBook spellBook) { List<Skill> getAvailableSkillsFromSkillBook(SkillBook skillBook) {
return spellBook.spells return skillBook.skills
.map((spell) => SkillData.getSkillBySpellName(spell.name)) .map((entry) => SkillData.getSkillBySpellName(entry.name))
.whereType<Skill>() .whereType<Skill>()
.toList(); .toList();
} }
/// SpellBook에서 스킬의 랭크(레벨) 조회 /// SkillBook에서 스킬의 랭크(레벨) 조회
/// ///
/// 로마숫자 랭크(I, II, III)를 정수로 변환하여 반환 /// 로마숫자 랭크(I, II, III)를 정수로 변환하여 반환
/// 스이 없으면 1 반환 /// 스이 없으면 1 반환
int getSkillRankFromSpellBook(SpellBook spellBook, String skillId) { int getSkillRankFromSkillBook(SkillBook skillBook, String skillId) {
// skillId로 스킬 찾기 // skillId로 스킬 찾기
final skill = SkillData.getSkillById(skillId); final skill = SkillData.getSkillById(skillId);
if (skill == null) return 1; if (skill == null) return 1;
// 스킬 이름으로 SpellEntry 찾기 // 스킬 이름으로 SkillEntry 찾기
for (final spell in spellBook.spells) { for (final entry in skillBook.skills) {
if (spell.name == skill.name) { if (entry.name == skill.name) {
return romanToInt(spell.rank); return romanToInt(entry.rank);
} }
} }
return 1; // 기본 랭크 return 1; // 기본 랭크
} }
/// SpellBook에서 스킬 ID 목록 조회 /// SkillBook에서 스킬 ID 목록 조회
/// ///
/// 전투 시스템에서 사용 가능한 스킬 ID 목록 반환 /// 전투 시스템에서 사용 가능한 스킬 ID 목록 반환
List<String> getAvailableSkillIdsFromSpellBook(SpellBook spellBook) { List<String> getAvailableSkillIdsFromSkillBook(SkillBook skillBook) {
return getAvailableSkillsFromSpellBook( return getAvailableSkillsFromSkillBook(
spellBook, skillBook,
).map((skill) => skill.id).toList(); ).map((skill) => skill.id).toList();
} }
/// 랭크 스케일링이 적용된 공격 스킬 사용 /// 랭크 스케일링이 적용된 공격 스킬 사용
/// ///
/// [rank] 스펠 랭크 (SpellBook에서 조회) /// [rank] 스펠 랭크 (SkillBook에서 조회)
({ ({
SkillUseResult result, SkillUseResult result,
CombatStats updatedPlayer, CombatStats updatedPlayer,

View File

@@ -21,7 +21,7 @@ class GameState {
Stats? stats, Stats? stats,
Inventory? inventory, Inventory? inventory,
Equipment? equipment, Equipment? equipment,
SpellBook? spellBook, SkillBook? skillBook,
ProgressState? progress, ProgressState? progress,
QueueState? queue, QueueState? queue,
SkillSystemState? skillSystem, SkillSystemState? skillSystem,
@@ -32,7 +32,7 @@ class GameState {
stats = stats ?? Stats.empty(), stats = stats ?? Stats.empty(),
inventory = inventory ?? Inventory.empty(), inventory = inventory ?? Inventory.empty(),
equipment = equipment ?? Equipment.empty(), equipment = equipment ?? Equipment.empty(),
spellBook = spellBook ?? SpellBook.empty(), skillBook = skillBook ?? SkillBook.empty(),
progress = progress ?? ProgressState.empty(), progress = progress ?? ProgressState.empty(),
queue = queue ?? QueueState.empty(), queue = queue ?? QueueState.empty(),
skillSystem = skillSystem ?? SkillSystemState.empty(), skillSystem = skillSystem ?? SkillSystemState.empty(),
@@ -44,7 +44,7 @@ class GameState {
Stats? stats, Stats? stats,
Inventory? inventory, Inventory? inventory,
Equipment? equipment, Equipment? equipment,
SpellBook? spellBook, SkillBook? skillBook,
ProgressState? progress, ProgressState? progress,
QueueState? queue, QueueState? queue,
SkillSystemState? skillSystem, SkillSystemState? skillSystem,
@@ -57,7 +57,7 @@ class GameState {
stats: stats, stats: stats,
inventory: inventory, inventory: inventory,
equipment: equipment, equipment: equipment,
spellBook: spellBook, skillBook: skillBook,
progress: progress, progress: progress,
queue: queue, queue: queue,
skillSystem: skillSystem, skillSystem: skillSystem,
@@ -71,7 +71,7 @@ class GameState {
final Stats stats; final Stats stats;
final Inventory inventory; final Inventory inventory;
final Equipment equipment; final Equipment equipment;
final SpellBook spellBook; final SkillBook skillBook;
final ProgressState progress; final ProgressState progress;
final QueueState queue; final QueueState queue;
@@ -93,7 +93,7 @@ class GameState {
Stats? stats, Stats? stats,
Inventory? inventory, Inventory? inventory,
Equipment? equipment, Equipment? equipment,
SpellBook? spellBook, SkillBook? skillBook,
ProgressState? progress, ProgressState? progress,
QueueState? queue, QueueState? queue,
SkillSystemState? skillSystem, SkillSystemState? skillSystem,
@@ -107,7 +107,7 @@ class GameState {
stats: stats ?? this.stats, stats: stats ?? this.stats,
inventory: inventory ?? this.inventory, inventory: inventory ?? this.inventory,
equipment: equipment ?? this.equipment, equipment: equipment ?? this.equipment,
spellBook: spellBook ?? this.spellBook, skillBook: skillBook ?? this.skillBook,
progress: progress ?? this.progress, progress: progress ?? this.progress,
queue: queue ?? this.queue, queue: queue ?? this.queue,
skillSystem: skillSystem ?? this.skillSystem, skillSystem: skillSystem ?? this.skillSystem,
@@ -660,26 +660,26 @@ class Equipment {
} }
} }
class SpellEntry { class SkillEntry {
const SpellEntry({required this.name, required this.rank}); const SkillEntry({required this.name, required this.rank});
final String name; final String name;
final String rank; // e.g., Roman numerals final String rank; // e.g., Roman numerals
SpellEntry copyWith({String? name, String? rank}) { SkillEntry copyWith({String? name, String? rank}) {
return SpellEntry(name: name ?? this.name, rank: rank ?? this.rank); return SkillEntry(name: name ?? this.name, rank: rank ?? this.rank);
} }
} }
class SpellBook { class SkillBook {
const SpellBook({required this.spells}); const SkillBook({required this.skills});
final List<SpellEntry> spells; final List<SkillEntry> skills;
factory SpellBook.empty() => const SpellBook(spells: []); factory SkillBook.empty() => const SkillBook(skills: []);
SpellBook copyWith({List<SpellEntry>? spells}) { SkillBook copyWith({List<SkillEntry>? skills}) {
return SpellBook(spells: spells ?? this.spells); return SkillBook(skills: skills ?? this.skills);
} }
} }

View File

@@ -21,7 +21,7 @@ class HallOfFameEntry {
required this.clearedAt, required this.clearedAt,
this.finalStats, this.finalStats,
this.finalEquipment, this.finalEquipment,
this.finalSpells, this.finalSkills,
}); });
/// 고유 ID (UUID) /// 고유 ID (UUID)
@@ -61,7 +61,7 @@ class HallOfFameEntry {
final List<EquipmentItem>? finalEquipment; final List<EquipmentItem>? finalEquipment;
/// 최종 스펠북 (스펠 이름 + 랭크) /// 최종 스펠북 (스펠 이름 + 랭크)
final List<Map<String, String>>? finalSpells; final List<Map<String, String>>? finalSkills;
/// 플레이 시간을 Duration으로 변환 /// 플레이 시간을 Duration으로 변환
Duration get totalPlayTime => Duration(milliseconds: totalPlayTimeMs); Duration get totalPlayTime => Duration(milliseconds: totalPlayTimeMs);
@@ -96,7 +96,7 @@ class HallOfFameEntry {
DateTime? clearedAt, DateTime? clearedAt,
CombatStats? finalStats, CombatStats? finalStats,
List<EquipmentItem>? finalEquipment, List<EquipmentItem>? finalEquipment,
List<Map<String, String>>? finalSpells, List<Map<String, String>>? finalSkills,
}) { }) {
return HallOfFameEntry( return HallOfFameEntry(
id: id ?? this.id, id: id ?? this.id,
@@ -111,7 +111,7 @@ class HallOfFameEntry {
clearedAt: clearedAt ?? this.clearedAt, clearedAt: clearedAt ?? this.clearedAt,
finalStats: finalStats ?? this.finalStats, finalStats: finalStats ?? this.finalStats,
finalEquipment: finalEquipment ?? this.finalEquipment, finalEquipment: finalEquipment ?? this.finalEquipment,
finalSpells: finalSpells ?? this.finalSpells, finalSkills: finalSkills ?? this.finalSkills,
); );
} }
@@ -135,7 +135,7 @@ class HallOfFameEntry {
clearedAt: DateTime.now(), clearedAt: DateTime.now(),
finalStats: combatStats, finalStats: combatStats,
finalEquipment: List<EquipmentItem>.from(state.equipment.items), finalEquipment: List<EquipmentItem>.from(state.equipment.items),
finalSpells: state.spellBook.spells finalSkills: state.skillBook.skills
.map((s) => {'name': s.name, 'rank': s.rank}) .map((s) => {'name': s.name, 'rank': s.rank})
.toList(), .toList(),
); );
@@ -156,7 +156,7 @@ class HallOfFameEntry {
'clearedAt': clearedAt.toIso8601String(), 'clearedAt': clearedAt.toIso8601String(),
'finalStats': finalStats?.toJson(), 'finalStats': finalStats?.toJson(),
'finalEquipment': finalEquipment?.map((e) => e.toJson()).toList(), 'finalEquipment': finalEquipment?.map((e) => e.toJson()).toList(),
'finalSpells': finalSpells, 'finalSkills': finalSkills,
}; };
} }
@@ -181,8 +181,8 @@ class HallOfFameEntry {
.map((e) => EquipmentItem.fromJson(e as Map<String, dynamic>)) .map((e) => EquipmentItem.fromJson(e as Map<String, dynamic>))
.toList() .toList()
: null, : null,
finalSpells: json['finalSpells'] != null finalSkills: json['finalSkills'] != null
? (json['finalSpells'] as List<dynamic>) ? (json['finalSkills'] as List<dynamic>)
.map((s) => Map<String, String>.from(s as Map)) .map((s) => Map<String, String>.from(s as Map))
.toList() .toList()
: null, : null,

View File

@@ -13,7 +13,7 @@ class GameSave {
required this.stats, required this.stats,
required this.inventory, required this.inventory,
required this.equipment, required this.equipment,
required this.spellBook, required this.skillBook,
required this.progress, required this.progress,
required this.queue, required this.queue,
}); });
@@ -26,7 +26,7 @@ class GameSave {
stats: state.stats, stats: state.stats,
inventory: state.inventory, inventory: state.inventory,
equipment: state.equipment, equipment: state.equipment,
spellBook: state.spellBook, skillBook: state.skillBook,
progress: state.progress, progress: state.progress,
queue: state.queue, queue: state.queue,
); );
@@ -38,7 +38,7 @@ class GameSave {
final Stats stats; final Stats stats;
final Inventory inventory; final Inventory inventory;
final Equipment equipment; final Equipment equipment;
final SpellBook spellBook; final SkillBook skillBook;
final ProgressState progress; final ProgressState progress;
final QueueState queue; final QueueState queue;
@@ -88,7 +88,7 @@ class GameSave {
'sollerets': equipment.sollerets, 'sollerets': equipment.sollerets,
'bestIndex': equipment.bestIndex, 'bestIndex': equipment.bestIndex,
}, },
'spells': spellBook.spells 'skills': skillBook.skills
.map((e) => {'name': e.name, 'rank': e.rank}) .map((e) => {'name': e.name, 'rank': e.rank})
.toList(), .toList(),
'progress': { 'progress': {
@@ -140,7 +140,7 @@ class GameSave {
final equipmentJson = json['equipment'] as Map<String, dynamic>; final equipmentJson = json['equipment'] as Map<String, dynamic>;
final progressJson = json['progress'] as Map<String, dynamic>; final progressJson = json['progress'] as Map<String, dynamic>;
final queueJson = (json['queue'] as List<dynamic>? ?? []).cast<dynamic>(); final queueJson = (json['queue'] as List<dynamic>? ?? []).cast<dynamic>();
final spellsJson = (json['spells'] as List<dynamic>? ?? []).cast<dynamic>(); final skillsJson = (json['skills'] as List<dynamic>? ?? []).cast<dynamic>();
return GameSave( return GameSave(
version: json['version'] as int? ?? kSaveVersion, version: json['version'] as int? ?? kSaveVersion,
@@ -192,10 +192,10 @@ class GameSave {
sollerets: equipmentJson['sollerets'] as String? ?? '', sollerets: equipmentJson['sollerets'] as String? ?? '',
bestIndex: equipmentJson['bestIndex'] as int? ?? 0, bestIndex: equipmentJson['bestIndex'] as int? ?? 0,
), ),
spellBook: SpellBook( skillBook: SkillBook(
spells: spellsJson skills: skillsJson
.map( .map(
(e) => SpellEntry( (e) => SkillEntry(
name: (e as Map<String, dynamic>)['name'] as String? ?? '', name: (e as Map<String, dynamic>)['name'] as String? ?? '',
rank: (e)['rank'] as String? ?? 'I', rank: (e)['rank'] as String? ?? 'I',
), ),
@@ -261,7 +261,7 @@ class GameSave {
stats: stats, stats: stats,
inventory: inventory, inventory: inventory,
equipment: equipment, equipment: equipment,
spellBook: spellBook, skillBook: skillBook,
progress: progress, progress: progress,
queue: queue, queue: queue,
); );

View File

@@ -172,7 +172,7 @@ class _ArenaBattleScreenState extends State<ArenaBattleScreen>
message: '${widget.match.challenger.characterName} uses ' message: '${widget.match.challenger.characterName} uses '
'${turn.challengerSkillUsed}!', '${turn.challengerSkillUsed}!',
timestamp: DateTime.now(), timestamp: DateTime.now(),
type: CombatLogType.spell, type: CombatLogType.skill,
)); ));
} }
@@ -223,7 +223,7 @@ class _ArenaBattleScreenState extends State<ArenaBattleScreen>
message: '${widget.match.opponent.characterName} uses ' message: '${widget.match.opponent.characterName} uses '
'${turn.opponentSkillUsed}!', '${turn.opponentSkillUsed}!',
timestamp: DateTime.now(), timestamp: DateTime.now(),
type: CombatLogType.spell, type: CombatLogType.skill,
)); ));
} }

View File

@@ -366,7 +366,7 @@ class _GamePlayScreenState extends State<GamePlayScreen>
) )
: ( : (
game_l10n.combatSkillDamage(skillName, event.damage), game_l10n.combatSkillDamage(skillName, event.damage),
CombatLogType.spell, CombatLogType.skill,
), ),
CombatEventType.playerHeal => ( CombatEventType.playerHeal => (
game_l10n.combatSkillHeal( game_l10n.combatSkillHeal(
@@ -1327,11 +1327,11 @@ class _GamePlayScreenState extends State<GamePlayScreen>
); );
} }
/// 통합 스킬 목록 (SpellBook 기반) /// 통합 스킬 목록 (SkillBook 기반)
/// ///
/// 스 이름, 랭크, 스킬 타입, 쿨타임 표시 /// 스 이름, 랭크, 스킬 타입, 쿨타임 표시
Widget _buildSkillsList(GameState state) { Widget _buildSkillsList(GameState state) {
if (state.spellBook.spells.isEmpty) { if (state.skillBook.skills.isEmpty) {
return Center( return Center(
child: Text( child: Text(
L10n.of(context).noSpellsYet, L10n.of(context).noSpellsYet,
@@ -1345,12 +1345,12 @@ class _GamePlayScreenState extends State<GamePlayScreen>
} }
return ListView.builder( return ListView.builder(
itemCount: state.spellBook.spells.length, itemCount: state.skillBook.skills.length,
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final spell = state.spellBook.spells[index]; final skillEntry = state.skillBook.skills[index];
final skill = SkillData.getSkillBySpellName(spell.name); final skill = SkillData.getSkillBySpellName(skillEntry.name);
final spellName = GameDataL10n.getSpellName(context, spell.name); final skillName = GameDataL10n.getSpellName(context, skillEntry.name);
// 쿨타임 상태 확인 // 쿨타임 상태 확인
final skillState = skill != null final skillState = skill != null
@@ -1361,8 +1361,8 @@ class _GamePlayScreenState extends State<GamePlayScreen>
!skillState.isReady(state.skillSystem.elapsedMs, skill!.cooldownMs); !skillState.isReady(state.skillSystem.elapsedMs, skill!.cooldownMs);
return _SkillRow( return _SkillRow(
spellName: spellName, skillName: skillName,
rank: spell.rank, rank: skillEntry.rank,
skill: skill, skill: skill,
isOnCooldown: isOnCooldown, isOnCooldown: isOnCooldown,
); );
@@ -1615,16 +1615,16 @@ class _GamePlayScreenState extends State<GamePlayScreen>
/// 스킬 행 위젯 /// 스킬 행 위젯
/// ///
/// 스 이름, 랭크, 스킬 타입 아이콘, 쿨타임 상태 표시 /// 스 이름, 랭크, 스킬 타입 아이콘, 쿨타임 상태 표시
class _SkillRow extends StatelessWidget { class _SkillRow extends StatelessWidget {
const _SkillRow({ const _SkillRow({
required this.spellName, required this.skillName,
required this.rank, required this.rank,
required this.skill, required this.skill,
required this.isOnCooldown, required this.isOnCooldown,
}); });
final String spellName; final String skillName;
final String rank; final String rank;
final Skill? skill; final Skill? skill;
final bool isOnCooldown; final bool isOnCooldown;
@@ -1641,7 +1641,7 @@ class _SkillRow extends StatelessWidget {
// 스킬 이름 // 스킬 이름
Expanded( Expanded(
child: Text( child: Text(
spellName, skillName,
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 11,
color: isOnCooldown ? Colors.grey : null, color: isOnCooldown ? Colors.grey : null,

View File

@@ -678,7 +678,7 @@ class _MobileCarouselLayoutState extends State<MobileCarouselLayout> {
children: [ children: [
// 0: 스킬 // 0: 스킬
SkillsPage( SkillsPage(
spellBook: state.spellBook, skillBook: state.skillBook,
skillSystem: state.skillSystem, skillSystem: state.skillSystem,
), ),

View File

@@ -10,15 +10,15 @@ import 'package:asciineverdie/src/features/game/widgets/active_buff_panel.dart';
/// 스킬 페이지 (캐로셀) /// 스킬 페이지 (캐로셀)
/// ///
/// SpellBook 기반 스킬 목록과 활성 버프 표시. /// SkillBook 기반 스킬 목록과 활성 버프 표시.
class SkillsPage extends StatelessWidget { class SkillsPage extends StatelessWidget {
const SkillsPage({ const SkillsPage({
super.key, super.key,
required this.spellBook, required this.skillBook,
required this.skillSystem, required this.skillSystem,
}); });
final SpellBook spellBook; final SkillBook skillBook;
final SkillSystemState skillSystem; final SkillSystemState skillSystem;
@override @override
@@ -61,7 +61,7 @@ class SkillsPage extends StatelessWidget {
} }
Widget _buildSkillsList(BuildContext context) { Widget _buildSkillsList(BuildContext context) {
if (spellBook.spells.isEmpty) { if (skillBook.skills.isEmpty) {
return Center( return Center(
child: Text( child: Text(
L10n.of(context).noSpellsYet, L10n.of(context).noSpellsYet,
@@ -71,12 +71,12 @@ class SkillsPage extends StatelessWidget {
} }
return ListView.builder( return ListView.builder(
itemCount: spellBook.spells.length, itemCount: skillBook.skills.length,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final spell = spellBook.spells[index]; final skillEntry = skillBook.skills[index];
final skill = SkillData.getSkillBySpellName(spell.name); final skill = SkillData.getSkillBySpellName(skillEntry.name);
final spellName = GameDataL10n.getSpellName(context, spell.name); final skillName = GameDataL10n.getSpellName(context, skillEntry.name);
// 쿨타임 상태 확인 // 쿨타임 상태 확인
final skillState = skill != null final skillState = skill != null
@@ -87,8 +87,8 @@ class SkillsPage extends StatelessWidget {
!skillState.isReady(skillSystem.elapsedMs, skill!.cooldownMs); !skillState.isReady(skillSystem.elapsedMs, skill!.cooldownMs);
return _SkillRow( return _SkillRow(
spellName: spellName, skillName: skillName,
rank: spell.rank, rank: skillEntry.rank,
skill: skill, skill: skill,
isOnCooldown: isOnCooldown, isOnCooldown: isOnCooldown,
); );
@@ -100,13 +100,13 @@ class SkillsPage extends StatelessWidget {
/// 스킬 행 위젯 /// 스킬 행 위젯
class _SkillRow extends StatelessWidget { class _SkillRow extends StatelessWidget {
const _SkillRow({ const _SkillRow({
required this.spellName, required this.skillName,
required this.rank, required this.rank,
required this.skill, required this.skill,
required this.isOnCooldown, required this.isOnCooldown,
}); });
final String spellName; final String skillName;
final String rank; final String rank;
final Skill? skill; final Skill? skill;
final bool isOnCooldown; final bool isOnCooldown;
@@ -123,7 +123,7 @@ class _SkillRow extends StatelessWidget {
// 스킬 이름 // 스킬 이름
Expanded( Expanded(
child: Text( child: Text(
spellName, skillName,
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
color: isOnCooldown ? Colors.grey : null, color: isOnCooldown ? Colors.grey : null,

View File

@@ -21,7 +21,7 @@ enum CombatLogType {
levelUp, // 레벨업 levelUp, // 레벨업
questComplete, // 퀘스트 완료 questComplete, // 퀘스트 완료
loot, // 전리품 획득 loot, // 전리품 획득
spell, // 스킬 사용 skill, // 스킬 사용
critical, // 크리티컬 히트 critical, // 크리티컬 히트
evade, // 회피 evade, // 회피
block, // 방패 방어 block, // 방패 방어
@@ -157,7 +157,7 @@ class _LogEntryTile extends StatelessWidget {
CombatLogType.levelUp => (Colors.amber, Icons.arrow_upward), CombatLogType.levelUp => (Colors.amber, Icons.arrow_upward),
CombatLogType.questComplete => (Colors.blue.shade300, Icons.check_circle), CombatLogType.questComplete => (Colors.blue.shade300, Icons.check_circle),
CombatLogType.loot => (Colors.orange.shade300, Icons.inventory_2), CombatLogType.loot => (Colors.orange.shade300, Icons.inventory_2),
CombatLogType.spell => (Colors.purple.shade300, Icons.auto_fix_high), CombatLogType.skill => (Colors.purple.shade300, Icons.auto_fix_high),
CombatLogType.critical => (Colors.yellow.shade300, Icons.flash_on), CombatLogType.critical => (Colors.yellow.shade300, Icons.flash_on),
CombatLogType.evade => (Colors.cyan.shade300, Icons.directions_run), CombatLogType.evade => (Colors.cyan.shade300, Icons.directions_run),
CombatLogType.block => (Colors.blueGrey.shade300, Icons.shield), CombatLogType.block => (Colors.blueGrey.shade300, Icons.shield),

View File

@@ -516,12 +516,12 @@ class _HallOfFameDetailDialog extends StatelessWidget {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
], ],
// 스 섹션 (Spells Section) // 스 섹션 (Skills Section)
if (entry.finalSpells != null && entry.finalSpells!.isNotEmpty) if (entry.finalSkills != null && entry.finalSkills!.isNotEmpty)
_buildSection( _buildSection(
icon: Icons.auto_fix_high, icon: Icons.auto_fix_high,
title: l10n.hofSpells, title: l10n.hofSpells,
child: _buildSpellList(context), child: _buildSkillList(context),
), ),
], ],
), ),
@@ -983,15 +983,15 @@ class _HallOfFameDetailDialog extends StatelessWidget {
return widgets; return widgets;
} }
Widget _buildSpellList(BuildContext context) { Widget _buildSkillList(BuildContext context) {
final spells = entry.finalSpells!; final skills = entry.finalSkills!;
return Wrap( return Wrap(
spacing: 8, spacing: 8,
runSpacing: 4, runSpacing: 4,
children: spells.map((spell) { children: skills.map((skill) {
final name = spell['name'] ?? ''; final name = skill['name'] ?? '';
final rank = spell['rank'] ?? ''; final rank = skill['rank'] ?? '';
// 스 이름 번역 적용 // 스 이름 번역 적용
final translatedName = GameDataL10n.getSpellName(context, name); final translatedName = GameDataL10n.getSpellName(context, name);
return Container( return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),

View File

@@ -261,7 +261,7 @@ class _NewCharacterScreenState extends State<NewCharacterScreen> {
stats: finalStats, stats: finalStats,
inventory: const Inventory(gold: 0, items: []), inventory: const Inventory(gold: 0, items: []),
equipment: Equipment.empty(), equipment: Equipment.empty(),
spellBook: SpellBook.empty(), skillBook: SkillBook.empty(),
progress: ProgressState.empty(), progress: ProgressState.empty(),
queue: QueueState.empty(), queue: QueueState.empty(),
); );