zenno: lint fixes
This commit is contained in:
78
zenno/src/lib/alpha123Umalator.ts
Normal file
78
zenno/src/lib/alpha123Umalator.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { AptitudeLevel, Mood, RunningStyle } from './race';
|
||||||
|
import type { Runner } from './runner';
|
||||||
|
|
||||||
|
const aptitude_map = {
|
||||||
|
G: AptitudeLevel.G,
|
||||||
|
F: AptitudeLevel.F,
|
||||||
|
E: AptitudeLevel.E,
|
||||||
|
D: AptitudeLevel.D,
|
||||||
|
C: AptitudeLevel.C,
|
||||||
|
B: AptitudeLevel.B,
|
||||||
|
A: AptitudeLevel.A,
|
||||||
|
S: AptitudeLevel.S,
|
||||||
|
} as const;
|
||||||
|
type AptitudeString = keyof typeof aptitude_map;
|
||||||
|
|
||||||
|
const style_map = {
|
||||||
|
Nige: RunningStyle.FrontRunner,
|
||||||
|
Sentou: RunningStyle.PaceChaser,
|
||||||
|
Sasi: RunningStyle.LateSurger,
|
||||||
|
Oikomi: RunningStyle.EndCloser,
|
||||||
|
Oonige: RunningStyle.GreatEscape,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export interface ImportUma {
|
||||||
|
outfitId: string;
|
||||||
|
starCount: number;
|
||||||
|
speed: number;
|
||||||
|
stamina: number;
|
||||||
|
power: number;
|
||||||
|
guts: number;
|
||||||
|
wisdom: number;
|
||||||
|
strategy: keyof typeof style_map;
|
||||||
|
distanceAptitude: AptitudeString;
|
||||||
|
surfaceAptitude: AptitudeString;
|
||||||
|
strategyAptitude: AptitudeString;
|
||||||
|
aptitudes: [
|
||||||
|
AptitudeString,
|
||||||
|
AptitudeString,
|
||||||
|
AptitudeString,
|
||||||
|
AptitudeString,
|
||||||
|
AptitudeString,
|
||||||
|
AptitudeString,
|
||||||
|
AptitudeString,
|
||||||
|
AptitudeString,
|
||||||
|
AptitudeString,
|
||||||
|
AptitudeString,
|
||||||
|
];
|
||||||
|
skills: string[];
|
||||||
|
uniqueLv: number;
|
||||||
|
mood: Mood;
|
||||||
|
popularity: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function load(obj: ImportUma, name?: string): Runner {
|
||||||
|
return {
|
||||||
|
name: name ?? '',
|
||||||
|
chara_card_id: obj.outfitId !== '' ? parseInt(obj.outfitId) : 0,
|
||||||
|
style: style_map[obj.strategy],
|
||||||
|
mood: obj.mood,
|
||||||
|
speed: obj.speed,
|
||||||
|
stamina: obj.stamina,
|
||||||
|
power: obj.power,
|
||||||
|
guts: obj.guts,
|
||||||
|
wit: obj.wisdom,
|
||||||
|
sprint: aptitude_map[obj.aptitudes[0]],
|
||||||
|
mile: aptitude_map[obj.aptitudes[1]],
|
||||||
|
medium: aptitude_map[obj.aptitudes[2]],
|
||||||
|
long: aptitude_map[obj.aptitudes[3]],
|
||||||
|
front: aptitude_map[obj.aptitudes[4]],
|
||||||
|
pace: aptitude_map[obj.aptitudes[5]],
|
||||||
|
late: aptitude_map[obj.aptitudes[6]],
|
||||||
|
end: aptitude_map[obj.aptitudes[7]],
|
||||||
|
turf: aptitude_map[obj.aptitudes[8]],
|
||||||
|
dirt: aptitude_map[obj.aptitudes[9]],
|
||||||
|
skills: obj.skills.map((s) => parseInt(s)),
|
||||||
|
unique_level: obj.uniqueLv,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
// Umamusume race mechanics adapted from KuromiAK's doc:
|
// Umamusume race mechanics adapted from KuromiAK's doc:
|
||||||
// https://docs.google.com/document/d/15VzW9W2tXBBTibBRbZ8IVpW6HaMX8H0RP03kq6Az7Xg/edit?usp=sharing
|
// https://docs.google.com/document/d/15VzW9W2tXBBTibBRbZ8IVpW6HaMX8H0RP03kq6Az7Xg/edit?usp=sharing
|
||||||
|
|
||||||
import type { Uma } from './data/uma';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fundamental stats of umas.
|
* Fundamental stats of umas.
|
||||||
*/
|
*/
|
||||||
@@ -19,70 +17,6 @@ export enum Stat {
|
|||||||
*/
|
*/
|
||||||
export const StatList = [Stat.Speed, Stat.Stamina, Stat.Power, Stat.Guts, Stat.Wit] as const;
|
export const StatList = [Stat.Speed, Stat.Stamina, Stat.Power, Stat.Guts, Stat.Wit] as const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Race runner, i.e. a trained horse.
|
|
||||||
*/
|
|
||||||
export interface Runner {
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
chara_card_id: number;
|
|
||||||
style: RunningStyle;
|
|
||||||
mood: Mood;
|
|
||||||
|
|
||||||
speed: number;
|
|
||||||
stamina: number;
|
|
||||||
power: number;
|
|
||||||
guts: number;
|
|
||||||
wit: number;
|
|
||||||
|
|
||||||
sprint: AptitudeLevel;
|
|
||||||
mile: AptitudeLevel;
|
|
||||||
medium: AptitudeLevel;
|
|
||||||
long: AptitudeLevel;
|
|
||||||
front: AptitudeLevel;
|
|
||||||
pace: AptitudeLevel;
|
|
||||||
late: AptitudeLevel;
|
|
||||||
end: AptitudeLevel;
|
|
||||||
turf: AptitudeLevel;
|
|
||||||
dirt: AptitudeLevel;
|
|
||||||
|
|
||||||
skills: number[];
|
|
||||||
unique_level: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new runner with baseline stats.
|
|
||||||
* @param name Name to apply to the runner
|
|
||||||
* @param base_uma Character card (trainee or uma) to use for aptitudes; otherwise all aptitudes are A
|
|
||||||
* @returns Baseline runner
|
|
||||||
*/
|
|
||||||
export function new_runner(name?: string, base_uma?: Uma): Runner {
|
|
||||||
return {
|
|
||||||
name: name ?? '',
|
|
||||||
chara_card_id: base_uma?.chara_card_id ?? 0,
|
|
||||||
// TODO(zeph): default running style
|
|
||||||
style: RunningStyle.FrontRunner,
|
|
||||||
mood: Mood.Normal,
|
|
||||||
speed: 1200,
|
|
||||||
stamina: 1200,
|
|
||||||
power: 1200,
|
|
||||||
guts: 1200,
|
|
||||||
wit: 1200,
|
|
||||||
sprint: base_uma?.sprint ?? AptitudeLevel.A,
|
|
||||||
mile: base_uma?.mile ?? AptitudeLevel.A,
|
|
||||||
medium: base_uma?.medium ?? AptitudeLevel.A,
|
|
||||||
long: base_uma?.long ?? AptitudeLevel.A,
|
|
||||||
front: base_uma?.front ?? AptitudeLevel.A,
|
|
||||||
pace: base_uma?.pace ?? AptitudeLevel.A,
|
|
||||||
late: base_uma?.late ?? AptitudeLevel.A,
|
|
||||||
end: base_uma?.end ?? AptitudeLevel.A,
|
|
||||||
turf: base_uma?.turf ?? AptitudeLevel.A,
|
|
||||||
dirt: base_uma?.dirt ?? AptitudeLevel.A,
|
|
||||||
skills: base_uma != null ? [base_uma.unique] : [],
|
|
||||||
unique_level: 4,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mood levels.
|
* Mood levels.
|
||||||
*/
|
*/
|
||||||
@@ -145,106 +79,6 @@ export enum Phase {
|
|||||||
LateRace,
|
LateRace,
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Alpha123Umalator {
|
|
||||||
const aptitude_map = {
|
|
||||||
G: AptitudeLevel.G,
|
|
||||||
F: AptitudeLevel.F,
|
|
||||||
E: AptitudeLevel.E,
|
|
||||||
D: AptitudeLevel.D,
|
|
||||||
C: AptitudeLevel.C,
|
|
||||||
B: AptitudeLevel.B,
|
|
||||||
A: AptitudeLevel.A,
|
|
||||||
S: AptitudeLevel.S,
|
|
||||||
} as const;
|
|
||||||
type AptitudeString = keyof typeof aptitude_map;
|
|
||||||
|
|
||||||
const style_map = {
|
|
||||||
Nige: RunningStyle.FrontRunner,
|
|
||||||
Sentou: RunningStyle.PaceChaser,
|
|
||||||
Sasi: RunningStyle.LateSurger,
|
|
||||||
Oikomi: RunningStyle.EndCloser,
|
|
||||||
Oonige: RunningStyle.GreatEscape,
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export interface ImportUma {
|
|
||||||
outfitId: string;
|
|
||||||
starCount: number;
|
|
||||||
speed: number;
|
|
||||||
stamina: number;
|
|
||||||
power: number;
|
|
||||||
guts: number;
|
|
||||||
wisdom: number;
|
|
||||||
strategy: keyof typeof style_map;
|
|
||||||
distanceAptitude: AptitudeString;
|
|
||||||
surfaceAptitude: AptitudeString;
|
|
||||||
strategyAptitude: AptitudeString;
|
|
||||||
aptitudes: [
|
|
||||||
AptitudeString,
|
|
||||||
AptitudeString,
|
|
||||||
AptitudeString,
|
|
||||||
AptitudeString,
|
|
||||||
AptitudeString,
|
|
||||||
AptitudeString,
|
|
||||||
AptitudeString,
|
|
||||||
AptitudeString,
|
|
||||||
AptitudeString,
|
|
||||||
AptitudeString,
|
|
||||||
];
|
|
||||||
skills: string[];
|
|
||||||
uniqueLv: number;
|
|
||||||
mood: Mood;
|
|
||||||
popularity: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function load(obj: ImportUma, name?: string): Runner {
|
|
||||||
return {
|
|
||||||
name: name ?? '',
|
|
||||||
chara_card_id: obj.outfitId !== '' ? parseInt(obj.outfitId) : 0,
|
|
||||||
style: style_map[obj.strategy],
|
|
||||||
mood: obj.mood,
|
|
||||||
speed: obj.speed,
|
|
||||||
stamina: obj.stamina,
|
|
||||||
power: obj.power,
|
|
||||||
guts: obj.guts,
|
|
||||||
wit: obj.wisdom,
|
|
||||||
sprint: aptitude_map[obj.aptitudes[0]],
|
|
||||||
mile: aptitude_map[obj.aptitudes[1]],
|
|
||||||
medium: aptitude_map[obj.aptitudes[2]],
|
|
||||||
long: aptitude_map[obj.aptitudes[3]],
|
|
||||||
front: aptitude_map[obj.aptitudes[4]],
|
|
||||||
pace: aptitude_map[obj.aptitudes[5]],
|
|
||||||
late: aptitude_map[obj.aptitudes[6]],
|
|
||||||
end: aptitude_map[obj.aptitudes[7]],
|
|
||||||
turf: aptitude_map[obj.aptitudes[8]],
|
|
||||||
dirt: aptitude_map[obj.aptitudes[9]],
|
|
||||||
skills: obj.skills.map((s) => parseInt(s)),
|
|
||||||
unique_level: obj.uniqueLv,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import a runner from an external source.
|
|
||||||
* @param obj Decoded object to import
|
|
||||||
* @param name Name or memo to apply to the runner
|
|
||||||
* @returns Imported runner, or null if import was not possible
|
|
||||||
*/
|
|
||||||
export function import_runner(obj: any, name?: string): Runner | null {
|
|
||||||
// TODO(zeph): check for keys that identify the uma source
|
|
||||||
if (typeof obj === 'object') {
|
|
||||||
try {
|
|
||||||
const r = Alpha123Umalator.load(obj as Alpha123Umalator.ImportUma, name);
|
|
||||||
// TODO(zeph): validate?
|
|
||||||
return r;
|
|
||||||
} catch (exc) {
|
|
||||||
console.warn('failed to import', obj, 'as alpha123 umalator:', exc);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.warn('no guess on how to import', obj);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function baseSpeed(raceLen: number): number {
|
function baseSpeed(raceLen: number): number {
|
||||||
return 20 - (raceLen - 2000) / 1000;
|
return 20 - (raceLen - 2000) / 1000;
|
||||||
}
|
}
|
||||||
|
|||||||
89
zenno/src/lib/runner.ts
Normal file
89
zenno/src/lib/runner.ts
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import type { Uma } from './data/uma';
|
||||||
|
import { AptitudeLevel, Mood, RunningStyle } from './race';
|
||||||
|
import * as alpha123Umalator from './alpha123Umalator';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Race runner, i.e. a trained horse.
|
||||||
|
*/
|
||||||
|
export interface Runner {
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
chara_card_id: number;
|
||||||
|
style: RunningStyle;
|
||||||
|
mood: Mood;
|
||||||
|
|
||||||
|
speed: number;
|
||||||
|
stamina: number;
|
||||||
|
power: number;
|
||||||
|
guts: number;
|
||||||
|
wit: number;
|
||||||
|
|
||||||
|
sprint: AptitudeLevel;
|
||||||
|
mile: AptitudeLevel;
|
||||||
|
medium: AptitudeLevel;
|
||||||
|
long: AptitudeLevel;
|
||||||
|
front: AptitudeLevel;
|
||||||
|
pace: AptitudeLevel;
|
||||||
|
late: AptitudeLevel;
|
||||||
|
end: AptitudeLevel;
|
||||||
|
turf: AptitudeLevel;
|
||||||
|
dirt: AptitudeLevel;
|
||||||
|
|
||||||
|
skills: number[];
|
||||||
|
unique_level: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new runner with baseline stats.
|
||||||
|
* @param name Name to apply to the runner
|
||||||
|
* @param base_uma Character card (trainee or uma) to use for aptitudes; otherwise all aptitudes are A
|
||||||
|
* @returns Baseline runner
|
||||||
|
*/
|
||||||
|
export function new_runner(name?: string, base_uma?: Uma): Runner {
|
||||||
|
return {
|
||||||
|
name: name ?? '',
|
||||||
|
chara_card_id: base_uma?.chara_card_id ?? 0,
|
||||||
|
// TODO(zeph): default running style
|
||||||
|
style: RunningStyle.FrontRunner,
|
||||||
|
mood: Mood.Normal,
|
||||||
|
speed: 1200,
|
||||||
|
stamina: 1200,
|
||||||
|
power: 1200,
|
||||||
|
guts: 1200,
|
||||||
|
wit: 1200,
|
||||||
|
sprint: base_uma?.sprint ?? AptitudeLevel.A,
|
||||||
|
mile: base_uma?.mile ?? AptitudeLevel.A,
|
||||||
|
medium: base_uma?.medium ?? AptitudeLevel.A,
|
||||||
|
long: base_uma?.long ?? AptitudeLevel.A,
|
||||||
|
front: base_uma?.front ?? AptitudeLevel.A,
|
||||||
|
pace: base_uma?.pace ?? AptitudeLevel.A,
|
||||||
|
late: base_uma?.late ?? AptitudeLevel.A,
|
||||||
|
end: base_uma?.end ?? AptitudeLevel.A,
|
||||||
|
turf: base_uma?.turf ?? AptitudeLevel.A,
|
||||||
|
dirt: base_uma?.dirt ?? AptitudeLevel.A,
|
||||||
|
skills: base_uma != null ? [base_uma.unique] : [],
|
||||||
|
unique_level: 4,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import a runner from an external source.
|
||||||
|
* @param obj Decoded object to import
|
||||||
|
* @param name Name or memo to apply to the runner
|
||||||
|
* @returns Imported runner, or null if import was not possible
|
||||||
|
*/
|
||||||
|
export function import_runner(obj: unknown, name?: string): Runner | null {
|
||||||
|
// TODO(zeph): check for keys that identify the uma source
|
||||||
|
if (typeof obj === 'object') {
|
||||||
|
try {
|
||||||
|
const r = alpha123Umalator.load(obj as alpha123Umalator.ImportUma, name);
|
||||||
|
// TODO(zeph): validate?
|
||||||
|
return r;
|
||||||
|
} catch (exc) {
|
||||||
|
console.warn('failed to import', obj, 'as alpha123 umalator:', exc);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.warn('no guess on how to import', obj);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -131,14 +131,14 @@
|
|||||||
<SpeedDur speed={boost} dur={skillDuration(dur, raceLen)} accel={accel[phase]} decel={decel[phase]}>{name}</SpeedDur>
|
<SpeedDur speed={boost} dur={skillDuration(dur, raceLen)} accel={accel[phase]} decel={decel[phase]}>{name}</SpeedDur>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="mx-auto py-4 h-60 md:h-96 md:w-3xl">
|
<div class="mx-auto h-60 py-4 md:h-96 md:w-3xl">
|
||||||
<StatChart class="flex-1" stat={Stat.Guts} y={ssY} yLabel="Lengths Gained" range={[0, 1.5, 2.5]} xRule={gutsStat} {yRule} />
|
<StatChart class="flex-1" stat={Stat.Guts} y={ssY} yLabel="Lengths Gained" range={[0, 1.5, 2.5]} xRule={gutsStat} {yRule} />
|
||||||
</div>
|
</div>
|
||||||
<div class="mx-auto mt-4 md:mt-0 py-4 h-60 md:h-96 md:w-3xl">
|
<div class="mx-auto mt-4 h-60 py-4 md:mt-0 md:h-96 md:w-3xl">
|
||||||
<StatChart class="flex-1" stat={Stat.Power} y={lcY} yLabel="Lengths Gained" range={[0, 1.5, 2.5]} xRule={powerStat} {yRule} />
|
<StatChart class="flex-1" stat={Stat.Power} y={lcY} yLabel="Lengths Gained" range={[0, 1.5, 2.5]} xRule={powerStat} {yRule} />
|
||||||
</div>
|
</div>
|
||||||
<div class="mx-auto mt-12 md:mt-8 w-full max-w-4xl border-t">
|
<div class="mx-auto mt-12 w-full max-w-4xl border-t md:mt-8">
|
||||||
<ul class="list-disc ml-4">
|
<ul class="ml-4 list-disc">
|
||||||
<li>All lengths gained include acceleration at the beginning of each speed boost and deceleration after its end.</li>
|
<li>All lengths gained include acceleration at the beginning of each speed boost and deceleration after its end.</li>
|
||||||
<li>Each effect is assumed to be isolated and executed on level ground.</li>
|
<li>Each effect is assumed to be isolated and executed on level ground.</li>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -18,14 +18,14 @@
|
|||||||
const decels = $derived([decel].flat(1));
|
const decels = $derived([decel].flat(1));
|
||||||
|
|
||||||
const gain = $derived(decels.map((d) => speedGain(speed, accel, d, dur) / HORSE_LENGTH));
|
const gain = $derived(decels.map((d) => speedGain(speed, accel, d, dur) / HORSE_LENGTH));
|
||||||
const text = $derived(gain.map(fmtp).join(' – '));
|
const text = $derived(gain.map(fmtp).join(' – '));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="m-2 flex h-full w-full max-w-80 flex-1 flex-col rounded-md border p-2 text-center shadow-sm transition-shadow hover:shadow-md"
|
class="m-2 flex h-full w-full max-w-80 flex-1 flex-col rounded-md border p-2 text-center shadow-sm transition-shadow hover:shadow-md"
|
||||||
>
|
>
|
||||||
<div class="block">{@render children()}</div>
|
<div class="block">{@render children()}</div>
|
||||||
<span class="block text-xl">{@html text} L</span>
|
<span class="block text-xl">{text} L</span>
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
<span class="flex-1 text-xs">{fmtp(speed)} m/s</span>
|
<span class="flex-1 text-xs">{fmtp(speed)} m/s</span>
|
||||||
<span class="flex-1 text-xs">{dur.toFixed(3)} s</span>
|
<span class="flex-1 text-xs">{dur.toFixed(3)} s</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user