feat(core): 엔진, 모델, 애니메이션 개선

- ProgressService 로직 개선
- CombatCalculator 업데이트
- GameState, MonsterCombatStats 확장
- CanvasBattleComposer 개선
This commit is contained in:
JiWoong Sul
2026-01-14 00:17:59 +09:00
parent 4e9265ab87
commit f89017e5ba
5 changed files with 101 additions and 36 deletions

View File

@@ -588,8 +588,18 @@ class ProgressService {
// 4. 최종 보스 전투 체크
// finalBossState == fighting이면 Glitch God 스폰
// 단, 레벨링 모드 중이면 일반 몬스터로 레벨업 후 재도전
if (state.progress.finalBossState == FinalBossState.fighting) {
return _startFinalBossFight(state, progress, queue);
if (state.progress.isInBossLevelingMode) {
// 레벨링 모드: 일반 몬스터 전투로 대체 (아래 MonsterTask로 진행)
} else {
// 레벨링 모드 종료 또는 첫 도전: 보스전 시작
// 레벨링 모드가 끝났으면 타이머 초기화
if (state.progress.bossLevelingEndTime != null) {
progress = progress.copyWith(clearBossLevelingEndTime: true);
}
return _startFinalBossFight(state, progress, queue);
}
}
// 5. MonsterTask 실행 (원본 678-684줄)
@@ -634,6 +644,7 @@ class ProgressService {
name: monsterResult.displayName,
level: effectiveMonsterLevel,
speedType: MonsterCombatStats.inferSpeedType(monsterResult.baseName),
plotStageCount: state.progress.plotStageCount,
);
// 전투 상태 초기화
@@ -1667,6 +1678,7 @@ class ProgressService {
/// 플레이어 사망 처리 (Phase 4)
///
/// 모든 장비 상실 및 사망 정보 기록
/// 보스전 사망 시: 장비 보호 + 5분 레벨링 모드 진입
GameState _processPlayerDeath(
GameState state, {
required String killerName,
@@ -1676,30 +1688,36 @@ class ProgressService {
final lastCombatEvents =
state.progress.currentCombat?.recentEvents ?? const [];
// 무기(슬롯 0)를 제외한 장착된 장비 중 1개를 제물로 삭제
// 장착된 비무기 슬롯 인덱스 수집 (슬롯 1~10 중 장비가 있는 것)
final equippedNonWeaponSlots = <int>[];
for (var i = 1; i < Equipment.slotCount; i++) {
if (state.equipment.getItemByIndex(i).isNotEmpty) {
equippedNonWeaponSlots.add(i);
}
}
// 보스전 사망 여부 확인 (최종 보스 fighting 상태)
final isBossDeath =
state.progress.finalBossState == FinalBossState.fighting;
// 제물로 바칠 장비 선택 및 삭제
// 보스전 사망이 아닐 경우에만 장비 손실
var newEquipment = state.equipment;
final lostCount = equippedNonWeaponSlots.isNotEmpty ? 1 : 0;
var lostCount = 0;
if (equippedNonWeaponSlots.isNotEmpty) {
// 랜덤하게 1개 슬롯 선택
final sacrificeIndex =
equippedNonWeaponSlots[state.rng.nextInt(equippedNonWeaponSlots.length)];
final slot = EquipmentSlot.values[sacrificeIndex];
if (!isBossDeath) {
// 무기(슬롯 0)를 제외한 장착된 장비 중 1개를 제물로 삭제
final equippedNonWeaponSlots = <int>[];
for (var i = 1; i < Equipment.slotCount; i++) {
if (state.equipment.getItemByIndex(i).isNotEmpty) {
equippedNonWeaponSlots.add(i);
}
}
// 해당 슬롯을 빈 장비로 교체
newEquipment = newEquipment.setItemByIndex(
sacrificeIndex,
EquipmentItem.empty(slot),
);
if (equippedNonWeaponSlots.isNotEmpty) {
lostCount = 1;
// 랜덤하게 1개 슬롯 선택
final sacrificeIndex = equippedNonWeaponSlots[
state.rng.nextInt(equippedNonWeaponSlots.length)];
final slot = EquipmentSlot.values[sacrificeIndex];
// 해당 슬롯을 빈 장비로 교체
newEquipment = newEquipment.setItemByIndex(
sacrificeIndex,
EquipmentItem.empty(slot),
);
}
}
// 사망 정보 생성 (전투 로그 포함)
@@ -1713,12 +1731,16 @@ class ProgressService {
lastCombatEvents: lastCombatEvents,
);
// 보스전 사망 시 5분 레벨링 모드 진입
final bossLevelingEndTime = isBossDeath
? DateTime.now().millisecondsSinceEpoch + (5 * 60 * 1000) // 5분
: null;
// 전투 상태 초기화 및 사망 횟수 증가
// pendingActCompletion 플래그는 유지 (Boss 리트라이를 위해)
final progress = state.progress.copyWith(
currentCombat: null,
deathCount: state.progress.deathCount + 1,
// pendingActCompletion은 copyWith에서 명시하지 않으면 기존 값 유지
bossLevelingEndTime: bossLevelingEndTime,
);
return state.copyWith(