mirror of
https://github.com/arthur-pbty/xiao.git
synced 2026-06-03 15:07:42 +02:00
Mafia Command
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,86 @@
|
||||
const Command = require('../../structures/Command');
|
||||
const Game = require('../../structures/mafia/Game');
|
||||
const { verify } = require('../../util/Util');
|
||||
const storyCount = 21;
|
||||
|
||||
module.exports = class MafiaCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'mafia',
|
||||
group: 'mafia',
|
||||
memberName: 'mafia',
|
||||
description: 'Who is the Mafia? Who is the detective? Will the Mafia kill them all?',
|
||||
guildOnly: true
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
const current = this.client.games.get(msg.channel.id);
|
||||
if (current) return msg.reply(`Please wait until the current game of \`${current.name}\` is finished.`);
|
||||
const connection = this.client.voice.connections.get(msg.guild.id);
|
||||
if (!connection) {
|
||||
const usage = this.client.registry.commands.get('join').usage();
|
||||
return msg.reply(`I am not in a voice channel. Use ${usage} to fix that!`);
|
||||
}
|
||||
for (const member of connection.channel.members.values()) await msg.guild.members.fetch(member.id);
|
||||
if (connection.channel.members.size > 16) return msg.reply('Please do not have more than 15 players.');
|
||||
if (connection.channel.members.size < 7) return msg.reply('Please have at least 5 players before starting.');
|
||||
const game = new Game(this.client, msg.channel, connection);
|
||||
this.client.games.set(msg.channel.id, game);
|
||||
try {
|
||||
await game.generate(connection.channel.members.filter(m => !m.user.bot).map(m => m.user));
|
||||
await game.playAudio('init');
|
||||
await game.playAudio('rule-ask');
|
||||
await msg.say('Type `yes` to hear a rule explanation.');
|
||||
const rules = await verify(msg.channel, msg.author);
|
||||
if (rules) await game.playAudio('rules');
|
||||
while (!game.shouldEnd) {
|
||||
let killed = null;
|
||||
await game.playAudio(`night-${game.turn}`);
|
||||
await game.playAudio('mafia');
|
||||
const mafia = game.players.filter(p => p.role === 'mafia');
|
||||
const choices = await Promise.all(mafia.map(player => player.dmRound()));
|
||||
const randomizer = choices.filter(c => c !== null);
|
||||
if (randomizer.length) killed = game.players.get(randomizer[Math.floor(Math.random() * randomizer.length)]);
|
||||
await game.playAudio('mafia-decision-made');
|
||||
const detective = game.players.find(p => p.role === 'detective');
|
||||
if (detective) {
|
||||
await game.playAudio('detective');
|
||||
await detective.dmRound();
|
||||
await game.playAudio('detective-decision-made');
|
||||
}
|
||||
await game.playAudio(`day-${game.turn}`);
|
||||
if (killed) {
|
||||
const story = Math.floor(Math.random() * storyCount) + 1;
|
||||
await game.playAudio(`story-${story}`);
|
||||
await game.playAudio('reveal-deceased');
|
||||
await msg.say(`Deceased: **${killed}**`);
|
||||
game.players.delete(killed.id);
|
||||
} else {
|
||||
await game.playAudio('no-deceased');
|
||||
}
|
||||
await game.playAudio('vote');
|
||||
const playersArr = Array.from(game.players.values());
|
||||
const votes = await game.getVotes(playersArr);
|
||||
if (!votes) {
|
||||
await game.playAudio('no-votes');
|
||||
continue;
|
||||
}
|
||||
const hanged = game.getHanged(votes, playersArr);
|
||||
await game.playAudio('hanged');
|
||||
await msg.say(`Hanged: **${hanged.user}**`);
|
||||
game.players.delete(hanged.id);
|
||||
++game.turn;
|
||||
}
|
||||
const mafia = game.players.find(p => p.role === 'mafia');
|
||||
if (mafia) await game.playAudio('mafia-wins');
|
||||
else await game.playAudio('mafia-loses');
|
||||
await game.playAudio('credits');
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return null;
|
||||
} catch (err) {
|
||||
this.client.games.delete(msg.channel.id);
|
||||
return msg.reply(`Oh no, an error occurred: \`${err.message}\`. Try again later!`);
|
||||
}
|
||||
}
|
||||
};
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xiao",
|
||||
"version": "132.5.0",
|
||||
"version": "132.6.0",
|
||||
"description": "Your personal server companion.",
|
||||
"main": "Xiao.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
const Collection = require('@discordjs/collection');
|
||||
const path = require('path');
|
||||
const { stripIndents } = require('common-tags');
|
||||
const Player = require('./Player');
|
||||
const { shuffle } = require('../../util/Util');
|
||||
const { SUCCESS_EMOJI_ID } = process.env;
|
||||
|
||||
module.exports = class Game {
|
||||
constructor(client, channel, connection) {
|
||||
Object.defineProperty(this, 'client', { value: client });
|
||||
|
||||
this.name = 'mafia';
|
||||
this.players = new Collection();
|
||||
this.channel = channel;
|
||||
this.connection = connection;
|
||||
this.turn = 1;
|
||||
}
|
||||
|
||||
determineRoles(playerCount) {
|
||||
const roles = ['detective', 'mafia', 'mafia'];
|
||||
for (let i = 0; i < (playerCount - 3); i++) roles.push('innocent');
|
||||
return shuffle(roles);
|
||||
}
|
||||
|
||||
async generate(list) {
|
||||
const roles = this.determineRoles(list.length);
|
||||
let i = 0;
|
||||
for (const user of list) {
|
||||
try {
|
||||
await user.send(`You are ${roles[i] === 'detective' ? 'the' : 'a part of the'} **${roles[i]}**.`);
|
||||
} catch (err) {
|
||||
await this.channel.send(
|
||||
`${user}, I couldn't send a DM to you. Please open your DMs and use the \`me\` command to see your role.`
|
||||
);
|
||||
}
|
||||
const player = new Player(this, user, roles[i]);
|
||||
this.players.set(user.id, player);
|
||||
i++;
|
||||
}
|
||||
return this.players;
|
||||
}
|
||||
|
||||
playAudio(id) {
|
||||
this.dispatcher = this.connection.play(
|
||||
path.join(__dirname, '..', '..', 'assets', 'sounds', 'mafia', `${id}.mp3`), { volume: 2 }
|
||||
);
|
||||
return new Promise((res, rej) => {
|
||||
this.dispatcher.once('finish', () => {
|
||||
this.dispatcher = null;
|
||||
return res(true);
|
||||
});
|
||||
this.dispatcher.once('error', err => {
|
||||
this.dispatcher = null;
|
||||
return rej(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async getVotes(playersArr) {
|
||||
await this.channel.send(stripIndents`
|
||||
Who do you think is a Mafia member? Please type the number.
|
||||
${playersArr.map((p, i) => `**${i + 1}.** ${p.user.tag}`).join('\n')}
|
||||
`);
|
||||
const voted = [];
|
||||
const filter = res => {
|
||||
if (!this.players.some(p => p.user.id === res.author.id)) return false;
|
||||
if (voted.includes(res.author.id)) return false;
|
||||
if (!playersArr[Number.parseInt(res.content, 10) - 1]) return false;
|
||||
voted.push(res.author.id);
|
||||
res.react(SUCCESS_EMOJI_ID || '✅').catch(() => null);
|
||||
return true;
|
||||
};
|
||||
const votes = await this.channel.awaitMessages(filter, {
|
||||
max: this.players.size,
|
||||
time: 90000
|
||||
});
|
||||
if (!votes.size) return null;
|
||||
return votes;
|
||||
}
|
||||
|
||||
getHanged(votes, playersArr) {
|
||||
const counts = new Collection();
|
||||
for (const vote of votes.values()) {
|
||||
const player = this.players.get(playersArr[Number.parseInt(vote.content, 10) - 1].id);
|
||||
if (counts.has(player.id)) {
|
||||
++counts.get(player.id).votes;
|
||||
} else {
|
||||
counts.set(player.id, {
|
||||
id: player.id,
|
||||
votes: 1,
|
||||
user: player.user
|
||||
});
|
||||
}
|
||||
}
|
||||
return counts.sort((a, b) => b.votes - a.votes).first();
|
||||
}
|
||||
|
||||
get shouldEnd() {
|
||||
return this.players.size < 4 && !this.players.some(p => p.role === 'mafia');
|
||||
}
|
||||
|
||||
get voiceChannel() {
|
||||
return this.connection.channel;
|
||||
}
|
||||
|
||||
get dispatcher() {
|
||||
return this.client.dispatchers.get(this.channel.guild.id);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
const { stripIndents } = require('common-tags');
|
||||
const questions = {
|
||||
mafia: 'Who would you like to kill?',
|
||||
detective: 'Who do you think is a Mafia member?'
|
||||
};
|
||||
|
||||
module.exports = class Player {
|
||||
constructor(game, user, role) {
|
||||
this.game = game;
|
||||
this.user = user;
|
||||
this.id = user.id;
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.user.toString();
|
||||
}
|
||||
|
||||
async dmRound() {
|
||||
const valid = Array.from(this.game.players.filter(p => p.role !== this.role).values());
|
||||
await this.user.send(stripIndents`
|
||||
${questions[this.role]} Please type the number.
|
||||
${valid.map((p, i) => `**${i + 1}.** ${p.user.tag}`).join('\n')}
|
||||
`);
|
||||
const filter = res => valid[Number.parseInt(res.content, 10) - 1];
|
||||
const decision = await this.user.dmChannel.awaitMessages(filter, {
|
||||
max: 1,
|
||||
time: 120000
|
||||
});
|
||||
if (!decision.size) {
|
||||
await this.user.send('Sorry, time is up!');
|
||||
return null;
|
||||
}
|
||||
const choice = valid[Number.parseInt(decision.first().content, 10) - 1].id;
|
||||
if (this.role === 'detective') {
|
||||
const isMafia = this.game.players.get(choice).role === 'mafia';
|
||||
await this.user.send(isMafia ? 'Yes, they are a Mafioso.' : 'No, they are not a Mafioso.');
|
||||
} else {
|
||||
await this.user.send(`**${this.game.players.get(choice).user.tag}** is your choice...`);
|
||||
}
|
||||
return choice;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user