Files
Endfield-Data/LuaScripts/Phase/CharFormation/PhaseCharFormation.lua
2026-01-31 21:42:01 +07:00

2415 lines
68 KiB
Lua

local phaseBase = require_ex('Phase/Core/PhaseBase')
local PHASE_ID = PhaseId.CharFormation
local OVERRIDE_CAMERA_PATH = "OverrideCameras/"
local MODEL_CACHE_TOTAL_NUM = 6
local MODEL_LOADING_TAG = -1
local VIRTUAL_MOUSE_HINT_KEY = "virtual_mouse_hint_edit"
local PHASE_CHAR_FORMATION_GAME_OBJECT = "CharFormation"
PhaseCharFormation = HL.Class('PhaseCharFormation', phaseBase.PhaseBase)
local Panels = { PanelId.CharFormation, }
local CameraIndex = {
Team = 1,
TeamEx = 2,
Single = 3,
Multi = 4,
OverrideSingle = 5,
}
local AUDIO_EVENT_CHAR_GLITCH = "Au_UI_Event_CharFormation_Glitch"
local AUDIO_EVENT_CHAR_GLITCH_INTERVAL = 0.1
PhaseCharFormation.s_messages = HL.StaticField(HL.Table) << {
[MessageConst.SQUAD_CHANGE] = { '_OnSquadChange', true },
[MessageConst.SQUAD_NAME_CHANGE] = { '_OnSquadNameChange', true },
[MessageConst.ON_CHAR_TEAM_MEMBER_COUNT_CHANGED] = { 'OnSlotLockChanged', true },
[MessageConst.TEAM_NORMAL_SKILL_CHANGE] = { '_OnCharTeamNormalSkillChange', true },
[MessageConst.ON_PUT_ON_WEAPON] = { 'OnPutOnWeapon', true },
[MessageConst.ON_GEM_ATTACH] = { 'OnGemChanged', true },
[MessageConst.ON_GEM_DETACH] = { 'OnGemChanged', true },
[MessageConst.ON_WEAPON_ATTACH_GEM_ENHANCE_MAX] = { 'OnGemChanged', true },
[MessageConst.ON_CHAR_POTENTIAL_UNLOCK] = { 'OnCharPotentialUnlock', true },
[MessageConst.PRE_LEVEL_START] = { 'OnPreLevelStart', false },
[MessageConst.ON_SCENE_LOAD_START] = { 'OnSceneLoadStart', false },
[MessageConst.ON_SWITCH_LANGUAGE] = { '_OnSwitchLanguage', false },
[MessageConst.ON_CAMPFIRE_OPEN_FORMATION] = { 'OnCampfireOpenFormation', false },
[MessageConst.ON_CHAR_FORMATION_LIST_MULTI_SELECT] = { 'OnCharListMultiSelect', true },
[MessageConst.ON_CHAR_FORMATION_LIST_SINGLE_SELECT] = { 'OnCharListSingleSelect', true },
[MessageConst.ON_CHAR_FORMATION_SELECT_TEAM_CHANGE] = { 'OnCurSelectTeamChange', true },
[MessageConst.ON_CHAR_FORMATION_TEAM_SET] = { 'OnCharListTeamSet', true },
[MessageConst.ON_CHAR_FORMATION_ENTER_MULTI_SELECT] = { 'OnEnterMultiSelect', true },
[MessageConst.ON_CHAR_FORMATION_LIST_CONFIRM] = { 'OnCharListConfirm', true },
[MessageConst.ON_CHAR_FORMATION_CONFIRM_SINGLE_CHAR] = { 'OnConfirmSingleChar', true },
[MessageConst.ON_CHAR_FORMATION_UNEQUIP_INDEX] = { 'OnUnEquipIndex', true },
[MessageConst.ON_CHAR_FORMATION_REFRESH_SLOT] = { 'OnRefreshSlot', true },
[MessageConst.ON_CHAR_FORMATION_CHANGE_HOVER_INDEX] = { 'OnChangeSlotHoverIndex', true },
[MessageConst.ON_CHAR_FORMATION_CONFIRM_HOVER] = { 'OnConfirmSelectedSlotHover', true },
}
PhaseCharFormation.m_curTeam = HL.Field(HL.Table)
PhaseCharFormation.m_tmpTeam = HL.Field(HL.Table)
PhaseCharFormation.m_tempMultiSelectCharInfoList = HL.Field(HL.Table)
PhaseCharFormation.m_curTeamIndex = HL.Field(HL.Number) << 1
PhaseCharFormation.m_teamSkillCache = HL.Field(HL.Table)
PhaseCharFormation.m_charFormation = HL.Field(HL.Forward("PhasePanelItem"))
PhaseCharFormation.m_skillTip = HL.Field(HL.Forward("PhasePanelItem"))
PhaseCharFormation.m_sceneObject = HL.Field(HL.Forward("PhaseGameObjectItem"))
PhaseCharFormation.m_singleCharIndex = HL.Field(HL.Number) << -1
PhaseCharFormation.m_navigatedCharIndex = HL.Field(HL.Number) << -1
PhaseCharFormation.m_inited = HL.Field(HL.Boolean) << false
PhaseCharFormation.m_virtualMouseInited = HL.Field(HL.Boolean) << false
PhaseCharFormation.m_clearedKey = HL.Field(HL.Number) << -1
PhaseCharFormation.m_updateModelsCounter = HL.Field(HL.Number) << 0
PhaseCharFormation.m_charModelCache = HL.Field(HL.Table)
PhaseCharFormation.m_charModelInUse = HL.Field(HL.Table)
PhaseCharFormation.m_templateId2LightGroup = HL.Field(HL.Table)
PhaseCharFormation.m_templateId2TrackGroup = HL.Field(HL.Table)
PhaseCharFormation.m_templateId2CameraGroup = HL.Field(HL.Table)
PhaseCharFormation.m_templateId2VolumeGroup = HL.Field(HL.Table)
PhaseCharFormation.m_charVolumeTween = HL.Field(HL.Userdata)
PhaseCharFormation.m_overrideSingleCamera = HL.Field(HL.Userdata)
PhaseCharFormation.m_cacheNum = HL.Field(HL.Number) << 0
PhaseCharFormation.m_tickKey = HL.Field(HL.Number) << -1
PhaseCharFormation.m_waitModels = HL.Field(HL.Table)
PhaseCharFormation.m_preCharInfoList = HL.Field(HL.Table)
PhaseCharFormation.m_lastPostGlitchEventTime = HL.Field(HL.Number) << 0
PhaseCharFormation.m_hideCamCor = HL.Field(HL.Thread)
PhaseCharFormation._OnInit = HL.Override() << function(self)
self:_ProcessArgs()
self.m_curTeam = {}
self.m_charModelCache = {}
self.m_charModelInUse = {}
self.m_templateId2LightGroup = {}
self.m_templateId2TrackGroup = {}
self.m_templateId2CameraGroup = {}
self.m_templateId2VolumeGroup = {}
self.m_teamSkillCache = {}
self.m_waitModels = nil
self.m_tickKey = LuaUpdate:Add("Tick", function(deltaTime)
self:_TryConsumeWaitModels()
end)
PhaseCharFormation.Super._OnInit(self)
CS.HG.Rendering.ScriptBridge.HGRenderBridgeStatics.SetVFXPPPriorityFilterCinematic()
CS.HG.Rendering.ScriptBridge.HGRenderBridgeStatics.SetSceneDarkEnabled(false)
end
PhaseCharFormation._OnRefresh = HL.Override() << function(self)
self:_ProcessArgs()
self:_BackToTeamSet()
PhaseCharFormation.Super._OnRefresh(self)
self.m_charFormation.uiCtrl:InitSelectTeam()
end
PhaseCharFormation.PrepareTransition = HL.Override(HL.Number, HL.Boolean, HL.Opt(HL.Number)) << function(self, transitionType, fastMode, anotherPhaseId)
if transitionType == PhaseConst.EPhaseState.TransitionIn and not fastMode then
UIManager:PreloadPanelAsset(PanelId.CharFormation, PHASE_ID)
end
if not fastMode and (transitionType == PhaseConst.EPhaseState.TransitionIn or transitionType == PhaseConst.EPhaseState.TransitionOut) then
coroutine.waitCondition(function()
return true
end, coroutine.TailTick)
Notify(MessageConst.PREPARE_BLOCK_GLITCH_TRANSITION)
coroutine.waitForRenderDone()
end
if transitionType == PhaseConst.EPhaseState.TransitionBackToTop then
self.m_hideCamCor = self:_ClearCoroutine(self.m_hideCamCor)
self.m_sceneObject.view.light.gameObject:SetActive(true)
end
end
PhaseCharFormation._DoPhaseTransitionIn = HL.Override(HL.Boolean, HL.Opt(HL.Table)) << function(self, fastMode, args)
if not fastMode then
Notify(MessageConst.SHOW_BLOCK_GLITCH_TRANSITION)
end
self:_InitGameObject()
if self.m_sceneObject then
self.m_sceneObject.go:SetActive(true)
end
end
PhaseCharFormation._OnActivated = HL.Override() << function(self)
self:_InitPhaseItems()
UIManager:Hide(PanelId.Touch)
self:_PlayTeamVoice()
self:_HideSkillTip()
self:_InitControllerSlotSelectedState()
self.m_hideCamCor = self:_ClearCoroutine(self.m_hideCamCor)
self.m_sceneObject.view.light.gameObject:SetActive(true)
CameraManager:AddMainCamCullingMaskConfig("CharFormation", UIConst.LAYERS.CharFormation)
CS.HG.Rendering.ScriptBridge.HGRenderBridgeStatics.SetVFXPPPriorityFilterCinematic()
CS.HG.Rendering.ScriptBridge.HGRenderBridgeStatics.SetSceneDarkEnabled(false)
end
PhaseCharFormation._OnDeActivated = HL.Override() << function(self)
self:_HideSkillTip()
CameraManager:RemoveMainCamCullingMaskConfig("CharFormation")
end
PhaseCharFormation._DoPhaseTransitionOut = HL.Override(HL.Boolean, HL.Opt(HL.Table)) << function(self, fastMode, args)
if not fastMode then
Notify(MessageConst.SHOW_BLOCK_GLITCH_TRANSITION)
end
end
PhaseCharFormation._DoPhaseTransitionBehind = HL.Override(HL.Boolean, HL.Opt(HL.Table)) << function(self, fastMode, args)
self.m_hideCamCor = self:_ClearCoroutine(self.m_hideCamCor)
self.m_hideCamCor = self:_StartCoroutine(function()
coroutine.wait(1)
self.m_sceneObject.view.light.gameObject:SetActive(false)
end)
end
PhaseCharFormation._DoPhaseTransitionBackToTop = HL.Override(HL.Boolean, HL.Opt(HL.Table)) << function(self, fastMode, args)
end
PhaseCharFormation._OnDestroy = HL.Override() << function(self)
CameraManager:RemoveMainCamCullingMaskConfig("CharFormation")
if self.m_tickKey > 0 then
LuaUpdate:Remove(self.m_tickKey)
self.m_tickKey = -1
end
self:_ClearUIComp()
UIManager:Show(PanelId.Touch)
CS.HG.Rendering.ScriptBridge.HGRenderBridgeStatics.SetVFXPPPriorityFilterNormal()
CS.HG.Rendering.ScriptBridge.HGRenderBridgeStatics.SetSceneDarkEnabled(true)
GameInstance.player.charBag:ClearAllClientCharAndItemData()
end
PhaseCharFormation._ProcessArgs = HL.Method() << function(self)
self.arg = self.arg or {}
if type(self.arg) == "string" then
local teamConfigId = self.arg
self.arg = {}
self.arg.lockedTeamData = self:_GenerateLockedFormationData(teamConfigId)
end
if not string.isEmpty(self.arg.dungeonId) then
local hasValue
local subGameData
hasValue, subGameData = DataManager.subGameInstDataTable:TryGetValue(self.arg.dungeonId)
if hasValue and not string.isEmpty(subGameData.teamConfigId) then
self.arg.lockedTeamData = self:_GenerateLockedFormationData(subGameData.teamConfigId)
end
end
self.m_lockedTeamData = self.arg.lockedTeamData
end
PhaseCharFormation._InitPhaseItems = HL.Method() << function(self)
self:_InitGameObject()
if not self.m_inited then
for _, panelId in pairs(Panels) do
self:CreatePhasePanelItem(panelId, self.arg)
end
self.m_charFormation = self:_GetPanelPhaseItem(PanelId.CharFormation)
self.m_charFormation.uiCtrl:InitSelectTeam()
end
self.m_inited = true
end
PhaseCharFormation._InitGameObject = HL.Method() << function(self)
if not self.m_sceneObject then
self.m_sceneObject = self:CreatePhaseGOItem(PHASE_CHAR_FORMATION_GAME_OBJECT)
self:RefreshCameraController(CameraIndex.Team)
self.m_sceneObject.view.cameraAnimWrapper:ClearTween()
self.m_sceneObject.view.cameraAnimWrapper:PlayInAnimation()
end
self:_InitSlots()
self:_Refresh3DUIVisible(true)
end
PhaseCharFormation.OnCampfireOpenFormation = HL.StaticMethod(HL.Table) << function(msgArg)
local arg = {}
PhaseManager:GoToPhase(PhaseId.CharFormation, arg)
end
PhaseCharFormation.OnCommonBackClicked = HL.Method() << function(self)
if self.m_charFormation.uiCtrl.state == UIConst.UI_CHAR_FORMATION_STATE.CharChange or
self.m_charFormation.uiCtrl.state == UIConst.UI_CHAR_FORMATION_STATE.SingleChar then
self:_BackToTeamSet()
else
self:CloseSelf()
end
end
PhaseCharFormation.OnShowSkillTips = HL.Method(HL.Table) << function(self, arg)
local skillInfo, showTypeAll = unpack(arg)
if not self.m_skillTip then
self.m_skillTip = self:CreatePhasePanelItem(PanelId.CharFormationSkillTips, {
isSkillTipSelectable = showTypeAll,
})
end
self.m_skillTip.uiCtrl:SetTeamIndex(self.m_curTeamIndex)
self.m_skillTip.uiCtrl:ShowTip(skillInfo, showTypeAll, self.m_teamSkillCache)
end
PhaseCharFormation.OnCharListSingleSelect = HL.Method(HL.Any) << function(self, arg)
local arg1, arg2 = unpack(arg)
local cellInfo = arg2
local curCharItem = self.m_tmpTeam[self.m_singleCharIndex]
local curInstId = curCharItem and curCharItem.instId or nil
local instId = cellInfo.instId
local curSelectedInstId = nil
if self.m_curTeam and self.m_singleCharIndex and self.m_curTeam[self.m_singleCharIndex] then
curSelectedInstId = self.m_curTeam[self.m_singleCharIndex].charInstId
end
local slotIndex = cellInfo.slotIndex
local info = {
charInstId = instId,
charId = cellInfo.templateId,
isLocked = cellInfo.isLocked,
isTrail = cellInfo.isTrail,
isReplaceable = cellInfo.isReplaceable,
}
local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(instId)
local isDead = charInfo.isDead
local singleState
if instId == curInstId then
singleState = UIConst.UI_CHAR_FORMATION_SINGLE_STATE.Current
if self.m_lockedTeamData and self.m_singleCharIndex <= self.m_lockedTeamData.lockedTeamMemberCount then
singleState = UIConst.UI_CHAR_FORMATION_SINGLE_STATE.CurrentLocked
end
elseif isDead then
singleState = UIConst.UI_CHAR_FORMATION_SINGLE_STATE.OtherDead
elseif slotIndex and slotIndex <= Const.BATTLE_SQUAD_MAX_CHAR_NUM then
if cellInfo.isLocked then
singleState = UIConst.UI_CHAR_FORMATION_SINGLE_STATE.OtherInTeamLocked
else
singleState = UIConst.UI_CHAR_FORMATION_SINGLE_STATE.OtherInTeam
end
else
if self.m_lockedTeamData and self.m_singleCharIndex <= self.m_lockedTeamData.lockedTeamMemberCount and
(not self.m_lockedTeamData.chars[self.m_singleCharIndex].isReplaceable
or (self.m_lockedTeamData.chars[self.m_singleCharIndex].isReplaceable and
cellInfo.templateId ~= self.m_curTeam[self.m_singleCharIndex].charId)) then
singleState = UIConst.UI_CHAR_FORMATION_SINGLE_STATE.OtherUnavailable
else
singleState = UIConst.UI_CHAR_FORMATION_SINGLE_STATE.OtherAvailable
end
end
self.m_charFormation.uiCtrl:RefreshCharInformation(info, self.m_teamSkillCache)
self.m_charFormation.uiCtrl:RefreshSingleBtns(singleState, info)
self:UpdateChar(self.m_singleCharIndex, info)
self:_RefreshEmpty()
Utils.triggerVoice("chrbark_squad", info.charId)
local cameraData = {
cameraIndex = CameraIndex.Single,
singleIndex = self.m_singleCharIndex,
charInfo = info,
}
self:_RefreshCamera(cameraData)
self:_HideSkillTip()
local slot = self.m_sceneObject.view["slot" .. string.format("%d", self.m_singleCharIndex)]
slot.slotCharDisableFx.gameObject:SetActive(isDead)
end
PhaseCharFormation.OnCharListMultiSelect = HL.Method(HL.Any) << function(self, arg)
local arg1, arg2 = unpack(arg)
local charItemList = arg1
local charInfoList = arg2
self.m_tmpTeam = charItemList
self.m_tempMultiSelectCharInfoList = charInfoList
self:_TryUpdateModels(charInfoList)
self:_RefreshEmpty()
for i = 1, Const.BATTLE_SQUAD_MAX_CHAR_NUM do
local slot = self.m_sceneObject.view["slot" .. string.format("%d", i)]
local isDead = false
local charInfo
local instId = charItemList[i] and charItemList[i].instId or nil
if instId then
charInfo = CharInfoUtils.getPlayerCharInfoByInstId(instId)
isDead = charInfo.isDead
end
slot.slotCharDisable.gameObject:SetActive(isDead)
slot.slotCharDisableFx.gameObject:SetActive(isDead)
self:_SetActiveCharMark(i, charInfo == nil)
end
end
PhaseCharFormation._RefreshEmpty = HL.Method(HL.Opt(HL.Boolean)) << function(self, forceEmpty)
if not self.m_charFormation then
return
end
local empty
if forceEmpty ~= nil then
empty = forceEmpty
else
empty = self.m_charFormation.uiCtrl:GetCharListEmpty()
end
self.m_charFormation.uiCtrl:RefreshEmpty(empty)
end
PhaseCharFormation.OnEnterMultiSelect = HL.Method(HL.Opt(HL.Any)) << function(self, _)
local cameraData = {
cameraIndex = CameraIndex.Multi,
}
self:_RefreshCamera(cameraData)
self.m_tmpTeam = self.m_charFormation.uiCtrl:GetCurCharList()
self:_RefreshEmpty()
self:_Refresh3DUIVisible(false)
self:_HideAllControllerSlotSelected()
end
PhaseCharFormation.OnCharListConfirm = HL.Method(HL.Any) << function(self, teamNum)
local res = self:_TrySendSetSquad()
if res then
self:_PlayCharListVoice()
self:_BackToTeamSet(true)
end
end
PhaseCharFormation.OnConfirmSingleChar = HL.Method(HL.Any) << function(self, teamNum)
self.m_tmpTeam = nil
local res = self:_TrySendSetSquad()
if res then
self:_PlaySingleCharVoice()
self:_BackToTeamSet(true)
end
end
PhaseCharFormation.OnUnEquipIndex = HL.Method() << function(self)
if #self.m_tmpTeam == 1 then
Notify(MessageConst.SHOW_TOAST, Language.LUA_CAN_NOT_UNEQUIP)
return
end
self.m_tmpTeam[self.m_singleCharIndex] = nil
self.m_curTeam[self.m_singleCharIndex] = nil
local res = self:_TrySendSetSquad()
if res then
self:_BackToTeamSet(true)
end
end
PhaseCharFormation.OnCharListTeamSet = HL.Method(HL.Opt(HL.Boolean)) << function(self, ignoreCheck)
self:_SendChangeActiveSquad(ignoreCheck)
end
PhaseCharFormation.OnEnterSingleChar = HL.Method(HL.Number) << function(self, index)
self.m_singleCharIndex = index
local curIndexInfo = self.m_curTeam[self.m_singleCharIndex]
local charInstId
if curIndexInfo then
charInstId = curIndexInfo.charInstId
Utils.triggerVoice("chrbark_squad", curIndexInfo.charId)
end
self.m_charFormation.uiCtrl:SetSingleCharIndex(index)
self.m_charFormation.uiCtrl:OpenCharList(UIConst.CharListMode.Single, charInstId)
self.m_charFormation.uiCtrl:SetState(UIConst.UI_CHAR_FORMATION_STATE.SingleChar)
self:RefreshSlotVisible(index)
local cameraData = {
cameraIndex = CameraIndex.Single,
singleIndex = index,
charInfo = curIndexInfo,
}
self:_RefreshCamera(cameraData)
self.m_charFormation.uiCtrl:SetCharListMode(UIConst.CharListMode.Single, charInstId)
local charInfoList = {}
charInfoList[self.m_singleCharIndex] = self.m_curTeam[self.m_singleCharIndex]
self:_TryUpdateModels(charInfoList)
self.m_tmpTeam = self.m_charFormation.uiCtrl:GetCurCharList()
self:_RefreshEmpty()
self:_Refresh3DUIVisible(false)
self:_HideAllControllerSlotSelected()
end
PhaseCharFormation.OnCurSelectTeamChange = HL.Method(HL.Number) << function(self, teamIndex)
self.m_curTeamIndex = teamIndex
local isLockedTeam = self.m_lockedTeamData ~= nil
self.m_sceneObject.view.formationDeco.gameObject:SetActive(not isLockedTeam)
if not isLockedTeam then
self.m_sceneObject.view.formationDeco.textNum.text = string.format("0%d", teamIndex)
self.m_sceneObject.view.formationDeco.animationWrapper:PlayInAnimation()
end
self:_RefreshTeamChars()
if self.m_skillTip then
self.m_skillTip.uiCtrl:SetTeamIndex(self.m_curTeamIndex)
end
end
PhaseCharFormation._CheckCurModelsReady = HL.Method().Return(HL.Boolean) << function(self)
for _, phaseCharItem in pairs(self.m_charModelInUse) do
if phaseCharItem and phaseCharItem == -1 then
return false
end
end
return true
end
PhaseCharFormation._TryUpdateModels = HL.Method(HL.Table) << function(self, charInfoList)
self.m_updateModelsCounter = self.m_updateModelsCounter + 1
self.m_waitModels = charInfoList
self:_TryConsumeWaitModels()
end
PhaseCharFormation._TryConsumeWaitModels = HL.Method() << function(self)
if not self:_CheckCurModelsReady() then
return
end
if not self.m_waitModels then
return
end
self:_DoRefreshAllModels(self.m_waitModels)
self.m_waitModels = nil
end
PhaseCharFormation.UpdateChar = HL.Method(HL.Number, HL.Table) << function(self, index, charInfo)
local charInfoList = {}
charInfoList[index] = charInfo
self:_TryUpdateModels(charInfoList)
local curIndex = nil
if self.m_charFormation.uiCtrl.state == UIConst.UI_CHAR_FORMATION_STATE.SingleChar then
self.m_curTeam = {}
for _, char in pairs(self.m_tmpTeam) do
local newCharInfo = {
charInstId = char.instId,
charId = char.templateId,
isLocked = char.isLocked,
isTrail = char.isTrail,
isReplaceable = char.isReplaceable,
}
table.insert(self.m_curTeam, newCharInfo)
end
end
for i, info in pairs(self.m_curTeam) do
if info and info.charId == charInfo.charId and info.charInstId == charInfo.charInstId then
curIndex = i
end
end
if curIndex then
self.m_curTeam[curIndex] = nil
end
self.m_curTeam[index] = charInfo
end
PhaseCharFormation.UpdateCharList = HL.Method(HL.Table) << function(self, charInfoList)
self:_TryUpdateModels(charInfoList)
self.m_curTeam = charInfoList
end
PhaseCharFormation._MoveCharModel2Index = HL.Method(HL.Table, HL.Number) << function(self,
cacheData,
desSlotIndex)
if cacheData then
local phaseCharItem = cacheData.phaseCharItem
local srcSlotIndex = cacheData.slotIndex
local animStateInt = desSlotIndex
if self.m_singleCharIndex > 0 and self.m_singleCharIndex == desSlotIndex then
animStateInt = 0
end
if srcSlotIndex ~= desSlotIndex then
local parent = self.m_sceneObject.view[string.format("charContainer%d", desSlotIndex)]
phaseCharItem:SetParent(parent)
phaseCharItem:SetPos(Vector3.zero)
PhaseCharFormation._UpdateModelName(phaseCharItem, srcSlotIndex, desSlotIndex)
end
self:_RefreshPhaseCharItem(phaseCharItem, animStateInt, desSlotIndex)
end
end
PhaseCharFormation._RefreshPhaseCharItem = HL.Method(HL.Forward("PhaseCharItem"), HL.Number, HL.Number) << function(
self,phaseCharItem,animStateInt, desSlotIndex)
local weaponState = animStateInt > 0 and CS.Beyond.Gameplay.View.CharUIModelMono.WeaponState.FORCE_SHOW or CS.Beyond.Gameplay.View.CharUIModelMono.WeaponState.FORCE_HIDE
phaseCharItem:SetVisible(true)
phaseCharItem:SetTrigger(UIConst.PHASE_CHAR_ITEM_ENABLE_SWITCH_FORMATION)
phaseCharItem:SetInteger(PhaseConst.PHASE_CHAR_ITEM_FORMATION_PARAM_NAME, animStateInt)
phaseCharItem:ReloadWeapon()
phaseCharItem:SwitchWeaponState(weaponState)
phaseCharItem.uiModelMono:ForceUpdateAnimator()
local isModelChanged = self.m_preCharInfoList == nil or self.m_preCharInfoList[desSlotIndex] == nil or
self.m_preCharInfoList[desSlotIndex].charInstId ~= phaseCharItem.charInstId
if isModelChanged or animStateInt == 0 then
self:_PlayModelEffect(desSlotIndex, phaseCharItem.charId)
if Time.realtimeSinceStartup - self.m_lastPostGlitchEventTime > AUDIO_EVENT_CHAR_GLITCH_INTERVAL then
self.m_lastPostGlitchEventTime = Time.realtimeSinceStartup
if self.m_updateModelsCounter > 1 then
AudioAdapter.PostEvent(AUDIO_EVENT_CHAR_GLITCH)
end
end
end
end
PhaseCharFormation._StopModelEffect = HL.Method(HL.Number) << function(self, index)
local effect = self.m_sceneObject.view["charEffect" .. string.format("%d", index)]
effect.gameObject:SetActive(false)
effect:Stop()
end
PhaseCharFormation._PlayModelEffect = HL.Method(HL.Number, HL.Any) << function(self, index, charId)
local effectParent
local parent
local height
if index <= 0 or string.isEmpty(charId) or not self.m_sceneObject then
return
end
local charDisplayData = CharInfoUtils.getCharDisplayData(charId)
if charDisplayData then
height = LuaIndex(charDisplayData.height:ToInt())
end
if self.m_charFormation and self.m_charFormation.uiCtrl.state == UIConst.UI_CHAR_FORMATION_STATE.SingleChar then
effectParent = self.m_sceneObject.view[string.format("effectSingle%d", index)]
else
effectParent = self.m_sceneObject.view[string.format("effectList%d", index)]
end
effectParent.gameObject:SetActive(true)
parent = effectParent[string.format("effect%d", height)]
local effect = self.m_sceneObject.view["charEffect" .. string.format("%d", index)]
effect.transform:SetParent(parent)
effect.transform.localPosition = Vector3.zero
effect.transform.localEulerAngles = Vector3.zero
effect.transform.localScale = Vector3.one
effect.gameObject:SetActive(true)
effect:Play()
end
PhaseCharFormation._DoRefreshAllModels = HL.Method(HL.Table) << function(self, models)
local curInUse = {}
for slotIndex, phaseCharItem in pairs(self.m_charModelInUse) do
local charInstId = phaseCharItem.charInstId
curInUse[charInstId] = {
phaseCharItem = phaseCharItem,
slotIndex = slotIndex,
}
end
self.m_charModelInUse = {}
for slotIndex, charInfo in pairs(models) do
local instId = charInfo.charInstId
local cacheData = curInUse[instId]
if cacheData then
self:_MoveCharModel2Index(cacheData, slotIndex)
curInUse[instId] = nil
self.m_charModelInUse[slotIndex] = cacheData.phaseCharItem
self:_SetPreCharInfo(slotIndex, charInfo)
else
local animStateInt = slotIndex
if self.m_singleCharIndex > 0 and self.m_singleCharIndex == slotIndex then
animStateInt = 0
end
self:_TryGetCharModel(charInfo, slotIndex, function(phaseItem)
if not phaseItem then
self.m_charModelInUse[slotIndex] = nil
return
end
self.m_charModelInUse[slotIndex] = phaseItem
self:_RefreshPhaseCharItem(phaseItem, animStateInt, slotIndex)
self:_SetPreCharInfo(slotIndex, charInfo)
end)
end
end
for charInstId, cacheData in pairs(curInUse) do
self:_TryCacheCharModel(cacheData)
if cacheData then
self:_ClearPreCharInfo(charInstId)
end
end
local lightEnableTemplateId
if self.m_singleCharIndex > 0 and models[self.m_singleCharIndex] then
lightEnableTemplateId = models[self.m_singleCharIndex].charId
local light = self:_TryGetLight(lightEnableTemplateId, self.m_singleCharIndex)
if light ~= nil then
light.gameObject:SetActive(true)
light:TweenLightGroupAlpha(0, 1, 1)
end
self.m_sceneObject.view.lightTeam.gameObject:SetActive(false)
local volume = self:_TryGetVolume(lightEnableTemplateId, self.m_singleCharIndex)
if volume ~= nil then
self.m_sceneObject.view.charOverrideVolume.gameObject:SetActive(true)
local tween = volume:GetMainLightBiasTween(self.m_sceneObject.view.charOverrideVolume, volume.tweenDuration)
if self.m_charVolumeTween then
self.m_charVolumeTween:Kill()
end
self.m_charVolumeTween = tween
tween:Play()
end
else
self.m_sceneObject.view.lightTeam.gameObject:SetActive(true)
self.m_sceneObject.view.charOverrideVolume.gameObject:SetActive(false)
end
for templateId, lightGroup in pairs(self.m_templateId2LightGroup) do
local light = PhaseCharFormation._GetLight(lightGroup)
if lightEnableTemplateId then
if lightEnableTemplateId ~= templateId then
if light.gameObject.activeSelf then
light:TweenLightGroupAlpha(1, 0, 1)
else
light.gameObject:SetActive(false)
end
end
else
light.gameObject:SetActive(false)
end
end
end
PhaseCharFormation._GetLight = HL.StaticMethod(HL.Forward("PhaseGameObjectItem")).Return(HL.Any) << function(lightGroup)
local light
if lightGroup then
local lightName = string.format("light_%s", UIConst.PHASE_CHAR_ITEM_CAMERA_POSTFIX_DICT.OVERVIEW)
light = lightGroup.view[lightName]
end
return light
end
PhaseCharFormation._GetSingleCamera = HL.StaticMethod(HL.Any).Return(HL.Any) << function(cameraGroup)
local camera
if cameraGroup then
local cameraName = string.format("vcam_%s", UIConst.PHASE_CHAR_ITEM_CAMERA_POSTFIX_DICT.FORMATION)
camera = cameraGroup[cameraName]
end
return camera
end
PhaseCharFormation._GetVolume = HL.StaticMethod(HL.Any).Return(HL.Any) << function(volumeGroup)
local volume
if volumeGroup then
local volumeName = string.format("volume_%s", UIConst.PHASE_CHAR_ITEM_CAMERA_POSTFIX_DICT.OVERVIEW)
volume = volumeGroup[volumeName]
end
return volume
end
PhaseCharFormation._TryGetLightGroup = HL.Method(HL.String).Return(HL.Forward("PhaseGameObjectItem")) << function(self, templateId)
local charDisplayData = CharInfoUtils.getCharDisplayData(templateId)
local lightGroup = self.m_templateId2LightGroup[templateId]
if not lightGroup and not string.isEmpty(charDisplayData.charInfoLightGroup) then
local success, result = xpcall(self.CreatePhaseGOItem, debug.traceback, self, charDisplayData.charInfoLightGroup, nil, nil, "CharInfo")
if success then
lightGroup = result
lightGroup.go:SetAllChildrenActiveIfNecessary(false)
end
self.m_templateId2LightGroup[templateId] = lightGroup
end
return lightGroup
end
PhaseCharFormation._TryGetTrackGroup = HL.Method(HL.String).Return(HL.Forward("PhaseGameObjectItem")) << function(self, templateId)
local charDisplayData = CharInfoUtils.getCharDisplayData(templateId)
local trackGroup = self.m_templateId2TrackGroup[templateId]
if not trackGroup and not string.isEmpty(charDisplayData.charInfoCameraGroup) then
local success, result = xpcall(self.CreatePhaseGOItem, debug.traceback, self, charDisplayData.charInfoCameraGroup, nil, nil, "CharInfo")
if success then
trackGroup = result
if UNITY_EDITOR then
local cinemachineWaypointGroup = trackGroup.go:AddComponent(typeof(CS.Beyond.DevTools.CinemachineWaypointGroup))
if cinemachineWaypointGroup then
cinemachineWaypointGroup:SyncWaypointChange()
end
end
local extraCams = trackGroup.view.extraCams
extraCams.extra_cam_equip_second.gameObject:SetActive(false)
extraCams.extra_cam_weapon_second.gameObject:SetActive(false)
end
self.m_templateId2TrackGroup[templateId] = trackGroup
end
return trackGroup
end
PhaseCharFormation._TryGetCameraGroup = HL.Method(HL.String).Return(HL.Any) << function(self, templateId)
local cameraGroup = self.m_templateId2CameraGroup[templateId]
if not cameraGroup then
local trackGroup = self:_TryGetTrackGroup(templateId)
if trackGroup then
cameraGroup = trackGroup.view.cameraGroup
cameraGroup.gameObject:SetAllChildrenActiveIfNecessary(false)
self.m_templateId2CameraGroup[templateId] = cameraGroup
end
end
return cameraGroup
end
PhaseCharFormation._TryGetVolumeGroup = HL.Method(HL.String).Return(HL.Any) << function(self, templateId)
local volumeGroup = self.m_templateId2VolumeGroup[templateId]
if not volumeGroup then
local trackGroup = self:_TryGetTrackGroup(templateId)
if trackGroup then
volumeGroup = trackGroup.view.volumeModifiers
self.m_templateId2VolumeGroup[templateId] = volumeGroup
end
end
return volumeGroup
end
PhaseCharFormation._MoveGoToCharContainer = HL.Method(HL.Userdata, HL.Number) << function(self, go, slotIndex)
local parent = self.m_sceneObject.view[string.format("charContainer%d", slotIndex)]
go.transform:SetParent(parent.transform)
go.transform.localPosition = Vector3.zero
go.transform.localEulerAngles = Vector3.zero
end
PhaseCharFormation._TryGetLight = HL.Method(HL.String, HL.Number).Return(HL.Any) << function(self, templateId, slotIndex)
local lightGroup = self:_TryGetLightGroup(templateId)
if lightGroup ~= nil then
lightGroup:SetActive(true)
self:_MoveGoToCharContainer(lightGroup.go, slotIndex or 1)
end
local light = PhaseCharFormation._GetLight(lightGroup)
return light
end
PhaseCharFormation._TryGetSingleCamera = HL.Method(HL.String, HL.Number).Return(HL.Any) << function(self, templateId, slotIndex)
local cameraGroup = self:_TryGetCameraGroup(templateId)
if cameraGroup ~= nil then
cameraGroup.gameObject:SetActive(true)
self:_MoveGoToCharContainer(self:_TryGetTrackGroup(templateId).go, slotIndex or 1)
end
local camera = PhaseCharFormation._GetSingleCamera(cameraGroup)
return camera
end
PhaseCharFormation._TryGetVolume = HL.Method(HL.String, HL.Number).Return(HL.Any) << function(self, templateId, slotIndex)
local volumeGroup = self:_TryGetVolumeGroup(templateId)
if volumeGroup ~= nil then
volumeGroup.gameObject:SetActive(true)
self:_MoveGoToCharContainer(self:_TryGetTrackGroup(templateId).go, slotIndex or 1)
end
local volume = PhaseCharFormation._GetVolume(volumeGroup)
return volume
end
PhaseCharFormation._TryGetCharModel = HL.Method(HL.Table, HL.Opt(HL.Number, HL.Function)) << function(self,
data,
slotIndex,
callback)
local charInstId = data.charInstId
local cacheData = self.m_charModelCache[charInstId]
if cacheData then
self.m_charModelCache[charInstId] = nil
self.m_cacheNum = self.m_cacheNum - 1
local phaseItem = cacheData.phaseCharItem
self:_MoveCharModel2Index(cacheData, slotIndex)
if callback then
callback(phaseItem)
end
else
self.m_charModelInUse[slotIndex] = MODEL_LOADING_TAG
self:_SetPreCharInfo(slotIndex, nil)
local index = slotIndex or 1
local go = self.m_sceneObject.view[string.format("charContainer%d", index)]
self:CreatePhaseCharItem(data, go, function(phaseItem)
if not phaseItem then
callback(nil)
return
end
PhaseCharFormation._UpdateModelName(phaseItem, -1, index)
local lightGroup = self:_TryGetLightGroup(data.charId)
if lightGroup then
phaseItem.uiModelMono:InitLightFollower(lightGroup.go.transform)
end
local lookAtIk = phaseItem.go:GetComponent("LookAtIK")
if lookAtIk then
lookAtIk.solver:SetLookAtWeight(0)
end
callback(phaseItem)
end)
end
end
PhaseCharFormation._UpdateModelName = HL.StaticMethod(HL.Forward("PhaseCharItem"), HL.Number, HL.Number) << function(phaseCharItem, srcIndex, dstIndex)
local srcName = phaseCharItem:GetName()
local dstName
if not srcIndex or srcIndex <= 0 then
dstName = srcName .. string.format("_slot%d", dstIndex)
else
local srcSlot = string.format("_slot%d", srcIndex)
local dstSlot = string.format("_slot%d", dstIndex)
dstName = string.gsub(srcName, srcSlot, dstSlot)
end
phaseCharItem:SetName(dstName)
end
PhaseCharFormation._TryCacheCharModel = HL.Method(HL.Table) << function(self, cacheData)
if cacheData then
local phaseCharItem = cacheData.phaseCharItem
local charId = phaseCharItem.charId
if self.m_charModelCache[cacheData.phaseCharItem.charInstId] then
logger.error("PhaseCharFormation._CacheCharModel Error: "
.. charId .. ", already in m_charModelCache!!!")
else
self:_DoCacheCharModel(cacheData)
end
end
end
PhaseCharFormation._DoCacheCharModel = HL.Method(HL.Table) << function(self, cacheData)
local phaseCharItem = cacheData.phaseCharItem
if self.m_cacheNum >= MODEL_CACHE_TOTAL_NUM then
self:RemovePhaseCharItemByInstId(phaseCharItem.charInstId)
return
end
phaseCharItem:SetVisible(false)
phaseCharItem:SwitchWeaponState(CS.Beyond.Gameplay.View.CharUIModelMono.WeaponState.HIDE)
self.m_charModelCache[phaseCharItem.charInstId] = cacheData
self.m_cacheNum = self.m_cacheNum + 1
end
PhaseCharFormation._GetCharTeamIndex = HL.Method(HL.Int, HL.Table).Return(HL.Number) << function(self, charInstId,
charList)
for i = 1, #charList do
local charInfo = charList[i]
if charInfo and charInstId == charInfo.charInstId then
return i
end
end
return -1
end
PhaseCharFormation._SquadToTeamInfo = HL.Method(HL.Userdata).Return(HL.Table) << function(self, squad)
local teamInfo = {}
teamInfo.slots = {}
if squad ~= nil then
for i = 0, squad.memberList.Count - 1 do
local charInstId = squad.memberList[i]
if charInstId > 0 then
local templateId = CharInfoUtils.getPlayerCharInfoByInstId(charInstId).templateId
table.insert(teamInfo.slots, {
charInstId = charInstId,
charId = templateId
})
end
end
teamInfo.leaderIndex = LuaIndex(squad.leaderIndex)
end
return teamInfo
end
PhaseCharFormation._LockedTeamDataToTeamInfo = HL.Method(HL.Table).Return(HL.Table) << function(self, lockedTeamData)
local teamInfo = {}
teamInfo.slots = {}
teamInfo.leaderIndex = 1
if lockedTeamData then
for _, char in ipairs(lockedTeamData.chars) do
local charInfo = {
charInstId = char.charInstId,
charId = char.charId,
isLocked = char.isLocked,
isTrail = char.isTrail,
isReplaceable = char.isReplaceable,
}
table.insert(teamInfo.slots, charInfo)
end
end
return teamInfo
end
PhaseCharFormation._GetCharModelPos = HL.Method().Return(HL.Table) << function(self)
local table = {}
for i = 1, Const.BATTLE_SQUAD_MAX_CHAR_NUM do
local go = self.m_sceneObject.view["charContainer" .. tostring(i)]
local pos = go.position
local uiPos, _ = UIUtils.objectPosToUI(pos, self.m_charFormation.uiCtrl.uiCamera)
table[i] = uiPos
end
return table
end
PhaseCharFormation._GetMaxCharTeamMemberCount = HL.Method().Return(HL.Number, HL.String) << function(self)
if self.m_lockedTeamData then
return self.m_lockedTeamData.maxTeamMemberCount, Language.LUA_CHAR_TEAM_MEMBER_COUNT_MAX
else
return GameInstance.player.charBag.maxCharTeamMemberCount, Language.LUA_CHAR_TEAM_MEMBER_COUNT_LOCKED
end
end
PhaseCharFormation._RefreshTeamChars = HL.Method() << function(self)
local teamInfo
if self.m_lockedTeamData then
teamInfo = self:_LockedTeamDataToTeamInfo(self.m_lockedTeamData)
else
local teamIndex = CSIndex(self.m_curTeamIndex)
local squad = GameInstance.player.charBag:GetMainTeam(teamIndex)
teamInfo = self:_SquadToTeamInfo(squad)
end
if self.m_charFormation then
self.m_charFormation.uiCtrl:RefreshTeamCharInfo(teamInfo)
end
self:UpdateCharList(teamInfo.slots)
end
PhaseCharFormation._SetPreCharInfo = HL.Method(HL.Number, HL.Table) << function(self, slotIndex, charInfo)
if self.m_charFormation and self.m_charFormation.uiCtrl.state ~= UIConst.UI_CHAR_FORMATION_STATE.SingleChar then
if not self.m_preCharInfoList then
self.m_preCharInfoList = {}
end
if charInfo then
self:_ClearPreCharInfo(charInfo.charInstId)
end
self.m_preCharInfoList[slotIndex] = charInfo
end
end
PhaseCharFormation._ClearPreCharInfo = HL.Method(HL.Number) << function(self, charInstId)
if not self.m_preCharInfoList or self.m_charFormation.uiCtrl.state == UIConst.UI_CHAR_FORMATION_STATE.SingleChar then
return
end
for index, charInfo in pairs(self.m_preCharInfoList) do
if charInfo and charInfo.charInstId == charInstId then
self.m_preCharInfoList[index] = nil
end
end
end
PhaseCharFormation._BackToTeamSet = HL.Method(HL.Opt(HL.Boolean)) << function(self, setSquad)
self.m_teamSkillCache = {}
self.m_singleCharIndex = 0
if self.m_curTeamIndex == LuaIndex(GameInstance.player.charBag.curTeamIndex) then
self.m_charFormation.uiCtrl:SetState(UIConst.UI_CHAR_FORMATION_STATE.TeamHasSet)
else
self.m_charFormation.uiCtrl:SetState(UIConst.UI_CHAR_FORMATION_STATE.TeamWaitSet)
end
self:RefreshSlotVisible(-1, true)
self.m_charFormation.uiCtrl:SetSingleCharIndex(0)
self.m_charFormation.uiCtrl:CloseCharList()
local cameraData = {
cameraIndex = CameraIndex.Team,
}
self:_RefreshCamera(cameraData)
if not setSquad then
self:_RefreshTeamChars()
else
local charInfoList = {}
if self.m_tmpTeam then
for _, charItem in pairs(self.m_tmpTeam) do
local info = {
charId = charItem.templateId,
charInstId = charItem.instId,
}
table.insert(charInfoList, info)
end
end
self:_TryUpdateModels(charInfoList)
end
self:_HideSkillTip()
self:_RefreshEmpty(false)
self.m_tmpTeam = nil
self:_Refresh3DUIVisible(true)
self:_RefreshControllerSlotSelectedState(self.m_navigatedCharIndex, true)
end
PhaseCharFormation._HideSkillTip = HL.Method() << function(self)
if self.m_skillTip then
self.m_skillTip.uiCtrl:Hide()
end
end
local CameraNames = {
[CameraIndex.Team] = "teamCamera",
[CameraIndex.TeamEx] = "teamExtraCamera",
[CameraIndex.Single] = "singleCamera",
[CameraIndex.Multi] = "multiCamera",
}
PhaseCharFormation.RefreshCameraController = HL.Method(HL.Number) << function(self, index)
local cameraController = self.m_sceneObject.view.cameraController
for camIndex, cameraName in pairs(CameraNames) do
local camera = cameraController[cameraName]
if camera == nil then
logger.error("PhaseFormation {0} camera is nil ", cameraName)
else
camera.gameObject:SetActive(camIndex == index)
end
end
if self.m_overrideSingleCamera then
self.m_overrideSingleCamera.gameObject:SetActive(index == CameraIndex.OverrideSingle)
end
end
PhaseCharFormation._RefreshCamera = HL.Method(HL.Table) << function(self, cameraData)
local cameraIndex = cameraData.cameraIndex
local charInfo = cameraData.charInfo
local index = cameraData.singleIndex
local virtualCamera
if self.m_overrideSingleCamera then
self.m_overrideSingleCamera.gameObject:SetActive(false)
end
if cameraIndex == CameraIndex.Team then
if self:_CheckCameraEx() then
cameraIndex = CameraIndex.TeamEx
end
elseif cameraIndex == CameraIndex.Single then
local overrideSingleCamera = charInfo and self:_TryGetSingleCamera(charInfo.charId, index)
if overrideSingleCamera then
self.m_overrideSingleCamera = overrideSingleCamera
cameraIndex = CameraIndex.OverrideSingle
else
local cameras = self.m_sceneObject.view["singleCameras" .. string.format("%d", index)]
if charInfo then
local charId = charInfo.charId
local charDisplayData = CharInfoUtils.getCharDisplayData(charId)
if charDisplayData then
local overridePath = charDisplayData.cameraConfig.charFormationOverride
if string.isEmpty(overridePath) then
virtualCamera = cameras["camera" .. string.format("%d", LuaIndex(charDisplayData.height:ToInt()))]
else
virtualCamera = self:_GetOverrideCamera(overridePath, cameras.transform)
end
else
logger.error("PhaseCharFormation._RefreshCamera getCharDisplayData nil: " .. charId .. "!!!")
end
else
virtualCamera = cameras["camera" .. string.format("%d", 1)]
end
end
end
if virtualCamera then
local singleCamera = self.m_sceneObject.view.cameraController[CameraNames[CameraIndex.Single]]
local transform = virtualCamera.transform
local fov = virtualCamera.m_Lens.FieldOfView
singleCamera:SetFieldOfView(fov)
singleCamera.transform.position = transform.position
singleCamera.transform.rotation = transform.rotation
end
self:RefreshCameraController(cameraIndex)
end
PhaseCharFormation._GetOverrideCamera = HL.Method(HL.String, Transform).Return(HL.Userdata) << function(self, name,
parent)
local path = OVERRIDE_CAMERA_PATH .. name
local phaseItem = self:_GetGOPhaseItem(path)
if not phaseItem then
phaseItem = self:CreatePhaseGOItem(path)
phaseItem.go:SetActive(false)
end
phaseItem.go.transform:SetParent(parent)
return phaseItem.go:GetComponent("CinemachineVirtualCamera")
end
PhaseCharFormation._CheckCameraEx = HL.Method().Return(HL.Boolean) << function(self)
local check = false
if self.m_curTeam[1] then
local charId = self.m_curTeam[1].charId
local charDisplayData = CharInfoUtils.getCharDisplayData(charId)
if charDisplayData and charDisplayData.height == Const.CharHeightEnum.Male then
check = true
end
end
return check
end
PhaseCharFormation._OnSquadChange = HL.Method(HL.Table) << function(self, args)
local teamIndex = unpack(args)
local teamIndex = LuaIndex(teamIndex)
if self.m_curTeamIndex == teamIndex then
if self.m_charFormation then
local squad = GameInstance.player.charBag:GetMainTeam(CSIndex(teamIndex))
local teamInfo = self:_SquadToTeamInfo(squad)
self.m_charFormation.uiCtrl:RefreshTeamCharInfo(teamInfo)
end
self:_RefreshTeamChars()
end
end
PhaseCharFormation.OnSlotLockChanged = HL.Method(HL.Table) << function(self, arg)
end
PhaseCharFormation._OnCharTeamNormalSkillChange = HL.Method(HL.Table) << function(self, arg)
local csTeamIndex, charInstId, normalSkillId = unpack(arg)
local teamIndex = LuaIndex(csTeamIndex)
if self.m_curTeamIndex == teamIndex then
local templateId = CharInfoUtils.getPlayerCharInfoByInstId(charInstId).templateId
local slotIndex = CharInfoUtils.checkCharInTeam(charInstId, teamIndex)
if slotIndex > 0 then
local slot = self.m_sceneObject.view["slot" .. string.format("%d", slotIndex)]
self:_SetSlotCharInfo(slot, {
charInstId = charInstId,
charId = templateId,
})
end
end
end
PhaseCharFormation.OnPutOnWeapon = HL.Method(HL.Table) << function(self, arg)
local charInstId, weaponInstId, lastWeaponInstId = unpack(arg)
local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId)
if charInfo then
local phaseCharItem = self:_GetCharPhaseItem(charInstId)
if phaseCharItem then
phaseCharItem:ReloadWeapon()
end
end
local weaponInstData = CharInfoUtils.getWeaponInstInfo(lastWeaponInstId)
local weaponInst = weaponInstData.weaponInst
local equippedCharServerId = weaponInst.equippedCharServerId
charInfo = CharInfoUtils.getPlayerCharInfoByInstId(equippedCharServerId)
if charInfo then
local phaseCharItem = self:_GetCharPhaseItem(equippedCharServerId)
if phaseCharItem then
phaseCharItem:ReloadWeapon()
end
end
end
PhaseCharFormation.OnGemChanged = HL.Method(HL.Table) << function(self, arg)
local weaponInstId, _ = unpack(arg)
local weaponInstData = CharInfoUtils.getWeaponInstInfo(weaponInstId)
local weaponInst = weaponInstData.weaponInst
local equippedCharServerId = weaponInst.equippedCharServerId
local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(equippedCharServerId)
if charInfo then
local phaseCharItem = self:_GetCharPhaseItem(equippedCharServerId)
if phaseCharItem then
phaseCharItem:ReloadWeaponDecoEffect(weaponInstId)
end
end
end
PhaseCharFormation.OnCharPotentialUnlock = HL.Method(HL.Table) << function(self, args)
local charInstId, level = unpack(args)
local charPhaseItem = self:_GetCharPhaseItem(charInstId)
local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId)
if charPhaseItem and charInfo and charInfo.potentialLevel >= UIConst.CHAR_MAX_POTENTIAL then
charPhaseItem:LoadPotentialEffects()
end
end
PhaseCharFormation._OnSquadNameChange = HL.Method(HL.Table) << function(self, arg)
local teamIndex, teamName = unpack(arg)
if self.m_curTeamIndex == LuaIndex(teamIndex) and self.m_charFormation then
self.m_charFormation.uiCtrl:RefreshTeamName(teamName)
end
Notify(MessageConst.HIDE_POP_UP)
end
PhaseCharFormation._TrySendSetSquad = HL.Method().Return(HL.Boolean, HL.Number) << function(self)
if self.m_lockedTeamData then
self:_StartCoroutine(function()
coroutine.step()
local chars = self.m_curTeam
if self.m_tempMultiSelectCharInfoList then
chars = self.m_tempMultiSelectCharInfoList
self.m_tempMultiSelectCharInfoList = nil
end
self.m_lockedTeamData.chars = lume.deepCopy(chars)
self:_RefreshTeamChars()
end)
return true, 0
end
local charInstIds = {}
local aliveCharInstIds = {}
local normalSkillIds = {}
if self.m_tmpTeam then
for _, charItem in pairs(self.m_tmpTeam) do
local charInstId = charItem.instId
local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId)
local normalSkillId = charInfo.normalSkillId
if not charInfo.isDead then
table.insert(aliveCharInstIds, charInstId)
end
local cacheNormalSkillId = self.m_teamSkillCache[charInstId]
if cacheNormalSkillId then
table.insert(normalSkillIds, cacheNormalSkillId)
else
table.insert(normalSkillIds, normalSkillId)
end
table.insert(charInstIds, charInstId)
end
else
for _, charData in pairs(self.m_curTeam) do
local charInstId = charData.charInstId
local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId)
local isDead = charInfo.isDead
local normalSkillId = charInfo.normalSkillId
if not isDead then
table.insert(aliveCharInstIds, charInstId)
end
local cacheNormalSkillId = self.m_teamSkillCache[charInstId]
if cacheNormalSkillId then
table.insert(normalSkillIds, cacheNormalSkillId)
else
table.insert(normalSkillIds, normalSkillId)
end
table.insert(charInstIds, charInstId)
end
end
if #aliveCharInstIds == 0 then
local toast
if self.m_curTeamIndex == LuaIndex(GameInstance.player.charBag.curTeamIndex) then
toast = Language.LUA_CAN_NOT_SET_CUR_SQUAD_NO_CHAR
else
toast = Language.LUA_CAN_NOT_SET_SQUAD_ALL_DEAD
end
Notify(MessageConst.SHOW_TOAST, toast)
return false, 0
else
GameInstance.player.charBag:SetTeamWithSkill(CSIndex(self.m_curTeamIndex), charInstIds, normalSkillIds)
return true, aliveCharInstIds[1]
end
end
PhaseCharFormation._CheckTeamCanFight = HL.Method().Return(HL.Boolean, HL.Any) << function(self)
local toast
if #self.m_curTeam == 0 then
toast = Language.LUA_CAN_NOT_SET_CUR_SQUAD_NO_CHAR
return false, toast
end
local hasAlive = false
toast = Language.LUA_CAN_NOT_SET_CUR_SQUAD_ALL_DEAD
for _, info in pairs(self.m_curTeam) do
local charInstId = info.charInstId
local charInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId)
if not charInfo.isDead then
hasAlive = true
toast = nil
break
end
end
return hasAlive, toast
end
PhaseCharFormation._SendChangeActiveSquad = HL.Method(HL.Opt(HL.Boolean)) << function(self, ignoreCheck)
if not ignoreCheck then
local res, toast = self:_CheckTeamCanFight()
if not res then
Notify(MessageConst.SHOW_TOAST, toast)
return
end
end
GameInstance.player.charBag:SendSetActiveTeam(CSIndex(self.m_curTeamIndex))
end
PhaseCharFormation.SetMemberAndActiveTeam = HL.Method() << function(self)
local res, firstAliveInstId = self:_TrySendSetSquad()
if res then
self:_PlayCharListVoice()
self:_BackToTeamSet(true)
GameInstance.player.charBag:SendSetActiveTeam(CSIndex(self.m_curTeamIndex), firstAliveInstId)
end
end
PhaseCharFormation._InitSlots = HL.Method() << function(self)
for index = 1, Const.BATTLE_SQUAD_MAX_CHAR_NUM do
local slot = self.m_sceneObject.view["slot" .. string.format("%d", index)]
slot.canvas.worldCamera = CameraManager.mainCamera
slot.btnSet.clickHintTextId = VIRTUAL_MOUSE_HINT_KEY
slot.btnAdd.clickHintTextId = VIRTUAL_MOUSE_HINT_KEY
slot.btnSet.onClick:RemoveAllListeners()
slot.btnSet.onClick:AddListener(function()
self:_OnSingleCharClicked(index)
end)
slot.btnAdd.onClick:RemoveAllListeners()
slot.btnAdd.onClick:AddListener(function()
self:_OnSingleCharClicked(index)
end)
slot.gameObject:SetActive(true)
end
end
PhaseCharFormation._ClearUIComp = HL.Method() << function(self)
for index = 1, Const.BATTLE_SQUAD_MAX_CHAR_NUM do
local slot = self.m_sceneObject.view["slot" .. string.format("%d", index)]
CSUtils.ClearUIComponents(slot.gameObject)
end
end
PhaseCharFormation._Refresh3DUIVisible = HL.Method(HL.Boolean) << function(self, allVisible)
if self.m_charFormation and self.m_charFormation.uiCtrl.state == UIConst.UI_CHAR_FORMATION_STATE.SingleChar then
allVisible = false
end
local maxCharTeamMemberCount = self:_GetMaxCharTeamMemberCount()
for index = 1, Const.BATTLE_SQUAD_MAX_CHAR_NUM do
local slot = self.m_sceneObject.view["slot" .. string.format("%d", index)]
local root = slot.root
local slotEmpty = slot.slotEmpty
if not allVisible then
if index > maxCharTeamMemberCount then
slot.slotEmpty.gameObject:SetActive(false)
slot.btnSet.gameObject:SetActive(true)
slot.slotChar.gameObject:SetActive(false)
slot.slotLock.gameObject:SetActive(true)
elseif slotEmpty.gameObject.activeSelf then
slot.slotEmpty:PlayOutAnimation(function()
root.gameObject:SetActive(allVisible)
end)
else
root.gameObject:SetActive(allVisible)
end
else
root.gameObject:SetActive(allVisible)
end
end
if self.m_lockedTeamData then
self.m_sceneObject.view.formationDeco.gameObject:SetActive(false)
else
if not allVisible and self.m_sceneObject.view.formationDeco.gameObject.activeSelf then
self.m_sceneObject.view.formationDeco.animationWrapper:PlayOutAnimation(function()
self.m_sceneObject.view.formationDeco.gameObject:SetActive(allVisible)
end)
else
self.m_sceneObject.view.formationDeco.gameObject:SetActive(allVisible)
end
end
end
PhaseCharFormation._OnSingleCharClicked = HL.Method(HL.Number) << function(self, index)
local maxCharTeamMemberCount, toast = self:_GetMaxCharTeamMemberCount()
if index > maxCharTeamMemberCount then
Notify(MessageConst.SHOW_TOAST, toast)
return
end
local state = self.m_charFormation.uiCtrl.state
if state ~= UIConst.UI_CHAR_FORMATION_STATE.CharChange and state ~= UIConst.UI_CHAR_FORMATION_STATE.SingleChar then
self:OnEnterSingleChar(index)
end
end
PhaseCharFormation.RefreshSlotVisible = HL.Method(HL.Number, HL.Opt(HL.Boolean)) << function(self, index, allVisible)
for i = 1, Const.BATTLE_SQUAD_MAX_CHAR_NUM do
local slot = self.m_sceneObject.view["slot" .. string.format("%d", i)]
local root = slot.root
local slotEmpty = slot.slotEmpty
if not allVisible then
if slotEmpty.gameObject.activeSelf then
slot.slotEmpty:PlayOutAnimation(function()
root.gameObject:SetActive(allVisible)
end)
else
root.gameObject:SetActive(allVisible)
end
else
root.gameObject:SetActive(allVisible)
end
slot.slotCharDisable.gameObject:SetActive(false)
end
end
PhaseCharFormation._SetActiveCharMark = HL.Method(HL.Number, HL.Boolean) << function(self, index, active)
local charMark = self.m_sceneObject.view[string.format("charMark%d", index)]
charMark.decoCross.gameObject:SetActive(active)
end
PhaseCharFormation._RefreshSlot = HL.Method(HL.Table, HL.Number, HL.Table) << function(self, slot, index, charInfo)
local maxCharTeamMemberCount = self:_GetMaxCharTeamMemberCount()
if self.m_lockedTeamData then
maxCharTeamMemberCount = self.m_lockedTeamData.maxTeamMemberCount
end
if slot then
slot.isLocked = index > maxCharTeamMemberCount
if slot.isLocked then
slot.slotLock.gameObject:SetActive(true)
slot.slotEmpty.gameObject:SetActive(false)
slot.slotChar.gameObject:SetActive(false)
slot.slotCharDisable.gameObject:SetActive(false)
slot.slotCharDisableFx.gameObject:SetActive(false)
slot.btnSet.gameObject:SetActive(true)
return
end
local hasChar = charInfo and charInfo.charId ~= ""
local isDead = false
if hasChar then
local csCharInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInfo.charInstId)
isDead = csCharInfo.isDead
end
if hasChar then
self:_SetSlotCharInfo(slot, charInfo)
end
if slot.empty == nil then
slot.empty = slot.slotEmpty.gameObject.activeSelf
end
if slot.empty and hasChar then
slot.slotEmpty:PlayOutAnimation(function()
slot.slotEmpty.gameObject:SetActive(false)
end)
slot.btnSet.gameObject:SetActive(true)
elseif not slot.empty and not hasChar then
slot.slotEmpty.gameObject:SetActive(true)
slot.slotEmpty:PlayInAnimation()
slot.btnSet.gameObject:SetActive(false)
end
slot.empty = not hasChar
slot.slotChar.gameObject:SetActive(hasChar)
slot.slotCharDisable.gameObject:SetActive(isDead)
slot.slotCharDisableFx.gameObject:SetActive(isDead)
slot.slotLock.gameObject:SetActive(false)
end
end
PhaseCharFormation._SetSlotCharInfo = HL.Method(HL.Table, HL.Table) << function(self, slot, info)
local characterTable = Tables.characterTable
local templateId = info.charId
local data = characterTable:GetValue(templateId)
local instId = info.charInstId
local charInfo = nil
if instId and instId > 0 then
charInfo = CharInfoUtils.getPlayerCharInfoByInstId(instId)
end
if charInfo then
slot.textLv.text = string.format("%02d", charInfo.level)
end
slot.textName.text = data.name
slot.charElementIcon:InitCharTypeIcon(data.charTypeId)
local proSpriteName = CharInfoUtils.getCharProfessionIconName(data.profession, true)
slot.imagePro:LoadSprite(UIConst.UI_SPRITE_CHAR_PROFESSION, proSpriteName)
local dungeonId = self.arg.dungeonId
local tacticalItemArgs = {
itemId = charInfo.tacticalItemId,
isLocked = info.isTrail,
isForbidden = (not string.isEmpty(dungeonId) and
UIUtils.isItemTypeForbidden(dungeonId, GEnums.ItemType.TacticalItem)) or self.arg.weekRaidArg ~= nil,
isClickable = false,
charTemplateId = templateId,
charInstId = instId,
}
slot.charFormationTacticalItem:InitCharFormationTacticalItem(tacticalItemArgs)
local isFixed, isTrail = CharInfoUtils.getLockedFormationCharTipsShow(info)
slot.fixedTips.gameObject:SetActive(isFixed)
slot.tryoutTips.gameObject:SetActive(isTrail)
if slot.charId ~= templateId and not string.isEmpty(templateId) then
slot.slotChar:PlayInAnimation()
end
slot.charId = templateId
end
PhaseCharFormation.GetCurNaviSlot = HL.Method().Return(HL.Table) << function(self)
return self.m_sceneObject.view["slot" .. string.format("%d", self.m_navigatedCharIndex)]
end
PhaseCharFormation.OnRefreshSlot = HL.Method(HL.Table) << function(self, args)
local arg1, arg2 = unpack(args)
local slotIndex = arg1
local charInfo = arg2
local slot = self.m_sceneObject.view["slot" .. string.format("%d", slotIndex)]
self:_RefreshSlot(slot, slotIndex, charInfo)
self:_SetActiveCharMark(slotIndex, charInfo == nil)
end
PhaseCharFormation._PlayTeamVoice = HL.Method() << function(self)
if not self.m_curTeam or self.m_charFormation.uiCtrl.state == UIConst.UI_CHAR_FORMATION_STATE.SingleChar then
return
end
local memberCount = #self.m_curTeam
local index = math.random(1, memberCount)
local charId = self.m_curTeam[index].charId
Utils.triggerVoice("chrbark_squad", charId)
end
PhaseCharFormation._PlaySingleCharVoice = HL.Method() << function(self)
local squad = GameInstance.player.charBag:GetCurrentMainTeam()
local serverTeam = self:_SquadToTeamInfo(squad).slots
local maxCharTeamMemberCount = self:_GetMaxCharTeamMemberCount()
local changedChars = {}
for i = 1, maxCharTeamMemberCount do
if i > #serverTeam and self.m_curTeam[i] ~= nil then
table.insert(changedChars, self.m_curTeam[i].charId)
end
if i <= #serverTeam and self.m_curTeam[i] ~= nil and
serverTeam[i].charId ~= self.m_curTeam[i].charId then
table.insert(changedChars, self.m_curTeam[i].charId)
end
end
if #changedChars > 0 then
local randomIndex = math.random(1, #changedChars)
Utils.triggerVoice("chrbark_join", changedChars[randomIndex])
end
end
PhaseCharFormation._PlayCharListVoice = HL.Method() << function(self)
local curTeam = {}
if self.m_tmpTeam then
for _, charItem in pairs(self.m_tmpTeam) do
local charInfo = {
charId = charItem.templateId,
charInstId = charItem.instId,
}
table.insert(curTeam, charInfo)
end
else
curTeam = self.m_curTeam
end
local squad = GameInstance.player.charBag:GetCurrentMainTeam()
local serverTeam = self:_SquadToTeamInfo(squad).slots
local changedChars = {}
for i = 1, #curTeam do
local isChangedChar = true
for j = 1, #serverTeam do
if curTeam[i].charId == serverTeam[j].charId then
isChangedChar = false
end
end
if isChangedChar then
table.insert(changedChars, curTeam[i].charId)
end
end
if #changedChars > 0 then
local randomIndex = math.random(1, #changedChars)
Utils.triggerVoice("chrbark_join", changedChars[randomIndex])
else
local randomIndex = math.random(1, #curTeam)
Utils.triggerVoice("chrbark_join", curTeam[randomIndex].charId)
end
end
PhaseCharFormation.OnPreLevelStart = HL.StaticMethod() << function()
PhaseManager:TryCacheGOByName(PHASE_ID, PHASE_CHAR_FORMATION_GAME_OBJECT)
end
PhaseCharFormation.OnSceneLoadStart = HL.StaticMethod() << function()
end
PhaseCharFormation._OnSwitchLanguage = HL.StaticMethod() << function()
PhaseManager:ReleaseCache(PHASE_ID, PHASE_CHAR_FORMATION_GAME_OBJECT)
PhaseManager:TryCacheGOByName(PHASE_ID, PHASE_CHAR_FORMATION_GAME_OBJECT)
end
PhaseCharFormation.m_lockedTeamData = HL.Field(HL.Table)
PhaseCharFormation._GenerateLockedFormationData = HL.Method(HL.String).Return(HL.Table) << function(self, teamConfigId)
local lockedTeamData = CharInfoUtils.getLockedFormationData(teamConfigId, true)
if lockedTeamData.lockedTeamMemberCount < lockedTeamData.maxTeamMemberCount then
local teamInfo = GameInstance.player.charBag:GetCurrentMainTeam()
local curTeamMemberCount = lockedTeamData.lockedTeamMemberCount
local curSquadSlotCSIndex = curTeamMemberCount
for i = curTeamMemberCount + 1, lockedTeamData.maxTeamMemberCount do
while curSquadSlotCSIndex < teamInfo.memberList.Count do
local charInstId = teamInfo.memberList[curSquadSlotCSIndex]
local csCharInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId)
local isInLockedTeam = false
for _, char in ipairs(lockedTeamData.chars) do
if char.charId == csCharInfo.templateId then
isInLockedTeam = true
break
end
end
local isDead = csCharInfo and csCharInfo.isDead
if isDead or isInLockedTeam then
curSquadSlotCSIndex = curSquadSlotCSIndex + 1
else
break
end
end
if curSquadSlotCSIndex >= teamInfo.memberList.Count then
break
end
local charInstId = teamInfo.memberList[curSquadSlotCSIndex]
local csCharInfo = CharInfoUtils.getPlayerCharInfoByInstId(charInstId)
local charInfo = {
charInstId = charInstId,
charId = csCharInfo.templateId,
}
table.insert(lockedTeamData.chars, charInfo)
curSquadSlotCSIndex = curSquadSlotCSIndex + 1
end
end
return lockedTeamData
end
PhaseCharFormation._InitControllerSlotSelectedState = HL.Method() << function(self)
if not DeviceInfo.usingController then
return
end
self:_HideAllControllerSlotSelected()
self.m_navigatedCharIndex = 1
self:_RefreshControllerSlotSelectedState(self.m_navigatedCharIndex, true)
end
PhaseCharFormation._HideAllControllerSlotSelected = HL.Method() << function(self)
for i = 1, Const.BATTLE_SQUAD_MAX_CHAR_NUM do
self:_RefreshControllerSlotSelectedState(i, false)
end
end
PhaseCharFormation._RefreshControllerSlotSelectedState = HL.Method(HL.Number, HL.Boolean) << function(self, index, isSelected)
local selectEffect = self.m_sceneObject.view["selectEffect" .. string.format("%d", index)]
if selectEffect == nil then
return
end
selectEffect.gameObject:SetActive(isSelected)
end
PhaseCharFormation.OnChangeSlotHoverIndex = HL.Method(HL.Boolean) << function(self, isNext)
self:_RefreshControllerSlotSelectedState(self.m_navigatedCharIndex, false)
self.m_navigatedCharIndex = isNext and self.m_navigatedCharIndex + 1 or self.m_navigatedCharIndex - 1
if self.m_navigatedCharIndex > Const.BATTLE_SQUAD_MAX_CHAR_NUM then
self.m_navigatedCharIndex = 1
elseif self.m_navigatedCharIndex < 1 then
self.m_navigatedCharIndex = Const.BATTLE_SQUAD_MAX_CHAR_NUM
end
self:_RefreshControllerSlotSelectedState(self.m_navigatedCharIndex, true)
AudioAdapter.PostEvent("Au_UI_Toggle_CharSelect")
end
PhaseCharFormation.OnConfirmSelectedSlotHover = HL.Method() << function(self)
self:_OnSingleCharClicked(self.m_navigatedCharIndex)
end
HL.Commit(PhaseCharFormation)