local RolePlugin = {} function RolePlugin.bind(Role) function Role:log() end function Role:loadAll() self:loadDaily() self:loadEquips() self:loadRunes() self:loadHeros() self:loadDiner() end function Role:reloadWhenLogin() end function Role:onCrossDay(now, notify) local ltime = self:getProperty("ltime") if isCrossDay(ltime, now) then local response = {} self.dailyData:refreshDailyData(notify) self.dinerData:refreshDailyData(notify) if notify then self:notifyUpdateProperties(response) end if RESET_TIME == RESET_RANK_TIME then self:onResetRank_raw(ltime, now, notify) end self:setProperty("ltime", now) return true end end function Role:onResetRank(now, notify) local ltime = self:getProperty("ltime") if isCrossDay(ltime, now, RESET_RANK_TIME) then local response = self:onResetRank_raw(ltime, now, notify) if notify and next(response) then self:notifyUpdateProperties(response) end self:setProperty("ltime", now) return true end end function Role:onResetRank_raw(ltime, now, notify) local response = {} self.dinerData:rankResetData(notify) return response end function Role:onOfflineEvent() 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 globalCsv.store_type[tempData.type] == page then curCount = curCount + 1 if curCount >= limit then count = 0 break 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) end, } local itemTypeAward = { [ItemType.Hero] = function() pms.type = itemId - ItemStartId.Hero for _= 1, count do self:addHero(pms) end end, [ItemType.EquipBase] = function() local typ = math.floor((itemId-7000)/100) local lv = (itemId-7000)%100 self:addEquip(typ, lv, count ,pms) self:checkTaskEnter("AddEquip", {equipId = itemId}, pms.notNotify) end, [ItemType.Rune] = function() local typ = math.floor((itemId-2000)/100) for _= 1, count do self:addRune({type = typ,id = itemId}) end end, [ItemType.AdvItem] = function() --冒险道具不会进入 玩家仓库 count = 0 end, [ItemType.FuncOpen] = function() self:funcOpen(itemId, count) 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, count in pairs(tgift) do local count, change = _award(self, itemId, count, params) if next(change) then local cr, cc = self:award(change, params) -- 内部转换忽略 for _id, _ct in pairs(cr) do reward[_id] = (reward[_id] or 0) + _ct end table.insert(allChange, {form = {[itemId] = count}, to = cr}) else if count > 0 then reward[itemId] = (reward[itemId] or 0) + count end end end return reward, allChange --实际获得的奖励 和 最高级奖励转化过程 end function Role:addPlayExp(addExp) 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 else newExp = csvdb["player_expCsv"][level].exp - 1 -- 没有下一级了 经验溢出太多 扣除 end end self:updateProperties({level = level, exp = newExp}) 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 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 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 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 if not csvdb["unitCsv"][heroType] 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, } 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")}, 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 return true 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 true end end end function Role:delHero(heroId) local roleId = self:getProperty('id') local hero = self.heros[heroId] 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) 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: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: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 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 return 0 else return 1 end end function Role:delRunes(runeIds) -- 批量删除 {id, } 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 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:setProperty("delete", 1) -- self:sendGmMsg("系统检测到你多次使用加速器,已经将你封杀,请联系管理员。") -- self:log("gmAction",{desc = "ban"}) -- return -- end -- if heartWarning < 50 and heartWarning % 5 == 0 then -- self:sendGmMsg("警告!系统检测到你使用加速器,请立即停止使用!否则我们将封杀此账号!") -- self:log("gmAction",{desc = "heartWarning", count = heartWarning}) -- end end function Role:getHeroActiveRelation(heros) local relations = {} for _, id in pairs(heros or {}) do local hero = self.heros[id] if hero then local job = csvdb["unitCsv"][hero:getProperty("type")].job relations[job] = (relations[job] or 0) + 1 end end if not next(relations) then return {} end local result = {} for _, data in pairs(csvdb["unit_relationCsv"]) do local ok = true for typ, count in pairs(data.relation:toNumMap()) do if (relations[typ] or 0) < count then ok = false end end if ok then for attr, value in pairs(data.effect:toNumMap()) do result[AttsEnumEx[attr]] = (result[AttsEnumEx[attr]] or 0) + value end end end return result end function Role:getRealBattleValue(heros) -- 获取队伍战斗力 羁绊加成 local activeRelation = 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() -- todo return globalCsv.adv_daily_cross_count end function Role:getAdvElLimit() -- todo return globalCsv.adv_endless_daily_cross_count end function Role:isFuncOpen(func) return self:getProperty("funcOpen")[func] == 1 end function Role:getFuncLv(func) return self:getProperty("funcLv")[func] or 1 end function Role:funcOpen(func, count) count = count or 1 if csvdb["itemCsv"][func] and csvdb["itemCsv"][func].type == ItemType.FuncOpen then local unlockData = csvdb["unlockCsv"][func] if TypeIsFunc[unlockData.type] then if unlockData.value1 == 0 or unlockData.value1 == 1 then self:changeUpdates({{type = "funcOpen", field = unlockData.type, value = 1}}) else local oldV = self:getFuncLv(unlockData.type) local newLv = math.min(oldV + count, unlockData.value2) self:changeUpdates({{type = "funcLv", field = unlockData.type, value = newLv}}) end else self:changeUpdates({{type = "funcOpen", field = func, value = 1}}) end end end function Role:advChapterIsOpen(chapterId, layer) local exlayer = math.floor((layer - 1) / 10) * 10 + 1 if exlayer == 1 then --第一层判断前置 local advPass = self:getProperty("advPass") local chapterData = csvdb["adv_chapterCsv"][chapterId] for id, l in pairs(chapterData.prepose:toNumMap()) do if (advPass[id] or 0) < l then return false end -- 前置 end return true end local unlock = {} for func , data in pairs(csvdb["unlockCsv"]) do if data.type == 1 and chapterId == data.value1 and exlayer == data.value2 then return self:isFuncOpen(func) end end 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() if self:getProperty("advElS") ~= globalCsv.adv_endless_season then 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) self:setProperty("advElS", globalCsv.adv_endless_season) end end function Role:getTeamBattleValue(heros) local battleV = 0 for _, heroId in pairs(heros) do local hero = self.heros[heroId] battleV = battleV + hero:getProperty("battleV") end return battleV end function Role:recordRankTeam(heroIds) local heros = {} for slot, heroId in pairs(heroIds) do local hero = self.heros[heroId] heros[slot] = { htype = hero:getProperty("type"), lv = hero:getProperty("level"), breakL = hero:getProperty("breakL"), } end return heros end local StdDinerRankTime = toUnixtime("20190101"..string.format("%02x", RESET_RANK_TIME)) --跨天时间 function Role:getCurDinerRankKey() local now = skynet.timex() local idx = 1 if math.floor((now - StdDinerRankTime) / 86400) % 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:recordRankTeam(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 end return RolePlugin