Commit 4e4082ba6a0805ace90be4e9f6621da55a8594f9

Authored by zhouhaihai
2 parents 5ed0c637 1070d7ce

Merge branch 'develop' into tr/cb

* develop:
  定向抽卡活动与ssr up活动统一开放关闭
  万能贴纸
  取消爬塔次数
  不要聊天记录缓存
  日历任务 拾荒开始任务
  资助升级等级限制放开
  日历活动bug
  特权卡bug
  增加抽卡英雄up
  限时礼包,抽卡ssr广播
  引导调整
  忽略心跳和未登录状态 超时处理
  队长技能 不失效
@@ -69,6 +69,7 @@ ItemType = { @@ -69,6 +69,7 @@ ItemType = {
69 FuncOpen = 15, -- 管理功能开放 69 FuncOpen = 15, -- 管理功能开放
70 SpeedBox = 16, -- 加速箱子 70 SpeedBox = 16, -- 加速箱子
71 SelectItemBox = 17, -- 自选箱子 71 SelectItemBox = 17, -- 自选箱子
  72 + CommonPaster = 18, -- 万能贴纸
72 } 73 }
73 74
74 --在这个里面的会记录的是功能开放 对应类型open 而不是 ID 75 --在这个里面的会记录的是功能开放 对应类型open 而不是 ID
@@ -307,9 +308,12 @@ MailId = { @@ -307,9 +308,12 @@ MailId = {
307 } 308 }
308 309
309 TriggerEventType = { 310 TriggerEventType = {
310 - HangPass = 1,  
311 - LevelUp = 2, 311 + HangPass = 1,
  312 + AdvPass = 2,
312 TowerPass = 3, 313 TowerPass = 3,
  314 + LevelUp = 4,
  315 + AddNewHero = 5,
  316 + SSRCount = 6,
313 } 317 }
314 318
315 DrawCardType = { 319 DrawCardType = {
src/ProtocolCode.lua
@@ -48,6 +48,7 @@ actionCodes = { @@ -48,6 +48,7 @@ actionCodes = {
48 Role_getDownloadCvRewardRpc = 132, 48 Role_getDownloadCvRewardRpc = 132,
49 Role_updateFeedbackInfoRpc = 133, 49 Role_updateFeedbackInfoRpc = 133,
50 Role_useSelectItemRpc = 134, -- 使用多选一礼包 50 Role_useSelectItemRpc = 134, -- 使用多选一礼包
  51 + Role_broadGetSSR = 135, -- 全服广播 获得ssr英雄
51 52
52 Adv_startAdvRpc = 151, 53 Adv_startAdvRpc = 151,
53 Adv_startHangRpc = 152, 54 Adv_startHangRpc = 152,
src/actions/HangAction.lua
@@ -26,6 +26,8 @@ local function checkReward(role) @@ -26,6 +26,8 @@ local function checkReward(role)
26 local nowCoinTime = math.min(skynet.timex(), hangInfo.endCoinTime or 0) 26 local nowCoinTime = math.min(skynet.timex(), hangInfo.endCoinTime or 0)
27 local nowItemTime = math.min(skynet.timex(), hangInfo.endItemTime or 0) 27 local nowItemTime = math.min(skynet.timex(), hangInfo.endItemTime or 0)
28 28
  29 + local expCoef, itemCoef = role.storeData:getHangDropCoef()
  30 +
29 -- 此次挂机,其中翻倍时长占多少 31 -- 此次挂机,其中翻倍时长占多少
30 local doubleTime = role.activity:getActHangDoubleTime(hangInfo.coinTime, nowCoinTime) 32 local doubleTime = role.activity:getActHangDoubleTime(hangInfo.coinTime, nowCoinTime)
31 local normalTime = nowCoinTime - hangInfo.coinTime - doubleTime 33 local normalTime = nowCoinTime - hangInfo.coinTime - doubleTime
@@ -39,7 +41,7 @@ local function checkReward(role) @@ -39,7 +41,7 @@ local function checkReward(role)
39 hangInfo.itemTime = nowItemTime 41 hangInfo.itemTime = nowItemTime
40 42
41 local items = role:getProperty("hangBag") 43 local items = role:getProperty("hangBag")
42 - coinCount = coinCount + coinDoubleCount 44 + coinCount = (coinCount + coinDoubleCount) * expCoef
43 items[ItemId.Gold] = math.floor((items[ItemId.Gold] or 0) + coinCount * expCarbonData.money) 45 items[ItemId.Gold] = math.floor((items[ItemId.Gold] or 0) + coinCount * expCarbonData.money)
44 items[ItemId.Exp] = math.floor((items[ItemId.Exp] or 0) + coinCount * expCarbonData.exp) 46 items[ItemId.Exp] = math.floor((items[ItemId.Exp] or 0) + coinCount * expCarbonData.exp)
45 items[ItemId.PlayerExp] = math.floor((items[ItemId.PlayerExp] or 0) + coinCount * expCarbonData.playerExp) 47 items[ItemId.PlayerExp] = math.floor((items[ItemId.PlayerExp] or 0) + coinCount * expCarbonData.playerExp)
@@ -75,6 +77,7 @@ local function checkReward(role) @@ -75,6 +77,7 @@ local function checkReward(role)
75 if cur[1] == ItemId.BreakCost and doubleTime > 0 then 77 if cur[1] == ItemId.BreakCost and doubleTime > 0 then
76 cur[2] = cur[2] * 2 78 cur[2] = cur[2] * 2
77 end 79 end
  80 + cur[2] = cur[2] * itemCoef
78 if (items[cur[1]] and math.ceil((items[cur[1]] + cur[2]) / globalCsv.idle_field_limit) > math.ceil(items[cur[1]] / globalCsv.idle_field_limit)) 81 if (items[cur[1]] and math.ceil((items[cur[1]] + cur[2]) / globalCsv.idle_field_limit) > math.ceil(items[cur[1]] / globalCsv.idle_field_limit))
79 or not items[cur[1]] then --要占用新栏位的情况 82 or not items[cur[1]] then --要占用新栏位的情况
80 local addFC 83 local addFC
@@ -162,16 +165,6 @@ function _M.startRpc( agent, data ) @@ -162,16 +165,6 @@ function _M.startRpc( agent, data )
162 165
163 role:updateProperty({field = "hangInfo", value = hangInfo}) 166 role:updateProperty({field = "hangInfo", value = hangInfo})
164 167
165 - -- 指定当前引导的步骤  
166 - if carbonId == 10101 then  
167 - role:saveGuide(5,11)  
168 - elseif carbonId == 10102 then  
169 - role:saveGuide(8,2)  
170 - elseif carbonId == 10103 then  
171 - role:saveGuide(9,2)  
172 - elseif carbonId == 10220 then  
173 - role:saveGuide(22,1)  
174 - end  
175 role:mylog("hang_action", {desc = "startHang", int1 = carbonId}) 168 role:mylog("hang_action", {desc = "startHang", int1 = carbonId})
176 SendPacket(actionCodes.Hang_startRpc, '') 169 SendPacket(actionCodes.Hang_startRpc, '')
177 return true 170 return true
@@ -262,12 +255,7 @@ function _M.endBattleRpc(agent, data) @@ -262,12 +255,7 @@ function _M.endBattleRpc(agent, data)
262 255
263 -- 引导 256 -- 引导
264 if carbonId == 10101 then 257 if carbonId == 10101 then
265 - role:finishGuide(5)  
266 - elseif carbonId == 10102 then  
267 - role:finishGuide(8)  
268 - role:saveGuide(9, 2)  
269 - elseif carbonId == 10103 then  
270 - role:finishGuide(9) 258 + role:finishGuide(6)
271 elseif carbonId == 20101 then 259 elseif carbonId == 20101 then
272 role:finishGuide(22) 260 role:finishGuide(22)
273 end 261 end
@@ -341,7 +329,7 @@ function _M.roleFormatRpc(agent , data) @@ -341,7 +329,7 @@ function _M.roleFormatRpc(agent , data)
341 hangTeam.leader = msg.leader 329 hangTeam.leader = msg.leader
342 hangTeam.supports = supports 330 hangTeam.supports = supports
343 role:saveHangTeam(hangTeam) 331 role:saveHangTeam(hangTeam)
344 - role:saveGuide(5,8) 332 + role:finishGuide(5)
345 SendPacket(actionCodes.Hang_roleFormatRpc, '') 333 SendPacket(actionCodes.Hang_roleFormatRpc, '')
346 return true 334 return true
347 end 335 end
@@ -500,8 +488,9 @@ function _M.buyBonusCountRpc(agent, data) @@ -500,8 +488,9 @@ function _M.buyBonusCountRpc(agent, data)
500 end 488 end
501 489
502 local bonusC = role.dailyData:getProperty("bonusC") 490 local bonusC = role.dailyData:getProperty("bonusC")
  491 + local extraCnt = role.storeData:getBonusExtraFightCount()
503 bonusC[btype] = bonusC[btype] or {c = 0, b = 0} 492 bonusC[btype] = bonusC[btype] or {c = 0, b = 0}
504 - local lastCount = globalCsv.bonus_daily_buy_count * coef - bonusC[btype]["b"] 493 + local lastCount = globalCsv.bonus_daily_buy_count * coef + extraCnt - bonusC[btype]["b"]
505 if math.illegalNum(count, 1, lastCount) then return 1 end 494 if math.illegalNum(count, 1, lastCount) then return 1 end
506 495
507 if not role:checkItemEnough({[ItemId.Diamond] = globalCsv.bonus_buy_cost * count}) then return 2 end 496 if not role:checkItemEnough({[ItemId.Diamond] = globalCsv.bonus_buy_cost * count}) then return 2 end
@@ -541,12 +530,13 @@ function _M.startBonusBattleRpc(agent, data) @@ -541,12 +530,13 @@ function _M.startBonusBattleRpc(agent, data)
541 530
542 local actData = csvdb["activity_ctrlCsv"][actId] 531 local actData = csvdb["activity_ctrlCsv"][actId]
543 532
  533 + local extraCnt = role.storeData:getBonusExtraFightCount()
544 local coef = 1 534 local coef = 1
545 if open and actData then 535 if open and actData then
546 coef = tonumber(actData.condition2) 536 coef = tonumber(actData.condition2)
547 end 537 end
548 538
549 - if globalCsv.bonus_daily_count * coef - bonusC[bonusData.type]["c"] <= 0 then return 7 end 539 + if globalCsv.bonus_daily_count * coef + extraCnt - bonusC[bonusData.type]["c"] <= 0 then return 7 end
550 540
551 541
552 role.__bonusBattleCache = { 542 role.__bonusBattleCache = {
@@ -566,6 +556,7 @@ function _M.endBonusBattleRpc(agent, data) @@ -566,6 +556,7 @@ function _M.endBonusBattleRpc(agent, data)
566 if not role.__bonusBattleCache then return 1 end 556 if not role.__bonusBattleCache then return 1 end
567 local open, actId = role.activity:isOpen("BonusDouble") 557 local open, actId = role.activity:isOpen("BonusDouble")
568 local actData = csvdb["activity_ctrlCsv"][actId] 558 local actData = csvdb["activity_ctrlCsv"][actId]
  559 + local extraCnt = role.storeData:getBonusExtraFightCount()
569 560
570 local coef = 1 561 local coef = 1
571 if open and actData then 562 if open and actData then
@@ -583,7 +574,7 @@ function _M.endBonusBattleRpc(agent, data) @@ -583,7 +574,7 @@ function _M.endBonusBattleRpc(agent, data)
583 -- 胜利扣除次数 574 -- 胜利扣除次数
584 local bonusC = role.dailyData:getProperty("bonusC") 575 local bonusC = role.dailyData:getProperty("bonusC")
585 bonusC[bonusData.type] = bonusC[bonusData.type] or {c = 0, b = 0} 576 bonusC[bonusData.type] = bonusC[bonusData.type] or {c = 0, b = 0}
586 - if globalCsv.bonus_daily_count * coef - bonusC[bonusData.type]["c"] <= 0 then return 3 end 577 + if globalCsv.bonus_daily_count * coef + extraCnt - bonusC[bonusData.type]["c"] <= 0 then return 3 end
587 bonusC[bonusData.type]["c"] = bonusC[bonusData.type]["c"] + 1 578 bonusC[bonusData.type]["c"] = bonusC[bonusData.type]["c"] + 1
588 role.dailyData:updateProperty({field = "bonusC", value = bonusC}) 579 role.dailyData:updateProperty({field = "bonusC", value = bonusC})
589 580
src/actions/HeroAction.lua
@@ -54,9 +54,6 @@ function _M.levelUpRpc( agent, data ) @@ -54,9 +54,6 @@ function _M.levelUpRpc( agent, data )
54 hero_upgrade_scoreget = hero:getProperty("battleV") - oldBattleV, -- 通过英雄升级提升的评分 54 hero_upgrade_scoreget = hero:getProperty("battleV") - oldBattleV, -- 通过英雄升级提升的评分
55 }) 55 })
56 56
57 - if hero:getProperty("type") == 103 then  
58 - role:finishGuide(7)  
59 - end  
60 hero:mylog({desc = "levelUp", int1 = hero:getProperty("level")}) 57 hero:mylog({desc = "levelUp", int1 = hero:getProperty("level")})
61 58
62 role:checkTaskEnter("HeroLevelUp", {level = hero:getProperty("level")}) 59 role:checkTaskEnter("HeroLevelUp", {level = hero:getProperty("level")})
@@ -129,6 +126,10 @@ function _M.wakeRpc(agent, data) @@ -129,6 +126,10 @@ function _M.wakeRpc(agent, data)
129 hero_rise_result = getChangeAttrJson(oldAttr, hero:getTotalAttrs()), --英雄觉醒效果,可记录效果ID,或json格式记录提升效果,{攻击:20,闪避:20,……..} 126 hero_rise_result = getChangeAttrJson(oldAttr, hero:getTotalAttrs()), --英雄觉醒效果,可记录效果ID,或json格式记录提升效果,{攻击:20,闪避:20,……..}
130 }) 127 })
131 128
  129 + if hero:getProperty("type") == 204 then
  130 + role:finishGuide(7)
  131 + end
  132 +
132 SendPacket(actionCodes.Hero_wakeRpc, '') 133 SendPacket(actionCodes.Hero_wakeRpc, '')
133 134
134 role:checkTaskEnter("HeroStarCollect", {}) 135 role:checkTaskEnter("HeroStarCollect", {})
@@ -737,7 +738,7 @@ function _M.drawHeroRpc(agent, data) @@ -737,7 +738,7 @@ function _M.drawHeroRpc(agent, data)
737 738
738 if btype == 1 then 739 if btype == 1 then
739 -- 判断定向卡池活动开启 740 -- 判断定向卡池活动开启
740 - if not role.activity:isOpen("RaceDraw") then 741 + if not role.activity:isOpen("SsrUpPoolChange") then
741 return 742 return
742 end 743 end
743 end 744 end
@@ -819,26 +820,44 @@ function _M.drawHeroRpc(agent, data) @@ -819,26 +820,44 @@ function _M.drawHeroRpc(agent, data)
819 end 820 end
820 end 821 end
821 822
822 - for itemId, oneData in pairs(isFloorBack and csvdb["build_floorCsv"] or csvdb["build_poolCsv"]) do  
823 - local pool_str = "pool_" .. poolId  
824 - if oneData[pool_str] and oneData[pool_str] ~= "" then  
825 - local itemData = csvdb["itemCsv"][itemId]  
826 - while itemData do  
827 - if itemData.type ~= ItemType.Hero then break end  
828 - local heroData = csvdb["unitCsv"][itemData.id - ItemStartId.Hero]  
829 - if not heroData then break end  
830 - local ok = true  
831 - -- 保底是全随机,不用比较类型  
832 - if not isFloorBack then  
833 - for idx, field in ipairs(condition) do  
834 - if heroData[field] ~= values[idx] then ok = false break end 823 + local weight = 0
  824 + local up_pool = nil
  825 + local rand_v = math.randomInt(1, 100)
  826 + if values[1] == HeroQuality.SR then
  827 + weight = unitPool["up_sr_weight"]
  828 + up_pool = unitPool["up_sr_id"]
  829 + elseif values[1] == HeroQuality.SSR then
  830 + weight = unitPool["up_ssr_weight"]
  831 + up_pool = unitPool["up_ssr_id"]
  832 + end
  833 + --print(poolId, rand_v, weight, up_pool, values[1])
  834 + if rand_v < weight and up_pool then
  835 + up_pool = up_pool:toArray(true, "=")
  836 + for k, v in ipairs(up_pool) do
  837 + resultPool[v] = {1}
  838 + end
  839 + else
  840 + for itemId, oneData in pairs(isFloorBack and csvdb["build_floorCsv"] or csvdb["build_poolCsv"]) do
  841 + local pool_str = "pool_" .. poolId
  842 + if oneData[pool_str] and oneData[pool_str] ~= "" then
  843 + local itemData = csvdb["itemCsv"][itemId]
  844 + while itemData do
  845 + if itemData.type ~= ItemType.Hero then break end
  846 + local heroData = csvdb["unitCsv"][itemData.id - ItemStartId.Hero]
  847 + if not heroData then break end
  848 + local ok = true
  849 + -- 保底是全随机,不用比较类型
  850 + if not isFloorBack then
  851 + for idx, field in ipairs(condition) do
  852 + if heroData[field] ~= values[idx] then ok = false break end
  853 + end
835 end 854 end
  855 + if not ok then break end
  856 + if oneData[pool_str] > 0 then
  857 + resultPool[itemId] = {oneData[pool_str]} -- itemId, count, 概率
  858 + end
  859 + break
836 end 860 end
837 - if not ok then break end  
838 - if oneData[pool_str] > 0 then  
839 - resultPool[itemId] = {oneData[pool_str]} -- itemId, count, 概率  
840 - end  
841 - break  
842 end 861 end
843 end 862 end
844 end 863 end
@@ -846,9 +865,9 @@ function _M.drawHeroRpc(agent, data) @@ -846,9 +865,9 @@ function _M.drawHeroRpc(agent, data)
846 865
847 role:costItems(cost, {log = {desc = "drawHero", int1 = btype, int2 = poolId}}) 866 role:costItems(cost, {log = {desc = "drawHero", int1 = btype, int2 = poolId}})
848 867
849 - local guideHero  
850 - if role:getProperty("newerGuide") == "11=1" then  
851 - guideHero = globalCsv.newdraw_hero_item_id or 613 868 + local guideHero = nil
  869 + if role:getProperty("newerGuide") == "8=1" then
  870 + guideHero = globalCsv.newdraw_hero_item_id or 503
852 end 871 end
853 872
854 local ssrCount = 0 873 local ssrCount = 0
@@ -867,12 +886,16 @@ function _M.drawHeroRpc(agent, data) @@ -867,12 +886,16 @@ function _M.drawHeroRpc(agent, data)
867 local itemId = math.randWeight(resultPool, 1) 886 local itemId = math.randWeight(resultPool, 1)
868 if guideHero then 887 if guideHero then
869 itemId = guideHero 888 itemId = guideHero
870 - guideHero = nil  
871 end 889 end
872 890
873 local itemData = csvdb["itemCsv"][itemId] 891 local itemData = csvdb["itemCsv"][itemId]
874 if itemData.quality == HeroQuality.SSR then 892 if itemData.quality == HeroQuality.SSR then
875 ssrCount = ssrCount + 1 893 ssrCount = ssrCount + 1
  894 + if not guideHero then
  895 + -- 广播获得ssr英雄
  896 + local ntf = {heroId = itemData.id - ItemStartId.Hero, nick = role:getProperty("name")}
  897 + mcast_util.pub_world(actionCodes.Role_broadGetSSR, MsgPack.pack(ntf))
  898 + end
876 end 899 end
877 900
878 if itemData.quality >= HeroQuality.SR then 901 if itemData.quality >= HeroQuality.SR then
@@ -903,7 +926,7 @@ function _M.drawHeroRpc(agent, data) @@ -903,7 +926,7 @@ function _M.drawHeroRpc(agent, data)
903 if ssrCount > 0 then 926 if ssrCount > 0 then
904 role:checkTaskEnter("DrawSSR", {count = ssrCount}) 927 role:checkTaskEnter("DrawSSR", {count = ssrCount})
905 end 928 end
906 - role:finishGuide(11) 929 + role:finishGuide(8)
907 930
908 role:log("gacha", { 931 role:log("gacha", {
909 gacha_id = poolId, -- 卡池ID 932 gacha_id = poolId, -- 卡池ID
@@ -1023,4 +1046,4 @@ function _M.changeCrown(agent, data) @@ -1023,4 +1046,4 @@ function _M.changeCrown(agent, data)
1023 return true 1046 return true
1024 end 1047 end
1025 1048
1026 -return _M  
1027 \ No newline at end of file 1049 \ No newline at end of file
  1050 +return _M
src/actions/RoleAction.lua
@@ -264,7 +264,8 @@ function _M.loginRpc( agent, data ) @@ -264,7 +264,8 @@ function _M.loginRpc( agent, data )
264 264
265 -- 发下缓存的世界消息 265 -- 发下缓存的世界消息
266 local worldChatResponse = {worldChats = {}} 266 local worldChatResponse = {worldChats = {}}
267 - local ok, msgs = pcall(skynet.call, '.globald', "lua", "getWorldMsg", role._channelIdx) 267 + -- local ok, msgs = pcall(skynet.call, '.globald', "lua", "getWorldMsg", role._channelIdx)
  268 + local ok, msgs = true, {}
268 if not ok then 269 if not ok then
269 msgs = {} 270 msgs = {}
270 end 271 end
@@ -945,7 +946,7 @@ function _M.chatRpc(agent, data) @@ -945,7 +946,7 @@ function _M.chatRpc(agent, data)
945 end 946 end
946 end 947 end
947 mcast_util.pub_world(actionCodes.Role_chat, MsgPack.pack(response)) 948 mcast_util.pub_world(actionCodes.Role_chat, MsgPack.pack(response))
948 - pcall(skynet.send, '.globald', "lua", "sendWorldMsg", role._channelIdx, response) 949 + -- pcall(skynet.send, '.globald', "lua", "sendWorldMsg", role._channelIdx, response)
949 role:mylog("role_action", {desc = "chatWorld", text1 = content}) 950 role:mylog("role_action", {desc = "chatWorld", text1 = content})
950 end, 951 end,
951 -- 私聊 952 -- 私聊
@@ -1235,7 +1236,7 @@ function _M.useSelectItemRpc(agent, data) @@ -1235,7 +1236,7 @@ function _M.useSelectItemRpc(agent, data)
1235 local count = msg.count 1236 local count = msg.count
1236 if math.illegalNum(count, 1, role:getItemCount(itemId)) then return end 1237 if math.illegalNum(count, 1, role:getItemCount(itemId)) then return end
1237 local itemData = csvdb["itemCsv"][itemId] 1238 local itemData = csvdb["itemCsv"][itemId]
1238 - if itemData.type ~= ItemType.SelectItemBox then return end 1239 + if not (itemData.type == ItemType.SelectItemBox or itemData.type == ItemType.CommonPaster) then return end
1239 local itemMap = itemData.use_effect:toNumMap() 1240 local itemMap = itemData.use_effect:toNumMap()
1240 local reward, change = {} 1241 local reward, change = {}
1241 for k, v in pairs(itemMap) do 1242 for k, v in pairs(itemMap) do
src/actions/TowerAction.lua
@@ -62,7 +62,7 @@ function _M.startBattleRpc(agent, data) @@ -62,7 +62,7 @@ function _M.startBattleRpc(agent, data)
62 62
63 if not csvdb["tower_battleCsv"][id] then return end 63 if not csvdb["tower_battleCsv"][id] then return end
64 local curCount, nextTime = getUpdateTime(towerInfo.c, towerInfo.t) 64 local curCount, nextTime = getUpdateTime(towerInfo.c, towerInfo.t)
65 - if curCount < 1 then return end -- 没有次数返回 65 + --if curCount < 1 then return end -- 没有次数返回
66 66
67 --搞起来 67 --搞起来
68 towerInfo.c = curCount - 1 68 towerInfo.c = curCount - 1
@@ -136,10 +136,15 @@ end @@ -136,10 +136,15 @@ end
136 136
137 function _M.bugCountRpc(agent, data) 137 function _M.bugCountRpc(agent, data)
138 local role = agent.role 138 local role = agent.role
  139 + local msg = MsgPack.unpack(data)
  140 + local buyCount = msg.count
139 141
140 local towerInfo = role:getProperty("towerInfo") 142 local towerInfo = role:getProperty("towerInfo")
141 local curCount, nextTime = getUpdateTime(towerInfo.c, towerInfo.t) 143 local curCount, nextTime = getUpdateTime(towerInfo.c, towerInfo.t)
142 local needCount = globalCsv.tower_count_limit - curCount 144 local needCount = globalCsv.tower_count_limit - curCount
  145 + if needCount > buyCount then
  146 + needCount = buyCount
  147 + end
143 if needCount > 0 then -- 补充 148 if needCount > 0 then -- 补充
144 local cost = globalCsv.tower_chance_item:toNumMap() 149 local cost = globalCsv.tower_chance_item:toNumMap()
145 for k , v in pairs(cost) do 150 for k , v in pairs(cost) do
@@ -147,7 +152,7 @@ function _M.bugCountRpc(agent, data) @@ -147,7 +152,7 @@ function _M.bugCountRpc(agent, data)
147 end 152 end
148 if not role:checkItemEnough(cost) then return end 153 if not role:checkItemEnough(cost) then return end
149 role:costItems(cost, {log = {desc = "towerCount"}}) 154 role:costItems(cost, {log = {desc = "towerCount"}})
150 - curCount = globalCsv.tower_count_limit 155 + curCount = curCount + needCount
151 end 156 end
152 towerInfo.c = curCount 157 towerInfo.c = curCount
153 towerInfo.t = nextTime 158 towerInfo.t = nextTime
src/adv/AdvPlayer.lua
@@ -670,7 +670,7 @@ function Player:effectBattleBuff() @@ -670,7 +670,7 @@ function Player:effectBattleBuff()
670 for _, buff in ipairs(self.buffs) do 670 for _, buff in ipairs(self.buffs) do
671 if not buff:isHide() and (buff:getType() == Buff.BATTLE_BUFF or buff:getType() == Buff.BATTLE_PASSIVE) then 671 if not buff:isHide() and (buff:getType() == Buff.BATTLE_BUFF or buff:getType() == Buff.BATTLE_PASSIVE) then
672 buff:effect() 672 buff:effect()
673 - if not buff.buffData.classify:sismember(7, " ") then -- 神器buff 不会清除 673 + if not buff.buffData.classify:sismember(7, " ") and not buff.buffData.classify:sismember(8, " ") then -- 神器buff 不会清除 队长技
674 buff:uncover() 674 buff:uncover()
675 end 675 end
676 end 676 end
@@ -29,12 +29,6 @@ _codeSession = {} @@ -29,12 +29,6 @@ _codeSession = {}
29 --- {{{ 定时器相关 29 --- {{{ 定时器相关
30 local function handle_timeout() 30 local function handle_timeout()
31 if not agentInfo.open_timer then return end 31 if not agentInfo.open_timer then return end
32 -  
33 - if not agentInfo.role then  
34 - skynet.timeout(100, handle_timeout)  
35 - return  
36 - end  
37 -  
38 agent_util:update(agentInfo) 32 agent_util:update(agentInfo)
39 skynet.timeout(100, handle_timeout) 33 skynet.timeout(100, handle_timeout)
40 end 34 end
@@ -274,6 +268,8 @@ function CMD.start(session, source, gate, fd, ip, hotfixs) @@ -274,6 +268,8 @@ function CMD.start(session, source, gate, fd, ip, hotfixs)
274 end 268 end
275 end 269 end
276 270
  271 + start_agent_timer()
  272 +
277 -- 这里将消息伪装成 watchdog 发出,这样就由 A->B->C->B->A 变成 A->B->C->A 273 -- 这里将消息伪装成 watchdog 发出,这样就由 A->B->C->B->A 变成 A->B->C->A
278 skynet.redirect(gate, source, "lua", session, skynet.pack("forward", fd, 0, skynet.self())) 274 skynet.redirect(gate, source, "lua", session, skynet.pack("forward", fd, 0, skynet.self()))
279 end 275 end
1 -Subproject commit 29d26c6e3083676ddaa828f8d0b22cd1d0ee48cf 1 +Subproject commit e97f773db5d87e95086840cf48cd01b17ec8fc27
src/models/Activity.lua
@@ -18,7 +18,7 @@ Activity.ActivityType = { @@ -18,7 +18,7 @@ Activity.ActivityType = {
18 DrawHero = 12, --抽卡周 招募 18 DrawHero = 12, --抽卡周 招募
19 AdvDraw = 13, --拾荒抽周 资助 19 AdvDraw = 13, --拾荒抽周 资助
20 OpenBox = 14, --拆解周 时钟箱 20 OpenBox = 14, --拆解周 时钟箱
21 - RaceDraw = 15, -- 定向招募活动 21 + --RaceDraw = 15, -- 定向招募活动
22 } 22 }
23 23
24 24
src/models/Hero.lua
@@ -109,4 +109,8 @@ function Hero:getCamp() @@ -109,4 +109,8 @@ function Hero:getCamp()
109 return csvdb["unitCsv"][self:getProperty("type")].camp 109 return csvdb["unitCsv"][self:getProperty("type")].camp
110 end 110 end
111 111
  112 +function Hero:getRare()
  113 + return csvdb["unitCsv"][self:getProperty("type")].rare
  114 +end
  115 +
112 return Hero 116 return Hero
113 \ No newline at end of file 117 \ No newline at end of file
src/models/RolePlugin.lua
@@ -452,7 +452,11 @@ function RolePlugin.bind(Role) @@ -452,7 +452,11 @@ function RolePlugin.bind(Role)
452 newHero.owner = self 452 newHero.owner = self
453 newHero:saveBattleValue() 453 newHero:saveBattleValue()
454 self.heros[heroId] = newHero 454 self.heros[heroId] = newHero
455 - self:checkTaskEnter("AddHero", {heroType = heroType, wakeL = newHero:getProperty("wakeL"), camp = unitData.camp, job = unitData.job}, params.notNotify) 455 + local ssrCount = 0
  456 + if unitData.rare == HeroQuality.SSR then
  457 + ssrCount = self:getSSRHeroCount()
  458 + end
  459 + self:checkTaskEnter("AddHero", {heroType = heroType, wakeL = newHero:getProperty("wakeL"), camp = unitData.camp, job = unitData.job, ssrCount = ssrCount}, params.notNotify)
456 self:checkTaskEnter("HeroQualityCollect", {}) 460 self:checkTaskEnter("HeroQualityCollect", {})
457 if not params.notNotify then 461 if not params.notNotify then
458 local heroResponse = {} 462 local heroResponse = {}
@@ -486,6 +490,16 @@ function RolePlugin.bind(Role) @@ -486,6 +490,16 @@ function RolePlugin.bind(Role)
486 end 490 end
487 end 491 end
488 492
  493 + function Role:getSSRHeroCount()
  494 + local count = 0
  495 + for _, hero in pairs(self.heros) do
  496 + if hero:getRare() == HeroQuality.SSR then
  497 + count = count + 1
  498 + end
  499 + end
  500 + return count
  501 + end
  502 +
489 503
490 function Role:loadHeros() 504 function Role:loadHeros()
491 local roleId = self:getProperty("id") 505 local roleId = self:getProperty("id")
@@ -1182,7 +1196,8 @@ function RolePlugin.bind(Role) @@ -1182,7 +1196,8 @@ function RolePlugin.bind(Role)
1182 end 1196 end
1183 1197
1184 while newExp >= csvdb["adv_level_fundCsv"][level].exp do 1198 while newExp >= csvdb["adv_level_fundCsv"][level].exp do
1185 - if csvdb["adv_level_fundCsv"][level + 1] and self:advChapterIsOpen(100 + csvdb["adv_level_fundCsv"][level + 1].chapter) then -- 有下一级 1199 + --if csvdb["adv_level_fundCsv"][level + 1] and self:advChapterIsOpen(100 + csvdb["adv_level_fundCsv"][level + 1].chapter) then -- 有下一级
  1200 + if csvdb["adv_level_fundCsv"][level + 1] then -- 有下一级
1186 newExp = newExp - csvdb["adv_level_fundCsv"][level].exp 1201 newExp = newExp - csvdb["adv_level_fundCsv"][level].exp
1187 level = level + 1 1202 level = level + 1
1188 else 1203 else
src/models/RoleTask.lua
@@ -235,6 +235,8 @@ local StoreListener = { @@ -235,6 +235,8 @@ local StoreListener = {
235 [TaskType.HangPass] = {{TriggerEventType.HangPass, f("id")}}, 235 [TaskType.HangPass] = {{TriggerEventType.HangPass, f("id")}},
236 [TaskType.RoleLevelUp] = {{TriggerEventType.LevelUp, f("level")}}, 236 [TaskType.RoleLevelUp] = {{TriggerEventType.LevelUp, f("level")}},
237 [TaskType.TowerPass] = {{TriggerEventType.TowerPass, f("level")}}, 237 [TaskType.TowerPass] = {{TriggerEventType.TowerPass, f("level")}},
  238 + [TaskType.AdvPass] = {{TriggerEventType.AdvPass, f("id")}},
  239 + [TaskType.AddHero] = {{TriggerEventType.AddNewHero, f("heroType")}, {TriggerEventType.SSRCount, f("ssrCount")}},
238 } 240 }
239 } 241 }
240 242
@@ -243,7 +245,7 @@ local CalendaTaskListener = { @@ -243,7 +245,7 @@ local CalendaTaskListener = {
243 listen = { 245 listen = {
244 [TaskType.DrawHero] = {{1, 1, f("count")}}, 246 [TaskType.DrawHero] = {{1, 1, f("count")}},
245 [TaskType.BonusPass]= {{2, 1}}, 247 [TaskType.BonusPass]= {{2, 1}},
246 - [TaskType.AdvPass]= {{3, 1}}, 248 + [TaskType.AdvStart]= {{3, 1}},
247 [TaskType.DinerLevelUp]= {{4, 2, f("level")}}, 249 [TaskType.DinerLevelUp]= {{4, 2, f("level")}},
248 [TaskType.HeroLvlCollect]= {{5, 3}}, -- x名y级英雄 250 [TaskType.HeroLvlCollect]= {{5, 3}}, -- x名y级英雄
249 [TaskType.AdvHang]= {{6, 1}}, ---- 251 [TaskType.AdvHang]= {{6, 1}}, ----
@@ -580,10 +582,12 @@ function RoleTask.bind(Role) @@ -580,10 +582,12 @@ function RoleTask.bind(Role)
580 end 582 end
581 583
582 function Role:checkActivityTask(notNotify, activityType, ...) 584 function Role:checkActivityTask(notNotify, activityType, ...)
  585 + if not self.activity then return end
583 self.activity:checkActivity(notNotify, activityType, ...) 586 self.activity:checkActivity(notNotify, activityType, ...)
584 end 587 end
585 588
586 function Role:checkStoreTask(notNotify, triggerType, param) 589 function Role:checkStoreTask(notNotify, triggerType, param)
  590 + if not self.storeData then return end
587 self.storeData:OnTriggerLimitTimePack(triggerType, param) 591 self.storeData:OnTriggerLimitTimePack(triggerType, param)
588 end 592 end
589 593
@@ -629,7 +633,7 @@ function RoleTask.bind(Role) @@ -629,7 +633,7 @@ function RoleTask.bind(Role)
629 count = count + 1 633 count = count + 1
630 end 634 end
631 end 635 end
632 - if calTask[id] < count then 636 + if (calTask[id] or 0) < count then
633 calTask[id] = count 637 calTask[id] = count
634 end 638 end
635 elseif cfg.type == 16 then -- 英雄星级收集进度 639 elseif cfg.type == 16 then -- 英雄星级收集进度
@@ -639,7 +643,7 @@ function RoleTask.bind(Role) @@ -639,7 +643,7 @@ function RoleTask.bind(Role)
639 count = count + 1 643 count = count + 1
640 end 644 end
641 end 645 end
642 - if calTask[id] < count then 646 + if (calTask[id] or 0) < count then
643 calTask[id] = count 647 calTask[id] = count
644 end 648 end
645 elseif cfg.type == 18 then -- 挂机累计收获id,y个 649 elseif cfg.type == 18 then -- 挂机累计收获id,y个
src/models/Store.lua
@@ -23,11 +23,11 @@ Store.schema = { @@ -23,11 +23,11 @@ Store.schema = {
23 battleFR = {"string", ""}, -- 免费赛季卡领取记录 23 battleFR = {"string", ""}, -- 免费赛季卡领取记录
24 battleLR = {"string", ""}, -- 付费赛季卡领取记录 24 battleLR = {"string", ""}, -- 付费赛季卡领取记录
25 25
26 - limitTPack = {"table", {}}, -- 限时礼包 {id=expire_ts} 26 + limitTPack = {"table", {}}, -- 限时礼包 {id={expire_ts, trigger_type}}
27 privCardEx = {"number", 0}, -- 特权卡过期时间戳 27 privCardEx = {"number", 0}, -- 特权卡过期时间戳
28 getMailT1 = {"number",0}, -- 上次发送月卡福利邮件的时间 28 getMailT1 = {"number",0}, -- 上次发送月卡福利邮件的时间
29 getMailT2 = {"number",0}, -- 上次发送超级月卡福利邮件的时间 29 getMailT2 = {"number",0}, -- 上次发送超级月卡福利邮件的时间
30 - packTrigger = {"table", {}}, -- 礼包触发记录 {关卡难度1={id, 通关关卡数,升级数,爬塔层数}, ...} 30 + --packTrigger = {"table", {}}, -- 礼包触发记录 {关卡难度1={id, 通关关卡数,升级数,爬塔层数}, ...}
31 31
32 -- 活动商品购买记录 32 -- 活动商品购买记录
33 actGoodsFlag = {"table", {}}, -- ActGoodsType 1购买,0未购买 33 actGoodsFlag = {"table", {}}, -- ActGoodsType 1购买,0未购买
@@ -65,10 +65,11 @@ function Store:deleteExpireLimitGoods() @@ -65,10 +65,11 @@ function Store:deleteExpireLimitGoods()
65 local timeNow = skynet.timex() 65 local timeNow = skynet.timex()
66 local limitGoodsList = self:getProperty("limitTPack") 66 local limitGoodsList = self:getProperty("limitTPack")
67 for k, v in pairs(limitGoodsList) do 67 for k, v in pairs(limitGoodsList) do
68 - if timeNow > v then 68 + if timeNow > v[1] then
69 limitGoodsList[k] = nil 69 limitGoodsList[k] = nil
70 end 70 end
71 end 71 end
  72 + self:updateProperty({field = "limitTPack", value = limitGoodsList, notNotify = true})
72 end 73 end
73 74
74 -- 发送月卡邮件 75 -- 发送月卡邮件
@@ -162,6 +163,26 @@ function Store:getGearExchangeCoef() @@ -162,6 +163,26 @@ function Store:getGearExchangeCoef()
162 return 1 + coef 163 return 1 + coef
163 end 164 end
164 165
  166 +-- 奖励关卡 特权卡额外数量
  167 +function Store:getBonusExtraFightCount()
  168 + if self:isPrivCardExpire() then
  169 + return 0
  170 + end
  171 +
  172 + local cnt = globalCsv.bonus_extra_fight_count or 1
  173 + return cnt
  174 +end
  175 +
  176 +-- 挂机道具掉落系数 特权卡挂机掉落系数
  177 +function Store:getHangDropCoef()
  178 + if self:isPrivCardExpire() then
  179 + return 1, 1
  180 + end
  181 +
  182 + return (1 + globalCsv.hang_drop_exp_coef) or 1, (1 + globalCsv.hang_drop_item_coef) or 1
  183 +end
  184 +
  185 +
165 -- 购买通行证 186 -- 购买通行证
166 function Store:onBuyCard(type, duration, id) 187 function Store:onBuyCard(type, duration, id)
167 local timeNow = skynet.timex() 188 local timeNow = skynet.timex()
@@ -292,64 +313,52 @@ end @@ -292,64 +313,52 @@ end
292 --触发限时礼包 313 --触发限时礼包
293 function Store:OnTriggerLimitTimePack(eventType, param) 314 function Store:OnTriggerLimitTimePack(eventType, param)
294 local limitPack = self:getProperty("limitTPack") 315 local limitPack = self:getProperty("limitTPack")
295 - local payRecord = self:getProperty("payR") 316 + --local payRecord = self:getProperty("payR")
296 local timeNow = skynet.timex() 317 local timeNow = skynet.timex()
297 - local find = false 318 + --local find = false
298 -- 有未过期的限时礼包不再推送 319 -- 有未过期的限时礼包不再推送
299 - for k, v in pairs(limitPack) do  
300 - if v > timeNow and not payRecord[k] then  
301 - find = true  
302 - break  
303 - end  
304 - end  
305 - if find == true then  
306 - return  
307 - end  
308 - limitPack = {}  
309 - local hangPass = self.owner:getProperty("hangPass")  
310 - local triggerRecord = self:getProperty("packTrigger")  
311 - local result = {}  
312 - local maxDiff = 0 320 + --for k, v in pairs(limitPack) do
  321 + -- if v > timeNow and not payRecord[k] then
  322 + -- find = true
  323 + -- break
  324 + -- end
  325 + --end
  326 + --if find == true then
  327 + -- return
  328 + --end
  329 + --local hangPass = self.owner:getProperty("hangPass")
  330 + --local triggerRecord = self:getProperty("packTrigger")
  331 + --local result = {}
  332 + --local maxDiff = 0
313 -- 取满足限时礼包关卡要求的对应数据 333 -- 取满足限时礼包关卡要求的对应数据
314 - for diff, maxCarbonId in pairs(hangPass) do  
315 - for id, cfg in pairs(csvdb["shop_packCsv"]) do  
316 - local range = cfg.showRange:toArray(true, "=")  
317 - local beginRange = range[1] or 0  
318 - local endRange = range[2] or 0  
319 - if maxCarbonId > beginRange and maxCarbonId <= endRange and cfg.type == eventType then  
320 - result[diff] = cfg  
321 - maxDiff = math.max(maxDiff, diff)  
322 - break  
323 - end  
324 - end  
325 - end  
326 - local shopGoodsId = 0  
327 - for diff, cfg in pairs(result) do  
328 - if diff == maxDiff then  
329 - local record = triggerRecord[diff] or {}  
330 - if (record[0] or 0) ~= cfg.id and next(record) then  
331 - record = {}  
332 - end  
333 - record[0] = cfg.id  
334 - record[eventType] = (record[eventType] or 0) + 1  
335 - if record[eventType] > 0 and record[eventType] % 10 == 0 then  
336 - local pool = cfg.packId:toArray(true, "=")  
337 - local idx = math.random(1, #pool)  
338 - shopGoodsId = pool[idx]  
339 - end  
340 - triggerRecord[diff] = record 334 + --for diff, maxCarbonId in pairs(hangPass) do
  335 + -- for id, cfg in pairs(csvdb["shop_packCsv"]) do
  336 + -- local range = cfg.showRange:toArray(true, "=")
  337 + -- local beginRange = range[1] or 0
  338 + -- local endRange = range[2] or 0
  339 + -- if maxCarbonId > beginRange and maxCarbonId <= endRange and cfg.type == eventType then
  340 + -- result[diff] = cfg
  341 + -- maxDiff = math.max(maxDiff, diff)
  342 + -- break
  343 + -- end
  344 + -- end
  345 + --end
  346 + local config = nil
  347 + for id, cfg in pairs(csvdb["shop_packCsv"]) do
  348 + if cfg.type == eventType and cfg.condition == param then
  349 + config = cfg
341 end 350 end
342 end 351 end
343 - if shopGoodsId ~= 0 then  
344 - local rechargeCfg = csvdb["shop_rechargeCsv"][shopGoodsId] 352 + if config ~= nil then
  353 + local rechargeCfg = csvdb["shop_rechargeCsv"][config.packId]
345 if rechargeCfg then 354 if rechargeCfg then
346 - limitPack[rechargeCfg.id] = timeNow + rechargeCfg.time 355 + limitPack[rechargeCfg.id] = {timeNow + rechargeCfg.time, config.id}
347 self:updateProperty({field = "limitTPack", value = limitPack}) 356 self:updateProperty({field = "limitTPack", value = limitPack})
348 end 357 end
349 end 358 end
350 - if next(result) then  
351 - self:updateProperty({field = "packTrigger", value = triggerRecord})  
352 - end 359 + --if next(result) then
  360 + -- self:updateProperty({field = "packTrigger", value = triggerRecord})
  361 + --end
353 end 362 end
354 363
355 function GetActGoodsIndex(goodsType) 364 function GetActGoodsIndex(goodsType)
@@ -419,7 +428,7 @@ function Store:data() @@ -419,7 +428,7 @@ function Store:data()
419 battleLR = self:getProperty("battleLR"), 428 battleLR = self:getProperty("battleLR"),
420 limitTPack = self:getProperty("limitTPack"), 429 limitTPack = self:getProperty("limitTPack"),
421 privCardEx = self:getProperty("privCardEx"), 430 privCardEx = self:getProperty("privCardEx"),
422 - packTrigger = self:getProperty("packTrigger"), 431 + --packTrigger = self:getProperty("packTrigger"),
423 actGoodsFlag = self:getProperty("actGoodsFlag"), 432 actGoodsFlag = self:getProperty("actGoodsFlag"),
424 bpInfo = self:getProperty("bpInfo"), 433 bpInfo = self:getProperty("bpInfo"),
425 } 434 }
src/services/agent_util.lua
@@ -17,15 +17,32 @@ local HEART_TIMEOUT_COUNT_MAX = 20 @@ -17,15 +17,32 @@ local HEART_TIMEOUT_COUNT_MAX = 20
17 local HEART_QUICK_COUNT_MAX = 5 17 local HEART_QUICK_COUNT_MAX = 5
18 -- 心跳定时间隔 18 -- 心跳定时间隔
19 local HEART_TIMER_INTERVAL = 5 19 local HEART_TIMER_INTERVAL = 5
  20 +-- 忽略心跳的等待时间
  21 +local WAIT_IGNORE_HEART = 300
  22 +
  23 +--开始忽略心跳的时间
  24 +local ignoreHeartTime = nil
20 25
21 local function check_heart_beat(agent, now) 26 local function check_heart_beat(agent, now)
22 -- 充值等操作不检查心跳 27 -- 充值等操作不检查心跳
23 local role = agent.role 28 local role = agent.role
24 - if role.ignoreHeartbeat then 29 + if not role or role.ignoreHeartbeat then
25 lastHeartCheckTime = now - HEART_TIMER_INTERVAL 30 lastHeartCheckTime = now - HEART_TIMER_INTERVAL
26 heartTimeoutCount = 0 31 heartTimeoutCount = 0
  32 +
  33 + if not ignoreHeartTime then
  34 + ignoreHeartTime = now
  35 + end
  36 +
  37 + if now - ignoreHeartTime >= WAIT_IGNORE_HEART then -- 等待太久了 踢掉
  38 + skynet.error("timeout! then agent will shut down by self with ignoreHeartbeat or no login", agent.client_fd)
  39 + skynet.call(agent.gate_serv, "lua", "kick", agent.client_fd)
  40 + ignoreHeartTime = nil
  41 + end
27 return 42 return
28 end 43 end
  44 + ignoreHeartTime = nil
  45 +
29 if lastHeartCheckTime - now > HEART_TIMER_INTERVAL or 46 if lastHeartCheckTime - now > HEART_TIMER_INTERVAL or
30 now - lastHeartCheckTime > HEART_TIMER_INTERVAL then 47 now - lastHeartCheckTime > HEART_TIMER_INTERVAL then
31 heartTimeoutCount = heartTimeoutCount + 1 48 heartTimeoutCount = heartTimeoutCount + 1
@@ -46,6 +63,7 @@ function _M:update(agent) @@ -46,6 +63,7 @@ function _M:update(agent)
46 pcall(check_heart_beat, agent, now) 63 pcall(check_heart_beat, agent, now)
47 nextCheckTime = now + HEART_TIMER_INTERVAL 64 nextCheckTime = now + HEART_TIMER_INTERVAL
48 end 65 end
  66 + if not role then return end
49 pcall(role.onRecoverTimer, role, now) 67 pcall(role.onRecoverTimer, role, now)
50 end 68 end
51 69
@@ -73,6 +91,7 @@ end @@ -73,6 +91,7 @@ end
73 function _M:reset() 91 function _M:reset()
74 heartTimeoutCount = 0 92 heartTimeoutCount = 0
75 heartQuickCount = 0 93 heartQuickCount = 0
  94 + ignoreHeartTime = nil
76 lastHeartCheckTime = skynet.timex() 95 lastHeartCheckTime = skynet.timex()
77 end 96 end
78 97
src/utils/StringUtil.lua
@@ -347,4 +347,20 @@ function string.toMap(str, tonum, sep) @@ -347,4 +347,20 @@ function string.toMap(str, tonum, sep)
347 end 347 end
348 end 348 end
349 return tab 349 return tab
  350 +end
  351 +
  352 +--[[
  353 +from: 1=2=3=4
  354 +to: {1,2,3,4}
  355 +]]
  356 +function string.toMap(str, tonum, sep)
  357 + local str_vec = string.split(str, " ")
  358 + local tab = {}
  359 + for _, v in pairs(str_vec) do
  360 + local vec = string.split(v, sep)
  361 + if #vec == 2 then
  362 + tab[vec[1]] = tonum and tonumber(vec[2]) or vec[2]
  363 + end
  364 + end
  365 + return tab
350 end 366 end
351 \ No newline at end of file 367 \ No newline at end of file