refactor(engine): 포션/진행 서비스 개선

- PotionService 로직 개선
- ProgressService 몬스터 등급 지원
This commit is contained in:
JiWoong Sul
2026-01-05 17:52:57 +09:00
parent 4688aff56b
commit 7570a4205c
2 changed files with 31 additions and 4 deletions

View File

@@ -1,4 +1,7 @@
import 'dart:math' as math;
import 'package:asciineverdie/data/potion_data.dart'; import 'package:asciineverdie/data/potion_data.dart';
import 'package:asciineverdie/src/core/model/monster_grade.dart';
import 'package:asciineverdie/src/core/model/potion.dart'; import 'package:asciineverdie/src/core/model/potion.dart';
/// 물약 서비스 /// 물약 서비스
@@ -357,19 +360,35 @@ class PotionService {
/// ///
/// 전투 승리 시 물약 드랍 여부 결정 및 물약 획득 /// 전투 승리 시 물약 드랍 여부 결정 및 물약 획득
/// [playerLevel] 플레이어 레벨 (드랍 확률 및 티어 결정) /// [playerLevel] 플레이어 레벨 (드랍 확률 및 티어 결정)
/// [monsterLevel] 몬스터 레벨 (티어 결정에 영향)
/// [monsterGrade] 몬스터 등급 (드랍 확률 보너스)
/// [inventory] 현재 물약 인벤토리 /// [inventory] 현재 물약 인벤토리
/// [roll] 0~99 범위의 난수 (드랍 확률 판정) /// [roll] 0~99 범위의 난수 (드랍 확률 판정)
/// [typeRoll] 0~99 범위의 난수 (HP/MP 결정) /// [typeRoll] 0~99 범위의 난수 (HP/MP 결정)
/// Returns: (업데이트된 인벤토리, 드랍된 물약 또는 null) /// Returns: (업데이트된 인벤토리, 드랍된 물약 또는 null)
(PotionInventory, Potion?) tryPotionDrop({ (PotionInventory, Potion?) tryPotionDrop({
required int playerLevel, required int playerLevel,
required int monsterLevel,
required MonsterGrade monsterGrade,
required PotionInventory inventory, required PotionInventory inventory,
required int roll, required int roll,
required int typeRoll, required int typeRoll,
}) { }) {
// 드랍 확률 계산 // 기본 드랍 확률 계산
final dropChance = (baseDropChance + playerLevel * dropChancePerLevel) var dropChance = (baseDropChance + playerLevel * dropChancePerLevel)
.clamp(baseDropChance, maxDropChance); .clamp(baseDropChance, maxDropChance);
// 몬스터 등급 보너스 (Elite +5%, Boss +15%)
dropChance += monsterGrade.potionDropBonus;
// 몬스터 레벨 > 플레이어 레벨이면 추가 확률 (+1%/레벨 차이)
if (monsterLevel > playerLevel) {
dropChance += (monsterLevel - playerLevel) * 0.01;
}
// 최대 확률 제한 (50%)
dropChance = dropChance.clamp(0.0, 0.5);
final dropThreshold = (dropChance * 100).round(); final dropThreshold = (dropChance * 100).round();
// 드랍 실패 // 드랍 실패
@@ -380,8 +399,9 @@ class PotionService {
// 물약 타입 결정 (60% HP, 40% MP) // 물약 타입 결정 (60% HP, 40% MP)
final isHpPotion = typeRoll < 60; final isHpPotion = typeRoll < 60;
// 레벨 기반 티어 결정 // 티어 결정: max(플레이어 레벨, 몬스터 레벨) 기반
final tier = PotionData.tierForLevel(playerLevel); final effectiveLevel = math.max(playerLevel, monsterLevel);
final tier = PotionData.tierForLevel(effectiveLevel);
// 물약 선택 // 물약 선택
final Potion? potion; final Potion? potion;

View File

@@ -14,6 +14,7 @@ import 'package:asciineverdie/src/core/model/equipment_item.dart';
import 'package:asciineverdie/src/core/model/equipment_slot.dart'; import 'package:asciineverdie/src/core/model/equipment_slot.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/monster_grade.dart';
import 'package:asciineverdie/src/core/model/potion.dart'; import 'package:asciineverdie/src/core/model/potion.dart';
import 'package:asciineverdie/src/core/model/pq_config.dart'; import 'package:asciineverdie/src/core/model/pq_config.dart';
import 'package:asciineverdie/src/core/model/skill.dart'; import 'package:asciineverdie/src/core/model/skill.dart';
@@ -591,6 +592,7 @@ class ProgressService {
monsterBaseName: monsterResult.baseName, monsterBaseName: monsterResult.baseName,
monsterPart: monsterResult.part, monsterPart: monsterResult.part,
monsterLevel: monsterResult.level, monsterLevel: monsterResult.level,
monsterGrade: monsterResult.grade,
), ),
currentCombat: combatState, currentCombat: combatState,
); );
@@ -646,6 +648,7 @@ class ProgressService {
monsterBaseName: 'Glitch God', monsterBaseName: 'Glitch God',
monsterPart: '*', // 특수 전리품 monsterPart: '*', // 특수 전리품
monsterLevel: glitchGod.level, monsterLevel: glitchGod.level,
monsterGrade: MonsterGrade.boss, // 최종 보스는 항상 boss 등급
), ),
currentCombat: combatState, currentCombat: combatState,
); );
@@ -963,8 +966,12 @@ class ProgressService {
// 물약 드랍 시도 // 물약 드랍 시도
final potionService = const PotionService(); final potionService = const PotionService();
final rng = resultState.rng; final rng = resultState.rng;
final monsterLevel = taskInfo.monsterLevel ?? resultState.traits.level;
final monsterGrade = taskInfo.monsterGrade ?? MonsterGrade.normal;
final (updatedPotionInventory, droppedPotion) = potionService.tryPotionDrop( final (updatedPotionInventory, droppedPotion) = potionService.tryPotionDrop(
playerLevel: resultState.traits.level, playerLevel: resultState.traits.level,
monsterLevel: monsterLevel,
monsterGrade: monsterGrade,
inventory: resultState.potionInventory, inventory: resultState.potionInventory,
roll: rng.nextInt(100), roll: rng.nextInt(100),
typeRoll: rng.nextInt(100), typeRoll: rng.nextInt(100),