-- 新玩家欢迎系统
local function OnPlayerLogin(event, player)
-- 检查是否为新玩家
local level = player:GetLevel()
local playedTime = player:GetTotalPlayedTime()
if level == 1 and playedTime < 300 then -- 5分钟内的1级玩家
-- 发送欢迎消息
local playerName = player:GetName()
player:SendBroadcastMessage("欢迎来到我们的服务器," .. playerName .. "!")
player:SendBroadcastMessage("你已获得新手礼包,祝你游戏愉快!")
-- 给予新手礼包
player:AddItem(6948, 1) -- 炉石
player:AddItem(4540, 10) -- 恢复药水
player:AddItem(117, 10) -- 食物
player:ModifyMoney(100000) -- 10金币
-- 传送到新手村(暴风城)
player:Teleport(0, -8949.95, -132.493, 83.5312, 0)
-- 3秒后发送额外提示
CreateLuaEvent(function()
if player:IsInWorld() then
player:SendBroadcastMessage("记得查看你的背包,里面有新手礼包哦!")
end
end, 3000, 1)
end
end
-- 注册玩家登录事件
RegisterPlayerEvent(3, OnPlayerLogin) -- PLAYER_EVENT_ON_LOGIN = 3
使用说明
1. 将此脚本保存为 welcome_system.lua 文件
2. 放置在服务器的 lua_scripts 目录下
3. 重启服务器或重新加载LUA脚本
4. 新创建的1级角色登录时会自动触发欢迎系统
等级奖励系统
玩家升级时自动给予相应的奖励,包括金币、物品和技能点数。
功能特点
监听玩家升级事件
根据等级给予不同奖励
特殊等级(10、20、30等)给予额外奖励
发送升级祝贺消息
完整脚本代码
-- 等级奖励系统
local function OnPlayerLevelUp(event, player, oldLevel)
local newLevel = player:GetLevel()
local playerName = player:GetName()
-- 基础升级奖励
local goldReward = newLevel * 1000 -- 每级1金币
player:ModifyMoney(goldReward)
-- 发送升级祝贺
player:SendBroadcastMessage("恭喜升级到 " .. newLevel .. " 级!")
player:SendBroadcastMessage("获得奖励:" .. (goldReward/10000) .. " 金币")
-- 特殊等级奖励
if newLevel % 10 == 0 then -- 每10级
player:AddItem(6948, 1) -- 额外炉石
player:SendBroadcastMessage("达到 " .. newLevel .. " 级里程碑!获得特殊奖励!")
-- 全服公告重要等级
if newLevel >= 60 then
SendWorldMessage(playerName .. " 达到了 " .. newLevel .. " 级!让我们祝贺他!")
end
end
-- 满级奖励
if newLevel == 80 then
player:AddItem(12345, 1) -- 满级纪念品
player:ModifyMoney(1000000) -- 100金币
SendWorldMessage(playerName .. " 达到了满级80级!真是太厉害了!")
end
end
-- 注册玩家升级事件
RegisterPlayerEvent(13, OnPlayerLevelUp) -- PLAYER_EVENT_ON_LEVEL_CHANGE = 13
使用说明
1. 将脚本保存为 level_reward.lua
2. 可以根据服务器需要调整奖励数量和物品ID
3. 特殊等级的判断条件可以自定义修改
4. 满级等级可以根据服务器版本调整(60、70、80等)
NPC和生物脚本
智能NPC对话系统
创建一个智能NPC,能够根据玩家等级、职业和任务状态提供不同的对话和服务。
功能特点
根据玩家等级提供不同的对话内容
检测玩家职业并给出专业建议
提供任务状态查询功能
动态生成对话选项
完整脚本代码
-- 智能NPC对话系统
local NPC_ENTRY = 190000 -- 自定义NPC ID
-- 职业名称映射
local CLASS_NAMES = {
[1] = "战士", [2] = "圣骑士", [3] = "猎人", [4] = "盗贼",
[5] = "牧师", [6] = "死亡骑士", [7] = "萨满", [8] = "法师",
[9] = "术士", [11] = "德鲁伊"
}
-- NPC对话处理
local function OnGossipHello(event, player, creature)
local level = player:GetLevel()
local class = player:GetClass()
local className = CLASS_NAMES[class] or "未知职业"
-- 清除之前的对话选项
player:GossipClearMenu()
-- 根据等级提供不同的欢迎语
local greeting = ""
if level < 10 then
greeting = "你好,年轻的" .. className .. "!我看得出你刚开始你的冒险之旅。"
elseif level < 30 then
greeting = "欢迎," .. className .. "!你已经积累了一些经验,继续努力吧!"
elseif level < 60 then
greeting = "致敬,经验丰富的" .. className .. "!你的实力令人印象深刻。"
else
greeting = "向你致敬,传奇的" .. className .. "!你的名声已经传遍了整个大陆。"
end
-- 添加基本对话选项
player:GossipMenuAddItem(0, "查看我的角色信息", 0, 1)
player:GossipMenuAddItem(0, "获取职业专属建议", 0, 2)
player:GossipMenuAddItem(0, "检查任务状态", 0, 3)
-- 高级玩家专属选项
if level >= 60 then
player:GossipMenuAddItem(0, "传奇玩家专属奖励", 0, 4)
end
player:GossipMenuAddItem(0, "再见", 0, 99)
-- 发送对话菜单
player:GossipSendMenu(1, creature, greeting)
end
-- 处理对话选择
local function OnGossipSelect(event, player, creature, sender, intid, code)
local level = player:GetLevel()
local class = player:GetClass()
local className = CLASS_NAMES[class] or "未知职业"
if intid == 1 then -- 角色信息
local info = string.format(
"角色信息:\\n" ..
"名称: %s\\n" ..
"等级: %d\\n" ..
"职业: %s\\n" ..
"金币: %d金 %d银 %d铜",
player:GetName(),
level,
className,
player:GetCoinage() / 10000,
(player:GetCoinage() % 10000) / 100,
player:GetCoinage() % 100
)
player:SendBroadcastMessage(info)
elseif intid == 2 then -- 职业建议
local advice = ""
if class == 1 then -- 战士
advice = "作为战士,记住你是团队的盾牌。提升你的防御技能和仇恨控制能力。"
elseif class == 8 then -- 法师
advice = "法师应该专注于法术强度和法力管理。学会合理使用控制技能。"
elseif class == 5 then -- 牧师
advice = "牧师是团队的生命线。平衡治疗和伤害输出,保护好你的队友。"
else
advice = "继续磨练你的技能,每个职业都有其独特的优势和作用。"
end
player:SendBroadcastMessage(advice)
elseif intid == 3 then -- 任务状态
-- 这里可以添加任务检查逻辑
player:SendBroadcastMessage("任务系统检查完毕,继续你的冒险吧!")
elseif intid == 4 and level >= 60 then -- 传奇奖励
player:AddItem(6948, 1) -- 给予特殊物品
player:SendBroadcastMessage("恭喜!你获得了传奇玩家专属奖励!")
elseif intid == 99 then -- 再见
player:GossipComplete()
return
end
-- 返回主菜单
OnGossipHello(event, player, creature)
end
-- 注册事件
RegisterCreatureGossipEvent(NPC_ENTRY, 1, OnGossipHello)
RegisterCreatureGossipEvent(NPC_ENTRY, 2, OnGossipSelect)
使用说明
1. 修改 NPC_ENTRY 为你的自定义NPC ID
2. 在数据库中创建对应的NPC
3. 可以根据需要添加更多的对话选项和功能
4. 建议结合数据库查询来实现更复杂的功能
服务器管理脚本
自动公告系统
创建一个自动公告系统,定时发送服务器公告,支持多条消息轮播和特殊事件提醒。
功能特点
支持多条公告消息轮播
可配置公告间隔时间
支持特殊事件公告
自动检测在线玩家数量
完整脚本代码
-- 自动公告系统
local ANNOUNCEMENT_INTERVAL = 300000 -- 5分钟 = 300000毫秒
-- 公告消息列表
local ANNOUNCEMENTS = {
"欢迎来到我们的服务器!请遵守服务器规则。",
"记得定期保存你的角色数据,避免意外损失。",
"加入我们的QQ群获取最新资讯和活动信息!",
"服务器每天凌晨4点进行维护,请提前下线。",
"发现BUG请及时反馈给管理员,感谢您的支持!"
}
-- 当前公告索引
local currentAnnouncementIndex = 1
-- 发送公告函数
local function SendAnnouncement()
local playerCount = GetPlayerCount()
if playerCount > 0 then
local message = ANNOUNCEMENTS[currentAnnouncementIndex]
local fullMessage = string.format(
"[服务器公告] %s (当前在线: %d人)",
message,
playerCount
)
SendWorldMessage(fullMessage)
-- 移动到下一条公告
currentAnnouncementIndex = currentAnnouncementIndex + 1
if currentAnnouncementIndex > #ANNOUNCEMENTS then
currentAnnouncementIndex = 1
end
end
end
-- 启动公告系统
local function StartAnnouncementSystem()
-- 立即发送第一条公告
SendAnnouncement()
-- 创建定时器
CreateLuaEvent(SendAnnouncement, ANNOUNCEMENT_INTERVAL, 0)
print("自动公告系统已启动,间隔时间: " .. (ANNOUNCEMENT_INTERVAL/1000) .. "秒")
end
-- 服务器启动时初始化公告系统
local function OnServerStartup()
-- 延迟30秒后启动公告系统,确保服务器完全启动
CreateLuaEvent(StartAnnouncementSystem, 30000, 1)
end
-- 注册服务器启动事件
RegisterServerEvent(33, OnServerStartup) -- SERVER_EVENT_ON_STARTUP = 33
使用说明
1. 修改 ANNOUNCEMENTS 数组添加你的公告内容
2. 调整 ANNOUNCEMENT_INTERVAL 设置公告间隔
3. 可以添加更多的公告类型和条件判断
4. 建议在服务器启动脚本中加载此模块
物品和装备脚本
自定义物品使用效果
创建自定义物品的使用效果,包括传送卷轴、经验药水、属性增强药剂等特殊功能物品。
功能特点
支持多种物品类型的自定义效果
包含冷却时间和使用限制
支持随机效果和概率触发
完整的错误处理和用户提示
完整脚本代码
-- 自定义物品使用效果系统
local CUSTOM_ITEMS = {
[190001] = "teleport_scroll", -- 传送卷轴
[190002] = "exp_potion", -- 经验药水
[190003] = "stat_elixir", -- 属性药剂
[190004] = "lucky_box" -- 幸运宝箱
}
-- 冷却时间记录 (玩家GUID -> 物品ID -> 过期时间)
local itemCooldowns = {}
-- 检查冷却时间
local function IsItemOnCooldown(player, itemId, cooldownSeconds)
local guid = player:GetGUIDLow()
local currentTime = GetCurrTime()
if not itemCooldowns[guid] then
itemCooldowns[guid] = {}
end
if itemCooldowns[guid][itemId] and itemCooldowns[guid][itemId] > currentTime then
local remaining = itemCooldowns[guid][itemId] - currentTime
return true, remaining
end
-- 设置新的冷却时间
itemCooldowns[guid][itemId] = currentTime + cooldownSeconds
return false, 0
end
-- 传送卷轴效果
local function UseTeleportScroll(player, item)
local onCooldown, remaining = IsItemOnCooldown(player, item:GetEntry(), 300) -- 5分钟冷却
if onCooldown then
player:SendBroadcastMessage("传送卷轴冷却中,还需等待 " .. remaining .. " 秒")
return false
end
-- 传送位置列表
local teleportLocations = {
{name = "暴风城", map = 0, x = -8949.95, y = -132.493, z = 83.5312},
{name = "奥格瑞玛", map = 1, x = 1676.21, y = -4315.29, z = 61.5243},
{name = "铁炉堡", map = 0, x = -4981.25, y = -881.542, z = 501.66},
{name = "达纳苏斯", map = 1, x = 9947.52, y = 2482.73, z = 1316.21}
}
-- 随机选择一个位置
local location = teleportLocations[math.random(1, #teleportLocations)]
if player:Teleport(location.map, location.x, location.y, location.z, 0) then
player:SendBroadcastMessage("传送到 " .. location.name .. " 成功!")
return true
else
player:SendBroadcastMessage("传送失败,请稍后再试")
return false
end
end
-- 经验药水效果
local function UseExpPotion(player, item)
local level = player:GetLevel()
if level >= 80 then
player:SendBroadcastMessage("满级角色无法使用经验药水")
return false
end
local onCooldown, remaining = IsItemOnCooldown(player, item:GetEntry(), 3600) -- 1小时冷却
if onCooldown then
player:SendBroadcastMessage("经验药水冷却中,还需等待 " .. math.floor(remaining/60) .. " 分钟")
return false
end
-- 根据等级给予不同经验
local expGain = level * 1000 + math.random(500, 1500)
player:GiveXP(expGain)
player:SendBroadcastMessage("获得 " .. expGain .. " 点经验值!")
return true
end
-- 属性药剂效果
local function UseStatElixir(player, item)
local onCooldown, remaining = IsItemOnCooldown(player, item:GetEntry(), 1800) -- 30分钟冷却
if onCooldown then
player:SendBroadcastMessage("属性药剂冷却中,还需等待 " .. math.floor(remaining/60) .. " 分钟")
return false
end
-- 随机属性增强效果 (这里需要使用光环或buff系统)
local effects = {
{spell = 1234, name = "力量增强"},
{spell = 1235, name = "敏捷增强"},
{spell = 1236, name = "智力增强"},
{spell = 1237, name = "耐力增强"}
}
local effect = effects[math.random(1, #effects)]
player:AddAura(effect.spell, player) -- 添加增益效果
player:SendBroadcastMessage("获得 " .. effect.name .. " 效果!持续30分钟")
return true
end
-- 幸运宝箱效果
local function UseLuckyBox(player, item)
-- 奖励列表
local rewards = {
{type = "item", id = 6948, count = 1, chance = 30, name = "炉石"},
{type = "item", id = 4540, count = 10, chance = 25, name = "恢复药水x10"},
{type = "money", amount = 100000, chance = 20, name = "10金币"},
{type = "exp", amount = 5000, chance = 15, name = "5000经验"},
{type = "item", id = 12345, count = 1, chance = 10, name = "稀有装备"}
}
-- 随机选择奖励
local roll = math.random(1, 100)
local currentChance = 0
for _, reward in ipairs(rewards) do
currentChance = currentChance + reward.chance
if roll <= currentChance then
if reward.type == "item" then
player:AddItem(reward.id, reward.count)
elseif reward.type == "money" then
player:ModifyMoney(reward.amount)
elseif reward.type == "exp" then
player:GiveXP(reward.amount)
end
player:SendBroadcastMessage("幸运宝箱开出:" .. reward.name .. "!")
return true
end
end
player:SendBroadcastMessage("很遗憾,这次没有获得奖励")
return true
end
-- 物品使用事件处理
local function OnItemUse(event, player, item, target)
local itemId = item:GetEntry()
local itemType = CUSTOM_ITEMS[itemId]
if not itemType then
return -- 不是自定义物品
end
local success = false
if itemType == "teleport_scroll" then
success = UseTeleportScroll(player, item)
elseif itemType == "exp_potion" then
success = UseExpPotion(player, item)
elseif itemType == "stat_elixir" then
success = UseStatElixir(player, item)
elseif itemType == "lucky_box" then
success = UseLuckyBox(player, item)
end
-- 如果使用成功,消耗物品
if success then
player:RemoveItem(itemId, 1)
end
end
-- 注册物品使用事件
RegisterPlayerEvent(15, OnItemUse) -- PLAYER_EVENT_ON_USE_ITEM = 15
使用说明
1. 修改 CUSTOM_ITEMS 表添加你的自定义物品ID
2. 在数据库中创建对应的物品模板
3. 可以根据需要调整冷却时间和效果
4. 奖励物品ID需要确保在数据库中存在
副本和团队脚本
智能副本管理系统
创建一个智能副本管理系统,包括难度调整、奖励分配、进度追踪和团队协作功能。
功能特点
根据团队人数和等级自动调整副本难度
智能奖励分配系统
副本进度追踪和统计
团队协作增益效果
副本重置和冷却管理
完整脚本代码
-- 智能副本管理系统
local DUNGEON_MAPS = {
[33] = {name = "影牙城堡", minLevel = 18, maxLevel = 25, maxPlayers = 5},
[36] = {name = "死亡矿井", minLevel = 15, maxLevel = 23, maxPlayers = 5},
[43] = {name = "哀嚎洞穴", minLevel = 15, maxLevel = 25, maxPlayers = 5},
[47] = {name = "剃刀沼泽", minLevel = 35, maxLevel = 45, maxPlayers = 5}
}
-- 副本数据存储
local dungeonData = {}
-- 获取副本信息
local function GetDungeonInfo(mapId)
return DUNGEON_MAPS[mapId]
end
-- 计算团队平均等级
local function GetGroupAverageLevel(group)
if not group then return 0 end
local totalLevel = 0
local memberCount = 0
local members = group:GetMembers()
for _, member in pairs(members) do
if member:IsInWorld() then
totalLevel = totalLevel + member:GetLevel()
memberCount = memberCount + 1
end
end
return memberCount > 0 and math.floor(totalLevel / memberCount) or 0
end
-- 调整副本难度
local function AdjustDungeonDifficulty(mapId, group)
local dungeonInfo = GetDungeonInfo(mapId)
if not dungeonInfo then return end
local memberCount = group:GetMembersCount()
local avgLevel = GetGroupAverageLevel(group)
-- 计算难度系数
local difficultyMultiplier = 1.0
-- 根据人数调整
if memberCount < dungeonInfo.maxPlayers then
difficultyMultiplier = difficultyMultiplier * (0.8 + memberCount * 0.05)
elseif memberCount > dungeonInfo.maxPlayers then
difficultyMultiplier = difficultyMultiplier * (1.0 + (memberCount - dungeonInfo.maxPlayers) * 0.2)
end
-- 根据等级调整
local levelDiff = avgLevel - dungeonInfo.minLevel
if levelDiff > 5 then
difficultyMultiplier = difficultyMultiplier * (1.0 + levelDiff * 0.1)
end
-- 存储副本数据
if not dungeonData[mapId] then
dungeonData[mapId] = {}
end
dungeonData[mapId].difficulty = difficultyMultiplier
dungeonData[mapId].groupId = group:GetGUID()
dungeonData[mapId].startTime = GetCurrTime()
-- 通知团队
local members = group:GetMembers()
for _, member in pairs(members) do
member:SendBroadcastMessage(string.format(
"副本难度已调整: %.1fx (团队%d人, 平均等级%d)",
difficultyMultiplier, memberCount, avgLevel
))
end
end
-- 玩家进入副本事件
local function OnPlayerEnterDungeon(event, player)
local mapId = player:GetMapId()
local dungeonInfo = GetDungeonInfo(mapId)
if not dungeonInfo then return end
local group = player:GetGroup()
if not group then
player:SendBroadcastMessage("建议组队进入副本以获得更好的体验!")
return
end
-- 检查等级要求
local playerLevel = player:GetLevel()
if playerLevel < dungeonInfo.minLevel then
player:SendBroadcastMessage(string.format(
"等级过低!建议等级: %d-%d",
dungeonInfo.minLevel, dungeonInfo.maxLevel
))
elseif playerLevel > dungeonInfo.maxLevel + 10 then
player:SendBroadcastMessage("等级过高,经验和奖励将会减少")
end
-- 调整副本难度
AdjustDungeonDifficulty(mapId, group)
-- 给予团队增益
if group:GetMembersCount() >= 3 then
local members = group:GetMembers()
for _, member in pairs(members) do
if member:GetMapId() == mapId then
member:AddAura(15366, member) -- 团队精神光环
end
end
end
end
-- BOSS死亡事件
local function OnBossKilled(event, creature, killer)
if not killer or not killer:IsPlayer() then return end
local player = killer:ToPlayer()
local mapId = player:GetMapId()
local dungeonInfo = GetDungeonInfo(mapId)
if not dungeonInfo then return end
local group = player:GetGroup()
if not group then return end
-- 计算奖励
local baseReward = {
exp = creature:GetLevel() * 100,
money = creature:GetLevel() * 1000
}
-- 应用难度系数
local difficulty = dungeonData[mapId] and dungeonData[mapId].difficulty or 1.0
baseReward.exp = math.floor(baseReward.exp * difficulty)
baseReward.money = math.floor(baseReward.money * difficulty)
-- 分配奖励给团队成员
local members = group:GetMembers()
local nearbyMembers = {}
for _, member in pairs(members) do
if member:GetMapId() == mapId and member:GetDistance(creature) < 100 then
table.insert(nearbyMembers, member)
end
end
-- 团队奖励加成
local teamBonus = #nearbyMembers >= 3 and 1.2 or 1.0
for _, member in pairs(nearbyMembers) do
local memberExp = math.floor(baseReward.exp * teamBonus)
local memberMoney = math.floor(baseReward.money * teamBonus)
member:GiveXP(memberExp)
member:ModifyMoney(memberMoney)
member:SendBroadcastMessage(string.format(
"击败BOSS奖励: %d经验, %d铜币 (团队加成: %.0f%%)",
memberExp, memberMoney, (teamBonus - 1) * 100
))
-- 随机掉落特殊物品
if math.random(1, 100) <= 20 then -- 20%概率
local rareItems = {12345, 12346, 12347} -- 稀有物品列表
local randomItem = rareItems[math.random(1, #rareItems)]
member:AddItem(randomItem, 1)
-- 通知全团队
for _, teamMember in pairs(nearbyMembers) do
teamMember:SendBroadcastMessage(
member:GetName() .. " 获得了稀有物品!"
)
end
end
end
end
-- 副本完成统计
local function OnDungeonComplete(mapId, group)
local dungeonInfo = GetDungeonInfo(mapId)
if not dungeonInfo or not dungeonData[mapId] then return end
local completionTime = GetCurrTime() - dungeonData[mapId].startTime
local minutes = math.floor(completionTime / 60)
local seconds = completionTime % 60
local members = group:GetMembers()
for _, member in pairs(members) do
if member:GetMapId() == mapId then
member:SendBroadcastMessage(string.format(
"副本 %s 完成!用时: %d分%d秒",
dungeonInfo.name, minutes, seconds
))
-- 完成奖励
member:AddItem(6948, 1) -- 完成纪念品
member:ModifyMoney(50000) -- 5金币完成奖励
end
end
-- 清理副本数据
dungeonData[mapId] = nil
end
-- 注册事件
RegisterPlayerEvent(28, OnPlayerEnterDungeon) -- PLAYER_EVENT_ON_MAP_CHANGE
RegisterCreatureEvent(0, 4, OnBossKilled) -- 所有生物死亡事件
使用说明
1. 修改 DUNGEON_MAPS 表添加你的副本地图ID和配置
2. 调整奖励物品ID和数量
3. 可以根据服务器需要修改难度计算公式
4. 建议配合副本重置系统使用
PVP和竞技场脚本
PVP竞技场管理系统
创建一个完整的PVP竞技场系统,包括匹配机制、等级分级、奖励系统和排行榜功能。
功能特点
智能匹配系统,根据等级和技能匹配对手
多种竞技场模式(1v1, 2v2, 3v3)
积分和排名系统
季度奖励和成就系统
观战功能和回放系统
完整脚本代码
-- PVP竞技场管理系统
local ARENA_MAPS = {
[559] = {name = "纳格兰竞技场", type = "2v2", minLevel = 70},
[562] = {name = "刀锋山竞技场", type = "3v3", minLevel = 70},
[572] = {name = "废墟之城", type = "5v5", minLevel = 70}
}
-- 玩家竞技场数据
local arenaPlayers = {}
local arenaQueue = {["1v1"] = {}, ["2v2"] = {}, ["3v3"] = {}}
local activeMatches = {}
-- 初始化玩家竞技场数据
local function InitPlayerArenaData(player)
local guid = player:GetGUIDLow()
if not arenaPlayers[guid] then
arenaPlayers[guid] = {
rating = 1500,
wins = 0,
losses = 0,
streak = 0,
lastMatch = 0,
seasonPoints = 0
}
end
return arenaPlayers[guid]
end
-- 计算玩家战斗力
local function CalculatePlayerPower(player)
local level = player:GetLevel()
local health = player:GetMaxHealth()
local mana = player:GetMaxMana()
-- 获取装备评分
local gearScore = 0
for slot = 0, 19 do
local item = player:GetItemByPos(255, slot)
if item then
gearScore = gearScore + (item:GetItemLevel() or 0)
end
end
-- 综合战斗力计算
local power = level * 10 + (health / 100) + (mana / 100) + gearScore
return math.floor(power)
end
-- 寻找匹配对手
local function FindArenaMatch(player, arenaType)
local playerData = InitPlayerArenaData(player)
local playerRating = playerData.rating
local playerPower = CalculatePlayerPower(player)
local queue = arenaQueue[arenaType]
-- 寻找合适的对手
for i, queuedPlayer in ipairs(queue) do
if queuedPlayer:IsInWorld() then
local opponentData = InitPlayerArenaData(queuedPlayer)
local ratingDiff = math.abs(playerRating - opponentData.rating)
local powerDiff = math.abs(playerPower - CalculatePlayerPower(queuedPlayer))
-- 匹配条件:等级差距不超过200,战力差距不超过1000
if ratingDiff <= 200 and powerDiff <= 1000 then
-- 找到匹配,移除队列中的对手
table.remove(queue, i)
return queuedPlayer
end
else
-- 移除离线玩家
table.remove(queue, i)
end
end
return nil
end
-- 加入竞技场队列
local function JoinArenaQueue(player, arenaType)
local playerData = InitPlayerArenaData(player)
local currentTime = GetCurrTime()
-- 检查冷却时间
if currentTime - playerData.lastMatch < 300 then -- 5分钟冷却
local remaining = 300 - (currentTime - playerData.lastMatch)
player:SendBroadcastMessage("竞技场冷却中,还需等待 " .. remaining .. " 秒")
return false
end
-- 检查是否已在队列中
for _, queuedPlayer in ipairs(arenaQueue[arenaType]) do
if queuedPlayer:GetGUIDLow() == player:GetGUIDLow() then
player:SendBroadcastMessage("你已经在 " .. arenaType .. " 队列中")
return false
end
end
-- 尝试寻找匹配
local opponent = FindArenaMatch(player, arenaType)
if opponent then
-- 找到对手,开始匹配
StartArenaMatch(player, opponent, arenaType)
else
-- 加入队列等待
table.insert(arenaQueue[arenaType], player)
player:SendBroadcastMessage("已加入 " .. arenaType .. " 竞技场队列,等待匹配...")
-- 30秒后如果还没匹配到,扩大匹配范围
CreateLuaEvent(function()
ExpandMatchmaking(player, arenaType)
end, 30000, 1)
end
return true
end
-- 扩大匹配范围
local function ExpandMatchmaking(player, arenaType)
if not player:IsInWorld() then return end
-- 检查玩家是否还在队列中
local inQueue = false
for _, queuedPlayer in ipairs(arenaQueue[arenaType]) do
if queuedPlayer:GetGUIDLow() == player:GetGUIDLow() then
inQueue = true
break
end
end
if inQueue then
player:SendBroadcastMessage("扩大匹配范围,寻找对手中...")
-- 这里可以实现更宽松的匹配条件
end
end
-- 开始竞技场比赛
local function StartArenaMatch(player1, player2, arenaType)
local matchId = GetCurrTime() .. "_" .. player1:GetGUIDLow() .. "_" .. player2:GetGUIDLow()
-- 选择竞技场地图
local arenaMapId = 559 -- 默认地图
for mapId, mapData in pairs(ARENA_MAPS) do
if mapData.type == arenaType then
arenaMapId = mapId
break
end
end
-- 传送玩家到竞技场
local arenaCoords = {
[559] = {{x = 4055.5, y = 2919.5, z = 13.6}, {x = 4023.5, y = 2887.5, z = 13.6}}
}
local coords = arenaCoords[arenaMapId] or arenaCoords[559]
player1:Teleport(arenaMapId, coords[1].x, coords[1].y, coords[1].z, 0)
player2:Teleport(arenaMapId, coords[2].x, coords[2].y, coords[2].z, 0)
-- 记录比赛信息
activeMatches[matchId] = {
player1 = player1,
player2 = player2,
arenaType = arenaType,
startTime = GetCurrTime(),
mapId = arenaMapId
}
-- 通知玩家
player1:SendBroadcastMessage("竞技场比赛开始!对手: " .. player2:GetName())
player2:SendBroadcastMessage("竞技场比赛开始!对手: " .. player1:GetName())
-- 30秒准备时间
CreateLuaEvent(function()
StartArenaCombat(matchId)
end, 30000, 1)
end
-- 开始竞技场战斗
local function StartArenaCombat(matchId)
local match = activeMatches[matchId]
if not match then return end
local player1, player2 = match.player1, match.player2
if player1:IsInWorld() and player2:IsInWorld() then
player1:SendBroadcastMessage("战斗开始!")
player2:SendBroadcastMessage("战斗开始!")
-- 设置10分钟比赛时间限制
CreateLuaEvent(function()
EndArenaMatch(matchId, "timeout")
end, 600000, 1)
else
-- 有玩家离线,取消比赛
EndArenaMatch(matchId, "disconnect")
end
end
-- 结束竞技场比赛
local function EndArenaMatch(matchId, result, winner)
local match = activeMatches[matchId]
if not match then return end
local player1, player2 = match.player1, match.player2
local player1Data = InitPlayerArenaData(player1)
local player2Data = InitPlayerArenaData(player2)
-- 更新比赛记录
player1Data.lastMatch = GetCurrTime()
player2Data.lastMatch = GetCurrTime()
if result == "win" and winner then
local loser = (winner == player1) and player2 or player1
local winnerData = InitPlayerArenaData(winner)
local loserData = InitPlayerArenaData(loser)
-- 更新胜负记录
winnerData.wins = winnerData.wins + 1
winnerData.streak = winnerData.streak + 1
loserData.losses = loserData.losses + 1
loserData.streak = 0
-- 计算积分变化
local ratingChange = CalculateRatingChange(winnerData.rating, loserData.rating)
winnerData.rating = winnerData.rating + ratingChange
loserData.rating = math.max(0, loserData.rating - ratingChange)
-- 奖励
local seasonPoints = math.floor(ratingChange / 2)
winnerData.seasonPoints = winnerData.seasonPoints + seasonPoints
-- 通知结果
winner:SendBroadcastMessage("胜利!积分 +" .. ratingChange .. ",赛季点数 +" .. seasonPoints)
loser:SendBroadcastMessage("失败!积分 -" .. ratingChange)
-- 连胜奖励
if winnerData.streak >= 5 then
winner:AddItem(29434, 1) -- 连胜奖励物品
winner:SendBroadcastMessage("连胜 " .. winnerData.streak .. " 场!获得特殊奖励!")
end
elseif result == "timeout" then
player1:SendBroadcastMessage("比赛超时,平局")
player2:SendBroadcastMessage("比赛超时,平局")
elseif result == "disconnect" then
if player1:IsInWorld() then
player1:SendBroadcastMessage("对手离线,比赛取消")
end
if player2:IsInWorld() then
player2:SendBroadcastMessage("对手离线,比赛取消")
end
end
-- 传送玩家离开竞技场
if player1:IsInWorld() then
player1:Teleport(0, -8949.95, -132.493, 83.5312, 0) -- 暴风城
end
if player2:IsInWorld() then
player2:Teleport(0, -8949.95, -132.493, 83.5312, 0) -- 暴风城
end
-- 清理比赛数据
activeMatches[matchId] = nil
end
-- 计算积分变化
local function CalculateRatingChange(winnerRating, loserRating)
local ratingDiff = loserRating - winnerRating
local expectedScore = 1 / (1 + math.pow(10, ratingDiff / 400))
local kFactor = 32 -- K因子
return math.floor(kFactor * (1 - expectedScore))
end
-- 玩家死亡事件处理
local function OnPlayerDeath(event, player, killer)
-- 检查是否在竞技场中
for matchId, match in pairs(activeMatches) do
if match.player1 == player then
EndArenaMatch(matchId, "win", match.player2)
break
elseif match.player2 == player then
EndArenaMatch(matchId, "win", match.player1)
break
end
end
end
-- 显示竞技场排行榜
local function ShowArenaLeaderboard(player)
-- 按积分排序
local sortedPlayers = {}
for guid, data in pairs(arenaPlayers) do
table.insert(sortedPlayers, {guid = guid, data = data})
end
table.sort(sortedPlayers, function(a, b)
return a.data.rating > b.data.rating
end)
player:SendBroadcastMessage("=== 竞技场排行榜 ===")
for i = 1, math.min(10, #sortedPlayers) do
local playerData = sortedPlayers[i]
local playerName = "玩家" .. playerData.guid -- 这里需要根据GUID获取玩家名称
player:SendBroadcastMessage(string.format(
"%d. %s - 积分: %d (胜: %d, 负: %d)",
i, playerName, playerData.data.rating,
playerData.data.wins, playerData.data.losses
))
end
end
-- 注册事件
RegisterPlayerEvent(4, OnPlayerDeath) -- PLAYER_EVENT_ON_KILL_PLAYER
-- 竞技场命令处理
local function OnPlayerChat(event, player, msg, type, lang)
if msg:lower():find("^%.arena") then
local args = {}
for word in msg:gmatch("%S+") do
table.insert(args, word)
end
if args[2] == "join" and args[3] then
JoinArenaQueue(player, args[3])
elseif args[2] == "leave" then
-- 离开队列逻辑
player:SendBroadcastMessage("已离开竞技场队列")
elseif args[2] == "stats" then
local data = InitPlayerArenaData(player)
player:SendBroadcastMessage(string.format(
"竞技场统计 - 积分: %d, 胜: %d, 负: %d, 连胜: %d",
data.rating, data.wins, data.losses, data.streak
))
elseif args[2] == "top" then
ShowArenaLeaderboard(player)
end
end
end
RegisterPlayerEvent(18, OnPlayerChat) -- PLAYER_EVENT_ON_CHAT