diff --git a/plugin/genshin/ys.go b/plugin/genshin/ys.go new file mode 100644 index 00000000..38746aeb --- /dev/null +++ b/plugin/genshin/ys.go @@ -0,0 +1,453 @@ +package genshin + +import ( + "archive/zip" + "fmt" + "image" + "image/color" + "image/draw" + "image/jpeg" + "image/png" + "io" + "math/rand" + "os" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "time" + + control "github.com/FloatTech/zbputils/control" + "github.com/FloatTech/zbputils/control/order" + "github.com/FloatTech/zbputils/file" + "github.com/golang/freetype" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +var ( + //genzip = "https://gitcode.net/qq_33747476/Images/-/raw/master/zero/Genshin.zip" + genzip = "https://raw.githubusercontent.com/FloatTech/zbpdata/main/Genshin/Genshin.zip" //素材包 + Three, four, four2, five, five2 = []string{}, []string{}, []string{}, []string{}, []string{} //三 , 四, 五星的名字 + + DP, gen, ZipN, Spath = "./data/Genshin/", "_genshin.jpg", DP + "Genshin.zip", DP + "gacha/" //路径 + five_bg, four_bg, three_bg = DP + "five_bg.jpg", DP + "four_bg.jpg", DP + "three_bg.jpg" //背景图片名 + StarN3, StarN4, StarN5 = Spath + "ThreeStar.png", Spath + "FourStar.png", Spath + "FiveStar.png" //星级图标 + + Toatl, IMGN, isPath, Lock = 0, 0, false, false //累计抽奖次数, 卡池总数, 是否遍历过路径, 锁 + DefaultMode, FiveMode, iPrefix = true, false, 0 //抽卡模式,文件前缀 + + engine = control.Register("genshin", order.AcquirePrio(), &control.Options{ + DisableOnDefault: false, + Help: "genshin\n@bot\n- 十连\n- 十连抽\n- 切换卡池\n- 刷新卡池", + }) +) + +func init() { + + engine.OnFullMatchGroup([]string{"刷新卡池"}, zero.OnlyToMe).SetBlock(false). + Handle(func(ctx *zero.Ctx) { + if IsExists(DP) { + IMGN = 0 + LoadFolder() + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("刷新完成!\n数量:", IMGN)) + IMGN = 0 + } else { + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("没有素材哦~\n请发送 十连 \n下载素材..")) + } + }) + + engine.OnFullMatchGroup([]string{"切换卡池"}, zero.OnlyToMe).SetBlock(false). + Handle(func(ctx *zero.Ctx) { + if !DefaultMode { + DefaultMode, FiveMode = true, false + ctx.SendChain(message.Text("切换到普通卡池~")) + } else { + DefaultMode, FiveMode = false, true + ctx.SendChain(message.Text("切换到五星卡池~")) + } + }) + //@bot + engine.OnFullMatchGroup([]string{"十连", "十连抽", "来发十连", "来次十连", "来份十连"}, zero.OnlyToMe).SetBlock(false). + Handle(func(ctx *zero.Ctx) { + times := time.Now().Unix() + iPrefix++ + if !isPath { + if Lock { + return + } + if !IsExists(DP) && !Lock { + Lock = true + ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("素材未下载...\n是否需要下载素材\n下载素材|取消下载")) + ch := make(chan int, 1) + defer close(ch) + rule := func(ctx *zero.Ctx) bool { + for _, v := range ctx.Event.Message { + if v.Type == "text" { + text := strings.ReplaceAll(v.Data["text"], " ", "") + if text == "下载素材" { + return true + } + if text == "取消下载" { + ch <- 1 + return false + } + } + } + return false + } + next := zero.NewFutureEvent("message", 999, false, zero.CheckUser(ctx.Event.UserID), rule) + recv, cancel := next.Repeat() + select { + case <-time.After(time.Second * 60): + Lock = false + cancel() + return + case <-recv: + cancel() + ctx.SendChain(message.Text("正在下载中~")) + os.Mkdir(DP, 0755) + err := file.DownloadTo(genzip, ZipN, true) + Lock = false + if err != nil { + ctx.SendChain(message.Text("下载出错了~", err)) + return + } + case <-ch: + cancel() + ctx.SendChain(message.Text("取消了呢~")) + Lock = false + close(ch) + return + } + err := unzip(ZipN, "./data/") + if err != nil { + ctx.SendChain(message.Text("解压出错了~", err)) + } + ctx.SendChain(message.Text("下载完成~")) + os.Remove(ZipN) + os.Chmod(DP, 0755) + return + } else { + LoadFolder() + } + } + Str := strconv.Itoa(iPrefix) + defer os.Remove(DP + Str + gen) //删除图片 + Add(Str) + ctx.SendChain(message.At(ctx.Event.UserID), message.Text("十连成功~"), + message.Image("file:///"+file.Pwd()+"/data/Genshin/"+Str+gen)) + fmt.Printf("OK %v 秒\n", time.Now().Unix()-times) + }) +} + +func Add(sf string) { + var ( + fourName, fiveName = []string{}, []string{} //抽到 四, 五星角色的名字 + ThreeArms, fourArms, fiveArms = []string{}, []string{}, []string{} //抽到 三 , 四, 五星武器的名字 + + fourN, fiveN, Nums, bgs = 0, 0, 10, []string{} //抽到 四, 五星角色的数量, 连抽次数, 背景图片名 + ThreeN2, fourN2, fiveN2 = 0, 0, 0 //抽到 三 , 四, 五星武器的数量 + Hero, StarName = []string{}, []string{} //角色武器名, 储存星级图标 + + Cicon, He_N = []string{}, []string{} //元素图标 + ) + + rand.Seed(time.Now().UnixNano()) + if Toatl == 9 { //累计9次十连加入一个五星 + switch a := rand.Intn(2); a { + case 0: + fiveN++ + f := rand.Intn(len(five)) + fiveName = append(fiveName, five[f]) + case 1: + fiveN2++ + f := rand.Intn(len(five2)) + fiveArms = append(fiveArms, five2[f]) + } + Toatl, Nums = 0, 9 + } + + if DefaultMode { //默认模式 + for i := 0; i < Nums; i++ { + a := rand.Intn(1000) + if a >= 0 && a <= 750 { //抽卡几率 三星75% 四星18% 五星7% + ThreeN2++ + ta := rand.Intn(len(Three)) //名字总个数 + ThreeArms = append(ThreeArms, Three[ta]) + } else if a > 750 && a <= 840 { + fourN++ + tb := rand.Intn(len(four)) + fourName = append(fourName, four[tb]) //随机角色 + } else if a > 840 && a <= 930 { + fourN2++ + tb := rand.Intn(len(four2)) + fourArms = append(fourArms, four2[tb]) //随机武器 + } else if a > 930 && a <= 965 { + fiveN++ + tc := rand.Intn(len(five)) + fiveName = append(fiveName, five[tc]) + } else if a > 965 { + fiveN2++ + tc := rand.Intn(len(five2)) + fiveArms = append(fiveArms, five2[tc]) + } + } + if fourN+fourN2 == 0 && ThreeN2 > 0 { //没有四星时自动加入 + ThreeN2-- + ThreeArms = ThreeArms[:len(ThreeArms)-1] + switch a := rand.Intn(2); a { + case 0: + fourN++ + f := rand.Intn(len(four)) + fourName = append(fourName, four[f]) //随机角色 + case 1: + fourN2++ + f := rand.Intn(len(four2)) + fourArms = append(fourArms, four2[f]) //随机武器 + } + } + Toatl++ //次数+1 + } + + if FiveMode { //5星模式 + for i := 0; i < Nums; i++ { + a := rand.Intn(100) + if a >= 0 && a <= 50 { + fiveN++ + tc := rand.Intn(len(five)) + fiveName = append(fiveName, five[tc]) //随机角色 + } else if a > 50 { + fiveN2++ + tc := rand.Intn(len(five2)) + fiveArms = append(fiveArms, five2[tc]) //随机武器 + } + } + } + //正则取出图标名 + Addicon := func(Prefix string) string { + + regC, _ := regexp.Compile(`\/[a-z]+_`) + regC2, _ := regexp.Compile(`\/`) + + if runtime.GOOS == "windows" { + regC, _ = regexp.Compile(`\\[a-z]+_`) + regC2, _ = regexp.Compile(`\\`) + } + Pr := regC.FindAllString(Prefix, 1) //取出字符 + str := strings.Join(Pr, "") //连接字符 + Sp := strings.Split(str, "_") + Str2 := strings.Join(Sp, "") + Str3 := regC2.ReplaceAllString(Str2, "") + + switch Str3 { + case "anemo": + return DP + "anemo.png" + case "cryo": + return DP + "cryo.png" + case "dendro": + return DP + "dendro.png" + case "electro": + return DP + "electro.png" + case "geo": + return DP + "geo.png" + case "hydro": + return DP + "hydro.png" + case "pyro": + return DP + "pyro.png" + case "bow": + return DP + "bow.png" + case "catalyst": + return DP + "catalyst.png" + case "claymore": + return DP + "claymore.png" + case "polearm": + return DP + "polearm.png" + default: + return DP + "sword.png" + } + } + + He := func(StarNum int, id int, Star string, bg string) { + for i := 0; i < StarNum; i++ { + switch id { + case 1: + He_N = ThreeArms + case 2: + He_N = fourArms + case 3: + He_N = fourName + case 4: + He_N = fiveArms + case 5: + He_N = fiveName + } + bgs = append(bgs, bg) //加入颜色背景 + Hero = append(Hero, He_N[i]) + StarName = append(StarName, Star) //加入星级图标 + Cicon = append(Cicon, Addicon(He_N[i])) //加入元素图标 + } + } + + if fiveN > 0 { //按顺序加入 + He(fiveN, 5, StarN5, five_bg) //五星角色 + } + if fourN > 0 { + He(fourN, 3, StarN4, four_bg) //四星角色 + } + if fiveN2 > 0 { + He(fiveN2, 4, StarN5, five_bg) //五星武器 + } + if fourN2 > 0 { + He(fourN2, 2, StarN4, four_bg) //四星武器 + } + if ThreeN2 > 0 { + He(ThreeN2, 1, StarN3, three_bg) //三星武器 + } + // fmt.Printf("三星数量 = %v 四星数量 = %v 五星数量 = %v\n", ThreeN2, fourN+fourN2, fiveN+fiveN2) + // fmt.Printf("三星 = %v \n四星 = %v%v \n五星 = %v%v\n", ThreeArms, fourName, fourArms, fiveName, fiveArms) + + var ( + inp = DP + "bg0.jpg" //背景导入图片路径 + c1, c2, c3 uint8 = 50, 50, 50 //背景颜色 + opt jpeg.Options + //字体rgb 205, 205, 205 + ) + + rectangle := image.Rect(0, 0, 1920, 1080) // 图片宽度, 图片高度 + rgba := image.NewRGBA(rectangle) + draw.Draw(rgba, rgba.Bounds(), image.NewUniform(color.RGBA{c1, c2, c3, 255}), image.Point{}, draw.Over) + context := freetype.NewContext() // 创建一个新的上下文 + context.SetDPI(72) //每英寸 dpi + context.SetClip(rgba.Bounds()) + context.SetDst(rgba) + + img00, _ := os.Open(inp) // 打开背景图片 + defer img00.Close() + img0, _ := jpeg.Decode(img00) //读取一个本地图像 + offset := image.Pt(0, 0) //图片在背景上的位置 + draw.Draw(rgba, img0.Bounds().Add(offset), img0, image.Point{}, draw.Over) + + OpenW1, OpenH1 := 230, 0 + for i := 0; i < len(Hero); i++ { + if i > 0 { + OpenW1 += 146 //图片宽度 + } + imgs, _ := os.Open(bgs[i]) //取出背景图片 + defer imgs.Close() + img, _ := jpeg.Decode(imgs) + offset := image.Pt(OpenW1, OpenH1) + draw.Draw(rgba, img.Bounds().Add(offset), img, image.Point{}, draw.Over) + + imgs1, _ := os.Open(Hero[i]) //取出图片名 + defer imgs1.Close() + img1, _ := png.Decode(imgs1) + offset1 := image.Pt(OpenW1, OpenH1) + draw.Draw(rgba, img1.Bounds().Add(offset1), img1, image.Point{}, draw.Over) + + imgs2, _ := os.Open(StarName[i]) //取出星级图标 + defer imgs2.Close() + img2, _ := png.Decode(imgs2) + offset2 := image.Pt(OpenW1, OpenH1) + draw.Draw(rgba, img2.Bounds().Add(offset2), img2, image.Point{}, draw.Over) + + imgs3, _ := os.Open(Cicon[i]) //取出类型图标 + defer imgs3.Close() + img3, _ := png.Decode(imgs3) + offset3 := image.Pt(OpenW1, OpenH1) + draw.Draw(rgba, img3.Bounds().Add(offset3), img3, image.Point{}, draw.Over) + } + imgs4, _ := os.Open(DP + "Reply.png") //"分享" 图标 + defer imgs4.Close() + img4, _ := png.Decode(imgs4) + offset4 := image.Pt(1270, 945) //宽, 高 + draw.Draw(rgba, img4.Bounds().Add(offset4), img4, image.Point{}, draw.Over) + + file, err := os.Create(DP + sf + gen) //输出图片 + + if err != nil { + fmt.Printf("输出图片错误: %v\n", err) + return + } + defer file.Close() + //png.Encode(file, rgba) //输出png + opt.Quality = 100 + jpeg.Encode(file, rgba, &opt) //输出jpg +} + +//遍历文件夹 +func LoadFolder() { + isPath = true + Three, four = []string{}, []string{} //重置变量 + four2, five, five2 = []string{}, []string{}, []string{} + ReadPath(DP+"Three", "Three") + ReadPath(DP+"four", "four") + ReadPath(DP+"four2", "four2") + ReadPath(DP+"five", "five") + ReadPath(DP+"five2", "five2") +} + +func ReadPath(lpath string, star string) { + err := filepath.Walk(lpath, func(filename string, fi os.FileInfo, err error) error { + if fi.IsDir() { // 忽略目录 + return nil + } + f := filename + if star == "five" { + five = append(five, "./"+f) + } else if star == "five2" { + five2 = append(five2, "./"+f) + } else if star == "four" { + four = append(four, "./"+f) + } else if star == "four2" { + four2 = append(four2, "./"+f) + } else { + Three = append(Three, "./"+f) + } + IMGN++ + return nil + }) + if err != nil { + fmt.Printf("读取文件错误%v\n", err) + } +} + +func IsExists(path string) bool { //判断文件是否存在 + _, err := os.Stat(path) + if err != nil && !os.IsExist(err) { + return false + } + return true +} + +//解压缩 +func unzip(zipFile string, destDir string) error { + zipReader, err := zip.OpenReader(zipFile) + if err != nil { + return err + } + defer zipReader.Close() + for _, f := range zipReader.File { + fpath := filepath.Join(destDir, f.Name) + if f.FileInfo().IsDir() { + os.MkdirAll(fpath, os.ModePerm) + } else { + if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { + return err + } + inFile, err := f.Open() //读取压缩文件 + if err != nil { + return err + } + defer inFile.Close() + outFile, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, f.Mode()) //创建的新文件 + if err != nil { + return err + } + defer outFile.Close() + _, _ = io.Copy(outFile, inFile) + } + } + return err +}