1105 lines
41 KiB
C#
1105 lines
41 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using Animancer;
|
||
using Logic;
|
||
using Logic.Action;
|
||
using Logic.Audio;
|
||
using Logic.CrashSight;
|
||
using Logic.Multilingual;
|
||
using Logic.Skill;
|
||
using RuntimeData;
|
||
using TH1_Core.Events;
|
||
using TH1_Core.Managers;
|
||
using TH1_Logic.Config;
|
||
using TH1_Logic.Core;
|
||
using TH1_Logic.MatchConfig;
|
||
using TH1_Presentation.Sequencer.Task;
|
||
using TH1_UI.Components;
|
||
using TH1_UI.HintUI;
|
||
using TH1Renderer;
|
||
using TH1Resource;
|
||
using TMPro;
|
||
using UI.HintUI;
|
||
using Unity.VisualScripting;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
namespace TH1_UI.View.Info
|
||
{
|
||
public class UIInfoGridInfoView : Base.View
|
||
{
|
||
public Button closeButton;
|
||
public ViDelegateAssisstant.Dele OnBtnCloseClick;
|
||
|
||
[Header("Color相关")]
|
||
public Image BGUnder;
|
||
public Image BGSurface;
|
||
public Image BG2Under;
|
||
public Image BG2Surface;
|
||
public Image AvatarTitleBG;
|
||
|
||
|
||
[Header("GridInfo相关")]
|
||
public GameObject GridInfoArea;
|
||
public GameObject GridPreview;
|
||
public GameObject GridCamera;
|
||
public TextMeshProUGUI GridInfoTitle;
|
||
public TextMeshProUGUI GridInfoDesc;
|
||
public TextMeshProUGUI GridInfoTerrainTxt;
|
||
public TextMeshProUGUI GridInfoResourceTxt;
|
||
public TextMeshProUGUI GridInfoBuildingTxt;
|
||
public HintTrigger GridInfoHint;
|
||
|
||
[Header("CityInfo相关")]
|
||
public GameObject CityInfoArea;
|
||
public GameObject CityPreview;
|
||
public GameObject CityCamera;
|
||
public GameObject CityInfoDataArea;
|
||
public TextMeshProUGUI CityInfoTitle;
|
||
public TextMeshProUGUI CityInfoDesc;
|
||
public TextMeshProUGUI CityInfoCoinTxt;
|
||
public TextMeshProUGUI CityInfoTechTxt;
|
||
public TextMeshProUGUI CityInfoCultureTxt;
|
||
public TextMeshProUGUI CityInfoDiamondTxt;
|
||
public TextMeshProUGUI CityInfoPopulationTxt;
|
||
public TextMeshProUGUI CityInfoConnectTxt;
|
||
|
||
[Header("UnitInfo相关")]
|
||
public GameObject UnitInfoArea;
|
||
public Image UnitPreview;
|
||
public Image HeroBG;
|
||
public GameObject SkillArea;
|
||
public TextMeshProUGUI UnitInfoTitle;
|
||
public TextMeshProUGUI UnitInfoDesc;
|
||
public TextMeshProUGUI UnitInfoAttackTxt;
|
||
public TextMeshProUGUI UnitInfoDefendTxt;
|
||
public TextMeshProUGUI UnitInfoHealthTxt;
|
||
public TextMeshProUGUI UnitInfoMoveTxt;
|
||
public TextMeshProUGUI UnitInfoRangeTxt;
|
||
public TextMeshProUGUI UnitInfoSightTxt;
|
||
public TextMeshProUGUI UnitInfoMobilityTxt;
|
||
public HintTrigger UnitInfoHint;
|
||
public GameObject UnitCity;
|
||
public Button UnitCityBtn;
|
||
public TextMeshProUGUI UnitCityText;
|
||
|
||
[Header("TaskInfo相关")]
|
||
public GameObject TaskArea;
|
||
public TextMeshProUGUI TaskDesc;
|
||
|
||
|
||
[Header("CommonInfo相关")]
|
||
public GameObject AvatarArea;
|
||
|
||
public GameObject AvatarHint;
|
||
public GameObject Avatar;
|
||
public GameObject AvatarTitleArea;
|
||
public TextMeshProUGUI AvatarTitle;
|
||
public Image AvatarImg;
|
||
public Button AvatarBtn;
|
||
|
||
|
||
|
||
|
||
public GameObject ActionArea;
|
||
public TextMeshProUGUI ActionHint;
|
||
public RectTransform VerticalGroup;
|
||
public GameObject ActionCirclePrefab;
|
||
public GameObject SkillCirclePrefab;
|
||
|
||
[Header("ActionPoint相关")]
|
||
public GameObject APBox;
|
||
public Transform APContainer;
|
||
public GameObject ActionPointPrefab;
|
||
|
||
private List<UIInfoCommonBaseActionCircleMono> ActionCircleMonoList = null;
|
||
private List<UIInfoCommonBaseSkillCircleMono> SkillCircleMonoList = null;
|
||
private List<UIInfoGridInfoActionPointMono> ActionPointMonoList = null;
|
||
private int _actionCount;
|
||
protected override void OnInit()
|
||
{
|
||
base.OnInit();
|
||
ActionCircleMonoList = new List<UIInfoCommonBaseActionCircleMono>();
|
||
SkillCircleMonoList = new List<UIInfoCommonBaseSkillCircleMono>();
|
||
ActionPointMonoList = new List<UIInfoGridInfoActionPointMono>();
|
||
ActionAreaInit();
|
||
SkillAreaInit();
|
||
APBoxInit();
|
||
BindUnitInfoItems();
|
||
closeButton.onClick.RemoveAllListeners();
|
||
closeButton.onClick.AddListener(() => { OnBtnCloseClick?.Invoke(); });
|
||
//CheckPanel.InitStart(RefreshStatus);
|
||
|
||
|
||
}
|
||
|
||
private void BindUnitInfoItems()
|
||
{
|
||
if (UnitInfoSightTxt != null || UnitInfoArea == null) return;
|
||
|
||
foreach (var child in UnitInfoArea.GetComponentsInChildren<Transform>(true))
|
||
{
|
||
if (child.name != "SightInfoItem") continue;
|
||
|
||
var itemInfo = child.GetComponent<UIInfoGridInfoItemInfoMono>();
|
||
if (itemInfo != null && itemInfo.ValueText != null)
|
||
{
|
||
UnitInfoSightTxt = itemInfo.ValueText;
|
||
return;
|
||
}
|
||
|
||
UnitInfoSightTxt = child.Find("ValueText")?.GetComponent<TextMeshProUGUI>();
|
||
return;
|
||
}
|
||
}
|
||
|
||
//清除所有actioncircle,重新开始生成
|
||
private void ActionAreaInit()
|
||
{
|
||
if (gameObject == null) return;
|
||
for (int i = ActionArea.transform.childCount - 1; i >= 0; i--)
|
||
{
|
||
Transform child = ActionArea.transform.GetChild(i);
|
||
// 判断组件是否存在
|
||
if (child.GetComponent<UIInfoCommonBaseActionCircleMono>() != null)
|
||
{
|
||
// 正确调用 Destroy 方法,销毁子对象的 GameObject
|
||
Destroy(child.gameObject);
|
||
}
|
||
}
|
||
|
||
ActionCircleMonoList.Clear();
|
||
ActionCircleMonoList = new List<UIInfoCommonBaseActionCircleMono>();
|
||
}
|
||
|
||
private void SkillAreaInit()
|
||
{
|
||
if (gameObject == null) return;
|
||
for (int i = SkillArea.transform.childCount - 1; i >= 0; i--)
|
||
{
|
||
Transform child = SkillArea.transform.GetChild(i);
|
||
// 判断组件是否存在
|
||
if (child.GetComponent<UIInfoCommonBaseSkillCircleMono>() != null)
|
||
{
|
||
// 正确调用 Destroy 方法,销毁子对象的 GameObject
|
||
Destroy(child.gameObject);
|
||
}
|
||
}
|
||
|
||
SkillCircleMonoList.Clear();
|
||
SkillCircleMonoList = new List<UIInfoCommonBaseSkillCircleMono>();
|
||
}
|
||
|
||
public void SetContent(ShowUIInfoGridInfo evt)
|
||
{
|
||
TryMarkCityBorderForSelection(evt);
|
||
SetContentAvatar(evt);
|
||
SetContentGrid(evt);
|
||
SetContentUnit(evt);
|
||
SetContentCity(evt);
|
||
SetContentSkill(evt);
|
||
SetContentAction(evt);
|
||
SetContentAPBox(evt);
|
||
SetContentTask(evt);
|
||
LayoutRebuilder.ForceRebuildLayoutImmediate(VerticalGroup);
|
||
}
|
||
|
||
// "始终显示选中地块所属城市边界"设置打开时,把宿主格所属城市的整片领土 mark 起来。
|
||
// 仅在选中地块 (GridInfo) 时生效;选中单位不触发——单位选中不应连带亮起城市边界。
|
||
// 关闭时不做事,仍由 SetContentCity 处理"点城市中心格才亮"的旧行为。
|
||
// CancelAllHighlight 已经在每次点击前清零全图 mark,所以这里只管置 true。
|
||
private void TryMarkCityBorderForSelection(ShowUIInfoGridInfo evt)
|
||
{
|
||
if (!ConfigManager.Instance.Config.AlwaysShowCityBorder) return;
|
||
|
||
if (evt.type != UIGridInfoType.grid) return;
|
||
|
||
if (!Main.MapData.GetCityDataByTerritoryGid(evt.id, out var city)) return;
|
||
|
||
foreach (var gid in city.Territory.TerritoryArea)
|
||
if (Main.MapData.GridMap.GetGridDataByGid(gid, out var gridData))
|
||
gridData.CityBorderRenderMark = true;
|
||
}
|
||
|
||
private void SetContentAvatar(ShowUIInfoGridInfo evt)
|
||
{
|
||
AvatarArea.SetActive(true);
|
||
|
||
PlayerData player = null;
|
||
switch (evt.type)
|
||
{
|
||
case UIGridInfoType.grid: // City is on a grid, so its ID is a GID
|
||
Main.MapData.GetPlayerDataByTerritoryGridId(evt.id, out player);
|
||
break;
|
||
case UIGridInfoType.unit:
|
||
Main.MapData.GetPlayerDataByUnitId(evt.id, out player);
|
||
break;
|
||
}
|
||
|
||
if (player == null || !Table.Instance.PlayerDataAssets.GetPlayerInfo(player, out var info))
|
||
{
|
||
AvatarTitleArea.SetActive(false);
|
||
AvatarHint.SetActive(false);
|
||
Avatar.SetActive(false);
|
||
|
||
//设置中立领土颜色
|
||
SetColor(Table.Instance.PlayerDataAssets.CommonColor);
|
||
return;
|
||
}
|
||
|
||
AvatarTitleArea.SetActive(true);
|
||
AvatarHint.SetActive(true);
|
||
Avatar.SetActive(true);
|
||
|
||
Table.Instance.PlayerDataAssets.GetPlayerInfo(player, out var playerInfo);
|
||
SetColor(playerInfo?.Color ?? Color.black);
|
||
|
||
if(!Main.MapData.PlayerMap.SelfPlayerData.MeetPlayers.Contains(player.Id))
|
||
{
|
||
AvatarBtn.onClick.RemoveAllListeners();
|
||
AvatarImg.sprite = Table.Instance.PlayerDataAssets.CommonPlayerAvatar;
|
||
AvatarTitle.text = "???";
|
||
LayoutRebuilder.ForceRebuildLayoutImmediate(AvatarTitleArea.GetComponent<RectTransform>());
|
||
return;
|
||
}
|
||
|
||
|
||
AvatarImg.sprite = info.LeaderAvatar;
|
||
|
||
// 如果当前显示的是unit且该unit被视为英雄,用英雄头像替换
|
||
if (evt.type == UIGridInfoType.unit
|
||
&& Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id, out var heroUnit)
|
||
&& heroUnit.TreatedAsHero(Main.MapData, null, out var heroGiantType)
|
||
&& heroGiantType != GiantType.None
|
||
&& Table.Instance.HeroDataAssets.GetHeroInfo(heroGiantType, out var heroInfoData)
|
||
&& heroInfoData.HeroAvatar != null)
|
||
{
|
||
AvatarImg.sprite = heroInfoData.HeroAvatar;
|
||
}
|
||
|
||
AvatarTitle.text = Logic.PlayerLogic.GetDisplayForceName(Main.MapData, player);
|
||
LayoutRebuilder.ForceRebuildLayoutImmediate(AvatarTitleArea.GetComponent<RectTransform>());
|
||
|
||
AvatarBtn.onClick.RemoveAllListeners();
|
||
AvatarBtn.onClick.AddListener(() =>
|
||
{
|
||
EventManager.Publish(new ShowUIInfoDiplomacy() { Pid = player.Id });
|
||
//因为gridinfo和diplomacyinfo 同属infoUI,打开diploInfo会自动关闭gridinfo,这里如果再主动关闭自身,会重复关闭导致错误
|
||
//OnBtnCloseClick?.Invoke();
|
||
});
|
||
}
|
||
|
||
private void SetColor(Color color)
|
||
{
|
||
var colorUnder = color;
|
||
colorUnder.a = 0.4f;
|
||
BGUnder.color = colorUnder;
|
||
BGSurface.color = color;
|
||
BG2Under.color = colorUnder;
|
||
BG2Surface.color = color;
|
||
AvatarTitleBG.color = color;
|
||
|
||
}
|
||
|
||
private void SetContentGrid(ShowUIInfoGridInfo evt)
|
||
{
|
||
if (evt.type != UIGridInfoType.grid || !Main.MapData.GridMap.GetGridDataByGid(evt.id, out var grid) || Main.MapData.GetCityDataByGid(evt.id, out var _))
|
||
{
|
||
GridInfoArea.SetActive(false);
|
||
return;
|
||
}
|
||
GridInfoArea.SetActive(true);
|
||
|
||
|
||
//Step #1 GridPreview
|
||
|
||
GameObject clone =
|
||
Instantiate(MapRenderer.Instance.ROGridMap[evt.id].GetROGrid() as GameObject);
|
||
for (int i = GridPreview.transform.childCount - 1; i >= 0; i--)
|
||
Destroy(GridPreview.transform.GetChild(i).gameObject);
|
||
clone.transform.SetParent(GridPreview.transform);
|
||
clone.transform.localPosition = new Vector3(0,15,0);
|
||
clone.transform.Find("SelectHighlight").gameObject.SetActive(false);
|
||
SetLayerRecursively(clone, LayerMask.NameToLayer("Preview"));
|
||
GridCamera.SetActive(true);
|
||
Timer.Instance.TimerRegister(GridCamera, () => { GridCamera.SetActive(false); }, 0.001f,"HideCamera");
|
||
|
||
|
||
//Step #2 Title & Desc
|
||
//title 逻辑 -> building > resource > forest > mountain > plain
|
||
string title_DECODE = "";
|
||
string desc_DECODE = "";
|
||
|
||
|
||
Empire empire = new Empire(grid.CivEnum,grid.Player(Main.MapData)?.ForceEnum??ForceEnum.Common);
|
||
var spType = grid.GetTopGridSpType();
|
||
//如果是奇观
|
||
if (grid.Resource == ResourceType.Wonder)
|
||
{
|
||
// Name / Desc 走 LibraryDataAssets(图鉴文案),其他奇观信息仍由 WonderInfo 提供
|
||
if (Table.Instance.LibraryDataAssets.GetLibraryInfoByWonder(grid.Wonder, out var libraryData))
|
||
{
|
||
title_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(libraryData.Name);
|
||
desc_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(libraryData.Desc);
|
||
}
|
||
}
|
||
//如果显示建筑或者资源
|
||
else if (grid.Resource != ResourceType.None && Main.MapData.PlayerMap.SelfPlayerData.CanShowResource(grid.Resource))
|
||
{
|
||
title_DECODE = Table.Instance.GridAndResourceDataAssets.GetResourceNameWithLevel_DECODE(grid,empire,spType);
|
||
//var spr = Table.Instance.GridAndResourceDataAssets.GetResourceSprite(grid.Resource, grid.Player(Main.MapData), grid);
|
||
Table.Instance.GridAndResourceDataAssets.GetResourceInfo(grid.Resource, out var resourceInfo);
|
||
desc_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(resourceInfo.GetResourceDesc(empire,spType));
|
||
}
|
||
//如果显示树木
|
||
else if(grid.Vegetation == Vegetation.Trees)
|
||
{
|
||
Table.Instance.GridAndResourceDataAssets.GetVegetationInfo(out var vegetationInfo);
|
||
title_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(vegetationInfo.GetResourceName(empire,spType));
|
||
desc_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(vegetationInfo.GetResourceDesc(empire,spType));
|
||
}
|
||
//如果显示山脉
|
||
else if(grid.Feature == TerrainFeature.Mountain)
|
||
{
|
||
Table.Instance.GridAndResourceDataAssets.GetMountainInfo(out var mountainInfo);
|
||
title_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(mountainInfo.ResourceName);
|
||
desc_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(mountainInfo.ResourceDesc);
|
||
}
|
||
//如果显示地形
|
||
else
|
||
{
|
||
Table.Instance.GridAndResourceDataAssets.GetTerrainInfo(grid.Terrain, out var terrainInfo);
|
||
title_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(terrainInfo.ResourceName);
|
||
desc_DECODE = MultilingualManager.Instance.GetMultilingualTextSafe(terrainInfo.ResourceDesc);
|
||
}
|
||
GridInfoTitle.text = title_DECODE;
|
||
GridInfoDesc.text = desc_DECODE;
|
||
|
||
//Step #3 设置详细info
|
||
//resource / building
|
||
if (grid.Resource != ResourceType.None && Table.Instance.GridAndResourceDataAssets.GetResourceInfo(grid.Resource, out var resourceInfo2))
|
||
{
|
||
if (resourceInfo2.ResourceSubType == ResourceSubType.Building)
|
||
{
|
||
GridInfoBuildingTxt.text = Table.Instance.GridAndResourceDataAssets.GetResourceNameWithLevel_DECODE(grid,empire,spType);
|
||
//处理盖在建筑下面的资源
|
||
if (grid.ResourceUnderBuilding != ResourceType.None &&
|
||
Table.Instance.GridAndResourceDataAssets.GetResourceInfo(grid.ResourceUnderBuilding,
|
||
out var resourceInfo3) && resourceInfo3.ResourceSubType == ResourceSubType.Resource)
|
||
MultilingualManager.Instance.SetUIText(GridInfoResourceTxt,
|
||
Table.Instance.GridAndResourceDataAssets.GetResourceName(grid.ResourceUnderBuilding,empire,spType));
|
||
else GridInfoResourceTxt.text = "-";
|
||
}
|
||
else
|
||
{
|
||
GridInfoBuildingTxt.text = "-";
|
||
if(Main.MapData.PlayerMap.SelfPlayerData.CanShowResource(grid.Resource))
|
||
MultilingualManager.Instance.SetUIText(GridInfoResourceTxt, Table.Instance.GridAndResourceDataAssets.GetResourceName(grid.Resource,empire,spType));
|
||
else GridInfoResourceTxt.text = "-";
|
||
}
|
||
}
|
||
else
|
||
{
|
||
GridInfoBuildingTxt.text = "-";
|
||
GridInfoResourceTxt.text = "-";
|
||
}
|
||
//terrain
|
||
if (grid.Feature == TerrainFeature.Mountain)
|
||
{
|
||
Table.Instance.GridAndResourceDataAssets.GetMountainInfo(out var mountainInfo);
|
||
MultilingualManager.Instance.SetUIText(GridInfoTerrainTxt, mountainInfo.ResourceName);
|
||
}
|
||
else if (grid.Vegetation == Vegetation.Trees)
|
||
{
|
||
Table.Instance.GridAndResourceDataAssets.GetVegetationInfo(out var vegetationInfo);
|
||
MultilingualManager.Instance.SetUIText(GridInfoTerrainTxt, vegetationInfo.ResourceName);
|
||
}
|
||
else
|
||
{
|
||
Table.Instance.GridAndResourceDataAssets.GetTerrainInfo(grid.Terrain,out var terrainInfo);
|
||
MultilingualManager.Instance.SetUIText(GridInfoTerrainTxt, terrainInfo.ResourceName);
|
||
}
|
||
|
||
//处理GeoHintInfo
|
||
//TODO 不能在这里修改mapData,这是错误的, 必须要调用action 来修改mapData
|
||
grid.UpdateGeoInfo(Main.MapData);
|
||
if (grid.GeoIdList?.Count > 0)
|
||
{
|
||
GridInfoHint.gameObject.SetActive(true);
|
||
GridInfoHint.DataProvider.HintDataType = HintDataType.GeoData;
|
||
|
||
|
||
|
||
GridInfoHint.DataProvider.GeoIdList = grid.GetRealTimeGeoIdList();
|
||
}
|
||
else
|
||
{
|
||
GridInfoHint.gameObject.SetActive(false);
|
||
}
|
||
|
||
}
|
||
|
||
private void SetContentUnit(ShowUIInfoGridInfo evt)
|
||
{
|
||
if (evt.type != UIGridInfoType.unit || !Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id, out var unitData))
|
||
{
|
||
UnitInfoArea.SetActive(false);
|
||
if (HeroBG != null) HeroBG.gameObject.SetActive(false);
|
||
return;
|
||
}
|
||
UnitInfoArea.SetActive(true);
|
||
// 获取关联数据
|
||
Main.MapData.GetPlayerDataByUnitId(unitData.Id, out var playerData);
|
||
Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitData.UnitFullType, out var unitTypeInfo);
|
||
|
||
// GiantJuggernaut 是 Giant 上船形态,真实英雄信息在 CarryUnitFullType
|
||
var heroFullType = unitData.UnitFullType.UnitType == UnitType.GiantJuggernaut
|
||
? unitData.CarryUnitFullType
|
||
: unitData.UnitFullType;
|
||
|
||
// Step #1: Unit Preview
|
||
if (Table.Instance.UnitTypeDataAssets.GetUnitSprite(Main.MapData, unitData, out var spr))
|
||
UnitPreview.sprite = spr;
|
||
|
||
// HeroBG: Giant单位且在Library中有Illustration时显示
|
||
if (HeroBG != null)
|
||
{
|
||
LibraryGiantData libData = null;
|
||
bool showHeroBG = unitData.UnitType is UnitType.Giant or UnitType.GiantJuggernaut
|
||
&& heroFullType.GiantType != GiantType.None
|
||
&& Table.Instance.LibraryDataAssets.GetLibraryInfoByGiant(heroFullType.GiantType, out libData)
|
||
&& libData.Illust != null;
|
||
HeroBG.gameObject.SetActive(showHeroBG);
|
||
if (showHeroBG)
|
||
HeroBG.sprite = libData.Illust;
|
||
}
|
||
|
||
// Step #2: Title & Description
|
||
// 逻辑参考 BottomInfoUI.cs -> UpdateInfoUnit
|
||
string title = MultilingualManager.Instance.GetMultilingualTextSafe(unitTypeInfo.Name);
|
||
|
||
//处理Officer的情况
|
||
if (unitData.IsOfficer()) title += "("+ MultilingualManager.Instance.GetMultilingualText(Table.Instance.TextDataAssets.UnitOfficerName)+")"; // 示例
|
||
else if (unitData.IsPrepareOfficer()) title += $"({unitData.GetKillCount()}/3)";
|
||
|
||
UnitInfoTitle.text = title;
|
||
MultilingualManager.Instance.SetUIText(UnitInfoDesc, unitTypeInfo.Desc);
|
||
// Step #3: Core Stats
|
||
UnitInfoHealthTxt.text = $"{unitData.Health}/{unitData.GetMaxHealth()}";
|
||
UnitInfoAttackTxt.text = unitData.GetAttackShowString(Main.MapData);
|
||
UnitInfoDefendTxt.text = unitData.GetDefenseShowString(Main.MapData);
|
||
UnitInfoMoveTxt.text = unitData.GetMoveRangeShowString(Main.MapData);
|
||
UnitInfoRangeTxt.text = unitData.GetAttackRangeShowString(Main.MapData);
|
||
if (UnitInfoSightTxt != null) UnitInfoSightTxt.text = unitData.GetSightRange(Main.MapData).ToString();
|
||
UnitInfoMobilityTxt.text = Table.Instance.MobilityDataAssets.GetLandTypeText_DECODE(unitTypeInfo.LandType);
|
||
|
||
//Step #4 处理Giant Hint
|
||
bool isgiant = unitData.UnitFullType.UnitType is UnitType.Giant or UnitType.GiantJuggernaut;
|
||
UnitInfoHint.gameObject.SetActive(isgiant);
|
||
if (isgiant)
|
||
{
|
||
UnitInfoHint.DataProvider.HintDataType = HintDataType.TextDataGiantUpgrate;
|
||
UnitInfoHint.DataProvider.UnitFullType = heroFullType;
|
||
}
|
||
|
||
//Step #5 处理UnitCity - 仅我方单位显示所属城市
|
||
var selfPlayer = Main.MapData.PlayerMap.SelfPlayerData;
|
||
bool showCity = playerData != null && playerData.Id == selfPlayer.Id;
|
||
CityData unitCity = null;
|
||
if (showCity)
|
||
{
|
||
unitCity = unitData.City(Main.MapData);
|
||
showCity = unitCity != null;
|
||
}
|
||
|
||
// 处理UnitCity显示/隐藏
|
||
if (UnitCity != null)
|
||
{
|
||
UnitCity.SetActive(showCity);
|
||
|
||
if (showCity && UnitCityText != null && unitCity != null)
|
||
{
|
||
UnitCityText.gameObject.SetActive(true);
|
||
if (Table.Instance.CivDataAssets.GetCityInfo(unitCity.Name, out var cityInfo))
|
||
{
|
||
UnitCityText.text = MultilingualManager.Instance.GetMultilingualTextSafe(cityInfo.CityName);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理按钮点击
|
||
if (UnitCityBtn != null)
|
||
{
|
||
UnitCityBtn.onClick.RemoveAllListeners();
|
||
if (showCity && unitCity != null)
|
||
{
|
||
// 使用局部变量捕获避免闭包问题
|
||
var capturedCity = unitCity;
|
||
UnitCityBtn.onClick.AddListener(() =>
|
||
{
|
||
var grid = capturedCity.Grid(Main.MapData);
|
||
if (grid != null)
|
||
{
|
||
// 先关闭当前面板,再显示新内容
|
||
OnBtnCloseClick?.Invoke();
|
||
|
||
EventManager.Publish(new ShowUIInfoGridInfo()
|
||
{
|
||
type = UIGridInfoType.grid,
|
||
id = grid.Id
|
||
});
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
private void SetContentCity(ShowUIInfoGridInfo evt)
|
||
{
|
||
if (evt.type != UIGridInfoType.grid || !Main.MapData.GetCityDataByGid(evt.id,out var city)
|
||
|| !Main.MapData.GetPlayerDataByCityId(city.Id, out var player))
|
||
{
|
||
CityInfoArea.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
|
||
//TODO 这里临时去现实city的border
|
||
foreach (var gid in city.Territory.TerritoryArea)
|
||
if(Main.MapData.GridMap.GetGridDataByGid(gid,out var gridData))
|
||
gridData.CityBorderRenderMark = true;
|
||
|
||
|
||
|
||
CityInfoArea.SetActive(true);
|
||
|
||
// Step 1: Preview (Placeholder)
|
||
GameObject clone =
|
||
Instantiate(MapRenderer.Instance.ROGridMap[evt.id].GetROGrid() as GameObject);
|
||
for (int i = CityPreview.transform.childCount - 1; i >= 0; i--)
|
||
Destroy(CityPreview.transform.GetChild(i).gameObject);
|
||
clone.transform.SetParent(CityPreview.transform);
|
||
clone.transform.localPosition = new Vector3(0,15,0);
|
||
clone.transform.Find("SelectHighlight").gameObject.SetActive(false);
|
||
SetLayerRecursively(clone, LayerMask.NameToLayer("Preview"));
|
||
CityCamera.SetActive(true);
|
||
Timer.Instance.TimerRegister(CityCamera, () => { CityCamera.SetActive(false); }, 0.001f,"HideCamera");
|
||
|
||
// Step 2: Title & Description
|
||
Table.Instance.CivDataAssets.GetCityInfo(city.Name, out var cityInfo);
|
||
CityInfoTitle.text = MultilingualManager.Instance.GetMultilingualTextSafe(cityInfo.CityName) + " Lv." + city.Level;
|
||
MultilingualManager.Instance.SetUIText(CityInfoDesc, cityInfo.CityDescription);
|
||
|
||
// Step 3: Detailed Info (differs for self vs. others)
|
||
if (player.Id == Main.MapData.PlayerMap.SelfPlayerData.Id)
|
||
{
|
||
CityInfoDataArea.SetActive(true);
|
||
var tb = Table.Instance.TextDataAssets;
|
||
//被敌方单位站住的城市本回合不产出,UI显示0
|
||
var heldByEnemy = Main.CityLogic.IsCityHeldByEnemyUnit(Main.MapData, city);
|
||
var coinPerTurn = heldByEnemy ? 0 : Main.CityLogic.GetCityCoinPerTurn(Main.MapData, city);
|
||
var techPerTurn = heldByEnemy ? 0 : Main.CityLogic.GetCityTechPointPerTurn(Main.MapData, city);
|
||
CityInfoCoinTxt.text = "+" + coinPerTurn + MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_PerTurn);
|
||
CityInfoTechTxt.text = "+" + techPerTurn + MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_PerTurn);
|
||
//var culturePerTurn = Main.CityLogic.GetCityCulturePointPerTurn(Main.MapData, city);
|
||
//CityInfoCultureTxt.text = "+" + culturePerTurn + MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_PerTurn);
|
||
//CityInfoCultureTxt.gameObject.SetActive(culturePerTurn > 0);
|
||
CityInfoPopulationTxt.text = MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_Population) + Main.MapData.GetUnitCount(city.Id) + "/" + city.Level;
|
||
CityInfoDiamondTxt.text = city.ParkCount + MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_Diamond);
|
||
CityInfoConnectTxt.text = city.IsCapital ? MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_Capital) : (city.IsConnectedCapital ? MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_Connected) :
|
||
MultilingualManager.Instance.GetMultilingualTextSafe(tb.GridInfoText_Unconnected));
|
||
}
|
||
else
|
||
CityInfoDataArea.SetActive(false);
|
||
|
||
|
||
|
||
}
|
||
|
||
private void SetContentSkill(ShowUIInfoGridInfo evt)
|
||
{
|
||
if (evt.type == UIGridInfoType.grid)
|
||
{
|
||
SetContentGridStatusSkill(evt);
|
||
return;
|
||
}
|
||
|
||
if (evt.type != UIGridInfoType.unit)
|
||
{
|
||
SkillArea.SetActive(false);
|
||
return;
|
||
}
|
||
if (!Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id, out var unit)) return;
|
||
|
||
var skillList = new List<SkillBase>();
|
||
foreach (var skill in unit.Skills)
|
||
{
|
||
var skillType = skill.GetSkillType();
|
||
if(!Table.Instance.SkillDataAssets.GetSkillInfo(skillType, out var info)
|
||
|| !SkillDataAssets.ShouldShowInUnitSkillList(skillType, info) || !skill.ShowSkill)continue;
|
||
skillList.Add(skill);
|
||
}
|
||
|
||
if (skillList.Count == 0)
|
||
{
|
||
SkillArea.SetActive(false);
|
||
return;
|
||
}
|
||
SkillArea.SetActive(true);
|
||
|
||
|
||
//Step #2 确定格位够不够
|
||
while (SkillCircleMonoList.Count < skillList.Count)
|
||
{
|
||
GameObject actionCircle = Instantiate(SkillCirclePrefab, SkillArea.transform, true);
|
||
actionCircle.GetComponent<RectTransform>().localScale = Vector3.one;
|
||
actionCircle.GetComponent<RectTransform>().localPosition = Vector3.zero;
|
||
SkillCircleMonoList.Add(actionCircle.GetComponent<UIInfoCommonBaseSkillCircleMono>());
|
||
}
|
||
//Step #3 skill分类sort序列
|
||
var skillSort = new List<int>();
|
||
var skillViewType = new List<SkillViewType>();
|
||
foreach (var t in skillList)
|
||
{
|
||
Table.Instance.SkillDataAssets.GetSkillInfo(t.GetSkillType(), out var info);
|
||
var viewType = info?.SkillViewType ?? SkillViewType.Normal;
|
||
if (t.HasTimeLimit && viewType != SkillViewType.Positive && viewType != SkillViewType.Negative)
|
||
viewType = SkillViewType.Positive;
|
||
skillViewType.Add(viewType);
|
||
}
|
||
for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Normal)skillSort.Add(i);
|
||
for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Special)skillSort.Add(i);
|
||
for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Unique)skillSort.Add(i);
|
||
for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Positive)skillSort.Add(i);
|
||
for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Negative)skillSort.Add(i);
|
||
|
||
|
||
//Step #3 设置每一个action
|
||
//bool unitIsBanned = unit.IsFrozen();
|
||
for (int i = 0; i < SkillCircleMonoList.Count; i++)
|
||
if (i < skillSort.Count && skillSort[i] < skillList.Count)
|
||
{
|
||
var skill = skillList[skillSort[i]];
|
||
bool isBanned = skill.IsFrozen(unit);
|
||
SkillCircleMonoList[i].gameObject.SetActive(true);
|
||
SkillCircleMonoList[i].SetContent(skill,unit.UnitFullType,isBanned);
|
||
}
|
||
else
|
||
SkillCircleMonoList[i].gameObject.SetActive(false);
|
||
|
||
|
||
}
|
||
|
||
private void SetContentGridStatusSkill(ShowUIInfoGridInfo evt)
|
||
{
|
||
if (!Main.MapData.GridMap.GetGridDataByGid(evt.id, out var grid))
|
||
{
|
||
SkillArea.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
var skillList = new List<SkillBase>();
|
||
if (Main.MapData.GetCityDataByGid(evt.id, out var city))
|
||
AddVisibleGridInfoSkills(city.Skills, skillList);
|
||
else
|
||
AddVisibleGridInfoSkills(grid.Skills, skillList);
|
||
|
||
var virtualIconList = new List<Sprite>();
|
||
var virtualHintList = new List<string>();
|
||
AddVisibleGridSpStatus(grid, virtualIconList, virtualHintList);
|
||
|
||
var count = skillList.Count + virtualIconList.Count;
|
||
if (count == 0)
|
||
{
|
||
SkillArea.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
SkillArea.SetActive(true);
|
||
while (SkillCircleMonoList.Count < count)
|
||
{
|
||
GameObject actionCircle = Instantiate(SkillCirclePrefab, SkillArea.transform, true);
|
||
actionCircle.GetComponent<RectTransform>().localScale = Vector3.one;
|
||
actionCircle.GetComponent<RectTransform>().localPosition = Vector3.zero;
|
||
SkillCircleMonoList.Add(actionCircle.GetComponent<UIInfoCommonBaseSkillCircleMono>());
|
||
}
|
||
|
||
var skillSort = new List<int>();
|
||
var skillViewType = new List<SkillViewType>();
|
||
foreach (var skill in skillList)
|
||
{
|
||
Table.Instance.SkillDataAssets.GetSkillInfo(skill.GetSkillType(), out var info);
|
||
var viewType = info?.SkillViewType ?? SkillViewType.Normal;
|
||
if (skill.HasTimeLimit && viewType != SkillViewType.Positive && viewType != SkillViewType.Negative)
|
||
viewType = SkillViewType.Positive;
|
||
skillViewType.Add(viewType);
|
||
}
|
||
for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Normal)skillSort.Add(i);
|
||
for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Special)skillSort.Add(i);
|
||
for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Unique)skillSort.Add(i);
|
||
for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Positive)skillSort.Add(i);
|
||
for(int i = 0;i < skillList.Count; i++)if(skillViewType.Count > i && skillViewType[i] == SkillViewType.Negative)skillSort.Add(i);
|
||
|
||
var itemIndex = 0;
|
||
for (int i = 0; i < skillSort.Count; i++)
|
||
{
|
||
var skill = skillList[skillSort[i]];
|
||
SkillCircleMonoList[itemIndex].gameObject.SetActive(true);
|
||
SkillCircleMonoList[itemIndex].SetContent(skill, new UnitFullType());
|
||
itemIndex++;
|
||
}
|
||
|
||
var virtualBGColor = Table.Instance.SkillDataAssets.GetBGColor(SkillViewType.Special, false);
|
||
for (int i = 0; i < virtualIconList.Count; i++)
|
||
{
|
||
SkillCircleMonoList[itemIndex].gameObject.SetActive(true);
|
||
SkillCircleMonoList[itemIndex].SetStatusContent(virtualIconList[i], virtualBGColor, virtualHintList[i]);
|
||
itemIndex++;
|
||
}
|
||
|
||
for (int i = itemIndex; i < SkillCircleMonoList.Count; i++)
|
||
SkillCircleMonoList[i].gameObject.SetActive(false);
|
||
}
|
||
|
||
private void AddVisibleGridInfoSkills(List<SkillBase> source, List<SkillBase> target)
|
||
{
|
||
foreach (var skill in source)
|
||
{
|
||
var skillType = skill.GetSkillType();
|
||
if(!Table.Instance.SkillDataAssets.GetSkillInfo(skillType, out var info)
|
||
|| info.NotShow || !skill.ShowSkill)continue;
|
||
if (!HasCompleteGridInfoSkillDisplayData(skillType, skill)) continue;
|
||
target.Add(skill);
|
||
}
|
||
}
|
||
|
||
private bool HasCompleteGridInfoSkillDisplayData(SkillType skillType, SkillBase skill)
|
||
{
|
||
var unitFullType = new UnitFullType();
|
||
if (!Table.Instance.SkillDataAssets.GetSkillIcon(skillType, unitFullType, out var icon) || icon == null) return false;
|
||
if (!Table.Instance.SkillDataAssets.GetSkillNameAndDesc_DECODE(skillType, unitFullType, skill, out var name, out var desc)) return false;
|
||
return !string.IsNullOrWhiteSpace(name) && !string.IsNullOrWhiteSpace(desc);
|
||
}
|
||
|
||
private void AddVisibleGridSpStatus(GridData grid, List<Sprite> iconList, List<string> hintList)
|
||
{
|
||
if (grid.SpTypeList == null || grid.SpTypeList.Count == 0) return;
|
||
|
||
var player = grid.Player(Main.MapData);
|
||
var empire = player?.Empire ?? new Empire(grid.CivEnum, ForceEnum.Common);
|
||
var addedTypes = new HashSet<GridSpType>();
|
||
foreach (var spType in grid.SpTypeList)
|
||
{
|
||
if (spType == GridSpType.None || spType == GridSpType.Max || !addedTypes.Add(spType)) continue;
|
||
if (spType == GridSpType.KasenBeastGuide && grid.GetSkill(SkillType.KasenBeastGuideGrid, out _)) continue;
|
||
if (!Table.Instance.GridAndResourceDataAssets.GetGridSpDisplayInfo(empire, spType, out var icon, out var nameRaw, out var descRaw)) continue;
|
||
if (icon == null || string.IsNullOrWhiteSpace(nameRaw) || string.IsNullOrWhiteSpace(descRaw)) continue;
|
||
|
||
var name = MultilingualManager.Instance.GetMultilingualTextSafe(nameRaw);
|
||
var desc = MultilingualManager.Instance.GetMultilingualTextSafe(descRaw);
|
||
iconList.Add(icon);
|
||
hintList.Add($"<color=orange>{name}</color><br>{desc}");
|
||
}
|
||
}
|
||
|
||
private void SetContentAction(ShowUIInfoGridInfo evt)
|
||
{
|
||
//观战模式:非自己回合时不显示Action区域
|
||
if (Main.MapData.CurPlayer != Main.MapData.PlayerMap.SelfPlayerData)
|
||
{
|
||
ActionArea.SetActive(false);
|
||
_actionCount = 0;
|
||
return;
|
||
}
|
||
|
||
//Step #1 获取actionList
|
||
//ResourceCache.Instance.SpriteCache.ActionBGAvailable
|
||
var actionList = new List<ActionLogicBase>();
|
||
var cantTypeList = new List<ShowType>();
|
||
bool showAction = false;
|
||
var subType = evt.type;
|
||
CommonActionParams param = null;
|
||
if (subType == UIGridInfoType.unit && Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id,out var unit))
|
||
{
|
||
param = new CommonActionParams(mapData:Main.MapData,playerData:Main.MapData.PlayerMap.SelfPlayerData,unitData:unit,mainObjectType:MainObjectType.Unit);
|
||
showAction = ActionLogicFactory.MainObjectCanShowAction(param, out actionList,out cantTypeList);
|
||
MultilingualManager.Instance.SetUIText(ActionHint,Table.Instance.TextDataAssets.GridInfoText_UnitInfoHint);
|
||
|
||
}
|
||
else if (subType == UIGridInfoType.grid && Main.MapData.GetCityDataByGid(evt.id,out var city))
|
||
{
|
||
param = new CommonActionParams(mapData:Main.MapData,playerData:Main.MapData.PlayerMap.SelfPlayerData,cityData:city,mainObjectType:MainObjectType.City);
|
||
showAction = ActionLogicFactory.MainObjectCanShowAction(param,out actionList,out cantTypeList);
|
||
MultilingualManager.Instance.SetUIText(ActionHint,Table.Instance.TextDataAssets.GridInfoText_CityInfoHint);
|
||
|
||
// Tutor 模式 + PlayerCannotTrainUnit 限制:禁止 City 的所有 Action(生产单位/升级城市等)
|
||
if (Main.MapData.MatchSettlement.SettlementType == MatchSettlementType.Tutor
|
||
&& Main.MapData.MapConfig.MatchLimits != null
|
||
&& Main.MapData.MapConfig.MatchLimits.Contains(MatchLimitType.PlayerCannotTrainUnit))
|
||
{
|
||
actionList.Clear();
|
||
cantTypeList.Clear();
|
||
showAction = false;
|
||
}
|
||
}
|
||
else if (subType == UIGridInfoType.grid && Main.MapData.GridMap.GetGridDataByGid(evt.id,out var grid))
|
||
{
|
||
param = new CommonActionParams(mapData:Main.MapData,Main.MapData.PlayerMap.SelfPlayerData,gridData:grid,mainObjectType:MainObjectType.Grid);
|
||
showAction = ActionLogicFactory.MainObjectCanShowAction(param,out actionList,out cantTypeList);
|
||
if(grid.Resource is ResourceType.Military or ResourceType.RemiliaMilitary)
|
||
MultilingualManager.Instance.SetUIText(ActionHint,Table.Instance.TextDataAssets.GridInfoText_CityInfoHint);
|
||
MultilingualManager.Instance.SetUIText(ActionHint,Table.Instance.TextDataAssets.GridInfoText_GridInfoHint);
|
||
}
|
||
|
||
if (!showAction)
|
||
{
|
||
// 我方Unit即使没有Action也保留ActionArea(用于显示APBox),但隐藏标题
|
||
bool isSelfUnit = subType == UIGridInfoType.unit
|
||
&& Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id, out var selfCheckUnit)
|
||
&& Main.MapData.GetPlayerDataByUnitId(evt.id, out var selfCheckPlayer)
|
||
&& selfCheckPlayer.Id == Main.MapData.PlayerMap.SelfPlayerData.Id;
|
||
if (isSelfUnit)
|
||
{
|
||
ActionArea.SetActive(true);
|
||
ActionHint.gameObject.SetActive(false);
|
||
// 隐藏所有ActionCircle
|
||
for (int i = 0; i < ActionCircleMonoList.Count; i++)
|
||
ActionCircleMonoList[i].gameObject.SetActive(false);
|
||
_actionCount = 0;
|
||
return;
|
||
}
|
||
|
||
ActionArea.SetActive(false);
|
||
//_actionCount必须设置为0,因为其他地方会用到
|
||
_actionCount = 0;
|
||
return;
|
||
}
|
||
ActionArea.SetActive(true);
|
||
ActionHint.gameObject.SetActive(true);
|
||
//Step #2 确定格位够不够
|
||
while (ActionCircleMonoList.Count < actionList.Count)
|
||
{
|
||
GameObject actionCircle = Instantiate(ActionCirclePrefab, ActionArea.transform, true);
|
||
actionCircle.GetComponent<RectTransform>().localScale = Vector3.one;
|
||
actionCircle.GetComponent<RectTransform>().localPosition = Vector3.zero;
|
||
ActionCircleMonoList.Add(actionCircle.GetComponent<UIInfoCommonBaseActionCircleMono>());
|
||
}
|
||
|
||
//Step #2.5 过滤掉未在ActionData中配置的action
|
||
for (int i = actionList.Count - 1; i >= 0; i--)
|
||
{
|
||
if (!Table.Instance.ActionDataAssets.GetActionInfo(actionList[i].ActionId, out _))
|
||
{
|
||
actionList.RemoveAt(i);
|
||
cantTypeList.RemoveAt(i);
|
||
}
|
||
}
|
||
_actionCount = actionList.Count;
|
||
|
||
//Step #3 设置每一个action
|
||
for (int i = 0; i < ActionCircleMonoList.Count; i++)
|
||
{
|
||
ActionCircleMonoList[i].gameObject.SetActive(i < actionList.Count);
|
||
if (i >= actionList.Count) continue;
|
||
ActionCircleMonoList[i].SetContent(actionList[i].ActionId,cantTypeList[i],param,OnActionCircleClicked);
|
||
}
|
||
|
||
|
||
|
||
}
|
||
|
||
|
||
public void ExecuteAction(ExecuteUIInfoGridInfo evt)
|
||
{
|
||
if(evt.idx >= ActionCircleMonoList.Count || evt.idx >= _actionCount) return;
|
||
ActionCircleMonoList[(int)evt.idx].ClickButton.onClick.Invoke();
|
||
}
|
||
private void OnActionCircleClicked(CommonActionId actionId, CommonActionParams param)
|
||
{
|
||
var action = ActionLogicFactory.GetActionLogic(actionId);
|
||
if (action.CheckCan(param) && action.CompleteExecute(param))
|
||
{
|
||
// Action执行成功后立即刷新APBox,确保关闭/重开面板时显示最新状态
|
||
if (param.UnitData != null)
|
||
RefreshActionPoints(param.UnitData);
|
||
|
||
OnBtnCloseClick?.Invoke();
|
||
|
||
//这里特殊处理 点击了action但是不关闭gridInfo而是让单位继续行动的情况。后续需要将这个属性归化
|
||
if(action.ActionId.UnitActionType == UnitActionType.AYAMOVEAGAIN)
|
||
PresentationManager.EnqueueTask(new InputSequencerTask(MapRenderer.Instance.SelectUnitData.Grid(Main.MapData)));
|
||
}
|
||
}
|
||
|
||
//清除所有ActionPoint,重新开始
|
||
private void APBoxInit()
|
||
{
|
||
if (APContainer == null) return;
|
||
for (int i = APContainer.childCount - 1; i >= 0; i--)
|
||
{
|
||
Transform child = APContainer.GetChild(i);
|
||
if (child.GetComponent<UIInfoGridInfoActionPointMono>() != null)
|
||
Destroy(child.gameObject);
|
||
}
|
||
ActionPointMonoList.Clear();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据当前GridInfo展示的类型,决定APBox是否显示,以及填充ActionPoint列表。
|
||
/// 仅在展示Unit的ActionArea时才显示APBox。
|
||
/// </summary>
|
||
private void SetContentAPBox(ShowUIInfoGridInfo evt)
|
||
{
|
||
// 只有当展示的是Unit,并且ActionArea可见时,才显示APBox
|
||
if (evt.type != UIGridInfoType.unit
|
||
|| !Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id, out var unitData)
|
||
|| !ActionArea.activeSelf)
|
||
{
|
||
if (APBox != null) APBox.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
if (APBox != null) APBox.SetActive(true);
|
||
RefreshActionPoints(unitData);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新APContainer下ActionPoint的数量和显示内容。
|
||
/// 根据unitData里的行动点信息,动态生成/复用/隐藏ActionPoint对象。
|
||
/// </summary>
|
||
public void RefreshActionPoints(RuntimeData.UnitData unitData)
|
||
{
|
||
if (APContainer == null || ActionPointPrefab == null || unitData == null) return;
|
||
|
||
// 将ActionPoint字典展开为一个平铺列表,每个点一个条目
|
||
var flatList = new List<RuntimeData.ActionPointType>();
|
||
if (unitData.ActionPoint != null)
|
||
{
|
||
foreach (var kv in unitData.ActionPoint)
|
||
{
|
||
for (int j = 0; j < kv.Value; j++)
|
||
flatList.Add(kv.Key);
|
||
}
|
||
}
|
||
|
||
// 如果总量为0,仍然显示一个Empty
|
||
int needCount = flatList.Count > 0 ? flatList.Count : 1;
|
||
|
||
// 确保池中有足够的ActionPoint实例
|
||
while (ActionPointMonoList.Count < needCount)
|
||
{
|
||
GameObject go = Instantiate(ActionPointPrefab, APContainer, false);
|
||
go.GetComponent<RectTransform>().localScale = Vector3.one;
|
||
var mono = go.GetComponent<UIInfoGridInfoActionPointMono>();
|
||
if (mono == null) mono = go.AddComponent<UIInfoGridInfoActionPointMono>();
|
||
ActionPointMonoList.Add(mono);
|
||
}
|
||
|
||
// 设置每个ActionPoint的显示/隐藏和内容
|
||
for (int i = 0; i < ActionPointMonoList.Count; i++)
|
||
{
|
||
if (i < needCount)
|
||
{
|
||
ActionPointMonoList[i].gameObject.SetActive(true);
|
||
if (flatList.Count == 0)
|
||
ActionPointMonoList[i].SetEmpty();
|
||
else
|
||
ActionPointMonoList[i].SetContent(flatList[i]);
|
||
}
|
||
else
|
||
{
|
||
ActionPointMonoList[i].gameObject.SetActive(false);
|
||
ActionPointMonoList[i].ResetContent();
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SetLayerRecursively(GameObject obj, int newLayer)
|
||
{
|
||
obj.layer = newLayer;
|
||
|
||
foreach (Transform child in obj.transform)
|
||
{
|
||
SetLayerRecursively(child.gameObject, newLayer);
|
||
}
|
||
}
|
||
|
||
private void SetContentTask(ShowUIInfoGridInfo evt)
|
||
{
|
||
// Step #1 判断是否有task需要显示
|
||
if (evt.type != UIGridInfoType.unit ||
|
||
!Main.MapData.UnitMap.GetUnitDataByUnitId(evt.id, out var unit) ||
|
||
!Main.MapData.GetPlayerDataByUnitId(evt.id, out var player) )
|
||
{
|
||
TaskArea.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
bool shouldShowTask = (unit.UnitFullType.UnitType is UnitType.Giant or UnitType.GiantJuggernaut)&&
|
||
unit.UnitFullType.UnitLevel < 4 &&
|
||
player.Id == Main.MapData.PlayerMap.SelfPlayerId;
|
||
if (!shouldShowTask)
|
||
{
|
||
TaskArea.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
//Step #2 设置具体内容
|
||
TaskArea.SetActive(true);
|
||
// GiantJuggernaut 是 Giant 上船形态,真实英雄 GiantType 在 CarryUnitFullType
|
||
var heroGiantType = unit.UnitFullType.UnitType == UnitType.GiantJuggernaut
|
||
? unit.CarryUnitFullType.GiantType
|
||
: unit.GiantType;
|
||
if (!Table.Instance.HeroDataAssets.GetHeroInfo(heroGiantType, out var heroInfo) ||
|
||
heroInfo.TaskList.Count <= unit.UnitLevel - 1 ||
|
||
!Main.MapData.PlayerMap.SelfPlayerData.PlayerHeroData.GetHeroTask(heroGiantType, out var task))
|
||
{
|
||
TaskArea.SetActive(false);
|
||
return;
|
||
}
|
||
if (task.IsForceFinished)
|
||
{
|
||
MultilingualManager.Instance.SetUIText(TaskDesc, Table.Instance.TextDataAssets.HeroTaskFinishedDesc);
|
||
}
|
||
else
|
||
{
|
||
var param1 = task.LevelShowString();
|
||
var param2 = task.TargetLevelShowString();
|
||
var param3 = "";
|
||
if (task.SkillType != SkillType.NONE && Table.Instance.SkillDataAssets.GetSkillInfo(task.SkillType, out var skillInfo))
|
||
{
|
||
param3 = MultilingualManager.Instance.GetMultilingualTextSafe(skillInfo.SkillName);
|
||
}
|
||
var taskDesc = heroInfo.TaskList[(int)(unit.UnitLevel - 1)].Desc;
|
||
MultilingualManager.Instance.SetUIText(TaskDesc, taskDesc, new List<string> { param1, param2, param3 });
|
||
}
|
||
}
|
||
|
||
public void CloseView()
|
||
{
|
||
// 不停止音乐,只恢复轮播(如果正在播放的不是轮播音乐,会继续播放)
|
||
Logic.Audio.AudioManager.Instance.ResumeBgmRotationIfEnabled();
|
||
}
|
||
|
||
protected override void OnShowAnimFinished()
|
||
{
|
||
base.OnShowAnimFinished();
|
||
|
||
// 延迟一帧执行布局刷新,确保 RectTransform 尺寸已正确计算
|
||
StartCoroutine(RefreshLayoutNextFrame());
|
||
}
|
||
|
||
private System.Collections.IEnumerator RefreshLayoutNextFrame()
|
||
{
|
||
yield return null; // 等待一帧
|
||
if (VerticalGroup != null)
|
||
{
|
||
LayoutRebuilder.ForceRebuildLayoutImmediate(VerticalGroup);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
}
|