geometry-tower-defense-base/src-ref/UI/General/UseCase/RewardSelectFormUseCase.cs

237 lines
7.0 KiB
C#

using System;
using System.Collections.Generic;
using GeometryTD.Definition;
using UnityEngine;
namespace GeometryTD.UI
{
public class RewardSelectFormUseCase : IUIUseCase
{
private readonly List<RewardSelectItemRawData> _rewardPool = new List<RewardSelectItemRawData>();
private RewardSelectFormRawData _currentModel;
private Action<RewardSelectItemRawData> _onRewardSelected;
private Action _onGiveUp;
private int _displayCount = 3;
private int _refreshCost;
private bool _allowRotateOnce = true;
private bool _allowGiveUp = true;
private bool _hasRotated;
private int _selectionOffset;
private string _tipText = "Select one reward";
// RewardSelectForm keeps a fixed reward pool for the current node.
// The "refresh" action only rotates which slice of that pool is shown so save/load
// can reopen the same node with the exact same reward contents.
public void ConfigureRewardPool(
IReadOnlyList<RewardSelectItemRawData> rewardPool,
int displayCount = 3,
int refreshCost = 0,
bool allowRotateOnce = true,
bool allowGiveUp = true,
string tipText = null)
{
_rewardPool.Clear();
if (rewardPool != null)
{
foreach (var item in rewardPool)
{
if (item == null)
{
continue;
}
_rewardPool.Add(item);
}
}
_displayCount = Mathf.Max(1, displayCount);
_refreshCost = Mathf.Max(0, refreshCost);
_allowRotateOnce = allowRotateOnce;
_allowGiveUp = allowGiveUp;
_tipText = string.IsNullOrWhiteSpace(tipText) ? "Select one reward" : tipText;
_hasRotated = false;
_selectionOffset = 0;
_currentModel = null;
}
public void ConfigureRewardCandidates(
IReadOnlyList<TowerCompItemData> rewardCandidates,
int displayCount = 3,
int refreshCost = 0,
bool allowRotateOnce = true,
bool allowGiveUp = true,
string tipText = null)
{
_rewardPool.Clear();
if (rewardCandidates != null)
{
foreach (var item in rewardCandidates)
{
if (item == null)
{
continue;
}
_rewardPool.Add(RewardSelectItemRawDataBuilder.Build(item));
}
}
_displayCount = Mathf.Max(1, displayCount);
_refreshCost = Mathf.Max(0, refreshCost);
_allowRotateOnce = allowRotateOnce;
_allowGiveUp = allowGiveUp;
_tipText = string.IsNullOrWhiteSpace(tipText) ? "Select one reward" : tipText;
_hasRotated = false;
_selectionOffset = 0;
_currentModel = null;
}
public void SetCallbacks(Action<RewardSelectItemRawData> onRewardSelected, Action onGiveUp = null)
{
_onRewardSelected = onRewardSelected;
_onGiveUp = onGiveUp;
}
public RewardSelectFormRawData CreateInitialModel()
{
_hasRotated = false;
_currentModel = BuildModel();
return _currentModel;
}
public RewardSelectFormRawData TryRotateSelection()
{
if (_currentModel == null)
{
return null;
}
if (!CanRotateSelectionInternal())
{
return _currentModel;
}
if (!TryConsumeRotateCost())
{
_currentModel.CanRefresh = false;
return _currentModel;
}
_hasRotated = true;
if (_rewardPool.Count > 0)
{
_selectionOffset = (_selectionOffset + _displayCount) % _rewardPool.Count;
}
_currentModel = BuildModel();
return _currentModel;
}
public RewardSelectFormRawData SelectReward(int selectedIndex)
{
if (_currentModel?.RewardItems == null || _currentModel.RewardItems.Length <= 0)
{
return null;
}
if (selectedIndex < 0 || selectedIndex >= _currentModel.RewardItems.Length)
{
return _currentModel;
}
RewardSelectItemRawData selectedReward = _currentModel.RewardItems[selectedIndex];
_onRewardSelected?.Invoke(selectedReward);
_currentModel = null;
return null;
}
public bool TryGiveUp()
{
if (!_allowGiveUp)
{
return false;
}
_onGiveUp?.Invoke();
_currentModel = null;
return true;
}
private RewardSelectFormRawData BuildModel()
{
RewardSelectItemRawData[] selectedRewards = SelectRewards();
return new RewardSelectFormRawData
{
TipText = _tipText,
RewardItems = selectedRewards,
RefreshCost = _refreshCost,
CanRefresh = selectedRewards.Length > 0 && CanRotateSelectionInternal(),
CanGiveUp = _allowGiveUp
};
}
private RewardSelectItemRawData[] SelectRewards()
{
if (_rewardPool.Count <= 0)
{
return Array.Empty<RewardSelectItemRawData>();
}
int finalCount = Mathf.Clamp(_displayCount, 1, _rewardPool.Count);
RewardSelectItemRawData[] results = new RewardSelectItemRawData[finalCount];
for (int i = 0; i < finalCount; i++)
{
int sourceIndex = (_selectionOffset + i) % _rewardPool.Count;
RewardSelectItemRawData source = _rewardPool[sourceIndex];
results[i] = source;
}
return results;
}
private bool CanRotateSelectionInternal()
{
if (!_allowRotateOnce || _hasRotated)
{
return false;
}
return CanPayRotateCost();
}
private bool CanPayRotateCost()
{
if (_refreshCost <= 0)
{
return true;
}
if (GameEntry.PlayerInventory == null)
{
return true;
}
return GameEntry.PlayerInventory.Gold >= _refreshCost;
}
private bool TryConsumeRotateCost()
{
if (_refreshCost <= 0)
{
return true;
}
if (GameEntry.PlayerInventory == null)
{
return true;
}
return GameEntry.PlayerInventory.TryConsumeGold(_refreshCost);
}
}
}