feat(combat): 디버프 시스템 추가

- CombatEventType.playerDebuff 추가
- CombatState에 activeDebuffs 목록 추가
- SkillService.useDebuffSkill() 구현
- 스킬 자동 선택에 디버프 우선순위 추가
- 밸런스 상수 업데이트
This commit is contained in:
JiWoong Sul
2025-12-30 15:58:03 +09:00
parent bdd3b45329
commit 80b6cd63e3
5 changed files with 294 additions and 51 deletions

View File

@@ -984,12 +984,20 @@ class ProgressService {
var updatedSkillSystem = skillSystem;
var activeDoTs = [...combat.activeDoTs];
var usedPotionTypes = {...combat.usedPotionTypes};
var activeDebuffs = [...combat.activeDebuffs];
PotionInventory? updatedPotionInventory;
// 새 전투 이벤트 수집
final newEvents = <CombatEvent>[];
final timestamp = updatedSkillSystem.elapsedMs;
// =========================================================================
// 만료된 디버프 정리
// =========================================================================
activeDebuffs = activeDebuffs
.where((debuff) => !debuff.isExpired(timestamp))
.toList();
// =========================================================================
// DOT 틱 처리
// =========================================================================
@@ -1090,6 +1098,7 @@ class ProgressService {
skillSystem: updatedSkillSystem,
availableSkillIds: availableSkillIds,
activeDoTs: activeDoTs,
activeDebuffs: activeDebuffs,
);
if (selectedSkill != null && selectedSkill.isAttack) {
@@ -1183,6 +1192,33 @@ class ProgressService {
skillName: selectedSkill.name,
),
);
} else if (selectedSkill != null && selectedSkill.isDebuff) {
// 디버프 스킬 사용
final skillResult = skillService.useDebuffSkill(
skill: selectedSkill,
player: playerStats,
skillSystem: updatedSkillSystem,
currentDebuffs: activeDebuffs,
);
playerStats = skillResult.updatedPlayer;
updatedSkillSystem = skillResult.updatedSkillSystem;
// 디버프 효과 추가 (기존 같은 디버프 제거 후)
if (skillResult.debuffEffect != null) {
activeDebuffs = activeDebuffs
.where((d) => d.effect.id != skillResult.debuffEffect!.effect.id)
.toList()
..add(skillResult.debuffEffect!);
}
// 디버프 이벤트 생성
newEvents.add(
CombatEvent.playerDebuff(
timestamp: timestamp,
skillName: selectedSkill.name,
targetName: monsterStats.name,
),
);
} else {
// 일반 공격
final attackResult = calculator.playerAttackMonster(
@@ -1221,8 +1257,25 @@ class ProgressService {
// 몬스터가 살아있으면 반격
if (monsterStats.isAlive &&
monsterAccumulator >= monsterStats.attackDelayMs) {
// 디버프 효과 적용된 몬스터 스탯 계산
var debuffedMonster = monsterStats;
if (activeDebuffs.isNotEmpty) {
double atkMod = 0;
for (final debuff in activeDebuffs) {
if (!debuff.isExpired(timestamp)) {
atkMod += debuff.effect.atkModifier; // 음수 값
}
}
// ATK 감소 적용 (최소 10% ATK 유지)
final newAtk = (monsterStats.atk * (1 + atkMod)).round().clamp(
monsterStats.atk ~/ 10,
monsterStats.atk,
);
debuffedMonster = monsterStats.copyWith(atk: newAtk);
}
final attackResult = calculator.monsterAttackPlayer(
attacker: monsterStats,
attacker: debuffedMonster,
defender: playerStats,
);
playerStats = attackResult.updatedDefender;
@@ -1288,6 +1341,7 @@ class ProgressService {
recentEvents: recentEvents,
activeDoTs: activeDoTs,
usedPotionTypes: usedPotionTypes,
activeDebuffs: activeDebuffs,
),
skillSystem: updatedSkillSystem,
potionInventory: updatedPotionInventory,