koishi-plugin-hangman
Version:
Hangman game in Koishi
127 lines (126 loc) • 5.28 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.apply = exports.Config = exports.name = void 0;
const koishi_1 = require("koishi");
const path_1 = require("path");
exports.name = 'hangman';
exports.Config = koishi_1.Schema.object({
chances: koishi_1.Schema.number().default(10).description('允许猜测的最大次数。'),
wordList: koishi_1.Schema.string().description('存储单词表的文件路径。').hidden(process.env.KOISHI_ENV === 'browser'),
submission: koishi_1.Schema.union([
koishi_1.Schema.const('strict').description('只接受指令输入'),
koishi_1.Schema.const('loose').description('允许直接输入答案文本'),
koishi_1.Schema.const('mention').description('仅在私聊或被提及时接受直接输入'),
]).role('radio').description('答案提交方式。').default('mention'),
});
function Word(word) {
if (typeof word !== 'string')
return word;
return { text: word };
}
function apply(ctx, config) {
function getWordList() {
if (process.env.KOISHI_ENV === 'browser' || !config.wordList) {
return require('../words.json');
}
else {
const filename = (0, path_1.resolve)(ctx.baseDir, config.wordList);
return require(filename);
}
}
const wordList = getWordList();
const stages = Object.create(null);
ctx.i18n.define('zh-CN', require('./locales/zh-CN'));
ctx.middleware(async (session, next) => {
const state = stages[session.cid];
if (!state || config.submission === 'strict')
return next();
const { content, atSelf } = session.stripped;
if (!session.isDirect && !atSelf && config.submission !== 'loose')
return next();
if (!/^[a-z]+$/i.test(content))
return next();
return session.execute({
name: 'hangman',
args: [content],
});
});
ctx.command('hangman [letter:string]')
.alias('hang')
.alias('吊死鬼')
.option('quit', '-q', { notUsage: true })
.action(async ({ session, options }, letters = '') => {
const id = session.cid;
if (!stages[id]) {
if (letters.length || options.quit) {
return session.text('.idle');
}
const word = Word(koishi_1.Random.pick(wordList));
const current = '?'.repeat(word.text.length);
stages[id] = { ...word, current, history: '', chances: config.chances };
const output = [session.text('.start', [current])];
ctx.emit(session, 'hangman/start', stages[id], output);
return output.join('\n');
}
const { chances: _chances, history: _history, text } = stages[id];
if (options.quit) {
const output = [session.text('.stop')];
ctx.emit(session, 'hangman/stop', stages[id], output);
delete stages[id];
return output.join('\n');
}
if (!letters.length) {
if (_history) {
return session.text('.history', stages[id]);
}
else {
return session.text('.history-clean', stages[id]);
}
}
for (const letter of letters.toLowerCase()) {
if (letter < 'a' || letter > 'z' || stages[id].history.includes(letter))
continue;
const history = stages[id].history += letter;
if (text.includes(letter)) {
const current = stages[id].current = text.split('').map(c => history.includes(c) ? c : '?').join('');
if (current === text) {
const answer = session.text('.answer', stages[id]);
const output = [session.text('.win', [answer, session.username])];
delete stages[id];
ctx.emit(session, 'hangman/win', stages[id], output);
return output.join('\n');
}
}
else {
if (!(stages[id].chances -= 1)) {
const answer = session.text('.answer', stages[id]);
const output = [session.text('.lose', [answer, session.username])];
delete stages[id];
ctx.emit(session, 'hangman/lose', stages[id], output);
return output.join('\n');
}
}
}
const { chances, history } = stages[id];
const charCount = history.length - _history.length;
if (!charCount) {
if (letters.match(/[a-zA-Z]/)) {
return session.text('.char-used');
}
else {
return session.text('.char-invalid');
}
}
if (_chances - chances === charCount) {
const output = [session.text('.wrong', stages[id])];
ctx.emit(session, 'hangman/wrong', stages[id], output);
return output.join('\n');
}
else {
const output = [session.text('.right', stages[id])];
ctx.emit(session, 'hangman/right', stages[id], output);
return output.join('\n');
}
});
}
exports.apply = apply;