feat:使用niu包,添加新玩法牛牛拍卖行 (#1098)

This commit is contained in:
宇~ 2025-01-20 14:45:02 +08:00 committed by GitHub
parent 2c5596cd96
commit 70ebb03434
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 217 additions and 875 deletions

View File

@ -1045,6 +1045,10 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 赎牛牛
- [x] 牛牛拍卖行
- [x] 出售牛牛
- [x] 牛牛商店
- [x] 牛牛背包

View File

@ -1,41 +1,34 @@
package niuniu
import (
"bytes"
"fmt"
"image"
"image/png"
"net/http"
"github.com/FloatTech/AnimeAPI/niu"
"github.com/FloatTech/floatbox/file"
"github.com/FloatTech/rendercard"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/img/text"
zero "github.com/wdvxdr1123/ZeroBot"
)
type drawUserRanking struct {
name string
user *userInfo
}
type drawer []drawUserRanking
func (allUsers drawer) draw(t bool) (img image.Image, err error) {
fontbyte, err := file.GetLazyData(text.GlowSansFontFile, control.Md5File, true)
func processRankingImg(allUsers niu.BaseInfos, ctx *zero.Ctx, t bool) ([]byte, error) {
fontByte, err := file.GetLazyData(text.GlowSansFontFile, control.Md5File, true)
if err != nil {
return nil, err
}
var (
title string
s string
)
title = "牛牛深度排行"
s := "牛牛长度"
title := "牛牛长度排行"
if !t {
s = "牛牛深度"
if t {
title = "牛牛长度排行"
s = "牛牛长度"
title = "牛牛深度排行"
}
ri := make([]*rendercard.RankInfo, len(allUsers))
for i, user := range allUsers {
resp, err := http.Get(fmt.Sprintf("https://q1.qlogo.cn/g?b=qq&nk=%d&s=100", user.user.UID))
resp, err := http.Get(fmt.Sprintf("https://q1.qlogo.cn/g?b=qq&nk=%d&s=100", user.UID))
if err != nil {
return nil, err
}
@ -46,11 +39,16 @@ func (allUsers drawer) draw(t bool) (img image.Image, err error) {
}
ri[i] = &rendercard.RankInfo{
Avatar: decode,
TopLeftText: user.name,
BottomLeftText: fmt.Sprintf("QQ:%d", user.user.UID),
RightText: fmt.Sprintf("%s:%.2fcm", s, user.user.Length),
TopLeftText: ctx.CardOrNickName(user.UID),
BottomLeftText: fmt.Sprintf("QQ:%d", user.UID),
RightText: fmt.Sprintf("%s:%.2fcm", s, user.Length),
}
}
img, err = rendercard.DrawRankingCard(fontbyte, title, ri)
return
img, err := rendercard.DrawRankingCard(fontByte, title, ri)
if err != nil {
return nil, err
}
var buf bytes.Buffer
err = png.Encode(&buf, img)
return buf.Bytes(), err
}

View File

@ -3,10 +3,11 @@ package niuniu
import (
"fmt"
"math/rand"
"strconv"
"strings"
"time"
"github.com/FloatTech/AnimeAPI/niu"
"github.com/FloatTech/AnimeAPI/wallet"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
@ -23,11 +24,6 @@ type lastLength struct {
Length float64
}
type propsCount struct {
Count int
TimeLimit time.Time
}
var (
en = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
@ -38,59 +34,124 @@ var (
"- 使用[道具名称]jj@xxx\n" +
"- 注册牛牛\n" +
"- 赎牛牛(cd:60分钟)\n" +
"- 出售牛牛\n" +
"- 牛牛拍卖行\n" +
"- 牛牛商店\n" +
"- 牛牛背包\n" +
"- 注销牛牛\n" +
"- 查看我的牛牛\n" +
"- 牛子长度排行\n" +
"- 牛子深度排行\n",
"- 牛子深度排行\n" +
"\n ps : 出售后的牛牛都会进入牛牛拍卖行哦",
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]{}
register = syncx.Map[string, *lastLength]{}
)
func init() {
en.OnFullMatch("牛牛背包", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) {
en.OnFullMatch("牛牛拍卖行", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
gid := ctx.Event.GroupID
uid := ctx.Event.UserID
niu, err := db.findNiuNiu(gid, uid)
auction, err := niu.ShowAuction(gid)
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("你还没有牛牛呢快去注册一个吧!"))
ctx.SendChain(message.Text("ERROR:", err))
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次")))
messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text("牛牛拍卖行有以下牛牛")))
for _, info := range auction {
msg := fmt.Sprintf("商品序号: %d\n牛牛原所属: %d\n牛牛价格: %d%s\n牛牛大小: %.2fcm",
info.ID+1, info.UserID, info.Money, wallet.GetWalletName(), info.Length)
messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text(msg)))
}
if id := ctx.Send(messages).ID(); id == 0 {
ctx.Send(message.Text("发送拍卖行失败"))
return
}
ctx.SendChain(message.Reply(ctx.Event.Message), 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
}
n--
msg, err := niu.Auction(gid, uid, n)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(message.Reply(ctx.Event.Message), message.Text(msg))
return
}
}
})
en.OnFullMatch("出售牛牛", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
gid := ctx.Event.GroupID
uid := ctx.Event.UserID
sell, err := niu.Sell(gid, uid)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(sell))
})
en.OnFullMatch("牛牛背包", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
gid := ctx.Event.GroupID
uid := ctx.Event.UserID
bag, err := niu.Bag(gid, uid)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(bag))
})
en.OnFullMatch("牛牛商店", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
gid := ctx.Event.GroupID
uid := ctx.Event.UserID
if _, err := niu.GetWordNiuNiu(gid, uid); err != nil {
ctx.SendChain(message.Text(niu.ErrNoNiuNiu))
return
}
propMap := map[int]struct {
name string
cost int
scope string
description string
count int
}{
1: {"伟哥", 300, "打胶", "可以让你打胶每次都增长", 5},
2: {"媚药", 300, "打胶", "可以让你打胶每次都减少", 5},
3: {"击剑神器", 500, "jj", "可以让你每次击剑都立于不败之地", 2},
4: {"击剑神稽", 500, "jj", "可以让你每次击剑都失败", 2},
}
var messages message.Message
messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text("牛牛商店当前售卖的物品如下")))
for id := range propMap {
product := propMap[id]
productInfo := fmt.Sprintf("商品%d\n商品名: %s\n商品价格: %dATRI币\n商品作用域: %s\n商品描述: %s\n使用次数:%d",
id, product.name, product.cost, product.scope, product.description, product.count)
messages = append(messages, ctxext.FakeSenderForwardNode(ctx, message.Text(productInfo)))
}
if id := ctx.Send(messages).ID(); id == 0 {
ctx.Send(message.Text("发送商店失败"))
return
@ -115,29 +176,7 @@ func init() {
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 {
if err = niu.Store(gid, uid, n); err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
@ -147,7 +186,7 @@ func init() {
}
}
})
en.OnFullMatch("赎牛牛", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) {
en.OnFullMatch("赎牛牛", zero.OnlyGroup).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))
@ -157,7 +196,7 @@ func init() {
return
}
if time.Since(last.TimeLimit) > time.Minute*60 {
if time.Since(last.TimeLimit) > time.Hour {
ctx.SendChain(message.Text("时间已经过期了,牛牛已被收回!"))
jjCount.Delete(fmt.Sprintf("%d_%d", gid, uid))
return
@ -167,103 +206,74 @@ func init() {
ctx.SendChain(message.Text("你还没有被厥够4次呢,不能赎牛牛"))
return
}
money := wallet.GetWalletOf(uid)
if money < 150 {
ctx.SendChain(message.Text("赎牛牛需要150ATRI币快去赚钱吧"))
ctx.SendChain(message.Text("再次确认一下哦,这次赎牛牛,牛牛长度将会变成", last.Length, "cm\n还需要嘛【是|否】"))
recv, cancel := zero.NewFutureEvent("message", 999, false, zero.CheckUser(uid), zero.CheckGroup(gid), zero.RegexRule(`^(是|否)$`)).Repeat()
defer cancel()
timer := time.NewTimer(2 * time.Minute)
defer timer.Stop()
for {
select {
case <-timer.C:
ctx.SendChain(message.Text("操作超时,已自动取消"))
return
case c := <-recv:
answer := c.Event.Message.String()
if answer == "否" {
ctx.SendChain(message.Text("取消成功!"))
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))
if err := niu.Redeem(gid, uid, last.Length); 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))
ctx.SendChain(message.At(uid), message.Text(fmt.Sprintf("恭喜你!成功赎回牛牛,当前长度为:%.2fcm", last.Length)))
return
}
}
})
en.OnFullMatch("查看我的牛牛", getdb, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
en.OnFullMatch("牛子长度排行", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
gid := ctx.Event.GroupID
infos, err := niu.GetRankingInfo(gid, true)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
img, err := processRankingImg(infos, ctx, true)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.ImageBytes(img))
})
en.OnFullMatch("牛子深度排行", zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
gid := ctx.Event.GroupID
infos, err := niu.GetRankingInfo(gid, false)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
img, err := processRankingImg(infos, ctx, false)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.ImageBytes(img))
})
en.OnFullMatch("查看我的牛牛", 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)
view, err := niu.View(gid, uid, ctx.CardOrNickName(uid))
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))
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(view))
})
en.OnRegex(`^(?:.*使用(.*))??打胶$`, zero.OnlyGroup,
getdb).SetBlock(true).Limit(func(ctx *zero.Ctx) *rate.Limiter {
en.OnRegex(`^(?:.*使用(.*))??打胶$`, zero.OnlyGroup).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
@ -279,58 +289,27 @@ func init() {
// 获取群号和用户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)
msg, err := niu.HitGlue(gid, uid, fiancee[1])
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))
dajiaoLimiter.Delete(fmt.Sprintf("%d_%d", ctx.Event.GroupID, ctx.Event.UserID))
return
}
ctx.SendChain(message.Text(messages))
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(msg))
})
en.OnFullMatch("注册牛牛", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) {
en.OnFullMatch("注册牛牛", zero.OnlyGroup).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 {
msg, err := niu.Register(gid, uid)
if 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"))
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(msg))
})
en.OnRegex(`^(?:.*使用(.*))??jj\s?(\[CQ:at,(?:\S*,)?qq=(\d+)(?:,\S*)?\]|(\d+))$`, getdb,
en.OnMessage(zero.NewPattern().Text(`^(?:.*使用(.*))??jj`).At().AsRule(),
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()
@ -345,82 +324,55 @@ func init() {
})))
},
).Handle(func(ctx *zero.Ctx) {
fiancee := ctx.State["regex_matched"].([]string)
adduser, err := strconv.ParseInt(fiancee[3]+fiancee[4], 10, 64)
patternParsed := ctx.State[zero.KeyPattern].([]zero.PatternParsed)
adduser, err := strconv.ParseInt(patternParsed[1].At(), 10, 64)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
jjLimiter.Delete(fmt.Sprintf("%d_%d", ctx.Event.GroupID, ctx.Event.UserID))
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)
msg, length, err := niu.JJ(gid, uid, adduser, patternParsed[0].Text()[1])
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))
jjLimiter.Delete(fmt.Sprintf("%d_%d", ctx.Event.GroupID, ctx.Event.UserID))
return
}
if err = db.insertNiuNiu(&adduserniuniu, gid); err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.At(uid), message.Text(" ", fencingResult))
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(msg))
j := fmt.Sprintf("%d_%d", gid, adduser)
count, ok := jjCount.Load(j)
var c lastLength
// 按照第一次jj时的时间计算超过45分钟则重置
// 按照最后一次被jj时的时间计算超过60分钟则重置
if !ok {
c = lastLength{
TimeLimit: time.Now(),
Count: 1,
Length: adduserniuniu.Length,
Length: length,
}
} else {
c = lastLength{
TimeLimit: c.TimeLimit,
TimeLimit: time.Now(),
Count: count.Count + 1,
Length: count.Length,
}
if time.Since(c.TimeLimit) > time.Minute*60 {
if time.Since(c.TimeLimit) > time.Hour {
c = lastLength{
TimeLimit: time.Now(),
Count: 1,
Length: adduserniuniu.Length,
Length: 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 {
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 {
@ -429,19 +381,33 @@ func init() {
}
}
})
en.OnFullMatch("注销牛牛", getdb, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
en.OnFullMatch("注销牛牛", 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("你还没有牛牛呢,咋的你想凭空造一个啊"))
key := fmt.Sprintf("%d_%d", gid, uid)
data, ok := register.Load(key)
switch {
case !ok || time.Since(data.TimeLimit) > time.Hour*12:
data = &lastLength{
TimeLimit: time.Now(),
Count: 1,
}
default:
if err := wallet.InsertWalletOf(uid, -data.Count*50); err != nil {
ctx.SendChain(message.Text("你的钱不够你注销牛牛了,这次注销需要", data.Count*50, wallet.GetWalletName()))
return
}
err = db.deleteniuniu(gid, uid)
}
register.Store(key, data)
msg, err := niu.Cancel(gid, uid)
if err != nil {
ctx.SendChain(message.Text("注销失败"))
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text("注销成功,你已经没有牛牛了"))
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(msg))
})
}
func randomChoice(options []string) string {
return options[rand.Intn(len(options))]
}

View File

@ -1,376 +0,0 @@
// Package niuniu 牛牛大作战
package niuniu
import (
"bytes"
"errors"
"fmt"
"image/png"
"math"
"math/rand"
"sort"
"strconv"
"sync"
"time"
fcext "github.com/FloatTech/floatbox/ctxext"
sql "github.com/FloatTech/sqlite"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
type model struct {
sync.RWMutex
sql sql.Sqlite
}
type userInfo struct {
UID int64
Length float64
UserCount int
WeiGe int // 伟哥
Philter int // 媚药
Artifact int // 击剑神器
ShenJi int // 击剑神稽
Buff1 int // 暂定
Buff2 int // 暂定
Buff3 int // 暂定
Buff4 int // 暂定
Buff5 int // 暂定
}
type users []*userInfo
var (
db = &model{}
getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
db.sql = sql.New(en.DataFolder() + "niuniu.db")
err := db.sql.Open(time.Hour * 24)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return false
}
return true
})
)
// useWeiGe 使用道具伟哥
func (u *userInfo) useWeiGe() (string, float64) {
niuniu := u.Length
reduce := math.Abs(hitGlue(niuniu))
niuniu += reduce
return randomChoice([]string{
fmt.Sprintf("哈哈,你这一用道具,牛牛就像是被激发了潜能,增加了%.2fcm!看来今天是个大日子呢!", reduce),
fmt.Sprintf("你这是用了什么神奇的道具?牛牛竟然增加了%.2fcm,简直是牛气冲天!", reduce),
fmt.Sprintf("使用道具后,你的牛牛就像是开启了加速模式,一下增加了%.2fcm,这成长速度让人惊叹!", reduce),
}), niuniu
}
// usePhilter 使用道具媚药
func (u *userInfo) usePhilter() (string, float64) {
niuniu := u.Length
reduce := math.Abs(hitGlue(niuniu))
niuniu -= reduce
return randomChoice([]string{
fmt.Sprintf("你使用媚药,咿呀咿呀一下使当前长度发生了一些变化,当前长度%.2f", niuniu),
fmt.Sprintf("看来你追求的是‘微观之美’,故意使用道具让牛牛凹进去了%.2fcm", reduce),
fmt.Sprintf("缩小奇迹’在你身上发生了,牛牛凹进去了%.2fcm,你的选择真是独特!", reduce),
}), niuniu
}
// useArtifact 使用道具击剑神器
func (u *userInfo) useArtifact(adduserniuniu float64) (string, float64, float64) {
myLength := u.Length
difference := myLength - adduserniuniu
var (
change float64
)
if difference > 0 {
change = hitGlue(myLength + adduserniuniu)
} else {
change = hitGlue((myLength + adduserniuniu) / 2)
}
myLength += change
return randomChoice([]string{
fmt.Sprintf("凭借神秘道具的力量,你让对方在你的长度面前俯首称臣!你的长度增加了%.2fcm,当前长度达到了%.2fcm", change, myLength),
fmt.Sprintf("神器在手,天下我有!你使用道具后,长度猛增%.2fcm,现在的总长度是%.2fcm,无人能敌!", change, myLength),
fmt.Sprintf("这就是道具的魔力!你轻松增加了%.2fcm,让对手望尘莫及,当前长度为%.2fcm", change, myLength),
fmt.Sprintf("道具一出,谁与争锋!你的长度因道具而增长%.2fcm,现在的长度是%.2fcm,霸气尽显!", change, myLength),
fmt.Sprintf("使用道具的你,如同获得神助!你的长度增长了%.2fcm,达到%.2fcm的惊人长度,胜利自然到手!", change, myLength),
}), myLength, adduserniuniu - change/1.3
}
// useShenJi 使用道具击剑神稽
func (u *userInfo) useShenJi(adduserniuniu float64) (string, float64, float64) {
myLength := u.Length
difference := myLength - adduserniuniu
var (
change float64
)
if difference > 0 {
change = hitGlue(myLength + adduserniuniu)
} else {
change = hitGlue((myLength + adduserniuniu) / 2)
}
myLength -= change
var r string
if myLength > 0 {
r = randomChoice([]string{
fmt.Sprintf("哦吼!?看来你的牛牛因为使用了神秘道具而缩水了呢🤣🤣🤣!缩小了%.2fcm", change),
fmt.Sprintf("哈哈,看来这个道具有点儿调皮,让你的长度缩水了%.2fcm!现在你的长度是%.2fcm,下次可得小心使用哦!", change, myLength),
fmt.Sprintf("使用道具后,你的牛牛似乎有点儿害羞,缩水了%.2fcm!现在的长度是%.2fcm,希望下次它能挺直腰板!", change, myLength),
fmt.Sprintf("哎呀,这个道具的效果有点儿意外,你的长度减少了%.2fcm,现在只有%.2fcm了!下次选道具可得睁大眼睛!", change, myLength),
})
} else {
r = randomChoice([]string{
fmt.Sprintf("哦哟,小姐姐真是玩得一手好游戏,使用道具后数值又降低了%.2fcm,小巧得更显魅力!", change),
fmt.Sprintf("看来小姐姐喜欢更加精致的风格,使用道具后,数值减少了%.2fcm,更加迷人了!", change),
fmt.Sprintf("小姐姐的每一次变化都让人惊喜,使用道具后,数值减少了%.2fcm,更加优雅动人!", change),
fmt.Sprintf("小姐姐这是在展示什么是真正的精致小巧,使用道具后,数值减少了%.2fcm,美得不可方物!", change),
})
}
return r, myLength, adduserniuniu + 0.7*change
}
func (u *userInfo) processNiuNiuAction(t string, props string) (string, error) {
var (
messages string
info userInfo
err error
f float64
)
load, ok := prop.Load(t)
info = *u
if props != "" {
if contains(t, dajiaoProp) {
return "", errors.New("道具不存在")
}
if err = u.createUserInfoByProps(props); err != nil {
return "", err
}
}
switch {
case ok && load.Count > 1 && time.Since(load.TimeLimit) < time.Minute*8:
messages, f = generateRandomStingTwo(u.Length)
u.Length = f
errMessage := fmt.Sprintf("你使用道具次数太快了,此次道具不会生效,等待%d再来吧", time.Minute*8-time.Since(load.TimeLimit))
err = errors.New(errMessage)
case u.WeiGe-info.WeiGe != 0:
messages, f = u.useWeiGe()
u.Length = f
updateMap(t, true)
case u.Philter-info.Philter != 0:
messages, f = u.usePhilter()
u.Length = f
updateMap(t, true)
default:
messages, f = generateRandomStingTwo(u.Length)
u.Length = f
}
return messages, err
}
func (u *userInfo) createUserInfoByProps(props string) error {
var (
err error
)
switch props {
case "伟哥":
if u.WeiGe > 0 {
u.WeiGe--
} else {
err = errors.New("你还没有伟哥呢,不能使用")
}
case "媚药":
if u.Philter > 0 {
u.Philter--
} else {
err = errors.New("你还没有媚药呢,不能使用")
}
case "击剑神器":
if u.Artifact > 0 {
u.Artifact--
} else {
err = errors.New("你还没有击剑神器呢,不能使用")
}
case "击剑神稽":
if u.ShenJi > 0 {
u.ShenJi--
} else {
err = errors.New("你还没有击剑神稽呢,不能使用")
}
default:
err = errors.New("道具不存在")
}
return err
}
// 接收值依次是 被jj用户的信息 记录gid和uid的字符串 道具名称
// 返回值依次是 要发送的消息 错误信息
func (u *userInfo) processJJuAction(adduserniuniu *userInfo, t string, props string) (string, error) {
var (
fencingResult string
f float64
f1 float64
info userInfo
err error
)
v, ok := prop.Load(t)
info = *u
if props != "" {
if contains(t, jjProp) {
return "", errors.New("道具不存在")
}
if err = u.createUserInfoByProps(props); err != nil {
return "", err
}
}
switch {
case ok && v.Count > 1 && time.Since(v.TimeLimit) < time.Minute*8:
fencingResult, f, f1 = fencing(u.Length, adduserniuniu.Length)
u.Length = f
adduserniuniu.Length = f1
errMessage := fmt.Sprintf("你使用道具次数太快了,此次道具不会生效,等待%d再来吧", time.Minute*8-time.Since(v.TimeLimit))
err = errors.New(errMessage)
case u.ShenJi-info.ShenJi != 0:
fencingResult, f, f1 = u.useShenJi(adduserniuniu.Length)
u.Length = f
adduserniuniu.Length = f1
updateMap(t, true)
case u.Artifact-info.Artifact != 0:
fencingResult, f, f1 = u.useArtifact(adduserniuniu.Length)
u.Length = f
adduserniuniu.Length = f1
updateMap(t, true)
default:
fencingResult, f, f1 = fencing(u.Length, adduserniuniu.Length)
u.Length = f
adduserniuniu.Length = f1
}
return fencingResult, err
}
func (u *userInfo) purchaseItem(n int) (int, error) {
var (
money int
err error
)
switch n {
case 1:
money = 300
u.WeiGe += 5
case 2:
money = 300
u.Philter += 5
case 3:
money = 500
u.Artifact += 2
case 4:
money = 500
u.ShenJi += 2
default:
err = errors.New("无效的选择")
}
return money, err
}
func (m users) setupDrawList(ctx *zero.Ctx, t bool) ([]byte, error) {
allUsers := make(drawer, len(m))
for i, info := range m {
allUsers[i] = drawUserRanking{
name: ctx.CardOrNickName(info.UID),
user: info,
}
}
image, err := allUsers.draw(t)
if err != nil {
return nil, err
}
var buf bytes.Buffer
err = png.Encode(&buf, image)
return buf.Bytes(), err
}
func (m users) positive() users {
var m1 []*userInfo
for _, i2 := range m {
if i2.Length > 0 {
m1 = append(m1, i2)
}
}
return m1
}
func (m users) negative() users {
var m1 []*userInfo
for _, i2 := range m {
if i2.Length <= 0 {
m1 = append(m1, i2)
}
}
return m1
}
func (m users) sort(isDesc bool) {
t := func(i, j int) bool {
return m[i].Length < m[j].Length
}
if isDesc {
t = func(i, j int) bool {
return m[i].Length > m[j].Length
}
}
sort.Slice(m, t)
}
func (m users) ranking(niuniu float64, uid int64) int {
m.sort(niuniu > 0)
for i, user := range m {
if user.UID == uid {
return i + 1
}
}
return -1
}
func (db *model) randLength() float64 {
return float64(rand.Intn(9)+1) + (float64(rand.Intn(100)) / 100)
}
func (db *model) createGIDTable(gid int64) error {
db.Lock()
defer db.Unlock()
return db.sql.Create(strconv.FormatInt(gid, 10), &userInfo{})
}
// findNiuNiu 返回一个用户的牛牛信息
func (db *model) findNiuNiu(gid, uid int64) (userInfo, error) {
db.RLock()
defer db.RUnlock()
u := userInfo{}
err := db.sql.Find(strconv.FormatInt(gid, 10), &u, "WHERE UID = ?", uid)
return u, err
}
// insertNiuNiu 更新一个用户的牛牛信息
func (db *model) insertNiuNiu(u *userInfo, gid int64) error {
db.Lock()
defer db.Unlock()
return db.sql.Insert(strconv.FormatInt(gid, 10), u)
}
func (db *model) deleteniuniu(gid, uid int64) error {
db.Lock()
defer db.Unlock()
return db.sql.Del(strconv.FormatInt(gid, 10), "WHERE UID = ?", uid)
}
func (db *model) readAllTable(gid int64) (users, error) {
db.Lock()
defer db.Unlock()
a, err := sql.FindAll[userInfo](&db.sql, strconv.FormatInt(gid, 10), "WHERE UserCount = 0")
return a, err
}

View File

@ -1,250 +0,0 @@
// Package niuniu 牛牛大作战
package niuniu
import (
"fmt"
"math"
"math/rand"
"strings"
"time"
)
var (
jjProp = []string{"击剑神器", "击剑神稽"}
dajiaoProp = []string{"伟哥", "媚药"}
)
// 检查字符串是否在切片中
func contains(s string, array []string) bool {
for _, item := range array {
if strings.EqualFold(item, s) {
return true
}
}
return false
}
func randomChoice(options []string) string {
return options[rand.Intn(len(options))]
}
func updateMap(t string, d bool) {
value, ok := prop.Load(t)
if value == nil {
return
}
// 检查一次是否已经过期
if !d {
if time.Since(value.TimeLimit) > time.Minute*8 {
prop.Delete(t)
}
return
}
if ok {
prop.Store(t, &propsCount{
Count: value.Count + 1,
TimeLimit: value.TimeLimit,
})
} else {
prop.Store(t, &propsCount{
Count: 1,
TimeLimit: time.Now(),
})
}
if time.Since(value.TimeLimit) > time.Minute*8 {
prop.Delete(t)
}
}
func generateRandomStingTwo(niuniu float64) (string, float64) {
probability := rand.Intn(100 + 1)
reduce := math.Abs(hitGlue(niuniu))
switch {
case probability <= 40:
niuniu += reduce
return randomChoice([]string{
fmt.Sprintf("你嘿咻嘿咻一下,促进了牛牛发育,牛牛增加%.2fcm了呢!", reduce),
fmt.Sprintf("你打了个舒服痛快的🦶呐,牛牛增加了%.2fcm呢!", reduce),
}), niuniu
case probability <= 60:
return randomChoice([]string{
"你打了个🦶,但是什么变化也没有,好奇怪捏~",
"你的牛牛刚开始变长了,可过了一会又回来了,什么变化也没有,好奇怪捏~",
}), niuniu
default:
niuniu -= reduce
if niuniu < 0 {
return randomChoice([]string{
fmt.Sprintf("哦吼!?看来你的牛牛凹进去了%.2fcm呢!", reduce),
fmt.Sprintf("你突发恶疾!你的牛牛凹进去了%.2fcm", reduce),
fmt.Sprintf("笑死,你因为打🦶过度导致牛牛凹进去了%.2fcm!🤣🤣🤣", reduce),
}), niuniu
}
return randomChoice([]string{
fmt.Sprintf("阿哦,你过度打🦶,牛牛缩短%.2fcm了呢!", reduce),
fmt.Sprintf("你的牛牛变长了很多,你很激动地继续打🦶,然后牛牛缩短了%.2fcm呢!", reduce),
fmt.Sprintf("小打怡情,大打伤身,强打灰飞烟灭!你过度打🦶,牛牛缩短了%.2fcm捏!", reduce),
}), niuniu
}
}
func generateRandomString(niuniu float64) string {
switch {
case niuniu <= -100:
return "wtf你已经进化成魅魔了魅魔在击剑时有20%的几率消耗自身长度吞噬对方牛牛呢。"
case niuniu <= -50:
return "嗯....好像已经穿过了身体吧..从另一面来看也可以算是凸出来的吧?"
case niuniu <= -25:
return randomChoice([]string{
"这名女生,你的身体很健康哦!",
"WOW,真的凹进去了好多呢!",
"你已经是我们女孩子的一员啦!",
})
case niuniu <= -10:
return randomChoice([]string{
"你已经是一名女生了呢,",
"从女生的角度来说,你发育良好(,",
"你醒啦?你已经是一名女孩子啦!",
"唔...可以放进去一根手指了都...",
})
case niuniu <= 0:
return randomChoice([]string{
"安了安了,不要伤心嘛,做女生有什么不好的啊。",
"不哭不哭,摸摸头,虽然很难再长出来,但是请不要伤心啦啊!",
"加油加油!我看好你哦!",
"你醒啦?你现在已经是一名女孩子啦!",
})
case niuniu <= 10:
return randomChoice([]string{
"你行不行啊?细狗!",
"虽然短,但是小小的也很可爱呢。",
"像一只蚕宝宝。",
"长大了。",
})
case niuniu <= 25:
return randomChoice([]string{
"唔...没话说",
"已经很长了呢!",
})
case niuniu <= 50:
return randomChoice([]string{
"话说这种真的有可能吗?",
"厚礼谢!",
})
case niuniu <= 100:
return randomChoice([]string{
"已经突破天际了嘛...",
"唔...这玩意应该不会变得比我高吧?",
"你这个长度会死人的...",
"你马上要进化成牛头人了!!",
"你是什么怪物,不要过来啊!!",
})
default:
return "惊世骇俗你已经进化成牛头人了牛头人在击剑时有20%的几率消耗自身长度吞噬对方牛牛呢。"
}
}
// fencing 击剑对决逻辑返回对决结果和myLength的变化值
func fencing(myLength, oppoLength float64) (string, float64, float64) {
devourLimit := 0.27
probability := rand.Intn(100) + 1
switch {
case oppoLength <= -100 && myLength > 0 && 10 < probability && probability <= 20:
change := hitGlue(oppoLength) + rand.Float64()*math.Log2(math.Abs(0.5*(myLength+oppoLength)))
myLength += change
return fmt.Sprintf("对方身为魅魔诱惑了你,你同化成魅魔!当前长度%.2fcm", -myLength), -myLength, oppoLength
case oppoLength >= 100 && myLength > 0 && 10 < probability && probability <= 20:
change := math.Min(math.Abs(devourLimit*myLength), math.Abs(1.5*myLength))
myLength += change
return fmt.Sprintf("对方以牛头人的荣誉摧毁了你的牛牛!当前长度%.2fcm", myLength), myLength, oppoLength
case myLength <= -100 && oppoLength > 0 && 10 < probability && probability <= 20:
change := hitGlue(myLength+oppoLength) + rand.Float64()*math.Log2(math.Abs(0.5*(myLength+oppoLength)))
oppoLength -= change
myLength -= change
return fmt.Sprintf("你身为魅魔诱惑了对方,吞噬了对方部分长度!当前长度%.2fcm", myLength), myLength, oppoLength
case myLength >= 100 && oppoLength > 0 && 10 < probability && probability <= 20:
myLength -= oppoLength
oppoLength = 0.01
return fmt.Sprintf("你以牛头人的荣誉摧毁了对方的牛牛!当前长度%.2fcm", myLength), myLength, oppoLength
default:
return determineResultBySkill(myLength, oppoLength)
}
}
// determineResultBySkill 根据击剑技巧决定结果
func determineResultBySkill(myLength, oppoLength float64) (string, float64, float64) {
probability := rand.Intn(100) + 1
winProbability := calculateWinProbability(myLength, oppoLength) * 100
return applySkill(myLength, oppoLength,
float64(probability) <= winProbability)
}
// calculateWinProbability 计算胜率
func calculateWinProbability(heightA, heightB float64) float64 {
pA := 0.9
heightRatio := math.Max(heightA, heightB) / math.Min(heightA, heightB)
reductionRate := 0.1 * (heightRatio - 1)
reduction := pA * reductionRate
adjustedPA := pA - reduction
return math.Max(adjustedPA, 0.01)
}
// applySkill 应用击剑技巧并生成结果
func applySkill(myLength, oppoLength float64, increaseLength1 bool) (string, float64, float64) {
reduce := fence(oppoLength)
// 兜底操作
if reduce == 0 {
reduce = rand.Float64() + float64(rand.Intn(3))
}
if increaseLength1 {
myLength += reduce
oppoLength -= 0.8 * reduce
if myLength < 0 {
return fmt.Sprintf("哦吼!?你的牛牛在长大欸!长大了%.2fcm", reduce), myLength, oppoLength
}
return fmt.Sprintf("你以绝对的长度让对方屈服了呢!你的长度增加%.2fcm,当前长度%.2fcm", reduce, myLength), myLength, oppoLength
}
myLength -= reduce
oppoLength += 0.8 * reduce
if myLength < 0 {
return fmt.Sprintf("哦吼!?看来你的牛牛因为击剑而凹进去了呢🤣🤣🤣!凹进去了%.2fcm", reduce), myLength, oppoLength
}
return fmt.Sprintf("对方以绝对的长度让你屈服了呢!你的长度减少%.2fcm,当前长度%.2fcm", reduce, myLength), myLength, oppoLength
}
// fence 根据长度计算减少的长度
func fence(rd float64) float64 {
rd = math.Abs(rd)
if rd == 0 {
rd = 1
}
r := hitGlue(rd)*2 + rand.Float64()*math.Log2(rd)
return float64(int(r * rand.Float64()))
}
func hitGlue(l float64) float64 {
if l == 0 {
l = 0.1
}
l = math.Abs(l)
switch {
case l > 1 && l <= 10:
return rand.Float64() * math.Log2(l*2)
case 10 < l && l <= 100:
return rand.Float64() * math.Log2(l*1.5)
case 100 < l && l <= 1000:
return rand.Float64() * (math.Log10(l*1.5) * 2)
case l > 1000:
return rand.Float64() * (math.Log10(l) * 2)
default:
return rand.Float64()
}
}