-- 怪物军团活动系统 local this = {} MonsterLegionDefine = this -- 系统常量 MonsterLegionDefine = { STATUS = { NOT_STARTED = 0, -- 未开始 PREPARING = 1, -- 准备中 INVADING = 2, -- 入侵中 FINISHED = 3 -- 已结束 }, PHASE = { PREPARE = 1, -- 准备阶段 WAVE_1 = 2, -- 第一波 WAVE_2 = 3, -- 第二波 WAVE_3 = 4, -- 第三波 BOSS_WAVE = 5, -- BOSS波 SETTLEMENT = 6 -- 结算阶段 }, ACTIVITY_CONFIG = { DURATION = 90, -- 活动持续时间(分钟) PREPARE_TIME = 15, -- 准备时间(分钟) WAVE_DURATION = 15, -- 每波持续时间(分钟) BOSS_WAVE_DURATION = 20, -- BOSS波持续时间(分钟) MIN_PLAYERS = 20, -- 最少参与玩家数 MAX_WAVES = 5 -- 最大波数 }, DB_KEYS = { ACTIVITY_STATUS = "G$MonsterLegion_ActivityStatus", CURRENT_PHASE = "G$MonsterLegion_CurrentPhase", ACTIVITY_START_TIME = "G$MonsterLegion_ActivityStartTime", PHASE_START_TIME = "G$MonsterLegion_PhaseStartTime", PARTICIPATING_PLAYERS = "G$MonsterLegion_ParticipatingPlayers", CURRENT_WAVE = "G$MonsterLegion_CurrentWave", WAVE_MONSTERS = "G$MonsterLegion_WaveMonsters", PLAYER_SCORES = "G$MonsterLegion_PlayerScores", ALLIANCE_SCORES = "G$MonsterLegion_AllianceScores", TOTAL_KILLS = "G$MonsterLegion_TotalKills", BOSS_KILLED = "G$MonsterLegion_BossKilled" } } -- 怪物波次配置 local WAVE_CONFIG = { [1] = { name = "第一波:小怪入侵", monsterTypes = {"goblin", "orc", "troll"}, monsterCount = 50, monsterLevel = 100, spawnInterval = 3, difficulty = 1.0 }, [2] = { name = "第二波:精英怪", monsterTypes = {"elite_goblin", "elite_orc", "elite_troll"}, monsterCount = 30, monsterLevel = 150, spawnInterval = 5, difficulty = 1.5 }, [3] = { name = "第三波:混合部队", monsterTypes = {"goblin", "orc", "troll", "elite_goblin", "elite_orc"}, monsterCount = 40, monsterLevel = 200, spawnInterval = 4, difficulty = 2.0 }, [4] = { name = "第四波:强力精英", monsterTypes = {"elite_troll", "veteran_goblin", "veteran_orc"}, monsterCount = 25, monsterLevel = 250, spawnInterval = 6, difficulty = 2.5 }, [5] = { name = "最终波:军团BOSS", monsterTypes = {"legion_boss"}, monsterCount = 1, monsterLevel = 300, spawnInterval = 0, difficulty = 3.0 } } -- 奖励配置 local REWARD_CONFIG = { BASE_SCORE = 100, KILL_MULTIPLIER = 10, BOSS_KILL_BONUS = 1000, WAVE_COMPLETE_BONUS = 500, ALLIANCE_BONUS = 1.2 } -- 初始化系统 function this.Init() info("怪物军团活动系统初始化开始") this.StartTimers() info("怪物军团活动系统初始化完成") end -- 启动定时器 function this.StartTimers() setTimer(60000, function() this.CheckAndStartActivity() end) end -- 检查并启动活动 function this.CheckAndStartActivity() local now = os.time() local currentStatus = getsysvar(MonsterLegionDefine.DB_KEYS.ACTIVITY_STATUS) or MonsterLegionDefine.STATUS.NOT_STARTED if currentStatus == MonsterLegionDefine.STATUS.NOT_STARTED and this.IsActivityTime(now) then this.StartActivity() elseif currentStatus == MonsterLegionDefine.STATUS.PREPARING then local startTime = getsysvar(MonsterLegionDefine.DB_KEYS.PHASE_START_TIME) or 0 if now - startTime >= MonsterLegionDefine.ACTIVITY_CONFIG.PREPARE_TIME * 60 then this.StartFirstWave() end elseif currentStatus == MonsterLegionDefine.STATUS.INVADING then local startTime = getsysvar(MonsterLegionDefine.DB_KEYS.PHASE_START_TIME) or 0 local currentWave = getsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_WAVE) or 1 local waveDuration = this.GetWaveDuration(currentWave) if now - startTime >= waveDuration * 60 then this.CompleteWave(currentWave) end end end -- 检查是否为活动时间 function this.IsActivityTime(now) local timeInfo = os.date("*t", now) return (timeInfo.wday == 3 or timeInfo.wday == 5) and timeInfo.hour == 19 and timeInfo.min == 0 end -- 获取波次持续时间 function this.GetWaveDuration(waveNumber) if waveNumber == MonsterLegionDefine.PHASE.BOSS_WAVE then return MonsterLegionDefine.ACTIVITY_CONFIG.BOSS_WAVE_DURATION else return MonsterLegionDefine.ACTIVITY_CONFIG.WAVE_DURATION end end -- 开始活动 function this.StartActivity() info("怪物军团活动开始") setsysvar(MonsterLegionDefine.DB_KEYS.ACTIVITY_STATUS, MonsterLegionDefine.STATUS.PREPARING) setsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_PHASE, MonsterLegionDefine.PHASE.PREPARE) setsysvar(MonsterLegionDefine.DB_KEYS.ACTIVITY_START_TIME, os.time()) setsysvar(MonsterLegionDefine.DB_KEYS.PHASE_START_TIME, os.time()) setsysvar(MonsterLegionDefine.DB_KEYS.PARTICIPATING_PLAYERS, {}) setsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_WAVE, 0) setsysvar(MonsterLegionDefine.DB_KEYS.WAVE_MONSTERS, {}) setsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES, {}) setsysvar(MonsterLegionDefine.DB_KEYS.ALLIANCE_SCORES, {}) setsysvar(MonsterLegionDefine.DB_KEYS.TOTAL_KILLS, 0) setsysvar(MonsterLegionDefine.DB_KEYS.BOSS_KILLED, false) this.SendWorldNotice("怪物军团活动开始!准备阶段15分钟,所有玩家可参与") info("怪物军团活动启动完成") end -- 开始第一波 function this.StartFirstWave() info("怪物军团第一波开始") setsysvar(MonsterLegionDefine.DB_KEYS.ACTIVITY_STATUS, MonsterLegionDefine.STATUS.INVADING) setsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_PHASE, MonsterLegionDefine.PHASE.WAVE_1) setsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_WAVE, 1) setsysvar(MonsterLegionDefine.DB_KEYS.PHASE_START_TIME, os.time()) this.GenerateWaveMonsters(1) this.SendWorldNotice("怪物军团第一波开始!小怪入侵,请所有玩家准备战斗") end -- 生成波次怪物 function this.GenerateWaveMonsters(waveNumber) local waveConfig = WAVE_CONFIG[waveNumber] if not waveConfig then return end local waveMonsters = {} for i = 1, waveConfig.monsterCount do local monsterType = waveConfig.monsterTypes[math.random(1, #waveConfig.monsterTypes)] local monster = { id = "ML_" .. waveNumber .. "_" .. i, type = monsterType, level = waveConfig.monsterLevel, hp = this.CalculateMonsterHP(waveConfig.monsterLevel, waveConfig.difficulty), maxHp = this.CalculateMonsterHP(waveConfig.monsterLevel, waveConfig.difficulty), spawnTime = os.time() + (i - 1) * waveConfig.spawnInterval, isAlive = true, waveNumber = waveNumber } table.insert(waveMonsters, monster) end setsysvar(MonsterLegionDefine.DB_KEYS.WAVE_MONSTERS, waveMonsters) info("生成第", waveNumber, "波怪物,数量:", #waveMonsters) end -- 计算怪物血量 function this.CalculateMonsterHP(level, difficulty) local baseHP = level * 100 return math.floor(baseHP * difficulty) end -- 完成波次 function this.CompleteWave(waveNumber) info("怪物军团第", waveNumber, "波完成") if waveNumber < MonsterLegionDefine.ACTIVITY_CONFIG.MAX_WAVES then this.StartNextWave(waveNumber + 1) else this.EndActivity() end end -- 开始下一波 function this.StartNextWave(waveNumber) info("怪物军团第", waveNumber, "波开始") local phase = MonsterLegionDefine.PHASE.WAVE_1 + waveNumber - 1 setsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_PHASE, phase) setsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_WAVE, waveNumber) setsysvar(MonsterLegionDefine.DB_KEYS.PHASE_START_TIME, os.time()) this.GenerateWaveMonsters(waveNumber) local waveConfig = WAVE_CONFIG[waveNumber] this.SendWorldNotice("怪物军团第" .. waveNumber .. "波开始!" .. waveConfig.name) this.GiveWaveCompleteReward(waveNumber) end -- 给波次完成奖励 function this.GiveWaveCompleteReward(waveNumber) local participatingPlayers = getsysvar(MonsterLegionDefine.DB_KEYS.PARTICIPATING_PLAYERS) or {} local playerScores = getsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES) or {} for _, playerId in ipairs(participatingPlayers) do if playerScores[playerId] then playerScores[playerId] = playerScores[playerId] + REWARD_CONFIG.WAVE_COMPLETE_BONUS end end setsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES, playerScores) info("第", waveNumber, "波完成奖励发放完成") end -- 结束活动 function this.EndActivity() info("怪物军团活动结束") setsysvar(MonsterLegionDefine.DB_KEYS.ACTIVITY_STATUS, MonsterLegionDefine.STATUS.FINISHED) this.CalculateFinalResult() this.DistributeRewards() this.CleanupActivityData() this.SendWorldNotice("怪物军团活动结束!结果已公布,奖励已分配") end -- 玩家报名 function this.PlayerRegister(actor) local currentStatus = getsysvar(MonsterLegionDefine.DB_KEYS.ACTIVITY_STATUS) or MonsterLegionDefine.STATUS.NOT_STARTED if currentStatus == MonsterLegionDefine.STATUS.NOT_STARTED then tipinfo(actor, "活动未开始") return false end local playerId = actor:toString() local participatingPlayers = getsysvar(MonsterLegionDefine.DB_KEYS.PARTICIPATING_PLAYERS) or {} for _, id in ipairs(participatingPlayers) do if id == playerId then tipinfo(actor, "您已经报名了") return false end end table.insert(participatingPlayers, playerId) setsysvar(MonsterLegionDefine.DB_KEYS.PARTICIPATING_PLAYERS, participatingPlayers) local playerScores = getsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES) or {} playerScores[playerId] = 0 setsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES, playerScores) tipinfo(actor, "报名成功!请等待活动开始") info("玩家报名成功:", playerId, ",当前报名人数:", #participatingPlayers) return true end -- 记录怪物击杀 function this.RecordMonsterKill(actor, monsterId) local currentStatus = getsysvar(MonsterLegionDefine.DB_KEYS.ACTIVITY_STATUS) or MonsterLegionDefine.STATUS.NOT_STARTED if currentStatus ~= MonsterLegionDefine.STATUS.INVADING then return end local playerId = actor:toString() local allianceId = getbaseinfo(actor, "guildid") local participatingPlayers = getsysvar(MonsterLegionDefine.DB_KEYS.PARTICIPATING_PLAYERS) or {} local isParticipating = false for _, id in ipairs(participatingPlayers) do if id == playerId then isParticipating = true break end end if not isParticipating then return end local waveMonsters = getsysvar(MonsterLegionDefine.DB_KEYS.WAVE_MONSTERS) or {} local monster = nil for _, m in ipairs(waveMonsters) do if m.id == monsterId and m.isAlive then monster = m break end end if not monster then return end monster.isAlive = false local killScore = this.CalculateKillScore(monster) this.UpdatePlayerScore(actor, killScore) if allianceId and allianceId > 0 then this.UpdateAllianceScore(allianceId, killScore) end local totalKills = getsysvar(MonsterLegionDefine.DB_KEYS.TOTAL_KILLS) or 0 setsysvar(MonsterLegionDefine.DB_KEYS.TOTAL_KILLS, totalKills + 1) if monster.type == "legion_boss" then setsysvar(MonsterLegionDefine.DB_KEYS.BOSS_KILLED, true) this.OnBossKilled(actor) end this.CheckWaveCompletion() info("怪物击杀记录:玩家", playerId, "击杀怪物", monsterId, ",获得分数:", killScore) end -- 计算击杀分数 function this.CalculateKillScore(monster) local baseScore = REWARD_CONFIG.BASE_SCORE local levelMultiplier = monster.level / 100 local difficultyMultiplier = monster.waveNumber local finalScore = math.floor(baseScore * levelMultiplier * difficultyMultiplier * REWARD_CONFIG.KILL_MULTIPLIER) if monster.type == "legion_boss" then finalScore = finalScore + REWARD_CONFIG.BOSS_KILL_BONUS end return finalScore end -- 更新玩家分数 function this.UpdatePlayerScore(actor, score) local playerScores = getsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES) or {} local playerId = actor:toString() playerScores[playerId] = (playerScores[playerId] or 0) + score setsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES, playerScores) end -- 更新战盟分数 function this.UpdateAllianceScore(allianceId, score) local allianceScores = getsysvar(MonsterLegionDefine.DB_KEYS.ALLIANCE_SCORES) or {} allianceScores[allianceId] = (allianceScores[allianceId] or 0) + score setsysvar(MonsterLegionDefine.DB_KEYS.ALLIANCE_SCORES, allianceScores) end -- BOSS被击杀 function this.OnBossKilled(actor) local playerId = actor:toString() local playerScores = getsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES) or {} playerScores[playerId] = (playerScores[playerId] or 0) + REWARD_CONFIG.BOSS_KILL_BONUS setsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES, playerScores) this.SendWorldNotice("恭喜玩家 " .. getbaseinfo(actor, "rolename") .. " 击杀了军团BOSS!") info("军团BOSS被击杀,击杀者:", playerId) end -- 检查波次是否完成 function this.CheckWaveCompletion() local waveMonsters = getsysvar(MonsterLegionDefine.DB_KEYS.WAVE_MONSTERS) or {} local aliveCount = 0 for _, monster in ipairs(waveMonsters) do if monster.isAlive then aliveCount = aliveCount + 1 end end if aliveCount == 0 then local currentWave = getsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_WAVE) or 1 this.CompleteWave(currentWave) end end -- 计算最终结果 function this.CalculateFinalResult() local totalKills = getsysvar(MonsterLegionDefine.DB_KEYS.TOTAL_KILLS) or 0 local bossKilled = getsysvar(MonsterLegionDefine.DB_KEYS.BOSS_KILLED) or false info("怪物军团活动结果:总击杀数:", totalKills, ",BOSS是否击杀:", bossKilled) end -- 分配奖励 function this.DistributeRewards() local playerScores = getsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES) or {} local allianceScores = getsysvar(MonsterLegionDefine.DB_KEYS.ALLIANCE_SCORES) or {} for playerId, score in pairs(playerScores) do if score > 0 then this.GivePlayerReward(playerId, score) end end for allianceId, score in pairs(allianceScores) do if score > 0 then this.GiveAllianceReward(allianceId, score) end end info("怪物军团活动奖励分配完成") end -- 给玩家发放奖励 function this.GivePlayerReward(playerId, score) local playerActor = getactor(tonumber(playerId)) if playerActor then info("玩家奖励:", playerId, ",分数:", score) end end -- 给战盟发放奖励 function this.GiveAllianceReward(allianceId, score) info("战盟奖励:", allianceId, ",分数:", score) end -- 清理活动数据 function this.CleanupActivityData() setsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_PHASE, nil) setsysvar(MonsterLegionDefine.DB_KEYS.ACTIVITY_START_TIME, nil) setsysvar(MonsterLegionDefine.DB_KEYS.PHASE_START_TIME, nil) setsysvar(MonsterLegionDefine.DB_KEYS.PARTICIPATING_PLAYERS, nil) setsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_WAVE, nil) setsysvar(MonsterLegionDefine.DB_KEYS.WAVE_MONSTERS, nil) setsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES, nil) setsysvar(MonsterLegionDefine.DB_KEYS.ALLIANCE_SCORES, nil) setsysvar(MonsterLegionDefine.DB_KEYS.TOTAL_KILLS, nil) setsysvar(MonsterLegionDefine.DB_KEYS.BOSS_KILLED, nil) info("怪物军团活动数据清理完成") end -- 发送全服公告 function this.SendWorldNotice(message) info("全服公告:", message) end -- 获取活动状态 function this.GetActivityStatus() return getsysvar(MonsterLegionDefine.DB_KEYS.ACTIVITY_STATUS) or MonsterLegionDefine.STATUS.NOT_STARTED end -- 获取当前阶段 function this.GetCurrentPhase() return getsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_PHASE) or MonsterLegionDefine.PHASE.PREPARE end -- 获取当前波次 function this.GetCurrentWave() return getsysvar(MonsterLegionDefine.DB_KEYS.CURRENT_WAVE) or 0 end -- 获取玩家分数排名 function this.GetPlayerScoreRanking() local playerScores = getsysvar(MonsterLegionDefine.DB_KEYS.PLAYER_SCORES) or {} local playerList = {} for playerId, score in pairs(playerScores) do table.insert(playerList, {id = playerId, score = score}) end table.sort(playerList, function(a, b) return a.score > b.score end) return playerList end -- 获取战盟分数排名 function this.GetAllianceScoreRanking() local allianceScores = getsysvar(MonsterLegionDefine.DB_KEYS.ALLIANCE_SCORES) or {} local allianceList = {} for allianceId, score in pairs(allianceScores) do table.insert(allianceList, {id = allianceId, score = score}) end table.sort(allianceList, function(a, b) return a.score > b.score end) return allianceList end -- 获取活动剩余时间 function this.GetActivityRemainingTime() local currentStatus = this.GetActivityStatus() local startTime = getsysvar(MonsterLegionDefine.DB_KEYS.ACTIVITY_START_TIME) or 0 local now = os.time() if currentStatus == MonsterLegionDefine.STATUS.PREPARING then return math.max(0, MonsterLegionDefine.ACTIVITY_CONFIG.PREPARE_TIME * 60 - (now - startTime)) elseif currentStatus == MonsterLegionDefine.STATUS.INVADING then local phaseStartTime = getsysvar(MonsterLegionDefine.DB_KEYS.PHASE_START_TIME) or 0 local currentWave = this.GetCurrentWave() local waveDuration = this.GetWaveDuration(currentWave) return math.max(0, waveDuration * 60 - (now - phaseStartTime)) end return 0 end -- 检查玩家是否已报名 function this.IsPlayerRegistered(actor) local playerId = actor:toString() local participatingPlayers = getsysvar(MonsterLegionDefine.DB_KEYS.PARTICIPATING_PLAYERS) or {} for _, id in ipairs(participatingPlayers) do if id == playerId then return true end end return false end -- 检查玩家是否可参与活动 function this.CanPlayerParticipate(actor) local currentStatus = this.GetActivityStatus() if currentStatus == MonsterLegionDefine.STATUS.NOT_STARTED then return false, "活动未开始" elseif currentStatus == MonsterLegionDefine.STATUS.PREPARING then return this.IsPlayerRegistered(actor), "请先报名参加活动" elseif currentStatus == MonsterLegionDefine.STATUS.INVADING then return this.IsPlayerRegistered(actor), "请先报名参加活动" end return false, "活动状态异常" end -- 获取当前波次怪物信息 function this.GetCurrentWaveMonsters() return getsysvar(MonsterLegionDefine.DB_KEYS.WAVE_MONSTERS) or {} end -- 获取活动统计信息 function this.GetActivityStats() local totalKills = getsysvar(MonsterLegionDefine.DB_KEYS.TOTAL_KILLS) or 0 local bossKilled = getsysvar(MonsterLegionDefine.DB_KEYS.BOSS_KILLED) or false local currentWave = this.GetCurrentWave() local participatingPlayers = getsysvar(MonsterLegionDefine.DB_KEYS.PARTICIPATING_PLAYERS) or {} return { totalKills = totalKills, bossKilled = bossKilled, currentWave = currentWave, participantCount = #participatingPlayers, timeRemaining = this.GetActivityRemainingTime() } end return this