diff --git a/README.md b/README.md
index 05828a3393..1b36f9df17 100644
--- a/README.md
+++ b/README.md
@@ -1009,22 +1009,6 @@ print("run[CQ:image,file="+j["img"]+"]")
- 注:刷新文件夹较慢,请耐心等待刷新完成,会提示“成功”。
-
-
- 抽wife
-
- `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/nativewife"`
-
- - [x] 抽wife[@xxx]
-
- - [x] 添加wife[名字][图片]
-
- - [x] 删除wife[名字]
-
- - [x] [让 | 不让]所有人均可添加wife
-
- - 注:不同群添加后不会重叠
-
拼音首字母释义工具
@@ -1067,6 +1051,42 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 当图片属于非 neutral 类别时自动发送评价(默认禁用,启用输入 /启用 nsfwauto)
+
+
+ 抽wife
+
+ `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/nwife"`
+
+ - [x] 抽wife[@xxx]
+
+ - [x] 添加wife[名字][图片]
+
+ - [x] 删除wife[名字]
+
+ - [x] [让 | 不让]所有人均可添加wife
+
+ - 注:不同群添加后不会重叠
+
+
+
+ 牛牛大作战
+
+`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/niuniu" `
+
+- [x] 打胶
+
+- [x] jj[@xxx]
+
+- [x] 注册牛牛
+
+- [x] 注销牛牛
+
+- [x] 牛子长度排行
+
+- [x] 牛子深度排行
+
+- [x] 查看我的牛牛
+
浅草寺求签
diff --git a/main.go b/main.go
index d21599c505..66f5d2b803 100644
--- a/main.go
+++ b/main.go
@@ -116,6 +116,7 @@ import (
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/novel" // 铅笔小说网搜索
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nsfw" // nsfw图片识别
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nwife" // 本地老婆
+ _ "github.com/FloatTech/ZeroBot-Plugin/plugin/niuniu" // 牛牛大作战
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/omikuji" // 浅草寺求签
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/poker" // 抽扑克
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife" // 一群一天一夫一妻制群老婆
diff --git a/plugin/niuniu/main.go b/plugin/niuniu/main.go
new file mode 100644
index 0000000000..5d04b218a1
--- /dev/null
+++ b/plugin/niuniu/main.go
@@ -0,0 +1,244 @@
+// Package niuniu 牛牛大作战
+package niuniu
+
+import (
+ "fmt"
+ ctrl "github.com/FloatTech/zbpctrl"
+ "github.com/FloatTech/zbputils/control"
+ "github.com/FloatTech/zbputils/ctxext"
+ zero "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/extension/rate"
+ "github.com/wdvxdr1123/ZeroBot/message"
+ "math/rand"
+ "strconv"
+ "strings"
+ "time"
+)
+
+var (
+ en = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
+ DisableOnDefault: false,
+ Brief: "牛牛大作战",
+ Help: "- 打胶\n" +
+ "- 注册牛牛\n" +
+ "- 注销牛牛\n" +
+ "- 查看我的牛牛\n" +
+ "- jj@xxx\n" +
+ "- 牛子长度排行\n" +
+ "- 牛子深度排行\n",
+ PrivateDataFolder: "niuniu",
+ })
+ dajiaoLimiter = rate.NewManager[string](time.Second*90, 1)
+ jjLimiter = rate.NewManager[string](time.Second*150, 1)
+)
+
+func init() {
+ en.OnFullMatch("牛子长度排行", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) {
+ gid := ctx.Event.GroupID
+ niuniuList, err := db.readAllTable(gid)
+ if err != nil {
+ ctx.SendChain(message.Text("ERROR: ", err))
+ return
+ }
+ m := niuniuList.positive()
+ if m == nil {
+ ctx.SendChain(message.Text("暂时没有男孩子哦"))
+ return
+ }
+ var messages strings.Builder
+ messages.WriteString("牛子长度排行\n")
+ for i, user := range niuniuList.sort(true) {
+ messages.WriteString(fmt.Sprintf("第%d名 id:%s 长度:%.2fcm\n", i+1,
+ ctx.CardOrNickName(user.UID), user.Length))
+ }
+ msg := ctxext.FakeSenderForwardNode(ctx, message.Text(&messages))
+ if id := ctx.Send(message.Message{msg}).ID(); id == 0 {
+ ctx.Send(message.Text("发送排行失败"))
+ }
+ })
+ en.OnFullMatch("牛子深度排行", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) {
+ gid := ctx.Event.GroupID
+ niuniuList, err := db.readAllTable(gid)
+ if err != nil {
+ ctx.SendChain(message.Text("ERROR: ", err))
+ return
+ }
+ m := niuniuList.negative()
+ if m == nil {
+ ctx.SendChain(message.Text("暂时没有女孩子哦"))
+ return
+ }
+ var messages strings.Builder
+ messages.WriteString("牛牛深度排行榜\n")
+ for i, user := range niuniuList.sort(false) {
+ messages.WriteString(fmt.Sprintf("第%d名 id:%s 长度:%.2fcm\n", i+1,
+ ctx.CardOrNickName(user.UID), user.Length))
+ }
+ msg := ctxext.FakeSenderForwardNode(ctx, message.Text(&messages))
+ if id := ctx.Send(message.Message{msg}).ID(); id == 0 {
+ ctx.Send(message.Text("发送排行失败"))
+ }
+ })
+ en.OnFullMatch("查看我的牛牛", getdb, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
+ uid := ctx.Event.UserID
+ gid := ctx.Event.GroupID
+ niuniu, err := db.findniuniu(gid, uid)
+ if err != nil {
+ ctx.SendChain(message.Text("你还没有牛牛呢不能查看!"))
+ return
+ }
+ var result strings.Builder
+ sexLong := "长"
+ sex := "♂️"
+ if niuniu < 0 {
+ sexLong = "深"
+ sex = "♀️"
+ }
+ niuniuList, err := db.readAllTable(gid)
+ if err != nil {
+ ctx.SendChain(message.Text("ERROR:", err))
+ return
+ }
+ result.WriteString(fmt.Sprintf("\n📛%s<%s>的牛牛信息\n⭕性别:%s\n⭕%s度:%.2fcm\n⭕排行:%d\n⭕%s ",
+ ctx.CardOrNickName(uid), strconv.FormatInt(uid, 10),
+ sex, sexLong, niuniu, niuniuList.ranking(niuniu, uid), generateRandomString(niuniu)))
+ ctx.SendChain(message.At(uid), message.Text(&result))
+ })
+ en.OnFullMatchGroup([]string{"dj", "打胶"}, zero.OnlyGroup,
+ getdb).SetBlock(true).Limit(func(ctx *zero.Ctx) *rate.Limiter {
+ lt := dajiaoLimiter.Load(fmt.Sprintf("%d_%d", ctx.Event.GroupID, ctx.Event.UserID))
+ ctx.State["dajiao_last_touch"] = lt.LastTouch()
+ return lt
+ }, func(ctx *zero.Ctx) {
+ timePass := int(time.Since(time.Unix(ctx.State["dajiao_last_touch"].(int64), 0)).Seconds())
+ ctx.SendChain(message.Text(randomChoice([]string{
+ fmt.Sprintf("才过去了%ds时间,你就又要打🦶了,身体受得住吗", timePass),
+ fmt.Sprintf("不行不行,你的身体会受不了的,歇%ds再来吧", 90-timePass),
+ fmt.Sprintf("休息一下吧,会炸膛的!%ds后再来吧", 90-timePass),
+ fmt.Sprintf("打咩哟,你的牛牛会爆炸的,休息%ds再来吧", 90-timePass),
+ })))
+ }).Handle(func(ctx *zero.Ctx) {
+ // 获取群号和用户ID
+ gid := ctx.Event.GroupID
+ uid := ctx.Event.UserID
+ niuniu, err := db.findniuniu(gid, uid)
+ if err != nil {
+ ctx.SendChain(message.Text("请先注册牛牛!"))
+ dajiaoLimiter.Delete(fmt.Sprintf("%d_%d", gid, uid))
+ return
+ }
+ messages, f := generateRandomStingTwo(niuniu)
+ u := userInfo{
+ UID: uid,
+ Length: f,
+ }
+ ctx.SendChain(message.Text(messages))
+ if err = db.insertniuniu(&u, gid); err != nil {
+ ctx.SendChain(message.Text("ERROR:", err))
+ return
+ }
+ })
+ en.OnFullMatch("注册牛牛", zero.OnlyGroup, getdb).SetBlock(true).Handle(func(ctx *zero.Ctx) {
+ gid := ctx.Event.GroupID
+ uid := ctx.Event.UserID
+ if _, err := db.findniuniu(gid, uid); err == nil {
+ ctx.SendChain(message.Text("你已经注册过了"))
+ return
+ }
+ //获取初始长度
+ long := db.randLength()
+ u := userInfo{
+ UID: uid,
+ Length: long,
+ UserCount: 0,
+ }
+ //添加数据进入表
+ err := db.insertniuniu(&u, gid)
+ if err != nil {
+ err = db.createGIDTable(gid)
+ if err != nil {
+ ctx.SendChain(message.Text("ERROR:", err))
+ return
+ }
+ err = db.insertniuniu(&u, gid)
+ if err != nil {
+ ctx.SendChain(message.Text("ERROR:", err))
+ return
+ }
+ }
+ ctx.SendChain(message.Reply(ctx.Event.GroupID),
+ message.Text("注册成功,你的牛牛现在有", u.Length, "cm"))
+ })
+ en.OnRegex(`jj\[CQ:at,qq=(\d+),name=[\s\S]*\]$`, getdb,
+ zero.OnlyGroup).SetBlock(true).Limit(func(ctx *zero.Ctx) *rate.Limiter {
+ lt := jjLimiter.Load(fmt.Sprintf("%d_%d", ctx.Event.GroupID, ctx.Event.UserID))
+ ctx.State["jj_last_touch"] = lt.LastTouch()
+ return lt
+ }, func(ctx *zero.Ctx) {
+ timePass := int(time.Since(time.Unix(ctx.State["jj_last_touch"].(int64), 0)).Seconds())
+ ctx.SendChain(message.Text(randomChoice([]string{
+ fmt.Sprintf("才过去了%ds时间,你就又要击剑了,真是饥渴难耐啊", timePass),
+ fmt.Sprintf("不行不行,你的身体会受不了的,歇%ds再来吧", 150-timePass),
+ fmt.Sprintf("你这种男同就应该被送去集中营!等待%ds再来吧", 150-timePass),
+ fmt.Sprintf("打咩哟!你的牛牛会炸的,休息%ds再来吧", 150-timePass),
+ })))
+ },
+ ).Handle(func(ctx *zero.Ctx) {
+ adduser, err := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64)
+ if err != nil {
+ ctx.SendChain(message.Text("ERROR:", err))
+ return
+ }
+ uid := ctx.Event.UserID
+ gid := ctx.Event.GroupID
+ myniuniu, err := db.findniuniu(gid, uid)
+ if err != nil {
+ ctx.SendChain(message.Text("你还没有牛牛快去注册一个吧!"))
+ jjLimiter.Delete(fmt.Sprintf("%d_%d", gid, uid))
+ return
+ }
+ adduserniuniu, err := db.findniuniu(gid, adduser)
+ if err != nil {
+ ctx.SendChain(message.At(uid), message.Text("对方还没有牛牛呢,不能🤺"))
+ jjLimiter.Delete(fmt.Sprintf("%d_%d", gid, uid))
+ return
+ }
+ if uid == adduser {
+ ctx.SendChain(message.Text("你要和谁🤺?你自己吗?"))
+ jjLimiter.Delete(fmt.Sprintf("%d_%d", gid, uid))
+ return
+ }
+ fencingResult, f, f1 := fencing(myniuniu, adduserniuniu)
+ err = db.insertniuniu(&userInfo{UID: uid, Length: f}, gid)
+ if err != nil {
+ ctx.SendChain(message.Text("ERROR:", err))
+ return
+ }
+ err = db.insertniuniu(&userInfo{UID: adduser, Length: f1}, gid)
+ if err != nil {
+ ctx.SendChain(message.Text("ERROR:", err))
+ return
+ }
+ ctx.SendChain(message.At(uid), message.Text(fencingResult))
+ })
+ en.OnFullMatch("注销牛牛", getdb, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
+ uid := ctx.Event.UserID
+ gid := ctx.Event.GroupID
+ _, err := db.findniuniu(gid, uid)
+ if err != nil {
+ ctx.SendChain(message.Text("你还没有牛牛呢,咋的你想凭空造一个啊"))
+ return
+ }
+ err = db.deleteniuniu(gid, uid)
+ if err != nil {
+ ctx.SendChain(message.Text("注销失败"))
+ return
+ }
+ ctx.SendChain(message.Text("注销成功,你已经没有牛牛了"))
+ })
+}
+
+func randomChoice(options []string) string {
+ return options[rand.Intn(len(options))]
+}
+
diff --git a/plugin/niuniu/model.go b/plugin/niuniu/model.go
new file mode 100644
index 0000000000..0f7462b1a2
--- /dev/null
+++ b/plugin/niuniu/model.go
@@ -0,0 +1,119 @@
+// Package niuniu 牛牛大作战
+package niuniu
+
+import (
+ fcext "github.com/FloatTech/floatbox/ctxext"
+ sql "github.com/FloatTech/sqlite"
+ zero "github.com/wdvxdr1123/ZeroBot"
+ "github.com/wdvxdr1123/ZeroBot/message"
+ "math/rand"
+ "sort"
+ "strconv"
+ "sync"
+ "time"
+)
+
+type model struct {
+ sql sql.Sqlite
+ sync.RWMutex
+}
+
+type userInfo struct {
+ UID int64
+ Length float64
+ UserCount int
+}
+type users []*userInfo
+
+var (
+ db = &model{}
+ getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
+ db.sql.DBPath = en.DataFolder() + "niuniu.db"
+ err := db.sql.Open(time.Hour * 24)
+ if err != nil {
+ ctx.SendChain(message.Text("ERROR: ", err))
+ return false
+ }
+ return true
+ })
+)
+
+func (m users) positive() []userInfo {
+ var m1 []userInfo
+ for _, i2 := range m {
+ if i2.Length > 0 {
+ m1 = append(m1, *i2)
+ }
+ }
+ return m1
+}
+
+func (m users) negative() []userInfo {
+ var m1 []userInfo
+ for _, i2 := range m {
+ if i2.Length <= 0 {
+ m1 = append(m1, *i2)
+ }
+ }
+ return m1
+}
+
+func (m users) sort(isDesc bool) users {
+ t := func(i, j int) bool {
+ return m[i].UserCount < m[j].UserCount
+ }
+ if isDesc {
+ t = func(i, j int) bool {
+ return m[i].Length > m[j].Length
+ }
+ }
+ sort.Slice(m, t)
+ return m
+}
+
+func (m users) ranking(niuniu float64, uid int64) int {
+ result := niuniu > 0
+ for i, user := range m.sort(result) {
+ if user.UID == uid {
+ return i + 1
+ }
+ }
+ return -1
+}
+
+func (db *model) randLength() float64 {
+ return float64(rand.Intn(9)+1) + (float64(rand.Intn(100)) / 100)
+}
+
+func (db *model) createGIDTable(gid int64) error {
+ db.Lock()
+ defer db.Unlock()
+ return db.sql.Create(strconv.FormatInt(gid, 10), &userInfo{})
+}
+
+func (db *model) findniuniu(gid, uid int64) (float64, error) {
+ db.RLock()
+ defer db.RUnlock()
+ u := userInfo{}
+ err := db.sql.Find(strconv.FormatInt(gid, 10), &u, "where UID = "+strconv.FormatInt(uid, 10))
+ return u.Length, err
+}
+
+func (db *model) insertniuniu(u *userInfo, gid int64) error {
+ db.Lock()
+ defer db.Unlock()
+ return db.sql.Insert(strconv.FormatInt(gid, 10), u)
+}
+
+func (db *model) deleteniuniu(gid, uid int64) error {
+ db.Lock()
+ defer db.Unlock()
+ return db.sql.Del(strconv.FormatInt(gid, 10), "where UID = "+strconv.FormatInt(uid, 10))
+}
+
+func (db *model) readAllTable(gid int64) (users, error) {
+ db.Lock()
+ defer db.Unlock()
+ a, err := sql.FindAll[userInfo](&db.sql, strconv.FormatInt(gid, 10), "where UserCount = 0")
+ return a, err
+}
diff --git a/plugin/niuniu/utils.go b/plugin/niuniu/utils.go
new file mode 100644
index 0000000000..77575e5fa8
--- /dev/null
+++ b/plugin/niuniu/utils.go
@@ -0,0 +1,192 @@
+// Package niuniu 牛牛大作战
+package niuniu
+
+import (
+ "fmt"
+ "math"
+ "math/rand"
+ "time"
+)
+
+func generateRandomStingTwo(niuniu float64) (string, float64) {
+ probability := rand.Intn(100 + 1)
+ reduce := math.Abs(hitGlue(niuniu))
+ switch {
+ case probability <= 40:
+ niuniu += reduce
+ return randomChoice([]string{
+ fmt.Sprintf("你嘿咻嘿咻一下,促进了牛牛发育,牛牛增加%.2fcm了呢!", reduce),
+ fmt.Sprintf("你打了个舒服痛快的🦶呐,牛牛增加了%.2fcm呢!", reduce),
+ }), niuniu
+ case probability <= 60:
+ return randomChoice([]string{
+ "你打了个🦶,但是什么变化也没有,好奇怪捏~",
+ "你的牛牛刚开始变长了,可过了一会又回来了,什么变化也没有,好奇怪捏~",
+ }), niuniu
+ default:
+ niuniu -= reduce
+ if niuniu < 0 {
+ return randomChoice([]string{
+ fmt.Sprintf("哦吼!?看来你的牛牛凹进去了%.2fcm呢!", reduce),
+ fmt.Sprintf("你突发恶疾!你的牛牛凹进去了%.2fcm!", reduce),
+ fmt.Sprintf("笑死,你因为打🦶过度导致牛牛凹进去了%.2fcm!🤣🤣🤣", reduce),
+ }), niuniu
+ } else {
+ return randomChoice([]string{
+ fmt.Sprintf("阿哦,你过度打🦶,牛牛缩短%.2fcm了呢!", reduce),
+ fmt.Sprintf("你的牛牛变长了很多,你很激动地继续打🦶,然后牛牛缩短了%.2fcm呢!", reduce),
+ fmt.Sprintf("小打怡情,大打伤身,强打灰飞烟灭!你过度打🦶,牛牛缩短了%.2fcm捏!", reduce),
+ }), niuniu
+ }
+ }
+}
+
+func generateRandomString(niuniu float64) string {
+ switch {
+ case niuniu <= -100:
+ return "wtf?你已经进化成魅魔了!魅魔在击剑时有20%的几率消耗自身长度吞噬对方牛牛呢。"
+ case niuniu <= -50:
+ return "嗯....好像已经穿过了身体吧..从另一面来看也可以算是凸出来的吧?"
+ case niuniu <= -25:
+ return randomChoice([]string{
+ "这名女生,你的身体很健康哦!",
+ "WOW,真的凹进去了好多呢!",
+ "你已经是我们女孩子的一员啦!",
+ })
+ case niuniu <= -10:
+ return randomChoice([]string{
+ "你已经是一名女生了呢,",
+ "从女生的角度来说,你发育良好(,",
+ "你醒啦?你已经是一名女孩子啦!",
+ "唔...可以放进去一根手指了都...",
+ })
+ case niuniu <= 0:
+ return randomChoice([]string{
+ "安了安了,不要伤心嘛,做女生有什么不好的啊。",
+ "不哭不哭,摸摸头,虽然很难再长出来,但是请不要伤心啦啊!",
+ "加油加油!我看好你哦!",
+ "你醒啦?你现在已经是一名女孩子啦!",
+ })
+ case niuniu <= 10:
+ return randomChoice([]string{
+ "你行不行啊?细狗!",
+ "虽然短,但是小小的也很可爱呢。",
+ "像一只蚕宝宝。",
+ "长大了。",
+ })
+ case niuniu <= 25:
+ return randomChoice([]string{
+ "唔...没话说",
+ "已经很长了呢!",
+ })
+ case niuniu <= 50:
+ return randomChoice([]string{
+ "话说这种真的有可能吗?",
+ "厚礼谢!",
+ })
+ case niuniu <= 100:
+ return randomChoice([]string{
+ "已经突破天际了嘛...",
+ "唔...这玩意应该不会变得比我高吧?",
+ "你这个长度会死人的...!",
+ "你马上要进化成牛头人了!!",
+ "你是什么怪物,不要过来啊!!",
+ })
+ default:
+ return "惊世骇俗!你已经进化成牛头人了!牛头人在击剑时有20%的几率消耗自身长度吞噬对方牛牛呢。"
+ }
+}
+
+// fencing 击剑对决逻辑,返回对决结果和myLength的变化值
+func fencing(myLength, oppoLength float64) (string, float64, float64) {
+ lossLimit := 0.25
+ devourLimit := 0.27
+
+ probability := rand.Intn(100) + 1
+
+ switch {
+ case oppoLength <= -100 && myLength > 0 && 10 < probability && probability <= 20:
+ oppoLength *= 0.85
+ change := -math.Min(math.Abs(lossLimit*myLength), math.Abs(1.5*myLength))
+ myLength += change
+ return fmt.Sprintf("对方身为魅魔诱惑了你,你同化成魅魔!当前长度%.2fcm!", myLength), myLength, oppoLength
+ case oppoLength >= 100 && myLength > 0 && 10 < probability && probability <= 20:
+ oppoLength *= 0.85
+ change := -math.Min(math.Abs(devourLimit*myLength), math.Abs(1.5*myLength))
+ myLength += change
+ return fmt.Sprintf("对方以牛头人的荣誉摧毁了你的牛牛!当前长度%.2fcm!", myLength), myLength, oppoLength
+
+ case myLength <= -100 && oppoLength > 0 && 10 < probability && probability <= 20:
+ myLength *= 0.85
+ change := math.Min(math.Abs(lossLimit*oppoLength), math.Abs(1.5*oppoLength))
+ oppoLength -= change
+ return fmt.Sprintf("你身为魅魔诱惑了对方,吞噬了对方部分长度!当前长度%.2fcm!", myLength), myLength, oppoLength
+
+ case myLength >= 100 && oppoLength > 0 && 10 < probability && probability <= 20:
+ myLength *= 0.85
+ change := math.Min(math.Abs(devourLimit*oppoLength), math.Abs(1.5*oppoLength))
+ oppoLength += change
+ return fmt.Sprintf("你以牛头人的荣誉摧毁了对方的牛牛!当前长度%.2fcm!", myLength), myLength, oppoLength
+
+ default:
+ return determineResultBySkill(myLength, oppoLength)
+ }
+}
+
+// determineResultBySkill 根据击剑技巧决定结果
+func determineResultBySkill(myLength, oppoLength float64) (string, float64, float64) {
+ probability := rand.Intn(100) + 1
+ winProbability := calculateWinProbability(myLength, oppoLength) * 100
+ return applySkill(myLength, oppoLength,
+ 0 < probability && float64(probability) <= winProbability)
+}
+
+// calculateWinProbability 计算胜率
+func calculateWinProbability(heightA, heightB float64) float64 {
+ var pA float64
+ if heightA > heightB {
+ pA = 0.7 + 0.2*(heightA-heightB)/heightA
+ } else {
+ pA = 0.6 - 0.2*(heightB-heightA)/heightB
+ }
+ heightRatio := math.Max(heightA, heightB) / math.Min(heightA, heightB)
+ reductionRate := 0.1 * (heightRatio - 1)
+ reduction := pA * reductionRate
+ adjustedPA := pA - reduction
+ return math.Max(adjustedPA, 0.01)
+}
+
+// applySkill 应用击剑技巧并生成结果
+func applySkill(myLength, oppoLength float64, increaseLength1 bool) (string, float64, float64) {
+ reduce := fence(oppoLength)
+ if increaseLength1 {
+ myLength += reduce
+ oppoLength -= 0.8 * reduce
+ if myLength < 0 {
+ return fmt.Sprintf("哦吼!?你的牛牛在长大欸!长大了%.2fcm!", reduce), myLength, oppoLength
+ }
+ return fmt.Sprintf("你以绝对的长度让对方屈服了呢!你的长度增加%.2fcm,当前长度%.2fcm!", reduce, myLength), myLength, oppoLength
+
+ }
+ myLength -= reduce
+ oppoLength += 0.8 * reduce
+ if myLength < 0 {
+ return fmt.Sprintf("哦吼!?看来你的牛牛因为击剑而凹进去了呢🤣🤣🤣!凹进去了%.2fcm!", reduce), myLength, oppoLength
+ }
+ return fmt.Sprintf("对方以绝对的长度让你屈服了呢!你的长度减少%.2fcm,当前长度%.2fcm!", reduce, myLength), myLength, oppoLength
+
+}
+
+// fence
+func fence(rd float64) float64 {
+ rd -= float64(time.Now().UnixNano() % 10)
+ if rd > 1000000 {
+ return rd - rand.Float64()*rd
+ }
+ return float64(int(rd * rand.Float64()))
+}
+
+func hitGlue(l float64) float64 {
+ return rand.Float64() * math.Log2(l) / 2
+}
+