diff --git a/lib/src/core/model/combat_stats.dart b/lib/src/core/model/combat_stats.dart index b416e27..89f7dc7 100644 --- a/lib/src/core/model/combat_stats.dart +++ b/lib/src/core/model/combat_stats.dart @@ -1,12 +1,18 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + import 'package:asciineverdie/src/core/model/class_traits.dart'; import 'package:asciineverdie/src/core/model/game_state.dart'; import 'package:asciineverdie/src/core/model/race_traits.dart'; +part 'combat_stats.freezed.dart'; +part 'combat_stats.g.dart'; + /// 전투용 파생 스탯 /// /// 기본 Stats와 Equipment를 기반으로 계산되는 전투 관련 수치. /// 불변(immutable) 객체로 설계되어 상태 변경 시 새 인스턴스 생성. -class CombatStats { +@freezed +class CombatStats with _$CombatStats { // ============================================================================ // 레벨 페널티 상수 (Phase 12) // ============================================================================ @@ -38,121 +44,65 @@ class CombatStats { // ============================================================================ /// 레벨 차이에 따른 확률 감소 배율 (플레이어 전용) - /// - /// - levelDiff = monsterLevel - playerLevel (몬스터가 높으면 양수) - /// - 0레벨 차이: 1.0 (100% 유지) - /// - 10레벨 이상 차이: 0.2 (20% = 최저) - /// - 상승 없음 (플레이어가 높아도 보너스 없음) static double _getLevelPenalty(int playerLevel, int monsterLevel) { final levelDiff = monsterLevel - playerLevel; - if (levelDiff <= 0) return 1.0; // 플레이어가 높거나 같으면 페널티 없음 - - // 1레벨당 8%씩 감소 (100% → 92% → 84% → ... → 20%) + if (levelDiff <= 0) return 1.0; final penalty = 1.0 - (levelDiff * _levelPenaltyPerLevel); return penalty.clamp(_minLevelMultiplier, 1.0); } - const CombatStats({ - // 기본 스탯 (Stats에서 복사) - required this.str, - required this.con, - required this.dex, - required this.intelligence, - required this.wis, - required this.cha, - // 파생 스탯 - required this.atk, - required this.def, - required this.magAtk, - required this.magDef, - required this.criRate, - required this.criDamage, - required this.evasion, - required this.accuracy, - required this.blockRate, - required this.parryRate, - required this.attackDelayMs, + const CombatStats._(); + + const factory CombatStats({ + // 기본 스탯 + /// 힘: 물리 공격력 보정 + required int str, + /// 체력: HP, 방어력 보정 + required int con, + /// 민첩: 회피율, 크리티컬율, 명중률, 공격 속도 + required int dex, + /// 지능: 마법 공격력, MP + required int intelligence, + /// 지혜: 마법 방어력, MP 회복 + required int wis, + /// 매력: 상점 가격, 드롭률 보정 + required int cha, + // 파생 스탯 (전투용) + /// 물리 공격력 + required int atk, + /// 물리 방어력 + required int def, + /// 마법 공격력 + required int magAtk, + /// 마법 방어력 + required int magDef, + /// 크리티컬 확률 (0.0 ~ 1.0) + required double criRate, + /// 크리티컬 데미지 배율 (1.5 ~ 3.0) + required double criDamage, + /// 회피율 (0.0 ~ 0.5) + required double evasion, + /// 명중률 (0.8 ~ 1.0) + required double accuracy, + /// 방패 방어율 (0.0 ~ 0.4) + required double blockRate, + /// 무기로 쳐내기 확률 (0.0 ~ 0.3) + required double parryRate, + /// 공격 딜레이 (밀리초) + required int attackDelayMs, // 자원 - required this.hpMax, - required this.hpCurrent, - required this.mpMax, - required this.mpCurrent, - }); + /// 최대 HP + required int hpMax, + /// 현재 HP + required int hpCurrent, + /// 최대 MP + required int mpMax, + /// 현재 MP + required int mpCurrent, + }) = _CombatStats; - // ============================================================================ - // 기본 스탯 - // ============================================================================ - - /// 힘: 물리 공격력 보정 - final int str; - - /// 체력: HP, 방어력 보정 - final int con; - - /// 민첩: 회피율, 크리티컬율, 명중률, 공격 속도 - final int dex; - - /// 지능: 마법 공격력, MP - final int intelligence; - - /// 지혜: 마법 방어력, MP 회복 - final int wis; - - /// 매력: 상점 가격, 드롭률 보정 - final int cha; - - // ============================================================================ - // 파생 스탯 (전투용) - // ============================================================================ - - /// 물리 공격력 - final int atk; - - /// 물리 방어력 - final int def; - - /// 마법 공격력 - final int magAtk; - - /// 마법 방어력 - final int magDef; - - /// 크리티컬 확률 (0.0 ~ 1.0) - final double criRate; - - /// 크리티컬 데미지 배율 (1.5 ~ 3.0) - final double criDamage; - - /// 회피율 (0.0 ~ 0.5) - final double evasion; - - /// 명중률 (0.8 ~ 1.0) - final double accuracy; - - /// 방패 방어율 (0.0 ~ 0.4) - final double blockRate; - - /// 무기로 쳐내기 확률 (0.0 ~ 0.3) - final double parryRate; - - /// 공격 딜레이 (밀리초) - final int attackDelayMs; - - // ============================================================================ - // 자원 - // ============================================================================ - - /// 최대 HP - final int hpMax; - - /// 현재 HP - final int hpCurrent; - - /// 최대 MP - final int mpMax; - - /// 현재 MP - final int mpCurrent; + factory CombatStats.fromJson(Map json) => + _$CombatStatsFromJson(json); // ============================================================================ // 유틸리티 @@ -190,66 +140,11 @@ class CombatStats { return withHp(hpCurrent + amount); } - CombatStats copyWith({ - int? str, - int? con, - int? dex, - int? intelligence, - int? wis, - int? cha, - int? atk, - int? def, - int? magAtk, - int? magDef, - double? criRate, - double? criDamage, - double? evasion, - double? accuracy, - double? blockRate, - double? parryRate, - int? attackDelayMs, - int? hpMax, - int? hpCurrent, - int? mpMax, - int? mpCurrent, - }) { - return CombatStats( - str: str ?? this.str, - con: con ?? this.con, - dex: dex ?? this.dex, - intelligence: intelligence ?? this.intelligence, - wis: wis ?? this.wis, - cha: cha ?? this.cha, - atk: atk ?? this.atk, - def: def ?? this.def, - magAtk: magAtk ?? this.magAtk, - magDef: magDef ?? this.magDef, - criRate: criRate ?? this.criRate, - criDamage: criDamage ?? this.criDamage, - evasion: evasion ?? this.evasion, - accuracy: accuracy ?? this.accuracy, - blockRate: blockRate ?? this.blockRate, - parryRate: parryRate ?? this.parryRate, - attackDelayMs: attackDelayMs ?? this.attackDelayMs, - hpMax: hpMax ?? this.hpMax, - hpCurrent: hpCurrent ?? this.hpCurrent, - mpMax: mpMax ?? this.mpMax, - mpCurrent: mpCurrent ?? this.mpCurrent, - ); - } - // ============================================================================ // 팩토리 메서드 // ============================================================================ /// Stats와 Equipment에서 CombatStats 생성 - /// - /// [stats] 캐릭터 기본 스탯 - /// [equipment] 장착 장비 (장비 스탯 적용) - /// [level] 캐릭터 레벨 (스케일링용) - /// [race] 종족 특성 (선택사항, Phase 5) - /// [klass] 클래스 특성 (선택사항, Phase 5) - /// [monsterLevel] 상대 몬스터 레벨 (레벨 페널티 계산용, Phase 12) factory CombatStats.fromStats({ required Stats stats, required Equipment equipment, @@ -321,7 +216,6 @@ class CombatStats { final parryRate = (baseParryRate + equipStats.parryRate).clamp(0.0, 0.4); // 공격 속도: 무기 기본 공속 + DEX 보정 - // 무기 attackSpeed가 0이면 기본값 1000ms 사용 final weaponItem = equipment.items[0]; // 무기 슬롯 final weaponSpeed = weaponItem.stats.attackSpeed; final baseAttackSpeed = weaponSpeed > 0 ? weaponSpeed : 1000; @@ -339,32 +233,27 @@ class CombatStats { // 종족 패시브 적용 (Phase 5) // ======================================================================== - // HP 보너스 (Heap Troll: +20%) final raceHpBonus = race?.getPassiveValue(PassiveType.hpBonus) ?? 0.0; if (raceHpBonus > 0) { totalHpMax = (totalHpMax * (1 + raceHpBonus)).round(); } - // MP 보너스 (Pointer Fairy: +20%) final raceMpBonus = race?.getPassiveValue(PassiveType.mpBonus) ?? 0.0; if (raceMpBonus > 0) { totalMpMax = (totalMpMax * (1 + raceMpBonus)).round(); } - // 마법 데미지 보너스 (Null Elf: +15%) final raceMagicBonus = race?.getPassiveValue(PassiveType.magicDamageBonus) ?? 0.0; if (raceMagicBonus > 0) { baseMagAtk = (baseMagAtk * (1 + raceMagicBonus)).round(); } - // 방어력 보너스 (Buffer Dwarf: +10%) final raceDefBonus = race?.getPassiveValue(PassiveType.defenseBonus) ?? 0.0; if (raceDefBonus > 0) { baseDef = (baseDef * (1 + raceDefBonus)).round(); } - // 크리티컬 보너스 (Stack Goblin: +5%) final raceCritBonus = race?.getPassiveValue(PassiveType.criticalBonus) ?? 0.0; criRate += raceCritBonus; @@ -373,40 +262,34 @@ class CombatStats { // 클래스 패시브 적용 (Phase 5) // ======================================================================== - // HP 보너스 (Garbage Collector: +30%) final classHpBonus = klass?.getPassiveValue(ClassPassiveType.hpBonus) ?? 0.0; if (classHpBonus > 0) { totalHpMax = (totalHpMax * (1 + classHpBonus)).round(); } - // 물리 공격력 보너스 (Bug Hunter: +20%) final classPhysBonus = klass?.getPassiveValue(ClassPassiveType.physicalDamageBonus) ?? 0.0; if (classPhysBonus > 0) { baseAtk = (baseAtk * (1 + classPhysBonus)).round(); } - // 방어력 보너스 (Debugger Paladin: +15%) final classDefBonus = klass?.getPassiveValue(ClassPassiveType.defenseBonus) ?? 0.0; if (classDefBonus > 0) { baseDef = (baseDef * (1 + classDefBonus)).round(); } - // 마법 데미지 보너스 (Compiler Mage: +25%) final classMagBonus = klass?.getPassiveValue(ClassPassiveType.magicDamageBonus) ?? 0.0; if (classMagBonus > 0) { baseMagAtk = (baseMagAtk * (1 + classMagBonus)).round(); } - // 회피율 보너스 (Refactor Monk: +15%) final classEvasionBonus = klass?.getPassiveValue(ClassPassiveType.evasionBonus) ?? 0.0; evasion += classEvasionBonus; - // 크리티컬 보너스 (Pointer Assassin: +20%) final classCritBonus = klass?.getPassiveValue(ClassPassiveType.criticalBonus) ?? 0.0; criRate += classCritBonus; @@ -415,13 +298,11 @@ class CombatStats { // 레벨 페널티 및 최종 클램핑 (Phase 12) // ======================================================================== - // 레벨 페널티 적용 (크리/회피/블록/패리) criRate *= levelPenalty; evasion *= levelPenalty; var finalBlockRate = blockRate * levelPenalty; var finalParryRate = parryRate * levelPenalty; - // 최종 클램핑 (새 캡 적용) criRate = criRate.clamp(0.05, _maxCriRate); evasion = evasion.clamp(0.0, _maxEvasion); finalBlockRate = finalBlockRate.clamp(0.0, _maxBlockRate); @@ -452,60 +333,6 @@ class CombatStats { ); } - /// JSON으로 직렬화 - Map toJson() { - return { - 'str': str, - 'con': con, - 'dex': dex, - 'intelligence': intelligence, - 'wis': wis, - 'cha': cha, - 'atk': atk, - 'def': def, - 'magAtk': magAtk, - 'magDef': magDef, - 'criRate': criRate, - 'criDamage': criDamage, - 'evasion': evasion, - 'accuracy': accuracy, - 'blockRate': blockRate, - 'parryRate': parryRate, - 'attackDelayMs': attackDelayMs, - 'hpMax': hpMax, - 'hpCurrent': hpCurrent, - 'mpMax': mpMax, - 'mpCurrent': mpCurrent, - }; - } - - /// JSON에서 역직렬화 - factory CombatStats.fromJson(Map json) { - return CombatStats( - str: json['str'] as int, - con: json['con'] as int, - dex: json['dex'] as int, - intelligence: json['intelligence'] as int, - wis: json['wis'] as int, - cha: json['cha'] as int, - atk: json['atk'] as int, - def: json['def'] as int, - magAtk: json['magAtk'] as int, - magDef: json['magDef'] as int, - criRate: (json['criRate'] as num).toDouble(), - criDamage: (json['criDamage'] as num).toDouble(), - evasion: (json['evasion'] as num).toDouble(), - accuracy: (json['accuracy'] as num).toDouble(), - blockRate: (json['blockRate'] as num).toDouble(), - parryRate: (json['parryRate'] as num).toDouble(), - attackDelayMs: json['attackDelayMs'] as int, - hpMax: json['hpMax'] as int, - hpCurrent: json['hpCurrent'] as int, - mpMax: json['mpMax'] as int, - mpCurrent: json['mpCurrent'] as int, - ); - } - /// 테스트/디버그용 기본값 factory CombatStats.empty() => const CombatStats( str: 10, diff --git a/lib/src/core/model/combat_stats.freezed.dart b/lib/src/core/model/combat_stats.freezed.dart new file mode 100644 index 0000000..5323237 --- /dev/null +++ b/lib/src/core/model/combat_stats.freezed.dart @@ -0,0 +1,733 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'combat_stats.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); + +CombatStats _$CombatStatsFromJson(Map json) { + return _CombatStats.fromJson(json); +} + +/// @nodoc +mixin _$CombatStats { + // 기본 스탯 + /// 힘: 물리 공격력 보정 + int get str => throw _privateConstructorUsedError; + + /// 체력: HP, 방어력 보정 + int get con => throw _privateConstructorUsedError; + + /// 민첩: 회피율, 크리티컬율, 명중률, 공격 속도 + int get dex => throw _privateConstructorUsedError; + + /// 지능: 마법 공격력, MP + int get intelligence => throw _privateConstructorUsedError; + + /// 지혜: 마법 방어력, MP 회복 + int get wis => throw _privateConstructorUsedError; + + /// 매력: 상점 가격, 드롭률 보정 + int get cha => throw _privateConstructorUsedError; // 파생 스탯 (전투용) + /// 물리 공격력 + int get atk => throw _privateConstructorUsedError; + + /// 물리 방어력 + int get def => throw _privateConstructorUsedError; + + /// 마법 공격력 + int get magAtk => throw _privateConstructorUsedError; + + /// 마법 방어력 + int get magDef => throw _privateConstructorUsedError; + + /// 크리티컬 확률 (0.0 ~ 1.0) + double get criRate => throw _privateConstructorUsedError; + + /// 크리티컬 데미지 배율 (1.5 ~ 3.0) + double get criDamage => throw _privateConstructorUsedError; + + /// 회피율 (0.0 ~ 0.5) + double get evasion => throw _privateConstructorUsedError; + + /// 명중률 (0.8 ~ 1.0) + double get accuracy => throw _privateConstructorUsedError; + + /// 방패 방어율 (0.0 ~ 0.4) + double get blockRate => throw _privateConstructorUsedError; + + /// 무기로 쳐내기 확률 (0.0 ~ 0.3) + double get parryRate => throw _privateConstructorUsedError; + + /// 공격 딜레이 (밀리초) + int get attackDelayMs => throw _privateConstructorUsedError; // 자원 + /// 최대 HP + int get hpMax => throw _privateConstructorUsedError; + + /// 현재 HP + int get hpCurrent => throw _privateConstructorUsedError; + + /// 최대 MP + int get mpMax => throw _privateConstructorUsedError; + + /// 현재 MP + int get mpCurrent => throw _privateConstructorUsedError; + + /// Serializes this CombatStats to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of CombatStats + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $CombatStatsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CombatStatsCopyWith<$Res> { + factory $CombatStatsCopyWith( + CombatStats value, + $Res Function(CombatStats) then, + ) = _$CombatStatsCopyWithImpl<$Res, CombatStats>; + @useResult + $Res call({ + int str, + int con, + int dex, + int intelligence, + int wis, + int cha, + int atk, + int def, + int magAtk, + int magDef, + double criRate, + double criDamage, + double evasion, + double accuracy, + double blockRate, + double parryRate, + int attackDelayMs, + int hpMax, + int hpCurrent, + int mpMax, + int mpCurrent, + }); +} + +/// @nodoc +class _$CombatStatsCopyWithImpl<$Res, $Val extends CombatStats> + implements $CombatStatsCopyWith<$Res> { + _$CombatStatsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of CombatStats + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? str = null, + Object? con = null, + Object? dex = null, + Object? intelligence = null, + Object? wis = null, + Object? cha = null, + Object? atk = null, + Object? def = null, + Object? magAtk = null, + Object? magDef = null, + Object? criRate = null, + Object? criDamage = null, + Object? evasion = null, + Object? accuracy = null, + Object? blockRate = null, + Object? parryRate = null, + Object? attackDelayMs = null, + Object? hpMax = null, + Object? hpCurrent = null, + Object? mpMax = null, + Object? mpCurrent = null, + }) { + return _then( + _value.copyWith( + str: null == str + ? _value.str + : str // ignore: cast_nullable_to_non_nullable + as int, + con: null == con + ? _value.con + : con // ignore: cast_nullable_to_non_nullable + as int, + dex: null == dex + ? _value.dex + : dex // ignore: cast_nullable_to_non_nullable + as int, + intelligence: null == intelligence + ? _value.intelligence + : intelligence // ignore: cast_nullable_to_non_nullable + as int, + wis: null == wis + ? _value.wis + : wis // ignore: cast_nullable_to_non_nullable + as int, + cha: null == cha + ? _value.cha + : cha // ignore: cast_nullable_to_non_nullable + as int, + atk: null == atk + ? _value.atk + : atk // ignore: cast_nullable_to_non_nullable + as int, + def: null == def + ? _value.def + : def // ignore: cast_nullable_to_non_nullable + as int, + magAtk: null == magAtk + ? _value.magAtk + : magAtk // ignore: cast_nullable_to_non_nullable + as int, + magDef: null == magDef + ? _value.magDef + : magDef // ignore: cast_nullable_to_non_nullable + as int, + criRate: null == criRate + ? _value.criRate + : criRate // ignore: cast_nullable_to_non_nullable + as double, + criDamage: null == criDamage + ? _value.criDamage + : criDamage // ignore: cast_nullable_to_non_nullable + as double, + evasion: null == evasion + ? _value.evasion + : evasion // ignore: cast_nullable_to_non_nullable + as double, + accuracy: null == accuracy + ? _value.accuracy + : accuracy // ignore: cast_nullable_to_non_nullable + as double, + blockRate: null == blockRate + ? _value.blockRate + : blockRate // ignore: cast_nullable_to_non_nullable + as double, + parryRate: null == parryRate + ? _value.parryRate + : parryRate // ignore: cast_nullable_to_non_nullable + as double, + attackDelayMs: null == attackDelayMs + ? _value.attackDelayMs + : attackDelayMs // ignore: cast_nullable_to_non_nullable + as int, + hpMax: null == hpMax + ? _value.hpMax + : hpMax // ignore: cast_nullable_to_non_nullable + as int, + hpCurrent: null == hpCurrent + ? _value.hpCurrent + : hpCurrent // ignore: cast_nullable_to_non_nullable + as int, + mpMax: null == mpMax + ? _value.mpMax + : mpMax // ignore: cast_nullable_to_non_nullable + as int, + mpCurrent: null == mpCurrent + ? _value.mpCurrent + : mpCurrent // ignore: cast_nullable_to_non_nullable + as int, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$CombatStatsImplCopyWith<$Res> + implements $CombatStatsCopyWith<$Res> { + factory _$$CombatStatsImplCopyWith( + _$CombatStatsImpl value, + $Res Function(_$CombatStatsImpl) then, + ) = __$$CombatStatsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + int str, + int con, + int dex, + int intelligence, + int wis, + int cha, + int atk, + int def, + int magAtk, + int magDef, + double criRate, + double criDamage, + double evasion, + double accuracy, + double blockRate, + double parryRate, + int attackDelayMs, + int hpMax, + int hpCurrent, + int mpMax, + int mpCurrent, + }); +} + +/// @nodoc +class __$$CombatStatsImplCopyWithImpl<$Res> + extends _$CombatStatsCopyWithImpl<$Res, _$CombatStatsImpl> + implements _$$CombatStatsImplCopyWith<$Res> { + __$$CombatStatsImplCopyWithImpl( + _$CombatStatsImpl _value, + $Res Function(_$CombatStatsImpl) _then, + ) : super(_value, _then); + + /// Create a copy of CombatStats + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? str = null, + Object? con = null, + Object? dex = null, + Object? intelligence = null, + Object? wis = null, + Object? cha = null, + Object? atk = null, + Object? def = null, + Object? magAtk = null, + Object? magDef = null, + Object? criRate = null, + Object? criDamage = null, + Object? evasion = null, + Object? accuracy = null, + Object? blockRate = null, + Object? parryRate = null, + Object? attackDelayMs = null, + Object? hpMax = null, + Object? hpCurrent = null, + Object? mpMax = null, + Object? mpCurrent = null, + }) { + return _then( + _$CombatStatsImpl( + str: null == str + ? _value.str + : str // ignore: cast_nullable_to_non_nullable + as int, + con: null == con + ? _value.con + : con // ignore: cast_nullable_to_non_nullable + as int, + dex: null == dex + ? _value.dex + : dex // ignore: cast_nullable_to_non_nullable + as int, + intelligence: null == intelligence + ? _value.intelligence + : intelligence // ignore: cast_nullable_to_non_nullable + as int, + wis: null == wis + ? _value.wis + : wis // ignore: cast_nullable_to_non_nullable + as int, + cha: null == cha + ? _value.cha + : cha // ignore: cast_nullable_to_non_nullable + as int, + atk: null == atk + ? _value.atk + : atk // ignore: cast_nullable_to_non_nullable + as int, + def: null == def + ? _value.def + : def // ignore: cast_nullable_to_non_nullable + as int, + magAtk: null == magAtk + ? _value.magAtk + : magAtk // ignore: cast_nullable_to_non_nullable + as int, + magDef: null == magDef + ? _value.magDef + : magDef // ignore: cast_nullable_to_non_nullable + as int, + criRate: null == criRate + ? _value.criRate + : criRate // ignore: cast_nullable_to_non_nullable + as double, + criDamage: null == criDamage + ? _value.criDamage + : criDamage // ignore: cast_nullable_to_non_nullable + as double, + evasion: null == evasion + ? _value.evasion + : evasion // ignore: cast_nullable_to_non_nullable + as double, + accuracy: null == accuracy + ? _value.accuracy + : accuracy // ignore: cast_nullable_to_non_nullable + as double, + blockRate: null == blockRate + ? _value.blockRate + : blockRate // ignore: cast_nullable_to_non_nullable + as double, + parryRate: null == parryRate + ? _value.parryRate + : parryRate // ignore: cast_nullable_to_non_nullable + as double, + attackDelayMs: null == attackDelayMs + ? _value.attackDelayMs + : attackDelayMs // ignore: cast_nullable_to_non_nullable + as int, + hpMax: null == hpMax + ? _value.hpMax + : hpMax // ignore: cast_nullable_to_non_nullable + as int, + hpCurrent: null == hpCurrent + ? _value.hpCurrent + : hpCurrent // ignore: cast_nullable_to_non_nullable + as int, + mpMax: null == mpMax + ? _value.mpMax + : mpMax // ignore: cast_nullable_to_non_nullable + as int, + mpCurrent: null == mpCurrent + ? _value.mpCurrent + : mpCurrent // ignore: cast_nullable_to_non_nullable + as int, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$CombatStatsImpl extends _CombatStats { + const _$CombatStatsImpl({ + required this.str, + required this.con, + required this.dex, + required this.intelligence, + required this.wis, + required this.cha, + required this.atk, + required this.def, + required this.magAtk, + required this.magDef, + required this.criRate, + required this.criDamage, + required this.evasion, + required this.accuracy, + required this.blockRate, + required this.parryRate, + required this.attackDelayMs, + required this.hpMax, + required this.hpCurrent, + required this.mpMax, + required this.mpCurrent, + }) : super._(); + + factory _$CombatStatsImpl.fromJson(Map json) => + _$$CombatStatsImplFromJson(json); + + // 기본 스탯 + /// 힘: 물리 공격력 보정 + @override + final int str; + + /// 체력: HP, 방어력 보정 + @override + final int con; + + /// 민첩: 회피율, 크리티컬율, 명중률, 공격 속도 + @override + final int dex; + + /// 지능: 마법 공격력, MP + @override + final int intelligence; + + /// 지혜: 마법 방어력, MP 회복 + @override + final int wis; + + /// 매력: 상점 가격, 드롭률 보정 + @override + final int cha; + // 파생 스탯 (전투용) + /// 물리 공격력 + @override + final int atk; + + /// 물리 방어력 + @override + final int def; + + /// 마법 공격력 + @override + final int magAtk; + + /// 마법 방어력 + @override + final int magDef; + + /// 크리티컬 확률 (0.0 ~ 1.0) + @override + final double criRate; + + /// 크리티컬 데미지 배율 (1.5 ~ 3.0) + @override + final double criDamage; + + /// 회피율 (0.0 ~ 0.5) + @override + final double evasion; + + /// 명중률 (0.8 ~ 1.0) + @override + final double accuracy; + + /// 방패 방어율 (0.0 ~ 0.4) + @override + final double blockRate; + + /// 무기로 쳐내기 확률 (0.0 ~ 0.3) + @override + final double parryRate; + + /// 공격 딜레이 (밀리초) + @override + final int attackDelayMs; + // 자원 + /// 최대 HP + @override + final int hpMax; + + /// 현재 HP + @override + final int hpCurrent; + + /// 최대 MP + @override + final int mpMax; + + /// 현재 MP + @override + final int mpCurrent; + + @override + String toString() { + return 'CombatStats(str: $str, con: $con, dex: $dex, intelligence: $intelligence, wis: $wis, cha: $cha, atk: $atk, def: $def, magAtk: $magAtk, magDef: $magDef, criRate: $criRate, criDamage: $criDamage, evasion: $evasion, accuracy: $accuracy, blockRate: $blockRate, parryRate: $parryRate, attackDelayMs: $attackDelayMs, hpMax: $hpMax, hpCurrent: $hpCurrent, mpMax: $mpMax, mpCurrent: $mpCurrent)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$CombatStatsImpl && + (identical(other.str, str) || other.str == str) && + (identical(other.con, con) || other.con == con) && + (identical(other.dex, dex) || other.dex == dex) && + (identical(other.intelligence, intelligence) || + other.intelligence == intelligence) && + (identical(other.wis, wis) || other.wis == wis) && + (identical(other.cha, cha) || other.cha == cha) && + (identical(other.atk, atk) || other.atk == atk) && + (identical(other.def, def) || other.def == def) && + (identical(other.magAtk, magAtk) || other.magAtk == magAtk) && + (identical(other.magDef, magDef) || other.magDef == magDef) && + (identical(other.criRate, criRate) || other.criRate == criRate) && + (identical(other.criDamage, criDamage) || + other.criDamage == criDamage) && + (identical(other.evasion, evasion) || other.evasion == evasion) && + (identical(other.accuracy, accuracy) || + other.accuracy == accuracy) && + (identical(other.blockRate, blockRate) || + other.blockRate == blockRate) && + (identical(other.parryRate, parryRate) || + other.parryRate == parryRate) && + (identical(other.attackDelayMs, attackDelayMs) || + other.attackDelayMs == attackDelayMs) && + (identical(other.hpMax, hpMax) || other.hpMax == hpMax) && + (identical(other.hpCurrent, hpCurrent) || + other.hpCurrent == hpCurrent) && + (identical(other.mpMax, mpMax) || other.mpMax == mpMax) && + (identical(other.mpCurrent, mpCurrent) || + other.mpCurrent == mpCurrent)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hashAll([ + runtimeType, + str, + con, + dex, + intelligence, + wis, + cha, + atk, + def, + magAtk, + magDef, + criRate, + criDamage, + evasion, + accuracy, + blockRate, + parryRate, + attackDelayMs, + hpMax, + hpCurrent, + mpMax, + mpCurrent, + ]); + + /// Create a copy of CombatStats + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$CombatStatsImplCopyWith<_$CombatStatsImpl> get copyWith => + __$$CombatStatsImplCopyWithImpl<_$CombatStatsImpl>(this, _$identity); + + @override + Map toJson() { + return _$$CombatStatsImplToJson(this); + } +} + +abstract class _CombatStats extends CombatStats { + const factory _CombatStats({ + required final int str, + required final int con, + required final int dex, + required final int intelligence, + required final int wis, + required final int cha, + required final int atk, + required final int def, + required final int magAtk, + required final int magDef, + required final double criRate, + required final double criDamage, + required final double evasion, + required final double accuracy, + required final double blockRate, + required final double parryRate, + required final int attackDelayMs, + required final int hpMax, + required final int hpCurrent, + required final int mpMax, + required final int mpCurrent, + }) = _$CombatStatsImpl; + const _CombatStats._() : super._(); + + factory _CombatStats.fromJson(Map json) = + _$CombatStatsImpl.fromJson; + + // 기본 스탯 + /// 힘: 물리 공격력 보정 + @override + int get str; + + /// 체력: HP, 방어력 보정 + @override + int get con; + + /// 민첩: 회피율, 크리티컬율, 명중률, 공격 속도 + @override + int get dex; + + /// 지능: 마법 공격력, MP + @override + int get intelligence; + + /// 지혜: 마법 방어력, MP 회복 + @override + int get wis; + + /// 매력: 상점 가격, 드롭률 보정 + @override + int get cha; // 파생 스탯 (전투용) + /// 물리 공격력 + @override + int get atk; + + /// 물리 방어력 + @override + int get def; + + /// 마법 공격력 + @override + int get magAtk; + + /// 마법 방어력 + @override + int get magDef; + + /// 크리티컬 확률 (0.0 ~ 1.0) + @override + double get criRate; + + /// 크리티컬 데미지 배율 (1.5 ~ 3.0) + @override + double get criDamage; + + /// 회피율 (0.0 ~ 0.5) + @override + double get evasion; + + /// 명중률 (0.8 ~ 1.0) + @override + double get accuracy; + + /// 방패 방어율 (0.0 ~ 0.4) + @override + double get blockRate; + + /// 무기로 쳐내기 확률 (0.0 ~ 0.3) + @override + double get parryRate; + + /// 공격 딜레이 (밀리초) + @override + int get attackDelayMs; // 자원 + /// 최대 HP + @override + int get hpMax; + + /// 현재 HP + @override + int get hpCurrent; + + /// 최대 MP + @override + int get mpMax; + + /// 현재 MP + @override + int get mpCurrent; + + /// Create a copy of CombatStats + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$CombatStatsImplCopyWith<_$CombatStatsImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/src/core/model/combat_stats.g.dart b/lib/src/core/model/combat_stats.g.dart new file mode 100644 index 0000000..0c65cd9 --- /dev/null +++ b/lib/src/core/model/combat_stats.g.dart @@ -0,0 +1,57 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'combat_stats.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$CombatStatsImpl _$$CombatStatsImplFromJson(Map json) => + _$CombatStatsImpl( + str: (json['str'] as num).toInt(), + con: (json['con'] as num).toInt(), + dex: (json['dex'] as num).toInt(), + intelligence: (json['intelligence'] as num).toInt(), + wis: (json['wis'] as num).toInt(), + cha: (json['cha'] as num).toInt(), + atk: (json['atk'] as num).toInt(), + def: (json['def'] as num).toInt(), + magAtk: (json['magAtk'] as num).toInt(), + magDef: (json['magDef'] as num).toInt(), + criRate: (json['criRate'] as num).toDouble(), + criDamage: (json['criDamage'] as num).toDouble(), + evasion: (json['evasion'] as num).toDouble(), + accuracy: (json['accuracy'] as num).toDouble(), + blockRate: (json['blockRate'] as num).toDouble(), + parryRate: (json['parryRate'] as num).toDouble(), + attackDelayMs: (json['attackDelayMs'] as num).toInt(), + hpMax: (json['hpMax'] as num).toInt(), + hpCurrent: (json['hpCurrent'] as num).toInt(), + mpMax: (json['mpMax'] as num).toInt(), + mpCurrent: (json['mpCurrent'] as num).toInt(), + ); + +Map _$$CombatStatsImplToJson(_$CombatStatsImpl instance) => + { + 'str': instance.str, + 'con': instance.con, + 'dex': instance.dex, + 'intelligence': instance.intelligence, + 'wis': instance.wis, + 'cha': instance.cha, + 'atk': instance.atk, + 'def': instance.def, + 'magAtk': instance.magAtk, + 'magDef': instance.magDef, + 'criRate': instance.criRate, + 'criDamage': instance.criDamage, + 'evasion': instance.evasion, + 'accuracy': instance.accuracy, + 'blockRate': instance.blockRate, + 'parryRate': instance.parryRate, + 'attackDelayMs': instance.attackDelayMs, + 'hpMax': instance.hpMax, + 'hpCurrent': instance.hpCurrent, + 'mpMax': instance.mpMax, + 'mpCurrent': instance.mpCurrent, + }; diff --git a/lib/src/core/model/equipment_item.dart b/lib/src/core/model/equipment_item.dart index 303fa8c..738bf81 100644 --- a/lib/src/core/model/equipment_item.dart +++ b/lib/src/core/model/equipment_item.dart @@ -1,51 +1,38 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + import 'package:asciineverdie/src/core/model/equipment_slot.dart'; import 'package:asciineverdie/src/core/model/item_stats.dart'; +part 'equipment_item.freezed.dart'; +part 'equipment_item.g.dart'; + /// 장비 아이템 /// /// 개별 장비의 이름, 슬롯, 레벨, 스탯 등을 포함하는 클래스. /// 불변(immutable) 객체로 설계됨. -class EquipmentItem { - const EquipmentItem({ - required this.name, - required this.slot, - required this.level, - required this.weight, - required this.stats, - required this.rarity, - }); +@freezed +class EquipmentItem with _$EquipmentItem { + const EquipmentItem._(); - /// 아이템 이름 (예: "Flaming Sword of Doom") - final String name; + const factory EquipmentItem({ + /// 아이템 이름 (예: "Flaming Sword of Doom") + required String name, + /// 장착 슬롯 + @JsonKey(fromJson: _slotFromJson, toJson: _slotToJson) + required EquipmentSlot slot, + /// 아이템 레벨 + required int level, + /// 무게 (STR 기반 휴대 제한용) + required int weight, + /// 아이템 스탯 보정치 + required ItemStats stats, + /// 희귀도 + @JsonKey(fromJson: _rarityFromJson, toJson: _rarityToJson) + required ItemRarity rarity, + }) = _EquipmentItem; - /// 장착 슬롯 - 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.fromJson(Map json) => + _$EquipmentItemFromJson(json); /// 빈 아이템 생성 (특정 슬롯) factory EquipmentItem.empty(EquipmentSlot slot) { @@ -54,7 +41,7 @@ class EquipmentItem { slot: slot, level: 0, weight: 0, - stats: ItemStats.empty, + stats: const ItemStats(), rarity: ItemRarity.common, ); } @@ -71,59 +58,39 @@ class EquipmentItem { ); } - 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, - ); + /// 가중치 (자동 장착 비교용) + /// + /// 가중치 = 기본값 + (레벨 * 10) + (희귀도 보너스) + (스탯 합계) + int get itemWeight { + const baseValue = 10; + return baseValue + (level * 10) + rarity.weightBonus + stats.totalStatValue; } - /// JSON으로 직렬화 - Map toJson() { - return { - 'name': name, - 'slot': slot.name, - 'level': level, - 'weight': weight, - 'stats': stats.toJson(), - 'rarity': rarity.name, - }; - } + /// 빈 아이템 여부 + bool get isEmpty => name.isEmpty; - /// JSON에서 역직렬화 - factory EquipmentItem.fromJson(Map 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) - : ItemStats.empty, - rarity: ItemRarity.values.firstWhere( - (r) => r.name == rarityName, - orElse: () => ItemRarity.common, - ), - ); - } + /// 유효한 아이템 여부 + bool get isNotEmpty => name.isNotEmpty; @override String toString() => name.isEmpty ? '(empty)' : name; } + +// JSON 변환 헬퍼 (세이브 파일 호환성 유지) +EquipmentSlot _slotFromJson(String? value) { + return EquipmentSlot.values.firstWhere( + (s) => s.name == value, + orElse: () => EquipmentSlot.weapon, + ); +} + +String _slotToJson(EquipmentSlot slot) => slot.name; + +ItemRarity _rarityFromJson(String? value) { + return ItemRarity.values.firstWhere( + (r) => r.name == value, + orElse: () => ItemRarity.common, + ); +} + +String _rarityToJson(ItemRarity rarity) => rarity.name; diff --git a/lib/src/core/model/equipment_item.freezed.dart b/lib/src/core/model/equipment_item.freezed.dart new file mode 100644 index 0000000..e888b72 --- /dev/null +++ b/lib/src/core/model/equipment_item.freezed.dart @@ -0,0 +1,335 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'equipment_item.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); + +EquipmentItem _$EquipmentItemFromJson(Map json) { + return _EquipmentItem.fromJson(json); +} + +/// @nodoc +mixin _$EquipmentItem { + /// 아이템 이름 (예: "Flaming Sword of Doom") + String get name => throw _privateConstructorUsedError; + + /// 장착 슬롯 + @JsonKey(fromJson: _slotFromJson, toJson: _slotToJson) + EquipmentSlot get slot => throw _privateConstructorUsedError; + + /// 아이템 레벨 + int get level => throw _privateConstructorUsedError; + + /// 무게 (STR 기반 휴대 제한용) + int get weight => throw _privateConstructorUsedError; + + /// 아이템 스탯 보정치 + ItemStats get stats => throw _privateConstructorUsedError; + + /// 희귀도 + @JsonKey(fromJson: _rarityFromJson, toJson: _rarityToJson) + ItemRarity get rarity => throw _privateConstructorUsedError; + + /// Serializes this EquipmentItem to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of EquipmentItem + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $EquipmentItemCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $EquipmentItemCopyWith<$Res> { + factory $EquipmentItemCopyWith( + EquipmentItem value, + $Res Function(EquipmentItem) then, + ) = _$EquipmentItemCopyWithImpl<$Res, EquipmentItem>; + @useResult + $Res call({ + String name, + @JsonKey(fromJson: _slotFromJson, toJson: _slotToJson) EquipmentSlot slot, + int level, + int weight, + ItemStats stats, + @JsonKey(fromJson: _rarityFromJson, toJson: _rarityToJson) + ItemRarity rarity, + }); + + $ItemStatsCopyWith<$Res> get stats; +} + +/// @nodoc +class _$EquipmentItemCopyWithImpl<$Res, $Val extends EquipmentItem> + implements $EquipmentItemCopyWith<$Res> { + _$EquipmentItemCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of EquipmentItem + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? slot = null, + Object? level = null, + Object? weight = null, + Object? stats = null, + Object? rarity = null, + }) { + return _then( + _value.copyWith( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + slot: null == slot + ? _value.slot + : slot // ignore: cast_nullable_to_non_nullable + as EquipmentSlot, + level: null == level + ? _value.level + : level // ignore: cast_nullable_to_non_nullable + as int, + weight: null == weight + ? _value.weight + : weight // ignore: cast_nullable_to_non_nullable + as int, + stats: null == stats + ? _value.stats + : stats // ignore: cast_nullable_to_non_nullable + as ItemStats, + rarity: null == rarity + ? _value.rarity + : rarity // ignore: cast_nullable_to_non_nullable + as ItemRarity, + ) + as $Val, + ); + } + + /// Create a copy of EquipmentItem + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $ItemStatsCopyWith<$Res> get stats { + return $ItemStatsCopyWith<$Res>(_value.stats, (value) { + return _then(_value.copyWith(stats: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$EquipmentItemImplCopyWith<$Res> + implements $EquipmentItemCopyWith<$Res> { + factory _$$EquipmentItemImplCopyWith( + _$EquipmentItemImpl value, + $Res Function(_$EquipmentItemImpl) then, + ) = __$$EquipmentItemImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + String name, + @JsonKey(fromJson: _slotFromJson, toJson: _slotToJson) EquipmentSlot slot, + int level, + int weight, + ItemStats stats, + @JsonKey(fromJson: _rarityFromJson, toJson: _rarityToJson) + ItemRarity rarity, + }); + + @override + $ItemStatsCopyWith<$Res> get stats; +} + +/// @nodoc +class __$$EquipmentItemImplCopyWithImpl<$Res> + extends _$EquipmentItemCopyWithImpl<$Res, _$EquipmentItemImpl> + implements _$$EquipmentItemImplCopyWith<$Res> { + __$$EquipmentItemImplCopyWithImpl( + _$EquipmentItemImpl _value, + $Res Function(_$EquipmentItemImpl) _then, + ) : super(_value, _then); + + /// Create a copy of EquipmentItem + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? slot = null, + Object? level = null, + Object? weight = null, + Object? stats = null, + Object? rarity = null, + }) { + return _then( + _$EquipmentItemImpl( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + slot: null == slot + ? _value.slot + : slot // ignore: cast_nullable_to_non_nullable + as EquipmentSlot, + level: null == level + ? _value.level + : level // ignore: cast_nullable_to_non_nullable + as int, + weight: null == weight + ? _value.weight + : weight // ignore: cast_nullable_to_non_nullable + as int, + stats: null == stats + ? _value.stats + : stats // ignore: cast_nullable_to_non_nullable + as ItemStats, + rarity: null == rarity + ? _value.rarity + : rarity // ignore: cast_nullable_to_non_nullable + as ItemRarity, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$EquipmentItemImpl extends _EquipmentItem { + const _$EquipmentItemImpl({ + required this.name, + @JsonKey(fromJson: _slotFromJson, toJson: _slotToJson) required this.slot, + required this.level, + required this.weight, + required this.stats, + @JsonKey(fromJson: _rarityFromJson, toJson: _rarityToJson) + required this.rarity, + }) : super._(); + + factory _$EquipmentItemImpl.fromJson(Map json) => + _$$EquipmentItemImplFromJson(json); + + /// 아이템 이름 (예: "Flaming Sword of Doom") + @override + final String name; + + /// 장착 슬롯 + @override + @JsonKey(fromJson: _slotFromJson, toJson: _slotToJson) + final EquipmentSlot slot; + + /// 아이템 레벨 + @override + final int level; + + /// 무게 (STR 기반 휴대 제한용) + @override + final int weight; + + /// 아이템 스탯 보정치 + @override + final ItemStats stats; + + /// 희귀도 + @override + @JsonKey(fromJson: _rarityFromJson, toJson: _rarityToJson) + final ItemRarity rarity; + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$EquipmentItemImpl && + (identical(other.name, name) || other.name == name) && + (identical(other.slot, slot) || other.slot == slot) && + (identical(other.level, level) || other.level == level) && + (identical(other.weight, weight) || other.weight == weight) && + (identical(other.stats, stats) || other.stats == stats) && + (identical(other.rarity, rarity) || other.rarity == rarity)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => + Object.hash(runtimeType, name, slot, level, weight, stats, rarity); + + /// Create a copy of EquipmentItem + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$EquipmentItemImplCopyWith<_$EquipmentItemImpl> get copyWith => + __$$EquipmentItemImplCopyWithImpl<_$EquipmentItemImpl>(this, _$identity); + + @override + Map toJson() { + return _$$EquipmentItemImplToJson(this); + } +} + +abstract class _EquipmentItem extends EquipmentItem { + const factory _EquipmentItem({ + required final String name, + @JsonKey(fromJson: _slotFromJson, toJson: _slotToJson) + required final EquipmentSlot slot, + required final int level, + required final int weight, + required final ItemStats stats, + @JsonKey(fromJson: _rarityFromJson, toJson: _rarityToJson) + required final ItemRarity rarity, + }) = _$EquipmentItemImpl; + const _EquipmentItem._() : super._(); + + factory _EquipmentItem.fromJson(Map json) = + _$EquipmentItemImpl.fromJson; + + /// 아이템 이름 (예: "Flaming Sword of Doom") + @override + String get name; + + /// 장착 슬롯 + @override + @JsonKey(fromJson: _slotFromJson, toJson: _slotToJson) + EquipmentSlot get slot; + + /// 아이템 레벨 + @override + int get level; + + /// 무게 (STR 기반 휴대 제한용) + @override + int get weight; + + /// 아이템 스탯 보정치 + @override + ItemStats get stats; + + /// 희귀도 + @override + @JsonKey(fromJson: _rarityFromJson, toJson: _rarityToJson) + ItemRarity get rarity; + + /// Create a copy of EquipmentItem + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$EquipmentItemImplCopyWith<_$EquipmentItemImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/src/core/model/equipment_item.g.dart b/lib/src/core/model/equipment_item.g.dart new file mode 100644 index 0000000..cda0004 --- /dev/null +++ b/lib/src/core/model/equipment_item.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'equipment_item.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$EquipmentItemImpl _$$EquipmentItemImplFromJson(Map json) => + _$EquipmentItemImpl( + name: json['name'] as String, + slot: _slotFromJson(json['slot'] as String?), + level: (json['level'] as num).toInt(), + weight: (json['weight'] as num).toInt(), + stats: ItemStats.fromJson(json['stats'] as Map), + rarity: _rarityFromJson(json['rarity'] as String?), + ); + +Map _$$EquipmentItemImplToJson(_$EquipmentItemImpl instance) => + { + 'name': instance.name, + 'slot': _slotToJson(instance.slot), + 'level': instance.level, + 'weight': instance.weight, + 'stats': instance.stats, + 'rarity': _rarityToJson(instance.rarity), + }; diff --git a/lib/src/core/model/item_stats.dart b/lib/src/core/model/item_stats.dart index 75eff1c..18adcde 100644 --- a/lib/src/core/model/item_stats.dart +++ b/lib/src/core/model/item_stats.dart @@ -1,3 +1,8 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'item_stats.freezed.dart'; +part 'item_stats.g.dart'; + /// 아이템 희귀도 enum ItemRarity { common, @@ -29,80 +34,55 @@ enum ItemRarity { /// /// 장비 아이템이 제공하는 스탯 보너스. /// 모든 값은 기본 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, - }); +@freezed +class ItemStats with _$ItemStats { + const ItemStats._(); - /// 물리 공격력 보정 - final int atk; + const factory ItemStats({ + /// 물리 공격력 보정 + @Default(0) int atk, + /// 물리 방어력 보정 + @Default(0) int def, + /// 마법 공격력 보정 + @Default(0) int magAtk, + /// 마법 방어력 보정 + @Default(0) int magDef, + /// 크리티컬 확률 보정 (0.0 ~ 1.0) + @Default(0.0) double criRate, + /// 회피율 보정 (0.0 ~ 1.0) + @Default(0.0) double evasion, + /// 방패 방어율 (방패 전용, 0.0 ~ 1.0) + @Default(0.0) double blockRate, + /// 무기 쳐내기 확률 (무기 전용, 0.0 ~ 1.0) + @Default(0.0) double parryRate, + /// HP 보너스 + @Default(0) int hpBonus, + /// MP 보너스 + @Default(0) int mpBonus, + /// STR 보너스 + @Default(0) int strBonus, + /// CON 보너스 + @Default(0) int conBonus, + /// DEX 보너스 + @Default(0) int dexBonus, + /// INT 보너스 + @Default(0) int intBonus, + /// WIS 보너스 + @Default(0) int wisBonus, + /// CHA 보너스 + @Default(0) int chaBonus, + /// 무기 공격속도 (밀리초, 무기 전용) + /// + /// 0이면 기본값(1000ms) 사용, 값이 클수록 느린 공격. + /// 느린 무기는 높은 기본 데미지를 가짐. + @Default(0) int attackSpeed, + }) = _ItemStats; - /// 물리 방어력 보정 - final int def; + factory ItemStats.fromJson(Map json) => + _$ItemStatsFromJson(json); - /// 마법 공격력 보정 - 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; + /// 빈 스탯 (보너스 없음) + static const empty = ItemStats(); /// 스탯 합계 (가중치 계산용) int get totalStatValue { @@ -124,55 +104,6 @@ class ItemStats { chaBonus * 5; } - /// 빈 스탯 (보너스 없음) - static const empty = ItemStats(); - - /// JSON으로 직렬화 - Map 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 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는 합산 대상 아님 (무기 슬롯 단일 값) @@ -197,44 +128,4 @@ class ItemStats { // 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, - ); - } } diff --git a/lib/src/core/model/item_stats.freezed.dart b/lib/src/core/model/item_stats.freezed.dart new file mode 100644 index 0000000..ec7c54b --- /dev/null +++ b/lib/src/core/model/item_stats.freezed.dart @@ -0,0 +1,651 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'item_stats.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); + +ItemStats _$ItemStatsFromJson(Map json) { + return _ItemStats.fromJson(json); +} + +/// @nodoc +mixin _$ItemStats { + /// 물리 공격력 보정 + int get atk => throw _privateConstructorUsedError; + + /// 물리 방어력 보정 + int get def => throw _privateConstructorUsedError; + + /// 마법 공격력 보정 + int get magAtk => throw _privateConstructorUsedError; + + /// 마법 방어력 보정 + int get magDef => throw _privateConstructorUsedError; + + /// 크리티컬 확률 보정 (0.0 ~ 1.0) + double get criRate => throw _privateConstructorUsedError; + + /// 회피율 보정 (0.0 ~ 1.0) + double get evasion => throw _privateConstructorUsedError; + + /// 방패 방어율 (방패 전용, 0.0 ~ 1.0) + double get blockRate => throw _privateConstructorUsedError; + + /// 무기 쳐내기 확률 (무기 전용, 0.0 ~ 1.0) + double get parryRate => throw _privateConstructorUsedError; + + /// HP 보너스 + int get hpBonus => throw _privateConstructorUsedError; + + /// MP 보너스 + int get mpBonus => throw _privateConstructorUsedError; + + /// STR 보너스 + int get strBonus => throw _privateConstructorUsedError; + + /// CON 보너스 + int get conBonus => throw _privateConstructorUsedError; + + /// DEX 보너스 + int get dexBonus => throw _privateConstructorUsedError; + + /// INT 보너스 + int get intBonus => throw _privateConstructorUsedError; + + /// WIS 보너스 + int get wisBonus => throw _privateConstructorUsedError; + + /// CHA 보너스 + int get chaBonus => throw _privateConstructorUsedError; + + /// 무기 공격속도 (밀리초, 무기 전용) + /// + /// 0이면 기본값(1000ms) 사용, 값이 클수록 느린 공격. + /// 느린 무기는 높은 기본 데미지를 가짐. + int get attackSpeed => throw _privateConstructorUsedError; + + /// Serializes this ItemStats to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ItemStats + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ItemStatsCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ItemStatsCopyWith<$Res> { + factory $ItemStatsCopyWith(ItemStats value, $Res Function(ItemStats) then) = + _$ItemStatsCopyWithImpl<$Res, ItemStats>; + @useResult + $Res call({ + 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, + }); +} + +/// @nodoc +class _$ItemStatsCopyWithImpl<$Res, $Val extends ItemStats> + implements $ItemStatsCopyWith<$Res> { + _$ItemStatsCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ItemStats + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? atk = null, + Object? def = null, + Object? magAtk = null, + Object? magDef = null, + Object? criRate = null, + Object? evasion = null, + Object? blockRate = null, + Object? parryRate = null, + Object? hpBonus = null, + Object? mpBonus = null, + Object? strBonus = null, + Object? conBonus = null, + Object? dexBonus = null, + Object? intBonus = null, + Object? wisBonus = null, + Object? chaBonus = null, + Object? attackSpeed = null, + }) { + return _then( + _value.copyWith( + atk: null == atk + ? _value.atk + : atk // ignore: cast_nullable_to_non_nullable + as int, + def: null == def + ? _value.def + : def // ignore: cast_nullable_to_non_nullable + as int, + magAtk: null == magAtk + ? _value.magAtk + : magAtk // ignore: cast_nullable_to_non_nullable + as int, + magDef: null == magDef + ? _value.magDef + : magDef // ignore: cast_nullable_to_non_nullable + as int, + criRate: null == criRate + ? _value.criRate + : criRate // ignore: cast_nullable_to_non_nullable + as double, + evasion: null == evasion + ? _value.evasion + : evasion // ignore: cast_nullable_to_non_nullable + as double, + blockRate: null == blockRate + ? _value.blockRate + : blockRate // ignore: cast_nullable_to_non_nullable + as double, + parryRate: null == parryRate + ? _value.parryRate + : parryRate // ignore: cast_nullable_to_non_nullable + as double, + hpBonus: null == hpBonus + ? _value.hpBonus + : hpBonus // ignore: cast_nullable_to_non_nullable + as int, + mpBonus: null == mpBonus + ? _value.mpBonus + : mpBonus // ignore: cast_nullable_to_non_nullable + as int, + strBonus: null == strBonus + ? _value.strBonus + : strBonus // ignore: cast_nullable_to_non_nullable + as int, + conBonus: null == conBonus + ? _value.conBonus + : conBonus // ignore: cast_nullable_to_non_nullable + as int, + dexBonus: null == dexBonus + ? _value.dexBonus + : dexBonus // ignore: cast_nullable_to_non_nullable + as int, + intBonus: null == intBonus + ? _value.intBonus + : intBonus // ignore: cast_nullable_to_non_nullable + as int, + wisBonus: null == wisBonus + ? _value.wisBonus + : wisBonus // ignore: cast_nullable_to_non_nullable + as int, + chaBonus: null == chaBonus + ? _value.chaBonus + : chaBonus // ignore: cast_nullable_to_non_nullable + as int, + attackSpeed: null == attackSpeed + ? _value.attackSpeed + : attackSpeed // ignore: cast_nullable_to_non_nullable + as int, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$ItemStatsImplCopyWith<$Res> + implements $ItemStatsCopyWith<$Res> { + factory _$$ItemStatsImplCopyWith( + _$ItemStatsImpl value, + $Res Function(_$ItemStatsImpl) then, + ) = __$$ItemStatsImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + 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, + }); +} + +/// @nodoc +class __$$ItemStatsImplCopyWithImpl<$Res> + extends _$ItemStatsCopyWithImpl<$Res, _$ItemStatsImpl> + implements _$$ItemStatsImplCopyWith<$Res> { + __$$ItemStatsImplCopyWithImpl( + _$ItemStatsImpl _value, + $Res Function(_$ItemStatsImpl) _then, + ) : super(_value, _then); + + /// Create a copy of ItemStats + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? atk = null, + Object? def = null, + Object? magAtk = null, + Object? magDef = null, + Object? criRate = null, + Object? evasion = null, + Object? blockRate = null, + Object? parryRate = null, + Object? hpBonus = null, + Object? mpBonus = null, + Object? strBonus = null, + Object? conBonus = null, + Object? dexBonus = null, + Object? intBonus = null, + Object? wisBonus = null, + Object? chaBonus = null, + Object? attackSpeed = null, + }) { + return _then( + _$ItemStatsImpl( + atk: null == atk + ? _value.atk + : atk // ignore: cast_nullable_to_non_nullable + as int, + def: null == def + ? _value.def + : def // ignore: cast_nullable_to_non_nullable + as int, + magAtk: null == magAtk + ? _value.magAtk + : magAtk // ignore: cast_nullable_to_non_nullable + as int, + magDef: null == magDef + ? _value.magDef + : magDef // ignore: cast_nullable_to_non_nullable + as int, + criRate: null == criRate + ? _value.criRate + : criRate // ignore: cast_nullable_to_non_nullable + as double, + evasion: null == evasion + ? _value.evasion + : evasion // ignore: cast_nullable_to_non_nullable + as double, + blockRate: null == blockRate + ? _value.blockRate + : blockRate // ignore: cast_nullable_to_non_nullable + as double, + parryRate: null == parryRate + ? _value.parryRate + : parryRate // ignore: cast_nullable_to_non_nullable + as double, + hpBonus: null == hpBonus + ? _value.hpBonus + : hpBonus // ignore: cast_nullable_to_non_nullable + as int, + mpBonus: null == mpBonus + ? _value.mpBonus + : mpBonus // ignore: cast_nullable_to_non_nullable + as int, + strBonus: null == strBonus + ? _value.strBonus + : strBonus // ignore: cast_nullable_to_non_nullable + as int, + conBonus: null == conBonus + ? _value.conBonus + : conBonus // ignore: cast_nullable_to_non_nullable + as int, + dexBonus: null == dexBonus + ? _value.dexBonus + : dexBonus // ignore: cast_nullable_to_non_nullable + as int, + intBonus: null == intBonus + ? _value.intBonus + : intBonus // ignore: cast_nullable_to_non_nullable + as int, + wisBonus: null == wisBonus + ? _value.wisBonus + : wisBonus // ignore: cast_nullable_to_non_nullable + as int, + chaBonus: null == chaBonus + ? _value.chaBonus + : chaBonus // ignore: cast_nullable_to_non_nullable + as int, + attackSpeed: null == attackSpeed + ? _value.attackSpeed + : attackSpeed // ignore: cast_nullable_to_non_nullable + as int, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$ItemStatsImpl extends _ItemStats { + const _$ItemStatsImpl({ + 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, + }) : super._(); + + factory _$ItemStatsImpl.fromJson(Map json) => + _$$ItemStatsImplFromJson(json); + + /// 물리 공격력 보정 + @override + @JsonKey() + final int atk; + + /// 물리 방어력 보정 + @override + @JsonKey() + final int def; + + /// 마법 공격력 보정 + @override + @JsonKey() + final int magAtk; + + /// 마법 방어력 보정 + @override + @JsonKey() + final int magDef; + + /// 크리티컬 확률 보정 (0.0 ~ 1.0) + @override + @JsonKey() + final double criRate; + + /// 회피율 보정 (0.0 ~ 1.0) + @override + @JsonKey() + final double evasion; + + /// 방패 방어율 (방패 전용, 0.0 ~ 1.0) + @override + @JsonKey() + final double blockRate; + + /// 무기 쳐내기 확률 (무기 전용, 0.0 ~ 1.0) + @override + @JsonKey() + final double parryRate; + + /// HP 보너스 + @override + @JsonKey() + final int hpBonus; + + /// MP 보너스 + @override + @JsonKey() + final int mpBonus; + + /// STR 보너스 + @override + @JsonKey() + final int strBonus; + + /// CON 보너스 + @override + @JsonKey() + final int conBonus; + + /// DEX 보너스 + @override + @JsonKey() + final int dexBonus; + + /// INT 보너스 + @override + @JsonKey() + final int intBonus; + + /// WIS 보너스 + @override + @JsonKey() + final int wisBonus; + + /// CHA 보너스 + @override + @JsonKey() + final int chaBonus; + + /// 무기 공격속도 (밀리초, 무기 전용) + /// + /// 0이면 기본값(1000ms) 사용, 값이 클수록 느린 공격. + /// 느린 무기는 높은 기본 데미지를 가짐. + @override + @JsonKey() + final int attackSpeed; + + @override + String toString() { + return 'ItemStats(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)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ItemStatsImpl && + (identical(other.atk, atk) || other.atk == atk) && + (identical(other.def, def) || other.def == def) && + (identical(other.magAtk, magAtk) || other.magAtk == magAtk) && + (identical(other.magDef, magDef) || other.magDef == magDef) && + (identical(other.criRate, criRate) || other.criRate == criRate) && + (identical(other.evasion, evasion) || other.evasion == evasion) && + (identical(other.blockRate, blockRate) || + other.blockRate == blockRate) && + (identical(other.parryRate, parryRate) || + other.parryRate == parryRate) && + (identical(other.hpBonus, hpBonus) || other.hpBonus == hpBonus) && + (identical(other.mpBonus, mpBonus) || other.mpBonus == mpBonus) && + (identical(other.strBonus, strBonus) || + other.strBonus == strBonus) && + (identical(other.conBonus, conBonus) || + other.conBonus == conBonus) && + (identical(other.dexBonus, dexBonus) || + other.dexBonus == dexBonus) && + (identical(other.intBonus, intBonus) || + other.intBonus == intBonus) && + (identical(other.wisBonus, wisBonus) || + other.wisBonus == wisBonus) && + (identical(other.chaBonus, chaBonus) || + other.chaBonus == chaBonus) && + (identical(other.attackSpeed, attackSpeed) || + other.attackSpeed == attackSpeed)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + atk, + def, + magAtk, + magDef, + criRate, + evasion, + blockRate, + parryRate, + hpBonus, + mpBonus, + strBonus, + conBonus, + dexBonus, + intBonus, + wisBonus, + chaBonus, + attackSpeed, + ); + + /// Create a copy of ItemStats + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ItemStatsImplCopyWith<_$ItemStatsImpl> get copyWith => + __$$ItemStatsImplCopyWithImpl<_$ItemStatsImpl>(this, _$identity); + + @override + Map toJson() { + return _$$ItemStatsImplToJson(this); + } +} + +abstract class _ItemStats extends ItemStats { + const factory _ItemStats({ + final int atk, + final int def, + final int magAtk, + final int magDef, + final double criRate, + final double evasion, + final double blockRate, + final double parryRate, + final int hpBonus, + final int mpBonus, + final int strBonus, + final int conBonus, + final int dexBonus, + final int intBonus, + final int wisBonus, + final int chaBonus, + final int attackSpeed, + }) = _$ItemStatsImpl; + const _ItemStats._() : super._(); + + factory _ItemStats.fromJson(Map json) = + _$ItemStatsImpl.fromJson; + + /// 물리 공격력 보정 + @override + int get atk; + + /// 물리 방어력 보정 + @override + int get def; + + /// 마법 공격력 보정 + @override + int get magAtk; + + /// 마법 방어력 보정 + @override + int get magDef; + + /// 크리티컬 확률 보정 (0.0 ~ 1.0) + @override + double get criRate; + + /// 회피율 보정 (0.0 ~ 1.0) + @override + double get evasion; + + /// 방패 방어율 (방패 전용, 0.0 ~ 1.0) + @override + double get blockRate; + + /// 무기 쳐내기 확률 (무기 전용, 0.0 ~ 1.0) + @override + double get parryRate; + + /// HP 보너스 + @override + int get hpBonus; + + /// MP 보너스 + @override + int get mpBonus; + + /// STR 보너스 + @override + int get strBonus; + + /// CON 보너스 + @override + int get conBonus; + + /// DEX 보너스 + @override + int get dexBonus; + + /// INT 보너스 + @override + int get intBonus; + + /// WIS 보너스 + @override + int get wisBonus; + + /// CHA 보너스 + @override + int get chaBonus; + + /// 무기 공격속도 (밀리초, 무기 전용) + /// + /// 0이면 기본값(1000ms) 사용, 값이 클수록 느린 공격. + /// 느린 무기는 높은 기본 데미지를 가짐. + @override + int get attackSpeed; + + /// Create a copy of ItemStats + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ItemStatsImplCopyWith<_$ItemStatsImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/src/core/model/item_stats.g.dart b/lib/src/core/model/item_stats.g.dart new file mode 100644 index 0000000..d589ff6 --- /dev/null +++ b/lib/src/core/model/item_stats.g.dart @@ -0,0 +1,49 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'item_stats.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ItemStatsImpl _$$ItemStatsImplFromJson(Map json) => + _$ItemStatsImpl( + atk: (json['atk'] as num?)?.toInt() ?? 0, + def: (json['def'] as num?)?.toInt() ?? 0, + magAtk: (json['magAtk'] as num?)?.toInt() ?? 0, + magDef: (json['magDef'] as num?)?.toInt() ?? 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 num?)?.toInt() ?? 0, + mpBonus: (json['mpBonus'] as num?)?.toInt() ?? 0, + strBonus: (json['strBonus'] as num?)?.toInt() ?? 0, + conBonus: (json['conBonus'] as num?)?.toInt() ?? 0, + dexBonus: (json['dexBonus'] as num?)?.toInt() ?? 0, + intBonus: (json['intBonus'] as num?)?.toInt() ?? 0, + wisBonus: (json['wisBonus'] as num?)?.toInt() ?? 0, + chaBonus: (json['chaBonus'] as num?)?.toInt() ?? 0, + attackSpeed: (json['attackSpeed'] as num?)?.toInt() ?? 0, + ); + +Map _$$ItemStatsImplToJson(_$ItemStatsImpl instance) => + { + 'atk': instance.atk, + 'def': instance.def, + 'magAtk': instance.magAtk, + 'magDef': instance.magDef, + 'criRate': instance.criRate, + 'evasion': instance.evasion, + 'blockRate': instance.blockRate, + 'parryRate': instance.parryRate, + 'hpBonus': instance.hpBonus, + 'mpBonus': instance.mpBonus, + 'strBonus': instance.strBonus, + 'conBonus': instance.conBonus, + 'dexBonus': instance.dexBonus, + 'intBonus': instance.intBonus, + 'wisBonus': instance.wisBonus, + 'chaBonus': instance.chaBonus, + 'attackSpeed': instance.attackSpeed, + }; diff --git a/pubspec.lock b/pubspec.lock index f6040db..586b05d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,22 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f + url: "https://pub.dev" + source: hosted + version: "85.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d" + url: "https://pub.dev" + source: hosted + version: "7.7.1" archive: dependency: transitive description: @@ -41,6 +57,70 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + build: + dependency: transitive + description: + name: build + sha256: "51dc711996cbf609b90cbe5b335bbce83143875a9d58e4b5c6d3c4f684d3dda7" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + build_config: + dependency: transitive + description: + name: build_config + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957 + url: "https://pub.dev" + source: hosted + version: "4.1.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: ee4257b3f20c0c90e72ed2b57ad637f694ccba48839a821e87db762548c22a62 + url: "https://pub.dev" + source: hosted + version: "2.5.4" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "382a4d649addbfb7ba71a3631df0ec6a45d5ab9b098638144faf27f02778eb53" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "85fbbb1036d576d966332a3f5ce83f2ce66a40bea1a94ad2d5fc29a19a0d3792" + url: "https://pub.dev" + source: hosted + version: "9.1.2" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "7931c90b84bc573fef103548e354258ae4c9d28d140e41961df6843c5d60d4d8" + url: "https://pub.dev" + source: hosted + version: "8.12.3" characters: dependency: transitive description: @@ -73,6 +153,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "6a6cab2ba4680d6423f34a9b972a4c9a94ebe1b62ecec4e1a1f2cba91fd1319d" + url: "https://pub.dev" + source: hosted + version: "4.11.1" collection: dependency: transitive description: @@ -81,6 +169,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" crypto: dependency: transitive description: @@ -97,6 +193,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" + url: "https://pub.dev" + source: hosted + version: "3.1.1" fake_async: dependency: "direct dev" description: @@ -165,6 +269,70 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: "59a584c24b3acdc5250bb856d0d3e9c0b798ed14a4af1ddb7dc1c7b41df91c9c" + url: "https://pub.dev" + source: hosted + version: "2.5.8" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 + url: "https://pub.dev" + source: hosted + version: "2.4.4" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + http: + dependency: transitive + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" image: dependency: transitive description: @@ -181,14 +349,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.20.2" - json_annotation: + io: dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + js: + dependency: transitive + description: + name: js + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + json_annotation: + dependency: "direct main" description: name: json_annotation sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted version: "4.9.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c + url: "https://pub.dev" + source: hosted + version: "6.9.5" just_audio: dependency: "direct main" description: @@ -245,6 +437,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.1.1" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" matcher: dependency: transitive description: @@ -269,6 +469,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.16.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" path: dependency: transitive description: @@ -349,6 +565,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pool: + dependency: transitive + description: + name: pool + sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + url: "https://pub.dev" + source: hosted + version: "1.5.2" posix: dependency: transitive description: @@ -357,6 +581,22 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.3" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" rxdart: dependency: transitive description: @@ -421,11 +661,43 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.1" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" + source: hosted + version: "3.0.0" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.0" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: a447acb083d3a5ef17f983dd36201aeea33fedadb3228fa831f2f0c92f0f3aca + url: "https://pub.dev" + source: hosted + version: "1.3.7" source_span: dependency: transitive description: @@ -450,6 +722,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" string_scanner: dependency: transitive description: @@ -482,6 +762,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.6" + timing: + dependency: transitive + description: + name: timing + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" + source: hosted + version: "1.0.2" typed_data: dependency: transitive description: @@ -514,6 +802,14 @@ packages: url: "https://pub.dev" source: hosted version: "15.0.2" + watcher: + dependency: transitive + description: + name: watcher + sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635" + url: "https://pub.dev" + source: hosted + version: "1.2.1" web: dependency: transitive description: @@ -522,6 +818,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9f5d0bf..8b3926f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,11 +38,18 @@ dependencies: path_provider: ^2.1.4 shared_preferences: ^2.3.1 just_audio: ^0.9.42 + # Code generation annotations + freezed_annotation: ^2.4.1 + json_annotation: ^4.9.0 dev_dependencies: flutter_test: sdk: flutter fake_async: ^1.3.2 + # Code generation + build_runner: ^2.4.13 + freezed: ^2.5.7 + json_serializable: ^6.8.0 # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is