feat: refactor refinement cost logic and update success rates and combat reward formulas

This commit is contained in:
이정수 2026-03-30 17:41:20 +09:00
parent 0c7a562b00
commit 793bba5a6a
2 changed files with 43 additions and 9 deletions

View File

@ -10,7 +10,16 @@ The Refinement mini-game allows users to strengthen their virtual weapons, parti
### 1. Weapon Refinement
- **Progression**: Level- **재련 비용**: `floor(10 × 1.6^level)G` (레벨별 기하급수적 증가)
- **판매 가격**: `floor(현재_단계_비용 × 2)G`
- **내구도**: 전투 참여 시(공격/방어 모두) 내구도 -1.
- **재련 성공 확률**:
- 0→4강: 100% ~ 90% (비교적 안전)
- 4→5강: **5%** (급락)
- 5→10강: 4% ~ 0.5% (사실상 불가)
- 10강 이상: **0.1%** (신화의 영역)
- **전투 보상**: `floor(승리자_현재_강화_비용 × 2.0) + (레벨_차이 × 5000)G`
- **판매 가격**: `floor(현재_단계_비용 × 2)G`
- **전투 규칙**:
- 0강 무기 소유자는 전투를 걸 수 없으며, 공격 대상으로 지정될 수도 없습니다.
- 전투 참여 시(공격/방어 모두) 내구도 -1.
- **파괴 조건**:
- 재련 실패 시 낮은 확률로 파괴 (0단계 회귀).
- 내구도가 0인 상태에서 전투 시도(공격) 시 전투 후 무기 파괴.

View File

@ -29,6 +29,13 @@ export class RefinementService {
private static START_GOLD = 1000;
private static CHECKIN_GOLD = 500;
/**
*
*/
public static calculateCost(level: number): number {
return Math.floor(10 * Math.pow(1.6, level));
}
/**
*
*/
@ -40,7 +47,7 @@ export class RefinementService {
}
// 비용 계산: floor(10 * 1.6^level)
const cost = Math.floor(10 * Math.pow(1.6, profile.weaponLevel));
const cost = this.calculateCost(profile.weaponLevel);
if (profile.gold < cost) {
throw new Error('골드가 부족합니다.');
@ -48,9 +55,22 @@ export class RefinementService {
const fever = await FeverService.getFeverBonus(guildId);
// 확률 계산 (20단계 기준 조정)
// 기본 성공률 = max(5%, 80% - level * 4%)
const baseSuccessRate = Math.max(0.05, 0.8 - profile.weaponLevel * 0.04);
const level = profile.weaponLevel;
let baseSuccessRate = 0;
if (level === 0) baseSuccessRate = 1.0;
else if (level === 1) baseSuccessRate = 0.98;
else if (level === 2) baseSuccessRate = 0.95;
else if (level === 3) baseSuccessRate = 0.92;
else if (level === 4) baseSuccessRate = 0.90;
else if (level === 5) baseSuccessRate = 0.05; // 급격한 하향 구간 시작
else if (level === 6) baseSuccessRate = 0.04;
else if (level === 7) baseSuccessRate = 0.03;
else if (level === 8) baseSuccessRate = 0.02;
else if (level === 9) baseSuccessRate = 0.01;
else if (level < 15) baseSuccessRate = 0.005; // 0.5%
else baseSuccessRate = 0.001; // 0.1% (신화적인 영역)
const successRate = baseSuccessRate + (fever.active ? fever.bonusRate : 0);
const random = Math.random();
@ -105,6 +125,10 @@ export class RefinementService {
const attacker = await this.getOrCreateProfile(attackerId, guildId);
const target = await this.getOrCreateProfile(targetId, guildId);
if (attacker.weaponLevel === 0 || target.weaponLevel === 0) {
throw new Error('0강 무기 소유자는 전투에 참여할 수 없습니다. 최소 1강 이상 강화하세요.');
}
if (attacker.isDisabled) throw new Error('현재 전투 불능 상태입니다. 무기 수리(재련 시도 등)가 필요합니다.');
let attackerDestroyed = false;
@ -120,10 +144,11 @@ export class RefinementService {
const winnerId = isAttackerWin ? attackerId : targetId;
const loserId = isAttackerWin ? targetId : attackerId;
// 보상 계산: 내 강화도 * 50G +- |차이| * 10G
// 보상 계산: 승리자의 현재 강화 비용의 200% + |차이| * 5,000G
const levelDiff = Math.abs(attacker.weaponLevel - target.weaponLevel);
const baseReward = (isAttackerWin ? attacker.weaponLevel : target.weaponLevel) * 50;
const reward = Math.max(100, baseReward + (isAttackerWin ? -levelDiff : levelDiff) * 10);
const winnerLevel = isAttackerWin ? attacker.weaponLevel : target.weaponLevel;
const winnerCost = this.calculateCost(winnerLevel);
const reward = Math.floor(winnerCost * 2.0) + (levelDiff * 5000);
// 내구도 감소 (양쪽 모두 -1)
const newAttackerDurability = Math.max(0, attacker.durability - 1);
@ -206,7 +231,7 @@ export class RefinementService {
const profile = await this.getOrCreateProfile(userId, guildId);
if (profile.weaponLevel === 0) throw new Error('0단계 무기는 판매할 수 없습니다.');
const currentCost = Math.floor(10 * Math.pow(1.6, profile.weaponLevel));
const currentCost = this.calculateCost(profile.weaponLevel);
const price = Math.floor(currentCost * 2);
const updated = await prisma.refinementProfile.update({