feat(item): Phase 2 아이템 시스템 구현

- ItemStats, ItemRarity 클래스 추가 (아이템 스탯/희귀도)
- EquipmentItem 클래스 추가 (개별 장비 아이템)
- ItemService 추가 (아이템 생성/관리/무게 시스템)
- Equipment 클래스 확장 (EquipmentItem 기반, 기존 API 호환)
- CombatStats에서 장비 스탯 반영
- 레거시 세이브 파일 호환성 유지
This commit is contained in:
JiWoong Sul
2025-12-17 16:57:23 +09:00
parent c62687f7bd
commit 6a696ecd57
6 changed files with 726 additions and 122 deletions

View File

@@ -0,0 +1,94 @@
import 'package:askiineverdie/src/core/model/equipment_slot.dart';
import 'package:askiineverdie/src/core/model/item_stats.dart';
/// 장비 아이템
///
/// 개별 장비의 이름, 슬롯, 레벨, 스탯 등을 포함하는 클래스.
/// 불변(immutable) 객체로 설계됨.
class EquipmentItem {
const EquipmentItem({
required this.name,
required this.slot,
required this.level,
required this.weight,
required this.stats,
required this.rarity,
});
/// 아이템 이름 (예: "Flaming Sword of Doom")
final String name;
/// 장착 슬롯
final EquipmentSlot slot;
/// 아이템 레벨
final int level;
/// 무게 (STR 기반 휴대 제한용)
final int weight;
/// 아이템 스탯 보정치
final ItemStats stats;
/// 희귀도
final ItemRarity rarity;
/// 가중치 (자동 장착 비교용)
///
/// 가중치 = 기본값 + (레벨 * 10) + (희귀도 보너스) + (스탯 합계)
int get itemWeight {
const baseValue = 10;
return baseValue + (level * 10) + rarity.weightBonus + stats.totalStatValue;
}
/// 빈 아이템 여부
bool get isEmpty => name.isEmpty;
/// 유효한 아이템 여부
bool get isNotEmpty => name.isNotEmpty;
/// 빈 아이템 생성 (특정 슬롯)
factory EquipmentItem.empty(EquipmentSlot slot) {
return EquipmentItem(
name: '',
slot: slot,
level: 0,
weight: 0,
stats: ItemStats.empty,
rarity: ItemRarity.common,
);
}
/// 기본 무기 (Keyboard)
factory EquipmentItem.defaultWeapon() {
return const EquipmentItem(
name: 'Keyboard',
slot: EquipmentSlot.weapon,
level: 1,
weight: 5,
stats: ItemStats(atk: 1),
rarity: ItemRarity.common,
);
}
EquipmentItem copyWith({
String? name,
EquipmentSlot? slot,
int? level,
int? weight,
ItemStats? stats,
ItemRarity? rarity,
}) {
return EquipmentItem(
name: name ?? this.name,
slot: slot ?? this.slot,
level: level ?? this.level,
weight: weight ?? this.weight,
stats: stats ?? this.stats,
rarity: rarity ?? this.rarity,
);
}
@override
String toString() => name.isEmpty ? '(empty)' : name;
}