geometry-tower-defense/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/InventoryGenerationComponen...

241 lines
8.5 KiB
C#

using System.Collections.Generic;
using GameFramework.DataTable;
using GeometryTD.DataTable;
using GeometryTD.Definition;
using GeometryTD.Factory;
using GeometryTD.UI;
using UnityEngine;
using UnityGameFramework.Runtime;
using Random = System.Random;
namespace GeometryTD.CustomComponent
{
public sealed class InventoryGenerationComponent : GameFrameworkComponent
{
private int _runSeed;
private int _nodeSequenceIndex = -1;
private int _nextDropOrdinal;
private int _nextRewardOrdinal;
private readonly List<DRShopPrice> _shopPriceRows = new();
private IDataTable<DRShopPrice> _shopPriceTable;
private IDataTable<DROutGameDropPool> _dropPoolTable;
private IDataTable<DRMuzzleComp> _muzzleCompTable;
private IDataTable<DRBearingComp> _bearingCompTable;
private IDataTable<DRBaseComp> _baseCompTable;
private ShopGoodsBuilder _shopGoodsBuilder;
private DropPoolRoller _dropPoolRoller;
private RewardCandidateBuilder _rewardCandidateBuilder;
private OutGameDropItemBuilder _outGameDropItemBuilder;
public void ConfigureRunContext(int runSeed, int sequenceIndex)
{
_runSeed = runSeed;
_nodeSequenceIndex = sequenceIndex;
_nextDropOrdinal = 0;
_nextRewardOrdinal = 0;
}
public List<GoodsItemRawData> BuildShopGoods(int goodsCount, int runSeed = 0, int sequenceIndex = -1)
{
EnsureShopBuilder();
return _shopGoodsBuilder.BuildGoods(goodsCount, runSeed, sequenceIndex);
}
public EnemyDropResult ResolveEnemyDrop(in EnemyDropContext context)
{
DREnemy enemy = context.Enemy;
if (enemy == null)
{
return EnemyDropResult.Empty;
}
int coin = Mathf.Max(0, enemy.DropCoin);
int gold = 0;
float dropRate = enemy.DropPercent > 1f
? Mathf.Clamp01(enemy.DropPercent * 0.01f)
: Mathf.Clamp01(enemy.DropPercent);
int dropOrdinal = AllocateDropOrdinal();
InventoryGenerationRandomContext randomContext =
new(_runSeed, _nodeSequenceIndex, InventoryTagSourceType.Drop, dropOrdinal);
Random random = randomContext.CreateRandom();
if (enemy.DropGold > 0 && dropRate > 0f && random.NextDouble() <= dropRate)
{
gold = Mathf.Max(0, enemy.DropGold);
}
TowerCompItemData lootItem = null;
if (OutGameDropRuleService.ShouldRollOutGameItem(context.DisplayPhaseIndex, random) &&
TryRollOutGameItem(
context.DisplayPhaseIndex,
context.ThemeType,
randomContext,
random,
out TowerCompItemData droppedItem))
{
lootItem = droppedItem;
}
return new EnemyDropResult(coin, gold, lootItem);
}
public IReadOnlyList<TowerCompItemData> BuildRewardCandidates(
int displayPhaseIndex,
LevelThemeType themeType,
int candidateCount)
{
RewardCandidateBuilder rewardCandidateBuilder = EnsureRewardCandidateBuilder();
return rewardCandidateBuilder.BuildCandidates(
displayPhaseIndex,
themeType,
candidateCount,
CreateNextRewardRandomContext,
BuildRewardCandidateItem);
}
private void EnsureShopTables()
{
_shopPriceTable ??= GameEntry.DataTable.GetDataTable<DRShopPrice>();
_muzzleCompTable ??= GameEntry.DataTable.GetDataTable<DRMuzzleComp>();
_bearingCompTable ??= GameEntry.DataTable.GetDataTable<DRBearingComp>();
_baseCompTable ??= GameEntry.DataTable.GetDataTable<DRBaseComp>();
if (_shopPriceTable == null || _muzzleCompTable == null || _bearingCompTable == null ||
_baseCompTable == null)
{
throw new System.InvalidOperationException(
"InventoryGenerationComponent requires ShopPrice, MuzzleComp, BearingComp, and BaseComp data tables.");
}
if (_shopPriceRows.Count > 0)
{
return;
}
DRShopPrice[] rows = _shopPriceTable.GetAllDataRows();
if (rows == null || rows.Length <= 0)
{
throw new System.InvalidOperationException(
"InventoryGenerationComponent requires at least one shop price row.");
}
foreach (var row in rows)
{
if (row != null)
{
_shopPriceRows.Add(row);
}
}
if (_shopPriceRows.Count <= 0)
{
throw new System.InvalidOperationException("InventoryGenerationComponent requires non-null shop price rows.");
}
}
private void EnsureShopBuilder()
{
EnsureShopTables();
_shopGoodsBuilder ??= new ShopGoodsBuilder(
_shopPriceRows,
_muzzleCompTable,
_bearingCompTable,
_baseCompTable);
}
private void EnsureDropTables()
{
_dropPoolTable ??= GameEntry.DataTable.GetDataTable<DROutGameDropPool>();
_muzzleCompTable ??= GameEntry.DataTable.GetDataTable<DRMuzzleComp>();
_bearingCompTable ??= GameEntry.DataTable.GetDataTable<DRBearingComp>();
_baseCompTable ??= GameEntry.DataTable.GetDataTable<DRBaseComp>();
if (_dropPoolTable == null || _muzzleCompTable == null || _bearingCompTable == null || _baseCompTable == null)
{
throw new System.InvalidOperationException(
"InventoryGenerationComponent requires OutGameDropPool, MuzzleComp, BearingComp, and BaseComp data tables.");
}
}
private DropPoolRoller EnsureDropPoolRoller()
{
EnsureDropTables();
_dropPoolRoller ??= new DropPoolRoller(_dropPoolTable);
return _dropPoolRoller;
}
private RewardCandidateBuilder EnsureRewardCandidateBuilder()
{
_rewardCandidateBuilder ??= new RewardCandidateBuilder(EnsureDropPoolRoller());
return _rewardCandidateBuilder;
}
private OutGameDropItemBuilder EnsureOutGameDropItemBuilder()
{
EnsureDropTables();
_outGameDropItemBuilder ??= new OutGameDropItemBuilder(
_muzzleCompTable,
_bearingCompTable,
_baseCompTable);
return _outGameDropItemBuilder;
}
private bool TryRollOutGameItem(
int displayPhaseIndex,
LevelThemeType themeType,
InventoryGenerationRandomContext randomContext,
Random random,
out TowerCompItemData droppedItem)
{
droppedItem = null;
DropPoolRoller dropPoolRoller = EnsureDropPoolRoller();
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
if (!dropPoolRoller.TryRollRow(
phaseIndex,
themeType,
random,
out DROutGameDropPool selectedRow,
out RarityType selectedRarity) || selectedRow == null)
{
return false;
}
return EnsureOutGameDropItemBuilder().TryBuildItem(selectedRow, selectedRarity, randomContext, out droppedItem);
}
private int AllocateDropOrdinal()
{
return _nextDropOrdinal++;
}
private int AllocateRewardOrdinal()
{
return _nextRewardOrdinal++;
}
private InventoryGenerationRandomContext CreateNextRewardRandomContext()
{
return new InventoryGenerationRandomContext(
_runSeed,
_nodeSequenceIndex,
InventoryTagSourceType.Reward,
AllocateRewardOrdinal());
}
private TowerCompItemData BuildRewardCandidateItem(
DROutGameDropPool row,
RarityType rarity,
InventoryGenerationRandomContext randomContext)
{
if (!EnsureOutGameDropItemBuilder().TryBuildItem(row, rarity, randomContext, out TowerCompItemData droppedItem))
{
return null;
}
return droppedItem;
}
}
}