public static Node[] GetIncomingNodesOnShortestPath(
            DirectionalMatrix <DistanceCalculation> distances,
            Direction dir, int fromX, int fromY, int toX, int toY,
            FiringLineMatrix firingLineMatrix       = null,
            bool keepMovingCloserOnFiringLastBullet = false)
        {
            DistanceCalculation distanceCalc = distances[dir, fromX, fromY];

            if (distanceCalc.Distance == Constants.UNREACHABLE_DISTANCE)
            {
                return(new Node[0]);
            }

            int length = distanceCalc.Distance;

            Node[] nodes = new Node[length];
            int    nodeIndex;
            Node   node;

            nodeIndex = 0;
            node      = distanceCalc.AdjacentNode;
            while (nodeIndex != length)
            {
                if (node.ActionType == ActionType.FiringLine)
                {
                    Line <FiringDistance> firingLine     = firingLineMatrix[toX, toY, node.Dir.GetOpposite(), node.EdgeOffset];
                    FiringDistance        firingDistance = firingLine[node.FiringLineIndex];
                    FiringDistanceCalculator.AddFiringLineNodesToRoute(firingDistance,
                                                                       firingLine.DirectionOfLine.GetOpposite(), nodes, ref nodeIndex, keepMovingCloserOnFiringLastBullet);
                    break;
                }

                // Add the node:
                nodes[nodeIndex] = node;
                nodeIndex++;
                if (node.ActionType == ActionType.Firing)
                {
                    // Add a moving node - the only reason to fire is to move...
                    node             = new Node(ActionType.Moving, node.Dir, node.X + node.Dir.GetXOffset(), node.Y + node.Dir.GetYOffset());
                    nodes[nodeIndex] = node;
                    nodeIndex++;
                }
                distanceCalc = distances[node.Dir, node.X, node.Y];
                node         = distanceCalc.AdjacentNode;
            }
            if (nodeIndex < length)
            {
                Array.Resize(ref nodes, nodeIndex);
            }
            return(nodes);
        }
        public static Node[] GetOutgoingNodesOnShortestAttackPath(
            CombinedMovementAndFiringDistanceCalculation combinedCalculation,
            DirectionalMatrix <DistanceCalculation> distances,
            bool keepMovingCloserOnFiringLastBullet = false)
        {
            int length = combinedCalculation.TicksTillTargetShot;

            if (length == Constants.UNREACHABLE_DISTANCE)
            {
                return(new Node[0]);
            }

            Point               startingTankPositionOnFiringLine = combinedCalculation.FiringDistance.StartingTankPosition;
            Direction           finalAttackDir = combinedCalculation.FinalMovementDirectionTowardsTarget;
            DistanceCalculation distanceCalc   = combinedCalculation.MovementDistanceToFiringLine;

            // Add nodes to move onto firing line (in reverse order):
            Node[] nodes     = new Node[combinedCalculation.TicksTillTargetShot];
            int    nodeIndex = distanceCalc.Distance;
            Node   node      = new Node(ActionType.Moving, finalAttackDir,
                                        startingTankPositionOnFiringLine.X, startingTankPositionOnFiringLine.Y);

            while (nodeIndex != 0)
            {
                nodeIndex--;
                nodes[nodeIndex] = node;
                node             = distanceCalc.AdjacentNode;
                if (node.ActionType == ActionType.Firing)
                {
                    nodeIndex--;
                    nodes[nodeIndex] = node;
                    node             = new Node(ActionType.Moving, node.Dir, node.X, node.Y);
                }
                distanceCalc = distances[node.Dir, node.X, node.Y];
            }

            // Add firing line nodes:
            FiringDistanceCalculator.AddFiringLineNodesToRoute(combinedCalculation.FiringDistance,
                                                               finalAttackDir, nodes, ref nodeIndex, keepMovingCloserOnFiringLastBullet);

            if (nodeIndex < length)
            {
                Array.Resize(ref nodes, nodeIndex);
            }
            return(nodes);
        }