Add static clause rule for encounter selector filtering
When disabled, static encounters (legendaries, scripted Pokémon) are grayed out and unselectable in the encounter selector. Enabled by default. Adds 'static' to METHOD_CONFIG/METHOD_ORDER with a teal badge. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,10 @@ export const METHOD_CONFIG: Record<string, { label: string; color: string }> = {
|
||||
label: 'Trade',
|
||||
color: 'bg-emerald-900/40 text-emerald-300 light:bg-emerald-100 light:text-emerald-700',
|
||||
},
|
||||
static: {
|
||||
label: 'Static',
|
||||
color: 'bg-teal-900/40 text-teal-300 light:bg-teal-100 light:text-teal-700',
|
||||
},
|
||||
walk: {
|
||||
label: 'Grass',
|
||||
color: 'bg-green-900/40 text-green-300 light:bg-green-100 light:text-green-700',
|
||||
@@ -59,6 +63,7 @@ export const METHOD_ORDER = [
|
||||
'gift',
|
||||
'fossil',
|
||||
'trade',
|
||||
'static',
|
||||
'walk',
|
||||
'headbutt',
|
||||
'surf',
|
||||
|
||||
@@ -42,6 +42,7 @@ interface EncounterModalProps {
|
||||
onClose: () => void
|
||||
isPending: boolean
|
||||
useAllPokemon?: boolean | undefined
|
||||
staticClause?: boolean | undefined
|
||||
}
|
||||
|
||||
const statusOptions: {
|
||||
@@ -132,7 +133,8 @@ function groupByMethod(
|
||||
} else {
|
||||
// Determine the display rate
|
||||
let displayRate: number | null = null
|
||||
const isSpecial = SPECIAL_METHODS.includes(rp.encounterMethod)
|
||||
const isSpecial =
|
||||
SPECIAL_METHODS.includes(rp.encounterMethod) || rp.encounterMethod === 'static'
|
||||
if (!isSpecial) {
|
||||
if (selectedCondition) {
|
||||
const key = `${rp.pokemonId}:${rp.encounterMethod}`
|
||||
@@ -198,6 +200,7 @@ export function EncounterModal({
|
||||
onClose,
|
||||
isPending,
|
||||
useAllPokemon,
|
||||
staticClause = true,
|
||||
}: EncounterModalProps) {
|
||||
const { data: routePokemon, isLoading: loadingPokemon } = useRoutePokemon(
|
||||
useAllPokemon ? null : route.id,
|
||||
@@ -443,7 +446,10 @@ export function EncounterModal({
|
||||
}
|
||||
onClick={() => {
|
||||
if (routePokemon) {
|
||||
setSelectedPokemon(pickRandomPokemon(routePokemon, dupedPokemonIds))
|
||||
const eligible = staticClause
|
||||
? routePokemon
|
||||
: routePokemon.filter((rp) => rp.encounterMethod !== 'static')
|
||||
setSelectedPokemon(pickRandomPokemon(eligible, dupedPokemonIds))
|
||||
}
|
||||
}}
|
||||
className="px-2.5 py-1 text-xs font-medium rounded-lg border border-purple-600 text-purple-400 light:text-purple-700 light:border-purple-500 hover:bg-purple-900/20 light:hover:bg-purple-50 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||
@@ -508,6 +514,9 @@ export function EncounterModal({
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{pokemon.map(({ encounter: rp, conditions, displayRate }) => {
|
||||
const isDuped = dupedPokemonIds?.has(rp.pokemonId) ?? false
|
||||
const isStaticDisabled =
|
||||
!staticClause && rp.encounterMethod === 'static'
|
||||
const isDisabled = isDuped || isStaticDisabled
|
||||
const isSelected =
|
||||
selectedPokemon?.pokemonId === rp.pokemonId &&
|
||||
selectedPokemon?.encounterMethod === rp.encounterMethod
|
||||
@@ -515,10 +524,10 @@ export function EncounterModal({
|
||||
<button
|
||||
key={`${rp.encounterMethod}-${rp.pokemonId}`}
|
||||
type="button"
|
||||
onClick={() => !isDuped && setSelectedPokemon(rp)}
|
||||
disabled={isDuped}
|
||||
onClick={() => !isDisabled && setSelectedPokemon(rp)}
|
||||
disabled={isDisabled}
|
||||
className={`flex flex-col items-center p-2 rounded-lg border text-center transition-colors ${
|
||||
isDuped
|
||||
isDisabled
|
||||
? 'opacity-40 cursor-not-allowed border-border-default'
|
||||
: isSelected
|
||||
? 'border-accent-400 bg-accent-900/30'
|
||||
@@ -546,22 +555,31 @@ export function EncounterModal({
|
||||
: 'already caught'}
|
||||
</span>
|
||||
)}
|
||||
{!isDuped && SPECIAL_METHODS.includes(rp.encounterMethod) && (
|
||||
<EncounterMethodBadge method={rp.encounterMethod} />
|
||||
)}
|
||||
{!isDuped && displayRate !== null && displayRate !== undefined && (
|
||||
<span className="text-[10px] text-purple-400 light:text-purple-700 font-medium">
|
||||
{displayRate}%
|
||||
{isStaticDisabled && (
|
||||
<span className="text-[10px] text-text-tertiary italic">
|
||||
static clause off
|
||||
</span>
|
||||
)}
|
||||
{!isDuped &&
|
||||
{!isDisabled &&
|
||||
(SPECIAL_METHODS.includes(rp.encounterMethod) ||
|
||||
rp.encounterMethod === 'static') && (
|
||||
<EncounterMethodBadge method={rp.encounterMethod} />
|
||||
)}
|
||||
{!isDisabled &&
|
||||
displayRate !== null &&
|
||||
displayRate !== undefined && (
|
||||
<span className="text-[10px] text-purple-400 light:text-purple-700 font-medium">
|
||||
{displayRate}%
|
||||
</span>
|
||||
)}
|
||||
{!isDisabled &&
|
||||
selectedCondition === null &&
|
||||
conditions.length > 0 && (
|
||||
<span className="text-[10px] text-purple-400 light:text-purple-700">
|
||||
{conditions.join(', ')}
|
||||
</span>
|
||||
)}
|
||||
{!isDuped && (
|
||||
{!isDisabled && (
|
||||
<span className="text-[10px] text-text-tertiary">
|
||||
Lv. {rp.minLevel}
|
||||
{rp.maxLevel !== rp.minLevel && `–${rp.maxLevel}`}
|
||||
|
||||
@@ -1543,6 +1543,7 @@ export function RunEncounters() {
|
||||
}}
|
||||
isPending={createEncounter.isPending || updateEncounter.isPending}
|
||||
useAllPokemon={useAllPokemon}
|
||||
staticClause={run?.rules?.staticClause ?? true}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ export interface NuzlockeRules {
|
||||
duplicatesClause: boolean
|
||||
shinyClause: boolean
|
||||
giftClause: boolean
|
||||
staticClause: boolean
|
||||
pinwheelClause: boolean
|
||||
levelCaps: boolean
|
||||
|
||||
@@ -22,6 +23,7 @@ export const DEFAULT_RULES: NuzlockeRules = {
|
||||
duplicatesClause: true,
|
||||
shinyClause: true,
|
||||
giftClause: false,
|
||||
staticClause: true,
|
||||
pinwheelClause: true,
|
||||
levelCaps: false,
|
||||
|
||||
@@ -66,6 +68,13 @@ export const RULE_DEFINITIONS: RuleDefinition[] = [
|
||||
"In-game gift Pokémon (starters, trades, fossils) do not count against a location's encounter limit.",
|
||||
category: 'core',
|
||||
},
|
||||
{
|
||||
key: 'staticClause',
|
||||
name: 'Static Clause',
|
||||
description:
|
||||
'Static encounters (legendaries, scripted Pokémon) are available in the encounter selector. Disable to skip them and treat the next wild encounter as your pick.',
|
||||
category: 'core',
|
||||
},
|
||||
{
|
||||
key: 'pinwheelClause',
|
||||
name: 'Pinwheel Clause',
|
||||
|
||||
Reference in New Issue
Block a user