-- 攻城战系统 local this = {} SiegeWar = this -- 系统常量 SiegeWarDefine = { STATUS = { NOT_STARTED = 0, -- 未开始 PREPARING = 1, -- 准备中 FIGHTING = 2, -- 战斗中 FINISHED = 3 -- 已结束 }, PHASE = { PREPARE = 1, -- 准备阶段 ATTACK = 2, -- 攻击阶段 DEFEND = 3, -- 防守阶段 SETTLEMENT = 4 -- 结算阶段 }, ACTIVITY_CONFIG = { OPEN_DAYS = 14, -- 开服后多少天开启 DURATION = 120, -- 活动持续时间(分钟) PREPARE_TIME = 30, -- 准备时间(分钟) ATTACK_TIME = 60, -- 攻击时间(分钟) DEFEND_TIME = 30 -- 防守时间(分钟) }, DB_KEYS = { ACTIVITY_STATUS = "G$SiegeWar_ActivityStatus", CURRENT_PHASE = "G$SiegeWar_CurrentPhase", ACTIVITY_START_TIME = "G$SiegeWar_ActivityStartTime", PHASE_START_TIME = "G$SiegeWar_PhaseStartTime", PARTICIPATING_ALLIANCES = "G$SiegeWar_ParticipatingAlliances", CASTLE_HP = "G$SiegeWar_CastleHP", CASTLE_MAX_HP = "G$SiegeWar_CastleMaxHP", ALLIANCE_SCORES = "G$SiegeWar_AllianceScores", PLAYER_SCORES = "G$SiegeWar_PlayerScores", CASTLE_OWNER = "G$SiegeWar_CastleOwner", WINNER_ALLIANCE = "G$SiegeWar_WinnerAlliance" } } -- 城堡配置 local CASTLE_CONFIG = { MAX_HP = 1000000, -- 城堡最大血量 DEFENSE_BONUS = 1.5, -- 防守方伤害加成 ATTACK_BONUS = 1.2, -- 攻击方伤害加成 CAPTURE_THRESHOLD = 0.1, -- 占领阈值(剩余血量百分比) REWARD_MULTIPLIER = 2.0 -- 奖励倍数 } -- 初始化系统 function this.Init() -- info("攻城战系统初始化开始") -- 检查服务器开启天数 this.CheckServerOpenDays() -- 启动定时器 this.StartTimers() -- info("攻城战系统初始化完成") end -- 检查服务器开启天数 function this.CheckServerOpenDays() local serverOpenDays = getbaseinfo(nil, "serveropendays") or 0 if serverOpenDays >= SiegeWarDefine.ACTIVITY_CONFIG.OPEN_DAYS then -- 服务器开启天数满足要求,可以开启攻城战 this.EnableSiegeWar() else -- info("服务器开启天数不足,攻城战暂未开启。当前天数:", serverOpenDays, ",需要天数:", SiegeWarDefine.ACTIVITY_CONFIG.OPEN_DAYS) end end -- 启用攻城战 function this.EnableSiegeWar() -- info("攻城战系统已启用") -- 这里可以设置一些标志位或通知客户端 end -- 启动定时器 function this.StartTimers() -- 每分钟检查一次活动状态 setTimer(60000, function() this.CheckAndStartActivity() end) end -- 检查并启动活动 function this.CheckAndStartActivity() local now = os.time() local currentStatus = getsysvar(SiegeWarDefine.DB_KEYS.ACTIVITY_STATUS) or SiegeWarDefine.STATUS.NOT_STARTED if currentStatus == SiegeWarDefine.STATUS.NOT_STARTED then -- 检查是否到了活动时间 if this.IsActivityTime(now) then this.StartActivity() end elseif currentStatus == SiegeWarDefine.STATUS.PREPARING then -- 检查准备阶段是否结束 local startTime = getsysvar(SiegeWarDefine.DB_KEYS.PHASE_START_TIME) or 0 if now - startTime >= SiegeWarDefine.ACTIVITY_CONFIG.PREPARE_TIME * 60 then this.StartAttackPhase() end elseif currentStatus == SiegeWarDefine.STATUS.FIGHTING then -- 检查攻击阶段是否结束 local startTime = getsysvar(SiegeWarDefine.DB_KEYS.PHASE_START_TIME) or 0 if now - startTime >= SiegeWarDefine.ACTIVITY_CONFIG.ATTACK_TIME * 60 then this.StartDefendPhase() end end end -- 检查是否为活动时间 function this.IsActivityTime(now) -- 这里可以根据具体需求设置活动时间 -- 例如:每周六晚上8点 local timeInfo = os.date("*t", now) return timeInfo.wday == 6 and timeInfo.hour == 20 and timeInfo.min == 0 end -- 开始活动 function this.StartActivity() -- info("攻城战活动开始") -- 设置活动状态 setsysvar(SiegeWarDefine.DB_KEYS.ACTIVITY_STATUS, SiegeWarDefine.STATUS.PREPARING) setsysvar(SiegeWarDefine.DB_KEYS.CURRENT_PHASE, SiegeWarDefine.PHASE.PREPARE) setsysvar(SiegeWarDefine.DB_KEYS.ACTIVITY_START_TIME, os.time()) setsysvar(SiegeWarDefine.DB_KEYS.PHASE_START_TIME, os.time()) setsysvar(SiegeWarDefine.DB_KEYS.PARTICIPATING_ALLIANCES, {}) setsysvar(SiegeWarDefine.DB_KEYS.ALLIANCE_SCORES, {}) setsysvar(SiegeWarDefine.DB_KEYS.PLAYER_SCORES, {}) -- 设置城堡血量 setsysvar(SiegeWarDefine.DB_KEYS.CASTLE_HP, CASTLE_CONFIG.MAX_HP) setsysvar(SiegeWarDefine.DB_KEYS.CASTLE_MAX_HP, CASTLE_CONFIG.MAX_HP) -- 获取当前城堡拥有者 local castleOwner = this.GetCastleOwner() if castleOwner then setsysvar(SiegeWarDefine.DB_KEYS.CASTLE_OWNER, castleOwner) end -- 发送全服公告 this.SendWorldNotice("攻城战活动开始!准备阶段30分钟,所有战盟可报名参与") -- info("攻城战活动启动完成") end -- 开始攻击阶段 function this.StartAttackPhase() -- info("攻城战攻击阶段开始") setsysvar(SiegeWarDefine.DB_KEYS.ACTIVITY_STATUS, SiegeWarDefine.STATUS.FIGHTING) setsysvar(SiegeWarDefine.DB_KEYS.CURRENT_PHASE, SiegeWarDefine.PHASE.ATTACK) setsysvar(SiegeWarDefine.DB_KEYS.PHASE_START_TIME, os.time()) this.SendWorldNotice("攻城战攻击阶段开始!攻击时间60分钟,所有报名战盟可攻击城堡") end -- 开始防守阶段 function this.StartDefendPhase() -- info("攻城战防守阶段开始") setsysvar(SiegeWarDefine.DB_KEYS.CURRENT_PHASE, SiegeWarDefine.PHASE.DEFEND) setsysvar(SiegeWarDefine.DB_KEYS.PHASE_START_TIME, os.time()) this.SendWorldNotice("攻城战防守阶段开始!防守时间30分钟,城堡拥有者战盟可防守城堡") -- 延迟结束活动 setTimer(SiegeWarDefine.ACTIVITY_CONFIG.DEFEND_TIME * 60 * 1000, function() this.EndActivity() end) end -- 结束活动 function this.EndActivity() -- info("攻城战活动结束") setsysvar(SiegeWarDefine.DB_KEYS.ACTIVITY_STATUS, SiegeWarDefine.STATUS.FINISHED) -- 计算最终结果 this.CalculateFinalResult() -- 分配奖励 this.DistributeRewards() -- 清理数据 this.CleanupActivityData() this.SendWorldNotice("攻城战活动结束!结果已公布,奖励已分配") end -- 战盟报名 function this.AllianceRegister(actor) local currentStatus = getsysvar(SiegeWarDefine.DB_KEYS.ACTIVITY_STATUS) or SiegeWarDefine.STATUS.NOT_STARTED if currentStatus ~= SiegeWarDefine.STATUS.PREPARING then tipinfo(actor, "当前不在报名时间") return false end local allianceId = getbaseinfo(actor, "guildid") if not allianceId or allianceId <= 0 then tipinfo(actor, "您不是战盟成员") return false end local participatingAlliances = getsysvar(SiegeWarDefine.DB_KEYS.PARTICIPATING_ALLIANCES) or {} -- 检查是否已报名 for _, id in ipairs(participatingAlliances) do if id == allianceId then tipinfo(actor, "您的战盟已经报名了") return false end end -- 添加战盟到报名列表 table.insert(participatingAlliances, allianceId) setsysvar(SiegeWarDefine.DB_KEYS.PARTICIPATING_ALLIANCES, participatingAlliances) -- 初始化战盟分数 local allianceScores = getsysvar(SiegeWarDefine.DB_KEYS.ALLIANCE_SCORES) or {} allianceScores[allianceId] = 0 setsysvar(SiegeWarDefine.DB_KEYS.ALLIANCE_SCORES, allianceScores) tipinfo(actor, "战盟报名成功!请等待战斗开始") -- info("战盟报名成功:", allianceId, ",当前报名战盟数:", #participatingAlliances) return true end -- 记录玩家伤害 function this.RecordPlayerDamage(actor, damage, isDefender) local currentStatus = getsysvar(SiegeWarDefine.DB_KEYS.ACTIVITY_STATUS) or SiegeWarDefine.STATUS.NOT_STARTED if currentStatus ~= SiegeWarDefine.STATUS.FIGHTING then return end local playerId = actor:toString() local allianceId = getbaseinfo(actor, "guildid") if not allianceId or allianceId <= 0 then return end -- 检查战盟是否已报名 local participatingAlliances = getsysvar(SiegeWarDefine.DB_KEYS.PARTICIPATING_ALLIANCES) or {} local isParticipating = false for _, id in ipairs(participatingAlliances) do if id == allianceId then isParticipating = true break end end if not isParticipating then return end -- 应用伤害加成 local finalDamage = damage if isDefender then finalDamage = math.floor(damage * CASTLE_CONFIG.DEFENSE_BONUS) else finalDamage = math.floor(damage * CASTLE_CONFIG.ATTACK_BONUS) end -- 更新城堡血量 this.UpdateCastleHP(finalDamage, isDefender) -- 更新玩家分数 this.UpdatePlayerScore(actor, finalDamage) -- 更新战盟分数 this.UpdateAllianceScore(allianceId, finalDamage) -- 检查城堡是否被攻破 this.CheckCastleCapture() end -- 更新城堡血量 function this.UpdateCastleHP(damage, isDefender) local currentHP = getsysvar(SiegeWarDefine.DB_KEYS.CASTLE_HP) or CASTLE_CONFIG.MAX_HP local maxHP = getsysvar(SiegeWarDefine.DB_KEYS.CASTLE_MAX_HP) or CASTLE_CONFIG.MAX_HP if isDefender then -- 防守方攻击,恢复城堡血量 currentHP = math.min(maxHP, currentHP + damage) else -- 攻击方攻击,减少城堡血量 currentHP = math.max(0, currentHP - damage) end setsysvar(SiegeWarDefine.DB_KEYS.CASTLE_HP, currentHP) -- info("城堡血量更新:", currentHP, "/", maxHP, ",伤害:", damage, ",是否防守方:", isDefender) end -- 更新玩家分数 function this.UpdatePlayerScore(actor, damage) local playerScores = getsysvar(SiegeWarDefine.DB_KEYS.PLAYER_SCORES) or {} local playerId = actor:toString() playerScores[playerId] = (playerScores[playerId] or 0) + damage setsysvar(SiegeWarDefine.DB_KEYS.PLAYER_SCORES, playerScores) end -- 更新战盟分数 function this.UpdateAllianceScore(allianceId, damage) local allianceScores = getsysvar(SiegeWarDefine.DB_KEYS.ALLIANCE_SCORES) or {} allianceScores[allianceId] = (allianceScores[allianceId] or 0) + damage setsysvar(SiegeWarDefine.DB_KEYS.ALLIANCE_SCORES, allianceScores) end -- 检查城堡是否被攻破 function this.CheckCastleCapture() local currentHP = getsysvar(SiegeWarDefine.DB_KEYS.CASTLE_HP) or CASTLE_CONFIG.MAX_HP local maxHP = getsysvar(SiegeWarDefine.DB_KEYS.CASTLE_MAX_HP) or CASTLE_CONFIG.MAX_HP if currentHP <= maxHP * CASTLE_CONFIG.CAPTURE_THRESHOLD then -- 城堡被攻破 this.OnCastleCaptured() end end -- 城堡被攻破 function this.OnCastleCaptured() -- info("城堡被攻破") -- 找到伤害最高的攻击方战盟 local allianceScores = getsysvar(SiegeWarDefine.DB_KEYS.ALLIANCE_SCORES) or {} local castleOwner = getsysvar(SiegeWarDefine.DB_KEYS.CASTLE_OWNER) local maxScore = 0 local winnerAlliance = nil for allianceId, score in pairs(allianceScores) do if allianceId ~= castleOwner and score > maxScore then maxScore = score winnerAlliance = allianceId end end if winnerAlliance then -- 设置新的城堡拥有者 setsysvar(SiegeWarDefine.DB_KEYS.CASTLE_OWNER, winnerAlliance) setsysvar(SiegeWarDefine.DB_KEYS.WINNER_ALLIANCE, winnerAlliance) this.SendWorldNotice("城堡已被攻破!新的城堡拥有者:" .. this.GetAllianceName(winnerAlliance)) -- 恢复城堡血量 setsysvar(SiegeWarDefine.DB_KEYS.CASTLE_HP, CASTLE_CONFIG.MAX_HP) end end -- 计算最终结果 function this.CalculateFinalResult() local castleOwner = getsysvar(SiegeWarDefine.DB_KEYS.CASTLE_OWNER) local allianceScores = getsysvar(SiegeWarDefine.DB_KEYS.ALLIANCE_SCORES) or {} if castleOwner then -- 城堡拥有者获胜 setsysvar(SiegeWarDefine.DB_KEYS.WINNER_ALLIANCE, castleOwner) -- info("攻城战结果:城堡拥有者获胜,战盟ID:", castleOwner) else -- 没有城堡拥有者,按分数排名 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) if #allianceList > 0 then setsysvar(SiegeWarDefine.DB_KEYS.WINNER_ALLIANCE, allianceList[1].id) -- info("攻城战结果:按分数排名获胜,战盟ID:", allianceList[1].id, ",分数:", allianceList[1].score) end end end -- 分配奖励 function this.DistributeRewards() local winnerAlliance = getsysvar(SiegeWarDefine.DB_KEYS.WINNER_ALLIANCE) local allianceScores = getsysvar(SiegeWarDefine.DB_KEYS.ALLIANCE_SCORES) or {} if winnerAlliance then -- 给获胜战盟发放奖励 this.GiveAllianceReward(winnerAlliance, true) -- 给其他参与战盟发放参与奖励 for allianceId, score in pairs(allianceScores) do if allianceId ~= winnerAlliance and score > 0 then this.GiveAllianceReward(allianceId, false) end end end -- info("攻城战奖励分配完成") end -- 给战盟发放奖励 function this.GiveAllianceReward(allianceId, isWinner) local rewardMultiplier = isWinner and CASTLE_CONFIG.REWARD_MULTIPLIER or 1.0 local baseReward = 1000 -- 基础奖励 local finalReward = math.floor(baseReward * rewardMultiplier) -- 这里需要实现具体的奖励发放逻辑 -- 可以给战盟成员发放邮件奖励 -- info("战盟奖励:", allianceId, ",是否获胜:", isWinner, ",奖励:", finalReward) end -- 清理活动数据 function this.CleanupActivityData() setsysvar(SiegeWarDefine.DB_KEYS.CURRENT_PHASE, nil) setsysvar(SiegeWarDefine.DB_KEYS.ACTIVITY_START_TIME, nil) setsysvar(SiegeWarDefine.DB_KEYS.PHASE_START_TIME, nil) setsysvar(SiegeWarDefine.DB_KEYS.PARTICIPATING_ALLIANCES, nil) setsysvar(SiegeWarDefine.DB_KEYS.ALLIANCE_SCORES, nil) setsysvar(SiegeWarDefine.DB_KEYS.PLAYER_SCORES, nil) -- info("攻城战活动数据清理完成") end -- 获取城堡拥有者 function this.GetCastleOwner() -- 这里需要实现获取城堡拥有者的逻辑 -- 可以从配置文件或数据库读取 return nil end -- 获取战盟名称 function this.GetAllianceName(allianceId) -- 这里需要实现获取战盟名称的逻辑 return "战盟" .. allianceId end -- 发送全服公告 function this.SendWorldNotice(message) -- info("全服公告:", message) end -- 获取活动状态 function this.GetActivityStatus() return getsysvar(SiegeWarDefine.DB_KEYS.ACTIVITY_STATUS) or SiegeWarDefine.STATUS.NOT_STARTED end -- 获取当前阶段 function this.GetCurrentPhase() return getsysvar(SiegeWarDefine.DB_KEYS.CURRENT_PHASE) or SiegeWarDefine.PHASE.PREPARE end -- 获取城堡血量信息 function this.GetCastleHPInfo() local currentHP = getsysvar(SiegeWarDefine.DB_KEYS.CASTLE_HP) or CASTLE_CONFIG.MAX_HP local maxHP = getsysvar(SiegeWarDefine.DB_KEYS.CASTLE_MAX_HP) or CASTLE_CONFIG.MAX_HP return { current = currentHP, max = maxHP, percentage = maxHP > 0 and (currentHP / maxHP * 100) or 0 } end -- 获取战盟分数排名 function this.GetAllianceScoreRanking() local allianceScores = getsysvar(SiegeWarDefine.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.GetPlayerScoreRanking() local playerScores = getsysvar(SiegeWarDefine.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.GetActivityRemainingTime() local currentStatus = this.GetActivityStatus() local startTime = getsysvar(SiegeWarDefine.DB_KEYS.ACTIVITY_START_TIME) or 0 local now = os.time() if currentStatus == SiegeWarDefine.STATUS.PREPARING then return math.max(0, SiegeWarDefine.ACTIVITY_CONFIG.PREPARE_TIME * 60 - (now - startTime)) elseif currentStatus == SiegeWarDefine.STATUS.FIGHTING then local phaseStartTime = getsysvar(SiegeWarDefine.DB_KEYS.PHASE_START_TIME) or 0 local currentPhase = this.GetCurrentPhase() if currentPhase == SiegeWarDefine.PHASE.ATTACK then return math.max(0, SiegeWarDefine.ACTIVITY_CONFIG.ATTACK_TIME * 60 - (now - phaseStartTime)) elseif currentPhase == SiegeWarDefine.PHASE.DEFEND then return math.max(0, SiegeWarDefine.ACTIVITY_CONFIG.DEFEND_TIME * 60 - (now - phaseStartTime)) end end return 0 end -- 检查战盟是否已报名 function this.IsAllianceRegistered(actor) local allianceId = getbaseinfo(actor, "guildid") if not allianceId or allianceId <= 0 then return false end local participatingAlliances = getsysvar(SiegeWarDefine.DB_KEYS.PARTICIPATING_ALLIANCES) or {} for _, id in ipairs(participatingAlliances) do if id == allianceId then return true end end return false end -- 检查玩家是否可参与活动 function this.CanPlayerParticipate(actor) local currentStatus = this.GetActivityStatus() if currentStatus == SiegeWarDefine.STATUS.NOT_STARTED then return false, "活动未开始" elseif currentStatus == SiegeWarDefine.STATUS.PREPARING then return this.IsAllianceRegistered(actor), "请先报名参加活动" elseif currentStatus == SiegeWarDefine.STATUS.FIGHTING then return this.IsAllianceRegistered(actor), "请先报名参加活动" end return false, "活动状态异常" end return this