fix(death): 사망 시 희생 아이템 선택 디버그 로그 추가
- 장비 슬롯 상태 콘솔 로그 추가 - resurrection_service에 lostItemSlot 설정 누락 수정 - resetBattleUsage 존재하지 않는 메서드 호출 제거
This commit is contained in:
@@ -7,7 +7,6 @@ import 'package:asciineverdie/src/core/model/combat_state.dart';
|
|||||||
import 'package:asciineverdie/src/core/model/combat_stats.dart';
|
import 'package:asciineverdie/src/core/model/combat_stats.dart';
|
||||||
import 'package:asciineverdie/src/core/model/game_state.dart';
|
import 'package:asciineverdie/src/core/model/game_state.dart';
|
||||||
import 'package:asciineverdie/src/core/model/monster_combat_stats.dart';
|
import 'package:asciineverdie/src/core/model/monster_combat_stats.dart';
|
||||||
import 'package:asciineverdie/src/core/model/potion.dart';
|
|
||||||
import 'package:asciineverdie/src/core/model/skill.dart';
|
import 'package:asciineverdie/src/core/model/skill.dart';
|
||||||
import 'package:asciineverdie/src/core/util/deterministic_random.dart';
|
import 'package:asciineverdie/src/core/util/deterministic_random.dart';
|
||||||
|
|
||||||
@@ -68,7 +67,7 @@ class CombatTickService {
|
|||||||
var turnsElapsed = combat.turnsElapsed;
|
var turnsElapsed = combat.turnsElapsed;
|
||||||
var updatedSkillSystem = skillSystem;
|
var updatedSkillSystem = skillSystem;
|
||||||
var activeDoTs = [...combat.activeDoTs];
|
var activeDoTs = [...combat.activeDoTs];
|
||||||
var usedPotionTypes = {...combat.usedPotionTypes};
|
var lastPotionUsedMs = combat.lastPotionUsedMs;
|
||||||
var activeDebuffs = [...combat.activeDebuffs];
|
var activeDebuffs = [...combat.activeDebuffs];
|
||||||
PotionInventory? updatedPotionInventory;
|
PotionInventory? updatedPotionInventory;
|
||||||
|
|
||||||
@@ -94,18 +93,18 @@ class CombatTickService {
|
|||||||
totalDamageDealt = dotResult.totalDamageDealt;
|
totalDamageDealt = dotResult.totalDamageDealt;
|
||||||
newEvents.addAll(dotResult.events);
|
newEvents.addAll(dotResult.events);
|
||||||
|
|
||||||
// 긴급 물약 자동 사용 (HP < 30%)
|
// 긴급 물약 자동 사용 (HP < 30% 또는 MP < 50%)
|
||||||
final potionResult = _tryEmergencyPotion(
|
final potionResult = _tryEmergencyPotion(
|
||||||
playerStats: playerStats,
|
playerStats: playerStats,
|
||||||
potionInventory: state.potionInventory,
|
potionInventory: state.potionInventory,
|
||||||
usedPotionTypes: usedPotionTypes,
|
lastPotionUsedMs: lastPotionUsedMs,
|
||||||
playerLevel: state.traits.level,
|
playerLevel: state.traits.level,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
potionService: potionService,
|
potionService: potionService,
|
||||||
);
|
);
|
||||||
if (potionResult != null) {
|
if (potionResult != null) {
|
||||||
playerStats = potionResult.playerStats;
|
playerStats = potionResult.playerStats;
|
||||||
usedPotionTypes = potionResult.usedPotionTypes;
|
lastPotionUsedMs = potionResult.lastPotionUsedMs;
|
||||||
updatedPotionInventory = potionResult.potionInventory;
|
updatedPotionInventory = potionResult.potionInventory;
|
||||||
newEvents.addAll(potionResult.events);
|
newEvents.addAll(potionResult.events);
|
||||||
}
|
}
|
||||||
@@ -176,7 +175,7 @@ class CombatTickService {
|
|||||||
isActive: isActive,
|
isActive: isActive,
|
||||||
recentEvents: recentEvents,
|
recentEvents: recentEvents,
|
||||||
activeDoTs: activeDoTs,
|
activeDoTs: activeDoTs,
|
||||||
usedPotionTypes: usedPotionTypes,
|
lastPotionUsedMs: lastPotionUsedMs,
|
||||||
activeDebuffs: activeDebuffs,
|
activeDebuffs: activeDebuffs,
|
||||||
),
|
),
|
||||||
skillSystem: updatedSkillSystem,
|
skillSystem: updatedSkillSystem,
|
||||||
@@ -246,38 +245,38 @@ class CombatTickService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 긴급 물약 자동 사용
|
/// 긴급 물약 자동 사용 (HP/MP 통합 글로벌 쿨타임)
|
||||||
({
|
({
|
||||||
CombatStats playerStats,
|
CombatStats playerStats,
|
||||||
Set<PotionType> usedPotionTypes,
|
int lastPotionUsedMs,
|
||||||
PotionInventory potionInventory,
|
PotionInventory potionInventory,
|
||||||
List<CombatEvent> events,
|
List<CombatEvent> events,
|
||||||
})? _tryEmergencyPotion({
|
})? _tryEmergencyPotion({
|
||||||
required CombatStats playerStats,
|
required CombatStats playerStats,
|
||||||
required PotionInventory potionInventory,
|
required PotionInventory potionInventory,
|
||||||
required Set<PotionType> usedPotionTypes,
|
required int lastPotionUsedMs,
|
||||||
required int playerLevel,
|
required int playerLevel,
|
||||||
required int timestamp,
|
required int timestamp,
|
||||||
required PotionService potionService,
|
required PotionService potionService,
|
||||||
}) {
|
}) {
|
||||||
final hpRatio = playerStats.hpCurrent / playerStats.hpMax;
|
// 글로벌 쿨타임 체크
|
||||||
if (hpRatio > PotionService.emergencyHpThreshold) {
|
if (timestamp - lastPotionUsedMs < PotionService.globalPotionCooldownMs) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final emergencyPotion = potionService.selectEmergencyHpPotion(
|
// 우선순위 1: HP 물약 (HP <= 30%)
|
||||||
|
final hpRatio = playerStats.hpCurrent / playerStats.hpMax;
|
||||||
|
if (hpRatio <= PotionService.emergencyHpThreshold) {
|
||||||
|
final hpPotion = potionService.selectEmergencyHpPotion(
|
||||||
currentHp: playerStats.hpCurrent,
|
currentHp: playerStats.hpCurrent,
|
||||||
maxHp: playerStats.hpMax,
|
maxHp: playerStats.hpMax,
|
||||||
inventory: potionInventory,
|
inventory: potionInventory,
|
||||||
playerLevel: playerLevel,
|
playerLevel: playerLevel,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (emergencyPotion == null || usedPotionTypes.contains(PotionType.hp)) {
|
if (hpPotion != null) {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final result = potionService.usePotion(
|
final result = potionService.usePotion(
|
||||||
potionId: emergencyPotion.id,
|
potionId: hpPotion.id,
|
||||||
inventory: potionInventory,
|
inventory: potionInventory,
|
||||||
currentHp: playerStats.hpCurrent,
|
currentHp: playerStats.hpCurrent,
|
||||||
maxHp: playerStats.hpMax,
|
maxHp: playerStats.hpMax,
|
||||||
@@ -285,24 +284,64 @@ class CombatTickService {
|
|||||||
maxMp: playerStats.mpMax,
|
maxMp: playerStats.mpMax,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!result.success) {
|
if (result.success) {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
playerStats: playerStats.copyWith(hpCurrent: result.newHp),
|
playerStats: playerStats.copyWith(hpCurrent: result.newHp),
|
||||||
usedPotionTypes: {...usedPotionTypes, PotionType.hp},
|
lastPotionUsedMs: timestamp,
|
||||||
potionInventory: result.newInventory!,
|
potionInventory: result.newInventory!,
|
||||||
events: [
|
events: [
|
||||||
CombatEvent.playerPotion(
|
CombatEvent.playerPotion(
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
potionName: emergencyPotion.name,
|
potionName: hpPotion.name,
|
||||||
healAmount: result.healedAmount,
|
healAmount: result.healedAmount,
|
||||||
isHp: true,
|
isHp: true,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 우선순위 2: MP 물약 (MP <= 50%)
|
||||||
|
final mpRatio = playerStats.mpCurrent / playerStats.mpMax;
|
||||||
|
if (mpRatio <= PotionService.emergencyMpThreshold) {
|
||||||
|
final mpPotion = potionService.selectEmergencyMpPotion(
|
||||||
|
currentMp: playerStats.mpCurrent,
|
||||||
|
maxMp: playerStats.mpMax,
|
||||||
|
inventory: potionInventory,
|
||||||
|
playerLevel: playerLevel,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mpPotion != null) {
|
||||||
|
final result = potionService.usePotion(
|
||||||
|
potionId: mpPotion.id,
|
||||||
|
inventory: potionInventory,
|
||||||
|
currentHp: playerStats.hpCurrent,
|
||||||
|
maxHp: playerStats.hpMax,
|
||||||
|
currentMp: playerStats.mpCurrent,
|
||||||
|
maxMp: playerStats.mpMax,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
return (
|
||||||
|
playerStats: playerStats.copyWith(mpCurrent: result.newMp),
|
||||||
|
lastPotionUsedMs: timestamp,
|
||||||
|
potionInventory: result.newInventory!,
|
||||||
|
events: [
|
||||||
|
CombatEvent.playerPotion(
|
||||||
|
timestamp: timestamp,
|
||||||
|
potionName: mpPotion.name,
|
||||||
|
healAmount: result.healedAmount,
|
||||||
|
isHp: false,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// 플레이어 공격 처리
|
/// 플레이어 공격 처리
|
||||||
({
|
({
|
||||||
|
|||||||
@@ -10,11 +10,14 @@ import 'package:asciineverdie/src/core/model/potion.dart';
|
|||||||
class PotionService {
|
class PotionService {
|
||||||
const PotionService();
|
const PotionService();
|
||||||
|
|
||||||
|
/// 글로벌 물약 쿨타임 (1배속 기준 3초)
|
||||||
|
static const int globalPotionCooldownMs = 3000;
|
||||||
|
|
||||||
/// 긴급 물약 사용 HP 임계치 (30%)
|
/// 긴급 물약 사용 HP 임계치 (30%)
|
||||||
static const double emergencyHpThreshold = 0.30;
|
static const double emergencyHpThreshold = 0.30;
|
||||||
|
|
||||||
/// 긴급 물약 사용 MP 임계치 (20%)
|
/// 긴급 물약 사용 MP 임계치 (50%)
|
||||||
static const double emergencyMpThreshold = 0.20;
|
static const double emergencyMpThreshold = 0.50;
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// 물약 사용 가능 여부
|
// 물약 사용 가능 여부
|
||||||
@@ -40,11 +43,6 @@ class PotionService {
|
|||||||
return (false, PotionUseFailReason.outOfStock);
|
return (false, PotionUseFailReason.outOfStock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 전투당 종류별 1회 제한 체크
|
|
||||||
if (!inventory.canUseType(potion.type)) {
|
|
||||||
return (false, PotionUseFailReason.alreadyUsedThisBattle);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (true, null);
|
return (true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +86,7 @@ class PotionService {
|
|||||||
healedAmount = newMp - currentMp; // 실제 회복량
|
healedAmount = newMp - currentMp; // 실제 회복량
|
||||||
}
|
}
|
||||||
|
|
||||||
final newInventory = inventory.usePotion(potionId, potion.type);
|
final newInventory = inventory.usePotion(potionId);
|
||||||
|
|
||||||
return PotionUseResult(
|
return PotionUseResult(
|
||||||
success: true,
|
success: true,
|
||||||
@@ -121,9 +119,6 @@ class PotionService {
|
|||||||
final hpRatio = currentHp / maxHp;
|
final hpRatio = currentHp / maxHp;
|
||||||
if (hpRatio > emergencyHpThreshold) return null;
|
if (hpRatio > emergencyHpThreshold) return null;
|
||||||
|
|
||||||
// 전투 중 이미 HP 물약 사용했으면 불가
|
|
||||||
if (!inventory.canUseType(PotionType.hp)) return null;
|
|
||||||
|
|
||||||
// 적정 티어 계산
|
// 적정 티어 계산
|
||||||
final targetTier = PotionData.tierForLevel(playerLevel);
|
final targetTier = PotionData.tierForLevel(playerLevel);
|
||||||
|
|
||||||
@@ -159,9 +154,6 @@ class PotionService {
|
|||||||
final mpRatio = currentMp / maxMp;
|
final mpRatio = currentMp / maxMp;
|
||||||
if (mpRatio > emergencyMpThreshold) return null;
|
if (mpRatio > emergencyMpThreshold) return null;
|
||||||
|
|
||||||
// 전투 중 이미 MP 물약 사용했으면 불가
|
|
||||||
if (!inventory.canUseType(PotionType.mp)) return null;
|
|
||||||
|
|
||||||
// 적정 티어 계산
|
// 적정 티어 계산
|
||||||
final targetTier = PotionData.tierForLevel(playerLevel);
|
final targetTier = PotionData.tierForLevel(playerLevel);
|
||||||
|
|
||||||
@@ -188,11 +180,6 @@ class PotionService {
|
|||||||
// 인벤토리 관리
|
// 인벤토리 관리
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/// 전투 종료 시 사용 기록 초기화
|
|
||||||
PotionInventory resetBattleUsage(PotionInventory inventory) {
|
|
||||||
return inventory.resetBattleUsage();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 물약 드랍 추가
|
/// 물약 드랍 추가
|
||||||
PotionInventory addPotionDrop(
|
PotionInventory addPotionDrop(
|
||||||
PotionInventory inventory,
|
PotionInventory inventory,
|
||||||
@@ -470,8 +457,8 @@ enum PotionUseFailReason {
|
|||||||
/// 보유 물약 없음 (재고 부족)
|
/// 보유 물약 없음 (재고 부족)
|
||||||
outOfStock,
|
outOfStock,
|
||||||
|
|
||||||
/// 이번 전투에서 이미 해당 종류 물약 사용
|
/// 글로벌 쿨타임 중
|
||||||
alreadyUsedThisBattle,
|
onCooldown,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 물약 구매 결과
|
/// 물약 구매 결과
|
||||||
|
|||||||
@@ -327,11 +327,9 @@ class ProgressService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final resetPotionInventory = nextState.potionInventory.resetBattleUsage();
|
|
||||||
nextState = nextState.copyWith(
|
nextState = nextState.copyWith(
|
||||||
progress: progress,
|
progress: progress,
|
||||||
queue: queue,
|
queue: queue,
|
||||||
potionInventory: resetPotionInventory,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// 최종 보스 처치 체크
|
// 최종 보스 처치 체크
|
||||||
@@ -977,10 +975,17 @@ class ProgressService {
|
|||||||
// 무기(슬롯 0)를 제외한 장착된 장비 중 1개를 제물로 삭제
|
// 무기(슬롯 0)를 제외한 장착된 장비 중 1개를 제물로 삭제
|
||||||
final equippedNonWeaponSlots = <int>[];
|
final equippedNonWeaponSlots = <int>[];
|
||||||
for (var i = 1; i < Equipment.slotCount; i++) {
|
for (var i = 1; i < Equipment.slotCount; i++) {
|
||||||
if (state.equipment.getItemByIndex(i).isNotEmpty) {
|
final item = state.equipment.getItemByIndex(i);
|
||||||
|
// 디버그: 장비 슬롯 상태 확인
|
||||||
|
// ignore: avoid_print
|
||||||
|
print('[Death] Slot $i: "${item.name}" isEmpty=${item.isEmpty}');
|
||||||
|
if (item.isNotEmpty) {
|
||||||
equippedNonWeaponSlots.add(i);
|
equippedNonWeaponSlots.add(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 디버그: 장착된 슬롯 목록
|
||||||
|
// ignore: avoid_print
|
||||||
|
print('[Death] equippedNonWeaponSlots: $equippedNonWeaponSlots');
|
||||||
|
|
||||||
if (equippedNonWeaponSlots.isNotEmpty) {
|
if (equippedNonWeaponSlots.isNotEmpty) {
|
||||||
lostCount = 1;
|
lostCount = 1;
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ class ResurrectionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String? lostItemName;
|
String? lostItemName;
|
||||||
|
EquipmentSlot? lostItemSlot;
|
||||||
var newEquipment = state.equipment;
|
var newEquipment = state.equipment;
|
||||||
|
|
||||||
if (equippedItems.isNotEmpty) {
|
if (equippedItems.isNotEmpty) {
|
||||||
@@ -55,12 +56,12 @@ class ResurrectionService {
|
|||||||
final slotIndex = equippedItems[random.nextInt(equippedItems.length)];
|
final slotIndex = equippedItems[random.nextInt(equippedItems.length)];
|
||||||
final lostItem = state.equipment.getItemByIndex(slotIndex);
|
final lostItem = state.equipment.getItemByIndex(slotIndex);
|
||||||
lostItemName = lostItem.name;
|
lostItemName = lostItem.name;
|
||||||
|
lostItemSlot = EquipmentSlot.values[slotIndex];
|
||||||
|
|
||||||
// 해당 슬롯만 빈 아이템으로 교체
|
// 해당 슬롯만 빈 아이템으로 교체
|
||||||
final slot = EquipmentSlot.values[slotIndex];
|
|
||||||
newEquipment = state.equipment.setItemByIndex(
|
newEquipment = state.equipment.setItemByIndex(
|
||||||
slotIndex,
|
slotIndex,
|
||||||
EquipmentItem.empty(slot),
|
EquipmentItem.empty(lostItemSlot),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +71,7 @@ class ResurrectionService {
|
|||||||
killerName: killerName,
|
killerName: killerName,
|
||||||
lostEquipmentCount: lostItemName != null ? 1 : 0,
|
lostEquipmentCount: lostItemName != null ? 1 : 0,
|
||||||
lostItemName: lostItemName,
|
lostItemName: lostItemName,
|
||||||
|
lostItemSlot: lostItemSlot,
|
||||||
goldAtDeath: state.inventory.gold,
|
goldAtDeath: state.inventory.gold,
|
||||||
levelAtDeath: state.traits.level,
|
levelAtDeath: state.traits.level,
|
||||||
timestamp: state.skillSystem.elapsedMs,
|
timestamp: state.skillSystem.elapsedMs,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:asciineverdie/src/core/model/combat_event.dart';
|
import 'package:asciineverdie/src/core/model/combat_event.dart';
|
||||||
import 'package:asciineverdie/src/core/model/combat_stats.dart';
|
import 'package:asciineverdie/src/core/model/combat_stats.dart';
|
||||||
import 'package:asciineverdie/src/core/model/monster_combat_stats.dart';
|
import 'package:asciineverdie/src/core/model/monster_combat_stats.dart';
|
||||||
import 'package:asciineverdie/src/core/model/potion.dart';
|
|
||||||
import 'package:asciineverdie/src/core/model/skill.dart';
|
import 'package:asciineverdie/src/core/model/skill.dart';
|
||||||
|
|
||||||
/// 현재 전투 상태
|
/// 현재 전투 상태
|
||||||
@@ -20,7 +19,7 @@ class CombatState {
|
|||||||
required this.isActive,
|
required this.isActive,
|
||||||
this.recentEvents = const [],
|
this.recentEvents = const [],
|
||||||
this.activeDoTs = const [],
|
this.activeDoTs = const [],
|
||||||
this.usedPotionTypes = const {},
|
this.lastPotionUsedMs = 0,
|
||||||
this.activeDebuffs = const [],
|
this.activeDebuffs = const [],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -54,8 +53,8 @@ class CombatState {
|
|||||||
/// 활성 DOT 효과 목록
|
/// 활성 DOT 효과 목록
|
||||||
final List<DotEffect> activeDoTs;
|
final List<DotEffect> activeDoTs;
|
||||||
|
|
||||||
/// 이번 전투에서 사용한 물약 종류 (종류별 1회 제한)
|
/// 마지막 물약 사용 시간 (글로벌 쿨타임용)
|
||||||
final Set<PotionType> usedPotionTypes;
|
final int lastPotionUsedMs;
|
||||||
|
|
||||||
/// 몬스터에 적용된 활성 디버프 목록
|
/// 몬스터에 적용된 활성 디버프 목록
|
||||||
final List<ActiveBuff> activeDebuffs;
|
final List<ActiveBuff> activeDebuffs;
|
||||||
@@ -79,8 +78,10 @@ class CombatState {
|
|||||||
/// 몬스터 HP 비율
|
/// 몬스터 HP 비율
|
||||||
double get monsterHpRatio => monsterStats.hpRatio;
|
double get monsterHpRatio => monsterStats.hpRatio;
|
||||||
|
|
||||||
/// 특정 종류 물약 사용 가능 여부
|
/// 물약 사용 가능 여부 (글로벌 쿨타임 체크)
|
||||||
bool canUsePotionType(PotionType type) => !usedPotionTypes.contains(type);
|
bool canUsePotion(int currentMs, int cooldownMs) {
|
||||||
|
return currentMs - lastPotionUsedMs >= cooldownMs;
|
||||||
|
}
|
||||||
|
|
||||||
/// 활성 DOT 존재 여부
|
/// 활성 DOT 존재 여부
|
||||||
bool get hasActiveDoTs => activeDoTs.isNotEmpty;
|
bool get hasActiveDoTs => activeDoTs.isNotEmpty;
|
||||||
@@ -121,7 +122,7 @@ class CombatState {
|
|||||||
bool? isActive,
|
bool? isActive,
|
||||||
List<CombatEvent>? recentEvents,
|
List<CombatEvent>? recentEvents,
|
||||||
List<DotEffect>? activeDoTs,
|
List<DotEffect>? activeDoTs,
|
||||||
Set<PotionType>? usedPotionTypes,
|
int? lastPotionUsedMs,
|
||||||
List<ActiveBuff>? activeDebuffs,
|
List<ActiveBuff>? activeDebuffs,
|
||||||
}) {
|
}) {
|
||||||
return CombatState(
|
return CombatState(
|
||||||
@@ -137,7 +138,7 @@ class CombatState {
|
|||||||
isActive: isActive ?? this.isActive,
|
isActive: isActive ?? this.isActive,
|
||||||
recentEvents: recentEvents ?? this.recentEvents,
|
recentEvents: recentEvents ?? this.recentEvents,
|
||||||
activeDoTs: activeDoTs ?? this.activeDoTs,
|
activeDoTs: activeDoTs ?? this.activeDoTs,
|
||||||
usedPotionTypes: usedPotionTypes ?? this.usedPotionTypes,
|
lastPotionUsedMs: lastPotionUsedMs ?? this.lastPotionUsedMs,
|
||||||
activeDebuffs: activeDebuffs ?? this.activeDebuffs,
|
activeDebuffs: activeDebuffs ?? this.activeDebuffs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,39 +60,30 @@ class Potion {
|
|||||||
|
|
||||||
/// 물약 인벤토리 상태
|
/// 물약 인벤토리 상태
|
||||||
///
|
///
|
||||||
/// 보유 물약 수량 및 전투 중 사용 기록 관리
|
/// 보유 물약 수량 관리 (쿨타임은 CombatState에서 관리)
|
||||||
class PotionInventory {
|
class PotionInventory {
|
||||||
const PotionInventory({
|
const PotionInventory({
|
||||||
this.potions = const {},
|
this.potions = const {},
|
||||||
this.usedInBattle = const {},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/// 보유 물약 (물약 ID → 수량)
|
/// 보유 물약 (물약 ID → 수량)
|
||||||
final Map<String, int> potions;
|
final Map<String, int> potions;
|
||||||
|
|
||||||
/// 현재 전투에서 사용한 물약 종류
|
|
||||||
final Set<PotionType> usedInBattle;
|
|
||||||
|
|
||||||
/// 물약 보유 여부
|
/// 물약 보유 여부
|
||||||
bool hasPotion(String potionId) => (potions[potionId] ?? 0) > 0;
|
bool hasPotion(String potionId) => (potions[potionId] ?? 0) > 0;
|
||||||
|
|
||||||
/// 물약 수량 조회
|
/// 물약 수량 조회
|
||||||
int getQuantity(String potionId) => potions[potionId] ?? 0;
|
int getQuantity(String potionId) => potions[potionId] ?? 0;
|
||||||
|
|
||||||
/// 특정 종류 물약 사용 가능 여부
|
|
||||||
///
|
|
||||||
/// 전투당 종류별 1회 제한 체크
|
|
||||||
bool canUseType(PotionType type) => !usedInBattle.contains(type);
|
|
||||||
|
|
||||||
/// 물약 추가
|
/// 물약 추가
|
||||||
PotionInventory addPotion(String potionId, [int count = 1]) {
|
PotionInventory addPotion(String potionId, [int count = 1]) {
|
||||||
final newPotions = Map<String, int>.from(potions);
|
final newPotions = Map<String, int>.from(potions);
|
||||||
newPotions[potionId] = (newPotions[potionId] ?? 0) + count;
|
newPotions[potionId] = (newPotions[potionId] ?? 0) + count;
|
||||||
return PotionInventory(potions: newPotions, usedInBattle: usedInBattle);
|
return PotionInventory(potions: newPotions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 물약 사용 (수량 감소)
|
/// 물약 사용 (수량 감소)
|
||||||
PotionInventory usePotion(String potionId, PotionType type) {
|
PotionInventory usePotion(String potionId) {
|
||||||
final currentQty = potions[potionId] ?? 0;
|
final currentQty = potions[potionId] ?? 0;
|
||||||
if (currentQty <= 0) return this;
|
if (currentQty <= 0) return this;
|
||||||
|
|
||||||
@@ -102,14 +93,7 @@ class PotionInventory {
|
|||||||
newPotions.remove(potionId);
|
newPotions.remove(potionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
final newUsed = Set<PotionType>.from(usedInBattle)..add(type);
|
return PotionInventory(potions: newPotions);
|
||||||
|
|
||||||
return PotionInventory(potions: newPotions, usedInBattle: newUsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 전투 종료 시 사용 기록 초기화
|
|
||||||
PotionInventory resetBattleUsage() {
|
|
||||||
return PotionInventory(potions: potions, usedInBattle: const {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 빈 인벤토리
|
/// 빈 인벤토리
|
||||||
@@ -117,11 +101,9 @@ class PotionInventory {
|
|||||||
|
|
||||||
PotionInventory copyWith({
|
PotionInventory copyWith({
|
||||||
Map<String, int>? potions,
|
Map<String, int>? potions,
|
||||||
Set<PotionType>? usedInBattle,
|
|
||||||
}) {
|
}) {
|
||||||
return PotionInventory(
|
return PotionInventory(
|
||||||
potions: potions ?? this.potions,
|
potions: potions ?? this.potions,
|
||||||
usedInBattle: usedInBattle ?? this.usedInBattle,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user