Modified weapon scripts to eliminate specialized projectile behavior - allows charged weapons to have projectiles and modify weapon stats when charged Added machine gun weapon & VFX Moved third party code to Plugins folder to improve compile times
209 lines
7.4 KiB
C#
209 lines
7.4 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Microsoft.Msagl.Core.DataStructures;
|
|
using Microsoft.Msagl.Core.Layout;
|
|
using Microsoft.Msagl.Core;
|
|
using Microsoft.Msagl.Core.Geometry;
|
|
|
|
namespace Microsoft.Msagl.Layout.Incremental {
|
|
class TNode {
|
|
internal LinkedListNode<TNode> stackNode;
|
|
internal Node v;
|
|
internal bool visited;
|
|
internal List<TNode> outNeighbours = new List<TNode>();
|
|
internal List<TNode> inNeighbours = new List<TNode>();
|
|
internal TNode(Node v) {
|
|
this.v = v;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create separation constraints between the source and target of edges not involved in cycles
|
|
/// in order to better show flow
|
|
/// </summary>
|
|
public class EdgeConstraintGenerator
|
|
{
|
|
IdealEdgeLengthSettings settings;
|
|
IEnumerable<Edge> edges;
|
|
Dictionary<Node, TNode> nodeMap = new Dictionary<Node, TNode>();
|
|
LinkedList<TNode> stack = new LinkedList<TNode>();
|
|
List<TNode> component;
|
|
AxisSolver horizontalSolver;
|
|
AxisSolver verticalSolver;
|
|
List<Set<Node>> cyclicComponents = new List<Set<Node>>();
|
|
|
|
/// <summary>
|
|
/// Creates a VerticalSeparationConstraint for each edge in the given set to structural constraints,
|
|
/// to require these edges to be downward pointing. Also checks for cycles, and edges involved
|
|
/// in a cycle receive no VerticalSeparationConstraint, but can optionally receive a circle constraint.
|
|
/// </summary>
|
|
/// <param name="edges"></param>
|
|
/// <param name="settings"></param>
|
|
/// <param name="horizontalSolver"></param>
|
|
/// <param name="verticalSolver"></param>
|
|
internal static void GenerateEdgeConstraints(
|
|
IEnumerable<Edge> edges,
|
|
IdealEdgeLengthSettings settings,
|
|
AxisSolver horizontalSolver,
|
|
AxisSolver verticalSolver)
|
|
{
|
|
if (settings.EdgeDirectionConstraints == Directions.None)
|
|
{
|
|
return;
|
|
}
|
|
EdgeConstraintGenerator g = new EdgeConstraintGenerator(edges, settings, horizontalSolver, verticalSolver);
|
|
g.GenerateSeparationConstraints();
|
|
|
|
// we have in the past used Circular constraints to better show cycles... it's a little experimental though
|
|
// so it's not currently enabled
|
|
//foreach (var c in g.CyclicComponents) {
|
|
// constraints.Add(new ProcrustesCircleConstraint(c));
|
|
//}
|
|
}
|
|
|
|
internal EdgeConstraintGenerator(
|
|
IEnumerable<Edge> edges,
|
|
IdealEdgeLengthSettings settings,
|
|
AxisSolver horizontalSolver,
|
|
AxisSolver verticalSolver)
|
|
{
|
|
// filter out self edges
|
|
this.edges = edges.Where(e => e.Source != e.Target);
|
|
|
|
this.settings = settings;
|
|
this.horizontalSolver = horizontalSolver;
|
|
this.verticalSolver = verticalSolver;
|
|
|
|
foreach (var e in this.edges) {
|
|
TNode u = CreateTNode(e.Source), v = CreateTNode(e.Target);
|
|
u.outNeighbours.Add(v);
|
|
v.inNeighbours.Add(u);
|
|
}
|
|
|
|
foreach (var v in nodeMap.Values) {
|
|
if(v.stackNode==null) {
|
|
DFS(v);
|
|
}
|
|
}
|
|
|
|
while (stack.Count > 0) {
|
|
component = new List<TNode>();
|
|
RDFS(stack.Last.Value);
|
|
if (component.Count > 1) {
|
|
var cyclicComponent = new Set<Node>();
|
|
foreach (var v in component) {
|
|
cyclicComponent.Insert(v.v);
|
|
}
|
|
cyclicComponents.Add(cyclicComponent);
|
|
}
|
|
}
|
|
|
|
switch (settings.EdgeDirectionConstraints) {
|
|
case Directions.South:
|
|
this.addConstraint = this.AddSConstraint;
|
|
break;
|
|
case Directions.North:
|
|
this.addConstraint = this.AddNConstraint;
|
|
break;
|
|
case Directions.West:
|
|
this.addConstraint = this.AddWConstraint;
|
|
break;
|
|
case Directions.East:
|
|
this.addConstraint = this.AddEConstraint;
|
|
break;
|
|
}
|
|
}
|
|
|
|
private delegate void AddConstraint(Node u, Node v);
|
|
private AddConstraint addConstraint;
|
|
|
|
private void AddSConstraint(Node u, Node v)
|
|
{
|
|
verticalSolver.AddStructuralConstraint(
|
|
new VerticalSeparationConstraint(u, v, (u.Height + v.Height) / 2 + settings.ConstrainedEdgeSeparation));
|
|
}
|
|
|
|
private void AddNConstraint(Node u, Node v)
|
|
{
|
|
verticalSolver.AddStructuralConstraint(
|
|
new VerticalSeparationConstraint(v, u, (u.Height + v.Height) / 2 + settings.ConstrainedEdgeSeparation));
|
|
}
|
|
|
|
private void AddEConstraint(Node u, Node v)
|
|
{
|
|
horizontalSolver.AddStructuralConstraint(
|
|
new HorizontalSeparationConstraint(v, u, (u.Width + v.Width) / 2 + settings.ConstrainedEdgeSeparation));
|
|
}
|
|
|
|
private void AddWConstraint(Node u, Node v)
|
|
{
|
|
horizontalSolver.AddStructuralConstraint(
|
|
new HorizontalSeparationConstraint(u, v, (u.Width + v.Width) / 2 + settings.ConstrainedEdgeSeparation));
|
|
}
|
|
|
|
/// <summary>
|
|
/// For each edge not involved in a cycle create a constraint
|
|
/// </summary>
|
|
public void GenerateSeparationConstraints() {
|
|
foreach (var e in edges) {
|
|
bool edgeInCycle = false;
|
|
Node u = e.Source, v = e.Target;
|
|
foreach (var c in cyclicComponents) {
|
|
if (c.Contains(u) && c.Contains(v)) {
|
|
edgeInCycle = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!edgeInCycle) {
|
|
this.addConstraint(u, v);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get an Enumeration of CyclicComponents
|
|
/// </summary>
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
|
|
public IEnumerable<IEnumerable<Node>> CyclicComponents {
|
|
get {
|
|
return from c in cyclicComponents
|
|
select c.AsEnumerable();
|
|
}
|
|
}
|
|
private void DFS(TNode u) {
|
|
u.visited = true;
|
|
foreach (var v in u.outNeighbours) {
|
|
if (!v.visited) {
|
|
DFS(v);
|
|
}
|
|
}
|
|
PushStack(u);
|
|
}
|
|
private void RDFS(TNode u) {
|
|
component.Add(u);
|
|
PopStack(u);
|
|
foreach (var v in u.inNeighbours) {
|
|
if (v.stackNode != null) {
|
|
RDFS(v);
|
|
}
|
|
}
|
|
}
|
|
private TNode CreateTNode(Node v) {
|
|
TNode tv;
|
|
if (!nodeMap.ContainsKey(v)) {
|
|
tv = new TNode(v);
|
|
nodeMap[v] = tv;
|
|
} else {
|
|
tv = nodeMap[v];
|
|
}
|
|
return tv;
|
|
}
|
|
private void PushStack(TNode v) {
|
|
v.stackNode = stack.AddLast(v);
|
|
}
|
|
private void PopStack(TNode v) {
|
|
stack.Remove(v.stackNode);
|
|
v.stackNode = null;
|
|
}
|
|
}
|
|
}
|