查看: 42|回复: 1

[Lua] 土城跑酷活动:检查点计时 + 排行奖励 + 防传送作弊

[复制链接]

46

主题

42

回帖

1212

积分

金牌会员

积分
1212
发表于 2026-6-6 10:23:37 | 显示全部楼层 |阅读模式
分享一个土城跑酷活动模板,适合做晚间活动、节日活动、开区娱乐玩法。

功能点:
1. 玩家从起点 NPC 开始计时。
2. 按顺序踩检查点,不能跳点。
3. 超时失败,完成后按耗时发奖励。
4. 检查点之间距离异常时判定为疑似传送作弊。

实际使用时,把 Parkour.onStart 绑到起点 NPC,把 Parkour.onCheckpoint 绑到每个坐标触发器。

-- TuchengParkour.lua
-- 土城跑酷:检查点、计时、超时、防跳点

local VvApi = {}

function VvApi.getPlayerName(player)
    return player.name
end

function VvApi.getMapId(player)
    return player.mapId or "3"
end

function VvApi.getPos(player)
    return player.x or 0, player.y or 0
end

function VvApi.now()
    return os.time()
end

function VvApi.getVar(key, default)
    _G.__vv_vars = _G.__vv_vars or {}
    local v = _G.__vv_vars[key]
    if v == nil then return default end
    return v
end

function VvApi.setVar(key, value)
    _G.__vv_vars = _G.__vv_vars or {}
    _G.__vv_vars[key] = value
end

function VvApi.addItem(player, itemName, count)
    print("add item", VvApi.getPlayerName(player), itemName, count)
end

function VvApi.sendMsg(player, msg)
    print(msg)
end

function VvApi.teleport(player, mapId, x, y)
    -- TODO: 替换为传送接口,可用于失败后拉回起点
    print("teleport", VvApi.getPlayerName(player), mapId, x, y)
end

local Parkour = {}

Parkour.config = {
    mapId = "3",          -- 土城地图 ID
    timeLimit = 180,      -- 180 秒内完成
    maxStepDistance = 80, -- 两个检查点之间超过该距离,认为疑似异常
    startPos = { x = 330, y = 330 },
    checkpoints = {
        { x = 320, y = 300 },
        { x = 350, y = 285 },
        { x = 380, y = 310 },
        { x = 365, y = 350 },
        { x = 335, y = 360 },
    },
    rewards = {
        { maxTime = 60, item = "跑酷冠军礼包", count = 1 },
        { maxTime = 120, item = "跑酷优秀礼包", count = 1 },
        { maxTime = 180, item = "跑酷参与礼包", count = 1 },
    },
}

local function key(name, field)
    return "parkour:" .. field .. ":" .. name
end

local function distance(a, b)
    local dx = a.x - b.x
    local dy = a.y - b.y
    return math.sqrt(dx * dx + dy * dy)
end

function Parkour.onStart(player)
    if VvApi.getMapId(player) ~= Parkour.config.mapId then
        VvApi.sendMsg(player, "请先到土城参加跑酷活动。")
        return false
    end

    local name = VvApi.getPlayerName(player)
    VvApi.setVar(key(name, "active"), 1)
    VvApi.setVar(key(name, "start"), VvApi.now())
    VvApi.setVar(key(name, "next"), 1)

    local x, y = VvApi.getPos(player)
    VvApi.setVar(key(name, "lastx"), x)
    VvApi.setVar(key(name, "lasty"), y)

    VvApi.sendMsg(player, "土城跑酷开始,请按顺序踩完所有检查点。")
    return true
end

function Parkour.onCheckpoint(player, checkpointIndex)
    local name = VvApi.getPlayerName(player)
    if VvApi.getVar(key(name, "active"), 0) ~= 1 then
        return false
    end

    local startTime = VvApi.getVar(key(name, "start"), 0)
    local usedTime = VvApi.now() - startTime
    if usedTime > Parkour.config.timeLimit then
        VvApi.setVar(key(name, "active"), 0)
        VvApi.teleport(player, Parkour.config.mapId, Parkour.config.startPos.x, Parkour.config.startPos.y)
        VvApi.sendMsg(player, "跑酷超时,挑战失败。")
        return false
    end

    local nextIndex = VvApi.getVar(key(name, "next"), 1)
    if checkpointIndex ~= nextIndex then
        VvApi.sendMsg(player, "检查点顺序错误,请回到正确路线。")
        return false
    end

    local lastPos = {
        x = VvApi.getVar(key(name, "lastx"), 0),
        y = VvApi.getVar(key(name, "lasty"), 0),
    }
    local x, y = VvApi.getPos(player)
    local nowPos = { x = x, y = y }

    if distance(lastPos, nowPos) > Parkour.config.maxStepDistance then
        VvApi.setVar(key(name, "active"), 0)
        VvApi.sendMsg(player, "移动距离异常,本次跑酷已取消。")
        return false
    end

    VvApi.setVar(key(name, "lastx"), x)
    VvApi.setVar(key(name, "lasty"), y)
    VvApi.setVar(key(name, "next"), nextIndex + 1)

    if nextIndex < #Parkour.config.checkpoints then
        VvApi.sendMsg(player, "通过检查点 " .. nextIndex .. "/" .. #Parkour.config.checkpoints)
        return true
    end

    VvApi.setVar(key(name, "active"), 0)

    for _, reward in ipairs(Parkour.config.rewards) do
        if usedTime <= reward.maxTime then
            VvApi.addItem(player, reward.item, reward.count)
            break
        end
    end

    VvApi.sendMsg(player, "跑酷完成,用时 " .. usedTime .. " 秒。")
    return true
end

return Parkour

1

主题

228

回帖

1585

积分

金牌会员

积分
1585
发表于 2026-6-6 22:01:10 | 显示全部楼层
独家版本后期最怕的不是功能少,而是脚本结构乱。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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