340 lines
11 KiB
C#
340 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using GeometryTD.CustomUtility;
|
|
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 = InventorySeedUtility.CreateSampleInventory();
|
|
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;
|
|
}
|
|
}
|
|
}
|