400 lines
18 KiB
C#
400 lines
18 KiB
C#
using System.Collections.Generic;
|
|
using GeometryTD.CustomEvent;
|
|
using GeometryTD.Definition;
|
|
using GeometryTD.Factory;
|
|
using GeometryTD.Procedure;
|
|
using NUnit.Framework;
|
|
|
|
namespace GeometryTD.Tests.EditMode
|
|
{
|
|
public sealed class RunStateTests
|
|
{
|
|
[Test]
|
|
public void Factory_Creates_RunState_With_First_Node_Available()
|
|
{
|
|
BackpackInventoryData sourceInventory = new BackpackInventoryData
|
|
{
|
|
Gold = 120
|
|
};
|
|
sourceInventory.ParticipantTowerInstanceIds.Add(11);
|
|
|
|
RunState runState = RunStateFactory.Create(
|
|
LevelThemeType.Plain,
|
|
sourceInventory,
|
|
new List<RunNodeSeed>
|
|
{
|
|
new RunNodeSeed { NodeType = RunNodeType.Combat, LinkedLevelId = 1 },
|
|
new RunNodeSeed { NodeType = RunNodeType.Event },
|
|
new RunNodeSeed { NodeType = RunNodeType.BossCombat, LinkedLevelId = 4 }
|
|
},
|
|
"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);
|
|
Assert.That(runState.Nodes.Count, Is.EqualTo(3));
|
|
Assert.That(runState.Nodes[0].Status, Is.EqualTo(RunNodeStatus.Available));
|
|
Assert.That(runState.Nodes[1].Status, Is.EqualTo(RunNodeStatus.Locked));
|
|
Assert.That(runState.RunInventorySnapshot.Gold, Is.EqualTo(120));
|
|
Assert.That(runState.ThemeStageIndex, Is.EqualTo(0));
|
|
Assert.That(runState.CurrentThemePool, Is.EqualTo(new[] { LevelThemeType.Plain }));
|
|
Assert.That(runState.ThemeHistory, Is.EqualTo(new[] { LevelThemeType.Plain }));
|
|
Assert.That(runState.CurrentNodeContinueChallengeLayer, Is.EqualTo(0));
|
|
Assert.That(runState.RunItems, Is.Empty);
|
|
|
|
sourceInventory.Gold = 1;
|
|
sourceInventory.ParticipantTowerInstanceIds[0] = 99;
|
|
|
|
Assert.That(runState.RunInventorySnapshot.Gold, Is.EqualTo(120));
|
|
Assert.That(runState.RunInventorySnapshot.ParticipantTowerInstanceIds[0], Is.EqualTo(11));
|
|
}
|
|
|
|
[Test]
|
|
public void AdvanceService_Completes_Run_And_Unlocks_Next_Node()
|
|
{
|
|
RunState runState = RunStateFactory.Create(
|
|
LevelThemeType.Plain,
|
|
new BackpackInventoryData { Gold = 50 },
|
|
new[]
|
|
{
|
|
new RunNodeSeed { NodeId = 101, NodeType = RunNodeType.Combat, LinkedLevelId = 1 },
|
|
new RunNodeSeed { NodeId = 102, NodeType = RunNodeType.Shop },
|
|
new RunNodeSeed { NodeId = 103, NodeType = RunNodeType.BossCombat, LinkedLevelId = 4 }
|
|
});
|
|
|
|
bool firstCompleted = RunStateAdvanceService.TryCompleteCurrentNode(
|
|
runState,
|
|
RunNodeCompletionStatus.Completed,
|
|
CreateCompletionSnapshot(
|
|
new BackpackInventoryData { Gold = 80 },
|
|
continueChallengeLayer: 3,
|
|
runItemId: 1001,
|
|
runItemStackCount: 2));
|
|
|
|
Assert.That(firstCompleted, Is.True);
|
|
Assert.That(runState.Nodes[0].Status, Is.EqualTo(RunNodeStatus.Completed));
|
|
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(1));
|
|
Assert.That(runState.Nodes[1].Status, Is.EqualTo(RunNodeStatus.Available));
|
|
Assert.That(runState.RunInventorySnapshot.Gold, Is.EqualTo(80));
|
|
Assert.That(runState.CurrentNodeContinueChallengeLayer, Is.EqualTo(0));
|
|
Assert.That(runState.RunItems.Count, Is.EqualTo(1));
|
|
Assert.That(runState.RunItems[0].ItemId, Is.EqualTo(1001));
|
|
Assert.That(runState.RunItems[0].StackCount, Is.EqualTo(2));
|
|
|
|
RunStateAdvanceService.TryCompleteCurrentNode(
|
|
runState,
|
|
RunNodeCompletionStatus.Completed,
|
|
CreateCompletionSnapshot(new BackpackInventoryData { Gold = 95 }));
|
|
RunStateAdvanceService.TryCompleteCurrentNode(
|
|
runState,
|
|
RunNodeCompletionStatus.Completed,
|
|
CreateCompletionSnapshot(new BackpackInventoryData { Gold = 130 }));
|
|
|
|
Assert.That(runState.IsCompleted, Is.True);
|
|
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(3));
|
|
Assert.That(runState.CompletedNodeCount, Is.EqualTo(3));
|
|
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()
|
|
{
|
|
RunState runState = RunStateFactory.Create(
|
|
LevelThemeType.Plain,
|
|
new BackpackInventoryData { Gold = 20 },
|
|
new[]
|
|
{
|
|
new RunNodeSeed { NodeType = RunNodeType.Combat }
|
|
});
|
|
|
|
bool result = RunStateAdvanceService.TryCompleteCurrentNode(
|
|
runState,
|
|
RunNodeCompletionStatus.Exception,
|
|
CreateCompletionSnapshot(new BackpackInventoryData { Gold = 5 }, continueChallengeLayer: 4));
|
|
|
|
Assert.That(result, Is.True);
|
|
Assert.That(runState.IsCompleted, Is.False);
|
|
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(0));
|
|
Assert.That(runState.CurrentNode.Status, Is.EqualTo(RunNodeStatus.Exception));
|
|
Assert.That(runState.RunInventorySnapshot.Gold, Is.EqualTo(5));
|
|
Assert.That(runState.CurrentNodeContinueChallengeLayer, Is.EqualTo(4));
|
|
}
|
|
|
|
[Test]
|
|
public void NodeCompleteEventArgs_Completed_Win_Clones_CompletionSnapshot_And_Clears_State()
|
|
{
|
|
RunNodeCompletionSnapshot completionSnapshot = CreateCompletionSnapshot(
|
|
new BackpackInventoryData { Gold = 66 },
|
|
themeType: LevelThemeType.Volcano,
|
|
themeStageIndex: 2,
|
|
continueChallengeLayer: 5,
|
|
runItemId: 901,
|
|
runItemStackCount: 3);
|
|
NodeCompleteEventArgs eventArgs = NodeCompleteEventArgs.Create(
|
|
"run-1",
|
|
7,
|
|
RunNodeType.Shop,
|
|
3,
|
|
RunNodeCompletionStatus.Completed,
|
|
true,
|
|
completionSnapshot);
|
|
|
|
completionSnapshot.InventorySnapshot.Gold = 1;
|
|
completionSnapshot.CurrentThemePool[0] = LevelThemeType.Mountain;
|
|
completionSnapshot.RunItems[0].StackCount = 99;
|
|
|
|
Assert.That(eventArgs.RunId, Is.EqualTo("run-1"));
|
|
Assert.That(eventArgs.NodeId, Is.EqualTo(7));
|
|
Assert.That(eventArgs.NodeType, Is.EqualTo(RunNodeType.Shop));
|
|
Assert.That(eventArgs.SequenceIndex, Is.EqualTo(3));
|
|
Assert.That(eventArgs.CompletionStatus, Is.EqualTo(RunNodeCompletionStatus.Completed));
|
|
Assert.That(eventArgs.CombatWon, Is.True);
|
|
Assert.That(eventArgs.CompletionSnapshot.InventorySnapshot.Gold, Is.EqualTo(66));
|
|
Assert.That(eventArgs.CompletionSnapshot.ThemeType, Is.EqualTo(LevelThemeType.Volcano));
|
|
Assert.That(eventArgs.CompletionSnapshot.ThemeStageIndex, Is.EqualTo(2));
|
|
Assert.That(eventArgs.CompletionSnapshot.CurrentThemePool, Is.EqualTo(new[] { LevelThemeType.Volcano }));
|
|
Assert.That(eventArgs.CompletionSnapshot.RunItems[0].StackCount, Is.EqualTo(3));
|
|
|
|
eventArgs.Clear();
|
|
|
|
Assert.That(eventArgs.RunId, Is.Null);
|
|
Assert.That(eventArgs.NodeId, Is.EqualTo(0));
|
|
Assert.That(eventArgs.NodeType, Is.EqualTo(RunNodeType.None));
|
|
Assert.That(eventArgs.SequenceIndex, Is.EqualTo(-1));
|
|
Assert.That(eventArgs.CompletionStatus, Is.EqualTo(RunNodeCompletionStatus.None));
|
|
Assert.That(eventArgs.CombatWon, Is.False);
|
|
Assert.That(eventArgs.CompletionSnapshot, Is.Null);
|
|
}
|
|
|
|
[Test]
|
|
public void NodeCompleteEventArgs_Completed_Loss_Preserves_NonWin_Semantics()
|
|
{
|
|
RunNodeCompletionSnapshot completionSnapshot = CreateCompletionSnapshot(new BackpackInventoryData { Gold = 12 });
|
|
NodeCompleteEventArgs eventArgs = NodeCompleteEventArgs.Create(
|
|
"run-2",
|
|
8,
|
|
RunNodeType.Combat,
|
|
4,
|
|
RunNodeCompletionStatus.Completed,
|
|
false,
|
|
completionSnapshot);
|
|
|
|
completionSnapshot.InventorySnapshot.Gold = 99;
|
|
|
|
Assert.That(eventArgs.RunId, Is.EqualTo("run-2"));
|
|
Assert.That(eventArgs.NodeId, Is.EqualTo(8));
|
|
Assert.That(eventArgs.NodeType, Is.EqualTo(RunNodeType.Combat));
|
|
Assert.That(eventArgs.SequenceIndex, Is.EqualTo(4));
|
|
Assert.That(eventArgs.CompletionStatus, Is.EqualTo(RunNodeCompletionStatus.Completed));
|
|
Assert.That(eventArgs.CombatWon, Is.False);
|
|
Assert.That(eventArgs.CompletionSnapshot.InventorySnapshot.Gold, Is.EqualTo(12));
|
|
}
|
|
|
|
[Test]
|
|
public void NodeCompleteEventArgs_Exception_Preserves_Exception_Semantics()
|
|
{
|
|
RunNodeCompletionSnapshot completionSnapshot = CreateCompletionSnapshot(new BackpackInventoryData { Gold = 7 });
|
|
NodeCompleteEventArgs eventArgs = NodeCompleteEventArgs.Create(
|
|
"run-3",
|
|
9,
|
|
RunNodeType.BossCombat,
|
|
5,
|
|
RunNodeCompletionStatus.Exception,
|
|
false,
|
|
completionSnapshot);
|
|
|
|
completionSnapshot.InventorySnapshot.Gold = 100;
|
|
|
|
Assert.That(eventArgs.RunId, Is.EqualTo("run-3"));
|
|
Assert.That(eventArgs.NodeId, Is.EqualTo(9));
|
|
Assert.That(eventArgs.NodeType, Is.EqualTo(RunNodeType.BossCombat));
|
|
Assert.That(eventArgs.SequenceIndex, Is.EqualTo(5));
|
|
Assert.That(eventArgs.CompletionStatus, Is.EqualTo(RunNodeCompletionStatus.Exception));
|
|
Assert.That(eventArgs.CombatWon, Is.False);
|
|
Assert.That(eventArgs.CompletionSnapshot.InventorySnapshot.Gold, Is.EqualTo(7));
|
|
}
|
|
|
|
[Test]
|
|
public void CreateCurrentNodeContext_Clones_Run_State_Collections()
|
|
{
|
|
RunState runState = RunStateFactory.Create(
|
|
LevelThemeType.Plain,
|
|
new BackpackInventoryData { Gold = 20 },
|
|
new[]
|
|
{
|
|
new RunNodeSeed { NodeId = 99, NodeType = RunNodeType.Combat, LinkedLevelId = 1 },
|
|
new RunNodeSeed { NodeId = 100, NodeType = RunNodeType.Event }
|
|
});
|
|
|
|
RunNodeCompletionSnapshot seededSnapshot = new RunNodeCompletionSnapshot
|
|
{
|
|
InventorySnapshot = new BackpackInventoryData { Gold = 35 },
|
|
ThemeType = LevelThemeType.Mountain,
|
|
ThemeStageIndex = 3,
|
|
CurrentThemePool = new List<LevelThemeType> { LevelThemeType.Mountain, LevelThemeType.Volcano },
|
|
ThemeHistory = new List<LevelThemeType> { LevelThemeType.Plain, LevelThemeType.Mountain },
|
|
CurrentNodeContinueChallengeLayer = 6,
|
|
RunItems = new List<RunItemState>
|
|
{
|
|
new RunItemState { ItemId = 2001, StackCount = 4 }
|
|
}
|
|
};
|
|
RunStateAdvanceService.TryCompleteCurrentNode(
|
|
runState,
|
|
RunNodeCompletionStatus.Completed,
|
|
seededSnapshot);
|
|
runState.ApplyCompletionSnapshot(seededSnapshot);
|
|
|
|
RunNodeExecutionContext context = runState.CreateCurrentNodeContext();
|
|
|
|
runState.CurrentThemePool[0] = LevelThemeType.Plain;
|
|
runState.ThemeHistory[0] = LevelThemeType.Volcano;
|
|
runState.RunItems[0].StackCount = 1;
|
|
|
|
Assert.That(context.RunId, Is.EqualTo(runState.RunId));
|
|
Assert.That(context.NodeId, Is.EqualTo(100));
|
|
Assert.That(context.ThemeStageIndex, Is.EqualTo(3));
|
|
Assert.That(context.CurrentThemePool, Is.EqualTo(new[] { LevelThemeType.Mountain, LevelThemeType.Volcano }));
|
|
Assert.That(context.ThemeHistory, Is.EqualTo(new[] { LevelThemeType.Plain, LevelThemeType.Mountain }));
|
|
Assert.That(context.CurrentNodeContinueChallengeLayer, Is.EqualTo(6));
|
|
Assert.That(context.RunItems[0].ItemId, Is.EqualTo(2001));
|
|
Assert.That(context.RunItems[0].StackCount, Is.EqualTo(4));
|
|
}
|
|
|
|
[Test]
|
|
public void FixedRunNodeSequenceBuilder_Builds_Plain_Ten_Node_Sequence()
|
|
{
|
|
IReadOnlyList<RunNodeSeed> nodeSeeds = FixedRunNodeSequenceBuilder.Build(LevelThemeType.Plain);
|
|
|
|
Assert.That(nodeSeeds, Is.Not.Null);
|
|
Assert.That(nodeSeeds.Count, Is.EqualTo(10));
|
|
|
|
Assert.That(nodeSeeds[0].NodeType, Is.EqualTo(RunNodeType.Combat));
|
|
Assert.That(nodeSeeds[1].NodeType, Is.EqualTo(RunNodeType.Event));
|
|
Assert.That(nodeSeeds[2].NodeType, Is.EqualTo(RunNodeType.Combat));
|
|
Assert.That(nodeSeeds[3].NodeType, Is.EqualTo(RunNodeType.Shop));
|
|
Assert.That(nodeSeeds[4].NodeType, Is.EqualTo(RunNodeType.Combat));
|
|
Assert.That(nodeSeeds[5].NodeType, Is.EqualTo(RunNodeType.Event));
|
|
Assert.That(nodeSeeds[6].NodeType, Is.EqualTo(RunNodeType.Combat));
|
|
Assert.That(nodeSeeds[7].NodeType, Is.EqualTo(RunNodeType.Shop));
|
|
Assert.That(nodeSeeds[8].NodeType, Is.EqualTo(RunNodeType.Event));
|
|
Assert.That(nodeSeeds[9].NodeType, Is.EqualTo(RunNodeType.BossCombat));
|
|
|
|
Assert.That(nodeSeeds[0].LinkedLevelId, Is.EqualTo(1));
|
|
Assert.That(nodeSeeds[2].LinkedLevelId, Is.EqualTo(2));
|
|
Assert.That(nodeSeeds[4].LinkedLevelId, Is.EqualTo(3));
|
|
Assert.That(nodeSeeds[6].LinkedLevelId, Is.EqualTo(1));
|
|
Assert.That(nodeSeeds[9].LinkedLevelId, Is.EqualTo(4));
|
|
Assert.That(nodeSeeds[1].LinkedLevelId, Is.EqualTo(0));
|
|
Assert.That(nodeSeeds[3].LinkedLevelId, Is.EqualTo(0));
|
|
}
|
|
|
|
[Test]
|
|
public void FixedRunNodeSequenceBuilder_Returns_Empty_For_Unsupported_Theme()
|
|
{
|
|
IReadOnlyList<RunNodeSeed> nodeSeeds = FixedRunNodeSequenceBuilder.Build(LevelThemeType.Volcano);
|
|
|
|
Assert.That(nodeSeeds, Is.Not.Null);
|
|
Assert.That(nodeSeeds.Count, Is.EqualTo(0));
|
|
}
|
|
|
|
[Test]
|
|
public void CreateFixedRun_Creates_Ten_Node_Run_And_Completes_After_Ten_Advances()
|
|
{
|
|
RunState runState = RunStateFactory.CreateFixedRun(
|
|
LevelThemeType.Plain,
|
|
new BackpackInventoryData { Gold = 100 },
|
|
"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));
|
|
Assert.That(runState.Nodes[0].Status, Is.EqualTo(RunNodeStatus.Available));
|
|
Assert.That(runState.Nodes[9].Status, Is.EqualTo(RunNodeStatus.Locked));
|
|
Assert.That(runState.GetNodeBySequenceIndex(9), Is.Not.Null);
|
|
Assert.That(RunState.IsBossNode(runState.GetNodeBySequenceIndex(9)), Is.True);
|
|
|
|
for (int i = 0; i < runState.NodeCount; i++)
|
|
{
|
|
bool advanced = RunStateAdvanceService.TryCompleteCurrentNode(
|
|
runState,
|
|
RunNodeCompletionStatus.Completed,
|
|
CreateCompletionSnapshot(new BackpackInventoryData { Gold = 100 + i }));
|
|
|
|
Assert.That(advanced, Is.True);
|
|
}
|
|
|
|
Assert.That(runState.IsCompleted, Is.True);
|
|
Assert.That(runState.CompletedNodeCount, Is.EqualTo(10));
|
|
Assert.That(runState.CurrentNodeIndex, Is.EqualTo(10));
|
|
Assert.That(runState.RunInventorySnapshot.Gold, Is.EqualTo(109));
|
|
}
|
|
|
|
private static RunNodeCompletionSnapshot CreateCompletionSnapshot(
|
|
BackpackInventoryData inventorySnapshot,
|
|
LevelThemeType themeType = LevelThemeType.Plain,
|
|
int themeStageIndex = 0,
|
|
int continueChallengeLayer = 0,
|
|
int runItemId = 0,
|
|
int runItemStackCount = 0)
|
|
{
|
|
RunNodeCompletionSnapshot snapshot = new RunNodeCompletionSnapshot
|
|
{
|
|
InventorySnapshot = inventorySnapshot,
|
|
ThemeType = themeType,
|
|
ThemeStageIndex = themeStageIndex,
|
|
CurrentThemePool = new List<LevelThemeType>(),
|
|
ThemeHistory = new List<LevelThemeType>(),
|
|
CurrentNodeContinueChallengeLayer = continueChallengeLayer,
|
|
RunItems = new List<RunItemState>()
|
|
};
|
|
|
|
if (themeType != LevelThemeType.None)
|
|
{
|
|
snapshot.CurrentThemePool.Add(themeType);
|
|
snapshot.ThemeHistory.Add(themeType);
|
|
}
|
|
|
|
if (runItemId > 0)
|
|
{
|
|
snapshot.RunItems.Add(new RunItemState
|
|
{
|
|
ItemId = runItemId,
|
|
StackCount = runItemStackCount
|
|
});
|
|
}
|
|
|
|
return snapshot;
|
|
}
|
|
}
|
|
}
|