Map Select and Unlocks

In short

Maps open one at a time in the order of ContentDatabase.ballparks. On each map, beat Normal to open Medium, and beat Medium to open Hard and the next map. Beating Hard is the map’s 100%. Only the first map is open on a new save.

How it works

The screen (MapSelectView, title PICK A BALLPARK): a carousel of park cards that slides left and right, in unlock order, so parks get harder to the right.

  • The centred card (yellow border): the park’s picture, its name, a difficulty rating (one baseball per place in the order, filled up to this park’s), its description, then one button per difficulty (NORMAL, MEDIUM, HARD; a locked one is greyed with a lock) with BEST score under it once you have one. Under those: what the picked difficulty changes (Difficulty), a yellow hint of what beating it opens (“Beat it to unlock Medium.”, “Beat it to unlock Hard and the next park, name.”, “Beat it for the park’s 100%.”, “Beaten! Play again for a higher score.”), and the PLAY BALL! slab. A 100% pill sits on the picture when all three are beaten.
  • Side cards are smaller and shaded, with a pip per difficulty (ticked in its colour once beaten). Click one, or the round arrows on the centred card’s edges, to slide to it.
  • Locked parks can be looked at, not played: the picture is darkened with LOCKED and “BEAT previous park ON MEDIUM”, and the slab reads LOCKED.
  • Keys (hint bar at the bottom): Left / Right or A / D slide, Up / Down or W / S change difficulty, 1 / 2 / 3 pick Normal / Medium / Hard, Enter plays, Esc goes back. The mouse wheel slides one card per flick. BACK (top left) returns to the title. Picking a locked difficulty or playing a locked park buzzes.
  • Opening it starts on the newest open park the first time, or after a new park opened; otherwise where you left off. The difficulty starts at the park’s highest open one, and each park remembers your pick for the session.
  • Behind the cards the centred park (or, while it is locked, the newest open one: no spoilers) is built and a slow camera sweeps over it.
  • Park pictures (ParkSnapshots): the first visit builds every park in turn and photographs it from up behind the plate with the main camera (same sky, lights and post effects as play). A WARMING UP THE BALLPARKS loading bar covers the flicker. Pictures are kept for the session.
  • The park’s modifiers and targets are no longer on this screen; they are on the between-innings briefing.

The rules (MetaProgression):

  1. Each map has a MapProgress in the save: beaten (0 = none, 1 = Normal, 2 = Medium, 3 = Hard) and best (best score per difficulty).
  2. IsMapUnlocked: the first map always; any other map once the map before it has beaten >= 2 (Medium beaten).
  3. IsUnlocked(map, difficulty): the map is open and beaten >= difficulty (Normal = 0, Medium = 1, Hard = 2).
  4. RecordMap runs at the end of every non-daily run. It always keeps the best score for that difficulty. On a win at the hardest open difficulty (beaten == difficulty), beaten goes up by one and it returns the unlock lines shown on the results screen:
    • Normal won: MEDIUM UNLOCKED: SANDLOT FIELD
    • Medium won: HARD UNLOCKED: ... and NEW MAP: ... (if there is a next map)
    • Hard won: SANDLOT FIELD 100% COMPLETE!

Numbers

WhatValueWhere to tune
Unlock orderSandlot Field, Farmyard, Windy City Yard, Midnight Yard, Moon Stadiumorder of db.ballparks in DefaultContent
Goal growth per map along the orderx1.15RunConfig.mapGoalGrowth
Difficulties per map3Difficulties.Count
Maps open on a new save1 (the first)MetaProgression.IsMapUnlocked
Card size / picture height520 x 572 / 260 pxMapSelectView.CardW, CardH, ImageH
Side card scale0.76 next to the centre, 0.62 further outNeighbourScale, FarScale
Wheel cooldown0.18 sMapSelectView.WheelCooldown
Park picture size768 x 368ParkSnapshots.Width, Height

First-inning goal on Normal per map, worked out from RunState.InningGoal (500 x 1.15^order, nearest 25):

MapSandlot FieldFarmyardWindy City YardMidnight YardMoon Stadium
Inning 1 goal500575650750875

In the code

FileWhat it does
Assets/_Project/Scripts/UI/MapSelectView.csThe carousel: DrawCard, DrawPlayArea, DrawPicture, DrawRating, DrawProgress, HandleInput, UnlockHint, LatestUnlocked
Assets/_Project/Scripts/UI/ParkSnapshots.csWarm, For(park), IsWarming, Progress: one picture per park, cached for the session
Assets/_Project/Scripts/Progression/MetaProgression.csIsMapUnlocked, IsUnlocked(park, difficulty), HighestUnlocked, Beaten, BestScore, RecordMap
Assets/_Project/Scripts/Progression/SaveData.csMapProgress (parkId, beaten, best[]) in SaveData.maps
Assets/_Project/Scripts/Data/DefaultContent.csdb.ballparks.AddRange(...) sets the order; practiceParks holds Scoreboard Smash
Assets/_Project/Editor/RunStructureTest.csUnlockOrder and DevMapTools check every rule above

Gotchas

  • Winning a lower difficulty again unlocks nothing new (beaten only moves when you win at beaten == difficulty).
  • A loss still records the best score for that map and difficulty.
  • The daily run never calls RecordMap: it opens nothing and does not set map bests. See Daily Seed and Leaderboard.
  • In co-op a team win records the map for every player. See Co-op Rules.
  • Practice parks (Scoreboard Smash) are never run maps; they only appear in the Batting Cage.
  • Old saves without maps load with only the first map open.
  • The results screen’s button still says PICK A MAP; it opens this screen.
  • The first visit each session shows the loading bar while every park is photographed; later visits are instant.
  • The goals per difficulty (inning 1 and 9) are no longer printed on the cards.
  • Dev menu: unlock all maps sets beaten to 2 on every map (every difficulty open, nothing marked 100%); you can also set one map’s beaten count or reset maps. See Dev Menu and Shortcuts.