Commit b3987d60 authored by nanahira's avatar nanahira

first

parent f5165e01
{ {
"name": "koishi-plugin-myplugin", "name": "koishi-plugin-dicex",
"description": "一个 Koishi 插件", "description": "Koishi 骰娘插件 +1",
"version": "1.0.0", "version": "1.0.0",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://code.mycard.moe/3rdeye/koishi-plugin-myplugin.git" "url": "https://code.mycard.moe/3rdeye/koishi-plugin-dicex.git"
}, },
"author": "Nanahira <nanahira@momobako.com>", "author": "Nanahira <nanahira@momobako.com>",
"license": "MIT", "license": "MIT",
...@@ -18,12 +18,15 @@ ...@@ -18,12 +18,15 @@
"Koishi.js", "Koishi.js",
"qqbot", "qqbot",
"cqhttp", "cqhttp",
"onebot" "onebot",
"dice",
"dicebot",
"optional:database"
], ],
"bugs": { "bugs": {
"url": "https://code.mycard.moe/3rdeye/koishi-plugin-myplugin/issues" "url": "https://code.mycard.moe/3rdeye/koishi-plugin-dicex/issues"
}, },
"homepage": "https://code.mycard.moe/3rdeye/koishi-plugin-myplugin", "homepage": "https://code.mycard.moe/3rdeye/koishi-plugin-dicex",
"peerDependencies": { "peerDependencies": {
"koishi": "^4.0.0-rc.0" "koishi": "^4.0.0-rc.0"
}, },
......
import 'source-map-support/register'; import 'source-map-support/register';
import { Context, NextFunction, Random, Session } from 'koishi'; import { Channel, Context, NextFunction, Random, Session } from 'koishi';
import { DicePluginConfig, DicePluginConfigLike } from './config'; import { DicePluginConfig, DicePluginConfigLike } from './config';
import { import {
KoishiPlugin, CommandAlias,
InjectConfig,
UseCommand,
CommandShortcut,
CommandUserFields,
CommandExample, CommandExample,
PutSession, CommandShortcut,
Inject,
InjectConfig,
KoishiPlugin,
OnApply,
PutArg, PutArg,
PutChannel,
PutUserName,
UseCommand,
UseMiddleware, UseMiddleware,
} from 'koishi-thirdeye'; } from 'koishi-thirdeye';
import { DiceDbModule } from './modules/db';
import { RcResult, RcRuleList } from './utility/rc-rules';
export * from './config'; export * from './config';
declare module 'koishi' { declare module 'koishi' {
interface Modules { interface Modules {
dicex: typeof import('.'); dicex: typeof import('.');
} }
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Context {
interface Services {
dicexDb: DiceDbModule;
}
}
} }
const regexp = /^((\d*)d)?(\d+)(\+((\d*)d)?(\d+))*$/i; const rollRegexp = /^((\d*)d)?(\d+)(\+((\d*)d)?(\d+))*$/i;
const rcRegexp = /^[ac](\d{1,3})( +[^ ].*)?$/i;
@KoishiPlugin({ name: 'dicex', schema: DicePluginConfig }) @KoishiPlugin({ name: 'dicex', schema: DicePluginConfig })
export default class DicePlugin { export default class DicePlugin implements OnApply {
constructor(private ctx: Context, config: DicePluginConfigLike) {} constructor(private ctx: Context, config: DicePluginConfigLike) {}
@InjectConfig() @InjectConfig()
private config: DicePluginConfig; private config: DicePluginConfig;
@UseCommand('roll [expr:string]', '掷骰') @Inject('dicexDb')
private db: DiceDbModule;
@UseCommand('dice', '骰子指令', { empty: true })
// eslint-disable-next-line @typescript-eslint/no-empty-function
diceCommand() {}
@UseCommand('dice/roll [expr:string]', '掷骰')
@CommandShortcut('掷骰', { fuzzy: true }) @CommandShortcut('掷骰', { fuzzy: true })
@CommandUserFields(['name', 'timers'])
@CommandExample('roll 2d6+d10') @CommandExample('roll 2d6+d10')
onRoll(@PutSession() session: Session, @PutArg(0) message = '1d6') { onRoll(@PutUserName(true) username: string, @PutArg(0) message = '1d6') {
if (!regexp.test(message)) return '表达式语法错误。'; if (!rollRegexp.test(message)) return '表达式语法错误。';
const { maxPoint = 1 << 16, maxTimes = 64 } = this.config; const { maxPoint = 1 << 16, maxTimes = 64 } = this.config;
const expressions = message.split('+'); const expressions = message.split('+');
let hasMultiple = false; let hasMultiple = false;
let output = `${session.username} 掷骰:${message}=`; let output = `${username} 掷骰:${message}=`;
let total = 0; let total = 0;
for (const expr of expressions) { for (const expr of expressions) {
...@@ -84,12 +103,59 @@ export default class DicePlugin { ...@@ -84,12 +103,59 @@ export default class DicePlugin {
return output; return output;
} }
private getRcRule(channel: Channel) {
const index = channel?.diceRcMode || 0;
return RcRuleList[index];
}
@UseCommand('dice/rc <rate:integer> [reason:string]', '检定')
@CommandAlias('ra')
@CommandShortcut('检定', { fuzzy: true })
@CommandExample('rc 20 潜行')
onRc(
@PutUserName(true) username: string,
@PutArg(0) rate: number,
@PutArg(1) reason: string,
@PutChannel(['diceRcMode']) channel: Channel,
) {
if (!rate || rate < 0 || rate > 100) {
return '成功率必须在 0 到 100 之间。';
}
const rule = this.getRcRule(channel);
const value = Random.int(1, 101);
const result = rule.check(rate, value);
const resultText =
result === RcResult.BigFailure
? '大失败!'
: result === RcResult.Failure
? '失败'
: result === RcResult.Success
? '成功'
: '大成功!';
return `${username}${
reason ? `要${reason},开始` : ''
}进行检定:D100=${value}/${rate} ${resultText}`;
}
@UseMiddleware() @UseMiddleware()
onRollCompat(session: Session, next: NextFunction) { onRollCompat(session: Session, next: NextFunction) {
const { content, prefix } = session.parsed; const { content, prefix } = session.parsed;
if (!prefix || content[0] !== 'r') return next(); if (!prefix || content[0] !== 'r') return next();
const expr = content.slice(1); const expr = content.slice(1);
if (!regexp.test(expr)) return next(); if (rollRegexp.test(expr)) {
return session.execute({ name: 'roll', args: [expr] }); return session.execute({ name: 'roll', args: [expr] });
}
if (rcRegexp.test(expr)) {
const matching = expr.match(rcRegexp);
return session.execute({
name: 'rc',
args: [matching[1], ...(matching[2] ? [matching[2].trim()] : [])],
});
}
return next();
}
onApply() {
this.ctx.plugin(DiceDbModule, this.config);
} }
} }
import {
CommandExample,
CommandUsage,
Inject,
InjectConfig,
InjectLogger,
KoishiPlugin,
OnApply,
OnChannel,
Provide,
PutChannel,
PutOption,
UseCommand,
} from 'koishi-thirdeye';
import { DicePluginConfig } from '../config';
import { Channel, Context, Database, Logger, Model } from 'koishi';
import { RcRuleList } from '../utility/rc-rules';
declare module 'koishi' {
interface Channel {
diceRcMode: number;
}
}
@Provide('dicexDb')
@KoishiPlugin({ name: 'dicex-db', schema: DicePluginConfig })
export class DiceDbModule implements OnApply {
constructor(private ctx: Context, config: DicePluginConfig) {}
@InjectConfig()
private config: DicePluginConfig;
@Inject(true)
private database: Database;
@Inject(true)
private model: Model;
@InjectLogger('dicex-db')
private logger: Logger;
onApply() {
this.model.extend('channel', {
diceRcMode: { type: 'integer', initial: 0 },
});
this.logger.info(`Dice database module loaded.`);
}
@OnChannel()
@UseCommand('dice/rcmode', '设置检点规则')
@CommandUsage(
`默认规则为0,规则序号如下:\n\n${RcRuleList.map(
(rule, index) => `${index}\n${rule.text}\n`,
).join('\n')}`,
)
@CommandExample('rcmode -s 1 设置当前频道的检点规则为1。')
fetchRcMode(
@PutChannel(['diceRcMode']) channel: Channel,
@PutOption('set', '-s <rule:integer> 设置规则') setRule: number,
) {
if (setRule == null) {
return `当前频道的检点规则如下:\n\n${
RcRuleList[channel.diceRcMode].text
}`;
}
if (setRule < 0 || setRule >= RcRuleList.length) {
return '规则序号不合法';
}
channel.diceRcMode = setRule;
return `已设置当前频道的检点规则为${setRule}。`;
}
}
export enum RcResult {
BigSuccess = 1,
Success = 2,
Failure = 3,
BigFailure = 4,
}
export class RcRule {
text: string;
check(rate: number, value: number): RcResult {
return value <= rate ? RcResult.Success : RcResult.Failure;
}
}
export class RcRule0 extends RcRule {
text = '出1大成功\n不满50出96-100大失败,满50出100大失败';
check(rate: number, value: number): RcResult {
if (value <= 1) {
return RcResult.BigSuccess;
}
const res = super.check(rate, value);
if (
res === RcResult.Failure &&
((rate < 50 && value >= 96) || (rate >= 50 && value >= 100))
) {
return RcResult.BigFailure;
}
return res;
}
}
export class RcRule1 extends RcRule {
text =
'不满50出1大成功,满50出1-5大成功\n不满50出96-100大失败,满50出100大失败';
check(rate: number, value: number): RcResult {
const res = super.check(rate, value);
if (res === RcResult.Success) {
if ((rate < 50 && value <= 1) || (rate >= 50 && value <= 5)) {
return RcResult.BigSuccess;
}
} else {
if (
((rate < 50 && value >= 96) || (rate >= 50 && value >= 100)) &&
res === RcResult.Failure
) {
return RcResult.BigFailure;
}
}
return res;
}
}
export class RcRule2 extends RcRule {
text = '出1-5且<=成功率大成功\n出100或出96-99且>成功率大失败';
check(rate: number, value: number): RcResult {
const res = super.check(rate, value);
if (res === RcResult.Success) {
if (value <= 5) {
return RcResult.BigSuccess;
}
} else {
if (value >= 96) {
return RcResult.BigFailure;
}
}
return res;
}
}
export class RcRule3 extends RcRule {
text = '出1-5大成功\n出96-100大失败';
check(rate: number, value: number): RcResult {
if (value <= 5) {
return RcResult.BigSuccess;
}
if (value >= 96) {
return RcResult.BigFailure;
}
return super.check(rate, value);
}
}
export class RcRule4 extends RcRule {
text =
'出1-5且<=十分之一大成功\\n不满50出>=96+十分之一大失败,满50出100大失败';
check(rate: number, value: number): RcResult {
const res = super.check(rate, value);
if (res === RcResult.Success) {
if (value <= 5 && value <= rate / 10) {
return RcResult.BigSuccess;
}
} else {
if (
(rate < 50 && value >= 96 + rate / 10) ||
(rate >= 50 && value >= 100)
) {
return RcResult.BigFailure;
}
}
return res;
}
}
export class RcRule5 extends RcRule {
text = '出1-2且<五分之一大成功\\n不满50出96-100大失败,满50出99-100大失败';
check(rate: number, value: number): RcResult {
const res = super.check(rate, value);
if (res === RcResult.Success) {
if (value <= 2 && value <= rate / 5) {
return RcResult.BigSuccess;
}
} else {
if (
(rate < 50 && value >= 96) ||
(rate >= 50 && value >= 99 && value <= 100)
) {
return RcResult.BigFailure;
}
}
return res;
}
}
export const RcRuleList: RcRule[] = [
new RcRule0(),
new RcRule1(),
new RcRule2(),
new RcRule3(),
new RcRule4(),
new RcRule5(),
];
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment