geometry-tower-defense/Assets/GameMain/Scripts/UI/General/UseCase/RewardSelectFormUseCase.cs

339 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using GeometryTD.Definition;
using UnityEngine;
using Random = UnityEngine.Random;
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 _allowRefreshOnce = true;
private bool _allowGiveUp = true;
private bool _hasRefreshed;
private string _tipText = "Select one reward";
public RewardSelectFormUseCase()
{
ConfigureRewardPool(BuildDefaultRewardPool());
}
public void ConfigureRewardPool(
IReadOnlyList<RewardSelectItemRawData> rewardPool,
int displayCount = 3,
int refreshCost = 0,
bool allowRefreshOnce = true,
bool allowGiveUp = true,
string tipText = null)
{
_rewardPool.Clear();
if (rewardPool != null)
{
for (int i = 0; i < rewardPool.Count; i++)
{
RewardSelectItemRawData item = rewardPool[i];
if (item == null)
{
continue;
}
_rewardPool.Add(CloneRawItem(item));
}
}
_displayCount = Mathf.Max(1, displayCount);
_refreshCost = Mathf.Max(0, refreshCost);
_allowRefreshOnce = allowRefreshOnce;
_allowGiveUp = allowGiveUp;
_tipText = string.IsNullOrWhiteSpace(tipText) ? "Select one reward" : tipText;
_hasRefreshed = false;
_currentModel = null;
}
public void SetCallbacks(Action<RewardSelectItemRawData> onRewardSelected, Action onGiveUp = null)
{
_onRewardSelected = onRewardSelected;
_onGiveUp = onGiveUp;
}
public RewardSelectFormRawData CreateInitialModel()
{
_hasRefreshed = false;
_currentModel = BuildModel();
return _currentModel;
}
public RewardSelectFormRawData TryRefresh()
{
if (_currentModel == null)
{
return null;
}
if (!CanRefreshInternal())
{
return _currentModel;
}
if (!TryConsumeRefreshCost())
{
_currentModel.CanRefresh = false;
return _currentModel;
}
_hasRefreshed = true;
_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 && CanRefreshInternal(),
CanGiveUp = _allowGiveUp
};
}
private RewardSelectItemRawData[] SelectRewards()
{
if (_rewardPool.Count <= 0)
{
return Array.Empty<RewardSelectItemRawData>();
}
int finalCount = Mathf.Clamp(_displayCount, 1, _rewardPool.Count);
int[] indexes = new int[_rewardPool.Count];
for (int i = 0; i < indexes.Length; i++)
{
indexes[i] = i;
}
for (int i = 0; i < finalCount; i++)
{
int randomIndex = Random.Range(i, indexes.Length);
(indexes[i], indexes[randomIndex]) = (indexes[randomIndex], indexes[i]);
}
RewardSelectItemRawData[] results = new RewardSelectItemRawData[finalCount];
for (int i = 0; i < finalCount; i++)
{
RewardSelectItemRawData source = _rewardPool[indexes[i]];
results[i] = CloneRawItem(source);
}
return results;
}
private bool CanRefreshInternal()
{
if (!_allowRefreshOnce || _hasRefreshed)
{
return false;
}
return CanPayRefreshCost();
}
private bool CanPayRefreshCost()
{
if (_refreshCost <= 0)
{
return true;
}
if (GameEntry.PlayerInventory == null)
{
return true;
}
return GameEntry.PlayerInventory.Gold >= _refreshCost;
}
private bool TryConsumeRefreshCost()
{
if (_refreshCost <= 0)
{
return true;
}
if (GameEntry.PlayerInventory == null)
{
return true;
}
return GameEntry.PlayerInventory.TryConsumeGold(_refreshCost);
}
private static List<RewardSelectItemRawData> BuildDefaultRewardPool()
{
BackpackInventoryData inventory = RepoFormUseCase.SampleInventory();
List<RewardSelectItemRawData> rewards = new List<RewardSelectItemRawData>();
if (inventory?.MuzzleComponents != null)
{
for (int i = 0; i < inventory.MuzzleComponents.Count; i++)
{
MuzzleCompItemData item = inventory.MuzzleComponents[i];
if (item == null)
{
continue;
}
rewards.Add(BuildRawItem(item));
}
}
if (inventory?.BearingComponents != null)
{
for (int i = 0; i < inventory.BearingComponents.Count; i++)
{
BearingCompItemData item = inventory.BearingComponents[i];
if (item == null)
{
continue;
}
rewards.Add(BuildRawItem(item));
}
}
if (inventory?.BaseComponents != null)
{
for (int i = 0; i < inventory.BaseComponents.Count; i++)
{
BaseCompItemData item = inventory.BaseComponents[i];
if (item == null)
{
continue;
}
rewards.Add(BuildRawItem(item));
}
}
return rewards;
}
private static RewardSelectItemRawData BuildRawItem(TowerCompItemData item)
{
return new RewardSelectItemRawData
{
RewardId = item.InstanceId,
SlotType = item.SlotType,
Title = item.Name,
TypeText = BuildTypeText(item.SlotType),
Description = BuildDescription(item),
Rarity = item.Rarity,
Tags = item.Tags != null ? (TagType[])item.Tags.Clone() : Array.Empty<TagType>(),
Icon = null,
IsSelectable = true,
SourceItem = item
};
}
private static RewardSelectItemRawData CloneRawItem(RewardSelectItemRawData source)
{
if (source == null)
{
return null;
}
return new RewardSelectItemRawData
{
RewardId = source.RewardId,
SlotType = source.SlotType,
Title = source.Title,
TypeText = source.TypeText,
Description = source.Description,
Rarity = source.Rarity,
Tags = source.Tags != null ? (TagType[])source.Tags.Clone() : Array.Empty<TagType>(),
Icon = source.Icon,
IsSelectable = source.IsSelectable,
SourceItem = source.SourceItem,
UserData = source.UserData
};
}
private static string BuildTypeText(TowerCompSlotType slotType)
{
return slotType switch
{
TowerCompSlotType.Muzzle => "Muzzle Component",
TowerCompSlotType.Bearing => "Bearing Component",
TowerCompSlotType.Base => "Base Component",
TowerCompSlotType.Accessory => "Accessory",
_ => "Component"
};
}
private static string BuildDescription(TowerCompItemData item)
{
if (item is MuzzleCompItemData muzzle)
{
int damage = muzzle.AttackDamage != null && muzzle.AttackDamage.Length > 0 ? muzzle.AttackDamage[0] : 0;
return $"Damage: {damage}, Spread: {muzzle.DamageRandomRate:P0}";
}
if (item is BearingCompItemData bearing)
{
float range = bearing.AttackRange != null && bearing.AttackRange.Length > 0 ? bearing.AttackRange[0] : 0f;
float rotateSpeed = bearing.RotateSpeed != null && bearing.RotateSpeed.Length > 0 ? bearing.RotateSpeed[0] : 0f;
return $"Range: {range:0.##}, Rotate Speed: {rotateSpeed:0.##}";
}
if (item is BaseCompItemData baseComp)
{
float attackSpeed = baseComp.AttackSpeed != null && baseComp.AttackSpeed.Length > 0 ? baseComp.AttackSpeed[0] : 0f;
return $"Attack Speed: {attackSpeed:0.##}, Property: {baseComp.AttackPropertyType}";
}
return string.Empty;
}
}
}