Among us用のDiscordボットを作った話


概要

最近Among usを友達とやるようになり、AutoMuteUsというとても便利なボットの存在を知りました。
しかし、このボットはWindows PCにSteam版のAmong usを入れないと使えないものでした。
Macしか持っていなくても、せめて会議ごとに全員のミュート状態を操作できるようにしたい!と思いました。
絶対誰か作ってるでしょと思って検索してもなかなか出てこなかったので作ってみました!
開発時間は3時間ほどでした。

最終的なコードはこちらです:https://glitch.com/edit/#!/amongus-mute

ボットの使い方

AmongUsMuteBotの使い方
0. もしbotがオフラインだったらglitchのプロジェクトに一回アクセス
1. 全員ボイスチャンネルに入った状態で!start
2. タスクやる時間の時に!ship(生きてる人がマイクとスピーカーがオフされて死人はオンになる)
3. 会議の時に!meeting(生きてる人のマイクとスピーカーがオンになり死人のマイクがオフになる)
4. 会議の時、新たに死人が発見されたら!dead @メンション(その人のマイクがオフになる。このコマンドは1人づつやってください)
5. ゲーム終了時に!end

作業の概要

  1. https://note.com/bami55/n/ncc3a68652697 を参考にボットの作成とGlitchのプロジェクトのセットアップをしました。
  2. その後ボット用のコードを追加していきました。

コード

いくつかコードを紹介していきます。

まず、生存者と死者を格納する配列を作りました:

var alives = [];
var deads = [];

次にメッセージを受け取った時にコマンドかどうかを判断し、コマンドと引数を格納します:

  const prefix = "!"
  if (!message.content.startsWith(prefix) || message.author.bot) return;

  const args = message.content.slice(prefix.length).trim().split(/ +/);
  const command = args.shift().toLowerCase();

その後コマンドの名前によって呼び出す関数を変えていきました。
例えば、Discordで!meetingとメッセージを送ると、command == "meeting"となります。
その場合、生存者のマイクとスピーカーをオンにして、死者のマイクをオフにする関数を呼び出します。

!dead @メンションでは、メンションされた人をdeads配列に追加しalives配列から削除します:

      if (args[0]) {
        const user = getUserFromMention(message, args[0]);
        setDeads(user);
      }
      muteDeads();
      return;

getUserFromMention()Discordのドキュメントを参考にしました。
ドキュメントから変更したのは、最後のreturnのところです:

function getUserFromMention(message, mention) {
    ...
    // return client.users.cache.get(mention); ここを以下に変更
    return message.guild.members.cache.find(member => member.user === client.users.cache.get(mention));
    }
}

元のコードではUserを返していましたが、GuildMemberを返すようにしました。
ここで躓いて1時間ほど溶かしました...

マイクとスピーカーののオンオフはそれぞれsetMutesetDeafでできます:

  alives.forEach((x) => {
    x.voice.setMute(false).catch(err => console.log(err));
    x.voice.setDeaf(false).catch(err => console.log(err));
  });

truefalseにするとオンになります。

function getUserFromMention(message, mention) {
    if (!mention) return;

    if (mention.startsWith('<@') && mention.endsWith('>')) {
        mention = mention.slice(2, -1);

        if (mention.startsWith('!')) {
            mention = mention.slice(1);
        }

    return message.guild.members.cache.find(member => member.user === client.users.cache.get(mention));
    }
}

終わりに

ゲーム中にコマンドを打たなくちゃいけないのは若干めんどくさいかもしれませんが、死者がボイスチャットを移動することなく会話できるのは便利かなと思っています。
Javascriptに詳しくないことを言い訳にあまり綺麗なコードはかけていないので、時間があればリファクタリングしていきたいです。