diff --git a/src/ProtocolCode.lua b/src/ProtocolCode.lua index a037048..0b4be73 100644 --- a/src/ProtocolCode.lua +++ b/src/ProtocolCode.lua @@ -223,6 +223,10 @@ actionCodes = { Activity_exchangeRpc = 657, Activity_gachakonRpc = 658, Activity_hangDropRpc = 659, + Activity_startBattleRpc = 660, + Activity_endBattleRpc = 661, + Activity_battleRankRpc = 662, + Activity_battleMilestoneRpc = 663, Radio_startQuestRpc = 700, Radio_finishQuestRpc = 701, diff --git a/src/RedisKeys.lua b/src/RedisKeys.lua index b83d08d..064e7dd 100644 --- a/src/RedisKeys.lua +++ b/src/RedisKeys.lua @@ -15,6 +15,11 @@ R_STORE = "role:%d:store" -- 商店 R_ORDERS = "role:%d:orders" -- 订单 R_ORDER = "order:%d:%d" +-- 通用排行榜 +RANK_COMMON = "rank:common:" +RANK_TYPE = { + ActBattleBoss = "act_battle_boss", +} -- rank RANK_TOWER = "rank:tower" diff --git a/src/actions/ActivityAction.lua b/src/actions/ActivityAction.lua index 0bf4eea..5211a0d 100644 --- a/src/actions/ActivityAction.lua +++ b/src/actions/ActivityAction.lua @@ -319,7 +319,6 @@ function _M.gachakonRpc(agent, data) for i = 1, count do local tmpCfg = clone(actCfg) remain = 0 - print("-----------------, ", i) for id, cfg in pairs(tmpCfg) do local num = gachakonInfo[id] or 0 num = cfg.amount >= num and cfg.amount - num or 0 @@ -327,7 +326,7 @@ function _M.gachakonRpc(agent, data) if cfg.weight > 0 then remain = remain + num end - print("num ".. num, id, cfg.weight, cfg.amount) + --print("num ".. num, id, cfg.weight, cfg.amount) end if remain == 0 then break @@ -350,9 +349,9 @@ function _M.gachakonRpc(agent, data) role:costItems(cost, {log = {desc = "actGachakon", int1 = actid, int2 = count}}) local reward, change = role:award(award, {log = {desc = "actGachakon", int1 = actid, int2 = count}}) - if remain <= count then + --print("-----------", remain, count) + if remain <= 1 then gachakonInfo = {} - print("hahaha") end role.activity:updateActData("Gachakon", gachakonInfo) @@ -415,4 +414,316 @@ function _M.hangDropRpc(agent, data) return true end +local function getStarCount(cfg, data) + local count = 0 + for i = 0, #(cfg.sweep_condition:toTableArray(true)) do + if (1 << i & data) > 0 then + count = count + 1 + end + end + + return count +end + +function _M.startBattleRpc(agent, data) + local role = agent.role + local msg = MsgPack.unpack(data) + local actid = msg.actid + local id = msg.id + local count = msg.count + if not role.activity:isOpenById(actid) then return 1 end + role.activity:getBattleTicket(role, actid) + + local actCfg = csvdb["activity_battleCsv"][actid] + if not actCfg then return 2 end + + local battleCfg = actCfg[id] + if not battleCfg then return 3 end + + local actData = role.activity:getActData("ChallengeLevel") or {} + + local preArr = battleCfg.prepose:toArray(true, "=") + for _, v in ipairs(preArr) do + local battleInfo = actData[v] + if not battleInfo then + return 4 + end + local star = battleInfo["star"] or 0 + if star <= 0 then + return 4 + end + end + -- check cost + local changeFlag = false + local ticket = actData["ticket"] + if battleCfg.type ~= "" then + local num = battleCfg.type:toArray(true, "=")[3] + if count and count > 0 then + if battleCfg.rank == 0 then + return 7 + end + local bi = actData[id] + if not bi then return 8 end + local star = bi["star"] or 0 + if star < 1 then + return 9 + end + num = num * count + end + if ticket < num then + return 6 + end + actData["ticket"] = ticket - num + changeFlag = true + end + + if not count then + role.__actBattleCache = { + key = tostring(math.random()), + actid = actid, + id = id, + } + SendPacket(actionCodes.Activity_startBattleRpc, MsgPack.pack({key = role.__actBattleCache.key})) + else + if count <= 0 then + return + end + if battleCfg.rank == 0 then + return 7 + end + local bi = actData[id] + local star = bi["star"] + local award = battleCfg.item_clear:toNumMap() + if getStarCount(battleCfg, star) == 3 then + local aw = battleCfg.perfect_reward:toNumMap() + for k, v in pairs(aw) do + award[k] = (award[k] or 0) + v + end + end + for k, v in pairs(award) do + award[k] = v * count + end + local reward, change = role:award(award, {log = {desc = "actBattle", int1 = actid, int2 = count or 0}}) + SendPacket(actionCodes.Activity_startBattleRpc, MsgPack.pack(role:packReward(reward, change))) + + bi["sum"] = bi["sum"] + bi["top"] + actData[id] = bi + changeFlag = true + + local rankVal = 0 + if battleCfg.rank == 1 then + rankVal = bi["sum"] + elseif battleCfg.rank == 2 then + rankVal = bi["top"] + end + role:updateRankCommon(RANK_TYPE.ActBattleBoss, rankVal) + end + if changeFlag then + role.activity:updateActData("ChallengeLevel", actData) + end + + return true +end + +function _M.endBattleRpc(agent, data) + local role = agent.role + local msg = MsgPack.unpack(data) + local actid = msg.actid + local id = msg.id + local key = msg.key + local isWin = msg.isWin + local heros = msg.heros + local support = msg.support + if not role.activity:isOpenById(actid) then return 1 end + + if not role.__actBattleCache then return 2 end + + if role.__actBattleCache.id ~= id or role.__actBattleCache.key ~= key and role.__actBattleCache.actid ~= actid then + SendPacket(actionCodes.Activity_endBattleRpc, MsgPack.pack({errorCode = 1})) + end + + local actCfg = csvdb["activity_battleCsv"][actid] + if not actCfg then return 3 end + + local battleCfg = actCfg[id] + if not battleCfg then return 4 end + + local actData = role.activity:getActData("ChallengeLevel") or {} + + local reward, change = {}, nil + + local battleInfo = actData[id] or {} + local curStar = 0 + if isWin then + local herosInfo = msg.heros + + local check = {} + -- 1 通关 + check[1] = function(_) + return true + end + -- 2 阵亡人数 <= N + check[2] = function(_, cond) + return msg.info.dead and msg.info.dead <= cond + end + -- 3 全员存活 + check[3] = function(_) + return msg.info.dead and msg.info.dead == 0 + end + -- 4 指定种族 >= N + check[4] = function(_, cond) + local count = 0 + for _, one in pairs(herosInfo) do + local heroData = csvdb["unitCsv"][one.type] + if heroData.camp == cond then + count = count + 1 + end + end + return count >= cond + end + -- 5 指定职业 >= N + check[5] = function(_, cond) + local count = 0 + for _, one in pairs(herosInfo) do + local heroData = csvdb["unitCsv"][one.type] + if heroData.job == cond then + count = count + 1 + end + end + return count >= cond + end + -- 6 含有指定角色 + check[6] = function(_, cond) + for _, one in pairs(herosInfo) do + if one.type == cond then + return true + end + end + return false + end + -- 7 通关耗时 <= X 秒 msg.info.atime + check[7] = function(_, cond) + return msg.info.atime and msg.info.atime <= cond + end + curStar = 0 + local sweepConds = battleCfg.sweep_condition:toTableArray(true) + for i, cond in ipairs(sweepConds) do + if check[cond[1]] and check[cond[1]](table.unpack(cond)) then + curStar = curStar + (1 << (i - 1)) + end + end + else + curStar = 0 + end + local oldStarNum = getStarCount(battleCfg, battleInfo["star"] or 0) + local newStarNum = getStarCount(battleCfg, curStar) + if newStarNum > oldStarNum then + battleInfo["star"] = curStar + end + + if battleCfg.rank ~= 0 then + -- 更新排行榜 最高伤害 + local dmg = 0 + for k, v in pairs(msg.info.damage) do + if k % 100 == 2 then + dmg = dmg + v + end + end + battleInfo["top"] = math.max(battleInfo["top"] or 0, dmg) + battleInfo["sum"] = (battleInfo["sum"] or 0) + dmg + local rankVal = 0 + if battleCfg.rank == 1 then + rankVal = battleInfo["sum"] + elseif battleCfg.rank == 2 then + rankVal = battleInfo["top"] + end + if rankVal > 0 then + role:updateRankCommon(RANK_TYPE.ActBattleBoss, rankVal) + end + end + actData[id] = battleInfo + role.activity:updateActData("ChallengeLevel", actData) + + if oldStarNum == 0 or battleCfg.rank ~= 0 then + reward = battleCfg.item_clear:toNumMap() + end + if (oldStarNum < 3 and newStarNum == 3) or battleCfg.rank ~= 0 then + local aw = battleCfg.perfect_reward:toNumMap() + for k, v in pairs(aw) do + reward[k] = (reward[k] or 0) + v + end + end + + role:checkBattle("act_battle", { + cfg = battleCfg, + star = newStarNum, + isWin = isWin, + info = msg.info, + reward = reward, + heros = heros, + supports = support, + }) + + reward, change = role:award(reward, {log = {desc = "actBattle", int1 = actid, int2 = newStarNum}}) + + SendPacket(actionCodes.Activity_endBattleRpc, MsgPack.pack({ + reward = reward, + change = change + })) + + return true +end + +function _M.battleRankRpc(agent, data) + local role = agent.role + local msg = MsgPack.unpack(data) + local actid = msg.actid + if not role.activity:isOpenById(actid) then return 1 end + + local rankInfo = role:getRankInfoCommon(RANK_TYPE.ActBattleBoss) + + SendPacket(actionCodes.Activity_battleRankRpc, MsgPack.pack(rankInfo)) + return true +end + +function _M.battleMilestoneRpc(agent, data) + local role = agent.role + local msg = MsgPack.unpack(data) + local actid = msg.actid + local id = msg.id + local index = msg.index + + if not role.activity:isOpenById(actid) then return 1 end + + local actCfg = csvdb["activity_mileageCsv"][actid] + if not actCfg then return 3 end + + local mileCfg = actCfg[index] + if not mileCfg then return 4 end + + local actData = role.activity:getActData("ChallengeLevel") or {} + local battleInfo = actData[id] or {} + local val = 0 + if mileCfg.type == 1 then + val = battleInfo["sum"] or 0 + elseif mileCfg.type == 2 then + val = battleInfo["top"] or 0 + end + + local record = battleInfo["r"] or "" + local flag = string.char(string.getbit(record, index)) + if flag == "1" then return 5 end + if mileCfg.condition > val then return 6 end + + battleInfo["r"] = string.setbit(record, index) + actData[id] = battleInfo + role.activity:updateActData("ChallengeLevel", actData) + + local award = mileCfg.reward:toNumMap() + local reward, change = role:award(award, {log = {desc = "actMilestone", int1 = actid, int2 = index}}) + SendPacket(actionCodes.Activity_battleMilestoneRpc, MsgPack.pack(role:packReward(reward, change))) + + return true +end + return _M \ No newline at end of file diff --git a/src/actions/GmAction.lua b/src/actions/GmAction.lua index 2a507d3..34064c8 100644 --- a/src/actions/GmAction.lua +++ b/src/actions/GmAction.lua @@ -535,6 +535,7 @@ function _M.test(role, pms) --hero.unlockPoolRpc({role = role}, MsgPack.pack({type = id})) --role:sendMail(13, nil, "1=2", {111}) + dump(redisproxy:zrevrange("rank:tower", 0 , 10, "WITHSCORES")) return "成功" end diff --git a/src/actions/HangAction.lua b/src/actions/HangAction.lua index 900ff89..4237854 100644 --- a/src/actions/HangAction.lua +++ b/src/actions/HangAction.lua @@ -632,7 +632,7 @@ function _M.endBonusBattleRpc(agent, data) check[4] = function(_, cond) local count = 0 for _, one in pairs(herosInfo) do - local heroData = csv["unitCsv"][one.type] + local heroData = csvdb["unitCsv"][one.type] if heroData.camp == cond then count = count + 1 end @@ -643,7 +643,7 @@ function _M.endBonusBattleRpc(agent, data) check[5] = function(_, cond) local count = 0 for _, one in pairs(herosInfo) do - local heroData = csv["unitCsv"][one.type] + local heroData = csvdb["unitCsv"][one.type] if heroData.job == cond then count = count + 1 end diff --git a/src/csvdata b/src/csvdata index 295fead..4cafc1b 160000 --- a/src/csvdata +++ b/src/csvdata @@ -1 +1 @@ -Subproject commit 295feade86593a4793972e2cd2d83135d8aee247 +Subproject commit 4cafc1bd8425bca1270ea2d1a31586cc1b723223 diff --git a/src/models/Activity.lua b/src/models/Activity.lua index 923b498..3effef4 100644 --- a/src/models/Activity.lua +++ b/src/models/Activity.lua @@ -179,6 +179,7 @@ function Activity:checkActivityStatus(now, isCrossDay, notify) if isOpen then if actime[actId] and actime[actId] == startTime then -- 还是之前的状态 开放中 + self:onLoginActivity(actId) else -- 重置 actime[actId] = startTime self:closeActivity(actId, notify, true) @@ -484,11 +485,30 @@ activityFunc[Activity.ActivityType.HangDrop] = { end } +--ChallengeLevel +activityFunc[Activity.ActivityType.ChallengeLevel] = { + ["init"] = function(self, actType, isCrossDay, notify, actId) + self:getBattleTicket(actId) + end, + ["login"] = function(self, actType, actId) + self:getBattleTicket(actId) + end +} + +function Activity:onLoginActivity(actId) + local actData = csvdb["activity_ctrlCsv"][actId] + if not actData then return end + local actType = actData.showType + if activityFunc[actType] and activityFunc[actType]['login'] then + activityFunc[actType]["login"](self, actType, actId) + end +end + function Activity:initActivity(actId, isCrossDay, notify) local actData = csvdb["activity_ctrlCsv"][actId] if not actData then return end local actType = actData.showType - if activityFunc[actType] and activityFunc[actType]['close'] then + if activityFunc[actType] and activityFunc[actType]['init'] then activityFunc[actType]["init"](self, actType, isCrossDay, notify, actId) end end @@ -633,5 +653,39 @@ function Activity:recycleActItem(actId) end end +-- 活动挑战关卡计算门票 +function Activity:getBattleTicket(actId) + local role = self.owner + local createTs = role:getProperty("ctime") + local actCfg = csvdb["activity_ctrlCsv"][actId] + if not actCfg then return 0 end + + local actStartTime = 0 + local openTimes = actCfg.time:toArray(false, "=") + actStartTime = toUnixtime(openTimes[1]..string_format("%02x", RESET_TIME)) + local actData = self:getActData("ChallengeLevel") or {} + local startTs = actData["ts"] or math.max(actStartTime, createTs) + local timeNow = skynet.timex() + local modify = false + local arr = actCfg.condition2:toArray(true, "=") + + local ticketId, init, limit, duration = arr[1] or 0, arr[2] or 0, arr[3] or 0, arr[4] or 10000 + + local count = actData["ticket"] or init + local add = math.max(math.floor((timeNow - startTs) / (duration * 60)), 0) + + local newCount= math.min(count + add, limit) + if newCount ~= count or newCount >= limit then + modify = true + end + add = newCount - count + + if modify or not next(actData) then + actData["ticket"] = newCount + actData["ts"] = newCount >= limit and timeNow or (startTs + add * duration * 60) + self:updateActData("ChallengeLevel", actData) + end +end + return Activity diff --git a/src/models/RoleBattle.lua b/src/models/RoleBattle.lua index 60786fe..50fbe48 100644 --- a/src/models/RoleBattle.lua +++ b/src/models/RoleBattle.lua @@ -16,6 +16,7 @@ local BattleType = { bonus = 300, pvpc = 500, pvph = 501, + act_battle = 502, } RoleBattle.bind = function (Role) @@ -86,6 +87,20 @@ function Role:checkBattle(battleType, params) enemylist[#enemylist + 1] = one["unitType"] end end, + act_battle = function() + for slot, hero in pairs(self:getTeamHerosInfo(params.heros)) do + selflist[slot] = hero.type + end + heroscore = self:getTeamBattleValue(params.heros) + for slot , one in pairs(params.supports) do + teamskill[one[1]] = one[2] + end + local carbonData = params.cfg + local monsterData = csvdb[carbonData.monster:match("/([^/]*)$") .. "Csv"] + for slot, one in pairs(monsterData[1]) do + enemylist[#enemylist + 1] = one["unitType"] + end + end, pvpc = function() for slot, hero in pairs(self:getProperty("pvpTSC")) do selflist[slot] = hero.type @@ -163,7 +178,7 @@ function Role:checkBattle(battleType, params) mission_starttime = clientInfo.start or 0, -- 战斗开始时间,格式 unixtime 秒级 mission_roundtime = clientInfo.atime or 0, -- 对局时长(秒) mission_result = params.isWin and 1 or 2, -- 战斗结果(0-无效,1-胜利,2-失败) - mission_star = 0, -- 战斗完成星数,无星级的话填写0 + mission_star = params.star or 0, -- 战斗完成星数,无星级的话填写0 mission_restriction = 0, -- 周期内参与限制(0表示没有上限) mission_difficulty = 0, -- 关卡困难度,无难度区分的话填写0 mission_strength = 1, -- 消耗的体力或次数 diff --git a/src/models/RoleLog.lua b/src/models/RoleLog.lua index 9320b40..e70e730 100644 --- a/src/models/RoleLog.lua +++ b/src/models/RoleLog.lua @@ -47,6 +47,8 @@ local ItemReason = { actGachakon = 132, -- 扭蛋活动 totalRecharge = 133, -- 累计充值奖励 actHangDrop = 134, -- 掉落活动奖励 + actBattle = 135, -- 活动关卡 + actMilestone = 136, -- 活动关卡boss伤害里程碑 advHang = 301, -- 拾荒挂机 diff --git a/src/models/RolePlugin.lua b/src/models/RolePlugin.lua index dc3c578..9fafd76 100644 --- a/src/models/RolePlugin.lua +++ b/src/models/RolePlugin.lua @@ -1929,6 +1929,51 @@ function RolePlugin.bind(Role) end deleteNotify({pattern = pattern}) end + + local CommonRankTime = toUnixtime("2019010100") + function Role:updateRankCommon(rankType, rankVal, reserve) + if not rankType then return end + reserve = reserve or 0 + local now = skynet.timex() + local ct = math.ceil((now - CommonRankTime) / 86400) --按天计算 365 * 27 < 10000 可以维持 27 年 + ct = 10000 - ct -- 越早的排名越靠前 + local score = (reserve * 10000 + ct) * 10000000 + rankVal + + local roleId = self:getProperty("id") + redisproxy:pipelining(function (red) + red:zadd(RANK_COMMON..rankType, score, roleId) --更新分数 + end) + end + + function Role:getRankInfoCommon(rankType) + if not rankType then return end + local list = {} + local rankKey = RANK_COMMON .. rankType + local ids = redisproxy:zrevrange(rankKey, 0 , 99, "WITHSCORES") + for i = 1, #ids, 2 do + local roleId = tonumber(ids[i]) + local rankVal = tonumber(ids[i + 1]) + rankVal = rankVal % 10000000 + table.insert(list, {roleId = roleId, player = rankVal}) + end + + for _, v in ipairs(list) do + local _, curInfo = rpcRole(v.roleId, "friendSInfo") + curInfo.ltime = nil + curInfo.rankVal = v.player + v.player = curInfo + end + + local rank = redisproxy:ZREVRANK(rankKey, self:getProperty("id")) + if not rank then + rank = -1 + else + rank = rank + 1 + end + return {list = list, rank = rank} + end + + end return RolePlugin \ No newline at end of file diff --git a/src/services/globald.lua b/src/services/globald.lua index b299552..b841007 100644 --- a/src/services/globald.lua +++ b/src/services/globald.lua @@ -7,6 +7,7 @@ require "shared.init" require "utils.init" require "RedisKeys" require "skynet.manager" +require "GlobalVar" local ipairs = ipairs @@ -16,6 +17,7 @@ local string_format = string.format local CHECK_MAIL_STATUS_INTERVAL = 100 * 60 +local CHECK_BATTLE_ACT_CLOSE_INTERVAL = 100 * 1 local function mailQuene() local delayEmail = tonum(redisproxy:hget("autoincrement_set", "delay_email")) if delayEmail == 0 then @@ -91,6 +93,64 @@ local function check_mail_queue() skynet.timeout(CHECK_MAIL_STATUS_INTERVAL, check_mail_queue) end +-- @desc: 检测关卡活动结束 排行榜奖励发放 +local lastCheckBattleActTs = 0 +local function check_battle_act_close() + local csvdb = require "shared.csvdata" + local act = require "models.Activity" + local st = 0 + local et = 0 + local actId = 0 + local timeNow = skynet.timex() + for k, v in pairs(csvdb["activity_ctrlCsv"]) do + if v.showType == act.ActivityType.ChallengeLevel then + local openTimes = v.time:toArray(false, "=") + if openTimes[1] ~= "0" then + st = toUnixtime(openTimes[1]..string_format("%02x", RESET_TIME)) + end + if openTimes[2] ~= "0" then + et = toUnixtime(openTimes[2]..string_format("%02x", RESET_TIME)) + end + actId = k + break + end + end + if st ~= 0 and et ~= 0 and actId ~= 0 then + -- close + if lastCheckBattleActTs < et and timeNow >= et then + -- check rank key exist + local rankKey = RANK_COMMON..RANK_TYPE.ActBattleBoss + local flag = redisproxy:exists(rankKey) + if flag then + local actData = csvdb["activity_groupCsv"][actId] + local lastRank = actData[#actData].rank + + local ids = redisproxy:zrevrange(rankKey, 0 , lastRank - 1) + local rankIndex = 0 + for roleId in pairs(ids) do + rankIndex = rankIndex + 1 + for _, cfg in pairs(actData) do + if rankIndex <= cfg.rank then + redisproxy:insertEmail({ + roleId = roleId, + emailId = cfg.email_1, + attachments = cfg.reward_1, + contentPms = {rankIndex}, + }) + break + end + end + end + + redisproxy:del(rankKey..":bak") + redisproxy:rename(rankKey, rankKey..":bak") + end + end + end + lastCheckBattleActTs = skynet.timex() + skynet.timeout(CHECK_BATTLE_ACT_CLOSE_INTERVAL, check_battle_act_close) +end + local CMD = {} @@ -115,6 +175,7 @@ end function CMD.start() check_mail_queue() + check_battle_act_close() end local function __init__() -- libgit2 0.21.2