From caa19dd85a39e7ad42b86403b431d808a380d0f8 Mon Sep 17 00:00:00 2001
From: Branden J Brown
Date: Fri, 11 Sep 2026 18:14:14 -0400
Subject: [PATCH] zenno/doc/mdb: document races
---
zenno/src/routes/doc/mdb/+page.svelte | 455 ++++++++++++++++++++++++++
1 file changed, 455 insertions(+)
diff --git a/zenno/src/routes/doc/mdb/+page.svelte b/zenno/src/routes/doc/mdb/+page.svelte
index 76f1d3f..73e80ec 100644
--- a/zenno/src/routes/doc/mdb/+page.svelte
+++ b/zenno/src/routes/doc/mdb/+page.svelte
@@ -17,8 +17,107 @@
}
});
+ const raceGroups = [
+ [1, 'Common'],
+ [2, 'Daily Race'],
+ [3, '"Training Practice"'],
+ [4, '"Story Condition"'],
+ [5, '"Team Building"'],
+ [6, 'Practice'],
+ [7, 'Career-Exclusive'],
+ [8, 'Legend Race'],
+ [9, 'Team Trials'],
+ [10, 'Unity Cup Team Race'],
+ [11, "Champions' Meet"],
+ [12, 'Room Match'],
+ [13, '"Challenge Match"'],
+ [14, 'League of Heroes Race'],
+ [61, 'Custom G1'],
+ ] as const;
+
+ const raceGrades = [
+ [100, 'G1'],
+ [200, 'G2'],
+ [300, 'G3'],
+ [400, 'OP'],
+ [700, 'Pre-OP'],
+ [800, 'Maiden'],
+ [900, 'Debut'],
+ [999, 'Daily Race or Room Match (?)'],
+ [1000, 'Unity Cup Team Race (?)'],
+ ] as const;
+
+ const raceTimes = [
+ [1, 'Morning (unused)'],
+ [2, 'Daytime'],
+ [3, 'Evening'],
+ [4, 'Night'],
+ ] as const;
+
+ const raceInitialLanes = [
+ [1, 9, 0.03333333],
+ [2, 0, 0],
+ [3, 14, 0.10333333],
+ [4, 8, 0.03333333],
+ ] as const;
+
+ const raceAreas = [
+ [0, 'Hokkaido'],
+ [1, 'Tohoku'],
+ [2, 'Kanto'],
+ [3, 'Western Japan'],
+ [4, 'Kokura'],
+ [5, 'France'],
+ [6, 'America'],
+ ] as const;
+
+ const raceLoops = [
+ [1, 'None'],
+ [2, 'Inner'],
+ [3, 'Outer'],
+ [4, 'Outer→Inner'],
+ ] as const;
+
+ const raceRotations = [
+ [1, 'Right'],
+ [2, 'Left'],
+ [3, 'Rightward Stretch (unused)'],
+ [4, 'Leftward Stretch'],
+ ] as const;
+
+ const raceCourseThresholds = [
+ [1, 1, 0],
+ [2, 2, 0],
+ [3, 3, 0],
+ [4, 4, 0],
+ [5, 5, 0],
+ [6, 1, 2],
+ [7, 2, 3],
+ [8, 2, 4],
+ [9, 3, 5],
+ [10, 2, 5],
+ [11, 4, 5],
+ ] as const;
+
+ const raceSaddleTypes = [
+ [0, 'Special'],
+ [1, 'G3'],
+ [2, 'G2'],
+ [3, 'G1'],
+ ] as const;
+
+ const racePermissions = [
+ [1, 'Junior'],
+ [2, 'Classic'],
+ [3, 'Classic and Senior'],
+ [4, 'Senior'],
+ [5, 'Finale'],
+ ] as const;
+
const skills = $derived({
rickey: skillMap.get(100981),
+ right1: skillMap.get(200012),
+ left1: skillMap.get(200022),
fall2: skillMap.get(200191),
fall1: skillMap.get(200192),
fallX: skillMap.get(200193),
@@ -330,6 +429,362 @@
>, but a few categories that have useful strings are missing from there.
+ Races
+ First, some terminology, as the game uses it internally. (Some UI phrasing disagrees.)
+
+ A race is an organized running competition, typically held annually. A race instance is a single holding of a
+ race at a specific date and time; this includes special race instances like Team Trials races, Aim for the Stars races,
+ &c. Race instances are held on a given race course, which is a fixed-length segment of a physical location called a
+ race track. A win saddle is a given horse's victory of a race or a specific group of races, e.g. Classic Triple Crown
+ or Dual Grand Prix. This section will cover races, race instances, race tracks, race courses, and win saddles.
+
+
+ text_data categories relevant to races include:
+
+
+ - 32 and 33 are both race names, the latter for jikkyo (the announcer's lines).
+ -
+ 28 is race instance names. 29 is abbreviated race instance names, e.g. Mile Ch. instead of Mile Championship.
+
+ -
+ 31 and 34 are race track full names, the former for jikkyo, e.g. Kyoto Racecourse. 35 is race track names
+ without "Racecourse".
+
+ - 111 is win saddle names.
+
+
+ Race Info
+
+ Races are defined in race, which is quite a direct name innit.
+
+
+ -
+ Race ID is just id.
+
+ -
+ group is the game situation where the race occurs.
+
+
+
+ | Group |
+ Meaning |
+
+
+
+ {#each raceGroups as [id, name] (id)}
+
+ | {id} |
+ {name} |
+
+ {/each}
+
+
+
+ -
+ grade defines the race grade.
+
+
+
+ | Grade ID |
+ Meaning |
+
+
+
+ {#each raceGrades as [id, name] (id)}
+
+ | {id} |
+ {name} |
+
+ {/each}
+
+
+
+ - course_set gives the race course where the race occurs.
+ - thumbnail_id is the resource ID of the race's thumbnail image.
+ - entry_num is the maximum number of horses that can run the race.
+
+
+ Some races are ostensibly defined twice to account for variant races run during some characters' careers, e.g. Maruzensky's
+ five opponent Spring Stakes, McQueen/Ryan/Rice's Kyoto Takarazuka Kinen, &c.
+
+
+ Race Instances
+
+ The table is race_instance.
+
+
+ - id is the race instance ID.
+ - race_id joins with race.id.
+ -
+ npc_group_id should define the NPC racers allowed to appear in the race instance, although I haven't looked into
+ it.
+
+ -
+ date gives the month and day-of-month when the race instance occurs, expressed as M×100+d – 1 Jan is
+ 101 and 31 Dec is 1231. This appears to decide the season that the race instance occurs in and thus the applicable green skill.
+ E.g., we can see in career that Challenge Cup is offered on the Early December turn, but its race instance has a date of 1130 (i.e. 30 Nov), so it is a fall rather than winter race. All races occur in 2019.
+
+ -
+ time is the time of day that the race instance is held.
+
+
+
+ | Time |
+ Meaning |
+
+
+
+ {#each raceTimes as [id, name] (id)}
+
+ | {id} |
+ {name} |
+
+ {/each}
+
+
+
+ -
+ clock_time has a value of 1605 for one race and is otherwise always 0. It might be a specific hour and minute that
+ a race instance occurs, but I'm not sure why that would ever matter.
+
+ -
+ race_number takes every value between -1 and 12, but I couldn't find any explanation for it.
+
+
+
+ Similarly to races, some race instances are ostensibly defined twice to account for variant races run during some characters'
+ careers.
+
+
+ Race Tracks
+
+ Since race tracks are the physical locations where races are held, there are not many rows in race_track. Most of
+ its purpose is to define appearance characteristics, but some fields are mechanically relevant.
+
+
+ - id is the race track ID.
+ -
+ initial_lane_type describes the starting lane positions of each horse by determining the location and width of the
+ gap between posts.
+
+
+
+ | ID |
+ Gap After Gate |
+ Gap Width (CW) |
+
+
+
+ {#each raceInitialLanes as [id, gate, w] (id)}
+
+ | {id} |
+ {gate} |
+ {w} |
+
+ {/each}
+
+
+ Horses in gatesafter the Gap After Gate listed in this table have the gap width added to their starting lane.
+ initial_lane_type is 2 on Oi, Kawasaki, and Funabashi; 3 on Longchamp; 4 on Morioka; and 1 elsewhere. (The race mechanics
+ doc's
+ description of initial lane
+ uses horse index rather than gate number and describes lanes in units of horse lanes rather than course widths.)
+
+ -
+ area defines the geographic region where the race track exists.
+
+
+
+ | ID |
+ Region |
+
+
+
+ {#each raceAreas as [id, name] (id)}
+
+ | {id} |
+ {name} |
+
+ {/each}
+
+
+
+
+
+ Race Courses
+
+ Race courses are physical segments of race tracks. They are defined in race_course_set.
+
+
+ Most tracks have one or two turf loops (the "(Inner)" and "(Outer)" or sometimes "(Outer→Inner)") and one dirt loop. The
+ length of a race course is determined solely by the position of the gates: since the race course is a physical structure with
+ the audience stands in a specific location, and since said audience wants to see the race finish clearly, courses of all
+ lengths end at the same place on the front stretch. The straight opposite the front stretch is called the backstretch. Corners
+ are counted backward from the front stretch in the order 4, 3, 2, 1; all races except Ibis Summer Dash include corners 3 and
+ 4, while long and sometimes medium races run corners multiple times. Some courses start on an extra segment of the track which
+ is neither straight nor corner (which means straight_random==1 skills won't fire there).
+
+
+ - id gives the race course ID.
+ - race_track_id joins with race_track.id.
+ - distance is the race course length in meters.
+ - ground is 1 for turf and 2 for dirt.
+ -
+ inout gives the loop for the surface type where the race occurs.
+
+
+
+ | ID |
+ Loop |
+
+
+
+ {#each raceLoops as [id, name] (id)}
+
+ | {id} |
+ {name} |
+
+ {/each}
+
+
+
+ -
+ turn gives the handedness of the track, i.e. the direction from horses to the rail as they round the track's corners.
+
+
+
+ | ID |
+ Handedness |
+
+
+
+ {#each raceRotations as [id, name] (id)}
+
+ | {id} |
+ {name} |
+
+ {/each}
+
+
+ Stretch types have no corners and do not activate or or their variants.
+ Niigata 1000 is the only such race course in the game.
+
+ -
+ float_lane_max gives the initial race course width in units of ten thousandths of course widths. (Confusingly,
+ no race course has a width of 1 course width.) Some race courses have locations where the lane max changes, but these are defined
+ as events and are not in the mdb.
+
+ -
+ course_set_status_id joins with race_course_set_status.course_set_status_id to define the stat thresholds.
+ A value of 0 means no thresholds.
+
+ race_course_set_status
+
+
+ | course_set_status_id |
+ target_status_1 |
+ target_status_2 |
+
+
+
+ {#each raceCourseThresholds as [id, stat1, stat2] (id)}
+
+ | {id} |
+ {stat1} |
+ {stat2} |
+
+ {/each}
+
+
+ Status of 1 is Speed, 2 is Power, and so on up to 5 for Wit. 0 means no (second) threshold.
+
+
+
+ Characteristics like straight and corner locations, slopes, lane max changes, &c. are not in the mdb. They are defined
+ as assets instead and must be extracted using special tools.
+
+
+ Win Saddles
+
+ single_mode_wins_saddle defines the awards given to the horse (not the player) for winning a race or specific group
+ of races. These are the medals displayed as important wins for a horse at the end of a career. They are now purely aesthetic, but
+ I am documenting them anyway because I have the notes already since they used to determine affinity.
+
+
+ - id is the win saddle ID.
+ - priority is the sort order for win saddles.
+ -
+ group_id associates multiple win saddles for the same race, for horses whose careers have special versions of some
+ races.
+
+ -
+ win_saddle_type is the type of the win saddle, used to determine the color of the medal displayed.
+
+
+
+ | ID |
+ Type |
+
+
+
+ {#each raceSaddleTypes as [id, name] (id)}
+
+ | {id} |
+ {name} |
+
+ {/each}
+
+
+ Special win saddles are for win saddles requiring multiple wins, e.g. Classic Triple Crown.
+
+ -
+ race_instance_id_1 through race_instance_id_8 define the race instance IDs that must be won to be awarded
+ the win saddle. Columns beyond race_instance_id_3 are unused.
+
+
+
+ Single Mode Program
+
+ The table single_mode_program defines the race instances offered each turn in a career. Confusingly, races that permit
+ both classic and senior year horses are only defined here once.
+
+
+ - race_instance_id joins with race_instance.id.
+ -
+ race_permission gives the career years that offer the race. (More precisely, it gives the age ranges of horses that
+ are permitted to enter.)
+
+
+
+ | ID |
+ Meaning |
+
+
+
+ {#each racePermissions as [id, name] (id)}
+
+ | {id} |
+ {name} |
+
+ {/each}
+
+
+
+ - month and half give the turn that the race is held.
+
+
+ I was unable to identify whether any of the columns indicate maiden races, despite the UI restrictions on when they can
+ appear.
+
+
Skills
Relevant text_data categories include 47 for skill names and 48 for skill descriptions. Otherwise, info for skills