refactor(engine): 서비스 로직 정리

- ArenaService, PotionService, ProgressService 개선
- ResurrectionService, SkillService 정리
This commit is contained in:
JiWoong Sul
2026-01-12 16:17:00 +09:00
parent 32ecafd33d
commit 95528786eb
5 changed files with 176 additions and 55 deletions

View File

@@ -104,8 +104,10 @@ class ProgressService {
);
// ExpBar 초기화 (원본 743-746줄)
final expBar =
ProgressBarState(position: 0, max: ExpConstants.requiredExp(1));
final expBar = ProgressBarState(
position: 0,
max: ExpConstants.requiredExp(1),
);
// PlotBar 초기화 - Prologue 5분 (300초)
final plotBar = const ProgressBarState(position: 0, max: 300);
@@ -299,23 +301,40 @@ class ProgressService {
progress = progress.copyWith(currentCombat: combatForReset);
}
// 전투 상태 초기화, 몬스터 처치 수 증가 및 물약 사용 기록 초기화
progress = progress.copyWith(
currentCombat: null,
monstersKilled: progress.monstersKilled + 1,
);
// Boss 승리 처리: 시네마틱 트리거
if (progress.pendingActCompletion) {
// Act Boss를 처치했으므로 시네마틱 재생
final cinematicEntries = pq_logic.interplotCinematic(
config,
nextState.rng,
nextState.traits.level,
progress.plotStageCount,
);
queue = QueueState(entries: [...queue.entries, ...cinematicEntries]);
progress = progress.copyWith(
currentCombat: null,
monstersKilled: progress.monstersKilled + 1,
pendingActCompletion: false, // Boss 처치 완료
);
} else {
// 일반 전투 종료
progress = progress.copyWith(
currentCombat: null,
monstersKilled: progress.monstersKilled + 1,
);
}
final resetPotionInventory = nextState.potionInventory.resetBattleUsage();
nextState = nextState.copyWith(
progress: progress,
queue: queue,
potionInventory: resetPotionInventory,
);
// 최종 보스 처치 체크
if (progress.finalBossState == FinalBossState.fighting) {
// 글리치 갓 처치 완료 - 게임 클리어
progress = progress.copyWith(
finalBossState: FinalBossState.defeated,
);
progress = progress.copyWith(finalBossState: FinalBossState.defeated);
nextState = nextState.copyWith(progress: progress);
// completeAct를 호출하여 게임 완료 처리
@@ -406,22 +425,22 @@ class ProgressService {
}
}
// 플롯(plot) 바가 완료되면 InterplotCinematic 트리거
// (원본 Main.pas:1301-1304)
// 플롯(plot) 바가 완료되면 Act Boss 소환
// (개선: Boss 처치 → 시네마틱 → Act 전환 순서)
if (gain &&
progress.plot.max > 0 &&
progress.plot.position >= progress.plot.max) {
// InterplotCinematic을 호출하여 시네마틱 이벤트 큐에 추가
final cinematicEntries = pq_logic.interplotCinematic(
config,
nextState.rng,
nextState.traits.level,
nextState.progress.plotStageCount,
progress.plot.position >= progress.plot.max &&
!progress.pendingActCompletion) {
// Act Boss 소환 및 플래그 설정
final actBoss = _createActBoss(nextState);
progress = progress.copyWith(
plot: progress.plot.copyWith(position: 0), // Plot bar 리셋
currentCombat: actBoss,
pendingActCompletion: true, // Boss 처치 대기 플래그
);
queue = QueueState(entries: [...queue.entries, ...cinematicEntries]);
// 플롯 바를 0으로 리셋하지 않음 - completeAct에서 처리됨
} else if (progress.currentTask.type != TaskType.load &&
progress.plot.max > 0) {
progress.plot.max > 0 &&
!progress.pendingActCompletion) {
final uncappedPlot = progress.plot.position + incrementSeconds;
final int newPlotPos = uncappedPlot > progress.plot.max
? progress.plot.max
@@ -531,13 +550,44 @@ class ProgressService {
return (progress: progress, queue: queue);
}
// 3. 최종 보스 전투 체크
// 3. Act Boss 리트라이 체크
// pendingActCompletion이 true면 Act Boss 재소환
if (state.progress.pendingActCompletion) {
final actBoss = _createActBoss(state);
final combatCalculator = CombatCalculator(rng: state.rng);
final durationMillis = combatCalculator.estimateCombatDurationMs(
player: actBoss.playerStats,
monster: actBoss.monsterStats,
);
final taskResult = pq_logic.startTask(
progress,
l10n.taskDebugging(actBoss.monsterStats.name),
durationMillis,
);
progress = taskResult.progress.copyWith(
currentTask: TaskInfo(
caption: taskResult.caption,
type: TaskType.kill,
monsterBaseName: actBoss.monsterStats.name,
monsterPart: '*', // Boss는 WinItem 드랍
monsterLevel: actBoss.monsterStats.level,
monsterGrade: MonsterGrade.boss,
),
currentCombat: actBoss,
);
return (progress: progress, queue: queue);
}
// 4. 최종 보스 전투 체크
// finalBossState == fighting이면 Glitch God 스폰
if (state.progress.finalBossState == FinalBossState.fighting) {
return _startFinalBossFight(state, progress, queue);
}
// 4. MonsterTask 실행 (원본 678-684줄)
// 5. MonsterTask 실행 (원본 678-684줄)
final level = state.traits.level;
// 원본 Main.pas:548-551: 25% 확률로 Quest Monster 사용
@@ -878,7 +928,8 @@ class ProgressService {
var nextState = state;
// 현재 레벨이 목표 레벨보다 낮으면 레벨업 (최대 100레벨)
while (nextState.traits.level < targetLevel && nextState.traits.level < 100) {
while (nextState.traits.level < targetLevel &&
nextState.traits.level < 100) {
nextState = _levelUp(nextState);
}
@@ -1390,10 +1441,13 @@ class ProgressService {
// 디버프 효과 추가 (기존 같은 디버프 제거 후)
if (skillResult.debuffEffect != null) {
activeDebuffs = activeDebuffs
.where((d) => d.effect.id != skillResult.debuffEffect!.effect.id)
.toList()
..add(skillResult.debuffEffect!);
activeDebuffs =
activeDebuffs
.where(
(d) => d.effect.id != skillResult.debuffEffect!.effect.id,
)
.toList()
..add(skillResult.debuffEffect!);
}
// 디버프 이벤트 생성
@@ -1533,6 +1587,55 @@ class ProgressService {
);
}
/// Act Boss 생성 (Act 완료 시)
///
/// 보스 레벨 = min(플레이어 레벨, Act 최소 레벨)로 설정하여
/// 플레이어가 이길 수 있는 수준 보장
CombatState _createActBoss(GameState state) {
final plotStage = state.progress.plotStageCount;
final actNumber = plotStage + 1;
// 보스 레벨 = min(플레이어 레벨, Act 최소 레벨)
// → 플레이어가 현재 레벨보다 높은 보스를 만나지 않도록 보장
final actMinLevel = ActMonsterLevel.forPlotStage(actNumber);
final bossLevel = math.min(state.traits.level, actMinLevel);
// Named monster 생성 (pq_logic.namedMonster 활용)
final bossName = pq_logic.namedMonster(config, state.rng, bossLevel);
final bossStats = MonsterBaseStats.forLevel(bossLevel);
// 플레이어 전투 스탯 생성
final playerCombatStats = CombatStats.fromStats(
stats: state.stats,
equipment: state.equipment,
level: state.traits.level,
monsterLevel: bossLevel,
);
// Boss 몬스터 스탯 생성 (일반 몬스터 대비 강화)
final monsterCombatStats = MonsterCombatStats(
name: bossName,
level: bossLevel,
atk: (bossStats.atk * 1.5).round(), // Boss 보정 (1.5배)
def: (bossStats.def * 1.5).round(),
hpMax: (bossStats.hp * 2.0).round(), // HP는 2.0배 (보스다운 전투 시간)
hpCurrent: (bossStats.hp * 2.0).round(),
criRate: 0.05,
criDamage: 1.5,
evasion: 0.0,
accuracy: 0.8,
attackDelayMs: 1000,
expReward: (bossStats.exp * 2.5).round(), // 경험치 보상 증가
);
// 전투 상태 초기화
return CombatState.start(
playerStats: playerCombatStats,
monsterStats: monsterCombatStats,
);
}
/// 플레이어 사망 처리 (Phase 4)
///
/// 모든 장비 상실 및 사망 정보 기록
@@ -1578,9 +1681,11 @@ class ProgressService {
);
// 전투 상태 초기화 및 사망 횟수 증가
// pendingActCompletion 플래그는 유지 (Boss 리트라이를 위해)
final progress = state.progress.copyWith(
currentCombat: null,
deathCount: state.progress.deathCount + 1,
// pendingActCompletion은 copyWith에서 명시하지 않으면 기존 값 유지
);
return state.copyWith(