using System.Collections.Generic; using GameFramework.Event; using GeometryTD.CustomEvent; using GeometryTD.CustomUtility; using GeometryTD.Definition; using UnityEngine; using UnityGameFramework.Runtime; namespace GeometryTD.UI { public class CombatFinishFormController : UIFormControllerCommonBase { private CombatFinishFormUseCase _useCase; private readonly Dictionary _itemDescSeedMap = new Dictionary(); private sealed class ItemDescSeed { public string Title; public string TypeText; public string Description; public TagType[] Tags; public TagRuntimeData[] TagRuntimes; } protected override UIFormType UIFormTypeId => UIFormType.CombatFinishForm; protected override void RefreshUI(CombatFinishForm form, CombatFinishFormContext context) { form.RefreshUI(context); } protected override void SubscribeCustomEvents() { GameEntry.Event.Subscribe(CombatFinishReturnEventArgs.EventId, OnCombatFinishReturnButtonClicked); GameEntry.Event.Subscribe(RepoItemClickedEventArgs.EventId, OnRepoItemClicked); } protected override void UnsubscribeCustomEvents() { GameEntry.Event.Unsubscribe(CombatFinishReturnEventArgs.EventId, OnCombatFinishReturnButtonClicked); GameEntry.Event.Unsubscribe(RepoItemClickedEventArgs.EventId, OnRepoItemClicked); } public override int? OpenUI(object userData = null) { if (userData is CombatFinishFormContext context) { return OpenUIInternal(context); } if (userData is CombatFinishFormRawData rawDataFromUserData) { return OpenUI(rawDataFromUserData); } if (userData != null) { Log.Warning("CombatFinishFormController.OpenUI() userData type is invalid."); return null; } if (_useCase == null) { Log.Error("CombatFinishFormController.OpenUI() useCase is null."); return null; } CombatFinishFormRawData rawData = _useCase.CreateInitialModel(); return OpenUI(rawData); } public int? OpenUI(CombatFinishFormRawData rawData) { CombatFinishFormContext context = BuildContext(rawData); return OpenUIInternal(context); } public override void BindUseCase(IUIUseCase useCase) { if (!(useCase is CombatFinishFormUseCase combatFinishFormUseCase)) { Log.Error("CombatFinishFormController.BindUseCase() useCase is invalid."); return; } _useCase = combatFinishFormUseCase; } private CombatFinishFormContext BuildContext(CombatFinishFormRawData rawData) { _itemDescSeedMap.Clear(); if (rawData == null) { return null; } return new CombatFinishFormContext { EnemyKilledText = rawData.DefeatedEnemyCount.ToString(), GoldGainedText = rawData.GainedGold.ToString(), RewardItems = BuildRewardItems(rawData.RewardInventory), CanReturn = rawData.CanReturn }; } private RepoItemContext[] BuildRewardItems(BackpackInventoryData inventory) { if (inventory == null) { return System.Array.Empty(); } Dictionary muzzleMap = BuildComponentMap(inventory.MuzzleComponents); Dictionary bearingMap = BuildComponentMap(inventory.BearingComponents); Dictionary baseMap = BuildComponentMap(inventory.BaseComponents); List itemContexts = new List(); if (inventory.Towers != null) { foreach (TowerItemData tower in inventory.Towers) { if (tower == null) { continue; } itemContexts.Add(new RepoItemContext { InstanceId = tower.InstanceId, CanDrag = false, EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap), ClickActionType = RepoItemClickActionType.OpenDetail, ComponentSlotType = TowerCompSlotType.None, IconAreaContext = BuildTowerIconContext(tower, muzzleMap, bearingMap, baseMap) }); AddItemDescSeed( tower.InstanceId, tower.Name, "Tower", ItemDescUtility.BuildTowerDesc(tower, muzzleMap, bearingMap, baseMap) ?? string.Empty, tower.Stats?.Tags, tower.Stats?.TagRuntimes); } } if (inventory.MuzzleComponents != null) { foreach (MuzzleCompItemData item in inventory.MuzzleComponents) { if (item == null) { continue; } itemContexts.Add(new RepoItemContext { InstanceId = item.InstanceId, CanDrag = false, EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item), ClickActionType = RepoItemClickActionType.OpenDetail, ComponentSlotType = TowerCompSlotType.Muzzle, IconAreaContext = BuildIconAreaContext(item) }); AddItemDescSeed( item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), ItemDescUtility.BuildMuzzleDesc(item) ?? string.Empty, item.Tags, null); } } if (inventory.BearingComponents != null) { foreach (BearingCompItemData item in inventory.BearingComponents) { if (item == null) { continue; } itemContexts.Add(new RepoItemContext { InstanceId = item.InstanceId, CanDrag = false, EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item), ClickActionType = RepoItemClickActionType.OpenDetail, ComponentSlotType = TowerCompSlotType.Bearing, IconAreaContext = BuildIconAreaContext(item) }); AddItemDescSeed( item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), ItemDescUtility.BuildBearingDesc(item) ?? string.Empty, item.Tags, null); } } if (inventory.BaseComponents != null) { foreach (BaseCompItemData item in inventory.BaseComponents) { if (item == null) { continue; } itemContexts.Add(new RepoItemContext { InstanceId = item.InstanceId, CanDrag = false, EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item), ClickActionType = RepoItemClickActionType.OpenDetail, ComponentSlotType = TowerCompSlotType.Base, IconAreaContext = BuildIconAreaContext(item) }); AddItemDescSeed( item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), ItemDescUtility.BuildBaseDesc(item) ?? string.Empty, item.Tags, null); } } return itemContexts.ToArray(); } private static TowerIconAreaContext BuildTowerIconContext( TowerItemData tower, IReadOnlyDictionary muzzleMap, IReadOnlyDictionary bearingMap, IReadOnlyDictionary baseMap) { if (tower == null) { return null; } return new TowerIconAreaContext { Rarity = tower.Rarity, MuzzleColor = ResolveComponentColor(tower.MuzzleComponentInstanceId, muzzleMap), BearingColor = ResolveComponentColor(tower.BearingComponentInstanceId, bearingMap), BaseColor = ResolveComponentColor(tower.BaseComponentInstanceId, baseMap) }; } private static Color ResolveComponentColor(long instanceId, IReadOnlyDictionary componentMap) where TComp : TowerCompItemData { if (instanceId > 0 && componentMap != null && componentMap.TryGetValue(instanceId, out TComp comp) && comp != null) { return IconColorGenerator.GenerateForComponent(comp); } return Color.white; } private void AddItemDescSeed( long itemId, string title, string typeText, string description, TagType[] tags, TagRuntimeData[] tagRuntimes) { if (itemId <= 0) { return; } _itemDescSeedMap[itemId] = new ItemDescSeed { Title = string.IsNullOrWhiteSpace(title) ? $"Item {itemId}" : title, TypeText = typeText ?? string.Empty, Description = description ?? string.Empty, Tags = CloneTags(tags), TagRuntimes = CloneTagRuntimes(tagRuntimes) }; } private static TagType[] CloneTags(TagType[] tags) { return tags != null ? (TagType[])tags.Clone() : System.Array.Empty(); } private static TagRuntimeData[] CloneTagRuntimes(TagRuntimeData[] tagRuntimes) { return InventoryCloneUtility.CloneTagRuntimes(tagRuntimes); } private static string BuildComponentTypeText(TowerCompSlotType slotType) { return slotType switch { TowerCompSlotType.Muzzle => "Muzzle Component", TowerCompSlotType.Bearing => "Bearing Component", TowerCompSlotType.Base => "Base Component", TowerCompSlotType.Accessory => "Accessory", _ => "Component" }; } private static Dictionary BuildComponentMap(IReadOnlyList items) where TComp : TowerCompItemData { Dictionary map = new Dictionary(); if (items == null) { return map; } foreach (TComp item in items) { if (item == null || item.InstanceId <= 0) { continue; } map[item.InstanceId] = item; } return map; } private static IconAreaContext BuildIconAreaContext(TowerCompItemData item) { if (item == null) { return new IconAreaContext { ComponentSlotType = TowerCompSlotType.None, Rarity = RarityType.None, Color = Color.white, Icon = null }; } return new IconAreaContext { ComponentSlotType = item.SlotType, Rarity = item.Rarity, Color = IconColorGenerator.GenerateForComponent(item), Icon = null }; } #region Event Handlers private void OnCombatFinishReturnButtonClicked(object sender, GameEventArgs e) { if (!IsEventFromCurrentForm(sender) || !(e is CombatFinishReturnEventArgs)) { return; } _useCase?.TryReturnToMenu(); } private void OnRepoItemClicked(object sender, GameEventArgs e) { if (!IsEventFromCurrentForm(sender)) { return; } if (!(e is RepoItemClickedEventArgs args)) { return; } if (!_itemDescSeedMap.TryGetValue(args.ItemId, out ItemDescSeed seed)) { return; } GameEntry.UIRouter.OpenUI(UIFormType.ItemDescForm, new ItemDescFormRawData { Title = seed.Title, TypeText = seed.TypeText, Description = seed.Description ?? string.Empty, Price = 0, ScreenPosition = args.ScreenPosition, Tags = CloneTags(seed.Tags), TagRuntimes = CloneTagRuntimes(seed.TagRuntimes) }); } #endregion private bool IsEventFromCurrentForm(object sender) { if (Form == null) { return false; } if (ReferenceEquals(sender, Form)) { return true; } if (sender is Component component) { CombatFinishForm ownerForm = component.GetComponentInParent(); return ownerForm == Form; } return false; } } }