// Package niuniu 牛牛大作战 package niuniu import ( "fmt" "strconv" "strings" "time" "github.com/FloatTech/AnimeAPI/wallet" ctrl "github.com/FloatTech/zbpctrl" "github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/ctxext" "github.com/RomiChan/syncx" zero "github.com/wdvxdr1123/ZeroBot" "github.com/wdvxdr1123/ZeroBot/extension/rate" "github.com/wdvxdr1123/ZeroBot/message" ) type lastLength struct { TimeLimit time.Time Count int Length float64 } type propsCount struct { Count int TimeLimit time.Time } var ( en = control.AutoRegister(&ctrl.Options[*zero.Ctx]{ DisableOnDefault: false, Brief: "牛牛大作战", Help: "- 打胶\n" + "- 使用[道具名称]打胶\n" + "- jj@xxx\n" + "- 使用[道具名称]jj@xxx\n" + "- 注册牛牛\n" + "- 赎牛牛(cd:60分钟)\n" + "- 牛牛商店\n" + "- 牛牛背包\n" + "- 注销牛牛\n" + "- 查看我的牛牛\n" + "- 牛子长度排行\n" + "- 牛子深度排行\n", PrivateDataFolder: "niuniu", }) dajiaoLimiter = rate.NewManager[string](time.Second*90, 1) jjLimiter = rate.NewManager[string](time.Second*150, 1) jjCount = syncx.Map[string, *lastLength]{} prop = syncx.Map[string, *propsCount]{} ) func init() { en.OnFullMatch("牛牛背包", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) { gid := ctx.Event.GroupID uid := ctx.Event.UserID niu, err := db.findNiuNiu(gid, uid) if err != nil { ctx.SendChain(message.Text("你还没有牛牛呢快去注册一个吧!")) return } ctx.SendChain(message.Text("当前牛牛背包如下", "\n伟哥:", niu.WeiGe, "\n媚药:", niu.Philter, "\n击剑神器:", niu.Artifact, "\n击剑神稽:", niu.ShenJi)) }) en.OnFullMatch("牛牛商店", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) { gid := ctx.Event.GroupID uid := ctx.Event.UserID if _, err := db.findNiuNiu(gid, uid); err != nil { ctx.SendChain(message.Text("你还没有牛牛呢快去注册一个吧!")) return } var messages message.Message messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text("牛牛商店当前售卖的物品如下"))) messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text("商品1\n商品名:伟哥\n商品价格:300ATRI币\n商品描述:可以让你打胶每次都增长,有效5次"))) messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text("商品2\n商品名:媚药\n商品价格:300ATRI币\n商品描述:可以让你打胶每次都减少,有效5次"))) messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text("商品3\n商品名:击剑神器\n商品价格:500ATRI币\n商品描述:可以让你每次击剑都立于不败之地,有效2次"))) messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text("商品4\n商品名:击剑神稽\n商品价格:500ATRI币\n商品描述:可以让你每次击剑都失败,有效2次"))) if id := ctx.Send(messages).ID(); id == 0 { ctx.Send(message.Text("发送商店失败")) return } ctx.SendChain(message.Text("输入对应序号进行购买商品")) recv, cancel := zero.NewFutureEvent("message", 999, false, zero.CheckUser(uid), zero.CheckGroup(gid), zero.RegexRule(`^(\d+)$`)).Repeat() defer cancel() timer := time.NewTimer(120 * time.Second) answer := "" defer timer.Stop() for { select { case <-timer.C: ctx.SendChain(message.At(uid), message.Text(" 超时,已自动取消")) return case r := <-recv: answer = r.Event.Message.String() n, err := strconv.Atoi(answer) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } info, err := db.findNiuNiu(gid, uid) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } money, err := info.purchaseItem(n) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } if wallet.GetWalletOf(uid) < money { ctx.SendChain(message.Text("你还没有足够的ATRI币呢,不能购买")) return } if err = wallet.InsertWalletOf(uid, -money); err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } if err = db.insertNiuNiu(&info, gid); err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } ctx.SendChain(message.Text("购买成功!")) return } } }) en.OnFullMatch("赎牛牛", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) { gid := ctx.Event.GroupID uid := ctx.Event.UserID last, ok := jjCount.Load(fmt.Sprintf("%d_%d", gid, uid)) if !ok { ctx.SendChain(message.Text("你还没有被厥呢")) return } if time.Since(last.TimeLimit) > time.Minute*60 { ctx.SendChain(message.Text("时间已经过期了,牛牛已被收回!")) jjCount.Delete(fmt.Sprintf("%d_%d", gid, uid)) return } if last.Count < 4 { ctx.SendChain(message.Text("你还没有被厥够4次呢,不能赎牛牛")) return } money := wallet.GetWalletOf(uid) if money < 150 { ctx.SendChain(message.Text("赎牛牛需要150ATRI币,快去赚钱吧")) return } if err := wallet.InsertWalletOf(uid, -150); err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } niuniu, err := db.findNiuNiu(gid, uid) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } niuniu.Length = last.Length if err = db.insertNiuNiu(&niuniu, gid); err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } jjCount.Delete(fmt.Sprintf("%d_%d", gid, uid)) ctx.SendChain(message.At(uid), message.Text(fmt.Sprintf("恭喜你!成功赎回牛牛,当前长度为:%.2fcm", last.Length))) }) en.OnFullMatch("牛子长度排行", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) { gid := ctx.Event.GroupID niuniuList, err := db.readAllTable(gid) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } m := niuniuList.positive() if m == nil { ctx.SendChain(message.Text("暂时没有男孩子哦")) return } m.sort(true) buf, err := m.setupDrawList(ctx, true) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } ctx.SendChain(message.ImageBytes(buf)) }) en.OnFullMatch("牛子深度排行", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) { gid := ctx.Event.GroupID niuniuList, err := db.readAllTable(gid) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } m := niuniuList.negative() if m == nil { ctx.SendChain(message.Text("暂时没有女孩子哦")) return } m.sort(false) buf, err := m.setupDrawList(ctx, false) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } ctx.SendChain(message.ImageBytes(buf)) }) en.OnFullMatch("查看我的牛牛", getdb, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) { uid := ctx.Event.UserID gid := ctx.Event.GroupID i, err := db.findNiuNiu(gid, uid) if err != nil { ctx.SendChain(message.Text("你还没有牛牛呢不能查看!")) return } niuniu := i.Length var result strings.Builder sexLong := "长" sex := "♂️" if niuniu < 0 { sexLong = "深" sex = "♀️" } niuniuList, err := db.readAllTable(gid) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } result.WriteString(fmt.Sprintf("\n📛%s<%s>的牛牛信息\n⭕性别:%s\n⭕%s度:%.2fcm\n⭕排行:%d\n⭕%s ", ctx.CardOrNickName(uid), strconv.FormatInt(uid, 10), sex, sexLong, niuniu, niuniuList.ranking(niuniu, uid), generateRandomString(niuniu))) ctx.SendChain(message.Text(&result)) }) en.OnRegex(`^(?:.*使用(.*))??打胶$`, zero.OnlyGroup, getdb).SetBlock(true).Limit(func(ctx *zero.Ctx) *rate.Limiter { lt := dajiaoLimiter.Load(fmt.Sprintf("%d_%d", ctx.Event.GroupID, ctx.Event.UserID)) ctx.State["dajiao_last_touch"] = lt.LastTouch() return lt }, func(ctx *zero.Ctx) { timePass := int(time.Since(time.Unix(ctx.State["dajiao_last_touch"].(int64), 0)).Seconds()) ctx.SendChain(message.Text(randomChoice([]string{ fmt.Sprintf("才过去了%ds时间,你就又要打🦶了,身体受得住吗", timePass), fmt.Sprintf("不行不行,你的身体会受不了的,歇%ds再来吧", 90-timePass), fmt.Sprintf("休息一下吧,会炸膛的!%ds后再来吧", 90-timePass), fmt.Sprintf("打咩哟,你的牛牛会爆炸的,休息%ds再来吧", 90-timePass), }))) }).Handle(func(ctx *zero.Ctx) { // 获取群号和用户ID gid := ctx.Event.GroupID uid := ctx.Event.UserID t := fmt.Sprintf("%d_%d", gid, uid) fiancee := ctx.State["regex_matched"].([]string) updateMap(t, false) niuniu, err := db.findNiuNiu(gid, uid) if err != nil { ctx.SendChain(message.Text("请先注册牛牛!")) dajiaoLimiter.Delete(fmt.Sprintf("%d_%d", gid, uid)) return } messages, err := niuniu.processNiuNiuAction(t, fiancee[1]) if err != nil { ctx.SendChain(message.Text(err)) dajiaoLimiter.Delete(fmt.Sprintf("%d_%d", gid, uid)) return } if err = db.insertNiuNiu(&niuniu, gid); err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } ctx.SendChain(message.Text(messages)) }) en.OnFullMatch("注册牛牛", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) { gid := ctx.Event.GroupID uid := ctx.Event.UserID if _, err := db.findNiuNiu(gid, uid); err == nil { ctx.SendChain(message.Text("你已经注册过了")) return } // 获取初始长度 length := db.randLength() u := userInfo{ UID: uid, Length: length, } // 添加数据进入表 if err := db.insertNiuNiu(&u, gid); err != nil { if err = db.createGIDTable(gid); err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } if err = db.insertNiuNiu(&u, gid); err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } } ctx.SendChain(message.At(uid), message.Text("注册成功,你的牛牛现在有", u.Length, "cm")) }) en.OnRegex(`^(?:.*使用(.*))??jj\s?(\[CQ:at,(?:\S*,)?qq=(\d+)(?:,\S*)?\]|(\d+))$`, getdb, zero.OnlyGroup).SetBlock(true).Limit(func(ctx *zero.Ctx) *rate.Limiter { lt := jjLimiter.Load(fmt.Sprintf("%d_%d", ctx.Event.GroupID, ctx.Event.UserID)) ctx.State["jj_last_touch"] = lt.LastTouch() return lt }, func(ctx *zero.Ctx) { timePass := int(time.Since(time.Unix(ctx.State["jj_last_touch"].(int64), 0)).Seconds()) ctx.SendChain(message.Text(randomChoice([]string{ fmt.Sprintf("才过去了%ds时间,你就又要击剑了,真是饥渴难耐啊", timePass), fmt.Sprintf("不行不行,你的身体会受不了的,歇%ds再来吧", 150-timePass), fmt.Sprintf("你这种男同就应该被送去集中营!等待%ds再来吧", 150-timePass), fmt.Sprintf("打咩哟!你的牛牛会炸的,休息%ds再来吧", 150-timePass), }))) }, ).Handle(func(ctx *zero.Ctx) { fiancee := ctx.State["regex_matched"].([]string) adduser, err := strconv.ParseInt(fiancee[3]+fiancee[4], 10, 64) if err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } uid := ctx.Event.UserID gid := ctx.Event.GroupID t := fmt.Sprintf("%d_%d", gid, uid) updateMap(t, false) myniuniu, err := db.findNiuNiu(gid, uid) if err != nil { ctx.SendChain(message.Text("你还没有牛牛快去注册一个吧!")) jjLimiter.Delete(t) return } adduserniuniu, err := db.findNiuNiu(gid, adduser) if err != nil { ctx.SendChain(message.At(uid), message.Text("对方还没有牛牛呢,不能🤺")) jjLimiter.Delete(t) return } if uid == adduser { ctx.SendChain(message.Text("你要和谁🤺?你自己吗?")) jjLimiter.Delete(t) return } fencingResult, err := myniuniu.processJJuAction(&adduserniuniu, t, fiancee[1]) if err != nil { ctx.SendChain(message.Text(err)) jjLimiter.Delete(t) return } if err = db.insertNiuNiu(&myniuniu, gid); err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } if err = db.insertNiuNiu(&adduserniuniu, gid); err != nil { ctx.SendChain(message.Text("ERROR: ", err)) return } ctx.SendChain(message.At(uid), message.Text(" ", fencingResult)) j := fmt.Sprintf("%d_%d", gid, adduser) count, ok := jjCount.Load(j) var c lastLength // 按照第一次jj时的时间计算,超过45分钟则重置 if !ok { c = lastLength{ TimeLimit: time.Now(), Count: 1, Length: adduserniuniu.Length, } } else { c = lastLength{ TimeLimit: c.TimeLimit, Count: count.Count + 1, Length: count.Length, } if time.Since(c.TimeLimit) > time.Minute*60 { c = lastLength{ TimeLimit: time.Now(), Count: 1, Length: adduserniuniu.Length, } } } jjCount.Store(j, &c) if c.Count > 2 { ctx.SendChain(message.Text(randomChoice([]string{fmt.Sprintf("你们太厉害了,对方已经被你们打了%d次了,你们可以继续找他🤺", c.Count), "你们不要再找ta🤺啦!"}))) // 保证只发送一次 if c.Count < 4 { id := ctx.SendPrivateMessage(adduser, message.Text(fmt.Sprintf("你在%d群里已经被厥冒烟了,快去群里赎回你原本的牛牛!\n发送:`赎牛牛`即可!", gid))) if id == 0 { ctx.SendChain(message.At(adduser), message.Text("快发送`赎牛牛`来赎回你原本的牛牛!")) } } } }) en.OnFullMatch("注销牛牛", getdb, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) { uid := ctx.Event.UserID gid := ctx.Event.GroupID _, err := db.findNiuNiu(gid, uid) if err != nil { ctx.SendChain(message.Text("你还没有牛牛呢,咋的你想凭空造一个啊")) return } err = db.deleteniuniu(gid, uid) if err != nil { ctx.SendChain(message.Text("注销失败")) return } ctx.SendChain(message.Text("注销成功,你已经没有牛牛了")) }) }