feat: refactor refinement cost logic and update success rates and combat reward formulas
This commit is contained in:
parent
0c7a562b00
commit
793bba5a6a
|
|
@ -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인 상태에서 전투 시도(공격) 시 전투 후 무기 파괴.
|
||||
|
|
|
|||
|
|
@ -28,6 +28,13 @@ export class RefinementService {
|
|||
private static MAX_LEVEL = 20;
|
||||
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({
|
||||
|
|
|
|||
Loading…
Reference in New Issue