diff --git a/zenno/src/lib/alpha123Umalator.ts b/zenno/src/lib/alpha123Umalator.ts new file mode 100644 index 0000000..0cf4439 --- /dev/null +++ b/zenno/src/lib/alpha123Umalator.ts @@ -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, + }; +} diff --git a/zenno/src/lib/race.ts b/zenno/src/lib/race.ts index f6d2659..8d72bdf 100644 --- a/zenno/src/lib/race.ts +++ b/zenno/src/lib/race.ts @@ -1,8 +1,6 @@ // Umamusume race mechanics adapted from KuromiAK's doc: // https://docs.google.com/document/d/15VzW9W2tXBBTibBRbZ8IVpW6HaMX8H0RP03kq6Az7Xg/edit?usp=sharing -import type { Uma } from './data/uma'; - /** * 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; -/** - * 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. */ @@ -145,106 +79,6 @@ export enum Phase { 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 { return 20 - (raceLen - 2000) / 1000; } diff --git a/zenno/src/lib/runner.ts b/zenno/src/lib/runner.ts new file mode 100644 index 0000000..8555974 --- /dev/null +++ b/zenno/src/lib/runner.ts @@ -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; +} diff --git a/zenno/src/routes/mspeed/+page.svelte b/zenno/src/routes/mspeed/+page.svelte index 7088b49..f936dee 100644 --- a/zenno/src/routes/mspeed/+page.svelte +++ b/zenno/src/routes/mspeed/+page.svelte @@ -131,14 +131,14 @@ {name} {/each} -
+
-
+
-
-
    +
    +
    • All lengths gained include acceleration at the beginning of each speed boost and deceleration after its end.
    • Each effect is assumed to be isolated and executed on level ground.
    • diff --git a/zenno/src/routes/mspeed/SpeedDur.svelte b/zenno/src/routes/mspeed/SpeedDur.svelte index e59412d..4312b75 100644 --- a/zenno/src/routes/mspeed/SpeedDur.svelte +++ b/zenno/src/routes/mspeed/SpeedDur.svelte @@ -18,14 +18,14 @@ const decels = $derived([decel].flat(1)); 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(' – '));
      {@render children()}
      - {@html text} L + {text} L
      {fmtp(speed)} m/s {dur.toFixed(3)} s