zenno: update stat charts for new limits
This commit is contained in:
@@ -55,39 +55,37 @@
|
||||
let width = $state(0);
|
||||
let height = $state(0);
|
||||
|
||||
let expand = $state(false);
|
||||
|
||||
const xLabel = $derived(Stat[stat]);
|
||||
const xLabel = $derived(`Raw ${Stat[stat]}`);
|
||||
const xLines = $derived([xRule].flat(1));
|
||||
const xMin = $derived(xRange?.[0] ?? 200);
|
||||
const xMax = $derived.by(() => {
|
||||
if (xRange?.[1] != null) {
|
||||
return xRange[1];
|
||||
}
|
||||
if (expand) {
|
||||
return 2000;
|
||||
}
|
||||
return 100 * Math.ceil(Math.max(1200, ...xLines) / 100);
|
||||
return 100 * Math.ceil(Math.max(2000, ...xLines) / 100);
|
||||
});
|
||||
const xVal = $derived(d3.range(xMin, xMax + 1, 5)); // +1 because d3.range does not include the max
|
||||
const thrX = 1200;
|
||||
|
||||
function adj(x: number): number {
|
||||
return Math.min(x, 1200) + 0.5 * (Math.max(x, 1200) - 1200);
|
||||
}
|
||||
const series = $derived([y].flat(1).filter((s) => s != null));
|
||||
const areas = $derived([yArea].flat(1).filter((s) => s != null));
|
||||
const vals = $derived(series.flatMap(({ y, label }) => xVal.map((x) => ({ x, y: y(x), label }))));
|
||||
const areaVals = $derived(areas.flatMap(({ y1, y2, label }) => xVal.map((x) => ({ x, y1: y1(x), y2: y2(x), label }))));
|
||||
const vals = $derived(series.flatMap(({ y, label }) => xVal.map((x) => ({ x, y: y(adj(x), x), label }))));
|
||||
const areaVals = $derived(areas.flatMap(({ y1, y2, label }) => xVal.map((x) => ({ x, y1: y1(adj(x), x), y2: y2(adj(x), x), label }))));
|
||||
const yRange: [number, number] = $derived.by(() => {
|
||||
if (range != null) {
|
||||
if (range.length === 2) {
|
||||
return range;
|
||||
}
|
||||
return [range[0], expand ? range[2] : range[1]];
|
||||
return [range[0], range[2]];
|
||||
}
|
||||
const l = d3.min(vals, ({ y }) => y) ?? 0;
|
||||
const r = d3.max(vals, ({ y }) => y) ?? 1;
|
||||
return [l, r];
|
||||
});
|
||||
const yLines = $derived(xLines.flatMap((x) => series.map(({ y, label }) => ({ y: y(x), label }))));
|
||||
const yLines = $derived(xLines.flatMap((x) => series.map(({ y, label }) => ({ y: y(adj(x), x), label }))));
|
||||
|
||||
const makeChart: Attachment = (el) => {
|
||||
$effect(() => {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export interface ComputedSeries {
|
||||
y: (x: number) => number;
|
||||
y: (base: number, raw: number) => number;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface ComputedAreas {
|
||||
y1: (x: number) => number;
|
||||
y2: (x: number) => number;
|
||||
y1: (base: number, raw: number) => number;
|
||||
y2: (base: number, raw: number) => number;
|
||||
label: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -519,7 +519,8 @@ export function speedGain(speedBonus: number, dur: number, accel: number | null,
|
||||
* @returns Probability per candidate to accept
|
||||
*/
|
||||
export function reducedSpurtChance(witStat: number): number {
|
||||
return 0.15 + 0.0005 * witStat;
|
||||
// 1900 wit style S exceeds 100% chance if we don't explicitly cap.
|
||||
return Math.min(0.15 + 0.0005 * witStat, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -414,8 +414,8 @@
|
||||
never happen, its duration also scales with the guts stat. Unlike skills, its duration <i>does not</i> scale with race distance.
|
||||
</p>
|
||||
<div class="mb-4 grid h-60 w-full grid-cols-2 md:h-96">
|
||||
<StatChart stat={Stat.Guts} y={ssBoostSeries} yLabel="Speed Bonus (m/s)" range={[0, 0.3]} />
|
||||
<StatChart stat={Stat.Guts} y={ssDurSeries} yLabel="Duration (s)" range={[0, 12]} />
|
||||
<StatChart stat={Stat.Guts} y={ssBoostSeries} yLabel="Speed Bonus (m/s)" range={[0, 0.4]} />
|
||||
<StatChart stat={Stat.Guts} y={ssDurSeries} yLabel="Duration (s)" range={[0, 14]} />
|
||||
</div>
|
||||
<p>
|
||||
Spot struggle also greatly increases HP consumption. For normal front runners, the rate is slightly less than Rushed. For
|
||||
@@ -443,7 +443,7 @@
|
||||
y={laneComboSeries}
|
||||
yLabel="Speed Boost"
|
||||
yRule={lcYRule}
|
||||
range={[0.2, 0.5]}
|
||||
range={[0.2, 0.6]}
|
||||
/>
|
||||
</div>
|
||||
<p>
|
||||
@@ -530,7 +530,7 @@
|
||||
stat={Stat.Wit}
|
||||
y={downhillSeries}
|
||||
yLabel="Entry Chance (% each second)"
|
||||
range={[0, 60]}
|
||||
range={[0, 75]}
|
||||
/>
|
||||
</div>
|
||||
<p>
|
||||
@@ -550,7 +550,7 @@
|
||||
stat={Stat.Wit}
|
||||
yArea={secSpeedSeries}
|
||||
yLabel="Section Speed (m/s)"
|
||||
range={[17.5, 22.5]}
|
||||
range={[17, 23]}
|
||||
plotOptions={{ color: { legend: true } }}
|
||||
/>
|
||||
<div class="mx-auto flex w-full md:max-w-2xl">
|
||||
|
||||
@@ -67,10 +67,13 @@
|
||||
]);
|
||||
const laneChange: ComputedSeries[] = [{ label: 'Lane Change Target Speed', y: (x) => race.laneChangeSpeed(x) }];
|
||||
const gutsSpurt: Array<ComputedSeries | null> = $derived([
|
||||
{ label: `Speed 1200`, y: (x) => race.spurtSpeed(1200, x, style, distanceApt, raceLen) },
|
||||
{ label: `Speed 600`, y: (x) => race.spurtSpeed(600, x, style, distanceApt, raceLen) },
|
||||
{ label: `Speed 1200`, y: (x) => race.spurtSpeed(1200, x, style, distanceApt, raceLen) },
|
||||
// NOTE(zeph): The label is 1600 despite the input being 1400
|
||||
// for raw vs final difference.
|
||||
{ label: `Speed 1600`, y: (x) => race.spurtSpeed(1400, x, style, distanceApt, raceLen) },
|
||||
distanceApt !== race.AptitudeLevel.A
|
||||
? { label: `${raceLenType} A, Speed 1200`, y: (x) => race.spurtSpeed(1200, x, style, race.AptitudeLevel.A, raceLen) }
|
||||
? { label: `${raceLenType} A, Speed 1600`, y: (x) => race.spurtSpeed(1400, x, style, race.AptitudeLevel.A, raceLen) }
|
||||
: null,
|
||||
]);
|
||||
const minSpeed: ComputedSeries[] = $derived([{ label: 'Minimum Speed', y: (x) => race.minSpeed(raceLen, x) }]);
|
||||
@@ -241,7 +244,7 @@
|
||||
|
||||
<Sec h={3} id="spurt-speed">Spurt Speed</Sec>
|
||||
<p>Target speed during the Uma's last spurt. See also <a href="#spurt-speed-guts">the effect of Guts</a>.</p>
|
||||
{@render statChart(race.Stat.Speed, spurtSpeed, 'Spurt Speed (m/s)', [20, 26], { len: true, style: true, dist: true })}
|
||||
{@render statChart(race.Stat.Speed, spurtSpeed, 'Spurt Speed (m/s)', [20, 26.5], { len: true, style: true, dist: true })}
|
||||
|
||||
<Sec h={3} id="late-race-speed">Late Race Speed</Sec>
|
||||
<p>Base target speed during late race when the Uma is not spurting (but not dead yet).</p>
|
||||
@@ -261,7 +264,7 @@
|
||||
href={resolve('/doc/frbm#lane-combo')}>lane combo</a
|
||||
>.
|
||||
</p>
|
||||
{@render statChart(race.Stat.Power, moveLane, 'Target Speed Modifier (m/s)', [0.2, 0.5])}
|
||||
{@render statChart(race.Stat.Power, moveLane, 'Target Speed Modifier (m/s)', [0.2, 0.6])}
|
||||
|
||||
<Sec h={3} id="uphill">Uphill Target Speed Loss</Sec>
|
||||
<p>Target speed modifier while running uphill.</p>
|
||||
@@ -269,7 +272,7 @@
|
||||
|
||||
<Sec h={3} id="acceleration">Acceleration</Sec>
|
||||
<p>Acceleration.</p>
|
||||
{@render statChart(race.Stat.Power, accel, 'Acceleration (m/s²)', [0.1, 0.5], { style: true })}
|
||||
{@render statChart(race.Stat.Power, accel, 'Acceleration (m/s²)', [0.1, 0.55], { style: true })}
|
||||
|
||||
<Sec h={3} id="lane-change-target-speed">Lane Change Target Speed</Sec>
|
||||
<p>Horizontal (rather than forward) target speed of changing lanes.</p>
|
||||
@@ -279,7 +282,7 @@
|
||||
stat={race.Stat.Power}
|
||||
y={laneChange}
|
||||
yLabel="Lane Change Target Speed (CW/s)"
|
||||
range={[0.01, 0.03]}
|
||||
range={[0.01, 0.04]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -287,11 +290,11 @@
|
||||
|
||||
<Sec h={3} id="spurt-speed-guts">Spurt Speed</Sec>
|
||||
<p>Target speed during the Uma's last spurt. See also <a href="#spurt-speed">the effect of Speed</a>.</p>
|
||||
{@render statChart(race.Stat.Guts, gutsSpurt, 'Spurt Speed (m/s)', [20, 26], { len: true, style: true, dist: true })}
|
||||
{@render statChart(race.Stat.Guts, gutsSpurt, 'Spurt Speed (m/s)', [20, 26.5], { len: true, style: true, dist: true })}
|
||||
|
||||
<Sec h={3} id="min-speed">Minimum Speed</Sec>
|
||||
<p>Forced minimum speed, as well as target speed when out of HP.</p>
|
||||
{@render statChart(race.Stat.Guts, minSpeed, 'Target Speed (m/s)', [15.8, 18.4], { len: true })}
|
||||
{@render statChart(race.Stat.Guts, minSpeed, 'Target Speed (m/s)', [15.8, 18.5], { len: true })}
|
||||
|
||||
<Sec h={3} id="hp-rate-mod">Late Race HP Consumption Rate Modifier</Sec>
|
||||
<p>Multiplier on HP consumption rate during late race and last spurt phase.</p>
|
||||
@@ -300,15 +303,15 @@
|
||||
<Sec h={3} id="spot-struggle">Spot Struggle</Sec>
|
||||
<p>Speed boost and duration of spot struggle.</p>
|
||||
<div class="mb-4 grid h-96 w-full md:grid-cols-2">
|
||||
<StatChart stat={race.Stat.Guts} y={ssBoost} yLabel="Speed Bonus (m/s)" range={[0, 0.3]} />
|
||||
<StatChart stat={race.Stat.Guts} y={ssDur} yLabel="Duration (s)" range={[0, 12]} />
|
||||
<StatChart stat={race.Stat.Guts} y={ssBoost} yLabel="Speed Bonus (m/s)" range={[0, 0.4]} />
|
||||
<StatChart stat={race.Stat.Guts} y={ssDur} yLabel="Duration (s)" range={[0, 14]} />
|
||||
</div>
|
||||
|
||||
<Sec h={3} id="dueling">Dueling</Sec>
|
||||
<p>Speed boost and acceleration boost of dueling.</p>
|
||||
<div class="mb-4 grid h-96 w-full md:grid-cols-2">
|
||||
<StatChart stat={race.Stat.Guts} y={duelSpeed} yLabel="Speed Bonus (m/s)" range={[0, 0.65]} />
|
||||
<StatChart stat={race.Stat.Guts} y={duelAccel} yLabel="Acceleration Bonus (m/s²)" range={[0, 0.14]} />
|
||||
<StatChart stat={race.Stat.Guts} y={duelSpeed} yLabel="Speed Bonus (m/s)" range={[0, 0.8]} />
|
||||
<StatChart stat={race.Stat.Guts} y={duelAccel} yLabel="Acceleration Bonus (m/s²)" range={[0, 0.16]} />
|
||||
</div>
|
||||
|
||||
<Sec h={2} id="wit">Wit</Sec>
|
||||
@@ -321,7 +324,7 @@
|
||||
stat={race.Stat.Wit}
|
||||
yArea={secSpeed}
|
||||
yLabel="Section Speed (m/s)"
|
||||
range={[17.5, 22.5]}
|
||||
range={[17, 23]}
|
||||
plotOptions={{ color: { legend: true } }}
|
||||
/>
|
||||
<div class="mx-auto flex w-full md:max-w-2xl">
|
||||
@@ -347,7 +350,7 @@
|
||||
|
||||
<Sec h={3} id="downhill">Downhill Accel Mode Chance</Sec>
|
||||
<p>Chance each second to enter downhill accel mode when eligible.</p>
|
||||
{@render statChart(race.Stat.Wit, downhill, 'Entry Chance (% each second)', [0, 60])}
|
||||
{@render statChart(race.Stat.Wit, downhill, 'Entry Chance (% each second)', [0, 75])}
|
||||
|
||||
<Sec h={3} id="spurt-accept">Reduced Spurt Accept Chance</Sec>
|
||||
<p>Chance to accept each checked spurt delay and speed when not full spurting.</p>
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
stat={Stat.Guts}
|
||||
y={ssY}
|
||||
yLabel="Lengths Gained"
|
||||
range={[0, 1.5, 2.5]}
|
||||
range={[0, 2]}
|
||||
xRule={gutsStat}
|
||||
yRule={ssYRule}
|
||||
/>
|
||||
@@ -178,7 +178,7 @@
|
||||
stat={Stat.Power}
|
||||
y={lcY}
|
||||
yLabel="Lengths Gained"
|
||||
range={[0, 1.5, 2.5]}
|
||||
range={[0, 1.1]}
|
||||
xRule={powerStat}
|
||||
yRule={lcYRule}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user