diff --git a/.github/workflows/pull.yml b/.github/workflows/pull.yml
index 52b6d117c0..844d450d44 100644
--- a/.github/workflows/pull.yml
+++ b/.github/workflows/pull.yml
@@ -29,7 +29,9 @@ jobs:
go-version: '1.20'
- name: Check out code into the Go module directory
- uses: actions/checkout@master
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
- name: golangci-lint
uses: golangci/golangci-lint-action@master
diff --git a/.golangci.yml b/.golangci.yml
index c464edfc74..e300f5612f 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -61,7 +61,8 @@ run:
# output configuration options
output:
- formats: ["colored-line-number"]
+ formats:
+ - format: "colored-line-number"
print-issued-lines: true
print-linter-name: true
uniq-by-line: true
diff --git a/README.md b/README.md
index 565835e8e2..5d2a092afb 100644
--- a/README.md
+++ b/README.md
@@ -900,7 +900,7 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 钓鱼商店
- [x] 购买xxx [数量]
- - [x] 出售xxx [数量]
+ - [x] 出售[xxx [数量]|所有垃圾]
- [x] 钓鱼背包
- [x] 装备[xx竿|三叉戟|美西螈]
- [x] 附魔[诱钓|海之眷顾]
@@ -1069,6 +1069,14 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 解签
+
+
+ 抽扑克
+
+ `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/poker"`
+
+ - [x] 抽扑克牌
+
一群一天一夫一妻制群老婆
@@ -1135,6 +1143,14 @@ print("run[CQ:image,file="+j["img"]+"]")
- 注:本插件来源于[tgbot](https://github.com/YukariChiba/tgbot/blob/main/modules/Reborn.py)
+
+
+ 打劫
+
+`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/robbery"`
+
+- [x] 打劫[对方Q号|@对方QQ]
+
在线代码运行
diff --git a/data b/data
index 9b983625ca..69b0c8a9fc 160000
--- a/data
+++ b/data
@@ -1 +1 @@
-Subproject commit 9b983625cad379783e3f9cda8026f9a7a6c38132
+Subproject commit 69b0c8a9fc24214db185aeccd6836ee9d38e7c3a
diff --git a/main.go b/main.go
index 929d8c778c..8c48fb8742 100644
--- a/main.go
+++ b/main.go
@@ -115,10 +115,12 @@ import (
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/nsfw" // nsfw图片识别
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/nwife" // 本地老婆
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/omikuji" // 浅草寺求签
+ // _ "github.com/FloatTech/ZeroBot-Plugin/plugin/poker" // 抽扑克
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife" // 一群一天一夫一妻制群老婆
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/qzone" // qq空间表白墙
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan" // realcugan清晰术
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/reborn" // 投胎
+ // _ "github.com/FloatTech/ZeroBot-Plugin/plugin/robbery" // 打劫群友的ATRI币
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode" // 在线运行代码
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/saucenao" // 以图搜图
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/score" // 分数
diff --git a/plugin/dish/dish.go b/plugin/dish/dish.go
index dd70295e85..6fd9985837 100644
--- a/plugin/dish/dish.go
+++ b/plugin/dish/dish.go
@@ -77,7 +77,8 @@ func init() {
}
var d dish
- if err := db.Find("dish", &d, fmt.Sprintf("WHERE name like %%%s%%", dishName)); err != nil {
+ if err := db.Find("dish", &d, fmt.Sprintf("WHERE name like '%%%s%%'", dishName)); err != nil {
+ ctx.SendChain(message.Text("客官,本店没有" + dishName))
return
}
@@ -86,7 +87,7 @@ func init() {
"原材料:%s\n"+
"步骤:\n"+
"%s",
- name, dishName, d.Materials, d.Steps),
+ name, d.Name, d.Materials, d.Steps),
))
})
@@ -96,7 +97,7 @@ func init() {
return
}
- name := ctx.NickName()
+ name := ctx.CardOrNickName(ctx.Event.UserID)
var d dish
if err := db.Pick("dish", &d); err != nil {
ctx.SendChain(message.Text("小店好像出错了,暂时端不出菜来惹"))
diff --git a/plugin/gif/context.go b/plugin/gif/context.go
index 74613bc69a..a1161053fc 100644
--- a/plugin/gif/context.go
+++ b/plugin/gif/context.go
@@ -87,13 +87,13 @@ func dlrange(prefix string, end int, wg *sync.WaitGroup, exit func(error)) []str
}
// 新的上下文
-func newContext(user int64) *context {
+func newContext(user int64, atUser int64) *context {
c := new(context)
- c.usrdir = datapath + "users/" + strconv.FormatInt(user, 10) + `/`
+ c.usrdir = datapath + "users/" + strconv.FormatInt(atUser, 10) + `/`
_ = os.MkdirAll(c.usrdir, 0755)
c.headimgsdir = make([]string, 2)
- c.headimgsdir[0] = c.usrdir + "0.gif"
- c.headimgsdir[1] = c.usrdir + "1.gif"
+ c.headimgsdir[0] = datapath + "users/" + strconv.FormatInt(atUser, 10) + ".gif"
+ c.headimgsdir[1] = datapath + "users/" + strconv.FormatInt(user, 10) + ".gif"
return c
}
diff --git a/plugin/gif/logo.go b/plugin/gif/logo.go
index 3d78726072..f0fe05b654 100644
--- a/plugin/gif/logo.go
+++ b/plugin/gif/logo.go
@@ -14,9 +14,9 @@ func (cc *context) prepareLogos(s ...string) error {
for i, v := range s {
_, err := strconv.Atoi(v)
if err != nil {
- err = file.DownloadTo("https://gchat.qpic.cn/gchatpic_new//--"+strings.ToUpper(v)+"/0", cc.usrdir+strconv.Itoa(i)+".gif")
+ err = file.DownloadTo("https://gchat.qpic.cn/gchatpic_new//--"+strings.ToUpper(v)+"/0", cc.headimgsdir[i])
} else {
- err = file.DownloadTo("http://q4.qlogo.cn/g?b=qq&nk="+v+"&s=640", cc.usrdir+strconv.Itoa(i)+".gif")
+ err = file.DownloadTo("http://q4.qlogo.cn/g?b=qq&nk="+v+"&s=640", cc.headimgsdir[i])
}
if err != nil {
return err
diff --git a/plugin/gif/run.go b/plugin/gif/run.go
index bf9f036e3a..04524c2cd1 100644
--- a/plugin/gif/run.go
+++ b/plugin/gif/run.go
@@ -152,8 +152,9 @@ func init() { // 插件主体
datapath = file.BOTPATH + "/" + en.DataFolder()
en.OnRegex(`^(` + strings.Join(cmd, "|") + `)[\s\S]*?(\[CQ:(image\,file=([0-9a-zA-Z]{32}).*|at.+?(\d{5,11}))\].*|(\d+))$`).
SetBlock(true).Handle(func(ctx *zero.Ctx) {
- c := newContext(ctx.Event.UserID)
list := ctx.State["regex_matched"].([]string)
+ atUserID, _ := strconv.ParseInt(list[4]+list[5]+list[6], 10, 64)
+ c := newContext(ctx.Event.UserID, atUserID)
err := c.prepareLogos(list[4]+list[5]+list[6], strconv.FormatInt(ctx.Event.UserID, 10))
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
diff --git a/plugin/guessmusic/guessmusic.go b/plugin/guessmusic/guessmusic.go
index 34dc920a6b..07de481406 100644
--- a/plugin/guessmusic/guessmusic.go
+++ b/plugin/guessmusic/guessmusic.go
@@ -109,6 +109,12 @@ func init() {
ctx.SendChain(message.Text(err))
return
}
+ // 猜歌环节-提供猜歌选项
+ files, err := os.ReadDir(pathOfMusic)
+ if err != nil {
+ return
+ }
+ getMusicSelect(ctx, files, musicName)
// 进行猜歌环节
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + outputPath + "0.wav"))
var next *zero.FutureEvent
@@ -221,26 +227,8 @@ func musicLottery(musicPath, listName string) (pathOfMusic, musicName string, er
}
return
}
- // 进行随机抽取
- if playlistID == 0 || !cfg.API {
- musicName = getLocalMusic(files, 10)
- } else {
- switch rand.Intn(3) { // 三分二概率抽取API的
- case 1:
- musicName = getLocalMusic(files, 10)
- default:
- if cfg.APIURL == "" {
- // 如果没有配置过API地址,尝试连接独角兽
- musicName, err = downloadByOvooa(playlistID, pathOfMusic)
- } else {
- // 从API中抽取歌曲
- musicName, err = drawByAPI(playlistID, pathOfMusic)
- }
- if err != nil {
- musicName = getLocalMusic(files, 10)
- }
- }
- }
+ // 只猜本地已经下好的歌曲
+ musicName = getLocalMusic(files, 10)
if musicName == "" {
err = errors.New("抽取歌曲轮空了,请重试")
}
@@ -295,15 +283,13 @@ func cutMusic(musicName, pathOfMusic, outputPath string) (err error) {
// 数据匹配(结果信息,答题次数,提示次数,是否结束游戏)
func gameMatch(c *zero.Ctx, beginner int64, musicInfo []string, answerTimes, tickTimes int) (message.MessageSegment, int, int, bool) {
answer := strings.Replace(c.Event.Message.String(), "-", "", 1)
- // 大小写,简繁体转换
+ // 回答内容转小写,比对时再把标准答案转小写
answer = ConvertText(answer)
- for i, element := range musicInfo {
- musicInfo[i] = ConvertText(element)
- }
+
switch {
case answer == "取消":
if c.Event.UserID == beginner {
- return message.Text("游戏已取消,猜歌答案是\n", musicInfo[len(musicInfo)-1], "\n\n\n下面欣赏猜歌的歌曲"), answerTimes, tickTimes, true
+ return message.Text("游戏已取消,猜歌答案是\n", musicInfo[len(musicInfo)-1], "\n\n下面欣赏猜歌的歌曲"), answerTimes, tickTimes, true
}
return message.Text("你无权限取消"), answerTimes, tickTimes, false
case answer == "提示":
@@ -312,11 +298,11 @@ func gameMatch(c *zero.Ctx, beginner int64, musicInfo []string, answerTimes, tic
return message.Text("已经没有提示了哦"), answerTimes, tickTimes, false
}
return message.Text("再听这段音频,要仔细听哦"), answerTimes, tickTimes, false
- case strings.Contains(musicInfo[0], answer) || strings.EqualFold(musicInfo[0], answer):
+ case strings.Contains(ConvertText(musicInfo[0]), answer) || strings.EqualFold(ConvertText(musicInfo[0]), answer):
return message.Text("太棒了,你猜对歌曲名了!答案是\n", musicInfo[len(musicInfo)-1], "\n\n下面欣赏猜歌的歌曲"), answerTimes, tickTimes, true
- case strings.Contains(musicInfo[1], answer) || strings.EqualFold(musicInfo[1], answer):
+ case strings.Contains(ConvertText(musicInfo[1]), answer) || strings.EqualFold(ConvertText(musicInfo[1]), answer):
return message.Text("太棒了,你猜对歌手名了!答案是\n", musicInfo[len(musicInfo)-1], "\n\n下面欣赏猜歌的歌曲"), answerTimes, tickTimes, true
- case len(musicInfo) == 4 && (strings.Contains(musicInfo[2], answer) || strings.EqualFold(musicInfo[2], answer)):
+ case len(musicInfo) == 4 && (strings.Contains(ConvertText(musicInfo[2]), answer) || strings.EqualFold(ConvertText(musicInfo[2]), answer)):
return message.Text("太棒了,你猜对相关信息了!答案是\n", musicInfo[len(musicInfo)-1], "\n\n下面欣赏猜歌的歌曲"), answerTimes, tickTimes, true
default:
answerTimes++
@@ -343,3 +329,39 @@ func ConvertText(input string) string {
}
return toLower
}
+
+func getMusicSelect(ctx *zero.Ctx, files []fs.DirEntry, musicName string) {
+ // 生成音乐选项
+ var musicInfo []string
+ musicInfo = append(musicInfo, musicName)
+ for i := 1; i < 4; i++ {
+ musicInfo = append(musicInfo, getLocalMusic(files, 10))
+ for musicInfo[0] == musicInfo[i] {
+ musicInfo[i] = getLocalMusic(files, 10)
+ }
+ }
+ // 对调正确答案
+ j := rand.Intn(len(musicInfo))
+ musicInfo[0], musicInfo[j] = musicInfo[j], musicInfo[0]
+
+ musicNameSelect := "请选出正确歌曲:\n"
+ for i := 0; i < len(musicInfo); i++ {
+ // 解析歌曲信息
+ music := strings.Split(musicInfo[i], ".")
+ // 获取音乐后缀
+ musicType := music[len(music)-1]
+ if !strings.Contains(musictypelist, musicType) {
+ ctx.SendChain(message.Text("抽取到了歌曲:\n",
+ musicInfo[i], "\n该歌曲不是音乐后缀,请联系bot主人修改"))
+ }
+ // 获取音乐信息
+ musicInfo := strings.Split(strings.ReplaceAll(musicInfo[i], "."+musicType, ""), " - ")
+ infoNum := len(musicInfo)
+ if infoNum == 1 {
+ ctx.SendChain(message.Text("抽取到了歌曲:\n",
+ musicInfo[i], "\n该歌曲命名不符合命名规则,请联系bot主人修改"))
+ }
+ musicNameSelect += musicInfo[0] + " 歌手:" + musicInfo[1] + "\n"
+ }
+ ctx.SendChain(message.Text(musicNameSelect))
+}
diff --git a/plugin/guessmusic/main.go b/plugin/guessmusic/main.go
index 061a94b352..211da1279c 100644
--- a/plugin/guessmusic/main.go
+++ b/plugin/guessmusic/main.go
@@ -32,7 +32,7 @@ var (
cfg config
// 插件主体
engine = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
- DisableOnDefault: false,
+ DisableOnDefault: true,
Brief: "猜歌插件",
Help: "------bot主人指令------\n" +
"- 设置猜歌歌库路径 [绝对路径]\n" +
diff --git a/plugin/mcfish/main.go b/plugin/mcfish/main.go
index 150263db3f..8b58a58585 100644
--- a/plugin/mcfish/main.go
+++ b/plugin/mcfish/main.go
@@ -131,7 +131,7 @@ var (
DisableOnDefault: false,
Brief: "钓鱼",
Help: "一款钓鱼模拟器\n----------指令----------\n" +
- "- 钓鱼看板/钓鱼商店\n- 购买xxx\n- 购买xxx [数量]\n- 出售xxx\n- 出售xxx [数量]\n" +
+ "- 钓鱼看板/钓鱼商店\n- 购买xxx\n- 购买xxx [数量]\n- 出售xxx\n- 出售xxx [数量]\n- 出售所有垃圾\n" +
"- 钓鱼背包\n- 装备[xx竿|三叉戟|美西螈]\n- 附魔[诱钓|海之眷顾]\n- 修复鱼竿\n- 合成[xx竿|三叉戟]\n- 消除[绑定|宝藏]诅咒\n- 消除[绑定|宝藏]诅咒 [数量]\n" +
"- 进行钓鱼\n- 进行n次钓鱼\n- 当前装备概率明细\n" +
"规则V" + version + ":\n" +
@@ -530,6 +530,26 @@ func (sql *fishdb) getNumberFor(uid int64, thing string) (number int, err error)
return
}
+// 获取用户的某类物品信息
+func (sql *fishdb) getUserTypeInfo(uid int64, thingType string) (thingInfos []article, err error) {
+ name := strconv.FormatInt(uid, 10) + "Pack"
+ sql.Lock()
+ defer sql.Unlock()
+ userInfo := article{}
+ err = sql.db.Create(name, &userInfo)
+ if err != nil {
+ return
+ }
+ if !sql.db.CanFind(name, "where Type = '"+thingType+"'") {
+ return
+ }
+ err = sql.db.FindFor(name, &userInfo, "where Type = '"+thingType+"'", func() error {
+ thingInfos = append(thingInfos, userInfo)
+ return nil
+ })
+ return
+}
+
/*********************************************************/
/************************商店相关函数***********************/
/*********************************************************/
diff --git a/plugin/mcfish/store.go b/plugin/mcfish/store.go
index a7d5935436..85e90dc2a6 100644
--- a/plugin/mcfish/store.go
+++ b/plugin/mcfish/store.go
@@ -306,6 +306,77 @@ func init() {
}
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("出售成功,你赚到了", pice*number, msg)))
})
+ engine.OnRegex(`^出售所有垃圾`, getdb, refreshFish).SetBlock(true).Limit(limitSet).Handle(func(ctx *zero.Ctx) {
+ uid := ctx.Event.UserID
+
+ articles, err := dbdata.getUserTypeInfo(uid, "waste")
+ if err != nil {
+ ctx.SendChain(message.Text("[ERROR]:获取背包信息错误", err))
+ return
+ }
+ if len(articles) == 0 {
+ ctx.SendChain(message.Text("你的背包不存在该物品"))
+ return
+ }
+ if len(articles) > 1 {
+ msg := make(message.Message, 0, 3+len(articles))
+ msg = append(msg, message.Reply(ctx.Event.MessageID), message.Text("找到以下物品:\n"))
+ for i, info := range articles {
+ msg = append(msg, message.Text(
+ "[", i, "]", info.Name, " 数量: ", info.Number, "\n"))
+ }
+ ctx.Send(msg)
+ }
+
+ pice := 0
+ for _, info := range articles {
+ pice += (priceList[info.Name] * discountList[info.Name] / 100) * info.Number * 8 / 10
+ }
+
+ ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("是否接受商店将以", pice, "收购全部垃圾", "?\n回答\"是\"或\"否\"")))
+ // 等待用户下一步选择
+ recv, cancel1 := zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^(是|否)$`), zero.CheckUser(ctx.Event.UserID)).Repeat()
+ defer cancel1()
+ buy := false
+ for {
+ select {
+ case <-time.After(time.Second * 60):
+ ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("等待超时,取消钓鱼")))
+ return
+ case e := <-recv:
+ nextcmd := e.Event.Message.String()
+ if nextcmd == "否" {
+ ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("已取消出售")))
+ return
+ }
+ buy = true
+ }
+ if buy {
+ break
+ }
+ }
+
+ msg := ""
+ curse, err := dbdata.getNumberFor(uid, "宝藏诅咒")
+ if err != nil {
+ ctx.SendChain(message.Text("[ERROR at store.go.9.3]:", err))
+ return
+ }
+ if curse != 0 {
+ msg = "\n(你身上绑定了" + strconv.Itoa(curse) + "层诅咒)"
+ pice = pice * (100 - 10*curse) / 100
+ }
+
+ for _, info := range articles {
+ info.Number = 0
+ err = dbdata.updateUserThingInfo(uid, info)
+ if err != nil {
+ ctx.SendChain(message.Text("[ERROR at store.go.6]:", err))
+ return
+ }
+ }
+ ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("出售成功,你赚到了", pice, msg)))
+ })
engine.OnRegex(`^购买(`+strings.Join(thingList, "|")+`)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(limitSet).Handle(func(ctx *zero.Ctx) {
uid := ctx.Event.UserID
numberOfPole, err := dbdata.getNumberFor(uid, "竿")
diff --git a/plugin/poker/poker.go b/plugin/poker/poker.go
new file mode 100644
index 0000000000..32def3c247
--- /dev/null
+++ b/plugin/poker/poker.go
@@ -0,0 +1,53 @@
+// Package poker 抽扑克牌
+package poker
+
+import (
+ "encoding/json"
+ "math/rand"
+
+ fcext "github.com/FloatTech/floatbox/ctxext"
+ ctrl "github.com/FloatTech/zbpctrl"
+ "github.com/FloatTech/zbputils/control"
+ "github.com/FloatTech/zbputils/ctxext"
+ zero "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/message"
+)
+
+// 图片来源 https://www.bilibili.com/opus/834601953403076633
+
+var cardImgPathList []string
+
+func init() {
+ engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
+ DisableOnDefault: false,
+ Brief: "抽扑克牌",
+ Help: "- 抽扑克\n- poker",
+ PublicDataFolder: "Poker",
+ }).ApplySingle(ctxext.DefaultSingle)
+
+ getImg := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
+ data, err := engine.GetLazyData("imgdata.json", true)
+ if err != nil {
+ ctx.SendChain(message.Text("ERROR:", err))
+ return false
+ }
+ err = json.Unmarshal(data, &cardImgPathList)
+ if err != nil {
+ ctx.SendChain(message.Text("ERROR:", err))
+ return false
+ }
+ return true
+ })
+
+ engine.OnFullMatchGroup([]string{"抽扑克", "poker"}, getImg).SetBlock(true).
+ Handle(func(ctx *zero.Ctx) {
+ randomIndex := rand.Intn(len(cardImgPathList))
+ randomImgPath := cardImgPathList[randomIndex]
+ imgData, err := engine.GetLazyData(randomImgPath, true)
+ if err != nil {
+ ctx.Send("[poker]读取扑克图片失败")
+ return
+ }
+ ctx.Send(message.ImageBytes(imgData))
+ })
+}
diff --git a/plugin/robbery/robbery.go b/plugin/robbery/robbery.go
new file mode 100644
index 0000000000..a4d3ec8c25
--- /dev/null
+++ b/plugin/robbery/robbery.go
@@ -0,0 +1,173 @@
+// Package robbery 打劫群友 基于“qqwife”插件魔改
+package robbery
+
+import (
+ "math/rand"
+ "strconv"
+ "sync"
+ "time"
+
+ fcext "github.com/FloatTech/floatbox/ctxext"
+ sql "github.com/FloatTech/sqlite"
+ ctrl "github.com/FloatTech/zbpctrl"
+ "github.com/FloatTech/zbputils/control"
+ "github.com/wdvxdr1123/ZeroBot/extension/single"
+
+ "github.com/FloatTech/AnimeAPI/wallet"
+ "github.com/FloatTech/floatbox/math"
+ "github.com/FloatTech/zbputils/ctxext"
+ zero "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/message"
+)
+
+type robberyRepo struct {
+ db *sql.Sqlite
+ sync.RWMutex
+}
+
+type robberyRecord struct {
+ UserID int64 `db:"user_id"` // 劫匪
+ VictimID int64 `db:"victim_id"` // 受害者
+ Time string `db:"time"` // 时间
+}
+
+func init() {
+ police := &robberyRepo{
+ db: &sql.Sqlite{},
+ }
+ engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
+ DisableOnDefault: false,
+ Brief: "打劫别人的ATRI币",
+ Help: "- 打劫[对方Q号|@对方QQ]\n" +
+ "1. 受害者钱包少于1000不能被打劫\n" +
+ "2. 打劫成功率 40%\n" +
+ "4. 打劫失败罚款1000(钱不够不罚钱)\n" +
+ "5. 保险赔付0-80%\n" +
+ "6. 打劫成功获得对方0-5%+500的财产(最高1W)\n" +
+ "7. 每日可打劫或被打劫一次\n" +
+ "8. 打劫失败不计入次数\n",
+ PrivateDataFolder: "robbery",
+ }).ApplySingle(single.New(
+ single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
+ single.WithPostFn[int64](func(ctx *zero.Ctx) {
+ ctx.Send(
+ message.ReplyWithMessage(ctx.Event.MessageID,
+ message.Text("别着急,警察局门口排长队了!"),
+ ),
+ )
+ }),
+ ))
+ getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
+ police.db.DBPath = engine.DataFolder() + "robbery.db"
+ err := police.db.Open(time.Hour)
+ if err == nil {
+ // 创建CD表
+ err = police.db.Create("criminal_record", &robberyRecord{})
+ if err != nil {
+ ctx.SendChain(message.Text("[ERROR]:", err))
+ return false
+ }
+ return true
+ }
+ ctx.SendChain(message.Text("[ERROR]:", err))
+ return false
+ })
+
+ // 打劫功能
+ engine.OnRegex(`^打劫\s?(\[CQ:at,qq=(\d+)\]|(\d+))`, getdb).SetBlock(true).Limit(ctxext.LimitByUser).
+ Handle(func(ctx *zero.Ctx) {
+ uid := ctx.Event.UserID
+ fiancee := ctx.State["regex_matched"].([]string)
+ victimID, _ := strconv.ParseInt(fiancee[2]+fiancee[3], 10, 64)
+ if victimID == uid {
+ ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.At(uid), message.Text("不能打劫自己")))
+ return
+ }
+
+ // 查询记录
+ ok, err := police.getRecord(victimID, uid)
+ if err != nil {
+ ctx.SendChain(message.Text("[ERROR]:", err))
+ return
+ }
+ if !ok {
+ ctx.SendChain(message.Text("你已经打劫过了/对方已经被打劫过了"))
+ return
+ }
+
+ // 穷人保护
+ victimWallet := wallet.GetWalletOf(victimID)
+ if victimWallet < 1000 {
+ ctx.SendChain(message.Text("对方太穷了!打劫失败"))
+ return
+ }
+
+ // 判断打劫是否成功
+ if rand.Intn(100) > 60 {
+ ctx.SendChain(message.Text("打劫失败,罚款1000"))
+ err := wallet.InsertWalletOf(uid, -1000)
+ if err != nil {
+ ctx.SendChain(message.Text("[ERROR]:罚款失败,钱包坏掉力:\n", err))
+ return
+ }
+ return
+ }
+ userIncrMonry := math.Min(rand.Intn(victimWallet/20)+500, 10000)
+ victimDecrMonry := userIncrMonry / (rand.Intn(4) + 1)
+
+ // 记录结果
+ err = wallet.InsertWalletOf(victimID, -victimDecrMonry)
+ if err != nil {
+ ctx.SendChain(message.Text("[ERROR]:钱包坏掉力:\n", err))
+ return
+ }
+ err = wallet.InsertWalletOf(uid, +userIncrMonry)
+ if err != nil {
+ ctx.SendChain(message.Text("[ERROR]:打劫失败,脏款掉入虚无\n", err))
+ return
+ }
+
+ // 写入记录
+ err = police.insertRecord(victimID, uid)
+ if err != nil {
+ ctx.SendChain(message.At(uid), message.Text("[ERROR]:犯罪记录写入失败\n", err))
+ }
+
+ ctx.SendChain(message.At(uid), message.Text("打劫成功,钱包增加:", userIncrMonry, "ATRI币"))
+ ctx.SendChain(message.At(victimID), message.Text("保险公司对您进行了赔付,您实际损失:", victimDecrMonry, "ATRI币"))
+ })
+}
+
+func (sql *robberyRepo) getRecord(victimID, uid int64) (ok bool, err error) {
+ sql.Lock()
+ defer sql.Unlock()
+ // 创建群表格
+ err = sql.db.Create("criminal_record", &robberyRecord{})
+ if err != nil {
+ return false, err
+ }
+ limitID := "where victim_id is " + strconv.FormatInt(victimID, 10) +
+ " or user_id is " + strconv.FormatInt(uid, 10)
+ if !sql.db.CanFind("criminal_record", limitID) {
+ // 没有记录即不用比较
+ return true, nil
+ }
+ cdinfo := robberyRecord{}
+ _ = sql.db.Find("criminal_record", &cdinfo, limitID)
+ if time.Now().Format("2006/01/02") != cdinfo.Time {
+ // // 如果跨天了就删除
+ err = sql.db.Del("criminal_record", limitID)
+ return true, err
+ }
+ return false, nil
+}
+
+func (sql *robberyRepo) insertRecord(vid int64, uid int64) error {
+ sql.Lock()
+ defer sql.Unlock()
+ return sql.db.Insert("criminal_record", &robberyRecord{
+ UserID: uid,
+ VictimID: vid,
+ Time: time.Now().Format("2006/01/02"),
+ })
+}