Add boss team match playstyle rule
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / actions-lint (push) Successful in 16s
CI / frontend-lint (push) Successful in 21s

When enabled, the sticky boss banner shows the next boss's team size
as a hint for players who voluntarily match the boss's party count.
Handles variant boss teams by using the auto-detected starter variant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 22:03:11 +01:00
parent 6968d35a33
commit 347c25e8ed
5 changed files with 45 additions and 20 deletions

View File

@@ -1,33 +1,29 @@
---
# nuzlocke-tracker-fv7w
title: Add team size limit rule
status: todo
title: Add boss team match rule
status: in-progress
type: feature
priority: normal
created_at: 2026-02-20T19:56:22Z
updated_at: 2026-02-20T20:01:53Z
updated_at: 2026-02-20T21:01:36Z
parent: nuzlocke-tracker-49xj
---
Cap the active party size with warnings when the limit is exceeded.
When enabled, hint to the player that they should limit their active party to the same number of Pokemon as the next boss fight. This is a self-imposed difficulty rule — the tracker cannot enforce it since it doesn't track the active party, but it can surface the information.
## Design Decisions
## Design
**Configurable limit:** Add `teamSizeLimit: number | null` to `NuzlockeRules`. `null` means no limit (disabled). Default Pokemon party size is 6, but variants like "trio-locke" use 3.
**Rule:** Add `bossTeamMatch: boolean` to `NuzlockeRules` (default: `false`, category: `playstyle`).
**What counts:** "Active team" = encounters with status `caught` and not fainted. The tracker already tracks this — alive Pokemon are shown in the team section on RunEncounters.
**Display:** When enabled and the sticky boss banner is shown, add a hint next to the boss name showing their team size, e.g. "Next: Brock (2 Pokemon — match their team)". This reuses the existing `nextBoss` and its `pokemon` array.
**No PC box tracking:** The tracker doesn't model a PC box. Excess catches beyond the team limit are still logged normally. The tracker just warns that the team is over capacity.
**Variant bosses:** Some bosses have conditional teams (e.g. rival starter choice). Use the same logic as `BossTeamPreview`: count pokemon without a `conditionLabel` plus those matching the auto-detected variant (via `matchVariant`). Falls back to first variant if no match is detected.
**Enforcement:** Soft enforcement. Show a warning banner on the encounters page when alive count exceeds the limit. Highlight the count in the team section header. Don't block new catches.
**UI:** Add a numeric input to `RulesConfiguration` (shown when team size toggle is on, min 1, max 6). Display the limit in the sticky bar alongside level caps if enabled.
**Scope:** Frontend-only. No backend or data model changes needed.
## Checklist
- [ ] Add `teamSizeLimit: number | null` to `NuzlockeRules` interface (default: `null`)
- [ ] Add `RuleDefinition` entry under `'difficulty'` category
- [ ] Add numeric input to `RulesConfiguration` (shown when enabled, min 1, max 6)
- [ ] Show warning banner on RunEncounters when alive team count exceeds limit
- [ ] Display team size limit in sticky bar alongside level caps
- [ ] Show count in team section header (e.g., "Team (4/3)" in red when over)
- [x] Add `bossTeamMatch: boolean` to `NuzlockeRules` interface and `DEFAULT_RULES` (default: false)
- [x] Add `RuleDefinition` entry (category: `playstyle`)
- [x] Show boss team size hint in the sticky level cap banner when the rule is enabled
- [x] Handle variant boss teams (use auto-matched variant count when available)

View File

@@ -1,11 +1,11 @@
---
# nuzlocke-tracker-sij8
title: Add gift clause rule
status: in-progress
status: completed
type: feature
priority: normal
created_at: 2026-02-20T19:56:10Z
updated_at: 2026-02-20T20:53:15Z
updated_at: 2026-02-20T20:55:23Z
parent: nuzlocke-tracker-49xj
---

View File

@@ -149,6 +149,7 @@ DEFAULT_RULES = {
"levelCaps": False,
"hardcoreMode": False,
"setModeOnly": False,
"bossTeamMatch": False,
"egglocke": False,
"wonderlocke": False,
"randomizer": False,

View File

@@ -178,6 +178,17 @@ function matchVariant(labels: string[], starterName?: string | null): string | n
return matches.length === 1 ? (matches[0] ?? null) : null
}
/** Count boss pokemon for the effective variant (or all if no variants). */
function getBossTeamSize(pokemon: BossPokemon[], starterName?: string | null): number {
const labels = [
...new Set(pokemon.filter((bp) => bp.conditionLabel).map((bp) => bp.conditionLabel!)),
]
if (labels.length === 0) return pokemon.length
const matched = matchVariant(labels, starterName)
const variant = matched ?? labels[0] ?? null
return pokemon.filter((bp) => bp.conditionLabel === variant || bp.conditionLabel === null).length
}
function BossTeamPreview({
pokemon,
starterName,
@@ -1060,7 +1071,15 @@ export function RunEncounters() {
Level Cap: {currentLevelCap ?? '—'}
</span>
{nextBoss && (
<span className="text-sm text-text-tertiary">Next: {nextBoss.name}</span>
<span className="text-sm text-text-tertiary">
Next: {nextBoss.name}
{run.rules?.bossTeamMatch && (
<span className="text-text-muted">
{' '}
({getBossTeamSize(nextBoss.pokemon, starterName)} Pokémon match their team)
</span>
)}
</span>
)}
{!nextBoss && (
<span className="text-sm text-status-active">All bosses defeated!</span>

View File

@@ -9,6 +9,7 @@ export interface NuzlockeRules {
// Playstyle (informational, for stats/categorization)
hardcoreMode: boolean
setModeOnly: boolean
bossTeamMatch: boolean
// Variant (changes which Pokemon can appear)
egglocke: boolean
@@ -27,6 +28,7 @@ export const DEFAULT_RULES: NuzlockeRules = {
// Playstyle - off by default
hardcoreMode: false,
setModeOnly: false,
bossTeamMatch: false,
// Variant - off by default
egglocke: false,
@@ -93,6 +95,13 @@ export const RULE_DEFINITIONS: RuleDefinition[] = [
'The game must be played in "Set" battle style, meaning you cannot switch Pokémon after knocking out an opponent.',
category: 'playstyle',
},
{
key: 'bossTeamMatch',
name: 'Boss Team Match',
description:
'Limit your active party to the same number of Pokémon as the boss you are challenging.',
category: 'playstyle',
},
// Variant
{