130 lines
3.2 KiB
Dart
130 lines
3.2 KiB
Dart
import 'package:asciineverdie/src/core/model/equipment_slot.dart';
|
|
import 'package:asciineverdie/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, attackSpeed: 1000),
|
|
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,
|
|
);
|
|
}
|
|
|
|
/// JSON으로 직렬화
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'name': name,
|
|
'slot': slot.name,
|
|
'level': level,
|
|
'weight': weight,
|
|
'stats': stats.toJson(),
|
|
'rarity': rarity.name,
|
|
};
|
|
}
|
|
|
|
/// JSON에서 역직렬화
|
|
factory EquipmentItem.fromJson(Map<String, dynamic> json) {
|
|
final slotName = json['slot'] as String? ?? 'weapon';
|
|
final rarityName = json['rarity'] as String? ?? 'common';
|
|
|
|
return EquipmentItem(
|
|
name: json['name'] as String? ?? '',
|
|
slot: EquipmentSlot.values.firstWhere(
|
|
(s) => s.name == slotName,
|
|
orElse: () => EquipmentSlot.weapon,
|
|
),
|
|
level: json['level'] as int? ?? 0,
|
|
weight: json['weight'] as int? ?? 0,
|
|
stats: json['stats'] != null
|
|
? ItemStats.fromJson(json['stats'] as Map<String, dynamic>)
|
|
: ItemStats.empty,
|
|
rarity: ItemRarity.values.firstWhere(
|
|
(r) => r.name == rarityName,
|
|
orElse: () => ItemRarity.common,
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
String toString() => name.isEmpty ? '(empty)' : name;
|
|
}
|