| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565 |
- -- 攻城战系统
- 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
|