Files
asciinevrdie/lib/src/core/model/item_stats.dart
JiWoong Sul 5c8ab0d3f4 feat(core): 몬스터 등급 시스템 추가
- MonsterGrade 열거형 및 색상 정의
- GameState/ItemStats 확장
- pq_logic 유틸리티 함수 추가
- ASCII 색상 상수 추가
2026-01-05 17:52:47 +09:00

254 lines
6.5 KiB
Dart

import 'package:asciineverdie/src/core/animation/canvas/ascii_cell.dart';
/// 아이템 희귀도
enum ItemRarity {
common,
uncommon,
rare,
epic,
legendary;
/// 희귀도 배율 (스탯 계산용)
double get multiplier => switch (this) {
common => 1.0,
uncommon => 1.3,
rare => 1.7,
epic => 2.2,
legendary => 3.0,
};
/// 가중치 보너스
int get weightBonus => switch (this) {
common => 0,
uncommon => 50,
rare => 150,
epic => 400,
legendary => 1000,
};
/// 공격 이펙트 셀 색상 (Phase 9: 무기 등급별 이펙트)
///
/// common은 기본 positive(시안), 나머지는 등급별 고유 색상
AsciiCellColor get effectCellColor => switch (this) {
ItemRarity.common => AsciiCellColor.positive,
ItemRarity.uncommon => AsciiCellColor.rarityUncommon,
ItemRarity.rare => AsciiCellColor.rarityRare,
ItemRarity.epic => AsciiCellColor.rarityEpic,
ItemRarity.legendary => AsciiCellColor.rarityLegendary,
};
}
/// 아이템 스탯 보정치
///
/// 장비 아이템이 제공하는 스탯 보너스.
/// 모든 값은 기본 0이며, 장착 시 플레이어 스탯에 가산됨.
class ItemStats {
const ItemStats({
this.atk = 0,
this.def = 0,
this.magAtk = 0,
this.magDef = 0,
this.criRate = 0.0,
this.evasion = 0.0,
this.blockRate = 0.0,
this.parryRate = 0.0,
this.hpBonus = 0,
this.mpBonus = 0,
this.strBonus = 0,
this.conBonus = 0,
this.dexBonus = 0,
this.intBonus = 0,
this.wisBonus = 0,
this.chaBonus = 0,
this.attackSpeed = 0,
});
/// 물리 공격력 보정
final int atk;
/// 물리 방어력 보정
final int def;
/// 마법 공격력 보정
final int magAtk;
/// 마법 방어력 보정
final int magDef;
/// 크리티컬 확률 보정 (0.0 ~ 1.0)
final double criRate;
/// 회피율 보정 (0.0 ~ 1.0)
final double evasion;
/// 방패 방어율 (방패 전용, 0.0 ~ 1.0)
final double blockRate;
/// 무기 쳐내기 확률 (무기 전용, 0.0 ~ 1.0)
final double parryRate;
/// HP 보너스
final int hpBonus;
/// MP 보너스
final int mpBonus;
/// STR 보너스
final int strBonus;
/// CON 보너스
final int conBonus;
/// DEX 보너스
final int dexBonus;
/// INT 보너스
final int intBonus;
/// WIS 보너스
final int wisBonus;
/// CHA 보너스
final int chaBonus;
/// 무기 공격속도 (밀리초, 무기 전용)
///
/// 0이면 기본값(1000ms) 사용, 값이 클수록 느린 공격.
/// 느린 무기는 높은 기본 데미지를 가짐.
final int attackSpeed;
/// 스탯 합계 (가중치 계산용)
int get totalStatValue {
return atk +
def +
magAtk +
magDef +
(criRate * 100).round() +
(evasion * 100).round() +
(blockRate * 100).round() +
(parryRate * 100).round() +
hpBonus +
mpBonus +
strBonus * 5 +
conBonus * 5 +
dexBonus * 5 +
intBonus * 5 +
wisBonus * 5 +
chaBonus * 5;
}
/// 빈 스탯 (보너스 없음)
static const empty = ItemStats();
/// JSON으로 직렬화
Map<String, dynamic> toJson() {
return {
'atk': atk,
'def': def,
'magAtk': magAtk,
'magDef': magDef,
'criRate': criRate,
'evasion': evasion,
'blockRate': blockRate,
'parryRate': parryRate,
'hpBonus': hpBonus,
'mpBonus': mpBonus,
'strBonus': strBonus,
'conBonus': conBonus,
'dexBonus': dexBonus,
'intBonus': intBonus,
'wisBonus': wisBonus,
'chaBonus': chaBonus,
'attackSpeed': attackSpeed,
};
}
/// JSON에서 역직렬화
factory ItemStats.fromJson(Map<String, dynamic> json) {
return ItemStats(
atk: json['atk'] as int? ?? 0,
def: json['def'] as int? ?? 0,
magAtk: json['magAtk'] as int? ?? 0,
magDef: json['magDef'] as int? ?? 0,
criRate: (json['criRate'] as num?)?.toDouble() ?? 0.0,
evasion: (json['evasion'] as num?)?.toDouble() ?? 0.0,
blockRate: (json['blockRate'] as num?)?.toDouble() ?? 0.0,
parryRate: (json['parryRate'] as num?)?.toDouble() ?? 0.0,
hpBonus: json['hpBonus'] as int? ?? 0,
mpBonus: json['mpBonus'] as int? ?? 0,
strBonus: json['strBonus'] as int? ?? 0,
conBonus: json['conBonus'] as int? ?? 0,
dexBonus: json['dexBonus'] as int? ?? 0,
intBonus: json['intBonus'] as int? ?? 0,
wisBonus: json['wisBonus'] as int? ?? 0,
chaBonus: json['chaBonus'] as int? ?? 0,
attackSpeed: json['attackSpeed'] as int? ?? 0,
);
}
/// 두 스탯 합산
///
/// attackSpeed는 합산 대상 아님 (무기 슬롯 단일 값)
ItemStats operator +(ItemStats other) {
return ItemStats(
atk: atk + other.atk,
def: def + other.def,
magAtk: magAtk + other.magAtk,
magDef: magDef + other.magDef,
criRate: criRate + other.criRate,
evasion: evasion + other.evasion,
blockRate: blockRate + other.blockRate,
parryRate: parryRate + other.parryRate,
hpBonus: hpBonus + other.hpBonus,
mpBonus: mpBonus + other.mpBonus,
strBonus: strBonus + other.strBonus,
conBonus: conBonus + other.conBonus,
dexBonus: dexBonus + other.dexBonus,
intBonus: intBonus + other.intBonus,
wisBonus: wisBonus + other.wisBonus,
chaBonus: chaBonus + other.chaBonus,
// attackSpeed는 무기에서만 직접 참조
);
}
ItemStats copyWith({
int? atk,
int? def,
int? magAtk,
int? magDef,
double? criRate,
double? evasion,
double? blockRate,
double? parryRate,
int? hpBonus,
int? mpBonus,
int? strBonus,
int? conBonus,
int? dexBonus,
int? intBonus,
int? wisBonus,
int? chaBonus,
int? attackSpeed,
}) {
return ItemStats(
atk: atk ?? this.atk,
def: def ?? this.def,
magAtk: magAtk ?? this.magAtk,
magDef: magDef ?? this.magDef,
criRate: criRate ?? this.criRate,
evasion: evasion ?? this.evasion,
blockRate: blockRate ?? this.blockRate,
parryRate: parryRate ?? this.parryRate,
hpBonus: hpBonus ?? this.hpBonus,
mpBonus: mpBonus ?? this.mpBonus,
strBonus: strBonus ?? this.strBonus,
conBonus: conBonus ?? this.conBonus,
dexBonus: dexBonus ?? this.dexBonus,
intBonus: intBonus ?? this.intBonus,
wisBonus: wisBonus ?? this.wisBonus,
chaBonus: chaBonus ?? this.chaBonus,
attackSpeed: attackSpeed ?? this.attackSpeed,
);
}
}