5 Commits
Author SHA1 Message Date
zephyr 56bd5b460d zenno/doc/race: better section speed charts
ci/woodpecker/push/horsebot Pipeline was successful
ci/woodpecker/push/zenno Pipeline was successful
Fixes #49.
2026-11-05 14:45:59 -05:00
zephyr ddaf100069 meta: update go version in ci container
ci/woodpecker/push/horsebot Pipeline was successful
ci/woodpecker/push/zenno Pipeline was successful
2026-11-03 09:09:36 -05:00
zephyr f013aa4765 umadump/ism: remove old field 2026-11-03 09:09:36 -05:00
zephyr 2f676f0a62 umadump/ism: resparking info is populated now 2026-11-03 09:09:36 -05:00
zephyr 04cb6388c3 zenno/race/skillzone: indicate inherits
ci/woodpecker/push/horsebot Pipeline failed
ci/woodpecker/push/zenno Pipeline was successful
2026-10-31 21:12:17 -04:00
4 changed files with 63 additions and 59 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ when:
steps: steps:
- name: test - name: test
image: golang:1.26-alpine image: golang:1.27-alpine
commands: commands:
- go vet ./... - go vet ./...
- go test ./... - go test ./...
+1 -2
View File
@@ -323,7 +323,7 @@ type End struct {
StoryEventMissions []umadump.Never `json:"story_event_mission_list"` StoryEventMissions []umadump.Never `json:"story_event_mission_list"`
StoryEventCharaBonuses []umadump.Never `json:"story_event_chara_bonus_list"` StoryEventCharaBonuses []umadump.Never `json:"story_event_chara_bonus_list"`
StartDressInfo []umadump.Never `json:"start_dress_info"` StartDressInfo []umadump.Never `json:"start_dress_info"`
ResumeFactorSelect *umadump.Never `json:"resume_factor_select"` ResumeFactorSelect any `json:"resume_factor_select"` // don't care yet
RaceRandomPrograms []umadump.Never `json:"race_random_program_array"` RaceRandomPrograms []umadump.Never `json:"race_random_program_array"`
RaceRewardLimitMore []umadump.Never `json:"race_reward_limit_more_list"` RaceRewardLimitMore []umadump.Never `json:"race_reward_limit_more_list"`
SkillFilterSettings []umadump.Never `json:"skill_filter_setting_array"` SkillFilterSettings []umadump.Never `json:"skill_filter_setting_array"`
@@ -344,6 +344,5 @@ type WorkIdleSingleMode struct {
ProgressInfo ProgressInfo `json:"progress_info"` ProgressInfo ProgressInfo `json:"progress_info"`
ProgressLog IdleSingleModeProgressLog `json:"progress_log_info"` ProgressLog IdleSingleModeProgressLog `json:"progress_log_info"`
End End `json:"end_info"` End End `json:"end_info"`
OldChara *SingleModeChara `json:"chara_info"`
Extra map[string]any `json:"extra_data"` Extra map[string]any `json:"extra_data"`
} }
+57 -53
View File
@@ -7,10 +7,6 @@
import { resolve } from '$app/paths'; import { resolve } from '$app/paths';
import RaceLenSlider from '$lib/RaceLenSlider.svelte'; import RaceLenSlider from '$lib/RaceLenSlider.svelte';
function modemean(x: number, bonus: number, p: number): number {
return x * (1 - p) + x * bonus * p;
}
let style = $state(race.RunningStyle.FrontRunner); let style = $state(race.RunningStyle.FrontRunner);
let surfaceApt = $state(race.AptitudeLevel.A); let surfaceApt = $state(race.AptitudeLevel.A);
let distanceApt = $state(race.AptitudeLevel.A); let distanceApt = $state(race.AptitudeLevel.A);
@@ -84,39 +80,39 @@
]; ];
const duelSpeed: ComputedSeries[] = [{ label: 'Dueling Speed Boost', y: (x) => race.duelSpeedMod(x) }]; const duelSpeed: ComputedSeries[] = [{ label: 'Dueling Speed Boost', y: (x) => race.duelSpeedMod(x) }];
const duelAccel: ComputedSeries[] = [{ label: 'Dueling Acceleration Boost', y: (x) => race.duelAccelMod(x) }]; const duelAccel: ComputedSeries[] = [{ label: 'Dueling Acceleration Boost', y: (x) => race.duelAccelMod(x) }];
const secSpeed: Array<ComputedAreas | null> = $derived([ const secSpeedEarly: Array<ComputedAreas | null> = $derived([
{ {
label: 'Early Race', label: styleIsFront ? 'Front S' : 'Style S',
y1: (x) => race.sectionSpeed(raceLen, x * 1.1, style, race.Phase.EarlyRace)[0],
y2: (x) => race.sectionSpeed(raceLen, x * 1.1, style, race.Phase.EarlyRace)[1],
},
{
label: styleIsFront ? 'Front A' : 'Style A',
y1: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.EarlyRace)[0], y1: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.EarlyRace)[0],
y2: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.EarlyRace)[1], y2: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.EarlyRace)[1],
}, },
{ {
label: 'Mid Race', label: styleIsFront ? 'Front A Speed-Up Mode' : 'Style A Pace-Up Mode',
y1: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.EarlyRace)[0] * 1.04,
y2: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.EarlyRace)[1] * 1.04,
},
]);
const secSpeedMid: Array<ComputedAreas | null> = $derived([
{
label: styleIsFront ? 'Front S' : 'Style S',
y1: (x) => race.sectionSpeed(raceLen, x * 1.1, style, race.Phase.MidRace)[0],
y2: (x) => race.sectionSpeed(raceLen, x * 1.1, style, race.Phase.MidRace)[1],
},
{
label: styleIsFront ? 'Front A' : 'Style A',
y1: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.MidRace)[0], y1: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.MidRace)[0],
y2: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.MidRace)[1], y2: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.MidRace)[1],
}, },
styleIsFront {
? { label: styleIsFront ? 'Front A Speed-Up Mode' : 'Style A Pace-Up Mode',
label: 'Early Race + Mean Speed-Up Mode', y1: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.MidRace)[0] * 1.04,
y1: (x) => modemean(race.sectionSpeed(raceLen, x, style, race.Phase.EarlyRace)[0], 1.04, race.frontModeEnterChance(x)), y2: (x) => race.sectionSpeed(raceLen, x, style, race.Phase.MidRace)[1] * 1.04,
y2: (x) => modemean(race.sectionSpeed(raceLen, x, style, race.Phase.EarlyRace)[1], 1.04, race.frontModeEnterChance(x)), },
}
: {
label: 'Early Race + Mean Pace-Up Mode',
y1: (x) => modemean(race.sectionSpeed(raceLen, x, style, race.Phase.EarlyRace)[0], 1.04, race.paceUpEnterChance(x)),
y2: (x) => modemean(race.sectionSpeed(raceLen, x, style, race.Phase.EarlyRace)[1], 1.04, race.paceUpEnterChance(x)),
},
styleIsFront
? {
label: 'Mid Race + Mean Speed-Up Mode',
y1: (x) => modemean(race.sectionSpeed(raceLen, x, style, race.Phase.MidRace)[0], 1.04, race.frontModeEnterChance(x)),
y2: (x) => modemean(race.sectionSpeed(raceLen, x, style, race.Phase.MidRace)[1], 1.04, race.frontModeEnterChance(x)),
}
: {
label: 'Mid Race + Mean Pace-Up Mode',
y1: (x) => modemean(race.sectionSpeed(raceLen, x, style, race.Phase.MidRace)[0], 1.04, race.paceUpEnterChance(x)),
y2: (x) => modemean(race.sectionSpeed(raceLen, x, style, race.Phase.MidRace)[1], 1.04, race.paceUpEnterChance(x)),
},
]); ]);
const downhill: ComputedSeries[] = [ const downhill: ComputedSeries[] = [
{ label: 'Style S', y: (x) => race.downhillAccelEnterChance(x * 1.1) * 100 }, { label: 'Style S', y: (x) => race.downhillAccelEnterChance(x * 1.1) * 100 },
@@ -396,34 +392,42 @@
>Section Speed</Sec >Section Speed</Sec
> >
<p>Random variance in target speed per race section.</p> <p>Random variance in target speed per race section.</p>
<div class="mb-24 h-60 w-full md:mb-20 md:h-96"> <div class="mb-10 grid h-96 w-full md:grid-cols-2">
<StatChart <StatChart
class="mx-auto mb-12 h-full w-full max-w-3xl md:mb-10"
stat={race.Stat.Wit} stat={race.Stat.Wit}
yArea={secSpeed} yArea={secSpeedEarly}
yLabel="Section Speed (m/s)" yLabel="Early Race Section Speed (m/s)"
range={[17, 23]} range={[17, 23.5]}
plotOptions={{ color: { legend: true } }} plotOptions={{ color: { legend: true } }}
class="h-96 max-h-96"
/> />
<div class="mx-auto flex w-full md:max-w-2xl"> <StatChart
<label class="my-auto hidden flex-1 pr-2 text-right text-sm md:inline" for="secSpeedRaceLen">Race Length</label> stat={race.Stat.Wit}
<input yArea={secSpeedMid}
class="my-auto max-w-40 flex-1 md:flex-2" yLabel="Mid Race Section Speed (m/s)"
type="range" range={[17, 23.5]}
id="secSpeedRaceLen" plotOptions={{ color: { legend: true } }}
min="1000" class="h-96 max-h-96"
max="3600" />
step="100" </div>
bind:value={raceLen} <div class="mx-auto mb-4 flex w-full md:max-w-2xl">
/> <label class="my-auto hidden flex-1 pr-2 text-right text-sm md:inline" for="secSpeedRaceLen">Race Length</label>
<span class="my-auto flex-1 pl-2 text-sm">{raceLen}m</span> <input
<label class="my-auto hidden flex-1 pr-2 text-right text-sm md:inline" for="secSpeedStyle">Style</label> class="my-auto max-w-40 flex-1 md:flex-2"
<select class="my-auto flex-1 text-sm" id="secSpeedStyle" bind:value={style}> type="range"
{#each race.RUNNING_STYLES as [name, style] (style)} id="secSpeedRaceLen"
<option value={style}>{name}</option> min="1000"
{/each} max="3600"
</select> step="100"
</div> bind:value={raceLen}
/>
<span class="my-auto flex-1 pl-2 text-sm">{raceLen}m</span>
<label class="my-auto hidden flex-1 pr-2 text-right text-sm md:inline" for="secSpeedStyle">Style</label>
<select class="my-auto flex-1 text-sm" id="secSpeedStyle" bind:value={style}>
{#each race.RUNNING_STYLES as [name, style] (style)}
<option value={style}>{name}</option>
{/each}
</select>
</div> </div>
<Sec <Sec
+4 -3
View File
@@ -67,7 +67,8 @@
return { id: c.race_course_id, name: racecourse.referName(c) }; return { id: c.race_course_id, name: racecourse.referName(c) };
} }
function skillKey(sk: skill.Skill) { function skillKey(sk: skill.Skill) {
return { id: sk.skill_id, name: sk.name }; const name = sk.unique_owner != null && sk.rarity === 1 ? `${sk.name} (Inherited)` : sk.name;
return { id: sk.skill_id, name };
} }
let skillToAdd: skill.Skill | undefined = $state(); let skillToAdd: skill.Skill | undefined = $state();
@@ -126,7 +127,7 @@
{#snippet option(sk)} {#snippet option(sk)}
<span> <span>
<SkillIcon icon_id={sk.icon_id} size={16} /> <SkillIcon icon_id={sk.icon_id} size={16} />
{sk.name} {skillKey(sk).name}
</span> </span>
{/snippet} {/snippet}
</Pick> </Pick>
@@ -173,7 +174,7 @@
{#snippet option(sk)} {#snippet option(sk)}
<span> <span>
<SkillIcon icon_id={sk.icon_id} size={16} /> <SkillIcon icon_id={sk.icon_id} size={16} />
{sk.name} {skillKey(sk).name}
</span> </span>
{/snippet} {/snippet}
</Pick> </Pick>