MonsterHunt = {} local this = {} local VAR = { --积分存储 MONSTER_HUNT_INTEGRAL = "R$_MONSTER_HUNT_INTEGRAL", --时间记录 MONSTER_HUNT_TIME_INFO = "R$_MONSTER_HUNT_TIME_INFO", --重置状态 MONSTER_HUNT_STATE = "R$_MONSTER_HUNT_STATE", --通知刷新次数 MONSTER_HUNT_NOTICE_COUNT = "G$MONSTER_HUNT_NOTICE_COUNT", } local GLOBAL_ID = { INTEGRAL_2_MEDAL = 27001, TIME = 27002, GET_EXTRA_HIGH_LIMIT = 27005, SEASON_SETTLE = 27006, } --猎魔勋章的道具ID local MEDAL_ITEM_ID = 10230001 local STATE_OK = 0 local STATE_DENY = 1 function this.getTimeInfo(actor) actor = this.getActor(actor) local timeInfo = getsysvar(actor,VAR.MONSTER_HUNT_TIME_INFO) if timeInfo == nil then return { settleTime = nil, resetTime = nil } else return timeInfo end end function this.setTimeInfo(timeInfo) setsysvar(VAR.MONSTER_HUNT_TIME_INFO, timeInfo) end function this.getState(actor) actor = this.getActor(actor) local state = getsysvar(actor,VAR.MONSTER_HUNT_STATE) return state or 0 end function this.getNoticeCount() return getsysvar(VAR.MONSTER_HUNT_NOTICE_COUNT) or 0 end function this.setNoticeCount(count) setsysvar(VAR.MONSTER_HUNT_NOTICE_COUNT, count) end function this.setState(state) setsysvar(VAR.MONSTER_HUNT_STATE, state) end function this.addIntegral(actor, integral) callonserial(actor, "monsterhurt_add_integral", integral) end function this.clearAllMedal() local roles = getallrolesummaryinfos() if roles then for _, role in ipairs(roles) do local actor = role["actor"] local count = getbagitemcountbyid(actor, MEDAL_ITEM_ID) or 0 if count > 0 then removeitemfrombag(actor, MEDAL_ITEM_ID, count) end end end end function monsterhurt_clear_all_data() this.setTimeInfo(nil) this.setState(STATE_OK) this.setNoticeCount(0) this.setIntegralInfo(nil, nil) this.clearAllMedal() end function monsterhurt_add_integral(actor, integral) local allIntegralInfo = getsysvar(actor,VAR.MONSTER_HUNT_INTEGRAL) if allIntegralInfo == nil then allIntegralInfo = {} end local rid = tonumber(actor:toString()) local actorInfo = allIntegralInfo[rid] if actorInfo == nil then actorInfo = {} allIntegralInfo[rid] = actorInfo end local oldIntegral = actorInfo["integral"] or 0 oldIntegral = oldIntegral + tonumber(integral) actorInfo["integral"] = oldIntegral actorInfo["time"] = getbaseinfo("now") --保存 setsysvar(actor,VAR.MONSTER_HUNT_INTEGRAL, allIntegralInfo) this.loginfo("击杀怪物获得积分", actor, integral, oldIntegral) end function this.getIntegralInfo(actor) actor = this.getActor(actor) local allIntegralInfo = getsysvar(actor,VAR.MONSTER_HUNT_INTEGRAL) if allIntegralInfo == nil then allIntegralInfo = {} end return allIntegralInfo end function this.setIntegralInfo(actor,intervalInfo) actor = this.getActor(actor) setsysvar(actor, VAR.MONSTER_HUNT_INTEGRAL, intervalInfo) end function this.clearIntegralInfo() callonserial("monsterhurt_clear_integral_info") end function monsterhurt_clear_integral_info() setsysvar(VAR.MONSTER_HUNT_INTEGRAL, nil) end function this.getActor(actor) if actor == nil then return getactor(0,0) else return actor end end function this.monsterDie(ownerId, monsterCfgId) -- 不在赛季时间内不生效 if not this.isSeasonTime() then return end local monsterHuntID = ConfigDataManager.getTableValue("cfg_monster", "monsterhunt", "id", monsterCfgId) if string.isNullOrEmpty(monsterHuntID) then return end local config = ConfigDataManager.getById("cfg_monsterHunt", tonumber(monsterHuntID)) if config == nil then return end if ownerId == nil or tonumber(ownerId) <= 0 then this.logerror("怪物击杀者为空", ownerId, monsterCfgId) return end local actor = getactor(tonumber(ownerId)) local state = this.getState(actor) if state == STATE_DENY then this.loginfo("重置之前不积累积分") return end local strLevel = config["level"] local strNum = config["number"] local selfLevel = getbaseinfo(actor, "level") local levelPair = string.split(strLevel, "|") local index = 0 for i, levelStr in pairs(levelPair) do local lowHigh = string.split(levelStr, "#") local low = tonumber(lowHigh[1]) local high = tonumber(lowHigh[2]) if low <= selfLevel and selfLevel <= high then index = i break end end if index == 0 then return end local strNums = string.split(strNum, "#") local strNum = strNums[index] if strNum == nil then return end local num = tonumber(strNum) --增加积分 this.addIntegral(actor, num) end function this.isSeasonTime() local value = ConfigDataManager.getTableValue("cfg_global","value", "id", GLOBAL_ID.SEASON_SETTLE) if string.isNullOrEmpty(value) then return true end local seasons = string.split(value, "|") for _, seasonInfo in ipairs(seasons) do local beginTime = string.split(string.split(seasonInfo, "&")[2], "#") local endTime = string.split(string.split(seasonInfo, "&")[3], "#") local beginSec = this.convertToTimestamp(tonumber(beginTime[1]), tonumber(beginTime[2]), tonumber(beginTime[3]), tonumber(beginTime[4])) local endSec = this.convertToTimestamp(tonumber(endTime[1]), tonumber(endTime[2]), tonumber(endTime[3]), tonumber(endTime[4])) local nowSec = getbaseinfo("nowsec") if nowSec >= beginSec and nowSec <= endSec then return true end end return false end function this.convertToTimestamp(year, month, day, hour) return os.time({ year = year, month = month, day = day, hour = hour or 0, min = 0, sec = 0 }) end --获得积分和勋章的转换比 function this.medalScaleByIntegral(integral) local globalCfg = ConfigDataManager.getTableValue("cfg_global", "value", "id", GLOBAL_ID.INTEGRAL_2_MEDAL) if globalCfg == nil then return 0 end local items = string.split(globalCfg, "|") local prevKv; local prevK = 0 local prevV = 0 local currK = 0 local currV = 0 for _, curr in pairs(items) do local currKv = string.split(curr, "#") if prevKv ~= nil then prevK = tonumber(prevKv[1]) prevV = tonumber(prevKv[2]) currK = tonumber(currKv[1]) currV = tonumber(currKv[2]) if integral >= prevK and integral <= currK then return prevV end end prevKv = currKv end return currV end function this.getTimeConfig() local timeCfg = ConfigDataManager.getTableValue("cfg_global", "value", "id", GLOBAL_ID.TIME) if string.isNullOrEmpty(timeCfg) then return nil end local items = string.split(timeCfg, "#") if table.isNullOrEmpty(items) then return nil end return tonumber(items[1]), tonumber(items[2]) end function this.checkTimeInMinuteHeart(hour, settleHour, settleTime) if tonumber(hour) ~= tonumber(settleHour) then --不在刷新的时间点 return false end if settleTime ~= nil and settleTime > 0 then local now = getbaseinfo("now") local diff = datediff(tonumber(settleTime), now, "day") if diff == 0 then --刷新过了 return false end end return true end function this.getRankList(integralInfo) local medalTotal = 0 local integralTotal = 0 local rankList = {} local index = 0 for id, roleIntegralInfo in pairs(integralInfo) do local integral = roleIntegralInfo["integral"] or 0 local time = roleIntegralInfo["time"] or 0 if integral > 0 then integralTotal = integralTotal + integral table.insert(rankList, { rid = id, integral = integral, time=time }) end end --计算勋章总数 local medalScale = this.medalScaleByIntegral(integralTotal) or 0 medalTotal = math.floor(integralTotal * medalScale / 10000) --计算排名 table.sort(rankList, function(a, b) if a.integral == b.integral then return a.time < b.time else return a.integral > b.integral end end) for _, rankItem in pairs(rankList) do index = index + 1 rankItem["rank"] = index end local rewardPercentTotal = this.getSumRewardPercentByRankList(rankList) for _, rankItem in pairs(rankList) do local rankNum = rankItem.rank local percent, _ = this.getRewardPercentByRank(rankNum) local scale = percent / rewardPercentTotal local medalCount = math.floor( medalTotal * scale ) rankItem["medalCount"] = medalCount --this.loginfo("id", rankItem.rid, "排名", rankNum, "瓜分比例", scale, "瓜分比率", percent, "总比率", rewardPercentTotal,"积分",rankItem.integral, "瓜分勋章数量", medalCount, "总勋章数量", medalTotal) end return rankList, medalTotal,integralTotal end function this.getSumRewardPercentByRankList(rankList) local total = 0 for _, rankItem in pairs(rankList) do local rankNum = rankItem.rank local percent, _ = this.getRewardPercentByRank(rankNum) total = total + percent end return total end --是否能获得额外的积分 function this.isGetExtra(selfIntegral) local highLimit = ConfigDataManager.getTableValue("cfg_global", "value", "id", GLOBAL_ID.GET_EXTRA_HIGH_LIMIT) if string.isNullOrEmpty(highLimit) then return false end return selfIntegral >= tonumber(highLimit) end --结算 function this.Settle(hour, settleHour) if this.getState() == STATE_DENY then this.loginfo("未重置状态下不能结算") return end local timeInfo = this.getTimeInfo() local settleTime = timeInfo.settleTime local ok = this.checkTimeInMinuteHeart(hour, settleHour, settleTime) this.loginfo("是否可以结算", ok, timeInfo) if not ok then return end --先把状态改掉 this.setState(STATE_DENY) --执行结算 local integralInfo = this.getIntegralInfo(nil) local rankList, medalTotal,integralTotal = this.getRankList(integralInfo) this.loginfo("结算数据", medalTotal, rankList) if medalTotal == 0 then this.loginfo("可分配的勋章数量为0", medalTotal, rankList) return end local rankMap = {} for rankNum, rankItem in pairs(rankList) do local item = rankMap[rankNum] if item == nil then item = {} rankMap[rankNum] = item end table.insert(item, rankItem) end this.loginfo("rankMap", rankMap) for rankNum, idList in pairs(rankMap) do local percent, item, extraMedalCount = this.getRewardPercentByRank(rankNum) if percent >= 0 then for _, rankItem in pairs(idList) do local rid = rankItem.rid local integral = rankItem.integral local medalCount = rankItem.medalCount local rewardMap = {} if not string.isNullOrEmpty(extraMedalCount) and this.isGetExtra(integral) then medalCount = medalCount + tonumber(extraMedalCount) end rewardMap[MEDAL_ITEM_ID] = medalCount if not string.isNullOrEmpty(item) then local itemMap = string.toIntIntMap(item, "#", "|") if itemMap ~= nil then table.mergeTable(rewardMap, itemMap) else error("奖励配置格式格式错误", item) end end this.sendRewardToMail(getactor(rid),rid,rankItem.time,medalTotal,integralTotal , rankNum, integral, medalCount, rewardMap) end end end --设置结算时间 local timeInfo = this.getTimeInfo() timeInfo.settleTime = getbaseinfo("now") this.setTimeInfo(timeInfo) end --重置 function this.Reset(hour, resetHour) local timeInfo = this.getTimeInfo() local resetTime = timeInfo.resetTime local ok = this.checkTimeInMinuteHeart(hour, resetHour, resetTime) this.loginfo("是否可以重置", ok, timeInfo) if not ok then return end this.clearIntegralInfo() local timeInfo = this.getTimeInfo() timeInfo.resetTime = getbaseinfo("now") this.setTimeInfo(timeInfo) this.setState(STATE_OK) this.loginfo("重置完成,打印相关数据", this.getTimeInfo(), this.getIntegralInfo(nil), this.getState()) end function this.sendRewardToMail(actor,rid,time,medalTotal, integralTotal, rank, integral, medalCount, rewardMap) local config = ConfigDataManager.getById("cfg_mail", MailConfig.MONSTER_HUNT_INTEGRAL) if config == nil then this.logerror(actor, "奖励邮件配置不存在", MailConfig.MONSTER_HUNT_INTEGRAL) this.loginfo("奖励入包", actor, rank, integral, medalCount, rewardMap) additemmaptobag(actor, rewardMap, 0, 9999, "猎魔积分") else -- local title = config["title"] -- local content = config["content"] -- content = string.format(content, integralTotal, medalTotal, rank, medalCount) -- sendmail(actor, title, content, rewardMap) sendconfigmailbyrid(actor, rid, MailConfig.MONSTER_HUNT_INTEGRAL, rewardMap, integralTotal .. "#" .. medalTotal .. "#" .. rank .. "#" .. medalCount) this.loginfo("发送奖励邮件", actor, rewardMap) end --记录日志 gameDebug.debug(this.saveLog,actor,time,integral, medalCount, rank) end function this.saveLog(actor,time,integral,medalCount,rank) local roleName = getbaseinfo(actor, "rolename") local level = getbaseinfo(actor, "level") local lastLoginTime = getbaseinfo(actor, "logintime") local loginLong = getbaseinfo(actor, "loginlong") / 60 local rechargeTotal = RechargeRecord.getTotalCount(actor) local lastGetIntegralTime = os.date('%Y-%m-%d %H:%M:%S', math.floor(time / 1000)) logBody = {} logBody["角色名字"] = roleName logBody["等级"] = level logBody["最后登录时间"] = lastLoginTime logBody["登录时长"] = loginLong logBody["充值金额"] = rechargeTotal logBody["最后获得积分时间"] = lastGetIntegralTime logBody["杀怪积分"] = integral logBody["勋章数量"] = medalCount logBody["排名"] = rank local logContent = "" for k, v in pairs(logBody) do logContent = logContent .. k .. "=" .. v .. "," end logContent = string.sub(logContent,1, string.len(logContent) - 1) logop(actor, LogOpType.MONSTER_HUNT, logContent) end function this.getRewardPercentByRank(rank) local configList = ConfigDataManager.getTable("cfg_monsterHuntReward") local selfScale = 0 local otherReward = nil local extraMedalCount = nil for _, config in pairs(configList) do local ranks = string.split(config.rank, "#") local rewardScale = tonumber(config.reward) local lowRank = tonumber(ranks[1]) local highRank = tonumber(ranks[2]) if lowRank <= rank and rank <= highRank then selfScale = rewardScale otherReward = config.item extraMedalCount = config.extra end end --this.loginfo("根据排名获得奖励比率", rank, selfScale, otherReward, extraMedalCount) return selfScale, otherReward,extraMedalCount end function this.checkSettleAndReset() local serverType = getbaseinfo("servertype") if serverType == 2 then --跨服不用结算 return end local settleHour, resetHour = this.getTimeConfig() this.loginfo("检查结算和重置", settleHour, resetHour) if settleHour == nil or resetHour == nil then return end local hour = getbaseinfo("hour") this.Settle(hour, settleHour) this.Reset(hour, resetHour) end function this.buildOneRole(id) local actor = getactor(id) local role = {} role["career"] = getbaseinfo(actor, "getbasecareer") role["name"] = getbaseinfo(actor, "rolename") local serverId = getbaseinfo(actor, "originalserverid") role["serverid"] = serverId role["online"] = getbaseinfo(actor, "onlinestate") return role end function this.rankList(actor) local integralInfo = this.getIntegralInfo(actor) local rankList,medalTotal,integralTotal = this.getRankList(integralInfo) local resRankList = {} for _, rankItem in pairs(rankList) do local newItem = { rid = rankItem.rid, integral = rankItem.integral, medal= rankItem.medalCount, rank = rankItem.rank, roleInfo = this.buildOneRole(rankItem.rid) } table.insert(resRankList, newItem) end this.loginfo(actor, "总勋章数量", tostring(medalTotal),"总积分数量",integralTotal,"榜列表", resRankList) sendluamsg(actor, LuaMessageIdToClient.RES_MONSTER_HUNT_RANK, resRankList) end function this.notice() local serverType = getbaseinfo("servertype") if serverType == 2 then --跨服不用结算 return end local count = this.getNoticeCount() count = count + 1 this.setNoticeCount(count) if count % 5 == 0 then --每5分中发送通知 this.sendNotice() end end function this.getNameByIndex(rankList, index) if table.isNullOrEmpty(rankList) then return "" end if #rankList >= index then local item = rankList[index] local rid = item.rid local actor = getactor(rid) local name = getbaseinfo(actor, "rolename") return name end return "" end function this.sendNotice() local integralInfo = this.getIntegralInfo(nil) local rankList = this.getRankList(integralInfo) local first = this.getNameByIndex(rankList, 1) local second = this.getNameByIndex(rankList, 2) local third = this.getNameByIndex(rankList, 3) local allplayer = getallplayer() for _, id in pairs(allplayer) do local actor = getactor(id) noticeTip.noticeinfo(actor, StringIdConst.TEXT27001, first, second, third) end end function this.info(actor) if not this.isSeasonTime() then sendluamsg(actor, LuaMessageIdToClient.RES_MONSTER_HUNT_INFO, {settleSec = 0, resetSec= 0}) return end local settleHour, resetHour = this.getTimeConfig() local res if settleHour == nil or resetHour == nil then res = { settleSec= 0, resetSec= 0 } else local timeInfo = this.getTimeInfo(actor) local settleSec = this.getTargetDateTimeSec(settleHour, timeInfo.settleTime) local resetSec = this.getTargetDateTimeSec(resetHour, timeInfo.resetTime) res = { settleSec= settleSec, resetSec= resetSec } end this.loginfo("信息", res) sendluamsg(actor, LuaMessageIdToClient.RES_MONSTER_HUNT_INFO, res) end --今天是否刷过了 function this.todayIsRefresh(prevRefreshTimeMills) if prevRefreshTimeMills == nil or prevRefreshTimeMills <= 0 then return false end --this.loginfo("prevRefreshTimeMills", prevRefreshTimeMills, type(prevRefreshTimeMills)) local now = getbaseinfo("now") local diffDays = datediff(now, prevRefreshTimeMills, "day") return diffDays == 0 end function this.getTargetDateTimeSec(hour, prevRefreshTimeMills) local dateTimeFormat = "%s-%s-%s %s:%s:%s" local now = getbaseinfo("now") local target local todayIsRefresh = this.todayIsRefresh(prevRefreshTimeMills) if todayIsRefresh then --加一天 target = dateadd(now, 1) else local y = year(now) local m = month(now) local d = day(now) local dateTimeString = string.format(dateTimeFormat, y, m, d, hour, 0, 0) local t = timestamp(dateTimeString) if t > now then this.loginfo("刷新间隔计算1", todayIsRefresh, dateTimeString, t, now ) --今天刷 --return datediff(t,now, "second") return math.round(t / 1000) else --明天刷 target = dateadd(now, 1) end end local y = year(target) local m = month(target) local d = day(target) local dateTimeString = string.format(dateTimeFormat, y, m, d, hour, 0, 0) local t = timestamp(dateTimeString) this.loginfo("刷新间隔计算2", todayIsRefresh, dateTimeString, t, now ) --return datediff(t,now, "second") return math.round(t / 1000) end function this.loginfo(...) info("[猎魔勋章]", ...) end function this.logerror(...) error("[猎魔勋章]", ...) end function MonsterHunt.GetMonsterHuntIntegralKey() return VAR.MONSTER_HUNT_INTEGRAL; end function MonsterHunt.CombineMonsterHuntIntegral(varData) if table.isNullOrEmpty(varData) then return end this.loginfo("猎魔积分合服数据", varData) local currIntegralInfo = this.getIntegralInfo(nil) for sid, integralInfo in pairs(varData) do table.merge(currIntegralInfo, integralInfo) end this.setIntegralInfo(nil, currIntegralInfo) end --怪物死亡触发 function MonsterHunt.MonsterDie(ownerId, monsterCfgId) gameDebug.debug(this.monsterDie, ownerId, monsterCfgId) end --结算 function MonsterHunt.CheckSettleAndReset() gameDebug.debug(this.checkSettleAndReset) end function MonsterHunt.Notice() gameDebug.debug(this.notice) end function MonsterHunt.RankList(actor) gameDebug.debug(this.rankList, actor) end --@lua monsterhuntinfo function MonsterHunt.Info(actor) gameDebug.debug(this.info, actor) end --- func desc 检查赛季是否结束 function MonsterHunt.checkSeason() local value = ConfigDataManager.getTableValue("cfg_global","value", "id", GLOBAL_ID.SEASON_SETTLE) if string.isNullOrEmpty(value) then return end local seasons = string.split(value, "|") for _, seasonInfo in ipairs(seasons) do local timeInfo = string.split(string.split(seasonInfo, "&")[3], "#") local year = tonumber(timeInfo[1]) local month = tonumber(timeInfo[2]) local day = tonumber(timeInfo[3]) local hour = tonumber(timeInfo[4]) local nowSec = getbaseinfo("nowsec") local date = TimeUtil.timeToDate(nowSec) if date.year == year and date.month == month and date.day == day and date.hour == hour and date.min == 0 then info("猎魔赛季结算, 重置所有数据, year-",year,"month-",month,"day-",day,"hour-",hour) callonserial("monsterhurt_clear_all_data") -- this.resetAllData() break end end end --打印排行榜列表 --@lua monsterhuntranklist function monsterhuntranklist(actor) this.rankList(actor) end --@lua monsterhuntchecksettleandreset function monsterhuntchecksettleandreset() this.checkSettleAndReset() end --@lua monsterhuntsendnotice function monsterhuntsendnotice() this.sendNotice() end -- @lua monsterhuntinfo function monsterhuntinfo(actor) this.info(actor) end -- @createMonster 80006 -- @lua monstercleartimeinfo function monstercleartimeinfo(actor) this.setTimeInfo(nil) this.setState(nil) end --- func desc ---@param actor any function clall(actor) callonserial("monsterhurt_clear_all_data") end --- func desc ---@param actor any function allhunt(actor) local timeInfo = getsysvar(actor,VAR.MONSTER_HUNT_TIME_INFO) local state = getsysvar(actor,VAR.MONSTER_HUNT_STATE) local count = getsysvar(VAR.MONSTER_HUNT_NOTICE_COUNT) or 0 local allIntegralInfo = getsysvar(actor,VAR.MONSTER_HUNT_INTEGRAL) lg("时间信息:",timeInfo,"状态:",state,"通知次数:",count,"积分信息:",allIntegralInfo) end