UNPKG

@bot-shiki/koishi-plugin-werewolf

Version:
231 lines (230 loc) 9.03 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WerewolfGame = void 0; const koishi_1 = require("koishi"); const koishi_plugin_lobby_1 = require("koishi-plugin-lobby"); const utils_1 = require("./utils"); const iku_1 = __importDefault(require("./action/iku")); const yukari_1 = __importDefault(require("./action/yukari")); const remilia_1 = __importDefault(require("./action/remilia")); const mamizou_1 = __importDefault(require("./action/mamizou")); const doremy_1 = __importDefault(require("./action/doremy")); const ningen_1 = __importDefault(require("./action/ningen")); const sage_1 = __importDefault(require("./action/sage")); const exile_1 = __importDefault(require("./action/exile")); const death_1 = __importDefault(require("./action/death")); class WerewolfGame extends koishi_plugin_lobby_1.Game { dayCount = 0; weather = null; seats; chars; winner; iku = new iku_1.default(this); sage = new sage_1.default(this); exile = new exile_1.default(this); death = new death_1.default(this); ningen = new ningen_1.default(this); remilia = new remilia_1.default(this); mamizou = new mamizou_1.default(this); yukari = new yukari_1.default(this); doremy = new doremy_1.default(this); getChar(identity) { return this.seats.find(c => c.identity === identity); } async validate() { if (this.room.size < 6 || this.room.size > 16) { throw new Error('lobby.game.th-werewolf.invalid-size'); } } leave(player) { const char = this.chars.get(player); if (char.isOut) return; char.isOut = true; char.killer = 'offline'; this.check(); } async init() { const [ningenCount, youkaiCount, ...extra] = koishi_1.Random.pick(utils_1.Preset.default[this.room.size]); const identities = [ koishi_1.Random.pick(utils_1.Identity.Ningen.Normal, ningenCount), koishi_1.Random.pick(utils_1.Identity.Youkai.Normal, youkaiCount), ...extra.map(([count, ...options]) => { if (!this.options.weather) { options = options.filter(i => i !== 'iku'); } return koishi_1.Random.pick(options, count); }), ].flat(); const parties = { ningen: [], youkai: [], neutral: [] }; for (const identity of identities) { const party = utils_1.Identity.getParty(identity); parties[party].push(identity); } const output = [(0, utils_1.t)('init.parties')]; for (const party in parties) { if (!parties[party].length) continue; const elements = []; parties[party].forEach((identity, index) => { if (index) elements.push(', '); elements.push((0, utils_1.t)(`character.${identity}.name`)); }); output.push((0, koishi_1.h)('p', [(0, utils_1.t)(`party.${party}`), ': ', ...elements])); } this.seats = []; this.chars = new Map(); await this.room.broadcast(output); const players = Object.values(this.room.players); await Promise.all(players.map(async (player, index) => { const identity = identities[index]; const char = new utils_1.Character(this, player, identity); utils_1.logger.debug('init %s [%s]', char, char.party); this.chars.set(player, char); this.seats.push(char); const output = [ (0, utils_1.t)('init.character', [(0, utils_1.t)(`character.${identity}.name`)]), (0, utils_1.t)('init.party', [(0, utils_1.t)(`party.${char.party}`)]), ]; if (char.isExpert) { output.push((0, utils_1.t)(`character.${identity}.skill`)); } await player.send(output.map(el => (0, koishi_1.h)('p', el))); await player.pause(60000, null, true); })); this.seats = koishi_1.Random.shuffle(this.seats); } async start() { this.room.allowSpeech = false; try { await this.init(); while (true) { await this.dayAction(); await this.iku.action(); await this.remilia.action(); await this.mamizou.action(); await this.ningen.action(); await this.yukari.action(); await this.doremy.action(); await this.sage.action(); await this.nightAction(); await this.death.action(); await this.exile.action(); await this.death.action(); } } catch (e) { if (!this.winner) throw e; } await this.announce(); } isNingenWinner() { const alive = this.seats.filter(c => !c.isDead || c.identity === 'utsuho' && c.killer === 'vote'); if (this.room.size <= 7) { return alive.every(c => c.party === 'ningen'); } else { return alive.every(c => c.party !== 'youkai' || c.isExpert) || alive.every(c => c.party !== 'youkai' || !c.isExpert); } } check() { const alive = this.seats.filter(c => !c.isOut); if (alive.length === 0) { const parsee = this.getChar('parsee'); if (parsee && !parsee.isDead) { parsee.killer = null; this.winner = 'parsee'; } else { this.winner = 'draw'; } } else if (alive.length === 1 && alive[0].identity === 'parsee') { this.winner = 'parsee'; } else if (alive.every(c => c.nightmare || c.identity === 'doremy')) { alive.forEach((char) => { if (char.identity !== 'doremy') { char.killer = 'doremy'; } }); this.winner = 'doremy'; } else if (alive.every(c => c.party !== 'ningen')) { this.winner = 'youkai'; } else if (this.isNingenWinner()) { this.winner = 'ningen'; } if (this.winner) throw new Error('game over'); } async announce() { utils_1.logger.debug('winner:', this.winner); if (this.winner === 'draw') { await this.room.broadcast((0, utils_1.t)('winner.draw')); } else if (this.winner === 'ningen' || this.winner === 'youkai') { await this.room.broadcast((0, utils_1.t)('winner.party', [ (0, utils_1.t)(`party.${this.winner}`), this.seats.filter(c => c.party === this.winner).map(c => c.player.name).join(', '), ])); } else { await this.room.broadcast((0, utils_1.t)('winner.single', [ (0, utils_1.t)(`character.${this.winner}`), this.getChar(this.winner).player.name, ])); } const output = this.seats.map((char) => { const content = [char.player.name, ' ']; if (!char.killer) { content.push((0, utils_1.t)('killer.survive')); } else if (utils_1.Identity.Expert.includes(char.killer)) { content.push((0, utils_1.t)(`character.${char.killer}.name`)); } else { content.push((0, utils_1.t)(`killer.${char.killer}`)); } return (0, koishi_1.h)('p', content); }); output.unshift((0, utils_1.t)('killer.header')); await this.room.broadcast(output); } async dayAction() { this.dayCount += 1; utils_1.logger.debug('day %s', this.dayCount); await this.room.broadcast((0, utils_1.t)('general.day', [this.dayCount])); } async nightAction() { const deaths = this.seats.filter(c => c.killer && !c.isDead); if (deaths.length) { await this.room.broadcast((0, utils_1.t)('general.night-death', [this.dayCount, deaths.map(c => c.player.name).join(', ')])); } else { await this.room.broadcast((0, utils_1.t)('general.night-peace', [this.dayCount])); } } } exports.WerewolfGame = WerewolfGame; class RPSCorridor extends koishi_plugin_lobby_1.Corridor { config; factory = WerewolfGame; constructor(ctx, config) { super(ctx, 'th-werewolf'); this.config = config; ctx.i18n.define('zh-CN', require('./locales/zh-CN')); this.cmd.option('weather', '-W, --no-weather', { fallback: true }); } } (function (RPSCorridor) { RPSCorridor.Config = koishi_1.z.object({}); })(RPSCorridor || (RPSCorridor = {})); exports.default = RPSCorridor;