|
|
|
|
|
|
|
|
|
|
|
export interface CaptureResult { |
|
success: boolean; |
|
shakes: number; |
|
odds: number; |
|
} |
|
|
|
export interface CaptureAttemptParams { |
|
|
|
maxHp: number; |
|
currentHp: number; |
|
baseCatchRate: number; |
|
|
|
|
|
statusEffect?: 'sleep' | 'freeze' | 'poison' | 'burn' | 'paralysis' | 'toxic' | null; |
|
|
|
|
|
battleTurn?: number; |
|
picletLevel?: number; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
export function getCatchRateForTier(tier: string): number { |
|
switch (tier.toLowerCase()) { |
|
case 'legendary': return 3; |
|
case 'high': return 25; |
|
case 'medium': return 75; |
|
case 'low': return 150; |
|
default: return 75; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
function getStatusMultiplier(status: string | null | undefined): number { |
|
switch (status) { |
|
case 'sleep': |
|
case 'freeze': |
|
return 2.0; |
|
case 'poison': |
|
case 'burn': |
|
case 'paralysis': |
|
case 'toxic': |
|
return 1.5; |
|
default: |
|
return 1.0; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function calculateCaptureOdds(params: CaptureAttemptParams): number { |
|
const { maxHp, currentHp, baseCatchRate, statusEffect } = params; |
|
|
|
|
|
const ballMultiplier = 10; |
|
|
|
|
|
|
|
const hpFactor = (maxHp * 3 - currentHp * 2) / (maxHp * 3); |
|
|
|
|
|
const statusMultiplier = getStatusMultiplier(statusEffect); |
|
|
|
|
|
const odds = (baseCatchRate * ballMultiplier / 10) * hpFactor * statusMultiplier; |
|
|
|
return Math.max(0, Math.floor(odds)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function calculateShakeOdds(captureOdds: number): number { |
|
if (captureOdds === 0) return 0; |
|
|
|
const shakeOdds = 1048560 / Math.sqrt(Math.sqrt(16711680 / captureOdds)); |
|
return Math.floor(shakeOdds); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function simulateShake(shakeOdds: number): boolean { |
|
const randomValue = Math.floor(Math.random() * 65536); |
|
return randomValue < shakeOdds; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
export function attemptCapture(params: CaptureAttemptParams): CaptureResult { |
|
const odds = calculateCaptureOdds(params); |
|
|
|
|
|
if (odds > 254) { |
|
return { |
|
success: true, |
|
shakes: 3, |
|
odds |
|
}; |
|
} |
|
|
|
|
|
if (odds === 0) { |
|
return { |
|
success: false, |
|
shakes: 0, |
|
odds |
|
}; |
|
} |
|
|
|
|
|
const shakeOdds = calculateShakeOdds(odds); |
|
|
|
|
|
let shakes = 0; |
|
for (let i = 0; i < 3; i++) { |
|
if (simulateShake(shakeOdds)) { |
|
shakes++; |
|
} else { |
|
|
|
return { |
|
success: false, |
|
shakes, |
|
odds |
|
}; |
|
} |
|
} |
|
|
|
|
|
return { |
|
success: true, |
|
shakes: 3, |
|
odds |
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
export function calculateCapturePercentage(params: CaptureAttemptParams): number { |
|
const odds = calculateCaptureOdds(params); |
|
|
|
|
|
if (odds > 254) return 100; |
|
|
|
|
|
if (odds === 0) return 0; |
|
|
|
|
|
const shakeOdds = calculateShakeOdds(odds); |
|
const shakeSuccessRate = shakeOdds / 65536; |
|
|
|
|
|
const captureRate = Math.pow(shakeSuccessRate, 3) * 100; |
|
|
|
return Math.min(100, Math.max(0.1, captureRate)); |
|
} |
|
|
|
|
|
|
|
|
|
export function getCaptureDescription(percentage: number): string { |
|
if (percentage >= 95) return "Almost certain"; |
|
if (percentage >= 75) return "Very likely"; |
|
if (percentage >= 50) return "Good chance"; |
|
if (percentage >= 25) return "Moderate chance"; |
|
if (percentage >= 10) return "Low chance"; |
|
if (percentage >= 5) return "Very low chance"; |
|
return "Extremely difficult"; |
|
} |
|
|
|
|
|
|
|
|
|
export function simulateMultipleCaptures(params: CaptureAttemptParams, attempts: number = 1000): { |
|
successRate: number; |
|
averageShakes: number; |
|
distribution: { [key: number]: number }; |
|
} { |
|
let successes = 0; |
|
let totalShakes = 0; |
|
const shakeDistribution: { [key: number]: number } = { 0: 0, 1: 0, 2: 0, 3: 0 }; |
|
|
|
for (let i = 0; i < attempts; i++) { |
|
const result = attemptCapture(params); |
|
if (result.success) successes++; |
|
totalShakes += result.shakes; |
|
shakeDistribution[result.shakes]++; |
|
} |
|
|
|
return { |
|
successRate: (successes / attempts) * 100, |
|
averageShakes: totalShakes / attempts, |
|
distribution: shakeDistribution |
|
}; |
|
} |