@bot-shiki/koishi-plugin-werewolf
Version:
Touhou werewolf game
129 lines (128 loc) • 5.22 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const _1 = require(".");
const utils_1 = require("../utils");
class TargetRecord {
count = 0;
latest = 0;
}
class NingenAction extends _1.Action {
target;
isNingen(character) {
if (character.party !== 'ningen')
return false;
if (character.identity !== 'rinnosuke')
return true;
return this.game.seats.filter(c => c.party === 'ningen' && !c.isDead).length <= 1;
}
async action() {
const others = this.game.room.filter((player) => {
const char = this.game.chars.get(player);
return char.party !== 'ningen';
});
const dead = this.game.room.filter((player) => {
const char = this.game.chars.get(player);
return char.party === 'ningen' && char.isDead;
});
utils_1.logger.debug('ningen action');
const tasks = [
others.broadcast((0, utils_1.t)('general.ningen-action')),
dead.broadcast((0, utils_1.t)('ningen.dead')),
];
// TODO
// const rinnosuke = this.getChar('rinnosuke')
tasks.push(this.ningen());
await Promise.all(tasks);
}
async ningen() {
const choices = ['.', '。'];
this.game.seats.forEach((char) => {
char.target = null;
char.voteTime = 0;
});
const ningens = this.game.seats.filter((c, i) => {
const result = this.isNingen(c);
if (!c.isOut)
choices.push(String(i + 1));
return result && !c.isOut;
});
const output = this.game.seats.map((c) => c.render({
disabled: c.isOut,
labels: [
...c.isNingen ? [(0, utils_1.t)('party.ningen')] : [],
],
}));
output.unshift((0, utils_1.t)('ningen.header'));
output.push((0, utils_1.t)('ningen.footer'));
await new Promise((resolve) => {
const disposables = [];
const done = () => {
disposables.forEach(dispose => dispose());
resolve();
};
const updateTarget = () => {
const targets = new Set(ningens.map(c => c.target));
if (targets.size === 1 && !targets.has(null))
done();
};
for (const ningen of ningens) {
ningen.target = null;
ningen.player.allowSpeech = true;
ningen.player.privateSpeech = true;
ningen.player.send((0, utils_1.t)('ningen.hint'));
ningen.player.send(output);
disposables.push(this.game.room.lobby.ctx.middleware(async (session, next) => {
if (!session.isDirect)
return next();
if (session.userId !== ningen.player.userId || session.platform !== ningen.player.platform)
return next();
const content = session.content?.trim().toUpperCase();
if (!choices.includes(content))
return next();
ningen.voteTime = Date.now();
if (['.', '。'].includes(content)) {
utils_1.logger.debug('ningen %s chooses nobody', ningen);
ningen.target = null;
}
else {
ningen.target = this.game.seats[+content - 1];
utils_1.logger.debug('ningen %s chooses %s', ningen, ningen.target);
}
for (const { player } of ningens) {
player.send(ningen.target
? (0, utils_1.t)('ningen.update-1', [ningen.player.name, ningen.target.player.name])
: (0, utils_1.t)('ningen.update-0', [ningen.player.name]));
}
updateTarget();
}, true));
}
disposables.push(this.game.room.lobby.ctx.setTimeout(done, 300000));
});
const map = new Map(this.game.seats.map(c => [c, new TargetRecord()]));
map.set(null, new TargetRecord());
for (const ningen of ningens) {
ningen.player.allowSpeech = false;
ningen.player.privateSpeech = false;
if (!ningen.voteTime)
continue;
const target = map.get(ningen.target);
target.count += 1;
target.latest = Math.max(target.latest, ningen.voteTime);
}
let final = null;
map.forEach((record, char) => {
const finalRecord = map.get(final);
if (record.count < finalRecord.count)
return;
if (record.count > finalRecord.count || record.latest > finalRecord.latest) {
final = char;
}
});
this.target = final;
utils_1.logger.debug('ningen target: %s', final);
if (this.target && this.target !== this.game.mamizou.target) {
this.target.killer = 'ningen';
}
}
}
exports.default = NingenAction;