123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- import {osu_fetch} from './api.js';
- import bancho from './bancho.js';
- import db from './database.js';
- import {get_user_rank} from './elo.js';
- import Config from './util/config.js';
- import {gen_url} from './util/helpers.js';
- async function reply(user, lobby, message) {
- if (lobby) {
- await lobby.send(`${user}: ${message}`);
- } else {
- await bancho.privmsg(user, message);
- }
- }
- async function rank_command(msg, match, lobby) {
- const requested_username = match[1].trim() || msg.from;
- const res = db.prepare(`SELECT user_id FROM user WHERE username = ?`).get(requested_username);
- let user_id = null;
- if (res) {
- user_id = res.user_id;
- } else {
- try {
- user_id = await bancho.whois(requested_username);
- } catch (err) {
- user_id = null;
- }
- }
- const rank = get_user_rank(user_id, lobby?.data?.ruleset || 0);
- if (!rank) {
- await reply(msg.from, lobby, `${requested_username} hasn't played in a ranked lobby yet.`);
- return;
- }
- const user_page = gen_url(lobby?.data?.ruleset, `/u/${user_id}/`);
- await reply(msg.from, lobby, `[${user_page} ${requested_username}] | Rank: ${rank.text} (#${rank.rank_nb}) | Elo: ${rank.fancy_elo} | Games played: ${rank.total_scores}`);
- }
- async function start_command(msg, match, lobby) {
- if (lobby.countdown != -1 || lobby.playing) return;
- if (lobby.players.length < 2) {
- await lobby.send(`!mp start .${Math.random().toString(36).substring(2, 6)}`);
- return;
- }
- lobby.countdown = setTimeout(async () => {
- if (lobby.playing) {
- lobby.countdown = -1;
- return;
- }
- lobby.countdown = setTimeout(async () => {
- lobby.countdown = -1;
- if (!lobby.playing) {
- await lobby.send(`!mp start .${Math.random().toString(36).substring(2, 6)}`);
- }
- }, 10000);
- await lobby.send('Starting the match in 10 seconds... Ready up to start sooner.');
- }, 20000);
- await lobby.send('Starting the match in 30 seconds... Ready up to start sooner.');
- }
- async function wait_command(msg, match, lobby) {
- if (lobby.countdown == -1) return;
- clearTimeout(lobby.countdown);
- lobby.countdown = -1;
- await lobby.send('Match auto-start is cancelled. Type !start to restart it.');
- }
- async function about_command(msg, match, lobby) {
- const faq_page = gen_url(lobby?.data?.ruleset, `/faq/`);
- if (lobby) {
- await lobby.send(`In this lobby, you get a rank based on how well you score against other players. More info: ${faq_page}`);
- } else {
- await bancho.privmsg(msg.from, faq_page);
- }
- }
- async function discord_command(msg, match, lobby) {
- await reply(msg.from, lobby, `[${Config.discord_invite_link} Come hang out in voice chat!] (or just text, no pressure)`);
- }
- async function abort_command(msg, match, lobby) {
- if (!lobby.playing) {
- await lobby.send(`${msg.from}: The match has not started, cannot abort.`);
- return;
- }
- if (!lobby.voteaborts.includes(msg.from)) {
- lobby.voteaborts.push(msg.from);
- const nb_voted_to_abort = lobby.voteaborts.length;
- const nb_required_to_abort = Math.ceil(lobby.players.length / 4);
- if (lobby.voteaborts.length >= nb_required_to_abort) {
- await lobby.send(`!mp abort ${Math.random().toString(36).substring(2, 6)}`);
- lobby.voteaborts = [];
- await lobby.select_next_map();
- } else {
- await lobby.send(`${msg.from} voted to abort the match. ${nb_voted_to_abort}/${nb_required_to_abort} votes needed.`);
- }
- }
- }
- async function close_command(msg, match, lobby) {
- lobby.dont_reopen = true;
- await lobby.send(`!mp close ${Math.random().toString(36).substring(2, 6)}`);
- }
- async function ban_command(msg, match, lobby) {
- const bad_player = match[1].trim();
- if (bad_player == '') {
- await lobby.send(msg.from + ': You need to specify which player to ban.');
- return;
- }
- if (!lobby.votekicks[bad_player]) {
- lobby.votekicks[bad_player] = [];
- }
- if (!lobby.votekicks[bad_player].includes(msg.from)) {
- lobby.votekicks[bad_player].push(msg.from);
- const nb_voted_to_kick = lobby.votekicks[bad_player].length;
- let nb_required_to_kick = Math.ceil(lobby.players.length / 2);
- if (nb_required_to_kick == 1) nb_required_to_kick = 2; // don't allow a player to hog the lobby
- if (nb_voted_to_kick >= nb_required_to_kick) {
- await lobby.send('!mp ban ' + bad_player);
- } else {
- await lobby.send(`${msg.from} voted to ban ${bad_player}. ${nb_voted_to_kick}/${nb_required_to_kick} votes needed.`);
- }
- }
- }
- async function skip_command(msg, match, lobby) {
- if (lobby.players.length < 5) {
- await lobby.select_next_map();
- return;
- }
- // Skip map if DMCA'd
- // When bot just joined the lobby, beatmap_id is null.
- if (lobby.beatmap_id && !lobby.map_data) {
- try {
- console.info(`[API] Fetching map data for map ID ${lobby.beatmap_id}`);
- lobby.map_data = await osu_fetch(`https://osu.ppy.sh/api/v2/beatmaps/lookup?id=${lobby.beatmap_id}`);
- if (lobby.map_data.beatmapset.availability.download_disabled) {
- clearTimeout(lobby.countdown);
- lobby.countdown = -1;
- db.prepare(`UPDATE map SET dmca = 1 WHERE map_id = ?`).run(lobby.beatmap_id);
- await lobby.select_next_map();
- await lobby.send(`Skipped previous map because download was unavailable [${lobby.map_data.beatmapset.availability.more_information} (more info)].`);
- return;
- }
- } catch (err) {
- console.error(`Failed to fetch map data for beatmap #${lobby.beatmap_id}: ${err}`);
- }
- }
- // Skip map if player is lobby creator
- let user_is_creator = false;
- for (const player of lobby.players) {
- if (player.irc_username == msg.from) {
- user_is_creator = player.user_id == lobby.data.creator_id;
- break;
- }
- }
- if (user_is_creator) {
- await lobby.select_next_map();
- return;
- }
- // Skip map if player has been in the lobby long enough
- for (const player of lobby.players) {
- if (player.irc_username == msg.from) {
- // Make sure the field is initialized
- if (!player.matches_finished) {
- player.matches_finished = 0;
- }
- if (player.matches_finished >= 5) {
- player.matches_finished = 0;
- await lobby.select_next_map();
- } else {
- await reply(msg.from, lobby, `You need to play ${5 - player.matches_finished} more matches in this lobby before you can skip.`);
- }
- return;
- }
- }
- await reply(msg.from, lobby, `You need to play 5 more matches in this lobby before you can skip.`);
- }
- const commands = [
- {
- regex: /^!about$/i,
- handler: about_command,
- creator_only: false,
- modes: ['pm', 'lobby'],
- },
- {
- regex: /^!info/i,
- handler: about_command,
- creator_only: false,
- modes: ['pm', 'lobby'],
- },
- {
- regex: /^!help$/i,
- handler: about_command,
- creator_only: false,
- modes: ['pm', 'lobby'],
- },
- {
- regex: /^!discord$/i,
- handler: discord_command,
- creator_only: false,
- modes: ['pm', 'lobby'],
- },
- {
- regex: /^!rank(.*)/i,
- handler: rank_command,
- creator_only: false,
- modes: ['pm', 'lobby'],
- },
- {
- regex: /^!abort$/i,
- handler: abort_command,
- creator_only: false,
- modes: ['lobby'],
- },
- {
- regex: /^!close$/i,
- handler: close_command,
- creator_only: true,
- modes: ['lobby'],
- },
- {
- regex: /^!start$/i,
- handler: start_command,
- creator_only: false,
- modes: ['lobby'],
- },
- {
- regex: /^!wait$/i,
- handler: wait_command,
- creator_only: false,
- modes: ['lobby'],
- },
- {
- regex: /^!stop$/i,
- handler: wait_command,
- creator_only: false,
- modes: ['lobby'],
- },
- {
- regex: /^!ban(.*)/i,
- handler: ban_command,
- creator_only: false,
- modes: ['lobby'],
- },
- {
- regex: /^!kick(.*)/i,
- handler: ban_command,
- creator_only: false,
- modes: ['lobby'],
- },
- {
- regex: /^!skip$/i,
- handler: skip_command,
- creator_only: false,
- modes: ['lobby'],
- },
- ];
- export default commands;
|