refactor 8:
- CombatScheduler 不再反向访问 GameEntry.CombatNode。现在由 CombatNodeComponent.cs:322 在初始化时把完成回调传进 scheduler,运行时回调保存在 CombatSchedulerRuntimeContext.cs:27,完成时由 CombatSchedulerFlowCoordinator.cs:245 触发;主题解析也只看当前战斗上下文,不再回退查 facade,见 CombatSchedulerFlowCoordinator.cs:161。同时把 MapEntity 的 coin 回调改成直接连到资源真值来源 CombatLoadingState.cs:56,并把 ICombatSchedulerHost 上那两个资源转发接口删掉,见 ICombatSchedulerHost.cs:5。 - 地图加载入口也收紧了。CombatLoadSession 现在要求必须有 MapEntityLoadContext.InitialMapData,不再走隐式兜底,见 CombatLoadSession.cs:227。EntityExtension 删除了 ShowMap(MapData) 旧重载,当前只保留 ShowMap(MapEntityLoadContext),见 EntityExtension.cs:52;MapEntity 也不再接受裸 MapData 的遗留分支,见 MapEntity.cs:263。
This commit is contained in:
parent
703fd6f540
commit
380f901c1a
|
|
@ -319,7 +319,7 @@ namespace GeometryTD.CustomComponent
|
|||
return true;
|
||||
}
|
||||
|
||||
_combatScheduler.OnInit();
|
||||
_combatScheduler.OnInit(OnCombatEndedByScheduler);
|
||||
_runtimeInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +1,19 @@
|
|||
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 List<TowerItemData> _participantTowerSnapshot = 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 BackpackInventoryData _combatInventorySnapshot = new();
|
||||
private bool _isCombatActive;
|
||||
|
||||
public int CurrentCoin { get; private set; }
|
||||
|
|
@ -54,7 +35,7 @@ namespace GeometryTD.CustomComponent
|
|||
MaxBaseHp = Mathf.Max(0, level.BaseHp);
|
||||
CurrentBaseHp = MaxBaseHp;
|
||||
CurrentCoin = Mathf.Max(0, level.StartCoin);
|
||||
CacheBuildTowerStatsSnapshot();
|
||||
CacheCombatSnapshots();
|
||||
_isCombatActive = true;
|
||||
}
|
||||
|
||||
|
|
@ -72,13 +53,14 @@ namespace GeometryTD.CustomComponent
|
|||
GainedCoin = 0;
|
||||
GainedGold = 0;
|
||||
_buildTowerStatsSnapshot.Clear();
|
||||
_participantTowerSnapshot.Clear();
|
||||
_combatInventorySnapshot = new BackpackInventoryData();
|
||||
_rewardInventory.Gold = 0;
|
||||
_rewardInventory.MuzzleComponents.Clear();
|
||||
_rewardInventory.BearingComponents.Clear();
|
||||
_rewardInventory.BaseComponents.Clear();
|
||||
_rewardInventory.Towers.Clear();
|
||||
_rewardInventory.ParticipantTowerInstanceIds.Clear();
|
||||
_nextDropItemInstanceId = 1;
|
||||
}
|
||||
|
||||
public BackpackInventoryData GetRewardInventorySnapshot()
|
||||
|
|
@ -86,6 +68,26 @@ namespace GeometryTD.CustomComponent
|
|||
return InventoryCloneUtility.CloneInventory(_rewardInventory);
|
||||
}
|
||||
|
||||
public BackpackInventoryData GetCombatInventorySnapshot()
|
||||
{
|
||||
return InventoryCloneUtility.CloneInventory(_combatInventorySnapshot);
|
||||
}
|
||||
|
||||
public IReadOnlyList<TowerItemData> GetParticipantTowerSnapshot()
|
||||
{
|
||||
List<TowerItemData> snapshot = new List<TowerItemData>(_participantTowerSnapshot.Count);
|
||||
for (int i = 0; i < _participantTowerSnapshot.Count; i++)
|
||||
{
|
||||
TowerItemData tower = _participantTowerSnapshot[i];
|
||||
if (tower != null)
|
||||
{
|
||||
snapshot.Add(InventoryCloneUtility.CloneTower(tower));
|
||||
}
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
public bool TryConsumeCoin(int coin)
|
||||
{
|
||||
int requiredCoin = Mathf.Max(0, coin);
|
||||
|
|
@ -188,9 +190,23 @@ namespace GeometryTD.CustomComponent
|
|||
_rewardInventory.Gold += gold;
|
||||
}
|
||||
|
||||
private void CacheBuildTowerStatsSnapshot()
|
||||
public void AddEnemyDefeatedLoot(TowerCompItemData droppedItem)
|
||||
{
|
||||
if (!_isCombatActive || droppedItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AppendRewardItem(droppedItem);
|
||||
}
|
||||
|
||||
private void CacheCombatSnapshots()
|
||||
{
|
||||
_buildTowerStatsSnapshot.Clear();
|
||||
_participantTowerSnapshot.Clear();
|
||||
_combatInventorySnapshot = GameEntry.PlayerInventory != null
|
||||
? GameEntry.PlayerInventory.GetInventorySnapshot()
|
||||
: new BackpackInventoryData();
|
||||
if (GameEntry.PlayerInventory == null)
|
||||
{
|
||||
return;
|
||||
|
|
@ -205,12 +221,16 @@ namespace GeometryTD.CustomComponent
|
|||
for (int i = 0; i < towers.Count; i++)
|
||||
{
|
||||
TowerItemData tower = towers[i];
|
||||
if (tower?.Stats == null)
|
||||
if (tower == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_buildTowerStatsSnapshot.Add(InventoryCloneUtility.CloneTowerStats(tower.Stats));
|
||||
_participantTowerSnapshot.Add(InventoryCloneUtility.CloneTower(tower));
|
||||
if (tower.Stats != null)
|
||||
{
|
||||
_buildTowerStatsSnapshot.Add(InventoryCloneUtility.CloneTowerStats(tower.Stats));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -234,427 +254,20 @@ namespace GeometryTD.CustomComponent
|
|||
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)
|
||||
private void AppendRewardItem(TowerCompItemData droppedItem)
|
||||
{
|
||||
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
|
||||
float dropChance = Mathf.Clamp(DropChanceBase + (phaseIndex - 1) * DropChancePerPhase, 0f, DropChanceCap);
|
||||
if (Random.value > dropChance)
|
||||
switch (droppedItem)
|
||||
{
|
||||
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)
|
||||
{
|
||||
case MuzzleCompItemData muzzleComp:
|
||||
_rewardInventory.MuzzleComponents.Add(InventoryCloneUtility.CloneMuzzleComp(muzzleComp));
|
||||
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)
|
||||
{
|
||||
case BearingCompItemData bearingComp:
|
||||
_rewardInventory.BearingComponents.Add(InventoryCloneUtility.CloneBearingComp(bearingComp));
|
||||
break;
|
||||
case BaseCompItemData baseComp:
|
||||
_rewardInventory.BaseComponents.Add(InventoryCloneUtility.CloneBaseComp(baseComp));
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,6 +233,12 @@ namespace GeometryTD.CustomComponent
|
|||
return false;
|
||||
}
|
||||
|
||||
if (mapLoadContext?.InitialMapData == null)
|
||||
{
|
||||
errorMessage = "CombatLoadSession map load failed. MapEntityLoadContext is missing initial map data.";
|
||||
return false;
|
||||
}
|
||||
|
||||
string mapAssetName = level.Id.ToString();
|
||||
string mapAssetPath = AssetUtility.GetLevelMapAsset(mapAssetName);
|
||||
if (GameEntry.Resource.HasAsset(mapAssetPath) == HasAssetResult.NotExist)
|
||||
|
|
@ -242,13 +248,11 @@ namespace GeometryTD.CustomComponent
|
|||
}
|
||||
|
||||
_loadingMapEntityId = _entity.GenerateSerialId();
|
||||
MapData resolvedMapData = mapLoadContext?.InitialMapData != null
|
||||
? mapLoadContext.InitialMapData.CloneForEntity(_loadingMapEntityId, Vector3.zero)
|
||||
: new MapData(_loadingMapEntityId, level.Id, Vector3.zero);
|
||||
MapData resolvedMapData = mapLoadContext.InitialMapData.CloneForEntity(_loadingMapEntityId, Vector3.zero);
|
||||
MapEntityLoadContext resolvedLoadContext = new MapEntityLoadContext(
|
||||
resolvedMapData,
|
||||
mapLoadContext?.TryConsumeCoin,
|
||||
mapLoadContext?.AddCoin);
|
||||
mapLoadContext.TryConsumeCoin,
|
||||
mapLoadContext.AddCoin);
|
||||
_entity.ShowMap(resolvedLoadContext, mapAssetName);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.DataTable;
|
||||
|
|
@ -39,8 +40,10 @@ namespace GeometryTD.CustomComponent
|
|||
public int GainedCoin => _context.CombatInRunResourceManager.GainedCoin;
|
||||
public int GainedGold => _context.CombatInRunResourceManager.GainedGold;
|
||||
|
||||
public void OnInit()
|
||||
public void OnInit(Action<bool> combatEndedCallback)
|
||||
{
|
||||
_context.CombatEndedCallback = combatEndedCallback;
|
||||
|
||||
if (!_initialized)
|
||||
{
|
||||
_context.Entity = GameEntry.Entity;
|
||||
|
|
@ -142,6 +145,7 @@ namespace GeometryTD.CustomComponent
|
|||
_context.EventBridge.Unbind();
|
||||
_context.CombatFinishFormUseCase = null;
|
||||
_context.RewardSelectFormUseCase = null;
|
||||
_context.CombatEndedCallback = null;
|
||||
|
||||
_context.Entity = null;
|
||||
_initialized = false;
|
||||
|
|
@ -187,15 +191,7 @@ namespace GeometryTD.CustomComponent
|
|||
_flowCoordinator.ResolveCurrentThemeType());
|
||||
EnemyDropResolveResult result = _context.EnemyDropResolver.Resolve(context);
|
||||
_context.CombatInRunResourceManager.AddEnemyDefeatedReward(result.Coin, result.Gold);
|
||||
|
||||
if (!result.ShouldRollOutGameItem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_context.CombatInRunResourceManager.TryRollOutGameItemDrop(
|
||||
context.DisplayPhaseIndex,
|
||||
context.ThemeType);
|
||||
_context.CombatInRunResourceManager.AddEnemyDefeatedLoot(result.LootItem);
|
||||
}
|
||||
|
||||
public bool OnCombatFinishReturnRequested()
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ namespace GeometryTD.CustomComponent
|
|||
_context.PhaseLoopRuntime.Reset();
|
||||
_context.LoadSession.Reset();
|
||||
_context.CombatInRunResourceManager.Reset();
|
||||
_context.EnemyDropResolver.Reset();
|
||||
_context.SettlementContext = null;
|
||||
_context.CurrentLevel = null;
|
||||
_context.IsFinishAsVictory = true;
|
||||
|
|
@ -164,11 +165,6 @@ namespace GeometryTD.CustomComponent
|
|||
return _context.CurrentLevel.LevelThemeType;
|
||||
}
|
||||
|
||||
if (GameEntry.CombatNode != null)
|
||||
{
|
||||
return GameEntry.CombatNode.CurrentThemeType;
|
||||
}
|
||||
|
||||
return LevelThemeType.None;
|
||||
}
|
||||
|
||||
|
|
@ -177,16 +173,6 @@ namespace GeometryTD.CustomComponent
|
|||
return _context.CombatInRunResourceManager.ApplyBaseDamage(damage);
|
||||
}
|
||||
|
||||
public bool TryConsumeCoin(int coin)
|
||||
{
|
||||
return _schedulerHost.TryConsumeCoin(coin);
|
||||
}
|
||||
|
||||
public void AddCoin(int coin)
|
||||
{
|
||||
_schedulerHost.AddCoin(coin);
|
||||
}
|
||||
|
||||
public int GetCurrentBaseHp()
|
||||
{
|
||||
return Mathf.Max(0, _context.CombatInRunResourceManager.CurrentBaseHp);
|
||||
|
|
@ -261,7 +247,7 @@ namespace GeometryTD.CustomComponent
|
|||
_context.IsCompleted = true;
|
||||
_context.CurrentState = null;
|
||||
_context.CombatInRunResourceManager.MarkCombatEnded();
|
||||
GameEntry.CombatNode?.OnCombatEndedByScheduler(succeeded);
|
||||
_context.CombatEndedCallback?.Invoke(succeeded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Entity;
|
||||
|
|
@ -23,6 +24,7 @@ namespace GeometryTD.CustomComponent
|
|||
public CombatFinishFormUseCase CombatFinishFormUseCase { get; set; }
|
||||
public RewardSelectFormUseCase RewardSelectFormUseCase { get; set; }
|
||||
public CombatStateBase CurrentState { get; set; }
|
||||
public Action<bool> CombatEndedCallback { get; set; }
|
||||
public bool IsFinishAsVictory { get; set; } = true;
|
||||
public bool IsCompleted { get; set; }
|
||||
public bool NodeEnterFired { get; set; }
|
||||
|
|
|
|||
|
|
@ -87,19 +87,19 @@ namespace GeometryTD.CustomComponent
|
|||
|
||||
public bool TryPrepareRewardSelection(
|
||||
CombatSettlementContext settlementContext,
|
||||
CombatInRunResourceManager resourceManager,
|
||||
EnemyDropResolver enemyDropResolver,
|
||||
int displayPhaseIndex,
|
||||
LevelThemeType themeType,
|
||||
RewardSelectFormUseCase rewardSelectFormUseCase,
|
||||
Action<RewardSelectItemRawData> onRewardSelected,
|
||||
Action onGiveUp)
|
||||
{
|
||||
if (settlementContext == null || resourceManager == null || rewardSelectFormUseCase == null)
|
||||
if (settlementContext == null || enemyDropResolver == null || rewardSelectFormUseCase == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IReadOnlyList<TowerCompItemData> candidateItems = resourceManager.RollSettlementRewardCandidates(
|
||||
IReadOnlyList<TowerCompItemData> candidateItems = enemyDropResolver.RollSettlementRewardCandidates(
|
||||
displayPhaseIndex,
|
||||
themeType,
|
||||
RewardSelectDisplayCount);
|
||||
|
|
|
|||
|
|
@ -60,13 +60,12 @@ namespace GeometryTD.CustomComponent
|
|||
position: Vector3.zero,
|
||||
initialCoin: Context.CombatInRunResourceManager.CurrentCoin,
|
||||
buildTowerStatsSnapshot: buildTowerStatsSnapshot,
|
||||
inventorySnapshot: GameEntry.PlayerInventory != null
|
||||
? GameEntry.PlayerInventory.GetInventorySnapshot()
|
||||
: null,
|
||||
participantTowerSnapshot: GameEntry.PlayerInventory != null
|
||||
? GameEntry.PlayerInventory.GetParticipantTowerSnapshot()
|
||||
: null);
|
||||
return new MapEntityLoadContext(mapData, Flow.TryConsumeCoin, Flow.AddCoin);
|
||||
inventorySnapshot: Context.CombatInRunResourceManager.GetCombatInventorySnapshot(),
|
||||
participantTowerSnapshot: Context.CombatInRunResourceManager.GetParticipantTowerSnapshot());
|
||||
return new MapEntityLoadContext(
|
||||
mapData,
|
||||
Context.CombatInRunResourceManager.TryConsumeCoin,
|
||||
Context.CombatInRunResourceManager.AddCoin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace GeometryTD.CustomComponent
|
|||
Flow.EnsureRewardSelectFormUseCaseBound();
|
||||
if (!Context.SettlementFlowService.TryPrepareRewardSelection(
|
||||
Context.SettlementContext,
|
||||
Context.CombatInRunResourceManager,
|
||||
Context.EnemyDropResolver,
|
||||
Context.PhaseLoopRuntime.DisplayPhaseIndex,
|
||||
Flow.ResolveCurrentThemeType(),
|
||||
Context.RewardSelectFormUseCase,
|
||||
|
|
|
|||
|
|
@ -1,20 +1,22 @@
|
|||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
internal readonly struct EnemyDropResolveResult
|
||||
{
|
||||
public static EnemyDropResolveResult Empty => new(0, 0, false);
|
||||
public static EnemyDropResolveResult Empty => new(0, 0, null);
|
||||
|
||||
public EnemyDropResolveResult(int coin, int gold, bool shouldRollOutGameItem)
|
||||
public EnemyDropResolveResult(int coin, int gold, TowerCompItemData lootItem)
|
||||
{
|
||||
Coin = coin;
|
||||
Gold = gold;
|
||||
ShouldRollOutGameItem = shouldRollOutGameItem;
|
||||
LootItem = lootItem;
|
||||
}
|
||||
|
||||
public int Coin { get; }
|
||||
|
||||
public int Gold { get; }
|
||||
|
||||
public bool ShouldRollOutGameItem { get; }
|
||||
public TowerCompItemData LootItem { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GameFramework.DataTable;
|
||||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Definition;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
|
|
@ -6,6 +10,27 @@ namespace GeometryTD.CustomComponent
|
|||
{
|
||||
internal sealed class EnemyDropResolver
|
||||
{
|
||||
private const float DropChanceBase = 0.05f;
|
||||
private const float DropChancePerPhase = 0.2f;
|
||||
private const float DropChanceCap = 0.2f;
|
||||
private const float RarityCurveScalePhase = 30f;
|
||||
|
||||
private readonly List<DROutGameDropPool> _eligibleDropPoolBuffer = new();
|
||||
private readonly Dictionary<RarityType, float> _rarityRollWeightBuffer = new();
|
||||
|
||||
private IDataTable<DROutGameDropPool> _drOutGameDropPool;
|
||||
private IDataTable<DRMuzzleComp> _drMuzzleComp;
|
||||
private IDataTable<DRBearingComp> _drBearingComp;
|
||||
private IDataTable<DRBaseComp> _drBaseComp;
|
||||
private long _nextDropItemInstanceId = 1;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_eligibleDropPoolBuffer.Clear();
|
||||
_rarityRollWeightBuffer.Clear();
|
||||
_nextDropItemInstanceId = 1;
|
||||
}
|
||||
|
||||
public EnemyDropResolveResult Resolve(in EnemyDropResolveContext context)
|
||||
{
|
||||
DREnemy enemy = context.Enemy;
|
||||
|
|
@ -26,7 +51,375 @@ namespace GeometryTD.CustomComponent
|
|||
gold = Mathf.Max(0, enemy.DropGold);
|
||||
}
|
||||
|
||||
return new EnemyDropResolveResult(coin, gold, shouldRollOutGameItem: true);
|
||||
TowerCompItemData lootItem = null;
|
||||
if (ShouldRollOutGameItem(context.DisplayPhaseIndex) &&
|
||||
TryRollOutGameItem(context.DisplayPhaseIndex, context.ThemeType, out TowerCompItemData droppedItem))
|
||||
{
|
||||
lootItem = droppedItem;
|
||||
}
|
||||
|
||||
return new EnemyDropResolveResult(coin, gold, lootItem);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static bool ShouldRollOutGameItem(int displayPhaseIndex)
|
||||
{
|
||||
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
|
||||
float dropChance = Mathf.Clamp(DropChanceBase + (phaseIndex - 1) * DropChancePerPhase, 0f, DropChanceCap);
|
||||
return Random.value <= dropChance;
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (row.LevelThemeType != themeType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ namespace GeometryTD.CustomComponent
|
|||
bool CanEndCombat { get; }
|
||||
|
||||
void ChangeState(CombatStateBase nextState);
|
||||
bool TryConsumeCoin(int coin);
|
||||
void AddCoin(int coin);
|
||||
bool TryEndCombatByPlayer();
|
||||
bool TryDebugFail(string errorMessage);
|
||||
bool OnCombatFinishReturnRequested();
|
||||
|
|
|
|||
|
|
@ -49,16 +49,6 @@ namespace GeometryTD
|
|||
entityComponent.ShowEntity(typeof(BulletEntity), "Bullet", Constant.AssetPriority.BulletAsset, data);
|
||||
}
|
||||
|
||||
public static void ShowMap(this EntityComponent entityComponent, MapData data)
|
||||
{
|
||||
ShowMap(entityComponent, data, null);
|
||||
}
|
||||
|
||||
public static void ShowMap(this EntityComponent entityComponent, MapData data, string mapAssetName)
|
||||
{
|
||||
ShowMap(entityComponent, new MapEntityLoadContext(data, null, null), mapAssetName);
|
||||
}
|
||||
|
||||
public static void ShowMap(this EntityComponent entityComponent, MapEntityLoadContext loadContext)
|
||||
{
|
||||
ShowMap(entityComponent, loadContext, null);
|
||||
|
|
|
|||
|
|
@ -267,11 +267,6 @@ namespace GeometryTD.Entity
|
|||
return loadContext;
|
||||
}
|
||||
|
||||
if (userData is MapData legacyMapData)
|
||||
{
|
||||
return new MapEntityLoadContext(legacyMapData, null, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -440,4 +435,3 @@ namespace GeometryTD.Entity
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue