Preact: Show additional rule options in challenge forms (#2610)

This commit is contained in:
Aurastic 2026-03-15 09:26:26 +05:30 committed by GitHub
parent 95bb6568f3
commit 49a311cc9b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 53 additions and 5 deletions

View File

@ -1313,11 +1313,14 @@ class ChatPanel extends PSRoomPanel<ChatRoom> {
const challengeSent = room.teamSent && !room.challenged;
const challengeTo = room.challenging ? <div class="challenge outgoing">
<p>Waiting for {room.pmTarget}...</p>
<TeamForm format={room.challenging.formatName} teamFormat={room.challenging.teamFormat} onSubmit={null}>
<TeamForm
format={room.challenging.formatName} teamFormat={room.challenging.teamFormat}
onSubmit={null} selectType="challenge"
>
<button data-cmd="/cancelchallenge" class="button">Cancel</button>
</TeamForm>
</div> : room.challengeMenuOpen ? <div class="challenge outgoing">
<TeamForm onSubmit={this.makeChallenge} defaultFormat={defaultFormat}>
<TeamForm onSubmit={this.makeChallenge} defaultFormat={defaultFormat} selectType="challenge">
{challengeSent && <button class="button" disabled>
Challenging...
</button>}
@ -1333,7 +1336,10 @@ class ChatPanel extends PSRoomPanel<ChatRoom> {
const challengeFrom = room.challenged ? <div class="challenge">
{!!room.challenged.message && <p>{room.challenged.message}</p>}
<TeamForm format={room.challenged.formatName} teamFormat={room.challenged.teamFormat} onSubmit={this.acceptChallenge}>
<TeamForm
format={room.challenged.formatName} teamFormat={room.challenged.teamFormat}
onSubmit={this.acceptChallenge} selectType="challenge"
>
{room.teamSent && <button class="button" disabled>
Accepting...
</button>}

View File

@ -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<HTMLButtonElement>('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<HTMLInputElement>('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 <form class={this.props.class} onSubmit={this.submit} onClick={this.handleClick}>
{!this.props.hideFormat && <p>
<label class="label">
@ -884,6 +910,19 @@ export class TeamForm extends preact.Component<{
<TeamDropdown format={this.props.teamFormat || this.format} />
</label>
</p>
{this.props.selectType === 'challenge' &&
window.BattleFormats[formatId]?.teraPreviewDefault && <p>
<label class="checkbox">
<input type="checkbox" name="terapreview" onChange={this.toggleCustomRule} />
<abbr title="Start a battle with Tera Type Preview">Tera Type Preview</abbr></label></p>}
{this.props.selectType === 'challenge' &&
window.BattleFormats[formatId]?.bestOfDefault && <p>
<label class="checkbox"><input type="checkbox" name="bestof" onChange={this.toggleCustomRule} />
<abbr title="Start a team-locked best-of-n series">
Best-of-<input
name="bestofvalue" type="number" min="3" max="9" step="2" value="3" style="width: 28px; vertical-align: initial;"
/>
</abbr></label></p>}
<p>{this.props.children}</p>
</form>;
}

View File

@ -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;