diff --git a/Assets/GameMain/DataTables/BaseComp.txt b/Assets/GameMain/DataTables/BaseComp.txt index b2d8a39..3410112 100644 --- a/Assets/GameMain/DataTables/BaseComp.txt +++ b/Assets/GameMain/DataTables/BaseComp.txt @@ -4,3 +4,7 @@ 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] 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] diff --git a/Assets/GameMain/DataTables/BearingComp.txt b/Assets/GameMain/DataTables/BearingComp.txt index f7ae8ec..4b19402 100644 --- a/Assets/GameMain/DataTables/BearingComp.txt +++ b/Assets/GameMain/DataTables/BearingComp.txt @@ -4,3 +4,7 @@ 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] 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] diff --git a/Assets/GameMain/DataTables/Entity.txt b/Assets/GameMain/DataTables/Entity.txt index 9a6631a..fe1a33e 100644 --- a/Assets/GameMain/DataTables/Entity.txt +++ b/Assets/GameMain/DataTables/Entity.txt @@ -1,9 +1,6 @@ # Id 策划备注 AssetName # int string # 实体编号 资源名称 - 101 测试枪口 TestMuzzle - 201 测试轴承 TestBearing - 301 测试底座 TestBase 401 防御塔实体 TowerEntity 501 普通子弹 NormalBullet 1001 测试普通敌人 TestEnemy diff --git a/Assets/GameMain/DataTables/MuzzleComp.txt b/Assets/GameMain/DataTables/MuzzleComp.txt index 8085750..a223e11 100644 --- a/Assets/GameMain/DataTables/MuzzleComp.txt +++ b/Assets/GameMain/DataTables/MuzzleComp.txt @@ -4,3 +4,7 @@ 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] 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] diff --git a/Assets/GameMain/DataTables/OutGameDropPool.txt b/Assets/GameMain/DataTables/OutGameDropPool.txt index 1d962e7..1c2d34b 100644 --- a/Assets/GameMain/DataTables/OutGameDropPool.txt +++ b/Assets/GameMain/DataTables/OutGameDropPool.txt @@ -1,48 +1,24 @@ -# Id 列1 LevelThemeType Rarity ItemType ItemId Weight MinPhase MaxPhase -# int LevelThemeType RarityType ItemType int int int int -# 道具池号 策划备注 关卡所属主题类型 道具稀有度 道具类型 道具Id 权重 出现的最低波次 出现的最高波次 - 1 平原战斗池 Plain White MuzzleComp 1 10 1 10 - 2 Plain White MuzzleComp 2 10 1 10 - 3 Plain White MuzzleComp 3 10 1 10 - 4 Plain White BearingComp 1 10 1 10 - 5 Plain White BearingComp 2 10 1 10 - 6 Plain White BearingComp 3 10 1 10 - 7 Plain White BaseComp 1 10 1 10 - 8 Plain White BaseComp 2 10 1 10 - 9 Plain White BaseComp 3 10 1 10 - 10 Plain Green MuzzleComp 1 5 2 10 - 11 Plain Green MuzzleComp 2 5 2 10 - 12 Plain Green MuzzleComp 3 5 2 10 - 13 Plain Green BearingComp 1 5 2 10 - 14 Plain Green BearingComp 2 5 2 10 - 15 Plain Green BearingComp 3 5 2 10 - 16 Plain Green BaseComp 1 5 2 10 - 17 Plain Green BaseComp 2 5 2 10 - 18 Plain Green BaseComp 3 5 2 10 - 19 Plain Blue MuzzleComp 1 3 3 15 - 20 Plain Blue MuzzleComp 2 3 3 15 - 21 Plain Blue MuzzleComp 3 3 3 15 - 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 +# Id 列1 LevelThemeType ItemType ItemId Weights MinPhase MaxPhase +# int LevelThemeType ItemType int int[] int[] int[] +# 道具池号 策划备注 关卡所属主题类型 道具类型 道具Id 权重 出现的最低波次 出现的最高波次 + 1 平原战斗池 Plain MuzzleComp 1 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50] + 2 Plain MuzzleComp 2 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50] + 3 Plain MuzzleComp 3 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50] + 4 Plain MuzzleComp 4 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] + 5 Plain MuzzleComp 5 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] + 6 Plain MuzzleComp 6 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] + 7 Plain MuzzleComp 7 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] + 8 Plain BearingComp 1 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50] + 9 Plain BearingComp 2 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50] + 10 Plain BearingComp 3 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50] + 11 Plain BearingComp 4 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] + 12 Plain BearingComp 5 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] + 13 Plain BearingComp 6 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] + 14 Plain BearingComp 7 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] + 15 Plain BaseComp 1 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50] + 16 Plain BaseComp 2 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50] + 17 Plain BaseComp 3 [20,10,6,4,2] [1,2,3,4,5] [10,10,15,20,50] + 18 Plain BaseComp 4 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] + 19 Plain BaseComp 5 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] + 20 Plain BaseComp 6 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] + 21 Plain BaseComp 7 [15,8,5,3,1] [1,2,3,4,5] [10,10,15,20,50] diff --git a/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/DropPoolRoller.cs b/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/DropPoolRoller.cs index 9964a04..203424c 100644 --- a/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/DropPoolRoller.cs +++ b/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/DropPoolRoller.cs @@ -19,9 +19,14 @@ namespace GeometryTD.CustomComponent _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; + selectedRarity = RarityType.None; DROutGameDropPool[] allRows = _dropPoolTable.GetAllDataRows(); if (allRows == null || allRows.Length <= 0) @@ -35,22 +40,30 @@ namespace GeometryTD.CustomComponent return false; } - RarityType selectedRarity = RollRarity(displayPhaseIndex); + selectedRarity = RollRarity(displayPhaseIndex); if (selectedRarity == RarityType.None) { return false; } int totalWeight = 0; + DROutGameDropPool fallbackRow = null; for (int i = 0; i < _eligibleRowBuffer.Count; i++) { DROutGameDropPool row = _eligibleRowBuffer[i]; - if (row.Rarity != selectedRarity) + if (!IsEligibleAtPhase(row, selectedRarity, displayPhaseIndex)) { continue; } - totalWeight += Mathf.Max(1, row.Weight); + int rowWeight = row.GetWeight(selectedRarity); + if (rowWeight <= 0) + { + continue; + } + + fallbackRow = row; + totalWeight += rowWeight; } if (totalWeight <= 0) @@ -62,12 +75,18 @@ namespace GeometryTD.CustomComponent int cumulativeWeight = 0; foreach (var row in _eligibleRowBuffer) { - if (row.Rarity != selectedRarity) + if (!IsEligibleAtPhase(row, selectedRarity, displayPhaseIndex)) { continue; } - cumulativeWeight += Mathf.Max(1, row.Weight); + int rowWeight = row.GetWeight(selectedRarity); + if (rowWeight <= 0) + { + continue; + } + + cumulativeWeight += rowWeight; if (randomWeight <= cumulativeWeight) { selectedRow = row; @@ -75,7 +94,7 @@ namespace GeometryTD.CustomComponent } } - selectedRow = _eligibleRowBuffer[_eligibleRowBuffer.Count - 1]; + selectedRow = fallbackRow; return selectedRow != null; } @@ -99,7 +118,7 @@ namespace GeometryTD.CustomComponent continue; } - if (displayPhaseIndex < row.MinPhase || displayPhaseIndex > row.MaxPhase) + if (!IsEligibleAtPhase(row, displayPhaseIndex)) { continue; } @@ -116,20 +135,35 @@ namespace GeometryTD.CustomComponent for (int i = 0; i < _eligibleRowBuffer.Count; i++) { DROutGameDropPool row = _eligibleRowBuffer[i]; - float curveWeight = GetRarityCurveWeight(row.Rarity, phaseT); - if (curveWeight <= 0f) + for (int rarityIndex = (int)RarityType.White; rarityIndex <= (int)RarityType.Red; rarityIndex++) { - continue; - } + RarityType rarity = (RarityType)rarityIndex; + if (!IsEligibleAtPhase(row, rarity, displayPhaseIndex)) + { + continue; + } - float rowWeight = Mathf.Max(1, row.Weight) * curveWeight; - if (_rarityWeightBuffer.TryGetValue(row.Rarity, out float existingWeight)) - { - _rarityWeightBuffer[row.Rarity] = existingWeight + rowWeight; - } - else - { - _rarityWeightBuffer[row.Rarity] = rowWeight; + int rowWeight = row.GetWeight(rarity); + if (rowWeight <= 0) + { + continue; + } + + float curveWeight = GetRarityCurveWeight(rarity, phaseT); + if (curveWeight <= 0f) + { + continue; + } + + float rarityWeight = rowWeight * curveWeight; + if (_rarityWeightBuffer.TryGetValue(rarity, out float existingWeight)) + { + _rarityWeightBuffer[rarity] = existingWeight + rarityWeight; + } + else + { + _rarityWeightBuffer[rarity] = rarityWeight; + } } } @@ -163,6 +197,32 @@ namespace GeometryTD.CustomComponent 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) { float hump = Mathf.Exp(-Mathf.Pow((phaseT - 0.35f) / 0.28f, 2f)); @@ -183,4 +243,4 @@ namespace GeometryTD.CustomComponent } } } -} \ No newline at end of file +} diff --git a/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/InventoryGenerationComponent.cs b/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/InventoryGenerationComponent.cs index 6799808..c26f97c 100644 --- a/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/InventoryGenerationComponent.cs +++ b/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/InventoryGenerationComponent.cs @@ -183,16 +183,26 @@ namespace GeometryTD.CustomComponent droppedItem = null; DropPoolRoller dropPoolRoller = EnsureDropPoolRoller(); 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 TryBuildDropItem(selectedRow, InventoryTagSourceType.Drop, AllocateDropTagOrdinal(), out droppedItem); + return TryBuildDropItem( + selectedRow, + selectedRarity, + InventoryTagSourceType.Drop, + AllocateDropTagOrdinal(), + out droppedItem); } private bool TryBuildDropItem( DROutGameDropPool row, + RarityType rarity, InventoryTagSourceType sourceType, int localOrdinal, out TowerCompItemData droppedItem) @@ -215,7 +225,7 @@ namespace GeometryTD.CustomComponent droppedItem = ComponentItemFactory.CreateMuzzle( config, AllocateTempInstanceId(), - row.Rarity, + rarity, CreateRandomContext(sourceType, localOrdinal, config.Id)); return true; } @@ -231,7 +241,7 @@ namespace GeometryTD.CustomComponent droppedItem = ComponentItemFactory.CreateBearing( config, AllocateTempInstanceId(), - row.Rarity, + rarity, CreateRandomContext(sourceType, localOrdinal, config.Id)); return true; } @@ -247,7 +257,7 @@ namespace GeometryTD.CustomComponent droppedItem = ComponentItemFactory.CreateBase( config, AllocateTempInstanceId(), - row.Rarity, + rarity, CreateRandomContext(sourceType, localOrdinal, config.Id)); return true; } @@ -265,9 +275,14 @@ namespace GeometryTD.CustomComponent 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; } diff --git a/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/RewardCandidateBuilder.cs b/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/RewardCandidateBuilder.cs index e3abe08..545b4fa 100644 --- a/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/RewardCandidateBuilder.cs +++ b/Assets/GameMain/Scripts/CustomComponent/InventoryGeneration/RewardCandidateBuilder.cs @@ -19,7 +19,7 @@ namespace GeometryTD.CustomComponent int displayPhaseIndex, LevelThemeType themeType, int candidateCount, - Func buildRewardItem) + Func buildRewardItem) { int resolvedCount = Mathf.Max(0, candidateCount); if (resolvedCount <= 0) @@ -28,7 +28,7 @@ namespace GeometryTD.CustomComponent } List candidates = new List(resolvedCount); - HashSet selectedPoolRowIds = new HashSet(); + HashSet selectedPoolEntryKeys = new HashSet(); int maxAttempts = Mathf.Max(resolvedCount * 6, resolvedCount); int phaseIndex = Mathf.Max(1, displayPhaseIndex); @@ -36,17 +36,21 @@ namespace GeometryTD.CustomComponent while (candidates.Count < resolvedCount && attempts < maxAttempts) { 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; } - if (!selectedPoolRowIds.Add(selectedRow.Id)) + if (!selectedPoolEntryKeys.Add(BuildSelectionKey(selectedRow.Id, selectedRarity))) { continue; } - TowerCompItemData candidate = buildRewardItem(selectedRow); + TowerCompItemData candidate = buildRewardItem(selectedRow, selectedRarity); if (candidate == null) { continue; @@ -59,12 +63,16 @@ namespace GeometryTD.CustomComponent while (candidates.Count < resolvedCount && attempts < maxAttempts) { 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; } - TowerCompItemData candidate = buildRewardItem(selectedRow); + TowerCompItemData candidate = buildRewardItem(selectedRow, selectedRarity); if (candidate == null) { continue; @@ -75,5 +83,10 @@ namespace GeometryTD.CustomComponent return candidates; } + + private static long BuildSelectionKey(int rowId, RarityType rarity) + { + return ((long)rowId << 32) | (uint)rarity; + } } } diff --git a/Assets/GameMain/Scripts/DataTable/DROutGameDropPool.cs b/Assets/GameMain/Scripts/DataTable/DROutGameDropPool.cs index c4a0e6a..6972bed 100644 --- a/Assets/GameMain/Scripts/DataTable/DROutGameDropPool.cs +++ b/Assets/GameMain/Scripts/DataTable/DROutGameDropPool.cs @@ -1,5 +1,7 @@ +using System; using GeometryTD.CustomUtility; using GeometryTD.Definition; +using UnityEngine; using UnityGameFramework.Runtime; namespace GeometryTD.DataTable @@ -14,12 +16,11 @@ namespace GeometryTD.DataTable public override int Id => m_Id; public LevelThemeType LevelThemeType { get; private set; } - public RarityType Rarity { get; private set; } public string ItemType { get; private set; } public int ItemId { get; private set; } - public int Weight { get; private set; } - public int MinPhase { get; private set; } - public int MaxPhase { get; private set; } + public int[] Weights { get; private set; } + public int[] MinPhase { get; private set; } + public int[] MaxPhase { get; private set; } public override bool ParseDataRow(string dataRowString, object userData) { @@ -34,31 +35,110 @@ namespace GeometryTD.DataTable m_Id = int.Parse(columnStrings[index++]); index++; LevelThemeType = EnumUtility.Get(columnStrings[index++]); - Rarity = EnumUtility.Get(columnStrings[index++]); ItemType = columnStrings[index++]; ItemId = ParseIntOrDefault(columnStrings[index++], 0); - Weight = ParseIntOrDefault(columnStrings[index++], 1); - MinPhase = ParseIntOrDefault(columnStrings[index++], 1); - MaxPhase = ParseIntOrDefault(columnStrings[index++], int.MaxValue); - - if (Weight <= 0) - { - Weight = 1; - } - - if (MinPhase <= 0) - { - MinPhase = 1; - } - - if (MaxPhase < MinPhase) - { - MaxPhase = MinPhase; - } + Weights = ParseWeights(columnStrings[index++]); + MinPhase = ParsePhases(columnStrings[index++], 1); + MaxPhase = ParsePhases(columnStrings[index++], int.MaxValue); + NormalizePhaseRanges(); 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) { if (int.TryParse(raw, out int parsed)) @@ -68,5 +148,7 @@ namespace GeometryTD.DataTable return fallbackValue; } + + private const int RarityCount = (int)RarityType.Red; } } diff --git a/Assets/GameMain/Scripts/Utility/ItemDescUtility.cs b/Assets/GameMain/Scripts/Utility/ItemDescUtility.cs index 8031d5b..5fa5888 100644 --- a/Assets/GameMain/Scripts/Utility/ItemDescUtility.cs +++ b/Assets/GameMain/Scripts/Utility/ItemDescUtility.cs @@ -270,7 +270,7 @@ namespace GeometryTD.CustomUtility AttackPropertyType.None => "无效", AttackPropertyType.Physics => "物理", //yellow AttackPropertyType.Fire => "火", //red - AttackPropertyType.Water => "水/color>", //cyan + AttackPropertyType.Water => "水", //cyan AttackPropertyType.Earth => "自然", //lime AttackPropertyType.Poison => "毒", //green AttackPropertyType.Ice => "冰", //darkblue diff --git a/数据表/Entity.xlsx b/数据表/Entity.xlsx index 545c055..ceb0c61 100644 Binary files a/数据表/Entity.xlsx and b/数据表/Entity.xlsx differ diff --git a/数据表/OutGameDropPool.xlsx b/数据表/OutGameDropPool.xlsx index a1620bf..d9a9a10 100644 Binary files a/数据表/OutGameDropPool.xlsx and b/数据表/OutGameDropPool.xlsx differ diff --git a/数据表/TowerComp.xlsx b/数据表/TowerComp.xlsx index e1caaeb..c69822f 100644 Binary files a/数据表/TowerComp.xlsx and b/数据表/TowerComp.xlsx differ