Skip to content

Commit 7bd1653

Browse files
authored
feat(wife): 增加作品名&猜老婆 (#1208)
1 parent 6c4c6a3 commit 7bd1653

File tree

2 files changed

+240
-8
lines changed

2 files changed

+240
-8
lines changed

plugin/wife/main.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package wife
33

44
import (
55
"encoding/json"
6+
"fmt"
67
"os"
7-
"strings"
8+
"regexp"
89

910
fcext "github.com/FloatTech/floatbox/ctxext"
1011
ctrl "github.com/FloatTech/zbpctrl"
@@ -15,15 +16,27 @@ import (
1516
"github.com/wdvxdr1123/ZeroBot/message"
1617
)
1718

18-
func init() {
19-
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
19+
var (
20+
cards = []string{}
21+
re = regexp.MustCompile(`^\[(.*?)\](.*)\..*$`)
22+
engine = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
2023
DisableOnDefault: false,
2124
Help: "- 抽老婆",
2225
Brief: "从老婆库抽每日老婆",
2326
PublicDataFolder: "Wife",
2427
}).ApplySingle(ctxext.DefaultSingle)
28+
)
29+
30+
func card2name(card string) (string, string) {
31+
match := re.FindStringSubmatch(card)
32+
if len(match) >= 3 {
33+
return match[1], match[2]
34+
}
35+
return "", ""
36+
}
37+
38+
func init() {
2539
_ = os.MkdirAll(engine.DataFolder()+"wives", 0755)
26-
cards := []string{}
2740
engine.OnFullMatch("抽老婆", fcext.DoOnceOnSuccess(
2841
func(ctx *zero.Ctx) bool {
2942
data, err := engine.GetLazyData("wife.json", true)
@@ -43,22 +56,28 @@ func init() {
4356
Handle(func(ctx *zero.Ctx) {
4457
card := cards[fcext.RandSenderPerDayN(ctx.Event.UserID, len(cards))]
4558
data, err := engine.GetLazyData("wives/"+card, true)
46-
card, _, _ = strings.Cut(card, ".")
59+
var msgText string
60+
work, name := card2name(card)
61+
if work != "" && name != "" {
62+
msgText = fmt.Sprintf("今天的二次元老婆是~来自【%s】的【%s】哒", work, name)
63+
} else {
64+
msgText = fmt.Sprintf("今天的二次元老婆是~【%s】哒", card)
65+
}
4766
if err != nil {
4867
ctx.SendChain(
4968
message.At(ctx.Event.UserID),
50-
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片下载失败: ", err, "】"),
69+
message.Text(msgText, "\n【图片下载失败: ", err, "】"),
5170
)
5271
return
5372
}
5473
if id := ctx.SendChain(
5574
message.At(ctx.Event.UserID),
56-
message.Text("今天的二次元老婆是~【", card, "】哒"),
75+
message.Text(msgText),
5776
message.ImageBytes(data),
5877
); id.ID() == 0 {
5978
ctx.SendChain(
6079
message.At(ctx.Event.UserID),
61-
message.Text("今天的二次元老婆是~【", card, "】哒\n【图片发送失败, 请联系维护者】"),
80+
message.Text(msgText, "\n【图片发送失败, 多半是被夹了,请联系维护者】"),
6281
)
6382
}
6483
})

plugin/wife/wifegame.go

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// Package wife 抽老婆
2+
package wife
3+
4+
import (
5+
"errors"
6+
"image/color"
7+
"io/fs"
8+
"math/rand"
9+
"os"
10+
"strings"
11+
"time"
12+
13+
"github.com/FloatTech/floatbox/file"
14+
"github.com/FloatTech/gg"
15+
ctrl "github.com/FloatTech/zbpctrl"
16+
"github.com/FloatTech/zbputils/control"
17+
"github.com/FloatTech/zbputils/ctxext"
18+
zero "github.com/wdvxdr1123/ZeroBot"
19+
"github.com/wdvxdr1123/ZeroBot/extension/single"
20+
"github.com/wdvxdr1123/ZeroBot/message"
21+
22+
zbmath "github.com/FloatTech/floatbox/math"
23+
"github.com/FloatTech/imgfactory"
24+
)
25+
26+
var (
27+
sizeList = []int{0, 3, 5, 8}
28+
enguess = control.Register("wifegame", &ctrl.Options[*zero.Ctx]{
29+
DisableOnDefault: false,
30+
Help: "- 猜老婆",
31+
Brief: "从老婆库猜老婆",
32+
}).ApplySingle(single.New(
33+
single.WithKeyFn(func(ctx *zero.Ctx) int64 {
34+
if ctx.Event.GroupID != 0 {
35+
return ctx.Event.GroupID
36+
}
37+
return -ctx.Event.UserID
38+
}),
39+
single.WithPostFn[int64](func(ctx *zero.Ctx) {
40+
ctx.Send(
41+
message.ReplyWithMessage(ctx.Event.MessageID,
42+
message.Text("已经有正在进行的游戏..."),
43+
),
44+
)
45+
}),
46+
))
47+
)
48+
49+
func init() {
50+
// _ = os.MkdirAll(engine.DataFolder()+"wives", 0755)
51+
enguess.OnFullMatch("猜老婆").SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
52+
var err error
53+
class := 3
54+
55+
fileName, err := lottery()
56+
if err != nil {
57+
ctx.SendChain(message.Text("[猜老婆]error:\n", err))
58+
return
59+
}
60+
61+
work, name := card2name(fileName)
62+
picFile := file.BOTPATH + "/" + engine.DataFolder() + "wives/" + fileName
63+
pic, err := os.ReadFile(picFile)
64+
if err != nil {
65+
ctx.SendChain(message.Text("[猜老婆]error:\n", err))
66+
return
67+
}
68+
img, err := gg.LoadImage(picFile)
69+
if err != nil {
70+
ctx.SendChain(message.Text("[猜老婆]error:\n", err))
71+
return
72+
}
73+
dst := imgfactory.Size(img, img.Bounds().Dx(), img.Bounds().Dy())
74+
q, err := mosaic(dst, class)
75+
if err != nil {
76+
ctx.SendChain(
77+
message.Reply(ctx.Event.MessageID),
78+
message.Text("[猜老婆]图片生成失败:\n", err),
79+
)
80+
return
81+
}
82+
if id := ctx.SendChain(
83+
message.ImageBytes(q),
84+
); id.ID() != 0 {
85+
ctx.SendChain(message.Text("请回答该二次元角色名字\n以“xxx酱”格式回答"))
86+
}
87+
var next *zero.FutureEvent
88+
if ctx.Event.GroupID == 0 {
89+
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`(·)?.+酱$`), ctx.CheckSession())
90+
} else {
91+
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`(·)?.+酱$`), zero.CheckGroup(ctx.Event.GroupID))
92+
}
93+
recv, cancel := next.Repeat()
94+
defer cancel()
95+
tick := time.NewTimer(105 * time.Second)
96+
after := time.NewTimer(120 * time.Second)
97+
for {
98+
select {
99+
case <-tick.C:
100+
ctx.SendChain(message.Text("[猜老婆]你还有15s作答时间"))
101+
case <-after.C:
102+
ctx.Send(
103+
message.ReplyWithMessage(ctx.Event.MessageID,
104+
message.ImageBytes(pic),
105+
message.Text("[猜老婆]倒计时结束,游戏结束...\n角色是:\n", name, "\n出自《", work, "》\n"),
106+
),
107+
)
108+
return
109+
case c := <-recv:
110+
tick.Reset(105 * time.Second)
111+
after.Reset(120 * time.Second)
112+
msg := c.Event.Message.String()
113+
msg, _, _ = strings.Cut(msg, "酱")
114+
class--
115+
if strings.Contains(name, msg) {
116+
if msgID := ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
117+
message.Text("太棒了,你猜对了!\n角色是:\n", name, "\n出自《", work, "》\n"),
118+
message.ImageBytes(pic))); msgID.ID() == 0 {
119+
ctx.SendChain(message.Text("太棒了,你猜对了!\n图片发送失败,可能被风控\n角色是:\n", name, "\n出自《", work, "》"))
120+
}
121+
return
122+
}
123+
if class < 1 {
124+
if msgID := ctx.Send(message.ReplyWithMessage(c.Event.MessageID,
125+
message.Text("很遗憾,次数到了,游戏结束!\n角色是:\n", name, "\n出自《", work, "》\n"),
126+
message.ImageBytes(pic))); msgID.ID() == 0 {
127+
ctx.SendChain(message.Text("很遗憾,次数到了,游戏结束!\n图片发送失败,可能被风控\n角色是:\n", name, "\n出自《", work, "》"))
128+
}
129+
return
130+
}
131+
q, err = mosaic(dst, class)
132+
if err != nil {
133+
ctx.SendChain(
134+
message.Text("回答错误,你还有", class, "次机会\n请继续作答\n(提示:", work, ")"),
135+
)
136+
continue
137+
}
138+
ctx.SendChain(
139+
message.Text("回答错误,你还有", class, "次机会\n请继续作答(难度降低)\n"),
140+
message.ImageBytes(q),
141+
)
142+
continue
143+
}
144+
}
145+
})
146+
}
147+
148+
// 从本地图库随机抽取,规避网络问题
149+
func lottery() (fileName string, err error) {
150+
path := engine.DataFolder() + "wives" + "/"
151+
if file.IsNotExist(path) {
152+
err = errors.New("图库文件夹不存在,请先发送“抽老婆”扩展图库")
153+
return
154+
}
155+
files, err := os.ReadDir(path)
156+
if err != nil {
157+
return
158+
}
159+
// 如果本地列表为空
160+
if len(files) == 0 {
161+
err = errors.New("本地数据为0,请先发送“抽老婆”扩展图库")
162+
return
163+
}
164+
fileName = randPicture(files, 10)
165+
if fileName == "" {
166+
err = errors.New("抽取图库轮空了,请重试")
167+
}
168+
return
169+
}
170+
171+
func randPicture(files []fs.DirEntry, indexMax int) (fileName string) {
172+
if len(files) > 1 {
173+
picture := files[rand.Intn(len(files))]
174+
// 如果是文件夹就递归
175+
if picture.IsDir() {
176+
indexMax--
177+
if indexMax <= 0 {
178+
return
179+
}
180+
fileName = randPicture(files, indexMax)
181+
} else {
182+
fileName = picture.Name()
183+
}
184+
} else {
185+
music := files[0]
186+
if !music.IsDir() {
187+
fileName = files[0].Name()
188+
}
189+
}
190+
return
191+
}
192+
193+
// 马赛克生成
194+
func mosaic(dst *imgfactory.Factory, level int) ([]byte, error) {
195+
b := dst.Image().Bounds()
196+
p := imgfactory.NewFactoryBG(dst.W(), dst.H(), color.NRGBA{255, 255, 255, 255})
197+
markSize := zbmath.Max(b.Max.X, b.Max.Y) * sizeList[level] / 200
198+
199+
for yOfMarknum := 0; yOfMarknum <= zbmath.Ceil(b.Max.Y, markSize); yOfMarknum++ {
200+
for xOfMarknum := 0; xOfMarknum <= zbmath.Ceil(b.Max.X, markSize); xOfMarknum++ {
201+
a := dst.Image().At(xOfMarknum*markSize+markSize/2, yOfMarknum*markSize+markSize/2)
202+
cc := color.NRGBAModel.Convert(a).(color.NRGBA)
203+
for y := 0; y < markSize; y++ {
204+
for x := 0; x < markSize; x++ {
205+
xOfPic := xOfMarknum*markSize + x
206+
yOfPic := yOfMarknum*markSize + y
207+
p.Image().Set(xOfPic, yOfPic, cc)
208+
}
209+
}
210+
}
211+
}
212+
return imgfactory.ToBytes(p.Blur(3).Image())
213+
}

0 commit comments

Comments
 (0)