From 46e73741fab9d1a26b0b788ed3bb31aaf00454ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sat, 2 Sep 2023 10:07:06 +0800 Subject: [PATCH 01/12] Add files via upload --- plugin/mcfish/fish.go | 327 +++++++++++++++++++++++ plugin/mcfish/main.go | 507 +++++++++++++++++++++++++++++++++++ plugin/mcfish/pack.go | 386 +++++++++++++++++++++++++++ plugin/mcfish/pole.go | 478 +++++++++++++++++++++++++++++++++ plugin/mcfish/store.go | 593 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 2291 insertions(+) create mode 100644 plugin/mcfish/fish.go create mode 100644 plugin/mcfish/main.go create mode 100644 plugin/mcfish/pack.go create mode 100644 plugin/mcfish/pole.go create mode 100644 plugin/mcfish/store.go diff --git a/plugin/mcfish/fish.go b/plugin/mcfish/fish.go new file mode 100644 index 0000000000..5614d20714 --- /dev/null +++ b/plugin/mcfish/fish.go @@ -0,0 +1,327 @@ +// Package mcfish 钓鱼模拟器 +package mcfish + +import ( + "math/rand" + "strconv" + "time" + + "github.com/FloatTech/AnimeAPI/wallet" + "github.com/FloatTech/zbputils/ctxext" + "github.com/sirupsen/logrus" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +func init() { + engine.OnRegex(`^进行(([1-5]\d*)次)?钓鱼$`, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + fishNumber := 1 + info := ctx.State["regex_matched"].([]string)[2] + if info != "" { + number, err := strconv.Atoi(info) + if err != nil || number > 50 { + ctx.SendChain(message.Text("请输入正确的次数")) + return + } + fishNumber = number + } + residue, err := dbdata.updateFishInfo(uid, fishNumber) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.1]:", err)) + return + } + if residue == 0 { + ctx.SendChain(message.Text("今天你已经进行", fishLimit, "次钓鱼了.\n游戏虽好,但请不要沉迷。")) + return + } + fishNumber = residue + equipInfo, err := dbdata.getUserEquip(uid) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.2]:", err)) + return + } + if equipInfo == (equip{}) { + ok, err := dbdata.checkEquipFor(uid) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.2.1]:", err)) + return + } + if !ok { + ctx.SendChain(message.At(uid), message.Text("请装备鱼竿后钓鱼", err)) + return + } + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你尚未装备鱼竿,是否花费100购买鱼竿?\n回答\"是\"或\"否\"")) + // 等待用户下一步选择 + recv, cancel := zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^(是|否)$`), zero.CheckUser(ctx.Event.UserID)).Repeat() + defer cancel() + buy := false + for { + select { + case <-time.After(time.Second * 120): + 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 + } + money := wallet.GetWalletOf(uid) + if money < 100 { + ctx.SendChain(message.Text("你钱包当前只有", money, "ATRI币,无法完成支付")) + return + } + err = wallet.InsertWalletOf(uid, -100) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.3]:", err)) + return + } + equipInfo = equip{ + ID: uid, + Equip: "木竿", + Durable: 30, + } + err = dbdata.updateUserEquip(equipInfo) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.4]:", err)) + return + } + err = dbdata.setEquipFor(uid) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.4]:", err)) + return + } + buy = true + } + if buy { + break + } + } + } else if equipInfo.Durable < fishNumber { + fishNumber = equipInfo.Durable + } + msg := "" + if equipInfo.Equip != "美西螈" { + equipInfo.Durable -= fishNumber + err = dbdata.updateUserEquip(equipInfo) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.5]:", err)) + return + } + if equipInfo.Durable < 10 { + msg = "(你的鱼竿耐久仅剩" + strconv.Itoa(equipInfo.Durable) + ")" + } + } else { + fishNmae, err := dbdata.pickFishFor(uid) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.5.1]:", err)) + return + } + if fishNmae == "" { + equipInfo.Durable = 0 + err = dbdata.updateUserEquip(equipInfo) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.5]:", err)) + } + ctx.SendChain(message.Text("美西螈因为没吃到鱼,钓鱼时一直没回来,你失去了美西螈")) + return + } + msg = "(美西螈吃掉了一条" + fishNmae + ")" + } + waitTime := 120 / (equipInfo.Induce + 1) + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你开始去钓鱼了,请耐心等待鱼上钩(预计要", time.Second*time.Duration(waitTime), ")")) + timer := time.NewTimer(time.Second * time.Duration(rand.Intn(waitTime)+1)) + for { + <-timer.C + timer.Stop() + break + } + // 概率 + wasteProbability := 41 + equipInfo.Favor*10 + poleProbability := 11 + equipInfo.Favor*3 + bookProbability := 1 + equipInfo.Favor*1 + // 钓到鱼的范围 + number, err := dbdata.getNumberFor(uid, "鱼") + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.5.1]:", err)) + return + } + getFishMaxDy := 9 + getFishMinDy := 2 + getFishMaxDx := 9 + getFishMinDx := 1 + if number > 100 || equipInfo.Equip == "美西螈" { + getFishMaxDy = 10 + getFishMinDy = 1 + getFishMaxDx = 10 + getFishMinDx = 0 + } + // 钓鱼结算 + thingNameList := make(map[string]int) + picName := "" + for i := fishNumber; i > 0; i-- { + fishDx := rand.Intn(11) + fishDy := rand.Intn(11) + if fishDx < getFishMinDx || fishDx > getFishMaxDx || fishDy < getFishMinDy || fishDy > getFishMaxDy { + if fishNumber == 1 { + ctx.SendChain(message.At(uid), message.Text("很遗憾你没有钓到鱼", msg)) + return + } + thingNameList["空竿"]++ + continue + } + dice := rand.Intn(100) + switch { + case dice >= wasteProbability: // 垃圾 + waste := wasteList[rand.Intn(len(wasteList))] + money := 10 + if equipInfo.Equip == "美西螈" { + money *= 3 + } + err := wallet.InsertWalletOf(uid, money) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.9]:", err)) + return + } + picName = waste + thingNameList[waste]++ + if fishNumber == 1 { + msg = "为河流净化做出了贡献,\n给予" + strconv.Itoa(money) + "奖励金\n" + msg + } + case dice <= bookProbability: + picName = "book" + thingName := "诱钓" + dice := rand.Intn(100) + switch { + case dice == 0: + picName = "美西螈" + thingName = "美西螈" + case dice == 1: + picName = "唱片" + thingName = "唱片" + case dice < 41 && dice > 1: + thingName = "海之眷顾" + } + books, err := dbdata.getUserThingInfo(uid, thingName) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.6]:", err)) + return + } + if len(books) == 0 { + books = append(books, article{ + Duration: time.Now().Unix()*100 + int64(i), + Type: "article", + Name: thingName, + }) + } + if thingName == "美西螈" { + books[0].Type = "pole" + books[0].Other = "999/0/0/0" + } + number := 1 + if equipInfo.Equip == "美西螈" && thingName != "美西螈" { + number += 2 + } + books[0].Number += number + err = dbdata.updateUserThingInfo(uid, books[0]) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.7]:", err)) + return + } + thingNameList[thingName] += number + case dice > bookProbability && dice <= poleProbability: + poleNmae := "木竿" + dice := rand.Intn(100) + switch { + case dice >= 10 && dice < 30: + poleNmae = "铁竿" + case dice >= 4 && dice < 10: + poleNmae = "金竿" + case dice >= 1 && dice < 4: + poleNmae = "钻石竿" + case dice == 0: + poleNmae = "下界合金竿竿竿" + } + newPole := article{ + Duration: time.Now().Unix()*100 + int64(i), + Type: "pole", + Name: poleNmae, + Number: 1, + Other: strconv.Itoa(rand.Intn(equipAttribute[poleNmae])+1) + + "/" + strconv.Itoa(rand.Intn(10)) + "/" + + strconv.Itoa(rand.Intn(3)) + "/" + strconv.Itoa(rand.Intn(2)), + } + err = dbdata.updateUserThingInfo(uid, newPole) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.8]:", err)) + return + } + picName = poleNmae + thingNameList[poleNmae]++ + default: + fishName := "" + dice = rand.Intn(100) + switch { + case dice == 99: + fishName = "墨鱼" + case dice >= 30 && dice != 99: + fishName = "鳕鱼" + case dice >= 10 && dice < 30: + fishName = "鲑鱼" + case dice >= 4 && dice < 10: + fishName = "热带鱼" + case dice >= 1 && dice < 4: + fishName = "河豚" + default: + fishName = "鹦鹉螺" + } + fishes, err := dbdata.getUserThingInfo(uid, fishName) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.10]:", err)) + return + } + if len(fishes) == 0 { + fishes = append(fishes, article{ + Duration: time.Now().Unix()*100 + int64(i), + Type: "fish", + Name: fishName, + }) + } + number := 1 + if equipInfo.Equip == "美西螈" || equipInfo.Equip == "三叉戟" { + number += 2 + } + fishes[0].Number += number + err = dbdata.updateUserThingInfo(uid, fishes[0]) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.11]:", err)) + return + } + picName = fishName + thingNameList[fishName] += number + } + } + if len(thingNameList) == 1 { + thingName := "" + for name := range thingNameList { + thingName = name + } + pic, err := engine.GetLazyData(picName+".png", false) + if err != nil { + logrus.Warnln("[mcfish]error:", err) + ctx.SendChain(message.At(uid), message.Text("恭喜你钓到了", thingName, "\n", msg)) + return + } + ctx.SendChain(message.At(uid), message.Text("恭喜你钓到了", thingName, "\n", msg), message.ImageBytes(pic)) + return + } + msgInfo := make(message.Message, 0, 3+len(thingNameList)) + msgInfo = append(msgInfo, message.Reply(ctx.Event.MessageID), message.Text("你进行了", fishNumber, "次钓鱼,结果如下:\n")) + for name, number := range thingNameList { + msgInfo = append(msgInfo, message.Text(name, " : ", number, "\n")) + } + msgInfo = append(msgInfo, message.Text(msg)) + ctx.Send(msgInfo) + }) +} diff --git a/plugin/mcfish/main.go b/plugin/mcfish/main.go new file mode 100644 index 0000000000..574f0401f0 --- /dev/null +++ b/plugin/mcfish/main.go @@ -0,0 +1,507 @@ +// Package mcfish 钓鱼模拟器 +package mcfish + +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/FloatTech/zbputils/ctxext" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +type fishdb struct { + db *sql.Sqlite + sync.RWMutex +} + +/* +type userInfo struct { + UserID int64 // QQ + Bait int // 鱼饵 + // 鱼竿 10% 装备/耐久/维修次数/诱钓/眷顾 + WoodenPole string // 木竿属性 70% + IronPole string // 铁竿属性 20% + GoldenPole string // 金竿属性 6% + DiamondPole string // 钻石竿属性 3% + NetherPole string // 下界合金竿属性 1% + // 鱼 30% + Cod int // 鳕鱼数量 69% + Salmon int // 鲑鱼数量 20% + Tropical int // 热带鱼 6% + Globe int // 河豚 3% + Nautilus int // 鹦鹉螺 1% + Nautilus int // 墨鱼1% + // 宝藏 1% + Induce int // 诱钓 59% + Favor int // 眷顾 39% + Record int // 唱片 1% + Record int // 美西螈 1% + // 垃圾 59% + Leaf int // 荷叶 10% + Rod int // 木棍 10% + bamboo int // 竹子 10% + Shoe int // 鞋子 10% + Bottle int // 瓶子 10% + Hanger int // 拌线钩 10% + Bone int // 骨头 10% + Leather int // 皮革 10% + Carrion int // 腐肉 10% + Bowl int // 碗 10% +} +*/ + +type equip struct { + ID int64 // 用户 + Equip string // 装备名称 + Durable int // 耐久 + Maintenance int // 维修次数 + Induce int // 诱钓等级 + Favor int // 眷顾等级 +} + +type article struct { + Duration int64 + Name string + Number int + Other string // 耐久/维修次数/诱钓/眷顾 + Type string +} + +type store struct { + Duration int64 + Name string + Number int + Price int + Other string // 耐久/维修次数/诱钓/眷顾 + Type string +} + +type fishState struct { + ID int64 + Duration int64 + Fish int + Equip int +} + +type storeDiscount struct { + Name string + Discount int +} + +var ( + equipAttribute = map[string]int{ + "木竿": 30, "铁竿": 50, "金竿": 70, "钻石竿": 100, "下界合金竿": 150, "三叉戟": 300, "美西螈": 999, + } + thingPice = map[string]int{ + "鳕鱼": 10, "鲑鱼": 50, "热带鱼": 100, "河豚": 300, "鹦鹉螺": 500, "墨鱼": 500, + "木竿": 100, "铁竿": 300, "金竿": 700, "钻石竿": 1500, "下界合金竿": 3100, "三叉戟": 4000, + "诱钓": 1000, "海之眷顾": 2500, "唱片": 3000, "美西螈": 3000, + } + discount = map[string]int{ + "鳕鱼": 100, "鲑鱼": 100, "热带鱼": 100, "河豚": 100, "鹦鹉螺": 100, "墨鱼": 100, + "木竿": 100, "铁竿": 100, "金竿": 100, "钻石竿": 100, "下界合金竿": 100, "三叉戟": 100, + "诱钓": 100, "海之眷顾": 100, "唱片": 100, "美西螈": 100, + } + fishList = []string{"鳕鱼", "鲑鱼", "热带鱼"} + wasteList = []string{"海草", "木棍", "帽子", "鞋子", "瓶子", "拌线钩", "骨头", "皮革", "腐肉", "碗"} + enchantLevel = []string{"0", "Ⅰ", "Ⅱ", "Ⅲ"} + dbdata = &fishdb{ + db: &sql.Sqlite{}, + } + engine = control.Register("mcfish", &ctrl.Options[*zero.Ctx]{ + DisableOnDefault: false, + Brief: "钓鱼", + Help: "一款钓鱼模拟器\n----------指令----------\n" + + "- 钓鱼看板/钓鱼商店\n- 购买xxx\n- 购买xxx [数量]\n- 出售xxx\n- 出售xxx [数量]\n" + + "- 钓鱼背包\n- 装备[xx竿|三叉戟|美西螈]\n- 附魔[诱钓|海之眷顾]\n- 修复鱼竿\n- 合成[xx竿|三叉戟]\n" + + "- 进行钓鱼\n- 进行n次钓鱼\n" + + "规则:\n1.每日的商店价格是波动的!!如何最大化收益自己考虑一下喔\n" + + "2.装备信息:\n-> 木竿 : 耐久上限:30 均价:100 上钩概率:7%\n-> 铁竿 : 耐久上限:50 均价:300 上钩概率:2%\n-> 金竿 : 耐久上限:70 均价700 上钩概率:0.6%\n" + + "-> 钻石竿 : 耐久上限:100 均价1500 上钩概率:0.3%\n-> 下界合金竿 : 耐久上限:150 均价3100 上钩概率:0.1%\n-> 三叉戟 : 可使钓的鱼类物品数量变成3 耐久上限:300 均价4000 只能合成和交易\n" + + "3.附魔书信息:\n-> 诱钓 : 减少上钩时间. 均价:1000, 上钩概率:0.59%\n-> 海之眷顾 : 增加宝藏上钩概率. 均价:2500, 上钩概率:0.39%\n" + + "4.稀有物品:\n-> 唱片 : 出售物品时使用该物品使价格翻倍. 均价:3000, 上钩概率:0.01%\n-> 美西螈 : 可装备,获得隐形[钓鱼佬]buff,并让钓到除鱼竿和美西螈外的物品数量变成3,无耐久上限.不可修复/附魔,每次钓鱼消耗任意一鱼类物品. 均价:3000, 上钩概率:0.01%\n" + + "5.鱼类信息:\n-> 鳕鱼 : 均价:10 上钩概率:20.7%\n-> 鲑鱼 : 均价:50 上钩概率:6%\n-> 热带鱼 : 均价:100 上钩概率:1.8%\n-> 河豚 : 均价:300 上钩概率:0.9%\n-> 鹦鹉螺 : 均价:500 上钩概率:0.3%\n-> 墨鱼 : 均价:500 上钩概率:0.3%\n" + + "6.物品BUFF:\n-> 钓鱼佬 : 当背包名字含有'鱼'的物品数量超过100时激活,钓到物品概率提高至90%\n-> 修复大师 : 当背包鱼竿数量超过10时激活,修复物品时耐久百分百继承\n" + + "7.合成:\n-> 铁竿 : 3x木竿\n-> 金竿 : 3x铁竿\n-> 钻石竿 : 3x金竿\n-> 下界合金竿 : 3x钻石竿\n-> 三叉戟 : 3x下界合金竿\n注:合成成功率70%,继承附魔等级合/3的等级\n" + + "8.杂项:\n-> 无装备的情况下,每人最多可以购买3次100块钱的鱼竿\n-> 默认状态钓鱼上钩概率为56%\n-> 附魔的鱼竿会因附魔变得昂贵,每个附魔最高3级\n-> 三叉戟不算鱼竿", + PublicDataFolder: "McFish", + }).ApplySingle(ctxext.DefaultSingle) + getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { + dbdata.db.DBPath = engine.DataFolder() + "fishdata.db" + err := dbdata.db.Open(time.Hour * 24) + if err != nil { + ctx.SendChain(message.Text("[ERROR at main.go.1]:", err)) + return false + } + return true + }) + fishLimit = 50 // 钓鱼次数上限 +) + +/* +func init() { + for name := range thingPice { + _, _ = engine.GetLazyData(name+".png", false) + } +} +*/ +// 获取装备信息 +func (sql *fishdb) getUserEquip(uid int64) (userInfo equip, err error) { + sql.Lock() + defer sql.Unlock() + err = sql.db.Create("equips", &userInfo) + if err != nil { + return + } + if !sql.db.CanFind("equips", "where ID = "+strconv.FormatInt(uid, 10)) { + return + } + err = sql.db.Find("equips", &userInfo, "where ID = "+strconv.FormatInt(uid, 10)) + return +} + +// 更新装备信息 +func (sql *fishdb) updateUserEquip(userInfo equip) (err error) { + sql.Lock() + defer sql.Unlock() + err = sql.db.Create("equips", &userInfo) + if err != nil { + return + } + if userInfo.Durable == 0 { + return sql.db.Del("equips", "where ID = "+strconv.FormatInt(userInfo.ID, 10)) + } + return sql.db.Insert("equips", &userInfo) +} + +// 获取用户背包信息 +func (sql *fishdb) getUserPack(uid int64) (thingInfos []article, err error) { + sql.Lock() + defer sql.Unlock() + userInfo := article{} + err = sql.db.Create(strconv.FormatInt(uid, 10)+"Pack", &userInfo) + if err != nil { + return + } + count, err := sql.db.Count(strconv.FormatInt(uid, 10) + "Pack") + if err != nil { + return + } + if count == 0 { + return + } + err = sql.db.FindFor(strconv.FormatInt(uid, 10)+"Pack", &userInfo, "ORDER by Type, Name, Other ASC", func() error { + thingInfos = append(thingInfos, userInfo) + return nil + }) + return +} + +// 获取用户物品信息 +func (sql *fishdb) getUserThingInfo(uid int64, thing 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 + } + count, err := sql.db.Count(name) + if err != nil { + return + } + if count == 0 { + return + } + if !sql.db.CanFind(name, "where Name = '"+thing+"'") { + return + } + err = sql.db.FindFor(name, &userInfo, "where Name = '"+thing+"'", func() error { + thingInfos = append(thingInfos, userInfo) + return nil + }) + return +} + +// 更新用户物品信息 +func (sql *fishdb) updateUserThingInfo(uid int64, userInfo article) (err error) { + name := strconv.FormatInt(uid, 10) + "Pack" + sql.Lock() + defer sql.Unlock() + err = sql.db.Create(name, &userInfo) + if err != nil { + return + } + if userInfo.Number == 0 { + return sql.db.Del(name, "where Duration = "+strconv.FormatInt(userInfo.Duration, 10)) + } + return sql.db.Insert(name, &userInfo) +} + +// 获取商店信息 +func (sql *fishdb) getStoreInfo() (thingInfos []store, err error) { + sql.Lock() + defer sql.Unlock() + thingInfo := store{} + err = sql.db.Create("store", &thingInfo) + if err != nil { + return + } + count, err := sql.db.Count("store") + if err != nil { + return + } + if count == 0 { + return + } + err = sql.db.FindFor("store", &thingInfo, "ORDER by Type, Name, Price ASC", func() error { + thingInfos = append(thingInfos, thingInfo) + return nil + }) + return +} + +// 获取商店物品信息 +func (sql *fishdb) getStoreThingInfo(thing string) (thingInfos []store, err error) { + sql.Lock() + defer sql.Unlock() + thingInfo := store{} + err = sql.db.Create("store", &thingInfo) + if err != nil { + return + } + count, err := sql.db.Count("store") + if err != nil { + return + } + if count == 0 { + return + } + if !sql.db.CanFind("store", "where Name = '"+thing+"'") { + return + } + err = sql.db.FindFor("store", &thingInfo, "where Name = '"+thing+"'", func() error { + thingInfos = append(thingInfos, thingInfo) + return nil + }) + return +} + +// 更新商店信息 +func (sql *fishdb) updateStoreInfo(thingInfo store) (err error) { + sql.Lock() + defer sql.Unlock() + err = sql.db.Create("store", &thingInfo) + if err != nil { + return + } + if thingInfo.Number == 0 { + return sql.db.Del("store", "where Duration = "+strconv.FormatInt(thingInfo.Duration, 10)) + } + return sql.db.Insert("store", &thingInfo) +} + +// 更新上限信息 +func (sql *fishdb) updateFishInfo(uid int64, number int) (residue int, err error) { + sql.Lock() + defer sql.Unlock() + userInfo := fishState{ID: uid} + err = sql.db.Create("fishState", &userInfo) + if err != nil { + return 0, err + } + _ = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10)) + if time.Unix(userInfo.Duration, 0).Day() != time.Now().Day() { + userInfo.Fish = 0 + userInfo.Duration = time.Now().Unix() + } + if userInfo.Fish >= fishLimit { + return 0, nil + } + residue = number + if userInfo.Fish+number > fishLimit { + residue = fishLimit - userInfo.Fish + number = residue + } + userInfo.Fish += number + err = sql.db.Insert("fishState", &userInfo) + return +} + +// 更新上限信息 +func (sql *fishdb) refreshStroeInfo() (ok bool, err error) { + sql.Lock() + defer sql.Unlock() + err = sql.db.Create("stroeDiscount", &storeDiscount{}) + if err != nil { + return false, err + } + lastTime := storeDiscount{} + _ = sql.db.Find("stroeDiscount", &lastTime, "where Name = 'lastTime'") + refresh := false + timeNow := time.Now().Day() + if timeNow != lastTime.Discount { + lastTime = storeDiscount{ + Name: "lastTime", + Discount: timeNow, + } + err = sql.db.Insert("stroeDiscount", &lastTime) + if err != nil { + return false, err + } + refresh = true + } + for name := range thingPice { + thing := storeDiscount{} + switch refresh { + case true: + thingDiscount := 50 + rand.Intn(150) + thing = storeDiscount{ + Name: name, + Discount: thingDiscount, + } + err = sql.db.Insert("stroeDiscount", &thing) + if err != nil { + return + } + default: + err = sql.db.Find("stroeDiscount", &thing, "where Name = '"+name+"'") + if err != nil { + return + } + } + if thing.Discount != 0 { + discount[name] = thing.Discount + } else { + discount[name] = 100 + } + } + if refresh { // 每天调控1种鱼 + thingInfo := store{} + err = sql.db.Create("store", &thingInfo) + if err != nil { + return + } + fish := fishList[rand.Intn(len(fishList))] + _ = sql.db.Find("store", &thingInfo, "where Name = '"+fish+"'") + if thingInfo == (store{}) { + thingInfo.Duration = time.Now().Unix() + thingInfo.Type = "fish" + thingInfo.Name = fish + thingInfo.Price = thingPice[fish] * discount[fish] / 100 + } + thingInfo.Number -= (discount[fish] - 100) + if thingInfo.Number < 1 { + thingInfo.Number = 1 + } + _ = sql.db.Insert("store", &thingInfo) + } + return true, nil +} + +func (sql *fishdb) getNumberFor(uid int64, thing string) (number int, 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 + } + count, err := sql.db.Count(name) + if err != nil { + return + } + if count == 0 { + return + } + if !sql.db.CanFind(name, "where Name glob '*"+thing+"*'") { + return + } + err = sql.db.FindFor(name, &article{}, "where Name glob '*"+thing+"*'", func() error { + number++ + return nil + }) + return +} + +func (sql *fishdb) checkEquipFor(uid int64) (ok bool, err error) { + sql.Lock() + defer sql.Unlock() + userInfo := fishState{ID: uid} + err = sql.db.Create("fishState", &userInfo) + if err != nil { + return false, err + } + if !sql.db.CanFind("fishState", "where ID = "+strconv.FormatInt(uid, 10)) { + return true, nil + } + err = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10)) + if err != nil { + return false, err + } + if userInfo.Equip > 3 { + return false, nil + } + return true, nil +} + +func (sql *fishdb) setEquipFor(uid int64) (err error) { + sql.Lock() + defer sql.Unlock() + userInfo := fishState{ID: uid} + err = sql.db.Create("fishState", &userInfo) + if err != nil { + return err + } + _ = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10)) + if err != nil { + return err + } + userInfo.Equip++ + return sql.db.Insert("fishState", &userInfo) +} + +func (sql *fishdb) pickFishFor(uid int64) (fishName string, 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 + } + count, err := sql.db.Count(name) + if err != nil { + return + } + if count == 0 { + return + } + if !sql.db.CanFind(name, "where Type is 'fish'") { + return + } + fishTypes := make([]article, 0, count) + fishInfo := article{} + err = sql.db.FindFor(name, &fishInfo, "where Type is 'fish'", func() error { + fishTypes = append(fishTypes, fishInfo) + return nil + }) + if err != nil { + return + } + if len(fishTypes) == 0 { + return + } + randNumber := rand.Intn(len(fishTypes)) + fishTypes[randNumber].Number-- + return fishTypes[randNumber].Name, sql.db.Insert(name, &fishTypes[randNumber]) +} diff --git a/plugin/mcfish/pack.go b/plugin/mcfish/pack.go new file mode 100644 index 0000000000..0ec4f5cc53 --- /dev/null +++ b/plugin/mcfish/pack.go @@ -0,0 +1,386 @@ +// Package mcfish 钓鱼模拟器 +package mcfish + +import ( + "bytes" + "errors" + "image" + "image/color" + "strconv" + "strings" + "sync" + + "github.com/FloatTech/AnimeAPI/wallet" + "github.com/FloatTech/floatbox/file" + "github.com/FloatTech/floatbox/math" + "github.com/FloatTech/gg" + "github.com/FloatTech/imgfactory" + "github.com/FloatTech/zbputils/control" + "github.com/FloatTech/zbputils/ctxext" + "github.com/FloatTech/zbputils/img/text" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +func init() { + engine.OnFullMatch("钓鱼背包", getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + equipInfo, err := dbdata.getUserEquip(uid) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pack.go.1]:", err)) + return + } + articles, err := dbdata.getUserPack(uid) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pack.go.2]:", err)) + return + } + pic, err := drawPackImage(uid, equipInfo, articles) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pack.go.3]:", err)) + return + } + ctx.SendChain(message.ImageBytes(pic)) + }) +} + +func drawPackImage(uid int64, equipInfo equip, articles []article) (imagePicByte []byte, err error) { + fontdata, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true) + if err != nil { + return nil, err + } + var ( + wg sync.WaitGroup + equipBlock image.Image // 装备信息 + packBlock image.Image // 背包信息 + ) + wg.Add(1) + // 绘制ID + go func() { + defer wg.Done() + if equipInfo == (equip{}) { + equipBlock, err = drawEquipEmptyBlock(fontdata) + } else { + equipBlock, err = drawEquipInfoBlock(equipInfo, fontdata) + } + if err != nil { + return + } + }() + wg.Add(1) + // 绘制基本信息 + go func() { + defer wg.Done() + if len(articles) == 0 { + packBlock, err = drawArticleEmptyBlock(fontdata) + } else { + packBlock, err = drawArticleInfoBlock(uid, articles, fontdata) + } + if err != nil { + return + } + }() + wg.Wait() + if equipBlock == nil || packBlock == nil { + err = errors.New("生成图片失败,数据缺失") + return + } + // 计算图片高度 + backDX := 1020 + backDY := 10 + equipBlock.Bounds().Dy() + 10 + packBlock.Bounds().Dy() + 10 + canvas := gg.NewContext(backDX, backDY) + + // 画底色 + canvas.DrawRectangle(0, 0, float64(backDX), float64(backDY)) + canvas.SetRGBA255(150, 150, 150, 255) + canvas.Fill() + canvas.DrawRectangle(10, 10, float64(backDX-20), float64(backDY-20)) + canvas.SetRGBA255(255, 255, 255, 255) + canvas.Fill() + + canvas.DrawImage(equipBlock, 10, 10) + canvas.DrawImage(packBlock, 10, 10+equipBlock.Bounds().Dy()+10) + + return imgfactory.ToBytes(canvas.Image()) +} + +// 绘制装备栏区域 +func drawEquipEmptyBlock(fontdata []byte) (image.Image, error) { + canvas := gg.NewContext(1000, 300) + // 画底色 + canvas.DrawRectangle(0, 0, 1000, 300) + canvas.SetRGBA255(255, 255, 255, 150) + canvas.Fill() + // 边框框 + canvas.DrawRectangle(0, 0, 1000, 300) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + + canvas.SetColor(color.Black) + err := canvas.ParseFontFace(fontdata, 100) + if err != nil { + return nil, err + } + textW, textH := canvas.MeasureString("装备信息") + canvas.DrawString("装备信息", 10, 10+textH) + canvas.DrawLine(10, textH*1.2, textW, textH*1.2) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + if err = canvas.ParseFontFace(fontdata, 50); err != nil { + return nil, err + } + canvas.DrawString("没有装备任何鱼竿", 50, 10+textH*2+50) + return canvas.Image(), nil +} +func drawEquipInfoBlock(equipInfo equip, fontdata []byte) (image.Image, error) { + canvas := gg.NewContext(1, 1) + err := canvas.ParseFontFace(fontdata, 100) + if err != nil { + return nil, err + } + _, titleH := canvas.MeasureString("装备信息") + err = canvas.ParseFontFace(fontdata, 50) + if err != nil { + return nil, err + } + _, textH := canvas.MeasureString("装备信息") + + backDY := math.Max(int(10+titleH*2+(textH*2)*4+10), 300) + + canvas = gg.NewContext(1000, backDY) + // 画底色 + canvas.DrawRectangle(0, 0, 1000, float64(backDY)) + canvas.SetRGBA255(255, 255, 255, 150) + canvas.Fill() + // 边框框 + canvas.DrawRectangle(0, 0, 1000, float64(backDY)) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + getAvatar, err := engine.GetLazyData(equipInfo.Equip+".png", false) + if err != nil { + return nil, err + } + equipPic, _, err := image.Decode(bytes.NewReader(getAvatar)) + if err != nil { + return nil, err + } + picDy := float64(backDY) - 10 - titleH*2 + equipPic = imgfactory.Size(equipPic, int(picDy)-10, int(picDy)-10).Image() + canvas.DrawImage(equipPic, 10, 10+int(titleH)*2) + + // 放字 + canvas.SetColor(color.Black) + if err = canvas.ParseFontFace(fontdata, 100); err != nil { + return nil, err + } + titleW, titleH := canvas.MeasureString("装备信息") + canvas.DrawString("装备信息", 10, 10+titleH*1.2) + canvas.DrawLine(10, titleH*1.6, titleW, titleH*1.6) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + + textDx := picDy + 10 + textDy := 10 + titleH*2 + if err = canvas.ParseFontFace(fontdata, 75); err != nil { + return nil, err + } + textW, textH := canvas.MeasureString(equipInfo.Equip) + canvas.DrawStringAnchored(equipInfo.Equip, textDx+textW/2, textDy+textH/2, 0.5, 0.5) + + textDy += textH * 1.5 + if err = canvas.ParseFontFace(fontdata, 50); err != nil { + return nil, err + } + textW, textH = canvas.MeasureString("维修次数") + durable := strconv.Itoa(equipInfo.Durable) + valueW, _ := canvas.MeasureString("100") + barW := 1000 - textDx - textW - 10 - valueW - 10 + + canvas.DrawStringAnchored("装备耐久", textDx+textW/2, textDy+textH/2, 0.5, 0.5) + canvas.DrawRectangle(textDx+textW+5, textDy, barW, textH*1.2) + canvas.SetRGB255(150, 150, 150) + canvas.Fill() + canvas.SetRGB255(0, 0, 0) + durableW := barW * float64(equipInfo.Durable) / float64(equipAttribute[equipInfo.Equip]) + canvas.DrawRectangle(textDx+textW+5, textDy, durableW, textH*1.2) + canvas.SetRGB255(102, 102, 102) + canvas.Fill() + canvas.SetColor(color.Black) + canvas.DrawStringAnchored(durable, textDx+textW+5+barW+5+valueW/2, textDy+textH/2, 0.5, 0.5) + + textDy += textH * 2 + maintenance := strconv.Itoa(equipInfo.Maintenance) + canvas.DrawStringAnchored("维修次数", textDx+textW/2, textDy+textH/2, 0.5, 0.5) + canvas.DrawRectangle(textDx+textW+5, textDy, barW, textH*1.2) + canvas.SetRGB255(150, 150, 150) + canvas.Fill() + canvas.SetRGB255(0, 0, 0) + canvas.DrawRectangle(textDx+textW+5, textDy, barW*float64(equipInfo.Maintenance)/10, textH*1.2) + canvas.SetRGB255(102, 102, 102) + canvas.Fill() + canvas.SetColor(color.Black) + canvas.DrawStringAnchored(maintenance, textDx+textW+5+barW+5+valueW/2, textDy+textH/2, 0.5, 0.5) + + textDy += textH * 3 + canvas.DrawString(" 附魔: 诱钓"+enchantLevel[equipInfo.Induce]+" 海之眷顾"+enchantLevel[equipInfo.Favor], textDx, textDy) + return canvas.Image(), nil +} + +// 绘制背包信息区域 +func drawArticleEmptyBlock(fontdata []byte) (image.Image, error) { + canvas := gg.NewContext(1000, 300) + // 画底色 + canvas.DrawRectangle(0, 0, 1000, 300) + canvas.SetRGBA255(255, 255, 255, 150) + canvas.Fill() + // 边框框 + canvas.DrawRectangle(0, 0, 1000, 300) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + + canvas.SetColor(color.Black) + err := canvas.ParseFontFace(fontdata, 100) + if err != nil { + return nil, err + } + textW, textH := canvas.MeasureString("背包信息") + canvas.DrawString("背包信息", 10, 10+textH*1.2) + canvas.DrawLine(10, textH*1.6, textW, textH*1.6) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + if err = canvas.ParseFontFace(fontdata, 50); err != nil { + return nil, err + } + canvas.DrawStringAnchored("背包没有存放任何东西", 500, 10+textH*2+50, 0.5, 0) + return canvas.Image(), nil +} +func drawArticleInfoBlock(uid int64, articles []article, fontdata []byte) (image.Image, error) { + canvas := gg.NewContext(1, 1) + err := canvas.ParseFontFace(fontdata, 100) + if err != nil { + return nil, err + } + titleW, titleH := canvas.MeasureString("背包信息") + front := 50.0 + err = canvas.ParseFontFace(fontdata, front) + if err != nil { + return nil, err + } + _, textH := canvas.MeasureString("高度") + + nameWOfFiest := 0.0 + nameWOfSecond := 0.0 + for i, info := range articles { + textW, _ := canvas.MeasureString(info.Name + "(" + info.Other + ")") + if i%2 == 0 && textW > nameWOfFiest { + nameWOfFiest = textW + } else if textW > nameWOfSecond { + nameWOfSecond = textW + } + } + valueW, _ := canvas.MeasureString("10000") + + if (10+nameWOfFiest+10+valueW+10)+(10+nameWOfSecond+10+valueW+10) > 980 { + front = 32.0 + err = canvas.ParseFontFace(fontdata, front) + if err != nil { + return nil, err + } + _, textH = canvas.MeasureString("高度") + + nameWOfFiest = 0 + nameWOfSecond = 0 + for i, info := range articles { + textW, _ := canvas.MeasureString(info.Name + "(" + info.Other + ")") + if i%2 == 0 && textW > nameWOfFiest { + nameWOfFiest = textW + } else if textW > nameWOfSecond { + nameWOfSecond = textW + } + } + valueW, _ = canvas.MeasureString("10000") + } + wallW := (980 - (10 + nameWOfFiest + 10 + valueW + 10) - (10 + nameWOfSecond + 10 + valueW + 10)) / 2 + backY := math.Max(10+int(titleH*1.6)+10+int(textH*2)*(math.Ceil(len(articles), 2)+1), 500) + canvas = gg.NewContext(1000, backY) + // 画底色 + canvas.DrawRectangle(0, 0, 1000, float64(backY)) + canvas.SetRGBA255(255, 255, 255, 150) + canvas.Fill() + // 边框框 + canvas.DrawRectangle(0, 0, 1000, float64(backY)) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + + // 放字 + canvas.SetColor(color.Black) + err = canvas.ParseFontFace(fontdata, 100) + if err != nil { + return nil, err + } + canvas.DrawString("背包信息", 10, 10+titleH*1.2) + canvas.DrawLine(10, titleH*1.6, titleW, titleH*1.6) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + + textDy := 10 + titleH*1.7 + if err = canvas.ParseFontFace(fontdata, front); err != nil { + return nil, err + } + canvas.SetColor(color.Black) + numberOfFish := 0 + numberOfEquip := 0 + canvas.DrawStringAnchored("名称", wallW+20+nameWOfFiest/2, textDy+textH/2, 0.5, 0.5) + canvas.DrawStringAnchored("数量", wallW+20+nameWOfFiest+10+valueW/2, textDy+textH/2, 0.5, 0.5) + canvas.DrawStringAnchored("名称", wallW+20+nameWOfFiest+10+valueW+10+10+nameWOfSecond/2, textDy+textH/2, 0.5, 0.5) + canvas.DrawStringAnchored("数量", wallW+20+nameWOfFiest+10+valueW+10+10+nameWOfSecond+10+valueW/2, textDy+textH/2, 0.5, 0.5) + textDy += textH * 2 + for i, info := range articles { + name := info.Name + if info.Other != "" { + numberOfEquip++ + name += "(" + info.Other + ")" + } else if strings.Contains(name, "鱼") { + numberOfFish += info.Number + } + valueStr := strconv.Itoa(info.Number) + if i%2 == 0 { + if i != 0 { + textDy += textH * 2 + } + canvas.DrawStringAnchored(name, wallW+20+nameWOfFiest/2, textDy+textH/2, 0.5, 0.5) + canvas.DrawStringAnchored(valueStr, wallW+20+nameWOfFiest+10+valueW/2, textDy+textH/2, 0.5, 0.5) + } else { + canvas.DrawStringAnchored(name, wallW+20+nameWOfFiest+10+valueW+10+10+nameWOfSecond/2, textDy+textH/2, 0.5, 0.5) + canvas.DrawStringAnchored(valueStr, wallW+20+nameWOfFiest+10+valueW+10+10+nameWOfSecond+10+valueW/2, textDy+textH/2, 0.5, 0.5) + } + } + if err = canvas.ParseFontFace(fontdata, 30); err != nil { + return nil, err + } + textDy = 10 + text := "钱包余额: " + strconv.Itoa(wallet.GetWalletOf(uid)) + textW, textH := canvas.MeasureString(text) + w, _ := canvas.MeasureString("维修大师[已激活]") + if w > textW { + textW = w + } + canvas.DrawStringAnchored(text, 980-textW/2, textDy+textH/2, 0.5, 0.5) + textDy += textH * 1.5 + if numberOfFish > 100 { + canvas.DrawStringAnchored("钓鱼佬[已激活]", 980-textW/2, textDy+textH/2, 0.5, 0.5) + textDy += textH * 1.5 + } + if numberOfEquip > 10 { + canvas.DrawStringAnchored("维修大师[已激活]", 980-textW/2, textDy+textH/2, 0.5, 0.5) + } + return canvas.Image(), nil +} diff --git a/plugin/mcfish/pole.go b/plugin/mcfish/pole.go new file mode 100644 index 0000000000..e4989c742a --- /dev/null +++ b/plugin/mcfish/pole.go @@ -0,0 +1,478 @@ +// Package mcfish 钓鱼模拟器 +package mcfish + +import ( + "math/rand" + "strconv" + "strings" + "time" + + "github.com/FloatTech/zbputils/ctxext" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +func init() { + engine.OnRegex("^装备(.+竿|美西螈|三叉戟)$", getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + equipInfo, err := dbdata.getUserEquip(uid) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.1]:", err)) + return + } + thingName := ctx.State["regex_matched"].([]string)[1] + articles, err := dbdata.getUserThingInfo(uid, thingName) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.2]:", err)) + return + } + if len(articles) == 0 { + ctx.SendChain(message.Text("你的背包不存在该物品")) + return + } + poles := make([]equip, 0, len(articles)) + for _, info := range articles { + poleInfo := strings.Split(info.Other, "/") + durable, _ := strconv.Atoi(poleInfo[0]) + maintenance, _ := strconv.Atoi(poleInfo[1]) + induceLevel, _ := strconv.Atoi(poleInfo[2]) + favorLevel, _ := strconv.Atoi(poleInfo[3]) + poles = append(poles, equip{ + ID: uid, + Equip: info.Name, + Durable: durable, + Maintenance: maintenance, + Induce: induceLevel, + Favor: favorLevel, + }) + } + check := false + index := 0 + if thingName != "美西螈" && len(poles) > 1 { + msg := make(message.Message, 0, 3+len(articles)) + msg = append(msg, message.Reply(ctx.Event.MessageID), message.Text("找到以下鱼竿:\n")) + for i, info := range poles { + msg = append(msg, message.Text("[", i, "] ", info.Equip, " : 耐", info.Durable, "/修", info.Maintenance, + "/诱", enchantLevel[info.Induce], "/眷顾", enchantLevel[info.Favor], "\n")) + } + msg = append(msg, message.Text("————————\n输入对应序号进行装备,或回复“取消”取消")) + ctx.Send(msg) + // 等待用户下一步选择 + recv, cancel := zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^(取消|\d+)$`), zero.CheckUser(ctx.Event.UserID)).Repeat() + defer cancel() + for { + select { + case <-time.After(time.Second * 120): + 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 + } + index, err = strconv.Atoi(nextcmd) + if err != nil || index > len(articles)-1 { + ctx.SendChain(message.At(ctx.Event.UserID), message.Text("请输入正确的序号")) + continue + } + check = true + } + if check { + break + } + } + } + newEquipInfo := poles[index] + packEquip := articles[index] + packEquip.Number-- + err = dbdata.updateUserThingInfo(uid, packEquip) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.3]:", err)) + return + } + err = dbdata.updateUserEquip(newEquipInfo) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.3.1]:", err)) + return + } + oldthing := article{} + if equipInfo != (equip{}) && equipInfo.Equip != "美西螈" { + oldthing = article{ + Duration: time.Now().Unix(), + Type: "pole", + Name: equipInfo.Equip, + Number: 1, + Other: strconv.Itoa(equipInfo.Durable) + "/" + strconv.Itoa(equipInfo.Maintenance) + "/" + strconv.Itoa(equipInfo.Induce) + "/" + strconv.Itoa(equipInfo.Favor), + } + } else if equipInfo.Equip == "美西螈" { + articles, err = dbdata.getUserThingInfo(uid, "美西螈") + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.3.2]:", err)) + return + } + if len(articles) == 0 { + oldthing = article{ + Duration: time.Now().Unix(), + Type: "pole", + Name: equipInfo.Equip, + Number: 1, + Other: strconv.Itoa(equipInfo.Durable) + "/" + strconv.Itoa(equipInfo.Maintenance) + "/" + strconv.Itoa(equipInfo.Induce) + "/" + strconv.Itoa(equipInfo.Favor), + } + } else { + oldthing = articles[0] + oldthing.Number++ + } + } + err = dbdata.updateUserThingInfo(uid, oldthing) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.4]:", err)) + return + } + ctx.Send( + message.ReplyWithMessage(ctx.Event.MessageID, + message.Text("装备成功"), + ), + ) + }) + engine.OnFullMatchGroup([]string{"修复鱼竿", "维修鱼竿"}, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + equipInfo, err := dbdata.getUserEquip(uid) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.5]:", err)) + return + } + if equipInfo.Equip == "" || equipInfo.Equip == "美西螈" || equipInfo.Equip == "三叉戟" { + ctx.SendChain(message.Text("仅能修复装备中的鱼竿")) + return + } + if equipInfo.Maintenance >= 10 { + ctx.SendChain(message.Text("装备的鱼竿已经达到修复上限")) + return + } + articles, err := dbdata.getUserThingInfo(uid, equipInfo.Equip) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.6]:", err)) + return + } + if len(articles) == 0 { + ctx.SendChain(message.Text("你的背包不存在相同鱼竿进行修复")) + return + } + poles := make([]equip, 0, len(articles)) + for _, info := range articles { + poleInfo := strings.Split(info.Other, "/") + durable, _ := strconv.Atoi(poleInfo[0]) + maintenance, _ := strconv.Atoi(poleInfo[1]) + induceLevel, _ := strconv.Atoi(poleInfo[2]) + favorLevel, _ := strconv.Atoi(poleInfo[3]) + poles = append(poles, equip{ + ID: uid, + Equip: info.Name, + Durable: durable, + Maintenance: maintenance, + Induce: induceLevel, + Favor: favorLevel, + }) + } + index := 0 + check := false + if len(articles) > 1 { + msg := make(message.Message, 0, 3+len(articles)) + msg = append(msg, message.Text("找到以下鱼竿:\n")) + for i, info := range poles { + msg = append(msg, message.Text("[", i, "] ", info.Equip, " : 耐", info.Durable, "/修", info.Maintenance, + "/诱", enchantLevel[info.Induce], "/眷顾", enchantLevel[info.Favor], "\n")) + } + msg = append(msg, message.Text("————————\n输入对应序号进行修复,或回复“取消”取消")) + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, msg...)) + // 等待用户下一步选择 + recv, cancel := zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^(取消|\d+)$`), zero.CheckUser(ctx.Event.UserID)).Repeat() + defer cancel() + for { + select { + case <-time.After(time.Second * 120): + 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 + } + index, err = strconv.Atoi(nextcmd) + if err != nil || index > len(articles)-1 { + ctx.SendChain(message.At(ctx.Event.UserID), message.Text("请输入正确的序号")) + continue + } + check = true + } + if check { + break + } + } + } + newEquipInfo := poles[index] + number, err := dbdata.getNumberFor(uid, "竿") + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.5.1]:", err)) + return + } + if number <= 10 { + number = 8 + } else { + number = 10 + } + equipInfo.Durable += newEquipInfo.Durable * number / 10 + if equipInfo.Durable > equipAttribute[equipInfo.Equip] { + equipInfo.Durable = equipAttribute[equipInfo.Equip] + } + msg := "" + if newEquipInfo.Induce != 0 && rand.Intn(100) < 50 { + equipInfo.Induce += newEquipInfo.Induce + if equipInfo.Induce > 3 { + equipInfo.Induce = 3 + } + msg += ",诱钓等级提升至" + enchantLevel[equipInfo.Induce] + } + if newEquipInfo.Favor != 0 && rand.Intn(100) < 50 { + equipInfo.Favor += newEquipInfo.Favor + if equipInfo.Favor > 3 { + equipInfo.Favor = 3 + } + msg += ",海之眷顾等级提升至" + enchantLevel[equipInfo.Favor] + } + thingInfo := articles[index] + thingInfo.Number = 0 + err = dbdata.updateUserThingInfo(uid, thingInfo) + if err == nil { + equipInfo.Maintenance++ + err = dbdata.updateUserEquip(equipInfo) + } + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.7]:", err)) + return + } + ctx.Send( + message.ReplyWithMessage(ctx.Event.MessageID, + message.Text("鱼竿修复成功,耐久提高至", equipInfo.Durable, msg), + ), + ) + }) + engine.OnPrefix("附魔", getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + equipInfo, err := dbdata.getUserEquip(uid) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.7]:", err)) + return + } + if equipInfo.Equip == "" || equipInfo.Equip == "美西螈" { + ctx.SendChain(message.Text("仅可对装备中的进行附魔")) + return + } + book := strings.TrimSpace(ctx.State["args"].(string)) + books, err := dbdata.getUserThingInfo(uid, book) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.8]:", err)) + return + } + if len(books) == 0 { + ctx.SendChain(message.Text("你的背包不存在", book, "进行附魔")) + return + } + bookInfo := books[0] + bookInfo.Number-- + err = dbdata.updateUserThingInfo(uid, bookInfo) + number := 0 + if err == nil { + if rand.Intn(100) > 50 { + ctx.SendChain(message.Text("附魔失败了")) + return + } + switch book { + case "诱钓": + equipInfo.Induce++ + if equipInfo.Induce > 3 { + equipInfo.Induce = 3 + } + number = equipInfo.Induce + case "海之眷顾": + equipInfo.Favor++ + if equipInfo.Favor > 3 { + equipInfo.Favor = 3 + } + number = equipInfo.Favor + default: + ctx.SendChain(message.Text("附魔失败了")) + return + } + err = dbdata.updateUserEquip(equipInfo) + } + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.9]:", err)) + return + } + ctx.SendChain(message.Text("附魔成功,", book, "等级提高至", enchantLevel[number])) + }) + engine.OnRegex(`^合成(.+竿|三叉戟)$`, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + thingList := []string{"木竿", "铁竿", "金竿", "钻石竿", "下界合金竿", "三叉戟"} + thingName := ctx.State["regex_matched"].([]string)[1] + indexOfMaterial := -1 + for i, name := range thingList { + if thingName == name { + indexOfMaterial = (i - 1) + break + } + } + if indexOfMaterial < 0 { + return + } + articles, err := dbdata.getUserThingInfo(uid, thingList[indexOfMaterial]) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.10]:", err)) + return + } + max := len(articles) + if max == 0 { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你的合成材料不足")) + return + } + poles := make([]equip, 0, max) + for _, info := range articles { + poleInfo := strings.Split(info.Other, "/") + durable, _ := strconv.Atoi(poleInfo[0]) + maintenance, _ := strconv.Atoi(poleInfo[1]) + induceLevel, _ := strconv.Atoi(poleInfo[2]) + favorLevel, _ := strconv.Atoi(poleInfo[3]) + poles = append(poles, equip{ + ID: uid, + Equip: info.Name, + Durable: durable, + Maintenance: maintenance, + Induce: induceLevel, + Favor: favorLevel, + }) + } + list := []int{0, 1, 2} + check := false + if len(articles) > 3 { + msg := make(message.Message, 0, 3+len(articles)) + msg = append(msg, message.Text("找到以下鱼竿:\n")) + for i, info := range poles { + msg = append(msg, message.Text("[", i, "] ", info.Equip, " : 耐", info.Durable, "/修", info.Maintenance, + "/诱", enchantLevel[info.Induce], "/眷顾", enchantLevel[info.Favor], "\n")) + } + msg = append(msg, message.Text("————————\n输入3个序号进行合成(用空格分割),或回复“取消”取消")) + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, msg...)) + // 等待用户下一步选择 + recv, cancel := zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^(取消|\d+ \d+ \d+)$`), zero.CheckUser(ctx.Event.UserID)).Repeat() + defer cancel() + for { + select { + case <-time.After(time.Second * 120): + 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 + } + chooseList := strings.Split(nextcmd, " ") + if list[0] == list[1] || list[0] == list[2] || list[1] == list[2] { + ctx.SendChain(message.At(ctx.Event.UserID), message.Text("[0]请输入正确的序号\n", list)) + continue + } + first, err := strconv.Atoi(chooseList[0]) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.11.1]:", err)) + return + } + second, err := strconv.Atoi(chooseList[1]) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.11.2]:", err)) + return + } + third, err := strconv.Atoi(chooseList[2]) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.11.3]:", err)) + return + } + if first > max || second > max || third > max { + ctx.SendChain(message.At(ctx.Event.UserID), message.Text("[", max, "]请输入正确的序号\n", list)) + continue + } + list = []int{first, second, third} + check = true + } + if check { + break + } + } + } + favorLevel := 0 + induceLevel := 0 + for _, index := range list { + thingInfo := articles[index] + thingInfo.Number = 0 + err = dbdata.updateUserThingInfo(uid, thingInfo) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.12]:", err)) + return + } + favorLevel += poles[index].Favor + induceLevel += poles[index].Induce + } + if rand.Intn(10) > 6 { + ctx.Send( + message.ReplyWithMessage(ctx.Event.MessageID, + message.Text("合成失败,材料已销毁"), + ), + ) + return + } + attribute := strconv.Itoa(equipAttribute[thingName]) + "/0/" + strconv.Itoa(induceLevel/3) + "/" + strconv.Itoa(favorLevel/3) + newthing := article{ + Duration: time.Now().Unix(), + Type: "pole", + Name: thingName, + Number: 1, + Other: attribute, + } + err = dbdata.updateUserThingInfo(uid, newthing) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pole.go.12]:", err)) + return + } + ctx.Send( + message.ReplyWithMessage(ctx.Event.MessageID, + message.Text(thingName, "合成成功\n属性: ", attribute), + ), + ) + }) +} diff --git a/plugin/mcfish/store.go b/plugin/mcfish/store.go new file mode 100644 index 0000000000..0591a26fa6 --- /dev/null +++ b/plugin/mcfish/store.go @@ -0,0 +1,593 @@ +// Package mcfish 钓鱼模拟器 +package mcfish + +import ( + "image" + "image/color" + "strconv" + "strings" + "time" + + "github.com/FloatTech/AnimeAPI/wallet" + "github.com/FloatTech/floatbox/file" + "github.com/FloatTech/floatbox/math" + "github.com/FloatTech/gg" + "github.com/FloatTech/imgfactory" + "github.com/FloatTech/zbputils/control" + "github.com/FloatTech/zbputils/ctxext" + "github.com/FloatTech/zbputils/img/text" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +var ( + refresh = false + timeNow = 0 + refreshFish = func(ctx *zero.Ctx) bool { + if refresh && timeNow == time.Now().Day() { + return true + } + refresh, err := dbdata.refreshStroeInfo() + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.1]:", err)) + return refresh + } + timeNow = time.Now().Day() + return refresh + } +) + +func init() { + engine.OnFullMatchGroup([]string{"钓鱼看板", "钓鱼商店"}, getdb, refreshFish).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + infos, err := dbdata.getStoreInfo() + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.2]:", err)) + return + } + var picImage image.Image + if len(infos) == 0 { + picImage, err = drawStroeEmptyImage() + } else { + picImage, err = drawStroeInfoImage(infos) + } + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.3]:", err)) + return + } + pic, err := imgfactory.ToBytes(picImage) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.4]:", err)) + return + } + ctx.SendChain(message.ImageBytes(pic)) + }) + engine.OnRegex(`^出售(.+(竿|鱼)|河豚|鹦鹉螺|诱钓|海之眷顾|唱片|美西螈)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + thingName := ctx.State["regex_matched"].([]string)[1] + number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[3]) + if number == 0 { + number = 1 + } + articles, err := dbdata.getUserThingInfo(uid, thingName) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.5]:", err)) + return + } + if len(articles) == 0 { + ctx.SendChain(message.Text("你的背包不存在该物品")) + return + } + index := 0 + thing := article{} + 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 { + if info.Other != "" { + msg = append(msg, message.Text("[", i, "] ", info.Name, "(", info.Other, ")\n")) + } else { + msg = append(msg, message.Text( + "[", i, "]", info.Name, " 数量: ", info.Number, "\n")) + } + + } + msg = append(msg, message.Reply(ctx.Event.MessageID), message.Text("————————\n输入对应序号进行装备,或回复“取消”取消")) + ctx.Send(msg) + // 等待用户下一步选择 + sell := false + recv, cancel := zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^(取消|\d+)$`), zero.CheckUser(ctx.Event.UserID)).Repeat() + defer cancel() + for { + select { + case <-time.After(time.Second * 120): + 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 + } + index, err = strconv.Atoi(nextcmd) + if err != nil || index > len(articles)-1 { + ctx.SendChain(message.At(ctx.Event.UserID), message.Text("请输入正确的序号")) + continue + } + sell = true + } + if sell { + break + } + } + } + + thing = articles[index] + if thing.Number < number { + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("背包数量不足"))) + return + } + + var pice int + if strings.Contains(thingName, "竿") { + poleInfo := strings.Split(articles[index].Other, "/") + durable, _ := strconv.Atoi(poleInfo[0]) + maintenance, _ := strconv.Atoi(poleInfo[1]) + induceLevel, _ := strconv.Atoi(poleInfo[2]) + favorLevel, _ := strconv.Atoi(poleInfo[3]) + pice = (thingPice[thingName] - (equipAttribute[thingName] - durable) - maintenance*2 + induceLevel*600 + favorLevel*1800) * discount[thingName] / 100 + } else { + pice = thingPice[thingName] * discount[thingName] / 100 + } + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("是否接受商店将以", pice*number*8/10, "收购", number, "个", thingName, "?\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 + } + } + + records, err := dbdata.getUserThingInfo(uid, "唱片") + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.9.1]:", err)) + return + } + if len(records) != 0 { + recordInfo := records[0] + numberOfRecord := recordInfo.Number + if thingName == "唱片" { + numberOfRecord-- + } + if numberOfRecord > 0 { + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("是否使用唱片让价格翻倍?\n回答\"是\"或\"否\""))) + // 等待用户下一步选择 + recv, cancel2 := zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^(是|否)$`), zero.CheckUser(ctx.Event.UserID)).Repeat() + defer cancel2() + use := false + checkTime := false + for { + select { + case <-time.After(time.Second * 60): + checkTime = true + case e := <-recv: + nextcmd := e.Event.Message.String() + if nextcmd == "是" { + use = true + } + checkTime = true + } + if checkTime { + break + } + } + if use { + pice *= 2 + recordInfo.Number-- + err = dbdata.updateUserThingInfo(uid, recordInfo) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.9.2]:", err)) + return + } + } + } + } + thing.Number -= number + err = dbdata.updateUserThingInfo(uid, thing) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.6]:", err)) + return + } + if strings.Contains(thingName, "竿") { + if pice >= thingPice[thingName]*3/4 { // 不值钱的删了 + newCommodity := store{ + Duration: time.Now().Unix(), + Type: "pole", + Name: thingName, + Number: 1, + Price: pice, + Other: thing.Other, + } + err = dbdata.updateStoreInfo(newCommodity) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.7]:", err)) + return + } + } + } else { + things, err1 := dbdata.getStoreThingInfo(thingName) + if err1 != nil { + ctx.SendChain(message.Text("[ERROR at store.go.8]:", err1)) + return + } + if len(things) == 0 { + things = append(things, store{ + Duration: time.Now().Unix(), + Name: thingName, + Number: 0, + Price: pice, + }) + if thingName == "海之眷顾" || thingName == "诱钓" || thingName == "唱片" { + things[0].Type = "article" + } else { + things[0].Type = "fish" + } + } + things[0].Number += number + err = dbdata.updateStoreInfo(things[0]) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.9]:", err)) + return + } + } + pice = pice * 8 / 10 + err = wallet.InsertWalletOf(uid, pice*number) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.10]:", err)) + return + } + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("出售成功,你赚到了", pice*number))) + }) + engine.OnRegex(`^购买(.+(竿|鱼)|河豚|鹦鹉螺|诱钓|海之眷顾|唱片|美西螈)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + thingName := ctx.State["regex_matched"].([]string)[1] + number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[3]) + if number == 0 { + number = 1 + } + thingInfos, err := dbdata.getStoreThingInfo(thingName) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.11]:", err)) + return + } + if len(thingInfos) == 0 { + ctx.SendChain(message.Text("当前商店并没有上架该物品")) + return + } + index := 0 + pice := make([]int, 0, len(thingInfos)) + for _, info := range thingInfos { + if strings.Contains(thingName, "竿") { + poleInfo := strings.Split(info.Other, "/") + durable, _ := strconv.Atoi(poleInfo[0]) + maintenance, _ := strconv.Atoi(poleInfo[1]) + induceLevel, _ := strconv.Atoi(poleInfo[2]) + favorLevel, _ := strconv.Atoi(poleInfo[3]) + thingPice := (thingPice[info.Name] - (equipAttribute[info.Name] - durable) - maintenance*2 + induceLevel*600 + favorLevel*1800) * discount[info.Name] / 100 + pice = append(pice, thingPice) + } else { + thingPice := thingPice[info.Name] * discount[info.Name] / 100 + pice = append(pice, thingPice) + } + + } + if len(thingInfos) > 1 { + msg := make(message.Message, 0, 3+len(thingInfos)) + msg = append(msg, message.Text("找到以下物品:\n")) + for i, info := range thingInfos { + if strings.Contains(thingName, "竿") { + msg = append(msg, message.Text( + "[", i, "]", info.Name, "(", info.Other, ") 价格:", pice[i], "\n")) + } else { + msg = append(msg, message.Text( + "[", i, "]", info.Name, " 数量:", info.Number, " 价格:", pice[i], "\n")) + } + + } + msg = append(msg, message.Text("————————\n输入对应序号进行装备,或回复“取消”取消")) + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, msg...)) + // 等待用户下一步选择 + sell := false + recv, cancel := zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^(取消|\d+)$`), zero.CheckUser(ctx.Event.UserID)).Repeat() + defer cancel() + for { + select { + case <-time.After(time.Second * 120): + 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 + } + index, err = strconv.Atoi(nextcmd) + if err != nil || index > len(thingInfos)-1 { + ctx.SendChain(message.At(ctx.Event.UserID), message.Text("请输入正确的序号")) + continue + } + sell = true + } + if sell { + break + } + } + } + + thing := thingInfos[index] + if thing.Number < number { + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("商店数量不足"))) + return + } + + money := wallet.GetWalletOf(uid) + if money < pice[index]*number { + ctx.SendChain(message.Text("你身上的钱(", money, ")不够支付")) + return + } + + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你确定花费", pice[index]*number, "购买", number, "个", thingName, "?\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 + } + } + + thing.Number -= number + err = dbdata.updateStoreInfo(thing) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.12]:", err)) + return + } + err = wallet.InsertWalletOf(uid, -pice[index]*number) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.13]:", err)) + return + } + if strings.Contains(thingName, "竿") { + newCommodity := article{ + Duration: time.Now().Unix(), + Type: "pole", + Name: thingName, + Number: 1, + Other: thing.Other, + } + err = dbdata.updateUserThingInfo(uid, newCommodity) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.14]:", err)) + return + } + } else { + things, err1 := dbdata.getUserThingInfo(uid, thingName) + if err1 != nil { + ctx.SendChain(message.Text("[ERROR at store.go.15]:", err1)) + return + } + if len(things) == 0 { + things = append(things, article{ + Duration: time.Now().Unix(), + Name: thingName, + Number: 0, + }) + if thingName == "海之眷顾" || thingName == "诱钓" || thingName == "唱片" { + things[0].Type = "article" + } else { + things[0].Type = "fish" + } + } + things[0].Number += number + err = dbdata.updateUserThingInfo(uid, things[0]) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.16]:", err)) + return + } + } + ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("购买成功"))) + }) +} + +func drawStroeEmptyImage() (picImage image.Image, err error) { + fontdata, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true) + if err != nil { + return nil, err + } + canvas := gg.NewContext(1000, 300) + // 画底色 + canvas.DrawRectangle(0, 0, 1000, 300) + canvas.SetRGBA255(255, 255, 255, 150) + canvas.Fill() + // 边框框 + canvas.DrawRectangle(0, 0, 1000, 300) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + + canvas.SetColor(color.Black) + err = canvas.ParseFontFace(fontdata, 100) + if err != nil { + return nil, err + } + textW, textH := canvas.MeasureString("价格信息") + canvas.DrawString("价格信息", 10, 10+textH*1.2) + canvas.DrawLine(10, textH*1.6, textW, textH*1.6) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + if err = canvas.ParseFontFace(fontdata, 50); err != nil { + return nil, err + } + canvas.DrawStringAnchored("当前商店并没有上架任何物品", 500, 10+textH*2+50, 0.5, 0) + return canvas.Image(), nil +} + +func drawStroeInfoImage(stroeInfo []store) (picImage image.Image, err error) { + fontdata, err := file.GetLazyData(text.BoldFontFile, control.Md5File, true) + if err != nil { + return nil, err + } + canvas := gg.NewContext(1, 1) + err = canvas.ParseFontFace(fontdata, 100) + if err != nil { + return nil, err + } + titleW, titleH := canvas.MeasureString("价格信息") + + err = canvas.ParseFontFace(fontdata, 50) + if err != nil { + return nil, err + } + _, textH := canvas.MeasureString("高度") + nameW, _ := canvas.MeasureString("下界合金竿(100/100/0/0)") + numberW, _ := canvas.MeasureString("10000") + priceW, _ := canvas.MeasureString("10000") + + bolckW := int(10 + nameW + 50 + numberW + 50 + priceW + 10) + backY := 10 + int(titleH*2+10)*2 + 10 + (len(stroeInfo)+len(discount)/2+2)*int(textH*2) + 10 + canvas = gg.NewContext(bolckW, math.Max(backY, 500)) + // 画底色 + canvas.DrawRectangle(0, 0, float64(bolckW), float64(backY)) + canvas.SetRGBA255(150, 150, 150, 255) + canvas.Fill() + + // 放字 + canvas.SetColor(color.Black) + err = canvas.ParseFontFace(fontdata, 100) + if err != nil { + return nil, err + } + canvas.DrawString("今日波动", 10, 10+titleH*1.2) + canvas.DrawLine(10, titleH*1.6, titleW, titleH*1.6) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + + textDy := 10 + titleH*1.7 + if err = canvas.ParseFontFace(fontdata, 35); err != nil { + return nil, err + } + textDx, textDh := canvas.MeasureString("下界合金竿(均价1000)") + valueDx, _ := canvas.MeasureString("+100%") + i := 0 + for name, info := range discount { + text := name + "(均价" + strconv.Itoa(thingPice[name]) + ") " + + if i == 2 { + i = 0 + textDy += textDh * 2 + } + canvas.SetColor(color.Black) + canvas.DrawStringAnchored(text, 20+(textDx+valueDx+10)*float64(i)+10, textDy+textDh/2, 0, 0.5) + if info-100 > 0 { + canvas.SetRGBA255(200, 50, 50, 255) + text = "+" + strconv.Itoa(info-100) + "%" + } else { + canvas.SetRGBA255(63, 133, 55, 255) + text = strconv.Itoa(info-100) + "%" + } + canvas.DrawStringAnchored(text, 20+(textDx+valueDx+10)*float64(i)+10+textDx+10, textDy+textDh/2, 0, 0.5) + i++ + } + canvas.SetColor(color.Black) + textDy += textDh * 2 + canvas.DrawStringAnchored("注:出售商品将会额外扣除20%的税收,附魔鱼竿请按实际价格", 10, textDy+10+textDh/2, 0, 0.5) + + textDy += textH * 2 + err = canvas.ParseFontFace(fontdata, 100) + if err != nil { + return nil, err + } + canvas.DrawString("上架内容", 10, textDy+titleH*1.2) + canvas.DrawLine(10, textDy+titleH*1.6, titleW, textDy+titleH*1.6) + canvas.SetLineWidth(3) + canvas.SetRGBA255(0, 0, 0, 255) + canvas.Stroke() + + textDy += 10 + titleH*1.7 + if err = canvas.ParseFontFace(fontdata, 50); err != nil { + return nil, err + } + + canvas.DrawStringAnchored("名称", 10+nameW/2, textDy+textH/2, 0.5, 0.5) + canvas.DrawStringAnchored("数量", 10+nameW+10+numberW/2, textDy+textH/2, 0.5, 0.5) + canvas.DrawStringAnchored("价格", 10+nameW+10+numberW+50+priceW/2, textDy+textH/2, 0.5, 0.5) + + for _, info := range stroeInfo { + textDy += textH * 2 + name := info.Name + if info.Other != "" { + name += "(" + info.Other + ")" + } + numberStr := strconv.Itoa(info.Number) + pice := 0 + if strings.Contains(name, "竿") { + poleInfo := strings.Split(info.Other, "/") + durable, _ := strconv.Atoi(poleInfo[0]) + maintenance, _ := strconv.Atoi(poleInfo[1]) + induceLevel, _ := strconv.Atoi(poleInfo[2]) + favorLevel, _ := strconv.Atoi(poleInfo[3]) + pice = (thingPice[info.Name] - (equipAttribute[info.Name] - durable) - maintenance*2 + induceLevel*600 + favorLevel*1800) * discount[info.Name] / 100 + } else { + pice = thingPice[info.Name] * discount[info.Name] / 100 + } + + canvas.DrawStringAnchored(name, 10+nameW/2, textDy+textH/2, 0.5, 0.5) + canvas.DrawStringAnchored(numberStr, 10+nameW+10+numberW/2, textDy+textH/2, 0.5, 0.5) + canvas.DrawStringAnchored(strconv.Itoa(pice), 10+nameW+10+numberW+50+priceW/2, textDy+textH/2, 0.5, 0.5) + } + return canvas.Image(), nil +} From 6b319921664886d1367429a95dfd714a2d005b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sat, 2 Sep 2023 10:11:06 +0800 Subject: [PATCH 02/12] Update README.md --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 1c788dccb3..f015babcf2 100644 --- a/README.md +++ b/README.md @@ -959,6 +959,23 @@ print("run[CQ:image,file="+j["img"]+"]") - [x] 吟唱提示[xxxx] + +
+ 钓鱼模拟器 + + `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/mcfish"` + + - [x] 钓鱼商店 + - [x] 购买xxx [数量] + - [x] 出售xxx [数量] + - [x] 钓鱼背包 + - [x] 装备[xx竿|三叉戟|美西螈] + - [x] 附魔[诱钓|海之眷顾] + - [x] 修复鱼竿 + - [x] 合成[xx竿|三叉戟] + - [x] 进行钓鱼 + - [x] 进行n次钓鱼 +
简易midi音乐制作 From b007cef600bfb29f97eba86f7ec457f059070812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sat, 2 Sep 2023 11:20:54 +0800 Subject: [PATCH 03/12] Add files via upload --- plugin/mcfish/pack.go | 2 +- plugin/mcfish/store.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin/mcfish/pack.go b/plugin/mcfish/pack.go index 0ec4f5cc53..2df31eb05d 100644 --- a/plugin/mcfish/pack.go +++ b/plugin/mcfish/pack.go @@ -267,7 +267,7 @@ func drawArticleInfoBlock(uid int64, articles []article, fontdata []byte) (image return nil, err } titleW, titleH := canvas.MeasureString("背包信息") - front := 50.0 + front := 45.0 err = canvas.ParseFontFace(fontdata, front) if err != nil { return nil, err diff --git a/plugin/mcfish/store.go b/plugin/mcfish/store.go index 0591a26fa6..8f246ab525 100644 --- a/plugin/mcfish/store.go +++ b/plugin/mcfish/store.go @@ -61,7 +61,7 @@ func init() { } ctx.SendChain(message.ImageBytes(pic)) }) - engine.OnRegex(`^出售(.+(竿|鱼)|河豚|鹦鹉螺|诱钓|海之眷顾|唱片|美西螈)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + engine.OnRegex(`^出售(.+(竿|鱼)|河豚|鹦鹉螺|诱钓|海之眷顾|唱片|美西螈|三叉戟)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { uid := ctx.Event.UserID thingName := ctx.State["regex_matched"].([]string)[1] number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[3]) @@ -269,7 +269,7 @@ func init() { } ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("出售成功,你赚到了", pice*number))) }) - engine.OnRegex(`^购买(.+(竿|鱼)|河豚|鹦鹉螺|诱钓|海之眷顾|唱片|美西螈)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + engine.OnRegex(`^购买(.+(竿|鱼)|河豚|鹦鹉螺|诱钓|海之眷顾|唱片|美西螈|三叉戟)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { uid := ctx.Event.UserID thingName := ctx.State["regex_matched"].([]string)[1] number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[3]) From 18eb9beaf45046b3c5f3c52a6ac2dbba5b2dbf27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sat, 2 Sep 2023 12:18:38 +0800 Subject: [PATCH 04/12] Add files via upload --- plugin/mcfish/pack.go | 6 ++-- plugin/mcfish/pole.go | 4 +-- plugin/mcfish/store.go | 72 +++++++++++++++++++++++------------------- 3 files changed, 45 insertions(+), 37 deletions(-) diff --git a/plugin/mcfish/pack.go b/plugin/mcfish/pack.go index 2df31eb05d..9304b0c7dc 100644 --- a/plugin/mcfish/pack.go +++ b/plugin/mcfish/pack.go @@ -345,8 +345,10 @@ func drawArticleInfoBlock(uid int64, articles []article, fontdata []byte) (image textDy += textH * 2 for i, info := range articles { name := info.Name - if info.Other != "" { - numberOfEquip++ + if info.Other != "" && info.Name != "美西螈" { + if info.Name != "三叉戟" { + numberOfEquip++ + } name += "(" + info.Other + ")" } else if strings.Contains(name, "鱼") { numberOfFish += info.Number diff --git a/plugin/mcfish/pole.go b/plugin/mcfish/pole.go index e4989c742a..bd7ac4a054 100644 --- a/plugin/mcfish/pole.go +++ b/plugin/mcfish/pole.go @@ -275,7 +275,7 @@ func init() { ), ) }) - engine.OnPrefix("附魔", getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + engine.OnRegex(`^附魔(诱钓|海之眷顾)$`, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { uid := ctx.Event.UserID equipInfo, err := dbdata.getUserEquip(uid) if err != nil { @@ -286,7 +286,7 @@ func init() { ctx.SendChain(message.Text("仅可对装备中的进行附魔")) return } - book := strings.TrimSpace(ctx.State["args"].(string)) + book := ctx.State["regex_matched"].([]string)[1] books, err := dbdata.getUserThingInfo(uid, book) if err != nil { ctx.SendChain(message.Text("[ERROR at pole.go.8]:", err)) diff --git a/plugin/mcfish/store.go b/plugin/mcfish/store.go index 8f246ab525..a6d0198c57 100644 --- a/plugin/mcfish/store.go +++ b/plugin/mcfish/store.go @@ -83,7 +83,7 @@ func init() { msg := make(message.Message, 0, 3+len(articles)) msg = append(msg, message.Reply(ctx.Event.MessageID), message.Text("找到以下物品:\n")) for i, info := range articles { - if info.Other != "" { + if info.Other != "" && info.Name != "美西螈" { msg = append(msg, message.Text("[", i, "] ", info.Name, "(", info.Other, ")\n")) } else { msg = append(msg, message.Text( @@ -136,7 +136,7 @@ func init() { } var pice int - if strings.Contains(thingName, "竿") { + if strings.Contains(thingName, "竿") || thingName == "三叉戟" { poleInfo := strings.Split(articles[index].Other, "/") durable, _ := strconv.Atoi(poleInfo[0]) maintenance, _ := strconv.Atoi(poleInfo[1]) @@ -219,9 +219,10 @@ func init() { ctx.SendChain(message.Text("[ERROR at store.go.6]:", err)) return } - if strings.Contains(thingName, "竿") { + newCommodity := store{} + if strings.Contains(thingName, "竿") || thingName == "三叉戟" { if pice >= thingPice[thingName]*3/4 { // 不值钱的删了 - newCommodity := store{ + newCommodity = store{ Duration: time.Now().Unix(), Type: "pole", Name: thingName, @@ -229,11 +230,6 @@ func init() { Price: pice, Other: thing.Other, } - err = dbdata.updateStoreInfo(newCommodity) - if err != nil { - ctx.SendChain(message.Text("[ERROR at store.go.7]:", err)) - return - } } } else { things, err1 := dbdata.getStoreThingInfo(thingName) @@ -248,18 +244,22 @@ func init() { Number: 0, Price: pice, }) - if thingName == "海之眷顾" || thingName == "诱钓" || thingName == "唱片" { + switch { + case thingName == "海之眷顾" || thingName == "诱钓" || thingName == "唱片": things[0].Type = "article" - } else { + case thingName == "美西螈": + things[0].Type = "pole" + default: things[0].Type = "fish" } } - things[0].Number += number - err = dbdata.updateStoreInfo(things[0]) - if err != nil { - ctx.SendChain(message.Text("[ERROR at store.go.9]:", err)) - return - } + newCommodity = things[0] + newCommodity.Number += number + } + err = dbdata.updateStoreInfo(newCommodity) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.9]:", err)) + return } pice = pice * 8 / 10 err = wallet.InsertWalletOf(uid, pice*number) @@ -288,7 +288,7 @@ func init() { index := 0 pice := make([]int, 0, len(thingInfos)) for _, info := range thingInfos { - if strings.Contains(thingName, "竿") { + if strings.Contains(thingName, "竿") || thingName == "三叉戟" { poleInfo := strings.Split(info.Other, "/") durable, _ := strconv.Atoi(poleInfo[0]) maintenance, _ := strconv.Atoi(poleInfo[1]) @@ -306,7 +306,7 @@ func init() { msg := make(message.Message, 0, 3+len(thingInfos)) msg = append(msg, message.Text("找到以下物品:\n")) for i, info := range thingInfos { - if strings.Contains(thingName, "竿") { + if strings.Contains(thingName, "竿") || thingName == "三叉戟" { msg = append(msg, message.Text( "[", i, "]", info.Name, "(", info.Other, ") 价格:", pice[i], "\n")) } else { @@ -399,20 +399,25 @@ func init() { ctx.SendChain(message.Text("[ERROR at store.go.13]:", err)) return } - if strings.Contains(thingName, "竿") { - newCommodity := article{ + newCommodity := article{} + switch { + case strings.Contains(thingName, "竿") || thingName == "三叉戟": + newCommodity = article{ Duration: time.Now().Unix(), Type: "pole", Name: thingName, Number: 1, Other: thing.Other, } - err = dbdata.updateUserThingInfo(uid, newCommodity) - if err != nil { - ctx.SendChain(message.Text("[ERROR at store.go.14]:", err)) - return + case thingName == "美西螈": + newCommodity = article{ + Duration: time.Now().Unix(), + Type: "pole", + Name: thingName, + Number: 1, + Other: "999/0/0/0", } - } else { + default: things, err1 := dbdata.getUserThingInfo(uid, thingName) if err1 != nil { ctx.SendChain(message.Text("[ERROR at store.go.15]:", err1)) @@ -430,12 +435,13 @@ func init() { things[0].Type = "fish" } } - things[0].Number += number - err = dbdata.updateUserThingInfo(uid, things[0]) - if err != nil { - ctx.SendChain(message.Text("[ERROR at store.go.16]:", err)) - return - } + newCommodity = things[0] + newCommodity.Number += number + } + err = dbdata.updateUserThingInfo(uid, newCommodity) + if err != nil { + ctx.SendChain(message.Text("[ERROR at store.go.14]:", err)) + return } ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("购买成功"))) }) @@ -569,7 +575,7 @@ func drawStroeInfoImage(stroeInfo []store) (picImage image.Image, err error) { for _, info := range stroeInfo { textDy += textH * 2 name := info.Name - if info.Other != "" { + if info.Other != "" && info.Name != "美西螈" { name += "(" + info.Other + ")" } numberStr := strconv.Itoa(info.Number) From 36a90780549b8a0c6d738c9cceef964ac0caba87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sat, 2 Sep 2023 12:24:22 +0800 Subject: [PATCH 05/12] Update pole.go --- plugin/mcfish/pole.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/mcfish/pole.go b/plugin/mcfish/pole.go index bd7ac4a054..89d2abd8c0 100644 --- a/plugin/mcfish/pole.go +++ b/plugin/mcfish/pole.go @@ -350,7 +350,7 @@ func init() { return } max := len(articles) - if max == 0 { + if max < 3 { ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你的合成材料不足")) return } From 25edb92d253a4bd961848b6959abb39792ec4fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sat, 2 Sep 2023 12:28:27 +0800 Subject: [PATCH 06/12] Update pole.go --- plugin/mcfish/pole.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/mcfish/pole.go b/plugin/mcfish/pole.go index 89d2abd8c0..f8ff7e1e91 100644 --- a/plugin/mcfish/pole.go +++ b/plugin/mcfish/pole.go @@ -448,7 +448,7 @@ func init() { favorLevel += poles[index].Favor induceLevel += poles[index].Induce } - if rand.Intn(10) > 6 { + if rand.Intn(100) >= 90 { ctx.Send( message.ReplyWithMessage(ctx.Event.MessageID, message.Text("合成失败,材料已销毁"), From bc23be88840c8511e9ca68cca28a4ceb3ddb03c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sat, 2 Sep 2023 12:28:56 +0800 Subject: [PATCH 07/12] Update main.go --- plugin/mcfish/main.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugin/mcfish/main.go b/plugin/mcfish/main.go index 574f0401f0..8370bf21bd 100644 --- a/plugin/mcfish/main.go +++ b/plugin/mcfish/main.go @@ -23,8 +23,6 @@ type fishdb struct { /* type userInfo struct { - UserID int64 // QQ - Bait int // 鱼饵 // 鱼竿 10% 装备/耐久/维修次数/诱钓/眷顾 WoodenPole string // 木竿属性 70% IronPole string // 铁竿属性 20% @@ -129,7 +127,7 @@ var ( "4.稀有物品:\n-> 唱片 : 出售物品时使用该物品使价格翻倍. 均价:3000, 上钩概率:0.01%\n-> 美西螈 : 可装备,获得隐形[钓鱼佬]buff,并让钓到除鱼竿和美西螈外的物品数量变成3,无耐久上限.不可修复/附魔,每次钓鱼消耗任意一鱼类物品. 均价:3000, 上钩概率:0.01%\n" + "5.鱼类信息:\n-> 鳕鱼 : 均价:10 上钩概率:20.7%\n-> 鲑鱼 : 均价:50 上钩概率:6%\n-> 热带鱼 : 均价:100 上钩概率:1.8%\n-> 河豚 : 均价:300 上钩概率:0.9%\n-> 鹦鹉螺 : 均价:500 上钩概率:0.3%\n-> 墨鱼 : 均价:500 上钩概率:0.3%\n" + "6.物品BUFF:\n-> 钓鱼佬 : 当背包名字含有'鱼'的物品数量超过100时激活,钓到物品概率提高至90%\n-> 修复大师 : 当背包鱼竿数量超过10时激活,修复物品时耐久百分百继承\n" + - "7.合成:\n-> 铁竿 : 3x木竿\n-> 金竿 : 3x铁竿\n-> 钻石竿 : 3x金竿\n-> 下界合金竿 : 3x钻石竿\n-> 三叉戟 : 3x下界合金竿\n注:合成成功率70%,继承附魔等级合/3的等级\n" + + "7.合成:\n-> 铁竿 : 3x木竿\n-> 金竿 : 3x铁竿\n-> 钻石竿 : 3x金竿\n-> 下界合金竿 : 3x钻石竿\n-> 三叉戟 : 3x下界合金竿\n注:合成成功率90%,继承附魔等级合/3的等级\n" + "8.杂项:\n-> 无装备的情况下,每人最多可以购买3次100块钱的鱼竿\n-> 默认状态钓鱼上钩概率为56%\n-> 附魔的鱼竿会因附魔变得昂贵,每个附魔最高3级\n-> 三叉戟不算鱼竿", PublicDataFolder: "McFish", }).ApplySingle(ctxext.DefaultSingle) From 8730c7b4525638648001cb4345c5e1b3bbf675f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sat, 2 Sep 2023 13:37:02 +0800 Subject: [PATCH 08/12] Add files via upload --- plugin/mcfish/fish.go | 12 +++++++++--- plugin/mcfish/main.go | 23 +++++++++++++++++++---- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/plugin/mcfish/fish.go b/plugin/mcfish/fish.go index 5614d20714..858bf27a12 100644 --- a/plugin/mcfish/fish.go +++ b/plugin/mcfish/fish.go @@ -113,12 +113,12 @@ func init() { msg = "(你的鱼竿耐久仅剩" + strconv.Itoa(equipInfo.Durable) + ")" } } else { - fishNmae, err := dbdata.pickFishFor(uid) + fishNmaes, err := dbdata.pickFishFor(uid, fishNumber) if err != nil { ctx.SendChain(message.Text("[ERROR at fish.go.5.1]:", err)) return } - if fishNmae == "" { + if len(fishNmaes) == 0 { equipInfo.Durable = 0 err = dbdata.updateUserEquip(equipInfo) if err != nil { @@ -127,7 +127,13 @@ func init() { ctx.SendChain(message.Text("美西螈因为没吃到鱼,钓鱼时一直没回来,你失去了美西螈")) return } - msg = "(美西螈吃掉了一条" + fishNmae + ")" + msg = "(美西螈吃掉了" + fishNumber = 0 + for name, number := range fishNmaes { + fishNumber += number + msg += strconv.Itoa(number) + name + "、" + } + msg += ")" } waitTime := 120 / (equipInfo.Induce + 1) ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你开始去钓鱼了,请耐心等待鱼上钩(预计要", time.Second*time.Duration(waitTime), ")")) diff --git a/plugin/mcfish/main.go b/plugin/mcfish/main.go index 8370bf21bd..5924690705 100644 --- a/plugin/mcfish/main.go +++ b/plugin/mcfish/main.go @@ -468,7 +468,8 @@ func (sql *fishdb) setEquipFor(uid int64) (err error) { return sql.db.Insert("fishState", &userInfo) } -func (sql *fishdb) pickFishFor(uid int64) (fishName string, err error) { +func (sql *fishdb) pickFishFor(uid int64, number int) (fishNames map[string]int, err error) { + fishNames = make(map[string]int, 6) name := strconv.FormatInt(uid, 10) + "Pack" sql.Lock() defer sql.Unlock() @@ -499,7 +500,21 @@ func (sql *fishdb) pickFishFor(uid int64) (fishName string, err error) { if len(fishTypes) == 0 { return } - randNumber := rand.Intn(len(fishTypes)) - fishTypes[randNumber].Number-- - return fishTypes[randNumber].Name, sql.db.Insert(name, &fishTypes[randNumber]) + max := 0 + for _, info := range fishTypes { + max += info.Number + } + if max < number { + number = max + } + for i := number; i > 0; i-- { + randNumber := rand.Intn(len(fishTypes)) + fishTypes[randNumber].Number-- + err = sql.db.Insert(name, &fishTypes[randNumber]) + if err != nil { + return + } + fishNames[fishTypes[randNumber].Name]++ + } + return } From 80ba593ba6536eccb9b234d4fe7fb5743a94adeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sun, 3 Sep 2023 09:22:19 +0800 Subject: [PATCH 09/12] Add files via upload --- plugin/mcfish/fish.go | 273 +++++++++++----------- plugin/mcfish/main.go | 497 +++++++++++++++++++++++------------------ plugin/mcfish/pack.go | 72 +++++- plugin/mcfish/pole.go | 43 ++-- plugin/mcfish/store.go | 48 ++-- 5 files changed, 529 insertions(+), 404 deletions(-) diff --git a/plugin/mcfish/fish.go b/plugin/mcfish/fish.go index 858bf27a12..7b9736e4f8 100644 --- a/plugin/mcfish/fish.go +++ b/plugin/mcfish/fish.go @@ -4,6 +4,7 @@ package mcfish import ( "math/rand" "strconv" + "strings" "time" "github.com/FloatTech/AnimeAPI/wallet" @@ -14,13 +15,13 @@ import ( ) func init() { - engine.OnRegex(`^进行(([1-5]\d*)次)?钓鱼$`, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + engine.OnRegex(`^进行(([1-5]\d|[1-9])次)?钓鱼$`, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { uid := ctx.Event.UserID fishNumber := 1 info := ctx.State["regex_matched"].([]string)[2] if info != "" { number, err := strconv.Atoi(info) - if err != nil || number > 50 { + if err != nil || number > FishLimit { ctx.SendChain(message.Text("请输入正确的次数")) return } @@ -32,7 +33,7 @@ func init() { return } if residue == 0 { - ctx.SendChain(message.Text("今天你已经进行", fishLimit, "次钓鱼了.\n游戏虽好,但请不要沉迷。")) + ctx.SendChain(message.Text("今天你已经进行", FishLimit, "次钓鱼了.\n游戏虽好,但请不要沉迷。")) return } fishNumber = residue @@ -143,169 +144,157 @@ func init() { timer.Stop() break } - // 概率 - wasteProbability := 41 + equipInfo.Favor*10 - poleProbability := 11 + equipInfo.Favor*3 - bookProbability := 1 + equipInfo.Favor*1 // 钓到鱼的范围 number, err := dbdata.getNumberFor(uid, "鱼") if err != nil { ctx.SendChain(message.Text("[ERROR at fish.go.5.1]:", err)) return } - getFishMaxDy := 9 - getFishMinDy := 2 - getFishMaxDx := 9 - getFishMinDx := 1 - if number > 100 || equipInfo.Equip == "美西螈" { - getFishMaxDy = 10 - getFishMinDy = 1 - getFishMaxDx = 10 - getFishMinDx = 0 + if number > 100 || equipInfo.Equip == "美西螈" { //放大概率 + probabilities["treasure"] = probabilityLimit{ + Min: 0, + Max: 2, + } + probabilities["pole"] = probabilityLimit{ + Min: 2, + Max: 10, + } + probabilities["fish"] = probabilityLimit{ + Min: 10, + Max: 45, + } + probabilities["waste"] = probabilityLimit{ + Min: 45, + Max: 90, + } + } + for name, info := range probabilities { + switch name { + case "treasure": + info.Max += equipInfo.Favor + probabilities[name] = info + case "pole": + info.Min += equipInfo.Favor + info.Max += equipInfo.Favor * 2 + probabilities[name] = info + case "fish": + info.Min += equipInfo.Favor * 2 + info.Max += equipInfo.Favor * 3 + probabilities[name] = info + case "waste": + info.Min += equipInfo.Favor * 3 + probabilities[name] = info + } } // 钓鱼结算 - thingNameList := make(map[string]int) picName := "" + thingNameList := make(map[string]int) for i := fishNumber; i > 0; i-- { - fishDx := rand.Intn(11) - fishDy := rand.Intn(11) - if fishDx < getFishMinDx || fishDx > getFishMaxDx || fishDy < getFishMinDy || fishDy > getFishMaxDy { - if fishNumber == 1 { - ctx.SendChain(message.At(uid), message.Text("很遗憾你没有钓到鱼", msg)) - return - } - thingNameList["空竿"]++ - continue - } + thingName := "" + typeOfThing := "" + number := 1 dice := rand.Intn(100) switch { - case dice >= wasteProbability: // 垃圾 - waste := wasteList[rand.Intn(len(wasteList))] - money := 10 - if equipInfo.Equip == "美西螈" { - money *= 3 - } - err := wallet.InsertWalletOf(uid, money) - if err != nil { - ctx.SendChain(message.Text("[ERROR at fish.go.9]:", err)) - return - } - picName = waste - thingNameList[waste]++ - if fishNumber == 1 { - msg = "为河流净化做出了贡献,\n给予" + strconv.Itoa(money) + "奖励金\n" + msg - } - case dice <= bookProbability: - picName = "book" - thingName := "诱钓" - dice := rand.Intn(100) + case dice <= probabilities["waste"].Min && dice < probabilities["waste"].Max: // 垃圾 + typeOfThing = "waste" + thingName = wasteList[rand.Intn(len(wasteList))] + picName = thingName + case dice <= probabilities["treasure"].Min && dice < probabilities["treasure"].Max: // 宝藏 + dice = rand.Intn(100) switch { - case dice == 0: + case dice <= probabilities["美西螈"].Min && dice < probabilities["美西螈"].Max: + typeOfThing = "pole" picName = "美西螈" thingName = "美西螈" - case dice == 1: + case dice <= probabilities["唱片"].Min && dice < probabilities["唱片"].Max: + typeOfThing = "article" picName = "唱片" thingName = "唱片" - case dice < 41 && dice > 1: + case dice <= probabilities["海之眷顾"].Min && dice < probabilities["海之眷顾"].Max: + typeOfThing = "article" + picName = "book" thingName = "海之眷顾" + default: + typeOfThing = "article" + picName = "book" + thingName = "诱钓" } - books, err := dbdata.getUserThingInfo(uid, thingName) - if err != nil { - ctx.SendChain(message.Text("[ERROR at fish.go.6]:", err)) - return - } - if len(books) == 0 { - books = append(books, article{ - Duration: time.Now().Unix()*100 + int64(i), - Type: "article", - Name: thingName, - }) - } - if thingName == "美西螈" { - books[0].Type = "pole" - books[0].Other = "999/0/0/0" - } - number := 1 - if equipInfo.Equip == "美西螈" && thingName != "美西螈" { - number += 2 - } - books[0].Number += number - err = dbdata.updateUserThingInfo(uid, books[0]) - if err != nil { - ctx.SendChain(message.Text("[ERROR at fish.go.7]:", err)) - return - } - thingNameList[thingName] += number - case dice > bookProbability && dice <= poleProbability: - poleNmae := "木竿" + case dice <= probabilities["pole"].Min && dice < probabilities["pole"].Max: // 宝藏 + typeOfThing = "pole" dice := rand.Intn(100) switch { - case dice >= 10 && dice < 30: - poleNmae = "铁竿" - case dice >= 4 && dice < 10: - poleNmae = "金竿" - case dice >= 1 && dice < 4: - poleNmae = "钻石竿" - case dice == 0: - poleNmae = "下界合金竿竿竿" - } - newPole := article{ - Duration: time.Now().Unix()*100 + int64(i), - Type: "pole", - Name: poleNmae, - Number: 1, - Other: strconv.Itoa(rand.Intn(equipAttribute[poleNmae])+1) + - "/" + strconv.Itoa(rand.Intn(10)) + "/" + - strconv.Itoa(rand.Intn(3)) + "/" + strconv.Itoa(rand.Intn(2)), - } - err = dbdata.updateUserThingInfo(uid, newPole) - if err != nil { - ctx.SendChain(message.Text("[ERROR at fish.go.8]:", err)) - return + case dice <= probabilities["铁竿"].Min && dice < probabilities["铁竿"].Max: + thingName = "铁竿" + case dice <= probabilities["金竿"].Min && dice < probabilities["金竿"].Max: + thingName = "金竿" + case dice <= probabilities["钻石竿"].Min && dice < probabilities["钻石竿"].Max: + thingName = "钻石竿" + case dice <= probabilities["下界合金竿竿竿"].Min && dice < probabilities["下界合金竿竿竿"].Max: + thingName = "下界合金竿竿竿" + default: + thingName = "木竿" } - picName = poleNmae - thingNameList[poleNmae]++ - default: - fishName := "" + picName = thingName + case dice <= probabilities["fish"].Min && dice < probabilities["fish"].Max: + typeOfThing = "fish" dice = rand.Intn(100) switch { - case dice == 99: - fishName = "墨鱼" - case dice >= 30 && dice != 99: - fishName = "鳕鱼" - case dice >= 10 && dice < 30: - fishName = "鲑鱼" - case dice >= 4 && dice < 10: - fishName = "热带鱼" - case dice >= 1 && dice < 4: - fishName = "河豚" + case dice <= probabilities["墨鱼"].Min && dice < probabilities["墨鱼"].Max: + thingName = "墨鱼" + case dice <= probabilities["鳕鱼"].Min && dice < probabilities["鳕鱼"].Max: + thingName = "鳕鱼" + case dice <= probabilities["鲑鱼"].Min && dice < probabilities["鲑鱼"].Max: + thingName = "鲑鱼" + case dice <= probabilities["热带鱼"].Min && dice < probabilities["热带鱼"].Max: + thingName = "热带鱼" + case dice <= probabilities["河豚"].Min && dice < probabilities["河豚"].Max: + thingName = "河豚" default: - fishName = "鹦鹉螺" + thingName = "鹦鹉螺" } - fishes, err := dbdata.getUserThingInfo(uid, fishName) - if err != nil { - ctx.SendChain(message.Text("[ERROR at fish.go.10]:", err)) - return - } - if len(fishes) == 0 { - fishes = append(fishes, article{ + picName = thingName + default: + thingNameList["赛博空气"]++ + } + if thingName != "" { + newThing := article{} + if strings.Contains(thingName, "竿") { + info := strconv.Itoa(rand.Intn(discountList[thingName])+1) + + "/" + strconv.Itoa(rand.Intn(10)) + "/" + + strconv.Itoa(rand.Intn(3)) + "/" + strconv.Itoa(rand.Intn(2)) + newThing = article{ Duration: time.Now().Unix()*100 + int64(i), - Type: "fish", - Name: fishName, - }) - } - number := 1 - if equipInfo.Equip == "美西螈" || equipInfo.Equip == "三叉戟" { - number += 2 + Type: typeOfThing, + Name: thingName, + Number: number, + Other: info, + } + } else { + thingInfo, err := dbdata.getUserThingInfo(uid, thingName) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.6]:", err)) + return + } + if len(thingInfo) == 0 { + newThing = article{ + Duration: time.Now().Unix()*100 + int64(i), + Type: typeOfThing, + Name: thingName, + } + } else { + newThing = thingInfo[0] + } + if equipInfo.Equip == "美西螈" && thingName != "美西螈" { + number += 2 + } + newThing.Number += number } - fishes[0].Number += number - err = dbdata.updateUserThingInfo(uid, fishes[0]) + err = dbdata.updateUserThingInfo(uid, newThing) if err != nil { - ctx.SendChain(message.Text("[ERROR at fish.go.11]:", err)) + ctx.SendChain(message.Text("[ERROR at fish.go.7]:", err)) return } - picName = fishName - thingNameList[fishName] += number + thingNameList[thingName] += number } } if len(thingNameList) == 1 { @@ -313,13 +302,17 @@ func init() { for name := range thingNameList { thingName = name } - pic, err := engine.GetLazyData(picName+".png", false) - if err != nil { - logrus.Warnln("[mcfish]error:", err) - ctx.SendChain(message.At(uid), message.Text("恭喜你钓到了", thingName, "\n", msg)) + if picName != "" { + pic, err := engine.GetLazyData(picName+".png", false) + if err != nil { + logrus.Warnln("[mcfish]error:", err) + ctx.SendChain(message.At(uid), message.Text("恭喜你钓到了", thingName, "\n", msg)) + return + } + ctx.SendChain(message.At(uid), message.Text("恭喜你钓到了", thingName, "\n", msg), message.ImageBytes(pic)) return } - ctx.SendChain(message.At(uid), message.Text("恭喜你钓到了", thingName, "\n", msg), message.ImageBytes(pic)) + ctx.SendChain(message.At(uid), message.Text("恭喜你钓到了", thingName, "\n", msg)) return } msgInfo := make(message.Message, 0, 3+len(thingNameList)) diff --git a/plugin/mcfish/main.go b/plugin/mcfish/main.go index 5924690705..d22aa1b47d 100644 --- a/plugin/mcfish/main.go +++ b/plugin/mcfish/main.go @@ -2,7 +2,9 @@ package mcfish import ( + "encoding/json" "math/rand" + "os" "strconv" "sync" "time" @@ -21,39 +23,30 @@ type fishdb struct { sync.RWMutex } -/* -type userInfo struct { - // 鱼竿 10% 装备/耐久/维修次数/诱钓/眷顾 - WoodenPole string // 木竿属性 70% - IronPole string // 铁竿属性 20% - GoldenPole string // 金竿属性 6% - DiamondPole string // 钻石竿属性 3% - NetherPole string // 下界合金竿属性 1% - // 鱼 30% - Cod int // 鳕鱼数量 69% - Salmon int // 鲑鱼数量 20% - Tropical int // 热带鱼 6% - Globe int // 河豚 3% - Nautilus int // 鹦鹉螺 1% - Nautilus int // 墨鱼1% - // 宝藏 1% - Induce int // 诱钓 59% - Favor int // 眷顾 39% - Record int // 唱片 1% - Record int // 美西螈 1% - // 垃圾 59% - Leaf int // 荷叶 10% - Rod int // 木棍 10% - bamboo int // 竹子 10% - Shoe int // 鞋子 10% - Bottle int // 瓶子 10% - Hanger int // 拌线钩 10% - Bone int // 骨头 10% - Leather int // 皮革 10% - Carrion int // 腐肉 10% - Bowl int // 碗 10% +// FishLimit 钓鱼次数上限 +const FishLimit = 50 + +// 各物品信息 +type jsonInfo struct { + ZoneInfo []zoneInfo `json:"分类"` // 区域概率 + ArticleInfo []articleInfo `json:"物品"` // 物品信息 +} +type zoneInfo struct { + Name string `json:"类型"` //类型 + Probability int `json:"概率[0-100)"` // 概率 +} +type articleInfo struct { + Name string `json:"名称"` //名称 + Type string `json:"类型"` // 类型 + Probability int `json:"概率[0-100),omitempty"` // 概率 + Durable int `json:"耐久上限,omitempty"` // 耐久 + Price int `json:"价格"` // 价格 +} + +type probabilityLimit struct { + Min int + Max int } -*/ type equip struct { ID int64 // 用户 @@ -94,25 +87,23 @@ type storeDiscount struct { } var ( - equipAttribute = map[string]int{ - "木竿": 30, "铁竿": 50, "金竿": 70, "钻石竿": 100, "下界合金竿": 150, "三叉戟": 300, "美西螈": 999, - } - thingPice = map[string]int{ - "鳕鱼": 10, "鲑鱼": 50, "热带鱼": 100, "河豚": 300, "鹦鹉螺": 500, "墨鱼": 500, - "木竿": 100, "铁竿": 300, "金竿": 700, "钻石竿": 1500, "下界合金竿": 3100, "三叉戟": 4000, - "诱钓": 1000, "海之眷顾": 2500, "唱片": 3000, "美西螈": 3000, - } - discount = map[string]int{ - "鳕鱼": 100, "鲑鱼": 100, "热带鱼": 100, "河豚": 100, "鹦鹉螺": 100, "墨鱼": 100, - "木竿": 100, "铁竿": 100, "金竿": 100, "钻石竿": 100, "下界合金竿": 100, "三叉戟": 100, - "诱钓": 100, "海之眷顾": 100, "唱片": 100, "美西螈": 100, - } - fishList = []string{"鳕鱼", "鲑鱼", "热带鱼"} - wasteList = []string{"海草", "木棍", "帽子", "鞋子", "瓶子", "拌线钩", "骨头", "皮革", "腐肉", "碗"} - enchantLevel = []string{"0", "Ⅰ", "Ⅱ", "Ⅲ"} - dbdata = &fishdb{ + articlesInfo = jsonInfo{} // 物品信息 + thingList = make([]string, 0, 100) // 竿列表 + poleList = make([]string, 0, 10) // 竿列表 + fishList = make([]string, 0, 10) // 鱼列表 + treasureList = make([]string, 0, 10) // 鱼列表 + wasteList = make([]string, 0, 10) // 垃圾列表 + probabilities = make(map[string]probabilityLimit, 50) // 概率分布 + priceList = make(map[string]int, 50) // 价格分布 + durationList = make(map[string]int, 50) // 装备耐久分布 + discountList = make(map[string]int, 50) // 价格波动信息 + enchantLevel = []string{"0", "Ⅰ", "Ⅱ", "Ⅲ"} + dbdata = &fishdb{ db: &sql.Sqlite{}, } +) + +var ( engine = control.Register("mcfish", &ctrl.Options[*zero.Ctx]{ DisableOnDefault: false, Brief: "钓鱼", @@ -121,14 +112,14 @@ var ( "- 钓鱼背包\n- 装备[xx竿|三叉戟|美西螈]\n- 附魔[诱钓|海之眷顾]\n- 修复鱼竿\n- 合成[xx竿|三叉戟]\n" + "- 进行钓鱼\n- 进行n次钓鱼\n" + "规则:\n1.每日的商店价格是波动的!!如何最大化收益自己考虑一下喔\n" + - "2.装备信息:\n-> 木竿 : 耐久上限:30 均价:100 上钩概率:7%\n-> 铁竿 : 耐久上限:50 均价:300 上钩概率:2%\n-> 金竿 : 耐久上限:70 均价700 上钩概率:0.6%\n" + - "-> 钻石竿 : 耐久上限:100 均价1500 上钩概率:0.3%\n-> 下界合金竿 : 耐久上限:150 均价3100 上钩概率:0.1%\n-> 三叉戟 : 可使钓的鱼类物品数量变成3 耐久上限:300 均价4000 只能合成和交易\n" + + "2.装备信息:\n-> 木竿 : 耐久上限:30 均价:100 上钩概率:0.7%\n-> 铁竿 : 耐久上限:50 均价:300 上钩概率:0.2%\n-> 金竿 : 耐久上限:70 均价700 上钩概率:0.06%\n" + + "-> 钻石竿 : 耐久上限:100 均价1500 上钩概率:0..3%\n-> 下界合金竿 : 耐久上限:150 均价3100 上钩概率:0..1%\n-> 三叉戟 : 可使钓的鱼类物品数量变成3 耐久上限:300 均价4000 只能合成和交易\n" + "3.附魔书信息:\n-> 诱钓 : 减少上钩时间. 均价:1000, 上钩概率:0.59%\n-> 海之眷顾 : 增加宝藏上钩概率. 均价:2500, 上钩概率:0.39%\n" + "4.稀有物品:\n-> 唱片 : 出售物品时使用该物品使价格翻倍. 均价:3000, 上钩概率:0.01%\n-> 美西螈 : 可装备,获得隐形[钓鱼佬]buff,并让钓到除鱼竿和美西螈外的物品数量变成3,无耐久上限.不可修复/附魔,每次钓鱼消耗任意一鱼类物品. 均价:3000, 上钩概率:0.01%\n" + - "5.鱼类信息:\n-> 鳕鱼 : 均价:10 上钩概率:20.7%\n-> 鲑鱼 : 均价:50 上钩概率:6%\n-> 热带鱼 : 均价:100 上钩概率:1.8%\n-> 河豚 : 均价:300 上钩概率:0.9%\n-> 鹦鹉螺 : 均价:500 上钩概率:0.3%\n-> 墨鱼 : 均价:500 上钩概率:0.3%\n" + + "5.鱼类信息:\n-> 鳕鱼 : 均价:10 上钩概率:0.69%\n-> 鲑鱼 : 均价:50 上钩概率:0.2%\n-> 热带鱼 : 均价:100 上钩概率:0.06%\n-> 河豚 : 均价:300 上钩概率:0.03%\n-> 鹦鹉螺 : 均价:500 上钩概率:0.01%\n-> 墨鱼 : 均价:500 上钩概率:0.01%\n" + "6.物品BUFF:\n-> 钓鱼佬 : 当背包名字含有'鱼'的物品数量超过100时激活,钓到物品概率提高至90%\n-> 修复大师 : 当背包鱼竿数量超过10时激活,修复物品时耐久百分百继承\n" + "7.合成:\n-> 铁竿 : 3x木竿\n-> 金竿 : 3x铁竿\n-> 钻石竿 : 3x金竿\n-> 下界合金竿 : 3x钻石竿\n-> 三叉戟 : 3x下界合金竿\n注:合成成功率90%,继承附魔等级合/3的等级\n" + - "8.杂项:\n-> 无装备的情况下,每人最多可以购买3次100块钱的鱼竿\n-> 默认状态钓鱼上钩概率为56%\n-> 附魔的鱼竿会因附魔变得昂贵,每个附魔最高3级\n-> 三叉戟不算鱼竿", + "8.杂项:\n-> 无装备的情况下,每人最多可以购买3次100块钱的鱼竿\n-> 默认状态钓鱼上钩概率为60%(理论值!!!)\n-> 附魔的鱼竿会因附魔变得昂贵,每个附魔最高3级\n-> 三叉戟不算鱼竿", PublicDataFolder: "McFish", }).ApplySingle(ctxext.DefaultSingle) getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { @@ -140,16 +131,147 @@ var ( } return true }) - fishLimit = 50 // 钓鱼次数上限 ) -/* func init() { - for name := range thingPice { - _, _ = engine.GetLazyData(name+".png", false) + //go func() { + _, err := engine.GetLazyData("articlesInfo.json", false) + if err != nil { + panic(err) + } + reader, err := os.Open(engine.DataFolder() + "articlesInfo.json") + if err == nil { + err = json.NewDecoder(reader).Decode(&articlesInfo) + } + if err == nil { + err = reader.Close() + } + if err != nil { + panic(err) + } + probableList := make([]int, 4) + for _, info := range articlesInfo.ZoneInfo { + switch info.Name { + case "treasure": + probableList[0] = info.Probability + case "pole": + probableList[1] = info.Probability + case "fish": + probableList[2] = info.Probability + case "waste": + probableList[3] = info.Probability + } + } + probabilities["treasure"] = probabilityLimit{ + Min: 0, + Max: probableList[0], + } + probabilities["pole"] = probabilityLimit{ + Min: probableList[0], + Max: probableList[1], + } + probabilities["fish"] = probabilityLimit{ + Min: probableList[1], + Max: probableList[2], + } + probabilities["waste"] = probabilityLimit{ + Min: probableList[2], + Max: probableList[3], + } + min := make(map[string]int, 4) + for _, info := range articlesInfo.ArticleInfo { + switch { + case info.Type == "pole": + poleList = append(poleList, info.Name) + case info.Type == "fish": + fishList = append(fishList, info.Name) + case info.Type == "waste": + wasteList = append(wasteList, info.Name) + case info.Type == "treasure": + treasureList = append(treasureList, info.Name) + } + thingList = append(thingList, info.Name) + priceList[info.Name] = info.Price + if info.Durable != 0 { + durationList[info.Name] = info.Durable + } + probabilities[info.Name] = probabilityLimit{ + Min: min[info.Type], + Max: min[info.Type] + info.Probability, + } + min[info.Type] += info.Probability + } + //}() +} + +// 更新上限信息 +func (sql *fishdb) updateFishInfo(uid int64, number int) (residue int, err error) { + sql.Lock() + defer sql.Unlock() + userInfo := fishState{ID: uid} + err = sql.db.Create("fishState", &userInfo) + if err != nil { + return 0, err + } + _ = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10)) + if time.Unix(userInfo.Duration, 0).Day() != time.Now().Day() { + userInfo.Fish = 0 + userInfo.Duration = time.Now().Unix() + } + if userInfo.Fish >= FishLimit { + return 0, nil + } + residue = number + if userInfo.Fish+number > FishLimit { + residue = FishLimit - userInfo.Fish + number = residue + } + userInfo.Fish += number + err = sql.db.Insert("fishState", &userInfo) + return +} + +/*********************************************************/ +/************************装备相关函数***********************/ +/*********************************************************/ + +func (sql *fishdb) checkEquipFor(uid int64) (ok bool, err error) { + sql.Lock() + defer sql.Unlock() + userInfo := fishState{ID: uid} + err = sql.db.Create("fishState", &userInfo) + if err != nil { + return false, err + } + if !sql.db.CanFind("fishState", "where ID = "+strconv.FormatInt(uid, 10)) { + return true, nil + } + err = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10)) + if err != nil { + return false, err + } + if userInfo.Equip > 3 { + return false, nil + } + return true, nil +} + +func (sql *fishdb) setEquipFor(uid int64) (err error) { + sql.Lock() + defer sql.Unlock() + userInfo := fishState{ID: uid} + err = sql.db.Create("fishState", &userInfo) + if err != nil { + return err + } + _ = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10)) + if err != nil { + return err } + userInfo.Equip++ + return sql.db.Insert("fishState", &userInfo) } -*/ + // 获取装备信息 func (sql *fishdb) getUserEquip(uid int64) (userInfo equip, err error) { sql.Lock() @@ -179,6 +301,61 @@ func (sql *fishdb) updateUserEquip(userInfo equip) (err error) { return sql.db.Insert("equips", &userInfo) } +func (sql *fishdb) pickFishFor(uid int64, number int) (fishNames map[string]int, err error) { + fishNames = make(map[string]int, 6) + name := strconv.FormatInt(uid, 10) + "Pack" + sql.Lock() + defer sql.Unlock() + userInfo := article{} + err = sql.db.Create(name, &userInfo) + if err != nil { + return + } + count, err := sql.db.Count(name) + if err != nil { + return + } + if count == 0 { + return + } + if !sql.db.CanFind(name, "where Type is 'fish'") { + return + } + fishTypes := make([]article, 0, count) + fishInfo := article{} + err = sql.db.FindFor(name, &fishInfo, "where Type is 'fish'", func() error { + fishTypes = append(fishTypes, fishInfo) + return nil + }) + if err != nil { + return + } + if len(fishTypes) == 0 { + return + } + max := 0 + for _, info := range fishTypes { + max += info.Number + } + if max < number { + number = max + } + for i := number; i > 0; i-- { + randNumber := rand.Intn(len(fishTypes)) + fishTypes[randNumber].Number-- + err = sql.db.Insert(name, &fishTypes[randNumber]) + if err != nil { + return + } + fishNames[fishTypes[randNumber].Name]++ + } + return +} + +/*********************************************************/ +/************************背包相关函数***********************/ +/*********************************************************/ + // 获取用户背包信息 func (sql *fishdb) getUserPack(uid int64) (thingInfos []article, err error) { sql.Lock() @@ -244,97 +421,39 @@ func (sql *fishdb) updateUserThingInfo(uid int64, userInfo article) (err error) return sql.db.Insert(name, &userInfo) } -// 获取商店信息 -func (sql *fishdb) getStoreInfo() (thingInfos []store, err error) { - sql.Lock() - defer sql.Unlock() - thingInfo := store{} - err = sql.db.Create("store", &thingInfo) - if err != nil { - return - } - count, err := sql.db.Count("store") - if err != nil { - return - } - if count == 0 { - return - } - err = sql.db.FindFor("store", &thingInfo, "ORDER by Type, Name, Price ASC", func() error { - thingInfos = append(thingInfos, thingInfo) - return nil - }) - return -} - -// 获取商店物品信息 -func (sql *fishdb) getStoreThingInfo(thing string) (thingInfos []store, err error) { +// 获取某关键字的数量 +func (sql *fishdb) getNumberFor(uid int64, thing string) (number int, err error) { + name := strconv.FormatInt(uid, 10) + "Pack" sql.Lock() defer sql.Unlock() - thingInfo := store{} - err = sql.db.Create("store", &thingInfo) + userInfo := article{} + err = sql.db.Create(name, &userInfo) if err != nil { return } - count, err := sql.db.Count("store") + count, err := sql.db.Count(name) if err != nil { return } if count == 0 { return } - if !sql.db.CanFind("store", "where Name = '"+thing+"'") { + if !sql.db.CanFind(name, "where Name glob '*"+thing+"*'") { return } - err = sql.db.FindFor("store", &thingInfo, "where Name = '"+thing+"'", func() error { - thingInfos = append(thingInfos, thingInfo) + info := article{} + err = sql.db.FindFor(name, &info, "where Name glob '*"+thing+"*'", func() error { + number += info.Number return nil }) return } -// 更新商店信息 -func (sql *fishdb) updateStoreInfo(thingInfo store) (err error) { - sql.Lock() - defer sql.Unlock() - err = sql.db.Create("store", &thingInfo) - if err != nil { - return - } - if thingInfo.Number == 0 { - return sql.db.Del("store", "where Duration = "+strconv.FormatInt(thingInfo.Duration, 10)) - } - return sql.db.Insert("store", &thingInfo) -} - -// 更新上限信息 -func (sql *fishdb) updateFishInfo(uid int64, number int) (residue int, err error) { - sql.Lock() - defer sql.Unlock() - userInfo := fishState{ID: uid} - err = sql.db.Create("fishState", &userInfo) - if err != nil { - return 0, err - } - _ = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10)) - if time.Unix(userInfo.Duration, 0).Day() != time.Now().Day() { - userInfo.Fish = 0 - userInfo.Duration = time.Now().Unix() - } - if userInfo.Fish >= fishLimit { - return 0, nil - } - residue = number - if userInfo.Fish+number > fishLimit { - residue = fishLimit - userInfo.Fish - number = residue - } - userInfo.Fish += number - err = sql.db.Insert("fishState", &userInfo) - return -} +/*********************************************************/ +/************************商店相关函数***********************/ +/*********************************************************/ -// 更新上限信息 +// 刷新商店信息 func (sql *fishdb) refreshStroeInfo() (ok bool, err error) { sql.Lock() defer sql.Unlock() @@ -357,7 +476,7 @@ func (sql *fishdb) refreshStroeInfo() (ok bool, err error) { } refresh = true } - for name := range thingPice { + for name := range priceList { thing := storeDiscount{} switch refresh { case true: @@ -371,15 +490,12 @@ func (sql *fishdb) refreshStroeInfo() (ok bool, err error) { return } default: - err = sql.db.Find("stroeDiscount", &thing, "where Name = '"+name+"'") - if err != nil { - return - } + _ = sql.db.Find("stroeDiscount", &thing, "where Name = '"+name+"'") } if thing.Discount != 0 { - discount[name] = thing.Discount + discountList[name] = thing.Discount } else { - discount[name] = 100 + discountList[name] = 100 } } if refresh { // 每天调控1种鱼 @@ -394,9 +510,9 @@ func (sql *fishdb) refreshStroeInfo() (ok bool, err error) { thingInfo.Duration = time.Now().Unix() thingInfo.Type = "fish" thingInfo.Name = fish - thingInfo.Price = thingPice[fish] * discount[fish] / 100 + thingInfo.Price = priceList[fish] * discountList[fish] / 100 } - thingInfo.Number -= (discount[fish] - 100) + thingInfo.Number += (100 - discountList[fish]) if thingInfo.Number < 1 { thingInfo.Number = 1 } @@ -405,116 +521,65 @@ func (sql *fishdb) refreshStroeInfo() (ok bool, err error) { return true, nil } -func (sql *fishdb) getNumberFor(uid int64, thing string) (number int, err error) { - name := strconv.FormatInt(uid, 10) + "Pack" +// 获取商店信息 +func (sql *fishdb) getStoreInfo() (thingInfos []store, err error) { sql.Lock() defer sql.Unlock() - userInfo := article{} - err = sql.db.Create(name, &userInfo) + thingInfo := store{} + err = sql.db.Create("store", &thingInfo) if err != nil { return } - count, err := sql.db.Count(name) + count, err := sql.db.Count("store") if err != nil { return } if count == 0 { return } - if !sql.db.CanFind(name, "where Name glob '*"+thing+"*'") { - return - } - err = sql.db.FindFor(name, &article{}, "where Name glob '*"+thing+"*'", func() error { - number++ + err = sql.db.FindFor("store", &thingInfo, "ORDER by Type, Name, Price ASC", func() error { + thingInfos = append(thingInfos, thingInfo) return nil }) return } -func (sql *fishdb) checkEquipFor(uid int64) (ok bool, err error) { - sql.Lock() - defer sql.Unlock() - userInfo := fishState{ID: uid} - err = sql.db.Create("fishState", &userInfo) - if err != nil { - return false, err - } - if !sql.db.CanFind("fishState", "where ID = "+strconv.FormatInt(uid, 10)) { - return true, nil - } - err = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10)) - if err != nil { - return false, err - } - if userInfo.Equip > 3 { - return false, nil - } - return true, nil -} - -func (sql *fishdb) setEquipFor(uid int64) (err error) { - sql.Lock() - defer sql.Unlock() - userInfo := fishState{ID: uid} - err = sql.db.Create("fishState", &userInfo) - if err != nil { - return err - } - _ = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10)) - if err != nil { - return err - } - userInfo.Equip++ - return sql.db.Insert("fishState", &userInfo) -} - -func (sql *fishdb) pickFishFor(uid int64, number int) (fishNames map[string]int, err error) { - fishNames = make(map[string]int, 6) - name := strconv.FormatInt(uid, 10) + "Pack" +// 获取商店物品信息 +func (sql *fishdb) getStoreThingInfo(thing string) (thingInfos []store, err error) { sql.Lock() defer sql.Unlock() - userInfo := article{} - err = sql.db.Create(name, &userInfo) + thingInfo := store{} + err = sql.db.Create("store", &thingInfo) if err != nil { return } - count, err := sql.db.Count(name) + count, err := sql.db.Count("store") if err != nil { return } if count == 0 { return } - if !sql.db.CanFind(name, "where Type is 'fish'") { + if !sql.db.CanFind("store", "where Name = '"+thing+"'") { return } - fishTypes := make([]article, 0, count) - fishInfo := article{} - err = sql.db.FindFor(name, &fishInfo, "where Type is 'fish'", func() error { - fishTypes = append(fishTypes, fishInfo) + err = sql.db.FindFor("store", &thingInfo, "where Name = '"+thing+"'", func() error { + thingInfos = append(thingInfos, thingInfo) return nil }) + return +} + +// 更新商店信息 +func (sql *fishdb) updateStoreInfo(thingInfo store) (err error) { + sql.Lock() + defer sql.Unlock() + err = sql.db.Create("store", &thingInfo) if err != nil { return } - if len(fishTypes) == 0 { - return - } - max := 0 - for _, info := range fishTypes { - max += info.Number - } - if max < number { - number = max - } - for i := number; i > 0; i-- { - randNumber := rand.Intn(len(fishTypes)) - fishTypes[randNumber].Number-- - err = sql.db.Insert(name, &fishTypes[randNumber]) - if err != nil { - return - } - fishNames[fishTypes[randNumber].Name]++ + if thingInfo.Number == 0 { + return sql.db.Del("store", "where Duration = "+strconv.FormatInt(thingInfo.Duration, 10)) } - return + return sql.db.Insert("store", &thingInfo) } diff --git a/plugin/mcfish/pack.go b/plugin/mcfish/pack.go index 9304b0c7dc..f57d6df48f 100644 --- a/plugin/mcfish/pack.go +++ b/plugin/mcfish/pack.go @@ -42,6 +42,72 @@ func init() { } ctx.SendChain(message.ImageBytes(pic)) }) + engine.OnFullMatch("当前装备概率明细", getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + uid := ctx.Event.UserID + equipInfo, err := dbdata.getUserEquip(uid) + if err != nil { + ctx.SendChain(message.Text("[ERROR at pack.go.1]:", err)) + return + } + number, err := dbdata.getNumberFor(uid, "鱼") + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.5.1]:", err)) + return + } + msg := make(message.Message, 0, 20+len(thingList)) + msg = append(msg, message.At(uid), message.Text("\n大类概率:\n")) + probableList := make([]int, 4) + for _, info := range articlesInfo.ZoneInfo { + switch info.Name { + case "treasure": + probableList[0] = info.Probability + case "pole": + probableList[1] = info.Probability + case "fish": + probableList[2] = info.Probability + case "waste": + probableList[3] = info.Probability + } + } + if number > 100 || equipInfo.Equip == "美西螈" { //放大概率 + probableList = []int{2, 8, 35, 45} + } + if equipInfo.Favor > 0 { + probableList[0] += equipInfo.Favor + probableList[1] += equipInfo.Favor + probableList[2] += equipInfo.Favor + probableList[3] -= equipInfo.Favor * 3 + } + probable := probableList[0] + msg = append(msg, message.Text("宝藏 : ", probableList[0], "%\n")) + probable += probableList[1] + msg = append(msg, message.Text("鱼竿 : ", probableList[1], "%\n")) + probable += probableList[2] + msg = append(msg, message.Text("鱼类 : ", probableList[2], "%\n")) + probable += probableList[3] + msg = append(msg, message.Text("垃圾 : ", probableList[3], "%\n")) + msg = append(msg, message.Text("合计 : ", probable, "%\n")) + msg = append(msg, message.Text("-----------\n宝藏概率:\n")) + for _, name := range treasureList { + msg = append(msg, message.Text(name, " : ", + strconv.FormatFloat(float64(probabilities[name].Max-probabilities[name].Min)*float64(probableList[0])/100, 'f', 2, 64), + "%\n")) + } + msg = append(msg, message.Text("-----------\n鱼竿概率:\n")) + for _, name := range poleList { + msg = append(msg, message.Text(name, " : ", + strconv.FormatFloat(float64(probabilities[name].Max-probabilities[name].Min)*float64(probableList[0])/100, 'f', 2, 64), + "%\n")) + } + msg = append(msg, message.Text("-----------\n鱼类概率:\n")) + for _, name := range fishList { + msg = append(msg, message.Text(name, " : ", + strconv.FormatFloat(float64(probabilities[name].Max-probabilities[name].Min)*float64(probableList[0])/100, 'f', 2, 64), + "%\n")) + } + msg = append(msg, message.Text("-----------")) + ctx.Send(msg) + }) } func drawPackImage(uid int64, equipInfo equip, articles []article) (imagePicByte []byte, err error) { @@ -205,7 +271,7 @@ func drawEquipInfoBlock(equipInfo equip, fontdata []byte) (image.Image, error) { canvas.SetRGB255(150, 150, 150) canvas.Fill() canvas.SetRGB255(0, 0, 0) - durableW := barW * float64(equipInfo.Durable) / float64(equipAttribute[equipInfo.Equip]) + durableW := barW * float64(equipInfo.Durable) / float64(durationList[equipInfo.Equip]) canvas.DrawRectangle(textDx+textW+5, textDy, durableW, textH*1.2) canvas.SetRGB255(102, 102, 102) canvas.Fill() @@ -345,8 +411,8 @@ func drawArticleInfoBlock(uid int64, articles []article, fontdata []byte) (image textDy += textH * 2 for i, info := range articles { name := info.Name - if info.Other != "" && info.Name != "美西螈" { - if info.Name != "三叉戟" { + if info.Other != "" { + if strings.Contains(info.Name, "竿") { numberOfEquip++ } name += "(" + info.Other + ")" diff --git a/plugin/mcfish/pole.go b/plugin/mcfish/pole.go index f8ff7e1e91..3cf1a5fad2 100644 --- a/plugin/mcfish/pole.go +++ b/plugin/mcfish/pole.go @@ -13,7 +13,7 @@ import ( ) func init() { - engine.OnRegex("^装备(.+竿|美西螈|三叉戟)$", getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + engine.OnRegex(`^装备(`+strings.Join(poleList, "|")+`)$`, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { uid := ctx.Event.UserID equipInfo, err := dbdata.getUserEquip(uid) if err != nil { @@ -31,24 +31,32 @@ func init() { return } poles := make([]equip, 0, len(articles)) - for _, info := range articles { - poleInfo := strings.Split(info.Other, "/") - durable, _ := strconv.Atoi(poleInfo[0]) - maintenance, _ := strconv.Atoi(poleInfo[1]) - induceLevel, _ := strconv.Atoi(poleInfo[2]) - favorLevel, _ := strconv.Atoi(poleInfo[3]) + if thingName != "美西螈" { + for _, info := range articles { + poleInfo := strings.Split(info.Other, "/") + durable, _ := strconv.Atoi(poleInfo[0]) + maintenance, _ := strconv.Atoi(poleInfo[1]) + induceLevel, _ := strconv.Atoi(poleInfo[2]) + favorLevel, _ := strconv.Atoi(poleInfo[3]) + poles = append(poles, equip{ + ID: uid, + Equip: info.Name, + Durable: durable, + Maintenance: maintenance, + Induce: induceLevel, + Favor: favorLevel, + }) + } + } else { poles = append(poles, equip{ - ID: uid, - Equip: info.Name, - Durable: durable, - Maintenance: maintenance, - Induce: induceLevel, - Favor: favorLevel, + ID: uid, + Equip: thingName, + Durable: 999, }) } check := false index := 0 - if thingName != "美西螈" && len(poles) > 1 { + if len(poles) > 1 { msg := make(message.Message, 0, 3+len(articles)) msg = append(msg, message.Reply(ctx.Event.MessageID), message.Text("找到以下鱼竿:\n")) for i, info := range poles { @@ -125,7 +133,6 @@ func init() { Type: "pole", Name: equipInfo.Equip, Number: 1, - Other: strconv.Itoa(equipInfo.Durable) + "/" + strconv.Itoa(equipInfo.Maintenance) + "/" + strconv.Itoa(equipInfo.Induce) + "/" + strconv.Itoa(equipInfo.Favor), } } else { oldthing = articles[0] @@ -240,8 +247,8 @@ func init() { number = 10 } equipInfo.Durable += newEquipInfo.Durable * number / 10 - if equipInfo.Durable > equipAttribute[equipInfo.Equip] { - equipInfo.Durable = equipAttribute[equipInfo.Equip] + if equipInfo.Durable > durationList[equipInfo.Equip] { + equipInfo.Durable = durationList[equipInfo.Equip] } msg := "" if newEquipInfo.Induce != 0 && rand.Intn(100) < 50 { @@ -456,7 +463,7 @@ func init() { ) return } - attribute := strconv.Itoa(equipAttribute[thingName]) + "/0/" + strconv.Itoa(induceLevel/3) + "/" + strconv.Itoa(favorLevel/3) + attribute := strconv.Itoa(durationList[thingName]) + "/0/" + strconv.Itoa(induceLevel/3) + "/" + strconv.Itoa(favorLevel/3) newthing := article{ Duration: time.Now().Unix(), Type: "pole", diff --git a/plugin/mcfish/store.go b/plugin/mcfish/store.go index a6d0198c57..696240e04b 100644 --- a/plugin/mcfish/store.go +++ b/plugin/mcfish/store.go @@ -61,10 +61,10 @@ func init() { } ctx.SendChain(message.ImageBytes(pic)) }) - engine.OnRegex(`^出售(.+(竿|鱼)|河豚|鹦鹉螺|诱钓|海之眷顾|唱片|美西螈|三叉戟)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + engine.OnRegex(`^出售(`+strings.Join(thingList, "|")+`)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { uid := ctx.Event.UserID thingName := ctx.State["regex_matched"].([]string)[1] - number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[3]) + number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[2]) if number == 0 { number = 1 } @@ -142,9 +142,9 @@ func init() { maintenance, _ := strconv.Atoi(poleInfo[1]) induceLevel, _ := strconv.Atoi(poleInfo[2]) favorLevel, _ := strconv.Atoi(poleInfo[3]) - pice = (thingPice[thingName] - (equipAttribute[thingName] - durable) - maintenance*2 + induceLevel*600 + favorLevel*1800) * discount[thingName] / 100 + pice = (priceList[thingName] - (durationList[thingName] - durable) - maintenance*2 + induceLevel*600 + favorLevel*1800) * discountList[thingName] / 100 } else { - pice = thingPice[thingName] * discount[thingName] / 100 + pice = priceList[thingName] * discountList[thingName] / 100 } ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("是否接受商店将以", pice*number*8/10, "收购", number, "个", thingName, "?\n回答\"是\"或\"否\""))) // 等待用户下一步选择 @@ -221,7 +221,7 @@ func init() { } newCommodity := store{} if strings.Contains(thingName, "竿") || thingName == "三叉戟" { - if pice >= thingPice[thingName]*3/4 { // 不值钱的删了 + if pice >= priceList[thingName]*4/5 { // 不值钱的删了 newCommodity = store{ Duration: time.Now().Unix(), Type: "pole", @@ -269,10 +269,10 @@ func init() { } ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("出售成功,你赚到了", pice*number))) }) - engine.OnRegex(`^购买(.+(竿|鱼)|河豚|鹦鹉螺|诱钓|海之眷顾|唱片|美西螈|三叉戟)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { + engine.OnRegex(`^购买(`+strings.Join(thingList, "|")+`)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) { uid := ctx.Event.UserID thingName := ctx.State["regex_matched"].([]string)[1] - number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[3]) + number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[2]) if number == 0 { number = 1 } @@ -294,10 +294,10 @@ func init() { maintenance, _ := strconv.Atoi(poleInfo[1]) induceLevel, _ := strconv.Atoi(poleInfo[2]) favorLevel, _ := strconv.Atoi(poleInfo[3]) - thingPice := (thingPice[info.Name] - (equipAttribute[info.Name] - durable) - maintenance*2 + induceLevel*600 + favorLevel*1800) * discount[info.Name] / 100 + thingPice := (priceList[info.Name] - (durationList[info.Name] - durable) - maintenance*2 + induceLevel*600 + favorLevel*1800) * discountList[info.Name] / 100 pice = append(pice, thingPice) } else { - thingPice := thingPice[info.Name] * discount[info.Name] / 100 + thingPice := priceList[info.Name] * discountList[info.Name] / 100 pice = append(pice, thingPice) } @@ -400,8 +400,7 @@ func init() { return } newCommodity := article{} - switch { - case strings.Contains(thingName, "竿") || thingName == "三叉戟": + if strings.Contains(thingName, "竿") || thingName == "三叉戟" { newCommodity = article{ Duration: time.Now().Unix(), Type: "pole", @@ -409,15 +408,7 @@ func init() { Number: 1, Other: thing.Other, } - case thingName == "美西螈": - newCommodity = article{ - Duration: time.Now().Unix(), - Type: "pole", - Name: thingName, - Number: 1, - Other: "999/0/0/0", - } - default: + } else { things, err1 := dbdata.getUserThingInfo(uid, thingName) if err1 != nil { ctx.SendChain(message.Text("[ERROR at store.go.15]:", err1)) @@ -429,9 +420,12 @@ func init() { Name: thingName, Number: 0, }) - if thingName == "海之眷顾" || thingName == "诱钓" || thingName == "唱片" { + switch { + case thingName == "海之眷顾" || thingName == "诱钓" || thingName == "唱片": things[0].Type = "article" - } else { + case thingName == "美西螈": + things[0].Type = "pole" + default: things[0].Type = "fish" } } @@ -503,7 +497,7 @@ func drawStroeInfoImage(stroeInfo []store) (picImage image.Image, err error) { priceW, _ := canvas.MeasureString("10000") bolckW := int(10 + nameW + 50 + numberW + 50 + priceW + 10) - backY := 10 + int(titleH*2+10)*2 + 10 + (len(stroeInfo)+len(discount)/2+2)*int(textH*2) + 10 + backY := 10 + int(titleH*2+10)*2 + 10 + (len(stroeInfo)+len(discountList)/2+2)*int(textH*2) + 10 canvas = gg.NewContext(bolckW, math.Max(backY, 500)) // 画底色 canvas.DrawRectangle(0, 0, float64(bolckW), float64(backY)) @@ -529,8 +523,8 @@ func drawStroeInfoImage(stroeInfo []store) (picImage image.Image, err error) { textDx, textDh := canvas.MeasureString("下界合金竿(均价1000)") valueDx, _ := canvas.MeasureString("+100%") i := 0 - for name, info := range discount { - text := name + "(均价" + strconv.Itoa(thingPice[name]) + ") " + for name, info := range discountList { + text := name + "(均价" + strconv.Itoa(priceList[name]) + ") " if i == 2 { i = 0 @@ -586,9 +580,9 @@ func drawStroeInfoImage(stroeInfo []store) (picImage image.Image, err error) { maintenance, _ := strconv.Atoi(poleInfo[1]) induceLevel, _ := strconv.Atoi(poleInfo[2]) favorLevel, _ := strconv.Atoi(poleInfo[3]) - pice = (thingPice[info.Name] - (equipAttribute[info.Name] - durable) - maintenance*2 + induceLevel*600 + favorLevel*1800) * discount[info.Name] / 100 + pice = (priceList[info.Name] - (durationList[info.Name] - durable) - maintenance*2 + induceLevel*600 + favorLevel*1800) * discountList[info.Name] / 100 } else { - pice = thingPice[info.Name] * discount[info.Name] / 100 + pice = priceList[info.Name] * discountList[info.Name] / 100 } canvas.DrawStringAnchored(name, 10+nameW/2, textDy+textH/2, 0.5, 0.5) From 9da31034d5e554187b25b85a5bdbddcb2076f7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sun, 3 Sep 2023 09:34:49 +0800 Subject: [PATCH 10/12] Update main.go --- plugin/mcfish/main.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugin/mcfish/main.go b/plugin/mcfish/main.go index d22aa1b47d..726d892ecf 100644 --- a/plugin/mcfish/main.go +++ b/plugin/mcfish/main.go @@ -113,13 +113,14 @@ var ( "- 进行钓鱼\n- 进行n次钓鱼\n" + "规则:\n1.每日的商店价格是波动的!!如何最大化收益自己考虑一下喔\n" + "2.装备信息:\n-> 木竿 : 耐久上限:30 均价:100 上钩概率:0.7%\n-> 铁竿 : 耐久上限:50 均价:300 上钩概率:0.2%\n-> 金竿 : 耐久上限:70 均价700 上钩概率:0.06%\n" + - "-> 钻石竿 : 耐久上限:100 均价1500 上钩概率:0..3%\n-> 下界合金竿 : 耐久上限:150 均价3100 上钩概率:0..1%\n-> 三叉戟 : 可使钓的鱼类物品数量变成3 耐久上限:300 均价4000 只能合成和交易\n" + + "-> 钻石竿 : 耐久上限:100 均价1500 上钩概率:0.03%\n-> 下界合金竿 : 耐久上限:150 均价3100 上钩概率:0.01%\n-> 三叉戟 : 可使钓的鱼类物品数量变成3 耐久上限:300 均价4000 只能合成和交易\n" + "3.附魔书信息:\n-> 诱钓 : 减少上钩时间. 均价:1000, 上钩概率:0.59%\n-> 海之眷顾 : 增加宝藏上钩概率. 均价:2500, 上钩概率:0.39%\n" + "4.稀有物品:\n-> 唱片 : 出售物品时使用该物品使价格翻倍. 均价:3000, 上钩概率:0.01%\n-> 美西螈 : 可装备,获得隐形[钓鱼佬]buff,并让钓到除鱼竿和美西螈外的物品数量变成3,无耐久上限.不可修复/附魔,每次钓鱼消耗任意一鱼类物品. 均价:3000, 上钩概率:0.01%\n" + "5.鱼类信息:\n-> 鳕鱼 : 均价:10 上钩概率:0.69%\n-> 鲑鱼 : 均价:50 上钩概率:0.2%\n-> 热带鱼 : 均价:100 上钩概率:0.06%\n-> 河豚 : 均价:300 上钩概率:0.03%\n-> 鹦鹉螺 : 均价:500 上钩概率:0.01%\n-> 墨鱼 : 均价:500 上钩概率:0.01%\n" + - "6.物品BUFF:\n-> 钓鱼佬 : 当背包名字含有'鱼'的物品数量超过100时激活,钓到物品概率提高至90%\n-> 修复大师 : 当背包鱼竿数量超过10时激活,修复物品时耐久百分百继承\n" + - "7.合成:\n-> 铁竿 : 3x木竿\n-> 金竿 : 3x铁竿\n-> 钻石竿 : 3x金竿\n-> 下界合金竿 : 3x钻石竿\n-> 三叉戟 : 3x下界合金竿\n注:合成成功率90%,继承附魔等级合/3的等级\n" + - "8.杂项:\n-> 无装备的情况下,每人最多可以购买3次100块钱的鱼竿\n-> 默认状态钓鱼上钩概率为60%(理论值!!!)\n-> 附魔的鱼竿会因附魔变得昂贵,每个附魔最高3级\n-> 三叉戟不算鱼竿", + "6.垃圾:\n-> 均价:10 上钩概率:30%\n" + + "7.物品BUFF:\n-> 钓鱼佬 : 当背包名字含有'鱼'的物品数量超过100时激活,钓到物品概率提高至90%\n-> 修复大师 : 当背包鱼竿数量超过10时激活,修复物品时耐久百分百继承\n" + + "8.合成:\n-> 铁竿 : 3x木竿\n-> 金竿 : 3x铁竿\n-> 钻石竿 : 3x金竿\n-> 下界合金竿 : 3x钻石竿\n-> 三叉戟 : 3x下界合金竿\n注:合成成功率90%,继承附魔等级合/3的等级\n" + + "9.杂项:\n-> 无装备的情况下,每人最多可以购买3次100块钱的鱼竿\n-> 默认状态钓鱼上钩概率为60%(理论值!!!)\n-> 附魔的鱼竿会因附魔变得昂贵,每个附魔最高3级\n-> 三叉戟不算鱼竿", PublicDataFolder: "McFish", }).ApplySingle(ctxext.DefaultSingle) getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { From c5f7552ac00ada56708b4c1852fe6b1f0a5ac4d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sun, 3 Sep 2023 09:39:16 +0800 Subject: [PATCH 11/12] Update pack.go --- plugin/mcfish/pack.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/mcfish/pack.go b/plugin/mcfish/pack.go index f57d6df48f..053d9a6dc6 100644 --- a/plugin/mcfish/pack.go +++ b/plugin/mcfish/pack.go @@ -96,13 +96,13 @@ func init() { msg = append(msg, message.Text("-----------\n鱼竿概率:\n")) for _, name := range poleList { msg = append(msg, message.Text(name, " : ", - strconv.FormatFloat(float64(probabilities[name].Max-probabilities[name].Min)*float64(probableList[0])/100, 'f', 2, 64), + strconv.FormatFloat(float64(probabilities[name].Max-probabilities[name].Min)*float64(probableList[1])/100, 'f', 2, 64), "%\n")) } msg = append(msg, message.Text("-----------\n鱼类概率:\n")) for _, name := range fishList { msg = append(msg, message.Text(name, " : ", - strconv.FormatFloat(float64(probabilities[name].Max-probabilities[name].Min)*float64(probableList[0])/100, 'f', 2, 64), + strconv.FormatFloat(float64(probabilities[name].Max-probabilities[name].Min)*float64(probableList[2])/100, 'f', 2, 64), "%\n")) } msg = append(msg, message.Text("-----------")) From f15ac7c56093bea95f46befcba4fc55cefd6b706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=B9=E6=9F=B3=E7=85=9C?= <101934327+fangliuyu@users.noreply.github.com> Date: Sun, 3 Sep 2023 11:06:05 +0800 Subject: [PATCH 12/12] Add files via upload --- plugin/mcfish/fish.go | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/plugin/mcfish/fish.go b/plugin/mcfish/fish.go index 7b9736e4f8..4045b3eea6 100644 --- a/plugin/mcfish/fish.go +++ b/plugin/mcfish/fish.go @@ -27,16 +27,6 @@ func init() { } fishNumber = number } - residue, err := dbdata.updateFishInfo(uid, fishNumber) - if err != nil { - ctx.SendChain(message.Text("[ERROR at fish.go.1]:", err)) - return - } - if residue == 0 { - ctx.SendChain(message.Text("今天你已经进行", FishLimit, "次钓鱼了.\n游戏虽好,但请不要沉迷。")) - return - } - fishNumber = residue equipInfo, err := dbdata.getUserEquip(uid) if err != nil { ctx.SendChain(message.Text("[ERROR at fish.go.2]:", err)) @@ -99,9 +89,20 @@ func init() { break } } - } else if equipInfo.Durable < fishNumber { + } + if equipInfo.Durable < fishNumber { fishNumber = equipInfo.Durable } + residue, err := dbdata.updateFishInfo(uid, fishNumber) + if err != nil { + ctx.SendChain(message.Text("[ERROR at fish.go.1]:", err)) + return + } + if residue == 0 { + ctx.SendChain(message.Text("今天你已经进行", FishLimit, "次钓鱼了.\n游戏虽好,但请不要沉迷。")) + return + } + fishNumber = residue msg := "" if equipInfo.Equip != "美西螈" { equipInfo.Durable -= fishNumber @@ -110,8 +111,10 @@ func init() { ctx.SendChain(message.Text("[ERROR at fish.go.5]:", err)) return } - if equipInfo.Durable < 10 { + if equipInfo.Durable < 10 || equipInfo.Durable > 0 { msg = "(你的鱼竿耐久仅剩" + strconv.Itoa(equipInfo.Durable) + ")" + } else if equipInfo.Durable <= 0 { + msg = "(你的鱼竿耐已销毁)" } } else { fishNmaes, err := dbdata.pickFishFor(uid, fishNumber)