local RolePlugin = {} function RolePlugin.bind(Role) function Role:loadAll() self:loadDaily() self:loadEquips() self:loadRunes() self:loadHeros() self:loadDiner() self:loadActivity() self:loadStoreInfo() end function Role:reloadWhenLogin() end function Role:SendPacket(...) SendPacket(...) end function Role:onOfflineEvent() -- 设置最新的登录时间 self:setProperty("ltime", skynet.timex()) end local function checkItemCount(self, itemId, count) local itemData = csvdb["itemCsv"][itemId] -- 种类 类型数量限制 local page = globalCsv.store_type[itemData.type] local limit = self:getProperty("bagLimit")[page] if limit and self:getItemCount(itemId) == 0 then local curCount = 0 local items = self:getProperty("items"):toNumMap() for id ,_ in pairs(items) do local tempData = csvdb["itemCsv"][id] if tempData then if globalCsv.store_type[tempData.type] == page then curCount = curCount + 1 if curCount >= limit then count = 0 break end end end end end return count end local function _award(self, itemId, count, params) local pms = clone(params) local itemData = csvdb["itemCsv"][itemId] if not itemData then -- 加一层保护 return 0, {} end local curType = itemData.type local change = {} -- 奖励被转化为了其他奖励 id = count local itemIdAward = { [ItemId.PlayerExp] = function() self:addPlayExp(count, pms) end, } local itemTypeAward = { [ItemType.Hero] = function() pms.type = itemId - ItemStartId.Hero local status = self:addHero(pms) local gcount = 1 if not status then gcount = 0 end if count - gcount > 0 then local heroData = csvdb["unitCsv"][pms.type] change[pms.type] = (change[pms.type] or 0) + (count - gcount) * globalCsv.draw_unit_tofragment[heroData.rare] end count = gcount end, [ItemType.EquipBase] = function() local typ = math.floor((itemId-7000)/100) local lv = (itemId-7000)%100 self:addEquip(typ, lv, count ,pms) local equipCsv = (csvdb["equipCsv"][typ] or {})[lv] self:checkTaskEnter("AddEquip", {equipId = itemId, rarity = equipCsv.rarity}, pms.notNotify) end, [ItemType.Rune] = function() local typ = math.floor((itemId-10000)/1000) for _= 1, count do self:addRune({type = typ,id = itemId, notNotify = pms.notNotify, log = pms.log}) end end, [ItemType.AdvItem] = function() --冒险道具不会进入 玩家仓库 count = 0 end, [ItemType.FuncOpen] = function() self:funcOpen(itemId, count, pms) end, } -- 对数量筛查 count = checkItemCount(self, itemId, count) if count ~= 0 then if itemIdAward[itemId] then itemIdAward[itemId]() elseif itemTypeAward[curType] then itemTypeAward[curType]() else pms.itemId = itemId pms.count = count self:addItem(pms) end end return count, change -- count 实际发放的奖励个数 change 物品实际奖励与当前id 不符 就发生转换 而不实际发奖 end -- 发奖功能入口 award string id=count or {[id] = count} function Role:award(gift, params) params = params or {} local tgift = {} if type(gift) == "string" then for _, one in pairs(gift:toTableArray(true)) do tgift[one[1]] = (tgift[one[1]] or 0) + one[2] end else tgift = gift end local reward, allChange = {}, {} for itemId, rcount in pairs(tgift) do local count, change = _award(self, itemId, rcount, params) if count > 0 then reward[itemId] = (reward[itemId] or 0) + count end if next(change) then local cr, _ = self:award(change, params) -- 内部转换忽略 防止死循环 if next(cr) then for _id, _ct in pairs(cr) do reward[_id] = (reward[_id] or 0) + _ct end table.insert(allChange, {form = {[itemId] = rcount - count}, to = cr}) end end end if not next(allChange) then allChange = nil end return reward, allChange --实际获得的奖励 和 最高级奖励转化过程 end function Role:packReward(reward, change) if not reward then return nil end return {reward = reward, change = change} end function Role:awardExpireItem(expireTime, gift, params) if expireTime <= skynet.timex() then return end local reward = self:award(gift, params) local expireItem = self:getProperty("expireItem") for itemId, _ in pairs(reward) do expireItem[itemId] = expireTime end self:setProperty("expireItem", expireItem) end function Role:checkExpireItem(notNotify) local expireItem = self:getProperty("expireItem") local now = skynet.timex() for itemId, expireTime in pairs(expireItem) do if expireTime <= now then expireItem[itemId] = nil local itemCount = self:getItemCount(itemId) if itemCount > 0 then -- 过期物品删掉 self:addItem({itemId = itemId, count = -itemCount, log = {desc = "expire"}, notNotify = notNotify}) --过期 local itemData = csvdb["itemCsv"][itemId] if itemData then if itemData.type == ItemType.Head then -- 检查头像是不是在穿戴 if self:getProperty("headId") == itemId then self:changeHead(globalCsv.defaultHead, notNotify) local headData = csvdb["player_iconCsv"][itemId] -- pvp 跨服竞技场奖励 if headData and headData.path == 2 then redisproxy:insertEmail({roleId = self:getProperty("id"), emailId = 19}) end end end end end end end self:setProperty("expireItem", expireItem) end function Role:changeHead(id, notNotify) self:updateProperty({field = "headId" ,value = id, notNotify = notNotify}) self:changeCrossServerPvpSelfInfo("headId") self:log("role_action", {desc = "changeHead", int1 = id}) end function Role:addPlayExp(addExp, params) local level = self:getProperty("level") if not csvdb["player_expCsv"][level + 1] then return end local exp = self:getProperty("exp") local newExp = exp + addExp while newExp >= csvdb["player_expCsv"][level].exp do if csvdb["player_expCsv"][level + 1] then -- 有下一级 newExp = newExp - csvdb["player_expCsv"][level].exp level = level + 1 self:checkTaskEnter("RoleLevelUp", {level = level}) else newExp = csvdb["player_expCsv"][level].exp - 1 -- 没有下一级了 经验溢出太多 扣除 end end if params.log then local log = clone(params.log) if log["cint1"] or log["cint2"] then print("addPlayExp error log have cint1 or cint2 or cint3", debug.traceback()) end log["cint1"] = addExp log["cint2"] = newExp log["cint3"] = level self:log("player_exp", log) else print("addPlayExp no log ", debug.traceback()) end self:updateProperties({level = level, exp = newExp}) self:changeCrossServerPvpSelfInfo("level") end function Role:addItem(params) params = params or {} if params.itemId == ItemId.Diamond then self:gainDiamond(params) return end local items = self:getProperty("items") local origin = items:getv(params.itemId, 0) local nums = origin+params.count if nums <= 0 then items = items:delk(params.itemId) nums = 0 else items = items:incrv(params.itemId, params.count) end if params.log then local log = clone(params.log) if log["cint1"] or log["cint2"] then print("addItem error log have cint1 or cint2 ", debug.traceback()) end log["cint1"] = params.itemId log["cint2"] = math.abs(params.count) if params.count <= 0 then self:log("out_item", log) else self:log("in_item", log) end else print("addItem no log ", debug.traceback()) end self:setProperty("items", items) if not params.notNotify then SendPacket(actionCodes.Role_updateItems, MsgPack.pack({[params.itemId] = nums})) end end function Role:checkItemEnough(itemCountT) local less = {} if not next(itemCountT) then return false, less end for itemId, count in pairs(itemCountT) do if count <= 0 then -- 判断物品数量值不应该小于等于0 less[itemId] = 0 else local last = self:getItemCount(itemId) - count if last < 0 then less[itemId] = -last end end end return (not next(less)), less -- 是否足够,,缺什么缺多少 end function Role:costItems(itemCountT, params) local pms = clone(params or {}) if itemCountT[ItemId.Diamond] then --优先扣除钻石 pms.count = itemCountT[ItemId.Diamond] if not self:costDiamond(pms) then return end itemCountT[ItemId.Diamond] = nil end for itemId, count in pairs(itemCountT) do pms.itemId = itemId pms.count = - count self:addItem(pms) end return true end function Role:getItemCount(itemId) if itemId == ItemId.Diamond then return self:getAllDiamond() end return self:getProperty("items"):getv(itemId, 0) end function Role:getAllDiamond() return self:getProperty("diamond") + self:getProperty("reDiamond") end function Role:gainDiamond(params) if not params or type(params) ~= "table" then return false end local count = tonum(params.count) if isnan(count) then return false end local origind = self:getProperty("diamond") local originr = self:getProperty("reDiamond") local origin = origind + originr if params.isRecharge then self:incrProperty("reDiamond", count) else self:incrProperty("diamond", count) end if params.log then local log = clone(params.log) if log["cint1"] or log["cint2"] or log["cint3"] then print("costDiamond error log have cint1 or cint2 or cint3 ", debug.traceback()) end log["cint1"] = origin log["cint2"] = count self:log("in_diamond", log) else print("gainDiamond no log ", debug.traceback()) end self:notifyUpdateProperty("diamond", self:getAllDiamond()) return true end function Role:costDiamond(params) if not params or type(params) ~= "table" then return false end local count = tonum(params.count) if isnan(count) then return false end if count <= 0 then return false end local origind = self:getProperty("diamond") local originr = self:getProperty("reDiamond") local origin = origind + originr if origin < 0 then return false end if origin < count then return false end local last = count local costFirst = {"diamond", "reDiamond"} if params.isRecharge then costFirst = {"reDiamond", "diamond"} end last = math.max(last - self:getProperty(costFirst[1]), 0) if last < count then self:incrProperty(costFirst[1], last - count) end if last > 0 then self:incrProperty(costFirst[2], -last) end if params.log then local log = clone(params.log) if log["cint1"] or log["cint2"] or log["cint3"] then print("costDiamond error log have cint1 or cint2 or cint3 ", debug.traceback()) end log["cint1"] = origin log["cint2"] = count self:log("out_diamond", log) else print("costDiamond no log ", debug.traceback()) end self:notifyUpdateProperty("diamond", self:getAllDiamond()) return true end function Role:addHero(params) local roleId = self:getProperty("id") local heroType = params.type if self:isHaveHero(heroType) then return end local unitData = csvdb["unitCsv"][heroType] if not unitData then return false end local heroId = tonum(redisproxy:hincrby(string.format(R_INCR, roleId), "hero", 1)) redisproxy:sadd(string.format(R_HEROS, roleId), heroId) local heroInfo = { key = string.format(R_HERO, roleId, heroId), id = heroId, type= heroType, wakeL = globalCsv.unit_wake_initLevel[unitData.rare], } local newHero = require("models.Hero").new(heroInfo) newHero:create() newHero.owner = self newHero:saveBattleValue() self.heros[heroId] = newHero self:checkTaskEnter("AddHero", {heroType = heroType, wakeL = newHero:getProperty("wakeL"), camp = unitData.camp, job = unitData.job}, params.notNotify) if not params.notNotify then local heroResponse = {} table.insert(heroResponse, newHero:data()) local bin = MsgPack.pack(heroResponse) SendPacket(actionCodes.Hero_loadInfos, bin) end if params.log then local log = clone(params.log) if log["cint1"] or log["cint2"] or log["cint3"] then print("addHero error log have cint1 or cint2 or cint3 ", debug.traceback()) end log["cint1"] = heroId log["cint2"] = heroType self:log("in_hero", log) else print("addHero no log ", debug.traceback()) end return true, newHero end function Role:isHaveHero(heroType) if not csvdb["unitCsv"][heroType] then return false end for _, hero in pairs(self.heros) do if hero:getProperty("type") == heroType then return hero end end end function Role:delHero(heroId, params) params = params or {} local roleId = self:getProperty('id') local hero = self.heros[heroId] local heroType = hero:getProperty("type") if not hero then return end self.heros[heroId] = nil redisproxy:pipelining(function (red) red:del(string.format(R_HERO, roleId, heroId)) red:srem(string.format(R_HEROS, roleId), heroId) end) if params.log then local log = clone(params.log) if log["cint1"] or log["cint2"] or log["cint3"] then print("delHero error log have cint1 or cint2 or cint3 ", debug.traceback()) end log["cint1"] = heroId log["cint2"] = heroType self:log("out_hero", log) else print("delHero no log ", debug.traceback()) end SendPacket(actionCodes.Hero_loadInfos, MsgPack.pack({{id = heroId, bDel = true}})) end function Role:loadHeros() local roleId = self:getProperty("id") local heroIds = redisproxy:smembers(string.format(R_HEROS, roleId)) local redret = redisproxy:pipelining(function (red) for _, heroId in ipairs(heroIds) do red:hgetall(string.format(R_HERO, roleId, heroId)) end end) for index, heroId in ipairs(heroIds) do local hero = require("models.Hero").new({key = string.format(R_HERO, roleId, heroId)}) if hero:load(table.array2Table(redret[index])) then hero.owner = self self.heros[tonumber(heroId)] = hero end end end function Role:loadDaily() local roleId = self:getProperty("id") local dataKey = string.format(R_DAILY, roleId) self.dailyData = require("models.Daily").new({key = dataKey}) self.dailyData.owner = self if not redisproxy:exists(dataKey) then self.dailyData:create() else self.dailyData:load() end end function Role:loadActivity() local roleId = self:getProperty("id") local dataKey = string.format(R_ACTIVITY, roleId) self.activity = require("models.Activity").new({key = dataKey}) self.activity.owner = self if not redisproxy:exists(dataKey) then self.activity:create() else self.activity:load() end end function Role:loadDiner() local roleId = self:getProperty("id") local dataKey = string.format(R_DINER, roleId) self.dinerData = require("models.Diner").new({key = dataKey}) self.dinerData.owner = self if not redisproxy:exists(dataKey) then self.dinerData:create() else self.dinerData:load() end end function Role:loadEquips() -- 放role 里面了 end function Role:loadStoreInfo() local roleId = self:getProperty("id") local dataKey = string.format(R_STORE, roleId) self.storeData = require("models.Store").new({key = dataKey}) self.storeData.owner = self if not redisproxy:exists(dataKey) then self.storeData:create() else self.storeData:load() end end function Role:addEquip(equipType, equipLv, count, pms) pms = pms or {} if count ~= count then return end local equipCsv = (csvdb["equipCsv"][equipType] or {})[equipLv] if not equipCsv then return end local equips = self:getProperty("equips") local curTypeEquips = equips[equipType] or {} local curCount = (curTypeEquips[equipLv] or 0) + count -- 是否足够上层判断 if curCount < 0 then curCount = 0 curTypeEquips[equipLv] = nil else curTypeEquips[equipLv] = curCount end if next(curTypeEquips) then equips[equipType] = curTypeEquips else equips[equipType] = nil end self:setProperty("equips", equips) if pms.log then local log = clone(pms.log) if log["cint1"] or log["cint2"] or log["cint3"] then print("addEquip error log have cint1 or cint2 or cint3 ", debug.traceback()) end log["cint1"] = equipType log["cint2"] = equipLv log["cint3"] = math.abs(count) if count < 0 then self:log("out_equip", log) else self:log("in_equip", log) end else print("addEquip no log ", debug.traceback()) end if not pms.notNotify then self:changeUpdates({{type = "equips", field = {equipType, equipLv}, value = curCount, isOnlyToC = true}}) -- 通知客户端 end end function Role:getEquipCount(typ,lv) return (self:getProperty("equips")[typ] or {})[lv] or 0 end function Role:loadRunes() local roleId = self:getProperty("id") local runeIds = redisproxy:smembers(string.format(R_RUNEIDS, roleId)) local redret = redisproxy:pipelining(function (red) for _, runeId in ipairs(runeIds) do red:hgetall(string.format(R_RUNE, roleId, runeId)) end end) for index, runeId in ipairs(runeIds) do local rune = require("models.Rune").new({key = string.format(R_RUNE, roleId, runeId)}) if rune:load(table.array2Table(redret[index])) then rune.owner = self self.runeBag[tonumber(runeId)] = rune end end end -- 0 为操作成功 function Role:addRune(params) if params.type and params.id then local set = csvdb["runeCsv"][params.type] if not set then return 2 end local data = set[params.id] if not data then return 3 end local roleId = self:getProperty("id") local runeUid = tonum(redisproxy:hincrby(string.format(R_INCR, roleId), "rune", 1)) redisproxy:sadd(string.format(R_RUNEIDS, roleId), runeUid) local heroInfo = { key = string.format(R_RUNE, roleId, runeUid), uid = runeUid, type = params.type, id = params.id, } local newRune = require("models.Rune").new(heroInfo) newRune:create() newRune:generateAttrs() newRune.owner = self self.runeBag[runeUid] = newRune if not params.notNotify then local response = {} table.insert(response, newRune:data()) SendPacket(actionCodes.Role_loadRunes, MsgPack.pack(response)) end self:checkTaskEnter("AddRune", {id = params.id, type = params.type, rarity = data.rarity}, params.notNotify) if params.log then local log = clone(params.log) if log["cint1"] or log["cint2"] or log["cint3"] then print("addRune error log have cint1 or cint2 or cint3 ", debug.traceback()) end log["cint1"] = runeUid log["cint2"] = params.type log["cint3"] = params.id self:log("in_rune", log) else print("addRune no log ", debug.traceback()) end return 0, newRune else return 1 end end function Role:delRunes(runeIds, params) -- 批量删除 {id, } params = params or {} local roleId = self:getProperty('id') local bDel = {} for _, runeId in pairs(runeIds) do local rune = self.runeBag[runeId] if rune and rune:getProperty("refer") == 0 then if params.log then local log = clone(params.log) if log["cint1"] or log["cint2"] or log["cint3"] then print("delRunes error log have cint1 or cint2 or cint3 ", debug.traceback()) end log["cint1"] = runeId log["cint2"] = rune:getProperty("type") log["cint3"] = rune:getProperty("id") self:log("out_rune", log) else print("delRunes no log ", debug.traceback()) end self.runeBag[runeId] = nil table.insert(bDel, runeId) end end redisproxy:pipelining(function (red) for _, runeId in pairs(bDel) do red:del(string.format(R_RUNE, roleId, runeId)) red:srem(string.format(R_RUNEIDS, roleId), runeId) end end) local response = {} for _, runeId in pairs(bDel) do table.insert(response, {uid = runeId, bDel = true}) end SendPacket(actionCodes.Role_loadRunes, MsgPack.pack(response)) end function Role:getRuneByType(typ) local runeSet = {} for _,v in pairs(self.runeBag) do if v.type == typ then table.insert(runeSet,v) end end return runeSet end function Role:getAdvData() if not self.advData then self.advData = require("adv.Adv").new(self) end return self.advData end function Role:getHeroMaxField(field, hType) local max = 0 for _, hero in pairs(self.heros) do if not hType or hero:getProperty("type") == hType then if hero:getProperty(field) > max then max = hero:getProperty(field) end end end return max end function Role:warningHeartTooQuick() -- 加速器检测 local heartWarning = self:getProperty("heartWarning") heartWarning = heartWarning + 1 self:setProperty("heartWarning", heartWarning) if heartWarning == 50 then self:setBan(30, 1) --封禁 30天 self:sendGmMsg("server_accountBanned_inGame_1") return end if heartWarning < 50 and heartWarning % 5 == 0 then self:sendGmMsg("server_accountBanned_warning") self:log("role_action",{desc = "heartWarning", int1 = heartWarning}) end end function Role:setBan(time, banType) time = time or 0 banType = banType or 0 local now = skynet.timex() if time == 0 then self:setProperty("banTime", 0) self:setProperty("banType", 0) self:setProperty("heartWarning", 0) self:log("role_action", {desc = "ban_rm"}) else self:setProperty("banTime", now + 86400 * time) self:setProperty("banType", banType) self:log("role_action", {desc = "ban", int1 = time, int2 = banType}) end end function Role:sendGmMsg(text, isNotKey) SendPacket(actionCodes.Sys_maintainNotice, MsgPack.pack({ body = text, iskey = not isNotKey})) end function Role:getHeroActiveRelationData(heros) local relations = {} for _, id in pairs(heros or {}) do local hero = self.heros[id] if hero then local camp = csvdb["unitCsv"][hero:getProperty("type")].camp relations[camp] = (relations[camp] or 0) + 1 end end local curData = csvdb["unit_relationCsv"][0] if not next(relations) then return curData end for _, data in ipairs(csvdb["unit_relationCsv"]) do local had = {} local isDone = true for _, count in pairs(data.relation:toArray(true, "=")) do local find = false for camp, _count in pairs(relations) do if count == _count and not had[camp] then had[camp] = true find = true break end end if not find then isDone = false break end end if isDone then curData = data end end return curData end function Role:getHeroActiveRelation(heros) local data = self:getHeroActiveRelationData(heros) local result = {} for attr, value in pairs(data.effect:toNumMap()) do result[AttsEnumEx[attr]] = (result[AttsEnumEx[attr]] or 0) + value end return result end function Role:getHerosCamp(heros) local had = {} for _, id in pairs(heros or {}) do local hero = self.heros[id] if hero then local camp = csvdb["unitCsv"][hero:getProperty("type")].camp had[camp] = (had[camp] or 0) + 1 end end local curCamp = 0 for camp , count in pairs(had) do if count >= 3 then curCamp = camp break end end return curCamp end function Role:getRealBattleValue(heros, activeRelation) -- 获取队伍战斗力 羁绊加成 heros = heros or {} local activeRelation = activeRelation or self:getHeroActiveRelation(heros) local battleValue = 0 for _, id in pairs(heros) do local hero = self.heros[id] if hero then battleValue = battleValue + hero:getBattleValue(activeRelation) end end return battleValue end function Role:getAdvHangLimit() return globalCsv.adv_daily_cross_count + self:getFuncLv(FuncOpenType.AdvCount) end function Role:checkAdvCount(need) local oldCount = self:getProperty("advC") local oldTime = self:getProperty("advCT") local newCount = oldCount if oldCount > 0 then local add = math.max(math.floor((skynet.timex() - oldTime) / (globalCsv.adv_daily_regain_min * 60)), 0) newCount = math.max(oldCount - add, 0) end return newCount + need <= self:getAdvHangLimit() end --忽略上限 function Role:changeAdvCount(change) if change == 0 then return end local count = self:getProperty("advC") local ctime = self:getProperty("advCT") if ctime == 0 then ctime = skynet.timex() end local add = math.max(math.floor((skynet.timex() - ctime) / (globalCsv.adv_daily_regain_min * 60)), 0) local nextTime = ctime + add * (globalCsv.adv_daily_regain_min * 60) if count > 0 then count = math.max(count - add, 0) end self:updateProperties({ advC = count + change, advCT = nextTime, }) end function Role:getAdvElLimit() return globalCsv.adv_endless_daily_cross_count + self:getFuncLv(FuncOpenType.AdvCountEL) end -- 走 guide_unlock 表的 被动解锁 function Role:isFuncUnlock(func) if not func then return true end -- 没有就是解锁了 local data = csvdb["guide_unlockCsv"][func] if not data then return true end -- 没有就是解锁了 if self:checkHangPass(data.carbonId) then return true else return false end end -- 走 unlock 表的主动解锁 function Role:isFuncOpen(func) return self:getProperty("funcOpen")[func] == 1 end function Role:getFuncLv(func) return self:getProperty("funcLv")[func] or 1 end -- 参数有level 则是检查是否可以升级 function Role:isArtifactOpen(id, isEndless, level) local isCheckLevel = not not level level = level or 1 local curData = (csvdb["adv_artifactCsv"][id] or {})[level] if not curData then return false end if curData.unlock == 1 then -- 获得解锁 return self:getProperty("advAFOpen")[id] and true or false elseif curData.unlock == 2 then -- 特殊神器 不可解锁 return isCheckLevel elseif curData.unlock == 3 then return isEndless end return true end function Role:funcOpen(func, count, params) params = params or {} count = count or 1 if params.log then local log = clone(params.log) if log["cint1"] or log["cint2"] or log["cint3"] then print("funcOpen error log have cint1 or cint2 or cint3 ", debug.traceback()) end log["cint1"] = func log["cint2"] = count self:log("func_open", log) else print("funcOpen no log ", debug.traceback()) end if csvdb["itemCsv"][func] and csvdb["itemCsv"][func].type == ItemType.FuncOpen then local unlockData = csvdb["unlockCsv"][func] if unlockData.type == 4 then -- 解锁神器 if self:getProperty("advAFOpen")[unlockData.value1] ~= 1 then self:changeUpdates({{type = "advAFOpen", field = unlockData.value1, value = 1}}) end elseif TypeIsFunc[unlockData.type] then if unlockData.value1 == 0 or unlockData.value1 == 1 then if self:getProperty("funcOpen")[unlockData.type] ~= 1 then self:changeUpdates({{type = "funcOpen", field = unlockData.type, value = 1}}) end else local oldV = self:getFuncLv(unlockData.type) local newLv = math.min(oldV + count, unlockData.value2) if oldV ~= newLv then self:changeUpdates({{type = "funcLv", field = unlockData.type, value = newLv}}) end end else if self:getProperty("funcOpen")[func] ~= 1 then self:changeUpdates({{type = "funcOpen", field = func, value = 1}}) end end end end function Role:advChapterIsOpen(chapterId) local chapterData = csvdb["adv_chapterCsv"][chapterId] if chapterData.prepose ~= 0 and not self:checkHangPass(chapterData.prepose) then return false end return true end function Role:advEventOpenStatus() local openStatus = {} for func , data in pairs(csvdb["unlockCsv"]) do if data.type == 5 then openStatus[data.value1] = openStatus[data.value1] or {} openStatus[data.value1][data.value2] = self:isFuncOpen(func) end end return openStatus end -- 赛季检查 function Role:advEndlessSeasonCheck(notNotify) -- 重置一下冒险 local nowSeason = tonum(redisproxy:hget("adv_season", "idx")) if self:getProperty("advElS") ~= nowSeason then -- 胡博文让注释掉 衰减 从0开始 -- local ml = self:getProperty("advElM") -- local nl = math.max(0, ml - (math.floor(ml / 50) + 2) * 10) -- self:setProperty("advElM", math.floor(nl / 10) * 10) -- 正在无尽冒险清掉 local adv = self:getAdvData() if adv:isRunning() and adv:isEndless() then adv:forceOver() end -- 路过的中继层重置掉 local advRelay = self:getProperty("advRelay") advRelay[-1] = nil -- 清掉冒险手册 self:updateProperties({ advEAchiev = {}, advElM = 0, advElS = nowSeason, advRelay = advRelay, }, notNotify) -- 重新设定冒险章节和冒险结束时间 self.advElChapter = tonum(redisproxy:hget("adv_season", "chapter"), globalCsv.adv_endless_default_chapter) self.advOverTime = tonum(redisproxy:hget("adv_season", "overTime")) if not notNotify then SendPacket(actionCodes.Role_updateProperties, MsgPack.pack({ advElChapter = self.advElChapter, advOverTime = self.advOverTime, })) end end end -- 获得激活的冒险效果 function Role:getAdvActiveSupportEffect() local effect = {} local advEAchiev = self:getProperty("advEAchiev") for id, status in pairs(advEAchiev[self.advElChapter] or {}) do if status == -1 then local achvData = csvdb["adv_achievementCsv"][id] if achvData and achvData.support ~= 0 then effect[achvData.support] = 1 end end end return effect end --获取冒险支援效果免费刷新次数 function Role:getAdvSupportFreeCount() local count = 1 --默认每天有1次 local openEffects = self:getAdvActiveSupportEffect() for aId, _ in pairs(openEffects) do local curData = csvdb["adv_supportCsv"][aId] if curData.type == 2 then for _, effect in ipairs(curData.effect:toArray()) do local cur = effect:toArray(true, "=") if cur[1] == 8 then count = count + cur[2] end end end end return count end -- 冒险随机新的支援效果 function Role:advRandomSupportEffect(notNotify) local pool = {} local openEffects = self:getAdvActiveSupportEffect() for id, data in pairs(csvdb["adv_supportCsv"]) do if data.type == 0 then if openEffects[id] then table.insert(pool, data) end elseif data.type == 1 then table.insert(pool, data) end end local advSup = {} for i = 1, math.min(3, #pool) do local idx = math.randWeight(pool, "showup") table.insert(advSup, pool[idx].id) table.remove(pool, idx) end self:updateProperty({field = "advSup", value = advSup, notNotify = notNotify}) end function Role:getCurDinerRankKey() local round = self:getTimeResetRound(TimeReset.DinerRank) local idx = 1 if round % 2 == 1 then idx = 2 end return RANK_DINER[idx] end local StdTowerRankTime = toUnixtime("2019010100") function Role:setTowerRank(level) local now = skynet.timex() local ct = math.ceil((now - StdTowerRankTime) / 86400) --按天计算 365 * 27 < 10000 可以维持 27 年 local ct = 10000 - ct -- 越早的排名越靠前 local towerTeam = self:getProperty("towerF") local battleV = self:getTeamBattleValue(towerTeam.heros) local score = (level * 10000 + ct) * 10000000 + battleV local curInfo = { name = self:getProperty("name"), headId = self:getProperty("headId"), lv = self:getProperty("level"), batteV = battleV, level = level, format = self:getTeamHerosInfo(towerTeam.heros), } local roleId = self:getProperty("id") redisproxy:pipelining(function (red) red:zadd(RANK_TOWER, score, roleId) --更新分数 red:hset(RANK_TOWER_INFO, roleId, MsgPack.pack(curInfo)) end) end function Role:getTowerRank() local list = {} local ids = redisproxy:zrevrange(RANK_TOWER, 0 , 99) local redret = {} if ids and next(ids) then redret = redisproxy:pipelining(function (red) for i = 1, #ids do local roleId = ids[i] table.insert(list, {roleId = tonumber(roleId)}) red:hget(RANK_TOWER_INFO, roleId) end end) end for i = 1, #redret do local player = MsgPack.unpack(redret[i]) player.format = nil list[i].player = player end local rank = redisproxy:ZREVRANK(RANK_TOWER, self:getProperty("id")) if not rank then rank = -1 else rank = rank + 1 end return {list = list, rank = rank} end function Role:getTowerRankOneInfo(roleId) local data = redisproxy:hget(RANK_TOWER_INFO, roleId) if data then local player = MsgPack.unpack(data) return player.format end end function Role:addAdvLvExp(exp) local advL = self:getProperty("advL") local level = advL[1] local newExp = (advL[2] or 0) + exp if not csvdb["adv_level_fundCsv"][level + 1] then return end while newExp >= csvdb["adv_level_fundCsv"][level].exp do if csvdb["adv_level_fundCsv"][level + 1] and self:advChapterIsOpen(100 + csvdb["adv_level_fundCsv"][level + 1].chapter) then -- 有下一级 newExp = newExp - csvdb["adv_level_fundCsv"][level].exp level = level + 1 else newExp = csvdb["adv_level_fundCsv"][level].exp - 1 -- 没有下一级了 经验溢出太多 扣除 end end if level > advL[1] then self:checkTaskEnter("AdvLevel", {level = level}) end advL[1] = level advL[2] = newExp self:updateProperty({field = "advL", value = advL}) end function Role:getAdvWheelSurfLv(ptype) local level = 1 for i = 0, self:getProperty("advL")[1] do local effects = csvdb["adv_level_fundCsv"][i].effect:toArray() for _, one in ipairs(effects) do local effect = one:toArray(true, "=") if effect[1] == 2 and ptype == effect[2] then level = effect[3] end end end return level end function Role:fixAdvScoreChange(score) local change = 0 for i = 0, self:getProperty("advL")[1] do local effects = csvdb["adv_level_fundCsv"][i].effect:toArray() for _, one in ipairs(effects) do local effect = one:toArray(true, "=") if effect[1] == 3 then change = change + effect[2] end end end return math.floor(score * (1 + change / 100)) end function Role:getAdvLvAddAttrs() -- 1=冒险队属性;1=点数/百分比=属性枚举=参数;属性枚举(1=生命上限/2=魔法上限/3=攻击/4=防御);点数/百分比(0=点数/1=百分比) local attrs = {} for i = 0, self:getProperty("advL")[1] do local effects = csvdb["adv_level_fundCsv"][i].effect:toArray() for _, one in ipairs(effects) do local effect = one:toArray(true, "=") if effect[1] == 1 then attrs[effect[2]] = (attrs[effect[2]] or 0) + effect[3] end end end return attrs end function Role:getTeamBattleInfo(team) local teamInfo = {heros = {}, supports = {}} local activeRelation = self:getHeroActiveRelation(team.heros) for slot, id in pairs(team.heros or {}) do local info = {} local hero = self.heros[id] if not hero then print("error heroid " .. id) end local attrs = hero:getTotalAttrs({activeRelation = activeRelation}) for k, v in pairs(AttsEnumEx) do info[v] = (attrs[v] or 0) end info.type = hero:getProperty("type") info.level = hero:getProperty("level") info.wakeL = hero:getProperty("wakeL") info.blockLevel = hero:getSkillLevel(4) info.specialLevel = hero:getSkillLevel(1) info.passiveLevel = hero:getSkillLevel(3) info.runeSkill = hero:getRuneSkill(102) teamInfo.heros[slot] = info end for slot, id in pairs(team.supports or {}) do teamInfo.supports[slot] = {id, self.dinerData:getProperty("dishTree"):getv(id, 0)} end return teamInfo end function Role:getTeamHerosInfo(heroIds) local heros = {} for slot, heroId in pairs(heroIds or {}) do local hero = self.heros[heroId] heros[slot] = { type = hero:getProperty("type"), level = hero:getProperty("level"), wakeL = hero:getProperty("wakeL"), } end return heros end function Role:getTeamBattleValue(heros) -- local battleV = 0 -- for _, heroId in pairs(heros or {}) do -- local hero = self.heros[heroId] -- battleV = battleV + hero:getProperty("battleV") -- end -- return battleV return self:getRealBattleValue(heros) end -- 不传参数 只修改保存的阵容信息 function Role:saveHangTeam(team) if not team then team = self:getProperty("hangTeam") else self:updateProperty({field = "hangTeam", value = team}) end self:setProperties({ hangTS = self:getTeamHerosInfo(team.heros), hangTB = self:getTeamBattleInfo(team), hangTBV = self:getTeamBattleValue(team.heros), }) end function Role:savePvpCTeam(team) if not team then team = self:getProperty("pvpTC") else self:updateProperty({field = "pvpTC", value = team}) end self:setProperties({ pvpTSC = self:getTeamHerosInfo(team.heros), pvpTBC = self:getTeamBattleInfo(team), pvpTBVC = self:getTeamBattleValue(team.heros), }) end function Role:savePvpHTeam(team) if not team then team = self:getProperty("pvpTH") else self:updateProperty({field = "pvpTH", value = team}) end local pvpTSH, pvpTBH, pvpTBVH = {}, {}, {} for i = 1, 3 do if team[i] then pvpTSH[i] = self:getTeamHerosInfo(team[i].heros) pvpTBH[i] = self:getTeamBattleInfo(team[i]) pvpTBVH[i] = self:getTeamBattleValue(team[i].heros) end end self:setProperties({ pvpTSH = pvpTSH, pvpTBH = pvpTBH, pvpTBVH = pvpTBVH, }) end -- update function Role:onRecoverTimer(now) self:updateTimeReset(now, true) self:checkNewEvent(now) end local function breath(sec, name) local last_breath = 0 return function (now, role) if name == "email" and role.sendMailFlag then last_breath = now + sec return true end if now >= last_breath then last_breath = now + sec return true end return false end end local breathes = { ["email"] = breath(120, "email"), -- email ["pvphg"] = breath(300, "pvphg"), -- 高级竞技场 奖励满的红点 } function Role:checkNewEvent(now) if now - self:getProperty("ltime") < 5 then return end local checks = {} -- 检查全局邮件 -- 增加邮件红点 checks["email"] = function() local mid = self:getProperty("sid") local result = redisproxy:hmget("autoincrement_set", "email", "emailTimestamp") local globalEmail = tonum(result[1]) local timestamp = tonum(result[2]) local emailSync = self:getProperty("emailSync") if globalEmail > emailSync and timestamp > self:getProperty("ctime") then local emailSync = math.max(emailSync + 1, globalEmail - EMAIL_LIMIT + 1) local redret = redisproxy:pipelining(function (red) for id = emailSync, globalEmail do red:hgetall(string.format("globalEmail:%s", id)) end end) for _, data in ipairs(redret) do local email = tarr2tab(data) if tonum(email.createtime) > self:getProperty("ctime") and ( not email.mid or tonum(email.mid) == mid ) and ( not email.endtime or tonum(email.endtime) > now )then return true end end end local roleId = self:getProperty("id") local email_rds = string.format(R_EMAIL, roleId) local emailIds = redisproxy:lrange(email_rds, 0, EMAIL_LIMIT - 1) or {} local redret = redisproxy:pipelining(function (red) for _, id in ipairs(emailIds) do red:hget(string.format(R_EMAIL_ITEM, roleId, id), "status") end end) self.SendMailFlag = false for index, id in ipairs(emailIds) do if tonumber(redret[index]) == 0 then return true end end end checks["pvphg"] = function() if not self:isTimeResetOpen(TimeReset.PvpHight) then return end local pvpHGTime = self:getProperty("pvpHGTime") if pvpHGTime == 0 then return end local division = self:getPvpHDivision() local divisionData = csvdb["pvp_group_divisionCsv"][division] local newTime, newReward = self:calculatePvpHGift(division) if table.pack(next(newReward))[2] >= divisionData.limit then return true end end local events = {} for name, breath in pairs(breathes) do if breath(now, self) and checks[name] then local status = checks[name]() if status then if status == true then events[name] = 1 else events[name] = status end end end end if next(events) then SendPacket(actionCodes.Role_notifyNewEvent, MsgPack.pack({events = events})) end end function Role:checkHangPass(carbonId) local hangPass = self:getProperty("hangPass") local diff = math.floor(carbonId / 10000) return (hangPass[diff] or 0) >= carbonId end function Role:hangFinish(carbonId) local hangPass = self:getProperty("hangPass") local diff = math.floor(carbonId / 10000) if (hangPass[diff] or 0) < carbonId then hangPass[diff] = carbonId self:updateProperty({field = "hangPass", value = hangPass}) end end function Role:getAdvRankKey() local round = self:getProperty("advElS") local idx = 1 if round % 2 == 1 then idx = 2 end return RANK_ADV[idx] end -- 是否需要进行引导 function Role:checkOverGuide(guideId) local funcGuide = self:getProperty("funcGuide") if funcGuide:getv(guideId, 0) > 0 then return true end return false end -- 消除指定tag 红点 function Role:clearRedPTag(tag) local redp = self:getProperty("redp") redp[tag] = nil self:updateProperty({field = "redp", value = redp}) end -- 充值 -- --[[ request.order = data.out_trade_no request.amount = data.money / 100 request.game_money = data.game_money request.product_id = data.product_id request.pay_time = data.pay_time request.transactionId = data.order_no ]] function Role:handlePurchase(params) local roleId = self:getProperty("id") local partnerOrderStr = params.order local _, _, orderId = string.match(partnerOrderStr, "(.+)_(.+)_(.+)") local orderObject = require("models.Order").new({ key = string.format("order:%d:%d", roleId, orderId) }) if not orderObject:load() then -- 订单不存在 skynet.error("ayncPurchaseRpc", string.format("order %s not exist", partnerOrderStr)) return end if orderObject:getProperty("finishTime") > 0 then -- 订单已经处理 SendPacket(actionCodes.Store_ayncPurchaseRpc, MsgPack.pack({ result = "handled" })) return end local rechargeData = csvdb["shop_rechargeCsv"][orderObject:getProperty("rechargeId")] if rechargeData.rmb ~= tonumber(params.amount) then skynet.error(string.format("fake order: %s, roleId: %d, order: %s, rmb %s, get %s", params.transactionId, roleId, partnerOrderStr, rechargeData.rmb, params.amount )) return end local reward = self:recharge({ id = orderObject:getProperty("rechargeId"), transactionId = params.transactionId, pay_time = params.pay_time, order = partnerOrderStr }) orderObject:setProperty("finishTime", skynet.time()) orderObject:setProperty("status", "finish") redisproxy:srem(string.format("role:%d:orders", roleId), partnerOrderStr) SendPacket(actionCodes.Store_ayncPurchaseRpc, MsgPack.pack({ order = partnerOrderStr, result = "success", reward = reward})) return orderObject:getProperty("rechargeId") end function Role:recharge(params) local id = tonumber(params.id) local rechargeData = csvdb["shop_rechargeCsv"][id] if not rechargeData then skynet.error("recharge id not exist", id) return end if not self.storeData:checkRechargeRecord(rechargeData.limit, id) then return 1 end local diamondCount = 0 local reward = {} if rechargeData.shop == 1 then -- 钻石 local rechargeF = self:getProperty("rechargeF") diamondCount = rechargeData.diamond + rechargeData.diamondExtra if not rechargeF[id] then diamondCount = diamondCount + rechargeData.diamondFirst rechargeF[id] = 1 self:updateProperty({field = "rechargeF", value = rechargeF}) end self:gainDiamond({count = diamondCount, isRecharge = true, log = {desc = "recharge", int1 = id}}) elseif rechargeData.shop == 2 then --通行证商店 reward, _ = self:award(rechargeData.itemFirst, {log = {desc = "recharge", int1 = id}}) self.storeData:onBuyCard(rechargeData.type, rechargeData.time) elseif rechargeData.shop == 3 then -- 礼包商店 reward, _ = self:award(rechargeData.itemFirst, {log = {desc = "recharge", int1 = id}}) else skynet.error("invalid recharge shop type " .. id) return end if diamondCount > 0 then reward[ItemId.Diamond] = (reward[ItemId.Diamond] or 0) + diamondCount end -- 累充 local rmb = rechargeData.rmb self:updateProperty({field = "rmbC", delta = rmb}) self:log("role_action", {desc = "recharge", int1 = id, int2 = rmb, key1 = params.transactionId, key2 = params.order, long1 = params.pay_time}) return reward end --直接给玩家发送邮件,立即推送小红点 function Role:sendMail(mailId, createTime, reward, contentPms) local tgift = {} if type(reward) == "string" then for _, one in pairs(reward:toTableArray(true)) do tgift[one[1]] = (tgift[one[1]] or 0) + one[2] end else tgift = reward or {} end local gift = "" for k, v in pairs(tgift) do gift = gift .. k.."="..v.." " end redisproxy:insertEmail({roleId = self:getProperty("id"), emailId = mailId, createtime = createTime, attachments = gift, contentPms = contentPms}) self.sendMailFlag = true end -- 保存引导步骤 function Role:saveGuide(master,slave) local newerGuide = self:getProperty("newerGuide") local guide = newerGuide:toArray(true,"=") local sMaster, sSlave = guide[1], guide[2] if master < sMaster and slave < sSlave then return end local guideCsv = csvdb["guide_mainCsv"] if not guideCsv[master] or not guideCsv[master][slave] then return end self:log("guide", {desc = "guide_new",int1 = master*1000+slave}) newerGuide = string.format("%d=%d",master,slave) self:updateProperty({field = "newerGuide", value = newerGuide}) end -- 引导大步骤结束 function Role:finishGuide(master) local newerGuide = self:getProperty("newerGuide") local guide = newerGuide:toArray(true,"=") if guide[1] > master then return end local guideCsv = csvdb["guide_mainCsv"] local lastStep = guideCsv[master][#guideCsv[master]] if guideCsv[master + 1] then self:updateProperty({field = "newerGuide", value = string.format("%d=%d",master + 1,1)}) else self:updateProperty({field = "newerGuide", value = "9999=1"}) end end end return RolePlugin