A map is a BallparkDefinition built with Park(...) in DefaultContent and added to db.ballparks. Its place in
that list is its unlock order and sets how high its goals are: every goal is x1.15 per step along the list.
Practice-only parks go in db.practiceParks instead.
Steps
Create the park in Assets/_Project/Scripts/Data/DefaultContent.cs, block // ---------- Ballparks ----------.
Park(id, name, description, leftFieldFt, centerFieldFt, rightFieldFt, wallHeightFt, grassColor, wallColor):
var windy = Park("windy", "Windy City Yard", "The wind is blowing out to left.", 330f, 400f, 340f, 12f, new Color(0.3f, 0.66f, 0.26f), new Color(0.14f, 0.42f, 0.24f));
Add targets (score zones past the wall). A multiplier zone uses Target(label, sprayDeg, distanceFt, radiusFt, multiplier, color); a flat-points bonus location outside the stadium uses Bonus(...), optionally up in the air:
Spray: -45 = left field line, 0 = center, 45 = right field line. See Scoring.
Set the modifiers and look as fields on the object: windMph, windDirectionDeg, gravityScale, isNight,
batterModifiers, sky (Add a Sky), ground (GroundStyle), wallStyle, seatColor, crowdDensity,
stadium = false for an open field, dressing (a Resources prefab path). New kinds of modifier:
Add a Ballpark Modifier.
Give it a special ball (optional): windy.balls.Add(Ball(BallEffect.SuperFast, 1f / 3f, "fastball", "slider"));
A ball with a pitch list also makes every pitcher here lean on those pitches (about 70% of pitches). See
Add a Special Ball.
Give it its own final boss: create a boss and set finalBossId (windy.finalBossId = "gale";). Every run map
has one since #41; without one, inning 9 is drawn from the roaming boss pool, which is only The Ace and Knuckle
Sandwich, both already used in innings 3 and 6, so inning 9 repeats one of them. See Add a Final Boss.
Put it in the unlock order. Add it to the db.ballparks.AddRange(new[] { sandlot, farm, windy, midnight, moon });
line at the position where it should unlock. A batting-cage-only park goes in db.practiceParks.Add(...) instead
(never a run map, never unlocked, not in the co-op lobby).
Props (optional). An open field can be decorated by a code layout in Ballparks/ParkLayouts.cs (today only
farm and moon have one, keyed by park id in ParkLayouts.Has) and baked into a prefab with
Tools → Home Run Derby → Bake Park Dressing. See Ballpark Building.
Nothing else to register. These read the park list or the definition on their own:
the map select carousel (UI/MapSelectView) and its card picture, which UI/ParkSnapshots builds and photographs
once per session for every park in db.ballparks (#39, #45);
the match intro (#40): the stadium, tour and map shots use the walls and targets, and the card lists the park’s
conditions, special balls and targets with what each pays (Cutscenes);
the main menu INDEX’s BALLPARKS tab (Index Screen);
Goal of an inning (RunState.InningGoal), rounded to the nearest 25, at least 25:
inningGoal x inningGoalGrowth^inning x (bossGoalMultiplier in a boss inning) x mapGoalGrowth^order x difficulty multiplier
What
Value
Where to tune
First inning goal, first map, Normal
500
RunConfig.inningGoal
Growth per map along the list
x1.15
RunConfig.mapGoalGrowth
Growth per inning
x1.25
RunConfig.inningGoalGrowth
Boss inning
x1.25
RunConfig.bossGoalMultiplier
Medium / Hard goals
x1.4 / x1.9
Difficulties.GoalMultiplier
Unlock rule
The first map is always open. Beating a map on Normal opens its Medium; beating Medium opens its Hard and the next
map in the list (MetaProgression.IsMapUnlocked, RecordMap). See Map Select and Unlocks.
Check it works
Tools → Home Run Derby → Run Run Structure Test: checks innings, goals and the unlock order, and that the
dev insta-home-run bat clears every park’s wall (including practice parks).
Tools → Home Run Derby → Run Scoreboard Smash Test: checks that an ordinary home run never reaches the
scoreboard in a run park, and logs how hard you must hit it in each park.
Tools → Home Run Derby → Run Ball Effect Test: EveryParkHasItsOwnBoss uses a fixed park → boss table; add the
new pair to it.
Press Play, start a run on the new park, then Tools → Home Run Derby → Preview Match Intro (or I on the run
map, Editor only) replays the intro on that inning to check its shots.
Press Play: the map should appear on the map select screen. F1 → MAPS can unlock every map to try it.
The batting cage lists every park too (Batting Cage).
Gotchas
Inserting a map in the middle changes the goals of every map after it and moves who unlocks whom. Players who
had beaten the map before the new one on Medium will find the new map open, and the map that used to follow is
locked again for them until they beat the new one on Medium (unlocks are worked out from the list each time, not
saved per map).
db.ballparks[0] is also the backdrop of the title, lobby and Customize screens (GameRoot.GoToMainMenu).
The daily challenge picks parks[Derive(today, 0xDA11) % parks.Count], so adding a map changes which map the daily is on
(and builds with different map lists disagree on the daily).
Saves store the park id (MapProgress.parkId, RunSaveData.parkId). Never rename an id.
Co-op: the host sends the park id in StartRun; every player needs the same content. Since the build version is
always 1.0, only NetSession.Protocol catches mismatched builds (see Protocol Versions).
Tools → Home Run Derby → Export Default Content To Assets does not export practiceParks.