733 lines
27 KiB
C#
733 lines
27 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Animancer;
|
|
using Logic.AI;
|
|
using Logic.Multilingual;
|
|
using RuntimeData;
|
|
using TH1_Logic.Core;
|
|
using TH1_Logic.Net;
|
|
using TH1_UI.View.Outside;
|
|
using TH1Resource;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
public class UIOutsideSelectCheckPanelMono : MonoBehaviour
|
|
{
|
|
public UIOutsideSelectOptionGroupMono GameMode;
|
|
public UIOutsideSelectOptionGroupMono PlayerCount;
|
|
public UIOutsideSelectOptionGroupMono MapSize;
|
|
public UIOutsideSelectOptionGroupMono Diff;
|
|
public UIOutsideSelectOptionGroupMono Water;
|
|
public GameObject WinTitle;
|
|
public UIOutsideSelectOptionGroupMono WinGroup;
|
|
public GameObject AISettingTitle;
|
|
public GameObject AISettingGroup;
|
|
public GameObject AISettingRowPrefab;
|
|
public GameObject TestTitle;
|
|
public GameObject TestGroup;
|
|
public Toggle ResumeToggle;
|
|
public Toggle NearToggle;
|
|
public Button StartButton;
|
|
public Button CloseButton;
|
|
public Button BlockerButton;
|
|
public AnimancerComponent Animancer;
|
|
|
|
private const string LAST_MAP_SIZE_INDEX_KEY = "LastCreativeMapSizeIndex";
|
|
private const string DISABLE_NEARBY_SPAWN_POINTS_PREFS_KEY = "DisableNearbySpawnPoints";
|
|
private static readonly uint[] CreativeWinMatchConfigIds = { 7, 9, 10 };
|
|
private static readonly List<(CivEnum Civ, ForceEnum Force)> FallbackForceOptions = new List<(CivEnum Civ, ForceEnum Force)>
|
|
{
|
|
(CivEnum.Egyptian, ForceEnum.Remilia),
|
|
(CivEnum.French, ForceEnum.Kaguya),
|
|
(CivEnum.Germany, ForceEnum.Kanako),
|
|
(CivEnum.Indian, ForceEnum.Satori),
|
|
};
|
|
|
|
private Action _onStartClick;
|
|
private Empire _playerEmpire;
|
|
private bool _playerEmpireIsRandom;
|
|
private readonly List<AISettingData> _aiSettings = new List<AISettingData>();
|
|
private readonly List<UIOutsideSelectAISettingRowMono> _aiSettingRows = new List<UIOutsideSelectAISettingRowMono>();
|
|
private bool _aiSettingRowsCached;
|
|
|
|
public uint WinSelectedIndex => WinGroup != null ? WinGroup.SelectedIndex : 0;
|
|
public bool IsTestMode => GameMode != null && GameMode.SelectedIndex == 2 && ResumeToggle != null && ResumeToggle.isOn;
|
|
public bool DisableNearbySpawnPoints => GameMode != null
|
|
&& GameMode.SelectedIndex == 2
|
|
&& NearToggle != null
|
|
&& NearToggle.isOn;
|
|
public IReadOnlyList<AISettingData> AISettings => _aiSettings;
|
|
|
|
public class AISettingData
|
|
{
|
|
public int SlotIndex;
|
|
public uint CivId;
|
|
public uint ForceId;
|
|
public bool IsRandom;
|
|
public int TeamId;
|
|
public bool IsForceUserEdited;
|
|
public bool IsTeamUserEdited;
|
|
}
|
|
|
|
public void Init(Action onStartClick)
|
|
{
|
|
InitSetting();
|
|
_onStartClick = onStartClick;
|
|
|
|
StartButton.onClick.RemoveAllListeners();
|
|
StartButton.onClick.AddListener(() => _onStartClick?.Invoke());
|
|
|
|
CloseButton.onClick.RemoveAllListeners();
|
|
CloseButton.onClick.AddListener(Hide);
|
|
|
|
BlockerButton.onClick.RemoveAllListeners();
|
|
BlockerButton.onClick.AddListener(Hide);
|
|
}
|
|
|
|
public void SetPlayerEmpire(Empire playerEmpire, bool isRandom = false)
|
|
{
|
|
_playerEmpire = playerEmpire;
|
|
_playerEmpireIsRandom = isRandom;
|
|
uint playerCount = PlayerCount != null
|
|
? PlayerCount.SelectedIndex + 2
|
|
: Main.Instance.MapConfig?.PlayerCount ?? 2;
|
|
var preserveUserEdits = GameMode != null && GameMode.SelectedIndex == 2;
|
|
InitAISettings(playerCount, preserveUserEdits, preserveUserEdits);
|
|
RefreshAISettingRows();
|
|
}
|
|
|
|
public void PrepareAISettingsForStart(uint playerCount, bool preserveUserEdits)
|
|
{
|
|
InitAISettings(playerCount, preserveUserEdits, preserveUserEdits);
|
|
RefreshAISettingRows();
|
|
}
|
|
|
|
public void InitSetting()
|
|
{
|
|
Main.Instance.MapConfig?.ResetTransientMatchOptions();
|
|
|
|
uint playerCount = 2;
|
|
AIDifficult diff = AIDifficult.HARD;
|
|
GameMode gameMode = RuntimeData.GameMode.PERFECT;
|
|
uint matchConfigId = 7;
|
|
|
|
if (Main.Instance.MapConfig != null)
|
|
{
|
|
playerCount = Main.Instance.MapConfig.PlayerCount;
|
|
diff = Main.Instance.MapConfig.AIDiff;
|
|
gameMode = Main.Instance.MapConfig.GameMode;
|
|
matchConfigId = Main.Instance.MapConfig.Id;
|
|
}
|
|
|
|
uint playerCountIdx = playerCount >= 2 ? playerCount - 2 : 0;
|
|
uint mapSizeIdx = gameMode == RuntimeData.GameMode.CREATIVE
|
|
? (uint)PlayerPrefs.GetInt(LAST_MAP_SIZE_INDEX_KEY, 3)
|
|
: playerCount switch
|
|
{
|
|
2 => 0,
|
|
3 => 1,
|
|
4 => 2,
|
|
_ => 3
|
|
};
|
|
uint diffIdx = diff switch
|
|
{
|
|
AIDifficult.EASY => 0,
|
|
AIDifficult.NORMAL => 1,
|
|
AIDifficult.HARD => 2,
|
|
_ => 3
|
|
};
|
|
uint gameModeIdx = gameMode switch
|
|
{
|
|
RuntimeData.GameMode.DOMINATION => 0,
|
|
RuntimeData.GameMode.PERFECT => 1,
|
|
RuntimeData.GameMode.CREATIVE => 2,
|
|
_ => 2
|
|
};
|
|
uint waterIdx = gameMode == RuntimeData.GameMode.CREATIVE && Main.Instance.MapConfig != null
|
|
? (uint)Main.Instance.MapConfig.WaterType
|
|
: 2;
|
|
|
|
GameMode.OnOptionClicked = OnGameModeOptionClicked;
|
|
PlayerCount.OnOptionClicked = OnPlayerOptionClicked;
|
|
if (WinGroup != null) WinGroup.OnOptionClicked = OnWinOptionClicked;
|
|
if (ResumeToggle != null)
|
|
{
|
|
ResumeToggle.onValueChanged.RemoveAllListeners();
|
|
ResumeToggle.onValueChanged.AddListener(OnTestModeChanged);
|
|
}
|
|
if (NearToggle != null)
|
|
{
|
|
NearToggle.onValueChanged.RemoveAllListeners();
|
|
NearToggle.onValueChanged.AddListener(OnNearToggleChanged);
|
|
}
|
|
SetNearToggleSavedValue(gameMode == RuntimeData.GameMode.CREATIVE);
|
|
|
|
GameMode.Init(gameModeIdx);
|
|
PlayerCount.Init(playerCountIdx);
|
|
MapSize.Init(mapSizeIdx);
|
|
Diff.Init(diffIdx);
|
|
if (Water != null) Water.Init(waterIdx);
|
|
if (WinGroup != null) WinGroup.Init(GetWinIndexByMatchConfigId(matchConfigId));
|
|
|
|
InitAISettings(playerCount, false, false);
|
|
OnGameModeOptionClicked(gameModeIdx);
|
|
}
|
|
|
|
public void OnPlayerOptionClicked(uint idx)
|
|
{
|
|
var preserveUserEdits = GameMode != null && GameMode.SelectedIndex == 2;
|
|
InitAISettings(idx + 2, preserveUserEdits, preserveUserEdits);
|
|
RefreshAISettingRows();
|
|
|
|
if (GameMode.SelectedIndex == 2) return;
|
|
uint mapSizeIdx = idx switch
|
|
{
|
|
0 => 0,
|
|
1 => 1,
|
|
2 => 2,
|
|
_ => 3
|
|
};
|
|
MapSize.Select(mapSizeIdx);
|
|
}
|
|
|
|
public void OnGameModeOptionClicked(uint idx)
|
|
{
|
|
bool isCreative = idx == 2;
|
|
if (WinTitle != null) WinTitle.SetActive(isCreative);
|
|
if (WinGroup != null)
|
|
{
|
|
WinGroup.gameObject.SetActive(isCreative);
|
|
WinGroup.Init(WinGroup.SelectedIndex);
|
|
}
|
|
if (AISettingTitle != null) AISettingTitle.SetActive(isCreative);
|
|
if (AISettingGroup != null) AISettingGroup.SetActive(isCreative);
|
|
if (TestTitle != null) TestTitle.SetActive(isCreative);
|
|
if (TestGroup != null) TestGroup.SetActive(isCreative);
|
|
RefreshNearToggleVisibility(isCreative);
|
|
RefreshAISettingRows();
|
|
|
|
if (isCreative)
|
|
{
|
|
MapSize.Passive = false;
|
|
MapSize.Init(MapSize.SelectedIndex);
|
|
if (Water != null)
|
|
{
|
|
Water.Passive = false;
|
|
Water.Init(Water.SelectedIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MapSize.Passive = true;
|
|
MapSize.Init(MapSize.SelectedIndex);
|
|
OnPlayerOptionClicked(PlayerCount.SelectedIndex);
|
|
if (Water != null)
|
|
{
|
|
Water.Passive = true;
|
|
Water.Init(2);
|
|
}
|
|
}
|
|
}
|
|
|
|
public uint GetSelectedCreativeMatchConfigId()
|
|
{
|
|
return GetCreativeMatchConfigIdByWinIndex(WinSelectedIndex);
|
|
}
|
|
|
|
private void SetNearToggleSavedValue(bool isCreative)
|
|
{
|
|
if (NearToggle == null) return;
|
|
NearToggle.SetIsOnWithoutNotify(isCreative && PlayerPrefs.GetInt(DISABLE_NEARBY_SPAWN_POINTS_PREFS_KEY, 0) == 1);
|
|
}
|
|
|
|
private void RefreshNearToggleVisibility(bool isCreative)
|
|
{
|
|
if (NearToggle == null) return;
|
|
|
|
NearToggle.gameObject.SetActive(isCreative);
|
|
NearToggle.interactable = isCreative;
|
|
NearToggle.SetIsOnWithoutNotify(isCreative && PlayerPrefs.GetInt(DISABLE_NEARBY_SPAWN_POINTS_PREFS_KEY, 0) == 1);
|
|
}
|
|
|
|
private void OnNearToggleChanged(bool selected)
|
|
{
|
|
if (GameMode == null || GameMode.SelectedIndex != 2) return;
|
|
SaveDisableNearbySpawnPointsPreference(selected);
|
|
}
|
|
|
|
public void SaveDisableNearbySpawnPointsPreference()
|
|
{
|
|
if (GameMode == null || GameMode.SelectedIndex != 2) return;
|
|
SaveDisableNearbySpawnPointsPreference(NearToggle != null && NearToggle.isOn);
|
|
}
|
|
|
|
private static void SaveDisableNearbySpawnPointsPreference(bool selected)
|
|
{
|
|
PlayerPrefs.SetInt(DISABLE_NEARBY_SPAWN_POINTS_PREFS_KEY, selected ? 1 : 0);
|
|
PlayerPrefs.Save();
|
|
}
|
|
|
|
public void Show()
|
|
{
|
|
InitSetting();
|
|
gameObject.SetActive(true);
|
|
Animancer.Play(ResourceCache.Instance.AnimCache.UICommonPanelFadeIn);
|
|
|
|
Timer.Instance.TimerRegister(this, () =>
|
|
{
|
|
GameMode.OnShow();
|
|
PlayerCount.OnShow();
|
|
MapSize.OnShow();
|
|
Diff.OnShow();
|
|
if (Water != null) Water.OnShow();
|
|
if (WinGroup != null && WinGroup.gameObject.activeInHierarchy) WinGroup.OnShow();
|
|
}, 0.01f, "");
|
|
}
|
|
|
|
public void Hide()
|
|
{
|
|
var state = Animancer.Play(ResourceCache.Instance.AnimCache.UICommonPanelFadeOut);
|
|
state.Events.OnEnd = () => { gameObject.SetActive(false); };
|
|
}
|
|
|
|
private void InitAISettings(uint playerCount, bool preserveUserTeamEdits, bool preserveUserForceEdits)
|
|
{
|
|
int targetCount = Mathf.Max(0, (int)playerCount - 1);
|
|
var usedPlayerOptions = new HashSet<(uint CivId, uint ForceId)>();
|
|
AddPlayerEmpireToUsedOptions(usedPlayerOptions);
|
|
var nextSettings = new List<AISettingData>();
|
|
|
|
for (int slotIndex = 1; slotIndex <= targetCount; slotIndex++)
|
|
{
|
|
var existingData = GetAISettingData(slotIndex);
|
|
var slot = GetExistingPlayerSlot(slotIndex);
|
|
var setting = CreateAISettingData(slotIndex, playerCount, usedPlayerOptions, existingData, slot, preserveUserTeamEdits, preserveUserForceEdits);
|
|
nextSettings.Add(setting);
|
|
if (!setting.IsRandom) usedPlayerOptions.Add((setting.CivId, setting.ForceId));
|
|
}
|
|
|
|
_aiSettings.Clear();
|
|
_aiSettings.AddRange(nextSettings);
|
|
}
|
|
|
|
private AISettingData CreateAISettingData(
|
|
int slotIndex,
|
|
uint playerCount,
|
|
HashSet<(uint CivId, uint ForceId)> usedPlayerOptions,
|
|
AISettingData existingData,
|
|
MemberCiv slot,
|
|
bool preserveUserTeamEdits,
|
|
bool preserveUserForceEdits)
|
|
{
|
|
if (preserveUserForceEdits
|
|
&& existingData != null
|
|
&& existingData.IsForceUserEdited
|
|
&& (existingData.IsRandom || IsValidPlayerOption(existingData.CivId, existingData.ForceId)))
|
|
{
|
|
return new AISettingData
|
|
{
|
|
SlotIndex = slotIndex,
|
|
CivId = existingData.CivId,
|
|
ForceId = existingData.ForceId,
|
|
IsRandom = existingData.IsRandom,
|
|
TeamId = GetPreferredTeamId(existingData, slotIndex, (int)playerCount, preserveUserTeamEdits),
|
|
IsForceUserEdited = existingData.IsForceUserEdited,
|
|
IsTeamUserEdited = preserveUserTeamEdits && existingData.IsTeamUserEdited
|
|
};
|
|
}
|
|
|
|
var playerOption = PickDefaultPlayerOption(Mathf.Max(0, slotIndex - 1), usedPlayerOptions);
|
|
return new AISettingData
|
|
{
|
|
SlotIndex = slotIndex,
|
|
CivId = playerOption.CivId,
|
|
ForceId = playerOption.ForceId,
|
|
IsRandom = false,
|
|
TeamId = GetPreferredTeamId(existingData, slotIndex, (int)playerCount, preserveUserTeamEdits),
|
|
IsForceUserEdited = false,
|
|
IsTeamUserEdited = preserveUserTeamEdits && existingData?.IsTeamUserEdited == true
|
|
};
|
|
}
|
|
|
|
private void RefreshAISettingRows()
|
|
{
|
|
CacheExistingAISettingRows();
|
|
bool show = GameMode != null && GameMode.SelectedIndex == 2 && AISettingGroup != null;
|
|
if (AISettingGroup != null) AISettingGroup.SetActive(show);
|
|
if (!show)
|
|
{
|
|
for (int i = 0; i < _aiSettingRows.Count; i++)
|
|
if (_aiSettingRows[i] != null) _aiSettingRows[i].gameObject.SetActive(false);
|
|
RefreshAISettingLayout();
|
|
return;
|
|
}
|
|
|
|
var sameCountDict = BuildForceSameCountDict();
|
|
int maxTeamId = Mathf.Max(1, (int)(PlayerCount.SelectedIndex + 2));
|
|
int visibleRowCount = 0;
|
|
RenderSelfPlayerRow(sameCountDict, maxTeamId);
|
|
visibleRowCount++;
|
|
|
|
for (int i = 0; i < _aiSettings.Count; i++)
|
|
{
|
|
int rowIndex = i + 1;
|
|
var row = GetAISettingRow(rowIndex);
|
|
if (row == null) continue;
|
|
|
|
row.gameObject.SetActive(true);
|
|
row.transform.SetSiblingIndex(rowIndex);
|
|
var data = _aiSettings[i];
|
|
if (data.IsRandom)
|
|
{
|
|
row.SetRandomContent(data.TeamId, maxTeamId,
|
|
direction => OnAIRowForceChanged(data.SlotIndex, direction),
|
|
direction => OnAIRowTeamChanged(data.SlotIndex, direction));
|
|
visibleRowCount++;
|
|
continue;
|
|
}
|
|
|
|
var civ = Table.Instance.TransCivIdToCivEnum(data.CivId);
|
|
var force = Table.Instance.TransForceIdToForceEnum(data.ForceId);
|
|
var forceNameOverride = GetForceNameOverride(data, civ, force, sameCountDict);
|
|
row.SetContent(civ, force, data.TeamId, maxTeamId, forceNameOverride,
|
|
direction => OnAIRowForceChanged(data.SlotIndex, direction),
|
|
direction => OnAIRowTeamChanged(data.SlotIndex, direction));
|
|
visibleRowCount++;
|
|
}
|
|
|
|
for (int i = visibleRowCount; i < _aiSettingRows.Count; i++)
|
|
{
|
|
if (_aiSettingRows[i] == null) continue;
|
|
_aiSettingRows[i].gameObject.SetActive(false);
|
|
_aiSettingRows[i].transform.SetSiblingIndex(i);
|
|
}
|
|
|
|
RefreshAISettingLayout();
|
|
}
|
|
|
|
private void RenderSelfPlayerRow(Dictionary<(CivEnum, ForceEnum), int> sameCountDict, int maxTeamId)
|
|
{
|
|
var row = GetAISettingRow(0);
|
|
if (row == null) return;
|
|
|
|
row.gameObject.SetActive(true);
|
|
row.transform.SetSiblingIndex(0);
|
|
|
|
if (_playerEmpireIsRandom)
|
|
{
|
|
row.SetRandomSelfContent(1, maxTeamId);
|
|
return;
|
|
}
|
|
|
|
var playerEmpire = GetCurrentPlayerEmpire();
|
|
var forceNameOverride = GetSelfForceNameOverride(playerEmpire.Civ, playerEmpire.Force, sameCountDict);
|
|
row.SetContent(playerEmpire.Civ, playerEmpire.Force, 1, maxTeamId, forceNameOverride, null, null, false, false);
|
|
}
|
|
|
|
private UIOutsideSelectAISettingRowMono GetAISettingRow(int index)
|
|
{
|
|
CacheExistingAISettingRows();
|
|
if (AISettingRowPrefab == null || AISettingGroup == null) return null;
|
|
while (_aiSettingRows.Count <= index)
|
|
{
|
|
var item = Instantiate(AISettingRowPrefab, AISettingGroup.transform);
|
|
item.SetActive(true);
|
|
_aiSettingRows.Add(item.GetComponent<UIOutsideSelectAISettingRowMono>());
|
|
}
|
|
|
|
return _aiSettingRows[index];
|
|
}
|
|
|
|
private void CacheExistingAISettingRows()
|
|
{
|
|
if (_aiSettingRowsCached || AISettingGroup == null) return;
|
|
_aiSettingRowsCached = true;
|
|
|
|
for (int i = 0; i < AISettingGroup.transform.childCount; i++)
|
|
{
|
|
var row = AISettingGroup.transform.GetChild(i).GetComponent<UIOutsideSelectAISettingRowMono>();
|
|
if (row != null && !_aiSettingRows.Contains(row)) _aiSettingRows.Add(row);
|
|
}
|
|
}
|
|
|
|
private void RefreshAISettingLayout()
|
|
{
|
|
if (AISettingGroup == null) return;
|
|
var groupRect = AISettingGroup.GetComponent<RectTransform>();
|
|
if (groupRect == null) return;
|
|
|
|
Canvas.ForceUpdateCanvases();
|
|
LayoutRebuilder.ForceRebuildLayoutImmediate(groupRect);
|
|
|
|
var parentRect = groupRect.parent as RectTransform;
|
|
if (parentRect != null) LayoutRebuilder.ForceRebuildLayoutImmediate(parentRect);
|
|
Canvas.ForceUpdateCanvases();
|
|
}
|
|
|
|
private Dictionary<(CivEnum, ForceEnum), int> BuildForceSameCountDict()
|
|
{
|
|
var sameCountDict = new Dictionary<(CivEnum, ForceEnum), int>();
|
|
if (!_playerEmpireIsRandom)
|
|
{
|
|
var playerEmpire = GetCurrentPlayerEmpire();
|
|
AddSameCount(playerEmpire.Civ, playerEmpire.Force);
|
|
}
|
|
foreach (var data in _aiSettings)
|
|
{
|
|
if (data.IsRandom) continue;
|
|
AddSameCount(Table.Instance.TransCivIdToCivEnum(data.CivId), Table.Instance.TransForceIdToForceEnum(data.ForceId));
|
|
}
|
|
|
|
return sameCountDict;
|
|
|
|
void AddSameCount(CivEnum civ, ForceEnum force)
|
|
{
|
|
if (civ == CivEnum.Common || force == ForceEnum.Common) return;
|
|
var key = (civ, force);
|
|
sameCountDict.TryGetValue(key, out var prevCnt);
|
|
sameCountDict[key] = prevCnt + 1;
|
|
}
|
|
}
|
|
|
|
private string GetForceNameOverride(AISettingData data, CivEnum civ, ForceEnum force, Dictionary<(CivEnum, ForceEnum), int> sameCountDict)
|
|
{
|
|
if (data != null && data.IsRandom) return null;
|
|
if (!sameCountDict.TryGetValue((civ, force), out var sameCnt) || sameCnt < 2) return null;
|
|
if (!Table.Instance.PlayerDataAssets.GetPlayerInfo(civ, force, out var pi)) return null;
|
|
var raw = MultilingualManager.Instance.GetMultilingualTextSafe(pi.ForceName);
|
|
return $"{raw} {data.SlotIndex + 1}P";
|
|
}
|
|
|
|
private string GetSelfForceNameOverride(CivEnum civ, ForceEnum force, Dictionary<(CivEnum, ForceEnum), int> sameCountDict)
|
|
{
|
|
if (!sameCountDict.TryGetValue((civ, force), out var sameCnt) || sameCnt < 2) return null;
|
|
if (!Table.Instance.PlayerDataAssets.GetPlayerInfo(civ, force, out var pi)) return null;
|
|
var raw = MultilingualManager.Instance.GetMultilingualTextSafe(pi.ForceName);
|
|
return $"{raw} 1P";
|
|
}
|
|
|
|
private void OnAIRowForceChanged(int slotIndex, int direction)
|
|
{
|
|
var data = GetAISettingData(slotIndex);
|
|
if (data == null) return;
|
|
|
|
var next = GetNextAIForce(data.CivId, data.ForceId, direction);
|
|
data.IsRandom = next.Civ == CivEnum.Common && next.Force == ForceEnum.Common;
|
|
if (data.IsRandom)
|
|
{
|
|
data.CivId = MapConfig.RandomCivId;
|
|
data.ForceId = MapConfig.RandomForceId;
|
|
}
|
|
else
|
|
{
|
|
data.CivId = Table.Instance.TransCivEnumToCivId(next.Civ);
|
|
data.ForceId = Table.Instance.TransForceEnumToForceId(next.Force);
|
|
}
|
|
data.IsForceUserEdited = true;
|
|
RefreshAISettingRows();
|
|
}
|
|
|
|
private void OnAIRowTeamChanged(int slotIndex, int direction)
|
|
{
|
|
var data = GetAISettingData(slotIndex);
|
|
if (data == null) return;
|
|
|
|
data.TeamId = GetNextTeamId(data.TeamId, direction);
|
|
data.IsTeamUserEdited = true;
|
|
RefreshAISettingRows();
|
|
}
|
|
|
|
private AISettingData GetAISettingData(int slotIndex)
|
|
{
|
|
for (int i = 0; i < _aiSettings.Count; i++)
|
|
if (_aiSettings[i].SlotIndex == slotIndex) return _aiSettings[i];
|
|
return null;
|
|
}
|
|
|
|
private int GetNextTeamId(int teamId, int direction)
|
|
{
|
|
int maxTeamId = Mathf.Max(1, (int)(PlayerCount.SelectedIndex + 2));
|
|
teamId += direction;
|
|
if (teamId < 1) return maxTeamId;
|
|
if (teamId > maxTeamId) return 1;
|
|
return teamId;
|
|
}
|
|
|
|
private (CivEnum Civ, ForceEnum Force) GetNextAIForce(uint civId, uint forceId, int direction)
|
|
{
|
|
var options = GetAIForceOptionsWithRandom();
|
|
var isRandom = MapConfig.IsRandomPlayerSlotCiv(civId, forceId, false);
|
|
var civ = isRandom ? CivEnum.Common : Table.Instance.TransCivIdToCivEnum(civId);
|
|
var force = isRandom ? ForceEnum.Common : Table.Instance.TransForceIdToForceEnum(forceId);
|
|
int index = 0;
|
|
for (int i = 0; i < options.Count; i++)
|
|
{
|
|
if (options[i].Civ == civ && options[i].Force == force)
|
|
{
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
index = (index + direction + options.Count) % options.Count;
|
|
return options[index];
|
|
}
|
|
|
|
private IReadOnlyList<(CivEnum Civ, ForceEnum Force)> GetAIForceOptionsWithRandom()
|
|
{
|
|
var options = new List<(CivEnum Civ, ForceEnum Force)> { (CivEnum.Common, ForceEnum.Common) };
|
|
options.AddRange(GetAIForceOptions());
|
|
return options;
|
|
}
|
|
|
|
private IReadOnlyList<(CivEnum Civ, ForceEnum Force)> GetAIForceOptions()
|
|
{
|
|
var assets = Table.Instance.PlayerDataAssets;
|
|
var options = new List<(CivEnum Civ, ForceEnum Force)>();
|
|
var optionSet = new HashSet<(CivEnum Civ, ForceEnum Force)>();
|
|
if (assets?.PlayerDataList != null)
|
|
{
|
|
foreach (var info in assets.PlayerDataList)
|
|
{
|
|
if (info == null) continue;
|
|
var civ = Table.Instance.TransCivIdToCivEnum(info.CivId);
|
|
var force = Table.Instance.TransForceIdToForceEnum(info.ForceId);
|
|
if (civ == CivEnum.Common || force == ForceEnum.Common) continue;
|
|
if (!ContentGate.CanUseEmpire(new Empire(civ, force))) continue;
|
|
if (!optionSet.Add((civ, force))) continue;
|
|
options.Add((civ, force));
|
|
}
|
|
}
|
|
|
|
if (options.Count > 0) return options;
|
|
|
|
foreach (var fallback in FallbackForceOptions)
|
|
{
|
|
if (ContentGate.CanUseEmpire(new Empire(fallback.Civ, fallback.Force))) options.Add(fallback);
|
|
}
|
|
|
|
if (options.Count == 0) options.Add((CivEnum.Egyptian, ForceEnum.Remilia));
|
|
return options;
|
|
}
|
|
|
|
private bool IsValidPlayerOption(uint civId, uint forceId)
|
|
{
|
|
var civ = Table.Instance.TransCivIdToCivEnum(civId);
|
|
var force = Table.Instance.TransForceIdToForceEnum(forceId);
|
|
if (civ == CivEnum.Common || force == ForceEnum.Common) return false;
|
|
if (!ContentGate.CanUseEmpire(new Empire(civ, force))) return false;
|
|
return Table.Instance.PlayerDataAssets.GetPlayerInfo(civ, force, out _);
|
|
}
|
|
|
|
private static int GetPreferredTeamId(AISettingData existingData, int slotIndex, int playerCount, bool preserveUserTeamEdits)
|
|
{
|
|
if (preserveUserTeamEdits && existingData != null && existingData.IsTeamUserEdited)
|
|
return GetValidTeamId(existingData.TeamId, slotIndex, playerCount);
|
|
return GetDefaultTeamId(slotIndex, playerCount);
|
|
}
|
|
|
|
private static int GetValidTeamId(int teamId, int slotIndex, int playerCount)
|
|
{
|
|
int maxTeamId = Mathf.Max(1, playerCount);
|
|
if (teamId >= 1 && teamId <= maxTeamId) return teamId;
|
|
return GetDefaultTeamId(slotIndex, playerCount);
|
|
}
|
|
|
|
private static int GetDefaultTeamId(int slotIndex, int playerCount)
|
|
{
|
|
return Mathf.Clamp(slotIndex + 1, 1, Mathf.Max(1, playerCount));
|
|
}
|
|
|
|
private void AddPlayerEmpireToUsedOptions(HashSet<(uint CivId, uint ForceId)> usedPlayerOptions)
|
|
{
|
|
if (_playerEmpireIsRandom) return;
|
|
|
|
var playerEmpire = GetCurrentPlayerEmpire();
|
|
if (playerEmpire.Civ != CivEnum.Common && playerEmpire.Force != ForceEnum.Common)
|
|
{
|
|
var civId = Table.Instance.TransCivEnumToCivId(playerEmpire.Civ);
|
|
var forceId = Table.Instance.TransForceEnumToForceId(playerEmpire.Force);
|
|
if (IsValidPlayerOption(civId, forceId))
|
|
{
|
|
usedPlayerOptions.Add((civId, forceId));
|
|
return;
|
|
}
|
|
}
|
|
|
|
var selfSlot = GetExistingPlayerSlot(0);
|
|
if (selfSlot != null && IsValidPlayerOption(selfSlot.CivId, selfSlot.ForceId))
|
|
{
|
|
usedPlayerOptions.Add((selfSlot.CivId, selfSlot.ForceId));
|
|
}
|
|
}
|
|
|
|
private Empire GetCurrentPlayerEmpire()
|
|
{
|
|
if (_playerEmpire.Civ != CivEnum.Common && _playerEmpire.Force != ForceEnum.Common
|
|
&& ContentGate.CanUseEmpire(_playerEmpire))
|
|
return _playerEmpire;
|
|
|
|
var selfSlot = GetExistingPlayerSlot(0);
|
|
if (selfSlot != null)
|
|
{
|
|
var civ = Table.Instance.TransCivIdToCivEnum(selfSlot.CivId);
|
|
var force = Table.Instance.TransForceIdToForceEnum(selfSlot.ForceId);
|
|
var empire = new Empire(civ, force);
|
|
if (civ != CivEnum.Common && force != ForceEnum.Common && ContentGate.CanUseEmpire(empire)) return empire;
|
|
}
|
|
|
|
var options = GetAIForceOptions();
|
|
var fallback = options[0];
|
|
return new Empire(fallback.Civ, fallback.Force);
|
|
}
|
|
|
|
private (uint CivId, uint ForceId) PickDefaultPlayerOption(int preferredIndex, HashSet<(uint CivId, uint ForceId)> usedPlayerOptions)
|
|
{
|
|
var options = GetAIForceOptions();
|
|
for (int offset = 0; offset < options.Count; offset++)
|
|
{
|
|
int index = (preferredIndex + offset) % options.Count;
|
|
var option = options[index];
|
|
var ids = (
|
|
Table.Instance.TransCivEnumToCivId(option.Civ),
|
|
Table.Instance.TransForceEnumToForceId(option.Force));
|
|
if (!usedPlayerOptions.Contains(ids)) return ids;
|
|
}
|
|
|
|
var fallback = options[preferredIndex % options.Count];
|
|
return (
|
|
Table.Instance.TransCivEnumToCivId(fallback.Civ),
|
|
Table.Instance.TransForceEnumToForceId(fallback.Force));
|
|
}
|
|
|
|
private static MemberCiv GetExistingPlayerSlot(int slotIndex)
|
|
{
|
|
var slots = Main.Instance.MapConfig?.MultiCivs;
|
|
if (slots == null || slotIndex < 0 || slotIndex >= slots.Count) return null;
|
|
return slots[slotIndex];
|
|
}
|
|
|
|
private void OnWinOptionClicked(uint idx)
|
|
{
|
|
}
|
|
|
|
private void OnTestModeChanged(bool isOn)
|
|
{
|
|
}
|
|
|
|
private static uint GetWinIndexByMatchConfigId(uint matchConfigId)
|
|
{
|
|
for (int i = 0; i < CreativeWinMatchConfigIds.Length; i++)
|
|
{
|
|
if (CreativeWinMatchConfigIds[i] == matchConfigId) return (uint)i;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
private static uint GetCreativeMatchConfigIdByWinIndex(uint idx)
|
|
{
|
|
return idx < CreativeWinMatchConfigIds.Length ? CreativeWinMatchConfigIds[(int)idx] : CreativeWinMatchConfigIds[0];
|
|
}
|
|
}
|