549 lines
16 KiB
C#
549 lines
16 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using Animancer;
|
||
using Logic;
|
||
using Logic.Action;
|
||
using MapWaterType = Logic.MapWaterType;
|
||
using Logic.AI;
|
||
using Logic.Audio;
|
||
using Logic.CrashSight;
|
||
using Logic.Multilingual;
|
||
using ParadoxNotion;
|
||
using RuntimeData;
|
||
using MapConfig = RuntimeData.MapConfig;
|
||
using Steamworks;
|
||
using TH1_Core.Events;
|
||
using TH1_Core.Managers;
|
||
using TH1_Logic.Action;
|
||
using TH1_Logic.Core;
|
||
using TH1_Logic.MatchConfig;
|
||
using TH1_Logic.Net;
|
||
using TH1_Logic.Steam;
|
||
using TH1_UI.View.Announce;
|
||
using TH1Resource;
|
||
using TMPro;
|
||
using Unity.VisualScripting;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
namespace TH1_UI.View.Outside
|
||
{
|
||
|
||
public class UIOutsideSelectView : Base.View
|
||
{
|
||
[Header("按钮")]
|
||
public Button CloseButton;
|
||
public Button SettingButton;
|
||
|
||
[Header("选择列表")]
|
||
public List<Empire> CivForceList;
|
||
public List<GameObject> PicList;
|
||
public GameObject SelectAvatarPrefab;
|
||
public GameObject SelectList;
|
||
private List<UIOutsideSelectAvatarMono> _monoList;
|
||
private UIOutsideSelectAvatarMono _randomAvatarMono;
|
||
private Empire _selectEmpire;
|
||
private bool _selectRandom;
|
||
//暴露当前选中的阵营,供 Controller 在开始游戏时传给 Loading 界面
|
||
public Empire SelectedEmpire => _selectEmpire;
|
||
|
||
[Header("详细信息")]
|
||
public RectTransform InfoGroup;
|
||
public RectTransform CivBG;
|
||
public TextMeshProUGUI ForceName;
|
||
public TextMeshProUGUI CivName;
|
||
public TextMeshProUGUI LeaderDesc;
|
||
public TextMeshProUGUI EmpireDesc;
|
||
public List<GameObject> StarList;
|
||
public List<GameObject> GreyStarList;
|
||
public GameObject SkillCircleGroup;
|
||
public GameObject SkillCirclePrefab;
|
||
public List<UIOutsideSelectSkillCircleMono> SkillCircleList;
|
||
public GameObject RandomPanel;
|
||
public AnimancerComponent RandomPanelAnimancer;
|
||
|
||
|
||
[Header("中央立绘区")]
|
||
public Image BG1;
|
||
public Image BG2;
|
||
public List<UIOutsideSelectForceGroupMono> ForceGroupList;
|
||
|
||
[Header("子界面")]
|
||
public UIOutsideSelectCheckPanelMono SelectCheckPanelMono;
|
||
|
||
//关闭时执行的委托
|
||
public ViDelegateAssisstant.Dele OnBtnCloseClick;
|
||
|
||
//开始游戏时执行的委托(目前委托内容就是执行controller的Close())
|
||
public ViDelegateAssisstant.Dele OnStartGame;
|
||
|
||
// PlayerPrefs key for saving last selected empire
|
||
private const string LAST_SELECTED_CIV_KEY = "LastSelectedCiv";
|
||
private const string LAST_SELECTED_FORCE_KEY = "LastSelectedForce";
|
||
// PlayerPrefs key for saving last selected map size in CREATIVE mode
|
||
private const string LAST_MAP_SIZE_INDEX_KEY = "LastCreativeMapSizeIndex";
|
||
|
||
protected override void OnInit()
|
||
{
|
||
base.OnInit();
|
||
//清空List下的内容
|
||
for(int i = SelectList.transform.childCount - 1;i >= 0;i --)
|
||
{
|
||
Transform child = SelectList.transform.GetChild(i);
|
||
GameObject.Destroy(child.gameObject);
|
||
}
|
||
_monoList = new List<UIOutsideSelectAvatarMono>();
|
||
foreach (var t in CivForceList)
|
||
{
|
||
if (!ContentGate.CanSelectEmpire(t)) continue;
|
||
// TODO: 暂时屏蔽第四阵营(Indian/Satori),待正式上线后移除此判断
|
||
//if (t.Civ == CivEnum.Indian) continue;
|
||
|
||
var obj = Instantiate(SelectAvatarPrefab, SelectList.transform);
|
||
var mono = obj.GetComponent<UIOutsideSelectAvatarMono>();
|
||
if (mono == null) continue;
|
||
mono.SetContent(t,OnAvatarClicked);
|
||
_monoList.Add(mono);
|
||
}
|
||
CreateRandomAvatar();
|
||
SetRandomPanelVisible(false, true);
|
||
|
||
CloseButton.onClick.RemoveAllListeners();
|
||
CloseButton.onClick.AddListener(() =>
|
||
{
|
||
OnBtnCloseClick?.Invoke();
|
||
});
|
||
|
||
//处理ChekPanel
|
||
SelectCheckPanelMono.Init(OnStartClicked);
|
||
SettingButton.onClick.RemoveAllListeners();
|
||
SettingButton.onClick.AddListener(OnSettingClicked);
|
||
|
||
|
||
|
||
}
|
||
|
||
private void OnAvatarClicked(Empire playerEmpire)
|
||
{
|
||
if (!ContentGate.CanUseEmpire(playerEmpire)) return;
|
||
_selectRandom = false;
|
||
foreach(var t in _monoList)
|
||
if(t.PlayerEmpire != playerEmpire)
|
||
t.SetHide();
|
||
SetRandomPanelVisible(false);
|
||
SetCivForceInfo(playerEmpire);
|
||
}
|
||
|
||
private void OnRandomAvatarClicked(UIOutsideSelectAvatarMono randomMono)
|
||
{
|
||
_selectRandom = true;
|
||
foreach(var t in _monoList)
|
||
if(t != randomMono)
|
||
t.SetHide();
|
||
SelectCheckPanelMono?.SetPlayerEmpire(new Empire(CivEnum.Common, ForceEnum.Common), true);
|
||
SetRandomPanelVisible(true);
|
||
}
|
||
|
||
|
||
|
||
public void Update()
|
||
{
|
||
|
||
}
|
||
public void SetContent(ShowUIOutsideSelect evt)
|
||
{
|
||
if (_monoList.Count == 0) return;
|
||
SelectCheckPanelMono.gameObject.SetActive(false) ;
|
||
|
||
// Try to restore last selected empire
|
||
Empire? lastSelectedEmpire = GetLastSelectedEmpire();
|
||
UIOutsideSelectAvatarMono targetMono = null;
|
||
|
||
if (lastSelectedEmpire.HasValue)
|
||
{
|
||
// Find the mono that matches the last selected empire
|
||
foreach (var mono in _monoList)
|
||
{
|
||
if (mono.PlayerEmpire.Civ == lastSelectedEmpire.Value.Civ &&
|
||
mono.PlayerEmpire.Force == lastSelectedEmpire.Value.Force)
|
||
{
|
||
targetMono = mono;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// If no last selection found or not available, default to first
|
||
if (targetMono == null)
|
||
{
|
||
targetMono = GetFirstSelectableAvatar();
|
||
if (targetMono == null) return;
|
||
}
|
||
|
||
targetMono.Button.onClick.Invoke();
|
||
SetCivForceInfo(targetMono.PlayerEmpire);
|
||
}
|
||
|
||
public void SetCivForceInfo(Empire playerEmpire)
|
||
{
|
||
if (!ContentGate.CanUseEmpire(playerEmpire)) return;
|
||
_selectRandom = false;
|
||
_selectEmpire = playerEmpire;
|
||
SelectCheckPanelMono?.SetPlayerEmpire(playerEmpire);
|
||
if (!Table.Instance.PlayerDataAssets.GetPlayerInfo(playerEmpire.Civ, playerEmpire.Force, out var info)) return;
|
||
//Step #1 设置文明基础文字信息
|
||
MultilingualManager.Instance.SetUIText(ForceName,info.ForceName);
|
||
MultilingualManager.Instance.SetUIText(CivName,info.CivName);
|
||
LayoutRebuilder.ForceRebuildLayoutImmediate(CivBG);
|
||
|
||
//Step #2 设置文明的难度情况
|
||
var dif = info.Diff;
|
||
var grey = 4 - dif;
|
||
for(int i = 0;i < StarList.Count ; i++)
|
||
StarList[i].SetActive(i < dif);
|
||
for(int i = 0;i < GreyStarList.Count ; i++)
|
||
GreyStarList[i].SetActive(i < grey);
|
||
|
||
//Step #2 设置文明特色SkillGroup
|
||
//清空SkillGroup
|
||
for (int i = SkillCircleGroup.transform.childCount - 1; i >= 0; i--)
|
||
{
|
||
Transform child = SkillCircleGroup.transform.GetChild(i);
|
||
child.gameObject.SetActive(false);
|
||
}
|
||
for (int i = SkillCircleGroup.transform.childCount; i < info.TechAtomList.Count; i++)
|
||
{
|
||
var pre = Instantiate(SkillCirclePrefab, SkillCircleGroup.transform);
|
||
var mono = pre?.GetComponent<UIOutsideSelectSkillCircleMono>();
|
||
if(mono == null)continue;
|
||
SkillCircleList.Add(mono);
|
||
}
|
||
SkillCircleList = new List<UIOutsideSelectSkillCircleMono>();
|
||
for (int i = 0; i < info.TechAtomList.Count; i++)
|
||
{
|
||
Transform child = SkillCircleGroup.transform.GetChild(i);
|
||
if (child == null) break;
|
||
child.gameObject.SetActive(true);
|
||
var mono = child?.GetComponent<UIOutsideSelectSkillCircleMono>();
|
||
if(mono == null)continue;
|
||
SkillCircleList.Add(mono);
|
||
mono.SetContent(playerEmpire,info.TechAtomList[i]);
|
||
}
|
||
|
||
//Step #3 设置文明基础文字信息
|
||
MultilingualManager.Instance.SetUIText(EmpireDesc,info.EmpireDesc);
|
||
MultilingualManager.Instance.SetUIText(LeaderDesc,info.LeaderDesc);
|
||
//LayoutRebuilder.ForceRebuildLayoutImmediate(CivBG);
|
||
//LayoutRebuilder.ForceRebuildLayoutImmediate(SkillCircleGroup.GetComponent<RectTransform>());
|
||
|
||
LayoutRebuilder.ForceRebuildLayoutImmediate(InfoGroup);
|
||
|
||
//Step #4 设置立绘
|
||
foreach (var forceGroup in ForceGroupList)
|
||
{
|
||
|
||
if (forceGroup.Empire == playerEmpire)
|
||
{
|
||
forceGroup.gameObject.SetActive(true);
|
||
BG1.color = info.Color;
|
||
BG2.color = info.Color;
|
||
foreach(var heroPack in forceGroup.HeroList)
|
||
heroPack.SetContent();
|
||
}
|
||
else
|
||
forceGroup.gameObject.SetActive(false);
|
||
}
|
||
|
||
|
||
//Step #5 播放对应音乐
|
||
AudioManager.Instance.PlayMusic(info.MusicName,1f,1f,true);
|
||
|
||
}
|
||
|
||
//在Controller 调用Close的时候,会先调用这个closeview
|
||
public void OnCloseView()
|
||
{
|
||
}
|
||
|
||
public void OnSettingClicked()
|
||
{
|
||
SelectCheckPanelMono.Show();
|
||
}
|
||
|
||
public void OnStartClicked()
|
||
{
|
||
bool wasRandomSelected = _selectRandom;
|
||
if (wasRandomSelected)
|
||
{
|
||
ApplyRandomSelectedEmpire();
|
||
}
|
||
if (!ContentGate.CanUseEmpire(_selectEmpire))
|
||
{
|
||
var targetMono = GetFirstSelectableAvatar();
|
||
if (targetMono == null) return;
|
||
SetCivForceInfo(targetMono.PlayerEmpire);
|
||
}
|
||
|
||
GameMode gameMode = SelectCheckPanelMono.GameMode.SelectedIndex switch
|
||
{
|
||
0 => GameMode.DOMINATION,
|
||
1 => GameMode.PERFECT,
|
||
_ => GameMode.CREATIVE
|
||
};
|
||
uint playerCount = SelectCheckPanelMono.PlayerCount.SelectedIndex + 2;
|
||
uint mapSize;
|
||
mapSize = SelectCheckPanelMono.MapSize.SelectedIndex switch
|
||
{
|
||
0 => 11,
|
||
1 => 14,
|
||
2 => 16,
|
||
3 => 18,
|
||
4 => 20,
|
||
5 => 24,
|
||
6 => 30,
|
||
_ => 18
|
||
};
|
||
AIDifficult diff = SelectCheckPanelMono.Diff.SelectedIndex switch
|
||
{
|
||
0 => AIDifficult.EASY,
|
||
1 => AIDifficult.NORMAL,
|
||
2 => AIDifficult.HARD,
|
||
_ => AIDifficult.LUNATIC
|
||
};
|
||
|
||
MapWaterType waterType = (MapWaterType)(SelectCheckPanelMono.Water != null
|
||
? SelectCheckPanelMono.Water.SelectedIndex
|
||
: 2); // default Pangea
|
||
|
||
// domination => 2, perfect => 6, creative => custom win group
|
||
uint matchConfigId = gameMode switch
|
||
{
|
||
GameMode.PERFECT => 6,
|
||
GameMode.CREATIVE => SelectCheckPanelMono.GetSelectedCreativeMatchConfigId(),
|
||
_ => 2 // DOMINATION
|
||
};
|
||
Main.Instance.MapConfig.ChangeByMapConfig(MatchConfigManager.Instance.GetMatchConfig(matchConfigId));
|
||
Main.Instance.MapConfig.Id = matchConfigId;
|
||
Main.Instance.MapConfig.GameMode = gameMode;
|
||
Main.Instance.MapConfig.Width = mapSize;
|
||
Main.Instance.MapConfig.Height = mapSize;
|
||
Main.Instance.MapConfig.SetPlayerCount(playerCount, NetMode.Single);
|
||
Main.Instance.MapConfig.AIDiff = diff;
|
||
Main.Instance.MapConfig.WaterType = waterType;
|
||
Main.Instance.MapConfig.DisableNearbySpawnPoints =
|
||
gameMode == GameMode.CREATIVE && SelectCheckPanelMono.DisableNearbySpawnPoints;
|
||
Main.Instance.MapConfig.SetSinglePlayerCiv(
|
||
Table.Instance.TransCivEnumToCivId(_selectEmpire.Civ),
|
||
Table.Instance.TransForceEnumToForceId(_selectEmpire.Force));
|
||
SelectCheckPanelMono.PrepareAISettingsForStart(playerCount, gameMode == GameMode.CREATIVE);
|
||
ApplyAISettingsToMapConfig(gameMode);
|
||
|
||
// Save the selected empire for next time
|
||
if (!wasRandomSelected)
|
||
{
|
||
SaveLastSelectedEmpire(_selectEmpire);
|
||
}
|
||
|
||
// CREATIVE模式下保存MapSize选择
|
||
if (gameMode == GameMode.CREATIVE)
|
||
{
|
||
SaveLastMapSize(SelectCheckPanelMono.MapSize.SelectedIndex);
|
||
}
|
||
|
||
//设置好参数后,调用Controller的委托
|
||
OnStartGame?.Invoke();
|
||
|
||
}
|
||
|
||
private void ApplyAISettingsToMapConfig(GameMode gameMode)
|
||
{
|
||
if (SelectCheckPanelMono == null || Main.Instance.MapConfig?.MultiCivs == null) return;
|
||
|
||
int maxTeamId = Mathf.Max(1, (int)Main.Instance.MapConfig.PlayerCount);
|
||
var selfSlot = Main.Instance.MapConfig.GetPlayerSlot(0, NetMode.Single);
|
||
if (selfSlot != null)
|
||
{
|
||
selfSlot.TeamId = gameMode == GameMode.CREATIVE ? 1 : MapConfig.NoTeamId;
|
||
selfSlot.IsAI = false;
|
||
selfSlot.IsHostControlled = false;
|
||
selfSlot.IsCivFixed = true;
|
||
}
|
||
|
||
foreach (var setting in SelectCheckPanelMono.AISettings)
|
||
{
|
||
var slot = Main.Instance.MapConfig.GetPlayerSlot(setting.SlotIndex, NetMode.Single);
|
||
if (slot == null) continue;
|
||
|
||
slot.Index = setting.SlotIndex;
|
||
slot.MemberId = 0;
|
||
slot.PlayerId = 0;
|
||
slot.CivId = setting.IsRandom ? MapConfig.RandomCivId : setting.CivId;
|
||
slot.ForceId = setting.IsRandom ? MapConfig.RandomForceId : setting.ForceId;
|
||
slot.TeamId = gameMode == GameMode.CREATIVE
|
||
? Mathf.Clamp(setting.TeamId, 1, maxTeamId)
|
||
: MapConfig.NoTeamId;
|
||
slot.IsCivFixed = !setting.IsRandom;
|
||
slot.IsReady = false;
|
||
slot.IsAI = !SelectCheckPanelMono.IsTestMode;
|
||
slot.IsHostControlled = SelectCheckPanelMono.IsTestMode;
|
||
}
|
||
|
||
Main.Instance.MapConfig.ResolveRandomPlayerSlotCivsForStart(NetMode.Single);
|
||
|
||
LogSingleCreativeTeamConfig(gameMode);
|
||
}
|
||
|
||
private void LogSingleCreativeTeamConfig(GameMode gameMode)
|
||
{
|
||
var config = Main.Instance.MapConfig;
|
||
if (gameMode != GameMode.CREATIVE || config?.MultiCivs == null) return;
|
||
|
||
var sb = new System.Text.StringBuilder();
|
||
sb.Append("[SingleCreativeTeam] BeforeStart ");
|
||
for (int i = 0; i < config.MultiCivs.Count; i++)
|
||
{
|
||
var slot = config.MultiCivs[i];
|
||
if (slot == null) continue;
|
||
if (i > 0) sb.Append(" | ");
|
||
sb.Append($"slot={slot.Index},team={slot.TeamId},civ={slot.CivId},force={slot.ForceId},ai={slot.IsAI},hostControlled={slot.IsHostControlled}");
|
||
}
|
||
|
||
LogSystem.LogInfo(sb.ToString());
|
||
}
|
||
|
||
private void CreateRandomAvatar()
|
||
{
|
||
if (SelectAvatarPrefab == null || SelectList == null) return;
|
||
|
||
var obj = Instantiate(SelectAvatarPrefab, SelectList.transform);
|
||
_randomAvatarMono = obj.GetComponent<UIOutsideSelectAvatarMono>();
|
||
if (_randomAvatarMono == null) return;
|
||
|
||
var randomAvatar = Table.Instance?.PlayerDataAssets?.CommonPlayerAvatar;
|
||
if (randomAvatar == null)
|
||
{
|
||
randomAvatar = TH1Resource.ResourceLoader.Load<Sprite>("TH1UI/Common/CommonAvatar/CommonAvatar");
|
||
}
|
||
var randomTitle = Table.Instance?.TextDataAssets?.OutsideSelectRandomEmpire;
|
||
_randomAvatarMono.SetRandomContent(randomAvatar, randomTitle, OnRandomAvatarClicked);
|
||
_monoList.Add(_randomAvatarMono);
|
||
}
|
||
|
||
private void ApplyRandomSelectedEmpire()
|
||
{
|
||
var candidates = new List<Empire>();
|
||
foreach (var mono in _monoList)
|
||
{
|
||
if (mono == null || mono.IsRandom) continue;
|
||
candidates.Add(mono.PlayerEmpire);
|
||
}
|
||
if (candidates.Count == 0) return;
|
||
|
||
var index = UnityEngine.Random.Range(0, candidates.Count);
|
||
SetCivForceInfo(candidates[index]);
|
||
}
|
||
|
||
private UIOutsideSelectAvatarMono GetFirstSelectableAvatar()
|
||
{
|
||
foreach (var mono in _monoList)
|
||
{
|
||
if (mono == null || mono.IsRandom) continue;
|
||
if (ContentGate.CanUseEmpire(mono.PlayerEmpire)) return mono;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
private void SetRandomPanelVisible(bool visible, bool immediate = false)
|
||
{
|
||
if (RandomPanel == null) return;
|
||
|
||
var canvasGroup = RandomPanel.GetComponent<CanvasGroup>();
|
||
if (immediate)
|
||
{
|
||
if (RandomPanelAnimancer != null) RandomPanelAnimancer.Stop();
|
||
if (canvasGroup != null) canvasGroup.alpha = visible ? 1f : 0f;
|
||
RandomPanel.SetActive(visible);
|
||
return;
|
||
}
|
||
|
||
if (visible)
|
||
{
|
||
RandomPanel.SetActive(true);
|
||
var clip = ResourceCache.Instance?.AnimCache?.UICommonPanelFadeIn;
|
||
if (RandomPanelAnimancer != null && RandomPanelAnimancer.Animator != null && clip != null)
|
||
{
|
||
RandomPanelAnimancer.Play(clip);
|
||
}
|
||
else if (canvasGroup != null)
|
||
{
|
||
canvasGroup.alpha = 1f;
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (!RandomPanel.activeSelf) return;
|
||
|
||
var fadeOutClip = ResourceCache.Instance?.AnimCache?.UICommonPanelFadeOut;
|
||
if (RandomPanelAnimancer != null && RandomPanelAnimancer.Animator != null && fadeOutClip != null)
|
||
{
|
||
var state = RandomPanelAnimancer.Play(fadeOutClip);
|
||
state.Events.OnEnd = () =>
|
||
{
|
||
if (RandomPanel != null) RandomPanel.SetActive(false);
|
||
state.Events.OnEnd = null;
|
||
};
|
||
}
|
||
else
|
||
{
|
||
if (canvasGroup != null) canvasGroup.alpha = 0f;
|
||
RandomPanel.SetActive(false);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Save the last selected empire to PlayerPrefs
|
||
/// </summary>
|
||
private void SaveLastSelectedEmpire(Empire empire)
|
||
{
|
||
PlayerPrefs.SetInt(LAST_SELECTED_CIV_KEY, (int)empire.Civ);
|
||
PlayerPrefs.SetInt(LAST_SELECTED_FORCE_KEY, (int)empire.Force);
|
||
PlayerPrefs.Save();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Save the last selected map size index for CREATIVE mode
|
||
/// </summary>
|
||
private void SaveLastMapSize(uint mapSizeIndex)
|
||
{
|
||
PlayerPrefs.SetInt(LAST_MAP_SIZE_INDEX_KEY, (int)mapSizeIndex);
|
||
PlayerPrefs.Save();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get the last selected empire from PlayerPrefs
|
||
/// </summary>
|
||
private Empire? GetLastSelectedEmpire()
|
||
{
|
||
if (!PlayerPrefs.HasKey(LAST_SELECTED_CIV_KEY) || !PlayerPrefs.HasKey(LAST_SELECTED_FORCE_KEY))
|
||
return null;
|
||
|
||
int civValue = PlayerPrefs.GetInt(LAST_SELECTED_CIV_KEY);
|
||
int forceValue = PlayerPrefs.GetInt(LAST_SELECTED_FORCE_KEY);
|
||
|
||
// Validate the values are valid enums
|
||
if (!Enum.IsDefined(typeof(CivEnum), civValue) || !Enum.IsDefined(typeof(ForceEnum), forceValue))
|
||
return null;
|
||
|
||
var empire = new Empire((CivEnum)civValue, (ForceEnum)forceValue);
|
||
return ContentGate.CanUseEmpire(empire) ? empire : null;
|
||
}
|
||
|
||
public void CloseView()
|
||
{
|
||
AudioManager.Instance.StopMusic();
|
||
}
|
||
}
|
||
|
||
}
|