From 49a311cc9b18ecbfe86431f53e94ca87455253b3 Mon Sep 17 00:00:00 2001 From: Aurastic <33085835+ISenseAura@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:26:26 +0530 Subject: [PATCH] Preact: Show additional rule options in challenge forms (#2610) --- play.pokemonshowdown.com/src/panel-chat.tsx | 12 ++++-- .../src/panel-mainmenu.tsx | 43 ++++++++++++++++++- .../src/panel-teamdropdown.tsx | 3 ++ 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/play.pokemonshowdown.com/src/panel-chat.tsx b/play.pokemonshowdown.com/src/panel-chat.tsx index 4869a7bc9..6665d4d22 100644 --- a/play.pokemonshowdown.com/src/panel-chat.tsx +++ b/play.pokemonshowdown.com/src/panel-chat.tsx @@ -1313,11 +1313,14 @@ class ChatPanel extends PSRoomPanel { const challengeSent = room.teamSent && !room.challenged; const challengeTo = room.challenging ?

Waiting for {room.pmTarget}...

- +
: room.challengeMenuOpen ?
- + {challengeSent && } @@ -1333,7 +1336,10 @@ class ChatPanel extends PSRoomPanel { const challengeFrom = room.challenged ?
{!!room.challenged.message &&

{room.challenged.message}

} - + {room.teamSent && } diff --git a/play.pokemonshowdown.com/src/panel-mainmenu.tsx b/play.pokemonshowdown.com/src/panel-mainmenu.tsx index 297fa05ee..d2e104f9f 100644 --- a/play.pokemonshowdown.com/src/panel-mainmenu.tsx +++ b/play.pokemonshowdown.com/src/panel-mainmenu.tsx @@ -246,6 +246,9 @@ export class MainMenuRoom extends PSRoom { let searchShow = true; let challengeShow = true; let tournamentShow = true; + let partner = false; + let bestOfDefault = false; + let teraPreviewDefault = false; let team: 'preset' | null = null; let teambuilderLevel: number | null = null; let lastCommaIndex = name.lastIndexOf(','); @@ -257,6 +260,9 @@ export class MainMenuRoom extends PSRoom { if (!(code & 4)) challengeShow = false; if (!(code & 8)) tournamentShow = false; if (code & 16) teambuilderLevel = 50; + if (code & 32) partner = true; + if (code & 64) bestOfDefault = true; + if (code & 128) teraPreviewDefault = true; } else { // Backwards compatibility: late 0.9.0 -> 0.10.0 if (name.substr(name.length - 2) === ',#') { // preset teams @@ -318,8 +324,11 @@ export class MainMenuRoom extends PSRoom { searchShow, challengeShow, tournamentShow, + bestOfDefault, + teraPreviewDefault, rated: searchShow && id.substr(4, 7) !== 'unrated', teambuilderLevel, + partner, teambuilderFormat, isTeambuilderFormat, effectType: 'Format', @@ -812,12 +821,14 @@ export class TeamForm extends preact.Component<{ onValidate?: ((e: Event, format: string, team?: Team) => void) | null, }> { format = ''; + teraPreview = false; + bestOf = false; changeFormat = (ev: Event) => { this.format = (ev.target as HTMLButtonElement).value; }; submit = (ev: Event, validate?: 'validate') => { ev.preventDefault(); - const format = this.format; + let format = this.format; const teamElement = this.base!.querySelector('button[name=team]'); const teamKey = teamElement!.value; const team = teamKey ? PS.teams.byKey[teamKey] : undefined; @@ -827,10 +838,25 @@ export class TeamForm extends preact.Component<{ }); return; } + if (this.teraPreview) { + const hasCustomRules = format.includes('@@@'); + format = `${format}${hasCustomRules ? ', Tera Type Preview' : '@@@ Tera Type Preview'}`; + } + if (this.bestOf) { + const hasCustomRules = format.includes('@@@'); + const value = this.base?.querySelector('input[name=bestofvalue]')?.value; + format = `${format}${hasCustomRules ? `, Best of = ${value!}` : `@@@ Best of = ${value!}`}`; + } PS.teams.loadTeam(team).then(() => { (validate === 'validate' ? this.props.onValidate : this.props.onSubmit)?.(ev, format, team); }); }; + toggleCustomRule = (ev: Event) => { + const checked = (ev.target as HTMLInputElement)?.checked; + const rule = (ev.target as HTMLInputElement)?.name; + if (rule === 'terapreview') this.teraPreview = checked; + if (rule === 'bestof') this.bestOf = checked; + }; handleClick = (ev: Event) => { let target = ev.target as HTMLButtonElement | null; while (target && target !== this.base) { @@ -842,6 +868,7 @@ export class TeamForm extends preact.Component<{ } }; render() { + const formatId = toID(this.format.split('@@@')[0]); if (window.BattleFormats) { this.format ||= this.props.defaultFormat || ''; if (!this.format) { @@ -867,7 +894,6 @@ export class TeamForm extends preact.Component<{ this.format = this.props.defaultFormat.slice(2); } if (this.props.format) this.format = this.props.format; - return
{!this.props.hideFormat &&

+ {this.props.selectType === 'challenge' && + window.BattleFormats[formatId]?.teraPreviewDefault &&

+

} + {this.props.selectType === 'challenge' && + window.BattleFormats[formatId]?.bestOfDefault &&

+

}

{this.props.children}

; } diff --git a/play.pokemonshowdown.com/src/panel-teamdropdown.tsx b/play.pokemonshowdown.com/src/panel-teamdropdown.tsx index 12f5e569e..8102e9508 100644 --- a/play.pokemonshowdown.com/src/panel-teamdropdown.tsx +++ b/play.pokemonshowdown.com/src/panel-teamdropdown.tsx @@ -347,8 +347,11 @@ export interface FormatData { searchShow?: boolean; challengeShow?: boolean; tournamentShow?: boolean; + bestOfDefault?: boolean; + teraPreviewDefault?: boolean; rated: boolean; teambuilderLevel?: number | null; + partner?: boolean; teambuilderFormat?: ID; battleFormat?: string; isTeambuilderFormat: boolean;