Files
bl/logic/service/fight/Capture.go

341 lines
9.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package fight
import (
"fmt"
"math"
"math/rand"
"time"
)
// 异常状态类型
const (
StatusNormal = iota
StatusParalysis
StatusPoison
StatusSleep
StatusFreeze
)
// 异常状态倍率
var statusBonuses = map[int]float64{
StatusNormal: 1.0,
StatusParalysis: 1.5,
StatusPoison: 1.5,
StatusSleep: 2.0,
StatusFreeze: 2.0,
}
// 胶囊配置ItemID -> Bonus
var capsuleBonuses = map[int]float64{
300001: 1.0, // 普通精灵胶囊
300002: 1.5, // 中级精灵胶囊
300003: 2.0, // 高级精灵胶囊
300004: 3.0, // 超级精灵胶囊
300005: 4.0, // 特级精灵胶囊
300006: 256.0, // 无敌精灵胶囊
300007: 256.0, // 超能胶囊
300008: 2.0, // 赫星精灵胶囊
300009: 256.0, // 时空精灵胶囊
300010: 256.0, // 无敌精灵胶囊Ω
}
// PlayerCaptureContext 用户捕捉上下文(每次登录创建)
type PlayerCaptureContext struct {
random *rand.Rand
denominator int // 统一分母=1000
decayFactor float64 // 衰减系数
minDecayNum int // 衰减分子最小值
guarantees map[int]int // 每种精灵的保底分子 map[petId]numerator
}
// CaptureParams 捕捉参数
type CaptureParams struct {
PetID int // 精灵ID
MaxHP int // 目标最大HP
CurrentHP int // 目标当前HP
CatchRate int // 目标捕获率
ItemID int // 使用的道具ID
StatusType int // 状态类型
OwnedCount int // 已拥有数量(-1=保底0=锁定≥1=衰减)
}
// NewPlayerCaptureContext 创建用户捕捉上下文(每次登录调用)
func NewPlayerCaptureContext(decayFactor float64, minDecayNum int) *PlayerCaptureContext {
if minDecayNum <= 0 {
minDecayNum = 1
}
if decayFactor <= 0 || decayFactor >= 1 {
decayFactor = 0.3
}
return &PlayerCaptureContext{
random: rand.New(rand.NewSource(time.Now().UnixNano())),
denominator: 1000, // 统一分母=1000
decayFactor: decayFactor,
minDecayNum: minDecayNum,
guarantees: make(map[int]int), // 初始化map
}
}
// getItemBonus 获取道具倍率
func getItemBonus(itemID int) float64 {
if bonus, ok := capsuleBonuses[itemID]; ok {
return bonus
}
return 1.0 // 默认普通胶囊倍率
}
// GetStatusBonus 获取状态倍率
func GetStatusBonus(statusType int) float64 {
if bonus, ok := statusBonuses[statusType]; ok {
return bonus
}
return statusBonuses[StatusNormal]
}
// calcBaseA 按公式计算a值
func (c *PlayerCaptureContext) calcBaseA(params CaptureParams) int {
catchRate := params.CatchRate
if catchRate < 3 {
catchRate = 3
}
if params.MaxHP <= 0 {
params.MaxHP = 1
}
currentHP := params.CurrentHP
if currentHP <= 0 {
currentHP = 1
}
hpRatio := (3.0*float64(params.MaxHP) - 2.0*float64(currentHP)) / (3.0 * float64(params.MaxHP))
if hpRatio < 0 {
hpRatio = 0
}
itemBonus := getItemBonus(params.ItemID)
statusBonus := GetStatusBonus(params.StatusType)
return int(hpRatio * float64(catchRate) * itemBonus * statusBonus)
}
// calcBaseRate 按公式计算基础成功率
func (c *PlayerCaptureContext) calcBaseRate(params CaptureParams) float64 {
// Bonus >= 255 必定成功
if getItemBonus(params.ItemID) >= 255 {
return 1.0
}
a := c.calcBaseA(params)
if a >= 255 {
return 1.0
}
g := int(1048560.0 / math.Floor(math.Sqrt(math.Floor(math.Sqrt(math.Floor(16711680.0/float64(a)))))))
return math.Pow(float64(g)/65536.0, 4.0)
}
// getGuaranteeNumerator 获取指定精灵的保底分子默认1
func (c *PlayerCaptureContext) getGuaranteeNumerator(petID int) int {
if num, ok := c.guarantees[petID]; ok {
return num
}
return 1
}
// setGuaranteeNumerator 设置指定精灵的保底分子
func (c *PlayerCaptureContext) setGuaranteeNumerator(petID, numerator int) {
c.guarantees[petID] = numerator
}
// applyModeModifier 应用模式修正(保底/衰减/锁定)
func (c *PlayerCaptureContext) applyModeModifier(baseRate float64, params CaptureParams) (float64, string, float64) {
guaranteeBonus := 0.0
switch {
case params.OwnedCount == 0:
// 锁定模式成功率0
return 0.0, "锁定模式(ownedCount=0)", 0.0
case params.OwnedCount > 0:
// 衰减模式:已拥有数量越多,成功率越低
decay := math.Pow(1-c.decayFactor, float64(params.OwnedCount))
modified := baseRate * decay
if modified < 0 {
modified = 0
}
return modified, "衰减模式", 0.0
default: // params.OwnedCount == -1
// 保底模式失败叠加分子按精灵ID独立计算
num := c.getGuaranteeNumerator(params.PetID)
guaranteeBonus = float64(num) / float64(c.denominator) // 分母=1000
modified := baseRate + guaranteeBonus
if modified > 1.0 {
modified = 1.0
}
return modified, "保底模式", guaranteeBonus * 100 // 百分比形式
}
}
// Capture 执行捕捉
func (c *PlayerCaptureContext) Capture(params CaptureParams) (bool, CaptureDetails) {
// 记录当前保底值(用于显示)
currentGuarantee := c.getGuaranteeNumerator(params.PetID)
// 特殊胶囊必定成功Bonus>=255
if getItemBonus(params.ItemID) >= 255 {
// 若是保底模式,成功后重置该精灵的保底分子
if params.OwnedCount == -1 {
c.setGuaranteeNumerator(params.PetID, 1)
}
return true, CaptureDetails{
Success: true,
Mode: "特殊胶囊必定成功",
BaseRate: 100.0,
ModifiedRate: 100.0,
GuaranteeBonus: float64(currentGuarantee) / float64(c.denominator) * 100,
Details: fmt.Sprintf("道具ID=%d必定成功", params.ItemID),
}
}
// 锁定模式直接失败
if params.OwnedCount == 0 {
return false, CaptureDetails{
Success: false,
Mode: "锁定模式(ownedCount=0)",
BaseRate: 0.0,
ModifiedRate: 0.0,
GuaranteeBonus: 0.0,
Details: "已拥有数量为0无法捕捉",
}
}
baseRate := c.calcBaseRate(params)
modifiedRate, mode, guaranteeBonus := c.applyModeModifier(baseRate, params)
// 随机判定
success := c.random.Float64() < modifiedRate
// 更新保底状态(仅对保底模式)
if params.OwnedCount == -1 {
if success {
// 成功重置该精灵的保底分子为1
c.setGuaranteeNumerator(params.PetID, 1)
} else {
// 失败:该精灵的保底分子+1
c.setGuaranteeNumerator(params.PetID, currentGuarantee+1)
}
}
return success, CaptureDetails{
Success: success,
Mode: mode,
BaseRate: baseRate * 100,
ModifiedRate: modifiedRate * 100,
GuaranteeBonus: guaranteeBonus,
Details: fmt.Sprintf("a=%d, g=%.0f, 分母=1000, 当前保底分子=%d",
c.calcBaseA(params),
math.Floor(math.Sqrt(math.Floor(math.Sqrt(math.Floor(16711680.0/float64(c.calcBaseA(params))))))),
currentGuarantee),
}
}
// CaptureDetails 捕捉详情
type CaptureDetails struct {
Success bool
Mode string
BaseRate float64
ModifiedRate float64
GuaranteeBonus float64 // 百分比
Details string
}
func main() {
// 每次登录创建用户捕捉上下文
ctx := NewPlayerCaptureContext(0.1, 1)
fmt.Println("=== 测试三种模式 ===")
// 测试1保底模式ownedCount=-1- 不同精灵独立计算
fmt.Println("\n--- 保底模式测试(不同精灵独立计算) ---")
paramsA := CaptureParams{
PetID: 1001, // 精灵A
MaxHP: 20,
CurrentHP: 1,
CatchRate: 45,
ItemID: 300003, // 高级精灵胶囊
StatusType: StatusNormal,
OwnedCount: -1, // 保底模式
}
paramsB := CaptureParams{
PetID: 1002, // 精灵B
MaxHP: 50,
CurrentHP: 5,
CatchRate: 60,
ItemID: 300002, // 中级精灵胶囊
StatusType: StatusNormal,
OwnedCount: -1, // 保底模式
}
// 交替捕捉精灵A和精灵B验证保底分子独立
for i := 1; i <= 10; i++ {
successA, detailsA := ctx.Capture(paramsA)
fmt.Printf("第%d轮-精灵A%v | 模式=%s | 基础=%.2f%% | 实际=%.2f%% | 保底加成=%.2f%%\n",
i, successA, detailsA.Mode, detailsA.BaseRate, detailsA.ModifiedRate, detailsA.GuaranteeBonus)
successB, detailsB := ctx.Capture(paramsB)
fmt.Printf("第%d轮-精灵B%v | 模式=%s | 基础=%.2f%% | 实际=%.2f%% | 保底加成=%.2f%%\n",
i, successB, detailsB.Mode, detailsB.BaseRate, detailsB.ModifiedRate, detailsB.GuaranteeBonus)
}
// 测试2衰减模式ownedCount递增
fmt.Println("\n--- 衰减模式测试ownedCount递增 ---")
paramsDecay := CaptureParams{
PetID: 2001,
MaxHP: 100,
CurrentHP: 10,
CatchRate: 3,
ItemID: 300003, // 高级精灵胶囊
StatusType: StatusSleep,
OwnedCount: 1, // 衰减模式起始
}
for i := 1; i <= 50; i++ {
paramsDecay.OwnedCount = 2
success, details := ctx.Capture(paramsDecay)
fmt.Printf("拥有%d只%v | 模式=%s | 基础=%.2f%% | 实际=%.2f%%\n",
paramsDecay.OwnedCount, success, details.Mode, details.BaseRate, details.ModifiedRate)
}
// 测试3锁定模式ownedCount=0
fmt.Println("\n--- 锁定模式测试 ---")
paramsLock := CaptureParams{
PetID: 3001,
MaxHP: 100,
CurrentHP: 1,
CatchRate: 255,
ItemID: 300004, // 超级精灵胶囊
StatusType: StatusFreeze,
OwnedCount: 0, // 锁定模式
}
successLock, detailsLock := ctx.Capture(paramsLock)
fmt.Printf("捕捉结果:%v | 模式=%s | 基础=%.2f%% | 实际=%.2f%%\n",
successLock, detailsLock.Mode, detailsLock.BaseRate, detailsLock.ModifiedRate)
// 测试4特殊胶囊必定成功
fmt.Println("\n--- 特殊胶囊测试 ---")
paramsSpecial := CaptureParams{
PetID: 4001,
MaxHP: 1000,
CurrentHP: 1000,
CatchRate: 1,
ItemID: 300006, // 无敌精灵胶囊
StatusType: StatusNormal,
OwnedCount: -1, // 保底模式
}
successSpecial, detailsSpecial := ctx.Capture(paramsSpecial)
fmt.Printf("捕捉结果:%v | 模式=%s | 基础=%.2f%% | 实际=%.2f%% | 保底加成=%.2f%%\n",
successSpecial, detailsSpecial.Mode, detailsSpecial.BaseRate, detailsSpecial.ModifiedRate, detailsSpecial.GuaranteeBonus)
}