Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions plugin/wife/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package wife

import (
"encoding/json"
"fmt"
"os"
"strings"
"regexp"

fcext "github.com/FloatTech/floatbox/ctxext"
ctrl "github.com/FloatTech/zbpctrl"
Expand All @@ -15,15 +16,27 @@ import (
"github.com/wdvxdr1123/ZeroBot/message"
)

func init() {
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
var (
cards = []string{}
re = regexp.MustCompile(`^\[(.*?)\](.*)\..*$`)
engine = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Help: "- 抽老婆",
Brief: "从老婆库抽每日老婆",
PublicDataFolder: "Wife",
}).ApplySingle(ctxext.DefaultSingle)
)

func card2name(card string) (string, string) {
match := re.FindStringSubmatch(card)
if len(match) >= 3 {
return match[1], match[2]
}
return "", ""
}

func init() {
_ = os.MkdirAll(engine.DataFolder()+"wives", 0755)
cards := []string{}
engine.OnFullMatch("抽老婆", fcext.DoOnceOnSuccess(
func(ctx *zero.Ctx) bool {
data, err := engine.GetLazyData("wife.json", true)
Expand All @@ -43,22 +56,28 @@ func init() {
Handle(func(ctx *zero.Ctx) {
card := cards[fcext.RandSenderPerDayN(ctx.Event.UserID, len(cards))]
data, err := engine.GetLazyData("wives/"+card, true)
card, _, _ = strings.Cut(card, ".")
var msgText string
work, name := card2name(card)
if work != "" && name != "" {
msgText = fmt.Sprintf("今天的二次元老婆是~来自【%s】的【%s】哒", work, name)
} else {
msgText = fmt.Sprintf("今天的二次元老婆是~【%s】哒", card)
}
if err != nil {
ctx.SendChain(
message.At(ctx.Event.UserID),
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片下载失败: ", err, "】"),
message.Text(msgText, "\n【图片下载失败: ", err, "】"),
)
return
}
if id := ctx.SendChain(
message.At(ctx.Event.UserID),
message.Text("今天的二次元老婆是~【", card, "】哒"),
message.Text(msgText),
message.ImageBytes(data),
); id.ID() == 0 {
ctx.SendChain(
message.At(ctx.Event.UserID),
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片发送失败, 请联系维护者】"),
message.Text(msgText, "\n【图片发送失败, 多半是被夹了,请联系维护者】"),
)
}
})
Expand Down
213 changes: 213 additions & 0 deletions plugin/wife/wifegame.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
// Package wife 抽老婆
package wife

import (
"errors"
"image/color"
"io/fs"
"math/rand"
"os"
"strings"
"time"

"github.com/FloatTech/floatbox/file"
"github.com/FloatTech/gg"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/extension/single"
"github.com/wdvxdr1123/ZeroBot/message"

zbmath "github.com/FloatTech/floatbox/math"
"github.com/FloatTech/imgfactory"
)

var (
sizeList = []int{0, 3, 5, 8}
enguess = control.Register("wifegame", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Help: "- 猜老婆",
Brief: "从老婆库猜老婆",
}).ApplySingle(single.New(
single.WithKeyFn(func(ctx *zero.Ctx) int64 {
if ctx.Event.GroupID != 0 {
return ctx.Event.GroupID
}
return -ctx.Event.UserID
}),
single.WithPostFn[int64](func(ctx *zero.Ctx) {
ctx.Send(
message.ReplyWithMessage(ctx.Event.MessageID,
message.Text("已经有正在进行的游戏..."),
),
)
}),
))
)

func init() {
// _ = os.MkdirAll(engine.DataFolder()+"wives", 0755)
enguess.OnFullMatch("猜老婆").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
var err error
class := 3

fileName, err := lottery()
if err != nil {
ctx.SendChain(message.Text("[猜老婆]error:\n", err))
return
}

work, name := card2name(fileName)
picFile := file.BOTPATH + "/" + engine.DataFolder() + "wives/" + fileName
pic, err := os.ReadFile(picFile)
if err != nil {
ctx.SendChain(message.Text("[猜老婆]error:\n", err))
return
}
img, err := gg.LoadImage(picFile)
if err != nil {
ctx.SendChain(message.Text("[猜老婆]error:\n", err))
return
}
dst := imgfactory.Size(img, img.Bounds().Dx(), img.Bounds().Dy())
q, err := mosaic(dst, class)
if err != nil {
ctx.SendChain(
message.Reply(ctx.Event.MessageID),
message.Text("[猜老婆]图片生成失败:\n", err),
)
return
}
if id := ctx.SendChain(
message.ImageBytes(q),
); id.ID() != 0 {
ctx.SendChain(message.Text("请回答该二次元角色名字\n以“xxx酱”格式回答"))
}
var next *zero.FutureEvent
if ctx.Event.GroupID == 0 {
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`(·)?.+酱$`), ctx.CheckSession())
} else {
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`(·)?.+酱$`), zero.CheckGroup(ctx.Event.GroupID))
}
recv, cancel := next.Repeat()
defer cancel()
tick := time.NewTimer(105 * time.Second)
after := time.NewTimer(120 * time.Second)
for {
select {
case <-tick.C:
ctx.SendChain(message.Text("[猜老婆]你还有15s作答时间"))
case <-after.C:
ctx.Send(
message.ReplyWithMessage(ctx.Event.MessageID,
message.ImageBytes(pic),
message.Text("[猜老婆]倒计时结束,游戏结束...\n角色是:\n", name, "\n出自《", work, "》\n"),
),
)
return
case c := <-recv:
tick.Reset(105 * time.Second)
after.Reset(120 * time.Second)
msg := c.Event.Message.String()
msg, _, _ = strings.Cut(msg, "酱")
class--
if strings.Contains(name, msg) {
if msgID := ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
message.Text("太棒了,你猜对了!\n角色是:\n", name, "\n出自《", work, "》\n"),
message.ImageBytes(pic))); msgID.ID() == 0 {
ctx.SendChain(message.Text("太棒了,你猜对了!\n图片发送失败,可能被风控\n角色是:\n", name, "\n出自《", work, "》"))
}
return
}
if class < 1 {
if msgID := ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
message.Text("很遗憾,次数到了,游戏结束!\n角色是:\n", name, "\n出自《", work, "》\n"),
message.ImageBytes(pic))); msgID.ID() == 0 {
ctx.SendChain(message.Text("很遗憾,次数到了,游戏结束!\n图片发送失败,可能被风控\n角色是:\n", name, "\n出自《", work, "》"))
}
return
}
q, err = mosaic(dst, class)
if err != nil {
ctx.SendChain(
message.Text("回答错误,你还有", class, "次机会\n请继续作答\n(提示:", work, ")"),
)
continue
}
ctx.SendChain(
message.Text("回答错误,你还有", class, "次机会\n请继续作答(难度降低)\n"),
message.ImageBytes(q),
)
continue
}
}
})
}

// 从本地图库随机抽取,规避网络问题
func lottery() (fileName string, err error) {
path := engine.DataFolder() + "wives" + "/"
if file.IsNotExist(path) {
err = errors.New("图库文件夹不存在,请先发送“抽老婆”扩展图库")
return
}
files, err := os.ReadDir(path)
if err != nil {
return
}
// 如果本地列表为空
if len(files) == 0 {
err = errors.New("本地数据为0,请先发送“抽老婆”扩展图库")
return
}
fileName = randPicture(files, 10)
if fileName == "" {
err = errors.New("抽取图库轮空了,请重试")
}
return
}

func randPicture(files []fs.DirEntry, indexMax int) (fileName string) {
if len(files) > 1 {
picture := files[rand.Intn(len(files))]
// 如果是文件夹就递归
if picture.IsDir() {
indexMax--
if indexMax <= 0 {
return
}
fileName = randPicture(files, indexMax)
} else {
fileName = picture.Name()
}
} else {
music := files[0]
if !music.IsDir() {
fileName = files[0].Name()
}
}
return
}

// 马赛克生成
func mosaic(dst *imgfactory.Factory, level int) ([]byte, error) {
b := dst.Image().Bounds()
p := imgfactory.NewFactoryBG(dst.W(), dst.H(), color.NRGBA{255, 255, 255, 255})
markSize := zbmath.Max(b.Max.X, b.Max.Y) * sizeList[level] / 200

for yOfMarknum := 0; yOfMarknum <= zbmath.Ceil(b.Max.Y, markSize); yOfMarknum++ {
for xOfMarknum := 0; xOfMarknum <= zbmath.Ceil(b.Max.X, markSize); xOfMarknum++ {
a := dst.Image().At(xOfMarknum*markSize+markSize/2, yOfMarknum*markSize+markSize/2)
cc := color.NRGBAModel.Convert(a).(color.NRGBA)
for y := 0; y < markSize; y++ {
for x := 0; x < markSize; x++ {
xOfPic := xOfMarknum*markSize + x
yOfPic := yOfMarknum*markSize + y
p.Image().Set(xOfPic, yOfPic, cc)
}
}
}
}
return imgfactory.ToBytes(p.Blur(3).Image())
}
Loading