调整 OutGameDropPool 表定义 + 添加部分组件定义

This commit is contained in:
SepComet 2026-03-13 10:08:12 +08:00
parent 26aaa945a9
commit 0c92fd9886
13 changed files with 265 additions and 110 deletions

View File

@ -4,3 +4,7 @@
1 元素底座 [2,2.1,2.2,2.3,2.5] 0.2 Fire [Fire,BurnSpread,IgniteBurst,Inferno] 1 元素底座 [2,2.1,2.2,2.3,2.5] 0.2 Fire [Fire,BurnSpread,IgniteBurst,Inferno]
2 控制底座 [4,4.2,4.4,4.6,4.8] 0.1 Ice [Ice,FreezeMask,Shatter,AbsoluteZero] 2 控制底座 [4,4.2,4.4,4.6,4.8] 0.1 Ice [Ice,FreezeMask,Shatter,AbsoluteZero]
3 穿透底座 [1,1,1,1,1] 0 Physics [Pierce,Crit,Overpenetrate,Execution] 3 穿透底座 [1,1,1,1,1] 0 Physics [Pierce,Crit,Overpenetrate,Execution]
4 12底座 [1,1,1,1,1] 0.1 Poison [Fire,BurnSpread,IgniteBurst,Inferno,Ice,FreezeMask,Shatter,AbsoluteZero]
5 23底座 [1,1,1,1,1] 0.1 Water [Ice,FreezeMask,Shatter,AbsoluteZero,Pierce,Crit,Overpenetrate,Execution]
6 13底座 [1,1,1,1,1] 0.1 Earth [Fire,BurnSpread,IgniteBurst,Inferno,Pierce,Crit,Overpenetrate,Execution]
7 123底座 [1,1,1,1,1] 0.1 Fire [Fire,BurnSpread,IgniteBurst,Inferno,Ice,FreezeMask,Shatter,AbsoluteZero,Pierce,Crit,Overpenetrate,Execution]

View File

@ -4,3 +4,7 @@
1 元素轴承 [10,12,13,14,15] 15 [2,2,2,2,2] 0.3 [Fire,BurnSpread,IgniteBurst,Inferno] 1 元素轴承 [10,12,13,14,15] 15 [2,2,2,2,2] 0.3 [Fire,BurnSpread,IgniteBurst,Inferno]
2 控制轴承 [20,25,30,32,35] 0 [6,6.5,7,8,8] 0.2 [Ice,FreezeMask,Shatter,AbsoluteZero] 2 控制轴承 [20,25,30,32,35] 0 [6,6.5,7,8,8] 0.2 [Ice,FreezeMask,Shatter,AbsoluteZero]
3 穿透轴承 [60,70,80,90,100] 20 [4,4.5,5,5.5,6] 0 [Pierce,Crit,Overpenetrate,Execution] 3 穿透轴承 [60,70,80,90,100] 20 [4,4.5,5,5.5,6] 0 [Pierce,Crit,Overpenetrate,Execution]
4 12轴承 [60,70,80,90,100] 20 [4,4.5,5,5.5,6] 0 [Fire,BurnSpread,IgniteBurst,Inferno,Ice,FreezeMask,Shatter,AbsoluteZero]
5 23轴承 [60,70,80,90,100] 20 [4,4.5,5,5.5,6] 0 [Ice,FreezeMask,Shatter,AbsoluteZero,Pierce,Crit,Overpenetrate,Execution]
6 13轴承 [60,70,80,90,100] 20 [4,4.5,5,5.5,6] 0 [Fire,BurnSpread,IgniteBurst,Inferno,Pierce,Crit,Overpenetrate,Execution]
7 123轴承 [60,70,80,90,100] 20 [4,4.5,5,5.5,6] 0 [Fire,BurnSpread,IgniteBurst,Inferno,Ice,FreezeMask,Shatter,AbsoluteZero,Pierce,Crit,Overpenetrate,Execution]

View File

@ -1,9 +1,6 @@
# Id 策划备注 AssetName # Id 策划备注 AssetName
# int string # int string
# 实体编号 资源名称 # 实体编号 资源名称
101 测试枪口 TestMuzzle
201 测试轴承 TestBearing
301 测试底座 TestBase
401 防御塔实体 TowerEntity 401 防御塔实体 TowerEntity
501 普通子弹 NormalBullet 501 普通子弹 NormalBullet
1001 测试普通敌人 TestEnemy 1001 测试普通敌人 TestEnemy

View File

@ -4,3 +4,7 @@
1 元素枪口 [20,30,40,50,80] 10 0.05 NormalBullet [Fire,BurnSpread,IgniteBurst,Inferno] 1 元素枪口 [20,30,40,50,80] 10 0.05 NormalBullet [Fire,BurnSpread,IgniteBurst,Inferno]
2 控制枪口 [30,50,70,90,100] 20 0.01 NormalBullet [Ice,FreezeMask,Shatter,AbsoluteZero] 2 控制枪口 [30,50,70,90,100] 20 0.01 NormalBullet [Ice,FreezeMask,Shatter,AbsoluteZero]
3 穿透枪口 [50,55,60,80,90] 30 0.02 NormalBullet [Pierce,Crit,Overpenetrate,Execution] 3 穿透枪口 [50,55,60,80,90] 30 0.02 NormalBullet [Pierce,Crit,Overpenetrate,Execution]
4 12枪口 [50,55,60,80,90] 30 0.02 NormalBullet [Fire,BurnSpread,IgniteBurst,Inferno,Ice,FreezeMask,Shatter,AbsoluteZero]
5 23枪口 [50,55,60,80,90] 30 0.02 NormalBullet [Ice,FreezeMask,Shatter,AbsoluteZero,Pierce,Crit,Overpenetrate,Execution]
6 13枪口 [50,55,60,80,90] 30 0.02 NormalBullet [Fire,BurnSpread,IgniteBurst,Inferno,Pierce,Crit,Overpenetrate,Execution]
7 123枪口 [50,55,60,80,90] 30 0.02 NormalBullet [Fire,BurnSpread,IgniteBurst,Inferno,Ice,FreezeMask,Shatter,AbsoluteZero,Pierce,Crit,Overpenetrate,Execution]

View File

@ -1,48 +1,24 @@
# Id 列1 LevelThemeType Rarity ItemType ItemId Weight MinPhase MaxPhase # Id 列1 LevelThemeType ItemType ItemId Weights MinPhase MaxPhase
# int LevelThemeType RarityType ItemType int int int int # int LevelThemeType ItemType int int[] int[] int[]
# 道具池号 策划备注 关卡所属主题类型 道具稀有度 道具类型 道具Id 权重 出现的最低波次 出现的最高波次 # 道具池号 策划备注 关卡所属主题类型 道具类型 道具Id 权重 出现的最低波次 出现的最高波次
1 平原战斗池 Plain White MuzzleComp 1 10 1 10 1 平原战斗池 Plain MuzzleComp 1 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50]
2 Plain White MuzzleComp 2 10 1 10 2 Plain MuzzleComp 2 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50]
3 Plain White MuzzleComp 3 10 1 10 3 Plain MuzzleComp 3 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50]
4 Plain White BearingComp 1 10 1 10 4 Plain MuzzleComp 4 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
5 Plain White BearingComp 2 10 1 10 5 Plain MuzzleComp 5 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
6 Plain White BearingComp 3 10 1 10 6 Plain MuzzleComp 6 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
7 Plain White BaseComp 1 10 1 10 7 Plain MuzzleComp 7 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
8 Plain White BaseComp 2 10 1 10 8 Plain BearingComp 1 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50]
9 Plain White BaseComp 3 10 1 10 9 Plain BearingComp 2 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50]
10 Plain Green MuzzleComp 1 5 2 10 10 Plain BearingComp 3 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50]
11 Plain Green MuzzleComp 2 5 2 10 11 Plain BearingComp 4 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
12 Plain Green MuzzleComp 3 5 2 10 12 Plain BearingComp 5 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
13 Plain Green BearingComp 1 5 2 10 13 Plain BearingComp 6 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
14 Plain Green BearingComp 2 5 2 10 14 Plain BearingComp 7 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
15 Plain Green BearingComp 3 5 2 10 15 Plain BaseComp 1 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50]
16 Plain Green BaseComp 1 5 2 10 16 Plain BaseComp 2 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50]
17 Plain Green BaseComp 2 5 2 10 17 Plain BaseComp 3 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50]
18 Plain Green BaseComp 3 5 2 10 18 Plain BaseComp 4 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
19 Plain Blue MuzzleComp 1 3 3 15 19 Plain BaseComp 5 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
20 Plain Blue MuzzleComp 2 3 3 15 20 Plain BaseComp 6 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
21 Plain Blue MuzzleComp 3 3 3 15 21 Plain BaseComp 7 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50]
22 Plain Blue BearingComp 1 3 3 15
23 Plain Blue BearingComp 2 3 3 15
24 Plain Blue BearingComp 3 3 3 15
25 Plain Blue BaseComp 1 3 3 15
26 Plain Blue BaseComp 2 3 3 15
27 Plain Blue BaseComp 3 3 3 15
28 Plain Purple MuzzleComp 1 2 4 20
29 Plain Purple MuzzleComp 2 2 4 20
30 Plain Purple MuzzleComp 3 2 4 20
31 Plain Purple BearingComp 1 2 4 20
32 Plain Purple BearingComp 2 2 4 20
33 Plain Purple BearingComp 3 2 4 20
34 Plain Purple BaseComp 1 2 4 20
35 Plain Purple BaseComp 2 2 4 20
36 Plain Purple BaseComp 3 2 4 20
37 Plain Red MuzzleComp 1 1 5 50
38 Plain Red MuzzleComp 2 1 5 50
39 Plain Red MuzzleComp 3 1 5 50
40 Plain Red BearingComp 1 1 5 50
41 Plain Red BearingComp 2 1 5 50
42 Plain Red BearingComp 3 1 5 50
43 Plain Red BaseComp 1 1 5 50
44 Plain Red BaseComp 2 1 5 50
45 Plain Red BaseComp 3 1 5 50

View File

@ -19,9 +19,14 @@ namespace GeometryTD.CustomComponent
_dropPoolTable = dropPoolTable; _dropPoolTable = dropPoolTable;
} }
public bool TryRollRow(int displayPhaseIndex, LevelThemeType themeType, out DROutGameDropPool selectedRow) public bool TryRollRow(
int displayPhaseIndex,
LevelThemeType themeType,
out DROutGameDropPool selectedRow,
out RarityType selectedRarity)
{ {
selectedRow = null; selectedRow = null;
selectedRarity = RarityType.None;
DROutGameDropPool[] allRows = _dropPoolTable.GetAllDataRows(); DROutGameDropPool[] allRows = _dropPoolTable.GetAllDataRows();
if (allRows == null || allRows.Length <= 0) if (allRows == null || allRows.Length <= 0)
@ -35,22 +40,30 @@ namespace GeometryTD.CustomComponent
return false; return false;
} }
RarityType selectedRarity = RollRarity(displayPhaseIndex); selectedRarity = RollRarity(displayPhaseIndex);
if (selectedRarity == RarityType.None) if (selectedRarity == RarityType.None)
{ {
return false; return false;
} }
int totalWeight = 0; int totalWeight = 0;
DROutGameDropPool fallbackRow = null;
for (int i = 0; i < _eligibleRowBuffer.Count; i++) for (int i = 0; i < _eligibleRowBuffer.Count; i++)
{ {
DROutGameDropPool row = _eligibleRowBuffer[i]; DROutGameDropPool row = _eligibleRowBuffer[i];
if (row.Rarity != selectedRarity) if (!IsEligibleAtPhase(row, selectedRarity, displayPhaseIndex))
{ {
continue; continue;
} }
totalWeight += Mathf.Max(1, row.Weight); int rowWeight = row.GetWeight(selectedRarity);
if (rowWeight <= 0)
{
continue;
}
fallbackRow = row;
totalWeight += rowWeight;
} }
if (totalWeight <= 0) if (totalWeight <= 0)
@ -62,12 +75,18 @@ namespace GeometryTD.CustomComponent
int cumulativeWeight = 0; int cumulativeWeight = 0;
foreach (var row in _eligibleRowBuffer) foreach (var row in _eligibleRowBuffer)
{ {
if (row.Rarity != selectedRarity) if (!IsEligibleAtPhase(row, selectedRarity, displayPhaseIndex))
{ {
continue; continue;
} }
cumulativeWeight += Mathf.Max(1, row.Weight); int rowWeight = row.GetWeight(selectedRarity);
if (rowWeight <= 0)
{
continue;
}
cumulativeWeight += rowWeight;
if (randomWeight <= cumulativeWeight) if (randomWeight <= cumulativeWeight)
{ {
selectedRow = row; selectedRow = row;
@ -75,7 +94,7 @@ namespace GeometryTD.CustomComponent
} }
} }
selectedRow = _eligibleRowBuffer[_eligibleRowBuffer.Count - 1]; selectedRow = fallbackRow;
return selectedRow != null; return selectedRow != null;
} }
@ -99,7 +118,7 @@ namespace GeometryTD.CustomComponent
continue; continue;
} }
if (displayPhaseIndex < row.MinPhase || displayPhaseIndex > row.MaxPhase) if (!IsEligibleAtPhase(row, displayPhaseIndex))
{ {
continue; continue;
} }
@ -116,20 +135,35 @@ namespace GeometryTD.CustomComponent
for (int i = 0; i < _eligibleRowBuffer.Count; i++) for (int i = 0; i < _eligibleRowBuffer.Count; i++)
{ {
DROutGameDropPool row = _eligibleRowBuffer[i]; DROutGameDropPool row = _eligibleRowBuffer[i];
float curveWeight = GetRarityCurveWeight(row.Rarity, phaseT); for (int rarityIndex = (int)RarityType.White; rarityIndex <= (int)RarityType.Red; rarityIndex++)
{
RarityType rarity = (RarityType)rarityIndex;
if (!IsEligibleAtPhase(row, rarity, displayPhaseIndex))
{
continue;
}
int rowWeight = row.GetWeight(rarity);
if (rowWeight <= 0)
{
continue;
}
float curveWeight = GetRarityCurveWeight(rarity, phaseT);
if (curveWeight <= 0f) if (curveWeight <= 0f)
{ {
continue; continue;
} }
float rowWeight = Mathf.Max(1, row.Weight) * curveWeight; float rarityWeight = rowWeight * curveWeight;
if (_rarityWeightBuffer.TryGetValue(row.Rarity, out float existingWeight)) if (_rarityWeightBuffer.TryGetValue(rarity, out float existingWeight))
{ {
_rarityWeightBuffer[row.Rarity] = existingWeight + rowWeight; _rarityWeightBuffer[rarity] = existingWeight + rarityWeight;
} }
else else
{ {
_rarityWeightBuffer[row.Rarity] = rowWeight; _rarityWeightBuffer[rarity] = rarityWeight;
}
} }
} }
@ -163,6 +197,32 @@ namespace GeometryTD.CustomComponent
return RarityType.None; return RarityType.None;
} }
private static bool IsEligibleAtPhase(DROutGameDropPool row, int displayPhaseIndex)
{
for (int rarityIndex = (int)RarityType.White; rarityIndex <= (int)RarityType.Red; rarityIndex++)
{
RarityType rarity = (RarityType)rarityIndex;
if (IsEligibleAtPhase(row, rarity, displayPhaseIndex))
{
return true;
}
}
return false;
}
private static bool IsEligibleAtPhase(DROutGameDropPool row, RarityType rarity, int displayPhaseIndex)
{
if (row.GetWeight(rarity) <= 0)
{
return false;
}
int minPhase = row.GetMinPhase(rarity);
int maxPhase = row.GetMaxPhase(rarity);
return displayPhaseIndex >= minPhase && displayPhaseIndex <= maxPhase;
}
private static float GetRarityCurveWeight(RarityType rarityType, float phaseT) private static float GetRarityCurveWeight(RarityType rarityType, float phaseT)
{ {
float hump = Mathf.Exp(-Mathf.Pow((phaseT - 0.35f) / 0.28f, 2f)); float hump = Mathf.Exp(-Mathf.Pow((phaseT - 0.35f) / 0.28f, 2f));

View File

@ -183,16 +183,26 @@ namespace GeometryTD.CustomComponent
droppedItem = null; droppedItem = null;
DropPoolRoller dropPoolRoller = EnsureDropPoolRoller(); DropPoolRoller dropPoolRoller = EnsureDropPoolRoller();
int phaseIndex = Mathf.Max(1, displayPhaseIndex); int phaseIndex = Mathf.Max(1, displayPhaseIndex);
if (!dropPoolRoller.TryRollRow(phaseIndex, themeType, out DROutGameDropPool selectedRow) || selectedRow == null) if (!dropPoolRoller.TryRollRow(
phaseIndex,
themeType,
out DROutGameDropPool selectedRow,
out RarityType selectedRarity) || selectedRow == null)
{ {
return false; return false;
} }
return TryBuildDropItem(selectedRow, InventoryTagSourceType.Drop, AllocateDropTagOrdinal(), out droppedItem); return TryBuildDropItem(
selectedRow,
selectedRarity,
InventoryTagSourceType.Drop,
AllocateDropTagOrdinal(),
out droppedItem);
} }
private bool TryBuildDropItem( private bool TryBuildDropItem(
DROutGameDropPool row, DROutGameDropPool row,
RarityType rarity,
InventoryTagSourceType sourceType, InventoryTagSourceType sourceType,
int localOrdinal, int localOrdinal,
out TowerCompItemData droppedItem) out TowerCompItemData droppedItem)
@ -215,7 +225,7 @@ namespace GeometryTD.CustomComponent
droppedItem = ComponentItemFactory.CreateMuzzle( droppedItem = ComponentItemFactory.CreateMuzzle(
config, config,
AllocateTempInstanceId(), AllocateTempInstanceId(),
row.Rarity, rarity,
CreateRandomContext(sourceType, localOrdinal, config.Id)); CreateRandomContext(sourceType, localOrdinal, config.Id));
return true; return true;
} }
@ -231,7 +241,7 @@ namespace GeometryTD.CustomComponent
droppedItem = ComponentItemFactory.CreateBearing( droppedItem = ComponentItemFactory.CreateBearing(
config, config,
AllocateTempInstanceId(), AllocateTempInstanceId(),
row.Rarity, rarity,
CreateRandomContext(sourceType, localOrdinal, config.Id)); CreateRandomContext(sourceType, localOrdinal, config.Id));
return true; return true;
} }
@ -247,7 +257,7 @@ namespace GeometryTD.CustomComponent
droppedItem = ComponentItemFactory.CreateBase( droppedItem = ComponentItemFactory.CreateBase(
config, config,
AllocateTempInstanceId(), AllocateTempInstanceId(),
row.Rarity, rarity,
CreateRandomContext(sourceType, localOrdinal, config.Id)); CreateRandomContext(sourceType, localOrdinal, config.Id));
return true; return true;
} }
@ -265,9 +275,14 @@ namespace GeometryTD.CustomComponent
return _nextRewardTagOrdinal++; return _nextRewardTagOrdinal++;
} }
private TowerCompItemData BuildRewardCandidateItem(DROutGameDropPool row) private TowerCompItemData BuildRewardCandidateItem(DROutGameDropPool row, RarityType rarity)
{ {
if (!TryBuildDropItem(row, InventoryTagSourceType.Reward, AllocateRewardTagOrdinal(), out TowerCompItemData droppedItem)) if (!TryBuildDropItem(
row,
rarity,
InventoryTagSourceType.Reward,
AllocateRewardTagOrdinal(),
out TowerCompItemData droppedItem))
{ {
return null; return null;
} }

View File

@ -19,7 +19,7 @@ namespace GeometryTD.CustomComponent
int displayPhaseIndex, int displayPhaseIndex,
LevelThemeType themeType, LevelThemeType themeType,
int candidateCount, int candidateCount,
Func<DROutGameDropPool, TowerCompItemData> buildRewardItem) Func<DROutGameDropPool, RarityType, TowerCompItemData> buildRewardItem)
{ {
int resolvedCount = Mathf.Max(0, candidateCount); int resolvedCount = Mathf.Max(0, candidateCount);
if (resolvedCount <= 0) if (resolvedCount <= 0)
@ -28,7 +28,7 @@ namespace GeometryTD.CustomComponent
} }
List<TowerCompItemData> candidates = new List<TowerCompItemData>(resolvedCount); List<TowerCompItemData> candidates = new List<TowerCompItemData>(resolvedCount);
HashSet<int> selectedPoolRowIds = new HashSet<int>(); HashSet<long> selectedPoolEntryKeys = new HashSet<long>();
int maxAttempts = Mathf.Max(resolvedCount * 6, resolvedCount); int maxAttempts = Mathf.Max(resolvedCount * 6, resolvedCount);
int phaseIndex = Mathf.Max(1, displayPhaseIndex); int phaseIndex = Mathf.Max(1, displayPhaseIndex);
@ -36,17 +36,21 @@ namespace GeometryTD.CustomComponent
while (candidates.Count < resolvedCount && attempts < maxAttempts) while (candidates.Count < resolvedCount && attempts < maxAttempts)
{ {
attempts++; attempts++;
if (!_dropPoolRoller.TryRollRow(phaseIndex, themeType, out DROutGameDropPool selectedRow) || selectedRow == null) if (!_dropPoolRoller.TryRollRow(
phaseIndex,
themeType,
out DROutGameDropPool selectedRow,
out RarityType selectedRarity) || selectedRow == null)
{ {
break; break;
} }
if (!selectedPoolRowIds.Add(selectedRow.Id)) if (!selectedPoolEntryKeys.Add(BuildSelectionKey(selectedRow.Id, selectedRarity)))
{ {
continue; continue;
} }
TowerCompItemData candidate = buildRewardItem(selectedRow); TowerCompItemData candidate = buildRewardItem(selectedRow, selectedRarity);
if (candidate == null) if (candidate == null)
{ {
continue; continue;
@ -59,12 +63,16 @@ namespace GeometryTD.CustomComponent
while (candidates.Count < resolvedCount && attempts < maxAttempts) while (candidates.Count < resolvedCount && attempts < maxAttempts)
{ {
attempts++; attempts++;
if (!_dropPoolRoller.TryRollRow(phaseIndex, themeType, out DROutGameDropPool selectedRow) || selectedRow == null) if (!_dropPoolRoller.TryRollRow(
phaseIndex,
themeType,
out DROutGameDropPool selectedRow,
out RarityType selectedRarity) || selectedRow == null)
{ {
break; break;
} }
TowerCompItemData candidate = buildRewardItem(selectedRow); TowerCompItemData candidate = buildRewardItem(selectedRow, selectedRarity);
if (candidate == null) if (candidate == null)
{ {
continue; continue;
@ -75,5 +83,10 @@ namespace GeometryTD.CustomComponent
return candidates; return candidates;
} }
private static long BuildSelectionKey(int rowId, RarityType rarity)
{
return ((long)rowId << 32) | (uint)rarity;
}
} }
} }

View File

@ -1,5 +1,7 @@
using System;
using GeometryTD.CustomUtility; using GeometryTD.CustomUtility;
using GeometryTD.Definition; using GeometryTD.Definition;
using UnityEngine;
using UnityGameFramework.Runtime; using UnityGameFramework.Runtime;
namespace GeometryTD.DataTable namespace GeometryTD.DataTable
@ -14,12 +16,11 @@ namespace GeometryTD.DataTable
public override int Id => m_Id; public override int Id => m_Id;
public LevelThemeType LevelThemeType { get; private set; } public LevelThemeType LevelThemeType { get; private set; }
public RarityType Rarity { get; private set; }
public string ItemType { get; private set; } public string ItemType { get; private set; }
public int ItemId { get; private set; } public int ItemId { get; private set; }
public int Weight { get; private set; } public int[] Weights { get; private set; }
public int MinPhase { get; private set; } public int[] MinPhase { get; private set; }
public int MaxPhase { get; private set; } public int[] MaxPhase { get; private set; }
public override bool ParseDataRow(string dataRowString, object userData) public override bool ParseDataRow(string dataRowString, object userData)
{ {
@ -34,31 +35,110 @@ namespace GeometryTD.DataTable
m_Id = int.Parse(columnStrings[index++]); m_Id = int.Parse(columnStrings[index++]);
index++; index++;
LevelThemeType = EnumUtility<LevelThemeType>.Get(columnStrings[index++]); LevelThemeType = EnumUtility<LevelThemeType>.Get(columnStrings[index++]);
Rarity = EnumUtility<RarityType>.Get(columnStrings[index++]);
ItemType = columnStrings[index++]; ItemType = columnStrings[index++];
ItemId = ParseIntOrDefault(columnStrings[index++], 0); ItemId = ParseIntOrDefault(columnStrings[index++], 0);
Weight = ParseIntOrDefault(columnStrings[index++], 1); Weights = ParseWeights(columnStrings[index++]);
MinPhase = ParseIntOrDefault(columnStrings[index++], 1); MinPhase = ParsePhases(columnStrings[index++], 1);
MaxPhase = ParseIntOrDefault(columnStrings[index++], int.MaxValue); MaxPhase = ParsePhases(columnStrings[index++], int.MaxValue);
NormalizePhaseRanges();
if (Weight <= 0)
{
Weight = 1;
}
if (MinPhase <= 0)
{
MinPhase = 1;
}
if (MaxPhase < MinPhase)
{
MaxPhase = MinPhase;
}
return true; return true;
} }
public int GetWeight(RarityType rarity)
{
int index = Mathf.Clamp((int)rarity - 1, 0, RarityCount - 1);
return Weights[index];
}
public int GetMinPhase(RarityType rarity)
{
int index = Mathf.Clamp((int)rarity - 1, 0, RarityCount - 1);
return MinPhase[index];
}
public int GetMaxPhase(RarityType rarity)
{
int index = Mathf.Clamp((int)rarity - 1, 0, RarityCount - 1);
return MaxPhase[index];
}
private static int[] ParseWeights(string raw)
{
if (!raw.StartsWith('[') || !raw.EndsWith(']'))
{
throw new ArgumentException("Weights must be enclosed in square brackets.");
}
if (raw.Length == 2)
{
return new int[RarityCount];
}
string[] raws = raw.Substring(1, raw.Length - 2).Split(",");
if (raws.Length != RarityCount)
{
throw new ArgumentException($"Weights must contain exactly {RarityCount} values.");
}
int[] weights = new int[RarityCount];
for (int i = 0; i < raws.Length; i++)
{
weights[i] = Mathf.Max(0, int.Parse(raws[i]));
}
return weights;
}
private static int[] ParsePhases(string raw, int fallbackValue)
{
if (!raw.StartsWith('[') || !raw.EndsWith(']'))
{
throw new ArgumentException("Phase ranges must be enclosed in square brackets.");
}
if (raw.Length == 2)
{
int[] fallbackValues = new int[RarityCount];
for (int i = 0; i < fallbackValues.Length; i++)
{
fallbackValues[i] = fallbackValue;
}
return fallbackValues;
}
string[] raws = raw.Substring(1, raw.Length - 2).Split(",");
if (raws.Length != RarityCount)
{
throw new ArgumentException($"Phase ranges must contain exactly {RarityCount} values.");
}
int[] phases = new int[RarityCount];
for (int i = 0; i < raws.Length; i++)
{
phases[i] = int.Parse(raws[i]);
}
return phases;
}
private void NormalizePhaseRanges()
{
for (int i = 0; i < RarityCount; i++)
{
if (MinPhase[i] <= 0)
{
MinPhase[i] = 1;
}
if (MaxPhase[i] < MinPhase[i])
{
MaxPhase[i] = MinPhase[i];
}
}
}
private static int ParseIntOrDefault(string raw, int fallbackValue) private static int ParseIntOrDefault(string raw, int fallbackValue)
{ {
if (int.TryParse(raw, out int parsed)) if (int.TryParse(raw, out int parsed))
@ -68,5 +148,7 @@ namespace GeometryTD.DataTable
return fallbackValue; return fallbackValue;
} }
private const int RarityCount = (int)RarityType.Red;
} }
} }

View File

@ -270,7 +270,7 @@ namespace GeometryTD.CustomUtility
AttackPropertyType.None => "无效", AttackPropertyType.None => "无效",
AttackPropertyType.Physics => "<color=#ffff00ff>物理</color>", //yellow AttackPropertyType.Physics => "<color=#ffff00ff>物理</color>", //yellow
AttackPropertyType.Fire => "<color=#ff0000ff>火</color>", //red AttackPropertyType.Fire => "<color=#ff0000ff>火</color>", //red
AttackPropertyType.Water => "<color=#00ffffff>水/color>", //cyan AttackPropertyType.Water => "<color=#00ffffff>水</color>", //cyan
AttackPropertyType.Earth => "<color=#00ff00ff>自然</color>", //lime AttackPropertyType.Earth => "<color=#00ff00ff>自然</color>", //lime
AttackPropertyType.Poison => "<color=#008000ff>毒</color>", //green AttackPropertyType.Poison => "<color=#008000ff>毒</color>", //green
AttackPropertyType.Ice => "<color=#0000a0ff>冰</color>", //darkblue AttackPropertyType.Ice => "<color=#0000a0ff>冰</color>", //darkblue

Binary file not shown.

Binary file not shown.

Binary file not shown.