Files
Endfield-Data/LuaScripts/Common/Utils/DungeonUtils.lua
2026-01-31 21:42:01 +07:00

543 lines
18 KiB
Lua

local DungeonUtils = {}
function DungeonUtils.checkCanOpenPhase(args)
local dungeonId = args.dungeonId or ""
local dungeonSeriesId = args.dungeonSeriesId or ""
local dungeonIdValid = Tables.dungeonTable:ContainsKey(dungeonId)
local dungeonSeriesIdValid = Tables.dungeonSeriesTable:ContainsKey(dungeonSeriesId)
if not dungeonIdValid and not dungeonSeriesIdValid then
logger.error("open failed: both dungeonId and dungeonSeriesId invalid")
return false
end
return true
end
function DungeonUtils.isDungeonUnlock(dungeonId)
return GameInstance.dungeonManager:IsDungeonUnlocked(dungeonId)
end
function DungeonUtils.isDungeonPassed(dungeonId)
return GameInstance.dungeonManager:IsDungeonPassed(dungeonId)
end
function DungeonUtils.isDungeonActive(dungeonId)
return GameInstance.dungeonManager:IsDungeonActive(dungeonId)
end
function DungeonUtils.isDungeonHasHunterMode(dungeonId)
return not string.isEmpty(Tables.dungeonTable[dungeonId].hunterModeRewardId)
end
function DungeonUtils.isHunterModeUnlocked()
return GameInstance.dungeonManager:IsHunterModeUnlocked()
end
function DungeonUtils.isDungeonCostStamina(dungeonId)
local dungeonCfg = Tables.dungeonTable[dungeonId]
local hasHunterMode = DungeonUtils.isDungeonHasHunterMode(dungeonId)
local hunterModeOpen = DungeonUtils.isHunterModeUnlocked()
if hasHunterMode and hunterModeOpen and dungeonCfg.hunterModeCostStamina > 0 then
return true, dungeonCfg.hunterModeCostStamina
end
if not hasHunterMode and dungeonCfg.costStamina > 0 then
return true, dungeonCfg.costStamina
end
return false, 0
end
function DungeonUtils.diffActionByConditionId(conditionId)
local conditionCfg = Tables.gameMechanicConditionTable[conditionId]
local conditionType = conditionCfg.conditionType
local param = conditionCfg.parameter[0]
if conditionType == GEnums.ConditionType.CheckPassGameMechanicsId then
local preDungeonId = param.valueStringList[0]
local dungeonTypeCfg = Tables.dungeonTypeTable[Tables.dungeonTable[preDungeonId].dungeonCategory]
local _, instId = GameInstance.player.mapManager:GetMapMarkInstId(dungeonTypeCfg.mapMarkType, Tables.dungeonTable[preDungeonId].dungeonSeriesId)
MapUtils.openMap(instId)
elseif conditionType == GEnums.ConditionType.CheckSceneGrade then
local levelId = param.valueStringList[0]
MapUtils.openMap(nil, levelId)
elseif conditionType == GEnums.ConditionType.QuestStateEqual then
local questId = param.valueStringList[0]
local missionId = GameInstance.player.mission:GetMissionIdByQuestId(questId)
PhaseManager:OpenPhase(PhaseId.Mission, {autoSelect = missionId, useBlackMask = true})
elseif conditionType == GEnums.ConditionType.MissionStateEqual then
local missionId = param.valueStringList[0]
PhaseManager:OpenPhase(PhaseId.Mission, {autoSelect = missionId, useBlackMask = true})
else
Notify(MessageConst.SHOW_TOAST, "Error")
end
end
function DungeonUtils.getConditionCanJump(dungeonId, conditionId)
local conditionCfg = Tables.gameMechanicConditionTable[conditionId]
local conditionType = conditionCfg.conditionType
if conditionCfg.parameter.length == 0 then
return false
end
local param = conditionCfg.parameter[0]
if conditionType == GEnums.ConditionType.CheckPassGameMechanicsId then
local preDungeonId = param.valueStringList[0]
local dungeonCfg = Tables.dungeonTable[dungeonId]
local preDungeonCfg = Tables.dungeonTable[preDungeonId]
return dungeonCfg.dungeonSeriesId ~= preDungeonCfg.dungeonSeriesId
end
return true
end
function DungeonUtils.getUncompletedConditionIds(dungeonId)
local uncompletedConditionIds = {}
local _, gameUnlockCondition = GameInstance.player.subGameSys:TryGetSubGameUnlockCondition(dungeonId)
for conditionId, completed in pairs(gameUnlockCondition.unlockConditionFlags) do
if not completed then
table.insert(uncompletedConditionIds, conditionId)
end
end
return uncompletedConditionIds
end
function DungeonUtils.groupDungeonsByCondition(dungeonIds)
local rootDungeonIds = {}
for _, v in ipairs(dungeonIds) do
if Tables.GameMechanicGroupByConditionTable:ContainsKey(v) then
table.insert(rootDungeonIds, v)
end
end
local groupDungeonIds = {}
for _, rootDungeonId in ipairs(rootDungeonIds) do
local group = {}
table.insert(group, rootDungeonId)
local _, data = Tables.GameMechanicGroupByConditionTable:TryGetValue(rootDungeonId)
for _, childDungeonId in pairs(data.childGameMechanicsId) do
local exist = false
for _, v in ipairs(dungeonIds) do
if v == childDungeonId then
exist = true
end
end
if exist then
table.insert(group, childDungeonId)
end
end
table.insert(groupDungeonIds, group)
end
return #rootDungeonIds > 0, groupDungeonIds
end
function DungeonUtils.getEntryLocation(levelId, ignoreDomain)
if string.isEmpty(levelId) then
return ""
end
local domainId = DataManager.levelBasicInfoTable:get_Item(levelId).domainName
local levelName = Tables.levelDescTable[levelId].showName
if ignoreDomain then
return levelName
else
local succ, domainDataCfg = Tables.domainDataTable:TryGetValue(domainId)
if succ then
return domainDataCfg.domainName.."-"..levelName
else
return levelName
end
end
end
function DungeonUtils.getListByStr(str)
return string.isEmpty(str) and {} or string.split(str, "\n")
end
function DungeonUtils.getEntryText(dungeonId)
local dungeonCfg = Tables.dungeonTable[dungeonId]
local succ, dungeonTypeCfg = Tables.dungeonTypeTable:TryGetValue(dungeonCfg.dungeonCategory)
local entryText = succ and dungeonTypeCfg.entryText or dungeonCfg.dungeonCategory
return entryText
end
function DungeonUtils.onClickExitDungeonBtn()
local dungeonId = GameInstance.dungeonManager.curDungeonId
if string.isEmpty(dungeonId) then
return
end
if GameWorld.worldInfo.subGame == nil then
return
end
if not string.isEmpty(GameInstance.player.systemActionConflictManager.curProcessingSystemAction) then
logger.warn("DungeonUtils.onClickExitDungeonBtn systemConflict:", GameInstance.player.systemActionConflictManager:GetCurProcessingSystemActionInfo())
return
end
local dungeonCfg = Tables.dungeonTable[dungeonId]
local confirmHint
local succ, dungeonTypeCfg = Tables.dungeonTypeTable:TryGetValue(dungeonCfg.dungeonCategory)
if succ then
confirmHint = GameWorld.worldInfo.subGame.isPass and dungeonTypeCfg.afterSuccStopConfirmText or
dungeonTypeCfg.beforeSuccStopConfirmText
else
confirmHint = "副本类型表中没有配置:" .. dungeonCfg.dungeonCategory
end
local arg = {
content = confirmHint,
onConfirm = function()
GameInstance.dungeonManager:LeaveDungeon()
end,
freezeWorld = true,
pauseGame = true,
showGameSettingBtn = true,
interrupt = {
interruptMessage = { MessageConst.SHOW_DEATH_INFO },
},
}
if succ and dungeonTypeCfg.dungeonType == "dungeon_weeklyraid" then
AudioAdapter.PostEvent("Au_UI_Menu_StripMenuPauseTick_Open")
arg.onCancel = function()
AudioAdapter.PostEvent("Au_UI_Menu_StripMenuPauseTick_Close")
end
end
Notify(MessageConst.SHOW_POP_UP, arg)
end
function DungeonUtils.getDungeonChestCount(sceneId)
local collectionManager = GameInstance.player.collectionManager
local sceneCollectionData = collectionManager:GetSceneData(sceneId)
if not sceneCollectionData then
return 0, 0
end
local chestTag = Tables.dungeonConst.dungeonChestCollectionTag
local _, chestIdList = Tables.collectionLabelTable:TryGetValue(chestTag)
local gainedCount = 0
local maxCount = 0
for _, idCfg in pairs(chestIdList.list) do
local gained = sceneCollectionData:GetItemCurCnt(idCfg.prefabId)
local total = sceneCollectionData:GetItemTotalCnt(idCfg.prefabId)
gainedCount = gainedCount + gained
maxCount = maxCount + total
end
return gainedCount, maxCount
end
function DungeonUtils.TryShowDungeonInsufficientStaminaPopup(dungeonId, confirmCallback)
local dungeonCfg = Tables.dungeonTable[dungeonId]
local serializedHintKey = string.format(DungeonConst.IGNORE_STAMINA_SHORT_HINT_FORMAT, dungeonCfg.dungeonSeriesId)
local succ, ignoreHint = ClientDataManagerInst:GetBool(serializedHintKey, false, false, DungeonConst.SERIALIZED_CATEGORY)
if ignoreHint then
confirmCallback()
else
local hasHunterMode = DungeonUtils.isDungeonHasHunterMode(dungeonId)
local hintContent
if hasHunterMode then
if GameInstance.dungeonManager:IsDungeonFirstPassRewardGained(dungeonId) then
hintContent = Language.LUA_DUNGEON_HUNTER_MODE_STAMINA_SHORT_CONFIRM_HINT
else
hintContent = Language.LUA_DUNGEON_HUNTER_MODE_STAMINA_SHORT_WITH_REWARD_CONFIRM_HINT
end
else
hintContent = Language.LUA_DUNGEON_STAMINA_SHORT_CONFIRM_HINT
end
local closuresIsOn = false
Notify(MessageConst.SHOW_POP_UP, {
toggle = {
onValueChanged = function(isOn)
closuresIsOn = isOn
end,
toggleText = Language.LUA_DUNGEON_TODAY_IGNORE_SHORT_STAMINA_HINT,
isOn = false,
},
content = hintContent,
onConfirm = function()
ClientDataManagerInst:SetBool(serializedHintKey, closuresIsOn, false, DungeonConst.SERIALIZED_CATEGORY, true, EClientDataTimeValidType.CurrentDay)
confirmCallback()
end,
onCancel = function()
end
})
end
end
function DungeonUtils.isDungeonPerfectComplete(dungeonId)
local dungeonManager = GameInstance.dungeonManager
local isComplete = dungeonManager:IsDungeonPassed(dungeonId)
local _, dungeonCfg = Tables.dungeonTable:TryGetValue(dungeonId)
local _, rewardCfg = Tables.rewardTable:TryGetValue(dungeonCfg.extraRewardId)
local hasExtraReward = rewardCfg ~= nil
local collectChestNum, maxChestNum = DungeonUtils.getDungeonChestCount(dungeonCfg.sceneId)
local isPerfectComplete = isComplete and
(not hasExtraReward or dungeonManager:IsDungeonExtraRewardGained(dungeonId)) and
(maxChestNum < 1 or collectChestNum >= maxChestNum)
return isPerfectComplete
end
function DungeonUtils.genFirstPartRewardsInfo(dungeonId)
local firstRowRewards = {}
local dungeonMgr = GameInstance.dungeonManager
local dungeonCfg = Tables.dungeonTable[dungeonId]
local gained = dungeonMgr:IsDungeonFirstPassRewardGained(dungeonId)
local rewardId = dungeonCfg.firstPassRewardId
if not string.isEmpty(rewardId) then
local rewardCfg = Tables.rewardTable[rewardId]
for _, itemBundle in pairs(rewardCfg.itemBundles) do
local itemCfg = Tables.itemTable[itemBundle.id]
table.insert(firstRowRewards, {
id = itemBundle.id,
count = itemBundle.count,
gained = gained,
sortId1 = itemCfg.sortId1,
sortId2 = itemCfg.sortId2,
})
end
end
local hasRecycleReward = not string.isEmpty(dungeonCfg.rewardId)
if hasRecycleReward then
local rewardCfg = Tables.rewardTable[dungeonCfg.rewardId]
for _, itemBundle in pairs(rewardCfg.itemBundles) do
local itemCfg = Tables.itemTable[itemBundle.id]
table.insert(firstRowRewards, {
id = itemBundle.id,
count = itemBundle.count,
sortId1 = itemCfg.sortId1,
sortId2 = itemCfg.sortId2,
})
end
end
table.sort(firstRowRewards, Utils.genSortFunction(UIConst.COMMON_ITEM_SORT_KEYS))
return firstRowRewards
end
function DungeonUtils.genSecondPartRewardsInfo(dungeonId)
local secondRowRewards = {}
local dungeonMgr = GameInstance.dungeonManager
local dungeonCfg = Tables.dungeonTable[dungeonId]
local rewardId = dungeonCfg.extraRewardId
local hasExtraReward = not string.isEmpty(rewardId)
local hunterModeRewardId = dungeonCfg.hunterModeRewardId
local hasHunterModeReward = not string.isEmpty(hunterModeRewardId)
if hasExtraReward then
local gained = dungeonMgr:IsDungeonExtraRewardGained(dungeonId)
local rewardCfg = Tables.rewardTable[rewardId]
for _, itemBundle in pairs(rewardCfg.itemBundles) do
local itemCfg = Tables.itemTable[itemBundle.id]
table.insert(secondRowRewards, {
id = itemBundle.id,
count = itemBundle.count,
gained = gained,
typeTag = DungeonConst.DUNGEON_REWARD_TAG_STATE.Extra,
sortId1 = itemCfg.sortId1,
sortId2 = itemCfg.sortId2,
})
end
table.sort(secondRowRewards, Utils.genSortFunction(UIConst.COMMON_ITEM_SORT_KEYS))
elseif hasHunterModeReward then
local rewardCfg = Tables.rewardTable[hunterModeRewardId]
for _, itemBundle in pairs(rewardCfg.itemBundles) do
local itemCfg = Tables.itemTable[itemBundle.id]
table.insert(secondRowRewards, {
id = itemCfg.id,
typeSortId = 0,
typeTag = DungeonConst.DUNGEON_REWARD_TAG_STATE.Regular,
sortId1 = itemCfg.sortId1,
sortId2 = itemCfg.sortId2,
})
end
for _, itemBundle in pairs(rewardCfg.probItemBundles) do
local itemCfg = Tables.itemTable[itemBundle.id]
table.insert(secondRowRewards, {
id = itemCfg.id,
typeSortId = -1,
typeTag = DungeonConst.DUNGEON_REWARD_TAG_STATE.Random,
sortId1 = itemCfg.sortId1,
sortId2 = itemCfg.sortId2,
})
end
local sortKeys = UIConst.COMMON_ITEM_SORT_KEYS
table.insert(sortKeys, 1, "typeSortId")
table.sort(secondRowRewards, Utils.genSortFunction(sortKeys))
end
return secondRowRewards
end
function DungeonUtils.getRewardsDetailFirstRowTitle(dungeonId)
local dungeonCfg = Tables.dungeonTable[dungeonId]
local langKey = DungeonConst.DUNGEON_FIRST_ROW_REWARDS_TITLE[dungeonCfg.dungeonCategory]
if langKey == nil then
return
end
return Language[langKey]
end
function DungeonUtils.getRewardsDetailSecondRowTitle(dungeonId)
local dungeonCfg = Tables.dungeonTable[dungeonId]
local extraRewardId = dungeonCfg.extraRewardId
local hunterModeId = dungeonCfg.hunterModeRewardId
if not string.isEmpty(extraRewardId) then
return Language.LUA_DUNGEON_REWARD_SHOW_EXTRAREWARD
elseif not string.isEmpty(hunterModeId) then
return Language.LUA_DUNGEON_REWARD_SHOW_HUNTERMODE
else
return "TBD"
end
end
function DungeonUtils.startSubGameLeaveTick(action)
local tickId = LuaUpdate:Add("LateTick", function(deltaTime)
local game = GameWorld.worldInfo.subGame
local leftTime = 0
if game ~= nil then
leftTime = game:GetRealLeaveTimestampForLua() - DateTimeUtils.GetCurrentTimestampBySeconds()
end
if leftTime >= 0 and action ~= nil then
action(leftTime)
end
end)
return tickId
end
function DungeonUtils.onClickDungeonInfoBtn()
local dungeonId = GameInstance.dungeonManager.curDungeonId
if DungeonUtils.isDungeonCharTutorial(dungeonId) then
local curStage = GameWorld.worldInfo.subGame.stage
local charTutorialCfg = Tables.dungeonCharTutorialTable[dungeonId]
local stageCfg = charTutorialCfg.tutorialStageData[CSIndex(curStage)]
GameAction.ManuallyStartGuideGroup(stageCfg.guideGroupId)
else
UIManager:AutoOpen(PanelId.DungeonInfoPopup, { dungeonId = dungeonId, needBindAction = true })
end
end
function DungeonUtils.checkVisibilityDungeonInfoBtn()
if not Utils.isInDungeon() then
return false
end
local curDungeonId = GameInstance.dungeonManager.curDungeonId
if not DungeonUtils.isDungeonCharTutorial(curDungeonId) then
return DungeonUtils.isDungeonHasFeatureInfo(curDungeonId)
end
local game = GameWorld.worldInfo.subGame
if not game then
return false
end
local stage = game.stage
local charTutorialCfg = Tables.dungeonCharTutorialTable[curDungeonId]
local tutorialStageCfg = charTutorialCfg.tutorialStageData[CSIndex(stage)]
return not string.isEmpty(tutorialStageCfg.guideGroupId)
end
function DungeonUtils.isDungeonHasFeatureInfo(dungeonId)
if string.isEmpty(dungeonId) then
return false
end
local succ, dungeonCfg = Tables.dungeonTable:TryGetValue(dungeonId)
return succ and not string.isEmpty(dungeonCfg.featureDesc)
end
function DungeonUtils.checkCanPopupInfoPanel(dungeonId)
if DungeonUtils.isDungeonCharTutorial(dungeonId) then
return false
end
if not DungeonUtils.isDungeonHasFeatureInfo(dungeonId) then
return false
end
if GameInstance.dungeonManager:IsDungeonPassed(dungeonId) then
return false
end
local succ, dungeonCfg = Tables.dungeonTable:TryGetValue(dungeonId)
if succ and dungeonCfg.forceIgnoreFeaturePopup then
return false
end
return true
end
function DungeonUtils.dungeonTypeValidate(dungeonId, dungeonCategory)
local succ, dungeonCfg = Tables.dungeonTable:TryGetValue(dungeonId)
return succ and dungeonCfg.dungeonCategory == dungeonCategory
end
function DungeonUtils.isDungeonTrain(dungeonId)
return DungeonUtils.dungeonTypeValidate(dungeonId, DungeonConst.DUNGEON_CATEGORY.Train)
end
function DungeonUtils.isDungeonCharTutorial(dungeonId)
return DungeonUtils.dungeonTypeValidate(dungeonId, DungeonConst.DUNGEON_CATEGORY.CharTutorial)
end
function DungeonUtils.isDungeonChar(dungeonId)
return DungeonUtils.dungeonTypeValidate(dungeonId, DungeonConst.DUNGEON_CATEGORY.Char)
end
function DungeonUtils.isDungeonChallenge(dungeonId)
return DungeonUtils.dungeonTypeValidate(dungeonId, DungeonConst.DUNGEON_CATEGORY.Challenge)
end
_G.DungeonUtils = DungeonUtils
return DungeonUtils