From b84c601976feffd5dc6b5249e4e3843d5dea1184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Fri, 27 Oct 2023 22:36:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0qqwife=E6=8F=92=E4=BB=B6=20(#?= =?UTF-8?q?8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 添加qqwife插件 * fix * fix * update * update * fix --- README.md | 31 ++ main.go | 1 + plugin/qqwife/dbfile.go | 385 ++++++++++++++++++++++ plugin/qqwife/happyplay.go | 649 +++++++++++++++++++++++++++++++++++++ plugin/qqwife/main.go | 206 ++++++++++++ 5 files changed, 1272 insertions(+) create mode 100644 plugin/qqwife/dbfile.go create mode 100644 plugin/qqwife/happyplay.go create mode 100644 plugin/qqwife/main.go diff --git a/README.md b/README.md index 3775da1..865a416 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,37 @@ nanobot [-Tadhst] ID1 ID2 ... +
+ 娶群友 + + `import _ "github.com/FloatTech/NanoBot-Plugin/plugin/qqwife"` + + - [x] 娶群友 + + - [x] 群老婆列表 + + - [x] (娶|嫁)@对方QQ + + - [x] 牛@对方QQ + + - [x] 闹离婚 + + - [x] 买礼物给@对方QQ + + - [x] 做媒 @攻方QQ @受方QQ + + - [x] 查好感度@对方QQ + + - [x] 好感度列表 + + - [x] [允许|禁止]自由恋爱 + + - [x] [允许|禁止]牛头人 + + - [x] 设置CD为xx小时 →(默认12小时) + +
+
在线代码运行 diff --git a/main.go b/main.go index e36a471..0568d73 100644 --- a/main.go +++ b/main.go @@ -24,6 +24,7 @@ import ( _ "github.com/FloatTech/NanoBot-Plugin/plugin/genshin" _ "github.com/FloatTech/NanoBot-Plugin/plugin/hyaku" _ "github.com/FloatTech/NanoBot-Plugin/plugin/manager" + _ "github.com/FloatTech/NanoBot-Plugin/plugin/qqwife" _ "github.com/FloatTech/NanoBot-Plugin/plugin/runcode" _ "github.com/FloatTech/NanoBot-Plugin/plugin/score" _ "github.com/FloatTech/NanoBot-Plugin/plugin/status" diff --git a/plugin/qqwife/dbfile.go b/plugin/qqwife/dbfile.go new file mode 100644 index 0000000..13d4aa6 --- /dev/null +++ b/plugin/qqwife/dbfile.go @@ -0,0 +1,385 @@ +// Package qqwife 娶群友 +package qqwife + +import ( + "errors" + "path" + "runtime" + "strconv" + "strings" + "sync" + "time" + + nano "github.com/fumiama/NanoBot" + + fcext "github.com/FloatTech/floatbox/ctxext" + "github.com/FloatTech/gg" + sql "github.com/FloatTech/sqlite" +) + +type userInfo struct { + ID string + Nick string + Avatar string +} + +type dbData struct { + db *sql.Sqlite + sync.RWMutex +} + +// 群设置 +type setting struct { + GID string + LastTime int + CanMatch int // 嫁婚开关 + CanNtr int // Ntr开关 + CDtime int64 // CD时间 +} + +// 结婚证信息 +type marriage struct { + Users string // 双方QQ号 + Sname string // 户主名称 + Mname string // 对象名称 + Updatetime string // 登记时间 + Spic string + Mpic string +} + +// 预留10个为后续扩展 +type cdsheet struct { + User string `db:"User"` + Mar int64 `db:"CD0"` // 娶 + Rob int64 `db:"CD1"` // 强 + Lef int64 `db:"CD2"` // 离 + Buy int64 `db:"CD3"` // 礼 + MMk int64 `db:"CD4"` // 做媒 + CD5 int64 `db:"CD5"` + CD6 int64 `db:"CD6"` + CD7 int64 `db:"CD7"` + CD8 int64 `db:"CD8"` + CD9 int64 `db:"CD9"` +} + +// 好感度列表 +type favor struct { + Users string // 双方QQ号 + Favor int // 好感度 +} + +var ( + wifeData = &dbData{ + db: &sql.Sqlite{}, + } + getdb = fcext.DoOnceOnSuccess(func(ctx *nano.Ctx) bool { + wifeData.db.DBPath = engine.DataFolder() + "结婚登记表.db" + err := wifeData.db.Open(time.Hour) + if err == nil { + // 创建群配置表 + err = wifeData.db.Create("setting", &setting{}) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return false + } + // 创建CD表 + err = wifeData.db.Create("cdsheet", &cdsheet{}) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return false + } + // 创建好感度表 + err = wifeData.db.Create("favor", &favor{}) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return false + } + // 刷新列表 + err = wifeData.refresh(ctx.Message.GuildID) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return false + } + return true + } + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return false + }) +) + +func getUserInfoIn(ctx *nano.Ctx, gid, uid string) (info userInfo, err error) { + uInfo, err := ctx.GetGuildMemberOf(gid, uid) + if err != nil { + return + } + nick := uInfo.Nick + if nick == "" { + nick = uInfo.User.Username + } + info = userInfo{ + ID: uInfo.User.ID, + Nick: nick, + Avatar: uInfo.User.Avatar, + } + return +} + +func (sql *dbData) getSet(gid string) (dbinfo setting, err error) { + sql.Lock() + defer sql.Unlock() + // 创建群表格 + err = sql.db.Create("setting", &dbinfo) + if err != nil { + return + } + if !sql.db.CanFind("setting", "where gid is "+gid) { + // 没有记录 + return setting{ + GID: gid, + CanMatch: 1, + CanNtr: 1, + CDtime: 12, + }, nil + } + _ = sql.db.Find("setting", &dbinfo, "where gid is "+gid) + return +} + +func (sql *dbData) updateSet(dbinfo setting) error { + sql.Lock() + defer sql.Unlock() + return sql.db.Insert("setting", &dbinfo) +} + +func (sql *dbData) refresh(gid string) error { + sql.Lock() + defer sql.Unlock() + // 创建群表格 + err := sql.db.Create("setting", &setting{}) + if err != nil { + return err + } + if !sql.db.CanFind("setting", "where gid is "+gid) { + return nil + } + dbinfo := setting{} + _ = sql.db.Find("setting", &dbinfo, "where gid is "+gid) + if time.Now().Day() != dbinfo.LastTime && time.Now().Hour() >= 4 { + _ = sql.db.Drop("group" + gid) + // 更新数据时间 + dbinfo.GID = gid + dbinfo.LastTime = time.Now().Day() + return sql.db.Insert("setting", &dbinfo) + } + return nil +} + +func (sql *dbData) checkUser(gid, uid string) (userinfo marriage, err error) { + sql.Lock() + defer sql.Unlock() + gidstr := "group" + gid + // 创建群表格 + err = sql.db.Create(gidstr, &userinfo) + if err != nil { + return + } + if !sql.db.CanFind(gidstr, "where Users glob '*"+uid+"*'") { + return + } + err = sql.db.Find(gidstr, &userinfo, "where Users glob '*"+uid+"*'") + return +} + +// 民政局登记数据 +func (sql *dbData) register(gid string, uid, target userInfo) error { + sql.Lock() + defer sql.Unlock() + gidstr := "group" + gid + uidinfo := marriage{ + Users: uid.ID + " & " + target.ID, + Sname: uid.Nick, + Spic: uid.Avatar, + Mname: target.Nick, + Mpic: target.Avatar, + Updatetime: time.Now().Format("15:04:05"), + } + return sql.db.Insert(gidstr, &uidinfo) +} + +// 民政局离婚 +func (sql *dbData) divorce(gid, uid string) error { + sql.Lock() + defer sql.Unlock() + gidstr := "group" + gid + // 创建群表格 + userinfo := marriage{} + err := sql.db.Create(gidstr, &userinfo) + if err != nil { + return err + } + if !sql.db.CanFind(gidstr, "where Users glob '*"+uid+"*'") { + return errors.New("user(" + uid + ") not found") + } + return sql.db.Del(gidstr, "where Users glob '*"+uid+"*'") +} + +func (sql *dbData) getlist(gid string) (list []marriage, err error) { + sql.Lock() + defer sql.Unlock() + gidstr := "group" + gid + number, _ := sql.db.Count(gidstr) + if number <= 0 { + return + } + var info marriage + err = sql.db.FindFor(gidstr, &info, "GROUP BY Users", func() error { + users := strings.Split(info.Users, " & ") + if users[0] == "" || users[1] == "" { + return nil + } + list = append(list, info) + return nil + }) + return +} + +func slicename(name string, canvas *gg.Context) (resultname string) { + usermane := []rune(name) // 将每个字符单独放置 + widthlen := 0 + numberlen := 0 + for i, v := range usermane { + width, _ := canvas.MeasureString(string(v)) // 获取单个字符的宽度 + widthlen += int(width) + if widthlen > 650 { + break // 总宽度不能超过350 + } + numberlen = i + } + if widthlen > 650 { + resultname = string(usermane[:numberlen-1]) + "......" // 名字切片 + } else { + resultname = name + } + return +} + +func (sql *dbData) favorFor(uid, target string, add int) (favorValue int, err error) { + sql.Lock() + defer sql.Unlock() + // 创建群表格 + err = sql.db.Create("favor", &favor{}) + if err != nil { + return + } + key := uid + " & " + target + uidInt64, _ := strconv.ParseInt(uid, 10, 64) + targetInt64, _ := strconv.ParseInt(target, 10, 64) + if uidInt64 < targetInt64 { + key = target + " & " + uid + } + info := favor{} + _ = sql.db.Find("favor", &info, "where Users is '"+key+"'") + if add > 0 { + info.Users = key + info.Favor += add + err = sql.db.Insert("favor", &info) + } + return info.Favor, err +} + +func (sql *dbData) getGroupFavorability(uid string) (list []favor, err error) { + sql.RLock() + defer sql.RUnlock() + info := favor{} + err = sql.db.FindFor("favor", &info, "where Users glob '*"+uid+"*' AND Favor > 0 ORDER BY DESC", func() error { + var target string + userList := strings.Split(info.Users, " & ") + switch { + case len(userList) == 0: + return errors.New("好感度系统数据存在错误") + case userList[0] == uid: + target = userList[1] + default: + target = userList[0] + } + list = append(list, favor{ + Users: target, + Favor: info.Favor, + }) + return nil + }) + return +} + +func (sql *dbData) checkCD(gid, uid string, funcType string) (cdTime time.Duration, err error) { + setting, err := wifeData.getSet(gid) + if err != nil { + return + } + sql.Lock() + defer sql.Unlock() + // 创建群表格 + err = sql.db.Create("cdsheet", &cdsheet{}) + if err != nil { + return + } + number, _ := sql.db.Count("cdsheet") + if number <= 0 { + return + } + info := cdsheet{} + if !sql.db.CanFind("cdsheet", "where User is '"+uid+"'") { + return + } + err = sql.db.Find("cdsheet", &info, "where User is '"+uid+"'") + if err != nil { + return + } + switch funcType { + case "娶", "嫁": + cdTime = time.Duration(setting.CDtime)*time.Hour - time.Since(time.Unix(info.Mar, 0)) + case "牛": + cdTime = time.Duration(setting.CDtime)*time.Hour - time.Since(time.Unix(info.Rob, 0)) + case "离": + cdTime = time.Duration(setting.CDtime)*time.Hour - time.Since(time.Unix(info.Lef, 0)) + case "媒": + cdTime = time.Duration(setting.CDtime)*time.Hour - time.Since(time.Unix(info.MMk, 0)) + case "买": + cdTime = time.Duration(setting.CDtime)*time.Hour - time.Since(time.Unix(info.Buy, 0)) + } + return +} + +func (sql *dbData) setCD(uid string, funcType string) error { + sql.Lock() + defer sql.Unlock() + // 创建群表格 + err := sql.db.Create("cdsheet", &cdsheet{}) + if err != nil { + return err + } + info := cdsheet{} + _ = sql.db.Find("cdsheet", &info, "where User is '"+uid+"'") + info.User = uid + switch funcType { + case "娶", "嫁": + info.Mar = time.Now().Unix() + case "牛": + info.Rob = time.Now().Unix() + case "离": + info.Lef = time.Now().Unix() + case "媒": + info.MMk = time.Now().Unix() + case "买": + info.Buy = time.Now().Unix() + } + return sql.db.Insert("cdsheet", &info) +} + +func getLine() string { + _, file, line, ok := runtime.Caller(1) + if ok { + return path.Base(file) + "." + strconv.Itoa(line) + } + return "" +} diff --git a/plugin/qqwife/happyplay.go b/plugin/qqwife/happyplay.go new file mode 100644 index 0000000..7d565d5 --- /dev/null +++ b/plugin/qqwife/happyplay.go @@ -0,0 +1,649 @@ +package qqwife + +import ( + "math/rand" + "strconv" + "strings" + + "github.com/FloatTech/AnimeAPI/wallet" + "github.com/FloatTech/NanoBot-Plugin/utils/ctxext" + "github.com/FloatTech/floatbox/file" + "github.com/FloatTech/floatbox/math" + "github.com/FloatTech/gg" + "github.com/FloatTech/imgfactory" + "github.com/FloatTech/zbputils/img/text" + nano "github.com/fumiama/NanoBot" + log "github.com/sirupsen/logrus" +) + +var sendtext = [...][]string{ + { // 表白成功 + "是个勇敢的孩子(*/ω\*) 今天的运气都降临在你的身边~\n\n", + "(´・ω・`)对方答应了你 并表示愿意当今天的CP\n\n", + }, + { // 表白失败 + "今天的运气有一点背哦~明天再试试叭", + "_(:з」∠)_下次还有机会 咱抱抱你w", + "今天失败了惹. 摸摸头~咱明天还有机会", + }, + { // ntr成功 + "因为你的个人魅力~~今天他就是你的了w\n\n", + }, + { // 离婚失败 + "打是情,骂是爱,不打不亲不相爱。答应我不要分手。", + "床头打架床尾和,夫妻没有隔夜仇。安啦安啦,不要闹变扭。", + }, + { // 离婚成功 + "离婚成功力\n话说你不考虑当个1?", + "离婚成功力\n天涯何处无芳草,何必单恋一枝花?不如再摘一支(bushi", + }, +} + +func init() { + engine.OnMessageRegex(`^设置CD为(\d+)小时`, nano.OnlyChannel, nano.AdminPermission, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *nano.Ctx) { + cdTime, err := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:请设置纯数字\n", err) + return + } + groupInfo, err := wifeData.getSet(ctx.Message.GuildID) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + groupInfo.CDtime = cdTime + err = wifeData.updateSet(groupInfo) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]设置CD时长失败\n", err) + return + } + _, _ = ctx.SendPlainMessage(true, "设置成功") + }) + engine.OnMessageRegex(`^(允许|禁止)(自由恋爱|牛头人)$`, nano.OnlyChannel, nano.AdminPermission, getdb).SetBlock(true).Handle(func(ctx *nano.Ctx) { + status := ctx.State["regex_matched"].([]string)[1] + mode := ctx.State["regex_matched"].([]string)[2] + groupInfo, err := wifeData.getSet(ctx.Message.GuildID) + switch { + case err != nil: + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + case mode == "自由恋爱": + if status == "允许" { + groupInfo.CanMatch = 1 + } else { + groupInfo.CanMatch = 0 + } + case mode == "牛头人": + if status == "允许" { + groupInfo.CanNtr = 1 + } else { + groupInfo.CanNtr = 0 + } + } + err = wifeData.updateSet(groupInfo) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + _, _ = ctx.SendPlainMessage(true, "设置成功") + }) + // 单身技能 + engine.OnMessageRegex(`^(娶|嫁)\s*<@!(\d+)>$`, nano.OnlyChannel, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *nano.Ctx) { + gid := ctx.Message.GuildID + setting, err := wifeData.getSet(gid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if setting.CanMatch == 0 { + _, _ = ctx.SendPlainMessage(true, "该频道已发布了禁止自由恋爱,请认真水群") + return + } + uid := ctx.Message.Author.ID + choice := ctx.State["regex_matched"].([]string)[1] + cdTime, err := wifeData.checkCD(gid, uid, choice) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if cdTime > 0 { + _, _ = ctx.SendPlainMessage(true, "你的技能CD还有", cdTime) + return + } + fiance := ctx.State["regex_matched"].([]string)[2] + uInfo, err := wifeData.checkUser(gid, uid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if uInfo.Users != "" { + info := strings.Split(uInfo.Users, " & ") + switch { + case info[0] == "" || info[1] == "": + _, _ = ctx.SendPlainMessage(true, "今天的你是单身贵族噢") + return + case info[0] == fiance || info[1] == fiance: + _, _ = ctx.SendPlainMessage(true, "笨蛋!你们已经在一起了!") + return + case info[0] == uid: // 如果如为攻 + _, _ = ctx.SendPlainMessage(true, "笨蛋~你家里还有个吃白饭的w") + return + case info[1] == uid: // 如果为受 + _, _ = ctx.SendPlainMessage(true, "该是0就是0,当0有什么不好") + return + } + } + fInfo, err := wifeData.checkUser(gid, uid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if fInfo.Users != "" { + info := strings.Split(fInfo.Users, " & ") + switch { + case info[0] == "" || info[1] == "": + _, _ = ctx.SendPlainMessage(true, "今天的ta是单身贵族噢") + return + case info[0] == uid: // 如果如为攻 + _, _ = ctx.SendPlainMessage(true, "他有别的女人了,你该放下了") + return + case info[1] == uid: // 如果为受 + _, _ = ctx.SendPlainMessage(true, "ta被别人娶了,你来晚力") + return + } + } + // 写入CD + err = wifeData.setCD(uid, choice) + if err != nil { + log.Warnln("[qqwife]你的技能CD记录失败,", err) + } + uBook, err := getUserInfoIn(ctx, gid, uid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if uid == fiance { // 如果是自己 + switch rand.Intn(3) { + case 1: + err := wifeData.register(gid, uBook, userInfo{}) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + _, _ = ctx.SendPlainMessage(true, "今日获得成就:单身贵族") + default: + _, _ = ctx.SendPlainMessage(true, "今日获得成就:自恋狂") + } + return + } + fBook, err := getUserInfoIn(ctx, gid, fiance) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + favor, err := wifeData.favorFor(uid, fiance, 0) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if favor < 30 { + favor = 30 // 保底30%概率 + } + if rand.Intn(101) >= favor { + _, _ = ctx.SendPlainMessage(true, sendtext[1][rand.Intn(len(sendtext[1]))]) + return + } + // 去民政局登记 + var choicetext string + switch choice { + case "娶": + err = wifeData.register(gid, uBook, fBook) + choicetext = "\n今天你的群老婆是" + default: + err = wifeData.register(gid, fBook, uBook) + choicetext = "\n今天你的群老公是" + } + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + // 请大家吃席 + _, err = ctx.SendChain(nano.ReplyTo(ctx.Message.ID), + nano.Text(sendtext[0][rand.Intn(len(sendtext[0]))], "\n", + choicetext, "[", fBook.Nick, "]\n", + "当前你们好感度为", favor), nano.Image(fBook.Avatar)) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "", getLine(), " ->ERROR: ", err) + } + }) + // NTR技能 + engine.OnMessageRegex(`^牛\s*<@!(\d+)>$`, nano.OnlyChannel, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *nano.Ctx) { + gid := ctx.Message.GuildID + setting, err := wifeData.getSet(gid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if setting.CanNtr == 0 { + _, _ = ctx.SendPlainMessage(true, "该频道已发布了禁止牛头人,请认真水群") + return + } + uid := ctx.Message.Author.ID + cdTime, err := wifeData.checkCD(gid, uid, "牛") + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if cdTime > 0 { + _, _ = ctx.SendPlainMessage(true, "你的技能CD还有", cdTime) + return + } + fiance := ctx.State["regex_matched"].([]string)[1] + uInfo, err := wifeData.checkUser(gid, uid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if uInfo.Users != "" { + info := strings.Split(uInfo.Users, " & ") + switch { + case info[0] == "" || info[1] == "": + _, _ = ctx.SendPlainMessage(true, "今天的你是单身贵族噢") + return + case info[0] == fiance || info[1] == fiance: + _, _ = ctx.SendPlainMessage(true, "笨蛋!你们已经在一起了!") + return + case info[0] == uid: // 如果如为攻 + _, _ = ctx.SendPlainMessage(true, "笨蛋~你家里还有个吃白饭的w") + return + case info[1] == uid: // 如果为受 + _, _ = ctx.SendPlainMessage(true, "该是0就是0,当0有什么不好") + return + } + } + fInfo, err := wifeData.checkUser(gid, fiance) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if fInfo.Users == "" { + _, _ = ctx.SendPlainMessage(true, "今天的ta是单身噢,快去明媒正娶吧!") + return + } + // 写入CD + err = wifeData.setCD(uid, "牛") + if err != nil { + log.Warnln("[qqwife]你的技能CD记录失败,", err) + } + if fiance == uid { + _, _ = ctx.SendPlainMessage(true, "今日获得成就:自我攻略") + return + } + favor, err := wifeData.favorFor(uid, fiance, 0) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if favor < 30 { + favor = 30 // 保底10%概率 + } + if rand.Intn(101) >= favor/3 { + _, _ = ctx.SendPlainMessage(true, "失败了!可惜") + return + } + // 判断target是老公还是老婆 + choicetext := "老公" + ntrID := uid + targetID := fiance + greenID := "" // 被牛的 + + err = wifeData.divorce(gid, fiance) + if err != nil { + _, _ = ctx.SendPlainMessage(true, "ta不想和原来的对象分手...\n[error]", err) + return + } + user := strings.Split(fInfo.Users, " & ") + switch { + case user[0] == fiance: // 是1 + ntrID = fiance + targetID = uid + greenID = user[1] + case user[1] == fiance: // 是0 + greenID = user[0] + choicetext = "老婆" + default: + _, _ = ctx.SendPlainMessage(true, "数据库发生问题力") + return + } + userInfo, err := getUserInfoIn(ctx, gid, ntrID) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + fianceInfo, err := getUserInfoIn(ctx, gid, targetID) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + err = wifeData.register(gid, userInfo, fianceInfo) + if err != nil { + _, _ = ctx.SendPlainMessage(true, "[qqwife]复婚登记失败力\n", err) + return + } + favor, err = wifeData.favorFor(uid, fiance, -5) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + } + _, err = wifeData.favorFor(uid, greenID, 5) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + } + // 输出结果 + _, err = ctx.SendChain(nano.ReplyTo(ctx.Message.ID), + nano.Text(sendtext[2][rand.Intn(len(sendtext[2]))], "\n", + choicetext, "[", fianceInfo.Nick, "]\n", + "当前你们好感度为", favor), nano.Image(fianceInfo.Avatar)) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]: ", err) + } + }) + // 做媒技能 + engine.OnMessageRegex(`^做媒\s*<@!(\d+)>\s*<@!(\d+)>`, nano.OnlyChannel, nano.AdminPermission, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *nano.Ctx) { + gid := ctx.Message.GuildID + uid := ctx.Message.Author.ID + cdTime, err := wifeData.checkCD(gid, uid, "媒") + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if cdTime > 0 { + _, _ = ctx.SendPlainMessage(true, "你的技能CD还有", cdTime) + return + } + gayOne := ctx.State["regex_matched"].([]string)[1] + gaynano := ctx.State["regex_matched"].([]string)[2] + uInfo, err := wifeData.checkUser(gid, gayOne) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if uInfo.Users != "" { + _, _ = ctx.SendChain(nano.ReplyTo(ctx.Message.ID), nano.At(gayOne), nano.Text("已有家妻")) + return + } + fInfo, err := wifeData.checkUser(gid, gaynano) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if fInfo.Users != "" { + _, _ = ctx.SendChain(nano.ReplyTo(ctx.Message.ID), nano.At(gaynano), nano.Text("已有所属")) + return + } + // 写入CD + err = wifeData.setCD(uid, "媒") + if err != nil { + log.Warnln("[qqwife]你的技能CD记录失败,", err) + } + favor, err := wifeData.favorFor(gayOne, gaynano, 0) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if favor < 30 { + favor = 30 // 保底30%概率 + } + if rand.Intn(101) >= favor { + _, err = wifeData.favorFor(uid, gayOne, -1) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + } + _, err = wifeData.favorFor(uid, gaynano, -1) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + } + _, _ = ctx.SendPlainMessage(true, sendtext[1][rand.Intn(len(sendtext[1]))]) + return + } + // 去民政局登记 + userInfo, err := getUserInfoIn(ctx, gid, gayOne) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + fianceInfo, err := getUserInfoIn(ctx, gid, gaynano) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + err = wifeData.register(gid, userInfo, fianceInfo) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + _, err = wifeData.favorFor(uid, gayOne, 1) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + } + _, err = wifeData.favorFor(uid, gaynano, 1) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + } + _, err = wifeData.favorFor(gayOne, gaynano, 1) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + } + // 请大家吃席 + _, err = ctx.SendChain(nano.ReplyTo(ctx.Message.ID), + nano.Text("恭喜你成功撮合了一对CP\n\n"), nano.At(gayOne), nano.Text("今天你的群老婆是[", fianceInfo.Nick, "]"), + nano.Image(fianceInfo.Avatar)) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "", getLine(), " ->ERROR: ", err) + } + }) + engine.OnMessageFullMatchGroup([]string{"闹离婚", "办离婚"}, nano.OnlyChannel, getdb).Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *nano.Ctx) { + gid := ctx.Message.GuildID + uid := ctx.Message.Author.ID + cdTime, err := wifeData.checkCD(gid, uid, "离") + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if cdTime > 0 { + _, _ = ctx.SendPlainMessage(true, "你的技能CD还有", cdTime) + return + } + uInfo, err := wifeData.checkUser(gid, uid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if uInfo.Users == "" { + _, _ = ctx.SendPlainMessage(true, "你还是单身噢,快去娶群友吧!") + return + } + // 写入CD + err = wifeData.setCD(uid, "离") + if err != nil { + _, _ = ctx.SendPlainMessage(true, "[qqwife]你的技能CD记录失败\n", err) + } + user := strings.Split(uInfo.Users, " & ") + mun := 0 + if user[1] == uid { + mun = 1 + } + favor, err := wifeData.favorFor(user[0], user[1], 0) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if favor < 30 { + favor = 10 + } + if rand.Intn(101) > 110-favor { + _, _ = ctx.SendPlainMessage(true, sendtext[3][rand.Intn(len(sendtext[3]))]) + return + } + err = wifeData.divorce(gid, uid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + /* + if rand.Intn(100) > 50 { + _, _ = wifeData.favorFor(user[0], user[1], -rand.Intn(favor/2)) + } + */ + _, _ = ctx.SendPlainMessage(true, sendtext[4][mun]) + }) + + // 好感度系统 + engine.OnMessageRegex(`^查好感度\s*<@!(\d+)>`, nano.OnlyChannel, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *nano.Ctx) { + fiance := ctx.State["regex_matched"].([]string)[1] + uid := ctx.Message.Author.ID + favor, err := wifeData.favorFor(uid, fiance, 0) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + // 输出结果 + _, _ = ctx.SendPlainMessage(true, "当前你们好感度为", favor) + }) + // 礼物系统 + engine.OnMessageRegex(`^买礼物给\s*<@!(\d+)>`, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *nano.Ctx) { + gid := ctx.Message.GuildID + uid := ctx.Message.Author.ID + fiance := ctx.State["regex_matched"].([]string)[1] + if fiance == uid { + _, _ = ctx.SendPlainMessage(true, "你想给自己买什么礼物呢?") + return + } + // 获取CD + cdTime, err := wifeData.checkCD(gid, uid, "买") + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if cdTime > 0 { + _, _ = ctx.SendPlainMessage(true, "你的技能CD还有", cdTime) + return + } + // 获取好感度 + favor, err := wifeData.favorFor(uid, fiance, 0) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + // 对接小熊饼干 + uidint64, _ := strconv.ParseInt(uid, 10, 64) + walletinfo := wallet.GetWalletOf(uidint64) + if walletinfo < 1 { + _, _ = ctx.SendPlainMessage(true, "你钱包没钱啦!") + return + } + moneyToFavor := rand.Intn(math.Min(walletinfo, 100)) + 1 + // 计算钱对应的好感值 + newFavor := 1 + moodMax := 2 + if favor > 50 { + newFavor = moneyToFavor % 10 // 礼物厌倦 + } else { + moodMax = 5 + newFavor += rand.Intn(moneyToFavor) + } + // 随机对方心情 + mood := rand.Intn(moodMax) + if mood == 0 { + newFavor = -newFavor + } + // 记录结果 + err = wallet.InsertWalletOf(uidint64, -moneyToFavor) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + lastfavor, err := wifeData.favorFor(uid, fiance, newFavor) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + // 写入CD + err = wifeData.setCD(uid, "买") + if err != nil { + _, _ = ctx.SendPlainMessage(true, "[qqwife]你的技能CD记录失败\n", err) + } + // 输出结果 + if mood == 0 { + _, _ = ctx.SendPlainMessage(true, "你花了", moneyToFavor, "ATRI币买了一件女装送给了ta,ta很不喜欢,你们的好感度降低至", lastfavor) + } else { + _, _ = ctx.SendPlainMessage(true, "你花了", moneyToFavor, "ATRI币买了一件女装送给了ta,ta很喜欢,你们的好感度升至", lastfavor) + } + }) + engine.OnMessageFullMatch("好感度列表", nano.OnlyChannel, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *nano.Ctx) { + gid := ctx.Message.GuildID + uid := ctx.Message.Author.ID + fianceeInfo, err := wifeData.getGroupFavorability(uid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + /***********设置图片的大小和底色***********/ + number := len(fianceeInfo) + fontSize := 50.0 + canvas := gg.NewContext(1150, int(170+(50+70)*float64(number))) + canvas.SetRGB(1, 1, 1) // 白色 + canvas.Clear() + /***********下载字体***********/ + data, err := file.GetLazyData(text.BoldFontFile, nano.Md5File, true) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + } + /***********设置字体颜色为黑色***********/ + canvas.SetRGB(0, 0, 0) + /***********设置字体大小,并获取字体高度用来定位***********/ + if err = canvas.ParseFontFace(data, fontSize*2); err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + sl, h := canvas.MeasureString("你的好感度排行列表") + /***********绘制标题***********/ + canvas.DrawString("你的好感度排行列表", (1100-sl)/2, 100) // 放置在中间位置 + canvas.DrawString("————————————————————", 0, 160) + /***********设置字体大小,并获取字体高度用来定位***********/ + if err = canvas.ParseFontFace(data, fontSize); err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + i := 0 + for _, info := range fianceeInfo { + if info.Favor == 0 { + break + } + if info.Users == "" { + continue + } + user, err := getUserInfoIn(ctx, gid, info.Users) + if err != nil { + log.Warnln("[", getLine(), " ->ERROR]:", err.Error()) + continue + } + canvas.SetRGB255(0, 0, 0) + canvas.DrawString(user.Nick+"("+user.ID+")", 10, float64(180+(50+70)*i)) + canvas.DrawString(strconv.Itoa(info.Favor), 1020, float64(180+60+(50+70)*i)) + canvas.DrawRectangle(10, float64(180+60+(50+70)*i)-h/2, 1000, 50) + canvas.SetRGB255(150, 150, 150) + canvas.Fill() + canvas.SetRGB255(0, 0, 0) + canvas.DrawRectangle(10, float64(180+60+(50+70)*i)-h/2, float64(info.Favor)*10, 50) + canvas.SetRGB255(231, 27, 100) + canvas.Fill() + i++ + } + data, err = imgfactory.ToBytes(canvas.Image()) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + _, _ = ctx.SendImageBytes(data, true) + }) +} diff --git a/plugin/qqwife/main.go b/plugin/qqwife/main.go new file mode 100644 index 0000000..aa12bf9 --- /dev/null +++ b/plugin/qqwife/main.go @@ -0,0 +1,206 @@ +// Package qqwife 娶群友 +package qqwife + +import ( + "math/rand" + "strconv" + "strings" + + "github.com/FloatTech/NanoBot-Plugin/utils/ctxext" + "github.com/FloatTech/imgfactory" + ctrl "github.com/FloatTech/zbpctrl" + nano "github.com/fumiama/NanoBot" + + "github.com/FloatTech/floatbox/file" + "github.com/FloatTech/gg" + "github.com/FloatTech/zbputils/img/text" +) + +var ( + engine = nano.Register("qqwife", &ctrl.Options[*nano.Ctx]{ + DisableOnDefault: false, + Brief: "娶群友", + Help: "- 娶群友\n- 群老婆列表\n" + + "- [允许|禁止]自由恋爱\n- [允许|禁止]牛头人\n" + + "- 设置CD为xx小时 →(默认12小时)\n" + + "- 查好感度@对方QQ\n" + + "- 好感度列表\n" + + "--------------------------------\n以下指令存在CD,频道共用,不跨天刷新,前两个受指令开关\n--------------------------------\n" + + "- (娶|嫁)@对方QQ\n (好感度越高成功率越高,保底30%概率)\n" + + "- 牛@对方QQ\n (好感度越高成功率越高,保底10%概率)\n" + + "- 闹离婚\n (好感度越高成功率越低)\n" + + "- 买礼物给@对方QQ\n (使用bot钱包插件的金额获取好感度)\n" + + "- 做媒 @攻方QQ @受方QQ\n (攻受双方好感度越高成功率越高,保底30%概率)\n" + + "--------------------------------\n好感度规则\n--------------------------------\n" + + "\"娶群友\"指令好感度随机增加1~5。\n\"A牛B的C\"会导致C恨A, 好感度-5;\nB为了报复A, 好感度+5(什么柜子play)\nA为BC做媒,成功B、C对A好感度+1反之-1\n做媒成功BC好感度+1" + + "\nTips: 群老婆列表每天4点刷新", + PrivateDataFolder: "qqwife", + }).ApplySingle(nano.NewSingle( + nano.WithKeyFn(func(ctx *nano.Ctx) int64 { + gid, _ := strconv.ParseUint(ctx.Message.GuildID, 10, 64) + return int64(gid) + }), + nano.WithPostFn[int64](func(ctx *nano.Ctx) { + _, _ = ctx.SendPlainMessage(true, "别着急,民政局门口排长队了!") + }), + )) +) + +func init() { + engine.OnMessageFullMatch("娶群友", nano.OnlyChannel, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *nano.Ctx) { + gid := ctx.Message.GuildID + uid := ctx.Message.Author.ID + + info, err := wifeData.checkUser(gid, uid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + uInfo, err := getUserInfoIn(ctx, gid, uid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if info.Users == "" { + menbers, err := ctx.GetGuildMembersIn(gid, "0", 1000) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + list := make(map[int]userInfo, 1000) + for i, member := range menbers { + nick := member.Nick + if nick == "" { + nick = member.User.Username + } + list[i] = userInfo{ + ID: member.User.ID, + Nick: nick, + Avatar: member.User.Avatar, + } + } + target := list[rand.Intn(len(list))] + if target.ID == uid { + err = wifeData.register(gid, uInfo, userInfo{}) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + _, err = ctx.SendChain(nano.At(uid), nano.Text("今日获得成就:单身贵族")) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]: ", err) + } + } + info, err = wifeData.checkUser(gid, target.ID) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + if info.Users != "" { + _, _ = ctx.SendPlainMessage(true, "呜...没娶到,你可以再尝试一次") + return + } + err = wifeData.register(gid, uInfo, target) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + favor, err := wifeData.favorFor(uid, target.ID, rand.Intn(5)+1) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + _, err = ctx.SendChain(nano.At(uid), nano.Text("\n今天你的群老婆是\n[", target.Nick, "]哒\n当前你们好感度为", favor), nano.Image(target.Avatar)) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]: ", err) + } + return + } + users := strings.Split(info.Users, " & ") + switch { + case (users[0] == uid && users[1] == "") || (users[1] == uid && users[0] == ""): // 如果是单身贵族 + _, _ = ctx.SendPlainMessage(true, "今天你是单身贵族噢") + return + case users[0] == uid: // 娶过别人 + favor, err := wifeData.favorFor(uid, users[1], 0) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + _, err = ctx.SendChain(nano.At(uid), + nano.Text("\n今天你在", info.Updatetime, "娶了群友[", info.Mname, "]\n", + "当前你们好感度为", favor), nano.Image(info.Mpic)) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]: ", err) + } + return + case users[1] == uid: // 嫁给别人 + favor, err := wifeData.favorFor(users[0], uid, 0) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + _, err = ctx.SendChain(nano.At(uid), + nano.Text("\n今天你在", info.Updatetime, "被群友[", info.Sname, "]娶了\n", + "当前你们好感度为", favor), nano.Image(info.Spic)) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]: ", err) + } + return + } + }) + engine.OnMessageFullMatch("群老婆列表", nano.OnlyChannel, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *nano.Ctx) { + gid := ctx.Message.GuildID + list, err := wifeData.getlist(gid) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]:", err) + return + } + number := len(list) + if number <= 0 { + _, _ = ctx.SendPlainMessage(false, "今天没有人结婚哦: ") + return + } + /***********设置图片的大小和底色***********/ + fontSize := 50.0 + if number < 10 { + number = 10 + } + canvas := gg.NewContext(1500, int(250+fontSize*float64(number))) + canvas.SetRGB(1, 1, 1) // 白色 + canvas.Clear() + /***********下载字体,可以注销掉***********/ + data, err := file.GetLazyData(text.BoldFontFile, nano.Md5File, true) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]: ", err) + } + /***********设置字体颜色为黑色***********/ + canvas.SetRGB(0, 0, 0) + /***********设置字体大小,并获取字体高度用来定位***********/ + if err = canvas.ParseFontFace(data, fontSize*2); err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]: ", err) + return + } + sl, h := canvas.MeasureString("群老婆列表") + /***********绘制标题***********/ + canvas.DrawString("群老婆列表", (1500-sl)/2, 160-h) // 放置在中间位置 + canvas.DrawString("————————————————————", 0, 250-h) + /***********设置字体大小,并获取字体高度用来定位***********/ + if err = canvas.ParseFontFace(data, fontSize); err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]: ", err) + return + } + _, h = canvas.MeasureString("焯") + for i, info := range list { + canvas.DrawString(slicename(info.Sname, canvas), 0, float64(260+50*i)-h) + canvas.DrawString("←→", 700, float64(260+50*i)-h) + canvas.DrawString(slicename(info.Mname, canvas), 800, float64(260+50*i)-h) + } + data, err = imgfactory.ToBytes(canvas.Image()) + if err != nil { + _, _ = ctx.SendPlainMessage(false, "[", getLine(), " ->ERROR]: ", err) + return + } + _, _ = ctx.SendImageBytes(data, false) + }) +}