为 RepoForm 添加出售功能,ShopNode 只承载玩家购买组件的逻辑
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
using GeometryTD.UI;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class RepoFormContext : UIContext
|
||||
{
|
||||
public string GoldText;
|
||||
public RepoFormState State;
|
||||
public bool ShowSellModeButton;
|
||||
public string SellModeButtonText;
|
||||
public bool ShowCombineArea;
|
||||
public bool ShowSellArea;
|
||||
public CombineAreaContext CombineAreaContext;
|
||||
public SellAreaContext SellAreaContext;
|
||||
public CompAreaContext CompAreaContext;
|
||||
public ParticipantAreaContext ParticipantAreaContext;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public enum RepoFormState
|
||||
{
|
||||
Assemble = 0,
|
||||
Sell = 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9110fc764f3044bda40df4a8c02f320b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -11,6 +11,9 @@ namespace GeometryTD.UI
|
||||
public float EnduranceRate01;
|
||||
public RepoItemClickActionType ClickActionType;
|
||||
public TowerCompSlotType ComponentSlotType;
|
||||
public bool IsSellMode;
|
||||
public bool IsSellable = true;
|
||||
public bool IsSellSelected;
|
||||
public IconAreaContext IconAreaContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class SellAreaContext
|
||||
{
|
||||
public string TotalPriceText;
|
||||
public bool CanConfirmSell;
|
||||
public RepoItemContext[] ComponentItems;
|
||||
public TowerRepoItemContext[] TowerItems;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f153d1a509df4bb69c6d231df5b60db9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+136
-37
@@ -23,21 +23,44 @@ namespace GeometryTD.UI
|
||||
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(rawData.Inventory.BearingComponents);
|
||||
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(rawData.Inventory.BaseComponents);
|
||||
Dictionary<long, TowerItemData> towerMap = BuildTowerMap(rawData.Inventory.Towers);
|
||||
HashSet<long> selectedSellItemIds = BuildSelectedSellItemSet(rawData.SelectedSellItemIds);
|
||||
bool isSellState = rawData.State == RepoFormState.Sell;
|
||||
|
||||
List<RepoItemContext> componentItems = new List<RepoItemContext>();
|
||||
List<TowerRepoItemContext> towerItems = new List<TowerRepoItemContext>();
|
||||
List<RepoItemContext> selectedSellComponentItems = new List<RepoItemContext>();
|
||||
List<TowerRepoItemContext> selectedSellTowerItems = new List<TowerRepoItemContext>();
|
||||
|
||||
if (rawData.Inventory.Towers != null)
|
||||
{
|
||||
foreach (var tower in rawData.Inventory.Towers)
|
||||
foreach (TowerItemData tower in rawData.Inventory.Towers)
|
||||
{
|
||||
if (tower == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TowerRepoItemContext towerContext = BuildTowerRepoItemContext(tower, muzzleMap, bearingMap, baseMap,
|
||||
RepoItemClickActionType.OpenDetail, true);
|
||||
bool isParticipantTower = rawData.Inventory.ParticipantTowerInstanceIds != null &&
|
||||
rawData.Inventory.ParticipantTowerInstanceIds.Contains(tower.InstanceId);
|
||||
bool isSellSelected = isSellState && selectedSellItemIds.Contains(tower.InstanceId);
|
||||
|
||||
TowerRepoItemContext towerContext = BuildTowerRepoItemContext(
|
||||
tower,
|
||||
muzzleMap,
|
||||
bearingMap,
|
||||
baseMap,
|
||||
RepoItemClickActionType.OpenDetail,
|
||||
!isSellState,
|
||||
isSellState,
|
||||
!isParticipantTower,
|
||||
isSellSelected,
|
||||
false);
|
||||
AddTowerItemContext(towerItems, towerContext);
|
||||
if (isSellSelected)
|
||||
{
|
||||
selectedSellTowerItems.Add(towerContext);
|
||||
}
|
||||
|
||||
AddItemDescSeed(
|
||||
tower.InstanceId,
|
||||
tower.Name,
|
||||
@@ -50,23 +73,24 @@ namespace GeometryTD.UI
|
||||
|
||||
if (rawData.Inventory.MuzzleComponents != null)
|
||||
{
|
||||
foreach (var item in rawData.Inventory.MuzzleComponents)
|
||||
foreach (MuzzleCompItemData item in rawData.Inventory.MuzzleComponents)
|
||||
{
|
||||
if (item == null || item.IsAssembledIntoTower)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RepoItemContext componentContext = new RepoItemContext
|
||||
{
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = true,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Muzzle,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
};
|
||||
RepoItemContext componentContext = BuildSellableComponentContext(
|
||||
item,
|
||||
TowerCompSlotType.Muzzle,
|
||||
isSellState,
|
||||
selectedSellItemIds.Contains(item.InstanceId));
|
||||
AddComponentItemContext(componentItems, componentContext);
|
||||
if (componentContext.IsSellSelected)
|
||||
{
|
||||
selectedSellComponentItems.Add(componentContext);
|
||||
}
|
||||
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
@@ -86,16 +110,17 @@ namespace GeometryTD.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
RepoItemContext componentContext = new RepoItemContext
|
||||
{
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = true,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Bearing,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
};
|
||||
RepoItemContext componentContext = BuildSellableComponentContext(
|
||||
item,
|
||||
TowerCompSlotType.Bearing,
|
||||
isSellState,
|
||||
selectedSellItemIds.Contains(item.InstanceId));
|
||||
AddComponentItemContext(componentItems, componentContext);
|
||||
if (componentContext.IsSellSelected)
|
||||
{
|
||||
selectedSellComponentItems.Add(componentContext);
|
||||
}
|
||||
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
@@ -115,16 +140,17 @@ namespace GeometryTD.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
RepoItemContext componentContext = new RepoItemContext
|
||||
{
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = true,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = TowerCompSlotType.Base,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
};
|
||||
RepoItemContext componentContext = BuildSellableComponentContext(
|
||||
item,
|
||||
TowerCompSlotType.Base,
|
||||
isSellState,
|
||||
selectedSellItemIds.Contains(item.InstanceId));
|
||||
AddComponentItemContext(componentItems, componentContext);
|
||||
if (componentContext.IsSellSelected)
|
||||
{
|
||||
selectedSellComponentItems.Add(componentContext);
|
||||
}
|
||||
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
@@ -141,7 +167,19 @@ namespace GeometryTD.UI
|
||||
return new RepoFormContext
|
||||
{
|
||||
GoldText = $"金币: {rawData.Inventory.Gold}",
|
||||
State = rawData.State,
|
||||
ShowSellModeButton = rawData.State == RepoFormState.Assemble,
|
||||
SellModeButtonText = "出售模式",
|
||||
ShowCombineArea = rawData.State == RepoFormState.Assemble,
|
||||
ShowSellArea = rawData.State == RepoFormState.Sell,
|
||||
CombineAreaContext = new CombineAreaContext(),
|
||||
SellAreaContext = new SellAreaContext
|
||||
{
|
||||
TotalPriceText = $"总价值: {rawData.SelectedSellTotalPrice}",
|
||||
CanConfirmSell = rawData.State == RepoFormState.Sell && rawData.SelectedSellItemCount > 0,
|
||||
ComponentItems = selectedSellComponentItems.ToArray(),
|
||||
TowerItems = selectedSellTowerItems.ToArray()
|
||||
},
|
||||
CompAreaContext = new CompAreaContext
|
||||
{
|
||||
ComponentItems = componentItems.ToArray(),
|
||||
@@ -151,6 +189,26 @@ namespace GeometryTD.UI
|
||||
};
|
||||
}
|
||||
|
||||
private static RepoItemContext BuildSellableComponentContext(
|
||||
TowerCompItemData item,
|
||||
TowerCompSlotType slotType,
|
||||
bool isSellState,
|
||||
bool isSellSelected)
|
||||
{
|
||||
return new RepoItemContext
|
||||
{
|
||||
InstanceId = item.InstanceId,
|
||||
CanDrag = !isSellState,
|
||||
EnduranceRate01 = ItemDescUtility.ResolveComponentEnduranceRate(item),
|
||||
ClickActionType = RepoItemClickActionType.OpenDetail,
|
||||
ComponentSlotType = slotType,
|
||||
IsSellMode = isSellState,
|
||||
IsSellable = true,
|
||||
IsSellSelected = isSellState && isSellSelected,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
};
|
||||
}
|
||||
|
||||
private void AddComponentItemContext(List<RepoItemContext> items, RepoItemContext itemContext)
|
||||
{
|
||||
if (itemContext == null)
|
||||
@@ -218,7 +276,7 @@ namespace GeometryTD.UI
|
||||
return map;
|
||||
}
|
||||
|
||||
foreach (var item in items)
|
||||
foreach (TComp item in items)
|
||||
{
|
||||
if (item == null || item.InstanceId <= 0)
|
||||
{
|
||||
@@ -231,6 +289,26 @@ namespace GeometryTD.UI
|
||||
return map;
|
||||
}
|
||||
|
||||
private static HashSet<long> BuildSelectedSellItemSet(IReadOnlyList<long> selectedSellItemIds)
|
||||
{
|
||||
HashSet<long> selectedIds = new HashSet<long>();
|
||||
if (selectedSellItemIds == null)
|
||||
{
|
||||
return selectedIds;
|
||||
}
|
||||
|
||||
for (int i = 0; i < selectedSellItemIds.Count; i++)
|
||||
{
|
||||
long itemId = selectedSellItemIds[i];
|
||||
if (itemId > 0)
|
||||
{
|
||||
selectedIds.Add(itemId);
|
||||
}
|
||||
}
|
||||
|
||||
return selectedIds;
|
||||
}
|
||||
|
||||
private static Dictionary<long, TowerItemData> BuildTowerMap(IReadOnlyList<TowerItemData> towers)
|
||||
{
|
||||
Dictionary<long, TowerItemData> map = new Dictionary<long, TowerItemData>();
|
||||
@@ -239,7 +317,7 @@ namespace GeometryTD.UI
|
||||
return map;
|
||||
}
|
||||
|
||||
foreach (var tower in towers)
|
||||
foreach (TowerItemData tower in towers)
|
||||
{
|
||||
if (tower == null || tower.InstanceId <= 0)
|
||||
{
|
||||
@@ -263,7 +341,7 @@ namespace GeometryTD.UI
|
||||
List<TowerRepoItemContext> participantItems = new List<TowerRepoItemContext>();
|
||||
if (inventory?.ParticipantTowerInstanceIds != null && towerMap != null)
|
||||
{
|
||||
foreach (var towerId in inventory.ParticipantTowerInstanceIds)
|
||||
foreach (long towerId in inventory.ParticipantTowerInstanceIds)
|
||||
{
|
||||
if (towerId <= 0)
|
||||
{
|
||||
@@ -280,8 +358,17 @@ namespace GeometryTD.UI
|
||||
continue;
|
||||
}
|
||||
|
||||
TowerRepoItemContext towerContext = BuildTowerRepoItemContext(tower, muzzleMap, bearingMap, baseMap,
|
||||
RepoItemClickActionType.RemoveParticipant, false);
|
||||
TowerRepoItemContext towerContext = BuildTowerRepoItemContext(
|
||||
tower,
|
||||
muzzleMap,
|
||||
bearingMap,
|
||||
baseMap,
|
||||
RepoItemClickActionType.RemoveParticipant,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
if (towerContext != null)
|
||||
{
|
||||
participantItems.Add(towerContext);
|
||||
@@ -304,6 +391,11 @@ namespace GeometryTD.UI
|
||||
return;
|
||||
}
|
||||
|
||||
if (Context != null && Context.State == RepoFormState.Sell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (long towerId in _compAreaTowerIds)
|
||||
{
|
||||
Form.SetRepoItemSelected(towerId, _participantTowerIds.Contains(towerId));
|
||||
@@ -334,7 +426,11 @@ namespace GeometryTD.UI
|
||||
IReadOnlyDictionary<long, BearingCompItemData> bearingMap,
|
||||
IReadOnlyDictionary<long, BaseCompItemData> baseMap,
|
||||
RepoItemClickActionType clickActionType,
|
||||
bool canDrag)
|
||||
bool canDrag,
|
||||
bool isSellMode,
|
||||
bool isSellable,
|
||||
bool isSellSelected,
|
||||
bool highlightSelected)
|
||||
{
|
||||
if (tower == null)
|
||||
{
|
||||
@@ -348,6 +444,9 @@ namespace GeometryTD.UI
|
||||
EnduranceRate01 = ItemDescUtility.ResolveTowerEnduranceRate(tower, muzzleMap, bearingMap, baseMap),
|
||||
ClickActionType = clickActionType,
|
||||
ComponentSlotType = TowerCompSlotType.None,
|
||||
IsSellMode = isSellMode,
|
||||
IsSellable = isSellable,
|
||||
IsSellSelected = isSellSelected || highlightSelected,
|
||||
IconAreaContext = new TowerIconAreaContext
|
||||
{
|
||||
Rarity = tower.Rarity,
|
||||
|
||||
@@ -3,6 +3,7 @@ using GeometryTD.CustomEvent;
|
||||
using GeometryTD.CustomUtility;
|
||||
using GeometryTD.Definition;
|
||||
using GameFramework.Event;
|
||||
using GeometryTD.CustomComponent;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
@@ -43,6 +44,9 @@ namespace GeometryTD.UI
|
||||
GameEntry.Event.Subscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested);
|
||||
GameEntry.Event.Subscribe(RepoParticipantAssignRequestedEventArgs.EventId, OnRepoParticipantAssignRequested);
|
||||
GameEntry.Event.Subscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn);
|
||||
GameEntry.Event.Subscribe(RepoSellModeToggleRequestedEventArgs.EventId, OnRepoSellModeToggleRequested);
|
||||
GameEntry.Event.Subscribe(RepoSellCancelRequestedEventArgs.EventId, OnRepoSellCancelRequested);
|
||||
GameEntry.Event.Subscribe(RepoSellConfirmRequestedEventArgs.EventId, OnRepoSellConfirmRequested);
|
||||
}
|
||||
|
||||
protected override void UnsubscribeCustomEvents()
|
||||
@@ -53,6 +57,9 @@ namespace GeometryTD.UI
|
||||
GameEntry.Event.Unsubscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested);
|
||||
GameEntry.Event.Unsubscribe(RepoParticipantAssignRequestedEventArgs.EventId, OnRepoParticipantAssignRequested);
|
||||
GameEntry.Event.Unsubscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn);
|
||||
GameEntry.Event.Unsubscribe(RepoSellModeToggleRequestedEventArgs.EventId, OnRepoSellModeToggleRequested);
|
||||
GameEntry.Event.Unsubscribe(RepoSellCancelRequestedEventArgs.EventId, OnRepoSellCancelRequested);
|
||||
GameEntry.Event.Unsubscribe(RepoSellConfirmRequestedEventArgs.EventId, OnRepoSellConfirmRequested);
|
||||
}
|
||||
|
||||
public override int? OpenUI(object userData = null)
|
||||
@@ -125,6 +132,24 @@ namespace GeometryTD.UI
|
||||
return;
|
||||
}
|
||||
|
||||
if (_useCase != null && _useCase.State == RepoFormState.Sell)
|
||||
{
|
||||
if (_useCase.TryToggleSellSelection(
|
||||
args.ItemId,
|
||||
out RepoFormRawData sellModeRawData,
|
||||
out PlayerInventorySaleFailureReason failureReason))
|
||||
{
|
||||
SetContext(BuildContext(sellModeRawData));
|
||||
RefreshCurrentUI();
|
||||
}
|
||||
else if (failureReason == PlayerInventorySaleFailureReason.ParticipantTower)
|
||||
{
|
||||
OpenSellBlockedDialog("参战防御塔不能直接出售,请先移出参战区。");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (clickActionType == RepoItemClickActionType.RemoveParticipant)
|
||||
{
|
||||
if (_useCase == null || Form == null)
|
||||
@@ -165,6 +190,11 @@ namespace GeometryTD.UI
|
||||
return;
|
||||
}
|
||||
|
||||
if (Context != null && Context.State == RepoFormState.Sell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(e is RepoItemDragEndedEventArgs args))
|
||||
{
|
||||
return;
|
||||
@@ -188,6 +218,11 @@ namespace GeometryTD.UI
|
||||
return;
|
||||
}
|
||||
|
||||
if (Context != null && Context.State == RepoFormState.Sell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(e is CombineSlotClickedEventArgs args))
|
||||
{
|
||||
return;
|
||||
@@ -257,6 +292,11 @@ namespace GeometryTD.UI
|
||||
return;
|
||||
}
|
||||
|
||||
if (Context != null && Context.State == RepoFormState.Sell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(e is RepoParticipantAssignRequestedEventArgs args))
|
||||
{
|
||||
return;
|
||||
@@ -288,6 +328,65 @@ namespace GeometryTD.UI
|
||||
RefreshParticipantAreaOnly();
|
||||
}
|
||||
|
||||
private void OnRepoSellModeToggleRequested(object sender, GameEventArgs e)
|
||||
{
|
||||
if (!IsEventFromCurrentForm(sender) || !(e is RepoSellModeToggleRequestedEventArgs) || _useCase == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_useCase.State != RepoFormState.Assemble)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RepoFormRawData rawData = _useCase.EnterSellState();
|
||||
SetContext(BuildContext(rawData));
|
||||
RefreshCurrentUI();
|
||||
}
|
||||
|
||||
private void OnRepoSellCancelRequested(object sender, GameEventArgs e)
|
||||
{
|
||||
if (!IsEventFromCurrentForm(sender) || !(e is RepoSellCancelRequestedEventArgs) || _useCase == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_useCase.State != RepoFormState.Sell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetContext(BuildContext(_useCase.ExitSellState()));
|
||||
RefreshCurrentUI();
|
||||
}
|
||||
|
||||
private void OnRepoSellConfirmRequested(object sender, GameEventArgs e)
|
||||
{
|
||||
if (!IsEventFromCurrentForm(sender) || !(e is RepoSellConfirmRequestedEventArgs) || _useCase == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_useCase.TryConfirmSellSelection(out RepoFormRawData rawData, out PlayerInventorySaleResult result))
|
||||
{
|
||||
if (result != null && result.FailureReason == PlayerInventorySaleFailureReason.ParticipantTower)
|
||||
{
|
||||
OpenSellBlockedDialog("参战防御塔不能直接出售,请先移出参战区。");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SetContext(BuildContext(rawData));
|
||||
RefreshCurrentUI();
|
||||
|
||||
if (GameEntry.UI.GetUIForm(UIFormType.ShopForm) != null)
|
||||
{
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.ShopForm);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsEventFromCurrentForm(object sender)
|
||||
{
|
||||
if (Form == null)
|
||||
@@ -309,6 +408,18 @@ namespace GeometryTD.UI
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void OpenSellBlockedDialog(string message)
|
||||
{
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.DialogForm, new DialogFormRawData
|
||||
{
|
||||
Mode = 1,
|
||||
Title = "无法出售",
|
||||
Message = message,
|
||||
PauseGame = false,
|
||||
ConfirmText = "知道了"
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,5 +5,9 @@ namespace GeometryTD.UI
|
||||
public class RepoFormRawData
|
||||
{
|
||||
public BackpackInventoryData Inventory;
|
||||
public RepoFormState State;
|
||||
public long[] SelectedSellItemIds;
|
||||
public int SelectedSellItemCount;
|
||||
public int SelectedSellTotalPrice;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using GeometryTD.CustomUtility;
|
||||
using System.Collections.Generic;
|
||||
using GeometryTD.CustomComponent;
|
||||
using GeometryTD.CustomUtility;
|
||||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
@@ -7,6 +9,8 @@ namespace GeometryTD.UI
|
||||
{
|
||||
private const int MaxParticipantCount = 4;
|
||||
private BackpackInventoryData _fallbackInventory;
|
||||
private readonly HashSet<long> _selectedSellItemIds = new HashSet<long>();
|
||||
private RepoFormState _state = RepoFormState.Assemble;
|
||||
|
||||
public RepoFormRawData CreateInitialModel()
|
||||
{
|
||||
@@ -15,12 +19,23 @@ namespace GeometryTD.UI
|
||||
: GetOrCreateFallbackInventory();
|
||||
return new RepoFormRawData
|
||||
{
|
||||
Inventory = sample
|
||||
Inventory = sample,
|
||||
State = _state,
|
||||
SelectedSellItemIds = BuildSelectedSellItemArray(),
|
||||
SelectedSellItemCount = _selectedSellItemIds.Count,
|
||||
SelectedSellTotalPrice = ResolveSelectedSellTotalPrice()
|
||||
};
|
||||
}
|
||||
|
||||
public RepoFormState State => _state;
|
||||
|
||||
public bool TryAssembleTower(long muzzleItemId, long bearingItemId, long baseItemId)
|
||||
{
|
||||
if (_state == RepoFormState.Sell)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GameEntry.PlayerInventory == null)
|
||||
{
|
||||
return false;
|
||||
@@ -35,6 +50,15 @@ namespace GeometryTD.UI
|
||||
|
||||
public ParticipantTowerAssignResult TryAddParticipantTower(long towerItemId)
|
||||
{
|
||||
if (_state == RepoFormState.Sell)
|
||||
{
|
||||
return new ParticipantTowerAssignResult
|
||||
{
|
||||
TowerInstanceId = towerItemId,
|
||||
FailureReason = ParticipantTowerAssignFailureReason.ParticipantAreaFull
|
||||
};
|
||||
}
|
||||
|
||||
if (GameEntry.PlayerInventory == null)
|
||||
{
|
||||
BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory();
|
||||
@@ -44,11 +68,16 @@ namespace GeometryTD.UI
|
||||
MaxParticipantCount);
|
||||
}
|
||||
|
||||
return GameEntry.PlayerInventory.TryAddParticipantTower(towerItemId, 4);
|
||||
return GameEntry.PlayerInventory.TryAddParticipantTower(towerItemId, MaxParticipantCount);
|
||||
}
|
||||
|
||||
public bool TryRemoveParticipantTower(long towerItemId)
|
||||
{
|
||||
if (_state == RepoFormState.Sell)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GameEntry.PlayerInventory == null)
|
||||
{
|
||||
BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory();
|
||||
@@ -61,12 +90,120 @@ namespace GeometryTD.UI
|
||||
return GameEntry.PlayerInventory.TryRemoveParticipantTower(towerItemId);
|
||||
}
|
||||
|
||||
public RepoFormRawData EnterSellState()
|
||||
{
|
||||
_state = RepoFormState.Sell;
|
||||
_selectedSellItemIds.Clear();
|
||||
return CreateInitialModel();
|
||||
}
|
||||
|
||||
public RepoFormRawData ExitSellState()
|
||||
{
|
||||
_state = RepoFormState.Assemble;
|
||||
_selectedSellItemIds.Clear();
|
||||
return CreateInitialModel();
|
||||
}
|
||||
|
||||
public bool TryToggleSellSelection(
|
||||
long itemId,
|
||||
out RepoFormRawData rawData,
|
||||
out PlayerInventorySaleFailureReason failureReason)
|
||||
{
|
||||
rawData = null;
|
||||
failureReason = PlayerInventorySaleFailureReason.None;
|
||||
if (_state != RepoFormState.Sell || itemId <= 0 || GameEntry.PlayerInventory == null)
|
||||
{
|
||||
failureReason = PlayerInventorySaleFailureReason.InvalidSelection;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_selectedSellItemIds.Contains(itemId))
|
||||
{
|
||||
_selectedSellItemIds.Remove(itemId);
|
||||
rawData = CreateInitialModel();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!GameEntry.PlayerInventory.TryGetSaleCandidate(itemId, out PlayerInventorySaleCandidate candidate) ||
|
||||
candidate == null)
|
||||
{
|
||||
failureReason = PlayerInventorySaleFailureReason.ItemNotFound;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!candidate.IsSellable)
|
||||
{
|
||||
failureReason = candidate.FailureReason;
|
||||
return false;
|
||||
}
|
||||
|
||||
_selectedSellItemIds.Add(itemId);
|
||||
rawData = CreateInitialModel();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryConfirmSellSelection(out RepoFormRawData rawData, out PlayerInventorySaleResult result)
|
||||
{
|
||||
rawData = null;
|
||||
result = null;
|
||||
if (_state != RepoFormState.Sell || _selectedSellItemIds.Count <= 0 || GameEntry.PlayerInventory == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GameEntry.PlayerInventory.TrySellItems(_selectedSellItemIds, out PlayerInventorySaleResult saleResult) ||
|
||||
saleResult == null ||
|
||||
!saleResult.IsSuccess)
|
||||
{
|
||||
result = saleResult;
|
||||
rawData = CreateInitialModel();
|
||||
return false;
|
||||
}
|
||||
|
||||
_selectedSellItemIds.Clear();
|
||||
result = saleResult;
|
||||
rawData = CreateInitialModel();
|
||||
return true;
|
||||
}
|
||||
|
||||
private BackpackInventoryData GetOrCreateFallbackInventory()
|
||||
{
|
||||
_fallbackInventory ??= InventorySeedUtility.CreateSampleInventory();
|
||||
InventoryParticipantUtility.NormalizeParticipantState(_fallbackInventory, MaxParticipantCount);
|
||||
return _fallbackInventory;
|
||||
}
|
||||
|
||||
private long[] BuildSelectedSellItemArray()
|
||||
{
|
||||
if (_selectedSellItemIds.Count <= 0)
|
||||
{
|
||||
return System.Array.Empty<long>();
|
||||
}
|
||||
|
||||
long[] itemIds = new long[_selectedSellItemIds.Count];
|
||||
_selectedSellItemIds.CopyTo(itemIds);
|
||||
return itemIds;
|
||||
}
|
||||
|
||||
private int ResolveSelectedSellTotalPrice()
|
||||
{
|
||||
if (_state != RepoFormState.Sell || _selectedSellItemIds.Count <= 0 || GameEntry.PlayerInventory == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
foreach (long itemId in _selectedSellItemIds)
|
||||
{
|
||||
if (GameEntry.PlayerInventory.TryGetSaleCandidate(itemId, out PlayerInventorySaleCandidate candidate) &&
|
||||
candidate != null &&
|
||||
candidate.IsSellable)
|
||||
{
|
||||
total += candidate.Price;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace GeometryTD.UI
|
||||
public class CombineArea : MonoBehaviour, IDropHandler
|
||||
{
|
||||
[SerializeField] private CombineSlotItem[] _slots;
|
||||
private bool _isInteractionEnabled = true;
|
||||
|
||||
public void OnInit(CombineAreaContext context)
|
||||
{
|
||||
@@ -43,6 +44,11 @@ namespace GeometryTD.UI
|
||||
|
||||
public void OnCombineClick()
|
||||
{
|
||||
if (!_isInteractionEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryGetBoundItemId(TowerCompSlotType.Muzzle, out long muzzleItemId) ||
|
||||
!TryGetBoundItemId(TowerCompSlotType.Bearing, out long bearingItemId) ||
|
||||
!TryGetBoundItemId(TowerCompSlotType.Base, out long baseItemId))
|
||||
@@ -55,6 +61,11 @@ namespace GeometryTD.UI
|
||||
|
||||
public bool TryAssignItem(RepoItemContext itemContext)
|
||||
{
|
||||
if (!_isInteractionEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemContext == null || itemContext.ComponentSlotType == TowerCompSlotType.None)
|
||||
{
|
||||
return false;
|
||||
@@ -91,6 +102,11 @@ namespace GeometryTD.UI
|
||||
|
||||
public void OnDrop(PointerEventData eventData)
|
||||
{
|
||||
if (!_isInteractionEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventData == null)
|
||||
{
|
||||
return;
|
||||
@@ -113,6 +129,11 @@ namespace GeometryTD.UI
|
||||
dragItem.SetDropResult(assigned);
|
||||
}
|
||||
|
||||
public void SetInteractionEnabled(bool enabled)
|
||||
{
|
||||
_isInteractionEnabled = enabled;
|
||||
}
|
||||
|
||||
private CombineSlotItem FindSlot(TowerCompSlotType slotType)
|
||||
{
|
||||
if (_slots == null)
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace GeometryTD.UI
|
||||
[SerializeField] private Transform _content;
|
||||
[SerializeField] private TowerRepoItem _towerItemTemplate;
|
||||
[SerializeField] private int _instancePoolCapacity = 8;
|
||||
private bool _isInteractionEnabled = true;
|
||||
|
||||
private readonly List<TowerRepoItem> _activeItems = new List<TowerRepoItem>();
|
||||
private readonly HashSet<long> _boundItemIds = new HashSet<long>();
|
||||
@@ -81,6 +82,11 @@ namespace GeometryTD.UI
|
||||
|
||||
public bool CanAssign(IRepoDragItemView dragItem)
|
||||
{
|
||||
if (!_isInteractionEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dragItem == null || dragItem.InstanceId <= 0)
|
||||
{
|
||||
return false;
|
||||
@@ -106,6 +112,11 @@ namespace GeometryTD.UI
|
||||
|
||||
public void OnDrop(PointerEventData eventData)
|
||||
{
|
||||
if (!_isInteractionEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventData == null)
|
||||
{
|
||||
return;
|
||||
@@ -134,6 +145,11 @@ namespace GeometryTD.UI
|
||||
GameEntry.Event.Fire(this, RepoParticipantAssignRequestedEventArgs.Create(dragItem.InstanceId));
|
||||
}
|
||||
|
||||
public void SetInteractionEnabled(bool enabled)
|
||||
{
|
||||
_isInteractionEnabled = enabled;
|
||||
}
|
||||
|
||||
private void EnsurePool()
|
||||
{
|
||||
if (_itemPool != null)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using GeometryTD.CustomEvent;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
@@ -8,12 +9,12 @@ namespace GeometryTD.UI
|
||||
public class RepoForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private CombineArea _combineArea;
|
||||
|
||||
[SerializeField] private CompArea _compArea;
|
||||
|
||||
[SerializeField] private SellArea _sellArea;
|
||||
[SerializeField] private ParticipantArea _participantArea;
|
||||
|
||||
[SerializeField] private TMP_Text _goldText;
|
||||
[SerializeField] private CommonButton _sellModeButton;
|
||||
[SerializeField] private TMP_Text _sellModeButtonText;
|
||||
|
||||
public void RefreshUI(RepoFormContext context)
|
||||
{
|
||||
@@ -23,10 +24,25 @@ namespace GeometryTD.UI
|
||||
}
|
||||
|
||||
RefreshGoldText(context.GoldText);
|
||||
RefreshStateUI(context);
|
||||
|
||||
_combineArea?.OnInit(context.CombineAreaContext);
|
||||
_compArea?.OnInit(context.CompAreaContext);
|
||||
_sellArea?.OnInit(context.SellAreaContext);
|
||||
_participantArea?.OnInit(context.ParticipantAreaContext);
|
||||
|
||||
if (_combineArea != null)
|
||||
{
|
||||
_combineArea.gameObject.SetActive(context.ShowCombineArea);
|
||||
_combineArea.SetInteractionEnabled(context.State == RepoFormState.Assemble);
|
||||
}
|
||||
|
||||
if (_sellArea != null)
|
||||
{
|
||||
_sellArea.gameObject.SetActive(context.ShowSellArea);
|
||||
}
|
||||
|
||||
_participantArea?.SetInteractionEnabled(context.State == RepoFormState.Assemble);
|
||||
}
|
||||
|
||||
public void RefreshGoldText(string goldText)
|
||||
@@ -89,6 +105,7 @@ namespace GeometryTD.UI
|
||||
|
||||
_combineArea?.OnReset();
|
||||
_compArea?.OnReset();
|
||||
_sellArea?.OnReset();
|
||||
_participantArea?.OnReset();
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
@@ -97,5 +114,23 @@ namespace GeometryTD.UI
|
||||
{
|
||||
GameEntry.Event.Fire(this, RepoFormReturnEventArgs.Create());
|
||||
}
|
||||
|
||||
public void OnSellModeButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, RepoSellModeToggleRequestedEventArgs.Create());
|
||||
}
|
||||
|
||||
private void RefreshStateUI(RepoFormContext context)
|
||||
{
|
||||
if (_sellModeButton != null)
|
||||
{
|
||||
_sellModeButton.gameObject.SetActive(context != null && context.ShowSellModeButton);
|
||||
}
|
||||
|
||||
if (_sellModeButtonText != null)
|
||||
{
|
||||
_sellModeButtonText.text = context?.SellModeButtonText ?? "出售模式";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace GeometryTD.UI
|
||||
[SerializeField] private IconArea _iconArea;
|
||||
|
||||
private static readonly Color SelectedColor = new Color32(255, 216, 102, 255);
|
||||
private static readonly Color DisabledSellColor = new Color32(96, 96, 96, 255);
|
||||
private static readonly Color EmptyEnduranceColor = new Color(0.8f, 0f, 0f, 1f);
|
||||
private static readonly Color FullEnduranceColor = new Color(0f, 0.8f, 0f, 1f);
|
||||
private static readonly Vector2 DefaultDragGhostSize = new Vector2(64f, 64f);
|
||||
@@ -72,7 +73,7 @@ namespace GeometryTD.UI
|
||||
_context = context;
|
||||
_iconArea.OnInit(context.IconAreaContext);
|
||||
|
||||
SetSelected(false);
|
||||
SetSelected(context.IsSellSelected);
|
||||
ResetDragState();
|
||||
}
|
||||
|
||||
@@ -104,6 +105,12 @@ namespace GeometryTD.UI
|
||||
return;
|
||||
}
|
||||
|
||||
if (_context != null && _context.IsSellMode && !_context.IsSellable)
|
||||
{
|
||||
_bgImage.color = DisabledSellColor;
|
||||
return;
|
||||
}
|
||||
|
||||
float enduranceRate = _context != null ? Mathf.Clamp01(_context.EnduranceRate01) : 1f;
|
||||
_bgImage.color = Color.Lerp(EmptyEnduranceColor, FullEnduranceColor, enduranceRate);
|
||||
}
|
||||
@@ -212,6 +219,11 @@ namespace GeometryTD.UI
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_context.IsSellMode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_isSelected && _context.ComponentSlotType != TowerCompSlotType.None)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
using System.Collections.Generic;
|
||||
using GeometryTD.CustomEvent;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class SellArea : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Transform _content;
|
||||
[SerializeField] private RepoItem _itemTemplate;
|
||||
[SerializeField] private TowerRepoItem _towerItemTemplate;
|
||||
[SerializeField] private TMP_Text _totalPrice;
|
||||
|
||||
private readonly List<RepoItem> _activeComponentItems = new List<RepoItem>();
|
||||
private readonly List<TowerRepoItem> _activeTowerItems = new List<TowerRepoItem>();
|
||||
private SellAreaContext _context;
|
||||
|
||||
public void OnInit(SellAreaContext context)
|
||||
{
|
||||
OnReset();
|
||||
_context = context;
|
||||
|
||||
if (_totalPrice != null)
|
||||
{
|
||||
_totalPrice.text = context?.TotalPriceText ?? string.Empty;
|
||||
}
|
||||
|
||||
if (context == null || _content == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.ComponentItems != null)
|
||||
{
|
||||
foreach (RepoItemContext itemContext in context.ComponentItems)
|
||||
{
|
||||
if (itemContext == null || _itemTemplate == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RepoItem item = Instantiate(_itemTemplate, _content);
|
||||
item.gameObject.SetActive(true);
|
||||
item.OnInit(itemContext);
|
||||
_activeComponentItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.TowerItems != null)
|
||||
{
|
||||
foreach (TowerRepoItemContext itemContext in context.TowerItems)
|
||||
{
|
||||
if (itemContext == null || _towerItemTemplate == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TowerRepoItem item = Instantiate(_towerItemTemplate, _content);
|
||||
item.gameObject.SetActive(true);
|
||||
item.OnInit(itemContext);
|
||||
_activeTowerItems.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
{
|
||||
for (int i = _activeComponentItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
RepoItem item = _activeComponentItems[i];
|
||||
if (item != null)
|
||||
{
|
||||
Destroy(item.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = _activeTowerItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
TowerRepoItem item = _activeTowerItems[i];
|
||||
if (item != null)
|
||||
{
|
||||
Destroy(item.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
_activeComponentItems.Clear();
|
||||
_activeTowerItems.Clear();
|
||||
_context = null;
|
||||
|
||||
if (_totalPrice != null)
|
||||
{
|
||||
_totalPrice.text = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCancelButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, RepoSellCancelRequestedEventArgs.Create());
|
||||
}
|
||||
|
||||
public void OnConfirmButtonClick()
|
||||
{
|
||||
if (_context == null || !_context.CanConfirmSell)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, RepoSellConfirmRequestedEventArgs.Create());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 548fcad4dc8202f41b67f48aab7bed13
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user