feat(ui): HP/MP 바 개선 및 전투 시스템 UI 업데이트
- HP/MP 변화 시 플래시 효과 및 변화량 표시 추가 - 전투 중 몬스터 HP 바 표시 기능 추가 - 몬스터 HP 바 Row 오버플로우 버그 수정 (Flexible 적용) - 전투 상태 및 이벤트 모델 개선 - 캐릭터 애니메이션 및 전투 컴포저 업데이트
This commit is contained in:
@@ -1,7 +1,13 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:askiineverdie/data/class_data.dart';
|
||||
import 'package:askiineverdie/data/race_data.dart';
|
||||
import 'package:askiineverdie/src/core/engine/shop_service.dart';
|
||||
import 'package:askiineverdie/src/core/model/class_traits.dart';
|
||||
import 'package:askiineverdie/src/core/model/equipment_item.dart';
|
||||
import 'package:askiineverdie/src/core/model/equipment_slot.dart';
|
||||
import 'package:askiineverdie/src/core/model/game_state.dart';
|
||||
import 'package:askiineverdie/src/core/model/race_traits.dart';
|
||||
|
||||
/// 부활 시스템 서비스 (Phase 4)
|
||||
///
|
||||
@@ -17,7 +23,7 @@ class ResurrectionService {
|
||||
|
||||
/// 플레이어 사망 처리
|
||||
///
|
||||
/// 1. 모든 장비 제거 (인벤토리로 이동하지 않음 - 상실)
|
||||
/// 1. 1개의 랜덤 장비 제거 (제물로 바침)
|
||||
/// 2. 전투 상태 초기화
|
||||
/// 3. 사망 정보 기록
|
||||
GameState processDeath({
|
||||
@@ -25,32 +31,40 @@ class ResurrectionService {
|
||||
required String killerName,
|
||||
required DeathCause cause,
|
||||
}) {
|
||||
// 상실할 장비 개수 계산
|
||||
final lostCount = state.equipment.equippedItems.length;
|
||||
// 제물로 바칠 아이템 선택 (장착된 아이템 중 랜덤 1개)
|
||||
final equippedItems = <int>[]; // 장착된 아이템의 슬롯 인덱스
|
||||
for (var i = 0; i < Equipment.slotCount; i++) {
|
||||
final item = state.equipment.getItemByIndex(i);
|
||||
// 빈 슬롯과 기본 무기(Keyboard) 제외
|
||||
if (item.isNotEmpty && item.name != 'Keyboard') {
|
||||
equippedItems.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 빈 장비 생성 (기본 무기만 유지)
|
||||
final emptyEquipment = Equipment(
|
||||
items: [
|
||||
EquipmentItem.defaultWeapon(), // 무기 슬롯에 기본 Keyboard
|
||||
EquipmentItem.empty(EquipmentSlot.shield),
|
||||
EquipmentItem.empty(EquipmentSlot.helm),
|
||||
EquipmentItem.empty(EquipmentSlot.hauberk),
|
||||
EquipmentItem.empty(EquipmentSlot.brassairts),
|
||||
EquipmentItem.empty(EquipmentSlot.vambraces),
|
||||
EquipmentItem.empty(EquipmentSlot.gauntlets),
|
||||
EquipmentItem.empty(EquipmentSlot.gambeson),
|
||||
EquipmentItem.empty(EquipmentSlot.cuisses),
|
||||
EquipmentItem.empty(EquipmentSlot.greaves),
|
||||
EquipmentItem.empty(EquipmentSlot.sollerets),
|
||||
],
|
||||
bestIndex: 0,
|
||||
);
|
||||
String? lostItemName;
|
||||
var newEquipment = state.equipment;
|
||||
|
||||
if (equippedItems.isNotEmpty) {
|
||||
// 랜덤하게 1개 슬롯 선택
|
||||
final random = Random();
|
||||
final slotIndex = equippedItems[random.nextInt(equippedItems.length)];
|
||||
final lostItem = state.equipment.getItemByIndex(slotIndex);
|
||||
lostItemName = lostItem.name;
|
||||
|
||||
// 해당 슬롯만 빈 아이템으로 교체
|
||||
final slot = EquipmentSlot.values[slotIndex];
|
||||
newEquipment = state.equipment.setItemByIndex(
|
||||
slotIndex,
|
||||
EquipmentItem.empty(slot),
|
||||
);
|
||||
}
|
||||
|
||||
// 사망 정보 생성
|
||||
final deathInfo = DeathInfo(
|
||||
cause: cause,
|
||||
killerName: killerName,
|
||||
lostEquipmentCount: lostCount,
|
||||
lostEquipmentCount: lostItemName != null ? 1 : 0,
|
||||
lostItemName: lostItemName,
|
||||
goldAtDeath: state.inventory.gold,
|
||||
levelAtDeath: state.traits.level,
|
||||
timestamp: state.skillSystem.elapsedMs,
|
||||
@@ -62,7 +76,7 @@ class ResurrectionService {
|
||||
);
|
||||
|
||||
return state.copyWith(
|
||||
equipment: emptyEquipment,
|
||||
equipment: newEquipment,
|
||||
progress: progress,
|
||||
deathInfo: deathInfo,
|
||||
);
|
||||
@@ -74,33 +88,37 @@ class ResurrectionService {
|
||||
|
||||
/// 플레이어 부활 처리
|
||||
///
|
||||
/// 1. HP/MP 전체 회복
|
||||
/// 2. 골드로 구매 가능한 장비 자동 구매
|
||||
/// 1. 골드로 구매 가능한 장비 자동 구매
|
||||
/// 2. HP/MP 전체 회복 (장비/종족/클래스 보너스 포함)
|
||||
/// 3. 사망 상태 해제
|
||||
/// 4. 안전 지역으로 이동 태스크 설정
|
||||
GameState processResurrection(GameState state) {
|
||||
if (!state.isDead) return state;
|
||||
|
||||
// HP/MP 전체 회복
|
||||
// 1. 먼저 장비 구매 (HP 계산에 필요)
|
||||
final autoBuyResult = shopService.autoBuyForEmptySlots(
|
||||
playerLevel: state.traits.level,
|
||||
currentGold: state.inventory.gold,
|
||||
currentEquipment: state.equipment,
|
||||
);
|
||||
|
||||
// 장비 적용
|
||||
var nextState = state.copyWith(
|
||||
stats: state.stats.copyWith(
|
||||
hpCurrent: state.stats.hpMax,
|
||||
mpCurrent: state.stats.mpMax,
|
||||
equipment: autoBuyResult.updatedEquipment,
|
||||
inventory: state.inventory.copyWith(
|
||||
gold: autoBuyResult.remainingGold,
|
||||
),
|
||||
);
|
||||
|
||||
// 빈 슬롯에 자동 장비 구매
|
||||
final autoBuyResult = shopService.autoBuyForEmptySlots(
|
||||
playerLevel: nextState.traits.level,
|
||||
currentGold: nextState.inventory.gold,
|
||||
currentEquipment: nextState.equipment,
|
||||
);
|
||||
// 2. 전체 HP/MP 계산 (장비 + 종족 + 클래스 보너스 포함)
|
||||
final totalHpMax = _calculateTotalHpMax(nextState);
|
||||
final totalMpMax = _calculateTotalMpMax(nextState);
|
||||
|
||||
// 결과 적용
|
||||
// HP/MP 전체 회복
|
||||
nextState = nextState.copyWith(
|
||||
equipment: autoBuyResult.updatedEquipment,
|
||||
inventory: nextState.inventory.copyWith(
|
||||
gold: autoBuyResult.remainingGold,
|
||||
stats: nextState.stats.copyWith(
|
||||
hpCurrent: totalHpMax,
|
||||
mpCurrent: totalMpMax,
|
||||
),
|
||||
clearDeathInfo: true, // 사망 상태 해제
|
||||
);
|
||||
@@ -115,6 +133,49 @@ class ResurrectionService {
|
||||
return nextState;
|
||||
}
|
||||
|
||||
/// 장비/종족/클래스 보너스를 포함한 전체 HP 계산
|
||||
int _calculateTotalHpMax(GameState state) {
|
||||
// 기본 HP + 장비 보너스
|
||||
var totalHp = state.stats.hpMax + state.equipment.totalStats.hpBonus;
|
||||
|
||||
// 종족 HP 보너스 (예: Heap Troll +20%)
|
||||
final race = RaceData.findById(state.traits.raceId);
|
||||
if (race != null) {
|
||||
final raceHpBonus = race.getPassiveValue(PassiveType.hpBonus);
|
||||
if (raceHpBonus > 0) {
|
||||
totalHp = (totalHp * (1 + raceHpBonus)).round();
|
||||
}
|
||||
}
|
||||
|
||||
// 클래스 HP 보너스 (예: Garbage Collector +30%)
|
||||
final klass = ClassData.findById(state.traits.classId);
|
||||
if (klass != null) {
|
||||
final classHpBonus = klass.getPassiveValue(ClassPassiveType.hpBonus);
|
||||
if (classHpBonus > 0) {
|
||||
totalHp = (totalHp * (1 + classHpBonus)).round();
|
||||
}
|
||||
}
|
||||
|
||||
return totalHp;
|
||||
}
|
||||
|
||||
/// 장비/종족/클래스 보너스를 포함한 전체 MP 계산
|
||||
int _calculateTotalMpMax(GameState state) {
|
||||
// 기본 MP + 장비 보너스
|
||||
var totalMp = state.stats.mpMax + state.equipment.totalStats.mpBonus;
|
||||
|
||||
// 종족 MP 보너스 (예: Pointer Fairy +20%)
|
||||
final race = RaceData.findById(state.traits.raceId);
|
||||
if (race != null) {
|
||||
final raceMpBonus = race.getPassiveValue(PassiveType.mpBonus);
|
||||
if (raceMpBonus > 0) {
|
||||
totalMp = (totalMp * (1 + raceMpBonus)).round();
|
||||
}
|
||||
}
|
||||
|
||||
return totalMp;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 유틸리티
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user