661 lines
22 KiB
C#
661 lines
22 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using GameFramework.DataTable;
|
||
using GeometryTD.CustomEvent;
|
||
using GeometryTD.CustomUtility;
|
||
using GeometryTD.DataTable;
|
||
using GeometryTD.Definition;
|
||
using UnityEngine;
|
||
using Random = UnityEngine.Random;
|
||
|
||
namespace GeometryTD.CustomComponent
|
||
{
|
||
internal sealed class CombatInRunResourceManager
|
||
{
|
||
// 每次击杀敌人后,进入“掉组件判定”的概率:
|
||
// chance = clamp(DropChanceBase + (phaseIndex - 1) * DropChancePerPhase, 0, DropChanceCap)
|
||
private const float DropChanceBase = 0.05f;
|
||
private const float DropChancePerPhase = 0.2f;
|
||
private const float DropChanceCap = 0.2f;
|
||
|
||
// 用于把阶段映射到 [0,1] 的稀有度曲线输入:
|
||
// phaseT = clamp01((phaseIndex - 1) / RarityCurveScalePhase)
|
||
// 该值越大,稀有度随阶段提升的节奏越慢。
|
||
private const float RarityCurveScalePhase = 30f;
|
||
|
||
private readonly List<DROutGameDropPool> _eligibleDropPoolBuffer = new();
|
||
private readonly List<TowerStatsData> _buildTowerStatsSnapshot = new();
|
||
private readonly Dictionary<RarityType, float> _rarityRollWeightBuffer = new();
|
||
private readonly BackpackInventoryData _rewardInventory = new();
|
||
|
||
private IDataTable<DROutGameDropPool> _drOutGameDropPool;
|
||
private IDataTable<DRMuzzleComp> _drMuzzleComp;
|
||
private IDataTable<DRBearingComp> _drBearingComp;
|
||
private IDataTable<DRBaseComp> _drBaseComp;
|
||
private long _nextDropItemInstanceId = 1;
|
||
private bool _isCombatActive;
|
||
|
||
public int CurrentCoin { get; private set; }
|
||
public int CurrentGold => _isCombatActive ? GainedGold : 0;
|
||
public int CurrentBaseHp { get; private set; }
|
||
public int MaxBaseHp { get; private set; }
|
||
public int CurrentBuildTowerCount => _isCombatActive ? _buildTowerStatsSnapshot.Count : 0;
|
||
public int GainedCoin { get; private set; }
|
||
public int GainedGold { get; private set; }
|
||
|
||
public void InitializeForCombat(DRLevel level)
|
||
{
|
||
Reset();
|
||
if (level == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
MaxBaseHp = Mathf.Max(0, level.BaseHp);
|
||
CurrentBaseHp = MaxBaseHp;
|
||
CurrentCoin = Mathf.Max(0, level.StartCoin);
|
||
CacheBuildTowerStatsSnapshot();
|
||
_isCombatActive = true;
|
||
}
|
||
|
||
public void MarkCombatEnded()
|
||
{
|
||
_isCombatActive = false;
|
||
}
|
||
|
||
public void Reset()
|
||
{
|
||
_isCombatActive = false;
|
||
CurrentCoin = 0;
|
||
CurrentBaseHp = 0;
|
||
MaxBaseHp = 0;
|
||
GainedCoin = 0;
|
||
GainedGold = 0;
|
||
_buildTowerStatsSnapshot.Clear();
|
||
_rewardInventory.Gold = 0;
|
||
_rewardInventory.MuzzleComponents.Clear();
|
||
_rewardInventory.BearingComponents.Clear();
|
||
_rewardInventory.BaseComponents.Clear();
|
||
_rewardInventory.Towers.Clear();
|
||
_rewardInventory.ParticipantTowerInstanceIds.Clear();
|
||
_nextDropItemInstanceId = 1;
|
||
}
|
||
|
||
public BackpackInventoryData GetRewardInventorySnapshot()
|
||
{
|
||
return InventoryCloneUtility.CloneInventory(_rewardInventory);
|
||
}
|
||
|
||
public bool TryConsumeCoin(int coin)
|
||
{
|
||
int requiredCoin = Mathf.Max(0, coin);
|
||
if (requiredCoin <= 0)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
if (!_isCombatActive || CurrentCoin < requiredCoin)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
CurrentCoin -= requiredCoin;
|
||
FireCoinChangedEvent(-requiredCoin);
|
||
return true;
|
||
}
|
||
|
||
public void AddCoin(int coin)
|
||
{
|
||
int gainedCoin = Mathf.Max(0, coin);
|
||
if (!_isCombatActive || gainedCoin <= 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
CurrentCoin += gainedCoin;
|
||
FireCoinChangedEvent(gainedCoin);
|
||
}
|
||
|
||
public int ApplyBaseDamage(int damage)
|
||
{
|
||
int resolvedDamage = Mathf.Max(0, damage);
|
||
if (!_isCombatActive || resolvedDamage <= 0)
|
||
{
|
||
return CurrentBaseHp;
|
||
}
|
||
|
||
int previousBaseHp = CurrentBaseHp;
|
||
CurrentBaseHp = Mathf.Max(0, CurrentBaseHp - resolvedDamage);
|
||
int deltaBaseHp = CurrentBaseHp - previousBaseHp;
|
||
if (deltaBaseHp != 0)
|
||
{
|
||
FireBaseHpChangedEvent(deltaBaseHp);
|
||
}
|
||
|
||
return CurrentBaseHp;
|
||
}
|
||
|
||
public bool TryGetBuildTowerStats(int buildIndex, out TowerStatsData stats)
|
||
{
|
||
stats = null;
|
||
if (!_isCombatActive || buildIndex < 0 || buildIndex >= _buildTowerStatsSnapshot.Count)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
TowerStatsData sourceStats = _buildTowerStatsSnapshot[buildIndex];
|
||
if (sourceStats == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
stats = InventoryCloneUtility.CloneTowerStats(sourceStats);
|
||
return stats != null;
|
||
}
|
||
|
||
public void AddEnemyDefeatedReward(int gainedCoin, int gainedGold)
|
||
{
|
||
if (!_isCombatActive)
|
||
{
|
||
return;
|
||
}
|
||
|
||
int coin = Mathf.Max(0, gainedCoin);
|
||
int gold = Mathf.Max(0, gainedGold);
|
||
GainedCoin += coin;
|
||
GainedGold += gold;
|
||
if (coin > 0)
|
||
{
|
||
CurrentCoin += coin;
|
||
FireCoinChangedEvent(coin);
|
||
}
|
||
|
||
if (gold > 0)
|
||
{
|
||
_rewardInventory.Gold += gold;
|
||
}
|
||
}
|
||
|
||
public void AddSettlementGold(int gainedGold)
|
||
{
|
||
int gold = Mathf.Max(0, gainedGold);
|
||
if (gold <= 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
GainedGold += gold;
|
||
_rewardInventory.Gold += gold;
|
||
}
|
||
|
||
private void CacheBuildTowerStatsSnapshot()
|
||
{
|
||
_buildTowerStatsSnapshot.Clear();
|
||
if (GameEntry.PlayerInventory == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
IReadOnlyList<TowerItemData> towers = GameEntry.PlayerInventory.GetParticipantTowerSnapshot();
|
||
if (towers == null || towers.Count <= 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
for (int i = 0; i < towers.Count; i++)
|
||
{
|
||
TowerItemData tower = towers[i];
|
||
if (tower?.Stats == null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
_buildTowerStatsSnapshot.Add(InventoryCloneUtility.CloneTowerStats(tower.Stats));
|
||
}
|
||
}
|
||
|
||
private void FireCoinChangedEvent(int deltaCoin)
|
||
{
|
||
if (!_isCombatActive)
|
||
{
|
||
return;
|
||
}
|
||
|
||
GameEntry.Event.Fire(this, CombatCoinChangedEventArgs.Create(CurrentCoin, deltaCoin));
|
||
}
|
||
|
||
private void FireBaseHpChangedEvent(int deltaBaseHp)
|
||
{
|
||
if (!_isCombatActive)
|
||
{
|
||
return;
|
||
}
|
||
|
||
GameEntry.Event.Fire(this, CombatBaseHpChangedEventArgs.Create(CurrentBaseHp, deltaBaseHp));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 击杀敌人时的掉落入口。
|
||
/// displayPhaseIndex 会影响:
|
||
/// 1) 总掉落概率(由 DropChanceBase / DropChancePerPhase / DropChanceCap 决定)
|
||
/// 2) 稀有度倾向(通过 phaseT 进入 RollRarity)
|
||
/// themeType 会按关卡主题过滤掉落池(LevelThemeType 不匹配直接不参与)。
|
||
/// </summary>
|
||
public bool TryRollOutGameItemDrop(int displayPhaseIndex, LevelThemeType themeType)
|
||
{
|
||
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
|
||
float dropChance = Mathf.Clamp(DropChanceBase + (phaseIndex - 1) * DropChancePerPhase, 0f, DropChanceCap);
|
||
if (Random.value > dropChance)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (!TryRollOutGameItem(phaseIndex, themeType, out TowerCompItemData droppedItem))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (droppedItem is MuzzleCompItemData muzzleCompItemData)
|
||
{
|
||
_rewardInventory.MuzzleComponents.Add(muzzleCompItemData);
|
||
return true;
|
||
}
|
||
|
||
if (droppedItem is BearingCompItemData bearingCompItemData)
|
||
{
|
||
_rewardInventory.BearingComponents.Add(bearingCompItemData);
|
||
return true;
|
||
}
|
||
|
||
if (droppedItem is BaseCompItemData baseCompItemData)
|
||
{
|
||
_rewardInventory.BaseComponents.Add(baseCompItemData);
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 直接抽取一个具体掉落物(不走前面的总掉率门槛)。
|
||
/// 但 displayPhaseIndex 和 themeType 仍会通过掉落池过滤、稀有度加权影响结果。
|
||
/// </summary>
|
||
public bool TryRollOutGameItem(int displayPhaseIndex, LevelThemeType themeType, out TowerCompItemData droppedItem)
|
||
{
|
||
droppedItem = null;
|
||
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
|
||
if (!TryPickDropPoolRow(phaseIndex, themeType, out DROutGameDropPool selectedRow))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return TryBuildDropItem(selectedRow, out droppedItem);
|
||
}
|
||
|
||
public IReadOnlyList<TowerCompItemData> RollSettlementRewardCandidates(
|
||
int displayPhaseIndex,
|
||
LevelThemeType themeType,
|
||
int candidateCount)
|
||
{
|
||
int resolvedCount = Mathf.Max(0, candidateCount);
|
||
if (resolvedCount <= 0)
|
||
{
|
||
return Array.Empty<TowerCompItemData>();
|
||
}
|
||
|
||
List<TowerCompItemData> candidates = new List<TowerCompItemData>(resolvedCount);
|
||
HashSet<int> selectedPoolRowIds = new HashSet<int>();
|
||
int maxAttempts = Mathf.Max(resolvedCount * 6, resolvedCount);
|
||
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
|
||
|
||
int attempts = 0;
|
||
while (candidates.Count < resolvedCount && attempts < maxAttempts)
|
||
{
|
||
attempts++;
|
||
if (!TryPickDropPoolRow(phaseIndex, themeType, out DROutGameDropPool selectedRow) || selectedRow == null)
|
||
{
|
||
break;
|
||
}
|
||
|
||
if (!selectedPoolRowIds.Add(selectedRow.Id))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (!TryBuildDropItem(selectedRow, out TowerCompItemData droppedItem) || droppedItem == null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
candidates.Add(droppedItem);
|
||
}
|
||
|
||
attempts = 0;
|
||
while (candidates.Count < resolvedCount && attempts < maxAttempts)
|
||
{
|
||
attempts++;
|
||
if (!TryRollOutGameItem(phaseIndex, themeType, out TowerCompItemData droppedItem) || droppedItem == null)
|
||
{
|
||
break;
|
||
}
|
||
|
||
candidates.Add(droppedItem);
|
||
}
|
||
|
||
return candidates;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 两阶段加权抽样:
|
||
/// 1) 先按主题 + 阶段区间过滤候选行
|
||
/// 2) 先抽稀有度(稀有度权重 = 同稀有度所有行的 row.Weight * 稀有度曲线权重 之和)
|
||
/// 3) 在该稀有度内再按 row.Weight 抽具体行
|
||
/// </summary>
|
||
private bool TryPickDropPoolRow(int displayPhaseIndex, LevelThemeType themeType, out DROutGameDropPool selectedRow)
|
||
{
|
||
selectedRow = null;
|
||
IDataTable<DROutGameDropPool> dropTable = EnsureOutGameDropPoolTable();
|
||
if (dropTable == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
_eligibleDropPoolBuffer.Clear();
|
||
DROutGameDropPool[] allRows = dropTable.GetAllDataRows();
|
||
for (int i = 0; i < allRows.Length; i++)
|
||
{
|
||
DROutGameDropPool row = allRows[i];
|
||
if (row == null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 主题过滤:主题不匹配的行,概率为 0。
|
||
if (row.LevelThemeType != themeType)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 阶段过滤:不在 [MinPhase, MaxPhase] 的行,概率为 0。
|
||
if (displayPhaseIndex < row.MinPhase || displayPhaseIndex > row.MaxPhase)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
_eligibleDropPoolBuffer.Add(row);
|
||
}
|
||
|
||
if (_eligibleDropPoolBuffer.Count <= 0)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
RarityType selectedRarity = RollRarity(displayPhaseIndex, _eligibleDropPoolBuffer);
|
||
if (selectedRarity == RarityType.None)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
int totalWeight = 0;
|
||
for (int i = 0; i < _eligibleDropPoolBuffer.Count; i++)
|
||
{
|
||
DROutGameDropPool row = _eligibleDropPoolBuffer[i];
|
||
if (row.Rarity != selectedRarity)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 在已选稀有度内,row.Weight 是线性权重倍率。
|
||
totalWeight += Mathf.Max(1, row.Weight);
|
||
}
|
||
|
||
if (totalWeight <= 0)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
int randomWeight = Random.Range(1, totalWeight + 1);
|
||
int cumulativeWeight = 0;
|
||
for (int i = 0; i < _eligibleDropPoolBuffer.Count; i++)
|
||
{
|
||
DROutGameDropPool row = _eligibleDropPoolBuffer[i];
|
||
if (row.Rarity != selectedRarity)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
cumulativeWeight += Mathf.Max(1, row.Weight);
|
||
if (randomWeight <= cumulativeWeight)
|
||
{
|
||
selectedRow = row;
|
||
return true;
|
||
}
|
||
}
|
||
|
||
selectedRow = _eligibleDropPoolBuffer[_eligibleDropPoolBuffer.Count - 1];
|
||
return selectedRow != null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在过滤后的候选行里抽稀有度。
|
||
/// 实际稀有度权重公式:
|
||
/// rarityWeight = sum(max(1, row.Weight) * GetRarityCurveWeight(row.Rarity, phaseT))
|
||
/// 其中 phaseT = clamp01((displayPhaseIndex - 1) / RarityCurveScalePhase)。
|
||
/// </summary>
|
||
private RarityType RollRarity(int displayPhaseIndex, List<DROutGameDropPool> candidates)
|
||
{
|
||
_rarityRollWeightBuffer.Clear();
|
||
float phaseT = Mathf.Clamp01((displayPhaseIndex - 1) / RarityCurveScalePhase);
|
||
for (int i = 0; i < candidates.Count; i++)
|
||
{
|
||
DROutGameDropPool row = candidates[i];
|
||
if (row == null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
float curveWeight = GetRarityCurveWeight(row.Rarity, phaseT);
|
||
if (curveWeight <= 0f)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (_rarityRollWeightBuffer.TryGetValue(row.Rarity, out float existingWeight))
|
||
{
|
||
_rarityRollWeightBuffer[row.Rarity] = existingWeight + Mathf.Max(1, row.Weight) * curveWeight;
|
||
}
|
||
else
|
||
{
|
||
_rarityRollWeightBuffer[row.Rarity] = Mathf.Max(1, row.Weight) * curveWeight;
|
||
}
|
||
}
|
||
|
||
float totalWeight = 0f;
|
||
foreach (var pair in _rarityRollWeightBuffer)
|
||
{
|
||
totalWeight += Mathf.Max(0f, pair.Value);
|
||
}
|
||
|
||
if (totalWeight <= 0f)
|
||
{
|
||
return RarityType.None;
|
||
}
|
||
|
||
float randomWeight = Random.value * totalWeight;
|
||
float cumulativeWeight = 0f;
|
||
foreach (var pair in _rarityRollWeightBuffer)
|
||
{
|
||
cumulativeWeight += Mathf.Max(0f, pair.Value);
|
||
if (randomWeight <= cumulativeWeight)
|
||
{
|
||
return pair.Key;
|
||
}
|
||
}
|
||
|
||
foreach (var pair in _rarityRollWeightBuffer)
|
||
{
|
||
return pair.Key;
|
||
}
|
||
|
||
return RarityType.None;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 返回各稀有度在当前阶段的曲线权重。
|
||
/// 返回值越大,该稀有度在 RollRarity 中越容易被抽到。
|
||
/// phaseT 取值范围为 [0,1]:
|
||
/// - White/Green:钟形趋势(前中期权重更高)
|
||
/// - Blue/Purple:随阶段近似线性上升
|
||
/// - Red:随阶段二次上升(前期很低,后期明显抬升)
|
||
/// </summary>
|
||
private static float GetRarityCurveWeight(RarityType rarityType, float phaseT)
|
||
{
|
||
float hump = Mathf.Exp(-Mathf.Pow((phaseT - 0.35f) / 0.28f, 2f));
|
||
switch (rarityType)
|
||
{
|
||
case RarityType.White:
|
||
return Mathf.Max(0.05f, 0.18f + 1.25f * hump);
|
||
case RarityType.Green:
|
||
return Mathf.Max(0.05f, 0.35f + 0.55f * hump);
|
||
case RarityType.Blue:
|
||
return 0.18f + 0.55f * phaseT;
|
||
case RarityType.Purple:
|
||
return 0.05f + 0.22f * phaseT;
|
||
case RarityType.Red:
|
||
return 0.01f + 0.08f * phaseT * phaseT;
|
||
default:
|
||
return 0f;
|
||
}
|
||
}
|
||
|
||
private IDataTable<DROutGameDropPool> EnsureOutGameDropPoolTable()
|
||
{
|
||
if (_drOutGameDropPool != null)
|
||
{
|
||
return _drOutGameDropPool;
|
||
}
|
||
|
||
_drOutGameDropPool = GameEntry.DataTable.GetDataTable<DROutGameDropPool>();
|
||
return _drOutGameDropPool;
|
||
}
|
||
|
||
private bool TryBuildDropItem(DROutGameDropPool row, out TowerCompItemData droppedItem)
|
||
{
|
||
droppedItem = null;
|
||
if (row == null || row.ItemId <= 0 || string.IsNullOrWhiteSpace(row.ItemType))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
string itemType = row.ItemType.Trim();
|
||
if (itemType.Equals("MuzzleComp", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
return TryBuildMuzzleCompItem(row, out droppedItem);
|
||
}
|
||
|
||
if (itemType.Equals("BearingComp", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
return TryBuildBearingCompItem(row, out droppedItem);
|
||
}
|
||
|
||
if (itemType.Equals("BaseComp", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
return TryBuildBaseCompItem(row, out droppedItem);
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
private bool TryBuildMuzzleCompItem(DROutGameDropPool row, out TowerCompItemData droppedItem)
|
||
{
|
||
droppedItem = null;
|
||
_drMuzzleComp ??= GameEntry.DataTable.GetDataTable<DRMuzzleComp>();
|
||
if (_drMuzzleComp == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
DRMuzzleComp config = _drMuzzleComp.GetDataRow(row.ItemId);
|
||
if (config == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
droppedItem = new MuzzleCompItemData
|
||
{
|
||
InstanceId = _nextDropItemInstanceId++,
|
||
ConfigId = config.Id,
|
||
Name = config.Name,
|
||
Rarity = row.Rarity,
|
||
Endurance = 100f,
|
||
Constraint = config.Constraint,
|
||
Tags = config.PossibleTag != null ? (TagType[])config.PossibleTag.Clone() : Array.Empty<TagType>(),
|
||
AttackDamage = config.AttackDamage != null ? (int[])config.AttackDamage.Clone() : Array.Empty<int>(),
|
||
DamageRandomRate = config.DamageRandomRate,
|
||
AttackMethodType = config.AttackMethodType
|
||
};
|
||
return true;
|
||
}
|
||
|
||
private bool TryBuildBearingCompItem(DROutGameDropPool row, out TowerCompItemData droppedItem)
|
||
{
|
||
droppedItem = null;
|
||
_drBearingComp ??= GameEntry.DataTable.GetDataTable<DRBearingComp>();
|
||
if (_drBearingComp == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
DRBearingComp config = _drBearingComp.GetDataRow(row.ItemId);
|
||
if (config == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
droppedItem = new BearingCompItemData
|
||
{
|
||
InstanceId = _nextDropItemInstanceId++,
|
||
ConfigId = config.Id,
|
||
Name = config.Name,
|
||
Rarity = row.Rarity,
|
||
Endurance = 100f,
|
||
Constraint = config.Constraint,
|
||
Tags = config.PossibleTag != null ? (TagType[])config.PossibleTag.Clone() : Array.Empty<TagType>(),
|
||
RotateSpeed = config.RotateSpeed != null ? (float[])config.RotateSpeed.Clone() : Array.Empty<float>(),
|
||
AttackRange = config.AttackRange != null ? (float[])config.AttackRange.Clone() : Array.Empty<float>()
|
||
};
|
||
return true;
|
||
}
|
||
|
||
private bool TryBuildBaseCompItem(DROutGameDropPool row, out TowerCompItemData droppedItem)
|
||
{
|
||
droppedItem = null;
|
||
_drBaseComp ??= GameEntry.DataTable.GetDataTable<DRBaseComp>();
|
||
if (_drBaseComp == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
DRBaseComp config = _drBaseComp.GetDataRow(row.ItemId);
|
||
if (config == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
droppedItem = new BaseCompItemData
|
||
{
|
||
InstanceId = _nextDropItemInstanceId++,
|
||
ConfigId = config.Id,
|
||
Name = config.Name,
|
||
Rarity = row.Rarity,
|
||
Endurance = 100f,
|
||
Constraint = config.Constraint,
|
||
Tags = config.PossibleTag != null ? (TagType[])config.PossibleTag.Clone() : Array.Empty<TagType>(),
|
||
AttackSpeed = config.AttackSpeed != null ? (float[])config.AttackSpeed.Clone() : Array.Empty<float>(),
|
||
AttackPropertyType = config.AttackPropertyType
|
||
};
|
||
return true;
|
||
}
|
||
}
|
||
}
|