S7-01 + S7-02
This commit is contained in:
parent
d34af661b9
commit
185ea43323
|
|
@ -178,6 +178,7 @@ namespace GeometryTD.CustomComponent
|
|||
public void StartCombat(
|
||||
int levelId = 0,
|
||||
string runId = null,
|
||||
int runSeed = 0,
|
||||
int nodeId = 0,
|
||||
RunNodeType nodeType = RunNodeType.None,
|
||||
int sequenceIndex = -1)
|
||||
|
|
@ -232,6 +233,7 @@ namespace GeometryTD.CustomComponent
|
|||
phaseList,
|
||||
_selectedSpawnEntriesByPhaseId,
|
||||
runId,
|
||||
runSeed,
|
||||
nodeId,
|
||||
nodeType,
|
||||
sequenceIndex))
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ namespace GeometryTD.CustomComponent
|
|||
IReadOnlyList<DRLevelPhase> phases,
|
||||
IReadOnlyDictionary<int, IReadOnlyList<DRLevelSpawnEntry>> spawnEntriesByPhaseId,
|
||||
string runId = null,
|
||||
int runSeed = 0,
|
||||
int nodeId = 0,
|
||||
RunNodeType nodeType = RunNodeType.None,
|
||||
int sequenceIndex = -1)
|
||||
|
|
@ -95,9 +96,11 @@ namespace GeometryTD.CustomComponent
|
|||
|
||||
_runtime.CurrentLevel = level;
|
||||
_runtime.RunId = runId;
|
||||
_runtime.RunSeed = runSeed;
|
||||
_runtime.NodeId = nodeId;
|
||||
_runtime.NodeType = nodeType;
|
||||
_runtime.SequenceIndex = sequenceIndex;
|
||||
_runtime.EnemyDropResolver.ConfigureRunContext(runSeed, sequenceIndex);
|
||||
_runtime.CombatRunResourceStore.InitializeForCombat(level);
|
||||
for (int i = 0; i < phases.Count; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ namespace GeometryTD.CustomComponent
|
|||
_runtime.IsCompleted = false;
|
||||
_runtime.NodeEnterFired = false;
|
||||
_runtime.RunId = null;
|
||||
_runtime.RunSeed = 0;
|
||||
_runtime.NodeId = 0;
|
||||
_runtime.NodeType = RunNodeType.None;
|
||||
_runtime.SequenceIndex = -1;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ namespace GeometryTD.CustomComponent
|
|||
public bool NodeEnterFired { get; set; }
|
||||
public CombatSettlementContext SettlementContext { get; set; }
|
||||
public string RunId { get; set; }
|
||||
public int RunSeed { get; set; }
|
||||
public int NodeId { get; set; }
|
||||
public RunNodeType NodeType { get; set; }
|
||||
public int SequenceIndex { get; set; }
|
||||
|
|
|
|||
|
|
@ -22,12 +22,28 @@ namespace GeometryTD.CustomComponent
|
|||
private IDataTable<DRBearingComp> _drBearingComp;
|
||||
private IDataTable<DRBaseComp> _drBaseComp;
|
||||
private long _nextDropItemInstanceId = 1;
|
||||
private int _runSeed;
|
||||
private int _nodeSequenceIndex = -1;
|
||||
private int _nextDropTagOrdinal;
|
||||
private int _nextRewardTagOrdinal;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_eligibleDropPoolBuffer.Clear();
|
||||
_rarityRollWeightBuffer.Clear();
|
||||
_nextDropItemInstanceId = 1;
|
||||
_runSeed = 0;
|
||||
_nodeSequenceIndex = -1;
|
||||
_nextDropTagOrdinal = 0;
|
||||
_nextRewardTagOrdinal = 0;
|
||||
}
|
||||
|
||||
public void ConfigureRunContext(int runSeed, int nodeSequenceIndex)
|
||||
{
|
||||
_runSeed = runSeed;
|
||||
_nodeSequenceIndex = nodeSequenceIndex;
|
||||
_nextDropTagOrdinal = 0;
|
||||
_nextRewardTagOrdinal = 0;
|
||||
}
|
||||
|
||||
public EnemyDropResult Resolve(in EnemyDropContext context)
|
||||
|
|
@ -90,7 +106,7 @@ namespace GeometryTD.CustomComponent
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!TryBuildDropItem(selectedRow, out TowerCompItemData droppedItem) || droppedItem == null)
|
||||
if (!TryBuildDropItem(selectedRow, InventoryTagSourceType.Reward, AllocateRewardTagOrdinal(), out TowerCompItemData droppedItem) || droppedItem == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -129,7 +145,7 @@ namespace GeometryTD.CustomComponent
|
|||
return false;
|
||||
}
|
||||
|
||||
return TryBuildDropItem(selectedRow, out droppedItem);
|
||||
return TryBuildDropItem(selectedRow, InventoryTagSourceType.Drop, AllocateDropTagOrdinal(), out droppedItem);
|
||||
}
|
||||
|
||||
private bool TryPickDropPoolRow(int displayPhaseIndex, LevelThemeType themeType, out DROutGameDropPool selectedRow)
|
||||
|
|
@ -303,7 +319,11 @@ namespace GeometryTD.CustomComponent
|
|||
return _drOutGameDropPool;
|
||||
}
|
||||
|
||||
private bool TryBuildDropItem(DROutGameDropPool row, out TowerCompItemData droppedItem)
|
||||
private bool TryBuildDropItem(
|
||||
DROutGameDropPool row,
|
||||
InventoryTagSourceType sourceType,
|
||||
int localOrdinal,
|
||||
out TowerCompItemData droppedItem)
|
||||
{
|
||||
droppedItem = null;
|
||||
if (row == null || row.ItemId <= 0 || string.IsNullOrWhiteSpace(row.ItemType))
|
||||
|
|
@ -314,23 +334,27 @@ namespace GeometryTD.CustomComponent
|
|||
string itemType = row.ItemType.Trim();
|
||||
if (itemType.Equals("MuzzleComp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return TryBuildMuzzleCompItem(row, out droppedItem);
|
||||
return TryBuildMuzzleCompItem(row, sourceType, localOrdinal, out droppedItem);
|
||||
}
|
||||
|
||||
if (itemType.Equals("BearingComp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return TryBuildBearingCompItem(row, out droppedItem);
|
||||
return TryBuildBearingCompItem(row, sourceType, localOrdinal, out droppedItem);
|
||||
}
|
||||
|
||||
if (itemType.Equals("BaseComp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return TryBuildBaseCompItem(row, out droppedItem);
|
||||
return TryBuildBaseCompItem(row, sourceType, localOrdinal, out droppedItem);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryBuildMuzzleCompItem(DROutGameDropPool row, out TowerCompItemData droppedItem)
|
||||
private bool TryBuildMuzzleCompItem(
|
||||
DROutGameDropPool row,
|
||||
InventoryTagSourceType sourceType,
|
||||
int localOrdinal,
|
||||
out TowerCompItemData droppedItem)
|
||||
{
|
||||
droppedItem = null;
|
||||
_drMuzzleComp ??= GameEntry.DataTable.GetDataTable<DRMuzzleComp>();
|
||||
|
|
@ -358,9 +382,7 @@ namespace GeometryTD.CustomComponent
|
|||
Tags = ComponentTagGenerationService.ResolveComponentTags(
|
||||
config.PossibleTag,
|
||||
rarity,
|
||||
InventoryTagSourceType.Drop,
|
||||
instanceId,
|
||||
config.Id),
|
||||
CreateRandomContext(sourceType, localOrdinal, config.Id)),
|
||||
AttackDamage = config.AttackDamage != null ? (int[])config.AttackDamage.Clone() : Array.Empty<int>(),
|
||||
DamageRandomRate = config.DamageRandomRate,
|
||||
AttackMethodType = config.AttackMethodType
|
||||
|
|
@ -368,7 +390,11 @@ namespace GeometryTD.CustomComponent
|
|||
return true;
|
||||
}
|
||||
|
||||
private bool TryBuildBearingCompItem(DROutGameDropPool row, out TowerCompItemData droppedItem)
|
||||
private bool TryBuildBearingCompItem(
|
||||
DROutGameDropPool row,
|
||||
InventoryTagSourceType sourceType,
|
||||
int localOrdinal,
|
||||
out TowerCompItemData droppedItem)
|
||||
{
|
||||
droppedItem = null;
|
||||
_drBearingComp ??= GameEntry.DataTable.GetDataTable<DRBearingComp>();
|
||||
|
|
@ -396,16 +422,18 @@ namespace GeometryTD.CustomComponent
|
|||
Tags = ComponentTagGenerationService.ResolveComponentTags(
|
||||
config.PossibleTag,
|
||||
rarity,
|
||||
InventoryTagSourceType.Drop,
|
||||
instanceId,
|
||||
config.Id),
|
||||
CreateRandomContext(sourceType, localOrdinal, config.Id)),
|
||||
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)
|
||||
private bool TryBuildBaseCompItem(
|
||||
DROutGameDropPool row,
|
||||
InventoryTagSourceType sourceType,
|
||||
int localOrdinal,
|
||||
out TowerCompItemData droppedItem)
|
||||
{
|
||||
droppedItem = null;
|
||||
_drBaseComp ??= GameEntry.DataTable.GetDataTable<DRBaseComp>();
|
||||
|
|
@ -433,13 +461,33 @@ namespace GeometryTD.CustomComponent
|
|||
Tags = ComponentTagGenerationService.ResolveComponentTags(
|
||||
config.PossibleTag,
|
||||
rarity,
|
||||
InventoryTagSourceType.Drop,
|
||||
instanceId,
|
||||
config.Id),
|
||||
CreateRandomContext(sourceType, localOrdinal, config.Id)),
|
||||
AttackSpeed = config.AttackSpeed != null ? (float[])config.AttackSpeed.Clone() : Array.Empty<float>(),
|
||||
AttackPropertyType = config.AttackPropertyType
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
private InventoryTagRandomContext CreateRandomContext(
|
||||
InventoryTagSourceType sourceType,
|
||||
int localOrdinal,
|
||||
int configId)
|
||||
{
|
||||
return sourceType switch
|
||||
{
|
||||
InventoryTagSourceType.Reward => InventoryTagRandomContext.CreateReward(_runSeed, _nodeSequenceIndex, localOrdinal, configId),
|
||||
_ => InventoryTagRandomContext.CreateDrop(_runSeed, _nodeSequenceIndex, localOrdinal, configId)
|
||||
};
|
||||
}
|
||||
|
||||
private int AllocateDropTagOrdinal()
|
||||
{
|
||||
return _nextDropTagOrdinal++;
|
||||
}
|
||||
|
||||
private int AllocateRewardTagOrdinal()
|
||||
{
|
||||
return _nextRewardTagOrdinal++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@ namespace GeometryTD.CustomComponent
|
|||
}
|
||||
}
|
||||
|
||||
public void OnInit()
|
||||
public void OnInit(BackpackInventoryData initialInventory = null)
|
||||
{
|
||||
EnsureServices();
|
||||
_commandModel.Initialize(InventorySeedUtility.CreateSampleInventory(), MaxParticipantTowerCount);
|
||||
_commandModel.Initialize(initialInventory ?? InventorySeedUtility.CreateSampleInventory(), MaxParticipantTowerCount);
|
||||
|
||||
BackpackInventoryData inventory = _queryModel.Inventory;
|
||||
Log.Info(
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ namespace GeometryTD.CustomComponent
|
|||
public class ShopNodeComponent : GameFrameworkComponent
|
||||
{
|
||||
private string _activeRunId;
|
||||
private int _activeRunSeed;
|
||||
private int _activeNodeId;
|
||||
private RunNodeType _activeNodeType = RunNodeType.None;
|
||||
private int _activeSequenceIndex = -1;
|
||||
|
|
@ -28,20 +29,21 @@ namespace GeometryTD.CustomComponent
|
|||
_initialized = true;
|
||||
}
|
||||
|
||||
public void StartShop(string runId = null, int nodeId = 0, RunNodeType nodeType = RunNodeType.None, int sequenceIndex = -1)
|
||||
public void StartShop(string runId = null, int runSeed = 0, int nodeId = 0, RunNodeType nodeType = RunNodeType.None, int sequenceIndex = -1)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
OnInit();
|
||||
}
|
||||
|
||||
if (_shopFormUseCase == null || !_shopFormUseCase.PrepareForOpen())
|
||||
if (_shopFormUseCase == null || !_shopFormUseCase.PrepareForOpen(runSeed, sequenceIndex))
|
||||
{
|
||||
Log.Warning("ShopNodeComponent.StartShop() failed. Shop use case is unavailable or goods generation failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
_activeRunId = runId;
|
||||
_activeRunSeed = runSeed;
|
||||
_activeNodeId = nodeId;
|
||||
_activeNodeType = nodeType;
|
||||
_activeSequenceIndex = sequenceIndex;
|
||||
|
|
@ -68,6 +70,7 @@ namespace GeometryTD.CustomComponent
|
|||
private void ClearActiveNodeContext()
|
||||
{
|
||||
_activeRunId = null;
|
||||
_activeRunSeed = 0;
|
||||
_activeNodeId = 0;
|
||||
_activeNodeType = RunNodeType.None;
|
||||
_activeSequenceIndex = -1;
|
||||
|
|
|
|||
|
|
@ -10,9 +10,7 @@ namespace GeometryTD.Definition
|
|||
public static TagType[] ResolveComponentTags(
|
||||
IReadOnlyList<TagType> possibleTags,
|
||||
RarityType rarity,
|
||||
InventoryTagSourceType sourceType,
|
||||
long itemInstanceId,
|
||||
int configId,
|
||||
InventoryTagRandomContext randomContext,
|
||||
IReadOnlyDictionary<TagType, TagGenerationRule> rulesByTag = null,
|
||||
IReadOnlyDictionary<RarityType, RarityTagBudgetRule> rarityTagBudgetRulesByRarity = null)
|
||||
{
|
||||
|
|
@ -23,7 +21,7 @@ namespace GeometryTD.Definition
|
|||
return Array.Empty<TagType>();
|
||||
}
|
||||
|
||||
Random random = new Random(BuildStableSeed(rarity, sourceType, itemInstanceId, configId));
|
||||
Random random = new Random(BuildStableSeed(rarity, randomContext));
|
||||
int tagBudget = ResolveRarityTagBudget(rarity, random, rarityTagBudgetRulesByRarity);
|
||||
if (tagBudget <= 0)
|
||||
{
|
||||
|
|
@ -43,6 +41,23 @@ namespace GeometryTD.Definition
|
|||
return result;
|
||||
}
|
||||
|
||||
public static TagType[] ResolveComponentTags(
|
||||
IReadOnlyList<TagType> possibleTags,
|
||||
RarityType rarity,
|
||||
InventoryTagSourceType sourceType,
|
||||
long itemInstanceId,
|
||||
int configId,
|
||||
IReadOnlyDictionary<TagType, TagGenerationRule> rulesByTag = null,
|
||||
IReadOnlyDictionary<RarityType, RarityTagBudgetRule> rarityTagBudgetRulesByRarity = null)
|
||||
{
|
||||
return ResolveComponentTags(
|
||||
possibleTags,
|
||||
rarity,
|
||||
new InventoryTagRandomContext(0, sourceType, itemInstanceId, configId),
|
||||
rulesByTag,
|
||||
rarityTagBudgetRulesByRarity);
|
||||
}
|
||||
|
||||
public static TagType[] GetEligibleTags(
|
||||
IReadOnlyList<TagType> possibleTags,
|
||||
RarityType rarity,
|
||||
|
|
@ -170,20 +185,17 @@ namespace GeometryTD.Definition
|
|||
return pool.Count - 1;
|
||||
}
|
||||
|
||||
private static int BuildStableSeed(
|
||||
RarityType rarity,
|
||||
InventoryTagSourceType sourceType,
|
||||
long itemInstanceId,
|
||||
int configId)
|
||||
private static int BuildStableSeed(RarityType rarity, InventoryTagRandomContext randomContext)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int seed = 17;
|
||||
seed = seed * 31 + randomContext.RunSeed;
|
||||
seed = seed * 31 + (int)InventoryRarityRuleService.NormalizeComponentRarity(rarity);
|
||||
seed = seed * 31 + (int)sourceType;
|
||||
seed = seed * 31 + configId;
|
||||
seed = seed * 31 + (int)itemInstanceId;
|
||||
seed = seed * 31 + (int)(itemInstanceId >> 32);
|
||||
seed = seed * 31 + (int)randomContext.SourceType;
|
||||
seed = seed * 31 + randomContext.ConfigId;
|
||||
seed = seed * 31 + (int)randomContext.ItemInstanceId;
|
||||
seed = seed * 31 + (int)(randomContext.ItemInstanceId >> 32);
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
|
||||
namespace GeometryTD.Definition
|
||||
{
|
||||
[Serializable]
|
||||
public readonly struct InventoryTagRandomContext
|
||||
{
|
||||
public InventoryTagRandomContext(int runSeed, InventoryTagSourceType sourceType, long itemInstanceId, int configId)
|
||||
{
|
||||
RunSeed = runSeed;
|
||||
SourceType = sourceType;
|
||||
ItemInstanceId = itemInstanceId;
|
||||
ConfigId = configId;
|
||||
}
|
||||
|
||||
public int RunSeed { get; }
|
||||
|
||||
public InventoryTagSourceType SourceType { get; }
|
||||
|
||||
public long ItemInstanceId { get; }
|
||||
|
||||
public int ConfigId { get; }
|
||||
|
||||
public static InventoryTagRandomContext CreateSeed(int runSeed, long itemInstanceId, int configId)
|
||||
{
|
||||
return new InventoryTagRandomContext(runSeed, InventoryTagSourceType.Seed, itemInstanceId, configId);
|
||||
}
|
||||
|
||||
public static InventoryTagRandomContext CreateShop(int runSeed, int nodeSequenceIndex, int goodsIndex, int configId)
|
||||
{
|
||||
return new InventoryTagRandomContext(
|
||||
runSeed,
|
||||
InventoryTagSourceType.Shop,
|
||||
ComposeLocalItemInstanceId(nodeSequenceIndex, goodsIndex),
|
||||
configId);
|
||||
}
|
||||
|
||||
public static InventoryTagRandomContext CreateDrop(int runSeed, int nodeSequenceIndex, int dropOrdinal, int configId)
|
||||
{
|
||||
return new InventoryTagRandomContext(
|
||||
runSeed,
|
||||
InventoryTagSourceType.Drop,
|
||||
ComposeLocalItemInstanceId(nodeSequenceIndex, dropOrdinal),
|
||||
configId);
|
||||
}
|
||||
|
||||
public static InventoryTagRandomContext CreateReward(int runSeed, int nodeSequenceIndex, int rewardOrdinal, int configId)
|
||||
{
|
||||
return new InventoryTagRandomContext(
|
||||
runSeed,
|
||||
InventoryTagSourceType.Reward,
|
||||
ComposeLocalItemInstanceId(nodeSequenceIndex, rewardOrdinal),
|
||||
configId);
|
||||
}
|
||||
|
||||
public static long ComposeLocalItemInstanceId(int nodeSequenceIndex, int localOrdinal)
|
||||
{
|
||||
long normalizedSequence = Math.Max(0, nodeSequenceIndex) + 1L;
|
||||
long normalizedOrdinal = Math.Max(0, localOrdinal) + 1L;
|
||||
return (normalizedSequence << 32) | (uint)normalizedOrdinal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8d4f8e95f2f94e4ca876ff4c871f5b41
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -22,11 +22,7 @@ namespace GeometryTD.Definition
|
|||
|
||||
public static void LoadFromRows(IEnumerable<DRTagConfig> rows)
|
||||
{
|
||||
ResetToDefaults();
|
||||
foreach (DRTagConfig row in rows)
|
||||
{
|
||||
ApplyRow(row);
|
||||
}
|
||||
ReloadFromRows(rows, null);
|
||||
}
|
||||
|
||||
public static bool TryGetDefinition(TagType tagType, out TagDefinition definition)
|
||||
|
|
@ -47,6 +43,27 @@ namespace GeometryTD.Definition
|
|||
}
|
||||
}
|
||||
|
||||
public static void ReloadFromRows(IEnumerable<DRTagConfig> tagConfigRows, IEnumerable<DRTag> tagRows)
|
||||
{
|
||||
ResetToDefaults();
|
||||
|
||||
if (tagConfigRows != null)
|
||||
{
|
||||
foreach (DRTagConfig row in tagConfigRows)
|
||||
{
|
||||
ApplyRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
if (tagRows != null)
|
||||
{
|
||||
foreach (DRTag row in tagRows)
|
||||
{
|
||||
ApplyTagRow(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<TagType, TagDefinition> CreateDefaultDefinitions()
|
||||
{
|
||||
return new Dictionary<TagType, TagDefinition>
|
||||
|
|
|
|||
|
|
@ -199,22 +199,12 @@ namespace GeometryTD.Procedure
|
|||
|
||||
if (ne.DataTableAssetName == AssetUtility.GetDataTableAsset("TagConfig", false))
|
||||
{
|
||||
var tagConfigTable = GameEntry.DataTable.GetDataTable<DRTagConfig>();
|
||||
if (tagConfigTable != null)
|
||||
{
|
||||
TagDefinitionRegistry.LoadFromRows(tagConfigTable.GetAllDataRows());
|
||||
}
|
||||
ReloadTagRegistriesFromLoadedTables();
|
||||
}
|
||||
|
||||
if (ne.DataTableAssetName == AssetUtility.GetDataTableAsset("Tag", false))
|
||||
{
|
||||
var tagTable = GameEntry.DataTable.GetDataTable<DRTag>();
|
||||
if (tagTable != null)
|
||||
{
|
||||
DRTag[] rows = tagTable.GetAllDataRows();
|
||||
TagGenerationRuleRegistry.LoadFromRows(rows);
|
||||
TagDefinitionRegistry.ApplyTagRows(rows);
|
||||
}
|
||||
ReloadTagRegistriesFromLoadedTables();
|
||||
}
|
||||
|
||||
if (ne.DataTableAssetName == AssetUtility.GetDataTableAsset("RarityTagBudget", false))
|
||||
|
|
@ -227,6 +217,26 @@ namespace GeometryTD.Procedure
|
|||
}
|
||||
}
|
||||
|
||||
private static void ReloadTagRegistriesFromLoadedTables()
|
||||
{
|
||||
DRTagConfig[] tagConfigRows = null;
|
||||
var tagConfigTable = GameEntry.DataTable.GetDataTable<DRTagConfig>();
|
||||
if (tagConfigTable != null)
|
||||
{
|
||||
tagConfigRows = tagConfigTable.GetAllDataRows();
|
||||
}
|
||||
|
||||
DRTag[] tagRows = null;
|
||||
var tagTable = GameEntry.DataTable.GetDataTable<DRTag>();
|
||||
if (tagTable != null)
|
||||
{
|
||||
tagRows = tagTable.GetAllDataRows();
|
||||
TagGenerationRuleRegistry.LoadFromRows(tagRows);
|
||||
}
|
||||
|
||||
TagDefinitionRegistry.ReloadFromRows(tagConfigRows, tagRows);
|
||||
}
|
||||
|
||||
private void OnLoadDataTableFailure(object sender, GameEventArgs e)
|
||||
{
|
||||
LoadDataTableFailureEventArgs ne = (LoadDataTableFailureEventArgs)e;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
using GameFramework.Event;
|
||||
using GameFramework.Fsm;
|
||||
using GameFramework.Procedure;
|
||||
using System;
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.CustomUtility;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
|
@ -34,13 +36,19 @@ namespace GeometryTD.Procedure
|
|||
GameEntry.EventNode.OnInit();
|
||||
GameEntry.CombatNode.OnInit(LevelThemeType.Plain);
|
||||
GameEntry.ShopNode.OnInit();
|
||||
GameEntry.PlayerInventory?.OnInit();
|
||||
|
||||
string runId = Guid.NewGuid().ToString("N");
|
||||
int runSeed = RunStateFactory.CreateRunSeed();
|
||||
BackpackInventoryData initialInventory = InventorySeedUtility.CreateSampleInventory(runSeed);
|
||||
GameEntry.PlayerInventory?.OnInit(initialInventory);
|
||||
|
||||
_currentRunState = RunStateFactory.CreateFixedRun(
|
||||
LevelThemeType.Plain,
|
||||
GameEntry.PlayerInventory != null
|
||||
? GameEntry.PlayerInventory.GetInventorySnapshot()
|
||||
: null);
|
||||
: initialInventory,
|
||||
runId,
|
||||
runSeed);
|
||||
|
||||
_repoFormUseCase = new RepoFormUseCase();
|
||||
GameEntry.UIRouter.BindUIUseCase(UIFormType.RepoForm, _repoFormUseCase);
|
||||
|
|
@ -259,6 +267,7 @@ namespace GeometryTD.Procedure
|
|||
GameEntry.CombatNode.StartCombat(
|
||||
currentNode.LinkedLevelId,
|
||||
_currentRunState.RunId,
|
||||
_currentRunState.RunSeed,
|
||||
currentNode.NodeId,
|
||||
currentNode.NodeType,
|
||||
currentNode.SequenceIndex);
|
||||
|
|
@ -273,6 +282,7 @@ namespace GeometryTD.Procedure
|
|||
case RunNodeType.Shop:
|
||||
GameEntry.ShopNode.StartShop(
|
||||
_currentRunState.RunId,
|
||||
_currentRunState.RunSeed,
|
||||
currentNode.NodeId,
|
||||
currentNode.NodeType,
|
||||
currentNode.SequenceIndex);
|
||||
|
|
|
|||
|
|
@ -71,11 +71,13 @@ namespace GeometryTD.Procedure
|
|||
|
||||
internal RunState(
|
||||
string runId,
|
||||
int runSeed,
|
||||
LevelThemeType themeType,
|
||||
List<RunNodeState> nodes,
|
||||
BackpackInventoryData runInventorySnapshot)
|
||||
{
|
||||
RunId = string.IsNullOrWhiteSpace(runId) ? Guid.NewGuid().ToString("N") : runId;
|
||||
RunSeed = runSeed == 0 ? RunStateFactory.CreateRunSeed() : runSeed;
|
||||
ThemeType = themeType;
|
||||
_nodes = nodes ?? new List<RunNodeState>();
|
||||
RunInventorySnapshot = InventoryCloneUtility.CloneInventory(runInventorySnapshot);
|
||||
|
|
@ -85,6 +87,8 @@ namespace GeometryTD.Procedure
|
|||
|
||||
public string RunId { get; internal set; }
|
||||
|
||||
public int RunSeed { get; internal set; }
|
||||
|
||||
public LevelThemeType ThemeType { get; internal set; }
|
||||
|
||||
public int CurrentNodeIndex { get; internal set; }
|
||||
|
|
|
|||
|
|
@ -8,17 +8,19 @@ namespace GeometryTD.Procedure
|
|||
public static RunState CreateFixedRun(
|
||||
LevelThemeType themeType,
|
||||
BackpackInventoryData initialInventorySnapshot,
|
||||
string runId = null)
|
||||
string runId = null,
|
||||
int runSeed = 0)
|
||||
{
|
||||
IReadOnlyList<RunNodeSeed> fixedNodeSeeds = FixedRunNodeSequenceBuilder.Build(themeType);
|
||||
return Create(themeType, initialInventorySnapshot, fixedNodeSeeds, runId);
|
||||
return Create(themeType, initialInventorySnapshot, fixedNodeSeeds, runId, runSeed);
|
||||
}
|
||||
|
||||
public static RunState Create(
|
||||
LevelThemeType themeType,
|
||||
BackpackInventoryData initialInventorySnapshot,
|
||||
IEnumerable<RunNodeSeed> nodeSeeds,
|
||||
string runId = null)
|
||||
string runId = null,
|
||||
int runSeed = 0)
|
||||
{
|
||||
List<RunNodeState> nodes = new List<RunNodeState>();
|
||||
if (nodeSeeds != null)
|
||||
|
|
@ -44,7 +46,13 @@ namespace GeometryTD.Procedure
|
|||
}
|
||||
}
|
||||
|
||||
return new RunState(runId, themeType, nodes, initialInventorySnapshot);
|
||||
return new RunState(runId, runSeed, themeType, nodes, initialInventorySnapshot);
|
||||
}
|
||||
|
||||
public static int CreateRunSeed()
|
||||
{
|
||||
int seed = System.Guid.NewGuid().GetHashCode();
|
||||
return seed == 0 ? 1 : seed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ namespace GeometryTD.UI
|
|||
{
|
||||
private const int GoodsCount = 4;
|
||||
private long _nextTempInstanceId = 1000000;
|
||||
private int _activeRunSeed;
|
||||
private int _activeSequenceIndex = -1;
|
||||
|
||||
private readonly List<GoodsItemRawData> _currentGoods = new List<GoodsItemRawData>(GoodsCount);
|
||||
private readonly List<DRShopPrice> _shopPriceRows = new List<DRShopPrice>();
|
||||
|
|
@ -21,13 +23,15 @@ namespace GeometryTD.UI
|
|||
private IDataTable<DRBearingComp> _bearingCompTable;
|
||||
private IDataTable<DRBaseComp> _baseCompTable;
|
||||
|
||||
public bool PrepareForOpen()
|
||||
public bool PrepareForOpen(int runSeed = 0, int sequenceIndex = -1)
|
||||
{
|
||||
if (!EnsureTables())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_activeRunSeed = runSeed;
|
||||
_activeSequenceIndex = sequenceIndex;
|
||||
_currentGoods.Clear();
|
||||
for (int i = 0; i < GoodsCount; i++)
|
||||
{
|
||||
|
|
@ -132,7 +136,7 @@ namespace GeometryTD.UI
|
|||
private bool TryBuildRandomGoodsItem(int goodsIndex, out GoodsItemRawData goodsItem)
|
||||
{
|
||||
goodsItem = null;
|
||||
TowerCompItemData sourceItem = BuildRandomComponentItem();
|
||||
TowerCompItemData sourceItem = BuildRandomComponentItem(goodsIndex);
|
||||
if (sourceItem == null)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -153,7 +157,7 @@ namespace GeometryTD.UI
|
|||
return true;
|
||||
}
|
||||
|
||||
private TowerCompItemData BuildRandomComponentItem()
|
||||
private TowerCompItemData BuildRandomComponentItem(int goodsIndex)
|
||||
{
|
||||
int slotRoll = UnityEngine.Random.Range(0, 3);
|
||||
DRShopPrice priceRow = _shopPriceRows[UnityEngine.Random.Range(0, _shopPriceRows.Count)];
|
||||
|
|
@ -163,15 +167,15 @@ namespace GeometryTD.UI
|
|||
switch (slotRoll)
|
||||
{
|
||||
case 0:
|
||||
return BuildRandomMuzzleItem(rarity);
|
||||
return BuildRandomMuzzleItem(rarity, goodsIndex);
|
||||
case 1:
|
||||
return BuildRandomBearingItem(rarity);
|
||||
return BuildRandomBearingItem(rarity, goodsIndex);
|
||||
default:
|
||||
return BuildRandomBaseItem(rarity);
|
||||
return BuildRandomBaseItem(rarity, goodsIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private MuzzleCompItemData BuildRandomMuzzleItem(RarityType rarity)
|
||||
private MuzzleCompItemData BuildRandomMuzzleItem(RarityType rarity, int goodsIndex)
|
||||
{
|
||||
DRMuzzleComp[] rows = _muzzleCompTable.GetAllDataRows();
|
||||
DRMuzzleComp config = rows[UnityEngine.Random.Range(0, rows.Length)];
|
||||
|
|
@ -188,16 +192,14 @@ namespace GeometryTD.UI
|
|||
Tags = ComponentTagGenerationService.ResolveComponentTags(
|
||||
config.PossibleTag,
|
||||
normalizedRarity,
|
||||
InventoryTagSourceType.Shop,
|
||||
instanceId,
|
||||
config.Id),
|
||||
InventoryTagRandomContext.CreateShop(_activeRunSeed, _activeSequenceIndex, goodsIndex, config.Id)),
|
||||
AttackDamage = config.AttackDamage != null ? (int[])config.AttackDamage.Clone() : Array.Empty<int>(),
|
||||
DamageRandomRate = config.DamageRandomRate,
|
||||
AttackMethodType = config.AttackMethodType
|
||||
};
|
||||
}
|
||||
|
||||
private BearingCompItemData BuildRandomBearingItem(RarityType rarity)
|
||||
private BearingCompItemData BuildRandomBearingItem(RarityType rarity, int goodsIndex)
|
||||
{
|
||||
DRBearingComp[] rows = _bearingCompTable.GetAllDataRows();
|
||||
DRBearingComp config = rows[UnityEngine.Random.Range(0, rows.Length)];
|
||||
|
|
@ -214,15 +216,13 @@ namespace GeometryTD.UI
|
|||
Tags = ComponentTagGenerationService.ResolveComponentTags(
|
||||
config.PossibleTag,
|
||||
normalizedRarity,
|
||||
InventoryTagSourceType.Shop,
|
||||
instanceId,
|
||||
config.Id),
|
||||
InventoryTagRandomContext.CreateShop(_activeRunSeed, _activeSequenceIndex, goodsIndex, config.Id)),
|
||||
RotateSpeed = config.RotateSpeed != null ? (float[])config.RotateSpeed.Clone() : Array.Empty<float>(),
|
||||
AttackRange = config.AttackRange != null ? (float[])config.AttackRange.Clone() : Array.Empty<float>()
|
||||
};
|
||||
}
|
||||
|
||||
private BaseCompItemData BuildRandomBaseItem(RarityType rarity)
|
||||
private BaseCompItemData BuildRandomBaseItem(RarityType rarity, int goodsIndex)
|
||||
{
|
||||
DRBaseComp[] rows = _baseCompTable.GetAllDataRows();
|
||||
DRBaseComp config = rows[UnityEngine.Random.Range(0, rows.Length)];
|
||||
|
|
@ -239,9 +239,7 @@ namespace GeometryTD.UI
|
|||
Tags = ComponentTagGenerationService.ResolveComponentTags(
|
||||
config.PossibleTag,
|
||||
normalizedRarity,
|
||||
InventoryTagSourceType.Shop,
|
||||
instanceId,
|
||||
config.Id),
|
||||
InventoryTagRandomContext.CreateShop(_activeRunSeed, _activeSequenceIndex, goodsIndex, config.Id)),
|
||||
AttackSpeed = config.AttackSpeed != null ? (float[])config.AttackSpeed.Clone() : Array.Empty<float>(),
|
||||
AttackPropertyType = config.AttackPropertyType
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace GeometryTD.CustomUtility
|
|||
private static readonly TagType[] IceAbsoluteZeroPool = { TagType.Ice, TagType.AbsoluteZero };
|
||||
private static readonly TagType[] PierceExecutionPool = { TagType.Pierce, TagType.Execution };
|
||||
|
||||
public static BackpackInventoryData CreateSampleInventory()
|
||||
public static BackpackInventoryData CreateSampleInventory(int runSeed = 0)
|
||||
{
|
||||
BackpackInventoryData inventory = new BackpackInventoryData
|
||||
{
|
||||
|
|
@ -31,7 +31,7 @@ namespace GeometryTD.CustomUtility
|
|||
DamageRandomRate = 0.05f,
|
||||
AttackMethodType = AttackMethodType.NormalBullet,
|
||||
Constraint = string.Empty,
|
||||
Tags = ResolveSeedTags(FirePool, RarityType.Blue, 10001, 1)
|
||||
Tags = ResolveSeedTags(FirePool, RarityType.Blue, runSeed, 10001, 1)
|
||||
};
|
||||
|
||||
BearingCompItemData bearing = new BearingCompItemData
|
||||
|
|
@ -45,7 +45,7 @@ namespace GeometryTD.CustomUtility
|
|||
RotateSpeed = new[] { 100f, 120f, 130f, 140f, 150f },
|
||||
AttackRange = new[] { 3f, 4f, 5f, 6f, 8f },
|
||||
Constraint = string.Empty,
|
||||
Tags = ResolveSeedTags(FirePool, RarityType.Blue, 20001, 1)
|
||||
Tags = ResolveSeedTags(FirePool, RarityType.Blue, runSeed, 20001, 1)
|
||||
};
|
||||
|
||||
BaseCompItemData baseComp = new BaseCompItemData
|
||||
|
|
@ -59,7 +59,7 @@ namespace GeometryTD.CustomUtility
|
|||
AttackSpeed = new[] { 1f, 2f, 3f, 3.5f, 0.7f },
|
||||
AttackPropertyType = AttackPropertyType.Fire,
|
||||
Constraint = string.Empty,
|
||||
Tags = ResolveSeedTags(FirePool, RarityType.Blue, 30001, 1)
|
||||
Tags = ResolveSeedTags(FirePool, RarityType.Blue, runSeed, 30001, 1)
|
||||
};
|
||||
|
||||
TowerItemData tower = new TowerItemData
|
||||
|
|
@ -108,7 +108,7 @@ namespace GeometryTD.CustomUtility
|
|||
DamageRandomRate = 0.01f,
|
||||
AttackMethodType = AttackMethodType.NormalBullet,
|
||||
Constraint = string.Empty,
|
||||
Tags = ResolveSeedTags(IceFreezePool, RarityType.Blue, 10002, 2)
|
||||
Tags = ResolveSeedTags(IceFreezePool, RarityType.Blue, runSeed, 10002, 2)
|
||||
});
|
||||
|
||||
inventory.MuzzleComponents.Add(new MuzzleCompItemData
|
||||
|
|
@ -123,7 +123,7 @@ namespace GeometryTD.CustomUtility
|
|||
DamageRandomRate = 0.02f,
|
||||
AttackMethodType = AttackMethodType.NormalBullet,
|
||||
Constraint = string.Empty,
|
||||
Tags = ResolveSeedTags(CritPiercePool, RarityType.Purple, 10003, 3)
|
||||
Tags = ResolveSeedTags(CritPiercePool, RarityType.Purple, runSeed, 10003, 3)
|
||||
});
|
||||
|
||||
inventory.BearingComponents.Add(new BearingCompItemData
|
||||
|
|
@ -137,7 +137,7 @@ namespace GeometryTD.CustomUtility
|
|||
RotateSpeed = new[] { 200f, 250f, 300f, 320f, 350f },
|
||||
AttackRange = new[] { 6f, 6.5f, 7f, 8f, 8f },
|
||||
Constraint = string.Empty,
|
||||
Tags = ResolveSeedTags(IceShatterPool, RarityType.Blue, 20002, 2)
|
||||
Tags = ResolveSeedTags(IceShatterPool, RarityType.Blue, runSeed, 20002, 2)
|
||||
});
|
||||
|
||||
inventory.BearingComponents.Add(new BearingCompItemData
|
||||
|
|
@ -151,7 +151,7 @@ namespace GeometryTD.CustomUtility
|
|||
RotateSpeed = new[] { 60f, 70f, 80f, 90f, 100f },
|
||||
AttackRange = new[] { 4f, 4.5f, 5f, 5.5f, 6f },
|
||||
Constraint = string.Empty,
|
||||
Tags = ResolveSeedTags(PierceOverpenetratePool, RarityType.Purple, 20003, 3)
|
||||
Tags = ResolveSeedTags(PierceOverpenetratePool, RarityType.Purple, runSeed, 20003, 3)
|
||||
});
|
||||
|
||||
inventory.BaseComponents.Add(new BaseCompItemData
|
||||
|
|
@ -165,7 +165,7 @@ namespace GeometryTD.CustomUtility
|
|||
AttackSpeed = new[] { 4f, 4.2f, 4.4f, 4.6f, 4.8f },
|
||||
AttackPropertyType = AttackPropertyType.Ice,
|
||||
Constraint = string.Empty,
|
||||
Tags = ResolveSeedTags(IceAbsoluteZeroPool, RarityType.Blue, 30002, 2)
|
||||
Tags = ResolveSeedTags(IceAbsoluteZeroPool, RarityType.Blue, runSeed, 30002, 2)
|
||||
});
|
||||
|
||||
inventory.BaseComponents.Add(new BaseCompItemData
|
||||
|
|
@ -179,7 +179,7 @@ namespace GeometryTD.CustomUtility
|
|||
AttackSpeed = new[] { 1f, 1f, 1f, 1f, 1f },
|
||||
AttackPropertyType = AttackPropertyType.Physics,
|
||||
Constraint = string.Empty,
|
||||
Tags = ResolveSeedTags(PierceExecutionPool, RarityType.Purple, 30003, 3)
|
||||
Tags = ResolveSeedTags(PierceExecutionPool, RarityType.Purple, runSeed, 30003, 3)
|
||||
});
|
||||
|
||||
inventory.ParticipantTowerInstanceIds.Add(90001);
|
||||
|
|
@ -187,14 +187,12 @@ namespace GeometryTD.CustomUtility
|
|||
return inventory;
|
||||
}
|
||||
|
||||
private static TagType[] ResolveSeedTags(TagType[] possibleTags, RarityType rarity, long instanceId, int configId)
|
||||
private static TagType[] ResolveSeedTags(TagType[] possibleTags, RarityType rarity, int runSeed, long instanceId, int configId)
|
||||
{
|
||||
return ComponentTagGenerationService.ResolveComponentTags(
|
||||
possibleTags,
|
||||
rarity,
|
||||
InventoryTagSourceType.Seed,
|
||||
instanceId,
|
||||
configId);
|
||||
InventoryTagRandomContext.CreateSeed(runSeed, instanceId, configId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,31 +55,44 @@ namespace GeometryTD.Tests.EditMode
|
|||
TagType[] first = ComponentTagGenerationService.ResolveComponentTags(
|
||||
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter },
|
||||
RarityType.Blue,
|
||||
InventoryTagSourceType.Shop,
|
||||
12345,
|
||||
7,
|
||||
InventoryTagRandomContext.CreateShop(1001, 2, 0, 7),
|
||||
RulesByTag);
|
||||
|
||||
TagType[] second = ComponentTagGenerationService.ResolveComponentTags(
|
||||
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter },
|
||||
RarityType.Blue,
|
||||
InventoryTagSourceType.Shop,
|
||||
12345,
|
||||
7,
|
||||
InventoryTagRandomContext.CreateShop(1001, 2, 0, 7),
|
||||
RulesByTag);
|
||||
|
||||
Assert.That(second, Is.EqualTo(first));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ResolveComponentTags_Distinguishes_Different_RunSeed_With_Same_Other_Context()
|
||||
{
|
||||
TagType[] first = ComponentTagGenerationService.ResolveComponentTags(
|
||||
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter, TagType.Inferno, TagType.Execution },
|
||||
RarityType.Purple,
|
||||
InventoryTagRandomContext.CreateDrop(1001, 3, 0, 7),
|
||||
RulesByTag,
|
||||
RarityTagBudgetRulesByRarity);
|
||||
TagType[] second = ComponentTagGenerationService.ResolveComponentTags(
|
||||
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter, TagType.Inferno, TagType.Execution },
|
||||
RarityType.Purple,
|
||||
InventoryTagRandomContext.CreateDrop(2002, 3, 0, 7),
|
||||
RulesByTag,
|
||||
RarityTagBudgetRulesByRarity);
|
||||
|
||||
Assert.That(second, Is.Not.EqualTo(first));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ResolveComponentTags_Uses_Purple_Budget_And_Does_Not_Repeat()
|
||||
{
|
||||
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
|
||||
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter, TagType.Inferno, TagType.Execution },
|
||||
RarityType.Purple,
|
||||
InventoryTagSourceType.Drop,
|
||||
9001,
|
||||
4,
|
||||
InventoryTagRandomContext.CreateDrop(1001, 1, 0, 4),
|
||||
RulesByTag,
|
||||
RarityTagBudgetRulesByRarity);
|
||||
|
||||
|
|
@ -93,9 +106,7 @@ namespace GeometryTD.Tests.EditMode
|
|||
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
|
||||
new[] { TagType.Fire, TagType.BurnSpread },
|
||||
RarityType.Red,
|
||||
InventoryTagSourceType.Seed,
|
||||
42,
|
||||
1,
|
||||
InventoryTagRandomContext.CreateSeed(1001, 42, 1),
|
||||
RulesByTag,
|
||||
RarityTagBudgetRulesByRarity);
|
||||
|
||||
|
|
@ -116,9 +127,7 @@ namespace GeometryTD.Tests.EditMode
|
|||
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
|
||||
new[] { TagType.Fire, TagType.Ice, TagType.Crit },
|
||||
RarityType.Green,
|
||||
InventoryTagSourceType.Shop,
|
||||
1,
|
||||
1,
|
||||
InventoryTagRandomContext.CreateShop(1001, 0, 0, 1),
|
||||
weightedRules,
|
||||
RarityTagBudgetRulesByRarity);
|
||||
|
||||
|
|
@ -144,9 +153,7 @@ namespace GeometryTD.Tests.EditMode
|
|||
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
|
||||
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter },
|
||||
RarityType.Green,
|
||||
InventoryTagSourceType.Shop,
|
||||
1000 + i,
|
||||
1,
|
||||
InventoryTagRandomContext.CreateShop(1001 + i, 0, 0, 1),
|
||||
weightedRules,
|
||||
RarityTagBudgetRulesByRarity);
|
||||
|
||||
|
|
@ -189,6 +196,46 @@ namespace GeometryTD.Tests.EditMode
|
|||
Assert.That(absoluteZeroRule.Weight, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetEligibleTags_Uses_Final_TagDefinition_State_When_TagConfig_Loads_First()
|
||||
{
|
||||
DRTagConfig fireConfigRow = CreateFireConfigRow();
|
||||
DRTag fireTagRow = CreateFireDisabledRow();
|
||||
|
||||
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, null);
|
||||
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, new[] { fireTagRow });
|
||||
|
||||
TagType[] result = ComponentTagGenerationService.GetEligibleTags(
|
||||
new[] { TagType.Fire, TagType.Ice },
|
||||
RarityType.White,
|
||||
RulesByTag);
|
||||
|
||||
Assert.That(result, Is.EqualTo(new[] { TagType.Ice }));
|
||||
|
||||
TagDefinitionRegistry.ResetToDefaults();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ResolveComponentTags_Uses_Final_TagDefinition_State_When_Tag_Loads_First()
|
||||
{
|
||||
DRTagConfig fireConfigRow = CreateFireConfigRow();
|
||||
DRTag fireTagRow = CreateFireDisabledRow();
|
||||
|
||||
TagDefinitionRegistry.ReloadFromRows(null, new[] { fireTagRow });
|
||||
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, new[] { fireTagRow });
|
||||
|
||||
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
|
||||
new[] { TagType.Fire, TagType.Ice },
|
||||
RarityType.Green,
|
||||
InventoryTagRandomContext.CreateShop(1001, 0, 0, 11),
|
||||
RulesByTag,
|
||||
RarityTagBudgetRulesByRarity);
|
||||
|
||||
Assert.That(result, Is.EqualTo(new[] { TagType.Ice }));
|
||||
|
||||
TagDefinitionRegistry.ResetToDefaults();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ResolveRarityTagBudget_Uses_TableDriven_Range_Rules()
|
||||
{
|
||||
|
|
@ -227,9 +274,7 @@ namespace GeometryTD.Tests.EditMode
|
|||
TagType[] result = ComponentTagGenerationService.ResolveComponentTags(
|
||||
new[] { TagType.Fire, TagType.Ice, TagType.Crit, TagType.Shatter, TagType.Inferno, TagType.Execution },
|
||||
RarityType.Purple,
|
||||
InventoryTagSourceType.Drop,
|
||||
99,
|
||||
7,
|
||||
InventoryTagRandomContext.CreateDrop(1001, 1, 0, 7),
|
||||
RulesByTag,
|
||||
customBudgetRules);
|
||||
|
||||
|
|
@ -277,7 +322,7 @@ namespace GeometryTD.Tests.EditMode
|
|||
[Test]
|
||||
public void CreateSampleInventory_Generates_SeedTags_Within_Launch_Set_And_Matches_Tower_Stats()
|
||||
{
|
||||
BackpackInventoryData inventory = InventorySeedUtility.CreateSampleInventory();
|
||||
BackpackInventoryData inventory = InventorySeedUtility.CreateSampleInventory(1001);
|
||||
TowerItemData tower = inventory.Towers[0];
|
||||
MuzzleCompItemData muzzle = inventory.MuzzleComponents[0];
|
||||
BearingCompItemData bearing = inventory.BearingComponents[0];
|
||||
|
|
@ -291,5 +336,44 @@ namespace GeometryTD.Tests.EditMode
|
|||
Assert.That(tower.Stats.TagRuntimes[0].TotalStack, Is.EqualTo(3));
|
||||
Assert.That(tower.Stats.Tags, Is.EqualTo(new[] { TagType.Fire }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateSampleInventory_Is_Deterministic_For_Same_RunSeed()
|
||||
{
|
||||
BackpackInventoryData first = InventorySeedUtility.CreateSampleInventory(1001);
|
||||
BackpackInventoryData second = InventorySeedUtility.CreateSampleInventory(1001);
|
||||
|
||||
Assert.That(first.MuzzleComponents[1].Tags, Is.EqualTo(second.MuzzleComponents[1].Tags));
|
||||
Assert.That(first.BearingComponents[1].Tags, Is.EqualTo(second.BearingComponents[1].Tags));
|
||||
Assert.That(first.BaseComponents[1].Tags, Is.EqualTo(second.BaseComponents[1].Tags));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InventoryTagRandomContext_Composes_Stable_Local_InstanceIds_Per_Source()
|
||||
{
|
||||
InventoryTagRandomContext shop = InventoryTagRandomContext.CreateShop(1001, 2, 1, 7);
|
||||
InventoryTagRandomContext drop = InventoryTagRandomContext.CreateDrop(1001, 2, 1, 7);
|
||||
InventoryTagRandomContext reward = InventoryTagRandomContext.CreateReward(1001, 2, 1, 7);
|
||||
|
||||
Assert.That(shop.ItemInstanceId, Is.EqualTo(InventoryTagRandomContext.ComposeLocalItemInstanceId(2, 1)));
|
||||
Assert.That(drop.ItemInstanceId, Is.EqualTo(reward.ItemInstanceId));
|
||||
Assert.That(shop.SourceType, Is.EqualTo(InventoryTagSourceType.Shop));
|
||||
Assert.That(drop.SourceType, Is.EqualTo(InventoryTagSourceType.Drop));
|
||||
Assert.That(reward.SourceType, Is.EqualTo(InventoryTagSourceType.Reward));
|
||||
}
|
||||
|
||||
private static DRTagConfig CreateFireConfigRow()
|
||||
{
|
||||
DRTagConfig row = new DRTagConfig();
|
||||
Assert.That(row.ParseDataRow("\t1\t元素\tFire\tOnAfterHit\t火焰测试描述\t{\"BurnDurationSeconds\":4,\"BurnDamagePerSecondPerStack\":25,\"MaxEffectiveStack\":3}", null), Is.True);
|
||||
return row;
|
||||
}
|
||||
|
||||
private static DRTag CreateFireDisabledRow()
|
||||
{
|
||||
DRTag row = new DRTag();
|
||||
Assert.That(row.ParseDataRow("\t1\t元素\tFire\tElement\tWhite\t20\tFalse", null), Is.True);
|
||||
return row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ namespace GeometryTD.Tests.EditMode
|
|||
"run-test");
|
||||
|
||||
Assert.That(runState.RunId, Is.EqualTo("run-test"));
|
||||
Assert.That(runState.RunSeed, Is.Not.EqualTo(0));
|
||||
Assert.That(runState.ThemeType, Is.EqualTo(LevelThemeType.Plain));
|
||||
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(0));
|
||||
Assert.That(runState.IsCompleted, Is.False);
|
||||
|
|
@ -83,6 +84,31 @@ namespace GeometryTD.Tests.EditMode
|
|||
Assert.That(runState.RunInventorySnapshot.Gold, Is.EqualTo(130));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Factory_Preserves_Explicit_RunSeed_And_Generates_NonZero_Default_RunSeed()
|
||||
{
|
||||
RunState explicitSeedRun = RunStateFactory.Create(
|
||||
LevelThemeType.Plain,
|
||||
new BackpackInventoryData(),
|
||||
new[]
|
||||
{
|
||||
new RunNodeSeed { NodeType = RunNodeType.Combat, LinkedLevelId = 1 }
|
||||
},
|
||||
"run-explicit",
|
||||
123456);
|
||||
RunState generatedSeedRun = RunStateFactory.Create(
|
||||
LevelThemeType.Plain,
|
||||
new BackpackInventoryData(),
|
||||
new[]
|
||||
{
|
||||
new RunNodeSeed { NodeType = RunNodeType.Combat, LinkedLevelId = 1 }
|
||||
},
|
||||
"run-generated");
|
||||
|
||||
Assert.That(explicitSeedRun.RunSeed, Is.EqualTo(123456));
|
||||
Assert.That(generatedSeedRun.RunSeed, Is.Not.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AdvanceService_Exception_Marks_Current_Node_Exception_Without_Completing_Run()
|
||||
{
|
||||
|
|
@ -234,6 +260,7 @@ namespace GeometryTD.Tests.EditMode
|
|||
"fixed-run");
|
||||
|
||||
Assert.That(runState.RunId, Is.EqualTo("fixed-run"));
|
||||
Assert.That(runState.RunSeed, Is.Not.EqualTo(0));
|
||||
Assert.That(runState.NodeCount, Is.EqualTo(10));
|
||||
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(0));
|
||||
Assert.That(runState.CurrentNode.NodeType, Is.EqualTo(RunNodeType.Combat));
|
||||
|
|
|
|||
|
|
@ -435,6 +435,34 @@ namespace GeometryTD.Tests.EditMode
|
|||
TagDefinitionRegistry.ResetToDefaults();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReloadFromRows_Uses_TagTable_As_IsImplemented_Source_When_TagConfig_Loads_First()
|
||||
{
|
||||
DRTagConfig fireConfigRow = CreateFireConfigRow();
|
||||
DRTag fireTagRow = CreateFireDisabledRow();
|
||||
|
||||
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, null);
|
||||
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, new[] { fireTagRow });
|
||||
|
||||
AssertFireDefinition(false);
|
||||
|
||||
TagDefinitionRegistry.ResetToDefaults();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReloadFromRows_Uses_TagTable_As_IsImplemented_Source_When_Tag_Loads_First()
|
||||
{
|
||||
DRTagConfig fireConfigRow = CreateFireConfigRow();
|
||||
DRTag fireTagRow = CreateFireDisabledRow();
|
||||
|
||||
TagDefinitionRegistry.ReloadFromRows(null, new[] { fireTagRow });
|
||||
TagDefinitionRegistry.ReloadFromRows(new[] { fireConfigRow }, new[] { fireTagRow });
|
||||
|
||||
AssertFireDefinition(false);
|
||||
|
||||
TagDefinitionRegistry.ResetToDefaults();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BuildTagDescriptionText_Uses_Registry_Descriptions()
|
||||
{
|
||||
|
|
@ -502,6 +530,34 @@ namespace GeometryTD.Tests.EditMode
|
|||
Assert.That(definition.Category, Is.EqualTo(expectedCategory));
|
||||
Assert.That(definition.TriggerPhase, Is.EqualTo(expectedPhase));
|
||||
}
|
||||
|
||||
private static DRTagConfig CreateFireConfigRow()
|
||||
{
|
||||
DRTagConfig row = new DRTagConfig();
|
||||
Assert.That(row.ParseDataRow("\t1\t元素\tFire\tOnAfterHit\t火焰测试描述\t{\"BurnDurationSeconds\":4,\"BurnDamagePerSecondPerStack\":25,\"MaxEffectiveStack\":3}", null), Is.True);
|
||||
return row;
|
||||
}
|
||||
|
||||
private static DRTag CreateFireDisabledRow()
|
||||
{
|
||||
DRTag row = new DRTag();
|
||||
Assert.That(row.ParseDataRow("\t1\t元素\tFire\tElement\tWhite\t20\tFalse", null), Is.True);
|
||||
return row;
|
||||
}
|
||||
|
||||
private static void AssertFireDefinition(bool isImplemented)
|
||||
{
|
||||
Assert.That(TagDefinitionRegistry.TryGetDefinition(TagType.Fire, out TagDefinition fire), Is.True);
|
||||
Assert.That(fire.TriggerPhase, Is.EqualTo(TagTriggerPhase.OnAfterHit));
|
||||
Assert.That(fire.Description, Is.EqualTo("火焰测试描述"));
|
||||
Assert.That(fire.Config, Is.TypeOf<FireTagConfig>());
|
||||
|
||||
FireTagConfig config = (FireTagConfig)fire.Config;
|
||||
Assert.That(config.IsImplemented, Is.EqualTo(isImplemented));
|
||||
Assert.That(config.BurnDurationSeconds, Is.EqualTo(4f).Within(0.001f));
|
||||
Assert.That(config.BurnDamagePerSecondPerStack, Is.EqualTo(25f).Within(0.001f));
|
||||
Assert.That(config.MaxEffectiveStack, Is.EqualTo(3));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AttackPayloadFlowTests
|
||||
|
|
|
|||
Loading…
Reference in New Issue