zenno/doc/frbm: chart and calcs for section speed

This commit is contained in:
2026-05-24 17:55:57 -04:00
parent bd99cfaa6d
commit b1c6850ce1
4 changed files with 191 additions and 28 deletions
+64
View File
@@ -1,6 +1,7 @@
// Umamusume race mechanics adapted from KuromiAK's doc:
// https://docs.google.com/document/d/15VzW9W2tXBBTibBRbZ8IVpW6HaMX8H0RP03kq6Az7Xg/edit?usp=sharing
import * as math from "mathjs";
import { binomPMF } from "./prob";
/**
@@ -43,6 +44,17 @@ export enum RunningStyle {
GreatEscape,
}
/**
* Running styles with their proper names, for easy iterating.
*/
export const RUNNING_STYLES = [
['Front Runner', RunningStyle.FrontRunner],
['Pace Chaser', RunningStyle.PaceChaser],
['Late Surger', RunningStyle.LateSurger],
['End Closer', RunningStyle.EndCloser],
['Great Escape', RunningStyle.GreatEscape],
] as const;
/**
* Aptitude or proficiency levels.
*/
@@ -95,6 +107,40 @@ const speedStrategyPhaseCoeff = [
const distanceProficiencyMod = [0.1, 0.2, 0.4, 0.6, 0.8, 0.9, 1.0, 1.05] as const;
/**
* Calculate the range of section speed values for a horse in early or mid race.
* @param raceLen Length of the race in meters
* @param baseWit Base wit, after mood but before other modifiers
* @param witStat Final wit stat, including strategy proficiency and skills
* @param style Horse's running style
* @param phase Phase of the current section
*/
export function sectionSpeed(raceLen: number, baseWit: number, witStat: number, style: RunningStyle, phase: Exclude<Phase, Phase.LateRace>): [number, number];
/**
* Calculate the range of section speed values for a horse not spurting during late race.
* @param raceLen Length of the race in meters
* @param speedStat Final speed stat
* @param baseWit Base wit, after mood but before other modifiers
* @param witStat Final wit stat, including strategy proficiency and skills
* @param style Horse's running style
* @param distance Hores's distance proficiency aptitude
* @param phase Phase.LateRace
*/
export function sectionSpeed(raceLen: number, speedStat: number, baseWit: number, witStat: number, style: RunningStyle, distance: AptitudeLevel, phase: Phase.LateRace): [number, number];
export function sectionSpeed(raceLen: number, speedStatOrBaseWit: number, baseWitOrWitStat: number, witStatOrStyle: number | RunningStyle, styleOrPhase: RunningStyle | Phase, distance?: AptitudeLevel, lateRace?: Phase.LateRace): [number, number] {
const speedStat = lateRace !== undefined ? speedStatOrBaseWit : 0;
const baseWit = lateRace !== undefined ? baseWitOrWitStat : speedStatOrBaseWit;
const witStat = lateRace !== undefined ? witStatOrStyle : baseWitOrWitStat;
const style = lateRace !== undefined ? styleOrPhase as RunningStyle : witStatOrStyle as RunningStyle;
const phase = lateRace !== undefined ? lateRace : styleOrPhase as Phase;
const base = baseSpeed(raceLen);
const baseTarget = base * speedStrategyPhaseCoeff[style][phase];
const late = phase === Phase.LateRace ? (math.sqrt(500 * speedStat) as number) * distanceProficiencyMod[distance ?? AptitudeLevel.A] * 0.002 : 0;
const u = witStat / 550000 * math.log10(baseWit * 0.1);
const l = u - 0.0065;
return [baseTarget + late + base*l, baseTarget + late + base*u];
}
/**
* Calculate an Uma's last spurt target speed.
* @param speedStat Adjusted speed stat
@@ -326,3 +372,21 @@ export function speedGain(speedBonus: number, dur: number, accel: number | null,
export function downhillAccelEnterChance(witStat: number): number {
return witStat * 0.0004;
}
/**
* Calculate the chance for a front runner to enter speed-up or overtake mode when eligible.
* @param witStat Final wit stat, including style aptitude modifier
* @returns Probability each eligible tick to enter speed-up or overtake mode
*/
export function frontModeEnterChance(witStat: number): number {
return 0.2 * math.log10(witStat) - 0.2;
}
/**
* Calculate the chance for a non-front runner to enter pace-up mode when eligible.
* @param witStat Final wit stat, including style aptitude modifier
* @returns Probability each eligible tick to enter pace-up mode
*/
export function paceUpEnterChance(witStat: number): number {
return 0.15 * math.log10(witStat) - 0.15;
}