Initial version - 1.2.0.60

EN: 1.2.0.60
CN: 1.2.0.61
JP: 1.2.0.63
KR: 1.2.0.67
This commit is contained in:
SL1900
2025-12-03 01:00:00 +09:00
commit 5e0d58cfad
3595 changed files with 9373562 additions and 0 deletions
@@ -0,0 +1,438 @@
local BdConvertBuildCtrl = class("BdConvertBuildCtrl", BaseCtrl)
local LocalData = require("GameCore.Data.LocalData")
local newDayTime = UTILS.GetDayRefreshTimeOffset()
BdConvertBuildCtrl._mapNodeConfig = {
TopBar = {
sNodeName = "TopBarPanel",
sCtrlName = "Game.UI.TopBarEx.TopBarCtrl"
},
BuildListContent = {},
BuildListContent_Empty = {},
txt_empty = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_BuildEmpty"
},
BuildList = {
sComponentName = "LoopScrollView"
},
btn_sort_time = {
sComponentName = "UIButton",
callback = "OnBtnClick_SortTime"
},
btn_sort_score = {
sComponentName = "UIButton",
callback = "OnBtnClick_SortScore"
},
img_icon = {
sNodeName = "img_icon_detail",
sComponentName = "Image"
},
txt_title = {sComponentName = "TMP_Text"},
txt_reward = {sComponentName = "TMP_Text"},
sv = {},
svItem = {
sComponentName = "LoopScrollView"
},
txt_SubmitTips = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_BuildTips"
},
txt_srot_timeTitle = {
sComponentName = "TMP_Text",
sLanguageId = "RoguelikeBuild_Manage_SortTime"
},
txt_srot_ScoreTitle = {
sComponentName = "TMP_Text",
sLanguageId = "RoguelikeBuild_Manage_SortScore"
},
txt_Allselect = {sComponentName = "TMP_Text"},
btn_submit = {
sComponentName = "UIButton",
callback = "OnBtnClick_Submit"
},
txt_submit = {
nCount = 2,
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_Submit"
},
btn_submit_none = {
sComponentName = "UIButton",
callback = "OnBtnClick_Submit"
},
BdConvertFinishPanel = {
sCtrlName = "Game.UI.Activity.BdConvert._500001.BdConvertFinishCtrl"
},
bg_anim = {sNodeName = "----BG----", sComponentName = "Animator"},
anim = {
sNodeName = "SafeAreaRoot",
sComponentName = "Animator"
},
txt_detailTips = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_DesTips"
}
}
BdConvertBuildCtrl._mapEventConfig = {
BdConvert_ShowReward = "OnEvent_ShowReward",
BdConvert_FinishPanelClose = "OnEvent_CloseReward",
[EventId.UIBackConfirm] = "OnEvent_BackHome",
[EventId.UIHomeConfirm] = "OnEvent_Home"
}
BdConvertBuildCtrl._mapRedDotConfig = {}
local SortType = {Time = 1, Score = 2}
local SortOrder = {Descending = true, Ascending = false}
local BtnTextColor = {
[true] = Color(0.3288888888888889, 0.43555555555555553, 0.5422222222222223, 1),
[false] = Color(0.7288888888888889, 0.8, 0.8711111111111111, 1)
}
function BdConvertBuildCtrl:Awake()
self._mapNode.BdConvertFinishPanel.gameObject:SetActive(false)
local param = self:GetPanelParam()
if type(param) == "table" then
self.nActId = param[1]
self.nOptionId = param[2]
end
self.actData = PlayerData.Activity:GetActivityDataById(self.nActId)
self.nSortype = SortType.Score
self.nSortOrder = SortOrder.Ascending
self.tbSelected = {}
end
function BdConvertBuildCtrl:OnEnable()
EventManager.Hit(EventId.TemporaryBlockInput, 0.6)
self.tbItemIns = {}
self.mapListItemCtrl = {}
self:InitSort()
self:InitData()
end
function BdConvertBuildCtrl:OnDisable()
if self.tbItemIns ~= nil then
for _, ctrl in pairs(self.tbItemIns) do
self:UnbindCtrlByNode(ctrl)
end
end
if self.mapListItemCtrl ~= nil then
for _, ctrl in pairs(self.mapListItemCtrl) do
self:UnbindCtrlByNode(ctrl)
end
end
end
function BdConvertBuildCtrl:OnDestroy()
end
function BdConvertBuildCtrl:InitData()
self._tbAllBuild = self.actData:GetAllBuildByOpId(self.nOptionId)
self.bdCfg = self.actData:GetBdConvertConfig()
self.contentCfg = ConfigTable.GetData("BdConvertContent", self.nOptionId)
self.data = self.actData:GetBdDataBy(self.nOptionId)
if self.data == nil then
return
end
if self.contentCfg.Icon ~= "" then
self:SetPngSprite(self._mapNode.img_icon, self.contentCfg.Icon)
end
self.tbItem = {}
local tbReward = decodeJson(self.contentCfg.BasicReward)
local tbTemp = {}
for key, value in pairs(tbReward) do
tbTemp[tonumber(key)] = tonumber(value)
end
for _, rewardId in ipairs(self.contentCfg.BasicRewardPreview) do
table.insert(self.tbItem, {
itemId = rewardId,
itemCount = tbTemp[rewardId]
})
end
self._mapNode.svItem:Init(#self.tbItem, self, self.OnRewardItemGridRefresh, self.OnGridBtnClick)
NovaAPI.SetTMPText(self._mapNode.txt_title, self.contentCfg.Des)
NovaAPI.SetTMPText(self._mapNode.txt_reward, ConfigTable.GetUIText("BdConvert_RewardTitle") .. " " .. self.data.nCurSub .. "/" .. self.data.nMaxSub)
local tbTarget = {}
for i = 1, 5 do
local target = self._mapNode.sv.transform:Find("Viewport/Content/target" .. i)
target.gameObject:SetActive(false)
table.insert(tbTarget, target)
end
for index, optionId in ipairs(self.contentCfg.ConvertConditionList) do
local txt_target = tbTarget[index]:Find("txt_target"):GetComponent("TMP_Text")
local targetCfg = ConfigTable.GetData("BdConvertCondition", optionId)
if targetCfg ~= nil then
NovaAPI.SetTMPText(txt_target, targetCfg.RequestDes)
tbTarget[index].gameObject:SetActive(true)
end
end
CS.UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(self._mapNode.sv.transform:Find("Viewport/Content"):GetComponent("RectTransform"))
self:RefreshList()
end
function BdConvertBuildCtrl:OnTargetGridRefresh(goGrid, nIndex)
local nDataIndex = nIndex + 1
local txt_target = goGrid.transform:Find("txt_target"):GetComponent("TMP_Text")
local targetId = self.contentCfg.ConvertConditionList[nDataIndex]
local targetCfg = ConfigTable.GetData("BdConvertCondition", targetId)
if targetCfg == nil then
return
end
NovaAPI.SetTMPText(txt_target, targetCfg.RequestDes)
end
function BdConvertBuildCtrl:OnRewardItemGridRefresh(goGrid, nIndex)
local nDataIndex = nIndex + 1
local itemId = self.tbItem[nDataIndex].itemId
local goItem = goGrid.transform:Find("btnGrid/AnimRoot/tcItem").gameObject
local instanceId = goItem:GetInstanceID()
if self.tbItemIns[instanceId] == nil then
self.tbItemIns[instanceId] = self:BindCtrlByNode(goItem, "Game.UI.TemplateEx.TemplateItemCtrl")
end
local bGet = self.data.nCurSub == self.data.nMaxSub
self.tbItemIns[instanceId]:SetItem(itemId, nil, self.tbItem[nDataIndex].itemCount, nil, bGet)
end
function BdConvertBuildCtrl:OnGridBtnClick(goGrid, nIndex)
local nDataIndex = nIndex + 1
local itemId = self.tbItem[nDataIndex].itemId
UTILS.ClickItemGridWithTips(itemId, goGrid.transform:Find("btnGrid"), true, false, false)
end
function BdConvertBuildCtrl:InitSort()
NovaAPI.SetTMPColor(self._mapNode.txt_srot_timeTitle, BtnTextColor[self.nSortype == SortType.Time])
NovaAPI.SetTMPColor(self._mapNode.txt_srot_ScoreTitle, BtnTextColor[self.nSortype == SortType.Score])
self._mapNode.btn_sort_score.transform:Find("AnimRoot/btn_AsceIcon"):GetComponent("Button").interactable = self.nSortype == SortType.Score and self.nSortOrder == SortOrder.Ascending
self._mapNode.btn_sort_score.transform:Find("AnimRoot/btn_DescIcon"):GetComponent("Button").interactable = self.nSortype == SortType.Score and self.nSortOrder == SortOrder.Descending
self._mapNode.btn_sort_time.transform:Find("AnimRoot/btn_AsceIcon"):GetComponent("Button").interactable = self.nSortype == SortType.Time and self.nSortOrder == SortOrder.Ascending
self._mapNode.btn_sort_time.transform:Find("AnimRoot/btn_DescIcon"):GetComponent("Button").interactable = self.nSortype == SortType.Time and self.nSortOrder == SortOrder.Descending
end
function BdConvertBuildCtrl:OnBtnClick_AAA()
end
function BdConvertBuildCtrl:OnEvent_AAA()
end
function BdConvertBuildCtrl:RefreshList()
self._tbAllBuild = self.actData:GetAllBuildByOpId(self.nOptionId)
if #self._tbAllBuild == 0 then
self._mapNode.BuildListContent:SetActive(false)
self._mapNode.BuildListContent_Empty:SetActive(true)
self._mapNode.btn_submit_none.gameObject:SetActive(true)
self._mapNode.btn_submit.gameObject:SetActive(false)
NovaAPI.SetTMPText(self._mapNode.txt_Empty, ConfigTable.GetUIText("RoguelikeBuild_Manage_EmptyList"))
self:RerfeshSelected()
return
else
self._mapNode.BuildListContent:SetActive(true)
self._mapNode.btn_submit_none.gameObject:SetActive(false)
self._mapNode.btn_submit.gameObject:SetActive(true)
end
self:SortBuildData()
self._mapNode.BuildList:Init(#self._tbAllBuild, self, self.RefreshBuildGrid, self.OnBtnCal)
self:RerfeshSelected()
end
function BdConvertBuildCtrl:RefreshBuildGrid(goGrid, gridIndex)
local nIndex = gridIndex + 1
local mapData = self._tbAllBuild[nIndex]
if self.mapListItemCtrl[goGrid] == nil then
self.mapListItemCtrl[goGrid] = self:BindCtrlByNode(goGrid, "Game.UI.Activity.BdConvert._500001.BdConvertBuildItemCtrl")
self.mapListItemCtrl[goGrid]:Init(self)
end
self.mapListItemCtrl[goGrid]:RefreshGrid(mapData)
local index = table.indexof(self.tbSelected, mapData)
if 0 < index then
self:RerfeshSelected()
end
end
function BdConvertBuildCtrl:RerfeshSelected()
EventManager.Hit("BdConvert_BuildCancleSelect")
for index, data in ipairs(self.tbSelected) do
EventManager.Hit("BdConvert_BuildRefreshIndex", data, index)
end
local str = string.format("<color=#0abec5>%s</color>/%s", #self.tbSelected, self.data.nMaxSub - self.data.nCurSub)
NovaAPI.SetTMPText(self._mapNode.txt_Allselect, ConfigTable.GetUIText("BdConvert_Selected") .. " " .. str)
end
function BdConvertBuildCtrl:ClearSelectedData()
self.tbSelected = {}
self:RerfeshSelected()
end
function BdConvertBuildCtrl:SortBuildData()
if self.nSortype == SortType.Time then
local sortByTime = function(a, b)
if self.nSortOrder == SortOrder.Descending then
return a.nBuildId > b.nBuildId
else
return a.nBuildId < b.nBuildId
end
end
table.sort(self._tbAllBuild, sortByTime)
else
local sortByScore = function(a, b)
if self.nSortOrder == SortOrder.Descending then
if a.nScore ~= b.nScore then
return a.nScore > b.nScore
else
return a.nBuildId > b.nBuildId
end
elseif a.nScore ~= b.nScore then
return a.nScore < b.nScore
else
return a.nBuildId > b.nBuildId
end
end
table.sort(self._tbAllBuild, sortByScore)
end
end
function BdConvertBuildCtrl:OnBtnClick_SortTime(btn)
if self.nSortype == SortType.Time then
self.nSortOrder = not self.nSortOrder
self._mapNode.btn_sort_time.transform:Find("AnimRoot/btn_AsceIcon"):GetComponent("Button").interactable = self.nSortOrder == SortOrder.Ascending
self._mapNode.btn_sort_time.transform:Find("AnimRoot/btn_DescIcon"):GetComponent("Button").interactable = self.nSortOrder == SortOrder.Descending
else
self.nSortype = SortType.Time
self.nSortOrder = SortOrder.Descending
self._mapNode.btn_sort_time.transform:Find("AnimRoot/btn_AsceIcon"):GetComponent("Button").interactable = false
self._mapNode.btn_sort_time.transform:Find("AnimRoot/btn_DescIcon"):GetComponent("Button").interactable = true
self._mapNode.btn_sort_score.transform:Find("AnimRoot/btn_AsceIcon"):GetComponent("Button").interactable = false
self._mapNode.btn_sort_score.transform:Find("AnimRoot/btn_DescIcon"):GetComponent("Button").interactable = false
NovaAPI.SetTMPColor(self._mapNode.txt_srot_timeTitle, BtnTextColor[self.nSortype == SortType.Time])
NovaAPI.SetTMPColor(self._mapNode.txt_srot_ScoreTitle, BtnTextColor[self.nSortype == SortType.Score])
end
self:RefreshList()
end
function BdConvertBuildCtrl:OnBtnClick_SortScore(btn)
if self.nSortype == SortType.Score then
self.nSortOrder = not self.nSortOrder
self._mapNode.btn_sort_score.transform:Find("AnimRoot/btn_AsceIcon"):GetComponent("Button").interactable = self.nSortOrder == SortOrder.Ascending
self._mapNode.btn_sort_score.transform:Find("AnimRoot/btn_DescIcon"):GetComponent("Button").interactable = self.nSortOrder == SortOrder.Descending
else
self.nSortype = SortType.Score
self.nSortOrder = SortOrder.Descending
self._mapNode.btn_sort_score.transform:Find("AnimRoot/btn_AsceIcon"):GetComponent("Button").interactable = false
self._mapNode.btn_sort_score.transform:Find("AnimRoot/btn_DescIcon"):GetComponent("Button").interactable = true
self._mapNode.btn_sort_time.transform:Find("AnimRoot/btn_AsceIcon"):GetComponent("Button").interactable = false
self._mapNode.btn_sort_time.transform:Find("AnimRoot/btn_DescIcon"):GetComponent("Button").interactable = false
NovaAPI.SetTMPColor(self._mapNode.txt_srot_timeTitle, BtnTextColor[self.nSortype == SortType.Time])
NovaAPI.SetTMPColor(self._mapNode.txt_srot_ScoreTitle, BtnTextColor[self.nSortype == SortType.Score])
end
self:RefreshList()
end
function BdConvertBuildCtrl:OnBtnClickGrid(nIdx, itemCtrl)
local mapBuild = self._tbAllBuild[nIdx]
if mapBuild.bLock then
EventManager.Hit(EventId.OpenMessageBox, ConfigTable.GetUIText("BdConvert_LockTips"))
return
end
local index = table.indexof(self.tbSelected, itemCtrl._mapData)
if index ~= nil and 0 < index then
table.remove(self.tbSelected, index)
self:RerfeshSelected()
return
end
if #self.tbSelected >= self.data.nMaxSub - self.data.nCurSub then
EventManager.Hit(EventId.OpenMessageBox, ConfigTable.GetUIText("BdConvert_SelectedMaxTips"))
return
end
table.insert(self.tbSelected, mapBuild)
self:RerfeshSelected()
end
function BdConvertBuildCtrl:OpenBuildDes(nIdx, itemCtrl)
local mapBuild = self._tbAllBuild[nIdx]
EventManager.Hit(EventId.OpenPanel, PanelId.BdConvertBuildDetail, mapBuild, self.actData)
end
function BdConvertBuildCtrl:OnBuildGridLock(nIdx, itemCtrl)
local mapBuild = self._tbAllBuild[nIdx]
local callback = function()
itemCtrl:SetLockState(mapBuild.bLock)
self:RerfeshSelected()
end
self.actData:ChangeBuildLock(mapBuild.nBuildId, not mapBuild.bLock, callback)
end
function BdConvertBuildCtrl:OnBtnClick_Submit()
if #self.tbSelected == 0 then
EventManager.Hit(EventId.OpenMessageBox, ConfigTable.GetUIText("BdConvert_SubmitNoneTips"))
return
end
local bHasHighLevelBuild = false
for _, mapBuild in ipairs(self.tbSelected) do
if mapBuild.mapRank.Level >= self.contentCfg.DoubleCheckMinLevel then
bHasHighLevelBuild = true
break
end
end
local tbBuildId = {}
for _, buildData in ipairs(self.tbSelected) do
table.insert(tbBuildId, buildData.nBuildId)
end
if bHasHighLevelBuild then
local TipsTime = LocalData.GetPlayerLocalData("BdConvert_BuildTips_Time")
local _tipDay = 0
if TipsTime ~= nil then
_tipDay = tonumber(TipsTime)
end
local curTimeStamp = CS.ClientManager.Instance.serverTimeStampWithTimeZone
local fixedTimeStamp = curTimeStamp + newDayTime * 3600
local nYear = tonumber(os.date("!%Y", fixedTimeStamp))
local nMonth = tonumber(os.date("!%m", fixedTimeStamp))
local nDay = tonumber(os.date("!%d", fixedTimeStamp))
local nowD = nYear * 366 + nMonth * 31 + nDay
if nowD == _tipDay then
self.actData:RequestSubmitBuild(self.nOptionId, tbBuildId)
self:ClearSelectedData()
else
local isSelectAgain = false
local confirmCallback = function()
if isSelectAgain then
local _curTimeStamp = CS.ClientManager.Instance.serverTimeStampWithTimeZone
local _fixedTimeStamp = _curTimeStamp + newDayTime * 3600
local _nYear = tonumber(os.date("!%Y", _fixedTimeStamp))
local _nMonth = tonumber(os.date("!%m", _fixedTimeStamp))
local _nDay = tonumber(os.date("!%d", _fixedTimeStamp))
local _nowD = _nYear * 366 + _nMonth * 31 + _nDay
LocalData.SetPlayerLocalData("BdConvert_BuildTips_Time", tostring(_nowD))
end
self:ClearSelectedData()
self.actData:RequestSubmitBuild(self.nOptionId, tbBuildId)
end
local againCallback = function(isSelect)
isSelectAgain = isSelect
end
local msg = {
nType = AllEnum.MessageBox.Confirm,
sContent = ConfigTable.GetUIText("BdConvert_CheckTips"),
callbackConfirmAfterClose = confirmCallback,
callbackAgain = againCallback
}
EventManager.Hit(EventId.OpenMessageBox, msg)
end
else
self.actData:RequestSubmitBuild(self.nOptionId, tbBuildId)
self:ClearSelectedData()
end
end
function BdConvertBuildCtrl:OnEvent_ShowReward(tbItem, icon)
if tbItem == nil or #tbItem == 0 then
return
end
local tbItemData = {}
for _, itemData in ipairs(tbItem) do
table.insert(tbItemData, {
id = itemData.Tid,
count = itemData.Qty
})
end
local callback = function()
self:InitData()
if self.data.nCurSub == self.data.nMaxSub then
self:OnEvent_BackHome(PanelId.BdConvertBuildPanel)
end
end
self._mapNode.BdConvertFinishPanel.gameObject:SetActive(true)
self._mapNode.BdConvertFinishPanel:ShowReward(tbItemData, icon, callback)
end
function BdConvertBuildCtrl:OnEvent_CloseReward()
self._mapNode.BdConvertFinishPanel.gameObject:SetActive(false)
end
function BdConvertBuildCtrl:OnEvent_BackHome(nPanelId)
if nPanelId == PanelId.BdConvertBuildPanel then
self._mapNode.anim:Play("BdConvertBuildPanel_out")
self._mapNode.bg_anim:Play("BdConvertBuildPanel_Bg_out")
EventManager.Hit(EventId.TemporaryBlockInput, 0.2)
self:AddTimer(1, 0.2, function()
EventManager.Hit(EventId.ClosePanel, PanelId.BdConvertBuildPanel)
end, true, true, true)
end
end
function BdConvertBuildCtrl:OnEvent_Home(nPanelId)
if nPanelId == PanelId.BdConvertBuildPanel then
PanelManager.Home()
end
end
return BdConvertBuildCtrl
@@ -0,0 +1,98 @@
local BdConvertBuildDetailCtrl = class("BdConvertBuildDetailCtrl", BaseCtrl)
BdConvertBuildDetailCtrl._mapNodeConfig = {
TopBar = {
sNodeName = "TopBarPanel",
sCtrlName = "Game.UI.TopBarEx.TopBarCtrl"
},
TMPBuildSaveTime = {sComponentName = "TMP_Text"},
btnRename = {},
btn_Preference = {},
txtBuildLock = {sComponentName = "TMP_Text"},
btn_Lock = {
sComponentName = "UIButton",
callback = "OnBtnClick_Lock"
},
btn_LockIcon = {sComponentName = "Button"},
btnDelete = {},
ani_root = {
sNodeName = "----SafeAreaRoot----",
sComponentName = "Animator"
},
BuildDetail = {
sCtrlName = "Game.UI.StarTower.Build.StarTowerBuildDetailItemCtrl"
},
ContentList = {
sCtrlName = "Game.UI.StarTower.Build.StarTowerBuildContentCtrl"
}
}
BdConvertBuildDetailCtrl._mapEventConfig = {}
function BdConvertBuildDetailCtrl:InitPanel()
self._mapNode.btnRename:SetActive(false)
self._mapNode.btn_Preference:SetActive(false)
self._mapNode.btnDelete:SetActive(false)
if not self.mapBuild.bDetail then
print("build数据错误 无详细数据")
return
end
self._mapNode.BuildDetail:Refresh(self.mapBuild)
self._mapNode.ContentList:Refresh(self.mapBuild)
self._mapNode.btn_LockIcon.interactable = self.mapBuild.bLock
NovaAPI.SetTMPText(self._mapNode.txtBuildLock, self.mapBuild.bLock and ConfigTable.GetUIText("RoguelikeBuild_Save_Lock") or ConfigTable.GetUIText("RoguelikeBuild_Save_Unlock"))
NovaAPI.SetTMPColor(self._mapNode.txtBuildLock, self.mapBuild.bLock and Color(0.14901960784313725, 0.25882352941176473, 0.47058823529411764) or Color(0.5803921568627451, 0.6666666666666666, 0.7529411764705882))
NovaAPI.SetTMPText(self._mapNode.TMPBuildSaveTime, string.format("<color=#5e89b4>保存时间:</color>%s", os.date("%Y/%m/%d %H:%M", math.floor(self.mapBuild.nBuildId / 1.0E9))))
end
function BdConvertBuildDetailCtrl:OpenConfirmHint()
end
function BdConvertBuildDetailCtrl:Awake()
self.tbCoinRate = ConfigTable.GetConfigArray("StarTowerBuildTransformParas")
local tbParam = self:GetPanelParam()
if type(tbParam) == "table" then
self.mapBuild = tbParam[1]
self.actData = tbParam[2]
end
end
function BdConvertBuildDetailCtrl:OnEnable()
self:InitPanel()
end
function BdConvertBuildDetailCtrl:OnDisable()
end
function BdConvertBuildDetailCtrl:OnDestroy()
end
function BdConvertBuildDetailCtrl:OnRelease()
end
function BdConvertBuildDetailCtrl:OnBtnClick_Preference(btn)
local tbPreferenceCheckIn = {}
local tbPreferenceCheckOut = {}
local callback = function()
self._mapNode.btn_PreferenceIcon.interactable = self.mapBuild.bPreference
NovaAPI.SetTMPColor(self._mapNode.txtLike, self.mapBuild.bPreference and Color(0.14901960784313725, 0.25882352941176473, 0.47058823529411764) or Color(0.5803921568627451, 0.6666666666666666, 0.7529411764705882))
end
if self.mapBuild.bPreference then
table.insert(tbPreferenceCheckOut, self.mapBuild.nBuildId)
else
table.insert(tbPreferenceCheckIn, self.mapBuild.nBuildId)
end
PlayerData.Build:SetBuildPreference(tbPreferenceCheckIn, tbPreferenceCheckOut, callback)
end
function BdConvertBuildDetailCtrl:OnBtnClick_Lock(btn)
local callback = function()
self._mapNode.btn_LockIcon.interactable = self.mapBuild.bLock
NovaAPI.SetTMPText(self._mapNode.txtBuildLock, self.mapBuild.bLock and ConfigTable.GetUIText("RoguelikeBuild_Save_Lock") or ConfigTable.GetUIText("RoguelikeBuild_Save_Unlock"))
NovaAPI.SetTMPColor(self._mapNode.txtBuildLock, self.mapBuild.bLock and Color(0.14901960784313725, 0.25882352941176473, 0.47058823529411764) or Color(0.5803921568627451, 0.6666666666666666, 0.7529411764705882))
end
self.actData:ChangeBuildLock(self.mapBuild.nBuildId, not self.mapBuild.bLock, callback)
end
function BdConvertBuildDetailCtrl:OnBtnClick_DeleteBuild(btn)
end
function BdConvertBuildDetailCtrl:OnBtnClick_Rename(btn)
end
function BdConvertBuildDetailCtrl:OnBtnClick_CharInfo(btn, nIndex)
local nCharTid = self.mapBuild.tbChar[nIndex].nTid
local tbChar = {
self.mapBuild.tbChar[1].nTid,
self.mapBuild.tbChar[2].nTid,
self.mapBuild.tbChar[3].nTid
}
EventManager.Hit(EventId.OpenPanel, PanelId.CharBgPanel, PanelId.CharInfo, nCharTid, tbChar)
end
return BdConvertBuildDetailCtrl
@@ -0,0 +1,19 @@
local BdConvertBuildDetailPanel = class("BdConvertBuildDetailPanel", BasePanel)
BdConvertBuildDetailPanel._sUIResRootPath = "UI_Activity/"
BdConvertBuildDetailPanel._tbDefine = {
{
sPrefabPath = "_500001/BdConvertBuildDetailPanel.prefab",
sCtrlName = "Game.UI.Activity.BdConvert._500001.BdConvertBuildDetailCtrl"
}
}
function BdConvertBuildDetailPanel:Awake()
end
function BdConvertBuildDetailPanel:OnEnable()
end
function BdConvertBuildDetailPanel:OnDisable()
end
function BdConvertBuildDetailPanel:OnDestroy()
end
function BdConvertBuildDetailPanel:OnRelease()
end
return BdConvertBuildDetailPanel
@@ -0,0 +1,165 @@
local BdConvertBuildItemCtrl = class("BdConvertBuildItemCtrl", BaseCtrl)
local PanelState = {
Normal = 1,
Delete = 2,
Preference = 3
}
BdConvertBuildItemCtrl._mapNodeConfig = {
img_SelectPreference = {},
btn_LockIcon = {sComponentName = "Button"},
btn_grid = {
sComponentName = "UIButton",
callback = "OnBtnClick_Grid"
},
btn_Lock = {
sComponentName = "UIButton",
callback = "OnBtnClick_Lock"
},
imgRareFrame = {sComponentName = "Image"},
imgRareScore = {sComponentName = "Image"},
txtBuildName = {sComponentName = "TMP_Text"},
imgLike = {},
txtLeaderCn = {
sComponentName = "TMP_Text",
sLanguageId = "StarTower_Build_Leader"
},
txtSubCn = {
nCount = 2,
sComponentName = "TMP_Text",
sLanguageId = "StarTower_Build_Sub"
},
imgCharIcon = {nCount = 3, sComponentName = "Image"},
imgCharFrame = {nCount = 3, sComponentName = "Image"},
txtPotentialCount = {nCount = 3, sComponentName = "TMP_Text"},
imgCharElement = {nCount = 3, sComponentName = "Image"},
txtChar = {
sComponentName = "TMP_Text",
sLanguageId = "StarTower_Build_Char_Title"
},
txtDisc = {
sComponentName = "TMP_Text",
sLanguageId = "StarTower_Build_MainDisc_Title"
},
goDiscItem = {
nCount = 3,
sCtrlName = "Game.UI.StarTower.Build.BuildSimpleDiscItem"
},
objUnavailable = {},
objUnavailableIcon = {sComponentName = "Image"},
imgRareScoreMask = {sComponentName = "Image"},
texUnavailable = {
sComponentName = "TMP_Text",
sLanguageId = "InfinityTower_Build_NotAvailable"
},
imgUnavailable = {},
imgBuildUsed = {},
txtBuildUsed = {
sComponentName = "TMP_Text",
sLanguageId = "JointDrill_Build_Used"
},
imgCharUsed = {},
txtCharUsed = {
sComponentName = "TMP_Text",
sLanguageId = "JointDrill_Build_Char_Used"
},
selectedIndex = {},
txt_select_index = {sComponentName = "TMP_Text"},
txt_select = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_Selected"
}
}
BdConvertBuildItemCtrl._mapEventConfig = {
BdConvert_BuildRefreshIndex = "RefreshIndex",
BdConvert_BuildCancleSelect = "CancleSelected"
}
function BdConvertBuildItemCtrl:RefreshGrid(mapData)
self._mapData = mapData
self:RefreshInfo()
self:RefreshChar()
self:RefreshDisc()
self:CancleSelected()
end
function BdConvertBuildItemCtrl:RefreshInfo()
local sScore = "Icon/BuildRank/BuildRank_" .. self._mapData.mapRank.Id
local sFrame = AllEnum.FrameType_New.BuildRankDB .. AllEnum.FrameColor_New[self._mapData.mapRank.Rarity]
self:SetPngSprite(self._mapNode.imgRareScore, sScore)
self:SetAtlasSprite(self._mapNode.imgRareFrame, "12_rare", sFrame)
if self._mapData.sName == "" or self._mapData.sName == nil then
NovaAPI.SetTMPText(self._mapNode.txtBuildName, ConfigTable.GetUIText("RoguelikeBuild_EmptyBuildName"))
else
NovaAPI.SetTMPText(self._mapNode.txtBuildName, self._mapData.sName)
end
self._mapNode.imgLike:SetActive(self._mapData.bPreference)
self._mapNode.btn_LockIcon.interactable = self._mapData.bLock
end
function BdConvertBuildItemCtrl:RefreshChar()
for i = 1, 3 do
local nCharTid = self._mapData.tbChar[i].nTid
local nCharSkinId = PlayerData.Char:GetCharSkinId(nCharTid)
local mapCharSkin = ConfigTable.GetData_CharacterSkin(nCharSkinId)
local mapCharCfg = ConfigTable.GetData_Character(nCharTid)
local sFrame = AllEnum.FrameType_New.BoardFrame .. AllEnum.BoardFrameColor[mapCharCfg.Grade]
self:SetPngSprite(self._mapNode.imgCharIcon[i], mapCharSkin.Icon .. AllEnum.CharHeadIconSurfix.XXL)
self:SetAtlasSprite(self._mapNode.imgCharFrame[i], "12_rare", sFrame)
NovaAPI.SetTMPText(self._mapNode.txtPotentialCount[i], self._mapData.tbChar[i].nPotentialCount)
self:SetAtlasSprite(self._mapNode.imgCharElement[i], "12_rare", AllEnum.Char_Element[mapCharCfg.EET].icon)
end
end
function BdConvertBuildItemCtrl:RefreshDisc()
local tbDisc = self._mapData.tbDisc
local nIndex = 1
for _, nId in ipairs(tbDisc) do
if nil ~= self._mapNode.goDiscItem[nIndex] and nIndex <= 3 then
self._mapNode.goDiscItem[nIndex]:Init(nId)
end
nIndex = nIndex + 1
end
end
function BdConvertBuildItemCtrl:RefreshIndex(mapData, nIndex)
if mapData ~= self._mapData then
return
end
self:Selected(nIndex)
end
function BdConvertBuildItemCtrl:Init(parentCtrl)
self._parentCtrl = parentCtrl
end
function BdConvertBuildItemCtrl:SetLockState(bLock)
self._mapNode.btn_LockIcon.interactable = bLock
end
function BdConvertBuildItemCtrl:CancleSelected()
self._mapNode.img_SelectPreference:SetActive(false)
self._mapNode.selectedIndex:SetActive(false)
end
function BdConvertBuildItemCtrl:Selected(nIndex)
self._mapNode.img_SelectPreference:SetActive(true)
self._mapNode.selectedIndex:SetActive(true)
NovaAPI.SetTMPText(self._mapNode.txt_select_index, nIndex)
end
function BdConvertBuildItemCtrl:Awake()
end
function BdConvertBuildItemCtrl:OnEnable()
end
function BdConvertBuildItemCtrl:OnDisable()
end
function BdConvertBuildItemCtrl:OnDestroy()
end
function BdConvertBuildItemCtrl:OnRelease()
end
function BdConvertBuildItemCtrl:OnBtnClick_Grid(btn)
if btn.Operate_Type == 0 then
local nIndex = tonumber(self.gameObject.name) + 1
self._parentCtrl:OnBtnClickGrid(nIndex, self)
elseif btn.Operate_Type == 2 then
local nIndex = tonumber(self.gameObject.name) + 1
self._parentCtrl:OpenBuildDes(nIndex, self)
end
end
function BdConvertBuildItemCtrl:OnBtnClick_Lock(btn)
local nIndex = tonumber(self.gameObject.name) + 1
self._parentCtrl:OnBuildGridLock(nIndex, self)
end
function BdConvertBuildItemCtrl:OnBtnClick_Preference(btn)
end
return BdConvertBuildItemCtrl
@@ -0,0 +1,24 @@
local BdConvertBuildPanel = class("BdConvertBuildPanel", BasePanel)
BdConvertBuildPanel._bIsMainPanel = true
BdConvertBuildPanel._bAddToBackHistory = true
BdConvertBuildPanel._sSortingLayerName = AllEnum.SortingLayerName.UI
BdConvertBuildPanel._sUIResRootPath = "UI_Activity/"
BdConvertBuildPanel._tbDefine = {
{
sPrefabPath = "_500001/BdConvertBuildPanel.prefab",
sCtrlName = "Game.UI.Activity.BdConvert._500001.BdConvertBuildCtrl"
}
}
function BdConvertBuildPanel:Awake()
end
function BdConvertBuildPanel:OnEnable()
end
function BdConvertBuildPanel:OnAfterEnter()
end
function BdConvertBuildPanel:OnDisable()
end
function BdConvertBuildPanel:OnDestroy()
end
function BdConvertBuildPanel:OnRelease()
end
return BdConvertBuildPanel
@@ -0,0 +1,167 @@
local BdConvertCellCtrl = class("BdConvertCellCtrl", BaseCtrl)
local minHeight = 85.26
BdConvertCellCtrl._mapNodeConfig = {
bg = {
sComponentName = "RectTransform"
},
img_unOpen = {
sComponentName = "RectTransform"
},
txt_unOpenTips = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_UnopenTips"
},
txt_unOpen = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_Unopen"
},
txt_finishTips = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_Finish"
},
icon = {sComponentName = "Image"},
txt_title = {sComponentName = "TMP_Text"},
bg_reward = {
sComponentName = "RectTransform"
},
txt_reward = {sComponentName = "TMP_Text"},
svItem = {
sComponentName = "LoopScrollView"
},
icon_com = {},
img_finish = {},
btnGrid = {
sComponentName = "UIButton",
callback = "OnBtnClick_JumpTo"
},
btnGrid_None = {
sComponentName = "UIButton",
callback = "OnBtnClick_JumpTo"
},
txt_btn = {
nCount = 2,
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_ToBuild"
},
txt_tip = {sComponentName = "TMP_Text"},
icon_star = {},
Content = {
sComponentName = "RectTransform"
},
target = {nCount = 3}
}
function BdConvertCellCtrl:Awake()
self.tbItemIns = {}
end
function BdConvertCellCtrl:OnDisable()
if self.tbItemIns ~= nil then
for _, ctrl in pairs(self.tbItemIns) do
self:UnbindCtrlByNode(ctrl)
end
end
self.tbItemIns = {}
end
function BdConvertCellCtrl:SetData(actId, optionId)
self.nActId = actId
self.nOptionId = optionId
self.actData = PlayerData.Activity:GetActivityDataById(self.nActId)
self.contentData = self.actData:GetBdDataBy(self.nOptionId)
local contentCfg = ConfigTable.GetData("BdConvertContent", self.nOptionId)
if contentCfg == nil then
return
end
local data = self.actData:GetBdDataBy(optionId)
if data == nil then
return
end
self._mapNode.img_unOpen.gameObject:SetActive(data.bIsOpen == false)
if contentCfg.Icon ~= "" then
self:SetPngSprite(self._mapNode.icon, contentCfg.Icon)
end
NovaAPI.SetTMPText(self._mapNode.txt_title, contentCfg.Des)
NovaAPI.SetTMPText(self._mapNode.txt_reward, ConfigTable.GetUIText("BdConvert_RewardTitle") .. " " .. data.nCurSub .. "/" .. data.nMaxSub)
self.tbItem = {}
local tbReward = decodeJson(contentCfg.BasicReward)
local tbTemp = {}
for key, value in pairs(tbReward) do
tbTemp[tonumber(key)] = tonumber(value)
end
for _, rewardId in ipairs(contentCfg.BasicRewardPreview) do
table.insert(self.tbItem, {
itemId = rewardId,
itemCount = tbTemp[rewardId]
})
end
self._mapNode.svItem:Init(#self.tbItem, self, self.OnRewardItemGridRefresh, self.OnGridBtnClick)
self._mapNode.icon_com:SetActive(data.nCurSub == data.nMaxSub)
self._mapNode.img_finish:SetActive(data.nCurSub == data.nMaxSub)
self._mapNode.icon_star:SetActive(data.nCurSub ~= data.nMaxSub)
self._mapNode.txt_unOpen.gameObject:SetActive(data.bIsOpen == false)
for i = 1, 3 do
self._mapNode.target[i].gameObject:SetActive(false)
end
for index, optionId in ipairs(contentCfg.ConvertConditionList) do
if index <= 3 then
local txt_target = self._mapNode.target[index].transform:Find("txt_target"):GetComponent("TMP_Text")
local targetCfg = ConfigTable.GetData("BdConvertCondition", optionId)
if targetCfg ~= nil then
NovaAPI.SetTMPText(txt_target, targetCfg.RequestDes)
self._mapNode.target[index].gameObject:SetActive(true)
end
end
end
local nCount = 0
local tbAllbuild = self.actData:GetAllBuildByOpId(self.nOptionId)
if tbAllbuild ~= nil then
nCount = #tbAllbuild
end
self._mapNode.btnGrid_None.gameObject:SetActive(nCount == 0)
self._mapNode.btnGrid.gameObject:SetActive(nCount ~= 0)
if nCount == 0 then
NovaAPI.SetTMPText(self._mapNode.txt_tip, ConfigTable.GetUIText("BdConvert_BuildCountTips1"))
else
NovaAPI.SetTMPText(self._mapNode.txt_tip, orderedFormat(ConfigTable.GetUIText("BdConvert_BuildCountTips2"), nCount))
end
local bGet = self.contentData.nCurSub == self.contentData.nMaxSub
if bGet then
self._mapNode.btnGrid_None.gameObject:SetActive(false)
self._mapNode.btnGrid.gameObject:SetActive(false)
self._mapNode.txt_tip.gameObject:SetActive(false)
self._mapNode.txt_finishTips.gameObject:SetActive(true)
else
self._mapNode.txt_finishTips.gameObject:SetActive(false)
end
local wait = function()
coroutine.yield(CS.UnityEngine.WaitForEndOfFrame())
CS.UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(self._mapNode.bg_reward)
CS.UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(self._mapNode.Content)
coroutine.yield(CS.UnityEngine.WaitForEndOfFrame())
local curHeight = self._mapNode.Content.sizeDelta.y
local rectTransform = self.gameObject:GetComponent("RectTransform")
rectTransform.sizeDelta = Vector2(rectTransform.sizeDelta.x, rectTransform.sizeDelta.y + curHeight - minHeight)
self._mapNode.bg.sizeDelta = Vector2(self._mapNode.bg.sizeDelta.x, self._mapNode.bg.sizeDelta.y + curHeight - minHeight)
CS.UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform)
CS.UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(self._mapNode.bg)
end
cs_coroutine.start(wait)
end
function BdConvertCellCtrl:OnRewardItemGridRefresh(goGrid, nIndex)
local nDataIndex = nIndex + 1
local itemId = self.tbItem[nDataIndex].itemId
local goItem = goGrid.transform:Find("btnGrid/AnimRoot/tcItem").gameObject
local instanceId = goItem:GetInstanceID()
if self.tbItemIns[instanceId] == nil then
self.tbItemIns[instanceId] = self:BindCtrlByNode(goItem, "Game.UI.TemplateEx.TemplateItemCtrl")
end
local bGet = self.contentData.nCurSub == self.contentData.nMaxSub
self.tbItemIns[instanceId]:SetItem(itemId, nil, self.tbItem[nDataIndex].itemCount, nil, bGet)
end
function BdConvertCellCtrl:OnGridBtnClick(goGrid, nIndex)
local nDataIndex = nIndex + 1
local itemId = self.tbItem[nDataIndex].itemId
UTILS.ClickItemGridWithTips(itemId, goGrid.transform:Find("btnGrid").transform, true, true, false)
end
function BdConvertCellCtrl:OnBtnClick_JumpTo()
EventManager.Hit("BdConvert_JumpToBuildPanel", self.nOptionId)
end
return BdConvertCellCtrl
@@ -0,0 +1,223 @@
local BdConvertCtrl = class("BdConvertCtrl", BaseCtrl)
local LocalSettingData = require("GameCore.Data.LocalSettingData")
local Actor2DManager = require("Game.Actor2D.Actor2DManager")
local barMinX = -378
local barMaxX = 0
BdConvertCtrl._mapNodeConfig = {
TopBar = {
sNodeName = "TopBarPanel",
sCtrlName = "Game.UI.TopBarEx.TopBarCtrl"
},
txt_quest = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_QuestTitle"
},
redDotQuest = {},
btn_quest = {
sComponentName = "UIButton",
callback = "OnBtnClick_Quest"
},
txt_mainProcess = {sComponentName = "TMP_Text"},
imgMainBarFill = {
sComponentName = "RectTransform"
},
Actor2D = {
sNodeName = "----Actor2D----"
},
btn_starTower = {
sComponentName = "UIButton",
callback = "OnBtnClick_GoStarTower"
},
anim = {
sNodeName = "----SafeAreaRoot----",
sComponentName = "Animator"
},
bg_anim = {sNodeName = "----BG----", sComponentName = "Animator"},
imgBgLevelSelect = {
sNodeName = "----Actor2D----",
sComponentName = "RawImage"
},
trActor2D_PNG = {
sNodeName = "----Actor2D_PNG----",
sComponentName = "Transform"
},
cell = {},
ListContent = {
sComponentName = "RectTransform"
},
ListCanvasGroup = {
sNodeName = "ListContent",
sComponentName = "CanvasGroup"
},
txt_starTower = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_GoToStarTower"
}
}
BdConvertCtrl._mapEventConfig = {
BdConvertQuestUpdate = "InitQuest",
BdConvert_JumpToBuildPanel = "OnEvent_JumpTo",
[EventId.UIBackConfirm] = "OnEvent_BackHome",
[EventId.UIHomeConfirm] = "OnEvent_Home"
}
BdConvertCtrl._mapRedDotConfig = {
[RedDotDefine.Activity_BdConvert_AllQuest] = {
sNodeName = "redDotQuest"
}
}
function BdConvertCtrl:Awake()
local param = self:GetPanelParam()
if type(param) == "table" then
self.nActId = param[1]
end
self.actData = PlayerData.Activity:GetActivityDataById(self.nActId)
self.bInAnim_In = false
end
function BdConvertCtrl:OnEnable()
if self._panel.bPlayedAnim_In then
EventManager.Hit(EventId.BlockInput, true)
self._mapNode.anim:Play("BdConVertPanel_in_02")
self._mapNode.bg_anim:Play("BdConvertPanel_Bg_out_02")
self.bInAnim_In = true
self:AddTimer(1, 0.7, function()
self.bInAnim_In = false
EventManager.Hit(EventId.BlockInput, false)
end, true, true, true)
else
EventManager.Hit(EventId.BlockInput, true)
self._mapNode.anim:Play("BdConVertPanel_in_01")
self._mapNode.bg_anim:Play("BdConvertPanel_Bg_in_01")
self.bInAnim_In = true
self:AddTimer(1, 0.67, function()
self.bInAnim_In = false
EventManager.Hit(EventId.BlockInput, false)
end, true, true, true)
end
self._panel.bPlayedAnim_In = true
local bUseL2D = LocalSettingData.mapData.UseLive2D
self._mapNode.imgBgLevelSelect.transform.localScale = bUseL2D == true and Vector3.one or Vector3.zero
self._mapNode.trActor2D_PNG.localScale = bUseL2D == true and Vector3.zero or Vector3.one
if bUseL2D == true then
Actor2DManager.SetBoardNPC2D(self:GetPanelId(), self._mapNode.imgBgLevelSelect, 9102)
else
Actor2DManager.SetBoardNPC2D_PNG(self._mapNode.trActor2D_PNG, self:GetPanelId(), 9102)
end
local bResult = self.actData:CheckBuildsData()
if bResult then
self:UpdateOptionList()
else
EventManager.Hit(EventId.BlockInput, true)
self.actData:RequestAllBuildData(function()
if not self.bInAnim_In then
EventManager.Hit(EventId.BlockInput, false)
end
self:UpdateOptionList()
end)
end
self:InitQuest()
end
function BdConvertCtrl:OnDisable()
Actor2DManager.UnsetBoardNPC2D()
if self.GridIns ~= nil then
for _, ctrl in pairs(self.GridIns) do
self:UnbindCtrlByNode(ctrl)
end
end
self.GridIns = {}
if self.tbListCtrl ~= nil then
for _, ctrl in pairs(self.tbListCtrl) do
self:UnbindCtrlByNode(ctrl)
end
end
self.tbListCtrl = {}
end
function BdConvertCtrl:UpdateOptionList()
self.bdConfig = self.actData:GetBdConvertConfig()
self.optionList = self.bdConfig.OptionList
local sort = function(a, b)
local contentA_Data = self.actData:GetBdDataBy(a)
local contentB_Data = self.actData:GetBdDataBy(b)
local bFinish_A = contentA_Data.nCurSub == contentA_Data.nMaxSub
local bFinish_B = contentB_Data.nCurSub == contentB_Data.nMaxSub
if bFinish_A and not bFinish_B then
return false
elseif not bFinish_A and bFinish_B then
return true
end
return a < b
end
table.sort(self.optionList, sort)
self.tbGridSize = {}
for _, optionId in ipairs(self.optionList) do
local contentCfg = ConfigTable.GetData("BdConvertContent", optionId)
if contentCfg ~= nil then
local height = 0
if #contentCfg.ConvertConditionList >= 3 then
height = 360
else
height = 310
end
table.insert(self.tbGridSize, height)
end
end
delChildren(self._mapNode.ListContent.gameObject)
NovaAPI.SetCanvasGroupAlpha(self._mapNode.ListCanvasGroup, 0)
if self.tbListCtrl ~= nil then
for _, ctrl in pairs(self.tbListCtrl) do
self:UnbindCtrlByNode(ctrl)
end
end
self.tbListCtrl = {}
self.GridIns = {}
for _, opId in ipairs(self.optionList) do
local go = instantiate(self._mapNode.cell, self._mapNode.ListContent)
local ctrl = self:BindCtrlByNode(go, "Game.UI.Activity.BdConvert._500001.BdConvertCellCtrl")
ctrl:SetData(self.nActId, opId)
table.insert(self.tbListCtrl, ctrl)
go:SetActive(true)
end
local wait = function()
coroutine.yield(CS.UnityEngine.WaitForEndOfFrame())
coroutine.yield(CS.UnityEngine.WaitForEndOfFrame())
coroutine.yield(CS.UnityEngine.WaitForEndOfFrame())
NovaAPI.SetCanvasGroupAlpha(self._mapNode.ListCanvasGroup, 1)
CS.UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(self._mapNode.ListContent)
end
cs_coroutine.start(wait)
end
function BdConvertCtrl:InitQuest()
local allCount = self.actData:GetAllQuestCount()
local receivedCount = self.actData:GetAllReceivedCount()
NovaAPI.SetTMPText(self._mapNode.txt_mainProcess, receivedCount .. "/" .. allCount)
self._mapNode.imgMainBarFill.anchoredPosition = Vector2(barMinX + (barMaxX - barMinX) * (receivedCount / allCount), self._mapNode.imgMainBarFill.anchoredPosition.y)
end
function BdConvertCtrl:OnBtnClick_Quest()
EventManager.Hit(EventId.OpenPanel, PanelId.BdConvertQuestPanel, self.nActId)
end
function BdConvertCtrl:OnBtnClick_GoStarTower()
EventManager.Hit(EventId.OpenPanel, PanelId.LevelMenu, 2)
end
function BdConvertCtrl:OnEvent_JumpTo(nOptionId)
self._mapNode.bg_anim:Play("BdConvertPanel_Bg_in_02")
self._mapNode.anim:Play("BdConVertPanel_out_01")
EventManager.Hit(EventId.TemporaryBlockInput, 0.17)
self:AddTimer(1, 0.17, function()
EventManager.Hit(EventId.OpenPanel, PanelId.BdConvertBuildPanel, self.nActId, nOptionId)
end, true, true, true)
end
function BdConvertCtrl:OnEvent_BackHome(nPanelId)
if nPanelId == PanelId.BdConvertPanel then
self._mapNode.anim:Play("BdConVertPanel_out_02")
self._mapNode.bg_anim:Play("BdConvertPanel_Bg_out_01")
EventManager.Hit(EventId.TemporaryBlockInput, 0.23)
self:AddTimer(1, 0.23, function()
EventManager.Hit(EventId.ClosePanel, PanelId.BdConvertPanel)
end, true, true, true)
end
end
function BdConvertCtrl:OnEvent_Home(nPanelId)
if nPanelId == PanelId.BdConvertPanel then
PanelManager.Home()
end
end
return BdConvertCtrl
@@ -0,0 +1,144 @@
local BdConvertFinishCtrl = class("BdConvertFinishCtrl", BaseCtrl)
local WwiseAudioMgr = CS.WwiseAudioManager.Instance
local GamepadUIManager = require("GameCore.Module.GamepadUIManager")
BdConvertFinishCtrl._mapNodeConfig = {
goBlur = {
sNodeName = "t_fullscreen_blur_black"
},
btn_close = {
sComponentName = "UIButton",
callback = "OnBtnClick_Close"
},
HideRoot = {
sNodeName = "----SafeAreaRoot----"
},
aniRoot = {
sNodeName = "----SafeAreaRoot----",
sComponentName = "Animator"
},
btnSkip = {
sComponentName = "Button",
callback = "OnBtnClick_Skip"
},
btnGrid = {},
img_icon = {sComponentName = "Image"},
txt_tips = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_RewardTips"
},
goItemList1 = {
sComponentName = "RectTransform"
}
}
BdConvertFinishCtrl._mapEventConfig = {}
BdConvertFinishCtrl._mapRedDotConfig = {}
function BdConvertFinishCtrl:RefreshNormal()
for _, v in ipairs(self.tbReward) do
local nItemId = v.id
local goItem = instantiate(self._mapNode.btnGrid, self._mapNode.goItemList1)
local ctrlObj = self:BindCtrlByNode(goItem, "Game.UI.TemplateEx.TemplateItemCtrl")
local mapCfg = ConfigTable.GetData_Item(nItemId)
if mapCfg then
if mapCfg.Type == GameEnum.itemType.Char or mapCfg.Type == GameEnum.itemType.CharacterSkin then
ctrlObj:SetChar(nItemId, v.count, nil, v.rewardType)
else
ctrlObj:SetItem(nItemId, mapCfg.Rarity, v.count, nil, nil, v.rewardType and v.rewardType == AllEnum.RewardType.First, v.rewardType and v.rewardType == AllEnum.RewardType.Three, true, false, false, v.rewardType and v.rewardType == AllEnum.RewardType.Extra)
end
end
local btnGrid = goItem:GetComponent("UIButton")
btnGrid.onClick:RemoveAllListeners()
local cbSelect = function()
self:OnSelectItem(nItemId, btnGrid, v.nHasCount)
EventManager.Hit("Stop_InfinityTowerAutoNextLv")
end
btnGrid.onClick:AddListener(cbSelect)
goItem.gameObject:SetActive(true)
NovaAPI.SetCanvasGroupAlpha(goItem:GetComponent("CanvasGroup"), 0)
end
self:PlayNormalAni()
end
function BdConvertFinishCtrl:OnSelectItem(itemId, btn, nHasCount)
UTILS.ClickItemGridWithTips(itemId, btn.transform, false, true, false, nHasCount)
end
function BdConvertFinishCtrl:PlayNormalAni()
self.sequence = DOTween.Sequence()
self.sequence:AppendInterval(0.18)
for i = 1, self.nRewardCount do
self.sequence:AppendCallback(function()
local goGrid = self._mapNode.goItemList1:GetChild(i - 1)
if goGrid then
NovaAPI.SetCanvasGroupAlpha(goGrid:GetComponent("CanvasGroup"), 1)
local ani = goGrid.transform:Find("AnimRoot/aniGrid"):GetComponent("Animator")
ani:Play("receiveprops_icon_t_in")
end
end)
self.sequence:AppendInterval(0.14)
end
self.sequence.onComplete = dotween_callback_handler(self, function()
self:CloseSkip()
end)
self.sequence:SetUpdate(true)
end
function BdConvertFinishCtrl:ShowReward(tbReward, sIconPath, callback)
self.tbReward = tbReward
self.nRewardCount = #tbReward
self.callback = callback
local sort = function(a, b)
local cfgA = ConfigTable.GetData_Item(a.id)
local cfgB = ConfigTable.GetData_Item(b.id)
local rarityA = cfgA.Rarity
local rarityB = cfgB.Rarity
local typeA = cfgA.Type
local typeB = cfgB.Type
if a.rewardType ~= nil ~= (b.rewardType ~= nil) then
return a.rewardType ~= nil and b.rewardType == nil
elseif a.rewardType and b.rewardType and a.rewardType ~= b.rewardType then
return a.rewardType < b.rewardType
elseif rarityA ~= rarityB then
return rarityA < rarityB
elseif typeA ~= typeB then
return typeA < typeB
elseif a.count ~= b.count then
return a.count > b.count
else
return a.id < b.id
end
end
table.sort(self.tbReward, sort)
self:RefreshNormal()
self:SetPngSprite(self._mapNode.img_icon:GetComponent("Image"), sIconPath)
self._mapNode.goBlur:SetActive(true)
local wait = function()
coroutine.yield(CS.UnityEngine.WaitForEndOfFrame())
self._mapNode.HideRoot:SetActive(true)
self._mapNode.aniRoot:Play("receiveprops_t_in")
WwiseAudioMgr:PlaySound("ui_roguelike_gacha_reward")
end
cs_coroutine.start(wait)
EventManager.Hit(EventId.TemporaryBlockInput, 0.5)
end
function BdConvertFinishCtrl:CloseSkip()
self._mapNode.btnSkip.gameObject:SetActive(false)
self._mapNode.btn_close.interactable = true
end
function BdConvertFinishCtrl:OnBtnClick_Close()
delChildren(self._mapNode.goItemList1)
EventManager.Hit("BdConvert_FinishPanelClose")
if self.callback ~= nil then
self.callback()
end
end
function BdConvertFinishCtrl:OnBtnClick_Skip(btn)
if self.sequence then
self.sequence:Kill()
self.sequence = nil
end
for i = 1, self.nRewardCount do
local goGrid = self._mapNode.goItemList1:GetChild(i - 1)
if goGrid then
NovaAPI.SetCanvasGroupAlpha(goGrid:GetComponent("CanvasGroup"), 1)
end
end
self:CloseSkip()
end
return BdConvertFinishCtrl
@@ -0,0 +1,23 @@
local BdConvertPanel = class("BdConvertPanel", BasePanel)
BdConvertPanel._bIsMainPanel = true
BdConvertPanel._sSortingLayerName = AllEnum.SortingLayerName.UI
BdConvertPanel._sUIResRootPath = "UI_Activity/"
BdConvertPanel._tbDefine = {
{
sPrefabPath = "_500001/BdConvertPanel.prefab",
sCtrlName = "Game.UI.Activity.BdConvert._500001.BdConvertCtrl"
}
}
function BdConvertPanel:Awake()
end
function BdConvertPanel:OnEnable()
end
function BdConvertPanel:OnAfterEnter()
end
function BdConvertPanel:OnDisable()
end
function BdConvertPanel:OnDestroy()
end
function BdConvertPanel:OnRelease()
end
return BdConvertPanel
@@ -0,0 +1,143 @@
local BdConvertQuestCtrl = class("BdConvertQuestCtrl", BaseCtrl)
local barMinX = -750
local barMaxX = 0
BdConvertQuestCtrl._mapNodeConfig = {
goBlur = {
sNodeName = "t_fullscreen_blur_blue"
},
animator = {sNodeName = "quest", sComponentName = "Animator"},
txtWindowTitle = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_QuestTitle"
},
btnClose = {
sComponentName = "UIButton",
callback = "OnBtnClick_Close"
},
btnFullClose = {
sComponentName = "UIButton",
callback = "OnBtnClick_Close"
},
txt_socreTitle = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_Score"
},
txt_score = {sComponentName = "TMP_Text"},
sv = {
sComponentName = "LoopScrollView"
},
btn_GetAllReward = {
sComponentName = "UIButton",
callback = "OnBtnClick_GetAllReward"
},
btn_GetAllReward_None = {
sComponentName = "UIButton",
callback = "OnBtnClick_GetAllReward"
},
txt_GetAll = {
nCount = 2,
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_GetQuestReward"
}
}
BdConvertQuestCtrl._mapEventConfig = {}
BdConvertQuestCtrl._mapRedDotConfig = {}
function BdConvertQuestCtrl:Awake()
local param = self:GetPanelParam()
if type(param) == "table" then
self.nActId = param[1]
end
self:InitData()
end
function BdConvertQuestCtrl:OnEnable()
self._mapNode.goBlur:SetActive(true)
self._mapNode.animator:Play("t_window_04_t_in")
EventManager.Hit(EventId.TemporaryBlockInput, 0.3)
end
function BdConvertQuestCtrl:OnDestory()
if self.tbItemCtrl ~= nil then
for _, ctrl in pairs(self.tbItemCtrl) do
self:UnbindCtrlByNode(ctrl)
end
end
end
function BdConvertQuestCtrl:InitData()
self.tbItemCtrl = {}
self.actData = PlayerData.Activity:GetActivityDataById(self.nActId)
self.bdConfig = self.actData:GetBdConvertConfig()
self:InitQuest()
self:UpdateScore()
local bHasComQuest = self.actData:CheckHasComQuest()
self._mapNode.btn_GetAllReward.gameObject:SetActive(bHasComQuest)
self._mapNode.btn_GetAllReward_None.gameObject:SetActive(not bHasComQuest)
end
function BdConvertQuestCtrl:InitQuest()
self.questIdList = self.actData:GetQuestIdList()
self._mapNode.sv:Init(#self.questIdList, self, self.OnGridRefresh)
end
function BdConvertQuestCtrl:OnGridRefresh(goGrid, gridIndex)
local nIndex = gridIndex + 1
local instanceId = goGrid:GetInstanceID()
local nId = self.questIdList[nIndex]
local questData = self.actData:GetQuestDataById(nId)
local img_Received = goGrid.transform:Find("GameObject/AnimRoot/Root/img_Received")
local btn_item = goGrid.transform:Find("GameObject/AnimRoot/Root/btn_item"):GetComponent("UIButton")
local item = goGrid.transform:Find("GameObject/AnimRoot/Root/btn_item/AnimRoot/item")
if self.tbItemCtrl[instanceId] == nil then
self.tbItemCtrl[instanceId] = self:BindCtrlByNode(item, "Game.UI.TemplateEx.TemplateItemCtrl")
end
local txtTarget = goGrid.transform:Find("GameObject/AnimRoot/Root/txt_target"):GetComponent("TMP_Text")
local txt_com1 = goGrid.transform:Find("GameObject/AnimRoot/txt_com1"):GetComponent("TMP_Text")
local txt_com2 = goGrid.transform:Find("GameObject/AnimRoot/txt_com2"):GetComponent("TMP_Text")
local bar = goGrid.transform:Find("GameObject/AnimRoot/Root/imgBarBg/rtBarFill/imgMainBarFill"):GetComponent("RectTransform")
local img_state1 = goGrid.transform:Find("GameObject/AnimRoot/Root/img_state1").gameObject
local img_state2 = goGrid.transform:Find("GameObject/AnimRoot/Root/img_state2").gameObject
local img_state3 = goGrid.transform:Find("GameObject/AnimRoot/Root/img_state3").gameObject
img_state1:SetActive(questData.nState == AllEnum.ActQuestStatus.Complete)
img_state2:SetActive(questData.nState == AllEnum.ActQuestStatus.Received)
img_state3:SetActive(questData.nState == AllEnum.ActQuestStatus.UnComplete)
img_Received.gameObject:SetActive(questData.nState == AllEnum.ActQuestStatus.Received)
btn_item.onClick:RemoveAllListeners()
local questConfig = ConfigTable.GetData("BdConvertRewardGroup", questData.nId)
local tbReward = decodeJson(questConfig.Rewards)
local itemId = 0
local itemCount = 0
for k, v in pairs(tbReward) do
itemId = tonumber(k)
itemCount = tonumber(v)
end
btn_item.onClick:AddListener(function()
UTILS.ClickItemGridWithTips(itemId, btn_item.transform, true, false, false)
end)
self.tbItemCtrl[instanceId]:SetItem(itemId, nil, itemCount, false, questData.nState == AllEnum.ActQuestStatus.Received, false, false)
NovaAPI.SetTMPText(txtTarget, questConfig.Des)
if questData.nState == AllEnum.ActQuestStatus.UnComplete then
NovaAPI.SetTMPText(txt_com1, tostring(questData.nCur) .. "/" .. tostring(questData.nMax))
NovaAPI.SetTMPText(txt_com2, tostring(questData.nCur) .. "/" .. tostring(questData.nMax))
else
NovaAPI.SetTMPText(txt_com1, ConfigTable.GetUIText("BdConvert_QuestFinish"))
NovaAPI.SetTMPText(txt_com2, ConfigTable.GetUIText("BdConvert_QuestFinish"))
end
txt_com1.gameObject:SetActive(questData.nState ~= AllEnum.ActQuestStatus.Received)
txt_com2.gameObject:SetActive(questData.nState == AllEnum.ActQuestStatus.Received)
bar.anchoredPosition = Vector2(barMinX + (barMaxX - barMinX) * (questData.nCur / questData.nMax), bar.anchoredPosition.y)
end
function BdConvertQuestCtrl:UpdateScore()
local nCurScore = self.actData:GetScore()
local nMaxScore = self.bdConfig.ScoreItemLimit
NovaAPI.SetTMPText(self._mapNode.txt_score, string.format("<color=#D19C62>%s</color>/%s", nCurScore, nMaxScore))
end
function BdConvertQuestCtrl:OnBtnClick_Close()
self._mapNode.animator:Play("t_window_04_t_out")
EventManager.Hit(EventId.TemporaryBlockInput, 0.3)
self:AddTimer(1, 0.3, function()
EventManager.Hit(EventId.ClosePanel, PanelId.BdConvertQuestPanel)
end, true, true, true, nil)
end
function BdConvertQuestCtrl:OnBtnClick_GetAllReward()
local callback = function()
self:InitData()
end
self.actData:RequestReceiveQuest(callback)
end
return BdConvertQuestCtrl
@@ -0,0 +1,23 @@
local BdConvertQuestPanel = class("BdConvertQuestPanel", BasePanel)
BdConvertQuestPanel._bIsMainPanel = false
BdConvertQuestPanel._sSortingLayerName = AllEnum.SortingLayerName.UI
BdConvertQuestPanel._sUIResRootPath = "UI_Activity/"
BdConvertQuestPanel._tbDefine = {
{
sPrefabPath = "_500001/BdConvertQuestPanel.prefab",
sCtrlName = "Game.UI.Activity.BdConvert._500001.BdConvertQuestCtrl"
}
}
function BdConvertQuestPanel:Awake()
end
function BdConvertQuestPanel:OnEnable()
end
function BdConvertQuestPanel:OnAfterEnter()
end
function BdConvertQuestPanel:OnDisable()
end
function BdConvertQuestPanel:OnDestroy()
end
function BdConvertQuestPanel:OnRelease()
end
return BdConvertQuestPanel
@@ -0,0 +1,182 @@
local BdConvertActCtrl = class("BdConvertActCtrl", BaseCtrl)
local TimerManager = require("GameCore.Timer.TimerManager")
local LocalSettingData = require("GameCore.Data.LocalSettingData")
local Actor2DManager = require("Game.Actor2D.Actor2DManager")
local barMinX = -378
local barMaxX = 0
BdConvertActCtrl._mapNodeConfig = {
txt_time = {sComponentName = "TMP_Text"},
txt_des = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_DesTitle"
},
btn_des = {
sComponentName = "UIButton",
callback = "OnBtnClick_Detail"
},
txt_quest = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_QuestTitle"
},
redDotQuest = {},
btn_quest = {
sComponentName = "UIButton",
callback = "OnBtnClick_Quest"
},
txt_mainProcess = {sComponentName = "TMP_Text"},
imgMainBarFill = {
sComponentName = "RectTransform"
},
txt_go = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_EnterActivity"
},
btn_go = {
sComponentName = "UIButton",
callback = "OnBtnClick_Go"
},
txtRewardTitle = {
sComponentName = "TMP_Text",
sLanguageId = "BdConvert_RewardPre"
},
svItem = {
sComponentName = "LoopScrollView"
},
imgBgLevelSelect = {
sNodeName = "----Actor2D----",
sComponentName = "RawImage"
},
trActor2D_PNG = {
sNodeName = "----Actor2D_PNG----",
sComponentName = "Transform"
}
}
BdConvertActCtrl._mapEventConfig = {BdConvertQuestUpdate = "InitQuest"}
BdConvertActCtrl._mapRedDotConfig = {
[RedDotDefine.Activity_BdConvert_AllQuest] = {
sNodeName = "redDotQuest"
}
}
function BdConvertActCtrl:RefreshRemainTime()
if self.actData.actCfg.EndType == GameEnum.activityEndType.NoLimit then
self._mapNode.txt_time.transform.parent.gameObject:SetActive(false)
else
local endTime = self.actData:GetActEndTime()
local curTime = CS.ClientManager.Instance.serverTimeStamp
local remainTime = endTime - curTime
if remainTime < 0 then
TimerManager.Remove(self.remainTimer)
self.remainTimer = nil
EventManager.Hit(EventId.OpenMessageBox, {
nType = AllEnum.MessageBox.Alert,
sContent = ConfigTable.GetUIText("Activity_Invalid_Tip_1"),
callbackConfirm = function()
EventManager.Hit(EventId.ClosePanel, PanelId.ActivityList)
end
})
end
local sTimeStr = self:GetTimeText(remainTime)
NovaAPI.SetTMPText(self._mapNode.txt_time, orderedFormat(ConfigTable.GetUIText("PerActivity_Remain_Time") or "", sTimeStr))
end
end
function BdConvertActCtrl:GetTimeText(remainTime)
local sTimeStr = ""
if remainTime <= 60 then
local sec = math.floor(remainTime)
sTimeStr = orderedFormat(ConfigTable.GetUIText("Activity_Remain_Time_Sec") or "", sec)
elseif 60 < remainTime and remainTime <= 3600 then
local min = math.floor(remainTime / 60)
local sec = math.floor(remainTime - min * 60)
sTimeStr = orderedFormat(ConfigTable.GetUIText("Activity_Remain_Time_Min") or "", min, sec)
elseif 3600 < remainTime and remainTime <= 86400 then
local hour = math.floor(remainTime / 3600)
local min = math.floor((remainTime - hour * 3600) / 60)
sTimeStr = orderedFormat(ConfigTable.GetUIText("Activity_Remain_Time_Hour") or "", hour, min)
elseif 86400 < remainTime then
local day = math.floor(remainTime / 86400)
local hour = math.floor((remainTime - day * 86400) / 3600)
sTimeStr = orderedFormat(ConfigTable.GetUIText("Activity_Remain_Time_Day") or "", day, hour)
end
return sTimeStr
end
function BdConvertActCtrl:InitItem()
local rewardData = ConfigTable.GetData("BdConvertControl", self.nActId)
if rewardData == nil then
return
end
self.tbReward = rewardData.RewardsShow
self.tbItemIns = {}
self._mapNode.svItem:Init(#self.tbReward, self, self.OnGridRefresh, self.OnGridBtnClick)
end
function BdConvertActCtrl:OnGridRefresh(go, nIndex)
local nDataIndex = nIndex + 1
local itemId = self.tbReward[nDataIndex]
local goItem = go.transform:Find("btnGrid/AnimRoot/tcItem").gameObject
local instanceId = goItem:GetInstanceID()
if self.tbItemIns[instanceId] == nil then
self.tbItemIns[instanceId] = self:BindCtrlByNode(goItem, "Game.UI.TemplateEx.TemplateItemCtrl")
end
self.tbItemIns[instanceId]:SetItem(itemId)
end
function BdConvertActCtrl:OnGridBtnClick(go, nIndex)
local nDataIndex = nIndex + 1
local itemId = self.tbReward[nDataIndex]
UTILS.ClickItemGridWithTips(itemId, go.transform:Find("btnGrid"), true, false, false)
end
function BdConvertActCtrl:InitQuest()
local allCount = self.actData:GetAllQuestCount()
local receivedCount = self.actData:GetAllReceivedCount()
NovaAPI.SetTMPText(self._mapNode.txt_mainProcess, receivedCount .. "/" .. allCount)
self._mapNode.imgMainBarFill.anchoredPosition = Vector2(barMinX + (barMaxX - barMinX) * (receivedCount / allCount), self._mapNode.imgMainBarFill.anchoredPosition.y)
end
function BdConvertActCtrl:InitActData(actData)
self.actData = actData
self.nActId = actData:GetActId()
self:RefreshRemainTime()
if nil == self.remainTimer then
self.remainTimer = self:AddTimer(0, 1, "RefreshRemainTime", true, true, false)
end
self:InitItem()
self:InitQuest()
local bUseL2D = LocalSettingData.mapData.UseLive2D
self._mapNode.imgBgLevelSelect.transform.localScale = bUseL2D == true and Vector3.one or Vector3.zero
self._mapNode.trActor2D_PNG.localScale = bUseL2D == true and Vector3.zero or Vector3.one
if bUseL2D == true then
Actor2DManager.SetBoardNPC2D(PanelId.BdConvertActPanel, self._mapNode.imgBgLevelSelect, 9102)
else
Actor2DManager.SetBoardNPC2D_PNG(self._mapNode.trActor2D_PNG, PanelId.BdConvertActPanel, 9102)
end
end
function BdConvertActCtrl:ClearActivity()
Actor2DManager.UnsetBoardNPC2D()
if self.tbItemIns ~= nil then
for _, ctrl in pairs(self.tbItemIns) do
self:UnbindCtrlByNode(ctrl)
end
end
self.tbItemIns = {}
end
function BdConvertActCtrl:OnBtnClick_Detail()
local config = ConfigTable.GetData("BdConvertControl", self.nActId)
if config == nil then
return
end
EventManager.Hit(EventId.OpenMessageBox, {
nType = AllEnum.MessageBox.Desc,
sContent = config.DesText,
sTitle = ConfigTable.GetUIText("Activity_Btn_Detail")
})
end
function BdConvertActCtrl:OnBtnClick_Quest()
EventManager.Hit(EventId.OpenPanel, PanelId.BdConvertQuestPanel, self.nActId)
end
function BdConvertActCtrl:OnBtnClick_Go()
local bPlayCond = self.actData:CheckActJumpCond(true)
if not bPlayCond then
return
end
self.actData:RequestAllBuildData(function()
EventManager.Hit(EventId.OpenPanel, PanelId.BdConvertPanel, self.nActId)
end)
end
return BdConvertActCtrl