This commit is contained in:
2026-04-30 19:33:16 +08:00
commit fb2252f688
556 changed files with 69721 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
using GeometryTD.Definition;
using GeometryTD.Procedure;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public class EventFormUseCase : IUIUseCase
{
private EventItem _currentEvent;
private RunNodeExecutionContext _currentContext;
private readonly EventOptionExecutor _executor = new EventOptionExecutor();
public void BindEvent(
EventItem eventItem,
RunNodeExecutionContext context)
{
_currentEvent = eventItem;
_currentContext = context != null ? context.Clone() : null;
}
public void Clear()
{
_currentEvent = null;
_currentContext = null;
}
public EventFormRawData CreateInitialModel()
{
if (_currentEvent == null)
{
return null;
}
return new EventFormRawData
{
EventId = _currentEvent.Id,
Title = _currentEvent.Title,
Description = _currentEvent.Description,
OptionItems = BuildOptionItems()
};
}
public bool TrySelectOption(int optionIndex)
{
if (_currentEvent == null || _currentEvent.Options == null)
{
return false;
}
if (optionIndex < 0 || optionIndex >= _currentEvent.Options.Length)
{
Log.Warning("EventFormUseCase.TrySelectOption() option index is invalid: {0}", optionIndex);
return false;
}
BackpackInventoryData workingInventory = GameEntry.PlayerInventory != null
? GameEntry.PlayerInventory.GetInventorySnapshot()
: new BackpackInventoryData();
EventOptionExecutionResult executionResult = _executor.Execute(
_currentEvent,
optionIndex,
_currentContext,
workingInventory);
if (!executionResult.IsAccepted)
{
Log.Warning(
"EventFormUseCase.TrySelectOption() rejected. EventId={0}, OptionIndex={1}, Reason={2}",
_currentEvent.Id,
optionIndex,
executionResult.FailureReason);
return false;
}
if (GameEntry.PlayerInventory != null)
{
GameEntry.PlayerInventory.ReplaceInventorySnapshot(workingInventory);
}
GameEntry.EventNode.EndEvent();
return true;
}
private EventOptionRawData[] BuildOptionItems()
{
EventOption[] options = _currentEvent.Options ?? System.Array.Empty<EventOption>();
EventOptionRawData[] result = new EventOptionRawData[options.Length];
BackpackInventoryData inventory = GameEntry.PlayerInventory != null
? GameEntry.PlayerInventory.GetInventorySnapshot()
: new BackpackInventoryData();
for (int i = 0; i < options.Length; i++)
{
EventOption option = options[i];
EventOptionAvailability availability = _executor.EvaluateOption(option, inventory);
result[i] = new EventOptionRawData
{
OptionIndex = i,
OptionText = option?.OptionText ?? string.Empty,
IsSelectable = availability.IsSelectable,
BlockedReason = availability.BlockedReason
};
}
return result;
}
}
}
@@ -0,0 +1,156 @@
using System.Collections.Generic;
using GeometryTD.Procedure;
namespace GeometryTD.UI
{
public sealed class NodeMapFormUseCase : IUIUseCase
{
private RunState _runState;
public void SetRunState(RunState runState)
{
_runState = runState;
}
public NodeMapFormRawData CreateInitialModel()
{
return BuildRawData(_runState);
}
public bool TryRequestEnterNode(int sequenceIndex, out NodeMapNodeRawData selectedNode, out NodeMapFormRawData latestRawData)
{
latestRawData = BuildRawData(_runState);
selectedNode = null;
if (_runState == null || _runState.IsCompleted)
{
return false;
}
RunNodeState currentNode = _runState.CurrentNode;
if (currentNode == null || currentNode.SequenceIndex != sequenceIndex || !_runState.CanEnterCurrentNode)
{
return false;
}
RunNodeState targetNode = _runState.GetNodeBySequenceIndex(sequenceIndex);
if (targetNode == null || targetNode.Status != RunNodeStatus.Available)
{
return false;
}
selectedNode = BuildNodeRawData(_runState.RunId, targetNode, currentNode.SequenceIndex);
return selectedNode != null && selectedNode.CanEnter;
}
private static NodeMapFormRawData BuildRawData(RunState runState)
{
if (runState == null)
{
return new NodeMapFormRawData
{
Title = "节点地图",
ProgressText = "0 / 0",
CurrentNodeText = "当前节点: 无",
IsRunCompleted = true,
Nodes = new List<NodeMapNodeRawData>()
};
}
List<NodeMapNodeRawData> nodes = new List<NodeMapNodeRawData>(runState.NodeCount);
int currentSequenceIndex = runState.CurrentNode != null ? runState.CurrentNode.SequenceIndex : -1;
foreach (RunNodeState node in runState.Nodes)
{
NodeMapNodeRawData nodeRawData = BuildNodeRawData(runState.RunId, node, currentSequenceIndex);
if (nodeRawData != null)
{
nodes.Add(nodeRawData);
}
}
string currentNodeText = runState.IsCompleted
? "当前节点: 已完成"
: $"当前节点: {BuildNodeTitle(runState.CurrentNode)}";
return new NodeMapFormRawData
{
RunId = runState.RunId,
Title = "节点地图",
ProgressText = $"{runState.CompletedNodeCount} / {runState.NodeCount}",
CurrentNodeText = currentNodeText,
IsRunCompleted = runState.IsCompleted,
Nodes = nodes
};
}
private static NodeMapNodeRawData BuildNodeRawData(string runId, RunNodeState node, int currentSequenceIndex)
{
if (node == null)
{
return null;
}
bool isCurrentNode = node.SequenceIndex == currentSequenceIndex;
bool canEnter = isCurrentNode && node.Status == RunNodeStatus.Available;
return new NodeMapNodeRawData
{
RunId = runId,
NodeId = node.NodeId,
SequenceIndex = node.SequenceIndex,
NodeType = node.NodeType,
Status = node.Status,
IsCurrentNode = isCurrentNode,
CanEnter = canEnter,
Title = BuildNodeTitle(node),
StatusText = BuildStatusText(node.Status, canEnter)
};
}
private static string BuildNodeTitle(RunNodeState node)
{
return node == null ? "未知节点" : BuildNodeTitle(node.NodeType);
}
private static string BuildNodeTitle(RunNodeType nodeType)
{
switch (nodeType)
{
case RunNodeType.Combat:
return "战斗";
case RunNodeType.Event:
return "事件";
case RunNodeType.Shop:
return "商店";
case RunNodeType.BossCombat:
return "Boss";
default:
return "未知节点";
}
}
private static string BuildStatusText(RunNodeStatus status, bool canEnter)
{
if (canEnter)
{
return "当前";
}
switch (status)
{
case RunNodeStatus.Locked:
return "未解锁";
case RunNodeStatus.Available:
return "可进入";
case RunNodeStatus.Completed:
return "已完成";
case RunNodeStatus.Exception:
return "异常";
case RunNodeStatus.Skipped:
return "跳过";
default:
return string.Empty;
}
}
}
}
+209
View File
@@ -0,0 +1,209 @@
using System.Collections.Generic;
using GeometryTD.CustomComponent;
using GeometryTD.CustomUtility;
using GeometryTD.Definition;
namespace GeometryTD.UI
{
public class RepoFormUseCase : IUIUseCase
{
private const int MaxParticipantCount = 4;
private BackpackInventoryData _fallbackInventory;
private readonly HashSet<long> _selectedSellItemIds = new HashSet<long>();
private RepoFormState _state = RepoFormState.Assemble;
public RepoFormRawData CreateInitialModel()
{
BackpackInventoryData sample = GameEntry.PlayerInventory != null
? GameEntry.PlayerInventory.GetInventorySnapshot()
: GetOrCreateFallbackInventory();
return new RepoFormRawData
{
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;
}
return GameEntry.PlayerInventory.TryAssembleTower(
muzzleItemId,
bearingItemId,
baseItemId,
out _);
}
public ParticipantTowerAssignResult TryAddParticipantTower(long towerItemId)
{
if (_state == RepoFormState.Sell)
{
return new ParticipantTowerAssignResult
{
TowerInstanceId = towerItemId,
FailureReason = ParticipantTowerAssignFailureReason.ParticipantAreaFull
};
}
if (GameEntry.PlayerInventory == null)
{
BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory();
return InventoryParticipantUtility.TryAddParticipantTower(
fallbackInventory,
towerItemId,
MaxParticipantCount);
}
return GameEntry.PlayerInventory.TryAddParticipantTower(towerItemId, MaxParticipantCount);
}
public bool TryRemoveParticipantTower(long towerItemId)
{
if (_state == RepoFormState.Sell)
{
return false;
}
if (GameEntry.PlayerInventory == null)
{
BackpackInventoryData fallbackInventory = GetOrCreateFallbackInventory();
return InventoryParticipantUtility.TryRemoveParticipantTower(
fallbackInventory,
towerItemId,
MaxParticipantCount);
}
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;
}
}
}