diff --git a/src/index.ts b/src/index.ts index 92cee26..7ad61cc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,7 @@ import config from './config'; import _log from './utils/log'; import CoreModule from './modules/core'; +import TalkModule from './modules/talk'; import BirthdayModule from './modules/birthday'; import ReversiModule from './modules/reversi'; import PingModule from './modules/ping'; @@ -58,6 +59,7 @@ promiseRetry(retry => { // 藍起動 new 藍(account, [ + new CoreModule(), new EmojiModule(), new EmojiReactModule(), new FortuneModule(), @@ -66,7 +68,7 @@ promiseRetry(retry => { new ReversiModule(), new TimerModule(), new DiceModule(), - new CoreModule(), + new TalkModule(), new PingModule(), new WelcomeModule(), new ServerModule(), diff --git a/src/modules/core/index.ts b/src/modules/core/index.ts index 4f147e8..25ec82d 100644 --- a/src/modules/core/index.ts +++ b/src/modules/core/index.ts @@ -1,9 +1,7 @@ import autobind from 'autobind-decorator'; -import { HandlerResult } from '../../ai'; import Module from '../../module'; import Message from '../../message'; -import serifs, { getSerif } from '../../serifs'; -import getDate from '../../utils/get-date'; +import serifs from '../../serifs'; const titles = ['さん', 'くん', '君', 'ちゃん', '様', '先生']; @@ -27,21 +25,7 @@ export default class extends Module { return ( this.transferBegin(msg) || this.transferEnd(msg) || - this.setName(msg) || - this.greet(msg) || - this.erait(msg) || - this.omedeto(msg) || - this.nadenade(msg) || - this.kawaii(msg) || - this.suki(msg) || - this.hug(msg) || - this.humu(msg) || - this.batou(msg) || - this.itai(msg) || - this.ote(msg) || - this.ponkotu(msg) || - this.rmrf(msg) || - this.shutdown(msg) + this.setName(msg) ); } @@ -123,300 +107,6 @@ export default class extends Module { return true; } - @autobind - private greet(msg: Message): boolean { - if (msg.text == null) return false; - - const incLove = () => { - //#region 1日に1回だけ親愛度を上げる - const today = getDate(); - - const data = msg.friend.getPerModulesData(this); - - if (data.lastGreetedAt == today) return; - - data.lastGreetedAt = today; - msg.friend.setPerModulesData(this, data); - - msg.friend.incLove(); - //#endregion - }; - - // 末尾のエクスクラメーションマーク - const tension = (msg.text.match(/[!!]{2,}/g) || ['']) - .sort((a, b) => a.length < b.length ? 1 : -1)[0] - .substr(1); - - if (msg.includes(['こんにちは', 'こんにちわ'])) { - msg.reply(serifs.core.hello(msg.friend.name)); - incLove(); - return true; - } - - if (msg.includes(['こんばんは', 'こんばんわ'])) { - msg.reply(serifs.core.helloNight(msg.friend.name)); - incLove(); - return true; - } - - if (msg.includes(['おは', 'おっは', 'お早う'])) { - msg.reply(serifs.core.goodMorning(tension, msg.friend.name)); - incLove(); - return true; - } - - if (msg.includes(['おやすみ', 'お休み'])) { - msg.reply(serifs.core.goodNight(msg.friend.name)); - incLove(); - return true; - } - - if (msg.includes(['行ってくる', '行ってきます', 'いってくる', 'いってきます'])) { - msg.reply( - msg.friend.love >= 7 - ? serifs.core.itterassyai.love(msg.friend.name) - : serifs.core.itterassyai.normal(msg.friend.name)); - incLove(); - return true; - } - - if (msg.includes(['ただいま'])) { - msg.reply( - msg.friend.love >= 15 ? serifs.core.okaeri.love2(msg.friend.name) : - msg.friend.love >= 7 ? getSerif(serifs.core.okaeri.love(msg.friend.name)) : - serifs.core.okaeri.normal(msg.friend.name)); - incLove(); - return true; - } - - return false; - } - - @autobind - private erait(msg: Message): boolean { - const match = msg.extractedText.match(/(.+?)た(から|ので)(褒|ほ)めて/); - if (match) { - msg.reply(getSerif(serifs.core.erait.specify(match[1], msg.friend.name))); - return true; - } - - const match2 = msg.extractedText.match(/(.+?)る(から|ので)(褒|ほ)めて/); - if (match2) { - msg.reply(getSerif(serifs.core.erait.specify(match2[1], msg.friend.name))); - return true; - } - - const match3 = msg.extractedText.match(/(.+?)だから(褒|ほ)めて/); - if (match3) { - msg.reply(getSerif(serifs.core.erait.specify(match3[1], msg.friend.name))); - return true; - } - - if (!msg.includes(['褒めて', 'ほめて'])) return false; - - msg.reply(getSerif(serifs.core.erait.general(msg.friend.name))); - - return true; - } - - @autobind - private omedeto(msg: Message): boolean { - if (!msg.includes(['おめでと'])) return false; - - msg.reply(serifs.core.omedeto(msg.friend.name)); - - return true; - } - - @autobind - private nadenade(msg: Message): boolean { - if (!msg.includes(['なでなで'])) return false; - - // メッセージのみ - if (!msg.isDm) return true; - - //#region 1日に1回だけ親愛度を上げる(嫌われてない場合のみ) - if (msg.friend.love >= 0) { - const today = getDate(); - - const data = msg.friend.getPerModulesData(this); - - if (data.lastNadenadeAt != today) { - data.lastNadenadeAt = today; - msg.friend.setPerModulesData(this, data); - - msg.friend.incLove(); - } - } - //#endregion - - msg.reply(getSerif( - msg.friend.love >= 10 ? serifs.core.nadenade.love3 : - msg.friend.love >= 5 ? serifs.core.nadenade.love2 : - msg.friend.love <= -15 ? serifs.core.nadenade.hate4 : - msg.friend.love <= -10 ? serifs.core.nadenade.hate3 : - msg.friend.love <= -5 ? serifs.core.nadenade.hate2 : - msg.friend.love <= -1 ? serifs.core.nadenade.hate1 : - serifs.core.nadenade.normal - )); - - return true; - } - - @autobind - private kawaii(msg: Message): boolean { - if (!msg.includes(['かわいい', '可愛い'])) return false; - - // メッセージのみ - if (!msg.isDm) return true; - - msg.reply(getSerif( - msg.friend.love >= 5 ? serifs.core.kawaii.love : - msg.friend.love <= -3 ? serifs.core.kawaii.hate : - serifs.core.kawaii.normal)); - - return true; - } - - @autobind - private suki(msg: Message): boolean { - if (!msg.or(['好き', 'すき'])) return false; - - // メッセージのみ - if (!msg.isDm) return true; - - msg.reply( - msg.friend.love >= 5 ? (msg.friend.name ? serifs.core.suki.love(msg.friend.name) : serifs.core.suki.normal) : - msg.friend.love <= -3 ? serifs.core.suki.hate : - serifs.core.suki.normal); - - return true; - } - - @autobind - private hug(msg: Message): boolean { - if (!msg.or(['ぎゅ', 'むぎゅ', /^はぐ(し(て|よ|よう)?)?$/])) return false; - - // メッセージのみ - if (!msg.isDm) return true; - - //#region 前のハグから1分経ってない場合は返信しない - // これは、「ハグ」と言って「ぎゅー」と返信したとき、相手が - // それに対してさらに「ぎゅー」と返信するケースがあったため。 - // そうするとその「ぎゅー」に対してもマッチするため、また - // 藍がそれに返信してしまうことになり、少し不自然になる。 - // これを防ぐために前にハグしてから少し時間が経っていないと - // 返信しないようにする - const now = Date.now(); - - const data = msg.friend.getPerModulesData(this); - - if (data.lastHuggedAt != null) { - if (now - data.lastHuggedAt < (1000 * 60)) return true; - } - - data.lastHuggedAt = now; - msg.friend.setPerModulesData(this, data); - //#endregion - - msg.reply( - msg.friend.love >= 5 ? serifs.core.hug.love : - msg.friend.love <= -3 ? serifs.core.hug.hate : - serifs.core.hug.normal); - - return true; - } - - @autobind - private humu(msg: Message): boolean { - if (!msg.includes(['踏んで'])) return false; - - // メッセージのみ - if (!msg.isDm) return true; - - msg.reply( - msg.friend.love >= 5 ? serifs.core.humu.love : - msg.friend.love <= -3 ? serifs.core.humu.hate : - serifs.core.humu.normal); - - return true; - } - - @autobind - private batou(msg: Message): boolean { - if (!msg.includes(['罵倒して', '罵って'])) return false; - - // メッセージのみ - if (!msg.isDm) return true; - - msg.reply( - msg.friend.love >= 5 ? serifs.core.batou.love : - msg.friend.love <= -5 ? serifs.core.batou.hate : - serifs.core.batou.normal); - - return true; - } - - @autobind - private itai(msg: Message): boolean { - if (!msg.or(['痛い', 'いたい']) && !msg.extractedText.endsWith('痛い')) return false; - - // メッセージのみ - if (!msg.isDm) return true; - - msg.reply(serifs.core.itai(msg.friend.name)); - - return true; - } - - @autobind - private ote(msg: Message): boolean { - if (!msg.or(['お手'])) return false; - - // メッセージのみ - if (!msg.isDm) return true; - - msg.reply( - msg.friend.love >= 10 ? serifs.core.ote.love2 : - msg.friend.love >= 5 ? serifs.core.ote.love1 : - serifs.core.ote.normal); - - return true; - } - - @autobind - private ponkotu(msg: Message): boolean | HandlerResult { - if (!msg.includes(['ぽんこつ'])) return false; - - msg.friend.decLove(); - - return { - reaction: 'angry' - }; - } - - @autobind - private rmrf(msg: Message): boolean | HandlerResult { - if (!msg.includes(['rm -rf'])) return false; - - msg.friend.decLove(); - - return { - reaction: 'angry' - }; - } - - @autobind - private shutdown(msg: Message): boolean | HandlerResult { - if (!msg.includes(['shutdown'])) return false; - - msg.reply(serifs.core.shutdown); - - return { - reaction: 'confused' - }; - } - @autobind private async contextHook(msg: Message, data: any) { if (msg.text == null) return; diff --git a/src/modules/talk/index.ts b/src/modules/talk/index.ts new file mode 100644 index 0000000..fb0b972 --- /dev/null +++ b/src/modules/talk/index.ts @@ -0,0 +1,333 @@ +import autobind from 'autobind-decorator'; +import { HandlerResult } from '../../ai'; +import Module from '../../module'; +import Message from '../../message'; +import serifs, { getSerif } from '../../serifs'; +import getDate from '../../utils/get-date'; + +export default class extends Module { + public readonly name = 'talk'; + + @autobind + public install() { + return { + mentionHook: this.mentionHook, + }; + } + + @autobind + private async mentionHook(msg: Message) { + if (!msg.text) return false; + + return ( + this.greet(msg) || + this.erait(msg) || + this.omedeto(msg) || + this.nadenade(msg) || + this.kawaii(msg) || + this.suki(msg) || + this.hug(msg) || + this.humu(msg) || + this.batou(msg) || + this.itai(msg) || + this.ote(msg) || + this.ponkotu(msg) || + this.rmrf(msg) || + this.shutdown(msg) + ); + } + + @autobind + private greet(msg: Message): boolean { + if (msg.text == null) return false; + + const incLove = () => { + //#region 1日に1回だけ親愛度を上げる + const today = getDate(); + + const data = msg.friend.getPerModulesData(this); + + if (data.lastGreetedAt == today) return; + + data.lastGreetedAt = today; + msg.friend.setPerModulesData(this, data); + + msg.friend.incLove(); + //#endregion + }; + + // 末尾のエクスクラメーションマーク + const tension = (msg.text.match(/[!!]{2,}/g) || ['']) + .sort((a, b) => a.length < b.length ? 1 : -1)[0] + .substr(1); + + if (msg.includes(['こんにちは', 'こんにちわ'])) { + msg.reply(serifs.core.hello(msg.friend.name)); + incLove(); + return true; + } + + if (msg.includes(['こんばんは', 'こんばんわ'])) { + msg.reply(serifs.core.helloNight(msg.friend.name)); + incLove(); + return true; + } + + if (msg.includes(['おは', 'おっは', 'お早う'])) { + msg.reply(serifs.core.goodMorning(tension, msg.friend.name)); + incLove(); + return true; + } + + if (msg.includes(['おやすみ', 'お休み'])) { + msg.reply(serifs.core.goodNight(msg.friend.name)); + incLove(); + return true; + } + + if (msg.includes(['行ってくる', '行ってきます', 'いってくる', 'いってきます'])) { + msg.reply( + msg.friend.love >= 7 + ? serifs.core.itterassyai.love(msg.friend.name) + : serifs.core.itterassyai.normal(msg.friend.name)); + incLove(); + return true; + } + + if (msg.includes(['ただいま'])) { + msg.reply( + msg.friend.love >= 15 ? serifs.core.okaeri.love2(msg.friend.name) : + msg.friend.love >= 7 ? getSerif(serifs.core.okaeri.love(msg.friend.name)) : + serifs.core.okaeri.normal(msg.friend.name)); + incLove(); + return true; + } + + return false; + } + + @autobind + private erait(msg: Message): boolean { + const match = msg.extractedText.match(/(.+?)た(から|ので)(褒|ほ)めて/); + if (match) { + msg.reply(getSerif(serifs.core.erait.specify(match[1], msg.friend.name))); + return true; + } + + const match2 = msg.extractedText.match(/(.+?)る(から|ので)(褒|ほ)めて/); + if (match2) { + msg.reply(getSerif(serifs.core.erait.specify(match2[1], msg.friend.name))); + return true; + } + + const match3 = msg.extractedText.match(/(.+?)だから(褒|ほ)めて/); + if (match3) { + msg.reply(getSerif(serifs.core.erait.specify(match3[1], msg.friend.name))); + return true; + } + + if (!msg.includes(['褒めて', 'ほめて'])) return false; + + msg.reply(getSerif(serifs.core.erait.general(msg.friend.name))); + + return true; + } + + @autobind + private omedeto(msg: Message): boolean { + if (!msg.includes(['おめでと'])) return false; + + msg.reply(serifs.core.omedeto(msg.friend.name)); + + return true; + } + + @autobind + private nadenade(msg: Message): boolean { + if (!msg.includes(['なでなで'])) return false; + + // メッセージのみ + if (!msg.isDm) return true; + + //#region 1日に1回だけ親愛度を上げる(嫌われてない場合のみ) + if (msg.friend.love >= 0) { + const today = getDate(); + + const data = msg.friend.getPerModulesData(this); + + if (data.lastNadenadeAt != today) { + data.lastNadenadeAt = today; + msg.friend.setPerModulesData(this, data); + + msg.friend.incLove(); + } + } + //#endregion + + msg.reply(getSerif( + msg.friend.love >= 10 ? serifs.core.nadenade.love3 : + msg.friend.love >= 5 ? serifs.core.nadenade.love2 : + msg.friend.love <= -15 ? serifs.core.nadenade.hate4 : + msg.friend.love <= -10 ? serifs.core.nadenade.hate3 : + msg.friend.love <= -5 ? serifs.core.nadenade.hate2 : + msg.friend.love <= -1 ? serifs.core.nadenade.hate1 : + serifs.core.nadenade.normal + )); + + return true; + } + + @autobind + private kawaii(msg: Message): boolean { + if (!msg.includes(['かわいい', '可愛い'])) return false; + + // メッセージのみ + if (!msg.isDm) return true; + + msg.reply(getSerif( + msg.friend.love >= 5 ? serifs.core.kawaii.love : + msg.friend.love <= -3 ? serifs.core.kawaii.hate : + serifs.core.kawaii.normal)); + + return true; + } + + @autobind + private suki(msg: Message): boolean { + if (!msg.or(['好き', 'すき'])) return false; + + // メッセージのみ + if (!msg.isDm) return true; + + msg.reply( + msg.friend.love >= 5 ? (msg.friend.name ? serifs.core.suki.love(msg.friend.name) : serifs.core.suki.normal) : + msg.friend.love <= -3 ? serifs.core.suki.hate : + serifs.core.suki.normal); + + return true; + } + + @autobind + private hug(msg: Message): boolean { + if (!msg.or(['ぎゅ', 'むぎゅ', /^はぐ(し(て|よ|よう)?)?$/])) return false; + + // メッセージのみ + if (!msg.isDm) return true; + + //#region 前のハグから1分経ってない場合は返信しない + // これは、「ハグ」と言って「ぎゅー」と返信したとき、相手が + // それに対してさらに「ぎゅー」と返信するケースがあったため。 + // そうするとその「ぎゅー」に対してもマッチするため、また + // 藍がそれに返信してしまうことになり、少し不自然になる。 + // これを防ぐために前にハグしてから少し時間が経っていないと + // 返信しないようにする + const now = Date.now(); + + const data = msg.friend.getPerModulesData(this); + + if (data.lastHuggedAt != null) { + if (now - data.lastHuggedAt < (1000 * 60)) return true; + } + + data.lastHuggedAt = now; + msg.friend.setPerModulesData(this, data); + //#endregion + + msg.reply( + msg.friend.love >= 5 ? serifs.core.hug.love : + msg.friend.love <= -3 ? serifs.core.hug.hate : + serifs.core.hug.normal); + + return true; + } + + @autobind + private humu(msg: Message): boolean { + if (!msg.includes(['踏んで'])) return false; + + // メッセージのみ + if (!msg.isDm) return true; + + msg.reply( + msg.friend.love >= 5 ? serifs.core.humu.love : + msg.friend.love <= -3 ? serifs.core.humu.hate : + serifs.core.humu.normal); + + return true; + } + + @autobind + private batou(msg: Message): boolean { + if (!msg.includes(['罵倒して', '罵って'])) return false; + + // メッセージのみ + if (!msg.isDm) return true; + + msg.reply( + msg.friend.love >= 5 ? serifs.core.batou.love : + msg.friend.love <= -5 ? serifs.core.batou.hate : + serifs.core.batou.normal); + + return true; + } + + @autobind + private itai(msg: Message): boolean { + if (!msg.or(['痛い', 'いたい']) && !msg.extractedText.endsWith('痛い')) return false; + + // メッセージのみ + if (!msg.isDm) return true; + + msg.reply(serifs.core.itai(msg.friend.name)); + + return true; + } + + @autobind + private ote(msg: Message): boolean { + if (!msg.or(['お手'])) return false; + + // メッセージのみ + if (!msg.isDm) return true; + + msg.reply( + msg.friend.love >= 10 ? serifs.core.ote.love2 : + msg.friend.love >= 5 ? serifs.core.ote.love1 : + serifs.core.ote.normal); + + return true; + } + + @autobind + private ponkotu(msg: Message): boolean | HandlerResult { + if (!msg.includes(['ぽんこつ'])) return false; + + msg.friend.decLove(); + + return { + reaction: 'angry' + }; + } + + @autobind + private rmrf(msg: Message): boolean | HandlerResult { + if (!msg.includes(['rm -rf'])) return false; + + msg.friend.decLove(); + + return { + reaction: 'angry' + }; + } + + @autobind + private shutdown(msg: Message): boolean | HandlerResult { + if (!msg.includes(['shutdown'])) return false; + + msg.reply(serifs.core.shutdown); + + return { + reaction: 'confused' + }; + } +}