mirror of
https://github.com/smogon/pokemon-showdown-client.git
synced 2026-03-21 17:50:29 -05:00
Support making and receiving challenges
Actually playing the game that opens when you accept a challenge is, of course, yet to be implemented.
This commit is contained in:
parent
64b95e23cc
commit
6b66a0322e
|
|
@ -559,6 +559,7 @@ const PS = new class extends PSModel {
|
|||
case 'html':
|
||||
case 'raw':
|
||||
case 'challstr':
|
||||
case 'popup':
|
||||
case '':
|
||||
return [cmd, str.slice(index + 1)];
|
||||
case 'c':
|
||||
|
|
@ -878,11 +879,18 @@ const PS = new class extends PSModel {
|
|||
}
|
||||
return buf;
|
||||
}
|
||||
getPMRoom(userid: ID) {
|
||||
const myUserid = PS.user.userid;
|
||||
const roomid = `pm-${[userid, myUserid].sort().join('-')}` as RoomID;
|
||||
if (this.rooms[roomid]) return this.rooms[roomid] as ChatRoom;
|
||||
this.join(roomid);
|
||||
return this.rooms[roomid] as ChatRoom;
|
||||
}
|
||||
addRoom(options: RoomOptions, noFocus?: boolean) {
|
||||
// support hardcoded PM room-IDs
|
||||
if (options.id.startsWith('challenge-')) {
|
||||
options.id = `pm-${options.id.slice(10)}` as RoomID;
|
||||
options.challenging = true;
|
||||
options.challengeMenuOpen = true;
|
||||
}
|
||||
if (options.id.startsWith('pm-') && options.id.indexOf('-', 3) < 0) {
|
||||
const userid1 = PS.user.userid;
|
||||
|
|
@ -902,7 +910,7 @@ const PS = new class extends PSModel {
|
|||
}
|
||||
}
|
||||
if (!noFocus) {
|
||||
if (options.challenging) {
|
||||
if (options.challengeMenuOpen) {
|
||||
(this.rooms[options.id] as ChatRoom).openChallenge();
|
||||
}
|
||||
this.focusRoom(options.id);
|
||||
|
|
|
|||
|
|
@ -9,12 +9,17 @@ class ChatRoom extends PSRoom {
|
|||
readonly classType: string = 'chat';
|
||||
users: {[userid: string]: string} = {};
|
||||
userCount = 0;
|
||||
|
||||
// PM-only properties
|
||||
pmTarget: string | null = null;
|
||||
challenging = false;
|
||||
challengeMenuOpen = false;
|
||||
challengingFormat: string | null = null;
|
||||
challengedFormat: string | null = null;
|
||||
|
||||
constructor(options: RoomOptions) {
|
||||
super(options);
|
||||
if (options.pmTarget) this.pmTarget = options.pmTarget as string;
|
||||
if (options.challenging) this.challenging = true;
|
||||
if (options.challengeMenuOpen) this.challengeMenuOpen = true;
|
||||
this.updateTarget(true);
|
||||
this.connect();
|
||||
}
|
||||
|
|
@ -64,6 +69,9 @@ class ChatRoom extends PSRoom {
|
|||
}
|
||||
this.openChallenge();
|
||||
return true;
|
||||
} case 'cchall': case 'cancelchallenge': {
|
||||
this.cancelChallenge();
|
||||
return true;
|
||||
}}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -72,7 +80,21 @@ class ChatRoom extends PSRoom {
|
|||
this.receive(`|error|Can only be used in a PM.`);
|
||||
return;
|
||||
}
|
||||
this.challenging = true;
|
||||
this.challengeMenuOpen = true;
|
||||
this.update('');
|
||||
}
|
||||
cancelChallenge() {
|
||||
if (!this.pmTarget) {
|
||||
this.receive(`|error|Can only be used in a PM.`);
|
||||
return;
|
||||
}
|
||||
if (this.challengingFormat) {
|
||||
this.send('/cancelchallenge', true);
|
||||
this.challengingFormat = null;
|
||||
this.challengeMenuOpen = true;
|
||||
} else {
|
||||
this.challengeMenuOpen = false;
|
||||
}
|
||||
this.update('');
|
||||
}
|
||||
send(line: string, direct?: boolean) {
|
||||
|
|
@ -310,30 +332,57 @@ class ChatPanel extends PSRoomPanel<ChatRoom> {
|
|||
challenge = (e: Event, format: string, team?: Team) => {
|
||||
const room = this.props.room;
|
||||
const packedTeam = team ? team.packedTeam : '';
|
||||
room.challenging = false;
|
||||
if (!room.pmTarget) throw new Error("Not a PM room");
|
||||
PS.send(`|/utm ${packedTeam}`);
|
||||
PS.send(`|/challenge ${room.pmTarget}, ${format}`);
|
||||
room.challengeMenuOpen = false;
|
||||
room.challengingFormat = format;
|
||||
room.update('');
|
||||
};
|
||||
acceptChallenge = (e: Event, format: string, team?: Team) => {
|
||||
const room = this.props.room;
|
||||
const packedTeam = team ? team.packedTeam : '';
|
||||
if (!room.pmTarget) throw new Error("Not a PM room");
|
||||
PS.send(`|/utm ${packedTeam}`);
|
||||
this.props.room.send(`/accept`);
|
||||
room.challengedFormat = null;
|
||||
room.update('');
|
||||
};
|
||||
cancelChallenge = (e: Event) => {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
this.props.room.cancelChallenge();
|
||||
};
|
||||
rejectChallenge = (e: Event) => {
|
||||
const room = this.props.room;
|
||||
room.challenging = false;
|
||||
room.update('');
|
||||
room.challengedFormat = null;
|
||||
room.send(`/reject`);
|
||||
};
|
||||
render() {
|
||||
const room = this.props.room;
|
||||
|
||||
const challenge = room.challenging ? <div class="challenge">
|
||||
const challengeTo = room.challengingFormat ? <div class="challenge">
|
||||
<TeamForm format={room.challengingFormat} onSubmit={null}>
|
||||
<button onClick={this.cancelChallenge} class="button">Cancel</button>
|
||||
</TeamForm>
|
||||
</div> : room.challengeMenuOpen ? <div class="challenge">
|
||||
<TeamForm onSubmit={this.challenge}>
|
||||
<button type="submit" class="button disabled"><strong>Challenge</strong></button> {}
|
||||
<button onClick={this.cancelChallenge} class="button">Cancel</button>
|
||||
</TeamForm>
|
||||
</div> : null;
|
||||
|
||||
const challengeFrom = room.challengedFormat ? <div class="challenge">
|
||||
<TeamForm format={room.challengedFormat} onSubmit={this.acceptChallenge}>
|
||||
<button type="submit" class="button disabled"><strong>Accept</strong></button> {}
|
||||
<button onClick={this.rejectChallenge} class="button">Reject</button>
|
||||
</TeamForm>
|
||||
</div> : null;
|
||||
|
||||
return <PSPanelWrapper room={this.props.room}>
|
||||
<div class="tournament-wrapper hasuserlist"></div>
|
||||
<ChatLog class="chat-log hasuserlist" room={this.props.room} onClick={this.focusIfNoSelection}>
|
||||
{challenge}
|
||||
{challengeTo || challengeFrom && [challengeTo, challengeFrom]}
|
||||
</ChatLog>
|
||||
<ChatTextEntry room={this.props.room} onMessage={this.send} onKey={this.onKey} />
|
||||
<ChatUserList room={this.props.room} />
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@ class MainMenuRoom extends PSRoom {
|
|||
case 'updateuser':
|
||||
PS.user.setName(tokens[1], tokens[2] === '1', tokens[3]);
|
||||
return;
|
||||
case 'updatechallenges':
|
||||
this.receiveChallenges(tokens[1]);
|
||||
return;
|
||||
case 'queryresponse':
|
||||
this.handleQueryResponse(tokens[1] as ID, JSON.parse(tokens[2]));
|
||||
return;
|
||||
|
|
@ -47,10 +50,37 @@ class MainMenuRoom extends PSRoom {
|
|||
case 'formats':
|
||||
this.parseFormats(tokens);
|
||||
return;
|
||||
case 'popup':
|
||||
alert(tokens[1]);
|
||||
return;
|
||||
}
|
||||
const lobby = PS.rooms['lobby'];
|
||||
if (lobby) lobby.receive(line);
|
||||
}
|
||||
receiveChallenges(dataBuf: string) {
|
||||
let json;
|
||||
try {
|
||||
json = JSON.parse(dataBuf);
|
||||
} catch {}
|
||||
for (const userid in json.challengesFrom) {
|
||||
PS.getPMRoom(toID(userid));
|
||||
}
|
||||
if (json.challengeTo) {
|
||||
PS.getPMRoom(toID(json.challengeTo.to));
|
||||
}
|
||||
for (const roomid in PS.rooms) {
|
||||
const room = PS.rooms[roomid] as ChatRoom;
|
||||
if (!room.pmTarget) continue;
|
||||
const targetUserid = toID(room.pmTarget);
|
||||
if (!room.challengedFormat && !(targetUserid in json.challengesFrom) &&
|
||||
!room.challengingFormat && (json.challengeTo || {}).to !== targetUserid) {
|
||||
continue;
|
||||
}
|
||||
room.challengedFormat = json.challengesFrom[targetUserid] || null;
|
||||
room.challengingFormat = json.challengeTo.to === targetUserid ? json.challengeTo.format : null;
|
||||
room.update('');
|
||||
}
|
||||
}
|
||||
parseFormats(formatsList: string[]) {
|
||||
let isSection = false;
|
||||
let section = '';
|
||||
|
|
@ -378,7 +408,7 @@ class TeamDropdown extends preact.Component<{format: string}> {
|
|||
|
||||
class TeamForm extends preact.Component<{
|
||||
children: preact.ComponentChildren, class?: string, format?: string,
|
||||
onSubmit: (e: Event, format: string, team?: Team) => void,
|
||||
onSubmit: null | ((e: Event, format: string, team?: Team) => void),
|
||||
}> {
|
||||
state = {format: '[Gen 7] Random Battle'};
|
||||
changeFormat = (e: Event) => {
|
||||
|
|
@ -389,7 +419,7 @@ class TeamForm extends preact.Component<{
|
|||
const format = (this.base!.querySelector('button[name=format]') as HTMLButtonElement).value;
|
||||
const teamKey = (this.base!.querySelector('button[name=team]') as HTMLButtonElement).value;
|
||||
const team = teamKey ? PS.teams.byKey[teamKey] : undefined;
|
||||
this.props.onSubmit(e, format, team);
|
||||
if (this.props.onSubmit) this.props.onSubmit(e, format, team);
|
||||
};
|
||||
render() {
|
||||
return <form class={this.props.class} onSubmit={this.submit}>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user