Summary
Once player levels are captured (#70) and DHModels exposes tier utilities (gwillish/DHModels#21), the difficulty assessor and adversary roster should become tier-aware.
Blocked by
Party tier calculation
Party tier = DifficultyBudget.partyTier(levels:) — median character level → tier, rounding up when the median straddles a tier boundary.
Examples:
| Party levels |
Median |
Party tier |
| [1] |
1 |
T1 |
| [2, 3, 4, 5] |
3.5 → rounds up → 4 → T2 |
T2 |
| [4, 5] |
4.5 → rounds up → 5 → T3 |
T3 |
| [7, 8, 9] |
8 |
T4 |
Changes
DifficultyAssessorView
- Compute party tier from
playerConfigs.map(\.level) and pass to DifficultyBudget.suggestedAdjustments
lowerTierAdversary auto-detected (and shown as auto-applied) when any roster adversary is below party tier
- Display party tier alongside the budget summary, e.g. "Party: T2 · 4 players · 14 pts"
AdversaryRosterRow / AdversaryRosterSection
- Highlight adversaries whose tier differs from party tier:
- Below party tier — amber tint + "T1" badge (still addable; just flagged)
- Above party tier — red tint + tier badge
- Matching tier — no decoration
- Tooltips / accessibility hints should describe the tier relationship
Notes
- Highlighting is informational only — no adversary is blocked or removed
- With enough lower-tier adversaries the budget will still show the encounter as challenging (the budget numbers tell that story)
- If all
playerConfigs have level == 0 or the array is empty, skip tier highlighting gracefully (no party tier derivable)
Summary
Once player levels are captured (#70) and DHModels exposes tier utilities (gwillish/DHModels#21), the difficulty assessor and adversary roster should become tier-aware.
Blocked by
Party tier calculation
Party tier =
DifficultyBudget.partyTier(levels:)— median character level → tier, rounding up when the median straddles a tier boundary.Examples:
Changes
DifficultyAssessorViewplayerConfigs.map(\.level)and pass toDifficultyBudget.suggestedAdjustmentslowerTierAdversaryauto-detected (and shown as auto-applied) when any roster adversary is below party tierAdversaryRosterRow/AdversaryRosterSectionNotes
playerConfigshavelevel == 0or the array is empty, skip tier highlighting gracefully (no party tier derivable)