Skip to content

feat: add a box to park, switch, and collect Pokémon - #265

Open
Seb1337 wants to merge 9 commits into
chattymin:mainfrom
Seb1337:feature/box
Open

Seb1337 wants to merge 9 commits into
chattymin:mainfrom
Seb1337:feature/box

Conversation

@Seb1337

@Seb1337 Seb1337 commented Sep 3, 2026

Copy link
Copy Markdown

What

The app raises one active companion at a time, and finishing or rerolling a Pokémon discarded the previous one. This adds a box to store individual Pokémon, switch which one is active, and keep the ones you finish raising. Each stored Pokémon keeps its exact growth state (stageIndex/usedAtStage), so parking and resuming is lossless. Buying an egg now parks the current companion in the box instead of releasing it. The active companion still grows on its own — the box is opt-in.

Changes

  • Model: CompanionState.box: [MonState], a stable MonState.id, and MonState.isComplete (set at graduation). Additive and lenient-decoded, so old saves load unchanged — no save-schema bump.
  • CompanionStore.setActiveFromBox(id:) swaps a boxed Pokémon with the active one (growth preserved); graduated trophies can't be activated. graduate() keeps the finished Pokémon in the box (isComplete) alongside the existing dex record; applyUsage no longer re-grows a completed mon.
  • dexSpecies / ownsSpecies / ownsShinySpecies now count boxed individuals, so switching the active companion never drops species from the Pokédex.
  • buyEgg parks the active companion in the box (previously released it into the dex via releasedDexEntry, now removed) and starts the new egg immediately; canBuyEgg is unchanged (needs an active companion and funds). Price and rarity-guarantee mechanics are untouched.
  • SaveTransfer: box is classified as progress, and sanitized() clamps box entries at the import trust boundary just like the active companion.

UI

  • Collection gains a segmented Pokédex | Box (grouped on the left) with Catch log set apart on the right (CollectionSection).
  • BoxGridView: paged 4×6 grid; inline confirm to set active (no sheets, matching the popover rule); names resolved through the cached line provider; a 🏆 badge marks graduated trophies, which show a short reason instead of the switch button.
  • New localized strings for the box (en/ko/ja/es/fr/pt/de).

Verification

  • Full test suite: 916 tests, 0 failures.
  • Added coverage: box round-trip preserves token status; swap semantics and guards; graduation → box; final form ≠ graduated; graduated can't be activated; box species stay in the Pokédex across a switch; egg purchase parks instead of releasing (fresh + premium); import clamping of box entries; backward-compatible decode.

Note

The one change to the established loop is the egg purchase (release → park). Happy to split that into its own PR or gate it behind a setting — the box stands on its own without it.


Edit (2026-09-10): Updated onto the latest main and resolved the conflicts.

  • Integrates cleanly with the new individual-profile feature: boxed/parked Pokémon carry their profile, graduation and box swaps preserve it, and sanitized() clamps box entries' profiles too (shared clampMon helper).
  • buyEgg now uses the new price(of:) API while keeping the park-in-box behavior; the now-unused releasedDexEntry was removed.
  • Full test suite green after the merge: 1030 tests, 0 failures.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant