123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- --- 离线挂机
- local this = {}
- onHook = {}
- --- 获取离线挂机信息
- ---@param actor 玩家对象
- function onHook.getOffLineOnHookInfo(actor)
- local onHookInfo = getonhookinfo(actor)
- local duration = tonumber(onHookInfo["duration"])
- local fightExp = getplaydef(actor, PlayerDefKey.offline.FIGHT_EXP)
- if string.isNullOrEmpty(fightExp) then
- fightExp = 0
- end
- local offlineStartTime = getplaydef(actor, PlayerDefKey.offline.START_TIME)
- local offlineEndTime = getplaydef(actor, PlayerDefKey.offline.END_TIME)
- if not string.isNullOrEmpty(offlineEndTime) then
- duration = math.round((offlineEndTime - offlineStartTime) / 1000)
- end
- local offlineTimeout = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.OFFLINE_ON_HOOK_TIMEOUT)
- local timeout = duration > offlineTimeout * 60
- duration = timeout and offlineTimeout * 60 or duration
- local secondDiff = this.calcBubblePointTime(actor, offlineTimeout)
- -- 泡点经验
- local bubblePointExp = getplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_EXP)
- if string.isNullOrEmpty(bubblePointExp) then
- bubblePointExp = 0
- end
- onHookInfo["freeExp"] = tostring(bubblePointExp)
- -- 泡点时长与总离线挂机时长
- onHookInfo["freeDuration"] = math.round(secondDiff)
- onHookInfo["duration"] = math.round(duration)
- onHookInfo["fightDuration"] = math.round(duration - secondDiff)
- onHookInfo["fightExp"] = tostring(fightExp)
- local isReceive = getplaydef(actor, PlayerDefKey.offline.IS_RECEIVE)
- if string.isNullOrEmpty(isReceive) then
- isReceive = false
- end
- onHookInfo["receiveExp"] = isReceive
- local totalExp = getplaydef(actor, PlayerDefKey.offline.TOTAL_EXP)
- if string.isNullOrEmpty(totalExp) then
- totalExp = 0
- end
- local expLimit = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.OFFLINE_ON_HOOK_EXP_LIMIT)
- local total = totalExp + bubblePointExp + fightExp
- if expLimit and tonumber(expLimit) < total then
- total = tonumber(expLimit)
- end
- onHookInfo["totalExp"] = tostring(total)
- local openBubbleTime = getplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_START)
- local mapId = getplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_MAP)
- if not string.isNullOrEmpty(openBubbleTime) and tonumber(openBubbleTime) >= tonumber(offlineStartTime) then
- local temp = {}
- temp[openBubbleTime] = mapId
- onHookInfo["openBubbleMap"] = temp
- end
- -- 如果后端服务重启,则需要重新计算挂机超时时间点
- if timeout then
- onHookInfo["timeout"] = offlineStartTime + offlineTimeout * TimeUnit.MINUTE * TimeUnit.MILLISECOND
- end
- sendluamsg(actor, LuaMessageIdToClient.RES_OFFLINE_ON_HOOK_INFO, onHookInfo)
- end
- --- 请求领取离线挂机经验
- ---@param actor 玩家对象
- function onHook.reqReceiveOfflineOnHookExp(actor)
- -- 领取过离线挂机经验直接返回
- if getplaydef(actor, PlayerDefKey.offline.IS_RECEIVE) then
- return
- end
- -- 计算角色泡点经验
- local bubblePointExp = getplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_EXP)
- if string.isNullOrEmpty(bubblePointExp) then
- bubblePointExp = 0
- end
- local fightExp = getplaydef(actor, PlayerDefKey.offline.FIGHT_EXP)
- if string.isNullOrEmpty(fightExp) then
- fightExp = 0
- end
- local totalExp = getplaydef(actor, PlayerDefKey.offline.TOTAL_EXP)
- if string.isNullOrEmpty(totalExp) then
- totalExp = 0
- end
- local exp = bubblePointExp + fightExp + totalExp
- local expLimit = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.OFFLINE_ON_HOOK_EXP_LIMIT)
- exp = exp > tonumber(expLimit) and tonumber(expLimit) or exp
- additemtobag(actor, ItemConfigId.EXP, exp, 0, 9999, '离线挂机')
- setplaydef(actor, PlayerDefKey.offline.IS_RECEIVE, true)
- end
- --- 角色登录存储泡点结束时间与离线挂机结束时间
- ---@param actor 玩家对象
- function onHook.login(actor)
- onHook.setOfflineState(actor, 0)
- local offlineTimeout = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.OFFLINE_ON_HOOK_TIMEOUT)
- local offlineStartTime = getplaydef(actor, PlayerDefKey.offline.START_TIME)
- local offlineBubblePointStart = getplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_START)
- local serverStart = getsysvar(SystemVarConst.SERVER_START)
- -- 角色离线挂机开始时间小于服务器最新启动时间则表示玩家离线挂机期间服务器重启过
- local now = getbaseinfo(actor, "now")
- local fightExp = getplaydef(actor, PlayerDefKey.offline.FIGHT_EXP)
- local isFirstLogin = getplaydef(actor, "T$_isResetReceiveFlag")
- if offlineStartTime and serverStart and tonumber(serverStart) > tonumber(offlineStartTime) and not isFirstLogin then
- -- 设置已经重置过领取经验标识
- setplaydef(actor, "T$_isResetReceiveFlag", 1)
- -- 设置领取经验为false,防止服务器重启领取经验标识为true,导致玩家无法领取离线挂机经验
- setplaydef(actor, PlayerDefKey.offline.IS_RECEIVE, false)
- -- 判断当前角色是否在安全区内,如果不在安全区,根据配表计算战斗经验
- if string.isNullOrEmpty(offlineBubblePointStart) then
- local lastTime = getplaydef(actor, PlayerDefKey.offline.LAST_TIME)
- local fightTime = tonumber(now) - tonumber(lastTime)
- local timeoutMillisecond = tonumber(offlineTimeout * TimeUnit.MINUTE * TimeUnit.MILLISECOND)
- fightTime = fightTime > timeoutMillisecond and timeoutMillisecond or fightTime
- local mapId = getbaseinfo(actor, "map")
- local patrolState = getplaydef(actor, PlayerDefKey.offline.PATROL_STATE)
- local monsterState = patrolState and 2 or 1
- local expConfig = ConfigDataManager.getTableValue("cfg_hangupReboot", "monstergroup", "mapid", mapId, "monstername", monsterState)
- if not string.isNullOrEmpty(expConfig) then
- local second = string.split(expConfig, "#")[1]
- local exp = string.split(expConfig, "#")[2]
- local step = math.round((fightTime / 1000) / second)
- if step > 0 then
- local baseExp = fightExp and tonumber(fightExp) or 0
- setplaydef(actor, PlayerDefKey.offline.FIGHT_EXP, baseExp + (tonumber(exp) * step))
- end
- end
- end
- end
- if offlineBubblePointStart then
- local offlineBubblePointEnd = getplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_END)
- if string.isNullOrEmpty(offlineBubblePointEnd) and this.checkBubblePointArea(actor) then
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_END, now)
- -- 将离线泡点经验持久化,如果上次离线的泡点经验没有领取则累加
- local onHookInfo = getonhookinfo(actor)
- if table.isNullOrEmpty(onHookInfo) then
- return
- end
- local bubblePointExp = getplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_EXP)
- local exp = this.calcBubblePointExp(actor, this.calcBubblePointTime(actor, offlineTimeout))
- if string.isNullOrEmpty(bubblePointExp) then
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_EXP, exp)
- else
- local bubbleExp = tonumber(bubblePointExp) + exp
- if this.checkExpLimit(actor, fightExp, bubbleExp) then
- local expLimit = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.OFFLINE_ON_HOOK_EXP_LIMIT)
- local totalExp = getplaydef(actor, PlayerDefKey.offline.TOTAL_EXP)
- bubbleExp = tonumber(expLimit) - fightExp - totalExp
- end
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_EXP, bubbleExp)
- end
- end
- end
- if offlineStartTime then
- local offlineEndTime = getplaydef(actor, PlayerDefKey.offline.END_TIME)
- if string.isNullOrEmpty(offlineEndTime) then
- setplaydef(actor, PlayerDefKey.offline.END_TIME, now)
- end
- end
- end
- --- 角色退出清空泡点相关信息
- ---@param actor 玩家对象
- function onHook.logout(actor)
- -- 角色重置过领取经验标识重置
- setplaydef(actor, "T$_isResetReceiveFlag", nil)
- -- 重置结束时间
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_END, nil)
- setplaydef(actor, PlayerDefKey.offline.END_TIME, nil)
- -- 领取过经验后重置存储的经验信息
- if getplaydef(actor, PlayerDefKey.offline.IS_RECEIVE) then
- setplaydef(actor, PlayerDefKey.offline.IS_RECEIVE, false)
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_EXP, nil)
- setplaydef(actor, PlayerDefKey.offline.FIGHT_EXP, nil)
- setplaydef(actor, PlayerDefKey.offline.TOTAL_EXP, nil)
- else
- local totalExp = getplaydef(actor, PlayerDefKey.offline.TOTAL_EXP)
- if string.isNullOrEmpty(totalExp) then
- totalExp = 0
- end
- local bubblePointExp = getplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_EXP)
- if not string.isNullOrEmpty(bubblePointExp) then
- totalExp = totalExp + bubblePointExp
- end
- local fightExp = getplaydef(actor, PlayerDefKey.offline.FIGHT_EXP)
- if not string.isNullOrEmpty(fightExp) then
- totalExp = totalExp + fightExp
- end
- local expLimit = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.OFFLINE_ON_HOOK_EXP_LIMIT)
- if expLimit and totalExp > tonumber(expLimit) then
- totalExp = tonumber(expLimit)
- end
- setplaydef(actor, PlayerDefKey.offline.TOTAL_EXP, totalExp)
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_EXP, nil)
- setplaydef(actor, PlayerDefKey.offline.FIGHT_EXP, nil)
- end
- local level = tonumber(getbaseinfo(actor, "level"))
- -- 是否达到开启离线挂机的等级
- local offlineOnHookLevel = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.OFFLINE_ON_HOOK_LEVEL)
- if level >= tonumber(offlineOnHookLevel) then
- -- 记录离线挂机开启时间
- setplaydef(actor, PlayerDefKey.offline.START_TIME, getbaseinfo(actor, "now"))
- if this.checkBubblePointArea(actor) then
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_MAP, getbaseinfo(actor, "map"))
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_START, getbaseinfo(actor, "now"))
- else
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_MAP, nil)
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_START, nil)
- end
- end
- end
- --- 玩家传送后判断是否进入泡点区域
- ---@param actor 玩家对象
- function onHook.afterTransmit(actor)
- -- 非离线挂机玩家不处理
- if not isofflineplay(actor) then
- return
- end
- -- 是否达到开启离线挂机的等级,离线挂机传送只可能是免费复活后传送,所以此处不需要判断区域是否为泡点区域
- local offlineOnHookLevel = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.OFFLINE_ON_HOOK_LEVEL)
- if tonumber(getbaseinfo(actor, "level")) >= tonumber(offlineOnHookLevel) then
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_MAP, getbaseinfo(actor, "map"))
- setplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_START, getbaseinfo(actor, "now"))
- end
- end
- --- 检查区域是否是泡点区域
- ---@param actor 玩家对象
- ---@return boolean 是否在泡点区域
- function this.checkBubblePointArea(actor)
- local level = tonumber(getbaseinfo(actor, "level"))
- local mapId = getbaseinfo(actor, "map")
- local safeArea = getbaseinfo(actor, "safearea")
- local configString = ConfigDataManager.getTableValue("cfg_bubble_point", "expMap", "id", level)
- local configMap = string.toStringStringMap(configString, "#", "|")
- local checkArea = false
- for key, value in pairs(configMap) do
- mapId = tonumber(mapId)
- key = tonumber(key)
- value = tonumber(value)
- if mapId == key then
- if value == 3 then
- checkArea = true
- elseif value == 2 and safeArea == false then
- checkArea = true
- elseif value == 1 and safeArea == true then
- checkArea = true
- end
- end
- end
- return checkArea
- end
- --- 计算泡点时长
- ---@param actor 玩家对象
- ---@param duration 离线挂机战斗时长
- ---@return number 泡点时长(s)
- function this.calcBubblePointTime(actor, offlineTimeout)
- local offlineBubblePointStart = getplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_START)
- local offlineBubblePointEnd = getplaydef(actor, PlayerDefKey.offline.BUBBLE_POINT_END)
- if not string.isNullOrEmpty(offlineBubblePointStart)
- and not string.isNullOrEmpty(offlineBubblePointEnd)
- and tonumber(offlineBubblePointEnd) - tonumber(offlineBubblePointStart) > 0 then
- local secondDiff = math.round((tonumber(offlineBubblePointEnd) - tonumber(offlineBubblePointStart)) / 1000)
- -- 泡点时长处理
- if secondDiff > tonumber(offlineTimeout) * 60 then
- secondDiff = tonumber(offlineTimeout) * 60
- local offlineStartTime = getplaydef(actor, PlayerDefKey.offline.START_TIME)
- local diff = (offlineBubblePointStart - offlineStartTime) / 1000
- if offlineBubblePointStart > offlineStartTime then
- if diff > offlineTimeout * 60 then
- secondDiff = 0
- else
- secondDiff = offlineTimeout * 60 - diff
- end
- end
- end
- return secondDiff
- end
- return 0
- end
- --- 根据泡点时长获取泡点经验
- ---@param actor 玩家对象
- ---@param secondDiff 泡点时长(s)
- ---@return number 泡点经验
- function this.calcBubblePointExp(actor, secondDiff)
- if secondDiff == 0 then
- return 0
- end
- local level = tonumber(getbaseinfo(actor, "level"))
- local expInterval = ConfigDataManager.getTableValue("cfg_bubble_point", "expInterval", "id", level)
- if string.isNullOrEmpty(expInterval) then
- gameDebug.print("找不到cfg_bubble_point配置,id:" .. level)
- return 0, 0
- end
- local times = math.round(secondDiff / expInterval)
- local expConfig = ConfigDataManager.getTableValue("cfg_bubble_point", "exp", "id", level)
- local exp = string.split(expConfig, "#")[2]
- return tonumber(exp) * tonumber(times)
- end
- --- 检查离线挂机经验是否超限
- ---@param fightExp number 战斗经验
- ---@param bubblePointExp number 泡点经验
- function this.checkExpLimit(actor, fightExp, bubblePointExp)
- local expLimit = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.OFFLINE_ON_HOOK_EXP_LIMIT)
- if not string.isNullOrEmpty(expLimit) then
- local totalExp = getplaydef(actor, PlayerDefKey.offline.TOTAL_EXP)
- totalExp = totalExp or 0
- fightExp = fightExp or 0
- bubblePointExp = bubblePointExp or 0
- return fightExp + bubblePointExp + totalExp > tonumber(expLimit)
- end
- return false
- end
- --- 保存离线挂机战斗经验
- ---@param actor 玩家对象
- ---@param exp 战斗经验
- function onHook.saveOfflineFightExp(actor, exp)
- -- 是否超时判断
- local start = getplaydef(actor, PlayerDefKey.offline.START_TIME)
- local offlineTimeout = ConfigDataManager.getTableValue("cfg_global", "value", "id", GlobalConfigId.OFFLINE_ON_HOOK_TIMEOUT)
- local now = getbaseinfo(actor, "now")
- if now - start > tonumber(offlineTimeout) * TimeUnit.MINUTE * TimeUnit.MILLISECOND then
- return
- end
- local offlineFightExp = getplaydef(actor, PlayerDefKey.offline.FIGHT_EXP)
- if string.isNullOrEmpty(offlineFightExp) then
- setplaydef(actor, PlayerDefKey.offline.FIGHT_EXP, tonumber(exp))
- else
- if not this.checkExpLimit(actor, offlineFightExp, 0) then
- setplaydef(actor, PlayerDefKey.offline.FIGHT_EXP, tonumber(offlineFightExp) + tonumber(exp))
- end
- end
- end
- --- 设置离线挂机巡逻状态
- ---@param actor table 玩家对象
- ---@param state number 状态 巡逻状态:1 战斗状态:2 无状态:0
- function onHook.setOfflineState(actor, state)
- setofflinepatrolstate(actor, state)
- setplaydef(actor, PlayerDefKey.offline.PATROL_STATE, state)
- end
- --- 记录玩家最后一次离线挂机时间
- ---@param actor table 玩家对象
- function onHook.recordLastTime(actor)
- setplaydef(actor, PlayerDefKey.offline.LAST_TIME, getbaseinfo(actor, "now"))
- end
- --- 记录服务器启动时间
- function onHook.recordStartTime()
- setsysvar(SystemVarConst.SERVER_START, getbaseinfo("now"))
- end
- --- 进入泡点地图设置离线挂机状态
- function onHook.enterMap(actor)
- if this.checkBubblePointArea(actor) then
- setofflinepatrolstate(actor, 0)
- else
- -- 不是泡点地图设置为战斗状态
- setofflinepatrolstate(actor, 2)
- end
- end
|