tibaiwan1888 发表于 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
    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 = 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

qq154886255 发表于 2026-6-6 22:01:10

独家版本后期最怕的不是功能少,而是脚本结构乱。
页: [1]
查看完整版本: 土城跑酷活动:检查点计时 + 排行奖励 + 防传送作弊