diff --git a/cmd/horsebot/main.go b/cmd/horsebot/main.go index e26d50c..926a588 100644 --- a/cmd/horsebot/main.go +++ b/cmd/horsebot/main.go @@ -44,7 +44,7 @@ func main() { level slog.Level textfmt string ) - flag.StringVar(&addr, "http", ":80", "`address` to bind HTTP server") + flag.StringVar(&addr, "http", ":13669", "`address` to bind HTTP server") flag.StringVar(&mdbf, "mdb", "", "`path` to master.mdb") flag.StringVar(&public, "public", "", "`dir`ectory containing the website to serve") flag.StringVar(&tokenFile, "token", "", "`file` containing the Discord bot token") @@ -154,7 +154,7 @@ func main() { } srv := http.Server{ Addr: addr, - Handler: mux, + Handler: httpmiddle.Logger(mux), ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, BaseContext: func(l net.Listener) context.Context { return ctx }, diff --git a/zenno/src/lib/CharaPick.svelte b/zenno/src/lib/CharaPick.svelte index fc7b55b..e134640 100644 --- a/zenno/src/lib/CharaPick.svelte +++ b/zenno/src/lib/CharaPick.svelte @@ -4,7 +4,7 @@ interface Props { id: string; - characters: Character[]; + characters: Character[] | null; value: number; class?: ClassValue | null; optionClass?: ClassValue | null; @@ -18,7 +18,7 @@ {#if !required} {/if} - {#each characters as c (c.chara_id)} + {#each characters ?? [] as c (c.chara_id)} {/each} diff --git a/zenno/src/lib/Skill.svelte b/zenno/src/lib/Skill.svelte index b8da408..d79a534 100644 --- a/zenno/src/lib/Skill.svelte +++ b/zenno/src/lib/Skill.svelte @@ -3,39 +3,37 @@ ABILITY_SCALE_NAME, ABILITY_TYPE_FORMAT, DURATION_SCALE_NAME, - skills, Target, TARGET_FORMAT, tenThousandths, - ZERO_SKILL, type Ability, type Skill, } from './data/skill'; - interface CommonProps { - hint?: string; + interface Props { + skill: Skill | null | undefined; mention?: boolean; } - type Props = CommonProps & ({ skill: number; name?: never } | { name: string; skill?: never }); + const ZERO_SKILL: Skill = { + skill_id: 0, + name: 'Skill data is loading...', + description: 'Skill data is still loading, or else something went wrong.', + group: 0, + rarity: 1, + group_rate: 1, + wit_check: false, + activations: [], + icon_id: 0, + }; - let { hint, mention, skill, name }: Props = $props(); + let { mention, skill }: Props = $props(); function splitCond(c: string): string[] { return c.replaceAll('&', ' & ').split('@'); } - const s: Readonly = $derived.by(() => { - const l = - skill != null ? skills.global.filter((s) => s.skill_id === skill) : skills.global.filter((s) => s.name.includes(name!)); - if (name != null) { - console.warn(`skills specified as ${name} (${hint}):`, l); - } - if (l.length === 0) { - return ZERO_SKILL; - } - return l[0]; - }); + const s = $derived(skill ?? ZERO_SKILL); const activationClass = $derived(s.activations.length === 1 ? null : 'block my-2 border rounded-md'); const spanClass = $derived(mention ? 'italic' : 'font-bold'); diff --git a/zenno/src/lib/Spark.svelte b/zenno/src/lib/Spark.svelte index df6653a..4612354 100644 --- a/zenno/src/lib/Spark.svelte +++ b/zenno/src/lib/Spark.svelte @@ -1,19 +1,17 @@ -{#if cur != null} +{#if spark != null}
- {cur.name} + {spark.name} {stars}
{/if} diff --git a/zenno/src/lib/data/affinity.ts b/zenno/src/lib/data/affinity.ts index 8146ed6..8f3995c 100644 --- a/zenno/src/lib/data/affinity.ts +++ b/zenno/src/lib/data/affinity.ts @@ -1,5 +1,3 @@ -import globalJSON from '../../../../global/affinity.json'; - /** * Precomputed character pair and trio affinity. */ @@ -24,9 +22,10 @@ export interface Affinity { affinity: number; } -export const affinity = { - global: globalJSON as Affinity[], -} as const; +export async function affinity(): Promise { + const resp = await fetch('/api/global/affinity'); + return resp.json(); +} export function lookup(aff: Affinity[], chara_a: number, chara_b: number, chara_c?: number): number { const [a, b, c] = [chara_a, chara_b, chara_c ?? Infinity].sort((a, b) => a - b); diff --git a/zenno/src/lib/data/character.ts b/zenno/src/lib/data/character.ts index d6b2a3a..0097e9e 100644 --- a/zenno/src/lib/data/character.ts +++ b/zenno/src/lib/data/character.ts @@ -1,5 +1,4 @@ import type { RegionalName } from '$lib/regional-name'; -import globalJSON from '../../../../global/character.json'; /** * Character definitions. @@ -16,11 +15,11 @@ export interface Character { name: string; } -export const character = { - global: globalJSON as Character[], -}; +export async function character(): Promise { + const resp = await fetch('/api/global/character'); + return resp.json(); +} -export const charaNames = globalJSON.reduce( - (m, c) => m.set(c.chara_id, { en: c.name }), - new Map(), -); +export function charaNames(charas: Character[]) { + return charas.reduce((m, c) => m.set(c.chara_id, { en: c.name }), new Map()); +} diff --git a/zenno/src/lib/data/convo.ts b/zenno/src/lib/data/convo.ts index 11630d0..7df53cd 100644 --- a/zenno/src/lib/data/convo.ts +++ b/zenno/src/lib/data/convo.ts @@ -1,5 +1,4 @@ import type { RegionalName } from '$lib/regional-name'; -import globalJSON from '../../../../global/conversation.json'; /** * Lobby conversation data. @@ -17,10 +16,6 @@ export interface Conversation { * Location ID of the conversation. */ location: 110 | 120 | 130 | 210 | 220 | 310 | 410 | 420 | 430 | 510 | 520 | 530; - /** - * English name of the location, for convenience. - */ - location_name: string; /** * First character in the conversation. * Not necessarily equal to chara_id. @@ -40,16 +35,17 @@ export interface Conversation { condition_type: 0 | 1 | 2 | 3 | 4; } -export const conversation = { - global: globalJSON as Conversation[], -}; +export async function conversation(): Promise { + const resp = await fetch('/api/global/conversation'); + return resp.json(); +} -export const byChara = { - global: globalJSON.reduce( +export function byChara(convos: Conversation[]) { + return convos.reduce( (m, c) => m.set(c.chara_id, (m.get(c.chara_id) ?? []).concat(c as Conversation)), - new Map(), - ), -}; + new Map(), + ); +} export const locations: Record = { 110: { name: { en: 'right side front' }, group: 1 }, @@ -74,12 +70,12 @@ function locCharas(convos: Conversation[], locGroup: 1 | 2 | 3 | 4 | 5) { return [...m].toSorted((a, b) => b[1] - a[1]); // descending } -export const groupPopulars = { - global: { - 1: locCharas(conversation.global, 1), - 2: locCharas(conversation.global, 2), - 3: locCharas(conversation.global, 3), - 4: locCharas(conversation.global, 4), - 5: locCharas(conversation.global, 5), - }, -}; +export function groupPopulars(convos: Conversation[]) { + return { + 1: locCharas(convos, 1), + 2: locCharas(convos, 2), + 3: locCharas(convos, 3), + 4: locCharas(convos, 4), + 5: locCharas(convos, 5), + }; +} diff --git a/zenno/src/lib/data/skill.ts b/zenno/src/lib/data/skill.ts index 0e20850..18db074 100644 --- a/zenno/src/lib/data/skill.ts +++ b/zenno/src/lib/data/skill.ts @@ -1,6 +1,3 @@ -import skillGlobal from '../../../../global/skill.json'; -import groupGlobal from '../../../../global/skill-group.json'; - /** * Skill data. */ @@ -323,22 +320,12 @@ export interface SkillGroup { skill_bad?: number; } -export const skills = { - global: skillGlobal as Skill[], -} as const; +export async function skills(): Promise { + const resp = await fetch('/api/global/skill'); + return resp.json(); +} -export const skillGroups = { - global: groupGlobal as SkillGroup[], -} as const; - -export const ZERO_SKILL: Readonly = { - skill_id: 0, - name: 'invalid skill', - description: 'an invalid skill was specified', - group: 0, - rarity: 1, - group_rate: 1, - wit_check: false, - activations: [], - icon_id: 0, -} as const; +export async function skillGroups(): Promise { + const resp = await fetch('/api/global/skill-group'); + return resp.json(); +} diff --git a/zenno/src/lib/data/spark.ts b/zenno/src/lib/data/spark.ts index 0964301..08e46b4 100644 --- a/zenno/src/lib/data/spark.ts +++ b/zenno/src/lib/data/spark.ts @@ -1,5 +1,3 @@ -import globalJSON from '../../../../global/spark.json'; - /** * Sparks, or succession factors. */ @@ -48,6 +46,7 @@ export interface SparkEffect { value2: number; } -export const sparks = { - global: globalJSON as Spark[], -} as const; +export async function sparks(): Promise { + const resp = await fetch('/api/global/spark'); + return resp.json(); +} diff --git a/zenno/src/lib/data/uma.ts b/zenno/src/lib/data/uma.ts index 7863457..61cb322 100644 --- a/zenno/src/lib/data/uma.ts +++ b/zenno/src/lib/data/uma.ts @@ -1,5 +1,3 @@ -import globalJSON from '../../../../global/uma.json'; - /** * Uma or character card definitions. */ @@ -70,6 +68,7 @@ export interface Uma { export type AptitudeLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7; -export const uma = { - global: globalJSON as Uma[], -}; +export async function uma(): Promise { + const resp = await fetch('/api/global/uma'); + return resp.json(); +} diff --git a/zenno/src/routes/convo/+page.svelte b/zenno/src/routes/convo/+page.svelte index 862a4a4..0a7b4af 100644 --- a/zenno/src/routes/convo/+page.svelte +++ b/zenno/src/routes/convo/+page.svelte @@ -1,30 +1,42 @@

Lobby Conversations

@@ -42,32 +54,37 @@ -{#if cur} -
-
- {cur1Name}{alone} - {#if cur2Name} - {cur2Name} - {/if} - {#if cur3Name} - {cur3Name} - {/if} +{#await suggested} +
Loading...
+{:then suggested} + {#if cur} +
+
+ {cur1Name}{alone} + {#if cur2Name} + {cur2Name} + {/if} + {#if cur3Name} + {cur3Name} + {/if} +
+
+ at {curLoc?.name.en} +
-
- at {locations[cur.location].name.en} +
+ Other characters who appear here most often:
-
-
- Other characters who appear here most often: -
-
- {#each suggested as s (s.chara_id)} - {charaNames.get(s.chara_id)?.en}: {s.count}× - {/each} -
-
- - Set these characters to fixed positions (main, upgrades, story, races) to maximize the chance of getting this conversation. - -
-{/if} +
+ {#each suggested as s (s.chara_id)} + {s.chara_name?.en}: {s.count}× + {/each} +
+
+ + Set these characters to fixed positions (main, upgrades, story, races) to maximize the chance of getting this + conversation. + +
+ {/if} +{/await} diff --git a/zenno/src/routes/doc/Article.svelte b/zenno/src/routes/doc/Article.svelte index 011b982..27cf3bc 100644 --- a/zenno/src/routes/doc/Article.svelte +++ b/zenno/src/routes/doc/Article.svelte @@ -20,13 +20,13 @@ tocViewed = true; obs.disconnect(); } - } + }; $effect(() => { if (tocElem == null) { return; } - const obs = new IntersectionObserver(observeTOC, {rootMargin: "20% 0px"}); + const obs = new IntersectionObserver(observeTOC, { rootMargin: '20% 0px' }); obs.observe(tocElem); }); diff --git a/zenno/src/routes/doc/frbm/+page.svelte b/zenno/src/routes/doc/frbm/+page.svelte index a5f8d9a..716e1ae 100644 --- a/zenno/src/routes/doc/frbm/+page.svelte +++ b/zenno/src/routes/doc/frbm/+page.svelte @@ -20,12 +20,93 @@ } from '$lib/race'; import Skill from '$lib/Skill.svelte'; import StatChart from '$lib/StatChart.svelte'; + import { onMount } from 'svelte'; import Article from '../Article.svelte'; import Sec from '../Sec.svelte'; + import * as skill from '$lib/data/skill'; let raceLen = $state(2000); let secSpeedStyle = $state(RunningStyle.FrontRunner); + let allSkillsList: skill.Skill[] = $state([]); + onMount(async () => { + allSkillsList = await skill.skills(); + }); + const allSkills = $derived(allSkillsList.reduce((m, s) => m.set(s.skill_id, s), new Map())); + const skills = $derived({ + view: allSkills.get(100021), + sfv: allSkills.get(100101), + uma2: allSkills.get(100321), + falcoUlt: allSkills.get(100461), + palmerUlt: allSkills.get(100641), + kfc: allSkills.get(110041), + cacao: allSkills.get(110261), + right: allSkills.get(200012), + left: allSkills.get(200022), + firm: allSkills.get(200152), + compSpirit: allSkills.get(200282), + professor: allSkills.get(200331), + cornerAdept: allSkills.get(200332), + cornerConn: allSkills.get(200341), + rushingGale: allSkills.get(200371), + conc: allSkills.get(200431), + focus: allSkills.get(200432), + centerStage: allSkills.get(200451), + pp: allSkills.get(200452), + ramp: allSkills.get(200462), + nsm: allSkills.get(200491), + nn: allSkills.get(200492), + homestretchHaste: allSkills.get(200512), + ttl: allSkills.get(200531), + earlyLead: allSkills.get(200532), + escapeArtist: allSkills.get(200541), + fastPaced: allSkills.get(200542), + unrestrained: allSkills.get(200551), + encroaching: allSkills.get(200641), + spurt: allSkills.get(200642), + turboSprint: allSkills.get(200651), + tunes: allSkills.get(200721), + greed: allSkills.get(201081), + speedEater: allSkills.get(201082), + siphon: allSkills.get(201221), + murmurGold: allSkills.get(201161), + longStraights: allSkills.get(201172), + blast: allSkills.get(201173), + straights: allSkills.get(201242), + corners: allSkills.get(201252), + sixthSense: allSkills.get(201261), + dd: allSkills.get(201262), + topRunner: allSkills.get(201271), + leadersPride: allSkills.get(201272), + moxie: allSkills.get(201282), + eyes: allSkills.get(201441), + savvy: allSkills.get(201522), + lucky7: allSkills.get(201562), + gw: allSkills.get(201601), + thh: allSkills.get(201611), + loneWolf: allSkills.get(201641), + slipstream: allSkills.get(201651), + pto: allSkills.get(201661), + risky: allSkills.get(202032), + runaway: allSkills.get(202051), + burningWIT: allSkills.get(210051), + ignitedWIT: allSkills.get(210052), + radiant: allSkills.get(210061), + redshiftInherit: allSkills.get(900041), + pulseInherit: allSkills.get(900061), + anglingInherit: allSkills.get(900201), + pumpInherit: allSkills.get(900271), + inesInherit: allSkills.get(900311), + uma2Inherit: allSkills.get(900321), + beyondInherit: allSkills.get(900591), + vcInherit: allSkills.get(900681), + pastaInherit: allSkills.get(900141), + kfcInherit: allSkills.get(910041), + barcaroleInherit: allSkills.get(910151), + cacaoInherit: allSkills.get(910261), + mummyCreekInherit: allSkills.get(910451), + }); + function mean2(x: [number, number]): number { return (x[0] + x[1]) * 0.5; } @@ -193,7 +274,7 @@ At the start of late race, if they have enough HP remaining for their last spurt, horses accelerate from the mid race base target speed to their spurt speed, which varies by speed stat, distance aptitude, running style, race distance, and guts stat, in decreasing order of effect. "Last spurt" and "last spurt phase" are different and unrelated things; the latter is only used - mechanically in the condition for . + mechanically in the condition for .

Speed skills add a flat amount of target speed, generally +0.15 m/s for white skills, +0.25 m/s for double circle skills and @@ -204,8 +285,8 @@ Runaway

- The skill converts front runners into the Great Escape running style. However, - no player has ever uttered the words "Great Escape" when talking about Umamusume, presumably because Runaway is a much cooler + The skill converts front runners into the Great Escape running style. However, no + player has ever uttered the words "Great Escape" when talking about Umamusume, presumably because Runaway is a much cooler name. ("Great Escape" is a direct translation of Japanese 大逃げ oonige, whereas "Front Runner" is a more liberal localization of 逃げ nige that technically just means "escape.")

@@ -239,32 +320,31 @@

  • - , sometimes called Rod, is currently the second best skill in the game. Its condition + , sometimes called Rod, is currently the second best skill in the game. Its condition is to be in first place on any late race corner, which is the case immediately at the start of late race on all medium tracks, all but one mile, and some sprints.
  • - On long distance tracks, takes that role instead. The front two horses get it, and it has half + On long distance tracks, takes that role instead. The front two horses get it, and it has half the acceleration value.
  • - On those sprints where Angling is dead, the front-specific option is (VPP, or Pasta). Multi-front - builds also have access to (HCreek). It takes both of them to equal Angling, so such - sprints may be better served gambling on , (VPP, or Pasta). Multi-front + builds also have access to (HCreek). It takes both of them to equal Angling, so such + sprints may be better served gambling on , , and possibly instead. Front runners are especially strong on sprints - for other reasons anyway. + />, and possibly instead. Front runners are especially strong on sprints for + other reasons anyway.

- is the best skill in the game. Unfortunately, for the most part, it's bad on front runners; - generally not a win condition. Activating NSM requires not being in first, which means whoever was used Angling and is - pulling away from you before you accumulate the blocked time to activate it. That said, on VC tracks specifically, NSM or its - white version can be an option for multi-front builds, since the two frontmost horses - get VC and final corner lane movement hasn't happened. + is the best skill in the game. Unfortunately, for the most part, it's bad on front runners; generally + not a win condition. Activating NSM requires not being in first, which means whoever was used Angling and is pulling + away from you before you accumulate the blocked time to activate it. That said, on VC tracks specifically, NSM or its white + version can be an option for multi-front builds, since the two frontmost horses get VC and final + corner lane movement hasn't happened.

Positioning Mechanics @@ -357,14 +437,13 @@ />

- Front runners have access to the skill , which forces a horse who uses it to move outward to - a specific distance from the rail. DD almost always ends shortly before the horse has finished accelerating to early race - speed, so it does not convert the move lane speed modifier into distance. + Front runners have access to the skill , which forces a horse who uses it to move outward to a + specific distance from the rail. DD almost always ends shortly before the horse has finished accelerating to early race speed, + so it does not convert the move lane speed modifier into distance.

- We get advantage from move lane speed modifier by following DD with or or . DD created an opportunity for those return skills to convert into huge forward speed. This setup is called lane combo.

@@ -379,13 +458,12 @@ an efficient pickup as a short burst of high speed to gain position.

- The gold versions of lane combo skills – , , , – are excellent to take on parents, but they generally make lane combo - itself less effective. They have stronger lane change movement boosts, which does not affect the forward speed boost and is likely - to make it last a shorter time, since the horse will return to the rail more quickly. + />, – are excellent to take on parents, but they generally make lane combo itself + less effective. They have stronger lane change movement boosts, which does not affect the forward speed boost and is likely to make + it last a shorter time, since the horse will return to the rail more quickly.

For the same reasons, Ignited WIT is a bit stronger than PP, because it has a smaller effect value and also a longer base @@ -509,9 +587,9 @@

For the most part, there's nothing you can do about the no-overtake zone. The exception to this is with Smart Falcon, who has a speed unique that can fire on any mid race straight. On Tokyo 1600 (both turf and dirt), the first corner is far enough into - mid race that is likely to fire before entering the no-overtake zone, helping to propel - her into a lead that other front runners can't challenge until the corner begins – which is especially strong because it's - harder to pass on corners, and on those tracks, that corner lasts all the way into late race. + mid race that is likely to fire before entering the no-overtake zone, helping to propel her into + a lead that other front runners can't challenge until the corner begins – which is especially strong because it's harder to + pass on corners, and on those tracks, that corner lasts all the way into late race.

Skills @@ -522,37 +600,34 @@

  • - On miles, is the strongest speed skill in the game, because it is both a full strength - speed skill (i.e. +0.15 target speed for base 3s) and a full strength speed debuff. It plays both offense and defense simultaneously. + On miles, is the strongest speed skill in the game, because it is both a full strength speed + skill (i.e. +0.15 target speed for base 3s) and a full strength speed debuff. It plays both offense and defense simultaneously. Every front runner should have it on every mile. Speed Eater technically has a gold version, , but Cygames apparently recognized that it must not ever be allowed to exist, because there's still no source of it on JP.
  • - is a full strength speed skill that is triggered by other skills, so it excels at stacking - – triggering THH with another speed skill is very likely to secure a pass. + is a full strength speed skill that is triggered by other skills, so it excels at stacking – + triggering THH with another speed skill is very likely to secure a pass.
  • - is only a half strength speed skill (base 1.8s), but it fires upon overtake, which helps - to turn that into a complete pass. + is only a half strength speed skill (base 1.8s), but it fires upon overtake, which helps to turn + that into a complete pass.
  • - and are mechanically similar full-strength speed - skills with cooldowns, so they can fire multiple times per race. Slipstream requires not being in first, and it's always wasted - if it triggers during the no-overtake zone, so it's marginally weaker. Both want multi-front builds. + and are mechanically similar full-strength speed skills with + cooldowns, so they can fire multiple times per race. Slipstream requires not being in first, and it's always wasted if it triggers + during the no-overtake zone, so it's marginally weaker. Both want multi-front builds.
Gate Skills

- Gate skills are (GW), , and (Conc), as well as all green skills including (but excluding (GW), , and (Conc), + as well as all green skills including (but excluding ). These skills activate the moment the race starts. Other running styles can largely ignore them, but for front runners, they are critical. @@ -574,33 +649,31 @@ />

- GW must be combined with if you want any chance of being first out of early race. The gold version - of EL, , is highly accessible as the skill from the Mihono Bourbon Wit event SSR. In - practice, I've found it adds fewer lengths over the white, and hence less positioning ability, than a mid race gold speed - skill. It is still absolutely good, and Bourbon Wit is a very usable card (treat her as a speed card that gives extra - energy on wit), but I don't consider it mandatory anymore. + GW must be combined with if you want any chance of being first out of early race. The gold version + of EL, , is highly accessible as the skill from the Mihono Bourbon Wit event SSR. In practice, + I've found it adds fewer lengths over the white, and hence less positioning ability, than a mid race gold speed skill. It is + still absolutely good, and Bourbon Wit is a very usable card (treat her as a speed card that gives extra energy on + wit), but I don't consider it mandatory anymore.

Conc is less critical. It's worth taking on horses who have it, but it isn't worth using support card slots just to get it. On - the other hand, its white version, , is bad; its only real use is as a backup gate skill - for GW when you don't have enough greens available. + the other hand, its white version, , is bad; its only real use is as a backup gate skill for GW + when you don't have enough greens available.

Spurt Skills

Because they are post-Angling, skills that activate in the final spurt are typically less interesting to front runners. - Notable exceptions are and, on Tokyo turf, and, on Tokyo turf, - These are good inherits for those who don't have easy access to and and .

- is another spurt skill that may come up sometimes and is interesting to think about. It's + is another spurt skill that may come up sometimes and is interesting to think about. It's a 0.25 speed skill that requires being in at best second place to activate. Is it worth it to take?

@@ -618,9 +691,8 @@ Other Horses' Skills

There are two categories of other horses' skills to think about.

- The first is stamina debuffs: , , , , . My conclusion is that Global doesn't understand how to build debuffers, so front runners can mostly ignore these – assume one will hit you, but not three.

@@ -631,9 +703,9 @@

The other category of skills to think about is other horses' uniques. - , , and a number of others need tight positioning, - requiring something like 2-4 or 3-4 in CM. The number of front runners in the match can dictate whether it's ever possible for - those uniques to activate. This is the fundamental idea behind triple front builds. + , , and a number of others need tight positioning, requiring + something like 2-4 or 3-4 in CM. The number of front runners in the match can dictate whether it's ever possible for those + uniques to activate. This is the fundamental idea behind triple front builds.

Skill Timing @@ -692,11 +764,10 @@ the early and mid race skills you can manage. Gate skills are especially important, because runaways have a tremendously higher early race target speed. If there is a real difference between a correctly built runaway blocker and a runaway ace, it's that - and are arguably more appropriate inherits than Angling, but the argument isn't strong + and are arguably more appropriate inherits than Angling, but the argument isn't strong if you're still able to hit a good stat line on your runaway.

@@ -729,21 +800,19 @@ Long Double Front

At long distances, double front has different implications. - is the front runner win condition, and the front two horses both get it. With late race being - before the final corner and hence extra move lane not having started, you can take advantage of to turn the second place front runner into the winner. + is the front runner win condition, and the front two horses both get it. With late race being + before the final corner and hence extra move lane not having started, you can take advantage of to turn + the second place front runner into the winner.

Building for second place to bunny with NN does not mean manipulating stats and skills to force one of the front runners into second. Both fronts need to be strong enough to be adjacent at late race start, and you have to beat other people's front - runners, too. (Especially since VC and are currently the only consistent accels - for long distance.) So, double front for long is ultimately about the same as double front for other distances, just with different + runners, too. (Especially since VC and are currently the only consistent accels for + long distance.) So, double front for long is ultimately about the same as double front for other distances, just with different goals when choosing the legacy.

- Given that NN is good, it's also worth considering the gold version, + Given that NN is good, it's also worth considering the gold version, NSM is a better skill for the long double front build, but for now, the only way to get it while running MANT is from Yukino Bijin Wit. That card's numbers are not great. It's still possible to get a good stat line using her, but it will take more careers to get there than to just get NN from Fine Motion. @@ -752,8 +821,7 @@ If you're feeling adventurous, runaway is another consideration for double (and triple) front on long distances. Your ace (hopefully) still gets VC, but the runaway paces up the race. As mentioned in the solo front section, this especially punishes end closers, who tend to be popular on long tracks because of . It also keeps your ace in overtake mode, which is better than speed-up mode, for position keep.

@@ -771,9 +839,8 @@ One type of support that all front runners do automatically is helping to kill position-based pace chaser skills. Such skills have conditions that translate into needing to be in 3rd or 4th, or sometimes 2nd through 4th, to activate. When you're bringing three front runners, if anyone else brings a single other one, they're going to occupy 2-4 naturally. If there happen - to be three others, then even late/end win cons like and and are dead.

@@ -794,10 +861,9 @@ An SS support doesn't strictly need as much in the way of mid race skills, since her main job is to give the others overtake mode and then be passed. It's nonetheless a good idea to take those skills for less risk if your other fronts have a poor showing. In addition to the normal front win cons, it's potentially strong to take unconditional gambles like and . + /> and .

SS supports do best on medium and long tracks, because you want to be building everyone for spot struggle on miles and @@ -808,11 +874,7 @@ Chariot

A front runner build that I have seen but not attempted is the chariot: a runaway with a strong mid race but insufficient HP - to spurt stays in front of one or two other front runners who have + to spurt stays in front of one or two other front runners who have

I saw a team using a chariot in CM13 round 2 day 2; that team had an overall eleven wins at the time. Maybe their horses just @@ -828,7 +890,7 @@

Most front runners enjoy easy careers thanks to strong kits and little chance to be blocked.

Currently, this chapter is about MANT (a.k.a. Trackblazer). Unity Cup is still useful – obviously for runaways, but also - for spinning up an legacy. + for spinning up an legacy.

Support Cards @@ -838,47 +900,41 @@

  • - Ines Fujin gives , , and , , and . Her guts SSR is the Kitasan Black of guts cards, with 15% training effectiveness and 80 specialty priority. She also has a relatively new wit SR that is decently strong even at LB0, though still objectively beaten by Marv SR until MLB.
  • - Marvelous Sunday, both power SSR and wit SR versions, give and and as hints. The SSR has 15% race bonus, while the SR has 10% race bonus and gives +3 hints. The numbers on both are otherwise disappointing, but those elements alone are enough to justify using them.
  • Cards that give generic or distance-specific gold speed skills, especially mid race ones, are very valuable to front - runners. Since is strong, Kitasan Black is still around despite only 5% race - bonus. El Condor Pasa gives . + runners. Since is strong, Kitasan Black is still around despite only 5% race bonus. + El Condor Pasa gives .
  • - For parent runs, Smart Falcon SSR is mandatory. She gives guaranteed in her chain, - and her gold skill is , which you want for building a + For parent runs, Smart Falcon SSR is mandatory. She gives guaranteed in her chain, and her + gold skill is , which you want for building a lane combo legacy. On ace runs, she is acceptable if you own her at MLB, but you'd rather get her skills from inheritance and use the card slot for a strong speed skill.
  • - Seiun Sky SSR is another good parent card for parents. Her chain starts with and ends - with - (albeit agemasen). She also carries a hint. Unfortunately, between being a stamina card and not being Super Creek, she isn't viable for ace runs. + Seiun Sky SSR is another good parent card for parents. Her chain starts with and ends with + (albeit agemasen). She also carries a hint. + Unfortunately, between being a stamina card and not being Super Creek, she isn't viable for ace runs.
  • Other parenting cards include Kawakami Princess speed and Hishi Akebono guts, for gold versions of lane combo skills.

A future sight advisory: Maruzensky's speed SSR is coming in early July. At this point, you should probably be saving all your - carats for her. She is an extremely strong stat stick and gives , the gold - version of . + carats for her. She is an extremely strong stat stick and gives , the gold version + of .

Taking Skills @@ -890,38 +946,37 @@ your chance of getting skills you don't have hints for.

- is a snap take skill. The only time to sit on EL is when you happen to get - the first +1 hint the turn before inspiration. (Even then, I'd probably still take it, since there's still a race to run.) - Early Lead is one of the strongest skills in terms of lengths gained, it applies to all tracks and conditions, and + is a snap take skill. The only time to sit on EL is when you happen to get the first + +1 hint the turn before inspiration. (Even then, I'd probably still take it, since there's still a race to run.) Early Lead is + one of the strongest skills in terms of lengths gained, it applies to all tracks and conditions, and it saves late starts, which are your only source of losses on most races after junior year. Moreover, it has a base cost of only 120 SP; even if you do get Fast Learner after taking it, your opportunity cost was 12 SP. If you prune EL and a - hint lands on or instead, - you gave up that potential 12 SP to save 18. It's incredibly good to take early. + hint lands on or instead, you gave up that + potential 12 SP to save 18. It's incredibly good to take early.

- On parent runs, or exactly one of your three CM horses, is another snap take. Base cost - of 60 SP for +40 speed, which can secure a lot of races, especially early in career. Be extremely careful not to take it on multiple - horses on a team. Save and quit from the career if you need to check. It's technically better to have it on two horses than zero, - but it's tremendously better than that to have it on one. + On parent runs, or exactly one of your three CM horses, is another snap take. Base cost of 60 + SP for +40 speed, which can secure a lot of races, especially early in career. Be extremely careful not to take it on multiple horses + on a team. Save and quit from the career if you need to check. It's technically better to have it on two horses than zero, but it's + tremendously better than that to have it on one.

- is a strong consideration as a mid-career take. Inheritance events are more likely to activate + is a strong consideration as a mid-career take. Inheritance events are more likely to activate green sparks than white sparks, so the risk of missing out on SP by taking it early is higher. However, Angling is an almost automatic win condition for career (outside of 3Ks and Niigata 1600). Taking Angling early can save a lot of clocks, and it can rescue runs that don't get what is normally the minimum speed to win races before summer.

- I've had debate about this one, but I feel that is a skill you will pretty much always want - at least the first level of. Wit is a strong stat for front runners, and Savvy is a guaranteed Groundwork trigger. It's also the - second cheapest front-specific skill, after Dodging Danger. On parent runs, it could arguably be worth sitting on it until the +2 - or +3 hint, because taking the second level gives a slightly boosted chance to generate the spark, and hints save twice as much - SP on the double circle. + I've had debate about this one, but I feel that is a skill you will pretty much always want at least + the first level of. Wit is a strong stat for front runners, and Savvy is a guaranteed Groundwork trigger. It's also the second cheapest + front-specific skill, after Dodging Danger. On parent runs, it could arguably be worth sitting on it until the +2 or +3 hint, because + taking the second level gives a slightly boosted chance to generate the spark, and hints save twice as much SP on the double circle.

- and are strong and cheap. If you've - taken Early Lead and Angling, they probably won't change the outcomes of any races, but it's still reasonable to take the first - level to prune. As a corollary, outside parent runs, you should have a specific distance in mind, so your distance straights/corners - should usually be even quicker takes. + and are strong and cheap. If you've taken Early Lead and Angling, + they probably won't change the outcomes of any races, but it's still reasonable to take the first level to prune. As a corollary, + outside parent runs, you should have a specific distance in mind, so your distance straights/corners should usually be even quicker + takes.

Niigata Junior Stakes @@ -969,9 +1024,9 @@ tested much without them, because I don't like throwing away my runs.

- is the only front-specific recovery skill you can get from MANT rivals. It also is a guaranteed - option in Bourbon Wit's first chain event. That makes it pretty often available for the 3Ks. However, if you end up overstam at - the end of the run, buying Moxie can be as much as -162 SP, which is certainly not a trivial amount. + is the only front-specific recovery skill you can get from MANT rivals. It also is a guaranteed option + in Bourbon Wit's first chain event. That makes it pretty often available for the 3Ks. However, if you end up overstam at the end + of the run, buying Moxie can be as much as -162 SP, which is certainly not a trivial amount.

An alternative option to buying a recovery is to switch to Late Surger for those races. I've won Kikuka Sho with circa 300 @@ -1005,44 +1060,36 @@

  • Valentine's Mihono Bourbon (VBourbon) is the easiest font runner to train because she has built in, whereas most others have to get it from either inheritance or cards that aren't terribly strong. She is also the - strongest front runner, because is full strength, mid race, extremely forgiving - in activation, and even has a heal. And she has and built in, both strong distance-agnostic front runner skills with awkward sources otherwise. And she's a great parent for all - the same reasons that her unique is strong (except that the heal becomes irrelevant). + strongest front runner, because is full strength, mid race, extremely forgiving in activation, + and even has a heal. And she has and built + in, both strong distance-agnostic front runner skills with awkward sources otherwise. And she's a great parent for all the same + reasons that her unique is strong (except that the heal becomes irrelevant).
  • - Summer Maruzensky (SMaru or KFC) is just shy of VBourbon in strength with her unique, . It uses a heal to trigger instead of having a heal built in, but that means it sometimes has carryover potential. Using + Summer Maruzensky (SMaru or KFC) is just shy of VBourbon in strength with her unique, . + It uses a heal to trigger instead of having a heal built in, but that means it sometimes has carryover potential. Using VBourbon as a parent for SMaru works as a trigger, too, which is especially good for shorter distances that don't want to spend SP on pure recoveries.
  • - Seiun Sky is the source of and therefore the best horse for front runner parenting + Seiun Sky is the source of and therefore the best horse for front runner parenting in the game, forever. As a runner, she is outshone by the former two and others who will come later, but she is an excellent choice for a second front runner in a team comp.
  • Kitasan Black is the definitive front runner of long distance, both as a parent and as a competitor. - is the gold version of , - which is extremely strong to have built in (especially noting that hints on Long Straights take 27 SP off the price of - Blast). + is the gold version of , which is + extremely strong to have built in (especially noting that hints on Long Straights take 27 SP off the price of Blast).
  • Silence Suzuka and Mejiro Palmer are currently the only runaways in the game. Both of them have uniques that are inconsistent normally but very consistent as runaways: - and . Outside of Team Trials, - runaways aren't very useful in the MANT era. (My Suzuka runaway remains my #1 top scorer in TT, though. Runaway and Conc are - both busted for points.) + and . Outside of Team Trials, runaways + aren't very useful in the MANT era. (My Suzuka runaway remains my #1 top scorer in TT, though. Runaway and Conc are both + busted for points.)

@@ -1053,8 +1100,8 @@ Christmas Oguri Cap

As is perhaps expected, Christmas Oguri Cap (COC) is very strong as a front runner on specific tracks. The front-specific heal - is , which activates at the very start of the first uphill. When that first - uphill is at the start of late race, as in the case of Tokyo 1600 Dirt, COC is online as a front runner. + is , which activates at the very start of the first uphill. When that first uphill is at + the start of late race, as in the case of Tokyo 1600 Dirt, COC is online as a front runner.

I've been told COC is very hard to train as a front runner. Something about aptitudes. I don't have any variety of Oguri, but @@ -1062,8 +1109,7 @@

Another rare manifestation of Front COC is as a third place horse in a triple front build where is strong. I convinced Werseter, the Umadump guy, to try this for CM12 after he accidentally made an 8★ front Tachyon parent. He reported a 7% win rate for her. (But a much higher win rate overall – after all, he was using triple front.) @@ -1111,37 +1157,36 @@

Front runners are more reliant than other styles on getting certain skills from inspiration:

  • - Building a full legacy is the first step to front runner training. Fronts without it are non-competitive + Building a full legacy is the first step to front runner training. Fronts without it are non-competitive even as supports. The cards that give it aren't great for ace builds. There is no gold version of it yet, so getting it from inheritance is truly ideal.
  • - similarly doesn't come from good cards (since Sweep Tosho has fallen off). As a piece of + similarly doesn't come from good cards (since Sweep Tosho has fallen off). As a piece of lane combo, it isn't applicable to every race, but it's very strong when it is. The white skill is better than the gold skill, so it is another ideal inherit.
  • - is the stronger lane combo piece. The only sources of it are inheritance and Unity - Cup; which is to say, the source of it is inheritance. When searching databases for borrows, looking for Ignited WIT is a shortcut - for listing good front runner legacies, since it's only valuable to fronts and somewhat hard to get even when you focus on it. + is the stronger lane combo piece. The only sources of it are inheritance and Unity Cup; which + is to say, the source of it is inheritance. When searching databases for borrows, looking for Ignited WIT is a shortcut for listing + good front runner legacies, since it's only valuable to fronts and somewhat hard to get even when you focus on it.
  • Almost all green skills are valuable to inherit at one point or another as GW triggers. - and are particularly good; one of the two is always - the best green available for a race. - is a bit less strong, and slightly superseded by the existence of Narita Top Road, but it - applies to the majority of CM races. Season greens are great, but a bit narrow; distance greens are good. Weather greens are acceptable, + and are particularly good; one of the two is always the best green + available for a race. + is a bit less strong, and slightly superseded by the existence of Narita Top Road, but it applies + to the majority of CM races. Season greens are great, but a bit narrow; distance greens are good. Weather greens are acceptable, but while guts is better on front runners than other styles, it isn't good. - is good if you like to do triple front builds, - because it activates when there are four of the runner's style in CM. - is slightly less valuable as an inherit, since it can come from rivals. + is good if you like to do triple front builds, because it + activates when there are four of the runner's style in CM. + is slightly less valuable as an inherit, since it can come from rivals.
  • All generic speed skills that aren't strictly late race are good inherits. - is the best one by ratio of strength to difficulty to acquire. - , , , and is the best one by ratio of strength to difficulty to acquire. + , , , and are also strong, but available as hints or chain skills from some usable-to-good cards.
  • Obviously, getting front-runner-specific skills from inheritance makes them cheaper and more consistent to get.
  • @@ -1300,7 +1345,7 @@ CM13 – Taurus Cup (Tokyo Derby)

    - Maruzensky's unique, , is live for approximately everyone. Filling the ranks + Maruzensky's unique, , is live for approximately everyone. Filling the ranks with front runners should be a strong means to delay it for later positions, especially COC.

    @@ -1425,8 +1470,8 @@

    As a sprint, this is also where spot struggle shines. Time for Unity Cup guts builds.

    - I forgot that requires being in first place, so I thought it would be reasonable - to base my team around gambling on it. That turned out not to be a great decision. + I forgot that requires being in first place, so I thought it would be reasonable to + base my team around gambling on it. That turned out not to be a great decision.

    1. @@ -1447,13 +1492,12 @@

    - The plan worked exactly as I hoped, but what the plan lacked was . While I was + The plan worked exactly as I hoped, but what the plan lacked was . While I was suppressing it on other teams' front runners with my outstanding mid race, they were also gambling on and , and I didn't have enough accel to beat them. I found a mention in - my chat history that, as of round 2 day 1, I had a 78% top two rate with a 32% win rate. Lessons learned. Still managed to get - 2nd in the finals, and also my first ever group A round 2 sweep. + /> and , and I didn't have enough accel to beat them. I found a mention in my chat + history that, as of round 2 day 1, I had a 78% top two rate with a 32% win rate. Lessons learned. Still managed to get 2nd in + the finals, and also my first ever group A round 2 sweep.

    diff --git a/zenno/svelte.config.js b/zenno/svelte.config.js index c56c1f4..0d5cbd3 100644 --- a/zenno/svelte.config.js +++ b/zenno/svelte.config.js @@ -12,6 +12,9 @@ const config = { return isExternalLibrary ? undefined : true; }, + experimental: { + async: true, + }, }, kit: { adapter: adapter(), diff --git a/zenno/vite.config.ts b/zenno/vite.config.ts index 503c1b0..47520ac 100644 --- a/zenno/vite.config.ts +++ b/zenno/vite.config.ts @@ -4,6 +4,7 @@ import { playwright } from '@vitest/browser-playwright'; import { sveltekit } from '@sveltejs/kit/vite'; export default defineConfig({ + clearScreen: false, plugins: [tailwindcss(), sveltekit()], test: { expect: { requireAssertions: true }, @@ -33,4 +34,11 @@ export default defineConfig({ }, ], }, + server: { + proxy: { + '/api': { + target: 'http://localhost:13669', + }, + }, + }, });