356 lines
12 KiB
C#
356 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using GeometryTD.CustomUtility;
|
|
using GeometryTD.Definition;
|
|
using GeometryTD.Factory;
|
|
|
|
namespace GeometryTD.Procedure
|
|
{
|
|
public enum RunNodeType
|
|
{
|
|
None = 0,
|
|
Combat = 1,
|
|
Event = 2,
|
|
Shop = 3,
|
|
BossCombat = 4
|
|
}
|
|
|
|
public enum RunNodeStatus
|
|
{
|
|
Locked = 0,
|
|
Available = 1,
|
|
Completed = 2,
|
|
Exception = 3,
|
|
Skipped = 4
|
|
}
|
|
|
|
public enum RunNodeCompletionStatus
|
|
{
|
|
None = 0,
|
|
Completed = 1,
|
|
Exception = 2
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class RunNodeSeed
|
|
{
|
|
public int NodeId { get; set; }
|
|
public RunNodeType NodeType { get; set; }
|
|
public LevelThemeType ThemeType { get; set; }
|
|
public int LinkedLevelId { get; set; }
|
|
public int SequenceIndex { get; set; } = -1;
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class RunNodeState
|
|
{
|
|
public int NodeId { get; internal set; }
|
|
public RunNodeType NodeType { get; internal set; }
|
|
public LevelThemeType ThemeType { get; internal set; }
|
|
public int LinkedLevelId { get; internal set; }
|
|
public RunNodeStatus Status { get; internal set; }
|
|
public int SequenceIndex { get; internal set; }
|
|
|
|
internal RunNodeState Clone()
|
|
{
|
|
return new RunNodeState
|
|
{
|
|
NodeId = NodeId,
|
|
NodeType = NodeType,
|
|
ThemeType = ThemeType,
|
|
LinkedLevelId = LinkedLevelId,
|
|
Status = Status,
|
|
SequenceIndex = SequenceIndex
|
|
};
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class RunItemState
|
|
{
|
|
public int ItemId { get; set; }
|
|
public int StackCount { get; set; }
|
|
|
|
internal RunItemState Clone()
|
|
{
|
|
return new RunItemState
|
|
{
|
|
ItemId = ItemId,
|
|
StackCount = StackCount
|
|
};
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class RunNodeExecutionContext
|
|
{
|
|
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; }
|
|
public LevelThemeType ThemeType { get; set; }
|
|
public int ThemeStageIndex { get; set; }
|
|
public List<LevelThemeType> CurrentThemePool { get; set; } = new List<LevelThemeType>();
|
|
public List<LevelThemeType> ThemeHistory { get; set; } = new List<LevelThemeType>();
|
|
public int CurrentNodeContinueChallengeLayer { get; set; }
|
|
public List<RunItemState> RunItems { get; set; } = new List<RunItemState>();
|
|
|
|
internal RunNodeExecutionContext Clone()
|
|
{
|
|
return new RunNodeExecutionContext
|
|
{
|
|
RunId = RunId,
|
|
RunSeed = RunSeed,
|
|
NodeId = NodeId,
|
|
NodeType = NodeType,
|
|
SequenceIndex = SequenceIndex,
|
|
ThemeType = ThemeType,
|
|
ThemeStageIndex = ThemeStageIndex,
|
|
CurrentThemePool = RunStateCloneUtility.CloneThemeList(CurrentThemePool),
|
|
ThemeHistory = RunStateCloneUtility.CloneThemeList(ThemeHistory),
|
|
CurrentNodeContinueChallengeLayer = CurrentNodeContinueChallengeLayer,
|
|
RunItems = RunStateCloneUtility.CloneRunItems(RunItems)
|
|
};
|
|
}
|
|
|
|
public RunNodeCompletionSnapshot CreateCompletionSnapshot(BackpackInventoryData inventorySnapshot)
|
|
{
|
|
return new RunNodeCompletionSnapshot
|
|
{
|
|
InventorySnapshot = InventoryCloneUtility.CloneInventory(inventorySnapshot),
|
|
ThemeType = ThemeType,
|
|
ThemeStageIndex = ThemeStageIndex,
|
|
CurrentThemePool = RunStateCloneUtility.CloneThemeList(CurrentThemePool),
|
|
ThemeHistory = RunStateCloneUtility.CloneThemeList(ThemeHistory),
|
|
CurrentNodeContinueChallengeLayer = CurrentNodeContinueChallengeLayer,
|
|
RunItems = RunStateCloneUtility.CloneRunItems(RunItems)
|
|
};
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class RunNodeCompletionSnapshot
|
|
{
|
|
public BackpackInventoryData InventorySnapshot { get; set; }
|
|
public LevelThemeType ThemeType { get; set; }
|
|
public int ThemeStageIndex { get; set; }
|
|
public List<LevelThemeType> CurrentThemePool { get; set; } = new List<LevelThemeType>();
|
|
public List<LevelThemeType> ThemeHistory { get; set; } = new List<LevelThemeType>();
|
|
public int CurrentNodeContinueChallengeLayer { get; set; }
|
|
public List<RunItemState> RunItems { get; set; } = new List<RunItemState>();
|
|
|
|
internal RunNodeCompletionSnapshot Clone()
|
|
{
|
|
return new RunNodeCompletionSnapshot
|
|
{
|
|
InventorySnapshot = InventoryCloneUtility.CloneInventory(InventorySnapshot),
|
|
ThemeType = ThemeType,
|
|
ThemeStageIndex = ThemeStageIndex,
|
|
CurrentThemePool = RunStateCloneUtility.CloneThemeList(CurrentThemePool),
|
|
ThemeHistory = RunStateCloneUtility.CloneThemeList(ThemeHistory),
|
|
CurrentNodeContinueChallengeLayer = CurrentNodeContinueChallengeLayer,
|
|
RunItems = RunStateCloneUtility.CloneRunItems(RunItems)
|
|
};
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public sealed class RunState
|
|
{
|
|
private readonly List<RunNodeState> _nodes;
|
|
|
|
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);
|
|
ThemeStageIndex = 0;
|
|
CurrentThemePool = CreateDefaultThemeList(themeType);
|
|
ThemeHistory = CreateDefaultThemeList(themeType);
|
|
CurrentNodeContinueChallengeLayer = 0;
|
|
RunItems = new List<RunItemState>();
|
|
CurrentNodeIndex = _nodes.Count > 0 ? 0 : -1;
|
|
IsCompleted = _nodes.Count <= 0;
|
|
}
|
|
|
|
public string RunId { get; internal set; }
|
|
|
|
public int RunSeed { get; internal set; }
|
|
|
|
public LevelThemeType ThemeType { get; internal set; }
|
|
|
|
public int CurrentNodeIndex { get; internal set; }
|
|
|
|
public bool IsCompleted { get; internal set; }
|
|
|
|
public BackpackInventoryData RunInventorySnapshot { get; internal set; }
|
|
|
|
public int ThemeStageIndex { get; internal set; }
|
|
|
|
public List<LevelThemeType> CurrentThemePool { get; internal set; }
|
|
|
|
public List<LevelThemeType> ThemeHistory { get; internal set; }
|
|
|
|
public int CurrentNodeContinueChallengeLayer { get; internal set; }
|
|
|
|
public List<RunItemState> RunItems { get; internal set; }
|
|
|
|
public IReadOnlyList<RunNodeState> Nodes => _nodes;
|
|
|
|
public int NodeCount => _nodes.Count;
|
|
|
|
public RunNodeState CurrentNode
|
|
{
|
|
get
|
|
{
|
|
if (CurrentNodeIndex < 0 || CurrentNodeIndex >= _nodes.Count)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return _nodes[CurrentNodeIndex];
|
|
}
|
|
}
|
|
|
|
public bool CanEnterCurrentNode => !IsCompleted && CurrentNode != null && CurrentNode.Status == RunNodeStatus.Available;
|
|
|
|
public RunNodeState GetNodeBySequenceIndex(int sequenceIndex)
|
|
{
|
|
if (sequenceIndex < 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
foreach (RunNodeState nodeState in _nodes)
|
|
{
|
|
if (nodeState.SequenceIndex == sequenceIndex)
|
|
{
|
|
return nodeState;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static bool IsBossNode(RunNodeState nodeState)
|
|
{
|
|
return nodeState != null && nodeState.NodeType == RunNodeType.BossCombat;
|
|
}
|
|
|
|
public int CompletedNodeCount
|
|
{
|
|
get
|
|
{
|
|
int count = 0;
|
|
foreach (var nodeState in _nodes)
|
|
{
|
|
if (nodeState.Status == RunNodeStatus.Completed)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
}
|
|
|
|
internal void ReplaceInventorySnapshot(BackpackInventoryData inventorySnapshot)
|
|
{
|
|
RunInventorySnapshot = InventoryCloneUtility.CloneInventory(inventorySnapshot);
|
|
}
|
|
|
|
public RunNodeExecutionContext CreateCurrentNodeContext()
|
|
{
|
|
RunNodeState currentNode = CurrentNode;
|
|
if (currentNode == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new RunNodeExecutionContext
|
|
{
|
|
RunId = RunId,
|
|
RunSeed = RunSeed,
|
|
NodeId = currentNode.NodeId,
|
|
NodeType = currentNode.NodeType,
|
|
SequenceIndex = currentNode.SequenceIndex,
|
|
ThemeType = ThemeType,
|
|
ThemeStageIndex = ThemeStageIndex,
|
|
CurrentThemePool = RunStateCloneUtility.CloneThemeList(CurrentThemePool),
|
|
ThemeHistory = RunStateCloneUtility.CloneThemeList(ThemeHistory),
|
|
CurrentNodeContinueChallengeLayer = CurrentNodeContinueChallengeLayer,
|
|
RunItems = RunStateCloneUtility.CloneRunItems(RunItems)
|
|
};
|
|
}
|
|
|
|
public void ApplyCompletionSnapshot(RunNodeCompletionSnapshot completionSnapshot)
|
|
{
|
|
RunInventorySnapshot = InventoryCloneUtility.CloneInventory(completionSnapshot.InventorySnapshot);
|
|
ThemeType = completionSnapshot.ThemeType;
|
|
ThemeStageIndex = completionSnapshot.ThemeStageIndex;
|
|
CurrentThemePool = RunStateCloneUtility.CloneThemeList(completionSnapshot.CurrentThemePool);
|
|
ThemeHistory = RunStateCloneUtility.CloneThemeList(completionSnapshot.ThemeHistory);
|
|
CurrentNodeContinueChallengeLayer = completionSnapshot.CurrentNodeContinueChallengeLayer;
|
|
RunItems = RunStateCloneUtility.CloneRunItems(completionSnapshot.RunItems);
|
|
}
|
|
|
|
private static List<LevelThemeType> CreateDefaultThemeList(LevelThemeType themeType)
|
|
{
|
|
List<LevelThemeType> themes = new List<LevelThemeType>();
|
|
if (themeType != LevelThemeType.None)
|
|
{
|
|
themes.Add(themeType);
|
|
}
|
|
|
|
return themes;
|
|
}
|
|
}
|
|
|
|
internal static class RunStateCloneUtility
|
|
{
|
|
internal static List<LevelThemeType> CloneThemeList(IReadOnlyList<LevelThemeType> source)
|
|
{
|
|
List<LevelThemeType> cloned = new List<LevelThemeType>();
|
|
if (source == null)
|
|
{
|
|
return cloned;
|
|
}
|
|
|
|
for (int i = 0; i < source.Count; i++)
|
|
{
|
|
cloned.Add(source[i]);
|
|
}
|
|
|
|
return cloned;
|
|
}
|
|
|
|
internal static List<RunItemState> CloneRunItems(IReadOnlyList<RunItemState> source)
|
|
{
|
|
List<RunItemState> cloned = new List<RunItemState>();
|
|
if (source == null)
|
|
{
|
|
return cloned;
|
|
}
|
|
|
|
for (int i = 0; i < source.Count; i++)
|
|
{
|
|
RunItemState item = source[i];
|
|
if (item != null)
|
|
{
|
|
cloned.Add(item.Clone());
|
|
}
|
|
}
|
|
|
|
return cloned;
|
|
}
|
|
}
|
|
}
|