查看: 71|回复: 6

[Lua] 动态爆率系统:怪物等级 × 玩家幸运值 × 保底机制

[复制链接]

46

主题

42

回帖

1212

积分

金牌会员

积分
1212
发表于 2026-6-5 00:05:49 | 显示全部楼层 |阅读模式
本帖最后由 tibaiwan1888 于 2026-6-5 00:07 编辑

-- DropSystem.lua
-- 动态爆率 = 基础率 × 等级系数 × 幸运加成,带保底计数器

local M = {}

-- 品质基础爆率(%)
local BASE_RATE = { [1]=60, [2]=25, [3]=10, [4]=4, [5]=1 }

-- 保底:连续未爆N次后强制提升一档
local PITY = { [3]=30, [4]=80, [5]=200 }  -- 稀有30次保底,史诗80次,传说200次

-- 玩家保底计数器(存内存,重要数据应持久化)
local _pityCounter = {}  -- { playerName = { [3]=n, [4]=n, [5]=n } }

local function getCounter(name)
    if not _pityCounter[name] then
        _pityCounter[name] = { [3]=0, [4]=0, [5]=0 }
    end
    return _pityCounter[name]
end

-- 根据怪物等级和玩家幸运值计算实际爆率
local function calcRate(baseRate, monsterLv, playerLuck)
    local lvBonus   = math.min(monsterLv / 100, 0.5)   -- 怪物等级最多加50%
    local luckBonus = math.min(playerLuck / 1000, 0.3)  -- 幸运值最多加30%
    return baseRate * (1 + lvBonus + luckBonus)
end

-- 单次掉落计算,返回品质列表(可能掉多件)
function M.roll(playerName, monsterLv, playerLuck)
    local counter = getCounter(playerName)
    local drops   = {}

    -- 从高品质向低品质判定,高品质先判,避免重叠
    for q = 5, 1, -1 do
        local rate = calcRate(BASE_RATE[q], monsterLv, playerLuck)

        -- 保底触发
        local pityLimit = PITY[q]
        local forced = false
        if pityLimit and counter[q] and counter[q] >= pityLimit then
            forced = true
        end

        if forced or math.random() * 100 <= rate then
            table.insert(drops, { quality = q, forced = forced })
            if counter[q] then counter[q] = 0 end
            break  -- 每次只掉最高品质的一件
        else
            if counter[q] then counter[q] = counter[q] + 1 end
        end
    end

    if #drops == 0 then
        table.insert(drops, { quality = 1, forced = false })
    end

    return drops
end

-- 查询保底进度(可用于UI显示)
function M.getPityProgress(playerName)
    local c = getCounter(playerName)
    return {
        rare   = string.format("%d/%d", c[3], PITY[3]),
        epic   = string.format("%d/%d", c[4], PITY[4]),
        legend = string.format("%d/%d", c[5], PITY[5]),
    }
end

整合鉴定系统的完整拾取流程:
local Drop     = require("DropSystem")
local Identify = require("IdentifySystem")

local QUALITY_NAME = {"普通","精良","稀有","史诗","传说"}

-- 玩家击杀怪物时调用
function OnMonsterDie(playerName, monsterLv)
    local luck  = GetPlayerAttr(playerName, "luck") or 0
    local drops = Drop.roll(playerName, monsterLv, luck)

    for _, drop in ipairs(drops) do
        local q       = drop.quality
        local affixes = Identify.identify(q)

        -- 拼装装备信息
        local lines = { "【" .. QUALITY_NAME[q] .. "】装备" }
        if drop.forced then
            table.insert(lines, "  ★ 保底触发")
        end
        for _, a in ipairs(affixes) do
            table.insert(lines, "  · " .. a.desc)
        end

        -- 发给玩家
        GiveEquip(playerName, q, affixes)
        SendPlayerMsg(playerName, table.concat(lines, "\n"))
    end

    -- 显示保底进度
    local prog = Drop.getPityProgress(playerName)
    SendPlayerMsg(playerName, string.format(
        "[保底进度] 稀有:%s 史诗:%s 传说:%s",
        prog.rare, prog.epic, prog.legend
    ))
end

return M



1

主题

228

回帖

1585

积分

金牌会员

积分
1585
发表于 2026-6-5 10:12:51 | 显示全部楼层
快了快了,马上就能用VV了

25

主题

89

回帖

1323

积分

金牌会员

积分
1323
发表于 2026-6-5 10:25:55 | 显示全部楼层
快了快了,马上就能用VV了

46

主题

42

回帖

1212

积分

金牌会员

积分
1212
楼主 发表于 2026-6-5 13:54:41 | 显示全部楼层
整合鉴定系统的完整拾取流程:

1

主题

228

回帖

1585

积分

金牌会员

积分
1585
发表于 2026-6-5 23:10:57 | 显示全部楼层
很厉害啊!学到了

25

主题

89

回帖

1323

积分

金牌会员

积分
1323
发表于 2026-6-6 00:33:23 | 显示全部楼层
快了快了,马上就能用VV了

25

主题

89

回帖

1323

积分

金牌会员

积分
1323
发表于 2026-6-6 00:38:17 | 显示全部楼层
快了快了,马上就能用VV了
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表